blob: 99c527adae5bf1ee154b2a02eb0f93a6df32e333 [file] [log] [blame]
Hank Janssenfceaf242009-07-13 15:34:54 -07001/*
Hank Janssenfceaf242009-07-13 15:34:54 -07002 * Copyright (c) 2009, Microsoft Corporation.
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms and conditions of the GNU General Public License,
6 * version 2, as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
11 * more details.
12 *
13 * You should have received a copy of the GNU General Public License along with
Jeff Kirsheradf8d3f2013-12-06 06:28:47 -080014 * this program; if not, see <http://www.gnu.org/licenses/>.
Hank Janssenfceaf242009-07-13 15:34:54 -070015 *
16 * Authors:
17 * Haiyang Zhang <haiyangz@microsoft.com>
18 * Hank Janssen <hjanssen@microsoft.com>
Hank Janssenfceaf242009-07-13 15:34:54 -070019 */
Greg Kroah-Hartman5654e932009-07-14 15:08:20 -070020#include <linux/kernel.h>
K. Y. Srinivasan0c3b7b22011-02-11 09:59:43 -080021#include <linux/sched.h>
22#include <linux/wait.h>
Bill Pemberton45da89e2009-07-29 17:00:15 -040023#include <linux/highmem.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090024#include <linux/slab.h>
Greg Kroah-Hartman0120ee02009-09-02 09:17:52 -070025#include <linux/io.h>
Stephen Hemminger9f8bd8b2010-05-04 09:58:54 -070026#include <linux/if_ether.h>
Hank Jansseneb335bc2011-03-29 13:58:48 -070027#include <linux/netdevice.h>
Haiyang Zhang1f5f3a72012-03-12 10:20:50 +000028#include <linux/if_vlan.h>
Haiyang Zhang1ce09e82012-07-10 07:19:22 +000029#include <linux/nls.h>
K. Y. Srinivasan3f335ea2011-05-12 19:34:15 -070030
K. Y. Srinivasan5ca72522011-05-12 19:34:37 -070031#include "hyperv_net.h"
Hank Janssenfceaf242009-07-13 15:34:54 -070032
Hank Janssenfceaf242009-07-13 15:34:54 -070033
Haiyang Zhang5b54dac2014-04-21 10:20:28 -070034#define RNDIS_EXT_LEN PAGE_SIZE
Greg Kroah-Hartmane681b952009-08-28 16:26:27 -070035struct rndis_request {
Haiyang Zhangc2a4efd2010-12-10 12:03:56 -080036 struct list_head list_ent;
K. Y. Srinivasan98d79692011-05-10 07:55:42 -070037 struct completion wait_event;
Hank Janssenfceaf242009-07-13 15:34:54 -070038
Haiyang Zhangc2a4efd2010-12-10 12:03:56 -080039 struct rndis_message response_msg;
Haiyang Zhanga3a6cab2012-10-02 05:30:24 +000040 /*
41 * The buffer for extended info after the RNDIS response message. It's
42 * referenced based on the data offset in the RNDIS message. Its size
43 * is enough for current needs, and should be sufficient for the near
44 * future.
45 */
46 u8 response_ext[RNDIS_EXT_LEN];
Hank Janssenfceaf242009-07-13 15:34:54 -070047
Bill Pemberton454f18a2009-07-27 16:47:24 -040048 /* Simplify allocation by having a netvsc packet inline */
Haiyang Zhangc2a4efd2010-12-10 12:03:56 -080049 struct hv_netvsc_packet pkt;
Haiyang Zhang99e3fcf2012-10-02 05:30:21 +000050 /* Set 2 pages for rndis requests crossing page boundary */
51 struct hv_page_buffer buf[2];
Haiyang Zhang0f489172012-08-09 08:04:18 +000052
Haiyang Zhangc2a4efd2010-12-10 12:03:56 -080053 struct rndis_message request_msg;
Haiyang Zhang0f489172012-08-09 08:04:18 +000054 /*
Haiyang Zhanga3a6cab2012-10-02 05:30:24 +000055 * The buffer for the extended info after the RNDIS request message.
56 * It is referenced and sized in a similar way as response_ext.
Haiyang Zhang0f489172012-08-09 08:04:18 +000057 */
Haiyang Zhanga3a6cab2012-10-02 05:30:24 +000058 u8 request_ext[RNDIS_EXT_LEN];
Greg Kroah-Hartmane681b952009-08-28 16:26:27 -070059};
Hank Janssenfceaf242009-07-13 15:34:54 -070060
Haiyang Zhang9c26aa02010-12-10 12:03:57 -080061static struct rndis_device *get_rndis_device(void)
Hank Janssenfceaf242009-07-13 15:34:54 -070062{
Greg Kroah-Hartmane681b952009-08-28 16:26:27 -070063 struct rndis_device *device;
Hank Janssenfceaf242009-07-13 15:34:54 -070064
Greg Kroah-Hartmane681b952009-08-28 16:26:27 -070065 device = kzalloc(sizeof(struct rndis_device), GFP_KERNEL);
Hank Janssenfceaf242009-07-13 15:34:54 -070066 if (!device)
Hank Janssenfceaf242009-07-13 15:34:54 -070067 return NULL;
Hank Janssenfceaf242009-07-13 15:34:54 -070068
Greg Kroah-Hartman880fb892009-07-15 14:55:29 -070069 spin_lock_init(&device->request_lock);
Hank Janssenfceaf242009-07-13 15:34:54 -070070
Haiyang Zhangc2a4efd2010-12-10 12:03:56 -080071 INIT_LIST_HEAD(&device->req_list);
Hank Janssenfceaf242009-07-13 15:34:54 -070072
Haiyang Zhangc2a4efd2010-12-10 12:03:56 -080073 device->state = RNDIS_DEV_UNINITIALIZED;
Hank Janssenfceaf242009-07-13 15:34:54 -070074
75 return device;
76}
77
Haiyang Zhang9c26aa02010-12-10 12:03:57 -080078static struct rndis_request *get_rndis_request(struct rndis_device *dev,
Haiyang Zhangc2a4efd2010-12-10 12:03:56 -080079 u32 msg_type,
80 u32 msg_len)
Hank Janssenfceaf242009-07-13 15:34:54 -070081{
Greg Kroah-Hartmane681b952009-08-28 16:26:27 -070082 struct rndis_request *request;
Haiyang Zhangc2a4efd2010-12-10 12:03:56 -080083 struct rndis_message *rndis_msg;
Greg Kroah-Hartman9f33d052009-08-19 16:26:24 -070084 struct rndis_set_request *set;
Greg Kroah-Hartman880fb892009-07-15 14:55:29 -070085 unsigned long flags;
Hank Janssenfceaf242009-07-13 15:34:54 -070086
Greg Kroah-Hartmane681b952009-08-28 16:26:27 -070087 request = kzalloc(sizeof(struct rndis_request), GFP_KERNEL);
Hank Janssenfceaf242009-07-13 15:34:54 -070088 if (!request)
Hank Janssenfceaf242009-07-13 15:34:54 -070089 return NULL;
Hank Janssenfceaf242009-07-13 15:34:54 -070090
K. Y. Srinivasan98d79692011-05-10 07:55:42 -070091 init_completion(&request->wait_event);
Hank Janssenfceaf242009-07-13 15:34:54 -070092
Haiyang Zhangc2a4efd2010-12-10 12:03:56 -080093 rndis_msg = &request->request_msg;
Haiyang Zhanga388eb12010-12-10 12:04:00 -080094 rndis_msg->ndis_msg_type = msg_type;
95 rndis_msg->msg_len = msg_len;
Hank Janssenfceaf242009-07-13 15:34:54 -070096
Haiyang Zhang5b54dac2014-04-21 10:20:28 -070097 request->pkt.q_idx = 0;
98
Greg Kroah-Hartman0120ee02009-09-02 09:17:52 -070099 /*
100 * Set the request id. This field is always after the rndis header for
101 * request/response packet types so we just used the SetRequest as a
102 * template
103 */
Haiyang Zhanga388eb12010-12-10 12:04:00 -0800104 set = &rndis_msg->msg.set_req;
105 set->req_id = atomic_inc_return(&dev->new_req_id);
Hank Janssenfceaf242009-07-13 15:34:54 -0700106
Bill Pemberton454f18a2009-07-27 16:47:24 -0400107 /* Add to the request list */
Haiyang Zhangc2a4efd2010-12-10 12:03:56 -0800108 spin_lock_irqsave(&dev->request_lock, flags);
109 list_add_tail(&request->list_ent, &dev->req_list);
110 spin_unlock_irqrestore(&dev->request_lock, flags);
Hank Janssenfceaf242009-07-13 15:34:54 -0700111
112 return request;
113}
114
Haiyang Zhang9c26aa02010-12-10 12:03:57 -0800115static void put_rndis_request(struct rndis_device *dev,
Haiyang Zhangc2a4efd2010-12-10 12:03:56 -0800116 struct rndis_request *req)
Hank Janssenfceaf242009-07-13 15:34:54 -0700117{
Greg Kroah-Hartman880fb892009-07-15 14:55:29 -0700118 unsigned long flags;
119
Haiyang Zhangc2a4efd2010-12-10 12:03:56 -0800120 spin_lock_irqsave(&dev->request_lock, flags);
121 list_del(&req->list_ent);
122 spin_unlock_irqrestore(&dev->request_lock, flags);
Hank Janssenfceaf242009-07-13 15:34:54 -0700123
Haiyang Zhangc2a4efd2010-12-10 12:03:56 -0800124 kfree(req);
Hank Janssenfceaf242009-07-13 15:34:54 -0700125}
126
Haiyang Zhang729a2842011-05-27 06:21:54 -0700127static void dump_rndis_message(struct hv_device *hv_dev,
128 struct rndis_message *rndis_msg)
Hank Janssenfceaf242009-07-13 15:34:54 -0700129{
K. Y. Srinivasan2ddd5e52011-09-13 10:59:49 -0700130 struct net_device *netdev;
131 struct netvsc_device *net_device;
132
133 net_device = hv_get_drvdata(hv_dev);
134 netdev = net_device->ndev;
Haiyang Zhang729a2842011-05-27 06:21:54 -0700135
Haiyang Zhanga388eb12010-12-10 12:04:00 -0800136 switch (rndis_msg->ndis_msg_type) {
Linus Walleij51491162012-05-11 22:17:07 +0000137 case RNDIS_MSG_PACKET:
138 netdev_dbg(netdev, "RNDIS_MSG_PACKET (len %u, "
Greg Kroah-Hartman0120ee02009-09-02 09:17:52 -0700139 "data offset %u data len %u, # oob %u, "
140 "oob offset %u, oob len %u, pkt offset %u, "
Haiyang Zhang729a2842011-05-27 06:21:54 -0700141 "pkt len %u\n",
Haiyang Zhanga388eb12010-12-10 12:04:00 -0800142 rndis_msg->msg_len,
143 rndis_msg->msg.pkt.data_offset,
144 rndis_msg->msg.pkt.data_len,
145 rndis_msg->msg.pkt.num_oob_data_elements,
146 rndis_msg->msg.pkt.oob_data_offset,
147 rndis_msg->msg.pkt.oob_data_len,
148 rndis_msg->msg.pkt.per_pkt_info_offset,
149 rndis_msg->msg.pkt.per_pkt_info_len);
Hank Janssenfceaf242009-07-13 15:34:54 -0700150 break;
151
Linus Walleij51491162012-05-11 22:17:07 +0000152 case RNDIS_MSG_INIT_C:
153 netdev_dbg(netdev, "RNDIS_MSG_INIT_C "
Greg Kroah-Hartman0120ee02009-09-02 09:17:52 -0700154 "(len %u, id 0x%x, status 0x%x, major %d, minor %d, "
155 "device flags %d, max xfer size 0x%x, max pkts %u, "
Haiyang Zhang729a2842011-05-27 06:21:54 -0700156 "pkt aligned %u)\n",
Haiyang Zhanga388eb12010-12-10 12:04:00 -0800157 rndis_msg->msg_len,
158 rndis_msg->msg.init_complete.req_id,
159 rndis_msg->msg.init_complete.status,
160 rndis_msg->msg.init_complete.major_ver,
161 rndis_msg->msg.init_complete.minor_ver,
162 rndis_msg->msg.init_complete.dev_flags,
163 rndis_msg->msg.init_complete.max_xfer_size,
164 rndis_msg->msg.init_complete.
165 max_pkt_per_msg,
166 rndis_msg->msg.init_complete.
167 pkt_alignment_factor);
Hank Janssenfceaf242009-07-13 15:34:54 -0700168 break;
169
Linus Walleij51491162012-05-11 22:17:07 +0000170 case RNDIS_MSG_QUERY_C:
171 netdev_dbg(netdev, "RNDIS_MSG_QUERY_C "
Greg Kroah-Hartman0120ee02009-09-02 09:17:52 -0700172 "(len %u, id 0x%x, status 0x%x, buf len %u, "
Haiyang Zhang729a2842011-05-27 06:21:54 -0700173 "buf offset %u)\n",
Haiyang Zhanga388eb12010-12-10 12:04:00 -0800174 rndis_msg->msg_len,
175 rndis_msg->msg.query_complete.req_id,
176 rndis_msg->msg.query_complete.status,
177 rndis_msg->msg.query_complete.
178 info_buflen,
179 rndis_msg->msg.query_complete.
180 info_buf_offset);
Hank Janssenfceaf242009-07-13 15:34:54 -0700181 break;
182
Linus Walleij51491162012-05-11 22:17:07 +0000183 case RNDIS_MSG_SET_C:
Haiyang Zhang729a2842011-05-27 06:21:54 -0700184 netdev_dbg(netdev,
Linus Walleij51491162012-05-11 22:17:07 +0000185 "RNDIS_MSG_SET_C (len %u, id 0x%x, status 0x%x)\n",
Haiyang Zhanga388eb12010-12-10 12:04:00 -0800186 rndis_msg->msg_len,
187 rndis_msg->msg.set_complete.req_id,
188 rndis_msg->msg.set_complete.status);
Hank Janssenfceaf242009-07-13 15:34:54 -0700189 break;
190
Linus Walleij51491162012-05-11 22:17:07 +0000191 case RNDIS_MSG_INDICATE:
192 netdev_dbg(netdev, "RNDIS_MSG_INDICATE "
Haiyang Zhang729a2842011-05-27 06:21:54 -0700193 "(len %u, status 0x%x, buf len %u, buf offset %u)\n",
Haiyang Zhanga388eb12010-12-10 12:04:00 -0800194 rndis_msg->msg_len,
195 rndis_msg->msg.indicate_status.status,
196 rndis_msg->msg.indicate_status.status_buflen,
197 rndis_msg->msg.indicate_status.status_buf_offset);
Hank Janssenfceaf242009-07-13 15:34:54 -0700198 break;
199
200 default:
Haiyang Zhang729a2842011-05-27 06:21:54 -0700201 netdev_dbg(netdev, "0x%x (len %u)\n",
Haiyang Zhanga388eb12010-12-10 12:04:00 -0800202 rndis_msg->ndis_msg_type,
203 rndis_msg->msg_len);
Hank Janssenfceaf242009-07-13 15:34:54 -0700204 break;
205 }
206}
207
Haiyang Zhang9c26aa02010-12-10 12:03:57 -0800208static int rndis_filter_send_request(struct rndis_device *dev,
Haiyang Zhangc2a4efd2010-12-10 12:03:56 -0800209 struct rndis_request *req)
Hank Janssenfceaf242009-07-13 15:34:54 -0700210{
Greg Kroah-Hartman0120ee02009-09-02 09:17:52 -0700211 int ret;
Nicolas Palix4193d4f2009-07-29 14:10:10 +0200212 struct hv_netvsc_packet *packet;
Hank Janssenfceaf242009-07-13 15:34:54 -0700213
Bill Pemberton454f18a2009-07-27 16:47:24 -0400214 /* Setup the packet to send it */
Haiyang Zhangc2a4efd2010-12-10 12:03:56 -0800215 packet = &req->pkt;
Hank Janssenfceaf242009-07-13 15:34:54 -0700216
Haiyang Zhang72a2f5b2010-12-10 12:03:58 -0800217 packet->is_data_pkt = false;
Haiyang Zhanga388eb12010-12-10 12:04:00 -0800218 packet->total_data_buflen = req->request_msg.msg_len;
Haiyang Zhang72a2f5b2010-12-10 12:03:58 -0800219 packet->page_buf_cnt = 1;
Hank Janssenfceaf242009-07-13 15:34:54 -0700220
Haiyang Zhangca623ad2011-01-26 12:12:11 -0800221 packet->page_buf[0].pfn = virt_to_phys(&req->request_msg) >>
Greg Kroah-Hartman0120ee02009-09-02 09:17:52 -0700222 PAGE_SHIFT;
Haiyang Zhangca623ad2011-01-26 12:12:11 -0800223 packet->page_buf[0].len = req->request_msg.msg_len;
224 packet->page_buf[0].offset =
Haiyang Zhangc2a4efd2010-12-10 12:03:56 -0800225 (unsigned long)&req->request_msg & (PAGE_SIZE - 1);
Hank Janssenfceaf242009-07-13 15:34:54 -0700226
Haiyang Zhang99e3fcf2012-10-02 05:30:21 +0000227 /* Add one page_buf when request_msg crossing page boundary */
228 if (packet->page_buf[0].offset + packet->page_buf[0].len > PAGE_SIZE) {
229 packet->page_buf_cnt++;
230 packet->page_buf[0].len = PAGE_SIZE -
231 packet->page_buf[0].offset;
232 packet->page_buf[1].pfn = virt_to_phys((void *)&req->request_msg
233 + packet->page_buf[0].len) >> PAGE_SHIFT;
234 packet->page_buf[1].offset = 0;
235 packet->page_buf[1].len = req->request_msg.msg_len -
236 packet->page_buf[0].len;
237 }
238
Haiyang Zhang893f6622014-04-21 14:54:44 -0700239 packet->send_completion = NULL;
Hank Janssenfceaf242009-07-13 15:34:54 -0700240
K. Y. Srinivasan0ec6ff42011-05-12 19:34:55 -0700241 ret = netvsc_send(dev->net_dev->dev, packet);
Hank Janssenfceaf242009-07-13 15:34:54 -0700242 return ret;
243}
244
Haiyang Zhang1b07da52014-03-04 14:11:06 -0800245static void rndis_set_link_state(struct rndis_device *rdev,
246 struct rndis_request *request)
247{
248 u32 link_status;
249 struct rndis_query_complete *query_complete;
250
251 query_complete = &request->response_msg.msg.query_complete;
252
253 if (query_complete->status == RNDIS_STATUS_SUCCESS &&
254 query_complete->info_buflen == sizeof(u32)) {
255 memcpy(&link_status, (void *)((unsigned long)query_complete +
256 query_complete->info_buf_offset), sizeof(u32));
257 rdev->link_state = link_status != 0;
258 }
259}
260
Haiyang Zhang9c26aa02010-12-10 12:03:57 -0800261static void rndis_filter_receive_response(struct rndis_device *dev,
Haiyang Zhangc2a4efd2010-12-10 12:03:56 -0800262 struct rndis_message *resp)
Hank Janssenfceaf242009-07-13 15:34:54 -0700263{
Greg Kroah-Hartmane681b952009-08-28 16:26:27 -0700264 struct rndis_request *request = NULL;
Greg Kroah-Hartman0e727612009-07-15 12:46:44 -0700265 bool found = false;
Greg Kroah-Hartman880fb892009-07-15 14:55:29 -0700266 unsigned long flags;
K. Y. Srinivasan2ddd5e52011-09-13 10:59:49 -0700267 struct net_device *ndev;
268
269 ndev = dev->net_dev->ndev;
Hank Janssenfceaf242009-07-13 15:34:54 -0700270
Haiyang Zhangc2a4efd2010-12-10 12:03:56 -0800271 spin_lock_irqsave(&dev->request_lock, flags);
272 list_for_each_entry(request, &dev->req_list, list_ent) {
Greg Kroah-Hartman0120ee02009-09-02 09:17:52 -0700273 /*
274 * All request/response message contains RequestId as the 1st
275 * field
276 */
Haiyang Zhanga388eb12010-12-10 12:04:00 -0800277 if (request->request_msg.msg.init_req.req_id
278 == resp->msg.init_complete.req_id) {
Greg Kroah-Hartman0e727612009-07-15 12:46:44 -0700279 found = true;
Hank Janssenfceaf242009-07-13 15:34:54 -0700280 break;
281 }
282 }
Haiyang Zhangc2a4efd2010-12-10 12:03:56 -0800283 spin_unlock_irqrestore(&dev->request_lock, flags);
Hank Janssenfceaf242009-07-13 15:34:54 -0700284
Greg Kroah-Hartman0120ee02009-09-02 09:17:52 -0700285 if (found) {
Haiyang Zhanga3a6cab2012-10-02 05:30:24 +0000286 if (resp->msg_len <=
287 sizeof(struct rndis_message) + RNDIS_EXT_LEN) {
Haiyang Zhangc2a4efd2010-12-10 12:03:56 -0800288 memcpy(&request->response_msg, resp,
Haiyang Zhanga388eb12010-12-10 12:04:00 -0800289 resp->msg_len);
Haiyang Zhang1b07da52014-03-04 14:11:06 -0800290 if (request->request_msg.ndis_msg_type ==
291 RNDIS_MSG_QUERY && request->request_msg.msg.
292 query_req.oid == RNDIS_OID_GEN_MEDIA_CONNECT_STATUS)
293 rndis_set_link_state(dev, request);
Greg Kroah-Hartman0120ee02009-09-02 09:17:52 -0700294 } else {
Haiyang Zhangd9871152011-09-01 12:19:41 -0700295 netdev_err(ndev,
Hank Jansseneb335bc2011-03-29 13:58:48 -0700296 "rndis response buffer overflow "
297 "detected (size %u max %zu)\n",
298 resp->msg_len,
KY Srinivasan86eedac2014-02-16 16:38:43 -0800299 sizeof(struct rndis_message));
Hank Janssenfceaf242009-07-13 15:34:54 -0700300
Haiyang Zhanga388eb12010-12-10 12:04:00 -0800301 if (resp->ndis_msg_type ==
Linus Walleij51491162012-05-11 22:17:07 +0000302 RNDIS_MSG_RESET_C) {
Greg Kroah-Hartman0120ee02009-09-02 09:17:52 -0700303 /* does not have a request id field */
Haiyang Zhanga388eb12010-12-10 12:04:00 -0800304 request->response_msg.msg.reset_complete.
Linus Walleij007e5c82012-05-11 22:15:59 +0000305 status = RNDIS_STATUS_BUFFER_OVERFLOW;
Greg Kroah-Hartman0120ee02009-09-02 09:17:52 -0700306 } else {
Haiyang Zhanga388eb12010-12-10 12:04:00 -0800307 request->response_msg.msg.
308 init_complete.status =
Linus Walleij007e5c82012-05-11 22:15:59 +0000309 RNDIS_STATUS_BUFFER_OVERFLOW;
Hank Janssenfceaf242009-07-13 15:34:54 -0700310 }
311 }
312
K. Y. Srinivasan98d79692011-05-10 07:55:42 -0700313 complete(&request->wait_event);
Greg Kroah-Hartman0120ee02009-09-02 09:17:52 -0700314 } else {
Haiyang Zhangd9871152011-09-01 12:19:41 -0700315 netdev_err(ndev,
Hank Jansseneb335bc2011-03-29 13:58:48 -0700316 "no rndis request found for this response "
317 "(id 0x%x res type 0x%x)\n",
318 resp->msg.init_complete.req_id,
319 resp->ndis_msg_type);
Hank Janssenfceaf242009-07-13 15:34:54 -0700320 }
Hank Janssenfceaf242009-07-13 15:34:54 -0700321}
322
Haiyang Zhang9c26aa02010-12-10 12:03:57 -0800323static void rndis_filter_receive_indicate_status(struct rndis_device *dev,
Haiyang Zhangc2a4efd2010-12-10 12:03:56 -0800324 struct rndis_message *resp)
Hank Janssenfceaf242009-07-13 15:34:54 -0700325{
Greg Kroah-Hartman0120ee02009-09-02 09:17:52 -0700326 struct rndis_indicate_status *indicate =
Haiyang Zhanga388eb12010-12-10 12:04:00 -0800327 &resp->msg.indicate_status;
Hank Janssenfceaf242009-07-13 15:34:54 -0700328
Haiyang Zhanga388eb12010-12-10 12:04:00 -0800329 if (indicate->status == RNDIS_STATUS_MEDIA_CONNECT) {
K. Y. Srinivasan39fb6aa2011-05-12 19:34:56 -0700330 netvsc_linkstatus_callback(
Haiyang Zhang53d21fd2010-12-10 12:03:59 -0800331 dev->net_dev->dev, 1);
Haiyang Zhanga388eb12010-12-10 12:04:00 -0800332 } else if (indicate->status == RNDIS_STATUS_MEDIA_DISCONNECT) {
K. Y. Srinivasan39fb6aa2011-05-12 19:34:56 -0700333 netvsc_linkstatus_callback(
Haiyang Zhang53d21fd2010-12-10 12:03:59 -0800334 dev->net_dev->dev, 0);
Greg Kroah-Hartman0120ee02009-09-02 09:17:52 -0700335 } else {
336 /*
337 * TODO:
338 */
Hank Janssenfceaf242009-07-13 15:34:54 -0700339 }
340}
341
Haiyang Zhang1f5f3a72012-03-12 10:20:50 +0000342/*
343 * Get the Per-Packet-Info with the specified type
344 * return NULL if not found.
345 */
346static inline void *rndis_get_ppi(struct rndis_packet *rpkt, u32 type)
347{
348 struct rndis_per_packet_info *ppi;
349 int len;
350
351 if (rpkt->per_pkt_info_offset == 0)
352 return NULL;
353
354 ppi = (struct rndis_per_packet_info *)((ulong)rpkt +
355 rpkt->per_pkt_info_offset);
356 len = rpkt->per_pkt_info_len;
357
358 while (len > 0) {
359 if (ppi->type == type)
360 return (void *)((ulong)ppi + ppi->ppi_offset);
361 len -= ppi->size;
362 ppi = (struct rndis_per_packet_info *)((ulong)ppi + ppi->size);
363 }
364
365 return NULL;
366}
367
Haiyang Zhang9c26aa02010-12-10 12:03:57 -0800368static void rndis_filter_receive_data(struct rndis_device *dev,
Haiyang Zhangc2a4efd2010-12-10 12:03:56 -0800369 struct rndis_message *msg,
370 struct hv_netvsc_packet *pkt)
Hank Janssenfceaf242009-07-13 15:34:54 -0700371{
Haiyang Zhangc2a4efd2010-12-10 12:03:56 -0800372 struct rndis_packet *rndis_pkt;
373 u32 data_offset;
Haiyang Zhang1f5f3a72012-03-12 10:20:50 +0000374 struct ndis_pkt_8021q_info *vlan;
KY Srinivasane3d605e2014-03-08 19:23:16 -0800375 struct ndis_tcp_ip_checksum_info *csum_info;
Hank Janssenfceaf242009-07-13 15:34:54 -0700376
Haiyang Zhanga388eb12010-12-10 12:04:00 -0800377 rndis_pkt = &msg->msg.pkt;
Hank Janssenfceaf242009-07-13 15:34:54 -0700378
Bill Pemberton454f18a2009-07-27 16:47:24 -0400379 /* Remove the rndis header and pass it back up the stack */
Haiyang Zhanga388eb12010-12-10 12:04:00 -0800380 data_offset = RNDIS_HEADER_SIZE + rndis_pkt->data_offset;
Hank Janssenfceaf242009-07-13 15:34:54 -0700381
Haiyang Zhang72a2f5b2010-12-10 12:03:58 -0800382 pkt->total_data_buflen -= data_offset;
Wei Yongjun4b8a8bc2012-02-01 20:17:23 +0000383
384 /*
385 * Make sure we got a valid RNDIS message, now total_data_buflen
386 * should be the data packet size plus the trailer padding size
387 */
388 if (pkt->total_data_buflen < rndis_pkt->data_len) {
389 netdev_err(dev->net_dev->ndev, "rndis message buffer "
390 "overflow detected (got %u, min %u)"
391 "...dropping this message!\n",
392 pkt->total_data_buflen, rndis_pkt->data_len);
393 return;
394 }
395
396 /*
397 * Remove the rndis trailer padding from rndis packet message
398 * rndis_pkt->data_len tell us the real data length, we only copy
399 * the data packet to the stack, without the rndis trailer padding
400 */
401 pkt->total_data_buflen = rndis_pkt->data_len;
Haiyang Zhang45326342011-12-15 13:45:15 -0800402 pkt->data = (void *)((unsigned long)pkt->data + data_offset);
Haiyang Zhang669c1fc2011-09-01 12:19:47 -0700403
Haiyang Zhang1f5f3a72012-03-12 10:20:50 +0000404 vlan = rndis_get_ppi(rndis_pkt, IEEE_8021Q_INFO);
405 if (vlan) {
406 pkt->vlan_tci = VLAN_TAG_PRESENT | vlan->vlanid |
407 (vlan->pri << VLAN_PRIO_SHIFT);
408 } else {
409 pkt->vlan_tci = 0;
410 }
411
KY Srinivasane3d605e2014-03-08 19:23:16 -0800412 csum_info = rndis_get_ppi(rndis_pkt, TCPIP_CHKSUM_PKTINFO);
413 netvsc_recv_callback(dev->net_dev->dev, pkt, csum_info);
Hank Janssenfceaf242009-07-13 15:34:54 -0700414}
415
K. Y. Srinivasan5fcc4112011-05-12 19:34:52 -0700416int rndis_filter_receive(struct hv_device *dev,
Haiyang Zhangc2a4efd2010-12-10 12:03:56 -0800417 struct hv_netvsc_packet *pkt)
Hank Janssenfceaf242009-07-13 15:34:54 -0700418{
K. Y. Srinivasan2ddd5e52011-09-13 10:59:49 -0700419 struct netvsc_device *net_dev = hv_get_drvdata(dev);
Haiyang Zhangc2a4efd2010-12-10 12:03:56 -0800420 struct rndis_device *rndis_dev;
Haiyang Zhangef31bef2012-03-12 10:20:49 +0000421 struct rndis_message *rndis_msg;
K. Y. Srinivasan2ddd5e52011-09-13 10:59:49 -0700422 struct net_device *ndev;
Haiyang Zhang63f69212012-10-02 05:30:23 +0000423 int ret = 0;
K. Y. Srinivasan2ddd5e52011-09-13 10:59:49 -0700424
Haiyang Zhang63f69212012-10-02 05:30:23 +0000425 if (!net_dev) {
426 ret = -EINVAL;
427 goto exit;
428 }
Bill Pemberton8a62d712010-05-05 15:27:47 -0400429
K. Y. Srinivasan715a4802011-10-06 10:10:56 -0700430 ndev = net_dev->ndev;
431
Bill Pemberton454f18a2009-07-27 16:47:24 -0400432 /* Make sure the rndis device state is initialized */
Haiyang Zhang53d21fd2010-12-10 12:03:59 -0800433 if (!net_dev->extension) {
Haiyang Zhangd9871152011-09-01 12:19:41 -0700434 netdev_err(ndev, "got rndis message but no rndis device - "
Hank Jansseneb335bc2011-03-29 13:58:48 -0700435 "dropping this message!\n");
Haiyang Zhang63f69212012-10-02 05:30:23 +0000436 ret = -ENODEV;
437 goto exit;
Hank Janssenfceaf242009-07-13 15:34:54 -0700438 }
439
Haiyang Zhang53d21fd2010-12-10 12:03:59 -0800440 rndis_dev = (struct rndis_device *)net_dev->extension;
Haiyang Zhangc2a4efd2010-12-10 12:03:56 -0800441 if (rndis_dev->state == RNDIS_DEV_UNINITIALIZED) {
Haiyang Zhangd9871152011-09-01 12:19:41 -0700442 netdev_err(ndev, "got rndis message but rndis device "
Hank Jansseneb335bc2011-03-29 13:58:48 -0700443 "uninitialized...dropping this message!\n");
Haiyang Zhang63f69212012-10-02 05:30:23 +0000444 ret = -ENODEV;
445 goto exit;
Hank Janssenfceaf242009-07-13 15:34:54 -0700446 }
447
Haiyang Zhangef31bef2012-03-12 10:20:49 +0000448 rndis_msg = pkt->data;
Hank Janssenfceaf242009-07-13 15:34:54 -0700449
Haiyang Zhangef31bef2012-03-12 10:20:49 +0000450 dump_rndis_message(dev, rndis_msg);
Hank Janssenfceaf242009-07-13 15:34:54 -0700451
Haiyang Zhangef31bef2012-03-12 10:20:49 +0000452 switch (rndis_msg->ndis_msg_type) {
Linus Walleij51491162012-05-11 22:17:07 +0000453 case RNDIS_MSG_PACKET:
Greg Kroah-Hartman0120ee02009-09-02 09:17:52 -0700454 /* data msg */
Haiyang Zhangef31bef2012-03-12 10:20:49 +0000455 rndis_filter_receive_data(rndis_dev, rndis_msg, pkt);
Hank Janssenfceaf242009-07-13 15:34:54 -0700456 break;
457
Linus Walleij51491162012-05-11 22:17:07 +0000458 case RNDIS_MSG_INIT_C:
459 case RNDIS_MSG_QUERY_C:
460 case RNDIS_MSG_SET_C:
Greg Kroah-Hartman0120ee02009-09-02 09:17:52 -0700461 /* completion msgs */
Haiyang Zhangef31bef2012-03-12 10:20:49 +0000462 rndis_filter_receive_response(rndis_dev, rndis_msg);
Hank Janssenfceaf242009-07-13 15:34:54 -0700463 break;
464
Linus Walleij51491162012-05-11 22:17:07 +0000465 case RNDIS_MSG_INDICATE:
Greg Kroah-Hartman0120ee02009-09-02 09:17:52 -0700466 /* notification msgs */
Haiyang Zhangef31bef2012-03-12 10:20:49 +0000467 rndis_filter_receive_indicate_status(rndis_dev, rndis_msg);
Hank Janssenfceaf242009-07-13 15:34:54 -0700468 break;
469 default:
Haiyang Zhangd9871152011-09-01 12:19:41 -0700470 netdev_err(ndev,
Hank Jansseneb335bc2011-03-29 13:58:48 -0700471 "unhandled rndis message (type %u len %u)\n",
Haiyang Zhangef31bef2012-03-12 10:20:49 +0000472 rndis_msg->ndis_msg_type,
473 rndis_msg->msg_len);
Hank Janssenfceaf242009-07-13 15:34:54 -0700474 break;
475 }
476
Haiyang Zhang63f69212012-10-02 05:30:23 +0000477exit:
478 if (ret != 0)
479 pkt->status = NVSP_STAT_FAIL;
480
481 return ret;
Hank Janssenfceaf242009-07-13 15:34:54 -0700482}
483
Haiyang Zhang9c26aa02010-12-10 12:03:57 -0800484static int rndis_filter_query_device(struct rndis_device *dev, u32 oid,
Haiyang Zhangc2a4efd2010-12-10 12:03:56 -0800485 void *result, u32 *result_size)
Hank Janssenfceaf242009-07-13 15:34:54 -0700486{
Greg Kroah-Hartmane681b952009-08-28 16:26:27 -0700487 struct rndis_request *request;
Haiyang Zhangc2a4efd2010-12-10 12:03:56 -0800488 u32 inresult_size = *result_size;
Greg Kroah-Hartman9f33d052009-08-19 16:26:24 -0700489 struct rndis_query_request *query;
Haiyang Zhangc2a4efd2010-12-10 12:03:56 -0800490 struct rndis_query_complete *query_complete;
Greg Kroah-Hartman0120ee02009-09-02 09:17:52 -0700491 int ret = 0;
K. Y. Srinivasan98d79692011-05-10 07:55:42 -0700492 int t;
Hank Janssenfceaf242009-07-13 15:34:54 -0700493
Haiyang Zhangc2a4efd2010-12-10 12:03:56 -0800494 if (!result)
Bill Pemberton8a62d712010-05-05 15:27:47 -0400495 return -EINVAL;
Hank Janssenfceaf242009-07-13 15:34:54 -0700496
Haiyang Zhangc2a4efd2010-12-10 12:03:56 -0800497 *result_size = 0;
Linus Walleij51491162012-05-11 22:17:07 +0000498 request = get_rndis_request(dev, RNDIS_MSG_QUERY,
Greg Kroah-Hartman0120ee02009-09-02 09:17:52 -0700499 RNDIS_MESSAGE_SIZE(struct rndis_query_request));
500 if (!request) {
K. Y. Srinivasande6e0582011-08-25 09:49:18 -0700501 ret = -ENOMEM;
K. Y. Srinivasan1c627872011-08-25 09:49:24 -0700502 goto cleanup;
Hank Janssenfceaf242009-07-13 15:34:54 -0700503 }
504
Bill Pemberton454f18a2009-07-27 16:47:24 -0400505 /* Setup the rndis query */
Haiyang Zhanga388eb12010-12-10 12:04:00 -0800506 query = &request->request_msg.msg.query_req;
507 query->oid = oid;
508 query->info_buf_offset = sizeof(struct rndis_query_request);
509 query->info_buflen = 0;
510 query->dev_vc_handle = 0;
Hank Janssenfceaf242009-07-13 15:34:54 -0700511
Haiyang Zhang5b54dac2014-04-21 10:20:28 -0700512 if (oid == OID_GEN_RECEIVE_SCALE_CAPABILITIES) {
513 struct ndis_recv_scale_cap *cap;
514
515 request->request_msg.msg_len +=
516 sizeof(struct ndis_recv_scale_cap);
517 query->info_buflen = sizeof(struct ndis_recv_scale_cap);
518 cap = (struct ndis_recv_scale_cap *)((unsigned long)query +
519 query->info_buf_offset);
520 cap->hdr.type = NDIS_OBJECT_TYPE_RSS_CAPABILITIES;
521 cap->hdr.rev = NDIS_RECEIVE_SCALE_CAPABILITIES_REVISION_2;
522 cap->hdr.size = sizeof(struct ndis_recv_scale_cap);
523 }
524
Haiyang Zhang9c26aa02010-12-10 12:03:57 -0800525 ret = rndis_filter_send_request(dev, request);
Hank Janssenfceaf242009-07-13 15:34:54 -0700526 if (ret != 0)
K. Y. Srinivasan1c627872011-08-25 09:49:24 -0700527 goto cleanup;
Hank Janssenfceaf242009-07-13 15:34:54 -0700528
K. Y. Srinivasan5c5781b32011-06-16 13:16:35 -0700529 t = wait_for_completion_timeout(&request->wait_event, 5*HZ);
K. Y. Srinivasan98d79692011-05-10 07:55:42 -0700530 if (t == 0) {
K. Y. Srinivasan0c3b7b22011-02-11 09:59:43 -0800531 ret = -ETIMEDOUT;
K. Y. Srinivasan1c627872011-08-25 09:49:24 -0700532 goto cleanup;
K. Y. Srinivasan0c3b7b22011-02-11 09:59:43 -0800533 }
Hank Janssenfceaf242009-07-13 15:34:54 -0700534
Bill Pemberton454f18a2009-07-27 16:47:24 -0400535 /* Copy the response back */
Haiyang Zhanga388eb12010-12-10 12:04:00 -0800536 query_complete = &request->response_msg.msg.query_complete;
Hank Janssenfceaf242009-07-13 15:34:54 -0700537
Haiyang Zhanga388eb12010-12-10 12:04:00 -0800538 if (query_complete->info_buflen > inresult_size) {
Hank Janssenfceaf242009-07-13 15:34:54 -0700539 ret = -1;
K. Y. Srinivasan1c627872011-08-25 09:49:24 -0700540 goto cleanup;
Hank Janssenfceaf242009-07-13 15:34:54 -0700541 }
542
Haiyang Zhangc2a4efd2010-12-10 12:03:56 -0800543 memcpy(result,
544 (void *)((unsigned long)query_complete +
Haiyang Zhanga388eb12010-12-10 12:04:00 -0800545 query_complete->info_buf_offset),
546 query_complete->info_buflen);
Hank Janssenfceaf242009-07-13 15:34:54 -0700547
Haiyang Zhanga388eb12010-12-10 12:04:00 -0800548 *result_size = query_complete->info_buflen;
Hank Janssenfceaf242009-07-13 15:34:54 -0700549
K. Y. Srinivasan1c627872011-08-25 09:49:24 -0700550cleanup:
Hank Janssenfceaf242009-07-13 15:34:54 -0700551 if (request)
Haiyang Zhang9c26aa02010-12-10 12:03:57 -0800552 put_rndis_request(dev, request);
Hank Janssenfceaf242009-07-13 15:34:54 -0700553
554 return ret;
555}
556
Haiyang Zhang9c26aa02010-12-10 12:03:57 -0800557static int rndis_filter_query_device_mac(struct rndis_device *dev)
Hank Janssenfceaf242009-07-13 15:34:54 -0700558{
Stephen Hemminger9f8bd8b2010-05-04 09:58:54 -0700559 u32 size = ETH_ALEN;
Hank Janssenfceaf242009-07-13 15:34:54 -0700560
Haiyang Zhang9c26aa02010-12-10 12:03:57 -0800561 return rndis_filter_query_device(dev,
Greg Kroah-Hartman0120ee02009-09-02 09:17:52 -0700562 RNDIS_OID_802_3_PERMANENT_ADDRESS,
Haiyang Zhangc2a4efd2010-12-10 12:03:56 -0800563 dev->hw_mac_adr, &size);
Hank Janssenfceaf242009-07-13 15:34:54 -0700564}
565
Haiyang Zhang1ce09e82012-07-10 07:19:22 +0000566#define NWADR_STR "NetworkAddress"
567#define NWADR_STRLEN 14
568
569int rndis_filter_set_device_mac(struct hv_device *hdev, char *mac)
570{
571 struct netvsc_device *nvdev = hv_get_drvdata(hdev);
572 struct rndis_device *rdev = nvdev->extension;
573 struct net_device *ndev = nvdev->ndev;
574 struct rndis_request *request;
575 struct rndis_set_request *set;
576 struct rndis_config_parameter_info *cpi;
577 wchar_t *cfg_nwadr, *cfg_mac;
578 struct rndis_set_complete *set_complete;
579 char macstr[2*ETH_ALEN+1];
580 u32 extlen = sizeof(struct rndis_config_parameter_info) +
581 2*NWADR_STRLEN + 4*ETH_ALEN;
582 int ret, t;
583
584 request = get_rndis_request(rdev, RNDIS_MSG_SET,
585 RNDIS_MESSAGE_SIZE(struct rndis_set_request) + extlen);
586 if (!request)
587 return -ENOMEM;
588
589 set = &request->request_msg.msg.set_req;
590 set->oid = RNDIS_OID_GEN_RNDIS_CONFIG_PARAMETER;
591 set->info_buflen = extlen;
592 set->info_buf_offset = sizeof(struct rndis_set_request);
593 set->dev_vc_handle = 0;
594
595 cpi = (struct rndis_config_parameter_info *)((ulong)set +
596 set->info_buf_offset);
597 cpi->parameter_name_offset =
598 sizeof(struct rndis_config_parameter_info);
599 /* Multiply by 2 because host needs 2 bytes (utf16) for each char */
600 cpi->parameter_name_length = 2*NWADR_STRLEN;
601 cpi->parameter_type = RNDIS_CONFIG_PARAM_TYPE_STRING;
602 cpi->parameter_value_offset =
603 cpi->parameter_name_offset + cpi->parameter_name_length;
604 /* Multiply by 4 because each MAC byte displayed as 2 utf16 chars */
605 cpi->parameter_value_length = 4*ETH_ALEN;
606
607 cfg_nwadr = (wchar_t *)((ulong)cpi + cpi->parameter_name_offset);
608 cfg_mac = (wchar_t *)((ulong)cpi + cpi->parameter_value_offset);
609 ret = utf8s_to_utf16s(NWADR_STR, NWADR_STRLEN, UTF16_HOST_ENDIAN,
610 cfg_nwadr, NWADR_STRLEN);
611 if (ret < 0)
612 goto cleanup;
613 snprintf(macstr, 2*ETH_ALEN+1, "%pm", mac);
614 ret = utf8s_to_utf16s(macstr, 2*ETH_ALEN, UTF16_HOST_ENDIAN,
615 cfg_mac, 2*ETH_ALEN);
616 if (ret < 0)
617 goto cleanup;
618
619 ret = rndis_filter_send_request(rdev, request);
620 if (ret != 0)
621 goto cleanup;
622
623 t = wait_for_completion_timeout(&request->wait_event, 5*HZ);
624 if (t == 0) {
625 netdev_err(ndev, "timeout before we got a set response...\n");
626 /*
627 * can't put_rndis_request, since we may still receive a
628 * send-completion.
629 */
630 return -EBUSY;
631 } else {
632 set_complete = &request->response_msg.msg.set_complete;
Haiyang Zhangb02a8062012-11-30 09:23:41 +0000633 if (set_complete->status != RNDIS_STATUS_SUCCESS) {
634 netdev_err(ndev, "Fail to set MAC on host side:0x%x\n",
635 set_complete->status);
Haiyang Zhang1ce09e82012-07-10 07:19:22 +0000636 ret = -EINVAL;
Haiyang Zhangb02a8062012-11-30 09:23:41 +0000637 }
Haiyang Zhang1ce09e82012-07-10 07:19:22 +0000638 }
639
640cleanup:
641 put_rndis_request(rdev, request);
642 return ret;
643}
644
KY Srinivasan4a0e70a2014-03-08 19:23:15 -0800645int rndis_filter_set_offload_params(struct hv_device *hdev,
646 struct ndis_offload_params *req_offloads)
647{
648 struct netvsc_device *nvdev = hv_get_drvdata(hdev);
649 struct rndis_device *rdev = nvdev->extension;
650 struct net_device *ndev = nvdev->ndev;
651 struct rndis_request *request;
652 struct rndis_set_request *set;
653 struct ndis_offload_params *offload_params;
654 struct rndis_set_complete *set_complete;
655 u32 extlen = sizeof(struct ndis_offload_params);
656 int ret, t;
KY Srinivasanaf9893a2014-04-09 15:00:47 -0700657 u32 vsp_version = nvdev->nvsp_version;
658
659 if (vsp_version <= NVSP_PROTOCOL_VERSION_4) {
660 extlen = VERSION_4_OFFLOAD_SIZE;
661 /* On NVSP_PROTOCOL_VERSION_4 and below, we do not support
662 * UDP checksum offload.
663 */
664 req_offloads->udp_ip_v4_csum = 0;
665 req_offloads->udp_ip_v6_csum = 0;
666 }
KY Srinivasan4a0e70a2014-03-08 19:23:15 -0800667
668 request = get_rndis_request(rdev, RNDIS_MSG_SET,
669 RNDIS_MESSAGE_SIZE(struct rndis_set_request) + extlen);
670 if (!request)
671 return -ENOMEM;
672
673 set = &request->request_msg.msg.set_req;
674 set->oid = OID_TCP_OFFLOAD_PARAMETERS;
675 set->info_buflen = extlen;
676 set->info_buf_offset = sizeof(struct rndis_set_request);
677 set->dev_vc_handle = 0;
678
679 offload_params = (struct ndis_offload_params *)((ulong)set +
680 set->info_buf_offset);
681 *offload_params = *req_offloads;
682 offload_params->header.type = NDIS_OBJECT_TYPE_DEFAULT;
683 offload_params->header.revision = NDIS_OFFLOAD_PARAMETERS_REVISION_3;
684 offload_params->header.size = extlen;
685
686 ret = rndis_filter_send_request(rdev, request);
687 if (ret != 0)
688 goto cleanup;
689
690 t = wait_for_completion_timeout(&request->wait_event, 5*HZ);
691 if (t == 0) {
692 netdev_err(ndev, "timeout before we got aOFFLOAD set response...\n");
693 /* can't put_rndis_request, since we may still receive a
694 * send-completion.
695 */
696 return -EBUSY;
697 } else {
698 set_complete = &request->response_msg.msg.set_complete;
699 if (set_complete->status != RNDIS_STATUS_SUCCESS) {
KY Srinivasanaf9893a2014-04-09 15:00:47 -0700700 netdev_err(ndev, "Fail to set offload on host side:0x%x\n",
KY Srinivasan4a0e70a2014-03-08 19:23:15 -0800701 set_complete->status);
702 ret = -EINVAL;
703 }
704 }
705
706cleanup:
707 put_rndis_request(rdev, request);
708 return ret;
709}
Haiyang Zhang1ce09e82012-07-10 07:19:22 +0000710
Haiyang Zhang5b54dac2014-04-21 10:20:28 -0700711u8 netvsc_hash_key[HASH_KEYLEN] = {
712 0x6d, 0x5a, 0x56, 0xda, 0x25, 0x5b, 0x0e, 0xc2,
713 0x41, 0x67, 0x25, 0x3d, 0x43, 0xa3, 0x8f, 0xb0,
714 0xd0, 0xca, 0x2b, 0xcb, 0xae, 0x7b, 0x30, 0xb4,
715 0x77, 0xcb, 0x2d, 0xa3, 0x80, 0x30, 0xf2, 0x0c,
716 0x6a, 0x42, 0xb7, 0x3b, 0xbe, 0xac, 0x01, 0xfa
717};
718
719int rndis_filter_set_rss_param(struct rndis_device *rdev, int num_queue)
720{
721 struct net_device *ndev = rdev->net_dev->ndev;
722 struct rndis_request *request;
723 struct rndis_set_request *set;
724 struct rndis_set_complete *set_complete;
725 u32 extlen = sizeof(struct ndis_recv_scale_param) +
726 4*ITAB_NUM + HASH_KEYLEN;
727 struct ndis_recv_scale_param *rssp;
728 u32 *itab;
729 u8 *keyp;
730 int i, t, ret;
731
732 request = get_rndis_request(
733 rdev, RNDIS_MSG_SET,
734 RNDIS_MESSAGE_SIZE(struct rndis_set_request) + extlen);
735 if (!request)
736 return -ENOMEM;
737
738 set = &request->request_msg.msg.set_req;
739 set->oid = OID_GEN_RECEIVE_SCALE_PARAMETERS;
740 set->info_buflen = extlen;
741 set->info_buf_offset = sizeof(struct rndis_set_request);
742 set->dev_vc_handle = 0;
743
744 rssp = (struct ndis_recv_scale_param *)(set + 1);
745 rssp->hdr.type = NDIS_OBJECT_TYPE_RSS_PARAMETERS;
746 rssp->hdr.rev = NDIS_RECEIVE_SCALE_PARAMETERS_REVISION_2;
747 rssp->hdr.size = sizeof(struct ndis_recv_scale_param);
748 rssp->flag = 0;
749 rssp->hashinfo = NDIS_HASH_FUNC_TOEPLITZ | NDIS_HASH_IPV4 |
750 NDIS_HASH_TCP_IPV4;
751 rssp->indirect_tabsize = 4*ITAB_NUM;
752 rssp->indirect_taboffset = sizeof(struct ndis_recv_scale_param);
753 rssp->hashkey_size = HASH_KEYLEN;
754 rssp->kashkey_offset = rssp->indirect_taboffset +
755 rssp->indirect_tabsize;
756
757 /* Set indirection table entries */
758 itab = (u32 *)(rssp + 1);
759 for (i = 0; i < ITAB_NUM; i++)
760 itab[i] = i % num_queue;
761
762 /* Set hask key values */
763 keyp = (u8 *)((unsigned long)rssp + rssp->kashkey_offset);
764 for (i = 0; i < HASH_KEYLEN; i++)
765 keyp[i] = netvsc_hash_key[i];
766
767
768 ret = rndis_filter_send_request(rdev, request);
769 if (ret != 0)
770 goto cleanup;
771
772 t = wait_for_completion_timeout(&request->wait_event, 5*HZ);
773 if (t == 0) {
774 netdev_err(ndev, "timeout before we got a set response...\n");
775 /* can't put_rndis_request, since we may still receive a
776 * send-completion.
777 */
778 return -ETIMEDOUT;
779 } else {
780 set_complete = &request->response_msg.msg.set_complete;
781 if (set_complete->status != RNDIS_STATUS_SUCCESS) {
782 netdev_err(ndev, "Fail to set RSS parameters:0x%x\n",
783 set_complete->status);
784 ret = -EINVAL;
785 }
786 }
787
788cleanup:
789 put_rndis_request(rdev, request);
790 return ret;
791}
792
793
Haiyang Zhang9c26aa02010-12-10 12:03:57 -0800794static int rndis_filter_query_device_link_status(struct rndis_device *dev)
Hank Janssenfceaf242009-07-13 15:34:54 -0700795{
Greg Kroah-Hartman0120ee02009-09-02 09:17:52 -0700796 u32 size = sizeof(u32);
K. Y. Srinivasan6f274572011-09-13 15:21:27 -0700797 u32 link_status;
798 int ret;
Hank Janssenfceaf242009-07-13 15:34:54 -0700799
K. Y. Srinivasan6f274572011-09-13 15:21:27 -0700800 ret = rndis_filter_query_device(dev,
Greg Kroah-Hartman0120ee02009-09-02 09:17:52 -0700801 RNDIS_OID_GEN_MEDIA_CONNECT_STATUS,
K. Y. Srinivasan6f274572011-09-13 15:21:27 -0700802 &link_status, &size);
K. Y. Srinivasan6f274572011-09-13 15:21:27 -0700803
804 return ret;
Hank Janssenfceaf242009-07-13 15:34:54 -0700805}
806
Haiyang Zhangd426b2e2011-11-30 07:19:08 -0800807int rndis_filter_set_packet_filter(struct rndis_device *dev, u32 new_filter)
Hank Janssenfceaf242009-07-13 15:34:54 -0700808{
Greg Kroah-Hartmane681b952009-08-28 16:26:27 -0700809 struct rndis_request *request;
Greg Kroah-Hartman9f33d052009-08-19 16:26:24 -0700810 struct rndis_set_request *set;
Haiyang Zhangc2a4efd2010-12-10 12:03:56 -0800811 struct rndis_set_complete *set_complete;
Greg Kroah-Hartman4d643112009-07-14 15:09:36 -0700812 u32 status;
K. Y. Srinivasan98d79692011-05-10 07:55:42 -0700813 int ret, t;
K. Y. Srinivasan2ddd5e52011-09-13 10:59:49 -0700814 struct net_device *ndev;
815
816 ndev = dev->net_dev->ndev;
Hank Janssenfceaf242009-07-13 15:34:54 -0700817
Linus Walleij51491162012-05-11 22:17:07 +0000818 request = get_rndis_request(dev, RNDIS_MSG_SET,
Greg Kroah-Hartman0120ee02009-09-02 09:17:52 -0700819 RNDIS_MESSAGE_SIZE(struct rndis_set_request) +
820 sizeof(u32));
821 if (!request) {
K. Y. Srinivasan58ef3972011-08-25 09:49:19 -0700822 ret = -ENOMEM;
K. Y. Srinivasan1c627872011-08-25 09:49:24 -0700823 goto cleanup;
Hank Janssenfceaf242009-07-13 15:34:54 -0700824 }
825
Bill Pemberton454f18a2009-07-27 16:47:24 -0400826 /* Setup the rndis set */
Haiyang Zhanga388eb12010-12-10 12:04:00 -0800827 set = &request->request_msg.msg.set_req;
828 set->oid = RNDIS_OID_GEN_CURRENT_PACKET_FILTER;
829 set->info_buflen = sizeof(u32);
830 set->info_buf_offset = sizeof(struct rndis_set_request);
Hank Janssenfceaf242009-07-13 15:34:54 -0700831
Greg Kroah-Hartman0120ee02009-09-02 09:17:52 -0700832 memcpy((void *)(unsigned long)set + sizeof(struct rndis_set_request),
Haiyang Zhangc2a4efd2010-12-10 12:03:56 -0800833 &new_filter, sizeof(u32));
Hank Janssenfceaf242009-07-13 15:34:54 -0700834
Haiyang Zhang9c26aa02010-12-10 12:03:57 -0800835 ret = rndis_filter_send_request(dev, request);
Hank Janssenfceaf242009-07-13 15:34:54 -0700836 if (ret != 0)
K. Y. Srinivasan1c627872011-08-25 09:49:24 -0700837 goto cleanup;
Hank Janssenfceaf242009-07-13 15:34:54 -0700838
K. Y. Srinivasan5c5781b32011-06-16 13:16:35 -0700839 t = wait_for_completion_timeout(&request->wait_event, 5*HZ);
K. Y. Srinivasan98d79692011-05-10 07:55:42 -0700840
841 if (t == 0) {
Haiyang Zhangd9871152011-09-01 12:19:41 -0700842 netdev_err(ndev,
Hank Jansseneb335bc2011-03-29 13:58:48 -0700843 "timeout before we got a set response...\n");
Haiyang Zhangea496372012-10-02 05:30:20 +0000844 ret = -ETIMEDOUT;
Greg Kroah-Hartman0120ee02009-09-02 09:17:52 -0700845 /*
Lucas De Marchi25985ed2011-03-30 22:57:33 -0300846 * We can't deallocate the request since we may still receive a
Greg Kroah-Hartman0120ee02009-09-02 09:17:52 -0700847 * send completion for it.
848 */
K. Y. Srinivasan5585d812011-08-25 09:49:25 -0700849 goto exit;
Greg Kroah-Hartman0120ee02009-09-02 09:17:52 -0700850 } else {
Haiyang Zhanga388eb12010-12-10 12:04:00 -0800851 set_complete = &request->response_msg.msg.set_complete;
852 status = set_complete->status;
Hank Janssenfceaf242009-07-13 15:34:54 -0700853 }
854
K. Y. Srinivasan1c627872011-08-25 09:49:24 -0700855cleanup:
Hank Janssenfceaf242009-07-13 15:34:54 -0700856 if (request)
Haiyang Zhang9c26aa02010-12-10 12:03:57 -0800857 put_rndis_request(dev, request);
K. Y. Srinivasan5585d812011-08-25 09:49:25 -0700858exit:
Hank Janssenfceaf242009-07-13 15:34:54 -0700859 return ret;
860}
861
Hank Janssenfceaf242009-07-13 15:34:54 -0700862
Haiyang Zhang9c26aa02010-12-10 12:03:57 -0800863static int rndis_filter_init_device(struct rndis_device *dev)
Hank Janssenfceaf242009-07-13 15:34:54 -0700864{
Greg Kroah-Hartmane681b952009-08-28 16:26:27 -0700865 struct rndis_request *request;
Greg Kroah-Hartman9f33d052009-08-19 16:26:24 -0700866 struct rndis_initialize_request *init;
Haiyang Zhangc2a4efd2010-12-10 12:03:56 -0800867 struct rndis_initialize_complete *init_complete;
Greg Kroah-Hartman4d643112009-07-14 15:09:36 -0700868 u32 status;
K. Y. Srinivasan98d79692011-05-10 07:55:42 -0700869 int ret, t;
Hank Janssenfceaf242009-07-13 15:34:54 -0700870
Linus Walleij51491162012-05-11 22:17:07 +0000871 request = get_rndis_request(dev, RNDIS_MSG_INIT,
Greg Kroah-Hartman0120ee02009-09-02 09:17:52 -0700872 RNDIS_MESSAGE_SIZE(struct rndis_initialize_request));
873 if (!request) {
K. Y. Srinivasanbc49b9262011-08-25 09:49:20 -0700874 ret = -ENOMEM;
K. Y. Srinivasan1c627872011-08-25 09:49:24 -0700875 goto cleanup;
Hank Janssenfceaf242009-07-13 15:34:54 -0700876 }
877
Bill Pemberton454f18a2009-07-27 16:47:24 -0400878 /* Setup the rndis set */
Haiyang Zhanga388eb12010-12-10 12:04:00 -0800879 init = &request->request_msg.msg.init_req;
880 init->major_ver = RNDIS_MAJOR_VERSION;
881 init->minor_ver = RNDIS_MINOR_VERSION;
Haiyang Zhangfb1d0742012-10-02 05:30:19 +0000882 init->max_xfer_size = 0x4000;
Hank Janssenfceaf242009-07-13 15:34:54 -0700883
Haiyang Zhangc2a4efd2010-12-10 12:03:56 -0800884 dev->state = RNDIS_DEV_INITIALIZING;
Hank Janssenfceaf242009-07-13 15:34:54 -0700885
Haiyang Zhang9c26aa02010-12-10 12:03:57 -0800886 ret = rndis_filter_send_request(dev, request);
Greg Kroah-Hartman0120ee02009-09-02 09:17:52 -0700887 if (ret != 0) {
Haiyang Zhangc2a4efd2010-12-10 12:03:56 -0800888 dev->state = RNDIS_DEV_UNINITIALIZED;
K. Y. Srinivasan1c627872011-08-25 09:49:24 -0700889 goto cleanup;
Hank Janssenfceaf242009-07-13 15:34:54 -0700890 }
891
K. Y. Srinivasan0c3b7b22011-02-11 09:59:43 -0800892
K. Y. Srinivasan5c5781b32011-06-16 13:16:35 -0700893 t = wait_for_completion_timeout(&request->wait_event, 5*HZ);
K. Y. Srinivasan98d79692011-05-10 07:55:42 -0700894
895 if (t == 0) {
K. Y. Srinivasan0c3b7b22011-02-11 09:59:43 -0800896 ret = -ETIMEDOUT;
K. Y. Srinivasan1c627872011-08-25 09:49:24 -0700897 goto cleanup;
K. Y. Srinivasan0c3b7b22011-02-11 09:59:43 -0800898 }
Hank Janssenfceaf242009-07-13 15:34:54 -0700899
Haiyang Zhanga388eb12010-12-10 12:04:00 -0800900 init_complete = &request->response_msg.msg.init_complete;
901 status = init_complete->status;
Greg Kroah-Hartman0120ee02009-09-02 09:17:52 -0700902 if (status == RNDIS_STATUS_SUCCESS) {
Haiyang Zhangc2a4efd2010-12-10 12:03:56 -0800903 dev->state = RNDIS_DEV_INITIALIZED;
Hank Janssenfceaf242009-07-13 15:34:54 -0700904 ret = 0;
Greg Kroah-Hartman0120ee02009-09-02 09:17:52 -0700905 } else {
Haiyang Zhangc2a4efd2010-12-10 12:03:56 -0800906 dev->state = RNDIS_DEV_UNINITIALIZED;
K. Y. Srinivasanbc49b9262011-08-25 09:49:20 -0700907 ret = -EINVAL;
Hank Janssenfceaf242009-07-13 15:34:54 -0700908 }
909
K. Y. Srinivasan1c627872011-08-25 09:49:24 -0700910cleanup:
Hank Janssenfceaf242009-07-13 15:34:54 -0700911 if (request)
Haiyang Zhang9c26aa02010-12-10 12:03:57 -0800912 put_rndis_request(dev, request);
Hank Janssenfceaf242009-07-13 15:34:54 -0700913
914 return ret;
915}
916
Haiyang Zhang9c26aa02010-12-10 12:03:57 -0800917static void rndis_filter_halt_device(struct rndis_device *dev)
Hank Janssenfceaf242009-07-13 15:34:54 -0700918{
Greg Kroah-Hartmane681b952009-08-28 16:26:27 -0700919 struct rndis_request *request;
Greg Kroah-Hartman9f33d052009-08-19 16:26:24 -0700920 struct rndis_halt_request *halt;
Haiyang Zhangae9e63b2012-08-03 09:32:18 +0000921 struct netvsc_device *nvdev = dev->net_dev;
922 struct hv_device *hdev = nvdev->dev;
923 ulong flags;
Hank Janssenfceaf242009-07-13 15:34:54 -0700924
Bill Pemberton454f18a2009-07-27 16:47:24 -0400925 /* Attempt to do a rndis device halt */
Linus Walleij51491162012-05-11 22:17:07 +0000926 request = get_rndis_request(dev, RNDIS_MSG_HALT,
Greg Kroah-Hartman0120ee02009-09-02 09:17:52 -0700927 RNDIS_MESSAGE_SIZE(struct rndis_halt_request));
Hank Janssenfceaf242009-07-13 15:34:54 -0700928 if (!request)
K. Y. Srinivasan1c627872011-08-25 09:49:24 -0700929 goto cleanup;
Hank Janssenfceaf242009-07-13 15:34:54 -0700930
Bill Pemberton454f18a2009-07-27 16:47:24 -0400931 /* Setup the rndis set */
Haiyang Zhanga388eb12010-12-10 12:04:00 -0800932 halt = &request->request_msg.msg.halt_req;
933 halt->req_id = atomic_inc_return(&dev->new_req_id);
Hank Janssenfceaf242009-07-13 15:34:54 -0700934
Bill Pemberton454f18a2009-07-27 16:47:24 -0400935 /* Ignore return since this msg is optional. */
Haiyang Zhang9c26aa02010-12-10 12:03:57 -0800936 rndis_filter_send_request(dev, request);
Hank Janssenfceaf242009-07-13 15:34:54 -0700937
Haiyang Zhangc2a4efd2010-12-10 12:03:56 -0800938 dev->state = RNDIS_DEV_UNINITIALIZED;
Hank Janssenfceaf242009-07-13 15:34:54 -0700939
K. Y. Srinivasan1c627872011-08-25 09:49:24 -0700940cleanup:
Haiyang Zhangae9e63b2012-08-03 09:32:18 +0000941 spin_lock_irqsave(&hdev->channel->inbound_lock, flags);
942 nvdev->destroy = true;
943 spin_unlock_irqrestore(&hdev->channel->inbound_lock, flags);
944
945 /* Wait for all send completions */
946 wait_event(nvdev->wait_drain,
947 atomic_read(&nvdev->num_outstanding_sends) == 0);
948
Hank Janssenfceaf242009-07-13 15:34:54 -0700949 if (request)
Haiyang Zhang9c26aa02010-12-10 12:03:57 -0800950 put_rndis_request(dev, request);
Hank Janssenfceaf242009-07-13 15:34:54 -0700951 return;
952}
953
Haiyang Zhang9c26aa02010-12-10 12:03:57 -0800954static int rndis_filter_open_device(struct rndis_device *dev)
Hank Janssenfceaf242009-07-13 15:34:54 -0700955{
Greg Kroah-Hartman0120ee02009-09-02 09:17:52 -0700956 int ret;
Hank Janssenfceaf242009-07-13 15:34:54 -0700957
Haiyang Zhangc2a4efd2010-12-10 12:03:56 -0800958 if (dev->state != RNDIS_DEV_INITIALIZED)
Hank Janssenfceaf242009-07-13 15:34:54 -0700959 return 0;
960
Haiyang Zhang9c26aa02010-12-10 12:03:57 -0800961 ret = rndis_filter_set_packet_filter(dev,
Greg Kroah-Hartman0120ee02009-09-02 09:17:52 -0700962 NDIS_PACKET_TYPE_BROADCAST |
Haiyang Zhang95beae92010-04-19 15:32:11 +0000963 NDIS_PACKET_TYPE_ALL_MULTICAST |
Greg Kroah-Hartman0120ee02009-09-02 09:17:52 -0700964 NDIS_PACKET_TYPE_DIRECTED);
Hank Janssenfceaf242009-07-13 15:34:54 -0700965 if (ret == 0)
Haiyang Zhangc2a4efd2010-12-10 12:03:56 -0800966 dev->state = RNDIS_DEV_DATAINITIALIZED;
Hank Janssenfceaf242009-07-13 15:34:54 -0700967
Hank Janssenfceaf242009-07-13 15:34:54 -0700968 return ret;
969}
970
Haiyang Zhang9c26aa02010-12-10 12:03:57 -0800971static int rndis_filter_close_device(struct rndis_device *dev)
Hank Janssenfceaf242009-07-13 15:34:54 -0700972{
973 int ret;
974
Haiyang Zhangc2a4efd2010-12-10 12:03:56 -0800975 if (dev->state != RNDIS_DEV_DATAINITIALIZED)
Hank Janssenfceaf242009-07-13 15:34:54 -0700976 return 0;
977
Haiyang Zhang9c26aa02010-12-10 12:03:57 -0800978 ret = rndis_filter_set_packet_filter(dev, 0);
Hank Janssenfceaf242009-07-13 15:34:54 -0700979 if (ret == 0)
Haiyang Zhangc2a4efd2010-12-10 12:03:56 -0800980 dev->state = RNDIS_DEV_INITIALIZED;
Hank Janssenfceaf242009-07-13 15:34:54 -0700981
Hank Janssenfceaf242009-07-13 15:34:54 -0700982 return ret;
983}
984
Haiyang Zhang5b54dac2014-04-21 10:20:28 -0700985static void netvsc_sc_open(struct vmbus_channel *new_sc)
986{
987 struct netvsc_device *nvscdev;
988 u16 chn_index = new_sc->offermsg.offer.sub_channel_index;
989 int ret;
990
991 nvscdev = hv_get_drvdata(new_sc->primary_channel->device_obj);
992
993 if (chn_index >= nvscdev->num_chn)
994 return;
995
996 set_per_channel_state(new_sc, nvscdev->sub_cb_buf + (chn_index - 1) *
997 NETVSC_PACKET_SIZE);
998
999 ret = vmbus_open(new_sc, nvscdev->ring_size * PAGE_SIZE,
1000 nvscdev->ring_size * PAGE_SIZE, NULL, 0,
1001 netvsc_channel_cb, new_sc);
1002
1003 if (ret == 0)
1004 nvscdev->chn_table[chn_index] = new_sc;
1005}
1006
Haiyang Zhangbdbad572011-05-23 09:03:49 -07001007int rndis_filter_device_add(struct hv_device *dev,
Haiyang Zhangc2a4efd2010-12-10 12:03:56 -08001008 void *additional_info)
Hank Janssenfceaf242009-07-13 15:34:54 -07001009{
1010 int ret;
K. Y. Srinivasan86c921a2011-09-13 10:59:54 -07001011 struct netvsc_device *net_device;
K. Y. Srinivasanb13cc342011-09-13 10:59:55 -07001012 struct rndis_device *rndis_device;
K. Y. Srinivasan3c4deba2011-09-13 10:59:56 -07001013 struct netvsc_device_info *device_info = additional_info;
KY Srinivasan4a0e70a2014-03-08 19:23:15 -08001014 struct ndis_offload_params offloads;
Haiyang Zhang5b54dac2014-04-21 10:20:28 -07001015 struct nvsp_message *init_packet;
1016 int t;
1017 struct ndis_recv_scale_cap rsscap;
1018 u32 rsscap_size = sizeof(struct ndis_recv_scale_cap);
Hank Janssenfceaf242009-07-13 15:34:54 -07001019
K. Y. Srinivasanb13cc342011-09-13 10:59:55 -07001020 rndis_device = get_rndis_device();
1021 if (!rndis_device)
K. Y. Srinivasan327efba2011-08-25 09:49:21 -07001022 return -ENODEV;
Hank Janssenfceaf242009-07-13 15:34:54 -07001023
Greg Kroah-Hartman0120ee02009-09-02 09:17:52 -07001024 /*
1025 * Let the inner driver handle this first to create the netvsc channel
1026 * NOTE! Once the channel is created, we may get a receive callback
1027 * (RndisFilterOnReceive()) before this call is completed
1028 */
K. Y. Srinivasance5bf662011-05-10 07:55:00 -07001029 ret = netvsc_device_add(dev, additional_info);
Greg Kroah-Hartman0120ee02009-09-02 09:17:52 -07001030 if (ret != 0) {
K. Y. Srinivasanb13cc342011-09-13 10:59:55 -07001031 kfree(rndis_device);
Hank Janssenfceaf242009-07-13 15:34:54 -07001032 return ret;
1033 }
1034
Bill Pemberton454f18a2009-07-27 16:47:24 -04001035
1036 /* Initialize the rndis device */
K. Y. Srinivasan86c921a2011-09-13 10:59:54 -07001037 net_device = hv_get_drvdata(dev);
Haiyang Zhang5b54dac2014-04-21 10:20:28 -07001038 net_device->num_chn = 1;
Hank Janssenfceaf242009-07-13 15:34:54 -07001039
K. Y. Srinivasanb13cc342011-09-13 10:59:55 -07001040 net_device->extension = rndis_device;
1041 rndis_device->net_dev = net_device;
Hank Janssenfceaf242009-07-13 15:34:54 -07001042
Bill Pemberton454f18a2009-07-27 16:47:24 -04001043 /* Send the rndis initialization message */
K. Y. Srinivasanb13cc342011-09-13 10:59:55 -07001044 ret = rndis_filter_init_device(rndis_device);
Greg Kroah-Hartman0120ee02009-09-02 09:17:52 -07001045 if (ret != 0) {
Haiyang Zhang5243e7b2012-07-25 08:08:42 +00001046 rndis_filter_device_remove(dev);
1047 return ret;
Hank Janssenfceaf242009-07-13 15:34:54 -07001048 }
1049
Bill Pemberton454f18a2009-07-27 16:47:24 -04001050 /* Get the mac address */
K. Y. Srinivasanb13cc342011-09-13 10:59:55 -07001051 ret = rndis_filter_query_device_mac(rndis_device);
Greg Kroah-Hartman0120ee02009-09-02 09:17:52 -07001052 if (ret != 0) {
Haiyang Zhang5243e7b2012-07-25 08:08:42 +00001053 rndis_filter_device_remove(dev);
1054 return ret;
Hank Janssenfceaf242009-07-13 15:34:54 -07001055 }
1056
K. Y. Srinivasan3c4deba2011-09-13 10:59:56 -07001057 memcpy(device_info->mac_adr, rndis_device->hw_mac_adr, ETH_ALEN);
Hank Janssenfceaf242009-07-13 15:34:54 -07001058
KY Srinivasan4a0e70a2014-03-08 19:23:15 -08001059 /* Turn on the offloads; the host supports all of the relevant
1060 * offloads.
1061 */
1062 memset(&offloads, 0, sizeof(struct ndis_offload_params));
1063 /* A value of zero means "no change"; now turn on what we
1064 * want.
1065 */
1066 offloads.ip_v4_csum = NDIS_OFFLOAD_PARAMETERS_TX_RX_ENABLED;
1067 offloads.tcp_ip_v4_csum = NDIS_OFFLOAD_PARAMETERS_TX_RX_ENABLED;
1068 offloads.udp_ip_v4_csum = NDIS_OFFLOAD_PARAMETERS_TX_RX_ENABLED;
1069 offloads.tcp_ip_v6_csum = NDIS_OFFLOAD_PARAMETERS_TX_RX_ENABLED;
1070 offloads.udp_ip_v6_csum = NDIS_OFFLOAD_PARAMETERS_TX_RX_ENABLED;
1071 offloads.lso_v2_ipv4 = NDIS_OFFLOAD_PARAMETERS_LSOV2_ENABLED;
1072
1073
1074 ret = rndis_filter_set_offload_params(dev, &offloads);
1075 if (ret)
1076 goto err_dev_remv;
1077
K. Y. Srinivasanb13cc342011-09-13 10:59:55 -07001078 rndis_filter_query_device_link_status(rndis_device);
Hank Janssenfceaf242009-07-13 15:34:54 -07001079
K. Y. Srinivasan6f274572011-09-13 15:21:27 -07001080 device_info->link_state = rndis_device->link_state;
Hank Jansseneb335bc2011-03-29 13:58:48 -07001081
K. Y. Srinivasan6f274572011-09-13 15:21:27 -07001082 dev_info(&dev->device, "Device MAC %pM link state %s\n",
K. Y. Srinivasanb13cc342011-09-13 10:59:55 -07001083 rndis_device->hw_mac_adr,
K. Y. Srinivasan6f274572011-09-13 15:21:27 -07001084 device_info->link_state ? "down" : "up");
Hank Janssenfceaf242009-07-13 15:34:54 -07001085
Haiyang Zhang5b54dac2014-04-21 10:20:28 -07001086 if (net_device->nvsp_version < NVSP_PROTOCOL_VERSION_5)
1087 return 0;
1088
1089 /* vRSS setup */
1090 memset(&rsscap, 0, rsscap_size);
1091 ret = rndis_filter_query_device(rndis_device,
1092 OID_GEN_RECEIVE_SCALE_CAPABILITIES,
1093 &rsscap, &rsscap_size);
1094 if (ret || rsscap.num_recv_que < 2)
1095 goto out;
1096
1097 net_device->num_chn = (num_online_cpus() < rsscap.num_recv_que) ?
1098 num_online_cpus() : rsscap.num_recv_que;
1099 if (net_device->num_chn == 1)
1100 goto out;
1101
1102 net_device->sub_cb_buf = vzalloc((net_device->num_chn - 1) *
1103 NETVSC_PACKET_SIZE);
1104 if (!net_device->sub_cb_buf) {
1105 net_device->num_chn = 1;
1106 dev_info(&dev->device, "No memory for subchannels.\n");
1107 goto out;
1108 }
1109
1110 vmbus_set_sc_create_callback(dev->channel, netvsc_sc_open);
1111
1112 init_packet = &net_device->channel_init_pkt;
1113 memset(init_packet, 0, sizeof(struct nvsp_message));
1114 init_packet->hdr.msg_type = NVSP_MSG5_TYPE_SUBCHANNEL;
1115 init_packet->msg.v5_msg.subchn_req.op = NVSP_SUBCHANNEL_ALLOCATE;
1116 init_packet->msg.v5_msg.subchn_req.num_subchannels =
1117 net_device->num_chn - 1;
1118 ret = vmbus_sendpacket(dev->channel, init_packet,
1119 sizeof(struct nvsp_message),
1120 (unsigned long)init_packet,
1121 VM_PKT_DATA_INBAND,
1122 VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
1123 if (ret)
1124 goto out;
1125 t = wait_for_completion_timeout(&net_device->channel_init_wait, 5*HZ);
1126 if (t == 0) {
1127 ret = -ETIMEDOUT;
1128 goto out;
1129 }
1130 if (init_packet->msg.v5_msg.subchn_comp.status !=
1131 NVSP_STAT_SUCCESS) {
1132 ret = -ENODEV;
1133 goto out;
1134 }
1135 net_device->num_chn = 1 +
1136 init_packet->msg.v5_msg.subchn_comp.num_subchannels;
1137
1138 vmbus_are_subchannels_present(dev->channel);
1139
1140 ret = rndis_filter_set_rss_param(rndis_device, net_device->num_chn);
1141
1142out:
1143 if (ret)
1144 net_device->num_chn = 1;
1145 return 0; /* return 0 because primary channel can be used alone */
KY Srinivasan4a0e70a2014-03-08 19:23:15 -08001146
1147err_dev_remv:
1148 rndis_filter_device_remove(dev);
1149 return ret;
Hank Janssenfceaf242009-07-13 15:34:54 -07001150}
1151
Haiyang Zhangdf06bcf2011-05-23 09:03:47 -07001152void rndis_filter_device_remove(struct hv_device *dev)
Hank Janssenfceaf242009-07-13 15:34:54 -07001153{
K. Y. Srinivasan2ddd5e52011-09-13 10:59:49 -07001154 struct netvsc_device *net_dev = hv_get_drvdata(dev);
Haiyang Zhang53d21fd2010-12-10 12:03:59 -08001155 struct rndis_device *rndis_dev = net_dev->extension;
Hank Janssenfceaf242009-07-13 15:34:54 -07001156
Bill Pemberton454f18a2009-07-27 16:47:24 -04001157 /* Halt and release the rndis device */
Haiyang Zhang9c26aa02010-12-10 12:03:57 -08001158 rndis_filter_halt_device(rndis_dev);
Hank Janssenfceaf242009-07-13 15:34:54 -07001159
Haiyang Zhangc2a4efd2010-12-10 12:03:56 -08001160 kfree(rndis_dev);
Haiyang Zhang53d21fd2010-12-10 12:03:59 -08001161 net_dev->extension = NULL;
Hank Janssenfceaf242009-07-13 15:34:54 -07001162
K. Y. Srinivasan3fae5c82011-05-10 07:55:02 -07001163 netvsc_device_remove(dev);
Hank Janssenfceaf242009-07-13 15:34:54 -07001164}
1165
Hank Janssenfceaf242009-07-13 15:34:54 -07001166
Haiyang Zhang9c26aa02010-12-10 12:03:57 -08001167int rndis_filter_open(struct hv_device *dev)
Hank Janssenfceaf242009-07-13 15:34:54 -07001168{
K. Y. Srinivasan86c921a2011-09-13 10:59:54 -07001169 struct netvsc_device *net_device = hv_get_drvdata(dev);
Hank Janssenfceaf242009-07-13 15:34:54 -07001170
K. Y. Srinivasan86c921a2011-09-13 10:59:54 -07001171 if (!net_device)
Bill Pemberton8a62d712010-05-05 15:27:47 -04001172 return -EINVAL;
1173
K. Y. Srinivasan86c921a2011-09-13 10:59:54 -07001174 return rndis_filter_open_device(net_device->extension);
Hank Janssenfceaf242009-07-13 15:34:54 -07001175}
1176
Haiyang Zhang9c26aa02010-12-10 12:03:57 -08001177int rndis_filter_close(struct hv_device *dev)
Hank Janssenfceaf242009-07-13 15:34:54 -07001178{
Haiyang Zhang5fccab32012-02-05 12:13:08 +00001179 struct netvsc_device *nvdev = hv_get_drvdata(dev);
Hank Janssenfceaf242009-07-13 15:34:54 -07001180
Haiyang Zhang5fccab32012-02-05 12:13:08 +00001181 if (!nvdev)
Bill Pemberton8a62d712010-05-05 15:27:47 -04001182 return -EINVAL;
1183
Haiyang Zhang5fccab32012-02-05 12:13:08 +00001184 return rndis_filter_close_device(nvdev->extension);
Hank Janssenfceaf242009-07-13 15:34:54 -07001185}