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