ipx_pcb.c revision 139823
1139823Simp/*- 2139485Srwatson * Copyright (c) 2004 Robert N. M. Watson 311819Sjulian * Copyright (c) 1995, Mike Mitchell 411819Sjulian * Copyright (c) 1984, 1985, 1986, 1987, 1993 511819Sjulian * The Regents of the University of California. All rights reserved. 611819Sjulian * 711819Sjulian * Redistribution and use in source and binary forms, with or without 811819Sjulian * modification, are permitted provided that the following conditions 911819Sjulian * are met: 1011819Sjulian * 1. Redistributions of source code must retain the above copyright 1111819Sjulian * notice, this list of conditions and the following disclaimer. 1211819Sjulian * 2. Redistributions in binary form must reproduce the above copyright 1311819Sjulian * notice, this list of conditions and the following disclaimer in the 1411819Sjulian * documentation and/or other materials provided with the distribution. 1511819Sjulian * 3. All advertising materials mentioning features or use of this software 1611819Sjulian * must display the following acknowledgement: 1711819Sjulian * This product includes software developed by the University of 1811819Sjulian * California, Berkeley and its contributors. 1911819Sjulian * 4. Neither the name of the University nor the names of its contributors 2011819Sjulian * may be used to endorse or promote products derived from this software 2111819Sjulian * without specific prior written permission. 2211819Sjulian * 2311819Sjulian * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2411819Sjulian * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2511819Sjulian * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2611819Sjulian * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2711819Sjulian * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2811819Sjulian * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2911819Sjulian * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 3011819Sjulian * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 3111819Sjulian * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3211819Sjulian * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3311819Sjulian * SUCH DAMAGE. 3411819Sjulian * 3512057Sjulian * @(#)ipx_pcb.c 3611819Sjulian */ 3711819Sjulian 38116189Sobrien#include <sys/cdefs.h> 39116189Sobrien__FBSDID("$FreeBSD: head/sys/netipx/ipx_pcb.c 139823 2005-01-07 01:45:51Z imp $"); 40116189Sobrien 4111819Sjulian#include <sys/param.h> 4211819Sjulian#include <sys/systm.h> 4329024Sbde#include <sys/malloc.h> 4411819Sjulian#include <sys/socket.h> 4511819Sjulian#include <sys/socketvar.h> 4611819Sjulian 4711819Sjulian#include <net/if.h> 4811819Sjulian#include <net/route.h> 4911819Sjulian 5011819Sjulian#include <netipx/ipx.h> 5111819Sjulian#include <netipx/ipx_if.h> 5211819Sjulian#include <netipx/ipx_pcb.h> 5325652Sjhay#include <netipx/ipx_var.h> 5411819Sjulian 5533181Seivindstatic struct ipx_addr zeroipx_addr; 56139584Srwatsonstatic u_short ipxpcb_lport_cache; 5711819Sjulian 5811819Sjulianint 5983366Sjulianipx_pcballoc(so, head, td) 6011819Sjulian struct socket *so; 61139444Srwatson struct ipxpcbhead *head; 6283366Sjulian struct thread *td; 6311819Sjulian{ 6411819Sjulian register struct ipxpcb *ipxp; 6511819Sjulian 6669781Sdwmalone MALLOC(ipxp, struct ipxpcb *, sizeof *ipxp, M_PCB, M_NOWAIT | M_ZERO); 6728270Swollman if (ipxp == NULL) 6811819Sjulian return (ENOBUFS); 6911819Sjulian ipxp->ipxp_socket = so; 7050519Sjhay if (ipxcksum) 7150519Sjhay ipxp->ipxp_flags |= IPXP_CHECKSUM; 72139444Srwatson LIST_INSERT_HEAD(head, ipxp, ipxp_list); 7311819Sjulian so->so_pcb = (caddr_t)ipxp; 7411819Sjulian return (0); 7511819Sjulian} 76139584Srwatson 7711819Sjulianint 7883366Sjulianipx_pcbbind(ipxp, nam, td) 7911819Sjulian register struct ipxpcb *ipxp; 8028270Swollman struct sockaddr *nam; 8183366Sjulian struct thread *td; 8211819Sjulian{ 8311819Sjulian register struct sockaddr_ipx *sipx; 8411819Sjulian u_short lport = 0; 8511819Sjulian 8611819Sjulian if (ipxp->ipxp_lport || !ipx_nullhost(ipxp->ipxp_laddr)) 8711819Sjulian return (EINVAL); 8825652Sjhay if (nam == NULL) 8911819Sjulian goto noname; 9028270Swollman sipx = (struct sockaddr_ipx *)nam; 9111819Sjulian if (!ipx_nullhost(sipx->sipx_addr)) { 9211819Sjulian int tport = sipx->sipx_port; 9311819Sjulian 9411819Sjulian sipx->sipx_port = 0; /* yech... */ 95139559Srwatson if (ifa_ifwithaddr((struct sockaddr *)sipx) == NULL) 9611819Sjulian return (EADDRNOTAVAIL); 9711819Sjulian sipx->sipx_port = tport; 9811819Sjulian } 9911819Sjulian lport = sipx->sipx_port; 10011819Sjulian if (lport) { 10111819Sjulian u_short aport = ntohs(lport); 10225345Sjhay int error; 10311819Sjulian 10425652Sjhay if (aport < IPXPORT_RESERVED && 10593593Sjhb td != NULL && (error = suser(td)) != 0) 10625345Sjhay return (error); 10711819Sjulian if (ipx_pcblookup(&zeroipx_addr, lport, 0)) 10811819Sjulian return (EADDRINUSE); 10911819Sjulian } 11011819Sjulian ipxp->ipxp_laddr = sipx->sipx_addr; 11111819Sjuliannoname: 11211819Sjulian if (lport == 0) 11311819Sjulian do { 114139445Srwatson ipxpcb_lport_cache++; 115139445Srwatson if ((ipxpcb_lport_cache < IPXPORT_RESERVED) || 116139445Srwatson (ipxpcb_lport_cache >= IPXPORT_WELLKNOWN)) 117139445Srwatson ipxpcb_lport_cache = IPXPORT_RESERVED; 118139445Srwatson lport = htons(ipxpcb_lport_cache); 11911819Sjulian } while (ipx_pcblookup(&zeroipx_addr, lport, 0)); 12011819Sjulian ipxp->ipxp_lport = lport; 12111819Sjulian return (0); 12211819Sjulian} 12311819Sjulian 12411819Sjulian/* 12511819Sjulian * Connect from a socket to a specified address. 12611819Sjulian * Both address and port must be specified in argument sipx. 12711819Sjulian * If don't have a local address for this socket yet, 12811819Sjulian * then pick one. 12911819Sjulian */ 13011819Sjulianint 13183366Sjulianipx_pcbconnect(ipxp, nam, td) 13211819Sjulian struct ipxpcb *ipxp; 13328270Swollman struct sockaddr *nam; 13483366Sjulian struct thread *td; 13511819Sjulian{ 13611819Sjulian struct ipx_ifaddr *ia; 13728270Swollman register struct sockaddr_ipx *sipx = (struct sockaddr_ipx *)nam; 13811819Sjulian register struct ipx_addr *dst; 13911819Sjulian register struct route *ro; 14011819Sjulian struct ifnet *ifp; 14111819Sjulian 14225652Sjhay ia = NULL; 14325652Sjhay 14411819Sjulian if (sipx->sipx_family != AF_IPX) 14511819Sjulian return (EAFNOSUPPORT); 14625652Sjhay if (sipx->sipx_port == 0 || ipx_nullhost(sipx->sipx_addr)) 14711819Sjulian return (EADDRNOTAVAIL); 14811819Sjulian /* 14911819Sjulian * If we haven't bound which network number to use as ours, 15011819Sjulian * we will use the number of the outgoing interface. 15111819Sjulian * This depends on having done a routing lookup, which 15211819Sjulian * we will probably have to do anyway, so we might 15311819Sjulian * as well do it now. On the other hand if we are 15411819Sjulian * sending to multiple destinations we may have already 15511819Sjulian * done the lookup, so see if we can use the route 15611819Sjulian * from before. In any case, we only 15711819Sjulian * chose a port number once, even if sending to multiple 15811819Sjulian * destinations. 15911819Sjulian */ 16011819Sjulian ro = &ipxp->ipxp_route; 16111819Sjulian dst = &satoipx_addr(ro->ro_dst); 16297658Stanimura if (ipxp->ipxp_socket->so_options & SO_DONTROUTE) 16311819Sjulian goto flush; 16411819Sjulian if (!ipx_neteq(ipxp->ipxp_lastdst, sipx->sipx_addr)) 16511819Sjulian goto flush; 16611819Sjulian if (!ipx_hosteq(ipxp->ipxp_lastdst, sipx->sipx_addr)) { 16725652Sjhay if (ro->ro_rt != NULL && !(ro->ro_rt->rt_flags & RTF_HOST)) { 16811819Sjulian /* can patch route to avoid rtalloc */ 16911819Sjulian *dst = sipx->sipx_addr; 17011819Sjulian } else { 17111819Sjulian flush: 17225652Sjhay if (ro->ro_rt != NULL) 17311819Sjulian RTFREE(ro->ro_rt); 17425652Sjhay ro->ro_rt = NULL; 17511819Sjulian } 17611819Sjulian }/* else cached route is ok; do nothing */ 17711819Sjulian ipxp->ipxp_lastdst = sipx->sipx_addr; 17811819Sjulian if ((ipxp->ipxp_socket->so_options & SO_DONTROUTE) == 0 && /*XXX*/ 17925652Sjhay (ro->ro_rt == NULL || ro->ro_rt->rt_ifp == NULL)) { 18011819Sjulian /* No route yet, so try to acquire one */ 18111819Sjulian ro->ro_dst.sa_family = AF_IPX; 18211819Sjulian ro->ro_dst.sa_len = sizeof(ro->ro_dst); 18311819Sjulian *dst = sipx->sipx_addr; 18411819Sjulian dst->x_port = 0; 185139556Srwatson rtalloc_ign(ro, 0); 18697658Stanimura } 18711819Sjulian if (ipx_neteqnn(ipxp->ipxp_laddr.x_net, ipx_zeronet)) { 188139584Srwatson /* 18911819Sjulian * If route is known or can be allocated now, 19011819Sjulian * our src addr is taken from the i/f, else punt. 19111819Sjulian */ 19211819Sjulian 19311819Sjulian /* 19411819Sjulian * If we found a route, use the address 19511819Sjulian * corresponding to the outgoing interface 19611819Sjulian */ 19725652Sjhay if (ro->ro_rt != NULL && (ifp = ro->ro_rt->rt_ifp) != NULL) 19825652Sjhay for (ia = ipx_ifaddr; ia != NULL; ia = ia->ia_next) 19911819Sjulian if (ia->ia_ifp == ifp) 20011819Sjulian break; 20125652Sjhay if (ia == NULL) { 20211819Sjulian u_short fport = sipx->sipx_addr.x_port; 20311819Sjulian sipx->sipx_addr.x_port = 0; 20411819Sjulian ia = (struct ipx_ifaddr *) 20511819Sjulian ifa_ifwithdstaddr((struct sockaddr *)sipx); 20611819Sjulian sipx->sipx_addr.x_port = fport; 20725652Sjhay if (ia == NULL) 20811819Sjulian ia = ipx_iaonnetof(&sipx->sipx_addr); 20925652Sjhay if (ia == NULL) 21011819Sjulian ia = ipx_ifaddr; 21125652Sjhay if (ia == NULL) 21211819Sjulian return (EADDRNOTAVAIL); 21311819Sjulian } 21411819Sjulian ipxp->ipxp_laddr.x_net = satoipx_addr(ia->ia_addr).x_net; 21511819Sjulian } 21625652Sjhay if (ipx_nullhost(ipxp->ipxp_laddr)) { 217139584Srwatson /* 21825652Sjhay * If route is known or can be allocated now, 21925652Sjhay * our src addr is taken from the i/f, else punt. 22025652Sjhay */ 22125652Sjhay 22225652Sjhay /* 22325652Sjhay * If we found a route, use the address 22425652Sjhay * corresponding to the outgoing interface 22525652Sjhay */ 22625652Sjhay if (ro->ro_rt != NULL && (ifp = ro->ro_rt->rt_ifp) != NULL) 22725652Sjhay for (ia = ipx_ifaddr; ia != NULL; ia = ia->ia_next) 22825652Sjhay if (ia->ia_ifp == ifp) 22925652Sjhay break; 23025652Sjhay if (ia == NULL) { 23125652Sjhay u_short fport = sipx->sipx_addr.x_port; 23225652Sjhay sipx->sipx_addr.x_port = 0; 23325652Sjhay ia = (struct ipx_ifaddr *) 23425652Sjhay ifa_ifwithdstaddr((struct sockaddr *)sipx); 23525652Sjhay sipx->sipx_addr.x_port = fport; 23625652Sjhay if (ia == NULL) 23725652Sjhay ia = ipx_iaonnetof(&sipx->sipx_addr); 23825652Sjhay if (ia == NULL) 23925652Sjhay ia = ipx_ifaddr; 24025652Sjhay if (ia == NULL) 24125652Sjhay return (EADDRNOTAVAIL); 24225652Sjhay } 24325652Sjhay ipxp->ipxp_laddr.x_host = satoipx_addr(ia->ia_addr).x_host; 24425652Sjhay } 24511819Sjulian if (ipx_pcblookup(&sipx->sipx_addr, ipxp->ipxp_lport, 0)) 24611819Sjulian return (EADDRINUSE); 24725652Sjhay if (ipxp->ipxp_lport == 0) 24883366Sjulian ipx_pcbbind(ipxp, (struct sockaddr *)NULL, td); 24925652Sjhay 25025652Sjhay /* XXX just leave it zero if we can't find a route */ 25125652Sjhay 25211819Sjulian ipxp->ipxp_faddr = sipx->sipx_addr; 25311819Sjulian /* Includes ipxp->ipxp_fport = sipx->sipx_port; */ 25411819Sjulian return (0); 25511819Sjulian} 25611819Sjulian 25711819Sjulianvoid 25811819Sjulianipx_pcbdisconnect(ipxp) 25911819Sjulian struct ipxpcb *ipxp; 26011819Sjulian{ 26111819Sjulian 26211819Sjulian ipxp->ipxp_faddr = zeroipx_addr; 26397658Stanimura if (ipxp->ipxp_socket->so_state & SS_NOFDREF) 26411819Sjulian ipx_pcbdetach(ipxp); 26511819Sjulian} 26611819Sjulian 26711819Sjulianvoid 26811819Sjulianipx_pcbdetach(ipxp) 26911819Sjulian struct ipxpcb *ipxp; 27011819Sjulian{ 27111819Sjulian struct socket *so = ipxp->ipxp_socket; 27211819Sjulian 273136682Srwatson ACCEPT_LOCK(); 274130387Srwatson SOCK_LOCK(so); 275139559Srwatson so->so_pcb = NULL; 27686487Sdillon sotryfree(so); 27725652Sjhay if (ipxp->ipxp_route.ro_rt != NULL) 278139557Srwatson RTFREE(ipxp->ipxp_route.ro_rt); 279139444Srwatson LIST_REMOVE(ipxp, ipxp_list); 28028270Swollman FREE(ipxp, M_PCB); 28111819Sjulian} 28211819Sjulian 28311819Sjulianvoid 28411819Sjulianipx_setsockaddr(ipxp, nam) 28511819Sjulian register struct ipxpcb *ipxp; 28628270Swollman struct sockaddr **nam; 28711819Sjulian{ 28828270Swollman struct sockaddr_ipx *sipx, ssipx; 289139584Srwatson 29028270Swollman sipx = &ssipx; 29125652Sjhay bzero((caddr_t)sipx, sizeof(*sipx)); 29211819Sjulian sipx->sipx_len = sizeof(*sipx); 29311819Sjulian sipx->sipx_family = AF_IPX; 29411819Sjulian sipx->sipx_addr = ipxp->ipxp_laddr; 295126425Srwatson *nam = sodupsockaddr((struct sockaddr *)sipx, M_NOWAIT); 29611819Sjulian} 29711819Sjulian 29811819Sjulianvoid 29911819Sjulianipx_setpeeraddr(ipxp, nam) 30011819Sjulian register struct ipxpcb *ipxp; 30128270Swollman struct sockaddr **nam; 30211819Sjulian{ 30328270Swollman struct sockaddr_ipx *sipx, ssipx; 304139587Srwatson 30528270Swollman sipx = &ssipx; 306139587Srwatson bzero(sipx, sizeof(*sipx)); 30711819Sjulian sipx->sipx_len = sizeof(*sipx); 30811819Sjulian sipx->sipx_family = AF_IPX; 30911819Sjulian sipx->sipx_addr = ipxp->ipxp_faddr; 310139587Srwatson *nam = sodupsockaddr((struct sockaddr *)sipx, M_WAITOK); 31111819Sjulian} 31211819Sjulian 31311819Sjulianstruct ipxpcb * 31411819Sjulianipx_pcblookup(faddr, lport, wildp) 31511819Sjulian struct ipx_addr *faddr; 31611819Sjulian u_short lport; 31711819Sjulian int wildp; 31811819Sjulian{ 319139559Srwatson register struct ipxpcb *ipxp, *match = NULL; 32011819Sjulian int matchwild = 3, wildcard; 32111819Sjulian u_short fport; 32211819Sjulian 32311819Sjulian fport = faddr->x_port; 324139444Srwatson LIST_FOREACH(ipxp, &ipxpcb_list, ipxp_list) { 32511819Sjulian if (ipxp->ipxp_lport != lport) 32611819Sjulian continue; 32711819Sjulian wildcard = 0; 32811819Sjulian if (ipx_nullhost(ipxp->ipxp_faddr)) { 32911819Sjulian if (!ipx_nullhost(*faddr)) 33011819Sjulian wildcard++; 33111819Sjulian } else { 33211819Sjulian if (ipx_nullhost(*faddr)) 33311819Sjulian wildcard++; 33411819Sjulian else { 33511819Sjulian if (!ipx_hosteq(ipxp->ipxp_faddr, *faddr)) 33611819Sjulian continue; 33711819Sjulian if (ipxp->ipxp_fport != fport) { 33811819Sjulian if (ipxp->ipxp_fport != 0) 33911819Sjulian continue; 34011819Sjulian else 34111819Sjulian wildcard++; 34211819Sjulian } 34311819Sjulian } 34411819Sjulian } 34525652Sjhay if (wildcard && wildp == 0) 34611819Sjulian continue; 34711819Sjulian if (wildcard < matchwild) { 34811819Sjulian match = ipxp; 34911819Sjulian matchwild = wildcard; 35011819Sjulian if (wildcard == 0) 35111819Sjulian break; 35211819Sjulian } 35311819Sjulian } 35411819Sjulian return (match); 35511819Sjulian} 356