/* Network Interface functions */ static void utun_start(ifnet_t interface) { mbuf_t data; struct utun_pcb*pcb = ifnet_softc(interface); for (;;) { bool can_accept_packets = true; ifnet_lock_shared(pcb->utun_ifp); can_accept_packets = (pcb->utun_pending_packets < pcb->utun_max_pending_packets); if (!can_accept_packets && pcb->utun_ctlref) { u_int32_t difference = 0; if (ctl_getenqueuereadable(pcb->utun_ctlref, pcb->utun_unit, &difference) == 0) { if (difference > 0) { // If the low-water mark has not yet been reached, we still need to enqueue data // into the buffer can_accept_packets = true; } } } if (!can_accept_packets) { errno_t error = ifnet_disable_output(interface); if (error != 0) { printf("utun_start: ifnet_disable_output returned error %d\n", error); } ifnet_lock_done(pcb->utun_ifp); break; } ifnet_lock_done(pcb->utun_ifp); if (ifnet_dequeue(interface, &data) != 0) break; if (utun_output(interface, data) != 0) break; } }
static void utun_ctl_rcvd(kern_ctl_ref kctlref, u_int32_t unit, void *unitinfo, int flags) { #pragma unused(flags) bool reenable_output = false; struct utun_pcb *pcb = unitinfo; if (pcb == NULL) { return; } ifnet_lock_exclusive(pcb->utun_ifp); u_int32_t utun_packet_cnt; errno_t error_pc = ctl_getenqueuepacketcount(kctlref, unit, &utun_packet_cnt); if (error_pc != 0) { printf("utun_ctl_rcvd: ctl_getenqueuepacketcount returned error %d\n", error_pc); utun_packet_cnt = 0; } if (utun_packet_cnt < pcb->utun_max_pending_packets) { reenable_output = true; } if (reenable_output) { errno_t error = ifnet_enable_output(pcb->utun_ifp); if (error != 0) { printf("utun_ctl_rcvd: ifnet_enable_output returned error %d\n", error); } } ifnet_lock_done(pcb->utun_ifp); }
int if_set_low_power(ifnet_t ifp, bool on) { int error = 0; if (ifp == NULL) return (EINVAL); os_log(OS_LOG_DEFAULT, "%s: ifp %s low_power mode %d", __func__, if_name(ifp), on); ifnet_lock_exclusive(ifp); ifp->if_xflags = on ? (ifp->if_xflags | IFXF_LOW_POWER) : (ifp->if_xflags & ~IFXF_LOW_POWER); ifnet_lock_done(ifp); return (error); }
static void if_low_power_evhdlr_callback(__unused struct eventhandler_entry_arg arg, struct ifnet *ifp, if_low_power_ev_code_t event_code) { struct kev_dl_low_power_mode kev; if (!IF_FULLY_ATTACHED(ifp)) return; if (if_low_power_verbose > 0) { os_log_info(OS_LOG_DEFAULT, "%s: ifp %s event_code %d", __func__, if_name(ifp), event_code); } ifnet_lock_exclusive(ifp); if (event_code == IF_LOW_POWER_EVENT_OFF) { ifp->if_xflags &= ~IFXF_LOW_POWER; } else { ifp->if_xflags |= IFXF_LOW_POWER; } ifnet_lock_done(ifp); if (event_code == IF_LOW_POWER_EVENT_ON) { atomic_add_32(&ifp->if_low_power_gencnt, 1); if (if_low_power_restricted != 0) { shutdown_sockets_on_interface(ifp); intf_event_enqueue_nwk_wq_entry(ifp, NULL, INTF_EVENT_CODE_LOW_POWER_UPDATE); } } bzero(&kev, sizeof(struct kev_dl_low_power_mode)); kev.low_power_event = event_code; dlil_post_msg(ifp, KEV_DL_SUBCLASS, KEV_DL_LOW_POWER_MODE_CHANGED, (struct net_event_data *)&kev, sizeof(struct kev_dl_low_power_mode)); }
static errno_t utun_output( ifnet_t interface, mbuf_t data) { struct utun_pcb *pcb = ifnet_softc(interface); errno_t result; if (m_pktlen(data) >= 4) { bpf_tap_out(pcb->utun_ifp, DLT_NULL, data, 0, 0); } if (pcb->utun_flags & UTUN_FLAGS_NO_OUTPUT) { /* flush data */ mbuf_freem(data); return 0; } // otherwise, fall thru to ctl_enqueumbuf if (pcb->utun_ctlref) { int length; // only pass packets to utun-crypto if crypto is enabled and 'suspend data traffic' is not. if ((pcb->utun_flags & (UTUN_FLAGS_CRYPTO | UTUN_FLAGS_CRYPTO_STOP_DATA_TRAFFIC)) == UTUN_FLAGS_CRYPTO) { if (utun_pkt_crypto_output(pcb, &data) == 0) { return 0; } } /* * The ABI requires the protocol in network byte order */ if (m_pktlen(data) >= 4) *(u_int32_t *)mbuf_data(data) = htonl(*(u_int32_t *)mbuf_data(data)); length = mbuf_pkthdr_len(data); // Increment packet count optimistically ifnet_lock_exclusive(pcb->utun_ifp); pcb->utun_pending_packets++; ifnet_lock_done(pcb->utun_ifp); result = ctl_enqueuembuf(pcb->utun_ctlref, pcb->utun_unit, data, CTL_DATA_EOR); if (result != 0) { // Decrement packet count if errored ifnet_lock_exclusive(pcb->utun_ifp); pcb->utun_pending_packets--; ifnet_lock_done(pcb->utun_ifp); mbuf_freem(data); printf("utun_output - ctl_enqueuembuf failed: %d\n", result); ifnet_stat_increment_out(interface, 0, 0, 1); } else { if (!pcb->utun_ext_ifdata_stats) ifnet_stat_increment_out(interface, 1, length, 0); } } else mbuf_freem(data); return 0; }