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