diff --git a/drivers/net/hyperv/hyperv_net.h b/drivers/net/hyperv/hyperv_net.h index d58f28c463862a4a5bf89fa1d014d6ff485eb9b5..5fd6f4674326f0d3236ae8a97127b842ffffa008 100644 --- a/drivers/net/hyperv/hyperv_net.h +++ b/drivers/net/hyperv/hyperv_net.h @@ -35,6 +35,7 @@ struct hv_netvsc_packet; /* Represent the xfer page packet which contains 1 or more netvsc packet */ struct xferpage_packet { struct list_head list_ent; + u32 status; /* # of netvsc packets this xfer packet contains */ u32 count; @@ -47,6 +48,7 @@ struct xferpage_packet { struct hv_netvsc_packet { /* Bookkeeping stuff */ struct list_head list_ent; + u32 status; struct hv_device *device; bool is_data_pkt; diff --git a/drivers/net/hyperv/netvsc.c b/drivers/net/hyperv/netvsc.c index d9c4c0399c88d9a9d6034f35cc67a1ba138a713c..1cd77483da50114c2c309ab70a69dff134c3a919 100644 --- a/drivers/net/hyperv/netvsc.c +++ b/drivers/net/hyperv/netvsc.c @@ -558,7 +558,7 @@ int netvsc_send(struct hv_device *device, } static void netvsc_send_recv_completion(struct hv_device *device, - u64 transaction_id) + u64 transaction_id, u32 status) { struct nvsp_message recvcompMessage; int retries = 0; @@ -571,9 +571,7 @@ static void netvsc_send_recv_completion(struct hv_device *device, recvcompMessage.hdr.msg_type = NVSP_MSG1_TYPE_SEND_RNDIS_PKT_COMPLETE; - /* FIXME: Pass in the status */ - recvcompMessage.msg.v1_msg.send_rndis_pkt_complete.status = - NVSP_STAT_SUCCESS; + recvcompMessage.msg.v1_msg.send_rndis_pkt_complete.status = status; retry_send_cmplt: /* Send the completion */ @@ -613,6 +611,7 @@ static void netvsc_receive_completion(void *context) bool fsend_receive_comp = false; unsigned long flags; struct net_device *ndev; + u32 status = NVSP_STAT_NONE; /* * Even though it seems logical to do a GetOutboundNetDevice() here to @@ -627,6 +626,9 @@ static void netvsc_receive_completion(void *context) /* Overloading use of the lock. */ spin_lock_irqsave(&net_device->recv_pkt_list_lock, flags); + if (packet->status != NVSP_STAT_SUCCESS) + packet->xfer_page_pkt->status = NVSP_STAT_FAIL; + packet->xfer_page_pkt->count--; /* @@ -636,6 +638,7 @@ static void netvsc_receive_completion(void *context) if (packet->xfer_page_pkt->count == 0) { fsend_receive_comp = true; transaction_id = packet->completion.recv.recv_completion_tid; + status = packet->xfer_page_pkt->status; list_add_tail(&packet->xfer_page_pkt->list_ent, &net_device->recv_pkt_list); @@ -647,7 +650,7 @@ static void netvsc_receive_completion(void *context) /* Send a receive completion for the xfer page packet */ if (fsend_receive_comp) - netvsc_send_recv_completion(device, transaction_id); + netvsc_send_recv_completion(device, transaction_id, status); } @@ -736,7 +739,8 @@ static void netvsc_receive(struct hv_device *device, flags); netvsc_send_recv_completion(device, - vmxferpage_packet->d.trans_id); + vmxferpage_packet->d.trans_id, + NVSP_STAT_FAIL); return; } @@ -744,6 +748,7 @@ static void netvsc_receive(struct hv_device *device, /* Remove the 1st packet to represent the xfer page packet itself */ xferpage_packet = (struct xferpage_packet *)listHead.next; list_del(&xferpage_packet->list_ent); + xferpage_packet->status = NVSP_STAT_SUCCESS; /* This is how much we can satisfy */ xferpage_packet->count = count - 1; @@ -760,6 +765,7 @@ static void netvsc_receive(struct hv_device *device, list_del(&netvsc_packet->list_ent); /* Initialize the netvsc packet */ + netvsc_packet->status = NVSP_STAT_SUCCESS; netvsc_packet->xfer_page_pkt = xferpage_packet; netvsc_packet->completion.recv.recv_completion = netvsc_receive_completion; diff --git a/drivers/net/hyperv/netvsc_drv.c b/drivers/net/hyperv/netvsc_drv.c index e91111a656f715b77398e1208208f4b0ab5644a8..f825a629a699cfe5fac73803353da4b47ca18974 100644 --- a/drivers/net/hyperv/netvsc_drv.c +++ b/drivers/net/hyperv/netvsc_drv.c @@ -265,6 +265,7 @@ int netvsc_recv_callback(struct hv_device *device_obj, if (!net) { netdev_err(net, "got receive callback but net device" " not initialized yet\n"); + packet->status = NVSP_STAT_FAIL; return 0; } @@ -272,6 +273,7 @@ int netvsc_recv_callback(struct hv_device *device_obj, skb = netdev_alloc_skb_ip_align(net, packet->total_data_buflen); if (unlikely(!skb)) { ++net->stats.rx_dropped; + packet->status = NVSP_STAT_FAIL; return 0; } diff --git a/drivers/net/hyperv/rndis_filter.c b/drivers/net/hyperv/rndis_filter.c index f25f41e1fdb794d9f9197b6dea1f4caa7cf9a3d8..e7e12cfbbf379a69836b6778c17abef9bc82a601 100644 --- a/drivers/net/hyperv/rndis_filter.c +++ b/drivers/net/hyperv/rndis_filter.c @@ -411,9 +411,12 @@ int rndis_filter_receive(struct hv_device *dev, struct rndis_device *rndis_dev; struct rndis_message *rndis_msg; struct net_device *ndev; + int ret = 0; - if (!net_dev) - return -EINVAL; + if (!net_dev) { + ret = -EINVAL; + goto exit; + } ndev = net_dev->ndev; @@ -421,14 +424,16 @@ int rndis_filter_receive(struct hv_device *dev, if (!net_dev->extension) { netdev_err(ndev, "got rndis message but no rndis device - " "dropping this message!\n"); - return -ENODEV; + ret = -ENODEV; + goto exit; } rndis_dev = (struct rndis_device *)net_dev->extension; if (rndis_dev->state == RNDIS_DEV_UNINITIALIZED) { netdev_err(ndev, "got rndis message but rndis device " "uninitialized...dropping this message!\n"); - return -ENODEV; + ret = -ENODEV; + goto exit; } rndis_msg = pkt->data; @@ -460,7 +465,11 @@ int rndis_filter_receive(struct hv_device *dev, break; } - return 0; +exit: + if (ret != 0) + pkt->status = NVSP_STAT_FAIL; + + return ret; } static int rndis_filter_query_device(struct rndis_device *dev, u32 oid,