ipx_usrreq.c revision 157366
138032Speter/*- 2141862Sgshapiro * Copyright (c) 1984, 1985, 1986, 1987, 1993 364565Sgshapiro * The Regents of the University of California. 438032Speter * Copyright (c) 1995, Mike Mitchell 538032Speter * Copyright (c) 2004-2006 Robert N. M. Watson 638032Speter * All rights reserved. 738032Speter * 838032Speter * Redistribution and use in source and binary forms, with or without 938032Speter * modification, are permitted provided that the following conditions 1038032Speter * are met: 1138032Speter * 1. Redistributions of source code must retain the above copyright 12121826Sgshapiro * notice, this list of conditions and the following disclaimer. 1338032Speter * 2. Redistributions in binary form must reproduce the above copyright 1438032Speter * notice, this list of conditions and the following disclaimer in the 1590795Sgshapiro * documentation and/or other materials provided with the distribution. 1690795Sgshapiro * 3. All advertising materials mentioning features or use of this software 1790795Sgshapiro * must display the following acknowledgement: 18141862Sgshapiro * This product includes software developed by the University of 1964565Sgshapiro * California, Berkeley and its contributors. 2064565Sgshapiro * 4. Neither the name of the University nor the names of its contributors 2164565Sgshapiro * may be used to endorse or promote products derived from this software 2290795Sgshapiro * without specific prior written permission. 2338032Speter * 24141862Sgshapiro * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2564565Sgshapiro * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2638032Speter * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2738032Speter * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2838032Speter * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2938032Speter * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 3038032Speter * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 3138032Speter * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 3238032Speter * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3338032Speter * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3438032Speter * SUCH DAMAGE. 3538032Speter * 3638032Speter * @(#)ipx_usrreq.c 3738032Speter */ 3838032Speter 3938032Speter#include <sys/cdefs.h> 4038032Speter__FBSDID("$FreeBSD: head/sys/netipx/ipx_usrreq.c 157366 2006-04-01 15:15:05Z rwatson $"); 4138081Speter 4238032Speter#include "opt_ipx.h" 4338032Speter 4464565Sgshapiro#include <sys/param.h> 4564565Sgshapiro#include <sys/kernel.h> 4664565Sgshapiro#include <sys/lock.h> 4738032Speter#include <sys/mbuf.h> 4838032Speter#include <sys/protosw.h> 4964565Sgshapiro#include <sys/signalvar.h> 5038032Speter#include <sys/socket.h> 5138032Speter#include <sys/socketvar.h> 5238032Speter#include <sys/sx.h> 5338032Speter#include <sys/sysctl.h> 5438032Speter#include <sys/systm.h> 5538032Speter 5638032Speter#include <net/if.h> 5790795Sgshapiro#include <net/route.h> 5898125Sgshapiro 5990795Sgshapiro#include <netinet/in.h> 6038032Speter 61105016Sgshapiro#include <netipx/ipx.h> 62105016Sgshapiro#include <netipx/ipx_if.h> 6338032Speter#include <netipx/ipx_ip.h> 6438032Speter#include <netipx/ipx_pcb.h> 6564565Sgshapiro#include <netipx/ipx_var.h> 6638032Speter 6738032Speter/* 6864565Sgshapiro * IPX protocol implementation. 6938032Speter */ 7038032Speter 7138032Speterstatic int ipxsendspace = IPXSNDQ; 7238032SpeterSYSCTL_INT(_net_ipx_ipx, OID_AUTO, ipxsendspace, CTLFLAG_RW, 7390795Sgshapiro &ipxsendspace, 0, ""); 7490795Sgshapirostatic int ipxrecvspace = IPXRCVQ; 7564565SgshapiroSYSCTL_INT(_net_ipx_ipx, OID_AUTO, ipxrecvspace, CTLFLAG_RW, 7638032Speter &ipxrecvspace, 0, ""); 7738032Speter 7890795Sgshapirostatic void ipx_usr_abort(struct socket *so); 7990795Sgshapirostatic int ipx_attach(struct socket *so, int proto, struct thread *td); 8090795Sgshapirostatic int ipx_bind(struct socket *so, struct sockaddr *nam, struct thread *td); 8190795Sgshapirostatic int ipx_connect(struct socket *so, struct sockaddr *nam, 8290795Sgshapiro struct thread *td); 8364565Sgshapirostatic int ipx_detach(struct socket *so); 8438032Speterstatic int ipx_disconnect(struct socket *so); 8538032Speterstatic int ipx_send(struct socket *so, int flags, struct mbuf *m, 8638032Speter struct sockaddr *addr, struct mbuf *control, 8738032Speter struct thread *td); 8838032Speterstatic int ipx_shutdown(struct socket *so); 8938032Speterstatic int ripx_attach(struct socket *so, int proto, struct thread *td); 9090795Sgshapirostatic int ipx_output(struct ipxpcb *ipxp, struct mbuf *m0); 9190795Sgshapiro 9290795Sgshapirostruct pr_usrreqs ipx_usrreqs = { 9390795Sgshapiro .pru_abort = ipx_usr_abort, 9490795Sgshapiro .pru_attach = ipx_attach, 9564565Sgshapiro .pru_bind = ipx_bind, 9638032Speter .pru_connect = ipx_connect, 9764565Sgshapiro .pru_control = ipx_control, 9864565Sgshapiro .pru_detach = ipx_detach, 9964565Sgshapiro .pru_disconnect = ipx_disconnect, 100141862Sgshapiro .pru_peeraddr = ipx_peeraddr, 101141862Sgshapiro .pru_send = ipx_send, 10264565Sgshapiro .pru_shutdown = ipx_shutdown, 10364565Sgshapiro .pru_sockaddr = ipx_sockaddr, 10464565Sgshapiro}; 10564565Sgshapiro 10664565Sgshapirostruct pr_usrreqs ripx_usrreqs = { 10764565Sgshapiro .pru_abort = ipx_usr_abort, 10864565Sgshapiro .pru_attach = ripx_attach, 10964565Sgshapiro .pru_bind = ipx_bind, 11064565Sgshapiro .pru_connect = ipx_connect, 11164565Sgshapiro .pru_control = ipx_control, 11264565Sgshapiro .pru_detach = ipx_detach, 11364565Sgshapiro .pru_disconnect = ipx_disconnect, 11464565Sgshapiro .pru_peeraddr = ipx_peeraddr, 115141862Sgshapiro .pru_send = ipx_send, 11664565Sgshapiro .pru_shutdown = ipx_shutdown, 11764565Sgshapiro .pru_sockaddr = ipx_sockaddr, 11890795Sgshapiro}; 11990795Sgshapiro 12064565Sgshapiro/* 12164565Sgshapiro * This may also be called for raw listeners. 12264565Sgshapiro */ 12364565Sgshapirovoid 124125823Sgshapiroipx_input(m, ipxp) 12564565Sgshapiro struct mbuf *m; 126125823Sgshapiro register struct ipxpcb *ipxp; 12764565Sgshapiro{ 12890795Sgshapiro register struct ipx *ipx = mtod(m, struct ipx *); 12990795Sgshapiro struct ifnet *ifp = m->m_pkthdr.rcvif; 13064565Sgshapiro struct sockaddr_ipx ipx_ipx; 13164565Sgshapiro 13264565Sgshapiro KASSERT(ipxp != NULL, ("ipx_input: NULL ipxpcb")); 13364565Sgshapiro IPX_LOCK_ASSERT(ipxp); 13464565Sgshapiro /* 13564565Sgshapiro * Construct sockaddr format source address. 13698125Sgshapiro * Stuff source address and datagram in user buffer. 137125823Sgshapiro */ 13864565Sgshapiro ipx_ipx.sipx_len = sizeof(ipx_ipx); 13964565Sgshapiro ipx_ipx.sipx_family = AF_IPX; 14038032Speter ipx_ipx.sipx_addr = ipx->ipx_sna; 14138032Speter ipx_ipx.sipx_zero[0] = '\0'; 14238032Speter ipx_ipx.sipx_zero[1] = '\0'; 14338032Speter if (ipx_neteqnn(ipx->ipx_sna.x_net, ipx_zeronet) && ifp != NULL) { 14438032Speter register struct ifaddr *ifa; 14538032Speter 14638032Speter for (ifa = TAILQ_FIRST(&ifp->if_addrhead); ifa != NULL; 14764565Sgshapiro ifa = TAILQ_NEXT(ifa, ifa_link)) { 14838032Speter if (ifa->ifa_addr->sa_family == AF_IPX) { 14964565Sgshapiro ipx_ipx.sipx_addr.x_net = 15064565Sgshapiro IA_SIPX(ifa)->sipx_addr.x_net; 15138032Speter break; 15238032Speter } 15364565Sgshapiro } 154105016Sgshapiro } 15538032Speter ipxp->ipxp_rpt = ipx->ipx_pt; 15664565Sgshapiro if ((ipxp->ipxp_flags & IPXP_RAWIN) == 0) { 15764565Sgshapiro m->m_len -= sizeof(struct ipx); 15838032Speter m->m_pkthdr.len -= sizeof(struct ipx); 15964565Sgshapiro m->m_data += sizeof(struct ipx); 16038032Speter } 16164565Sgshapiro if (sbappendaddr(&ipxp->ipxp_socket->so_rcv, 16264565Sgshapiro (struct sockaddr *)&ipx_ipx, m, NULL) == 0) 16338032Speter m_freem(m); 16498125Sgshapiro else 16538032Speter sorwakeup(ipxp->ipxp_socket); 16638032Speter} 16738032Speter 16838032Speter/* 16938032Speter * Drop connection, reporting 17038032Speter * the specified error. 17138032Speter */ 17264565Sgshapirovoid 17364565Sgshapiroipx_drop(ipxp, errno) 17438032Speter register struct ipxpcb *ipxp; 17538032Speter int errno; 17690795Sgshapiro{ 17790795Sgshapiro struct socket *so = ipxp->ipxp_socket; 17864565Sgshapiro 17938032Speter IPX_LIST_LOCK_ASSERT(); 18064565Sgshapiro IPX_LOCK_ASSERT(ipxp); 18138032Speter 18238032Speter /* 18338032Speter * someday, in the IPX world 18477352Sgshapiro * we will generate error protocol packets 18577352Sgshapiro * announcing that the socket has gone away. 18638032Speter * 18738032Speter * XXX Probably never. IPX does not have error packets. 18838032Speter */ 18938032Speter /*if (TCPS_HAVERCVDSYN(tp->t_state)) { 19038032Speter tp->t_state = TCPS_CLOSED; 19138032Speter tcp_output(tp); 19238032Speter }*/ 19364565Sgshapiro so->so_error = errno; 19438032Speter ipx_pcbdisconnect(ipxp); 19564565Sgshapiro soisdisconnected(so); 19664565Sgshapiro} 19764565Sgshapiro 19838032Speterstatic int 19938032Speteripx_output(ipxp, m0) 20090795Sgshapiro struct ipxpcb *ipxp; 20164565Sgshapiro struct mbuf *m0; 20264565Sgshapiro{ 20390795Sgshapiro register struct ipx *ipx; 20438032Speter register struct socket *so; 20538032Speter register int len = 0; 20638032Speter register struct route *ro; 20738032Speter struct mbuf *m; 20838032Speter struct mbuf *mprev = NULL; 20990795Sgshapiro 21038032Speter IPX_LOCK_ASSERT(ipxp); 21190795Sgshapiro 21290795Sgshapiro /* 21364565Sgshapiro * Calculate data length. 21464565Sgshapiro */ 21564565Sgshapiro for (m = m0; m != NULL; m = m->m_next) { 21638032Speter mprev = m; 21738032Speter len += m->m_len; 21838032Speter } 21964565Sgshapiro /* 22064565Sgshapiro * Make sure packet is actually of even length. 22190795Sgshapiro */ 22238032Speter 22398125Sgshapiro if (len & 1) { 22438032Speter m = mprev; 22564565Sgshapiro if ((m->m_flags & M_EXT) == 0 && 22664565Sgshapiro (m->m_len + m->m_data < &m->m_dat[MLEN])) { 22764565Sgshapiro mtod(m, char*)[m->m_len++] = 0; 22864565Sgshapiro } else { 22938032Speter struct mbuf *m1 = m_get(M_DONTWAIT, MT_DATA); 23064565Sgshapiro 23164565Sgshapiro if (m1 == NULL) { 23264565Sgshapiro m_freem(m0); 23364565Sgshapiro return (ENOBUFS); 23438032Speter } 23564565Sgshapiro m1->m_len = 1; 23664565Sgshapiro * mtod(m1, char *) = 0; 23790795Sgshapiro m->m_next = m1; 23890795Sgshapiro } 23990795Sgshapiro m0->m_pkthdr.len++; 24064565Sgshapiro } 24190795Sgshapiro 24264565Sgshapiro /* 24364565Sgshapiro * Fill in mbuf with extended IPX header 24464565Sgshapiro * and addresses and length put into network format. 24538032Speter */ 24638032Speter m = m0; 24738032Speter if (ipxp->ipxp_flags & IPXP_RAWOUT) { 24864565Sgshapiro ipx = mtod(m, struct ipx *); 24964565Sgshapiro } else { 25064565Sgshapiro M_PREPEND(m, sizeof(struct ipx), M_DONTWAIT); 25164565Sgshapiro if (m == NULL) 25264565Sgshapiro return (ENOBUFS); 25364565Sgshapiro ipx = mtod(m, struct ipx *); 25464565Sgshapiro ipx->ipx_tc = 0; 25564565Sgshapiro ipx->ipx_pt = ipxp->ipxp_dpt; 25664565Sgshapiro ipx->ipx_sna = ipxp->ipxp_laddr; 25764565Sgshapiro ipx->ipx_dna = ipxp->ipxp_faddr; 25864565Sgshapiro len += sizeof(struct ipx); 25964565Sgshapiro } 26064565Sgshapiro 26164565Sgshapiro ipx->ipx_len = htons((u_short)len); 26264565Sgshapiro 26364565Sgshapiro if (ipxp->ipxp_flags & IPXP_CHECKSUM) { 26464565Sgshapiro ipx->ipx_sum = ipx_cksum(m, len); 26564565Sgshapiro } else 26664565Sgshapiro ipx->ipx_sum = 0xffff; 26738032Speter 26864565Sgshapiro /* 26964565Sgshapiro * Output datagram. 27064565Sgshapiro */ 27190795Sgshapiro so = ipxp->ipxp_socket; 27298125Sgshapiro if (so->so_options & SO_DONTROUTE) 27364565Sgshapiro return (ipx_outputfl(m, (struct route *)NULL, 27464565Sgshapiro (so->so_options & SO_BROADCAST) | IPX_ROUTETOIF)); 27590795Sgshapiro /* 27664565Sgshapiro * Use cached route for previous datagram if 27764565Sgshapiro * possible. If the previous net was the same 27864565Sgshapiro * and the interface was a broadcast medium, or 27964565Sgshapiro * if the previous destination was identical, 28090795Sgshapiro * then we are ok. 28198125Sgshapiro * 28264565Sgshapiro * NB: We don't handle broadcasts because that 28364565Sgshapiro * would require 3 subroutine calls. 28464565Sgshapiro */ 28564565Sgshapiro ro = &ipxp->ipxp_route; 28698125Sgshapiro#ifdef ancient_history 28798125Sgshapiro /* 28864565Sgshapiro * I think that this will all be handled in ipx_pcbconnect! 28964565Sgshapiro */ 29064565Sgshapiro if (ro->ro_rt != NULL) { 29198125Sgshapiro if(ipx_neteq(ipxp->ipxp_lastdst, ipx->ipx_dna)) { 29298125Sgshapiro /* 29398125Sgshapiro * This assumes we have no GH type routes 29498125Sgshapiro */ 29598125Sgshapiro if (ro->ro_rt->rt_flags & RTF_HOST) { 29698125Sgshapiro if (!ipx_hosteq(ipxp->ipxp_lastdst, ipx->ipx_dna)) 297110563Sgshapiro goto re_route; 29898125Sgshapiro 29998125Sgshapiro } 30098125Sgshapiro if ((ro->ro_rt->rt_flags & RTF_GATEWAY) == 0) { 30198125Sgshapiro register struct ipx_addr *dst = 302110563Sgshapiro &satoipx_addr(ro->ro_dst); 30398125Sgshapiro dst->x_host = ipx->ipx_dna.x_host; 30498125Sgshapiro } 30598125Sgshapiro /* 30698125Sgshapiro * Otherwise, we go through the same gateway 30798125Sgshapiro * and dst is already set up. 30864565Sgshapiro */ 30990795Sgshapiro } else { 31090795Sgshapiro re_route: 31164565Sgshapiro RTFREE(ro->ro_rt); 312105016Sgshapiro ro->ro_rt = NULL; 313105016Sgshapiro } 314105016Sgshapiro } 315105016Sgshapiro ipxp->ipxp_lastdst = ipx->ipx_dna; 316110563Sgshapiro#endif /* ancient_history */ 317105016Sgshapiro return (ipx_outputfl(m, ro, so->so_options & SO_BROADCAST)); 318105016Sgshapiro} 319105016Sgshapiro 320105016Sgshapiroint 321110563Sgshapiroipx_ctloutput(so, sopt) 322105016Sgshapiro struct socket *so; 323105016Sgshapiro struct sockopt *sopt; 324105016Sgshapiro{ 325105016Sgshapiro struct ipxpcb *ipxp = sotoipxpcb(so); 326105016Sgshapiro int mask, error, optval; 327105016Sgshapiro short soptval; 328105016Sgshapiro struct ipx ioptval; 329105016Sgshapiro long seq; 330105016Sgshapiro 331105016Sgshapiro KASSERT(ipxp != NULL, ("ipx_ctloutput: ipxp == NULL")); 332105016Sgshapiro error = 0; 333105016Sgshapiro 334110563Sgshapiro switch (sopt->sopt_dir) { 335105016Sgshapiro case SOPT_GET: 336105016Sgshapiro switch (sopt->sopt_name) { 337105016Sgshapiro case SO_ALL_PACKETS: 338105016Sgshapiro mask = IPXP_ALL_PACKETS; 339110563Sgshapiro goto get_flags; 340105016Sgshapiro 341105016Sgshapiro case SO_HEADERS_ON_INPUT: 342105016Sgshapiro mask = IPXP_RAWIN; 343105016Sgshapiro goto get_flags; 34464565Sgshapiro 34564565Sgshapiro case SO_IPX_CHECKSUM: 34664565Sgshapiro mask = IPXP_CHECKSUM; 34790795Sgshapiro goto get_flags; 348110563Sgshapiro 34990795Sgshapiro case SO_HEADERS_ON_OUTPUT: 35064565Sgshapiro mask = IPXP_RAWOUT; 35164565Sgshapiro get_flags: 35264565Sgshapiro /* Unlocked read. */ 353110563Sgshapiro soptval = ipxp->ipxp_flags & mask; 35490795Sgshapiro error = sooptcopyout(sopt, &soptval, sizeof soptval); 35564565Sgshapiro break; 35664565Sgshapiro 35764565Sgshapiro case SO_DEFAULT_HEADERS: 35838032Speter ioptval.ipx_len = 0; 35964565Sgshapiro ioptval.ipx_sum = 0; 36064565Sgshapiro ioptval.ipx_tc = 0; 36164565Sgshapiro IPX_LOCK(ipxp); 36264565Sgshapiro ioptval.ipx_pt = ipxp->ipxp_dpt; 36390795Sgshapiro ioptval.ipx_dna = ipxp->ipxp_faddr; 36464565Sgshapiro ioptval.ipx_sna = ipxp->ipxp_laddr; 36590795Sgshapiro IPX_UNLOCK(ipxp); 36664565Sgshapiro error = sooptcopyout(sopt, &soptval, sizeof soptval); 36738032Speter break; 36838032Speter 36964565Sgshapiro case SO_SEQNO: 37064565Sgshapiro IPX_LIST_LOCK(); 37164565Sgshapiro seq = ipx_pexseq; 37264565Sgshapiro ipx_pexseq++; 37390795Sgshapiro IPX_LIST_UNLOCK(); 37490795Sgshapiro error = sooptcopyout(sopt, &seq, sizeof seq); 37590795Sgshapiro break; 37664565Sgshapiro 37764565Sgshapiro default: 37864565Sgshapiro error = EINVAL; 37990795Sgshapiro } 38090795Sgshapiro break; 38190795Sgshapiro 38264565Sgshapiro case SOPT_SET: 38364565Sgshapiro switch (sopt->sopt_name) { 38464565Sgshapiro case SO_ALL_PACKETS: 38564565Sgshapiro mask = IPXP_ALL_PACKETS; 38664565Sgshapiro goto set_head; 38764565Sgshapiro 38864565Sgshapiro case SO_HEADERS_ON_INPUT: 38990795Sgshapiro mask = IPXP_RAWIN; 39064565Sgshapiro goto set_head; 39164565Sgshapiro 39264565Sgshapiro case SO_IPX_CHECKSUM: 39364565Sgshapiro mask = IPXP_CHECKSUM; 39490795Sgshapiro 39590795Sgshapiro case SO_HEADERS_ON_OUTPUT: 39664565Sgshapiro mask = IPXP_RAWOUT; 39764565Sgshapiro set_head: 39890795Sgshapiro error = sooptcopyin(sopt, &optval, sizeof optval, 39964565Sgshapiro sizeof optval); 40038032Speter if (error) 40198125Sgshapiro break; 40264565Sgshapiro IPX_LOCK(ipxp); 40364565Sgshapiro if (optval) 40490795Sgshapiro ipxp->ipxp_flags |= mask; 40590795Sgshapiro else 40664565Sgshapiro ipxp->ipxp_flags &= ~mask; 40790795Sgshapiro IPX_UNLOCK(ipxp); 40890795Sgshapiro break; 40964565Sgshapiro 41064565Sgshapiro case SO_DEFAULT_HEADERS: 41138032Speter error = sooptcopyin(sopt, &ioptval, sizeof ioptval, 41264565Sgshapiro sizeof ioptval); 41364565Sgshapiro if (error) 41464565Sgshapiro break; 41590795Sgshapiro /* Unlocked write. */ 41690795Sgshapiro ipxp->ipxp_dpt = ioptval.ipx_pt; 41764565Sgshapiro break; 41864565Sgshapiro#ifdef IPXIP 41964565Sgshapiro case SO_IPXIP_ROUTE: 42064565Sgshapiro error = ipxip_route(so, sopt); 42164565Sgshapiro break; 42238032Speter#endif /* IPXIP */ 42338032Speter default: 42438032Speter error = EINVAL; 42538032Speter } 42638032Speter break; 42738032Speter } 42890795Sgshapiro return (error); 42964565Sgshapiro} 430121826Sgshapiro 431121826Sgshapirostatic void 43264565Sgshapiroipx_usr_abort(so) 43364565Sgshapiro struct socket *so; 43490795Sgshapiro{ 43564565Sgshapiro struct ipxpcb *ipxp = sotoipxpcb(so); 43664565Sgshapiro 43790795Sgshapiro KASSERT(ipxp != NULL, ("ipx_usr_abort: ipxp == NULL")); 43838032Speter IPX_LIST_LOCK(); 43964565Sgshapiro IPX_LOCK(ipxp); 44064565Sgshapiro ipx_pcbdetach(ipxp); 44138032Speter ipx_pcbfree(ipxp); 442 IPX_LIST_UNLOCK(); 443 soisdisconnected(so); 444} 445 446static int 447ipx_attach(so, proto, td) 448 struct socket *so; 449 int proto; 450 struct thread *td; 451{ 452 struct ipxpcb *ipxp = sotoipxpcb(so); 453 int error; 454 455 KASSERT(ipxp == NULL, ("ipx_attach: ipxp != NULL")); 456 error = soreserve(so, ipxsendspace, ipxrecvspace); 457 if (error != 0) 458 return (error); 459 IPX_LIST_LOCK(); 460 error = ipx_pcballoc(so, &ipxpcb_list, td); 461 IPX_LIST_UNLOCK(); 462 return (error); 463} 464 465static int 466ipx_bind(so, nam, td) 467 struct socket *so; 468 struct sockaddr *nam; 469 struct thread *td; 470{ 471 struct ipxpcb *ipxp = sotoipxpcb(so); 472 int error; 473 474 KASSERT(ipxp != NULL, ("ipx_bind: ipxp == NULL")); 475 IPX_LIST_LOCK(); 476 IPX_LOCK(ipxp); 477 error = ipx_pcbbind(ipxp, nam, td); 478 IPX_UNLOCK(ipxp); 479 IPX_LIST_UNLOCK(); 480 return (error); 481} 482 483static int 484ipx_connect(so, nam, td) 485 struct socket *so; 486 struct sockaddr *nam; 487 struct thread *td; 488{ 489 struct ipxpcb *ipxp = sotoipxpcb(so); 490 int error; 491 492 KASSERT(ipxp != NULL, ("ipx_connect: ipxp == NULL")); 493 IPX_LIST_LOCK(); 494 IPX_LOCK(ipxp); 495 if (!ipx_nullhost(ipxp->ipxp_faddr)) { 496 error = EISCONN; 497 goto out; 498 } 499 error = ipx_pcbconnect(ipxp, nam, td); 500 if (error == 0) 501 soisconnected(so); 502out: 503 IPX_UNLOCK(ipxp); 504 IPX_LIST_UNLOCK(); 505 return (error); 506} 507 508static int 509ipx_detach(so) 510 struct socket *so; 511{ 512 struct ipxpcb *ipxp = sotoipxpcb(so); 513 514 KASSERT(ipxp != NULL, ("ipx_detach: ipxp == NULL")); 515 IPX_LIST_LOCK(); 516 IPX_LOCK(ipxp); 517 ipx_pcbdetach(ipxp); 518 ipx_pcbfree(ipxp); 519 IPX_LIST_UNLOCK(); 520 return (0); 521} 522 523static int 524ipx_disconnect(so) 525 struct socket *so; 526{ 527 struct ipxpcb *ipxp = sotoipxpcb(so); 528 int error; 529 530 KASSERT(ipxp != NULL, ("ipx_disconnect: ipxp == NULL")); 531 IPX_LIST_LOCK(); 532 IPX_LOCK(ipxp); 533 error = 0; 534 if (ipx_nullhost(ipxp->ipxp_faddr)) { 535 error = ENOTCONN; 536 goto out; 537 } 538 ipx_pcbdisconnect(ipxp); 539 soisdisconnected(so); 540out: 541 IPX_UNLOCK(ipxp); 542 IPX_LIST_UNLOCK(); 543 return (0); 544} 545 546int 547ipx_peeraddr(so, nam) 548 struct socket *so; 549 struct sockaddr **nam; 550{ 551 struct ipxpcb *ipxp = sotoipxpcb(so); 552 553 KASSERT(ipxp != NULL, ("ipx_peeraddr: ipxp == NULL")); 554 ipx_setpeeraddr(ipxp, nam); 555 return (0); 556} 557 558static int 559ipx_send(so, flags, m, nam, control, td) 560 struct socket *so; 561 int flags; 562 struct mbuf *m; 563 struct sockaddr *nam; 564 struct mbuf *control; 565 struct thread *td; 566{ 567 int error; 568 struct ipxpcb *ipxp = sotoipxpcb(so); 569 struct ipx_addr laddr; 570 571 KASSERT(ipxp != NULL, ("ipxp_send: ipxp == NULL")); 572 /* 573 * Attempt to only acquire the necessary locks: if the socket is 574 * already connected, we don't need to hold the IPX list lock to be 575 * used by ipx_pcbconnect() and ipx_pcbdisconnect(), just the IPX 576 * pcb lock. 577 */ 578 if (nam != NULL) { 579 IPX_LIST_LOCK(); 580 IPX_LOCK(ipxp); 581 laddr = ipxp->ipxp_laddr; 582 if (!ipx_nullhost(ipxp->ipxp_faddr)) { 583 IPX_UNLOCK(ipxp); 584 IPX_LIST_UNLOCK(); 585 error = EISCONN; 586 goto send_release; 587 } 588 /* 589 * Must block input while temporarily connected. 590 */ 591 error = ipx_pcbconnect(ipxp, nam, td); 592 if (error) { 593 IPX_UNLOCK(ipxp); 594 IPX_LIST_UNLOCK(); 595 goto send_release; 596 } 597 } else { 598 IPX_LOCK(ipxp); 599 if (ipx_nullhost(ipxp->ipxp_faddr)) { 600 IPX_UNLOCK(ipxp); 601 error = ENOTCONN; 602 goto send_release; 603 } 604 } 605 error = ipx_output(ipxp, m); 606 m = NULL; 607 if (nam != NULL) { 608 ipx_pcbdisconnect(ipxp); 609 ipxp->ipxp_laddr = laddr; 610 IPX_UNLOCK(ipxp); 611 IPX_LIST_UNLOCK(); 612 } else 613 IPX_UNLOCK(ipxp); 614 615send_release: 616 if (m != NULL) 617 m_freem(m); 618 return (error); 619} 620 621static int 622ipx_shutdown(so) 623 struct socket *so; 624{ 625 626 KASSERT(so->so_pcb != NULL, ("ipx_shutdown: so_pcb == NULL")); 627 socantsendmore(so); 628 return (0); 629} 630 631int 632ipx_sockaddr(so, nam) 633 struct socket *so; 634 struct sockaddr **nam; 635{ 636 struct ipxpcb *ipxp = sotoipxpcb(so); 637 638 KASSERT(ipxp != NULL, ("ipx_sockaddr: ipxp == NULL")); 639 ipx_setsockaddr(ipxp, nam); 640 return (0); 641} 642 643static int 644ripx_attach(so, proto, td) 645 struct socket *so; 646 int proto; 647 struct thread *td; 648{ 649 int error = 0; 650 struct ipxpcb *ipxp = sotoipxpcb(so); 651 652 KASSERT(ipxp == NULL, ("ripx_attach: ipxp != NULL")); 653 if (td != NULL && (error = suser(td)) != 0) 654 return (error); 655 /* 656 * We hold the IPX list lock for the duration as address parameters 657 * of the IPX pcb are changed. Since no one else holds a reference 658 * to the ipxpcb yet, we don't need the ipxpcb lock here. 659 */ 660 IPX_LIST_LOCK(); 661 error = ipx_pcballoc(so, &ipxrawpcb_list, td); 662 if (error) 663 goto out; 664 ipxp = sotoipxpcb(so); 665 error = soreserve(so, ipxsendspace, ipxrecvspace); 666 if (error) 667 goto out; 668 ipxp->ipxp_faddr.x_host = ipx_broadhost; 669 ipxp->ipxp_flags = IPXP_RAWIN | IPXP_RAWOUT; 670out: 671 IPX_LIST_UNLOCK(); 672 return (error); 673} 674