blob: 9195d5da8485d50ee669e5dc1fb36ec80ebf7b82 [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>
Stephen Rothwelld6472302015-06-02 19:01:38 +100030#include <linux/vmalloc.h>
K. Y. Srinivasan3f335ea2011-05-12 19:34:15 -070031
K. Y. Srinivasan5ca72522011-05-12 19:34:37 -070032#include "hyperv_net.h"
Hank Janssenfceaf242009-07-13 15:34:54 -070033
Hank Janssenfceaf242009-07-13 15:34:54 -070034
Haiyang Zhang5b54dac2014-04-21 10:20:28 -070035#define RNDIS_EXT_LEN PAGE_SIZE
Greg Kroah-Hartmane681b952009-08-28 16:26:27 -070036struct rndis_request {
Haiyang Zhangc2a4efd2010-12-10 12:03:56 -080037 struct list_head list_ent;
K. Y. Srinivasan98d79692011-05-10 07:55:42 -070038 struct completion wait_event;
Hank Janssenfceaf242009-07-13 15:34:54 -070039
Haiyang Zhangc2a4efd2010-12-10 12:03:56 -080040 struct rndis_message response_msg;
Haiyang Zhanga3a6cab2012-10-02 05:30:24 +000041 /*
42 * The buffer for extended info after the RNDIS response message. It's
43 * referenced based on the data offset in the RNDIS message. Its size
44 * is enough for current needs, and should be sufficient for the near
45 * future.
46 */
47 u8 response_ext[RNDIS_EXT_LEN];
Hank Janssenfceaf242009-07-13 15:34:54 -070048
Bill Pemberton454f18a2009-07-27 16:47:24 -040049 /* Simplify allocation by having a netvsc packet inline */
Haiyang Zhangc2a4efd2010-12-10 12:03:56 -080050 struct hv_netvsc_packet pkt;
Haiyang Zhang0f489172012-08-09 08:04:18 +000051
Haiyang Zhangc2a4efd2010-12-10 12:03:56 -080052 struct rndis_message request_msg;
Haiyang Zhang0f489172012-08-09 08:04:18 +000053 /*
Haiyang Zhanga3a6cab2012-10-02 05:30:24 +000054 * The buffer for the extended info after the RNDIS request message.
55 * It is referenced and sized in a similar way as response_ext.
Haiyang Zhang0f489172012-08-09 08:04:18 +000056 */
Haiyang Zhanga3a6cab2012-10-02 05:30:24 +000057 u8 request_ext[RNDIS_EXT_LEN];
Greg Kroah-Hartmane681b952009-08-28 16:26:27 -070058};
Hank Janssenfceaf242009-07-13 15:34:54 -070059
Haiyang Zhang9c26aa02010-12-10 12:03:57 -080060static struct rndis_device *get_rndis_device(void)
Hank Janssenfceaf242009-07-13 15:34:54 -070061{
Greg Kroah-Hartmane681b952009-08-28 16:26:27 -070062 struct rndis_device *device;
Hank Janssenfceaf242009-07-13 15:34:54 -070063
Greg Kroah-Hartmane681b952009-08-28 16:26:27 -070064 device = kzalloc(sizeof(struct rndis_device), GFP_KERNEL);
Hank Janssenfceaf242009-07-13 15:34:54 -070065 if (!device)
Hank Janssenfceaf242009-07-13 15:34:54 -070066 return NULL;
Hank Janssenfceaf242009-07-13 15:34:54 -070067
Greg Kroah-Hartman880fb892009-07-15 14:55:29 -070068 spin_lock_init(&device->request_lock);
Hank Janssenfceaf242009-07-13 15:34:54 -070069
Haiyang Zhangc2a4efd2010-12-10 12:03:56 -080070 INIT_LIST_HEAD(&device->req_list);
Hank Janssenfceaf242009-07-13 15:34:54 -070071
Haiyang Zhangc2a4efd2010-12-10 12:03:56 -080072 device->state = RNDIS_DEV_UNINITIALIZED;
Hank Janssenfceaf242009-07-13 15:34:54 -070073
74 return device;
75}
76
Haiyang Zhang9c26aa02010-12-10 12:03:57 -080077static struct rndis_request *get_rndis_request(struct rndis_device *dev,
Haiyang Zhangc2a4efd2010-12-10 12:03:56 -080078 u32 msg_type,
79 u32 msg_len)
Hank Janssenfceaf242009-07-13 15:34:54 -070080{
Greg Kroah-Hartmane681b952009-08-28 16:26:27 -070081 struct rndis_request *request;
Haiyang Zhangc2a4efd2010-12-10 12:03:56 -080082 struct rndis_message *rndis_msg;
Greg Kroah-Hartman9f33d052009-08-19 16:26:24 -070083 struct rndis_set_request *set;
Greg Kroah-Hartman880fb892009-07-15 14:55:29 -070084 unsigned long flags;
Hank Janssenfceaf242009-07-13 15:34:54 -070085
Greg Kroah-Hartmane681b952009-08-28 16:26:27 -070086 request = kzalloc(sizeof(struct rndis_request), GFP_KERNEL);
Hank Janssenfceaf242009-07-13 15:34:54 -070087 if (!request)
Hank Janssenfceaf242009-07-13 15:34:54 -070088 return NULL;
Hank Janssenfceaf242009-07-13 15:34:54 -070089
K. Y. Srinivasan98d79692011-05-10 07:55:42 -070090 init_completion(&request->wait_event);
Hank Janssenfceaf242009-07-13 15:34:54 -070091
Haiyang Zhangc2a4efd2010-12-10 12:03:56 -080092 rndis_msg = &request->request_msg;
Haiyang Zhanga388eb12010-12-10 12:04:00 -080093 rndis_msg->ndis_msg_type = msg_type;
94 rndis_msg->msg_len = msg_len;
Hank Janssenfceaf242009-07-13 15:34:54 -070095
Haiyang Zhang5b54dac2014-04-21 10:20:28 -070096 request->pkt.q_idx = 0;
97
Greg Kroah-Hartman0120ee02009-09-02 09:17:52 -070098 /*
99 * Set the request id. This field is always after the rndis header for
100 * request/response packet types so we just used the SetRequest as a
101 * template
102 */
Haiyang Zhanga388eb12010-12-10 12:04:00 -0800103 set = &rndis_msg->msg.set_req;
104 set->req_id = atomic_inc_return(&dev->new_req_id);
Hank Janssenfceaf242009-07-13 15:34:54 -0700105
Bill Pemberton454f18a2009-07-27 16:47:24 -0400106 /* Add to the request list */
Haiyang Zhangc2a4efd2010-12-10 12:03:56 -0800107 spin_lock_irqsave(&dev->request_lock, flags);
108 list_add_tail(&request->list_ent, &dev->req_list);
109 spin_unlock_irqrestore(&dev->request_lock, flags);
Hank Janssenfceaf242009-07-13 15:34:54 -0700110
111 return request;
112}
113
Haiyang Zhang9c26aa02010-12-10 12:03:57 -0800114static void put_rndis_request(struct rndis_device *dev,
Haiyang Zhangc2a4efd2010-12-10 12:03:56 -0800115 struct rndis_request *req)
Hank Janssenfceaf242009-07-13 15:34:54 -0700116{
Greg Kroah-Hartman880fb892009-07-15 14:55:29 -0700117 unsigned long flags;
118
Haiyang Zhangc2a4efd2010-12-10 12:03:56 -0800119 spin_lock_irqsave(&dev->request_lock, flags);
120 list_del(&req->list_ent);
121 spin_unlock_irqrestore(&dev->request_lock, flags);
Hank Janssenfceaf242009-07-13 15:34:54 -0700122
Haiyang Zhangc2a4efd2010-12-10 12:03:56 -0800123 kfree(req);
Hank Janssenfceaf242009-07-13 15:34:54 -0700124}
125
Haiyang Zhang729a2842011-05-27 06:21:54 -0700126static void dump_rndis_message(struct hv_device *hv_dev,
127 struct rndis_message *rndis_msg)
Hank Janssenfceaf242009-07-13 15:34:54 -0700128{
Vitaly Kuznetsov3d541ac2016-05-13 13:55:22 +0200129 struct net_device *netdev = hv_get_drvdata(hv_dev);
Haiyang Zhang729a2842011-05-27 06:21:54 -0700130
Haiyang Zhanga388eb12010-12-10 12:04:00 -0800131 switch (rndis_msg->ndis_msg_type) {
Linus Walleij51491162012-05-11 22:17:07 +0000132 case RNDIS_MSG_PACKET:
133 netdev_dbg(netdev, "RNDIS_MSG_PACKET (len %u, "
Greg Kroah-Hartman0120ee02009-09-02 09:17:52 -0700134 "data offset %u data len %u, # oob %u, "
135 "oob offset %u, oob len %u, pkt offset %u, "
Haiyang Zhang729a2842011-05-27 06:21:54 -0700136 "pkt len %u\n",
Haiyang Zhanga388eb12010-12-10 12:04:00 -0800137 rndis_msg->msg_len,
138 rndis_msg->msg.pkt.data_offset,
139 rndis_msg->msg.pkt.data_len,
140 rndis_msg->msg.pkt.num_oob_data_elements,
141 rndis_msg->msg.pkt.oob_data_offset,
142 rndis_msg->msg.pkt.oob_data_len,
143 rndis_msg->msg.pkt.per_pkt_info_offset,
144 rndis_msg->msg.pkt.per_pkt_info_len);
Hank Janssenfceaf242009-07-13 15:34:54 -0700145 break;
146
Linus Walleij51491162012-05-11 22:17:07 +0000147 case RNDIS_MSG_INIT_C:
148 netdev_dbg(netdev, "RNDIS_MSG_INIT_C "
Greg Kroah-Hartman0120ee02009-09-02 09:17:52 -0700149 "(len %u, id 0x%x, status 0x%x, major %d, minor %d, "
150 "device flags %d, max xfer size 0x%x, max pkts %u, "
Haiyang Zhang729a2842011-05-27 06:21:54 -0700151 "pkt aligned %u)\n",
Haiyang Zhanga388eb12010-12-10 12:04:00 -0800152 rndis_msg->msg_len,
153 rndis_msg->msg.init_complete.req_id,
154 rndis_msg->msg.init_complete.status,
155 rndis_msg->msg.init_complete.major_ver,
156 rndis_msg->msg.init_complete.minor_ver,
157 rndis_msg->msg.init_complete.dev_flags,
158 rndis_msg->msg.init_complete.max_xfer_size,
159 rndis_msg->msg.init_complete.
160 max_pkt_per_msg,
161 rndis_msg->msg.init_complete.
162 pkt_alignment_factor);
Hank Janssenfceaf242009-07-13 15:34:54 -0700163 break;
164
Linus Walleij51491162012-05-11 22:17:07 +0000165 case RNDIS_MSG_QUERY_C:
166 netdev_dbg(netdev, "RNDIS_MSG_QUERY_C "
Greg Kroah-Hartman0120ee02009-09-02 09:17:52 -0700167 "(len %u, id 0x%x, status 0x%x, buf len %u, "
Haiyang Zhang729a2842011-05-27 06:21:54 -0700168 "buf offset %u)\n",
Haiyang Zhanga388eb12010-12-10 12:04:00 -0800169 rndis_msg->msg_len,
170 rndis_msg->msg.query_complete.req_id,
171 rndis_msg->msg.query_complete.status,
172 rndis_msg->msg.query_complete.
173 info_buflen,
174 rndis_msg->msg.query_complete.
175 info_buf_offset);
Hank Janssenfceaf242009-07-13 15:34:54 -0700176 break;
177
Linus Walleij51491162012-05-11 22:17:07 +0000178 case RNDIS_MSG_SET_C:
Haiyang Zhang729a2842011-05-27 06:21:54 -0700179 netdev_dbg(netdev,
Linus Walleij51491162012-05-11 22:17:07 +0000180 "RNDIS_MSG_SET_C (len %u, id 0x%x, status 0x%x)\n",
Haiyang Zhanga388eb12010-12-10 12:04:00 -0800181 rndis_msg->msg_len,
182 rndis_msg->msg.set_complete.req_id,
183 rndis_msg->msg.set_complete.status);
Hank Janssenfceaf242009-07-13 15:34:54 -0700184 break;
185
Linus Walleij51491162012-05-11 22:17:07 +0000186 case RNDIS_MSG_INDICATE:
187 netdev_dbg(netdev, "RNDIS_MSG_INDICATE "
Haiyang Zhang729a2842011-05-27 06:21:54 -0700188 "(len %u, status 0x%x, buf len %u, buf offset %u)\n",
Haiyang Zhanga388eb12010-12-10 12:04:00 -0800189 rndis_msg->msg_len,
190 rndis_msg->msg.indicate_status.status,
191 rndis_msg->msg.indicate_status.status_buflen,
192 rndis_msg->msg.indicate_status.status_buf_offset);
Hank Janssenfceaf242009-07-13 15:34:54 -0700193 break;
194
195 default:
Haiyang Zhang729a2842011-05-27 06:21:54 -0700196 netdev_dbg(netdev, "0x%x (len %u)\n",
Haiyang Zhanga388eb12010-12-10 12:04:00 -0800197 rndis_msg->ndis_msg_type,
198 rndis_msg->msg_len);
Hank Janssenfceaf242009-07-13 15:34:54 -0700199 break;
200 }
201}
202
Haiyang Zhang9c26aa02010-12-10 12:03:57 -0800203static int rndis_filter_send_request(struct rndis_device *dev,
Haiyang Zhangc2a4efd2010-12-10 12:03:56 -0800204 struct rndis_request *req)
Hank Janssenfceaf242009-07-13 15:34:54 -0700205{
Greg Kroah-Hartman0120ee02009-09-02 09:17:52 -0700206 int ret;
Nicolas Palix4193d4f2009-07-29 14:10:10 +0200207 struct hv_netvsc_packet *packet;
KY Srinivasanb08cc792015-03-29 21:08:42 -0700208 struct hv_page_buffer page_buf[2];
KY Srinivasana9f2e2d2015-12-01 16:43:13 -0800209 struct hv_page_buffer *pb = page_buf;
Vitaly Kuznetsov3d541ac2016-05-13 13:55:22 +0200210 struct net_device_context *net_device_ctx = netdev_priv(dev->ndev);
Hank Janssenfceaf242009-07-13 15:34:54 -0700211
Bill Pemberton454f18a2009-07-27 16:47:24 -0400212 /* Setup the packet to send it */
Haiyang Zhangc2a4efd2010-12-10 12:03:56 -0800213 packet = &req->pkt;
Hank Janssenfceaf242009-07-13 15:34:54 -0700214
Haiyang Zhanga388eb12010-12-10 12:04:00 -0800215 packet->total_data_buflen = req->request_msg.msg_len;
Haiyang Zhang72a2f5b2010-12-10 12:03:58 -0800216 packet->page_buf_cnt = 1;
Hank Janssenfceaf242009-07-13 15:34:54 -0700217
KY Srinivasana9f2e2d2015-12-01 16:43:13 -0800218 pb[0].pfn = virt_to_phys(&req->request_msg) >>
Greg Kroah-Hartman0120ee02009-09-02 09:17:52 -0700219 PAGE_SHIFT;
KY Srinivasana9f2e2d2015-12-01 16:43:13 -0800220 pb[0].len = req->request_msg.msg_len;
221 pb[0].offset =
Haiyang Zhangc2a4efd2010-12-10 12:03:56 -0800222 (unsigned long)&req->request_msg & (PAGE_SIZE - 1);
Hank Janssenfceaf242009-07-13 15:34:54 -0700223
Haiyang Zhang99e3fcf2012-10-02 05:30:21 +0000224 /* Add one page_buf when request_msg crossing page boundary */
KY Srinivasana9f2e2d2015-12-01 16:43:13 -0800225 if (pb[0].offset + pb[0].len > PAGE_SIZE) {
Haiyang Zhang99e3fcf2012-10-02 05:30:21 +0000226 packet->page_buf_cnt++;
KY Srinivasana9f2e2d2015-12-01 16:43:13 -0800227 pb[0].len = PAGE_SIZE -
228 pb[0].offset;
229 pb[1].pfn = virt_to_phys((void *)&req->request_msg
230 + pb[0].len) >> PAGE_SHIFT;
231 pb[1].offset = 0;
232 pb[1].len = req->request_msg.msg_len -
233 pb[0].len;
Haiyang Zhang99e3fcf2012-10-02 05:30:21 +0000234 }
235
Vitaly Kuznetsov3d541ac2016-05-13 13:55:22 +0200236 ret = netvsc_send(net_device_ctx->device_ctx, packet, NULL, &pb, NULL);
Hank Janssenfceaf242009-07-13 15:34:54 -0700237 return ret;
238}
239
Haiyang Zhang1b07da52014-03-04 14:11:06 -0800240static void rndis_set_link_state(struct rndis_device *rdev,
241 struct rndis_request *request)
242{
243 u32 link_status;
244 struct rndis_query_complete *query_complete;
245
246 query_complete = &request->response_msg.msg.query_complete;
247
248 if (query_complete->status == RNDIS_STATUS_SUCCESS &&
249 query_complete->info_buflen == sizeof(u32)) {
250 memcpy(&link_status, (void *)((unsigned long)query_complete +
251 query_complete->info_buf_offset), sizeof(u32));
252 rdev->link_state = link_status != 0;
253 }
254}
255
Haiyang Zhang9c26aa02010-12-10 12:03:57 -0800256static void rndis_filter_receive_response(struct rndis_device *dev,
Haiyang Zhangc2a4efd2010-12-10 12:03:56 -0800257 struct rndis_message *resp)
Hank Janssenfceaf242009-07-13 15:34:54 -0700258{
Greg Kroah-Hartmane681b952009-08-28 16:26:27 -0700259 struct rndis_request *request = NULL;
Greg Kroah-Hartman0e727612009-07-15 12:46:44 -0700260 bool found = false;
Greg Kroah-Hartman880fb892009-07-15 14:55:29 -0700261 unsigned long flags;
Vitaly Kuznetsov3d541ac2016-05-13 13:55:22 +0200262 struct net_device *ndev = dev->ndev;
Hank Janssenfceaf242009-07-13 15:34:54 -0700263
Haiyang Zhangc2a4efd2010-12-10 12:03:56 -0800264 spin_lock_irqsave(&dev->request_lock, flags);
265 list_for_each_entry(request, &dev->req_list, list_ent) {
Greg Kroah-Hartman0120ee02009-09-02 09:17:52 -0700266 /*
267 * All request/response message contains RequestId as the 1st
268 * field
269 */
Haiyang Zhanga388eb12010-12-10 12:04:00 -0800270 if (request->request_msg.msg.init_req.req_id
271 == resp->msg.init_complete.req_id) {
Greg Kroah-Hartman0e727612009-07-15 12:46:44 -0700272 found = true;
Hank Janssenfceaf242009-07-13 15:34:54 -0700273 break;
274 }
275 }
Haiyang Zhangc2a4efd2010-12-10 12:03:56 -0800276 spin_unlock_irqrestore(&dev->request_lock, flags);
Hank Janssenfceaf242009-07-13 15:34:54 -0700277
Greg Kroah-Hartman0120ee02009-09-02 09:17:52 -0700278 if (found) {
Haiyang Zhanga3a6cab2012-10-02 05:30:24 +0000279 if (resp->msg_len <=
280 sizeof(struct rndis_message) + RNDIS_EXT_LEN) {
Haiyang Zhangc2a4efd2010-12-10 12:03:56 -0800281 memcpy(&request->response_msg, resp,
Haiyang Zhanga388eb12010-12-10 12:04:00 -0800282 resp->msg_len);
Haiyang Zhang1b07da52014-03-04 14:11:06 -0800283 if (request->request_msg.ndis_msg_type ==
284 RNDIS_MSG_QUERY && request->request_msg.msg.
285 query_req.oid == RNDIS_OID_GEN_MEDIA_CONNECT_STATUS)
286 rndis_set_link_state(dev, request);
Greg Kroah-Hartman0120ee02009-09-02 09:17:52 -0700287 } else {
Haiyang Zhangd9871152011-09-01 12:19:41 -0700288 netdev_err(ndev,
Hank Jansseneb335bc2011-03-29 13:58:48 -0700289 "rndis response buffer overflow "
290 "detected (size %u max %zu)\n",
291 resp->msg_len,
KY Srinivasan86eedac2014-02-16 16:38:43 -0800292 sizeof(struct rndis_message));
Hank Janssenfceaf242009-07-13 15:34:54 -0700293
Haiyang Zhanga388eb12010-12-10 12:04:00 -0800294 if (resp->ndis_msg_type ==
Linus Walleij51491162012-05-11 22:17:07 +0000295 RNDIS_MSG_RESET_C) {
Greg Kroah-Hartman0120ee02009-09-02 09:17:52 -0700296 /* does not have a request id field */
Haiyang Zhanga388eb12010-12-10 12:04:00 -0800297 request->response_msg.msg.reset_complete.
Linus Walleij007e5c82012-05-11 22:15:59 +0000298 status = RNDIS_STATUS_BUFFER_OVERFLOW;
Greg Kroah-Hartman0120ee02009-09-02 09:17:52 -0700299 } else {
Haiyang Zhanga388eb12010-12-10 12:04:00 -0800300 request->response_msg.msg.
301 init_complete.status =
Linus Walleij007e5c82012-05-11 22:15:59 +0000302 RNDIS_STATUS_BUFFER_OVERFLOW;
Hank Janssenfceaf242009-07-13 15:34:54 -0700303 }
304 }
305
K. Y. Srinivasan98d79692011-05-10 07:55:42 -0700306 complete(&request->wait_event);
Greg Kroah-Hartman0120ee02009-09-02 09:17:52 -0700307 } else {
Haiyang Zhangd9871152011-09-01 12:19:41 -0700308 netdev_err(ndev,
Hank Jansseneb335bc2011-03-29 13:58:48 -0700309 "no rndis request found for this response "
310 "(id 0x%x res type 0x%x)\n",
311 resp->msg.init_complete.req_id,
312 resp->ndis_msg_type);
Hank Janssenfceaf242009-07-13 15:34:54 -0700313 }
Hank Janssenfceaf242009-07-13 15:34:54 -0700314}
315
Haiyang Zhang1f5f3a72012-03-12 10:20:50 +0000316/*
317 * Get the Per-Packet-Info with the specified type
318 * return NULL if not found.
319 */
320static inline void *rndis_get_ppi(struct rndis_packet *rpkt, u32 type)
321{
322 struct rndis_per_packet_info *ppi;
323 int len;
324
325 if (rpkt->per_pkt_info_offset == 0)
326 return NULL;
327
328 ppi = (struct rndis_per_packet_info *)((ulong)rpkt +
329 rpkt->per_pkt_info_offset);
330 len = rpkt->per_pkt_info_len;
331
332 while (len > 0) {
333 if (ppi->type == type)
334 return (void *)((ulong)ppi + ppi->ppi_offset);
335 len -= ppi->size;
336 ppi = (struct rndis_per_packet_info *)((ulong)ppi + ppi->size);
337 }
338
339 return NULL;
340}
341
KY Srinivasan10082f92015-12-01 16:43:18 -0800342static int rndis_filter_receive_data(struct rndis_device *dev,
Haiyang Zhangc2a4efd2010-12-10 12:03:56 -0800343 struct rndis_message *msg,
KY Srinivasan25b85ee2015-12-01 16:43:05 -0800344 struct hv_netvsc_packet *pkt,
KY Srinivasanc4b20c62015-12-01 16:43:07 -0800345 void **data,
KY Srinivasan25b85ee2015-12-01 16:43:05 -0800346 struct vmbus_channel *channel)
Hank Janssenfceaf242009-07-13 15:34:54 -0700347{
Haiyang Zhangc2a4efd2010-12-10 12:03:56 -0800348 struct rndis_packet *rndis_pkt;
349 u32 data_offset;
Haiyang Zhang1f5f3a72012-03-12 10:20:50 +0000350 struct ndis_pkt_8021q_info *vlan;
KY Srinivasane3d605e2014-03-08 19:23:16 -0800351 struct ndis_tcp_ip_checksum_info *csum_info;
KY Srinivasan760d1e32015-12-01 16:43:19 -0800352 u16 vlan_tci = 0;
Vitaly Kuznetsov3d541ac2016-05-13 13:55:22 +0200353 struct net_device_context *net_device_ctx = netdev_priv(dev->ndev);
Hank Janssenfceaf242009-07-13 15:34:54 -0700354
Haiyang Zhanga388eb12010-12-10 12:04:00 -0800355 rndis_pkt = &msg->msg.pkt;
Hank Janssenfceaf242009-07-13 15:34:54 -0700356
Bill Pemberton454f18a2009-07-27 16:47:24 -0400357 /* Remove the rndis header and pass it back up the stack */
Haiyang Zhanga388eb12010-12-10 12:04:00 -0800358 data_offset = RNDIS_HEADER_SIZE + rndis_pkt->data_offset;
Hank Janssenfceaf242009-07-13 15:34:54 -0700359
Haiyang Zhang72a2f5b2010-12-10 12:03:58 -0800360 pkt->total_data_buflen -= data_offset;
Wei Yongjun4b8a8bc2012-02-01 20:17:23 +0000361
362 /*
363 * Make sure we got a valid RNDIS message, now total_data_buflen
364 * should be the data packet size plus the trailer padding size
365 */
366 if (pkt->total_data_buflen < rndis_pkt->data_len) {
Vitaly Kuznetsov3d541ac2016-05-13 13:55:22 +0200367 netdev_err(dev->ndev, "rndis message buffer "
Wei Yongjun4b8a8bc2012-02-01 20:17:23 +0000368 "overflow detected (got %u, min %u)"
369 "...dropping this message!\n",
370 pkt->total_data_buflen, rndis_pkt->data_len);
KY Srinivasan10082f92015-12-01 16:43:18 -0800371 return NVSP_STAT_FAIL;
Wei Yongjun4b8a8bc2012-02-01 20:17:23 +0000372 }
373
374 /*
375 * Remove the rndis trailer padding from rndis packet message
376 * rndis_pkt->data_len tell us the real data length, we only copy
377 * the data packet to the stack, without the rndis trailer padding
378 */
379 pkt->total_data_buflen = rndis_pkt->data_len;
KY Srinivasanc4b20c62015-12-01 16:43:07 -0800380 *data = (void *)((unsigned long)(*data) + data_offset);
Haiyang Zhang669c1fc2011-09-01 12:19:47 -0700381
Haiyang Zhang1f5f3a72012-03-12 10:20:50 +0000382 vlan = rndis_get_ppi(rndis_pkt, IEEE_8021Q_INFO);
383 if (vlan) {
KY Srinivasan760d1e32015-12-01 16:43:19 -0800384 vlan_tci = VLAN_TAG_PRESENT | vlan->vlanid |
Haiyang Zhang1f5f3a72012-03-12 10:20:50 +0000385 (vlan->pri << VLAN_PRIO_SHIFT);
Haiyang Zhang1f5f3a72012-03-12 10:20:50 +0000386 }
387
KY Srinivasane3d605e2014-03-08 19:23:16 -0800388 csum_info = rndis_get_ppi(rndis_pkt, TCPIP_CHKSUM_PKTINFO);
Vitaly Kuznetsov3d541ac2016-05-13 13:55:22 +0200389 return netvsc_recv_callback(net_device_ctx->device_ctx, pkt, data,
KY Srinivasan760d1e32015-12-01 16:43:19 -0800390 csum_info, channel, vlan_tci);
Hank Janssenfceaf242009-07-13 15:34:54 -0700391}
392
K. Y. Srinivasan5fcc4112011-05-12 19:34:52 -0700393int rndis_filter_receive(struct hv_device *dev,
KY Srinivasan25b85ee2015-12-01 16:43:05 -0800394 struct hv_netvsc_packet *pkt,
KY Srinivasanc4b20c62015-12-01 16:43:07 -0800395 void **data,
KY Srinivasan25b85ee2015-12-01 16:43:05 -0800396 struct vmbus_channel *channel)
Hank Janssenfceaf242009-07-13 15:34:54 -0700397{
Vitaly Kuznetsov3d541ac2016-05-13 13:55:22 +0200398 struct net_device *ndev = hv_get_drvdata(dev);
399 struct net_device_context *net_device_ctx = netdev_priv(ndev);
400 struct netvsc_device *net_dev = net_device_ctx->nvdev;
Haiyang Zhangc2a4efd2010-12-10 12:03:56 -0800401 struct rndis_device *rndis_dev;
Haiyang Zhangef31bef2012-03-12 10:20:49 +0000402 struct rndis_message *rndis_msg;
Haiyang Zhang63f69212012-10-02 05:30:23 +0000403 int ret = 0;
K. Y. Srinivasan2ddd5e52011-09-13 10:59:49 -0700404
Haiyang Zhang63f69212012-10-02 05:30:23 +0000405 if (!net_dev) {
KY Srinivasan10082f92015-12-01 16:43:18 -0800406 ret = NVSP_STAT_FAIL;
Haiyang Zhang63f69212012-10-02 05:30:23 +0000407 goto exit;
408 }
Bill Pemberton8a62d712010-05-05 15:27:47 -0400409
Bill Pemberton454f18a2009-07-27 16:47:24 -0400410 /* Make sure the rndis device state is initialized */
Haiyang Zhang53d21fd2010-12-10 12:03:59 -0800411 if (!net_dev->extension) {
Haiyang Zhangd9871152011-09-01 12:19:41 -0700412 netdev_err(ndev, "got rndis message but no rndis device - "
Hank Jansseneb335bc2011-03-29 13:58:48 -0700413 "dropping this message!\n");
KY Srinivasan10082f92015-12-01 16:43:18 -0800414 ret = NVSP_STAT_FAIL;
Haiyang Zhang63f69212012-10-02 05:30:23 +0000415 goto exit;
Hank Janssenfceaf242009-07-13 15:34:54 -0700416 }
417
Haiyang Zhang53d21fd2010-12-10 12:03:59 -0800418 rndis_dev = (struct rndis_device *)net_dev->extension;
Haiyang Zhangc2a4efd2010-12-10 12:03:56 -0800419 if (rndis_dev->state == RNDIS_DEV_UNINITIALIZED) {
Haiyang Zhangd9871152011-09-01 12:19:41 -0700420 netdev_err(ndev, "got rndis message but rndis device "
Hank Jansseneb335bc2011-03-29 13:58:48 -0700421 "uninitialized...dropping this message!\n");
KY Srinivasan10082f92015-12-01 16:43:18 -0800422 ret = NVSP_STAT_FAIL;
Haiyang Zhang63f69212012-10-02 05:30:23 +0000423 goto exit;
Hank Janssenfceaf242009-07-13 15:34:54 -0700424 }
425
KY Srinivasanc4b20c62015-12-01 16:43:07 -0800426 rndis_msg = *data;
Hank Janssenfceaf242009-07-13 15:34:54 -0700427
Vitaly Kuznetsov3d541ac2016-05-13 13:55:22 +0200428 if (netif_msg_rx_err(net_device_ctx))
Simon Xiao3f300ff2015-04-28 01:05:17 -0700429 dump_rndis_message(dev, rndis_msg);
Hank Janssenfceaf242009-07-13 15:34:54 -0700430
Haiyang Zhangef31bef2012-03-12 10:20:49 +0000431 switch (rndis_msg->ndis_msg_type) {
Linus Walleij51491162012-05-11 22:17:07 +0000432 case RNDIS_MSG_PACKET:
Greg Kroah-Hartman0120ee02009-09-02 09:17:52 -0700433 /* data msg */
KY Srinivasan10082f92015-12-01 16:43:18 -0800434 ret = rndis_filter_receive_data(rndis_dev, rndis_msg, pkt,
435 data, channel);
Hank Janssenfceaf242009-07-13 15:34:54 -0700436 break;
437
Linus Walleij51491162012-05-11 22:17:07 +0000438 case RNDIS_MSG_INIT_C:
439 case RNDIS_MSG_QUERY_C:
440 case RNDIS_MSG_SET_C:
Greg Kroah-Hartman0120ee02009-09-02 09:17:52 -0700441 /* completion msgs */
Haiyang Zhangef31bef2012-03-12 10:20:49 +0000442 rndis_filter_receive_response(rndis_dev, rndis_msg);
Hank Janssenfceaf242009-07-13 15:34:54 -0700443 break;
444
Linus Walleij51491162012-05-11 22:17:07 +0000445 case RNDIS_MSG_INDICATE:
Greg Kroah-Hartman0120ee02009-09-02 09:17:52 -0700446 /* notification msgs */
Haiyang Zhang3a494e72014-06-19 18:34:36 -0700447 netvsc_linkstatus_callback(dev, rndis_msg);
Hank Janssenfceaf242009-07-13 15:34:54 -0700448 break;
449 default:
Haiyang Zhangd9871152011-09-01 12:19:41 -0700450 netdev_err(ndev,
Hank Jansseneb335bc2011-03-29 13:58:48 -0700451 "unhandled rndis message (type %u len %u)\n",
Haiyang Zhangef31bef2012-03-12 10:20:49 +0000452 rndis_msg->ndis_msg_type,
453 rndis_msg->msg_len);
Hank Janssenfceaf242009-07-13 15:34:54 -0700454 break;
455 }
456
Haiyang Zhang63f69212012-10-02 05:30:23 +0000457exit:
Haiyang Zhang63f69212012-10-02 05:30:23 +0000458 return ret;
Hank Janssenfceaf242009-07-13 15:34:54 -0700459}
460
Haiyang Zhang9c26aa02010-12-10 12:03:57 -0800461static int rndis_filter_query_device(struct rndis_device *dev, u32 oid,
Haiyang Zhangc2a4efd2010-12-10 12:03:56 -0800462 void *result, u32 *result_size)
Hank Janssenfceaf242009-07-13 15:34:54 -0700463{
Greg Kroah-Hartmane681b952009-08-28 16:26:27 -0700464 struct rndis_request *request;
Haiyang Zhangc2a4efd2010-12-10 12:03:56 -0800465 u32 inresult_size = *result_size;
Greg Kroah-Hartman9f33d052009-08-19 16:26:24 -0700466 struct rndis_query_request *query;
Haiyang Zhangc2a4efd2010-12-10 12:03:56 -0800467 struct rndis_query_complete *query_complete;
Greg Kroah-Hartman0120ee02009-09-02 09:17:52 -0700468 int ret = 0;
Hank Janssenfceaf242009-07-13 15:34:54 -0700469
Haiyang Zhangc2a4efd2010-12-10 12:03:56 -0800470 if (!result)
Bill Pemberton8a62d712010-05-05 15:27:47 -0400471 return -EINVAL;
Hank Janssenfceaf242009-07-13 15:34:54 -0700472
Haiyang Zhangc2a4efd2010-12-10 12:03:56 -0800473 *result_size = 0;
Linus Walleij51491162012-05-11 22:17:07 +0000474 request = get_rndis_request(dev, RNDIS_MSG_QUERY,
Greg Kroah-Hartman0120ee02009-09-02 09:17:52 -0700475 RNDIS_MESSAGE_SIZE(struct rndis_query_request));
476 if (!request) {
K. Y. Srinivasande6e0582011-08-25 09:49:18 -0700477 ret = -ENOMEM;
K. Y. Srinivasan1c627872011-08-25 09:49:24 -0700478 goto cleanup;
Hank Janssenfceaf242009-07-13 15:34:54 -0700479 }
480
Bill Pemberton454f18a2009-07-27 16:47:24 -0400481 /* Setup the rndis query */
Haiyang Zhanga388eb12010-12-10 12:04:00 -0800482 query = &request->request_msg.msg.query_req;
483 query->oid = oid;
484 query->info_buf_offset = sizeof(struct rndis_query_request);
485 query->info_buflen = 0;
486 query->dev_vc_handle = 0;
Hank Janssenfceaf242009-07-13 15:34:54 -0700487
Haiyang Zhang5b54dac2014-04-21 10:20:28 -0700488 if (oid == OID_GEN_RECEIVE_SCALE_CAPABILITIES) {
489 struct ndis_recv_scale_cap *cap;
490
491 request->request_msg.msg_len +=
492 sizeof(struct ndis_recv_scale_cap);
493 query->info_buflen = sizeof(struct ndis_recv_scale_cap);
494 cap = (struct ndis_recv_scale_cap *)((unsigned long)query +
495 query->info_buf_offset);
496 cap->hdr.type = NDIS_OBJECT_TYPE_RSS_CAPABILITIES;
497 cap->hdr.rev = NDIS_RECEIVE_SCALE_CAPABILITIES_REVISION_2;
498 cap->hdr.size = sizeof(struct ndis_recv_scale_cap);
499 }
500
Haiyang Zhang9c26aa02010-12-10 12:03:57 -0800501 ret = rndis_filter_send_request(dev, request);
Hank Janssenfceaf242009-07-13 15:34:54 -0700502 if (ret != 0)
K. Y. Srinivasan1c627872011-08-25 09:49:24 -0700503 goto cleanup;
Hank Janssenfceaf242009-07-13 15:34:54 -0700504
Vitaly Kuznetsov53628552016-06-09 12:44:03 +0200505 wait_for_completion(&request->wait_event);
Hank Janssenfceaf242009-07-13 15:34:54 -0700506
Bill Pemberton454f18a2009-07-27 16:47:24 -0400507 /* Copy the response back */
Haiyang Zhanga388eb12010-12-10 12:04:00 -0800508 query_complete = &request->response_msg.msg.query_complete;
Hank Janssenfceaf242009-07-13 15:34:54 -0700509
Haiyang Zhanga388eb12010-12-10 12:04:00 -0800510 if (query_complete->info_buflen > inresult_size) {
Hank Janssenfceaf242009-07-13 15:34:54 -0700511 ret = -1;
K. Y. Srinivasan1c627872011-08-25 09:49:24 -0700512 goto cleanup;
Hank Janssenfceaf242009-07-13 15:34:54 -0700513 }
514
Haiyang Zhangc2a4efd2010-12-10 12:03:56 -0800515 memcpy(result,
516 (void *)((unsigned long)query_complete +
Haiyang Zhanga388eb12010-12-10 12:04:00 -0800517 query_complete->info_buf_offset),
518 query_complete->info_buflen);
Hank Janssenfceaf242009-07-13 15:34:54 -0700519
Haiyang Zhanga388eb12010-12-10 12:04:00 -0800520 *result_size = query_complete->info_buflen;
Hank Janssenfceaf242009-07-13 15:34:54 -0700521
K. Y. Srinivasan1c627872011-08-25 09:49:24 -0700522cleanup:
Hank Janssenfceaf242009-07-13 15:34:54 -0700523 if (request)
Haiyang Zhang9c26aa02010-12-10 12:03:57 -0800524 put_rndis_request(dev, request);
Hank Janssenfceaf242009-07-13 15:34:54 -0700525
526 return ret;
527}
528
Haiyang Zhang9c26aa02010-12-10 12:03:57 -0800529static int rndis_filter_query_device_mac(struct rndis_device *dev)
Hank Janssenfceaf242009-07-13 15:34:54 -0700530{
Stephen Hemminger9f8bd8b2010-05-04 09:58:54 -0700531 u32 size = ETH_ALEN;
Hank Janssenfceaf242009-07-13 15:34:54 -0700532
Haiyang Zhang9c26aa02010-12-10 12:03:57 -0800533 return rndis_filter_query_device(dev,
Greg Kroah-Hartman0120ee02009-09-02 09:17:52 -0700534 RNDIS_OID_802_3_PERMANENT_ADDRESS,
Haiyang Zhangc2a4efd2010-12-10 12:03:56 -0800535 dev->hw_mac_adr, &size);
Hank Janssenfceaf242009-07-13 15:34:54 -0700536}
537
Haiyang Zhang1ce09e82012-07-10 07:19:22 +0000538#define NWADR_STR "NetworkAddress"
539#define NWADR_STRLEN 14
540
Vitaly Kuznetsove834da9a2016-06-03 17:51:01 +0200541int rndis_filter_set_device_mac(struct net_device *ndev, char *mac)
Haiyang Zhang1ce09e82012-07-10 07:19:22 +0000542{
Vitaly Kuznetsov26254662016-06-03 17:50:59 +0200543 struct netvsc_device *nvdev = net_device_to_netvsc_device(ndev);
Haiyang Zhang1ce09e82012-07-10 07:19:22 +0000544 struct rndis_device *rdev = nvdev->extension;
Haiyang Zhang1ce09e82012-07-10 07:19:22 +0000545 struct rndis_request *request;
546 struct rndis_set_request *set;
547 struct rndis_config_parameter_info *cpi;
548 wchar_t *cfg_nwadr, *cfg_mac;
549 struct rndis_set_complete *set_complete;
550 char macstr[2*ETH_ALEN+1];
551 u32 extlen = sizeof(struct rndis_config_parameter_info) +
552 2*NWADR_STRLEN + 4*ETH_ALEN;
Nicholas Mc Guire999028c2015-01-25 15:48:23 +0100553 int ret;
Haiyang Zhang1ce09e82012-07-10 07:19:22 +0000554
555 request = get_rndis_request(rdev, RNDIS_MSG_SET,
556 RNDIS_MESSAGE_SIZE(struct rndis_set_request) + extlen);
557 if (!request)
558 return -ENOMEM;
559
560 set = &request->request_msg.msg.set_req;
561 set->oid = RNDIS_OID_GEN_RNDIS_CONFIG_PARAMETER;
562 set->info_buflen = extlen;
563 set->info_buf_offset = sizeof(struct rndis_set_request);
564 set->dev_vc_handle = 0;
565
566 cpi = (struct rndis_config_parameter_info *)((ulong)set +
567 set->info_buf_offset);
568 cpi->parameter_name_offset =
569 sizeof(struct rndis_config_parameter_info);
570 /* Multiply by 2 because host needs 2 bytes (utf16) for each char */
571 cpi->parameter_name_length = 2*NWADR_STRLEN;
572 cpi->parameter_type = RNDIS_CONFIG_PARAM_TYPE_STRING;
573 cpi->parameter_value_offset =
574 cpi->parameter_name_offset + cpi->parameter_name_length;
575 /* Multiply by 4 because each MAC byte displayed as 2 utf16 chars */
576 cpi->parameter_value_length = 4*ETH_ALEN;
577
578 cfg_nwadr = (wchar_t *)((ulong)cpi + cpi->parameter_name_offset);
579 cfg_mac = (wchar_t *)((ulong)cpi + cpi->parameter_value_offset);
580 ret = utf8s_to_utf16s(NWADR_STR, NWADR_STRLEN, UTF16_HOST_ENDIAN,
581 cfg_nwadr, NWADR_STRLEN);
582 if (ret < 0)
583 goto cleanup;
584 snprintf(macstr, 2*ETH_ALEN+1, "%pm", mac);
585 ret = utf8s_to_utf16s(macstr, 2*ETH_ALEN, UTF16_HOST_ENDIAN,
586 cfg_mac, 2*ETH_ALEN);
587 if (ret < 0)
588 goto cleanup;
589
590 ret = rndis_filter_send_request(rdev, request);
591 if (ret != 0)
592 goto cleanup;
593
Vitaly Kuznetsov53628552016-06-09 12:44:03 +0200594 wait_for_completion(&request->wait_event);
595
596 set_complete = &request->response_msg.msg.set_complete;
597 if (set_complete->status != RNDIS_STATUS_SUCCESS) {
598 netdev_err(ndev, "Fail to set MAC on host side:0x%x\n",
599 set_complete->status);
600 ret = -EINVAL;
Haiyang Zhang1ce09e82012-07-10 07:19:22 +0000601 }
602
603cleanup:
604 put_rndis_request(rdev, request);
605 return ret;
606}
607
Lad, Prabhakarda19fcd2015-02-05 15:06:33 +0000608static int
Vitaly Kuznetsov426d9542016-06-03 17:51:02 +0200609rndis_filter_set_offload_params(struct net_device *ndev,
KY Srinivasan4a0e70a2014-03-08 19:23:15 -0800610 struct ndis_offload_params *req_offloads)
611{
Vitaly Kuznetsov26254662016-06-03 17:50:59 +0200612 struct netvsc_device *nvdev = net_device_to_netvsc_device(ndev);
KY Srinivasan4a0e70a2014-03-08 19:23:15 -0800613 struct rndis_device *rdev = nvdev->extension;
KY Srinivasan4a0e70a2014-03-08 19:23:15 -0800614 struct rndis_request *request;
615 struct rndis_set_request *set;
616 struct ndis_offload_params *offload_params;
617 struct rndis_set_complete *set_complete;
618 u32 extlen = sizeof(struct ndis_offload_params);
Nicholas Mc Guire999028c2015-01-25 15:48:23 +0100619 int ret;
KY Srinivasanaf9893a2014-04-09 15:00:47 -0700620 u32 vsp_version = nvdev->nvsp_version;
621
622 if (vsp_version <= NVSP_PROTOCOL_VERSION_4) {
623 extlen = VERSION_4_OFFLOAD_SIZE;
624 /* On NVSP_PROTOCOL_VERSION_4 and below, we do not support
625 * UDP checksum offload.
626 */
627 req_offloads->udp_ip_v4_csum = 0;
628 req_offloads->udp_ip_v6_csum = 0;
629 }
KY Srinivasan4a0e70a2014-03-08 19:23:15 -0800630
631 request = get_rndis_request(rdev, RNDIS_MSG_SET,
632 RNDIS_MESSAGE_SIZE(struct rndis_set_request) + extlen);
633 if (!request)
634 return -ENOMEM;
635
636 set = &request->request_msg.msg.set_req;
637 set->oid = OID_TCP_OFFLOAD_PARAMETERS;
638 set->info_buflen = extlen;
639 set->info_buf_offset = sizeof(struct rndis_set_request);
640 set->dev_vc_handle = 0;
641
642 offload_params = (struct ndis_offload_params *)((ulong)set +
643 set->info_buf_offset);
644 *offload_params = *req_offloads;
645 offload_params->header.type = NDIS_OBJECT_TYPE_DEFAULT;
646 offload_params->header.revision = NDIS_OFFLOAD_PARAMETERS_REVISION_3;
647 offload_params->header.size = extlen;
648
649 ret = rndis_filter_send_request(rdev, request);
650 if (ret != 0)
651 goto cleanup;
652
Vitaly Kuznetsov53628552016-06-09 12:44:03 +0200653 wait_for_completion(&request->wait_event);
654 set_complete = &request->response_msg.msg.set_complete;
655 if (set_complete->status != RNDIS_STATUS_SUCCESS) {
656 netdev_err(ndev, "Fail to set offload on host side:0x%x\n",
657 set_complete->status);
658 ret = -EINVAL;
KY Srinivasan4a0e70a2014-03-08 19:23:15 -0800659 }
660
661cleanup:
662 put_rndis_request(rdev, request);
663 return ret;
664}
Haiyang Zhang1ce09e82012-07-10 07:19:22 +0000665
Stephen Hemminger94773862016-08-23 12:17:45 -0700666static const u8 netvsc_hash_key[] = {
Haiyang Zhang5b54dac2014-04-21 10:20:28 -0700667 0x6d, 0x5a, 0x56, 0xda, 0x25, 0x5b, 0x0e, 0xc2,
668 0x41, 0x67, 0x25, 0x3d, 0x43, 0xa3, 0x8f, 0xb0,
669 0xd0, 0xca, 0x2b, 0xcb, 0xae, 0x7b, 0x30, 0xb4,
670 0x77, 0xcb, 0x2d, 0xa3, 0x80, 0x30, 0xf2, 0x0c,
671 0x6a, 0x42, 0xb7, 0x3b, 0xbe, 0xac, 0x01, 0xfa
672};
Stephen Hemminger94773862016-08-23 12:17:45 -0700673#define HASH_KEYLEN ARRAY_SIZE(netvsc_hash_key)
Haiyang Zhang5b54dac2014-04-21 10:20:28 -0700674
Lad, Prabhakarda19fcd2015-02-05 15:06:33 +0000675static int rndis_filter_set_rss_param(struct rndis_device *rdev, int num_queue)
Haiyang Zhang5b54dac2014-04-21 10:20:28 -0700676{
Vitaly Kuznetsov3d541ac2016-05-13 13:55:22 +0200677 struct net_device *ndev = rdev->ndev;
Haiyang Zhang5b54dac2014-04-21 10:20:28 -0700678 struct rndis_request *request;
679 struct rndis_set_request *set;
680 struct rndis_set_complete *set_complete;
681 u32 extlen = sizeof(struct ndis_recv_scale_param) +
682 4*ITAB_NUM + HASH_KEYLEN;
683 struct ndis_recv_scale_param *rssp;
684 u32 *itab;
685 u8 *keyp;
Nicholas Mc Guire999028c2015-01-25 15:48:23 +0100686 int i, ret;
Haiyang Zhang5b54dac2014-04-21 10:20:28 -0700687
688 request = get_rndis_request(
689 rdev, RNDIS_MSG_SET,
690 RNDIS_MESSAGE_SIZE(struct rndis_set_request) + extlen);
691 if (!request)
692 return -ENOMEM;
693
694 set = &request->request_msg.msg.set_req;
695 set->oid = OID_GEN_RECEIVE_SCALE_PARAMETERS;
696 set->info_buflen = extlen;
697 set->info_buf_offset = sizeof(struct rndis_set_request);
698 set->dev_vc_handle = 0;
699
700 rssp = (struct ndis_recv_scale_param *)(set + 1);
701 rssp->hdr.type = NDIS_OBJECT_TYPE_RSS_PARAMETERS;
702 rssp->hdr.rev = NDIS_RECEIVE_SCALE_PARAMETERS_REVISION_2;
703 rssp->hdr.size = sizeof(struct ndis_recv_scale_param);
704 rssp->flag = 0;
705 rssp->hashinfo = NDIS_HASH_FUNC_TOEPLITZ | NDIS_HASH_IPV4 |
Haiyang Zhang4c874542014-10-30 14:07:17 -0700706 NDIS_HASH_TCP_IPV4 | NDIS_HASH_IPV6 |
707 NDIS_HASH_TCP_IPV6;
Haiyang Zhang5b54dac2014-04-21 10:20:28 -0700708 rssp->indirect_tabsize = 4*ITAB_NUM;
709 rssp->indirect_taboffset = sizeof(struct ndis_recv_scale_param);
710 rssp->hashkey_size = HASH_KEYLEN;
711 rssp->kashkey_offset = rssp->indirect_taboffset +
712 rssp->indirect_tabsize;
713
714 /* Set indirection table entries */
715 itab = (u32 *)(rssp + 1);
716 for (i = 0; i < ITAB_NUM; i++)
717 itab[i] = i % num_queue;
718
719 /* Set hask key values */
720 keyp = (u8 *)((unsigned long)rssp + rssp->kashkey_offset);
721 for (i = 0; i < HASH_KEYLEN; i++)
722 keyp[i] = netvsc_hash_key[i];
723
Haiyang Zhang5b54dac2014-04-21 10:20:28 -0700724 ret = rndis_filter_send_request(rdev, request);
725 if (ret != 0)
726 goto cleanup;
727
Vitaly Kuznetsov53628552016-06-09 12:44:03 +0200728 wait_for_completion(&request->wait_event);
729 set_complete = &request->response_msg.msg.set_complete;
730 if (set_complete->status != RNDIS_STATUS_SUCCESS) {
731 netdev_err(ndev, "Fail to set RSS parameters:0x%x\n",
732 set_complete->status);
733 ret = -EINVAL;
Haiyang Zhang5b54dac2014-04-21 10:20:28 -0700734 }
735
736cleanup:
737 put_rndis_request(rdev, request);
738 return ret;
739}
740
Haiyang Zhang9c26aa02010-12-10 12:03:57 -0800741static int rndis_filter_query_device_link_status(struct rndis_device *dev)
Hank Janssenfceaf242009-07-13 15:34:54 -0700742{
Greg Kroah-Hartman0120ee02009-09-02 09:17:52 -0700743 u32 size = sizeof(u32);
K. Y. Srinivasan6f274572011-09-13 15:21:27 -0700744 u32 link_status;
745 int ret;
Hank Janssenfceaf242009-07-13 15:34:54 -0700746
K. Y. Srinivasan6f274572011-09-13 15:21:27 -0700747 ret = rndis_filter_query_device(dev,
Greg Kroah-Hartman0120ee02009-09-02 09:17:52 -0700748 RNDIS_OID_GEN_MEDIA_CONNECT_STATUS,
K. Y. Srinivasan6f274572011-09-13 15:21:27 -0700749 &link_status, &size);
K. Y. Srinivasan6f274572011-09-13 15:21:27 -0700750
751 return ret;
Hank Janssenfceaf242009-07-13 15:34:54 -0700752}
753
Haiyang Zhangb37879e2016-08-04 10:42:14 -0700754static int rndis_filter_query_link_speed(struct rndis_device *dev)
755{
756 u32 size = sizeof(u32);
757 u32 link_speed;
758 struct net_device_context *ndc;
759 int ret;
760
761 ret = rndis_filter_query_device(dev, RNDIS_OID_GEN_LINK_SPEED,
762 &link_speed, &size);
763
764 if (!ret) {
765 ndc = netdev_priv(dev->ndev);
766
767 /* The link speed reported from host is in 100bps unit, so
768 * we convert it to Mbps here.
769 */
770 ndc->speed = link_speed / 10000;
771 }
772
773 return ret;
774}
775
Haiyang Zhangd426b2e2011-11-30 07:19:08 -0800776int rndis_filter_set_packet_filter(struct rndis_device *dev, u32 new_filter)
Hank Janssenfceaf242009-07-13 15:34:54 -0700777{
Greg Kroah-Hartmane681b952009-08-28 16:26:27 -0700778 struct rndis_request *request;
Greg Kroah-Hartman9f33d052009-08-19 16:26:24 -0700779 struct rndis_set_request *set;
Haiyang Zhangc2a4efd2010-12-10 12:03:56 -0800780 struct rndis_set_complete *set_complete;
Greg Kroah-Hartman4d643112009-07-14 15:09:36 -0700781 u32 status;
Nicholas Mc Guire999028c2015-01-25 15:48:23 +0100782 int ret;
Hank Janssenfceaf242009-07-13 15:34:54 -0700783
Linus Walleij51491162012-05-11 22:17:07 +0000784 request = get_rndis_request(dev, RNDIS_MSG_SET,
Greg Kroah-Hartman0120ee02009-09-02 09:17:52 -0700785 RNDIS_MESSAGE_SIZE(struct rndis_set_request) +
786 sizeof(u32));
787 if (!request) {
K. Y. Srinivasan58ef3972011-08-25 09:49:19 -0700788 ret = -ENOMEM;
K. Y. Srinivasan1c627872011-08-25 09:49:24 -0700789 goto cleanup;
Hank Janssenfceaf242009-07-13 15:34:54 -0700790 }
791
Bill Pemberton454f18a2009-07-27 16:47:24 -0400792 /* Setup the rndis set */
Haiyang Zhanga388eb12010-12-10 12:04:00 -0800793 set = &request->request_msg.msg.set_req;
794 set->oid = RNDIS_OID_GEN_CURRENT_PACKET_FILTER;
795 set->info_buflen = sizeof(u32);
796 set->info_buf_offset = sizeof(struct rndis_set_request);
Hank Janssenfceaf242009-07-13 15:34:54 -0700797
Greg Kroah-Hartman0120ee02009-09-02 09:17:52 -0700798 memcpy((void *)(unsigned long)set + sizeof(struct rndis_set_request),
Haiyang Zhangc2a4efd2010-12-10 12:03:56 -0800799 &new_filter, sizeof(u32));
Hank Janssenfceaf242009-07-13 15:34:54 -0700800
Haiyang Zhang9c26aa02010-12-10 12:03:57 -0800801 ret = rndis_filter_send_request(dev, request);
Hank Janssenfceaf242009-07-13 15:34:54 -0700802 if (ret != 0)
K. Y. Srinivasan1c627872011-08-25 09:49:24 -0700803 goto cleanup;
Hank Janssenfceaf242009-07-13 15:34:54 -0700804
Vitaly Kuznetsov53628552016-06-09 12:44:03 +0200805 wait_for_completion(&request->wait_event);
K. Y. Srinivasan98d79692011-05-10 07:55:42 -0700806
Vitaly Kuznetsov53628552016-06-09 12:44:03 +0200807 set_complete = &request->response_msg.msg.set_complete;
808 status = set_complete->status;
Hank Janssenfceaf242009-07-13 15:34:54 -0700809
K. Y. Srinivasan1c627872011-08-25 09:49:24 -0700810cleanup:
Hank Janssenfceaf242009-07-13 15:34:54 -0700811 if (request)
Haiyang Zhang9c26aa02010-12-10 12:03:57 -0800812 put_rndis_request(dev, request);
Hank Janssenfceaf242009-07-13 15:34:54 -0700813 return ret;
814}
815
Haiyang Zhang9c26aa02010-12-10 12:03:57 -0800816static int rndis_filter_init_device(struct rndis_device *dev)
Hank Janssenfceaf242009-07-13 15:34:54 -0700817{
Greg Kroah-Hartmane681b952009-08-28 16:26:27 -0700818 struct rndis_request *request;
Greg Kroah-Hartman9f33d052009-08-19 16:26:24 -0700819 struct rndis_initialize_request *init;
Haiyang Zhangc2a4efd2010-12-10 12:03:56 -0800820 struct rndis_initialize_complete *init_complete;
Greg Kroah-Hartman4d643112009-07-14 15:09:36 -0700821 u32 status;
Nicholas Mc Guire999028c2015-01-25 15:48:23 +0100822 int ret;
Vitaly Kuznetsov26254662016-06-03 17:50:59 +0200823 struct netvsc_device *nvdev = net_device_to_netvsc_device(dev->ndev);
Hank Janssenfceaf242009-07-13 15:34:54 -0700824
Linus Walleij51491162012-05-11 22:17:07 +0000825 request = get_rndis_request(dev, RNDIS_MSG_INIT,
Greg Kroah-Hartman0120ee02009-09-02 09:17:52 -0700826 RNDIS_MESSAGE_SIZE(struct rndis_initialize_request));
827 if (!request) {
K. Y. Srinivasanbc49b9262011-08-25 09:49:20 -0700828 ret = -ENOMEM;
K. Y. Srinivasan1c627872011-08-25 09:49:24 -0700829 goto cleanup;
Hank Janssenfceaf242009-07-13 15:34:54 -0700830 }
831
Bill Pemberton454f18a2009-07-27 16:47:24 -0400832 /* Setup the rndis set */
Haiyang Zhanga388eb12010-12-10 12:04:00 -0800833 init = &request->request_msg.msg.init_req;
834 init->major_ver = RNDIS_MAJOR_VERSION;
835 init->minor_ver = RNDIS_MINOR_VERSION;
Haiyang Zhangfb1d0742012-10-02 05:30:19 +0000836 init->max_xfer_size = 0x4000;
Hank Janssenfceaf242009-07-13 15:34:54 -0700837
Haiyang Zhangc2a4efd2010-12-10 12:03:56 -0800838 dev->state = RNDIS_DEV_INITIALIZING;
Hank Janssenfceaf242009-07-13 15:34:54 -0700839
Haiyang Zhang9c26aa02010-12-10 12:03:57 -0800840 ret = rndis_filter_send_request(dev, request);
Greg Kroah-Hartman0120ee02009-09-02 09:17:52 -0700841 if (ret != 0) {
Haiyang Zhangc2a4efd2010-12-10 12:03:56 -0800842 dev->state = RNDIS_DEV_UNINITIALIZED;
K. Y. Srinivasan1c627872011-08-25 09:49:24 -0700843 goto cleanup;
Hank Janssenfceaf242009-07-13 15:34:54 -0700844 }
845
Vitaly Kuznetsov53628552016-06-09 12:44:03 +0200846 wait_for_completion(&request->wait_event);
Hank Janssenfceaf242009-07-13 15:34:54 -0700847
Haiyang Zhanga388eb12010-12-10 12:04:00 -0800848 init_complete = &request->response_msg.msg.init_complete;
849 status = init_complete->status;
Greg Kroah-Hartman0120ee02009-09-02 09:17:52 -0700850 if (status == RNDIS_STATUS_SUCCESS) {
Haiyang Zhangc2a4efd2010-12-10 12:03:56 -0800851 dev->state = RNDIS_DEV_INITIALIZED;
Haiyang Zhang7c3877f2015-03-26 09:03:37 -0700852 nvdev->max_pkt = init_complete->max_pkt_per_msg;
853 nvdev->pkt_align = 1 << init_complete->pkt_alignment_factor;
Hank Janssenfceaf242009-07-13 15:34:54 -0700854 ret = 0;
Greg Kroah-Hartman0120ee02009-09-02 09:17:52 -0700855 } else {
Haiyang Zhangc2a4efd2010-12-10 12:03:56 -0800856 dev->state = RNDIS_DEV_UNINITIALIZED;
K. Y. Srinivasanbc49b9262011-08-25 09:49:20 -0700857 ret = -EINVAL;
Hank Janssenfceaf242009-07-13 15:34:54 -0700858 }
859
K. Y. Srinivasan1c627872011-08-25 09:49:24 -0700860cleanup:
Hank Janssenfceaf242009-07-13 15:34:54 -0700861 if (request)
Haiyang Zhang9c26aa02010-12-10 12:03:57 -0800862 put_rndis_request(dev, request);
Hank Janssenfceaf242009-07-13 15:34:54 -0700863
864 return ret;
865}
866
Haiyang Zhang9c26aa02010-12-10 12:03:57 -0800867static void rndis_filter_halt_device(struct rndis_device *dev)
Hank Janssenfceaf242009-07-13 15:34:54 -0700868{
Greg Kroah-Hartmane681b952009-08-28 16:26:27 -0700869 struct rndis_request *request;
Greg Kroah-Hartman9f33d052009-08-19 16:26:24 -0700870 struct rndis_halt_request *halt;
Vitaly Kuznetsov3d541ac2016-05-13 13:55:22 +0200871 struct net_device_context *net_device_ctx = netdev_priv(dev->ndev);
872 struct netvsc_device *nvdev = net_device_ctx->nvdev;
873 struct hv_device *hdev = net_device_ctx->device_ctx;
Haiyang Zhangae9e63b2012-08-03 09:32:18 +0000874 ulong flags;
Hank Janssenfceaf242009-07-13 15:34:54 -0700875
Bill Pemberton454f18a2009-07-27 16:47:24 -0400876 /* Attempt to do a rndis device halt */
Linus Walleij51491162012-05-11 22:17:07 +0000877 request = get_rndis_request(dev, RNDIS_MSG_HALT,
Greg Kroah-Hartman0120ee02009-09-02 09:17:52 -0700878 RNDIS_MESSAGE_SIZE(struct rndis_halt_request));
Hank Janssenfceaf242009-07-13 15:34:54 -0700879 if (!request)
K. Y. Srinivasan1c627872011-08-25 09:49:24 -0700880 goto cleanup;
Hank Janssenfceaf242009-07-13 15:34:54 -0700881
Bill Pemberton454f18a2009-07-27 16:47:24 -0400882 /* Setup the rndis set */
Haiyang Zhanga388eb12010-12-10 12:04:00 -0800883 halt = &request->request_msg.msg.halt_req;
884 halt->req_id = atomic_inc_return(&dev->new_req_id);
Hank Janssenfceaf242009-07-13 15:34:54 -0700885
Bill Pemberton454f18a2009-07-27 16:47:24 -0400886 /* Ignore return since this msg is optional. */
Haiyang Zhang9c26aa02010-12-10 12:03:57 -0800887 rndis_filter_send_request(dev, request);
Hank Janssenfceaf242009-07-13 15:34:54 -0700888
Haiyang Zhangc2a4efd2010-12-10 12:03:56 -0800889 dev->state = RNDIS_DEV_UNINITIALIZED;
Hank Janssenfceaf242009-07-13 15:34:54 -0700890
K. Y. Srinivasan1c627872011-08-25 09:49:24 -0700891cleanup:
Haiyang Zhangae9e63b2012-08-03 09:32:18 +0000892 spin_lock_irqsave(&hdev->channel->inbound_lock, flags);
893 nvdev->destroy = true;
894 spin_unlock_irqrestore(&hdev->channel->inbound_lock, flags);
895
896 /* Wait for all send completions */
897 wait_event(nvdev->wait_drain,
Haiyang Zhangc0b558e2016-08-19 14:47:09 -0700898 atomic_read(&nvdev->num_outstanding_sends) == 0 &&
899 atomic_read(&nvdev->num_outstanding_recvs) == 0);
Haiyang Zhangae9e63b2012-08-03 09:32:18 +0000900
Hank Janssenfceaf242009-07-13 15:34:54 -0700901 if (request)
Haiyang Zhang9c26aa02010-12-10 12:03:57 -0800902 put_rndis_request(dev, request);
Hank Janssenfceaf242009-07-13 15:34:54 -0700903}
904
Haiyang Zhang9c26aa02010-12-10 12:03:57 -0800905static int rndis_filter_open_device(struct rndis_device *dev)
Hank Janssenfceaf242009-07-13 15:34:54 -0700906{
Greg Kroah-Hartman0120ee02009-09-02 09:17:52 -0700907 int ret;
Hank Janssenfceaf242009-07-13 15:34:54 -0700908
Haiyang Zhangc2a4efd2010-12-10 12:03:56 -0800909 if (dev->state != RNDIS_DEV_INITIALIZED)
Hank Janssenfceaf242009-07-13 15:34:54 -0700910 return 0;
911
Haiyang Zhang9c26aa02010-12-10 12:03:57 -0800912 ret = rndis_filter_set_packet_filter(dev,
Greg Kroah-Hartman0120ee02009-09-02 09:17:52 -0700913 NDIS_PACKET_TYPE_BROADCAST |
Haiyang Zhang95beae92010-04-19 15:32:11 +0000914 NDIS_PACKET_TYPE_ALL_MULTICAST |
Greg Kroah-Hartman0120ee02009-09-02 09:17:52 -0700915 NDIS_PACKET_TYPE_DIRECTED);
Hank Janssenfceaf242009-07-13 15:34:54 -0700916 if (ret == 0)
Haiyang Zhangc2a4efd2010-12-10 12:03:56 -0800917 dev->state = RNDIS_DEV_DATAINITIALIZED;
Hank Janssenfceaf242009-07-13 15:34:54 -0700918
Hank Janssenfceaf242009-07-13 15:34:54 -0700919 return ret;
920}
921
Haiyang Zhang9c26aa02010-12-10 12:03:57 -0800922static int rndis_filter_close_device(struct rndis_device *dev)
Hank Janssenfceaf242009-07-13 15:34:54 -0700923{
924 int ret;
925
Haiyang Zhangc2a4efd2010-12-10 12:03:56 -0800926 if (dev->state != RNDIS_DEV_DATAINITIALIZED)
Hank Janssenfceaf242009-07-13 15:34:54 -0700927 return 0;
928
Haiyang Zhang9c26aa02010-12-10 12:03:57 -0800929 ret = rndis_filter_set_packet_filter(dev, 0);
Haiyang Zhangc3582a22014-12-01 13:28:39 -0800930 if (ret == -ENODEV)
931 ret = 0;
932
Hank Janssenfceaf242009-07-13 15:34:54 -0700933 if (ret == 0)
Haiyang Zhangc2a4efd2010-12-10 12:03:56 -0800934 dev->state = RNDIS_DEV_INITIALIZED;
Hank Janssenfceaf242009-07-13 15:34:54 -0700935
Hank Janssenfceaf242009-07-13 15:34:54 -0700936 return ret;
937}
938
Haiyang Zhang5b54dac2014-04-21 10:20:28 -0700939static void netvsc_sc_open(struct vmbus_channel *new_sc)
940{
Vitaly Kuznetsov3d541ac2016-05-13 13:55:22 +0200941 struct net_device *ndev =
942 hv_get_drvdata(new_sc->primary_channel->device_obj);
Vitaly Kuznetsov26254662016-06-03 17:50:59 +0200943 struct netvsc_device *nvscdev = net_device_to_netvsc_device(ndev);
Haiyang Zhang5b54dac2014-04-21 10:20:28 -0700944 u16 chn_index = new_sc->offermsg.offer.sub_channel_index;
945 int ret;
KY Srinivasanb3e6b822015-07-22 11:42:32 -0700946 unsigned long flags;
Haiyang Zhang5b54dac2014-04-21 10:20:28 -0700947
Haiyang Zhang5b54dac2014-04-21 10:20:28 -0700948 if (chn_index >= nvscdev->num_chn)
949 return;
950
951 set_per_channel_state(new_sc, nvscdev->sub_cb_buf + (chn_index - 1) *
952 NETVSC_PACKET_SIZE);
953
Haiyang Zhangc0b558e2016-08-19 14:47:09 -0700954 nvscdev->mrc[chn_index].buf = vzalloc(NETVSC_RECVSLOT_MAX *
955 sizeof(struct recv_comp_data));
956
Haiyang Zhang5b54dac2014-04-21 10:20:28 -0700957 ret = vmbus_open(new_sc, nvscdev->ring_size * PAGE_SIZE,
958 nvscdev->ring_size * PAGE_SIZE, NULL, 0,
959 netvsc_channel_cb, new_sc);
960
961 if (ret == 0)
962 nvscdev->chn_table[chn_index] = new_sc;
Haiyang Zhang3f735132016-03-23 14:54:48 -0700963
964 spin_lock_irqsave(&nvscdev->sc_lock, flags);
965 nvscdev->num_sc_offered--;
966 spin_unlock_irqrestore(&nvscdev->sc_lock, flags);
967 if (nvscdev->num_sc_offered == 0)
968 complete(&nvscdev->channel_init_wait);
Haiyang Zhang5b54dac2014-04-21 10:20:28 -0700969}
970
Haiyang Zhangbdbad572011-05-23 09:03:49 -0700971int rndis_filter_device_add(struct hv_device *dev,
Stephen Hemminger796cc882016-08-23 12:17:47 -0700972 void *additional_info)
Hank Janssenfceaf242009-07-13 15:34:54 -0700973{
974 int ret;
Vitaly Kuznetsov3d541ac2016-05-13 13:55:22 +0200975 struct net_device *net = hv_get_drvdata(dev);
976 struct net_device_context *net_device_ctx = netdev_priv(net);
K. Y. Srinivasan86c921a2011-09-13 10:59:54 -0700977 struct netvsc_device *net_device;
K. Y. Srinivasanb13cc342011-09-13 10:59:55 -0700978 struct rndis_device *rndis_device;
K. Y. Srinivasan3c4deba2011-09-13 10:59:56 -0700979 struct netvsc_device_info *device_info = additional_info;
KY Srinivasan4a0e70a2014-03-08 19:23:15 -0800980 struct ndis_offload_params offloads;
Haiyang Zhang5b54dac2014-04-21 10:20:28 -0700981 struct nvsp_message *init_packet;
Haiyang Zhang5b54dac2014-04-21 10:20:28 -0700982 struct ndis_recv_scale_cap rsscap;
983 u32 rsscap_size = sizeof(struct ndis_recv_scale_cap);
Haiyang Zhang4d3c9d32014-11-12 14:07:44 -0800984 u32 mtu, size;
KY Srinivasane01ec212015-05-27 13:16:57 -0700985 u32 num_rss_qs;
KY Srinivasanb3e6b822015-07-22 11:42:32 -0700986 u32 sc_delta;
KY Srinivasane01ec212015-05-27 13:16:57 -0700987 const struct cpumask *node_cpu_mask;
988 u32 num_possible_rss_qs;
KY Srinivasanb3e6b822015-07-22 11:42:32 -0700989 unsigned long flags;
Hank Janssenfceaf242009-07-13 15:34:54 -0700990
K. Y. Srinivasanb13cc342011-09-13 10:59:55 -0700991 rndis_device = get_rndis_device();
992 if (!rndis_device)
K. Y. Srinivasan327efba2011-08-25 09:49:21 -0700993 return -ENODEV;
Hank Janssenfceaf242009-07-13 15:34:54 -0700994
Greg Kroah-Hartman0120ee02009-09-02 09:17:52 -0700995 /*
996 * Let the inner driver handle this first to create the netvsc channel
997 * NOTE! Once the channel is created, we may get a receive callback
998 * (RndisFilterOnReceive()) before this call is completed
999 */
K. Y. Srinivasance5bf662011-05-10 07:55:00 -07001000 ret = netvsc_device_add(dev, additional_info);
Greg Kroah-Hartman0120ee02009-09-02 09:17:52 -07001001 if (ret != 0) {
K. Y. Srinivasanb13cc342011-09-13 10:59:55 -07001002 kfree(rndis_device);
Hank Janssenfceaf242009-07-13 15:34:54 -07001003 return ret;
1004 }
1005
Bill Pemberton454f18a2009-07-27 16:47:24 -04001006 /* Initialize the rndis device */
Vitaly Kuznetsov3d541ac2016-05-13 13:55:22 +02001007 net_device = net_device_ctx->nvdev;
Andrew Schwartzmeyer59995372015-02-26 16:27:14 -08001008 net_device->max_chn = 1;
Haiyang Zhang5b54dac2014-04-21 10:20:28 -07001009 net_device->num_chn = 1;
Hank Janssenfceaf242009-07-13 15:34:54 -07001010
KY Srinivasanb3e6b822015-07-22 11:42:32 -07001011 spin_lock_init(&net_device->sc_lock);
1012
K. Y. Srinivasanb13cc342011-09-13 10:59:55 -07001013 net_device->extension = rndis_device;
Vitaly Kuznetsov3d541ac2016-05-13 13:55:22 +02001014 rndis_device->ndev = net;
Hank Janssenfceaf242009-07-13 15:34:54 -07001015
Bill Pemberton454f18a2009-07-27 16:47:24 -04001016 /* Send the rndis initialization message */
K. Y. Srinivasanb13cc342011-09-13 10:59:55 -07001017 ret = rndis_filter_init_device(rndis_device);
Greg Kroah-Hartman0120ee02009-09-02 09:17:52 -07001018 if (ret != 0) {
Haiyang Zhang5243e7b2012-07-25 08:08:42 +00001019 rndis_filter_device_remove(dev);
1020 return ret;
Hank Janssenfceaf242009-07-13 15:34:54 -07001021 }
1022
Haiyang Zhang4d3c9d32014-11-12 14:07:44 -08001023 /* Get the MTU from the host */
1024 size = sizeof(u32);
1025 ret = rndis_filter_query_device(rndis_device,
1026 RNDIS_OID_GEN_MAXIMUM_FRAME_SIZE,
1027 &mtu, &size);
Vitaly Kuznetsov0a1275c2016-05-13 13:55:23 +02001028 if (ret == 0 && size == sizeof(u32) && mtu < net->mtu)
1029 net->mtu = mtu;
Haiyang Zhang4d3c9d32014-11-12 14:07:44 -08001030
Bill Pemberton454f18a2009-07-27 16:47:24 -04001031 /* Get the mac address */
K. Y. Srinivasanb13cc342011-09-13 10:59:55 -07001032 ret = rndis_filter_query_device_mac(rndis_device);
Greg Kroah-Hartman0120ee02009-09-02 09:17:52 -07001033 if (ret != 0) {
Haiyang Zhang5243e7b2012-07-25 08:08:42 +00001034 rndis_filter_device_remove(dev);
1035 return ret;
Hank Janssenfceaf242009-07-13 15:34:54 -07001036 }
1037
K. Y. Srinivasan3c4deba2011-09-13 10:59:56 -07001038 memcpy(device_info->mac_adr, rndis_device->hw_mac_adr, ETH_ALEN);
Hank Janssenfceaf242009-07-13 15:34:54 -07001039
KY Srinivasan4a0e70a2014-03-08 19:23:15 -08001040 /* Turn on the offloads; the host supports all of the relevant
1041 * offloads.
1042 */
1043 memset(&offloads, 0, sizeof(struct ndis_offload_params));
1044 /* A value of zero means "no change"; now turn on what we
1045 * want.
1046 */
1047 offloads.ip_v4_csum = NDIS_OFFLOAD_PARAMETERS_TX_RX_ENABLED;
1048 offloads.tcp_ip_v4_csum = NDIS_OFFLOAD_PARAMETERS_TX_RX_ENABLED;
1049 offloads.udp_ip_v4_csum = NDIS_OFFLOAD_PARAMETERS_TX_RX_ENABLED;
1050 offloads.tcp_ip_v6_csum = NDIS_OFFLOAD_PARAMETERS_TX_RX_ENABLED;
1051 offloads.udp_ip_v6_csum = NDIS_OFFLOAD_PARAMETERS_TX_RX_ENABLED;
1052 offloads.lso_v2_ipv4 = NDIS_OFFLOAD_PARAMETERS_LSOV2_ENABLED;
1053
Vitaly Kuznetsov426d9542016-06-03 17:51:02 +02001054 ret = rndis_filter_set_offload_params(net, &offloads);
KY Srinivasan4a0e70a2014-03-08 19:23:15 -08001055 if (ret)
1056 goto err_dev_remv;
1057
K. Y. Srinivasanb13cc342011-09-13 10:59:55 -07001058 rndis_filter_query_device_link_status(rndis_device);
Hank Janssenfceaf242009-07-13 15:34:54 -07001059
K. Y. Srinivasan6f274572011-09-13 15:21:27 -07001060 device_info->link_state = rndis_device->link_state;
Hank Jansseneb335bc2011-03-29 13:58:48 -07001061
K. Y. Srinivasan6f274572011-09-13 15:21:27 -07001062 dev_info(&dev->device, "Device MAC %pM link state %s\n",
K. Y. Srinivasanb13cc342011-09-13 10:59:55 -07001063 rndis_device->hw_mac_adr,
K. Y. Srinivasan6f274572011-09-13 15:21:27 -07001064 device_info->link_state ? "down" : "up");
Hank Janssenfceaf242009-07-13 15:34:54 -07001065
Haiyang Zhang5b54dac2014-04-21 10:20:28 -07001066 if (net_device->nvsp_version < NVSP_PROTOCOL_VERSION_5)
1067 return 0;
1068
Haiyang Zhangb37879e2016-08-04 10:42:14 -07001069 rndis_filter_query_link_speed(rndis_device);
1070
Haiyang Zhang5b54dac2014-04-21 10:20:28 -07001071 /* vRSS setup */
1072 memset(&rsscap, 0, rsscap_size);
1073 ret = rndis_filter_query_device(rndis_device,
1074 OID_GEN_RECEIVE_SCALE_CAPABILITIES,
1075 &rsscap, &rsscap_size);
1076 if (ret || rsscap.num_recv_que < 2)
1077 goto out;
1078
Haiyang Zhang9efc2f72016-03-23 09:43:10 -07001079 net_device->max_chn = min_t(u32, VRSS_CHANNEL_MAX, rsscap.num_recv_que);
KY Srinivasane01ec212015-05-27 13:16:57 -07001080
Haiyang Zhang9efc2f72016-03-23 09:43:10 -07001081 num_rss_qs = min(device_info->max_num_vrss_chns, net_device->max_chn);
KY Srinivasane01ec212015-05-27 13:16:57 -07001082
1083 /*
1084 * We will limit the VRSS channels to the number CPUs in the NUMA node
1085 * the primary channel is currently bound to.
1086 */
1087 node_cpu_mask = cpumask_of_node(cpu_to_node(dev->channel->target_cpu));
1088 num_possible_rss_qs = cpumask_weight(node_cpu_mask);
Andrew Schwartzmeyer8ebdcc52015-08-11 17:14:31 -07001089
1090 /* We will use the given number of channels if available. */
1091 if (device_info->num_chn && device_info->num_chn < net_device->max_chn)
1092 net_device->num_chn = device_info->num_chn;
1093 else
1094 net_device->num_chn = min(num_possible_rss_qs, num_rss_qs);
KY Srinivasane01ec212015-05-27 13:16:57 -07001095
KY Srinivasanb3e6b822015-07-22 11:42:32 -07001096 num_rss_qs = net_device->num_chn - 1;
1097 net_device->num_sc_offered = num_rss_qs;
1098
Haiyang Zhang5b54dac2014-04-21 10:20:28 -07001099 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;
Vitaly Kuznetsov53628552016-06-09 12:44:03 +02001125 wait_for_completion(&net_device->channel_init_wait);
1126
Haiyang Zhang5b54dac2014-04-21 10:20:28 -07001127 if (init_packet->msg.v5_msg.subchn_comp.status !=
1128 NVSP_STAT_SUCCESS) {
1129 ret = -ENODEV;
1130 goto out;
1131 }
1132 net_device->num_chn = 1 +
1133 init_packet->msg.v5_msg.subchn_comp.num_subchannels;
1134
Haiyang Zhang5b54dac2014-04-21 10:20:28 -07001135 ret = rndis_filter_set_rss_param(rndis_device, net_device->num_chn);
1136
KY Srinivasanb3e6b822015-07-22 11:42:32 -07001137 /*
Haiyang Zhangd66ab512016-03-04 15:07:43 -08001138 * Set the number of sub-channels to be received.
KY Srinivasanb3e6b822015-07-22 11:42:32 -07001139 */
1140 spin_lock_irqsave(&net_device->sc_lock, flags);
1141 sc_delta = num_rss_qs - (net_device->num_chn - 1);
1142 net_device->num_sc_offered -= sc_delta;
1143 spin_unlock_irqrestore(&net_device->sc_lock, flags);
1144
Haiyang Zhang5b54dac2014-04-21 10:20:28 -07001145out:
Andrew Schwartzmeyer59995372015-02-26 16:27:14 -08001146 if (ret) {
1147 net_device->max_chn = 1;
Haiyang Zhang5b54dac2014-04-21 10:20:28 -07001148 net_device->num_chn = 1;
Haiyang Zhangd66ab512016-03-04 15:07:43 -08001149 net_device->num_sc_offered = 0;
Andrew Schwartzmeyer59995372015-02-26 16:27:14 -08001150 }
KY Srinivasanb3e6b822015-07-22 11:42:32 -07001151
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{
Vitaly Kuznetsov26254662016-06-03 17:50:59 +02001161 struct netvsc_device *net_dev = hv_device_to_netvsc_device(dev);
Haiyang Zhang53d21fd2010-12-10 12:03:59 -08001162 struct rndis_device *rndis_dev = net_dev->extension;
Haiyang Zhangd66ab512016-03-04 15:07:43 -08001163
1164 /* If not all subchannel offers are complete, wait for them until
1165 * completion to avoid race.
1166 */
Vitaly Kuznetsov53628552016-06-09 12:44:03 +02001167 if (net_dev->num_sc_offered > 0)
1168 wait_for_completion(&net_dev->channel_init_wait);
Hank Janssenfceaf242009-07-13 15:34:54 -07001169
Bill Pemberton454f18a2009-07-27 16:47:24 -04001170 /* Halt and release the rndis device */
Haiyang Zhang9c26aa02010-12-10 12:03:57 -08001171 rndis_filter_halt_device(rndis_dev);
Hank Janssenfceaf242009-07-13 15:34:54 -07001172
Haiyang Zhangc2a4efd2010-12-10 12:03:56 -08001173 kfree(rndis_dev);
Haiyang Zhang53d21fd2010-12-10 12:03:59 -08001174 net_dev->extension = NULL;
Hank Janssenfceaf242009-07-13 15:34:54 -07001175
K. Y. Srinivasan3fae5c82011-05-10 07:55:02 -07001176 netvsc_device_remove(dev);
Hank Janssenfceaf242009-07-13 15:34:54 -07001177}
1178
Vitaly Kuznetsov2f5fa6c2016-06-03 17:51:00 +02001179int rndis_filter_open(struct netvsc_device *nvdev)
Hank Janssenfceaf242009-07-13 15:34:54 -07001180{
Vitaly Kuznetsov2f5fa6c2016-06-03 17:51:00 +02001181 if (!nvdev)
Bill Pemberton8a62d712010-05-05 15:27:47 -04001182 return -EINVAL;
1183
Vitaly Kuznetsov2f5fa6c2016-06-03 17:51:00 +02001184 if (atomic_inc_return(&nvdev->open_cnt) != 1)
KY Srinivasan84bf9ce2016-04-14 16:31:54 -07001185 return 0;
1186
Vitaly Kuznetsov2f5fa6c2016-06-03 17:51:00 +02001187 return rndis_filter_open_device(nvdev->extension);
Hank Janssenfceaf242009-07-13 15:34:54 -07001188}
1189
Vitaly Kuznetsov2f5fa6c2016-06-03 17:51:00 +02001190int rndis_filter_close(struct netvsc_device *nvdev)
Hank Janssenfceaf242009-07-13 15:34:54 -07001191{
Haiyang Zhang5fccab32012-02-05 12:13:08 +00001192 if (!nvdev)
Bill Pemberton8a62d712010-05-05 15:27:47 -04001193 return -EINVAL;
1194
KY Srinivasan84bf9ce2016-04-14 16:31:54 -07001195 if (atomic_dec_return(&nvdev->open_cnt) != 0)
1196 return 0;
1197
Haiyang Zhang5fccab32012-02-05 12:13:08 +00001198 return rndis_filter_close_device(nvdev->extension);
Hank Janssenfceaf242009-07-13 15:34:54 -07001199}