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
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
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 $
42 #include <sys/param.h>
43 #include <sys/systm.h>
44 #include <sys/kernel.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>
55 #include <net/route.h>
57 #include <netinet/in.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
,
81 static int ipx_connect(struct socket
*so
, struct sockaddr
*nam
,
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
,
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
,
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
,
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
,
140 * This may also be called for raw listeners.
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
;
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
;
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
,
182 sorwakeup(ipxp
->ipxp_socket
);
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.
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;
217 so
->so_error
= errno
;
218 ipx_pcbdisconnect(ipxp
);
219 soisdisconnected(so
);
223 ipx_output(struct ipxpcb
*ipxp
, struct mbuf
*m0
)
230 struct mbuf
*mprev
= NULL
;
233 * Calculate data length.
235 for (m
= m0
; m
!= NULL
; m
= m
->m_next
) {
240 * Make sure packet is actually of even length.
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;
249 struct mbuf
*m1
= m_get(MB_DONTWAIT
, MT_DATA
);
256 * mtod(m1
, char *) = 0;
263 * Fill in mbuf with extended IPX header
264 * and addresses and length put into network format.
267 if (ipxp
->ipxp_flags
& IPXP_RAWOUT
) {
268 ipx
= mtod(m
, struct ipx
*);
270 M_PREPEND(m
, sizeof(struct ipx
), MB_DONTWAIT
);
273 ipx
= mtod(m
, struct ipx
*);
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
);
286 ipx
->ipx_sum
= 0xffff;
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,
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
))
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.
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
;
352 switch (sopt
->sopt_dir
) {
354 switch (sopt
->sopt_name
) {
356 mask
= IPXP_ALL_PACKETS
;
359 case SO_HEADERS_ON_INPUT
:
363 case SO_IPX_CHECKSUM
:
364 mask
= IPXP_CHECKSUM
;
367 case SO_HEADERS_ON_OUTPUT
:
370 soptval
= ipxp
->ipxp_flags
& mask
;
371 error
= sooptcopyout(sopt
, &soptval
, sizeof soptval
);
374 case SO_DEFAULT_HEADERS
:
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
);
385 error
= sooptcopyout(sopt
, &ipx_pexseq
,
396 switch (sopt
->sopt_name
) {
398 mask
= IPXP_ALL_PACKETS
;
401 case SO_HEADERS_ON_INPUT
:
405 case SO_IPX_CHECKSUM
:
406 mask
= IPXP_CHECKSUM
;
408 case SO_HEADERS_ON_OUTPUT
:
411 error
= sooptcopyin(sopt
, &optval
, sizeof optval
,
416 ipxp
->ipxp_flags
|= mask
;
418 ipxp
->ipxp_flags
&= ~mask
;
421 case SO_DEFAULT_HEADERS
:
422 error
= sooptcopyin(sopt
, &ioptval
, sizeof ioptval
,
426 ipxp
->ipxp_dpt
= ioptval
.ipx_pt
;
430 error
= ipxip_route(so
, sopt
);
435 case SO_IPXTUNNEL_ROUTE
:
436 error
= ipxtun_route(so
, sopt
);
449 ipx_usr_abort(struct socket
*so
)
451 struct ipxpcb
*ipxp
= sotoipxpcb(so
);
457 soisdisconnected(so
);
462 ipx_attach(struct socket
*so
, int proto
, struct pru_attach_info
*ai
)
465 struct ipxpcb
*ipxp
= sotoipxpcb(so
);
470 error
= ipx_pcballoc(so
, &ipxpcb
);
473 error
= soreserve(so
, ipxsendspace
, ipxrecvspace
,
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
));
487 ipx_connect(struct socket
*so
, struct sockaddr
*nam
, struct thread
*td
)
490 struct ipxpcb
*ipxp
= sotoipxpcb(so
);
492 if (!ipx_nullhost(ipxp
->ipxp_faddr
))
495 error
= ipx_pcbconnect(ipxp
, nam
, td
);
503 ipx_detach(struct socket
*so
)
505 struct ipxpcb
*ipxp
= sotoipxpcb(so
);
516 ipx_disconnect(struct socket
*so
)
518 struct ipxpcb
*ipxp
= sotoipxpcb(so
);
520 if (ipx_nullhost(ipxp
->ipxp_faddr
))
523 ipx_pcbdisconnect(ipxp
);
525 soisdisconnected(so
);
530 ipx_peeraddr(struct socket
*so
, struct sockaddr
**nam
)
532 struct ipxpcb
*ipxp
= sotoipxpcb(so
);
534 ipx_setpeeraddr(ipxp
, nam
);
539 ipx_send(struct socket
*so
, int flags
, struct mbuf
*m
, struct sockaddr
*nam
,
540 struct mbuf
*control
, struct thread
*td
)
543 struct ipxpcb
*ipxp
= sotoipxpcb(so
);
544 struct ipx_addr laddr
;
548 laddr
= ipxp
->ipxp_laddr
;
549 if (!ipx_nullhost(ipxp
->ipxp_faddr
)) {
554 * Must block input while temporarily connected.
556 error
= ipx_pcbconnect(ipxp
, nam
, td
);
561 if (ipx_nullhost(ipxp
->ipxp_faddr
)) {
566 error
= ipx_output(ipxp
, m
);
569 ipx_pcbdisconnect(ipxp
);
570 ipxp
->ipxp_laddr
= laddr
;
580 ipx_shutdown(struct socket
*so
)
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? */
596 ripx_attach(struct socket
*so
, int proto
, struct pru_attach_info
*ai
)
601 if ((error
= priv_check_cred(ai
->p_ucred
, PRIV_ROOT
, NULL_CRED_OKAY
)) != 0)
604 error
= ipx_pcballoc(so
, &ipxrawpcb
);
608 error
= soreserve(so
, ipxsendspace
, ipxrecvspace
, ai
->sb_rlimit
);
611 ipxp
= sotoipxpcb(so
);
612 ipxp
->ipxp_faddr
.x_host
= ipx_broadhost
;
613 ipxp
->ipxp_flags
= IPXP_RAWIN
| IPXP_RAWOUT
;