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 <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>
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