Annotation of sys/netinet6/in6_pcb.c, Revision 1.1.1.1
1.1 nbrk 1: /* $OpenBSD: in6_pcb.c,v 1.43 2005/06/24 07:57:24 markus Exp $ */
2:
3: /*
4: * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
5: * 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. Neither the name of the project nor the names of its contributors
16: * may be used to endorse or promote products derived from this software
17: * without specific prior written permission.
18: *
19: * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
20: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22: * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
23: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29: * SUCH DAMAGE.
30: */
31:
32: /*
33: * @(#)COPYRIGHT 1.1 (NRL) 17 January 1995
34: *
35: * NRL grants permission for redistribution and use in source and binary
36: * forms, with or without modification, of the software and documentation
37: * created at NRL provided that the following conditions are met:
38: *
39: * 1. Redistributions of source code must retain the above copyright
40: * notice, this list of conditions and the following disclaimer.
41: * 2. Redistributions in binary form must reproduce the above copyright
42: * notice, this list of conditions and the following disclaimer in the
43: * documentation and/or other materials provided with the distribution.
44: * 3. All advertising materials mentioning features or use of this software
45: * must display the following acknowledgements:
46: * This product includes software developed by the University of
47: * California, Berkeley and its contributors.
48: * This product includes software developed at the Information
49: * Technology Division, US Naval Research Laboratory.
50: * 4. Neither the name of the NRL nor the names of its contributors
51: * may be used to endorse or promote products derived from this software
52: * without specific prior written permission.
53: *
54: * THE SOFTWARE PROVIDED BY NRL IS PROVIDED BY NRL AND CONTRIBUTORS ``AS
55: * IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
56: * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
57: * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NRL OR
58: * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
59: * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
60: * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
61: * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
62: * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
63: * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
64: * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
65: *
66: * The views and conclusions contained in the software and documentation
67: * are those of the authors and should not be interpreted as representing
68: * official policies, either expressed or implied, of the US Naval
69: * Research Laboratory (NRL).
70: */
71:
72: /*
73: * Copyright (c) 1982, 1986, 1990, 1993, 1995
74: * Regents of the University of California. All rights reserved.
75: *
76: * Redistribution and use in source and binary forms, with or without
77: * modification, are permitted provided that the following conditions
78: * are met:
79: * 1. Redistributions of source code must retain the above copyright
80: * notice, this list of conditions and the following disclaimer.
81: * 2. Redistributions in binary form must reproduce the above copyright
82: * notice, this list of conditions and the following disclaimer in the
83: * documentation and/or other materials provided with the distribution.
84: * 3. Neither the name of the University nor the names of its contributors
85: * may be used to endorse or promote products derived from this software
86: * without specific prior written permission.
87: *
88: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
89: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
90: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
91: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
92: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
93: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
94: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
95: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
96: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
97: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
98: * SUCH DAMAGE.
99: *
100: */
101:
102: #include <sys/param.h>
103: #include <sys/systm.h>
104: #include <sys/malloc.h>
105: #include <sys/mbuf.h>
106: #include <sys/domain.h>
107: #include <sys/protosw.h>
108: #include <sys/socket.h>
109: #include <sys/socketvar.h>
110: #include <sys/errno.h>
111: #include <sys/time.h>
112: #include <sys/proc.h>
113:
114: #include <net/if.h>
115: #include <net/route.h>
116:
117: #include <netinet/in.h>
118: #include <netinet/in_systm.h>
119: #include <netinet/ip.h>
120: #include <netinet/in_pcb.h>
121:
122: #include <netinet6/in6_var.h>
123: #include <netinet/ip6.h>
124: #include <netinet6/ip6_var.h>
125:
126: /*
127: * External globals
128: */
129:
130: #include <dev/rndvar.h>
131:
132: extern struct in6_ifaddr *in6_ifaddr;
133:
134: /*
135: * Globals
136: */
137:
138: struct in6_addr zeroin6_addr;
139:
140: extern int ipport_firstauto;
141: extern int ipport_lastauto;
142: extern int ipport_hifirstauto;
143: extern int ipport_hilastauto;
144:
145: /*
146: * Keep separate inet6ctlerrmap, because I may remap some of these.
147: * I also put it here, because, quite frankly, it belongs here, not in
148: * ip{v6,}_input().
149: */
150: #if 0
151: u_char inet6ctlerrmap[PRC_NCMDS] = {
152: 0, 0, 0, 0,
153: 0, EMSGSIZE, EHOSTDOWN, EHOSTUNREACH,
154: EHOSTUNREACH, EHOSTUNREACH, ECONNREFUSED, ECONNREFUSED,
155: EMSGSIZE, EHOSTUNREACH, 0, 0,
156: 0, 0, 0, 0,
157: ENOPROTOOPT
158: };
159: #endif
160:
161: /*
162: * Bind an address (or at least a port) to an PF_INET6 socket.
163: */
164: int
165: in6_pcbbind(inp, nam)
166: struct inpcb *inp;
167: struct mbuf *nam;
168: {
169: struct socket *so = inp->inp_socket;
170:
171: struct inpcbtable *head = inp->inp_table;
172: struct sockaddr_in6 *sin6;
173: struct proc *p = curproc; /* XXX */
174: u_short lport = 0;
175: int wild = INPLOOKUP_IPV6, reuseport = (so->so_options & SO_REUSEPORT);
176: int error;
177:
178: /*
179: * REMINDER: Once up to speed, flow label processing should go here,
180: * too. (Same with in6_pcbconnect.)
181: */
182: if (in6_ifaddr == 0)
183: return EADDRNOTAVAIL;
184:
185: if (inp->inp_lport != 0 || !IN6_IS_ADDR_UNSPECIFIED(&inp->inp_laddr6))
186: return EINVAL; /* If already bound, EINVAL! */
187:
188: if ((so->so_options & (SO_REUSEADDR | SO_REUSEPORT)) == 0 &&
189: ((so->so_proto->pr_flags & PR_CONNREQUIRED) == 0 ||
190: (so->so_options & SO_ACCEPTCONN) == 0))
191: wild |= INPLOOKUP_WILDCARD;
192:
193: /*
194: * If I did get a sockaddr passed in...
195: */
196: if (nam) {
197: sin6 = mtod(nam, struct sockaddr_in6 *);
198: if (nam->m_len != sizeof (*sin6))
199: return EINVAL;
200:
201: /*
202: * Unlike v4, I have no qualms about EAFNOSUPPORT if the
203: * wretched family is not filled in!
204: */
205: if (sin6->sin6_family != AF_INET6)
206: return EAFNOSUPPORT;
207:
208: /* KAME hack: embed scopeid */
209: if (in6_embedscope(&sin6->sin6_addr, sin6, inp, NULL) != 0)
210: return EINVAL;
211: /* this must be cleared for ifa_ifwithaddr() */
212: sin6->sin6_scope_id = 0;
213:
214: lport = sin6->sin6_port;
215:
216: /* reject IPv4 mapped address, we have no support for it */
217: if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr))
218: return EADDRNOTAVAIL;
219:
220: if (IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr)) {
221: /*
222: * Treat SO_REUSEADDR as SO_REUSEPORT for multicast;
223: * allow complete duplication of binding if
224: * SO_REUSEPORT is set, or if SO_REUSEADDR is set
225: * and a multicast address is bound on both
226: * new and duplicated sockets.
227: */
228: if (so->so_options & SO_REUSEADDR)
229: reuseport = SO_REUSEADDR | SO_REUSEPORT;
230: } else if (!IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) {
231: struct ifaddr *ia = NULL;
232:
233: sin6->sin6_port = 0; /*
234: * Yechhhh, because of upcoming
235: * call to ifa_ifwithaddr(), which
236: * does bcmp's over the PORTS as
237: * well. (What about flow?)
238: */
239: sin6->sin6_flowinfo = 0;
240: if ((ia = ifa_ifwithaddr((struct sockaddr *)sin6))
241: == NULL)
242: return EADDRNOTAVAIL;
243:
244: /*
245: * bind to an anycast address might accidentally
246: * cause sending a packet with an anycast source
247: * address, so we forbid it.
248: *
249: * We should allow to bind to a deprecated address,
250: * since the application dare to use it.
251: * But, can we assume that they are careful enough
252: * to check if the address is deprecated or not?
253: * Maybe, as a safeguard, we should have a setsockopt
254: * flag to control the bind(2) behavior against
255: * deprecated addresses (default: forbid bind(2)).
256: */
257: if (ia &&
258: ((struct in6_ifaddr *)ia)->ia6_flags &
259: (IN6_IFF_ANYCAST|IN6_IFF_NOTREADY|IN6_IFF_DETACHED))
260: return (EADDRNOTAVAIL);
261: }
262: if (lport) {
263: struct inpcb *t;
264:
265: /*
266: * Question: Do we wish to continue the Berkeley
267: * tradition of ports < IPPORT_RESERVED be only for
268: * root?
269: * Answer: For now yes, but IMHO, it should be REMOVED!
270: * OUCH: One other thing, is there no better way of
271: * finding a process for a socket instead of using
272: * curproc? (Marked with BSD's {in,}famous XXX ?
273: */
274: if (ntohs(lport) < IPPORT_RESERVED &&
275: (error = suser(p, 0)))
276: return error;
277:
278: t = in_pcblookup(head,
279: (struct in_addr *)&zeroin6_addr, 0,
280: (struct in_addr *)&sin6->sin6_addr, lport,
281: wild);
282:
283: if (t && (reuseport & t->inp_socket->so_options) == 0)
284: return EADDRINUSE;
285: }
286: inp->inp_laddr6 = sin6->sin6_addr;
287: }
288:
289: if (lport == 0) {
290: error = in6_pcbsetport(&inp->inp_laddr6, inp, p);
291: if (error != 0)
292: return error;
293: } else {
294: inp->inp_lport = lport;
295: in_pcbrehash(inp);
296: }
297:
298: return 0;
299: }
300:
301: int
302: in6_pcbsetport(laddr, inp, p)
303: struct in6_addr *laddr;
304: struct inpcb *inp;
305: struct proc *p;
306: {
307: struct socket *so = inp->inp_socket;
308: struct inpcbtable *table = inp->inp_table;
309: u_int16_t first, last;
310: u_int16_t *lastport = &inp->inp_table->inpt_lastport;
311: u_int16_t lport = 0;
312: int count;
313: int wild = INPLOOKUP_IPV6;
314: int error;
315:
316: /* XXX we no longer support IPv4 mapped address, so no tweaks here */
317:
318: if ((so->so_options & (SO_REUSEADDR|SO_REUSEPORT)) == 0 &&
319: ((so->so_proto->pr_flags & PR_CONNREQUIRED) == 0 ||
320: (so->so_options & SO_ACCEPTCONN) == 0))
321: wild |= INPLOOKUP_WILDCARD;
322:
323: if (inp->inp_flags & INP_HIGHPORT) {
324: first = ipport_hifirstauto; /* sysctl */
325: last = ipport_hilastauto;
326: } else if (inp->inp_flags & INP_LOWPORT) {
327: if ((error = suser(p, 0)))
328: return (EACCES);
329: first = IPPORT_RESERVED-1; /* 1023 */
330: last = 600; /* not IPPORT_RESERVED/2 */
331: } else {
332: first = ipport_firstauto; /* sysctl */
333: last = ipport_lastauto;
334: }
335:
336: /*
337: * Simple check to ensure all ports are not used up causing
338: * a deadlock here.
339: *
340: * We split the two cases (up and down) so that the direction
341: * is not being tested on each round of the loop.
342: */
343:
344: if (first > last) {
345: /*
346: * counting down
347: */
348: count = first - last;
349: if (count)
350: *lastport = first - (arc4random() % count);
351:
352: do {
353: if (count-- < 0) /* completely used? */
354: return (EADDRNOTAVAIL);
355: --*lastport;
356: if (*lastport > first || *lastport < last)
357: *lastport = first;
358: lport = htons(*lastport);
359: } while (in_baddynamic(*lastport, so->so_proto->pr_protocol) ||
360: in_pcblookup(table, &zeroin6_addr, 0,
361: &inp->inp_laddr6, lport, wild));
362: } else {
363: /*
364: * counting up
365: */
366: count = last - first;
367: if (count)
368: *lastport = first + (arc4random() % count);
369:
370: do {
371: if (count-- < 0) /* completely used? */
372: return (EADDRNOTAVAIL);
373: ++*lastport;
374: if (*lastport < first || *lastport > last)
375: *lastport = first;
376: lport = htons(*lastport);
377: } while (in_baddynamic(*lastport, so->so_proto->pr_protocol) ||
378: in_pcblookup(table, &zeroin6_addr, 0,
379: &inp->inp_laddr6, lport, wild));
380: }
381:
382: inp->inp_lport = lport;
383: in_pcbrehash(inp);
384:
385: #if 0
386: inp->inp_flowinfo = 0; /* XXX */
387: #endif
388:
389: return 0;
390: }
391:
392: /*
393: * Connect from a socket to a specified address.
394: * Both address and port must be specified in argument sin6.
395: * Eventually, flow labels will have to be dealt with here, as well.
396: *
397: * If don't have a local address for this socket yet,
398: * then pick one.
399: *
400: * I believe this has to be called at splnet().
401: */
402: int
403: in6_pcbconnect(inp, nam)
404: struct inpcb *inp;
405: struct mbuf *nam;
406: {
407: struct in6_addr *in6a = NULL;
408: struct sockaddr_in6 *sin6 = mtod(nam, struct sockaddr_in6 *);
409: struct ifnet *ifp = NULL; /* outgoing interface */
410: int error = 0;
411: struct sockaddr_in6 tmp;
412:
413: (void)&in6a; /* XXX fool gcc */
414:
415: if (nam->m_len != sizeof(*sin6))
416: return (EINVAL);
417: if (sin6->sin6_family != AF_INET6)
418: return (EAFNOSUPPORT);
419: if (sin6->sin6_port == 0)
420: return (EADDRNOTAVAIL);
421:
422: /* reject IPv4 mapped address, we have no support for it */
423: if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr))
424: return EADDRNOTAVAIL;
425:
426: /* sanity check for mapped address case */
427: if (IN6_IS_ADDR_V4MAPPED(&inp->inp_laddr6))
428: return EINVAL;
429:
430: /* protect *sin6 from overwrites */
431: tmp = *sin6;
432: sin6 = &tmp;
433:
434: /* KAME hack: embed scopeid */
435: if (in6_embedscope(&sin6->sin6_addr, sin6, inp, &ifp) != 0)
436: return EINVAL;
437: /* this must be cleared for ifa_ifwithaddr() */
438: sin6->sin6_scope_id = 0;
439:
440: /* Source address selection. */
441: /*
442: * XXX: in6_selectsrc might replace the bound local address
443: * with the address specified by setsockopt(IPV6_PKTINFO).
444: * Is it the intended behavior?
445: */
446: in6a = in6_selectsrc(sin6, inp->inp_outputopts6,
447: inp->inp_moptions6, &inp->inp_route6, &inp->inp_laddr6,
448: &error);
449: if (in6a == 0) {
450: if (error == 0)
451: error = EADDRNOTAVAIL;
452: return (error);
453: }
454:
455: if (inp->inp_route6.ro_rt)
456: ifp = inp->inp_route6.ro_rt->rt_ifp;
457:
458: inp->inp_ipv6.ip6_hlim = (u_int8_t)in6_selecthlim(inp, ifp);
459:
460: if (in_pcblookup(inp->inp_table, &sin6->sin6_addr, sin6->sin6_port,
461: IN6_IS_ADDR_UNSPECIFIED(&inp->inp_laddr6) ? in6a : &inp->inp_laddr6,
462: inp->inp_lport, INPLOOKUP_IPV6)) {
463: return (EADDRINUSE);
464: }
465: if (IN6_IS_ADDR_UNSPECIFIED(&inp->inp_laddr6)) {
466: if (inp->inp_lport == 0)
467: (void)in6_pcbbind(inp, (struct mbuf *)0);
468: inp->inp_laddr6 = *in6a;
469: }
470: inp->inp_faddr6 = sin6->sin6_addr;
471: inp->inp_fport = sin6->sin6_port;
472: inp->inp_flowinfo &= ~IPV6_FLOWLABEL_MASK;
473: if (ip6_auto_flowlabel)
474: inp->inp_flowinfo |=
475: (htonl(ip6_randomflowlabel()) & IPV6_FLOWLABEL_MASK);
476: in_pcbrehash(inp);
477: return (0);
478: }
479:
480: /*
481: * Pass some notification to all connections of a protocol
482: * associated with address dst. The local address and/or port numbers
483: * may be specified to limit the search. The "usual action" will be
484: * taken, depending on the ctlinput cmd. The caller must filter any
485: * cmds that are uninteresting (e.g., no error in the map).
486: * Call the protocol specific routine (if any) to report
487: * any errors for each matching socket.
488: *
489: * Also perform input-side security policy check
490: * once PCB to be notified has been located.
491: *
492: * Must be called at splnet.
493: */
494: int
495: in6_pcbnotify(head, dst, fport_arg, src, lport_arg, cmd, cmdarg, notify)
496: struct inpcbtable *head;
497: struct sockaddr *dst, *src;
498: uint fport_arg;
499: uint lport_arg;
500: int cmd;
501: void *cmdarg;
502: void (*notify)(struct inpcb *, int);
503: {
504: struct inpcb *inp, *ninp;
505: u_short fport = fport_arg, lport = lport_arg;
506: struct sockaddr_in6 sa6_src, *sa6_dst;
507: int errno, nmatch = 0;
508: u_int32_t flowinfo;
509:
510: if ((unsigned)cmd >= PRC_NCMDS || dst->sa_family != AF_INET6)
511: return (0);
512:
513: sa6_dst = (struct sockaddr_in6 *)dst;
514: if (IN6_IS_ADDR_UNSPECIFIED(&sa6_dst->sin6_addr))
515: return (0);
516: if (IN6_IS_ADDR_V4MAPPED(&sa6_dst->sin6_addr)) {
517: #ifdef DIAGNOSTIC
518: printf("Huh? Thought in6_pcbnotify() never got "
519: "called with mapped!\n");
520: #endif
521: return (0);
522: }
523:
524: /*
525: * note that src can be NULL when we get notify by local fragmentation.
526: */
527: sa6_src = (src == NULL) ? sa6_any : *(struct sockaddr_in6 *)src;
528: flowinfo = sa6_src.sin6_flowinfo;
529:
530: /*
531: * Redirects go to all references to the destination,
532: * and use in_rtchange to invalidate the route cache.
533: * Dead host indications: also use in_rtchange to invalidate
534: * the cache, and deliver the error to all the sockets.
535: * Otherwise, if we have knowledge of the local port and address,
536: * deliver only to that socket.
537: */
538: if (PRC_IS_REDIRECT(cmd) || cmd == PRC_HOSTDEAD) {
539: fport = 0;
540: lport = 0;
541: sa6_src.sin6_addr = in6addr_any;
542:
543: if (cmd != PRC_HOSTDEAD)
544: notify = in_rtchange;
545: }
546: errno = inet6ctlerrmap[cmd];
547:
548: for (inp = CIRCLEQ_FIRST(&head->inpt_queue);
549: inp != CIRCLEQ_END(&head->inpt_queue); inp = ninp) {
550: ninp = CIRCLEQ_NEXT(inp, inp_queue);
551:
552: if ((inp->inp_flags & INP_IPV6) == 0)
553: continue;
554:
555: /*
556: * Under the following condition, notify of redirects
557: * to the pcb, without making address matches against inpcb.
558: * - redirect notification is arrived.
559: * - the inpcb is unconnected.
560: * - the inpcb is caching !RTF_HOST routing entry.
561: * - the ICMPv6 notification is from the gateway cached in the
562: * inpcb. i.e. ICMPv6 notification is from nexthop gateway
563: * the inpcb used very recently.
564: *
565: * This is to improve interaction between netbsd/openbsd
566: * redirect handling code, and inpcb route cache code.
567: * without the clause, !RTF_HOST routing entry (which carries
568: * gateway used by inpcb right before the ICMPv6 redirect)
569: * will be cached forever in unconnected inpcb.
570: *
571: * There still is a question regarding to what is TRT:
572: * - On bsdi/freebsd, RTF_HOST (cloned) routing entry will be
573: * generated on packet output. inpcb will always cache
574: * RTF_HOST routing entry so there's no need for the clause
575: * (ICMPv6 redirect will update RTF_HOST routing entry,
576: * and inpcb is caching it already).
577: * However, bsdi/freebsd are vulnerable to local DoS attacks
578: * due to the cloned routing entries.
579: * - Specwise, "destination cache" is mentioned in RFC2461.
580: * Jinmei says that it implies bsdi/freebsd behavior, itojun
581: * is not really convinced.
582: * - Having hiwat/lowat on # of cloned host route (redirect/
583: * pmtud) may be a good idea. netbsd/openbsd has it. see
584: * icmp6_mtudisc_update().
585: */
586: if ((PRC_IS_REDIRECT(cmd) || cmd == PRC_HOSTDEAD) &&
587: IN6_IS_ADDR_UNSPECIFIED(&inp->inp_laddr6) &&
588: inp->inp_route.ro_rt &&
589: !(inp->inp_route.ro_rt->rt_flags & RTF_HOST)) {
590: struct sockaddr_in6 *dst6;
591:
592: dst6 = (struct sockaddr_in6 *)&inp->inp_route.ro_dst;
593: if (IN6_ARE_ADDR_EQUAL(&dst6->sin6_addr,
594: &sa6_dst->sin6_addr))
595: goto do_notify;
596: }
597:
598: /*
599: * Detect if we should notify the error. If no source and
600: * destination ports are specified, but non-zero flowinfo and
601: * local address match, notify the error. This is the case
602: * when the error is delivered with an encrypted buffer
603: * by ESP. Otherwise, just compare addresses and ports
604: * as usual.
605: */
606: if (lport == 0 && fport == 0 && flowinfo &&
607: inp->inp_socket != NULL &&
608: flowinfo == (inp->inp_flowinfo & IPV6_FLOWLABEL_MASK) &&
609: IN6_ARE_ADDR_EQUAL(&inp->inp_laddr6, &sa6_src.sin6_addr))
610: goto do_notify;
611: else if (!IN6_ARE_ADDR_EQUAL(&inp->inp_faddr6,
612: &sa6_dst->sin6_addr) ||
613: inp->inp_socket == 0 ||
614: (lport && inp->inp_lport != lport) ||
615: (!IN6_IS_ADDR_UNSPECIFIED(&sa6_src.sin6_addr) &&
616: !IN6_ARE_ADDR_EQUAL(&inp->inp_laddr6,
617: &sa6_src.sin6_addr)) ||
618: (fport && inp->inp_fport != fport)) {
619: continue;
620: }
621: do_notify:
622: nmatch++;
623: if (notify)
624: (*notify)(inp, errno);
625: }
626: return (nmatch);
627: }
628:
629: /*
630: * Get the local address/port, and put it in a sockaddr_in6.
631: * This services the getsockname(2) call.
632: */
633: int
634: in6_setsockaddr(inp, nam)
635: struct inpcb *inp;
636: struct mbuf *nam;
637: {
638: struct sockaddr_in6 *sin6;
639:
640: nam->m_len = sizeof(struct sockaddr_in6);
641: sin6 = mtod(nam,struct sockaddr_in6 *);
642:
643: bzero ((caddr_t)sin6,sizeof(struct sockaddr_in6));
644: sin6->sin6_family = AF_INET6;
645: sin6->sin6_len = sizeof(struct sockaddr_in6);
646: sin6->sin6_port = inp->inp_lport;
647: sin6->sin6_addr = inp->inp_laddr6;
648: /* KAME hack: recover scopeid */
649: (void)in6_recoverscope(sin6, &inp->inp_laddr6, NULL);
650:
651: return 0;
652: }
653:
654: /*
655: * Get the foreign address/port, and put it in a sockaddr_in6.
656: * This services the getpeername(2) call.
657: */
658: int
659: in6_setpeeraddr(inp, nam)
660: struct inpcb *inp;
661: struct mbuf *nam;
662: {
663: struct sockaddr_in6 *sin6;
664:
665: nam->m_len = sizeof(struct sockaddr_in6);
666: sin6 = mtod(nam,struct sockaddr_in6 *);
667:
668: bzero ((caddr_t)sin6,sizeof(struct sockaddr_in6));
669: sin6->sin6_family = AF_INET6;
670: sin6->sin6_len = sizeof(struct sockaddr_in6);
671: sin6->sin6_port = inp->inp_fport;
672: sin6->sin6_addr = inp->inp_faddr6;
673: /* KAME hack: recover scopeid */
674: (void)in6_recoverscope(sin6, &inp->inp_faddr6, NULL);
675:
676: return 0;
677: }
CVSweb