nl80211: report BSS status
authorJohannes Berg <johannes@sipsolutions.net>
Fri, 10 Jul 2009 16:42:31 +0000 (18:42 +0200)
committerJohn W. Linville <linville@tuxdriver.com>
Fri, 24 Jul 2009 19:05:11 +0000 (15:05 -0400)
When connected to a BSS, or joined to an IBSS, we'll want
to know in userspace without using wireless extensions, so
report the BSS status in the BSS list. Userspace can query
the BSS list, display all the information and retrieve the
station information as well.

For example (from hwsim):

$ iw dev wlan1 scan dump
BSS 02:00:00:00:00:00 (on wlan1) -- associated
freq: 2462
beacon interval: 100
capability: ESS ShortSlotTime (0x0401)
signal: -50.00 dBm
SSID: j
Supported rates: 1.0* 2.0* 5.5* 11.0* 6.0 9.0 12.0 18.0
DS Paramater set: channel 11
ERP: <no flags>
Extended supported rates: 24.0 36.0 48.0 54.0

Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
include/linux/nl80211.h
net/wireless/nl80211.c

index b043b78..962e223 100644 (file)
@@ -1260,6 +1260,7 @@ enum nl80211_channel_type {
  *     in mBm (100 * dBm) (s32)
  * @NL80211_BSS_SIGNAL_UNSPEC: signal strength of the probe response/beacon
  *     in unspecified units, scaled to 0..100 (u8)
+ * @NL80211_BSS_STATUS: status, if this BSS is "used"
  * @__NL80211_BSS_AFTER_LAST: internal
  * @NL80211_BSS_MAX: highest BSS attribute
  */
@@ -1273,12 +1274,22 @@ enum nl80211_bss {
        NL80211_BSS_INFORMATION_ELEMENTS,
        NL80211_BSS_SIGNAL_MBM,
        NL80211_BSS_SIGNAL_UNSPEC,
+       NL80211_BSS_STATUS,
 
        /* keep last */
        __NL80211_BSS_AFTER_LAST,
        NL80211_BSS_MAX = __NL80211_BSS_AFTER_LAST - 1
 };
 
+/**
+ * enum nl80211_bss_status - BSS "status"
+ */
+enum nl80211_bss_status {
+       NL80211_BSS_STATUS_AUTHENTICATED,
+       NL80211_BSS_STATUS_ASSOCIATED,
+       NL80211_BSS_STATUS_IBSS_JOINED,
+};
+
 /**
  * enum nl80211_auth_type - AuthenticationType
  *
index 45c5f9c..da450ef 100644 (file)
@@ -3094,11 +3094,15 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info)
 
 static int nl80211_send_bss(struct sk_buff *msg, u32 pid, u32 seq, int flags,
                            struct cfg80211_registered_device *rdev,
-                           struct net_device *dev,
-                           struct cfg80211_bss *res)
+                           struct wireless_dev *wdev,
+                           struct cfg80211_internal_bss *intbss)
 {
+       struct cfg80211_bss *res = &intbss->pub;
        void *hdr;
        struct nlattr *bss;
+       int i;
+
+       ASSERT_WDEV_LOCK(wdev);
 
        hdr = nl80211hdr_put(msg, pid, seq, flags,
                             NL80211_CMD_NEW_SCAN_RESULTS);
@@ -3107,7 +3111,7 @@ static int nl80211_send_bss(struct sk_buff *msg, u32 pid, u32 seq, int flags,
 
        NLA_PUT_U32(msg, NL80211_ATTR_SCAN_GENERATION,
                    rdev->bss_generation);
-       NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, dev->ifindex);
+       NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, wdev->netdev->ifindex);
 
        bss = nla_nest_start(msg, NL80211_ATTR_BSS);
        if (!bss)
@@ -3136,6 +3140,28 @@ static int nl80211_send_bss(struct sk_buff *msg, u32 pid, u32 seq, int flags,
                break;
        }
 
+       switch (wdev->iftype) {
+       case NL80211_IFTYPE_STATION:
+               if (intbss == wdev->current_bss)
+                       NLA_PUT_U32(msg, NL80211_BSS_STATUS,
+                                   NL80211_BSS_STATUS_ASSOCIATED);
+               else for (i = 0; i < MAX_AUTH_BSSES; i++) {
+                       if (intbss != wdev->auth_bsses[i])
+                               continue;
+                       NLA_PUT_U32(msg, NL80211_BSS_STATUS,
+                                   NL80211_BSS_STATUS_AUTHENTICATED);
+                       break;
+               }
+               break;
+       case NL80211_IFTYPE_ADHOC:
+               if (intbss == wdev->current_bss)
+                       NLA_PUT_U32(msg, NL80211_BSS_STATUS,
+                                   NL80211_BSS_STATUS_IBSS_JOINED);
+               break;
+       default:
+               break;
+       }
+
        nla_nest_end(msg, bss);
 
        return genlmsg_end(msg, hdr);
@@ -3148,9 +3174,10 @@ static int nl80211_send_bss(struct sk_buff *msg, u32 pid, u32 seq, int flags,
 static int nl80211_dump_scan(struct sk_buff *skb,
                             struct netlink_callback *cb)
 {
-       struct cfg80211_registered_device *dev;
-       struct net_device *netdev;
+       struct cfg80211_registered_device *rdev;
+       struct net_device *dev;
        struct cfg80211_internal_bss *scan;
+       struct wireless_dev *wdev;
        int ifidx = cb->args[0];
        int start = cb->args[1], idx = 0;
        int err;
@@ -3171,39 +3198,43 @@ static int nl80211_dump_scan(struct sk_buff *skb,
                cb->args[0] = ifidx;
        }
 
-       netdev = dev_get_by_index(&init_net, ifidx);
-       if (!netdev)
+       dev = dev_get_by_index(&init_net, ifidx);
+       if (!dev)
                return -ENODEV;
 
-       dev = cfg80211_get_dev_from_ifindex(ifidx);
-       if (IS_ERR(dev)) {
-               err = PTR_ERR(dev);
+       rdev = cfg80211_get_dev_from_ifindex(ifidx);
+       if (IS_ERR(rdev)) {
+               err = PTR_ERR(rdev);
                goto out_put_netdev;
        }
 
-       spin_lock_bh(&dev->bss_lock);
-       cfg80211_bss_expire(dev);
+       wdev = dev->ieee80211_ptr;
 
-       list_for_each_entry(scan, &dev->bss_list, list) {
+       wdev_lock(wdev);
+       spin_lock_bh(&rdev->bss_lock);
+       cfg80211_bss_expire(rdev);
+
+       list_for_each_entry(scan, &rdev->bss_list, list) {
                if (++idx <= start)
                        continue;
                if (nl80211_send_bss(skb,
                                NETLINK_CB(cb->skb).pid,
                                cb->nlh->nlmsg_seq, NLM_F_MULTI,
-                               dev, netdev, &scan->pub) < 0) {
+                               rdev, wdev, scan) < 0) {
                        idx--;
                        goto out;
                }
        }
 
  out:
-       spin_unlock_bh(&dev->bss_lock);
+       spin_unlock_bh(&rdev->bss_lock);
+       wdev_unlock(wdev);
 
        cb->args[1] = idx;
        err = skb->len;
-       cfg80211_unlock_rdev(dev);
+       cfg80211_unlock_rdev(rdev);
  out_put_netdev:
-       dev_put(netdev);
+       dev_put(dev);
 
        return err;
 }