/** * 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); }
/** * 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; }