in6_ifattach.c
来自「eCos操作系统源码」· C语言 代码 · 共 1,344 行 · 第 1/3 页
C
1,344 行
//==========================================================================//// src/sys/netinet6/in6_ifattach.c////==========================================================================//####BSDCOPYRIGHTBEGIN####//// -------------------------------------------//// Portions of this software may have been derived from OpenBSD, // FreeBSD or other sources, and are covered by the appropriate// copyright disclaimers included herein.//// Portions created by Red Hat are// Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.//// -------------------------------------------////####BSDCOPYRIGHTEND####//==========================================================================/* $KAME: in6_ifattach.c,v 1.149 2001/12/07 07:07:09 itojun Exp $ *//* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the project nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */#include <sys/param.h>#include <sys/malloc.h>#include <sys/socket.h>#include <sys/sockio.h>#ifdef __bsdi__#include <crypto/md5.h>#elif defined(__OpenBSD__)#include <sys/md5k.h>#else#include <sys/md5.h>#endif#ifdef __OpenBSD__#include <dev/rndvar.h>#endif#include <net/if.h>#include <net/if_dl.h>#include <net/if_types.h>#include <net/route.h>#include <netinet/in.h>#include <netinet/in_var.h>#ifndef __NetBSD__#include <netinet/if_ether.h>#endif#if (defined(__FreeBSD__) && __FreeBSD__ >= 4)#include <netinet/in_pcb.h>#endif#include <netinet/ip6.h>#include <netinet6/ip6_var.h>#include <netinet6/in6_var.h>#if (defined(__FreeBSD__) && __FreeBSD__ >= 4)#include <netinet6/in6_pcb.h>#endif#include <netinet6/in6_ifattach.h>#include <netinet6/ip6_var.h>#include <netinet6/nd6.h>#include <netinet6/scope6_var.h>struct in6_ifstat **in6_ifstat = NULL;struct icmp6_ifstat **icmp6_ifstat = NULL;size_t in6_ifstatmax = 0;size_t icmp6_ifstatmax = 0;unsigned long in6_maxmtu = 0;#ifdef IP6_AUTO_LINKLOCALint ip6_auto_linklocal = IP6_AUTO_LINKLOCAL;#elseint ip6_auto_linklocal = 1; /* enable by default */#endif#ifdef __NetBSD__struct callout in6_tmpaddrtimer_ch = CALLOUT_INITIALIZER;#elif (defined(__FreeBSD__) && __FreeBSD__ >= 3)struct callout in6_tmpaddrtimer_ch;#elif defined(__OpenBSD__)struct timeout in6_tmpaddrtimer_ch;#endif#if (defined(__FreeBSD__) && __FreeBSD__ >= 4)extern struct inpcbinfo udbinfo;extern struct inpcbinfo ripcbinfo;#endif#if defined(__NetBSD__) || defined(__OpenBSD__)static int get_hostid_ifid __P((struct ifnet *, struct in6_addr *));#endifstatic int get_rand_ifid __P((struct ifnet *, struct in6_addr *));static int generate_tmp_ifid __P((u_int8_t *, const u_int8_t *, u_int8_t *));static int get_hw_ifid __P((struct ifnet *, struct in6_addr *));#ifndef MIP6static int get_ifid __P((struct ifnet *, struct ifnet *, struct in6_addr *));#endif /* !MIP6 */static int in6_ifattach_linklocal __P((struct ifnet *, struct ifnet *));static int in6_ifattach_loopback __P((struct ifnet *));#define EUI64_GBIT 0x01#define EUI64_UBIT 0x02#define EUI64_TO_IFID(in6) do {(in6)->s6_addr[8] ^= EUI64_UBIT; } while (0)#define EUI64_GROUP(in6) ((in6)->s6_addr[8] & EUI64_GBIT)#define EUI64_INDIVIDUAL(in6) (!EUI64_GROUP(in6))#define EUI64_LOCAL(in6) ((in6)->s6_addr[8] & EUI64_UBIT)#define EUI64_UNIVERSAL(in6) (!EUI64_LOCAL(in6))#define IFID_LOCAL(in6) (!EUI64_LOCAL(in6))#define IFID_UNIVERSAL(in6) (!EUI64_UNIVERSAL(in6))#define GEN_TEMPID_RETRY_MAX 5#if defined(__NetBSD__) || defined(__OpenBSD__)/* * Generate a last-resort interface identifier from hostid. * works only for certain architectures (like sparc). * also, using hostid itself may constitute a privacy threat, much worse * than MAC addresses (hostids are used for software licensing). * maybe we should use MD5(hostid) instead. */static intget_hostid_ifid(ifp, in6) struct ifnet *ifp; struct in6_addr *in6; /* upper 64bits are preserved */{ int off, len; static u_int8_t allzero[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; static u_int8_t allone[8] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; if (!hostid) return -1; /* get up to 8 bytes from the hostid field - should we get */ len = (sizeof(hostid) > 8) ? 8 : sizeof(hostid); off = sizeof(*in6) - len; bcopy(&hostid, &in6->s6_addr[off], len); /* make sure we do not return anything bogus */ if (bcmp(&in6->s6_addr[8], allzero, sizeof(allzero))) return -1; if (bcmp(&in6->s6_addr[8], allone, sizeof(allone))) return -1; /* make sure to set "u" bit to local, and "g" bit to individual. */ in6->s6_addr[8] &= ~EUI64_GBIT; /* g bit to "individual" */ in6->s6_addr[8] |= EUI64_UBIT; /* u bit to "local" */ /* convert EUI64 into IPv6 interface identifier */ EUI64_TO_IFID(in6); return 0;}#endif/* * Generate a last-resort interface identifier, when the machine has no * IEEE802/EUI64 address sources. * The goal here is to get an interface identifier that is * (1) random enough and (2) does not change across reboot. * We currently use MD5(hostname) for it. */static intget_rand_ifid(ifp, in6) struct ifnet *ifp; struct in6_addr *in6; /* upper 64bits are preserved */{ MD5_CTX ctxt; u_int8_t digest[16];#ifdef __FreeBSD__ int hostnamelen = strlen(hostname);#endif#if 0 /* we need at least several letters as seed for ifid */ if (hostnamelen < 3) return -1;#endif /* generate 8 bytes of pseudo-random value. */ bzero(&ctxt, sizeof(ctxt)); MD5Init(&ctxt); MD5Update(&ctxt, hostname, hostnamelen); MD5Final(digest, &ctxt); /* assumes sizeof(digest) > sizeof(ifid) */ bcopy(digest, &in6->s6_addr[8], 8); /* make sure to set "u" bit to local, and "g" bit to individual. */ in6->s6_addr[8] &= ~EUI64_GBIT; /* g bit to "individual" */ in6->s6_addr[8] |= EUI64_UBIT; /* u bit to "local" */ /* convert EUI64 into IPv6 interface identifier */ EUI64_TO_IFID(in6); return 0;}static intgenerate_tmp_ifid(seed0, seed1, ret) u_int8_t *seed0, *ret; const u_int8_t *seed1;{ MD5_CTX ctxt; u_int8_t seed[16], digest[16], nullbuf[8]; u_int32_t val32;#ifndef __OpenBSD__ struct timeval tv;#endif /* * interface ID for subnet anycast addresses. * XXX: we assume the unicast address range that requires IDs * in EUI-64 format. */ const u_int8_t anycast_id[8] = {0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80}; const u_int8_t isatap_id[4] = {0x00, 0x00, 0x5e, 0xfe}; int badid, retry = 0; /* If there's no hisotry, start with a random seed. */ bzero(nullbuf, sizeof(nullbuf)); if (bcmp(nullbuf, seed0, sizeof(nullbuf)) == 0) { int i; for (i = 0; i < 2; i++) {#ifndef __OpenBSD__ microtime(&tv); val32 = random() ^ tv.tv_usec;#else val32 = arc4random();#endif bcopy(&val32, seed + sizeof(val32) * i, sizeof(val32)); } } else { bcopy(seed0, seed, 8); } /* copy the right-most 64-bits of the given address */ /* XXX assumption on the size of IFID */ bcopy(seed1, &seed[8], 8); again: if (0) { /* for debugging purposes only */ int i; printf("generate_tmp_ifid: new randomized ID from: "); for (i = 0; i < 16; i++) printf("%02x", seed[i]); printf(" "); } /* generate 16 bytes of pseudo-random value. */ bzero(&ctxt, sizeof(ctxt)); MD5Init(&ctxt); MD5Update(&ctxt, seed, sizeof(seed)); MD5Final(digest, &ctxt); /* * draft-ietf-ipngwg-temp-addresses-v2-00.txt 3.2.1. (3) * Take the left-most 64-bits of the MD5 digest and set bit 6 (the * left-most bit is numbered 0) to zero. */ bcopy(digest, ret, 8); ret[0] &= ~EUI64_UBIT; /* * Reject inappropriate identifiers according to * draft-ietf-ipngwg-temp-addresses-v2-00.txt 3.2.1. (4) * At this moment, we reject following cases: * - all 0 identifier * - identifiers that conflict with reserved subnet anycast addresses, * which are defined in RFC 2526. * - identifiers that conflict with ISATAP addresses * - identifiers used in our own addresses */ badid = 0; if (bcmp(nullbuf, ret, sizeof(nullbuf)) == 0) badid = 1; else if (bcmp(anycast_id, ret, 7) == 0 && (anycast_id[7] & ret[7]) == anycast_id[7]) { badid = 1; } else if (bcmp(isatap_id, ret, sizeof(isatap_id)) == 0) badid = 1; else { struct in6_ifaddr *ia; for (ia = in6_ifaddr; ia; ia = ia->ia_next) { if (bcmp(&ia->ia_addr.sin6_addr.s6_addr[8], ret, 8) == 0) { badid = 1; break; } } } /* * In the event that an unacceptable identifier has been generated, * restart the process, using the right-most 64 bits of the MD5 digest * obtained in place of the history value. */ if (badid) { if (0) { /* for debugging purposes only */ int i; printf("unacceptable random ID: "); for (i = 0; i < 16; i++) printf("%02x", digest[i]); printf("\n"); } if (++retry < GEN_TEMPID_RETRY_MAX) { bcopy(&digest[8], seed, 8); goto again; } else { /* * We're so unlucky. Give up for now, and return * all 0 IDs to tell the caller not to make a * temporary address. */ nd6log((LOG_NOTICE, "generate_tmp_ifid: never found a good ID\n")); bzero(ret, 8); } } /* * draft-ietf-ipngwg-temp-addresses-v2-00.txt 3.2.1. (6) * Take the rightmost 64-bits of the MD5 digest and save them in * stable storage as the history value to be used in the next * iteration of the algorithm. */ bcopy(&digest[8], seed0, 8); if (0) { /* for debugging purposes only */ int i; printf("to: "); for (i = 0; i < 16; i++) printf("%02x", digest[i]); printf("\n"); } return 0;}/* * Get interface identifier for the specified interface. * XXX assumes single sockaddr_dl (AF_LINK address) per an interface */static intget_hw_ifid(ifp, in6) struct ifnet *ifp; struct in6_addr *in6; /* upper 64bits are preserved */{ struct ifaddr *ifa; struct sockaddr_dl *sdl; u_int8_t *addr; size_t addrlen; static u_int8_t allzero[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; static u_int8_t allone[8] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };#if defined(__bsdi__) || (defined(__FreeBSD__) && __FreeBSD__ < 3) for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next)#else for (ifa = ifp->if_addrlist.tqh_first; ifa; ifa = ifa->ifa_list.tqe_next)#endif { if (ifa->ifa_addr->sa_family != AF_LINK) continue; sdl = (struct sockaddr_dl *)ifa->ifa_addr; if (sdl == NULL) continue; if (sdl->sdl_alen == 0) continue; goto found; } return -1;found: addr = LLADDR(sdl); addrlen = sdl->sdl_alen; switch (ifp->if_type) { case IFT_IEEE1394:#ifdef IFT_IEEE80211 case IFT_IEEE80211:#endif /* IEEE1394 uses 16byte length address starting with EUI64 */ if (addrlen > 8) addrlen = 8; break; default: break; } /* get EUI64 */ switch (ifp->if_type) { /* IEEE802/EUI64 cases - what others? */ case IFT_ETHER: case IFT_FDDI: case IFT_ATM: case IFT_IEEE1394:#ifdef IFT_IEEE80211 case IFT_IEEE80211:#endif /* look at IEEE802/EUI64 only */ if (addrlen != 8 && addrlen != 6) return -1; /* * check for invalid MAC address - on bsdi, we see it a lot * since wildboar configures all-zero MAC on pccard before
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?