3136 lines · 76.5 KB · C
RawDownload
// SPDX-License-Identifier: GPL-2.0/* * Wireless utility functions * * Copyright 2007-2009	Johannes Berg <johannes@sipsolutions.net> * Copyright 2013-2014  Intel Mobile Communications GmbH * Copyright 2017	Intel Deutschland GmbH * Copyright (C) 2018-2023, 2025-2026 Intel Corporation */#include <linux/export.h>#include <linux/bitops.h>#include <linux/etherdevice.h>#include <linux/slab.h>#include <linux/ieee80211.h>#include <net/cfg80211.h>#include <net/ip.h>#include <net/dsfield.h>#include <linux/if_vlan.h>#include <linux/mpls.h>#include <linux/gcd.h>#include <linux/bitfield.h>#include <linux/nospec.h>#include "core.h"#include "rdev-ops.h"  const struct ieee80211_rate *ieee80211_get_response_rate(struct ieee80211_supported_band *sband,			    u32 basic_rates, int bitrate){	struct ieee80211_rate *result = &sband->bitrates[0];	int i; 	for (i = 0; i < sband->n_bitrates; i++) {		if (!(basic_rates & BIT(i)))			continue;		if (sband->bitrates[i].bitrate > bitrate)			continue;		result = &sband->bitrates[i];	} 	return result;}EXPORT_SYMBOL(ieee80211_get_response_rate); u32 ieee80211_mandatory_rates(struct ieee80211_supported_band *sband){	struct ieee80211_rate *bitrates;	u32 mandatory_rates = 0;	enum ieee80211_rate_flags mandatory_flag;	int i; 	if (WARN_ON(!sband))		return 1; 	if (sband->band == NL80211_BAND_2GHZ)		mandatory_flag = IEEE80211_RATE_MANDATORY_B;	else		mandatory_flag = IEEE80211_RATE_MANDATORY_A; 	bitrates = sband->bitrates;	for (i = 0; i < sband->n_bitrates; i++)		if (bitrates[i].flags & mandatory_flag)			mandatory_rates |= BIT(i);	return mandatory_rates;}EXPORT_SYMBOL(ieee80211_mandatory_rates); u32 ieee80211_channel_to_freq_khz(int chan, enum nl80211_band band){	/* see 802.11 17.3.8.3.2 and Annex J	 * there are overlapping channel numbers in 5GHz and 2GHz bands */	if (chan <= 0)		return 0; /* not supported */	switch (band) {	case NL80211_BAND_2GHZ:	case NL80211_BAND_LC:		if (chan == 14)			return MHZ_TO_KHZ(2484);		else if (chan < 14)			return MHZ_TO_KHZ(2407 + chan * 5);		break;	case NL80211_BAND_5GHZ:		if (chan >= 182 && chan <= 196)			return MHZ_TO_KHZ(4000 + chan * 5);		else			return MHZ_TO_KHZ(5000 + chan * 5);		break;	case NL80211_BAND_6GHZ:		/* see 802.11ax D6.1 27.3.23.2 */		if (chan == 2)			return MHZ_TO_KHZ(5935);		if (chan <= 253)			return MHZ_TO_KHZ(5950 + chan * 5);		break;	case NL80211_BAND_60GHZ:		if (chan < 7)			return MHZ_TO_KHZ(56160 + chan * 2160);		break;	case NL80211_BAND_S1GHZ:		return 902000 + chan * 500;	default:		;	}	return 0; /* not supported */}EXPORT_SYMBOL(ieee80211_channel_to_freq_khz); int ieee80211_freq_khz_to_channel(u32 freq){	/* TODO: just handle MHz for now */	freq = KHZ_TO_MHZ(freq); 	/* see 802.11 17.3.8.3.2 and Annex J */	if (freq == 2484)		return 14;	else if (freq < 2484)		return (freq - 2407) / 5;	else if (freq >= 4910 && freq <= 4980)		return (freq - 4000) / 5;	else if (freq < 5925)		return (freq - 5000) / 5;	else if (freq == 5935)		return 2;	else if (freq <= 45000) /* DMG band lower limit */		/* see 802.11ax D6.1 27.3.22.2 */		return (freq - 5950) / 5;	else if (freq >= 58320 && freq <= 70200)		return (freq - 56160) / 2160;	else		return 0;}EXPORT_SYMBOL(ieee80211_freq_khz_to_channel); struct ieee80211_channel *ieee80211_get_channel_khz(struct wiphy *wiphy,						    u32 freq){	enum nl80211_band band;	struct ieee80211_supported_band *sband;	int i; 	for (band = 0; band < NUM_NL80211_BANDS; band++) {		sband = wiphy->bands[band]; 		if (!sband)			continue; 		for (i = 0; i < sband->n_channels; i++) {			struct ieee80211_channel *chan = &sband->channels[i]; 			if (ieee80211_channel_to_khz(chan) == freq)				return chan;		}	} 	return NULL;}EXPORT_SYMBOL(ieee80211_get_channel_khz); static void set_mandatory_flags_band(struct ieee80211_supported_band *sband){	int i, want; 	switch (sband->band) {	case NL80211_BAND_5GHZ:	case NL80211_BAND_6GHZ:		want = 3;		for (i = 0; i < sband->n_bitrates; i++) {			if (sband->bitrates[i].bitrate == 60 ||			    sband->bitrates[i].bitrate == 120 ||			    sband->bitrates[i].bitrate == 240) {				sband->bitrates[i].flags |=					IEEE80211_RATE_MANDATORY_A;				want--;			}		}		WARN_ON(want);		break;	case NL80211_BAND_2GHZ:	case NL80211_BAND_LC:		want = 7;		for (i = 0; i < sband->n_bitrates; i++) {			switch (sband->bitrates[i].bitrate) {			case 10:			case 20:			case 55:			case 110:				sband->bitrates[i].flags |=					IEEE80211_RATE_MANDATORY_B |					IEEE80211_RATE_MANDATORY_G;				want--;				break;			case 60:			case 120:			case 240:				sband->bitrates[i].flags |=					IEEE80211_RATE_MANDATORY_G;				want--;				fallthrough;			default:				sband->bitrates[i].flags |=					IEEE80211_RATE_ERP_G;				break;			}		}		WARN_ON(want != 0 && want != 3);		break;	case NL80211_BAND_60GHZ:		/* check for mandatory HT MCS 1..4 */		WARN_ON(!sband->ht_cap.ht_supported);		WARN_ON((sband->ht_cap.mcs.rx_mask[0] & 0x1e) != 0x1e);		break;	case NL80211_BAND_S1GHZ:		/* Figure 9-589bd: 3 means unsupported, so != 3 means at least		 * mandatory is ok.		 */		WARN_ON((sband->s1g_cap.nss_mcs[0] & 0x3) == 0x3);		break;	case NUM_NL80211_BANDS:	default:		WARN_ON(1);		break;	}} void ieee80211_set_bitrate_flags(struct wiphy *wiphy){	enum nl80211_band band; 	for (band = 0; band < NUM_NL80211_BANDS; band++)		if (wiphy->bands[band])			set_mandatory_flags_band(wiphy->bands[band]);} bool cfg80211_supported_cipher_suite(struct wiphy *wiphy, u32 cipher){	int i;	for (i = 0; i < wiphy->n_cipher_suites; i++)		if (cipher == wiphy->cipher_suites[i])			return true;	return false;} static bool cfg80211_igtk_cipher_supported(struct wiphy *wiphy){	int i; 	for (i = 0; i < wiphy->n_cipher_suites; i++) {		switch (wiphy->cipher_suites[i]) {		case WLAN_CIPHER_SUITE_AES_CMAC:		case WLAN_CIPHER_SUITE_BIP_CMAC_256:		case WLAN_CIPHER_SUITE_BIP_GMAC_128:		case WLAN_CIPHER_SUITE_BIP_GMAC_256:			return true;		}	} 	return false;} bool cfg80211_valid_key_idx(struct wireless_dev *wdev,			    int key_idx, bool pairwise,			    const u8 *mac_addr){	if (WARN_ON(!wdev))		return false; 	if (key_idx < 0)		return false; 	/*	 * Can't differentiate ciphers here so allow 0..3.	 * Pairwise keys must be for a station (MAC address given).	 */	if (pairwise) {		if (!mac_addr)			return false; 		return key_idx < 4;	} 	/*	 * For group keys, mac_addr==NULL means setting a group key	 * for TX, which is only supported on some interface types,	 * except for STATION/P2P_CLIENT, where it's setting the RX	 * key with the current AP (for legacy reasons.)	 *	 * Apart from that exception, a non-NULL mac_addr means RX	 * key being set.	 */ 	switch (wdev->iftype) {	case NL80211_IFTYPE_ADHOC:		if (!(wdev->wiphy->flags & WIPHY_FLAG_IBSS_RSN))			return false;		fallthrough;	case NL80211_IFTYPE_MESH_POINT:		/* no support for IGTK/BIGTK (yet?) */		return key_idx < 4;	case NL80211_IFTYPE_NAN_DATA:		/* these always need to support per-STA GTK */		return key_idx < 4;	case NL80211_IFTYPE_NAN:		/* no data */		if (key_idx < 4)			return false;		/* NAN reused this flag */		if (wiphy_ext_feature_isset(wdev->wiphy,					    NL80211_EXT_FEATURE_BEACON_PROTECTION))			return key_idx <= 7;		return key_idx <= 5;	case NL80211_IFTYPE_STATION:	case NL80211_IFTYPE_P2P_CLIENT:		/* see note about exception above */		if (mac_addr)			return false;		/* BIGTK support implies IGTK support */		if (wiphy_ext_feature_isset(wdev->wiphy,					    NL80211_EXT_FEATURE_BEACON_PROTECTION_CLIENT))			return key_idx <= 7;		fallthrough;	case NL80211_IFTYPE_AP:	case NL80211_IFTYPE_P2P_GO:		/* no RX with [B]IGTK */		if (mac_addr)			return false;		if (wiphy_ext_feature_isset(wdev->wiphy,					    NL80211_EXT_FEATURE_BEACON_PROTECTION))			return key_idx <= 7;		fallthrough;	case NL80211_IFTYPE_AP_VLAN:		/* no RX with GTK */		if (mac_addr)			return false;		if (cfg80211_igtk_cipher_supported(wdev->wiphy))			return key_idx <= 5;		return key_idx <= 3;	default:		return false;	}} int cfg80211_validate_key_settings(struct cfg80211_registered_device *rdev,				   struct wireless_dev *wdev,				   struct key_params *params, int key_idx,				   bool pairwise, const u8 *mac_addr){	if (!cfg80211_valid_key_idx(wdev, key_idx, pairwise, mac_addr))		return -EINVAL; 	switch (params->cipher) {	case WLAN_CIPHER_SUITE_TKIP:		/* Extended Key ID can only be used with CCMP/GCMP ciphers */		if ((pairwise && key_idx) ||		    params->mode != NL80211_KEY_RX_TX)			return -EINVAL;		break;	case WLAN_CIPHER_SUITE_CCMP:	case WLAN_CIPHER_SUITE_CCMP_256:	case WLAN_CIPHER_SUITE_GCMP:	case WLAN_CIPHER_SUITE_GCMP_256:		/* IEEE802.11-2016 allows only 0 and - when supporting		 * Extended Key ID - 1 as index for pairwise keys.		 * @NL80211_KEY_NO_TX is only allowed for pairwise keys when		 * the driver supports Extended Key ID.		 * @NL80211_KEY_SET_TX can't be set when installing and		 * validating a key.		 */		if ((params->mode == NL80211_KEY_NO_TX && !pairwise) ||		    params->mode == NL80211_KEY_SET_TX)			return -EINVAL;		if (wiphy_ext_feature_isset(&rdev->wiphy,					    NL80211_EXT_FEATURE_EXT_KEY_ID)) {			if (pairwise && (key_idx < 0 || key_idx > 1))				return -EINVAL;		} else if (pairwise && key_idx) {			return -EINVAL;		}		break;	case WLAN_CIPHER_SUITE_AES_CMAC:	case WLAN_CIPHER_SUITE_BIP_CMAC_256:	case WLAN_CIPHER_SUITE_BIP_GMAC_128:	case WLAN_CIPHER_SUITE_BIP_GMAC_256:		/* Disallow BIP (group-only) cipher as pairwise cipher */		if (pairwise)			return -EINVAL;		if (key_idx < 4)			return -EINVAL;		break;	case WLAN_CIPHER_SUITE_WEP40:	case WLAN_CIPHER_SUITE_WEP104:		if (key_idx > 3)			return -EINVAL;		break;	default:		break;	} 	/*	 * Per Wi-Fi Aware v4.0 section 7.1.2, NAN Data interfaces	 * shall only use CCMP-128 or GCMP-256.	 */	if (wdev->iftype == NL80211_IFTYPE_NAN_DATA &&	    params->cipher != WLAN_CIPHER_SUITE_CCMP &&	    params->cipher != WLAN_CIPHER_SUITE_GCMP_256)		return -EINVAL; 	switch (params->cipher) {	case WLAN_CIPHER_SUITE_WEP40:		if (params->key_len != WLAN_KEY_LEN_WEP40)			return -EINVAL;		break;	case WLAN_CIPHER_SUITE_TKIP:		if (params->key_len != WLAN_KEY_LEN_TKIP)			return -EINVAL;		break;	case WLAN_CIPHER_SUITE_CCMP:		if (params->key_len != WLAN_KEY_LEN_CCMP)			return -EINVAL;		break;	case WLAN_CIPHER_SUITE_CCMP_256:		if (params->key_len != WLAN_KEY_LEN_CCMP_256)			return -EINVAL;		break;	case WLAN_CIPHER_SUITE_GCMP:		if (params->key_len != WLAN_KEY_LEN_GCMP)			return -EINVAL;		break;	case WLAN_CIPHER_SUITE_GCMP_256:		if (params->key_len != WLAN_KEY_LEN_GCMP_256)			return -EINVAL;		break;	case WLAN_CIPHER_SUITE_WEP104:		if (params->key_len != WLAN_KEY_LEN_WEP104)			return -EINVAL;		break;	case WLAN_CIPHER_SUITE_AES_CMAC:		if (params->key_len != WLAN_KEY_LEN_AES_CMAC)			return -EINVAL;		break;	case WLAN_CIPHER_SUITE_BIP_CMAC_256:		if (params->key_len != WLAN_KEY_LEN_BIP_CMAC_256)			return -EINVAL;		break;	case WLAN_CIPHER_SUITE_BIP_GMAC_128:		if (params->key_len != WLAN_KEY_LEN_BIP_GMAC_128)			return -EINVAL;		break;	case WLAN_CIPHER_SUITE_BIP_GMAC_256:		if (params->key_len != WLAN_KEY_LEN_BIP_GMAC_256)			return -EINVAL;		break;	default:		/*		 * We don't know anything about this algorithm,		 * allow using it -- but the driver must check		 * all parameters! We still check below whether		 * or not the driver supports this algorithm,		 * of course.		 */		break;	} 	if (params->seq) {		switch (params->cipher) {		case WLAN_CIPHER_SUITE_WEP40:		case WLAN_CIPHER_SUITE_WEP104:			/* These ciphers do not use key sequence */			return -EINVAL;		case WLAN_CIPHER_SUITE_TKIP:		case WLAN_CIPHER_SUITE_CCMP:		case WLAN_CIPHER_SUITE_CCMP_256:		case WLAN_CIPHER_SUITE_GCMP:		case WLAN_CIPHER_SUITE_GCMP_256:		case WLAN_CIPHER_SUITE_AES_CMAC:		case WLAN_CIPHER_SUITE_BIP_CMAC_256:		case WLAN_CIPHER_SUITE_BIP_GMAC_128:		case WLAN_CIPHER_SUITE_BIP_GMAC_256:			if (params->seq_len != 6)				return -EINVAL;			break;		}	} 	if (!cfg80211_supported_cipher_suite(&rdev->wiphy, params->cipher))		return -EINVAL; 	if (params->ltf_keyseed) {		if (!wiphy_ext_feature_isset(&rdev->wiphy,					     NL80211_EXT_FEATURE_SECURE_LTF) ||		    !wiphy_ext_feature_isset(&rdev->wiphy,					     NL80211_EXT_FEATURE_SET_KEY_LTF_SEED))			return -EOPNOTSUPP; 		/*		 * LTF key seed is pairwise key material and must only be		 * used with a pairwise key		 */		if (!pairwise)			return -EINVAL;

Lines 1–500 of 3136.