rndis_filter.c 25.6 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
/*
 * Copyright (c) 2009, Microsoft Corporation.
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms and conditions of the GNU General Public License,
 * version 2, as published by the Free Software Foundation.
 *
 * This program is distributed in the hope it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
 * more details.
 *
 * You should have received a copy of the GNU General Public License along with
 * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
 * Place - Suite 330, Boston, MA 02111-1307 USA.
 *
 * Authors:
 *   Haiyang Zhang <haiyangz@microsoft.com>
 *   Hank Janssen  <hjanssen@microsoft.com>
 */
21
#include <linux/kernel.h>
22 23
#include <linux/sched.h>
#include <linux/wait.h>
24
#include <linux/highmem.h>
25
#include <linux/slab.h>
26
#include <linux/io.h>
27
#include <linux/if_ether.h>
28
#include <linux/netdevice.h>
29
#include <linux/if_vlan.h>
30
#include <linux/nls.h>
31

32
#include "hyperv_net.h"
33 34


35
#define RNDIS_EXT_LEN 100
36
struct rndis_request {
37
	struct list_head list_ent;
38
	struct completion  wait_event;
39

40
	struct rndis_message response_msg;
41
	/*
42 43 44 45
	 * The buffer for extended info after the RNDIS response message. It's
	 * referenced based on the data offset in the RNDIS message. Its size
	 * is enough for current needs, and should be sufficient for the near
	 * future.
46
	 */
47
	u8 response_ext[RNDIS_EXT_LEN];
48

49
	/* Simplify allocation by having a netvsc packet inline */
50
	struct hv_netvsc_packet	pkt;
51 52
	/* Set 2 pages for rndis requests crossing page boundary */
	struct hv_page_buffer buf[2];
53

54
	struct rndis_message request_msg;
55
	/*
56 57
	 * The buffer for the extended info after the RNDIS request message.
	 * It is referenced and sized in a similar way as response_ext.
58
	 */
59
	u8 request_ext[RNDIS_EXT_LEN];
60
};
61

62
static void rndis_filter_send_completion(void *ctx);
63

64
static void rndis_filter_send_request_completion(void *ctx);
65 66


67

68
static struct rndis_device *get_rndis_device(void)
69
{
70
	struct rndis_device *device;
71

72
	device = kzalloc(sizeof(struct rndis_device), GFP_KERNEL);
73 74 75
	if (!device)
		return NULL;

76
	spin_lock_init(&device->request_lock);
77

78
	INIT_LIST_HEAD(&device->req_list);
79

80
	device->state = RNDIS_DEV_UNINITIALIZED;
81 82 83 84

	return device;
}

85
static struct rndis_request *get_rndis_request(struct rndis_device *dev,
86 87
					     u32 msg_type,
					     u32 msg_len)
88
{
89
	struct rndis_request *request;
90
	struct rndis_message *rndis_msg;
91
	struct rndis_set_request *set;
92
	unsigned long flags;
93

94
	request = kzalloc(sizeof(struct rndis_request), GFP_KERNEL);
95 96 97
	if (!request)
		return NULL;

98
	init_completion(&request->wait_event);
99

100
	rndis_msg = &request->request_msg;
101 102
	rndis_msg->ndis_msg_type = msg_type;
	rndis_msg->msg_len = msg_len;
103

104 105 106 107 108
	/*
	 * Set the request id. This field is always after the rndis header for
	 * request/response packet types so we just used the SetRequest as a
	 * template
	 */
109 110
	set = &rndis_msg->msg.set_req;
	set->req_id = atomic_inc_return(&dev->new_req_id);
111

112
	/* Add to the request list */
113 114 115
	spin_lock_irqsave(&dev->request_lock, flags);
	list_add_tail(&request->list_ent, &dev->req_list);
	spin_unlock_irqrestore(&dev->request_lock, flags);
116 117 118 119

	return request;
}

120
static void put_rndis_request(struct rndis_device *dev,
121
			    struct rndis_request *req)
122
{
123 124
	unsigned long flags;

125 126 127
	spin_lock_irqsave(&dev->request_lock, flags);
	list_del(&req->list_ent);
	spin_unlock_irqrestore(&dev->request_lock, flags);
128

129
	kfree(req);
130 131
}

132 133
static void dump_rndis_message(struct hv_device *hv_dev,
			struct rndis_message *rndis_msg)
134
{
135 136 137 138 139
	struct net_device *netdev;
	struct netvsc_device *net_device;

	net_device = hv_get_drvdata(hv_dev);
	netdev = net_device->ndev;
140

141
	switch (rndis_msg->ndis_msg_type) {
142 143
	case RNDIS_MSG_PACKET:
		netdev_dbg(netdev, "RNDIS_MSG_PACKET (len %u, "
144 145
			   "data offset %u data len %u, # oob %u, "
			   "oob offset %u, oob len %u, pkt offset %u, "
146
			   "pkt len %u\n",
147 148 149 150 151 152 153 154
			   rndis_msg->msg_len,
			   rndis_msg->msg.pkt.data_offset,
			   rndis_msg->msg.pkt.data_len,
			   rndis_msg->msg.pkt.num_oob_data_elements,
			   rndis_msg->msg.pkt.oob_data_offset,
			   rndis_msg->msg.pkt.oob_data_len,
			   rndis_msg->msg.pkt.per_pkt_info_offset,
			   rndis_msg->msg.pkt.per_pkt_info_len);
155 156
		break;

157 158
	case RNDIS_MSG_INIT_C:
		netdev_dbg(netdev, "RNDIS_MSG_INIT_C "
159 160
			"(len %u, id 0x%x, status 0x%x, major %d, minor %d, "
			"device flags %d, max xfer size 0x%x, max pkts %u, "
161
			"pkt aligned %u)\n",
162 163 164 165 166 167 168 169 170 171 172
			rndis_msg->msg_len,
			rndis_msg->msg.init_complete.req_id,
			rndis_msg->msg.init_complete.status,
			rndis_msg->msg.init_complete.major_ver,
			rndis_msg->msg.init_complete.minor_ver,
			rndis_msg->msg.init_complete.dev_flags,
			rndis_msg->msg.init_complete.max_xfer_size,
			rndis_msg->msg.init_complete.
			   max_pkt_per_msg,
			rndis_msg->msg.init_complete.
			   pkt_alignment_factor);
173 174
		break;

175 176
	case RNDIS_MSG_QUERY_C:
		netdev_dbg(netdev, "RNDIS_MSG_QUERY_C "
177
			"(len %u, id 0x%x, status 0x%x, buf len %u, "
178
			"buf offset %u)\n",
179 180 181 182 183 184 185
			rndis_msg->msg_len,
			rndis_msg->msg.query_complete.req_id,
			rndis_msg->msg.query_complete.status,
			rndis_msg->msg.query_complete.
			   info_buflen,
			rndis_msg->msg.query_complete.
			   info_buf_offset);
186 187
		break;

188
	case RNDIS_MSG_SET_C:
189
		netdev_dbg(netdev,
190
			"RNDIS_MSG_SET_C (len %u, id 0x%x, status 0x%x)\n",
191 192 193
			rndis_msg->msg_len,
			rndis_msg->msg.set_complete.req_id,
			rndis_msg->msg.set_complete.status);
194 195
		break;

196 197
	case RNDIS_MSG_INDICATE:
		netdev_dbg(netdev, "RNDIS_MSG_INDICATE "
198
			"(len %u, status 0x%x, buf len %u, buf offset %u)\n",
199 200 201 202
			rndis_msg->msg_len,
			rndis_msg->msg.indicate_status.status,
			rndis_msg->msg.indicate_status.status_buflen,
			rndis_msg->msg.indicate_status.status_buf_offset);
203 204 205
		break;

	default:
206
		netdev_dbg(netdev, "0x%x (len %u)\n",
207 208
			rndis_msg->ndis_msg_type,
			rndis_msg->msg_len);
209 210 211 212
		break;
	}
}

213
static int rndis_filter_send_request(struct rndis_device *dev,
214
				  struct rndis_request *req)
215
{
216
	int ret;
217
	struct hv_netvsc_packet *packet;
218

219
	/* Setup the packet to send it */
220
	packet = &req->pkt;
221

222
	packet->is_data_pkt = false;
223
	packet->total_data_buflen = req->request_msg.msg_len;
224
	packet->page_buf_cnt = 1;
225

226
	packet->page_buf[0].pfn = virt_to_phys(&req->request_msg) >>
227
					PAGE_SHIFT;
228 229
	packet->page_buf[0].len = req->request_msg.msg_len;
	packet->page_buf[0].offset =
230
		(unsigned long)&req->request_msg & (PAGE_SIZE - 1);
231

232 233 234 235 236 237 238 239 240 241 242 243
	/* Add one page_buf when request_msg crossing page boundary */
	if (packet->page_buf[0].offset + packet->page_buf[0].len > PAGE_SIZE) {
		packet->page_buf_cnt++;
		packet->page_buf[0].len = PAGE_SIZE -
			packet->page_buf[0].offset;
		packet->page_buf[1].pfn = virt_to_phys((void *)&req->request_msg
			+ packet->page_buf[0].len) >> PAGE_SHIFT;
		packet->page_buf[1].offset = 0;
		packet->page_buf[1].len = req->request_msg.msg_len -
			packet->page_buf[0].len;
	}

244 245
	packet->completion.send.send_completion_ctx = req;/* packet; */
	packet->completion.send.send_completion =
246
		rndis_filter_send_request_completion;
247
	packet->completion.send.send_completion_tid = (unsigned long)dev;
248

249
	ret = netvsc_send(dev->net_dev->dev, packet);
250 251 252
	return ret;
}

253
static void rndis_filter_receive_response(struct rndis_device *dev,
254
				       struct rndis_message *resp)
255
{
256
	struct rndis_request *request = NULL;
257
	bool found = false;
258
	unsigned long flags;
259 260 261
	struct net_device *ndev;

	ndev = dev->net_dev->ndev;
262

263 264
	spin_lock_irqsave(&dev->request_lock, flags);
	list_for_each_entry(request, &dev->req_list, list_ent) {
265 266 267 268
		/*
		 * All request/response message contains RequestId as the 1st
		 * field
		 */
269 270
		if (request->request_msg.msg.init_req.req_id
		    == resp->msg.init_complete.req_id) {
271
			found = true;
272 273 274
			break;
		}
	}
275
	spin_unlock_irqrestore(&dev->request_lock, flags);
276

277
	if (found) {
278 279
		if (resp->msg_len <=
		    sizeof(struct rndis_message) + RNDIS_EXT_LEN) {
280
			memcpy(&request->response_msg, resp,
281
			       resp->msg_len);
282
		} else {
283
			netdev_err(ndev,
284 285 286 287
				"rndis response buffer overflow "
				"detected (size %u max %zu)\n",
				resp->msg_len,
				sizeof(struct rndis_filter_packet));
288

289
			if (resp->ndis_msg_type ==
290
			    RNDIS_MSG_RESET_C) {
291
				/* does not have a request id field */
292
				request->response_msg.msg.reset_complete.
293
					status = RNDIS_STATUS_BUFFER_OVERFLOW;
294
			} else {
295 296
				request->response_msg.msg.
				init_complete.status =
297
					RNDIS_STATUS_BUFFER_OVERFLOW;
298 299 300
			}
		}

301
		complete(&request->wait_event);
302
	} else {
303
		netdev_err(ndev,
304 305 306 307
			"no rndis request found for this response "
			"(id 0x%x res type 0x%x)\n",
			resp->msg.init_complete.req_id,
			resp->ndis_msg_type);
308 309 310
	}
}

311
static void rndis_filter_receive_indicate_status(struct rndis_device *dev,
312
					     struct rndis_message *resp)
313
{
314
	struct rndis_indicate_status *indicate =
315
			&resp->msg.indicate_status;
316

317
	if (indicate->status == RNDIS_STATUS_MEDIA_CONNECT) {
318
		netvsc_linkstatus_callback(
319
			dev->net_dev->dev, 1);
320
	} else if (indicate->status == RNDIS_STATUS_MEDIA_DISCONNECT) {
321
		netvsc_linkstatus_callback(
322
			dev->net_dev->dev, 0);
323 324 325 326
	} else {
		/*
		 * TODO:
		 */
327 328 329
	}
}

330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355
/*
 * Get the Per-Packet-Info with the specified type
 * return NULL if not found.
 */
static inline void *rndis_get_ppi(struct rndis_packet *rpkt, u32 type)
{
	struct rndis_per_packet_info *ppi;
	int len;

	if (rpkt->per_pkt_info_offset == 0)
		return NULL;

	ppi = (struct rndis_per_packet_info *)((ulong)rpkt +
		rpkt->per_pkt_info_offset);
	len = rpkt->per_pkt_info_len;

	while (len > 0) {
		if (ppi->type == type)
			return (void *)((ulong)ppi + ppi->ppi_offset);
		len -= ppi->size;
		ppi = (struct rndis_per_packet_info *)((ulong)ppi + ppi->size);
	}

	return NULL;
}

356
static void rndis_filter_receive_data(struct rndis_device *dev,
357 358
				   struct rndis_message *msg,
				   struct hv_netvsc_packet *pkt)
359
{
360 361
	struct rndis_packet *rndis_pkt;
	u32 data_offset;
362
	struct ndis_pkt_8021q_info *vlan;
363

364
	rndis_pkt = &msg->msg.pkt;
365

366
	/* Remove the rndis header and pass it back up the stack */
367
	data_offset = RNDIS_HEADER_SIZE + rndis_pkt->data_offset;
368

369
	pkt->total_data_buflen -= data_offset;
370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388

	/*
	 * Make sure we got a valid RNDIS message, now total_data_buflen
	 * should be the data packet size plus the trailer padding size
	 */
	if (pkt->total_data_buflen < rndis_pkt->data_len) {
		netdev_err(dev->net_dev->ndev, "rndis message buffer "
			   "overflow detected (got %u, min %u)"
			   "...dropping this message!\n",
			   pkt->total_data_buflen, rndis_pkt->data_len);
		return;
	}

	/*
	 * Remove the rndis trailer padding from rndis packet message
	 * rndis_pkt->data_len tell us the real data length, we only copy
	 * the data packet to the stack, without the rndis trailer padding
	 */
	pkt->total_data_buflen = rndis_pkt->data_len;
389
	pkt->data = (void *)((unsigned long)pkt->data + data_offset);
390

391
	pkt->is_data_pkt = true;
392

393 394 395 396 397 398 399 400
	vlan = rndis_get_ppi(rndis_pkt, IEEE_8021Q_INFO);
	if (vlan) {
		pkt->vlan_tci = VLAN_TAG_PRESENT | vlan->vlanid |
			(vlan->pri << VLAN_PRIO_SHIFT);
	} else {
		pkt->vlan_tci = 0;
	}

401
	netvsc_recv_callback(dev->net_dev->dev, pkt);
402 403
}

404
int rndis_filter_receive(struct hv_device *dev,
405
				struct hv_netvsc_packet	*pkt)
406
{
407
	struct netvsc_device *net_dev = hv_get_drvdata(dev);
408
	struct rndis_device *rndis_dev;
409
	struct rndis_message *rndis_msg;
410
	struct net_device *ndev;
411
	int ret = 0;
412

413 414 415 416
	if (!net_dev) {
		ret = -EINVAL;
		goto exit;
	}
417

418 419
	ndev = net_dev->ndev;

420
	/* Make sure the rndis device state is initialized */
421
	if (!net_dev->extension) {
422
		netdev_err(ndev, "got rndis message but no rndis device - "
423
			  "dropping this message!\n");
424 425
		ret = -ENODEV;
		goto exit;
426 427
	}

428
	rndis_dev = (struct rndis_device *)net_dev->extension;
429
	if (rndis_dev->state == RNDIS_DEV_UNINITIALIZED) {
430
		netdev_err(ndev, "got rndis message but rndis device "
431
			   "uninitialized...dropping this message!\n");
432 433
		ret = -ENODEV;
		goto exit;
434 435
	}

436
	rndis_msg = pkt->data;
437

438
	dump_rndis_message(dev, rndis_msg);
439

440
	switch (rndis_msg->ndis_msg_type) {
441
	case RNDIS_MSG_PACKET:
442
		/* data msg */
443
		rndis_filter_receive_data(rndis_dev, rndis_msg, pkt);
444 445
		break;

446 447 448
	case RNDIS_MSG_INIT_C:
	case RNDIS_MSG_QUERY_C:
	case RNDIS_MSG_SET_C:
449
		/* completion msgs */
450
		rndis_filter_receive_response(rndis_dev, rndis_msg);
451 452
		break;

453
	case RNDIS_MSG_INDICATE:
454
		/* notification msgs */
455
		rndis_filter_receive_indicate_status(rndis_dev, rndis_msg);
456 457
		break;
	default:
458
		netdev_err(ndev,
459
			"unhandled rndis message (type %u len %u)\n",
460 461
			   rndis_msg->ndis_msg_type,
			   rndis_msg->msg_len);
462 463 464
		break;
	}

465 466 467 468 469
exit:
	if (ret != 0)
		pkt->status = NVSP_STAT_FAIL;

	return ret;
470 471
}

472
static int rndis_filter_query_device(struct rndis_device *dev, u32 oid,
473
				  void *result, u32 *result_size)
474
{
475
	struct rndis_request *request;
476
	u32 inresult_size = *result_size;
477
	struct rndis_query_request *query;
478
	struct rndis_query_complete *query_complete;
479
	int ret = 0;
480
	int t;
481

482
	if (!result)
483
		return -EINVAL;
484

485
	*result_size = 0;
486
	request = get_rndis_request(dev, RNDIS_MSG_QUERY,
487 488
			RNDIS_MESSAGE_SIZE(struct rndis_query_request));
	if (!request) {
489
		ret = -ENOMEM;
490
		goto cleanup;
491 492
	}

493
	/* Setup the rndis query */
494 495 496 497 498
	query = &request->request_msg.msg.query_req;
	query->oid = oid;
	query->info_buf_offset = sizeof(struct rndis_query_request);
	query->info_buflen = 0;
	query->dev_vc_handle = 0;
499

500
	ret = rndis_filter_send_request(dev, request);
501
	if (ret != 0)
502
		goto cleanup;
503

504
	t = wait_for_completion_timeout(&request->wait_event, 5*HZ);
505
	if (t == 0) {
506
		ret = -ETIMEDOUT;
507
		goto cleanup;
508
	}
509

510
	/* Copy the response back */
511
	query_complete = &request->response_msg.msg.query_complete;
512

513
	if (query_complete->info_buflen > inresult_size) {
514
		ret = -1;
515
		goto cleanup;
516 517
	}

518 519
	memcpy(result,
	       (void *)((unsigned long)query_complete +
520 521
			 query_complete->info_buf_offset),
	       query_complete->info_buflen);
522

523
	*result_size = query_complete->info_buflen;
524

525
cleanup:
526
	if (request)
527
		put_rndis_request(dev, request);
528 529 530 531

	return ret;
}

532
static int rndis_filter_query_device_mac(struct rndis_device *dev)
533
{
534
	u32 size = ETH_ALEN;
535

536
	return rndis_filter_query_device(dev,
537
				      RNDIS_OID_802_3_PERMANENT_ADDRESS,
538
				      dev->hw_mac_adr, &size);
539 540
}

541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607
#define NWADR_STR "NetworkAddress"
#define NWADR_STRLEN 14

int rndis_filter_set_device_mac(struct hv_device *hdev, char *mac)
{
	struct netvsc_device *nvdev = hv_get_drvdata(hdev);
	struct rndis_device *rdev = nvdev->extension;
	struct net_device *ndev = nvdev->ndev;
	struct rndis_request *request;
	struct rndis_set_request *set;
	struct rndis_config_parameter_info *cpi;
	wchar_t *cfg_nwadr, *cfg_mac;
	struct rndis_set_complete *set_complete;
	char macstr[2*ETH_ALEN+1];
	u32 extlen = sizeof(struct rndis_config_parameter_info) +
		2*NWADR_STRLEN + 4*ETH_ALEN;
	int ret, t;

	request = get_rndis_request(rdev, RNDIS_MSG_SET,
		RNDIS_MESSAGE_SIZE(struct rndis_set_request) + extlen);
	if (!request)
		return -ENOMEM;

	set = &request->request_msg.msg.set_req;
	set->oid = RNDIS_OID_GEN_RNDIS_CONFIG_PARAMETER;
	set->info_buflen = extlen;
	set->info_buf_offset = sizeof(struct rndis_set_request);
	set->dev_vc_handle = 0;

	cpi = (struct rndis_config_parameter_info *)((ulong)set +
		set->info_buf_offset);
	cpi->parameter_name_offset =
		sizeof(struct rndis_config_parameter_info);
	/* Multiply by 2 because host needs 2 bytes (utf16) for each char */
	cpi->parameter_name_length = 2*NWADR_STRLEN;
	cpi->parameter_type = RNDIS_CONFIG_PARAM_TYPE_STRING;
	cpi->parameter_value_offset =
		cpi->parameter_name_offset + cpi->parameter_name_length;
	/* Multiply by 4 because each MAC byte displayed as 2 utf16 chars */
	cpi->parameter_value_length = 4*ETH_ALEN;

	cfg_nwadr = (wchar_t *)((ulong)cpi + cpi->parameter_name_offset);
	cfg_mac = (wchar_t *)((ulong)cpi + cpi->parameter_value_offset);
	ret = utf8s_to_utf16s(NWADR_STR, NWADR_STRLEN, UTF16_HOST_ENDIAN,
			      cfg_nwadr, NWADR_STRLEN);
	if (ret < 0)
		goto cleanup;
	snprintf(macstr, 2*ETH_ALEN+1, "%pm", mac);
	ret = utf8s_to_utf16s(macstr, 2*ETH_ALEN, UTF16_HOST_ENDIAN,
			      cfg_mac, 2*ETH_ALEN);
	if (ret < 0)
		goto cleanup;

	ret = rndis_filter_send_request(rdev, request);
	if (ret != 0)
		goto cleanup;

	t = wait_for_completion_timeout(&request->wait_event, 5*HZ);
	if (t == 0) {
		netdev_err(ndev, "timeout before we got a set response...\n");
		/*
		 * can't put_rndis_request, since we may still receive a
		 * send-completion.
		 */
		return -EBUSY;
	} else {
		set_complete = &request->response_msg.msg.set_complete;
608 609 610
		if (set_complete->status != RNDIS_STATUS_SUCCESS) {
			netdev_err(ndev, "Fail to set MAC on host side:0x%x\n",
				   set_complete->status);
611
			ret = -EINVAL;
612
		}
613 614 615 616 617 618 619 620
	}

cleanup:
	put_rndis_request(rdev, request);
	return ret;
}


621
static int rndis_filter_query_device_link_status(struct rndis_device *dev)
622
{
623
	u32 size = sizeof(u32);
624 625
	u32 link_status;
	int ret;
626

627
	ret = rndis_filter_query_device(dev,
628
				      RNDIS_OID_GEN_MEDIA_CONNECT_STATUS,
629 630 631 632
				      &link_status, &size);
	dev->link_state = (link_status != 0) ? true : false;

	return ret;
633 634
}

635
int rndis_filter_set_packet_filter(struct rndis_device *dev, u32 new_filter)
636
{
637
	struct rndis_request *request;
638
	struct rndis_set_request *set;
639
	struct rndis_set_complete *set_complete;
640
	u32 status;
641
	int ret, t;
642 643 644
	struct net_device *ndev;

	ndev = dev->net_dev->ndev;
645

646
	request = get_rndis_request(dev, RNDIS_MSG_SET,
647 648 649
			RNDIS_MESSAGE_SIZE(struct rndis_set_request) +
			sizeof(u32));
	if (!request) {
650
		ret = -ENOMEM;
651
		goto cleanup;
652 653
	}

654
	/* Setup the rndis set */
655 656 657 658
	set = &request->request_msg.msg.set_req;
	set->oid = RNDIS_OID_GEN_CURRENT_PACKET_FILTER;
	set->info_buflen = sizeof(u32);
	set->info_buf_offset = sizeof(struct rndis_set_request);
659

660
	memcpy((void *)(unsigned long)set + sizeof(struct rndis_set_request),
661
	       &new_filter, sizeof(u32));
662

663
	ret = rndis_filter_send_request(dev, request);
664
	if (ret != 0)
665
		goto cleanup;
666

667
	t = wait_for_completion_timeout(&request->wait_event, 5*HZ);
668 669

	if (t == 0) {
670
		netdev_err(ndev,
671
			"timeout before we got a set response...\n");
672
		ret = -ETIMEDOUT;
673
		/*
Lucas De Marchi's avatar
Lucas De Marchi committed
674
		 * We can't deallocate the request since we may still receive a
675 676
		 * send completion for it.
		 */
677
		goto exit;
678
	} else {
679 680
		set_complete = &request->response_msg.msg.set_complete;
		status = set_complete->status;
681 682
	}

683
cleanup:
684
	if (request)
685
		put_rndis_request(dev, request);
686
exit:
687 688 689 690
	return ret;
}


691
static int rndis_filter_init_device(struct rndis_device *dev)
692
{
693
	struct rndis_request *request;
694
	struct rndis_initialize_request *init;
695
	struct rndis_initialize_complete *init_complete;
696
	u32 status;
697
	int ret, t;
698

699
	request = get_rndis_request(dev, RNDIS_MSG_INIT,
700 701
			RNDIS_MESSAGE_SIZE(struct rndis_initialize_request));
	if (!request) {
702
		ret = -ENOMEM;
703
		goto cleanup;
704 705
	}

706
	/* Setup the rndis set */
707 708 709
	init = &request->request_msg.msg.init_req;
	init->major_ver = RNDIS_MAJOR_VERSION;
	init->minor_ver = RNDIS_MINOR_VERSION;
710
	init->max_xfer_size = 0x4000;
711

712
	dev->state = RNDIS_DEV_INITIALIZING;
713

714
	ret = rndis_filter_send_request(dev, request);
715
	if (ret != 0) {
716
		dev->state = RNDIS_DEV_UNINITIALIZED;
717
		goto cleanup;
718 719
	}

720

721
	t = wait_for_completion_timeout(&request->wait_event, 5*HZ);
722 723

	if (t == 0) {
724
		ret = -ETIMEDOUT;
725
		goto cleanup;
726
	}
727

728 729
	init_complete = &request->response_msg.msg.init_complete;
	status = init_complete->status;
730
	if (status == RNDIS_STATUS_SUCCESS) {
731
		dev->state = RNDIS_DEV_INITIALIZED;
732
		ret = 0;
733
	} else {
734
		dev->state = RNDIS_DEV_UNINITIALIZED;
735
		ret = -EINVAL;
736 737
	}

738
cleanup:
739
	if (request)
740
		put_rndis_request(dev, request);
741 742 743 744

	return ret;
}

745
static void rndis_filter_halt_device(struct rndis_device *dev)
746
{
Greg Kroah-Hartman's avatar