Annotation of sys/netatalk/aarp.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: aarp.c,v 1.7 2006/04/25 05:52:43 tedu Exp $ */
! 2:
! 3: /*
! 4: * Copyright (c) 1990,1991 Regents of The University of Michigan.
! 5: * All Rights Reserved.
! 6: */
! 7:
! 8: /*
! 9: * The following is the contents of the COPYRIGHT file from the
! 10: * netatalk-1.4a2 distribution, from which this file is derived.
! 11: */
! 12: /*
! 13: * Copyright (c) 1990,1996 Regents of The University of Michigan.
! 14: *
! 15: * All Rights Reserved.
! 16: *
! 17: * Permission to use, copy, modify, and distribute this software and
! 18: * its documentation for any purpose and without fee is hereby granted,
! 19: * provided that the above copyright notice appears in all copies and
! 20: * that both that copyright notice and this permission notice appear
! 21: * in supporting documentation, and that the name of The University
! 22: * of Michigan not be used in advertising or publicity pertaining to
! 23: * distribution of the software without specific, written prior
! 24: * permission. This software is supplied as is without expressed or
! 25: * implied warranties of any kind.
! 26: *
! 27: * This product includes software developed by the University of
! 28: * California, Berkeley and its contributors.
! 29: *
! 30: * Solaris code is encumbered by the following:
! 31: *
! 32: * Copyright (C) 1996 by Sun Microsystems Computer Co.
! 33: *
! 34: * Permission to use, copy, modify, and distribute this software and
! 35: * its documentation for any purpose and without fee is hereby
! 36: * granted, provided that the above copyright notice appear in all
! 37: * copies and that both that copyright notice and this permission
! 38: * notice appear in supporting documentation. This software is
! 39: * provided "as is" without express or implied warranty.
! 40: *
! 41: * Research Systems Unix Group
! 42: * The University of Michigan
! 43: * c/o Wesley Craig
! 44: * 535 W. William Street
! 45: * Ann Arbor, Michigan
! 46: * +1-313-764-2278
! 47: * netatalk@umich.edu
! 48: */
! 49: /*
! 50: * None of the Solaris code mentioned is included in OpenBSD.
! 51: * This code also relies heavily on previous effort in FreeBSD and NetBSD.
! 52: */
! 53:
! 54: #include <sys/param.h>
! 55: #include <sys/systm.h>
! 56: #include <sys/kernel.h>
! 57: #include <sys/malloc.h>
! 58: #include <sys/mbuf.h>
! 59: #include <sys/protosw.h>
! 60: #include <sys/socket.h>
! 61: #include <sys/ioctl.h>
! 62: #include <sys/errno.h>
! 63: #include <sys/syslog.h>
! 64: #include <sys/proc.h>
! 65: #include <sys/timeout.h>
! 66:
! 67: #include <net/if.h>
! 68: #include <net/route.h>
! 69: #include <netinet/in.h>
! 70: #undef s_net
! 71: #include <netinet/if_ether.h>
! 72: #include <net/if_llc.h>
! 73:
! 74: #include <machine/endian.h>
! 75:
! 76: #include <netatalk/at.h>
! 77: #include <netatalk/at_var.h>
! 78: #include <netatalk/aarp.h>
! 79: #include <netatalk/ddp_var.h>
! 80: #include <netatalk/phase2.h>
! 81: #include <netatalk/at_extern.h>
! 82:
! 83: static void aarptimer(void *);
! 84: struct ifaddr *at_ifawithnet(struct sockaddr_at *, struct ifaddr *);
! 85: static void aarpwhohas(struct arpcom *, struct sockaddr_at *);
! 86: int aarpresolve(struct arpcom *, struct mbuf *,
! 87: struct sockaddr_at *, u_int8_t *);
! 88: void aarpinput(struct arpcom *, struct mbuf *);
! 89: static void at_aarpinput(struct arpcom *, struct mbuf *);
! 90: static void aarptfree(struct aarptab *);
! 91: struct aarptab *aarptnew(struct at_addr *);
! 92: void aarpprobe(void *);
! 93: void aarp_clean(void);
! 94:
! 95: #ifdef GATEWAY
! 96: #define AARPTAB_BSIZ 16
! 97: #define AARPTAB_NB 37
! 98: #else
! 99: #define AARPTAB_BSIZ 9
! 100: #define AARPTAB_NB 19
! 101: #endif /* GATEWAY */
! 102:
! 103: #define AARPTAB_SIZE (AARPTAB_BSIZ * AARPTAB_NB)
! 104: struct aarptab aarptab[AARPTAB_SIZE];
! 105: int aarptab_size = AARPTAB_SIZE;
! 106:
! 107: struct timeout aarpprobe_timeout;
! 108: struct timeout aarptimer_timeout;
! 109:
! 110: #define AARPTAB_HASH(a) \
! 111: ((((a).s_net << 8 ) + (a).s_node ) % AARPTAB_NB )
! 112:
! 113: #define AARPTAB_LOOK(aat,addr) { \
! 114: int n; \
! 115: aat = &aarptab[ AARPTAB_HASH(addr) * AARPTAB_BSIZ ]; \
! 116: for ( n = 0; n < AARPTAB_BSIZ; n++, aat++ ) \
! 117: if ( aat->aat_ataddr.s_net == (addr).s_net && \
! 118: aat->aat_ataddr.s_node == (addr).s_node ) \
! 119: break; \
! 120: if ( n >= AARPTAB_BSIZ ) \
! 121: aat = 0; \
! 122: }
! 123:
! 124: #define AARPT_AGE (60 * 1)
! 125: #define AARPT_KILLC 20
! 126: #define AARPT_KILLI 3
! 127:
! 128: u_int8_t atmulticastaddr[ 6 ] = {
! 129: 0x09, 0x00, 0x07, 0xff, 0xff, 0xff,
! 130: };
! 131:
! 132: u_int8_t at_org_code[ 3 ] = {
! 133: 0x08, 0x00, 0x07,
! 134: };
! 135: u_int8_t aarp_org_code[ 3 ] = {
! 136: 0x00, 0x00, 0x00,
! 137: };
! 138:
! 139: /*ARGSUSED*/
! 140: static void
! 141: aarptimer(v)
! 142: void *v;
! 143: {
! 144: struct aarptab *aat;
! 145: int i, s;
! 146:
! 147: timeout_add(&aarptimer_timeout, AARPT_AGE * hz);
! 148: aat = aarptab;
! 149: for ( i = 0; i < AARPTAB_SIZE; i++, aat++ ) {
! 150: if ( aat->aat_flags == 0 || ( aat->aat_flags & ATF_PERM ))
! 151: continue;
! 152: if ( ++aat->aat_timer < (( aat->aat_flags & ATF_COM ) ?
! 153: AARPT_KILLC : AARPT_KILLI ))
! 154: continue;
! 155: s = splnet();
! 156: aarptfree( aat );
! 157: splx( s );
! 158: }
! 159: }
! 160:
! 161: struct ifaddr *
! 162: at_ifawithnet( sat, ifa )
! 163: struct sockaddr_at *sat;
! 164: struct ifaddr *ifa;
! 165: {
! 166: struct sockaddr_at *sat2;
! 167: struct netrange *nr;
! 168:
! 169: for (; ifa; ifa = ifa->ifa_list.tqe_next ) {
! 170: if ( ifa->ifa_addr->sa_family != AF_APPLETALK ) {
! 171: continue;
! 172: }
! 173: sat2 = satosat( ifa->ifa_addr );
! 174: if ( sat2->sat_addr.s_net == sat->sat_addr.s_net ) {
! 175: break;
! 176: }
! 177: nr = (struct netrange *)(sat2->sat_zero);
! 178: if( (nr->nr_phase == 2 )
! 179: && (ntohs(nr->nr_firstnet) <= ntohs(sat->sat_addr.s_net))
! 180: && (ntohs(nr->nr_lastnet) >= ntohs(sat->sat_addr.s_net))) {
! 181: break;
! 182: }
! 183: }
! 184: return( ifa );
! 185: }
! 186:
! 187: static void
! 188: aarpwhohas( ac, sat )
! 189: struct arpcom *ac;
! 190: struct sockaddr_at *sat;
! 191: {
! 192: struct mbuf *m;
! 193: struct ether_header *eh;
! 194: struct ether_aarp *ea;
! 195: struct at_ifaddr *aa;
! 196: struct llc *llc;
! 197: struct sockaddr sa;
! 198:
! 199: if (( m = m_gethdr( M_DONTWAIT, MT_DATA )) == NULL ) {
! 200: return;
! 201: }
! 202: m->m_len = sizeof( *ea );
! 203: m->m_pkthdr.len = sizeof( *ea );
! 204: MH_ALIGN( m, sizeof( *ea ));
! 205:
! 206: ea = mtod( m, struct ether_aarp *);
! 207: bzero((caddr_t)ea, sizeof( *ea ));
! 208:
! 209: ea->aarp_hrd = htons( AARPHRD_ETHER );
! 210: ea->aarp_pro = htons( ETHERTYPE_AT );
! 211: ea->aarp_hln = sizeof( ea->aarp_sha );
! 212: ea->aarp_pln = sizeof( ea->aarp_spu );
! 213: ea->aarp_op = htons( AARPOP_REQUEST );
! 214: bcopy((caddr_t)ac->ac_enaddr, (caddr_t)ea->aarp_sha,
! 215: sizeof( ea->aarp_sha ));
! 216:
! 217: /*
! 218: * We need to check whether the output ethernet type should
! 219: * be phase 1 or 2. We have the interface that we'll be sending
! 220: * the aarp out. We need to find an AppleTalk network on that
! 221: * interface with the same address as we're looking for. If the
! 222: * net is phase 2, generate an 802.2 and SNAP header.
! 223: */
! 224: if (( aa = (struct at_ifaddr *)
! 225: at_ifawithnet( sat, ac->ac_if.if_addrlist.tqh_first )) == NULL ) {
! 226: m_freem( m );
! 227: return;
! 228: }
! 229:
! 230: eh = (struct ether_header *)sa.sa_data;
! 231:
! 232: if ( aa->aa_flags & AFA_PHASE2 ) {
! 233: bcopy((caddr_t)atmulticastaddr, (caddr_t)eh->ether_dhost,
! 234: sizeof( eh->ether_dhost ));
! 235: eh->ether_type = htons(AT_LLC_SIZE + sizeof(struct ether_aarp));
! 236: M_PREPEND( m, AT_LLC_SIZE, M_DONTWAIT );
! 237: if (!m)
! 238: return;
! 239:
! 240: llc = mtod( m, struct llc *);
! 241: llc->llc_dsap = llc->llc_ssap = LLC_SNAP_LSAP;
! 242: llc->llc_control = LLC_UI;
! 243: bcopy( aarp_org_code, llc->llc_org_code, sizeof( aarp_org_code ));
! 244: llc->llc_ether_type = htons( ETHERTYPE_AARP );
! 245:
! 246: bcopy( &AA_SAT( aa )->sat_addr.s_net, ea->aarp_spnet,
! 247: sizeof( ea->aarp_spnet ));
! 248: ea->aarp_spnode = AA_SAT( aa )->sat_addr.s_node;
! 249: bcopy( &sat->sat_addr.s_net, ea->aarp_tpnet,
! 250: sizeof( ea->aarp_tpnet ));
! 251: ea->aarp_tpnode = sat->sat_addr.s_node;
! 252: } else {
! 253: bcopy((caddr_t)etherbroadcastaddr, (caddr_t)eh->ether_dhost,
! 254: sizeof( eh->ether_dhost ));
! 255: eh->ether_type = htons( ETHERTYPE_AARP );
! 256:
! 257: ea->aarp_spa = AA_SAT( aa )->sat_addr.s_node;
! 258: ea->aarp_tpa = sat->sat_addr.s_node;
! 259: }
! 260:
! 261: sa.sa_len = sizeof( struct sockaddr );
! 262: sa.sa_family = AF_UNSPEC;
! 263: /* XXX The NULL should be a struct rtentry. TBD */
! 264: (*ac->ac_if.if_output)(&ac->ac_if, m, &sa , NULL);
! 265: }
! 266:
! 267: int
! 268: aarpresolve( ac, m, destsat, desten )
! 269: struct arpcom *ac;
! 270: struct mbuf *m;
! 271: struct sockaddr_at *destsat;
! 272: u_int8_t *desten;
! 273: {
! 274: struct at_ifaddr *aa;
! 275: struct aarptab *aat;
! 276: int s;
! 277:
! 278: if ( at_broadcast( destsat )) {
! 279: if (( aa = (struct at_ifaddr *)at_ifawithnet( destsat,
! 280: ((struct ifnet *)ac)->if_addrlist.tqh_first )) == NULL ) {
! 281: m_freem( m );
! 282: return( 0 );
! 283: }
! 284: if ( aa->aa_flags & AFA_PHASE2 ) {
! 285: bcopy( (caddr_t)atmulticastaddr, (caddr_t)desten,
! 286: sizeof( atmulticastaddr ));
! 287: } else {
! 288: bcopy( (caddr_t)etherbroadcastaddr, (caddr_t)desten,
! 289: sizeof( etherbroadcastaddr ));
! 290: }
! 291: return( 1 );
! 292: }
! 293:
! 294: s = splnet();
! 295: AARPTAB_LOOK( aat, destsat->sat_addr );
! 296: if ( aat == 0 ) { /* No entry */
! 297: aat = aarptnew( &destsat->sat_addr );
! 298: if ( aat == 0 ) { /* XXX allocate more */
! 299: panic( "aarpresolve: no free entry" );
! 300: }
! 301: aat->aat_hold = m;
! 302: aarpwhohas( ac, destsat );
! 303: splx( s );
! 304: return( 0 );
! 305: }
! 306: /* found an entry */
! 307: aat->aat_timer = 0;
! 308: if ( aat->aat_flags & ATF_COM ) { /* entry is COMplete */
! 309: bcopy( (caddr_t)aat->aat_enaddr, (caddr_t)desten,
! 310: sizeof( aat->aat_enaddr ));
! 311: splx( s );
! 312: return( 1 );
! 313: }
! 314: /* entry has not completed */
! 315: if ( aat->aat_hold ) {
! 316: m_freem( aat->aat_hold );
! 317: }
! 318: aat->aat_hold = m;
! 319: aarpwhohas( ac, destsat );
! 320: splx( s );
! 321: return( 0 );
! 322: }
! 323:
! 324: void
! 325: aarpinput( ac, m )
! 326: struct arpcom *ac;
! 327: struct mbuf *m;
! 328: {
! 329: struct arphdr *ar;
! 330:
! 331: if ( ac->ac_if.if_flags & IFF_NOARP )
! 332: goto out;
! 333:
! 334: if ( m->m_len < sizeof( struct arphdr )) {
! 335: goto out;
! 336: }
! 337:
! 338: ar = mtod( m, struct arphdr *);
! 339: if ( ntohs( ar->ar_hrd ) != AARPHRD_ETHER ) {
! 340: goto out;
! 341: }
! 342:
! 343: if ( m->m_len < sizeof( struct arphdr ) + 2 * ar->ar_hln +
! 344: 2 * ar->ar_pln ) {
! 345: goto out;
! 346: }
! 347:
! 348: switch( ntohs( ar->ar_pro )) {
! 349: case ETHERTYPE_AT :
! 350: at_aarpinput( ac, m );
! 351: return;
! 352:
! 353: default:
! 354: break;
! 355: }
! 356:
! 357: out:
! 358: m_freem( m );
! 359: }
! 360:
! 361:
! 362: static void
! 363: at_aarpinput( ac, m )
! 364: struct arpcom *ac;
! 365: struct mbuf *m;
! 366: {
! 367: struct ether_aarp *ea;
! 368: struct at_ifaddr *aa;
! 369: struct aarptab *aat;
! 370: struct ether_header *eh;
! 371: struct llc *llc;
! 372: struct sockaddr_at sat;
! 373: struct sockaddr sa;
! 374: struct at_addr spa, tpa, ma;
! 375: int op;
! 376: u_int16_t net;
! 377:
! 378: ea = mtod( m, struct ether_aarp *);
! 379:
! 380: /* Check to see if from my hardware address */
! 381: if ( !bcmp(( caddr_t )ea->aarp_sha, ( caddr_t )ac->ac_enaddr,
! 382: sizeof( ac->ac_enaddr ))) {
! 383: m_freem( m );
! 384: return;
! 385: }
! 386:
! 387: /*
! 388: * Check if from broadcast address. This could be a more robust
! 389: * check, since we could look for multicasts. XXX
! 390: */
! 391: if ( !bcmp(( caddr_t )ea->aarp_sha, ( caddr_t )etherbroadcastaddr,
! 392: sizeof( etherbroadcastaddr ))) {
! 393: log( LOG_ERR,
! 394: "aarp: source is broadcast!\n" );
! 395: m_freem( m );
! 396: return;
! 397: }
! 398:
! 399: op = ntohs( ea->aarp_op );
! 400: bcopy( ea->aarp_tpnet, &net, sizeof( net ));
! 401:
! 402: if ( net != 0 ) {
! 403: sat.sat_len = sizeof(struct sockaddr_at);
! 404: sat.sat_family = AF_APPLETALK;
! 405: sat.sat_addr.s_net = net;
! 406: if (( aa = (struct at_ifaddr *)at_ifawithnet( &sat,
! 407: ac->ac_if.if_addrlist.tqh_first )) == NULL ) {
! 408: m_freem( m );
! 409: return;
! 410: }
! 411: bcopy( ea->aarp_spnet, &spa.s_net, sizeof( spa.s_net ));
! 412: bcopy( ea->aarp_tpnet, &tpa.s_net, sizeof( tpa.s_net ));
! 413: } else {
! 414: /*
! 415: * Since we don't know the net, we just look for the first
! 416: * phase 1 address on the interface.
! 417: */
! 418: for ( aa = (struct at_ifaddr *)ac->ac_if.if_addrlist.tqh_first; aa;
! 419: aa = (struct at_ifaddr *)aa->aa_ifa.ifa_list.tqe_next ) {
! 420: if ( AA_SAT( aa )->sat_family == AF_APPLETALK &&
! 421: ( aa->aa_flags & AFA_PHASE2 ) == 0 ) {
! 422: break;
! 423: }
! 424: }
! 425: if ( aa == NULL ) {
! 426: m_freem( m );
! 427: return;
! 428: }
! 429: tpa.s_net = spa.s_net = AA_SAT( aa )->sat_addr.s_net;
! 430: }
! 431:
! 432: spa.s_node = ea->aarp_spnode;
! 433: tpa.s_node = ea->aarp_tpnode;
! 434: ma.s_net = AA_SAT( aa )->sat_addr.s_net;
! 435: ma.s_node = AA_SAT( aa )->sat_addr.s_node;
! 436:
! 437: /*
! 438: * This looks like it's from us.
! 439: */
! 440: if ( spa.s_net == ma.s_net && spa.s_node == ma.s_node ) {
! 441: if ( aa->aa_flags & AFA_PROBING ) {
! 442: /*
! 443: * We're probing, someone either responded to our probe, or
! 444: * probed for the same address we'd like to use. Change the
! 445: * address we're probing for.
! 446: */
! 447: timeout_del(&aarpprobe_timeout);
! 448: wakeup( aa );
! 449: m_freem( m );
! 450: return;
! 451: } else if ( op != AARPOP_PROBE ) {
! 452: /*
! 453: * This is not a probe, and we're not probing. This means
! 454: * that someone's saying they have the same source address
! 455: * as the one we're using. Get upset...
! 456: */
! 457: /* XXX use ether_ntoa */
! 458: log( LOG_ERR,
! 459: "aarp: duplicate AT address!! %x:%x:%x:%x:%x:%x\n",
! 460: ea->aarp_sha[ 0 ], ea->aarp_sha[ 1 ], ea->aarp_sha[ 2 ],
! 461: ea->aarp_sha[ 3 ], ea->aarp_sha[ 4 ], ea->aarp_sha[ 5 ]);
! 462: m_freem( m );
! 463: return;
! 464: }
! 465: }
! 466:
! 467: AARPTAB_LOOK( aat, spa );
! 468: if ( aat ) {
! 469: if ( op == AARPOP_PROBE ) {
! 470: /*
! 471: * Someone's probing for spa, dealocate the one we've got,
! 472: * so that if the prober keeps the address, we'll be able
! 473: * to arp for him.
! 474: */
! 475: aarptfree( aat );
! 476: m_freem( m );
! 477: return;
! 478: }
! 479:
! 480: bcopy(( caddr_t )ea->aarp_sha, ( caddr_t )aat->aat_enaddr,
! 481: sizeof( ea->aarp_sha ));
! 482: aat->aat_flags |= ATF_COM;
! 483: if ( aat->aat_hold ) {
! 484: sat.sat_len = sizeof(struct sockaddr_at);
! 485: sat.sat_family = AF_APPLETALK;
! 486: sat.sat_addr = spa;
! 487: /* XXX the NULL should be a struct rtentry */
! 488: (*ac->ac_if.if_output)( &ac->ac_if, aat->aat_hold,
! 489: (struct sockaddr *)&sat, NULL );
! 490: aat->aat_hold = 0;
! 491: }
! 492: }
! 493:
! 494: if ( aat == 0 && tpa.s_net == ma.s_net && tpa.s_node == ma.s_node
! 495: && op != AARPOP_PROBE ) {
! 496: if ( (aat = aarptnew( &spa ))) {
! 497: bcopy(( caddr_t )ea->aarp_sha, ( caddr_t )aat->aat_enaddr,
! 498: sizeof( ea->aarp_sha ));
! 499: aat->aat_flags |= ATF_COM;
! 500: }
! 501: }
! 502:
! 503: /*
! 504: * Don't respond to responses, and never respond if we're
! 505: * still probing.
! 506: */
! 507: if ( tpa.s_net != ma.s_net || tpa.s_node != ma.s_node ||
! 508: op == AARPOP_RESPONSE || ( aa->aa_flags & AFA_PROBING )) {
! 509: m_freem( m );
! 510: return;
! 511: }
! 512:
! 513: bcopy(( caddr_t )ea->aarp_sha, ( caddr_t )ea->aarp_tha,
! 514: sizeof( ea->aarp_sha ));
! 515: bcopy(( caddr_t )ac->ac_enaddr, ( caddr_t )ea->aarp_sha,
! 516: sizeof( ea->aarp_sha ));
! 517:
! 518: /* XXX FreeBSD has an 'XXX' here but no comment as to why. */
! 519: eh = (struct ether_header *)sa.sa_data;
! 520: bcopy(( caddr_t )ea->aarp_tha, ( caddr_t )eh->ether_dhost,
! 521: sizeof( eh->ether_dhost ));
! 522:
! 523: if ( aa->aa_flags & AFA_PHASE2 ) {
! 524: eh->ether_type = htons( AT_LLC_SIZE +
! 525: sizeof( struct ether_aarp ));
! 526: M_PREPEND( m, AT_LLC_SIZE, M_DONTWAIT );
! 527: if ( m == NULL ) {
! 528: return;
! 529: }
! 530: llc = mtod( m, struct llc *);
! 531: llc->llc_dsap = llc->llc_ssap = LLC_SNAP_LSAP;
! 532: llc->llc_control = LLC_UI;
! 533: bcopy( aarp_org_code, llc->llc_org_code, sizeof( aarp_org_code ));
! 534: llc->llc_ether_type = htons( ETHERTYPE_AARP );
! 535:
! 536: bcopy( ea->aarp_spnet, ea->aarp_tpnet, sizeof( ea->aarp_tpnet ));
! 537: bcopy( &ma.s_net, ea->aarp_spnet, sizeof( ea->aarp_spnet ));
! 538: } else {
! 539: eh->ether_type = htons( ETHERTYPE_AARP );
! 540: }
! 541:
! 542: ea->aarp_tpnode = ea->aarp_spnode;
! 543: ea->aarp_spnode = ma.s_node;
! 544: ea->aarp_op = htons( AARPOP_RESPONSE );
! 545:
! 546: sa.sa_len = sizeof( struct sockaddr );
! 547: sa.sa_family = AF_UNSPEC;
! 548: /* XXX the NULL should be a struct rtentry */
! 549: (*ac->ac_if.if_output)( &ac->ac_if, m, &sa, NULL );
! 550: return;
! 551: }
! 552:
! 553: static void
! 554: aarptfree( aat )
! 555: struct aarptab *aat;
! 556: {
! 557:
! 558: if ( aat->aat_hold )
! 559: m_freem( aat->aat_hold );
! 560: aat->aat_hold = 0;
! 561: aat->aat_timer = aat->aat_flags = 0;
! 562: aat->aat_ataddr.s_net = 0;
! 563: aat->aat_ataddr.s_node = 0;
! 564: }
! 565:
! 566: struct aarptab *
! 567: aarptnew( addr )
! 568: struct at_addr *addr;
! 569: {
! 570: int n;
! 571: int oldest = -1;
! 572: struct aarptab *aat, *aato = NULL;
! 573: static int first = 1;
! 574:
! 575: if ( first ) {
! 576: first = 0;
! 577: timeout_set(&aarptimer_timeout, aarptimer, NULL);
! 578: timeout_add(&aarptimer_timeout, hz);
! 579: }
! 580: aat = &aarptab[ AARPTAB_HASH( *addr ) * AARPTAB_BSIZ ];
! 581: for ( n = 0; n < AARPTAB_BSIZ; n++, aat++ ) {
! 582: if ( aat->aat_flags == 0 )
! 583: goto out;
! 584: if ( aat->aat_flags & ATF_PERM )
! 585: continue;
! 586: if ((int) aat->aat_timer > oldest ) {
! 587: oldest = aat->aat_timer;
! 588: aato = aat;
! 589: }
! 590: }
! 591: if ( aato == NULL )
! 592: return( NULL );
! 593: aat = aato;
! 594: aarptfree( aat );
! 595: out:
! 596: aat->aat_ataddr = *addr;
! 597: aat->aat_flags = ATF_INUSE;
! 598: return( aat );
! 599: }
! 600:
! 601: void
! 602: aarpprobe( arg )
! 603: void *arg;
! 604: {
! 605: struct arpcom *ac = (struct arpcom *) arg;
! 606: struct mbuf *m;
! 607: struct ether_header *eh;
! 608: struct ether_aarp *ea;
! 609: struct at_ifaddr *aa;
! 610: struct llc *llc;
! 611: struct sockaddr sa;
! 612:
! 613: /*
! 614: * We need to check whether the output ethernet type should
! 615: * be phase 1 or 2. We have the interface that we'll be sending
! 616: * the aarp out. We need to find an AppleTalk network on that
! 617: * interface with the same address as we're looking for. If the
! 618: * net is phase 2, generate an 802.2 and SNAP header.
! 619: */
! 620: for ( aa = (struct at_ifaddr *)ac->ac_if.if_addrlist.tqh_first; aa;
! 621: aa = (struct at_ifaddr *)aa->aa_ifa.ifa_list.tqe_next) {
! 622: if ( AA_SAT( aa )->sat_family == AF_APPLETALK &&
! 623: ( aa->aa_flags & AFA_PROBING )) {
! 624: break;
! 625: }
! 626: }
! 627: if ( aa == NULL ) { /* serious error XXX */
! 628: printf( "aarpprobe why did this happen?!\n" );
! 629: return;
! 630: }
! 631:
! 632: if ( aa->aa_probcnt <= 0 ) {
! 633: aa->aa_flags &= ~AFA_PROBING;
! 634: wakeup( aa );
! 635: return;
! 636: } else {
! 637: timeout_set(&aarpprobe_timeout, aarpprobe, ac);
! 638: timeout_add(&aarpprobe_timeout, hz / 5);
! 639: }
! 640:
! 641: if (( m = m_gethdr( M_DONTWAIT, MT_DATA )) == NULL ) {
! 642: return;
! 643: }
! 644: m->m_len = sizeof( *ea );
! 645: m->m_pkthdr.len = sizeof( *ea );
! 646: MH_ALIGN( m, sizeof( *ea ));
! 647:
! 648: ea = mtod( m, struct ether_aarp *);
! 649: bzero((caddr_t)ea, sizeof( *ea ));
! 650:
! 651: ea->aarp_hrd = htons( AARPHRD_ETHER );
! 652: ea->aarp_pro = htons( ETHERTYPE_AT );
! 653: ea->aarp_hln = sizeof( ea->aarp_sha );
! 654: ea->aarp_pln = sizeof( ea->aarp_spu );
! 655: ea->aarp_op = htons( AARPOP_PROBE );
! 656: bcopy((caddr_t)ac->ac_enaddr, (caddr_t)ea->aarp_sha,
! 657: sizeof( ea->aarp_sha ));
! 658:
! 659: eh = (struct ether_header *)sa.sa_data;
! 660:
! 661: if ( aa->aa_flags & AFA_PHASE2 ) {
! 662: bcopy((caddr_t)atmulticastaddr, (caddr_t)eh->ether_dhost,
! 663: sizeof( eh->ether_dhost ));
! 664: eh->ether_type = htons( AT_LLC_SIZE +
! 665: sizeof( struct ether_aarp ));
! 666: M_PREPEND( m, AT_LLC_SIZE, M_DONTWAIT );
! 667: if (!m)
! 668: return;
! 669:
! 670: llc = mtod( m, struct llc *);
! 671: llc->llc_dsap = llc->llc_ssap = LLC_SNAP_LSAP;
! 672: llc->llc_control = LLC_UI;
! 673: bcopy( aarp_org_code, llc->llc_org_code, sizeof( aarp_org_code ));
! 674: llc->llc_ether_type = htons( ETHERTYPE_AARP );
! 675:
! 676: bcopy( &AA_SAT( aa )->sat_addr.s_net, ea->aarp_spnet,
! 677: sizeof( ea->aarp_spnet ));
! 678: bcopy( &AA_SAT( aa )->sat_addr.s_net, ea->aarp_tpnet,
! 679: sizeof( ea->aarp_tpnet ));
! 680: ea->aarp_spnode = ea->aarp_tpnode = AA_SAT( aa )->sat_addr.s_node;
! 681: } else {
! 682: bcopy((caddr_t)etherbroadcastaddr, (caddr_t)eh->ether_dhost,
! 683: sizeof( eh->ether_dhost ));
! 684: eh->ether_type = htons( ETHERTYPE_AARP );
! 685: ea->aarp_spa = ea->aarp_tpa = AA_SAT( aa )->sat_addr.s_node;
! 686: }
! 687:
! 688: sa.sa_len = sizeof( struct sockaddr );
! 689: sa.sa_family = AF_UNSPEC;
! 690: /* XXX the NULL should be a struct rtentry */
! 691: (*ac->ac_if.if_output)(&ac->ac_if, m, &sa, NULL );
! 692: aa->aa_probcnt--;
! 693: }
! 694:
! 695: void
! 696: aarp_clean(void)
! 697: {
! 698: struct aarptab *aat;
! 699: int i;
! 700:
! 701: timeout_del(&aarptimer_timeout);
! 702: for ( i = 0, aat = aarptab; i < AARPTAB_SIZE; i++, aat++ ) {
! 703: if ( aat->aat_hold ) {
! 704: m_freem( aat->aat_hold );
! 705: }
! 706: }
! 707: }
CVSweb