dma: add DragonFly compat files
[dragonfly.git] / sys / netproto / ipx / ipx_usrreq.c
blob32b2cdb97f9d02786cdbca6cb702aa0564563408
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.
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.
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.
34 * @(#)ipx_usrreq.c
36 * $FreeBSD: src/sys/netipx/ipx_usrreq.c,v 1.26.2.1 2001/02/22 09:44:18 bp Exp $
37 * $DragonFly: src/sys/netproto/ipx/ipx_usrreq.c,v 1.13 2008/03/07 11:34:21 sephe Exp $
40 #include "opt_ipx.h"
42 #include <sys/param.h>
43 #include <sys/systm.h>
44 #include <sys/kernel.h>
45 #include <sys/mbuf.h>
46 #include <sys/proc.h>
47 #include <sys/priv.h>
48 #include <sys/protosw.h>
49 #include <sys/socket.h>
50 #include <sys/socketvar.h>
51 #include <sys/sysctl.h>
52 #include <sys/thread2.h>
54 #include <net/if.h>
55 #include <net/route.h>
57 #include <netinet/in.h>
59 #include "ipx.h"
60 #include "ipx_pcb.h"
61 #include "ipx_if.h"
62 #include "ipx_var.h"
63 #include "ipx_ip.h"
66 * IPX protocol implementation.
69 static int ipxsendspace = IPXSNDQ;
70 SYSCTL_INT(_net_ipx_ipx, OID_AUTO, ipxsendspace, CTLFLAG_RW,
71 &ipxsendspace, 0, "");
72 static int ipxrecvspace = IPXRCVQ;
73 SYSCTL_INT(_net_ipx_ipx, OID_AUTO, ipxrecvspace, CTLFLAG_RW,
74 &ipxrecvspace, 0, "");
76 static int ipx_usr_abort(struct socket *so);
77 static int ipx_attach(struct socket *so, int proto,
78 struct pru_attach_info *ai);
79 static int ipx_bind(struct socket *so, struct sockaddr *nam,
80 struct thread *td);
81 static int ipx_connect(struct socket *so, struct sockaddr *nam,
82 struct thread *td);
83 static int ipx_detach(struct socket *so);
84 static int ipx_disconnect(struct socket *so);
85 static int ipx_send(struct socket *so, int flags, struct mbuf *m,
86 struct sockaddr *addr, struct mbuf *control,
87 struct thread *td);
88 static int ipx_shutdown(struct socket *so);
89 static int ripx_attach(struct socket *so, int proto,
90 struct pru_attach_info *ai);
91 static int ipx_output(struct ipxpcb *ipxp, struct mbuf *m0);
93 struct pr_usrreqs ipx_usrreqs = {
94 .pru_abort = ipx_usr_abort,
95 .pru_accept = pru_accept_notsupp,
96 .pru_attach = ipx_attach,
97 .pru_bind = ipx_bind,
98 .pru_connect = ipx_connect,
99 .pru_connect2 = pru_connect2_notsupp,
100 .pru_control = ipx_control,
101 .pru_detach = ipx_detach,
102 .pru_disconnect = ipx_disconnect,
103 .pru_listen = pru_listen_notsupp,
104 .pru_peeraddr = ipx_peeraddr,
105 .pru_rcvd = pru_rcvd_notsupp,
106 .pru_rcvoob = pru_rcvoob_notsupp,
107 .pru_send = ipx_send,
108 .pru_sense = pru_sense_null,
109 .pru_shutdown = ipx_shutdown,
110 .pru_sockaddr = ipx_sockaddr,
111 .pru_sosend = sosend,
112 .pru_soreceive = soreceive,
113 .pru_sopoll = sopoll
116 struct pr_usrreqs ripx_usrreqs = {
117 .pru_abort = ipx_usr_abort,
118 .pru_accept = pru_accept_notsupp,
119 .pru_attach = ripx_attach,
120 .pru_bind = ipx_bind,
121 .pru_connect = ipx_connect,
122 .pru_connect2 = pru_connect2_notsupp,
123 .pru_control = ipx_control,
124 .pru_detach = ipx_detach,
125 .pru_disconnect = ipx_disconnect,
126 .pru_listen = pru_listen_notsupp,
127 .pru_peeraddr = ipx_peeraddr,
128 .pru_rcvd = pru_rcvd_notsupp,
129 .pru_rcvoob = pru_rcvoob_notsupp,
130 .pru_send = ipx_send,
131 .pru_sense = pru_sense_null,
132 .pru_shutdown = ipx_shutdown,
133 .pru_sockaddr = ipx_sockaddr,
134 .pru_sosend = sosend,
135 .pru_soreceive = soreceive,
136 .pru_sopoll = sopoll
140 * This may also be called for raw listeners.
142 void
143 ipx_input(struct mbuf *m, struct ipxpcb *ipxp)
145 struct ipx *ipx = mtod(m, struct ipx *);
146 struct ifnet *ifp = m->m_pkthdr.rcvif;
147 struct sockaddr_ipx ipx_ipx;
149 if (ipxp == NULL)
150 panic("No ipxpcb");
152 * Construct sockaddr format source address.
153 * Stuff source address and datagram in user buffer.
155 ipx_ipx.sipx_len = sizeof(ipx_ipx);
156 ipx_ipx.sipx_family = AF_IPX;
157 ipx_ipx.sipx_addr = ipx->ipx_sna;
158 ipx_ipx.sipx_zero[0] = '\0';
159 ipx_ipx.sipx_zero[1] = '\0';
160 if (ipx_neteqnn(ipx->ipx_sna.x_net, ipx_zeronet) && ifp != NULL) {
161 struct ifaddr_container *ifac;
163 TAILQ_FOREACH(ifac, &ifp->if_addrheads[mycpuid], ifa_link) {
164 struct ifaddr *ifa = ifac->ifa;
166 if (ifa->ifa_addr->sa_family == AF_IPX) {
167 ipx_ipx.sipx_addr.x_net =
168 IA_SIPX(ifa)->sipx_addr.x_net;
169 break;
173 ipxp->ipxp_rpt = ipx->ipx_pt;
174 if (!(ipxp->ipxp_flags & IPXP_RAWIN) ) {
175 m->m_len -= sizeof(struct ipx);
176 m->m_pkthdr.len -= sizeof(struct ipx);
177 m->m_data += sizeof(struct ipx);
179 if (ssb_appendaddr(&ipxp->ipxp_socket->so_rcv, (struct sockaddr *)&ipx_ipx,
180 m, NULL) == 0)
181 goto bad;
182 sorwakeup(ipxp->ipxp_socket);
183 return;
184 bad:
185 m_freem(m);
188 void
189 ipx_abort(struct ipxpcb *ipxp)
191 struct socket *so = ipxp->ipxp_socket;
193 ipx_pcbdisconnect(ipxp);
194 soisdisconnected(so);
198 * Drop connection, reporting
199 * the specified error.
201 void
202 ipx_drop(struct ipxpcb *ipxp, int errno)
204 struct socket *so = ipxp->ipxp_socket;
207 * someday, in the IPX world
208 * we will generate error protocol packets
209 * announcing that the socket has gone away.
211 * XXX Probably never. IPX does not have error packets.
213 /*if (TCPS_HAVERCVDSYN(tp->t_state)) {
214 tp->t_state = TCPS_CLOSED;
215 tcp_output(tp);
217 so->so_error = errno;
218 ipx_pcbdisconnect(ipxp);
219 soisdisconnected(so);
222 static int
223 ipx_output(struct ipxpcb *ipxp, struct mbuf *m0)
225 struct ipx *ipx;
226 struct socket *so;
227 int len = 0;
228 struct route *ro;
229 struct mbuf *m;
230 struct mbuf *mprev = NULL;
233 * Calculate data length.
235 for (m = m0; m != NULL; m = m->m_next) {
236 mprev = m;
237 len += m->m_len;
240 * Make sure packet is actually of even length.
243 if (len & 1) {
244 m = mprev;
245 if ((m->m_flags & M_EXT) == 0 &&
246 (m->m_len + m->m_data < &m->m_dat[MLEN])) {
247 mtod(m, char*)[m->m_len++] = 0;
248 } else {
249 struct mbuf *m1 = m_get(MB_DONTWAIT, MT_DATA);
251 if (m1 == NULL) {
252 m_freem(m0);
253 return (ENOBUFS);
255 m1->m_len = 1;
256 * mtod(m1, char *) = 0;
257 m->m_next = m1;
259 m0->m_pkthdr.len++;
263 * Fill in mbuf with extended IPX header
264 * and addresses and length put into network format.
266 m = m0;
267 if (ipxp->ipxp_flags & IPXP_RAWOUT) {
268 ipx = mtod(m, struct ipx *);
269 } else {
270 M_PREPEND(m, sizeof(struct ipx), MB_DONTWAIT);
271 if (m == NULL)
272 return (ENOBUFS);
273 ipx = mtod(m, struct ipx *);
274 ipx->ipx_tc = 0;
275 ipx->ipx_pt = ipxp->ipxp_dpt;
276 ipx->ipx_sna = ipxp->ipxp_laddr;
277 ipx->ipx_dna = ipxp->ipxp_faddr;
278 len += sizeof(struct ipx);
281 ipx->ipx_len = htons((u_short)len);
283 if (ipxp->ipxp_flags & IPXP_CHECKSUM) {
284 ipx->ipx_sum = ipx_cksum(m, len);
285 } else
286 ipx->ipx_sum = 0xffff;
289 * Output datagram.
291 so = ipxp->ipxp_socket;
292 if (so->so_options & SO_DONTROUTE)
293 return (ipx_outputfl(m, NULL,
294 (so->so_options & SO_BROADCAST) | IPX_ROUTETOIF));
296 * Use cached route for previous datagram if
297 * possible. If the previous net was the same
298 * and the interface was a broadcast medium, or
299 * if the previous destination was identical,
300 * then we are ok.
302 * NB: We don't handle broadcasts because that
303 * would require 3 subroutine calls.
305 ro = &ipxp->ipxp_route;
306 #ifdef ancient_history
308 * I think that this will all be handled in ipx_pcbconnect!
310 if (ro->ro_rt != NULL) {
311 if(ipx_neteq(ipxp->ipxp_lastdst, ipx->ipx_dna)) {
313 * This assumes we have no GH type routes
315 if (ro->ro_rt->rt_flags & RTF_HOST) {
316 if (!ipx_hosteq(ipxp->ipxp_lastdst, ipx->ipx_dna))
317 goto re_route;
320 if ((ro->ro_rt->rt_flags & RTF_GATEWAY) == 0) {
321 struct ipx_addr *dst =
322 &satoipx_addr(ro->ro_dst);
323 dst->x_host = ipx->ipx_dna.x_host;
326 * Otherwise, we go through the same gateway
327 * and dst is already set up.
329 } else {
330 re_route:
331 RTFREE(ro->ro_rt);
332 ro->ro_rt = NULL;
335 ipxp->ipxp_lastdst = ipx->ipx_dna;
336 #endif /* ancient_history */
337 return (ipx_outputfl(m, ro, so->so_options & SO_BROADCAST));
341 ipx_ctloutput(struct socket *so, struct sockopt *sopt)
343 struct ipxpcb *ipxp = sotoipxpcb(so);
344 int mask, error, optval;
345 short soptval;
346 struct ipx ioptval;
348 error = 0;
349 if (ipxp == NULL)
350 return (EINVAL);
352 switch (sopt->sopt_dir) {
353 case SOPT_GET:
354 switch (sopt->sopt_name) {
355 case SO_ALL_PACKETS:
356 mask = IPXP_ALL_PACKETS;
357 goto get_flags;
359 case SO_HEADERS_ON_INPUT:
360 mask = IPXP_RAWIN;
361 goto get_flags;
363 case SO_IPX_CHECKSUM:
364 mask = IPXP_CHECKSUM;
365 goto get_flags;
367 case SO_HEADERS_ON_OUTPUT:
368 mask = IPXP_RAWOUT;
369 get_flags:
370 soptval = ipxp->ipxp_flags & mask;
371 error = sooptcopyout(sopt, &soptval, sizeof soptval);
372 break;
374 case SO_DEFAULT_HEADERS:
375 ioptval.ipx_len = 0;
376 ioptval.ipx_sum = 0;
377 ioptval.ipx_tc = 0;
378 ioptval.ipx_pt = ipxp->ipxp_dpt;
379 ioptval.ipx_dna = ipxp->ipxp_faddr;
380 ioptval.ipx_sna = ipxp->ipxp_laddr;
381 error = sooptcopyout(sopt, &soptval, sizeof soptval);
382 break;
384 case SO_SEQNO:
385 error = sooptcopyout(sopt, &ipx_pexseq,
386 sizeof ipx_pexseq);
387 ipx_pexseq++;
388 break;
390 default:
391 error = EINVAL;
393 break;
395 case SOPT_SET:
396 switch (sopt->sopt_name) {
397 case SO_ALL_PACKETS:
398 mask = IPXP_ALL_PACKETS;
399 goto set_head;
401 case SO_HEADERS_ON_INPUT:
402 mask = IPXP_RAWIN;
403 goto set_head;
405 case SO_IPX_CHECKSUM:
406 mask = IPXP_CHECKSUM;
408 case SO_HEADERS_ON_OUTPUT:
409 mask = IPXP_RAWOUT;
410 set_head:
411 error = sooptcopyin(sopt, &optval, sizeof optval,
412 sizeof optval);
413 if (error)
414 break;
415 if (optval)
416 ipxp->ipxp_flags |= mask;
417 else
418 ipxp->ipxp_flags &= ~mask;
419 break;
421 case SO_DEFAULT_HEADERS:
422 error = sooptcopyin(sopt, &ioptval, sizeof ioptval,
423 sizeof ioptval);
424 if (error)
425 break;
426 ipxp->ipxp_dpt = ioptval.ipx_pt;
427 break;
428 #ifdef IPXIP
429 case SO_IPXIP_ROUTE:
430 error = ipxip_route(so, sopt);
431 break;
432 #endif /* IPXIP */
433 #ifdef IPTUNNEL
434 #if 0
435 case SO_IPXTUNNEL_ROUTE:
436 error = ipxtun_route(so, sopt);
437 break;
438 #endif
439 #endif
440 default:
441 error = EINVAL;
443 break;
445 return (error);
448 static int
449 ipx_usr_abort(struct socket *so)
451 struct ipxpcb *ipxp = sotoipxpcb(so);
453 crit_enter();
454 ipx_pcbdetach(ipxp);
455 crit_exit();
456 sofree(so);
457 soisdisconnected(so);
458 return (0);
461 static int
462 ipx_attach(struct socket *so, int proto, struct pru_attach_info *ai)
464 int error;
465 struct ipxpcb *ipxp = sotoipxpcb(so);
467 if (ipxp != NULL)
468 return (EINVAL);
469 crit_enter();
470 error = ipx_pcballoc(so, &ipxpcb);
471 crit_exit();
472 if (error == 0)
473 error = soreserve(so, ipxsendspace, ipxrecvspace,
474 ai->sb_rlimit);
475 return (error);
478 static int
479 ipx_bind(struct socket *so, struct sockaddr *nam, struct thread *td)
481 struct ipxpcb *ipxp = sotoipxpcb(so);
483 return (ipx_pcbbind(ipxp, nam, td));
486 static int
487 ipx_connect(struct socket *so, struct sockaddr *nam, struct thread *td)
489 int error;
490 struct ipxpcb *ipxp = sotoipxpcb(so);
492 if (!ipx_nullhost(ipxp->ipxp_faddr))
493 return (EISCONN);
494 crit_enter();
495 error = ipx_pcbconnect(ipxp, nam, td);
496 crit_exit();
497 if (error == 0)
498 soisconnected(so);
499 return (error);
502 static int
503 ipx_detach(struct socket *so)
505 struct ipxpcb *ipxp = sotoipxpcb(so);
507 if (ipxp == NULL)
508 return (ENOTCONN);
509 crit_enter();
510 ipx_pcbdetach(ipxp);
511 crit_exit();
512 return (0);
515 static int
516 ipx_disconnect(struct socket *so)
518 struct ipxpcb *ipxp = sotoipxpcb(so);
520 if (ipx_nullhost(ipxp->ipxp_faddr))
521 return (ENOTCONN);
522 crit_enter();
523 ipx_pcbdisconnect(ipxp);
524 crit_exit();
525 soisdisconnected(so);
526 return (0);
530 ipx_peeraddr(struct socket *so, struct sockaddr **nam)
532 struct ipxpcb *ipxp = sotoipxpcb(so);
534 ipx_setpeeraddr(ipxp, nam);
535 return (0);
538 static int
539 ipx_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *nam,
540 struct mbuf *control, struct thread *td)
542 int error;
543 struct ipxpcb *ipxp = sotoipxpcb(so);
544 struct ipx_addr laddr;
546 crit_enter();
547 if (nam != NULL) {
548 laddr = ipxp->ipxp_laddr;
549 if (!ipx_nullhost(ipxp->ipxp_faddr)) {
550 error = EISCONN;
551 goto send_release;
554 * Must block input while temporarily connected.
556 error = ipx_pcbconnect(ipxp, nam, td);
557 if (error) {
558 goto send_release;
560 } else {
561 if (ipx_nullhost(ipxp->ipxp_faddr)) {
562 error = ENOTCONN;
563 goto send_release;
566 error = ipx_output(ipxp, m);
567 m = NULL;
568 if (nam != NULL) {
569 ipx_pcbdisconnect(ipxp);
570 ipxp->ipxp_laddr = laddr;
572 send_release:
573 crit_exit();
574 if (m != NULL)
575 m_freem(m);
576 return (error);
579 static int
580 ipx_shutdown(struct socket *so)
582 socantsendmore(so);
583 return (0);
587 ipx_sockaddr(struct socket *so, struct sockaddr **nam)
589 struct ipxpcb *ipxp = sotoipxpcb(so);
591 ipx_setsockaddr(ipxp, nam); /* XXX what if alloc fails? */
592 return (0);
595 static int
596 ripx_attach(struct socket *so, int proto, struct pru_attach_info *ai)
598 int error = 0;
599 struct ipxpcb *ipxp;
601 if ((error = priv_check_cred(ai->p_ucred, PRIV_ROOT, NULL_CRED_OKAY)) != 0)
602 return (error);
603 crit_enter();
604 error = ipx_pcballoc(so, &ipxrawpcb);
605 crit_exit();
606 if (error)
607 return (error);
608 error = soreserve(so, ipxsendspace, ipxrecvspace, ai->sb_rlimit);
609 if (error)
610 return (error);
611 ipxp = sotoipxpcb(so);
612 ipxp->ipxp_faddr.x_host = ipx_broadhost;
613 ipxp->ipxp_flags = IPXP_RAWIN | IPXP_RAWOUT;
614 return (error);