+ lck_mtx_unlock(rnh_lock);
+ }
+}
+
+static int
+if_rtmtu(struct radix_node *rn, void *arg)
+{
+ struct rtentry *rt = (struct rtentry *)rn;
+ struct ifnet *ifp = arg;
+
+ RT_LOCK(rt);
+ if (rt->rt_ifp == ifp) {
+ /*
+ * Update the MTU of this entry only if the MTU
+ * has not been locked (RTV_MTU is not set) and
+ * if it was non-zero to begin with.
+ */
+ if (!(rt->rt_rmx.rmx_locks & RTV_MTU) && rt->rt_rmx.rmx_mtu)
+ rt->rt_rmx.rmx_mtu = ifp->if_mtu;
+ }
+ RT_UNLOCK(rt);
+
+ return (0);
+}
+
+/*
+ * Update the MTU metric of all route entries in all protocol tables
+ * associated with a particular interface; this is called when the
+ * MTU of that interface has changed.
+ */
+static
+void if_rtmtu_update(struct ifnet *ifp)
+{
+ struct radix_node_head *rnh;
+ int p;
+
+ for (p = 0; p < AF_MAX + 1; p++) {
+ if ((rnh = rt_tables[p]) == NULL)
+ continue;
+
+ lck_mtx_lock(rnh_lock);
+ (void) rnh->rnh_walktree(rnh, if_rtmtu, ifp);
+ lck_mtx_unlock(rnh_lock);
+ }
+ routegenid_update();
+}
+
+__private_extern__ void
+if_data_internal_to_if_data(struct ifnet *ifp,
+ const struct if_data_internal *if_data_int, struct if_data *if_data)
+{
+#pragma unused(ifp)
+#define COPYFIELD(fld) if_data->fld = if_data_int->fld
+#define COPYFIELD32(fld) if_data->fld = (u_int32_t)(if_data_int->fld)
+/* compiler will cast down to 32-bit */
+#define COPYFIELD32_ATOMIC(fld) do { \
+ atomic_get_64(if_data->fld, \
+ (u_int64_t *)(void *)(uintptr_t)&if_data_int->fld); \
+} while (0)
+
+ COPYFIELD(ifi_type);
+ COPYFIELD(ifi_typelen);
+ COPYFIELD(ifi_physical);
+ COPYFIELD(ifi_addrlen);
+ COPYFIELD(ifi_hdrlen);
+ COPYFIELD(ifi_recvquota);
+ COPYFIELD(ifi_xmitquota);
+ if_data->ifi_unused1 = 0;
+ COPYFIELD(ifi_mtu);
+ COPYFIELD(ifi_metric);
+ if (if_data_int->ifi_baudrate & 0xFFFFFFFF00000000LL) {
+ if_data->ifi_baudrate = 0xFFFFFFFF;
+ } else {
+ COPYFIELD32(ifi_baudrate);
+ }
+
+ COPYFIELD32_ATOMIC(ifi_ipackets);
+ COPYFIELD32_ATOMIC(ifi_ierrors);
+ COPYFIELD32_ATOMIC(ifi_opackets);
+ COPYFIELD32_ATOMIC(ifi_oerrors);
+ COPYFIELD32_ATOMIC(ifi_collisions);
+ COPYFIELD32_ATOMIC(ifi_ibytes);
+ COPYFIELD32_ATOMIC(ifi_obytes);
+ COPYFIELD32_ATOMIC(ifi_imcasts);
+ COPYFIELD32_ATOMIC(ifi_omcasts);
+ COPYFIELD32_ATOMIC(ifi_iqdrops);
+ COPYFIELD32_ATOMIC(ifi_noproto);
+
+ COPYFIELD(ifi_recvtiming);
+ COPYFIELD(ifi_xmittiming);
+
+ if_data->ifi_lastchange.tv_sec = if_data_int->ifi_lastchange.tv_sec;
+ if_data->ifi_lastchange.tv_usec = if_data_int->ifi_lastchange.tv_usec;
+
+ if_data->ifi_lastchange.tv_sec += boottime_sec();
+
+ if_data->ifi_unused2 = 0;
+ COPYFIELD(ifi_hwassist);
+ if_data->ifi_reserved1 = 0;
+ if_data->ifi_reserved2 = 0;
+#undef COPYFIELD32_ATOMIC
+#undef COPYFIELD32
+#undef COPYFIELD
+}
+
+__private_extern__ void
+if_data_internal_to_if_data64(struct ifnet *ifp,
+ const struct if_data_internal *if_data_int,
+ struct if_data64 *if_data64)
+{
+#pragma unused(ifp)
+#define COPYFIELD64(fld) if_data64->fld = if_data_int->fld
+#define COPYFIELD64_ATOMIC(fld) do { \
+ atomic_get_64(if_data64->fld, \
+ (u_int64_t *)(void *)(uintptr_t)&if_data_int->fld); \
+} while (0)
+
+ COPYFIELD64(ifi_type);
+ COPYFIELD64(ifi_typelen);
+ COPYFIELD64(ifi_physical);
+ COPYFIELD64(ifi_addrlen);
+ COPYFIELD64(ifi_hdrlen);
+ COPYFIELD64(ifi_recvquota);
+ COPYFIELD64(ifi_xmitquota);
+ if_data64->ifi_unused1 = 0;
+ COPYFIELD64(ifi_mtu);
+ COPYFIELD64(ifi_metric);
+ COPYFIELD64(ifi_baudrate);
+
+ COPYFIELD64_ATOMIC(ifi_ipackets);
+ COPYFIELD64_ATOMIC(ifi_ierrors);
+ COPYFIELD64_ATOMIC(ifi_opackets);
+ COPYFIELD64_ATOMIC(ifi_oerrors);
+ COPYFIELD64_ATOMIC(ifi_collisions);
+ COPYFIELD64_ATOMIC(ifi_ibytes);
+ COPYFIELD64_ATOMIC(ifi_obytes);
+ COPYFIELD64_ATOMIC(ifi_imcasts);
+ COPYFIELD64_ATOMIC(ifi_omcasts);
+ COPYFIELD64_ATOMIC(ifi_iqdrops);
+ COPYFIELD64_ATOMIC(ifi_noproto);
+
+ /* Note these two fields are actually 32 bit, so doing COPYFIELD64_ATOMIC will
+ * cause them to be misaligned
+ */
+ COPYFIELD64(ifi_recvtiming);
+ COPYFIELD64(ifi_xmittiming);
+
+ if_data64->ifi_lastchange.tv_sec = if_data_int->ifi_lastchange.tv_sec;
+ if_data64->ifi_lastchange.tv_usec = if_data_int->ifi_lastchange.tv_usec;
+
+ if_data64->ifi_lastchange.tv_sec += boottime_sec();
+
+#undef COPYFIELD64
+}
+
+__private_extern__ void
+if_copy_traffic_class(struct ifnet *ifp,
+ struct if_traffic_class *if_tc)
+{
+#define COPY_IF_TC_FIELD64_ATOMIC(fld) do { \
+ atomic_get_64(if_tc->fld, \
+ (u_int64_t *)(void *)(uintptr_t)&ifp->if_tc.fld); \
+} while (0)
+
+ bzero(if_tc, sizeof (*if_tc));
+ COPY_IF_TC_FIELD64_ATOMIC(ifi_ibepackets);
+ COPY_IF_TC_FIELD64_ATOMIC(ifi_ibebytes);
+ COPY_IF_TC_FIELD64_ATOMIC(ifi_obepackets);
+ COPY_IF_TC_FIELD64_ATOMIC(ifi_obebytes);
+ COPY_IF_TC_FIELD64_ATOMIC(ifi_ibkpackets);
+ COPY_IF_TC_FIELD64_ATOMIC(ifi_ibkbytes);
+ COPY_IF_TC_FIELD64_ATOMIC(ifi_obkpackets);
+ COPY_IF_TC_FIELD64_ATOMIC(ifi_obkbytes);
+ COPY_IF_TC_FIELD64_ATOMIC(ifi_ivipackets);
+ COPY_IF_TC_FIELD64_ATOMIC(ifi_ivibytes);
+ COPY_IF_TC_FIELD64_ATOMIC(ifi_ovipackets);
+ COPY_IF_TC_FIELD64_ATOMIC(ifi_ovibytes);
+ COPY_IF_TC_FIELD64_ATOMIC(ifi_ivopackets);
+ COPY_IF_TC_FIELD64_ATOMIC(ifi_ivobytes);
+ COPY_IF_TC_FIELD64_ATOMIC(ifi_ovopackets);
+ COPY_IF_TC_FIELD64_ATOMIC(ifi_ovobytes);
+ COPY_IF_TC_FIELD64_ATOMIC(ifi_ipvpackets);
+ COPY_IF_TC_FIELD64_ATOMIC(ifi_ipvbytes);
+ COPY_IF_TC_FIELD64_ATOMIC(ifi_opvpackets);
+ COPY_IF_TC_FIELD64_ATOMIC(ifi_opvbytes);
+
+#undef COPY_IF_TC_FIELD64_ATOMIC
+}
+
+void
+if_copy_data_extended(struct ifnet *ifp, struct if_data_extended *if_de)
+{
+#define COPY_IF_DE_FIELD64_ATOMIC(fld) do { \
+ atomic_get_64(if_de->fld, \
+ (u_int64_t *)(void *)(uintptr_t)&ifp->if_data.fld); \
+} while (0)
+
+ bzero(if_de, sizeof (*if_de));
+ COPY_IF_DE_FIELD64_ATOMIC(ifi_alignerrs);
+ COPY_IF_DE_FIELD64_ATOMIC(ifi_dt_bytes);
+ COPY_IF_DE_FIELD64_ATOMIC(ifi_fpackets);
+ COPY_IF_DE_FIELD64_ATOMIC(ifi_fbytes);
+
+#undef COPY_IF_DE_FIELD64_ATOMIC
+}
+
+void
+if_copy_packet_stats(struct ifnet *ifp, struct if_packet_stats *if_ps)
+{
+#define COPY_IF_PS_TCP_FIELD64_ATOMIC(fld) do { \
+ atomic_get_64(if_ps->ifi_tcp_##fld, \
+ (u_int64_t *)(void *)(uintptr_t)&ifp->if_tcp_stat->fld); \
+} while (0)
+
+#define COPY_IF_PS_UDP_FIELD64_ATOMIC(fld) do { \
+ atomic_get_64(if_ps->ifi_udp_##fld, \
+ (u_int64_t *)(void *)(uintptr_t)&ifp->if_udp_stat->fld); \
+} while (0)
+
+ COPY_IF_PS_TCP_FIELD64_ATOMIC(badformat);
+ COPY_IF_PS_TCP_FIELD64_ATOMIC(unspecv6);
+ COPY_IF_PS_TCP_FIELD64_ATOMIC(synfin);
+ COPY_IF_PS_TCP_FIELD64_ATOMIC(badformatipsec);
+ COPY_IF_PS_TCP_FIELD64_ATOMIC(noconnnolist);
+ COPY_IF_PS_TCP_FIELD64_ATOMIC(noconnlist);
+ COPY_IF_PS_TCP_FIELD64_ATOMIC(listbadsyn);
+ COPY_IF_PS_TCP_FIELD64_ATOMIC(icmp6unreach);
+ COPY_IF_PS_TCP_FIELD64_ATOMIC(deprecate6);
+ COPY_IF_PS_TCP_FIELD64_ATOMIC(ooopacket);
+ COPY_IF_PS_TCP_FIELD64_ATOMIC(rstinsynrcv);
+ COPY_IF_PS_TCP_FIELD64_ATOMIC(dospacket);
+ COPY_IF_PS_TCP_FIELD64_ATOMIC(cleanup);
+ COPY_IF_PS_TCP_FIELD64_ATOMIC(synwindow);
+
+ COPY_IF_PS_UDP_FIELD64_ATOMIC(port_unreach);
+ COPY_IF_PS_UDP_FIELD64_ATOMIC(faithprefix);
+ COPY_IF_PS_UDP_FIELD64_ATOMIC(port0);
+ COPY_IF_PS_UDP_FIELD64_ATOMIC(badlength);
+ COPY_IF_PS_UDP_FIELD64_ATOMIC(badchksum);
+ COPY_IF_PS_UDP_FIELD64_ATOMIC(badmcast);
+ COPY_IF_PS_UDP_FIELD64_ATOMIC(cleanup);
+ COPY_IF_PS_UDP_FIELD64_ATOMIC(badipsec);
+
+#undef COPY_IF_PS_TCP_FIELD64_ATOMIC
+#undef COPY_IF_PS_UDP_FIELD64_ATOMIC
+}
+
+void
+if_copy_rxpoll_stats(struct ifnet *ifp, struct if_rxpoll_stats *if_rs)
+{
+ bzero(if_rs, sizeof (*if_rs));
+ if (!(ifp->if_eflags & IFEF_RXPOLL) || !ifnet_is_attached(ifp, 1))
+ return;
+
+ /* by now, ifnet will stay attached so if_inp must be valid */
+ VERIFY(ifp->if_inp != NULL);
+ bcopy(&ifp->if_inp->pstats, if_rs, sizeof (*if_rs));
+
+ /* Release the IO refcnt */
+ ifnet_decr_iorefcnt(ifp);
+}
+
+struct ifaddr *
+ifa_remref(struct ifaddr *ifa, int locked)
+{
+ if (!locked)
+ IFA_LOCK_SPIN(ifa);
+ else
+ IFA_LOCK_ASSERT_HELD(ifa);
+
+ if (ifa->ifa_refcnt == 0)
+ panic("%s: ifa %p negative refcnt\n", __func__, ifa);
+ else if (ifa->ifa_trace != NULL)
+ (*ifa->ifa_trace)(ifa, FALSE);
+ if (--ifa->ifa_refcnt == 0) {
+ if (ifa->ifa_debug & IFD_ATTACHED)
+ panic("ifa %p attached to ifp is being freed\n", ifa);
+ /*
+ * Some interface addresses are allocated either statically
+ * or carved out of a larger block. Only free it if it was
+ * allocated via MALLOC or via the corresponding per-address
+ * family allocator. Otherwise, leave it alone.
+ */
+ if (ifa->ifa_debug & IFD_ALLOC) {
+ if (ifa->ifa_free == NULL) {
+ IFA_UNLOCK(ifa);
+ FREE(ifa, M_IFADDR);
+ } else {
+ /* Become a regular mutex */
+ IFA_CONVERT_LOCK(ifa);
+ /* callee will unlock */
+ (*ifa->ifa_free)(ifa);
+ }
+ } else {
+ IFA_UNLOCK(ifa);
+ }
+ ifa = NULL;
+ }
+
+ if (!locked && ifa != NULL)
+ IFA_UNLOCK(ifa);
+
+ return (ifa);
+}
+
+void
+ifa_addref(struct ifaddr *ifa, int locked)
+{
+ if (!locked)
+ IFA_LOCK_SPIN(ifa);
+ else
+ IFA_LOCK_ASSERT_HELD(ifa);
+
+ if (++ifa->ifa_refcnt == 0) {
+ panic("%s: ifa %p wraparound refcnt\n", __func__, ifa);
+ /* NOTREACHED */
+ } else if (ifa->ifa_trace != NULL) {
+ (*ifa->ifa_trace)(ifa, TRUE);
+ }
+ if (!locked)
+ IFA_UNLOCK(ifa);
+}
+
+void
+ifa_lock_init(struct ifaddr *ifa)
+{
+ lck_mtx_init(&ifa->ifa_lock, ifa_mtx_grp, ifa_mtx_attr);
+}
+
+void
+ifa_lock_destroy(struct ifaddr *ifa)
+{
+ IFA_LOCK_ASSERT_NOTHELD(ifa);
+ lck_mtx_destroy(&ifa->ifa_lock, ifa_mtx_grp);
+}
+
+/*
+ * 'i' group ioctls.
+ *
+ * The switch statement below does nothing at runtime, as it serves as a
+ * compile time check to ensure that all of the socket 'i' ioctls (those
+ * in the 'i' group going thru soo_ioctl) that are made available by the
+ * networking stack is unique. This works as long as this routine gets
+ * updated each time a new interface ioctl gets added.
+ *
+ * Any failures at compile time indicates duplicated ioctl values.
+ */
+static __attribute__((unused)) void
+ifioctl_cassert(void)
+{
+ /*
+ * This is equivalent to _CASSERT() and the compiler wouldn't
+ * generate any instructions, thus for compile time only.
+ */
+ switch ((u_long)0) {
+ case 0:
+
+ /* bsd/net/if_ppp.h */
+ case SIOCGPPPSTATS:
+ case SIOCGPPPCSTATS:
+
+#if INET6
+ /* bsd/netinet6/in6_var.h */
+ case SIOCSIFADDR_IN6:
+ case SIOCGIFADDR_IN6:
+ case SIOCSIFDSTADDR_IN6:
+ case SIOCSIFNETMASK_IN6:
+ case SIOCGIFDSTADDR_IN6:
+ case SIOCGIFNETMASK_IN6:
+ case SIOCDIFADDR_IN6:
+ case SIOCAIFADDR_IN6_32:
+ case SIOCAIFADDR_IN6_64:
+ case SIOCSIFPHYADDR_IN6_32:
+ case SIOCSIFPHYADDR_IN6_64:
+ case SIOCGIFPSRCADDR_IN6:
+ case SIOCGIFPDSTADDR_IN6:
+ case SIOCGIFAFLAG_IN6:
+ case SIOCGDRLST_IN6_32:
+ case SIOCGDRLST_IN6_64:
+ case SIOCGPRLST_IN6_32:
+ case SIOCGPRLST_IN6_64:
+ case OSIOCGIFINFO_IN6:
+ case SIOCGIFINFO_IN6:
+ case SIOCSNDFLUSH_IN6:
+ case SIOCGNBRINFO_IN6_32:
+ case SIOCGNBRINFO_IN6_64:
+ case SIOCSPFXFLUSH_IN6:
+ case SIOCSRTRFLUSH_IN6:
+ case SIOCGIFALIFETIME_IN6:
+ case SIOCSIFALIFETIME_IN6:
+ case SIOCGIFSTAT_IN6:
+ case SIOCGIFSTAT_ICMP6:
+ case SIOCSDEFIFACE_IN6_32:
+ case SIOCSDEFIFACE_IN6_64:
+ case SIOCGDEFIFACE_IN6_32:
+ case SIOCGDEFIFACE_IN6_64:
+ case SIOCSIFINFO_FLAGS:
+ case SIOCSSCOPE6:
+ case SIOCGSCOPE6:
+ case SIOCGSCOPE6DEF:
+ case SIOCSIFPREFIX_IN6:
+ case SIOCGIFPREFIX_IN6:
+ case SIOCDIFPREFIX_IN6:
+ case SIOCAIFPREFIX_IN6:
+ case SIOCCIFPREFIX_IN6:
+ case SIOCSGIFPREFIX_IN6:
+ case SIOCPROTOATTACH_IN6_32:
+ case SIOCPROTOATTACH_IN6_64:
+ case SIOCPROTODETACH_IN6:
+ case SIOCLL_START_32:
+ case SIOCLL_START_64:
+ case SIOCLL_STOP:
+ case SIOCAUTOCONF_START:
+ case SIOCAUTOCONF_STOP:
+ case SIOCSETROUTERMODE_IN6:
+ case SIOCLL_CGASTART_32:
+ case SIOCLL_CGASTART_64:
+#endif /* INET6 */
+
+ /* bsd/sys/sockio.h */
+ case SIOCSIFADDR:
+ case OSIOCGIFADDR:
+ case SIOCSIFDSTADDR:
+ case OSIOCGIFDSTADDR:
+ case SIOCSIFFLAGS:
+ case SIOCGIFFLAGS:
+ case OSIOCGIFBRDADDR:
+ case SIOCSIFBRDADDR:
+ case OSIOCGIFCONF32:
+ case OSIOCGIFCONF64:
+ case OSIOCGIFNETMASK:
+ case SIOCSIFNETMASK:
+ case SIOCGIFMETRIC:
+ case SIOCSIFMETRIC:
+ case SIOCDIFADDR:
+ case SIOCAIFADDR:
+ case SIOCGIFADDR:
+ case SIOCGIFDSTADDR:
+ case SIOCGIFBRDADDR:
+ case SIOCGIFCONF32:
+ case SIOCGIFCONF64:
+ case SIOCGIFNETMASK:
+ case SIOCAUTOADDR:
+ case SIOCAUTONETMASK:
+ case SIOCARPIPLL:
+ case SIOCADDMULTI:
+ case SIOCDELMULTI:
+ case SIOCGIFMTU:
+ case SIOCSIFMTU:
+ case SIOCGIFPHYS:
+ case SIOCSIFPHYS:
+ case SIOCSIFMEDIA:
+ case SIOCGIFMEDIA32:
+ case SIOCGIFMEDIA64:
+ case SIOCSIFGENERIC:
+ case SIOCGIFGENERIC:
+ case SIOCRSLVMULTI:
+ case SIOCSIFLLADDR:
+ case SIOCGIFSTATUS:
+ case SIOCSIFPHYADDR:
+ case SIOCGIFPSRCADDR:
+ case SIOCGIFPDSTADDR:
+ case SIOCDIFPHYADDR:
+ case SIOCGIFDEVMTU:
+ case SIOCSIFALTMTU:
+ case SIOCGIFALTMTU:
+ case SIOCSIFBOND:
+ case SIOCGIFBOND:
+ case SIOCPROTOATTACH:
+ case SIOCPROTODETACH:
+ case SIOCSIFCAP:
+ case SIOCGIFCAP:
+ case SIOCIFCREATE:
+ case SIOCIFDESTROY:
+ case SIOCIFCREATE2:
+ case SIOCSDRVSPEC32:
+ case SIOCGDRVSPEC32:
+ case SIOCSDRVSPEC64:
+ case SIOCGDRVSPEC64:
+ case SIOCSIFVLAN:
+ case SIOCGIFVLAN:
+ case SIOCIFGCLONERS32:
+ case SIOCIFGCLONERS64:
+ case SIOCGIFASYNCMAP:
+ case SIOCSIFASYNCMAP:
+#if CONFIG_MACF_NET
+ case SIOCGIFMAC:
+ case SIOCSIFMAC:
+#endif /* CONFIG_MACF_NET */
+ case SIOCSIFKPI:
+ case SIOCGIFKPI:
+ case SIOCGIFWAKEFLAGS:
+ case SIOCGIFGETRTREFCNT:
+ case SIOCGIFLINKQUALITYMETRIC:
+ case SIOCSIFOPPORTUNISTIC:
+ case SIOCGIFOPPORTUNISTIC:
+ case SIOCSETROUTERMODE:
+ case SIOCGIFEFLAGS:
+ case SIOCSIFDESC:
+ case SIOCGIFDESC:
+ case SIOCSIFLINKPARAMS:
+ case SIOCGIFLINKPARAMS:
+ case SIOCGIFQUEUESTATS:
+ case SIOCSIFTHROTTLE:
+ case SIOCGIFTHROTTLE:
+ case SIOCSIFLOG:
+ case SIOCGIFLOG:
+ case SIOCGIFDELEGATE:
+ case SIOCGIFLLADDR:
+ case SIOCGIFTYPE:
+ case SIOCGIFFUNCTIONALTYPE:
+ case SIOCAIFAGENTID:
+ case SIOCDIFAGENTID:
+ case SIOCGIFAGENTIDS32:
+ case SIOCGIFAGENTIDS64:
+ case SIOCGIFAGENTDATA32:
+ case SIOCGIFAGENTDATA64:
+ case SIOCSIFINTERFACESTATE:
+ case SIOCGIFINTERFACESTATE:
+ case SIOCSIFPROBECONNECTIVITY:
+ case SIOCGIFPROBECONNECTIVITY:
+ case SIOCGECNMODE:
+ case SIOCSECNMODE:
+ ;
+ }