1 /* $NetBSD: in_pcb.c,v 1.23 1995/08/17 02:57:27 mycroft Exp $ */ 2 3 /* 4 * Copyright (c) 1982, 1986, 1991, 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 * @(#)in_pcb.c 8.2 (Berkeley) 1/4/94 36 */ 37 38 #include <sys/param.h> 39 #include <sys/systm.h> 40 #include <sys/malloc.h> 41 #include <sys/mbuf.h> 42 #include <sys/protosw.h> 43 #include <sys/socket.h> 44 #include <sys/socketvar.h> 45 #include <sys/ioctl.h> 46 #include <sys/errno.h> 47 #include <sys/time.h> 48 #include <sys/proc.h> 49 50 #include <net/if.h> 51 #include <net/route.h> 52 53 #include <netinet/in.h> 54 #include <netinet/in_systm.h> 55 #include <netinet/ip.h> 56 #include <netinet/in_pcb.h> 57 #include <netinet/in_var.h> 58 #include <netinet/ip_var.h> 59 60 struct in_addr zeroin_addr; 61 62 void 63 in_pcbinit(table) 64 struct inpcbtable *table; 65 { 66 67 CIRCLEQ_INIT(&table->inpt_queue); 68 table->inpt_lastport = 0; 69 } 70 71 int 72 in_pcballoc(so, table) 73 struct socket *so; 74 struct inpcbtable *table; 75 { 76 register struct inpcb *inp; 77 78 MALLOC(inp, struct inpcb *, sizeof(*inp), M_PCB, M_WAITOK); 79 if (inp == NULL) 80 return (ENOBUFS); 81 bzero((caddr_t)inp, sizeof(*inp)); 82 inp->inp_table = table; 83 inp->inp_socket = so; 84 CIRCLEQ_INSERT_HEAD(&table->inpt_queue, inp, inp_queue); 85 so->so_pcb = inp; 86 return (0); 87 } 88 89 int 90 in_pcbbind(inp, nam) 91 register struct inpcb *inp; 92 struct mbuf *nam; 93 { 94 register struct socket *so = inp->inp_socket; 95 register struct inpcbtable *table = inp->inp_table; 96 register struct sockaddr_in *sin; 97 struct proc *p = curproc; /* XXX */ 98 u_int16_t lport = 0; 99 int wild = 0, reuseport = (so->so_options & SO_REUSEPORT); 100 int error; 101 102 if (in_ifaddr.tqh_first == 0) 103 return (EADDRNOTAVAIL); 104 if (inp->inp_lport || inp->inp_laddr.s_addr != INADDR_ANY) 105 return (EINVAL); 106 if ((so->so_options & (SO_REUSEADDR|SO_REUSEPORT)) == 0 && 107 ((so->so_proto->pr_flags & PR_CONNREQUIRED) == 0 || 108 (so->so_options & SO_ACCEPTCONN) == 0)) 109 wild = INPLOOKUP_WILDCARD; 110 if (nam) { 111 sin = mtod(nam, struct sockaddr_in *); 112 if (nam->m_len != sizeof (*sin)) 113 return (EINVAL); 114 #ifdef notdef 115 /* 116 * We should check the family, but old programs 117 * incorrectly fail to initialize it. 118 */ 119 if (sin->sin_family != AF_INET) 120 return (EAFNOSUPPORT); 121 #endif 122 lport = sin->sin_port; 123 if (IN_MULTICAST(sin->sin_addr.s_addr)) { 124 /* 125 * Treat SO_REUSEADDR as SO_REUSEPORT for multicast; 126 * allow complete duplication of binding if 127 * SO_REUSEPORT is set, or if SO_REUSEADDR is set 128 * and a multicast address is bound on both 129 * new and duplicated sockets. 130 */ 131 if (so->so_options & SO_REUSEADDR) 132 reuseport = SO_REUSEADDR|SO_REUSEPORT; 133 } else if (sin->sin_addr.s_addr != INADDR_ANY) { 134 sin->sin_port = 0; /* yech... */ 135 if (ifa_ifwithaddr(sintosa(sin)) == 0) 136 return (EADDRNOTAVAIL); 137 } 138 if (lport) { 139 struct inpcb *t; 140 141 /* GROSS */ 142 if (ntohs(lport) < IPPORT_RESERVED && 143 (error = suser(p->p_ucred, &p->p_acflag))) 144 return (EACCES); 145 t = in_pcblookup(table, zeroin_addr, 0, 146 sin->sin_addr, lport, wild); 147 if (t && (reuseport & t->inp_socket->so_options) == 0) 148 return (EADDRINUSE); 149 } 150 inp->inp_laddr = sin->sin_addr; 151 } 152 if (lport == 0) 153 do { 154 if (table->inpt_lastport++ < IPPORT_RESERVED || 155 table->inpt_lastport > IPPORT_USERRESERVED) 156 table->inpt_lastport = IPPORT_RESERVED; 157 lport = htons(table->inpt_lastport); 158 } while (in_pcblookup(table, 159 zeroin_addr, 0, inp->inp_laddr, lport, wild)); 160 inp->inp_lport = lport; 161 return (0); 162 } 163 164 /* 165 * Connect from a socket to a specified address. 166 * Both address and port must be specified in argument sin. 167 * If don't have a local address for this socket yet, 168 * then pick one. 169 */ 170 int 171 in_pcbconnect(inp, nam) 172 register struct inpcb *inp; 173 struct mbuf *nam; 174 { 175 struct in_ifaddr *ia; 176 struct sockaddr_in *ifaddr; 177 register struct sockaddr_in *sin = mtod(nam, struct sockaddr_in *); 178 179 if (nam->m_len != sizeof (*sin)) 180 return (EINVAL); 181 if (sin->sin_family != AF_INET) 182 return (EAFNOSUPPORT); 183 if (sin->sin_port == 0) 184 return (EADDRNOTAVAIL); 185 if (in_ifaddr.tqh_first != 0) { 186 /* 187 * If the destination address is INADDR_ANY, 188 * use the primary local address. 189 * If the supplied address is INADDR_BROADCAST, 190 * and the primary interface supports broadcast, 191 * choose the broadcast address for that interface. 192 */ 193 if (sin->sin_addr.s_addr == INADDR_ANY) 194 sin->sin_addr = in_ifaddr.tqh_first->ia_addr.sin_addr; 195 else if (sin->sin_addr.s_addr == INADDR_BROADCAST && 196 (in_ifaddr.tqh_first->ia_ifp->if_flags & IFF_BROADCAST)) 197 sin->sin_addr = in_ifaddr.tqh_first->ia_broadaddr.sin_addr; 198 } 199 if (inp->inp_laddr.s_addr == INADDR_ANY) { 200 register struct route *ro; 201 202 ia = (struct in_ifaddr *)0; 203 /* 204 * If route is known or can be allocated now, 205 * our src addr is taken from the i/f, else punt. 206 */ 207 ro = &inp->inp_route; 208 if (ro->ro_rt && 209 (satosin(&ro->ro_dst)->sin_addr.s_addr != 210 sin->sin_addr.s_addr || 211 inp->inp_socket->so_options & SO_DONTROUTE)) { 212 RTFREE(ro->ro_rt); 213 ro->ro_rt = (struct rtentry *)0; 214 } 215 if ((inp->inp_socket->so_options & SO_DONTROUTE) == 0 && /*XXX*/ 216 (ro->ro_rt == (struct rtentry *)0 || 217 ro->ro_rt->rt_ifp == (struct ifnet *)0)) { 218 /* No route yet, so try to acquire one */ 219 ro->ro_dst.sa_family = AF_INET; 220 ro->ro_dst.sa_len = sizeof(struct sockaddr_in); 221 satosin(&ro->ro_dst)->sin_addr = sin->sin_addr; 222 rtalloc(ro); 223 } 224 /* 225 * If we found a route, use the address 226 * corresponding to the outgoing interface 227 * unless it is the loopback (in case a route 228 * to our address on another net goes to loopback). 229 */ 230 if (ro->ro_rt && !(ro->ro_rt->rt_ifp->if_flags & IFF_LOOPBACK)) 231 ia = ifatoia(ro->ro_rt->rt_ifa); 232 if (ia == 0) { 233 u_int16_t fport = sin->sin_port; 234 235 sin->sin_port = 0; 236 ia = ifatoia(ifa_ifwithdstaddr(sintosa(sin))); 237 if (ia == 0) 238 ia = ifatoia(ifa_ifwithnet(sintosa(sin))); 239 sin->sin_port = fport; 240 if (ia == 0) 241 ia = in_ifaddr.tqh_first; 242 if (ia == 0) 243 return (EADDRNOTAVAIL); 244 } 245 /* 246 * If the destination address is multicast and an outgoing 247 * interface has been set as a multicast option, use the 248 * address of that interface as our source address. 249 */ 250 if (IN_MULTICAST(sin->sin_addr.s_addr) && 251 inp->inp_moptions != NULL) { 252 struct ip_moptions *imo; 253 struct ifnet *ifp; 254 255 imo = inp->inp_moptions; 256 if (imo->imo_multicast_ifp != NULL) { 257 ifp = imo->imo_multicast_ifp; 258 for (ia = in_ifaddr.tqh_first; ia != 0; 259 ia = ia->ia_list.tqe_next) 260 if (ia->ia_ifp == ifp) 261 break; 262 if (ia == 0) 263 return (EADDRNOTAVAIL); 264 } 265 } 266 ifaddr = satosin(&ia->ia_addr); 267 } 268 if (in_pcblookup(inp->inp_table, 269 sin->sin_addr, 270 sin->sin_port, 271 inp->inp_laddr.s_addr ? inp->inp_laddr : ifaddr->sin_addr, 272 inp->inp_lport, 273 0)) 274 return (EADDRINUSE); 275 if (inp->inp_laddr.s_addr == INADDR_ANY) { 276 if (inp->inp_lport == 0) 277 (void)in_pcbbind(inp, (struct mbuf *)0); 278 inp->inp_laddr = ifaddr->sin_addr; 279 } 280 inp->inp_faddr = sin->sin_addr; 281 inp->inp_fport = sin->sin_port; 282 return (0); 283 } 284 285 int 286 in_pcbdisconnect(inp) 287 struct inpcb *inp; 288 { 289 290 inp->inp_faddr.s_addr = INADDR_ANY; 291 inp->inp_fport = 0; 292 if (inp->inp_socket->so_state & SS_NOFDREF) 293 in_pcbdetach(inp); 294 } 295 296 int 297 in_pcbdetach(inp) 298 struct inpcb *inp; 299 { 300 struct socket *so = inp->inp_socket; 301 302 so->so_pcb = 0; 303 sofree(so); 304 if (inp->inp_options) 305 (void)m_free(inp->inp_options); 306 if (inp->inp_route.ro_rt) 307 rtfree(inp->inp_route.ro_rt); 308 ip_freemoptions(inp->inp_moptions); 309 CIRCLEQ_REMOVE(&inp->inp_table->inpt_queue, inp, inp_queue); 310 FREE(inp, M_PCB); 311 } 312 313 int 314 in_setsockaddr(inp, nam) 315 register struct inpcb *inp; 316 struct mbuf *nam; 317 { 318 register struct sockaddr_in *sin; 319 320 nam->m_len = sizeof (*sin); 321 sin = mtod(nam, struct sockaddr_in *); 322 bzero((caddr_t)sin, sizeof (*sin)); 323 sin->sin_family = AF_INET; 324 sin->sin_len = sizeof(*sin); 325 sin->sin_port = inp->inp_lport; 326 sin->sin_addr = inp->inp_laddr; 327 } 328 329 int 330 in_setpeeraddr(inp, nam) 331 struct inpcb *inp; 332 struct mbuf *nam; 333 { 334 register struct sockaddr_in *sin; 335 336 nam->m_len = sizeof (*sin); 337 sin = mtod(nam, struct sockaddr_in *); 338 bzero((caddr_t)sin, sizeof (*sin)); 339 sin->sin_family = AF_INET; 340 sin->sin_len = sizeof(*sin); 341 sin->sin_port = inp->inp_fport; 342 sin->sin_addr = inp->inp_faddr; 343 } 344 345 /* 346 * Pass some notification to all connections of a protocol 347 * associated with address dst. The local address and/or port numbers 348 * may be specified to limit the search. The "usual action" will be 349 * taken, depending on the ctlinput cmd. The caller must filter any 350 * cmds that are uninteresting (e.g., no error in the map). 351 * Call the protocol specific routine (if any) to report 352 * any errors for each matching socket. 353 * 354 * Must be called at splsoftnet. 355 */ 356 void 357 in_pcbnotify(table, dst, fport_arg, laddr, lport_arg, errno, notify) 358 struct inpcbtable *table; 359 struct sockaddr *dst; 360 u_int fport_arg, lport_arg; 361 struct in_addr laddr; 362 int errno; 363 void (*notify) __P((struct inpcb *, int)); 364 { 365 register struct inpcb *inp, *oinp; 366 struct in_addr faddr; 367 u_int16_t fport = fport_arg, lport = lport_arg; 368 369 if (dst->sa_family != AF_INET) 370 return; 371 faddr = satosin(dst)->sin_addr; 372 if (faddr.s_addr == INADDR_ANY) 373 return; 374 375 for (inp = table->inpt_queue.cqh_first; 376 inp != (struct inpcb *)&table->inpt_queue;) { 377 if (inp->inp_faddr.s_addr != faddr.s_addr || 378 inp->inp_socket == 0 || 379 inp->inp_fport != fport || 380 inp->inp_lport != lport || 381 inp->inp_laddr.s_addr != laddr.s_addr) { 382 inp = inp->inp_queue.cqe_next; 383 continue; 384 } 385 oinp = inp; 386 inp = inp->inp_queue.cqe_next; 387 if (notify) 388 (*notify)(oinp, errno); 389 } 390 } 391 392 void 393 in_pcbnotifyall(table, dst, errno, notify) 394 struct inpcbtable *table; 395 struct sockaddr *dst; 396 int errno; 397 void (*notify) __P((struct inpcb *, int)); 398 { 399 register struct inpcb *inp, *oinp; 400 struct in_addr faddr; 401 402 if (dst->sa_family != AF_INET) 403 return; 404 faddr = satosin(dst)->sin_addr; 405 if (faddr.s_addr == INADDR_ANY) 406 return; 407 408 for (inp = table->inpt_queue.cqh_first; 409 inp != (struct inpcb *)&table->inpt_queue;) { 410 if (inp->inp_faddr.s_addr != faddr.s_addr || 411 inp->inp_socket == 0) { 412 inp = inp->inp_queue.cqe_next; 413 continue; 414 } 415 oinp = inp; 416 inp = inp->inp_queue.cqe_next; 417 if (notify) 418 (*notify)(oinp, errno); 419 } 420 } 421 422 /* 423 * Check for alternatives when higher level complains 424 * about service problems. For now, invalidate cached 425 * routing information. If the route was created dynamically 426 * (by a redirect), time to try a default gateway again. 427 */ 428 int 429 in_losing(inp) 430 struct inpcb *inp; 431 { 432 register struct rtentry *rt; 433 struct rt_addrinfo info; 434 435 if ((rt = inp->inp_route.ro_rt)) { 436 inp->inp_route.ro_rt = 0; 437 bzero((caddr_t)&info, sizeof(info)); 438 info.rti_info[RTAX_DST] = &inp->inp_route.ro_dst; 439 info.rti_info[RTAX_GATEWAY] = rt->rt_gateway; 440 info.rti_info[RTAX_NETMASK] = rt_mask(rt); 441 rt_missmsg(RTM_LOSING, &info, rt->rt_flags, 0); 442 if (rt->rt_flags & RTF_DYNAMIC) 443 (void) rtrequest(RTM_DELETE, rt_key(rt), 444 rt->rt_gateway, rt_mask(rt), rt->rt_flags, 445 (struct rtentry **)0); 446 else 447 /* 448 * A new route can be allocated 449 * the next time output is attempted. 450 */ 451 rtfree(rt); 452 } 453 } 454 455 /* 456 * After a routing change, flush old routing 457 * and allocate a (hopefully) better one. 458 */ 459 void 460 in_rtchange(inp, errno) 461 register struct inpcb *inp; 462 int errno; 463 { 464 if (inp->inp_route.ro_rt) { 465 rtfree(inp->inp_route.ro_rt); 466 inp->inp_route.ro_rt = 0; 467 /* 468 * A new route can be allocated the next time 469 * output is attempted. 470 */ 471 } 472 } 473 474 struct inpcb * 475 in_pcblookup(table, faddr, fport_arg, laddr, lport_arg, flags) 476 struct inpcbtable *table; 477 struct in_addr faddr, laddr; 478 u_int fport_arg, lport_arg; 479 int flags; 480 { 481 register struct inpcb *inp, *match = 0; 482 int matchwild = 3, wildcard; 483 u_int16_t fport = fport_arg, lport = lport_arg; 484 485 for (inp = table->inpt_queue.cqh_first; 486 inp != (struct inpcb *)&table->inpt_queue; 487 inp = inp->inp_queue.cqe_next) { 488 if (inp->inp_lport != lport) 489 continue; 490 wildcard = 0; 491 if (inp->inp_laddr.s_addr != INADDR_ANY) { 492 if (laddr.s_addr == INADDR_ANY) 493 wildcard++; 494 else if (inp->inp_laddr.s_addr != laddr.s_addr) 495 continue; 496 } else { 497 if (laddr.s_addr != INADDR_ANY) 498 wildcard++; 499 } 500 if (inp->inp_faddr.s_addr != INADDR_ANY) { 501 if (faddr.s_addr == INADDR_ANY) 502 wildcard++; 503 else if (inp->inp_faddr.s_addr != faddr.s_addr || 504 inp->inp_fport != fport) 505 continue; 506 } else { 507 if (faddr.s_addr != INADDR_ANY) 508 wildcard++; 509 } 510 if (wildcard && (flags & INPLOOKUP_WILDCARD) == 0) 511 continue; 512 if (wildcard < matchwild) { 513 match = inp; 514 matchwild = wildcard; 515 if (matchwild == 0) 516 break; 517 } 518 } 519 return (match); 520 } 521