Deleted Added
full compact
in_pcb.c (10940) in_pcb.c (11921)
1/*
2 * Copyright (c) 1982, 1986, 1991, 1993, 1995
3 * The Regents of the University of California. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
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.
20 *
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
31 * SUCH DAMAGE.
32 *
33 * @(#)in_pcb.c 8.4 (Berkeley) 5/24/95
1/*
2 * Copyright (c) 1982, 1986, 1991, 1993, 1995
3 * The Regents of the University of California. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
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.
20 *
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
31 * SUCH DAMAGE.
32 *
33 * @(#)in_pcb.c 8.4 (Berkeley) 5/24/95
34 * $Id: in_pcb.c,v 1.12 1995/05/30 08:09:28 rgrimes Exp $
34 * $Id: in_pcb.c,v 1.13 1995/09/21 17:55:49 wollman Exp $
35 */
36
37#include <sys/param.h>
38#include <sys/systm.h>
39#include <sys/malloc.h>
40#include <sys/mbuf.h>
41#include <sys/protosw.h>
42#include <sys/socket.h>
43#include <sys/socketvar.h>
44#include <sys/ioctl.h>
45#include <sys/errno.h>
46#include <sys/time.h>
47#include <sys/proc.h>
48#include <sys/queue.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
60struct in_addr zeroin_addr;
61
62int
63in_pcballoc(so, pcbinfo)
64 struct socket *so;
65 struct inpcbinfo *pcbinfo;
66{
67 register struct inpcb *inp;
68 int s;
69
70 MALLOC(inp, struct inpcb *, sizeof(*inp), M_PCB, M_NOWAIT);
71 if (inp == NULL)
72 return (ENOBUFS);
73 bzero((caddr_t)inp, sizeof(*inp));
74 inp->inp_pcbinfo = pcbinfo;
75 inp->inp_socket = so;
76 s = splnet();
77 LIST_INSERT_HEAD(pcbinfo->listhead, inp, inp_list);
78 in_pcbinshash(inp);
79 splx(s);
80 so->so_pcb = (caddr_t)inp;
81 return (0);
82}
83
84int
85in_pcbbind(inp, nam)
86 register struct inpcb *inp;
87 struct mbuf *nam;
88{
89 register struct socket *so = inp->inp_socket;
90 struct inpcbhead *head = inp->inp_pcbinfo->listhead;
91 unsigned short *lastport = &inp->inp_pcbinfo->lastport;
92 struct sockaddr_in *sin;
93 struct proc *p = curproc; /* XXX */
94 u_short lport = 0;
95 int wild = 0, reuseport = (so->so_options & SO_REUSEPORT);
96 int error;
97
98 if (in_ifaddr == 0)
99 return (EADDRNOTAVAIL);
100 if (inp->inp_lport || inp->inp_laddr.s_addr != INADDR_ANY)
101 return (EINVAL);
102 if ((so->so_options & (SO_REUSEADDR|SO_REUSEPORT)) == 0 &&
103 ((so->so_proto->pr_flags & PR_CONNREQUIRED) == 0 ||
104 (so->so_options & SO_ACCEPTCONN) == 0))
105 wild = INPLOOKUP_WILDCARD;
106 if (nam) {
107 sin = mtod(nam, struct sockaddr_in *);
108 if (nam->m_len != sizeof (*sin))
109 return (EINVAL);
110#ifdef notdef
111 /*
112 * We should check the family, but old programs
113 * incorrectly fail to initialize it.
114 */
115 if (sin->sin_family != AF_INET)
116 return (EAFNOSUPPORT);
117#endif
118 lport = sin->sin_port;
119 if (IN_MULTICAST(ntohl(sin->sin_addr.s_addr))) {
120 /*
121 * Treat SO_REUSEADDR as SO_REUSEPORT for multicast;
122 * allow complete duplication of binding if
123 * SO_REUSEPORT is set, or if SO_REUSEADDR is set
124 * and a multicast address is bound on both
125 * new and duplicated sockets.
126 */
127 if (so->so_options & SO_REUSEADDR)
128 reuseport = SO_REUSEADDR|SO_REUSEPORT;
129 } else if (sin->sin_addr.s_addr != INADDR_ANY) {
130 sin->sin_port = 0; /* yech... */
131 if (ifa_ifwithaddr((struct sockaddr *)sin) == 0)
132 return (EADDRNOTAVAIL);
133 }
134 if (lport) {
135 struct inpcb *t;
136
137 /* GROSS */
138 if (ntohs(lport) < IPPORT_RESERVED &&
139 (error = suser(p->p_ucred, &p->p_acflag)))
140 return (EACCES);
141 t = in_pcblookup(head, zeroin_addr, 0,
142 sin->sin_addr, lport, wild);
143 if (t && (reuseport & t->inp_socket->so_options) == 0)
144 return (EADDRINUSE);
145 }
146 inp->inp_laddr = sin->sin_addr;
147 }
148 if (lport == 0)
149 do {
150 ++*lastport;
151 if (*lastport < IPPORT_RESERVED ||
152 *lastport > IPPORT_USERRESERVED)
153 *lastport = IPPORT_RESERVED;
154 lport = htons(*lastport);
155 } while (in_pcblookup(head,
156 zeroin_addr, 0, inp->inp_laddr, lport, wild));
157 inp->inp_lport = lport;
158 in_pcbrehash(inp);
159 return (0);
160}
161
162/*
163 * Transform old in_pcbconnect() into an inner subroutine for new
164 * in_pcbconnect(): Do some validity-checking on the remote
165 * address (in mbuf 'nam') and then determine local host address
166 * (i.e., which interface) to use to access that remote host.
167 *
168 * This preserves definition of in_pcbconnect(), while supporting a
169 * slightly different version for T/TCP. (This is more than
170 * a bit of a kludge, but cleaning up the internal interfaces would
171 * have forced minor changes in every protocol).
172 */
173
174int
175in_pcbladdr(inp, nam, plocal_sin)
176 register struct inpcb *inp;
177 struct mbuf *nam;
178 struct sockaddr_in **plocal_sin;
179{
180 struct in_ifaddr *ia;
35 */
36
37#include <sys/param.h>
38#include <sys/systm.h>
39#include <sys/malloc.h>
40#include <sys/mbuf.h>
41#include <sys/protosw.h>
42#include <sys/socket.h>
43#include <sys/socketvar.h>
44#include <sys/ioctl.h>
45#include <sys/errno.h>
46#include <sys/time.h>
47#include <sys/proc.h>
48#include <sys/queue.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
60struct in_addr zeroin_addr;
61
62int
63in_pcballoc(so, pcbinfo)
64 struct socket *so;
65 struct inpcbinfo *pcbinfo;
66{
67 register struct inpcb *inp;
68 int s;
69
70 MALLOC(inp, struct inpcb *, sizeof(*inp), M_PCB, M_NOWAIT);
71 if (inp == NULL)
72 return (ENOBUFS);
73 bzero((caddr_t)inp, sizeof(*inp));
74 inp->inp_pcbinfo = pcbinfo;
75 inp->inp_socket = so;
76 s = splnet();
77 LIST_INSERT_HEAD(pcbinfo->listhead, inp, inp_list);
78 in_pcbinshash(inp);
79 splx(s);
80 so->so_pcb = (caddr_t)inp;
81 return (0);
82}
83
84int
85in_pcbbind(inp, nam)
86 register struct inpcb *inp;
87 struct mbuf *nam;
88{
89 register struct socket *so = inp->inp_socket;
90 struct inpcbhead *head = inp->inp_pcbinfo->listhead;
91 unsigned short *lastport = &inp->inp_pcbinfo->lastport;
92 struct sockaddr_in *sin;
93 struct proc *p = curproc; /* XXX */
94 u_short lport = 0;
95 int wild = 0, reuseport = (so->so_options & SO_REUSEPORT);
96 int error;
97
98 if (in_ifaddr == 0)
99 return (EADDRNOTAVAIL);
100 if (inp->inp_lport || inp->inp_laddr.s_addr != INADDR_ANY)
101 return (EINVAL);
102 if ((so->so_options & (SO_REUSEADDR|SO_REUSEPORT)) == 0 &&
103 ((so->so_proto->pr_flags & PR_CONNREQUIRED) == 0 ||
104 (so->so_options & SO_ACCEPTCONN) == 0))
105 wild = INPLOOKUP_WILDCARD;
106 if (nam) {
107 sin = mtod(nam, struct sockaddr_in *);
108 if (nam->m_len != sizeof (*sin))
109 return (EINVAL);
110#ifdef notdef
111 /*
112 * We should check the family, but old programs
113 * incorrectly fail to initialize it.
114 */
115 if (sin->sin_family != AF_INET)
116 return (EAFNOSUPPORT);
117#endif
118 lport = sin->sin_port;
119 if (IN_MULTICAST(ntohl(sin->sin_addr.s_addr))) {
120 /*
121 * Treat SO_REUSEADDR as SO_REUSEPORT for multicast;
122 * allow complete duplication of binding if
123 * SO_REUSEPORT is set, or if SO_REUSEADDR is set
124 * and a multicast address is bound on both
125 * new and duplicated sockets.
126 */
127 if (so->so_options & SO_REUSEADDR)
128 reuseport = SO_REUSEADDR|SO_REUSEPORT;
129 } else if (sin->sin_addr.s_addr != INADDR_ANY) {
130 sin->sin_port = 0; /* yech... */
131 if (ifa_ifwithaddr((struct sockaddr *)sin) == 0)
132 return (EADDRNOTAVAIL);
133 }
134 if (lport) {
135 struct inpcb *t;
136
137 /* GROSS */
138 if (ntohs(lport) < IPPORT_RESERVED &&
139 (error = suser(p->p_ucred, &p->p_acflag)))
140 return (EACCES);
141 t = in_pcblookup(head, zeroin_addr, 0,
142 sin->sin_addr, lport, wild);
143 if (t && (reuseport & t->inp_socket->so_options) == 0)
144 return (EADDRINUSE);
145 }
146 inp->inp_laddr = sin->sin_addr;
147 }
148 if (lport == 0)
149 do {
150 ++*lastport;
151 if (*lastport < IPPORT_RESERVED ||
152 *lastport > IPPORT_USERRESERVED)
153 *lastport = IPPORT_RESERVED;
154 lport = htons(*lastport);
155 } while (in_pcblookup(head,
156 zeroin_addr, 0, inp->inp_laddr, lport, wild));
157 inp->inp_lport = lport;
158 in_pcbrehash(inp);
159 return (0);
160}
161
162/*
163 * Transform old in_pcbconnect() into an inner subroutine for new
164 * in_pcbconnect(): Do some validity-checking on the remote
165 * address (in mbuf 'nam') and then determine local host address
166 * (i.e., which interface) to use to access that remote host.
167 *
168 * This preserves definition of in_pcbconnect(), while supporting a
169 * slightly different version for T/TCP. (This is more than
170 * a bit of a kludge, but cleaning up the internal interfaces would
171 * have forced minor changes in every protocol).
172 */
173
174int
175in_pcbladdr(inp, nam, plocal_sin)
176 register struct inpcb *inp;
177 struct mbuf *nam;
178 struct sockaddr_in **plocal_sin;
179{
180 struct in_ifaddr *ia;
181 struct sockaddr_in *ifaddr = 0;
182 register struct sockaddr_in *sin = mtod(nam, struct sockaddr_in *);
183
184 if (nam->m_len != sizeof (*sin))
185 return (EINVAL);
186 if (sin->sin_family != AF_INET)
187 return (EAFNOSUPPORT);
188 if (sin->sin_port == 0)
189 return (EADDRNOTAVAIL);
190 if (in_ifaddr) {
191 /*
192 * If the destination address is INADDR_ANY,
193 * use the primary local address.
194 * If the supplied address is INADDR_BROADCAST,
195 * and the primary interface supports broadcast,
196 * choose the broadcast address for that interface.
197 */
198#define satosin(sa) ((struct sockaddr_in *)(sa))
199#define sintosa(sin) ((struct sockaddr *)(sin))
200#define ifatoia(ifa) ((struct in_ifaddr *)(ifa))
201 if (sin->sin_addr.s_addr == INADDR_ANY)
202 sin->sin_addr = IA_SIN(in_ifaddr)->sin_addr;
203 else if (sin->sin_addr.s_addr == (u_long)INADDR_BROADCAST &&
204 (in_ifaddr->ia_ifp->if_flags & IFF_BROADCAST))
205 sin->sin_addr = satosin(&in_ifaddr->ia_broadaddr)->sin_addr;
206 }
207 if (inp->inp_laddr.s_addr == INADDR_ANY) {
208 register struct route *ro;
209
210 ia = (struct in_ifaddr *)0;
211 /*
212 * If route is known or can be allocated now,
213 * our src addr is taken from the i/f, else punt.
214 */
215 ro = &inp->inp_route;
216 if (ro->ro_rt &&
217 (satosin(&ro->ro_dst)->sin_addr.s_addr !=
218 sin->sin_addr.s_addr ||
219 inp->inp_socket->so_options & SO_DONTROUTE)) {
220 RTFREE(ro->ro_rt);
221 ro->ro_rt = (struct rtentry *)0;
222 }
223 if ((inp->inp_socket->so_options & SO_DONTROUTE) == 0 && /*XXX*/
224 (ro->ro_rt == (struct rtentry *)0 ||
225 ro->ro_rt->rt_ifp == (struct ifnet *)0)) {
226 /* No route yet, so try to acquire one */
227 ro->ro_dst.sa_family = AF_INET;
228 ro->ro_dst.sa_len = sizeof(struct sockaddr_in);
229 ((struct sockaddr_in *) &ro->ro_dst)->sin_addr =
230 sin->sin_addr;
231 rtalloc(ro);
232 }
233 /*
234 * If we found a route, use the address
235 * corresponding to the outgoing interface
236 * unless it is the loopback (in case a route
237 * to our address on another net goes to loopback).
238 */
239 if (ro->ro_rt && !(ro->ro_rt->rt_ifp->if_flags & IFF_LOOPBACK))
240 ia = ifatoia(ro->ro_rt->rt_ifa);
241 if (ia == 0) {
242 u_short fport = sin->sin_port;
243
244 sin->sin_port = 0;
245 ia = ifatoia(ifa_ifwithdstaddr(sintosa(sin)));
246 if (ia == 0)
247 ia = ifatoia(ifa_ifwithnet(sintosa(sin)));
248 sin->sin_port = fport;
249 if (ia == 0)
250 ia = in_ifaddr;
251 if (ia == 0)
252 return (EADDRNOTAVAIL);
253 }
254 /*
255 * If the destination address is multicast and an outgoing
256 * interface has been set as a multicast option, use the
257 * address of that interface as our source address.
258 */
259 if (IN_MULTICAST(ntohl(sin->sin_addr.s_addr)) &&
260 inp->inp_moptions != NULL) {
261 struct ip_moptions *imo;
262 struct ifnet *ifp;
263
264 imo = inp->inp_moptions;
265 if (imo->imo_multicast_ifp != NULL) {
266 ifp = imo->imo_multicast_ifp;
267 for (ia = in_ifaddr; ia; ia = ia->ia_next)
268 if (ia->ia_ifp == ifp)
269 break;
270 if (ia == 0)
271 return (EADDRNOTAVAIL);
272 }
273 }
274 /*
275 * Don't do pcblookup call here; return interface in plocal_sin
276 * and exit to caller, that will do the lookup.
277 */
278 *plocal_sin = &ia->ia_addr;
279
280 }
281 return(0);
282}
283
284/*
285 * Outer subroutine:
286 * Connect from a socket to a specified address.
287 * Both address and port must be specified in argument sin.
288 * If don't have a local address for this socket yet,
289 * then pick one.
290 */
291int
292in_pcbconnect(inp, nam)
293 register struct inpcb *inp;
294 struct mbuf *nam;
295{
296 struct sockaddr_in *ifaddr;
297 register struct sockaddr_in *sin = mtod(nam, struct sockaddr_in *);
298 int error;
299
300 /*
301 * Call inner routine, to assign local interface address.
302 */
303 if (error = in_pcbladdr(inp, nam, &ifaddr))
304 return(error);
305
306 if (in_pcblookuphash(inp->inp_pcbinfo, sin->sin_addr, sin->sin_port,
307 inp->inp_laddr.s_addr ? inp->inp_laddr : ifaddr->sin_addr,
308 inp->inp_lport) != NULL)
309 return (EADDRINUSE);
310 if (inp->inp_laddr.s_addr == INADDR_ANY) {
311 if (inp->inp_lport == 0)
312 (void)in_pcbbind(inp, (struct mbuf *)0);
313 inp->inp_laddr = ifaddr->sin_addr;
314 }
315 inp->inp_faddr = sin->sin_addr;
316 inp->inp_fport = sin->sin_port;
317 in_pcbrehash(inp);
318 return (0);
319}
320
321void
322in_pcbdisconnect(inp)
323 struct inpcb *inp;
324{
325
326 inp->inp_faddr.s_addr = INADDR_ANY;
327 inp->inp_fport = 0;
328 in_pcbrehash(inp);
329 if (inp->inp_socket->so_state & SS_NOFDREF)
330 in_pcbdetach(inp);
331}
332
333void
334in_pcbdetach(inp)
335 struct inpcb *inp;
336{
337 struct socket *so = inp->inp_socket;
338 int s;
339
340 so->so_pcb = 0;
341 sofree(so);
342 if (inp->inp_options)
343 (void)m_free(inp->inp_options);
344 if (inp->inp_route.ro_rt)
345 rtfree(inp->inp_route.ro_rt);
346 ip_freemoptions(inp->inp_moptions);
347 s = splnet();
348 LIST_REMOVE(inp, inp_hash);
349 LIST_REMOVE(inp, inp_list);
350 splx(s);
351 FREE(inp, M_PCB);
352}
353
354void
355in_setsockaddr(inp, nam)
356 register struct inpcb *inp;
357 struct mbuf *nam;
358{
359 register struct sockaddr_in *sin;
360
361 nam->m_len = sizeof (*sin);
362 sin = mtod(nam, struct sockaddr_in *);
363 bzero((caddr_t)sin, sizeof (*sin));
364 sin->sin_family = AF_INET;
365 sin->sin_len = sizeof(*sin);
366 sin->sin_port = inp->inp_lport;
367 sin->sin_addr = inp->inp_laddr;
368}
369
370void
371in_setpeeraddr(inp, nam)
372 struct inpcb *inp;
373 struct mbuf *nam;
374{
375 register struct sockaddr_in *sin;
376
377 nam->m_len = sizeof (*sin);
378 sin = mtod(nam, struct sockaddr_in *);
379 bzero((caddr_t)sin, sizeof (*sin));
380 sin->sin_family = AF_INET;
381 sin->sin_len = sizeof(*sin);
382 sin->sin_port = inp->inp_fport;
383 sin->sin_addr = inp->inp_faddr;
384}
385
386/*
387 * Pass some notification to all connections of a protocol
388 * associated with address dst. The local address and/or port numbers
389 * may be specified to limit the search. The "usual action" will be
390 * taken, depending on the ctlinput cmd. The caller must filter any
391 * cmds that are uninteresting (e.g., no error in the map).
392 * Call the protocol specific routine (if any) to report
393 * any errors for each matching socket.
394 *
395 * Must be called at splnet.
396 */
397void
398in_pcbnotify(head, dst, fport_arg, laddr, lport_arg, cmd, notify)
399 struct inpcbhead *head;
400 struct sockaddr *dst;
401 u_int fport_arg, lport_arg;
402 struct in_addr laddr;
403 int cmd;
404 void (*notify) __P((struct inpcb *, int));
405{
406 register struct inpcb *inp, *oinp;
407 struct in_addr faddr;
408 u_short fport = fport_arg, lport = lport_arg;
409 int errno, s;
410
411 if ((unsigned)cmd > PRC_NCMDS || dst->sa_family != AF_INET)
412 return;
413 faddr = ((struct sockaddr_in *)dst)->sin_addr;
414 if (faddr.s_addr == INADDR_ANY)
415 return;
416
417 /*
418 * Redirects go to all references to the destination,
419 * and use in_rtchange to invalidate the route cache.
420 * Dead host indications: notify all references to the destination.
421 * Otherwise, if we have knowledge of the local port and address,
422 * deliver only to that socket.
423 */
424 if (PRC_IS_REDIRECT(cmd) || cmd == PRC_HOSTDEAD) {
425 fport = 0;
426 lport = 0;
427 laddr.s_addr = 0;
428 if (cmd != PRC_HOSTDEAD)
429 notify = in_rtchange;
430 }
431 errno = inetctlerrmap[cmd];
432 s = splnet();
433 for (inp = head->lh_first; inp != NULL;) {
434 if (inp->inp_faddr.s_addr != faddr.s_addr ||
435 inp->inp_socket == 0 ||
436 (lport && inp->inp_lport != lport) ||
437 (laddr.s_addr && inp->inp_laddr.s_addr != laddr.s_addr) ||
438 (fport && inp->inp_fport != fport)) {
439 inp = inp->inp_list.le_next;
440 continue;
441 }
442 oinp = inp;
443 inp = inp->inp_list.le_next;
444 if (notify)
445 (*notify)(oinp, errno);
446 }
447 splx(s);
448}
449
450/*
451 * Check for alternatives when higher level complains
452 * about service problems. For now, invalidate cached
453 * routing information. If the route was created dynamically
454 * (by a redirect), time to try a default gateway again.
455 */
456void
457in_losing(inp)
458 struct inpcb *inp;
459{
460 register struct rtentry *rt;
461 struct rt_addrinfo info;
462
463 if ((rt = inp->inp_route.ro_rt)) {
464 inp->inp_route.ro_rt = 0;
465 bzero((caddr_t)&info, sizeof(info));
466 info.rti_info[RTAX_DST] =
467 (struct sockaddr *)&inp->inp_route.ro_dst;
468 info.rti_info[RTAX_GATEWAY] = rt->rt_gateway;
469 info.rti_info[RTAX_NETMASK] = rt_mask(rt);
470 rt_missmsg(RTM_LOSING, &info, rt->rt_flags, 0);
471 if (rt->rt_flags & RTF_DYNAMIC)
472 (void) rtrequest(RTM_DELETE, rt_key(rt),
473 rt->rt_gateway, rt_mask(rt), rt->rt_flags,
474 (struct rtentry **)0);
475 else
476 /*
477 * A new route can be allocated
478 * the next time output is attempted.
479 */
480 rtfree(rt);
481 }
482}
483
484/*
485 * After a routing change, flush old routing
486 * and allocate a (hopefully) better one.
487 */
488void
489in_rtchange(inp, errno)
490 register struct inpcb *inp;
491 int errno;
492{
493 if (inp->inp_route.ro_rt) {
494 rtfree(inp->inp_route.ro_rt);
495 inp->inp_route.ro_rt = 0;
496 /*
497 * A new route can be allocated the next time
498 * output is attempted.
499 */
500 }
501}
502
503struct inpcb *
504in_pcblookup(head, faddr, fport_arg, laddr, lport_arg, flags)
505 struct inpcbhead *head;
506 struct in_addr faddr, laddr;
507 u_int fport_arg, lport_arg;
508 int flags;
509{
510 register struct inpcb *inp, *match = NULL;
511 int matchwild = 3, wildcard;
512 u_short fport = fport_arg, lport = lport_arg;
513 int s;
514
515 s = splnet();
516
517 for (inp = head->lh_first; inp != NULL; inp = inp->inp_list.le_next) {
518 if (inp->inp_lport != lport)
519 continue;
520 wildcard = 0;
521 if (inp->inp_faddr.s_addr != INADDR_ANY) {
522 if (faddr.s_addr == INADDR_ANY)
523 wildcard++;
524 else if (inp->inp_faddr.s_addr != faddr.s_addr ||
525 inp->inp_fport != fport)
526 continue;
527 } else {
528 if (faddr.s_addr != INADDR_ANY)
529 wildcard++;
530 }
531 if (inp->inp_laddr.s_addr != INADDR_ANY) {
532 if (laddr.s_addr == INADDR_ANY)
533 wildcard++;
534 else if (inp->inp_laddr.s_addr != laddr.s_addr)
535 continue;
536 } else {
537 if (laddr.s_addr != INADDR_ANY)
538 wildcard++;
539 }
540 if (wildcard && (flags & INPLOOKUP_WILDCARD) == 0)
541 continue;
542 if (wildcard < matchwild) {
543 match = inp;
544 matchwild = wildcard;
545 if (matchwild == 0) {
546 break;
547 }
548 }
549 }
550 splx(s);
551 return (match);
552}
553
554/*
555 * Lookup PCB in hash list.
556 */
557struct inpcb *
558in_pcblookuphash(pcbinfo, faddr, fport_arg, laddr, lport_arg)
559 struct inpcbinfo *pcbinfo;
560 struct in_addr faddr, laddr;
561 u_int fport_arg, lport_arg;
562{
563 struct inpcbhead *head;
564 register struct inpcb *inp;
565 u_short fport = fport_arg, lport = lport_arg;
566 int s;
567
568 s = splnet();
569 /*
570 * First look for an exact match.
571 */
572 head = &pcbinfo->hashbase[(faddr.s_addr + lport + fport) % pcbinfo->hashsize];
573
574 for (inp = head->lh_first; inp != NULL; inp = inp->inp_hash.le_next) {
575 if (inp->inp_faddr.s_addr != faddr.s_addr ||
576 inp->inp_fport != fport ||
577 inp->inp_lport != lport ||
578 inp->inp_laddr.s_addr != laddr.s_addr)
579 continue;
580 /*
581 * Move PCB to head of this hash chain so that it can be
582 * found more quickly in the future.
583 */
584 if (inp != head->lh_first) {
585 LIST_REMOVE(inp, inp_hash);
586 LIST_INSERT_HEAD(head, inp, inp_hash);
587 }
588 break;
589 }
590 splx(s);
591 return (inp);
592}
593
594/*
595 * Insert PCB into hash chain. Must be called at splnet.
596 */
597void
598in_pcbinshash(inp)
599 struct inpcb *inp;
600{
601 struct inpcbhead *head;
602
603 head = &inp->inp_pcbinfo->hashbase[(inp->inp_faddr.s_addr +
604 inp->inp_lport + inp->inp_fport) % inp->inp_pcbinfo->hashsize];
605
606 LIST_INSERT_HEAD(head, inp, inp_hash);
607}
608
609void
610in_pcbrehash(inp)
611 struct inpcb *inp;
612{
613 struct inpcbhead *head;
614 int s;
615
616 s = splnet();
617 LIST_REMOVE(inp, inp_hash);
618
619 head = &inp->inp_pcbinfo->hashbase[(inp->inp_faddr.s_addr +
620 inp->inp_lport + inp->inp_fport) % inp->inp_pcbinfo->hashsize];
621
622 LIST_INSERT_HEAD(head, inp, inp_hash);
623 splx(s);
624}
181 register struct sockaddr_in *sin = mtod(nam, struct sockaddr_in *);
182
183 if (nam->m_len != sizeof (*sin))
184 return (EINVAL);
185 if (sin->sin_family != AF_INET)
186 return (EAFNOSUPPORT);
187 if (sin->sin_port == 0)
188 return (EADDRNOTAVAIL);
189 if (in_ifaddr) {
190 /*
191 * If the destination address is INADDR_ANY,
192 * use the primary local address.
193 * If the supplied address is INADDR_BROADCAST,
194 * and the primary interface supports broadcast,
195 * choose the broadcast address for that interface.
196 */
197#define satosin(sa) ((struct sockaddr_in *)(sa))
198#define sintosa(sin) ((struct sockaddr *)(sin))
199#define ifatoia(ifa) ((struct in_ifaddr *)(ifa))
200 if (sin->sin_addr.s_addr == INADDR_ANY)
201 sin->sin_addr = IA_SIN(in_ifaddr)->sin_addr;
202 else if (sin->sin_addr.s_addr == (u_long)INADDR_BROADCAST &&
203 (in_ifaddr->ia_ifp->if_flags & IFF_BROADCAST))
204 sin->sin_addr = satosin(&in_ifaddr->ia_broadaddr)->sin_addr;
205 }
206 if (inp->inp_laddr.s_addr == INADDR_ANY) {
207 register struct route *ro;
208
209 ia = (struct in_ifaddr *)0;
210 /*
211 * If route is known or can be allocated now,
212 * our src addr is taken from the i/f, else punt.
213 */
214 ro = &inp->inp_route;
215 if (ro->ro_rt &&
216 (satosin(&ro->ro_dst)->sin_addr.s_addr !=
217 sin->sin_addr.s_addr ||
218 inp->inp_socket->so_options & SO_DONTROUTE)) {
219 RTFREE(ro->ro_rt);
220 ro->ro_rt = (struct rtentry *)0;
221 }
222 if ((inp->inp_socket->so_options & SO_DONTROUTE) == 0 && /*XXX*/
223 (ro->ro_rt == (struct rtentry *)0 ||
224 ro->ro_rt->rt_ifp == (struct ifnet *)0)) {
225 /* No route yet, so try to acquire one */
226 ro->ro_dst.sa_family = AF_INET;
227 ro->ro_dst.sa_len = sizeof(struct sockaddr_in);
228 ((struct sockaddr_in *) &ro->ro_dst)->sin_addr =
229 sin->sin_addr;
230 rtalloc(ro);
231 }
232 /*
233 * If we found a route, use the address
234 * corresponding to the outgoing interface
235 * unless it is the loopback (in case a route
236 * to our address on another net goes to loopback).
237 */
238 if (ro->ro_rt && !(ro->ro_rt->rt_ifp->if_flags & IFF_LOOPBACK))
239 ia = ifatoia(ro->ro_rt->rt_ifa);
240 if (ia == 0) {
241 u_short fport = sin->sin_port;
242
243 sin->sin_port = 0;
244 ia = ifatoia(ifa_ifwithdstaddr(sintosa(sin)));
245 if (ia == 0)
246 ia = ifatoia(ifa_ifwithnet(sintosa(sin)));
247 sin->sin_port = fport;
248 if (ia == 0)
249 ia = in_ifaddr;
250 if (ia == 0)
251 return (EADDRNOTAVAIL);
252 }
253 /*
254 * If the destination address is multicast and an outgoing
255 * interface has been set as a multicast option, use the
256 * address of that interface as our source address.
257 */
258 if (IN_MULTICAST(ntohl(sin->sin_addr.s_addr)) &&
259 inp->inp_moptions != NULL) {
260 struct ip_moptions *imo;
261 struct ifnet *ifp;
262
263 imo = inp->inp_moptions;
264 if (imo->imo_multicast_ifp != NULL) {
265 ifp = imo->imo_multicast_ifp;
266 for (ia = in_ifaddr; ia; ia = ia->ia_next)
267 if (ia->ia_ifp == ifp)
268 break;
269 if (ia == 0)
270 return (EADDRNOTAVAIL);
271 }
272 }
273 /*
274 * Don't do pcblookup call here; return interface in plocal_sin
275 * and exit to caller, that will do the lookup.
276 */
277 *plocal_sin = &ia->ia_addr;
278
279 }
280 return(0);
281}
282
283/*
284 * Outer subroutine:
285 * Connect from a socket to a specified address.
286 * Both address and port must be specified in argument sin.
287 * If don't have a local address for this socket yet,
288 * then pick one.
289 */
290int
291in_pcbconnect(inp, nam)
292 register struct inpcb *inp;
293 struct mbuf *nam;
294{
295 struct sockaddr_in *ifaddr;
296 register struct sockaddr_in *sin = mtod(nam, struct sockaddr_in *);
297 int error;
298
299 /*
300 * Call inner routine, to assign local interface address.
301 */
302 if (error = in_pcbladdr(inp, nam, &ifaddr))
303 return(error);
304
305 if (in_pcblookuphash(inp->inp_pcbinfo, sin->sin_addr, sin->sin_port,
306 inp->inp_laddr.s_addr ? inp->inp_laddr : ifaddr->sin_addr,
307 inp->inp_lport) != NULL)
308 return (EADDRINUSE);
309 if (inp->inp_laddr.s_addr == INADDR_ANY) {
310 if (inp->inp_lport == 0)
311 (void)in_pcbbind(inp, (struct mbuf *)0);
312 inp->inp_laddr = ifaddr->sin_addr;
313 }
314 inp->inp_faddr = sin->sin_addr;
315 inp->inp_fport = sin->sin_port;
316 in_pcbrehash(inp);
317 return (0);
318}
319
320void
321in_pcbdisconnect(inp)
322 struct inpcb *inp;
323{
324
325 inp->inp_faddr.s_addr = INADDR_ANY;
326 inp->inp_fport = 0;
327 in_pcbrehash(inp);
328 if (inp->inp_socket->so_state & SS_NOFDREF)
329 in_pcbdetach(inp);
330}
331
332void
333in_pcbdetach(inp)
334 struct inpcb *inp;
335{
336 struct socket *so = inp->inp_socket;
337 int s;
338
339 so->so_pcb = 0;
340 sofree(so);
341 if (inp->inp_options)
342 (void)m_free(inp->inp_options);
343 if (inp->inp_route.ro_rt)
344 rtfree(inp->inp_route.ro_rt);
345 ip_freemoptions(inp->inp_moptions);
346 s = splnet();
347 LIST_REMOVE(inp, inp_hash);
348 LIST_REMOVE(inp, inp_list);
349 splx(s);
350 FREE(inp, M_PCB);
351}
352
353void
354in_setsockaddr(inp, nam)
355 register struct inpcb *inp;
356 struct mbuf *nam;
357{
358 register struct sockaddr_in *sin;
359
360 nam->m_len = sizeof (*sin);
361 sin = mtod(nam, struct sockaddr_in *);
362 bzero((caddr_t)sin, sizeof (*sin));
363 sin->sin_family = AF_INET;
364 sin->sin_len = sizeof(*sin);
365 sin->sin_port = inp->inp_lport;
366 sin->sin_addr = inp->inp_laddr;
367}
368
369void
370in_setpeeraddr(inp, nam)
371 struct inpcb *inp;
372 struct mbuf *nam;
373{
374 register struct sockaddr_in *sin;
375
376 nam->m_len = sizeof (*sin);
377 sin = mtod(nam, struct sockaddr_in *);
378 bzero((caddr_t)sin, sizeof (*sin));
379 sin->sin_family = AF_INET;
380 sin->sin_len = sizeof(*sin);
381 sin->sin_port = inp->inp_fport;
382 sin->sin_addr = inp->inp_faddr;
383}
384
385/*
386 * Pass some notification to all connections of a protocol
387 * associated with address dst. The local address and/or port numbers
388 * may be specified to limit the search. The "usual action" will be
389 * taken, depending on the ctlinput cmd. The caller must filter any
390 * cmds that are uninteresting (e.g., no error in the map).
391 * Call the protocol specific routine (if any) to report
392 * any errors for each matching socket.
393 *
394 * Must be called at splnet.
395 */
396void
397in_pcbnotify(head, dst, fport_arg, laddr, lport_arg, cmd, notify)
398 struct inpcbhead *head;
399 struct sockaddr *dst;
400 u_int fport_arg, lport_arg;
401 struct in_addr laddr;
402 int cmd;
403 void (*notify) __P((struct inpcb *, int));
404{
405 register struct inpcb *inp, *oinp;
406 struct in_addr faddr;
407 u_short fport = fport_arg, lport = lport_arg;
408 int errno, s;
409
410 if ((unsigned)cmd > PRC_NCMDS || dst->sa_family != AF_INET)
411 return;
412 faddr = ((struct sockaddr_in *)dst)->sin_addr;
413 if (faddr.s_addr == INADDR_ANY)
414 return;
415
416 /*
417 * Redirects go to all references to the destination,
418 * and use in_rtchange to invalidate the route cache.
419 * Dead host indications: notify all references to the destination.
420 * Otherwise, if we have knowledge of the local port and address,
421 * deliver only to that socket.
422 */
423 if (PRC_IS_REDIRECT(cmd) || cmd == PRC_HOSTDEAD) {
424 fport = 0;
425 lport = 0;
426 laddr.s_addr = 0;
427 if (cmd != PRC_HOSTDEAD)
428 notify = in_rtchange;
429 }
430 errno = inetctlerrmap[cmd];
431 s = splnet();
432 for (inp = head->lh_first; inp != NULL;) {
433 if (inp->inp_faddr.s_addr != faddr.s_addr ||
434 inp->inp_socket == 0 ||
435 (lport && inp->inp_lport != lport) ||
436 (laddr.s_addr && inp->inp_laddr.s_addr != laddr.s_addr) ||
437 (fport && inp->inp_fport != fport)) {
438 inp = inp->inp_list.le_next;
439 continue;
440 }
441 oinp = inp;
442 inp = inp->inp_list.le_next;
443 if (notify)
444 (*notify)(oinp, errno);
445 }
446 splx(s);
447}
448
449/*
450 * Check for alternatives when higher level complains
451 * about service problems. For now, invalidate cached
452 * routing information. If the route was created dynamically
453 * (by a redirect), time to try a default gateway again.
454 */
455void
456in_losing(inp)
457 struct inpcb *inp;
458{
459 register struct rtentry *rt;
460 struct rt_addrinfo info;
461
462 if ((rt = inp->inp_route.ro_rt)) {
463 inp->inp_route.ro_rt = 0;
464 bzero((caddr_t)&info, sizeof(info));
465 info.rti_info[RTAX_DST] =
466 (struct sockaddr *)&inp->inp_route.ro_dst;
467 info.rti_info[RTAX_GATEWAY] = rt->rt_gateway;
468 info.rti_info[RTAX_NETMASK] = rt_mask(rt);
469 rt_missmsg(RTM_LOSING, &info, rt->rt_flags, 0);
470 if (rt->rt_flags & RTF_DYNAMIC)
471 (void) rtrequest(RTM_DELETE, rt_key(rt),
472 rt->rt_gateway, rt_mask(rt), rt->rt_flags,
473 (struct rtentry **)0);
474 else
475 /*
476 * A new route can be allocated
477 * the next time output is attempted.
478 */
479 rtfree(rt);
480 }
481}
482
483/*
484 * After a routing change, flush old routing
485 * and allocate a (hopefully) better one.
486 */
487void
488in_rtchange(inp, errno)
489 register struct inpcb *inp;
490 int errno;
491{
492 if (inp->inp_route.ro_rt) {
493 rtfree(inp->inp_route.ro_rt);
494 inp->inp_route.ro_rt = 0;
495 /*
496 * A new route can be allocated the next time
497 * output is attempted.
498 */
499 }
500}
501
502struct inpcb *
503in_pcblookup(head, faddr, fport_arg, laddr, lport_arg, flags)
504 struct inpcbhead *head;
505 struct in_addr faddr, laddr;
506 u_int fport_arg, lport_arg;
507 int flags;
508{
509 register struct inpcb *inp, *match = NULL;
510 int matchwild = 3, wildcard;
511 u_short fport = fport_arg, lport = lport_arg;
512 int s;
513
514 s = splnet();
515
516 for (inp = head->lh_first; inp != NULL; inp = inp->inp_list.le_next) {
517 if (inp->inp_lport != lport)
518 continue;
519 wildcard = 0;
520 if (inp->inp_faddr.s_addr != INADDR_ANY) {
521 if (faddr.s_addr == INADDR_ANY)
522 wildcard++;
523 else if (inp->inp_faddr.s_addr != faddr.s_addr ||
524 inp->inp_fport != fport)
525 continue;
526 } else {
527 if (faddr.s_addr != INADDR_ANY)
528 wildcard++;
529 }
530 if (inp->inp_laddr.s_addr != INADDR_ANY) {
531 if (laddr.s_addr == INADDR_ANY)
532 wildcard++;
533 else if (inp->inp_laddr.s_addr != laddr.s_addr)
534 continue;
535 } else {
536 if (laddr.s_addr != INADDR_ANY)
537 wildcard++;
538 }
539 if (wildcard && (flags & INPLOOKUP_WILDCARD) == 0)
540 continue;
541 if (wildcard < matchwild) {
542 match = inp;
543 matchwild = wildcard;
544 if (matchwild == 0) {
545 break;
546 }
547 }
548 }
549 splx(s);
550 return (match);
551}
552
553/*
554 * Lookup PCB in hash list.
555 */
556struct inpcb *
557in_pcblookuphash(pcbinfo, faddr, fport_arg, laddr, lport_arg)
558 struct inpcbinfo *pcbinfo;
559 struct in_addr faddr, laddr;
560 u_int fport_arg, lport_arg;
561{
562 struct inpcbhead *head;
563 register struct inpcb *inp;
564 u_short fport = fport_arg, lport = lport_arg;
565 int s;
566
567 s = splnet();
568 /*
569 * First look for an exact match.
570 */
571 head = &pcbinfo->hashbase[(faddr.s_addr + lport + fport) % pcbinfo->hashsize];
572
573 for (inp = head->lh_first; inp != NULL; inp = inp->inp_hash.le_next) {
574 if (inp->inp_faddr.s_addr != faddr.s_addr ||
575 inp->inp_fport != fport ||
576 inp->inp_lport != lport ||
577 inp->inp_laddr.s_addr != laddr.s_addr)
578 continue;
579 /*
580 * Move PCB to head of this hash chain so that it can be
581 * found more quickly in the future.
582 */
583 if (inp != head->lh_first) {
584 LIST_REMOVE(inp, inp_hash);
585 LIST_INSERT_HEAD(head, inp, inp_hash);
586 }
587 break;
588 }
589 splx(s);
590 return (inp);
591}
592
593/*
594 * Insert PCB into hash chain. Must be called at splnet.
595 */
596void
597in_pcbinshash(inp)
598 struct inpcb *inp;
599{
600 struct inpcbhead *head;
601
602 head = &inp->inp_pcbinfo->hashbase[(inp->inp_faddr.s_addr +
603 inp->inp_lport + inp->inp_fport) % inp->inp_pcbinfo->hashsize];
604
605 LIST_INSERT_HEAD(head, inp, inp_hash);
606}
607
608void
609in_pcbrehash(inp)
610 struct inpcb *inp;
611{
612 struct inpcbhead *head;
613 int s;
614
615 s = splnet();
616 LIST_REMOVE(inp, inp_hash);
617
618 head = &inp->inp_pcbinfo->hashbase[(inp->inp_faddr.s_addr +
619 inp->inp_lport + inp->inp_fport) % inp->inp_pcbinfo->hashsize];
620
621 LIST_INSERT_HEAD(head, inp, inp_hash);
622 splx(s);
623}