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