📄 in6_ifattach.c
字号:
ip6_sprintf(&mltaddr.sin6_addr),
error));
}
}
}
}
void
in6_nigroup_detach(name, namelen)
const char *name;
int namelen;
{
struct ifnet *ifp;
struct sockaddr_in6 mltaddr;
struct in6_multi *in6m;
bzero(&mltaddr, sizeof(mltaddr));
mltaddr.sin6_family = AF_INET6;
mltaddr.sin6_len = sizeof(struct sockaddr_in6);
if (in6_nigroup(NULL, name, namelen, &mltaddr.sin6_addr) != 0)
return;
#if defined(__bsdi__) || (defined(__FreeBSD__) && __FreeBSD__ < 3)
for (ifp = ifnet; ifp; ifp = ifp->if_next)
#else
for (ifp = ifnet.tqh_first; ifp; ifp = ifp->if_list.tqe_next)
#endif
{
mltaddr.sin6_addr.s6_addr16[1] = htons(ifp->if_index);
IN6_LOOKUP_MULTI(mltaddr.sin6_addr, ifp, in6m);
if (in6m)
in6_delmulti(in6m);
}
}
#endif
/*
* XXX multiple loopback interface needs more care. for instance,
* nodelocal address needs to be configured onto only one of them.
* XXX multiple link-local address case
*/
void
in6_ifattach(ifp, altifp)
struct ifnet *ifp;
struct ifnet *altifp; /* secondary EUI64 source */
{
static size_t if_indexlim = 8;
struct in6_ifaddr *ia;
struct in6_addr in6;
/* some of the interfaces are inherently not IPv6 capable */
switch (ifp->if_type) {
#ifdef IFT_BRIDGE /* OpenBSD 2.8 */
case IFT_BRIDGE:
return;
#endif
#if defined(__OpenBSD__) || defined(__NetBSD__)
case IFT_PROPVIRTUAL:
if (strncmp("bridge", ifp->if_xname, sizeof("bridge")) == 0 &&
'0' <= ifp->if_xname[sizeof("bridge")] &&
ifp->if_xname[sizeof("bridge")] <= '9')
return;
break;
#endif
#ifdef IFT_PFLOG
case IFT_PFLOG:
return;
#endif
}
/*
* We have some arrays that should be indexed by if_index.
* since if_index will grow dynamically, they should grow too.
* struct in6_ifstat **in6_ifstat
* struct icmp6_ifstat **icmp6_ifstat
*/
if (in6_ifstat == NULL || icmp6_ifstat == NULL ||
if_index >= if_indexlim) {
size_t n;
caddr_t q;
size_t olim;
olim = if_indexlim;
while (if_index >= if_indexlim)
if_indexlim <<= 1;
/* grow in6_ifstat */
n = if_indexlim * sizeof(struct in6_ifstat *);
q = (caddr_t)malloc(n, M_IFADDR, M_WAITOK);
bzero(q, n);
if (in6_ifstat) {
bcopy((caddr_t)in6_ifstat, q,
olim * sizeof(struct in6_ifstat *));
free((caddr_t)in6_ifstat, M_IFADDR);
}
in6_ifstat = (struct in6_ifstat **)q;
in6_ifstatmax = if_indexlim;
/* grow icmp6_ifstat */
n = if_indexlim * sizeof(struct icmp6_ifstat *);
q = (caddr_t)malloc(n, M_IFADDR, M_WAITOK);
bzero(q, n);
if (icmp6_ifstat) {
bcopy((caddr_t)icmp6_ifstat, q,
olim * sizeof(struct icmp6_ifstat *));
free((caddr_t)icmp6_ifstat, M_IFADDR);
}
icmp6_ifstat = (struct icmp6_ifstat **)q;
icmp6_ifstatmax = if_indexlim;
}
/* initialize scope identifiers */
scope6_ifattach(ifp);
/* initialize NDP variables */
nd6_ifattach(ifp);
#if !(defined(__FreeBSD__) && __FreeBSD__ >= 3)
/* create a multicast kludge storage (if we have not had one) */
in6_createmkludge(ifp);
#endif
/*
* quirks based on interface type
*/
switch (ifp->if_type) {
#ifdef IFT_STF
case IFT_STF:
/*
* 6to4 interface is a very special kind of beast.
* no multicast, no linklocal. RFC2529 specifies how to make
* linklocals for 6to4 interface, but there's no use and
* it is rather harmful to have one.
*/
goto statinit;
#endif
default:
break;
}
/*
* usually, we require multicast capability to the interface
*/
if ((ifp->if_flags & IFF_MULTICAST) == 0) {
log(LOG_INFO, "in6_ifattach: "
"%s is not multicast capable, IPv6 not enabled\n",
if_name(ifp));
return;
}
/*
* assign loopback address for loopback interface.
* XXX multiple loopback interface case.
*/
if ((ifp->if_flags & IFF_LOOPBACK) != 0) {
in6 = in6addr_loopback;
if (in6ifa_ifpwithaddr(ifp, &in6) == NULL) {
if (in6_ifattach_loopback(ifp) != 0)
return;
}
}
/*
* assign a link-local address, if there's none.
*/
if (ip6_auto_linklocal) {
int s = splnet();
ia = in6ifa_ifpforlinklocal(ifp, 0);
if (ia == NULL) {
if (in6_ifattach_linklocal(ifp, altifp) == 0) {
/* linklocal address assigned */
} else {
/* failed to assign linklocal address. bark? */
}
}
splx(s);
}
#ifdef IFT_STF /* XXX */
statinit:
#endif
/* update dynamically. */
if (in6_maxmtu < ifp->if_mtu)
in6_maxmtu = ifp->if_mtu;
if (in6_ifstat[ifp->if_index] == NULL) {
in6_ifstat[ifp->if_index] = (struct in6_ifstat *)
malloc(sizeof(struct in6_ifstat), M_IFADDR, M_WAITOK);
bzero(in6_ifstat[ifp->if_index], sizeof(struct in6_ifstat));
}
if (icmp6_ifstat[ifp->if_index] == NULL) {
icmp6_ifstat[ifp->if_index] = (struct icmp6_ifstat *)
malloc(sizeof(struct icmp6_ifstat), M_IFADDR, M_WAITOK);
bzero(icmp6_ifstat[ifp->if_index], sizeof(struct icmp6_ifstat));
}
}
/*
* NOTE: in6_ifdetach() does not support loopback if at this moment.
* We don't need this function in bsdi, because interfaces are never removed
* from the ifnet list in bsdi.
*/
#if !(defined(__bsdi__) && _BSDI_VERSION >= 199802)
void
in6_ifdetach(ifp)
struct ifnet *ifp;
{
struct in6_ifaddr *ia, *oia;
struct ifaddr *ifa, *next;
#if defined(__bsdi__) || (defined(__FreeBSD__) && __FreeBSD__ < 3)
struct ifaddr *ifaprev = NULL;
#endif
struct rtentry *rt;
short rtflags;
struct sockaddr_in6 sin6;
#if (defined(__FreeBSD__) && __FreeBSD__ >= 3)
struct in6_multi *in6m, *in6m_next;
#endif
struct in6_multi_mship *imm;
/* remove neighbor management table */
nd6_purge(ifp);
/* nuke any of IPv6 addresses we have */
#if defined(__bsdi__) || (defined(__FreeBSD__) && __FreeBSD__ < 3)
for (ifa = ifp->if_addrlist; ifa; ifa = next)
#else
for (ifa = ifp->if_addrlist.tqh_first; ifa; ifa = next)
#endif
{
#if defined(__bsdi__) || (defined(__FreeBSD__) && __FreeBSD__ < 3)
next = ifa->ifa_next;
#else
next = ifa->ifa_list.tqe_next;
#endif
if (ifa->ifa_addr->sa_family != AF_INET6)
continue;
in6_purgeaddr(ifa);
}
/* undo everything done by in6_ifattach(), just in case */
#if defined(__bsdi__) || (defined(__FreeBSD__) && __FreeBSD__ < 3)
for (ifa = ifp->if_addrlist; ifa; ifa = next)
#else
for (ifa = ifp->if_addrlist.tqh_first; ifa; ifa = next)
#endif
{
#if defined(__bsdi__) || (defined(__FreeBSD__) && __FreeBSD__ < 3)
next = ifa->ifa_next;
#else
next = ifa->ifa_list.tqe_next;
#endif
if (ifa->ifa_addr->sa_family != AF_INET6
|| !IN6_IS_ADDR_LINKLOCAL(&satosin6(&ifa->ifa_addr)->sin6_addr)) {
#if defined(__bsdi__) || (defined(__FreeBSD__) && __FreeBSD__ < 3)
ifaprev = ifa;
#endif
continue;
}
ia = (struct in6_ifaddr *)ifa;
/*
* leave from multicast groups we have joined for the interface
*/
while ((imm = ia->ia6_memberships.lh_first) != NULL) {
LIST_REMOVE(imm, i6mm_chain);
in6_leavegroup(imm);
}
/* remove from the routing table */
if ((ia->ia_flags & IFA_ROUTE)
&& (rt = rtalloc1((struct sockaddr *)&ia->ia_addr, 0
#ifdef __FreeBSD__
, 0UL
#endif
))) {
rtflags = rt->rt_flags;
rtfree(rt);
rtrequest(RTM_DELETE,
(struct sockaddr *)&ia->ia_addr,
(struct sockaddr *)&ia->ia_addr,
(struct sockaddr *)&ia->ia_prefixmask,
rtflags, (struct rtentry **)0);
}
/* remove from the linked list */
#if defined(__bsdi__) || (defined(__FreeBSD__) && __FreeBSD__ < 3)
if (ifaprev)
ifaprev->ifa_next = ifa->ifa_next;
else
ifp->if_addrlist = ifa->ifa_next;
#else
TAILQ_REMOVE(&ifp->if_addrlist, (struct ifaddr *)ia, ifa_list);
#endif
IFAFREE(&ia->ia_ifa);
/* also remove from the IPv6 address chain(itojun&jinmei) */
oia = ia;
if (oia == (ia = in6_ifaddr))
in6_ifaddr = ia->ia_next;
else {
while (ia->ia_next && (ia->ia_next != oia))
ia = ia->ia_next;
if (ia->ia_next)
ia->ia_next = oia->ia_next;
else {
nd6log((LOG_ERR,
"%s: didn't unlink in6ifaddr from "
"list\n", if_name(ifp)));
}
}
IFAFREE(&oia->ia_ifa);
}
#if (defined(__FreeBSD__) && __FreeBSD__ >= 3)
/* leave from all multicast groups joined */
#if (defined(__FreeBSD__) && __FreeBSD__ >= 4)
in6_pcbpurgeif0(LIST_FIRST(udbinfo.listhead), ifp);
in6_pcbpurgeif0(LIST_FIRST(ripcbinfo.listhead), ifp);
#endif
for (in6m = LIST_FIRST(&in6_multihead); in6m; in6m = in6m_next) {
in6m_next = LIST_NEXT(in6m, in6m_entry);
if (in6m->in6m_ifp != ifp)
continue;
in6_delmulti(in6m);
in6m = NULL;
}
#endif
#if !(defined(__FreeBSD__) && __FreeBSD__ >= 3)
/* cleanup multicast address kludge table, if there is any */
in6_purgemkludge(ifp);
#endif
/*
* remove neighbor management table. we call it twice just to make
* sure we nuke everything. maybe we need just one call.
* XXX: since the first call did not release addresses, some prefixes
* might remain. We should call nd6_purge() again to release the
* prefixes after removing all addresses above.
* (Or can we just delay calling nd6_purge until at this point?)
*/
nd6_purge(ifp);
/* remove route to link-local allnodes multicast (ff02::1) */
bzero(&sin6, sizeof(sin6));
sin6.sin6_len = sizeof(struct sockaddr_in6);
sin6.sin6_family = AF_INET6;
sin6.sin6_addr = in6addr_linklocal_allnodes;
sin6.sin6_addr.s6_addr16[1] = htons(ifp->if_index);
#ifndef __FreeBSD__
rt = rtalloc1((struct sockaddr *)&sin6, 0);
#else
rt = rtalloc1((struct sockaddr *)&sin6, 0, 0UL);
#endif
if (rt && rt->rt_ifp == ifp) {
rtrequest(RTM_DELETE, (struct sockaddr *)rt_key(rt),
rt->rt_gateway, rt_mask(rt), rt->rt_flags, 0);
rtfree(rt);
}
}
#endif
int
in6_get_tmpifid(ifp, retbuf, baseid, generate)
struct ifnet *ifp;
u_int8_t *retbuf;
const u_int8_t *baseid;
int generate;
{
u_int8_t nullbuf[8];
struct nd_ifinfo *ndi = &nd_ifinfo[ifp->if_index];
bzero(nullbuf, sizeof(nullbuf));
if (bcmp(ndi->randomid, nullbuf, sizeof(nullbuf)) == 0) {
/* we've never created a random ID. Create a new one. */
generate = 1;
}
if (generate) {
bcopy(baseid, ndi->randomseed1, sizeof(ndi->randomseed1));
/* generate_tmp_ifid will update seedn and buf */
(void)generate_tmp_ifid(ndi->randomseed0, ndi->randomseed1,
ndi->randomid);
}
bcopy(ndi->randomid, retbuf, 8);
if (generate && bcmp(retbuf, nullbuf, sizeof(nullbuf)) == 0) {
/* generate_tmp_ifid could not found a good ID. */
return(-1);
}
return(0);
}
void
in6_tmpaddrtimer(ignored_arg)
void *ignored_arg;
{
int i;
struct nd_ifinfo *ndi;
u_int8_t nullbuf[8];
#ifdef __NetBSD__
int s = splsoftnet();
#else
int s = splnet();
#endif
#if defined(__NetBSD__) || (defined(__FreeBSD__) && __FreeBSD__ >= 3)
callout_reset(&in6_tmpaddrtimer_ch,
(ip6_temp_preferred_lifetime - ip6_desync_factor -
ip6_temp_regen_advance) * hz,
in6_tmpaddrtimer, NULL);
#elif defined(__OpenBSD__)
timeout_set(&in6_tmpaddrtimer_ch, in6_tmpaddrtimer, NULL);
timeout_add(&in6_tmpaddrtimer_ch,
(ip6_temp_preferred_lifetime - ip6_desync_factor -
ip6_temp_regen_advance) * hz);
#else
timeout(in6_tmpaddrtimer, (caddr_t)0,
(ip6_temp_preferred_lifetime - ip6_desync_factor -
ip6_temp_regen_advance) * hz);
#endif
bzero(nullbuf, sizeof(nullbuf));
for (i = 1; i < if_index + 1; i++) {
ndi = &nd_ifinfo[i];
if (bcmp(ndi->randomid, nullbuf, sizeof(nullbuf)) != 0) {
/*
* We've been generating a random ID on this interface.
* Create a new one.
*/
(void)generate_tmp_ifid(ndi->randomseed0,
ndi->randomseed1,
ndi->randomid);
}
}
splx(s);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -