diff --git a/sys/conf/files b/sys/conf/files index f3b34693e13b..f7ea057c0f38 100644 --- a/sys/conf/files +++ b/sys/conf/files @@ -156,6 +156,13 @@ net/rtsock.c standard net/slcompress.c optional ppp net/slcompress.c optional sl net/if_tun.c optional tun +netatalk/aarp.c optional netatalk +netatalk/at_control.c optional netatalk +netatalk/at_proto.c optional netatalk +netatalk/at_rmx.c optional netatalkdebug +netatalk/ddp_input.c optional netatalk +netatalk/ddp_output.c optional netatalk +netatalk/ddp_usrreq.c optional netatalk #netccitt/ccitt_proto.c optional ccitt #netccitt/hd_debug.c optional hdlc #netccitt/hd_input.c optional hdlc diff --git a/sys/net/if_ethersubr.c b/sys/net/if_ethersubr.c index e31352759bc1..97903ef8af78 100644 --- a/sys/net/if_ethersubr.c +++ b/sys/net/if_ethersubr.c @@ -31,7 +31,7 @@ * SUCH DAMAGE. * * @(#)if_ethersubr.c 8.1 (Berkeley) 6/10/93 - * $Id: if_ethersubr.c,v 1.14 1996/01/24 21:09:06 phk Exp $ + * $Id: if_ethersubr.c,v 1.15 1996/04/07 17:39:03 bde Exp $ */ #include @@ -76,15 +76,27 @@ #include #endif -#ifdef LLC +/*#ifdef LLC #include #include -#endif +#endif*/ #if defined(LLC) && defined(CCITT) extern struct ifqueue pkintrq; #endif +#ifdef NETATALK +#include +#include +#include + +#define llc_snap_org_code llc_un.type_snap.org_code +#define llc_snap_ether_type llc_un.type_snap.ether_type + +extern u_char at_org_code[ 3 ]; +extern u_char aarp_org_code[ 3 ]; +#endif NETATALK + u_char etherbroadcastaddr[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; #define senderr(e) { error = (e); goto bad;} @@ -111,6 +123,9 @@ ether_output(ifp, m0, dst, rt0) register struct ether_header *eh; int off, len = m->m_pkthdr.len; struct arpcom *ac = (struct arpcom *)ifp; +#ifdef NETATALK + struct at_ifaddr *aa; +#endif NETATALK if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) senderr(ENETDOWN); @@ -165,6 +180,44 @@ ether_output(ifp, m0, dst, rt0) mcopy = m_copy(m, 0, (int)M_COPYALL); break; #endif +#ifdef NETATALK + case AF_APPLETALK: + if (!aarpresolve(ac, m, (struct sockaddr_at *)dst, edst)) { +#ifdef NETATALKDEBUG + extern char *prsockaddr(struct sockaddr *); + printf("aarpresolv: failed for %s\n", prsockaddr(dst)); +#endif NETATALKDEBUG + return (0); + } + /* + * ifaddr is the first thing in at_ifaddr + */ + if ((aa = (struct at_ifaddr *)at_ifawithnet( + (struct sockaddr_at *)dst, ifp->if_addrlist)) + == 0) + goto bad; + + /* + * In the phase 2 case, we need to prepend an mbuf for the llc header. + * Since we must preserve the value of m, which is passed to us by + * value, we m_copy() the first mbuf, and use it for our llc header. + */ + if ( aa->aa_flags & AFA_PHASE2 ) { + struct llc llc; + + M_PREPEND(m, sizeof(struct llc), M_WAIT); + len += sizeof(struct llc); + llc.llc_dsap = llc.llc_ssap = LLC_SNAP_LSAP; + llc.llc_control = LLC_UI; + bcopy(at_org_code, llc.llc_snap_org_code, sizeof(at_org_code)); + llc.llc_snap_ether_type = htons( ETHERTYPE_AT ); + bcopy(&llc, mtod(m, caddr_t), sizeof(struct llc)); + type = m->m_pkthdr.len; + } else { + type = ETHERTYPE_AT; + } + break; +#endif NETATALK #ifdef NS case AF_NS: type = ETHERTYPE_NS; @@ -371,12 +424,51 @@ ether_input(ifp, eh, m) inq = &nsintrq; break; #endif +#ifdef NETATALK + case ETHERTYPE_AT: + schednetisr(NETISR_ATALK); + inq = &atintrq1; + break; + case ETHERTYPE_AARP: + /* probably this should be done with a NETISR as well */ + aarpinput((struct arpcom *)ifp, m); /* XXX */ + return; +#endif NETATALK default: -#if defined (ISO) || defined (LLC) +#if defined (ISO) || defined (LLC) || defined(NETATALK) if (ether_type > ETHERMTU) goto dropanyway; l = mtod(m, struct llc *); switch (l->llc_dsap) { +#ifdef NETATALK + case LLC_SNAP_LSAP: + switch (l->llc_control) { + case LLC_UI: + if (l->llc_ssap != LLC_SNAP_LSAP) + goto dropanyway; + + if (Bcmp(&(l->llc_snap_org_code)[0], at_org_code, + sizeof(at_org_code)) == 0 && + ntohs(l->llc_snap_ether_type) == ETHERTYPE_AT) { + inq = &atintrq2; + m_adj( m, sizeof( struct llc )); + schednetisr(NETISR_ATALK); + break; + } + + if (Bcmp(&(l->llc_snap_org_code)[0], aarp_org_code, + sizeof(aarp_org_code)) == 0 && + ntohs(l->llc_snap_ether_type) == ETHERTYPE_AARP) { + m_adj( m, sizeof( struct llc )); + aarpinput((struct arpcom *)ifp, m); /* XXX */ + return; + } + + default: + goto dropanyway; + } + break; +#endif NETATALK #ifdef ISO case LLC_ISO_LSAP: switch (l->llc_control) { @@ -469,10 +561,10 @@ ether_input(ifp, eh, m) m_freem(m); return; } -#else /* ISO || LLC */ +#else /* ISO || LLC || NETATALK */ m_freem(m); return; -#endif /* ISO || LLC */ +#endif /* ISO || LLC || NETATALK */ } s = splimp(); diff --git a/sys/net/if_loop.c b/sys/net/if_loop.c index 894a4b5f2071..acbc82287a66 100644 --- a/sys/net/if_loop.c +++ b/sys/net/if_loop.c @@ -31,7 +31,7 @@ * SUCH DAMAGE. * * @(#)if_loop.c 8.1 (Berkeley) 6/10/93 - * $Id: if_loop.c,v 1.18 1996/02/06 18:51:11 wollman Exp $ + * $Id: if_loop.c,v 1.19 1996/04/07 17:39:06 bde Exp $ */ /* @@ -77,6 +77,12 @@ #include #endif +#ifdef NETATALK +#include +#include +#include +#endif NETATALK + #include "bpfilter.h" static int loioctl __P((struct ifnet *, int, caddr_t)); @@ -194,6 +200,12 @@ looutput(ifp, m, dst, rt) isr = NETISR_ISO; break; #endif +#ifdef NETATALK + case AF_APPLETALK: + ifq = &atintrq2; + isr = NETISR_ATALK; + break; +#endif NETATALK default: printf("lo%d: can't handle af%d\n", ifp->if_unit, dst->sa_family); diff --git a/sys/net/netisr.h b/sys/net/netisr.h index a326493e5fb0..5c9bd295cb21 100644 --- a/sys/net/netisr.h +++ b/sys/net/netisr.h @@ -31,7 +31,7 @@ * SUCH DAMAGE. * * @(#)netisr.h 8.1 (Berkeley) 6/10/93 - * $Id: netisr.h,v 1.7 1995/10/26 20:30:22 julian Exp $ + * $Id: netisr.h,v 1.8 1995/10/31 19:07:49 peter Exp $ */ #ifndef _NET_NETISR_H_ @@ -61,6 +61,7 @@ #define NETISR_NS 6 /* same as AF_NS */ #define NETISR_ISO 7 /* same as AF_ISO */ #define NETISR_CCITT 10 /* same as AF_CCITT */ +#define NETISR_ATALK 16 /* same as AF_APPLETALK */ #define NETISR_ARP 18 /* same as AF_LINK */ #define NETISR_IPX 23 /* same as AF_IPX */ #define NETISR_ISDN 26 /* same as AF_E164 */ diff --git a/sys/netatalk/aarp.c b/sys/netatalk/aarp.c new file mode 100644 index 000000000000..84beef40df9a --- /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 +#include +#include +#include +#include +#if defined( __FreeBSD__ ) +#include +#include +#include +#endif +#include +#include +#ifndef _IBMR2 +#include +#endif _IBMR2 +#include +#include +#if !defined( __FreeBSD__ ) +#include +#endif +#include +#undef s_net +#include +#ifdef _IBMR2 +#include +#include +#include +#include +#endif _IBMR2 + +#include +#include +#include +#include +#include +#include + +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 ); + } + } +} diff --git a/sys/netatalk/aarp.h b/sys/netatalk/aarp.h new file mode 100644 index 000000000000..4911538a6b79 --- /dev/null +++ b/sys/netatalk/aarp.h @@ -0,0 +1,62 @@ +/* + * Copyright (c) 1990,1991 Regents of The University of Michigan. + * All Rights Reserved. + */ + +#ifndef _NETATALK_AARP_H_ +/* + * This structure is used for both phase 1 and 2. Under phase 1 + * the net is not filled in. It is in phase 2. In both cases, the + * hardware address length is (for some unknown reason) 4. If + * anyone at Apple could program their way out of paper bag, it + * would be 1 and 3 respectively for phase 1 and 2. + */ +union aapa { + u_char ap_pa[4]; + struct ap_node { + u_char an_zero; + u_char an_net[2]; + u_char an_node; + } ap_node; +}; + +struct ether_aarp { + struct arphdr eaa_hdr; + u_char aarp_sha[6]; + union aapa aarp_spu; + u_char aarp_tha[6]; + union aapa aarp_tpu; +}; +#define aarp_hrd eaa_hdr.ar_hrd +#define aarp_pro eaa_hdr.ar_pro +#define aarp_hln eaa_hdr.ar_hln +#define aarp_pln eaa_hdr.ar_pln +#define aarp_op eaa_hdr.ar_op +#define aarp_spa aarp_spu.ap_node.an_node +#define aarp_tpa aarp_tpu.ap_node.an_node +#define aarp_spnet aarp_spu.ap_node.an_net +#define aarp_tpnet aarp_tpu.ap_node.an_net +#define aarp_spnode aarp_spu.ap_node.an_node +#define aarp_tpnode aarp_tpu.ap_node.an_node + +struct aarptab { + struct at_addr aat_ataddr; + u_char aat_enaddr[ 6 ]; + u_char aat_timer; + u_char aat_flags; + struct mbuf *aat_hold; +}; + +#define AARPHRD_ETHER 0x0001 + +#define AARPOP_REQUEST 0x01 +#define AARPOP_RESPONSE 0x02 +#define AARPOP_PROBE 0x03 + +#ifdef KERNEL +struct aarptab *aarptnew(struct at_addr *); +#if !defined( __FreeBSD__ ) +int aarpprobe(); +#endif +#endif +#endif /* _NETATALK_AARP_H_ */ diff --git a/sys/netatalk/at.h b/sys/netatalk/at.h new file mode 100644 index 000000000000..eca11fb50cda --- /dev/null +++ b/sys/netatalk/at.h @@ -0,0 +1,117 @@ +/* + * Copyright (c) 1990,1991 Regents of The University of Michigan. + * All Rights Reserved. + * + * Permission to use, copy, modify, and distribute this software and + * its documentation for any purpose and without fee is hereby granted, + * provided that the above copyright notice appears in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation, and that the name of The University + * of Michigan not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. This software is supplied as is without expressed or + * implied warranties of any kind. + * + * Research Systems Unix Group + * The University of Michigan + * c/o Mike Clark + * 535 W. William Street + * Ann Arbor, Michigan + * +1-313-763-0525 + * netatalk@itd.umich.edu + */ + +#ifndef __AT_HEADER__ +#define __AT_HEADER__ +/* + * Supported protocols + */ +#define ATPROTO_DDP 0 +#define ATPROTO_AARP 254 + +/* + * Ethernet types, for DIX. + * These should really be in some global header file, but we can't + * count on them being there, and it's annoying to patch system files. + */ +#define ETHERTYPE_AT 0x809B /* AppleTalk protocol */ +#define ETHERTYPE_AARP 0x80F3 /* AppleTalk ARP */ + +#define DDP_MAXSZ 587 + +/* + * If ATPORT_FIRST <= Port < ATPORT_RESERVED, + * Port was created by a privileged process. + * If ATPORT_RESERVED <= Port < ATPORT_LAST, + * Port was not necessarily created by a + * privileged process. + */ +#define ATPORT_FIRST 1 +#define ATPORT_RESERVED 128 +#define ATPORT_LAST 255 + +/* + * AppleTalk address. + */ +struct at_addr { + u_short s_net; + u_char s_node; +}; + +#if defined( BSD4_4 ) && !defined( __FreeBSD__ ) +#define ATADDR_ANYNET (u_short)0xffff +#else +#define ATADDR_ANYNET (u_short)0x0000 +#endif +#define ATADDR_ANYNODE (u_char)0x00 +#define ATADDR_ANYPORT (u_char)0x00 +#define ATADDR_BCAST (u_char)0xff /* There is no BCAST for NET */ + +/* + * Socket address, AppleTalk style. We keep magic information in the + * zero bytes. There are three types, NONE, CONFIG which has the phase + * and a net range, and IFACE which has the network address of an + * interface. IFACE may be filled in by the client, and is filled in + * by the kernel. + */ +struct sockaddr_at { +#ifdef BSD4_4 + u_char sat_len; + u_char sat_family; +#else BSD4_4 + short sat_family; +#endif BSD4_4 + u_char sat_port; + struct at_addr sat_addr; +#ifdef notdef + struct { + u_char sh_type; +# define SATHINT_NONE 0 +# define SATHINT_CONFIG 1 +# define SATHINT_IFACE 2 + union { + char su_zero[ 7 ]; /* XXX check size */ + struct { + u_char sr_phase; + u_short sr_firstnet, sr_lastnet; + } su_range; + u_short su_interface; + } sh_un; + } sat_hints; +#else notdef + char sat_zero[ 8 ]; +#endif notdef +}; + +struct netrange { + u_char nr_phase; + u_short nr_firstnet; + u_short nr_lastnet; +}; + +#ifdef KERNEL +extern struct domain atalkdomain; +extern struct protosw atalksw[]; +#endif + +#endif __AT_HEADER__ diff --git a/sys/netatalk/at_control.c b/sys/netatalk/at_control.c new file mode 100644 index 000000000000..5a1294f6ce81 --- /dev/null +++ b/sys/netatalk/at_control.c @@ -0,0 +1,614 @@ +/* + * Copyright (c) 1990,1991 Regents of The University of Michigan. + * All Rights Reserved. + */ + +#include +#include +#ifdef ibm032 +#include +#endif ibm032 +#include +#ifndef BSD4_4 +#include +#endif +#include +#include +#include +#include +#ifndef _IBMR2 +#include +#endif _IBMR2 +#include +#include +#include +/* #include */ +#include +#include +#undef s_net +#include +#ifdef _IBMR2 +#include +#endif _IBMR2 + +#include "at.h" +#include "at_var.h" +#include "aarp.h" +#include "phase2.h" +#include + +static int at_scrub( struct ifnet *ifp, struct at_ifaddr *aa ); +static int at_ifinit( struct ifnet *ifp, struct at_ifaddr *aa, + struct sockaddr_at *sat ); + +#ifdef BSD4_4 +# define sateqaddr(a,b) ((a)->sat_len == (b)->sat_len && \ + (a)->sat_family == (b)->sat_family && \ + (a)->sat_addr.s_net == (b)->sat_addr.s_net && \ + (a)->sat_addr.s_node == (b)->sat_addr.s_node ) +#else BSD4_4 +atalk_hash( sat, hp ) + struct sockaddr_at *sat; + struct afhash *hp; +{ + hp->afh_nethash = sat->sat_addr.s_net; + hp->afh_hosthash = ( sat->sat_addr.s_net << 8 ) + + sat->sat_addr.s_node; +} + +/* + * Note the magic to get ifa_ifwithnet() to work without adding an + * ifaddr entry for each net in our local range. + */ +int +atalk_netmatch( sat1, sat2 ) + struct sockaddr_at *sat1, *sat2; +{ + struct at_ifaddr *aa; + + for ( aa = at_ifaddr; aa; aa = aa->aa_next ) { + if ( AA_SAT( aa ) == sat1 ) { + break; + } + } + if ( aa ) { + return( ntohs( aa->aa_firstnet ) <= ntohs( sat2->sat_addr.s_net ) && + ntohs( aa->aa_lastnet ) >= ntohs( sat2->sat_addr.s_net )); + } + return( sat1->sat_addr.s_net == sat2->sat_addr.s_net ); +} +#endif BSD4_4 + +int +at_control( int cmd, caddr_t data, struct ifnet *ifp, struct proc *p ) +{ + struct ifreq *ifr = (struct ifreq *)data; + struct sockaddr_at *sat; + struct netrange *nr; +#ifdef BSD4_4 + struct at_aliasreq *ifra = (struct at_aliasreq *)data; + struct at_ifaddr *aa0; +#endif BSD4_4 + struct at_ifaddr *aa = 0; + struct mbuf *m; + struct ifaddr *ifa; + + if ( ifp ) { + for ( aa = at_ifaddr; aa; aa = aa->aa_next ) { + if ( aa->aa_ifp == ifp ) break; + } + } + + switch ( cmd ) { +#ifdef BSD4_4 + case SIOCAIFADDR: + case SIOCDIFADDR: + if ( ifra->ifra_addr.sat_family == AF_APPLETALK ) { + for ( ; aa; aa = aa->aa_next ) { + if ( aa->aa_ifp == ifp && + sateqaddr( &aa->aa_addr, &ifra->ifra_addr )) { + break; + } + } + } + if ( cmd == SIOCDIFADDR && aa == 0 ) { + return( EADDRNOTAVAIL ); + } + /*FALLTHROUGH*/ +#endif BSD4_4 + + case SIOCSIFADDR: +#ifdef BSD4_4 + /* + * What a great idea this is: Let's reverse the meaning of + * the return... + */ +#if defined( __FreeBSD__ ) + if ( suser(p->p_ucred, &p->p_acflag) ) { +#else + if ( suser( u.u_cred, &u.u_acflag )) { +#endif + return( EPERM ); + } +#else BSD4_4 + if ( !suser()) { + return( EPERM ); + } +#endif BSD4_4 + + sat = satosat( &ifr->ifr_addr ); + nr = (struct netrange *)sat->sat_zero; + if ( nr->nr_phase == 1 ) { + for ( ; aa; aa = aa->aa_next ) { + if ( aa->aa_ifp == ifp && + ( aa->aa_flags & AFA_PHASE2 ) == 0 ) { + break; + } + } + } else { /* default to phase 2 */ + for ( ; aa; aa = aa->aa_next ) { + if ( aa->aa_ifp == ifp && ( aa->aa_flags & AFA_PHASE2 )) { + break; + } + } + } + + if ( ifp == 0 ) + panic( "at_control" ); + + if ( aa == (struct at_ifaddr *) 0 ) { + m = m_getclr( M_WAIT, MT_IFADDR ); + if ( m == (struct mbuf *)NULL ) { + return( ENOBUFS ); + } + + if (( aa = at_ifaddr ) != NULL ) { + /* + * Don't let the loopback be first, since the first + * address is the machine's default address for + * binding. + */ + if ( at_ifaddr->aa_ifp->if_flags & IFF_LOOPBACK ) { + aa = mtod( m, struct at_ifaddr *); + aa->aa_next = at_ifaddr; + at_ifaddr = aa; + } else { + for ( ; aa->aa_next; aa = aa->aa_next ) + ; + aa->aa_next = mtod( m, struct at_ifaddr *); + } + } else { + at_ifaddr = mtod( m, struct at_ifaddr *); + } + + aa = mtod( m, struct at_ifaddr *); + + if (( ifa = ifp->if_addrlist ) != NULL ) { + for ( ; ifa->ifa_next; ifa = ifa->ifa_next ) + ; + ifa->ifa_next = (struct ifaddr *)aa; + } else { + ifp->if_addrlist = (struct ifaddr *)aa; + } + +#ifdef BSD4_4 + aa->aa_ifa.ifa_addr = (struct sockaddr *)&aa->aa_addr; + aa->aa_ifa.ifa_dstaddr = (struct sockaddr *)&aa->aa_addr; + aa->aa_ifa.ifa_netmask = (struct sockaddr *)&aa->aa_netmask; +#endif BSD4_4 + + /* + * Set/clear the phase 2 bit. + */ + if ( nr->nr_phase == 1 ) { + aa->aa_flags &= ~AFA_PHASE2; + } else { + aa->aa_flags |= AFA_PHASE2; + } + aa->aa_ifp = ifp; + } else { + at_scrub( ifp, aa ); + } + break; + + case SIOCGIFADDR : + sat = satosat( &ifr->ifr_addr ); + nr = (struct netrange *)sat->sat_zero; + if ( nr->nr_phase == 1 ) { + for ( ; aa; aa = aa->aa_next ) { + if ( aa->aa_ifp == ifp && + ( aa->aa_flags & AFA_PHASE2 ) == 0 ) { + break; + } + } + } else { /* default to phase 2 */ + for ( ; aa; aa = aa->aa_next ) { + if ( aa->aa_ifp == ifp && ( aa->aa_flags & AFA_PHASE2 )) { + break; + } + } + } + + if ( aa == (struct at_ifaddr *) 0 ) + return( EADDRNOTAVAIL ); + break; + } + + switch ( cmd ) { + case SIOCGIFADDR: +#ifdef BSD4_4 + *(struct sockaddr_at *)&ifr->ifr_addr = aa->aa_addr; +#else BSD4_4 + ifr->ifr_addr = aa->aa_addr; +#endif BSD4_4 + break; + + case SIOCSIFADDR: + return( at_ifinit( ifp, aa, (struct sockaddr_at *)&ifr->ifr_addr )); + +#ifdef BSD4_4 + case SIOCAIFADDR: + if ( sateqaddr( &ifra->ifra_addr, &aa->aa_addr )) { + return( 0 ); + } + return( at_ifinit( ifp, aa, (struct sockaddr_at *)&ifr->ifr_addr )); + + case SIOCDIFADDR: + at_scrub( ifp, aa ); + if (( ifa = ifp->if_addrlist ) == (struct ifaddr *)aa ) { + ifp->if_addrlist = ifa->ifa_next; + } else { + while ( ifa->ifa_next && ( ifa->ifa_next != (struct ifaddr *)aa )) { + ifa = ifa->ifa_next; + } + if ( ifa->ifa_next ) { + ifa->ifa_next = ((struct ifaddr *)aa)->ifa_next; + } else { + panic( "at_control" ); + } + } + + aa0 = aa; + if ( aa0 == ( aa = at_ifaddr )) { + at_ifaddr = aa->aa_next; + } else { + while ( aa->aa_next && ( aa->aa_next != aa0 )) { + aa = aa->aa_next; + } + if ( aa->aa_next ) { + aa->aa_next = aa0->aa_next; + } else { + panic( "at_control" ); + } + } + m_free( dtom( aa0 )); + break; +#endif BSD4_4 + + default: + if ( ifp == 0 || ifp->if_ioctl == 0 ) + return( EOPNOTSUPP ); + return( (*ifp->if_ioctl)( ifp, cmd, data )); + } + return( 0 ); +} +static int +at_scrub( ifp, aa ) + struct ifnet *ifp; + struct at_ifaddr *aa; +{ +#ifndef BSD4_4 + struct sockaddr_at netsat; + u_short net; +#endif BSD4_4 + int error; + + if ( aa->aa_flags & AFA_ROUTE ) { +#ifdef BSD4_4 + if (( error = rtinit( &(aa->aa_ifa), RTM_DELETE, + ( ifp->if_flags & IFF_LOOPBACK ) ? RTF_HOST : 0 )) != 0 ) { + return( error ); + } + aa->aa_ifa.ifa_flags &= ~IFA_ROUTE; +#else BSD4_4 + if ( ifp->if_flags & IFF_LOOPBACK ) { + rtinit( &aa->aa_addr, &aa->aa_addr, SIOCDELRT, RTF_HOST ); + } else { + bzero( &netsat, sizeof( struct sockaddr_at )); + netsat.sat_family = AF_APPLETALK; + netsat.sat_addr.s_node = ATADDR_ANYNODE; + + /* + * If the range is the full 0-fffe range, just use + * the default route. + */ + if ( aa->aa_firstnet == htons( 0x0000 ) && + aa->aa_lastnet == htons( 0xfffe )) { + netsat.sat_addr.s_net = 0; + rtinit((struct sockaddr *)&netsat, &aa->aa_addr, + (int)SIOCDELRT, 0 ); + } else { + for ( net = ntohs( aa->aa_firstnet ); + net <= ntohs( aa->aa_lastnet ); net++ ) { + netsat.sat_addr.s_net = htons( net ); + rtinit((struct sockaddr *)&netsat, &aa->aa_addr, + (int)SIOCDELRT, 0 ); + } + } + } +#endif BSD4_4 + aa->aa_flags &= ~AFA_ROUTE; + } + return( 0 ); +} + +#if !defined( __FreeBSD__ ) +extern struct timeval time; +#endif __FreeBSD__ + +static int +at_ifinit( ifp, aa, sat ) + struct ifnet *ifp; + struct at_ifaddr *aa; + struct sockaddr_at *sat; +{ + struct netrange nr, onr; +#ifdef BSD4_4 + struct sockaddr_at oldaddr; +#else BSD4_4 + struct sockaddr oldaddr; +#endif BSD4_4 + struct sockaddr_at netaddr; + int s = splimp(), error = 0, i, j, netinc, nodeinc, nnets; + u_short net; + + oldaddr = aa->aa_addr; + bzero( AA_SAT( aa ), sizeof( struct sockaddr_at )); + bcopy( sat->sat_zero, &nr, sizeof( struct netrange )); + nnets = ntohs( nr.nr_lastnet ) - ntohs( nr.nr_firstnet ) + 1; + + onr.nr_firstnet = aa->aa_firstnet; + onr.nr_lastnet = aa->aa_lastnet; + aa->aa_firstnet = nr.nr_firstnet; + aa->aa_lastnet = nr.nr_lastnet; + + /* + * We could eliminate the need for a second phase 1 probe (post + * autoconf) if we check whether we're resetting the node. Note + * that phase 1 probes use only nodes, not net.node pairs. Under + * phase 2, both the net and node must be the same. + */ + if ( ifp->if_flags & IFF_LOOPBACK ) { +#ifdef BSD4_4 + AA_SAT( aa )->sat_len = sat->sat_len; +#endif BSD4_4 + AA_SAT( aa )->sat_family = AF_APPLETALK; + AA_SAT( aa )->sat_addr.s_net = sat->sat_addr.s_net; + AA_SAT( aa )->sat_addr.s_node = sat->sat_addr.s_node; + } else { + aa->aa_flags |= AFA_PROBING; +#ifdef BSD4_4 + AA_SAT( aa )->sat_len = sizeof(struct sockaddr_at); +#endif BSD4_4 + AA_SAT( aa )->sat_family = AF_APPLETALK; + if ( aa->aa_flags & AFA_PHASE2 ) { + if ( sat->sat_addr.s_net == ATADDR_ANYNET ) { + if ( nnets != 1 ) { + net = ntohs( nr.nr_firstnet ) + time.tv_sec % ( nnets - 1 ); + } else { + net = ntohs( nr.nr_firstnet ); + } + } else { + if ( ntohs( sat->sat_addr.s_net ) < ntohs( nr.nr_firstnet ) || + ntohs( sat->sat_addr.s_net ) > ntohs( nr.nr_lastnet )) { + aa->aa_addr = oldaddr; + aa->aa_firstnet = onr.nr_firstnet; + aa->aa_lastnet = onr.nr_lastnet; + return( EINVAL ); + } + net = ntohs( sat->sat_addr.s_net ); + } + } else { + net = ntohs( sat->sat_addr.s_net ); + } + + if ( sat->sat_addr.s_node == ATADDR_ANYNODE ) { + AA_SAT( aa )->sat_addr.s_node = time.tv_sec; + } else { + AA_SAT( aa )->sat_addr.s_node = sat->sat_addr.s_node; + } + + for ( i = nnets, netinc = 1; i > 0; net = ntohs( nr.nr_firstnet ) + + (( net - ntohs( nr.nr_firstnet ) + netinc ) % nnets ), i-- ) { + AA_SAT( aa )->sat_addr.s_net = htons( net ); + + for ( j = 0, nodeinc = time.tv_sec | 1; j < 256; + j++, AA_SAT( aa )->sat_addr.s_node += nodeinc ) { + if ( AA_SAT( aa )->sat_addr.s_node > 253 || + AA_SAT( aa )->sat_addr.s_node < 1 ) { + continue; + } + aa->aa_probcnt = 10; + timeout( (timeout_func_t)aarpprobe, (caddr_t)ifp, hz / 5 ); + splx( s ); + if ( +#if defined( __FreeBSD__ ) + tsleep( aa, PPAUSE|PCATCH, "at_ifinit", 0 ) +#else + sleep( aa, PSLEP|PCATCH ) +#endif + ) { + printf( "at_ifinit why did this happen?!\n" ); + aa->aa_addr = oldaddr; + aa->aa_firstnet = onr.nr_firstnet; + aa->aa_lastnet = onr.nr_lastnet; + return( EINTR ); + } + s = splimp(); + if (( aa->aa_flags & AFA_PROBING ) == 0 ) { + break; + } + } + if (( aa->aa_flags & AFA_PROBING ) == 0 ) { + break; + } + /* reset node for next network */ + AA_SAT( aa )->sat_addr.s_node = time.tv_sec; + } + + if ( aa->aa_flags & AFA_PROBING ) { + aa->aa_addr = oldaddr; + aa->aa_firstnet = onr.nr_firstnet; + aa->aa_lastnet = onr.nr_lastnet; + splx( s ); + return( EADDRINUSE ); + } + } + + if ( ifp->if_ioctl && + ( error = (*ifp->if_ioctl)( ifp, SIOCSIFADDR, (caddr_t)aa ))) { + splx( s ); + aa->aa_addr = oldaddr; + aa->aa_firstnet = onr.nr_firstnet; + aa->aa_lastnet = onr.nr_lastnet; + return( error ); + } + +#ifdef BSD4_4 + aa->aa_netmask.sat_len = 6/*sizeof(struct sockaddr_at)*/; + aa->aa_netmask.sat_family = AF_APPLETALK; + aa->aa_netmask.sat_addr.s_net = 0xffff; + aa->aa_netmask.sat_addr.s_node = 0; +#if defined( __FreeBSD__ ) + aa->aa_ifa.ifa_netmask =(struct sockaddr *) &(aa->aa_netmask); /* XXX */ +#endif __FreeBSD__ +#endif BSD4_4 + + if ( ifp->if_flags & IFF_LOOPBACK ) { +#ifndef BSD4_4 + rtinit( &aa->aa_addr, &aa->aa_addr, (int)SIOCADDRT, + RTF_HOST|RTF_UP ); +#else BSD4_4 + error = rtinit( &(aa->aa_ifa), (int)RTM_ADD, +#if !defined( __FreeBSD__ ) + RTF_HOST | +#else + /* XXX not a host route? */ +#endif __FreeBSD__ + RTF_UP ); +#endif BSD4_4 + } else { +#ifndef BSD4_4 + /* + * rtrequest looks for point-to-point links first. The + * broadaddr is in the same spot as the destaddr. So, if + * ATADDR_ANYNET is 0, and we don't fill in the broadaddr, we + * get 0.0 routed out the ether interface. So, initialize the + * broadaddr, even tho we don't use it. + * + * We *could* use the broadaddr field to reduce some of the + * sockaddr_at overloading that we've done. E.g. Just send + * to INTERFACE-NET.255, and have the kernel reroute that + * to broadaddr, which would be 0.255 for phase 2 interfaces, + * and IFACE-NET.255 for phase 1 interfaces. + */ + ((struct sockaddr_at *)&aa->aa_broadaddr)->sat_addr.s_net = + sat->sat_addr.s_net; + ((struct sockaddr_at *)&aa->aa_broadaddr)->sat_addr.s_node = + ATADDR_BCAST; + + bzero( &netaddr, sizeof( struct sockaddr_at )); + netaddr.sat_family = AF_APPLETALK; + netaddr.sat_addr.s_node = ATADDR_ANYNODE; + if (( aa->aa_flags & AFA_PHASE2 ) == 0 ) { + netaddr.sat_addr.s_net = AA_SAT( aa )->sat_addr.s_net; + rtinit((struct sockaddr *)&netaddr, &aa->aa_addr, + (int)SIOCADDRT, RTF_UP ); + } else { + /* + * If the range is the full 0-fffe range, just use + * the default route. + */ + if ( aa->aa_firstnet == htons( 0x0000 ) && + aa->aa_lastnet == htons( 0xfffe )) { + netaddr.sat_addr.s_net = 0; + rtinit((struct sockaddr *)&netaddr, &aa->aa_addr, + (int)SIOCADDRT, RTF_UP ); + } else { + for ( net = ntohs( aa->aa_firstnet ); + net <= ntohs( aa->aa_lastnet ); net++ ) { + netaddr.sat_addr.s_net = htons( net ); + rtinit((struct sockaddr *)&netaddr, &aa->aa_addr, + (int)SIOCADDRT, RTF_UP ); + } + } + } +#else BSD4_4 + error = rtinit( &(aa->aa_ifa), (int)RTM_ADD, RTF_UP ); +#endif BSD4_4 + } + if ( error ) { + aa->aa_addr = oldaddr; + aa->aa_firstnet = onr.nr_firstnet; + aa->aa_lastnet = onr.nr_lastnet; + splx( s ); + return( error ); + } + +#ifdef BSD4_4 + aa->aa_ifa.ifa_flags |= IFA_ROUTE; +#endif BSD4_4 + aa->aa_flags |= AFA_ROUTE; + splx( s ); + return( 0 ); +} + +int +at_broadcast( sat ) + struct sockaddr_at *sat; +{ + struct at_ifaddr *aa; + + if ( sat->sat_addr.s_node != ATADDR_BCAST ) { + return( 0 ); + } + if ( sat->sat_addr.s_net == ATADDR_ANYNET ) { + return( 1 ); + } else { + for ( aa = at_ifaddr; aa; aa = aa->aa_next ) { + if (( aa->aa_ifp->if_flags & IFF_BROADCAST ) && + ( ntohs( sat->sat_addr.s_net ) >= ntohs( aa->aa_firstnet ) && + ntohs( sat->sat_addr.s_net ) <= ntohs( aa->aa_lastnet ))) { + return( 1 ); + } + } + } + return( 0 ); +} + +static void +aa_clean(void) +{ + struct at_ifaddr *aa; + struct ifaddr *ifa; + struct ifnet *ifp; + + while ( aa = at_ifaddr ) { + ifp = aa->aa_ifp; + at_scrub( ifp, aa ); + at_ifaddr = aa->aa_next; + if (( ifa = ifp->if_addrlist ) == (struct ifaddr *)aa ) { + ifp->if_addrlist = ifa->ifa_next; + } else { + while ( ifa->ifa_next && + ( ifa->ifa_next != (struct ifaddr *)aa )) { + ifa = ifa->ifa_next; + } + if ( ifa->ifa_next ) { + ifa->ifa_next = ((struct ifaddr *)aa)->ifa_next; + } else { + panic( "at_entry" ); + } + } + } +} diff --git a/sys/netatalk/at_extern.h b/sys/netatalk/at_extern.h new file mode 100644 index 000000000000..18badf4fa21b --- /dev/null +++ b/sys/netatalk/at_extern.h @@ -0,0 +1,41 @@ + +#ifdef _NETINET_IF_ETHER_H_ +extern void aarpprobe __P((struct arpcom *)); +extern int aarpresolve __P((struct arpcom *, + struct mbuf *, + struct sockaddr_at *, + u_char *)); +extern void aarpinput __P(( struct arpcom *, struct mbuf *)); +extern int at_broadcast __P((struct sockaddr_at *)); +#endif + +#ifdef _NETATALK_AARP_H_ +extern void aarptfree __P((struct aarptab *)); +#endif + +extern void aarp_clean __P((void)); +extern int at_control __P(( int cmd, + caddr_t data, + struct ifnet *ifp, + struct proc *p )); +extern u_short at_cksum __P(( struct mbuf *m, int skip)); +extern int ddp_usrreq __P(( struct socket *so, int req, + struct mbuf *m, + struct mbuf *addr, + struct mbuf *rights)); +extern void ddp_init __P((void )); +extern struct ifaddr *at_ifawithnet __P((struct sockaddr_at *, + struct ifaddr *)); +#ifdef _NETATALK_DDP_VAR_H_ +extern int ddp_output __P(( struct ddpcb *ddp, struct mbuf *m)); +#endif +#if defined (_NETATALK_DDP_VAR_H_) && defined(_NETATALK_AT_VAR_H_) +extern struct ddpcb *ddp_search __P((struct sockaddr_at *, + struct sockaddr_at *, + struct at_ifaddr *)); +#endif +#ifdef _NET_ROUTE_H_ +int ddp_route( struct mbuf *m, struct route *ro); +#endif + + diff --git a/sys/netatalk/at_proto.c b/sys/netatalk/at_proto.c new file mode 100644 index 000000000000..0c8fdbffc71f --- /dev/null +++ b/sys/netatalk/at_proto.c @@ -0,0 +1,95 @@ +/* + * Copyright (c) 1990,1991 Regents of The University of Michigan. + * All Rights Reserved. + * + * Permission to use, copy, modify, and distribute this software and + * its documentation for any purpose and without fee is hereby granted, + * provided that the above copyright notice appears in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation, and that the name of The University + * of Michigan not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. This software is supplied as is without expressed or + * implied warranties of any kind. + * + * Research Systems Unix Group + * The University of Michigan + * c/o Mike Clark + * 535 W. William Street + * Ann Arbor, Michigan + * +1-313-763-0525 + * netatalk@itd.umich.edu + */ + +#include +#include +#include +#include +#include +#include + +#if defined( __FreeBSD__ ) +#include +#include +#include +#include +#include +#include +#endif + +#include "at.h" +#include "ddp.h" +#include "at_var.h" +#include "ddp_var.h" +#include + + +#ifdef ultrix +extern int ddp_ifoutput(); +extern int ddp_ifinput(); +extern int ddp_ifioctl(); +#endif ultrix + +struct protosw atalksw[] = { + { + /* Identifiers */ + SOCK_DGRAM, &atalkdomain, ATPROTO_DDP, PR_ATOMIC|PR_ADDR, + /* + * protocol-protocol interface. + * fields are pr_input, pr_output, pr_ctlinput, and pr_ctloutput. + * pr_input can be called from the udp protocol stack for iptalk + * packets bound for a local socket. + * pr_output can be used by higher level appletalk protocols, should + * they be included in the kernel. + */ + 0, ddp_output, 0, 0, + /* socket-protocol interface. */ + ddp_usrreq, + /* utility routines. */ + ddp_init, 0, 0, 0, +#ifdef ultrix + /* interface hooks */ + ddp_ifoutput, ddp_ifinput, ddp_ifioctl, 0, +#endif ultrix + }, +}; + +#if defined( __FreeBSD__ ) && defined ( NETATALKDEBUG ) +extern int at_inithead(); +#endif + +struct domain atalkdomain = { + AF_APPLETALK, "appletalk", 0, 0, 0, + atalksw, &atalksw[sizeof(atalksw)/sizeof(atalksw[0])] +#if defined( __FreeBSD__ ) +#ifdef NETATALKDEBUG + , 0, at_inithead, 32, sizeof(struct sockaddr_at) +#else + , 0, rn_inithead, 32, sizeof(struct sockaddr_at) +#endif +#endif +}; + +#if defined( __FreeBSD__ ) +DOMAIN_SET(atalk); +#endif diff --git a/sys/netatalk/at_rmx.c b/sys/netatalk/at_rmx.c new file mode 100644 index 000000000000..73747b64e9d5 --- /dev/null +++ b/sys/netatalk/at_rmx.c @@ -0,0 +1,160 @@ +/* + * Copyright 1994, 1995 Massachusetts Institute of Technology + * + * Permission to use, copy, modify, and distribute this software and + * its documentation for any purpose and without fee is hereby + * granted, provided that both the above copyright notice and this + * permission notice appear in all copies, that both the above + * copyright notice and this permission notice appear in all + * supporting documentation, and that the name of M.I.T. not be used + * in advertising or publicity pertaining to distribution of the + * software without specific, written prior permission. M.I.T. makes + * no representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied + * warranty. + * + * THIS SOFTWARE IS PROVIDED BY M.I.T. ``AS IS''. M.I.T. DISCLAIMS + * ALL EXPRESS OR IMPLIED WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT + * SHALL M.I.T. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * at_rmx.c,v 1.13 1995/05/30 08:09:31 rgrimes Exp + */ + +/* This code generates debugging traces to the radix code */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +static char hexbuf[256]; + +char * +prsockaddr(void *v) +{ + char *bp = &hexbuf[0]; + u_char *cp = v; + + if (v) { + int len = *cp; + u_char *cplim = cp + len; + + /* return: "(len) hexdump" */ + + bp += sprintf(bp, "(%d)", len); + for (cp++; cp < cplim && bp < hexbuf+252; cp++) { + *bp++ = "0123456789abcdef"[*cp / 16]; + *bp++ = "0123456789abcdef"[*cp % 16]; + } + } else { + bp+= sprintf(bp, "null"); + } + *bp = '\0'; + + return &hexbuf[0]; +} + +static struct radix_node * +at_addroute(void *v_arg, void *n_arg, struct radix_node_head *head, + struct radix_node *treenodes) +{ + struct radix_node *rn; + struct sockaddr_at *dst = v_arg, *mask = n_arg; + + printf("at_addroute: v=%s\n", prsockaddr(v_arg)); + printf("at_addroute: n=%s\n", prsockaddr(n_arg)); + printf("at_addroute: head=%x treenodes=%x\n", head, treenodes); + + rn = rn_addroute(v_arg, n_arg, head, treenodes); + + printf("at_addroute: returns rn=%x\n", rn); + + return rn; +} + +static struct radix_node * +at_matroute(void *v_arg, struct radix_node_head *head) +{ + struct radix_node *rn; + struct sockaddr_at *dst = v_arg; + + printf("at_matroute: v=%s\n", prsockaddr(v_arg)); + printf("at_matroute: head=%x\n", head); + + rn = rn_match(v_arg, head); + + printf("at_matroute: returns rn=%x\n", rn); + + return rn; +} + +static struct radix_node * +at_lookup(void *v_arg, void *m_arg, struct radix_node_head *head) +{ + struct radix_node *rn; + + printf("at_lookup: v=%s\n", prsockaddr(v_arg)); + printf("at_lookup: n=%s\n", prsockaddr(m_arg)); + printf("at_lookup: head=%x\n", head); + + rn = rn_lookup(v_arg, m_arg, head); + + printf("at_lookup: returns rn=%x\n", rn); + + return rn; +} + +static struct radix_node * +at_delroute(void *v_arg, void *netmask_arg, struct radix_node_head *head) +{ + struct radix_node *rn; + + printf("at_delroute: v=%s\n", prsockaddr(v_arg)); + printf("at_delroute: n=%s\n", prsockaddr(netmask_arg)); + printf("at_delroute: head=%x\n", head); + + rn = rn_delete(v_arg, netmask_arg, head); + + printf("at_delroute: returns rn=%x\n", rn); + + return rn; +} + +/* + * Initialize our routing tree with debugging hooks. + */ +int +at_inithead(void **head, int off) +{ + struct radix_node_head *rnh; + + if(!rn_inithead(head, off)) + return 0; + + rnh = *head; + rnh->rnh_addaddr = at_addroute; + rnh->rnh_deladdr = at_delroute; + rnh->rnh_matchaddr = at_matroute; + rnh->rnh_lookup = at_lookup; + return 1; +} + diff --git a/sys/netatalk/at_var.h b/sys/netatalk/at_var.h new file mode 100644 index 000000000000..31b452651755 --- /dev/null +++ b/sys/netatalk/at_var.h @@ -0,0 +1,71 @@ +/* + * Copyright (c) 1990,1991 Regents of The University of Michigan. + * All Rights Reserved. + * + * Permission to use, copy, modify, and distribute this software and + * its documentation for any purpose and without fee is hereby granted, + * provided that the above copyright notice appears in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation, and that the name of The University + * of Michigan not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. This software is supplied as is without expressed or + * implied warranties of any kind. + * + * Research Systems Unix Group + * The University of Michigan + * c/o Mike Clark + * 535 W. William Street + * Ann Arbor, Michigan + * +1-313-763-0525 + * netatalk@itd.umich.edu + */ + +#ifndef _NETATALK_AT_VAR_H_ +#define _NETATALK_AT_VAR_H_ 1 +/* + * For phase2, we need to keep not only our address on an interface, + * but also the legal networks on the interface. + */ +struct at_ifaddr { + struct ifaddr aa_ifa; +# define aa_ifp aa_ifa.ifa_ifp +#ifdef BSD4_4 + struct sockaddr_at aa_addr; + struct sockaddr_at aa_broadaddr; + struct sockaddr_at aa_netmask; +#else BSD4_4 +# define aa_addr aa_ifa.ifa_addr +# define aa_broadaddr aa_ifa.ifa_broadaddr +# define aa_dstaddr aa_ifa.ifa_dstaddr +#endif BSD4_4 + int aa_flags; + u_short aa_firstnet, aa_lastnet; + int aa_probcnt; + struct at_ifaddr *aa_next; +}; + +#ifdef BSD4_4 +struct at_aliasreq { + char ifra_name[IFNAMSIZ]; /* if name, e.g. "en0" */ + struct sockaddr_at ifra_addr; + struct sockaddr_at ifra_broadaddr; +#define ifra_dstaddr ifra_broadaddr + struct sockaddr_at ifra_mask; +}; +#endif BSD4_4 + +#define AA_SAT(aa) \ + ((struct sockaddr_at *)&((struct at_ifaddr *)(aa))->aa_addr) +#define satosat(sa) ((struct sockaddr_at *)(sa)) + +#define AFA_ROUTE 0x0001 +#define AFA_PROBING 0x0002 +#define AFA_PHASE2 0x0004 + +#ifdef KERNEL +struct at_ifaddr *at_ifaddr; +struct ifqueue atintrq1, atintrq2; +int atdebug; +#endif +#endif /* _NETATALK_AT_VAR_H_ */ diff --git a/sys/netatalk/ddp.h b/sys/netatalk/ddp.h new file mode 100644 index 000000000000..aec009cbe581 --- /dev/null +++ b/sys/netatalk/ddp.h @@ -0,0 +1,133 @@ +/* + * Copyright (c) 1990,1991 Regents of The University of Michigan. + * All Rights Reserved. + * + * Permission to use, copy, modify, and distribute this software and + * its documentation for any purpose and without fee is hereby granted, + * provided that the above copyright notice appears in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation, and that the name of The University + * of Michigan not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. This software is supplied as is without expressed or + * implied warranties of any kind. + * + * Research Systems Unix Group + * The University of Michigan + * c/o Mike Clark + * 535 W. William Street + * Ann Arbor, Michigan + * +1-313-763-0525 + * netatalk@itd.umich.edu + */ +#ifndef _NETATALK_DDP_H_ +#define _NETATALK_DDP_H_ 1 + +/* + * <-1byte(8bits) -> + * +---------------+ + * | 0 | hopc |len| + * +---------------+ + * | len (cont) | + * +---------------+ + * | | + * +- DDP csum -+ + * | | + * +---------------+ + * | | + * +- Dest NET -+ + * | | + * +---------------+ + * | | + * +- Src NET -+ + * | | + * +---------------+ + * | Dest NODE | + * +---------------+ + * | Src NODE | + * +---------------+ + * | Dest PORT | + * +---------------+ + * | Src PORT | + * +---------------+ + * + * On Apples, there is also a ddp_type field, after src_port. However, + * under this unix implementation, user level processes need to be able + * to set the ddp_type. In later revisions, the ddp_type may only be + * available in a raw_appletalk interface. + */ + +struct elaphdr { + u_char el_dnode; + u_char el_snode; + u_char el_type; +}; + +#define SZ_ELAPHDR 3 + +#define ELAP_DDPSHORT 0x01 +#define ELAP_DDPEXTEND 0x02 + +/* + * Extended DDP header. Includes sickness for dealing with arbitrary + * bitfields on a little-endian arch. + */ +struct ddpehdr { + union { + struct { +#if BYTE_ORDER == BIG_ENDIAN + unsigned dub_pad:2; + unsigned dub_hops:4; + unsigned dub_len:10; + unsigned dub_sum:16; +#endif +#if BYTE_ORDER == LITTLE_ENDIAN + unsigned dub_sum:16; + unsigned dub_len:10; + unsigned dub_hops:4; + unsigned dub_pad:2; +#endif + } du_bits; + unsigned du_bytes; + } deh_u; +#define deh_pad deh_u.du_bits.dub_pad +#define deh_hops deh_u.du_bits.dub_hops +#define deh_len deh_u.du_bits.dub_len +#define deh_sum deh_u.du_bits.dub_sum +#define deh_bytes deh_u.du_bytes + u_short deh_dnet; + u_short deh_snet; + u_char deh_dnode; + u_char deh_snode; + u_char deh_dport; + u_char deh_sport; +}; + +#define DDP_MAXHOPS 15 + +struct ddpshdr { + union { + struct { +#if BYTE_ORDER == BIG_ENDIAN + unsigned dub_pad:6; + unsigned dub_len:10; + unsigned dub_dport:8; + unsigned dub_sport:8; +#endif +#if BYTE_ORDER == LITTLE_ENDIAN + unsigned dub_sport:8; + unsigned dub_dport:8; + unsigned dub_len:10; + unsigned dub_pad:6; +#endif + } du_bits; + unsigned du_bytes; + } dsh_u; +#define dsh_pad dsh_u.du_bits.dub_pad +#define dsh_len dsh_u.du_bits.dub_len +#define dsh_dport dsh_u.du_bits.dub_dport +#define dsh_sport dsh_u.du_bits.dub_sport +#define dsh_bytes dsh_u.du_bytes +}; + +#endif /* _NETATALK_DDP_H_ */ diff --git a/sys/netatalk/ddp_input.c b/sys/netatalk/ddp_input.c new file mode 100644 index 000000000000..45a0c28cb89f --- /dev/null +++ b/sys/netatalk/ddp_input.c @@ -0,0 +1,413 @@ +/* + * Copyright (c) 1990,1994 Regents of The University of Michigan. + * All Rights Reserved. See COPYRIGHT. + */ + +#include +#include +#if defined( __FreeBSD__ ) +#include +#include +#include +#endif __FreeBSD__ +#include +#include +#include +#include +#include +#include +#ifdef _IBMR2 +#include +#endif _IBMR2 +#include +#include + +#include "at.h" +#include "at_var.h" +#include "endian.h" +#include "ddp.h" +#include "ddp_var.h" +#include + +int ddp_forward = 1; +int ddp_firewall = 0; +extern int ddp_cksum; +void ddp_input( struct mbuf *, struct ifnet *, struct elaphdr *, int ); + +/* + * Could probably merge these two code segments a little better... + */ +static void +atintr( void ) +{ + struct elaphdr *elhp, elh; + struct ifnet *ifp; + struct mbuf *m; + struct at_ifaddr *aa; + int s; + + for (;;) { +#ifndef _IBMR2 + s = splimp(); +#endif _IBMR2 + +#ifdef BSD4_4 + IF_DEQUEUE( &atintrq2, m ); +#else BSD4_4 + IF_DEQUEUEIF( &atintrq2, m, ifp ); +#endif BSD4_4 + +#ifndef _IBMR2 + splx( s ); +#endif _IBMR2 + + if ( m == 0 ) { /* no more queued packets */ + break; + } + +#ifdef BSD4_4 + ifp = m->m_pkthdr.rcvif; +#endif BSD4_4 + for ( aa = at_ifaddr; aa; aa = aa->aa_next ) { + if ( aa->aa_ifp == ifp && ( aa->aa_flags & AFA_PHASE2 )) { + break; + } + } + if ( aa == NULL ) { /* ifp not an appletalk interface */ + m_freem( m ); + continue; + } + + ddp_input( m, ifp, (struct elaphdr *)NULL, 2 ); + } + + for (;;) { +#ifndef _IBMR2 + s = splimp(); +#endif _IBMR2 + +#ifdef BSD4_4 + IF_DEQUEUE( &atintrq1, m ); +#else BSD4_4 + IF_DEQUEUEIF( &atintrq1, m, ifp ); +#endif BSD4_4 + +#ifndef _IBMR2 + splx( s ); +#endif _IBMR2 + + if ( m == 0 ) { /* no more queued packets */ + break; + } + +#ifdef BSD4_4 + ifp = m->m_pkthdr.rcvif; +#endif BSD4_4 + for ( aa = at_ifaddr; aa; aa = aa->aa_next ) { + if ( aa->aa_ifp == ifp && ( aa->aa_flags & AFA_PHASE2 ) == 0 ) { + break; + } + } + if ( aa == NULL ) { /* ifp not an appletalk interface */ + m_freem( m ); + continue; + } + + if ( m->m_len < SZ_ELAPHDR && + (( m = m_pullup( m, SZ_ELAPHDR )) == 0 )) { + ddpstat.ddps_tooshort++; + continue; + } + + elhp = mtod( m, struct elaphdr *); + m_adj( m, SZ_ELAPHDR ); + + if ( elhp->el_type == ELAP_DDPEXTEND ) { + ddp_input( m, ifp, (struct elaphdr *)NULL, 1 ); + } else { + bcopy((caddr_t)elhp, (caddr_t)&elh, SZ_ELAPHDR ); + ddp_input( m, ifp, &elh, 1 ); + } + } + return; +} + +#if defined( __FreeBSD__ ) +NETISR_SET(NETISR_ATALK, atintr); +#endif __FreeBSD__ + +struct route forwro; + +void +ddp_input( m, ifp, elh, phase ) + struct mbuf *m; + struct ifnet *ifp; + struct elaphdr *elh; + int phase; +{ + struct sockaddr_at from, to; + struct ddpshdr *dsh, ddps; + struct at_ifaddr *aa; + struct ddpehdr *deh, ddpe; +#ifndef BSD4_4 + struct mbuf *mp; +#endif BSD4_4 + struct ddpcb *ddp; + int dlen, mlen; + u_short cksum; + + bzero( (caddr_t)&from, sizeof( struct sockaddr_at )); + if ( elh ) { + ddpstat.ddps_short++; + + if ( m->m_len < sizeof( struct ddpshdr ) && + (( m = m_pullup( m, sizeof( struct ddpshdr ))) == 0 )) { + ddpstat.ddps_tooshort++; + return; + } + + dsh = mtod( m, struct ddpshdr *); + bcopy( (caddr_t)dsh, (caddr_t)&ddps, sizeof( struct ddpshdr )); + ddps.dsh_bytes = ntohl( ddps.dsh_bytes ); + dlen = ddps.dsh_len; + + to.sat_addr.s_net = ATADDR_ANYNET; + to.sat_addr.s_node = elh->el_dnode; + to.sat_port = ddps.dsh_dport; + from.sat_addr.s_net = ATADDR_ANYNET; + from.sat_addr.s_node = elh->el_snode; + from.sat_port = ddps.dsh_sport; + + for ( aa = at_ifaddr; aa; aa = aa->aa_next ) { + if ( aa->aa_ifp == ifp && ( aa->aa_flags & AFA_PHASE2 ) == 0 && + ( AA_SAT( aa )->sat_addr.s_node == to.sat_addr.s_node || + to.sat_addr.s_node == ATADDR_BCAST )) { + break; + } + } + if ( aa == NULL ) { + m_freem( m ); + return; + } + } else { + ddpstat.ddps_long++; + + if ( m->m_len < sizeof( struct ddpehdr ) && + (( m = m_pullup( m, sizeof( struct ddpehdr ))) == 0 )) { + ddpstat.ddps_tooshort++; + return; + } + + deh = mtod( m, struct ddpehdr *); + bcopy( (caddr_t)deh, (caddr_t)&ddpe, sizeof( struct ddpehdr )); + ddpe.deh_bytes = ntohl( ddpe.deh_bytes ); + dlen = ddpe.deh_len; + + if (( cksum = ddpe.deh_sum ) == 0 ) { + ddpstat.ddps_nosum++; + } + + from.sat_addr.s_net = ddpe.deh_snet; + from.sat_addr.s_node = ddpe.deh_snode; + from.sat_port = ddpe.deh_sport; + to.sat_addr.s_net = ddpe.deh_dnet; + to.sat_addr.s_node = ddpe.deh_dnode; + to.sat_port = ddpe.deh_dport; + + if ( to.sat_addr.s_net == ATADDR_ANYNET ) { + for ( aa = at_ifaddr; aa; aa = aa->aa_next ) { + if ( phase == 1 && ( aa->aa_flags & AFA_PHASE2 )) { + continue; + } + if ( phase == 2 && ( aa->aa_flags & AFA_PHASE2 ) == 0 ) { + continue; + } + if ( aa->aa_ifp == ifp && + ( AA_SAT( aa )->sat_addr.s_node == to.sat_addr.s_node || + to.sat_addr.s_node == ATADDR_BCAST || + ( ifp->if_flags & IFF_LOOPBACK ))) { + break; + } + } + } else { + for ( aa = at_ifaddr; aa; aa = aa->aa_next ) { + if ( to.sat_addr.s_net == aa->aa_firstnet && + to.sat_addr.s_node == 0 ) { + break; + } + if (( ntohs( to.sat_addr.s_net ) < ntohs( aa->aa_firstnet ) || + ntohs( to.sat_addr.s_net ) > ntohs( aa->aa_lastnet )) && + ( ntohs( to.sat_addr.s_net ) < ntohs( 0xff00 ) || + ntohs( to.sat_addr.s_net ) > ntohs( 0xfffe ))) { + continue; + } + if ( to.sat_addr.s_node != AA_SAT( aa )->sat_addr.s_node && + to.sat_addr.s_node != ATADDR_BCAST ) { + continue; + } + break; + } + } + } + + /* + * Adjust the length, removing any padding that may have been added + * at a link layer. We do this before we attempt to forward a packet, + * possibly on a different media. + */ +#ifdef BSD4_4 + mlen = m->m_pkthdr.len; +#else BSD4_4 + for ( mlen = 0, mp = m; mp; mp = mp->m_next ) { + mlen += mp->m_len; + } +#endif BSD4_4 + if ( mlen < dlen ) { + ddpstat.ddps_toosmall++; + m_freem( m ); + return; + } + if ( mlen > dlen ) { + m_adj( m, dlen - mlen ); + } + + /* + * XXX Should we deliver broadcasts locally, also, or rely on the + * link layer to give us a copy? For the moment, the latter. + */ + if ( aa == NULL || ( to.sat_addr.s_node == ATADDR_BCAST && + aa->aa_ifp != ifp && ( ifp->if_flags & IFF_LOOPBACK ) == 0 )) { + if ( ddp_forward == 0 ) { + m_freem( m ); + return; + } + if ( forwro.ro_rt && ( satosat( &forwro.ro_dst )->sat_addr.s_net != + to.sat_addr.s_net || + satosat( &forwro.ro_dst )->sat_addr.s_node != + to.sat_addr.s_node )) { +#ifdef ultrix + rtfree( forwro.ro_rt ); +#else ultrix + RTFREE( forwro.ro_rt ); +#endif ultrix + forwro.ro_rt = (struct rtentry *)0; + } + if ( forwro.ro_rt == (struct rtentry *)0 || + forwro.ro_rt->rt_ifp == (struct ifnet *)0 ) { +#ifdef BSD4_4 + forwro.ro_dst.sa_len = sizeof( struct sockaddr_at ); +#endif BSD4_4 + forwro.ro_dst.sa_family = AF_APPLETALK; + satosat( &forwro.ro_dst )->sat_addr.s_net = to.sat_addr.s_net; + satosat( &forwro.ro_dst )->sat_addr.s_node = to.sat_addr.s_node; + rtalloc( &forwro ); + } + + if ( to.sat_addr.s_net != satosat( &forwro.ro_dst )->sat_addr.s_net && + ddpe.deh_hops == DDP_MAXHOPS ) { + m_freem( m ); + return; + } + + if ( ddp_firewall && + ( forwro.ro_rt == NULL || forwro.ro_rt->rt_ifp != ifp )) { + m_freem( m ); + return; + } + + ddpe.deh_hops++; + ddpe.deh_bytes = htonl( ddpe.deh_bytes ); + bcopy( (caddr_t)&ddpe, (caddr_t)deh, sizeof( u_short )); /* XXX deh? */ + if ( ddp_route( m, &forwro )) { + ddpstat.ddps_cantforward++; + } else { + ddpstat.ddps_forward++; + } + return; + } + +#ifdef BSD4_4 + from.sat_len = sizeof( struct sockaddr_at ); +#endif BSD4_4 + from.sat_family = AF_APPLETALK; + + if ( elh ) { + m_adj( m, sizeof( struct ddpshdr )); + } else { + if ( ddp_cksum && cksum && cksum != at_cksum( m, sizeof( int ))) { + ddpstat.ddps_badsum++; + m_freem( m ); + return; + } + m_adj( m, sizeof( struct ddpehdr )); + } + + if (( ddp = ddp_search( &from, &to, aa )) == NULL ) { + m_freem( m ); + return; + } + + if ( sbappendaddr( &ddp->ddp_socket->so_rcv, (struct sockaddr *)&from, + m, (struct mbuf *)0 ) == 0 ) { + ddpstat.ddps_nosockspace++; + m_freem( m ); + return; + } + sorwakeup( ddp->ddp_socket ); +} + +#define BPXLEN 48 +#define BPALEN 16 +#include +char hexdig[] = "0123456789ABCDEF"; + +static void +bprint( char *data, int len ) +{ + char xout[ BPXLEN ], aout[ BPALEN ]; + int i = 0; + + bzero( xout, BPXLEN ); + bzero( aout, BPALEN ); + + for ( ;; ) { + if ( len < 1 ) { + if ( i != 0 ) { + printf( "%s\t%s\n", xout, aout ); + } + printf( "%s\n", "(end)" ); + break; + } + + xout[ (i*3) ] = hexdig[ ( *data & 0xf0 ) >> 4 ]; + xout[ (i*3) + 1 ] = hexdig[ *data & 0x0f ]; + + if ( (u_char)*data < 0x7f && (u_char)*data > 0x20 ) { + aout[ i ] = *data; + } else { + aout[ i ] = '.'; + } + + xout[ (i*3) + 2 ] = ' '; + + i++; + len--; + data++; + + if ( i > BPALEN - 2 ) { + printf( "%s\t%s\n", xout, aout ); + bzero( xout, BPXLEN ); + bzero( aout, BPALEN ); + i = 0; + continue; + } + } +} + +static void +m_printm( struct mbuf *m ) +{ + for (; m; m = m->m_next ) { + bprint( mtod( m, char * ), m->m_len ); + } +} diff --git a/sys/netatalk/ddp_output.c b/sys/netatalk/ddp_output.c new file mode 100644 index 000000000000..54a2c7a51cbf --- /dev/null +++ b/sys/netatalk/ddp_output.c @@ -0,0 +1,298 @@ +/* + * Copyright (c) 1990,1991 Regents of The University of Michigan. + * All Rights Reserved. + * + * Permission to use, copy, modify, and distribute this software and + * its documentation for any purpose and without fee is hereby granted, + * provided that the above copyright notice appears in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation, and that the name of The University + * of Michigan not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. This software is supplied as is without expressed or + * implied warranties of any kind. + * + * Research Systems Unix Group + * The University of Michigan + * c/o Mike Clark + * 535 W. William Street + * Ann Arbor, Michigan + * +1-313-763-0525 + * netatalk@itd.umich.edu + */ + +#include +#include +#if defined( __FreeBSD__ ) +#include +#endif __FreeBSD__ +#include +#include +#include +#include + +#include +#include + +#include +#undef s_net +#include + +#include "at.h" +#include "at_var.h" +#include "endian.h" +#include "ddp.h" +#include "ddp_var.h" +#include + +int ddp_cksum = 1; + +int +ddp_output( struct ddpcb *ddp, struct mbuf *m) +{ +#ifndef BSD4_4 + struct mbuf *m0; + int len; +#endif BSD4_4 + struct ifnet *ifp; + struct at_ifaddr *aa = NULL; + struct ddpehdr *deh; + u_short net; + +#ifdef BSD4_4 + M_PREPEND( m, sizeof( struct ddpehdr ), M_WAIT ); +#else BSD4_4 + for ( len = 0, m0 = m; m; m = m->m_next ) { + len += m->m_len; + } + MGET( m, M_WAIT, MT_HEADER ); + if ( m == 0 ) { + m_freem( m0 ); + return( ENOBUFS ); + } + m->m_next = m0; +#endif BSD4_4 + +#ifndef BSD4_4 +# define align(a) (((a)+3)&0xfc) + m->m_off = MMINOFF + align( SZ_ELAPHDR ); + m->m_len = sizeof( struct ddpehdr ); +#endif BSD4_4 + + deh = mtod( m, struct ddpehdr *); + deh->deh_pad = 0; + deh->deh_hops = 0; + +#ifdef BSD4_4 + deh->deh_len = m->m_pkthdr.len; +#else BSD4_4 + deh->deh_len = len + sizeof( struct ddpehdr ); +#endif BSD4_4 + + deh->deh_dnet = ddp->ddp_fsat.sat_addr.s_net; + deh->deh_dnode = ddp->ddp_fsat.sat_addr.s_node; + deh->deh_dport = ddp->ddp_fsat.sat_port; + deh->deh_snet = ddp->ddp_lsat.sat_addr.s_net; + deh->deh_snode = ddp->ddp_lsat.sat_addr.s_node; + deh->deh_sport = ddp->ddp_lsat.sat_port; + + /* + * The checksum calculation is done after all of the other bytes have + * been filled in. + */ + if ( ddp_cksum ) { + deh->deh_sum = at_cksum( m, sizeof( int )); + } else { + deh->deh_sum = 0; + } + deh->deh_bytes = htonl( deh->deh_bytes ); + + return( ddp_route( m, &ddp->ddp_route )); +} + +u_short +at_cksum( struct mbuf *m, int skip) +{ + u_char *data, *end; + u_long cksum = 0; + + for (; m; m = m->m_next ) { + for ( data = mtod( m, u_char * ), end = data + m->m_len; data < end; + data++ ) { + if ( skip ) { + skip--; + continue; + } + cksum = ( cksum + *data ) << 1; + if ( cksum & 0x00010000 ) { + cksum++; + } + cksum &= 0x0000ffff; + } + } + + if ( cksum == 0 ) { + cksum = 0x0000ffff; + } + return( (u_short)cksum ); +} + +int +ddp_route( struct mbuf *m, struct route *ro) +{ + struct sockaddr_at gate; + struct elaphdr *elh; + struct mbuf *m0; + struct at_ifaddr *aa = NULL; + struct ifnet *ifp = NULL; + int mlen; + u_short net; + + if ( ro->ro_rt && ( ifp = ro->ro_rt->rt_ifp )) { +#ifdef BSD4_4 + net = satosat( ro->ro_rt->rt_gateway )->sat_addr.s_net; +#else BSD4_4 + net = satosat( &ro->ro_rt->rt_gateway )->sat_addr.s_net; +#endif BSD4_4 + for ( aa = at_ifaddr; aa; aa = aa->aa_next ) { + if ( aa->aa_ifp == ifp && + ntohs( net ) >= ntohs( aa->aa_firstnet ) && + ntohs( net ) <= ntohs( aa->aa_lastnet )) { + break; + } + } + } + if ( aa == NULL ) { +printf( "ddp_route: oops\n" ); + m_freem( m ); + return( EINVAL ); + } + + /* + * There are several places in the kernel where data is added to + * an mbuf without ensuring that the mbuf pointer is aligned. + * This is bad for transition routing, since phase 1 and phase 2 + * packets end up poorly aligned due to the three byte elap header. + */ + if ( aa->aa_flags & AFA_PHASE2 ) { +#if defined( __FreeBSD__ ) + /* XXX don't need this because we can change if_ethersubr.c */ +#else + for ( mlen = 0, m0 = m; m0; m0 = m0->m_next ) { + mlen += m0->m_len; + } +#ifndef MIN +#define MIN(x,y) ((x)<(y)?(x):(y)) +#endif + if (( m = m_pullup( m, MIN( MLEN, mlen ))) == 0 ) { + printf("ddp_route: m_pullup of %d (mlen=%d) failed\n", + MIN( MLEN, mlen ), mlen); + return( ENOBUFS ); + } +#endif __FreeBSD__ + } else { +# ifdef notdef +#ifdef BSD4_4 + M_PREPEND( m, SZ_ELAPHDR, M_DONTWAIT ); + if ( m == NULL ) { + return( ENOBUFS ); + } +#else BSD4_4 + m->m_off -= SZ_ELAPHDR; + m->m_len += SZ_ELAPHDR; +#endif BSD4_4 +# endif notdef + + MGET( m0, M_WAIT, MT_HEADER ); + if ( m0 == 0 ) { + m_freem( m ); + printf("ddp_route: no buffers\n"); + return( ENOBUFS ); + } + m0->m_next = m; + +#ifndef BSD4_4 + m0->m_off = MMINOFF + align( sizeof( struct ether_header )); +#else + /* XXX perhaps we ought to align the header? */ +#endif BSD4_4 + m0->m_len = SZ_ELAPHDR; + m = m0; + + elh = mtod( m, struct elaphdr *); + elh->el_snode = satosat( &aa->aa_addr )->sat_addr.s_node; + elh->el_type = ELAP_DDPEXTEND; + if ( ntohs( satosat( &ro->ro_dst )->sat_addr.s_net ) >= + ntohs( aa->aa_firstnet ) && + ntohs( satosat( &ro->ro_dst )->sat_addr.s_net ) <= + ntohs( aa->aa_lastnet )) { + elh->el_dnode = satosat( &ro->ro_dst )->sat_addr.s_node; + } else { +#ifdef BSD4_4 + elh->el_dnode = satosat( ro->ro_rt->rt_gateway )->sat_addr.s_node; +#else BSD4_4 + elh->el_dnode = satosat( &ro->ro_rt->rt_gateway )->sat_addr.s_node; +#endif BSD4_4 + } + } + + if ( ntohs( satosat( &ro->ro_dst )->sat_addr.s_net ) >= + ntohs( aa->aa_firstnet ) && + ntohs( satosat( &ro->ro_dst )->sat_addr.s_net ) <= + ntohs( aa->aa_lastnet )) { + gate = *satosat( &ro->ro_dst ); + } else { +#ifdef BSD4_4 + gate = *satosat( ro->ro_rt->rt_gateway ); +#else BSD4_4 + gate = *satosat( &ro->ro_rt->rt_gateway ); +#endif BSD4_4 + } + ro->ro_rt->rt_use++; + +#ifdef ultrix + /* + * SAIEW: We can't make changes to net/if_loop.c, so we don't route + * further than this: if it's going to go through the lookback, + * short-circuit to ddp_input(). Who needs queuing? + * + * Note: Passing NULL for the elaphdr is cool, since we'll only ever + * try to send long form ddp throught the loopback. + */ + if ( ifp->if_flags & IFF_LOOPBACK ) { +#ifdef notdef + m->m_off += SZ_ELAPHDR; + m->m_len -= SZ_ELAPHDR; +#endif notdef + ddp_input( m, ifp, (struct elaphdr *)NULL, 2 ); + return( 0 ); + } +#endif ultrix + +#ifdef _IBMR2 + /* + * We can't make changes to the interface routines on RS6ks, and + * they don't provide hooks for if_output, so we just resolve + * our address here, and pass the packet as a raw ethernet packet. + * This doesn't work particularly well, if we aren't *on* ethernet, + * but it's ok for the moment. + */ + if ( ! ( ifp->if_flags & IFF_LOOPBACK )) { + struct ether_header eh; + + if ( !aarpresolve(( struct arpcom *)ifp, m, + &gate, eh.ether_dhost )) { + return( 0 ); + } + eh.ether_type = htons( ETHERTYPE_AT ); + gate.sat_family = AF_UNSPEC; + bcopy( &eh, (*(struct sockaddr *)&gate).sa_data, + sizeof( (*(struct sockaddr *)&gate).sa_data )); + } +#endif _IBMR2 + return((*ifp->if_output)( ifp, m, &gate +#if defined( __FreeBSD__ ) + , NULL /* XXX */ +#endif __FreeBSD__ + )); +} diff --git a/sys/netatalk/ddp_pcb.c b/sys/netatalk/ddp_pcb.c new file mode 100644 index 000000000000..d85bc719e9c0 --- /dev/null +++ b/sys/netatalk/ddp_pcb.c @@ -0,0 +1,582 @@ +/* + * Copyright (c) 1990,1994 Regents of The University of Michigan. + * All Rights Reserved. See COPYRIGHT. + */ + +#include +#include +#include +#include +#if defined( __FreeBSD__ ) +#include +#endif __FreeBSD__ +#ifdef ibm032 +#include +#endif ibm032 +#ifndef __FreeBSD__ +#include +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef _IBMR2 +#include +#endif _IBMR2 + +#include "at.h" +#include "at_var.h" +#include "ddp_var.h" +#include "aarp.h" +#include "endian.h" +#include + +static void at_pcbdisconnect( struct ddpcb *ddp ); +static void at_sockaddr( struct ddpcb *ddp, struct mbuf *addr ); +static int at_pcbsetaddr( struct ddpcb *ddp, struct mbuf *addr, struct proc *p); +static int at_pcbconnect( struct ddpcb *ddp, struct mbuf *addr, struct proc *p); +static void at_pcbdetach( struct socket *so, struct ddpcb *ddp); +static int at_pcballoc( struct socket *so ); + +struct ddpcb *ddp_ports[ ATPORT_LAST ]; +struct ddpcb *ddpcb = NULL; +u_long ddp_sendspace = DDP_MAXSZ; /* Max ddp size + 1 (ddp_type) */ +u_long ddp_recvspace = 10 * ( 587 + sizeof( struct sockaddr_at )); + +/*ARGSUSED*/ +int +ddp_usrreq( struct socket *so, int req, struct mbuf *m, + struct mbuf *addr, struct mbuf *rights) +{ +#if defined( __FreeBSD__ ) + struct proc *p = curproc; /* XXX */ +#endif __FreeBSD__ + struct ddpcb *ddp; + int error = 0; + + ddp = sotoddpcb( so ); + + if ( req == PRU_CONTROL ) { + return( at_control( (int) m, (caddr_t) addr, + (struct ifnet *) rights +#if defined( __FreeBSD__ ) + , (struct proc *)p +#endif __FreeBSD__ + )); + } + + if ( rights && rights->m_len ) { + error = EINVAL; + goto release; + } + + if ( ddp == NULL && req != PRU_ATTACH ) { + error = EINVAL; + goto release; + } + + switch ( req ) { + case PRU_ATTACH : + if ( ddp != NULL ) { + error = EINVAL; + break; + } + if (( error = at_pcballoc( so )) != 0 ) { + break; + } + error = soreserve( so, ddp_sendspace, ddp_recvspace ); + break; + + case PRU_DETACH : + at_pcbdetach( so, ddp ); + break; + + case PRU_BIND : + error = at_pcbsetaddr( ddp, addr +#if defined( __FreeBSD__ ) + , p +#endif __FreeBSD__ + ); + break; + + case PRU_SOCKADDR : + at_sockaddr( ddp, addr ); + break; + + case PRU_CONNECT: + if ( ddp->ddp_fsat.sat_port != ATADDR_ANYPORT ) { + error = EISCONN; + break; + } + + error = at_pcbconnect( ddp, addr +#if defined( __FreeBSD__ ) + , p +#endif __FreeBSD__ + ); + if ( error == 0 ) + soisconnected( so ); + break; + + case PRU_DISCONNECT: + if ( ddp->ddp_fsat.sat_addr.s_node == ATADDR_ANYNODE ) { + error = ENOTCONN; + break; + } + at_pcbdisconnect( ddp ); + soisdisconnected( so ); + break; + + case PRU_SHUTDOWN: + socantsendmore( so ); + break; + + case PRU_SEND: { + int s = 0; + + if ( addr ) { + if ( ddp->ddp_fsat.sat_port != ATADDR_ANYPORT ) { + error = EISCONN; + break; + } + + s = splnet(); + error = at_pcbconnect( ddp, addr +#if defined( __FreeBSD__ ) + , p +#endif __FreeBSD__ + ); + if ( error ) { + splx( s ); + break; + } + } else { + if ( ddp->ddp_fsat.sat_port == ATADDR_ANYPORT ) { + error = ENOTCONN; + break; + } + } + + error = ddp_output( ddp, m ); + m = NULL; + if ( addr ) { + at_pcbdisconnect( ddp ); + splx( s ); + } + } + break; + + case PRU_ABORT: + soisdisconnected( so ); + at_pcbdetach( so, ddp ); + break; + + case PRU_LISTEN: + case PRU_CONNECT2: + case PRU_ACCEPT: + case PRU_SENDOOB: + case PRU_FASTTIMO: + case PRU_SLOWTIMO: + case PRU_PROTORCV: + case PRU_PROTOSEND: + error = EOPNOTSUPP; + break; + + case PRU_RCVD: + case PRU_RCVOOB: + /* + * Don't mfree. Good architecture... + */ + return( EOPNOTSUPP ); + + case PRU_SENSE: + /* + * 1. Don't return block size. + * 2. Don't mfree. + */ + return( 0 ); + + default: + error = EOPNOTSUPP; + } + +release: + if ( m != NULL ) { + m_freem( m ); + } + return( error ); +} + +static void +at_sockaddr( struct ddpcb *ddp, struct mbuf *addr) +{ + struct sockaddr_at *sat; + + addr->m_len = sizeof( struct sockaddr_at ); + sat = mtod( addr, struct sockaddr_at *); + *sat = ddp->ddp_lsat; +} + +static int +at_pcbsetaddr( struct ddpcb *ddp, struct mbuf *addr, struct proc *p ) +{ + struct sockaddr_at lsat, *sat; + struct at_ifaddr *aa; + struct ddpcb *ddpp; + + if ( ddp->ddp_lsat.sat_port != ATADDR_ANYPORT ) { /* shouldn't be bound */ + return( EINVAL ); + } + + if ( addr != 0 ) { /* validate passed address */ + sat = mtod( addr, struct sockaddr_at *); + if ( addr->m_len != sizeof( *sat )) { + return( EINVAL ); + } + if ( sat->sat_family != AF_APPLETALK ) { + return( EAFNOSUPPORT ); + } + + if ( sat->sat_addr.s_node != ATADDR_ANYNODE || + sat->sat_addr.s_net != ATADDR_ANYNET ) { + for ( aa = at_ifaddr; aa; aa = aa->aa_next ) { + if (( sat->sat_addr.s_net == AA_SAT( aa )->sat_addr.s_net ) && + ( sat->sat_addr.s_node == AA_SAT( aa )->sat_addr.s_node )) { + break; + } + } + if ( !aa ) { + return( EADDRNOTAVAIL ); + } + } + + if ( sat->sat_port != ATADDR_ANYPORT ) { + if ( sat->sat_port < ATPORT_FIRST || + sat->sat_port >= ATPORT_LAST ) { + return( EINVAL ); + } +#ifdef BSD4_4 + if ( sat->sat_port < ATPORT_RESERVED && +#if defined( __FreeBSD__ ) + suser( p->p_ucred, &p->p_acflag ) +#else + suser( u.u_cred, &u.u_acflag ) +#endif __FreeBSD__ + ) { + return( EACCES ); + } +#else BSD4_4 + if ( sat->sat_port < ATPORT_RESERVED && ( !suser())) { + return( EACCES ); + } +#endif BSD4_4 + } + } else { + bzero( (caddr_t)&lsat, sizeof( struct sockaddr_at )); +#ifdef BSD4_4 + lsat.sat_len = sizeof(struct sockaddr_at); + lsat.sat_addr.s_node = ATADDR_ANYNODE; + lsat.sat_addr.s_net = ATADDR_ANYNET; +#endif BSD4_4 + lsat.sat_family = AF_APPLETALK; + sat = &lsat; + } + + if ( sat->sat_addr.s_node == ATADDR_ANYNODE && + sat->sat_addr.s_net == ATADDR_ANYNET ) { + if ( at_ifaddr == NULL ) { + return( EADDRNOTAVAIL ); + } + sat->sat_addr = AA_SAT( at_ifaddr )->sat_addr; + } + ddp->ddp_lsat = *sat; + + /* + * Choose port. + */ + if ( sat->sat_port == ATADDR_ANYPORT ) { + for ( sat->sat_port = ATPORT_RESERVED; + sat->sat_port < ATPORT_LAST; sat->sat_port++ ) { + if ( ddp_ports[ sat->sat_port - 1 ] == 0 ) { + break; + } + } + if ( sat->sat_port == ATPORT_LAST ) { + return( EADDRNOTAVAIL ); + } + ddp->ddp_lsat.sat_port = sat->sat_port; + ddp_ports[ sat->sat_port - 1 ] = ddp; + } else { + for ( ddpp = ddp_ports[ sat->sat_port - 1 ]; ddpp; + ddpp = ddpp->ddp_pnext ) { + if ( ddpp->ddp_lsat.sat_addr.s_net == sat->sat_addr.s_net && + ddpp->ddp_lsat.sat_addr.s_node == sat->sat_addr.s_node ) { + break; + } + } + if ( ddpp != NULL ) { + return( EADDRINUSE ); + } + ddp->ddp_pnext = ddp_ports[ sat->sat_port - 1 ]; + ddp_ports[ sat->sat_port - 1 ] = ddp; + if ( ddp->ddp_pnext ) { + ddp->ddp_pnext->ddp_pprev = ddp; + } + } + + return( 0 ); +} + +static int +at_pcbconnect( struct ddpcb *ddp, struct mbuf *addr, struct proc *p) +{ + struct sockaddr_at *sat = mtod( addr, struct sockaddr_at *); + struct route *ro; + struct at_ifaddr *aa = 0; + struct ifnet *ifp; + u_short hintnet = 0, net; + + if ( addr->m_len != sizeof( *sat )) + return( EINVAL ); + if ( sat->sat_family != AF_APPLETALK ) { + return( EAFNOSUPPORT ); + } + + /* + * Under phase 2, network 0 means "the network". We take "the + * network" to mean the network the control block is bound to. + * If the control block is not bound, there is an error. + */ + if ( sat->sat_addr.s_net == ATADDR_ANYNET + && sat->sat_addr.s_node != ATADDR_ANYNODE ) { + if ( ddp->ddp_lsat.sat_port == ATADDR_ANYPORT ) { + return( EADDRNOTAVAIL ); + } + hintnet = ddp->ddp_lsat.sat_addr.s_net; + } + + ro = &ddp->ddp_route; + /* + * If we've got an old route for this pcb, check that it is valid. + * If we've changed our address, we may have an old "good looking" + * route here. Attempt to detect it. + */ + if ( ro->ro_rt ) { + if ( hintnet ) { + net = hintnet; + } else { + net = sat->sat_addr.s_net; + } + aa = 0; + if ( ifp = ro->ro_rt->rt_ifp ) { + for ( aa = at_ifaddr; aa; aa = aa->aa_next ) { + if ( aa->aa_ifp == ifp && + ntohs( net ) >= ntohs( aa->aa_firstnet ) && + ntohs( net ) <= ntohs( aa->aa_lastnet )) { + printf("at_pcbconnect: found ifp net=%u\n", ntohs(net)); + break; + } + } + } + if ( aa == NULL || ( satosat( &ro->ro_dst )->sat_addr.s_net != + ( hintnet ? hintnet : sat->sat_addr.s_net ) || + satosat( &ro->ro_dst )->sat_addr.s_node != + sat->sat_addr.s_node )) { + printf("at_pcbconnect: freeing ro->ro_rt=0x%x\n", ro->ro_rt); +#ifdef ultrix + rtfree( ro->ro_rt ); +#else ultrix + RTFREE( ro->ro_rt ); +#endif ultrix + ro->ro_rt = (struct rtentry *)0; + } + } + + /* + * If we've got no route for this interface, try to find one. + */ + if ( ro->ro_rt == (struct rtentry *)0 || + ro->ro_rt->rt_ifp == (struct ifnet *)0 ) { +#ifdef BSD4_4 + ro->ro_dst.sa_len = sizeof( struct sockaddr_at ); +#endif BSD4_4 + ro->ro_dst.sa_family = AF_APPLETALK; + if ( hintnet ) { + satosat( &ro->ro_dst )->sat_addr.s_net = hintnet; + } else { + satosat( &ro->ro_dst )->sat_addr.s_net = sat->sat_addr.s_net; + } + satosat( &ro->ro_dst )->sat_addr.s_node = sat->sat_addr.s_node; + rtalloc( ro ); + } + + /* + * Make sure any route that we have has a valid interface. + */ + aa = 0; + if ( ro->ro_rt && ( ifp = ro->ro_rt->rt_ifp )) { + for ( aa = at_ifaddr; aa; aa = aa->aa_next ) { + if ( aa->aa_ifp == ifp ) { + break; + } + } + } + if ( aa == 0 ) { + printf("at_pcbconnect: ro->ro_rt=0x%x\n", ro->ro_rt); + if (ro->ro_rt) + printf("at_pcbconnect: ro->ro_rt->rt_ifp=0x%x", ro->ro_rt->rt_ifp); + return( ENETUNREACH ); + } + + ddp->ddp_fsat = *sat; + if ( ddp->ddp_lsat.sat_port == ATADDR_ANYPORT ) { + return( at_pcbsetaddr( ddp, (struct mbuf *)0 +#if defined( __FreeBSD__ ) + , p +#endif __FreeBSD__ + )); + } + return( 0 ); +} + +static void +at_pcbdisconnect( struct ddpcb *ddp ) +{ + ddp->ddp_fsat.sat_addr.s_net = ATADDR_ANYNET; + ddp->ddp_fsat.sat_addr.s_node = ATADDR_ANYNODE; + ddp->ddp_fsat.sat_port = ATADDR_ANYPORT; +} + +static int +at_pcballoc( struct socket *so ) +{ + struct ddpcb *ddp; + struct mbuf *m; + + m = m_getclr( M_WAIT, MT_PCB ); + ddp = mtod( m, struct ddpcb * ); + ddp->ddp_lsat.sat_port = ATADDR_ANYPORT; + + ddp->ddp_next = ddpcb; + ddp->ddp_prev = NULL; + ddp->ddp_pprev = NULL; + ddp->ddp_pnext = NULL; + if ( ddpcb ) { + ddpcb->ddp_prev = ddp; + } + ddpcb = ddp; + + ddp->ddp_socket = so; + so->so_pcb = (caddr_t)ddp; + return( 0 ); +} + +static void +at_pcbdetach( struct socket *so, struct ddpcb *ddp) +{ + soisdisconnected( so ); + so->so_pcb = 0; + sofree( so ); + + /* remove ddp from ddp_ports list */ + if ( ddp->ddp_lsat.sat_port != ATADDR_ANYPORT && + ddp_ports[ ddp->ddp_lsat.sat_port - 1 ] != NULL ) { + if ( ddp->ddp_pprev != NULL ) { + ddp->ddp_pprev->ddp_pnext = ddp->ddp_pnext; + } else { + ddp_ports[ ddp->ddp_lsat.sat_port - 1 ] = ddp->ddp_pnext; + } + if ( ddp->ddp_pnext != NULL ) { + ddp->ddp_pnext->ddp_pprev = ddp->ddp_pprev; + } + } + + if ( ddp->ddp_route.ro_rt ) { + rtfree( ddp->ddp_route.ro_rt ); + } + + if ( ddp->ddp_prev ) { + ddp->ddp_prev->ddp_next = ddp->ddp_next; + } else { + ddpcb = ddp->ddp_next; + } + if ( ddp->ddp_next ) { + ddp->ddp_next->ddp_prev = ddp->ddp_prev; + } + + (void) m_free( dtom( ddp )); +} + +/* + * For the moment, this just find the pcb with the correct local address. + * In the future, this will actually do some real searching, so we can use + * the sender's address to do de-multiplexing on a single port to many + * sockets (pcbs). + */ +struct ddpcb * +ddp_search( struct sockaddr_at *from, struct sockaddr_at *to, + struct at_ifaddr *aa) +{ + struct ddpcb *ddp; + + /* + * Check for bad ports. + */ + if ( to->sat_port < ATPORT_FIRST || to->sat_port >= ATPORT_LAST ) { + return( NULL ); + } + + /* + * Make sure the local address matches the sent address. What about + * the interface? + */ + for ( ddp = ddp_ports[ to->sat_port - 1 ]; ddp; ddp = ddp->ddp_pnext ) { + /* XXX should we handle 0.YY? */ + + /* XXXX.YY to socket on destination interface */ + if ( to->sat_addr.s_net == ddp->ddp_lsat.sat_addr.s_net && + to->sat_addr.s_node == ddp->ddp_lsat.sat_addr.s_node ) { + break; + } + + /* 0.255 to socket on receiving interface */ + if ( to->sat_addr.s_node == ATADDR_BCAST && ( to->sat_addr.s_net == 0 || + to->sat_addr.s_net == ddp->ddp_lsat.sat_addr.s_net ) && + ddp->ddp_lsat.sat_addr.s_net == AA_SAT( aa )->sat_addr.s_net ) { + break; + } + + /* XXXX.0 to socket on destination interface */ + if ( to->sat_addr.s_net == aa->aa_firstnet && + to->sat_addr.s_node == 0 && + ntohs( ddp->ddp_lsat.sat_addr.s_net ) >= + ntohs( aa->aa_firstnet ) && + ntohs( ddp->ddp_lsat.sat_addr.s_net ) <= + ntohs( aa->aa_lastnet )) { + break; + } + } + return( ddp ); +} + +void +ddp_init(void ) +{ + atintrq1.ifq_maxlen = IFQ_MAXLEN; + atintrq2.ifq_maxlen = IFQ_MAXLEN; +} + +static void +ddp_clean(void ) +{ + struct ddpcb *ddp; + + for ( ddp = ddpcb; ddp; ddp = ddp->ddp_next ) { + at_pcbdetach( ddp->ddp_socket, ddp ); + } +} diff --git a/sys/netatalk/ddp_usrreq.c b/sys/netatalk/ddp_usrreq.c new file mode 100644 index 000000000000..d85bc719e9c0 --- /dev/null +++ b/sys/netatalk/ddp_usrreq.c @@ -0,0 +1,582 @@ +/* + * Copyright (c) 1990,1994 Regents of The University of Michigan. + * All Rights Reserved. See COPYRIGHT. + */ + +#include +#include +#include +#include +#if defined( __FreeBSD__ ) +#include +#endif __FreeBSD__ +#ifdef ibm032 +#include +#endif ibm032 +#ifndef __FreeBSD__ +#include +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef _IBMR2 +#include +#endif _IBMR2 + +#include "at.h" +#include "at_var.h" +#include "ddp_var.h" +#include "aarp.h" +#include "endian.h" +#include + +static void at_pcbdisconnect( struct ddpcb *ddp ); +static void at_sockaddr( struct ddpcb *ddp, struct mbuf *addr ); +static int at_pcbsetaddr( struct ddpcb *ddp, struct mbuf *addr, struct proc *p); +static int at_pcbconnect( struct ddpcb *ddp, struct mbuf *addr, struct proc *p); +static void at_pcbdetach( struct socket *so, struct ddpcb *ddp); +static int at_pcballoc( struct socket *so ); + +struct ddpcb *ddp_ports[ ATPORT_LAST ]; +struct ddpcb *ddpcb = NULL; +u_long ddp_sendspace = DDP_MAXSZ; /* Max ddp size + 1 (ddp_type) */ +u_long ddp_recvspace = 10 * ( 587 + sizeof( struct sockaddr_at )); + +/*ARGSUSED*/ +int +ddp_usrreq( struct socket *so, int req, struct mbuf *m, + struct mbuf *addr, struct mbuf *rights) +{ +#if defined( __FreeBSD__ ) + struct proc *p = curproc; /* XXX */ +#endif __FreeBSD__ + struct ddpcb *ddp; + int error = 0; + + ddp = sotoddpcb( so ); + + if ( req == PRU_CONTROL ) { + return( at_control( (int) m, (caddr_t) addr, + (struct ifnet *) rights +#if defined( __FreeBSD__ ) + , (struct proc *)p +#endif __FreeBSD__ + )); + } + + if ( rights && rights->m_len ) { + error = EINVAL; + goto release; + } + + if ( ddp == NULL && req != PRU_ATTACH ) { + error = EINVAL; + goto release; + } + + switch ( req ) { + case PRU_ATTACH : + if ( ddp != NULL ) { + error = EINVAL; + break; + } + if (( error = at_pcballoc( so )) != 0 ) { + break; + } + error = soreserve( so, ddp_sendspace, ddp_recvspace ); + break; + + case PRU_DETACH : + at_pcbdetach( so, ddp ); + break; + + case PRU_BIND : + error = at_pcbsetaddr( ddp, addr +#if defined( __FreeBSD__ ) + , p +#endif __FreeBSD__ + ); + break; + + case PRU_SOCKADDR : + at_sockaddr( ddp, addr ); + break; + + case PRU_CONNECT: + if ( ddp->ddp_fsat.sat_port != ATADDR_ANYPORT ) { + error = EISCONN; + break; + } + + error = at_pcbconnect( ddp, addr +#if defined( __FreeBSD__ ) + , p +#endif __FreeBSD__ + ); + if ( error == 0 ) + soisconnected( so ); + break; + + case PRU_DISCONNECT: + if ( ddp->ddp_fsat.sat_addr.s_node == ATADDR_ANYNODE ) { + error = ENOTCONN; + break; + } + at_pcbdisconnect( ddp ); + soisdisconnected( so ); + break; + + case PRU_SHUTDOWN: + socantsendmore( so ); + break; + + case PRU_SEND: { + int s = 0; + + if ( addr ) { + if ( ddp->ddp_fsat.sat_port != ATADDR_ANYPORT ) { + error = EISCONN; + break; + } + + s = splnet(); + error = at_pcbconnect( ddp, addr +#if defined( __FreeBSD__ ) + , p +#endif __FreeBSD__ + ); + if ( error ) { + splx( s ); + break; + } + } else { + if ( ddp->ddp_fsat.sat_port == ATADDR_ANYPORT ) { + error = ENOTCONN; + break; + } + } + + error = ddp_output( ddp, m ); + m = NULL; + if ( addr ) { + at_pcbdisconnect( ddp ); + splx( s ); + } + } + break; + + case PRU_ABORT: + soisdisconnected( so ); + at_pcbdetach( so, ddp ); + break; + + case PRU_LISTEN: + case PRU_CONNECT2: + case PRU_ACCEPT: + case PRU_SENDOOB: + case PRU_FASTTIMO: + case PRU_SLOWTIMO: + case PRU_PROTORCV: + case PRU_PROTOSEND: + error = EOPNOTSUPP; + break; + + case PRU_RCVD: + case PRU_RCVOOB: + /* + * Don't mfree. Good architecture... + */ + return( EOPNOTSUPP ); + + case PRU_SENSE: + /* + * 1. Don't return block size. + * 2. Don't mfree. + */ + return( 0 ); + + default: + error = EOPNOTSUPP; + } + +release: + if ( m != NULL ) { + m_freem( m ); + } + return( error ); +} + +static void +at_sockaddr( struct ddpcb *ddp, struct mbuf *addr) +{ + struct sockaddr_at *sat; + + addr->m_len = sizeof( struct sockaddr_at ); + sat = mtod( addr, struct sockaddr_at *); + *sat = ddp->ddp_lsat; +} + +static int +at_pcbsetaddr( struct ddpcb *ddp, struct mbuf *addr, struct proc *p ) +{ + struct sockaddr_at lsat, *sat; + struct at_ifaddr *aa; + struct ddpcb *ddpp; + + if ( ddp->ddp_lsat.sat_port != ATADDR_ANYPORT ) { /* shouldn't be bound */ + return( EINVAL ); + } + + if ( addr != 0 ) { /* validate passed address */ + sat = mtod( addr, struct sockaddr_at *); + if ( addr->m_len != sizeof( *sat )) { + return( EINVAL ); + } + if ( sat->sat_family != AF_APPLETALK ) { + return( EAFNOSUPPORT ); + } + + if ( sat->sat_addr.s_node != ATADDR_ANYNODE || + sat->sat_addr.s_net != ATADDR_ANYNET ) { + for ( aa = at_ifaddr; aa; aa = aa->aa_next ) { + if (( sat->sat_addr.s_net == AA_SAT( aa )->sat_addr.s_net ) && + ( sat->sat_addr.s_node == AA_SAT( aa )->sat_addr.s_node )) { + break; + } + } + if ( !aa ) { + return( EADDRNOTAVAIL ); + } + } + + if ( sat->sat_port != ATADDR_ANYPORT ) { + if ( sat->sat_port < ATPORT_FIRST || + sat->sat_port >= ATPORT_LAST ) { + return( EINVAL ); + } +#ifdef BSD4_4 + if ( sat->sat_port < ATPORT_RESERVED && +#if defined( __FreeBSD__ ) + suser( p->p_ucred, &p->p_acflag ) +#else + suser( u.u_cred, &u.u_acflag ) +#endif __FreeBSD__ + ) { + return( EACCES ); + } +#else BSD4_4 + if ( sat->sat_port < ATPORT_RESERVED && ( !suser())) { + return( EACCES ); + } +#endif BSD4_4 + } + } else { + bzero( (caddr_t)&lsat, sizeof( struct sockaddr_at )); +#ifdef BSD4_4 + lsat.sat_len = sizeof(struct sockaddr_at); + lsat.sat_addr.s_node = ATADDR_ANYNODE; + lsat.sat_addr.s_net = ATADDR_ANYNET; +#endif BSD4_4 + lsat.sat_family = AF_APPLETALK; + sat = &lsat; + } + + if ( sat->sat_addr.s_node == ATADDR_ANYNODE && + sat->sat_addr.s_net == ATADDR_ANYNET ) { + if ( at_ifaddr == NULL ) { + return( EADDRNOTAVAIL ); + } + sat->sat_addr = AA_SAT( at_ifaddr )->sat_addr; + } + ddp->ddp_lsat = *sat; + + /* + * Choose port. + */ + if ( sat->sat_port == ATADDR_ANYPORT ) { + for ( sat->sat_port = ATPORT_RESERVED; + sat->sat_port < ATPORT_LAST; sat->sat_port++ ) { + if ( ddp_ports[ sat->sat_port - 1 ] == 0 ) { + break; + } + } + if ( sat->sat_port == ATPORT_LAST ) { + return( EADDRNOTAVAIL ); + } + ddp->ddp_lsat.sat_port = sat->sat_port; + ddp_ports[ sat->sat_port - 1 ] = ddp; + } else { + for ( ddpp = ddp_ports[ sat->sat_port - 1 ]; ddpp; + ddpp = ddpp->ddp_pnext ) { + if ( ddpp->ddp_lsat.sat_addr.s_net == sat->sat_addr.s_net && + ddpp->ddp_lsat.sat_addr.s_node == sat->sat_addr.s_node ) { + break; + } + } + if ( ddpp != NULL ) { + return( EADDRINUSE ); + } + ddp->ddp_pnext = ddp_ports[ sat->sat_port - 1 ]; + ddp_ports[ sat->sat_port - 1 ] = ddp; + if ( ddp->ddp_pnext ) { + ddp->ddp_pnext->ddp_pprev = ddp; + } + } + + return( 0 ); +} + +static int +at_pcbconnect( struct ddpcb *ddp, struct mbuf *addr, struct proc *p) +{ + struct sockaddr_at *sat = mtod( addr, struct sockaddr_at *); + struct route *ro; + struct at_ifaddr *aa = 0; + struct ifnet *ifp; + u_short hintnet = 0, net; + + if ( addr->m_len != sizeof( *sat )) + return( EINVAL ); + if ( sat->sat_family != AF_APPLETALK ) { + return( EAFNOSUPPORT ); + } + + /* + * Under phase 2, network 0 means "the network". We take "the + * network" to mean the network the control block is bound to. + * If the control block is not bound, there is an error. + */ + if ( sat->sat_addr.s_net == ATADDR_ANYNET + && sat->sat_addr.s_node != ATADDR_ANYNODE ) { + if ( ddp->ddp_lsat.sat_port == ATADDR_ANYPORT ) { + return( EADDRNOTAVAIL ); + } + hintnet = ddp->ddp_lsat.sat_addr.s_net; + } + + ro = &ddp->ddp_route; + /* + * If we've got an old route for this pcb, check that it is valid. + * If we've changed our address, we may have an old "good looking" + * route here. Attempt to detect it. + */ + if ( ro->ro_rt ) { + if ( hintnet ) { + net = hintnet; + } else { + net = sat->sat_addr.s_net; + } + aa = 0; + if ( ifp = ro->ro_rt->rt_ifp ) { + for ( aa = at_ifaddr; aa; aa = aa->aa_next ) { + if ( aa->aa_ifp == ifp && + ntohs( net ) >= ntohs( aa->aa_firstnet ) && + ntohs( net ) <= ntohs( aa->aa_lastnet )) { + printf("at_pcbconnect: found ifp net=%u\n", ntohs(net)); + break; + } + } + } + if ( aa == NULL || ( satosat( &ro->ro_dst )->sat_addr.s_net != + ( hintnet ? hintnet : sat->sat_addr.s_net ) || + satosat( &ro->ro_dst )->sat_addr.s_node != + sat->sat_addr.s_node )) { + printf("at_pcbconnect: freeing ro->ro_rt=0x%x\n", ro->ro_rt); +#ifdef ultrix + rtfree( ro->ro_rt ); +#else ultrix + RTFREE( ro->ro_rt ); +#endif ultrix + ro->ro_rt = (struct rtentry *)0; + } + } + + /* + * If we've got no route for this interface, try to find one. + */ + if ( ro->ro_rt == (struct rtentry *)0 || + ro->ro_rt->rt_ifp == (struct ifnet *)0 ) { +#ifdef BSD4_4 + ro->ro_dst.sa_len = sizeof( struct sockaddr_at ); +#endif BSD4_4 + ro->ro_dst.sa_family = AF_APPLETALK; + if ( hintnet ) { + satosat( &ro->ro_dst )->sat_addr.s_net = hintnet; + } else { + satosat( &ro->ro_dst )->sat_addr.s_net = sat->sat_addr.s_net; + } + satosat( &ro->ro_dst )->sat_addr.s_node = sat->sat_addr.s_node; + rtalloc( ro ); + } + + /* + * Make sure any route that we have has a valid interface. + */ + aa = 0; + if ( ro->ro_rt && ( ifp = ro->ro_rt->rt_ifp )) { + for ( aa = at_ifaddr; aa; aa = aa->aa_next ) { + if ( aa->aa_ifp == ifp ) { + break; + } + } + } + if ( aa == 0 ) { + printf("at_pcbconnect: ro->ro_rt=0x%x\n", ro->ro_rt); + if (ro->ro_rt) + printf("at_pcbconnect: ro->ro_rt->rt_ifp=0x%x", ro->ro_rt->rt_ifp); + return( ENETUNREACH ); + } + + ddp->ddp_fsat = *sat; + if ( ddp->ddp_lsat.sat_port == ATADDR_ANYPORT ) { + return( at_pcbsetaddr( ddp, (struct mbuf *)0 +#if defined( __FreeBSD__ ) + , p +#endif __FreeBSD__ + )); + } + return( 0 ); +} + +static void +at_pcbdisconnect( struct ddpcb *ddp ) +{ + ddp->ddp_fsat.sat_addr.s_net = ATADDR_ANYNET; + ddp->ddp_fsat.sat_addr.s_node = ATADDR_ANYNODE; + ddp->ddp_fsat.sat_port = ATADDR_ANYPORT; +} + +static int +at_pcballoc( struct socket *so ) +{ + struct ddpcb *ddp; + struct mbuf *m; + + m = m_getclr( M_WAIT, MT_PCB ); + ddp = mtod( m, struct ddpcb * ); + ddp->ddp_lsat.sat_port = ATADDR_ANYPORT; + + ddp->ddp_next = ddpcb; + ddp->ddp_prev = NULL; + ddp->ddp_pprev = NULL; + ddp->ddp_pnext = NULL; + if ( ddpcb ) { + ddpcb->ddp_prev = ddp; + } + ddpcb = ddp; + + ddp->ddp_socket = so; + so->so_pcb = (caddr_t)ddp; + return( 0 ); +} + +static void +at_pcbdetach( struct socket *so, struct ddpcb *ddp) +{ + soisdisconnected( so ); + so->so_pcb = 0; + sofree( so ); + + /* remove ddp from ddp_ports list */ + if ( ddp->ddp_lsat.sat_port != ATADDR_ANYPORT && + ddp_ports[ ddp->ddp_lsat.sat_port - 1 ] != NULL ) { + if ( ddp->ddp_pprev != NULL ) { + ddp->ddp_pprev->ddp_pnext = ddp->ddp_pnext; + } else { + ddp_ports[ ddp->ddp_lsat.sat_port - 1 ] = ddp->ddp_pnext; + } + if ( ddp->ddp_pnext != NULL ) { + ddp->ddp_pnext->ddp_pprev = ddp->ddp_pprev; + } + } + + if ( ddp->ddp_route.ro_rt ) { + rtfree( ddp->ddp_route.ro_rt ); + } + + if ( ddp->ddp_prev ) { + ddp->ddp_prev->ddp_next = ddp->ddp_next; + } else { + ddpcb = ddp->ddp_next; + } + if ( ddp->ddp_next ) { + ddp->ddp_next->ddp_prev = ddp->ddp_prev; + } + + (void) m_free( dtom( ddp )); +} + +/* + * For the moment, this just find the pcb with the correct local address. + * In the future, this will actually do some real searching, so we can use + * the sender's address to do de-multiplexing on a single port to many + * sockets (pcbs). + */ +struct ddpcb * +ddp_search( struct sockaddr_at *from, struct sockaddr_at *to, + struct at_ifaddr *aa) +{ + struct ddpcb *ddp; + + /* + * Check for bad ports. + */ + if ( to->sat_port < ATPORT_FIRST || to->sat_port >= ATPORT_LAST ) { + return( NULL ); + } + + /* + * Make sure the local address matches the sent address. What about + * the interface? + */ + for ( ddp = ddp_ports[ to->sat_port - 1 ]; ddp; ddp = ddp->ddp_pnext ) { + /* XXX should we handle 0.YY? */ + + /* XXXX.YY to socket on destination interface */ + if ( to->sat_addr.s_net == ddp->ddp_lsat.sat_addr.s_net && + to->sat_addr.s_node == ddp->ddp_lsat.sat_addr.s_node ) { + break; + } + + /* 0.255 to socket on receiving interface */ + if ( to->sat_addr.s_node == ATADDR_BCAST && ( to->sat_addr.s_net == 0 || + to->sat_addr.s_net == ddp->ddp_lsat.sat_addr.s_net ) && + ddp->ddp_lsat.sat_addr.s_net == AA_SAT( aa )->sat_addr.s_net ) { + break; + } + + /* XXXX.0 to socket on destination interface */ + if ( to->sat_addr.s_net == aa->aa_firstnet && + to->sat_addr.s_node == 0 && + ntohs( ddp->ddp_lsat.sat_addr.s_net ) >= + ntohs( aa->aa_firstnet ) && + ntohs( ddp->ddp_lsat.sat_addr.s_net ) <= + ntohs( aa->aa_lastnet )) { + break; + } + } + return( ddp ); +} + +void +ddp_init(void ) +{ + atintrq1.ifq_maxlen = IFQ_MAXLEN; + atintrq2.ifq_maxlen = IFQ_MAXLEN; +} + +static void +ddp_clean(void ) +{ + struct ddpcb *ddp; + + for ( ddp = ddpcb; ddp; ddp = ddp->ddp_next ) { + at_pcbdetach( ddp->ddp_socket, ddp ); + } +} diff --git a/sys/netatalk/ddp_var.h b/sys/netatalk/ddp_var.h new file mode 100644 index 000000000000..5507764c9b01 --- /dev/null +++ b/sys/netatalk/ddp_var.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 1990,1994 Regents of The University of Michigan. + * All Rights Reserved. See COPYRIGHT. + */ + +#ifndef _NETATALK_DDP_VAR_H_ +#define _NETATALK_DDP_VAR_H_ 1 +struct ddpcb { + struct sockaddr_at ddp_fsat, ddp_lsat; + struct route ddp_route; + struct socket *ddp_socket; + struct ddpcb *ddp_prev, *ddp_next; + struct ddpcb *ddp_pprev, *ddp_pnext; +}; + +#define sotoddpcb(so) ((struct ddpcb *)(so)->so_pcb) + +struct ddpstat { + long ddps_short; /* short header packets received */ + long ddps_long; /* long header packets received */ + long ddps_nosum; /* no checksum */ + long ddps_badsum; /* bad checksum */ + long ddps_tooshort; /* packet too short */ + long ddps_toosmall; /* not enough data */ + long ddps_forward; /* packets forwarded */ + long ddps_encap; /* packets encapsulated */ + long ddps_cantforward; /* packets rcvd for unreachable dest */ + long ddps_nosockspace; /* no space in sockbuf for packet */ +}; + +#ifdef KERNEL +extern struct ddpcb *ddp_ports[ ]; +extern struct ddpcb *ddpcb; +struct ddpstat ddpstat; +#endif +#endif /* _NETATALK_DDP_VAR_H_ */ diff --git a/sys/netatalk/endian.h b/sys/netatalk/endian.h new file mode 100644 index 000000000000..919d351489ab --- /dev/null +++ b/sys/netatalk/endian.h @@ -0,0 +1,87 @@ +/* + * Copyright (c) 1990,1991 Regents of The University of Michigan. + * All Rights Reserved. + * + * Permission to use, copy, modify, and distribute this software and + * its documentation for any purpose and without fee is hereby granted, + * provided that the above copyright notice appears in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation, and that the name of The University + * of Michigan not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. This software is supplied as is without expressed or + * implied warranties of any kind. + * + * Research Systems Unix Group + * The University of Michigan + * c/o Mike Clark + * 535 W. William Street + * Ann Arbor, Michigan + * +1-313-763-0525 + * netatalk@itd.umich.edu + */ + +# ifndef _ATALK_ENDIAN_H_ +#define _ATALK_ENDIAN_H_ + +#ifdef _IBMR2 +#include +#endif _IBMR2 + +#ifdef linux +#include +#define BYTE_ORDER __BYTE_ORDER +#endif linux + +#ifdef __FreeBSD__ +#include +#endif __FreeBSD__ + +# ifndef BYTE_ORDER +#define LITTLE_ENDIAN 1234 +#define BIG_ENDIAN 4321 +#define PDP_ENDIAN 3412 + +#ifdef sun +#ifdef i386 +#define BYTE_ORDER LITTLE_ENDIAN +#else i386 +#define BYTE_ORDER BIG_ENDIAN +#endif i386 +#else +#ifdef MIPSEB +#define BYTE_ORDER BIG_ENDIAN +#else +#ifdef MIPSEL +#define BYTE_ORDER LITTLE_ENDIAN +#else +Like, what is your byte order, man? +#endif MIPSEL +#endif MIPSEB +#endif sun +# endif BYTE_ORDER + +# ifndef ntohl +# if defined( sun ) || defined( ultrix ) || defined( _IBMR2 ) +#if BYTE_ORDER == BIG_ENDIAN +#define ntohl(x) (x) +#define ntohs(x) (x) +#define htonl(x) (x) +#define htons(x) (x) + +#else +#if defined( mips ) && defined( KERNEL ) +#define ntohl(x) nuxi_l(x) +#define ntohs(x) nuxi_s(x) +#define htonl(x) nuxi_l(x) +#define htons(x) nuxi_s(x) + +#else mips KERNEL +unsigned short ntohs(), htons(); +unsigned long ntohl(), htonl(); + +#endif mips KERNEL +#endif BYTE_ORDER +# endif sun ultrix _IBMR2 +# endif ntohl +# endif _ATALK_ENDIAN_H_ diff --git a/sys/netatalk/phase2.h b/sys/netatalk/phase2.h new file mode 100644 index 000000000000..9535a6a00c39 --- /dev/null +++ b/sys/netatalk/phase2.h @@ -0,0 +1,85 @@ +/* + * Copyright (c) 1990,1991 Regents of The University of Michigan. + * All Rights Reserved. + */ + +# if defined( ultrix ) || defined( BSD4_4 ) +#include +# if defined( __FreeBSD__ ) +#define llc_org_code llc_un.type_snap.org_code +#define llc_ether_type llc_un.type_snap.ether_type +# endif __FreeBSD__ +# else ultrix BSD4_4 + +#ifdef sun +#include +#endif sun + +/* + * Copyright (c) 1988 Regents of the University of California. + * All rights reserved. + * + * @(#)if_llc.h 7.2 (Berkeley) 6/28/90 + */ + +/* + * IEEE 802.2 Link Level Control headers, for use in conjunction with + * 802.{3,4,5} media access control methods. + * + * Headers here do not use bit fields due to shortcommings in many + * compilers. + */ + +struct llc { + u_char llc_dsap; + u_char llc_ssap; + union { + struct { + u_char control; + u_char format_id; + u_char class; + u_char window_x2; + } type_u; + struct { + u_char num_snd_x2; + u_char num_rcv_x2; + } type_i; + struct { + u_char control; + u_char num_rcv_x2; + } type_s; + struct { + u_char control; + u_char org_code[3]; + u_short ether_type; + } type_snap; + } llc_un; +}; +#define llc_control llc_un.type_u.control +#define llc_fid llc_un.type_u.format_id +#define llc_class llc_un.type_u.class +#define llc_window llc_un.type_u.window_x2 +#define llc_org_code llc_un.type_snap.org_code +#define llc_ether_type llc_un.type_snap.ether_type + +#define LLC_UI 0x3 +#define LLC_UI_P 0x13 +#define LLC_XID 0xaf +#define LLC_XID_P 0xbf +#define LLC_TEST 0xe3 +#define LLC_TEST_P 0xf3 + +#define LLC_ISO_LSAP 0xfe +#define LLC_SNAP_LSAP 0xaa + +# endif ultrix BSD4_4 + +#if defined( sun ) || defined( ibm032 ) +#define SIOCPHASE1 _IOW(i, 100, struct ifreq) /* AppleTalk phase 1 */ +#define SIOCPHASE2 _IOW(i, 101, struct ifreq) /* AppleTalk phase 2 */ +#endif sun ibm032 + +#if defined( ultrix ) || defined( BSD4_4 ) || defined( _IBMR2 ) +#define SIOCPHASE1 _IOW('i', 100, struct ifreq) /* AppleTalk phase 1 */ +#define SIOCPHASE2 _IOW('i', 101, struct ifreq) /* AppleTalk phase 2 */ +#endif ultrix BSD4_4 _IBMR2