cfg80211: Add support to update connection parameters
authorvamsi krishna <vamsin@qti.qualcomm.com>
Thu, 27 Oct 2016 13:51:11 +0000 (16:51 +0300)
committerJohannes Berg <johannes.berg@intel.com>
Thu, 27 Oct 2016 14:03:28 +0000 (16:03 +0200)
Add functionality to update the connection parameters when in connected
state, so that driver/firmware uses the updated parameters for
subsequent roaming. This is for drivers that support internal BSS
selection and roaming. The new command does not change the current
association state, i.e., it can be used to update IE contents for future
(re)associations without causing an immediate disassociation or
reassociation with the current BSS.

This commit implements the required functionality for updating IEs for
(Re)Association Request frame only. Other parameters can be added in
future when required.

Signed-off-by: vamsi krishna <vamsin@qti.qualcomm.com>
Signed-off-by: Jouni Malinen <jouni@qca.qualcomm.com>
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
include/net/cfg80211.h
include/uapi/linux/nl80211.h
net/wireless/nl80211.c
net/wireless/rdev-ops.h
net/wireless/trace.h

index 41ae3f500957a0f921af47922b71101717bc541b..c575583b50fbd460cebad105c4ba2b4674130a81 100644 (file)
@@ -2050,6 +2050,18 @@ struct cfg80211_connect_params {
        const u8 *prev_bssid;
 };
 
+/**
+ * enum cfg80211_connect_params_changed - Connection parameters being updated
+ *
+ * This enum provides information of all connect parameters that
+ * have to be updated as part of update_connect_params() call.
+ *
+ * @UPDATE_ASSOC_IES: Indicates whether association request IEs are updated
+ */
+enum cfg80211_connect_params_changed {
+       UPDATE_ASSOC_IES                = BIT(0),
+};
+
 /**
  * enum wiphy_params_flags - set_wiphy_params bitfield values
  * @WIPHY_PARAM_RETRY_SHORT: wiphy->retry_short has changed
@@ -2571,6 +2583,14 @@ struct cfg80211_nan_func {
  *     cases, the result of roaming is indicated with a call to
  *     cfg80211_roamed() or cfg80211_roamed_bss().
  *     (invoked with the wireless_dev mutex held)
+ * @update_connect_params: Update the connect parameters while connected to a
+ *     BSS. The updated parameters can be used by driver/firmware for
+ *     subsequent BSS selection (roaming) decisions and to form the
+ *     Authentication/(Re)Association Request frames. This call does not
+ *     request an immediate disassociation or reassociation with the current
+ *     BSS, i.e., this impacts only subsequent (re)associations. The bits in
+ *     changed are defined in &enum cfg80211_connect_params_changed.
+ *     (invoked with the wireless_dev mutex held)
  * @disconnect: Disconnect from the BSS/ESS or stop connection attempts if
  *      connection is in progress. Once done, call cfg80211_disconnected() in
  *      case connection was already established (invoked with the
@@ -2858,6 +2878,10 @@ struct cfg80211_ops {
 
        int     (*connect)(struct wiphy *wiphy, struct net_device *dev,
                           struct cfg80211_connect_params *sme);
+       int     (*update_connect_params)(struct wiphy *wiphy,
+                                        struct net_device *dev,
+                                        struct cfg80211_connect_params *sme,
+                                        u32 changed);
        int     (*disconnect)(struct wiphy *wiphy, struct net_device *dev,
                              u16 reason_code);
 
index e21d23dcb588b4eac8f1e334193c25560ad46265..259c9c77fdc1cc8505e36ae06d29f66a8e005bf4 100644 (file)
  *     This will contain a %NL80211_ATTR_NAN_MATCH nested attribute and
  *     %NL80211_ATTR_COOKIE.
  *
+ * @NL80211_CMD_UPDATE_CONNECT_PARAMS: Update one or more connect parameters
+ *     for subsequent roaming cases if the driver or firmware uses internal
+ *     BSS selection. This command can be issued only while connected and it
+ *     does not result in a change for the current association. Currently,
+ *     only the %NL80211_ATTR_IE data is used and updated with this command.
+ *
  * @NL80211_CMD_MAX: highest used command number
  * @__NL80211_CMD_AFTER_LAST: internal use
  */
@@ -1085,6 +1091,8 @@ enum nl80211_commands {
 
        NL80211_CMD_SET_MULTICAST_TO_UNICAST,
 
+       NL80211_CMD_UPDATE_CONNECT_PARAMS,
+
        /* add new commands above here */
 
        /* used to define NL80211_CMD_MAX below */
index 0c9d00c9cef18c260ac68603e791a85d874c88f8..bb30fa1969f9a27002aef9b0c2a533bf4df9b7eb 100644 (file)
@@ -1661,6 +1661,7 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *rdev,
                                        NL80211_FEATURE_SUPPORTS_WMM_ADMISSION)
                                CMD(add_tx_ts, ADD_TX_TS);
                        CMD(set_multicast_to_unicast, SET_MULTICAST_TO_UNICAST);
+                       CMD(update_connect_params, UPDATE_CONNECT_PARAMS);
                }
 #undef CMD
 
@@ -8779,6 +8780,37 @@ static int nl80211_connect(struct sk_buff *skb, struct genl_info *info)
        return err;
 }
 
+static int nl80211_update_connect_params(struct sk_buff *skb,
+                                        struct genl_info *info)
+{
+       struct cfg80211_connect_params connect = {};
+       struct cfg80211_registered_device *rdev = info->user_ptr[0];
+       struct net_device *dev = info->user_ptr[1];
+       struct wireless_dev *wdev = dev->ieee80211_ptr;
+       u32 changed = 0;
+       int ret;
+
+       if (!rdev->ops->update_connect_params)
+               return -EOPNOTSUPP;
+
+       if (info->attrs[NL80211_ATTR_IE]) {
+               if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE]))
+                       return -EINVAL;
+               connect.ie = nla_data(info->attrs[NL80211_ATTR_IE]);
+               connect.ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);
+               changed |= UPDATE_ASSOC_IES;
+       }
+
+       wdev_lock(dev->ieee80211_ptr);
+       if (!wdev->current_bss)
+               ret = -ENOLINK;
+       else
+               ret = rdev_update_connect_params(rdev, dev, &connect, changed);
+       wdev_unlock(dev->ieee80211_ptr);
+
+       return ret;
+}
+
 static int nl80211_disconnect(struct sk_buff *skb, struct genl_info *info)
 {
        struct cfg80211_registered_device *rdev = info->user_ptr[0];
@@ -12231,6 +12263,14 @@ static const struct genl_ops nl80211_ops[] = {
                .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
                                  NL80211_FLAG_NEED_RTNL,
        },
+       {
+               .cmd = NL80211_CMD_UPDATE_CONNECT_PARAMS,
+               .doit = nl80211_update_connect_params,
+               .policy = nl80211_policy,
+               .flags = GENL_ADMIN_PERM,
+               .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
+                                 NL80211_FLAG_NEED_RTNL,
+       },
        {
                .cmd = NL80211_CMD_DISCONNECT,
                .doit = nl80211_disconnect,
index e9ecf23e7942cbcdd1040cf1337218df692a6ab6..2f425075ada8eae81c8ecb04d975d0c9f0d36578 100644 (file)
@@ -490,6 +490,18 @@ static inline int rdev_connect(struct cfg80211_registered_device *rdev,
        return ret;
 }
 
+static inline int
+rdev_update_connect_params(struct cfg80211_registered_device *rdev,
+                          struct net_device *dev,
+                          struct cfg80211_connect_params *sme, u32 changed)
+{
+       int ret;
+       trace_rdev_update_connect_params(&rdev->wiphy, dev, sme, changed);
+       ret = rdev->ops->update_connect_params(&rdev->wiphy, dev, sme, changed);
+       trace_rdev_return_int(&rdev->wiphy, ret);
+       return ret;
+}
+
 static inline int rdev_disconnect(struct cfg80211_registered_device *rdev,
                                  struct net_device *dev, u16 reason_code)
 {
index 25f8318b3e0b499ed554dfa1ee7fa0095e9043b4..ea1b47e04fa474b601bd34a77d1e6cc05cf0e176 100644 (file)
@@ -1281,6 +1281,24 @@ TRACE_EVENT(rdev_connect,
                  __entry->wpa_versions, __entry->flags, MAC_PR_ARG(prev_bssid))
 );
 
+TRACE_EVENT(rdev_update_connect_params,
+       TP_PROTO(struct wiphy *wiphy, struct net_device *netdev,
+                struct cfg80211_connect_params *sme, u32 changed),
+       TP_ARGS(wiphy, netdev, sme, changed),
+       TP_STRUCT__entry(
+               WIPHY_ENTRY
+               NETDEV_ENTRY
+               __field(u32, changed)
+       ),
+       TP_fast_assign(
+               WIPHY_ASSIGN;
+               NETDEV_ASSIGN;
+               __entry->changed = changed;
+       ),
+       TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", parameters changed: %u",
+                 WIPHY_PR_ARG, NETDEV_PR_ARG,  __entry->changed)
+);
+
 TRACE_EVENT(rdev_set_cqm_rssi_config,
        TP_PROTO(struct wiphy *wiphy,
                 struct net_device *netdev, s32 rssi_thold,