summaryrefslogtreecommitdiffstats
path: root/sys/netatalk
diff options
context:
space:
mode:
authorjulian <julian@FreeBSD.org>1996-05-24 01:35:45 +0000
committerjulian <julian@FreeBSD.org>1996-05-24 01:35:45 +0000
commitab2eb71c6f0d52b75d38708dd906c6461ab8cd04 (patch)
treeec6b23430d90949e7d850ac2f7bf6a9abf504900 /sys/netatalk
parentf54ae37a95112e2bfe75acccd5720f7292ea0abc (diff)
downloadFreeBSD-src-ab2eb71c6f0d52b75d38708dd906c6461ab8cd04.zip
FreeBSD-src-ab2eb71c6f0d52b75d38708dd906c6461ab8cd04.tar.gz
Obtained from: netatalk distribution netatalk@itd.umich.edu
Kernel Appletalk protocol support both CAP and netatalk can make use of this.. still needs some owrk but it seemd the right tiime to commit it so other can experiment.
Diffstat (limited to 'sys/netatalk')
-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
16 files changed, 4192 insertions, 0 deletions
diff --git a/sys/netatalk/aarp.c b/sys/netatalk/aarp.c
new file mode 100644
index 0000000..84beef4
--- /dev/null
+++ b/sys/netatalk/aarp.c
@@ -0,0 +1,816 @@
+/*
+ * Copyright (c) 1990,1991 Regents of The University of Michigan.
+ * All Rights Reserved.
+ */
+
+#include <sys/types.h>
+#include <sys/cdefs.h>
+#include <sys/socket.h>
+#include <sys/syslog.h>
+#include <sys/param.h>
+#if defined( __FreeBSD__ )
+#include <machine/endian.h>
+#include <sys/systm.h>
+#include <sys/proc.h>
+#endif
+#include <sys/mbuf.h>
+#include <sys/time.h>
+#ifndef _IBMR2
+#include <sys/kernel.h>
+#endif _IBMR2
+#include <net/if.h>
+#include <net/route.h>
+#if !defined( __FreeBSD__ )
+#include <net/af.h>
+#endif
+#include <netinet/in.h>
+#undef s_net
+#include <netinet/if_ether.h>
+#ifdef _IBMR2
+#include <netinet/in_netarp.h>
+#include <net/spl.h>
+#include <sys/errno.h>
+#include <sys/err_rec.h>
+#endif _IBMR2
+
+#include <netatalk/at.h>
+#include <netatalk/at_var.h>
+#include <netatalk/aarp.h>
+#include <netatalk/ddp_var.h>
+#include <netatalk/phase2.h>
+#include <netatalk/at_extern.h>
+
+static void aarptfree( struct aarptab *aat);
+static void at_aarpinput( struct arpcom *ac, struct mbuf *m);
+
+#ifdef GATEWAY
+#define AARPTAB_BSIZ 16
+#define AARPTAB_NB 37
+#else
+#define AARPTAB_BSIZ 9
+#define AARPTAB_NB 19
+#endif GATEWAY
+#define AARPTAB_SIZE (AARPTAB_BSIZ * AARPTAB_NB)
+struct aarptab aarptab[AARPTAB_SIZE];
+int aarptab_size = AARPTAB_SIZE;
+
+#define AARPTAB_HASH(a) \
+ ((((a).s_net << 8 ) + (a).s_node ) % AARPTAB_NB )
+
+#define AARPTAB_LOOK(aat,addr) { \
+ int n; \
+ aat = &aarptab[ AARPTAB_HASH(addr) * AARPTAB_BSIZ ]; \
+ for ( n = 0; n < AARPTAB_BSIZ; n++, aat++ ) \
+ if ( aat->aat_ataddr.s_net == (addr).s_net && \
+ aat->aat_ataddr.s_node == (addr).s_node ) \
+ break; \
+ if ( n >= AARPTAB_BSIZ ) \
+ aat = 0; \
+}
+
+#define AARPT_AGE (60 * 1)
+#define AARPT_KILLC 20
+#define AARPT_KILLI 3
+
+#ifdef sun
+extern struct ether_addr etherbroadcastaddr;
+#else sun
+# if !defined( __FreeBSD__ )
+extern u_char etherbroadcastaddr[6];
+# endif __FreeBSD__
+#endif sun
+
+u_char atmulticastaddr[ 6 ] = {
+ 0x09, 0x00, 0x07, 0xff, 0xff, 0xff,
+};
+
+u_char at_org_code[ 3 ] = {
+ 0x08, 0x00, 0x07,
+};
+u_char aarp_org_code[ 3 ] = {
+ 0x00, 0x00, 0x00,
+};
+
+static void
+aarptimer(void *ignored)
+{
+ struct aarptab *aat;
+ int i, s;
+
+ timeout( aarptimer, (caddr_t)0, AARPT_AGE * hz );
+ aat = aarptab;
+ for ( i = 0; i < AARPTAB_SIZE; i++, aat++ ) {
+ if ( aat->aat_flags == 0 || ( aat->aat_flags & ATF_PERM ))
+ continue;
+ if ( ++aat->aat_timer < (( aat->aat_flags & ATF_COM ) ?
+ AARPT_KILLC : AARPT_KILLI ))
+ continue;
+ s = splimp();
+ aarptfree( aat );
+ splx( s );
+ }
+}
+
+struct ifaddr *
+at_ifawithnet( sat, ifa )
+ struct sockaddr_at *sat;
+ struct ifaddr *ifa;
+{
+ struct at_ifaddr *aa;
+
+ for (; ifa; ifa = ifa->ifa_next ) {
+#ifdef BSD4_4
+ if ( ifa->ifa_addr->sa_family != AF_APPLETALK ) {
+ continue;
+ }
+ if ( satosat( ifa->ifa_addr )->sat_addr.s_net ==
+ sat->sat_addr.s_net ) {
+ break;
+ }
+#else BSD4_4
+ if ( ifa->ifa_addr.sa_family != AF_APPLETALK ) {
+ continue;
+ }
+ aa = (struct at_ifaddr *)ifa;
+ if ( ntohs( sat->sat_addr.s_net ) >= ntohs( aa->aa_firstnet ) &&
+ ntohs( sat->sat_addr.s_net ) <= ntohs( aa->aa_lastnet )) {
+ break;
+ }
+#endif BSD4_4
+ }
+ return( ifa );
+}
+
+static void
+aarpwhohas( struct arpcom *ac, struct sockaddr_at *sat )
+{
+ struct mbuf *m;
+ struct ether_header *eh;
+ struct ether_aarp *ea;
+ struct at_ifaddr *aa;
+ struct llc *llc;
+ struct sockaddr sa;
+
+#ifdef BSD4_4
+ if (( m = m_gethdr( M_DONTWAIT, MT_DATA )) == NULL ) {
+ return;
+ }
+ m->m_len = sizeof( *ea );
+ m->m_pkthdr.len = sizeof( *ea );
+ MH_ALIGN( m, sizeof( *ea ));
+#else BSD4_4
+ if (( m = m_get( M_DONTWAIT, MT_DATA )) == NULL ) {
+ return;
+ }
+ m->m_len = sizeof( *ea );
+ m->m_off = MMAXOFF - sizeof( *ea );
+#endif BSD4_4
+
+ ea = mtod( m, struct ether_aarp *);
+ bzero((caddr_t)ea, sizeof( *ea ));
+
+ ea->aarp_hrd = htons( AARPHRD_ETHER );
+ ea->aarp_pro = htons( ETHERTYPE_AT );
+ ea->aarp_hln = sizeof( ea->aarp_sha );
+ ea->aarp_pln = sizeof( ea->aarp_spu );
+ ea->aarp_op = htons( AARPOP_REQUEST );
+#ifdef sun
+ bcopy((caddr_t)&ac->ac_enaddr, (caddr_t)ea->aarp_sha,
+ sizeof( ea->aarp_sha ));
+#else sun
+ bcopy((caddr_t)ac->ac_enaddr, (caddr_t)ea->aarp_sha,
+ sizeof( ea->aarp_sha ));
+#endif sun
+
+ /*
+ * We need to check whether the output ethernet type should
+ * be phase 1 or 2. We have the interface that we'll be sending
+ * the aarp out. We need to find an AppleTalk network on that
+ * interface with the same address as we're looking for. If the
+ * net is phase 2, generate an 802.2 and SNAP header.
+ */
+ if (( aa = (struct at_ifaddr *)at_ifawithnet( sat, ac->ac_if.if_addrlist ))
+ == NULL ) {
+ m_freem( m );
+ return;
+ }
+
+ eh = (struct ether_header *)sa.sa_data;
+
+ if ( aa->aa_flags & AFA_PHASE2 ) {
+#ifdef sun
+ bcopy((caddr_t)atmulticastaddr, (caddr_t)&eh->ether_dhost,
+ sizeof( eh->ether_dhost ));
+#else sun
+ bcopy((caddr_t)atmulticastaddr, (caddr_t)eh->ether_dhost,
+ sizeof( eh->ether_dhost ));
+#endif sun
+#if defined(sun) && defined(i386)
+ eh->ether_type = htons(sizeof(struct llc) + sizeof(struct ether_aarp));
+#else
+ eh->ether_type = sizeof(struct llc) + sizeof(struct ether_aarp);
+#endif
+#ifdef BSD4_4
+ M_PREPEND( m, sizeof( struct llc ), M_WAIT );
+#else BSD4_4
+ m->m_len += sizeof( struct llc );
+ m->m_off -= sizeof( struct llc );
+#endif BSD4_4
+ llc = mtod( m, struct llc *);
+ llc->llc_dsap = llc->llc_ssap = LLC_SNAP_LSAP;
+ llc->llc_control = LLC_UI;
+ bcopy( aarp_org_code, llc->llc_org_code, sizeof( aarp_org_code ));
+ llc->llc_ether_type = htons( ETHERTYPE_AARP );
+
+ bcopy( &AA_SAT( aa )->sat_addr.s_net, ea->aarp_spnet,
+ sizeof( ea->aarp_spnet ));
+ bcopy( &sat->sat_addr.s_net, ea->aarp_tpnet,
+ sizeof( ea->aarp_tpnet ));
+ ea->aarp_spnode = AA_SAT( aa )->sat_addr.s_node;
+ ea->aarp_tpnode = sat->sat_addr.s_node;
+ } else {
+#ifdef sun
+ bcopy((caddr_t)&etherbroadcastaddr, (caddr_t)&eh->ether_dhost,
+ sizeof( eh->ether_dhost ));
+#else sun
+ bcopy((caddr_t)etherbroadcastaddr, (caddr_t)eh->ether_dhost,
+ sizeof( eh->ether_dhost ));
+#endif sun
+#if defined(sun) && defined(i386)
+ eh->ether_type = htons( ETHERTYPE_AARP );
+#else
+ eh->ether_type = ETHERTYPE_AARP;
+#endif
+
+ ea->aarp_spa = AA_SAT( aa )->sat_addr.s_node;
+ ea->aarp_tpa = sat->sat_addr.s_node;
+ }
+
+#ifdef NETATALKDEBUG
+ printf("aarp: sending request for %u.%u\n",
+ ntohs(AA_SAT( aa )->sat_addr.s_net),
+ AA_SAT( aa )->sat_addr.s_node);
+#endif NETATALKDEBUG
+
+#ifdef BSD4_4
+ sa.sa_len = sizeof( struct sockaddr );
+#endif BSD4_4
+ sa.sa_family = AF_UNSPEC;
+ (*ac->ac_if.if_output)(&ac->ac_if, m, &sa
+#if defined( __FreeBSD__ )
+ , NULL /* XXX should be routing information */
+#endif __FreeBSD__
+ );
+}
+
+int
+aarpresolve( ac, m, destsat, desten )
+ struct arpcom *ac;
+ struct mbuf *m;
+ struct sockaddr_at *destsat;
+#ifdef sun
+ struct ether_addr *desten;
+#else sun
+ u_char *desten;
+#endif sun
+{
+ struct at_ifaddr *aa;
+ struct ifaddr ifa;
+ struct aarptab *aat;
+ int s;
+
+ if ( at_broadcast( destsat )) {
+ if (( aa = (struct at_ifaddr *)at_ifawithnet( destsat,
+ ((struct ifnet *)ac)->if_addrlist )) == NULL ) {
+ m_freem( m );
+ return( 0 );
+ }
+ if ( aa->aa_flags & AFA_PHASE2 ) {
+ bcopy( (caddr_t)atmulticastaddr, (caddr_t)desten,
+ sizeof( atmulticastaddr ));
+ } else {
+#ifdef sun
+ bcopy( (caddr_t)&etherbroadcastaddr, (caddr_t)desten,
+ sizeof( etherbroadcastaddr ));
+#else sun
+ bcopy( (caddr_t)etherbroadcastaddr, (caddr_t)desten,
+ sizeof( etherbroadcastaddr ));
+#endif sun
+ }
+ return( 1 );
+ }
+
+ s = splimp();
+ AARPTAB_LOOK( aat, destsat->sat_addr );
+ if ( aat == 0 ) { /* No entry */
+ aat = aarptnew( &destsat->sat_addr );
+ if ( aat == 0 ) {
+ panic( "aarpresolve: no free entry" );
+ }
+ aat->aat_hold = m;
+ aarpwhohas( ac, destsat );
+ splx( s );
+ return( 0 );
+ }
+ /* found an entry */
+ aat->aat_timer = 0;
+ if ( aat->aat_flags & ATF_COM ) { /* entry is COMplete */
+ bcopy( (caddr_t)aat->aat_enaddr, (caddr_t)desten,
+ sizeof( aat->aat_enaddr ));
+ splx( s );
+ return( 1 );
+ }
+ /* entry has not completed */
+ if ( aat->aat_hold ) {
+ m_freem( aat->aat_hold );
+ }
+ aat->aat_hold = m;
+ aarpwhohas( ac, destsat );
+ splx( s );
+ return( 0 );
+}
+
+void
+aarpinput( ac, m )
+ struct arpcom *ac;
+ struct mbuf *m;
+{
+ struct arphdr *ar;
+
+ if ( ac->ac_if.if_flags & IFF_NOARP )
+ goto out;
+
+#ifndef BSD4_4
+ IF_ADJ( m );
+#endif BSD4_4
+
+ if ( m->m_len < sizeof( struct arphdr )) {
+ goto out;
+ }
+
+ ar = mtod( m, struct arphdr *);
+ if ( ntohs( ar->ar_hrd ) != AARPHRD_ETHER ) {
+ goto out;
+ }
+
+ if ( m->m_len < sizeof( struct arphdr ) + 2 * ar->ar_hln +
+ 2 * ar->ar_pln ) {
+ goto out;
+ }
+
+ switch( ntohs( ar->ar_pro )) {
+ case ETHERTYPE_AT :
+ at_aarpinput( ac, m );
+ return;
+
+ default:
+ break;
+ }
+
+out:
+ m_freem( m );
+}
+
+static void
+at_aarpinput( struct arpcom *ac, struct mbuf *m)
+{
+ struct mbuf *m0;
+ struct ether_aarp *ea;
+ struct at_ifaddr *aa;
+ struct aarptab *aat;
+ struct ether_header *eh;
+ struct llc *llc;
+ struct sockaddr_at sat;
+ struct sockaddr sa;
+ struct at_addr spa, tpa, ma;
+ int op, s;
+ u_short net;
+
+ ea = mtod( m, struct ether_aarp *);
+
+ /* Check to see if from my hardware address */
+#ifdef sun
+ if ( !bcmp(( caddr_t )ea->aarp_sha, ( caddr_t )&ac->ac_enaddr,
+ sizeof( ac->ac_enaddr ))) {
+ m_freem( m );
+ return;
+ }
+#else sun
+ if ( !bcmp(( caddr_t )ea->aarp_sha, ( caddr_t )ac->ac_enaddr,
+ sizeof( ac->ac_enaddr ))) {
+ m_freem( m );
+ return;
+ }
+#endif sun
+
+ op = ntohs( ea->aarp_op );
+ bcopy( ea->aarp_tpnet, &net, sizeof( net ));
+
+ if ( net != 0 ) { /* should be ATADDR_ANYNET? */
+#ifdef BSD4_4
+ sat.sat_len = sizeof(struct sockaddr_at);
+#endif BSD4_4
+ sat.sat_family = AF_APPLETALK;
+ sat.sat_addr.s_net = net;
+ if (( aa = (struct at_ifaddr *)at_ifawithnet( &sat,
+ ac->ac_if.if_addrlist )) == NULL ) {
+ m_freem( m );
+ return;
+ }
+ bcopy( ea->aarp_spnet, &spa.s_net, sizeof( spa.s_net ));
+ bcopy( ea->aarp_tpnet, &tpa.s_net, sizeof( tpa.s_net ));
+ } else {
+ /*
+ * Since we don't know the net, we just look for the first
+ * phase 1 address on the interface.
+ */
+ for ( aa = (struct at_ifaddr *)ac->ac_if.if_addrlist; aa;
+ aa = (struct at_ifaddr *)aa->aa_ifa.ifa_next ) {
+ if ( AA_SAT( aa )->sat_family == AF_APPLETALK &&
+ ( aa->aa_flags & AFA_PHASE2 ) == 0 ) {
+ break;
+ }
+ }
+ if ( aa == NULL ) {
+ m_freem( m );
+ return;
+ }
+ tpa.s_net = spa.s_net = AA_SAT( aa )->sat_addr.s_net;
+ }
+
+ spa.s_node = ea->aarp_spnode;
+ tpa.s_node = ea->aarp_tpnode;
+ ma.s_net = AA_SAT( aa )->sat_addr.s_net;
+ ma.s_node = AA_SAT( aa )->sat_addr.s_node;
+
+ /*
+ * This looks like it's from us.
+ */
+ if ( spa.s_net == ma.s_net && spa.s_node == ma.s_node ) {
+ if ( aa->aa_flags & AFA_PROBING ) {
+ /*
+ * We're probing, someone either responded to our probe, or
+ * probed for the same address we'd like to use. Change the
+ * address we're probing for.
+ */
+ untimeout((timeout_func_t) aarpprobe, ac );
+ wakeup( aa );
+ m_freem( m );
+ return;
+ } else if ( op != AARPOP_PROBE ) {
+ /*
+ * This is not a probe, and we're not probing. This means
+ * that someone's saying they have the same source address
+ * as the one we're using. Get upset...
+ */
+#ifndef _IBMR2
+#ifdef ultrix
+ mprintf( LOG_ERR,
+#else ultrix
+ log( LOG_ERR,
+#endif ultrix
+ "aarp: duplicate AT address!! %x:%x:%x:%x:%x:%x\n",
+ ea->aarp_sha[ 0 ], ea->aarp_sha[ 1 ], ea->aarp_sha[ 2 ],
+ ea->aarp_sha[ 3 ], ea->aarp_sha[ 4 ], ea->aarp_sha[ 5 ]);
+#endif _IBMR2
+ m_freem( m );
+ return;
+ }
+ }
+
+ AARPTAB_LOOK( aat, spa );
+ if ( aat ) {
+ if ( op == AARPOP_PROBE ) {
+ /*
+ * Someone's probing for spa, dealocate the one we've got,
+ * so that if the prober keeps the address, we'll be able
+ * to arp for him.
+ */
+ aarptfree( aat );
+ m_freem( m );
+ return;
+ }
+
+ bcopy(( caddr_t )ea->aarp_sha, ( caddr_t )aat->aat_enaddr,
+ sizeof( ea->aarp_sha ));
+ aat->aat_flags |= ATF_COM;
+ if ( aat->aat_hold ) {
+#ifdef _IBMR2
+ /*
+ * Like in ddp_output(), we can't rely on the if_output
+ * routine to resolve AF_APPLETALK addresses, on the rs6k.
+ * So, we fill the destination ethernet address here.
+ *
+ * This should really be replaced with something like
+ * rsif_output(). XXX Will have to be for phase 2.
+ */
+ /* XXX maybe fill in the rest of the frame header */
+ sat.sat_family = AF_UNSPEC;
+ bcopy( aat->aat_enaddr, (*(struct sockaddr *)&sat).sa_data,
+ sizeof( aat->aat_enaddr ));
+#else _IBMR2
+#ifdef BSD4_4
+ sat.sat_len = sizeof(struct sockaddr_at);
+#endif BSD4_4
+ sat.sat_family = AF_APPLETALK;
+ sat.sat_addr = spa;
+#endif _IBMR2
+ (*ac->ac_if.if_output)( &ac->ac_if, aat->aat_hold,
+ (struct sockaddr *)&sat
+#if defined( __FreeBSD__ )
+ , NULL /* XXX */
+#endif __FreeBSD__
+ );
+ aat->aat_hold = 0;
+ }
+ }
+
+ if ( aat == 0 && tpa.s_net == ma.s_net && tpa.s_node == ma.s_node
+ && op != AARPOP_PROBE ) {
+ if ( aat = aarptnew( &spa )) {
+ bcopy(( caddr_t )ea->aarp_sha, ( caddr_t )aat->aat_enaddr,
+ sizeof( ea->aarp_sha ));
+ aat->aat_flags |= ATF_COM;
+ }
+ }
+
+ /*
+ * Don't respond to responses, and never respond if we're
+ * still probing.
+ */
+ if ( tpa.s_net != ma.s_net || tpa.s_node != ma.s_node ||
+ op == AARPOP_RESPONSE || ( aa->aa_flags & AFA_PROBING )) {
+ m_freem( m );
+ return;
+ }
+
+ bcopy(( caddr_t )ea->aarp_sha, ( caddr_t )ea->aarp_tha,
+ sizeof( ea->aarp_sha ));
+#ifdef sun
+ bcopy(( caddr_t )&ac->ac_enaddr, ( caddr_t )ea->aarp_sha,
+ sizeof( ea->aarp_sha ));
+#else sun
+ bcopy(( caddr_t )ac->ac_enaddr, ( caddr_t )ea->aarp_sha,
+ sizeof( ea->aarp_sha ));
+#endif sun
+
+ /* XXX */
+ eh = (struct ether_header *)sa.sa_data;
+#ifdef sun
+ bcopy(( caddr_t )ea->aarp_tha, ( caddr_t )&eh->ether_dhost,
+ sizeof( eh->ether_dhost ));
+#else sun
+ bcopy(( caddr_t )ea->aarp_tha, ( caddr_t )eh->ether_dhost,
+ sizeof( eh->ether_dhost ));
+#endif sun
+
+ if ( aa->aa_flags & AFA_PHASE2 ) {
+#if defined(sun) && defined(i386)
+ eh->ether_type = htons( sizeof( struct llc ) +
+ sizeof( struct ether_aarp ));
+#else
+ eh->ether_type = sizeof( struct llc ) + sizeof( struct ether_aarp );
+#endif
+#ifdef BSD4_4
+ M_PREPEND( m, sizeof( struct llc ), M_DONTWAIT );
+ if ( m == NULL ) {
+ return;
+ }
+#else BSD4_4
+ MGET( m0, M_DONTWAIT, MT_HEADER );
+ if ( m0 == NULL ) {
+ m_freem( m );
+ return;
+ }
+ m0->m_next = m;
+ m = m0;
+ m->m_off = MMAXOFF - sizeof( struct llc );
+ m->m_len = sizeof ( struct llc );
+#endif BSD4_4
+ llc = mtod( m, struct llc *);
+ llc->llc_dsap = llc->llc_ssap = LLC_SNAP_LSAP;
+ llc->llc_control = LLC_UI;
+ bcopy( aarp_org_code, llc->llc_org_code, sizeof( aarp_org_code ));
+ llc->llc_ether_type = htons( ETHERTYPE_AARP );
+
+ bcopy( ea->aarp_spnet, ea->aarp_tpnet, sizeof( ea->aarp_tpnet ));
+ bcopy( &ma.s_net, ea->aarp_spnet, sizeof( ea->aarp_spnet ));
+ } else {
+#if defined(sun) && defined(i386)
+ eh->ether_type = htons( ETHERTYPE_AARP );
+#else
+ eh->ether_type = ETHERTYPE_AARP;
+#endif
+ }
+
+ ea->aarp_tpnode = ea->aarp_spnode;
+ ea->aarp_spnode = ma.s_node;
+ ea->aarp_op = htons( AARPOP_RESPONSE );
+
+#ifdef BSD4_4
+ sa.sa_len = sizeof( struct sockaddr );
+#endif BSD4_4
+ sa.sa_family = AF_UNSPEC;
+ (*ac->ac_if.if_output)( &ac->ac_if, m, &sa
+#if defined( __FreeBSD__ )
+ , NULL /* XXX */
+#endif
+ );
+ return;
+}
+
+static void
+aarptfree( struct aarptab *aat)
+{
+
+ if ( aat->aat_hold )
+ m_freem( aat->aat_hold );
+ aat->aat_hold = 0;
+ aat->aat_timer = aat->aat_flags = 0;
+ aat->aat_ataddr.s_net = 0;
+ aat->aat_ataddr.s_node = 0;
+}
+
+ struct aarptab *
+aarptnew( addr )
+ struct at_addr *addr;
+{
+ int n;
+ int oldest = -1;
+ struct aarptab *aat, *aato = NULL;
+ static int first = 1;
+
+ if ( first ) {
+ first = 0;
+ timeout( aarptimer, (caddr_t)0, hz );
+ }
+ aat = &aarptab[ AARPTAB_HASH( *addr ) * AARPTAB_BSIZ ];
+ for ( n = 0; n < AARPTAB_BSIZ; n++, aat++ ) {
+ if ( aat->aat_flags == 0 )
+ goto out;
+ if ( aat->aat_flags & ATF_PERM )
+ continue;
+ if ((int) aat->aat_timer > oldest ) {
+ oldest = aat->aat_timer;
+ aato = aat;
+ }
+ }
+ if ( aato == NULL )
+ return( NULL );
+ aat = aato;
+ aarptfree( aat );
+out:
+ aat->aat_ataddr = *addr;
+ aat->aat_flags = ATF_INUSE;
+ return( aat );
+}
+
+
+void
+aarpprobe( struct arpcom *ac )
+{
+ struct mbuf *m;
+ struct ether_header *eh;
+ struct ether_aarp *ea;
+ struct at_ifaddr *aa;
+ struct llc *llc;
+ struct sockaddr sa;
+
+ /*
+ * We need to check whether the output ethernet type should
+ * be phase 1 or 2. We have the interface that we'll be sending
+ * the aarp out. We need to find an AppleTalk network on that
+ * interface with the same address as we're looking for. If the
+ * net is phase 2, generate an 802.2 and SNAP header.
+ */
+ for ( aa = (struct at_ifaddr *)ac->ac_if.if_addrlist; aa;
+ aa = (struct at_ifaddr *)aa->aa_ifa.ifa_next ) {
+ if ( AA_SAT( aa )->sat_family == AF_APPLETALK &&
+ ( aa->aa_flags & AFA_PROBING )) {
+ break;
+ }
+ }
+ if ( aa == NULL ) { /* serious error XXX */
+ printf( "aarpprobe why did this happen?!\n" );
+ return;
+ }
+
+ if ( aa->aa_probcnt <= 0 ) {
+ aa->aa_flags &= ~AFA_PROBING;
+ wakeup( aa );
+ return;
+ } else {
+ timeout( (timeout_func_t)aarpprobe, (caddr_t)ac, hz / 5 );
+ }
+
+#ifdef BSD4_4
+ if (( m = m_gethdr( M_DONTWAIT, MT_DATA )) == NULL ) {
+ return;
+ }
+ m->m_len = sizeof( *ea );
+ m->m_pkthdr.len = sizeof( *ea );
+ MH_ALIGN( m, sizeof( *ea ));
+#else BSD4_4
+ if (( m = m_get( M_DONTWAIT, MT_DATA )) == NULL ) {
+ return;
+ }
+ m->m_len = sizeof( *ea );
+ m->m_off = MMAXOFF - sizeof( *ea );
+#endif BSD4_4
+
+ ea = mtod( m, struct ether_aarp *);
+ bzero((caddr_t)ea, sizeof( *ea ));
+
+ ea->aarp_hrd = htons( AARPHRD_ETHER );
+ ea->aarp_pro = htons( ETHERTYPE_AT );
+ ea->aarp_hln = sizeof( ea->aarp_sha );
+ ea->aarp_pln = sizeof( ea->aarp_spu );
+ ea->aarp_op = htons( AARPOP_PROBE );
+#ifdef sun
+ bcopy((caddr_t)&ac->ac_enaddr, (caddr_t)ea->aarp_sha,
+ sizeof( ea->aarp_sha ));
+#else sun
+ bcopy((caddr_t)ac->ac_enaddr, (caddr_t)ea->aarp_sha,
+ sizeof( ea->aarp_sha ));
+#endif sun
+
+ eh = (struct ether_header *)sa.sa_data;
+
+ if ( aa->aa_flags & AFA_PHASE2 ) {
+#ifdef sun
+ bcopy((caddr_t)atmulticastaddr, (caddr_t)&eh->ether_dhost,
+ sizeof( eh->ether_dhost ));
+#else sun
+ bcopy((caddr_t)atmulticastaddr, (caddr_t)eh->ether_dhost,
+ sizeof( eh->ether_dhost ));
+#endif sun
+#if defined(sun) && defined(i386)
+ eh->ether_type = htons( sizeof( struct llc ) +
+ sizeof( struct ether_aarp ));
+#else
+ eh->ether_type = sizeof( struct llc ) + sizeof( struct ether_aarp );
+#endif
+#ifdef BSD4_4
+ M_PREPEND( m, sizeof( struct llc ), M_WAIT );
+#else BSD4_4
+ m->m_len += sizeof( struct llc );
+ m->m_off -= sizeof( struct llc );
+#endif BSD4_4
+ llc = mtod( m, struct llc *);
+ llc->llc_dsap = llc->llc_ssap = LLC_SNAP_LSAP;
+ llc->llc_control = LLC_UI;
+ bcopy( aarp_org_code, llc->llc_org_code, sizeof( aarp_org_code ));
+ llc->llc_ether_type = htons( ETHERTYPE_AARP );
+
+ bcopy( &AA_SAT( aa )->sat_addr.s_net, ea->aarp_spnet,
+ sizeof( ea->aarp_spnet ));
+ bcopy( &AA_SAT( aa )->sat_addr.s_net, ea->aarp_tpnet,
+ sizeof( ea->aarp_tpnet ));
+ ea->aarp_spnode = ea->aarp_tpnode = AA_SAT( aa )->sat_addr.s_node;
+ } else {
+#ifdef sun
+ bcopy((caddr_t)&etherbroadcastaddr, (caddr_t)&eh->ether_dhost,
+ sizeof( eh->ether_dhost ));
+#else sun
+ bcopy((caddr_t)etherbroadcastaddr, (caddr_t)eh->ether_dhost,
+ sizeof( eh->ether_dhost ));
+#endif sun
+#if defined(sun) && defined(i386)
+ eh->ether_type = htons( ETHERTYPE_AARP );
+#else
+ eh->ether_type = ETHERTYPE_AARP;
+#endif
+ ea->aarp_spa = ea->aarp_tpa = AA_SAT( aa )->sat_addr.s_node;
+ }
+
+#ifdef NETATALKDEBUG
+ printf("aarp: sending probe for %u.%u\n",
+ ntohs(AA_SAT( aa )->sat_addr.s_net),
+ AA_SAT( aa )->sat_addr.s_node);
+#endif NETATALKDEBUG
+
+#ifdef BSD4_4
+ sa.sa_len = sizeof( struct sockaddr );
+#endif BSD4_4
+ sa.sa_family = AF_UNSPEC;
+ (*ac->ac_if.if_output)(&ac->ac_if, m, &sa
+#if defined( __FreeBSD__ )
+ , NULL /* XXX */
+#endif __FreeBSD__
+ );
+ aa->aa_probcnt--;
+}
+
+void
+aarp_clean(void)
+{
+ struct aarptab *aat;
+ int i;
+
+ untimeout( aarptimer, 0 );
+ for ( i = 0, aat = aarptab; i < AARPTAB_SIZE; i++, aat++ ) {
+ if ( aat->aat_hold ) {
+ m_freem( aat->aat_hold );
+ }
+ }
+}
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