From 5037a00992e5fcb3d8509964313565a3dab6697c Mon Sep 17 00:00:00 2001 From: Sunil Dutt Date: Thu, 25 Jan 2018 17:13:37 +0200 Subject: nl80211: Introduce scan flags to emphasize requested scan behavior This commit defines new scan flags (LOW_SPAN, LOW_POWER, HIGH_LATENCY) to emphasize the requested scan behavior for the driver. These flags are optional and are mutually exclusive. The implementation of the respective functionality can be driver/hardware specific. These flags can be used to control the compromise between how long a scan takes, how much power it uses, and high accurate/complete the scan is in finding the BSSs. Signed-off-by: Sunil Dutt Signed-off-by: Jouni Malinen Signed-off-by: Johannes Berg --- include/uapi/linux/nl80211.h | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h index c587a61c32bf..6f60503fa617 100644 --- a/include/uapi/linux/nl80211.h +++ b/include/uapi/linux/nl80211.h @@ -4945,6 +4945,9 @@ enum nl80211_feature_flags { * probe request tx deferral and suppression * @NL80211_EXT_FEATURE_MFP_OPTIONAL: Driver supports the %NL80211_MFP_OPTIONAL * value in %NL80211_ATTR_USE_MFP. + * @NL80211_EXT_FEATURE_LOW_SPAN_SCAN: Driver supports low span scan. + * @NL80211_EXT_FEATURE_LOW_POWER_SCAN: Driver supports low power scan. + * @NL80211_EXT_FEATURE_HIGH_ACCURACY_SCAN: Driver supports high accuracy scan. * * @NUM_NL80211_EXT_FEATURES: number of extended features. * @MAX_NL80211_EXT_FEATURES: highest extended feature index. @@ -4972,6 +4975,9 @@ enum nl80211_ext_feature_index { NL80211_EXT_FEATURE_OCE_PROBE_REQ_HIGH_TX_RATE, NL80211_EXT_FEATURE_OCE_PROBE_REQ_DEFERRAL_SUPPRESSION, NL80211_EXT_FEATURE_MFP_OPTIONAL, + NL80211_EXT_FEATURE_LOW_SPAN_SCAN, + NL80211_EXT_FEATURE_LOW_POWER_SCAN, + NL80211_EXT_FEATURE_HIGH_ACCURACY_SCAN, /* add new features before the definition below */ NUM_NL80211_EXT_FEATURES, @@ -5032,6 +5038,10 @@ enum nl80211_timeout_reason { * of NL80211_CMD_TRIGGER_SCAN and NL80211_CMD_START_SCHED_SCAN * requests. * + * NL80211_SCAN_FLAG_LOW_SPAN, NL80211_SCAN_FLAG_LOW_POWER, and + * NL80211_SCAN_FLAG_HIGH_ACCURACY flags are exclusive of each other, i.e., only + * one of them can be used in the request. + * * @NL80211_SCAN_FLAG_LOW_PRIORITY: scan request has low priority * @NL80211_SCAN_FLAG_FLUSH: flush cache before scanning * @NL80211_SCAN_FLAG_AP: force a scan even if the interface is configured @@ -5059,7 +5069,20 @@ enum nl80211_timeout_reason { * and suppression (if it has received a broadcast Probe Response frame, * Beacon frame or FILS Discovery frame from an AP that the STA considers * a suitable candidate for (re-)association - suitable in terms of - * SSID and/or RSSI + * SSID and/or RSSI. + * @NL80211_SCAN_FLAG_LOW_SPAN: Span corresponds to the total time taken to + * accomplish the scan. Thus, this flag intends the driver to perform the + * scan request with lesser span/duration. It is specific to the driver + * implementations on how this is accomplished. Scan accuracy may get + * impacted with this flag. + * @NL80211_SCAN_FLAG_LOW_POWER: This flag intends the scan attempts to consume + * optimal possible power. Drivers can resort to their specific means to + * optimize the power. Scan accuracy may get impacted with this flag. + * @NL80211_SCAN_FLAG_HIGH_ACCURACY: Accuracy here intends to the extent of scan + * results obtained. Thus HIGH_ACCURACY scan flag aims to get maximum + * possible scan results. This flag hints the driver to use the best + * possible scan configuration to improve the accuracy in scanning. + * Latency and power use may get impacted with this flag. */ enum nl80211_scan_flags { NL80211_SCAN_FLAG_LOW_PRIORITY = 1<<0, @@ -5070,6 +5093,9 @@ enum nl80211_scan_flags { NL80211_SCAN_FLAG_ACCEPT_BCAST_PROBE_RESP = 1<<5, NL80211_SCAN_FLAG_OCE_PROBE_REQ_HIGH_TX_RATE = 1<<6, NL80211_SCAN_FLAG_OCE_PROBE_REQ_DEFERRAL_SUPPRESSION = 1<<7, + NL80211_SCAN_FLAG_LOW_SPAN = 1<<8, + NL80211_SCAN_FLAG_LOW_POWER = 1<<9, + NL80211_SCAN_FLAG_HIGH_ACCURACY = 1<<10, }; /** -- cgit v1.2.3 From 40cbfa90218bc570a7959b436b9d48a18c361041 Mon Sep 17 00:00:00 2001 From: Srinivas Dasari Date: Thu, 25 Jan 2018 17:13:38 +0200 Subject: cfg80211/nl80211: Optional authentication offload to userspace This interface allows the host driver to offload the authentication to user space. This is exclusively defined for host drivers that do not define separate commands for authentication and association, but rely on userspace SME (e.g., in wpa_supplicant for the ~WPA_DRIVER_FLAGS_SME case) for the authentication to happen. This can be used to implement SAE without full implementation in the kernel/firmware while still being able to use NL80211_CMD_CONNECT with driver-based BSS selection. Host driver sends NL80211_CMD_EXTERNAL_AUTH event to start/abort authentication to the port on which connect is triggered and status of authentication is further indicated by user space to host driver through the same command response interface. User space entities advertise this capability through the NL80211_ATTR_EXTERNAL_AUTH_SUPP flag in the NL80211_CMD_CONNECT request. Host drivers shall look at this capability to offload the authentication. Signed-off-by: Srinivas Dasari Signed-off-by: Jouni Malinen [add socket connection ownership check] Signed-off-by: Johannes Berg --- include/net/cfg80211.h | 54 +++++++++++++++++++++++-- include/uapi/linux/nl80211.h | 47 ++++++++++++++++++++++ net/wireless/nl80211.c | 94 ++++++++++++++++++++++++++++++++++++++++++++ net/wireless/rdev-ops.h | 15 +++++++ net/wireless/trace.h | 23 +++++++++++ 5 files changed, 230 insertions(+), 3 deletions(-) (limited to 'include') diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 81174f9b8d14..68def3e5b013 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -1905,11 +1905,16 @@ struct cfg80211_auth_request { * @ASSOC_REQ_DISABLE_HT: Disable HT (802.11n) * @ASSOC_REQ_DISABLE_VHT: Disable VHT * @ASSOC_REQ_USE_RRM: Declare RRM capability in this association + * @CONNECT_REQ_EXTERNAL_AUTH_SUPPORT: User space indicates external + * authentication capability. Drivers can offload authentication to + * userspace if this flag is set. Only applicable for cfg80211_connect() + * request (connect callback). */ enum cfg80211_assoc_req_flags { - ASSOC_REQ_DISABLE_HT = BIT(0), - ASSOC_REQ_DISABLE_VHT = BIT(1), - ASSOC_REQ_USE_RRM = BIT(2), + ASSOC_REQ_DISABLE_HT = BIT(0), + ASSOC_REQ_DISABLE_VHT = BIT(1), + ASSOC_REQ_USE_RRM = BIT(2), + CONNECT_REQ_EXTERNAL_AUTH_SUPPORT = BIT(3), }; /** @@ -2600,6 +2605,33 @@ struct cfg80211_pmk_conf { const u8 *pmk_r0_name; }; +/** + * struct cfg80211_external_auth_params - Trigger External authentication. + * + * Commonly used across the external auth request and event interfaces. + * + * @action: action type / trigger for external authentication. Only significant + * for the authentication request event interface (driver to user space). + * @bssid: BSSID of the peer with which the authentication has + * to happen. Used by both the authentication request event and + * authentication response command interface. + * @ssid: SSID of the AP. Used by both the authentication request event and + * authentication response command interface. + * @key_mgmt_suite: AKM suite of the respective authentication. Used by the + * authentication request event interface. + * @status: status code, %WLAN_STATUS_SUCCESS for successful authentication, + * use %WLAN_STATUS_UNSPECIFIED_FAILURE if user space cannot give you + * the real status code for failures. Used only for the authentication + * response command interface (user space to driver). + */ +struct cfg80211_external_auth_params { + enum nl80211_external_auth_action action; + u8 bssid[ETH_ALEN] __aligned(2); + struct cfg80211_ssid ssid; + unsigned int key_mgmt_suite; + u16 status; +}; + /** * struct cfg80211_ops - backend description for wireless configuration * @@ -2923,6 +2955,9 @@ struct cfg80211_pmk_conf { * (invoked with the wireless_dev mutex held) * @del_pmk: delete the previously configured PMK for the given authenticator. * (invoked with the wireless_dev mutex held) + * + * @external_auth: indicates result of offloaded authentication processing from + * user space */ struct cfg80211_ops { int (*suspend)(struct wiphy *wiphy, struct cfg80211_wowlan *wow); @@ -3216,6 +3251,8 @@ struct cfg80211_ops { const struct cfg80211_pmk_conf *conf); int (*del_pmk)(struct wiphy *wiphy, struct net_device *dev, const u8 *aa); + int (*external_auth)(struct wiphy *wiphy, struct net_device *dev, + struct cfg80211_external_auth_params *params); }; /* @@ -6202,6 +6239,17 @@ void cfg80211_nan_func_terminated(struct wireless_dev *wdev, /* ethtool helper */ void cfg80211_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info); +/** + * cfg80211_external_auth_request - userspace request for authentication + * @netdev: network device + * @params: External authentication parameters + * @gfp: allocation flags + * Returns: 0 on success, < 0 on error + */ +int cfg80211_external_auth_request(struct net_device *netdev, + struct cfg80211_external_auth_params *params, + gfp_t gfp); + /* Logging, debugging and troubleshooting/diagnostic helpers. */ /* wiphy_printk helpers, similar to dev_printk */ diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h index 6f60503fa617..c2342456cf16 100644 --- a/include/uapi/linux/nl80211.h +++ b/include/uapi/linux/nl80211.h @@ -992,6 +992,27 @@ * * @NL80211_CMD_RELOAD_REGDB: Request that the regdb firmware file is reloaded. * + * @NL80211_CMD_EXTERNAL_AUTH: This interface is exclusively defined for host + * drivers that do not define separate commands for authentication and + * association, but rely on user space for the authentication to happen. + * This interface acts both as the event request (driver to user space) + * to trigger the authentication and command response (userspace to + * driver) to indicate the authentication status. + * + * User space uses the %NL80211_CMD_CONNECT command to the host driver to + * trigger a connection. The host driver selects a BSS and further uses + * this interface to offload only the authentication part to the user + * space. Authentication frames are passed between the driver and user + * space through the %NL80211_CMD_FRAME interface. Host driver proceeds + * further with the association after getting successful authentication + * status. User space indicates the authentication status through + * %NL80211_ATTR_STATUS_CODE attribute in %NL80211_CMD_EXTERNAL_AUTH + * command interface. + * + * Host driver reports this status on an authentication failure to the + * user space through the connect result as the user space would have + * initiated the connection through the connect request. + * * @NL80211_CMD_MAX: highest used command number * @__NL80211_CMD_AFTER_LAST: internal use */ @@ -1198,6 +1219,8 @@ enum nl80211_commands { NL80211_CMD_RELOAD_REGDB, + NL80211_CMD_EXTERNAL_AUTH, + /* add new commands above here */ /* used to define NL80211_CMD_MAX below */ @@ -2153,6 +2176,16 @@ enum nl80211_commands { * @NL80211_ATTR_PMKR0_NAME: PMK-R0 Name for offloaded FT. * @NL80211_ATTR_PORT_AUTHORIZED: (reserved) * + * @NL80211_ATTR_EXTERNAL_AUTH_ACTION: Identify the requested external + * authentication operation (u32 attribute with an + * &enum nl80211_external_auth_action value). This is used with the + * &NL80211_CMD_EXTERNAL_AUTH request event. + * @NL80211_ATTR_EXTERNAL_AUTH_SUPPORT: Flag attribute indicating that the user + * space supports external authentication. This attribute shall be used + * only with %NL80211_CMD_CONNECT request. The driver may offload + * authentication processing to user space if this capability is indicated + * in NL80211_CMD_CONNECT requests from the user space. + * * @NUM_NL80211_ATTR: total number of nl80211_attrs available * @NL80211_ATTR_MAX: highest attribute number currently defined * @__NL80211_ATTR_AFTER_LAST: internal use @@ -2579,6 +2612,9 @@ enum nl80211_attrs { NL80211_ATTR_PMKR0_NAME, NL80211_ATTR_PORT_AUTHORIZED, + NL80211_ATTR_EXTERNAL_AUTH_ACTION, + NL80211_ATTR_EXTERNAL_AUTH_SUPPORT, + /* add attributes here, update the policy in nl80211.c */ __NL80211_ATTR_AFTER_LAST, @@ -5495,4 +5531,15 @@ enum nl80211_nan_match_attributes { NL80211_NAN_MATCH_ATTR_MAX = NUM_NL80211_NAN_MATCH_ATTR - 1 }; +/** + * nl80211_external_auth_action - Action to perform with external + * authentication request. Used by NL80211_ATTR_EXTERNAL_AUTH_ACTION. + * @NL80211_EXTERNAL_AUTH_START: Start the authentication. + * @NL80211_EXTERNAL_AUTH_ABORT: Abort the ongoing authentication. + */ +enum nl80211_external_auth_action { + NL80211_EXTERNAL_AUTH_START, + NL80211_EXTERNAL_AUTH_ABORT, +}; + #endif /* __LINUX_NL80211_H */ diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index dd249ec9f228..aa6b64069c80 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -420,6 +420,7 @@ static const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = { [NL80211_ATTR_FILS_CACHE_ID] = { .len = 2 }, [NL80211_ATTR_PMK] = { .type = NLA_BINARY, .len = PMK_MAX_LEN }, [NL80211_ATTR_SCHED_SCAN_MULTI] = { .type = NLA_FLAG }, + [NL80211_ATTR_EXTERNAL_AUTH_SUPPORT] = { .type = NLA_FLAG }, }; /* policy for the key attributes */ @@ -9161,6 +9162,15 @@ static int nl80211_connect(struct sk_buff *skb, struct genl_info *info) return -EINVAL; } + if (nla_get_flag(info->attrs[NL80211_ATTR_EXTERNAL_AUTH_SUPPORT])) { + if (!info->attrs[NL80211_ATTR_SOCKET_OWNER]) { + GENL_SET_ERR_MSG(info, + "external auth requires connection ownership"); + return -EINVAL; + } + connect.flags |= CONNECT_REQ_EXTERNAL_AUTH_SUPPORT; + } + wdev_lock(dev->ieee80211_ptr); err = cfg80211_connect(rdev, dev, &connect, connkeys, @@ -12469,6 +12479,41 @@ static int nl80211_del_pmk(struct sk_buff *skb, struct genl_info *info) return ret; } +static int nl80211_external_auth(struct sk_buff *skb, struct genl_info *info) +{ + struct cfg80211_registered_device *rdev = info->user_ptr[0]; + struct net_device *dev = info->user_ptr[1]; + struct cfg80211_external_auth_params params; + + if (rdev->ops->external_auth) + return -EOPNOTSUPP; + + if (!info->attrs[NL80211_ATTR_SSID]) + return -EINVAL; + + if (!info->attrs[NL80211_ATTR_BSSID]) + return -EINVAL; + + if (!info->attrs[NL80211_ATTR_STATUS_CODE]) + return -EINVAL; + + memset(¶ms, 0, sizeof(params)); + + params.ssid.ssid_len = nla_len(info->attrs[NL80211_ATTR_SSID]); + if (params.ssid.ssid_len == 0 || + params.ssid.ssid_len > IEEE80211_MAX_SSID_LEN) + return -EINVAL; + memcpy(params.ssid.ssid, nla_data(info->attrs[NL80211_ATTR_SSID]), + params.ssid.ssid_len); + + memcpy(params.bssid, nla_data(info->attrs[NL80211_ATTR_BSSID]), + ETH_ALEN); + + params.status = nla_get_u16(info->attrs[NL80211_ATTR_STATUS_CODE]); + + return rdev_external_auth(rdev, dev, ¶ms); +} + #define NL80211_FLAG_NEED_WIPHY 0x01 #define NL80211_FLAG_NEED_NETDEV 0x02 #define NL80211_FLAG_NEED_RTNL 0x04 @@ -13364,6 +13409,14 @@ static const struct genl_ops nl80211_ops[] = { .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | NL80211_FLAG_NEED_RTNL, }, + { + .cmd = NL80211_CMD_EXTERNAL_AUTH, + .doit = nl80211_external_auth, + .policy = nl80211_policy, + .flags = GENL_ADMIN_PERM, + .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | + NL80211_FLAG_NEED_RTNL, + }, }; @@ -15375,6 +15428,47 @@ void nl80211_send_ap_stopped(struct wireless_dev *wdev) nlmsg_free(msg); } +int cfg80211_external_auth_request(struct net_device *dev, + struct cfg80211_external_auth_params *params, + gfp_t gfp) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy); + struct sk_buff *msg; + void *hdr; + + if (!wdev->conn_owner_nlportid) + return -EINVAL; + + msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp); + if (!msg) + return -ENOMEM; + + hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_EXTERNAL_AUTH); + if (!hdr) + goto nla_put_failure; + + if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) || + nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex) || + nla_put_u32(msg, NL80211_ATTR_AKM_SUITES, params->key_mgmt_suite) || + nla_put_u32(msg, NL80211_ATTR_EXTERNAL_AUTH_ACTION, + params->action) || + nla_put(msg, NL80211_ATTR_BSSID, ETH_ALEN, params->bssid) || + nla_put(msg, NL80211_ATTR_SSID, params->ssid.ssid_len, + params->ssid.ssid)) + goto nla_put_failure; + + genlmsg_end(msg, hdr); + genlmsg_unicast(wiphy_net(&rdev->wiphy), msg, + wdev->conn_owner_nlportid); + return 0; + + nla_put_failure: + nlmsg_free(msg); + return -ENOBUFS; +} +EXPORT_SYMBOL(cfg80211_external_auth_request); + /* initialisation/exit functions */ int __init nl80211_init(void) diff --git a/net/wireless/rdev-ops.h b/net/wireless/rdev-ops.h index 0c06240d25af..84f23ae015fc 100644 --- a/net/wireless/rdev-ops.h +++ b/net/wireless/rdev-ops.h @@ -1190,4 +1190,19 @@ static inline int rdev_del_pmk(struct cfg80211_registered_device *rdev, trace_rdev_return_int(&rdev->wiphy, ret); return ret; } + +static inline int +rdev_external_auth(struct cfg80211_registered_device *rdev, + struct net_device *dev, + struct cfg80211_external_auth_params *params) +{ + int ret = -EOPNOTSUPP; + + trace_rdev_external_auth(&rdev->wiphy, dev, params); + if (rdev->ops->external_auth) + ret = rdev->ops->external_auth(&rdev->wiphy, dev, params); + 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 bcfedd39e7a3..5152938b358d 100644 --- a/net/wireless/trace.h +++ b/net/wireless/trace.h @@ -2319,6 +2319,29 @@ TRACE_EVENT(rdev_del_pmk, WIPHY_PR_ARG, NETDEV_PR_ARG, MAC_PR_ARG(aa)) ); +TRACE_EVENT(rdev_external_auth, + TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, + struct cfg80211_external_auth_params *params), + TP_ARGS(wiphy, netdev, params), + TP_STRUCT__entry(WIPHY_ENTRY + NETDEV_ENTRY + MAC_ENTRY(bssid) + __array(u8, ssid, IEEE80211_MAX_SSID_LEN + 1) + __field(u16, status) + ), + TP_fast_assign(WIPHY_ASSIGN; + NETDEV_ASSIGN; + MAC_ASSIGN(bssid, params->bssid); + memset(__entry->ssid, 0, IEEE80211_MAX_SSID_LEN + 1); + memcpy(__entry->ssid, params->ssid.ssid, + params->ssid.ssid_len); + __entry->status = params->status; + ), + TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", bssid: " MAC_PR_FMT + ", ssid: %s, status: %u", WIPHY_PR_ARG, NETDEV_PR_ARG, + __entry->bssid, __entry->ssid, __entry->status) +); + /************************************************************* * cfg80211 exported functions traces * *************************************************************/ -- cgit v1.2.3 From 466b9936bf93b7ec3bce1dcd493262ff0a8a4f44 Mon Sep 17 00:00:00 2001 From: "tamizhr@codeaurora.org" Date: Wed, 31 Jan 2018 16:24:49 +0530 Subject: cfg80211: Add support to notify station's opmode change to userspace ht/vht action frames will be sent to AP from station to notify change of its ht/vht opmode(max bandwidth, smps mode or nss) modified values. Currently these valuse used by driver/firmware for rate control algorithm. This patch introduces NL80211_CMD_STA_OPMODE_CHANGED command to notify those modified/current supported values(max bandwidth, smps mode, max nss) to userspace application. This will be useful for the application like steering, which closely monitoring station's capability changes. Since the application has taken these values during station association. Signed-off-by: Tamizh chelvam Signed-off-by: Johannes Berg --- include/net/cfg80211.h | 43 ++++++++++++++++++++++++++++++++++ include/uapi/linux/nl80211.h | 12 ++++++++++ net/wireless/nl80211.c | 55 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 110 insertions(+) (limited to 'include') diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 68def3e5b013..7d49cd0cf92d 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -3553,6 +3553,35 @@ enum wiphy_vendor_command_flags { WIPHY_VENDOR_CMD_NEED_RUNNING = BIT(2), }; +/** + * enum wiphy_opmode_flag - Station's ht/vht operation mode information flags + * + * @STA_OPMODE_MAX_BW_CHANGED: Max Bandwidth changed + * @STA_OPMODE_SMPS_MODE_CHANGED: SMPS mode changed + * @STA_OPMODE_N_SS_CHANGED: max N_SS (number of spatial streams) changed + * + */ +enum wiphy_opmode_flag { + STA_OPMODE_MAX_BW_CHANGED = BIT(0), + STA_OPMODE_SMPS_MODE_CHANGED = BIT(1), + STA_OPMODE_N_SS_CHANGED = BIT(2), +}; + +/** + * struct sta_opmode_info - Station's ht/vht operation mode information + * @changed: contains value from &enum wiphy_opmode_flag + * @smps_mode: New SMPS mode of a station + * @bw: new max bandwidth value of a station + * @rx_nss: new rx_nss value of a station + */ + +struct sta_opmode_info { + u32 changed; + u8 smps_mode; + u8 bw; + u8 rx_nss; +}; + /** * struct wiphy_vendor_command - vendor command definition * @info: vendor command identifying information, as used in nl80211 @@ -5721,6 +5750,20 @@ void cfg80211_cqm_beacon_loss_notify(struct net_device *dev, gfp_t gfp); void cfg80211_radar_event(struct wiphy *wiphy, struct cfg80211_chan_def *chandef, gfp_t gfp); +/** + * cfg80211_sta_opmode_change_notify - STA's ht/vht operation mode change event + * @dev: network device + * @mac: MAC address of a station which opmode got modified + * @sta_opmode: station's current opmode value + * @gfp: context flags + * + * Driver should call this function when station's opmode modified via action + * frame. + */ +void cfg80211_sta_opmode_change_notify(struct net_device *dev, const u8 *mac, + struct sta_opmode_info *sta_opmode, + gfp_t gfp); + /** * cfg80211_cac_event - Channel availability check (CAC) event * @netdev: network device diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h index c2342456cf16..ca3d5a613fc0 100644 --- a/include/uapi/linux/nl80211.h +++ b/include/uapi/linux/nl80211.h @@ -1013,6 +1013,11 @@ * user space through the connect result as the user space would have * initiated the connection through the connect request. * + * @NL80211_CMD_STA_OPMODE_CHANGED: An event that notify station's + * ht opmode or vht opmode changes using any of &NL80211_ATTR_SMPS_MODE, + * &NL80211_ATTR_CHANNEL_WIDTH,&NL80211_ATTR_NSS attributes with its + * address(specified in &NL80211_ATTR_MAC). + * * @NL80211_CMD_MAX: highest used command number * @__NL80211_CMD_AFTER_LAST: internal use */ @@ -1221,6 +1226,8 @@ enum nl80211_commands { NL80211_CMD_EXTERNAL_AUTH, + NL80211_CMD_STA_OPMODE_CHANGED, + /* add new commands above here */ /* used to define NL80211_CMD_MAX below */ @@ -2186,6 +2193,9 @@ enum nl80211_commands { * authentication processing to user space if this capability is indicated * in NL80211_CMD_CONNECT requests from the user space. * + * @NL80211_ATTR_NSS: Station's New/updated RX_NSS value notified using this + * u8 attribute. This is used with %NL80211_CMD_STA_OPMODE_CHANGED. + * * @NUM_NL80211_ATTR: total number of nl80211_attrs available * @NL80211_ATTR_MAX: highest attribute number currently defined * @__NL80211_ATTR_AFTER_LAST: internal use @@ -2615,6 +2625,8 @@ enum nl80211_attrs { NL80211_ATTR_EXTERNAL_AUTH_ACTION, NL80211_ATTR_EXTERNAL_AUTH_SUPPORT, + NL80211_ATTR_NSS, + /* add attributes here, update the policy in nl80211.c */ __NL80211_ATTR_AFTER_LAST, diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index bdb70fe74e3c..cc6ec5bab676 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -14950,6 +14950,61 @@ nl80211_radar_notify(struct cfg80211_registered_device *rdev, nlmsg_free(msg); } +void cfg80211_sta_opmode_change_notify(struct net_device *dev, const u8 *mac, + struct sta_opmode_info *sta_opmode, + gfp_t gfp) +{ + struct sk_buff *msg; + struct wireless_dev *wdev = dev->ieee80211_ptr; + struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy); + void *hdr; + + if (WARN_ON(!mac)) + return; + + msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp); + if (!msg) + return; + + hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_STA_OPMODE_CHANGED); + if (!hdr) { + nlmsg_free(msg); + return; + } + + if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx)) + goto nla_put_failure; + + if (nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex)) + goto nla_put_failure; + + if (nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, mac)) + goto nla_put_failure; + + if ((sta_opmode->changed & STA_OPMODE_SMPS_MODE_CHANGED) && + nla_put_u8(msg, NL80211_ATTR_SMPS_MODE, sta_opmode->smps_mode)) + goto nla_put_failure; + + if ((sta_opmode->changed & STA_OPMODE_MAX_BW_CHANGED) && + nla_put_u8(msg, NL80211_ATTR_CHANNEL_WIDTH, sta_opmode->bw)) + goto nla_put_failure; + + if ((sta_opmode->changed & STA_OPMODE_N_SS_CHANGED) && + nla_put_u8(msg, NL80211_ATTR_NSS, sta_opmode->rx_nss)) + 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: + nlmsg_free(msg); +} +EXPORT_SYMBOL(cfg80211_sta_opmode_change_notify); + void cfg80211_probe_status(struct net_device *dev, const u8 *addr, u64 cookie, bool acked, gfp_t gfp) { -- cgit v1.2.3 From c4b50cd31d25c3d17886ffc47ca4a9a12c6dc9bf Mon Sep 17 00:00:00 2001 From: Venkateswara Naralasetty Date: Tue, 13 Feb 2018 11:03:06 +0530 Subject: cfg80211: send ack_signal to user in probe client response This patch provides support to get ack signal in probe client response and in station info from user. Signed-off-by: Venkateswara Naralasetty [squash in compilation fixes] Signed-off-by: Johannes Berg --- drivers/net/wireless/ath/wil6210/cfg80211.c | 3 ++- include/net/cfg80211.h | 7 ++++++- include/uapi/linux/nl80211.h | 3 +++ net/mac80211/status.c | 2 +- net/wireless/nl80211.c | 8 ++++++-- 5 files changed, 18 insertions(+), 5 deletions(-) (limited to 'include') diff --git a/drivers/net/wireless/ath/wil6210/cfg80211.c b/drivers/net/wireless/ath/wil6210/cfg80211.c index 768f63f38341..b799a5384abb 100644 --- a/drivers/net/wireless/ath/wil6210/cfg80211.c +++ b/drivers/net/wireless/ath/wil6210/cfg80211.c @@ -1599,7 +1599,8 @@ static void wil_probe_client_handle(struct wil6210_priv *wil, */ bool alive = (sta->status == wil_sta_connected); - cfg80211_probe_status(ndev, sta->addr, req->cookie, alive, GFP_KERNEL); + cfg80211_probe_status(ndev, sta->addr, req->cookie, alive, + 0, false, GFP_KERNEL); } static struct list_head *next_probe_client(struct wil6210_priv *wil) diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 7d49cd0cf92d..56e905cd4b07 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -1147,6 +1147,7 @@ struct cfg80211_tid_stats { * @rx_duration: aggregate PPDU duration(usecs) for all the frames from a peer * @pertid: per-TID statistics, see &struct cfg80211_tid_stats, using the last * (IEEE80211_NUM_TIDS) index for MSDUs not encapsulated in QoS-MPDUs. + * @ack_signal: signal strength (in dBm) of the last ACK frame. */ struct station_info { u64 filled; @@ -1191,6 +1192,7 @@ struct station_info { u64 rx_duration; u8 rx_beacon_signal_avg; struct cfg80211_tid_stats pertid[IEEE80211_NUM_TIDS + 1]; + s8 ack_signal; }; #if IS_ENABLED(CONFIG_CFG80211) @@ -5838,10 +5840,13 @@ bool cfg80211_rx_unexpected_4addr_frame(struct net_device *dev, * @addr: the address of the peer * @cookie: the cookie filled in @probe_client previously * @acked: indicates whether probe was acked or not + * @ack_signal: signal strength (in dBm) of the ACK frame. + * @is_valid_ack_signal: indicates the ack_signal is valid or not. * @gfp: allocation flags */ void cfg80211_probe_status(struct net_device *dev, const u8 *addr, - u64 cookie, bool acked, gfp_t gfp); + u64 cookie, bool acked, s32 ack_signal, + bool is_valid_ack_signal, gfp_t gfp); /** * cfg80211_report_obss_beacon - report beacon from other APs diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h index ca3d5a613fc0..c13c84304be3 100644 --- a/include/uapi/linux/nl80211.h +++ b/include/uapi/linux/nl80211.h @@ -2626,6 +2626,7 @@ enum nl80211_attrs { NL80211_ATTR_EXTERNAL_AUTH_SUPPORT, NL80211_ATTR_NSS, + NL80211_ATTR_ACK_SIGNAL, /* add attributes here, update the policy in nl80211.c */ @@ -2947,6 +2948,7 @@ enum nl80211_sta_bss_param { * @NL80211_STA_INFO_RX_DURATION: aggregate PPDU duration for all frames * received from the station (u64, usec) * @NL80211_STA_INFO_PAD: attribute used for padding for 64-bit alignment + * @NL80211_STA_INFO_ACK_SIGNAL: signal strength of the last ACK frame(u8, dBm) * @__NL80211_STA_INFO_AFTER_LAST: internal * @NL80211_STA_INFO_MAX: highest possible station info attribute */ @@ -2985,6 +2987,7 @@ enum nl80211_sta_info { NL80211_STA_INFO_TID_STATS, NL80211_STA_INFO_RX_DURATION, NL80211_STA_INFO_PAD, + NL80211_STA_INFO_ACK_SIGNAL, /* keep last */ __NL80211_STA_INFO_AFTER_LAST, diff --git a/net/mac80211/status.c b/net/mac80211/status.c index da7427a41529..d74d44e65bd7 100644 --- a/net/mac80211/status.c +++ b/net/mac80211/status.c @@ -486,7 +486,7 @@ static void ieee80211_report_ack_skb(struct ieee80211_local *local, if (ieee80211_is_nullfunc(hdr->frame_control) || ieee80211_is_qos_nullfunc(hdr->frame_control)) cfg80211_probe_status(sdata->dev, hdr->addr1, - cookie, acked, + cookie, acked, 0, false, GFP_ATOMIC); else cfg80211_mgmt_tx_status(&sdata->wdev, cookie, diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index c6f256b29c73..050ff61b06a3 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -4486,6 +4486,7 @@ static int nl80211_send_station(struct sk_buff *msg, u32 cmd, u32 portid, PUT_SINFO_U64(RX_DROP_MISC, rx_dropped_misc); PUT_SINFO_U64(BEACON_RX, rx_beacon); PUT_SINFO(BEACON_SIGNAL_AVG, rx_beacon_signal_avg, u8); + PUT_SINFO(ACK_SIGNAL, ack_signal, u8); #undef PUT_SINFO #undef PUT_SINFO_U64 @@ -14984,7 +14985,8 @@ nla_put_failure: EXPORT_SYMBOL(cfg80211_sta_opmode_change_notify); void cfg80211_probe_status(struct net_device *dev, const u8 *addr, - u64 cookie, bool acked, gfp_t gfp) + u64 cookie, bool acked, s32 ack_signal, + bool is_valid_ack_signal, gfp_t gfp) { struct wireless_dev *wdev = dev->ieee80211_ptr; struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy); @@ -15009,7 +15011,9 @@ void cfg80211_probe_status(struct net_device *dev, const u8 *addr, nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr) || nla_put_u64_64bit(msg, NL80211_ATTR_COOKIE, cookie, NL80211_ATTR_PAD) || - (acked && nla_put_flag(msg, NL80211_ATTR_ACK))) + (acked && nla_put_flag(msg, NL80211_ATTR_ACK)) || + (is_valid_ack_signal && nla_put_s32(msg, NL80211_ATTR_ACK_SIGNAL, + ack_signal))) goto nla_put_failure; genlmsg_end(msg, hdr); -- cgit v1.2.3 From a78b26fffd2368fcd079802897f4c97f9baea833 Mon Sep 17 00:00:00 2001 From: Venkateswara Naralasetty Date: Tue, 13 Feb 2018 11:04:46 +0530 Subject: mac80211: Add tx ack signal support in sta info This allows users to get ack signal strength of last transmitted frame. Signed-off-by: Venkateswara Naralasetty Signed-off-by: Johannes Berg --- include/net/mac80211.h | 1 + net/mac80211/sta_info.c | 6 ++++++ net/mac80211/sta_info.h | 2 ++ net/mac80211/status.c | 13 +++++++++++-- 4 files changed, 20 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 906e90223066..854037b8163e 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -934,6 +934,7 @@ struct ieee80211_tx_info { u8 ampdu_len; u8 antenna; u16 tx_time; + bool is_valid_ack_signal; void *status_driver_data[19 / sizeof(void *)]; } status; struct { diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index 0c5627f8a104..0bc40c719a55 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c @@ -2287,6 +2287,12 @@ void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo) sinfo->filled |= BIT(NL80211_STA_INFO_EXPECTED_THROUGHPUT); sinfo->expected_throughput = thr; } + + if (!(sinfo->filled & BIT_ULL(NL80211_STA_INFO_ACK_SIGNAL)) && + sta->status_stats.ack_signal_filled) { + sinfo->ack_signal = sta->status_stats.last_ack_signal; + sinfo->filled |= BIT_ULL(NL80211_STA_INFO_ACK_SIGNAL); + } } u32 sta_get_expected_throughput(struct sta_info *sta) diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index cd53619435b6..f64eb86ca64b 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h @@ -548,6 +548,8 @@ struct sta_info { u64 msdu_retries[IEEE80211_NUM_TIDS + 1]; u64 msdu_failed[IEEE80211_NUM_TIDS + 1]; unsigned long last_ack; + s8 last_ack_signal; + bool ack_signal_filled; } status_stats; /* Updated from TX path only, no locking requirements */ diff --git a/net/mac80211/status.c b/net/mac80211/status.c index d74d44e65bd7..743e89c5926c 100644 --- a/net/mac80211/status.c +++ b/net/mac80211/status.c @@ -187,9 +187,16 @@ static void ieee80211_frame_acked(struct sta_info *sta, struct sk_buff *skb) struct ieee80211_mgmt *mgmt = (void *) skb->data; struct ieee80211_local *local = sta->local; struct ieee80211_sub_if_data *sdata = sta->sdata; + struct ieee80211_tx_info *txinfo = IEEE80211_SKB_CB(skb); - if (ieee80211_hw_check(&local->hw, REPORTS_TX_ACK_STATUS)) + if (ieee80211_hw_check(&local->hw, REPORTS_TX_ACK_STATUS)) { sta->status_stats.last_ack = jiffies; + if (txinfo->status.is_valid_ack_signal) { + sta->status_stats.last_ack_signal = + (s8)txinfo->status.ack_signal; + sta->status_stats.ack_signal_filled = true; + } + } if (ieee80211_is_data_qos(mgmt->frame_control)) { struct ieee80211_hdr *hdr = (void *) skb->data; @@ -486,7 +493,9 @@ static void ieee80211_report_ack_skb(struct ieee80211_local *local, if (ieee80211_is_nullfunc(hdr->frame_control) || ieee80211_is_qos_nullfunc(hdr->frame_control)) cfg80211_probe_status(sdata->dev, hdr->addr1, - cookie, acked, 0, false, + cookie, acked, + info->status.ack_signal, + info->status.is_valid_ack_signal, GFP_ATOMIC); else cfg80211_mgmt_tx_status(&sdata->wdev, cookie, -- cgit v1.2.3 From 22e76844c566e474a9a3e0c2206e45766b5941b7 Mon Sep 17 00:00:00 2001 From: Srinivas Dasari Date: Tue, 6 Feb 2018 19:49:35 +0530 Subject: ieee80211: Increase PMK maximum length to 64 bytes Increase the PMK maximum length to 64 bytes to accommodate the key length used in DPP with the NIST P-521 and Brainpool 512 curves. Signed-off-by: Srinivas Dasari Signed-off-by: Johannes Berg --- include/linux/ieee80211.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include') diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h index ee6657a0ed69..e4cba332b705 100644 --- a/include/linux/ieee80211.h +++ b/include/linux/ieee80211.h @@ -2111,7 +2111,7 @@ enum ieee80211_key_len { #define FILS_ERP_MAX_REALM_LEN 253 #define FILS_ERP_MAX_RRK_LEN 64 -#define PMK_MAX_LEN 48 +#define PMK_MAX_LEN 64 /* Public action codes (IEEE Std 802.11-2016, 9.6.8.1, Table 9-307) */ enum ieee80211_pub_actioncode { -- cgit v1.2.3 From 4fe0de5b143762d327bfaf1d7be7c5b58041a18c Mon Sep 17 00:00:00 2001 From: Denis Kenzior Date: Wed, 31 Jan 2018 19:04:15 -0600 Subject: uapi: Add 802.11 Preauthentication to if_ether This adds 0x88c7 protocol type to if_ether. Signed-off-by: Denis Kenzior Signed-off-by: Johannes Berg --- include/uapi/linux/if_ether.h | 1 + 1 file changed, 1 insertion(+) (limited to 'include') diff --git a/include/uapi/linux/if_ether.h b/include/uapi/linux/if_ether.h index f8cb5760ea4f..54585906e50a 100644 --- a/include/uapi/linux/if_ether.h +++ b/include/uapi/linux/if_ether.h @@ -89,6 +89,7 @@ #define ETH_P_AOE 0x88A2 /* ATA over Ethernet */ #define ETH_P_8021AD 0x88A8 /* 802.1ad Service VLAN */ #define ETH_P_802_EX1 0x88B5 /* 802.1 Local Experimental 1. */ +#define ETH_P_PREAUTH 0x88C7 /* 802.11 Preauthentication */ #define ETH_P_TIPC 0x88CA /* TIPC */ #define ETH_P_MACSEC 0x88E5 /* 802.1ae MACsec */ #define ETH_P_8021AH 0x88E7 /* 802.1ah Backbone Service Tag */ -- cgit v1.2.3 From 7299d6f7bfd1921c0cfb5e202155f1a5cfdb57d0 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 19 Feb 2018 14:48:39 +0200 Subject: mac80211: support reporting A-MPDU EOF bit value/known Support getting the EOF bit value reported from hardware and writing it out to radiotap. Signed-off-by: Johannes Berg --- include/net/ieee80211_radiotap.h | 2 ++ include/net/mac80211.h | 5 +++++ net/mac80211/rx.c | 4 ++++ 3 files changed, 11 insertions(+) (limited to 'include') diff --git a/include/net/ieee80211_radiotap.h b/include/net/ieee80211_radiotap.h index d91f9e7f4d71..960236fb1681 100644 --- a/include/net/ieee80211_radiotap.h +++ b/include/net/ieee80211_radiotap.h @@ -149,6 +149,8 @@ enum ieee80211_radiotap_ampdu_flags { IEEE80211_RADIOTAP_AMPDU_IS_LAST = 0x0008, IEEE80211_RADIOTAP_AMPDU_DELIM_CRC_ERR = 0x0010, IEEE80211_RADIOTAP_AMPDU_DELIM_CRC_KNOWN = 0x0020, + IEEE80211_RADIOTAP_AMPDU_EOF = 0x0040, + IEEE80211_RADIOTAP_AMPDU_EOF_KNOWN = 0x0080, }; /* for IEEE80211_RADIOTAP_VHT */ diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 854037b8163e..649f073eb6df 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -1099,6 +1099,9 @@ ieee80211_tx_info_clear_status(struct ieee80211_tx_info *info) * the first subframe. * @RX_FLAG_ICV_STRIPPED: The ICV is stripped from this frame. CRC checking must * be done in the hardware. + * @RX_FLAG_AMPDU_EOF_BIT: Value of the EOF bit in the A-MPDU delimiter for this + * frame + * @RX_FLAG_AMPDU_EOF_BIT_KNOWN: The EOF value is known */ enum mac80211_rx_flags { RX_FLAG_MMIC_ERROR = BIT(0), @@ -1125,6 +1128,8 @@ enum mac80211_rx_flags { RX_FLAG_MIC_STRIPPED = BIT(21), RX_FLAG_ALLOW_SAME_PN = BIT(22), RX_FLAG_ICV_STRIPPED = BIT(23), + RX_FLAG_AMPDU_EOF_BIT = BIT(24), + RX_FLAG_AMPDU_EOF_BIT_KNOWN = BIT(25), }; /** diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index e755f93ad735..478a9c735edb 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -439,6 +439,10 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local, flags |= IEEE80211_RADIOTAP_AMPDU_DELIM_CRC_ERR; if (status->flag & RX_FLAG_AMPDU_DELIM_CRC_KNOWN) flags |= IEEE80211_RADIOTAP_AMPDU_DELIM_CRC_KNOWN; + if (status->flag & RX_FLAG_AMPDU_EOF_BIT_KNOWN) + flags |= IEEE80211_RADIOTAP_AMPDU_EOF_KNOWN; + if (status->flag & RX_FLAG_AMPDU_EOF_BIT) + flags |= IEEE80211_RADIOTAP_AMPDU_EOF; put_unaligned_le16(flags, pos); pos += 2; if (status->flag & RX_FLAG_AMPDU_DELIM_CRC_KNOWN) -- cgit v1.2.3 From a1f2ba04cc92414b6b933289365eab878b0b2bf4 Mon Sep 17 00:00:00 2001 From: Sara Sharon Date: Mon, 19 Feb 2018 14:48:40 +0200 Subject: mac80211: add get TID helper Extracting the TID from the QOS header is common enough to justify helper. Signed-off-by: Sara Sharon Signed-off-by: Luca Coelho Signed-off-by: Johannes Berg --- include/linux/ieee80211.h | 12 ++++++++++++ net/mac80211/iface.c | 3 +-- net/mac80211/michael.c | 2 +- net/mac80211/mlme.c | 2 +- net/mac80211/rc80211_minstrel_ht.c | 2 +- net/mac80211/rx.c | 6 ++---- net/mac80211/tx.c | 9 ++------- net/mac80211/wpa.c | 8 +++----- 8 files changed, 23 insertions(+), 21 deletions(-) (limited to 'include') diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h index e4cba332b705..8fe7e4306816 100644 --- a/include/linux/ieee80211.h +++ b/include/linux/ieee80211.h @@ -8,6 +8,7 @@ * Copyright (c) 2006, Michael Wu * Copyright (c) 2013 - 2014 Intel Mobile Communications GmbH * Copyright (c) 2016 - 2017 Intel Deutschland GmbH + * Copyright (c) 2018 Intel Corporation * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -2501,6 +2502,17 @@ static inline u8 *ieee80211_get_qos_ctl(struct ieee80211_hdr *hdr) return (u8 *)hdr + 24; } +/** + * ieee80211_get_tid - get qos TID + * @hdr: the frame + */ +static inline u8 ieee80211_get_tid(struct ieee80211_hdr *hdr) +{ + u8 *qc = ieee80211_get_qos_ctl(hdr); + + return qc[0] & IEEE80211_QOS_CTL_TID_MASK; +} + /** * ieee80211_get_SA - get pointer to SA * @hdr: the frame diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index 5fe01f82df12..d13ba064951f 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -1324,8 +1324,7 @@ static void ieee80211_iface_work(struct work_struct *work) mutex_lock(&local->sta_mtx); sta = sta_info_get_bss(sdata, mgmt->sa); if (sta) { - u16 tid = *ieee80211_get_qos_ctl(hdr) & - IEEE80211_QOS_CTL_TID_MASK; + u16 tid = ieee80211_get_tid(hdr); __ieee80211_stop_rx_ba_session( sta, tid, WLAN_BACK_RECIPIENT, diff --git a/net/mac80211/michael.c b/net/mac80211/michael.c index 408649bd4702..37e172701a63 100644 --- a/net/mac80211/michael.c +++ b/net/mac80211/michael.c @@ -35,7 +35,7 @@ static void michael_mic_hdr(struct michael_mic_ctx *mctx, const u8 *key, da = ieee80211_get_DA(hdr); sa = ieee80211_get_SA(hdr); if (ieee80211_is_data_qos(hdr->frame_control)) - tid = *ieee80211_get_qos_ctl(hdr) & IEEE80211_QOS_CTL_TID_MASK; + tid = ieee80211_get_tid(hdr); else tid = 0; diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 39b660b9a908..010b127a3937 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -2151,7 +2151,7 @@ static void ieee80211_sta_tx_wmm_ac_notify(struct ieee80211_sub_if_data *sdata, u16 tx_time) { struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; - u16 tid = *ieee80211_get_qos_ctl(hdr) & IEEE80211_QOS_CTL_TID_MASK; + u16 tid = ieee80211_get_tid(hdr); int ac = ieee80211_ac_from_tid(tid); struct ieee80211_sta_tx_tspec *tx_tspec = &ifmgd->tx_tspec[ac]; unsigned long now = jiffies; diff --git a/net/mac80211/rc80211_minstrel_ht.c b/net/mac80211/rc80211_minstrel_ht.c index 4a5bdad9f303..fb586b6e5d49 100644 --- a/net/mac80211/rc80211_minstrel_ht.c +++ b/net/mac80211/rc80211_minstrel_ht.c @@ -669,7 +669,7 @@ minstrel_aggr_check(struct ieee80211_sta *pubsta, struct sk_buff *skb) if (unlikely(skb->protocol == cpu_to_be16(ETH_P_PAE))) return; - tid = *ieee80211_get_qos_ctl(hdr) & IEEE80211_QOS_CTL_TID_MASK; + tid = ieee80211_get_tid(hdr); if (likely(sta->ampdu_mlme.tid_tx[tid])) return; diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 478a9c735edb..3dc162ddc3a6 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -1189,7 +1189,7 @@ static void ieee80211_rx_reorder_ampdu(struct ieee80211_rx_data *rx, ack_policy = *ieee80211_get_qos_ctl(hdr) & IEEE80211_QOS_CTL_ACK_POLICY_MASK; - tid = *ieee80211_get_qos_ctl(hdr) & IEEE80211_QOS_CTL_TID_MASK; + tid = ieee80211_get_tid(hdr); tid_agg_rx = rcu_dereference(sta->ampdu_mlme.tid_rx[tid]); if (!tid_agg_rx) { @@ -1528,9 +1528,7 @@ ieee80211_rx_h_uapsd_and_pspoll(struct ieee80211_rx_data *rx) ieee80211_has_pm(hdr->frame_control) && (ieee80211_is_data_qos(hdr->frame_control) || ieee80211_is_qos_nullfunc(hdr->frame_control))) { - u8 tid; - - tid = *ieee80211_get_qos_ctl(hdr) & IEEE80211_QOS_CTL_TID_MASK; + u8 tid = ieee80211_get_tid(hdr); ieee80211_sta_uapsd_trigger(&rx->sta->sta, tid); } diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 5decd0fb247c..7643178ef132 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -797,7 +797,6 @@ ieee80211_tx_h_sequence(struct ieee80211_tx_data *tx) { struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb); struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)tx->skb->data; - u8 *qc; int tid; /* @@ -844,9 +843,7 @@ ieee80211_tx_h_sequence(struct ieee80211_tx_data *tx) return TX_CONTINUE; /* include per-STA, per-TID sequence counter */ - - qc = ieee80211_get_qos_ctl(hdr); - tid = *qc & IEEE80211_QOS_CTL_TID_MASK; + tid = ieee80211_get_tid(hdr); tx->sta->tx_stats.msdu[tid]++; hdr->seq_ctrl = ieee80211_tx_next_seq(tx->sta, tid); @@ -1158,7 +1155,6 @@ ieee80211_tx_prepare(struct ieee80211_sub_if_data *sdata, struct ieee80211_hdr *hdr; struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); int tid; - u8 *qc; memset(tx, 0, sizeof(*tx)); tx->skb = skb; @@ -1198,8 +1194,7 @@ ieee80211_tx_prepare(struct ieee80211_sub_if_data *sdata, !ieee80211_hw_check(&local->hw, TX_AMPDU_SETUP_IN_HW)) { struct tid_ampdu_tx *tid_tx; - qc = ieee80211_get_qos_ctl(hdr); - tid = *qc & IEEE80211_QOS_CTL_TID_MASK; + tid = ieee80211_get_tid(hdr); tid_tx = rcu_dereference(tx->sta->ampdu_mlme.tid_tx[tid]); if (tid_tx) { diff --git a/net/mac80211/wpa.c b/net/mac80211/wpa.c index 785056cb76f6..58d0b258b684 100644 --- a/net/mac80211/wpa.c +++ b/net/mac80211/wpa.c @@ -340,7 +340,7 @@ static void ccmp_special_blocks(struct sk_buff *skb, u8 *pn, u8 *b_0, u8 *aad) a4_included = ieee80211_has_a4(hdr->frame_control); if (ieee80211_is_data_qos(hdr->frame_control)) - qos_tid = *ieee80211_get_qos_ctl(hdr) & IEEE80211_QOS_CTL_TID_MASK; + qos_tid = ieee80211_get_tid(hdr); else qos_tid = 0; @@ -601,8 +601,7 @@ static void gcmp_special_blocks(struct sk_buff *skb, u8 *pn, u8 *j_0, u8 *aad) aad[23] = 0; if (ieee80211_is_data_qos(hdr->frame_control)) - qos_tid = *ieee80211_get_qos_ctl(hdr) & - IEEE80211_QOS_CTL_TID_MASK; + qos_tid = ieee80211_get_tid(hdr); else qos_tid = 0; @@ -867,8 +866,7 @@ ieee80211_crypto_cs_decrypt(struct ieee80211_rx_data *rx) return RX_DROP_UNUSABLE; if (ieee80211_is_data_qos(hdr->frame_control)) - qos_tid = *ieee80211_get_qos_ctl(hdr) & - IEEE80211_QOS_CTL_TID_MASK; + qos_tid = ieee80211_get_tid(hdr); else qos_tid = 0; -- cgit v1.2.3 From 94ba92713f8329c96e0a8e2880b3c1a785d1c95c Mon Sep 17 00:00:00 2001 From: Ilan Peer Date: Mon, 19 Feb 2018 14:48:41 +0200 Subject: mac80211: Call mgd_prep_tx before transmitting deauthentication In multi channel scenarios, when disassociating from the AP before a beacon was heard from the AP, it is not guaranteed that the virtual interface is granted air time for the transmission of the deauthentication frame. This in turn can lead to various issues as the AP might never get the deauthentication frame. To mitigate such possible issues, add a HW flag indicating that the driver requires mac80211 to call the mgd_prep_tx() driver callback to make sure that the virtual interface is granted immediate airtime to be able to transmit the frame, in case that no beacon was heard from the AP. Signed-off-by: Ilan Peer Signed-off-by: Luca Coelho Signed-off-by: Johannes Berg --- include/net/mac80211.h | 13 +++++++++++++ net/mac80211/debugfs.c | 1 + net/mac80211/mlme.c | 16 +++++++++++++++- 3 files changed, 29 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 649f073eb6df..dc3e9d9c3527 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -6,6 +6,7 @@ * Copyright 2007-2010 Johannes Berg * Copyright 2013-2014 Intel Mobile Communications GmbH * Copyright (C) 2015 - 2017 Intel Deutschland GmbH + * Copyright (C) 2018 Intel Corporation * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -2069,6 +2070,14 @@ struct ieee80211_txq { * @IEEE80211_HW_SUPPORTS_TDLS_BUFFER_STA: Hardware supports buffer STA on * TDLS links. * + * @IEEE80211_HW_DEAUTH_NEED_MGD_TX_PREP: The driver requires the + * mgd_prepare_tx() callback to be called before transmission of a + * deauthentication frame in case the association was completed but no + * beacon was heard. This is required in multi-channel scenarios, where the + * virtual interface might not be given air time for the transmission of + * the frame, as it is not synced with the AP/P2P GO yet, and thus the + * deauthentication frame might not be transmitted. + * * @NUM_IEEE80211_HW_FLAGS: number of hardware flags, used for sizing arrays */ enum ieee80211_hw_flags { @@ -2112,6 +2121,7 @@ enum ieee80211_hw_flags { IEEE80211_HW_REPORTS_LOW_ACK, IEEE80211_HW_SUPPORTS_TX_FRAG, IEEE80211_HW_SUPPORTS_TDLS_BUFFER_STA, + IEEE80211_HW_DEAUTH_NEED_MGD_TX_PREP, /* keep last, obviously */ NUM_IEEE80211_HW_FLAGS @@ -3356,6 +3366,9 @@ enum ieee80211_reconfig_type { * management frame prior to having successfully associated to allow the * driver to give it channel time for the transmission, to get a response * and to be able to synchronize with the GO. + * For drivers that set %IEEE80211_HW_DEAUTH_NEED_MGD_TX_PREP, mac80211 + * would also call this function before transmitting a deauthentication + * frame in case that no beacon was heard from the AP/P2P GO. * The callback will be called before each transmission and upon return * mac80211 will transmit the frame right away. * The callback is optional and can (should!) sleep. diff --git a/net/mac80211/debugfs.c b/net/mac80211/debugfs.c index 1f466d12a6bc..a75653affbf7 100644 --- a/net/mac80211/debugfs.c +++ b/net/mac80211/debugfs.c @@ -212,6 +212,7 @@ static const char *hw_flag_names[] = { FLAG(REPORTS_LOW_ACK), FLAG(SUPPORTS_TX_FRAG), FLAG(SUPPORTS_TDLS_BUFFER_STA), + FLAG(DEAUTH_NEED_MGD_TX_PREP), #undef FLAG }; diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 010b127a3937..0024eff9bb84 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -7,6 +7,7 @@ * Copyright 2007, Michael Wu * Copyright 2013-2014 Intel Mobile Communications GmbH * Copyright (C) 2015 - 2017 Intel Deutschland GmbH + * Copyright (C) 2018 Intel Corporation * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -2008,9 +2009,22 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, ieee80211_flush_queues(local, sdata, true); /* deauthenticate/disassociate now */ - if (tx || frame_buf) + if (tx || frame_buf) { + struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; + + /* + * In multi channel scenarios guarantee that the virtual + * interface is granted immediate airtime to transmit the + * deauthentication frame by calling mgd_prepare_tx, if the + * driver requested so. + */ + if (ieee80211_hw_check(&local->hw, DEAUTH_NEED_MGD_TX_PREP) && + !ifmgd->have_beacon) + drv_mgd_prepare_tx(sdata->local, sdata); + ieee80211_send_deauth_disassoc(sdata, ifmgd->bssid, stype, reason, tx, frame_buf); + } /* flush out frame - make sure the deauth was actually sent */ if (tx) -- cgit v1.2.3