ddp_input.c revision 111888
1/*
2 * Copyright (c) 1990,1994 Regents of The University of Michigan.
3 * All Rights Reserved.  See COPYRIGHT.
4 *
5 * $FreeBSD: head/sys/netatalk/ddp_input.c 111888 2003-03-04 23:19:55Z jlemon $
6 */
7
8#include "opt_mac.h"
9
10#include <sys/param.h>
11#include <sys/kernel.h>
12#include <sys/lock.h>
13#include <sys/mac.h>
14#include <sys/mbuf.h>
15#include <sys/signalvar.h>
16#include <sys/socket.h>
17#include <sys/socketvar.h>
18#include <sys/sx.h>
19#include <sys/systm.h>
20#include <net/if.h>
21#include <net/route.h>
22
23#include <netatalk/at.h>
24#include <netatalk/at_var.h>
25#include <netatalk/ddp.h>
26#include <netatalk/ddp_var.h>
27#include <netatalk/at_extern.h>
28
29static volatile int	ddp_forward = 1;
30static volatile int	ddp_firewall = 0;
31static struct ddpstat	ddpstat;
32static struct route	forwro;
33
34static void     ddp_input(struct mbuf *, struct ifnet *, struct elaphdr *, int);
35
36/*
37 * Could probably merge these two code segments a little better...
38 */
39void
40at2intr(struct mbuf *m)
41{
42
43	/*
44	 * Phase 2 packet handling
45	 */
46	ddp_input(m, m->m_pkthdr.rcvif, NULL, 2);
47	return;
48}
49
50void
51at1intr(struct mbuf *m)
52{
53	struct elaphdr *elhp, elh;
54
55	/*
56	 * Phase 1 packet handling
57	 */
58	if (m->m_len < SZ_ELAPHDR && ((m = m_pullup(m, SZ_ELAPHDR)) == 0)) {
59		ddpstat.ddps_tooshort++;
60		return;
61	}
62
63	/*
64	 * This seems a little dubious, but I don't know phase 1 so leave it.
65	 */
66	elhp = mtod(m, struct elaphdr *);
67	m_adj(m, SZ_ELAPHDR);
68
69	if (elhp->el_type == ELAP_DDPEXTEND) {
70		ddp_input(m, m->m_pkthdr.rcvif, NULL, 1);
71	} else {
72		bcopy((caddr_t)elhp, (caddr_t)&elh, SZ_ELAPHDR);
73		ddp_input(m, m->m_pkthdr.rcvif, &elh, 1);
74	}
75	return;
76}
77
78static void
79ddp_input( m, ifp, elh, phase )
80    struct mbuf		*m;
81    struct ifnet	*ifp;
82    struct elaphdr	*elh;
83    int			phase;
84{
85    struct sockaddr_at	from, to;
86    struct ddpshdr	*dsh, ddps;
87    struct at_ifaddr	*aa;
88    struct ddpehdr	*deh = NULL, ddpe;
89    struct ddpcb	*ddp;
90    int			dlen, mlen;
91    u_short		cksum = 0;
92
93    bzero( (caddr_t)&from, sizeof( struct sockaddr_at ));
94    bzero( (caddr_t)&to, sizeof( struct sockaddr_at ));
95    if ( elh ) {
96	/*
97	 * Extract the information in the short header.
98	 * netowrk information is defaulted to ATADDR_ANYNET
99	 * and node information comes from the elh info.
100	 * We must be phase 1.
101	 */
102	ddpstat.ddps_short++;
103
104	if ( m->m_len < sizeof( struct ddpshdr ) &&
105		(( m = m_pullup( m, sizeof( struct ddpshdr ))) == 0 )) {
106	    ddpstat.ddps_tooshort++;
107	    return;
108	}
109
110	dsh = mtod( m, struct ddpshdr *);
111	bcopy( (caddr_t)dsh, (caddr_t)&ddps, sizeof( struct ddpshdr ));
112	ddps.dsh_bytes = ntohl( ddps.dsh_bytes );
113	dlen = ddps.dsh_len;
114
115	to.sat_addr.s_net = ATADDR_ANYNET;
116	to.sat_addr.s_node = elh->el_dnode;
117	to.sat_port = ddps.dsh_dport;
118	from.sat_addr.s_net = ATADDR_ANYNET;
119	from.sat_addr.s_node = elh->el_snode;
120	from.sat_port = ddps.dsh_sport;
121
122	/*
123	 * Make sure that we point to the phase1 ifaddr info
124	 * and that it's valid for this packet.
125	 */
126	for ( aa = at_ifaddr; aa; aa = aa->aa_next ) {
127	    if ( (aa->aa_ifp == ifp)
128	    && ( (aa->aa_flags & AFA_PHASE2) == 0)
129	    && ( (to.sat_addr.s_node == AA_SAT( aa )->sat_addr.s_node)
130	      || (to.sat_addr.s_node == ATADDR_BCAST))) {
131		break;
132	    }
133	}
134	/*
135	 * maybe we got a broadcast not meant for us.. ditch it.
136	 */
137	if ( aa == NULL ) {
138	    m_freem( m );
139	    return;
140	}
141    } else {
142	/*
143	 * There was no 'elh' passed on. This could still be
144	 * either phase1 or phase2.
145	 * We have a long header, but we may be running on a phase 1 net.
146	 * Extract out all the info regarding this packet's src & dst.
147	 */
148	ddpstat.ddps_long++;
149
150	if ( m->m_len < sizeof( struct ddpehdr ) &&
151		(( m = m_pullup( m, sizeof( struct ddpehdr ))) == 0 )) {
152	    ddpstat.ddps_tooshort++;
153	    return;
154	}
155
156	deh = mtod( m, struct ddpehdr *);
157	bcopy( (caddr_t)deh, (caddr_t)&ddpe, sizeof( struct ddpehdr ));
158	ddpe.deh_bytes = ntohl( ddpe.deh_bytes );
159	dlen = ddpe.deh_len;
160
161	if (( cksum = ddpe.deh_sum ) == 0 ) {
162	    ddpstat.ddps_nosum++;
163	}
164
165	from.sat_addr.s_net = ddpe.deh_snet;
166	from.sat_addr.s_node = ddpe.deh_snode;
167	from.sat_port = ddpe.deh_sport;
168	to.sat_addr.s_net = ddpe.deh_dnet;
169	to.sat_addr.s_node = ddpe.deh_dnode;
170	to.sat_port = ddpe.deh_dport;
171
172	if ( to.sat_addr.s_net == ATADDR_ANYNET ) {
173	    /*
174	     * The TO address doesn't specify a net,
175	     * So by definition it's for this net.
176	     * Try find ifaddr info with the right phase,
177	     * the right interface, and either to our node, a broadcast,
178	     * or looped back (though that SHOULD be covered in the other
179	     * cases).
180	     *
181	     * XXX If we have multiple interfaces, then the first with
182	     * this node number will match (which may NOT be what we want,
183	     * but it's probably safe in 99.999% of cases.
184	     */
185	    for ( aa = at_ifaddr; aa; aa = aa->aa_next ) {
186		if ( phase == 1 && ( aa->aa_flags & AFA_PHASE2 )) {
187		    continue;
188		}
189		if ( phase == 2 && ( aa->aa_flags & AFA_PHASE2 ) == 0 ) {
190		    continue;
191		}
192		if ( (aa->aa_ifp == ifp)
193		&& ( (to.sat_addr.s_node == AA_SAT( aa )->sat_addr.s_node)
194		  || (to.sat_addr.s_node == ATADDR_BCAST)
195		  || (ifp->if_flags & IFF_LOOPBACK))) {
196		    break;
197		}
198	    }
199	} else {
200	    /*
201	     * A destination network was given. We just try to find
202	     * which ifaddr info matches it.
203	     */
204	    for ( aa = at_ifaddr; aa; aa = aa->aa_next ) {
205		/*
206		 * This is a kludge. Accept packets that are
207		 * for any router on a local netrange.
208		 */
209		if ( to.sat_addr.s_net == aa->aa_firstnet &&
210			to.sat_addr.s_node == 0 ) {
211		    break;
212		}
213		/*
214		 * Don't use ifaddr info for which we are totally outside the
215		 * netrange, and it's not a startup packet.
216		 * Startup packets are always implicitly allowed on to
217		 * the next test.
218		 */
219		if ((( ntohs( to.sat_addr.s_net ) < ntohs( aa->aa_firstnet ))
220		    || (ntohs( to.sat_addr.s_net ) > ntohs( aa->aa_lastnet )))
221		 && (( ntohs( to.sat_addr.s_net ) < 0xff00)
222		    || (ntohs( to.sat_addr.s_net ) > 0xfffe ))) {
223		    continue;
224		}
225
226		/*
227		 * Don't record a match either if we just don't have a match
228		 * in the node address. This can have if the interface
229		 * is in promiscuous mode for example.
230		 */
231		if (( to.sat_addr.s_node != AA_SAT( aa )->sat_addr.s_node)
232		&& (to.sat_addr.s_node != ATADDR_BCAST) ) {
233		    continue;
234		}
235		break;
236	    }
237	}
238    }
239
240    /*
241     * Adjust the length, removing any padding that may have been added
242     * at a link layer.  We do this before we attempt to forward a packet,
243     * possibly on a different media.
244     */
245    mlen = m->m_pkthdr.len;
246    if ( mlen < dlen ) {
247	ddpstat.ddps_toosmall++;
248	m_freem( m );
249	return;
250    }
251    if ( mlen > dlen ) {
252	m_adj( m, dlen - mlen );
253    }
254
255    /*
256     * If it aint for a net on any of our interfaces,
257     * or it IS for a net on a different interface than it came in on,
258     * (and it is not looped back) then consider if we should forward it.
259     * As we are not really a router this is a bit cheeky, but it may be
260     * useful some day.
261     */
262    if ( (aa == NULL)
263    || ( (to.sat_addr.s_node == ATADDR_BCAST)
264      && (aa->aa_ifp != ifp)
265      && (( ifp->if_flags & IFF_LOOPBACK ) == 0 ))) {
266	/*
267	 * If we've explicitly disabled it, don't route anything
268	 */
269	if ( ddp_forward == 0 ) {
270	    m_freem( m );
271	    return;
272	}
273	/*
274	 * If the cached forwarding route is still valid, use it.
275	 */
276	if ( forwro.ro_rt
277	&& ( satosat(&forwro.ro_dst)->sat_addr.s_net != to.sat_addr.s_net
278	  || satosat(&forwro.ro_dst)->sat_addr.s_node != to.sat_addr.s_node )) {
279	    RTFREE( forwro.ro_rt );
280	    forwro.ro_rt = (struct rtentry *)0;
281	}
282
283	/*
284	 * If we don't have a cached one (any more) or it's useless,
285	 * Then get a new route.
286	 * XXX this could cause a 'route leak'. check this!
287	 */
288	if ( forwro.ro_rt == (struct rtentry *)0
289	|| forwro.ro_rt->rt_ifp == (struct ifnet *)0 ) {
290	    forwro.ro_dst.sa_len = sizeof( struct sockaddr_at );
291	    forwro.ro_dst.sa_family = AF_APPLETALK;
292	    satosat(&forwro.ro_dst)->sat_addr.s_net = to.sat_addr.s_net;
293	    satosat(&forwro.ro_dst)->sat_addr.s_node = to.sat_addr.s_node;
294	    rtalloc(&forwro);
295	}
296
297	/*
298	 * If it's not going to get there on this hop, and it's
299	 * already done too many hops, then throw it away.
300	 */
301	if ( (to.sat_addr.s_net != satosat( &forwro.ro_dst )->sat_addr.s_net)
302	&& (ddpe.deh_hops == DDP_MAXHOPS) ) {
303	    m_freem( m );
304	    return;
305	}
306
307	/*
308	 * A ddp router might use the same interface
309	 * to forward the packet, which this would not effect.
310	 * Don't allow packets to cross from one interface to another however.
311	 */
312	if ( ddp_firewall
313	&& ( (forwro.ro_rt == NULL)
314	  || (forwro.ro_rt->rt_ifp != ifp))) {
315	    m_freem( m );
316	    return;
317	}
318
319	/*
320	 * Adjust the header.
321	 * If it was a short header then it would have not gotten here,
322	 * so we can assume there is room to drop the header in.
323	 * XXX what about promiscuous mode, etc...
324	 */
325	ddpe.deh_hops++;
326	ddpe.deh_bytes = htonl( ddpe.deh_bytes );
327	bcopy( (caddr_t)&ddpe, (caddr_t)deh, sizeof( u_short )); /* XXX deh? */
328	if ( ddp_route( m, &forwro )) {
329	    ddpstat.ddps_cantforward++;
330	} else {
331	    ddpstat.ddps_forward++;
332	}
333	return;
334    }
335
336    /*
337     * It was for us, and we have an ifaddr to use with it.
338     */
339    from.sat_len = sizeof( struct sockaddr_at );
340    from.sat_family = AF_APPLETALK;
341
342    /*
343     * We are no longer interested in the link layer.
344     * so cut it off.
345     */
346    if ( elh ) {
347	m_adj( m, sizeof( struct ddpshdr ));
348    } else {
349	if ( ddp_cksum && cksum && cksum != at_cksum( m, sizeof( int ))) {
350	    ddpstat.ddps_badsum++;
351	    m_freem( m );
352	    return;
353	}
354	m_adj( m, sizeof( struct ddpehdr ));
355    }
356
357    /*
358     * Search for ddp protocol control blocks that match these
359     * addresses.
360     */
361    if (( ddp = ddp_search( &from, &to, aa )) == NULL ) {
362	m_freem( m );
363	return;
364    }
365
366#ifdef MAC
367    if (mac_check_socket_deliver(ddp->ddp_socket, m) != 0) {
368	m_freem( m );
369	return;
370    }
371#endif
372
373    /*
374     * If we found one, deliver th epacket to the socket
375     */
376    if ( sbappendaddr( &ddp->ddp_socket->so_rcv, (struct sockaddr *)&from,
377	    m, (struct mbuf *)0 ) == 0 ) {
378	/*
379	 * If the socket is full (or similar error) dump the packet.
380	 */
381	ddpstat.ddps_nosockspace++;
382	m_freem( m );
383	return;
384    }
385    /*
386     * And wake up whatever might be waiting for it
387     */
388    sorwakeup( ddp->ddp_socket );
389}
390
391#if 0
392/* As if we haven't got enough of this sort of think floating
393around the kernel :) */
394
395#define BPXLEN	48
396#define BPALEN	16
397#include <ctype.h>
398char	hexdig[] = "0123456789ABCDEF";
399
400static void
401bprint( char *data, int len )
402{
403    char	xout[ BPXLEN ], aout[ BPALEN ];
404    int		i = 0;
405
406    bzero( xout, BPXLEN );
407    bzero( aout, BPALEN );
408
409    for ( ;; ) {
410	if ( len < 1 ) {
411	    if ( i != 0 ) {
412		printf( "%s\t%s\n", xout, aout );
413	    }
414	    printf( "%s\n", "(end)" );
415	    break;
416	}
417
418	xout[ (i*3) ] = hexdig[ ( *data & 0xf0 ) >> 4 ];
419	xout[ (i*3) + 1 ] = hexdig[ *data & 0x0f ];
420
421	if ( (u_char)*data < 0x7f && (u_char)*data > 0x20 ) {
422	    aout[ i ] = *data;
423	} else {
424	    aout[ i ] = '.';
425	}
426
427	xout[ (i*3) + 2 ] = ' ';
428
429	i++;
430	len--;
431	data++;
432
433	if ( i > BPALEN - 2 ) {
434	    printf( "%s\t%s\n", xout, aout );
435	    bzero( xout, BPXLEN );
436	    bzero( aout, BPALEN );
437	    i = 0;
438	    continue;
439	}
440    }
441}
442
443static void
444m_printm( struct mbuf *m )
445{
446    for (; m; m = m->m_next ) {
447	bprint( mtod( m, char * ), m->m_len );
448    }
449}
450#endif
451