1 /* 2 * Copyright (c) 1982, 1986, 1991 Regents of the University of California. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. All advertising materials mentioning features or use of this software 14 * must display the following acknowledgement: 15 * This product includes software developed by the University of 16 * California, Berkeley and its contributors. 17 * 4. Neither the name of the University nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 * 33 * $Id: in_pcb.c,v 1.1 94/10/20 10:53:27 root Exp $ 34 */ 35 36 #include "sys/param.h" 37 #include "sys/errno.h" 38 #include "systm.h" 39 #include "malloc.h" 40 #include "mbuf.h" 41 #include "protosw.h" 42 #include "sys/file.h" 43 #include "socketvar.h" 44 #include "sys/ioctl.h" 45 #include "prototypes.h" 46 47 #include "if.h" 48 #include "route.h" 49 50 #include "in.h" 51 #include "in_systm.h" 52 #include "ip.h" 53 #include "in_pcb.h" 54 #include "in_var.h" 55 56 struct in_addr zeroin_addr; 57 58 in_pcballoc(so, head) 59 struct socket *so; 60 struct inpcb *head; 61 { 62 struct mbuf *m; 63 register struct inpcb *inp; 64 65 m = m_getclr(M_DONTWAIT, MT_PCB); 66 if (m == NULL) 67 return (ENOBUFS); 68 inp = mtod(m, struct inpcb *); 69 inp->inp_head = head; 70 inp->inp_socket = so; 71 insque(inp, head); 72 so->so_pcb = (caddr_t)inp; 73 return (0); 74 } 75 76 in_pcbbind(inp, nam) 77 register struct inpcb *inp; 78 struct mbuf *nam; 79 { 80 register struct socket *so = inp->inp_socket; 81 register struct inpcb *head = inp->inp_head; 82 register struct sockaddr_in *sin; 83 u_short lport = 0; 84 int wild = 0; 85 86 if (in_ifaddr == 0) 87 return (EADDRNOTAVAIL); 88 if (inp->inp_lport || inp->inp_laddr.s_addr != INADDR_ANY) 89 return (EINVAL); 90 91 if ((so->so_options & SO_REUSEADDR) == 0 && 92 ((so->so_proto->pr_flags & PR_CONNREQUIRED) == 0 || 93 (so->so_options & SO_ACCEPTCONN) == 0)) 94 wild = INPLOOKUP_WILDCARD; 95 96 if (nam == 0) 97 goto noname; 98 sin = mtod(nam, struct sockaddr_in *); 99 if (nam->m_len != sizeof (*sin)) 100 return (EINVAL); 101 if (sin->sin_addr.s_addr != INADDR_ANY) { 102 int tport = sin->sin_port; 103 104 sin->sin_port = 0; /* yech... */ 105 if (ifa_ifwithaddr((struct sockaddr *)sin) == 0) 106 return (EADDRNOTAVAIL); 107 sin->sin_port = tport; 108 } 109 lport = sin->sin_port; 110 if (lport) { 111 u_short aport = ntohs(lport); 112 113 /* GROSS */ 114 if (aport < IPPORT_RESERVED && (so->so_state & SS_PRIV) == 0) 115 return (EACCES); 116 if (in_pcblookup(head, 117 zeroin_addr, 0, sin->sin_addr, lport, wild)) 118 return (EADDRINUSE); 119 } 120 inp->inp_laddr = sin->sin_addr; 121 noname: 122 if (lport == 0) 123 do { 124 if (head->inp_lport++ < IPPORT_RESERVED || 125 head->inp_lport > IPPORT_USERRESERVED) 126 head->inp_lport = IPPORT_RESERVED; 127 lport = htons(head->inp_lport); 128 } while (in_pcblookup(head, 129 zeroin_addr, 0, inp->inp_laddr, lport, wild)); 130 inp->inp_lport = lport; 131 return (0); 132 } 133 134 /* 135 * Connect from a socket to a specified address. 136 * Both address and port must be specified in argument sin. 137 * If don't have a local address for this socket yet, 138 * then pick one. 139 */ 140 in_pcbconnect(inp, nam) 141 register struct inpcb *inp; 142 struct mbuf *nam; 143 { 144 struct in_ifaddr *ia; 145 struct sockaddr_in *ifaddr; 146 register struct sockaddr_in *sin = mtod(nam, struct sockaddr_in *); 147 148 if (nam->m_len != sizeof (*sin)) 149 return (EINVAL); 150 if (sin->sin_family != AF_INET) 151 return (EAFNOSUPPORT); 152 if (sin->sin_port == 0) 153 return (EADDRNOTAVAIL); 154 if (in_ifaddr) { 155 /* 156 * If the destination address is INADDR_ANY, 157 * use the primary local address. 158 * If the supplied address is INADDR_BROADCAST, 159 * and the primary interface supports broadcast, 160 * choose the broadcast address for that interface. 161 */ 162 #define satosin(sa) ((struct sockaddr_in *)(sa)) 163 if (sin->sin_addr.s_addr == INADDR_ANY) 164 sin->sin_addr = IA_SIN(in_ifaddr)->sin_addr; 165 else if (sin->sin_addr.s_addr == (u_long)INADDR_BROADCAST && 166 (in_ifaddr->ia_ifp->if_flags & IFF_BROADCAST)) 167 sin->sin_addr = satosin(&in_ifaddr->ia_broadaddr)->sin_addr; 168 } 169 if (inp->inp_laddr.s_addr == INADDR_ANY) { 170 register struct route *ro; 171 struct ifnet *ifp; 172 173 ia = (struct in_ifaddr *)0; 174 /* 175 * If route is known or can be allocated now, 176 * our src addr is taken from the i/f, else punt. 177 */ 178 ro = &inp->inp_route; 179 if (ro->ro_rt && 180 (satosin(&ro->ro_dst)->sin_addr.s_addr != 181 sin->sin_addr.s_addr || 182 inp->inp_socket->so_options & SO_DONTROUTE)) { 183 RTFREE_(ro->ro_rt); 184 ro->ro_rt = (struct rtentry *)0; 185 } 186 if ((inp->inp_socket->so_options & SO_DONTROUTE) == 0 && /*XXX*/ 187 (ro->ro_rt == (struct rtentry *)0 || 188 ro->ro_rt->rt_ifp == (struct ifnet *)0)) { 189 /* No route yet, so try to acquire one */ 190 ro->ro_dst.sa_family = AF_INET; 191 ro->ro_dst.sa_len = sizeof(struct sockaddr_in); 192 ((struct sockaddr_in *) &ro->ro_dst)->sin_addr = 193 sin->sin_addr; 194 RTALLOC(ro); 195 } 196 /* 197 * If we found a route, use the address 198 * corresponding to the outgoing interface 199 * unless it is the loopback (in case a route 200 * to our address on another net goes to loopback). 201 */ 202 if (ro->ro_rt && (ifp = ro->ro_rt->rt_ifp) && 203 (ifp->if_flags & IFF_LOOPBACK) == 0) 204 for (ia = in_ifaddr; ia; ia = ia->ia_next) 205 if (ia->ia_ifp == ifp) 206 break; 207 if (ia == 0) { 208 int fport = sin->sin_port; 209 210 sin->sin_port = 0; 211 ia = (struct in_ifaddr *) 212 ifa_ifwithdstaddr((struct sockaddr *)sin); 213 sin->sin_port = fport; 214 if (ia == 0) 215 ia = in_iaonnetof(in_netof(sin->sin_addr)); 216 if (ia == 0) 217 ia = in_ifaddr; 218 if (ia == 0) 219 return (EADDRNOTAVAIL); 220 } 221 ifaddr = (struct sockaddr_in *)&ia->ia_addr; 222 } 223 if (in_pcblookup(inp->inp_head, 224 sin->sin_addr, 225 sin->sin_port, 226 inp->inp_laddr.s_addr ? inp->inp_laddr : ifaddr->sin_addr, 227 inp->inp_lport, 228 0)) 229 return (EADDRINUSE); 230 if (inp->inp_laddr.s_addr == INADDR_ANY) { 231 if (inp->inp_lport == 0) 232 (void)in_pcbbind(inp, (struct mbuf *)0); 233 inp->inp_laddr = ifaddr->sin_addr; 234 } 235 inp->inp_faddr = sin->sin_addr; 236 inp->inp_fport = sin->sin_port; 237 return (0); 238 } 239 240 in_pcbdisconnect(inp) 241 struct inpcb *inp; 242 { 243 244 inp->inp_faddr.s_addr = INADDR_ANY; 245 inp->inp_fport = 0; 246 if (inp->inp_socket->so_state & SS_NOFDREF) 247 in_pcbdetach(inp); 248 } 249 250 in_pcbdetach(inp) 251 struct inpcb *inp; 252 { 253 struct socket *so = inp->inp_socket; 254 255 so->so_pcb = 0; 256 sofree(so); 257 if (inp->inp_options) 258 (void)m_free(inp->inp_options); 259 if (inp->inp_route.ro_rt) 260 RTFREE(inp->inp_route.ro_rt); 261 remque(inp); 262 (void) m_free(dtom(inp)); 263 } 264 265 in_setsockaddr(inp, nam) 266 register struct inpcb *inp; 267 struct mbuf *nam; 268 { 269 register struct sockaddr_in *sin; 270 271 nam->m_len = sizeof (*sin); 272 sin = mtod(nam, struct sockaddr_in *); 273 (void) memset((caddr_t)sin, 0, sizeof (*sin)); 274 sin->sin_family = AF_INET; 275 sin->sin_len = sizeof(*sin); 276 sin->sin_port = inp->inp_lport; 277 sin->sin_addr = inp->inp_laddr; 278 } 279 280 in_setpeeraddr(inp, nam) 281 struct inpcb *inp; 282 struct mbuf *nam; 283 { 284 register struct sockaddr_in *sin; 285 286 nam->m_len = sizeof (*sin); 287 sin = mtod(nam, struct sockaddr_in *); 288 (void) memset((caddr_t)sin, 0, sizeof (*sin)); 289 sin->sin_family = AF_INET; 290 sin->sin_len = sizeof(*sin); 291 sin->sin_port = inp->inp_fport; 292 sin->sin_addr = inp->inp_faddr; 293 } 294 295 /* 296 * Pass some notification to all connections of a protocol 297 * associated with address dst. The local address and/or port numbers 298 * may be specified to limit the search. The "usual action" will be 299 * taken, depending on the ctlinput cmd. The caller must filter any 300 * cmds that are uninteresting (e.g., no error in the map). 301 * Call the protocol specific routine (if any) to report 302 * any errors for each matching socket. 303 * 304 * Must be called at splnet. 305 */ 306 in_pcbnotify(head, dst, fport, laddr, lport, cmd, notify) 307 struct inpcb *head; 308 struct sockaddr *dst; 309 u_short fport, lport; 310 struct in_addr laddr; 311 int cmd, (*notify)(); 312 { 313 register struct inpcb *inp, *oinp; 314 struct in_addr faddr; 315 int errno; 316 int in_rtchange(); 317 extern u_char inetctlerrmap[]; 318 319 if ((unsigned)cmd > PRC_NCMDS || dst->sa_family != AF_INET) 320 return; 321 faddr = ((struct sockaddr_in *)dst)->sin_addr; 322 if (faddr.s_addr == INADDR_ANY) 323 return; 324 325 /* 326 * Redirects go to all references to the destination, 327 * and use in_rtchange to invalidate the route cache. 328 * Dead host indications: notify all references to the destination. 329 * Otherwise, if we have knowledge of the local port and address, 330 * deliver only to that socket. 331 */ 332 if (PRC_IS_REDIRECT(cmd) || cmd == PRC_HOSTDEAD) { 333 fport = 0; 334 lport = 0; 335 laddr.s_addr = 0; 336 if (cmd != PRC_HOSTDEAD) 337 notify = in_rtchange; 338 } 339 errno = inetctlerrmap[cmd]; 340 for (inp = head->inp_next; inp != head;) { 341 if (inp->inp_faddr.s_addr != faddr.s_addr || 342 inp->inp_socket == 0 || 343 (lport && inp->inp_lport != lport) || 344 (laddr.s_addr && inp->inp_laddr.s_addr != laddr.s_addr) || 345 (fport && inp->inp_fport != fport)) { 346 inp = inp->inp_next; 347 continue; 348 } 349 oinp = inp; 350 inp = inp->inp_next; 351 if (notify) 352 (*notify)(oinp, errno); 353 } 354 } 355 356 /* 357 * Check for alternatives when higher level complains 358 * about service problems. For now, invalidate cached 359 * routing information. If the route was created dynamically 360 * (by a redirect), time to try a default gateway again. 361 */ 362 in_losing(inp) 363 struct inpcb *inp; 364 { 365 register struct rtentry *rt; 366 367 if ((rt = inp->inp_route.ro_rt)) { 368 RTMISSMSG(RTM_LOSING, &inp->inp_route.ro_dst, 369 rt->rt_gateway, (struct sockaddr *)rt_mask(rt), 370 (struct sockaddr *)0, rt->rt_flags, 0); 371 if (rt->rt_flags & RTF_DYNAMIC) 372 (void) RTREQUEST(RTM_DELETE, rt_key(rt), 373 rt->rt_gateway, rt_mask(rt), rt->rt_flags, 374 (struct rtentry **)0); 375 inp->inp_route.ro_rt = 0; 376 RTFREE(rt); 377 /* 378 * A new route can be allocated 379 * the next time output is attempted. 380 */ 381 } 382 } 383 384 /* 385 * After a routing change, flush old routing 386 * and allocate a (hopefully) better one. 387 */ 388 in_rtchange(inp) 389 register struct inpcb *inp; 390 { 391 if (inp->inp_route.ro_rt) { 392 RTFREE(inp->inp_route.ro_rt); 393 inp->inp_route.ro_rt = 0; 394 /* 395 * A new route can be allocated the next time 396 * output is attempted. 397 */ 398 } 399 } 400 401 struct inpcb * 402 in_pcblookup(head, faddr, fport, laddr, lport, flags) 403 struct inpcb *head; 404 struct in_addr faddr, laddr; 405 u_short fport, lport; 406 int flags; 407 { 408 register struct inpcb *inp, *match = 0; 409 int matchwild = 3, wildcard; 410 411 for (inp = head->inp_next; inp != head; inp = inp->inp_next) { 412 if (inp->inp_lport != lport) 413 continue; 414 wildcard = 0; 415 if (inp->inp_laddr.s_addr != INADDR_ANY) { 416 if (laddr.s_addr == INADDR_ANY) 417 wildcard++; 418 else if (inp->inp_laddr.s_addr != laddr.s_addr) 419 continue; 420 } else { 421 if (laddr.s_addr != INADDR_ANY) 422 wildcard++; 423 } 424 if (inp->inp_faddr.s_addr != INADDR_ANY) { 425 if (faddr.s_addr == INADDR_ANY) 426 wildcard++; 427 else if (inp->inp_faddr.s_addr != faddr.s_addr || 428 inp->inp_fport != fport) 429 continue; 430 } else { 431 if (faddr.s_addr != INADDR_ANY) 432 wildcard++; 433 } 434 if (wildcard && (flags & INPLOOKUP_WILDCARD) == 0) 435 continue; 436 if (wildcard < matchwild) { 437 match = inp; 438 matchwild = wildcard; 439 if (matchwild == 0) 440 break; 441 } 442 } 443 return (match); 444 } 445