diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/net/wireless/rndis_wlan.c | 114 |
1 files changed, 85 insertions, 29 deletions
diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c index db91db776508..c995d7c3139c 100644 --- a/drivers/net/wireless/rndis_wlan.c +++ b/drivers/net/wireless/rndis_wlan.c | |||
@@ -42,6 +42,8 @@ | |||
42 | #include <linux/ctype.h> | 42 | #include <linux/ctype.h> |
43 | #include <linux/spinlock.h> | 43 | #include <linux/spinlock.h> |
44 | #include <net/iw_handler.h> | 44 | #include <net/iw_handler.h> |
45 | #include <net/wireless.h> | ||
46 | #include <net/cfg80211.h> | ||
45 | #include <linux/usb/usbnet.h> | 47 | #include <linux/usb/usbnet.h> |
46 | #include <linux/usb/rndis_host.h> | 48 | #include <linux/usb/rndis_host.h> |
47 | 49 | ||
@@ -316,12 +318,44 @@ enum wpa_key_mgmt { KEY_MGMT_802_1X, KEY_MGMT_PSK, KEY_MGMT_NONE, | |||
316 | 318 | ||
317 | #define COMMAND_BUFFER_SIZE (CONTROL_BUFFER_SIZE + sizeof(struct rndis_set)) | 319 | #define COMMAND_BUFFER_SIZE (CONTROL_BUFFER_SIZE + sizeof(struct rndis_set)) |
318 | 320 | ||
321 | static const struct ieee80211_channel rndis_channels[] = { | ||
322 | { .center_freq = 2412 }, | ||
323 | { .center_freq = 2417 }, | ||
324 | { .center_freq = 2422 }, | ||
325 | { .center_freq = 2427 }, | ||
326 | { .center_freq = 2432 }, | ||
327 | { .center_freq = 2437 }, | ||
328 | { .center_freq = 2442 }, | ||
329 | { .center_freq = 2447 }, | ||
330 | { .center_freq = 2452 }, | ||
331 | { .center_freq = 2457 }, | ||
332 | { .center_freq = 2462 }, | ||
333 | { .center_freq = 2467 }, | ||
334 | { .center_freq = 2472 }, | ||
335 | { .center_freq = 2484 }, | ||
336 | }; | ||
337 | |||
338 | static const struct ieee80211_rate rndis_rates[] = { | ||
339 | { .bitrate = 10 }, | ||
340 | { .bitrate = 20, .flags = IEEE80211_RATE_SHORT_PREAMBLE }, | ||
341 | { .bitrate = 55, .flags = IEEE80211_RATE_SHORT_PREAMBLE }, | ||
342 | { .bitrate = 110, .flags = IEEE80211_RATE_SHORT_PREAMBLE }, | ||
343 | { .bitrate = 60 }, | ||
344 | { .bitrate = 90 }, | ||
345 | { .bitrate = 120 }, | ||
346 | { .bitrate = 180 }, | ||
347 | { .bitrate = 240 }, | ||
348 | { .bitrate = 360 }, | ||
349 | { .bitrate = 480 }, | ||
350 | { .bitrate = 540 } | ||
351 | }; | ||
352 | |||
319 | /* RNDIS device private data */ | 353 | /* RNDIS device private data */ |
320 | struct rndis_wext_private { | 354 | struct rndis_wext_private { |
321 | char name[32]; | ||
322 | |||
323 | struct usbnet *usbdev; | 355 | struct usbnet *usbdev; |
324 | 356 | ||
357 | struct wireless_dev wdev; | ||
358 | |||
325 | struct workqueue_struct *workqueue; | 359 | struct workqueue_struct *workqueue; |
326 | struct delayed_work stats_work; | 360 | struct delayed_work stats_work; |
327 | struct work_struct work; | 361 | struct work_struct work; |
@@ -329,6 +363,10 @@ struct rndis_wext_private { | |||
329 | spinlock_t stats_lock; | 363 | spinlock_t stats_lock; |
330 | unsigned long work_pending; | 364 | unsigned long work_pending; |
331 | 365 | ||
366 | struct ieee80211_supported_band band; | ||
367 | struct ieee80211_channel channels[ARRAY_SIZE(rndis_channels)]; | ||
368 | struct ieee80211_rate rates[ARRAY_SIZE(rndis_rates)]; | ||
369 | |||
332 | struct iw_statistics iwstats; | 370 | struct iw_statistics iwstats; |
333 | struct iw_statistics privstats; | 371 | struct iw_statistics privstats; |
334 | 372 | ||
@@ -369,7 +407,8 @@ struct rndis_wext_private { | |||
369 | }; | 407 | }; |
370 | 408 | ||
371 | 409 | ||
372 | static const int rates_80211g[8] = { 6, 9, 12, 18, 24, 36, 48, 54 }; | 410 | struct cfg80211_ops rndis_config_ops = { }; |
411 | void *rndis_wiphy_privid = &rndis_wiphy_privid; | ||
373 | 412 | ||
374 | static const int bcm4320_power_output[4] = { 25, 50, 75, 100 }; | 413 | static const int bcm4320_power_output[4] = { 25, 50, 75, 100 }; |
375 | 414 | ||
@@ -1151,15 +1190,15 @@ static int rndis_iw_get_range(struct net_device *dev, | |||
1151 | /* fill in 802.11g rates */ | 1190 | /* fill in 802.11g rates */ |
1152 | if (has_80211g_rates) { | 1191 | if (has_80211g_rates) { |
1153 | num = range->num_bitrates; | 1192 | num = range->num_bitrates; |
1154 | for (i = 0; i < ARRAY_SIZE(rates_80211g); i++) { | 1193 | for (i = 4; i < ARRAY_SIZE(rndis_rates); i++) { |
1155 | for (j = 0; j < num; j++) { | 1194 | for (j = 0; j < num; j++) { |
1156 | if (range->bitrate[j] == | 1195 | if (range->bitrate[j] == |
1157 | rates_80211g[i] * 1000000) | 1196 | rndis_rates[i].bitrate * 100000) |
1158 | break; | 1197 | break; |
1159 | } | 1198 | } |
1160 | if (j == num) | 1199 | if (j == num) |
1161 | range->bitrate[range->num_bitrates++] = | 1200 | range->bitrate[range->num_bitrates++] = |
1162 | rates_80211g[i] * 1000000; | 1201 | rndis_rates[i].bitrate * 100000; |
1163 | if (range->num_bitrates == IW_MAX_BITRATES) | 1202 | if (range->num_bitrates == IW_MAX_BITRATES) |
1164 | break; | 1203 | break; |
1165 | } | 1204 | } |
@@ -1204,17 +1243,6 @@ static int rndis_iw_get_range(struct net_device *dev, | |||
1204 | } | 1243 | } |
1205 | 1244 | ||
1206 | 1245 | ||
1207 | static int rndis_iw_get_name(struct net_device *dev, | ||
1208 | struct iw_request_info *info, union iwreq_data *wrqu, char *extra) | ||
1209 | { | ||
1210 | struct usbnet *usbdev = netdev_priv(dev); | ||
1211 | struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev); | ||
1212 | |||
1213 | strcpy(wrqu->name, priv->name); | ||
1214 | return 0; | ||
1215 | } | ||
1216 | |||
1217 | |||
1218 | static int rndis_iw_set_essid(struct net_device *dev, | 1246 | static int rndis_iw_set_essid(struct net_device *dev, |
1219 | struct iw_request_info *info, union iwreq_data *wrqu, char *essid) | 1247 | struct iw_request_info *info, union iwreq_data *wrqu, char *essid) |
1220 | { | 1248 | { |
@@ -2165,7 +2193,7 @@ static struct iw_statistics *rndis_get_wireless_stats(struct net_device *dev) | |||
2165 | static const iw_handler rndis_iw_handler[] = | 2193 | static const iw_handler rndis_iw_handler[] = |
2166 | { | 2194 | { |
2167 | IW_IOCTL(SIOCSIWCOMMIT) = rndis_iw_commit, | 2195 | IW_IOCTL(SIOCSIWCOMMIT) = rndis_iw_commit, |
2168 | IW_IOCTL(SIOCGIWNAME) = rndis_iw_get_name, | 2196 | IW_IOCTL(SIOCGIWNAME) = (iw_handler) cfg80211_wext_giwname, |
2169 | IW_IOCTL(SIOCSIWFREQ) = rndis_iw_set_freq, | 2197 | IW_IOCTL(SIOCSIWFREQ) = rndis_iw_set_freq, |
2170 | IW_IOCTL(SIOCGIWFREQ) = rndis_iw_get_freq, | 2198 | IW_IOCTL(SIOCGIWFREQ) = rndis_iw_get_freq, |
2171 | IW_IOCTL(SIOCSIWMODE) = rndis_iw_set_mode, | 2199 | IW_IOCTL(SIOCSIWMODE) = rndis_iw_set_mode, |
@@ -2338,12 +2366,6 @@ static int rndis_wext_get_caps(struct usbnet *usbdev) | |||
2338 | break; | 2366 | break; |
2339 | } | 2367 | } |
2340 | } | 2368 | } |
2341 | if (priv->caps & CAP_MODE_80211A) | ||
2342 | strcat(priv->name, "a"); | ||
2343 | if (priv->caps & CAP_MODE_80211B) | ||
2344 | strcat(priv->name, "b"); | ||
2345 | if (priv->caps & CAP_MODE_80211G) | ||
2346 | strcat(priv->name, "g"); | ||
2347 | } | 2369 | } |
2348 | 2370 | ||
2349 | return retval; | 2371 | return retval; |
@@ -2538,20 +2560,28 @@ static const struct net_device_ops rndis_wext_netdev_ops = { | |||
2538 | 2560 | ||
2539 | static int rndis_wext_bind(struct usbnet *usbdev, struct usb_interface *intf) | 2561 | static int rndis_wext_bind(struct usbnet *usbdev, struct usb_interface *intf) |
2540 | { | 2562 | { |
2563 | struct wiphy *wiphy; | ||
2541 | struct rndis_wext_private *priv; | 2564 | struct rndis_wext_private *priv; |
2542 | int retval, len; | 2565 | int retval, len; |
2543 | __le32 tmp; | 2566 | __le32 tmp; |
2544 | 2567 | ||
2545 | /* allocate rndis private data */ | 2568 | /* allocate wiphy and rndis private data |
2546 | priv = kzalloc(sizeof(struct rndis_wext_private), GFP_KERNEL); | 2569 | * NOTE: We only support a single virtual interface, so wiphy |
2547 | if (!priv) | 2570 | * and wireless_dev are somewhat synonymous for this device. |
2571 | */ | ||
2572 | wiphy = wiphy_new(&rndis_config_ops, sizeof(struct rndis_wext_private)); | ||
2573 | if (!wiphy) | ||
2548 | return -ENOMEM; | 2574 | return -ENOMEM; |
2549 | 2575 | ||
2576 | priv = wiphy_priv(wiphy); | ||
2577 | usbdev->net->ieee80211_ptr = &priv->wdev; | ||
2578 | priv->wdev.wiphy = wiphy; | ||
2579 | priv->wdev.iftype = NL80211_IFTYPE_STATION; | ||
2580 | |||
2550 | /* These have to be initialized before calling generic_rndis_bind(). | 2581 | /* These have to be initialized before calling generic_rndis_bind(). |
2551 | * Otherwise we'll be in big trouble in rndis_wext_early_init(). | 2582 | * Otherwise we'll be in big trouble in rndis_wext_early_init(). |
2552 | */ | 2583 | */ |
2553 | usbdev->driver_priv = priv; | 2584 | usbdev->driver_priv = priv; |
2554 | strcpy(priv->name, "IEEE802.11"); | ||
2555 | usbdev->net->wireless_handlers = &rndis_iw_handlers; | 2585 | usbdev->net->wireless_handlers = &rndis_iw_handlers; |
2556 | priv->usbdev = usbdev; | 2586 | priv->usbdev = usbdev; |
2557 | 2587 | ||
@@ -2595,7 +2625,31 @@ static int rndis_wext_bind(struct usbnet *usbdev, struct usb_interface *intf) | |||
2595 | | IW_QUAL_QUAL_INVALID | 2625 | | IW_QUAL_QUAL_INVALID |
2596 | | IW_QUAL_LEVEL_INVALID; | 2626 | | IW_QUAL_LEVEL_INVALID; |
2597 | 2627 | ||
2628 | /* fill-out wiphy structure and register w/ cfg80211 */ | ||
2629 | memcpy(wiphy->perm_addr, usbdev->net->dev_addr, ETH_ALEN); | ||
2630 | wiphy->privid = rndis_wiphy_privid; | ||
2631 | wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | ||
2632 | | BIT(NL80211_IFTYPE_ADHOC); | ||
2633 | wiphy->max_scan_ssids = 1; | ||
2634 | |||
2635 | /* TODO: fill-out band information based on priv->caps */ | ||
2598 | rndis_wext_get_caps(usbdev); | 2636 | rndis_wext_get_caps(usbdev); |
2637 | |||
2638 | memcpy(priv->channels, rndis_channels, sizeof(rndis_channels)); | ||
2639 | memcpy(priv->rates, rndis_rates, sizeof(rndis_rates)); | ||
2640 | priv->band.channels = priv->channels; | ||
2641 | priv->band.n_channels = ARRAY_SIZE(rndis_channels); | ||
2642 | priv->band.bitrates = priv->rates; | ||
2643 | priv->band.n_bitrates = ARRAY_SIZE(rndis_rates); | ||
2644 | wiphy->bands[IEEE80211_BAND_2GHZ] = &priv->band; | ||
2645 | |||
2646 | set_wiphy_dev(wiphy, &usbdev->udev->dev); | ||
2647 | |||
2648 | if (wiphy_register(wiphy)) { | ||
2649 | wiphy_free(wiphy); | ||
2650 | return -ENODEV; | ||
2651 | } | ||
2652 | |||
2599 | set_default_iw_params(usbdev); | 2653 | set_default_iw_params(usbdev); |
2600 | 2654 | ||
2601 | /* turn radio on */ | 2655 | /* turn radio on */ |
@@ -2632,9 +2686,11 @@ static void rndis_wext_unbind(struct usbnet *usbdev, struct usb_interface *intf) | |||
2632 | 2686 | ||
2633 | if (priv && priv->wpa_ie_len) | 2687 | if (priv && priv->wpa_ie_len) |
2634 | kfree(priv->wpa_ie); | 2688 | kfree(priv->wpa_ie); |
2635 | kfree(priv); | ||
2636 | 2689 | ||
2637 | rndis_unbind(usbdev, intf); | 2690 | rndis_unbind(usbdev, intf); |
2691 | |||
2692 | wiphy_unregister(priv->wdev.wiphy); | ||
2693 | wiphy_free(priv->wdev.wiphy); | ||
2638 | } | 2694 | } |
2639 | 2695 | ||
2640 | 2696 | ||