1 /*-
2 * Copyright (c) 1984, 1985, 1986, 1987, 1993
3 * The Regents of the University of California.
4 * Copyright (c) 2004-2005 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: releng/7.4/sys/netipx/ipx_input.c 215400 2010-11-16 15:02:53Z sobomax $");
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/sysctl.h>
76
77 #include <net/if.h>
78 #include <net/route.h>
79 #include <net/netisr.h>
80
81 #include <netipx/ipx.h>
82 #include <netipx/spx.h>
83 #include <netipx/ipx_if.h>
84 #include <netipx/ipx_pcb.h>
85 #include <netipx/ipx_var.h>
86
87 int ipxcksum = 0;
88 SYSCTL_INT(_net_ipx_ipx, OID_AUTO, checksum, CTLFLAG_RW,
89 &ipxcksum, 0, "");
90
91 static int ipxprintfs = 0; /* printing forwarding information */
92 SYSCTL_INT(_net_ipx_ipx, OID_AUTO, ipxprintfs, CTLFLAG_RW,
93 &ipxprintfs, 0, "");
94
95 static int ipxforwarding = 0;
96 SYSCTL_INT(_net_ipx_ipx, OID_AUTO, ipxforwarding, CTLFLAG_RW,
97 &ipxforwarding, 0, "");
98
99 static int ipxnetbios = 0;
100 SYSCTL_INT(_net_ipx, OID_AUTO, ipxnetbios, CTLFLAG_RW,
101 &ipxnetbios, 0, "");
102
103 const union ipx_net ipx_zeronet;
104 const union ipx_host ipx_zerohost;
105
106 const union ipx_net ipx_broadnet = { .s_net[0] = 0xffff,
107 .s_net[1] = 0xffff };
108 const union ipx_host ipx_broadhost = { .s_host[0] = 0xffff,
109 .s_host[1] = 0xffff,
110 .s_host[2] = 0xffff };
111
112 struct ipxstat ipxstat;
113 struct sockaddr_ipx ipx_netmask, ipx_hostmask;
114
115 /*
116 * IPX protocol control block (pcb) lists.
117 */
118 struct mtx ipxpcb_list_mtx;
119 struct ipxpcbhead ipxpcb_list;
120 struct ipxpcbhead ipxrawpcb_list;
121
122 static struct ifqueue ipxintrq;
123
124 long ipx_pexseq; /* Locked with ipxpcb_list_mtx. */
125
126 static int ipx_do_route(struct ipx_addr *src, struct route *ro);
127 static void ipx_undo_route(struct route *ro);
128 static void ipx_forward(struct mbuf *m);
129 static void ipxintr(struct mbuf *m);
130
131 /*
132 * IPX initialization.
133 */
134
135 void
136 ipx_init(void)
137 {
138
139 read_random(&ipx_pexseq, sizeof ipx_pexseq);
140
141 LIST_INIT(&ipxpcb_list);
142 LIST_INIT(&ipxrawpcb_list);
143
144 IPX_LIST_LOCK_INIT();
145
146 ipx_netmask.sipx_len = 6;
147 ipx_netmask.sipx_addr.x_net = ipx_broadnet;
148
149 ipx_hostmask.sipx_len = 12;
150 ipx_hostmask.sipx_addr.x_net = ipx_broadnet;
151 ipx_hostmask.sipx_addr.x_host = ipx_broadhost;
152
153 ipxintrq.ifq_maxlen = ifqmaxlen;
154 mtx_init(&ipxintrq.ifq_mtx, "ipx_inq", NULL, MTX_DEF);
155 netisr_register(NETISR_IPX, ipxintr, &ipxintrq, NETISR_MPSAFE);
156 }
157
158 /*
159 * IPX input routine. Pass to next level.
160 */
161 static void
162 ipxintr(struct mbuf *m)
163 {
164 struct ipx *ipx;
165 struct ipxpcb *ipxp;
166 struct ipx_ifaddr *ia;
167 int len;
168
169 /*
170 * If no IPX addresses have been set yet but the interfaces
171 * are receiving, can't do anything with incoming packets yet.
172 */
173 if (ipx_ifaddr == NULL) {
174 m_freem(m);
175 return;
176 }
177
178 ipxstat.ipxs_total++;
179
180 if ((m->m_flags & M_EXT || m->m_len < sizeof(struct ipx)) &&
181 (m = m_pullup(m, sizeof(struct ipx))) == NULL) {
182 ipxstat.ipxs_toosmall++;
183 return;
184 }
185
186 /*
187 * Give any raw listeners a crack at the packet
188 */
189 IPX_LIST_LOCK();
190 LIST_FOREACH(ipxp, &ipxrawpcb_list, ipxp_list) {
191 struct mbuf *m1 = m_copy(m, 0, (int)M_COPYALL);
192 if (m1 != NULL) {
193 IPX_LOCK(ipxp);
194 ipx_input(m1, ipxp);
195 IPX_UNLOCK(ipxp);
196 }
197 }
198 IPX_LIST_UNLOCK();
199
200 ipx = mtod(m, struct ipx *);
201 len = ntohs(ipx->ipx_len);
202 /*
203 * Check that the amount of data in the buffers
204 * is as at least much as the IPX header would have us expect.
205 * Trim mbufs if longer than we expect.
206 * Drop packet if shorter than we expect.
207 */
208 if (m->m_pkthdr.len < len) {
209 ipxstat.ipxs_tooshort++;
210 m_freem(m);
211 return;
212 }
213 if (m->m_pkthdr.len > len) {
214 if (m->m_len == m->m_pkthdr.len) {
215 m->m_len = len;
216 m->m_pkthdr.len = len;
217 } else
218 m_adj(m, len - m->m_pkthdr.len);
219 }
220 if (ipxcksum && ipx->ipx_sum != 0xffff) {
221 if (ipx->ipx_sum != ipx_cksum(m, len)) {
222 ipxstat.ipxs_badsum++;
223 m_freem(m);
224 return;
225 }
226 }
227
228 /*
229 * Propagated (Netbios) packets (type 20) has to be handled
230 * different. :-(
231 */
232 if (ipx->ipx_pt == IPXPROTO_NETBIOS) {
233 if (ipxnetbios) {
234 ipx_output_type20(m);
235 return;
236 } else {
237 m_freem(m);
238 return;
239 }
240 }
241
242 /*
243 * Is this a directed broadcast?
244 */
245 if (ipx_hosteqnh(ipx_broadhost,ipx->ipx_dna.x_host)) {
246 if ((!ipx_neteq(ipx->ipx_dna, ipx->ipx_sna)) &&
247 (!ipx_neteqnn(ipx->ipx_dna.x_net, ipx_broadnet)) &&
248 (!ipx_neteqnn(ipx->ipx_sna.x_net, ipx_zeronet)) &&
249 (!ipx_neteqnn(ipx->ipx_dna.x_net, ipx_zeronet)) ) {
250 /*
251 * If it is a broadcast to the net where it was
252 * received from, treat it as ours.
253 */
254 for (ia = ipx_ifaddr; ia != NULL; ia = ia->ia_next)
255 if((ia->ia_ifa.ifa_ifp == m->m_pkthdr.rcvif) &&
256 ipx_neteq(ia->ia_addr.sipx_addr,
257 ipx->ipx_dna))
258 goto ours;
259
260 /*
261 * Look to see if I need to eat this packet.
262 * Algorithm is to forward all young packets
263 * and prematurely age any packets which will
264 * by physically broadcasted.
265 * Any very old packets eaten without forwarding
266 * would die anyway.
267 *
268 * Suggestion of Bill Nesheim, Cornell U.
269 */
270 if (ipx->ipx_tc < IPX_MAXHOPS) {
271 ipx_forward(m);
272 return;
273 }
274 }
275 /*
276 * Is this our packet? If not, forward.
277 */
278 } else {
279 for (ia = ipx_ifaddr; ia != NULL; ia = ia->ia_next)
280 if (ipx_hosteq(ipx->ipx_dna, ia->ia_addr.sipx_addr) &&
281 (ipx_neteq(ipx->ipx_dna, ia->ia_addr.sipx_addr) ||
282 ipx_neteqnn(ipx->ipx_dna.x_net, ipx_zeronet)))
283 break;
284
285 if (ia == NULL) {
286 ipx_forward(m);
287 return;
288 }
289 }
290 ours:
291 /*
292 * Locate pcb for datagram.
293 */
294 IPX_LIST_LOCK();
295 ipxp = ipx_pcblookup(&ipx->ipx_sna, ipx->ipx_dna.x_port, IPX_WILDCARD);
296 /*
297 * Switch out to protocol's input routine.
298 */
299 if (ipxp != NULL) {
300 ipxstat.ipxs_delivered++;
301 if ((ipxp->ipxp_flags & IPXP_ALL_PACKETS) == 0)
302 switch (ipx->ipx_pt) {
303 case IPXPROTO_SPX:
304 IPX_LOCK(ipxp);
305 /* Will release both locks. */
306 spx_input(m, ipxp);
307 return;
308 }
309 IPX_LOCK(ipxp);
310 ipx_input(m, ipxp);
311 IPX_UNLOCK(ipxp);
312 } else
313 m_freem(m);
314 IPX_LIST_UNLOCK();
315 }
316
317 void
318 ipx_ctlinput(cmd, arg_as_sa, dummy)
319 int cmd;
320 struct sockaddr *arg_as_sa; /* XXX should be swapped with dummy */
321 void *dummy;
322 {
323
324 /* Currently, nothing. */
325 }
326
327 /*
328 * Forward a packet. If some error occurs drop the packet. IPX don't
329 * have a way to return errors to the sender.
330 */
331
332 static struct route ipx_droute;
333 static struct route ipx_sroute;
334
335 static void
336 ipx_forward(struct mbuf *m)
337 {
338 struct ipx *ipx = mtod(m, struct ipx *);
339 int error;
340 int agedelta = 1;
341 int flags = IPX_FORWARDING;
342 int ok_there = 0;
343 int ok_back = 0;
344
345 if (ipxforwarding == 0) {
346 /* can't tell difference between net and host */
347 ipxstat.ipxs_cantforward++;
348 m_freem(m);
349 goto cleanup;
350 }
351 ipx->ipx_tc++;
352 if (ipx->ipx_tc > IPX_MAXHOPS) {
353 ipxstat.ipxs_cantforward++;
354 m_freem(m);
355 goto cleanup;
356 }
357
358 if ((ok_there = ipx_do_route(&ipx->ipx_dna,&ipx_droute)) == 0) {
359 ipxstat.ipxs_noroute++;
360 m_freem(m);
361 goto cleanup;
362 }
363 /*
364 * Here we think about forwarding broadcast packets,
365 * so we try to insure that it doesn't go back out
366 * on the interface it came in on. Also, if we
367 * are going to physically broadcast this, let us
368 * age the packet so we can eat it safely the second time around.
369 */
370 if (ipx->ipx_dna.x_host.c_host[0] & 0x1) {
371 struct ipx_ifaddr *ia = ipx_iaonnetof(&ipx->ipx_dna);
372 struct ifnet *ifp;
373 if (ia != NULL) {
374 /* I'm gonna hafta eat this packet */
375 agedelta += IPX_MAXHOPS - ipx->ipx_tc;
376 ipx->ipx_tc = IPX_MAXHOPS;
377 }
378 if ((ok_back = ipx_do_route(&ipx->ipx_sna,&ipx_sroute)) == 0) {
379 /* error = ENETUNREACH; He'll never get it! */
380 ipxstat.ipxs_noroute++;
381 m_freem(m);
382 goto cleanup;
383 }
384 if (ipx_droute.ro_rt &&
385 (ifp = ipx_droute.ro_rt->rt_ifp) &&
386 ipx_sroute.ro_rt &&
387 (ifp != ipx_sroute.ro_rt->rt_ifp)) {
388 flags |= IPX_ALLOWBROADCAST;
389 } else {
390 ipxstat.ipxs_noroute++;
391 m_freem(m);
392 goto cleanup;
393 }
394 }
395 /*
396 * We don't need to recompute checksum because ipx_tc field
397 * is ignored by checksum calculation routine, however
398 * it may be desirable to reset checksum if ipxcksum == 0
399 */
400 #if 0
401 if (!ipxcksum)
402 ipx->ipx_sum = 0xffff;
403 #endif
404
405 error = ipx_outputfl(m, &ipx_droute, flags);
406 if (error == 0) {
407 ipxstat.ipxs_forward++;
408
409 if (ipxprintfs) {
410 printf("forward: ");
411 ipx_printhost(&ipx->ipx_sna);
412 printf(" to ");
413 ipx_printhost(&ipx->ipx_dna);
414 printf(" hops %d\n", ipx->ipx_tc);
415 }
416 }
417 cleanup:
418 if (ok_there)
419 ipx_undo_route(&ipx_droute);
420 if (ok_back)
421 ipx_undo_route(&ipx_sroute);
422 }
423
424 static int
425 ipx_do_route(struct ipx_addr *src, struct route *ro)
426 {
427 struct sockaddr_ipx *dst;
428
429 bzero((caddr_t)ro, sizeof(*ro));
430 dst = (struct sockaddr_ipx *)&ro->ro_dst;
431
432 dst->sipx_len = sizeof(*dst);
433 dst->sipx_family = AF_IPX;
434 dst->sipx_addr = *src;
435 dst->sipx_addr.x_port = 0;
436 rtalloc_ign(ro, 0);
437 if (ro->ro_rt == NULL || ro->ro_rt->rt_ifp == NULL) {
438 return (0);
439 }
440 ro->ro_rt->rt_use++;
441 return (1);
442 }
443
444 static void
445 ipx_undo_route(struct route *ro)
446 {
447
448 if (ro->ro_rt != NULL) {
449 RTFREE(ro->ro_rt);
450 }
451 }
452
453 /*
454 * XXXRW: This code should be run in its own netisr dispatch to avoid a call
455 * back into the socket code from the IPX output path.
456 */
457 void
458 ipx_watch_output(struct mbuf *m, struct ifnet *ifp)
459 {
460 struct ipxpcb *ipxp;
461 struct ifaddr *ifa;
462 struct ipx_ifaddr *ia;
463
464 /*
465 * Give any raw listeners a crack at the packet
466 */
467 IPX_LIST_LOCK();
468 LIST_FOREACH(ipxp, &ipxrawpcb_list, ipxp_list) {
469 struct mbuf *m0 = m_copy(m, 0, (int)M_COPYALL);
470 if (m0 != NULL) {
471 struct ipx *ipx;
472
473 M_PREPEND(m0, sizeof(*ipx), M_DONTWAIT);
474 if (m0 == NULL)
475 continue;
476 ipx = mtod(m0, struct ipx *);
477 ipx->ipx_sna.x_net = ipx_zeronet;
478 for (ia = ipx_ifaddr; ia != NULL; ia = ia->ia_next)
479 if (ifp == ia->ia_ifp)
480 break;
481 if (ia == NULL)
482 ipx->ipx_sna.x_host = ipx_zerohost;
483 else
484 ipx->ipx_sna.x_host =
485 ia->ia_addr.sipx_addr.x_host;
486
487 if (ifp != NULL && (ifp->if_flags & IFF_POINTOPOINT))
488 TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
489 if (ifa->ifa_addr->sa_family == AF_IPX) {
490 ipx->ipx_sna = IA_SIPX(ifa)->sipx_addr;
491 break;
492 }
493 }
494 ipx->ipx_len = ntohl(m0->m_pkthdr.len);
495 IPX_LOCK(ipxp);
496 ipx_input(m0, ipxp);
497 IPX_UNLOCK(ipxp);
498 }
499 }
500 IPX_LIST_UNLOCK();
501 }
Cache object: dd1d7be2839daa31767dd6ca801b2695
|