Ejemplo n.º 1
0
/**
 * netvsc_linkstatus_callback - Link up/down notification
 */
static void netvsc_linkstatus_callback(struct hv_device *device_obj,
				       unsigned int status)
{
	struct device_context *device_ctx = to_device_context(device_obj);
	struct net_device *net = dev_get_drvdata(&device_ctx->device);
	struct net_device_context *ndev_ctx;

	DPRINT_ENTER(NETVSC_DRV);

	if (!net) {
		DPRINT_ERR(NETVSC_DRV, "got link status but net device "
				"not initialized yet");
		return;
	}

	if (status == 1) {
		netif_carrier_on(net);
		netif_wake_queue(net);
		netif_notify_peers(net);
		ndev_ctx = netdev_priv(net);
		schedule_work(&ndev_ctx->work);
	} else {
		netif_carrier_off(net);
		netif_stop_queue(net);
	}
	DPRINT_EXIT(NETVSC_DRV);
}
Ejemplo n.º 2
0
/**
 * netvsc_recv_callback -  Callback when we receive a packet from the "wire" on the specified device.
 */
static int netvsc_recv_callback(struct hv_device *device_obj,
				struct hv_netvsc_packet *packet)
{
	struct device_context *device_ctx = to_device_context(device_obj);
	struct net_device *net = dev_get_drvdata(&device_ctx->device);
	struct net_device_context *net_device_ctx;
	struct sk_buff *skb;
	void *data;
	int ret;
	int i;
	unsigned long flags;

	DPRINT_ENTER(NETVSC_DRV);

	if (!net) {
		DPRINT_ERR(NETVSC_DRV, "got receive callback but net device "
				"not initialized yet");
		return 0;
	}

	net_device_ctx = netdev_priv(net);

	/* Allocate a skb - TODO preallocate this */
	/* Pad 2-bytes to align IP header to 16 bytes */
	skb = dev_alloc_skb(packet->TotalDataBufferLength + 2);
	ASSERT(skb);
	skb_reserve(skb, 2);
	skb->dev = net;

	/* for kmap_atomic */
	local_irq_save(flags);

	/*
	 * Copy to skb. This copy is needed here since the memory pointed by
	 * hv_netvsc_packet cannot be deallocated
	 */
	for (i = 0; i < packet->PageBufferCount; i++) {
		data = kmap_atomic(pfn_to_page(packet->PageBuffers[i].Pfn),
					       KM_IRQ1);
		data = (void *)(unsigned long)data +
				packet->PageBuffers[i].Offset;

		memcpy(skb_put(skb, packet->PageBuffers[i].Length), data,
		       packet->PageBuffers[i].Length);

		kunmap_atomic((void *)((unsigned long)data -
				       packet->PageBuffers[i].Offset), KM_IRQ1);
	}

	local_irq_restore(flags);

	skb->protocol = eth_type_trans(skb, net);

	skb->ip_summed = CHECKSUM_NONE;

	/*
	 * Pass the skb back up. Network stack will deallocate the skb when it
	 * is done
	 */
	ret = netif_rx(skb);

	switch (ret) {
	case NET_RX_DROP:
		net_device_ctx->stats.rx_dropped++;
		break;
	default:
		net_device_ctx->stats.rx_packets++;
		net_device_ctx->stats.rx_bytes += skb->len;
		break;

	}
	DPRINT_DBG(NETVSC_DRV, "# of recvs %lu total size %lu",
		   net_device_ctx->stats.rx_packets,
		   net_device_ctx->stats.rx_bytes);

	DPRINT_EXIT(NETVSC_DRV);

	return 0;
}