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