cfg80211: fix channel configuration in IBSS join
authorAntonio Quartulli <antonio@open-mesh.com>
Wed, 29 Jan 2014 16:53:43 +0000 (17:53 +0100)
committerJohannes Berg <johannes.berg@intel.com>
Tue, 4 Feb 2014 20:58:16 +0000 (21:58 +0100)
When receiving an IBSS_JOINED event select the BSS object
based on the {bssid, channel} couple rather than the bssid
only.
With the current approach if another cell having the same
BSSID (but using a different channel) exists then cfg80211
picks up the wrong BSS object.
The result is a mismatching channel configuration between
cfg80211 and the driver, that can lead to any sort of
problem.

The issue can be triggered by having an IBSS sitting on
given channel and then asking the driver to create a new
cell using the same BSSID but with a different frequency.
By passing the channel to cfg80211_get_bss() we can solve
this ambiguity and retrieve/create the correct BSS object.
All the users of cfg80211_ibss_joined() have been changed
accordingly.

Moreover WARN when cfg80211_ibss_joined() gets a NULL
channel as argument and remove a bogus call of the same
function in ath6kl (it does not make sense to call
cfg80211_ibss_joined() with a zero BSSID on ibss-leave).

Cc: Kalle Valo <kvalo@qca.qualcomm.com>
Cc: Arend van Spriel <arend@broadcom.com>
Cc: Bing Zhao <bzhao@marvell.com>
Cc: Jussi Kivilinna <jussi.kivilinna@iki.fi>
Cc: libertas-dev@lists.infradead.org
Acked-by: Kalle Valo <kvalo@qca.qualcomm.com>
Signed-off-by: Antonio Quartulli <antonio@open-mesh.com>
[minor code cleanup in ath6kl]
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
drivers/net/wireless/ath/ath6kl/cfg80211.c
drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c
drivers/net/wireless/libertas/cfg.c
drivers/net/wireless/mwifiex/cfg80211.c
drivers/net/wireless/rndis_wlan.c
include/net/cfg80211.h
net/mac80211/ibss.c
net/wireless/core.h
net/wireless/ibss.c
net/wireless/trace.h
net/wireless/util.c

index eba32f56850ab81efd3211afd528e1083f410ab8..c2c6f460495859ae3517c4f20daa2c15caebdde0 100644 (file)
@@ -790,7 +790,7 @@ void ath6kl_cfg80211_connect_event(struct ath6kl_vif *vif, u16 channel,
        if (nw_type & ADHOC_NETWORK) {
                ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "ad-hoc %s selected\n",
                           nw_type & ADHOC_CREATOR ? "creator" : "joiner");
-               cfg80211_ibss_joined(vif->ndev, bssid, GFP_KERNEL);
+               cfg80211_ibss_joined(vif->ndev, bssid, chan, GFP_KERNEL);
                cfg80211_put_bss(ar->wiphy, bss);
                return;
        }
@@ -861,13 +861,9 @@ void ath6kl_cfg80211_disconnect_event(struct ath6kl_vif *vif, u8 reason,
        }
 
        if (vif->nw_type & ADHOC_NETWORK) {
-               if (vif->wdev.iftype != NL80211_IFTYPE_ADHOC) {
+               if (vif->wdev.iftype != NL80211_IFTYPE_ADHOC)
                        ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
                                   "%s: ath6k not in ibss mode\n", __func__);
-                       return;
-               }
-               memset(bssid, 0, ETH_ALEN);
-               cfg80211_ibss_joined(vif->ndev, bssid, GFP_KERNEL);
                return;
        }
 
index 3d25c18340c57d11960b2ac1285faeb5404b77ac..1a80bf19cb8908465f9dd15119493ab1dbd02d96 100644 (file)
@@ -4658,6 +4658,7 @@ brcmf_notify_connect_status(struct brcmf_if *ifp,
        struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
        struct net_device *ndev = ifp->ndev;
        struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
+       struct ieee80211_channel *chan;
        s32 err = 0;
 
        if (ifp->vif->mode == WL_MODE_AP) {
@@ -4665,9 +4666,10 @@ brcmf_notify_connect_status(struct brcmf_if *ifp,
        } else if (brcmf_is_linkup(e)) {
                brcmf_dbg(CONN, "Linkup\n");
                if (brcmf_is_ibssmode(ifp->vif)) {
+                       chan = ieee80211_get_channel(cfg->wiphy, cfg->channel);
                        memcpy(profile->bssid, e->addr, ETH_ALEN);
                        wl_inform_ibss(cfg, ndev, e->addr);
-                       cfg80211_ibss_joined(ndev, e->addr, GFP_KERNEL);
+                       cfg80211_ibss_joined(ndev, e->addr, chan, GFP_KERNEL);
                        clear_bit(BRCMF_VIF_STATUS_CONNECTING,
                                  &ifp->vif->sme_state);
                        set_bit(BRCMF_VIF_STATUS_CONNECTED,
index 32f75007a825be6c24b6195d35a9f4e31d590961..2d72a6b4b93e927b37c0e7ee2c5d316c475b3a47 100644 (file)
@@ -1766,7 +1766,8 @@ static void lbs_join_post(struct lbs_private *priv,
        memcpy(priv->wdev->ssid, params->ssid, params->ssid_len);
        priv->wdev->ssid_len = params->ssid_len;
 
-       cfg80211_ibss_joined(priv->dev, bssid, GFP_KERNEL);
+       cfg80211_ibss_joined(priv->dev, bssid, params->chandef.chan,
+                            GFP_KERNEL);
 
        /* TODO: consider doing this at MACREG_INT_CODE_LINK_SENSED time */
        priv->connect_status = LBS_CONNECTED;
index f4cf9c9d40ec9677eb87e06c1a01f08c0f2afe33..0948ebe8942ee3419c653c48a8bfa5f17f38c8e7 100644 (file)
@@ -1882,7 +1882,8 @@ mwifiex_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *dev,
                                     params->privacy);
 done:
        if (!ret) {
-               cfg80211_ibss_joined(priv->netdev, priv->cfg_bssid, GFP_KERNEL);
+               cfg80211_ibss_joined(priv->netdev, priv->cfg_bssid,
+                                    params->chandef.chan, GFP_KERNEL);
                dev_dbg(priv->adapter->dev,
                        "info: joined/created adhoc network with bssid"
                        " %pM successfully\n", priv->cfg_bssid);
index 5028557aa18adb1a22c74c7a59123f1bb52b0d5a..2e89a865a67d1023d9ae64e0351c42d91c15c47e 100644 (file)
@@ -2835,7 +2835,9 @@ static void rndis_wlan_do_link_up_work(struct usbnet *usbdev)
                                        bssid, req_ie, req_ie_len,
                                        resp_ie, resp_ie_len, GFP_KERNEL);
        } else if (priv->infra_mode == NDIS_80211_INFRA_ADHOC)
-               cfg80211_ibss_joined(usbdev->net, bssid, GFP_KERNEL);
+               cfg80211_ibss_joined(usbdev->net, bssid,
+                                    get_current_channel(usbdev, NULL),
+                                    GFP_KERNEL);
 
        kfree(info);
 
index 009290e36d157525fd3411af112c65e5b770da93..c68201d78b9091d746a19849defd64aef1faf340 100644 (file)
@@ -3895,6 +3895,7 @@ void cfg80211_michael_mic_failure(struct net_device *dev, const u8 *addr,
  *
  * @dev: network device
  * @bssid: the BSSID of the IBSS joined
+ * @channel: the channel of the IBSS joined
  * @gfp: allocation flags
  *
  * This function notifies cfg80211 that the device joined an IBSS or
@@ -3904,7 +3905,8 @@ void cfg80211_michael_mic_failure(struct net_device *dev, const u8 *addr,
  * with the locally generated beacon -- this guarantees that there is
  * always a scan result for this IBSS. cfg80211 will handle the rest.
  */
-void cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid, gfp_t gfp);
+void cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid,
+                         struct ieee80211_channel *channel, gfp_t gfp);
 
 /**
  * cfg80211_notify_new_candidate - notify cfg80211 of a new mesh peer candidate
index 8e444476307ab06cf14a1d7925ba82ad4decbb3d..9c84b75f3de8a58dc4f4e3cbf8a0c0c72be63ab3 100644 (file)
@@ -382,7 +382,7 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
                                              presp->head_len, 0, GFP_KERNEL);
        cfg80211_put_bss(local->hw.wiphy, bss);
        netif_carrier_on(sdata->dev);
-       cfg80211_ibss_joined(sdata->dev, ifibss->bssid, GFP_KERNEL);
+       cfg80211_ibss_joined(sdata->dev, ifibss->bssid, chan, GFP_KERNEL);
 }
 
 static void ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
index 37ec16d7bb1ab6bf6e4948259aad19eb6e5a58cf..8a820f9c4a766cc0d250b6d4c78be912753b3570 100644 (file)
@@ -210,6 +210,7 @@ struct cfg80211_event {
                } dc;
                struct {
                        u8 bssid[ETH_ALEN];
+                       struct ieee80211_channel *channel;
                } ij;
        };
 };
@@ -257,7 +258,8 @@ int __cfg80211_leave_ibss(struct cfg80211_registered_device *rdev,
                          struct net_device *dev, bool nowext);
 int cfg80211_leave_ibss(struct cfg80211_registered_device *rdev,
                        struct net_device *dev, bool nowext);
-void __cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid);
+void __cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid,
+                           struct ieee80211_channel *channel);
 int cfg80211_ibss_wext_join(struct cfg80211_registered_device *rdev,
                            struct wireless_dev *wdev);
 
index f911c5f9f903d8ccdd791aaf26d950b19ad6dd9f..e37e39c29dfb82ada18f68fd3b065c92ff7a1093 100644 (file)
@@ -14,7 +14,8 @@
 #include "rdev-ops.h"
 
 
-void __cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid)
+void __cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid,
+                           struct ieee80211_channel *channel)
 {
        struct wireless_dev *wdev = dev->ieee80211_ptr;
        struct cfg80211_bss *bss;
@@ -28,8 +29,7 @@ void __cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid)
        if (!wdev->ssid_len)
                return;
 
-       bss = cfg80211_get_bss(wdev->wiphy, NULL, bssid,
-                              wdev->ssid, wdev->ssid_len,
+       bss = cfg80211_get_bss(wdev->wiphy, channel, bssid, NULL, 0,
                               WLAN_CAPABILITY_IBSS, WLAN_CAPABILITY_IBSS);
 
        if (WARN_ON(!bss))
@@ -54,21 +54,26 @@ void __cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid)
 #endif
 }
 
-void cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid, gfp_t gfp)
+void cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid,
+                         struct ieee80211_channel *channel, gfp_t gfp)
 {
        struct wireless_dev *wdev = dev->ieee80211_ptr;
        struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
        struct cfg80211_event *ev;
        unsigned long flags;
 
-       trace_cfg80211_ibss_joined(dev, bssid);
+       trace_cfg80211_ibss_joined(dev, bssid, channel);
+
+       if (WARN_ON(!channel))
+               return;
 
        ev = kzalloc(sizeof(*ev), gfp);
        if (!ev)
                return;
 
        ev->type = EVENT_IBSS_JOINED;
-       memcpy(ev->cr.bssid, bssid, ETH_ALEN);
+       memcpy(ev->ij.bssid, bssid, ETH_ALEN);
+       ev->ij.channel = channel;
 
        spin_lock_irqsave(&wdev->event_lock, flags);
        list_add_tail(&ev->list, &wdev->event_list);
index fbcc23edee5474459950b8566ecffd541ad4ed7d..5eaeed59db07651de6305320187f127c9fdd8b65 100644 (file)
@@ -2278,11 +2278,6 @@ DECLARE_EVENT_CLASS(cfg80211_rx_evt,
        TP_printk(NETDEV_PR_FMT ", " MAC_PR_FMT, NETDEV_PR_ARG, MAC_PR_ARG(addr))
 );
 
-DEFINE_EVENT(cfg80211_rx_evt, cfg80211_ibss_joined,
-       TP_PROTO(struct net_device *netdev, const u8 *addr),
-       TP_ARGS(netdev, addr)
-);
-
 DEFINE_EVENT(cfg80211_rx_evt, cfg80211_rx_spurious_frame,
        TP_PROTO(struct net_device *netdev, const u8 *addr),
        TP_ARGS(netdev, addr)
@@ -2293,6 +2288,24 @@ DEFINE_EVENT(cfg80211_rx_evt, cfg80211_rx_unexpected_4addr_frame,
        TP_ARGS(netdev, addr)
 );
 
+TRACE_EVENT(cfg80211_ibss_joined,
+       TP_PROTO(struct net_device *netdev, const u8 *bssid,
+                struct ieee80211_channel *channel),
+       TP_ARGS(netdev, bssid, channel),
+       TP_STRUCT__entry(
+               NETDEV_ENTRY
+               MAC_ENTRY(bssid)
+               CHAN_ENTRY
+       ),
+       TP_fast_assign(
+               NETDEV_ASSIGN;
+               MAC_ASSIGN(bssid, bssid);
+               CHAN_ASSIGN(channel);
+       ),
+       TP_printk(NETDEV_PR_FMT ", bssid: " MAC_PR_FMT ", " CHAN_PR_FMT,
+                 NETDEV_PR_ARG, MAC_PR_ARG(bssid), CHAN_PR_ARG)
+);
+
 TRACE_EVENT(cfg80211_probe_status,
        TP_PROTO(struct net_device *netdev, const u8 *addr, u64 cookie,
                 bool acked),
index d39c37104ae2f125c5def9c943dc65ab8a669f5a..7526a4d8aa16979e0577b1153885bf87afebb97c 100644 (file)
@@ -820,7 +820,8 @@ void cfg80211_process_wdev_events(struct wireless_dev *wdev)
                                                ev->dc.reason, true);
                        break;
                case EVENT_IBSS_JOINED:
-                       __cfg80211_ibss_joined(wdev->netdev, ev->ij.bssid);
+                       __cfg80211_ibss_joined(wdev->netdev, ev->ij.bssid,
+                                              ev->ij.channel);
                        break;
                }
                wdev_unlock(wdev);