/* * $Id: aarp.c,v 1.3 2002-01-03 17:49:39 sibaz Exp $ * * Copyright (c) 1990,1991 Regents of The University of Michigan. * All Rights Reserved. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif /* HAVE_CONFIG_H */ #include #include #include #include #include #include #ifndef _IBMR2 #include #endif /* _IBMR2 */ #include #include #include #include #undef s_net #include #ifdef _IBMR2 #include #include #include #include #endif /* _IBMR2 */ #include "at.h" #include "at_var.h" #include "aarp.h" #include "ddp_var.h" #include "endian.h" #include "phase2.h" #ifdef GATEWAY #define AARPTAB_BSIZ 16 #define AARPTAB_NB 37 #else /* GATEWAY */ #define AARPTAB_BSIZ 9 #define AARPTAB_NB 19 #endif /* GATEWAY */ #define AARPTAB_SIZE (AARPTAB_BSIZ * AARPTAB_NB) struct aarptab aarptab[AARPTAB_SIZE]; int aarptab_size = AARPTAB_SIZE; #define AARPTAB_HASH(a) \ ((((a).s_net << 8 ) + (a).s_node ) % AARPTAB_NB ) #define AARPTAB_LOOK(aat,addr) { \ int n; \ aat = &aarptab[ AARPTAB_HASH(addr) * AARPTAB_BSIZ ]; \ for ( n = 0; n < AARPTAB_BSIZ; n++, aat++ ) \ if ( aat->aat_ataddr.s_net == (addr).s_net && \ aat->aat_ataddr.s_node == (addr).s_node ) \ break; \ if ( n >= AARPTAB_BSIZ ) \ aat = 0; \ } #define AARPT_AGE (60 * 1) #define AARPT_KILLC 20 #define AARPT_KILLI 3 #ifdef sun extern struct ether_addr etherbroadcastaddr; #else /* sun */ extern u_char etherbroadcastaddr[6]; #endif /* sun */ u_char atmulticastaddr[ 6 ] = { 0x09, 0x00, 0x07, 0xff, 0xff, 0xff, }; u_char at_org_code[ 3 ] = { 0x08, 0x00, 0x07, }; u_char aarp_org_code[ 3 ] = { 0x00, 0x00, 0x00, }; aarptimer() { struct aarptab *aat; int i, s; timeout( aarptimer, (caddr_t)0, AARPT_AGE * hz ); aat = aarptab; for ( i = 0; i < AARPTAB_SIZE; i++, aat++ ) { if ( aat->aat_flags == 0 || ( aat->aat_flags & ATF_PERM )) continue; if ( ++aat->aat_timer < (( aat->aat_flags & ATF_COM ) ? AARPT_KILLC : AARPT_KILLI )) continue; s = splimp(); aarptfree( aat ); splx( s ); } } struct ifaddr * at_ifawithnet( sat, ifa ) struct sockaddr_at *sat; struct ifaddr *ifa; { struct at_ifaddr *aa; for (; ifa; ifa = ifa->ifa_next ) { #ifdef BSD4_4 if ( ifa->ifa_addr->sa_family != AF_APPLETALK ) { continue; } if ( satosat( ifa->ifa_addr )->sat_addr.s_net == sat->sat_addr.s_net ) { break; } #else /* BSD4_4 */ if ( ifa->ifa_addr.sa_family != AF_APPLETALK ) { continue; } aa = (struct at_ifaddr *)ifa; if ( ntohs( sat->sat_addr.s_net ) >= ntohs( aa->aa_firstnet ) && ntohs( sat->sat_addr.s_net ) <= ntohs( aa->aa_lastnet )) { break; } #endif /* BSD4_4 */ } return( ifa ); } aarpwhohas( ac, sat ) struct arpcom *ac; struct sockaddr_at *sat; { struct mbuf *m; struct ether_header *eh; struct ether_aarp *ea; struct at_ifaddr *aa; struct llc *llc; struct sockaddr sa; #ifdef BSD4_4 if (( m = m_gethdr( M_DONTWAIT, MT_DATA )) == NULL ) { return; } m->m_len = sizeof( *ea ); m->m_pkthdr.len = sizeof( *ea ); MH_ALIGN( m, sizeof( *ea )); #else /* BSD4_4 */ if (( m = m_get( M_DONTWAIT, MT_DATA )) == NULL ) { return; } m->m_len = sizeof( *ea ); m->m_off = MMAXOFF - sizeof( *ea ); #endif /* BSD4_4 */ ea = mtod( m, struct ether_aarp *); bzero((caddr_t)ea, sizeof( *ea )); ea->aarp_hrd = htons( AARPHRD_ETHER ); ea->aarp_pro = htons( ETHERTYPE_AT ); ea->aarp_hln = sizeof( ea->aarp_sha ); ea->aarp_pln = sizeof( ea->aarp_spu ); ea->aarp_op = htons( AARPOP_REQUEST ); #ifdef sun bcopy((caddr_t)&ac->ac_enaddr, (caddr_t)ea->aarp_sha, sizeof( ea->aarp_sha )); #else /* sun */ bcopy((caddr_t)ac->ac_enaddr, (caddr_t)ea->aarp_sha, sizeof( ea->aarp_sha )); #endif /* sun */ /* * We need to check whether the output ethernet type should * be phase 1 or 2. We have the interface that we'll be sending * the aarp out. We need to find an AppleTalk network on that * interface with the same address as we're looking for. If the * net is phase 2, generate an 802.2 and SNAP header. */ if (( aa = (struct at_ifaddr *)at_ifawithnet( sat, ac->ac_if.if_addrlist )) == NULL ) { m_freem( m ); return; } eh = (struct ether_header *)sa.sa_data; if ( aa->aa_flags & AFA_PHASE2 ) { #ifdef sun bcopy((caddr_t)atmulticastaddr, (caddr_t)&eh->ether_dhost, sizeof( eh->ether_dhost )); #else /* sun */ bcopy((caddr_t)atmulticastaddr, (caddr_t)eh->ether_dhost, sizeof( eh->ether_dhost )); #endif /* sun */ #if defined( sun ) && defined( i386 ) eh->ether_type = htons( sizeof( struct llc ) + sizeof( struct ether_aarp )); #else /* sun && i386 */ eh->ether_type = sizeof( struct llc ) + sizeof( struct ether_aarp ); #endif /* sun && i386 */ #ifdef BSD4_4 M_PREPEND( m, sizeof( struct llc ), M_WAIT ); #else /* BSD4_4 */ m->m_len += sizeof( struct llc ); m->m_off -= sizeof( struct llc ); #endif /* BSD4_4 */ llc = mtod( m, struct llc *); llc->llc_dsap = llc->llc_ssap = LLC_SNAP_LSAP; llc->llc_control = LLC_UI; bcopy( aarp_org_code, llc->llc_org_code, sizeof( aarp_org_code )); llc->llc_ether_type = htons( ETHERTYPE_AARP ); bcopy( &AA_SAT( aa )->sat_addr.s_net, ea->aarp_spnet, sizeof( ea->aarp_spnet )); ea->aarp_spnode = AA_SAT( aa )->sat_addr.s_node; bcopy( &sat->sat_addr.s_net, ea->aarp_tpnet, sizeof( ea->aarp_tpnet )); ea->aarp_tpnode = sat->sat_addr.s_node; } else { #ifdef sun bcopy((caddr_t)ðerbroadcastaddr, (caddr_t)&eh->ether_dhost, sizeof( eh->ether_dhost )); #else /* sun */ bcopy((caddr_t)etherbroadcastaddr, (caddr_t)eh->ether_dhost, sizeof( eh->ether_dhost )); #endif /* sun */ #if defined( sun ) && defined( i386 ) eh->ether_type = htons( ETHERTYPE_AARP ); #else /* sun && i386 */ eh->ether_type = ETHERTYPE_AARP; #endif /* sun && i386 */ ea->aarp_spa = AA_SAT( aa )->sat_addr.s_node; ea->aarp_tpa = sat->sat_addr.s_node; } #ifdef BSD4_4 sa.sa_len = sizeof( struct sockaddr ); #endif /* BSD4_4 */ sa.sa_family = AF_UNSPEC; (*ac->ac_if.if_output)(&ac->ac_if, m, &sa ); } aarpresolve( ac, m, destsat, desten ) struct arpcom *ac; struct mbuf *m; struct sockaddr_at *destsat; #ifdef sun struct ether_addr *desten; #else /* sun */ u_char *desten; #endif /* sun */ { struct at_ifaddr *aa; struct ifaddr ifa; struct aarptab *aat; int s; if ( at_broadcast( destsat )) { if (( aa = (struct at_ifaddr *)at_ifawithnet( destsat, ((struct ifnet *)ac)->if_addrlist )) == NULL ) { m_freem( m ); return( 0 ); } if ( aa->aa_flags & AFA_PHASE2 ) { bcopy( (caddr_t)atmulticastaddr, (caddr_t)desten, sizeof( atmulticastaddr )); } else { #ifdef sun bcopy( (caddr_t)ðerbroadcastaddr, (caddr_t)desten, sizeof( etherbroadcastaddr )); #else /* sun */ bcopy( (caddr_t)etherbroadcastaddr, (caddr_t)desten, sizeof( etherbroadcastaddr )); #endif /* sun */ } return( 1 ); } s = splimp(); AARPTAB_LOOK( aat, destsat->sat_addr ); if ( aat == 0 ) { /* No entry */ aat = aarptnew( &destsat->sat_addr ); if ( aat == 0 ) { panic( "aarpresolve: no free entry" ); } aat->aat_hold = m; aarpwhohas( ac, destsat ); splx( s ); return( 0 ); } /* found an entry */ aat->aat_timer = 0; if ( aat->aat_flags & ATF_COM ) { /* entry is COMplete */ bcopy( (caddr_t)aat->aat_enaddr, (caddr_t)desten, sizeof( aat->aat_enaddr )); splx( s ); return( 1 ); } /* entry has not completed */ if ( aat->aat_hold ) { m_freem( aat->aat_hold ); } aat->aat_hold = m; aarpwhohas( ac, destsat ); splx( s ); return( 0 ); } aarpinput( ac, m ) struct arpcom *ac; struct mbuf *m; { struct arphdr *ar; if ( ac->ac_if.if_flags & IFF_NOARP ) goto out; #ifndef BSD4_4 IF_ADJ( m ); #endif /* BSD4_4 */ if ( m->m_len < sizeof( struct arphdr )) { goto out; } ar = mtod( m, struct arphdr *); if ( ntohs( ar->ar_hrd ) != AARPHRD_ETHER ) { goto out; } if ( m->m_len < sizeof( struct arphdr ) + 2 * ar->ar_hln + 2 * ar->ar_pln ) { goto out; } switch( ntohs( ar->ar_pro )) { case ETHERTYPE_AT : at_aarpinput( ac, m ); return; default: break; } out: m_freem( m ); } at_aarpinput( ac, m ) struct arpcom *ac; struct mbuf *m; { struct mbuf *m0; struct ether_aarp *ea; struct at_ifaddr *aa; struct aarptab *aat; struct ether_header *eh; struct llc *llc; struct sockaddr_at sat; struct sockaddr sa; struct at_addr spa, tpa, ma; int op, s; u_short net; ea = mtod( m, struct ether_aarp *); /* Check to see if from my hardware address */ #ifdef sun if ( !bcmp(( caddr_t )ea->aarp_sha, ( caddr_t )&ac->ac_enaddr, sizeof( ac->ac_enaddr ))) { m_freem( m ); return; } #else /* sun */ if ( !bcmp(( caddr_t )ea->aarp_sha, ( caddr_t )ac->ac_enaddr, sizeof( ac->ac_enaddr ))) { m_freem( m ); return; } #endif /* sun */ /* * Check if from broadcast address. This could be a more robust * check, since we could look for multicasts. */ #ifdef sun if ( !bcmp(( caddr_t )ea->aarp_sha, ( caddr_t )ðerbroadcastaddr, sizeof( etherbroadcastaddr ))) { log( LOG_ERR, "aarp: source is broadcast!\n" ); m_freem( m ); return; } #else /* sun */ if ( !bcmp(( caddr_t )ea->aarp_sha, ( caddr_t )etherbroadcastaddr, sizeof( etherbroadcastaddr ))) { #ifndef _IBMR2 #ifdef ultrix mprintf( LOG_ERR, #else /* ultrix */ log( LOG_ERR, #endif /* ultrix */ "aarp: source is broadcast!\n" ); #endif /* ! _IBMR2 */ m_freem( m ); return; } #endif /* sun */ op = ntohs( ea->aarp_op ); bcopy( ea->aarp_tpnet, &net, sizeof( net )); if ( net != 0 ) { sat.sat_family = AF_APPLETALK; sat.sat_addr.s_net = net; if (( aa = (struct at_ifaddr *)at_ifawithnet( &sat, ac->ac_if.if_addrlist )) == NULL ) { m_freem( m ); return; } bcopy( ea->aarp_spnet, &spa.s_net, sizeof( spa.s_net )); bcopy( ea->aarp_tpnet, &tpa.s_net, sizeof( tpa.s_net )); } else { /* * Since we don't know the net, we just look for the first * phase 1 address on the interface. */ for ( aa = (struct at_ifaddr *)ac->ac_if.if_addrlist; aa; aa = (struct at_ifaddr *)aa->aa_ifa.ifa_next ) { if ( AA_SAT( aa )->sat_family == AF_APPLETALK && ( aa->aa_flags & AFA_PHASE2 ) == 0 ) { break; } } if ( aa == NULL ) { m_freem( m ); return; } tpa.s_net = spa.s_net = AA_SAT( aa )->sat_addr.s_net; } spa.s_node = ea->aarp_spnode; tpa.s_node = ea->aarp_tpnode; ma.s_net = AA_SAT( aa )->sat_addr.s_net; ma.s_node = AA_SAT( aa )->sat_addr.s_node; /* * This looks like it's from us. */ if ( spa.s_net == ma.s_net && spa.s_node == ma.s_node ) { if ( aa->aa_flags & AFA_PROBING ) { /* * We're probing, someone either responded to our probe, or * probed for the same address we'd like to use. Change the * address we're probing for. */ untimeout( aarpprobe, ac ); wakeup( aa ); m_freem( m ); return; } else if ( op != AARPOP_PROBE ) { /* * This is not a probe, and we're not probing. This means * that someone's saying they have the same source address * as the one we're using. Get upset... */ #ifndef _IBMR2 #ifdef ultrix mprintf( LOG_ERR, #else /* ultrix */ log( LOG_ERR, #endif /* ultrix */ "aarp: duplicate AT address!! %x:%x:%x:%x:%x:%x\n", ea->aarp_sha[ 0 ], ea->aarp_sha[ 1 ], ea->aarp_sha[ 2 ], ea->aarp_sha[ 3 ], ea->aarp_sha[ 4 ], ea->aarp_sha[ 5 ]); #endif /* ! _IBMR2 */ m_freem( m ); return; } } AARPTAB_LOOK( aat, spa ); if ( aat ) { if ( op == AARPOP_PROBE ) { /* * Someone's probing for spa, dealocate the one we've got, * so that if the prober keeps the address, we'll be able * to arp for him. */ aarptfree( aat ); m_freem( m ); return; } bcopy(( caddr_t )ea->aarp_sha, ( caddr_t )aat->aat_enaddr, sizeof( ea->aarp_sha )); aat->aat_flags |= ATF_COM; if ( aat->aat_hold ) { #ifdef _IBMR2 /* * Like in ddp_output(), we can't rely on the if_output * routine to resolve AF_APPLETALK addresses, on the rs6k. * So, we fill the destination ethernet address here. * * This should really be replaced with something like * rsif_output(). XXX Will have to be for phase 2. */ /* XXX maybe fill in the rest of the frame header */ sat.sat_family = AF_UNSPEC; bcopy( aat->aat_enaddr, (*(struct sockaddr *)&sat).sa_data, sizeof( aat->aat_enaddr )); #else /* _IBMR2 */ sat.sat_family = AF_APPLETALK; sat.sat_addr = spa; #endif /* _IBMR2 */ (*ac->ac_if.if_output)( &ac->ac_if, aat->aat_hold, (struct sockaddr *)&sat ); aat->aat_hold = 0; } } if ( aat == 0 && tpa.s_net == ma.s_net && tpa.s_node == ma.s_node && op != AARPOP_PROBE ) { if ( aat = aarptnew( &spa )) { bcopy(( caddr_t )ea->aarp_sha, ( caddr_t )aat->aat_enaddr, sizeof( ea->aarp_sha )); aat->aat_flags |= ATF_COM; } } /* * Don't respond to responses, and never respond if we're * still probing. */ if ( tpa.s_net != ma.s_net || tpa.s_node != ma.s_node || op == AARPOP_RESPONSE || ( aa->aa_flags & AFA_PROBING )) { m_freem( m ); return; } bcopy(( caddr_t )ea->aarp_sha, ( caddr_t )ea->aarp_tha, sizeof( ea->aarp_sha )); #ifdef sun bcopy(( caddr_t )&ac->ac_enaddr, ( caddr_t )ea->aarp_sha, sizeof( ea->aarp_sha )); #else /* sun */ bcopy(( caddr_t )ac->ac_enaddr, ( caddr_t )ea->aarp_sha, sizeof( ea->aarp_sha )); #endif /* sun */ eh = (struct ether_header *)sa.sa_data; #ifdef sun bcopy(( caddr_t )ea->aarp_tha, ( caddr_t )&eh->ether_dhost, sizeof( eh->ether_dhost )); #else /* sun */ bcopy(( caddr_t )ea->aarp_tha, ( caddr_t )eh->ether_dhost, sizeof( eh->ether_dhost )); #endif /* sun */ if ( aa->aa_flags & AFA_PHASE2 ) { #if defined( sun ) && defined( i386 ) eh->ether_type = htons( sizeof( struct llc ) + sizeof( struct ether_aarp )); #else /* sun && i386 */ eh->ether_type = sizeof( struct llc ) + sizeof( struct ether_aarp ); #endif /* sun && i386 */ #ifdef BSD4_4 M_PREPEND( m, sizeof( struct llc ), M_DONTWAIT ); if ( m == NULL ) { m_freem( m ); return; } #else /* BSD4_4 */ MGET( m0, M_DONTWAIT, MT_HEADER ); if ( m0 == NULL ) { m_freem( m ); return; } m0->m_next = m; m = m0; m->m_off = MMAXOFF - sizeof( struct llc ); m->m_len = sizeof ( struct llc ); #endif /* BSD4_4 */ llc = mtod( m, struct llc *); llc->llc_dsap = llc->llc_ssap = LLC_SNAP_LSAP; llc->llc_control = LLC_UI; bcopy( aarp_org_code, llc->llc_org_code, sizeof( aarp_org_code )); llc->llc_ether_type = htons( ETHERTYPE_AARP ); bcopy( ea->aarp_spnet, ea->aarp_tpnet, sizeof( ea->aarp_tpnet )); bcopy( &ma.s_net, ea->aarp_spnet, sizeof( ea->aarp_spnet )); } else { #if defined( sun ) && defined( i386 ) eh->ether_type = htons( ETHERTYPE_AARP ); #else /* sun && i386 */ eh->ether_type = ETHERTYPE_AARP; #endif /* sun && i386 */ } ea->aarp_tpnode = ea->aarp_spnode; ea->aarp_spnode = ma.s_node; ea->aarp_op = htons( AARPOP_RESPONSE ); #ifdef BSD4_4 sa.sa_len = sizeof( struct sockaddr ); #endif /* BSD4_4 */ sa.sa_family = AF_UNSPEC; (*ac->ac_if.if_output)( &ac->ac_if, m, &sa ); return; } aarptfree( aat ) struct aarptab *aat; { if ( aat->aat_hold ) m_freem( aat->aat_hold ); aat->aat_hold = 0; aat->aat_timer = aat->aat_flags = 0; aat->aat_ataddr.s_net = 0; aat->aat_ataddr.s_node = 0; } struct aarptab * aarptnew( addr ) struct at_addr *addr; { int n; int oldest = -1; struct aarptab *aat, *aato = NULL; static int first = 1; if ( first ) { first = 0; timeout( aarptimer, (caddr_t)0, hz ); } aat = &aarptab[ AARPTAB_HASH( *addr ) * AARPTAB_BSIZ ]; for ( n = 0; n < AARPTAB_BSIZ; n++, aat++ ) { if ( aat->aat_flags == 0 ) goto out; if ( aat->aat_flags & ATF_PERM ) continue; if ((int) aat->aat_timer > oldest ) { oldest = aat->aat_timer; aato = aat; } } if ( aato == NULL ) return( NULL ); aat = aato; aarptfree( aat ); out: aat->aat_ataddr = *addr; aat->aat_flags = ATF_INUSE; return( aat ); } aarpprobe( ac ) struct arpcom *ac; { struct mbuf *m; struct ether_header *eh; struct ether_aarp *ea; struct at_ifaddr *aa; struct llc *llc; struct sockaddr sa; /* * We need to check whether the output ethernet type should * be phase 1 or 2. We have the interface that we'll be sending * the aarp out. We need to find an AppleTalk network on that * interface with the same address as we're looking for. If the * net is phase 2, generate an 802.2 and SNAP header. */ for ( aa = (struct at_ifaddr *)ac->ac_if.if_addrlist; aa; aa = (struct at_ifaddr *)aa->aa_ifa.ifa_next ) { if ( AA_SAT( aa )->sat_family == AF_APPLETALK && ( aa->aa_flags & AFA_PROBING )) { break; } } if ( aa == NULL ) { /* serious error XXX */ printf( "aarpprobe why did this happen?!\n" ); return; } if ( aa->aa_probcnt <= 0 ) { aa->aa_flags &= ~AFA_PROBING; wakeup( aa ); return; } else { timeout( aarpprobe, (caddr_t)ac, hz / 5 ); } #ifdef BSD4_4 if (( m = m_gethdr( M_DONTWAIT, MT_DATA )) == NULL ) { return; } m->m_len = sizeof( *ea ); m->m_pkthdr.len = sizeof( *ea ); MH_ALIGN( m, sizeof( *ea )); #else /* BSD4_4 */ if (( m = m_get( M_DONTWAIT, MT_DATA )) == NULL ) { return; } m->m_len = sizeof( *ea ); m->m_off = MMAXOFF - sizeof( *ea ); #endif /* BSD4_4 */ ea = mtod( m, struct ether_aarp *); bzero((caddr_t)ea, sizeof( *ea )); ea->aarp_hrd = htons( AARPHRD_ETHER ); ea->aarp_pro = htons( ETHERTYPE_AT ); ea->aarp_hln = sizeof( ea->aarp_sha ); ea->aarp_pln = sizeof( ea->aarp_spu ); ea->aarp_op = htons( AARPOP_PROBE ); #ifdef sun bcopy((caddr_t)&ac->ac_enaddr, (caddr_t)ea->aarp_sha, sizeof( ea->aarp_sha )); #else /* sun */ bcopy((caddr_t)ac->ac_enaddr, (caddr_t)ea->aarp_sha, sizeof( ea->aarp_sha )); #endif /* sun */ eh = (struct ether_header *)sa.sa_data; if ( aa->aa_flags & AFA_PHASE2 ) { #ifdef sun bcopy((caddr_t)atmulticastaddr, (caddr_t)&eh->ether_dhost, sizeof( eh->ether_dhost )); #else /* sun */ bcopy((caddr_t)atmulticastaddr, (caddr_t)eh->ether_dhost, sizeof( eh->ether_dhost )); #endif /* sun */ #if defined( sun ) && defined( i386 ) eh->ether_type = htons( sizeof( struct llc ) + sizeof( struct ether_aarp )); #else /* sun && i386 */ eh->ether_type = sizeof( struct llc ) + sizeof( struct ether_aarp ); #endif /* sun && i386 */ #ifdef BSD4_4 M_PREPEND( m, sizeof( struct llc ), M_WAIT ); #else /* BSD4_4 */ m->m_len += sizeof( struct llc ); m->m_off -= sizeof( struct llc ); #endif /* BSD4_4 */ llc = mtod( m, struct llc *); llc->llc_dsap = llc->llc_ssap = LLC_SNAP_LSAP; llc->llc_control = LLC_UI; bcopy( aarp_org_code, llc->llc_org_code, sizeof( aarp_org_code )); llc->llc_ether_type = htons( ETHERTYPE_AARP ); bcopy( &AA_SAT( aa )->sat_addr.s_net, ea->aarp_spnet, sizeof( ea->aarp_spnet )); bcopy( &AA_SAT( aa )->sat_addr.s_net, ea->aarp_tpnet, sizeof( ea->aarp_tpnet )); ea->aarp_spnode = ea->aarp_tpnode = AA_SAT( aa )->sat_addr.s_node; } else { #ifdef sun bcopy((caddr_t)ðerbroadcastaddr, (caddr_t)&eh->ether_dhost, sizeof( eh->ether_dhost )); #else /* sun */ bcopy((caddr_t)etherbroadcastaddr, (caddr_t)eh->ether_dhost, sizeof( eh->ether_dhost )); #endif /* sun */ #if defined( sun ) && defined( i386 ) eh->ether_type = htons( ETHERTYPE_AARP ); #else /* sun && i386 */ eh->ether_type = ETHERTYPE_AARP; #endif /* sun && i386 */ ea->aarp_spa = ea->aarp_tpa = AA_SAT( aa )->sat_addr.s_node; } #ifdef BSD4_4 sa.sa_len = sizeof( struct sockaddr ); #endif /* BSD4_4 */ sa.sa_family = AF_UNSPEC; (*ac->ac_if.if_output)(&ac->ac_if, m, &sa ); aa->aa_probcnt--; } aarp_clean() { struct aarptab *aat; int i; untimeout( aarptimer, 0 ); for ( i = 0, aat = aarptab; i < AARPTAB_SIZE; i++, aat++ ) { if ( aat->aat_hold ) { m_freem( aat->aat_hold ); } } }