ipx_pcb.c revision 169463
152419Sjulian/*- 252419Sjulian * Copyright (c) 1984, 1985, 1986, 1987, 1993 3139823Simp * The Regents of the University of California. 4139823Simp * Copyright (c) 2004-2006 Robert N. M. Watson 5139823Simp * All rights reserved. 652419Sjulian * 752419Sjulian * Redistribution and use in source and binary forms, with or without 852419Sjulian * modification, are permitted provided that the following conditions 952419Sjulian * are met: 1052419Sjulian * 1. Redistributions of source code must retain the above copyright 1152419Sjulian * notice, this list of conditions and the following disclaimer. 1252419Sjulian * 2. Redistributions in binary form must reproduce the above copyright 1352419Sjulian * notice, this list of conditions and the following disclaimer in the 1452419Sjulian * documentation and/or other materials provided with the distribution. 1552419Sjulian * 4. Neither the name of the University nor the names of its contributors 1652419Sjulian * may be used to endorse or promote products derived from this software 1752419Sjulian * without specific prior written permission. 1852419Sjulian * 1952419Sjulian * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2052419Sjulian * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2152419Sjulian * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2252419Sjulian * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2352419Sjulian * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2452419Sjulian * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2552419Sjulian * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2652419Sjulian * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2752419Sjulian * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2852419Sjulian * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2952419Sjulian * SUCH DAMAGE. 3052419Sjulian * 3152419Sjulian * Copyright (c) 1995, Mike Mitchell 3252419Sjulian * All rights reserved. 3352419Sjulian * 3452419Sjulian * Redistribution and use in source and binary forms, with or without 3552419Sjulian * modification, are permitted provided that the following conditions 3652419Sjulian * are met: 3752419Sjulian * 1. Redistributions of source code must retain the above copyright 3867506Sjulian * notice, this list of conditions and the following disclaimer. 3952419Sjulian * 2. Redistributions in binary form must reproduce the above copyright 4052419Sjulian * notice, this list of conditions and the following disclaimer in the 4152752Sjulian * documentation and/or other materials provided with the distribution. 4252419Sjulian * 3. All advertising materials mentioning features or use of this software 4352419Sjulian * must display the following acknowledgement: 4452419Sjulian * This product includes software developed by the University of 45122481Sru * California, Berkeley and its contributors. 4652419Sjulian * 4. Neither the name of the University nor the names of its contributors 4755205Speter * may be used to endorse or promote products derived from this software 4852419Sjulian * without specific prior written permission. 4952419Sjulian * 5052419Sjulian * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 5170784Sjulian * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 5274914Sjhb * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 5370784Sjulian * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 5470784Sjulian * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 5570700Sjulian * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 56146259Sglebius * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 57179973Sgnn * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 58146259Sglebius * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 59179973Sgnn * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 60146259Sglebius * SUCH DAMAGE. 6170870Sjulian * 6270870Sjulian * @(#)ipx_pcb.c 6370784Sjulian */ 6470784Sjulian 6570784Sjulian#include <sys/cdefs.h> 6670784Sjulian__FBSDID("$FreeBSD: head/sys/netipx/ipx_pcb.c 169463 2007-05-11 10:38:34Z rwatson $"); 6770784Sjulian 6870784Sjulian#include <sys/param.h> 6970784Sjulian#include <sys/systm.h> 7070784Sjulian#include <sys/malloc.h> 71178228Smav#include <sys/priv.h> 7270784Sjulian#include <sys/socket.h> 7370784Sjulian#include <sys/socketvar.h> 7470784Sjulian 7570784Sjulian#include <net/if.h> 7670784Sjulian#include <net/route.h> 7770784Sjulian 7870784Sjulian#include <netipx/ipx.h> 7970784Sjulian#include <netipx/ipx_if.h> 8070784Sjulian#include <netipx/ipx_pcb.h> 8170784Sjulian#include <netipx/ipx_var.h> 8270784Sjulian 8370784Sjulianstatic struct ipx_addr zeroipx_addr; 8470784Sjulianstatic u_short ipxpcb_lport_cache; 8570784Sjulian 8670700Sjulianint 8770784Sjulianipx_pcballoc(struct socket *so, struct ipxpcbhead *head, struct thread *td) 8870784Sjulian{ 8970700Sjulian struct ipxpcb *ipxp; 9071885Sjulian 9171885Sjulian KASSERT(so->so_pcb == NULL, ("ipx_pcballoc: so_pcb != NULL")); 92129836Sjulian IPX_LIST_LOCK_ASSERT(); 9371885Sjulian 9471885Sjulian MALLOC(ipxp, struct ipxpcb *, sizeof *ipxp, M_PCB, M_NOWAIT | M_ZERO); 9571885Sjulian if (ipxp == NULL) 9671885Sjulian return (ENOBUFS); 9771885Sjulian IPX_LOCK_INIT(ipxp); 9871885Sjulian ipxp->ipxp_socket = so; 9971885Sjulian if (ipxcksum) 10071885Sjulian ipxp->ipxp_flags |= IPXP_CHECKSUM; 10171885Sjulian LIST_INSERT_HEAD(head, ipxp, ipxp_list); 10270784Sjulian so->so_pcb = (caddr_t)ipxp; 10370784Sjulian return (0); 10470784Sjulian} 10570784Sjulian 10652419Sjulianint 10752419Sjulianipx_pcbbind(struct ipxpcb *ipxp, struct sockaddr *nam, struct thread *td) 10852419Sjulian{ 109125021Sharti struct sockaddr_ipx *sipx; 11070784Sjulian u_short lport = 0; 11170784Sjulian 112148238Sglebius IPX_LIST_LOCK_ASSERT(); 11370784Sjulian IPX_LOCK_ASSERT(ipxp); 11470784Sjulian 11570784Sjulian if (ipxp->ipxp_lport || !ipx_nullhost(ipxp->ipxp_laddr)) 11671885Sjulian return (EINVAL); 11771885Sjulian if (nam == NULL) 118178228Smav goto noname; 11970784Sjulian sipx = (struct sockaddr_ipx *)nam; 12070784Sjulian if (!ipx_nullhost(sipx->sipx_addr)) { 12170784Sjulian int tport = sipx->sipx_port; 12270784Sjulian 12370784Sjulian sipx->sipx_port = 0; /* yech... */ 12470784Sjulian if (ifa_ifwithaddr((struct sockaddr *)sipx) == NULL) 12570784Sjulian return (EADDRNOTAVAIL); 12652419Sjulian sipx->sipx_port = tport; 12752419Sjulian } 12852419Sjulian lport = sipx->sipx_port; 12969922Sjulian if (lport) { 13070700Sjulian u_short aport = ntohs(lport); 13170935Sjulian 132175847Smav if (aport < IPXPORT_RESERVED && td != NULL && 13352419Sjulian priv_check(td, PRIV_NETIPX_RESERVEDPORT)) 13452419Sjulian return (EACCES); 13570784Sjulian if (ipx_pcblookup(&zeroipx_addr, lport, 0)) 13670784Sjulian return (EADDRINUSE); 13770784Sjulian } 13870784Sjulian ipxp->ipxp_laddr = sipx->sipx_addr; 13970784Sjuliannoname: 14070784Sjulian if (lport == 0) 14170784Sjulian do { 14270784Sjulian ipxpcb_lport_cache++; 14371885Sjulian if ((ipxpcb_lport_cache < IPXPORT_RESERVED) || 14471885Sjulian (ipxpcb_lport_cache >= IPXPORT_WELLKNOWN)) 14570784Sjulian ipxpcb_lport_cache = IPXPORT_RESERVED; 14670784Sjulian lport = htons(ipxpcb_lport_cache); 14773370Sjulian } while (ipx_pcblookup(&zeroipx_addr, lport, 0)); 14870784Sjulian ipxp->ipxp_lport = lport; 14970784Sjulian return (0); 15070784Sjulian} 15170784Sjulian 15270784Sjulian/* 153175847Smav * Connect from a socket to a specified address. 15470784Sjulian * Both address and port must be specified in argument sipx. 15570784Sjulian * If don't have a local address for this socket yet, 15670784Sjulian * then pick one. 15770784Sjulian */ 15870784Sjulianint 15970784Sjulianipx_pcbconnect(struct ipxpcb *ipxp, struct sockaddr *nam, struct thread *td) 16070784Sjulian{ 16170784Sjulian struct ipx_ifaddr *ia; 16270784Sjulian struct sockaddr_ipx *sipx = (struct sockaddr_ipx *)nam; 16370784Sjulian struct ipx_addr *dst; 16470784Sjulian struct route *ro; 16570784Sjulian struct ifnet *ifp; 16670784Sjulian 16770784Sjulian IPX_LIST_LOCK_ASSERT(); 16871885Sjulian IPX_LOCK_ASSERT(ipxp); 16971885Sjulian 17071885Sjulian ia = NULL; 17171885Sjulian 17271885Sjulian if (sipx->sipx_family != AF_IPX) 17370784Sjulian return (EAFNOSUPPORT); 17470784Sjulian if (sipx->sipx_port == 0 || ipx_nullhost(sipx->sipx_addr)) 17570784Sjulian return (EADDRNOTAVAIL); 17670784Sjulian /* 17770784Sjulian * If we haven't bound which network number to use as ours, 17870784Sjulian * we will use the number of the outgoing interface. 17970784Sjulian * This depends on having done a routing lookup, which 18070784Sjulian * we will probably have to do anyway, so we might 18170784Sjulian * as well do it now. On the other hand if we are 182148870Sjulian * sending to multiple destinations we may have already 18370784Sjulian * done the lookup, so see if we can use the route 18470784Sjulian * from before. In any case, we only 18570784Sjulian * chose a port number once, even if sending to multiple 18670784Sjulian * destinations. 18770784Sjulian */ 18870784Sjulian ro = &ipxp->ipxp_route; 18970784Sjulian dst = &satoipx_addr(ro->ro_dst); 19070784Sjulian if (ipxp->ipxp_socket->so_options & SO_DONTROUTE) 19170784Sjulian goto flush; 19270784Sjulian if (!ipx_neteq(ipxp->ipxp_lastdst, sipx->sipx_addr)) 19370784Sjulian goto flush; 19470784Sjulian if (!ipx_hosteq(ipxp->ipxp_lastdst, sipx->sipx_addr)) { 19570784Sjulian if (ro->ro_rt != NULL && !(ro->ro_rt->rt_flags & RTF_HOST)) { 19670784Sjulian /* can patch route to avoid rtalloc */ 19770784Sjulian *dst = sipx->sipx_addr; 198152451Sglebius } else { 19970784Sjulian flush: 20070784Sjulian if (ro->ro_rt != NULL) 20170784Sjulian RTFREE(ro->ro_rt); 20270784Sjulian ro->ro_rt = NULL; 20370784Sjulian } 20470784Sjulian }/* else cached route is ok; do nothing */ 205152451Sglebius ipxp->ipxp_lastdst = sipx->sipx_addr; 20670784Sjulian if ((ipxp->ipxp_socket->so_options & SO_DONTROUTE) == 0 && /*XXX*/ 20770784Sjulian (ro->ro_rt == NULL || ro->ro_rt->rt_ifp == NULL)) { 20870784Sjulian /* No route yet, so try to acquire one */ 20970784Sjulian ro->ro_dst.sa_family = AF_IPX; 21070784Sjulian ro->ro_dst.sa_len = sizeof(ro->ro_dst); 21170784Sjulian *dst = sipx->sipx_addr; 212152451Sglebius dst->x_port = 0; 21370784Sjulian rtalloc_ign(ro, 0); 21470784Sjulian } 21570784Sjulian if (ipx_neteqnn(ipxp->ipxp_laddr.x_net, ipx_zeronet)) { 21670784Sjulian /* 21770784Sjulian * If route is known or can be allocated now, 21870784Sjulian * our src addr is taken from the i/f, else punt. 219152451Sglebius */ 22070784Sjulian 22171885Sjulian /* 22271885Sjulian * If we found a route, use the address 22371885Sjulian * corresponding to the outgoing interface 22471885Sjulian */ 22571885Sjulian if (ro->ro_rt != NULL && (ifp = ro->ro_rt->rt_ifp) != NULL) 226152451Sglebius for (ia = ipx_ifaddr; ia != NULL; ia = ia->ia_next) 22771885Sjulian if (ia->ia_ifp == ifp) 22871885Sjulian break; 22971885Sjulian if (ia == NULL) { 23071885Sjulian u_short fport = sipx->sipx_addr.x_port; 23171885Sjulian sipx->sipx_addr.x_port = 0; 23271885Sjulian ia = (struct ipx_ifaddr *) 233152451Sglebius ifa_ifwithdstaddr((struct sockaddr *)sipx); 23471885Sjulian sipx->sipx_addr.x_port = fport; 23570784Sjulian if (ia == NULL) 23670784Sjulian ia = ipx_iaonnetof(&sipx->sipx_addr); 23770784Sjulian if (ia == NULL) 23870784Sjulian ia = ipx_ifaddr; 23970784Sjulian if (ia == NULL) 240152451Sglebius return (EADDRNOTAVAIL); 24170784Sjulian } 24270784Sjulian ipxp->ipxp_laddr.x_net = satoipx_addr(ia->ia_addr).x_net; 24370784Sjulian } 24470784Sjulian if (ipx_nullhost(ipxp->ipxp_laddr)) { 24570784Sjulian /* 24670784Sjulian * If route is known or can be allocated now, 247152451Sglebius * our src addr is taken from the i/f, else punt. 24870784Sjulian */ 24970784Sjulian 25070784Sjulian /* 25170784Sjulian * If we found a route, use the address 25270784Sjulian * corresponding to the outgoing interface 25370784Sjulian */ 254152451Sglebius if (ro->ro_rt != NULL && (ifp = ro->ro_rt->rt_ifp) != NULL) 25570784Sjulian for (ia = ipx_ifaddr; ia != NULL; ia = ia->ia_next) 25670784Sjulian if (ia->ia_ifp == ifp) 25770784Sjulian break; 25870784Sjulian if (ia == NULL) { 25970784Sjulian u_short fport = sipx->sipx_addr.x_port; 26070784Sjulian sipx->sipx_addr.x_port = 0; 261152451Sglebius ia = (struct ipx_ifaddr *) 26270784Sjulian ifa_ifwithdstaddr((struct sockaddr *)sipx); 26370784Sjulian sipx->sipx_addr.x_port = fport; 26470784Sjulian if (ia == NULL) 26570784Sjulian ia = ipx_iaonnetof(&sipx->sipx_addr); 26670784Sjulian if (ia == NULL) 26770784Sjulian ia = ipx_ifaddr; 268152451Sglebius if (ia == NULL) 26970784Sjulian return (EADDRNOTAVAIL); 27070784Sjulian } 27170784Sjulian ipxp->ipxp_laddr.x_host = satoipx_addr(ia->ia_addr).x_host; 27270784Sjulian } 27370784Sjulian if (ipx_pcblookup(&sipx->sipx_addr, ipxp->ipxp_lport, 0)) 27470784Sjulian return (EADDRINUSE); 275152451Sglebius if (ipxp->ipxp_lport == 0) 27670784Sjulian ipx_pcbbind(ipxp, (struct sockaddr *)NULL, td); 27770784Sjulian 27870784Sjulian /* XXX just leave it zero if we can't find a route */ 27970784Sjulian 28070784Sjulian ipxp->ipxp_faddr = sipx->sipx_addr; 28170784Sjulian /* Includes ipxp->ipxp_fport = sipx->sipx_port; */ 282152451Sglebius return (0); 28370784Sjulian} 284175847Smav 285175847Smavvoid 286175847Smavipx_pcbdisconnect(struct ipxpcb *ipxp) 287175847Smav{ 288175847Smav 289175847Smav IPX_LIST_LOCK_ASSERT(); 29070784Sjulian IPX_LOCK_ASSERT(ipxp); 291175847Smav 29270784Sjulian ipxp->ipxp_faddr = zeroipx_addr; 29370784Sjulian} 29470784Sjulian 29570784Sjulianvoid 29671885Sjulianipx_pcbdetach(struct ipxpcb *ipxp) 29771885Sjulian{ 29870784Sjulian struct socket *so = ipxp->ipxp_socket; 29970784Sjulian 30070784Sjulian IPX_LIST_LOCK_ASSERT(); 30170784Sjulian IPX_LOCK_ASSERT(ipxp); 30270784Sjulian 30370784Sjulian so->so_pcb = NULL; 30470784Sjulian ipxp->ipxp_socket = NULL; 305175847Smav} 30670784Sjulian 30770784Sjulianvoid 30870784Sjulianipx_pcbfree(struct ipxpcb *ipxp) 30970784Sjulian{ 31070784Sjulian 31170784Sjulian KASSERT(ipxp->ipxp_socket == NULL, 31270784Sjulian ("ipx_pcbfree: ipxp_socket != NULL")); 31371885Sjulian IPX_LIST_LOCK_ASSERT(); 31471885Sjulian IPX_LOCK_ASSERT(ipxp); 31570784Sjulian 31670784Sjulian if (ipxp->ipxp_route.ro_rt != NULL) 31770784Sjulian RTFREE(ipxp->ipxp_route.ro_rt); 31870784Sjulian LIST_REMOVE(ipxp, ipxp_list); 31970784Sjulian IPX_LOCK_DESTROY(ipxp); 32070784Sjulian FREE(ipxp, M_PCB); 32170784Sjulian} 322175847Smav 32370784Sjulianvoid 32470784Sjulianipx_getsockaddr(struct ipxpcb *ipxp, struct sockaddr **nam) 32570784Sjulian{ 32670784Sjulian struct sockaddr_ipx *sipx, ssipx; 32770784Sjulian 32870784Sjulian sipx = &ssipx; 32952419Sjulian bzero((caddr_t)sipx, sizeof(*sipx)); 33070784Sjulian sipx->sipx_len = sizeof(*sipx); 33170784Sjulian sipx->sipx_family = AF_IPX; 332152451Sglebius IPX_LOCK(ipxp); 33370784Sjulian sipx->sipx_addr = ipxp->ipxp_laddr; 33452419Sjulian IPX_UNLOCK(ipxp); 33570784Sjulian *nam = sodupsockaddr((struct sockaddr *)sipx, M_WAITOK); 336178228Smav} 337178228Smav 338152451Sglebiusvoid 339178228Smavipx_getpeeraddr(struct ipxpcb *ipxp, struct sockaddr **nam) 340178228Smav{ 34170784Sjulian struct sockaddr_ipx *sipx, ssipx; 34270784Sjulian 34352419Sjulian sipx = &ssipx; 344125021Sharti bzero(sipx, sizeof(*sipx)); 34570784Sjulian sipx->sipx_len = sizeof(*sipx); 34670784Sjulian sipx->sipx_family = AF_IPX; 34770784Sjulian IPX_LOCK(ipxp); 34870784Sjulian sipx->sipx_addr = ipxp->ipxp_faddr; 34970784Sjulian IPX_UNLOCK(ipxp); 35070784Sjulian *nam = sodupsockaddr((struct sockaddr *)sipx, M_WAITOK); 35170784Sjulian} 35270784Sjulian 35370784Sjulianstruct ipxpcb * 354178228Smavipx_pcblookup(struct ipx_addr *faddr, u_short lport, int wildp) 35570784Sjulian{ 35670784Sjulian struct ipxpcb *ipxp, *match = NULL; 35770784Sjulian int matchwild = 3, wildcard; 35870784Sjulian u_short fport; 35970784Sjulian 36070784Sjulian IPX_LIST_LOCK_ASSERT(); 36170784Sjulian 36252419Sjulian fport = faddr->x_port; 36352419Sjulian LIST_FOREACH(ipxp, &ipxpcb_list, ipxp_list) { 36452419Sjulian if (ipxp->ipxp_lport != lport) 365132464Sjulian continue; 366132464Sjulian wildcard = 0; 367132464Sjulian if (ipx_nullhost(ipxp->ipxp_faddr)) { 368132464Sjulian if (!ipx_nullhost(*faddr)) 369132464Sjulian wildcard++; 370132464Sjulian } else { 371132464Sjulian if (ipx_nullhost(*faddr)) 372132464Sjulian wildcard++; 373175847Smav else { 37452419Sjulian if (!ipx_hosteq(ipxp->ipxp_faddr, *faddr)) 37552419Sjulian continue; 37652419Sjulian if (ipxp->ipxp_fport != fport) { 37752419Sjulian if (ipxp->ipxp_fport != 0) 37852419Sjulian continue; 37952419Sjulian else 38070784Sjulian wildcard++; 38170784Sjulian } 38270784Sjulian } 38374078Sjulian } 38470784Sjulian if (wildcard && wildp == 0) 38570784Sjulian continue; 38670784Sjulian if (wildcard < matchwild) { 38770784Sjulian match = ipxp; 38870784Sjulian matchwild = wildcard; 38970784Sjulian if (wildcard == 0) 39070784Sjulian break; 391132464Sjulian } 392132464Sjulian } 39370784Sjulian return (match); 39470784Sjulian} 395132464Sjulian