+ return (0);
+}
+
+void
+rtkey_to_sa6(struct rtentry *rt, struct sockaddr_in6 *sin6)
+{
+ VERIFY(rt_key(rt)->sa_family == AF_INET6);
+
+ *sin6 = *((struct sockaddr_in6 *)(void *)rt_key(rt));
+ sin6->sin6_scope_id = 0;
+}
+
+void
+rtgw_to_sa6(struct rtentry *rt, struct sockaddr_in6 *sin6)
+{
+ VERIFY(rt->rt_flags & RTF_GATEWAY);
+
+ *sin6 = *((struct sockaddr_in6 *)(void *)rt->rt_gateway);
+ sin6->sin6_scope_id = 0;
+}
+
+/*
+ * generate standard sockaddr_in6 from embedded form.
+ */
+int
+sa6_recoverscope(struct sockaddr_in6 *sin6, boolean_t attachcheck)
+{
+ u_int32_t zoneid;
+
+ if (sin6->sin6_scope_id != 0) {
+ log(LOG_NOTICE,
+ "sa6_recoverscope: assumption failure (non 0 ID): %s%%%d\n",
+ ip6_sprintf(&sin6->sin6_addr), sin6->sin6_scope_id);
+ /* XXX: proceed anyway... */
+ }
+ if (IN6_IS_SCOPE_LINKLOCAL(&sin6->sin6_addr) ||
+ IN6_IS_ADDR_MC_INTFACELOCAL(&sin6->sin6_addr)) {
+ /*
+ * KAME assumption: link id == interface id
+ */
+ zoneid = ntohs(sin6->sin6_addr.s6_addr16[1]);
+ if (zoneid) {
+ /* sanity check */
+ if (if_index < zoneid)
+ return (ENXIO);
+ /*
+ * We use the attachcheck parameter to skip the
+ * interface attachment check.
+ * Some callers might hold the ifnet_head lock in
+ * exclusive mode. This means that:
+ * 1) the interface can't go away -- hence we don't
+ * need to perform this check
+ * 2) we can't perform this check because the lock is
+ * in exclusive mode and trying to lock it in shared
+ * mode would cause a deadlock.
+ */
+ if (attachcheck) {
+ ifnet_head_lock_shared();
+ if (ifindex2ifnet[zoneid] == NULL) {
+ ifnet_head_done();
+ return (ENXIO);
+ }
+ ifnet_head_done();
+ }
+ sin6->sin6_addr.s6_addr16[1] = 0;
+ sin6->sin6_scope_id = zoneid;
+ }