From 64b33e75a0b34e0eae8eb17637e1eb1328e6c27a Mon Sep 17 00:00:00 2001 From: Sunil Dutt Date: Wed, 9 Jan 2019 22:12:29 +0530 Subject: [PATCH] cfg80211/nl80211: Offload OWE processing to user space This interface allows the host driver to offload OWE processing to user space. This intends to support OWE/Enhanced Open AKM by the host drivers that implement SME but rely on the user space for the crypotographic/OWE processing.Such drivers are not capable of processing/deriving the DH IE's. This interface acts as both the event from the driver to userspace and a command from userspace to the driver. Host driver shall use the event to notify the OWE info of the peer to the userspace for the cryptographic processing of the DH ie's. Accordingly, the userspace shall update the OWE info/DH ie's to the host driver corresponding to the peer. Above sequence aims for the AP mode where the event carries the OWE info of the peer(STA) obtained in the Assoc Request. The request interface from the userspace shall update the OWE info to the host driver, which is used to send the Assoc response to the peer. This OWE info in the command interface shall contain the ie's which either include the pmkid of the peer if the PMKSA is still valid or an updated DH ie's for generating a new PMKSA with the peer. Change-Id: Id5a2e800bdae1ea31a20a062d012cc33e5a3c6a3 CRs-Fixed: 2414077 Signed-off-by: Liangwei Dong Signed-off-by: Sunil Dutt --- include/net/cfg80211.h | 41 +++++++++++++++++++ include/uapi/linux/nl80211.h | 6 +++ net/wireless/nl80211.c | 79 ++++++++++++++++++++++++++++++++++++ net/wireless/rdev-ops.h | 12 ++++++ net/wireless/trace.h | 37 +++++++++++++++++ 5 files changed, 175 insertions(+) diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 82d2cab4f1b8..0014bbc5bcb9 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -2426,6 +2426,31 @@ struct cfg80211_external_auth_params { const u8 *pmkid; }; +/** + * struct cfg80211_update_owe_info - OWE Information + * + * This structure provides information needed for the drivers to offload OWE + * (Oppurtunistic Wireless Encryption) processing to the user space. + * + * Commonly used across update_owe request and event interfaces. + * + * @bssid: BSSID of the peer from which the OWE processing has to be done. + * @status: status code, %WLAN_STATUS_SUCCESS for successful OWE info + * processing, use %WLAN_STATUS_UNSPECIFIED_FAILURE if user space + * cannot give you the real status code for failures. Used only for + * OWE update response command interface (user space to driver). + * @ie: IE's obtained from the peer or constructed by the user space. These are + * the IE's of the remote peer in the event from the host driver and + * the constructed IE's by the user space in the request interface. + * @ie_len: Length of IE's in octets. + */ +struct cfg80211_update_owe_info { + u8 bssid[ETH_ALEN] __aligned(2); + u16 status; + const u8 *ie; + size_t ie_len; +}; + /** * struct cfg80211_ops - backend description for wireless configuration * @@ -2724,6 +2749,10 @@ struct cfg80211_external_auth_params { * * @external_auth: indicates result of offloaded authentication processing from * user space + * + * @update_owe_info: Provide updated OWE info to driver. Driver implementing SME + * but offloading the OWE processing to the user space will get the updated + * DH IE's (from the IE's) obtained through this interface. */ struct cfg80211_ops { int (*suspend)(struct wiphy *wiphy, struct cfg80211_wowlan *wow); @@ -2995,6 +3024,8 @@ struct cfg80211_ops { const u8 *addr); int (*external_auth)(struct wiphy *wiphy, struct net_device *dev, struct cfg80211_external_auth_params *params); + int (*update_owe_info)(struct wiphy *wiphy, struct net_device *dev, + struct cfg80211_update_owe_info *owe_info); }; /* @@ -5886,4 +5917,14 @@ int cfg80211_external_auth_request(struct net_device *netdev, */ #define CFG80211_REMOVE_IEEE80211_BACKPORT 1 +/** + * cfg80211_update_owe_info_event - Notify the peer's OWE info to user space + * @netdev: network device + * @owe_info: peer's owe info + * @gfp: allocation flags + */ +void cfg80211_update_owe_info_event(struct net_device *netdev, + struct cfg80211_update_owe_info *owe_info, + gfp_t gfp); + #endif /* __NET_CFG80211_H */ diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h index ed9104095660..a704fbf49165 100644 --- a/include/uapi/linux/nl80211.h +++ b/include/uapi/linux/nl80211.h @@ -990,6 +990,11 @@ * indicated by %NL80211_ATTR_WIPHY_FREQ and other attributes * determining the width and type. * + * @NL80211_CMD_UPDATE_OWE_INFO: This interface allows the host driver to + * offload OWE processing to user space. This intends to support + * OWE/Enhanced Open AKM by the host drivers that implemnt SME but rely + * on the user space for the crypotographic/DH IE processing. + * * @NL80211_CMD_MAX: highest used command number * @__NL80211_CMD_AFTER_LAST: internal use */ @@ -1210,6 +1215,7 @@ enum nl80211_commands { NL80211_CMD_NOTIFY_RADAR, + NL80211_CMD_UPDATE_OWE_INFO, /* add new commands above here */ /* used to define NL80211_CMD_MAX below */ diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index c4413fb699ab..8510d96b431e 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -11212,6 +11212,34 @@ static int nl80211_external_auth(struct sk_buff *skb, struct genl_info *info) return rdev_external_auth(rdev, dev, ¶ms); } +static int nl80211_update_owe_info(struct sk_buff *skb, struct genl_info *info) +{ + struct cfg80211_registered_device *rdev = info->user_ptr[0]; + struct cfg80211_update_owe_info owe_info; + struct net_device *dev = info->user_ptr[1]; + + if (!rdev->ops->update_owe_info) + return -EOPNOTSUPP; + + if (!info->attrs[NL80211_ATTR_STATUS_CODE] || + (info->attrs[NL80211_ATTR_IE] && + !is_valid_ie_attr(info->attrs[NL80211_ATTR_IE]))) + return -EINVAL; + + memset(&owe_info, 0, sizeof(owe_info)); + owe_info.status = + nla_get_u16(info->attrs[NL80211_ATTR_STATUS_CODE]); + if (info->attrs[NL80211_ATTR_MAC]) + nla_memcpy(owe_info.bssid, info->attrs[NL80211_ATTR_MAC], + ETH_ALEN); + if (info->attrs[NL80211_ATTR_IE]) { + owe_info.ie = nla_data(info->attrs[NL80211_ATTR_IE]); + owe_info.ie_len = nla_len(info->attrs[NL80211_ATTR_IE]); + } + + return rdev_update_owe_info(rdev, dev, &owe_info); +} + #define NL80211_FLAG_NEED_WIPHY 0x01 #define NL80211_FLAG_NEED_NETDEV 0x02 #define NL80211_FLAG_NEED_RTNL 0x04 @@ -12054,6 +12082,14 @@ static const struct genl_ops nl80211_ops[] = { .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | NL80211_FLAG_NEED_RTNL, }, + { + .cmd = NL80211_CMD_UPDATE_OWE_INFO, + .doit = nl80211_update_owe_info, + .policy = nl80211_policy, + .flags = GENL_ADMIN_PERM, + .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | + NL80211_FLAG_NEED_RTNL, + }, }; /* notification functions */ @@ -14048,6 +14084,49 @@ int cfg80211_external_auth_request(struct net_device *dev, } EXPORT_SYMBOL(cfg80211_external_auth_request); +void cfg80211_update_owe_info_event(struct net_device *netdev, + struct cfg80211_update_owe_info *owe_info, + gfp_t gfp) +{ + struct wiphy *wiphy = netdev->ieee80211_ptr->wiphy; + struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy); + struct sk_buff *msg; + void *hdr; + + trace_cfg80211_update_owe_info_event(wiphy, netdev, owe_info); + + if (!owe_info) + return; + + msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp); + if (!msg) + return; + + hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_UPDATE_OWE_INFO); + if (!hdr) + goto nla_put_failure; + + if (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, owe_info->bssid)) + goto nla_put_failure; + + if (nla_put(msg, NL80211_ATTR_IE, owe_info->ie_len, owe_info->ie)) + goto nla_put_failure; + + genlmsg_end(msg, hdr); + + genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0, + NL80211_MCGRP_MLME, gfp); + return; + +nla_put_failure: + if (hdr) + genlmsg_cancel(msg, hdr); + nlmsg_free(msg); +} +EXPORT_SYMBOL(cfg80211_update_owe_info_event); + /* initialisation/exit functions */ int nl80211_init(void) diff --git a/net/wireless/rdev-ops.h b/net/wireless/rdev-ops.h index aef08a0f51f3..5cfd2634dafd 100644 --- a/net/wireless/rdev-ops.h +++ b/net/wireless/rdev-ops.h @@ -1054,4 +1054,16 @@ rdev_external_auth(struct cfg80211_registered_device *rdev, return ret; } +static inline int rdev_update_owe_info(struct cfg80211_registered_device *rdev, + struct net_device *dev, + struct cfg80211_update_owe_info *oweinfo) +{ + int ret; + + trace_rdev_update_owe_info(&rdev->wiphy, dev, oweinfo); + ret = rdev->ops->update_owe_info(&rdev->wiphy, dev, oweinfo); + trace_rdev_return_int(&rdev->wiphy, ret); + return ret; +} + #endif /* __CFG80211_RDEV_OPS */ diff --git a/net/wireless/trace.h b/net/wireless/trace.h index 54787c95b4ee..1341ff3d966e 100644 --- a/net/wireless/trace.h +++ b/net/wireless/trace.h @@ -2866,6 +2866,43 @@ TRACE_EVENT(cfg80211_stop_iface, WIPHY_PR_ARG, WDEV_PR_ARG) ); +TRACE_EVENT(rdev_update_owe_info, + TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, + struct cfg80211_update_owe_info *owe_info), + TP_ARGS(wiphy, netdev, owe_info), + TP_STRUCT__entry(WIPHY_ENTRY + NETDEV_ENTRY + MAC_ENTRY(bssid) + __field(u16, status) + __dynamic_array(u8, ie, owe_info->ie_len)), + TP_fast_assign(WIPHY_ASSIGN; + NETDEV_ASSIGN; + MAC_ASSIGN(bssid, owe_info->bssid); + __entry->status = owe_info->status; + memcpy(__get_dynamic_array(ie), + owe_info->ie, owe_info->ie_len);), + TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", peer: " MAC_PR_FMT + " status %d", WIPHY_PR_ARG, NETDEV_PR_ARG, MAC_PR_ARG(bssid), + __entry->status) +); + +TRACE_EVENT(cfg80211_update_owe_info_event, + TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, + struct cfg80211_update_owe_info *owe_info), + TP_ARGS(wiphy, netdev, owe_info), + TP_STRUCT__entry(WIPHY_ENTRY + NETDEV_ENTRY + MAC_ENTRY(bssid) + __dynamic_array(u8, ie, owe_info->ie_len)), + TP_fast_assign(WIPHY_ASSIGN; + NETDEV_ASSIGN; + MAC_ASSIGN(bssid, owe_info->bssid); + memcpy(__get_dynamic_array(ie), owe_info->ie, + owe_info->ie_len);), + TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", peer: " MAC_PR_FMT, + WIPHY_PR_ARG, NETDEV_PR_ARG, MAC_PR_ARG(bssid)) +); + #endif /* !__RDEV_OPS_TRACE || TRACE_HEADER_MULTI_READ */ #undef TRACE_INCLUDE_PATH