in_pcb.c revision 1.87 1 /* $NetBSD: in_pcb.c,v 1.87 2003/08/15 03:42:01 jonathan Exp $ */
2
3 /*
4 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the project nor the names of its contributors
16 * may be used to endorse or promote products derived from this software
17 * without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 */
31
32 /*-
33 * Copyright (c) 1998 The NetBSD Foundation, Inc.
34 * All rights reserved.
35 *
36 * This code is derived from software contributed to The NetBSD Foundation
37 * by Public Access Networks Corporation ("Panix"). It was developed under
38 * contract to Panix by Eric Haszlakiewicz and Thor Lancelot Simon.
39 *
40 * Redistribution and use in source and binary forms, with or without
41 * modification, are permitted provided that the following conditions
42 * are met:
43 * 1. Redistributions of source code must retain the above copyright
44 * notice, this list of conditions and the following disclaimer.
45 * 2. Redistributions in binary form must reproduce the above copyright
46 * notice, this list of conditions and the following disclaimer in the
47 * documentation and/or other materials provided with the distribution.
48 * 3. All advertising materials mentioning features or use of this software
49 * must display the following acknowledgement:
50 * This product includes software developed by the NetBSD
51 * Foundation, Inc. and its contributors.
52 * 4. Neither the name of The NetBSD Foundation nor the names of its
53 * contributors may be used to endorse or promote products derived
54 * from this software without specific prior written permission.
55 *
56 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
57 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
58 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
59 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
60 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
61 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
62 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
63 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
64 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
65 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
66 * POSSIBILITY OF SUCH DAMAGE.
67 */
68
69 /*
70 * Copyright (c) 1982, 1986, 1991, 1993, 1995
71 * The Regents of the University of California. All rights reserved.
72 *
73 * Redistribution and use in source and binary forms, with or without
74 * modification, are permitted provided that the following conditions
75 * are met:
76 * 1. Redistributions of source code must retain the above copyright
77 * notice, this list of conditions and the following disclaimer.
78 * 2. Redistributions in binary form must reproduce the above copyright
79 * notice, this list of conditions and the following disclaimer in the
80 * documentation and/or other materials provided with the distribution.
81 * 3. Neither the name of the University nor the names of its contributors
82 * may be used to endorse or promote products derived from this software
83 * without specific prior written permission.
84 *
85 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
86 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
87 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
88 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
89 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
90 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
91 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
92 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
93 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
94 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
95 * SUCH DAMAGE.
96 *
97 * @(#)in_pcb.c 8.4 (Berkeley) 5/24/95
98 */
99
100 #include <sys/cdefs.h>
101 __KERNEL_RCSID(0, "$NetBSD: in_pcb.c,v 1.87 2003/08/15 03:42:01 jonathan Exp $");
102
103 #include "opt_ipsec.h"
104
105 #include <sys/param.h>
106 #include <sys/systm.h>
107 #include <sys/malloc.h>
108 #include <sys/mbuf.h>
109 #include <sys/protosw.h>
110 #include <sys/socket.h>
111 #include <sys/socketvar.h>
112 #include <sys/ioctl.h>
113 #include <sys/errno.h>
114 #include <sys/time.h>
115 #include <sys/pool.h>
116 #include <sys/proc.h>
117
118 #include <net/if.h>
119 #include <net/route.h>
120
121 #include <netinet/in.h>
122 #include <netinet/in_systm.h>
123 #include <netinet/ip.h>
124 #include <netinet/in_pcb.h>
125 #include <netinet/in_var.h>
126 #include <netinet/ip_var.h>
127
128 #ifdef IPSEC
129 #include <netinet6/ipsec.h>
130 #include <netkey/key.h>
131 #elif FAST_IPSEC
132 #include <netipsec/ipsec.h>
133 #include <netipsec/key.h>
134 #endif /* IPSEC */
135
136 struct in_addr zeroin_addr;
137
138 #define INPCBHASH_BIND(table, laddr, lport) \
139 &(table)->inpt_bindhashtbl[ \
140 ((ntohl((laddr).s_addr) + ntohs(lport))) & (table)->inpt_bindhash]
141 #define INPCBHASH_CONNECT(table, faddr, fport, laddr, lport) \
142 &(table)->inpt_connecthashtbl[ \
143 ((ntohl((faddr).s_addr) + ntohs(fport)) + \
144 (ntohl((laddr).s_addr) + ntohs(lport))) & (table)->inpt_connecthash]
145
146 struct inpcb *
147 in_pcblookup_port __P((struct inpcbtable *,
148 struct in_addr, u_int, int));
149
150 int anonportmin = IPPORT_ANONMIN;
151 int anonportmax = IPPORT_ANONMAX;
152 int lowportmin = IPPORT_RESERVEDMIN;
153 int lowportmax = IPPORT_RESERVEDMAX;
154
155 struct pool inpcb_pool;
156
157 void
158 in_pcbinit(table, bindhashsize, connecthashsize)
159 struct inpcbtable *table;
160 int bindhashsize, connecthashsize;
161 {
162 static int inpcb_pool_initialized;
163
164 if (inpcb_pool_initialized == 0) {
165 pool_init(&inpcb_pool, sizeof(struct inpcb), 0, 0, 0,
166 "inpcbpl", NULL);
167 inpcb_pool_initialized = 1;
168 }
169
170 CIRCLEQ_INIT(&table->inpt_queue);
171 table->inpt_bindhashtbl = hashinit(bindhashsize, HASH_LIST, M_PCB,
172 M_WAITOK, &table->inpt_bindhash);
173 table->inpt_connecthashtbl = hashinit(connecthashsize, HASH_LIST,
174 M_PCB, M_WAITOK, &table->inpt_connecthash);
175 table->inpt_lastlow = IPPORT_RESERVEDMAX;
176 table->inpt_lastport = (u_int16_t)anonportmax;
177 }
178
179 int
180 in_pcballoc(so, v)
181 struct socket *so;
182 void *v;
183 {
184 struct inpcbtable *table = v;
185 struct inpcb *inp;
186 int s;
187 #if defined(IPSEC) || defined(FAST_IPSEC)
188 int error;
189 #endif
190
191 inp = pool_get(&inpcb_pool, PR_NOWAIT);
192 if (inp == NULL)
193 return (ENOBUFS);
194 bzero((caddr_t)inp, sizeof(*inp));
195 inp->inp_table = table;
196 inp->inp_socket = so;
197 inp->inp_errormtu = -1;
198 #if defined(IPSEC) || defined(FAST_IPSEC)
199 error = ipsec_init_pcbpolicy(so, &inp->inp_sp);
200 if (error != 0) {
201 pool_put(&inpcb_pool, inp);
202 return error;
203 }
204 #endif
205 so->so_pcb = inp;
206 s = splnet();
207 CIRCLEQ_INSERT_HEAD(&table->inpt_queue, inp, inp_queue);
208 in_pcbstate(inp, INP_ATTACHED);
209 splx(s);
210 return (0);
211 }
212
213 int
214 in_pcbbind(v, nam, p)
215 void *v;
216 struct mbuf *nam;
217 struct proc *p;
218 {
219 struct in_ifaddr *ia = NULL;
220 struct inpcb *inp = v;
221 struct socket *so = inp->inp_socket;
222 struct inpcbtable *table = inp->inp_table;
223 struct sockaddr_in *sin;
224 u_int16_t lport = 0;
225 int wild = 0, reuseport = (so->so_options & SO_REUSEPORT);
226
227 if (TAILQ_FIRST(&in_ifaddr) == 0)
228 return (EADDRNOTAVAIL);
229 if (inp->inp_lport || !in_nullhost(inp->inp_laddr))
230 return (EINVAL);
231 if ((so->so_options & (SO_REUSEADDR|SO_REUSEPORT)) == 0)
232 wild = 1;
233 if (nam == 0)
234 goto noname;
235 sin = mtod(nam, struct sockaddr_in *);
236 if (nam->m_len != sizeof (*sin))
237 return (EINVAL);
238 if (sin->sin_family != AF_INET)
239 return (EAFNOSUPPORT);
240 lport = sin->sin_port;
241 if (IN_MULTICAST(sin->sin_addr.s_addr)) {
242 /*
243 * Treat SO_REUSEADDR as SO_REUSEPORT for multicast;
244 * allow complete duplication of binding if
245 * SO_REUSEPORT is set, or if SO_REUSEADDR is set
246 * and a multicast address is bound on both
247 * new and duplicated sockets.
248 */
249 if (so->so_options & SO_REUSEADDR)
250 reuseport = SO_REUSEADDR|SO_REUSEPORT;
251 } else if (!in_nullhost(sin->sin_addr)) {
252 sin->sin_port = 0; /* yech... */
253 INADDR_TO_IA(sin->sin_addr, ia);
254 /* check for broadcast addresses */
255 if (ia == NULL)
256 ia = ifatoia(ifa_ifwithaddr(sintosa(sin)));
257 if (ia == NULL)
258 return (EADDRNOTAVAIL);
259 }
260 if (lport) {
261 struct inpcb *t;
262 #ifndef IPNOPRIVPORTS
263 /* GROSS */
264 if (ntohs(lport) < IPPORT_RESERVED &&
265 (p == 0 || suser(p->p_ucred, &p->p_acflag)))
266 return (EACCES);
267 #endif
268 if (so->so_uid && !IN_MULTICAST(sin->sin_addr.s_addr)) {
269 t = in_pcblookup_port(table, sin->sin_addr, lport, 1);
270 /*
271 * XXX: investigate ramifications of loosening this
272 * restriction so that as long as both ports have
273 * SO_REUSEPORT allow the bind
274 */
275 if (t &&
276 (!in_nullhost(sin->sin_addr) ||
277 !in_nullhost(t->inp_laddr) ||
278 (t->inp_socket->so_options & SO_REUSEPORT) == 0)
279 && (so->so_uid != t->inp_socket->so_uid)) {
280 return (EADDRINUSE);
281 }
282 }
283 t = in_pcblookup_port(table, sin->sin_addr, lport, wild);
284 if (t && (reuseport & t->inp_socket->so_options) == 0)
285 return (EADDRINUSE);
286 }
287 if (!in_nullhost(inp->inp_laddr)) {
288 KASSERT(inp->inp_ia != NULL);
289 LIST_REMOVE(inp, inp_ialink);
290 IFAFREE(&inp->inp_ia->ia_ifa);
291 inp->inp_ia = NULL;
292 }
293 inp->inp_laddr = sin->sin_addr;
294 if (ia != NULL) {
295 inp->inp_ia = ia;
296 LIST_INSERT_HEAD(&ia->ia_inpcbs, inp, inp_ialink);
297 IFAREF(&ia->ia_ifa);
298 }
299
300
301 noname:
302 if (lport == 0) {
303 int cnt;
304 u_int16_t min, max;
305 u_int16_t *lastport;
306
307 if (inp->inp_flags & INP_LOWPORT) {
308 #ifndef IPNOPRIVPORTS
309 if (p == 0 || suser(p->p_ucred, &p->p_acflag))
310 return (EACCES);
311 #endif
312 min = lowportmin;
313 max = lowportmax;
314 lastport = &table->inpt_lastlow;
315 } else {
316 min = anonportmin;
317 max = anonportmax;
318 lastport = &table->inpt_lastport;
319 }
320 if (min > max) { /* sanity check */
321 u_int16_t swp;
322
323 swp = min;
324 min = max;
325 max = swp;
326 }
327
328 lport = *lastport - 1;
329 for (cnt = max - min + 1; cnt; cnt--, lport--) {
330 if (lport < min || lport > max)
331 lport = max;
332 if (!in_pcblookup_port(table, inp->inp_laddr,
333 htons(lport), 1))
334 goto found;
335 }
336 if (!in_nullhost(inp->inp_laddr)) {
337 if (inp->inp_ia != NULL) {
338 LIST_REMOVE(inp, inp_ialink);
339 IFAFREE(&inp->inp_ia->ia_ifa);
340 inp->inp_ia = NULL;
341 }
342 inp->inp_laddr.s_addr = INADDR_ANY;
343 }
344 return (EAGAIN);
345 found:
346 inp->inp_flags |= INP_ANONPORT;
347 *lastport = lport;
348 lport = htons(lport);
349 }
350 inp->inp_lport = lport;
351 in_pcbstate(inp, INP_BOUND);
352 return (0);
353 }
354
355 /*
356 * Connect from a socket to a specified address.
357 * Both address and port must be specified in argument sin.
358 * If don't have a local address for this socket yet,
359 * then pick one.
360 */
361 int
362 in_pcbconnect(v, nam)
363 void *v;
364 struct mbuf *nam;
365 {
366 struct inpcb *inp = v;
367 struct in_ifaddr *ia = NULL;
368 struct sockaddr_in *ifaddr = NULL;
369 struct sockaddr_in *sin = mtod(nam, struct sockaddr_in *);
370 int error;
371
372 if (nam->m_len != sizeof (*sin))
373 return (EINVAL);
374 if (sin->sin_family != AF_INET)
375 return (EAFNOSUPPORT);
376 if (sin->sin_port == 0)
377 return (EADDRNOTAVAIL);
378 if (TAILQ_FIRST(&in_ifaddr) != 0) {
379 /*
380 * If the destination address is INADDR_ANY,
381 * use any local address (likely loopback).
382 * If the supplied address is INADDR_BROADCAST,
383 * use the broadcast address of an interface
384 * which supports broadcast. (loopback does not)
385 */
386
387 if (in_nullhost(sin->sin_addr)) {
388 sin->sin_addr =
389 TAILQ_FIRST(&in_ifaddr)->ia_addr.sin_addr;
390 } else if (sin->sin_addr.s_addr == INADDR_BROADCAST) {
391 TAILQ_FOREACH(ia, &in_ifaddr, ia_list) {
392 if (ia->ia_ifp->if_flags & IFF_BROADCAST) {
393 sin->sin_addr =
394 ia->ia_broadaddr.sin_addr;
395 break;
396 }
397 }
398 }
399 }
400 /*
401 * If we haven't bound which network number to use as ours,
402 * we will use the number of the outgoing interface.
403 * This depends on having done a routing lookup, which
404 * we will probably have to do anyway, so we might
405 * as well do it now. On the other hand if we are
406 * sending to multiple destinations we may have already
407 * done the lookup, so see if we can use the route
408 * from before. In any case, we only
409 * chose a port number once, even if sending to multiple
410 * destinations.
411 */
412 if (in_nullhost(inp->inp_laddr)) {
413 int error;
414 ifaddr = in_selectsrc(sin, &inp->inp_route,
415 inp->inp_socket->so_options, inp->inp_moptions, &error);
416 if (ifaddr == NULL) {
417 if (error == 0)
418 error = EADDRNOTAVAIL;
419 return error;
420 }
421 INADDR_TO_IA(ifaddr->sin_addr, ia);
422 if (ia == NULL)
423 return (EADDRNOTAVAIL);
424 }
425 if (in_pcblookup_connect(inp->inp_table, sin->sin_addr, sin->sin_port,
426 !in_nullhost(inp->inp_laddr) ? inp->inp_laddr : ifaddr->sin_addr,
427 inp->inp_lport) != 0)
428 return (EADDRINUSE);
429 if (in_nullhost(inp->inp_laddr)) {
430 if (inp->inp_lport == 0) {
431 error = in_pcbbind(inp, (struct mbuf *)0,
432 (struct proc *)0);
433 /*
434 * This used to ignore the return value
435 * completely, but we need to check for
436 * ephemeral port shortage.
437 * XXX Should we check for other errors, too?
438 */
439 if (error == EAGAIN)
440 return (error);
441 }
442 KASSERT(inp->inp_ia == NULL);
443 inp->inp_laddr = ia->ia_addr.sin_addr;
444 inp->inp_ia = ia;
445 LIST_INSERT_HEAD(&ia->ia_inpcbs, inp, inp_ialink);
446 IFAREF(&ia->ia_ifa);
447 inp->inp_laddr = ifaddr->sin_addr;
448 }
449 inp->inp_faddr = sin->sin_addr;
450 inp->inp_fport = sin->sin_port;
451 in_pcbstate(inp, INP_CONNECTED);
452 #if defined(IPSEC) /*|| defined(FAST_IPSEC)*/ /*XXX*/
453 if (inp->inp_socket->so_type == SOCK_STREAM)
454 ipsec_pcbconn(inp->inp_sp);
455 #endif
456 return (0);
457 }
458
459 void
460 in_pcbdisconnect(v)
461 void *v;
462 {
463 struct inpcb *inp = v;
464
465 inp->inp_faddr = zeroin_addr;
466 inp->inp_fport = 0;
467 in_pcbstate(inp, INP_BOUND);
468 if (inp->inp_socket->so_state & SS_NOFDREF)
469 in_pcbdetach(inp);
470 #if defined(IPSEC) /*|| defined(FAST_IPSEC)*/ /*XXX*/
471 ipsec_pcbdisconn(inp->inp_sp);
472 #endif
473 }
474
475 void
476 in_pcbdetach(v)
477 void *v;
478 {
479 struct inpcb *inp = v;
480 struct socket *so = inp->inp_socket;
481 int s;
482
483 #if defined(IPSEC) || defined(FAST_IPSEC)
484 ipsec4_delete_pcbpolicy(inp);
485 #endif /*IPSEC*/
486 so->so_pcb = 0;
487 sofree(so);
488 if (inp->inp_options)
489 (void)m_free(inp->inp_options);
490 if (inp->inp_route.ro_rt)
491 rtfree(inp->inp_route.ro_rt);
492 ip_freemoptions(inp->inp_moptions);
493 if (inp->inp_ia != NULL) {
494 LIST_REMOVE(inp, inp_ialink);
495 IFAFREE(&inp->inp_ia->ia_ifa);
496 inp->inp_ia = NULL;
497 }
498 s = splnet();
499 in_pcbstate(inp, INP_ATTACHED);
500 CIRCLEQ_REMOVE(&inp->inp_table->inpt_queue, inp, inp_queue);
501 splx(s);
502 pool_put(&inpcb_pool, inp);
503 }
504
505 void
506 in_setsockaddr(inp, nam)
507 struct inpcb *inp;
508 struct mbuf *nam;
509 {
510 struct sockaddr_in *sin;
511
512 nam->m_len = sizeof (*sin);
513 sin = mtod(nam, struct sockaddr_in *);
514 bzero((caddr_t)sin, sizeof (*sin));
515 sin->sin_family = AF_INET;
516 sin->sin_len = sizeof(*sin);
517 sin->sin_port = inp->inp_lport;
518 sin->sin_addr = inp->inp_laddr;
519 }
520
521 void
522 in_setpeeraddr(inp, nam)
523 struct inpcb *inp;
524 struct mbuf *nam;
525 {
526 struct sockaddr_in *sin;
527
528 nam->m_len = sizeof (*sin);
529 sin = mtod(nam, struct sockaddr_in *);
530 bzero((caddr_t)sin, sizeof (*sin));
531 sin->sin_family = AF_INET;
532 sin->sin_len = sizeof(*sin);
533 sin->sin_port = inp->inp_fport;
534 sin->sin_addr = inp->inp_faddr;
535 }
536
537 /*
538 * Pass some notification to all connections of a protocol
539 * associated with address dst. The local address and/or port numbers
540 * may be specified to limit the search. The "usual action" will be
541 * taken, depending on the ctlinput cmd. The caller must filter any
542 * cmds that are uninteresting (e.g., no error in the map).
543 * Call the protocol specific routine (if any) to report
544 * any errors for each matching socket.
545 *
546 * Must be called at splsoftnet.
547 */
548 int
549 in_pcbnotify(table, faddr, fport_arg, laddr, lport_arg, errno, notify)
550 struct inpcbtable *table;
551 struct in_addr faddr, laddr;
552 u_int fport_arg, lport_arg;
553 int errno;
554 void (*notify) __P((struct inpcb *, int));
555 {
556 struct inpcbhead *head;
557 struct inpcb *inp, *ninp;
558 u_int16_t fport = fport_arg, lport = lport_arg;
559 int nmatch;
560
561 if (in_nullhost(faddr) || notify == 0)
562 return (0);
563
564 nmatch = 0;
565 head = INPCBHASH_CONNECT(table, faddr, fport, laddr, lport);
566 for (inp = LIST_FIRST(head); inp != NULL; inp = ninp) {
567 ninp = LIST_NEXT(inp, inp_hash);
568 if (in_hosteq(inp->inp_faddr, faddr) &&
569 inp->inp_fport == fport &&
570 inp->inp_lport == lport &&
571 in_hosteq(inp->inp_laddr, laddr)) {
572 (*notify)(inp, errno);
573 nmatch++;
574 }
575 }
576 return (nmatch);
577 }
578
579 void
580 in_pcbnotifyall(table, faddr, errno, notify)
581 struct inpcbtable *table;
582 struct in_addr faddr;
583 int errno;
584 void (*notify) __P((struct inpcb *, int));
585 {
586 struct inpcb *inp, *ninp;
587
588 if (in_nullhost(faddr) || notify == 0)
589 return;
590
591 for (inp = CIRCLEQ_FIRST(&table->inpt_queue);
592 inp != (void *)&table->inpt_queue;
593 inp = ninp) {
594 ninp = CIRCLEQ_NEXT(inp, inp_queue);
595 if (in_hosteq(inp->inp_faddr, faddr))
596 (*notify)(inp, errno);
597 }
598 }
599
600 void
601 in_pcbpurgeif0(table, ifp)
602 struct inpcbtable *table;
603 struct ifnet *ifp;
604 {
605 struct inpcb *inp, *ninp;
606 struct ip_moptions *imo;
607 int i, gap;
608
609 for (inp = CIRCLEQ_FIRST(&table->inpt_queue);
610 inp != (void *)&table->inpt_queue;
611 inp = ninp) {
612 ninp = CIRCLEQ_NEXT(inp, inp_queue);
613 imo = inp->inp_moptions;
614 if (imo != NULL) {
615 /*
616 * Unselect the outgoing interface if it is being
617 * detached.
618 */
619 if (imo->imo_multicast_ifp == ifp)
620 imo->imo_multicast_ifp = NULL;
621
622 /*
623 * Drop multicast group membership if we joined
624 * through the interface being detached.
625 */
626 for (i = 0, gap = 0; i < imo->imo_num_memberships;
627 i++) {
628 if (imo->imo_membership[i]->inm_ifp == ifp) {
629 in_delmulti(imo->imo_membership[i]);
630 gap++;
631 } else if (gap != 0)
632 imo->imo_membership[i - gap] =
633 imo->imo_membership[i];
634 }
635 imo->imo_num_memberships -= gap;
636 }
637 }
638 }
639
640 void
641 in_pcbpurgeif(table, ifp)
642 struct inpcbtable *table;
643 struct ifnet *ifp;
644 {
645 struct inpcb *inp, *ninp;
646
647 for (inp = CIRCLEQ_FIRST(&table->inpt_queue);
648 inp != (void *)&table->inpt_queue;
649 inp = ninp) {
650 ninp = CIRCLEQ_NEXT(inp, inp_queue);
651 if (inp->inp_route.ro_rt != NULL &&
652 inp->inp_route.ro_rt->rt_ifp == ifp)
653 in_rtchange(inp, 0);
654 }
655 }
656
657 /*
658 * Check for alternatives when higher level complains
659 * about service problems. For now, invalidate cached
660 * routing information. If the route was created dynamically
661 * (by a redirect), time to try a default gateway again.
662 */
663 void
664 in_losing(inp)
665 struct inpcb *inp;
666 {
667 struct rtentry *rt;
668 struct rt_addrinfo info;
669
670 if ((rt = inp->inp_route.ro_rt)) {
671 inp->inp_route.ro_rt = 0;
672 bzero((caddr_t)&info, sizeof(info));
673 info.rti_info[RTAX_DST] = &inp->inp_route.ro_dst;
674 info.rti_info[RTAX_GATEWAY] = rt->rt_gateway;
675 info.rti_info[RTAX_NETMASK] = rt_mask(rt);
676 rt_missmsg(RTM_LOSING, &info, rt->rt_flags, 0);
677 if (rt->rt_flags & RTF_DYNAMIC)
678 (void) rtrequest(RTM_DELETE, rt_key(rt),
679 rt->rt_gateway, rt_mask(rt), rt->rt_flags,
680 (struct rtentry **)0);
681 else
682 /*
683 * A new route can be allocated
684 * the next time output is attempted.
685 */
686 rtfree(rt);
687 }
688 }
689
690 /*
691 * After a routing change, flush old routing
692 * and allocate a (hopefully) better one.
693 */
694 void
695 in_rtchange(inp, errno)
696 struct inpcb *inp;
697 int errno;
698 {
699
700 if (inp->inp_route.ro_rt) {
701 rtfree(inp->inp_route.ro_rt);
702 inp->inp_route.ro_rt = 0;
703 /*
704 * A new route can be allocated the next time
705 * output is attempted.
706 */
707 }
708 /* XXX SHOULD NOTIFY HIGHER-LEVEL PROTOCOLS */
709 }
710
711 struct inpcb *
712 in_pcblookup_port(table, laddr, lport_arg, lookup_wildcard)
713 struct inpcbtable *table;
714 struct in_addr laddr;
715 u_int lport_arg;
716 int lookup_wildcard;
717 {
718 struct inpcb *inp, *match = 0;
719 int matchwild = 3, wildcard;
720 u_int16_t lport = lport_arg;
721
722 CIRCLEQ_FOREACH(inp, &table->inpt_queue, inp_queue) {
723 if (inp->inp_lport != lport)
724 continue;
725 wildcard = 0;
726 if (!in_nullhost(inp->inp_faddr))
727 wildcard++;
728 if (in_nullhost(inp->inp_laddr)) {
729 if (!in_nullhost(laddr))
730 wildcard++;
731 } else {
732 if (in_nullhost(laddr))
733 wildcard++;
734 else {
735 if (!in_hosteq(inp->inp_laddr, laddr))
736 continue;
737 }
738 }
739 if (wildcard && !lookup_wildcard)
740 continue;
741 if (wildcard < matchwild) {
742 match = inp;
743 matchwild = wildcard;
744 if (matchwild == 0)
745 break;
746 }
747 }
748 return (match);
749 }
750
751 #ifdef DIAGNOSTIC
752 int in_pcbnotifymiss = 0;
753 #endif
754
755 struct inpcb *
756 in_pcblookup_connect(table, faddr, fport_arg, laddr, lport_arg)
757 struct inpcbtable *table;
758 struct in_addr faddr, laddr;
759 u_int fport_arg, lport_arg;
760 {
761 struct inpcbhead *head;
762 struct inpcb *inp;
763 u_int16_t fport = fport_arg, lport = lport_arg;
764
765 head = INPCBHASH_CONNECT(table, faddr, fport, laddr, lport);
766 LIST_FOREACH(inp, head, inp_hash) {
767 if (in_hosteq(inp->inp_faddr, faddr) &&
768 inp->inp_fport == fport &&
769 inp->inp_lport == lport &&
770 in_hosteq(inp->inp_laddr, laddr))
771 goto out;
772 }
773 #ifdef DIAGNOSTIC
774 if (in_pcbnotifymiss) {
775 printf("in_pcblookup_connect: faddr=%08x fport=%d laddr=%08x lport=%d\n",
776 ntohl(faddr.s_addr), ntohs(fport),
777 ntohl(laddr.s_addr), ntohs(lport));
778 }
779 #endif
780 return (0);
781
782 out:
783 /* Move this PCB to the head of hash chain. */
784 if (inp != LIST_FIRST(head)) {
785 LIST_REMOVE(inp, inp_hash);
786 LIST_INSERT_HEAD(head, inp, inp_hash);
787 }
788 return (inp);
789 }
790
791 struct inpcb *
792 in_pcblookup_bind(table, laddr, lport_arg)
793 struct inpcbtable *table;
794 struct in_addr laddr;
795 u_int lport_arg;
796 {
797 struct inpcbhead *head;
798 struct inpcb *inp;
799 u_int16_t lport = lport_arg;
800
801 head = INPCBHASH_BIND(table, laddr, lport);
802 LIST_FOREACH(inp, head, inp_hash) {
803 if (inp->inp_lport == lport &&
804 in_hosteq(inp->inp_laddr, laddr))
805 goto out;
806 }
807 head = INPCBHASH_BIND(table, zeroin_addr, lport);
808 LIST_FOREACH(inp, head, inp_hash) {
809 if (inp->inp_lport == lport &&
810 in_hosteq(inp->inp_laddr, zeroin_addr))
811 goto out;
812 }
813 #ifdef DIAGNOSTIC
814 if (in_pcbnotifymiss) {
815 printf("in_pcblookup_bind: laddr=%08x lport=%d\n",
816 ntohl(laddr.s_addr), ntohs(lport));
817 }
818 #endif
819 return (0);
820
821 out:
822 /* Move this PCB to the head of hash chain. */
823 if (inp != LIST_FIRST(head)) {
824 LIST_REMOVE(inp, inp_hash);
825 LIST_INSERT_HEAD(head, inp, inp_hash);
826 }
827 return (inp);
828 }
829
830 void
831 in_pcbstate(inp, state)
832 struct inpcb *inp;
833 int state;
834 {
835
836 if (inp->inp_state > INP_ATTACHED)
837 LIST_REMOVE(inp, inp_hash);
838
839 switch (state) {
840 case INP_BOUND:
841 LIST_INSERT_HEAD(INPCBHASH_BIND(inp->inp_table,
842 inp->inp_laddr, inp->inp_lport), inp, inp_hash);
843 break;
844 case INP_CONNECTED:
845 LIST_INSERT_HEAD(INPCBHASH_CONNECT(inp->inp_table,
846 inp->inp_faddr, inp->inp_fport,
847 inp->inp_laddr, inp->inp_lport), inp, inp_hash);
848 break;
849 }
850
851 inp->inp_state = state;
852 }
853
854 struct rtentry *
855 in_pcbrtentry(inp)
856 struct inpcb *inp;
857 {
858 struct route *ro;
859
860 ro = &inp->inp_route;
861
862 if (ro->ro_rt && ((ro->ro_rt->rt_flags & RTF_UP) == 0 ||
863 !in_hosteq(satosin(&ro->ro_dst)->sin_addr, inp->inp_faddr))) {
864 RTFREE(ro->ro_rt);
865 ro->ro_rt = (struct rtentry *)NULL;
866 }
867 if (ro->ro_rt == (struct rtentry *)NULL &&
868 !in_nullhost(inp->inp_faddr)) {
869 bzero(&ro->ro_dst, sizeof(struct sockaddr_in));
870 ro->ro_dst.sa_family = AF_INET;
871 ro->ro_dst.sa_len = sizeof(ro->ro_dst);
872 satosin(&ro->ro_dst)->sin_addr = inp->inp_faddr;
873 rtalloc(ro);
874 }
875 return (ro->ro_rt);
876 }
877
878 struct sockaddr_in *
879 in_selectsrc(sin, ro, soopts, mopts, errorp)
880 struct sockaddr_in *sin;
881 struct route *ro;
882 int soopts;
883 struct ip_moptions *mopts;
884 int *errorp;
885 {
886 struct in_ifaddr *ia;
887
888 ia = (struct in_ifaddr *)0;
889 /*
890 * If route is known or can be allocated now,
891 * our src addr is taken from the i/f, else punt.
892 * Note that we should check the address family of the cached
893 * destination, in case of sharing the cache with IPv6.
894 */
895 if (ro->ro_rt &&
896 (ro->ro_dst.sa_family != AF_INET ||
897 !in_hosteq(satosin(&ro->ro_dst)->sin_addr, sin->sin_addr) ||
898 soopts & SO_DONTROUTE)) {
899 RTFREE(ro->ro_rt);
900 ro->ro_rt = (struct rtentry *)0;
901 }
902 if ((soopts & SO_DONTROUTE) == 0 && /*XXX*/
903 (ro->ro_rt == (struct rtentry *)0 ||
904 ro->ro_rt->rt_ifp == (struct ifnet *)0)) {
905 /* No route yet, so try to acquire one */
906 bzero(&ro->ro_dst, sizeof(struct sockaddr_in));
907 ro->ro_dst.sa_family = AF_INET;
908 ro->ro_dst.sa_len = sizeof(struct sockaddr_in);
909 satosin(&ro->ro_dst)->sin_addr = sin->sin_addr;
910 rtalloc(ro);
911 }
912 /*
913 * If we found a route, use the address
914 * corresponding to the outgoing interface
915 * unless it is the loopback (in case a route
916 * to our address on another net goes to loopback).
917 *
918 * XXX Is this still true? Do we care?
919 */
920 if (ro->ro_rt && !(ro->ro_rt->rt_ifp->if_flags & IFF_LOOPBACK))
921 ia = ifatoia(ro->ro_rt->rt_ifa);
922 if (ia == NULL) {
923 u_int16_t fport = sin->sin_port;
924
925 sin->sin_port = 0;
926 ia = ifatoia(ifa_ifwithladdr(sintosa(sin)));
927 sin->sin_port = fport;
928 if (ia == 0) {
929 /* Find 1st non-loopback AF_INET address */
930 TAILQ_FOREACH(ia, &in_ifaddr, ia_list) {
931 if (!(ia->ia_ifp->if_flags & IFF_LOOPBACK))
932 break;
933 }
934 }
935 if (ia == NULL) {
936 *errorp = EADDRNOTAVAIL;
937 return NULL;
938 }
939 }
940 /*
941 * If the destination address is multicast and an outgoing
942 * interface has been set as a multicast option, use the
943 * address of that interface as our source address.
944 */
945 if (IN_MULTICAST(sin->sin_addr.s_addr) && mopts != NULL) {
946 struct ip_moptions *imo;
947 struct ifnet *ifp;
948
949 imo = mopts;
950 if (imo->imo_multicast_ifp != NULL) {
951 ifp = imo->imo_multicast_ifp;
952 IFP_TO_IA(ifp, ia); /* XXX */
953 if (ia == 0) {
954 *errorp = EADDRNOTAVAIL;
955 return NULL;
956 }
957 }
958 }
959 return satosin(&ia->ia_addr);
960 }
961