Commit d814b67e authored by David S. Miller's avatar David S. Miller

Merge branch 'hv_netvsc-Fix-send-indirection-table-offset'

Haiyang Zhang says:

====================
hv_netvsc: Fix send indirection table offset

Fix send indirection table offset issues related to guest and
host bugs.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 35fc59c9 171c1fd9
...@@ -609,7 +609,8 @@ struct nvsp_5_send_indirect_table { ...@@ -609,7 +609,8 @@ struct nvsp_5_send_indirect_table {
/* The number of entries in the send indirection table */ /* The number of entries in the send indirection table */
u32 count; u32 count;
/* The offset of the send indirection table from top of this struct. /* The offset of the send indirection table from the beginning of
* struct nvsp_message.
* The send indirection table tells which channel to put the send * The send indirection table tells which channel to put the send
* traffic on. Each entry is a channel number. * traffic on. Each entry is a channel number.
*/ */
......
...@@ -1178,20 +1178,39 @@ static int netvsc_receive(struct net_device *ndev, ...@@ -1178,20 +1178,39 @@ static int netvsc_receive(struct net_device *ndev,
} }
static void netvsc_send_table(struct net_device *ndev, static void netvsc_send_table(struct net_device *ndev,
const struct nvsp_message *nvmsg) struct netvsc_device *nvscdev,
const struct nvsp_message *nvmsg,
u32 msglen)
{ {
struct net_device_context *net_device_ctx = netdev_priv(ndev); struct net_device_context *net_device_ctx = netdev_priv(ndev);
u32 count, *tab; u32 count, offset, *tab;
int i; int i;
count = nvmsg->msg.v5_msg.send_table.count; count = nvmsg->msg.v5_msg.send_table.count;
offset = nvmsg->msg.v5_msg.send_table.offset;
if (count != VRSS_SEND_TAB_SIZE) { if (count != VRSS_SEND_TAB_SIZE) {
netdev_err(ndev, "Received wrong send-table size:%u\n", count); netdev_err(ndev, "Received wrong send-table size:%u\n", count);
return; return;
} }
tab = (u32 *)((unsigned long)&nvmsg->msg.v5_msg.send_table + /* If negotiated version <= NVSP_PROTOCOL_VERSION_6, the offset may be
nvmsg->msg.v5_msg.send_table.offset); * wrong due to a host bug. So fix the offset here.
*/
if (nvscdev->nvsp_version <= NVSP_PROTOCOL_VERSION_6 &&
msglen >= sizeof(struct nvsp_message_header) +
sizeof(union nvsp_6_message_uber) + count * sizeof(u32))
offset = sizeof(struct nvsp_message_header) +
sizeof(union nvsp_6_message_uber);
/* Boundary check for all versions */
if (offset > msglen - count * sizeof(u32)) {
netdev_err(ndev, "Received send-table offset too big:%u\n",
offset);
return;
}
tab = (void *)nvmsg + offset;
for (i = 0; i < count; i++) for (i = 0; i < count; i++)
net_device_ctx->tx_table[i] = tab[i]; net_device_ctx->tx_table[i] = tab[i];
...@@ -1210,11 +1229,13 @@ static void netvsc_send_vf(struct net_device *ndev, ...@@ -1210,11 +1229,13 @@ static void netvsc_send_vf(struct net_device *ndev,
} }
static void netvsc_receive_inband(struct net_device *ndev, static void netvsc_receive_inband(struct net_device *ndev,
const struct nvsp_message *nvmsg) struct netvsc_device *nvscdev,
const struct nvsp_message *nvmsg,
u32 msglen)
{ {
switch (nvmsg->hdr.msg_type) { switch (nvmsg->hdr.msg_type) {
case NVSP_MSG5_TYPE_SEND_INDIRECTION_TABLE: case NVSP_MSG5_TYPE_SEND_INDIRECTION_TABLE:
netvsc_send_table(ndev, nvmsg); netvsc_send_table(ndev, nvscdev, nvmsg, msglen);
break; break;
case NVSP_MSG4_TYPE_SEND_VF_ASSOCIATION: case NVSP_MSG4_TYPE_SEND_VF_ASSOCIATION:
...@@ -1232,6 +1253,7 @@ static int netvsc_process_raw_pkt(struct hv_device *device, ...@@ -1232,6 +1253,7 @@ static int netvsc_process_raw_pkt(struct hv_device *device,
{ {
struct vmbus_channel *channel = nvchan->channel; struct vmbus_channel *channel = nvchan->channel;
const struct nvsp_message *nvmsg = hv_pkt_data(desc); const struct nvsp_message *nvmsg = hv_pkt_data(desc);
u32 msglen = hv_pkt_datalen(desc);
trace_nvsp_recv(ndev, channel, nvmsg); trace_nvsp_recv(ndev, channel, nvmsg);
...@@ -1247,7 +1269,7 @@ static int netvsc_process_raw_pkt(struct hv_device *device, ...@@ -1247,7 +1269,7 @@ static int netvsc_process_raw_pkt(struct hv_device *device,
break; break;
case VM_PKT_DATA_INBAND: case VM_PKT_DATA_INBAND:
netvsc_receive_inband(ndev, nvmsg); netvsc_receive_inband(ndev, net_device, nvmsg, msglen);
break; break;
default: default:
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment