summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sys/conf/files7
-rw-r--r--sys/net/if_ethersubr.c104
-rw-r--r--sys/net/if_loop.c14
-rw-r--r--sys/net/netisr.h3
-rw-r--r--sys/netatalk/aarp.c816
-rw-r--r--sys/netatalk/aarp.h62
-rw-r--r--sys/netatalk/at.h117
-rw-r--r--sys/netatalk/at_control.c614
-rw-r--r--sys/netatalk/at_extern.h41
-rw-r--r--sys/netatalk/at_proto.c95
-rw-r--r--sys/netatalk/at_rmx.c160
-rw-r--r--sys/netatalk/at_var.h71
-rw-r--r--sys/netatalk/ddp.h133
-rw-r--r--sys/netatalk/ddp_input.c413
-rw-r--r--sys/netatalk/ddp_output.c298
-rw-r--r--sys/netatalk/ddp_pcb.c582
-rw-r--r--sys/netatalk/ddp_usrreq.c582
-rw-r--r--sys/netatalk/ddp_var.h36
-rw-r--r--sys/netatalk/endian.h87
-rw-r--r--sys/netatalk/phase2.h85
20 files changed, 4312 insertions, 8 deletions
diff --git a/sys/conf/files b/sys/conf/files
index f3b3469..f7ea057 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 e313527..97903ef 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 <sys/param.h>
@@ -76,15 +76,27 @@
#include <netiso/iso_snpac.h>
#endif
-#ifdef LLC
+/*#ifdef LLC
#include <netccitt/dll.h>
#include <netccitt/llc_var.h>
-#endif
+#endif*/
#if defined(LLC) && defined(CCITT)
extern struct ifqueue pkintrq;
#endif
+#ifdef NETATALK
+#include <netatalk/at.h>
+#include <netatalk/at_var.h>
+#include <netatalk/at_extern.h>
+
+#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 894a4b5..acbc822 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 <netiso/iso_var.h>
#endif
+#ifdef NETATALK
+#include <netinet/if_ether.h>
+#include <netatalk/at.h>
+#include <netatalk/at_var.h>
+#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 a326493..5c9bd29 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 0000000..84beef4
--- /dev/null
+++ b/sys/netatalk/aarp.c
@@ -0,0 +1,816 @@
+/*
+ * Copyright (c) 1990,1991 Regents of The University of Michigan.
+ * All Rights Reserved.
+ */
+
+#include <sys/types.h>
+#include <sys/cdefs.h>
+#include <sys/socket.h>
+#include <sys/syslog.h>
+#include <sys/param.h>
+#if defined( __FreeBSD__ )
+#include <machine/endian.h>
+#include <sys/systm.h>
+#include <sys/proc.h>
+#endif
+#include <sys/mbuf.h>
+#include <sys/time.h>
+#ifndef _IBMR2
+#include <sys/kernel.h>
+#endif _IBMR2
+#include <net/if.h>
+#include <net/route.h>
+#if !defined( __FreeBSD__ )
+#include <net/af.h>
+#endif
+#include <netinet/in.h>
+#undef s_net
+#include <netinet/if_ether.h>
+#ifdef _IBMR2
+#include <netinet/in_netarp.h>
+#include <net/spl.h>
+#include <sys/errno.h>
+#include <sys/err_rec.h>
+#endif _IBMR2
+
+#include <netatalk/at.h>
+#include <netatalk/at_var.h>
+#include <netatalk/aarp.h>
+#include <netatalk/ddp_var.h>
+#include <netatalk/phase2.h>
+#include <netatalk/at_extern.h>
+
+static void aarptfree( struct aarptab *aat);
+static void at_aarpinput( struct arpcom *ac, struct mbuf *m);
+
+#ifdef GATEWAY
+#define AARPTAB_BSIZ 16
+#define AARPTAB_NB 37
+#else
+#define AARPTAB_BSIZ 9
+#define AARPTAB_NB 19
+#endif GATEWAY
+#define AARPTAB_SIZE (AARPTAB_BSIZ * AARPTAB_NB)
+struct aarptab aarptab[AARPTAB_SIZE];
+int aarptab_size = AARPTAB_SIZE;
+
+#define AARPTAB_HASH(a) \
+ ((((a).s_net << 8 ) + (a).s_node ) % AARPTAB_NB )
+
+#define AARPTAB_LOOK(aat,addr) { \
+ int n; \
+ aat = &aarptab[ AARPTAB_HASH(addr) * AARPTAB_BSIZ ]; \
+ for ( n = 0; n < AARPTAB_BSIZ; n++, aat++ ) \
+ if ( aat->aat_ataddr.s_net == (addr).s_net && \
+ aat->aat_ataddr.s_node == (addr).s_node ) \
+ break; \
+ if ( n >= AARPTAB_BSIZ ) \
+ aat = 0; \
+}
+
+#define AARPT_AGE (60 * 1)
+#define AARPT_KILLC 20
+#define AARPT_KILLI 3
+
+#ifdef sun
+extern struct ether_addr etherbroadcastaddr;
+#else sun
+# if !defined( __FreeBSD__ )
+extern u_char etherbroadcastaddr[6];
+# endif __FreeBSD__
+#endif sun
+
+u_char atmulticastaddr[ 6 ] = {
+ 0x09, 0x00, 0x07, 0xff, 0xff, 0xff,
+};
+
+u_char at_org_code[ 3 ] = {
+ 0x08, 0x00, 0x07,
+};
+u_char aarp_org_code[ 3 ] = {
+ 0x00, 0x00, 0x00,
+};
+
+static void
+aarptimer(void *ignored)
+{
+ struct aarptab *aat;
+ int i, s;
+
+ timeout( aarptimer, (caddr_t)0, AARPT_AGE * hz );
+ aat = aarptab;
+ for ( i = 0; i < AARPTAB_SIZE; i++, aat++ ) {
+ if ( aat->aat_flags == 0 || ( aat->aat_flags & ATF_PERM ))
+ continue;
+ if ( ++aat->aat_timer < (( aat->aat_flags & ATF_COM ) ?
+ AARPT_KILLC : AARPT_KILLI ))
+ continue;
+ s = splimp();
+ aarptfree( aat );
+ splx( s );
+ }
+}
+
+struct ifaddr *
+at_ifawithnet( sat, ifa )
+ struct sockaddr_at *sat;
+ struct ifaddr *ifa;
+{
+ struct at_ifaddr *aa;
+
+ for (; ifa; ifa = ifa->ifa_next ) {
+#ifdef BSD4_4
+ if ( ifa->ifa_addr->sa_family != AF_APPLETALK ) {
+ continue;
+ }
+ if ( satosat( ifa->ifa_addr )->sat_addr.s_net ==
+ sat->sat_addr.s_net ) {
+ break;
+ }
+#else BSD4_4
+ if ( ifa->ifa_addr.sa_family != AF_APPLETALK ) {
+ continue;
+ }
+ aa = (struct at_ifaddr *)ifa;
+ if ( ntohs( sat->sat_addr.s_net ) >= ntohs( aa->aa_firstnet ) &&
+ ntohs( sat->sat_addr.s_net ) <= ntohs( aa->aa_lastnet )) {
+ break;
+ }
+#endif BSD4_4
+ }
+ return( ifa );
+}
+
+static void
+aarpwhohas( struct arpcom *ac, struct sockaddr_at *sat )
+{
+ struct mbuf *m;
+ struct ether_header *eh;
+ struct ether_aarp *ea;
+ struct at_ifaddr *aa;
+ struct llc *llc;
+ struct sockaddr sa;
+
+#ifdef BSD4_4
+ if (( m = m_gethdr( M_DONTWAIT, MT_DATA )) == NULL ) {
+ return;
+ }
+ m->m_len = sizeof( *ea );
+ m->m_pkthdr.len = sizeof( *ea );
+ MH_ALIGN( m, sizeof( *ea ));
+#else BSD4_4
+ if (( m = m_get( M_DONTWAIT, MT_DATA )) == NULL ) {
+ return;
+ }
+ m->m_len = sizeof( *ea );
+ m->m_off = MMAXOFF - sizeof( *ea );
+#endif BSD4_4
+
+ ea = mtod( m, struct ether_aarp *);
+ bzero((caddr_t)ea, sizeof( *ea ));
+
+ ea->aarp_hrd = htons( AARPHRD_ETHER );
+ ea->aarp_pro = htons( ETHERTYPE_AT );
+ ea->aarp_hln = sizeof( ea->aarp_sha );
+ ea->aarp_pln = sizeof( ea->aarp_spu );
+ ea->aarp_op = htons( AARPOP_REQUEST );
+#ifdef sun
+ bcopy((caddr_t)&ac->ac_enaddr, (caddr_t)ea->aarp_sha,
+ sizeof( ea->aarp_sha ));
+#else sun
+ bcopy((caddr_t)ac->ac_enaddr, (caddr_t)ea->aarp_sha,
+ sizeof( ea->aarp_sha ));
+#endif sun
+
+ /*
+ * We need to check whether the output ethernet type should
+ * be phase 1 or 2. We have the interface that we'll be sending
+ * the aarp out. We need to find an AppleTalk network on that
+ * interface with the same address as we're looking for. If the
+ * net is phase 2, generate an 802.2 and SNAP header.
+ */
+ if (( aa = (struct at_ifaddr *)at_ifawithnet( sat, ac->ac_if.if_addrlist ))
+ == NULL ) {
+ m_freem( m );
+ return;
+ }
+
+ eh = (struct ether_header *)sa.sa_data;
+
+ if ( aa->aa_flags & AFA_PHASE2 ) {
+#ifdef sun
+ bcopy((caddr_t)atmulticastaddr, (caddr_t)&eh->ether_dhost,
+ sizeof( eh->ether_dhost ));
+#else sun
+ bcopy((caddr_t)atmulticastaddr, (caddr_t)eh->ether_dhost,
+ sizeof( eh->ether_dhost ));
+#endif sun
+#if defined(sun) && defined(i386)
+ eh->ether_type = htons(sizeof(struct llc) + sizeof(struct ether_aarp));
+#else
+ eh->ether_type = sizeof(struct llc) + sizeof(struct ether_aarp);
+#endif
+#ifdef BSD4_4
+ M_PREPEND( m, sizeof( struct llc ), M_WAIT );
+#else BSD4_4
+ m->m_len += sizeof( struct llc );
+ m->m_off -= sizeof( struct llc );
+#endif BSD4_4
+ llc = mtod( m, struct llc *);
+ llc->llc_dsap = llc->llc_ssap = LLC_SNAP_LSAP;
+ llc->llc_control = LLC_UI;
+ bcopy( aarp_org_code, llc->llc_org_code, sizeof( aarp_org_code ));
+ llc->llc_ether_type = htons( ETHERTYPE_AARP );
+
+ bcopy( &AA_SAT( aa )->sat_addr.s_net, ea->aarp_spnet,
+ sizeof( ea->aarp_spnet ));
+ bcopy( &sat->sat_addr.s_net, ea->aarp_tpnet,
+ sizeof( ea->aarp_tpnet ));
+ ea->aarp_spnode = AA_SAT( aa )->sat_addr.s_node;
+ ea->aarp_tpnode = sat->sat_addr.s_node;
+ } else {
+#ifdef sun
+ bcopy((caddr_t)&etherbroadcastaddr, (caddr_t)&eh->ether_dhost,
+ sizeof( eh->ether_dhost ));
+#else sun
+ bcopy((caddr_t)etherbroadcastaddr, (caddr_t)eh->ether_dhost,
+ sizeof( eh->ether_dhost ));
+#endif sun
+#if defined(sun) && defined(i386)
+ eh->ether_type = htons( ETHERTYPE_AARP );
+#else
+ eh->ether_type = ETHERTYPE_AARP;
+#endif
+
+ ea->aarp_spa = AA_SAT( aa )->sat_addr.s_node;
+ ea->aarp_tpa = sat->sat_addr.s_node;
+ }
+
+#ifdef NETATALKDEBUG
+ printf("aarp: sending request for %u.%u\n",
+ ntohs(AA_SAT( aa )->sat_addr.s_net),
+ AA_SAT( aa )->sat_addr.s_node);
+#endif NETATALKDEBUG
+
+#ifdef BSD4_4
+ sa.sa_len = sizeof( struct sockaddr );
+#endif BSD4_4
+ sa.sa_family = AF_UNSPEC;
+ (*ac->ac_if.if_output)(&ac->ac_if, m, &sa
+#if defined( __FreeBSD__ )
+ , NULL /* XXX should be routing information */
+#endif __FreeBSD__
+ );
+}
+
+int
+aarpresolve( ac, m, destsat, desten )
+ struct arpcom *ac;
+ struct mbuf *m;
+ struct sockaddr_at *destsat;
+#ifdef sun
+ struct ether_addr *desten;
+#else sun
+ u_char *desten;
+#endif sun
+{
+ struct at_ifaddr *aa;
+ struct ifaddr ifa;
+ struct aarptab *aat;
+ int s;
+
+ if ( at_broadcast( destsat )) {
+ if (( aa = (struct at_ifaddr *)at_ifawithnet( destsat,
+ ((struct ifnet *)ac)->if_addrlist )) == NULL ) {
+ m_freem( m );
+ return( 0 );
+ }
+ if ( aa->aa_flags & AFA_PHASE2 ) {
+ bcopy( (caddr_t)atmulticastaddr, (caddr_t)desten,
+ sizeof( atmulticastaddr ));
+ } else {
+#ifdef sun
+ bcopy( (caddr_t)&etherbroadcastaddr, (caddr_t)desten,
+ sizeof( etherbroadcastaddr ));
+#else sun
+ bcopy( (caddr_t)etherbroadcastaddr, (caddr_t)desten,
+ sizeof( etherbroadcastaddr ));
+#endif sun
+ }
+ return( 1 );
+ }
+
+ s = splimp();
+ AARPTAB_LOOK( aat, destsat->sat_addr );
+ if ( aat == 0 ) { /* No entry */
+ aat = aarptnew( &destsat->sat_addr );
+ if ( aat == 0 ) {
+ panic( "aarpresolve: no free entry" );
+ }
+ aat->aat_hold = m;
+ aarpwhohas( ac, destsat );
+ splx( s );
+ return( 0 );
+ }
+ /* found an entry */
+ aat->aat_timer = 0;
+ if ( aat->aat_flags & ATF_COM ) { /* entry is COMplete */
+ bcopy( (caddr_t)aat->aat_enaddr, (caddr_t)desten,
+ sizeof( aat->aat_enaddr ));
+ splx( s );
+ return( 1 );
+ }
+ /* entry has not completed */
+ if ( aat->aat_hold ) {
+ m_freem( aat->aat_hold );
+ }
+ aat->aat_hold = m;
+ aarpwhohas( ac, destsat );
+ splx( s );
+ return( 0 );
+}
+
+void
+aarpinput( ac, m )
+ struct arpcom *ac;
+ struct mbuf *m;
+{
+ struct arphdr *ar;
+
+ if ( ac->ac_if.if_flags & IFF_NOARP )
+ goto out;
+
+#ifndef BSD4_4
+ IF_ADJ( m );
+#endif BSD4_4
+
+ if ( m->m_len < sizeof( struct arphdr )) {
+ goto out;
+ }
+
+ ar = mtod( m, struct arphdr *);
+ if ( ntohs( ar->ar_hrd ) != AARPHRD_ETHER ) {
+ goto out;
+ }
+
+ if ( m->m_len < sizeof( struct arphdr ) + 2 * ar->ar_hln +
+ 2 * ar->ar_pln ) {
+ goto out;
+ }
+
+ switch( ntohs( ar->ar_pro )) {
+ case ETHERTYPE_AT :
+ at_aarpinput( ac, m );
+ return;
+
+ default:
+ break;
+ }
+
+out:
+ m_freem( m );
+}
+
+static void
+at_aarpinput( struct arpcom *ac, struct mbuf *m)
+{
+ struct mbuf *m0;
+ struct ether_aarp *ea;
+ struct at_ifaddr *aa;
+ struct aarptab *aat;
+ struct ether_header *eh;
+ struct llc *llc;
+ struct sockaddr_at sat;
+ struct sockaddr sa;
+ struct at_addr spa, tpa, ma;
+ int op, s;
+ u_short net;
+
+ ea = mtod( m, struct ether_aarp *);
+
+ /* Check to see if from my hardware address */
+#ifdef sun
+ if ( !bcmp(( caddr_t )ea->aarp_sha, ( caddr_t )&ac->ac_enaddr,
+ sizeof( ac->ac_enaddr ))) {
+ m_freem( m );
+ return;
+ }
+#else sun
+ if ( !bcmp(( caddr_t )ea->aarp_sha, ( caddr_t )ac->ac_enaddr,
+ sizeof( ac->ac_enaddr ))) {
+ m_freem( m );
+ return;
+ }
+#endif sun
+
+ op = ntohs( ea->aarp_op );
+ bcopy( ea->aarp_tpnet, &net, sizeof( net ));
+
+ if ( net != 0 ) { /* should be ATADDR_ANYNET? */
+#ifdef BSD4_4
+ sat.sat_len = sizeof(struct sockaddr_at);
+#endif BSD4_4
+ sat.sat_family = AF_APPLETALK;
+ sat.sat_addr.s_net = net;
+ if (( aa = (struct at_ifaddr *)at_ifawithnet( &sat,
+ ac->ac_if.if_addrlist )) == NULL ) {
+ m_freem( m );
+ return;
+ }
+ bcopy( ea->aarp_spnet, &spa.s_net, sizeof( spa.s_net ));
+ bcopy( ea->aarp_tpnet, &tpa.s_net, sizeof( tpa.s_net ));
+ } else {
+ /*
+ * Since we don't know the net, we just look for the first
+ * phase 1 address on the interface.
+ */
+ for ( aa = (struct at_ifaddr *)ac->ac_if.if_addrlist; aa;
+ aa = (struct at_ifaddr *)aa->aa_ifa.ifa_next ) {
+ if ( AA_SAT( aa )->sat_family == AF_APPLETALK &&
+ ( aa->aa_flags & AFA_PHASE2 ) == 0 ) {
+ break;
+ }
+ }
+ if ( aa == NULL ) {
+ m_freem( m );
+ return;
+ }
+ tpa.s_net = spa.s_net = AA_SAT( aa )->sat_addr.s_net;
+ }
+
+ spa.s_node = ea->aarp_spnode;
+ tpa.s_node = ea->aarp_tpnode;
+ ma.s_net = AA_SAT( aa )->sat_addr.s_net;
+ ma.s_node = AA_SAT( aa )->sat_addr.s_node;
+
+ /*
+ * This looks like it's from us.
+ */
+ if ( spa.s_net == ma.s_net && spa.s_node == ma.s_node ) {
+ if ( aa->aa_flags & AFA_PROBING ) {
+ /*
+ * We're probing, someone either responded to our probe, or
+ * probed for the same address we'd like to use. Change the
+ * address we're probing for.
+ */
+ untimeout((timeout_func_t) aarpprobe, ac );
+ wakeup( aa );
+ m_freem( m );
+ return;
+ } else if ( op != AARPOP_PROBE ) {
+ /*
+ * This is not a probe, and we're not probing. This means
+ * that someone's saying they have the same source address
+ * as the one we're using. Get upset...
+ */
+#ifndef _IBMR2
+#ifdef ultrix
+ mprintf( LOG_ERR,
+#else ultrix
+ log( LOG_ERR,
+#endif ultrix
+ "aarp: duplicate AT address!! %x:%x:%x:%x:%x:%x\n",
+ ea->aarp_sha[ 0 ], ea->aarp_sha[ 1 ], ea->aarp_sha[ 2 ],
+ ea->aarp_sha[ 3 ], ea->aarp_sha[ 4 ], ea->aarp_sha[ 5 ]);
+#endif _IBMR2
+ m_freem( m );
+ return;
+ }
+ }
+
+ AARPTAB_LOOK( aat, spa );
+ if ( aat ) {
+ if ( op == AARPOP_PROBE ) {
+ /*
+ * Someone's probing for spa, dealocate the one we've got,
+ * so that if the prober keeps the address, we'll be able
+ * to arp for him.
+ */
+ aarptfree( aat );
+ m_freem( m );
+ return;
+ }
+
+ bcopy(( caddr_t )ea->aarp_sha, ( caddr_t )aat->aat_enaddr,
+ sizeof( ea->aarp_sha ));
+ aat->aat_flags |= ATF_COM;
+ if ( aat->aat_hold ) {
+#ifdef _IBMR2
+ /*
+ * Like in ddp_output(), we can't rely on the if_output
+ * routine to resolve AF_APPLETALK addresses, on the rs6k.
+ * So, we fill the destination ethernet address here.
+ *
+ * This should really be replaced with something like
+ * rsif_output(). XXX Will have to be for phase 2.
+ */
+ /* XXX maybe fill in the rest of the frame header */
+ sat.sat_family = AF_UNSPEC;
+ bcopy( aat->aat_enaddr, (*(struct sockaddr *)&sat).sa_data,
+ sizeof( aat->aat_enaddr ));
+#else _IBMR2
+#ifdef BSD4_4
+ sat.sat_len = sizeof(struct sockaddr_at);
+#endif BSD4_4
+ sat.sat_family = AF_APPLETALK;
+ sat.sat_addr = spa;
+#endif _IBMR2
+ (*ac->ac_if.if_output)( &ac->ac_if, aat->aat_hold,
+ (struct sockaddr *)&sat
+#if defined( __FreeBSD__ )
+ , NULL /* XXX */
+#endif __FreeBSD__
+ );
+ aat->aat_hold = 0;
+ }
+ }
+
+ if ( aat == 0 && tpa.s_net == ma.s_net && tpa.s_node == ma.s_node
+ && op != AARPOP_PROBE ) {
+ if ( aat = aarptnew( &spa )) {
+ bcopy(( caddr_t )ea->aarp_sha, ( caddr_t )aat->aat_enaddr,
+ sizeof( ea->aarp_sha ));
+ aat->aat_flags |= ATF_COM;
+ }
+ }
+
+ /*
+ * Don't respond to responses, and never respond if we're
+ * still probing.
+ */
+ if ( tpa.s_net != ma.s_net || tpa.s_node != ma.s_node ||
+ op == AARPOP_RESPONSE || ( aa->aa_flags & AFA_PROBING )) {
+ m_freem( m );
+ return;
+ }
+
+ bcopy(( caddr_t )ea->aarp_sha, ( caddr_t )ea->aarp_tha,
+ sizeof( ea->aarp_sha ));
+#ifdef sun
+ bcopy(( caddr_t )&ac->ac_enaddr, ( caddr_t )ea->aarp_sha,
+ sizeof( ea->aarp_sha ));
+#else sun
+ bcopy(( caddr_t )ac->ac_enaddr, ( caddr_t )ea->aarp_sha,
+ sizeof( ea->aarp_sha ));
+#endif sun
+
+ /* XXX */
+ eh = (struct ether_header *)sa.sa_data;
+#ifdef sun
+ bcopy(( caddr_t )ea->aarp_tha, ( caddr_t )&eh->ether_dhost,
+ sizeof( eh->ether_dhost ));
+#else sun
+ bcopy(( caddr_t )ea->aarp_tha, ( caddr_t )eh->ether_dhost,
+ sizeof( eh->ether_dhost ));
+#endif sun
+
+ if ( aa->aa_flags & AFA_PHASE2 ) {
+#if defined(sun) && defined(i386)
+ eh->ether_type = htons( sizeof( struct llc ) +
+ sizeof( struct ether_aarp ));
+#else
+ eh->ether_type = sizeof( struct llc ) + sizeof( struct ether_aarp );
+#endif
+#ifdef BSD4_4
+ M_PREPEND( m, sizeof( struct llc ), M_DONTWAIT );
+ if ( m == NULL ) {
+ return;
+ }
+#else BSD4_4
+ MGET( m0, M_DONTWAIT, MT_HEADER );
+ if ( m0 == NULL ) {
+ m_freem( m );
+ return;
+ }
+ m0->m_next = m;
+ m = m0;
+ m->m_off = MMAXOFF - sizeof( struct llc );
+ m->m_len = sizeof ( struct llc );
+#endif BSD4_4
+ llc = mtod( m, struct llc *);
+ llc->llc_dsap = llc->llc_ssap = LLC_SNAP_LSAP;
+ llc->llc_control = LLC_UI;
+ bcopy( aarp_org_code, llc->llc_org_code, sizeof( aarp_org_code ));
+ llc->llc_ether_type = htons( ETHERTYPE_AARP );
+
+ bcopy( ea->aarp_spnet, ea->aarp_tpnet, sizeof( ea->aarp_tpnet ));
+ bcopy( &ma.s_net, ea->aarp_spnet, sizeof( ea->aarp_spnet ));
+ } else {
+#if defined(sun) && defined(i386)
+ eh->ether_type = htons( ETHERTYPE_AARP );
+#else
+ eh->ether_type = ETHERTYPE_AARP;
+#endif
+ }
+
+ ea->aarp_tpnode = ea->aarp_spnode;
+ ea->aarp_spnode = ma.s_node;
+ ea->aarp_op = htons( AARPOP_RESPONSE );
+
+#ifdef BSD4_4
+ sa.sa_len = sizeof( struct sockaddr );
+#endif BSD4_4
+ sa.sa_family = AF_UNSPEC;
+ (*ac->ac_if.if_output)( &ac->ac_if, m, &sa
+#if defined( __FreeBSD__ )
+ , NULL /* XXX */
+#endif
+ );
+ return;
+}
+
+static void
+aarptfree( struct aarptab *aat)
+{
+
+ if ( aat->aat_hold )
+ m_freem( aat->aat_hold );
+ aat->aat_hold = 0;
+ aat->aat_timer = aat->aat_flags = 0;
+ aat->aat_ataddr.s_net = 0;
+ aat->aat_ataddr.s_node = 0;
+}
+
+ struct aarptab *
+aarptnew( addr )
+ struct at_addr *addr;
+{
+ int n;
+ int oldest = -1;
+ struct aarptab *aat, *aato = NULL;
+ static int first = 1;
+
+ if ( first ) {
+ first = 0;
+ timeout( aarptimer, (caddr_t)0, hz );
+ }
+ aat = &aarptab[ AARPTAB_HASH( *addr ) * AARPTAB_BSIZ ];
+ for ( n = 0; n < AARPTAB_BSIZ; n++, aat++ ) {
+ if ( aat->aat_flags == 0 )
+ goto out;
+ if ( aat->aat_flags & ATF_PERM )
+ continue;
+ if ((int) aat->aat_timer > oldest ) {
+ oldest = aat->aat_timer;
+ aato = aat;
+ }
+ }
+ if ( aato == NULL )
+ return( NULL );
+ aat = aato;
+ aarptfree( aat );
+out:
+ aat->aat_ataddr = *addr;
+ aat->aat_flags = ATF_INUSE;
+ return( aat );
+}
+
+
+void
+aarpprobe( struct arpcom *ac )
+{
+ struct mbuf *m;
+ struct ether_header *eh;
+ struct ether_aarp *ea;
+ struct at_ifaddr *aa;
+ struct llc *llc;
+ struct sockaddr sa;
+
+ /*
+ * We need to check whether the output ethernet type should
+ * be phase 1 or 2. We have the interface that we'll be sending
+ * the aarp out. We need to find an AppleTalk network on that
+ * interface with the same address as we're looking for. If the
+ * net is phase 2, generate an 802.2 and SNAP header.
+ */
+ for ( aa = (struct at_ifaddr *)ac->ac_if.if_addrlist; aa;
+ aa = (struct at_ifaddr *)aa->aa_ifa.ifa_next ) {
+ if ( AA_SAT( aa )->sat_family == AF_APPLETALK &&
+ ( aa->aa_flags & AFA_PROBING )) {
+ break;
+ }
+ }
+ if ( aa == NULL ) { /* serious error XXX */
+ printf( "aarpprobe why did this happen?!\n" );
+ return;
+ }
+
+ if ( aa->aa_probcnt <= 0 ) {
+ aa->aa_flags &= ~AFA_PROBING;
+ wakeup( aa );
+ return;
+ } else {
+ timeout( (timeout_func_t)aarpprobe, (caddr_t)ac, hz / 5 );
+ }
+
+#ifdef BSD4_4
+ if (( m = m_gethdr( M_DONTWAIT, MT_DATA )) == NULL ) {
+ return;
+ }
+ m->m_len = sizeof( *ea );
+ m->m_pkthdr.len = sizeof( *ea );
+ MH_ALIGN( m, sizeof( *ea ));
+#else BSD4_4
+ if (( m = m_get( M_DONTWAIT, MT_DATA )) == NULL ) {
+ return;
+ }
+ m->m_len = sizeof( *ea );
+ m->m_off = MMAXOFF - sizeof( *ea );
+#endif BSD4_4
+
+ ea = mtod( m, struct ether_aarp *);
+ bzero((caddr_t)ea, sizeof( *ea ));
+
+ ea->aarp_hrd = htons( AARPHRD_ETHER );
+ ea->aarp_pro = htons( ETHERTYPE_AT );
+ ea->aarp_hln = sizeof( ea->aarp_sha );
+ ea->aarp_pln = sizeof( ea->aarp_spu );
+ ea->aarp_op = htons( AARPOP_PROBE );
+#ifdef sun
+ bcopy((caddr_t)&ac->ac_enaddr, (caddr_t)ea->aarp_sha,
+ sizeof( ea->aarp_sha ));
+#else sun
+ bcopy((caddr_t)ac->ac_enaddr, (caddr_t)ea->aarp_sha,
+ sizeof( ea->aarp_sha ));
+#endif sun
+
+ eh = (struct ether_header *)sa.sa_data;
+
+ if ( aa->aa_flags & AFA_PHASE2 ) {
+#ifdef sun
+ bcopy((caddr_t)atmulticastaddr, (caddr_t)&eh->ether_dhost,
+ sizeof( eh->ether_dhost ));
+#else sun
+ bcopy((caddr_t)atmulticastaddr, (caddr_t)eh->ether_dhost,
+ sizeof( eh->ether_dhost ));
+#endif sun
+#if defined(sun) && defined(i386)
+ eh->ether_type = htons( sizeof( struct llc ) +
+ sizeof( struct ether_aarp ));
+#else
+ eh->ether_type = sizeof( struct llc ) + sizeof( struct ether_aarp );
+#endif
+#ifdef BSD4_4
+ M_PREPEND( m, sizeof( struct llc ), M_WAIT );
+#else BSD4_4
+ m->m_len += sizeof( struct llc );
+ m->m_off -= sizeof( struct llc );
+#endif BSD4_4
+ llc = mtod( m, struct llc *);
+ llc->llc_dsap = llc->llc_ssap = LLC_SNAP_LSAP;
+ llc->llc_control = LLC_UI;
+ bcopy( aarp_org_code, llc->llc_org_code, sizeof( aarp_org_code ));
+ llc->llc_ether_type = htons( ETHERTYPE_AARP );
+
+ bcopy( &AA_SAT( aa )->sat_addr.s_net, ea->aarp_spnet,
+ sizeof( ea->aarp_spnet ));
+ bcopy( &AA_SAT( aa )->sat_addr.s_net, ea->aarp_tpnet,
+ sizeof( ea->aarp_tpnet ));
+ ea->aarp_spnode = ea->aarp_tpnode = AA_SAT( aa )->sat_addr.s_node;
+ } else {
+#ifdef sun
+ bcopy((caddr_t)&etherbroadcastaddr, (caddr_t)&eh->ether_dhost,
+ sizeof( eh->ether_dhost ));
+#else sun
+ bcopy((caddr_t)etherbroadcastaddr, (caddr_t)eh->ether_dhost,
+ sizeof( eh->ether_dhost ));
+#endif sun
+#if defined(sun) && defined(i386)
+ eh->ether_type = htons( ETHERTYPE_AARP );
+#else
+ eh->ether_type = ETHERTYPE_AARP;
+#endif
+ ea->aarp_spa = ea->aarp_tpa = AA_SAT( aa )->sat_addr.s_node;
+ }
+
+#ifdef NETATALKDEBUG
+ printf("aarp: sending probe for %u.%u\n",
+ ntohs(AA_SAT( aa )->sat_addr.s_net),
+ AA_SAT( aa )->sat_addr.s_node);
+#endif NETATALKDEBUG
+
+#ifdef BSD4_4
+ sa.sa_len = sizeof( struct sockaddr );
+#endif BSD4_4
+ sa.sa_family = AF_UNSPEC;
+ (*ac->ac_if.if_output)(&ac->ac_if, m, &sa
+#if defined( __FreeBSD__ )
+ , NULL /* XXX */
+#endif __FreeBSD__
+ );
+ aa->aa_probcnt--;
+}
+
+void
+aarp_clean(void)
+{
+ struct aarptab *aat;
+ int i;
+
+ untimeout( aarptimer, 0 );
+ for ( i = 0, aat = aarptab; i < AARPTAB_SIZE; i++, aat++ ) {
+ if ( aat->aat_hold ) {
+ m_freem( aat->aat_hold );
+ }
+ }
+}
diff --git a/sys/netatalk/aarp.h b/sys/netatalk/aarp.h
new file mode 100644
index 0000000..4911538
--- /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 0000000..eca11fb
--- /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 0000000..5a1294f
--- /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 <sys/param.h>
+#include <sys/systm.h>
+#ifdef ibm032
+#include <sys/dir.h>
+#endif ibm032
+#include <sys/proc.h>
+#ifndef BSD4_4
+#include <sys/user.h>
+#endif
+#include <sys/types.h>
+#include <sys/errno.h>
+#include <sys/ioctl.h>
+#include <sys/mbuf.h>
+#ifndef _IBMR2
+#include <sys/kernel.h>
+#endif _IBMR2
+#include <sys/socket.h>
+#include <sys/socketvar.h>
+#include <net/if.h>
+/* #include <net/af.h> */
+#include <net/route.h>
+#include <netinet/in.h>
+#undef s_net
+#include <netinet/if_ether.h>
+#ifdef _IBMR2
+#include <net/spl.h>
+#endif _IBMR2
+
+#include "at.h"
+#include "at_var.h"
+#include "aarp.h"
+#include "phase2.h"
+#include <netatalk/at_extern.h>
+
+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 0000000..18badf4
--- /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 0000000..0c8fdbf
--- /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 <sys/param.h>
+#include <sys/systm.h>
+#include <sys/protosw.h>
+#include <sys/domain.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#if defined( __FreeBSD__ )
+#include <sys/kernel.h>
+#include <net/if.h>
+#include <net/radix.h>
+#include <netinet/in.h>
+#include <netinet/if_ether.h>
+#include <net/route.h>
+#endif
+
+#include "at.h"
+#include "ddp.h"
+#include "at_var.h"
+#include "ddp_var.h"
+#include <netatalk/at_extern.h>
+
+
+#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 0000000..73747b6
--- /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 <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/queue.h>
+#include <sys/socket.h>
+#include <sys/socketvar.h>
+#include <sys/mbuf.h>
+#include <sys/syslog.h>
+
+#include <net/if.h>
+#include <net/route.h>
+
+#include <netatalk/at.h>
+#include <netatalk/at_extern.h>
+
+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 0000000..31b4526
--- /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 0000000..aec009c
--- /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 0000000..45a0c28
--- /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 <sys/types.h>
+#include <sys/param.h>
+#if defined( __FreeBSD__ )
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <net/netisr.h>
+#endif __FreeBSD__
+#include <sys/mbuf.h>
+#include <sys/socket.h>
+#include <sys/socketvar.h>
+#include <sys/syslog.h>
+#include <net/if.h>
+#include <net/route.h>
+#ifdef _IBMR2
+#include <net/spl.h>
+#endif _IBMR2
+#include <netinet/in.h>
+#include <netinet/if_ether.h>
+
+#include "at.h"
+#include "at_var.h"
+#include "endian.h"
+#include "ddp.h"
+#include "ddp_var.h"
+#include <netatalk/at_extern.h>
+
+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 <ctype.h>
+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 0000000..54a2c7a
--- /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 <sys/types.h>
+#include <sys/param.h>
+#if defined( __FreeBSD__ )
+#include <sys/systm.h>
+#endif __FreeBSD__
+#include <sys/mbuf.h>
+#include <sys/socket.h>
+#include <sys/errno.h>
+#include <sys/syslog.h>
+
+#include <net/if.h>
+#include <net/route.h>
+
+#include <netinet/in.h>
+#undef s_net
+#include <netinet/if_ether.h>
+
+#include "at.h"
+#include "at_var.h"
+#include "endian.h"
+#include "ddp.h"
+#include "ddp_var.h"
+#include <netatalk/at_extern.h>
+
+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 0000000..d85bc71
--- /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 <sys/errno.h>
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/systm.h>
+#if defined( __FreeBSD__ )
+#include <sys/proc.h>
+#endif __FreeBSD__
+#ifdef ibm032
+#include <sys/dir.h>
+#endif ibm032
+#ifndef __FreeBSD__
+#include <sys/user.h>
+#endif
+#include <sys/mbuf.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <sys/socketvar.h>
+#include <sys/protosw.h>
+#include <net/if.h>
+#include <net/route.h>
+#include <netinet/in.h>
+#include <netinet/if_ether.h>
+#ifdef _IBMR2
+#include <net/spl.h>
+#endif _IBMR2
+
+#include "at.h"
+#include "at_var.h"
+#include "ddp_var.h"
+#include "aarp.h"
+#include "endian.h"
+#include <netatalk/at_extern.h>
+
+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 0000000..d85bc71
--- /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 <sys/errno.h>
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/systm.h>
+#if defined( __FreeBSD__ )
+#include <sys/proc.h>
+#endif __FreeBSD__
+#ifdef ibm032
+#include <sys/dir.h>
+#endif ibm032
+#ifndef __FreeBSD__
+#include <sys/user.h>
+#endif
+#include <sys/mbuf.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <sys/socketvar.h>
+#include <sys/protosw.h>
+#include <net/if.h>
+#include <net/route.h>
+#include <netinet/in.h>
+#include <netinet/if_ether.h>
+#ifdef _IBMR2
+#include <net/spl.h>
+#endif _IBMR2
+
+#include "at.h"
+#include "at_var.h"
+#include "ddp_var.h"
+#include "aarp.h"
+#include "endian.h"
+#include <netatalk/at_extern.h>
+
+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 0000000..5507764
--- /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 0000000..919d351
--- /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 <sys/machine.h>
+#endif _IBMR2
+
+#ifdef linux
+#include <bytesex.h>
+#define BYTE_ORDER __BYTE_ORDER
+#endif linux
+
+#ifdef __FreeBSD__
+#include <machine/endian.h>
+#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 0000000..9535a6a
--- /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 <net/if_llc.h>
+# 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 <net/if_ieee802.h>
+#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
OpenPOWER on IntegriCloud