cfg80211: Extend support for IEEE 802.11r Fast BSS Transition
authorJouni Malinen <jouni@qca.qualcomm.com>
Wed, 27 Feb 2013 15:14:27 +0000 (17:14 +0200)
committerJohannes Berg <johannes.berg@intel.com>
Wed, 6 Mar 2013 15:35:51 +0000 (16:35 +0100)
Add NL80211_CMD_UPDATE_FT_IES to support update of FT IEs to the WLAN
driver and NL80211_CMD_FT_EVENT to send FT events from the WLAN driver.
This will carry the target AP's MAC address along with the relevant
Information Elements. This event is used to report received FT IEs
(MDIE, FTIE, RSN IE, TIE, RICIE). These changes allow FT to be supported
with drivers that use an internal SME instead of user space option (like
FT implementation in wpa_supplicant with mac80211-based drivers).

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 73a523901c736981ca4e8f17742d90b06251a177..dfef0d5b5d3d801ee5ce4e4509cb1eb67e560fca 100644 (file)
@@ -1762,6 +1762,21 @@ struct cfg80211_gtk_rekey_data {
        u8 replay_ctr[NL80211_REPLAY_CTR_LEN];
 };
 
+/**
+ * struct cfg80211_update_ft_ies_params - FT IE Information
+ *
+ * This structure provides information needed to update the fast transition IE
+ *
+ * @md: The Mobility Domain ID, 2 Octet value
+ * @ie: Fast Transition IEs
+ * @ie_len: Length of ft_ie in octets
+ */
+struct cfg80211_update_ft_ies_params {
+       u16 md;
+       const u8 *ie;
+       size_t ie_len;
+};
+
 /**
  * struct cfg80211_ops - backend description for wireless configuration
  *
@@ -2208,6 +2223,8 @@ struct cfg80211_ops {
        int     (*start_radar_detection)(struct wiphy *wiphy,
                                         struct net_device *dev,
                                         struct cfg80211_chan_def *chandef);
+       int     (*update_ft_ies)(struct wiphy *wiphy, struct net_device *dev,
+                                struct cfg80211_update_ft_ies_params *ftie);
 };
 
 /*
@@ -4044,6 +4061,30 @@ u32 cfg80211_calculate_bitrate(struct rate_info *rate);
  */
 void cfg80211_unregister_wdev(struct wireless_dev *wdev);
 
+/**
+ * struct cfg80211_ft_event - FT Information Elements
+ * @ies: FT IEs
+ * @ies_len: length of the FT IE in bytes
+ * @target_ap: target AP's MAC address
+ * @ric_ies: RIC IE
+ * @ric_ies_len: length of the RIC IE in bytes
+ */
+struct cfg80211_ft_event_params {
+       const u8 *ies;
+       size_t ies_len;
+       const u8 *target_ap;
+       const u8 *ric_ies;
+       size_t ric_ies_len;
+};
+
+/**
+ * cfg80211_ft_event - notify userspace about FT IE and RIC IE
+ * @netdev: network device
+ * @ft_event: IE information
+ */
+void cfg80211_ft_event(struct net_device *netdev,
+                      struct cfg80211_ft_event_params *ft_event);
+
 /**
  * cfg80211_get_p2p_attr - find and copy a P2P attribute from IE buffer
  * @ies: the input IE buffer
index 2c3e88360037fbe1c73a7ae6ebff7bc819bfd885..2d0cff57ff8985aa50254475c05ca3450576f442 100644 (file)
  *     i.e. features for the nl80211 protocol rather than device features.
  *     Returns the features in the %NL80211_ATTR_PROTOCOL_FEATURES bitmap.
  *
+ * @NL80211_CMD_UPDATE_FT_IES: Pass down the most up-to-date Fast Transition
+ *     Information Element to the WLAN driver
+ *
+ * @NL80211_CMD_FT_EVENT: Send a Fast transition event from the WLAN driver
+ *     to the supplicant. This will carry the target AP's MAC address along
+ *     with the relevant Information Elements. This event is used to report
+ *     received FT IEs (MDIE, FTIE, RSN IE, TIE, RICIE).
+ *
  * @NL80211_CMD_MAX: highest used command number
  * @__NL80211_CMD_AFTER_LAST: internal use
  */
@@ -785,6 +793,9 @@ enum nl80211_commands {
 
        NL80211_CMD_GET_PROTOCOL_FEATURES,
 
+       NL80211_CMD_UPDATE_FT_IES,
+       NL80211_CMD_FT_EVENT,
+
        /* add new commands above here */
 
        /* used to define NL80211_CMD_MAX below */
@@ -1396,6 +1407,11 @@ enum nl80211_commands {
  *     receiving the data for a single wiphy split across multiple
  *     messages, given with wiphy dump message
  *
+ * @NL80211_ATTR_MDID: Mobility Domain Identifier
+ *
+ * @NL80211_ATTR_IE_RIC: Resource Information Container Information
+ *     Element
+ *
  * @NL80211_ATTR_MAX: highest attribute number currently defined
  * @__NL80211_ATTR_AFTER_LAST: internal use
  */
@@ -1688,6 +1704,9 @@ enum nl80211_attrs {
        NL80211_ATTR_DISABLE_VHT,
        NL80211_ATTR_VHT_CAPABILITY_MASK,
 
+       NL80211_ATTR_MDID,
+       NL80211_ATTR_IE_RIC,
+
        /* add attributes here, update the policy in nl80211.c */
 
        __NL80211_ATTR_AFTER_LAST,
index a8bd453d22b946cb39e2f65a95996aa92a2a2180..08de0c6035f1ca88255d8f7f93583dc9a68416b1 100644 (file)
@@ -375,6 +375,9 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = {
        [NL80211_ATTR_VHT_CAPABILITY_MASK] = {
                .len = NL80211_VHT_CAPABILITY_LEN,
        },
+       [NL80211_ATTR_MDID] = { .type = NLA_U16 },
+       [NL80211_ATTR_IE_RIC] = { .type = NLA_BINARY,
+                                 .len = IEEE80211_MAX_DATA_LEN },
 };
 
 /* policy for the key attributes */
@@ -8160,6 +8163,27 @@ static int nl80211_get_protocol_features(struct sk_buff *skb,
        return -ENOBUFS;
 }
 
+static int nl80211_update_ft_ies(struct sk_buff *skb, struct genl_info *info)
+{
+       struct cfg80211_registered_device *rdev = info->user_ptr[0];
+       struct cfg80211_update_ft_ies_params ft_params;
+       struct net_device *dev = info->user_ptr[1];
+
+       if (!rdev->ops->update_ft_ies)
+               return -EOPNOTSUPP;
+
+       if (!info->attrs[NL80211_ATTR_MDID] ||
+           !is_valid_ie_attr(info->attrs[NL80211_ATTR_IE]))
+               return -EINVAL;
+
+       memset(&ft_params, 0, sizeof(ft_params));
+       ft_params.md = nla_get_u16(info->attrs[NL80211_ATTR_MDID]);
+       ft_params.ie = nla_data(info->attrs[NL80211_ATTR_IE]);
+       ft_params.ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);
+
+       return rdev_update_ft_ies(rdev, dev, &ft_params);
+}
+
 #define NL80211_FLAG_NEED_WIPHY                0x01
 #define NL80211_FLAG_NEED_NETDEV       0x02
 #define NL80211_FLAG_NEED_RTNL         0x04
@@ -8841,6 +8865,14 @@ static struct genl_ops nl80211_ops[] = {
                .doit = nl80211_get_protocol_features,
                .policy = nl80211_policy,
        },
+       {
+               .cmd = NL80211_CMD_UPDATE_FT_IES,
+               .doit = nl80211_update_ft_ies,
+               .policy = nl80211_policy,
+               .flags = GENL_ADMIN_PERM,
+               .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
+                                 NL80211_FLAG_NEED_RTNL,
+       },
 };
 
 static struct genl_multicast_group nl80211_mlme_mcgrp = {
@@ -10542,6 +10574,50 @@ static struct notifier_block nl80211_netlink_notifier = {
        .notifier_call = nl80211_netlink_notify,
 };
 
+void cfg80211_ft_event(struct net_device *netdev,
+                      struct cfg80211_ft_event_params *ft_event)
+{
+       struct wiphy *wiphy = netdev->ieee80211_ptr->wiphy;
+       struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
+       struct sk_buff *msg;
+       void *hdr;
+       int err;
+
+       trace_cfg80211_ft_event(wiphy, netdev, ft_event);
+
+       if (!ft_event->target_ap)
+               return;
+
+       msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
+       if (!msg)
+               return;
+
+       hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_FT_EVENT);
+       if (!hdr) {
+               nlmsg_free(msg);
+               return;
+       }
+
+       nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx);
+       nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex);
+       nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, ft_event->target_ap);
+       if (ft_event->ies)
+               nla_put(msg, NL80211_ATTR_IE, ft_event->ies_len, ft_event->ies);
+       if (ft_event->ric_ies)
+               nla_put(msg, NL80211_ATTR_IE_RIC, ft_event->ric_ies_len,
+                       ft_event->ric_ies);
+
+       err = genlmsg_end(msg, hdr);
+       if (err < 0) {
+               nlmsg_free(msg);
+               return;
+       }
+
+       genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0,
+                               nl80211_mlme_mcgrp.id, GFP_KERNEL);
+}
+EXPORT_SYMBOL(cfg80211_ft_event);
+
 /* initialisation/exit functions */
 
 int nl80211_init(void)
index 422d38291d66e3eb00c8cf2cdb5b9369182530fd..8c8b26f574e85cc37bb53e95a0a088c781efbf0b 100644 (file)
@@ -887,4 +887,17 @@ static inline int rdev_set_mac_acl(struct cfg80211_registered_device *rdev,
        trace_rdev_return_int(&rdev->wiphy, ret);
        return ret;
 }
+
+static inline int rdev_update_ft_ies(struct cfg80211_registered_device *rdev,
+                                    struct net_device *dev,
+                                    struct cfg80211_update_ft_ies_params *ftie)
+{
+       int ret;
+
+       trace_rdev_update_ft_ies(&rdev->wiphy, dev, ftie);
+       ret = rdev->ops->update_ft_ies(&rdev->wiphy, dev, ftie);
+       trace_rdev_return_int(&rdev->wiphy, ret);
+       return ret;
+}
+
 #endif /* __CFG80211_RDEV_OPS */
index b7a531380e19d5bf879f2395eee1176a1abfac93..ccadef2106ac9626d4690e996e54579cbd9fb2c4 100644 (file)
@@ -1785,6 +1785,26 @@ TRACE_EVENT(rdev_set_mac_acl,
                  WIPHY_PR_ARG, NETDEV_PR_ARG, __entry->acl_policy)
 );
 
+TRACE_EVENT(rdev_update_ft_ies,
+       TP_PROTO(struct wiphy *wiphy, struct net_device *netdev,
+                struct cfg80211_update_ft_ies_params *ftie),
+       TP_ARGS(wiphy, netdev, ftie),
+       TP_STRUCT__entry(
+               WIPHY_ENTRY
+               NETDEV_ENTRY
+               __field(u16, md)
+               __dynamic_array(u8, ie, ftie->ie_len)
+       ),
+       TP_fast_assign(
+               WIPHY_ASSIGN;
+               NETDEV_ASSIGN;
+               __entry->md = ftie->md;
+               memcpy(__get_dynamic_array(ie), ftie->ie, ftie->ie_len);
+       ),
+       TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", md: 0x%x",
+                 WIPHY_PR_ARG, NETDEV_PR_ARG, __entry->md)
+);
+
 /*************************************************************
  *          cfg80211 exported functions traces              *
  *************************************************************/
@@ -2413,6 +2433,32 @@ TRACE_EVENT(cfg80211_report_wowlan_wakeup,
        TP_printk(WIPHY_PR_FMT ", " WDEV_PR_FMT, WIPHY_PR_ARG, WDEV_PR_ARG)
 );
 
+TRACE_EVENT(cfg80211_ft_event,
+       TP_PROTO(struct wiphy *wiphy, struct net_device *netdev,
+                struct cfg80211_ft_event_params *ft_event),
+       TP_ARGS(wiphy, netdev, ft_event),
+       TP_STRUCT__entry(
+               WIPHY_ENTRY
+               NETDEV_ENTRY
+               __dynamic_array(u8, ies, ft_event->ies_len)
+               MAC_ENTRY(target_ap)
+               __dynamic_array(u8, ric_ies, ft_event->ric_ies_len)
+       ),
+       TP_fast_assign(
+               WIPHY_ASSIGN;
+               NETDEV_ASSIGN;
+               if (ft_event->ies)
+                       memcpy(__get_dynamic_array(ies), ft_event->ies,
+                              ft_event->ies_len);
+               MAC_ASSIGN(target_ap, ft_event->target_ap);
+               if (ft_event->ric_ies)
+                       memcpy(__get_dynamic_array(ric_ies), ft_event->ric_ies,
+                              ft_event->ric_ies_len);
+       ),
+       TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", target_ap: " MAC_PR_FMT,
+                 WIPHY_PR_ARG, NETDEV_PR_ARG, MAC_PR_ARG(target_ap))
+);
+
 #endif /* !__RDEV_OPS_TRACE || TRACE_HEADER_MULTI_READ */
 
 #undef TRACE_INCLUDE_PATH