]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/netipx/ipx_input.c
linprocfs: add support for /sys/kernel/random/uuid
[FreeBSD/FreeBSD.git] / sys / netipx / ipx_input.c
1 /*-
2  * Copyright (c) 1984, 1985, 1986, 1987, 1993
3  *      The Regents of the University of California.
4  * Copyright (c) 2004-2009 Robert N. M. Watson
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 4. Neither the name of the University nor the names of its contributors
16  *    may be used to endorse or promote products derived from this software
17  *    without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29  * SUCH DAMAGE.
30  *
31  * Copyright (c) 1995, Mike Mitchell
32  * All rights reserved.
33  *
34  * Redistribution and use in source and binary forms, with or without
35  * modification, are permitted provided that the following conditions
36  * are met:
37  * 1. Redistributions of source code must retain the above copyright
38  *    notice, this list of conditions and the following disclaimer.
39  * 2. Redistributions in binary form must reproduce the above copyright
40  *    notice, this list of conditions and the following disclaimer in the
41  *    documentation and/or other materials provided with the distribution.
42  * 3. All advertising materials mentioning features or use of this software
43  *    must display the following acknowledgement:
44  *      This product includes software developed by the University of
45  *      California, Berkeley and its contributors.
46  * 4. Neither the name of the University nor the names of its contributors
47  *    may be used to endorse or promote products derived from this software
48  *    without specific prior written permission.
49  *
50  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
51  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
52  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
53  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
54  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
55  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
56  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
57  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
58  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
59  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
60  * SUCH DAMAGE.
61  *
62  *      @(#)ipx_input.c
63  */
64
65 #include <sys/cdefs.h>
66 __FBSDID("$FreeBSD$");
67
68 #include <sys/param.h>
69 #include <sys/systm.h>
70 #include <sys/mbuf.h>
71 #include <sys/protosw.h>
72 #include <sys/socket.h>
73 #include <sys/kernel.h>
74 #include <sys/random.h>
75 #include <sys/lock.h>
76 #include <sys/rwlock.h>
77 #include <sys/sysctl.h>
78
79 #include <net/if.h>
80 #include <net/if_var.h>
81 #include <net/route.h>
82 #include <net/netisr.h>
83
84 #include <netipx/ipx.h>
85 #include <netipx/spx.h>
86 #include <netipx/ipx_if.h>
87 #include <netipx/ipx_pcb.h>
88 #include <netipx/ipx_var.h>
89
90 int     ipxcksum = 0;
91 SYSCTL_INT(_net_ipx_ipx, OID_AUTO, checksum, CTLFLAG_RW,
92            &ipxcksum, 0, "Compute ipx checksum");
93
94 static int      ipxprintfs = 0;         /* printing forwarding information */
95 SYSCTL_INT(_net_ipx_ipx, OID_AUTO, ipxprintfs, CTLFLAG_RW,
96            &ipxprintfs, 0, "Printing forwarding information");
97
98 static int      ipxforwarding = 0;
99 SYSCTL_INT(_net_ipx_ipx, OID_AUTO, ipxforwarding, CTLFLAG_RW,
100             &ipxforwarding, 0, "Enable ipx forwarding");
101
102 static int      ipxnetbios = 0;
103 SYSCTL_INT(_net_ipx, OID_AUTO, ipxnetbios, CTLFLAG_RW,
104            &ipxnetbios, 0, "Propagate netbios over ipx");
105
106 static  int ipx_do_route(struct ipx_addr *src, struct route *ro);
107 static  void ipx_undo_route(struct route *ro);
108 static  void ipx_forward(struct mbuf *m);
109 static  void ipxintr(struct mbuf *m);
110
111 const union     ipx_net ipx_zeronet;
112
113 const union     ipx_net ipx_broadnet = { .s_net[0] = 0xffff,
114                                             .s_net[1] = 0xffff };
115 const union     ipx_host ipx_broadhost = { .s_host[0] = 0xffff,
116                                             .s_host[1] = 0xffff,
117                                             .s_host[2] = 0xffff };
118
119 struct  ipxstat ipxstat;
120 struct  sockaddr_ipx ipx_netmask, ipx_hostmask;
121
122 /*
123  * IPX protocol control block (pcb) lists.
124  */
125 struct mtx              ipxpcb_list_mtx;
126 struct ipxpcbhead       ipxpcb_list;
127 struct ipxpcbhead       ipxrawpcb_list;
128
129 static struct netisr_handler ipx_nh = {
130         .nh_name = "ipx",
131         .nh_handler = ipxintr,
132         .nh_proto = NETISR_IPX,
133         .nh_policy = NETISR_POLICY_SOURCE,
134 };
135
136 long    ipx_pexseq;             /* Locked with ipxpcb_list_mtx. */
137
138 /*
139  * IPX initialization.
140  */
141
142 void
143 ipx_init(void)
144 {
145
146         read_random(&ipx_pexseq, sizeof ipx_pexseq);
147
148         LIST_INIT(&ipxpcb_list);
149         LIST_INIT(&ipxrawpcb_list);
150         TAILQ_INIT(&ipx_ifaddrhead);
151
152         IPX_LIST_LOCK_INIT();
153         IPX_IFADDR_LOCK_INIT();
154
155         ipx_netmask.sipx_len = 6;
156         ipx_netmask.sipx_addr.x_net = ipx_broadnet;
157
158         ipx_hostmask.sipx_len = 12;
159         ipx_hostmask.sipx_addr.x_net = ipx_broadnet;
160         ipx_hostmask.sipx_addr.x_host = ipx_broadhost;
161
162         netisr_register(&ipx_nh);
163 }
164
165 /*
166  * IPX input routine.  Pass to next level.
167  */
168 static void
169 ipxintr(struct mbuf *m)
170 {
171         struct ipx *ipx;
172         struct ipxpcb *ipxp;
173         struct ipx_ifaddr *ia;
174         int len;
175
176         /*
177          * If no IPX addresses have been set yet but the interfaces
178          * are receiving, can't do anything with incoming packets yet.
179          */
180         if (TAILQ_EMPTY(&ipx_ifaddrhead)) {
181                 m_freem(m);
182                 return;
183         }
184
185         ipxstat.ipxs_total++;
186
187         if ((m->m_flags & M_EXT || m->m_len < sizeof(struct ipx)) &&
188             (m = m_pullup(m, sizeof(struct ipx))) == NULL) {
189                 ipxstat.ipxs_toosmall++;
190                 return;
191         }
192
193         /*
194          * Give any raw listeners a crack at the packet
195          */
196         IPX_LIST_LOCK();
197         LIST_FOREACH(ipxp, &ipxrawpcb_list, ipxp_list) {
198                 struct mbuf *m1 = m_copy(m, 0, (int)M_COPYALL);
199                 if (m1 != NULL) {
200                         IPX_LOCK(ipxp);
201                         ipx_input(m1, ipxp);
202                         IPX_UNLOCK(ipxp);
203                 }
204         }
205         IPX_LIST_UNLOCK();
206
207         ipx = mtod(m, struct ipx *);
208         len = ntohs(ipx->ipx_len);
209         /*
210          * Check that the amount of data in the buffers
211          * is as at least much as the IPX header would have us expect.
212          * Trim mbufs if longer than we expect.
213          * Drop packet if shorter than we expect.
214          */
215         if (m->m_pkthdr.len < len) {
216                 ipxstat.ipxs_tooshort++;
217                 m_freem(m);
218                 return;
219         }
220         if (m->m_pkthdr.len > len) {
221                 if (m->m_len == m->m_pkthdr.len) {
222                         m->m_len = len;
223                         m->m_pkthdr.len = len;
224                 } else
225                         m_adj(m, len - m->m_pkthdr.len);
226         }
227         if (ipxcksum && ipx->ipx_sum != 0xffff) {
228                 if (ipx->ipx_sum != ipx_cksum(m, len)) {
229                         ipxstat.ipxs_badsum++;
230                         m_freem(m);
231                         return;
232                 }
233         }
234
235         /*
236          * Propagated (Netbios) packets (type 20) has to be handled
237          * different. :-(
238          */
239         if (ipx->ipx_pt == IPXPROTO_NETBIOS) {
240                 if (ipxnetbios) {
241                         ipx_output_type20(m);
242                         return;
243                 } else {
244                         m_freem(m);
245                         return;
246                 }
247         }
248
249         /*
250          * Is this a directed broadcast?
251          */
252         if (ipx_hosteqnh(ipx_broadhost,ipx->ipx_dna.x_host)) {
253                 if ((!ipx_neteq(ipx->ipx_dna, ipx->ipx_sna)) &&
254                     (!ipx_neteqnn(ipx->ipx_dna.x_net, ipx_broadnet)) &&
255                     (!ipx_neteqnn(ipx->ipx_sna.x_net, ipx_zeronet)) &&
256                     (!ipx_neteqnn(ipx->ipx_dna.x_net, ipx_zeronet)) ) {
257                         /*
258                          * If it is a broadcast to the net where it was
259                          * received from, treat it as ours.
260                          */
261                         IPX_IFADDR_RLOCK();
262                         TAILQ_FOREACH(ia, &ipx_ifaddrhead, ia_link) {
263                                 if ((ia->ia_ifa.ifa_ifp == m->m_pkthdr.rcvif)
264                                     && ipx_neteq(ia->ia_addr.sipx_addr,
265                                     ipx->ipx_dna)) {
266                                         IPX_IFADDR_RUNLOCK();
267                                         goto ours;
268                                 }
269                         }
270                         IPX_IFADDR_RUNLOCK();
271
272                         /*
273                          * Look to see if I need to eat this packet.
274                          * Algorithm is to forward all young packets
275                          * and prematurely age any packets which will
276                          * by physically broadcasted.
277                          * Any very old packets eaten without forwarding
278                          * would die anyway.
279                          *
280                          * Suggestion of Bill Nesheim, Cornell U.
281                          */
282                         if (ipx->ipx_tc < IPX_MAXHOPS) {
283                                 ipx_forward(m);
284                                 return;
285                         }
286                 }
287         /*
288          * Is this our packet? If not, forward.
289          */
290         } else {
291                 IPX_IFADDR_RLOCK();
292                 TAILQ_FOREACH(ia, &ipx_ifaddrhead, ia_link) {
293                         if (ipx_hosteq(ipx->ipx_dna, ia->ia_addr.sipx_addr) &&
294                             (ipx_neteq(ipx->ipx_dna, ia->ia_addr.sipx_addr) ||
295                              ipx_neteqnn(ipx->ipx_dna.x_net, ipx_zeronet)))
296                                 break;
297                 }
298                 IPX_IFADDR_RUNLOCK();
299                 if (ia == NULL) {
300                         ipx_forward(m);
301                         return;
302                 }
303         }
304 ours:
305         /*
306          * Locate pcb for datagram.
307          */
308         IPX_LIST_LOCK();
309         ipxp = ipx_pcblookup(&ipx->ipx_sna, ipx->ipx_dna.x_port, IPX_WILDCARD);
310         /*
311          * Switch out to protocol's input routine.
312          */
313         if (ipxp != NULL) {
314                 ipxstat.ipxs_delivered++;
315                 if ((ipxp->ipxp_flags & IPXP_ALL_PACKETS) == 0)
316                         switch (ipx->ipx_pt) {
317                         case IPXPROTO_SPX:
318                                 IPX_LOCK(ipxp);
319                                 /* Will release both locks. */
320                                 spx_input(m, ipxp);
321                                 return;
322                         }
323                 IPX_LOCK(ipxp);
324                 ipx_input(m, ipxp);
325                 IPX_UNLOCK(ipxp);
326         } else
327                 m_freem(m);
328         IPX_LIST_UNLOCK();
329 }
330
331 void
332 ipx_ctlinput(cmd, arg_as_sa, dummy)
333         int cmd;
334         struct sockaddr *arg_as_sa;     /* XXX should be swapped with dummy */
335         void *dummy;
336 {
337
338         /* Currently, nothing. */
339 }
340
341 /*
342  * Forward a packet. If some error occurs drop the packet. IPX don't
343  * have a way to return errors to the sender.
344  */
345
346 static struct route ipx_droute;
347 static struct route ipx_sroute;
348
349 static void
350 ipx_forward(struct mbuf *m)
351 {
352         struct ipx *ipx = mtod(m, struct ipx *);
353         int error;
354         int agedelta = 1;
355         int flags = IPX_FORWARDING;
356         int ok_there = 0;
357         int ok_back = 0;
358
359         if (ipxforwarding == 0) {
360                 /* can't tell difference between net and host */
361                 ipxstat.ipxs_cantforward++;
362                 m_freem(m);
363                 goto cleanup;
364         }
365         ipx->ipx_tc++;
366         if (ipx->ipx_tc > IPX_MAXHOPS) {
367                 ipxstat.ipxs_cantforward++;
368                 m_freem(m);
369                 goto cleanup;
370         }
371
372         if ((ok_there = ipx_do_route(&ipx->ipx_dna,&ipx_droute)) == 0) {
373                 ipxstat.ipxs_noroute++;
374                 m_freem(m);
375                 goto cleanup;
376         }
377         /*
378          * Here we think about  forwarding  broadcast packets,
379          * so we try to insure that it doesn't go back out
380          * on the interface it came in on.  Also, if we
381          * are going to physically broadcast this, let us
382          * age the packet so we can eat it safely the second time around.
383          */
384         if (ipx->ipx_dna.x_host.c_host[0] & 0x1) {
385                 struct ipx_ifaddr *ia;
386                 struct ifnet *ifp;
387
388                 IPX_IFADDR_RLOCK();
389                 ia = ipx_iaonnetof(&ipx->ipx_dna);
390                 if (ia != NULL) {
391                         /* I'm gonna hafta eat this packet */
392                         agedelta += IPX_MAXHOPS - ipx->ipx_tc;
393                         ipx->ipx_tc = IPX_MAXHOPS;
394                 }
395                 IPX_IFADDR_RUNLOCK();
396                 if ((ok_back = ipx_do_route(&ipx->ipx_sna,&ipx_sroute)) == 0) {
397                         /* error = ENETUNREACH; He'll never get it! */
398                         ipxstat.ipxs_noroute++;
399                         m_freem(m);
400                         goto cleanup;
401                 }
402                 if (ipx_droute.ro_rt &&
403                     (ifp = ipx_droute.ro_rt->rt_ifp) &&
404                     ipx_sroute.ro_rt &&
405                     (ifp != ipx_sroute.ro_rt->rt_ifp)) {
406                         flags |= IPX_ALLOWBROADCAST;
407                 } else {
408                         ipxstat.ipxs_noroute++;
409                         m_freem(m);
410                         goto cleanup;
411                 }
412         }
413         /*
414          * We don't need to recompute checksum because ipx_tc field
415          * is ignored by checksum calculation routine, however
416          * it may be desirable to reset checksum if ipxcksum == 0
417          */
418 #if 0
419         if (!ipxcksum)
420                 ipx->ipx_sum = 0xffff;
421 #endif
422
423         error = ipx_outputfl(m, &ipx_droute, flags);
424         if (error == 0) {
425                 ipxstat.ipxs_forward++;
426
427                 if (ipxprintfs) {
428                         printf("forward: ");
429                         ipx_printhost(&ipx->ipx_sna);
430                         printf(" to ");
431                         ipx_printhost(&ipx->ipx_dna);
432                         printf(" hops %d\n", ipx->ipx_tc);
433                 }
434         } 
435 cleanup:
436         if (ok_there)
437                 ipx_undo_route(&ipx_droute);
438         if (ok_back)
439                 ipx_undo_route(&ipx_sroute);
440 }
441
442 static int
443 ipx_do_route(struct ipx_addr *src, struct route *ro)
444 {
445         struct sockaddr_ipx *dst;
446
447         bzero((caddr_t)ro, sizeof(*ro));
448         dst = (struct sockaddr_ipx *)&ro->ro_dst;
449
450         dst->sipx_len = sizeof(*dst);
451         dst->sipx_family = AF_IPX;
452         dst->sipx_addr = *src;
453         dst->sipx_addr.x_port = 0;
454         rtalloc_ign(ro, 0);
455         if (ro->ro_rt == NULL || ro->ro_rt->rt_ifp == NULL) {
456                 return (0);
457         }
458         ro->ro_rt->rt_use++;
459         return (1);
460 }
461
462 static void
463 ipx_undo_route(struct route *ro)
464 {
465
466         if (ro->ro_rt != NULL) {
467                 RTFREE(ro->ro_rt);
468         }
469 }