diff options
author | Jussi Kivilinna <jussi.kivilinna@mbnet.fi> | 2009-08-28 06:28:03 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2009-08-28 14:40:59 -0400 |
commit | 8b89a2883be4b6bad8ac0c5928784febb2b34172 (patch) | |
tree | b05da4e342dbab77e5d74315e94ac777850f9ea7 | |
parent | 84bf8400cee127be3b58a9d9b8cfa453dad999ab (diff) |
rndis_wlan: add cfg80211 get_station
Add cfg80211 get_station and convert SIOCGIWRATE and get_wireless_stats
to cfg80211.
Signed-off-by: Jussi Kivilinna <jussi.kivilinna@mbnet.fi>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
-rw-r--r-- | drivers/net/wireless/rndis_wlan.c | 118 |
1 files changed, 57 insertions, 61 deletions
diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c index 93b504bc2dc5..061bfec14a9c 100644 --- a/drivers/net/wireless/rndis_wlan.c +++ b/drivers/net/wireless/rndis_wlan.c | |||
@@ -444,17 +444,14 @@ struct rndis_wlan_private { | |||
444 | struct delayed_work scan_work; | 444 | struct delayed_work scan_work; |
445 | struct work_struct work; | 445 | struct work_struct work; |
446 | struct mutex command_lock; | 446 | struct mutex command_lock; |
447 | spinlock_t stats_lock; | ||
448 | unsigned long work_pending; | 447 | unsigned long work_pending; |
448 | int last_qual; | ||
449 | 449 | ||
450 | struct ieee80211_supported_band band; | 450 | struct ieee80211_supported_band band; |
451 | struct ieee80211_channel channels[ARRAY_SIZE(rndis_channels)]; | 451 | struct ieee80211_channel channels[ARRAY_SIZE(rndis_channels)]; |
452 | struct ieee80211_rate rates[ARRAY_SIZE(rndis_rates)]; | 452 | struct ieee80211_rate rates[ARRAY_SIZE(rndis_rates)]; |
453 | u32 cipher_suites[ARRAY_SIZE(rndis_cipher_suites)]; | 453 | u32 cipher_suites[ARRAY_SIZE(rndis_cipher_suites)]; |
454 | 454 | ||
455 | struct iw_statistics iwstats; | ||
456 | struct iw_statistics privstats; | ||
457 | |||
458 | int caps; | 455 | int caps; |
459 | int multicast_size; | 456 | int multicast_size; |
460 | 457 | ||
@@ -472,6 +469,7 @@ struct rndis_wlan_private { | |||
472 | int radio_on; | 469 | int radio_on; |
473 | int infra_mode; | 470 | int infra_mode; |
474 | bool connected; | 471 | bool connected; |
472 | u8 bssid[ETH_ALEN]; | ||
475 | struct ndis_80211_ssid essid; | 473 | struct ndis_80211_ssid essid; |
476 | __le32 current_command_oid; | 474 | __le32 current_command_oid; |
477 | 475 | ||
@@ -530,6 +528,9 @@ static int rndis_del_key(struct wiphy *wiphy, struct net_device *netdev, | |||
530 | static int rndis_set_default_key(struct wiphy *wiphy, struct net_device *netdev, | 528 | static int rndis_set_default_key(struct wiphy *wiphy, struct net_device *netdev, |
531 | u8 key_index); | 529 | u8 key_index); |
532 | 530 | ||
531 | static int rndis_get_station(struct wiphy *wiphy, struct net_device *dev, | ||
532 | u8 *mac, struct station_info *sinfo); | ||
533 | |||
533 | static struct cfg80211_ops rndis_config_ops = { | 534 | static struct cfg80211_ops rndis_config_ops = { |
534 | .change_virtual_intf = rndis_change_virtual_intf, | 535 | .change_virtual_intf = rndis_change_virtual_intf, |
535 | .scan = rndis_scan, | 536 | .scan = rndis_scan, |
@@ -544,6 +545,7 @@ static struct cfg80211_ops rndis_config_ops = { | |||
544 | .add_key = rndis_add_key, | 545 | .add_key = rndis_add_key, |
545 | .del_key = rndis_del_key, | 546 | .del_key = rndis_del_key, |
546 | .set_default_key = rndis_set_default_key, | 547 | .set_default_key = rndis_set_default_key, |
548 | .get_station = rndis_get_station, | ||
547 | }; | 549 | }; |
548 | 550 | ||
549 | static void *rndis_wiphy_privid = &rndis_wiphy_privid; | 551 | static void *rndis_wiphy_privid = &rndis_wiphy_privid; |
@@ -1931,6 +1933,7 @@ static int rndis_disconnect(struct wiphy *wiphy, struct net_device *dev, | |||
1931 | devdbg(usbdev, "cfg80211.disconnect(%d)", reason_code); | 1933 | devdbg(usbdev, "cfg80211.disconnect(%d)", reason_code); |
1932 | 1934 | ||
1933 | priv->connected = false; | 1935 | priv->connected = false; |
1936 | memset(priv->bssid, 0, ETH_ALEN); | ||
1934 | 1937 | ||
1935 | return deauthenticate(usbdev); | 1938 | return deauthenticate(usbdev); |
1936 | } | 1939 | } |
@@ -2037,6 +2040,7 @@ static int rndis_leave_ibss(struct wiphy *wiphy, struct net_device *dev) | |||
2037 | devdbg(usbdev, "cfg80211.leave_ibss()"); | 2040 | devdbg(usbdev, "cfg80211.leave_ibss()"); |
2038 | 2041 | ||
2039 | priv->connected = false; | 2042 | priv->connected = false; |
2043 | memset(priv->bssid, 0, ETH_ALEN); | ||
2040 | 2044 | ||
2041 | return deauthenticate(usbdev); | 2045 | return deauthenticate(usbdev); |
2042 | } | 2046 | } |
@@ -2114,6 +2118,43 @@ static int rndis_set_default_key(struct wiphy *wiphy, struct net_device *netdev, | |||
2114 | return add_wep_key(usbdev, key.material, key.len, key_index); | 2118 | return add_wep_key(usbdev, key.material, key.len, key_index); |
2115 | } | 2119 | } |
2116 | 2120 | ||
2121 | static void rndis_fill_station_info(struct usbnet *usbdev, | ||
2122 | struct station_info *sinfo) | ||
2123 | { | ||
2124 | __le32 linkspeed, rssi; | ||
2125 | int ret, len; | ||
2126 | |||
2127 | memset(sinfo, 0, sizeof(*sinfo)); | ||
2128 | |||
2129 | len = sizeof(linkspeed); | ||
2130 | ret = rndis_query_oid(usbdev, OID_GEN_LINK_SPEED, &linkspeed, &len); | ||
2131 | if (ret == 0) { | ||
2132 | sinfo->txrate.legacy = le32_to_cpu(linkspeed) / 1000; | ||
2133 | sinfo->filled |= STATION_INFO_TX_BITRATE; | ||
2134 | } | ||
2135 | |||
2136 | len = sizeof(rssi); | ||
2137 | ret = rndis_query_oid(usbdev, OID_802_11_RSSI, &rssi, &len); | ||
2138 | if (ret == 0) { | ||
2139 | sinfo->signal = level_to_qual(le32_to_cpu(rssi)); | ||
2140 | sinfo->filled |= STATION_INFO_SIGNAL; | ||
2141 | } | ||
2142 | } | ||
2143 | |||
2144 | static int rndis_get_station(struct wiphy *wiphy, struct net_device *dev, | ||
2145 | u8 *mac, struct station_info *sinfo) | ||
2146 | { | ||
2147 | struct rndis_wlan_private *priv = wiphy_priv(wiphy); | ||
2148 | struct usbnet *usbdev = priv->usbdev; | ||
2149 | |||
2150 | if (compare_ether_addr(priv->bssid, mac)) | ||
2151 | return -ENOENT; | ||
2152 | |||
2153 | rndis_fill_station_info(usbdev, sinfo); | ||
2154 | |||
2155 | return 0; | ||
2156 | } | ||
2157 | |||
2117 | /* | 2158 | /* |
2118 | * wireless extension handlers | 2159 | * wireless extension handlers |
2119 | */ | 2160 | */ |
@@ -2459,7 +2500,6 @@ static int rndis_iw_set_encode_ext(struct net_device *dev, | |||
2459 | (u8 *)&ext->addr.sa_data, ext->rx_seq, cipher, | 2500 | (u8 *)&ext->addr.sa_data, ext->rx_seq, cipher, |
2460 | flags); | 2501 | flags); |
2461 | } | 2502 | } |
2462 | #endif | ||
2463 | 2503 | ||
2464 | 2504 | ||
2465 | static int rndis_iw_get_rate(struct net_device *dev, | 2505 | static int rndis_iw_get_rate(struct net_device *dev, |
@@ -2492,6 +2532,7 @@ static struct iw_statistics *rndis_get_wireless_stats(struct net_device *dev) | |||
2492 | 2532 | ||
2493 | return &priv->iwstats; | 2533 | return &priv->iwstats; |
2494 | } | 2534 | } |
2535 | #endif | ||
2495 | 2536 | ||
2496 | 2537 | ||
2497 | #define IW_IOCTL(x) [(x) - SIOCSIWCOMMIT] | 2538 | #define IW_IOCTL(x) [(x) - SIOCSIWCOMMIT] |
@@ -2510,7 +2551,7 @@ static const iw_handler rndis_iw_handler[] = | |||
2510 | IW_IOCTL(SIOCGIWSCAN) = (iw_handler) cfg80211_wext_giwscan, | 2551 | IW_IOCTL(SIOCGIWSCAN) = (iw_handler) cfg80211_wext_giwscan, |
2511 | IW_IOCTL(SIOCSIWESSID) = (iw_handler) cfg80211_wext_siwessid, | 2552 | IW_IOCTL(SIOCSIWESSID) = (iw_handler) cfg80211_wext_siwessid, |
2512 | IW_IOCTL(SIOCGIWESSID) = (iw_handler) cfg80211_wext_giwessid, | 2553 | IW_IOCTL(SIOCGIWESSID) = (iw_handler) cfg80211_wext_giwessid, |
2513 | IW_IOCTL(SIOCGIWRATE) = rndis_iw_get_rate, | 2554 | IW_IOCTL(SIOCGIWRATE) = (iw_handler) cfg80211_wext_giwrate, |
2514 | IW_IOCTL(SIOCSIWRTS) = (iw_handler) cfg80211_wext_siwrts, | 2555 | IW_IOCTL(SIOCSIWRTS) = (iw_handler) cfg80211_wext_siwrts, |
2515 | IW_IOCTL(SIOCGIWRTS) = (iw_handler) cfg80211_wext_giwrts, | 2556 | IW_IOCTL(SIOCGIWRTS) = (iw_handler) cfg80211_wext_giwrts, |
2516 | IW_IOCTL(SIOCSIWFRAG) = (iw_handler) cfg80211_wext_siwfrag, | 2557 | IW_IOCTL(SIOCSIWFRAG) = (iw_handler) cfg80211_wext_siwfrag, |
@@ -2539,7 +2580,7 @@ static const struct iw_handler_def rndis_iw_handlers = { | |||
2539 | .standard = (iw_handler *)rndis_iw_handler, | 2580 | .standard = (iw_handler *)rndis_iw_handler, |
2540 | .private = (iw_handler *)rndis_wlan_private_handler, | 2581 | .private = (iw_handler *)rndis_wlan_private_handler, |
2541 | .private_args = (struct iw_priv_args *)rndis_wlan_private_args, | 2582 | .private_args = (struct iw_priv_args *)rndis_wlan_private_args, |
2542 | .get_wireless_stats = rndis_get_wireless_stats, | 2583 | .get_wireless_stats = cfg80211_wireless_stats, |
2543 | }; | 2584 | }; |
2544 | 2585 | ||
2545 | 2586 | ||
@@ -2614,6 +2655,7 @@ static void rndis_wlan_do_link_up_work(struct usbnet *usbdev) | |||
2614 | cfg80211_ibss_joined(usbdev->net, bssid, GFP_KERNEL); | 2655 | cfg80211_ibss_joined(usbdev->net, bssid, GFP_KERNEL); |
2615 | 2656 | ||
2616 | priv->connected = true; | 2657 | priv->connected = true; |
2658 | memcpy(priv->bssid, bssid, ETH_ALEN); | ||
2617 | 2659 | ||
2618 | usbnet_resume_rx(usbdev); | 2660 | usbnet_resume_rx(usbdev); |
2619 | netif_carrier_on(usbdev->net); | 2661 | netif_carrier_on(usbdev->net); |
@@ -2928,64 +2970,30 @@ static void rndis_update_wireless_stats(struct work_struct *work) | |||
2928 | struct rndis_wlan_private *priv = | 2970 | struct rndis_wlan_private *priv = |
2929 | container_of(work, struct rndis_wlan_private, stats_work.work); | 2971 | container_of(work, struct rndis_wlan_private, stats_work.work); |
2930 | struct usbnet *usbdev = priv->usbdev; | 2972 | struct usbnet *usbdev = priv->usbdev; |
2931 | struct iw_statistics iwstats; | ||
2932 | __le32 rssi, tmp; | 2973 | __le32 rssi, tmp; |
2933 | int len, ret, j; | 2974 | int len, ret, j; |
2934 | unsigned long flags; | ||
2935 | int update_jiffies = STATS_UPDATE_JIFFIES; | 2975 | int update_jiffies = STATS_UPDATE_JIFFIES; |
2936 | void *buf; | 2976 | void *buf; |
2937 | 2977 | ||
2938 | spin_lock_irqsave(&priv->stats_lock, flags); | 2978 | /* Only check/do workaround when connected. Calling is_associated() |
2939 | memcpy(&iwstats, &priv->privstats, sizeof(iwstats)); | 2979 | * also polls device with rndis_command() and catches for media link |
2940 | spin_unlock_irqrestore(&priv->stats_lock, flags); | 2980 | * indications. |
2941 | 2981 | */ | |
2942 | /* only update stats when connected */ | 2982 | if (!is_associated(usbdev)) |
2943 | if (!is_associated(usbdev)) { | ||
2944 | iwstats.qual.qual = 0; | ||
2945 | iwstats.qual.level = 0; | ||
2946 | iwstats.qual.updated = IW_QUAL_QUAL_UPDATED | ||
2947 | | IW_QUAL_LEVEL_UPDATED | ||
2948 | | IW_QUAL_NOISE_INVALID | ||
2949 | | IW_QUAL_QUAL_INVALID | ||
2950 | | IW_QUAL_LEVEL_INVALID; | ||
2951 | goto end; | 2983 | goto end; |
2952 | } | ||
2953 | 2984 | ||
2954 | len = sizeof(rssi); | 2985 | len = sizeof(rssi); |
2955 | ret = rndis_query_oid(usbdev, OID_802_11_RSSI, &rssi, &len); | 2986 | ret = rndis_query_oid(usbdev, OID_802_11_RSSI, &rssi, &len); |
2987 | if (ret == 0) | ||
2988 | priv->last_qual = level_to_qual(le32_to_cpu(rssi)); | ||
2956 | 2989 | ||
2957 | devdbg(usbdev, "stats: OID_802_11_RSSI -> %d, rssi:%d", ret, | 2990 | devdbg(usbdev, "stats: OID_802_11_RSSI -> %d, rssi:%d", ret, |
2958 | le32_to_cpu(rssi)); | 2991 | le32_to_cpu(rssi)); |
2959 | if (ret == 0) { | ||
2960 | memset(&iwstats.qual, 0, sizeof(iwstats.qual)); | ||
2961 | iwstats.qual.qual = level_to_qual(le32_to_cpu(rssi)); | ||
2962 | iwstats.qual.level = level_to_qual(le32_to_cpu(rssi)); | ||
2963 | iwstats.qual.updated = IW_QUAL_QUAL_UPDATED | ||
2964 | | IW_QUAL_LEVEL_UPDATED | ||
2965 | | IW_QUAL_NOISE_INVALID; | ||
2966 | } | ||
2967 | |||
2968 | memset(&iwstats.discard, 0, sizeof(iwstats.discard)); | ||
2969 | |||
2970 | len = sizeof(tmp); | ||
2971 | ret = rndis_query_oid(usbdev, OID_GEN_XMIT_ERROR, &tmp, &len); | ||
2972 | if (ret == 0) | ||
2973 | iwstats.discard.misc += le32_to_cpu(tmp); | ||
2974 | |||
2975 | len = sizeof(tmp); | ||
2976 | ret = rndis_query_oid(usbdev, OID_GEN_RCV_ERROR, &tmp, &len); | ||
2977 | if (ret == 0) | ||
2978 | iwstats.discard.misc += le32_to_cpu(tmp); | ||
2979 | |||
2980 | len = sizeof(tmp); | ||
2981 | ret = rndis_query_oid(usbdev, OID_GEN_RCV_NO_BUFFER, &tmp, &len); | ||
2982 | if (ret == 0) | ||
2983 | iwstats.discard.misc += le32_to_cpu(tmp); | ||
2984 | 2992 | ||
2985 | /* Workaround transfer stalls on poor quality links. | 2993 | /* Workaround transfer stalls on poor quality links. |
2986 | * TODO: find right way to fix these stalls (as stalls do not happen | 2994 | * TODO: find right way to fix these stalls (as stalls do not happen |
2987 | * with ndiswrapper/windows driver). */ | 2995 | * with ndiswrapper/windows driver). */ |
2988 | if (iwstats.qual.qual <= 25) { | 2996 | if (priv->last_qual <= 25) { |
2989 | /* Decrease stats worker interval to catch stalls. | 2997 | /* Decrease stats worker interval to catch stalls. |
2990 | * faster. Faster than 400-500ms causes packet loss, | 2998 | * faster. Faster than 400-500ms causes packet loss, |
2991 | * Slower doesn't catch stalls fast enough. | 2999 | * Slower doesn't catch stalls fast enough. |
@@ -3013,9 +3021,6 @@ static void rndis_update_wireless_stats(struct work_struct *work) | |||
3013 | kfree(buf); | 3021 | kfree(buf); |
3014 | } | 3022 | } |
3015 | end: | 3023 | end: |
3016 | spin_lock_irqsave(&priv->stats_lock, flags); | ||
3017 | memcpy(&priv->privstats, &iwstats, sizeof(iwstats)); | ||
3018 | spin_unlock_irqrestore(&priv->stats_lock, flags); | ||
3019 | 3024 | ||
3020 | if (update_jiffies >= HZ) | 3025 | if (update_jiffies >= HZ) |
3021 | update_jiffies = round_jiffies_relative(update_jiffies); | 3026 | update_jiffies = round_jiffies_relative(update_jiffies); |
@@ -3146,7 +3151,6 @@ static int rndis_wlan_bind(struct usbnet *usbdev, struct usb_interface *intf) | |||
3146 | priv->usbdev = usbdev; | 3151 | priv->usbdev = usbdev; |
3147 | 3152 | ||
3148 | mutex_init(&priv->command_lock); | 3153 | mutex_init(&priv->command_lock); |
3149 | spin_lock_init(&priv->stats_lock); | ||
3150 | 3154 | ||
3151 | /* because rndis_command() sleeps we need to use workqueue */ | 3155 | /* because rndis_command() sleeps we need to use workqueue */ |
3152 | priv->workqueue = create_singlethread_workqueue("rndis_wlan"); | 3156 | priv->workqueue = create_singlethread_workqueue("rndis_wlan"); |
@@ -3183,14 +3187,6 @@ static int rndis_wlan_bind(struct usbnet *usbdev, struct usb_interface *intf) | |||
3183 | else | 3187 | else |
3184 | usbdev->net->flags &= ~IFF_MULTICAST; | 3188 | usbdev->net->flags &= ~IFF_MULTICAST; |
3185 | 3189 | ||
3186 | priv->iwstats.qual.qual = 0; | ||
3187 | priv->iwstats.qual.level = 0; | ||
3188 | priv->iwstats.qual.updated = IW_QUAL_QUAL_UPDATED | ||
3189 | | IW_QUAL_LEVEL_UPDATED | ||
3190 | | IW_QUAL_NOISE_INVALID | ||
3191 | | IW_QUAL_QUAL_INVALID | ||
3192 | | IW_QUAL_LEVEL_INVALID; | ||
3193 | |||
3194 | /* fill-out wiphy structure and register w/ cfg80211 */ | 3190 | /* fill-out wiphy structure and register w/ cfg80211 */ |
3195 | memcpy(wiphy->perm_addr, usbdev->net->dev_addr, ETH_ALEN); | 3191 | memcpy(wiphy->perm_addr, usbdev->net->dev_addr, ETH_ALEN); |
3196 | wiphy->privid = rndis_wiphy_privid; | 3192 | wiphy->privid = rndis_wiphy_privid; |