示例#1
0
/* 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;
	}
}
示例#2
0
文件: if_utun.c 项目: onlynone/xnu
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);
}
示例#3
0
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);
}
示例#4
0
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));
}
示例#5
0
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;
}