mirror of
https://git.FreeBSD.org/src.git
synced 2024-12-28 11:57:28 +00:00
655929bfba
Kernel Appletalk protocol support both CAP and netatalk can make use of this.. still needs some owrk but it seemd the right tiime to commit it so other can experiment.
817 lines
20 KiB
C
817 lines
20 KiB
C
/*
|
|
* 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)ð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
|
|
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)ð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 );
|
|
}
|
|
|
|
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)ð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
|
|
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 );
|
|
}
|
|
}
|
|
}
|