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