+void
+ifnet_increment_generation(ifnet_t interface)
+{
+ OSIncrementAtomic(&interface->if_generation);
+}
+
+u_int32_t
+ifnet_get_generation(ifnet_t interface)
+{
+ return (interface->if_generation);
+}
+
+void
+ifnet_remove_from_ordered_list(struct ifnet *ifp)
+{
+ ifnet_head_assert_exclusive();
+
+ // Remove from list
+ TAILQ_REMOVE(&ifnet_ordered_head, ifp, if_ordered_link);
+ ifp->if_ordered_link.tqe_next = NULL;
+ ifp->if_ordered_link.tqe_prev = NULL;
+
+ // Update ordered count
+ VERIFY(if_ordered_count > 0);
+ if_ordered_count--;
+}
+
+static int
+ifnet_reset_order(u_int32_t *ordered_indices, u_int32_t count)
+{
+ struct ifnet *ifp = NULL;
+ int error = 0;
+
+ ifnet_head_lock_exclusive();
+
+ // Flush current ordered list
+ for (ifp = TAILQ_FIRST(&ifnet_ordered_head); ifp != NULL;
+ ifp = TAILQ_FIRST(&ifnet_ordered_head)) {
+ ifnet_lock_exclusive(ifp);
+ ifnet_remove_from_ordered_list(ifp);
+ ifnet_lock_done(ifp);
+ }
+
+ VERIFY(if_ordered_count == 0);
+
+ for (u_int32_t order_index = 0; order_index < count; order_index++) {
+ u_int32_t interface_index = ordered_indices[order_index];
+ if (interface_index == IFSCOPE_NONE ||
+ (int)interface_index > if_index) {
+ break;
+ }
+ ifp = ifindex2ifnet[interface_index];
+ if (ifp == NULL) {
+ continue;
+ }
+ ifnet_lock_exclusive(ifp);
+ TAILQ_INSERT_TAIL(&ifnet_ordered_head, ifp, if_ordered_link);
+ ifnet_lock_done(ifp);
+ if_ordered_count++;
+ }
+
+ ifnet_head_done();
+
+ necp_update_all_clients();
+
+ return (error);
+}
+
+int
+if_set_qosmarking_mode(struct ifnet *ifp, u_int32_t mode)
+{
+ int error = 0;
+ u_int32_t old_mode = ifp->if_qosmarking_mode;
+
+ switch (mode) {
+ case IFRTYPE_QOSMARKING_MODE_NONE:
+ ifp->if_qosmarking_mode = IFRTYPE_QOSMARKING_MODE_NONE;
+ ifp->if_eflags &= ~IFEF_QOSMARKING_CAPABLE;
+ break;
+ case IFRTYPE_QOSMARKING_FASTLANE:
+ ifp->if_qosmarking_mode = IFRTYPE_QOSMARKING_FASTLANE;
+ ifp->if_eflags |= IFEF_QOSMARKING_CAPABLE;
+ if (net_qos_policy_capable_enabled != 0)
+ ifp->if_eflags |= IFEF_QOSMARKING_ENABLED;
+ break;
+ default:
+ error = EINVAL;
+ break;
+ }
+ if (error == 0 && old_mode != ifp->if_qosmarking_mode) {
+ dlil_post_msg(ifp, KEV_DL_SUBCLASS, KEV_DL_QOS_MODE_CHANGED,
+ NULL, sizeof(struct kev_dl_rrc_state));
+
+ }
+ return (error);
+}
+
+static __attribute__((noinline)) int
+ifioctl_iforder(u_long cmd, caddr_t data)
+{
+ int error = 0;
+ u_int32_t *ordered_indices = NULL;
+
+ if (data == NULL) {
+ return (EINVAL);
+ }
+
+ switch (cmd) {
+ case SIOCSIFORDER: { /* struct if_order */
+ struct if_order *ifo = (struct if_order *)(void *)data;
+
+ if ((int)ifo->ifo_count > if_index) {
+ error = EINVAL;
+ break;
+ }
+
+ size_t length = (ifo->ifo_count * sizeof(u_int32_t));
+ if (length > 0) {
+ if (ifo->ifo_ordered_indices == USER_ADDR_NULL) {
+ error = EINVAL;
+ break;
+ }
+ ordered_indices = _MALLOC(length, M_NECP, M_WAITOK);
+ if (ordered_indices == NULL) {
+ error = ENOMEM;
+ break;
+ }
+
+ error = copyin(ifo->ifo_ordered_indices,
+ ordered_indices, length);
+ if (error != 0) {
+ break;
+ }
+ }
+
+ error = ifnet_reset_order(ordered_indices, ifo->ifo_count);
+ break;
+ }
+
+ case SIOCGIFORDER: { /* struct if_order */
+ struct if_order *ifo = (struct if_order *)(void *)data;
+
+ u_int32_t ordered_count = if_ordered_count;
+
+ if (ifo->ifo_count == 0 ||
+ ordered_count == 0) {
+ ifo->ifo_count = ordered_count;
+ } else if (ifo->ifo_ordered_indices != USER_ADDR_NULL) {
+ u_int32_t count_to_copy =
+ MIN(ordered_count, ifo->ifo_count);
+ size_t length = (count_to_copy * sizeof(u_int32_t));
+ struct ifnet *ifp = NULL;
+ u_int32_t cursor = 0;
+
+ ordered_indices = _MALLOC(length, M_NECP, M_WAITOK);
+ if (ordered_indices == NULL) {
+ error = ENOMEM;
+ break;
+ }
+
+ ifnet_head_lock_shared();
+ TAILQ_FOREACH(ifp, &ifnet_ordered_head, if_ordered_link) {
+ if (cursor > count_to_copy) {
+ break;
+ }
+ ordered_indices[cursor] = ifp->if_index;
+ cursor++;
+ }
+ ifnet_head_done();
+
+ ifo->ifo_count = count_to_copy;
+ error = copyout(ordered_indices,
+ ifo->ifo_ordered_indices, length);
+ } else {
+ error = EINVAL;
+ }
+ break;
+ }
+
+ default: {
+ VERIFY(0);
+ /* NOTREACHED */
+ }
+ }
+
+ if (ordered_indices != NULL) {
+ _FREE(ordered_indices, M_NECP);
+ }
+
+ return (error);
+}
+