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>
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
) {
160 struct ifaddr_container
*ifac
;
162 TAILQ_FOREACH(ifac
, &ifp
->if_addrheads
[mycpuid
], ifa_link
) {
163 struct ifaddr
*ifa
= ifac
->ifa
;
165 if (ifa
->ifa_addr
->sa_family
== AF_IPX
) {
166 ipx_ipx
.sipx_addr
.x_net
=
167 IA_SIPX(ifa
)->sipx_addr
.x_net
;
172 ipxp
->ipxp_rpt
= ipx
->ipx_pt
;
173 if (!(ipxp
->ipxp_flags
& IPXP_RAWIN
) ) {
174 m
->m_len
-= sizeof(struct ipx
);
175 m
->m_pkthdr
.len
-= sizeof(struct ipx
);
176 m
->m_data
+= sizeof(struct ipx
);
178 if (ssb_appendaddr(&ipxp
->ipxp_socket
->so_rcv
, (struct sockaddr
*)&ipx_ipx
,
179 m
, (struct mbuf
*)NULL
) == 0)
181 sorwakeup(ipxp
->ipxp_socket
);
188 ipx_abort(struct ipxpcb
*ipxp
)
190 struct socket
*so
= ipxp
->ipxp_socket
;
192 ipx_pcbdisconnect(ipxp
);
193 soisdisconnected(so
);
197 * Drop connection, reporting
198 * the specified error.
201 ipx_drop(struct ipxpcb
*ipxp
, int errno
)
203 struct socket
*so
= ipxp
->ipxp_socket
;
206 * someday, in the IPX world
207 * we will generate error protocol packets
208 * announcing that the socket has gone away.
210 * XXX Probably never. IPX does not have error packets.
212 /*if (TCPS_HAVERCVDSYN(tp->t_state)) {
213 tp->t_state = TCPS_CLOSED;
216 so
->so_error
= errno
;
217 ipx_pcbdisconnect(ipxp
);
218 soisdisconnected(so
);
222 ipx_output(struct ipxpcb
*ipxp
, struct mbuf
*m0
)
229 struct mbuf
*mprev
= NULL
;
232 * Calculate data length.
234 for (m
= m0
; m
!= NULL
; m
= m
->m_next
) {
239 * Make sure packet is actually of even length.
244 if ((m
->m_flags
& M_EXT
) == 0 &&
245 (m
->m_len
+ m
->m_data
< &m
->m_dat
[MLEN
])) {
246 mtod(m
, char*)[m
->m_len
++] = 0;
248 struct mbuf
*m1
= m_get(MB_DONTWAIT
, MT_DATA
);
255 * mtod(m1
, char *) = 0;
262 * Fill in mbuf with extended IPX header
263 * and addresses and length put into network format.
266 if (ipxp
->ipxp_flags
& IPXP_RAWOUT
) {
267 ipx
= mtod(m
, struct ipx
*);
269 M_PREPEND(m
, sizeof(struct ipx
), MB_DONTWAIT
);
272 ipx
= mtod(m
, struct ipx
*);
274 ipx
->ipx_pt
= ipxp
->ipxp_dpt
;
275 ipx
->ipx_sna
= ipxp
->ipxp_laddr
;
276 ipx
->ipx_dna
= ipxp
->ipxp_faddr
;
277 len
+= sizeof(struct ipx
);
280 ipx
->ipx_len
= htons((u_short
)len
);
282 if (ipxp
->ipxp_flags
& IPXP_CHECKSUM
) {
283 ipx
->ipx_sum
= ipx_cksum(m
, len
);
285 ipx
->ipx_sum
= 0xffff;
290 so
= ipxp
->ipxp_socket
;
291 if (so
->so_options
& SO_DONTROUTE
)
292 return (ipx_outputfl(m
, (struct route
*)NULL
,
293 (so
->so_options
& SO_BROADCAST
) | IPX_ROUTETOIF
));
295 * Use cached route for previous datagram if
296 * possible. If the previous net was the same
297 * and the interface was a broadcast medium, or
298 * if the previous destination was identical,
301 * NB: We don't handle broadcasts because that
302 * would require 3 subroutine calls.
304 ro
= &ipxp
->ipxp_route
;
305 #ifdef ancient_history
307 * I think that this will all be handled in ipx_pcbconnect!
309 if (ro
->ro_rt
!= NULL
) {
310 if(ipx_neteq(ipxp
->ipxp_lastdst
, ipx
->ipx_dna
)) {
312 * This assumes we have no GH type routes
314 if (ro
->ro_rt
->rt_flags
& RTF_HOST
) {
315 if (!ipx_hosteq(ipxp
->ipxp_lastdst
, ipx
->ipx_dna
))
319 if ((ro
->ro_rt
->rt_flags
& RTF_GATEWAY
) == 0) {
320 struct ipx_addr
*dst
=
321 &satoipx_addr(ro
->ro_dst
);
322 dst
->x_host
= ipx
->ipx_dna
.x_host
;
325 * Otherwise, we go through the same gateway
326 * and dst is already set up.
334 ipxp
->ipxp_lastdst
= ipx
->ipx_dna
;
335 #endif /* ancient_history */
336 return (ipx_outputfl(m
, ro
, so
->so_options
& SO_BROADCAST
));
340 ipx_ctloutput(struct socket
*so
, struct sockopt
*sopt
)
342 struct ipxpcb
*ipxp
= sotoipxpcb(so
);
343 int mask
, error
, optval
;
351 switch (sopt
->sopt_dir
) {
353 switch (sopt
->sopt_name
) {
355 mask
= IPXP_ALL_PACKETS
;
358 case SO_HEADERS_ON_INPUT
:
362 case SO_IPX_CHECKSUM
:
363 mask
= IPXP_CHECKSUM
;
366 case SO_HEADERS_ON_OUTPUT
:
369 soptval
= ipxp
->ipxp_flags
& mask
;
370 error
= sooptcopyout(sopt
, &soptval
, sizeof soptval
);
373 case SO_DEFAULT_HEADERS
:
377 ioptval
.ipx_pt
= ipxp
->ipxp_dpt
;
378 ioptval
.ipx_dna
= ipxp
->ipxp_faddr
;
379 ioptval
.ipx_sna
= ipxp
->ipxp_laddr
;
380 error
= sooptcopyout(sopt
, &soptval
, sizeof soptval
);
384 error
= sooptcopyout(sopt
, &ipx_pexseq
,
395 switch (sopt
->sopt_name
) {
397 mask
= IPXP_ALL_PACKETS
;
400 case SO_HEADERS_ON_INPUT
:
404 case SO_IPX_CHECKSUM
:
405 mask
= IPXP_CHECKSUM
;
407 case SO_HEADERS_ON_OUTPUT
:
410 error
= sooptcopyin(sopt
, &optval
, sizeof optval
,
415 ipxp
->ipxp_flags
|= mask
;
417 ipxp
->ipxp_flags
&= ~mask
;
420 case SO_DEFAULT_HEADERS
:
421 error
= sooptcopyin(sopt
, &ioptval
, sizeof ioptval
,
425 ipxp
->ipxp_dpt
= ioptval
.ipx_pt
;
429 error
= ipxip_route(so
, sopt
);
434 case SO_IPXTUNNEL_ROUTE
:
435 error
= ipxtun_route(so
, sopt
);
448 ipx_usr_abort(struct socket
*so
)
450 struct ipxpcb
*ipxp
= sotoipxpcb(so
);
456 soisdisconnected(so
);
461 ipx_attach(struct socket
*so
, int proto
, struct pru_attach_info
*ai
)
464 struct ipxpcb
*ipxp
= sotoipxpcb(so
);
469 error
= ipx_pcballoc(so
, &ipxpcb
);
472 error
= soreserve(so
, ipxsendspace
, ipxrecvspace
,
478 ipx_bind(struct socket
*so
, struct sockaddr
*nam
, struct thread
*td
)
480 struct ipxpcb
*ipxp
= sotoipxpcb(so
);
482 return (ipx_pcbbind(ipxp
, nam
, td
));
486 ipx_connect(struct socket
*so
, struct sockaddr
*nam
, struct thread
*td
)
489 struct ipxpcb
*ipxp
= sotoipxpcb(so
);
491 if (!ipx_nullhost(ipxp
->ipxp_faddr
))
494 error
= ipx_pcbconnect(ipxp
, nam
, td
);
502 ipx_detach(struct socket
*so
)
504 struct ipxpcb
*ipxp
= sotoipxpcb(so
);
515 ipx_disconnect(struct socket
*so
)
517 struct ipxpcb
*ipxp
= sotoipxpcb(so
);
519 if (ipx_nullhost(ipxp
->ipxp_faddr
))
522 ipx_pcbdisconnect(ipxp
);
524 soisdisconnected(so
);
529 ipx_peeraddr(struct socket
*so
, struct sockaddr
**nam
)
531 struct ipxpcb
*ipxp
= sotoipxpcb(so
);
533 ipx_setpeeraddr(ipxp
, nam
);
538 ipx_send(struct socket
*so
, int flags
, struct mbuf
*m
, struct sockaddr
*nam
,
539 struct mbuf
*control
, struct thread
*td
)
542 struct ipxpcb
*ipxp
= sotoipxpcb(so
);
543 struct ipx_addr laddr
;
547 laddr
= ipxp
->ipxp_laddr
;
548 if (!ipx_nullhost(ipxp
->ipxp_faddr
)) {
553 * Must block input while temporarily connected.
555 error
= ipx_pcbconnect(ipxp
, nam
, td
);
560 if (ipx_nullhost(ipxp
->ipxp_faddr
)) {
565 error
= ipx_output(ipxp
, m
);
568 ipx_pcbdisconnect(ipxp
);
569 ipxp
->ipxp_laddr
= laddr
;
579 ipx_shutdown(struct socket
*so
)
586 ipx_sockaddr(struct socket
*so
, struct sockaddr
**nam
)
588 struct ipxpcb
*ipxp
= sotoipxpcb(so
);
590 ipx_setsockaddr(ipxp
, nam
); /* XXX what if alloc fails? */
595 ripx_attach(struct socket
*so
, int proto
, struct pru_attach_info
*ai
)
598 struct ipxpcb
*ipxp
= sotoipxpcb(so
);
600 if ((error
= suser_cred(ai
->p_ucred
, NULL_CRED_OKAY
)) != 0)
603 error
= ipx_pcballoc(so
, &ipxrawpcb
);
607 error
= soreserve(so
, ipxsendspace
, ipxrecvspace
, ai
->sb_rlimit
);
610 ipxp
= sotoipxpcb(so
);
611 ipxp
->ipxp_faddr
.x_host
= ipx_broadhost
;
612 ipxp
->ipxp_flags
= IPXP_RAWIN
| IPXP_RAWOUT
;