Line data Source code
1 : /* $OpenBSD: in_pcb.c,v 1.244 2018/09/13 19:53:58 bluhm Exp $ */
2 : /* $NetBSD: in_pcb.c,v 1.25 1996/02/13 23:41:53 christos Exp $ */
3 :
4 : /*
5 : * Copyright (c) 1982, 1986, 1991, 1993
6 : * The Regents of the University of California. All rights reserved.
7 : *
8 : * Redistribution and use in source and binary forms, with or without
9 : * modification, are permitted provided that the following conditions
10 : * are met:
11 : * 1. Redistributions of source code must retain the above copyright
12 : * notice, this list of conditions and the following disclaimer.
13 : * 2. Redistributions in binary form must reproduce the above copyright
14 : * notice, this list of conditions and the following disclaimer in the
15 : * documentation and/or other materials provided with the distribution.
16 : * 3. Neither the name of the University nor the names of its contributors
17 : * may be used to endorse or promote products derived from this software
18 : * without specific prior written permission.
19 : *
20 : * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21 : * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 : * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 : * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24 : * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 : * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 : * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 : * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 : * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 : * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 : * SUCH DAMAGE.
31 : *
32 : * @(#)COPYRIGHT 1.1 (NRL) 17 January 1995
33 : *
34 : * NRL grants permission for redistribution and use in source and binary
35 : * forms, with or without modification, of the software and documentation
36 : * created at NRL provided that the following conditions are met:
37 : *
38 : * 1. Redistributions of source code must retain the above copyright
39 : * notice, this list of conditions and the following disclaimer.
40 : * 2. Redistributions in binary form must reproduce the above copyright
41 : * notice, this list of conditions and the following disclaimer in the
42 : * documentation and/or other materials provided with the distribution.
43 : * 3. All advertising materials mentioning features or use of this software
44 : * must display the following acknowledgements:
45 : * This product includes software developed by the University of
46 : * California, Berkeley and its contributors.
47 : * This product includes software developed at the Information
48 : * Technology Division, US Naval Research Laboratory.
49 : * 4. Neither the name of the NRL nor the names of its contributors
50 : * may be used to endorse or promote products derived from this software
51 : * without specific prior written permission.
52 : *
53 : * THE SOFTWARE PROVIDED BY NRL IS PROVIDED BY NRL AND CONTRIBUTORS ``AS
54 : * IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
55 : * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
56 : * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NRL OR
57 : * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
58 : * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
59 : * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
60 : * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
61 : * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
62 : * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
63 : * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
64 : *
65 : * The views and conclusions contained in the software and documentation
66 : * are those of the authors and should not be interpreted as representing
67 : * official policies, either expressed or implied, of the US Naval
68 : * Research Laboratory (NRL).
69 : */
70 :
71 : #include "pf.h"
72 :
73 : #include <sys/param.h>
74 : #include <sys/systm.h>
75 : #include <sys/mbuf.h>
76 : #include <sys/protosw.h>
77 : #include <sys/socket.h>
78 : #include <sys/socketvar.h>
79 : #include <sys/domain.h>
80 : #include <sys/mount.h>
81 : #include <sys/pool.h>
82 : #include <sys/proc.h>
83 :
84 : #include <net/if.h>
85 : #include <net/if_var.h>
86 : #include <net/pfvar.h>
87 : #include <net/route.h>
88 :
89 : #include <netinet/in.h>
90 : #include <netinet/in_var.h>
91 : #include <netinet/ip.h>
92 : #include <netinet/ip_var.h>
93 : #include <netinet/in_pcb.h>
94 : #ifdef IPSEC
95 : #include <netinet/ip_esp.h>
96 : #endif /* IPSEC */
97 :
98 : const struct in_addr zeroin_addr;
99 :
100 : union {
101 : struct in_addr za_in;
102 : struct in6_addr za_in6;
103 : } zeroin46_addr;
104 :
105 : /*
106 : * These configure the range of local port addresses assigned to
107 : * "unspecified" outgoing connections/packets/whatever.
108 : */
109 : int ipport_firstauto = IPPORT_RESERVED;
110 : int ipport_lastauto = IPPORT_USERRESERVED;
111 : int ipport_hifirstauto = IPPORT_HIFIRSTAUTO;
112 : int ipport_hilastauto = IPPORT_HILASTAUTO;
113 :
114 : struct baddynamicports baddynamicports;
115 : struct baddynamicports rootonlyports;
116 : struct pool inpcb_pool;
117 : int inpcb_pool_initialized = 0;
118 :
119 : int in_pcbresize (struct inpcbtable *, int);
120 :
121 : #define INPCBHASH_LOADFACTOR(_x) (((_x) * 3) / 4)
122 :
123 : struct inpcbhead *in_pcbhash(struct inpcbtable *, int,
124 : const struct in_addr *, u_short, const struct in_addr *, u_short);
125 : struct inpcbhead *in_pcblhash(struct inpcbtable *, int, u_short);
126 :
127 : struct inpcbhead *
128 0 : in_pcbhash(struct inpcbtable *table, int rdom,
129 : const struct in_addr *faddr, u_short fport,
130 : const struct in_addr *laddr, u_short lport)
131 : {
132 0 : SIPHASH_CTX ctx;
133 0 : u_int32_t nrdom = htonl(rdom);
134 :
135 0 : SipHash24_Init(&ctx, &table->inpt_key);
136 0 : SipHash24_Update(&ctx, &nrdom, sizeof(nrdom));
137 0 : SipHash24_Update(&ctx, faddr, sizeof(*faddr));
138 0 : SipHash24_Update(&ctx, &fport, sizeof(fport));
139 0 : SipHash24_Update(&ctx, laddr, sizeof(*laddr));
140 0 : SipHash24_Update(&ctx, &lport, sizeof(lport));
141 :
142 0 : return (&table->inpt_hashtbl[SipHash24_End(&ctx) & table->inpt_mask]);
143 0 : }
144 :
145 : struct inpcbhead *
146 0 : in_pcblhash(struct inpcbtable *table, int rdom, u_short lport)
147 : {
148 0 : SIPHASH_CTX ctx;
149 0 : u_int32_t nrdom = htonl(rdom);
150 :
151 0 : SipHash24_Init(&ctx, &table->inpt_key);
152 0 : SipHash24_Update(&ctx, &nrdom, sizeof(nrdom));
153 0 : SipHash24_Update(&ctx, &lport, sizeof(lport));
154 :
155 0 : return (&table->inpt_lhashtbl[SipHash24_End(&ctx) & table->inpt_lmask]);
156 0 : }
157 :
158 : void
159 0 : in_pcbinit(struct inpcbtable *table, int hashsize)
160 : {
161 :
162 0 : TAILQ_INIT(&table->inpt_queue);
163 0 : table->inpt_hashtbl = hashinit(hashsize, M_PCB, M_NOWAIT,
164 0 : &table->inpt_mask);
165 0 : if (table->inpt_hashtbl == NULL)
166 0 : panic("in_pcbinit: hashinit failed");
167 0 : table->inpt_lhashtbl = hashinit(hashsize, M_PCB, M_NOWAIT,
168 0 : &table->inpt_lmask);
169 0 : if (table->inpt_lhashtbl == NULL)
170 0 : panic("in_pcbinit: hashinit failed for lport");
171 0 : table->inpt_count = 0;
172 0 : table->inpt_size = hashsize;
173 0 : arc4random_buf(&table->inpt_key, sizeof(table->inpt_key));
174 0 : }
175 :
176 : /*
177 : * Check if the specified port is invalid for dynamic allocation.
178 : */
179 : int
180 0 : in_baddynamic(u_int16_t port, u_int16_t proto)
181 : {
182 0 : switch (proto) {
183 : case IPPROTO_TCP:
184 0 : return (DP_ISSET(baddynamicports.tcp, port));
185 : case IPPROTO_UDP:
186 : #ifdef IPSEC
187 : /* Cannot preset this as it is a sysctl */
188 0 : if (port == udpencap_port)
189 0 : return (1);
190 : #endif
191 0 : return (DP_ISSET(baddynamicports.udp, port));
192 : default:
193 0 : return (0);
194 : }
195 0 : }
196 :
197 : int
198 0 : in_rootonly(u_int16_t port, u_int16_t proto)
199 : {
200 0 : switch (proto) {
201 : case IPPROTO_TCP:
202 0 : return (port < IPPORT_RESERVED ||
203 0 : DP_ISSET(rootonlyports.tcp, port));
204 : case IPPROTO_UDP:
205 0 : return (port < IPPORT_RESERVED ||
206 0 : DP_ISSET(rootonlyports.udp, port));
207 : default:
208 0 : return (0);
209 : }
210 0 : }
211 :
212 : int
213 0 : in_pcballoc(struct socket *so, struct inpcbtable *table)
214 : {
215 : struct inpcb *inp;
216 : struct inpcbhead *head;
217 :
218 0 : NET_ASSERT_LOCKED();
219 :
220 0 : if (inpcb_pool_initialized == 0) {
221 0 : pool_init(&inpcb_pool, sizeof(struct inpcb), 0,
222 : IPL_SOFTNET, 0, "inpcbpl", NULL);
223 0 : inpcb_pool_initialized = 1;
224 0 : }
225 0 : inp = pool_get(&inpcb_pool, PR_NOWAIT|PR_ZERO);
226 0 : if (inp == NULL)
227 0 : return (ENOBUFS);
228 0 : inp->inp_table = table;
229 0 : inp->inp_socket = so;
230 0 : refcnt_init(&inp->inp_refcnt);
231 0 : inp->inp_seclevel[SL_AUTH] = IPSEC_AUTH_LEVEL_DEFAULT;
232 0 : inp->inp_seclevel[SL_ESP_TRANS] = IPSEC_ESP_TRANS_LEVEL_DEFAULT;
233 0 : inp->inp_seclevel[SL_ESP_NETWORK] = IPSEC_ESP_NETWORK_LEVEL_DEFAULT;
234 0 : inp->inp_seclevel[SL_IPCOMP] = IPSEC_IPCOMP_LEVEL_DEFAULT;
235 0 : inp->inp_rtableid = curproc->p_p->ps_rtableid;
236 0 : inp->inp_hops = -1;
237 : #ifdef INET6
238 : /*
239 : * Small change in this function to set the INP_IPV6 flag so routines
240 : * outside pcb-specific routines don't need to use sotopf(), and all
241 : * of its pointer chasing, later.
242 : */
243 0 : if (sotopf(so) == PF_INET6)
244 0 : inp->inp_flags = INP_IPV6;
245 0 : inp->inp_cksum6 = -1;
246 : #endif /* INET6 */
247 :
248 0 : if (table->inpt_count++ > INPCBHASH_LOADFACTOR(table->inpt_size))
249 0 : (void)in_pcbresize(table, table->inpt_size * 2);
250 0 : TAILQ_INSERT_HEAD(&table->inpt_queue, inp, inp_queue);
251 0 : head = in_pcblhash(table, inp->inp_rtableid, inp->inp_lport);
252 0 : LIST_INSERT_HEAD(head, inp, inp_lhash);
253 : #ifdef INET6
254 0 : if (sotopf(so) == PF_INET6)
255 0 : head = in6_pcbhash(table, rtable_l2(inp->inp_rtableid),
256 0 : &inp->inp_faddr6, inp->inp_fport,
257 0 : &inp->inp_laddr6, inp->inp_lport);
258 : else
259 : #endif /* INET6 */
260 0 : head = in_pcbhash(table, rtable_l2(inp->inp_rtableid),
261 0 : &inp->inp_faddr, inp->inp_fport,
262 0 : &inp->inp_laddr, inp->inp_lport);
263 0 : LIST_INSERT_HEAD(head, inp, inp_hash);
264 0 : so->so_pcb = inp;
265 :
266 0 : return (0);
267 0 : }
268 :
269 : int
270 0 : in_pcbbind(struct inpcb *inp, struct mbuf *nam, struct proc *p)
271 : {
272 0 : struct socket *so = inp->inp_socket;
273 0 : u_int16_t lport = 0;
274 : int wild = 0;
275 : void *laddr = &zeroin46_addr;
276 : int error;
277 :
278 0 : if (inp->inp_lport)
279 0 : return (EINVAL);
280 :
281 0 : if ((so->so_options & (SO_REUSEADDR|SO_REUSEPORT)) == 0 &&
282 0 : ((so->so_proto->pr_flags & PR_CONNREQUIRED) == 0 ||
283 0 : (so->so_options & SO_ACCEPTCONN) == 0))
284 0 : wild = INPLOOKUP_WILDCARD;
285 :
286 0 : switch (sotopf(so)) {
287 : #ifdef INET6
288 : case PF_INET6:
289 0 : if (!IN6_IS_ADDR_UNSPECIFIED(&inp->inp_laddr6))
290 0 : return (EINVAL);
291 0 : wild |= INPLOOKUP_IPV6;
292 :
293 0 : if (nam) {
294 0 : struct sockaddr_in6 *sin6;
295 :
296 0 : if ((error = in6_nam2sin6(nam, &sin6)))
297 0 : return (error);
298 0 : if ((error = in6_pcbaddrisavail(inp, sin6, wild, p)))
299 0 : return (error);
300 0 : laddr = &sin6->sin6_addr;
301 0 : lport = sin6->sin6_port;
302 0 : }
303 : break;
304 : #endif
305 : case PF_INET:
306 0 : if (inp->inp_laddr.s_addr != INADDR_ANY)
307 0 : return (EINVAL);
308 :
309 0 : if (nam) {
310 0 : struct sockaddr_in *sin;
311 :
312 0 : if ((error = in_nam2sin(nam, &sin)))
313 0 : return (error);
314 0 : if ((error = in_pcbaddrisavail(inp, sin, wild, p)))
315 0 : return (error);
316 0 : laddr = &sin->sin_addr;
317 0 : lport = sin->sin_port;
318 0 : }
319 : break;
320 : default:
321 0 : return (EINVAL);
322 : }
323 :
324 0 : if (lport == 0) {
325 0 : if ((error = in_pcbpickport(&lport, laddr, wild, inp, p)))
326 0 : return (error);
327 : } else {
328 0 : if (in_rootonly(ntohs(lport), so->so_proto->pr_protocol) &&
329 0 : suser(p) != 0)
330 0 : return (EACCES);
331 : }
332 0 : if (nam) {
333 0 : switch (sotopf(so)) {
334 : #ifdef INET6
335 : case PF_INET6:
336 0 : inp->inp_laddr6 = *(struct in6_addr *)laddr;
337 0 : break;
338 : #endif
339 : case PF_INET:
340 0 : inp->inp_laddr = *(struct in_addr *)laddr;
341 0 : break;
342 : }
343 : }
344 0 : inp->inp_lport = lport;
345 0 : in_pcbrehash(inp);
346 0 : return (0);
347 0 : }
348 :
349 : int
350 0 : in_pcbaddrisavail(struct inpcb *inp, struct sockaddr_in *sin, int wild,
351 : struct proc *p)
352 : {
353 0 : struct socket *so = inp->inp_socket;
354 0 : struct inpcbtable *table = inp->inp_table;
355 0 : u_int16_t lport = sin->sin_port;
356 0 : int reuseport = (so->so_options & SO_REUSEPORT);
357 :
358 0 : if (IN_MULTICAST(sin->sin_addr.s_addr)) {
359 : /*
360 : * Treat SO_REUSEADDR as SO_REUSEPORT for multicast;
361 : * allow complete duplication of binding if
362 : * SO_REUSEPORT is set, or if SO_REUSEADDR is set
363 : * and a multicast address is bound on both
364 : * new and duplicated sockets.
365 : */
366 0 : if (so->so_options & (SO_REUSEADDR|SO_REUSEPORT))
367 0 : reuseport = SO_REUSEADDR|SO_REUSEPORT;
368 0 : } else if (sin->sin_addr.s_addr != INADDR_ANY) {
369 : /*
370 : * we must check that we are binding to an address we
371 : * own except when:
372 : * - SO_BINDANY is set or
373 : * - we are binding a UDP socket to 255.255.255.255 or
374 : * - we are binding a UDP socket to one of our broadcast
375 : * addresses
376 : */
377 0 : if (!ISSET(so->so_options, SO_BINDANY) &&
378 0 : !(so->so_type == SOCK_DGRAM &&
379 0 : sin->sin_addr.s_addr == INADDR_BROADCAST) &&
380 0 : !(so->so_type == SOCK_DGRAM &&
381 0 : in_broadcast(sin->sin_addr, inp->inp_rtableid))) {
382 : struct ifaddr *ia;
383 :
384 0 : sin->sin_port = 0;
385 0 : memset(sin->sin_zero, 0, sizeof(sin->sin_zero));
386 0 : ia = ifa_ifwithaddr(sintosa(sin), inp->inp_rtableid);
387 0 : sin->sin_port = lport;
388 :
389 0 : if (ia == NULL)
390 0 : return (EADDRNOTAVAIL);
391 0 : }
392 : }
393 0 : if (lport) {
394 : struct inpcb *t;
395 :
396 0 : if (so->so_euid) {
397 0 : t = in_pcblookup_local(table, &sin->sin_addr, lport,
398 0 : INPLOOKUP_WILDCARD, inp->inp_rtableid);
399 0 : if (t && (so->so_euid != t->inp_socket->so_euid))
400 0 : return (EADDRINUSE);
401 : }
402 0 : t = in_pcblookup_local(table, &sin->sin_addr, lport,
403 0 : wild, inp->inp_rtableid);
404 0 : if (t && (reuseport & t->inp_socket->so_options) == 0)
405 0 : return (EADDRINUSE);
406 0 : }
407 :
408 0 : return (0);
409 0 : }
410 :
411 : int
412 0 : in_pcbpickport(u_int16_t *lport, void *laddr, int wild, struct inpcb *inp,
413 : struct proc *p)
414 : {
415 0 : struct socket *so = inp->inp_socket;
416 0 : struct inpcbtable *table = inp->inp_table;
417 : u_int16_t first, last, lower, higher, candidate, localport;
418 : int count;
419 :
420 0 : if (inp->inp_flags & INP_HIGHPORT) {
421 0 : first = ipport_hifirstauto; /* sysctl */
422 0 : last = ipport_hilastauto;
423 0 : } else if (inp->inp_flags & INP_LOWPORT) {
424 0 : if (suser(p))
425 0 : return (EACCES);
426 : first = IPPORT_RESERVED-1; /* 1023 */
427 : last = 600; /* not IPPORT_RESERVED/2 */
428 0 : } else {
429 0 : first = ipport_firstauto; /* sysctl */
430 0 : last = ipport_lastauto;
431 : }
432 0 : if (first < last) {
433 : lower = first;
434 : higher = last;
435 0 : } else {
436 : lower = last;
437 : higher = first;
438 : }
439 :
440 : /*
441 : * Simple check to ensure all ports are not used up causing
442 : * a deadlock here.
443 : */
444 :
445 0 : count = higher - lower;
446 0 : candidate = lower + arc4random_uniform(count);
447 :
448 0 : do {
449 0 : if (count-- < 0) /* completely used? */
450 0 : return (EADDRNOTAVAIL);
451 0 : ++candidate;
452 0 : if (candidate < lower || candidate > higher)
453 0 : candidate = lower;
454 0 : localport = htons(candidate);
455 0 : } while (in_baddynamic(candidate, so->so_proto->pr_protocol) ||
456 0 : in_pcblookup_local(table, laddr, localport, wild,
457 0 : inp->inp_rtableid));
458 0 : *lport = localport;
459 :
460 0 : return (0);
461 0 : }
462 :
463 : /*
464 : * Connect from a socket to a specified address.
465 : * Both address and port must be specified in argument sin.
466 : * If don't have a local address for this socket yet,
467 : * then pick one.
468 : */
469 : int
470 0 : in_pcbconnect(struct inpcb *inp, struct mbuf *nam)
471 : {
472 0 : struct in_addr *ina = NULL;
473 0 : struct sockaddr_in *sin;
474 0 : int error;
475 :
476 : #ifdef INET6
477 0 : if (sotopf(inp->inp_socket) == PF_INET6)
478 0 : return (in6_pcbconnect(inp, nam));
479 0 : KASSERT((inp->inp_flags & INP_IPV6) == 0);
480 : #endif /* INET6 */
481 :
482 0 : if ((error = in_nam2sin(nam, &sin)))
483 0 : return (error);
484 0 : if (sin->sin_port == 0)
485 0 : return (EADDRNOTAVAIL);
486 0 : error = in_pcbselsrc(&ina, sin, inp);
487 0 : if (error)
488 0 : return (error);
489 :
490 0 : if (in_pcbhashlookup(inp->inp_table, sin->sin_addr, sin->sin_port,
491 0 : *ina, inp->inp_lport, inp->inp_rtableid) != NULL)
492 0 : return (EADDRINUSE);
493 :
494 0 : KASSERT(inp->inp_laddr.s_addr == INADDR_ANY || inp->inp_lport);
495 :
496 0 : if (inp->inp_laddr.s_addr == INADDR_ANY) {
497 0 : if (inp->inp_lport == 0) {
498 0 : error = in_pcbbind(inp, NULL, curproc);
499 0 : if (error)
500 0 : return (error);
501 0 : if (in_pcbhashlookup(inp->inp_table, sin->sin_addr,
502 0 : sin->sin_port, *ina, inp->inp_lport,
503 0 : inp->inp_rtableid) != NULL) {
504 0 : inp->inp_lport = 0;
505 0 : return (EADDRINUSE);
506 : }
507 : }
508 0 : inp->inp_laddr = *ina;
509 0 : }
510 0 : inp->inp_faddr = sin->sin_addr;
511 0 : inp->inp_fport = sin->sin_port;
512 0 : in_pcbrehash(inp);
513 : #ifdef IPSEC
514 : {
515 : /* Cause an IPsec SA to be established. */
516 : /* error is just ignored */
517 0 : ipsp_spd_inp(NULL, AF_INET, 0, &error, IPSP_DIRECTION_OUT,
518 : NULL, inp, NULL);
519 : }
520 : #endif
521 0 : return (0);
522 0 : }
523 :
524 : void
525 0 : in_pcbdisconnect(struct inpcb *inp)
526 : {
527 0 : switch (sotopf(inp->inp_socket)) {
528 : #ifdef INET6
529 : case PF_INET6:
530 0 : inp->inp_faddr6 = in6addr_any;
531 0 : break;
532 : #endif
533 : case PF_INET:
534 0 : inp->inp_faddr.s_addr = INADDR_ANY;
535 0 : break;
536 : }
537 :
538 0 : inp->inp_fport = 0;
539 0 : in_pcbrehash(inp);
540 0 : if (inp->inp_socket->so_state & SS_NOFDREF)
541 0 : in_pcbdetach(inp);
542 0 : }
543 :
544 : void
545 0 : in_pcbdetach(struct inpcb *inp)
546 : {
547 0 : struct socket *so = inp->inp_socket;
548 :
549 0 : NET_ASSERT_LOCKED();
550 :
551 0 : so->so_pcb = NULL;
552 : /*
553 : * As long as the NET_LOCK() is the default lock for Internet
554 : * sockets, do not release it to not introduce new sleeping
555 : * points.
556 : */
557 0 : sofree(so, SL_NOUNLOCK);
558 0 : m_freem(inp->inp_options);
559 0 : if (inp->inp_route.ro_rt) {
560 0 : rtfree(inp->inp_route.ro_rt);
561 0 : inp->inp_route.ro_rt = NULL;
562 0 : }
563 : #ifdef INET6
564 0 : if (inp->inp_flags & INP_IPV6) {
565 0 : ip6_freepcbopts(inp->inp_outputopts6);
566 0 : ip6_freemoptions(inp->inp_moptions6);
567 0 : } else
568 : #endif
569 0 : ip_freemoptions(inp->inp_moptions);
570 : #if NPF > 0
571 0 : if (inp->inp_pf_sk) {
572 0 : pf_remove_divert_state(inp->inp_pf_sk);
573 : /* pf_remove_divert_state() may have detached the state */
574 0 : pf_inp_unlink(inp);
575 0 : }
576 : #endif
577 0 : LIST_REMOVE(inp, inp_lhash);
578 0 : LIST_REMOVE(inp, inp_hash);
579 0 : TAILQ_REMOVE(&inp->inp_table->inpt_queue, inp, inp_queue);
580 0 : inp->inp_table->inpt_count--;
581 0 : in_pcbunref(inp);
582 0 : }
583 :
584 : struct inpcb *
585 0 : in_pcbref(struct inpcb *inp)
586 : {
587 0 : if (inp != NULL)
588 0 : refcnt_take(&inp->inp_refcnt);
589 0 : return inp;
590 : }
591 :
592 : void
593 0 : in_pcbunref(struct inpcb *inp)
594 : {
595 0 : if (refcnt_rele(&inp->inp_refcnt)) {
596 0 : KASSERT((LIST_NEXT(inp, inp_hash) == NULL) ||
597 : (LIST_NEXT(inp, inp_hash) == _Q_INVALID));
598 0 : KASSERT((LIST_NEXT(inp, inp_lhash) == NULL) ||
599 : (LIST_NEXT(inp, inp_lhash) == _Q_INVALID));
600 0 : KASSERT((TAILQ_NEXT(inp, inp_queue) == NULL) ||
601 : (TAILQ_NEXT(inp, inp_queue) == _Q_INVALID));
602 0 : pool_put(&inpcb_pool, inp);
603 0 : }
604 0 : }
605 :
606 : void
607 0 : in_setsockaddr(struct inpcb *inp, struct mbuf *nam)
608 : {
609 : struct sockaddr_in *sin;
610 :
611 0 : nam->m_len = sizeof(*sin);
612 0 : sin = mtod(nam, struct sockaddr_in *);
613 0 : memset(sin, 0, sizeof(*sin));
614 0 : sin->sin_family = AF_INET;
615 0 : sin->sin_len = sizeof(*sin);
616 0 : sin->sin_port = inp->inp_lport;
617 0 : sin->sin_addr = inp->inp_laddr;
618 0 : }
619 :
620 : void
621 0 : in_setpeeraddr(struct inpcb *inp, struct mbuf *nam)
622 : {
623 : struct sockaddr_in *sin;
624 :
625 : #ifdef INET6
626 0 : if (sotopf(inp->inp_socket) == PF_INET6) {
627 0 : in6_setpeeraddr(inp, nam);
628 0 : return;
629 : }
630 : #endif /* INET6 */
631 :
632 0 : nam->m_len = sizeof(*sin);
633 0 : sin = mtod(nam, struct sockaddr_in *);
634 0 : memset(sin, 0, sizeof(*sin));
635 0 : sin->sin_family = AF_INET;
636 0 : sin->sin_len = sizeof(*sin);
637 0 : sin->sin_port = inp->inp_fport;
638 0 : sin->sin_addr = inp->inp_faddr;
639 0 : }
640 :
641 : /*
642 : * Pass some notification to all connections of a protocol
643 : * associated with address dst. The "usual action" will be
644 : * taken, depending on the ctlinput cmd. The caller must filter any
645 : * cmds that are uninteresting (e.g., no error in the map).
646 : * Call the protocol specific routine (if any) to report
647 : * any errors for each matching socket.
648 : */
649 : void
650 0 : in_pcbnotifyall(struct inpcbtable *table, struct sockaddr *dst, u_int rtable,
651 : int errno, void (*notify)(struct inpcb *, int))
652 : {
653 : struct inpcb *inp, *ninp;
654 : struct in_addr faddr;
655 : u_int rdomain;
656 :
657 0 : NET_ASSERT_LOCKED();
658 :
659 : #ifdef INET6
660 : /*
661 : * See in6_pcbnotify() for IPv6 codepath. By the time this
662 : * gets called, the addresses passed are either definitely IPv4 or
663 : * IPv6; *_pcbnotify() never gets called with v4-mapped v6 addresses.
664 : */
665 : #endif /* INET6 */
666 :
667 0 : if (dst->sa_family != AF_INET)
668 0 : return;
669 0 : faddr = satosin(dst)->sin_addr;
670 0 : if (faddr.s_addr == INADDR_ANY)
671 0 : return;
672 :
673 0 : rdomain = rtable_l2(rtable);
674 0 : TAILQ_FOREACH_SAFE(inp, &table->inpt_queue, inp_queue, ninp) {
675 : #ifdef INET6
676 0 : if (inp->inp_flags & INP_IPV6)
677 : continue;
678 : #endif
679 0 : if (inp->inp_faddr.s_addr != faddr.s_addr ||
680 0 : rtable_l2(inp->inp_rtableid) != rdomain ||
681 0 : inp->inp_socket == 0) {
682 : continue;
683 : }
684 0 : if (notify)
685 0 : (*notify)(inp, errno);
686 : }
687 0 : }
688 :
689 : /*
690 : * Check for alternatives when higher level complains
691 : * about service problems. For now, invalidate cached
692 : * routing information. If the route was created dynamically
693 : * (by a redirect), time to try a default gateway again.
694 : */
695 : void
696 0 : in_losing(struct inpcb *inp)
697 : {
698 0 : struct rtentry *rt = inp->inp_route.ro_rt;
699 :
700 0 : if (rt) {
701 0 : inp->inp_route.ro_rt = NULL;
702 :
703 0 : if (rt->rt_flags & RTF_DYNAMIC) {
704 : struct ifnet *ifp;
705 :
706 0 : ifp = if_get(rt->rt_ifidx);
707 : /*
708 : * If the interface is gone, all its attached
709 : * route entries have been removed from the table,
710 : * so we're dealing with a stale cache and have
711 : * nothing to do.
712 : */
713 0 : if (ifp != NULL)
714 0 : rtdeletemsg(rt, ifp, inp->inp_rtableid);
715 0 : if_put(ifp);
716 0 : }
717 : /*
718 : * A new route can be allocated
719 : * the next time output is attempted.
720 : * rtfree() needs to be called in anycase because the inp
721 : * is still holding a reference to rt.
722 : */
723 0 : rtfree(rt);
724 0 : }
725 0 : }
726 :
727 : /*
728 : * After a routing change, flush old routing
729 : * and allocate a (hopefully) better one.
730 : */
731 : void
732 0 : in_rtchange(struct inpcb *inp, int errno)
733 : {
734 0 : if (inp->inp_route.ro_rt) {
735 0 : rtfree(inp->inp_route.ro_rt);
736 0 : inp->inp_route.ro_rt = 0;
737 : /*
738 : * A new route can be allocated the next time
739 : * output is attempted.
740 : */
741 0 : }
742 0 : }
743 :
744 : struct inpcb *
745 0 : in_pcblookup_local(struct inpcbtable *table, void *laddrp, u_int lport_arg,
746 : int flags, u_int rtable)
747 : {
748 : struct inpcb *inp, *match = NULL;
749 : int matchwild = 3, wildcard;
750 0 : u_int16_t lport = lport_arg;
751 0 : struct in_addr laddr = *(struct in_addr *)laddrp;
752 : #ifdef INET6
753 0 : struct in6_addr *laddr6 = (struct in6_addr *)laddrp;
754 : #endif
755 : struct inpcbhead *head;
756 : u_int rdomain;
757 :
758 0 : rdomain = rtable_l2(rtable);
759 0 : head = in_pcblhash(table, rdomain, lport);
760 0 : LIST_FOREACH(inp, head, inp_lhash) {
761 0 : if (rtable_l2(inp->inp_rtableid) != rdomain)
762 : continue;
763 0 : if (inp->inp_lport != lport)
764 : continue;
765 : wildcard = 0;
766 : #ifdef INET6
767 0 : if (ISSET(flags, INPLOOKUP_IPV6)) {
768 0 : if (!ISSET(inp->inp_flags, INP_IPV6))
769 : continue;
770 :
771 0 : if (!IN6_IS_ADDR_UNSPECIFIED(&inp->inp_faddr6))
772 0 : wildcard++;
773 :
774 0 : if (!IN6_ARE_ADDR_EQUAL(&inp->inp_laddr6, laddr6)) {
775 0 : if (IN6_IS_ADDR_UNSPECIFIED(&inp->inp_laddr6) ||
776 0 : IN6_IS_ADDR_UNSPECIFIED(laddr6))
777 0 : wildcard++;
778 : else
779 : continue;
780 0 : }
781 :
782 : } else
783 : #endif /* INET6 */
784 : {
785 : #ifdef INET6
786 0 : if (ISSET(inp->inp_flags, INP_IPV6))
787 : continue;
788 : #endif /* INET6 */
789 :
790 0 : if (inp->inp_faddr.s_addr != INADDR_ANY)
791 0 : wildcard++;
792 :
793 0 : if (inp->inp_laddr.s_addr != laddr.s_addr) {
794 0 : if (inp->inp_laddr.s_addr == INADDR_ANY ||
795 0 : laddr.s_addr == INADDR_ANY)
796 0 : wildcard++;
797 : else
798 : continue;
799 0 : }
800 :
801 : }
802 0 : if ((!wildcard || (flags & INPLOOKUP_WILDCARD)) &&
803 0 : wildcard < matchwild) {
804 : match = inp;
805 0 : if ((matchwild = wildcard) == 0)
806 : break;
807 : }
808 : }
809 0 : return (match);
810 : }
811 :
812 : struct rtentry *
813 0 : in_pcbrtentry(struct inpcb *inp)
814 : {
815 : struct route *ro;
816 :
817 0 : ro = &inp->inp_route;
818 :
819 : /* check if route is still valid */
820 0 : if (!rtisvalid(ro->ro_rt)) {
821 0 : rtfree(ro->ro_rt);
822 0 : ro->ro_rt = NULL;
823 0 : }
824 :
825 : /*
826 : * No route yet, so try to acquire one.
827 : */
828 0 : if (ro->ro_rt == NULL) {
829 : #ifdef INET6
830 0 : memset(ro, 0, sizeof(struct route_in6));
831 : #else
832 : memset(ro, 0, sizeof(struct route));
833 : #endif
834 :
835 0 : switch(sotopf(inp->inp_socket)) {
836 : #ifdef INET6
837 : case PF_INET6:
838 0 : if (IN6_IS_ADDR_UNSPECIFIED(&inp->inp_faddr6))
839 : break;
840 0 : ro->ro_dst.sa_family = AF_INET6;
841 0 : ro->ro_dst.sa_len = sizeof(struct sockaddr_in6);
842 0 : satosin6(&ro->ro_dst)->sin6_addr = inp->inp_faddr6;
843 0 : ro->ro_tableid = inp->inp_rtableid;
844 0 : ro->ro_rt = rtalloc_mpath(&ro->ro_dst,
845 0 : &inp->inp_laddr6.s6_addr32[0], ro->ro_tableid);
846 0 : break;
847 : #endif /* INET6 */
848 : case PF_INET:
849 0 : if (inp->inp_faddr.s_addr == INADDR_ANY)
850 : break;
851 0 : ro->ro_dst.sa_family = AF_INET;
852 0 : ro->ro_dst.sa_len = sizeof(struct sockaddr_in);
853 0 : satosin(&ro->ro_dst)->sin_addr = inp->inp_faddr;
854 0 : ro->ro_tableid = inp->inp_rtableid;
855 0 : ro->ro_rt = rtalloc_mpath(&ro->ro_dst,
856 0 : &inp->inp_laddr.s_addr, ro->ro_tableid);
857 0 : break;
858 : }
859 : }
860 0 : return (ro->ro_rt);
861 : }
862 :
863 : /*
864 : * Return an IPv4 address, which is the most appropriate for a given
865 : * destination.
866 : * If necessary, this function lookups the routing table and returns
867 : * an entry to the caller for later use.
868 : */
869 : int
870 0 : in_pcbselsrc(struct in_addr **insrc, struct sockaddr_in *sin,
871 : struct inpcb *inp)
872 : {
873 0 : struct ip_moptions *mopts = inp->inp_moptions;
874 0 : struct route *ro = &inp->inp_route;
875 0 : struct in_addr *laddr = &inp->inp_laddr;
876 0 : u_int rtableid = inp->inp_rtableid;
877 :
878 : struct sockaddr_in *sin2;
879 : struct in_ifaddr *ia = NULL;
880 :
881 : /*
882 : * If the socket(if any) is already bound, use that bound address
883 : * unless it is INADDR_ANY or INADDR_BROADCAST.
884 : */
885 0 : if (laddr && laddr->s_addr != INADDR_ANY &&
886 0 : laddr->s_addr != INADDR_BROADCAST) {
887 0 : *insrc = laddr;
888 0 : return (0);
889 : }
890 :
891 : /*
892 : * If the destination address is multicast and an outgoing
893 : * interface has been set as a multicast option, use the
894 : * address of that interface as our source address.
895 : */
896 0 : if (IN_MULTICAST(sin->sin_addr.s_addr) && mopts != NULL) {
897 : struct ifnet *ifp;
898 :
899 0 : ifp = if_get(mopts->imo_ifidx);
900 0 : if (ifp != NULL) {
901 0 : if (ifp->if_rdomain == rtable_l2(rtableid))
902 0 : IFP_TO_IA(ifp, ia);
903 0 : if (ia == NULL) {
904 0 : if_put(ifp);
905 0 : return (EADDRNOTAVAIL);
906 : }
907 :
908 0 : *insrc = &ia->ia_addr.sin_addr;
909 0 : if_put(ifp);
910 0 : return (0);
911 : }
912 0 : }
913 : /*
914 : * If route is known or can be allocated now,
915 : * our src addr is taken from the i/f, else punt.
916 : */
917 0 : if (!rtisvalid(ro->ro_rt) || (ro->ro_tableid != rtableid) ||
918 0 : (satosin(&ro->ro_dst)->sin_addr.s_addr != sin->sin_addr.s_addr)) {
919 0 : rtfree(ro->ro_rt);
920 0 : ro->ro_rt = NULL;
921 0 : }
922 0 : if (ro->ro_rt == NULL) {
923 : /* No route yet, so try to acquire one */
924 0 : ro->ro_dst.sa_family = AF_INET;
925 0 : ro->ro_dst.sa_len = sizeof(struct sockaddr_in);
926 0 : satosin(&ro->ro_dst)->sin_addr = sin->sin_addr;
927 0 : ro->ro_tableid = rtableid;
928 0 : ro->ro_rt = rtalloc_mpath(&ro->ro_dst, NULL, ro->ro_tableid);
929 :
930 : /*
931 : * It is important to zero out the rest of the
932 : * struct sockaddr_in when mixing v6 & v4!
933 : */
934 0 : sin2 = satosin(&ro->ro_dst);
935 0 : memset(sin2->sin_zero, 0, sizeof(sin2->sin_zero));
936 0 : }
937 : /*
938 : * If we found a route, use the address
939 : * corresponding to the outgoing interface.
940 : */
941 0 : if (ro->ro_rt != NULL)
942 0 : ia = ifatoia(ro->ro_rt->rt_ifa);
943 :
944 0 : if (ia == NULL)
945 0 : return (EADDRNOTAVAIL);
946 :
947 0 : *insrc = &ia->ia_addr.sin_addr;
948 0 : return (0);
949 0 : }
950 :
951 : void
952 0 : in_pcbrehash(struct inpcb *inp)
953 : {
954 0 : struct inpcbtable *table = inp->inp_table;
955 : struct inpcbhead *head;
956 :
957 0 : NET_ASSERT_LOCKED();
958 :
959 0 : LIST_REMOVE(inp, inp_lhash);
960 0 : head = in_pcblhash(table, inp->inp_rtableid, inp->inp_lport);
961 0 : LIST_INSERT_HEAD(head, inp, inp_lhash);
962 0 : LIST_REMOVE(inp, inp_hash);
963 : #ifdef INET6
964 0 : if (inp->inp_flags & INP_IPV6)
965 0 : head = in6_pcbhash(table, rtable_l2(inp->inp_rtableid),
966 0 : &inp->inp_faddr6, inp->inp_fport,
967 0 : &inp->inp_laddr6, inp->inp_lport);
968 : else
969 : #endif /* INET6 */
970 0 : head = in_pcbhash(table, rtable_l2(inp->inp_rtableid),
971 0 : &inp->inp_faddr, inp->inp_fport,
972 0 : &inp->inp_laddr, inp->inp_lport);
973 0 : LIST_INSERT_HEAD(head, inp, inp_hash);
974 0 : }
975 :
976 : int
977 0 : in_pcbresize(struct inpcbtable *table, int hashsize)
978 : {
979 0 : u_long nmask, nlmask;
980 : int osize;
981 : void *nhashtbl, *nlhashtbl, *ohashtbl, *olhashtbl;
982 : struct inpcb *inp;
983 :
984 0 : ohashtbl = table->inpt_hashtbl;
985 0 : olhashtbl = table->inpt_lhashtbl;
986 0 : osize = table->inpt_size;
987 :
988 0 : nhashtbl = hashinit(hashsize, M_PCB, M_NOWAIT, &nmask);
989 0 : if (nhashtbl == NULL)
990 0 : return ENOBUFS;
991 0 : nlhashtbl = hashinit(hashsize, M_PCB, M_NOWAIT, &nlmask);
992 0 : if (nlhashtbl == NULL) {
993 0 : hashfree(nhashtbl, hashsize, M_PCB);
994 0 : return ENOBUFS;
995 : }
996 0 : table->inpt_hashtbl = nhashtbl;
997 0 : table->inpt_lhashtbl = nlhashtbl;
998 0 : table->inpt_mask = nmask;
999 0 : table->inpt_lmask = nlmask;
1000 0 : table->inpt_size = hashsize;
1001 0 : arc4random_buf(&table->inpt_key, sizeof(table->inpt_key));
1002 :
1003 0 : TAILQ_FOREACH(inp, &table->inpt_queue, inp_queue) {
1004 0 : in_pcbrehash(inp);
1005 : }
1006 0 : hashfree(ohashtbl, osize, M_PCB);
1007 0 : hashfree(olhashtbl, osize, M_PCB);
1008 :
1009 0 : return (0);
1010 0 : }
1011 :
1012 : #ifdef DIAGNOSTIC
1013 : int in_pcbnotifymiss = 0;
1014 : #endif
1015 :
1016 : /*
1017 : * The in(6)_pcbhashlookup functions are used to locate connected sockets
1018 : * quickly:
1019 : * faddr.fport <-> laddr.lport
1020 : * No wildcard matching is done so that listening sockets are not found.
1021 : * If the functions return NULL in(6)_pcblookup_listen can be used to
1022 : * find a listening/bound socket that may accept the connection.
1023 : * After those two lookups no other are necessary.
1024 : */
1025 : struct inpcb *
1026 0 : in_pcbhashlookup(struct inpcbtable *table, struct in_addr faddr,
1027 : u_int fport_arg, struct in_addr laddr, u_int lport_arg, u_int rtable)
1028 : {
1029 : struct inpcbhead *head;
1030 : struct inpcb *inp;
1031 0 : u_int16_t fport = fport_arg, lport = lport_arg;
1032 : u_int rdomain;
1033 :
1034 0 : rdomain = rtable_l2(rtable);
1035 0 : head = in_pcbhash(table, rdomain, &faddr, fport, &laddr, lport);
1036 0 : LIST_FOREACH(inp, head, inp_hash) {
1037 : #ifdef INET6
1038 0 : if (inp->inp_flags & INP_IPV6)
1039 : continue; /*XXX*/
1040 : #endif
1041 0 : if (inp->inp_faddr.s_addr == faddr.s_addr &&
1042 0 : inp->inp_fport == fport && inp->inp_lport == lport &&
1043 0 : inp->inp_laddr.s_addr == laddr.s_addr &&
1044 0 : rtable_l2(inp->inp_rtableid) == rdomain) {
1045 : /*
1046 : * Move this PCB to the head of hash chain so that
1047 : * repeated accesses are quicker. This is analogous to
1048 : * the historic single-entry PCB cache.
1049 : */
1050 0 : if (inp != LIST_FIRST(head)) {
1051 0 : LIST_REMOVE(inp, inp_hash);
1052 0 : LIST_INSERT_HEAD(head, inp, inp_hash);
1053 0 : }
1054 : break;
1055 : }
1056 : }
1057 : #ifdef DIAGNOSTIC
1058 0 : if (inp == NULL && in_pcbnotifymiss) {
1059 0 : printf("%s: faddr=%08x fport=%d laddr=%08x lport=%d rdom=%u\n",
1060 0 : __func__, ntohl(faddr.s_addr), ntohs(fport),
1061 0 : ntohl(laddr.s_addr), ntohs(lport), rdomain);
1062 0 : }
1063 : #endif
1064 0 : return (inp);
1065 : }
1066 :
1067 : /*
1068 : * The in(6)_pcblookup_listen functions are used to locate listening
1069 : * sockets quickly. This are sockets with unspecified foreign address
1070 : * and port:
1071 : * *.* <-> laddr.lport
1072 : * *.* <-> *.lport
1073 : */
1074 : struct inpcb *
1075 0 : in_pcblookup_listen(struct inpcbtable *table, struct in_addr laddr,
1076 : u_int lport_arg, struct mbuf *m, u_int rtable)
1077 : {
1078 : struct inpcbhead *head;
1079 : const struct in_addr *key1, *key2;
1080 : struct inpcb *inp;
1081 0 : u_int16_t lport = lport_arg;
1082 : u_int rdomain;
1083 :
1084 : key1 = &laddr;
1085 : key2 = &zeroin_addr;
1086 : #if NPF > 0
1087 0 : if (m && m->m_pkthdr.pf.flags & PF_TAG_DIVERTED) {
1088 : struct pf_divert *divert;
1089 :
1090 0 : divert = pf_find_divert(m);
1091 0 : KASSERT(divert != NULL);
1092 0 : switch (divert->type) {
1093 : case PF_DIVERT_TO:
1094 0 : key1 = key2 = &divert->addr.v4;
1095 0 : lport = divert->port;
1096 : break;
1097 : case PF_DIVERT_REPLY:
1098 0 : return (NULL);
1099 : default:
1100 0 : panic("%s: unknown divert type %d, mbuf %p, divert %p",
1101 : __func__, divert->type, m, divert);
1102 : }
1103 0 : } else if (m && m->m_pkthdr.pf.flags & PF_TAG_TRANSLATE_LOCALHOST) {
1104 : /*
1105 : * Redirected connections should not be treated the same
1106 : * as connections directed to 127.0.0.0/8 since localhost
1107 : * can only be accessed from the host itself.
1108 : * For example portmap(8) grants more permissions for
1109 : * connections to the socket bound to 127.0.0.1 than
1110 : * to the * socket.
1111 : */
1112 : key1 = &zeroin_addr;
1113 : key2 = &laddr;
1114 0 : }
1115 : #endif
1116 :
1117 0 : rdomain = rtable_l2(rtable);
1118 0 : head = in_pcbhash(table, rdomain, &zeroin_addr, 0, key1, lport);
1119 0 : LIST_FOREACH(inp, head, inp_hash) {
1120 : #ifdef INET6
1121 0 : if (inp->inp_flags & INP_IPV6)
1122 : continue; /*XXX*/
1123 : #endif
1124 0 : if (inp->inp_lport == lport && inp->inp_fport == 0 &&
1125 0 : inp->inp_laddr.s_addr == key1->s_addr &&
1126 0 : inp->inp_faddr.s_addr == INADDR_ANY &&
1127 0 : rtable_l2(inp->inp_rtableid) == rdomain)
1128 : break;
1129 : }
1130 0 : if (inp == NULL && key1->s_addr != key2->s_addr) {
1131 0 : head = in_pcbhash(table, rdomain,
1132 : &zeroin_addr, 0, key2, lport);
1133 0 : LIST_FOREACH(inp, head, inp_hash) {
1134 : #ifdef INET6
1135 0 : if (inp->inp_flags & INP_IPV6)
1136 : continue; /*XXX*/
1137 : #endif
1138 0 : if (inp->inp_lport == lport && inp->inp_fport == 0 &&
1139 0 : inp->inp_laddr.s_addr == key2->s_addr &&
1140 0 : inp->inp_faddr.s_addr == INADDR_ANY &&
1141 0 : rtable_l2(inp->inp_rtableid) == rdomain)
1142 : break;
1143 : }
1144 : }
1145 : /*
1146 : * Move this PCB to the head of hash chain so that
1147 : * repeated accesses are quicker. This is analogous to
1148 : * the historic single-entry PCB cache.
1149 : */
1150 0 : if (inp != NULL && inp != LIST_FIRST(head)) {
1151 0 : LIST_REMOVE(inp, inp_hash);
1152 0 : LIST_INSERT_HEAD(head, inp, inp_hash);
1153 0 : }
1154 : #ifdef DIAGNOSTIC
1155 0 : if (inp == NULL && in_pcbnotifymiss) {
1156 0 : printf("%s: laddr=%08x lport=%d rdom=%u\n",
1157 0 : __func__, ntohl(laddr.s_addr), ntohs(lport), rdomain);
1158 0 : }
1159 : #endif
1160 0 : return (inp);
1161 0 : }
|