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