linux/drivers/staging/rtl8192u/ieee80211/dot11d.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/* Implement 802.11d. */
   3
   4#include "dot11d.h"
   5
   6void rtl8192u_dot11d_init(struct ieee80211_device *ieee)
   7{
   8        struct rt_dot11d_info *dot11d_info = GET_DOT11D_INFO(ieee);
   9
  10        dot11d_info->dot11d_enabled = false;
  11
  12        dot11d_info->state = DOT11D_STATE_NONE;
  13        dot11d_info->country_ie_len = 0;
  14        memset(dot11d_info->channel_map, 0, MAX_CHANNEL_NUMBER + 1);
  15        memset(dot11d_info->max_tx_pwr_dbm_list, 0xFF, MAX_CHANNEL_NUMBER + 1);
  16        RESET_CIE_WATCHDOG(ieee);
  17}
  18EXPORT_SYMBOL(rtl8192u_dot11d_init);
  19
  20/* Reset to the state as we are just entering a regulatory domain. */
  21void dot11d_reset(struct ieee80211_device *ieee)
  22{
  23        u32 i;
  24        struct rt_dot11d_info *dot11d_info = GET_DOT11D_INFO(ieee);
  25        /* Clear old channel map */
  26        memset(dot11d_info->channel_map, 0, MAX_CHANNEL_NUMBER + 1);
  27        memset(dot11d_info->max_tx_pwr_dbm_list, 0xFF, MAX_CHANNEL_NUMBER + 1);
  28        /* Set new channel map */
  29        for (i = 1; i <= 11; i++)
  30                (dot11d_info->channel_map)[i] = 1;
  31
  32        for (i = 12; i <= 14; i++)
  33                (dot11d_info->channel_map)[i] = 2;
  34
  35        dot11d_info->state = DOT11D_STATE_NONE;
  36        dot11d_info->country_ie_len = 0;
  37        RESET_CIE_WATCHDOG(ieee);
  38}
  39EXPORT_SYMBOL(dot11d_reset);
  40
  41/*
  42 * Update country IE from Beacon or Probe Resopnse and configure PHY for
  43 * operation in the regulatory domain.
  44 *
  45 * TODO: Configure Tx power.
  46 * Assumption:
  47 * 1. IS_DOT11D_ENABLE() is TRUE.
  48 * 2. Input IE is an valid one.
  49 */
  50void dot11d_update_country_ie(struct ieee80211_device *dev, u8 *pTaddr,
  51                            u16 CoutryIeLen, u8 *pCoutryIe)
  52{
  53        struct rt_dot11d_info *dot11d_info = GET_DOT11D_INFO(dev);
  54        u8 i, j, NumTriples, MaxChnlNum;
  55        struct chnl_txpower_triple *pTriple;
  56
  57        memset(dot11d_info->channel_map, 0, MAX_CHANNEL_NUMBER + 1);
  58        memset(dot11d_info->max_tx_pwr_dbm_list, 0xFF, MAX_CHANNEL_NUMBER + 1);
  59        MaxChnlNum = 0;
  60        NumTriples = (CoutryIeLen - 3) / 3; /* skip 3-byte country string. */
  61        pTriple = (struct chnl_txpower_triple *)(pCoutryIe + 3);
  62        for (i = 0; i < NumTriples; i++) {
  63                if (MaxChnlNum >= pTriple->first_channel) {
  64                        /* It is not in a monotonically increasing order, so
  65                         * stop processing.
  66                         */
  67                        netdev_err(dev->dev, "%s: Invalid country IE, skip it 1\n", __func__);
  68                        return;
  69                }
  70                if (MAX_CHANNEL_NUMBER < (pTriple->first_channel + pTriple->num_channels)) {
  71                        /* It is not a valid set of channel id, so stop
  72                         * processing.
  73                         */
  74                        netdev_err(dev->dev, "%s: Invalid country IE, skip it 2\n", __func__);
  75                        return;
  76                }
  77
  78                for (j = 0; j < pTriple->num_channels; j++) {
  79                        dot11d_info->channel_map[pTriple->first_channel + j] = 1;
  80                        dot11d_info->max_tx_pwr_dbm_list[pTriple->first_channel + j] = pTriple->max_tx_pwr_dbm;
  81                        MaxChnlNum = pTriple->first_channel + j;
  82                }
  83
  84                pTriple = (struct chnl_txpower_triple *)((u8 *)pTriple + 3);
  85        }
  86        netdev_info(dev->dev, "Channel List:");
  87        for (i = 1; i <= MAX_CHANNEL_NUMBER; i++)
  88                if (dot11d_info->channel_map[i] > 0)
  89                        netdev_info(dev->dev, " %d", i);
  90        netdev_info(dev->dev, "\n");
  91
  92        UPDATE_CIE_SRC(dev, pTaddr);
  93
  94        dot11d_info->country_ie_len = CoutryIeLen;
  95        memcpy(dot11d_info->country_ie_buf, pCoutryIe, CoutryIeLen);
  96        dot11d_info->state = DOT11D_STATE_LEARNED;
  97}
  98EXPORT_SYMBOL(dot11d_update_country_ie);
  99
 100u8 dot11d_get_max_tx_pwr_in_dbm(struct ieee80211_device *dev, u8 Channel)
 101{
 102        struct rt_dot11d_info *dot11d_info = GET_DOT11D_INFO(dev);
 103        u8 MaxTxPwrInDbm = 255;
 104
 105        if (Channel > MAX_CHANNEL_NUMBER) {
 106                netdev_err(dev->dev, "%s: Invalid Channel\n", __func__);
 107                return MaxTxPwrInDbm;
 108        }
 109        if (dot11d_info->channel_map[Channel])
 110                MaxTxPwrInDbm = dot11d_info->max_tx_pwr_dbm_list[Channel];
 111
 112        return MaxTxPwrInDbm;
 113}
 114EXPORT_SYMBOL(dot11d_get_max_tx_pwr_in_dbm);
 115
 116void dot11d_scan_complete(struct ieee80211_device *dev)
 117{
 118        struct rt_dot11d_info *dot11d_info = GET_DOT11D_INFO(dev);
 119
 120        switch (dot11d_info->state) {
 121        case DOT11D_STATE_LEARNED:
 122                dot11d_info->state = DOT11D_STATE_DONE;
 123                break;
 124
 125        case DOT11D_STATE_DONE:
 126                if (GET_CIE_WATCHDOG(dev) == 0) {
 127                        /* Reset country IE if previous one is gone. */
 128                        dot11d_reset(dev);
 129                }
 130                break;
 131        case DOT11D_STATE_NONE:
 132                break;
 133        }
 134}
 135EXPORT_SYMBOL(dot11d_scan_complete);
 136
 137int is_legal_channel(struct ieee80211_device *dev, u8 channel)
 138{
 139        struct rt_dot11d_info *dot11d_info = GET_DOT11D_INFO(dev);
 140
 141        if (channel > MAX_CHANNEL_NUMBER) {
 142                netdev_err(dev->dev, "%s: Invalid Channel\n", __func__);
 143                return 0;
 144        }
 145        if (dot11d_info->channel_map[channel] > 0)
 146                return 1;
 147        return 0;
 148}
 149EXPORT_SYMBOL(is_legal_channel);
 150
 151int to_legal_channel(struct ieee80211_device *dev, u8 channel)
 152{
 153        struct rt_dot11d_info *dot11d_info = GET_DOT11D_INFO(dev);
 154        u8 default_chn = 0;
 155        u32 i = 0;
 156
 157        for (i = 1; i <= MAX_CHANNEL_NUMBER; i++) {
 158                if (dot11d_info->channel_map[i] > 0) {
 159                        default_chn = i;
 160                        break;
 161                }
 162        }
 163
 164        if (channel > MAX_CHANNEL_NUMBER) {
 165                netdev_err(dev->dev, "%s: Invalid Channel\n", __func__);
 166                return default_chn;
 167        }
 168
 169        if (dot11d_info->channel_map[channel] > 0)
 170                return channel;
 171
 172        return default_chn;
 173}
 174EXPORT_SYMBOL(to_legal_channel);
 175