ipx_pcb.c revision 25652
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.8 1997/05/01 06:21:29 jhay Exp $ 37 */ 38 39#include <sys/param.h> 40#include <sys/queue.h> 41#include <sys/systm.h> 42#include <sys/mbuf.h> 43#include <sys/proc.h> 44#include <sys/protosw.h> 45#include <sys/errno.h> 46#include <sys/socket.h> 47#include <sys/socketvar.h> 48 49#include <net/if.h> 50#include <net/route.h> 51 52#include <netipx/ipx.h> 53#include <netipx/ipx_if.h> 54#include <netipx/ipx_pcb.h> 55#include <netipx/ipx_var.h> 56 57struct ipx_addr zeroipx_addr; 58 59int 60ipx_pcballoc(so, head, p) 61 struct socket *so; 62 struct ipxpcb *head; 63 struct proc *p; 64{ 65 struct mbuf *m; 66 register struct ipxpcb *ipxp; 67 68 m = m_getclr(M_DONTWAIT, MT_PCB); 69 if (m == NULL) 70 return (ENOBUFS); 71 ipxp = mtod(m, struct ipxpcb *); 72 ipxp->ipxp_socket = so; 73 insque(ipxp, head); 74 so->so_pcb = (caddr_t)ipxp; 75 return (0); 76} 77 78int 79ipx_pcbbind(ipxp, nam, p) 80 register struct ipxpcb *ipxp; 81 struct mbuf *nam; 82 struct proc *p; 83{ 84 register struct sockaddr_ipx *sipx; 85 u_short lport = 0; 86 87 if (ipxp->ipxp_lport || !ipx_nullhost(ipxp->ipxp_laddr)) 88 return (EINVAL); 89 if (nam == NULL) 90 goto noname; 91 sipx = mtod(nam, struct sockaddr_ipx *); 92 if (nam->m_len != sizeof(*sipx)) 93 return (EINVAL); 94 if (!ipx_nullhost(sipx->sipx_addr)) { 95 int tport = sipx->sipx_port; 96 97 sipx->sipx_port = 0; /* yech... */ 98 if (ifa_ifwithaddr((struct sockaddr *)sipx) == 0) 99 return (EADDRNOTAVAIL); 100 sipx->sipx_port = tport; 101 } 102 lport = sipx->sipx_port; 103 if (lport) { 104 u_short aport = ntohs(lport); 105 int error; 106 107 if (aport < IPXPORT_RESERVED && 108 p != NULL && (error = suser(p->p_ucred, &p->p_acflag)) != 0) 109 return (error); 110 if (ipx_pcblookup(&zeroipx_addr, lport, 0)) 111 return (EADDRINUSE); 112 } 113 ipxp->ipxp_laddr = sipx->sipx_addr; 114noname: 115 if (lport == 0) 116 do { 117 ipxpcb.ipxp_lport++; 118 if ((ipxpcb.ipxp_lport < IPXPORT_RESERVED) || 119 (ipxpcb.ipxp_lport >= IPXPORT_WELLKNOWN)) 120 ipxpcb.ipxp_lport = IPXPORT_RESERVED; 121 lport = htons(ipxpcb.ipxp_lport); 122 } while (ipx_pcblookup(&zeroipx_addr, lport, 0)); 123 ipxp->ipxp_lport = lport; 124 return (0); 125} 126 127/* 128 * Connect from a socket to a specified address. 129 * Both address and port must be specified in argument sipx. 130 * If don't have a local address for this socket yet, 131 * then pick one. 132 */ 133int 134ipx_pcbconnect(ipxp, nam, p) 135 struct ipxpcb *ipxp; 136 struct mbuf *nam; 137 struct proc *p; 138{ 139 struct ipx_ifaddr *ia; 140 register struct sockaddr_ipx *sipx = mtod(nam, struct sockaddr_ipx *); 141 register struct ipx_addr *dst; 142 register struct route *ro; 143 struct ifnet *ifp; 144 145 ia = NULL; 146 147 if (nam->m_len != sizeof(*sipx)) 148 return (EINVAL); 149 if (sipx->sipx_family != AF_IPX) 150 return (EAFNOSUPPORT); 151 if (sipx->sipx_port == 0 || ipx_nullhost(sipx->sipx_addr)) 152 return (EADDRNOTAVAIL); 153 /* 154 * If we haven't bound which network number to use as ours, 155 * we will use the number of the outgoing interface. 156 * This depends on having done a routing lookup, which 157 * we will probably have to do anyway, so we might 158 * as well do it now. On the other hand if we are 159 * sending to multiple destinations we may have already 160 * done the lookup, so see if we can use the route 161 * from before. In any case, we only 162 * chose a port number once, even if sending to multiple 163 * destinations. 164 */ 165 ro = &ipxp->ipxp_route; 166 dst = &satoipx_addr(ro->ro_dst); 167 if (ipxp->ipxp_socket->so_options & SO_DONTROUTE) 168 goto flush; 169 if (!ipx_neteq(ipxp->ipxp_lastdst, sipx->sipx_addr)) 170 goto flush; 171 if (!ipx_hosteq(ipxp->ipxp_lastdst, sipx->sipx_addr)) { 172 if (ro->ro_rt != NULL && !(ro->ro_rt->rt_flags & RTF_HOST)) { 173 /* can patch route to avoid rtalloc */ 174 *dst = sipx->sipx_addr; 175 } else { 176 flush: 177 if (ro->ro_rt != NULL) 178 RTFREE(ro->ro_rt); 179 ro->ro_rt = NULL; 180 ipxp->ipxp_laddr.x_net = ipx_zeronet; 181 } 182 }/* else cached route is ok; do nothing */ 183 ipxp->ipxp_lastdst = sipx->sipx_addr; 184 if ((ipxp->ipxp_socket->so_options & SO_DONTROUTE) == 0 && /*XXX*/ 185 (ro->ro_rt == NULL || ro->ro_rt->rt_ifp == NULL)) { 186 /* No route yet, so try to acquire one */ 187 ro->ro_dst.sa_family = AF_IPX; 188 ro->ro_dst.sa_len = sizeof(ro->ro_dst); 189 *dst = sipx->sipx_addr; 190 dst->x_port = 0; 191 rtalloc(ro); 192 } 193 if (ipx_neteqnn(ipxp->ipxp_laddr.x_net, ipx_zeronet)) { 194 /* 195 * If route is known or can be allocated now, 196 * our src addr is taken from the i/f, else punt. 197 */ 198 199 /* 200 * If we found a route, use the address 201 * corresponding to the outgoing interface 202 */ 203 if (ro->ro_rt != NULL && (ifp = ro->ro_rt->rt_ifp) != NULL) 204 for (ia = ipx_ifaddr; ia != NULL; ia = ia->ia_next) 205 if (ia->ia_ifp == ifp) 206 break; 207 if (ia == NULL) { 208 u_short fport = sipx->sipx_addr.x_port; 209 sipx->sipx_addr.x_port = 0; 210 ia = (struct ipx_ifaddr *) 211 ifa_ifwithdstaddr((struct sockaddr *)sipx); 212 sipx->sipx_addr.x_port = fport; 213 if (ia == NULL) 214 ia = ipx_iaonnetof(&sipx->sipx_addr); 215 if (ia == NULL) 216 ia = ipx_ifaddr; 217 if (ia == NULL) 218 return (EADDRNOTAVAIL); 219 } 220 ipxp->ipxp_laddr.x_net = satoipx_addr(ia->ia_addr).x_net; 221 } 222 if (ipx_nullhost(ipxp->ipxp_laddr)) { 223 /* 224 * If route is known or can be allocated now, 225 * our src addr is taken from the i/f, else punt. 226 */ 227 228 /* 229 * If we found a route, use the address 230 * corresponding to the outgoing interface 231 */ 232 if (ro->ro_rt != NULL && (ifp = ro->ro_rt->rt_ifp) != NULL) 233 for (ia = ipx_ifaddr; ia != NULL; ia = ia->ia_next) 234 if (ia->ia_ifp == ifp) 235 break; 236 if (ia == NULL) { 237 u_short fport = sipx->sipx_addr.x_port; 238 sipx->sipx_addr.x_port = 0; 239 ia = (struct ipx_ifaddr *) 240 ifa_ifwithdstaddr((struct sockaddr *)sipx); 241 sipx->sipx_addr.x_port = fport; 242 if (ia == NULL) 243 ia = ipx_iaonnetof(&sipx->sipx_addr); 244 if (ia == NULL) 245 ia = ipx_ifaddr; 246 if (ia == NULL) 247 return (EADDRNOTAVAIL); 248 } 249 ipxp->ipxp_laddr.x_host = satoipx_addr(ia->ia_addr).x_host; 250 } 251 if (ipx_pcblookup(&sipx->sipx_addr, ipxp->ipxp_lport, 0)) 252 return (EADDRINUSE); 253 if (ipxp->ipxp_lport == 0) 254 ipx_pcbbind(ipxp, (struct mbuf *)NULL, p); 255 256 /* XXX just leave it zero if we can't find a route */ 257 258 ipxp->ipxp_faddr = sipx->sipx_addr; 259 /* Includes ipxp->ipxp_fport = sipx->sipx_port; */ 260 return (0); 261} 262 263void 264ipx_pcbdisconnect(ipxp) 265 struct ipxpcb *ipxp; 266{ 267 268 ipxp->ipxp_faddr = zeroipx_addr; 269 if (ipxp->ipxp_socket->so_state & SS_NOFDREF) 270 ipx_pcbdetach(ipxp); 271} 272 273void 274ipx_pcbdetach(ipxp) 275 struct ipxpcb *ipxp; 276{ 277 struct socket *so = ipxp->ipxp_socket; 278 279 so->so_pcb = 0; 280 sofree(so); 281 if (ipxp->ipxp_route.ro_rt != NULL) 282 rtfree(ipxp->ipxp_route.ro_rt); 283 remque(ipxp); 284 m_free(dtom(ipxp)); 285} 286 287void 288ipx_setsockaddr(ipxp, nam) 289 register struct ipxpcb *ipxp; 290 struct mbuf *nam; 291{ 292 register struct sockaddr_ipx *sipx = mtod(nam, struct sockaddr_ipx *); 293 294 nam->m_len = sizeof(*sipx); 295 sipx = mtod(nam, struct sockaddr_ipx *); 296 bzero((caddr_t)sipx, sizeof(*sipx)); 297 sipx->sipx_len = sizeof(*sipx); 298 sipx->sipx_family = AF_IPX; 299 sipx->sipx_addr = ipxp->ipxp_laddr; 300} 301 302void 303ipx_setpeeraddr(ipxp, nam) 304 register struct ipxpcb *ipxp; 305 struct mbuf *nam; 306{ 307 register struct sockaddr_ipx *sipx = mtod(nam, struct sockaddr_ipx *); 308 309 nam->m_len = sizeof(*sipx); 310 sipx = mtod(nam, struct sockaddr_ipx *); 311 bzero((caddr_t)sipx, sizeof(*sipx)); 312 sipx->sipx_len = sizeof(*sipx); 313 sipx->sipx_family = AF_IPX; 314 sipx->sipx_addr = ipxp->ipxp_faddr; 315} 316 317/* 318 * Pass some notification to all connections of a protocol 319 * associated with address dst. Call the 320 * protocol specific routine to handle each connection. 321 * Also pass an extra paramter via the ipxpcb. (which may in fact 322 * be a parameter list!) 323 */ 324void 325ipx_pcbnotify(dst, errno, notify, param) 326 register struct ipx_addr *dst; 327 int errno; 328 void (*notify)(struct ipxpcb *); 329 long param; 330{ 331 register struct ipxpcb *ipxp, *oinp; 332 int s = splimp(); 333 334 for (ipxp = (&ipxpcb)->ipxp_next; ipxp != (&ipxpcb);) { 335 if (!ipx_hosteq(*dst,ipxp->ipxp_faddr)) { 336 next: 337 ipxp = ipxp->ipxp_next; 338 continue; 339 } 340 if (ipxp->ipxp_socket == 0) 341 goto next; 342 if (errno) 343 ipxp->ipxp_socket->so_error = errno; 344 oinp = ipxp; 345 ipxp = ipxp->ipxp_next; 346 oinp->ipxp_notify_param = param; 347 (*notify)(oinp); 348 } 349 splx(s); 350} 351 352#ifdef notdef 353/* 354 * After a routing change, flush old routing 355 * and allocate a (hopefully) better one. 356 */ 357ipx_rtchange(ipxp) 358 struct ipxpcb *ipxp; 359{ 360 if (ipxp->ipxp_route.ro_rt != NULL) { 361 rtfree(ipxp->ipxp_route.ro_rt); 362 ipxp->ipxp_route.ro_rt = NULL; 363 /* 364 * A new route can be allocated the next time 365 * output is attempted. 366 */ 367 } 368 /* SHOULD NOTIFY HIGHER-LEVEL PROTOCOLS */ 369} 370#endif 371 372struct ipxpcb * 373ipx_pcblookup(faddr, lport, wildp) 374 struct ipx_addr *faddr; 375 u_short lport; 376 int wildp; 377{ 378 register struct ipxpcb *ipxp, *match = 0; 379 int matchwild = 3, wildcard; 380 u_short fport; 381 382 fport = faddr->x_port; 383 for (ipxp = (&ipxpcb)->ipxp_next; ipxp != (&ipxpcb); ipxp = ipxp->ipxp_next) { 384 if (ipxp->ipxp_lport != lport) 385 continue; 386 wildcard = 0; 387 if (ipx_nullhost(ipxp->ipxp_faddr)) { 388 if (!ipx_nullhost(*faddr)) 389 wildcard++; 390 } else { 391 if (ipx_nullhost(*faddr)) 392 wildcard++; 393 else { 394 if (!ipx_hosteq(ipxp->ipxp_faddr, *faddr)) 395 continue; 396 if (ipxp->ipxp_fport != fport) { 397 if (ipxp->ipxp_fport != 0) 398 continue; 399 else 400 wildcard++; 401 } 402 } 403 } 404 if (wildcard && wildp == 0) 405 continue; 406 if (wildcard < matchwild) { 407 match = ipxp; 408 matchwild = wildcard; 409 if (wildcard == 0) 410 break; 411 } 412 } 413 return (match); 414} 415