1 /* 2 * Copyright (c) 1982, 1986, 1991 Regents of the University of California. 3 * All rights reserved. 4 * 5 * %sccs.include.redist.c% 6 * 7 * @(#)in_pcb.c 7.24 (Berkeley) 01/08/93 8 */ 9 10 #include <sys/param.h> 11 #include <sys/systm.h> 12 #include <sys/malloc.h> 13 #include <sys/mbuf.h> 14 #include <sys/protosw.h> 15 #include <sys/socket.h> 16 #include <sys/socketvar.h> 17 #include <sys/ioctl.h> 18 #include <sys/errno.h> 19 20 #include <net/if.h> 21 #include <net/route.h> 22 23 #include <netinet/in.h> 24 #include <netinet/in_systm.h> 25 #include <netinet/ip.h> 26 #include <netinet/in_pcb.h> 27 #include <netinet/in_var.h> 28 29 #include <netinet/ip_var.h> 30 31 struct in_addr zeroin_addr; 32 33 in_pcballoc(so, head) 34 struct socket *so; 35 struct inpcb *head; 36 { 37 struct mbuf *m; 38 register struct inpcb *inp; 39 40 MALLOC(inp, struct inpcb *, sizeof(*inp), M_PCB, M_WAITOK); 41 if (inp == NULL) 42 return (ENOBUFS); 43 bzero((caddr_t)inp, sizeof(*inp)); 44 inp->inp_head = head; 45 inp->inp_socket = so; 46 insque(inp, head); 47 so->so_pcb = (caddr_t)inp; 48 return (0); 49 } 50 51 in_pcbbind(inp, nam) 52 register struct inpcb *inp; 53 struct mbuf *nam; 54 { 55 register struct socket *so = inp->inp_socket; 56 register struct inpcb *head = inp->inp_head; 57 register struct sockaddr_in *sin; 58 u_short lport = 0; 59 60 if (in_ifaddr == 0) 61 return (EADDRNOTAVAIL); 62 if (inp->inp_lport || inp->inp_laddr.s_addr != INADDR_ANY) 63 return (EINVAL); 64 if (nam == 0) 65 goto noname; 66 sin = mtod(nam, struct sockaddr_in *); 67 if (nam->m_len != sizeof (*sin)) 68 return (EINVAL); 69 if (sin->sin_addr.s_addr != INADDR_ANY) { 70 int tport = sin->sin_port; 71 72 sin->sin_port = 0; /* yech... */ 73 if (ifa_ifwithaddr((struct sockaddr *)sin) == 0) 74 return (EADDRNOTAVAIL); 75 sin->sin_port = tport; 76 } 77 lport = sin->sin_port; 78 if (lport) { 79 struct inpcb *t; 80 u_short aport = ntohs(lport); 81 int wild = 0; 82 83 /* GROSS */ 84 if (aport < IPPORT_RESERVED && (so->so_state & SS_PRIV) == 0) 85 return (EACCES); 86 /* even GROSSER, but this is the Internet */ 87 if ((so->so_options & SO_REUSEADDR) == 0 && 88 ((so->so_proto->pr_flags & PR_CONNREQUIRED) == 0 || 89 (so->so_options & SO_ACCEPTCONN) == 0)) 90 wild = INPLOOKUP_WILDCARD; 91 t = in_pcblookup(head, zeroin_addr, 0, 92 sin->sin_addr, lport, wild); 93 if (t && !((so->so_options & t->inp_socket->so_options) & 94 SO_REUSEPORT)) 95 return (EADDRINUSE); 96 } 97 inp->inp_laddr = sin->sin_addr; 98 noname: 99 if (lport == 0) 100 do { 101 if (head->inp_lport++ < IPPORT_RESERVED || 102 head->inp_lport > IPPORT_USERRESERVED) 103 head->inp_lport = IPPORT_RESERVED; 104 lport = htons(head->inp_lport); 105 } while (in_pcblookup(head, 106 zeroin_addr, 0, inp->inp_laddr, lport, 0)); 107 inp->inp_lport = lport; 108 return (0); 109 } 110 111 /* 112 * Connect from a socket to a specified address. 113 * Both address and port must be specified in argument sin. 114 * If don't have a local address for this socket yet, 115 * then pick one. 116 */ 117 in_pcbconnect(inp, nam) 118 register struct inpcb *inp; 119 struct mbuf *nam; 120 { 121 struct in_ifaddr *ia; 122 struct sockaddr_in *ifaddr; 123 register struct sockaddr_in *sin = mtod(nam, struct sockaddr_in *); 124 125 if (nam->m_len != sizeof (*sin)) 126 return (EINVAL); 127 if (sin->sin_family != AF_INET) 128 return (EAFNOSUPPORT); 129 if (sin->sin_port == 0) 130 return (EADDRNOTAVAIL); 131 if (in_ifaddr) { 132 /* 133 * If the destination address is INADDR_ANY, 134 * use the primary local address. 135 * If the supplied address is INADDR_BROADCAST, 136 * and the primary interface supports broadcast, 137 * choose the broadcast address for that interface. 138 */ 139 #define satosin(sa) ((struct sockaddr_in *)(sa)) 140 if (sin->sin_addr.s_addr == INADDR_ANY) 141 sin->sin_addr = IA_SIN(in_ifaddr)->sin_addr; 142 else if (sin->sin_addr.s_addr == (u_long)INADDR_BROADCAST && 143 (in_ifaddr->ia_ifp->if_flags & IFF_BROADCAST)) 144 sin->sin_addr = satosin(&in_ifaddr->ia_broadaddr)->sin_addr; 145 } 146 if (inp->inp_laddr.s_addr == INADDR_ANY) { 147 register struct route *ro; 148 struct ifnet *ifp; 149 150 ia = (struct in_ifaddr *)0; 151 /* 152 * If route is known or can be allocated now, 153 * our src addr is taken from the i/f, else punt. 154 */ 155 ro = &inp->inp_route; 156 if (ro->ro_rt && 157 (satosin(&ro->ro_dst)->sin_addr.s_addr != 158 sin->sin_addr.s_addr || 159 inp->inp_socket->so_options & SO_DONTROUTE)) { 160 RTFREE(ro->ro_rt); 161 ro->ro_rt = (struct rtentry *)0; 162 } 163 if ((inp->inp_socket->so_options & SO_DONTROUTE) == 0 && /*XXX*/ 164 (ro->ro_rt == (struct rtentry *)0 || 165 ro->ro_rt->rt_ifp == (struct ifnet *)0)) { 166 /* No route yet, so try to acquire one */ 167 ro->ro_dst.sa_family = AF_INET; 168 ro->ro_dst.sa_len = sizeof(struct sockaddr_in); 169 ((struct sockaddr_in *) &ro->ro_dst)->sin_addr = 170 sin->sin_addr; 171 rtalloc(ro); 172 } 173 /* 174 * If we found a route, use the address 175 * corresponding to the outgoing interface 176 * unless it is the loopback (in case a route 177 * to our address on another net goes to loopback). 178 */ 179 if (ro->ro_rt && (ifp = ro->ro_rt->rt_ifp) && 180 (ifp->if_flags & IFF_LOOPBACK) == 0 && 181 (ia = (struct in_ifaddr *)ro->ro_rt->rt_ifa) == 0) 182 for (ia = in_ifaddr; ia; ia = ia->ia_next) 183 if (ia->ia_ifp == ifp) 184 break; 185 if (ia == 0) { 186 int fport = sin->sin_port; 187 188 sin->sin_port = 0; 189 ia = (struct in_ifaddr *) 190 ifa_ifwithdstaddr((struct sockaddr *)sin); 191 sin->sin_port = fport; 192 if (ia == 0) 193 ia = in_iaonnetof(in_netof(sin->sin_addr)); 194 if (ia == 0) 195 ia = in_ifaddr; 196 if (ia == 0) 197 return (EADDRNOTAVAIL); 198 } 199 /* 200 * If the destination address is multicast and an outgoing 201 * interface has been set as a multicast option, use the 202 * address of that interface as our source address. 203 */ 204 if (IN_MULTICAST(ntohl(sin->sin_addr.s_addr)) && 205 inp->inp_moptions != NULL) { 206 struct ip_moptions *imo; 207 208 imo = inp->inp_moptions; 209 if (imo->imo_multicast_ifp != NULL) { 210 ifp = imo->imo_multicast_ifp; 211 for (ia = in_ifaddr; ia; ia = ia->ia_next) 212 if (ia->ia_ifp == ifp) 213 break; 214 if (ia == 0) 215 return (EADDRNOTAVAIL); 216 } 217 } 218 ifaddr = (struct sockaddr_in *)&ia->ia_addr; 219 } 220 if (in_pcblookup(inp->inp_head, 221 sin->sin_addr, 222 sin->sin_port, 223 inp->inp_laddr.s_addr ? inp->inp_laddr : ifaddr->sin_addr, 224 inp->inp_lport, 225 0)) 226 return (EADDRINUSE); 227 if (inp->inp_laddr.s_addr == INADDR_ANY) { 228 if (inp->inp_lport == 0) 229 (void)in_pcbbind(inp, (struct mbuf *)0); 230 inp->inp_laddr = ifaddr->sin_addr; 231 } 232 inp->inp_faddr = sin->sin_addr; 233 inp->inp_fport = sin->sin_port; 234 return (0); 235 } 236 237 in_pcbdisconnect(inp) 238 struct inpcb *inp; 239 { 240 241 inp->inp_faddr.s_addr = INADDR_ANY; 242 inp->inp_fport = 0; 243 if (inp->inp_socket->so_state & SS_NOFDREF) 244 in_pcbdetach(inp); 245 } 246 247 in_pcbdetach(inp) 248 struct inpcb *inp; 249 { 250 struct socket *so = inp->inp_socket; 251 252 so->so_pcb = 0; 253 sofree(so); 254 if (inp->inp_options) 255 (void)m_free(inp->inp_options); 256 if (inp->inp_route.ro_rt) 257 rtfree(inp->inp_route.ro_rt); 258 ip_freemoptions(inp->inp_moptions); 259 remque(inp); 260 FREE(inp, M_PCB); 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 struct rt_addrinfo info; 365 366 if ((rt = inp->inp_route.ro_rt)) { 367 inp->inp_route.ro_rt = 0; 368 bzero((caddr_t)&info, sizeof(info)); 369 info.rti_info[RTAX_DST] = 370 (struct sockaddr *)&inp->inp_route.ro_dst; 371 info.rti_info[RTAX_GATEWAY] = rt->rt_gateway; 372 info.rti_info[RTAX_NETMASK] = rt_mask(rt); 373 rt_missmsg(RTM_LOSING, &info, rt->rt_flags, 0); 374 if (rt->rt_flags & RTF_DYNAMIC) 375 (void) rtrequest(RTM_DELETE, rt_key(rt), 376 rt->rt_gateway, rt_mask(rt), rt->rt_flags, 377 (struct rtentry **)0); 378 else 379 /* 380 * A new route can be allocated 381 * the next time output is attempted. 382 */ 383 rtfree(rt); 384 } 385 } 386 387 /* 388 * After a routing change, flush old routing 389 * and allocate a (hopefully) better one. 390 */ 391 in_rtchange(inp) 392 register struct inpcb *inp; 393 { 394 if (inp->inp_route.ro_rt) { 395 rtfree(inp->inp_route.ro_rt); 396 inp->inp_route.ro_rt = 0; 397 /* 398 * A new route can be allocated the next time 399 * output is attempted. 400 */ 401 } 402 } 403 404 struct inpcb * 405 in_pcblookup(head, faddr, fport, laddr, lport, flags) 406 struct inpcb *head; 407 struct in_addr faddr, laddr; 408 u_short fport, lport; 409 int flags; 410 { 411 register struct inpcb *inp, *match = 0; 412 int matchwild = 3, wildcard; 413 414 for (inp = head->inp_next; inp != head; inp = inp->inp_next) { 415 if (inp->inp_lport != lport) 416 continue; 417 wildcard = 0; 418 if (inp->inp_laddr.s_addr != INADDR_ANY) { 419 if (laddr.s_addr == INADDR_ANY) 420 wildcard++; 421 else if (inp->inp_laddr.s_addr != laddr.s_addr) 422 continue; 423 } else { 424 if (laddr.s_addr != INADDR_ANY) 425 wildcard++; 426 } 427 if (inp->inp_faddr.s_addr != INADDR_ANY) { 428 if (faddr.s_addr == INADDR_ANY) 429 wildcard++; 430 else if (inp->inp_faddr.s_addr != faddr.s_addr || 431 inp->inp_fport != fport) 432 continue; 433 } else { 434 if (faddr.s_addr != INADDR_ANY) 435 wildcard++; 436 } 437 if (wildcard && (flags & INPLOOKUP_WILDCARD) == 0) 438 continue; 439 if (wildcard < matchwild) { 440 match = inp; 441 matchwild = wildcard; 442 if (matchwild == 0) 443 break; 444 } 445 } 446 return (match); 447 } 448