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