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