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.15 (Berkeley) 10/02/91 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 for (ia = in_ifaddr; ia; ia = ia->ia_next) 177 if (ia->ia_ifp == ifp) 178 break; 179 if (ia == 0) { 180 int fport = sin->sin_port; 181 182 sin->sin_port = 0; 183 ia = (struct in_ifaddr *) 184 ifa_ifwithdstaddr((struct sockaddr *)sin); 185 sin->sin_port = fport; 186 if (ia == 0) 187 ia = in_iaonnetof(in_netof(sin->sin_addr)); 188 if (ia == 0) 189 ia = in_ifaddr; 190 if (ia == 0) 191 return (EADDRNOTAVAIL); 192 } 193 ifaddr = (struct sockaddr_in *)&ia->ia_addr; 194 } 195 if (in_pcblookup(inp->inp_head, 196 sin->sin_addr, 197 sin->sin_port, 198 inp->inp_laddr.s_addr ? inp->inp_laddr : ifaddr->sin_addr, 199 inp->inp_lport, 200 0)) 201 return (EADDRINUSE); 202 if (inp->inp_laddr.s_addr == INADDR_ANY) { 203 if (inp->inp_lport == 0) 204 (void)in_pcbbind(inp, (struct mbuf *)0); 205 inp->inp_laddr = ifaddr->sin_addr; 206 } 207 inp->inp_faddr = sin->sin_addr; 208 inp->inp_fport = sin->sin_port; 209 return (0); 210 } 211 212 in_pcbdisconnect(inp) 213 struct inpcb *inp; 214 { 215 216 inp->inp_faddr.s_addr = INADDR_ANY; 217 inp->inp_fport = 0; 218 if (inp->inp_socket->so_state & SS_NOFDREF) 219 in_pcbdetach(inp); 220 } 221 222 in_pcbdetach(inp) 223 struct inpcb *inp; 224 { 225 struct socket *so = inp->inp_socket; 226 227 so->so_pcb = 0; 228 sofree(so); 229 if (inp->inp_options) 230 (void)m_free(inp->inp_options); 231 if (inp->inp_route.ro_rt) 232 rtfree(inp->inp_route.ro_rt); 233 remque(inp); 234 (void) m_free(dtom(inp)); 235 } 236 237 in_setsockaddr(inp, nam) 238 register struct inpcb *inp; 239 struct mbuf *nam; 240 { 241 register struct sockaddr_in *sin; 242 243 nam->m_len = sizeof (*sin); 244 sin = mtod(nam, struct sockaddr_in *); 245 bzero((caddr_t)sin, sizeof (*sin)); 246 sin->sin_family = AF_INET; 247 sin->sin_len = sizeof(*sin); 248 sin->sin_port = inp->inp_lport; 249 sin->sin_addr = inp->inp_laddr; 250 } 251 252 in_setpeeraddr(inp, nam) 253 struct inpcb *inp; 254 struct mbuf *nam; 255 { 256 register struct sockaddr_in *sin; 257 258 nam->m_len = sizeof (*sin); 259 sin = mtod(nam, struct sockaddr_in *); 260 bzero((caddr_t)sin, sizeof (*sin)); 261 sin->sin_family = AF_INET; 262 sin->sin_len = sizeof(*sin); 263 sin->sin_port = inp->inp_fport; 264 sin->sin_addr = inp->inp_faddr; 265 } 266 267 /* 268 * Pass some notification to all connections of a protocol 269 * associated with address dst. The local address and/or port numbers 270 * may be specified to limit the search. The "usual action" will be 271 * taken, depending on the ctlinput cmd. The caller must filter any 272 * cmds that are uninteresting (e.g., no error in the map). 273 * Call the protocol specific routine (if any) to report 274 * any errors for each matching socket. 275 * 276 * Must be called at splnet. 277 */ 278 in_pcbnotify(head, dst, fport, laddr, lport, cmd, notify) 279 struct inpcb *head; 280 struct sockaddr *dst; 281 u_short fport, lport; 282 struct in_addr laddr; 283 int cmd, (*notify)(); 284 { 285 register struct inpcb *inp, *oinp; 286 struct in_addr faddr; 287 int errno; 288 int in_rtchange(); 289 extern u_char inetctlerrmap[]; 290 291 if ((unsigned)cmd > PRC_NCMDS || dst->sa_family != AF_INET) 292 return; 293 faddr = ((struct sockaddr_in *)dst)->sin_addr; 294 if (faddr.s_addr == INADDR_ANY) 295 return; 296 297 /* 298 * Redirects go to all references to the destination, 299 * and use in_rtchange to invalidate the route cache. 300 * Dead host indications: notify all references to the destination. 301 * Otherwise, if we have knowledge of the local port and address, 302 * deliver only to that socket. 303 */ 304 if (PRC_IS_REDIRECT(cmd) || cmd == PRC_HOSTDEAD) { 305 fport = 0; 306 lport = 0; 307 laddr.s_addr = 0; 308 if (cmd != PRC_HOSTDEAD) 309 notify = in_rtchange; 310 } 311 errno = inetctlerrmap[cmd]; 312 for (inp = head->inp_next; inp != head;) { 313 if (inp->inp_faddr.s_addr != faddr.s_addr || 314 inp->inp_socket == 0 || 315 (lport && inp->inp_lport != lport) || 316 (laddr.s_addr && inp->inp_laddr.s_addr != laddr.s_addr) || 317 (fport && inp->inp_fport != fport)) { 318 inp = inp->inp_next; 319 continue; 320 } 321 oinp = inp; 322 inp = inp->inp_next; 323 if (notify) 324 (*notify)(oinp, errno); 325 } 326 } 327 328 /* 329 * Check for alternatives when higher level complains 330 * about service problems. For now, invalidate cached 331 * routing information. If the route was created dynamically 332 * (by a redirect), time to try a default gateway again. 333 */ 334 in_losing(inp) 335 struct inpcb *inp; 336 { 337 register struct rtentry *rt; 338 339 if ((rt = inp->inp_route.ro_rt)) { 340 rt_missmsg(RTM_LOSING, &inp->inp_route.ro_dst, 341 rt->rt_gateway, (struct sockaddr *)rt_mask(rt), 342 (struct sockaddr *)0, rt->rt_flags, 0); 343 if (rt->rt_flags & RTF_DYNAMIC) 344 (void) rtrequest(RTM_DELETE, rt_key(rt), 345 rt->rt_gateway, rt_mask(rt), rt->rt_flags, 346 (struct rtentry **)0); 347 inp->inp_route.ro_rt = 0; 348 rtfree(rt); 349 /* 350 * A new route can be allocated 351 * the next time output is attempted. 352 */ 353 } 354 } 355 356 /* 357 * After a routing change, flush old routing 358 * and allocate a (hopefully) better one. 359 */ 360 in_rtchange(inp) 361 register struct inpcb *inp; 362 { 363 if (inp->inp_route.ro_rt) { 364 rtfree(inp->inp_route.ro_rt); 365 inp->inp_route.ro_rt = 0; 366 /* 367 * A new route can be allocated the next time 368 * output is attempted. 369 */ 370 } 371 } 372 373 struct inpcb * 374 in_pcblookup(head, faddr, fport, laddr, lport, flags) 375 struct inpcb *head; 376 struct in_addr faddr, laddr; 377 u_short fport, lport; 378 int flags; 379 { 380 register struct inpcb *inp, *match = 0; 381 int matchwild = 3, wildcard; 382 383 for (inp = head->inp_next; inp != head; inp = inp->inp_next) { 384 if (inp->inp_lport != lport) 385 continue; 386 wildcard = 0; 387 if (inp->inp_laddr.s_addr != INADDR_ANY) { 388 if (laddr.s_addr == INADDR_ANY) 389 wildcard++; 390 else if (inp->inp_laddr.s_addr != laddr.s_addr) 391 continue; 392 } else { 393 if (laddr.s_addr != INADDR_ANY) 394 wildcard++; 395 } 396 if (inp->inp_faddr.s_addr != INADDR_ANY) { 397 if (faddr.s_addr == INADDR_ANY) 398 wildcard++; 399 else if (inp->inp_faddr.s_addr != faddr.s_addr || 400 inp->inp_fport != fport) 401 continue; 402 } else { 403 if (faddr.s_addr != INADDR_ANY) 404 wildcard++; 405 } 406 if (wildcard && (flags & INPLOOKUP_WILDCARD) == 0) 407 continue; 408 if (wildcard < matchwild) { 409 match = inp; 410 matchwild = wildcard; 411 if (matchwild == 0) 412 break; 413 } 414 } 415 return (match); 416 } 417