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