cfg80211: clarify set_channel APIs
authorJohannes Berg <johannes.berg@intel.com>
Wed, 6 Jun 2012 06:18:22 +0000 (08:18 +0200)
committerJohn W. Linville <linville@tuxdriver.com>
Wed, 6 Jun 2012 19:18:17 +0000 (15:18 -0400)
Now that we've removed all uses of the set_channel
API except for the monitor channel and in libertas,
clarify this. Split the libertas mesh use into a
new libertas_set_mesh_channel() operation, just to
keep backward compatibility, and rename the normal
set_channel() to set_monitor_channel().

Also describe the desired set_monitor_channel()
semantics more clearly.

Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
13 files changed:
drivers/net/wireless/libertas/cfg.c
drivers/net/wireless/libertas/dev.h
drivers/net/wireless/libertas/mesh.c
drivers/net/wireless/orinoco/cfg.c
include/net/cfg80211.h
net/mac80211/cfg.c
net/wireless/chan.c
net/wireless/core.h
net/wireless/mesh.c
net/wireless/mlme.c
net/wireless/nl80211.c
net/wireless/wext-compat.c
net/wireless/wext-sme.c

index 2fa879b015b6817d24e558395c0f74ef638cbc96..f4a203049fb470d59d5beb2064208ab82d5734e4 100644 (file)
@@ -435,24 +435,40 @@ static int lbs_add_wpa_tlv(u8 *tlv, const u8 *ie, u8 ie_len)
  * Set Channel
  */
 
-static int lbs_cfg_set_channel(struct wiphy *wiphy,
-       struct net_device *netdev,
-       struct ieee80211_channel *channel,
-       enum nl80211_channel_type channel_type)
+static int lbs_cfg_set_monitor_channel(struct wiphy *wiphy,
+                                      struct ieee80211_channel *channel,
+                                      enum nl80211_channel_type channel_type)
 {
        struct lbs_private *priv = wiphy_priv(wiphy);
        int ret = -ENOTSUPP;
 
-       lbs_deb_enter_args(LBS_DEB_CFG80211, "iface %s freq %d, type %d",
-                          netdev_name(netdev), channel->center_freq, channel_type);
+       lbs_deb_enter_args(LBS_DEB_CFG80211, "freq %d, type %d",
+                          channel->center_freq, channel_type);
 
        if (channel_type != NL80211_CHAN_NO_HT)
                goto out;
 
-       if (netdev == priv->mesh_dev)
-               ret = lbs_mesh_set_channel(priv, channel->hw_value);
-       else
-               ret = lbs_set_channel(priv, channel->hw_value);
+       ret = lbs_set_channel(priv, channel->hw_value);
+
+ out:
+       lbs_deb_leave_args(LBS_DEB_CFG80211, "ret %d", ret);
+       return ret;
+}
+
+static int lbs_cfg_set_mesh_channel(struct wiphy *wiphy,
+                                   struct net_device *netdev,
+                                   struct ieee80211_channel *channel)
+{
+       struct lbs_private *priv = wiphy_priv(wiphy);
+       int ret = -ENOTSUPP;
+
+       lbs_deb_enter_args(LBS_DEB_CFG80211, "iface %s freq %d",
+                          netdev_name(netdev), channel->center_freq);
+
+       if (netdev != priv->mesh_dev)
+               goto out;
+
+       ret = lbs_mesh_set_channel(priv, channel->hw_value);
 
  out:
        lbs_deb_leave_args(LBS_DEB_CFG80211, "ret %d", ret);
@@ -2029,7 +2045,8 @@ static int lbs_leave_ibss(struct wiphy *wiphy, struct net_device *dev)
  */
 
 static struct cfg80211_ops lbs_cfg80211_ops = {
-       .set_channel = lbs_cfg_set_channel,
+       .set_monitor_channel = lbs_cfg_set_monitor_channel,
+       .libertas_set_mesh_channel = lbs_cfg_set_mesh_channel,
        .scan = lbs_cfg_scan,
        .connect = lbs_cfg_connect,
        .disconnect = lbs_cfg_disconnect,
index 672005430acab75e0b650bda1a490245e79d2167..60996ce89f778932e0fa7270e6154e1ad86c03d0 100644 (file)
@@ -58,6 +58,7 @@ struct lbs_private {
        uint16_t mesh_tlv;
        u8 mesh_ssid[IEEE80211_MAX_SSID_LEN + 1];
        u8 mesh_ssid_len;
+       u8 mesh_channel;
 #endif
 
        /* Debugfs */
index e87c031b298fcd2c2a75f72a245944e752648763..97807751ebcfd59204fe6d651ce6874e52d552be 100644 (file)
@@ -131,16 +131,13 @@ static int lbs_mesh_config(struct lbs_private *priv, uint16_t action,
 
 int lbs_mesh_set_channel(struct lbs_private *priv, u8 channel)
 {
+       priv->mesh_channel = channel;
        return lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START, channel);
 }
 
 static uint16_t lbs_mesh_get_channel(struct lbs_private *priv)
 {
-       struct wireless_dev *mesh_wdev = priv->mesh_dev->ieee80211_ptr;
-       if (mesh_wdev->channel)
-               return mesh_wdev->channel->hw_value;
-       else
-               return 1;
+       return priv->mesh_channel ?: 1;
 }
 
 /***************************************************************************
index f7b15b8934fabb0648a70106c0c2c25c45f78434..e15675585fb10ae21a16ba7c9210fb3f703911c2 100644 (file)
@@ -160,10 +160,9 @@ static int orinoco_scan(struct wiphy *wiphy, struct net_device *dev,
        return err;
 }
 
-static int orinoco_set_channel(struct wiphy *wiphy,
-                       struct net_device *netdev,
-                       struct ieee80211_channel *chan,
-                       enum nl80211_channel_type channel_type)
+static int orinoco_set_monitor_channel(struct wiphy *wiphy,
+                                      struct ieee80211_channel *chan,
+                                      enum nl80211_channel_type channel_type)
 {
        struct orinoco_private *priv = wiphy_priv(wiphy);
        int err = 0;
@@ -286,7 +285,7 @@ static int orinoco_set_wiphy_params(struct wiphy *wiphy, u32 changed)
 
 const struct cfg80211_ops orinoco_cfg_ops = {
        .change_virtual_intf = orinoco_change_vif,
-       .set_channel = orinoco_set_channel,
+       .set_monitor_channel = orinoco_set_monitor_channel,
        .scan = orinoco_scan,
        .set_wiphy_params = orinoco_set_wiphy_params,
 };
index 4c90c44b8b75bef0ae78af760b76c78298d6999f..7319f25250b6a4c5d7eb55f03e279f518034a02e 100644 (file)
@@ -1420,11 +1420,14 @@ struct cfg80211_gtk_rekey_data {
  *
  * @set_txq_params: Set TX queue parameters
  *
- * @set_channel: Set channel for a given wireless interface. Some devices
- *     may support multi-channel operation (by channel hopping) so cfg80211
- *     doesn't verify much. Note, however, that the passed netdev may be
- *     %NULL as well if the user requested changing the channel for the
- *     device itself, or for a monitor interface.
+ * @libertas_set_mesh_channel: Only for backward compatibility for libertas,
+ *     as it doesn't implement join_mesh and needs to set the channel to
+ *     join the mesh instead.
+ *
+ * @set_monitor_channel: Set the monitor mode channel for the device. If other
+ *     interfaces are active this callback should reject the configuration.
+ *     If no interfaces are active or the device is down, the channel should
+ *     be stored for when a monitor interface becomes active.
  * @get_channel: Get the current operating channel, should return %NULL if
  *     there's no single defined operating channel if for example the
  *     device implements channel hopping for multi-channel virtual interfaces.
@@ -1614,9 +1617,13 @@ struct cfg80211_ops {
        int     (*set_txq_params)(struct wiphy *wiphy, struct net_device *dev,
                                  struct ieee80211_txq_params *params);
 
-       int     (*set_channel)(struct wiphy *wiphy, struct net_device *dev,
-                              struct ieee80211_channel *chan,
-                              enum nl80211_channel_type channel_type);
+       int     (*libertas_set_mesh_channel)(struct wiphy *wiphy,
+                                            struct net_device *dev,
+                                            struct ieee80211_channel *chan);
+
+       int     (*set_monitor_channel)(struct wiphy *wiphy,
+                                      struct ieee80211_channel *chan,
+                                      enum nl80211_channel_type channel_type);
 
        int     (*scan)(struct wiphy *wiphy, struct net_device *dev,
                        struct cfg80211_scan_request *request);
@@ -2325,7 +2332,6 @@ struct wireless_dev {
        spinlock_t event_lock;
 
        struct cfg80211_internal_bss *current_bss; /* associated / joined */
-       struct ieee80211_channel *channel;
        struct ieee80211_channel *preset_chan;
        enum nl80211_channel_type preset_chantype;
 
index 50aea1ac7e03985017ab32cd6b5837fe77cd208e..d99359a6f76dadc786d7d75491c1d5a171343c4f 100644 (file)
@@ -709,6 +709,13 @@ static int ieee80211_set_channel(struct wiphy *wiphy,
        return 0;
 }
 
+static int ieee80211_set_monitor_channel(struct wiphy *wiphy,
+                                        struct ieee80211_channel *chan,
+                                        enum nl80211_channel_type channel_type)
+{
+       return ieee80211_set_channel(wiphy, NULL, chan, channel_type);
+}
+
 static int ieee80211_set_probe_resp(struct ieee80211_sub_if_data *sdata,
                                    const u8 *resp, size_t resp_len)
 {
@@ -2932,7 +2939,7 @@ struct cfg80211_ops mac80211_config_ops = {
 #endif
        .change_bss = ieee80211_change_bss,
        .set_txq_params = ieee80211_set_txq_params,
-       .set_channel = ieee80211_set_channel,
+       .set_monitor_channel = ieee80211_set_monitor_channel,
        .suspend = ieee80211_suspend,
        .resume = ieee80211_resume,
        .scan = ieee80211_scan,
index 20b87d895722b6190bad6ee87a916b9b49ac6cde..c1999e45a07c125b51592a95763412e5863b2c37 100644 (file)
@@ -78,50 +78,17 @@ bool cfg80211_can_beacon_sec_chan(struct wiphy *wiphy,
 }
 EXPORT_SYMBOL(cfg80211_can_beacon_sec_chan);
 
-int cfg80211_set_freq(struct cfg80211_registered_device *rdev,
-                     struct wireless_dev *wdev, int freq,
-                     enum nl80211_channel_type channel_type)
+int cfg80211_set_monitor_channel(struct cfg80211_registered_device *rdev,
+                                int freq, enum nl80211_channel_type chantype)
 {
        struct ieee80211_channel *chan;
-       int result;
 
-       if (wdev && wdev->iftype == NL80211_IFTYPE_MONITOR)
-               wdev = NULL;
-
-       if (wdev) {
-               ASSERT_WDEV_LOCK(wdev);
-
-               if (!netif_running(wdev->netdev))
-                       return -ENETDOWN;
-       }
-
-       if (!rdev->ops->set_channel)
+       if (!rdev->ops->set_monitor_channel)
                return -EOPNOTSUPP;
 
-       chan = rdev_freq_to_chan(rdev, freq, channel_type);
+       chan = rdev_freq_to_chan(rdev, freq, chantype);
        if (!chan)
                return -EINVAL;
 
-       /* Both channels should be able to initiate communication */
-       if (wdev && (wdev->iftype == NL80211_IFTYPE_ADHOC ||
-                    wdev->iftype == NL80211_IFTYPE_AP ||
-                    wdev->iftype == NL80211_IFTYPE_AP_VLAN ||
-                    wdev->iftype == NL80211_IFTYPE_MESH_POINT ||
-                    wdev->iftype == NL80211_IFTYPE_P2P_GO) &&
-           !cfg80211_can_beacon_sec_chan(&rdev->wiphy, chan, channel_type)) {
-               printk(KERN_DEBUG
-                      "cfg80211: Secondary channel not allowed to beacon\n");
-               return -EINVAL;
-       }
-
-       result = rdev->ops->set_channel(&rdev->wiphy,
-                                       wdev ? wdev->netdev : NULL,
-                                       chan, channel_type);
-       if (result)
-               return result;
-
-       if (wdev)
-               wdev->channel = chan;
-
-       return 0;
+       return rdev->ops->set_monitor_channel(&rdev->wiphy, chan, chantype);
 }
index 1d3d24126946b33154d9bf8e71a6a14cdc16aa4b..9348a47562a4df5e489129af594465533f1e9eb4 100644 (file)
@@ -444,9 +444,8 @@ cfg80211_can_add_interface(struct cfg80211_registered_device *rdev,
 struct ieee80211_channel *
 rdev_freq_to_chan(struct cfg80211_registered_device *rdev,
                  int freq, enum nl80211_channel_type channel_type);
-int cfg80211_set_freq(struct cfg80211_registered_device *rdev,
-                     struct wireless_dev *wdev, int freq,
-                     enum nl80211_channel_type channel_type);
+int cfg80211_set_monitor_channel(struct cfg80211_registered_device *rdev,
+                                int freq, enum nl80211_channel_type chantype);
 
 int ieee80211_get_ratemask(struct ieee80211_supported_band *sband,
                           const u8 *rates, unsigned int n_rates,
index 2e3b700eba327acb3138f0934c9f818cd7b64be4..b44c736bf9cfb292a1d7baefb7333fe925800386 100644 (file)
@@ -179,6 +179,13 @@ int cfg80211_set_mesh_freq(struct cfg80211_registered_device *rdev,
 {
        struct ieee80211_channel *channel;
 
+       channel = rdev_freq_to_chan(rdev, freq, channel_type);
+       if (!channel || !cfg80211_can_beacon_sec_chan(&rdev->wiphy,
+                                                     channel,
+                                                     channel_type)) {
+               return -EINVAL;
+       }
+
        /*
         * Workaround for libertas (only!), it puts the interface
         * into mesh mode but doesn't implement join_mesh. Instead,
@@ -186,27 +193,20 @@ int cfg80211_set_mesh_freq(struct cfg80211_registered_device *rdev,
         * you set the channel. Note that the libertas mesh isn't
         * compatible with 802.11 mesh.
         */
-       if (!rdev->ops->join_mesh) {
-               int err;
+       if (rdev->ops->libertas_set_mesh_channel) {
+               if (channel_type != NL80211_CHAN_NO_HT)
+                       return -EINVAL;
 
                if (!netif_running(wdev->netdev))
                        return -ENETDOWN;
-               wdev_lock(wdev);
-               err = cfg80211_set_freq(rdev, wdev, freq, channel_type);
-               wdev_unlock(wdev);
-
-               return err;
+               return rdev->ops->libertas_set_mesh_channel(&rdev->wiphy,
+                                                           wdev->netdev,
+                                                           channel);
        }
 
        if (wdev->mesh_id_len)
                return -EBUSY;
 
-       channel = rdev_freq_to_chan(rdev, freq, channel_type);
-       if (!channel || !cfg80211_can_beacon_sec_chan(&rdev->wiphy,
-                                                     channel,
-                                                     channel_type)) {
-               return -EINVAL;
-       }
        wdev->preset_chan = channel;
        wdev->preset_chantype = channel_type;
        return 0;
index eb90988bbd36d4396ed2ac2094565561c5131875..da4406f11929e8235ac934ee40c04cc1b2a1547c 100644 (file)
@@ -947,8 +947,6 @@ void cfg80211_ch_switch_notify(struct net_device *dev, int freq,
        if (WARN_ON(!chan))
                goto out;
 
-       wdev->channel = chan;
-
        nl80211_ch_switch_notify(rdev, dev, freq, type, GFP_KERNEL);
 out:
        wdev_unlock(wdev);
index b22f1f876881b6c174bbd7fc14079147daeac78b..5e29bd38e7dff0f49cf27ec44cf065d628812a9c 100644 (file)
@@ -921,7 +921,7 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags,
                if (nla_put_u32(msg, i, NL80211_CMD_SET_WIPHY_NETNS))
                        goto nla_put_failure;
        }
-       if (dev->ops->set_channel || dev->ops->start_ap ||
+       if (dev->ops->set_monitor_channel || dev->ops->start_ap ||
            dev->ops->join_mesh) {
                i++;
                if (nla_put_u32(msg, i, NL80211_CMD_SET_CHANNEL))
@@ -1178,8 +1178,8 @@ static bool nl80211_can_set_dev_channel(struct wireless_dev *wdev)
         * the channel in the start-ap or join-mesh commands instead.
         *
         * Monitors are special as they are normally slaved to
-        * whatever else is going on, so they behave as though
-        * you tried setting the wiphy channel itself.
+        * whatever else is going on, so they have their own special
+        * operation to set the monitor channel if possible.
         */
        return !wdev ||
                wdev->iftype == NL80211_IFTYPE_AP ||
@@ -1217,6 +1217,10 @@ static int __nl80211_set_channel(struct cfg80211_registered_device *rdev,
        enum nl80211_channel_type channel_type = NL80211_CHAN_NO_HT;
        u32 freq;
        int result;
+       enum nl80211_iftype iftype = NL80211_IFTYPE_MONITOR;
+
+       if (wdev)
+               iftype = wdev->iftype;
 
        if (!info->attrs[NL80211_ATTR_WIPHY_FREQ])
                return -EINVAL;
@@ -1231,7 +1235,7 @@ static int __nl80211_set_channel(struct cfg80211_registered_device *rdev,
        freq = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]);
 
        mutex_lock(&rdev->devlist_mtx);
-       if (wdev) switch (wdev->iftype) {
+       switch (iftype) {
        case NL80211_IFTYPE_AP:
        case NL80211_IFTYPE_P2P_GO:
                if (wdev->beacon_interval) {
@@ -1252,12 +1256,11 @@ static int __nl80211_set_channel(struct cfg80211_registered_device *rdev,
        case NL80211_IFTYPE_MESH_POINT:
                result = cfg80211_set_mesh_freq(rdev, wdev, freq, channel_type);
                break;
+       case NL80211_IFTYPE_MONITOR:
+               result = cfg80211_set_monitor_channel(rdev, freq, channel_type);
+               break;
        default:
-               wdev_lock(wdev);
-               result = cfg80211_set_freq(rdev, wdev, freq, channel_type);
-               wdev_unlock(wdev);
-       } else {
-               result = cfg80211_set_freq(rdev, NULL, freq, channel_type);
+               result = -EINVAL;
        }
        mutex_unlock(&rdev->devlist_mtx);
 
index faeb03548aa45a1378904a5a09031ddaa6213c67..bc879833b21f91354822dcabe841cb593dea36ca 100644 (file)
@@ -802,9 +802,7 @@ static int cfg80211_wext_siwfreq(struct net_device *dev,
                if (freq == 0)
                        return -EINVAL;
                mutex_lock(&rdev->devlist_mtx);
-               wdev_lock(wdev);
-               err = cfg80211_set_freq(rdev, wdev, freq, NL80211_CHAN_NO_HT);
-               wdev_unlock(wdev);
+               err = cfg80211_set_monitor_channel(rdev, freq, NL80211_CHAN_NO_HT);
                mutex_unlock(&rdev->devlist_mtx);
                return err;
        case NL80211_IFTYPE_MESH_POINT:
@@ -848,11 +846,7 @@ static int cfg80211_wext_giwfreq(struct net_device *dev,
                freq->e = 6;
                return 0;
        default:
-               if (!wdev->channel)
-                       return -EINVAL;
-               freq->m = wdev->channel->center_freq;
-               freq->e = 6;
-               return 0;
+               return -EINVAL;
        }
 }
 
index 7decbd357d516161c0c659a093d9066926daac4b..1f773f668d1a557ae2712195ed510c3b9a2405b3 100644 (file)
@@ -111,9 +111,15 @@ int cfg80211_mgd_wext_siwfreq(struct net_device *dev,
 
        wdev->wext.connect.channel = chan;
 
-       /* SSID is not set, we just want to switch channel */
+       /*
+        * SSID is not set, we just want to switch monitor channel,
+        * this is really just backward compatibility, if the SSID
+        * is set then we use the channel to select the BSS to use
+        * to connect to instead. If we were connected on another
+        * channel we disconnected above and reconnect below.
+        */
        if (chan && !wdev->wext.connect.ssid_len) {
-               err = cfg80211_set_freq(rdev, wdev, freq, NL80211_CHAN_NO_HT);
+               err = cfg80211_set_monitor_channel(rdev, freq, NL80211_CHAN_NO_HT);
                goto out;
        }