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