summaryrefslogtreecommitdiffstats
path: root/freebsd/sys/netinet6/in6_ifattach.c
diff options
context:
space:
mode:
Diffstat (limited to 'freebsd/sys/netinet6/in6_ifattach.c')
-rw-r--r--freebsd/sys/netinet6/in6_ifattach.c205
1 files changed, 81 insertions, 124 deletions
diff --git a/freebsd/sys/netinet6/in6_ifattach.c b/freebsd/sys/netinet6/in6_ifattach.c
index a8f03017..791e9e27 100644
--- a/freebsd/sys/netinet6/in6_ifattach.c
+++ b/freebsd/sys/netinet6/in6_ifattach.c
@@ -41,11 +41,14 @@ __FBSDID("$FreeBSD$");
#include <sys/sockio.h>
#include <sys/jail.h>
#include <sys/kernel.h>
+#include <rtems/bsd/sys/lock.h>
#include <sys/proc.h>
+#include <sys/rmlock.h>
#include <sys/syslog.h>
#include <sys/md5.h>
#include <net/if.h>
+#include <net/if_var.h>
#include <net/if_dl.h>
#include <net/if_types.h>
#include <net/route.h>
@@ -279,9 +282,7 @@ found:
case IFT_ISO88025:
case IFT_ATM:
case IFT_IEEE1394:
-#ifdef IFT_IEEE80211
case IFT_IEEE80211:
-#endif
/* IEEE802/EUI64 cases - what others? */
/* IEEE1394 uses 16byte length address starting with EUI64 */
if (addrlen > 8)
@@ -343,9 +344,7 @@ found:
break;
case IFT_GIF:
-#ifdef IFT_STF
case IFT_STF:
-#endif
/*
* RFC2893 says: "SHOULD use IPv4 address as ifid source".
* however, IPv4 address is not very suitable as unique
@@ -412,7 +411,7 @@ get_ifid(struct ifnet *ifp0, struct ifnet *altifp,
/* next, try to get it from some other hardware interface */
IFNET_RLOCK_NOSLEEP();
- TAILQ_FOREACH(ifp, &V_ifnet, if_list) {
+ TAILQ_FOREACH(ifp, &V_ifnet, if_link) {
if (ifp == ifp0)
continue;
if (in6_get_hw_ifid(ifp, in6) != 0)
@@ -460,21 +459,13 @@ in6_ifattach_linklocal(struct ifnet *ifp, struct ifnet *altifp)
struct in6_ifaddr *ia;
struct in6_aliasreq ifra;
struct nd_prefixctl pr0;
- int i, error;
+ int error;
/*
* configure link-local address.
*/
- bzero(&ifra, sizeof(ifra));
-
- /*
- * in6_update_ifa() does not use ifra_name, but we accurately set it
- * for safety.
- */
- strncpy(ifra.ifra_name, if_name(ifp), sizeof(ifra.ifra_name));
+ in6_prepare_ifra(&ifra, NULL, &in6mask64);
- ifra.ifra_addr.sin6_family = AF_INET6;
- ifra.ifra_addr.sin6_len = sizeof(struct sockaddr_in6);
ifra.ifra_addr.sin6_addr.s6_addr32[0] = htonl(0xfe800000);
ifra.ifra_addr.sin6_addr.s6_addr32[1] = 0;
if ((ifp->if_flags & IFF_LOOPBACK) != 0) {
@@ -490,9 +481,6 @@ in6_ifattach_linklocal(struct ifnet *ifp, struct ifnet *altifp)
if (in6_setscope(&ifra.ifra_addr.sin6_addr, ifp, NULL))
return (-1);
- ifra.ifra_prefixmask.sin6_len = sizeof(struct sockaddr_in6);
- ifra.ifra_prefixmask.sin6_family = AF_INET6;
- ifra.ifra_prefixmask.sin6_addr = in6mask64;
/* link-local addresses should NEVER expire. */
ifra.ifra_lifetime.ia6t_vltime = ND6_INFINITE_LIFETIME;
ifra.ifra_lifetime.ia6t_pltime = ND6_INFINITE_LIFETIME;
@@ -537,10 +525,7 @@ in6_ifattach_linklocal(struct ifnet *ifp, struct ifnet *altifp)
pr0.ndpr_plen = in6_mask2len(&ifra.ifra_prefixmask.sin6_addr, NULL);
pr0.ndpr_prefix = ifra.ifra_addr;
/* apply the mask for safety. (nd6_prelist_add will apply it again) */
- for (i = 0; i < 4; i++) {
- pr0.ndpr_prefix.sin6_addr.s6_addr32[i] &=
- in6mask64.s6_addr32[i];
- }
+ IN6_MASK_ADDR(&pr0.ndpr_prefix.sin6_addr, &in6mask64);
/*
* Initialize parameters. The link-local prefix must always be
* on-link, and its lifetimes never expire.
@@ -573,17 +558,7 @@ in6_ifattach_loopback(struct ifnet *ifp)
struct in6_aliasreq ifra;
int error;
- bzero(&ifra, sizeof(ifra));
-
- /*
- * in6_update_ifa() does not use ifra_name, but we accurately set it
- * for safety.
- */
- strncpy(ifra.ifra_name, if_name(ifp), sizeof(ifra.ifra_name));
-
- ifra.ifra_prefixmask.sin6_len = sizeof(struct sockaddr_in6);
- ifra.ifra_prefixmask.sin6_family = AF_INET6;
- ifra.ifra_prefixmask.sin6_addr = in6mask128;
+ in6_prepare_ifra(&ifra, &in6addr_loopback, &in6mask128);
/*
* Always initialize ia_dstaddr (= broadcast address) to loopback
@@ -593,20 +568,10 @@ in6_ifattach_loopback(struct ifnet *ifp)
ifra.ifra_dstaddr.sin6_family = AF_INET6;
ifra.ifra_dstaddr.sin6_addr = in6addr_loopback;
- ifra.ifra_addr.sin6_len = sizeof(struct sockaddr_in6);
- ifra.ifra_addr.sin6_family = AF_INET6;
- ifra.ifra_addr.sin6_addr = in6addr_loopback;
-
/* the loopback address should NEVER expire. */
ifra.ifra_lifetime.ia6t_vltime = ND6_INFINITE_LIFETIME;
ifra.ifra_lifetime.ia6t_pltime = ND6_INFINITE_LIFETIME;
- /* we don't need to perform DAD on loopback interfaces. */
- ifra.ifra_flags |= IN6_IFF_NODAD;
-
- /* skip registration to the prefix list. XXX should be temporary. */
- ifra.ifra_flags |= IN6_IFF_NOPFX;
-
/*
* We are sure that this is a newly assigned address, so we can set
* NULL to the 3rd arg.
@@ -734,15 +699,8 @@ in6_ifattach(struct ifnet *ifp, struct ifnet *altifp)
struct in6_ifaddr *ia;
struct in6_addr in6;
- /* some of the interfaces are inherently not IPv6 capable */
- switch (ifp->if_type) {
- case IFT_PFLOG:
- case IFT_PFSYNC:
- ND_IFINFO(ifp)->flags &= ~ND6_IFF_AUTO_LINKLOCAL;
- ND_IFINFO(ifp)->flags |= ND6_IFF_IFDISABLED;
+ if (ifp->if_afdata[AF_INET6] == NULL)
return;
- }
-
/*
* quirks based on interface type
*/
@@ -813,64 +771,45 @@ in6_ifattach(struct ifnet *ifp, struct ifnet *altifp)
/*
* 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.
+ *
+ * When shutting down a VNET we clean up layers top-down. In that case
+ * upper layer protocols (ulp) are cleaned up already and locks are destroyed
+ * and we must not call into these cleanup functions anymore, thus purgeulp
+ * is set to 0 in that case by in6_ifdetach_destroy().
+ * The normal case of destroying a (cloned) interface still needs to cleanup
+ * everything related to the interface and will have purgeulp set to 1.
*/
-void
-in6_ifdetach(struct ifnet *ifp)
+static void
+_in6_ifdetach(struct ifnet *ifp, int purgeulp)
{
- struct in6_ifaddr *ia;
struct ifaddr *ifa, *next;
- struct radix_node_head *rnh;
- struct rtentry *rt;
- struct sockaddr_in6 sin6;
- struct in6_multi_mship *imm;
- /* remove neighbor management table */
- nd6_purge(ifp);
+ if (ifp->if_afdata[AF_INET6] == NULL)
+ return;
- /* nuke any of IPv6 addresses we have */
+ /*
+ * Remove neighbor management table.
+ * Enabling the nd6_purge will panic on vmove for interfaces on VNET
+ * teardown as the IPv6 layer is cleaned up already and the locks
+ * are destroyed.
+ */
+ if (purgeulp)
+ nd6_purge(ifp);
+
+ /*
+ * nuke any of IPv6 addresses we have
+ * XXX: all addresses should be already removed
+ */
TAILQ_FOREACH_SAFE(ifa, &ifp->if_addrhead, ifa_link, next) {
if (ifa->ifa_addr->sa_family != AF_INET6)
continue;
in6_purgeaddr(ifa);
}
-
- /* undo everything done by in6_ifattach(), just in case */
- TAILQ_FOREACH_SAFE(ifa, &ifp->if_addrhead, ifa_link, next) {
- if (ifa->ifa_addr->sa_family != AF_INET6
- || !IN6_IS_ADDR_LINKLOCAL(&satosin6(&ifa->ifa_addr)->sin6_addr)) {
- continue;
- }
-
- ia = (struct in6_ifaddr *)ifa;
-
- /*
- * leave from multicast groups we have joined for the interface
- */
- while ((imm = LIST_FIRST(&ia->ia6_memberships)) != NULL) {
- LIST_REMOVE(imm, i6mm_chain);
- in6_leavegroup(imm);
- }
-
- /* Remove link-local from the routing table. */
- if (ia->ia_flags & IFA_ROUTE)
- (void)rtinit(&ia->ia_ifa, RTM_DELETE, ia->ia_flags);
-
- /* remove from the linked list */
- IF_ADDR_WLOCK(ifp);
- TAILQ_REMOVE(&ifp->if_addrhead, ifa, ifa_link);
- IF_ADDR_WUNLOCK(ifp);
- ifa_free(ifa); /* if_addrhead */
-
- IN6_IFADDR_WLOCK();
- TAILQ_REMOVE(&V_in6_ifaddrhead, ia, ia_link);
- IN6_IFADDR_WUNLOCK();
- ifa_free(ifa);
+ if (purgeulp) {
+ in6_pcbpurgeif0(&V_udbinfo, ifp);
+ in6_pcbpurgeif0(&V_ulitecbinfo, ifp);
+ in6_pcbpurgeif0(&V_ripcbinfo, ifp);
}
-
- in6_pcbpurgeif0(&V_udbinfo, ifp);
- in6_pcbpurgeif0(&V_ripcbinfo, ifp);
/* leave from all multicast groups joined */
in6_purgemaddrs(ifp);
@@ -882,32 +821,22 @@ in6_ifdetach(struct ifnet *ifp)
* prefixes after removing all addresses above.
* (Or can we just delay calling nd6_purge until at this point?)
*/
- nd6_purge(ifp);
+ if (purgeulp)
+ nd6_purge(ifp);
+}
- /*
- * Remove route to link-local allnodes multicast (ff02::1).
- * These only get automatically installed for the default FIB.
- */
- bzero(&sin6, sizeof(sin6));
- sin6.sin6_len = sizeof(struct sockaddr_in6);
- sin6.sin6_family = AF_INET6;
- sin6.sin6_addr = in6addr_linklocal_allnodes;
- if (in6_setscope(&sin6.sin6_addr, ifp, NULL))
- /* XXX: should not fail */
- return;
- /* XXX grab lock first to avoid LOR */
- rnh = rt_tables_get_rnh(RT_DEFAULT_FIB, AF_INET6);
- if (rnh != NULL) {
- RADIX_NODE_HEAD_LOCK(rnh);
- rt = in6_rtalloc1((struct sockaddr *)&sin6, 0, RTF_RNH_LOCKED,
- RT_DEFAULT_FIB);
- if (rt) {
- if (rt->rt_ifp == ifp)
- rtexpunge(rt);
- RTFREE_LOCKED(rt);
- }
- RADIX_NODE_HEAD_UNLOCK(rnh);
- }
+void
+in6_ifdetach(struct ifnet *ifp)
+{
+
+ _in6_ifdetach(ifp, 1);
+}
+
+void
+in6_ifdetach_destroy(struct ifnet *ifp)
+{
+
+ _in6_ifdetach(ifp, 0);
}
int
@@ -948,7 +877,9 @@ in6_tmpaddrtimer(void *arg)
V_ip6_temp_regen_advance) * hz, in6_tmpaddrtimer, curvnet);
bzero(nullbuf, sizeof(nullbuf));
- TAILQ_FOREACH(ifp, &V_ifnet, if_list) {
+ TAILQ_FOREACH(ifp, &V_ifnet, if_link) {
+ if (ifp->if_afdata[AF_INET6] == NULL)
+ continue;
ndi = ND_IFINFO(ifp);
if (bcmp(ndi->randomid, nullbuf, sizeof(nullbuf)) != 0) {
/*
@@ -997,3 +928,29 @@ in6_purgemaddrs(struct ifnet *ifp)
IN6_MULTI_UNLOCK();
}
+
+void
+in6_ifattach_destroy(void)
+{
+
+ callout_drain(&V_in6_tmpaddrtimer_ch);
+}
+
+static void
+in6_ifattach_init(void *dummy)
+{
+
+ /* Timer for regeneranation of temporary addresses randomize ID. */
+ callout_init(&V_in6_tmpaddrtimer_ch, 0);
+ callout_reset(&V_in6_tmpaddrtimer_ch,
+ (V_ip6_temp_preferred_lifetime - V_ip6_desync_factor -
+ V_ip6_temp_regen_advance) * hz,
+ in6_tmpaddrtimer, curvnet);
+}
+
+/*
+ * Cheat.
+ * This must be after route_init(), which is now SI_ORDER_THIRD.
+ */
+SYSINIT(in6_ifattach_init, SI_SUB_PROTO_DOMAIN, SI_ORDER_MIDDLE,
+ in6_ifattach_init, NULL);