summaryrefslogtreecommitdiffstats
path: root/sys/netatalk/aarp.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/netatalk/aarp.c')
-rw-r--r--sys/netatalk/aarp.c816
1 files changed, 816 insertions, 0 deletions
diff --git a/sys/netatalk/aarp.c b/sys/netatalk/aarp.c
new file mode 100644
index 0000000..84beef4
--- /dev/null
+++ b/sys/netatalk/aarp.c
@@ -0,0 +1,816 @@
+/*
+ * Copyright (c) 1990,1991 Regents of The University of Michigan.
+ * All Rights Reserved.
+ */
+
+#include <sys/types.h>
+#include <sys/cdefs.h>
+#include <sys/socket.h>
+#include <sys/syslog.h>
+#include <sys/param.h>
+#if defined( __FreeBSD__ )
+#include <machine/endian.h>
+#include <sys/systm.h>
+#include <sys/proc.h>
+#endif
+#include <sys/mbuf.h>
+#include <sys/time.h>
+#ifndef _IBMR2
+#include <sys/kernel.h>
+#endif _IBMR2
+#include <net/if.h>
+#include <net/route.h>
+#if !defined( __FreeBSD__ )
+#include <net/af.h>
+#endif
+#include <netinet/in.h>
+#undef s_net
+#include <netinet/if_ether.h>
+#ifdef _IBMR2
+#include <netinet/in_netarp.h>
+#include <net/spl.h>
+#include <sys/errno.h>
+#include <sys/err_rec.h>
+#endif _IBMR2
+
+#include <netatalk/at.h>
+#include <netatalk/at_var.h>
+#include <netatalk/aarp.h>
+#include <netatalk/ddp_var.h>
+#include <netatalk/phase2.h>
+#include <netatalk/at_extern.h>
+
+static void aarptfree( struct aarptab *aat);
+static void at_aarpinput( struct arpcom *ac, struct mbuf *m);
+
+#ifdef GATEWAY
+#define AARPTAB_BSIZ 16
+#define AARPTAB_NB 37
+#else
+#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
+# if !defined( __FreeBSD__ )
+extern u_char etherbroadcastaddr[6];
+# endif __FreeBSD__
+#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,
+};
+
+static void
+aarptimer(void *ignored)
+{
+ 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 );
+}
+
+static void
+aarpwhohas( 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
+ eh->ether_type = sizeof(struct llc) + sizeof(struct ether_aarp);
+#endif
+#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( &sat->sat_addr.s_net, ea->aarp_tpnet,
+ sizeof( ea->aarp_tpnet ));
+ ea->aarp_spnode = AA_SAT( aa )->sat_addr.s_node;
+ ea->aarp_tpnode = sat->sat_addr.s_node;
+ } else {
+#ifdef sun
+ bcopy((caddr_t)&etherbroadcastaddr, (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
+ eh->ether_type = ETHERTYPE_AARP;
+#endif
+
+ ea->aarp_spa = AA_SAT( aa )->sat_addr.s_node;
+ ea->aarp_tpa = sat->sat_addr.s_node;
+ }
+
+#ifdef NETATALKDEBUG
+ printf("aarp: sending request for %u.%u\n",
+ ntohs(AA_SAT( aa )->sat_addr.s_net),
+ AA_SAT( aa )->sat_addr.s_node);
+#endif NETATALKDEBUG
+
+#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
+#if defined( __FreeBSD__ )
+ , NULL /* XXX should be routing information */
+#endif __FreeBSD__
+ );
+}
+
+int
+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)&etherbroadcastaddr, (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 );
+}
+
+void
+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 );
+}
+
+static void
+at_aarpinput( 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
+
+ op = ntohs( ea->aarp_op );
+ bcopy( ea->aarp_tpnet, &net, sizeof( net ));
+
+ if ( net != 0 ) { /* should be ATADDR_ANYNET? */
+#ifdef BSD4_4
+ sat.sat_len = sizeof(struct sockaddr_at);
+#endif BSD4_4
+ 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((timeout_func_t) 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
+#ifdef BSD4_4
+ sat.sat_len = sizeof(struct sockaddr_at);
+#endif BSD4_4
+ 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
+#if defined( __FreeBSD__ )
+ , NULL /* XXX */
+#endif __FreeBSD__
+ );
+ 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
+
+ /* XXX */
+ 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
+ eh->ether_type = sizeof( struct llc ) + sizeof( struct ether_aarp );
+#endif
+#ifdef BSD4_4
+ M_PREPEND( m, sizeof( struct llc ), M_DONTWAIT );
+ if ( m == NULL ) {
+ 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
+ eh->ether_type = ETHERTYPE_AARP;
+#endif
+ }
+
+ 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
+#if defined( __FreeBSD__ )
+ , NULL /* XXX */
+#endif
+ );
+ return;
+}
+
+static void
+aarptfree( 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 );
+}
+
+
+void
+aarpprobe( 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( (timeout_func_t)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
+ eh->ether_type = sizeof( struct llc ) + sizeof( struct ether_aarp );
+#endif
+#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)&etherbroadcastaddr, (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
+ eh->ether_type = ETHERTYPE_AARP;
+#endif
+ ea->aarp_spa = ea->aarp_tpa = AA_SAT( aa )->sat_addr.s_node;
+ }
+
+#ifdef NETATALKDEBUG
+ printf("aarp: sending probe for %u.%u\n",
+ ntohs(AA_SAT( aa )->sat_addr.s_net),
+ AA_SAT( aa )->sat_addr.s_node);
+#endif NETATALKDEBUG
+
+#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
+#if defined( __FreeBSD__ )
+ , NULL /* XXX */
+#endif __FreeBSD__
+ );
+ aa->aa_probcnt--;
+}
+
+void
+aarp_clean(void)
+{
+ 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 );
+ }
+ }
+}
OpenPOWER on IntegriCloud