Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 315384
b: refs/heads/master
c: 1ce09e8
h: refs/heads/master
v: v3
  • Loading branch information
Haiyang Zhang authored and David S. Miller committed Jul 17, 2012
1 parent da8fc19 commit 3bc889b
Show file tree
Hide file tree
Showing 4 changed files with 110 additions and 2 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 5e96855fc505082389813afcf796d4c46301d4fe
refs/heads/master: 1ce09e899d2864b4c8ed8f777c396bcb953aa3c9
1 change: 1 addition & 0 deletions trunk/drivers/net/hyperv/hyperv_net.h
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,7 @@ int rndis_filter_send(struct hv_device *dev,
struct hv_netvsc_packet *pkt);

int rndis_filter_set_packet_filter(struct rndis_device *dev, u32 new_filter);
int rndis_filter_set_device_mac(struct hv_device *hdev, char *mac);


#define NVSP_INVALID_PROTOCOL_VERSION ((u32)0xFFFFFFFF)
Expand Down
30 changes: 29 additions & 1 deletion trunk/drivers/net/hyperv/netvsc_drv.c
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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,
};

/*
Expand Down
79 changes: 79 additions & 0 deletions trunk/drivers/net/hyperv/rndis_filter.c
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
#include <linux/if_ether.h>
#include <linux/netdevice.h>
#include <linux/if_vlan.h>
#include <linux/nls.h>

#include "hyperv_net.h"

Expand All @@ -47,6 +48,7 @@ struct rndis_request {
struct hv_page_buffer buf;
/* FIXME: We assumed a fixed size request here. */
struct rndis_message request_msg;
u8 ext[100];
};

static void rndis_filter_send_completion(void *ctx);
Expand Down Expand Up @@ -511,6 +513,83 @@ static int rndis_filter_query_device_mac(struct rndis_device *dev)
dev->hw_mac_adr, &size);
}

#define NWADR_STR "NetworkAddress"
#define NWADR_STRLEN 14

int rndis_filter_set_device_mac(struct hv_device *hdev, char *mac)
{
struct netvsc_device *nvdev = hv_get_drvdata(hdev);
struct rndis_device *rdev = nvdev->extension;
struct net_device *ndev = nvdev->ndev;
struct rndis_request *request;
struct rndis_set_request *set;
struct rndis_config_parameter_info *cpi;
wchar_t *cfg_nwadr, *cfg_mac;
struct rndis_set_complete *set_complete;
char macstr[2*ETH_ALEN+1];
u32 extlen = sizeof(struct rndis_config_parameter_info) +
2*NWADR_STRLEN + 4*ETH_ALEN;
int ret, t;

request = get_rndis_request(rdev, RNDIS_MSG_SET,
RNDIS_MESSAGE_SIZE(struct rndis_set_request) + extlen);
if (!request)
return -ENOMEM;

set = &request->request_msg.msg.set_req;
set->oid = RNDIS_OID_GEN_RNDIS_CONFIG_PARAMETER;
set->info_buflen = extlen;
set->info_buf_offset = sizeof(struct rndis_set_request);
set->dev_vc_handle = 0;

cpi = (struct rndis_config_parameter_info *)((ulong)set +
set->info_buf_offset);
cpi->parameter_name_offset =
sizeof(struct rndis_config_parameter_info);
/* Multiply by 2 because host needs 2 bytes (utf16) for each char */
cpi->parameter_name_length = 2*NWADR_STRLEN;
cpi->parameter_type = RNDIS_CONFIG_PARAM_TYPE_STRING;
cpi->parameter_value_offset =
cpi->parameter_name_offset + cpi->parameter_name_length;
/* Multiply by 4 because each MAC byte displayed as 2 utf16 chars */
cpi->parameter_value_length = 4*ETH_ALEN;

cfg_nwadr = (wchar_t *)((ulong)cpi + cpi->parameter_name_offset);
cfg_mac = (wchar_t *)((ulong)cpi + cpi->parameter_value_offset);
ret = utf8s_to_utf16s(NWADR_STR, NWADR_STRLEN, UTF16_HOST_ENDIAN,
cfg_nwadr, NWADR_STRLEN);
if (ret < 0)
goto cleanup;
snprintf(macstr, 2*ETH_ALEN+1, "%pm", mac);
ret = utf8s_to_utf16s(macstr, 2*ETH_ALEN, UTF16_HOST_ENDIAN,
cfg_mac, 2*ETH_ALEN);
if (ret < 0)
goto cleanup;

ret = rndis_filter_send_request(rdev, request);
if (ret != 0)
goto cleanup;

t = wait_for_completion_timeout(&request->wait_event, 5*HZ);
if (t == 0) {
netdev_err(ndev, "timeout before we got a set response...\n");
/*
* can't put_rndis_request, since we may still receive a
* send-completion.
*/
return -EBUSY;
} else {
set_complete = &request->response_msg.msg.set_complete;
if (set_complete->status != RNDIS_STATUS_SUCCESS)
ret = -EINVAL;
}

cleanup:
put_rndis_request(rdev, request);
return ret;
}


static int rndis_filter_query_device_link_status(struct rndis_device *dev)
{
u32 size = sizeof(u32);
Expand Down

0 comments on commit 3bc889b

Please sign in to comment.