rndis_wlan.c 97.5 KB
Newer Older
1
2
3
4
/*
 * Driver for RNDIS based wireless USB devices.
 *
 * Copyright (C) 2007 by Bjorge Dijkstra <bjd@jooz.net>
5
 * Copyright (C) 2008-2009 by Jussi Kivilinna <jussi.kivilinna@mbnet.fi>
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that 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
 *
 *  Portions of this file are based on NDISwrapper project,
 *  Copyright (C) 2003-2005 Pontus Fuchs, Giridhar Pemmasani
 *  http://ndiswrapper.sourceforge.net/
 */

// #define	DEBUG			// error path messages, extra info
// #define	VERBOSE			// more; success messages

#include <linux/module.h>
#include <linux/init.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/ethtool.h>
#include <linux/workqueue.h>
#include <linux/mutex.h>
#include <linux/mii.h>
#include <linux/usb.h>
#include <linux/usb/cdc.h>
#include <linux/wireless.h>
Johannes Berg's avatar
Johannes Berg committed
40
#include <linux/ieee80211.h>
41
42
43
#include <linux/if_arp.h>
#include <linux/ctype.h>
#include <linux/spinlock.h>
44
#include <linux/slab.h>
45
#include <net/iw_handler.h>
46
#include <net/cfg80211.h>
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
#include <linux/usb/usbnet.h>
#include <linux/usb/rndis_host.h>


/* NOTE: All these are settings for Broadcom chipset */
static char modparam_country[4] = "EU";
module_param_string(country, modparam_country, 4, 0444);
MODULE_PARM_DESC(country, "Country code (ISO 3166-1 alpha-2), default: EU");

static int modparam_frameburst = 1;
module_param_named(frameburst, modparam_frameburst, int, 0444);
MODULE_PARM_DESC(frameburst, "enable frame bursting (default: on)");

static int modparam_afterburner = 0;
module_param_named(afterburner, modparam_afterburner, int, 0444);
MODULE_PARM_DESC(afterburner,
	"enable afterburner aka '125 High Speed Mode' (default: off)");

static int modparam_power_save = 0;
module_param_named(power_save, modparam_power_save, int, 0444);
MODULE_PARM_DESC(power_save,
	"set power save mode: 0=off, 1=on, 2=fast (default: off)");

static int modparam_power_output = 3;
module_param_named(power_output, modparam_power_output, int, 0444);
MODULE_PARM_DESC(power_output,
	"set power output: 0=25%, 1=50%, 2=75%, 3=100% (default: 100%)");

static int modparam_roamtrigger = -70;
module_param_named(roamtrigger, modparam_roamtrigger, int, 0444);
MODULE_PARM_DESC(roamtrigger,
	"set roaming dBm trigger: -80=optimize for distance, "
				"-60=bandwidth (default: -70)");

static int modparam_roamdelta = 1;
module_param_named(roamdelta, modparam_roamdelta, int, 0444);
MODULE_PARM_DESC(roamdelta,
	"set roaming tendency: 0=aggressive, 1=moderate, "
				"2=conservative (default: moderate)");

87
static int modparam_workaround_interval;
88
89
90
module_param_named(workaround_interval, modparam_workaround_interval,
							int, 0444);
MODULE_PARM_DESC(workaround_interval,
91
	"set stall workaround interval in msecs (0=disabled) (default: 0)");
92
93
94


/* various RNDIS OID defs */
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
#define OID_GEN_LINK_SPEED			cpu_to_le32(0x00010107)
#define OID_GEN_RNDIS_CONFIG_PARAMETER		cpu_to_le32(0x0001021b)

#define OID_GEN_XMIT_OK				cpu_to_le32(0x00020101)
#define OID_GEN_RCV_OK				cpu_to_le32(0x00020102)
#define OID_GEN_XMIT_ERROR			cpu_to_le32(0x00020103)
#define OID_GEN_RCV_ERROR			cpu_to_le32(0x00020104)
#define OID_GEN_RCV_NO_BUFFER			cpu_to_le32(0x00020105)

#define OID_802_3_CURRENT_ADDRESS		cpu_to_le32(0x01010102)
#define OID_802_3_MULTICAST_LIST		cpu_to_le32(0x01010103)
#define OID_802_3_MAXIMUM_LIST_SIZE		cpu_to_le32(0x01010104)

#define OID_802_11_BSSID			cpu_to_le32(0x0d010101)
#define OID_802_11_SSID				cpu_to_le32(0x0d010102)
#define OID_802_11_INFRASTRUCTURE_MODE		cpu_to_le32(0x0d010108)
#define OID_802_11_ADD_WEP			cpu_to_le32(0x0d010113)
#define OID_802_11_REMOVE_WEP			cpu_to_le32(0x0d010114)
#define OID_802_11_DISASSOCIATE			cpu_to_le32(0x0d010115)
#define OID_802_11_AUTHENTICATION_MODE		cpu_to_le32(0x0d010118)
#define OID_802_11_PRIVACY_FILTER		cpu_to_le32(0x0d010119)
#define OID_802_11_BSSID_LIST_SCAN		cpu_to_le32(0x0d01011a)
#define OID_802_11_ENCRYPTION_STATUS		cpu_to_le32(0x0d01011b)
#define OID_802_11_ADD_KEY			cpu_to_le32(0x0d01011d)
#define OID_802_11_REMOVE_KEY			cpu_to_le32(0x0d01011e)
#define OID_802_11_ASSOCIATION_INFORMATION	cpu_to_le32(0x0d01011f)
121
#define OID_802_11_CAPABILITY			cpu_to_le32(0x0d010122)
122
123
124
125
126
127
128
129
130
131
132
#define OID_802_11_PMKID			cpu_to_le32(0x0d010123)
#define OID_802_11_NETWORK_TYPES_SUPPORTED	cpu_to_le32(0x0d010203)
#define OID_802_11_NETWORK_TYPE_IN_USE		cpu_to_le32(0x0d010204)
#define OID_802_11_TX_POWER_LEVEL		cpu_to_le32(0x0d010205)
#define OID_802_11_RSSI				cpu_to_le32(0x0d010206)
#define OID_802_11_RSSI_TRIGGER			cpu_to_le32(0x0d010207)
#define OID_802_11_FRAGMENTATION_THRESHOLD	cpu_to_le32(0x0d010209)
#define OID_802_11_RTS_THRESHOLD		cpu_to_le32(0x0d01020a)
#define OID_802_11_SUPPORTED_RATES		cpu_to_le32(0x0d01020e)
#define OID_802_11_CONFIGURATION		cpu_to_le32(0x0d010211)
#define OID_802_11_BSSID_LIST			cpu_to_le32(0x0d010217)
133
134
135
136
137
138
139
140
141
142


/* Typical noise/maximum signal level values taken from ndiswrapper iw_ndis.h */
#define	WL_NOISE	-96	/* typical noise level in dBm */
#define	WL_SIGMAX	-32	/* typical maximum signal level in dBm */


/* Assume that Broadcom 4320 (only chipset at time of writing known to be
 * based on wireless rndis) has default txpower of 13dBm.
 * This value is from Linksys WUSB54GSC User Guide, Appendix F: Specifications.
143
144
145
146
 *  100% : 20 mW ~ 13dBm
 *   75% : 15 mW ~ 12dBm
 *   50% : 10 mW ~ 10dBm
 *   25% :  5 mW ~  7dBm
147
 */
148
149
150
151
#define BCM4320_DEFAULT_TXPOWER_DBM_100 13
#define BCM4320_DEFAULT_TXPOWER_DBM_75  12
#define BCM4320_DEFAULT_TXPOWER_DBM_50  10
#define BCM4320_DEFAULT_TXPOWER_DBM_25  7
152
153
154


/* codes for "status" field of completion messages */
155
156
#define RNDIS_STATUS_ADAPTER_NOT_READY		cpu_to_le32(0xc0010011)
#define RNDIS_STATUS_ADAPTER_NOT_OPEN		cpu_to_le32(0xc0010012)
157
158


159
160
161
162
163
164
/* Known device types */
#define RNDIS_UNKNOWN	0
#define RNDIS_BCM4320A	1
#define RNDIS_BCM4320B	2


165
166
167
168
169
170
171
/* NDIS data structures. Taken from wpa_supplicant driver_ndis.c
 * slightly modified for datatype endianess, etc
 */
#define NDIS_802_11_LENGTH_SSID 32
#define NDIS_802_11_LENGTH_RATES 8
#define NDIS_802_11_LENGTH_RATES_EX 16

172
enum ndis_80211_net_type {
173
174
175
176
	NDIS_80211_TYPE_FREQ_HOP,
	NDIS_80211_TYPE_DIRECT_SEQ,
	NDIS_80211_TYPE_OFDM_A,
	NDIS_80211_TYPE_OFDM_G
177
178
179
};

enum ndis_80211_net_infra {
180
181
182
	NDIS_80211_INFRA_ADHOC,
	NDIS_80211_INFRA_INFRA,
	NDIS_80211_INFRA_AUTO_UNKNOWN
183
184
185
};

enum ndis_80211_auth_mode {
186
187
188
189
190
191
192
193
	NDIS_80211_AUTH_OPEN,
	NDIS_80211_AUTH_SHARED,
	NDIS_80211_AUTH_AUTO_SWITCH,
	NDIS_80211_AUTH_WPA,
	NDIS_80211_AUTH_WPA_PSK,
	NDIS_80211_AUTH_WPA_NONE,
	NDIS_80211_AUTH_WPA2,
	NDIS_80211_AUTH_WPA2_PSK
194
195
196
};

enum ndis_80211_encr_status {
197
198
199
200
201
202
203
204
	NDIS_80211_ENCR_WEP_ENABLED,
	NDIS_80211_ENCR_DISABLED,
	NDIS_80211_ENCR_WEP_KEY_ABSENT,
	NDIS_80211_ENCR_NOT_SUPPORTED,
	NDIS_80211_ENCR_TKIP_ENABLED,
	NDIS_80211_ENCR_TKIP_KEY_ABSENT,
	NDIS_80211_ENCR_CCMP_ENABLED,
	NDIS_80211_ENCR_CCMP_KEY_ABSENT
205
206
207
};

enum ndis_80211_priv_filter {
208
209
	NDIS_80211_PRIV_ACCEPT_ALL,
	NDIS_80211_PRIV_8021X_WEP
210
211
};

212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
enum ndis_80211_status_type {
	NDIS_80211_STATUSTYPE_AUTHENTICATION,
	NDIS_80211_STATUSTYPE_MEDIASTREAMMODE,
	NDIS_80211_STATUSTYPE_PMKID_CANDIDATELIST,
	NDIS_80211_STATUSTYPE_RADIOSTATE,
};

enum ndis_80211_media_stream_mode {
	NDIS_80211_MEDIA_STREAM_OFF,
	NDIS_80211_MEDIA_STREAM_ON
};

enum ndis_80211_radio_status {
	NDIS_80211_RADIO_STATUS_ON,
	NDIS_80211_RADIO_STATUS_HARDWARE_OFF,
	NDIS_80211_RADIO_STATUS_SOFTWARE_OFF,
};

230
enum ndis_80211_addkey_bits {
231
232
233
234
	NDIS_80211_ADDKEY_8021X_AUTH = cpu_to_le32(1 << 28),
	NDIS_80211_ADDKEY_SET_INIT_RECV_SEQ = cpu_to_le32(1 << 29),
	NDIS_80211_ADDKEY_PAIRWISE_KEY = cpu_to_le32(1 << 30),
	NDIS_80211_ADDKEY_TRANSMIT_KEY = cpu_to_le32(1 << 31)
235
236
237
};

enum ndis_80211_addwep_bits {
238
239
	NDIS_80211_ADDWEP_PERCLIENT_KEY = cpu_to_le32(1 << 30),
	NDIS_80211_ADDWEP_TRANSMIT_KEY = cpu_to_le32(1 << 31)
240
241
};

242
243
244
245
246
struct ndis_80211_auth_request {
	__le32 length;
	u8 bssid[6];
	u8 padding[2];
	__le32 flags;
247
} __packed;
248
249
250
251
252

struct ndis_80211_pmkid_candidate {
	u8 bssid[6];
	u8 padding[2];
	__le32 flags;
253
} __packed;
254
255
256
257
258

struct ndis_80211_pmkid_cand_list {
	__le32 version;
	__le32 num_candidates;
	struct ndis_80211_pmkid_candidate candidate_list[0];
259
} __packed;
260
261
262
263

struct ndis_80211_status_indication {
	__le32 status_type;
	union {
264
265
		__le32					media_stream_mode;
		__le32					radio_status;
266
267
268
		struct ndis_80211_auth_request		auth_request[0];
		struct ndis_80211_pmkid_cand_list	cand_list;
	} u;
269
} __packed;
270

271
struct ndis_80211_ssid {
272
273
	__le32 length;
	u8 essid[NDIS_802_11_LENGTH_SSID];
274
} __packed;
275

276
struct ndis_80211_conf_freq_hop {
277
278
279
280
	__le32 length;
	__le32 hop_pattern;
	__le32 hop_set;
	__le32 dwell_time;
281
} __packed;
282

283
struct ndis_80211_conf {
284
285
286
287
288
	__le32 length;
	__le32 beacon_period;
	__le32 atim_window;
	__le32 ds_config;
	struct ndis_80211_conf_freq_hop fh_config;
289
} __packed;
290

291
struct ndis_80211_bssid_ex {
292
293
294
295
296
297
298
299
300
301
302
303
	__le32 length;
	u8 mac[6];
	u8 padding[2];
	struct ndis_80211_ssid ssid;
	__le32 privacy;
	__le32 rssi;
	__le32 net_type;
	struct ndis_80211_conf config;
	__le32 net_infra;
	u8 rates[NDIS_802_11_LENGTH_RATES_EX];
	__le32 ie_length;
	u8 ies[0];
304
} __packed;
305

306
struct ndis_80211_bssid_list_ex {
307
308
	__le32 num_items;
	struct ndis_80211_bssid_ex bssid[0];
309
} __packed;
310

311
struct ndis_80211_fixed_ies {
312
313
314
	u8 timestamp[8];
	__le16 beacon_interval;
	__le16 capabilities;
315
} __packed;
316

317
struct ndis_80211_wep_key {
318
319
320
321
	__le32 size;
	__le32 index;
	__le32 length;
	u8 material[32];
322
} __packed;
323

324
struct ndis_80211_key {
325
326
327
328
329
330
331
	__le32 size;
	__le32 index;
	__le32 length;
	u8 bssid[6];
	u8 padding[6];
	u8 rsc[8];
	u8 material[32];
332
} __packed;
333

334
struct ndis_80211_remove_key {
335
336
337
	__le32 size;
	__le32 index;
	u8 bssid[6];
338
	u8 padding[2];
339
} __packed;
340

341
struct ndis_config_param {
342
343
344
345
346
	__le32 name_offs;
	__le32 name_length;
	__le32 type;
	__le32 value_offs;
	__le32 value_length;
347
} __packed;
348

349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
struct ndis_80211_assoc_info {
	__le32 length;
	__le16 req_ies;
	struct req_ie {
		__le16 capa;
		__le16 listen_interval;
		u8 cur_ap_address[6];
	} req_ie;
	__le32 req_ie_length;
	__le32 offset_req_ies;
	__le16 resp_ies;
	struct resp_ie {
		__le16 capa;
		__le16 status_code;
		__le16 assoc_id;
	} resp_ie;
	__le32 resp_ie_length;
	__le32 offset_resp_ies;
367
} __packed;
368

369
370
371
struct ndis_80211_auth_encr_pair {
	__le32 auth_mode;
	__le32 encr_mode;
372
} __packed;
373
374
375
376
377
378
379

struct ndis_80211_capability {
	__le32 length;
	__le32 version;
	__le32 num_pmkids;
	__le32 num_auth_encr_pair;
	struct ndis_80211_auth_encr_pair auth_encr_pair[0];
380
} __packed;
381

382
383
384
385
386
387
388
389
390
391
392
struct ndis_80211_bssid_info {
	u8 bssid[6];
	u8 pmkid[16];
};

struct ndis_80211_pmkid {
	__le32 length;
	__le32 bssid_info_count;
	struct ndis_80211_bssid_info bssid_info[0];
};

393
394
395
396
397
398
399
400
401
402
/*
 *  private data
 */
#define NET_TYPE_11FB	0

#define CAP_MODE_80211A		1
#define CAP_MODE_80211B		2
#define CAP_MODE_80211G		4
#define CAP_MODE_MASK		7

403
404
405
#define WORK_LINK_UP		(1<<0)
#define WORK_LINK_DOWN		(1<<1)
#define WORK_SET_MULTICAST_LIST	(1<<2)
406

407
408
409
410
411
412
413
414
415
#define RNDIS_WLAN_ALG_NONE	0
#define RNDIS_WLAN_ALG_WEP	(1<<0)
#define RNDIS_WLAN_ALG_TKIP	(1<<1)
#define RNDIS_WLAN_ALG_CCMP	(1<<2)

#define RNDIS_WLAN_KEY_MGMT_NONE	0
#define RNDIS_WLAN_KEY_MGMT_802_1X	(1<<0)
#define RNDIS_WLAN_KEY_MGMT_PSK		(1<<1)

416
417
#define COMMAND_BUFFER_SIZE	(CONTROL_BUFFER_SIZE + sizeof(struct rndis_set))

418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
static const struct ieee80211_channel rndis_channels[] = {
	{ .center_freq = 2412 },
	{ .center_freq = 2417 },
	{ .center_freq = 2422 },
	{ .center_freq = 2427 },
	{ .center_freq = 2432 },
	{ .center_freq = 2437 },
	{ .center_freq = 2442 },
	{ .center_freq = 2447 },
	{ .center_freq = 2452 },
	{ .center_freq = 2457 },
	{ .center_freq = 2462 },
	{ .center_freq = 2467 },
	{ .center_freq = 2472 },
	{ .center_freq = 2484 },
};

static const struct ieee80211_rate rndis_rates[] = {
	{ .bitrate = 10 },
	{ .bitrate = 20, .flags = IEEE80211_RATE_SHORT_PREAMBLE },
	{ .bitrate = 55, .flags = IEEE80211_RATE_SHORT_PREAMBLE },
	{ .bitrate = 110, .flags = IEEE80211_RATE_SHORT_PREAMBLE },
	{ .bitrate = 60 },
	{ .bitrate = 90 },
	{ .bitrate = 120 },
	{ .bitrate = 180 },
	{ .bitrate = 240 },
	{ .bitrate = 360 },
	{ .bitrate = 480 },
	{ .bitrate = 540 }
};

450
451
452
453
454
455
456
static const u32 rndis_cipher_suites[] = {
	WLAN_CIPHER_SUITE_WEP40,
	WLAN_CIPHER_SUITE_WEP104,
	WLAN_CIPHER_SUITE_TKIP,
	WLAN_CIPHER_SUITE_CCMP,
};

457
458
struct rndis_wlan_encr_key {
	int len;
459
	u32 cipher;
460
461
462
463
464
465
	u8 material[32];
	u8 bssid[ETH_ALEN];
	bool pairwise;
	bool tx_key;
};

466
/* RNDIS device private data */
467
struct rndis_wlan_private {
468
469
	struct usbnet *usbdev;

470
471
	struct wireless_dev wdev;

472
473
	struct cfg80211_scan_request *scan_request;

474
	struct workqueue_struct *workqueue;
475
	struct delayed_work dev_poller_work;
476
	struct delayed_work scan_work;
477
478
479
	struct work_struct work;
	struct mutex command_lock;
	unsigned long work_pending;
480
	int last_qual;
481

482
483
484
	struct ieee80211_supported_band band;
	struct ieee80211_channel channels[ARRAY_SIZE(rndis_channels)];
	struct ieee80211_rate rates[ARRAY_SIZE(rndis_rates)];
485
	u32 cipher_suites[ARRAY_SIZE(rndis_cipher_suites)];
486

487
	int device_type;
488
489
490
491
492
493
494
495
496
497
498
499
500
501
	int caps;
	int multicast_size;

	/* module parameters */
	char param_country[4];
	int  param_frameburst;
	int  param_afterburner;
	int  param_power_save;
	int  param_power_output;
	int  param_roamtrigger;
	int  param_roamdelta;
	u32  param_workaround_interval;

	/* hardware state */
502
	bool radio_on;
503
	int infra_mode;
504
	bool connected;
505
	u8 bssid[ETH_ALEN];
506
	struct ndis_80211_ssid essid;
507
	__le32 current_command_oid;
508
509
510

	/* encryption stuff */
	int  encr_tx_key_index;
511
	struct rndis_wlan_encr_key encr_keys[4];
512
	int  wpa_version;
513
514

	u8 command_buffer[COMMAND_BUFFER_SIZE];
515
516
};

517
518
519
/*
 * cfg80211 ops
 */
520
521
static int rndis_change_virtual_intf(struct wiphy *wiphy,
					struct net_device *dev,
522
523
524
					enum nl80211_iftype type, u32 *flags,
					struct vif_params *params);

525
526
527
static int rndis_scan(struct wiphy *wiphy, struct net_device *dev,
			struct cfg80211_scan_request *request);

528
529
static int rndis_set_wiphy_params(struct wiphy *wiphy, u32 changed);

530
531
532
static int rndis_set_tx_power(struct wiphy *wiphy,
			      enum nl80211_tx_power_setting type,
			      int mbm);
533
534
static int rndis_get_tx_power(struct wiphy *wiphy, int *dbm);

535
536
537
538
539
540
541
542
543
544
545
static int rndis_connect(struct wiphy *wiphy, struct net_device *dev,
				struct cfg80211_connect_params *sme);

static int rndis_disconnect(struct wiphy *wiphy, struct net_device *dev,
				u16 reason_code);

static int rndis_join_ibss(struct wiphy *wiphy, struct net_device *dev,
					struct cfg80211_ibss_params *params);

static int rndis_leave_ibss(struct wiphy *wiphy, struct net_device *dev);

546
static int rndis_set_channel(struct wiphy *wiphy, struct net_device *dev,
547
548
	struct ieee80211_channel *chan, enum nl80211_channel_type channel_type);

549
static int rndis_add_key(struct wiphy *wiphy, struct net_device *netdev,
550
551
			 u8 key_index, bool pairwise, const u8 *mac_addr,
			 struct key_params *params);
552
553

static int rndis_del_key(struct wiphy *wiphy, struct net_device *netdev,
554
			 u8 key_index, bool pairwise, const u8 *mac_addr);
555
556

static int rndis_set_default_key(struct wiphy *wiphy, struct net_device *netdev,
557
				 u8 key_index, bool unicast, bool multicast);
558

559
560
561
static int rndis_get_station(struct wiphy *wiphy, struct net_device *dev,
					u8 *mac, struct station_info *sinfo);

562
563
564
static int rndis_dump_station(struct wiphy *wiphy, struct net_device *dev,
			       int idx, u8 *mac, struct station_info *sinfo);

565
566
567
568
569
570
571
572
static int rndis_set_pmksa(struct wiphy *wiphy, struct net_device *netdev,
				struct cfg80211_pmksa *pmksa);

static int rndis_del_pmksa(struct wiphy *wiphy, struct net_device *netdev,
				struct cfg80211_pmksa *pmksa);

static int rndis_flush_pmksa(struct wiphy *wiphy, struct net_device *netdev);

573
static struct cfg80211_ops rndis_config_ops = {
574
	.change_virtual_intf = rndis_change_virtual_intf,
575
	.scan = rndis_scan,
576
	.set_wiphy_params = rndis_set_wiphy_params,
577
578
	.set_tx_power = rndis_set_tx_power,
	.get_tx_power = rndis_get_tx_power,
579
580
581
582
	.connect = rndis_connect,
	.disconnect = rndis_disconnect,
	.join_ibss = rndis_join_ibss,
	.leave_ibss = rndis_leave_ibss,
583
	.set_channel = rndis_set_channel,
584
585
586
	.add_key = rndis_add_key,
	.del_key = rndis_del_key,
	.set_default_key = rndis_set_default_key,
587
	.get_station = rndis_get_station,
588
	.dump_station = rndis_dump_station,
589
590
591
	.set_pmksa = rndis_set_pmksa,
	.del_pmksa = rndis_del_pmksa,
	.flush_pmksa = rndis_flush_pmksa,
592
};
593

594
static void *rndis_wiphy_privid = &rndis_wiphy_privid;
595
596


597
static struct rndis_wlan_private *get_rndis_wlan_priv(struct usbnet *dev)
598
{
599
	return (struct rndis_wlan_private *)dev->driver_priv;
600
601
}

602
static u32 get_bcm4320_power_dbm(struct rndis_wlan_private *priv)
603
{
604
605
606
607
608
609
610
611
612
613
614
	switch (priv->param_power_output) {
	default:
	case 3:
		return BCM4320_DEFAULT_TXPOWER_DBM_100;
	case 2:
		return BCM4320_DEFAULT_TXPOWER_DBM_75;
	case 1:
		return BCM4320_DEFAULT_TXPOWER_DBM_50;
	case 0:
		return BCM4320_DEFAULT_TXPOWER_DBM_25;
	}
615
616
}

617
618
619
620
621
622
623
624
static bool is_wpa_key(struct rndis_wlan_private *priv, int idx)
{
	int cipher = priv->encr_keys[idx].cipher;

	return (cipher == WLAN_CIPHER_SUITE_CCMP ||
		cipher == WLAN_CIPHER_SUITE_TKIP);
}

625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
static int rndis_cipher_to_alg(u32 cipher)
{
	switch (cipher) {
	default:
		return RNDIS_WLAN_ALG_NONE;
	case WLAN_CIPHER_SUITE_WEP40:
	case WLAN_CIPHER_SUITE_WEP104:
		return RNDIS_WLAN_ALG_WEP;
	case WLAN_CIPHER_SUITE_TKIP:
		return RNDIS_WLAN_ALG_TKIP;
	case WLAN_CIPHER_SUITE_CCMP:
		return RNDIS_WLAN_ALG_CCMP;
	}
}

static int rndis_akm_suite_to_key_mgmt(u32 akm_suite)
{
	switch (akm_suite) {
	default:
		return RNDIS_WLAN_KEY_MGMT_NONE;
	case WLAN_AKM_SUITE_8021X:
		return RNDIS_WLAN_KEY_MGMT_802_1X;
	case WLAN_AKM_SUITE_PSK:
		return RNDIS_WLAN_KEY_MGMT_PSK;
	}
}

652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
#ifdef DEBUG
static const char *oid_to_string(__le32 oid)
{
	switch (oid) {
#define OID_STR(oid) case oid: return(#oid)
		/* from rndis_host.h */
		OID_STR(OID_802_3_PERMANENT_ADDRESS);
		OID_STR(OID_GEN_MAXIMUM_FRAME_SIZE);
		OID_STR(OID_GEN_CURRENT_PACKET_FILTER);
		OID_STR(OID_GEN_PHYSICAL_MEDIUM);

		/* from rndis_wlan.c */
		OID_STR(OID_GEN_LINK_SPEED);
		OID_STR(OID_GEN_RNDIS_CONFIG_PARAMETER);

		OID_STR(OID_GEN_XMIT_OK);
		OID_STR(OID_GEN_RCV_OK);
		OID_STR(OID_GEN_XMIT_ERROR);
		OID_STR(OID_GEN_RCV_ERROR);
		OID_STR(OID_GEN_RCV_NO_BUFFER);

		OID_STR(OID_802_3_CURRENT_ADDRESS);
		OID_STR(OID_802_3_MULTICAST_LIST);
		OID_STR(OID_802_3_MAXIMUM_LIST_SIZE);

		OID_STR(OID_802_11_BSSID);
		OID_STR(OID_802_11_SSID);
		OID_STR(OID_802_11_INFRASTRUCTURE_MODE);
		OID_STR(OID_802_11_ADD_WEP);
		OID_STR(OID_802_11_REMOVE_WEP);
		OID_STR(OID_802_11_DISASSOCIATE);
		OID_STR(OID_802_11_AUTHENTICATION_MODE);
		OID_STR(OID_802_11_PRIVACY_FILTER);
		OID_STR(OID_802_11_BSSID_LIST_SCAN);
		OID_STR(OID_802_11_ENCRYPTION_STATUS);
		OID_STR(OID_802_11_ADD_KEY);
		OID_STR(OID_802_11_REMOVE_KEY);
		OID_STR(OID_802_11_ASSOCIATION_INFORMATION);
		OID_STR(OID_802_11_PMKID);
		OID_STR(OID_802_11_NETWORK_TYPES_SUPPORTED);
		OID_STR(OID_802_11_NETWORK_TYPE_IN_USE);
		OID_STR(OID_802_11_TX_POWER_LEVEL);
		OID_STR(OID_802_11_RSSI);
		OID_STR(OID_802_11_RSSI_TRIGGER);
		OID_STR(OID_802_11_FRAGMENTATION_THRESHOLD);
		OID_STR(OID_802_11_RTS_THRESHOLD);
		OID_STR(OID_802_11_SUPPORTED_RATES);
		OID_STR(OID_802_11_CONFIGURATION);
		OID_STR(OID_802_11_BSSID_LIST);
#undef OID_STR
	}

	return "?";
}
#else
static const char *oid_to_string(__le32 oid)
{
	return "?";
}
#endif

713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
/* translate error code */
static int rndis_error_status(__le32 rndis_status)
{
	int ret = -EINVAL;
	switch (rndis_status) {
	case RNDIS_STATUS_SUCCESS:
		ret = 0;
		break;
	case RNDIS_STATUS_FAILURE:
	case RNDIS_STATUS_INVALID_DATA:
		ret = -EINVAL;
		break;
	case RNDIS_STATUS_NOT_SUPPORTED:
		ret = -EOPNOTSUPP;
		break;
	case RNDIS_STATUS_ADAPTER_NOT_READY:
	case RNDIS_STATUS_ADAPTER_NOT_OPEN:
		ret = -EBUSY;
		break;
	}
	return ret;
}

static int rndis_query_oid(struct usbnet *dev, __le32 oid, void *data, int *len)
{
738
	struct rndis_wlan_private *priv = get_rndis_wlan_priv(dev);
739
740
741
742
743
744
745
	union {
		void			*buf;
		struct rndis_msg_hdr	*header;
		struct rndis_query	*get;
		struct rndis_query_c	*get_c;
	} u;
	int ret, buflen;
746
	int resplen, respoffs, copylen;
747
748
749
750

	buflen = *len + sizeof(*u.get);
	if (buflen < CONTROL_BUFFER_SIZE)
		buflen = CONTROL_BUFFER_SIZE;
751
752
753
754
755
756
757
758
759
760
761

	if (buflen > COMMAND_BUFFER_SIZE) {
		u.buf = kmalloc(buflen, GFP_KERNEL);
		if (!u.buf)
			return -ENOMEM;
	} else {
		u.buf = priv->command_buffer;
	}

	mutex_lock(&priv->command_lock);

762
763
	memset(u.get, 0, sizeof *u.get);
	u.get->msg_type = RNDIS_MSG_QUERY;
764
	u.get->msg_len = cpu_to_le32(sizeof *u.get);
765
766
	u.get->oid = oid;

767
	priv->current_command_oid = oid;
768
	ret = rndis_command(dev, u.header, buflen);
769
	priv->current_command_oid = 0;
770
	if (ret < 0)
771
772
773
		netdev_dbg(dev->net, "%s(%s): rndis_command() failed, %d (%08x)\n",
			   __func__, oid_to_string(oid), ret,
			   le32_to_cpu(u.get_c->status));
774

775
	if (ret == 0) {
776
777
		resplen = le32_to_cpu(u.get_c->len);
		respoffs = le32_to_cpu(u.get_c->offset) + 8;
778

779
780
781
782
783
		if (respoffs > buflen) {
			/* Device returned data offset outside buffer, error. */
			netdev_dbg(dev->net, "%s(%s): received invalid "
				"data offset: %d > %d\n", __func__,
				oid_to_string(oid), respoffs, buflen);
784

785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
			ret = -EINVAL;
			goto exit_unlock;
		}

		if ((resplen + respoffs) > buflen) {
			/* Device would have returned more data if buffer would
			 * have been big enough. Copy just the bits that we got.
			 */
			copylen = buflen - respoffs;
		} else {
			copylen = resplen;
		}

		if (copylen > *len)
			copylen = *len;

		memcpy(data, u.buf + respoffs, copylen);

		*len = resplen;
804

805
		ret = rndis_error_status(u.get_c->status);
806
		if (ret < 0)
807
808
809
			netdev_dbg(dev->net, "%s(%s): device returned error,  0x%08x (%d)\n",
				   __func__, oid_to_string(oid),
				   le32_to_cpu(u.get_c->status), ret);
810
811
	}

812
exit_unlock:
813
814
815
816
	mutex_unlock(&priv->command_lock);

	if (u.buf != priv->command_buffer)
		kfree(u.buf);
817
818
819
	return ret;
}

Joe Perches's avatar
Joe Perches committed
820
821
static int rndis_set_oid(struct usbnet *dev, __le32 oid, const void *data,
			 int len)
822
{
823
	struct rndis_wlan_private *priv = get_rndis_wlan_priv(dev);
824
825
826
827
828
829
830
831
832
833
834
	union {
		void			*buf;
		struct rndis_msg_hdr	*header;
		struct rndis_set	*set;
		struct rndis_set_c	*set_c;
	} u;
	int ret, buflen;

	buflen = len + sizeof(*u.set);
	if (buflen < CONTROL_BUFFER_SIZE)
		buflen = CONTROL_BUFFER_SIZE;
835
836
837
838
839
840
841
842
843
844

	if (buflen > COMMAND_BUFFER_SIZE) {
		u.buf = kmalloc(buflen, GFP_KERNEL);
		if (!u.buf)
			return -ENOMEM;
	} else {
		u.buf = priv->command_buffer;
	}

	mutex_lock(&priv->command_lock);
845
846
847
848
849
850

	memset(u.set, 0, sizeof *u.set);
	u.set->msg_type = RNDIS_MSG_SET;
	u.set->msg_len = cpu_to_le32(sizeof(*u.set) + len);
	u.set->oid = oid;
	u.set->len = cpu_to_le32(len);
851
852
	u.set->offset = cpu_to_le32(sizeof(*u.set) - 8);
	u.set->handle = cpu_to_le32(0);
853
854
	memcpy(u.buf + sizeof(*u.set), data, len);

855
	priv->current_command_oid = oid;
856
	ret = rndis_command(dev, u.header, buflen);
857
	priv->current_command_oid = 0;
858
	if (ret < 0)
859
860
861
		netdev_dbg(dev->net, "%s(%s): rndis_command() failed, %d (%08x)\n",
			   __func__, oid_to_string(oid), ret,
			   le32_to_cpu(u.set_c->status));
862
863

	if (ret == 0) {
864
865
		ret = rndis_error_status(u.set_c->status);

866
		if (ret < 0)
867
868
869
			netdev_dbg(dev->net, "%s(%s): device returned error, 0x%08x (%d)\n",
				   __func__, oid_to_string(oid),
				   le32_to_cpu(u.set_c->status), ret);
870
871
	}

872
873
874
875
	mutex_unlock(&priv->command_lock);

	if (u.buf != priv->command_buffer)
		kfree(u.buf);
876
877
878
	return ret;
}

879
880
881
882
883
884
885
886
887
888
889
890
static int rndis_reset(struct usbnet *usbdev)
{
	struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev);
	struct rndis_reset *reset;
	int ret;

	mutex_lock(&priv->command_lock);

	reset = (void *)priv->command_buffer;
	memset(reset, 0, sizeof(*reset));
	reset->msg_type = RNDIS_MSG_RESET;
	reset->msg_len = cpu_to_le32(sizeof(*reset));
891
	priv->current_command_oid = 0;
892
893
894
895
896
897
898
899
900
	ret = rndis_command(usbdev, (void *)reset, CONTROL_BUFFER_SIZE);

	mutex_unlock(&priv->command_lock);

	if (ret < 0)
		return ret;
	return 0;
}

901
902
903
904
905
906
907
908
/*
 * Specs say that we can only set config parameters only soon after device
 * initialization.
 *   value_type: 0 = u32, 2 = unicode string
 */
static int rndis_set_config_parameter(struct usbnet *dev, char *param,
						int value_type, void *value)
{
909
	struct ndis_config_param *infobuf;
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
	int value_len, info_len, param_len, ret, i;
	__le16 *unibuf;
	__le32 *dst_value;

	if (value_type == 0)
		value_len = sizeof(__le32);
	else if (value_type == 2)
		value_len = strlen(value) * sizeof(__le16);
	else
		return -EINVAL;

	param_len = strlen(param) * sizeof(__le16);
	info_len = sizeof(*infobuf) + param_len + value_len;

#ifdef DEBUG
	info_len += 12;
#endif
	infobuf = kmalloc(info_len, GFP_KERNEL);
	if (!infobuf)
		return -ENOMEM;

#ifdef DEBUG
	info_len -= 12;
	/* extra 12 bytes are for padding (debug output) */
	memset(infobuf, 0xCC, info_len + 12);
#endif

	if (value_type == 2)
938
939
		netdev_dbg(dev->net, "setting config parameter: %s, value: %s\n",
			   param, (u8 *)value);
940
	else
941
942
		netdev_dbg(dev->net, "setting config parameter: %s, value: %d\n",
			   param, *(u32 *)value);
943

944
945
946
947
948
	infobuf->name_offs = cpu_to_le32(sizeof(*infobuf));
	infobuf->name_length = cpu_to_le32(param_len);
	infobuf->type = cpu_to_le32(value_type);
	infobuf->value_offs = cpu_to_le32(sizeof(*infobuf) + param_len);
	infobuf->value_length = cpu_to_le32(value_len);
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964

	/* simple string to unicode string conversion */
	unibuf = (void *)infobuf + sizeof(*infobuf);
	for (i = 0; i < param_len / sizeof(__le16); i++)
		unibuf[i] = cpu_to_le16(param[i]);

	if (value_type == 2) {
		unibuf = (void *)infobuf + sizeof(*infobuf) + param_len;
		for (i = 0; i < value_len / sizeof(__le16); i++)
			unibuf[i] = cpu_to_le16(((u8 *)value)[i]);
	} else {
		dst_value = (void *)infobuf + sizeof(*infobuf) + param_len;
		*dst_value = cpu_to_le32(*(u32 *)value);
	}

#ifdef DEBUG
965
	netdev_dbg(dev->net, "info buffer (len: %d)\n", info_len);
966
967
	for (i = 0; i < info_len; i += 12) {
		u32 *tmp = (u32 *)((u8 *)infobuf + i);
968
969
970
971
		netdev_dbg(dev->net, "%08X:%08X:%08X\n",
			   cpu_to_be32(tmp[0]),
			   cpu_to_be32(tmp[1]),
			   cpu_to_be32(tmp[2]));
972
973
974
975
976
977
	}
#endif

	ret = rndis_set_oid(dev, OID_GEN_RNDIS_CONFIG_PARAMETER,
							infobuf, info_len);
	if (ret != 0)
978
979
		netdev_dbg(dev->net, "setting rndis config parameter failed, %d\n",
			   ret);
980
981
982
983
984
985
986
987

	kfree(infobuf);
	return ret;
}

static int rndis_set_config_parameter_str(struct usbnet *dev,
						char *param, char *value)
{
Jussi Kivilinna's avatar
Jussi Kivilinna committed
988
	return rndis_set_config_parameter(dev, param, 2, value);
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
}

/*
 * data conversion functions
 */
static int level_to_qual(int level)
{
	int qual = 100 * (level - WL_NOISE) / (WL_SIGMAX - WL_NOISE);
	return qual >= 0 ? (qual <= 100 ? qual : 100) : 0;
}

/*
 * common functions
 */
1003
static int set_infra_mode(struct usbnet *usbdev, int mode);
1004
static void restore_keys(struct usbnet *usbdev);
1005
1006
static int rndis_check_bssid_list(struct usbnet *usbdev, u8 *match_bssid,
					bool *matched);
1007

1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
static int rndis_start_bssid_list_scan(struct usbnet *usbdev)
{
	__le32 tmp;

	/* Note: OID_802_11_BSSID_LIST_SCAN clears internal BSS list. */
	tmp = cpu_to_le32(1);
	return rndis_set_oid(usbdev, OID_802_11_BSSID_LIST_SCAN, &tmp,
							sizeof(tmp));
}

1018
static int set_essid(struct usbnet *usbdev, struct ndis_80211_ssid *ssid)
1019
{
1020
	struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev);
1021
1022
1023
	int ret;

	ret = rndis_set_oid(usbdev, OID_802_11_SSID, ssid, sizeof(*ssid));
1024
	if (ret < 0) {
1025
		netdev_warn(usbdev->net, "setting SSID failed (%08X)\n", ret);
1026
1027
		return ret;
	}
1028
1029
	if (ret == 0) {
		memcpy(&priv->essid, ssid, sizeof(priv->essid));
1030
		priv->radio_on = true;
1031
		netdev_dbg(usbdev->net, "%s(): radio_on = true\n", __func__);
1032
1033
1034
1035
1036
	}

	return ret;
}

Joe Perches's avatar
Joe Perches committed
1037
static int set_bssid(struct usbnet *usbdev, const u8 *bssid)
1038
1039
1040
1041
1042
{
	int ret;

	ret = rndis_set_oid(usbdev, OID_802_11_BSSID, bssid, ETH_ALEN);
	if (ret < 0) {
1043
1044
		netdev_warn(usbdev->net, "setting BSSID[%pM] failed (%08X)\n",
			    bssid, ret);
1045
1046
1047
1048
1049
1050
1051
1052
		return ret;
	}

	return ret;
}

static int clear_bssid(struct usbnet *usbdev)
{
Joe Perches's avatar
Joe Perches committed
1053
1054
1055
	static const u8 broadcast_mac[ETH_ALEN] = {
		0xff, 0xff, 0xff, 0xff, 0xff, 0xff
	};
1056
1057
1058

	return set_bssid(usbdev, broadcast_mac);
}
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072

static int get_bssid(struct usbnet *usbdev, u8 bssid[ETH_ALEN])
{
	int ret, len;

	len = ETH_ALEN;
	ret = rndis_query_oid(usbdev, OID_802_11_BSSID, bssid, &len);

	if (ret != 0)
		memset(bssid, 0, ETH_ALEN);

	return ret;
}

1073
1074
1075
1076
1077
1078
static int get_association_info(struct usbnet *usbdev,
			struct ndis_80211_assoc_info *info, int len)
{
	return rndis_query_oid(usbdev, OID_802_11_ASSOCIATION_INFORMATION,
				info, &len);
}
1079

1080
static bool is_associated(struct usbnet *usbdev)
1081
{
1082
	struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev);
1083
1084
1085
	u8 bssid[ETH_ALEN];
	int ret;

1086
1087
1088
	if (!priv->radio_on)
		return false;

1089
1090
	ret = get_bssid(usbdev, bssid);

1091
	return (ret == 0 && !is_zero_ether_addr(bssid));
1092
1093
}

1094
static int disassociate(struct usbnet *usbdev, bool reset_ssid)
1095
{
1096
	struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev);
1097
	struct ndis_80211_ssid ssid;
1098
1099
1100
1101
1102
	int i, ret = 0;

	if (priv->radio_on) {
		ret = rndis_set_oid(usbdev, OID_802_11_DISASSOCIATE, NULL, 0);
		if (ret == 0) {
1103
			priv->radio_on = false;
1104
1105
			netdev_dbg(usbdev->net, "%s(): radio_on = false\n",
				   __func__);
1106
1107
1108
1109
1110
1111
1112
1113
1114

			if (reset_ssid)
				msleep(100);
		}
	}

	/* disassociate causes radio to be turned off; if reset_ssid
	 * is given, set random ssid to enable radio */
	if (reset_ssid) {
1115
1116
1117
1118
1119
		/* Set device to infrastructure mode so we don't get ad-hoc
		 * 'media connect' indications with the random ssid.
		 */
		set_infra_mode(usbdev, NDIS_80211_INFRA_INFRA);

1120
1121
1122
1123
1124
1125
		ssid.length = cpu_to_le32(sizeof(ssid.essid));
		get_random_bytes(&ssid.essid[2], sizeof(ssid.essid)-2);
		ssid.essid[0] = 0x1;
		ssid.essid[1] = 0xff;
		for (i = 2; i < sizeof(ssid.essid); i++)
			ssid.essid[i] = 0x1 + (ssid.essid[i] * 0xfe / 0xff);
1126
1127
1128
1129
1130
		ret = set_essid(usbdev, &ssid);
	}
	return ret;
}

1131
1132
static int set_auth_mode(struct usbnet *usbdev, u32 wpa_version,
				enum nl80211_auth_type auth_type, int keymgmt)
1133
{
1134
	struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev);
1135
1136
1137
	__le32 tmp;
	int auth_mode, ret;

1138
1139
	netdev_dbg(usbdev->net, "%s(): wpa_version=0x%x authalg=0x%x keymgmt=0x%x\n",
		   __func__, wpa_version, auth_type, keymgmt);
1140

1141
1142
	if (wpa_version & NL80211_WPA_VERSION_2) {
		if (keymgmt & RNDIS_WLAN_KEY_MGMT_802_1X)
1143
			auth_mode = NDIS_80211_AUTH_WPA2;
1144
		else
1145
			auth_mode = NDIS_80211_AUTH_WPA2_PSK;
1146
1147
	} else if (wpa_version & NL80211_WPA_VERSION_1) {
		if (keymgmt & RNDIS_WLAN_KEY_MGMT_802_1X)
1148
			auth_mode = NDIS_80211_AUTH_WPA;
1149
		else if (keymgmt & RNDIS_WLAN_KEY_MGMT_PSK)
1150
			auth_mode = NDIS_80211_AUTH_WPA_PSK;
1151
		else
1152
			auth_mode = NDIS_80211_AUTH_WPA_NONE;
1153
1154
1155
	} else if (auth_type == NL80211_AUTHTYPE_SHARED_KEY)
		auth_mode = NDIS_80211_AUTH_SHARED;
	else if (auth_type == NL80211_AUTHTYPE_OPEN_SYSTEM)
1156
		auth_mode = NDIS_80211_AUTH_OPEN;
1157
1158
	else if (auth_type == NL80211_AUTHTYPE_AUTOMATIC)
		auth_mode = NDIS_80211_AUTH_AUTO_SWITCH;
1159
1160
	else
		return -ENOTSUPP;
1161
1162
1163
1164
1165

	tmp = cpu_to_le32(auth_mode);
	ret = rndis_set_oid(usbdev, OID_802_11_AUTHENTICATION_MODE, &tmp,
								sizeof(tmp));
	if (ret != 0) {
1166
1167
		netdev_warn(usbdev->net, "setting auth mode failed (%08X)\n",
			    ret);
1168
1169
1170
1171
		return ret;
	}

	priv->wpa_version = wpa_version;
1172

1173
1174
1175
1176
1177
	return 0;
}

static int set_priv_filter(struct usbnet *usbdev)
{
1178
	struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev);
1179
1180
	__le32 tmp;

1181
1182
	netdev_dbg(usbdev->net, "%s(): wpa_version=0x%x\n",
		   __func__, priv->wpa_version);
1183

1184
1185
	if (priv->wpa_version & NL80211_WPA_VERSION_2 ||
	    priv->wpa_version & NL80211_WPA_VERSION_1)
1186
		tmp = cpu_to_le32(NDIS_80211_PRIV_8021X_WEP);
1187
	else
1188
		tmp = cpu_to_le32(NDIS_80211_PRIV_ACCEPT_ALL);
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198

	return rndis_set_oid(usbdev, OID_802_11_PRIVACY_FILTER, &tmp,
								sizeof(tmp));
}

static int set_encr_mode(struct usbnet *usbdev, int pairwise, int groupwise)
{
	__le32 tmp;
	int encr_mode, ret;

1199
1200
	netdev_dbg(usbdev->net, "%s(): cipher_pair=0x%x cipher_group=0x%x\n",
		   __func__, pairwise, groupwise);
1201

1202
	if (pairwise & RNDIS_WLAN_ALG_CCMP)
1203
		encr_mode = NDIS_80211_ENCR_CCMP_ENABLED;
1204
	else if (pairwise & RNDIS_WLAN_ALG_TKIP)
1205
		encr_mode = NDIS_80211_ENCR_TKIP_ENABLED;
1206
	else if (pairwise & RNDIS_WLAN_ALG_WEP)
1207
		encr_mode = NDIS_80211_ENCR_WEP_ENABLED;
1208
	else if (groupwise & RNDIS_WLAN_ALG_CCMP)
1209
		encr_mode = NDIS_80211_ENCR_CCMP_ENABLED;
1210
	else if (groupwise & RNDIS_WLAN_ALG_TKIP)
1211
		encr_mode = NDIS_80211_ENCR_TKIP_ENABLED;
1212
	else
1213
		encr_mode = NDIS_80211_ENCR_DISABLED;
1214
1215
1216
1217
1218

	tmp = cpu_to_le32(encr_mode);
	ret = rndis_set_oid(usbdev, OID_802_11_ENCRYPTION_STATUS, &tmp,
								sizeof(tmp));
	if (ret != 0) {
1219
1220
		netdev_warn(usbdev->net, "setting encr mode failed (%08X)\n",
			    ret);
1221
1222
1223
1224
1225
1226
1227
1228
		return ret;
	}

	return 0;
}

static int set_infra_mode(struct usbnet *usbdev, int mode)
{
1229
	struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev);
1230
	__le32 tmp;
1231
	int ret;
1232

1233
1234
	netdev_dbg(usbdev->net, "%s(): infra_mode=0x%x\n",
		   __func__, priv->infra_mode);
1235
1236
1237
1238
1239

	tmp = cpu_to_le32(mode);
	ret = rndis_set_oid(usbdev, OID_802_11_INFRASTRUCTURE_MODE, &tmp,
								sizeof(tmp));
	if (ret != 0) {
1240
1241
		netdev_warn(usbdev->net, "setting infra mode failed (%08X)\n",
			    ret);
1242
1243
1244
1245
1246
1247
		return ret;
	}

	/* NDIS drivers clear keys when infrastructure mode is
	 * changed. But Linux tools assume otherwise. So set the
	 * keys */
1248
	restore_keys(usbdev);
1249
1250
1251
1252
1253

	priv->infra_mode = mode;
	return 0;
}

1254
1255
1256
1257
static int set_rts_threshold(struct usbnet *usbdev, u32 rts_threshold)
{
	__le32 tmp;

1258
	netdev_dbg(usbdev->net, "%s(): %i\n", __func__, rts_threshold);
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271

	if (rts_threshold < 0 || rts_threshold > 2347)
		rts_threshold = 2347;

	tmp = cpu_to_le32(rts_threshold);
	return rndis_set_oid(usbdev, OID_802_11_RTS_THRESHOLD, &tmp,
								sizeof(tmp));
}

static int set_frag_threshold(struct usbnet *usbdev, u32 frag_threshold)
{
	__le32 tmp;

1272
	netdev_dbg(usbdev->net, "%s(): %i\n", __func__, frag_threshold);
1273
1274
1275
1276
1277
1278
1279
1280
1281

	if (frag_threshold < 256 || frag_threshold > 2346)
		frag_threshold = 2346;

	tmp = cpu_to_le32(frag_threshold);
	return rndis_set_oid(usbdev, OID_802_11_FRAGMENTATION_THRESHOLD, &tmp,
								sizeof(tmp));
}

1282
1283
static void set_default_iw_params(struct usbnet *usbdev)
{
1284
	set_infra_mode(usbdev, NDIS_80211_INFRA_INFRA);
1285
1286
	set_auth_mode(usbdev, 0, NL80211_AUTHTYPE_OPEN_SYSTEM,
						RNDIS_WLAN_KEY_MGMT_NONE);
1287
	set_priv_filter(usbdev);
1288
	set_encr_mode(usbdev, RNDIS_WLAN_ALG_NONE, RNDIS_WLAN_ALG_NONE);
1289
1290
1291
1292
1293
1294
}

static int deauthenticate(struct usbnet *usbdev)
{
	int ret;

1295
	ret = disassociate(usbdev, true);
1296
1297
1298
1299
	set_default_iw_params(usbdev);
	return ret;
}

1300
1301
1302
1303
1304
1305
static int set_channel(struct usbnet *usbdev, int channel)
{
	struct ndis_80211_conf config;
	unsigned int dsconfig;
	int len, ret;

1306
	netdev_dbg(usbdev->net, "%s(%d)\n", __func__, channel);
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316

	/* this OID is valid only when not associated */
	if (is_associated(usbdev))
		return 0;

	dsconfig = ieee80211_dsss_chan_to_freq(channel) * 1000;

	len = sizeof(config);
	ret = rndis_query_oid(usbdev, OID_802_11_CONFIGURATION, &config, &len);
	if (ret < 0) {
1317
1318
		netdev_dbg(usbdev->net, "%s(): querying configuration failed\n",
			   __func__);
1319
1320
1321
1322
1323
1324
1325
		return ret;
	}

	config.ds_config = cpu_to_le32(dsconfig);
	ret = rndis_set_oid(usbdev, OID_802_11_CONFIGURATION, &config,
								sizeof(config));

1326
	netdev_dbg(usbdev->net, "%s(): %d -> %d\n", __func__, channel, ret);
Jussi Kivilinna's avatar