in6_src.c revision 121315
11556Srgrimes/* $FreeBSD: head/sys/netinet6/in6_src.c 121315 2003-10-21 20:05:32Z ume $ */ 21556Srgrimes/* $KAME: in6_src.c,v 1.37 2001/03/29 05:34:31 itojun Exp $ */ 31556Srgrimes 41556Srgrimes/* 51556Srgrimes * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. 61556Srgrimes * All rights reserved. 71556Srgrimes * 81556Srgrimes * Redistribution and use in source and binary forms, with or without 91556Srgrimes * modification, are permitted provided that the following conditions 101556Srgrimes * are met: 111556Srgrimes * 1. Redistributions of source code must retain the above copyright 121556Srgrimes * notice, this list of conditions and the following disclaimer. 131556Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 141556Srgrimes * notice, this list of conditions and the following disclaimer in the 151556Srgrimes * documentation and/or other materials provided with the distribution. 161556Srgrimes * 3. Neither the name of the project nor the names of its contributors 171556Srgrimes * may be used to endorse or promote products derived from this software 181556Srgrimes * without specific prior written permission. 191556Srgrimes * 201556Srgrimes * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 211556Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 221556Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 231556Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 241556Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 251556Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 261556Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 271556Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 281556Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 291556Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 301556Srgrimes * SUCH DAMAGE. 311556Srgrimes */ 321556Srgrimes 331556Srgrimes/* 3436150Scharnier * Copyright (c) 1982, 1986, 1991, 1993 3536150Scharnier * The Regents of the University of California. All rights reserved. 3636150Scharnier * 371556Srgrimes * Redistribution and use in source and binary forms, with or without 3899110Sobrien * modification, are permitted provided that the following conditions 3999110Sobrien * are met: 401556Srgrimes * 1. Redistributions of source code must retain the above copyright 4117987Speter * notice, this list of conditions and the following disclaimer. 4217987Speter * 2. Redistributions in binary form must reproduce the above copyright 4317987Speter * notice, this list of conditions and the following disclaimer in the 4420425Ssteve * documentation and/or other materials provided with the distribution. 4517987Speter * 3. All advertising materials mentioning features or use of this software 4617987Speter * must display the following acknowledgement: 47100661Stjr * This product includes software developed by the University of 4817987Speter * California, Berkeley and its contributors. 491556Srgrimes * 4. Neither the name of the University nor the names of its contributors 501556Srgrimes * may be used to endorse or promote products derived from this software 511556Srgrimes * without specific prior written permission. 521556Srgrimes * 531556Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 541556Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 551556Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 561556Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 571556Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 581556Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 591556Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 601556Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 6120425Ssteve * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 6217987Speter * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 631556Srgrimes * SUCH DAMAGE. 6417987Speter * 6520425Ssteve * @(#)in_pcb.c 8.2 (Berkeley) 1/4/94 66223060Sjilles */ 671556Srgrimes 68213811Sobrien#include "opt_inet.h" 69213811Sobrien#include "opt_inet6.h" 70213811Sobrien 71213811Sobrien#include <sys/param.h> 72213811Sobrien#include <sys/systm.h> 73213811Sobrien#include <sys/malloc.h> 74213811Sobrien#include <sys/mbuf.h> 75213811Sobrien#include <sys/protosw.h> 761556Srgrimes#include <sys/socket.h> 77213760Sobrien#include <sys/socketvar.h> 78213760Sobrien#include <sys/errno.h> 79213760Sobrien#include <sys/time.h> 801556Srgrimes 811556Srgrimes#include <net/if.h> 82240541Sjilles#include <net/route.h> 8317987Speter 84201053Sjilles#include <netinet/in.h> 85200956Sjilles#include <netinet/in_var.h> 861556Srgrimes#include <netinet/in_systm.h> 871556Srgrimes#include <netinet/ip.h> 88222154Sjilles#include <netinet/in_pcb.h> 89222154Sjilles#include <netinet6/in6_var.h> 90222292Sjilles#include <netinet/ip6.h> 911556Srgrimes#include <netinet6/in6_pcb.h> 92100664Stjr#include <netinet6/ip6_var.h> 93240541Sjilles#include <netinet6/nd6.h> 9497092Stjr#ifdef ENABLE_DEFAULT_SCOPE 95222154Sjilles#include <netinet6/scope6_var.h> 96222154Sjilles#endif 97222154Sjilles 9897092Stjr#include <net/net_osdep.h> 9997092Stjr 10097092Stjr/* 10197092Stjr * Return an IPv6 address, which is the most appropriate for a given 10297092Stjr * destination and user specified options. 10397092Stjr * If necessary, this function lookups the routing table and returns 10497092Stjr * an entry to the caller for later use. 10597092Stjr */ 10697092Stjrstruct in6_addr * 107240541Sjillesin6_selectsrc(dstsock, opts, mopts, ro, laddr, errorp) 10897092Stjr struct sockaddr_in6 *dstsock; 10997092Stjr struct ip6_pktopts *opts; 110240541Sjilles struct ip6_moptions *mopts; 1111556Srgrimes struct route_in6 *ro; 1125234Sbde struct in6_addr *laddr; 1135234Sbde int *errorp; 1141556Srgrimes{ 1151556Srgrimes struct in6_addr *dst; 11612273Speter struct in6_ifaddr *ia6 = 0; 11712273Speter struct in6_pktinfo *pi = NULL; 11812273Speter 11912273Speter dst = &dstsock->sin6_addr; 1201556Srgrimes *errorp = 0; 121222381Sjilles 122222381Sjilles /* 123222381Sjilles * If the source address is explicitly specified by the caller, 124222381Sjilles * use it. 1251556Srgrimes */ 1261556Srgrimes if (opts && (pi = opts->ip6po_pktinfo) && 127230095Sjilles !IN6_IS_ADDR_UNSPECIFIED(&pi->ipi6_addr)) 128230095Sjilles return (&pi->ipi6_addr); 129230095Sjilles 130230095Sjilles /* 131230095Sjilles * If the source address is not specified but the socket(if any) 132230095Sjilles * is already bound, use the bound address. 1331556Srgrimes */ 1341556Srgrimes if (laddr && !IN6_IS_ADDR_UNSPECIFIED(laddr)) 1351556Srgrimes return (laddr); 1361556Srgrimes 13738886Stegge /* 138159551Sstefanf * If the caller doesn't specify the source address but 139159551Sstefanf * the outgoing interface, use an address associated with 140159551Sstefanf * the interface. 1411556Srgrimes */ 142222154Sjilles if (pi && pi->ipi6_ifindex) { 143222154Sjilles /* XXX boundary check is assumed to be already done. */ 144222154Sjilles ia6 = in6_ifawithscope(ifnet_byindex(pi->ipi6_ifindex), dst); 145222292Sjilles if (ia6 == 0) { 146222292Sjilles *errorp = EADDRNOTAVAIL; 1471556Srgrimes return (0); 1481556Srgrimes } 149222292Sjilles return (&satosin6(&ia6->ia_addr)->sin6_addr); 15017987Speter } 15117987Speter 1521556Srgrimes /* 1531556Srgrimes * If the destination address is a link-local unicast address or 1541556Srgrimes * a multicast address, and if the outgoing interface is specified 1551556Srgrimes * by the sin6_scope_id filed, use an address associated with the 15697092Stjr * interface. 15720774Ssteve * XXX: We're now trying to define more specific semantics of 1581556Srgrimes * sin6_scope_id field, so this part will be rewritten in 159213811Sobrien * the near future. 16097092Stjr */ 16120425Ssteve if ((IN6_IS_ADDR_LINKLOCAL(dst) || IN6_IS_ADDR_MULTICAST(dst)) && 162222154Sjilles dstsock->sin6_scope_id) { 16397092Stjr /* 16497092Stjr * I'm not sure if boundary check for scope_id is done 16597092Stjr * somewhere... 16697092Stjr */ 167222154Sjilles if (dstsock->sin6_scope_id < 0 || 16897092Stjr if_index < dstsock->sin6_scope_id) { 16997092Stjr *errorp = ENXIO; /* XXX: better error? */ 17097092Stjr return (0); 17197092Stjr } 17297092Stjr ia6 = in6_ifawithscope(ifnet_byindex(dstsock->sin6_scope_id), 173222154Sjilles dst); 17497092Stjr if (ia6 == 0) { 17597092Stjr *errorp = EADDRNOTAVAIL; 176213811Sobrien return (0); 17797092Stjr } 17897092Stjr return (&satosin6(&ia6->ia_addr)->sin6_addr); 17938886Stegge } 18038886Stegge 18138886Stegge /* 18238886Stegge * If the destination address is a multicast address and 18338886Stegge * the outgoing interface for the address is specified 18438886Stegge * by the caller, use an address associated with the interface. 185262951Sjmmv * There is a sanity check here; if the destination has node-local 18620425Ssteve * scope, the outgoing interfacde should be a loopback address. 18738886Stegge * Even if the outgoing interface is not specified, we also 18838886Stegge * choose a loopback interface as the outgoing interface. 18938886Stegge */ 19038886Stegge if (IN6_IS_ADDR_MULTICAST(dst)) { 19138886Stegge struct ifnet *ifp = mopts ? mopts->im6o_multicast_ifp : NULL; 19238886Stegge 193262951Sjmmv if (ifp == NULL && IN6_IS_ADDR_MC_INTFACELOCAL(dst)) { 194262951Sjmmv ifp = &loif[0]; 195262951Sjmmv } 19638886Stegge 19738886Stegge if (ifp) { 19838886Stegge ia6 = in6_ifawithscope(ifp, dst); 19938886Stegge if (ia6 == 0) { 20038886Stegge *errorp = EADDRNOTAVAIL; 20138886Stegge return (0); 20238886Stegge } 20338886Stegge return (&satosin6(&ia6->ia_addr)->sin6_addr); 20438886Stegge } 20538886Stegge } 20638886Stegge 20738886Stegge /* 20838886Stegge * If the next hop address for the packet is specified 209215783Sjilles * by caller, use an address associated with the route 21038886Stegge * to the next hop. 21138886Stegge */ 21238886Stegge { 21397092Stjr struct sockaddr_in6 *sin6_next; 21438886Stegge struct rtentry *rt; 21538886Stegge 21638886Stegge if (opts && opts->ip6po_nexthop) { 21738886Stegge sin6_next = satosin6(opts->ip6po_nexthop); 21838886Stegge rt = nd6_lookup(&sin6_next->sin6_addr, 1, NULL); 2191556Srgrimes if (rt) { 220176521Sstefanf ia6 = in6_ifawithscope(rt->rt_ifp, dst); 2211556Srgrimes if (ia6 == 0) 22297092Stjr ia6 = ifatoia6(rt->rt_ifa); 2231556Srgrimes } 224176521Sstefanf if (ia6 == 0) { 2251556Srgrimes *errorp = EADDRNOTAVAIL; 22697092Stjr return (0); 2271556Srgrimes } 2281556Srgrimes return (&satosin6(&ia6->ia_addr)->sin6_addr); 229213811Sobrien } 23097092Stjr } 23197092Stjr 232176521Sstefanf /* 233222154Sjilles * If route is known or can be allocated now, 2341556Srgrimes * our src addr is taken from the i/f, else punt. 23597092Stjr */ 236215727Sjilles if (ro) { 23797092Stjr if (ro->ro_rt && 23897092Stjr (!(ro->ro_rt->rt_flags & RTF_UP) || 23997092Stjr satosin6(&ro->ro_dst)->sin6_family != AF_INET6 || 240215727Sjilles !IN6_ARE_ADDR_EQUAL(&satosin6(&ro->ro_dst)->sin6_addr, 241222154Sjilles dst))) { 242216622Sjilles RTFREE(ro->ro_rt); 243222154Sjilles ro->ro_rt = (struct rtentry *)0; 244222154Sjilles } 245176521Sstefanf if (ro->ro_rt == (struct rtentry *)0 || 24697092Stjr ro->ro_rt->rt_ifp == (struct ifnet *)0) { 247222154Sjilles struct sockaddr_in6 *sa6; 24897092Stjr 24997092Stjr /* No route yet, so try to acquire one */ 2501556Srgrimes bzero(&ro->ro_dst, sizeof(struct sockaddr_in6)); 2511556Srgrimes sa6 = (struct sockaddr_in6 *)&ro->ro_dst; 2521556Srgrimes sa6->sin6_family = AF_INET6; 2531556Srgrimes sa6->sin6_len = sizeof(struct sockaddr_in6); 254213811Sobrien sa6->sin6_addr = *dst; 25590111Simp sa6->sin6_scope_id = dstsock->sin6_scope_id; 25620774Ssteve if (IN6_IS_ADDR_MULTICAST(dst)) { 25725222Ssteve ro->ro_rt = rtalloc1(&((struct route *)ro) 2581556Srgrimes ->ro_dst, 0, 0UL); 2591556Srgrimes RT_UNLOCK(ro->ro_rt); 2601556Srgrimes } else { 2611556Srgrimes rtalloc((struct route *)ro); 2621556Srgrimes } 2631556Srgrimes } 2641556Srgrimes 2651556Srgrimes /* 2661556Srgrimes * in_pcbconnect() checks out IFF_LOOPBACK to skip using 2671556Srgrimes * the address. But we don't know why it does so. 2681556Srgrimes * It is necessary to ensure the scope even for lo0 2691556Srgrimes * so doesn't check out IFF_LOOPBACK. 2701556Srgrimes */ 2711556Srgrimes 2721556Srgrimes if (ro->ro_rt) { 2731556Srgrimes ia6 = in6_ifawithscope(ro->ro_rt->rt_ifa->ifa_ifp, dst); 2741556Srgrimes if (ia6 == 0) /* xxx scope error ?*/ 275213811Sobrien ia6 = ifatoia6(ro->ro_rt->rt_ifa); 276176521Sstefanf } 27720774Ssteve if (ia6 == 0) { 2781556Srgrimes *errorp = EHOSTUNREACH; /* no route */ 2791556Srgrimes return (0); 280262951Sjmmv } 2811556Srgrimes return (&satosin6(&ia6->ia_addr)->sin6_addr); 28238886Stegge } 28338886Stegge 28438886Stegge *errorp = EADDRNOTAVAIL; 28538886Stegge return (0); 28638886Stegge} 287199631Sstefanf 288199631Sstefanf/* 289262951Sjmmv * Default hop limit selection. The precedence is as follows: 290262951Sjmmv * 1. Hoplimit value specified via ioctl. 291262951Sjmmv * 2. (If the outgoing interface is detected) the current 2921556Srgrimes * hop limit of the interface specified by router advertisement. 2931556Srgrimes * 3. The system default hoplimit. 294215783Sjilles*/ 295215783Sjillesint 2961556Srgrimesin6_selecthlim(in6p, ifp) 2971556Srgrimes struct in6pcb *in6p; 2981556Srgrimes struct ifnet *ifp; 2991556Srgrimes{ 3001556Srgrimes if (in6p && in6p->in6p_hops >= 0) 3011556Srgrimes return (in6p->in6p_hops); 3021556Srgrimes else if (ifp) 303215783Sjilles return (ND_IFINFO(ifp)->chlim); 3041556Srgrimes else 3051556Srgrimes return (ip6_defhlim); 3061556Srgrimes} 3071556Srgrimes 3081556Srgrimes/* 309176521Sstefanf * XXX: this is borrowed from in6_pcbbind(). If possible, we should 310176521Sstefanf * share this function by all *bsd*... 311176521Sstefanf */ 312176521Sstefanfint 313176521Sstefanfin6_pcbsetport(laddr, inp, td) 314176521Sstefanf struct in6_addr *laddr; 315176521Sstefanf struct inpcb *inp; 316176521Sstefanf struct thread *td; 317213811Sobrien{ 318176521Sstefanf struct socket *so = inp->inp_socket; 319176521Sstefanf u_int16_t lport = 0, first, last, *lastport; 320176521Sstefanf int count, error = 0, wild = 0; 321176521Sstefanf struct inpcbinfo *pcbinfo = inp->inp_pcbinfo; 32238886Stegge 32338886Stegge /* XXX: this is redundant when called from in6_pcbbind */ 32438886Stegge if ((so->so_options & (SO_REUSEADDR|SO_REUSEPORT)) == 0) 325215727Sjilles wild = INPLOOKUP_WILDCARD; 32686176Stegge 32786176Stegge inp->inp_flags |= INP_ANONPORT; 3281556Srgrimes 3291556Srgrimes if (inp->inp_flags & INP_HIGHPORT) { 3301556Srgrimes first = ipport_hifirstauto; /* sysctl */ 331240541Sjilles last = ipport_hilastauto; 33217987Speter lastport = &pcbinfo->lasthi; 333199631Sstefanf } else if (inp->inp_flags & INP_LOWPORT) { 33497092Stjr if (td && (error = suser(td))) 3351556Srgrimes return error; 336100664Stjr first = ipport_lowfirstauto; /* 1023 */ 337240541Sjilles last = ipport_lowlastauto; /* 600 */ 33897092Stjr lastport = &pcbinfo->lastlow; 33997092Stjr } else { 34097092Stjr first = ipport_firstauto; /* sysctl */ 34197092Stjr last = ipport_lastauto; 34297092Stjr lastport = &pcbinfo->lastport; 34397092Stjr } 34497092Stjr /* 34597092Stjr * Simple check to ensure all ports are not used up causing 34697092Stjr * a deadlock here. 3471556Srgrimes * 348240541Sjilles * We split the two cases (up and down) so that the direction 34997092Stjr * is not being tested on each round of the loop. 35038886Stegge */ 35197092Stjr if (first > last) { 35297092Stjr /* 35397092Stjr * counting down 35497092Stjr */ 355199631Sstefanf count = first - last; 35697092Stjr 357199631Sstefanf do { 35897092Stjr if (count-- < 0) { /* completely used? */ 35997092Stjr /* 36038886Stegge * Undo any address bind that may have 36197092Stjr * occurred above. 36297092Stjr */ 36338886Stegge inp->in6p_laddr = in6addr_any; 3641556Srgrimes return (EAGAIN); 365176521Sstefanf } 3661556Srgrimes --*lastport; 367213811Sobrien if (*lastport > first || *lastport < last) 36890111Simp *lastport = first; 36920425Ssteve lport = htons(*lastport); 370176521Sstefanf } while (in6_pcblookup_local(pcbinfo, 37138886Stegge &inp->in6p_laddr, lport, wild)); 3721556Srgrimes } else { 37338886Stegge /* 374176521Sstefanf * counting up 375199631Sstefanf */ 376176521Sstefanf count = last - first; 377176521Sstefanf 378176521Sstefanf do { 379176521Sstefanf if (count-- < 0) { /* completely used? */ 380176521Sstefanf /* 381176521Sstefanf * Undo any address bind that may have 382199631Sstefanf * occurred above. 383199631Sstefanf */ 384176521Sstefanf inp->in6p_laddr = in6addr_any; 385176521Sstefanf return (EAGAIN); 386176521Sstefanf } 387213811Sobrien ++*lastport; 388199631Sstefanf if (*lastport < first || *lastport > last) 389176521Sstefanf *lastport = first; 390199631Sstefanf lport = htons(*lastport); 391199631Sstefanf } while (in6_pcblookup_local(pcbinfo, 39238886Stegge &inp->in6p_laddr, lport, wild)); 393199631Sstefanf } 394199631Sstefanf 395199631Sstefanf inp->inp_lport = lport; 396176521Sstefanf if (in_pcbinshash(inp) != 0) { 397199631Sstefanf inp->in6p_laddr = in6addr_any; 398199631Sstefanf inp->inp_lport = 0; 399199631Sstefanf return (EAGAIN); 40038886Stegge } 401199631Sstefanf 402206759Sjilles return (0); 403206759Sjilles} 404206759Sjilles 405206759Sjilles/* 406206759Sjilles * Generate kernel-internal form (scopeid embedded into s6_addr16[1]). 407206759Sjilles * If the address scope of is link-local, embed the interface index in the 408206759Sjilles * address. The routine determines our precedence 409206759Sjilles * between advanced API scope/interface specification and basic API 410206759Sjilles * specification. 411206759Sjilles * 412206759Sjilles * This function should be nuked in the future, when we get rid of embedded 413206759Sjilles * scopeid thing. 414206759Sjilles * 415206759Sjilles * XXX actually, it is over-specification to return ifp against sin6_scope_id. 416199631Sstefanf * there can be multiple interfaces that belong to a particular scope zone 417199631Sstefanf * (in specification, we have 1:N mapping between a scope zone and interfaces). 418199631Sstefanf * we may want to change the function to return something other than ifp. 419199631Sstefanf */ 420206759Sjillesint 421206759Sjillesin6_embedscope(in6, sin6, in6p, ifpp) 422206759Sjilles struct in6_addr *in6; 423199631Sstefanf const struct sockaddr_in6 *sin6; 424206759Sjilles#ifdef HAVE_NRL_INPCB 425206759Sjilles struct inpcb *in6p; 426206759Sjilles#define in6p_outputopts inp_outputopts6 4271556Srgrimes#define in6p_moptions inp_moptions6 428#else 429 struct in6pcb *in6p; 430#endif 431 struct ifnet **ifpp; 432{ 433 struct ifnet *ifp = NULL; 434 u_int32_t scopeid; 435 436 *in6 = sin6->sin6_addr; 437 scopeid = sin6->sin6_scope_id; 438 if (ifpp) 439 *ifpp = NULL; 440 441 /* 442 * don't try to read sin6->sin6_addr beyond here, since the caller may 443 * ask us to overwrite existing sockaddr_in6 444 */ 445 446#ifdef ENABLE_DEFAULT_SCOPE 447 if (scopeid == 0) 448 scopeid = scope6_addr2default(in6); 449#endif 450 451 if (IN6_IS_SCOPE_LINKLOCAL(in6)) { 452 struct in6_pktinfo *pi; 453 454 /* 455 * KAME assumption: link id == interface id 456 */ 457 458 if (in6p && in6p->in6p_outputopts && 459 (pi = in6p->in6p_outputopts->ip6po_pktinfo) && 460 pi->ipi6_ifindex) { 461 ifp = ifnet_byindex(pi->ipi6_ifindex); 462 in6->s6_addr16[1] = htons(pi->ipi6_ifindex); 463 } else if (in6p && IN6_IS_ADDR_MULTICAST(in6) && 464 in6p->in6p_moptions && 465 in6p->in6p_moptions->im6o_multicast_ifp) { 466 ifp = in6p->in6p_moptions->im6o_multicast_ifp; 467 in6->s6_addr16[1] = htons(ifp->if_index); 468 } else if (scopeid) { 469 /* boundary check */ 470 if (scopeid < 0 || if_index < scopeid) 471 return ENXIO; /* XXX EINVAL? */ 472 ifp = ifnet_byindex(scopeid); 473 /* XXX assignment to 16bit from 32bit variable */ 474 in6->s6_addr16[1] = htons(scopeid & 0xffff); 475 } 476 477 if (ifpp) 478 *ifpp = ifp; 479 } 480 481 return 0; 482} 483#ifdef HAVE_NRL_INPCB 484#undef in6p_outputopts 485#undef in6p_moptions 486#endif 487 488/* 489 * generate standard sockaddr_in6 from embedded form. 490 * touches sin6_addr and sin6_scope_id only. 491 * 492 * this function should be nuked in the future, when we get rid of 493 * embedded scopeid thing. 494 */ 495int 496in6_recoverscope(sin6, in6, ifp) 497 struct sockaddr_in6 *sin6; 498 const struct in6_addr *in6; 499 struct ifnet *ifp; 500{ 501 u_int32_t zoneid; 502 503 sin6->sin6_addr = *in6; 504 505 /* 506 * don't try to read *in6 beyond here, since the caller may 507 * ask us to overwrite existing sockaddr_in6 508 */ 509 510 sin6->sin6_scope_id = 0; 511 if (IN6_IS_SCOPE_LINKLOCAL(in6) || IN6_IS_ADDR_MC_INTFACELOCAL(in6)) { 512 /* 513 * KAME assumption: link id == interface id 514 */ 515 zoneid = ntohs(sin6->sin6_addr.s6_addr16[1]); 516 if (zoneid) { 517 /* sanity check */ 518 if (zoneid < 0 || if_index < zoneid) 519 return ENXIO; 520 if (ifp && ifp->if_index != zoneid) 521 return ENXIO; 522 sin6->sin6_addr.s6_addr16[1] = 0; 523 sin6->sin6_scope_id = zoneid; 524 } 525 } 526 527 return 0; 528} 529 530/* 531 * just clear the embedded scope identifier. 532 */ 533void 534in6_clearscope(addr) 535 struct in6_addr *addr; 536{ 537 if (IN6_IS_SCOPE_LINKLOCAL(addr) || IN6_IS_ADDR_MC_INTFACELOCAL(addr)) 538 addr->s6_addr16[1] = 0; 539} 540