aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJussi Kivilinna <jussi.kivilinna@mbnet.fi>2009-08-28 06:28:03 -0400
committerJohn W. Linville <linville@tuxdriver.com>2009-08-28 14:40:59 -0400
commit8b89a2883be4b6bad8ac0c5928784febb2b34172 (patch)
treeb05da4e342dbab77e5d74315e94ac777850f9ea7
parent84bf8400cee127be3b58a9d9b8cfa453dad999ab (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.c118
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,
530static int rndis_set_default_key(struct wiphy *wiphy, struct net_device *netdev, 528static int rndis_set_default_key(struct wiphy *wiphy, struct net_device *netdev,
531 u8 key_index); 529 u8 key_index);
532 530
531static int rndis_get_station(struct wiphy *wiphy, struct net_device *dev,
532 u8 *mac, struct station_info *sinfo);
533
533static struct cfg80211_ops rndis_config_ops = { 534static 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
549static void *rndis_wiphy_privid = &rndis_wiphy_privid; 551static 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
2121static 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
2144static 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
2465static int rndis_iw_get_rate(struct net_device *dev, 2505static 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 }
3015end: 3023end:
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;