ipx_usrreq.c revision 116189
123599Smarkm/* 223599Smarkm * Copyright (c) 1995, Mike Mitchell 323599Smarkm * Copyright (c) 1984, 1985, 1986, 1987, 1993 423599Smarkm * The Regents of the University of California. All rights reserved. 523599Smarkm * 623599Smarkm * Redistribution and use in source and binary forms, with or without 723599Smarkm * modification, are permitted provided that the following conditions 823599Smarkm * are met: 923599Smarkm * 1. Redistributions of source code must retain the above copyright 1023599Smarkm * notice, this list of conditions and the following disclaimer. 1123599Smarkm * 2. Redistributions in binary form must reproduce the above copyright 1223599Smarkm * notice, this list of conditions and the following disclaimer in the 1323599Smarkm * documentation and/or other materials provided with the distribution. 1423599Smarkm * 3. All advertising materials mentioning features or use of this software 1523599Smarkm * must display the following acknowledgement: 1623599Smarkm * This product includes software developed by the University of 1723599Smarkm * California, Berkeley and its contributors. 1823599Smarkm * 4. Neither the name of the University nor the names of its contributors 1923599Smarkm * may be used to endorse or promote products derived from this software 2023599Smarkm * without specific prior written permission. 2123599Smarkm * 2223599Smarkm * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2323599Smarkm * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2423599Smarkm * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2523599Smarkm * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2623599Smarkm * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2723599Smarkm * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2823599Smarkm * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2923599Smarkm * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 3039838Ssos * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3139838Ssos * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3223599Smarkm * SUCH DAMAGE. 3323599Smarkm * 3423599Smarkm * @(#)ipx_usrreq.c 3523599Smarkm */ 3623599Smarkm 3723599Smarkm#include <sys/cdefs.h> 3823599Smarkm__FBSDID("$FreeBSD: head/sys/netipx/ipx_usrreq.c 116189 2003-06-11 05:37:42Z obrien $"); 3923599Smarkm 4023599Smarkm#include "opt_ipx.h" 4135050Sahasty 4237611Sahasty#include <sys/param.h> 4337611Sahasty#include <sys/kernel.h> 4423599Smarkm#include <sys/lock.h> 4524246Sfsmp#include <sys/mbuf.h> 4624246Sfsmp#include <sys/protosw.h> 4724246Sfsmp#include <sys/signalvar.h> 4824246Sfsmp#include <sys/socket.h> 4924246Sfsmp#include <sys/socketvar.h> 5024246Sfsmp#include <sys/sx.h> 5124246Sfsmp#include <sys/sysctl.h> 5224246Sfsmp#include <sys/systm.h> 5324246Sfsmp 5423599Smarkm#include <net/if.h> 5524246Sfsmp#include <net/route.h> 5624246Sfsmp 5724528Sfsmp#include <netinet/in.h> 5824528Sfsmp 5924528Sfsmp#include <netipx/ipx.h> 6024528Sfsmp#include <netipx/ipx_if.h> 6124528Sfsmp#include <netipx/ipx_ip.h> 6238707Ssos#include <netipx/ipx_pcb.h> 6324528Sfsmp#include <netipx/ipx_var.h> 6424528Sfsmp 6524246Sfsmp/* 6624528Sfsmp * IPX protocol implementation. 6724528Sfsmp */ 6824528Sfsmp 6924528Sfsmpstatic int ipxsendspace = IPXSNDQ; 7037611SahastySYSCTL_INT(_net_ipx_ipx, OID_AUTO, ipxsendspace, CTLFLAG_RW, 7124528Sfsmp &ipxsendspace, 0, ""); 7224528Sfsmpstatic int ipxrecvspace = IPXRCVQ; 7324528SfsmpSYSCTL_INT(_net_ipx_ipx, OID_AUTO, ipxrecvspace, CTLFLAG_RW, 7424528Sfsmp &ipxrecvspace, 0, ""); 7524528Sfsmp 7624528Sfsmpstatic int ipx_usr_abort(struct socket *so); 7724246Sfsmpstatic int ipx_attach(struct socket *so, int proto, struct thread *td); 7824246Sfsmpstatic int ipx_bind(struct socket *so, struct sockaddr *nam, struct thread *td); 7924246Sfsmpstatic int ipx_connect(struct socket *so, struct sockaddr *nam, 8024246Sfsmp struct thread *td); 8124246Sfsmpstatic int ipx_detach(struct socket *so); 8224246Sfsmpstatic int ipx_disconnect(struct socket *so); 8324246Sfsmpstatic int ipx_send(struct socket *so, int flags, struct mbuf *m, 8424246Sfsmp struct sockaddr *addr, struct mbuf *control, 8524246Sfsmp struct thread *td); 8624246Sfsmpstatic int ipx_shutdown(struct socket *so); 8724528Sfsmpstatic int ripx_attach(struct socket *so, int proto, struct thread *td); 8824528Sfsmpstatic int ipx_output(struct ipxpcb *ipxp, struct mbuf *m0); 8924528Sfsmp 9024528Sfsmpstruct pr_usrreqs ipx_usrreqs = { 9124528Sfsmp ipx_usr_abort, pru_accept_notsupp, ipx_attach, ipx_bind, 9224528Sfsmp ipx_connect, pru_connect2_notsupp, ipx_control, ipx_detach, 9324528Sfsmp ipx_disconnect, pru_listen_notsupp, ipx_peeraddr, pru_rcvd_notsupp, 9424528Sfsmp pru_rcvoob_notsupp, ipx_send, pru_sense_null, ipx_shutdown, 9524246Sfsmp ipx_sockaddr, sosend, soreceive, sopoll 9624246Sfsmp}; 9724246Sfsmp 9824246Sfsmpstruct pr_usrreqs ripx_usrreqs = { 9924246Sfsmp ipx_usr_abort, pru_accept_notsupp, ripx_attach, ipx_bind, 10024528Sfsmp ipx_connect, pru_connect2_notsupp, ipx_control, ipx_detach, 10124528Sfsmp ipx_disconnect, pru_listen_notsupp, ipx_peeraddr, pru_rcvd_notsupp, 10224528Sfsmp pru_rcvoob_notsupp, ipx_send, pru_sense_null, ipx_shutdown, 10324528Sfsmp ipx_sockaddr, sosend, soreceive, sopoll 10424528Sfsmp}; 10524528Sfsmp 10624528Sfsmp/* 10724528Sfsmp * This may also be called for raw listeners. 10824528Sfsmp */ 10924246Sfsmpvoid 11024246Sfsmpipx_input(m, ipxp) 11124246Sfsmp struct mbuf *m; 11224246Sfsmp register struct ipxpcb *ipxp; 11324246Sfsmp{ 11424246Sfsmp register struct ipx *ipx = mtod(m, struct ipx *); 11524246Sfsmp struct ifnet *ifp = m->m_pkthdr.rcvif; 11624246Sfsmp struct sockaddr_ipx ipx_ipx; 11724246Sfsmp 11824246Sfsmp if (ipxp == NULL) 11924528Sfsmp panic("No ipxpcb"); 12024528Sfsmp /* 12124528Sfsmp * Construct sockaddr format source address. 12224528Sfsmp * Stuff source address and datagram in user buffer. 12324528Sfsmp */ 12424528Sfsmp ipx_ipx.sipx_len = sizeof(ipx_ipx); 12524528Sfsmp ipx_ipx.sipx_family = AF_IPX; 12624246Sfsmp ipx_ipx.sipx_addr = ipx->ipx_sna; 12724246Sfsmp ipx_ipx.sipx_zero[0] = '\0'; 12824246Sfsmp ipx_ipx.sipx_zero[1] = '\0'; 12924246Sfsmp if (ipx_neteqnn(ipx->ipx_sna.x_net, ipx_zeronet) && ifp != NULL) { 13024246Sfsmp register struct ifaddr *ifa; 13138707Ssos 13238707Ssos for (ifa = TAILQ_FIRST(&ifp->if_addrhead); ifa != NULL; 13338707Ssos ifa = TAILQ_NEXT(ifa, ifa_link)) { 13438707Ssos if (ifa->ifa_addr->sa_family == AF_IPX) { 13538707Ssos ipx_ipx.sipx_addr.x_net = 13638707Ssos IA_SIPX(ifa)->sipx_addr.x_net; 13738707Ssos break; 13838707Ssos } 13924246Sfsmp } 14024246Sfsmp } 14124246Sfsmp ipxp->ipxp_rpt = ipx->ipx_pt; 14224246Sfsmp if (!(ipxp->ipxp_flags & IPXP_RAWIN) ) { 14324246Sfsmp m->m_len -= sizeof(struct ipx); 14424246Sfsmp m->m_pkthdr.len -= sizeof(struct ipx); 14524246Sfsmp m->m_data += sizeof(struct ipx); 14624246Sfsmp } 14724246Sfsmp if (sbappendaddr(&ipxp->ipxp_socket->so_rcv, (struct sockaddr *)&ipx_ipx, 14824528Sfsmp m, (struct mbuf *)NULL) == 0) 14924528Sfsmp goto bad; 15024528Sfsmp sorwakeup(ipxp->ipxp_socket); 15124528Sfsmp return; 15224528Sfsmpbad: 15324528Sfsmp m_freem(m); 15424528Sfsmp} 15524528Sfsmp 15624246Sfsmpvoid 15724246Sfsmpipx_abort(ipxp) 15824528Sfsmp struct ipxpcb *ipxp; 15924528Sfsmp{ 16024528Sfsmp struct socket *so = ipxp->ipxp_socket; 16124528Sfsmp 16238707Ssos ipx_pcbdisconnect(ipxp); 16338707Ssos soisdisconnected(so); 16438707Ssos} 16538707Ssos 16624528Sfsmp/* 16724246Sfsmp * Drop connection, reporting 16824246Sfsmp * the specified error. 16924246Sfsmp */ 17024246Sfsmpvoid 17124246Sfsmpipx_drop(ipxp, errno) 17225329Sfsmp register struct ipxpcb *ipxp; 17324528Sfsmp int errno; 17424528Sfsmp{ 17524528Sfsmp struct socket *so = ipxp->ipxp_socket; 17624528Sfsmp 17725329Sfsmp /* 17825329Sfsmp * someday, in the IPX world 17925329Sfsmp * we will generate error protocol packets 18025329Sfsmp * announcing that the socket has gone away. 18125329Sfsmp * 18224246Sfsmp * XXX Probably never. IPX does not have error packets. 18324528Sfsmp */ 18424528Sfsmp /*if (TCPS_HAVERCVDSYN(tp->t_state)) { 18524528Sfsmp tp->t_state = TCPS_CLOSED; 18624528Sfsmp tcp_output(tp); 18724528Sfsmp }*/ 18824246Sfsmp so->so_error = errno; 18924246Sfsmp ipx_pcbdisconnect(ipxp); 19024246Sfsmp soisdisconnected(so); 19124246Sfsmp} 19238707Ssos 19338707Ssosstatic int 19438707Ssosipx_output(ipxp, m0) 19538707Ssos struct ipxpcb *ipxp; 19638707Ssos struct mbuf *m0; 19738707Ssos{ 19824246Sfsmp register struct ipx *ipx; 19924246Sfsmp register struct socket *so; 20024528Sfsmp register int len = 0; 20124528Sfsmp register struct route *ro; 20224528Sfsmp struct mbuf *m; 20324528Sfsmp struct mbuf *mprev = NULL; 20424528Sfsmp 20524528Sfsmp /* 20624528Sfsmp * Calculate data length. 20724528Sfsmp */ 20824528Sfsmp for (m = m0; m != NULL; m = m->m_next) { 20924528Sfsmp mprev = m; 21024528Sfsmp len += m->m_len; 21124528Sfsmp } 21224528Sfsmp /* 21324528Sfsmp * Make sure packet is actually of even length. 21424528Sfsmp */ 21524528Sfsmp 21624528Sfsmp if (len & 1) { 21724528Sfsmp m = mprev; 21824528Sfsmp if ((m->m_flags & M_EXT) == 0 && 21924528Sfsmp (m->m_len + m->m_data < &m->m_dat[MLEN])) { 22024528Sfsmp mtod(m, char*)[m->m_len++] = 0; 22124528Sfsmp } else { 22224528Sfsmp struct mbuf *m1 = m_get(M_DONTWAIT, MT_DATA); 22324528Sfsmp 22424246Sfsmp if (m1 == NULL) { 22524246Sfsmp m_freem(m0); 22629233Smarkm return (ENOBUFS); 22729233Smarkm } 22829233Smarkm m1->m_len = 1; 22929233Smarkm * mtod(m1, char *) = 0; 23029233Smarkm m->m_next = m1; 23129233Smarkm } 23229233Smarkm m0->m_pkthdr.len++; 23329233Smarkm } 23429233Smarkm 23529233Smarkm /* 23629233Smarkm * Fill in mbuf with extended IPX header 23729233Smarkm * and addresses and length put into network format. 23824528Sfsmp */ 23924528Sfsmp m = m0; 24024246Sfsmp if (ipxp->ipxp_flags & IPXP_RAWOUT) { 24124528Sfsmp ipx = mtod(m, struct ipx *); 24224528Sfsmp } else { 24324528Sfsmp M_PREPEND(m, sizeof(struct ipx), M_DONTWAIT); 24424528Sfsmp if (m == NULL) 24524528Sfsmp return (ENOBUFS); 24624246Sfsmp ipx = mtod(m, struct ipx *); 24724246Sfsmp ipx->ipx_tc = 0; 24824246Sfsmp ipx->ipx_pt = ipxp->ipxp_dpt; 24924246Sfsmp ipx->ipx_sna = ipxp->ipxp_laddr; 25024246Sfsmp ipx->ipx_dna = ipxp->ipxp_faddr; 25124246Sfsmp len += sizeof(struct ipx); 25224246Sfsmp } 25323599Smarkm 25424528Sfsmp ipx->ipx_len = htons((u_short)len); 25524246Sfsmp 25624246Sfsmp if (ipxp->ipxp_flags & IPXP_CHECKSUM) { 25724528Sfsmp ipx->ipx_sum = ipx_cksum(m, len); 25824528Sfsmp } else 25924528Sfsmp ipx->ipx_sum = 0xffff; 26024087Sfsmp 26124087Sfsmp /* 26224087Sfsmp * Output datagram. 26324087Sfsmp */ 26424087Sfsmp so = ipxp->ipxp_socket; 26524087Sfsmp if (so->so_options & SO_DONTROUTE) 26624087Sfsmp return (ipx_outputfl(m, (struct route *)NULL, 26724087Sfsmp (so->so_options & SO_BROADCAST) | IPX_ROUTETOIF)); 26824087Sfsmp /* 26924087Sfsmp * Use cached route for previous datagram if 27024087Sfsmp * possible. If the previous net was the same 27124087Sfsmp * and the interface was a broadcast medium, or 27224087Sfsmp * if the previous destination was identical, 27324087Sfsmp * then we are ok. 27424087Sfsmp * 27524087Sfsmp * NB: We don't handle broadcasts because that 27624087Sfsmp * would require 3 subroutine calls. 27724087Sfsmp */ 27824087Sfsmp ro = &ipxp->ipxp_route; 27924087Sfsmp#ifdef ancient_history 28024087Sfsmp /* 28124087Sfsmp * I think that this will all be handled in ipx_pcbconnect! 28224087Sfsmp */ 28324087Sfsmp if (ro->ro_rt != NULL) { 28424087Sfsmp if(ipx_neteq(ipxp->ipxp_lastdst, ipx->ipx_dna)) { 28524087Sfsmp /* 28624087Sfsmp * This assumes we have no GH type routes 28724087Sfsmp */ 28824087Sfsmp if (ro->ro_rt->rt_flags & RTF_HOST) { 28924087Sfsmp if (!ipx_hosteq(ipxp->ipxp_lastdst, ipx->ipx_dna)) 29024087Sfsmp goto re_route; 29124087Sfsmp 29224087Sfsmp } 29324087Sfsmp if ((ro->ro_rt->rt_flags & RTF_GATEWAY) == 0) { 29424087Sfsmp register struct ipx_addr *dst = 29524087Sfsmp &satoipx_addr(ro->ro_dst); 29624087Sfsmp dst->x_host = ipx->ipx_dna.x_host; 29724087Sfsmp } 29824087Sfsmp /* 29924087Sfsmp * Otherwise, we go through the same gateway 30024087Sfsmp * and dst is already set up. 30124087Sfsmp */ 30224087Sfsmp } else { 30324087Sfsmp re_route: 30424087Sfsmp RTFREE(ro->ro_rt); 30524087Sfsmp ro->ro_rt = NULL; 30624087Sfsmp } 30724087Sfsmp } 30824087Sfsmp ipxp->ipxp_lastdst = ipx->ipx_dna; 30924087Sfsmp#endif /* ancient_history */ 31024087Sfsmp return (ipx_outputfl(m, ro, so->so_options & SO_BROADCAST)); 31124087Sfsmp} 31223599Smarkm 31324528Sfsmpint 31423599Smarkmipx_ctloutput(so, sopt) 31523599Smarkm struct socket *so; 31623599Smarkm struct sockopt *sopt; 31723599Smarkm{ 31824528Sfsmp struct ipxpcb *ipxp = sotoipxpcb(so); 31924528Sfsmp int mask, error, optval; 32024246Sfsmp short soptval; 32124528Sfsmp struct ipx ioptval; 32224528Sfsmp 32324528Sfsmp error = 0; 32424528Sfsmp if (ipxp == NULL) 32524528Sfsmp return (EINVAL); 32633850Sahasty 32723599Smarkm switch (sopt->sopt_dir) { 32823599Smarkm case SOPT_GET: 32924528Sfsmp switch (sopt->sopt_name) { 33024528Sfsmp case SO_ALL_PACKETS: 33124528Sfsmp mask = IPXP_ALL_PACKETS; 33224528Sfsmp goto get_flags; 33333025Sahasty 33424528Sfsmp case SO_HEADERS_ON_INPUT: 33533025Sahasty mask = IPXP_RAWIN; 33633025Sahasty goto get_flags; 33733025Sahasty 33833025Sahasty case SO_IPX_CHECKSUM: 33933025Sahasty mask = IPXP_CHECKSUM; 34024528Sfsmp goto get_flags; 34124528Sfsmp 34224528Sfsmp case SO_HEADERS_ON_OUTPUT: 34324246Sfsmp mask = IPXP_RAWOUT; 34424246Sfsmp get_flags: 34539041Ssos soptval = ipxp->ipxp_flags & mask; 34624528Sfsmp error = sooptcopyout(sopt, &soptval, sizeof soptval); 34739838Ssos break; 34839838Ssos 34930856Seivind case SO_DEFAULT_HEADERS: 35030856Seivind ioptval.ipx_len = 0; 35124528Sfsmp ioptval.ipx_sum = 0; 35224528Sfsmp ioptval.ipx_tc = 0; 35324528Sfsmp ioptval.ipx_pt = ipxp->ipxp_dpt; 35424528Sfsmp ioptval.ipx_dna = ipxp->ipxp_faddr; 35524246Sfsmp ioptval.ipx_sna = ipxp->ipxp_laddr; 35623599Smarkm error = sooptcopyout(sopt, &soptval, sizeof soptval); 35724528Sfsmp break; 35824528Sfsmp 35924528Sfsmp case SO_SEQNO: 36024528Sfsmp error = sooptcopyout(sopt, &ipx_pexseq, 36124528Sfsmp sizeof ipx_pexseq); 36238706Ssos ipx_pexseq++; 36338706Ssos break; 36438706Ssos 36529233Smarkm default: 36638706Ssos error = EINVAL; 36730856Seivind } 36838706Ssos break; 36930856Seivind 37024528Sfsmp case SOPT_SET: 37124528Sfsmp switch (sopt->sopt_name) { 37225329Sfsmp case SO_ALL_PACKETS: 37325329Sfsmp mask = IPXP_ALL_PACKETS; 37423599Smarkm goto set_head; 37523599Smarkm 37623599Smarkm case SO_HEADERS_ON_INPUT: 37724528Sfsmp mask = IPXP_RAWIN; 37829233Smarkm goto set_head; 37929233Smarkm 38029233Smarkm case SO_IPX_CHECKSUM: 38129233Smarkm mask = IPXP_CHECKSUM; 38229233Smarkm 38329233Smarkm case SO_HEADERS_ON_OUTPUT: 38424528Sfsmp mask = IPXP_RAWOUT; 38524246Sfsmp set_head: 38623599Smarkm error = sooptcopyin(sopt, &optval, sizeof optval, 38723599Smarkm sizeof optval); 38823599Smarkm if (error) 38923599Smarkm break; 39023599Smarkm if (optval) 39136090Sahasty ipxp->ipxp_flags |= mask; 39223599Smarkm else 39323599Smarkm ipxp->ipxp_flags &= ~mask; 39423599Smarkm break; 39523599Smarkm 39623599Smarkm case SO_DEFAULT_HEADERS: 39723599Smarkm error = sooptcopyin(sopt, &ioptval, sizeof ioptval, 39823599Smarkm sizeof ioptval); 39923599Smarkm if (error) 40023599Smarkm break; 40123599Smarkm ipxp->ipxp_dpt = ioptval.ipx_pt; 40223599Smarkm break; 40338706Ssos#ifdef IPXIP 40438706Ssos case SO_IPXIP_ROUTE: 40538706Ssos error = ipxip_route(so, sopt); 40638706Ssos break; 40738706Ssos#endif /* IPXIP */ 40825329Sfsmp default: 40925329Sfsmp error = EINVAL; 41023599Smarkm } 41123599Smarkm break; 41223599Smarkm } 41323599Smarkm return (error); 41423599Smarkm} 41523599Smarkm 41623599Smarkmstatic int 41723599Smarkmipx_usr_abort(so) 41823599Smarkm struct socket *so; 41923599Smarkm{ 42023935Sfsmp int s; 42129233Smarkm struct ipxpcb *ipxp = sotoipxpcb(so); 42223599Smarkm 42323599Smarkm s = splnet(); 42423599Smarkm ipx_pcbdetach(ipxp); 42523599Smarkm splx(s); 42623599Smarkm sotryfree(so); 42723599Smarkm soisdisconnected(so); 42823599Smarkm return (0); 42923599Smarkm} 43023599Smarkm 43123599Smarkmstatic int 43223599Smarkmipx_attach(so, proto, td) 43323599Smarkm struct socket *so; 43439041Ssos int proto; 43539041Ssos struct thread *td; 43639041Ssos{ 43723599Smarkm int error; 43823599Smarkm int s; 43923599Smarkm struct ipxpcb *ipxp = sotoipxpcb(so); 44023599Smarkm 44123599Smarkm if (ipxp != NULL) 44223599Smarkm return (EINVAL); 44323599Smarkm s = splnet(); 44423599Smarkm error = ipx_pcballoc(so, &ipxpcb, td); 44523599Smarkm splx(s); 44623599Smarkm if (error == 0) 44723599Smarkm error = soreserve(so, ipxsendspace, ipxrecvspace); 44823599Smarkm return (error); 44923599Smarkm} 45023599Smarkm 45123599Smarkmstatic int 45223599Smarkmipx_bind(so, nam, td) 45323599Smarkm struct socket *so; 45423599Smarkm struct sockaddr *nam; 45523599Smarkm struct thread *td; 45623599Smarkm{ 45723599Smarkm struct ipxpcb *ipxp = sotoipxpcb(so); 45823599Smarkm 45923599Smarkm return (ipx_pcbbind(ipxp, nam, td)); 46023599Smarkm} 46124528Sfsmp 46224528Sfsmpstatic int 46324528Sfsmpipx_connect(so, nam, td) 46423599Smarkm struct socket *so; 46523599Smarkm struct sockaddr *nam; 46624246Sfsmp struct thread *td; 46724528Sfsmp{ 46824528Sfsmp int error; 46924528Sfsmp int s; 47024528Sfsmp struct ipxpcb *ipxp = sotoipxpcb(so); 47125329Sfsmp 47225329Sfsmp if (!ipx_nullhost(ipxp->ipxp_faddr)) 47325329Sfsmp return (EISCONN); 47425329Sfsmp s = splnet(); 47525329Sfsmp error = ipx_pcbconnect(ipxp, nam, td); 47625329Sfsmp splx(s); 47725329Sfsmp if (error == 0) 47825329Sfsmp soisconnected(so); 47925329Sfsmp return (error); 48025329Sfsmp} 48125329Sfsmp 48236090Sahastystatic int 48336090Sahastyipx_detach(so) 48436090Sahasty struct socket *so; 48537611Sahasty{ 48639841Ssos int s; 48739841Ssos struct ipxpcb *ipxp = sotoipxpcb(so); 48839841Ssos 48924528Sfsmp if (ipxp == NULL) 49023599Smarkm return (ENOTCONN); 49124528Sfsmp s = splnet(); 49224528Sfsmp ipx_pcbdetach(ipxp); 49336090Sahasty splx(s); 49436090Sahasty return (0); 49536090Sahasty} 49636090Sahasty 49736090Sahastystatic int 49836090Sahastyipx_disconnect(so) 49936090Sahasty struct socket *so; 50036090Sahasty{ 501 int s; 502 struct ipxpcb *ipxp = sotoipxpcb(so); 503 504 if (ipx_nullhost(ipxp->ipxp_faddr)) 505 return (ENOTCONN); 506 s = splnet(); 507 ipx_pcbdisconnect(ipxp); 508 splx(s); 509 soisdisconnected(so); 510 return (0); 511} 512 513int 514ipx_peeraddr(so, nam) 515 struct socket *so; 516 struct sockaddr **nam; 517{ 518 struct ipxpcb *ipxp = sotoipxpcb(so); 519 520 ipx_setpeeraddr(ipxp, nam); /* XXX what if alloc fails? */ 521 return (0); 522} 523 524static int 525ipx_send(so, flags, m, nam, control, td) 526 struct socket *so; 527 int flags; 528 struct mbuf *m; 529 struct sockaddr *nam; 530 struct mbuf *control; 531 struct thread *td; 532{ 533 int error; 534 struct ipxpcb *ipxp = sotoipxpcb(so); 535 struct ipx_addr laddr; 536 int s = 0; 537 538 if (nam != NULL) { 539 laddr = ipxp->ipxp_laddr; 540 if (!ipx_nullhost(ipxp->ipxp_faddr)) { 541 error = EISCONN; 542 goto send_release; 543 } 544 /* 545 * Must block input while temporarily connected. 546 */ 547 s = splnet(); 548 error = ipx_pcbconnect(ipxp, nam, td); 549 if (error) { 550 splx(s); 551 goto send_release; 552 } 553 } else { 554 if (ipx_nullhost(ipxp->ipxp_faddr)) { 555 error = ENOTCONN; 556 goto send_release; 557 } 558 } 559 error = ipx_output(ipxp, m); 560 m = NULL; 561 if (nam != NULL) { 562 ipx_pcbdisconnect(ipxp); 563 splx(s); 564 ipxp->ipxp_laddr = laddr; 565 } 566 567send_release: 568 if (m != NULL) 569 m_freem(m); 570 return (error); 571} 572 573static int 574ipx_shutdown(so) 575 struct socket *so; 576{ 577 socantsendmore(so); 578 return (0); 579} 580 581int 582ipx_sockaddr(so, nam) 583 struct socket *so; 584 struct sockaddr **nam; 585{ 586 struct ipxpcb *ipxp = sotoipxpcb(so); 587 588 ipx_setsockaddr(ipxp, nam); /* XXX what if alloc fails? */ 589 return (0); 590} 591 592static int 593ripx_attach(so, proto, td) 594 struct socket *so; 595 int proto; 596 struct thread *td; 597{ 598 int error = 0; 599 int s; 600 struct ipxpcb *ipxp = sotoipxpcb(so); 601 602 if (td != NULL && (error = suser(td)) != 0) 603 return (error); 604 s = splnet(); 605 error = ipx_pcballoc(so, &ipxrawpcb, td); 606 splx(s); 607 if (error) 608 return (error); 609 error = soreserve(so, ipxsendspace, ipxrecvspace); 610 if (error) 611 return (error); 612 ipxp = sotoipxpcb(so); 613 ipxp->ipxp_faddr.x_host = ipx_broadhost; 614 ipxp->ipxp_flags = IPXP_RAWIN | IPXP_RAWOUT; 615 return (error); 616} 617