/** * 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 vm_device *device_ctx = to_vm_device(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; }
/* * 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 vm_device *device_ctx = to_vm_device(device_obj); struct net_device *net = dev_get_drvdata(&device_ctx->device); struct sk_buff *skb; void *data; 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; } /* Allocate a skb - TODO direct I/O to pages? */ skb = netdev_alloc_skb_ip_align(net, packet->TotalDataBufferLength); if (unlikely(!skb)) { ++net->stats.rx_dropped; return 0; } /* 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; net->stats.rx_packets++; net->stats.rx_bytes += skb->len; /* * Pass the skb back up. Network stack will deallocate the skb when it * is done. * TODO - use NAPI? */ netif_rx(skb); DPRINT_DBG(NETVSC_DRV, "# of recvs %lu total size %lu", net->stats.rx_packets, net->stats.rx_bytes); DPRINT_EXIT(NETVSC_DRV); return 0; }