aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/rndis_wlan.c
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2008-06-14 20:15:39 -0400
committerDavid S. Miller <davem@davemloft.net>2008-06-14 20:15:39 -0400
commit942e7b102a4827fdb69a39c7f07c544542589ef9 (patch)
tree4c47174c91eb76aaa31abc141adbee1acc649987 /drivers/net/wireless/rndis_wlan.c
parent7d06b2e053d2d536348e3a0f6bb02982a41bea37 (diff)
parent87291c0269e77b029282676448fed3706a54211a (diff)
Merge branch 'master' of master.kernel.org:/pub/scm/linux/kernel/git/linville/wireless-next-2.6
Diffstat (limited to 'drivers/net/wireless/rndis_wlan.c')
-rw-r--r--drivers/net/wireless/rndis_wlan.c167
1 files changed, 95 insertions, 72 deletions
diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c
index 3954897d0678..a36d2c85e26e 100644
--- a/drivers/net/wireless/rndis_wlan.c
+++ b/drivers/net/wireless/rndis_wlan.c
@@ -310,8 +310,11 @@ enum wpa_key_mgmt { KEY_MGMT_802_1X, KEY_MGMT_PSK, KEY_MGMT_NONE,
310#define CAP_MODE_MASK 7 310#define CAP_MODE_MASK 7
311#define CAP_SUPPORT_TXPOWER 8 311#define CAP_SUPPORT_TXPOWER 8
312 312
313#define WORK_CONNECTION_EVENT (1<<0) 313#define WORK_LINK_UP (1<<0)
314#define WORK_SET_MULTICAST_LIST (1<<1) 314#define WORK_LINK_DOWN (1<<1)
315#define WORK_SET_MULTICAST_LIST (1<<2)
316
317#define COMMAND_BUFFER_SIZE (CONTROL_BUFFER_SIZE + sizeof(struct rndis_set))
315 318
316/* RNDIS device private data */ 319/* RNDIS device private data */
317struct rndis_wext_private { 320struct rndis_wext_private {
@@ -361,6 +364,8 @@ struct rndis_wext_private {
361 u8 *wpa_ie; 364 u8 *wpa_ie;
362 int wpa_cipher_pair; 365 int wpa_cipher_pair;
363 int wpa_cipher_group; 366 int wpa_cipher_group;
367
368 u8 command_buffer[COMMAND_BUFFER_SIZE];
364}; 369};
365 370
366 371
@@ -427,18 +432,23 @@ static int rndis_query_oid(struct usbnet *dev, __le32 oid, void *data, int *len)
427 buflen = *len + sizeof(*u.get); 432 buflen = *len + sizeof(*u.get);
428 if (buflen < CONTROL_BUFFER_SIZE) 433 if (buflen < CONTROL_BUFFER_SIZE)
429 buflen = CONTROL_BUFFER_SIZE; 434 buflen = CONTROL_BUFFER_SIZE;
430 u.buf = kmalloc(buflen, GFP_KERNEL); 435
431 if (!u.buf) 436 if (buflen > COMMAND_BUFFER_SIZE) {
432 return -ENOMEM; 437 u.buf = kmalloc(buflen, GFP_KERNEL);
438 if (!u.buf)
439 return -ENOMEM;
440 } else {
441 u.buf = priv->command_buffer;
442 }
443
444 mutex_lock(&priv->command_lock);
445
433 memset(u.get, 0, sizeof *u.get); 446 memset(u.get, 0, sizeof *u.get);
434 u.get->msg_type = RNDIS_MSG_QUERY; 447 u.get->msg_type = RNDIS_MSG_QUERY;
435 u.get->msg_len = ccpu2(sizeof *u.get); 448 u.get->msg_len = ccpu2(sizeof *u.get);
436 u.get->oid = oid; 449 u.get->oid = oid;
437 450
438 mutex_lock(&priv->command_lock);
439 ret = rndis_command(dev, u.header); 451 ret = rndis_command(dev, u.header);
440 mutex_unlock(&priv->command_lock);
441
442 if (ret == 0) { 452 if (ret == 0) {
443 ret = le32_to_cpu(u.get_c->len); 453 ret = le32_to_cpu(u.get_c->len);
444 *len = (*len > ret) ? ret : *len; 454 *len = (*len > ret) ? ret : *len;
@@ -446,7 +456,10 @@ static int rndis_query_oid(struct usbnet *dev, __le32 oid, void *data, int *len)
446 ret = rndis_error_status(u.get_c->status); 456 ret = rndis_error_status(u.get_c->status);
447 } 457 }
448 458
449 kfree(u.buf); 459 mutex_unlock(&priv->command_lock);
460
461 if (u.buf != priv->command_buffer)
462 kfree(u.buf);
450 return ret; 463 return ret;
451} 464}
452 465
@@ -465,9 +478,16 @@ static int rndis_set_oid(struct usbnet *dev, __le32 oid, void *data, int len)
465 buflen = len + sizeof(*u.set); 478 buflen = len + sizeof(*u.set);
466 if (buflen < CONTROL_BUFFER_SIZE) 479 if (buflen < CONTROL_BUFFER_SIZE)
467 buflen = CONTROL_BUFFER_SIZE; 480 buflen = CONTROL_BUFFER_SIZE;
468 u.buf = kmalloc(buflen, GFP_KERNEL); 481
469 if (!u.buf) 482 if (buflen > COMMAND_BUFFER_SIZE) {
470 return -ENOMEM; 483 u.buf = kmalloc(buflen, GFP_KERNEL);
484 if (!u.buf)
485 return -ENOMEM;
486 } else {
487 u.buf = priv->command_buffer;
488 }
489
490 mutex_lock(&priv->command_lock);
471 491
472 memset(u.set, 0, sizeof *u.set); 492 memset(u.set, 0, sizeof *u.set);
473 u.set->msg_type = RNDIS_MSG_SET; 493 u.set->msg_type = RNDIS_MSG_SET;
@@ -478,14 +498,14 @@ static int rndis_set_oid(struct usbnet *dev, __le32 oid, void *data, int len)
478 u.set->handle = ccpu2(0); 498 u.set->handle = ccpu2(0);
479 memcpy(u.buf + sizeof(*u.set), data, len); 499 memcpy(u.buf + sizeof(*u.set), data, len);
480 500
481 mutex_lock(&priv->command_lock);
482 ret = rndis_command(dev, u.header); 501 ret = rndis_command(dev, u.header);
483 mutex_unlock(&priv->command_lock);
484
485 if (ret == 0) 502 if (ret == 0)
486 ret = rndis_error_status(u.set_c->status); 503 ret = rndis_error_status(u.set_c->status);
487 504
488 kfree(u.buf); 505 mutex_unlock(&priv->command_lock);
506
507 if (u.buf != priv->command_buffer)
508 kfree(u.buf);
489 return ret; 509 return ret;
490} 510}
491 511
@@ -620,8 +640,7 @@ static void dsconfig_to_freq(unsigned int dsconfig, struct iw_freq *freq)
620static int freq_to_dsconfig(struct iw_freq *freq, unsigned int *dsconfig) 640static int freq_to_dsconfig(struct iw_freq *freq, unsigned int *dsconfig)
621{ 641{
622 if (freq->m < 1000 && freq->e == 0) { 642 if (freq->m < 1000 && freq->e == 0) {
623 if (freq->m >= 1 && 643 if (freq->m >= 1 && freq->m <= ARRAY_SIZE(freq_chan))
624 freq->m <= (sizeof(freq_chan) / sizeof(freq_chan[0])))
625 *dsconfig = freq_chan[freq->m - 1] * 1000; 644 *dsconfig = freq_chan[freq->m - 1] * 1000;
626 else 645 else
627 return -1; 646 return -1;
@@ -1159,10 +1178,9 @@ static int rndis_iw_get_range(struct net_device *dev,
1159 range->throughput = 11 * 1000 * 1000 / 2; 1178 range->throughput = 11 * 1000 * 1000 / 2;
1160 } 1179 }
1161 1180
1162 range->num_channels = (sizeof(freq_chan)/sizeof(freq_chan[0])); 1181 range->num_channels = ARRAY_SIZE(freq_chan);
1163 1182
1164 for (i = 0; i < (sizeof(freq_chan)/sizeof(freq_chan[0])) && 1183 for (i = 0; i < ARRAY_SIZE(freq_chan) && i < IW_MAX_FREQUENCIES; i++) {
1165 i < IW_MAX_FREQUENCIES; i++) {
1166 range->freq[i].i = i + 1; 1184 range->freq[i].i = i + 1;
1167 range->freq[i].m = freq_chan[i] * 100000; 1185 range->freq[i].m = freq_chan[i] * 100000;
1168 range->freq[i].e = 1; 1186 range->freq[i].e = 1;
@@ -2213,7 +2231,9 @@ static void rndis_wext_worker(struct work_struct *work)
2213 int assoc_size = sizeof(*info) + IW_CUSTOM_MAX + 32; 2231 int assoc_size = sizeof(*info) + IW_CUSTOM_MAX + 32;
2214 int ret, offset; 2232 int ret, offset;
2215 2233
2216 if (test_and_clear_bit(WORK_CONNECTION_EVENT, &priv->work_pending)) { 2234 if (test_and_clear_bit(WORK_LINK_UP, &priv->work_pending)) {
2235 netif_carrier_on(usbdev->net);
2236
2217 info = kzalloc(assoc_size, GFP_KERNEL); 2237 info = kzalloc(assoc_size, GFP_KERNEL);
2218 if (!info) 2238 if (!info)
2219 goto get_bssid; 2239 goto get_bssid;
@@ -2251,6 +2271,15 @@ get_bssid:
2251 } 2271 }
2252 } 2272 }
2253 2273
2274 if (test_and_clear_bit(WORK_LINK_DOWN, &priv->work_pending)) {
2275 netif_carrier_off(usbdev->net);
2276
2277 evt.data.flags = 0;
2278 evt.data.length = 0;
2279 memset(evt.ap_addr.sa_data, 0, ETH_ALEN);
2280 wireless_send_event(usbdev->net, SIOCGIWAP, &evt, NULL);
2281 }
2282
2254 if (test_and_clear_bit(WORK_SET_MULTICAST_LIST, &priv->work_pending)) 2283 if (test_and_clear_bit(WORK_SET_MULTICAST_LIST, &priv->work_pending))
2255 set_multicast_list(usbdev); 2284 set_multicast_list(usbdev);
2256} 2285}
@@ -2260,29 +2289,24 @@ static void rndis_wext_set_multicast_list(struct net_device *dev)
2260 struct usbnet *usbdev = dev->priv; 2289 struct usbnet *usbdev = dev->priv;
2261 struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev); 2290 struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev);
2262 2291
2292 if (test_bit(WORK_SET_MULTICAST_LIST, &priv->work_pending))
2293 return;
2294
2263 set_bit(WORK_SET_MULTICAST_LIST, &priv->work_pending); 2295 set_bit(WORK_SET_MULTICAST_LIST, &priv->work_pending);
2264 queue_work(priv->workqueue, &priv->work); 2296 queue_work(priv->workqueue, &priv->work);
2265} 2297}
2266 2298
2267static void rndis_wext_link_change(struct usbnet *dev, int state) 2299static void rndis_wext_link_change(struct usbnet *usbdev, int state)
2268{ 2300{
2269 struct rndis_wext_private *priv = get_rndis_wext_priv(dev); 2301 struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev);
2270 union iwreq_data evt;
2271 2302
2272 if (state) { 2303 /* queue work to avoid recursive calls into rndis_command */
2273 /* queue work to avoid recursive calls into rndis_command */ 2304 set_bit(state ? WORK_LINK_UP : WORK_LINK_DOWN, &priv->work_pending);
2274 set_bit(WORK_CONNECTION_EVENT, &priv->work_pending); 2305 queue_work(priv->workqueue, &priv->work);
2275 queue_work(priv->workqueue, &priv->work);
2276 } else {
2277 evt.data.flags = 0;
2278 evt.data.length = 0;
2279 memset(evt.ap_addr.sa_data, 0, ETH_ALEN);
2280 wireless_send_event(dev->net, SIOCGIWAP, &evt, NULL);
2281 }
2282} 2306}
2283 2307
2284 2308
2285static int rndis_wext_get_caps(struct usbnet *dev) 2309static int rndis_wext_get_caps(struct usbnet *usbdev)
2286{ 2310{
2287 struct { 2311 struct {
2288 __le32 num_items; 2312 __le32 num_items;
@@ -2290,18 +2314,18 @@ static int rndis_wext_get_caps(struct usbnet *dev)
2290 } networks_supported; 2314 } networks_supported;
2291 int len, retval, i, n; 2315 int len, retval, i, n;
2292 __le32 tx_power; 2316 __le32 tx_power;
2293 struct rndis_wext_private *priv = get_rndis_wext_priv(dev); 2317 struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev);
2294 2318
2295 /* determine if supports setting txpower */ 2319 /* determine if supports setting txpower */
2296 len = sizeof(tx_power); 2320 len = sizeof(tx_power);
2297 retval = rndis_query_oid(dev, OID_802_11_TX_POWER_LEVEL, &tx_power, 2321 retval = rndis_query_oid(usbdev, OID_802_11_TX_POWER_LEVEL, &tx_power,
2298 &len); 2322 &len);
2299 if (retval == 0 && le32_to_cpu(tx_power) != 0xFF) 2323 if (retval == 0 && le32_to_cpu(tx_power) != 0xFF)
2300 priv->caps |= CAP_SUPPORT_TXPOWER; 2324 priv->caps |= CAP_SUPPORT_TXPOWER;
2301 2325
2302 /* determine supported modes */ 2326 /* determine supported modes */
2303 len = sizeof(networks_supported); 2327 len = sizeof(networks_supported);
2304 retval = rndis_query_oid(dev, OID_802_11_NETWORK_TYPES_SUPPORTED, 2328 retval = rndis_query_oid(usbdev, OID_802_11_NETWORK_TYPES_SUPPORTED,
2305 &networks_supported, &len); 2329 &networks_supported, &len);
2306 if (retval >= 0) { 2330 if (retval >= 0) {
2307 n = le32_to_cpu(networks_supported.num_items); 2331 n = le32_to_cpu(networks_supported.num_items);
@@ -2440,9 +2464,9 @@ end:
2440} 2464}
2441 2465
2442 2466
2443static int bcm4320_early_init(struct usbnet *dev) 2467static int bcm4320_early_init(struct usbnet *usbdev)
2444{ 2468{
2445 struct rndis_wext_private *priv = get_rndis_wext_priv(dev); 2469 struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev);
2446 char buf[8]; 2470 char buf[8];
2447 2471
2448 /* Early initialization settings, setting these won't have effect 2472 /* Early initialization settings, setting these won't have effect
@@ -2490,51 +2514,48 @@ static int bcm4320_early_init(struct usbnet *dev)
2490 else 2514 else
2491 priv->param_workaround_interval = modparam_workaround_interval; 2515 priv->param_workaround_interval = modparam_workaround_interval;
2492 2516
2493 rndis_set_config_parameter_str(dev, "Country", priv->param_country); 2517 rndis_set_config_parameter_str(usbdev, "Country", priv->param_country);
2494 rndis_set_config_parameter_str(dev, "FrameBursting", 2518 rndis_set_config_parameter_str(usbdev, "FrameBursting",
2495 priv->param_frameburst ? "1" : "0"); 2519 priv->param_frameburst ? "1" : "0");
2496 rndis_set_config_parameter_str(dev, "Afterburner", 2520 rndis_set_config_parameter_str(usbdev, "Afterburner",
2497 priv->param_afterburner ? "1" : "0"); 2521 priv->param_afterburner ? "1" : "0");
2498 sprintf(buf, "%d", priv->param_power_save); 2522 sprintf(buf, "%d", priv->param_power_save);
2499 rndis_set_config_parameter_str(dev, "PowerSaveMode", buf); 2523 rndis_set_config_parameter_str(usbdev, "PowerSaveMode", buf);
2500 sprintf(buf, "%d", priv->param_power_output); 2524 sprintf(buf, "%d", priv->param_power_output);
2501 rndis_set_config_parameter_str(dev, "PwrOut", buf); 2525 rndis_set_config_parameter_str(usbdev, "PwrOut", buf);
2502 sprintf(buf, "%d", priv->param_roamtrigger); 2526 sprintf(buf, "%d", priv->param_roamtrigger);
2503 rndis_set_config_parameter_str(dev, "RoamTrigger", buf); 2527 rndis_set_config_parameter_str(usbdev, "RoamTrigger", buf);
2504 sprintf(buf, "%d", priv->param_roamdelta); 2528 sprintf(buf, "%d", priv->param_roamdelta);
2505 rndis_set_config_parameter_str(dev, "RoamDelta", buf); 2529 rndis_set_config_parameter_str(usbdev, "RoamDelta", buf);
2506 2530
2507 return 0; 2531 return 0;
2508} 2532}
2509 2533
2510 2534
2511static int rndis_wext_bind(struct usbnet *dev, struct usb_interface *intf) 2535static int rndis_wext_bind(struct usbnet *usbdev, struct usb_interface *intf)
2512{ 2536{
2513 struct net_device *net = dev->net;
2514 struct rndis_wext_private *priv; 2537 struct rndis_wext_private *priv;
2515 int retval, len; 2538 int retval, len;
2516 __le32 tmp; 2539 __le32 tmp;
2517 2540
2518 /* allocate rndis private data */ 2541 /* allocate rndis private data */
2519 priv = kmalloc(sizeof(struct rndis_wext_private), GFP_KERNEL); 2542 priv = kzalloc(sizeof(struct rndis_wext_private), GFP_KERNEL);
2520 if (!priv) 2543 if (!priv)
2521 return -ENOMEM; 2544 return -ENOMEM;
2522 2545
2523 /* These have to be initialized before calling generic_rndis_bind(). 2546 /* These have to be initialized before calling generic_rndis_bind().
2524 * Otherwise we'll be in big trouble in rndis_wext_early_init(). 2547 * Otherwise we'll be in big trouble in rndis_wext_early_init().
2525 */ 2548 */
2526 dev->driver_priv = priv; 2549 usbdev->driver_priv = priv;
2527 memset(priv, 0, sizeof(*priv));
2528 memset(priv->name, 0, sizeof(priv->name));
2529 strcpy(priv->name, "IEEE802.11"); 2550 strcpy(priv->name, "IEEE802.11");
2530 net->wireless_handlers = &rndis_iw_handlers; 2551 usbdev->net->wireless_handlers = &rndis_iw_handlers;
2531 priv->usbdev = dev; 2552 priv->usbdev = usbdev;
2532 2553
2533 mutex_init(&priv->command_lock); 2554 mutex_init(&priv->command_lock);
2534 spin_lock_init(&priv->stats_lock); 2555 spin_lock_init(&priv->stats_lock);
2535 2556
2536 /* try bind rndis_host */ 2557 /* try bind rndis_host */
2537 retval = generic_rndis_bind(dev, intf, FLAG_RNDIS_PHYM_WIRELESS); 2558 retval = generic_rndis_bind(usbdev, intf, FLAG_RNDIS_PHYM_WIRELESS);
2538 if (retval < 0) 2559 if (retval < 0)
2539 goto fail; 2560 goto fail;
2540 2561
@@ -2545,20 +2566,21 @@ static int rndis_wext_bind(struct usbnet *dev, struct usb_interface *intf)
2545 * rndis_host wants to avoid all OID as much as possible 2566 * rndis_host wants to avoid all OID as much as possible
2546 * so do promisc/multicast handling in rndis_wext. 2567 * so do promisc/multicast handling in rndis_wext.
2547 */ 2568 */
2548 dev->net->set_multicast_list = rndis_wext_set_multicast_list; 2569 usbdev->net->set_multicast_list = rndis_wext_set_multicast_list;
2549 tmp = RNDIS_PACKET_TYPE_DIRECTED | RNDIS_PACKET_TYPE_BROADCAST; 2570 tmp = RNDIS_PACKET_TYPE_DIRECTED | RNDIS_PACKET_TYPE_BROADCAST;
2550 retval = rndis_set_oid(dev, OID_GEN_CURRENT_PACKET_FILTER, &tmp, 2571 retval = rndis_set_oid(usbdev, OID_GEN_CURRENT_PACKET_FILTER, &tmp,
2551 sizeof(tmp)); 2572 sizeof(tmp));
2552 2573
2553 len = sizeof(tmp); 2574 len = sizeof(tmp);
2554 retval = rndis_query_oid(dev, OID_802_3_MAXIMUM_LIST_SIZE, &tmp, &len); 2575 retval = rndis_query_oid(usbdev, OID_802_3_MAXIMUM_LIST_SIZE, &tmp,
2576 &len);
2555 priv->multicast_size = le32_to_cpu(tmp); 2577 priv->multicast_size = le32_to_cpu(tmp);
2556 if (retval < 0 || priv->multicast_size < 0) 2578 if (retval < 0 || priv->multicast_size < 0)
2557 priv->multicast_size = 0; 2579 priv->multicast_size = 0;
2558 if (priv->multicast_size > 0) 2580 if (priv->multicast_size > 0)
2559 dev->net->flags |= IFF_MULTICAST; 2581 usbdev->net->flags |= IFF_MULTICAST;
2560 else 2582 else
2561 dev->net->flags &= ~IFF_MULTICAST; 2583 usbdev->net->flags &= ~IFF_MULTICAST;
2562 2584
2563 priv->iwstats.qual.qual = 0; 2585 priv->iwstats.qual.qual = 0;
2564 priv->iwstats.qual.level = 0; 2586 priv->iwstats.qual.level = 0;
@@ -2568,12 +2590,13 @@ static int rndis_wext_bind(struct usbnet *dev, struct usb_interface *intf)
2568 | IW_QUAL_QUAL_INVALID 2590 | IW_QUAL_QUAL_INVALID
2569 | IW_QUAL_LEVEL_INVALID; 2591 | IW_QUAL_LEVEL_INVALID;
2570 2592
2571 rndis_wext_get_caps(dev); 2593 rndis_wext_get_caps(usbdev);
2572 set_default_iw_params(dev); 2594 set_default_iw_params(usbdev);
2573 2595
2574 /* turn radio on */ 2596 /* turn radio on */
2575 priv->radio_on = 1; 2597 priv->radio_on = 1;
2576 disassociate(dev, 1); 2598 disassociate(usbdev, 1);
2599 netif_carrier_off(usbdev->net);
2577 2600
2578 /* because rndis_command() sleeps we need to use workqueue */ 2601 /* because rndis_command() sleeps we need to use workqueue */
2579 priv->workqueue = create_singlethread_workqueue("rndis_wlan"); 2602 priv->workqueue = create_singlethread_workqueue("rndis_wlan");
@@ -2590,12 +2613,12 @@ fail:
2590} 2613}
2591 2614
2592 2615
2593static void rndis_wext_unbind(struct usbnet *dev, struct usb_interface *intf) 2616static void rndis_wext_unbind(struct usbnet *usbdev, struct usb_interface *intf)
2594{ 2617{
2595 struct rndis_wext_private *priv = get_rndis_wext_priv(dev); 2618 struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev);
2596 2619
2597 /* turn radio off */ 2620 /* turn radio off */
2598 disassociate(dev, 0); 2621 disassociate(usbdev, 0);
2599 2622
2600 cancel_delayed_work_sync(&priv->stats_work); 2623 cancel_delayed_work_sync(&priv->stats_work);
2601 cancel_work_sync(&priv->work); 2624 cancel_work_sync(&priv->work);
@@ -2606,13 +2629,13 @@ static void rndis_wext_unbind(struct usbnet *dev, struct usb_interface *intf)
2606 kfree(priv->wpa_ie); 2629 kfree(priv->wpa_ie);
2607 kfree(priv); 2630 kfree(priv);
2608 2631
2609 rndis_unbind(dev, intf); 2632 rndis_unbind(usbdev, intf);
2610} 2633}
2611 2634
2612 2635
2613static int rndis_wext_reset(struct usbnet *dev) 2636static int rndis_wext_reset(struct usbnet *usbdev)
2614{ 2637{
2615 return deauthenticate(dev); 2638 return deauthenticate(usbdev);
2616} 2639}
2617 2640
2618 2641