Deleted Added
full compact
ipx_input.c (11947) ipx_input.c (11991)
1/*
2 * Copyright (c) 1995, Mike Mitchell
3 * Copyright (c) 1984, 1985, 1986, 1987, 1993
4 * The Regents of the University of California. All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. All advertising materials mentioning features or use of this software
15 * must display the following acknowledgement:
16 * This product includes software developed by the University of
17 * California, Berkeley and its contributors.
18 * 4. Neither the name of the University nor the names of its contributors
19 * may be used to endorse or promote products derived from this software
20 * without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE.
33 *
1/*
2 * Copyright (c) 1995, Mike Mitchell
3 * Copyright (c) 1984, 1985, 1986, 1987, 1993
4 * The Regents of the University of California. All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. All advertising materials mentioning features or use of this software
15 * must display the following acknowledgement:
16 * This product includes software developed by the University of
17 * California, Berkeley and its contributors.
18 * 4. Neither the name of the University nor the names of its contributors
19 * may be used to endorse or promote products derived from this software
20 * without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE.
33 *
34 * @(#)ipx_input.c
34 * @(#)$Id$
35 */
36
37#include <sys/param.h>
38#include <sys/systm.h>
39#include <sys/malloc.h>
40#include <sys/mbuf.h>
41#include <sys/domain.h>
42#include <sys/protosw.h>
43#include <sys/socket.h>
44#include <sys/socketvar.h>
45#include <sys/errno.h>
46#include <sys/time.h>
47#include <sys/kernel.h>
48
49#include <net/if.h>
50#include <net/route.h>
51#include <net/netisr.h>
52#include <net/raw_cb.h>
53
54#include <netipx/ipx.h>
55#include <netipx/spx.h>
56#include <netipx/ipx_if.h>
57#include <netipx/ipx_pcb.h>
58#include <netipx/ipx_var.h>
59#include <netipx/ipx_error.h>
60
61#ifndef IPXFORWARDING
62#ifdef GATEWAY
63#define IPXFORWARDING 1 /* forward IPX packets not for us */
64#else
65#define IPXFORWARDING 0 /* don't forward IPX packets not for us */
66#endif
67#endif
68#ifndef IPXPRINTFS
69#define IPXPRINTFS 1 /* printing forwarding information */
70#endif
71
72#ifndef IPXCKSUM
73#define IPXCKSUM 0 /* perform IPX checksum */
74#endif
75
76#ifndef IXDONOSOCKS
77#define IPXDONOSOCKS 0 /* return no socket errors */
78#endif
79
80int ipxcksum = IPXCKSUM;
81int ipxprintfs = IPXPRINTFS;
82int ipxdonosocks = IPXDONOSOCKS;
83int ipxforwarding = IPXFORWARDING;
84
85union ipx_host ipx_thishost;
86union ipx_net ipx_zeronet;
87union ipx_host ipx_zerohost;
88
89union ipx_net ipx_broadnet;
90union ipx_host ipx_broadhost;
91
92struct ipxstat ipxstat;
93struct sockaddr_ipx ipx_netmask, ipx_hostmask;
94
95int ipxintr_getpck = 0;
96int ipxintr_swtch = 0;
97
98static u_short allones[] = {-1, -1, -1};
99
100struct ipxpcb ipxpcb;
101struct ipxpcb ipxrawpcb;
102
103struct ifqueue ipxintrq;
104int ipxqmaxlen = IFQ_MAXLEN;
105
106long ipx_pexseq;
107
108NETISR_SET(NETISR_IPX, ipxintr);
109
110/*
111 * IPX initialization.
112 */
113
114void
115ipx_init()
116{
117 ipx_broadnet = * (union ipx_net *) allones;
118 ipx_broadhost = * (union ipx_host *) allones;
119
120 ipx_pexseq = time.tv_usec;
121 ipxintrq.ifq_maxlen = ipxqmaxlen;
122 ipxpcb.ipxp_next = ipxpcb.ipxp_prev = &ipxpcb;
123 ipxrawpcb.ipxp_next = ipxrawpcb.ipxp_prev = &ipxrawpcb;
124
125 ipx_netmask.sipx_len = 6;
126 ipx_netmask.sipx_addr.x_net = ipx_broadnet;
127
128 ipx_hostmask.sipx_len = 12;
129 ipx_hostmask.sipx_addr.x_net = ipx_broadnet;
130 ipx_hostmask.sipx_addr.x_host = ipx_broadhost;
131}
132
133/*
134 * IPX input routine. Pass to next level.
135 */
136void
137ipxintr()
138{
139 register struct ipx *ipx;
140 register struct mbuf *m;
141 register struct ipxpcb *ipxp;
142 register int i;
143 int len, s, error;
144 char oddpacketp;
145
146next:
147 /*
148 * Get next datagram off input queue and get IPX header
149 * in first mbuf.
150 */
151 s = splimp();
152 IF_DEQUEUE(&ipxintrq, m);
153 splx(s);
154 ipxintr_getpck++;
155 if (m == 0)
156 return;
157 if ((m->m_flags & M_EXT || m->m_len < sizeof (struct ipx)) &&
158 (m = m_pullup(m, sizeof (struct ipx))) == 0) {
159 ipxstat.ipxs_toosmall++;
160 goto next;
161 }
162
163 /*
164 * Give any raw listeners a crack at the packet
165 */
166 for (ipxp = ipxrawpcb.ipxp_next; ipxp != &ipxrawpcb; ipxp = ipxp->ipxp_next) {
167 struct mbuf *m1 = m_copy(m, 0, (int)M_COPYALL);
168 if (m1) ipx_input(m1, ipxp);
169 }
170
171 ipx = mtod(m, struct ipx *);
172 len = ntohs(ipx->ipx_len);
173 if (oddpacketp = len & 1) {
174 len++; /* If this packet is of odd length,
175 preserve garbage byte for checksum */
176 }
177
178 /*
179 * Check that the amount of data in the buffers
180 * is as at least much as the IPX header would have us expect.
181 * Trim mbufs if longer than we expect.
182 * Drop packet if shorter than we expect.
183 */
184 if (m->m_pkthdr.len < len) {
185 ipxstat.ipxs_tooshort++;
186 goto bad;
187 }
188 if (m->m_pkthdr.len > len) {
189 if (m->m_len == m->m_pkthdr.len) {
190 m->m_len = len;
191 m->m_pkthdr.len = len;
192 } else
193 m_adj(m, len - m->m_pkthdr.len);
194 }
195 if (ipxcksum && ((i = ipx->ipx_sum)!=0xffff)) {
196 ipx->ipx_sum = 0;
197 if (i != (ipx->ipx_sum = ipx_cksum(m, len))) {
198 ipxstat.ipxs_badsum++;
199 ipx->ipx_sum = i;
200 if (ipx_hosteqnh(ipx_thishost, ipx->ipx_dna.x_host))
201 error = IPX_ERR_BADSUM;
202 else
203 error = IPX_ERR_BADSUM_T;
204 ipx_error(m, error, 0);
205 goto next;
206 }
207 }
208 /*
209 * Is this a directed broadcast?
210 */
211 if (ipx_hosteqnh(ipx_broadhost,ipx->ipx_dna.x_host)) {
212 if ((!ipx_neteq(ipx->ipx_dna, ipx->ipx_sna)) &&
213 (!ipx_neteqnn(ipx->ipx_dna.x_net, ipx_broadnet)) &&
214 (!ipx_neteqnn(ipx->ipx_sna.x_net, ipx_zeronet)) &&
215 (!ipx_neteqnn(ipx->ipx_dna.x_net, ipx_zeronet)) ) {
216 /*
217 * Look to see if I need to eat this packet.
218 * Algorithm is to forward all young packets
219 * and prematurely age any packets which will
220 * by physically broadcasted.
221 * Any very old packets eaten without forwarding
222 * would die anyway.
223 *
224 * Suggestion of Bill Nesheim, Cornell U.
225 */
226 if (ipx->ipx_tc < IPX_MAXHOPS) {
227 ipx_forward(m);
228 goto next;
229 }
230 }
231 /*
232 * Is this our packet? If not, forward.
233 */
234 } else if (!ipx_hosteqnh(ipx_thishost,ipx->ipx_dna.x_host)) {
235 ipx_forward(m);
236 goto next;
237 }
238 /*
239 * Locate pcb for datagram.
240 */
241 ipxp = ipx_pcblookup(&ipx->ipx_sna, ipx->ipx_dna.x_port, IPX_WILDCARD);
242 /*
243 * Switch out to protocol's input routine.
244 */
245 ipxintr_swtch++;
246 if (ipxp) {
247 if (oddpacketp) {
248 m_adj(m, -1);
249 }
250 if ((ipxp->ipxp_flags & IPXP_ALL_PACKETS)==0)
251 switch (ipx->ipx_pt) {
252
253 case IPXPROTO_SPX:
254 spx_input(m, ipxp);
255 goto next;
256
257 case IPXPROTO_ERROR:
258 ipx_err_input(m);
259 goto next;
260 }
261 ipx_input(m, ipxp);
262 } else {
263 ipx_error(m, IPX_ERR_NOSOCK, 0);
264 }
265 goto next;
266
267bad:
268 m_freem(m);
269 goto next;
270}
271
272u_char ipxctlerrmap[PRC_NCMDS] = {
273 ECONNABORTED, ECONNABORTED, 0, 0,
274 0, 0, EHOSTDOWN, EHOSTUNREACH,
275 ENETUNREACH, EHOSTUNREACH, ECONNREFUSED, ECONNREFUSED,
276 EMSGSIZE, 0, 0, 0,
277 0, 0, 0, 0
278};
279
280void
281ipx_ctlinput(cmd, arg)
282 int cmd;
283 caddr_t arg;
284{
285 struct ipx_addr *ipx;
286 struct ipxpcb *ipxp;
287 struct ipx_errp *errp;
288 int type;
289
290 if (cmd < 0 || cmd > PRC_NCMDS)
291 return;
292 if (ipxctlerrmap[cmd] == 0)
293 return; /* XXX */
294 type = IPX_ERR_UNREACH_HOST;
295 errp = (struct ipx_errp *)arg;
296 switch (cmd) {
297 struct sockaddr_ipx *sipx;
298
299 case PRC_IFDOWN:
300 case PRC_HOSTDEAD:
301 case PRC_HOSTUNREACH:
302 sipx = (struct sockaddr_ipx *)arg;
303 if (sipx->sipx_family != AF_IPX)
304 return;
305 ipx = &sipx->sipx_addr;
306 break;
307
308 default:
309 ipx = &errp->ipx_err_ipx.ipx_dna;
310 type = errp->ipx_err_num;
311 type = ntohs((u_short)type);
312 break;
313 }
314 switch (type) {
315
316 case IPX_ERR_UNREACH_HOST:
317 ipx_pcbnotify(ipx, (int)ipxctlerrmap[cmd], ipx_abort, NULL);
318 break;
319
320 case IPX_ERR_NOSOCK:
321 ipxp = ipx_pcblookup(ipx, errp->ipx_err_ipx.ipx_sna.x_port,
322 IPX_WILDCARD);
323 if(ipxp && ipxdonosocks && ! ipx_nullhost(ipxp->ipxp_faddr))
324 (void) ipx_drop(ipxp, (int)ipxctlerrmap[cmd]);
325 }
326}
327
328/*
329 * Forward a packet. If some error occurs return the sender
330 * an error packet. Note we can't always generate a meaningful
331 * error message because the IPX errors don't have a large enough repetoire
332 * of codes and types.
333 */
334struct route ipx_droute;
335struct route ipx_sroute;
336
337void
338ipx_forward(m)
339struct mbuf *m;
340{
341 register struct ipx *ipx = mtod(m, struct ipx *);
342 register int error, type, code;
343 struct mbuf *mcopy = NULL;
344 int agedelta = 1;
345 int flags = IPX_FORWARDING;
346 int ok_there = 0;
347 int ok_back = 0;
348
349 if (ipxforwarding == 0) {
350 /* can't tell difference between net and host */
351 type = IPX_ERR_UNREACH_HOST, code = 0;
352 goto senderror;
353 }
354 ipx->ipx_tc++;
355 if (ipx->ipx_tc > IPX_MAXHOPS) {
356 type = IPX_ERR_TOO_OLD, code = 0;
357 goto senderror;
358 }
359 /*
360 * Save at most 42 bytes of the packet in case
361 * we need to generate an IPX error message to the src.
362 */
363 mcopy = m_copy(m, 0, imin((int)ntohs(ipx->ipx_len), 42));
364
365 if ((ok_there = ipx_do_route(&ipx->ipx_dna,&ipx_droute))==0) {
366 type = IPX_ERR_UNREACH_HOST, code = 0;
367 goto senderror;
368 }
369 /*
370 * Here we think about forwarding broadcast packets,
371 * so we try to insure that it doesn't go back out
372 * on the interface it came in on. Also, if we
373 * are going to physically broadcast this, let us
374 * age the packet so we can eat it safely the second time around.
375 */
376 if (ipx->ipx_dna.x_host.c_host[0] & 0x1) {
377 struct ipx_ifaddr *ia = ipx_iaonnetof(&ipx->ipx_dna);
378 struct ifnet *ifp;
379 if (ia) {
380 /* I'm gonna hafta eat this packet */
381 agedelta += IPX_MAXHOPS - ipx->ipx_tc;
382 ipx->ipx_tc = IPX_MAXHOPS;
383 }
384 if ((ok_back = ipx_do_route(&ipx->ipx_sna,&ipx_sroute))==0) {
385 /* error = ENETUNREACH; He'll never get it! */
386 m_freem(m);
387 goto cleanup;
388 }
389 if (ipx_droute.ro_rt &&
390 (ifp=ipx_droute.ro_rt->rt_ifp) &&
391 ipx_sroute.ro_rt &&
392 (ifp!=ipx_sroute.ro_rt->rt_ifp)) {
393 flags |= IPX_ALLOWBROADCAST;
394 } else {
395 type = IPX_ERR_UNREACH_HOST, code = 0;
396 goto senderror;
397 }
398 }
399 /* need to adjust checksum */
400 if (ipxcksum && ipx->ipx_sum != 0xffff) {
401 union bytes {
402 u_char c[4];
403 u_short s[2];
404 long l;
405 } x;
406 register int shift;
407 x.l = 0; x.c[0] = agedelta;
408 shift = (((((int)ntohs(ipx->ipx_len))+1)>>1)-2) & 0xf;
409 x.l = ipx->ipx_sum + (x.s[0] << shift);
410 x.l = x.s[0] + x.s[1];
411 x.l = x.s[0] + x.s[1];
412 if (x.l==0xffff) ipx->ipx_sum = 0; else ipx->ipx_sum = x.l;
413 } else
414 ipx->ipx_sum = 0xffff;
415
416 error = ipx_outputfl(m, &ipx_droute, flags);
417
418 if (ipxprintfs && !error) {
419 printf("forward: ");
420 ipx_printhost(&ipx->ipx_sna);
421 printf(" to ");
422 ipx_printhost(&ipx->ipx_dna);
423 printf(" hops %d\n", ipx->ipx_tc);
424 }
425
426 if (error && mcopy != NULL) {
427 ipx = mtod(mcopy, struct ipx *);
428 type = IPX_ERR_UNSPEC_T, code = 0;
429 switch (error) {
430
431 case ENETUNREACH:
432 case EHOSTDOWN:
433 case EHOSTUNREACH:
434 case ENETDOWN:
435 case EPERM:
436 type = IPX_ERR_UNREACH_HOST;
437 break;
438
439 case EMSGSIZE:
440 type = IPX_ERR_TOO_BIG;
441 code = 576; /* too hard to figure out mtu here */
442 break;
443
444 case ENOBUFS:
445 type = IPX_ERR_UNSPEC_T;
446 break;
447 }
448 mcopy = NULL;
449 senderror:
450 ipx_error(m, type, code);
451 }
452cleanup:
453 if (ok_there)
454 ipx_undo_route(&ipx_droute);
455 if (ok_back)
456 ipx_undo_route(&ipx_sroute);
457 if (mcopy != NULL)
458 m_freem(mcopy);
459}
460
461int
462ipx_do_route(src, ro)
463struct ipx_addr *src;
464struct route *ro;
465{
466 struct sockaddr_ipx *dst;
467
468 bzero((caddr_t)ro, sizeof (*ro));
469 dst = (struct sockaddr_ipx *)&ro->ro_dst;
470
471 dst->sipx_len = sizeof(*dst);
472 dst->sipx_family = AF_IPX;
473 dst->sipx_addr = *src;
474 dst->sipx_addr.x_port = 0;
475 rtalloc(ro);
476 if (ro->ro_rt == 0 || ro->ro_rt->rt_ifp == 0) {
477 return (0);
478 }
479 ro->ro_rt->rt_use++;
480 return (1);
481}
482
483void
484ipx_undo_route(ro)
485register struct route *ro;
486{
487 if (ro->ro_rt) {RTFREE(ro->ro_rt);}
488}
489
490void
491ipx_watch_output(m, ifp)
492struct mbuf *m;
493struct ifnet *ifp;
494{
495 register struct ipxpcb *ipxp;
496 register struct ifaddr *ifa;
497 /*
498 * Give any raw listeners a crack at the packet
499 */
500 for (ipxp = ipxrawpcb.ipxp_next; ipxp != &ipxrawpcb; ipxp = ipxp->ipxp_next) {
501 struct mbuf *m0 = m_copy(m, 0, (int)M_COPYALL);
502 if (m0) {
503 register struct ipx *ipx;
504
505 M_PREPEND(m0, sizeof (*ipx), M_DONTWAIT);
506 if (m0 == NULL)
507 continue;
508 ipx = mtod(m0, struct ipx *);
509 ipx->ipx_sna.x_net = ipx_zeronet;
510 ipx->ipx_sna.x_host = ipx_thishost;
511 if (ifp && (ifp->if_flags & IFF_POINTOPOINT))
512 for(ifa = ifp->if_addrlist; ifa;
513 ifa = ifa->ifa_next) {
514 if (ifa->ifa_addr->sa_family==AF_IPX) {
515 ipx->ipx_sna = IA_SIPX(ifa)->sipx_addr;
516 break;
517 }
518 }
519 ipx->ipx_len = ntohl(m0->m_pkthdr.len);
520 ipx_input(m0, ipxp);
521 }
522 }
523}
35 */
36
37#include <sys/param.h>
38#include <sys/systm.h>
39#include <sys/malloc.h>
40#include <sys/mbuf.h>
41#include <sys/domain.h>
42#include <sys/protosw.h>
43#include <sys/socket.h>
44#include <sys/socketvar.h>
45#include <sys/errno.h>
46#include <sys/time.h>
47#include <sys/kernel.h>
48
49#include <net/if.h>
50#include <net/route.h>
51#include <net/netisr.h>
52#include <net/raw_cb.h>
53
54#include <netipx/ipx.h>
55#include <netipx/spx.h>
56#include <netipx/ipx_if.h>
57#include <netipx/ipx_pcb.h>
58#include <netipx/ipx_var.h>
59#include <netipx/ipx_error.h>
60
61#ifndef IPXFORWARDING
62#ifdef GATEWAY
63#define IPXFORWARDING 1 /* forward IPX packets not for us */
64#else
65#define IPXFORWARDING 0 /* don't forward IPX packets not for us */
66#endif
67#endif
68#ifndef IPXPRINTFS
69#define IPXPRINTFS 1 /* printing forwarding information */
70#endif
71
72#ifndef IPXCKSUM
73#define IPXCKSUM 0 /* perform IPX checksum */
74#endif
75
76#ifndef IXDONOSOCKS
77#define IPXDONOSOCKS 0 /* return no socket errors */
78#endif
79
80int ipxcksum = IPXCKSUM;
81int ipxprintfs = IPXPRINTFS;
82int ipxdonosocks = IPXDONOSOCKS;
83int ipxforwarding = IPXFORWARDING;
84
85union ipx_host ipx_thishost;
86union ipx_net ipx_zeronet;
87union ipx_host ipx_zerohost;
88
89union ipx_net ipx_broadnet;
90union ipx_host ipx_broadhost;
91
92struct ipxstat ipxstat;
93struct sockaddr_ipx ipx_netmask, ipx_hostmask;
94
95int ipxintr_getpck = 0;
96int ipxintr_swtch = 0;
97
98static u_short allones[] = {-1, -1, -1};
99
100struct ipxpcb ipxpcb;
101struct ipxpcb ipxrawpcb;
102
103struct ifqueue ipxintrq;
104int ipxqmaxlen = IFQ_MAXLEN;
105
106long ipx_pexseq;
107
108NETISR_SET(NETISR_IPX, ipxintr);
109
110/*
111 * IPX initialization.
112 */
113
114void
115ipx_init()
116{
117 ipx_broadnet = * (union ipx_net *) allones;
118 ipx_broadhost = * (union ipx_host *) allones;
119
120 ipx_pexseq = time.tv_usec;
121 ipxintrq.ifq_maxlen = ipxqmaxlen;
122 ipxpcb.ipxp_next = ipxpcb.ipxp_prev = &ipxpcb;
123 ipxrawpcb.ipxp_next = ipxrawpcb.ipxp_prev = &ipxrawpcb;
124
125 ipx_netmask.sipx_len = 6;
126 ipx_netmask.sipx_addr.x_net = ipx_broadnet;
127
128 ipx_hostmask.sipx_len = 12;
129 ipx_hostmask.sipx_addr.x_net = ipx_broadnet;
130 ipx_hostmask.sipx_addr.x_host = ipx_broadhost;
131}
132
133/*
134 * IPX input routine. Pass to next level.
135 */
136void
137ipxintr()
138{
139 register struct ipx *ipx;
140 register struct mbuf *m;
141 register struct ipxpcb *ipxp;
142 register int i;
143 int len, s, error;
144 char oddpacketp;
145
146next:
147 /*
148 * Get next datagram off input queue and get IPX header
149 * in first mbuf.
150 */
151 s = splimp();
152 IF_DEQUEUE(&ipxintrq, m);
153 splx(s);
154 ipxintr_getpck++;
155 if (m == 0)
156 return;
157 if ((m->m_flags & M_EXT || m->m_len < sizeof (struct ipx)) &&
158 (m = m_pullup(m, sizeof (struct ipx))) == 0) {
159 ipxstat.ipxs_toosmall++;
160 goto next;
161 }
162
163 /*
164 * Give any raw listeners a crack at the packet
165 */
166 for (ipxp = ipxrawpcb.ipxp_next; ipxp != &ipxrawpcb; ipxp = ipxp->ipxp_next) {
167 struct mbuf *m1 = m_copy(m, 0, (int)M_COPYALL);
168 if (m1) ipx_input(m1, ipxp);
169 }
170
171 ipx = mtod(m, struct ipx *);
172 len = ntohs(ipx->ipx_len);
173 if (oddpacketp = len & 1) {
174 len++; /* If this packet is of odd length,
175 preserve garbage byte for checksum */
176 }
177
178 /*
179 * Check that the amount of data in the buffers
180 * is as at least much as the IPX header would have us expect.
181 * Trim mbufs if longer than we expect.
182 * Drop packet if shorter than we expect.
183 */
184 if (m->m_pkthdr.len < len) {
185 ipxstat.ipxs_tooshort++;
186 goto bad;
187 }
188 if (m->m_pkthdr.len > len) {
189 if (m->m_len == m->m_pkthdr.len) {
190 m->m_len = len;
191 m->m_pkthdr.len = len;
192 } else
193 m_adj(m, len - m->m_pkthdr.len);
194 }
195 if (ipxcksum && ((i = ipx->ipx_sum)!=0xffff)) {
196 ipx->ipx_sum = 0;
197 if (i != (ipx->ipx_sum = ipx_cksum(m, len))) {
198 ipxstat.ipxs_badsum++;
199 ipx->ipx_sum = i;
200 if (ipx_hosteqnh(ipx_thishost, ipx->ipx_dna.x_host))
201 error = IPX_ERR_BADSUM;
202 else
203 error = IPX_ERR_BADSUM_T;
204 ipx_error(m, error, 0);
205 goto next;
206 }
207 }
208 /*
209 * Is this a directed broadcast?
210 */
211 if (ipx_hosteqnh(ipx_broadhost,ipx->ipx_dna.x_host)) {
212 if ((!ipx_neteq(ipx->ipx_dna, ipx->ipx_sna)) &&
213 (!ipx_neteqnn(ipx->ipx_dna.x_net, ipx_broadnet)) &&
214 (!ipx_neteqnn(ipx->ipx_sna.x_net, ipx_zeronet)) &&
215 (!ipx_neteqnn(ipx->ipx_dna.x_net, ipx_zeronet)) ) {
216 /*
217 * Look to see if I need to eat this packet.
218 * Algorithm is to forward all young packets
219 * and prematurely age any packets which will
220 * by physically broadcasted.
221 * Any very old packets eaten without forwarding
222 * would die anyway.
223 *
224 * Suggestion of Bill Nesheim, Cornell U.
225 */
226 if (ipx->ipx_tc < IPX_MAXHOPS) {
227 ipx_forward(m);
228 goto next;
229 }
230 }
231 /*
232 * Is this our packet? If not, forward.
233 */
234 } else if (!ipx_hosteqnh(ipx_thishost,ipx->ipx_dna.x_host)) {
235 ipx_forward(m);
236 goto next;
237 }
238 /*
239 * Locate pcb for datagram.
240 */
241 ipxp = ipx_pcblookup(&ipx->ipx_sna, ipx->ipx_dna.x_port, IPX_WILDCARD);
242 /*
243 * Switch out to protocol's input routine.
244 */
245 ipxintr_swtch++;
246 if (ipxp) {
247 if (oddpacketp) {
248 m_adj(m, -1);
249 }
250 if ((ipxp->ipxp_flags & IPXP_ALL_PACKETS)==0)
251 switch (ipx->ipx_pt) {
252
253 case IPXPROTO_SPX:
254 spx_input(m, ipxp);
255 goto next;
256
257 case IPXPROTO_ERROR:
258 ipx_err_input(m);
259 goto next;
260 }
261 ipx_input(m, ipxp);
262 } else {
263 ipx_error(m, IPX_ERR_NOSOCK, 0);
264 }
265 goto next;
266
267bad:
268 m_freem(m);
269 goto next;
270}
271
272u_char ipxctlerrmap[PRC_NCMDS] = {
273 ECONNABORTED, ECONNABORTED, 0, 0,
274 0, 0, EHOSTDOWN, EHOSTUNREACH,
275 ENETUNREACH, EHOSTUNREACH, ECONNREFUSED, ECONNREFUSED,
276 EMSGSIZE, 0, 0, 0,
277 0, 0, 0, 0
278};
279
280void
281ipx_ctlinput(cmd, arg)
282 int cmd;
283 caddr_t arg;
284{
285 struct ipx_addr *ipx;
286 struct ipxpcb *ipxp;
287 struct ipx_errp *errp;
288 int type;
289
290 if (cmd < 0 || cmd > PRC_NCMDS)
291 return;
292 if (ipxctlerrmap[cmd] == 0)
293 return; /* XXX */
294 type = IPX_ERR_UNREACH_HOST;
295 errp = (struct ipx_errp *)arg;
296 switch (cmd) {
297 struct sockaddr_ipx *sipx;
298
299 case PRC_IFDOWN:
300 case PRC_HOSTDEAD:
301 case PRC_HOSTUNREACH:
302 sipx = (struct sockaddr_ipx *)arg;
303 if (sipx->sipx_family != AF_IPX)
304 return;
305 ipx = &sipx->sipx_addr;
306 break;
307
308 default:
309 ipx = &errp->ipx_err_ipx.ipx_dna;
310 type = errp->ipx_err_num;
311 type = ntohs((u_short)type);
312 break;
313 }
314 switch (type) {
315
316 case IPX_ERR_UNREACH_HOST:
317 ipx_pcbnotify(ipx, (int)ipxctlerrmap[cmd], ipx_abort, NULL);
318 break;
319
320 case IPX_ERR_NOSOCK:
321 ipxp = ipx_pcblookup(ipx, errp->ipx_err_ipx.ipx_sna.x_port,
322 IPX_WILDCARD);
323 if(ipxp && ipxdonosocks && ! ipx_nullhost(ipxp->ipxp_faddr))
324 (void) ipx_drop(ipxp, (int)ipxctlerrmap[cmd]);
325 }
326}
327
328/*
329 * Forward a packet. If some error occurs return the sender
330 * an error packet. Note we can't always generate a meaningful
331 * error message because the IPX errors don't have a large enough repetoire
332 * of codes and types.
333 */
334struct route ipx_droute;
335struct route ipx_sroute;
336
337void
338ipx_forward(m)
339struct mbuf *m;
340{
341 register struct ipx *ipx = mtod(m, struct ipx *);
342 register int error, type, code;
343 struct mbuf *mcopy = NULL;
344 int agedelta = 1;
345 int flags = IPX_FORWARDING;
346 int ok_there = 0;
347 int ok_back = 0;
348
349 if (ipxforwarding == 0) {
350 /* can't tell difference between net and host */
351 type = IPX_ERR_UNREACH_HOST, code = 0;
352 goto senderror;
353 }
354 ipx->ipx_tc++;
355 if (ipx->ipx_tc > IPX_MAXHOPS) {
356 type = IPX_ERR_TOO_OLD, code = 0;
357 goto senderror;
358 }
359 /*
360 * Save at most 42 bytes of the packet in case
361 * we need to generate an IPX error message to the src.
362 */
363 mcopy = m_copy(m, 0, imin((int)ntohs(ipx->ipx_len), 42));
364
365 if ((ok_there = ipx_do_route(&ipx->ipx_dna,&ipx_droute))==0) {
366 type = IPX_ERR_UNREACH_HOST, code = 0;
367 goto senderror;
368 }
369 /*
370 * Here we think about forwarding broadcast packets,
371 * so we try to insure that it doesn't go back out
372 * on the interface it came in on. Also, if we
373 * are going to physically broadcast this, let us
374 * age the packet so we can eat it safely the second time around.
375 */
376 if (ipx->ipx_dna.x_host.c_host[0] & 0x1) {
377 struct ipx_ifaddr *ia = ipx_iaonnetof(&ipx->ipx_dna);
378 struct ifnet *ifp;
379 if (ia) {
380 /* I'm gonna hafta eat this packet */
381 agedelta += IPX_MAXHOPS - ipx->ipx_tc;
382 ipx->ipx_tc = IPX_MAXHOPS;
383 }
384 if ((ok_back = ipx_do_route(&ipx->ipx_sna,&ipx_sroute))==0) {
385 /* error = ENETUNREACH; He'll never get it! */
386 m_freem(m);
387 goto cleanup;
388 }
389 if (ipx_droute.ro_rt &&
390 (ifp=ipx_droute.ro_rt->rt_ifp) &&
391 ipx_sroute.ro_rt &&
392 (ifp!=ipx_sroute.ro_rt->rt_ifp)) {
393 flags |= IPX_ALLOWBROADCAST;
394 } else {
395 type = IPX_ERR_UNREACH_HOST, code = 0;
396 goto senderror;
397 }
398 }
399 /* need to adjust checksum */
400 if (ipxcksum && ipx->ipx_sum != 0xffff) {
401 union bytes {
402 u_char c[4];
403 u_short s[2];
404 long l;
405 } x;
406 register int shift;
407 x.l = 0; x.c[0] = agedelta;
408 shift = (((((int)ntohs(ipx->ipx_len))+1)>>1)-2) & 0xf;
409 x.l = ipx->ipx_sum + (x.s[0] << shift);
410 x.l = x.s[0] + x.s[1];
411 x.l = x.s[0] + x.s[1];
412 if (x.l==0xffff) ipx->ipx_sum = 0; else ipx->ipx_sum = x.l;
413 } else
414 ipx->ipx_sum = 0xffff;
415
416 error = ipx_outputfl(m, &ipx_droute, flags);
417
418 if (ipxprintfs && !error) {
419 printf("forward: ");
420 ipx_printhost(&ipx->ipx_sna);
421 printf(" to ");
422 ipx_printhost(&ipx->ipx_dna);
423 printf(" hops %d\n", ipx->ipx_tc);
424 }
425
426 if (error && mcopy != NULL) {
427 ipx = mtod(mcopy, struct ipx *);
428 type = IPX_ERR_UNSPEC_T, code = 0;
429 switch (error) {
430
431 case ENETUNREACH:
432 case EHOSTDOWN:
433 case EHOSTUNREACH:
434 case ENETDOWN:
435 case EPERM:
436 type = IPX_ERR_UNREACH_HOST;
437 break;
438
439 case EMSGSIZE:
440 type = IPX_ERR_TOO_BIG;
441 code = 576; /* too hard to figure out mtu here */
442 break;
443
444 case ENOBUFS:
445 type = IPX_ERR_UNSPEC_T;
446 break;
447 }
448 mcopy = NULL;
449 senderror:
450 ipx_error(m, type, code);
451 }
452cleanup:
453 if (ok_there)
454 ipx_undo_route(&ipx_droute);
455 if (ok_back)
456 ipx_undo_route(&ipx_sroute);
457 if (mcopy != NULL)
458 m_freem(mcopy);
459}
460
461int
462ipx_do_route(src, ro)
463struct ipx_addr *src;
464struct route *ro;
465{
466 struct sockaddr_ipx *dst;
467
468 bzero((caddr_t)ro, sizeof (*ro));
469 dst = (struct sockaddr_ipx *)&ro->ro_dst;
470
471 dst->sipx_len = sizeof(*dst);
472 dst->sipx_family = AF_IPX;
473 dst->sipx_addr = *src;
474 dst->sipx_addr.x_port = 0;
475 rtalloc(ro);
476 if (ro->ro_rt == 0 || ro->ro_rt->rt_ifp == 0) {
477 return (0);
478 }
479 ro->ro_rt->rt_use++;
480 return (1);
481}
482
483void
484ipx_undo_route(ro)
485register struct route *ro;
486{
487 if (ro->ro_rt) {RTFREE(ro->ro_rt);}
488}
489
490void
491ipx_watch_output(m, ifp)
492struct mbuf *m;
493struct ifnet *ifp;
494{
495 register struct ipxpcb *ipxp;
496 register struct ifaddr *ifa;
497 /*
498 * Give any raw listeners a crack at the packet
499 */
500 for (ipxp = ipxrawpcb.ipxp_next; ipxp != &ipxrawpcb; ipxp = ipxp->ipxp_next) {
501 struct mbuf *m0 = m_copy(m, 0, (int)M_COPYALL);
502 if (m0) {
503 register struct ipx *ipx;
504
505 M_PREPEND(m0, sizeof (*ipx), M_DONTWAIT);
506 if (m0 == NULL)
507 continue;
508 ipx = mtod(m0, struct ipx *);
509 ipx->ipx_sna.x_net = ipx_zeronet;
510 ipx->ipx_sna.x_host = ipx_thishost;
511 if (ifp && (ifp->if_flags & IFF_POINTOPOINT))
512 for(ifa = ifp->if_addrlist; ifa;
513 ifa = ifa->ifa_next) {
514 if (ifa->ifa_addr->sa_family==AF_IPX) {
515 ipx->ipx_sna = IA_SIPX(ifa)->sipx_addr;
516 break;
517 }
518 }
519 ipx->ipx_len = ntohl(m0->m_pkthdr.len);
520 ipx_input(m0, ipxp);
521 }
522 }
523}