Deleted Added
full compact
ipx_usrreq.c (11819) ipx_usrreq.c (11947)
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_usrreq.c
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/protosw.h>
42#include <sys/socket.h>
43#include <sys/socketvar.h>
44#include <sys/errno.h>
45#include <sys/stat.h>
46
47#include <net/if.h>
48#include <net/route.h>
49
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_usrreq.c
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/protosw.h>
42#include <sys/socket.h>
43#include <sys/socketvar.h>
44#include <sys/errno.h>
45#include <sys/stat.h>
46
47#include <net/if.h>
48#include <net/route.h>
49
50#include <netinet/in.h>
51
50#include <netipx/ipx.h>
51#include <netipx/ipx_pcb.h>
52#include <netipx/ipx_if.h>
53#include <netipx/ipx_var.h>
54#include <netipx/ipx_error.h>
52#include <netipx/ipx.h>
53#include <netipx/ipx_pcb.h>
54#include <netipx/ipx_if.h>
55#include <netipx/ipx_var.h>
56#include <netipx/ipx_error.h>
57#include <netipx/ipx_ip.h>
55
56/*
57 * IPX protocol implementation.
58 */
59
60int noipxRoute;
61
62/*
63 * This may also be called for raw listeners.
64 */
65void
66ipx_input(m, ipxp)
67 struct mbuf *m;
68 register struct ipxpcb *ipxp;
69{
70 register struct ipx *ipx = mtod(m, struct ipx *);
71 struct ifnet *ifp = m->m_pkthdr.rcvif;
72 struct sockaddr_ipx ipx_ipx = { sizeof(ipx_ipx), AF_IPX };
73
74 if (ipxp==0)
75 panic("No ipxpcb");
76 /*
77 * Construct sockaddr format source address.
78 * Stuff source address and datagram in user buffer.
79 */
80 ipx_ipx.sipx_addr = ipx->ipx_sna;
81 if (ipx_neteqnn(ipx->ipx_sna.x_net, ipx_zeronet) && ifp) {
82 register struct ifaddr *ifa;
83
84 for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) {
85 if (ifa->ifa_addr->sa_family == AF_IPX) {
86 ipx_ipx.sipx_addr.x_net =
87 IA_SIPX(ifa)->sipx_addr.x_net;
88 break;
89 }
90 }
91 }
92 ipxp->ipxp_rpt = ipx->ipx_pt;
93 if ( ! (ipxp->ipxp_flags & IPXP_RAWIN) ) {
94 m->m_len -= sizeof (struct ipx);
95 m->m_pkthdr.len -= sizeof (struct ipx);
96 m->m_data += sizeof (struct ipx);
97 }
98 if (sbappendaddr(&ipxp->ipxp_socket->so_rcv, (struct sockaddr *)&ipx_ipx,
99 m, (struct mbuf *)0) == 0)
100 goto bad;
101 sorwakeup(ipxp->ipxp_socket);
102 return;
103bad:
104 m_freem(m);
105}
106
107void
108ipx_abort(ipxp)
109 struct ipxpcb *ipxp;
110{
111 struct socket *so = ipxp->ipxp_socket;
112
113 ipx_pcbdisconnect(ipxp);
114 soisdisconnected(so);
115}
116/*
117 * Drop connection, reporting
118 * the specified error.
119 */
120/* struct ipxpcb * DELETE THIS */
121void
122ipx_drop(ipxp, errno)
123 register struct ipxpcb *ipxp;
124 int errno;
125{
126 struct socket *so = ipxp->ipxp_socket;
127
128 /*
129 * someday, in the xerox world
130 * we will generate error protocol packets
131 * announcing that the socket has gone away.
132 */
133 /*if (TCPS_HAVERCVDSYN(tp->t_state)) {
134 tp->t_state = TCPS_CLOSED;
135 (void) tcp_output(tp);
136 }*/
137 so->so_error = errno;
138 ipx_pcbdisconnect(ipxp);
139 soisdisconnected(so);
140}
141
142int
143ipx_output(ipxp, m0)
144 struct ipxpcb *ipxp;
145 struct mbuf *m0;
146{
147 register struct mbuf *m;
148 register struct ipx *ipx;
149 register struct socket *so;
150 register int len = 0;
151 register struct route *ro;
152 struct mbuf *mprev = NULL;
153
154 /*
155 * Calculate data length.
156 */
157 for (m = m0; m; m = m->m_next) {
158 mprev = m;
159 len += m->m_len;
160 }
161 /*
162 * Make sure packet is actually of even length.
163 */
164
165 if (len & 1) {
166 m = mprev;
167 if ((m->m_flags & M_EXT) == 0 &&
168 (m->m_len + m->m_data < &m->m_dat[MLEN])) {
169 m->m_len++;
170 } else {
171 struct mbuf *m1 = m_get(M_DONTWAIT, MT_DATA);
172
173 if (m1 == 0) {
174 m_freem(m0);
175 return (ENOBUFS);
176 }
177 m1->m_len = 1;
178 * mtod(m1, char *) = 0;
179 m->m_next = m1;
180 }
181 m0->m_pkthdr.len++;
182 }
183
184 /*
185 * Fill in mbuf with extended IPX header
186 * and addresses and length put into network format.
187 */
188 m = m0;
189 if (ipxp->ipxp_flags & IPXP_RAWOUT) {
190 ipx = mtod(m, struct ipx *);
191 } else {
192 M_PREPEND(m, sizeof (struct ipx), M_DONTWAIT);
193 if (m == 0)
194 return (ENOBUFS);
195 ipx = mtod(m, struct ipx *);
196 ipx->ipx_tc = 0;
197 ipx->ipx_pt = ipxp->ipxp_dpt;
198 ipx->ipx_sna = ipxp->ipxp_laddr;
199 ipx->ipx_dna = ipxp->ipxp_faddr;
200 len += sizeof (struct ipx);
201 }
202
203 ipx->ipx_len = htons((u_short)len);
204
205 if (ipxcksum) {
206 ipx->ipx_sum = 0;
207 len = ((len - 1) | 1) + 1;
208 ipx->ipx_sum = ipx_cksum(m, len);
209 } else
210 ipx->ipx_sum = 0xffff;
211
212 /*
213 * Output datagram.
214 */
215 so = ipxp->ipxp_socket;
216 if (so->so_options & SO_DONTROUTE)
217 return (ipx_outputfl(m, (struct route *)0,
218 (so->so_options & SO_BROADCAST) | IPX_ROUTETOIF));
219 /*
220 * Use cached route for previous datagram if
221 * possible. If the previous net was the same
222 * and the interface was a broadcast medium, or
223 * if the previous destination was identical,
224 * then we are ok.
225 *
226 * NB: We don't handle broadcasts because that
227 * would require 3 subroutine calls.
228 */
229 ro = &ipxp->ipxp_route;
230#ifdef ancient_history
231 /*
232 * I think that this will all be handled in ipx_pcbconnect!
233 */
234 if (ro->ro_rt) {
235 if(ipx_neteq(ipxp->ipxp_lastdst, ipx->ipx_dna)) {
236 /*
237 * This assumes we have no GH type routes
238 */
239 if (ro->ro_rt->rt_flags & RTF_HOST) {
240 if (!ipx_hosteq(ipxp->ipxp_lastdst, ipx->ipx_dna))
241 goto re_route;
242
243 }
244 if ((ro->ro_rt->rt_flags & RTF_GATEWAY) == 0) {
245 register struct ipx_addr *dst =
246 &satoipx_addr(ro->ro_dst);
247 dst->x_host = ipx->ipx_dna.x_host;
248 }
249 /*
250 * Otherwise, we go through the same gateway
251 * and dst is already set up.
252 */
253 } else {
254 re_route:
255 RTFREE(ro->ro_rt);
256 ro->ro_rt = (struct rtentry *)0;
257 }
258 }
259 ipxp->ipxp_lastdst = ipx->ipx_dna;
260#endif /* ancient_history */
261 if (noipxRoute) ro = 0;
262 return (ipx_outputfl(m, ro, so->so_options & SO_BROADCAST));
263}
264/* ARGSUSED */
265int
266ipx_ctloutput(req, so, level, name, value)
267 int req, level;
268 struct socket *so;
269 int name;
270 struct mbuf **value;
271{
272 register struct mbuf *m;
273 struct ipxpcb *ipxp = sotoipxpcb(so);
274 int mask, error = 0;
275 /*extern long ipx_pexseq;*/ /*XXX*//*JRE*/
276
277 if (ipxp == NULL)
278 return (EINVAL);
279
280 switch (req) {
281
282 case PRCO_GETOPT:
283 if (value==NULL)
284 return (EINVAL);
285 m = m_get(M_DONTWAIT, MT_DATA);
286 if (m==NULL)
287 return (ENOBUFS);
288 switch (name) {
289
290 case SO_ALL_PACKETS:
291 mask = IPXP_ALL_PACKETS;
292 goto get_flags;
293
294 case SO_HEADERS_ON_INPUT:
295 mask = IPXP_RAWIN;
296 goto get_flags;
297
298 case SO_HEADERS_ON_OUTPUT:
299 mask = IPXP_RAWOUT;
300 get_flags:
301 m->m_len = sizeof(short);
302 *mtod(m, short *) = ipxp->ipxp_flags & mask;
303 break;
304
305 case SO_DEFAULT_HEADERS:
306 m->m_len = sizeof(struct ipx);
307 {
308 register struct ipx *ipx = mtod(m, struct ipx *);
309 ipx->ipx_len = 0;
310 ipx->ipx_sum = 0;
311 ipx->ipx_tc = 0;
312 ipx->ipx_pt = ipxp->ipxp_dpt;
313 ipx->ipx_dna = ipxp->ipxp_faddr;
314 ipx->ipx_sna = ipxp->ipxp_laddr;
315 }
316 break;
317
318 case SO_SEQNO:
319 m->m_len = sizeof(long);
320 *mtod(m, long *) = ipx_pexseq++;
321 break;
322
323 default:
324 error = EINVAL;
325 }
326 *value = m;
327 break;
328
329 case PRCO_SETOPT:
330 switch (name) {
331 int *ok;
332
333 case SO_ALL_PACKETS:
334 mask = IPXP_ALL_PACKETS;
335 goto set_head;
336
337 case SO_HEADERS_ON_INPUT:
338 mask = IPXP_RAWIN;
339 goto set_head;
340
341 case SO_HEADERS_ON_OUTPUT:
342 mask = IPXP_RAWOUT;
343 set_head:
344 if (value && *value) {
345 ok = mtod(*value, int *);
346 if (*ok)
347 ipxp->ipxp_flags |= mask;
348 else
349 ipxp->ipxp_flags &= ~mask;
350 } else error = EINVAL;
351 break;
352
353 case SO_DEFAULT_HEADERS:
354 {
355 register struct ipx *ipx
356 = mtod(*value, struct ipx *);
357 ipxp->ipxp_dpt = ipx->ipx_pt;
358 }
359 break;
360#ifdef IPXIP
361 case SO_IPXIP_ROUTE:
362 error = ipxip_route(*value);
363 break;
364#endif /* IPXIP */
365#ifdef IPXTUNNEL
366 case SO_IPXTUNNEL_ROUTE
367 error = ipxtun_route(*value);
368 break;
369#endif
370 default:
371 error = EINVAL;
372 }
373 if (value && *value)
374 m_freem(*value);
375 break;
376 }
377 return (error);
378}
379
380/*ARGSUSED*/
381int
382ipx_usrreq(so, req, m, nam, control)
383 struct socket *so;
384 int req;
385 struct mbuf *m, *nam, *control;
386{
387 struct ipxpcb *ipxp = sotoipxpcb(so);
388 int error = 0;
389
390 if (req == PRU_CONTROL)
391 return (ipx_control(so, (int)m, (caddr_t)nam,
392 (struct ifnet *)control));
393 if (control && control->m_len) {
394 error = EINVAL;
395 goto release;
396 }
397 if (ipxp == NULL && req != PRU_ATTACH) {
398 error = EINVAL;
399 goto release;
400 }
401 switch (req) {
402
403 case PRU_ATTACH:
404 if (ipxp != NULL) {
405 error = EINVAL;
406 break;
407 }
408 error = ipx_pcballoc(so, &ipxpcb);
409 if (error)
410 break;
411 error = soreserve(so, (u_long) 2048, (u_long) 2048);
412 if (error)
413 break;
414 break;
415
416 case PRU_DETACH:
417 if (ipxp == NULL) {
418 error = ENOTCONN;
419 break;
420 }
421 ipx_pcbdetach(ipxp);
422 break;
423
424 case PRU_BIND:
425 error = ipx_pcbbind(ipxp, nam);
426 break;
427
428 case PRU_LISTEN:
429 error = EOPNOTSUPP;
430 break;
431
432 case PRU_CONNECT:
433 if (!ipx_nullhost(ipxp->ipxp_faddr)) {
434 error = EISCONN;
435 break;
436 }
437 error = ipx_pcbconnect(ipxp, nam);
438 if (error == 0)
439 soisconnected(so);
440 break;
441
442 case PRU_CONNECT2:
443 error = EOPNOTSUPP;
444 break;
445
446 case PRU_ACCEPT:
447 error = EOPNOTSUPP;
448 break;
449
450 case PRU_DISCONNECT:
451 if (ipx_nullhost(ipxp->ipxp_faddr)) {
452 error = ENOTCONN;
453 break;
454 }
455 ipx_pcbdisconnect(ipxp);
456 soisdisconnected(so);
457 break;
458
459 case PRU_SHUTDOWN:
460 socantsendmore(so);
461 break;
462
463 case PRU_SEND:
464 {
465 struct ipx_addr laddr;
466 int s = 0;
467
468 if (nam) {
469 laddr = ipxp->ipxp_laddr;
470 if (!ipx_nullhost(ipxp->ipxp_faddr)) {
471 error = EISCONN;
472 break;
473 }
474 /*
475 * Must block input while temporarily connected.
476 */
477 s = splnet();
478 error = ipx_pcbconnect(ipxp, nam);
479 if (error) {
480 splx(s);
481 break;
482 }
483 } else {
484 if (ipx_nullhost(ipxp->ipxp_faddr)) {
485 error = ENOTCONN;
486 break;
487 }
488 }
489 error = ipx_output(ipxp, m);
490 m = NULL;
491 if (nam) {
492 ipx_pcbdisconnect(ipxp);
493 splx(s);
494 ipxp->ipxp_laddr.x_host = laddr.x_host;
495 ipxp->ipxp_laddr.x_port = laddr.x_port;
496 }
497 }
498 break;
499
500 case PRU_ABORT:
501 ipx_pcbdetach(ipxp);
502 sofree(so);
503 soisdisconnected(so);
504 break;
505
506 case PRU_SOCKADDR:
507 ipx_setsockaddr(ipxp, nam);
508 break;
509
510 case PRU_PEERADDR:
511 ipx_setpeeraddr(ipxp, nam);
512 break;
513
514 case PRU_SENSE:
515 /*
516 * stat: don't bother with a blocksize.
517 */
518 return (0);
519
520 case PRU_SENDOOB:
521 case PRU_FASTTIMO:
522 case PRU_SLOWTIMO:
523 case PRU_PROTORCV:
524 case PRU_PROTOSEND:
525 error = EOPNOTSUPP;
526 break;
527
528 case PRU_CONTROL:
529 case PRU_RCVD:
530 case PRU_RCVOOB:
531 return (EOPNOTSUPP); /* do not free mbuf's */
532
533 default:
534 panic("ipx_usrreq");
535 }
536release:
537 if (control != NULL)
538 m_freem(control);
539 if (m != NULL)
540 m_freem(m);
541 return (error);
542}
543/*ARGSUSED*/
544int
545ipx_raw_usrreq(so, req, m, nam, control)
546 struct socket *so;
547 int req;
548 struct mbuf *m, *nam, *control;
549{
550 int error = 0;
551 struct ipxpcb *ipxp = sotoipxpcb(so);
552 /*extern struct ipxpcb ipxrawpcb;*//*XXX*//*JRE*/
553
554 switch (req) {
555
556 case PRU_ATTACH:
557
558 if (!(so->so_state & SS_PRIV) || (ipxp != NULL)) {
559 error = EINVAL;
560 break;
561 }
562 error = ipx_pcballoc(so, &ipxrawpcb);
563 if (error)
564 break;
565 error = soreserve(so, (u_long) 2048, (u_long) 2048);
566 if (error)
567 break;
568 ipxp = sotoipxpcb(so);
569 ipxp->ipxp_faddr.x_host = ipx_broadhost;
570 ipxp->ipxp_flags = IPXP_RAWIN | IPXP_RAWOUT;
571 break;
572 default:
573 error = ipx_usrreq(so, req, m, nam, control);
574 }
575 return (error);
576}
577
58
59/*
60 * IPX protocol implementation.
61 */
62
63int noipxRoute;
64
65/*
66 * This may also be called for raw listeners.
67 */
68void
69ipx_input(m, ipxp)
70 struct mbuf *m;
71 register struct ipxpcb *ipxp;
72{
73 register struct ipx *ipx = mtod(m, struct ipx *);
74 struct ifnet *ifp = m->m_pkthdr.rcvif;
75 struct sockaddr_ipx ipx_ipx = { sizeof(ipx_ipx), AF_IPX };
76
77 if (ipxp==0)
78 panic("No ipxpcb");
79 /*
80 * Construct sockaddr format source address.
81 * Stuff source address and datagram in user buffer.
82 */
83 ipx_ipx.sipx_addr = ipx->ipx_sna;
84 if (ipx_neteqnn(ipx->ipx_sna.x_net, ipx_zeronet) && ifp) {
85 register struct ifaddr *ifa;
86
87 for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) {
88 if (ifa->ifa_addr->sa_family == AF_IPX) {
89 ipx_ipx.sipx_addr.x_net =
90 IA_SIPX(ifa)->sipx_addr.x_net;
91 break;
92 }
93 }
94 }
95 ipxp->ipxp_rpt = ipx->ipx_pt;
96 if ( ! (ipxp->ipxp_flags & IPXP_RAWIN) ) {
97 m->m_len -= sizeof (struct ipx);
98 m->m_pkthdr.len -= sizeof (struct ipx);
99 m->m_data += sizeof (struct ipx);
100 }
101 if (sbappendaddr(&ipxp->ipxp_socket->so_rcv, (struct sockaddr *)&ipx_ipx,
102 m, (struct mbuf *)0) == 0)
103 goto bad;
104 sorwakeup(ipxp->ipxp_socket);
105 return;
106bad:
107 m_freem(m);
108}
109
110void
111ipx_abort(ipxp)
112 struct ipxpcb *ipxp;
113{
114 struct socket *so = ipxp->ipxp_socket;
115
116 ipx_pcbdisconnect(ipxp);
117 soisdisconnected(so);
118}
119/*
120 * Drop connection, reporting
121 * the specified error.
122 */
123/* struct ipxpcb * DELETE THIS */
124void
125ipx_drop(ipxp, errno)
126 register struct ipxpcb *ipxp;
127 int errno;
128{
129 struct socket *so = ipxp->ipxp_socket;
130
131 /*
132 * someday, in the xerox world
133 * we will generate error protocol packets
134 * announcing that the socket has gone away.
135 */
136 /*if (TCPS_HAVERCVDSYN(tp->t_state)) {
137 tp->t_state = TCPS_CLOSED;
138 (void) tcp_output(tp);
139 }*/
140 so->so_error = errno;
141 ipx_pcbdisconnect(ipxp);
142 soisdisconnected(so);
143}
144
145int
146ipx_output(ipxp, m0)
147 struct ipxpcb *ipxp;
148 struct mbuf *m0;
149{
150 register struct mbuf *m;
151 register struct ipx *ipx;
152 register struct socket *so;
153 register int len = 0;
154 register struct route *ro;
155 struct mbuf *mprev = NULL;
156
157 /*
158 * Calculate data length.
159 */
160 for (m = m0; m; m = m->m_next) {
161 mprev = m;
162 len += m->m_len;
163 }
164 /*
165 * Make sure packet is actually of even length.
166 */
167
168 if (len & 1) {
169 m = mprev;
170 if ((m->m_flags & M_EXT) == 0 &&
171 (m->m_len + m->m_data < &m->m_dat[MLEN])) {
172 m->m_len++;
173 } else {
174 struct mbuf *m1 = m_get(M_DONTWAIT, MT_DATA);
175
176 if (m1 == 0) {
177 m_freem(m0);
178 return (ENOBUFS);
179 }
180 m1->m_len = 1;
181 * mtod(m1, char *) = 0;
182 m->m_next = m1;
183 }
184 m0->m_pkthdr.len++;
185 }
186
187 /*
188 * Fill in mbuf with extended IPX header
189 * and addresses and length put into network format.
190 */
191 m = m0;
192 if (ipxp->ipxp_flags & IPXP_RAWOUT) {
193 ipx = mtod(m, struct ipx *);
194 } else {
195 M_PREPEND(m, sizeof (struct ipx), M_DONTWAIT);
196 if (m == 0)
197 return (ENOBUFS);
198 ipx = mtod(m, struct ipx *);
199 ipx->ipx_tc = 0;
200 ipx->ipx_pt = ipxp->ipxp_dpt;
201 ipx->ipx_sna = ipxp->ipxp_laddr;
202 ipx->ipx_dna = ipxp->ipxp_faddr;
203 len += sizeof (struct ipx);
204 }
205
206 ipx->ipx_len = htons((u_short)len);
207
208 if (ipxcksum) {
209 ipx->ipx_sum = 0;
210 len = ((len - 1) | 1) + 1;
211 ipx->ipx_sum = ipx_cksum(m, len);
212 } else
213 ipx->ipx_sum = 0xffff;
214
215 /*
216 * Output datagram.
217 */
218 so = ipxp->ipxp_socket;
219 if (so->so_options & SO_DONTROUTE)
220 return (ipx_outputfl(m, (struct route *)0,
221 (so->so_options & SO_BROADCAST) | IPX_ROUTETOIF));
222 /*
223 * Use cached route for previous datagram if
224 * possible. If the previous net was the same
225 * and the interface was a broadcast medium, or
226 * if the previous destination was identical,
227 * then we are ok.
228 *
229 * NB: We don't handle broadcasts because that
230 * would require 3 subroutine calls.
231 */
232 ro = &ipxp->ipxp_route;
233#ifdef ancient_history
234 /*
235 * I think that this will all be handled in ipx_pcbconnect!
236 */
237 if (ro->ro_rt) {
238 if(ipx_neteq(ipxp->ipxp_lastdst, ipx->ipx_dna)) {
239 /*
240 * This assumes we have no GH type routes
241 */
242 if (ro->ro_rt->rt_flags & RTF_HOST) {
243 if (!ipx_hosteq(ipxp->ipxp_lastdst, ipx->ipx_dna))
244 goto re_route;
245
246 }
247 if ((ro->ro_rt->rt_flags & RTF_GATEWAY) == 0) {
248 register struct ipx_addr *dst =
249 &satoipx_addr(ro->ro_dst);
250 dst->x_host = ipx->ipx_dna.x_host;
251 }
252 /*
253 * Otherwise, we go through the same gateway
254 * and dst is already set up.
255 */
256 } else {
257 re_route:
258 RTFREE(ro->ro_rt);
259 ro->ro_rt = (struct rtentry *)0;
260 }
261 }
262 ipxp->ipxp_lastdst = ipx->ipx_dna;
263#endif /* ancient_history */
264 if (noipxRoute) ro = 0;
265 return (ipx_outputfl(m, ro, so->so_options & SO_BROADCAST));
266}
267/* ARGSUSED */
268int
269ipx_ctloutput(req, so, level, name, value)
270 int req, level;
271 struct socket *so;
272 int name;
273 struct mbuf **value;
274{
275 register struct mbuf *m;
276 struct ipxpcb *ipxp = sotoipxpcb(so);
277 int mask, error = 0;
278 /*extern long ipx_pexseq;*/ /*XXX*//*JRE*/
279
280 if (ipxp == NULL)
281 return (EINVAL);
282
283 switch (req) {
284
285 case PRCO_GETOPT:
286 if (value==NULL)
287 return (EINVAL);
288 m = m_get(M_DONTWAIT, MT_DATA);
289 if (m==NULL)
290 return (ENOBUFS);
291 switch (name) {
292
293 case SO_ALL_PACKETS:
294 mask = IPXP_ALL_PACKETS;
295 goto get_flags;
296
297 case SO_HEADERS_ON_INPUT:
298 mask = IPXP_RAWIN;
299 goto get_flags;
300
301 case SO_HEADERS_ON_OUTPUT:
302 mask = IPXP_RAWOUT;
303 get_flags:
304 m->m_len = sizeof(short);
305 *mtod(m, short *) = ipxp->ipxp_flags & mask;
306 break;
307
308 case SO_DEFAULT_HEADERS:
309 m->m_len = sizeof(struct ipx);
310 {
311 register struct ipx *ipx = mtod(m, struct ipx *);
312 ipx->ipx_len = 0;
313 ipx->ipx_sum = 0;
314 ipx->ipx_tc = 0;
315 ipx->ipx_pt = ipxp->ipxp_dpt;
316 ipx->ipx_dna = ipxp->ipxp_faddr;
317 ipx->ipx_sna = ipxp->ipxp_laddr;
318 }
319 break;
320
321 case SO_SEQNO:
322 m->m_len = sizeof(long);
323 *mtod(m, long *) = ipx_pexseq++;
324 break;
325
326 default:
327 error = EINVAL;
328 }
329 *value = m;
330 break;
331
332 case PRCO_SETOPT:
333 switch (name) {
334 int *ok;
335
336 case SO_ALL_PACKETS:
337 mask = IPXP_ALL_PACKETS;
338 goto set_head;
339
340 case SO_HEADERS_ON_INPUT:
341 mask = IPXP_RAWIN;
342 goto set_head;
343
344 case SO_HEADERS_ON_OUTPUT:
345 mask = IPXP_RAWOUT;
346 set_head:
347 if (value && *value) {
348 ok = mtod(*value, int *);
349 if (*ok)
350 ipxp->ipxp_flags |= mask;
351 else
352 ipxp->ipxp_flags &= ~mask;
353 } else error = EINVAL;
354 break;
355
356 case SO_DEFAULT_HEADERS:
357 {
358 register struct ipx *ipx
359 = mtod(*value, struct ipx *);
360 ipxp->ipxp_dpt = ipx->ipx_pt;
361 }
362 break;
363#ifdef IPXIP
364 case SO_IPXIP_ROUTE:
365 error = ipxip_route(*value);
366 break;
367#endif /* IPXIP */
368#ifdef IPXTUNNEL
369 case SO_IPXTUNNEL_ROUTE
370 error = ipxtun_route(*value);
371 break;
372#endif
373 default:
374 error = EINVAL;
375 }
376 if (value && *value)
377 m_freem(*value);
378 break;
379 }
380 return (error);
381}
382
383/*ARGSUSED*/
384int
385ipx_usrreq(so, req, m, nam, control)
386 struct socket *so;
387 int req;
388 struct mbuf *m, *nam, *control;
389{
390 struct ipxpcb *ipxp = sotoipxpcb(so);
391 int error = 0;
392
393 if (req == PRU_CONTROL)
394 return (ipx_control(so, (int)m, (caddr_t)nam,
395 (struct ifnet *)control));
396 if (control && control->m_len) {
397 error = EINVAL;
398 goto release;
399 }
400 if (ipxp == NULL && req != PRU_ATTACH) {
401 error = EINVAL;
402 goto release;
403 }
404 switch (req) {
405
406 case PRU_ATTACH:
407 if (ipxp != NULL) {
408 error = EINVAL;
409 break;
410 }
411 error = ipx_pcballoc(so, &ipxpcb);
412 if (error)
413 break;
414 error = soreserve(so, (u_long) 2048, (u_long) 2048);
415 if (error)
416 break;
417 break;
418
419 case PRU_DETACH:
420 if (ipxp == NULL) {
421 error = ENOTCONN;
422 break;
423 }
424 ipx_pcbdetach(ipxp);
425 break;
426
427 case PRU_BIND:
428 error = ipx_pcbbind(ipxp, nam);
429 break;
430
431 case PRU_LISTEN:
432 error = EOPNOTSUPP;
433 break;
434
435 case PRU_CONNECT:
436 if (!ipx_nullhost(ipxp->ipxp_faddr)) {
437 error = EISCONN;
438 break;
439 }
440 error = ipx_pcbconnect(ipxp, nam);
441 if (error == 0)
442 soisconnected(so);
443 break;
444
445 case PRU_CONNECT2:
446 error = EOPNOTSUPP;
447 break;
448
449 case PRU_ACCEPT:
450 error = EOPNOTSUPP;
451 break;
452
453 case PRU_DISCONNECT:
454 if (ipx_nullhost(ipxp->ipxp_faddr)) {
455 error = ENOTCONN;
456 break;
457 }
458 ipx_pcbdisconnect(ipxp);
459 soisdisconnected(so);
460 break;
461
462 case PRU_SHUTDOWN:
463 socantsendmore(so);
464 break;
465
466 case PRU_SEND:
467 {
468 struct ipx_addr laddr;
469 int s = 0;
470
471 if (nam) {
472 laddr = ipxp->ipxp_laddr;
473 if (!ipx_nullhost(ipxp->ipxp_faddr)) {
474 error = EISCONN;
475 break;
476 }
477 /*
478 * Must block input while temporarily connected.
479 */
480 s = splnet();
481 error = ipx_pcbconnect(ipxp, nam);
482 if (error) {
483 splx(s);
484 break;
485 }
486 } else {
487 if (ipx_nullhost(ipxp->ipxp_faddr)) {
488 error = ENOTCONN;
489 break;
490 }
491 }
492 error = ipx_output(ipxp, m);
493 m = NULL;
494 if (nam) {
495 ipx_pcbdisconnect(ipxp);
496 splx(s);
497 ipxp->ipxp_laddr.x_host = laddr.x_host;
498 ipxp->ipxp_laddr.x_port = laddr.x_port;
499 }
500 }
501 break;
502
503 case PRU_ABORT:
504 ipx_pcbdetach(ipxp);
505 sofree(so);
506 soisdisconnected(so);
507 break;
508
509 case PRU_SOCKADDR:
510 ipx_setsockaddr(ipxp, nam);
511 break;
512
513 case PRU_PEERADDR:
514 ipx_setpeeraddr(ipxp, nam);
515 break;
516
517 case PRU_SENSE:
518 /*
519 * stat: don't bother with a blocksize.
520 */
521 return (0);
522
523 case PRU_SENDOOB:
524 case PRU_FASTTIMO:
525 case PRU_SLOWTIMO:
526 case PRU_PROTORCV:
527 case PRU_PROTOSEND:
528 error = EOPNOTSUPP;
529 break;
530
531 case PRU_CONTROL:
532 case PRU_RCVD:
533 case PRU_RCVOOB:
534 return (EOPNOTSUPP); /* do not free mbuf's */
535
536 default:
537 panic("ipx_usrreq");
538 }
539release:
540 if (control != NULL)
541 m_freem(control);
542 if (m != NULL)
543 m_freem(m);
544 return (error);
545}
546/*ARGSUSED*/
547int
548ipx_raw_usrreq(so, req, m, nam, control)
549 struct socket *so;
550 int req;
551 struct mbuf *m, *nam, *control;
552{
553 int error = 0;
554 struct ipxpcb *ipxp = sotoipxpcb(so);
555 /*extern struct ipxpcb ipxrawpcb;*//*XXX*//*JRE*/
556
557 switch (req) {
558
559 case PRU_ATTACH:
560
561 if (!(so->so_state & SS_PRIV) || (ipxp != NULL)) {
562 error = EINVAL;
563 break;
564 }
565 error = ipx_pcballoc(so, &ipxrawpcb);
566 if (error)
567 break;
568 error = soreserve(so, (u_long) 2048, (u_long) 2048);
569 if (error)
570 break;
571 ipxp = sotoipxpcb(so);
572 ipxp->ipxp_faddr.x_host = ipx_broadhost;
573 ipxp->ipxp_flags = IPXP_RAWIN | IPXP_RAWOUT;
574 break;
575 default:
576 error = ipx_usrreq(so, req, m, nam, control);
577 }
578 return (error);
579}
580