ipx_pcb.c revision 50519
1117395Skan/* 2169689Skan * Copyright (c) 1995, Mike Mitchell 3117395Skan * Copyright (c) 1984, 1985, 1986, 1987, 1993 4117395Skan * The Regents of the University of California. All rights reserved. 5117395Skan * 6132718Skan * Redistribution and use in source and binary forms, with or without 7117395Skan * modification, are permitted provided that the following conditions 8132718Skan * are met: 9132718Skan * 1. Redistributions of source code must retain the above copyright 10132718Skan * notice, this list of conditions and the following disclaimer. 11132718Skan * 2. Redistributions in binary form must reproduce the above copyright 12117395Skan * notice, this list of conditions and the following disclaimer in the 13132718Skan * documentation and/or other materials provided with the distribution. 14132718Skan * 3. All advertising materials mentioning features or use of this software 15132718Skan * must display the following acknowledgement: 16132718Skan * This product includes software developed by the University of 17132718Skan * California, Berkeley and its contributors. 18117395Skan * 4. Neither the name of the University nor the names of its contributors 19132718Skan * may be used to endorse or promote products derived from this software 20169689Skan * without specific prior written permission. 21169689Skan * 22117395Skan * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 23132718Skan * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24132718Skan * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25132718Skan * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 26169689Skan * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27169689Skan * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28169689Skan * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29117395Skan * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30117395Skan * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31169689Skan * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32169689Skan * SUCH DAMAGE. 33169689Skan * 34169689Skan * @(#)ipx_pcb.c 35169689Skan * 36169689Skan * $FreeBSD: head/sys/netipx/ipx_pcb.c 50519 1999-08-28 18:21:55Z jhay $ 37169689Skan */ 38169689Skan 39169689Skan#include <sys/param.h> 40169689Skan#include <sys/systm.h> 41169689Skan#include <sys/malloc.h> 42169689Skan#include <sys/proc.h> 43169689Skan#include <sys/socket.h> 44169689Skan#include <sys/socketvar.h> 45169689Skan 46169689Skan#include <net/if.h> 47169689Skan#include <net/route.h> 48169689Skan 49169689Skan#include <netipx/ipx.h> 50169689Skan#include <netipx/ipx_if.h> 51169689Skan#include <netipx/ipx_pcb.h> 52169689Skan#include <netipx/ipx_var.h> 53169689Skan 54169689Skanstatic struct ipx_addr zeroipx_addr; 55169689Skan 56169689Skanint 57169689Skanipx_pcballoc(so, head, p) 58169689Skan struct socket *so; 59169689Skan struct ipxpcb *head; 60169689Skan struct proc *p; 61169689Skan{ 62169689Skan register struct ipxpcb *ipxp; 63169689Skan 64169689Skan MALLOC(ipxp, struct ipxpcb *, sizeof *ipxp, M_PCB, M_NOWAIT); 65169689Skan if (ipxp == NULL) 66169689Skan return (ENOBUFS); 67169689Skan bzero(ipxp, sizeof *ipxp); 68169689Skan ipxp->ipxp_socket = so; 69169689Skan if (ipxcksum) 70169689Skan ipxp->ipxp_flags |= IPXP_CHECKSUM; 71169689Skan insque(ipxp, head); 72169689Skan so->so_pcb = (caddr_t)ipxp; 73169689Skan return (0); 74169689Skan} 75169689Skan 76169689Skanint 77169689Skanipx_pcbbind(ipxp, nam, p) 78169689Skan register struct ipxpcb *ipxp; 79169689Skan struct sockaddr *nam; 80169689Skan struct proc *p; 81169689Skan{ 82169689Skan register struct sockaddr_ipx *sipx; 83169689Skan u_short lport = 0; 84169689Skan 85169689Skan if (ipxp->ipxp_lport || !ipx_nullhost(ipxp->ipxp_laddr)) 86169689Skan return (EINVAL); 87169689Skan if (nam == NULL) 88169689Skan goto noname; 89169689Skan sipx = (struct sockaddr_ipx *)nam; 90169689Skan if (!ipx_nullhost(sipx->sipx_addr)) { 91169689Skan int tport = sipx->sipx_port; 92169689Skan 93169689Skan sipx->sipx_port = 0; /* yech... */ 94169689Skan if (ifa_ifwithaddr((struct sockaddr *)sipx) == 0) 95169689Skan return (EADDRNOTAVAIL); 96169689Skan sipx->sipx_port = tport; 97169689Skan } 98169689Skan lport = sipx->sipx_port; 99169689Skan if (lport) { 100169689Skan u_short aport = ntohs(lport); 101169689Skan int error; 102169689Skan 103169689Skan if (aport < IPXPORT_RESERVED && 104169689Skan p != NULL && (error = suser(p)) != 0) 105169689Skan return (error); 106169689Skan if (ipx_pcblookup(&zeroipx_addr, lport, 0)) 107169689Skan return (EADDRINUSE); 108169689Skan } 109169689Skan ipxp->ipxp_laddr = sipx->sipx_addr; 110169689Skannoname: 111169689Skan if (lport == 0) 112169689Skan do { 113169689Skan ipxpcb.ipxp_lport++; 114169689Skan if ((ipxpcb.ipxp_lport < IPXPORT_RESERVED) || 115169689Skan (ipxpcb.ipxp_lport >= IPXPORT_WELLKNOWN)) 116169689Skan ipxpcb.ipxp_lport = IPXPORT_RESERVED; 117169689Skan lport = htons(ipxpcb.ipxp_lport); 118169689Skan } while (ipx_pcblookup(&zeroipx_addr, lport, 0)); 119169689Skan ipxp->ipxp_lport = lport; 120169689Skan return (0); 121169689Skan} 122169689Skan 123169689Skan/* 124169689Skan * Connect from a socket to a specified address. 125169689Skan * Both address and port must be specified in argument sipx. 126169689Skan * If don't have a local address for this socket yet, 127169689Skan * then pick one. 128169689Skan */ 129169689Skanint 130169689Skanipx_pcbconnect(ipxp, nam, p) 131169689Skan struct ipxpcb *ipxp; 132169689Skan struct sockaddr *nam; 133169689Skan struct proc *p; 134169689Skan{ 135169689Skan struct ipx_ifaddr *ia; 136169689Skan register struct sockaddr_ipx *sipx = (struct sockaddr_ipx *)nam; 137169689Skan register struct ipx_addr *dst; 138169689Skan register struct route *ro; 139169689Skan struct ifnet *ifp; 140169689Skan 141169689Skan ia = NULL; 142169689Skan 143169689Skan if (sipx->sipx_family != AF_IPX) 144169689Skan return (EAFNOSUPPORT); 145169689Skan if (sipx->sipx_port == 0 || ipx_nullhost(sipx->sipx_addr)) 146169689Skan return (EADDRNOTAVAIL); 147169689Skan /* 148169689Skan * If we haven't bound which network number to use as ours, 149169689Skan * we will use the number of the outgoing interface. 150169689Skan * This depends on having done a routing lookup, which 151169689Skan * we will probably have to do anyway, so we might 152169689Skan * as well do it now. On the other hand if we are 153169689Skan * sending to multiple destinations we may have already 154169689Skan * done the lookup, so see if we can use the route 155169689Skan * from before. In any case, we only 156169689Skan * chose a port number once, even if sending to multiple 157169689Skan * destinations. 158169689Skan */ 159132718Skan ro = &ipxp->ipxp_route; 160169689Skan dst = &satoipx_addr(ro->ro_dst); 161132718Skan if (ipxp->ipxp_socket->so_options & SO_DONTROUTE) 162132718Skan goto flush; 163132718Skan if (!ipx_neteq(ipxp->ipxp_lastdst, sipx->sipx_addr)) 164132718Skan goto flush; 165132718Skan if (!ipx_hosteq(ipxp->ipxp_lastdst, sipx->sipx_addr)) { 166132718Skan if (ro->ro_rt != NULL && !(ro->ro_rt->rt_flags & RTF_HOST)) { 167169689Skan /* can patch route to avoid rtalloc */ 168132718Skan *dst = sipx->sipx_addr; 169132718Skan } else { 170132718Skan flush: 171132718Skan if (ro->ro_rt != NULL) 172132718Skan RTFREE(ro->ro_rt); 173132718Skan ro->ro_rt = NULL; 174132718Skan } 175132718Skan }/* else cached route is ok; do nothing */ 176 ipxp->ipxp_lastdst = sipx->sipx_addr; 177 if ((ipxp->ipxp_socket->so_options & SO_DONTROUTE) == 0 && /*XXX*/ 178 (ro->ro_rt == NULL || ro->ro_rt->rt_ifp == NULL)) { 179 /* No route yet, so try to acquire one */ 180 ro->ro_dst.sa_family = AF_IPX; 181 ro->ro_dst.sa_len = sizeof(ro->ro_dst); 182 *dst = sipx->sipx_addr; 183 dst->x_port = 0; 184 rtalloc(ro); 185 } 186 if (ipx_neteqnn(ipxp->ipxp_laddr.x_net, ipx_zeronet)) { 187 /* 188 * If route is known or can be allocated now, 189 * our src addr is taken from the i/f, else punt. 190 */ 191 192 /* 193 * If we found a route, use the address 194 * corresponding to the outgoing interface 195 */ 196 if (ro->ro_rt != NULL && (ifp = ro->ro_rt->rt_ifp) != NULL) 197 for (ia = ipx_ifaddr; ia != NULL; ia = ia->ia_next) 198 if (ia->ia_ifp == ifp) 199 break; 200 if (ia == NULL) { 201 u_short fport = sipx->sipx_addr.x_port; 202 sipx->sipx_addr.x_port = 0; 203 ia = (struct ipx_ifaddr *) 204 ifa_ifwithdstaddr((struct sockaddr *)sipx); 205 sipx->sipx_addr.x_port = fport; 206 if (ia == NULL) 207 ia = ipx_iaonnetof(&sipx->sipx_addr); 208 if (ia == NULL) 209 ia = ipx_ifaddr; 210 if (ia == NULL) 211 return (EADDRNOTAVAIL); 212 } 213 ipxp->ipxp_laddr.x_net = satoipx_addr(ia->ia_addr).x_net; 214 } 215 if (ipx_nullhost(ipxp->ipxp_laddr)) { 216 /* 217 * If route is known or can be allocated now, 218 * our src addr is taken from the i/f, else punt. 219 */ 220 221 /* 222 * If we found a route, use the address 223 * corresponding to the outgoing interface 224 */ 225 if (ro->ro_rt != NULL && (ifp = ro->ro_rt->rt_ifp) != NULL) 226 for (ia = ipx_ifaddr; ia != NULL; ia = ia->ia_next) 227 if (ia->ia_ifp == ifp) 228 break; 229 if (ia == NULL) { 230 u_short fport = sipx->sipx_addr.x_port; 231 sipx->sipx_addr.x_port = 0; 232 ia = (struct ipx_ifaddr *) 233 ifa_ifwithdstaddr((struct sockaddr *)sipx); 234 sipx->sipx_addr.x_port = fport; 235 if (ia == NULL) 236 ia = ipx_iaonnetof(&sipx->sipx_addr); 237 if (ia == NULL) 238 ia = ipx_ifaddr; 239 if (ia == NULL) 240 return (EADDRNOTAVAIL); 241 } 242 ipxp->ipxp_laddr.x_host = satoipx_addr(ia->ia_addr).x_host; 243 } 244 if (ipx_pcblookup(&sipx->sipx_addr, ipxp->ipxp_lport, 0)) 245 return (EADDRINUSE); 246 if (ipxp->ipxp_lport == 0) 247 ipx_pcbbind(ipxp, (struct sockaddr *)NULL, p); 248 249 /* XXX just leave it zero if we can't find a route */ 250 251 ipxp->ipxp_faddr = sipx->sipx_addr; 252 /* Includes ipxp->ipxp_fport = sipx->sipx_port; */ 253 return (0); 254} 255 256void 257ipx_pcbdisconnect(ipxp) 258 struct ipxpcb *ipxp; 259{ 260 261 ipxp->ipxp_faddr = zeroipx_addr; 262 if (ipxp->ipxp_socket->so_state & SS_NOFDREF) 263 ipx_pcbdetach(ipxp); 264} 265 266void 267ipx_pcbdetach(ipxp) 268 struct ipxpcb *ipxp; 269{ 270 struct socket *so = ipxp->ipxp_socket; 271 272 so->so_pcb = 0; 273 sofree(so); 274 if (ipxp->ipxp_route.ro_rt != NULL) 275 rtfree(ipxp->ipxp_route.ro_rt); 276 remque(ipxp); 277 FREE(ipxp, M_PCB); 278} 279 280void 281ipx_setsockaddr(ipxp, nam) 282 register struct ipxpcb *ipxp; 283 struct sockaddr **nam; 284{ 285 struct sockaddr_ipx *sipx, ssipx; 286 287 sipx = &ssipx; 288 bzero((caddr_t)sipx, sizeof(*sipx)); 289 sipx->sipx_len = sizeof(*sipx); 290 sipx->sipx_family = AF_IPX; 291 sipx->sipx_addr = ipxp->ipxp_laddr; 292 *nam = dup_sockaddr((struct sockaddr *)sipx, 0); 293} 294 295void 296ipx_setpeeraddr(ipxp, nam) 297 register struct ipxpcb *ipxp; 298 struct sockaddr **nam; 299{ 300 struct sockaddr_ipx *sipx, ssipx; 301 302 sipx = &ssipx; 303 bzero((caddr_t)sipx, sizeof(*sipx)); 304 sipx->sipx_len = sizeof(*sipx); 305 sipx->sipx_family = AF_IPX; 306 sipx->sipx_addr = ipxp->ipxp_faddr; 307 *nam = dup_sockaddr((struct sockaddr *)sipx, 0); 308} 309 310/* 311 * Pass some notification to all connections of a protocol 312 * associated with address dst. Call the 313 * protocol specific routine to handle each connection. 314 * Also pass an extra paramter via the ipxpcb. (which may in fact 315 * be a parameter list!) 316 */ 317void 318ipx_pcbnotify(dst, errno, notify, param) 319 register struct ipx_addr *dst; 320 int errno; 321 void (*notify)(struct ipxpcb *); 322 long param; 323{ 324 register struct ipxpcb *ipxp, *oinp; 325 int s = splimp(); 326 327 for (ipxp = (&ipxpcb)->ipxp_next; ipxp != (&ipxpcb);) { 328 if (!ipx_hosteq(*dst,ipxp->ipxp_faddr)) { 329 next: 330 ipxp = ipxp->ipxp_next; 331 continue; 332 } 333 if (ipxp->ipxp_socket == 0) 334 goto next; 335 if (errno) 336 ipxp->ipxp_socket->so_error = errno; 337 oinp = ipxp; 338 ipxp = ipxp->ipxp_next; 339 oinp->ipxp_notify_param = param; 340 (*notify)(oinp); 341 } 342 splx(s); 343} 344 345#ifdef notdef 346/* 347 * After a routing change, flush old routing 348 * and allocate a (hopefully) better one. 349 */ 350ipx_rtchange(ipxp) 351 struct ipxpcb *ipxp; 352{ 353 if (ipxp->ipxp_route.ro_rt != NULL) { 354 rtfree(ipxp->ipxp_route.ro_rt); 355 ipxp->ipxp_route.ro_rt = NULL; 356 /* 357 * A new route can be allocated the next time 358 * output is attempted. 359 */ 360 } 361 /* SHOULD NOTIFY HIGHER-LEVEL PROTOCOLS */ 362} 363#endif 364 365struct ipxpcb * 366ipx_pcblookup(faddr, lport, wildp) 367 struct ipx_addr *faddr; 368 u_short lport; 369 int wildp; 370{ 371 register struct ipxpcb *ipxp, *match = 0; 372 int matchwild = 3, wildcard; 373 u_short fport; 374 375 fport = faddr->x_port; 376 for (ipxp = (&ipxpcb)->ipxp_next; ipxp != (&ipxpcb); ipxp = ipxp->ipxp_next) { 377 if (ipxp->ipxp_lport != lport) 378 continue; 379 wildcard = 0; 380 if (ipx_nullhost(ipxp->ipxp_faddr)) { 381 if (!ipx_nullhost(*faddr)) 382 wildcard++; 383 } else { 384 if (ipx_nullhost(*faddr)) 385 wildcard++; 386 else { 387 if (!ipx_hosteq(ipxp->ipxp_faddr, *faddr)) 388 continue; 389 if (ipxp->ipxp_fport != fport) { 390 if (ipxp->ipxp_fport != 0) 391 continue; 392 else 393 wildcard++; 394 } 395 } 396 } 397 if (wildcard && wildp == 0) 398 continue; 399 if (wildcard < matchwild) { 400 match = ipxp; 401 matchwild = wildcard; 402 if (wildcard == 0) 403 break; 404 } 405 } 406 return (match); 407} 408