ipx_pcb.c revision 21673
1214501Srpaulo/* 2214501Srpaulo * Copyright (c) 1995, Mike Mitchell 3214501Srpaulo * Copyright (c) 1984, 1985, 1986, 1987, 1993 4214501Srpaulo * The Regents of the University of California. All rights reserved. 5214501Srpaulo * 6214501Srpaulo * Redistribution and use in source and binary forms, with or without 7214501Srpaulo * modification, are permitted provided that the following conditions 8214501Srpaulo * are met: 9214501Srpaulo * 1. Redistributions of source code must retain the above copyright 10214501Srpaulo * notice, this list of conditions and the following disclaimer. 11214501Srpaulo * 2. Redistributions in binary form must reproduce the above copyright 12214501Srpaulo * notice, this list of conditions and the following disclaimer in the 13214501Srpaulo * documentation and/or other materials provided with the distribution. 14214501Srpaulo * 3. All advertising materials mentioning features or use of this software 15214501Srpaulo * must display the following acknowledgement: 16214501Srpaulo * This product includes software developed by the University of 17214501Srpaulo * California, Berkeley and its contributors. 18214501Srpaulo * 4. Neither the name of the University nor the names of its contributors 19214501Srpaulo * may be used to endorse or promote products derived from this software 20214501Srpaulo * without specific prior written permission. 21214501Srpaulo * 22214501Srpaulo * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 23214501Srpaulo * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24214501Srpaulo * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25214501Srpaulo * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 26214501Srpaulo * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27214501Srpaulo * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28214501Srpaulo * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29214501Srpaulo * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30214501Srpaulo * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31214501Srpaulo * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32214501Srpaulo * SUCH DAMAGE. 33214501Srpaulo * 34214501Srpaulo * @(#)ipx_pcb.c 35214501Srpaulo * 36214501Srpaulo * $FreeBSD: head/sys/netipx/ipx_pcb.c 21673 1997-01-14 07:20:47Z jkh $ 37214501Srpaulo */ 38214501Srpaulo 39214501Srpaulo#include <sys/param.h> 40214501Srpaulo#include <sys/queue.h> 41214501Srpaulo#include <sys/systm.h> 42214501Srpaulo#include <sys/mbuf.h> 43214501Srpaulo#include <sys/errno.h> 44214501Srpaulo#include <sys/socket.h> 45214501Srpaulo#include <sys/socketvar.h> 46214501Srpaulo#include <sys/protosw.h> 47214501Srpaulo 48214501Srpaulo#include <net/if.h> 49214501Srpaulo#include <net/route.h> 50214501Srpaulo 51214501Srpaulo#include <netipx/ipx.h> 52214501Srpaulo#include <netipx/ipx_if.h> 53214501Srpaulo#include <netipx/ipx_pcb.h> 54214501Srpaulo 55214501Srpaulostruct ipx_addr zeroipx_addr; 56214501Srpaulo 57214501Srpauloint 58214501Srpauloipx_pcballoc(so, head) 59214501Srpaulo struct socket *so; 60214501Srpaulo struct ipxpcb *head; 61214501Srpaulo{ 62214501Srpaulo struct mbuf *m; 63214501Srpaulo register struct ipxpcb *ipxp; 64214501Srpaulo 65214501Srpaulo m = m_getclr(M_DONTWAIT, MT_PCB); 66214501Srpaulo if (m == NULL) 67214501Srpaulo return (ENOBUFS); 68214501Srpaulo ipxp = mtod(m, struct ipxpcb *); 69214501Srpaulo ipxp->ipxp_socket = so; 70214501Srpaulo insque(ipxp, head); 71214501Srpaulo so->so_pcb = (caddr_t)ipxp; 72214501Srpaulo return (0); 73214501Srpaulo} 74214501Srpaulo 75214501Srpauloint 76214501Srpauloipx_pcbbind(ipxp, nam) 77214501Srpaulo register struct ipxpcb *ipxp; 78214501Srpaulo struct mbuf *nam; 79214501Srpaulo{ 80214501Srpaulo register struct sockaddr_ipx *sipx; 81214501Srpaulo u_short lport = 0; 82214501Srpaulo 83214501Srpaulo if (ipxp->ipxp_lport || !ipx_nullhost(ipxp->ipxp_laddr)) 84214501Srpaulo return (EINVAL); 85214501Srpaulo if (nam == 0) 86214501Srpaulo goto noname; 87214501Srpaulo sipx = mtod(nam, struct sockaddr_ipx *); 88214501Srpaulo if (nam->m_len != sizeof (*sipx)) 89214501Srpaulo return (EINVAL); 90214501Srpaulo if (!ipx_nullhost(sipx->sipx_addr)) { 91214501Srpaulo int tport = sipx->sipx_port; 92214501Srpaulo 93214501Srpaulo sipx->sipx_port = 0; /* yech... */ 94214501Srpaulo if (ifa_ifwithaddr((struct sockaddr *)sipx) == 0) 95214501Srpaulo return (EADDRNOTAVAIL); 96214501Srpaulo sipx->sipx_port = tport; 97214501Srpaulo } 98214501Srpaulo lport = sipx->sipx_port; 99214501Srpaulo if (lport) { 100214501Srpaulo u_short aport = ntohs(lport); 101214501Srpaulo 102214501Srpaulo if (aport < IPXPORT_MAX && 103214501Srpaulo (ipxp->ipxp_socket->so_state & SS_PRIV) == 0) 104214501Srpaulo return (EACCES); 105214501Srpaulo if (ipx_pcblookup(&zeroipx_addr, lport, 0)) 106214501Srpaulo return (EADDRINUSE); 107214501Srpaulo } 108214501Srpaulo ipxp->ipxp_laddr = sipx->sipx_addr; 109214501Srpaulononame: 110214501Srpaulo if (lport == 0) 111214501Srpaulo do { 112214501Srpaulo if (ipxpcb.ipxp_lport++ < IPXPORT_MAX) 113214501Srpaulo ipxpcb.ipxp_lport = IPXPORT_MAX; 114214501Srpaulo lport = htons(ipxpcb.ipxp_lport); 115214501Srpaulo } while (ipx_pcblookup(&zeroipx_addr, lport, 0)); 116214501Srpaulo ipxp->ipxp_lport = lport; 117214501Srpaulo return (0); 118214501Srpaulo} 119214501Srpaulo 120214501Srpaulo/* 121214501Srpaulo * Connect from a socket to a specified address. 122214501Srpaulo * Both address and port must be specified in argument sipx. 123214501Srpaulo * If don't have a local address for this socket yet, 124214501Srpaulo * then pick one. 125214501Srpaulo */ 126214501Srpauloint 127214501Srpauloipx_pcbconnect(ipxp, nam) 128214501Srpaulo struct ipxpcb *ipxp; 129214501Srpaulo struct mbuf *nam; 130214501Srpaulo{ 131214501Srpaulo struct ipx_ifaddr *ia; 132214501Srpaulo register struct sockaddr_ipx *sipx = mtod(nam, struct sockaddr_ipx *); 133214501Srpaulo register struct ipx_addr *dst; 134214501Srpaulo register struct route *ro; 135214501Srpaulo struct ifnet *ifp; 136214501Srpaulo 137214501Srpaulo if (nam->m_len != sizeof (*sipx)) 138214501Srpaulo return (EINVAL); 139214501Srpaulo if (sipx->sipx_family != AF_IPX) 140214501Srpaulo return (EAFNOSUPPORT); 141214501Srpaulo if (sipx->sipx_port==0 || ipx_nullhost(sipx->sipx_addr)) 142214501Srpaulo return (EADDRNOTAVAIL); 143214501Srpaulo /* 144214501Srpaulo * If we haven't bound which network number to use as ours, 145214501Srpaulo * we will use the number of the outgoing interface. 146214501Srpaulo * This depends on having done a routing lookup, which 147214501Srpaulo * we will probably have to do anyway, so we might 148214501Srpaulo * as well do it now. On the other hand if we are 149214501Srpaulo * sending to multiple destinations we may have already 150214501Srpaulo * done the lookup, so see if we can use the route 151214501Srpaulo * from before. In any case, we only 152214501Srpaulo * chose a port number once, even if sending to multiple 153214501Srpaulo * destinations. 154214501Srpaulo */ 155214501Srpaulo ro = &ipxp->ipxp_route; 156214501Srpaulo dst = &satoipx_addr(ro->ro_dst); 157214501Srpaulo if (ipxp->ipxp_socket->so_options & SO_DONTROUTE) 158214501Srpaulo goto flush; 159214501Srpaulo if (!ipx_neteq(ipxp->ipxp_lastdst, sipx->sipx_addr)) 160214501Srpaulo goto flush; 161214501Srpaulo if (!ipx_hosteq(ipxp->ipxp_lastdst, sipx->sipx_addr)) { 162214501Srpaulo if (ro->ro_rt && ! (ro->ro_rt->rt_flags & RTF_HOST)) { 163214501Srpaulo /* can patch route to avoid rtalloc */ 164214501Srpaulo *dst = sipx->sipx_addr; 165214501Srpaulo } else { 166214501Srpaulo flush: 167214501Srpaulo if (ro->ro_rt) 168214501Srpaulo RTFREE(ro->ro_rt); 169214501Srpaulo ro->ro_rt = (struct rtentry *)0; 170214501Srpaulo ipxp->ipxp_laddr.x_net = ipx_zeronet; 171214501Srpaulo } 172214501Srpaulo }/* else cached route is ok; do nothing */ 173214501Srpaulo ipxp->ipxp_lastdst = sipx->sipx_addr; 174214501Srpaulo if ((ipxp->ipxp_socket->so_options & SO_DONTROUTE) == 0 && /*XXX*/ 175214501Srpaulo (ro->ro_rt == (struct rtentry *)0 || 176214501Srpaulo ro->ro_rt->rt_ifp == (struct ifnet *)0)) { 177214501Srpaulo /* No route yet, so try to acquire one */ 178214501Srpaulo ro->ro_dst.sa_family = AF_IPX; 179214501Srpaulo ro->ro_dst.sa_len = sizeof(ro->ro_dst); 180214501Srpaulo *dst = sipx->sipx_addr; 181214501Srpaulo dst->x_port = 0; 182214501Srpaulo rtalloc(ro); 183214501Srpaulo } 184214501Srpaulo if (ipx_neteqnn(ipxp->ipxp_laddr.x_net, ipx_zeronet)) { 185214501Srpaulo /* 186214501Srpaulo * If route is known or can be allocated now, 187214501Srpaulo * our src addr is taken from the i/f, else punt. 188214501Srpaulo */ 189214501Srpaulo 190214501Srpaulo ia = (struct ipx_ifaddr *)0; 191214501Srpaulo /* 192214501Srpaulo * If we found a route, use the address 193214501Srpaulo * corresponding to the outgoing interface 194214501Srpaulo */ 195214501Srpaulo if (ro->ro_rt && (ifp = ro->ro_rt->rt_ifp)) 196214501Srpaulo for (ia = ipx_ifaddr; ia; ia = ia->ia_next) 197214501Srpaulo if (ia->ia_ifp == ifp) 198214501Srpaulo break; 199214501Srpaulo if (ia == 0) { 200214501Srpaulo u_short fport = sipx->sipx_addr.x_port; 201214501Srpaulo sipx->sipx_addr.x_port = 0; 202214501Srpaulo ia = (struct ipx_ifaddr *) 203214501Srpaulo ifa_ifwithdstaddr((struct sockaddr *)sipx); 204214501Srpaulo sipx->sipx_addr.x_port = fport; 205214501Srpaulo if (ia == 0) 206214501Srpaulo ia = ipx_iaonnetof(&sipx->sipx_addr); 207214501Srpaulo if (ia == 0) 208214501Srpaulo ia = ipx_ifaddr; 209214501Srpaulo if (ia == 0) 210214501Srpaulo return (EADDRNOTAVAIL); 211214501Srpaulo } 212214501Srpaulo ipxp->ipxp_laddr.x_net = satoipx_addr(ia->ia_addr).x_net; 213214501Srpaulo } 214214501Srpaulo if (ipx_pcblookup(&sipx->sipx_addr, ipxp->ipxp_lport, 0)) 215214501Srpaulo return (EADDRINUSE); 216214501Srpaulo if (ipx_nullhost(ipxp->ipxp_laddr)) { 217214501Srpaulo if (ipxp->ipxp_lport == 0) 218214501Srpaulo (void) ipx_pcbbind(ipxp, (struct mbuf *)0); 219214501Srpaulo ipxp->ipxp_laddr.x_host = ipx_thishost; 220214501Srpaulo } 221214501Srpaulo ipxp->ipxp_faddr = sipx->sipx_addr; 222214501Srpaulo /* Includes ipxp->ipxp_fport = sipx->sipx_port; */ 223214501Srpaulo return (0); 224214501Srpaulo} 225214501Srpaulo 226214501Srpaulovoid 227214501Srpauloipx_pcbdisconnect(ipxp) 228214501Srpaulo struct ipxpcb *ipxp; 229214501Srpaulo{ 230214501Srpaulo 231214501Srpaulo ipxp->ipxp_faddr = zeroipx_addr; 232214501Srpaulo if (ipxp->ipxp_socket->so_state & SS_NOFDREF) 233214501Srpaulo ipx_pcbdetach(ipxp); 234214501Srpaulo} 235214501Srpaulo 236214501Srpaulovoid 237214501Srpauloipx_pcbdetach(ipxp) 238214501Srpaulo struct ipxpcb *ipxp; 239214501Srpaulo{ 240214501Srpaulo struct socket *so = ipxp->ipxp_socket; 241214501Srpaulo 242214501Srpaulo so->so_pcb = 0; 243214501Srpaulo sofree(so); 244214501Srpaulo if (ipxp->ipxp_route.ro_rt) 245214501Srpaulo rtfree(ipxp->ipxp_route.ro_rt); 246214501Srpaulo remque(ipxp); 247214501Srpaulo (void) m_free(dtom(ipxp)); 248214501Srpaulo} 249214501Srpaulo 250214501Srpaulovoid 251214501Srpauloipx_setsockaddr(ipxp, nam) 252214501Srpaulo register struct ipxpcb *ipxp; 253214501Srpaulo struct mbuf *nam; 254214501Srpaulo{ 255214501Srpaulo register struct sockaddr_ipx *sipx = mtod(nam, struct sockaddr_ipx *); 256214501Srpaulo 257214501Srpaulo nam->m_len = sizeof (*sipx); 258214501Srpaulo sipx = mtod(nam, struct sockaddr_ipx *); 259214501Srpaulo bzero((caddr_t)sipx, sizeof (*sipx)); 260214501Srpaulo sipx->sipx_len = sizeof(*sipx); 261214501Srpaulo sipx->sipx_family = AF_IPX; 262214501Srpaulo sipx->sipx_addr = ipxp->ipxp_laddr; 263214501Srpaulo} 264214501Srpaulo 265214501Srpaulovoid 266214501Srpauloipx_setpeeraddr(ipxp, nam) 267214501Srpaulo register struct ipxpcb *ipxp; 268214501Srpaulo struct mbuf *nam; 269214501Srpaulo{ 270214501Srpaulo register struct sockaddr_ipx *sipx = mtod(nam, struct sockaddr_ipx *); 271214501Srpaulo 272214501Srpaulo nam->m_len = sizeof (*sipx); 273214501Srpaulo sipx = mtod(nam, struct sockaddr_ipx *); 274214501Srpaulo bzero((caddr_t)sipx, sizeof (*sipx)); 275214501Srpaulo sipx->sipx_len = sizeof(*sipx); 276214501Srpaulo sipx->sipx_family = AF_IPX; 277214501Srpaulo sipx->sipx_addr = ipxp->ipxp_faddr; 278214501Srpaulo} 279214501Srpaulo 280214501Srpaulo/* 281214501Srpaulo * Pass some notification to all connections of a protocol 282214501Srpaulo * associated with address dst. Call the 283214501Srpaulo * protocol specific routine to handle each connection. 284214501Srpaulo * Also pass an extra paramter via the ipxpcb. (which may in fact 285214501Srpaulo * be a parameter list!) 286214501Srpaulo */ 287214501Srpaulovoid 288214501Srpauloipx_pcbnotify(dst, errno, notify, param) 289214501Srpaulo register struct ipx_addr *dst; 290214501Srpaulo int errno; 291214501Srpaulo void (*notify)(struct ipxpcb *); 292214501Srpaulo long param; 293214501Srpaulo{ 294214501Srpaulo register struct ipxpcb *ipxp, *oinp; 295214501Srpaulo int s = splimp(); 296214501Srpaulo 297214501Srpaulo for (ipxp = (&ipxpcb)->ipxp_next; ipxp != (&ipxpcb);) { 298214501Srpaulo if (!ipx_hosteq(*dst,ipxp->ipxp_faddr)) { 299214501Srpaulo next: 300214501Srpaulo ipxp = ipxp->ipxp_next; 301214501Srpaulo continue; 302214501Srpaulo } 303214501Srpaulo if (ipxp->ipxp_socket == 0) 304214501Srpaulo goto next; 305214501Srpaulo if (errno) 306214501Srpaulo ipxp->ipxp_socket->so_error = errno; 307214501Srpaulo oinp = ipxp; 308214501Srpaulo ipxp = ipxp->ipxp_next; 309214501Srpaulo oinp->ipxp_notify_param = param; 310214501Srpaulo (*notify)(oinp); 311214501Srpaulo } 312214501Srpaulo splx(s); 313214501Srpaulo} 314214501Srpaulo 315214501Srpaulo#ifdef notdef 316214501Srpaulo/* 317214501Srpaulo * After a routing change, flush old routing 318214501Srpaulo * and allocate a (hopefully) better one. 319214501Srpaulo */ 320214501Srpauloipx_rtchange(ipxp) 321214501Srpaulo struct ipxpcb *ipxp; 322214501Srpaulo{ 323214501Srpaulo if (ipxp->ipxp_route.ro_rt) { 324214501Srpaulo rtfree(ipxp->ipxp_route.ro_rt); 325214501Srpaulo ipxp->ipxp_route.ro_rt = 0; 326214501Srpaulo /* 327214501Srpaulo * A new route can be allocated the next time 328214501Srpaulo * output is attempted. 329214501Srpaulo */ 330214501Srpaulo } 331214501Srpaulo /* SHOULD NOTIFY HIGHER-LEVEL PROTOCOLS */ 332214501Srpaulo} 333214501Srpaulo#endif 334214501Srpaulo 335214501Srpaulostruct ipxpcb * 336214501Srpauloipx_pcblookup(faddr, lport, wildp) 337214501Srpaulo struct ipx_addr *faddr; 338214501Srpaulo u_short lport; 339214501Srpaulo int wildp; 340214501Srpaulo{ 341214501Srpaulo register struct ipxpcb *ipxp, *match = 0; 342214501Srpaulo int matchwild = 3, wildcard; 343214501Srpaulo u_short fport; 344214501Srpaulo 345214501Srpaulo fport = faddr->x_port; 346214501Srpaulo for (ipxp = (&ipxpcb)->ipxp_next; ipxp != (&ipxpcb); ipxp = ipxp->ipxp_next) { 347214501Srpaulo if (ipxp->ipxp_lport != lport) 348214501Srpaulo continue; 349214501Srpaulo wildcard = 0; 350214501Srpaulo if (ipx_nullhost(ipxp->ipxp_faddr)) { 351214501Srpaulo if (!ipx_nullhost(*faddr)) 352214501Srpaulo wildcard++; 353214501Srpaulo } else { 354214501Srpaulo if (ipx_nullhost(*faddr)) 355214501Srpaulo wildcard++; 356214501Srpaulo else { 357214501Srpaulo if (!ipx_hosteq(ipxp->ipxp_faddr, *faddr)) 358214501Srpaulo continue; 359214501Srpaulo if (ipxp->ipxp_fport != fport) { 360214501Srpaulo if (ipxp->ipxp_fport != 0) 361214501Srpaulo continue; 362214501Srpaulo else 363214501Srpaulo wildcard++; 364214501Srpaulo } 365214501Srpaulo } 366214501Srpaulo } 367214501Srpaulo if (wildcard && wildp==0) 368214501Srpaulo continue; 369214501Srpaulo if (wildcard < matchwild) { 370214501Srpaulo match = ipxp; 371214501Srpaulo matchwild = wildcard; 372214501Srpaulo if (wildcard == 0) 373214501Srpaulo break; 374214501Srpaulo } 375214501Srpaulo } 376214501Srpaulo return (match); 377214501Srpaulo} 378214501Srpaulo