diff options
author | Haiyang Zhang <haiyangz@microsoft.com> | 2014-06-19 21:34:36 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2014-06-20 00:17:37 -0400 |
commit | 3a494e710367c0a233d86bcde9853781859fc008 (patch) | |
tree | d79694a284627d3015a4b8975dd2d6aa7e434e04 | |
parent | e0f802fbcaa3bffe4728e37a8fa1279b5d554173 (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.h | 3 | ||||
-rw-r--r-- | drivers/net/hyperv/netvsc_drv.c | 30 | ||||
-rw-r--r-- | drivers/net/hyperv/rndis_filter.c | 21 | ||||
-rw-r--r-- | include/linux/rndis.h | 1 |
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); | |||
185 | int netvsc_send(struct hv_device *device, | 186 | int netvsc_send(struct hv_device *device, |
186 | struct hv_netvsc_packet *packet); | 187 | struct hv_netvsc_packet *packet); |
187 | void netvsc_linkstatus_callback(struct hv_device *device_obj, | 188 | void netvsc_linkstatus_callback(struct hv_device *device_obj, |
188 | unsigned int status); | 189 | struct rndis_message *resp); |
189 | int netvsc_recv_callback(struct hv_device *device_obj, | 190 | int 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 | */ |
581 | void netvsc_linkstatus_callback(struct hv_device *device_obj, | 581 | void 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 | ||
323 | static 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 |