ipx_pcb.c revision 30813
13070Spst/* 23070Spst * Copyright (c) 1995, Mike Mitchell 33070Spst * Copyright (c) 1984, 1985, 1986, 1987, 1993 43070Spst * The Regents of the University of California. All rights reserved. 53070Spst * 63070Spst * Redistribution and use in source and binary forms, with or without 73070Spst * modification, are permitted provided that the following conditions 83070Spst * are met: 93070Spst * 1. Redistributions of source code must retain the above copyright 103070Spst * notice, this list of conditions and the following disclaimer. 113070Spst * 2. Redistributions in binary form must reproduce the above copyright 123070Spst * notice, this list of conditions and the following disclaimer in the 133070Spst * documentation and/or other materials provided with the distribution. 143070Spst * 3. All advertising materials mentioning features or use of this software 153070Spst * must display the following acknowledgement: 163070Spst * This product includes software developed by the University of 173070Spst * California, Berkeley and its contributors. 183070Spst * 4. Neither the name of the University nor the names of its contributors 193070Spst * may be used to endorse or promote products derived from this software 203070Spst * without specific prior written permission. 213070Spst * 223070Spst * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 233070Spst * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 243070Spst * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 253070Spst * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2692986Sobrien * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2792986Sobrien * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 283070Spst * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29113977Snectar * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30145626Sume * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 313070Spst * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 323070Spst * SUCH DAMAGE. 333070Spst * 343070Spst * @(#)ipx_pcb.c 353070Spst * 363070Spst * $Id: ipx_pcb.c,v 1.12 1997/09/02 01:19:10 bde Exp $ 373070Spst */ 38157779Sume 39145626Sume#include <sys/param.h> 403070Spst#include <sys/systm.h> 4165532Snectar#include <sys/malloc.h> 4265532Snectar#include <sys/proc.h> 43113977Snectar#include <sys/socket.h> 44145602Sume#include <sys/socketvar.h> 45158115Sume 46158115Sume#include <net/if.h> 47158115Sume#include <net/route.h> 483070Spst 4965532Snectar#include <netipx/ipx.h> 5065532Snectar#include <netipx/ipx_if.h> 5165532Snectar#include <netipx/ipx_pcb.h> 5265532Snectar#include <netipx/ipx_var.h> 5365532Snectar 5465532Snectarstruct ipx_addr zeroipx_addr; 553070Spst 5665532Snectarint 57157779Sumeipx_pcballoc(so, head, p) 5865532Snectar struct socket *so; 5965532Snectar struct ipxpcb *head; 6065532Snectar struct proc *p; 613070Spst{ 623070Spst register struct ipxpcb *ipxp; 63157779Sume 64157779Sume MALLOC(ipxp, struct ipxpcb *, sizeof *ipxp, M_PCB, M_NOWAIT); 65145626Sume if (ipxp == NULL) 66158115Sume return (ENOBUFS); 67158115Sume bzero(ipxp, sizeof *ipxp); 68158115Sume ipxp->ipxp_socket = so; 69158115Sume insque(ipxp, head); 70158115Sume so->so_pcb = (caddr_t)ipxp; 71158115Sume return (0); 72158115Sume} 73158115Sume 74158115Sumeint 75158115Sumeipx_pcbbind(ipxp, nam, p) 76158115Sume register struct ipxpcb *ipxp; 77158115Sume struct sockaddr *nam; 78158115Sume struct proc *p; 79158115Sume{ 80158115Sume register struct sockaddr_ipx *sipx; 81158115Sume u_short lport = 0; 82158115Sume 83158115Sume if (ipxp->ipxp_lport || !ipx_nullhost(ipxp->ipxp_laddr)) 84158115Sume return (EINVAL); 85158115Sume if (nam == NULL) 86158115Sume goto noname; 87158115Sume sipx = (struct sockaddr_ipx *)nam; 88158115Sume if (!ipx_nullhost(sipx->sipx_addr)) { 89158115Sume int tport = sipx->sipx_port; 90158115Sume 91158115Sume sipx->sipx_port = 0; /* yech... */ 92158115Sume if (ifa_ifwithaddr((struct sockaddr *)sipx) == 0) 93158115Sume return (EADDRNOTAVAIL); 94158115Sume sipx->sipx_port = tport; 95158115Sume } 96158115Sume lport = sipx->sipx_port; 97158115Sume if (lport) { 98158115Sume u_short aport = ntohs(lport); 99158115Sume int error; 100158115Sume 101158115Sume if (aport < IPXPORT_RESERVED && 102158115Sume p != NULL && (error = suser(p->p_ucred, &p->p_acflag)) != 0) 103158115Sume return (error); 104158115Sume if (ipx_pcblookup(&zeroipx_addr, lport, 0)) 105158115Sume return (EADDRINUSE); 106158115Sume } 107158115Sume ipxp->ipxp_laddr = sipx->sipx_addr; 108158115Sumenoname: 109158115Sume if (lport == 0) 110158115Sume do { 111158115Sume ipxpcb.ipxp_lport++; 112158115Sume if ((ipxpcb.ipxp_lport < IPXPORT_RESERVED) || 113158115Sume (ipxpcb.ipxp_lport >= IPXPORT_WELLKNOWN)) 114158115Sume ipxpcb.ipxp_lport = IPXPORT_RESERVED; 115158115Sume lport = htons(ipxpcb.ipxp_lport); 116158115Sume } while (ipx_pcblookup(&zeroipx_addr, lport, 0)); 117158115Sume ipxp->ipxp_lport = lport; 118158115Sume return (0); 119158115Sume} 120158115Sume 121158115Sume/* 122158115Sume * Connect from a socket to a specified address. 123158115Sume * Both address and port must be specified in argument sipx. 124158115Sume * If don't have a local address for this socket yet, 125158115Sume * then pick one. 126158115Sume */ 127158115Sumeint 128158115Sumeipx_pcbconnect(ipxp, nam, p) 129158115Sume struct ipxpcb *ipxp; 130158115Sume struct sockaddr *nam; 131158115Sume struct proc *p; 132158115Sume{ 133158115Sume struct ipx_ifaddr *ia; 134158115Sume register struct sockaddr_ipx *sipx = (struct sockaddr_ipx *)nam; 135158115Sume register struct ipx_addr *dst; 136158115Sume register struct route *ro; 137158115Sume struct ifnet *ifp; 138158115Sume 139158115Sume ia = NULL; 140158115Sume 141158115Sume if (sipx->sipx_family != AF_IPX) 142158115Sume return (EAFNOSUPPORT); 143158115Sume if (sipx->sipx_port == 0 || ipx_nullhost(sipx->sipx_addr)) 144158115Sume return (EADDRNOTAVAIL); 145158115Sume /* 146158115Sume * If we haven't bound which network number to use as ours, 147158115Sume * we will use the number of the outgoing interface. 148158115Sume * This depends on having done a routing lookup, which 149158115Sume * we will probably have to do anyway, so we might 150158115Sume * as well do it now. On the other hand if we are 151158115Sume * sending to multiple destinations we may have already 152158115Sume * done the lookup, so see if we can use the route 153158115Sume * from before. In any case, we only 154158115Sume * chose a port number once, even if sending to multiple 155158115Sume * destinations. 156158115Sume */ 157158115Sume ro = &ipxp->ipxp_route; 158158115Sume dst = &satoipx_addr(ro->ro_dst); 159158115Sume if (ipxp->ipxp_socket->so_options & SO_DONTROUTE) 160158115Sume goto flush; 161158115Sume if (!ipx_neteq(ipxp->ipxp_lastdst, sipx->sipx_addr)) 162158115Sume goto flush; 163158115Sume if (!ipx_hosteq(ipxp->ipxp_lastdst, sipx->sipx_addr)) { 164158115Sume if (ro->ro_rt != NULL && !(ro->ro_rt->rt_flags & RTF_HOST)) { 165158115Sume /* can patch route to avoid rtalloc */ 166158115Sume *dst = sipx->sipx_addr; 167158115Sume } else { 168158115Sume flush: 169158115Sume if (ro->ro_rt != NULL) 170158115Sume RTFREE(ro->ro_rt); 171158115Sume ro->ro_rt = NULL; 172158115Sume ipxp->ipxp_laddr.x_net = ipx_zeronet; 173158115Sume } 174158115Sume }/* else cached route is ok; do nothing */ 175158115Sume ipxp->ipxp_lastdst = sipx->sipx_addr; 176158115Sume if ((ipxp->ipxp_socket->so_options & SO_DONTROUTE) == 0 && /*XXX*/ 177158115Sume (ro->ro_rt == NULL || ro->ro_rt->rt_ifp == NULL)) { 178158115Sume /* No route yet, so try to acquire one */ 179158115Sume ro->ro_dst.sa_family = AF_IPX; 180158115Sume ro->ro_dst.sa_len = sizeof(ro->ro_dst); 181158115Sume *dst = sipx->sipx_addr; 182158115Sume dst->x_port = 0; 183158115Sume rtalloc(ro); 184158115Sume } 185158115Sume if (ipx_neteqnn(ipxp->ipxp_laddr.x_net, ipx_zeronet)) { 186158115Sume /* 187158115Sume * If route is known or can be allocated now, 188158115Sume * our src addr is taken from the i/f, else punt. 189158115Sume */ 190158115Sume 191158115Sume /* 192158115Sume * If we found a route, use the address 193158115Sume * corresponding to the outgoing interface 194158115Sume */ 195158115Sume if (ro->ro_rt != NULL && (ifp = ro->ro_rt->rt_ifp) != NULL) 196158115Sume for (ia = ipx_ifaddr; ia != NULL; ia = ia->ia_next) 197158115Sume if (ia->ia_ifp == ifp) 198158115Sume break; 199158115Sume if (ia == NULL) { 200158115Sume u_short fport = sipx->sipx_addr.x_port; 201158115Sume sipx->sipx_addr.x_port = 0; 202158115Sume ia = (struct ipx_ifaddr *) 203158115Sume ifa_ifwithdstaddr((struct sockaddr *)sipx); 204158115Sume sipx->sipx_addr.x_port = fport; 205158115Sume if (ia == NULL) 206158115Sume ia = ipx_iaonnetof(&sipx->sipx_addr); 207158115Sume if (ia == NULL) 208158115Sume ia = ipx_ifaddr; 209158115Sume if (ia == NULL) 210158115Sume return (EADDRNOTAVAIL); 211158115Sume } 212158115Sume ipxp->ipxp_laddr.x_net = satoipx_addr(ia->ia_addr).x_net; 213158115Sume } 214158115Sume if (ipx_nullhost(ipxp->ipxp_laddr)) { 215158115Sume /* 216158115Sume * If route is known or can be allocated now, 217158115Sume * our src addr is taken from the i/f, else punt. 218158115Sume */ 219158115Sume 220158115Sume /* 221158115Sume * If we found a route, use the address 222158115Sume * corresponding to the outgoing interface 223158115Sume */ 224158115Sume if (ro->ro_rt != NULL && (ifp = ro->ro_rt->rt_ifp) != NULL) 225158115Sume for (ia = ipx_ifaddr; ia != NULL; ia = ia->ia_next) 226158115Sume if (ia->ia_ifp == ifp) 227158115Sume break; 228158115Sume if (ia == NULL) { 229158115Sume u_short fport = sipx->sipx_addr.x_port; 230158115Sume sipx->sipx_addr.x_port = 0; 231158115Sume ia = (struct ipx_ifaddr *) 232158115Sume ifa_ifwithdstaddr((struct sockaddr *)sipx); 233158115Sume sipx->sipx_addr.x_port = fport; 234158115Sume if (ia == NULL) 235158115Sume ia = ipx_iaonnetof(&sipx->sipx_addr); 236158115Sume if (ia == NULL) 237158115Sume ia = ipx_ifaddr; 238158115Sume if (ia == NULL) 239158115Sume return (EADDRNOTAVAIL); 240158115Sume } 241158115Sume ipxp->ipxp_laddr.x_host = satoipx_addr(ia->ia_addr).x_host; 242158115Sume } 243158115Sume if (ipx_pcblookup(&sipx->sipx_addr, ipxp->ipxp_lport, 0)) 244158115Sume return (EADDRINUSE); 245158115Sume if (ipxp->ipxp_lport == 0) 246158115Sume ipx_pcbbind(ipxp, (struct sockaddr *)NULL, p); 247158115Sume 248158115Sume /* XXX just leave it zero if we can't find a route */ 249158115Sume 250158115Sume ipxp->ipxp_faddr = sipx->sipx_addr; 251158115Sume /* Includes ipxp->ipxp_fport = sipx->sipx_port; */ 252158115Sume return (0); 253158115Sume} 254158115Sume 255158115Sumevoid 256158115Sumeipx_pcbdisconnect(ipxp) 257158115Sume struct ipxpcb *ipxp; 258158115Sume{ 259158115Sume 260158115Sume ipxp->ipxp_faddr = zeroipx_addr; 261158115Sume if (ipxp->ipxp_socket->so_state & SS_NOFDREF) 262158115Sume ipx_pcbdetach(ipxp); 263158115Sume} 264158115Sume 265158115Sumevoid 266158115Sumeipx_pcbdetach(ipxp) 267158115Sume struct ipxpcb *ipxp; 268158115Sume{ 269158115Sume struct socket *so = ipxp->ipxp_socket; 270158115Sume 271158115Sume so->so_pcb = 0; 272158115Sume sofree(so); 273158115Sume if (ipxp->ipxp_route.ro_rt != NULL) 274158115Sume rtfree(ipxp->ipxp_route.ro_rt); 275158115Sume remque(ipxp); 276158115Sume FREE(ipxp, M_PCB); 277158115Sume} 278158115Sume 279158115Sumevoid 280145626Sumeipx_setsockaddr(ipxp, nam) 281157779Sume register struct ipxpcb *ipxp; 2823070Spst struct sockaddr **nam; 283157779Sume{ 284145626Sume struct sockaddr_ipx *sipx, ssipx; 285157779Sume 286145626Sume sipx = &ssipx; 287157779Sume bzero((caddr_t)sipx, sizeof(*sipx)); 288157779Sume sipx->sipx_len = sizeof(*sipx); 289157779Sume sipx->sipx_family = AF_IPX; 290145626Sume sipx->sipx_addr = ipxp->ipxp_laddr; 291145626Sume *nam = dup_sockaddr((struct sockaddr *)sipx, 0); 292145626Sume} 293157779Sume 294145626Sumevoid 295157779Sumeipx_setpeeraddr(ipxp, nam) 296145626Sume register struct ipxpcb *ipxp; 297145626Sume struct sockaddr **nam; 298157779Sume{ 299157779Sume struct sockaddr_ipx *sipx, ssipx; 300145626Sume 301157779Sume sipx = &ssipx; 302157779Sume bzero((caddr_t)sipx, sizeof(*sipx)); 303157779Sume sipx->sipx_len = sizeof(*sipx); 304145626Sume sipx->sipx_family = AF_IPX; 305157779Sume sipx->sipx_addr = ipxp->ipxp_faddr; 306157779Sume *nam = dup_sockaddr((struct sockaddr *)sipx, 0); 307157779Sume} 308157779Sume 309157779Sume/* 310157779Sume * Pass some notification to all connections of a protocol 311157779Sume * associated with address dst. Call the 312157779Sume * protocol specific routine to handle each connection. 313157779Sume * Also pass an extra paramter via the ipxpcb. (which may in fact 314157779Sume * be a parameter list!) 315157779Sume */ 316157779Sumevoid 317157779Sumeipx_pcbnotify(dst, errno, notify, param) 318157779Sume register struct ipx_addr *dst; 319157779Sume int errno; 320157779Sume void (*notify)(struct ipxpcb *); 321157779Sume long param; 322157779Sume{ 323157779Sume register struct ipxpcb *ipxp, *oinp; 324157779Sume int s = splimp(); 325157779Sume 326157779Sume for (ipxp = (&ipxpcb)->ipxp_next; ipxp != (&ipxpcb);) { 327157779Sume if (!ipx_hosteq(*dst,ipxp->ipxp_faddr)) { 328157779Sume next: 329157779Sume ipxp = ipxp->ipxp_next; 330157779Sume continue; 331157779Sume } 332157779Sume if (ipxp->ipxp_socket == 0) 333157779Sume goto next; 334157779Sume if (errno) 335157779Sume ipxp->ipxp_socket->so_error = errno; 336157779Sume oinp = ipxp; 337157779Sume ipxp = ipxp->ipxp_next; 338157779Sume oinp->ipxp_notify_param = param; 339157779Sume (*notify)(oinp); 340157779Sume } 341157779Sume splx(s); 342145626Sume} 343145626Sume 344145626Sume#ifdef notdef 345157779Sume/* 346157779Sume * After a routing change, flush old routing 347145626Sume * and allocate a (hopefully) better one. 348158115Sume */ 349158115Sumeipx_rtchange(ipxp) 350158115Sume struct ipxpcb *ipxp; 351158115Sume{ 352158115Sume if (ipxp->ipxp_route.ro_rt != NULL) { 353158115Sume rtfree(ipxp->ipxp_route.ro_rt); 35465532Snectar ipxp->ipxp_route.ro_rt = NULL; 35565532Snectar /* 35665532Snectar * A new route can be allocated the next time 35765532Snectar * output is attempted. 358158115Sume */ 359158115Sume } 360158115Sume /* SHOULD NOTIFY HIGHER-LEVEL PROTOCOLS */ 36165532Snectar} 362145626Sume#endif 363211276Sume 36465532Snectarstruct ipxpcb * 365157779Sumeipx_pcblookup(faddr, lport, wildp) 366157779Sume struct ipx_addr *faddr; 367157779Sume u_short lport; 368145626Sume int wildp; 369211276Sume{ 370211276Sume register struct ipxpcb *ipxp, *match = 0; 371211276Sume int matchwild = 3, wildcard; 372211276Sume u_short fport; 373211276Sume 3743070Spst fport = faddr->x_port; 3753070Spst for (ipxp = (&ipxpcb)->ipxp_next; ipxp != (&ipxpcb); ipxp = ipxp->ipxp_next) { 376145626Sume if (ipxp->ipxp_lport != lport) 377157779Sume continue; 378157779Sume wildcard = 0; 3793070Spst if (ipx_nullhost(ipxp->ipxp_faddr)) { 380158115Sume if (!ipx_nullhost(*faddr)) 381158115Sume wildcard++; 382158115Sume } else { 383158115Sume if (ipx_nullhost(*faddr)) 384158115Sume wildcard++; 385158115Sume else { 38665532Snectar if (!ipx_hosteq(ipxp->ipxp_faddr, *faddr)) 38765532Snectar continue; 38865532Snectar if (ipxp->ipxp_fport != fport) { 38965532Snectar if (ipxp->ipxp_fport != 0) 390158115Sume continue; 391158115Sume else 392158115Sume wildcard++; 39365532Snectar } 394145626Sume } 395211276Sume } 3963070Spst if (wildcard && wildp == 0) 397157779Sume continue; 398157779Sume if (wildcard < matchwild) { 399157779Sume match = ipxp; 40065532Snectar matchwild = wildcard; 401211276Sume if (wildcard == 0) 402211276Sume break; 403211276Sume } 404211276Sume } 405211276Sume return (match); 4063070Spst} 4073070Spst