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.12 2007/04/22 01:13:15 dillon Exp $
42 #include <sys/param.h>
43 #include <sys/systm.h>
44 #include <sys/kernel.h>
47 #include <sys/protosw.h>
48 #include <sys/socket.h>
49 #include <sys/socketvar.h>
50 #include <sys/sysctl.h>
51 #include <sys/thread2.h>
54 #include <net/route.h>
56 #include <netinet/in.h>
65 * IPX protocol implementation.
68 static int ipxsendspace
= IPXSNDQ
;
69 SYSCTL_INT(_net_ipx_ipx
, OID_AUTO
, ipxsendspace
, CTLFLAG_RW
,
70 &ipxsendspace
, 0, "");
71 static int ipxrecvspace
= IPXRCVQ
;
72 SYSCTL_INT(_net_ipx_ipx
, OID_AUTO
, ipxrecvspace
, CTLFLAG_RW
,
73 &ipxrecvspace
, 0, "");
75 static int ipx_usr_abort(struct socket
*so
);
76 static int ipx_attach(struct socket
*so
, int proto
,
77 struct pru_attach_info
*ai
);
78 static int ipx_bind(struct socket
*so
, struct sockaddr
*nam
,
80 static int ipx_connect(struct socket
*so
, struct sockaddr
*nam
,
82 static int ipx_detach(struct socket
*so
);
83 static int ipx_disconnect(struct socket
*so
);
84 static int ipx_send(struct socket
*so
, int flags
, struct mbuf
*m
,
85 struct sockaddr
*addr
, struct mbuf
*control
,
87 static int ipx_shutdown(struct socket
*so
);
88 static int ripx_attach(struct socket
*so
, int proto
,
89 struct pru_attach_info
*ai
);
90 static int ipx_output(struct ipxpcb
*ipxp
, struct mbuf
*m0
);
92 struct pr_usrreqs ipx_usrreqs
= {
93 .pru_abort
= ipx_usr_abort
,
94 .pru_accept
= pru_accept_notsupp
,
95 .pru_attach
= ipx_attach
,
97 .pru_connect
= ipx_connect
,
98 .pru_connect2
= pru_connect2_notsupp
,
99 .pru_control
= ipx_control
,
100 .pru_detach
= ipx_detach
,
101 .pru_disconnect
= ipx_disconnect
,
102 .pru_listen
= pru_listen_notsupp
,
103 .pru_peeraddr
= ipx_peeraddr
,
104 .pru_rcvd
= pru_rcvd_notsupp
,
105 .pru_rcvoob
= pru_rcvoob_notsupp
,
106 .pru_send
= ipx_send
,
107 .pru_sense
= pru_sense_null
,
108 .pru_shutdown
= ipx_shutdown
,
109 .pru_sockaddr
= ipx_sockaddr
,
110 .pru_sosend
= sosend
,
111 .pru_soreceive
= soreceive
,
115 struct pr_usrreqs ripx_usrreqs
= {
116 .pru_abort
= ipx_usr_abort
,
117 .pru_accept
= pru_accept_notsupp
,
118 .pru_attach
= ripx_attach
,
119 .pru_bind
= ipx_bind
,
120 .pru_connect
= ipx_connect
,
121 .pru_connect2
= pru_connect2_notsupp
,
122 .pru_control
= ipx_control
,
123 .pru_detach
= ipx_detach
,
124 .pru_disconnect
= ipx_disconnect
,
125 .pru_listen
= pru_listen_notsupp
,
126 .pru_peeraddr
= ipx_peeraddr
,
127 .pru_rcvd
= pru_rcvd_notsupp
,
128 .pru_rcvoob
= pru_rcvoob_notsupp
,
129 .pru_send
= ipx_send
,
130 .pru_sense
= pru_sense_null
,
131 .pru_shutdown
= ipx_shutdown
,
132 .pru_sockaddr
= ipx_sockaddr
,
133 .pru_sosend
= sosend
,
134 .pru_soreceive
= soreceive
,
139 * This may also be called for raw listeners.
142 ipx_input(struct mbuf
*m
, struct ipxpcb
*ipxp
)
144 struct ipx
*ipx
= mtod(m
, struct ipx
*);
145 struct ifnet
*ifp
= m
->m_pkthdr
.rcvif
;
146 struct sockaddr_ipx ipx_ipx
;
151 * Construct sockaddr format source address.
152 * Stuff source address and datagram in user buffer.
154 ipx_ipx
.sipx_len
= sizeof(ipx_ipx
);
155 ipx_ipx
.sipx_family
= AF_IPX
;
156 ipx_ipx
.sipx_addr
= ipx
->ipx_sna
;
157 ipx_ipx
.sipx_zero
[0] = '\0';
158 ipx_ipx
.sipx_zero
[1] = '\0';
159 if (ipx_neteqnn(ipx
->ipx_sna
.x_net
, ipx_zeronet
) && ifp
!= NULL
) {
162 for (ifa
= TAILQ_FIRST(&ifp
->if_addrhead
); ifa
!= NULL
;
163 ifa
= TAILQ_NEXT(ifa
, ifa_link
)) {
164 if (ifa
->ifa_addr
->sa_family
== AF_IPX
) {
165 ipx_ipx
.sipx_addr
.x_net
=
166 IA_SIPX(ifa
)->sipx_addr
.x_net
;
171 ipxp
->ipxp_rpt
= ipx
->ipx_pt
;
172 if (!(ipxp
->ipxp_flags
& IPXP_RAWIN
) ) {
173 m
->m_len
-= sizeof(struct ipx
);
174 m
->m_pkthdr
.len
-= sizeof(struct ipx
);
175 m
->m_data
+= sizeof(struct ipx
);
177 if (ssb_appendaddr(&ipxp
->ipxp_socket
->so_rcv
, (struct sockaddr
*)&ipx_ipx
,
178 m
, (struct mbuf
*)NULL
) == 0)
180 sorwakeup(ipxp
->ipxp_socket
);
187 ipx_abort(struct ipxpcb
*ipxp
)
189 struct socket
*so
= ipxp
->ipxp_socket
;
191 ipx_pcbdisconnect(ipxp
);
192 soisdisconnected(so
);
196 * Drop connection, reporting
197 * the specified error.
200 ipx_drop(struct ipxpcb
*ipxp
, int errno
)
202 struct socket
*so
= ipxp
->ipxp_socket
;
205 * someday, in the IPX world
206 * we will generate error protocol packets
207 * announcing that the socket has gone away.
209 * XXX Probably never. IPX does not have error packets.
211 /*if (TCPS_HAVERCVDSYN(tp->t_state)) {
212 tp->t_state = TCPS_CLOSED;
215 so
->so_error
= errno
;
216 ipx_pcbdisconnect(ipxp
);
217 soisdisconnected(so
);
221 ipx_output(struct ipxpcb
*ipxp
, struct mbuf
*m0
)
228 struct mbuf
*mprev
= NULL
;
231 * Calculate data length.
233 for (m
= m0
; m
!= NULL
; m
= m
->m_next
) {
238 * Make sure packet is actually of even length.
243 if ((m
->m_flags
& M_EXT
) == 0 &&
244 (m
->m_len
+ m
->m_data
< &m
->m_dat
[MLEN
])) {
245 mtod(m
, char*)[m
->m_len
++] = 0;
247 struct mbuf
*m1
= m_get(MB_DONTWAIT
, MT_DATA
);
254 * mtod(m1
, char *) = 0;
261 * Fill in mbuf with extended IPX header
262 * and addresses and length put into network format.
265 if (ipxp
->ipxp_flags
& IPXP_RAWOUT
) {
266 ipx
= mtod(m
, struct ipx
*);
268 M_PREPEND(m
, sizeof(struct ipx
), MB_DONTWAIT
);
271 ipx
= mtod(m
, struct ipx
*);
273 ipx
->ipx_pt
= ipxp
->ipxp_dpt
;
274 ipx
->ipx_sna
= ipxp
->ipxp_laddr
;
275 ipx
->ipx_dna
= ipxp
->ipxp_faddr
;
276 len
+= sizeof(struct ipx
);
279 ipx
->ipx_len
= htons((u_short
)len
);
281 if (ipxp
->ipxp_flags
& IPXP_CHECKSUM
) {
282 ipx
->ipx_sum
= ipx_cksum(m
, len
);
284 ipx
->ipx_sum
= 0xffff;
289 so
= ipxp
->ipxp_socket
;
290 if (so
->so_options
& SO_DONTROUTE
)
291 return (ipx_outputfl(m
, (struct route
*)NULL
,
292 (so
->so_options
& SO_BROADCAST
) | IPX_ROUTETOIF
));
294 * Use cached route for previous datagram if
295 * possible. If the previous net was the same
296 * and the interface was a broadcast medium, or
297 * if the previous destination was identical,
300 * NB: We don't handle broadcasts because that
301 * would require 3 subroutine calls.
303 ro
= &ipxp
->ipxp_route
;
304 #ifdef ancient_history
306 * I think that this will all be handled in ipx_pcbconnect!
308 if (ro
->ro_rt
!= NULL
) {
309 if(ipx_neteq(ipxp
->ipxp_lastdst
, ipx
->ipx_dna
)) {
311 * This assumes we have no GH type routes
313 if (ro
->ro_rt
->rt_flags
& RTF_HOST
) {
314 if (!ipx_hosteq(ipxp
->ipxp_lastdst
, ipx
->ipx_dna
))
318 if ((ro
->ro_rt
->rt_flags
& RTF_GATEWAY
) == 0) {
319 struct ipx_addr
*dst
=
320 &satoipx_addr(ro
->ro_dst
);
321 dst
->x_host
= ipx
->ipx_dna
.x_host
;
324 * Otherwise, we go through the same gateway
325 * and dst is already set up.
333 ipxp
->ipxp_lastdst
= ipx
->ipx_dna
;
334 #endif /* ancient_history */
335 return (ipx_outputfl(m
, ro
, so
->so_options
& SO_BROADCAST
));
339 ipx_ctloutput(struct socket
*so
, struct sockopt
*sopt
)
341 struct ipxpcb
*ipxp
= sotoipxpcb(so
);
342 int mask
, error
, optval
;
350 switch (sopt
->sopt_dir
) {
352 switch (sopt
->sopt_name
) {
354 mask
= IPXP_ALL_PACKETS
;
357 case SO_HEADERS_ON_INPUT
:
361 case SO_IPX_CHECKSUM
:
362 mask
= IPXP_CHECKSUM
;
365 case SO_HEADERS_ON_OUTPUT
:
368 soptval
= ipxp
->ipxp_flags
& mask
;
369 error
= sooptcopyout(sopt
, &soptval
, sizeof soptval
);
372 case SO_DEFAULT_HEADERS
:
376 ioptval
.ipx_pt
= ipxp
->ipxp_dpt
;
377 ioptval
.ipx_dna
= ipxp
->ipxp_faddr
;
378 ioptval
.ipx_sna
= ipxp
->ipxp_laddr
;
379 error
= sooptcopyout(sopt
, &soptval
, sizeof soptval
);
383 error
= sooptcopyout(sopt
, &ipx_pexseq
,
394 switch (sopt
->sopt_name
) {
396 mask
= IPXP_ALL_PACKETS
;
399 case SO_HEADERS_ON_INPUT
:
403 case SO_IPX_CHECKSUM
:
404 mask
= IPXP_CHECKSUM
;
406 case SO_HEADERS_ON_OUTPUT
:
409 error
= sooptcopyin(sopt
, &optval
, sizeof optval
,
414 ipxp
->ipxp_flags
|= mask
;
416 ipxp
->ipxp_flags
&= ~mask
;
419 case SO_DEFAULT_HEADERS
:
420 error
= sooptcopyin(sopt
, &ioptval
, sizeof ioptval
,
424 ipxp
->ipxp_dpt
= ioptval
.ipx_pt
;
428 error
= ipxip_route(so
, sopt
);
433 case SO_IPXTUNNEL_ROUTE
:
434 error
= ipxtun_route(so
, sopt
);
447 ipx_usr_abort(struct socket
*so
)
449 struct ipxpcb
*ipxp
= sotoipxpcb(so
);
455 soisdisconnected(so
);
460 ipx_attach(struct socket
*so
, int proto
, struct pru_attach_info
*ai
)
463 struct ipxpcb
*ipxp
= sotoipxpcb(so
);
468 error
= ipx_pcballoc(so
, &ipxpcb
);
471 error
= soreserve(so
, ipxsendspace
, ipxrecvspace
,
477 ipx_bind(struct socket
*so
, struct sockaddr
*nam
, struct thread
*td
)
479 struct ipxpcb
*ipxp
= sotoipxpcb(so
);
481 return (ipx_pcbbind(ipxp
, nam
, td
));
485 ipx_connect(struct socket
*so
, struct sockaddr
*nam
, struct thread
*td
)
488 struct ipxpcb
*ipxp
= sotoipxpcb(so
);
490 if (!ipx_nullhost(ipxp
->ipxp_faddr
))
493 error
= ipx_pcbconnect(ipxp
, nam
, td
);
501 ipx_detach(struct socket
*so
)
503 struct ipxpcb
*ipxp
= sotoipxpcb(so
);
514 ipx_disconnect(struct socket
*so
)
516 struct ipxpcb
*ipxp
= sotoipxpcb(so
);
518 if (ipx_nullhost(ipxp
->ipxp_faddr
))
521 ipx_pcbdisconnect(ipxp
);
523 soisdisconnected(so
);
528 ipx_peeraddr(struct socket
*so
, struct sockaddr
**nam
)
530 struct ipxpcb
*ipxp
= sotoipxpcb(so
);
532 ipx_setpeeraddr(ipxp
, nam
);
537 ipx_send(struct socket
*so
, int flags
, struct mbuf
*m
, struct sockaddr
*nam
,
538 struct mbuf
*control
, struct thread
*td
)
541 struct ipxpcb
*ipxp
= sotoipxpcb(so
);
542 struct ipx_addr laddr
;
546 laddr
= ipxp
->ipxp_laddr
;
547 if (!ipx_nullhost(ipxp
->ipxp_faddr
)) {
552 * Must block input while temporarily connected.
554 error
= ipx_pcbconnect(ipxp
, nam
, td
);
559 if (ipx_nullhost(ipxp
->ipxp_faddr
)) {
564 error
= ipx_output(ipxp
, m
);
567 ipx_pcbdisconnect(ipxp
);
568 ipxp
->ipxp_laddr
= laddr
;
578 ipx_shutdown(struct socket
*so
)
585 ipx_sockaddr(struct socket
*so
, struct sockaddr
**nam
)
587 struct ipxpcb
*ipxp
= sotoipxpcb(so
);
589 ipx_setsockaddr(ipxp
, nam
); /* XXX what if alloc fails? */
594 ripx_attach(struct socket
*so
, int proto
, struct pru_attach_info
*ai
)
597 struct ipxpcb
*ipxp
= sotoipxpcb(so
);
599 if ((error
= suser_cred(ai
->p_ucred
, NULL_CRED_OKAY
)) != 0)
602 error
= ipx_pcballoc(so
, &ipxrawpcb
);
606 error
= soreserve(so
, ipxsendspace
, ipxrecvspace
, ai
->sb_rlimit
);
609 ipxp
= sotoipxpcb(so
);
610 ipxp
->ipxp_faddr
.x_host
= ipx_broadhost
;
611 ipxp
->ipxp_flags
= IPXP_RAWIN
| IPXP_RAWOUT
;