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