15af33045SJules Irenge // SPDX-License-Identifier: GPL-2.0
294a79942SLarry Finger /******************************************************************************
394a79942SLarry Finger  * Copyright(c) 2008 - 2010 Realtek Corporation. All rights reserved.
494a79942SLarry Finger  *
594a79942SLarry Finger  * Contact Information:
694a79942SLarry Finger  * wlanfae <wlanfae@realtek.com>
794a79942SLarry Finger  ******************************************************************************/
894a79942SLarry Finger #include "dot11d.h"
994a79942SLarry Finger 
1094a79942SLarry Finger struct channel_list {
115f98ddc9SHimadri Pandya 	u8      channel[32];
1275752154SHimadri Pandya 	u8      len;
1394a79942SLarry Finger };
1494a79942SLarry Finger 
153262af00SHimadri Pandya static struct channel_list channel_array[] = {
1694a79942SLarry Finger 	{{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 36, 40, 44, 48, 52, 56, 60, 64,
1794a79942SLarry Finger 	  149, 153, 157, 161, 165}, 24},
1894a79942SLarry Finger 	{{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}, 11},
1994a79942SLarry Finger 	{{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 36, 40, 44, 48, 52, 56,
2094a79942SLarry Finger 	  60, 64}, 21},
2194a79942SLarry Finger 	{{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13}, 13},
2294a79942SLarry Finger 	{{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13}, 13},
2394a79942SLarry Finger 	{{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 36, 40, 44, 48, 52,
2494a79942SLarry Finger 	  56, 60, 64}, 22},
2594a79942SLarry Finger 	{{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 36, 40, 44, 48, 52,
2694a79942SLarry Finger 	  56, 60, 64}, 22},
2794a79942SLarry Finger 	{{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13}, 13},
2894a79942SLarry Finger 	{{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 36, 40, 44, 48, 52,
2994a79942SLarry Finger 	  56, 60, 64}, 22},
3094a79942SLarry Finger 	{{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 36, 40, 44, 48, 52,
3194a79942SLarry Finger 	 56, 60, 64}, 22},
3294a79942SLarry Finger 	{{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14}, 14},
3394a79942SLarry Finger 	{{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13}, 13},
3494a79942SLarry Finger 	{{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 36, 40, 44, 48, 52,
3594a79942SLarry Finger 	  56, 60, 64}, 21}
3694a79942SLarry Finger };
3794a79942SLarry Finger 
dot11d_init(struct rtllib_device * ieee)38976d5341SSean MacLennan void dot11d_init(struct rtllib_device *ieee)
3994a79942SLarry Finger {
40a180ef30SHimadri Pandya 	struct rt_dot11d_info *dot11d_info = GET_DOT11D_INFO(ieee);
413a6b70c3SMatthew Casey 
42a180ef30SHimadri Pandya 	dot11d_info->enabled = false;
4394a79942SLarry Finger 
44a180ef30SHimadri Pandya 	dot11d_info->state = DOT11D_STATE_NONE;
45a180ef30SHimadri Pandya 	dot11d_info->country_len = 0;
46a180ef30SHimadri Pandya 	memset(dot11d_info->channel_map, 0, MAX_CHANNEL_NUMBER + 1);
47a180ef30SHimadri Pandya 	memset(dot11d_info->max_tx_power_list, 0xFF, MAX_CHANNEL_NUMBER + 1);
4894a79942SLarry Finger 	RESET_CIE_WATCHDOG(ieee);
4994a79942SLarry Finger }
50976d5341SSean MacLennan EXPORT_SYMBOL(dot11d_init);
5194a79942SLarry Finger 
dot11d_channel_map(u8 channel_plan,struct rtllib_device * ieee)5230c311a2SHimadri Pandya void dot11d_channel_map(u8 channel_plan, struct rtllib_device *ieee)
5394a79942SLarry Finger {
5494a79942SLarry Finger 	int i, max_chan = 14, min_chan = 1;
5594a79942SLarry Finger 
56a180ef30SHimadri Pandya 	ieee->global_domain = false;
5794a79942SLarry Finger 
5875752154SHimadri Pandya 	if (channel_array[channel_plan].len != 0) {
5994a79942SLarry Finger 		memset(GET_DOT11D_INFO(ieee)->channel_map, 0,
6094a79942SLarry Finger 		       sizeof(GET_DOT11D_INFO(ieee)->channel_map));
6175752154SHimadri Pandya 		for (i = 0; i < channel_array[channel_plan].len; i++) {
623262af00SHimadri Pandya 			if (channel_array[channel_plan].channel[i] < min_chan ||
633262af00SHimadri Pandya 			    channel_array[channel_plan].channel[i] > max_chan)
6494a79942SLarry Finger 				break;
653262af00SHimadri Pandya 			GET_DOT11D_INFO(ieee)->channel_map[channel_array
665f98ddc9SHimadri Pandya 					[channel_plan].channel[i]] = 1;
6794a79942SLarry Finger 		}
6894a79942SLarry Finger 	}
6994a79942SLarry Finger 
7094a79942SLarry Finger 	switch (channel_plan) {
7194a79942SLarry Finger 	case COUNTRY_CODE_GLOBAL_DOMAIN:
72a180ef30SHimadri Pandya 		ieee->global_domain = true;
7394a79942SLarry Finger 		for (i = 12; i <= 14; i++)
7494a79942SLarry Finger 			GET_DOT11D_INFO(ieee)->channel_map[i] = 2;
75a180ef30SHimadri Pandya 		ieee->bss_start_channel = 10;
7694a79942SLarry Finger 		ieee->ibss_maxjoin_chal = 11;
7794a79942SLarry Finger 		break;
7894a79942SLarry Finger 
7994a79942SLarry Finger 	case COUNTRY_CODE_WORLD_WIDE_13:
8094a79942SLarry Finger 		for (i = 12; i <= 13; i++)
8194a79942SLarry Finger 			GET_DOT11D_INFO(ieee)->channel_map[i] = 2;
82a180ef30SHimadri Pandya 		ieee->bss_start_channel = 10;
8394a79942SLarry Finger 		ieee->ibss_maxjoin_chal = 11;
8494a79942SLarry Finger 		break;
8594a79942SLarry Finger 
8694a79942SLarry Finger 	default:
87a180ef30SHimadri Pandya 		ieee->bss_start_channel = 1;
8894a79942SLarry Finger 		ieee->ibss_maxjoin_chal = 14;
8994a79942SLarry Finger 		break;
9094a79942SLarry Finger 	}
9194a79942SLarry Finger }
9230c311a2SHimadri Pandya EXPORT_SYMBOL(dot11d_channel_map);
9394a79942SLarry Finger 
dot11d_reset(struct rtllib_device * ieee)948e9f5da2SHimadri Pandya void dot11d_reset(struct rtllib_device *ieee)
9594a79942SLarry Finger {
96a180ef30SHimadri Pandya 	struct rt_dot11d_info *dot11d_info = GET_DOT11D_INFO(ieee);
9794a79942SLarry Finger 	u32 i;
9894a79942SLarry Finger 
99a180ef30SHimadri Pandya 	memset(dot11d_info->channel_map, 0, MAX_CHANNEL_NUMBER + 1);
100a180ef30SHimadri Pandya 	memset(dot11d_info->max_tx_power_list, 0xFF, MAX_CHANNEL_NUMBER + 1);
10194a79942SLarry Finger 	for (i = 1; i <= 11; i++)
102a180ef30SHimadri Pandya 		(dot11d_info->channel_map)[i] = 1;
10394a79942SLarry Finger 	for (i = 12; i <= 14; i++)
104a180ef30SHimadri Pandya 		(dot11d_info->channel_map)[i] = 2;
105a180ef30SHimadri Pandya 	dot11d_info->state = DOT11D_STATE_NONE;
106a180ef30SHimadri Pandya 	dot11d_info->country_len = 0;
10794a79942SLarry Finger 	RESET_CIE_WATCHDOG(ieee);
10894a79942SLarry Finger }
10994a79942SLarry Finger 
dot11d_update_country(struct rtllib_device * dev,u8 * address,u16 country_len,u8 * country)1107ed27a09SHimadri Pandya void dot11d_update_country(struct rtllib_device *dev, u8 *address,
1117ed27a09SHimadri Pandya 			   u16 country_len, u8 *country)
11294a79942SLarry Finger {
113a180ef30SHimadri Pandya 	struct rt_dot11d_info *dot11d_info = GET_DOT11D_INFO(dev);
1145441ab2fSHimadri Pandya 	u8 i, j, number_of_triples, max_channel_number;
1155441ab2fSHimadri Pandya 	struct chnl_txpow_triple *triple;
11694a79942SLarry Finger 
117a180ef30SHimadri Pandya 	memset(dot11d_info->channel_map, 0, MAX_CHANNEL_NUMBER + 1);
118a180ef30SHimadri Pandya 	memset(dot11d_info->max_tx_power_list, 0xFF, MAX_CHANNEL_NUMBER + 1);
1195441ab2fSHimadri Pandya 	max_channel_number = 0;
1207ed27a09SHimadri Pandya 	number_of_triples = (country_len - 3) / 3;
1217ed27a09SHimadri Pandya 	triple = (struct chnl_txpow_triple *)(country + 3);
1225441ab2fSHimadri Pandya 	for (i = 0; i < number_of_triples; i++) {
1235441ab2fSHimadri Pandya 		if (max_channel_number >= triple->first_channel) {
124c476b2ecSMihaela Muraru 			netdev_info(dev->dev,
125c476b2ecSMihaela Muraru 				    "%s: Invalid country IE, skip it......1\n",
126c476b2ecSMihaela Muraru 				    __func__);
12794a79942SLarry Finger 			return;
12894a79942SLarry Finger 		}
1295441ab2fSHimadri Pandya 		if (MAX_CHANNEL_NUMBER < (triple->first_channel +
1305441ab2fSHimadri Pandya 		    triple->num_channels)) {
131c476b2ecSMihaela Muraru 			netdev_info(dev->dev,
132c476b2ecSMihaela Muraru 				    "%s: Invalid country IE, skip it......2\n",
133c476b2ecSMihaela Muraru 				    __func__);
13494a79942SLarry Finger 			return;
13594a79942SLarry Finger 		}
13694a79942SLarry Finger 
1375441ab2fSHimadri Pandya 		for (j = 0; j < triple->num_channels; j++) {
1385441ab2fSHimadri Pandya 			dot11d_info->channel_map[triple->first_channel + j] = 1;
1395441ab2fSHimadri Pandya 			dot11d_info->max_tx_power_list[triple->first_channel + j] =
1405441ab2fSHimadri Pandya 						 triple->max_tx_power;
1415441ab2fSHimadri Pandya 			max_channel_number = triple->first_channel + j;
14294a79942SLarry Finger 		}
14394a79942SLarry Finger 
1445441ab2fSHimadri Pandya 		triple = (struct chnl_txpow_triple *)((u8 *)triple + 3);
14594a79942SLarry Finger 	}
14694a79942SLarry Finger 
1477ed27a09SHimadri Pandya 	UPDATE_CIE_SRC(dev, address);
14894a79942SLarry Finger 
1497ed27a09SHimadri Pandya 	dot11d_info->country_len = country_len;
1507ed27a09SHimadri Pandya 	memcpy(dot11d_info->country_buffer, country, country_len);
151a180ef30SHimadri Pandya 	dot11d_info->state = DOT11D_STATE_LEARNED;
15294a79942SLarry Finger }
15394a79942SLarry Finger 
dot11d_scan_complete(struct rtllib_device * dev)154c40cac3bSHimadri Pandya void dot11d_scan_complete(struct rtllib_device *dev)
15594a79942SLarry Finger {
156a180ef30SHimadri Pandya 	struct rt_dot11d_info *dot11d_info = GET_DOT11D_INFO(dev);
15794a79942SLarry Finger 
158a180ef30SHimadri Pandya 	switch (dot11d_info->state) {
15994a79942SLarry Finger 	case DOT11D_STATE_LEARNED:
160a180ef30SHimadri Pandya 		dot11d_info->state = DOT11D_STATE_DONE;
16194a79942SLarry Finger 		break;
16294a79942SLarry Finger 	case DOT11D_STATE_DONE:
1638e9f5da2SHimadri Pandya 		dot11d_reset(dev);
16494a79942SLarry Finger 		break;
16594a79942SLarry Finger 	case DOT11D_STATE_NONE:
16694a79942SLarry Finger 		break;
16794a79942SLarry Finger 	}
16894a79942SLarry Finger }
169