Deleted Added
sdiff udiff text old ( 11819 ) new ( 11947 )
full compact
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
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>
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