1/*- 2 * Copyright (c) 1984, 1985, 1986, 1987, 1993 3 * The Regents of the University of California. 4 * Copyright (c) 2004-2009 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: releng/10.2/sys/netipx/ipx_pcb.c 194905 2009-06-24 20:57:50Z 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(struct socket *so, struct ipxpcbhead *head, struct thread *td) 88{ 89 struct ipxpcb *ipxp; 90 91 KASSERT(so->so_pcb == NULL, ("ipx_pcballoc: so_pcb != NULL")); 92 IPX_LIST_LOCK_ASSERT(); 93 94 ipxp = malloc(sizeof *ipxp, M_PCB, M_NOWAIT | M_ZERO); 95 if (ipxp == NULL) 96 return (ENOBUFS); 97 IPX_LOCK_INIT(ipxp); 98 ipxp->ipxp_socket = so; 99 if (ipxcksum) 100 ipxp->ipxp_flags |= IPXP_CHECKSUM; 101 LIST_INSERT_HEAD(head, ipxp, ipxp_list); 102 so->so_pcb = (caddr_t)ipxp; 103 return (0); 104} 105 106int 107ipx_pcbbind(struct ipxpcb *ipxp, struct sockaddr *nam, struct thread *td) 108{ 109 struct sockaddr_ipx *sipx; 110 u_short lport = 0; 111 112 IPX_LIST_LOCK_ASSERT(); 113 IPX_LOCK_ASSERT(ipxp); 114 115 if (ipxp->ipxp_lport || !ipx_nullhost(ipxp->ipxp_laddr)) 116 return (EINVAL); 117 if (nam == NULL) 118 goto noname; 119 sipx = (struct sockaddr_ipx *)nam; 120 if (!ipx_nullhost(sipx->sipx_addr)) { 121 int tport = sipx->sipx_port; 122 123 sipx->sipx_port = 0; /* yech... */ 124 if (ifa_ifwithaddr_check((struct sockaddr *)sipx) == 0) 125 return (EADDRNOTAVAIL); 126 sipx->sipx_port = tport; 127 } 128 lport = sipx->sipx_port; 129 if (lport) { 130 u_short aport = ntohs(lport); 131 132 if (aport < IPXPORT_RESERVED && td != NULL && 133 priv_check(td, PRIV_NETIPX_RESERVEDPORT)) 134 return (EACCES); 135 if (ipx_pcblookup(&zeroipx_addr, lport, 0)) 136 return (EADDRINUSE); 137 } 138 ipxp->ipxp_laddr = sipx->sipx_addr; 139noname: 140 if (lport == 0) 141 do { 142 ipxpcb_lport_cache++; 143 if ((ipxpcb_lport_cache < IPXPORT_RESERVED) || 144 (ipxpcb_lport_cache >= IPXPORT_WELLKNOWN)) 145 ipxpcb_lport_cache = IPXPORT_RESERVED; 146 lport = htons(ipxpcb_lport_cache); 147 } while (ipx_pcblookup(&zeroipx_addr, lport, 0)); 148 ipxp->ipxp_lport = lport; 149 return (0); 150} 151 152/* 153 * Connect from a socket to a specified address. 154 * Both address and port must be specified in argument sipx. 155 * If don't have a local address for this socket yet, 156 * then pick one. 157 */ 158int 159ipx_pcbconnect(struct ipxpcb *ipxp, struct sockaddr *nam, struct thread *td) 160{ 161 struct sockaddr_ipx *sipx = (struct sockaddr_ipx *)nam; 162 struct ipx_addr *dst; 163 struct route *ro; 164 struct ifnet *ifp; 165 166 IPX_LIST_LOCK_ASSERT(); 167 IPX_LOCK_ASSERT(ipxp); 168 169 if (sipx->sipx_family != AF_IPX) 170 return (EAFNOSUPPORT); 171 if (sipx->sipx_port == 0 || ipx_nullhost(sipx->sipx_addr)) 172 return (EADDRNOTAVAIL); 173 /* 174 * If we haven't bound which network number to use as ours, 175 * we will use the number of the outgoing interface. 176 * This depends on having done a routing lookup, which 177 * we will probably have to do anyway, so we might 178 * as well do it now. On the other hand if we are 179 * sending to multiple destinations we may have already 180 * done the lookup, so see if we can use the route 181 * from before. In any case, we only 182 * chose a port number once, even if sending to multiple 183 * destinations. 184 */ 185 ro = &ipxp->ipxp_route; 186 dst = &satoipx_addr(ro->ro_dst); 187 if (ipxp->ipxp_socket->so_options & SO_DONTROUTE) 188 goto flush; 189 if (!ipx_neteq(ipxp->ipxp_lastdst, sipx->sipx_addr)) 190 goto flush; 191 if (!ipx_hosteq(ipxp->ipxp_lastdst, sipx->sipx_addr)) { 192 if (ro->ro_rt != NULL && !(ro->ro_rt->rt_flags & RTF_HOST)) { 193 /* can patch route to avoid rtalloc */ 194 *dst = sipx->sipx_addr; 195 } else { 196 flush: 197 if (ro->ro_rt != NULL) 198 RTFREE(ro->ro_rt); 199 ro->ro_rt = NULL; 200 } 201 }/* else cached route is ok; do nothing */ 202 ipxp->ipxp_lastdst = sipx->sipx_addr; 203 if ((ipxp->ipxp_socket->so_options & SO_DONTROUTE) == 0 && /*XXX*/ 204 (ro->ro_rt == NULL || ro->ro_rt->rt_ifp == NULL)) { 205 /* No route yet, so try to acquire one */ 206 ro->ro_dst.sa_family = AF_IPX; 207 ro->ro_dst.sa_len = sizeof(ro->ro_dst); 208 *dst = sipx->sipx_addr; 209 dst->x_port = 0; 210 rtalloc_ign(ro, 0); 211 } 212 if (ipx_neteqnn(ipxp->ipxp_laddr.x_net, ipx_zeronet)) { 213 struct ipx_ifaddr *ia = NULL; 214 215 /* 216 * If route is known or can be allocated now, 217 * our src addr is taken from the i/f, else punt. 218 */ 219 220 /* 221 * If we found a route, use the address 222 * corresponding to the outgoing interface 223 */ 224 if (ro->ro_rt != NULL && (ifp = ro->ro_rt->rt_ifp) != NULL) { 225 IPX_IFADDR_RLOCK(); 226 TAILQ_FOREACH(ia, &ipx_ifaddrhead, ia_link) { 227 if (ia->ia_ifp == ifp) { 228 ifa_ref(&ia->ia_ifa); 229 break; 230 } 231 } 232 IPX_IFADDR_RUNLOCK(); 233 } 234 if (ia == NULL) { 235 u_short fport = sipx->sipx_addr.x_port; 236 sipx->sipx_addr.x_port = 0; 237 ia = (struct ipx_ifaddr *) 238 ifa_ifwithdstaddr((struct sockaddr *)sipx); 239 sipx->sipx_addr.x_port = fport; 240 if (ia == NULL) { 241 IPX_IFADDR_RLOCK(); 242 ia = ipx_iaonnetof(&sipx->sipx_addr); 243 if (ia != NULL) 244 ifa_ref(&ia->ia_ifa); 245 IPX_IFADDR_RUNLOCK(); 246 } 247 if (ia == NULL) { 248 IPX_IFADDR_RLOCK(); 249 ia = TAILQ_FIRST(&ipx_ifaddrhead); 250 if (ia != NULL) 251 ifa_ref(&ia->ia_ifa); 252 IPX_IFADDR_RUNLOCK(); 253 } 254 if (ia == NULL) 255 return (EADDRNOTAVAIL); 256 } 257 ipxp->ipxp_laddr.x_net = satoipx_addr(ia->ia_addr).x_net; 258 ifa_free(&ia->ia_ifa); 259 } 260 if (ipx_nullhost(ipxp->ipxp_laddr)) { 261 struct ipx_ifaddr *ia = NULL; 262 /* 263 * If route is known or can be allocated now, 264 * our src addr is taken from the i/f, else punt. 265 */ 266 267 /* 268 * If we found a route, use the address 269 * corresponding to the outgoing interface 270 */ 271 if (ro->ro_rt != NULL && (ifp = ro->ro_rt->rt_ifp) != NULL) { 272 IPX_IFADDR_RLOCK(); 273 TAILQ_FOREACH(ia, &ipx_ifaddrhead, ia_link) { 274 if (ia->ia_ifp == ifp) { 275 ifa_ref(&ia->ia_ifa); 276 break; 277 } 278 } 279 IPX_IFADDR_RUNLOCK(); 280 } 281 if (ia == NULL) { 282 u_short fport = sipx->sipx_addr.x_port; 283 sipx->sipx_addr.x_port = 0; 284 ia = (struct ipx_ifaddr *) 285 ifa_ifwithdstaddr((struct sockaddr *)sipx); 286 sipx->sipx_addr.x_port = fport; 287 if (ia == NULL) { 288 IPX_IFADDR_RLOCK(); 289 ia = ipx_iaonnetof(&sipx->sipx_addr); 290 if (ia != NULL) 291 ifa_ref(&ia->ia_ifa); 292 IPX_IFADDR_RUNLOCK(); 293 } 294 if (ia == NULL) { 295 IPX_IFADDR_RLOCK(); 296 ia = TAILQ_FIRST(&ipx_ifaddrhead); 297 if (ia != NULL) 298 ifa_ref(&ia->ia_ifa); 299 IPX_IFADDR_RUNLOCK(); 300 } 301 if (ia == NULL) 302 return (EADDRNOTAVAIL); 303 } 304 ipxp->ipxp_laddr.x_host = satoipx_addr(ia->ia_addr).x_host; 305 ifa_free(&ia->ia_ifa); 306 } 307 if (ipx_pcblookup(&sipx->sipx_addr, ipxp->ipxp_lport, 0)) 308 return (EADDRINUSE); 309 if (ipxp->ipxp_lport == 0) 310 ipx_pcbbind(ipxp, (struct sockaddr *)NULL, td); 311 312 /* XXX just leave it zero if we can't find a route */ 313 314 ipxp->ipxp_faddr = sipx->sipx_addr; 315 /* Includes ipxp->ipxp_fport = sipx->sipx_port; */ 316 return (0); 317} 318 319void 320ipx_pcbdisconnect(struct ipxpcb *ipxp) 321{ 322 323 IPX_LIST_LOCK_ASSERT(); 324 IPX_LOCK_ASSERT(ipxp); 325 326 ipxp->ipxp_faddr = zeroipx_addr; 327} 328 329void 330ipx_pcbdetach(struct ipxpcb *ipxp) 331{ 332 struct socket *so = ipxp->ipxp_socket; 333 334 IPX_LIST_LOCK_ASSERT(); 335 IPX_LOCK_ASSERT(ipxp); 336 337 so->so_pcb = NULL; 338 ipxp->ipxp_socket = NULL; 339} 340 341void 342ipx_pcbfree(struct ipxpcb *ipxp) 343{ 344 345 KASSERT(ipxp->ipxp_socket == NULL, 346 ("ipx_pcbfree: ipxp_socket != NULL")); 347 IPX_LIST_LOCK_ASSERT(); 348 IPX_LOCK_ASSERT(ipxp); 349 350 if (ipxp->ipxp_route.ro_rt != NULL) 351 RTFREE(ipxp->ipxp_route.ro_rt); 352 LIST_REMOVE(ipxp, ipxp_list); 353 IPX_LOCK_DESTROY(ipxp); 354 free(ipxp, M_PCB); 355} 356 357void 358ipx_getsockaddr(struct ipxpcb *ipxp, struct sockaddr **nam) 359{ 360 struct sockaddr_ipx *sipx, ssipx; 361 362 sipx = &ssipx; 363 bzero((caddr_t)sipx, sizeof(*sipx)); 364 sipx->sipx_len = sizeof(*sipx); 365 sipx->sipx_family = AF_IPX; 366 IPX_LOCK(ipxp); 367 sipx->sipx_addr = ipxp->ipxp_laddr; 368 IPX_UNLOCK(ipxp); 369 *nam = sodupsockaddr((struct sockaddr *)sipx, M_WAITOK); 370} 371 372void 373ipx_getpeeraddr(struct ipxpcb *ipxp, struct sockaddr **nam) 374{ 375 struct sockaddr_ipx *sipx, ssipx; 376 377 sipx = &ssipx; 378 bzero(sipx, sizeof(*sipx)); 379 sipx->sipx_len = sizeof(*sipx); 380 sipx->sipx_family = AF_IPX; 381 IPX_LOCK(ipxp); 382 sipx->sipx_addr = ipxp->ipxp_faddr; 383 IPX_UNLOCK(ipxp); 384 *nam = sodupsockaddr((struct sockaddr *)sipx, M_WAITOK); 385} 386 387struct ipxpcb * 388ipx_pcblookup(struct ipx_addr *faddr, u_short lport, int wildp) 389{ 390 struct ipxpcb *ipxp, *match = NULL; 391 int matchwild = 3, wildcard; 392 u_short fport; 393 394 IPX_LIST_LOCK_ASSERT(); 395 396 fport = faddr->x_port; 397 LIST_FOREACH(ipxp, &ipxpcb_list, ipxp_list) { 398 if (ipxp->ipxp_lport != lport) 399 continue; 400 wildcard = 0; 401 if (ipx_nullhost(ipxp->ipxp_faddr)) { 402 if (!ipx_nullhost(*faddr)) 403 wildcard++; 404 } else { 405 if (ipx_nullhost(*faddr)) 406 wildcard++; 407 else { 408 if (!ipx_hosteq(ipxp->ipxp_faddr, *faddr)) 409 continue; 410 if (ipxp->ipxp_fport != fport) { 411 if (ipxp->ipxp_fport != 0) 412 continue; 413 else 414 wildcard++; 415 } 416 } 417 } 418 if (wildcard && wildp == 0) 419 continue; 420 if (wildcard < matchwild) { 421 match = ipxp; 422 matchwild = wildcard; 423 if (wildcard == 0) 424 break; 425 } 426 } 427 return (match); 428} 429