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