ipx_pcb.c revision 43712
1/* 2 * Copyright (c) 1995, Mike Mitchell 3 * Copyright (c) 1984, 1985, 1986, 1987, 1993 4 * The Regents of the University of California. All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 3. All advertising materials mentioning features or use of this software 15 * must display the following acknowledgement: 16 * This product includes software developed by the University of 17 * California, Berkeley and its contributors. 18 * 4. Neither the name of the University nor the names of its contributors 19 * may be used to endorse or promote products derived from this software 20 * without specific prior written permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 * SUCH DAMAGE. 33 * 34 * @(#)ipx_pcb.c 35 * 36 * $Id: ipx_pcb.c,v 1.14 1998/02/09 06:10:23 eivind Exp $ 37 */ 38 39#include <sys/param.h> 40#include <sys/systm.h> 41#include <sys/malloc.h> 42#include <sys/proc.h> 43#include <sys/socket.h> 44#include <sys/socketvar.h> 45 46#include <net/if.h> 47#include <net/route.h> 48 49#include <netipx/ipx.h> 50#include <netipx/ipx_if.h> 51#include <netipx/ipx_pcb.h> 52#include <netipx/ipx_var.h> 53 54static struct ipx_addr zeroipx_addr; 55 56int 57ipx_pcballoc(so, head, p) 58 struct socket *so; 59 struct ipxpcb *head; 60 struct proc *p; 61{ 62 register struct ipxpcb *ipxp; 63 64 MALLOC(ipxp, struct ipxpcb *, sizeof *ipxp, M_PCB, M_NOWAIT); 65 if (ipxp == NULL) 66 return (ENOBUFS); 67 bzero(ipxp, sizeof *ipxp); 68 ipxp->ipxp_socket = so; 69 insque(ipxp, head); 70 so->so_pcb = (caddr_t)ipxp; 71 return (0); 72} 73 74int 75ipx_pcbbind(ipxp, nam, p) 76 register struct ipxpcb *ipxp; 77 struct sockaddr *nam; 78 struct proc *p; 79{ 80 register struct sockaddr_ipx *sipx; 81 u_short lport = 0; 82 83 if (ipxp->ipxp_lport || !ipx_nullhost(ipxp->ipxp_laddr)) 84 return (EINVAL); 85 if (nam == NULL) 86 goto noname; 87 sipx = (struct sockaddr_ipx *)nam; 88 if (!ipx_nullhost(sipx->sipx_addr)) { 89 int tport = sipx->sipx_port; 90 91 sipx->sipx_port = 0; /* yech... */ 92 if (ifa_ifwithaddr((struct sockaddr *)sipx) == 0) 93 return (EADDRNOTAVAIL); 94 sipx->sipx_port = tport; 95 } 96 lport = sipx->sipx_port; 97 if (lport) { 98 u_short aport = ntohs(lport); 99 int error; 100 101 if (aport < IPXPORT_RESERVED && 102 p != NULL && (error = suser(p->p_ucred, &p->p_acflag)) != 0) 103 return (error); 104 if (ipx_pcblookup(&zeroipx_addr, lport, 0)) 105 return (EADDRINUSE); 106 } 107 ipxp->ipxp_laddr = sipx->sipx_addr; 108noname: 109 if (lport == 0) 110 do { 111 ipxpcb.ipxp_lport++; 112 if ((ipxpcb.ipxp_lport < IPXPORT_RESERVED) || 113 (ipxpcb.ipxp_lport >= IPXPORT_WELLKNOWN)) 114 ipxpcb.ipxp_lport = IPXPORT_RESERVED; 115 lport = htons(ipxpcb.ipxp_lport); 116 } while (ipx_pcblookup(&zeroipx_addr, lport, 0)); 117 ipxp->ipxp_lport = lport; 118 return (0); 119} 120 121/* 122 * Connect from a socket to a specified address. 123 * Both address and port must be specified in argument sipx. 124 * If don't have a local address for this socket yet, 125 * then pick one. 126 */ 127int 128ipx_pcbconnect(ipxp, nam, p) 129 struct ipxpcb *ipxp; 130 struct sockaddr *nam; 131 struct proc *p; 132{ 133 struct ipx_ifaddr *ia; 134 register struct sockaddr_ipx *sipx = (struct sockaddr_ipx *)nam; 135 register struct ipx_addr *dst; 136 register struct route *ro; 137 struct ifnet *ifp; 138 139 ia = NULL; 140 141 if (sipx->sipx_family != AF_IPX) 142 return (EAFNOSUPPORT); 143 if (sipx->sipx_port == 0 || ipx_nullhost(sipx->sipx_addr)) 144 return (EADDRNOTAVAIL); 145 /* 146 * If we haven't bound which network number to use as ours, 147 * we will use the number of the outgoing interface. 148 * This depends on having done a routing lookup, which 149 * we will probably have to do anyway, so we might 150 * as well do it now. On the other hand if we are 151 * sending to multiple destinations we may have already 152 * done the lookup, so see if we can use the route 153 * from before. In any case, we only 154 * chose a port number once, even if sending to multiple 155 * destinations. 156 */ 157 ro = &ipxp->ipxp_route; 158 dst = &satoipx_addr(ro->ro_dst); 159 if (ipxp->ipxp_socket->so_options & SO_DONTROUTE) 160 goto flush; 161 if (!ipx_neteq(ipxp->ipxp_lastdst, sipx->sipx_addr)) 162 goto flush; 163 if (!ipx_hosteq(ipxp->ipxp_lastdst, sipx->sipx_addr)) { 164 if (ro->ro_rt != NULL && !(ro->ro_rt->rt_flags & RTF_HOST)) { 165 /* can patch route to avoid rtalloc */ 166 *dst = sipx->sipx_addr; 167 } else { 168 flush: 169 if (ro->ro_rt != NULL) 170 RTFREE(ro->ro_rt); 171 ro->ro_rt = NULL; 172 } 173 }/* else cached route is ok; do nothing */ 174 ipxp->ipxp_lastdst = sipx->sipx_addr; 175 if ((ipxp->ipxp_socket->so_options & SO_DONTROUTE) == 0 && /*XXX*/ 176 (ro->ro_rt == NULL || ro->ro_rt->rt_ifp == NULL)) { 177 /* No route yet, so try to acquire one */ 178 ro->ro_dst.sa_family = AF_IPX; 179 ro->ro_dst.sa_len = sizeof(ro->ro_dst); 180 *dst = sipx->sipx_addr; 181 dst->x_port = 0; 182 rtalloc(ro); 183 } 184 if (ipx_neteqnn(ipxp->ipxp_laddr.x_net, ipx_zeronet)) { 185 /* 186 * If route is known or can be allocated now, 187 * our src addr is taken from the i/f, else punt. 188 */ 189 190 /* 191 * If we found a route, use the address 192 * corresponding to the outgoing interface 193 */ 194 if (ro->ro_rt != NULL && (ifp = ro->ro_rt->rt_ifp) != NULL) 195 for (ia = ipx_ifaddr; ia != NULL; ia = ia->ia_next) 196 if (ia->ia_ifp == ifp) 197 break; 198 if (ia == NULL) { 199 u_short fport = sipx->sipx_addr.x_port; 200 sipx->sipx_addr.x_port = 0; 201 ia = (struct ipx_ifaddr *) 202 ifa_ifwithdstaddr((struct sockaddr *)sipx); 203 sipx->sipx_addr.x_port = fport; 204 if (ia == NULL) 205 ia = ipx_iaonnetof(&sipx->sipx_addr); 206 if (ia == NULL) 207 ia = ipx_ifaddr; 208 if (ia == NULL) 209 return (EADDRNOTAVAIL); 210 } 211 ipxp->ipxp_laddr.x_net = satoipx_addr(ia->ia_addr).x_net; 212 } 213 if (ipx_nullhost(ipxp->ipxp_laddr)) { 214 /* 215 * If route is known or can be allocated now, 216 * our src addr is taken from the i/f, else punt. 217 */ 218 219 /* 220 * If we found a route, use the address 221 * corresponding to the outgoing interface 222 */ 223 if (ro->ro_rt != NULL && (ifp = ro->ro_rt->rt_ifp) != NULL) 224 for (ia = ipx_ifaddr; ia != NULL; ia = ia->ia_next) 225 if (ia->ia_ifp == ifp) 226 break; 227 if (ia == NULL) { 228 u_short fport = sipx->sipx_addr.x_port; 229 sipx->sipx_addr.x_port = 0; 230 ia = (struct ipx_ifaddr *) 231 ifa_ifwithdstaddr((struct sockaddr *)sipx); 232 sipx->sipx_addr.x_port = fport; 233 if (ia == NULL) 234 ia = ipx_iaonnetof(&sipx->sipx_addr); 235 if (ia == NULL) 236 ia = ipx_ifaddr; 237 if (ia == NULL) 238 return (EADDRNOTAVAIL); 239 } 240 ipxp->ipxp_laddr.x_host = satoipx_addr(ia->ia_addr).x_host; 241 } 242 if (ipx_pcblookup(&sipx->sipx_addr, ipxp->ipxp_lport, 0)) 243 return (EADDRINUSE); 244 if (ipxp->ipxp_lport == 0) 245 ipx_pcbbind(ipxp, (struct sockaddr *)NULL, p); 246 247 /* XXX just leave it zero if we can't find a route */ 248 249 ipxp->ipxp_faddr = sipx->sipx_addr; 250 /* Includes ipxp->ipxp_fport = sipx->sipx_port; */ 251 return (0); 252} 253 254void 255ipx_pcbdisconnect(ipxp) 256 struct ipxpcb *ipxp; 257{ 258 259 ipxp->ipxp_faddr = zeroipx_addr; 260 if (ipxp->ipxp_socket->so_state & SS_NOFDREF) 261 ipx_pcbdetach(ipxp); 262} 263 264void 265ipx_pcbdetach(ipxp) 266 struct ipxpcb *ipxp; 267{ 268 struct socket *so = ipxp->ipxp_socket; 269 270 so->so_pcb = 0; 271 sofree(so); 272 if (ipxp->ipxp_route.ro_rt != NULL) 273 rtfree(ipxp->ipxp_route.ro_rt); 274 remque(ipxp); 275 FREE(ipxp, M_PCB); 276} 277 278void 279ipx_setsockaddr(ipxp, nam) 280 register struct ipxpcb *ipxp; 281 struct sockaddr **nam; 282{ 283 struct sockaddr_ipx *sipx, ssipx; 284 285 sipx = &ssipx; 286 bzero((caddr_t)sipx, sizeof(*sipx)); 287 sipx->sipx_len = sizeof(*sipx); 288 sipx->sipx_family = AF_IPX; 289 sipx->sipx_addr = ipxp->ipxp_laddr; 290 *nam = dup_sockaddr((struct sockaddr *)sipx, 0); 291} 292 293void 294ipx_setpeeraddr(ipxp, nam) 295 register struct ipxpcb *ipxp; 296 struct sockaddr **nam; 297{ 298 struct sockaddr_ipx *sipx, ssipx; 299 300 sipx = &ssipx; 301 bzero((caddr_t)sipx, sizeof(*sipx)); 302 sipx->sipx_len = sizeof(*sipx); 303 sipx->sipx_family = AF_IPX; 304 sipx->sipx_addr = ipxp->ipxp_faddr; 305 *nam = dup_sockaddr((struct sockaddr *)sipx, 0); 306} 307 308/* 309 * Pass some notification to all connections of a protocol 310 * associated with address dst. Call the 311 * protocol specific routine to handle each connection. 312 * Also pass an extra paramter via the ipxpcb. (which may in fact 313 * be a parameter list!) 314 */ 315void 316ipx_pcbnotify(dst, errno, notify, param) 317 register struct ipx_addr *dst; 318 int errno; 319 void (*notify)(struct ipxpcb *); 320 long param; 321{ 322 register struct ipxpcb *ipxp, *oinp; 323 int s = splimp(); 324 325 for (ipxp = (&ipxpcb)->ipxp_next; ipxp != (&ipxpcb);) { 326 if (!ipx_hosteq(*dst,ipxp->ipxp_faddr)) { 327 next: 328 ipxp = ipxp->ipxp_next; 329 continue; 330 } 331 if (ipxp->ipxp_socket == 0) 332 goto next; 333 if (errno) 334 ipxp->ipxp_socket->so_error = errno; 335 oinp = ipxp; 336 ipxp = ipxp->ipxp_next; 337 oinp->ipxp_notify_param = param; 338 (*notify)(oinp); 339 } 340 splx(s); 341} 342 343#ifdef notdef 344/* 345 * After a routing change, flush old routing 346 * and allocate a (hopefully) better one. 347 */ 348ipx_rtchange(ipxp) 349 struct ipxpcb *ipxp; 350{ 351 if (ipxp->ipxp_route.ro_rt != NULL) { 352 rtfree(ipxp->ipxp_route.ro_rt); 353 ipxp->ipxp_route.ro_rt = NULL; 354 /* 355 * A new route can be allocated the next time 356 * output is attempted. 357 */ 358 } 359 /* SHOULD NOTIFY HIGHER-LEVEL PROTOCOLS */ 360} 361#endif 362 363struct ipxpcb * 364ipx_pcblookup(faddr, lport, wildp) 365 struct ipx_addr *faddr; 366 u_short lport; 367 int wildp; 368{ 369 register struct ipxpcb *ipxp, *match = 0; 370 int matchwild = 3, wildcard; 371 u_short fport; 372 373 fport = faddr->x_port; 374 for (ipxp = (&ipxpcb)->ipxp_next; ipxp != (&ipxpcb); ipxp = ipxp->ipxp_next) { 375 if (ipxp->ipxp_lport != lport) 376 continue; 377 wildcard = 0; 378 if (ipx_nullhost(ipxp->ipxp_faddr)) { 379 if (!ipx_nullhost(*faddr)) 380 wildcard++; 381 } else { 382 if (ipx_nullhost(*faddr)) 383 wildcard++; 384 else { 385 if (!ipx_hosteq(ipxp->ipxp_faddr, *faddr)) 386 continue; 387 if (ipxp->ipxp_fport != fport) { 388 if (ipxp->ipxp_fport != 0) 389 continue; 390 else 391 wildcard++; 392 } 393 } 394 } 395 if (wildcard && wildp == 0) 396 continue; 397 if (wildcard < matchwild) { 398 match = ipxp; 399 matchwild = wildcard; 400 if (wildcard == 0) 401 break; 402 } 403 } 404 return (match); 405} 406