ipx_usrreq.c revision 139588
189857Sobrien/* 289857Sobrien * Copyright (c) 2004 Robert N. M. Watson 3218822Sdim * Copyright (c) 1995, Mike Mitchell 4218822Sdim * Copyright (c) 1984, 1985, 1986, 1987, 1993 5218822Sdim * The Regents of the University of California. All rights reserved. 6218822Sdim * 789857Sobrien * Redistribution and use in source and binary forms, with or without 889857Sobrien * modification, are permitted provided that the following conditions 989857Sobrien * are met: 1089857Sobrien * 1. Redistributions of source code must retain the above copyright 1189857Sobrien * notice, this list of conditions and the following disclaimer. 1289857Sobrien * 2. Redistributions in binary form must reproduce the above copyright 1389857Sobrien * notice, this list of conditions and the following disclaimer in the 1489857Sobrien * documentation and/or other materials provided with the distribution. 1589857Sobrien * 3. All advertising materials mentioning features or use of this software 1689857Sobrien * must display the following acknowledgement: 1789857Sobrien * This product includes software developed by the University of 1889857Sobrien * California, Berkeley and its contributors. 1989857Sobrien * 4. Neither the name of the University nor the names of its contributors 2089857Sobrien * may be used to endorse or promote products derived from this software 2189857Sobrien * without specific prior written permission. 22218822Sdim * 23218822Sdim * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2489857Sobrien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2589857Sobrien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2689857Sobrien * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2789857Sobrien * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2889857Sobrien * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2989857Sobrien * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 3089857Sobrien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 3189857Sobrien * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3289857Sobrien * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3389857Sobrien * SUCH DAMAGE. 3489857Sobrien * 3589857Sobrien * @(#)ipx_usrreq.c 3689857Sobrien */ 3789857Sobrien 3889857Sobrien#include <sys/cdefs.h> 3989857Sobrien__FBSDID("$FreeBSD: head/sys/netipx/ipx_usrreq.c 139588 2005-01-02 15:29:29Z rwatson $"); 4089857Sobrien 4189857Sobrien#include "opt_ipx.h" 4289857Sobrien 4389857Sobrien#include <sys/param.h> 4489857Sobrien#include <sys/kernel.h> 4589857Sobrien#include <sys/lock.h> 4689857Sobrien#include <sys/mbuf.h> 4789857Sobrien#include <sys/protosw.h> 4889857Sobrien#include <sys/signalvar.h> 4989857Sobrien#include <sys/socket.h> 5089857Sobrien#include <sys/socketvar.h> 5189857Sobrien#include <sys/sx.h> 5289857Sobrien#include <sys/sysctl.h> 5389857Sobrien#include <sys/systm.h> 5489857Sobrien 5589857Sobrien#include <net/if.h> 5689857Sobrien#include <net/route.h> 5789857Sobrien 5889857Sobrien#include <netinet/in.h> 5989857Sobrien 6089857Sobrien#include <netipx/ipx.h> 6189857Sobrien#include <netipx/ipx_if.h> 6289857Sobrien#include <netipx/ipx_ip.h> 6389857Sobrien#include <netipx/ipx_pcb.h> 6489857Sobrien#include <netipx/ipx_var.h> 6589857Sobrien 6689857Sobrien/* 6789857Sobrien * IPX protocol implementation. 6889857Sobrien */ 6989857Sobrien 7089857Sobrienstatic int ipxsendspace = IPXSNDQ; 7189857SobrienSYSCTL_INT(_net_ipx_ipx, OID_AUTO, ipxsendspace, CTLFLAG_RW, 7289857Sobrien &ipxsendspace, 0, ""); 7389857Sobrienstatic int ipxrecvspace = IPXRCVQ; 7489857SobrienSYSCTL_INT(_net_ipx_ipx, OID_AUTO, ipxrecvspace, CTLFLAG_RW, 7589857Sobrien &ipxrecvspace, 0, ""); 7689857Sobrien 7789857Sobrienstatic int ipx_usr_abort(struct socket *so); 7889857Sobrienstatic int ipx_attach(struct socket *so, int proto, struct thread *td); 7989857Sobrienstatic int ipx_bind(struct socket *so, struct sockaddr *nam, struct thread *td); 8089857Sobrienstatic int ipx_connect(struct socket *so, struct sockaddr *nam, 8189857Sobrien struct thread *td); 8289857Sobrienstatic int ipx_detach(struct socket *so); 8389857Sobrienstatic int ipx_disconnect(struct socket *so); 8489857Sobrienstatic int ipx_send(struct socket *so, int flags, struct mbuf *m, 8589857Sobrien struct sockaddr *addr, struct mbuf *control, 8689857Sobrien struct thread *td); 8789857Sobrienstatic int ipx_shutdown(struct socket *so); 8889857Sobrienstatic int ripx_attach(struct socket *so, int proto, struct thread *td); 8989857Sobrienstatic int ipx_output(struct ipxpcb *ipxp, struct mbuf *m0); 9089857Sobrien 9189857Sobrienstruct pr_usrreqs ipx_usrreqs = { 9289857Sobrien .pru_abort = ipx_usr_abort, 9389857Sobrien .pru_attach = ipx_attach, 9489857Sobrien .pru_bind = ipx_bind, 9589857Sobrien .pru_connect = ipx_connect, 9689857Sobrien .pru_control = ipx_control, 9789857Sobrien .pru_detach = ipx_detach, 9889857Sobrien .pru_disconnect = ipx_disconnect, 9989857Sobrien .pru_peeraddr = ipx_peeraddr, 10089857Sobrien .pru_send = ipx_send, 10189857Sobrien .pru_shutdown = ipx_shutdown, 10289857Sobrien .pru_sockaddr = ipx_sockaddr, 10389857Sobrien}; 10489857Sobrien 10589857Sobrienstruct pr_usrreqs ripx_usrreqs = { 10689857Sobrien .pru_abort = ipx_usr_abort, 10789857Sobrien .pru_attach = ripx_attach, 10889857Sobrien .pru_bind = ipx_bind, 10989857Sobrien .pru_connect = ipx_connect, 11089857Sobrien .pru_control = ipx_control, 11189857Sobrien .pru_detach = ipx_detach, 11289857Sobrien .pru_disconnect = ipx_disconnect, 11389857Sobrien .pru_peeraddr = ipx_peeraddr, 11489857Sobrien .pru_send = ipx_send, 11589857Sobrien .pru_shutdown = ipx_shutdown, 11689857Sobrien .pru_sockaddr = ipx_sockaddr, 11789857Sobrien}; 11889857Sobrien 11989857Sobrien/* 12089857Sobrien * This may also be called for raw listeners. 12189857Sobrien */ 12289857Sobrienvoid 12389857Sobrienipx_input(m, ipxp) 12489857Sobrien struct mbuf *m; 12589857Sobrien register struct ipxpcb *ipxp; 12689857Sobrien{ 12789857Sobrien register struct ipx *ipx = mtod(m, struct ipx *); 12889857Sobrien struct ifnet *ifp = m->m_pkthdr.rcvif; 12989857Sobrien struct sockaddr_ipx ipx_ipx; 13089857Sobrien 13189857Sobrien KASSERT(ipxp != NULL, ("ipx_input: NUL ipxpcb")); 13289857Sobrien /* 13389857Sobrien * Construct sockaddr format source address. 13489857Sobrien * Stuff source address and datagram in user buffer. 13589857Sobrien */ 13689857Sobrien ipx_ipx.sipx_len = sizeof(ipx_ipx); 13789857Sobrien ipx_ipx.sipx_family = AF_IPX; 13889857Sobrien ipx_ipx.sipx_addr = ipx->ipx_sna; 13989857Sobrien ipx_ipx.sipx_zero[0] = '\0'; 14089857Sobrien ipx_ipx.sipx_zero[1] = '\0'; 14189857Sobrien if (ipx_neteqnn(ipx->ipx_sna.x_net, ipx_zeronet) && ifp != NULL) { 14289857Sobrien register struct ifaddr *ifa; 14389857Sobrien 14489857Sobrien for (ifa = TAILQ_FIRST(&ifp->if_addrhead); ifa != NULL; 14589857Sobrien ifa = TAILQ_NEXT(ifa, ifa_link)) { 14689857Sobrien if (ifa->ifa_addr->sa_family == AF_IPX) { 14789857Sobrien ipx_ipx.sipx_addr.x_net = 14889857Sobrien IA_SIPX(ifa)->sipx_addr.x_net; 14989857Sobrien break; 15089857Sobrien } 15189857Sobrien } 15289857Sobrien } 15389857Sobrien ipxp->ipxp_rpt = ipx->ipx_pt; 15489857Sobrien if ((ipxp->ipxp_flags & IPXP_RAWIN) == 0) { 15589857Sobrien m->m_len -= sizeof(struct ipx); 15689857Sobrien m->m_pkthdr.len -= sizeof(struct ipx); 15789857Sobrien m->m_data += sizeof(struct ipx); 15889857Sobrien } 15989857Sobrien if (sbappendaddr(&ipxp->ipxp_socket->so_rcv, 16089857Sobrien (struct sockaddr *)&ipx_ipx, m, NULL) == 0) 16189857Sobrien m_freem(m); 16289857Sobrien else 16389857Sobrien sorwakeup(ipxp->ipxp_socket); 16489857Sobrien} 16589857Sobrien 16689857Sobrienvoid 16789857Sobrienipx_abort(ipxp) 16889857Sobrien struct ipxpcb *ipxp; 16989857Sobrien{ 17089857Sobrien struct socket *so = ipxp->ipxp_socket; 17189857Sobrien 17289857Sobrien ipx_pcbdisconnect(ipxp); 17389857Sobrien soisdisconnected(so); 17489857Sobrien} 17589857Sobrien 17689857Sobrien/* 17789857Sobrien * Drop connection, reporting 17889857Sobrien * the specified error. 17989857Sobrien */ 18089857Sobrienvoid 18189857Sobrienipx_drop(ipxp, errno) 18289857Sobrien register struct ipxpcb *ipxp; 18389857Sobrien int errno; 18489857Sobrien{ 18589857Sobrien struct socket *so = ipxp->ipxp_socket; 18689857Sobrien 18789857Sobrien /* 18889857Sobrien * someday, in the IPX world 18989857Sobrien * we will generate error protocol packets 19089857Sobrien * announcing that the socket has gone away. 19189857Sobrien * 19289857Sobrien * XXX Probably never. IPX does not have error packets. 19389857Sobrien */ 19489857Sobrien /*if (TCPS_HAVERCVDSYN(tp->t_state)) { 19589857Sobrien tp->t_state = TCPS_CLOSED; 19689857Sobrien tcp_output(tp); 19789857Sobrien }*/ 19889857Sobrien so->so_error = errno; 19989857Sobrien ipx_pcbdisconnect(ipxp); 20089857Sobrien soisdisconnected(so); 20189857Sobrien} 20289857Sobrien 20389857Sobrienstatic int 20489857Sobrienipx_output(ipxp, m0) 20589857Sobrien struct ipxpcb *ipxp; 20689857Sobrien struct mbuf *m0; 20789857Sobrien{ 20889857Sobrien register struct ipx *ipx; 20989857Sobrien register struct socket *so; 21089857Sobrien register int len = 0; 21189857Sobrien register struct route *ro; 21289857Sobrien struct mbuf *m; 21389857Sobrien struct mbuf *mprev = NULL; 21489857Sobrien 21589857Sobrien /* 21689857Sobrien * Calculate data length. 21789857Sobrien */ 21889857Sobrien for (m = m0; m != NULL; m = m->m_next) { 21989857Sobrien mprev = m; 22089857Sobrien len += m->m_len; 22189857Sobrien } 22289857Sobrien /* 22389857Sobrien * Make sure packet is actually of even length. 22489857Sobrien */ 22589857Sobrien 22689857Sobrien if (len & 1) { 22789857Sobrien m = mprev; 22889857Sobrien if ((m->m_flags & M_EXT) == 0 && 22989857Sobrien (m->m_len + m->m_data < &m->m_dat[MLEN])) { 23089857Sobrien mtod(m, char*)[m->m_len++] = 0; 23189857Sobrien } else { 23289857Sobrien struct mbuf *m1 = m_get(M_DONTWAIT, MT_DATA); 23389857Sobrien 23489857Sobrien if (m1 == NULL) { 23589857Sobrien m_freem(m0); 23689857Sobrien return (ENOBUFS); 23789857Sobrien } 23889857Sobrien m1->m_len = 1; 23989857Sobrien * mtod(m1, char *) = 0; 24089857Sobrien m->m_next = m1; 24189857Sobrien } 24289857Sobrien m0->m_pkthdr.len++; 24389857Sobrien } 24489857Sobrien 24589857Sobrien /* 24689857Sobrien * Fill in mbuf with extended IPX header 24789857Sobrien * and addresses and length put into network format. 24889857Sobrien */ 24989857Sobrien m = m0; 25089857Sobrien if (ipxp->ipxp_flags & IPXP_RAWOUT) { 25189857Sobrien ipx = mtod(m, struct ipx *); 25289857Sobrien } else { 25389857Sobrien M_PREPEND(m, sizeof(struct ipx), M_DONTWAIT); 25489857Sobrien if (m == NULL) 25589857Sobrien return (ENOBUFS); 25689857Sobrien ipx = mtod(m, struct ipx *); 25789857Sobrien ipx->ipx_tc = 0; 25889857Sobrien ipx->ipx_pt = ipxp->ipxp_dpt; 25989857Sobrien ipx->ipx_sna = ipxp->ipxp_laddr; 26089857Sobrien ipx->ipx_dna = ipxp->ipxp_faddr; 26189857Sobrien len += sizeof(struct ipx); 26289857Sobrien } 26389857Sobrien 26489857Sobrien ipx->ipx_len = htons((u_short)len); 26589857Sobrien 26689857Sobrien if (ipxp->ipxp_flags & IPXP_CHECKSUM) { 26789857Sobrien ipx->ipx_sum = ipx_cksum(m, len); 26889857Sobrien } else 26989857Sobrien ipx->ipx_sum = 0xffff; 27089857Sobrien 27189857Sobrien /* 27289857Sobrien * Output datagram. 27389857Sobrien */ 27489857Sobrien so = ipxp->ipxp_socket; 27589857Sobrien if (so->so_options & SO_DONTROUTE) 27689857Sobrien return (ipx_outputfl(m, (struct route *)NULL, 27789857Sobrien (so->so_options & SO_BROADCAST) | IPX_ROUTETOIF)); 27889857Sobrien /* 27989857Sobrien * Use cached route for previous datagram if 28089857Sobrien * possible. If the previous net was the same 28189857Sobrien * and the interface was a broadcast medium, or 28289857Sobrien * if the previous destination was identical, 28389857Sobrien * then we are ok. 28489857Sobrien * 28589857Sobrien * NB: We don't handle broadcasts because that 28689857Sobrien * would require 3 subroutine calls. 28789857Sobrien */ 28889857Sobrien ro = &ipxp->ipxp_route; 28989857Sobrien#ifdef ancient_history 29089857Sobrien /* 29189857Sobrien * I think that this will all be handled in ipx_pcbconnect! 29289857Sobrien */ 29389857Sobrien if (ro->ro_rt != NULL) { 29489857Sobrien if(ipx_neteq(ipxp->ipxp_lastdst, ipx->ipx_dna)) { 29589857Sobrien /* 29689857Sobrien * This assumes we have no GH type routes 29789857Sobrien */ 29889857Sobrien if (ro->ro_rt->rt_flags & RTF_HOST) { 29989857Sobrien if (!ipx_hosteq(ipxp->ipxp_lastdst, ipx->ipx_dna)) 30089857Sobrien goto re_route; 30189857Sobrien 30289857Sobrien } 30389857Sobrien if ((ro->ro_rt->rt_flags & RTF_GATEWAY) == 0) { 30489857Sobrien register struct ipx_addr *dst = 30589857Sobrien &satoipx_addr(ro->ro_dst); 30689857Sobrien dst->x_host = ipx->ipx_dna.x_host; 30789857Sobrien } 30889857Sobrien /* 30989857Sobrien * Otherwise, we go through the same gateway 31089857Sobrien * and dst is already set up. 31189857Sobrien */ 31289857Sobrien } else { 31389857Sobrien re_route: 31489857Sobrien RTFREE(ro->ro_rt); 31589857Sobrien ro->ro_rt = NULL; 31689857Sobrien } 31789857Sobrien } 31889857Sobrien ipxp->ipxp_lastdst = ipx->ipx_dna; 31989857Sobrien#endif /* ancient_history */ 32089857Sobrien return (ipx_outputfl(m, ro, so->so_options & SO_BROADCAST)); 32189857Sobrien} 32289857Sobrien 32389857Sobrienint 32489857Sobrienipx_ctloutput(so, sopt) 32589857Sobrien struct socket *so; 32689857Sobrien struct sockopt *sopt; 32789857Sobrien{ 32889857Sobrien struct ipxpcb *ipxp = sotoipxpcb(so); 32989857Sobrien int mask, error, optval; 33089857Sobrien short soptval; 33189857Sobrien struct ipx ioptval; 33289857Sobrien 33389857Sobrien error = 0; 33489857Sobrien if (ipxp == NULL) 33589857Sobrien return (EINVAL); 33689857Sobrien 33789857Sobrien switch (sopt->sopt_dir) { 33889857Sobrien case SOPT_GET: 33989857Sobrien switch (sopt->sopt_name) { 34089857Sobrien case SO_ALL_PACKETS: 34189857Sobrien mask = IPXP_ALL_PACKETS; 34289857Sobrien goto get_flags; 34389857Sobrien 34489857Sobrien case SO_HEADERS_ON_INPUT: 34589857Sobrien mask = IPXP_RAWIN; 34689857Sobrien goto get_flags; 34789857Sobrien 34889857Sobrien case SO_IPX_CHECKSUM: 34989857Sobrien mask = IPXP_CHECKSUM; 35089857Sobrien goto get_flags; 35189857Sobrien 35289857Sobrien case SO_HEADERS_ON_OUTPUT: 35389857Sobrien mask = IPXP_RAWOUT; 35489857Sobrien get_flags: 35589857Sobrien soptval = ipxp->ipxp_flags & mask; 35689857Sobrien error = sooptcopyout(sopt, &soptval, sizeof soptval); 35789857Sobrien break; 35889857Sobrien 35989857Sobrien case SO_DEFAULT_HEADERS: 36089857Sobrien ioptval.ipx_len = 0; 36189857Sobrien ioptval.ipx_sum = 0; 36289857Sobrien ioptval.ipx_tc = 0; 36389857Sobrien ioptval.ipx_pt = ipxp->ipxp_dpt; 36489857Sobrien ioptval.ipx_dna = ipxp->ipxp_faddr; 36589857Sobrien ioptval.ipx_sna = ipxp->ipxp_laddr; 36689857Sobrien error = sooptcopyout(sopt, &soptval, sizeof soptval); 36789857Sobrien break; 36889857Sobrien 36989857Sobrien case SO_SEQNO: 37089857Sobrien error = sooptcopyout(sopt, &ipx_pexseq, 37189857Sobrien sizeof ipx_pexseq); 37289857Sobrien ipx_pexseq++; 37389857Sobrien break; 37489857Sobrien 37589857Sobrien default: 37689857Sobrien error = EINVAL; 37789857Sobrien } 37889857Sobrien break; 37989857Sobrien 38089857Sobrien case SOPT_SET: 38189857Sobrien switch (sopt->sopt_name) { 38289857Sobrien case SO_ALL_PACKETS: 38389857Sobrien mask = IPXP_ALL_PACKETS; 38489857Sobrien goto set_head; 38589857Sobrien 38689857Sobrien case SO_HEADERS_ON_INPUT: 38789857Sobrien mask = IPXP_RAWIN; 38889857Sobrien goto set_head; 38989857Sobrien 39089857Sobrien case SO_IPX_CHECKSUM: 39189857Sobrien mask = IPXP_CHECKSUM; 39289857Sobrien 39389857Sobrien case SO_HEADERS_ON_OUTPUT: 39489857Sobrien mask = IPXP_RAWOUT; 39589857Sobrien set_head: 39689857Sobrien error = sooptcopyin(sopt, &optval, sizeof optval, 39789857Sobrien sizeof optval); 39889857Sobrien if (error) 39989857Sobrien break; 40089857Sobrien if (optval) 40189857Sobrien ipxp->ipxp_flags |= mask; 40289857Sobrien else 40389857Sobrien ipxp->ipxp_flags &= ~mask; 40489857Sobrien break; 40589857Sobrien 40689857Sobrien case SO_DEFAULT_HEADERS: 40789857Sobrien error = sooptcopyin(sopt, &ioptval, sizeof ioptval, 40889857Sobrien sizeof ioptval); 40989857Sobrien if (error) 41089857Sobrien break; 41189857Sobrien ipxp->ipxp_dpt = ioptval.ipx_pt; 41289857Sobrien break; 41389857Sobrien#ifdef IPXIP 41489857Sobrien case SO_IPXIP_ROUTE: 41589857Sobrien error = ipxip_route(so, sopt); 41689857Sobrien break; 41789857Sobrien#endif /* IPXIP */ 41889857Sobrien default: 41989857Sobrien error = EINVAL; 42089857Sobrien } 42189857Sobrien break; 42289857Sobrien } 42389857Sobrien return (error); 42489857Sobrien} 42589857Sobrien 42689857Sobrienstatic int 42789857Sobrienipx_usr_abort(so) 42889857Sobrien struct socket *so; 42989857Sobrien{ 43089857Sobrien int s; 43189857Sobrien struct ipxpcb *ipxp = sotoipxpcb(so); 43289857Sobrien 43389857Sobrien s = splnet(); 43489857Sobrien ipx_pcbdetach(ipxp); 43589857Sobrien splx(s); 43689857Sobrien soisdisconnected(so); 43789857Sobrien ACCEPT_LOCK(); 43889857Sobrien SOCK_LOCK(so); 43989857Sobrien sotryfree(so); 44089857Sobrien return (0); 44189857Sobrien} 442218822Sdim 44389857Sobrienstatic int 44489857Sobrienipx_attach(so, proto, td) 44589857Sobrien struct socket *so; 44689857Sobrien int proto; 447218822Sdim struct thread *td; 448218822Sdim{ 44989857Sobrien int error; 45089857Sobrien int s; 45189857Sobrien struct ipxpcb *ipxp = sotoipxpcb(so); 45289857Sobrien 45389857Sobrien if (ipxp != NULL) 454218822Sdim return (EINVAL); 45589857Sobrien s = splnet(); 45689857Sobrien error = ipx_pcballoc(so, &ipxpcb_list, td); 45789857Sobrien splx(s); 45889857Sobrien if (error == 0) 45989857Sobrien error = soreserve(so, ipxsendspace, ipxrecvspace); 46089857Sobrien return (error); 46189857Sobrien} 462218822Sdim 463218822Sdimstatic int 464218822Sdimipx_bind(so, nam, td) 46589857Sobrien struct socket *so; 46689857Sobrien struct sockaddr *nam; 46789857Sobrien struct thread *td; 46889857Sobrien{ 469218822Sdim struct ipxpcb *ipxp = sotoipxpcb(so); 470218822Sdim 471218822Sdim return (ipx_pcbbind(ipxp, nam, td)); 472218822Sdim} 47389857Sobrien 47489857Sobrienstatic int 47589857Sobrienipx_connect(so, nam, td) 47689857Sobrien struct socket *so; 477218822Sdim struct sockaddr *nam; 478218822Sdim struct thread *td; 47989857Sobrien{ 48089857Sobrien int error; 48189857Sobrien int s; 482218822Sdim struct ipxpcb *ipxp = sotoipxpcb(so); 483218822Sdim 484218822Sdim if (!ipx_nullhost(ipxp->ipxp_faddr)) 48589857Sobrien return (EISCONN); 48689857Sobrien s = splnet(); 48789857Sobrien error = ipx_pcbconnect(ipxp, nam, td); 48889857Sobrien splx(s); 48989857Sobrien if (error == 0) 49089857Sobrien soisconnected(so); 49189857Sobrien return (error); 49289857Sobrien} 49389857Sobrien 49489857Sobrienstatic int 49589857Sobrienipx_detach(so) 49689857Sobrien struct socket *so; 49789857Sobrien{ 49889857Sobrien int s; 499218822Sdim struct ipxpcb *ipxp = sotoipxpcb(so); 500218822Sdim 501218822Sdim if (ipxp == NULL) 502218822Sdim return (ENOTCONN); 50389857Sobrien s = splnet(); 50489857Sobrien ipx_pcbdetach(ipxp); 50589857Sobrien splx(s); 50689857Sobrien return (0); 507218822Sdim} 508218822Sdim 50989857Sobrienstatic int 51089857Sobrienipx_disconnect(so) 51189857Sobrien struct socket *so; 51289857Sobrien{ 51389857Sobrien int s; 51489857Sobrien struct ipxpcb *ipxp = sotoipxpcb(so); 51589857Sobrien 51689857Sobrien if (ipx_nullhost(ipxp->ipxp_faddr)) 51789857Sobrien return (ENOTCONN); 51889857Sobrien s = splnet(); 51989857Sobrien ipx_pcbdisconnect(ipxp); 52089857Sobrien splx(s); 52189857Sobrien soisdisconnected(so); 52289857Sobrien return (0); 52389857Sobrien} 524104834Sobrien 525104834Sobrienint 526104834Sobrienipx_peeraddr(so, nam) 527104834Sobrien struct socket *so; 528104834Sobrien struct sockaddr **nam; 529104834Sobrien{ 530104834Sobrien struct ipxpcb *ipxp = sotoipxpcb(so); 531104834Sobrien 532104834Sobrien ipx_setpeeraddr(ipxp, nam); 533104834Sobrien return (0); 53489857Sobrien} 535218822Sdim 536218822Sdimstatic int 537218822Sdimipx_send(so, flags, m, nam, control, td) 53889857Sobrien struct socket *so; 539218822Sdim int flags; 540218822Sdim struct mbuf *m; 541218822Sdim struct sockaddr *nam; 542218822Sdim struct mbuf *control; 543218822Sdim struct thread *td; 544218822Sdim{ 545218822Sdim int error; 54689857Sobrien struct ipxpcb *ipxp = sotoipxpcb(so); 547218822Sdim struct ipx_addr laddr; 548218822Sdim int s = 0; 54989857Sobrien 550218822Sdim if (nam != NULL) { 55189857Sobrien laddr = ipxp->ipxp_laddr; 55289857Sobrien if (!ipx_nullhost(ipxp->ipxp_faddr)) { 55389857Sobrien error = EISCONN; 55489857Sobrien goto send_release; 55589857Sobrien } 55689857Sobrien /* 55789857Sobrien * Must block input while temporarily connected. 55889857Sobrien */ 55989857Sobrien s = splnet(); 56089857Sobrien error = ipx_pcbconnect(ipxp, nam, td); 56189857Sobrien if (error) { 56289857Sobrien splx(s); 56389857Sobrien goto send_release; 56489857Sobrien } 56589857Sobrien } else { 566 if (ipx_nullhost(ipxp->ipxp_faddr)) { 567 error = ENOTCONN; 568 goto send_release; 569 } 570 } 571 error = ipx_output(ipxp, m); 572 m = NULL; 573 if (nam != NULL) { 574 ipx_pcbdisconnect(ipxp); 575 splx(s); 576 ipxp->ipxp_laddr = laddr; 577 } 578 579send_release: 580 if (m != NULL) 581 m_freem(m); 582 return (error); 583} 584 585static int 586ipx_shutdown(so) 587 struct socket *so; 588{ 589 socantsendmore(so); 590 return (0); 591} 592 593int 594ipx_sockaddr(so, nam) 595 struct socket *so; 596 struct sockaddr **nam; 597{ 598 struct ipxpcb *ipxp = sotoipxpcb(so); 599 600 ipx_setsockaddr(ipxp, nam); 601 return (0); 602} 603 604static int 605ripx_attach(so, proto, td) 606 struct socket *so; 607 int proto; 608 struct thread *td; 609{ 610 int error = 0; 611 int s; 612 struct ipxpcb *ipxp = sotoipxpcb(so); 613 614 if (td != NULL && (error = suser(td)) != 0) 615 return (error); 616 s = splnet(); 617 error = ipx_pcballoc(so, &ipxrawpcb_list, td); 618 splx(s); 619 if (error) 620 return (error); 621 error = soreserve(so, ipxsendspace, ipxrecvspace); 622 if (error) 623 return (error); 624 ipxp = sotoipxpcb(so); 625 ipxp->ipxp_faddr.x_host = ipx_broadhost; 626 ipxp->ipxp_flags = IPXP_RAWIN | IPXP_RAWOUT; 627 return (error); 628} 629