1 /* 2 * Copyright (c) 1982, 1986 Regents of the University of California. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms are permitted 6 * provided that this notice is preserved and that due credit is given 7 * to the University of California at Berkeley. The name of the University 8 * may not be used to endorse or promote products derived from this 9 * software without specific prior written permission. This software 10 * is provided ``as is'' without express or implied warranty. 11 * 12 * @(#)in_pcb.c 7.6 (Berkeley) 12/07/87 13 */ 14 15 #include "param.h" 16 #include "systm.h" 17 #include "dir.h" 18 #include "user.h" 19 #include "mbuf.h" 20 #include "socket.h" 21 #include "socketvar.h" 22 #include "ioctl.h" 23 #include "in.h" 24 #include "in_systm.h" 25 #include "../net/if.h" 26 #include "../net/route.h" 27 #include "in_pcb.h" 28 #include "in_var.h" 29 #include "protosw.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 m = m_getclr(M_DONTWAIT, MT_PCB); 41 if (m == NULL) 42 return (ENOBUFS); 43 inp = mtod(m, struct inpcb *); 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 u_short aport = ntohs(lport); 80 int wild = 0; 81 82 /* GROSS */ 83 if (aport < IPPORT_RESERVED && u.u_uid != 0) 84 return (EACCES); 85 /* even GROSSER, but this is the Internet */ 86 if ((so->so_options & SO_REUSEADDR) == 0 && 87 ((so->so_proto->pr_flags & PR_CONNREQUIRED) == 0 || 88 (so->so_options & SO_ACCEPTCONN) == 0)) 89 wild = INPLOOKUP_WILDCARD; 90 if (in_pcblookup(head, 91 zeroin_addr, 0, sin->sin_addr, lport, wild)) 92 return (EADDRINUSE); 93 } 94 inp->inp_laddr = sin->sin_addr; 95 noname: 96 if (lport == 0) 97 do { 98 if (head->inp_lport++ < IPPORT_RESERVED || 99 head->inp_lport > IPPORT_USERRESERVED) 100 head->inp_lport = IPPORT_RESERVED; 101 lport = htons(head->inp_lport); 102 } while (in_pcblookup(head, 103 zeroin_addr, 0, inp->inp_laddr, lport, 0)); 104 inp->inp_lport = lport; 105 return (0); 106 } 107 108 /* 109 * Connect from a socket to a specified address. 110 * Both address and port must be specified in argument sin. 111 * If don't have a local address for this socket yet, 112 * then pick one. 113 */ 114 in_pcbconnect(inp, nam) 115 register struct inpcb *inp; 116 struct mbuf *nam; 117 { 118 struct in_ifaddr *ia; 119 struct sockaddr_in *ifaddr; 120 register struct sockaddr_in *sin = mtod(nam, struct sockaddr_in *); 121 122 if (nam->m_len != sizeof (*sin)) 123 return (EINVAL); 124 if (sin->sin_family != AF_INET) 125 return (EAFNOSUPPORT); 126 if (sin->sin_port == 0) 127 return (EADDRNOTAVAIL); 128 if (in_ifaddr) { 129 /* 130 * If the destination address is INADDR_ANY, 131 * use the primary local address. 132 * If the supplied address is INADDR_BROADCAST, 133 * and the primary interface supports broadcast, 134 * choose the broadcast address for that interface. 135 */ 136 #define satosin(sa) ((struct sockaddr_in *)(sa)) 137 if (sin->sin_addr.s_addr == INADDR_ANY) 138 sin->sin_addr = IA_SIN(in_ifaddr)->sin_addr; 139 else if (sin->sin_addr.s_addr == (u_long)INADDR_BROADCAST && 140 (in_ifaddr->ia_ifp->if_flags & IFF_BROADCAST)) 141 sin->sin_addr = satosin(&in_ifaddr->ia_broadaddr)->sin_addr; 142 } 143 if (inp->inp_laddr.s_addr == INADDR_ANY) { 144 register struct route *ro; 145 struct ifnet *ifp; 146 147 ia = (struct in_ifaddr *)0; 148 /* 149 * If route is known or can be allocated now, 150 * our src addr is taken from the i/f, else punt. 151 */ 152 ro = &inp->inp_route; 153 if (ro->ro_rt && 154 (satosin(&ro->ro_dst)->sin_addr.s_addr != 155 sin->sin_addr.s_addr || 156 inp->inp_socket->so_options & SO_DONTROUTE)) { 157 RTFREE(ro->ro_rt); 158 ro->ro_rt = (struct rtentry *)0; 159 } 160 if ((inp->inp_socket->so_options & SO_DONTROUTE) == 0 && /*XXX*/ 161 (ro->ro_rt == (struct rtentry *)0 || 162 ro->ro_rt->rt_ifp == (struct ifnet *)0)) { 163 /* No route yet, so try to acquire one */ 164 ro->ro_dst.sa_family = AF_INET; 165 ((struct sockaddr_in *) &ro->ro_dst)->sin_addr = 166 sin->sin_addr; 167 rtalloc(ro); 168 } 169 /* 170 * If we found a route, use the address 171 * corresponding to the outgoing interface 172 * unless it is the loopback (in case a route 173 * to our address on another net goes to loopback). 174 */ 175 if (ro->ro_rt && (ifp = ro->ro_rt->rt_ifp) && 176 (ifp->if_flags & IFF_LOOPBACK) == 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_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_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. Call the protocol specific 269 * routine (if any) to handle each connection. 270 */ 271 in_pcbnotify(head, dst, errno, notify) 272 struct inpcb *head; 273 register struct in_addr *dst; 274 int errno, (*notify)(); 275 { 276 register struct inpcb *inp, *oinp; 277 int s = splimp(); 278 279 for (inp = head->inp_next; inp != head;) { 280 if (inp->inp_faddr.s_addr != dst->s_addr || 281 inp->inp_socket == 0) { 282 inp = inp->inp_next; 283 continue; 284 } 285 if (errno) 286 inp->inp_socket->so_error = errno; 287 oinp = inp; 288 inp = inp->inp_next; 289 if (notify) 290 (*notify)(oinp); 291 } 292 splx(s); 293 } 294 295 /* 296 * Check for alternatives when higher level complains 297 * about service problems. For now, invalidate cached 298 * routing information. If the route was created dynamically 299 * (by a redirect), time to try a default gateway again. 300 */ 301 in_losing(inp) 302 struct inpcb *inp; 303 { 304 register struct rtentry *rt; 305 306 if ((rt = inp->inp_route.ro_rt)) { 307 if (rt->rt_flags & RTF_DYNAMIC) 308 (void) rtrequest((int)SIOCDELRT, rt); 309 rtfree(rt); 310 inp->inp_route.ro_rt = 0; 311 /* 312 * A new route can be allocated 313 * the next time output is attempted. 314 */ 315 } 316 } 317 318 /* 319 * After a routing change, flush old routing 320 * and allocate a (hopefully) better one. 321 */ 322 in_rtchange(inp) 323 register struct inpcb *inp; 324 { 325 if (inp->inp_route.ro_rt) { 326 rtfree(inp->inp_route.ro_rt); 327 inp->inp_route.ro_rt = 0; 328 /* 329 * A new route can be allocated the next time 330 * output is attempted. 331 */ 332 } 333 } 334 335 struct inpcb * 336 in_pcblookup(head, faddr, fport, laddr, lport, flags) 337 struct inpcb *head; 338 struct in_addr faddr, laddr; 339 u_short fport, lport; 340 int flags; 341 { 342 register struct inpcb *inp, *match = 0; 343 int matchwild = 3, wildcard; 344 345 for (inp = head->inp_next; inp != head; inp = inp->inp_next) { 346 if (inp->inp_lport != lport) 347 continue; 348 wildcard = 0; 349 if (inp->inp_laddr.s_addr != INADDR_ANY) { 350 if (laddr.s_addr == INADDR_ANY) 351 wildcard++; 352 else if (inp->inp_laddr.s_addr != laddr.s_addr) 353 continue; 354 } else { 355 if (laddr.s_addr != INADDR_ANY) 356 wildcard++; 357 } 358 if (inp->inp_faddr.s_addr != INADDR_ANY) { 359 if (faddr.s_addr == INADDR_ANY) 360 wildcard++; 361 else if (inp->inp_faddr.s_addr != faddr.s_addr || 362 inp->inp_fport != fport) 363 continue; 364 } else { 365 if (faddr.s_addr != INADDR_ANY) 366 wildcard++; 367 } 368 if (wildcard && (flags & INPLOOKUP_WILDCARD) == 0) 369 continue; 370 if (wildcard < matchwild) { 371 match = inp; 372 matchwild = wildcard; 373 if (matchwild == 0) 374 break; 375 } 376 } 377 return (match); 378 } 379