aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHaiyang Zhang <haiyangz@microsoft.com>2014-06-19 21:34:36 -0400
committerDavid S. Miller <davem@davemloft.net>2014-06-20 00:17:37 -0400
commit3a494e710367c0a233d86bcde9853781859fc008 (patch)
treed79694a284627d3015a4b8975dd2d6aa7e434e04
parente0f802fbcaa3bffe4728e37a8fa1279b5d554173 (diff)
hyperv: Add handler for RNDIS_STATUS_NETWORK_CHANGE event
The RNDIS_STATUS_NETWORK_CHANGE event is received after the Hyper-V host sleep or hibernation. We refresh network at this time. MS-TFS: 135162 Signed-off-by: Haiyang Zhang <haiyangz@microsoft.com> Reviewed-by: K. Y. Srinivasan <kys@microsoft.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--drivers/net/hyperv/hyperv_net.h3
-rw-r--r--drivers/net/hyperv/netvsc_drv.c30
-rw-r--r--drivers/net/hyperv/rndis_filter.c21
-rw-r--r--include/linux/rndis.h1
4 files changed, 30 insertions, 25 deletions
diff --git a/drivers/net/hyperv/hyperv_net.h b/drivers/net/hyperv/hyperv_net.h
index 6cc37c15e0bf..24441ae832d1 100644
--- a/drivers/net/hyperv/hyperv_net.h
+++ b/drivers/net/hyperv/hyperv_net.h
@@ -170,6 +170,7 @@ struct rndis_device {
170 170
171 enum rndis_device_state state; 171 enum rndis_device_state state;
172 bool link_state; 172 bool link_state;
173 bool link_change;
173 atomic_t new_req_id; 174 atomic_t new_req_id;
174 175
175 spinlock_t request_lock; 176 spinlock_t request_lock;
@@ -185,7 +186,7 @@ int netvsc_device_remove(struct hv_device *device);
185int netvsc_send(struct hv_device *device, 186int netvsc_send(struct hv_device *device,
186 struct hv_netvsc_packet *packet); 187 struct hv_netvsc_packet *packet);
187void netvsc_linkstatus_callback(struct hv_device *device_obj, 188void netvsc_linkstatus_callback(struct hv_device *device_obj,
188 unsigned int status); 189 struct rndis_message *resp);
189int netvsc_recv_callback(struct hv_device *device_obj, 190int netvsc_recv_callback(struct hv_device *device_obj,
190 struct hv_netvsc_packet *packet, 191 struct hv_netvsc_packet *packet,
191 struct ndis_tcp_ip_checksum_info *csum_info); 192 struct ndis_tcp_ip_checksum_info *csum_info);
diff --git a/drivers/net/hyperv/netvsc_drv.c b/drivers/net/hyperv/netvsc_drv.c
index 4fd71b75e666..9b27ca8c1d39 100644
--- a/drivers/net/hyperv/netvsc_drv.c
+++ b/drivers/net/hyperv/netvsc_drv.c
@@ -579,8 +579,9 @@ drop:
579 * netvsc_linkstatus_callback - Link up/down notification 579 * netvsc_linkstatus_callback - Link up/down notification
580 */ 580 */
581void netvsc_linkstatus_callback(struct hv_device *device_obj, 581void netvsc_linkstatus_callback(struct hv_device *device_obj,
582 unsigned int status) 582 struct rndis_message *resp)
583{ 583{
584 struct rndis_indicate_status *indicate = &resp->msg.indicate_status;
584 struct net_device *net; 585 struct net_device *net;
585 struct net_device_context *ndev_ctx; 586 struct net_device_context *ndev_ctx;
586 struct netvsc_device *net_device; 587 struct netvsc_device *net_device;
@@ -589,7 +590,19 @@ void netvsc_linkstatus_callback(struct hv_device *device_obj,
589 net_device = hv_get_drvdata(device_obj); 590 net_device = hv_get_drvdata(device_obj);
590 rdev = net_device->extension; 591 rdev = net_device->extension;
591 592
592 rdev->link_state = status != 1; 593 switch (indicate->status) {
594 case RNDIS_STATUS_MEDIA_CONNECT:
595 rdev->link_state = false;
596 break;
597 case RNDIS_STATUS_MEDIA_DISCONNECT:
598 rdev->link_state = true;
599 break;
600 case RNDIS_STATUS_NETWORK_CHANGE:
601 rdev->link_change = true;
602 break;
603 default:
604 return;
605 }
593 606
594 net = net_device->ndev; 607 net = net_device->ndev;
595 608
@@ -597,7 +610,7 @@ void netvsc_linkstatus_callback(struct hv_device *device_obj,
597 return; 610 return;
598 611
599 ndev_ctx = netdev_priv(net); 612 ndev_ctx = netdev_priv(net);
600 if (status == 1) { 613 if (!rdev->link_state) {
601 schedule_delayed_work(&ndev_ctx->dwork, 0); 614 schedule_delayed_work(&ndev_ctx->dwork, 0);
602 schedule_delayed_work(&ndev_ctx->dwork, msecs_to_jiffies(20)); 615 schedule_delayed_work(&ndev_ctx->dwork, msecs_to_jiffies(20));
603 } else { 616 } else {
@@ -767,7 +780,9 @@ static void netvsc_link_change(struct work_struct *w)
767 struct net_device *net; 780 struct net_device *net;
768 struct netvsc_device *net_device; 781 struct netvsc_device *net_device;
769 struct rndis_device *rdev; 782 struct rndis_device *rdev;
770 bool notify; 783 bool notify, refresh = false;
784 char *argv[] = { "/etc/init.d/network", "restart", NULL };
785 char *envp[] = { "HOME=/", "PATH=/sbin:/usr/sbin:/bin:/usr/bin", NULL };
771 786
772 rtnl_lock(); 787 rtnl_lock();
773 788
@@ -782,10 +797,17 @@ static void netvsc_link_change(struct work_struct *w)
782 } else { 797 } else {
783 netif_carrier_on(net); 798 netif_carrier_on(net);
784 notify = true; 799 notify = true;
800 if (rdev->link_change) {
801 rdev->link_change = false;
802 refresh = true;
803 }
785 } 804 }
786 805
787 rtnl_unlock(); 806 rtnl_unlock();
788 807
808 if (refresh)
809 call_usermodehelper(argv[0], argv, envp, UMH_WAIT_EXEC);
810
789 if (notify) 811 if (notify)
790 netdev_notify_peers(net); 812 netdev_notify_peers(net);
791} 813}
diff --git a/drivers/net/hyperv/rndis_filter.c b/drivers/net/hyperv/rndis_filter.c
index 99c527adae5b..2b86f0b6f6d1 100644
--- a/drivers/net/hyperv/rndis_filter.c
+++ b/drivers/net/hyperv/rndis_filter.c
@@ -320,25 +320,6 @@ static void rndis_filter_receive_response(struct rndis_device *dev,
320 } 320 }
321} 321}
322 322
323static void rndis_filter_receive_indicate_status(struct rndis_device *dev,
324 struct rndis_message *resp)
325{
326 struct rndis_indicate_status *indicate =
327 &resp->msg.indicate_status;
328
329 if (indicate->status == RNDIS_STATUS_MEDIA_CONNECT) {
330 netvsc_linkstatus_callback(
331 dev->net_dev->dev, 1);
332 } else if (indicate->status == RNDIS_STATUS_MEDIA_DISCONNECT) {
333 netvsc_linkstatus_callback(
334 dev->net_dev->dev, 0);
335 } else {
336 /*
337 * TODO:
338 */
339 }
340}
341
342/* 323/*
343 * Get the Per-Packet-Info with the specified type 324 * Get the Per-Packet-Info with the specified type
344 * return NULL if not found. 325 * return NULL if not found.
@@ -464,7 +445,7 @@ int rndis_filter_receive(struct hv_device *dev,
464 445
465 case RNDIS_MSG_INDICATE: 446 case RNDIS_MSG_INDICATE:
466 /* notification msgs */ 447 /* notification msgs */
467 rndis_filter_receive_indicate_status(rndis_dev, rndis_msg); 448 netvsc_linkstatus_callback(dev, rndis_msg);
468 break; 449 break;
469 default: 450 default:
470 netdev_err(ndev, 451 netdev_err(ndev,
diff --git a/include/linux/rndis.h b/include/linux/rndis.h
index 0c8dc7195cdb..93c0a64aefa6 100644
--- a/include/linux/rndis.h
+++ b/include/linux/rndis.h
@@ -65,6 +65,7 @@
65#define RNDIS_STATUS_MEDIA_SPECIFIC_INDICATION 0x40010012 65#define RNDIS_STATUS_MEDIA_SPECIFIC_INDICATION 0x40010012
66#define RNDIS_STATUS_WW_INDICATION RDIA_SPECIFIC_INDICATION 66#define RNDIS_STATUS_WW_INDICATION RDIA_SPECIFIC_INDICATION
67#define RNDIS_STATUS_LINK_SPEED_CHANGE 0x40010013L 67#define RNDIS_STATUS_LINK_SPEED_CHANGE 0x40010013L
68#define RNDIS_STATUS_NETWORK_CHANGE 0x40010018
68 69
69#define RNDIS_STATUS_NOT_RESETTABLE 0x80010001 70#define RNDIS_STATUS_NOT_RESETTABLE 0x80010001
70#define RNDIS_STATUS_SOFT_ERRORS 0x80010003 71#define RNDIS_STATUS_SOFT_ERRORS 0x80010003