|
@@ -579,8 +579,9 @@ drop:
|
|
* netvsc_linkstatus_callback - Link up/down notification
|
|
* netvsc_linkstatus_callback - Link up/down notification
|
|
*/
|
|
*/
|
|
void netvsc_linkstatus_callback(struct hv_device *device_obj,
|
|
void netvsc_linkstatus_callback(struct hv_device *device_obj,
|
|
- unsigned int status)
|
|
|
|
|
|
+ struct rndis_message *resp)
|
|
{
|
|
{
|
|
|
|
+ struct rndis_indicate_status *indicate = &resp->msg.indicate_status;
|
|
struct net_device *net;
|
|
struct net_device *net;
|
|
struct net_device_context *ndev_ctx;
|
|
struct net_device_context *ndev_ctx;
|
|
struct netvsc_device *net_device;
|
|
struct netvsc_device *net_device;
|
|
@@ -589,7 +590,19 @@ void netvsc_linkstatus_callback(struct hv_device *device_obj,
|
|
net_device = hv_get_drvdata(device_obj);
|
|
net_device = hv_get_drvdata(device_obj);
|
|
rdev = net_device->extension;
|
|
rdev = net_device->extension;
|
|
|
|
|
|
- rdev->link_state = status != 1;
|
|
|
|
|
|
+ switch (indicate->status) {
|
|
|
|
+ case RNDIS_STATUS_MEDIA_CONNECT:
|
|
|
|
+ rdev->link_state = false;
|
|
|
|
+ break;
|
|
|
|
+ case RNDIS_STATUS_MEDIA_DISCONNECT:
|
|
|
|
+ rdev->link_state = true;
|
|
|
|
+ break;
|
|
|
|
+ case RNDIS_STATUS_NETWORK_CHANGE:
|
|
|
|
+ rdev->link_change = true;
|
|
|
|
+ break;
|
|
|
|
+ default:
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
|
|
net = net_device->ndev;
|
|
net = net_device->ndev;
|
|
|
|
|
|
@@ -597,7 +610,7 @@ void netvsc_linkstatus_callback(struct hv_device *device_obj,
|
|
return;
|
|
return;
|
|
|
|
|
|
ndev_ctx = netdev_priv(net);
|
|
ndev_ctx = netdev_priv(net);
|
|
- if (status == 1) {
|
|
|
|
|
|
+ if (!rdev->link_state) {
|
|
schedule_delayed_work(&ndev_ctx->dwork, 0);
|
|
schedule_delayed_work(&ndev_ctx->dwork, 0);
|
|
schedule_delayed_work(&ndev_ctx->dwork, msecs_to_jiffies(20));
|
|
schedule_delayed_work(&ndev_ctx->dwork, msecs_to_jiffies(20));
|
|
} else {
|
|
} else {
|
|
@@ -767,7 +780,9 @@ static void netvsc_link_change(struct work_struct *w)
|
|
struct net_device *net;
|
|
struct net_device *net;
|
|
struct netvsc_device *net_device;
|
|
struct netvsc_device *net_device;
|
|
struct rndis_device *rdev;
|
|
struct rndis_device *rdev;
|
|
- bool notify;
|
|
|
|
|
|
+ bool notify, refresh = false;
|
|
|
|
+ char *argv[] = { "/etc/init.d/network", "restart", NULL };
|
|
|
|
+ char *envp[] = { "HOME=/", "PATH=/sbin:/usr/sbin:/bin:/usr/bin", NULL };
|
|
|
|
|
|
rtnl_lock();
|
|
rtnl_lock();
|
|
|
|
|
|
@@ -782,10 +797,17 @@ static void netvsc_link_change(struct work_struct *w)
|
|
} else {
|
|
} else {
|
|
netif_carrier_on(net);
|
|
netif_carrier_on(net);
|
|
notify = true;
|
|
notify = true;
|
|
|
|
+ if (rdev->link_change) {
|
|
|
|
+ rdev->link_change = false;
|
|
|
|
+ refresh = true;
|
|
|
|
+ }
|
|
}
|
|
}
|
|
|
|
|
|
rtnl_unlock();
|
|
rtnl_unlock();
|
|
|
|
|
|
|
|
+ if (refresh)
|
|
|
|
+ call_usermodehelper(argv[0], argv, envp, UMH_WAIT_EXEC);
|
|
|
|
+
|
|
if (notify)
|
|
if (notify)
|
|
netdev_notify_peers(net);
|
|
netdev_notify_peers(net);
|
|
}
|
|
}
|