Staging: hv: Move the contents of logging.h to hyperv.h
[deliverable/linux.git] / drivers / staging / hv / rndis_filter.c
CommitLineData
fceaf24a 1/*
fceaf24a
HJ
2 * 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
14 * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
15 * Place - Suite 330, Boston, MA 02111-1307 USA.
16 *
17 * Authors:
18 * Haiyang Zhang <haiyangz@microsoft.com>
19 * Hank Janssen <hjanssen@microsoft.com>
fceaf24a 20 */
5654e932 21#include <linux/kernel.h>
0c3b7b2f
S
22#include <linux/sched.h>
23#include <linux/wait.h>
45da89e5 24#include <linux/highmem.h>
5a0e3ad6 25#include <linux/slab.h>
0120ee0d 26#include <linux/io.h>
9f8bd8ba 27#include <linux/if_ether.h>
eb335bc4 28#include <linux/netdevice.h>
3f335ea2
S
29
30#include "hyperv.h"
e3fe0bb6 31#include "hv_api.h"
a82c7a2a 32#include "netvsc_api.h"
043efcc3 33#include "rndis_filter.h"
fceaf24a 34
454f18a9 35/* Data types */
e681b954 36struct rndis_filter_driver_object {
454f18a9 37 /* The original driver */
c2a4efdd 38 struct netvsc_driver inner_drv;
e681b954 39};
fceaf24a 40
e681b954 41enum rndis_device_state {
fceaf24a
HJ
42 RNDIS_DEV_UNINITIALIZED = 0,
43 RNDIS_DEV_INITIALIZING,
44 RNDIS_DEV_INITIALIZED,
45 RNDIS_DEV_DATAINITIALIZED,
e681b954 46};
fceaf24a 47
e681b954 48struct rndis_device {
c2a4efdd 49 struct netvsc_device *net_dev;
fceaf24a 50
c2a4efdd
HZ
51 enum rndis_device_state state;
52 u32 link_stat;
53 atomic_t new_req_id;
fceaf24a 54
880fb89c 55 spinlock_t request_lock;
c2a4efdd 56 struct list_head req_list;
fceaf24a 57
c2a4efdd 58 unsigned char hw_mac_adr[ETH_ALEN];
e681b954 59};
fceaf24a 60
e681b954 61struct rndis_request {
c2a4efdd 62 struct list_head list_ent;
98d79690 63 struct completion wait_event;
fceaf24a 64
0120ee0d
GKH
65 /*
66 * FIXME: We assumed a fixed size response here. If we do ever need to
67 * handle a bigger response, we can either define a max response
68 * message or add a response buffer variable above this field
69 */
c2a4efdd 70 struct rndis_message response_msg;
fceaf24a 71
454f18a9 72 /* Simplify allocation by having a netvsc packet inline */
c2a4efdd
HZ
73 struct hv_netvsc_packet pkt;
74 struct hv_page_buffer buf;
454f18a9 75 /* FIXME: We assumed a fixed size request here. */
c2a4efdd 76 struct rndis_message request_msg;
e681b954 77};
fceaf24a
HJ
78
79
e681b954 80struct rndis_filter_packet {
c2a4efdd
HZ
81 void *completion_ctx;
82 void (*completion)(void *context);
83 struct rndis_message msg;
e681b954 84};
fceaf24a 85
454f18a9 86
9c26aa0d 87static int rndis_filter_send(struct hv_device *dev,
c2a4efdd 88 struct hv_netvsc_packet *pkt);
0120ee0d 89
9c26aa0d 90static void rndis_filter_send_completion(void *ctx);
0120ee0d 91
9c26aa0d 92static void rndis_filter_send_request_completion(void *ctx);
454f18a9
BP
93
94
95/* The one and only */
c2a4efdd 96static struct rndis_filter_driver_object rndis_filter;
fceaf24a 97
9c26aa0d 98static struct rndis_device *get_rndis_device(void)
fceaf24a 99{
e681b954 100 struct rndis_device *device;
fceaf24a 101
e681b954 102 device = kzalloc(sizeof(struct rndis_device), GFP_KERNEL);
fceaf24a 103 if (!device)
fceaf24a 104 return NULL;
fceaf24a 105
880fb89c 106 spin_lock_init(&device->request_lock);
fceaf24a 107
c2a4efdd 108 INIT_LIST_HEAD(&device->req_list);
fceaf24a 109
c2a4efdd 110 device->state = RNDIS_DEV_UNINITIALIZED;
fceaf24a
HJ
111
112 return device;
113}
114
9c26aa0d 115static struct rndis_request *get_rndis_request(struct rndis_device *dev,
c2a4efdd
HZ
116 u32 msg_type,
117 u32 msg_len)
fceaf24a 118{
e681b954 119 struct rndis_request *request;
c2a4efdd 120 struct rndis_message *rndis_msg;
9f33d054 121 struct rndis_set_request *set;
880fb89c 122 unsigned long flags;
fceaf24a 123
e681b954 124 request = kzalloc(sizeof(struct rndis_request), GFP_KERNEL);
fceaf24a 125 if (!request)
fceaf24a 126 return NULL;
fceaf24a 127
98d79690 128 init_completion(&request->wait_event);
fceaf24a 129
c2a4efdd 130 rndis_msg = &request->request_msg;
a388eb17
HZ
131 rndis_msg->ndis_msg_type = msg_type;
132 rndis_msg->msg_len = msg_len;
fceaf24a 133
0120ee0d
GKH
134 /*
135 * Set the request id. This field is always after the rndis header for
136 * request/response packet types so we just used the SetRequest as a
137 * template
138 */
a388eb17
HZ
139 set = &rndis_msg->msg.set_req;
140 set->req_id = atomic_inc_return(&dev->new_req_id);
fceaf24a 141
454f18a9 142 /* Add to the request list */
c2a4efdd
HZ
143 spin_lock_irqsave(&dev->request_lock, flags);
144 list_add_tail(&request->list_ent, &dev->req_list);
145 spin_unlock_irqrestore(&dev->request_lock, flags);
fceaf24a
HJ
146
147 return request;
148}
149
9c26aa0d 150static void put_rndis_request(struct rndis_device *dev,
c2a4efdd 151 struct rndis_request *req)
fceaf24a 152{
880fb89c
GKH
153 unsigned long flags;
154
c2a4efdd
HZ
155 spin_lock_irqsave(&dev->request_lock, flags);
156 list_del(&req->list_ent);
157 spin_unlock_irqrestore(&dev->request_lock, flags);
fceaf24a 158
c2a4efdd 159 kfree(req);
fceaf24a
HJ
160}
161
9c26aa0d 162static void dump_rndis_message(struct rndis_message *rndis_msg)
fceaf24a 163{
a388eb17 164 switch (rndis_msg->ndis_msg_type) {
fceaf24a 165 case REMOTE_NDIS_PACKET_MSG:
0120ee0d
GKH
166 DPRINT_DBG(NETVSC, "REMOTE_NDIS_PACKET_MSG (len %u, "
167 "data offset %u data len %u, # oob %u, "
168 "oob offset %u, oob len %u, pkt offset %u, "
169 "pkt len %u",
a388eb17
HZ
170 rndis_msg->msg_len,
171 rndis_msg->msg.pkt.data_offset,
172 rndis_msg->msg.pkt.data_len,
173 rndis_msg->msg.pkt.num_oob_data_elements,
174 rndis_msg->msg.pkt.oob_data_offset,
175 rndis_msg->msg.pkt.oob_data_len,
176 rndis_msg->msg.pkt.per_pkt_info_offset,
177 rndis_msg->msg.pkt.per_pkt_info_len);
fceaf24a
HJ
178 break;
179
180 case REMOTE_NDIS_INITIALIZE_CMPLT:
0120ee0d
GKH
181 DPRINT_DBG(NETVSC, "REMOTE_NDIS_INITIALIZE_CMPLT "
182 "(len %u, id 0x%x, status 0x%x, major %d, minor %d, "
183 "device flags %d, max xfer size 0x%x, max pkts %u, "
184 "pkt aligned %u)",
a388eb17
HZ
185 rndis_msg->msg_len,
186 rndis_msg->msg.init_complete.req_id,
187 rndis_msg->msg.init_complete.status,
188 rndis_msg->msg.init_complete.major_ver,
189 rndis_msg->msg.init_complete.minor_ver,
190 rndis_msg->msg.init_complete.dev_flags,
191 rndis_msg->msg.init_complete.max_xfer_size,
192 rndis_msg->msg.init_complete.
193 max_pkt_per_msg,
194 rndis_msg->msg.init_complete.
195 pkt_alignment_factor);
fceaf24a
HJ
196 break;
197
198 case REMOTE_NDIS_QUERY_CMPLT:
0120ee0d
GKH
199 DPRINT_DBG(NETVSC, "REMOTE_NDIS_QUERY_CMPLT "
200 "(len %u, id 0x%x, status 0x%x, buf len %u, "
201 "buf offset %u)",
a388eb17
HZ
202 rndis_msg->msg_len,
203 rndis_msg->msg.query_complete.req_id,
204 rndis_msg->msg.query_complete.status,
205 rndis_msg->msg.query_complete.
206 info_buflen,
207 rndis_msg->msg.query_complete.
208 info_buf_offset);
fceaf24a
HJ
209 break;
210
211 case REMOTE_NDIS_SET_CMPLT:
0120ee0d
GKH
212 DPRINT_DBG(NETVSC,
213 "REMOTE_NDIS_SET_CMPLT (len %u, id 0x%x, status 0x%x)",
a388eb17
HZ
214 rndis_msg->msg_len,
215 rndis_msg->msg.set_complete.req_id,
216 rndis_msg->msg.set_complete.status);
fceaf24a
HJ
217 break;
218
219 case REMOTE_NDIS_INDICATE_STATUS_MSG:
0120ee0d
GKH
220 DPRINT_DBG(NETVSC, "REMOTE_NDIS_INDICATE_STATUS_MSG "
221 "(len %u, status 0x%x, buf len %u, buf offset %u)",
a388eb17
HZ
222 rndis_msg->msg_len,
223 rndis_msg->msg.indicate_status.status,
224 rndis_msg->msg.indicate_status.status_buflen,
225 rndis_msg->msg.indicate_status.status_buf_offset);
fceaf24a
HJ
226 break;
227
228 default:
229 DPRINT_DBG(NETVSC, "0x%x (len %u)",
a388eb17
HZ
230 rndis_msg->ndis_msg_type,
231 rndis_msg->msg_len);
fceaf24a
HJ
232 break;
233 }
234}
235
9c26aa0d 236static int rndis_filter_send_request(struct rndis_device *dev,
c2a4efdd 237 struct rndis_request *req)
fceaf24a 238{
0120ee0d 239 int ret;
4193d4f4 240 struct hv_netvsc_packet *packet;
fceaf24a 241
454f18a9 242 /* Setup the packet to send it */
c2a4efdd 243 packet = &req->pkt;
fceaf24a 244
72a2f5bd 245 packet->is_data_pkt = false;
a388eb17 246 packet->total_data_buflen = req->request_msg.msg_len;
72a2f5bd 247 packet->page_buf_cnt = 1;
fceaf24a 248
ca623ad3 249 packet->page_buf[0].pfn = virt_to_phys(&req->request_msg) >>
0120ee0d 250 PAGE_SHIFT;
ca623ad3
HZ
251 packet->page_buf[0].len = req->request_msg.msg_len;
252 packet->page_buf[0].offset =
c2a4efdd 253 (unsigned long)&req->request_msg & (PAGE_SIZE - 1);
fceaf24a 254
72a2f5bd
HZ
255 packet->completion.send.send_completion_ctx = req;/* packet; */
256 packet->completion.send.send_completion =
9c26aa0d 257 rndis_filter_send_request_completion;
72a2f5bd 258 packet->completion.send.send_completion_tid = (unsigned long)dev;
fceaf24a 259
53d21fdb 260 ret = rndis_filter.inner_drv.send(dev->net_dev->dev, packet);
fceaf24a
HJ
261 return ret;
262}
263
9c26aa0d 264static void rndis_filter_receive_response(struct rndis_device *dev,
c2a4efdd 265 struct rndis_message *resp)
fceaf24a 266{
e681b954 267 struct rndis_request *request = NULL;
0e727613 268 bool found = false;
880fb89c 269 unsigned long flags;
fceaf24a 270
c2a4efdd
HZ
271 spin_lock_irqsave(&dev->request_lock, flags);
272 list_for_each_entry(request, &dev->req_list, list_ent) {
0120ee0d
GKH
273 /*
274 * All request/response message contains RequestId as the 1st
275 * field
276 */
a388eb17
HZ
277 if (request->request_msg.msg.init_req.req_id
278 == resp->msg.init_complete.req_id) {
0e727613 279 found = true;
fceaf24a
HJ
280 break;
281 }
282 }
c2a4efdd 283 spin_unlock_irqrestore(&dev->request_lock, flags);
fceaf24a 284
0120ee0d 285 if (found) {
a388eb17 286 if (resp->msg_len <= sizeof(struct rndis_message)) {
c2a4efdd 287 memcpy(&request->response_msg, resp,
a388eb17 288 resp->msg_len);
0120ee0d 289 } else {
eb335bc4
HJ
290 dev_err(&dev->net_dev->dev->device,
291 "rndis response buffer overflow "
292 "detected (size %u max %zu)\n",
293 resp->msg_len,
294 sizeof(struct rndis_filter_packet));
0120ee0d 295
a388eb17 296 if (resp->ndis_msg_type ==
0120ee0d
GKH
297 REMOTE_NDIS_RESET_CMPLT) {
298 /* does not have a request id field */
a388eb17
HZ
299 request->response_msg.msg.reset_complete.
300 status = STATUS_BUFFER_OVERFLOW;
0120ee0d 301 } else {
a388eb17
HZ
302 request->response_msg.msg.
303 init_complete.status =
c2a4efdd 304 STATUS_BUFFER_OVERFLOW;
fceaf24a
HJ
305 }
306 }
307
98d79690 308 complete(&request->wait_event);
0120ee0d 309 } else {
eb335bc4
HJ
310 dev_err(&dev->net_dev->dev->device,
311 "no rndis request found for this response "
312 "(id 0x%x res type 0x%x)\n",
313 resp->msg.init_complete.req_id,
314 resp->ndis_msg_type);
fceaf24a 315 }
fceaf24a
HJ
316}
317
9c26aa0d 318static void rndis_filter_receive_indicate_status(struct rndis_device *dev,
c2a4efdd 319 struct rndis_message *resp)
fceaf24a 320{
0120ee0d 321 struct rndis_indicate_status *indicate =
a388eb17 322 &resp->msg.indicate_status;
fceaf24a 323
a388eb17 324 if (indicate->status == RNDIS_STATUS_MEDIA_CONNECT) {
72a2f5bd 325 rndis_filter.inner_drv.link_status_change(
53d21fdb 326 dev->net_dev->dev, 1);
a388eb17 327 } else if (indicate->status == RNDIS_STATUS_MEDIA_DISCONNECT) {
72a2f5bd 328 rndis_filter.inner_drv.link_status_change(
53d21fdb 329 dev->net_dev->dev, 0);
0120ee0d
GKH
330 } else {
331 /*
332 * TODO:
333 */
fceaf24a
HJ
334 }
335}
336
9c26aa0d 337static void rndis_filter_receive_data(struct rndis_device *dev,
c2a4efdd
HZ
338 struct rndis_message *msg,
339 struct hv_netvsc_packet *pkt)
fceaf24a 340{
c2a4efdd
HZ
341 struct rndis_packet *rndis_pkt;
342 u32 data_offset;
fceaf24a 343
a388eb17 344 rndis_pkt = &msg->msg.pkt;
fceaf24a 345
0120ee0d
GKH
346 /*
347 * FIXME: Handle multiple rndis pkt msgs that maybe enclosed in this
348 * netvsc packet (ie TotalDataBufferLength != MessageLength)
349 */
fceaf24a 350
454f18a9 351 /* Remove the rndis header and pass it back up the stack */
a388eb17 352 data_offset = RNDIS_HEADER_SIZE + rndis_pkt->data_offset;
fceaf24a 353
72a2f5bd 354 pkt->total_data_buflen -= data_offset;
ca623ad3
HZ
355 pkt->page_buf[0].offset += data_offset;
356 pkt->page_buf[0].len -= data_offset;
fceaf24a 357
72a2f5bd 358 pkt->is_data_pkt = true;
fceaf24a 359
53d21fdb 360 rndis_filter.inner_drv.recv_cb(dev->net_dev->dev,
c2a4efdd 361 pkt);
fceaf24a
HJ
362}
363
9c26aa0d 364static int rndis_filter_receive(struct hv_device *dev,
c2a4efdd 365 struct hv_netvsc_packet *pkt)
fceaf24a 366{
ca623ad3 367 struct netvsc_device *net_dev = dev->ext;
c2a4efdd
HZ
368 struct rndis_device *rndis_dev;
369 struct rndis_message rndis_msg;
370 struct rndis_message *rndis_hdr;
fceaf24a 371
c2a4efdd 372 if (!net_dev)
8a62d716
BP
373 return -EINVAL;
374
454f18a9 375 /* Make sure the rndis device state is initialized */
53d21fdb 376 if (!net_dev->extension) {
eb335bc4
HJ
377 dev_err(&dev->device, "got rndis message but no rndis device - "
378 "dropping this message!\n");
fceaf24a
HJ
379 return -1;
380 }
381
53d21fdb 382 rndis_dev = (struct rndis_device *)net_dev->extension;
c2a4efdd 383 if (rndis_dev->state == RNDIS_DEV_UNINITIALIZED) {
eb335bc4
HJ
384 dev_err(&dev->device, "got rndis message but rndis device "
385 "uninitialized...dropping this message!\n");
fceaf24a
HJ
386 return -1;
387 }
388
c2a4efdd 389 rndis_hdr = (struct rndis_message *)kmap_atomic(
ca623ad3 390 pfn_to_page(pkt->page_buf[0].pfn), KM_IRQ0);
fceaf24a 391
c2a4efdd 392 rndis_hdr = (void *)((unsigned long)rndis_hdr +
ca623ad3 393 pkt->page_buf[0].offset);
fceaf24a 394
454f18a9 395 /* Make sure we got a valid rndis message */
0120ee0d
GKH
396 /*
397 * FIXME: There seems to be a bug in set completion msg where its
398 * MessageLength is 16 bytes but the ByteCount field in the xfer page
399 * range shows 52 bytes
400 * */
fceaf24a 401#if 0
a388eb17 402 if (pkt->total_data_buflen != rndis_hdr->msg_len) {
ca623ad3 403 kunmap_atomic(rndis_hdr - pkt->page_buf[0].offset,
0120ee0d
GKH
404 KM_IRQ0);
405
eb335bc4
HJ
406 dev_err(&dev->device, "invalid rndis message? (expected %u "
407 "bytes got %u)...dropping this message!\n",
a388eb17 408 rndis_hdr->msg_len,
72a2f5bd 409 pkt->total_data_buflen);
fceaf24a
HJ
410 return -1;
411 }
412#endif
413
a388eb17
HZ
414 if ((rndis_hdr->ndis_msg_type != REMOTE_NDIS_PACKET_MSG) &&
415 (rndis_hdr->msg_len > sizeof(struct rndis_message))) {
eb335bc4
HJ
416 dev_err(&dev->device, "incoming rndis message buffer overflow "
417 "detected (got %u, max %zu)..marking it an error!\n",
a388eb17 418 rndis_hdr->msg_len,
0120ee0d 419 sizeof(struct rndis_message));
fceaf24a
HJ
420 }
421
c2a4efdd 422 memcpy(&rndis_msg, rndis_hdr,
a388eb17 423 (rndis_hdr->msg_len > sizeof(struct rndis_message)) ?
0120ee0d 424 sizeof(struct rndis_message) :
a388eb17 425 rndis_hdr->msg_len);
fceaf24a 426
ca623ad3 427 kunmap_atomic(rndis_hdr - pkt->page_buf[0].offset, KM_IRQ0);
fceaf24a 428
9c26aa0d 429 dump_rndis_message(&rndis_msg);
fceaf24a 430
a388eb17 431 switch (rndis_msg.ndis_msg_type) {
fceaf24a 432 case REMOTE_NDIS_PACKET_MSG:
0120ee0d 433 /* data msg */
9c26aa0d 434 rndis_filter_receive_data(rndis_dev, &rndis_msg, pkt);
fceaf24a
HJ
435 break;
436
fceaf24a
HJ
437 case REMOTE_NDIS_INITIALIZE_CMPLT:
438 case REMOTE_NDIS_QUERY_CMPLT:
439 case REMOTE_NDIS_SET_CMPLT:
0120ee0d 440 /* completion msgs */
9c26aa0d 441 rndis_filter_receive_response(rndis_dev, &rndis_msg);
fceaf24a
HJ
442 break;
443
fceaf24a 444 case REMOTE_NDIS_INDICATE_STATUS_MSG:
0120ee0d 445 /* notification msgs */
9c26aa0d 446 rndis_filter_receive_indicate_status(rndis_dev, &rndis_msg);
fceaf24a
HJ
447 break;
448 default:
eb335bc4
HJ
449 dev_err(&dev->device,
450 "unhandled rndis message (type %u len %u)\n",
a388eb17
HZ
451 rndis_msg.ndis_msg_type,
452 rndis_msg.msg_len);
fceaf24a
HJ
453 break;
454 }
455
fceaf24a
HJ
456 return 0;
457}
458
9c26aa0d 459static int rndis_filter_query_device(struct rndis_device *dev, u32 oid,
c2a4efdd 460 void *result, u32 *result_size)
fceaf24a 461{
e681b954 462 struct rndis_request *request;
c2a4efdd 463 u32 inresult_size = *result_size;
9f33d054 464 struct rndis_query_request *query;
c2a4efdd 465 struct rndis_query_complete *query_complete;
0120ee0d 466 int ret = 0;
98d79690 467 int t;
fceaf24a 468
c2a4efdd 469 if (!result)
8a62d716 470 return -EINVAL;
fceaf24a 471
c2a4efdd 472 *result_size = 0;
9c26aa0d 473 request = get_rndis_request(dev, REMOTE_NDIS_QUERY_MSG,
0120ee0d
GKH
474 RNDIS_MESSAGE_SIZE(struct rndis_query_request));
475 if (!request) {
fceaf24a
HJ
476 ret = -1;
477 goto Cleanup;
478 }
479
454f18a9 480 /* Setup the rndis query */
a388eb17
HZ
481 query = &request->request_msg.msg.query_req;
482 query->oid = oid;
483 query->info_buf_offset = sizeof(struct rndis_query_request);
484 query->info_buflen = 0;
485 query->dev_vc_handle = 0;
fceaf24a 486
9c26aa0d 487 ret = rndis_filter_send_request(dev, request);
fceaf24a 488 if (ret != 0)
fceaf24a 489 goto Cleanup;
fceaf24a 490
98d79690
S
491 t = wait_for_completion_timeout(&request->wait_event, HZ);
492 if (t == 0) {
0c3b7b2f
S
493 ret = -ETIMEDOUT;
494 goto Cleanup;
495 }
fceaf24a 496
454f18a9 497 /* Copy the response back */
a388eb17 498 query_complete = &request->response_msg.msg.query_complete;
fceaf24a 499
a388eb17 500 if (query_complete->info_buflen > inresult_size) {
fceaf24a
HJ
501 ret = -1;
502 goto Cleanup;
503 }
504
c2a4efdd
HZ
505 memcpy(result,
506 (void *)((unsigned long)query_complete +
a388eb17
HZ
507 query_complete->info_buf_offset),
508 query_complete->info_buflen);
fceaf24a 509
a388eb17 510 *result_size = query_complete->info_buflen;
fceaf24a
HJ
511
512Cleanup:
513 if (request)
9c26aa0d 514 put_rndis_request(dev, request);
fceaf24a
HJ
515
516 return ret;
517}
518
9c26aa0d 519static int rndis_filter_query_device_mac(struct rndis_device *dev)
fceaf24a 520{
9f8bd8ba 521 u32 size = ETH_ALEN;
fceaf24a 522
9c26aa0d 523 return rndis_filter_query_device(dev,
0120ee0d 524 RNDIS_OID_802_3_PERMANENT_ADDRESS,
c2a4efdd 525 dev->hw_mac_adr, &size);
fceaf24a
HJ
526}
527
9c26aa0d 528static int rndis_filter_query_device_link_status(struct rndis_device *dev)
fceaf24a 529{
0120ee0d 530 u32 size = sizeof(u32);
fceaf24a 531
9c26aa0d 532 return rndis_filter_query_device(dev,
0120ee0d 533 RNDIS_OID_GEN_MEDIA_CONNECT_STATUS,
c2a4efdd 534 &dev->link_stat, &size);
fceaf24a
HJ
535}
536
9c26aa0d 537static int rndis_filter_set_packet_filter(struct rndis_device *dev,
c2a4efdd 538 u32 new_filter)
fceaf24a 539{
e681b954 540 struct rndis_request *request;
9f33d054 541 struct rndis_set_request *set;
c2a4efdd 542 struct rndis_set_complete *set_complete;
4d643114 543 u32 status;
98d79690 544 int ret, t;
fceaf24a 545
9c26aa0d 546 request = get_rndis_request(dev, REMOTE_NDIS_SET_MSG,
0120ee0d
GKH
547 RNDIS_MESSAGE_SIZE(struct rndis_set_request) +
548 sizeof(u32));
549 if (!request) {
fceaf24a
HJ
550 ret = -1;
551 goto Cleanup;
552 }
553
454f18a9 554 /* Setup the rndis set */
a388eb17
HZ
555 set = &request->request_msg.msg.set_req;
556 set->oid = RNDIS_OID_GEN_CURRENT_PACKET_FILTER;
557 set->info_buflen = sizeof(u32);
558 set->info_buf_offset = sizeof(struct rndis_set_request);
fceaf24a 559
0120ee0d 560 memcpy((void *)(unsigned long)set + sizeof(struct rndis_set_request),
c2a4efdd 561 &new_filter, sizeof(u32));
fceaf24a 562
9c26aa0d 563 ret = rndis_filter_send_request(dev, request);
fceaf24a 564 if (ret != 0)
fceaf24a 565 goto Cleanup;
fceaf24a 566
98d79690
S
567 t = wait_for_completion_timeout(&request->wait_event, HZ);
568
569 if (t == 0) {
fceaf24a 570 ret = -1;
eb335bc4
HJ
571 dev_err(&dev->net_dev->dev->device,
572 "timeout before we got a set response...\n");
0120ee0d 573 /*
25985edc 574 * We can't deallocate the request since we may still receive a
0120ee0d
GKH
575 * send completion for it.
576 */
fceaf24a 577 goto Exit;
0120ee0d 578 } else {
fceaf24a 579 if (ret > 0)
fceaf24a 580 ret = 0;
a388eb17
HZ
581 set_complete = &request->response_msg.msg.set_complete;
582 status = set_complete->status;
fceaf24a
HJ
583 }
584
585Cleanup:
586 if (request)
9c26aa0d 587 put_rndis_request(dev, request);
fceaf24a 588Exit:
fceaf24a
HJ
589 return ret;
590}
591
9c26aa0d 592int rndis_filter_init(struct netvsc_driver *drv)
fceaf24a 593{
72a2f5bd 594 drv->req_ext_size = sizeof(struct rndis_filter_packet);
fceaf24a 595
454f18a9 596 /* Driver->Context = rndisDriver; */
fceaf24a 597
c2a4efdd 598 memset(&rndis_filter, 0, sizeof(struct rndis_filter_driver_object));
fceaf24a
HJ
599
600 /*rndisDriver->Driver = Driver;
601
602 ASSERT(Driver->OnLinkStatusChanged);
603 rndisDriver->OnLinkStatusChanged = Driver->OnLinkStatusChanged;*/
604
454f18a9 605 /* Save the original dispatch handlers before we override it */
72a2f5bd
HZ
606 rndis_filter.inner_drv.send = drv->send;
607 rndis_filter.inner_drv.recv_cb = drv->recv_cb;
608 rndis_filter.inner_drv.link_status_change =
609 drv->link_status_change;
fceaf24a 610
454f18a9 611 /* Override */
72a2f5bd 612 drv->send = rndis_filter_send;
72a2f5bd 613 drv->recv_cb = rndis_filter_receive;
fceaf24a 614
fceaf24a
HJ
615 return 0;
616}
617
9c26aa0d 618static int rndis_filter_init_device(struct rndis_device *dev)
fceaf24a 619{
e681b954 620 struct rndis_request *request;
9f33d054 621 struct rndis_initialize_request *init;
c2a4efdd 622 struct rndis_initialize_complete *init_complete;
4d643114 623 u32 status;
98d79690 624 int ret, t;
fceaf24a 625
9c26aa0d 626 request = get_rndis_request(dev, REMOTE_NDIS_INITIALIZE_MSG,
0120ee0d
GKH
627 RNDIS_MESSAGE_SIZE(struct rndis_initialize_request));
628 if (!request) {
fceaf24a
HJ
629 ret = -1;
630 goto Cleanup;
631 }
632
454f18a9 633 /* Setup the rndis set */
a388eb17
HZ
634 init = &request->request_msg.msg.init_req;
635 init->major_ver = RNDIS_MAJOR_VERSION;
636 init->minor_ver = RNDIS_MINOR_VERSION;
0120ee0d 637 /* FIXME: Use 1536 - rounded ethernet frame size */
a388eb17 638 init->max_xfer_size = 2048;
fceaf24a 639
c2a4efdd 640 dev->state = RNDIS_DEV_INITIALIZING;
fceaf24a 641
9c26aa0d 642 ret = rndis_filter_send_request(dev, request);
0120ee0d 643 if (ret != 0) {
c2a4efdd 644 dev->state = RNDIS_DEV_UNINITIALIZED;
fceaf24a
HJ
645 goto Cleanup;
646 }
647
0c3b7b2f 648
98d79690
S
649 t = wait_for_completion_timeout(&request->wait_event, HZ);
650
651 if (t == 0) {
0c3b7b2f
S
652 ret = -ETIMEDOUT;
653 goto Cleanup;
654 }
fceaf24a 655
a388eb17
HZ
656 init_complete = &request->response_msg.msg.init_complete;
657 status = init_complete->status;
0120ee0d 658 if (status == RNDIS_STATUS_SUCCESS) {
c2a4efdd 659 dev->state = RNDIS_DEV_INITIALIZED;
fceaf24a 660 ret = 0;
0120ee0d 661 } else {
c2a4efdd 662 dev->state = RNDIS_DEV_UNINITIALIZED;
fceaf24a
HJ
663 ret = -1;
664 }
665
666Cleanup:
667 if (request)
9c26aa0d 668 put_rndis_request(dev, request);
fceaf24a
HJ
669
670 return ret;
671}
672
9c26aa0d 673static void rndis_filter_halt_device(struct rndis_device *dev)
fceaf24a 674{
e681b954 675 struct rndis_request *request;
9f33d054 676 struct rndis_halt_request *halt;
fceaf24a 677
454f18a9 678 /* Attempt to do a rndis device halt */
9c26aa0d 679 request = get_rndis_request(dev, REMOTE_NDIS_HALT_MSG,
0120ee0d 680 RNDIS_MESSAGE_SIZE(struct rndis_halt_request));
fceaf24a 681 if (!request)
fceaf24a 682 goto Cleanup;
fceaf24a 683
454f18a9 684 /* Setup the rndis set */
a388eb17
HZ
685 halt = &request->request_msg.msg.halt_req;
686 halt->req_id = atomic_inc_return(&dev->new_req_id);
fceaf24a 687
454f18a9 688 /* Ignore return since this msg is optional. */
9c26aa0d 689 rndis_filter_send_request(dev, request);
fceaf24a 690
c2a4efdd 691 dev->state = RNDIS_DEV_UNINITIALIZED;
fceaf24a
HJ
692
693Cleanup:
694 if (request)
9c26aa0d 695 put_rndis_request(dev, request);
fceaf24a
HJ
696 return;
697}
698
9c26aa0d 699static int rndis_filter_open_device(struct rndis_device *dev)
fceaf24a 700{
0120ee0d 701 int ret;
fceaf24a 702
c2a4efdd 703 if (dev->state != RNDIS_DEV_INITIALIZED)
fceaf24a
HJ
704 return 0;
705
9c26aa0d 706 ret = rndis_filter_set_packet_filter(dev,
0120ee0d 707 NDIS_PACKET_TYPE_BROADCAST |
95beae90 708 NDIS_PACKET_TYPE_ALL_MULTICAST |
0120ee0d 709 NDIS_PACKET_TYPE_DIRECTED);
fceaf24a 710 if (ret == 0)
c2a4efdd 711 dev->state = RNDIS_DEV_DATAINITIALIZED;
fceaf24a 712
fceaf24a
HJ
713 return ret;
714}
715
9c26aa0d 716static int rndis_filter_close_device(struct rndis_device *dev)
fceaf24a
HJ
717{
718 int ret;
719
c2a4efdd 720 if (dev->state != RNDIS_DEV_DATAINITIALIZED)
fceaf24a
HJ
721 return 0;
722
9c26aa0d 723 ret = rndis_filter_set_packet_filter(dev, 0);
fceaf24a 724 if (ret == 0)
c2a4efdd 725 dev->state = RNDIS_DEV_INITIALIZED;
fceaf24a 726
fceaf24a
HJ
727 return ret;
728}
729
10f5a6db 730int rndis_filte_device_add(struct hv_device *dev,
c2a4efdd 731 void *additional_info)
fceaf24a
HJ
732{
733 int ret;
ce9ea4cf 734 struct netvsc_device *netDevice;
e681b954 735 struct rndis_device *rndisDevice;
c2a4efdd 736 struct netvsc_device_info *deviceInfo = additional_info;
fceaf24a 737
9c26aa0d 738 rndisDevice = get_rndis_device();
83c720ea 739 if (!rndisDevice)
fceaf24a 740 return -1;
fceaf24a 741
0120ee0d
GKH
742 /*
743 * Let the inner driver handle this first to create the netvsc channel
744 * NOTE! Once the channel is created, we may get a receive callback
745 * (RndisFilterOnReceive()) before this call is completed
746 */
ce5bf661 747 ret = netvsc_device_add(dev, additional_info);
0120ee0d
GKH
748 if (ret != 0) {
749 kfree(rndisDevice);
fceaf24a
HJ
750 return ret;
751 }
752
454f18a9
BP
753
754 /* Initialize the rndis device */
ca623ad3 755 netDevice = dev->ext;
fceaf24a 756
53d21fdb 757 netDevice->extension = rndisDevice;
c2a4efdd 758 rndisDevice->net_dev = netDevice;
fceaf24a 759
454f18a9 760 /* Send the rndis initialization message */
9c26aa0d 761 ret = rndis_filter_init_device(rndisDevice);
0120ee0d
GKH
762 if (ret != 0) {
763 /*
764 * TODO: If rndis init failed, we will need to shut down the
765 * channel
766 */
fceaf24a
HJ
767 }
768
454f18a9 769 /* Get the mac address */
9c26aa0d 770 ret = rndis_filter_query_device_mac(rndisDevice);
0120ee0d
GKH
771 if (ret != 0) {
772 /*
773 * TODO: shutdown rndis device and the channel
774 */
fceaf24a
HJ
775 }
776
72a2f5bd 777 memcpy(deviceInfo->mac_adr, rndisDevice->hw_mac_adr, ETH_ALEN);
fceaf24a 778
9c26aa0d 779 rndis_filter_query_device_link_status(rndisDevice);
fceaf24a 780
72a2f5bd 781 deviceInfo->link_state = rndisDevice->link_stat;
eb335bc4
HJ
782
783 dev_info(&dev->device, "Device MAC %pM link state %s",
784 rndisDevice->hw_mac_adr,
785 ((deviceInfo->link_state) ? ("down\n") : ("up\n")));
fceaf24a 786
fceaf24a
HJ
787 return ret;
788}
789
1405139c 790int rndis_filter_device_remove(struct hv_device *dev)
fceaf24a 791{
ca623ad3 792 struct netvsc_device *net_dev = dev->ext;
53d21fdb 793 struct rndis_device *rndis_dev = net_dev->extension;
fceaf24a 794
454f18a9 795 /* Halt and release the rndis device */
9c26aa0d 796 rndis_filter_halt_device(rndis_dev);
fceaf24a 797
c2a4efdd 798 kfree(rndis_dev);
53d21fdb 799 net_dev->extension = NULL;
fceaf24a 800
3fae5c8f 801 netvsc_device_remove(dev);
fceaf24a 802
fceaf24a
HJ
803 return 0;
804}
805
fceaf24a 806
9c26aa0d 807int rndis_filter_open(struct hv_device *dev)
fceaf24a 808{
ca623ad3 809 struct netvsc_device *netDevice = dev->ext;
fceaf24a 810
8a62d716
BP
811 if (!netDevice)
812 return -EINVAL;
813
53d21fdb 814 return rndis_filter_open_device(netDevice->extension);
fceaf24a
HJ
815}
816
9c26aa0d 817int rndis_filter_close(struct hv_device *dev)
fceaf24a 818{
ca623ad3 819 struct netvsc_device *netDevice = dev->ext;
fceaf24a 820
8a62d716
BP
821 if (!netDevice)
822 return -EINVAL;
823
53d21fdb 824 return rndis_filter_close_device(netDevice->extension);
fceaf24a
HJ
825}
826
9c26aa0d 827static int rndis_filter_send(struct hv_device *dev,
c2a4efdd 828 struct hv_netvsc_packet *pkt)
fceaf24a 829{
0120ee0d 830 int ret;
e681b954 831 struct rndis_filter_packet *filterPacket;
9f33d054
GKH
832 struct rndis_message *rndisMessage;
833 struct rndis_packet *rndisPacket;
4d643114 834 u32 rndisMessageSize;
fceaf24a 835
454f18a9 836 /* Add the rndis header */
72a2f5bd 837 filterPacket = (struct rndis_filter_packet *)pkt->extension;
fceaf24a 838
e681b954 839 memset(filterPacket, 0, sizeof(struct rndis_filter_packet));
fceaf24a 840
c2a4efdd 841 rndisMessage = &filterPacket->msg;
9f33d054 842 rndisMessageSize = RNDIS_MESSAGE_SIZE(struct rndis_packet);
fceaf24a 843
a388eb17
HZ
844 rndisMessage->ndis_msg_type = REMOTE_NDIS_PACKET_MSG;
845 rndisMessage->msg_len = pkt->total_data_buflen +
0120ee0d 846 rndisMessageSize;
fceaf24a 847
a388eb17
HZ
848 rndisPacket = &rndisMessage->msg.pkt;
849 rndisPacket->data_offset = sizeof(struct rndis_packet);
850 rndisPacket->data_len = pkt->total_data_buflen;
fceaf24a 851
72a2f5bd 852 pkt->is_data_pkt = true;
ca623ad3
HZ
853 pkt->page_buf[0].pfn = virt_to_phys(rndisMessage) >> PAGE_SHIFT;
854 pkt->page_buf[0].offset =
0120ee0d 855 (unsigned long)rndisMessage & (PAGE_SIZE-1);
ca623ad3 856 pkt->page_buf[0].len = rndisMessageSize;
fceaf24a 857
454f18a9 858 /* Save the packet send completion and context */
72a2f5bd 859 filterPacket->completion = pkt->completion.send.send_completion;
c2a4efdd 860 filterPacket->completion_ctx =
72a2f5bd 861 pkt->completion.send.send_completion_ctx;
fceaf24a 862
454f18a9 863 /* Use ours */
72a2f5bd
HZ
864 pkt->completion.send.send_completion = rndis_filter_send_completion;
865 pkt->completion.send.send_completion_ctx = filterPacket;
fceaf24a 866
72a2f5bd 867 ret = rndis_filter.inner_drv.send(dev, pkt);
0120ee0d
GKH
868 if (ret != 0) {
869 /*
870 * Reset the completion to originals to allow retries from
871 * above
872 */
72a2f5bd 873 pkt->completion.send.send_completion =
c2a4efdd 874 filterPacket->completion;
72a2f5bd 875 pkt->completion.send.send_completion_ctx =
c2a4efdd 876 filterPacket->completion_ctx;
fceaf24a
HJ
877 }
878
fceaf24a
HJ
879 return ret;
880}
881
9c26aa0d 882static void rndis_filter_send_completion(void *ctx)
fceaf24a 883{
c2a4efdd 884 struct rndis_filter_packet *filterPacket = ctx;
fceaf24a 885
454f18a9 886 /* Pass it back to the original handler */
c2a4efdd 887 filterPacket->completion(filterPacket->completion_ctx);
fceaf24a
HJ
888}
889
890
9c26aa0d 891static void rndis_filter_send_request_completion(void *ctx)
fceaf24a 892{
454f18a9 893 /* Noop */
fceaf24a 894}
This page took 0.261693 seconds and 5 git commands to generate.