2 * Copyright (c) 1982, 1986, 1991, 1993, 1995
3 * The Regents of the University of California. All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by the University of
16 * California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * @(#)in_pcb.c 8.2 (Berkeley) 1/4/94
36 #include <sys/param.h>
37 #include <sys/systm.h>
38 #include <sys/malloc.h>
40 #include <sys/protosw.h>
41 #include <sys/socket.h>
42 #include <sys/socketvar.h>
43 #include <sys/ioctl.h>
44 #include <sys/errno.h>
47 #include <sys/queue.h>
50 #include <net/route.h>
52 #include <netinet/in.h>
53 #include <netinet/in_systm.h>
54 #include <netinet/ip.h>
55 #include <netinet/in_pcb.h>
56 #include <netinet/in_var.h>
57 #include <netinet/ip_var.h>
61 struct in_addr zeroin_addr
;
64 in_pcballoc(so
, pcbinfo
)
66 struct inpcbinfo
*pcbinfo
;
68 register struct inpcb
*inp
;
71 MALLOC(inp
, struct inpcb
*, sizeof(*inp
), M_PCB
, M_NOWAIT
);
74 bzero((caddr_t
)inp
, sizeof(*inp
));
75 inp
->inp_pcbinfo
= pcbinfo
;
78 LIST_INSERT_HEAD(pcbinfo
->listhead
, inp
, inp_list
);
81 so
->so_pcb
= (caddr_t
)inp
;
87 register struct inpcb
*inp
;
90 register struct socket
*so
= inp
->inp_socket
;
91 struct inpcbhead
*head
= inp
->inp_pcbinfo
->listhead
;
92 unsigned short *lastport
= &inp
->inp_pcbinfo
->lastport
;
93 struct sockaddr_in
*sin
;
95 struct proc
*p
= curproc
; /* XXX */
98 int wild
= 0, reuseport
= (so
->so_options
& SO_REUSEPORT
);
103 OS_DbgPrint(OSK_MID_TRACE
,("Called\n"));
105 if( nam
) OskitDumpBuffer( nam
->m_data
, nam
->m_len
);
108 if (in_ifaddr
== 0) {
109 OS_DbgPrint(OSK_MID_TRACE
,("Leaving EADDRNOTAVAIL\n"));
110 return (EADDRNOTAVAIL
);
113 if (inp
->inp_lport
|| inp
->inp_laddr
.s_addr
!= INADDR_ANY
)
115 if ((so
->so_options
& (SO_REUSEADDR
|SO_REUSEPORT
)) == 0 &&
116 ((so
->so_proto
->pr_flags
& PR_CONNREQUIRED
) == 0 ||
117 (so
->so_options
& SO_ACCEPTCONN
) == 0))
118 wild
= INPLOOKUP_WILDCARD
;
120 sin
= mtod(nam
, struct sockaddr_in
*);
121 if (nam
->m_len
!= sizeof (*sin
)) {
122 OS_DbgPrint(OSK_MID_TRACE
,("Leaving EINVAL\n"));
127 * We should check the family, but old programs
128 * incorrectly fail to initialize it.
130 if (sin
->sin_family
!= AF_INET
) {
131 OS_DbgPrint(OSK_MID_TRACE
,("Leaving EAFNOSUPPORT\n"));
132 return (EAFNOSUPPORT
);
135 lport
= sin
->sin_port
;
136 if (IN_MULTICAST(ntohl(sin
->sin_addr
.s_addr
))) {
138 * Treat SO_REUSEADDR as SO_REUSEPORT for multicast;
139 * allow complete duplication of binding if
140 * SO_REUSEPORT is set, or if SO_REUSEADDR is set
141 * and a multicast address is bound on both
142 * new and duplicated sockets.
144 if (so
->so_options
& SO_REUSEADDR
)
145 reuseport
= SO_REUSEADDR
|SO_REUSEPORT
;
146 } else if (sin
->sin_addr
.s_addr
!= INADDR_ANY
) {
147 sin
->sin_port
= 0; /* yech... */
148 OS_DbgPrint(OSK_MID_TRACE
,("Calling ifwithaddr\n"));
149 if (ifa_ifwithaddr((struct sockaddr
*)sin
) == 0) {
150 OS_DbgPrint(OSK_MID_TRACE
,
151 ("Leaving EADDRNOTAVAIL\n"));
152 return (EADDRNOTAVAIL
);
154 OS_DbgPrint(OSK_MID_TRACE
,("Yep, we have that addr\n"));
161 if (ntohs(lport
) < IPPORT_RESERVED
&&
162 (error
= suser(p
->p_ucred
, &p
->p_acflag
))) {
163 OS_DbgPrint(OSK_MID_TRACE
,
164 ("Leaving EACCESS\n"));
168 t
= in_pcblookup(head
, zeroin_addr
, 0,
169 sin
->sin_addr
, lport
, wild
);
170 if (t
&& (reuseport
& t
->inp_socket
->so_options
) == 0)
172 OS_DbgPrint(OSK_MID_TRACE
,
173 ("Leaving EADDRINUSE\n"));
177 inp
->inp_laddr
= sin
->sin_addr
;
182 OS_DbgPrint(OSK_MID_TRACE
,("Finding port %d\n",
184 if (*lastport
< IPPORT_RESERVED
||
185 *lastport
> IPPORT_USERRESERVED
)
186 *lastport
= IPPORT_RESERVED
;
187 lport
= htons(*lastport
);
188 } while (in_pcblookup(head
,
189 zeroin_addr
, 0, inp
->inp_laddr
,
191 inp
->inp_lport
= lport
;
194 OS_DbgPrint(OSK_MID_TRACE
,("Returning success\n"));
199 * Transform old in_pcbconnect() into an inner subroutine for new
200 * in_pcbconnect(): Do some validity-checking on the remote
201 * address (in mbuf 'nam') and then determine local host address
202 * (i.e., which interface) to use to access that remote host.
204 * This preserves definition of in_pcbconnect(), while supporting a
205 * slightly different version for T/TCP. (This is more than
206 * a bit of a kludge, but cleaning up the internal interfaces would
207 * have forced minor changes in every protocol).
211 in_pcbladdr(inp
, nam
, plocal_sin
)
212 register struct inpcb
*inp
;
214 struct sockaddr_in
**plocal_sin
;
216 struct in_ifaddr
*ia
;
218 struct sockaddr_in
*ifaddr
= 0;
220 register struct sockaddr_in
*sin
= mtod(nam
, struct sockaddr_in
*);
222 OS_DbgPrint(OSK_MID_TRACE
,("Called\n"));
224 if (nam
->m_len
!= sizeof (*sin
))
226 if (sin
->sin_family
!= AF_INET
)
227 return (EAFNOSUPPORT
);
228 if (sin
->sin_port
== 0)
229 return (EADDRNOTAVAIL
);
232 * If the destination address is INADDR_ANY,
233 * use the primary local address.
234 * If the supplied address is INADDR_BROADCAST,
235 * and the primary interface supports broadcast,
236 * choose the broadcast address for that interface.
238 #define satosin(sa) ((struct sockaddr_in *)(sa))
239 #define sintosa(sin) ((struct sockaddr *)(sin))
240 #define ifatoia(ifa) ((struct in_ifaddr *)(ifa))
241 if (sin
->sin_addr
.s_addr
== INADDR_ANY
)
242 sin
->sin_addr
= IA_SIN(in_ifaddr
)->sin_addr
;
244 else if (sin
->sin_addr
.s_addr
== (u_long
)INADDR_BROADCAST
&&
245 (in_ifaddr
->ia_ifp
->if_flags
& IFF_BROADCAST
))
246 sin
->sin_addr
= satosin(&in_ifaddr
->ia_broadaddr
)->sin_addr
;
249 if (inp
->inp_laddr
.s_addr
== INADDR_ANY
) {
250 register struct route
*ro
;
252 ia
= (struct in_ifaddr
*)0;
254 * If route is known or can be allocated now,
255 * our src addr is taken from the i/f, else punt.
257 ro
= &inp
->inp_route
;
259 (satosin(&ro
->ro_dst
)->sin_addr
.s_addr
!=
260 sin
->sin_addr
.s_addr
||
261 inp
->inp_socket
->so_options
& SO_DONTROUTE
)) {
263 ro
->ro_rt
= (struct rtentry
*)0;
265 if ((inp
->inp_socket
->so_options
& SO_DONTROUTE
) == 0 && /*XXX*/
266 (ro
->ro_rt
== (struct rtentry
*)0 ||
267 ro
->ro_rt
->rt_ifp
== (struct ifnet
*)0)) {
268 /* No route yet, so try to acquire one */
269 ro
->ro_dst
.sa_family
= AF_INET
;
270 ro
->ro_dst
.sa_len
= sizeof(struct sockaddr_in
);
271 ((struct sockaddr_in
*) &ro
->ro_dst
)->sin_addr
=
276 * If we found a route, use the address
277 * corresponding to the outgoing interface
278 * unless it is the loopback (in case a route
279 * to our address on another net goes to loopback).
281 if (ro
->ro_rt
&& !(ro
->ro_rt
->rt_ifp
->if_flags
& IFF_LOOPBACK
))
282 ia
= ifatoia(ro
->ro_rt
->rt_ifa
);
284 u_short fport
= sin
->sin_port
;
287 ia
= ifatoia(ifa_ifwithdstaddr(sintosa(sin
)));
290 ia
= ifatoia(ifa_ifwithnet(sintosa(sin
)));
291 sin
->sin_port
= fport
;
295 return (EADDRNOTAVAIL
);
298 * If the destination address is multicast and an outgoing
299 * interface has been set as a multicast option, use the
300 * address of that interface as our source address.
303 if (IN_MULTICAST(ntohl(sin
->sin_addr
.s_addr
)) &&
304 inp
->inp_moptions
!= NULL
) {
305 struct ip_moptions
*imo
;
308 imo
= inp
->inp_moptions
;
309 if (imo
->imo_multicast_ifp
!= NULL
) {
310 ifp
= imo
->imo_multicast_ifp
;
311 for (ia
= in_ifaddr
; ia
; ia
= ia
->ia_next
)
312 if (ia
->ia_ifp
== ifp
)
315 return (EADDRNOTAVAIL
);
320 * Don't do pcblookup call here; return interface in plocal_sin
321 * and exit to caller, that will do the lookup.
323 *plocal_sin
= (struct sockaddr_in
*)ia
->ia_ifa
.ifa_addr
;
324 OS_DbgPrint(OSK_MID_TRACE
,("plocal sin %x\n",
325 (*plocal_sin
)->sin_addr
.s_addr
));
333 * Connect from a socket to a specified address.
334 * Both address and port must be specified in argument sin.
335 * If don't have a local address for this socket yet,
339 in_pcbconnect(inp
, nam
)
340 register struct inpcb
*inp
;
343 struct sockaddr_in
*ifaddr
;
344 register struct sockaddr_in
*sin
= mtod(nam
, struct sockaddr_in
*);
348 * Call inner routine, to assign local interface address.
350 if ((error
= in_pcbladdr(inp
, nam
, &ifaddr
)))
353 if (in_pcblookuphash(inp
->inp_pcbinfo
, sin
->sin_addr
, sin
->sin_port
,
354 inp
->inp_laddr
.s_addr
? inp
->inp_laddr
: ifaddr
->sin_addr
,
355 inp
->inp_lport
) != NULL
)
357 if (inp
->inp_laddr
.s_addr
== INADDR_ANY
) {
358 if (inp
->inp_lport
== 0)
359 (void)in_pcbbind(inp
, (struct mbuf
*)0);
360 inp
->inp_laddr
= ifaddr
->sin_addr
;
362 inp
->inp_faddr
= sin
->sin_addr
;
363 inp
->inp_fport
= sin
->sin_port
;
369 in_pcbdisconnect(inp
)
373 inp
->inp_faddr
.s_addr
= INADDR_ANY
;
376 if (inp
->inp_socket
->so_state
& SS_NOFDREF
)
384 struct socket
*so
= inp
->inp_socket
;
389 if (inp
->inp_options
)
390 (void)m_free(inp
->inp_options
);
391 if (inp
->inp_route
.ro_rt
)
392 rtfree(inp
->inp_route
.ro_rt
);
393 ip_freemoptions(inp
->inp_moptions
);
395 LIST_REMOVE(inp
, inp_hash
);
396 LIST_REMOVE(inp
, inp_list
);
402 in_setsockaddr(inp
, nam
)
403 register struct inpcb
*inp
;
406 register struct sockaddr_in
*sin
;
408 nam
->m_len
= sizeof (*sin
);
409 sin
= mtod(nam
, struct sockaddr_in
*);
410 bzero((caddr_t
)sin
, sizeof (*sin
));
411 sin
->sin_family
= AF_INET
;
412 sin
->sin_len
= sizeof(*sin
);
413 sin
->sin_port
= inp
->inp_lport
;
414 sin
->sin_addr
= inp
->inp_laddr
;
418 in_setpeeraddr(inp
, nam
)
422 register struct sockaddr_in
*sin
;
424 nam
->m_len
= sizeof (*sin
);
425 sin
= mtod(nam
, struct sockaddr_in
*);
426 bzero((caddr_t
)sin
, sizeof (*sin
));
427 sin
->sin_family
= AF_INET
;
428 sin
->sin_len
= sizeof(*sin
);
429 sin
->sin_port
= inp
->inp_fport
;
430 sin
->sin_addr
= inp
->inp_faddr
;
434 * Pass some notification to all connections of a protocol
435 * associated with address dst. The local address and/or port numbers
436 * may be specified to limit the search. The "usual action" will be
437 * taken, depending on the ctlinput cmd. The caller must filter any
438 * cmds that are uninteresting (e.g., no error in the map).
439 * Call the protocol specific routine (if any) to report
440 * any errors for each matching socket.
442 * Must be called at splnet.
445 in_pcbnotify(head
, dst
, fport_arg
, laddr
, lport_arg
, cmd
, notify
)
446 struct inpcbhead
*head
;
447 struct sockaddr
*dst
;
448 u_int fport_arg
, lport_arg
;
449 struct in_addr laddr
;
451 void (*notify
) __P((struct inpcb
*, int));
453 register struct inpcb
*inp
, *oinp
;
454 struct in_addr faddr
;
455 u_short fport
= fport_arg
, lport
= lport_arg
;
458 if ((unsigned)cmd
> PRC_NCMDS
|| dst
->sa_family
!= AF_INET
)
460 faddr
= ((struct sockaddr_in
*)dst
)->sin_addr
;
461 if (faddr
.s_addr
== INADDR_ANY
)
465 * Redirects go to all references to the destination,
466 * and use in_rtchange to invalidate the route cache.
467 * Dead host indications: notify all references to the destination.
468 * Otherwise, if we have knowledge of the local port and address,
469 * deliver only to that socket.
471 if (PRC_IS_REDIRECT(cmd
) || cmd
== PRC_HOSTDEAD
) {
475 if (cmd
!= PRC_HOSTDEAD
)
476 notify
= in_rtchange
;
478 errno
= inetctlerrmap
[cmd
];
480 for (inp
= head
->lh_first
; inp
!= NULL
;) {
481 if (inp
->inp_faddr
.s_addr
!= faddr
.s_addr
||
482 inp
->inp_socket
== 0 ||
483 (lport
&& inp
->inp_lport
!= lport
) ||
484 (laddr
.s_addr
&& inp
->inp_laddr
.s_addr
!= laddr
.s_addr
) ||
485 (fport
&& inp
->inp_fport
!= fport
)) {
486 inp
= inp
->inp_list
.le_next
;
490 inp
= inp
->inp_list
.le_next
;
492 (*notify
)(oinp
, errno
);
498 * Check for alternatives when higher level complains
499 * about service problems. For now, invalidate cached
500 * routing information. If the route was created dynamically
501 * (by a redirect), time to try a default gateway again.
507 register struct rtentry
*rt
;
508 struct rt_addrinfo info
;
510 if ((rt
= inp
->inp_route
.ro_rt
)) {
511 inp
->inp_route
.ro_rt
= 0;
512 bzero((caddr_t
)&info
, sizeof(info
));
513 info
.rti_info
[RTAX_DST
] =
514 (struct sockaddr
*)&inp
->inp_route
.ro_dst
;
515 info
.rti_info
[RTAX_GATEWAY
] = rt
->rt_gateway
;
516 info
.rti_info
[RTAX_NETMASK
] = rt_mask(rt
);
517 rt_missmsg(RTM_LOSING
, &info
, rt
->rt_flags
, 0);
518 if (rt
->rt_flags
& RTF_DYNAMIC
)
519 (void) rtrequest(RTM_DELETE
, rt_key(rt
),
520 rt
->rt_gateway
, rt_mask(rt
), rt
->rt_flags
,
521 (struct rtentry
**)0);
524 * A new route can be allocated
525 * the next time output is attempted.
532 * After a routing change, flush old routing
533 * and allocate a (hopefully) better one.
536 in_rtchange(inp
, errno
)
537 register struct inpcb
*inp
;
540 if (inp
->inp_route
.ro_rt
) {
541 rtfree(inp
->inp_route
.ro_rt
);
542 inp
->inp_route
.ro_rt
= 0;
544 * A new route can be allocated the next time
545 * output is attempted.
551 in_pcblookup(head
, faddr
, fport_arg
, laddr
, lport_arg
, flags
)
552 struct inpcbhead
*head
;
553 struct in_addr faddr
, laddr
;
554 u_int fport_arg
, lport_arg
;
557 register struct inpcb
*inp
, *match
= NULL
;
558 int matchwild
= 3, wildcard
;
559 u_short fport
= fport_arg
, lport
= lport_arg
;
564 for (inp
= head
->lh_first
; inp
!= NULL
; inp
= inp
->inp_list
.le_next
) {
565 if (inp
->inp_lport
!= lport
)
568 if (inp
->inp_faddr
.s_addr
!= INADDR_ANY
) {
569 if (faddr
.s_addr
== INADDR_ANY
)
571 else if (inp
->inp_faddr
.s_addr
!= faddr
.s_addr
||
572 inp
->inp_fport
!= fport
)
575 if (faddr
.s_addr
!= INADDR_ANY
)
578 if (inp
->inp_laddr
.s_addr
!= INADDR_ANY
) {
579 if (laddr
.s_addr
== INADDR_ANY
)
581 else if (inp
->inp_laddr
.s_addr
!= laddr
.s_addr
)
584 if (laddr
.s_addr
!= INADDR_ANY
)
587 if (wildcard
&& (flags
& INPLOOKUP_WILDCARD
) == 0)
589 if (wildcard
< matchwild
) {
591 matchwild
= wildcard
;
592 if (matchwild
== 0) {
602 * Lookup PCB in hash list.
605 in_pcblookuphash(pcbinfo
, faddr
, fport_arg
, laddr
, lport_arg
)
606 struct inpcbinfo
*pcbinfo
;
607 struct in_addr faddr
, laddr
;
608 u_int fport_arg
, lport_arg
;
610 struct inpcbhead
*head
;
611 register struct inpcb
*inp
;
612 u_short fport
= fport_arg
, lport
= lport_arg
;
617 * First look for an exact match.
619 head
= &pcbinfo
->hashbase
[(faddr
.s_addr
+ lport
+ fport
) % pcbinfo
->hashsize
];
621 for (inp
= head
->lh_first
; inp
!= NULL
; inp
= inp
->inp_hash
.le_next
) {
622 if (inp
->inp_faddr
.s_addr
!= faddr
.s_addr
||
623 inp
->inp_fport
!= fport
||
624 inp
->inp_lport
!= lport
||
625 inp
->inp_laddr
.s_addr
!= laddr
.s_addr
)
628 * Move PCB to head of this hash chain so that it can be
629 * found more quickly in the future.
631 if (inp
!= head
->lh_first
) {
632 LIST_REMOVE(inp
, inp_hash
);
633 LIST_INSERT_HEAD(head
, inp
, inp_hash
);
642 * Insert PCB into hash chain. Must be called at splnet.
648 struct inpcbhead
*head
;
650 head
= &inp
->inp_pcbinfo
->hashbase
[(inp
->inp_faddr
.s_addr
+
651 inp
->inp_lport
+ inp
->inp_fport
) % inp
->inp_pcbinfo
->hashsize
];
653 LIST_INSERT_HEAD(head
, inp
, inp_hash
);
660 struct inpcbhead
*head
;
664 LIST_REMOVE(inp
, inp_hash
);
666 head
= &inp
->inp_pcbinfo
->hashbase
[(inp
->inp_faddr
.s_addr
+
667 inp
->inp_lport
+ inp
->inp_fport
) % inp
->inp_pcbinfo
->hashsize
];
669 LIST_INSERT_HEAD(head
, inp
, inp_hash
);