in_pcb.c revision 1.1.1.2 1 /*
2 * Copyright (c) 1982, 1986, 1991, 1993
3 * The Regents of the University of California. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by the University of
16 * California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 *
33 * @(#)in_pcb.c 8.2 (Berkeley) 1/4/94
34 */
35
36 #include <sys/param.h>
37 #include <sys/systm.h>
38 #include <sys/malloc.h>
39 #include <sys/mbuf.h>
40 #include <sys/protosw.h>
41 #include <sys/socket.h>
42 #include <sys/socketvar.h>
43 #include <sys/ioctl.h>
44 #include <sys/errno.h>
45 #include <sys/time.h>
46 #include <sys/proc.h>
47
48 #include <net/if.h>
49 #include <net/route.h>
50
51 #include <netinet/in.h>
52 #include <netinet/in_systm.h>
53 #include <netinet/ip.h>
54 #include <netinet/in_pcb.h>
55 #include <netinet/in_var.h>
56 #include <netinet/ip_var.h>
57
58 struct in_addr zeroin_addr;
59
60 int
61 in_pcballoc(so, head)
62 struct socket *so;
63 struct inpcb *head;
64 {
65 register struct inpcb *inp;
66
67 MALLOC(inp, struct inpcb *, sizeof(*inp), M_PCB, M_WAITOK);
68 if (inp == NULL)
69 return (ENOBUFS);
70 bzero((caddr_t)inp, sizeof(*inp));
71 inp->inp_head = head;
72 inp->inp_socket = so;
73 insque(inp, head);
74 so->so_pcb = (caddr_t)inp;
75 return (0);
76 }
77
78 int
79 in_pcbbind(inp, nam)
80 register struct inpcb *inp;
81 struct mbuf *nam;
82 {
83 register struct socket *so = inp->inp_socket;
84 register struct inpcb *head = inp->inp_head;
85 register struct sockaddr_in *sin;
86 struct proc *p = curproc; /* XXX */
87 u_short lport = 0;
88 int wild = 0, reuseport = (so->so_options & SO_REUSEPORT);
89 int error;
90
91 if (in_ifaddr == 0)
92 return (EADDRNOTAVAIL);
93 if (inp->inp_lport || inp->inp_laddr.s_addr != INADDR_ANY)
94 return (EINVAL);
95 if ((so->so_options & (SO_REUSEADDR|SO_REUSEPORT)) == 0 &&
96 ((so->so_proto->pr_flags & PR_CONNREQUIRED) == 0 ||
97 (so->so_options & SO_ACCEPTCONN) == 0))
98 wild = INPLOOKUP_WILDCARD;
99 if (nam) {
100 sin = mtod(nam, struct sockaddr_in *);
101 if (nam->m_len != sizeof (*sin))
102 return (EINVAL);
103 #ifdef notdef
104 /*
105 * We should check the family, but old programs
106 * incorrectly fail to initialize it.
107 */
108 if (sin->sin_family != AF_INET)
109 return (EAFNOSUPPORT);
110 #endif
111 lport = sin->sin_port;
112 if (IN_MULTICAST(ntohl(sin->sin_addr.s_addr))) {
113 /*
114 * Treat SO_REUSEADDR as SO_REUSEPORT for multicast;
115 * allow complete duplication of binding if
116 * SO_REUSEPORT is set, or if SO_REUSEADDR is set
117 * and a multicast address is bound on both
118 * new and duplicated sockets.
119 */
120 if (so->so_options & SO_REUSEADDR)
121 reuseport = SO_REUSEADDR|SO_REUSEPORT;
122 } else if (sin->sin_addr.s_addr != INADDR_ANY) {
123 sin->sin_port = 0; /* yech... */
124 if (ifa_ifwithaddr((struct sockaddr *)sin) == 0)
125 return (EADDRNOTAVAIL);
126 }
127 if (lport) {
128 struct inpcb *t;
129
130 /* GROSS */
131 if (ntohs(lport) < IPPORT_RESERVED &&
132 (error = suser(p->p_ucred, &p->p_acflag)))
133 return (error);
134 t = in_pcblookup(head, zeroin_addr, 0,
135 sin->sin_addr, lport, wild);
136 if (t && (reuseport & t->inp_socket->so_options) == 0)
137 return (EADDRINUSE);
138 }
139 inp->inp_laddr = sin->sin_addr;
140 }
141 if (lport == 0)
142 do {
143 if (head->inp_lport++ < IPPORT_RESERVED ||
144 head->inp_lport > IPPORT_USERRESERVED)
145 head->inp_lport = IPPORT_RESERVED;
146 lport = htons(head->inp_lport);
147 } while (in_pcblookup(head,
148 zeroin_addr, 0, inp->inp_laddr, lport, wild));
149 inp->inp_lport = lport;
150 return (0);
151 }
152
153 /*
154 * Connect from a socket to a specified address.
155 * Both address and port must be specified in argument sin.
156 * If don't have a local address for this socket yet,
157 * then pick one.
158 */
159 int
160 in_pcbconnect(inp, nam)
161 register struct inpcb *inp;
162 struct mbuf *nam;
163 {
164 struct in_ifaddr *ia;
165 struct sockaddr_in *ifaddr;
166 register struct sockaddr_in *sin = mtod(nam, struct sockaddr_in *);
167
168 if (nam->m_len != sizeof (*sin))
169 return (EINVAL);
170 if (sin->sin_family != AF_INET)
171 return (EAFNOSUPPORT);
172 if (sin->sin_port == 0)
173 return (EADDRNOTAVAIL);
174 if (in_ifaddr) {
175 /*
176 * If the destination address is INADDR_ANY,
177 * use the primary local address.
178 * If the supplied address is INADDR_BROADCAST,
179 * and the primary interface supports broadcast,
180 * choose the broadcast address for that interface.
181 */
182 #define satosin(sa) ((struct sockaddr_in *)(sa))
183 #define sintosa(sin) ((struct sockaddr *)(sin))
184 #define ifatoia(ifa) ((struct in_ifaddr *)(ifa))
185 if (sin->sin_addr.s_addr == INADDR_ANY)
186 sin->sin_addr = IA_SIN(in_ifaddr)->sin_addr;
187 else if (sin->sin_addr.s_addr == (u_long)INADDR_BROADCAST &&
188 (in_ifaddr->ia_ifp->if_flags & IFF_BROADCAST))
189 sin->sin_addr = satosin(&in_ifaddr->ia_broadaddr)->sin_addr;
190 }
191 if (inp->inp_laddr.s_addr == INADDR_ANY) {
192 register struct route *ro;
193
194 ia = (struct in_ifaddr *)0;
195 /*
196 * If route is known or can be allocated now,
197 * our src addr is taken from the i/f, else punt.
198 */
199 ro = &inp->inp_route;
200 if (ro->ro_rt &&
201 (satosin(&ro->ro_dst)->sin_addr.s_addr !=
202 sin->sin_addr.s_addr ||
203 inp->inp_socket->so_options & SO_DONTROUTE)) {
204 RTFREE(ro->ro_rt);
205 ro->ro_rt = (struct rtentry *)0;
206 }
207 if ((inp->inp_socket->so_options & SO_DONTROUTE) == 0 && /*XXX*/
208 (ro->ro_rt == (struct rtentry *)0 ||
209 ro->ro_rt->rt_ifp == (struct ifnet *)0)) {
210 /* No route yet, so try to acquire one */
211 ro->ro_dst.sa_family = AF_INET;
212 ro->ro_dst.sa_len = sizeof(struct sockaddr_in);
213 ((struct sockaddr_in *) &ro->ro_dst)->sin_addr =
214 sin->sin_addr;
215 rtalloc(ro);
216 }
217 /*
218 * If we found a route, use the address
219 * corresponding to the outgoing interface
220 * unless it is the loopback (in case a route
221 * to our address on another net goes to loopback).
222 */
223 if (ro->ro_rt && !(ro->ro_rt->rt_ifp->if_flags & IFF_LOOPBACK))
224 ia = ifatoia(ro->ro_rt->rt_ifa);
225 if (ia == 0) {
226 u_short fport = sin->sin_port;
227
228 sin->sin_port = 0;
229 ia = ifatoia(ifa_ifwithdstaddr(sintosa(sin)));
230 if (ia == 0)
231 ia = ifatoia(ifa_ifwithnet(sintosa(sin)));
232 sin->sin_port = fport;
233 if (ia == 0)
234 ia = in_ifaddr;
235 if (ia == 0)
236 return (EADDRNOTAVAIL);
237 }
238 /*
239 * If the destination address is multicast and an outgoing
240 * interface has been set as a multicast option, use the
241 * address of that interface as our source address.
242 */
243 if (IN_MULTICAST(ntohl(sin->sin_addr.s_addr)) &&
244 inp->inp_moptions != NULL) {
245 struct ip_moptions *imo;
246 struct ifnet *ifp;
247
248 imo = inp->inp_moptions;
249 if (imo->imo_multicast_ifp != NULL) {
250 ifp = imo->imo_multicast_ifp;
251 for (ia = in_ifaddr; ia; ia = ia->ia_next)
252 if (ia->ia_ifp == ifp)
253 break;
254 if (ia == 0)
255 return (EADDRNOTAVAIL);
256 }
257 }
258 ifaddr = (struct sockaddr_in *)&ia->ia_addr;
259 }
260 if (in_pcblookup(inp->inp_head,
261 sin->sin_addr,
262 sin->sin_port,
263 inp->inp_laddr.s_addr ? inp->inp_laddr : ifaddr->sin_addr,
264 inp->inp_lport,
265 0))
266 return (EADDRINUSE);
267 if (inp->inp_laddr.s_addr == INADDR_ANY) {
268 if (inp->inp_lport == 0)
269 (void)in_pcbbind(inp, (struct mbuf *)0);
270 inp->inp_laddr = ifaddr->sin_addr;
271 }
272 inp->inp_faddr = sin->sin_addr;
273 inp->inp_fport = sin->sin_port;
274 return (0);
275 }
276
277 int
278 in_pcbdisconnect(inp)
279 struct inpcb *inp;
280 {
281
282 inp->inp_faddr.s_addr = INADDR_ANY;
283 inp->inp_fport = 0;
284 if (inp->inp_socket->so_state & SS_NOFDREF)
285 in_pcbdetach(inp);
286 }
287
288 int
289 in_pcbdetach(inp)
290 struct inpcb *inp;
291 {
292 struct socket *so = inp->inp_socket;
293
294 so->so_pcb = 0;
295 sofree(so);
296 if (inp->inp_options)
297 (void)m_free(inp->inp_options);
298 if (inp->inp_route.ro_rt)
299 rtfree(inp->inp_route.ro_rt);
300 ip_freemoptions(inp->inp_moptions);
301 remque(inp);
302 FREE(inp, M_PCB);
303 }
304
305 int
306 in_setsockaddr(inp, nam)
307 register struct inpcb *inp;
308 struct mbuf *nam;
309 {
310 register struct sockaddr_in *sin;
311
312 nam->m_len = sizeof (*sin);
313 sin = mtod(nam, struct sockaddr_in *);
314 bzero((caddr_t)sin, sizeof (*sin));
315 sin->sin_family = AF_INET;
316 sin->sin_len = sizeof(*sin);
317 sin->sin_port = inp->inp_lport;
318 sin->sin_addr = inp->inp_laddr;
319 }
320
321 int
322 in_setpeeraddr(inp, nam)
323 struct inpcb *inp;
324 struct mbuf *nam;
325 {
326 register struct sockaddr_in *sin;
327
328 nam->m_len = sizeof (*sin);
329 sin = mtod(nam, struct sockaddr_in *);
330 bzero((caddr_t)sin, sizeof (*sin));
331 sin->sin_family = AF_INET;
332 sin->sin_len = sizeof(*sin);
333 sin->sin_port = inp->inp_fport;
334 sin->sin_addr = inp->inp_faddr;
335 }
336
337 /*
338 * Pass some notification to all connections of a protocol
339 * associated with address dst. The local address and/or port numbers
340 * may be specified to limit the search. The "usual action" will be
341 * taken, depending on the ctlinput cmd. The caller must filter any
342 * cmds that are uninteresting (e.g., no error in the map).
343 * Call the protocol specific routine (if any) to report
344 * any errors for each matching socket.
345 *
346 * Must be called at splnet.
347 */
348 int
349 in_pcbnotify(head, dst, fport_arg, laddr, lport_arg, cmd, notify)
350 struct inpcb *head;
351 struct sockaddr *dst;
352 u_int fport_arg, lport_arg;
353 struct in_addr laddr;
354 int cmd;
355 void (*notify) __P((struct inpcb *, int));
356 {
357 extern u_char inetctlerrmap[];
358 register struct inpcb *inp, *oinp;
359 struct in_addr faddr;
360 u_short fport = fport_arg, lport = lport_arg;
361 int errno;
362
363 if ((unsigned)cmd > PRC_NCMDS || dst->sa_family != AF_INET)
364 return;
365 faddr = ((struct sockaddr_in *)dst)->sin_addr;
366 if (faddr.s_addr == INADDR_ANY)
367 return;
368
369 /*
370 * Redirects go to all references to the destination,
371 * and use in_rtchange to invalidate the route cache.
372 * Dead host indications: notify all references to the destination.
373 * Otherwise, if we have knowledge of the local port and address,
374 * deliver only to that socket.
375 */
376 if (PRC_IS_REDIRECT(cmd) || cmd == PRC_HOSTDEAD) {
377 fport = 0;
378 lport = 0;
379 laddr.s_addr = 0;
380 if (cmd != PRC_HOSTDEAD)
381 notify = in_rtchange;
382 }
383 errno = inetctlerrmap[cmd];
384 for (inp = head->inp_next; inp != head;) {
385 if (inp->inp_faddr.s_addr != faddr.s_addr ||
386 inp->inp_socket == 0 ||
387 (lport && inp->inp_lport != lport) ||
388 (laddr.s_addr && inp->inp_laddr.s_addr != laddr.s_addr) ||
389 (fport && inp->inp_fport != fport)) {
390 inp = inp->inp_next;
391 continue;
392 }
393 oinp = inp;
394 inp = inp->inp_next;
395 if (notify)
396 (*notify)(oinp, errno);
397 }
398 }
399
400 /*
401 * Check for alternatives when higher level complains
402 * about service problems. For now, invalidate cached
403 * routing information. If the route was created dynamically
404 * (by a redirect), time to try a default gateway again.
405 */
406 int
407 in_losing(inp)
408 struct inpcb *inp;
409 {
410 register struct rtentry *rt;
411 struct rt_addrinfo info;
412
413 if ((rt = inp->inp_route.ro_rt)) {
414 inp->inp_route.ro_rt = 0;
415 bzero((caddr_t)&info, sizeof(info));
416 info.rti_info[RTAX_DST] =
417 (struct sockaddr *)&inp->inp_route.ro_dst;
418 info.rti_info[RTAX_GATEWAY] = rt->rt_gateway;
419 info.rti_info[RTAX_NETMASK] = rt_mask(rt);
420 rt_missmsg(RTM_LOSING, &info, rt->rt_flags, 0);
421 if (rt->rt_flags & RTF_DYNAMIC)
422 (void) rtrequest(RTM_DELETE, rt_key(rt),
423 rt->rt_gateway, rt_mask(rt), rt->rt_flags,
424 (struct rtentry **)0);
425 else
426 /*
427 * A new route can be allocated
428 * the next time output is attempted.
429 */
430 rtfree(rt);
431 }
432 }
433
434 /*
435 * After a routing change, flush old routing
436 * and allocate a (hopefully) better one.
437 */
438 void
439 in_rtchange(inp, errno)
440 register struct inpcb *inp;
441 int errno;
442 {
443 if (inp->inp_route.ro_rt) {
444 rtfree(inp->inp_route.ro_rt);
445 inp->inp_route.ro_rt = 0;
446 /*
447 * A new route can be allocated the next time
448 * output is attempted.
449 */
450 }
451 }
452
453 struct inpcb *
454 in_pcblookup(head, faddr, fport_arg, laddr, lport_arg, flags)
455 struct inpcb *head;
456 struct in_addr faddr, laddr;
457 u_int fport_arg, lport_arg;
458 int flags;
459 {
460 register struct inpcb *inp, *match = 0;
461 int matchwild = 3, wildcard;
462 u_short fport = fport_arg, lport = lport_arg;
463
464 for (inp = head->inp_next; inp != head; inp = inp->inp_next) {
465 if (inp->inp_lport != lport)
466 continue;
467 wildcard = 0;
468 if (inp->inp_laddr.s_addr != INADDR_ANY) {
469 if (laddr.s_addr == INADDR_ANY)
470 wildcard++;
471 else if (inp->inp_laddr.s_addr != laddr.s_addr)
472 continue;
473 } else {
474 if (laddr.s_addr != INADDR_ANY)
475 wildcard++;
476 }
477 if (inp->inp_faddr.s_addr != INADDR_ANY) {
478 if (faddr.s_addr == INADDR_ANY)
479 wildcard++;
480 else if (inp->inp_faddr.s_addr != faddr.s_addr ||
481 inp->inp_fport != fport)
482 continue;
483 } else {
484 if (faddr.s_addr != INADDR_ANY)
485 wildcard++;
486 }
487 if (wildcard && (flags & INPLOOKUP_WILDCARD) == 0)
488 continue;
489 if (wildcard < matchwild) {
490 match = inp;
491 matchwild = wildcard;
492 if (matchwild == 0)
493 break;
494 }
495 }
496 return (match);
497 }
498