ddp_input.c revision 18207
1/*
2 * Copyright (c) 1990,1994 Regents of The University of Michigan.
3 * All Rights Reserved.  See COPYRIGHT.
4 */
5
6#include <sys/types.h>
7#include <sys/param.h>
8#include <sys/systm.h>
9#include <sys/kernel.h>
10#include <net/netisr.h>
11#include <sys/mbuf.h>
12#include <sys/socket.h>
13#include <sys/socketvar.h>
14#include <sys/syslog.h>
15#include <net/if.h>
16#include <net/route.h>
17#include <netinet/in.h>
18#include <netinet/if_ether.h>
19
20#include <netatalk/at.h>
21#include <netatalk/at_var.h>
22#include <netatalk/endian.h>
23#include <netatalk/ddp.h>
24#include <netatalk/ddp_var.h>
25#include <netatalk/at_extern.h>
26
27int		ddp_forward = 1;
28int		ddp_firewall = 0;
29extern int	ddp_cksum;
30void     ddp_input( struct mbuf	*, struct ifnet *, struct elaphdr *, int );
31
32/*
33 * Could probably merge these two code segments a little better...
34 */
35static void
36atintr( void )
37{
38    struct elaphdr	*elhp, elh;
39    struct ifnet	*ifp;
40    struct mbuf		*m;
41    struct at_ifaddr	*aa;
42    int			s;
43
44    for (;;) {
45	s = splimp();
46
47	IF_DEQUEUE( &atintrq2, m );
48
49	splx( s );
50
51	if ( m == 0 ) {			/* no more queued packets */
52	    break;
53	}
54
55	ifp = m->m_pkthdr.rcvif;
56	for ( aa = at_ifaddr; aa; aa = aa->aa_next ) {
57	    if ( aa->aa_ifp == ifp && ( aa->aa_flags & AFA_PHASE2 )) {
58		break;
59	    }
60	}
61	if ( aa == NULL ) {		/* ifp not an appletalk interface */
62	    m_freem( m );
63	    continue;
64	}
65
66	ddp_input( m, ifp, (struct elaphdr *)NULL, 2 );
67    }
68
69    for (;;) {
70	s = splimp();
71
72	IF_DEQUEUE( &atintrq1, m );
73
74	splx( s );
75
76	if ( m == 0 ) {			/* no more queued packets */
77	    break;
78	}
79
80	ifp = m->m_pkthdr.rcvif;
81	for ( aa = at_ifaddr; aa; aa = aa->aa_next ) {
82	    if ( aa->aa_ifp == ifp && ( aa->aa_flags & AFA_PHASE2 ) == 0 ) {
83		break;
84	    }
85	}
86	if ( aa == NULL ) {		/* ifp not an appletalk interface */
87	    m_freem( m );
88	    continue;
89	}
90
91	if ( m->m_len < SZ_ELAPHDR &&
92		(( m = m_pullup( m, SZ_ELAPHDR )) == 0 )) {
93	    ddpstat.ddps_tooshort++;
94	    continue;
95	}
96
97	elhp = mtod( m, struct elaphdr *);
98	m_adj( m, SZ_ELAPHDR );
99
100	if ( elhp->el_type == ELAP_DDPEXTEND ) {
101	    ddp_input( m, ifp, (struct elaphdr *)NULL, 1 );
102	} else {
103	    bcopy((caddr_t)elhp, (caddr_t)&elh, SZ_ELAPHDR );
104	    ddp_input( m, ifp, &elh, 1 );
105	}
106    }
107    return;
108}
109
110NETISR_SET(NETISR_ATALK, atintr);
111
112struct route	forwro;
113
114void
115ddp_input( m, ifp, elh, phase )
116    struct mbuf		*m;
117    struct ifnet	*ifp;
118    struct elaphdr	*elh;
119    int			phase;
120{
121    struct sockaddr_at	from, to;
122    struct ddpshdr	*dsh, ddps;
123    struct at_ifaddr	*aa;
124    struct ddpehdr	*deh = NULL, ddpe;
125    struct ddpcb	*ddp;
126    int			dlen, mlen;
127    u_short		cksum = 0;
128
129    bzero( (caddr_t)&from, sizeof( struct sockaddr_at ));
130    if ( elh ) {
131	ddpstat.ddps_short++;
132
133	if ( m->m_len < sizeof( struct ddpshdr ) &&
134		(( m = m_pullup( m, sizeof( struct ddpshdr ))) == 0 )) {
135	    ddpstat.ddps_tooshort++;
136	    return;
137	}
138
139	dsh = mtod( m, struct ddpshdr *);
140	bcopy( (caddr_t)dsh, (caddr_t)&ddps, sizeof( struct ddpshdr ));
141	ddps.dsh_bytes = ntohl( ddps.dsh_bytes );
142	dlen = ddps.dsh_len;
143
144	to.sat_addr.s_net = ATADDR_ANYNET;
145	to.sat_addr.s_node = elh->el_dnode;
146	to.sat_port = ddps.dsh_dport;
147	from.sat_addr.s_net = ATADDR_ANYNET;
148	from.sat_addr.s_node = elh->el_snode;
149	from.sat_port = ddps.dsh_sport;
150
151	for ( aa = at_ifaddr; aa; aa = aa->aa_next ) {
152	    if ( aa->aa_ifp == ifp && ( aa->aa_flags & AFA_PHASE2 ) == 0 &&
153		    ( AA_SAT( aa )->sat_addr.s_node == to.sat_addr.s_node ||
154		    to.sat_addr.s_node == ATADDR_BCAST )) {
155		break;
156	    }
157	}
158	if ( aa == NULL ) {
159	    m_freem( m );
160	    return;
161	}
162    } else {
163	ddpstat.ddps_long++;
164
165	if ( m->m_len < sizeof( struct ddpehdr ) &&
166		(( m = m_pullup( m, sizeof( struct ddpehdr ))) == 0 )) {
167	    ddpstat.ddps_tooshort++;
168	    return;
169	}
170
171	deh = mtod( m, struct ddpehdr *);
172	bcopy( (caddr_t)deh, (caddr_t)&ddpe, sizeof( struct ddpehdr ));
173	ddpe.deh_bytes = ntohl( ddpe.deh_bytes );
174	dlen = ddpe.deh_len;
175
176	if (( cksum = ddpe.deh_sum ) == 0 ) {
177	    ddpstat.ddps_nosum++;
178	}
179
180	from.sat_addr.s_net = ddpe.deh_snet;
181	from.sat_addr.s_node = ddpe.deh_snode;
182	from.sat_port = ddpe.deh_sport;
183	to.sat_addr.s_net = ddpe.deh_dnet;
184	to.sat_addr.s_node = ddpe.deh_dnode;
185	to.sat_port = ddpe.deh_dport;
186
187	if ( to.sat_addr.s_net == ATADDR_ANYNET ) {
188	    for ( aa = at_ifaddr; aa; aa = aa->aa_next ) {
189		if ( phase == 1 && ( aa->aa_flags & AFA_PHASE2 )) {
190		    continue;
191		}
192		if ( phase == 2 && ( aa->aa_flags & AFA_PHASE2 ) == 0 ) {
193		    continue;
194		}
195		if ( aa->aa_ifp == ifp &&
196			( AA_SAT( aa )->sat_addr.s_node == to.sat_addr.s_node ||
197			to.sat_addr.s_node == ATADDR_BCAST ||
198			( ifp->if_flags & IFF_LOOPBACK ))) {
199		    break;
200		}
201	    }
202	} else {
203	    for ( aa = at_ifaddr; aa; aa = aa->aa_next ) {
204		if ( to.sat_addr.s_net == aa->aa_firstnet &&
205			to.sat_addr.s_node == 0 ) {
206		    break;
207		}
208		if (( ntohs( to.sat_addr.s_net ) < ntohs( aa->aa_firstnet ) ||
209			ntohs( to.sat_addr.s_net ) > ntohs( aa->aa_lastnet )) &&
210			( ntohs( to.sat_addr.s_net ) < ntohs( 0xff00 ) ||
211			ntohs( to.sat_addr.s_net ) > ntohs( 0xfffe ))) {
212		    continue;
213		}
214		if ( to.sat_addr.s_node != AA_SAT( aa )->sat_addr.s_node &&
215			to.sat_addr.s_node != ATADDR_BCAST ) {
216		    continue;
217		}
218		break;
219	    }
220	}
221    }
222
223    /*
224     * Adjust the length, removing any padding that may have been added
225     * at a link layer.  We do this before we attempt to forward a packet,
226     * possibly on a different media.
227     */
228    mlen = m->m_pkthdr.len;
229    if ( mlen < dlen ) {
230	ddpstat.ddps_toosmall++;
231	m_freem( m );
232	return;
233    }
234    if ( mlen > dlen ) {
235	m_adj( m, dlen - mlen );
236    }
237
238    /*
239     * XXX Should we deliver broadcasts locally, also, or rely on the
240     * link layer to give us a copy?  For the moment, the latter.
241     */
242    if ( aa == NULL || ( to.sat_addr.s_node == ATADDR_BCAST &&
243	    aa->aa_ifp != ifp && ( ifp->if_flags & IFF_LOOPBACK ) == 0 )) {
244	if ( ddp_forward == 0 ) {
245	    m_freem( m );
246	    return;
247	}
248	if ( forwro.ro_rt && ( satosat( &forwro.ro_dst )->sat_addr.s_net !=
249		to.sat_addr.s_net ||
250		satosat( &forwro.ro_dst )->sat_addr.s_node !=
251		to.sat_addr.s_node )) {
252	    RTFREE( forwro.ro_rt );
253	    forwro.ro_rt = (struct rtentry *)0;
254	}
255	if ( forwro.ro_rt == (struct rtentry *)0 ||
256	     forwro.ro_rt->rt_ifp == (struct ifnet *)0 ) {
257	    forwro.ro_dst.sa_len = sizeof( struct sockaddr_at );
258	    forwro.ro_dst.sa_family = AF_APPLETALK;
259	    satosat( &forwro.ro_dst )->sat_addr.s_net = to.sat_addr.s_net;
260	    satosat( &forwro.ro_dst )->sat_addr.s_node = to.sat_addr.s_node;
261	    rtalloc( &forwro );
262	}
263
264	if ( to.sat_addr.s_net != satosat( &forwro.ro_dst )->sat_addr.s_net &&
265		ddpe.deh_hops == DDP_MAXHOPS ) {
266	    m_freem( m );
267	    return;
268	}
269
270	if ( ddp_firewall &&
271		( forwro.ro_rt == NULL || forwro.ro_rt->rt_ifp != ifp )) {
272	    m_freem( m );
273	    return;
274	}
275
276	ddpe.deh_hops++;
277	ddpe.deh_bytes = htonl( ddpe.deh_bytes );
278	bcopy( (caddr_t)&ddpe, (caddr_t)deh, sizeof( u_short )); /* XXX deh? */
279	if ( ddp_route( m, &forwro )) {
280	    ddpstat.ddps_cantforward++;
281	} else {
282	    ddpstat.ddps_forward++;
283	}
284	return;
285    }
286
287    from.sat_len = sizeof( struct sockaddr_at );
288    from.sat_family = AF_APPLETALK;
289
290    if ( elh ) {
291	m_adj( m, sizeof( struct ddpshdr ));
292    } else {
293	if ( ddp_cksum && cksum && cksum != at_cksum( m, sizeof( int ))) {
294	    ddpstat.ddps_badsum++;
295	    m_freem( m );
296	    return;
297	}
298	m_adj( m, sizeof( struct ddpehdr ));
299    }
300
301    if (( ddp = ddp_search( &from, &to, aa )) == NULL ) {
302	m_freem( m );
303	return;
304    }
305
306    if ( sbappendaddr( &ddp->ddp_socket->so_rcv, (struct sockaddr *)&from,
307	    m, (struct mbuf *)0 ) == 0 ) {
308	ddpstat.ddps_nosockspace++;
309	m_freem( m );
310	return;
311    }
312    sorwakeup( ddp->ddp_socket );
313}
314
315#if 0
316
317#define BPXLEN	48
318#define BPALEN	16
319#include <ctype.h>
320char	hexdig[] = "0123456789ABCDEF";
321
322static void
323bprint( char *data, int len )
324{
325    char	xout[ BPXLEN ], aout[ BPALEN ];
326    int		i = 0;
327
328    bzero( xout, BPXLEN );
329    bzero( aout, BPALEN );
330
331    for ( ;; ) {
332	if ( len < 1 ) {
333	    if ( i != 0 ) {
334		printf( "%s\t%s\n", xout, aout );
335	    }
336	    printf( "%s\n", "(end)" );
337	    break;
338	}
339
340	xout[ (i*3) ] = hexdig[ ( *data & 0xf0 ) >> 4 ];
341	xout[ (i*3) + 1 ] = hexdig[ *data & 0x0f ];
342
343	if ( (u_char)*data < 0x7f && (u_char)*data > 0x20 ) {
344	    aout[ i ] = *data;
345	} else {
346	    aout[ i ] = '.';
347	}
348
349	xout[ (i*3) + 2 ] = ' ';
350
351	i++;
352	len--;
353	data++;
354
355	if ( i > BPALEN - 2 ) {
356	    printf( "%s\t%s\n", xout, aout );
357	    bzero( xout, BPXLEN );
358	    bzero( aout, BPALEN );
359	    i = 0;
360	    continue;
361	}
362    }
363}
364
365static void
366m_printm( struct mbuf *m )
367{
368    for (; m; m = m->m_next ) {
369	bprint( mtod( m, char * ), m->m_len );
370    }
371}
372#endif
373