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