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