diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h index b043b78dd2c3..962e2232a074 100644 --- a/include/linux/nl80211.h +++ b/include/linux/nl80211.h @@ -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 * diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 45c5f9c8e51b..da450ef1fc7e 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -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; }