aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/hyperv
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/hyperv')
-rw-r--r--drivers/net/hyperv/hyperv_net.h1
-rw-r--r--drivers/net/hyperv/netvsc_drv.c30
-rw-r--r--drivers/net/hyperv/rndis_filter.c79
3 files changed, 109 insertions, 1 deletions
diff --git a/drivers/net/hyperv/hyperv_net.h b/drivers/net/hyperv/hyperv_net.h
index 2857ab078aa..95ceb359304 100644
--- a/drivers/net/hyperv/hyperv_net.h
+++ b/drivers/net/hyperv/hyperv_net.h
@@ -131,6 +131,7 @@ int rndis_filter_send(struct hv_device *dev,
131 struct hv_netvsc_packet *pkt); 131 struct hv_netvsc_packet *pkt);
132 132
133int rndis_filter_set_packet_filter(struct rndis_device *dev, u32 new_filter); 133int rndis_filter_set_packet_filter(struct rndis_device *dev, u32 new_filter);
134int rndis_filter_set_device_mac(struct hv_device *hdev, char *mac);
134 135
135 136
136#define NVSP_INVALID_PROTOCOL_VERSION ((u32)0xFFFFFFFF) 137#define NVSP_INVALID_PROTOCOL_VERSION ((u32)0xFFFFFFFF)
diff --git a/drivers/net/hyperv/netvsc_drv.c b/drivers/net/hyperv/netvsc_drv.c
index 8f8ed332042..8e23c084c4a 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)
341 return 0; 341 return 0;
342} 342}
343 343
344
345static int netvsc_set_mac_addr(struct net_device *ndev, void *p)
346{
347 struct net_device_context *ndevctx = netdev_priv(ndev);
348 struct hv_device *hdev = ndevctx->device_ctx;
349 struct sockaddr *addr = p;
350 char save_adr[14];
351 unsigned char save_aatype;
352 int err;
353
354 memcpy(save_adr, ndev->dev_addr, ETH_ALEN);
355 save_aatype = ndev->addr_assign_type;
356
357 err = eth_mac_addr(ndev, p);
358 if (err != 0)
359 return err;
360
361 err = rndis_filter_set_device_mac(hdev, addr->sa_data);
362 if (err != 0) {
363 /* roll back to saved MAC */
364 memcpy(ndev->dev_addr, save_adr, ETH_ALEN);
365 ndev->addr_assign_type = save_aatype;
366 }
367
368 return err;
369}
370
371
344static const struct ethtool_ops ethtool_ops = { 372static const struct ethtool_ops ethtool_ops = {
345 .get_drvinfo = netvsc_get_drvinfo, 373 .get_drvinfo = netvsc_get_drvinfo,
346 .get_link = ethtool_op_get_link, 374 .get_link = ethtool_op_get_link,
@@ -353,7 +381,7 @@ static const struct net_device_ops device_ops = {
353 .ndo_set_rx_mode = netvsc_set_multicast_list, 381 .ndo_set_rx_mode = netvsc_set_multicast_list,
354 .ndo_change_mtu = netvsc_change_mtu, 382 .ndo_change_mtu = netvsc_change_mtu,
355 .ndo_validate_addr = eth_validate_addr, 383 .ndo_validate_addr = eth_validate_addr,
356 .ndo_set_mac_address = eth_mac_addr, 384 .ndo_set_mac_address = netvsc_set_mac_addr,
357}; 385};
358 386
359/* 387/*
diff --git a/drivers/net/hyperv/rndis_filter.c b/drivers/net/hyperv/rndis_filter.c
index 981ebb11563..fbf53946820 100644
--- a/drivers/net/hyperv/rndis_filter.c
+++ b/drivers/net/hyperv/rndis_filter.c
@@ -27,6 +27,7 @@
27#include <linux/if_ether.h> 27#include <linux/if_ether.h>
28#include <linux/netdevice.h> 28#include <linux/netdevice.h>
29#include <linux/if_vlan.h> 29#include <linux/if_vlan.h>
30#include <linux/nls.h>
30 31
31#include "hyperv_net.h" 32#include "hyperv_net.h"
32 33
@@ -47,6 +48,7 @@ struct rndis_request {
47 struct hv_page_buffer buf; 48 struct hv_page_buffer buf;
48 /* FIXME: We assumed a fixed size request here. */ 49 /* FIXME: We assumed a fixed size request here. */
49 struct rndis_message request_msg; 50 struct rndis_message request_msg;
51 u8 ext[100];
50}; 52};
51 53
52static void rndis_filter_send_completion(void *ctx); 54static void rndis_filter_send_completion(void *ctx);
@@ -511,6 +513,83 @@ static int rndis_filter_query_device_mac(struct rndis_device *dev)
511 dev->hw_mac_adr, &size); 513 dev->hw_mac_adr, &size);
512} 514}
513 515
516#define NWADR_STR "NetworkAddress"
517#define NWADR_STRLEN 14
518
519int rndis_filter_set_device_mac(struct hv_device *hdev, char *mac)
520{
521 struct netvsc_device *nvdev = hv_get_drvdata(hdev);
522 struct rndis_device *rdev = nvdev->extension;
523 struct net_device *ndev = nvdev->ndev;
524 struct rndis_request *request;
525 struct rndis_set_request *set;
526 struct rndis_config_parameter_info *cpi;
527 wchar_t *cfg_nwadr, *cfg_mac;
528 struct rndis_set_complete *set_complete;
529 char macstr[2*ETH_ALEN+1];
530 u32 extlen = sizeof(struct rndis_config_parameter_info) +
531 2*NWADR_STRLEN + 4*ETH_ALEN;
532 int ret, t;
533
534 request = get_rndis_request(rdev, RNDIS_MSG_SET,
535 RNDIS_MESSAGE_SIZE(struct rndis_set_request) + extlen);
536 if (!request)
537 return -ENOMEM;
538
539 set = &request->request_msg.msg.set_req;
540 set->oid = RNDIS_OID_GEN_RNDIS_CONFIG_PARAMETER;
541 set->info_buflen = extlen;
542 set->info_buf_offset = sizeof(struct rndis_set_request);
543 set->dev_vc_handle = 0;
544
545 cpi = (struct rndis_config_parameter_info *)((ulong)set +
546 set->info_buf_offset);
547 cpi->parameter_name_offset =
548 sizeof(struct rndis_config_parameter_info);
549 /* Multiply by 2 because host needs 2 bytes (utf16) for each char */
550 cpi->parameter_name_length = 2*NWADR_STRLEN;
551 cpi->parameter_type = RNDIS_CONFIG_PARAM_TYPE_STRING;
552 cpi->parameter_value_offset =
553 cpi->parameter_name_offset + cpi->parameter_name_length;
554 /* Multiply by 4 because each MAC byte displayed as 2 utf16 chars */
555 cpi->parameter_value_length = 4*ETH_ALEN;
556
557 cfg_nwadr = (wchar_t *)((ulong)cpi + cpi->parameter_name_offset);
558 cfg_mac = (wchar_t *)((ulong)cpi + cpi->parameter_value_offset);
559 ret = utf8s_to_utf16s(NWADR_STR, NWADR_STRLEN, UTF16_HOST_ENDIAN,
560 cfg_nwadr, NWADR_STRLEN);
561 if (ret < 0)
562 goto cleanup;
563 snprintf(macstr, 2*ETH_ALEN+1, "%pm", mac);
564 ret = utf8s_to_utf16s(macstr, 2*ETH_ALEN, UTF16_HOST_ENDIAN,
565 cfg_mac, 2*ETH_ALEN);
566 if (ret < 0)
567 goto cleanup;
568
569 ret = rndis_filter_send_request(rdev, request);
570 if (ret != 0)
571 goto cleanup;
572
573 t = wait_for_completion_timeout(&request->wait_event, 5*HZ);
574 if (t == 0) {
575 netdev_err(ndev, "timeout before we got a set response...\n");
576 /*
577 * can't put_rndis_request, since we may still receive a
578 * send-completion.
579 */
580 return -EBUSY;
581 } else {
582 set_complete = &request->response_msg.msg.set_complete;
583 if (set_complete->status != RNDIS_STATUS_SUCCESS)
584 ret = -EINVAL;
585 }
586
587cleanup:
588 put_rndis_request(rdev, request);
589 return ret;
590}
591
592
514static int rndis_filter_query_device_link_status(struct rndis_device *dev) 593static int rndis_filter_query_device_link_status(struct rndis_device *dev)
515{ 594{
516 u32 size = sizeof(u32); 595 u32 size = sizeof(u32);