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