summaryrefslogtreecommitdiffstats
path: root/drivers/net/hyperv/netvsc_drv.c
diff options
context:
space:
mode:
authorHaiyang Zhang2012-07-10 09:19:22 +0200
committerDavid S. Miller2012-07-17 07:54:24 +0200
commit1ce09e899d2864b4c8ed8f777c396bcb953aa3c9 (patch)
tree953c896879802b24e3596a51b403ec03d3677ccd /drivers/net/hyperv/netvsc_drv.c
parent6lowpan: Change byte order when storing/accessing to len field (diff)
downloadkernel-qcow2-linux-1ce09e899d2864b4c8ed8f777c396bcb953aa3c9.tar.gz
kernel-qcow2-linux-1ce09e899d2864b4c8ed8f777c396bcb953aa3c9.tar.xz
kernel-qcow2-linux-1ce09e899d2864b4c8ed8f777c396bcb953aa3c9.zip
hyperv: Add support for setting MAC from within guests
This adds support for setting synthetic NIC MAC address from within Linux guests. Before using this feature, the option "spoofing of MAC address" should be enabled at the Hyper-V manager / Settings of the synthetic NIC. Thanks to Kin Cho <kcho@infoblox.com> for the initial implementation and tests. And, thanks to Long Li <longli@microsoft.com> for the debugging works. Reported-and-tested-by: Kin Cho <kcho@infoblox.com> Reported-by: Long Li <longli@microsoft.com> 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>
Diffstat (limited to 'drivers/net/hyperv/netvsc_drv.c')
-rw-r--r--drivers/net/hyperv/netvsc_drv.c30
1 files changed, 29 insertions, 1 deletions
diff --git a/drivers/net/hyperv/netvsc_drv.c b/drivers/net/hyperv/netvsc_drv.c
index 8f8ed3320425..8e23c084c4a7 100644
--- a/drivers/net/hyperv/netvsc_drv.c
+++ b/drivers/net/hyperv/netvsc_drv.c
@@ -341,6 +341,34 @@ static int netvsc_change_mtu(struct net_device *ndev, int mtu)
return 0;
}
+
+static int netvsc_set_mac_addr(struct net_device *ndev, void *p)
+{
+ struct net_device_context *ndevctx = netdev_priv(ndev);
+ struct hv_device *hdev = ndevctx->device_ctx;
+ struct sockaddr *addr = p;
+ char save_adr[14];
+ unsigned char save_aatype;
+ int err;
+
+ memcpy(save_adr, ndev->dev_addr, ETH_ALEN);
+ save_aatype = ndev->addr_assign_type;
+
+ err = eth_mac_addr(ndev, p);
+ if (err != 0)
+ return err;
+
+ err = rndis_filter_set_device_mac(hdev, addr->sa_data);
+ if (err != 0) {
+ /* roll back to saved MAC */
+ memcpy(ndev->dev_addr, save_adr, ETH_ALEN);
+ ndev->addr_assign_type = save_aatype;
+ }
+
+ return err;
+}
+
+
static const struct ethtool_ops ethtool_ops = {
.get_drvinfo = netvsc_get_drvinfo,
.get_link = ethtool_op_get_link,
@@ -353,7 +381,7 @@ static const struct net_device_ops device_ops = {
.ndo_set_rx_mode = netvsc_set_multicast_list,
.ndo_change_mtu = netvsc_change_mtu,
.ndo_validate_addr = eth_validate_addr,
- .ndo_set_mac_address = eth_mac_addr,
+ .ndo_set_mac_address = netvsc_set_mac_addr,
};
/*