mac80211: prevent reconfigure calls while interfaces are down
[openwrt.git] / package / mac80211 / patches / 524-mac80211_configure_antenna_gain.patch
1 --- a/include/net/mac80211.h
2 +++ b/include/net/mac80211.h
3 @@ -851,6 +851,7 @@ enum ieee80211_smps_mode {
4   *     the CONF_PS flag is set.
5   *
6   * @power_level: requested transmit power (in dBm)
7 + * @max_antenna_gain: maximum antenna gain adjusted by user config (in dBi)
8   *
9   * @channel: the channel to tune to
10   * @channel_type: the channel (HT) type
11 @@ -870,6 +871,7 @@ struct ieee80211_conf {
12         u32 flags;
13         int power_level, dynamic_ps_timeout;
14         int max_sleep_period;
15 +       int max_antenna_gain;
16  
17         u16 listen_interval;
18         u8 ps_dtim_period;
19 --- a/net/mac80211/main.c
20 +++ b/net/mac80211/main.c
21 @@ -101,7 +101,7 @@ int ieee80211_hw_config(struct ieee80211
22  {
23         struct ieee80211_channel *chan;
24         int ret = 0;
25 -       int power;
26 +       int power, ant_gain, max_power;
27         enum nl80211_channel_type channel_type;
28         u32 offchannel_flag;
29  
30 @@ -152,19 +152,31 @@ int ieee80211_hw_config(struct ieee80211
31                 changed |= IEEE80211_CONF_CHANGE_SMPS;
32         }
33  
34 -       if (test_bit(SCAN_SW_SCANNING, &local->scanning) ||
35 -           test_bit(SCAN_ONCHANNEL_SCANNING, &local->scanning) ||
36 -           test_bit(SCAN_HW_SCANNING, &local->scanning) ||
37 -           !local->ap_power_level)
38 -               power = chan->max_power;
39 -       else
40 -               power = min(chan->max_power, local->ap_power_level);
41 +       max_power = chan->max_reg_power;
42 +       if (!test_bit(SCAN_SW_SCANNING, &local->scanning) &&
43 +           !test_bit(SCAN_ONCHANNEL_SCANNING, &local->scanning) &&
44 +           !test_bit(SCAN_HW_SCANNING, &local->scanning) &&
45 +           local->ap_power_level)
46 +               max_power = min(max_power, local->ap_power_level);
47 +
48 +       ant_gain = chan->max_antenna_gain;
49 +       if (local->user_antenna_gain > 0) {
50 +               if (local->user_antenna_gain > ant_gain) {
51 +                       max_power -= local->user_antenna_gain - ant_gain;
52 +                       ant_gain = 0;
53 +               } else
54 +                       ant_gain -= local->user_antenna_gain;
55 +       }
56 +
57 +       power = min(chan->max_power, max_power);
58  
59         if (local->user_power_level >= 0)
60                 power = min(power, local->user_power_level);
61  
62 -       if (local->hw.conf.power_level != power) {
63 +       if (local->hw.conf.power_level != power ||
64 +               local->hw.conf.max_antenna_gain != ant_gain) {
65                 changed |= IEEE80211_CONF_CHANGE_POWER;
66 +               local->hw.conf.max_antenna_gain = ant_gain;
67                 local->hw.cur_power_level = power;
68                 local->hw.conf.power_level = power;
69         }
70 @@ -620,6 +632,7 @@ struct ieee80211_hw *ieee80211_alloc_hw(
71                                          IEEE80211_RADIOTAP_MCS_HAVE_GI |
72                                          IEEE80211_RADIOTAP_MCS_HAVE_BW;
73         local->user_power_level = -1;
74 +       local->user_antenna_gain = -1;
75         wiphy->ht_capa_mod_mask = &mac80211_ht_capa_mod_mask;
76  
77         INIT_LIST_HEAD(&local->interfaces);
78 --- a/net/mac80211/ieee80211_i.h
79 +++ b/net/mac80211/ieee80211_i.h
80 @@ -1063,6 +1063,7 @@ struct ieee80211_local {
81  
82         int user_power_level; /* in dBm */
83         int ap_power_level; /* in dBm */
84 +       int user_antenna_gain; /* in dBi */
85  
86         enum ieee80211_smps_mode smps_mode;
87  
88 --- a/include/linux/nl80211.h
89 +++ b/include/linux/nl80211.h
90 @@ -1517,6 +1517,8 @@ enum nl80211_attrs {
91  
92         NL80211_ATTR_USER_REG_HINT_TYPE,
93  
94 +       NL80211_ATTR_WIPHY_ANTENNA_GAIN,
95 +
96         /* add attributes here, update the policy in nl80211.c */
97  
98         __NL80211_ATTR_AFTER_LAST,
99 --- a/net/wireless/nl80211.c
100 +++ b/net/wireless/nl80211.c
101 @@ -355,6 +355,7 @@ static const struct nla_policy nl80211_p
102         [NL80211_ATTR_BG_SCAN_PERIOD] = { .type = NLA_U16 },
103         [NL80211_ATTR_WDEV] = { .type = NLA_U64 },
104         [NL80211_ATTR_USER_REG_HINT_TYPE] = { .type = NLA_U32 },
105 +       [NL80211_ATTR_WIPHY_ANTENNA_GAIN] = { .type = NLA_U32 },
106  };
107  
108  /* policy for the key attributes */
109 @@ -1604,6 +1605,22 @@ static int nl80211_set_wiphy(struct sk_b
110                         goto bad_res;
111         }
112  
113 +       if (info->attrs[NL80211_ATTR_WIPHY_ANTENNA_GAIN]) {
114 +               int idx, dbi = 0;
115 +
116 +               if (!rdev->ops->set_antenna_gain) {
117 +                       result = -EOPNOTSUPP;
118 +                       goto bad_res;
119 +               }
120 +
121 +               idx = NL80211_ATTR_WIPHY_ANTENNA_GAIN;
122 +               dbi = nla_get_u32(info->attrs[idx]);
123 +
124 +               result = rdev->ops->set_antenna_gain(&rdev->wiphy, dbi);
125 +               if (result)
126 +                       goto bad_res;
127 +       }
128 +
129         if (info->attrs[NL80211_ATTR_WIPHY_ANTENNA_TX] &&
130             info->attrs[NL80211_ATTR_WIPHY_ANTENNA_RX]) {
131                 u32 tx_ant, rx_ant;
132 --- a/net/mac80211/cfg.c
133 +++ b/net/mac80211/cfg.c
134 @@ -1984,6 +1984,19 @@ static int ieee80211_get_tx_power(struct
135         return 0;
136  }
137  
138 +static int ieee80211_set_antenna_gain(struct wiphy *wiphy, int dbi)
139 +{
140 +       struct ieee80211_local *local = wiphy_priv(wiphy);
141 +
142 +       if (dbi < 0)
143 +               return -EINVAL;
144 +
145 +       local->user_antenna_gain = dbi;
146 +       ieee80211_hw_config(local, 0);
147 +
148 +       return 0;
149 +}
150 +
151  static int ieee80211_set_wds_peer(struct wiphy *wiphy, struct net_device *dev,
152                                   const u8 *addr)
153  {
154 @@ -3085,6 +3098,7 @@ struct cfg80211_ops mac80211_config_ops 
155         .set_wiphy_params = ieee80211_set_wiphy_params,
156         .set_tx_power = ieee80211_set_tx_power,
157         .get_tx_power = ieee80211_get_tx_power,
158 +       .set_antenna_gain = ieee80211_set_antenna_gain,
159         .set_wds_peer = ieee80211_set_wds_peer,
160         .rfkill_poll = ieee80211_rfkill_poll,
161         CFG80211_TESTMODE_CMD(ieee80211_testmode_cmd)
162 --- a/include/net/cfg80211.h
163 +++ b/include/net/cfg80211.h
164 @@ -1552,6 +1552,7 @@ struct cfg80211_gtk_rekey_data {
165   *     the power passed is in mBm, to get dBm use MBM_TO_DBM().
166   * @get_tx_power: store the current TX power into the dbm variable;
167   *     return 0 if successful
168 + * @set_antenna_gain: set antenna gain to reduce maximum tx power if necessary
169   *
170   * @set_wds_peer: set the WDS peer for a WDS interface
171   *
172 @@ -1751,6 +1752,7 @@ struct cfg80211_ops {
173         int     (*set_tx_power)(struct wiphy *wiphy,
174                                 enum nl80211_tx_power_setting type, int mbm);
175         int     (*get_tx_power)(struct wiphy *wiphy, int *dbm);
176 +       int     (*set_antenna_gain)(struct wiphy *wiphy, int dbi);
177  
178         int     (*set_wds_peer)(struct wiphy *wiphy, struct net_device *dev,
179                                 const u8 *addr);