|
@@ -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)
|