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