1474 lines · 35.0 KB · C
RawDownload
/* * Wireless utility functions * * Copyright 2007-2009	Johannes Berg <johannes@sipsolutions.net> */#include <linux/export.h>#include <linux/bitops.h>#include <linux/etherdevice.h>#include <linux/slab.h>#include <net/cfg80211.h>#include <net/ip.h>#include <net/dsfield.h>#include <linux/if_vlan.h>#include "core.h"#include "rdev-ops.h"  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,			      enum nl80211_bss_scan_width scan_width){	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 == IEEE80211_BAND_2GHZ) {		if (scan_width == NL80211_BSS_CHAN_WIDTH_5 ||		    scan_width == NL80211_BSS_CHAN_WIDTH_10)			mandatory_flag = IEEE80211_RATE_MANDATORY_G;		else			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); int ieee80211_channel_to_frequency(int chan, enum ieee80211_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 IEEE80211_BAND_2GHZ:		if (chan == 14)			return 2484;		else if (chan < 14)			return 2407 + chan * 5;		break;	case IEEE80211_BAND_5GHZ:		if (chan >= 182 && chan <= 196)			return 4000 + chan * 5;		else			return 5000 + chan * 5;		break;	case IEEE80211_BAND_60GHZ:		if (chan < 5)			return 56160 + chan * 2160;		break;	default:		;	}	return 0; /* not supported */}EXPORT_SYMBOL(ieee80211_channel_to_frequency); int ieee80211_frequency_to_channel(int 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 <= 45000) /* DMG band lower limit */		return (freq - 5000) / 5;	else if (freq >= 58320 && freq <= 64800)		return (freq - 56160) / 2160;	else		return 0;}EXPORT_SYMBOL(ieee80211_frequency_to_channel); struct ieee80211_channel *__ieee80211_get_channel(struct wiphy *wiphy,						  int freq){	enum ieee80211_band band;	struct ieee80211_supported_band *sband;	int i; 	for (band = 0; band < IEEE80211_NUM_BANDS; band++) {		sband = wiphy->bands[band]; 		if (!sband)			continue; 		for (i = 0; i < sband->n_channels; i++) {			if (sband->channels[i].center_freq == freq)				return &sband->channels[i];		}	} 	return NULL;}EXPORT_SYMBOL(__ieee80211_get_channel); static void set_mandatory_flags_band(struct ieee80211_supported_band *sband,				     enum ieee80211_band band){	int i, want; 	switch (band) {	case IEEE80211_BAND_5GHZ:		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 IEEE80211_BAND_2GHZ:		want = 7;		for (i = 0; i < sband->n_bitrates; i++) {			if (sband->bitrates[i].bitrate == 10) {				sband->bitrates[i].flags |=					IEEE80211_RATE_MANDATORY_B |					IEEE80211_RATE_MANDATORY_G;				want--;			} 			if (sband->bitrates[i].bitrate == 20 ||			    sband->bitrates[i].bitrate == 55 ||			    sband->bitrates[i].bitrate == 110 ||			    sband->bitrates[i].bitrate == 60 ||			    sband->bitrates[i].bitrate == 120 ||			    sband->bitrates[i].bitrate == 240) {				sband->bitrates[i].flags |=					IEEE80211_RATE_MANDATORY_G;				want--;			} 			if (sband->bitrates[i].bitrate != 10 &&			    sband->bitrates[i].bitrate != 20 &&			    sband->bitrates[i].bitrate != 55 &&			    sband->bitrates[i].bitrate != 110)				sband->bitrates[i].flags |=					IEEE80211_RATE_ERP_G;		}		WARN_ON(want != 0 && want != 3 && want != 6);		break;	case IEEE80211_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 IEEE80211_NUM_BANDS:		WARN_ON(1);		break;	}} void ieee80211_set_bitrate_flags(struct wiphy *wiphy){	enum ieee80211_band band; 	for (band = 0; band < IEEE80211_NUM_BANDS; band++)		if (wiphy->bands[band])			set_mandatory_flags_band(wiphy->bands[band], 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;} int cfg80211_validate_key_settings(struct cfg80211_registered_device *rdev,				   struct key_params *params, int key_idx,				   bool pairwise, const u8 *mac_addr){	if (key_idx > 5)		return -EINVAL; 	if (!pairwise && mac_addr && !(rdev->wiphy.flags & WIPHY_FLAG_IBSS_RSN))		return -EINVAL; 	if (pairwise && !mac_addr)		return -EINVAL; 	/*	 * Disallow pairwise keys with non-zero index unless it's WEP	 * or a vendor specific cipher (because current deployments use	 * pairwise WEP keys with non-zero indices and for vendor specific	 * ciphers this should be validated in the driver or hardware level	 * - but 802.11i clearly specifies to use zero)	 */	if (pairwise && key_idx &&	    ((params->cipher == WLAN_CIPHER_SUITE_TKIP) ||	     (params->cipher == WLAN_CIPHER_SUITE_CCMP) ||	     (params->cipher == WLAN_CIPHER_SUITE_AES_CMAC)))		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_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;	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_AES_CMAC:			if (params->seq_len != 6)				return -EINVAL;			break;		}	} 	if (!cfg80211_supported_cipher_suite(&rdev->wiphy, params->cipher))		return -EINVAL; 	return 0;} unsigned int __attribute_const__ ieee80211_hdrlen(__le16 fc){	unsigned int hdrlen = 24; 	if (ieee80211_is_data(fc)) {		if (ieee80211_has_a4(fc))			hdrlen = 30;		if (ieee80211_is_data_qos(fc)) {			hdrlen += IEEE80211_QOS_CTL_LEN;			if (ieee80211_has_order(fc))				hdrlen += IEEE80211_HT_CTL_LEN;		}		goto out;	} 	if (ieee80211_is_ctl(fc)) {		/*		 * ACK and CTS are 10 bytes, all others 16. To see how		 * to get this condition consider		 *   subtype mask:   0b0000000011110000 (0x00F0)		 *   ACK subtype:    0b0000000011010000 (0x00D0)		 *   CTS subtype:    0b0000000011000000 (0x00C0)		 *   bits that matter:         ^^^      (0x00E0)		 *   value of those: 0b0000000011000000 (0x00C0)		 */		if ((fc & cpu_to_le16(0x00E0)) == cpu_to_le16(0x00C0))			hdrlen = 10;		else			hdrlen = 16;	}out:	return hdrlen;}EXPORT_SYMBOL(ieee80211_hdrlen); unsigned int ieee80211_get_hdrlen_from_skb(const struct sk_buff *skb){	const struct ieee80211_hdr *hdr =			(const struct ieee80211_hdr *)skb->data;	unsigned int hdrlen; 	if (unlikely(skb->len < 10))		return 0;	hdrlen = ieee80211_hdrlen(hdr->frame_control);	if (unlikely(hdrlen > skb->len))		return 0;	return hdrlen;}EXPORT_SYMBOL(ieee80211_get_hdrlen_from_skb); unsigned int ieee80211_get_mesh_hdrlen(struct ieee80211s_hdr *meshhdr){	int ae = meshhdr->flags & MESH_FLAGS_AE;	/* 802.11-2012, 8.2.4.7.3 */	switch (ae) {	default:	case 0:		return 6;	case MESH_FLAGS_AE_A4:		return 12;	case MESH_FLAGS_AE_A5_A6:		return 18;	}}EXPORT_SYMBOL(ieee80211_get_mesh_hdrlen); int ieee80211_data_to_8023(struct sk_buff *skb, const u8 *addr,			   enum nl80211_iftype iftype){	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;	u16 hdrlen, ethertype;	u8 *payload;	u8 dst[ETH_ALEN];	u8 src[ETH_ALEN] __aligned(2); 	if (unlikely(!ieee80211_is_data_present(hdr->frame_control)))		return -1; 	hdrlen = ieee80211_hdrlen(hdr->frame_control); 	/* convert IEEE 802.11 header + possible LLC headers into Ethernet	 * header	 * IEEE 802.11 address fields:	 * ToDS FromDS Addr1 Addr2 Addr3 Addr4	 *   0     0   DA    SA    BSSID n/a	 *   0     1   DA    BSSID SA    n/a	 *   1     0   BSSID SA    DA    n/a	 *   1     1   RA    TA    DA    SA	 */	memcpy(dst, ieee80211_get_DA(hdr), ETH_ALEN);	memcpy(src, ieee80211_get_SA(hdr), ETH_ALEN); 	switch (hdr->frame_control &		cpu_to_le16(IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) {	case cpu_to_le16(IEEE80211_FCTL_TODS):		if (unlikely(iftype != NL80211_IFTYPE_AP &&			     iftype != NL80211_IFTYPE_AP_VLAN &&			     iftype != NL80211_IFTYPE_P2P_GO))			return -1;		break;	case cpu_to_le16(IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS):		if (unlikely(iftype != NL80211_IFTYPE_WDS &&			     iftype != NL80211_IFTYPE_MESH_POINT &&			     iftype != NL80211_IFTYPE_AP_VLAN &&			     iftype != NL80211_IFTYPE_STATION))			return -1;		if (iftype == NL80211_IFTYPE_MESH_POINT) {			struct ieee80211s_hdr *meshdr =				(struct ieee80211s_hdr *) (skb->data + hdrlen);			/* make sure meshdr->flags is on the linear part */			if (!pskb_may_pull(skb, hdrlen + 1))				return -1;			if (meshdr->flags & MESH_FLAGS_AE_A4)				return -1;			if (meshdr->flags & MESH_FLAGS_AE_A5_A6) {				skb_copy_bits(skb, hdrlen +					offsetof(struct ieee80211s_hdr, eaddr1),				       	dst, ETH_ALEN);				skb_copy_bits(skb, hdrlen +					offsetof(struct ieee80211s_hdr, eaddr2),				        src, ETH_ALEN);			}			hdrlen += ieee80211_get_mesh_hdrlen(meshdr);		}		break;	case cpu_to_le16(IEEE80211_FCTL_FROMDS):		if ((iftype != NL80211_IFTYPE_STATION &&		     iftype != NL80211_IFTYPE_P2P_CLIENT &&		     iftype != NL80211_IFTYPE_MESH_POINT) ||		    (is_multicast_ether_addr(dst) &&		     ether_addr_equal(src, addr)))			return -1;		if (iftype == NL80211_IFTYPE_MESH_POINT) {			struct ieee80211s_hdr *meshdr =				(struct ieee80211s_hdr *) (skb->data + hdrlen);			/* make sure meshdr->flags is on the linear part */			if (!pskb_may_pull(skb, hdrlen + 1))				return -1;			if (meshdr->flags & MESH_FLAGS_AE_A5_A6)				return -1;			if (meshdr->flags & MESH_FLAGS_AE_A4)				skb_copy_bits(skb, hdrlen +					offsetof(struct ieee80211s_hdr, eaddr1),					src, ETH_ALEN);			hdrlen += ieee80211_get_mesh_hdrlen(meshdr);		}		break;	case cpu_to_le16(0):		if (iftype != NL80211_IFTYPE_ADHOC &&		    iftype != NL80211_IFTYPE_STATION)				return -1;		break;	} 	if (!pskb_may_pull(skb, hdrlen + 8))		return -1; 	payload = skb->data + hdrlen;	ethertype = (payload[6] << 8) | payload[7]; 	if (likely((ether_addr_equal(payload, rfc1042_header) &&		    ethertype != ETH_P_AARP && ethertype != ETH_P_IPX) ||		   ether_addr_equal(payload, bridge_tunnel_header))) {		/* remove RFC1042 or Bridge-Tunnel encapsulation and		 * replace EtherType */		skb_pull(skb, hdrlen + 6);		memcpy(skb_push(skb, ETH_ALEN), src, ETH_ALEN);		memcpy(skb_push(skb, ETH_ALEN), dst, ETH_ALEN);	} else {		struct ethhdr *ehdr;		__be16 len; 		skb_pull(skb, hdrlen);		len = htons(skb->len);		ehdr = (struct ethhdr *) skb_push(skb, sizeof(struct ethhdr));		memcpy(ehdr->h_dest, dst, ETH_ALEN);		memcpy(ehdr->h_source, src, ETH_ALEN);		ehdr->h_proto = len;	}	return 0;}EXPORT_SYMBOL(ieee80211_data_to_8023); int ieee80211_data_from_8023(struct sk_buff *skb, const u8 *addr,			     enum nl80211_iftype iftype, u8 *bssid, bool qos){	struct ieee80211_hdr hdr;	u16 hdrlen, ethertype;	__le16 fc;	const u8 *encaps_data;	int encaps_len, skip_header_bytes;	int nh_pos, h_pos;	int head_need; 	if (unlikely(skb->len < ETH_HLEN))		return -EINVAL; 	nh_pos = skb_network_header(skb) - skb->data;	h_pos = skb_transport_header(skb) - skb->data; 	/* convert Ethernet header to proper 802.11 header (based on	 * operation mode) */	ethertype = (skb->data[12] << 8) | skb->data[13];	fc = cpu_to_le16(IEEE80211_FTYPE_DATA | IEEE80211_STYPE_DATA); 	switch (iftype) {	case NL80211_IFTYPE_AP:

Lines 1–500 of 1474.