summaryrefslogtreecommitdiffstats
path: root/sys/netatalk/ddp_input.c
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/ddp_input.c
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/ddp_input.c')
-rw-r--r--sys/netatalk/ddp_input.c413
1 files changed, 413 insertions, 0 deletions
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 );
+ }
+}
OpenPOWER on IntegriCloud