]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/netatalk/ddp_input.c
This commit was generated by cvs2svn to compensate for changes in r146525,
[FreeBSD/FreeBSD.git] / sys / netatalk / ddp_input.c
1 /*-
2  * Copyright (c) 2004 Robert N. M. Watson
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  */
26 /*-
27  * Copyright (c) 1990,1994 Regents of The University of Michigan.
28  *
29  * Permission to use, copy, modify, and distribute this software and
30  * its documentation for any purpose and without fee is hereby granted,
31  * provided that the above copyright notice appears in all copies and
32  * that both that copyright notice and this permission notice appear
33  * in supporting documentation, and that the name of The University
34  * of Michigan not be used in advertising or publicity pertaining to
35  * distribution of the software without specific, written prior
36  * permission. This software is supplied as is without expressed or
37  * implied warranties of any kind.
38  *
39  * This product includes software developed by the University of
40  * California, Berkeley and its contributors.
41  *
42  *      Research Systems Unix Group
43  *      The University of Michigan
44  *      c/o Wesley Craig
45  *      535 W. William Street
46  *      Ann Arbor, Michigan
47  *      +1-313-764-2278
48  *      netatalk@umich.edu
49  *
50  * $FreeBSD$
51  */
52
53 #include "opt_mac.h"
54
55 #include <sys/param.h>
56 #include <sys/kernel.h>
57 #include <sys/lock.h>
58 #include <sys/mac.h>
59 #include <sys/mbuf.h>
60 #include <sys/signalvar.h>
61 #include <sys/socket.h>
62 #include <sys/socketvar.h>
63 #include <sys/sx.h>
64 #include <sys/systm.h>
65 #include <net/if.h>
66 #include <net/route.h>
67
68 #include <netatalk/at.h>
69 #include <netatalk/at_var.h>
70 #include <netatalk/ddp.h>
71 #include <netatalk/ddp_var.h>
72 #include <netatalk/ddp_pcb.h>
73 #include <netatalk/at_extern.h>
74
75 static volatile int     ddp_forward = 1;
76 static volatile int     ddp_firewall = 0;
77 static struct ddpstat   ddpstat;
78
79 static struct route     forwro;
80
81 static void     ddp_input(struct mbuf *, struct ifnet *, struct elaphdr *, int);
82
83 /*
84  * Could probably merge these two code segments a little better...
85  */
86 void
87 at2intr(struct mbuf *m)
88 {
89
90         /*
91          * Phase 2 packet handling 
92          */
93         ddp_input(m, m->m_pkthdr.rcvif, NULL, 2);
94         return;
95 }
96
97 void
98 at1intr(struct mbuf *m)
99 {
100         struct elaphdr *elhp, elh;
101
102         /*
103          * Phase 1 packet handling 
104          */
105         if (m->m_len < SZ_ELAPHDR && ((m = m_pullup(m, SZ_ELAPHDR)) == NULL)) {
106                 ddpstat.ddps_tooshort++;
107                 return;
108         }
109
110         /*
111          * This seems a little dubious, but I don't know phase 1 so leave it.
112          */
113         elhp = mtod(m, struct elaphdr *);
114         m_adj(m, SZ_ELAPHDR);
115
116         if (elhp->el_type == ELAP_DDPEXTEND) {
117                 ddp_input(m, m->m_pkthdr.rcvif, NULL, 1);
118         } else {
119                 bcopy((caddr_t)elhp, (caddr_t)&elh, SZ_ELAPHDR);
120                 ddp_input(m, m->m_pkthdr.rcvif, &elh, 1);
121         }
122         return;
123 }
124
125 static void
126 ddp_input(m, ifp, elh, phase)
127     struct mbuf         *m;
128     struct ifnet        *ifp;
129     struct elaphdr      *elh;
130     int                 phase;
131 {
132     struct sockaddr_at  from, to;
133     struct ddpshdr      *dsh, ddps;
134     struct at_ifaddr    *aa;
135     struct ddpehdr      *deh = NULL, ddpe;
136     struct ddpcb        *ddp;
137     int                 dlen, mlen;
138     u_short             cksum = 0;
139
140     bzero((caddr_t)&from, sizeof(struct sockaddr_at));
141     bzero((caddr_t)&to, sizeof(struct sockaddr_at));
142     if (elh != NULL) {
143         /*
144          * Extract the information in the short header.
145          * netowrk information is defaulted to ATADDR_ANYNET
146          * and node information comes from the elh info.
147          * We must be phase 1.
148          */
149         ddpstat.ddps_short++;
150
151         if (m->m_len < sizeof(struct ddpshdr) &&
152                 ((m = m_pullup(m, sizeof(struct ddpshdr))) == NULL)) {
153             ddpstat.ddps_tooshort++;
154             return;
155         }
156
157         dsh = mtod(m, struct ddpshdr *);
158         bcopy((caddr_t)dsh, (caddr_t)&ddps, sizeof(struct ddpshdr));
159         ddps.dsh_bytes = ntohl(ddps.dsh_bytes);
160         dlen = ddps.dsh_len;
161
162         to.sat_addr.s_net = ATADDR_ANYNET;
163         to.sat_addr.s_node = elh->el_dnode;
164         to.sat_port = ddps.dsh_dport;
165         from.sat_addr.s_net = ATADDR_ANYNET;
166         from.sat_addr.s_node = elh->el_snode;
167         from.sat_port = ddps.dsh_sport;
168
169         /* 
170          * Make sure that we point to the phase1 ifaddr info 
171          * and that it's valid for this packet.
172          */
173         for (aa = at_ifaddr_list; aa != NULL; aa = aa->aa_next) {
174             if ((aa->aa_ifp == ifp)
175             && ((aa->aa_flags & AFA_PHASE2) == 0)
176             && ((to.sat_addr.s_node == AA_SAT(aa)->sat_addr.s_node)
177               || (to.sat_addr.s_node == ATADDR_BCAST))) {
178                 break;
179             }
180         }
181         /* 
182          * maybe we got a broadcast not meant for us.. ditch it.
183          */
184         if (aa == NULL) {
185             m_freem(m);
186             return;
187         }
188     } else {
189         /*
190          * There was no 'elh' passed on. This could still be
191          * either phase1 or phase2.
192          * We have a long header, but we may be running on a phase 1 net.
193          * Extract out all the info regarding this packet's src & dst.
194          */
195         ddpstat.ddps_long++;
196
197         if (m->m_len < sizeof(struct ddpehdr) &&
198                 ((m = m_pullup(m, sizeof(struct ddpehdr))) == NULL)) {
199             ddpstat.ddps_tooshort++;
200             return;
201         }
202
203         deh = mtod(m, struct ddpehdr *);
204         bcopy((caddr_t)deh, (caddr_t)&ddpe, sizeof(struct ddpehdr));
205         ddpe.deh_bytes = ntohl(ddpe.deh_bytes);
206         dlen = ddpe.deh_len;
207
208         if ((cksum = ddpe.deh_sum) == 0) {
209             ddpstat.ddps_nosum++;
210         }
211
212         from.sat_addr.s_net = ddpe.deh_snet;
213         from.sat_addr.s_node = ddpe.deh_snode;
214         from.sat_port = ddpe.deh_sport;
215         to.sat_addr.s_net = ddpe.deh_dnet;
216         to.sat_addr.s_node = ddpe.deh_dnode;
217         to.sat_port = ddpe.deh_dport;
218
219         if (to.sat_addr.s_net == ATADDR_ANYNET) {
220             /*
221              * The TO address doesn't specify a net,
222              * So by definition it's for this net.
223              * Try find ifaddr info with the right phase, 
224              * the right interface, and either to our node, a broadcast,
225              * or looped back (though that SHOULD be covered in the other
226              * cases).
227              *
228              * XXX If we have multiple interfaces, then the first with
229              * this node number will match (which may NOT be what we want,
230              * but it's probably safe in 99.999% of cases.
231              */
232             for (aa = at_ifaddr_list; aa != NULL; aa = aa->aa_next) {
233                 if (phase == 1 && (aa->aa_flags & AFA_PHASE2)) {
234                     continue;
235                 }
236                 if (phase == 2 && (aa->aa_flags & AFA_PHASE2) == 0) {
237                     continue;
238                 }
239                 if ((aa->aa_ifp == ifp)
240                 && ((to.sat_addr.s_node == AA_SAT(aa)->sat_addr.s_node)
241                   || (to.sat_addr.s_node == ATADDR_BCAST)
242                   || (ifp->if_flags & IFF_LOOPBACK))) {
243                     break;
244                 }
245             }
246         } else {
247             /* 
248              * A destination network was given. We just try to find 
249              * which ifaddr info matches it.
250              */
251             for (aa = at_ifaddr_list; aa != NULL; aa = aa->aa_next) {
252                 /*
253                  * This is a kludge. Accept packets that are
254                  * for any router on a local netrange.
255                  */
256                 if (to.sat_addr.s_net == aa->aa_firstnet &&
257                         to.sat_addr.s_node == 0) {
258                     break;
259                 }
260                 /*
261                  * Don't use ifaddr info for which we are totally outside the
262                  * netrange, and it's not a startup packet.
263                  * Startup packets are always implicitly allowed on to
264                  * the next test.
265                  */
266                 if (((ntohs(to.sat_addr.s_net) < ntohs(aa->aa_firstnet))
267                     || (ntohs(to.sat_addr.s_net) > ntohs(aa->aa_lastnet)))
268                  && ((ntohs(to.sat_addr.s_net) < 0xff00)
269                     || (ntohs(to.sat_addr.s_net) > 0xfffe))) {
270                     continue;
271                 }
272
273                 /*
274                  * Don't record a match either if we just don't have a match
275                  * in the node address. This can have if the interface
276                  * is in promiscuous mode for example.
277                  */
278                 if ((to.sat_addr.s_node != AA_SAT(aa)->sat_addr.s_node)
279                 && (to.sat_addr.s_node != ATADDR_BCAST)) {
280                     continue;
281                 }
282                 break;
283             }
284         }
285     }
286
287     /*
288      * Adjust the length, removing any padding that may have been added
289      * at a link layer.  We do this before we attempt to forward a packet,
290      * possibly on a different media.
291      */
292     mlen = m->m_pkthdr.len;
293     if (mlen < dlen) {
294         ddpstat.ddps_toosmall++;
295         m_freem(m);
296         return;
297     }
298     if (mlen > dlen) {
299         m_adj(m, dlen - mlen);
300     }
301
302     /*
303      * If it aint for a net on any of our interfaces,
304      * or it IS for a net on a different interface than it came in on,
305      * (and it is not looped back) then consider if we should forward it.
306      * As we are not really a router this is a bit cheeky, but it may be
307      * useful some day.
308      */
309     if ((aa == NULL)
310     || ((to.sat_addr.s_node == ATADDR_BCAST)
311       && (aa->aa_ifp != ifp)
312       && ((ifp->if_flags & IFF_LOOPBACK) == 0))) {
313         /* 
314          * If we've explicitly disabled it, don't route anything
315          */
316         if (ddp_forward == 0) {
317             m_freem(m);
318             return;
319         }
320         /* 
321          * If the cached forwarding route is still valid, use it.
322          */
323         if (forwro.ro_rt
324         && (satosat(&forwro.ro_dst)->sat_addr.s_net != to.sat_addr.s_net
325           || satosat(&forwro.ro_dst)->sat_addr.s_node != to.sat_addr.s_node)) {
326             RTFREE(forwro.ro_rt);
327             forwro.ro_rt = NULL;
328         }
329
330         /*
331          * If we don't have a cached one (any more) or it's useless,
332          * Then get a new route.
333          * XXX this could cause a 'route leak'. check this!
334          */
335         if (forwro.ro_rt == NULL || forwro.ro_rt->rt_ifp == NULL) {
336             forwro.ro_dst.sa_len = sizeof(struct sockaddr_at);
337             forwro.ro_dst.sa_family = AF_APPLETALK;
338             satosat(&forwro.ro_dst)->sat_addr.s_net = to.sat_addr.s_net;
339             satosat(&forwro.ro_dst)->sat_addr.s_node = to.sat_addr.s_node;
340             rtalloc(&forwro);
341         }
342
343         /* 
344          * If it's not going to get there on this hop, and it's
345          * already done too many hops, then throw it away.
346          */
347         if ((to.sat_addr.s_net != satosat(&forwro.ro_dst)->sat_addr.s_net)
348         && (ddpe.deh_hops == DDP_MAXHOPS)) {
349             m_freem(m);
350             return;
351         }
352
353         /*
354          * A ddp router might use the same interface
355          * to forward the packet, which this would not effect.
356          * Don't allow packets to cross from one interface to another however.
357          */
358         if (ddp_firewall
359         && ((forwro.ro_rt == NULL)
360           || (forwro.ro_rt->rt_ifp != ifp))) {
361             m_freem(m);
362             return;
363         }
364
365         /*
366          * Adjust the header.
367          * If it was a short header then it would have not gotten here,
368          * so we can assume there is room to drop the header in.
369          * XXX what about promiscuous mode, etc...
370          */
371         ddpe.deh_hops++;
372         ddpe.deh_bytes = htonl(ddpe.deh_bytes);
373         bcopy((caddr_t)&ddpe, (caddr_t)deh, sizeof(u_short)); /* XXX deh? */
374         if (ddp_route(m, &forwro)) {
375             ddpstat.ddps_cantforward++;
376         } else {
377             ddpstat.ddps_forward++;
378         }
379         return;
380     }
381
382     /*
383      * It was for us, and we have an ifaddr to use with it.
384      */
385     from.sat_len = sizeof(struct sockaddr_at);
386     from.sat_family = AF_APPLETALK;
387
388     /* 
389      * We are no longer interested in the link layer.
390      * so cut it off.
391      */
392     if (elh != NULL) {
393         m_adj(m, sizeof(struct ddpshdr));
394     } else {
395         if (ddp_cksum && cksum && cksum != at_cksum(m, sizeof(int))) {
396             ddpstat.ddps_badsum++;
397             m_freem(m);
398             return;
399         }
400         m_adj(m, sizeof(struct ddpehdr));
401     }
402
403     /* 
404      * Search for ddp protocol control blocks that match these
405      * addresses. 
406      */
407     DDP_LIST_SLOCK();
408     if ((ddp = ddp_search(&from, &to, aa)) == NULL) {
409         goto out;
410     }
411
412 #ifdef MAC
413     SOCK_LOCK(ddp->ddp_socket);
414     if (mac_check_socket_deliver(ddp->ddp_socket, m) != 0) {
415         SOCK_UNLOCK(ddp->ddp_socket);
416         goto out;
417     }
418     SOCK_UNLOCK(ddp->ddp_socket);
419 #endif
420
421     /* 
422      * If we found one, deliver the packet to the socket
423      */
424     SOCKBUF_LOCK(&ddp->ddp_socket->so_rcv);
425     if (sbappendaddr_locked(&ddp->ddp_socket->so_rcv, (struct sockaddr *)&from,
426             m, NULL) == 0) {
427         SOCKBUF_UNLOCK(&ddp->ddp_socket->so_rcv);
428         /* 
429          * If the socket is full (or similar error) dump the packet.
430          */
431         ddpstat.ddps_nosockspace++;
432         goto out;
433     }
434     /*
435      * And wake up whatever might be waiting for it
436      */
437     sorwakeup_locked(ddp->ddp_socket);
438     m = NULL;
439 out:
440     DDP_LIST_SUNLOCK();
441     if (m != NULL)
442         m_freem(m);
443 }
444
445 #if 0
446 /* As if we haven't got enough of this sort of think floating
447 around the kernel :) */
448
449 #define BPXLEN  48
450 #define BPALEN  16
451 #include <ctype.h>
452 char    hexdig[] = "0123456789ABCDEF";
453
454 static void
455 bprint(char *data, int len)
456 {
457     char        xout[ BPXLEN ], aout[ BPALEN ];
458     int         i = 0;
459
460     bzero(xout, BPXLEN);
461     bzero(aout, BPALEN);
462
463     for (;;) {
464         if (len < 1) {
465             if (i != 0) {
466                 printf("%s\t%s\n", xout, aout);
467             }
468             printf("%s\n", "(end)");
469             break;
470         }
471
472         xout[ (i*3) ] = hexdig[ (*data & 0xf0) >> 4 ];
473         xout[ (i*3) + 1 ] = hexdig[ *data & 0x0f ];
474
475         if ((u_char)*data < 0x7f && (u_char)*data > 0x20) {
476             aout[ i ] = *data;
477         } else {
478             aout[ i ] = '.';
479         }
480
481         xout[ (i*3) + 2 ] = ' ';
482
483         i++;
484         len--;
485         data++;
486
487         if (i > BPALEN - 2) {
488             printf("%s\t%s\n", xout, aout);
489             bzero(xout, BPXLEN);
490             bzero(aout, BPALEN);
491             i = 0;
492             continue;
493         }
494     }
495 }
496
497 static void
498 m_printm(struct mbuf *m)
499 {
500     for (; m; m = m->m_next) {
501         bprint(mtod(m, char *), m->m_len);
502     }
503 }
504 #endif