blob: 9118cea918821cb6bbe83a2f97a71134a58fd5dd [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 Zhang0f489172012-08-09 08:04:18 +000050
Haiyang Zhangc2a4efd2010-12-10 12:03:56 -080051 struct rndis_message request_msg;
Haiyang Zhang0f489172012-08-09 08:04:18 +000052 /*
Haiyang Zhanga3a6cab2012-10-02 05:30:24 +000053 * The buffer for the extended info after the RNDIS request message.
54 * It is referenced and sized in a similar way as response_ext.
Haiyang Zhang0f489172012-08-09 08:04:18 +000055 */
Haiyang Zhanga3a6cab2012-10-02 05:30:24 +000056 u8 request_ext[RNDIS_EXT_LEN];
Greg Kroah-Hartmane681b952009-08-28 16:26:27 -070057};
Hank Janssenfceaf242009-07-13 15:34:54 -070058
Haiyang Zhang9c26aa02010-12-10 12:03:57 -080059static struct rndis_device *get_rndis_device(void)
Hank Janssenfceaf242009-07-13 15:34:54 -070060{
Greg Kroah-Hartmane681b952009-08-28 16:26:27 -070061 struct rndis_device *device;
Hank Janssenfceaf242009-07-13 15:34:54 -070062
Greg Kroah-Hartmane681b952009-08-28 16:26:27 -070063 device = kzalloc(sizeof(struct rndis_device), GFP_KERNEL);
Hank Janssenfceaf242009-07-13 15:34:54 -070064 if (!device)
Hank Janssenfceaf242009-07-13 15:34:54 -070065 return NULL;
Hank Janssenfceaf242009-07-13 15:34:54 -070066
Greg Kroah-Hartman880fb892009-07-15 14:55:29 -070067 spin_lock_init(&device->request_lock);
Hank Janssenfceaf242009-07-13 15:34:54 -070068
Haiyang Zhangc2a4efd2010-12-10 12:03:56 -080069 INIT_LIST_HEAD(&device->req_list);
Hank Janssenfceaf242009-07-13 15:34:54 -070070
Haiyang Zhangc2a4efd2010-12-10 12:03:56 -080071 device->state = RNDIS_DEV_UNINITIALIZED;
Hank Janssenfceaf242009-07-13 15:34:54 -070072
73 return device;
74}
75
Haiyang Zhang9c26aa02010-12-10 12:03:57 -080076static struct rndis_request *get_rndis_request(struct rndis_device *dev,
Haiyang Zhangc2a4efd2010-12-10 12:03:56 -080077 u32 msg_type,
78 u32 msg_len)
Hank Janssenfceaf242009-07-13 15:34:54 -070079{
Greg Kroah-Hartmane681b952009-08-28 16:26:27 -070080 struct rndis_request *request;
Haiyang Zhangc2a4efd2010-12-10 12:03:56 -080081 struct rndis_message *rndis_msg;
Greg Kroah-Hartman9f33d052009-08-19 16:26:24 -070082 struct rndis_set_request *set;
Greg Kroah-Hartman880fb892009-07-15 14:55:29 -070083 unsigned long flags;
Hank Janssenfceaf242009-07-13 15:34:54 -070084
Greg Kroah-Hartmane681b952009-08-28 16:26:27 -070085 request = kzalloc(sizeof(struct rndis_request), GFP_KERNEL);
Hank Janssenfceaf242009-07-13 15:34:54 -070086 if (!request)
Hank Janssenfceaf242009-07-13 15:34:54 -070087 return NULL;
Hank Janssenfceaf242009-07-13 15:34:54 -070088
K. Y. Srinivasan98d79692011-05-10 07:55:42 -070089 init_completion(&request->wait_event);
Hank Janssenfceaf242009-07-13 15:34:54 -070090
Haiyang Zhangc2a4efd2010-12-10 12:03:56 -080091 rndis_msg = &request->request_msg;
Haiyang Zhanga388eb12010-12-10 12:04:00 -080092 rndis_msg->ndis_msg_type = msg_type;
93 rndis_msg->msg_len = msg_len;
Hank Janssenfceaf242009-07-13 15:34:54 -070094
Haiyang Zhang5b54dac2014-04-21 10:20:28 -070095 request->pkt.q_idx = 0;
96
Greg Kroah-Hartman0120ee02009-09-02 09:17:52 -070097 /*
98 * Set the request id. This field is always after the rndis header for
99 * request/response packet types so we just used the SetRequest as a
100 * template
101 */
Haiyang Zhanga388eb12010-12-10 12:04:00 -0800102 set = &rndis_msg->msg.set_req;
103 set->req_id = atomic_inc_return(&dev->new_req_id);
Hank Janssenfceaf242009-07-13 15:34:54 -0700104
Bill Pemberton454f18a2009-07-27 16:47:24 -0400105 /* Add to the request list */
Haiyang Zhangc2a4efd2010-12-10 12:03:56 -0800106 spin_lock_irqsave(&dev->request_lock, flags);
107 list_add_tail(&request->list_ent, &dev->req_list);
108 spin_unlock_irqrestore(&dev->request_lock, flags);
Hank Janssenfceaf242009-07-13 15:34:54 -0700109
110 return request;
111}
112
Haiyang Zhang9c26aa02010-12-10 12:03:57 -0800113static void put_rndis_request(struct rndis_device *dev,
Haiyang Zhangc2a4efd2010-12-10 12:03:56 -0800114 struct rndis_request *req)
Hank Janssenfceaf242009-07-13 15:34:54 -0700115{
Greg Kroah-Hartman880fb892009-07-15 14:55:29 -0700116 unsigned long flags;
117
Haiyang Zhangc2a4efd2010-12-10 12:03:56 -0800118 spin_lock_irqsave(&dev->request_lock, flags);
119 list_del(&req->list_ent);
120 spin_unlock_irqrestore(&dev->request_lock, flags);
Hank Janssenfceaf242009-07-13 15:34:54 -0700121
Haiyang Zhangc2a4efd2010-12-10 12:03:56 -0800122 kfree(req);
Hank Janssenfceaf242009-07-13 15:34:54 -0700123}
124
Haiyang Zhang729a2842011-05-27 06:21:54 -0700125static void dump_rndis_message(struct hv_device *hv_dev,
126 struct rndis_message *rndis_msg)
Hank Janssenfceaf242009-07-13 15:34:54 -0700127{
K. Y. Srinivasan2ddd5e52011-09-13 10:59:49 -0700128 struct net_device *netdev;
129 struct netvsc_device *net_device;
130
131 net_device = hv_get_drvdata(hv_dev);
132 netdev = net_device->ndev;
Haiyang Zhang729a2842011-05-27 06:21:54 -0700133
Haiyang Zhanga388eb12010-12-10 12:04:00 -0800134 switch (rndis_msg->ndis_msg_type) {
Linus Walleij51491162012-05-11 22:17:07 +0000135 case RNDIS_MSG_PACKET:
136 netdev_dbg(netdev, "RNDIS_MSG_PACKET (len %u, "
Greg Kroah-Hartman0120ee02009-09-02 09:17:52 -0700137 "data offset %u data len %u, # oob %u, "
138 "oob offset %u, oob len %u, pkt offset %u, "
Haiyang Zhang729a2842011-05-27 06:21:54 -0700139 "pkt len %u\n",
Haiyang Zhanga388eb12010-12-10 12:04:00 -0800140 rndis_msg->msg_len,
141 rndis_msg->msg.pkt.data_offset,
142 rndis_msg->msg.pkt.data_len,
143 rndis_msg->msg.pkt.num_oob_data_elements,
144 rndis_msg->msg.pkt.oob_data_offset,
145 rndis_msg->msg.pkt.oob_data_len,
146 rndis_msg->msg.pkt.per_pkt_info_offset,
147 rndis_msg->msg.pkt.per_pkt_info_len);
Hank Janssenfceaf242009-07-13 15:34:54 -0700148 break;
149
Linus Walleij51491162012-05-11 22:17:07 +0000150 case RNDIS_MSG_INIT_C:
151 netdev_dbg(netdev, "RNDIS_MSG_INIT_C "
Greg Kroah-Hartman0120ee02009-09-02 09:17:52 -0700152 "(len %u, id 0x%x, status 0x%x, major %d, minor %d, "
153 "device flags %d, max xfer size 0x%x, max pkts %u, "
Haiyang Zhang729a2842011-05-27 06:21:54 -0700154 "pkt aligned %u)\n",
Haiyang Zhanga388eb12010-12-10 12:04:00 -0800155 rndis_msg->msg_len,
156 rndis_msg->msg.init_complete.req_id,
157 rndis_msg->msg.init_complete.status,
158 rndis_msg->msg.init_complete.major_ver,
159 rndis_msg->msg.init_complete.minor_ver,
160 rndis_msg->msg.init_complete.dev_flags,
161 rndis_msg->msg.init_complete.max_xfer_size,
162 rndis_msg->msg.init_complete.
163 max_pkt_per_msg,
164 rndis_msg->msg.init_complete.
165 pkt_alignment_factor);
Hank Janssenfceaf242009-07-13 15:34:54 -0700166 break;
167
Linus Walleij51491162012-05-11 22:17:07 +0000168 case RNDIS_MSG_QUERY_C:
169 netdev_dbg(netdev, "RNDIS_MSG_QUERY_C "
Greg Kroah-Hartman0120ee02009-09-02 09:17:52 -0700170 "(len %u, id 0x%x, status 0x%x, buf len %u, "
Haiyang Zhang729a2842011-05-27 06:21:54 -0700171 "buf offset %u)\n",
Haiyang Zhanga388eb12010-12-10 12:04:00 -0800172 rndis_msg->msg_len,
173 rndis_msg->msg.query_complete.req_id,
174 rndis_msg->msg.query_complete.status,
175 rndis_msg->msg.query_complete.
176 info_buflen,
177 rndis_msg->msg.query_complete.
178 info_buf_offset);
Hank Janssenfceaf242009-07-13 15:34:54 -0700179 break;
180
Linus Walleij51491162012-05-11 22:17:07 +0000181 case RNDIS_MSG_SET_C:
Haiyang Zhang729a2842011-05-27 06:21:54 -0700182 netdev_dbg(netdev,
Linus Walleij51491162012-05-11 22:17:07 +0000183 "RNDIS_MSG_SET_C (len %u, id 0x%x, status 0x%x)\n",
Haiyang Zhanga388eb12010-12-10 12:04:00 -0800184 rndis_msg->msg_len,
185 rndis_msg->msg.set_complete.req_id,
186 rndis_msg->msg.set_complete.status);
Hank Janssenfceaf242009-07-13 15:34:54 -0700187 break;
188
Linus Walleij51491162012-05-11 22:17:07 +0000189 case RNDIS_MSG_INDICATE:
190 netdev_dbg(netdev, "RNDIS_MSG_INDICATE "
Haiyang Zhang729a2842011-05-27 06:21:54 -0700191 "(len %u, status 0x%x, buf len %u, buf offset %u)\n",
Haiyang Zhanga388eb12010-12-10 12:04:00 -0800192 rndis_msg->msg_len,
193 rndis_msg->msg.indicate_status.status,
194 rndis_msg->msg.indicate_status.status_buflen,
195 rndis_msg->msg.indicate_status.status_buf_offset);
Hank Janssenfceaf242009-07-13 15:34:54 -0700196 break;
197
198 default:
Haiyang Zhang729a2842011-05-27 06:21:54 -0700199 netdev_dbg(netdev, "0x%x (len %u)\n",
Haiyang Zhanga388eb12010-12-10 12:04:00 -0800200 rndis_msg->ndis_msg_type,
201 rndis_msg->msg_len);
Hank Janssenfceaf242009-07-13 15:34:54 -0700202 break;
203 }
204}
205
Haiyang Zhang9c26aa02010-12-10 12:03:57 -0800206static int rndis_filter_send_request(struct rndis_device *dev,
Haiyang Zhangc2a4efd2010-12-10 12:03:56 -0800207 struct rndis_request *req)
Hank Janssenfceaf242009-07-13 15:34:54 -0700208{
Greg Kroah-Hartman0120ee02009-09-02 09:17:52 -0700209 int ret;
Nicolas Palix4193d4f2009-07-29 14:10:10 +0200210 struct hv_netvsc_packet *packet;
KY Srinivasanb08cc792015-03-29 21:08:42 -0700211 struct hv_page_buffer page_buf[2];
Hank Janssenfceaf242009-07-13 15:34:54 -0700212
Bill Pemberton454f18a2009-07-27 16:47:24 -0400213 /* Setup the packet to send it */
Haiyang Zhangc2a4efd2010-12-10 12:03:56 -0800214 packet = &req->pkt;
Hank Janssenfceaf242009-07-13 15:34:54 -0700215
Haiyang Zhang72a2f5b2010-12-10 12:03:58 -0800216 packet->is_data_pkt = false;
Haiyang Zhanga388eb12010-12-10 12:04:00 -0800217 packet->total_data_buflen = req->request_msg.msg_len;
Haiyang Zhang72a2f5b2010-12-10 12:03:58 -0800218 packet->page_buf_cnt = 1;
KY Srinivasanb08cc792015-03-29 21:08:42 -0700219 packet->page_buf = page_buf;
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;
Haiyang Zhang7c3877f2015-03-26 09:03:37 -0700240 packet->xmit_more = false;
Hank Janssenfceaf242009-07-13 15:34:54 -0700241
K. Y. Srinivasan0ec6ff42011-05-12 19:34:55 -0700242 ret = netvsc_send(dev->net_dev->dev, packet);
Hank Janssenfceaf242009-07-13 15:34:54 -0700243 return ret;
244}
245
Haiyang Zhang1b07da52014-03-04 14:11:06 -0800246static void rndis_set_link_state(struct rndis_device *rdev,
247 struct rndis_request *request)
248{
249 u32 link_status;
250 struct rndis_query_complete *query_complete;
251
252 query_complete = &request->response_msg.msg.query_complete;
253
254 if (query_complete->status == RNDIS_STATUS_SUCCESS &&
255 query_complete->info_buflen == sizeof(u32)) {
256 memcpy(&link_status, (void *)((unsigned long)query_complete +
257 query_complete->info_buf_offset), sizeof(u32));
258 rdev->link_state = link_status != 0;
259 }
260}
261
Haiyang Zhang9c26aa02010-12-10 12:03:57 -0800262static void rndis_filter_receive_response(struct rndis_device *dev,
Haiyang Zhangc2a4efd2010-12-10 12:03:56 -0800263 struct rndis_message *resp)
Hank Janssenfceaf242009-07-13 15:34:54 -0700264{
Greg Kroah-Hartmane681b952009-08-28 16:26:27 -0700265 struct rndis_request *request = NULL;
Greg Kroah-Hartman0e727612009-07-15 12:46:44 -0700266 bool found = false;
Greg Kroah-Hartman880fb892009-07-15 14:55:29 -0700267 unsigned long flags;
K. Y. Srinivasan2ddd5e52011-09-13 10:59:49 -0700268 struct net_device *ndev;
269
270 ndev = dev->net_dev->ndev;
Hank Janssenfceaf242009-07-13 15:34:54 -0700271
Haiyang Zhangc2a4efd2010-12-10 12:03:56 -0800272 spin_lock_irqsave(&dev->request_lock, flags);
273 list_for_each_entry(request, &dev->req_list, list_ent) {
Greg Kroah-Hartman0120ee02009-09-02 09:17:52 -0700274 /*
275 * All request/response message contains RequestId as the 1st
276 * field
277 */
Haiyang Zhanga388eb12010-12-10 12:04:00 -0800278 if (request->request_msg.msg.init_req.req_id
279 == resp->msg.init_complete.req_id) {
Greg Kroah-Hartman0e727612009-07-15 12:46:44 -0700280 found = true;
Hank Janssenfceaf242009-07-13 15:34:54 -0700281 break;
282 }
283 }
Haiyang Zhangc2a4efd2010-12-10 12:03:56 -0800284 spin_unlock_irqrestore(&dev->request_lock, flags);
Hank Janssenfceaf242009-07-13 15:34:54 -0700285
Greg Kroah-Hartman0120ee02009-09-02 09:17:52 -0700286 if (found) {
Haiyang Zhanga3a6cab2012-10-02 05:30:24 +0000287 if (resp->msg_len <=
288 sizeof(struct rndis_message) + RNDIS_EXT_LEN) {
Haiyang Zhangc2a4efd2010-12-10 12:03:56 -0800289 memcpy(&request->response_msg, resp,
Haiyang Zhanga388eb12010-12-10 12:04:00 -0800290 resp->msg_len);
Haiyang Zhang1b07da52014-03-04 14:11:06 -0800291 if (request->request_msg.ndis_msg_type ==
292 RNDIS_MSG_QUERY && request->request_msg.msg.
293 query_req.oid == RNDIS_OID_GEN_MEDIA_CONNECT_STATUS)
294 rndis_set_link_state(dev, request);
Greg Kroah-Hartman0120ee02009-09-02 09:17:52 -0700295 } else {
Haiyang Zhangd9871152011-09-01 12:19:41 -0700296 netdev_err(ndev,
Hank Jansseneb335bc2011-03-29 13:58:48 -0700297 "rndis response buffer overflow "
298 "detected (size %u max %zu)\n",
299 resp->msg_len,
KY Srinivasan86eedac2014-02-16 16:38:43 -0800300 sizeof(struct rndis_message));
Hank Janssenfceaf242009-07-13 15:34:54 -0700301
Haiyang Zhanga388eb12010-12-10 12:04:00 -0800302 if (resp->ndis_msg_type ==
Linus Walleij51491162012-05-11 22:17:07 +0000303 RNDIS_MSG_RESET_C) {
Greg Kroah-Hartman0120ee02009-09-02 09:17:52 -0700304 /* does not have a request id field */
Haiyang Zhanga388eb12010-12-10 12:04:00 -0800305 request->response_msg.msg.reset_complete.
Linus Walleij007e5c82012-05-11 22:15:59 +0000306 status = RNDIS_STATUS_BUFFER_OVERFLOW;
Greg Kroah-Hartman0120ee02009-09-02 09:17:52 -0700307 } else {
Haiyang Zhanga388eb12010-12-10 12:04:00 -0800308 request->response_msg.msg.
309 init_complete.status =
Linus Walleij007e5c82012-05-11 22:15:59 +0000310 RNDIS_STATUS_BUFFER_OVERFLOW;
Hank Janssenfceaf242009-07-13 15:34:54 -0700311 }
312 }
313
K. Y. Srinivasan98d79692011-05-10 07:55:42 -0700314 complete(&request->wait_event);
Greg Kroah-Hartman0120ee02009-09-02 09:17:52 -0700315 } else {
Haiyang Zhangd9871152011-09-01 12:19:41 -0700316 netdev_err(ndev,
Hank Jansseneb335bc2011-03-29 13:58:48 -0700317 "no rndis request found for this response "
318 "(id 0x%x res type 0x%x)\n",
319 resp->msg.init_complete.req_id,
320 resp->ndis_msg_type);
Hank Janssenfceaf242009-07-13 15:34:54 -0700321 }
Hank Janssenfceaf242009-07-13 15:34:54 -0700322}
323
Haiyang Zhang1f5f3a72012-03-12 10:20:50 +0000324/*
325 * Get the Per-Packet-Info with the specified type
326 * return NULL if not found.
327 */
328static inline void *rndis_get_ppi(struct rndis_packet *rpkt, u32 type)
329{
330 struct rndis_per_packet_info *ppi;
331 int len;
332
333 if (rpkt->per_pkt_info_offset == 0)
334 return NULL;
335
336 ppi = (struct rndis_per_packet_info *)((ulong)rpkt +
337 rpkt->per_pkt_info_offset);
338 len = rpkt->per_pkt_info_len;
339
340 while (len > 0) {
341 if (ppi->type == type)
342 return (void *)((ulong)ppi + ppi->ppi_offset);
343 len -= ppi->size;
344 ppi = (struct rndis_per_packet_info *)((ulong)ppi + ppi->size);
345 }
346
347 return NULL;
348}
349
Haiyang Zhang9c26aa02010-12-10 12:03:57 -0800350static void rndis_filter_receive_data(struct rndis_device *dev,
Haiyang Zhangc2a4efd2010-12-10 12:03:56 -0800351 struct rndis_message *msg,
352 struct hv_netvsc_packet *pkt)
Hank Janssenfceaf242009-07-13 15:34:54 -0700353{
Haiyang Zhangc2a4efd2010-12-10 12:03:56 -0800354 struct rndis_packet *rndis_pkt;
355 u32 data_offset;
Haiyang Zhang1f5f3a72012-03-12 10:20:50 +0000356 struct ndis_pkt_8021q_info *vlan;
KY Srinivasane3d605e2014-03-08 19:23:16 -0800357 struct ndis_tcp_ip_checksum_info *csum_info;
Hank Janssenfceaf242009-07-13 15:34:54 -0700358
Haiyang Zhanga388eb12010-12-10 12:04:00 -0800359 rndis_pkt = &msg->msg.pkt;
Hank Janssenfceaf242009-07-13 15:34:54 -0700360
Bill Pemberton454f18a2009-07-27 16:47:24 -0400361 /* Remove the rndis header and pass it back up the stack */
Haiyang Zhanga388eb12010-12-10 12:04:00 -0800362 data_offset = RNDIS_HEADER_SIZE + rndis_pkt->data_offset;
Hank Janssenfceaf242009-07-13 15:34:54 -0700363
Haiyang Zhang72a2f5b2010-12-10 12:03:58 -0800364 pkt->total_data_buflen -= data_offset;
Wei Yongjun4b8a8bc2012-02-01 20:17:23 +0000365
366 /*
367 * Make sure we got a valid RNDIS message, now total_data_buflen
368 * should be the data packet size plus the trailer padding size
369 */
370 if (pkt->total_data_buflen < rndis_pkt->data_len) {
371 netdev_err(dev->net_dev->ndev, "rndis message buffer "
372 "overflow detected (got %u, min %u)"
373 "...dropping this message!\n",
374 pkt->total_data_buflen, rndis_pkt->data_len);
375 return;
376 }
377
378 /*
379 * Remove the rndis trailer padding from rndis packet message
380 * rndis_pkt->data_len tell us the real data length, we only copy
381 * the data packet to the stack, without the rndis trailer padding
382 */
383 pkt->total_data_buflen = rndis_pkt->data_len;
Haiyang Zhang45326342011-12-15 13:45:15 -0800384 pkt->data = (void *)((unsigned long)pkt->data + data_offset);
Haiyang Zhang669c1fc2011-09-01 12:19:47 -0700385
Haiyang Zhang1f5f3a72012-03-12 10:20:50 +0000386 vlan = rndis_get_ppi(rndis_pkt, IEEE_8021Q_INFO);
387 if (vlan) {
388 pkt->vlan_tci = VLAN_TAG_PRESENT | vlan->vlanid |
389 (vlan->pri << VLAN_PRIO_SHIFT);
390 } else {
391 pkt->vlan_tci = 0;
392 }
393
KY Srinivasane3d605e2014-03-08 19:23:16 -0800394 csum_info = rndis_get_ppi(rndis_pkt, TCPIP_CHKSUM_PKTINFO);
395 netvsc_recv_callback(dev->net_dev->dev, pkt, csum_info);
Hank Janssenfceaf242009-07-13 15:34:54 -0700396}
397
K. Y. Srinivasan5fcc4112011-05-12 19:34:52 -0700398int rndis_filter_receive(struct hv_device *dev,
Haiyang Zhangc2a4efd2010-12-10 12:03:56 -0800399 struct hv_netvsc_packet *pkt)
Hank Janssenfceaf242009-07-13 15:34:54 -0700400{
K. Y. Srinivasan2ddd5e52011-09-13 10:59:49 -0700401 struct netvsc_device *net_dev = hv_get_drvdata(dev);
Haiyang Zhangc2a4efd2010-12-10 12:03:56 -0800402 struct rndis_device *rndis_dev;
Haiyang Zhangef31bef2012-03-12 10:20:49 +0000403 struct rndis_message *rndis_msg;
K. Y. Srinivasan2ddd5e52011-09-13 10:59:49 -0700404 struct net_device *ndev;
Haiyang Zhang63f69212012-10-02 05:30:23 +0000405 int ret = 0;
K. Y. Srinivasan2ddd5e52011-09-13 10:59:49 -0700406
Haiyang Zhang63f69212012-10-02 05:30:23 +0000407 if (!net_dev) {
408 ret = -EINVAL;
409 goto exit;
410 }
Bill Pemberton8a62d712010-05-05 15:27:47 -0400411
K. Y. Srinivasan715a4802011-10-06 10:10:56 -0700412 ndev = net_dev->ndev;
413
Bill Pemberton454f18a2009-07-27 16:47:24 -0400414 /* Make sure the rndis device state is initialized */
Haiyang Zhang53d21fd2010-12-10 12:03:59 -0800415 if (!net_dev->extension) {
Haiyang Zhangd9871152011-09-01 12:19:41 -0700416 netdev_err(ndev, "got rndis message but no rndis device - "
Hank Jansseneb335bc2011-03-29 13:58:48 -0700417 "dropping this message!\n");
Haiyang Zhang63f69212012-10-02 05:30:23 +0000418 ret = -ENODEV;
419 goto exit;
Hank Janssenfceaf242009-07-13 15:34:54 -0700420 }
421
Haiyang Zhang53d21fd2010-12-10 12:03:59 -0800422 rndis_dev = (struct rndis_device *)net_dev->extension;
Haiyang Zhangc2a4efd2010-12-10 12:03:56 -0800423 if (rndis_dev->state == RNDIS_DEV_UNINITIALIZED) {
Haiyang Zhangd9871152011-09-01 12:19:41 -0700424 netdev_err(ndev, "got rndis message but rndis device "
Hank Jansseneb335bc2011-03-29 13:58:48 -0700425 "uninitialized...dropping this message!\n");
Haiyang Zhang63f69212012-10-02 05:30:23 +0000426 ret = -ENODEV;
427 goto exit;
Hank Janssenfceaf242009-07-13 15:34:54 -0700428 }
429
Haiyang Zhangef31bef2012-03-12 10:20:49 +0000430 rndis_msg = pkt->data;
Hank Janssenfceaf242009-07-13 15:34:54 -0700431
Simon Xiao3f300ff2015-04-28 01:05:17 -0700432 if (netif_msg_rx_err(net_dev->nd_ctx))
433 dump_rndis_message(dev, rndis_msg);
Hank Janssenfceaf242009-07-13 15:34:54 -0700434
Haiyang Zhangef31bef2012-03-12 10:20:49 +0000435 switch (rndis_msg->ndis_msg_type) {
Linus Walleij51491162012-05-11 22:17:07 +0000436 case RNDIS_MSG_PACKET:
Greg Kroah-Hartman0120ee02009-09-02 09:17:52 -0700437 /* data msg */
Haiyang Zhangef31bef2012-03-12 10:20:49 +0000438 rndis_filter_receive_data(rndis_dev, rndis_msg, pkt);
Hank Janssenfceaf242009-07-13 15:34:54 -0700439 break;
440
Linus Walleij51491162012-05-11 22:17:07 +0000441 case RNDIS_MSG_INIT_C:
442 case RNDIS_MSG_QUERY_C:
443 case RNDIS_MSG_SET_C:
Greg Kroah-Hartman0120ee02009-09-02 09:17:52 -0700444 /* completion msgs */
Haiyang Zhangef31bef2012-03-12 10:20:49 +0000445 rndis_filter_receive_response(rndis_dev, rndis_msg);
Hank Janssenfceaf242009-07-13 15:34:54 -0700446 break;
447
Linus Walleij51491162012-05-11 22:17:07 +0000448 case RNDIS_MSG_INDICATE:
Greg Kroah-Hartman0120ee02009-09-02 09:17:52 -0700449 /* notification msgs */
Haiyang Zhang3a494e72014-06-19 18:34:36 -0700450 netvsc_linkstatus_callback(dev, rndis_msg);
Hank Janssenfceaf242009-07-13 15:34:54 -0700451 break;
452 default:
Haiyang Zhangd9871152011-09-01 12:19:41 -0700453 netdev_err(ndev,
Hank Jansseneb335bc2011-03-29 13:58:48 -0700454 "unhandled rndis message (type %u len %u)\n",
Haiyang Zhangef31bef2012-03-12 10:20:49 +0000455 rndis_msg->ndis_msg_type,
456 rndis_msg->msg_len);
Hank Janssenfceaf242009-07-13 15:34:54 -0700457 break;
458 }
459
Haiyang Zhang63f69212012-10-02 05:30:23 +0000460exit:
461 if (ret != 0)
462 pkt->status = NVSP_STAT_FAIL;
463
464 return ret;
Hank Janssenfceaf242009-07-13 15:34:54 -0700465}
466
Haiyang Zhang9c26aa02010-12-10 12:03:57 -0800467static int rndis_filter_query_device(struct rndis_device *dev, u32 oid,
Haiyang Zhangc2a4efd2010-12-10 12:03:56 -0800468 void *result, u32 *result_size)
Hank Janssenfceaf242009-07-13 15:34:54 -0700469{
Greg Kroah-Hartmane681b952009-08-28 16:26:27 -0700470 struct rndis_request *request;
Haiyang Zhangc2a4efd2010-12-10 12:03:56 -0800471 u32 inresult_size = *result_size;
Greg Kroah-Hartman9f33d052009-08-19 16:26:24 -0700472 struct rndis_query_request *query;
Haiyang Zhangc2a4efd2010-12-10 12:03:56 -0800473 struct rndis_query_complete *query_complete;
Greg Kroah-Hartman0120ee02009-09-02 09:17:52 -0700474 int ret = 0;
Nicholas Mc Guire999028c2015-01-25 15:48:23 +0100475 unsigned long t;
Hank Janssenfceaf242009-07-13 15:34:54 -0700476
Haiyang Zhangc2a4efd2010-12-10 12:03:56 -0800477 if (!result)
Bill Pemberton8a62d712010-05-05 15:27:47 -0400478 return -EINVAL;
Hank Janssenfceaf242009-07-13 15:34:54 -0700479
Haiyang Zhangc2a4efd2010-12-10 12:03:56 -0800480 *result_size = 0;
Linus Walleij51491162012-05-11 22:17:07 +0000481 request = get_rndis_request(dev, RNDIS_MSG_QUERY,
Greg Kroah-Hartman0120ee02009-09-02 09:17:52 -0700482 RNDIS_MESSAGE_SIZE(struct rndis_query_request));
483 if (!request) {
K. Y. Srinivasande6e0582011-08-25 09:49:18 -0700484 ret = -ENOMEM;
K. Y. Srinivasan1c627872011-08-25 09:49:24 -0700485 goto cleanup;
Hank Janssenfceaf242009-07-13 15:34:54 -0700486 }
487
Bill Pemberton454f18a2009-07-27 16:47:24 -0400488 /* Setup the rndis query */
Haiyang Zhanga388eb12010-12-10 12:04:00 -0800489 query = &request->request_msg.msg.query_req;
490 query->oid = oid;
491 query->info_buf_offset = sizeof(struct rndis_query_request);
492 query->info_buflen = 0;
493 query->dev_vc_handle = 0;
Hank Janssenfceaf242009-07-13 15:34:54 -0700494
Haiyang Zhang5b54dac2014-04-21 10:20:28 -0700495 if (oid == OID_GEN_RECEIVE_SCALE_CAPABILITIES) {
496 struct ndis_recv_scale_cap *cap;
497
498 request->request_msg.msg_len +=
499 sizeof(struct ndis_recv_scale_cap);
500 query->info_buflen = sizeof(struct ndis_recv_scale_cap);
501 cap = (struct ndis_recv_scale_cap *)((unsigned long)query +
502 query->info_buf_offset);
503 cap->hdr.type = NDIS_OBJECT_TYPE_RSS_CAPABILITIES;
504 cap->hdr.rev = NDIS_RECEIVE_SCALE_CAPABILITIES_REVISION_2;
505 cap->hdr.size = sizeof(struct ndis_recv_scale_cap);
506 }
507
Haiyang Zhang9c26aa02010-12-10 12:03:57 -0800508 ret = rndis_filter_send_request(dev, request);
Hank Janssenfceaf242009-07-13 15:34:54 -0700509 if (ret != 0)
K. Y. Srinivasan1c627872011-08-25 09:49:24 -0700510 goto cleanup;
Hank Janssenfceaf242009-07-13 15:34:54 -0700511
K. Y. Srinivasan5c5781b32011-06-16 13:16:35 -0700512 t = wait_for_completion_timeout(&request->wait_event, 5*HZ);
K. Y. Srinivasan98d79692011-05-10 07:55:42 -0700513 if (t == 0) {
K. Y. Srinivasan0c3b7b22011-02-11 09:59:43 -0800514 ret = -ETIMEDOUT;
K. Y. Srinivasan1c627872011-08-25 09:49:24 -0700515 goto cleanup;
K. Y. Srinivasan0c3b7b22011-02-11 09:59:43 -0800516 }
Hank Janssenfceaf242009-07-13 15:34:54 -0700517
Bill Pemberton454f18a2009-07-27 16:47:24 -0400518 /* Copy the response back */
Haiyang Zhanga388eb12010-12-10 12:04:00 -0800519 query_complete = &request->response_msg.msg.query_complete;
Hank Janssenfceaf242009-07-13 15:34:54 -0700520
Haiyang Zhanga388eb12010-12-10 12:04:00 -0800521 if (query_complete->info_buflen > inresult_size) {
Hank Janssenfceaf242009-07-13 15:34:54 -0700522 ret = -1;
K. Y. Srinivasan1c627872011-08-25 09:49:24 -0700523 goto cleanup;
Hank Janssenfceaf242009-07-13 15:34:54 -0700524 }
525
Haiyang Zhangc2a4efd2010-12-10 12:03:56 -0800526 memcpy(result,
527 (void *)((unsigned long)query_complete +
Haiyang Zhanga388eb12010-12-10 12:04:00 -0800528 query_complete->info_buf_offset),
529 query_complete->info_buflen);
Hank Janssenfceaf242009-07-13 15:34:54 -0700530
Haiyang Zhanga388eb12010-12-10 12:04:00 -0800531 *result_size = query_complete->info_buflen;
Hank Janssenfceaf242009-07-13 15:34:54 -0700532
K. Y. Srinivasan1c627872011-08-25 09:49:24 -0700533cleanup:
Hank Janssenfceaf242009-07-13 15:34:54 -0700534 if (request)
Haiyang Zhang9c26aa02010-12-10 12:03:57 -0800535 put_rndis_request(dev, request);
Hank Janssenfceaf242009-07-13 15:34:54 -0700536
537 return ret;
538}
539
Haiyang Zhang9c26aa02010-12-10 12:03:57 -0800540static int rndis_filter_query_device_mac(struct rndis_device *dev)
Hank Janssenfceaf242009-07-13 15:34:54 -0700541{
Stephen Hemminger9f8bd8b2010-05-04 09:58:54 -0700542 u32 size = ETH_ALEN;
Hank Janssenfceaf242009-07-13 15:34:54 -0700543
Haiyang Zhang9c26aa02010-12-10 12:03:57 -0800544 return rndis_filter_query_device(dev,
Greg Kroah-Hartman0120ee02009-09-02 09:17:52 -0700545 RNDIS_OID_802_3_PERMANENT_ADDRESS,
Haiyang Zhangc2a4efd2010-12-10 12:03:56 -0800546 dev->hw_mac_adr, &size);
Hank Janssenfceaf242009-07-13 15:34:54 -0700547}
548
Haiyang Zhang1ce09e82012-07-10 07:19:22 +0000549#define NWADR_STR "NetworkAddress"
550#define NWADR_STRLEN 14
551
552int rndis_filter_set_device_mac(struct hv_device *hdev, char *mac)
553{
554 struct netvsc_device *nvdev = hv_get_drvdata(hdev);
555 struct rndis_device *rdev = nvdev->extension;
556 struct net_device *ndev = nvdev->ndev;
557 struct rndis_request *request;
558 struct rndis_set_request *set;
559 struct rndis_config_parameter_info *cpi;
560 wchar_t *cfg_nwadr, *cfg_mac;
561 struct rndis_set_complete *set_complete;
562 char macstr[2*ETH_ALEN+1];
563 u32 extlen = sizeof(struct rndis_config_parameter_info) +
564 2*NWADR_STRLEN + 4*ETH_ALEN;
Nicholas Mc Guire999028c2015-01-25 15:48:23 +0100565 int ret;
566 unsigned long t;
Haiyang Zhang1ce09e82012-07-10 07:19:22 +0000567
568 request = get_rndis_request(rdev, RNDIS_MSG_SET,
569 RNDIS_MESSAGE_SIZE(struct rndis_set_request) + extlen);
570 if (!request)
571 return -ENOMEM;
572
573 set = &request->request_msg.msg.set_req;
574 set->oid = RNDIS_OID_GEN_RNDIS_CONFIG_PARAMETER;
575 set->info_buflen = extlen;
576 set->info_buf_offset = sizeof(struct rndis_set_request);
577 set->dev_vc_handle = 0;
578
579 cpi = (struct rndis_config_parameter_info *)((ulong)set +
580 set->info_buf_offset);
581 cpi->parameter_name_offset =
582 sizeof(struct rndis_config_parameter_info);
583 /* Multiply by 2 because host needs 2 bytes (utf16) for each char */
584 cpi->parameter_name_length = 2*NWADR_STRLEN;
585 cpi->parameter_type = RNDIS_CONFIG_PARAM_TYPE_STRING;
586 cpi->parameter_value_offset =
587 cpi->parameter_name_offset + cpi->parameter_name_length;
588 /* Multiply by 4 because each MAC byte displayed as 2 utf16 chars */
589 cpi->parameter_value_length = 4*ETH_ALEN;
590
591 cfg_nwadr = (wchar_t *)((ulong)cpi + cpi->parameter_name_offset);
592 cfg_mac = (wchar_t *)((ulong)cpi + cpi->parameter_value_offset);
593 ret = utf8s_to_utf16s(NWADR_STR, NWADR_STRLEN, UTF16_HOST_ENDIAN,
594 cfg_nwadr, NWADR_STRLEN);
595 if (ret < 0)
596 goto cleanup;
597 snprintf(macstr, 2*ETH_ALEN+1, "%pm", mac);
598 ret = utf8s_to_utf16s(macstr, 2*ETH_ALEN, UTF16_HOST_ENDIAN,
599 cfg_mac, 2*ETH_ALEN);
600 if (ret < 0)
601 goto cleanup;
602
603 ret = rndis_filter_send_request(rdev, request);
604 if (ret != 0)
605 goto cleanup;
606
607 t = wait_for_completion_timeout(&request->wait_event, 5*HZ);
608 if (t == 0) {
609 netdev_err(ndev, "timeout before we got a set response...\n");
610 /*
611 * can't put_rndis_request, since we may still receive a
612 * send-completion.
613 */
614 return -EBUSY;
615 } else {
616 set_complete = &request->response_msg.msg.set_complete;
Haiyang Zhangb02a8062012-11-30 09:23:41 +0000617 if (set_complete->status != RNDIS_STATUS_SUCCESS) {
618 netdev_err(ndev, "Fail to set MAC on host side:0x%x\n",
619 set_complete->status);
Haiyang Zhang1ce09e82012-07-10 07:19:22 +0000620 ret = -EINVAL;
Haiyang Zhangb02a8062012-11-30 09:23:41 +0000621 }
Haiyang Zhang1ce09e82012-07-10 07:19:22 +0000622 }
623
624cleanup:
625 put_rndis_request(rdev, request);
626 return ret;
627}
628
Lad, Prabhakarda19fcd2015-02-05 15:06:33 +0000629static int
630rndis_filter_set_offload_params(struct hv_device *hdev,
KY Srinivasan4a0e70a2014-03-08 19:23:15 -0800631 struct ndis_offload_params *req_offloads)
632{
633 struct netvsc_device *nvdev = hv_get_drvdata(hdev);
634 struct rndis_device *rdev = nvdev->extension;
635 struct net_device *ndev = nvdev->ndev;
636 struct rndis_request *request;
637 struct rndis_set_request *set;
638 struct ndis_offload_params *offload_params;
639 struct rndis_set_complete *set_complete;
640 u32 extlen = sizeof(struct ndis_offload_params);
Nicholas Mc Guire999028c2015-01-25 15:48:23 +0100641 int ret;
642 unsigned long t;
KY Srinivasanaf9893a2014-04-09 15:00:47 -0700643 u32 vsp_version = nvdev->nvsp_version;
644
645 if (vsp_version <= NVSP_PROTOCOL_VERSION_4) {
646 extlen = VERSION_4_OFFLOAD_SIZE;
647 /* On NVSP_PROTOCOL_VERSION_4 and below, we do not support
648 * UDP checksum offload.
649 */
650 req_offloads->udp_ip_v4_csum = 0;
651 req_offloads->udp_ip_v6_csum = 0;
652 }
KY Srinivasan4a0e70a2014-03-08 19:23:15 -0800653
654 request = get_rndis_request(rdev, RNDIS_MSG_SET,
655 RNDIS_MESSAGE_SIZE(struct rndis_set_request) + extlen);
656 if (!request)
657 return -ENOMEM;
658
659 set = &request->request_msg.msg.set_req;
660 set->oid = OID_TCP_OFFLOAD_PARAMETERS;
661 set->info_buflen = extlen;
662 set->info_buf_offset = sizeof(struct rndis_set_request);
663 set->dev_vc_handle = 0;
664
665 offload_params = (struct ndis_offload_params *)((ulong)set +
666 set->info_buf_offset);
667 *offload_params = *req_offloads;
668 offload_params->header.type = NDIS_OBJECT_TYPE_DEFAULT;
669 offload_params->header.revision = NDIS_OFFLOAD_PARAMETERS_REVISION_3;
670 offload_params->header.size = extlen;
671
672 ret = rndis_filter_send_request(rdev, request);
673 if (ret != 0)
674 goto cleanup;
675
676 t = wait_for_completion_timeout(&request->wait_event, 5*HZ);
677 if (t == 0) {
678 netdev_err(ndev, "timeout before we got aOFFLOAD set response...\n");
679 /* can't put_rndis_request, since we may still receive a
680 * send-completion.
681 */
682 return -EBUSY;
683 } else {
684 set_complete = &request->response_msg.msg.set_complete;
685 if (set_complete->status != RNDIS_STATUS_SUCCESS) {
KY Srinivasanaf9893a2014-04-09 15:00:47 -0700686 netdev_err(ndev, "Fail to set offload on host side:0x%x\n",
KY Srinivasan4a0e70a2014-03-08 19:23:15 -0800687 set_complete->status);
688 ret = -EINVAL;
689 }
690 }
691
692cleanup:
693 put_rndis_request(rdev, request);
694 return ret;
695}
Haiyang Zhang1ce09e82012-07-10 07:19:22 +0000696
Haiyang Zhang5b54dac2014-04-21 10:20:28 -0700697u8 netvsc_hash_key[HASH_KEYLEN] = {
698 0x6d, 0x5a, 0x56, 0xda, 0x25, 0x5b, 0x0e, 0xc2,
699 0x41, 0x67, 0x25, 0x3d, 0x43, 0xa3, 0x8f, 0xb0,
700 0xd0, 0xca, 0x2b, 0xcb, 0xae, 0x7b, 0x30, 0xb4,
701 0x77, 0xcb, 0x2d, 0xa3, 0x80, 0x30, 0xf2, 0x0c,
702 0x6a, 0x42, 0xb7, 0x3b, 0xbe, 0xac, 0x01, 0xfa
703};
704
Lad, Prabhakarda19fcd2015-02-05 15:06:33 +0000705static int rndis_filter_set_rss_param(struct rndis_device *rdev, int num_queue)
Haiyang Zhang5b54dac2014-04-21 10:20:28 -0700706{
707 struct net_device *ndev = rdev->net_dev->ndev;
708 struct rndis_request *request;
709 struct rndis_set_request *set;
710 struct rndis_set_complete *set_complete;
711 u32 extlen = sizeof(struct ndis_recv_scale_param) +
712 4*ITAB_NUM + HASH_KEYLEN;
713 struct ndis_recv_scale_param *rssp;
714 u32 *itab;
715 u8 *keyp;
Nicholas Mc Guire999028c2015-01-25 15:48:23 +0100716 int i, ret;
717 unsigned long t;
Haiyang Zhang5b54dac2014-04-21 10:20:28 -0700718
719 request = get_rndis_request(
720 rdev, RNDIS_MSG_SET,
721 RNDIS_MESSAGE_SIZE(struct rndis_set_request) + extlen);
722 if (!request)
723 return -ENOMEM;
724
725 set = &request->request_msg.msg.set_req;
726 set->oid = OID_GEN_RECEIVE_SCALE_PARAMETERS;
727 set->info_buflen = extlen;
728 set->info_buf_offset = sizeof(struct rndis_set_request);
729 set->dev_vc_handle = 0;
730
731 rssp = (struct ndis_recv_scale_param *)(set + 1);
732 rssp->hdr.type = NDIS_OBJECT_TYPE_RSS_PARAMETERS;
733 rssp->hdr.rev = NDIS_RECEIVE_SCALE_PARAMETERS_REVISION_2;
734 rssp->hdr.size = sizeof(struct ndis_recv_scale_param);
735 rssp->flag = 0;
736 rssp->hashinfo = NDIS_HASH_FUNC_TOEPLITZ | NDIS_HASH_IPV4 |
Haiyang Zhang4c874542014-10-30 14:07:17 -0700737 NDIS_HASH_TCP_IPV4 | NDIS_HASH_IPV6 |
738 NDIS_HASH_TCP_IPV6;
Haiyang Zhang5b54dac2014-04-21 10:20:28 -0700739 rssp->indirect_tabsize = 4*ITAB_NUM;
740 rssp->indirect_taboffset = sizeof(struct ndis_recv_scale_param);
741 rssp->hashkey_size = HASH_KEYLEN;
742 rssp->kashkey_offset = rssp->indirect_taboffset +
743 rssp->indirect_tabsize;
744
745 /* Set indirection table entries */
746 itab = (u32 *)(rssp + 1);
747 for (i = 0; i < ITAB_NUM; i++)
748 itab[i] = i % num_queue;
749
750 /* Set hask key values */
751 keyp = (u8 *)((unsigned long)rssp + rssp->kashkey_offset);
752 for (i = 0; i < HASH_KEYLEN; i++)
753 keyp[i] = netvsc_hash_key[i];
754
755
756 ret = rndis_filter_send_request(rdev, request);
757 if (ret != 0)
758 goto cleanup;
759
760 t = wait_for_completion_timeout(&request->wait_event, 5*HZ);
761 if (t == 0) {
762 netdev_err(ndev, "timeout before we got a set response...\n");
763 /* can't put_rndis_request, since we may still receive a
764 * send-completion.
765 */
766 return -ETIMEDOUT;
767 } else {
768 set_complete = &request->response_msg.msg.set_complete;
769 if (set_complete->status != RNDIS_STATUS_SUCCESS) {
770 netdev_err(ndev, "Fail to set RSS parameters:0x%x\n",
771 set_complete->status);
772 ret = -EINVAL;
773 }
774 }
775
776cleanup:
777 put_rndis_request(rdev, request);
778 return ret;
779}
780
781
Haiyang Zhang9c26aa02010-12-10 12:03:57 -0800782static int rndis_filter_query_device_link_status(struct rndis_device *dev)
Hank Janssenfceaf242009-07-13 15:34:54 -0700783{
Greg Kroah-Hartman0120ee02009-09-02 09:17:52 -0700784 u32 size = sizeof(u32);
K. Y. Srinivasan6f274572011-09-13 15:21:27 -0700785 u32 link_status;
786 int ret;
Hank Janssenfceaf242009-07-13 15:34:54 -0700787
K. Y. Srinivasan6f274572011-09-13 15:21:27 -0700788 ret = rndis_filter_query_device(dev,
Greg Kroah-Hartman0120ee02009-09-02 09:17:52 -0700789 RNDIS_OID_GEN_MEDIA_CONNECT_STATUS,
K. Y. Srinivasan6f274572011-09-13 15:21:27 -0700790 &link_status, &size);
K. Y. Srinivasan6f274572011-09-13 15:21:27 -0700791
792 return ret;
Hank Janssenfceaf242009-07-13 15:34:54 -0700793}
794
Haiyang Zhangd426b2e2011-11-30 07:19:08 -0800795int rndis_filter_set_packet_filter(struct rndis_device *dev, u32 new_filter)
Hank Janssenfceaf242009-07-13 15:34:54 -0700796{
Greg Kroah-Hartmane681b952009-08-28 16:26:27 -0700797 struct rndis_request *request;
Greg Kroah-Hartman9f33d052009-08-19 16:26:24 -0700798 struct rndis_set_request *set;
Haiyang Zhangc2a4efd2010-12-10 12:03:56 -0800799 struct rndis_set_complete *set_complete;
Greg Kroah-Hartman4d643112009-07-14 15:09:36 -0700800 u32 status;
Nicholas Mc Guire999028c2015-01-25 15:48:23 +0100801 int ret;
802 unsigned long t;
K. Y. Srinivasan2ddd5e52011-09-13 10:59:49 -0700803 struct net_device *ndev;
804
805 ndev = dev->net_dev->ndev;
Hank Janssenfceaf242009-07-13 15:34:54 -0700806
Linus Walleij51491162012-05-11 22:17:07 +0000807 request = get_rndis_request(dev, RNDIS_MSG_SET,
Greg Kroah-Hartman0120ee02009-09-02 09:17:52 -0700808 RNDIS_MESSAGE_SIZE(struct rndis_set_request) +
809 sizeof(u32));
810 if (!request) {
K. Y. Srinivasan58ef3972011-08-25 09:49:19 -0700811 ret = -ENOMEM;
K. Y. Srinivasan1c627872011-08-25 09:49:24 -0700812 goto cleanup;
Hank Janssenfceaf242009-07-13 15:34:54 -0700813 }
814
Bill Pemberton454f18a2009-07-27 16:47:24 -0400815 /* Setup the rndis set */
Haiyang Zhanga388eb12010-12-10 12:04:00 -0800816 set = &request->request_msg.msg.set_req;
817 set->oid = RNDIS_OID_GEN_CURRENT_PACKET_FILTER;
818 set->info_buflen = sizeof(u32);
819 set->info_buf_offset = sizeof(struct rndis_set_request);
Hank Janssenfceaf242009-07-13 15:34:54 -0700820
Greg Kroah-Hartman0120ee02009-09-02 09:17:52 -0700821 memcpy((void *)(unsigned long)set + sizeof(struct rndis_set_request),
Haiyang Zhangc2a4efd2010-12-10 12:03:56 -0800822 &new_filter, sizeof(u32));
Hank Janssenfceaf242009-07-13 15:34:54 -0700823
Haiyang Zhang9c26aa02010-12-10 12:03:57 -0800824 ret = rndis_filter_send_request(dev, request);
Hank Janssenfceaf242009-07-13 15:34:54 -0700825 if (ret != 0)
K. Y. Srinivasan1c627872011-08-25 09:49:24 -0700826 goto cleanup;
Hank Janssenfceaf242009-07-13 15:34:54 -0700827
K. Y. Srinivasan5c5781b32011-06-16 13:16:35 -0700828 t = wait_for_completion_timeout(&request->wait_event, 5*HZ);
K. Y. Srinivasan98d79692011-05-10 07:55:42 -0700829
830 if (t == 0) {
Haiyang Zhangd9871152011-09-01 12:19:41 -0700831 netdev_err(ndev,
Hank Jansseneb335bc2011-03-29 13:58:48 -0700832 "timeout before we got a set response...\n");
Haiyang Zhangea496372012-10-02 05:30:20 +0000833 ret = -ETIMEDOUT;
Greg Kroah-Hartman0120ee02009-09-02 09:17:52 -0700834 /*
Lucas De Marchi25985ed2011-03-30 22:57:33 -0300835 * We can't deallocate the request since we may still receive a
Greg Kroah-Hartman0120ee02009-09-02 09:17:52 -0700836 * send completion for it.
837 */
K. Y. Srinivasan5585d812011-08-25 09:49:25 -0700838 goto exit;
Greg Kroah-Hartman0120ee02009-09-02 09:17:52 -0700839 } else {
Haiyang Zhanga388eb12010-12-10 12:04:00 -0800840 set_complete = &request->response_msg.msg.set_complete;
841 status = set_complete->status;
Hank Janssenfceaf242009-07-13 15:34:54 -0700842 }
843
K. Y. Srinivasan1c627872011-08-25 09:49:24 -0700844cleanup:
Hank Janssenfceaf242009-07-13 15:34:54 -0700845 if (request)
Haiyang Zhang9c26aa02010-12-10 12:03:57 -0800846 put_rndis_request(dev, request);
K. Y. Srinivasan5585d812011-08-25 09:49:25 -0700847exit:
Hank Janssenfceaf242009-07-13 15:34:54 -0700848 return ret;
849}
850
Hank Janssenfceaf242009-07-13 15:34:54 -0700851
Haiyang Zhang9c26aa02010-12-10 12:03:57 -0800852static int rndis_filter_init_device(struct rndis_device *dev)
Hank Janssenfceaf242009-07-13 15:34:54 -0700853{
Greg Kroah-Hartmane681b952009-08-28 16:26:27 -0700854 struct rndis_request *request;
Greg Kroah-Hartman9f33d052009-08-19 16:26:24 -0700855 struct rndis_initialize_request *init;
Haiyang Zhangc2a4efd2010-12-10 12:03:56 -0800856 struct rndis_initialize_complete *init_complete;
Greg Kroah-Hartman4d643112009-07-14 15:09:36 -0700857 u32 status;
Nicholas Mc Guire999028c2015-01-25 15:48:23 +0100858 int ret;
859 unsigned long t;
Haiyang Zhang7c3877f2015-03-26 09:03:37 -0700860 struct netvsc_device *nvdev = dev->net_dev;
Hank Janssenfceaf242009-07-13 15:34:54 -0700861
Linus Walleij51491162012-05-11 22:17:07 +0000862 request = get_rndis_request(dev, RNDIS_MSG_INIT,
Greg Kroah-Hartman0120ee02009-09-02 09:17:52 -0700863 RNDIS_MESSAGE_SIZE(struct rndis_initialize_request));
864 if (!request) {
K. Y. Srinivasanbc49b9262011-08-25 09:49:20 -0700865 ret = -ENOMEM;
K. Y. Srinivasan1c627872011-08-25 09:49:24 -0700866 goto cleanup;
Hank Janssenfceaf242009-07-13 15:34:54 -0700867 }
868
Bill Pemberton454f18a2009-07-27 16:47:24 -0400869 /* Setup the rndis set */
Haiyang Zhanga388eb12010-12-10 12:04:00 -0800870 init = &request->request_msg.msg.init_req;
871 init->major_ver = RNDIS_MAJOR_VERSION;
872 init->minor_ver = RNDIS_MINOR_VERSION;
Haiyang Zhangfb1d0742012-10-02 05:30:19 +0000873 init->max_xfer_size = 0x4000;
Hank Janssenfceaf242009-07-13 15:34:54 -0700874
Haiyang Zhangc2a4efd2010-12-10 12:03:56 -0800875 dev->state = RNDIS_DEV_INITIALIZING;
Hank Janssenfceaf242009-07-13 15:34:54 -0700876
Haiyang Zhang9c26aa02010-12-10 12:03:57 -0800877 ret = rndis_filter_send_request(dev, request);
Greg Kroah-Hartman0120ee02009-09-02 09:17:52 -0700878 if (ret != 0) {
Haiyang Zhangc2a4efd2010-12-10 12:03:56 -0800879 dev->state = RNDIS_DEV_UNINITIALIZED;
K. Y. Srinivasan1c627872011-08-25 09:49:24 -0700880 goto cleanup;
Hank Janssenfceaf242009-07-13 15:34:54 -0700881 }
882
K. Y. Srinivasan0c3b7b22011-02-11 09:59:43 -0800883
K. Y. Srinivasan5c5781b32011-06-16 13:16:35 -0700884 t = wait_for_completion_timeout(&request->wait_event, 5*HZ);
K. Y. Srinivasan98d79692011-05-10 07:55:42 -0700885
886 if (t == 0) {
K. Y. Srinivasan0c3b7b22011-02-11 09:59:43 -0800887 ret = -ETIMEDOUT;
K. Y. Srinivasan1c627872011-08-25 09:49:24 -0700888 goto cleanup;
K. Y. Srinivasan0c3b7b22011-02-11 09:59:43 -0800889 }
Hank Janssenfceaf242009-07-13 15:34:54 -0700890
Haiyang Zhanga388eb12010-12-10 12:04:00 -0800891 init_complete = &request->response_msg.msg.init_complete;
892 status = init_complete->status;
Greg Kroah-Hartman0120ee02009-09-02 09:17:52 -0700893 if (status == RNDIS_STATUS_SUCCESS) {
Haiyang Zhangc2a4efd2010-12-10 12:03:56 -0800894 dev->state = RNDIS_DEV_INITIALIZED;
Haiyang Zhang7c3877f2015-03-26 09:03:37 -0700895 nvdev->max_pkt = init_complete->max_pkt_per_msg;
896 nvdev->pkt_align = 1 << init_complete->pkt_alignment_factor;
Hank Janssenfceaf242009-07-13 15:34:54 -0700897 ret = 0;
Greg Kroah-Hartman0120ee02009-09-02 09:17:52 -0700898 } else {
Haiyang Zhangc2a4efd2010-12-10 12:03:56 -0800899 dev->state = RNDIS_DEV_UNINITIALIZED;
K. Y. Srinivasanbc49b9262011-08-25 09:49:20 -0700900 ret = -EINVAL;
Hank Janssenfceaf242009-07-13 15:34:54 -0700901 }
902
K. Y. Srinivasan1c627872011-08-25 09:49:24 -0700903cleanup:
Hank Janssenfceaf242009-07-13 15:34:54 -0700904 if (request)
Haiyang Zhang9c26aa02010-12-10 12:03:57 -0800905 put_rndis_request(dev, request);
Hank Janssenfceaf242009-07-13 15:34:54 -0700906
907 return ret;
908}
909
Haiyang Zhang9c26aa02010-12-10 12:03:57 -0800910static void rndis_filter_halt_device(struct rndis_device *dev)
Hank Janssenfceaf242009-07-13 15:34:54 -0700911{
Greg Kroah-Hartmane681b952009-08-28 16:26:27 -0700912 struct rndis_request *request;
Greg Kroah-Hartman9f33d052009-08-19 16:26:24 -0700913 struct rndis_halt_request *halt;
Haiyang Zhangae9e63b2012-08-03 09:32:18 +0000914 struct netvsc_device *nvdev = dev->net_dev;
915 struct hv_device *hdev = nvdev->dev;
916 ulong flags;
Hank Janssenfceaf242009-07-13 15:34:54 -0700917
Bill Pemberton454f18a2009-07-27 16:47:24 -0400918 /* Attempt to do a rndis device halt */
Linus Walleij51491162012-05-11 22:17:07 +0000919 request = get_rndis_request(dev, RNDIS_MSG_HALT,
Greg Kroah-Hartman0120ee02009-09-02 09:17:52 -0700920 RNDIS_MESSAGE_SIZE(struct rndis_halt_request));
Hank Janssenfceaf242009-07-13 15:34:54 -0700921 if (!request)
K. Y. Srinivasan1c627872011-08-25 09:49:24 -0700922 goto cleanup;
Hank Janssenfceaf242009-07-13 15:34:54 -0700923
Bill Pemberton454f18a2009-07-27 16:47:24 -0400924 /* Setup the rndis set */
Haiyang Zhanga388eb12010-12-10 12:04:00 -0800925 halt = &request->request_msg.msg.halt_req;
926 halt->req_id = atomic_inc_return(&dev->new_req_id);
Hank Janssenfceaf242009-07-13 15:34:54 -0700927
Bill Pemberton454f18a2009-07-27 16:47:24 -0400928 /* Ignore return since this msg is optional. */
Haiyang Zhang9c26aa02010-12-10 12:03:57 -0800929 rndis_filter_send_request(dev, request);
Hank Janssenfceaf242009-07-13 15:34:54 -0700930
Haiyang Zhangc2a4efd2010-12-10 12:03:56 -0800931 dev->state = RNDIS_DEV_UNINITIALIZED;
Hank Janssenfceaf242009-07-13 15:34:54 -0700932
K. Y. Srinivasan1c627872011-08-25 09:49:24 -0700933cleanup:
Haiyang Zhangae9e63b2012-08-03 09:32:18 +0000934 spin_lock_irqsave(&hdev->channel->inbound_lock, flags);
935 nvdev->destroy = true;
936 spin_unlock_irqrestore(&hdev->channel->inbound_lock, flags);
937
938 /* Wait for all send completions */
939 wait_event(nvdev->wait_drain,
940 atomic_read(&nvdev->num_outstanding_sends) == 0);
941
Hank Janssenfceaf242009-07-13 15:34:54 -0700942 if (request)
Haiyang Zhang9c26aa02010-12-10 12:03:57 -0800943 put_rndis_request(dev, request);
Hank Janssenfceaf242009-07-13 15:34:54 -0700944 return;
945}
946
Haiyang Zhang9c26aa02010-12-10 12:03:57 -0800947static int rndis_filter_open_device(struct rndis_device *dev)
Hank Janssenfceaf242009-07-13 15:34:54 -0700948{
Greg Kroah-Hartman0120ee02009-09-02 09:17:52 -0700949 int ret;
Hank Janssenfceaf242009-07-13 15:34:54 -0700950
Haiyang Zhangc2a4efd2010-12-10 12:03:56 -0800951 if (dev->state != RNDIS_DEV_INITIALIZED)
Hank Janssenfceaf242009-07-13 15:34:54 -0700952 return 0;
953
Haiyang Zhang9c26aa02010-12-10 12:03:57 -0800954 ret = rndis_filter_set_packet_filter(dev,
Greg Kroah-Hartman0120ee02009-09-02 09:17:52 -0700955 NDIS_PACKET_TYPE_BROADCAST |
Haiyang Zhang95beae92010-04-19 15:32:11 +0000956 NDIS_PACKET_TYPE_ALL_MULTICAST |
Greg Kroah-Hartman0120ee02009-09-02 09:17:52 -0700957 NDIS_PACKET_TYPE_DIRECTED);
Hank Janssenfceaf242009-07-13 15:34:54 -0700958 if (ret == 0)
Haiyang Zhangc2a4efd2010-12-10 12:03:56 -0800959 dev->state = RNDIS_DEV_DATAINITIALIZED;
Hank Janssenfceaf242009-07-13 15:34:54 -0700960
Hank Janssenfceaf242009-07-13 15:34:54 -0700961 return ret;
962}
963
Haiyang Zhang9c26aa02010-12-10 12:03:57 -0800964static int rndis_filter_close_device(struct rndis_device *dev)
Hank Janssenfceaf242009-07-13 15:34:54 -0700965{
966 int ret;
967
Haiyang Zhangc2a4efd2010-12-10 12:03:56 -0800968 if (dev->state != RNDIS_DEV_DATAINITIALIZED)
Hank Janssenfceaf242009-07-13 15:34:54 -0700969 return 0;
970
Haiyang Zhang9c26aa02010-12-10 12:03:57 -0800971 ret = rndis_filter_set_packet_filter(dev, 0);
Haiyang Zhangc3582a22014-12-01 13:28:39 -0800972 if (ret == -ENODEV)
973 ret = 0;
974
Hank Janssenfceaf242009-07-13 15:34:54 -0700975 if (ret == 0)
Haiyang Zhangc2a4efd2010-12-10 12:03:56 -0800976 dev->state = RNDIS_DEV_INITIALIZED;
Hank Janssenfceaf242009-07-13 15:34:54 -0700977
Hank Janssenfceaf242009-07-13 15:34:54 -0700978 return ret;
979}
980
Haiyang Zhang5b54dac2014-04-21 10:20:28 -0700981static void netvsc_sc_open(struct vmbus_channel *new_sc)
982{
983 struct netvsc_device *nvscdev;
984 u16 chn_index = new_sc->offermsg.offer.sub_channel_index;
985 int ret;
986
987 nvscdev = hv_get_drvdata(new_sc->primary_channel->device_obj);
988
989 if (chn_index >= nvscdev->num_chn)
990 return;
991
992 set_per_channel_state(new_sc, nvscdev->sub_cb_buf + (chn_index - 1) *
993 NETVSC_PACKET_SIZE);
994
995 ret = vmbus_open(new_sc, nvscdev->ring_size * PAGE_SIZE,
996 nvscdev->ring_size * PAGE_SIZE, NULL, 0,
997 netvsc_channel_cb, new_sc);
998
999 if (ret == 0)
1000 nvscdev->chn_table[chn_index] = new_sc;
1001}
1002
Haiyang Zhangbdbad572011-05-23 09:03:49 -07001003int rndis_filter_device_add(struct hv_device *dev,
Haiyang Zhangc2a4efd2010-12-10 12:03:56 -08001004 void *additional_info)
Hank Janssenfceaf242009-07-13 15:34:54 -07001005{
1006 int ret;
K. Y. Srinivasan86c921a2011-09-13 10:59:54 -07001007 struct netvsc_device *net_device;
K. Y. Srinivasanb13cc342011-09-13 10:59:55 -07001008 struct rndis_device *rndis_device;
K. Y. Srinivasan3c4deba2011-09-13 10:59:56 -07001009 struct netvsc_device_info *device_info = additional_info;
KY Srinivasan4a0e70a2014-03-08 19:23:15 -08001010 struct ndis_offload_params offloads;
Haiyang Zhang5b54dac2014-04-21 10:20:28 -07001011 struct nvsp_message *init_packet;
Nicholas Mc Guire999028c2015-01-25 15:48:23 +01001012 unsigned long t;
Haiyang Zhang5b54dac2014-04-21 10:20:28 -07001013 struct ndis_recv_scale_cap rsscap;
1014 u32 rsscap_size = sizeof(struct ndis_recv_scale_cap);
Haiyang Zhang4d3c9d32014-11-12 14:07:44 -08001015 u32 mtu, size;
Hank Janssenfceaf242009-07-13 15:34:54 -07001016
K. Y. Srinivasanb13cc342011-09-13 10:59:55 -07001017 rndis_device = get_rndis_device();
1018 if (!rndis_device)
K. Y. Srinivasan327efba2011-08-25 09:49:21 -07001019 return -ENODEV;
Hank Janssenfceaf242009-07-13 15:34:54 -07001020
Greg Kroah-Hartman0120ee02009-09-02 09:17:52 -07001021 /*
1022 * Let the inner driver handle this first to create the netvsc channel
1023 * NOTE! Once the channel is created, we may get a receive callback
1024 * (RndisFilterOnReceive()) before this call is completed
1025 */
K. Y. Srinivasance5bf662011-05-10 07:55:00 -07001026 ret = netvsc_device_add(dev, additional_info);
Greg Kroah-Hartman0120ee02009-09-02 09:17:52 -07001027 if (ret != 0) {
K. Y. Srinivasanb13cc342011-09-13 10:59:55 -07001028 kfree(rndis_device);
Hank Janssenfceaf242009-07-13 15:34:54 -07001029 return ret;
1030 }
1031
Bill Pemberton454f18a2009-07-27 16:47:24 -04001032
1033 /* Initialize the rndis device */
K. Y. Srinivasan86c921a2011-09-13 10:59:54 -07001034 net_device = hv_get_drvdata(dev);
Andrew Schwartzmeyer59995372015-02-26 16:27:14 -08001035 net_device->max_chn = 1;
Haiyang Zhang5b54dac2014-04-21 10:20:28 -07001036 net_device->num_chn = 1;
Hank Janssenfceaf242009-07-13 15:34:54 -07001037
K. Y. Srinivasanb13cc342011-09-13 10:59:55 -07001038 net_device->extension = rndis_device;
1039 rndis_device->net_dev = net_device;
Hank Janssenfceaf242009-07-13 15:34:54 -07001040
Bill Pemberton454f18a2009-07-27 16:47:24 -04001041 /* Send the rndis initialization message */
K. Y. Srinivasanb13cc342011-09-13 10:59:55 -07001042 ret = rndis_filter_init_device(rndis_device);
Greg Kroah-Hartman0120ee02009-09-02 09:17:52 -07001043 if (ret != 0) {
Haiyang Zhang5243e7b2012-07-25 08:08:42 +00001044 rndis_filter_device_remove(dev);
1045 return ret;
Hank Janssenfceaf242009-07-13 15:34:54 -07001046 }
1047
Haiyang Zhang4d3c9d32014-11-12 14:07:44 -08001048 /* Get the MTU from the host */
1049 size = sizeof(u32);
1050 ret = rndis_filter_query_device(rndis_device,
1051 RNDIS_OID_GEN_MAXIMUM_FRAME_SIZE,
1052 &mtu, &size);
1053 if (ret == 0 && size == sizeof(u32))
1054 net_device->ndev->mtu = mtu;
1055
Bill Pemberton454f18a2009-07-27 16:47:24 -04001056 /* Get the mac address */
K. Y. Srinivasanb13cc342011-09-13 10:59:55 -07001057 ret = rndis_filter_query_device_mac(rndis_device);
Greg Kroah-Hartman0120ee02009-09-02 09:17:52 -07001058 if (ret != 0) {
Haiyang Zhang5243e7b2012-07-25 08:08:42 +00001059 rndis_filter_device_remove(dev);
1060 return ret;
Hank Janssenfceaf242009-07-13 15:34:54 -07001061 }
1062
K. Y. Srinivasan3c4deba2011-09-13 10:59:56 -07001063 memcpy(device_info->mac_adr, rndis_device->hw_mac_adr, ETH_ALEN);
Hank Janssenfceaf242009-07-13 15:34:54 -07001064
KY Srinivasan4a0e70a2014-03-08 19:23:15 -08001065 /* Turn on the offloads; the host supports all of the relevant
1066 * offloads.
1067 */
1068 memset(&offloads, 0, sizeof(struct ndis_offload_params));
1069 /* A value of zero means "no change"; now turn on what we
1070 * want.
1071 */
1072 offloads.ip_v4_csum = NDIS_OFFLOAD_PARAMETERS_TX_RX_ENABLED;
1073 offloads.tcp_ip_v4_csum = NDIS_OFFLOAD_PARAMETERS_TX_RX_ENABLED;
1074 offloads.udp_ip_v4_csum = NDIS_OFFLOAD_PARAMETERS_TX_RX_ENABLED;
1075 offloads.tcp_ip_v6_csum = NDIS_OFFLOAD_PARAMETERS_TX_RX_ENABLED;
1076 offloads.udp_ip_v6_csum = NDIS_OFFLOAD_PARAMETERS_TX_RX_ENABLED;
1077 offloads.lso_v2_ipv4 = NDIS_OFFLOAD_PARAMETERS_LSOV2_ENABLED;
1078
1079
1080 ret = rndis_filter_set_offload_params(dev, &offloads);
1081 if (ret)
1082 goto err_dev_remv;
1083
K. Y. Srinivasanb13cc342011-09-13 10:59:55 -07001084 rndis_filter_query_device_link_status(rndis_device);
Hank Janssenfceaf242009-07-13 15:34:54 -07001085
K. Y. Srinivasan6f274572011-09-13 15:21:27 -07001086 device_info->link_state = rndis_device->link_state;
Hank Jansseneb335bc2011-03-29 13:58:48 -07001087
K. Y. Srinivasan6f274572011-09-13 15:21:27 -07001088 dev_info(&dev->device, "Device MAC %pM link state %s\n",
K. Y. Srinivasanb13cc342011-09-13 10:59:55 -07001089 rndis_device->hw_mac_adr,
K. Y. Srinivasan6f274572011-09-13 15:21:27 -07001090 device_info->link_state ? "down" : "up");
Hank Janssenfceaf242009-07-13 15:34:54 -07001091
Haiyang Zhang5b54dac2014-04-21 10:20:28 -07001092 if (net_device->nvsp_version < NVSP_PROTOCOL_VERSION_5)
1093 return 0;
1094
1095 /* vRSS setup */
1096 memset(&rsscap, 0, rsscap_size);
1097 ret = rndis_filter_query_device(rndis_device,
1098 OID_GEN_RECEIVE_SCALE_CAPABILITIES,
1099 &rsscap, &rsscap_size);
1100 if (ret || rsscap.num_recv_que < 2)
1101 goto out;
1102
Andrew Schwartzmeyer59995372015-02-26 16:27:14 -08001103 net_device->max_chn = rsscap.num_recv_que;
Haiyang Zhang5b54dac2014-04-21 10:20:28 -07001104 net_device->num_chn = (num_online_cpus() < rsscap.num_recv_que) ?
1105 num_online_cpus() : rsscap.num_recv_que;
1106 if (net_device->num_chn == 1)
1107 goto out;
1108
1109 net_device->sub_cb_buf = vzalloc((net_device->num_chn - 1) *
1110 NETVSC_PACKET_SIZE);
1111 if (!net_device->sub_cb_buf) {
1112 net_device->num_chn = 1;
1113 dev_info(&dev->device, "No memory for subchannels.\n");
1114 goto out;
1115 }
1116
1117 vmbus_set_sc_create_callback(dev->channel, netvsc_sc_open);
1118
1119 init_packet = &net_device->channel_init_pkt;
1120 memset(init_packet, 0, sizeof(struct nvsp_message));
1121 init_packet->hdr.msg_type = NVSP_MSG5_TYPE_SUBCHANNEL;
1122 init_packet->msg.v5_msg.subchn_req.op = NVSP_SUBCHANNEL_ALLOCATE;
1123 init_packet->msg.v5_msg.subchn_req.num_subchannels =
1124 net_device->num_chn - 1;
1125 ret = vmbus_sendpacket(dev->channel, init_packet,
1126 sizeof(struct nvsp_message),
1127 (unsigned long)init_packet,
1128 VM_PKT_DATA_INBAND,
1129 VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
1130 if (ret)
1131 goto out;
1132 t = wait_for_completion_timeout(&net_device->channel_init_wait, 5*HZ);
1133 if (t == 0) {
1134 ret = -ETIMEDOUT;
1135 goto out;
1136 }
1137 if (init_packet->msg.v5_msg.subchn_comp.status !=
1138 NVSP_STAT_SUCCESS) {
1139 ret = -ENODEV;
1140 goto out;
1141 }
1142 net_device->num_chn = 1 +
1143 init_packet->msg.v5_msg.subchn_comp.num_subchannels;
1144
Haiyang Zhang5b54dac2014-04-21 10:20:28 -07001145 ret = rndis_filter_set_rss_param(rndis_device, net_device->num_chn);
1146
1147out:
Andrew Schwartzmeyer59995372015-02-26 16:27:14 -08001148 if (ret) {
1149 net_device->max_chn = 1;
Haiyang Zhang5b54dac2014-04-21 10:20:28 -07001150 net_device->num_chn = 1;
Andrew Schwartzmeyer59995372015-02-26 16:27:14 -08001151 }
Haiyang Zhang5b54dac2014-04-21 10:20:28 -07001152 return 0; /* return 0 because primary channel can be used alone */
KY Srinivasan4a0e70a2014-03-08 19:23:15 -08001153
1154err_dev_remv:
1155 rndis_filter_device_remove(dev);
1156 return ret;
Hank Janssenfceaf242009-07-13 15:34:54 -07001157}
1158
Haiyang Zhangdf06bcf2011-05-23 09:03:47 -07001159void rndis_filter_device_remove(struct hv_device *dev)
Hank Janssenfceaf242009-07-13 15:34:54 -07001160{
K. Y. Srinivasan2ddd5e52011-09-13 10:59:49 -07001161 struct netvsc_device *net_dev = hv_get_drvdata(dev);
Haiyang Zhang53d21fd2010-12-10 12:03:59 -08001162 struct rndis_device *rndis_dev = net_dev->extension;
Hank Janssenfceaf242009-07-13 15:34:54 -07001163
Bill Pemberton454f18a2009-07-27 16:47:24 -04001164 /* Halt and release the rndis device */
Haiyang Zhang9c26aa02010-12-10 12:03:57 -08001165 rndis_filter_halt_device(rndis_dev);
Hank Janssenfceaf242009-07-13 15:34:54 -07001166
Haiyang Zhangc2a4efd2010-12-10 12:03:56 -08001167 kfree(rndis_dev);
Haiyang Zhang53d21fd2010-12-10 12:03:59 -08001168 net_dev->extension = NULL;
Hank Janssenfceaf242009-07-13 15:34:54 -07001169
K. Y. Srinivasan3fae5c82011-05-10 07:55:02 -07001170 netvsc_device_remove(dev);
Hank Janssenfceaf242009-07-13 15:34:54 -07001171}
1172
Hank Janssenfceaf242009-07-13 15:34:54 -07001173
Haiyang Zhang9c26aa02010-12-10 12:03:57 -08001174int rndis_filter_open(struct hv_device *dev)
Hank Janssenfceaf242009-07-13 15:34:54 -07001175{
K. Y. Srinivasan86c921a2011-09-13 10:59:54 -07001176 struct netvsc_device *net_device = hv_get_drvdata(dev);
Hank Janssenfceaf242009-07-13 15:34:54 -07001177
K. Y. Srinivasan86c921a2011-09-13 10:59:54 -07001178 if (!net_device)
Bill Pemberton8a62d712010-05-05 15:27:47 -04001179 return -EINVAL;
1180
K. Y. Srinivasan86c921a2011-09-13 10:59:54 -07001181 return rndis_filter_open_device(net_device->extension);
Hank Janssenfceaf242009-07-13 15:34:54 -07001182}
1183
Haiyang Zhang9c26aa02010-12-10 12:03:57 -08001184int rndis_filter_close(struct hv_device *dev)
Hank Janssenfceaf242009-07-13 15:34:54 -07001185{
Haiyang Zhang5fccab32012-02-05 12:13:08 +00001186 struct netvsc_device *nvdev = hv_get_drvdata(dev);
Hank Janssenfceaf242009-07-13 15:34:54 -07001187
Haiyang Zhang5fccab32012-02-05 12:13:08 +00001188 if (!nvdev)
Bill Pemberton8a62d712010-05-05 15:27:47 -04001189 return -EINVAL;
1190
Haiyang Zhang5fccab32012-02-05 12:13:08 +00001191 return rndis_filter_close_device(nvdev->extension);
Hank Janssenfceaf242009-07-13 15:34:54 -07001192}