ipx_pcb.c revision 139444
1/* 2 * Copyright (c) 2004, Robert N. M. Watson 3 * Copyright (c) 1995, Mike Mitchell 4 * Copyright (c) 1984, 1985, 1986, 1987, 1993 5 * The Regents of the University of California. 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 * 3. All advertising materials mentioning features or use of this software 16 * must display the following acknowledgement: 17 * This product includes software developed by the University of 18 * California, Berkeley and its contributors. 19 * 4. Neither the name of the University nor the names of its contributors 20 * may be used to endorse or promote products derived from this software 21 * without specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 * SUCH DAMAGE. 34 * 35 * @(#)ipx_pcb.c 36 */ 37 38#include <sys/cdefs.h> 39__FBSDID("$FreeBSD: head/sys/netipx/ipx_pcb.c 139444 2004-12-30 17:49:40Z rwatson $"); 40 41#include <sys/param.h> 42#include <sys/systm.h> 43#include <sys/malloc.h> 44#include <sys/socket.h> 45#include <sys/socketvar.h> 46 47#include <net/if.h> 48#include <net/route.h> 49 50#include <netipx/ipx.h> 51#include <netipx/ipx_if.h> 52#include <netipx/ipx_pcb.h> 53#include <netipx/ipx_var.h> 54 55static struct ipx_addr zeroipx_addr; 56 57int 58ipx_pcballoc(so, head, td) 59 struct socket *so; 60 struct ipxpcbhead *head; 61 struct thread *td; 62{ 63 register struct ipxpcb *ipxp; 64 65 MALLOC(ipxp, struct ipxpcb *, sizeof *ipxp, M_PCB, M_NOWAIT | M_ZERO); 66 if (ipxp == NULL) 67 return (ENOBUFS); 68 ipxp->ipxp_socket = so; 69 if (ipxcksum) 70 ipxp->ipxp_flags |= IPXP_CHECKSUM; 71 LIST_INSERT_HEAD(head, ipxp, ipxp_list); 72 so->so_pcb = (caddr_t)ipxp; 73 return (0); 74} 75 76int 77ipx_pcbbind(ipxp, nam, td) 78 register struct ipxpcb *ipxp; 79 struct sockaddr *nam; 80 struct thread *td; 81{ 82 register struct sockaddr_ipx *sipx; 83 u_short lport = 0; 84 85 if (ipxp->ipxp_lport || !ipx_nullhost(ipxp->ipxp_laddr)) 86 return (EINVAL); 87 if (nam == NULL) 88 goto noname; 89 sipx = (struct sockaddr_ipx *)nam; 90 if (!ipx_nullhost(sipx->sipx_addr)) { 91 int tport = sipx->sipx_port; 92 93 sipx->sipx_port = 0; /* yech... */ 94 if (ifa_ifwithaddr((struct sockaddr *)sipx) == 0) 95 return (EADDRNOTAVAIL); 96 sipx->sipx_port = tport; 97 } 98 lport = sipx->sipx_port; 99 if (lport) { 100 u_short aport = ntohs(lport); 101 int error; 102 103 if (aport < IPXPORT_RESERVED && 104 td != NULL && (error = suser(td)) != 0) 105 return (error); 106 if (ipx_pcblookup(&zeroipx_addr, lport, 0)) 107 return (EADDRINUSE); 108 } 109 ipxp->ipxp_laddr = sipx->sipx_addr; 110noname: 111 if (lport == 0) 112 do { 113 ipxpcb.ipxp_lport++; 114 if ((ipxpcb.ipxp_lport < IPXPORT_RESERVED) || 115 (ipxpcb.ipxp_lport >= IPXPORT_WELLKNOWN)) 116 ipxpcb.ipxp_lport = IPXPORT_RESERVED; 117 lport = htons(ipxpcb.ipxp_lport); 118 } while (ipx_pcblookup(&zeroipx_addr, lport, 0)); 119 ipxp->ipxp_lport = lport; 120 return (0); 121} 122 123/* 124 * Connect from a socket to a specified address. 125 * Both address and port must be specified in argument sipx. 126 * If don't have a local address for this socket yet, 127 * then pick one. 128 */ 129int 130ipx_pcbconnect(ipxp, nam, td) 131 struct ipxpcb *ipxp; 132 struct sockaddr *nam; 133 struct thread *td; 134{ 135 struct ipx_ifaddr *ia; 136 register struct sockaddr_ipx *sipx = (struct sockaddr_ipx *)nam; 137 register struct ipx_addr *dst; 138 register struct route *ro; 139 struct ifnet *ifp; 140 141 ia = NULL; 142 143 if (sipx->sipx_family != AF_IPX) 144 return (EAFNOSUPPORT); 145 if (sipx->sipx_port == 0 || ipx_nullhost(sipx->sipx_addr)) 146 return (EADDRNOTAVAIL); 147 /* 148 * If we haven't bound which network number to use as ours, 149 * we will use the number of the outgoing interface. 150 * This depends on having done a routing lookup, which 151 * we will probably have to do anyway, so we might 152 * as well do it now. On the other hand if we are 153 * sending to multiple destinations we may have already 154 * done the lookup, so see if we can use the route 155 * from before. In any case, we only 156 * chose a port number once, even if sending to multiple 157 * destinations. 158 */ 159 ro = &ipxp->ipxp_route; 160 dst = &satoipx_addr(ro->ro_dst); 161 if (ipxp->ipxp_socket->so_options & SO_DONTROUTE) 162 goto flush; 163 if (!ipx_neteq(ipxp->ipxp_lastdst, sipx->sipx_addr)) 164 goto flush; 165 if (!ipx_hosteq(ipxp->ipxp_lastdst, sipx->sipx_addr)) { 166 if (ro->ro_rt != NULL && !(ro->ro_rt->rt_flags & RTF_HOST)) { 167 /* can patch route to avoid rtalloc */ 168 *dst = sipx->sipx_addr; 169 } else { 170 flush: 171 if (ro->ro_rt != NULL) 172 RTFREE(ro->ro_rt); 173 ro->ro_rt = NULL; 174 } 175 }/* 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, td); 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 ACCEPT_LOCK(); 273 SOCK_LOCK(so); 274 so->so_pcb = 0; 275 sotryfree(so); 276 if (ipxp->ipxp_route.ro_rt != NULL) 277 rtfree(ipxp->ipxp_route.ro_rt); 278 LIST_REMOVE(ipxp, ipxp_list); 279 FREE(ipxp, M_PCB); 280} 281 282void 283ipx_setsockaddr(ipxp, nam) 284 register struct ipxpcb *ipxp; 285 struct sockaddr **nam; 286{ 287 struct sockaddr_ipx *sipx, ssipx; 288 289 sipx = &ssipx; 290 bzero((caddr_t)sipx, sizeof(*sipx)); 291 sipx->sipx_len = sizeof(*sipx); 292 sipx->sipx_family = AF_IPX; 293 sipx->sipx_addr = ipxp->ipxp_laddr; 294 *nam = sodupsockaddr((struct sockaddr *)sipx, M_NOWAIT); 295} 296 297void 298ipx_setpeeraddr(ipxp, nam) 299 register struct ipxpcb *ipxp; 300 struct sockaddr **nam; 301{ 302 struct sockaddr_ipx *sipx, ssipx; 303 304 sipx = &ssipx; 305 bzero((caddr_t)sipx, sizeof(*sipx)); 306 sipx->sipx_len = sizeof(*sipx); 307 sipx->sipx_family = AF_IPX; 308 sipx->sipx_addr = ipxp->ipxp_faddr; 309 *nam = sodupsockaddr((struct sockaddr *)sipx, M_NOWAIT); 310} 311 312struct ipxpcb * 313ipx_pcblookup(faddr, lport, wildp) 314 struct ipx_addr *faddr; 315 u_short lport; 316 int wildp; 317{ 318 register struct ipxpcb *ipxp, *match = 0; 319 int matchwild = 3, wildcard; 320 u_short fport; 321 322 fport = faddr->x_port; 323 LIST_FOREACH(ipxp, &ipxpcb_list, ipxp_list) { 324 if (ipxp->ipxp_lport != lport) 325 continue; 326 wildcard = 0; 327 if (ipx_nullhost(ipxp->ipxp_faddr)) { 328 if (!ipx_nullhost(*faddr)) 329 wildcard++; 330 } else { 331 if (ipx_nullhost(*faddr)) 332 wildcard++; 333 else { 334 if (!ipx_hosteq(ipxp->ipxp_faddr, *faddr)) 335 continue; 336 if (ipxp->ipxp_fport != fport) { 337 if (ipxp->ipxp_fport != 0) 338 continue; 339 else 340 wildcard++; 341 } 342 } 343 } 344 if (wildcard && wildp == 0) 345 continue; 346 if (wildcard < matchwild) { 347 match = ipxp; 348 matchwild = wildcard; 349 if (wildcard == 0) 350 break; 351 } 352 } 353 return (match); 354} 355