diff options
65 files changed, 3160 insertions, 833 deletions
diff --git a/drivers/net/wireless/ath/ath9k/rc.c b/drivers/net/wireless/ath/ath9k/rc.c index 714558d1ba78..54150b6a39ae 100644 --- a/drivers/net/wireless/ath/ath9k/rc.c +++ b/drivers/net/wireless/ath/ath9k/rc.c | |||
| @@ -1204,7 +1204,7 @@ static u8 ath_rc_build_ht_caps(struct ath_softc *sc, struct ieee80211_sta *sta) | |||
| 1204 | caps |= WLAN_RC_TS_FLAG | WLAN_RC_DS_FLAG; | 1204 | caps |= WLAN_RC_TS_FLAG | WLAN_RC_DS_FLAG; |
| 1205 | else if (sta->ht_cap.mcs.rx_mask[1]) | 1205 | else if (sta->ht_cap.mcs.rx_mask[1]) |
| 1206 | caps |= WLAN_RC_DS_FLAG; | 1206 | caps |= WLAN_RC_DS_FLAG; |
| 1207 | if (sta->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) { | 1207 | if (sta->bandwidth >= IEEE80211_STA_RX_BW_40) { |
| 1208 | caps |= WLAN_RC_40_FLAG; | 1208 | caps |= WLAN_RC_40_FLAG; |
| 1209 | if (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40) | 1209 | if (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40) |
| 1210 | caps |= WLAN_RC_SGI_FLAG; | 1210 | caps |= WLAN_RC_SGI_FLAG; |
diff --git a/drivers/net/wireless/iwlegacy/4965-rs.c b/drivers/net/wireless/iwlegacy/4965-rs.c index f3b8e91aa3dc..e8324b5e5bfe 100644 --- a/drivers/net/wireless/iwlegacy/4965-rs.c +++ b/drivers/net/wireless/iwlegacy/4965-rs.c | |||
| @@ -1183,8 +1183,7 @@ il4965_rs_switch_to_mimo2(struct il_priv *il, struct il_lq_sta *lq_sta, | |||
| 1183 | if (!conf_is_ht(conf) || !sta->ht_cap.ht_supported) | 1183 | if (!conf_is_ht(conf) || !sta->ht_cap.ht_supported) |
| 1184 | return -1; | 1184 | return -1; |
| 1185 | 1185 | ||
| 1186 | if (((sta->ht_cap.cap & IEEE80211_HT_CAP_SM_PS) >> 2) == | 1186 | if (sta->smps_mode == IEEE80211_SMPS_STATIC) |
| 1187 | WLAN_HT_CAP_SM_PS_STATIC) | ||
| 1188 | return -1; | 1187 | return -1; |
| 1189 | 1188 | ||
| 1190 | /* Need both Tx chains/antennas to support MIMO */ | 1189 | /* Need both Tx chains/antennas to support MIMO */ |
diff --git a/drivers/net/wireless/iwlegacy/common.c b/drivers/net/wireless/iwlegacy/common.c index 4ed2949f314d..e006ea831320 100644 --- a/drivers/net/wireless/iwlegacy/common.c +++ b/drivers/net/wireless/iwlegacy/common.c | |||
| @@ -1830,32 +1830,30 @@ il_set_ht_add_station(struct il_priv *il, u8 idx, struct ieee80211_sta *sta) | |||
| 1830 | { | 1830 | { |
| 1831 | struct ieee80211_sta_ht_cap *sta_ht_inf = &sta->ht_cap; | 1831 | struct ieee80211_sta_ht_cap *sta_ht_inf = &sta->ht_cap; |
| 1832 | __le32 sta_flags; | 1832 | __le32 sta_flags; |
| 1833 | u8 mimo_ps_mode; | ||
| 1834 | 1833 | ||
| 1835 | if (!sta || !sta_ht_inf->ht_supported) | 1834 | if (!sta || !sta_ht_inf->ht_supported) |
| 1836 | goto done; | 1835 | goto done; |
| 1837 | 1836 | ||
| 1838 | mimo_ps_mode = (sta_ht_inf->cap & IEEE80211_HT_CAP_SM_PS) >> 2; | ||
| 1839 | D_ASSOC("spatial multiplexing power save mode: %s\n", | 1837 | D_ASSOC("spatial multiplexing power save mode: %s\n", |
| 1840 | (mimo_ps_mode == WLAN_HT_CAP_SM_PS_STATIC) ? "static" : | 1838 | (sta->smps_mode == IEEE80211_SMPS_STATIC) ? "static" : |
| 1841 | (mimo_ps_mode == WLAN_HT_CAP_SM_PS_DYNAMIC) ? "dynamic" : | 1839 | (sta->smps_mode == IEEE80211_SMPS_DYNAMIC) ? "dynamic" : |
| 1842 | "disabled"); | 1840 | "disabled"); |
| 1843 | 1841 | ||
| 1844 | sta_flags = il->stations[idx].sta.station_flags; | 1842 | sta_flags = il->stations[idx].sta.station_flags; |
| 1845 | 1843 | ||
| 1846 | sta_flags &= ~(STA_FLG_RTS_MIMO_PROT_MSK | STA_FLG_MIMO_DIS_MSK); | 1844 | sta_flags &= ~(STA_FLG_RTS_MIMO_PROT_MSK | STA_FLG_MIMO_DIS_MSK); |
| 1847 | 1845 | ||
| 1848 | switch (mimo_ps_mode) { | 1846 | switch (sta->smps_mode) { |
| 1849 | case WLAN_HT_CAP_SM_PS_STATIC: | 1847 | case IEEE80211_SMPS_STATIC: |
| 1850 | sta_flags |= STA_FLG_MIMO_DIS_MSK; | 1848 | sta_flags |= STA_FLG_MIMO_DIS_MSK; |
| 1851 | break; | 1849 | break; |
| 1852 | case WLAN_HT_CAP_SM_PS_DYNAMIC: | 1850 | case IEEE80211_SMPS_DYNAMIC: |
| 1853 | sta_flags |= STA_FLG_RTS_MIMO_PROT_MSK; | 1851 | sta_flags |= STA_FLG_RTS_MIMO_PROT_MSK; |
| 1854 | break; | 1852 | break; |
| 1855 | case WLAN_HT_CAP_SM_PS_DISABLED: | 1853 | case IEEE80211_SMPS_OFF: |
| 1856 | break; | 1854 | break; |
| 1857 | default: | 1855 | default: |
| 1858 | IL_WARN("Invalid MIMO PS mode %d\n", mimo_ps_mode); | 1856 | IL_WARN("Invalid MIMO PS mode %d\n", sta->smps_mode); |
| 1859 | break; | 1857 | break; |
| 1860 | } | 1858 | } |
| 1861 | 1859 | ||
diff --git a/drivers/net/wireless/iwlwifi/dvm/agn.h b/drivers/net/wireless/iwlwifi/dvm/agn.h index f41ae79e6bc0..41ec27cb6efe 100644 --- a/drivers/net/wireless/iwlwifi/dvm/agn.h +++ b/drivers/net/wireless/iwlwifi/dvm/agn.h | |||
| @@ -338,7 +338,7 @@ int iwl_sta_update_ht(struct iwl_priv *priv, struct iwl_rxon_context *ctx, | |||
| 338 | 338 | ||
| 339 | bool iwl_is_ht40_tx_allowed(struct iwl_priv *priv, | 339 | bool iwl_is_ht40_tx_allowed(struct iwl_priv *priv, |
| 340 | struct iwl_rxon_context *ctx, | 340 | struct iwl_rxon_context *ctx, |
| 341 | struct ieee80211_sta_ht_cap *ht_cap); | 341 | struct ieee80211_sta *sta); |
| 342 | 342 | ||
| 343 | static inline int iwl_sta_id(struct ieee80211_sta *sta) | 343 | static inline int iwl_sta_id(struct ieee80211_sta *sta) |
| 344 | { | 344 | { |
diff --git a/drivers/net/wireless/iwlwifi/dvm/rs.c b/drivers/net/wireless/iwlwifi/dvm/rs.c index a131227c49e9..abe304267261 100644 --- a/drivers/net/wireless/iwlwifi/dvm/rs.c +++ b/drivers/net/wireless/iwlwifi/dvm/rs.c | |||
| @@ -1289,8 +1289,7 @@ static int rs_switch_to_mimo2(struct iwl_priv *priv, | |||
| 1289 | if (!conf_is_ht(conf) || !sta->ht_cap.ht_supported) | 1289 | if (!conf_is_ht(conf) || !sta->ht_cap.ht_supported) |
| 1290 | return -1; | 1290 | return -1; |
| 1291 | 1291 | ||
| 1292 | if (((sta->ht_cap.cap & IEEE80211_HT_CAP_SM_PS) >> 2) | 1292 | if (sta->smps_mode == IEEE80211_SMPS_STATIC) |
| 1293 | == WLAN_HT_CAP_SM_PS_STATIC) | ||
| 1294 | return -1; | 1293 | return -1; |
| 1295 | 1294 | ||
| 1296 | /* Need both Tx chains/antennas to support MIMO */ | 1295 | /* Need both Tx chains/antennas to support MIMO */ |
| @@ -1305,7 +1304,7 @@ static int rs_switch_to_mimo2(struct iwl_priv *priv, | |||
| 1305 | tbl->max_search = IWL_MAX_SEARCH; | 1304 | tbl->max_search = IWL_MAX_SEARCH; |
| 1306 | rate_mask = lq_sta->active_mimo2_rate; | 1305 | rate_mask = lq_sta->active_mimo2_rate; |
| 1307 | 1306 | ||
| 1308 | if (iwl_is_ht40_tx_allowed(priv, ctx, &sta->ht_cap)) | 1307 | if (iwl_is_ht40_tx_allowed(priv, ctx, sta)) |
| 1309 | tbl->is_ht40 = 1; | 1308 | tbl->is_ht40 = 1; |
| 1310 | else | 1309 | else |
| 1311 | tbl->is_ht40 = 0; | 1310 | tbl->is_ht40 = 0; |
| @@ -1345,8 +1344,7 @@ static int rs_switch_to_mimo3(struct iwl_priv *priv, | |||
| 1345 | if (!conf_is_ht(conf) || !sta->ht_cap.ht_supported) | 1344 | if (!conf_is_ht(conf) || !sta->ht_cap.ht_supported) |
| 1346 | return -1; | 1345 | return -1; |
| 1347 | 1346 | ||
| 1348 | if (((sta->ht_cap.cap & IEEE80211_HT_CAP_SM_PS) >> 2) | 1347 | if (sta->smps_mode == IEEE80211_SMPS_STATIC) |
| 1349 | == WLAN_HT_CAP_SM_PS_STATIC) | ||
| 1350 | return -1; | 1348 | return -1; |
| 1351 | 1349 | ||
| 1352 | /* Need both Tx chains/antennas to support MIMO */ | 1350 | /* Need both Tx chains/antennas to support MIMO */ |
| @@ -1361,7 +1359,7 @@ static int rs_switch_to_mimo3(struct iwl_priv *priv, | |||
| 1361 | tbl->max_search = IWL_MAX_11N_MIMO3_SEARCH; | 1359 | tbl->max_search = IWL_MAX_11N_MIMO3_SEARCH; |
| 1362 | rate_mask = lq_sta->active_mimo3_rate; | 1360 | rate_mask = lq_sta->active_mimo3_rate; |
| 1363 | 1361 | ||
| 1364 | if (iwl_is_ht40_tx_allowed(priv, ctx, &sta->ht_cap)) | 1362 | if (iwl_is_ht40_tx_allowed(priv, ctx, sta)) |
| 1365 | tbl->is_ht40 = 1; | 1363 | tbl->is_ht40 = 1; |
| 1366 | else | 1364 | else |
| 1367 | tbl->is_ht40 = 0; | 1365 | tbl->is_ht40 = 0; |
| @@ -1410,7 +1408,7 @@ static int rs_switch_to_siso(struct iwl_priv *priv, | |||
| 1410 | tbl->max_search = IWL_MAX_SEARCH; | 1408 | tbl->max_search = IWL_MAX_SEARCH; |
| 1411 | rate_mask = lq_sta->active_siso_rate; | 1409 | rate_mask = lq_sta->active_siso_rate; |
| 1412 | 1410 | ||
| 1413 | if (iwl_is_ht40_tx_allowed(priv, ctx, &sta->ht_cap)) | 1411 | if (iwl_is_ht40_tx_allowed(priv, ctx, sta)) |
| 1414 | tbl->is_ht40 = 1; | 1412 | tbl->is_ht40 = 1; |
| 1415 | else | 1413 | else |
| 1416 | tbl->is_ht40 = 0; | 1414 | tbl->is_ht40 = 0; |
diff --git a/drivers/net/wireless/iwlwifi/dvm/sta.c b/drivers/net/wireless/iwlwifi/dvm/sta.c index 2d33760a9dc2..94ef33838bc6 100644 --- a/drivers/net/wireless/iwlwifi/dvm/sta.c +++ b/drivers/net/wireless/iwlwifi/dvm/sta.c | |||
| @@ -173,7 +173,7 @@ int iwl_send_add_sta(struct iwl_priv *priv, | |||
| 173 | 173 | ||
| 174 | bool iwl_is_ht40_tx_allowed(struct iwl_priv *priv, | 174 | bool iwl_is_ht40_tx_allowed(struct iwl_priv *priv, |
| 175 | struct iwl_rxon_context *ctx, | 175 | struct iwl_rxon_context *ctx, |
| 176 | struct ieee80211_sta_ht_cap *ht_cap) | 176 | struct ieee80211_sta *sta) |
| 177 | { | 177 | { |
| 178 | if (!ctx->ht.enabled || !ctx->ht.is_40mhz) | 178 | if (!ctx->ht.enabled || !ctx->ht.is_40mhz) |
| 179 | return false; | 179 | return false; |
| @@ -183,20 +183,11 @@ bool iwl_is_ht40_tx_allowed(struct iwl_priv *priv, | |||
| 183 | return false; | 183 | return false; |
| 184 | #endif | 184 | #endif |
| 185 | 185 | ||
| 186 | /* | 186 | /* special case for RXON */ |
| 187 | * Remainder of this function checks ht_cap, but if it's | 187 | if (!sta) |
| 188 | * NULL then we can do HT40 (special case for RXON) | ||
| 189 | */ | ||
| 190 | if (!ht_cap) | ||
| 191 | return true; | 188 | return true; |
| 192 | 189 | ||
| 193 | if (!ht_cap->ht_supported) | 190 | return sta->bandwidth >= IEEE80211_STA_RX_BW_40; |
| 194 | return false; | ||
| 195 | |||
| 196 | if (!(ht_cap->cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40)) | ||
| 197 | return false; | ||
| 198 | |||
| 199 | return true; | ||
| 200 | } | 191 | } |
| 201 | 192 | ||
| 202 | static void iwl_sta_calc_ht_flags(struct iwl_priv *priv, | 193 | static void iwl_sta_calc_ht_flags(struct iwl_priv *priv, |
| @@ -205,7 +196,6 @@ static void iwl_sta_calc_ht_flags(struct iwl_priv *priv, | |||
| 205 | __le32 *flags, __le32 *mask) | 196 | __le32 *flags, __le32 *mask) |
| 206 | { | 197 | { |
| 207 | struct ieee80211_sta_ht_cap *sta_ht_inf = &sta->ht_cap; | 198 | struct ieee80211_sta_ht_cap *sta_ht_inf = &sta->ht_cap; |
| 208 | u8 mimo_ps_mode; | ||
| 209 | 199 | ||
| 210 | *mask = STA_FLG_RTS_MIMO_PROT_MSK | | 200 | *mask = STA_FLG_RTS_MIMO_PROT_MSK | |
| 211 | STA_FLG_MIMO_DIS_MSK | | 201 | STA_FLG_MIMO_DIS_MSK | |
| @@ -217,26 +207,24 @@ static void iwl_sta_calc_ht_flags(struct iwl_priv *priv, | |||
| 217 | if (!sta || !sta_ht_inf->ht_supported) | 207 | if (!sta || !sta_ht_inf->ht_supported) |
| 218 | return; | 208 | return; |
| 219 | 209 | ||
| 220 | mimo_ps_mode = (sta_ht_inf->cap & IEEE80211_HT_CAP_SM_PS) >> 2; | ||
| 221 | |||
| 222 | IWL_DEBUG_INFO(priv, "STA %pM SM PS mode: %s\n", | 210 | IWL_DEBUG_INFO(priv, "STA %pM SM PS mode: %s\n", |
| 223 | sta->addr, | 211 | sta->addr, |
| 224 | (mimo_ps_mode == WLAN_HT_CAP_SM_PS_STATIC) ? | 212 | (sta->smps_mode == IEEE80211_SMPS_STATIC) ? |
| 225 | "static" : | 213 | "static" : |
| 226 | (mimo_ps_mode == WLAN_HT_CAP_SM_PS_DYNAMIC) ? | 214 | (sta->smps_mode == IEEE80211_SMPS_DYNAMIC) ? |
| 227 | "dynamic" : "disabled"); | 215 | "dynamic" : "disabled"); |
| 228 | 216 | ||
| 229 | switch (mimo_ps_mode) { | 217 | switch (sta->smps_mode) { |
| 230 | case WLAN_HT_CAP_SM_PS_STATIC: | 218 | case IEEE80211_SMPS_STATIC: |
| 231 | *flags |= STA_FLG_MIMO_DIS_MSK; | 219 | *flags |= STA_FLG_MIMO_DIS_MSK; |
| 232 | break; | 220 | break; |
| 233 | case WLAN_HT_CAP_SM_PS_DYNAMIC: | 221 | case IEEE80211_SMPS_DYNAMIC: |
| 234 | *flags |= STA_FLG_RTS_MIMO_PROT_MSK; | 222 | *flags |= STA_FLG_RTS_MIMO_PROT_MSK; |
| 235 | break; | 223 | break; |
| 236 | case WLAN_HT_CAP_SM_PS_DISABLED: | 224 | case IEEE80211_SMPS_OFF: |
| 237 | break; | 225 | break; |
| 238 | default: | 226 | default: |
| 239 | IWL_WARN(priv, "Invalid MIMO PS mode %d\n", mimo_ps_mode); | 227 | IWL_WARN(priv, "Invalid MIMO PS mode %d\n", sta->smps_mode); |
| 240 | break; | 228 | break; |
| 241 | } | 229 | } |
| 242 | 230 | ||
| @@ -246,7 +234,7 @@ static void iwl_sta_calc_ht_flags(struct iwl_priv *priv, | |||
| 246 | *flags |= cpu_to_le32( | 234 | *flags |= cpu_to_le32( |
| 247 | (u32)sta_ht_inf->ampdu_density << STA_FLG_AGG_MPDU_DENSITY_POS); | 235 | (u32)sta_ht_inf->ampdu_density << STA_FLG_AGG_MPDU_DENSITY_POS); |
| 248 | 236 | ||
| 249 | if (iwl_is_ht40_tx_allowed(priv, ctx, &sta->ht_cap)) | 237 | if (iwl_is_ht40_tx_allowed(priv, ctx, sta)) |
| 250 | *flags |= STA_FLG_HT40_EN_MSK; | 238 | *flags |= STA_FLG_HT40_EN_MSK; |
| 251 | } | 239 | } |
| 252 | 240 | ||
diff --git a/drivers/net/wireless/iwlwifi/mvm/rs.c b/drivers/net/wireless/iwlwifi/mvm/rs.c index 60a4291ca221..56b636d9ab30 100644 --- a/drivers/net/wireless/iwlwifi/mvm/rs.c +++ b/drivers/net/wireless/iwlwifi/mvm/rs.c | |||
| @@ -1209,23 +1209,9 @@ static s32 rs_get_best_rate(struct iwl_mvm *mvm, | |||
| 1209 | return new_rate; | 1209 | return new_rate; |
| 1210 | } | 1210 | } |
| 1211 | 1211 | ||
| 1212 | static bool iwl_is_ht40_tx_allowed(struct iwl_mvm *mvm, | 1212 | static bool iwl_is_ht40_tx_allowed(struct ieee80211_sta *sta) |
| 1213 | struct ieee80211_sta_ht_cap *ht_cap) | ||
| 1214 | { | 1213 | { |
| 1215 | /* | 1214 | return sta->bandwidth >= IEEE80211_STA_RX_BW_40; |
| 1216 | * Remainder of this function checks ht_cap, but if it's | ||
| 1217 | * NULL then we can do HT40 (special case for RXON) | ||
| 1218 | */ | ||
| 1219 | if (!ht_cap) | ||
| 1220 | return true; | ||
| 1221 | |||
| 1222 | if (!ht_cap->ht_supported) | ||
| 1223 | return false; | ||
| 1224 | |||
| 1225 | if (!(ht_cap->cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40)) | ||
| 1226 | return false; | ||
| 1227 | |||
| 1228 | return true; | ||
| 1229 | } | 1215 | } |
| 1230 | 1216 | ||
| 1231 | /* | 1217 | /* |
| @@ -1243,8 +1229,7 @@ static int rs_switch_to_mimo2(struct iwl_mvm *mvm, | |||
| 1243 | if (!sta->ht_cap.ht_supported) | 1229 | if (!sta->ht_cap.ht_supported) |
| 1244 | return -1; | 1230 | return -1; |
| 1245 | 1231 | ||
| 1246 | if (((sta->ht_cap.cap & IEEE80211_HT_CAP_SM_PS) >> 2) | 1232 | if (sta->smps_mode == IEEE80211_SMPS_STATIC) |
| 1247 | == WLAN_HT_CAP_SM_PS_STATIC) | ||
| 1248 | return -1; | 1233 | return -1; |
| 1249 | 1234 | ||
| 1250 | /* Need both Tx chains/antennas to support MIMO */ | 1235 | /* Need both Tx chains/antennas to support MIMO */ |
| @@ -1258,7 +1243,7 @@ static int rs_switch_to_mimo2(struct iwl_mvm *mvm, | |||
| 1258 | tbl->max_search = IWL_MAX_SEARCH; | 1243 | tbl->max_search = IWL_MAX_SEARCH; |
| 1259 | rate_mask = lq_sta->active_mimo2_rate; | 1244 | rate_mask = lq_sta->active_mimo2_rate; |
| 1260 | 1245 | ||
| 1261 | if (iwl_is_ht40_tx_allowed(mvm, &sta->ht_cap)) | 1246 | if (iwl_is_ht40_tx_allowed(sta)) |
| 1262 | tbl->is_ht40 = 1; | 1247 | tbl->is_ht40 = 1; |
| 1263 | else | 1248 | else |
| 1264 | tbl->is_ht40 = 0; | 1249 | tbl->is_ht40 = 0; |
| @@ -1296,8 +1281,7 @@ static int rs_switch_to_mimo3(struct iwl_mvm *mvm, | |||
| 1296 | if (!sta->ht_cap.ht_supported) | 1281 | if (!sta->ht_cap.ht_supported) |
| 1297 | return -1; | 1282 | return -1; |
| 1298 | 1283 | ||
| 1299 | if (((sta->ht_cap.cap & IEEE80211_HT_CAP_SM_PS) >> 2) | 1284 | if (sta->smps_mode == IEEE80211_SMPS_STATIC) |
| 1300 | == WLAN_HT_CAP_SM_PS_STATIC) | ||
| 1301 | return -1; | 1285 | return -1; |
| 1302 | 1286 | ||
| 1303 | /* Need both Tx chains/antennas to support MIMO */ | 1287 | /* Need both Tx chains/antennas to support MIMO */ |
| @@ -1311,7 +1295,7 @@ static int rs_switch_to_mimo3(struct iwl_mvm *mvm, | |||
| 1311 | tbl->max_search = IWL_MAX_11N_MIMO3_SEARCH; | 1295 | tbl->max_search = IWL_MAX_11N_MIMO3_SEARCH; |
| 1312 | rate_mask = lq_sta->active_mimo3_rate; | 1296 | rate_mask = lq_sta->active_mimo3_rate; |
| 1313 | 1297 | ||
| 1314 | if (iwl_is_ht40_tx_allowed(mvm, &sta->ht_cap)) | 1298 | if (iwl_is_ht40_tx_allowed(sta)) |
| 1315 | tbl->is_ht40 = 1; | 1299 | tbl->is_ht40 = 1; |
| 1316 | else | 1300 | else |
| 1317 | tbl->is_ht40 = 0; | 1301 | tbl->is_ht40 = 0; |
| @@ -1356,7 +1340,7 @@ static int rs_switch_to_siso(struct iwl_mvm *mvm, | |||
| 1356 | tbl->max_search = IWL_MAX_SEARCH; | 1340 | tbl->max_search = IWL_MAX_SEARCH; |
| 1357 | rate_mask = lq_sta->active_siso_rate; | 1341 | rate_mask = lq_sta->active_siso_rate; |
| 1358 | 1342 | ||
| 1359 | if (iwl_is_ht40_tx_allowed(mvm, &sta->ht_cap)) | 1343 | if (iwl_is_ht40_tx_allowed(sta)) |
| 1360 | tbl->is_ht40 = 1; | 1344 | tbl->is_ht40 = 1; |
| 1361 | else | 1345 | else |
| 1362 | tbl->is_ht40 = 0; | 1346 | tbl->is_ht40 = 0; |
diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index b73e497fe770..cffdf4fbf161 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c | |||
| @@ -2247,6 +2247,7 @@ static int __init init_mac80211_hwsim(void) | |||
| 2247 | /* ask mac80211 to reserve space for magic */ | 2247 | /* ask mac80211 to reserve space for magic */ |
| 2248 | hw->vif_data_size = sizeof(struct hwsim_vif_priv); | 2248 | hw->vif_data_size = sizeof(struct hwsim_vif_priv); |
| 2249 | hw->sta_data_size = sizeof(struct hwsim_sta_priv); | 2249 | hw->sta_data_size = sizeof(struct hwsim_sta_priv); |
| 2250 | hw->chanctx_data_size = sizeof(struct hwsim_chanctx_priv); | ||
| 2250 | 2251 | ||
| 2251 | memcpy(data->channels_2ghz, hwsim_channels_2ghz, | 2252 | memcpy(data->channels_2ghz, hwsim_channels_2ghz, |
| 2252 | sizeof(hwsim_channels_2ghz)); | 2253 | sizeof(hwsim_channels_2ghz)); |
diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.c b/drivers/net/wireless/rt2x00/rt2x00queue.c index e26ec9d817cf..4d91795dc6a2 100644 --- a/drivers/net/wireless/rt2x00/rt2x00queue.c +++ b/drivers/net/wireless/rt2x00/rt2x00queue.c | |||
| @@ -354,10 +354,7 @@ static void rt2x00queue_create_tx_descriptor_ht(struct rt2x00_dev *rt2x00dev, | |||
| 354 | * when using more then one tx stream (>MCS7). | 354 | * when using more then one tx stream (>MCS7). |
| 355 | */ | 355 | */ |
| 356 | if (sta && txdesc->u.ht.mcs > 7 && | 356 | if (sta && txdesc->u.ht.mcs > 7 && |
| 357 | ((sta->ht_cap.cap & | 357 | sta->smps_mode == IEEE80211_SMPS_DYNAMIC) |
| 358 | IEEE80211_HT_CAP_SM_PS) >> | ||
| 359 | IEEE80211_HT_CAP_SM_PS_SHIFT) == | ||
| 360 | WLAN_HT_CAP_SM_PS_DYNAMIC) | ||
| 361 | __set_bit(ENTRY_TXD_HT_MIMO_PS, &txdesc->flags); | 358 | __set_bit(ENTRY_TXD_HT_MIMO_PS, &txdesc->flags); |
| 362 | } else { | 359 | } else { |
| 363 | txdesc->u.ht.mcs = rt2x00_get_rate_mcs(hwrate->mcs); | 360 | txdesc->u.ht.mcs = rt2x00_get_rate_mcs(hwrate->mcs); |
diff --git a/drivers/net/wireless/rtlwifi/base.c b/drivers/net/wireless/rtlwifi/base.c index 0f8b05185eda..99c5cea3fe21 100644 --- a/drivers/net/wireless/rtlwifi/base.c +++ b/drivers/net/wireless/rtlwifi/base.c | |||
| @@ -523,8 +523,8 @@ static void _rtl_query_shortgi(struct ieee80211_hw *hw, | |||
| 523 | if (mac->opmode == NL80211_IFTYPE_STATION) | 523 | if (mac->opmode == NL80211_IFTYPE_STATION) |
| 524 | bw_40 = mac->bw_40; | 524 | bw_40 = mac->bw_40; |
| 525 | else if (mac->opmode == NL80211_IFTYPE_AP || | 525 | else if (mac->opmode == NL80211_IFTYPE_AP || |
| 526 | mac->opmode == NL80211_IFTYPE_ADHOC) | 526 | mac->opmode == NL80211_IFTYPE_ADHOC) |
| 527 | bw_40 = sta->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40; | 527 | bw_40 = sta->bandwidth >= IEEE80211_STA_RX_BW_40; |
| 528 | 528 | ||
| 529 | if (bw_40 && sgi_40) | 529 | if (bw_40 && sgi_40) |
| 530 | tcb_desc->use_shortgi = true; | 530 | tcb_desc->use_shortgi = true; |
| @@ -634,8 +634,7 @@ static void _rtl_query_bandwidth_mode(struct ieee80211_hw *hw, | |||
| 634 | return; | 634 | return; |
| 635 | if (mac->opmode == NL80211_IFTYPE_AP || | 635 | if (mac->opmode == NL80211_IFTYPE_AP || |
| 636 | mac->opmode == NL80211_IFTYPE_ADHOC) { | 636 | mac->opmode == NL80211_IFTYPE_ADHOC) { |
| 637 | if (!(sta->ht_cap.ht_supported) || | 637 | if (sta->bandwidth == IEEE80211_STA_RX_BW_20) |
| 638 | !(sta->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40)) | ||
| 639 | return; | 638 | return; |
| 640 | } else if (mac->opmode == NL80211_IFTYPE_STATION) { | 639 | } else if (mac->opmode == NL80211_IFTYPE_STATION) { |
| 641 | if (!mac->bw_40 || !(sta->ht_cap.ht_supported)) | 640 | if (!mac->bw_40 || !(sta->ht_cap.ht_supported)) |
diff --git a/drivers/net/wireless/rtlwifi/rc.c b/drivers/net/wireless/rtlwifi/rc.c index 6ad8bb758961..f9f059dadb73 100644 --- a/drivers/net/wireless/rtlwifi/rc.c +++ b/drivers/net/wireless/rtlwifi/rc.c | |||
| @@ -116,9 +116,8 @@ static void _rtl_rc_rate_set_series(struct rtl_priv *rtlpriv, | |||
| 116 | if (txrc->short_preamble) | 116 | if (txrc->short_preamble) |
| 117 | rate->flags |= IEEE80211_TX_RC_USE_SHORT_PREAMBLE; | 117 | rate->flags |= IEEE80211_TX_RC_USE_SHORT_PREAMBLE; |
| 118 | if (mac->opmode == NL80211_IFTYPE_AP || | 118 | if (mac->opmode == NL80211_IFTYPE_AP || |
| 119 | mac->opmode == NL80211_IFTYPE_ADHOC) { | 119 | mac->opmode == NL80211_IFTYPE_ADHOC) { |
| 120 | if (sta && (sta->ht_cap.cap & | 120 | if (sta && (sta->bandwidth >= IEEE80211_STA_RX_BW_40)) |
| 121 | IEEE80211_HT_CAP_SUP_WIDTH_20_40)) | ||
| 122 | rate->flags |= IEEE80211_TX_RC_40_MHZ_WIDTH; | 121 | rate->flags |= IEEE80211_TX_RC_40_MHZ_WIDTH; |
| 123 | } else { | 122 | } else { |
| 124 | if (mac->bw_40) | 123 | if (mac->bw_40) |
diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/hw.c b/drivers/net/wireless/rtlwifi/rtl8192ce/hw.c index d1f34f6ffbdf..1b65db7fd651 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192ce/hw.c +++ b/drivers/net/wireless/rtlwifi/rtl8192ce/hw.c | |||
| @@ -1846,9 +1846,9 @@ static void rtl92ce_update_hal_rate_mask(struct ieee80211_hw *hw, | |||
| 1846 | struct rtl_sta_info *sta_entry = NULL; | 1846 | struct rtl_sta_info *sta_entry = NULL; |
| 1847 | u32 ratr_bitmap; | 1847 | u32 ratr_bitmap; |
| 1848 | u8 ratr_index; | 1848 | u8 ratr_index; |
| 1849 | u8 curtxbw_40mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) | 1849 | u8 curtxbw_40mhz = (sta->bandwidth >= IEEE80211_STA_RX_BW_40) ? 1 : 0; |
| 1850 | ? 1 : 0; | 1850 | u8 curshortgi_40mhz = curtxbw_40mhz && |
| 1851 | u8 curshortgi_40mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40) ? | 1851 | (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40) ? |
| 1852 | 1 : 0; | 1852 | 1 : 0; |
| 1853 | u8 curshortgi_20mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20) ? | 1853 | u8 curshortgi_20mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20) ? |
| 1854 | 1 : 0; | 1854 | 1 : 0; |
diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/trx.c b/drivers/net/wireless/rtlwifi/rtl8192ce/trx.c index da0e9022a99a..b9b1a6e0b16e 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192ce/trx.c +++ b/drivers/net/wireless/rtlwifi/rtl8192ce/trx.c | |||
| @@ -626,8 +626,7 @@ void rtl92ce_tx_fill_desc(struct ieee80211_hw *hw, | |||
| 626 | } else if (mac->opmode == NL80211_IFTYPE_AP || | 626 | } else if (mac->opmode == NL80211_IFTYPE_AP || |
| 627 | mac->opmode == NL80211_IFTYPE_ADHOC) { | 627 | mac->opmode == NL80211_IFTYPE_ADHOC) { |
| 628 | if (sta) | 628 | if (sta) |
| 629 | bw_40 = sta->ht_cap.cap & | 629 | bw_40 = sta->bandwidth >= IEEE80211_STA_RX_BW_40; |
| 630 | IEEE80211_HT_CAP_SUP_WIDTH_20_40; | ||
| 631 | } | 630 | } |
| 632 | 631 | ||
| 633 | seq_number = (le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_SEQ) >> 4; | 632 | seq_number = (le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_SEQ) >> 4; |
diff --git a/drivers/net/wireless/rtlwifi/rtl8192de/hw.c b/drivers/net/wireless/rtlwifi/rtl8192de/hw.c index f4051f4f0390..aa5b42521bb4 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192de/hw.c +++ b/drivers/net/wireless/rtlwifi/rtl8192de/hw.c | |||
| @@ -1970,8 +1970,7 @@ static void rtl92de_update_hal_rate_mask(struct ieee80211_hw *hw, | |||
| 1970 | struct rtl_sta_info *sta_entry = NULL; | 1970 | struct rtl_sta_info *sta_entry = NULL; |
| 1971 | u32 ratr_bitmap; | 1971 | u32 ratr_bitmap; |
| 1972 | u8 ratr_index; | 1972 | u8 ratr_index; |
| 1973 | u8 curtxbw_40mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) | 1973 | u8 curtxbw_40mhz = (sta->bandwidth >= IEEE80211_STA_RX_BW_40) ? 1 : 0; |
| 1974 | ? 1 : 0; | ||
| 1975 | u8 curshortgi_40mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40) ? | 1974 | u8 curshortgi_40mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40) ? |
| 1976 | 1 : 0; | 1975 | 1 : 0; |
| 1977 | u8 curshortgi_20mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20) ? | 1976 | u8 curshortgi_20mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20) ? |
diff --git a/drivers/net/wireless/rtlwifi/rtl8192de/trx.c b/drivers/net/wireless/rtlwifi/rtl8192de/trx.c index cdb570ffb4b5..941080e03c06 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192de/trx.c +++ b/drivers/net/wireless/rtlwifi/rtl8192de/trx.c | |||
| @@ -574,8 +574,7 @@ void rtl92de_tx_fill_desc(struct ieee80211_hw *hw, | |||
| 574 | } else if (mac->opmode == NL80211_IFTYPE_AP || | 574 | } else if (mac->opmode == NL80211_IFTYPE_AP || |
| 575 | mac->opmode == NL80211_IFTYPE_ADHOC) { | 575 | mac->opmode == NL80211_IFTYPE_ADHOC) { |
| 576 | if (sta) | 576 | if (sta) |
| 577 | bw_40 = sta->ht_cap.cap & | 577 | bw_40 = sta->bandwidth >= IEEE80211_STA_RX_BW_40; |
| 578 | IEEE80211_HT_CAP_SUP_WIDTH_20_40; | ||
| 579 | } | 578 | } |
| 580 | seq_number = (le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_SEQ) >> 4; | 579 | seq_number = (le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_SEQ) >> 4; |
| 581 | rtl_get_tcb_desc(hw, info, sta, skb, ptcb_desc); | 580 | rtl_get_tcb_desc(hw, info, sta, skb, ptcb_desc); |
diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/hw.c b/drivers/net/wireless/rtlwifi/rtl8192se/hw.c index 28526a7361f5..084e7773bce2 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192se/hw.c +++ b/drivers/net/wireless/rtlwifi/rtl8192se/hw.c | |||
| @@ -2085,8 +2085,7 @@ static void rtl92se_update_hal_rate_mask(struct ieee80211_hw *hw, | |||
| 2085 | struct rtl_sta_info *sta_entry = NULL; | 2085 | struct rtl_sta_info *sta_entry = NULL; |
| 2086 | u32 ratr_bitmap; | 2086 | u32 ratr_bitmap; |
| 2087 | u8 ratr_index = 0; | 2087 | u8 ratr_index = 0; |
| 2088 | u8 curtxbw_40mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) | 2088 | u8 curtxbw_40mhz = (sta->bandwidth >= IEEE80211_STA_RX_BW_40) ? 1 : 0; |
| 2089 | ? 1 : 0; | ||
| 2090 | u8 curshortgi_40mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40) ? | 2089 | u8 curshortgi_40mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40) ? |
| 2091 | 1 : 0; | 2090 | 1 : 0; |
| 2092 | u8 curshortgi_20mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20) ? | 2091 | u8 curshortgi_20mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20) ? |
diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/trx.c b/drivers/net/wireless/rtlwifi/rtl8192se/trx.c index f8431a3c2c9d..7b0a2e75b8b8 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192se/trx.c +++ b/drivers/net/wireless/rtlwifi/rtl8192se/trx.c | |||
| @@ -621,8 +621,7 @@ void rtl92se_tx_fill_desc(struct ieee80211_hw *hw, | |||
| 621 | } else if (mac->opmode == NL80211_IFTYPE_AP || | 621 | } else if (mac->opmode == NL80211_IFTYPE_AP || |
| 622 | mac->opmode == NL80211_IFTYPE_ADHOC) { | 622 | mac->opmode == NL80211_IFTYPE_ADHOC) { |
| 623 | if (sta) | 623 | if (sta) |
| 624 | bw_40 = sta->ht_cap.cap & | 624 | bw_40 = sta->bandwidth >= IEEE80211_STA_RX_BW_40; |
| 625 | IEEE80211_HT_CAP_SUP_WIDTH_20_40; | ||
| 626 | } | 625 | } |
| 627 | 626 | ||
| 628 | seq_number = (le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_SEQ) >> 4; | 627 | seq_number = (le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_SEQ) >> 4; |
diff --git a/drivers/net/wireless/rtlwifi/rtl8723ae/hw.c b/drivers/net/wireless/rtlwifi/rtl8723ae/hw.c index 149804816ac4..9a0c71c2e15e 100644 --- a/drivers/net/wireless/rtlwifi/rtl8723ae/hw.c +++ b/drivers/net/wireless/rtlwifi/rtl8723ae/hw.c | |||
| @@ -1866,8 +1866,7 @@ static void rtl8723ae_update_hal_rate_mask(struct ieee80211_hw *hw, | |||
| 1866 | struct rtl_sta_info *sta_entry = NULL; | 1866 | struct rtl_sta_info *sta_entry = NULL; |
| 1867 | u32 ratr_bitmap; | 1867 | u32 ratr_bitmap; |
| 1868 | u8 ratr_index; | 1868 | u8 ratr_index; |
| 1869 | u8 curtxbw_40mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) | 1869 | u8 curtxbw_40mhz = (sta->bandwidth >= IEEE80211_STA_RX_BW_40) ? 1 : 0; |
| 1870 | ? 1 : 0; | ||
| 1871 | u8 curshortgi_40mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40) ? | 1870 | u8 curshortgi_40mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40) ? |
| 1872 | 1 : 0; | 1871 | 1 : 0; |
| 1873 | u8 curshortgi_20mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20) ? | 1872 | u8 curshortgi_20mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20) ? |
diff --git a/drivers/net/wireless/rtlwifi/rtl8723ae/trx.c b/drivers/net/wireless/rtlwifi/rtl8723ae/trx.c index b1fd2b328abf..ac081297db50 100644 --- a/drivers/net/wireless/rtlwifi/rtl8723ae/trx.c +++ b/drivers/net/wireless/rtlwifi/rtl8723ae/trx.c | |||
| @@ -395,8 +395,7 @@ void rtl8723ae_tx_fill_desc(struct ieee80211_hw *hw, | |||
| 395 | } else if (mac->opmode == NL80211_IFTYPE_AP || | 395 | } else if (mac->opmode == NL80211_IFTYPE_AP || |
| 396 | mac->opmode == NL80211_IFTYPE_ADHOC) { | 396 | mac->opmode == NL80211_IFTYPE_ADHOC) { |
| 397 | if (sta) | 397 | if (sta) |
| 398 | bw_40 = sta->ht_cap.cap & | 398 | bw_40 = sta->bandwidth >= IEEE80211_STA_RX_BW_40; |
| 399 | IEEE80211_HT_CAP_SUP_WIDTH_20_40; | ||
| 400 | } | 399 | } |
| 401 | 400 | ||
| 402 | seq_number = (le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_SEQ) >> 4; | 401 | seq_number = (le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_SEQ) >> 4; |
diff --git a/drivers/net/wireless/ti/wl18xx/main.c b/drivers/net/wireless/ti/wl18xx/main.c index a10b7a7a215a..da3ef1b10a9c 100644 --- a/drivers/net/wireless/ti/wl18xx/main.c +++ b/drivers/net/wireless/ti/wl18xx/main.c | |||
| @@ -1374,7 +1374,7 @@ static void wl18xx_sta_rc_update(struct wl1271 *wl, | |||
| 1374 | struct ieee80211_sta *sta, | 1374 | struct ieee80211_sta *sta, |
| 1375 | u32 changed) | 1375 | u32 changed) |
| 1376 | { | 1376 | { |
| 1377 | bool wide = sta->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40; | 1377 | bool wide = sta->bandwidth >= IEEE80211_STA_RX_BW_40; |
| 1378 | 1378 | ||
| 1379 | wl1271_debug(DEBUG_MAC80211, "mac80211 sta_rc_update wide %d", wide); | 1379 | wl1271_debug(DEBUG_MAC80211, "mac80211 sta_rc_update wide %d", wide); |
| 1380 | 1380 | ||
diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h index 7e8a498efe6d..7e24fe0cfbcd 100644 --- a/include/linux/ieee80211.h +++ b/include/linux/ieee80211.h | |||
| @@ -714,6 +714,30 @@ enum ieee80211_ht_chanwidth_values { | |||
| 714 | IEEE80211_HT_CHANWIDTH_ANY = 1, | 714 | IEEE80211_HT_CHANWIDTH_ANY = 1, |
| 715 | }; | 715 | }; |
| 716 | 716 | ||
| 717 | /** | ||
| 718 | * enum ieee80211_opmode_bits - VHT operating mode field bits | ||
| 719 | * @IEEE80211_OPMODE_NOTIF_CHANWIDTH_MASK: channel width mask | ||
| 720 | * @IEEE80211_OPMODE_NOTIF_CHANWIDTH_20MHZ: 20 MHz channel width | ||
| 721 | * @IEEE80211_OPMODE_NOTIF_CHANWIDTH_40MHZ: 40 MHz channel width | ||
| 722 | * @IEEE80211_OPMODE_NOTIF_CHANWIDTH_80MHZ: 80 MHz channel width | ||
| 723 | * @IEEE80211_OPMODE_NOTIF_CHANWIDTH_160MHZ: 160 MHz or 80+80 MHz channel width | ||
| 724 | * @IEEE80211_OPMODE_NOTIF_RX_NSS_MASK: number of spatial streams mask | ||
| 725 | * (the NSS value is the value of this field + 1) | ||
| 726 | * @IEEE80211_OPMODE_NOTIF_RX_NSS_SHIFT: number of spatial streams shift | ||
| 727 | * @IEEE80211_OPMODE_NOTIF_RX_NSS_TYPE_BF: indicates streams in SU-MIMO PPDU | ||
| 728 | * using a beamforming steering matrix | ||
| 729 | */ | ||
| 730 | enum ieee80211_vht_opmode_bits { | ||
| 731 | IEEE80211_OPMODE_NOTIF_CHANWIDTH_MASK = 3, | ||
| 732 | IEEE80211_OPMODE_NOTIF_CHANWIDTH_20MHZ = 0, | ||
| 733 | IEEE80211_OPMODE_NOTIF_CHANWIDTH_40MHZ = 1, | ||
| 734 | IEEE80211_OPMODE_NOTIF_CHANWIDTH_80MHZ = 2, | ||
| 735 | IEEE80211_OPMODE_NOTIF_CHANWIDTH_160MHZ = 3, | ||
| 736 | IEEE80211_OPMODE_NOTIF_RX_NSS_MASK = 0x70, | ||
| 737 | IEEE80211_OPMODE_NOTIF_RX_NSS_SHIFT = 4, | ||
| 738 | IEEE80211_OPMODE_NOTIF_RX_NSS_TYPE_BF = 0x80, | ||
| 739 | }; | ||
| 740 | |||
| 717 | #define WLAN_SA_QUERY_TR_ID_LEN 2 | 741 | #define WLAN_SA_QUERY_TR_ID_LEN 2 |
| 718 | 742 | ||
| 719 | struct ieee80211_mgmt { | 743 | struct ieee80211_mgmt { |
| @@ -844,6 +868,10 @@ struct ieee80211_mgmt { | |||
| 844 | __le16 capability; | 868 | __le16 capability; |
| 845 | u8 variable[0]; | 869 | u8 variable[0]; |
| 846 | } __packed tdls_discover_resp; | 870 | } __packed tdls_discover_resp; |
| 871 | struct { | ||
| 872 | u8 action_code; | ||
| 873 | u8 operating_mode; | ||
| 874 | } __packed vht_opmode_notif; | ||
| 847 | } u; | 875 | } u; |
| 848 | } __packed action; | 876 | } __packed action; |
| 849 | } u; | 877 | } u; |
| @@ -1273,6 +1301,7 @@ struct ieee80211_vht_operation { | |||
| 1273 | #define IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454 0x00000002 | 1301 | #define IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454 0x00000002 |
| 1274 | #define IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ 0x00000004 | 1302 | #define IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ 0x00000004 |
| 1275 | #define IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ 0x00000008 | 1303 | #define IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ 0x00000008 |
| 1304 | #define IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK 0x0000000C | ||
| 1276 | #define IEEE80211_VHT_CAP_RXLDPC 0x00000010 | 1305 | #define IEEE80211_VHT_CAP_RXLDPC 0x00000010 |
| 1277 | #define IEEE80211_VHT_CAP_SHORT_GI_80 0x00000020 | 1306 | #define IEEE80211_VHT_CAP_SHORT_GI_80 0x00000020 |
| 1278 | #define IEEE80211_VHT_CAP_SHORT_GI_160 0x00000040 | 1307 | #define IEEE80211_VHT_CAP_SHORT_GI_160 0x00000040 |
| @@ -1598,6 +1627,7 @@ enum ieee80211_eid { | |||
| 1598 | 1627 | ||
| 1599 | WLAN_EID_VHT_CAPABILITY = 191, | 1628 | WLAN_EID_VHT_CAPABILITY = 191, |
| 1600 | WLAN_EID_VHT_OPERATION = 192, | 1629 | WLAN_EID_VHT_OPERATION = 192, |
| 1630 | WLAN_EID_OPMODE_NOTIF = 199, | ||
| 1601 | 1631 | ||
| 1602 | /* 802.11ad */ | 1632 | /* 802.11ad */ |
| 1603 | WLAN_EID_NON_TX_BSSID_CAP = 83, | 1633 | WLAN_EID_NON_TX_BSSID_CAP = 83, |
| @@ -1652,6 +1682,7 @@ enum ieee80211_category { | |||
| 1652 | WLAN_CATEGORY_WMM = 17, | 1682 | WLAN_CATEGORY_WMM = 17, |
| 1653 | WLAN_CATEGORY_FST = 18, | 1683 | WLAN_CATEGORY_FST = 18, |
| 1654 | WLAN_CATEGORY_UNPROT_DMG = 20, | 1684 | WLAN_CATEGORY_UNPROT_DMG = 20, |
| 1685 | WLAN_CATEGORY_VHT = 21, | ||
| 1655 | WLAN_CATEGORY_VENDOR_SPECIFIC_PROTECTED = 126, | 1686 | WLAN_CATEGORY_VENDOR_SPECIFIC_PROTECTED = 126, |
| 1656 | WLAN_CATEGORY_VENDOR_SPECIFIC = 127, | 1687 | WLAN_CATEGORY_VENDOR_SPECIFIC = 127, |
| 1657 | }; | 1688 | }; |
| @@ -1677,6 +1708,13 @@ enum ieee80211_ht_actioncode { | |||
| 1677 | WLAN_HT_ACTION_ASEL_IDX_FEEDBACK = 7, | 1708 | WLAN_HT_ACTION_ASEL_IDX_FEEDBACK = 7, |
| 1678 | }; | 1709 | }; |
| 1679 | 1710 | ||
| 1711 | /* VHT action codes */ | ||
| 1712 | enum ieee80211_vht_actioncode { | ||
| 1713 | WLAN_VHT_ACTION_COMPRESSED_BF = 0, | ||
| 1714 | WLAN_VHT_ACTION_GROUPID_MGMT = 1, | ||
| 1715 | WLAN_VHT_ACTION_OPMODE_NOTIF = 2, | ||
| 1716 | }; | ||
| 1717 | |||
| 1680 | /* Self Protected Action codes */ | 1718 | /* Self Protected Action codes */ |
| 1681 | enum ieee80211_self_protected_actioncode { | 1719 | enum ieee80211_self_protected_actioncode { |
| 1682 | WLAN_SP_RESERVED = 0, | 1720 | WLAN_SP_RESERVED = 0, |
| @@ -1738,6 +1776,8 @@ enum ieee80211_tdls_actioncode { | |||
| 1738 | #define WLAN_EXT_CAPA5_TDLS_ENABLED BIT(5) | 1776 | #define WLAN_EXT_CAPA5_TDLS_ENABLED BIT(5) |
| 1739 | #define WLAN_EXT_CAPA5_TDLS_PROHIBITED BIT(6) | 1777 | #define WLAN_EXT_CAPA5_TDLS_PROHIBITED BIT(6) |
| 1740 | 1778 | ||
| 1779 | #define WLAN_EXT_CAPA8_OPMODE_NOTIF BIT(6) | ||
| 1780 | |||
| 1741 | /* TDLS specific payload type in the LLC/SNAP header */ | 1781 | /* TDLS specific payload type in the LLC/SNAP header */ |
| 1742 | #define WLAN_TDLS_SNAP_RFTYPE 0x2 | 1782 | #define WLAN_TDLS_SNAP_RFTYPE 0x2 |
| 1743 | 1783 | ||
| @@ -2114,7 +2154,7 @@ static inline unsigned long ieee80211_tu_to_usec(unsigned long tu) | |||
| 2114 | * @tim_len: length of the TIM IE | 2154 | * @tim_len: length of the TIM IE |
| 2115 | * @aid: the AID to look for | 2155 | * @aid: the AID to look for |
| 2116 | */ | 2156 | */ |
| 2117 | static inline bool ieee80211_check_tim(struct ieee80211_tim_ie *tim, | 2157 | static inline bool ieee80211_check_tim(const struct ieee80211_tim_ie *tim, |
| 2118 | u8 tim_len, u16 aid) | 2158 | u8 tim_len, u16 aid) |
| 2119 | { | 2159 | { |
| 2120 | u8 mask; | 2160 | u8 mask; |
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 77686ca28948..fa2612952c19 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h | |||
| @@ -19,6 +19,7 @@ | |||
| 19 | #include <linux/nl80211.h> | 19 | #include <linux/nl80211.h> |
| 20 | #include <linux/if_ether.h> | 20 | #include <linux/if_ether.h> |
| 21 | #include <linux/ieee80211.h> | 21 | #include <linux/ieee80211.h> |
| 22 | #include <linux/net.h> | ||
| 22 | #include <net/regulatory.h> | 23 | #include <net/regulatory.h> |
| 23 | 24 | ||
| 24 | /** | 25 | /** |
| @@ -99,6 +100,16 @@ enum ieee80211_band { | |||
| 99 | * @IEEE80211_CHAN_NO_HT40MINUS: extension channel below this channel | 100 | * @IEEE80211_CHAN_NO_HT40MINUS: extension channel below this channel |
| 100 | * is not permitted. | 101 | * is not permitted. |
| 101 | * @IEEE80211_CHAN_NO_OFDM: OFDM is not allowed on this channel. | 102 | * @IEEE80211_CHAN_NO_OFDM: OFDM is not allowed on this channel. |
| 103 | * @IEEE80211_CHAN_NO_80MHZ: If the driver supports 80 MHz on the band, | ||
| 104 | * this flag indicates that an 80 MHz channel cannot use this | ||
| 105 | * channel as the control or any of the secondary channels. | ||
| 106 | * This may be due to the driver or due to regulatory bandwidth | ||
| 107 | * restrictions. | ||
| 108 | * @IEEE80211_CHAN_NO_160MHZ: If the driver supports 160 MHz on the band, | ||
| 109 | * this flag indicates that an 160 MHz channel cannot use this | ||
| 110 | * channel as the control or any of the secondary channels. | ||
| 111 | * This may be due to the driver or due to regulatory bandwidth | ||
| 112 | * restrictions. | ||
| 102 | */ | 113 | */ |
| 103 | enum ieee80211_channel_flags { | 114 | enum ieee80211_channel_flags { |
| 104 | IEEE80211_CHAN_DISABLED = 1<<0, | 115 | IEEE80211_CHAN_DISABLED = 1<<0, |
| @@ -108,11 +119,16 @@ enum ieee80211_channel_flags { | |||
| 108 | IEEE80211_CHAN_NO_HT40PLUS = 1<<4, | 119 | IEEE80211_CHAN_NO_HT40PLUS = 1<<4, |
| 109 | IEEE80211_CHAN_NO_HT40MINUS = 1<<5, | 120 | IEEE80211_CHAN_NO_HT40MINUS = 1<<5, |
| 110 | IEEE80211_CHAN_NO_OFDM = 1<<6, | 121 | IEEE80211_CHAN_NO_OFDM = 1<<6, |
| 122 | IEEE80211_CHAN_NO_80MHZ = 1<<7, | ||
| 123 | IEEE80211_CHAN_NO_160MHZ = 1<<8, | ||
| 111 | }; | 124 | }; |
| 112 | 125 | ||
| 113 | #define IEEE80211_CHAN_NO_HT40 \ | 126 | #define IEEE80211_CHAN_NO_HT40 \ |
| 114 | (IEEE80211_CHAN_NO_HT40PLUS | IEEE80211_CHAN_NO_HT40MINUS) | 127 | (IEEE80211_CHAN_NO_HT40PLUS | IEEE80211_CHAN_NO_HT40MINUS) |
| 115 | 128 | ||
| 129 | #define IEEE80211_DFS_MIN_CAC_TIME_MS 60000 | ||
| 130 | #define IEEE80211_DFS_MIN_NOP_TIME_MS (30 * 60 * 1000) | ||
| 131 | |||
| 116 | /** | 132 | /** |
| 117 | * struct ieee80211_channel - channel definition | 133 | * struct ieee80211_channel - channel definition |
| 118 | * | 134 | * |
| @@ -133,6 +149,9 @@ enum ieee80211_channel_flags { | |||
| 133 | * to enable this, this is useful only on 5 GHz band. | 149 | * to enable this, this is useful only on 5 GHz band. |
| 134 | * @orig_mag: internal use | 150 | * @orig_mag: internal use |
| 135 | * @orig_mpwr: internal use | 151 | * @orig_mpwr: internal use |
| 152 | * @dfs_state: current state of this channel. Only relevant if radar is required | ||
| 153 | * on this channel. | ||
| 154 | * @dfs_state_entered: timestamp (jiffies) when the dfs state was entered. | ||
| 136 | */ | 155 | */ |
| 137 | struct ieee80211_channel { | 156 | struct ieee80211_channel { |
| 138 | enum ieee80211_band band; | 157 | enum ieee80211_band band; |
| @@ -145,6 +164,8 @@ struct ieee80211_channel { | |||
| 145 | bool beacon_found; | 164 | bool beacon_found; |
| 146 | u32 orig_flags; | 165 | u32 orig_flags; |
| 147 | int orig_mag, orig_mpwr; | 166 | int orig_mag, orig_mpwr; |
| 167 | enum nl80211_dfs_state dfs_state; | ||
| 168 | unsigned long dfs_state_entered; | ||
| 148 | }; | 169 | }; |
| 149 | 170 | ||
| 150 | /** | 171 | /** |
| @@ -568,6 +589,7 @@ struct cfg80211_acl_data { | |||
| 568 | * @p2p_opp_ps: P2P opportunistic PS | 589 | * @p2p_opp_ps: P2P opportunistic PS |
| 569 | * @acl: ACL configuration used by the drivers which has support for | 590 | * @acl: ACL configuration used by the drivers which has support for |
| 570 | * MAC address based access control | 591 | * MAC address based access control |
| 592 | * @radar_required: set if radar detection is required | ||
| 571 | */ | 593 | */ |
| 572 | struct cfg80211_ap_settings { | 594 | struct cfg80211_ap_settings { |
| 573 | struct cfg80211_chan_def chandef; | 595 | struct cfg80211_chan_def chandef; |
| @@ -585,6 +607,7 @@ struct cfg80211_ap_settings { | |||
| 585 | u8 p2p_ctwindow; | 607 | u8 p2p_ctwindow; |
| 586 | bool p2p_opp_ps; | 608 | bool p2p_opp_ps; |
| 587 | const struct cfg80211_acl_data *acl; | 609 | const struct cfg80211_acl_data *acl; |
| 610 | bool radar_required; | ||
| 588 | }; | 611 | }; |
| 589 | 612 | ||
| 590 | /** | 613 | /** |
| @@ -603,12 +626,14 @@ enum plink_actions { | |||
| 603 | /** | 626 | /** |
| 604 | * enum station_parameters_apply_mask - station parameter values to apply | 627 | * enum station_parameters_apply_mask - station parameter values to apply |
| 605 | * @STATION_PARAM_APPLY_UAPSD: apply new uAPSD parameters (uapsd_queues, max_sp) | 628 | * @STATION_PARAM_APPLY_UAPSD: apply new uAPSD parameters (uapsd_queues, max_sp) |
| 629 | * @STATION_PARAM_APPLY_CAPABILITY: apply new capability | ||
| 606 | * | 630 | * |
| 607 | * Not all station parameters have in-band "no change" signalling, | 631 | * Not all station parameters have in-band "no change" signalling, |
| 608 | * for those that don't these flags will are used. | 632 | * for those that don't these flags will are used. |
| 609 | */ | 633 | */ |
| 610 | enum station_parameters_apply_mask { | 634 | enum station_parameters_apply_mask { |
| 611 | STATION_PARAM_APPLY_UAPSD = BIT(0), | 635 | STATION_PARAM_APPLY_UAPSD = BIT(0), |
| 636 | STATION_PARAM_APPLY_CAPABILITY = BIT(1), | ||
| 612 | }; | 637 | }; |
| 613 | 638 | ||
| 614 | /** | 639 | /** |
| @@ -639,6 +664,9 @@ enum station_parameters_apply_mask { | |||
| 639 | * see &enum station_parameters_apply_mask | 664 | * see &enum station_parameters_apply_mask |
| 640 | * @local_pm: local link-specific mesh power save mode (no change when set | 665 | * @local_pm: local link-specific mesh power save mode (no change when set |
| 641 | * to unknown) | 666 | * to unknown) |
| 667 | * @capability: station capability | ||
| 668 | * @ext_capab: extended capabilities of the station | ||
| 669 | * @ext_capab_len: number of extended capabilities | ||
| 642 | */ | 670 | */ |
| 643 | struct station_parameters { | 671 | struct station_parameters { |
| 644 | u8 *supported_rates; | 672 | u8 *supported_rates; |
| @@ -655,6 +683,9 @@ struct station_parameters { | |||
| 655 | u8 uapsd_queues; | 683 | u8 uapsd_queues; |
| 656 | u8 max_sp; | 684 | u8 max_sp; |
| 657 | enum nl80211_mesh_power_mode local_pm; | 685 | enum nl80211_mesh_power_mode local_pm; |
| 686 | u16 capability; | ||
| 687 | u8 *ext_capab; | ||
| 688 | u8 ext_capab_len; | ||
| 658 | }; | 689 | }; |
| 659 | 690 | ||
| 660 | /** | 691 | /** |
| @@ -1576,6 +1607,7 @@ struct cfg80211_pmksa { | |||
| 1576 | * one bit per byte, in same format as nl80211 | 1607 | * one bit per byte, in same format as nl80211 |
| 1577 | * @pattern: bytes to match where bitmask is 1 | 1608 | * @pattern: bytes to match where bitmask is 1 |
| 1578 | * @pattern_len: length of pattern (in bytes) | 1609 | * @pattern_len: length of pattern (in bytes) |
| 1610 | * @pkt_offset: packet offset (in bytes) | ||
| 1579 | * | 1611 | * |
| 1580 | * Internal note: @mask and @pattern are allocated in one chunk of | 1612 | * Internal note: @mask and @pattern are allocated in one chunk of |
| 1581 | * memory, free @mask only! | 1613 | * memory, free @mask only! |
| @@ -1583,6 +1615,42 @@ struct cfg80211_pmksa { | |||
| 1583 | struct cfg80211_wowlan_trig_pkt_pattern { | 1615 | struct cfg80211_wowlan_trig_pkt_pattern { |
| 1584 | u8 *mask, *pattern; | 1616 | u8 *mask, *pattern; |
| 1585 | int pattern_len; | 1617 | int pattern_len; |
| 1618 | int pkt_offset; | ||
| 1619 | }; | ||
| 1620 | |||
| 1621 | /** | ||
| 1622 | * struct cfg80211_wowlan_tcp - TCP connection parameters | ||
| 1623 | * | ||
| 1624 | * @sock: (internal) socket for source port allocation | ||
| 1625 | * @src: source IP address | ||
| 1626 | * @dst: destination IP address | ||
| 1627 | * @dst_mac: destination MAC address | ||
| 1628 | * @src_port: source port | ||
| 1629 | * @dst_port: destination port | ||
| 1630 | * @payload_len: data payload length | ||
| 1631 | * @payload: data payload buffer | ||
| 1632 | * @payload_seq: payload sequence stamping configuration | ||
| 1633 | * @data_interval: interval at which to send data packets | ||
| 1634 | * @wake_len: wakeup payload match length | ||
| 1635 | * @wake_data: wakeup payload match data | ||
| 1636 | * @wake_mask: wakeup payload match mask | ||
| 1637 | * @tokens_size: length of the tokens buffer | ||
| 1638 | * @payload_tok: payload token usage configuration | ||
| 1639 | */ | ||
| 1640 | struct cfg80211_wowlan_tcp { | ||
| 1641 | struct socket *sock; | ||
| 1642 | __be32 src, dst; | ||
| 1643 | u16 src_port, dst_port; | ||
| 1644 | u8 dst_mac[ETH_ALEN]; | ||
| 1645 | int payload_len; | ||
| 1646 | const u8 *payload; | ||
| 1647 | struct nl80211_wowlan_tcp_data_seq payload_seq; | ||
| 1648 | u32 data_interval; | ||
| 1649 | u32 wake_len; | ||
| 1650 | const u8 *wake_data, *wake_mask; | ||
| 1651 | u32 tokens_size; | ||
| 1652 | /* must be last, variable member */ | ||
| 1653 | struct nl80211_wowlan_tcp_data_token payload_tok; | ||
| 1586 | }; | 1654 | }; |
| 1587 | 1655 | ||
| 1588 | /** | 1656 | /** |
| @@ -1599,12 +1667,15 @@ struct cfg80211_wowlan_trig_pkt_pattern { | |||
| 1599 | * @eap_identity_req: wake up on EAP identity request packet | 1667 | * @eap_identity_req: wake up on EAP identity request packet |
| 1600 | * @four_way_handshake: wake up on 4-way handshake | 1668 | * @four_way_handshake: wake up on 4-way handshake |
| 1601 | * @rfkill_release: wake up when rfkill is released | 1669 | * @rfkill_release: wake up when rfkill is released |
| 1670 | * @tcp: TCP connection establishment/wakeup parameters, see nl80211.h. | ||
| 1671 | * NULL if not configured. | ||
| 1602 | */ | 1672 | */ |
| 1603 | struct cfg80211_wowlan { | 1673 | struct cfg80211_wowlan { |
| 1604 | bool any, disconnect, magic_pkt, gtk_rekey_failure, | 1674 | bool any, disconnect, magic_pkt, gtk_rekey_failure, |
| 1605 | eap_identity_req, four_way_handshake, | 1675 | eap_identity_req, four_way_handshake, |
| 1606 | rfkill_release; | 1676 | rfkill_release; |
| 1607 | struct cfg80211_wowlan_trig_pkt_pattern *patterns; | 1677 | struct cfg80211_wowlan_trig_pkt_pattern *patterns; |
| 1678 | struct cfg80211_wowlan_tcp *tcp; | ||
| 1608 | int n_patterns; | 1679 | int n_patterns; |
| 1609 | }; | 1680 | }; |
| 1610 | 1681 | ||
| @@ -1624,11 +1695,15 @@ struct cfg80211_wowlan { | |||
| 1624 | * frame triggers an 802.3 frame should be reported, for | 1695 | * frame triggers an 802.3 frame should be reported, for |
| 1625 | * disconnect due to deauth 802.11 frame. This indicates which | 1696 | * disconnect due to deauth 802.11 frame. This indicates which |
| 1626 | * it is. | 1697 | * it is. |
| 1698 | * @tcp_match: TCP wakeup packet received | ||
| 1699 | * @tcp_connlost: TCP connection lost or failed to establish | ||
| 1700 | * @tcp_nomoretokens: TCP data ran out of tokens | ||
| 1627 | */ | 1701 | */ |
| 1628 | struct cfg80211_wowlan_wakeup { | 1702 | struct cfg80211_wowlan_wakeup { |
| 1629 | bool disconnect, magic_pkt, gtk_rekey_failure, | 1703 | bool disconnect, magic_pkt, gtk_rekey_failure, |
| 1630 | eap_identity_req, four_way_handshake, | 1704 | eap_identity_req, four_way_handshake, |
| 1631 | rfkill_release, packet_80211; | 1705 | rfkill_release, packet_80211, |
| 1706 | tcp_match, tcp_connlost, tcp_nomoretokens; | ||
| 1632 | s32 pattern_idx; | 1707 | s32 pattern_idx; |
| 1633 | u32 packet_present_len, packet_len; | 1708 | u32 packet_present_len, packet_len; |
| 1634 | const void *packet; | 1709 | const void *packet; |
| @@ -1864,6 +1939,8 @@ struct cfg80211_gtk_rekey_data { | |||
| 1864 | * this new list replaces the existing one. Driver has to clear its ACL | 1939 | * this new list replaces the existing one. Driver has to clear its ACL |
| 1865 | * when number of MAC addresses entries is passed as 0. Drivers which | 1940 | * when number of MAC addresses entries is passed as 0. Drivers which |
| 1866 | * advertise the support for MAC based ACL have to implement this callback. | 1941 | * advertise the support for MAC based ACL have to implement this callback. |
| 1942 | * | ||
| 1943 | * @start_radar_detection: Start radar detection in the driver. | ||
| 1867 | */ | 1944 | */ |
| 1868 | struct cfg80211_ops { | 1945 | struct cfg80211_ops { |
| 1869 | int (*suspend)(struct wiphy *wiphy, struct cfg80211_wowlan *wow); | 1946 | int (*suspend)(struct wiphy *wiphy, struct cfg80211_wowlan *wow); |
| @@ -2087,6 +2164,10 @@ struct cfg80211_ops { | |||
| 2087 | 2164 | ||
| 2088 | int (*set_mac_acl)(struct wiphy *wiphy, struct net_device *dev, | 2165 | int (*set_mac_acl)(struct wiphy *wiphy, struct net_device *dev, |
| 2089 | const struct cfg80211_acl_data *params); | 2166 | const struct cfg80211_acl_data *params); |
| 2167 | |||
| 2168 | int (*start_radar_detection)(struct wiphy *wiphy, | ||
| 2169 | struct net_device *dev, | ||
| 2170 | struct cfg80211_chan_def *chandef); | ||
| 2090 | }; | 2171 | }; |
| 2091 | 2172 | ||
| 2092 | /* | 2173 | /* |
| @@ -2283,6 +2364,14 @@ enum wiphy_wowlan_support_flags { | |||
| 2283 | WIPHY_WOWLAN_RFKILL_RELEASE = BIT(7), | 2364 | WIPHY_WOWLAN_RFKILL_RELEASE = BIT(7), |
| 2284 | }; | 2365 | }; |
| 2285 | 2366 | ||
| 2367 | struct wiphy_wowlan_tcp_support { | ||
| 2368 | const struct nl80211_wowlan_tcp_data_token_feature *tok; | ||
| 2369 | u32 data_payload_max; | ||
| 2370 | u32 data_interval_max; | ||
| 2371 | u32 wake_payload_max; | ||
| 2372 | bool seq; | ||
| 2373 | }; | ||
| 2374 | |||
| 2286 | /** | 2375 | /** |
| 2287 | * struct wiphy_wowlan_support - WoWLAN support data | 2376 | * struct wiphy_wowlan_support - WoWLAN support data |
| 2288 | * @flags: see &enum wiphy_wowlan_support_flags | 2377 | * @flags: see &enum wiphy_wowlan_support_flags |
| @@ -2290,12 +2379,16 @@ enum wiphy_wowlan_support_flags { | |||
| 2290 | * (see nl80211.h for the pattern definition) | 2379 | * (see nl80211.h for the pattern definition) |
| 2291 | * @pattern_max_len: maximum length of each pattern | 2380 | * @pattern_max_len: maximum length of each pattern |
| 2292 | * @pattern_min_len: minimum length of each pattern | 2381 | * @pattern_min_len: minimum length of each pattern |
| 2382 | * @max_pkt_offset: maximum Rx packet offset | ||
| 2383 | * @tcp: TCP wakeup support information | ||
| 2293 | */ | 2384 | */ |
| 2294 | struct wiphy_wowlan_support { | 2385 | struct wiphy_wowlan_support { |
| 2295 | u32 flags; | 2386 | u32 flags; |
| 2296 | int n_patterns; | 2387 | int n_patterns; |
| 2297 | int pattern_max_len; | 2388 | int pattern_max_len; |
| 2298 | int pattern_min_len; | 2389 | int pattern_min_len; |
| 2390 | int max_pkt_offset; | ||
| 2391 | const struct wiphy_wowlan_tcp_support *tcp; | ||
| 2299 | }; | 2392 | }; |
| 2300 | 2393 | ||
| 2301 | /** | 2394 | /** |
| @@ -2395,6 +2488,14 @@ struct wiphy_wowlan_support { | |||
| 2395 | * | 2488 | * |
| 2396 | * @max_acl_mac_addrs: Maximum number of MAC addresses that the device | 2489 | * @max_acl_mac_addrs: Maximum number of MAC addresses that the device |
| 2397 | * supports for ACL. | 2490 | * supports for ACL. |
| 2491 | * | ||
| 2492 | * @extended_capabilities: extended capabilities supported by the driver, | ||
| 2493 | * additional capabilities might be supported by userspace; these are | ||
| 2494 | * the 802.11 extended capabilities ("Extended Capabilities element") | ||
| 2495 | * and are in the same format as in the information element. See | ||
| 2496 | * 802.11-2012 8.4.2.29 for the defined fields. | ||
| 2497 | * @extended_capabilities_mask: mask of the valid values | ||
| 2498 | * @extended_capabilities_len: length of the extended capabilities | ||
| 2398 | */ | 2499 | */ |
| 2399 | struct wiphy { | 2500 | struct wiphy { |
| 2400 | /* assign these fields before you register the wiphy */ | 2501 | /* assign these fields before you register the wiphy */ |
| @@ -2461,6 +2562,9 @@ struct wiphy { | |||
| 2461 | */ | 2562 | */ |
| 2462 | u32 probe_resp_offload; | 2563 | u32 probe_resp_offload; |
| 2463 | 2564 | ||
| 2565 | const u8 *extended_capabilities, *extended_capabilities_mask; | ||
| 2566 | u8 extended_capabilities_len; | ||
| 2567 | |||
| 2464 | /* If multiple wiphys are registered and you're handed e.g. | 2568 | /* If multiple wiphys are registered and you're handed e.g. |
| 2465 | * a regular netdev with assigned ieee80211_ptr, you won't | 2569 | * a regular netdev with assigned ieee80211_ptr, you won't |
| 2466 | * know whether it points to a wiphy your driver has registered | 2570 | * know whether it points to a wiphy your driver has registered |
| @@ -2658,6 +2762,8 @@ struct cfg80211_cached_keys; | |||
| 2658 | * beacons, 0 when not valid | 2762 | * beacons, 0 when not valid |
| 2659 | * @address: The address for this device, valid only if @netdev is %NULL | 2763 | * @address: The address for this device, valid only if @netdev is %NULL |
| 2660 | * @p2p_started: true if this is a P2P Device that has been started | 2764 | * @p2p_started: true if this is a P2P Device that has been started |
| 2765 | * @cac_started: true if DFS channel availability check has been started | ||
| 2766 | * @cac_start_time: timestamp (jiffies) when the dfs state was entered. | ||
| 2661 | */ | 2767 | */ |
| 2662 | struct wireless_dev { | 2768 | struct wireless_dev { |
| 2663 | struct wiphy *wiphy; | 2769 | struct wiphy *wiphy; |
| @@ -2709,6 +2815,9 @@ struct wireless_dev { | |||
| 2709 | 2815 | ||
| 2710 | u32 ap_unexpected_nlportid; | 2816 | u32 ap_unexpected_nlportid; |
| 2711 | 2817 | ||
| 2818 | bool cac_started; | ||
| 2819 | unsigned long cac_start_time; | ||
| 2820 | |||
| 2712 | #ifdef CONFIG_CFG80211_WEXT | 2821 | #ifdef CONFIG_CFG80211_WEXT |
| 2713 | /* wext data */ | 2822 | /* wext data */ |
| 2714 | struct { | 2823 | struct { |
| @@ -3698,6 +3807,31 @@ void cfg80211_cqm_rssi_notify(struct net_device *dev, | |||
| 3698 | gfp_t gfp); | 3807 | gfp_t gfp); |
| 3699 | 3808 | ||
| 3700 | /** | 3809 | /** |
| 3810 | * cfg80211_radar_event - radar detection event | ||
| 3811 | * @wiphy: the wiphy | ||
| 3812 | * @chandef: chandef for the current channel | ||
| 3813 | * @gfp: context flags | ||
| 3814 | * | ||
| 3815 | * This function is called when a radar is detected on the current chanenl. | ||
| 3816 | */ | ||
| 3817 | void cfg80211_radar_event(struct wiphy *wiphy, | ||
| 3818 | struct cfg80211_chan_def *chandef, gfp_t gfp); | ||
| 3819 | |||
| 3820 | /** | ||
| 3821 | * cfg80211_cac_event - Channel availability check (CAC) event | ||
| 3822 | * @netdev: network device | ||
| 3823 | * @event: type of event | ||
| 3824 | * @gfp: context flags | ||
| 3825 | * | ||
| 3826 | * This function is called when a Channel availability check (CAC) is finished | ||
| 3827 | * or aborted. This must be called to notify the completion of a CAC process, | ||
| 3828 | * also by full-MAC drivers. | ||
| 3829 | */ | ||
| 3830 | void cfg80211_cac_event(struct net_device *netdev, | ||
| 3831 | enum nl80211_radar_event event, gfp_t gfp); | ||
| 3832 | |||
| 3833 | |||
| 3834 | /** | ||
| 3701 | * cfg80211_cqm_pktloss_notify - notify userspace about packetloss to peer | 3835 | * cfg80211_cqm_pktloss_notify - notify userspace about packetloss to peer |
| 3702 | * @dev: network device | 3836 | * @dev: network device |
| 3703 | * @peer: peer's MAC address | 3837 | * @peer: peer's MAC address |
diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 0eaa9092364b..f7eba1300d82 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h | |||
| @@ -147,10 +147,12 @@ struct ieee80211_low_level_stats { | |||
| 147 | * enum ieee80211_chanctx_change - change flag for channel context | 147 | * enum ieee80211_chanctx_change - change flag for channel context |
| 148 | * @IEEE80211_CHANCTX_CHANGE_WIDTH: The channel width changed | 148 | * @IEEE80211_CHANCTX_CHANGE_WIDTH: The channel width changed |
| 149 | * @IEEE80211_CHANCTX_CHANGE_RX_CHAINS: The number of RX chains changed | 149 | * @IEEE80211_CHANCTX_CHANGE_RX_CHAINS: The number of RX chains changed |
| 150 | * @IEEE80211_CHANCTX_CHANGE_RADAR: radar detection flag changed | ||
| 150 | */ | 151 | */ |
| 151 | enum ieee80211_chanctx_change { | 152 | enum ieee80211_chanctx_change { |
| 152 | IEEE80211_CHANCTX_CHANGE_WIDTH = BIT(0), | 153 | IEEE80211_CHANCTX_CHANGE_WIDTH = BIT(0), |
| 153 | IEEE80211_CHANCTX_CHANGE_RX_CHAINS = BIT(1), | 154 | IEEE80211_CHANCTX_CHANGE_RX_CHAINS = BIT(1), |
| 155 | IEEE80211_CHANCTX_CHANGE_RADAR = BIT(2), | ||
| 154 | }; | 156 | }; |
| 155 | 157 | ||
| 156 | /** | 158 | /** |
| @@ -165,6 +167,7 @@ enum ieee80211_chanctx_change { | |||
| 165 | * @rx_chains_dynamic: The number of RX chains that must be enabled | 167 | * @rx_chains_dynamic: The number of RX chains that must be enabled |
| 166 | * after RTS/CTS handshake to receive SMPS MIMO transmissions; | 168 | * after RTS/CTS handshake to receive SMPS MIMO transmissions; |
| 167 | * this will always be >= @rx_chains_static. | 169 | * this will always be >= @rx_chains_static. |
| 170 | * @radar_enabled: whether radar detection is enabled on this channel. | ||
| 168 | * @drv_priv: data area for driver use, will always be aligned to | 171 | * @drv_priv: data area for driver use, will always be aligned to |
| 169 | * sizeof(void *), size is determined in hw information. | 172 | * sizeof(void *), size is determined in hw information. |
| 170 | */ | 173 | */ |
| @@ -173,6 +176,8 @@ struct ieee80211_chanctx_conf { | |||
| 173 | 176 | ||
| 174 | u8 rx_chains_static, rx_chains_dynamic; | 177 | u8 rx_chains_static, rx_chains_dynamic; |
| 175 | 178 | ||
| 179 | bool radar_enabled; | ||
| 180 | |||
| 176 | u8 drv_priv[0] __aligned(sizeof(void *)); | 181 | u8 drv_priv[0] __aligned(sizeof(void *)); |
| 177 | }; | 182 | }; |
| 178 | 183 | ||
| @@ -210,6 +215,9 @@ struct ieee80211_chanctx_conf { | |||
| 210 | * changed (currently only in P2P client mode, GO mode will be later) | 215 | * changed (currently only in P2P client mode, GO mode will be later) |
| 211 | * @BSS_CHANGED_DTIM_PERIOD: the DTIM period value was changed (set when | 216 | * @BSS_CHANGED_DTIM_PERIOD: the DTIM period value was changed (set when |
| 212 | * it becomes valid, managed mode only) | 217 | * it becomes valid, managed mode only) |
| 218 | * @BSS_CHANGED_BANDWIDTH: The bandwidth used by this interface changed, | ||
| 219 | * note that this is only called when it changes after the channel | ||
| 220 | * context had been assigned. | ||
| 213 | */ | 221 | */ |
| 214 | enum ieee80211_bss_change { | 222 | enum ieee80211_bss_change { |
| 215 | BSS_CHANGED_ASSOC = 1<<0, | 223 | BSS_CHANGED_ASSOC = 1<<0, |
| @@ -233,6 +241,7 @@ enum ieee80211_bss_change { | |||
| 233 | BSS_CHANGED_TXPOWER = 1<<18, | 241 | BSS_CHANGED_TXPOWER = 1<<18, |
| 234 | BSS_CHANGED_P2P_PS = 1<<19, | 242 | BSS_CHANGED_P2P_PS = 1<<19, |
| 235 | BSS_CHANGED_DTIM_PERIOD = 1<<20, | 243 | BSS_CHANGED_DTIM_PERIOD = 1<<20, |
| 244 | BSS_CHANGED_BANDWIDTH = 1<<21, | ||
| 236 | 245 | ||
| 237 | /* when adding here, make sure to change ieee80211_reconfig */ | 246 | /* when adding here, make sure to change ieee80211_reconfig */ |
| 238 | }; | 247 | }; |
| @@ -967,6 +976,7 @@ enum ieee80211_smps_mode { | |||
| 967 | * | 976 | * |
| 968 | * @channel: the channel to tune to | 977 | * @channel: the channel to tune to |
| 969 | * @channel_type: the channel (HT) type | 978 | * @channel_type: the channel (HT) type |
| 979 | * @radar_enabled: whether radar detection is enabled | ||
| 970 | * | 980 | * |
| 971 | * @long_frame_max_tx_count: Maximum number of transmissions for a "long" frame | 981 | * @long_frame_max_tx_count: Maximum number of transmissions for a "long" frame |
| 972 | * (a frame not RTS protected), called "dot11LongRetryLimit" in 802.11, | 982 | * (a frame not RTS protected), called "dot11LongRetryLimit" in 802.11, |
| @@ -993,6 +1003,7 @@ struct ieee80211_conf { | |||
| 993 | 1003 | ||
| 994 | struct ieee80211_channel *channel; | 1004 | struct ieee80211_channel *channel; |
| 995 | enum nl80211_channel_type channel_type; | 1005 | enum nl80211_channel_type channel_type; |
| 1006 | bool radar_enabled; | ||
| 996 | enum ieee80211_smps_mode smps_mode; | 1007 | enum ieee80211_smps_mode smps_mode; |
| 997 | }; | 1008 | }; |
| 998 | 1009 | ||
| @@ -1190,6 +1201,24 @@ enum ieee80211_sta_state { | |||
| 1190 | }; | 1201 | }; |
| 1191 | 1202 | ||
| 1192 | /** | 1203 | /** |
| 1204 | * enum ieee80211_sta_rx_bandwidth - station RX bandwidth | ||
| 1205 | * @IEEE80211_STA_RX_BW_20: station can only receive 20 MHz | ||
| 1206 | * @IEEE80211_STA_RX_BW_40: station can receive up to 40 MHz | ||
| 1207 | * @IEEE80211_STA_RX_BW_80: station can receive up to 80 MHz | ||
| 1208 | * @IEEE80211_STA_RX_BW_160: station can receive up to 160 MHz | ||
| 1209 | * (including 80+80 MHz) | ||
| 1210 | * | ||
| 1211 | * Implementation note: 20 must be zero to be initialized | ||
| 1212 | * correctly, the values must be sorted. | ||
| 1213 | */ | ||
| 1214 | enum ieee80211_sta_rx_bandwidth { | ||
| 1215 | IEEE80211_STA_RX_BW_20 = 0, | ||
| 1216 | IEEE80211_STA_RX_BW_40, | ||
| 1217 | IEEE80211_STA_RX_BW_80, | ||
| 1218 | IEEE80211_STA_RX_BW_160, | ||
| 1219 | }; | ||
| 1220 | |||
| 1221 | /** | ||
| 1193 | * struct ieee80211_sta - station table entry | 1222 | * struct ieee80211_sta - station table entry |
| 1194 | * | 1223 | * |
| 1195 | * A station table entry represents a station we are possibly | 1224 | * A station table entry represents a station we are possibly |
| @@ -1211,6 +1240,12 @@ enum ieee80211_sta_state { | |||
| 1211 | * @uapsd_queues: bitmap of queues configured for uapsd. Only valid | 1240 | * @uapsd_queues: bitmap of queues configured for uapsd. Only valid |
| 1212 | * if wme is supported. | 1241 | * if wme is supported. |
| 1213 | * @max_sp: max Service Period. Only valid if wme is supported. | 1242 | * @max_sp: max Service Period. Only valid if wme is supported. |
| 1243 | * @bandwidth: current bandwidth the station can receive with | ||
| 1244 | * @rx_nss: in HT/VHT, the maximum number of spatial streams the | ||
| 1245 | * station can receive at the moment, changed by operating mode | ||
| 1246 | * notifications and capabilities. The value is only valid after | ||
| 1247 | * the station moves to associated state. | ||
| 1248 | * @smps_mode: current SMPS mode (off, static or dynamic) | ||
| 1214 | */ | 1249 | */ |
| 1215 | struct ieee80211_sta { | 1250 | struct ieee80211_sta { |
| 1216 | u32 supp_rates[IEEE80211_NUM_BANDS]; | 1251 | u32 supp_rates[IEEE80211_NUM_BANDS]; |
| @@ -1221,6 +1256,9 @@ struct ieee80211_sta { | |||
| 1221 | bool wme; | 1256 | bool wme; |
| 1222 | u8 uapsd_queues; | 1257 | u8 uapsd_queues; |
| 1223 | u8 max_sp; | 1258 | u8 max_sp; |
| 1259 | u8 rx_nss; | ||
| 1260 | enum ieee80211_sta_rx_bandwidth bandwidth; | ||
| 1261 | enum ieee80211_smps_mode smps_mode; | ||
| 1224 | 1262 | ||
| 1225 | /* must be last */ | 1263 | /* must be last */ |
| 1226 | u8 drv_priv[0] __aligned(sizeof(void *)); | 1264 | u8 drv_priv[0] __aligned(sizeof(void *)); |
| @@ -2079,16 +2117,21 @@ enum ieee80211_frame_release_type { | |||
| 2079 | * enum ieee80211_rate_control_changed - flags to indicate what changed | 2117 | * enum ieee80211_rate_control_changed - flags to indicate what changed |
| 2080 | * | 2118 | * |
| 2081 | * @IEEE80211_RC_BW_CHANGED: The bandwidth that can be used to transmit | 2119 | * @IEEE80211_RC_BW_CHANGED: The bandwidth that can be used to transmit |
| 2082 | * to this station changed. | 2120 | * to this station changed. The actual bandwidth is in the station |
| 2121 | * information -- for HT20/40 the IEEE80211_HT_CAP_SUP_WIDTH_20_40 | ||
| 2122 | * flag changes, for HT and VHT the bandwidth field changes. | ||
| 2083 | * @IEEE80211_RC_SMPS_CHANGED: The SMPS state of the station changed. | 2123 | * @IEEE80211_RC_SMPS_CHANGED: The SMPS state of the station changed. |
| 2084 | * @IEEE80211_RC_SUPP_RATES_CHANGED: The supported rate set of this peer | 2124 | * @IEEE80211_RC_SUPP_RATES_CHANGED: The supported rate set of this peer |
| 2085 | * changed (in IBSS mode) due to discovering more information about | 2125 | * changed (in IBSS mode) due to discovering more information about |
| 2086 | * the peer. | 2126 | * the peer. |
| 2127 | * @IEEE80211_RC_NSS_CHANGED: N_SS (number of spatial streams) was changed | ||
| 2128 | * by the peer | ||
| 2087 | */ | 2129 | */ |
| 2088 | enum ieee80211_rate_control_changed { | 2130 | enum ieee80211_rate_control_changed { |
| 2089 | IEEE80211_RC_BW_CHANGED = BIT(0), | 2131 | IEEE80211_RC_BW_CHANGED = BIT(0), |
| 2090 | IEEE80211_RC_SMPS_CHANGED = BIT(1), | 2132 | IEEE80211_RC_SMPS_CHANGED = BIT(1), |
| 2091 | IEEE80211_RC_SUPP_RATES_CHANGED = BIT(2), | 2133 | IEEE80211_RC_SUPP_RATES_CHANGED = BIT(2), |
| 2134 | IEEE80211_RC_NSS_CHANGED = BIT(3), | ||
| 2092 | }; | 2135 | }; |
| 2093 | 2136 | ||
| 2094 | /** | 2137 | /** |
| @@ -3945,6 +3988,13 @@ void ieee80211_cqm_rssi_notify(struct ieee80211_vif *vif, | |||
| 3945 | gfp_t gfp); | 3988 | gfp_t gfp); |
| 3946 | 3989 | ||
| 3947 | /** | 3990 | /** |
| 3991 | * ieee80211_radar_detected - inform that a radar was detected | ||
| 3992 | * | ||
| 3993 | * @hw: pointer as obtained from ieee80211_alloc_hw() | ||
| 3994 | */ | ||
| 3995 | void ieee80211_radar_detected(struct ieee80211_hw *hw); | ||
| 3996 | |||
| 3997 | /** | ||
| 3948 | * ieee80211_chswitch_done - Complete channel switch process | 3998 | * ieee80211_chswitch_done - Complete channel switch process |
| 3949 | * @vif: &struct ieee80211_vif pointer from the add_interface callback. | 3999 | * @vif: &struct ieee80211_vif pointer from the add_interface callback. |
| 3950 | * @success: make the channel switch successful or not | 4000 | * @success: make the channel switch successful or not |
diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h index 9a2ecdc4136c..c46bb016f4e4 100644 --- a/include/uapi/linux/nl80211.h +++ b/include/uapi/linux/nl80211.h | |||
| @@ -603,6 +603,14 @@ | |||
| 603 | * command is used in AP/P2P GO mode. Driver has to make sure to clear its | 603 | * command is used in AP/P2P GO mode. Driver has to make sure to clear its |
| 604 | * ACL list during %NL80211_CMD_STOP_AP. | 604 | * ACL list during %NL80211_CMD_STOP_AP. |
| 605 | * | 605 | * |
| 606 | * @NL80211_CMD_RADAR_DETECT: Start a Channel availability check (CAC). Once | ||
| 607 | * a radar is detected or the channel availability scan (CAC) has finished | ||
| 608 | * or was aborted, or a radar was detected, usermode will be notified with | ||
| 609 | * this event. This command is also used to notify userspace about radars | ||
| 610 | * while operating on this channel. | ||
| 611 | * %NL80211_ATTR_RADAR_EVENT is used to inform about the type of the | ||
| 612 | * event. | ||
| 613 | * | ||
| 606 | * @NL80211_CMD_MAX: highest used command number | 614 | * @NL80211_CMD_MAX: highest used command number |
| 607 | * @__NL80211_CMD_AFTER_LAST: internal use | 615 | * @__NL80211_CMD_AFTER_LAST: internal use |
| 608 | */ | 616 | */ |
| @@ -755,6 +763,8 @@ enum nl80211_commands { | |||
| 755 | 763 | ||
| 756 | NL80211_CMD_SET_MAC_ACL, | 764 | NL80211_CMD_SET_MAC_ACL, |
| 757 | 765 | ||
| 766 | NL80211_CMD_RADAR_DETECT, | ||
| 767 | |||
| 758 | /* add new commands above here */ | 768 | /* add new commands above here */ |
| 759 | 769 | ||
| 760 | /* used to define NL80211_CMD_MAX below */ | 770 | /* used to define NL80211_CMD_MAX below */ |
| @@ -1342,6 +1352,22 @@ enum nl80211_commands { | |||
| 1342 | * number of MAC addresses that a device can support for MAC | 1352 | * number of MAC addresses that a device can support for MAC |
| 1343 | * ACL. | 1353 | * ACL. |
| 1344 | * | 1354 | * |
| 1355 | * @NL80211_ATTR_RADAR_EVENT: Type of radar event for notification to userspace, | ||
| 1356 | * contains a value of enum nl80211_radar_event (u32). | ||
| 1357 | * | ||
| 1358 | * @NL80211_ATTR_EXT_CAPA: 802.11 extended capabilities that the kernel driver | ||
| 1359 | * has and handles. The format is the same as the IE contents. See | ||
| 1360 | * 802.11-2012 8.4.2.29 for more information. | ||
| 1361 | * @NL80211_ATTR_EXT_CAPA_MASK: Extended capabilities that the kernel driver | ||
| 1362 | * has set in the %NL80211_ATTR_EXT_CAPA value, for multibit fields. | ||
| 1363 | * | ||
| 1364 | * @NL80211_ATTR_STA_CAPABILITY: Station capabilities (u16) are advertised to | ||
| 1365 | * the driver, e.g., to enable TDLS power save (PU-APSD). | ||
| 1366 | * | ||
| 1367 | * @NL80211_ATTR_STA_EXT_CAPABILITY: Station extended capabilities are | ||
| 1368 | * advertised to the driver, e.g., to enable TDLS off channel operations | ||
| 1369 | * and PU-APSD. | ||
| 1370 | * | ||
| 1345 | * @NL80211_ATTR_MAX: highest attribute number currently defined | 1371 | * @NL80211_ATTR_MAX: highest attribute number currently defined |
| 1346 | * @__NL80211_ATTR_AFTER_LAST: internal use | 1372 | * @__NL80211_ATTR_AFTER_LAST: internal use |
| 1347 | */ | 1373 | */ |
| @@ -1620,6 +1646,14 @@ enum nl80211_attrs { | |||
| 1620 | 1646 | ||
| 1621 | NL80211_ATTR_MAC_ACL_MAX, | 1647 | NL80211_ATTR_MAC_ACL_MAX, |
| 1622 | 1648 | ||
| 1649 | NL80211_ATTR_RADAR_EVENT, | ||
| 1650 | |||
| 1651 | NL80211_ATTR_EXT_CAPA, | ||
| 1652 | NL80211_ATTR_EXT_CAPA_MASK, | ||
| 1653 | |||
| 1654 | NL80211_ATTR_STA_CAPABILITY, | ||
| 1655 | NL80211_ATTR_STA_EXT_CAPABILITY, | ||
| 1656 | |||
| 1623 | /* add attributes here, update the policy in nl80211.c */ | 1657 | /* add attributes here, update the policy in nl80211.c */ |
| 1624 | 1658 | ||
| 1625 | __NL80211_ATTR_AFTER_LAST, | 1659 | __NL80211_ATTR_AFTER_LAST, |
| @@ -2022,6 +2056,20 @@ enum nl80211_band_attr { | |||
| 2022 | * on this channel in current regulatory domain. | 2056 | * on this channel in current regulatory domain. |
| 2023 | * @NL80211_FREQUENCY_ATTR_MAX_TX_POWER: Maximum transmission power in mBm | 2057 | * @NL80211_FREQUENCY_ATTR_MAX_TX_POWER: Maximum transmission power in mBm |
| 2024 | * (100 * dBm). | 2058 | * (100 * dBm). |
| 2059 | * @NL80211_FREQUENCY_ATTR_DFS_STATE: current state for DFS | ||
| 2060 | * (enum nl80211_dfs_state) | ||
| 2061 | * @NL80211_FREQUENCY_ATTR_DFS_TIME: time in miliseconds for how long | ||
| 2062 | * this channel is in this DFS state. | ||
| 2063 | * @NL80211_FREQUENCY_ATTR_NO_HT40_MINUS: HT40- isn't possible with this | ||
| 2064 | * channel as the control channel | ||
| 2065 | * @NL80211_FREQUENCY_ATTR_NO_HT40_PLUS: HT40+ isn't possible with this | ||
| 2066 | * channel as the control channel | ||
| 2067 | * @NL80211_FREQUENCY_ATTR_NO_80MHZ: any 80 MHz channel using this channel | ||
| 2068 | * as the primary or any of the secondary channels isn't possible, | ||
| 2069 | * this includes 80+80 channels | ||
| 2070 | * @NL80211_FREQUENCY_ATTR_NO_160MHZ: any 160 MHz (but not 80+80) channel | ||
| 2071 | * using this channel as the primary or any of the secondary channels | ||
| 2072 | * isn't possible | ||
| 2025 | * @NL80211_FREQUENCY_ATTR_MAX: highest frequency attribute number | 2073 | * @NL80211_FREQUENCY_ATTR_MAX: highest frequency attribute number |
| 2026 | * currently defined | 2074 | * currently defined |
| 2027 | * @__NL80211_FREQUENCY_ATTR_AFTER_LAST: internal use | 2075 | * @__NL80211_FREQUENCY_ATTR_AFTER_LAST: internal use |
| @@ -2034,6 +2082,12 @@ enum nl80211_frequency_attr { | |||
| 2034 | NL80211_FREQUENCY_ATTR_NO_IBSS, | 2082 | NL80211_FREQUENCY_ATTR_NO_IBSS, |
| 2035 | NL80211_FREQUENCY_ATTR_RADAR, | 2083 | NL80211_FREQUENCY_ATTR_RADAR, |
| 2036 | NL80211_FREQUENCY_ATTR_MAX_TX_POWER, | 2084 | NL80211_FREQUENCY_ATTR_MAX_TX_POWER, |
| 2085 | NL80211_FREQUENCY_ATTR_DFS_STATE, | ||
| 2086 | NL80211_FREQUENCY_ATTR_DFS_TIME, | ||
| 2087 | NL80211_FREQUENCY_ATTR_NO_HT40_MINUS, | ||
| 2088 | NL80211_FREQUENCY_ATTR_NO_HT40_PLUS, | ||
| 2089 | NL80211_FREQUENCY_ATTR_NO_80MHZ, | ||
| 2090 | NL80211_FREQUENCY_ATTR_NO_160MHZ, | ||
| 2037 | 2091 | ||
| 2038 | /* keep last */ | 2092 | /* keep last */ |
| 2039 | __NL80211_FREQUENCY_ATTR_AFTER_LAST, | 2093 | __NL80211_FREQUENCY_ATTR_AFTER_LAST, |
| @@ -2906,10 +2960,12 @@ enum nl80211_tx_power_setting { | |||
| 2906 | * corresponds to the lowest-order bit in the second byte of the mask. | 2960 | * corresponds to the lowest-order bit in the second byte of the mask. |
| 2907 | * For example: The match 00:xx:00:00:xx:00:00:00:00:xx:xx:xx (where | 2961 | * For example: The match 00:xx:00:00:xx:00:00:00:00:xx:xx:xx (where |
| 2908 | * xx indicates "don't care") would be represented by a pattern of | 2962 | * xx indicates "don't care") would be represented by a pattern of |
| 2909 | * twelve zero bytes, and a mask of "0xed,0x07". | 2963 | * twelve zero bytes, and a mask of "0xed,0x01". |
| 2910 | * Note that the pattern matching is done as though frames were not | 2964 | * Note that the pattern matching is done as though frames were not |
| 2911 | * 802.11 frames but 802.3 frames, i.e. the frame is fully unpacked | 2965 | * 802.11 frames but 802.3 frames, i.e. the frame is fully unpacked |
| 2912 | * first (including SNAP header unpacking) and then matched. | 2966 | * first (including SNAP header unpacking) and then matched. |
| 2967 | * @NL80211_WOWLAN_PKTPAT_OFFSET: packet offset, pattern is matched after | ||
| 2968 | * these fixed number of bytes of received packet | ||
| 2913 | * @NUM_NL80211_WOWLAN_PKTPAT: number of attributes | 2969 | * @NUM_NL80211_WOWLAN_PKTPAT: number of attributes |
| 2914 | * @MAX_NL80211_WOWLAN_PKTPAT: max attribute number | 2970 | * @MAX_NL80211_WOWLAN_PKTPAT: max attribute number |
| 2915 | */ | 2971 | */ |
| @@ -2917,6 +2973,7 @@ enum nl80211_wowlan_packet_pattern_attr { | |||
| 2917 | __NL80211_WOWLAN_PKTPAT_INVALID, | 2973 | __NL80211_WOWLAN_PKTPAT_INVALID, |
| 2918 | NL80211_WOWLAN_PKTPAT_MASK, | 2974 | NL80211_WOWLAN_PKTPAT_MASK, |
| 2919 | NL80211_WOWLAN_PKTPAT_PATTERN, | 2975 | NL80211_WOWLAN_PKTPAT_PATTERN, |
| 2976 | NL80211_WOWLAN_PKTPAT_OFFSET, | ||
| 2920 | 2977 | ||
| 2921 | NUM_NL80211_WOWLAN_PKTPAT, | 2978 | NUM_NL80211_WOWLAN_PKTPAT, |
| 2922 | MAX_NL80211_WOWLAN_PKTPAT = NUM_NL80211_WOWLAN_PKTPAT - 1, | 2979 | MAX_NL80211_WOWLAN_PKTPAT = NUM_NL80211_WOWLAN_PKTPAT - 1, |
| @@ -2927,6 +2984,7 @@ enum nl80211_wowlan_packet_pattern_attr { | |||
| 2927 | * @max_patterns: maximum number of patterns supported | 2984 | * @max_patterns: maximum number of patterns supported |
| 2928 | * @min_pattern_len: minimum length of each pattern | 2985 | * @min_pattern_len: minimum length of each pattern |
| 2929 | * @max_pattern_len: maximum length of each pattern | 2986 | * @max_pattern_len: maximum length of each pattern |
| 2987 | * @max_pkt_offset: maximum Rx packet offset | ||
| 2930 | * | 2988 | * |
| 2931 | * This struct is carried in %NL80211_WOWLAN_TRIG_PKT_PATTERN when | 2989 | * This struct is carried in %NL80211_WOWLAN_TRIG_PKT_PATTERN when |
| 2932 | * that is part of %NL80211_ATTR_WOWLAN_TRIGGERS_SUPPORTED in the | 2990 | * that is part of %NL80211_ATTR_WOWLAN_TRIGGERS_SUPPORTED in the |
| @@ -2936,6 +2994,7 @@ struct nl80211_wowlan_pattern_support { | |||
| 2936 | __u32 max_patterns; | 2994 | __u32 max_patterns; |
| 2937 | __u32 min_pattern_len; | 2995 | __u32 min_pattern_len; |
| 2938 | __u32 max_pattern_len; | 2996 | __u32 max_pattern_len; |
| 2997 | __u32 max_pkt_offset; | ||
| 2939 | } __attribute__((packed)); | 2998 | } __attribute__((packed)); |
| 2940 | 2999 | ||
| 2941 | /** | 3000 | /** |
| @@ -2951,9 +3010,10 @@ struct nl80211_wowlan_pattern_support { | |||
| 2951 | * @NL80211_WOWLAN_TRIG_PKT_PATTERN: wake up on the specified packet patterns | 3010 | * @NL80211_WOWLAN_TRIG_PKT_PATTERN: wake up on the specified packet patterns |
| 2952 | * which are passed in an array of nested attributes, each nested attribute | 3011 | * which are passed in an array of nested attributes, each nested attribute |
| 2953 | * defining a with attributes from &struct nl80211_wowlan_trig_pkt_pattern. | 3012 | * defining a with attributes from &struct nl80211_wowlan_trig_pkt_pattern. |
| 2954 | * Each pattern defines a wakeup packet. The matching is done on the MSDU, | 3013 | * Each pattern defines a wakeup packet. Packet offset is associated with |
| 2955 | * i.e. as though the packet was an 802.3 packet, so the pattern matching | 3014 | * each pattern which is used while matching the pattern. The matching is |
| 2956 | * is done after the packet is converted to the MSDU. | 3015 | * done on the MSDU, i.e. as though the packet was an 802.3 packet, so the |
| 3016 | * pattern matching is done after the packet is converted to the MSDU. | ||
| 2957 | * | 3017 | * |
| 2958 | * In %NL80211_ATTR_WOWLAN_TRIGGERS_SUPPORTED, it is a binary attribute | 3018 | * In %NL80211_ATTR_WOWLAN_TRIGGERS_SUPPORTED, it is a binary attribute |
| 2959 | * carrying a &struct nl80211_wowlan_pattern_support. | 3019 | * carrying a &struct nl80211_wowlan_pattern_support. |
| @@ -2985,6 +3045,17 @@ struct nl80211_wowlan_pattern_support { | |||
| 2985 | * @NL80211_WOWLAN_TRIG_WAKEUP_PKT_8023_LEN: Original length of the 802.3 | 3045 | * @NL80211_WOWLAN_TRIG_WAKEUP_PKT_8023_LEN: Original length of the 802.3 |
| 2986 | * packet, may be bigger than the @NL80211_WOWLAN_TRIG_WAKEUP_PKT_8023 | 3046 | * packet, may be bigger than the @NL80211_WOWLAN_TRIG_WAKEUP_PKT_8023 |
| 2987 | * attribute if the packet was truncated somewhere. | 3047 | * attribute if the packet was truncated somewhere. |
| 3048 | * @NL80211_WOWLAN_TRIG_TCP_CONNECTION: TCP connection wake, see DOC section | ||
| 3049 | * "TCP connection wakeup" for more details. This is a nested attribute | ||
| 3050 | * containing the exact information for establishing and keeping alive | ||
| 3051 | * the TCP connection. | ||
| 3052 | * @NL80211_WOWLAN_TRIG_TCP_WAKEUP_MATCH: For wakeup reporting only, the | ||
| 3053 | * wakeup packet was received on the TCP connection | ||
| 3054 | * @NL80211_WOWLAN_TRIG_WAKEUP_TCP_CONNLOST: For wakeup reporting only, the | ||
| 3055 | * TCP connection was lost or failed to be established | ||
| 3056 | * @NL80211_WOWLAN_TRIG_WAKEUP_TCP_NOMORETOKENS: For wakeup reporting only, | ||
| 3057 | * the TCP connection ran out of tokens to use for data to send to the | ||
| 3058 | * service | ||
| 2988 | * @NUM_NL80211_WOWLAN_TRIG: number of wake on wireless triggers | 3059 | * @NUM_NL80211_WOWLAN_TRIG: number of wake on wireless triggers |
| 2989 | * @MAX_NL80211_WOWLAN_TRIG: highest wowlan trigger attribute number | 3060 | * @MAX_NL80211_WOWLAN_TRIG: highest wowlan trigger attribute number |
| 2990 | * | 3061 | * |
| @@ -3006,6 +3077,10 @@ enum nl80211_wowlan_triggers { | |||
| 3006 | NL80211_WOWLAN_TRIG_WAKEUP_PKT_80211_LEN, | 3077 | NL80211_WOWLAN_TRIG_WAKEUP_PKT_80211_LEN, |
| 3007 | NL80211_WOWLAN_TRIG_WAKEUP_PKT_8023, | 3078 | NL80211_WOWLAN_TRIG_WAKEUP_PKT_8023, |
| 3008 | NL80211_WOWLAN_TRIG_WAKEUP_PKT_8023_LEN, | 3079 | NL80211_WOWLAN_TRIG_WAKEUP_PKT_8023_LEN, |
| 3080 | NL80211_WOWLAN_TRIG_TCP_CONNECTION, | ||
| 3081 | NL80211_WOWLAN_TRIG_WAKEUP_TCP_MATCH, | ||
| 3082 | NL80211_WOWLAN_TRIG_WAKEUP_TCP_CONNLOST, | ||
| 3083 | NL80211_WOWLAN_TRIG_WAKEUP_TCP_NOMORETOKENS, | ||
| 3009 | 3084 | ||
| 3010 | /* keep last */ | 3085 | /* keep last */ |
| 3011 | NUM_NL80211_WOWLAN_TRIG, | 3086 | NUM_NL80211_WOWLAN_TRIG, |
| @@ -3013,6 +3088,116 @@ enum nl80211_wowlan_triggers { | |||
| 3013 | }; | 3088 | }; |
| 3014 | 3089 | ||
| 3015 | /** | 3090 | /** |
| 3091 | * DOC: TCP connection wakeup | ||
| 3092 | * | ||
| 3093 | * Some devices can establish a TCP connection in order to be woken up by a | ||
| 3094 | * packet coming in from outside their network segment, or behind NAT. If | ||
| 3095 | * configured, the device will establish a TCP connection to the given | ||
| 3096 | * service, and periodically send data to that service. The first data | ||
| 3097 | * packet is usually transmitted after SYN/ACK, also ACKing the SYN/ACK. | ||
| 3098 | * The data packets can optionally include a (little endian) sequence | ||
| 3099 | * number (in the TCP payload!) that is generated by the device, and, also | ||
| 3100 | * optionally, a token from a list of tokens. This serves as a keep-alive | ||
| 3101 | * with the service, and for NATed connections, etc. | ||
| 3102 | * | ||
| 3103 | * During this keep-alive period, the server doesn't send any data to the | ||
| 3104 | * client. When receiving data, it is compared against the wakeup pattern | ||
| 3105 | * (and mask) and if it matches, the host is woken up. Similarly, if the | ||
| 3106 | * connection breaks or cannot be established to start with, the host is | ||
| 3107 | * also woken up. | ||
| 3108 | * | ||
| 3109 | * Developer's note: ARP offload is required for this, otherwise TCP | ||
| 3110 | * response packets might not go through correctly. | ||
| 3111 | */ | ||
| 3112 | |||
| 3113 | /** | ||
| 3114 | * struct nl80211_wowlan_tcp_data_seq - WoWLAN TCP data sequence | ||
| 3115 | * @start: starting value | ||
| 3116 | * @offset: offset of sequence number in packet | ||
| 3117 | * @len: length of the sequence value to write, 1 through 4 | ||
| 3118 | * | ||
| 3119 | * Note: don't confuse with the TCP sequence number(s), this is for the | ||
| 3120 | * keepalive packet payload. The actual value is written into the packet | ||
| 3121 | * in little endian. | ||
| 3122 | */ | ||
| 3123 | struct nl80211_wowlan_tcp_data_seq { | ||
| 3124 | __u32 start, offset, len; | ||
| 3125 | }; | ||
| 3126 | |||
| 3127 | /** | ||
| 3128 | * struct nl80211_wowlan_tcp_data_token - WoWLAN TCP data token config | ||
| 3129 | * @offset: offset of token in packet | ||
| 3130 | * @len: length of each token | ||
| 3131 | * @token_stream: stream of data to be used for the tokens, the length must | ||
| 3132 | * be a multiple of @len for this to make sense | ||
| 3133 | */ | ||
| 3134 | struct nl80211_wowlan_tcp_data_token { | ||
| 3135 | __u32 offset, len; | ||
| 3136 | __u8 token_stream[]; | ||
| 3137 | }; | ||
| 3138 | |||
| 3139 | /** | ||
| 3140 | * struct nl80211_wowlan_tcp_data_token_feature - data token features | ||
| 3141 | * @min_len: minimum token length | ||
| 3142 | * @max_len: maximum token length | ||
| 3143 | * @bufsize: total available token buffer size (max size of @token_stream) | ||
| 3144 | */ | ||
| 3145 | struct nl80211_wowlan_tcp_data_token_feature { | ||
| 3146 | __u32 min_len, max_len, bufsize; | ||
| 3147 | }; | ||
| 3148 | |||
| 3149 | /** | ||
| 3150 | * enum nl80211_wowlan_tcp_attrs - WoWLAN TCP connection parameters | ||
| 3151 | * @__NL80211_WOWLAN_TCP_INVALID: invalid number for nested attributes | ||
| 3152 | * @NL80211_WOWLAN_TCP_SRC_IPV4: source IPv4 address (in network byte order) | ||
| 3153 | * @NL80211_WOWLAN_TCP_DST_IPV4: destination IPv4 address | ||
| 3154 | * (in network byte order) | ||
| 3155 | * @NL80211_WOWLAN_TCP_DST_MAC: destination MAC address, this is given because | ||
| 3156 | * route lookup when configured might be invalid by the time we suspend, | ||
| 3157 | * and doing a route lookup when suspending is no longer possible as it | ||
| 3158 | * might require ARP querying. | ||
| 3159 | * @NL80211_WOWLAN_TCP_SRC_PORT: source port (u16); optional, if not given a | ||
| 3160 | * socket and port will be allocated | ||
| 3161 | * @NL80211_WOWLAN_TCP_DST_PORT: destination port (u16) | ||
| 3162 | * @NL80211_WOWLAN_TCP_DATA_PAYLOAD: data packet payload, at least one byte. | ||
| 3163 | * For feature advertising, a u32 attribute holding the maximum length | ||
| 3164 | * of the data payload. | ||
| 3165 | * @NL80211_WOWLAN_TCP_DATA_PAYLOAD_SEQ: data packet sequence configuration | ||
| 3166 | * (if desired), a &struct nl80211_wowlan_tcp_data_seq. For feature | ||
| 3167 | * advertising it is just a flag | ||
| 3168 | * @NL80211_WOWLAN_TCP_DATA_PAYLOAD_TOKEN: data packet token configuration, | ||
| 3169 | * see &struct nl80211_wowlan_tcp_data_token and for advertising see | ||
| 3170 | * &struct nl80211_wowlan_tcp_data_token_feature. | ||
| 3171 | * @NL80211_WOWLAN_TCP_DATA_INTERVAL: data interval in seconds, maximum | ||
| 3172 | * interval in feature advertising (u32) | ||
| 3173 | * @NL80211_WOWLAN_TCP_WAKE_PAYLOAD: wake packet payload, for advertising a | ||
| 3174 | * u32 attribute holding the maximum length | ||
| 3175 | * @NL80211_WOWLAN_TCP_WAKE_MASK: Wake packet payload mask, not used for | ||
| 3176 | * feature advertising. The mask works like @NL80211_WOWLAN_PKTPAT_MASK | ||
| 3177 | * but on the TCP payload only. | ||
| 3178 | * @NUM_NL80211_WOWLAN_TCP: number of TCP attributes | ||
| 3179 | * @MAX_NL80211_WOWLAN_TCP: highest attribute number | ||
| 3180 | */ | ||
| 3181 | enum nl80211_wowlan_tcp_attrs { | ||
| 3182 | __NL80211_WOWLAN_TCP_INVALID, | ||
| 3183 | NL80211_WOWLAN_TCP_SRC_IPV4, | ||
| 3184 | NL80211_WOWLAN_TCP_DST_IPV4, | ||
| 3185 | NL80211_WOWLAN_TCP_DST_MAC, | ||
| 3186 | NL80211_WOWLAN_TCP_SRC_PORT, | ||
| 3187 | NL80211_WOWLAN_TCP_DST_PORT, | ||
| 3188 | NL80211_WOWLAN_TCP_DATA_PAYLOAD, | ||
| 3189 | NL80211_WOWLAN_TCP_DATA_PAYLOAD_SEQ, | ||
| 3190 | NL80211_WOWLAN_TCP_DATA_PAYLOAD_TOKEN, | ||
| 3191 | NL80211_WOWLAN_TCP_DATA_INTERVAL, | ||
| 3192 | NL80211_WOWLAN_TCP_WAKE_PAYLOAD, | ||
| 3193 | NL80211_WOWLAN_TCP_WAKE_MASK, | ||
| 3194 | |||
| 3195 | /* keep last */ | ||
| 3196 | NUM_NL80211_WOWLAN_TCP, | ||
| 3197 | MAX_NL80211_WOWLAN_TCP = NUM_NL80211_WOWLAN_TCP - 1 | ||
| 3198 | }; | ||
| 3199 | |||
| 3200 | /** | ||
| 3016 | * enum nl80211_iface_limit_attrs - limit attributes | 3201 | * enum nl80211_iface_limit_attrs - limit attributes |
| 3017 | * @NL80211_IFACE_LIMIT_UNSPEC: (reserved) | 3202 | * @NL80211_IFACE_LIMIT_UNSPEC: (reserved) |
| 3018 | * @NL80211_IFACE_LIMIT_MAX: maximum number of interfaces that | 3203 | * @NL80211_IFACE_LIMIT_MAX: maximum number of interfaces that |
| @@ -3269,6 +3454,8 @@ enum nl80211_ap_sme_features { | |||
| 3269 | * Note that even for drivers that support this, the default is to add | 3454 | * Note that even for drivers that support this, the default is to add |
| 3270 | * stations in authenticated/associated state, so to add unauthenticated | 3455 | * stations in authenticated/associated state, so to add unauthenticated |
| 3271 | * stations the authenticated/associated bits have to be set in the mask. | 3456 | * stations the authenticated/associated bits have to be set in the mask. |
| 3457 | * @NL80211_FEATURE_ADVERTISE_CHAN_LIMITS: cfg80211 advertises channel limits | ||
| 3458 | * (HT40, VHT 80/160 MHz) if this flag is set | ||
| 3272 | */ | 3459 | */ |
| 3273 | enum nl80211_feature_flags { | 3460 | enum nl80211_feature_flags { |
| 3274 | NL80211_FEATURE_SK_TX_STATUS = 1 << 0, | 3461 | NL80211_FEATURE_SK_TX_STATUS = 1 << 0, |
| @@ -3284,7 +3471,9 @@ enum nl80211_feature_flags { | |||
| 3284 | NL80211_FEATURE_NEED_OBSS_SCAN = 1 << 10, | 3471 | NL80211_FEATURE_NEED_OBSS_SCAN = 1 << 10, |
| 3285 | NL80211_FEATURE_P2P_GO_CTWIN = 1 << 11, | 3472 | NL80211_FEATURE_P2P_GO_CTWIN = 1 << 11, |
| 3286 | NL80211_FEATURE_P2P_GO_OPPPS = 1 << 12, | 3473 | NL80211_FEATURE_P2P_GO_OPPPS = 1 << 12, |
| 3287 | NL80211_FEATURE_FULL_AP_CLIENT_STATE = 1 << 13, | 3474 | /* bit 13 is reserved */ |
| 3475 | NL80211_FEATURE_ADVERTISE_CHAN_LIMITS = 1 << 14, | ||
| 3476 | NL80211_FEATURE_FULL_AP_CLIENT_STATE = 1 << 15, | ||
| 3288 | }; | 3477 | }; |
| 3289 | 3478 | ||
| 3290 | /** | 3479 | /** |
| @@ -3358,4 +3547,44 @@ enum nl80211_acl_policy { | |||
| 3358 | NL80211_ACL_POLICY_DENY_UNLESS_LISTED, | 3547 | NL80211_ACL_POLICY_DENY_UNLESS_LISTED, |
| 3359 | }; | 3548 | }; |
| 3360 | 3549 | ||
| 3550 | /** | ||
| 3551 | * enum nl80211_radar_event - type of radar event for DFS operation | ||
| 3552 | * | ||
| 3553 | * Type of event to be used with NL80211_ATTR_RADAR_EVENT to inform userspace | ||
| 3554 | * about detected radars or success of the channel available check (CAC) | ||
| 3555 | * | ||
| 3556 | * @NL80211_RADAR_DETECTED: A radar pattern has been detected. The channel is | ||
| 3557 | * now unusable. | ||
| 3558 | * @NL80211_RADAR_CAC_FINISHED: Channel Availability Check has been finished, | ||
| 3559 | * the channel is now available. | ||
| 3560 | * @NL80211_RADAR_CAC_ABORTED: Channel Availability Check has been aborted, no | ||
| 3561 | * change to the channel status. | ||
| 3562 | * @NL80211_RADAR_NOP_FINISHED: The Non-Occupancy Period for this channel is | ||
| 3563 | * over, channel becomes usable. | ||
| 3564 | */ | ||
| 3565 | enum nl80211_radar_event { | ||
| 3566 | NL80211_RADAR_DETECTED, | ||
| 3567 | NL80211_RADAR_CAC_FINISHED, | ||
| 3568 | NL80211_RADAR_CAC_ABORTED, | ||
| 3569 | NL80211_RADAR_NOP_FINISHED, | ||
| 3570 | }; | ||
| 3571 | |||
| 3572 | /** | ||
| 3573 | * enum nl80211_dfs_state - DFS states for channels | ||
| 3574 | * | ||
| 3575 | * Channel states used by the DFS code. | ||
| 3576 | * | ||
| 3577 | * @IEEE80211_DFS_USABLE: The channel can be used, but channel availability | ||
| 3578 | * check (CAC) must be performed before using it for AP or IBSS. | ||
| 3579 | * @IEEE80211_DFS_UNAVAILABLE: A radar has been detected on this channel, it | ||
| 3580 | * is therefore marked as not available. | ||
| 3581 | * @IEEE80211_DFS_AVAILABLE: The channel has been CAC checked and is available. | ||
| 3582 | */ | ||
| 3583 | |||
| 3584 | enum nl80211_dfs_state { | ||
| 3585 | NL80211_DFS_USABLE, | ||
| 3586 | NL80211_DFS_UNAVAILABLE, | ||
| 3587 | NL80211_DFS_AVAILABLE, | ||
| 3588 | }; | ||
| 3589 | |||
| 3361 | #endif /* __LINUX_NL80211_H */ | 3590 | #endif /* __LINUX_NL80211_H */ |
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index a4c0a0d9098f..179dcbd8be1c 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c | |||
| @@ -928,6 +928,7 @@ static int ieee80211_start_ap(struct wiphy *wiphy, struct net_device *dev, | |||
| 928 | /* TODO: make hostapd tell us what it wants */ | 928 | /* TODO: make hostapd tell us what it wants */ |
| 929 | sdata->smps_mode = IEEE80211_SMPS_OFF; | 929 | sdata->smps_mode = IEEE80211_SMPS_OFF; |
| 930 | sdata->needed_rx_chains = sdata->local->rx_chains; | 930 | sdata->needed_rx_chains = sdata->local->rx_chains; |
| 931 | sdata->radar_required = params->radar_required; | ||
| 931 | 932 | ||
| 932 | err = ieee80211_vif_use_channel(sdata, ¶ms->chandef, | 933 | err = ieee80211_vif_use_channel(sdata, ¶ms->chandef, |
| 933 | IEEE80211_CHANCTX_SHARED); | 934 | IEEE80211_CHANCTX_SHARED); |
| @@ -1251,19 +1252,16 @@ static int sta_apply_parameters(struct ieee80211_local *local, | |||
| 1251 | 1252 | ||
| 1252 | if (params->ht_capa) | 1253 | if (params->ht_capa) |
| 1253 | ieee80211_ht_cap_ie_to_sta_ht_cap(sdata, sband, | 1254 | ieee80211_ht_cap_ie_to_sta_ht_cap(sdata, sband, |
| 1254 | params->ht_capa, | 1255 | params->ht_capa, sta); |
| 1255 | &sta->sta.ht_cap); | ||
| 1256 | 1256 | ||
| 1257 | if (params->vht_capa) | 1257 | if (params->vht_capa) |
| 1258 | ieee80211_vht_cap_ie_to_sta_vht_cap(sdata, sband, | 1258 | ieee80211_vht_cap_ie_to_sta_vht_cap(sdata, sband, |
| 1259 | params->vht_capa, | 1259 | params->vht_capa, sta); |
| 1260 | &sta->sta.vht_cap); | ||
| 1261 | 1260 | ||
| 1262 | if (ieee80211_vif_is_mesh(&sdata->vif)) { | 1261 | if (ieee80211_vif_is_mesh(&sdata->vif)) { |
| 1263 | #ifdef CONFIG_MAC80211_MESH | 1262 | #ifdef CONFIG_MAC80211_MESH |
| 1263 | u32 changed = 0; | ||
| 1264 | if (sdata->u.mesh.security & IEEE80211_MESH_SEC_SECURED) { | 1264 | if (sdata->u.mesh.security & IEEE80211_MESH_SEC_SECURED) { |
| 1265 | u32 changed = 0; | ||
| 1266 | |||
| 1267 | switch (params->plink_state) { | 1265 | switch (params->plink_state) { |
| 1268 | case NL80211_PLINK_ESTAB: | 1266 | case NL80211_PLINK_ESTAB: |
| 1269 | if (sta->plink_state != NL80211_PLINK_ESTAB) | 1267 | if (sta->plink_state != NL80211_PLINK_ESTAB) |
| @@ -1272,8 +1270,8 @@ static int sta_apply_parameters(struct ieee80211_local *local, | |||
| 1272 | sta->plink_state = params->plink_state; | 1270 | sta->plink_state = params->plink_state; |
| 1273 | 1271 | ||
| 1274 | ieee80211_mps_sta_status_update(sta); | 1272 | ieee80211_mps_sta_status_update(sta); |
| 1275 | ieee80211_mps_set_sta_local_pm(sta, | 1273 | changed |= ieee80211_mps_set_sta_local_pm(sta, |
| 1276 | sdata->u.mesh.mshcfg.power_mode); | 1274 | sdata->u.mesh.mshcfg.power_mode); |
| 1277 | break; | 1275 | break; |
| 1278 | case NL80211_PLINK_LISTEN: | 1276 | case NL80211_PLINK_LISTEN: |
| 1279 | case NL80211_PLINK_BLOCKED: | 1277 | case NL80211_PLINK_BLOCKED: |
| @@ -1287,26 +1285,29 @@ static int sta_apply_parameters(struct ieee80211_local *local, | |||
| 1287 | sta->plink_state = params->plink_state; | 1285 | sta->plink_state = params->plink_state; |
| 1288 | 1286 | ||
| 1289 | ieee80211_mps_sta_status_update(sta); | 1287 | ieee80211_mps_sta_status_update(sta); |
| 1290 | ieee80211_mps_local_status_update(sdata); | 1288 | changed |= |
| 1289 | ieee80211_mps_local_status_update(sdata); | ||
| 1291 | break; | 1290 | break; |
| 1292 | default: | 1291 | default: |
| 1293 | /* nothing */ | 1292 | /* nothing */ |
| 1294 | break; | 1293 | break; |
| 1295 | } | 1294 | } |
| 1296 | ieee80211_bss_info_change_notify(sdata, changed); | ||
| 1297 | } else { | 1295 | } else { |
| 1298 | switch (params->plink_action) { | 1296 | switch (params->plink_action) { |
| 1299 | case PLINK_ACTION_OPEN: | 1297 | case PLINK_ACTION_OPEN: |
| 1300 | mesh_plink_open(sta); | 1298 | changed |= mesh_plink_open(sta); |
| 1301 | break; | 1299 | break; |
| 1302 | case PLINK_ACTION_BLOCK: | 1300 | case PLINK_ACTION_BLOCK: |
| 1303 | mesh_plink_block(sta); | 1301 | changed |= mesh_plink_block(sta); |
| 1304 | break; | 1302 | break; |
| 1305 | } | 1303 | } |
| 1306 | } | 1304 | } |
| 1307 | 1305 | ||
| 1308 | if (params->local_pm) | 1306 | if (params->local_pm) |
| 1309 | ieee80211_mps_set_sta_local_pm(sta, params->local_pm); | 1307 | changed |= |
| 1308 | ieee80211_mps_set_sta_local_pm(sta, | ||
| 1309 | params->local_pm); | ||
| 1310 | ieee80211_bss_info_change_notify(sdata, changed); | ||
| 1310 | #endif | 1311 | #endif |
| 1311 | } | 1312 | } |
| 1312 | 1313 | ||
| @@ -1411,9 +1412,11 @@ static int ieee80211_change_station(struct wiphy *wiphy, | |||
| 1411 | return -ENOENT; | 1412 | return -ENOENT; |
| 1412 | } | 1413 | } |
| 1413 | 1414 | ||
| 1414 | /* in station mode, supported rates are only valid with TDLS */ | 1415 | /* in station mode, some updates are only valid with TDLS */ |
| 1415 | if (sdata->vif.type == NL80211_IFTYPE_STATION && | 1416 | if (sdata->vif.type == NL80211_IFTYPE_STATION && |
| 1416 | params->supported_rates && | 1417 | (params->supported_rates || params->ht_capa || params->vht_capa || |
| 1418 | params->sta_modify_mask || | ||
| 1419 | (params->sta_flags_mask & BIT(NL80211_STA_FLAG_WME))) && | ||
| 1417 | !test_sta_flag(sta, WLAN_STA_TDLS_PEER)) { | 1420 | !test_sta_flag(sta, WLAN_STA_TDLS_PEER)) { |
| 1418 | mutex_unlock(&local->sta_mtx); | 1421 | mutex_unlock(&local->sta_mtx); |
| 1419 | return -EINVAL; | 1422 | return -EINVAL; |
| @@ -1799,11 +1802,10 @@ static int ieee80211_update_mesh_config(struct wiphy *wiphy, | |||
| 1799 | conf->power_mode = nconf->power_mode; | 1802 | conf->power_mode = nconf->power_mode; |
| 1800 | ieee80211_mps_local_status_update(sdata); | 1803 | ieee80211_mps_local_status_update(sdata); |
| 1801 | } | 1804 | } |
| 1802 | if (_chg_mesh_attr(NL80211_MESHCONF_AWAKE_WINDOW, mask)) { | 1805 | if (_chg_mesh_attr(NL80211_MESHCONF_AWAKE_WINDOW, mask)) |
| 1803 | conf->dot11MeshAwakeWindowDuration = | 1806 | conf->dot11MeshAwakeWindowDuration = |
| 1804 | nconf->dot11MeshAwakeWindowDuration; | 1807 | nconf->dot11MeshAwakeWindowDuration; |
| 1805 | ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON); | 1808 | ieee80211_mbss_info_change_notify(sdata, BSS_CHANGED_BEACON); |
| 1806 | } | ||
| 1807 | return 0; | 1809 | return 0; |
| 1808 | } | 1810 | } |
| 1809 | 1811 | ||
| @@ -1829,9 +1831,7 @@ static int ieee80211_join_mesh(struct wiphy *wiphy, struct net_device *dev, | |||
| 1829 | if (err) | 1831 | if (err) |
| 1830 | return err; | 1832 | return err; |
| 1831 | 1833 | ||
| 1832 | ieee80211_start_mesh(sdata); | 1834 | return ieee80211_start_mesh(sdata); |
| 1833 | |||
| 1834 | return 0; | ||
| 1835 | } | 1835 | } |
| 1836 | 1836 | ||
| 1837 | static int ieee80211_leave_mesh(struct wiphy *wiphy, struct net_device *dev) | 1837 | static int ieee80211_leave_mesh(struct wiphy *wiphy, struct net_device *dev) |
| @@ -2396,7 +2396,8 @@ static int ieee80211_start_roc_work(struct ieee80211_local *local, | |||
| 2396 | INIT_LIST_HEAD(&roc->dependents); | 2396 | INIT_LIST_HEAD(&roc->dependents); |
| 2397 | 2397 | ||
| 2398 | /* if there's one pending or we're scanning, queue this one */ | 2398 | /* if there's one pending or we're scanning, queue this one */ |
| 2399 | if (!list_empty(&local->roc_list) || local->scanning) | 2399 | if (!list_empty(&local->roc_list) || |
| 2400 | local->scanning || local->radar_detect_enabled) | ||
| 2400 | goto out_check_combine; | 2401 | goto out_check_combine; |
| 2401 | 2402 | ||
| 2402 | /* if not HW assist, just queue & schedule work */ | 2403 | /* if not HW assist, just queue & schedule work */ |
| @@ -2646,6 +2647,37 @@ static int ieee80211_cancel_remain_on_channel(struct wiphy *wiphy, | |||
| 2646 | return ieee80211_cancel_roc(local, cookie, false); | 2647 | return ieee80211_cancel_roc(local, cookie, false); |
| 2647 | } | 2648 | } |
| 2648 | 2649 | ||
| 2650 | static int ieee80211_start_radar_detection(struct wiphy *wiphy, | ||
| 2651 | struct net_device *dev, | ||
| 2652 | struct cfg80211_chan_def *chandef) | ||
| 2653 | { | ||
| 2654 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
| 2655 | struct ieee80211_local *local = sdata->local; | ||
| 2656 | unsigned long timeout; | ||
| 2657 | int err; | ||
| 2658 | |||
| 2659 | if (!list_empty(&local->roc_list) || local->scanning) | ||
| 2660 | return -EBUSY; | ||
| 2661 | |||
| 2662 | /* whatever, but channel contexts should not complain about that one */ | ||
| 2663 | sdata->smps_mode = IEEE80211_SMPS_OFF; | ||
| 2664 | sdata->needed_rx_chains = local->rx_chains; | ||
| 2665 | sdata->radar_required = true; | ||
| 2666 | |||
| 2667 | mutex_lock(&local->iflist_mtx); | ||
| 2668 | err = ieee80211_vif_use_channel(sdata, chandef, | ||
| 2669 | IEEE80211_CHANCTX_SHARED); | ||
| 2670 | mutex_unlock(&local->iflist_mtx); | ||
| 2671 | if (err) | ||
| 2672 | return err; | ||
| 2673 | |||
| 2674 | timeout = msecs_to_jiffies(IEEE80211_DFS_MIN_CAC_TIME_MS); | ||
| 2675 | ieee80211_queue_delayed_work(&sdata->local->hw, | ||
| 2676 | &sdata->dfs_cac_timer_work, timeout); | ||
| 2677 | |||
| 2678 | return 0; | ||
| 2679 | } | ||
| 2680 | |||
| 2649 | static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev, | 2681 | static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev, |
| 2650 | struct ieee80211_channel *chan, bool offchan, | 2682 | struct ieee80211_channel *chan, bool offchan, |
| 2651 | unsigned int wait, const u8 *buf, size_t len, | 2683 | unsigned int wait, const u8 *buf, size_t len, |
| @@ -3351,4 +3383,5 @@ struct cfg80211_ops mac80211_config_ops = { | |||
| 3351 | .get_et_stats = ieee80211_get_et_stats, | 3383 | .get_et_stats = ieee80211_get_et_stats, |
| 3352 | .get_et_strings = ieee80211_get_et_strings, | 3384 | .get_et_strings = ieee80211_get_et_strings, |
| 3353 | .get_channel = ieee80211_cfg_get_channel, | 3385 | .get_channel = ieee80211_cfg_get_channel, |
| 3386 | .start_radar_detection = ieee80211_start_radar_detection, | ||
| 3354 | }; | 3387 | }; |
diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c index 038f249966d6..78c0d90dd641 100644 --- a/net/mac80211/chan.c +++ b/net/mac80211/chan.c | |||
| @@ -9,7 +9,7 @@ | |||
| 9 | #include "ieee80211_i.h" | 9 | #include "ieee80211_i.h" |
| 10 | #include "driver-ops.h" | 10 | #include "driver-ops.h" |
| 11 | 11 | ||
| 12 | static void ieee80211_change_chandef(struct ieee80211_local *local, | 12 | static void ieee80211_change_chanctx(struct ieee80211_local *local, |
| 13 | struct ieee80211_chanctx *ctx, | 13 | struct ieee80211_chanctx *ctx, |
| 14 | const struct cfg80211_chan_def *chandef) | 14 | const struct cfg80211_chan_def *chandef) |
| 15 | { | 15 | { |
| @@ -49,7 +49,7 @@ ieee80211_find_chanctx(struct ieee80211_local *local, | |||
| 49 | if (!compat) | 49 | if (!compat) |
| 50 | continue; | 50 | continue; |
| 51 | 51 | ||
| 52 | ieee80211_change_chandef(local, ctx, compat); | 52 | ieee80211_change_chanctx(local, ctx, compat); |
| 53 | 53 | ||
| 54 | return ctx; | 54 | return ctx; |
| 55 | } | 55 | } |
| @@ -137,7 +137,10 @@ static int ieee80211_assign_vif_chanctx(struct ieee80211_sub_if_data *sdata, | |||
| 137 | 137 | ||
| 138 | ieee80211_recalc_txpower(sdata); | 138 | ieee80211_recalc_txpower(sdata); |
| 139 | sdata->vif.bss_conf.idle = false; | 139 | sdata->vif.bss_conf.idle = false; |
| 140 | ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_IDLE); | 140 | |
| 141 | if (sdata->vif.type != NL80211_IFTYPE_P2P_DEVICE && | ||
| 142 | sdata->vif.type != NL80211_IFTYPE_MONITOR) | ||
| 143 | ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_IDLE); | ||
| 141 | 144 | ||
| 142 | return 0; | 145 | return 0; |
| 143 | } | 146 | } |
| @@ -172,7 +175,7 @@ static void ieee80211_recalc_chanctx_chantype(struct ieee80211_local *local, | |||
| 172 | if (WARN_ON_ONCE(!compat)) | 175 | if (WARN_ON_ONCE(!compat)) |
| 173 | return; | 176 | return; |
| 174 | 177 | ||
| 175 | ieee80211_change_chandef(local, ctx, compat); | 178 | ieee80211_change_chanctx(local, ctx, compat); |
| 176 | } | 179 | } |
| 177 | 180 | ||
| 178 | static void ieee80211_unassign_vif_chanctx(struct ieee80211_sub_if_data *sdata, | 181 | static void ieee80211_unassign_vif_chanctx(struct ieee80211_sub_if_data *sdata, |
| @@ -186,13 +189,17 @@ static void ieee80211_unassign_vif_chanctx(struct ieee80211_sub_if_data *sdata, | |||
| 186 | rcu_assign_pointer(sdata->vif.chanctx_conf, NULL); | 189 | rcu_assign_pointer(sdata->vif.chanctx_conf, NULL); |
| 187 | 190 | ||
| 188 | sdata->vif.bss_conf.idle = true; | 191 | sdata->vif.bss_conf.idle = true; |
| 189 | ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_IDLE); | 192 | |
| 193 | if (sdata->vif.type != NL80211_IFTYPE_P2P_DEVICE && | ||
| 194 | sdata->vif.type != NL80211_IFTYPE_MONITOR) | ||
| 195 | ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_IDLE); | ||
| 190 | 196 | ||
| 191 | drv_unassign_vif_chanctx(local, sdata, ctx); | 197 | drv_unassign_vif_chanctx(local, sdata, ctx); |
| 192 | 198 | ||
| 193 | if (ctx->refcount > 0) { | 199 | if (ctx->refcount > 0) { |
| 194 | ieee80211_recalc_chanctx_chantype(sdata->local, ctx); | 200 | ieee80211_recalc_chanctx_chantype(sdata->local, ctx); |
| 195 | ieee80211_recalc_smps_chanctx(local, ctx); | 201 | ieee80211_recalc_smps_chanctx(local, ctx); |
| 202 | ieee80211_recalc_radar_chanctx(local, ctx); | ||
| 196 | } | 203 | } |
| 197 | } | 204 | } |
| 198 | 205 | ||
| @@ -216,6 +223,37 @@ static void __ieee80211_vif_release_channel(struct ieee80211_sub_if_data *sdata) | |||
| 216 | ieee80211_free_chanctx(local, ctx); | 223 | ieee80211_free_chanctx(local, ctx); |
| 217 | } | 224 | } |
| 218 | 225 | ||
| 226 | void ieee80211_recalc_radar_chanctx(struct ieee80211_local *local, | ||
| 227 | struct ieee80211_chanctx *chanctx) | ||
| 228 | { | ||
| 229 | struct ieee80211_sub_if_data *sdata; | ||
| 230 | bool radar_enabled = false; | ||
| 231 | |||
| 232 | lockdep_assert_held(&local->chanctx_mtx); | ||
| 233 | |||
| 234 | rcu_read_lock(); | ||
| 235 | list_for_each_entry_rcu(sdata, &local->interfaces, list) { | ||
| 236 | if (sdata->radar_required) { | ||
| 237 | radar_enabled = true; | ||
| 238 | break; | ||
| 239 | } | ||
| 240 | } | ||
| 241 | rcu_read_unlock(); | ||
| 242 | |||
| 243 | if (radar_enabled == chanctx->conf.radar_enabled) | ||
| 244 | return; | ||
| 245 | |||
| 246 | chanctx->conf.radar_enabled = radar_enabled; | ||
| 247 | local->radar_detect_enabled = chanctx->conf.radar_enabled; | ||
| 248 | |||
| 249 | if (!local->use_chanctx) { | ||
| 250 | local->hw.conf.radar_enabled = chanctx->conf.radar_enabled; | ||
| 251 | ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL); | ||
| 252 | } | ||
| 253 | |||
| 254 | drv_change_chanctx(local, chanctx, IEEE80211_CHANCTX_CHANGE_RADAR); | ||
| 255 | } | ||
| 256 | |||
| 219 | void ieee80211_recalc_smps_chanctx(struct ieee80211_local *local, | 257 | void ieee80211_recalc_smps_chanctx(struct ieee80211_local *local, |
| 220 | struct ieee80211_chanctx *chanctx) | 258 | struct ieee80211_chanctx *chanctx) |
| 221 | { | 259 | { |
| @@ -331,6 +369,56 @@ int ieee80211_vif_use_channel(struct ieee80211_sub_if_data *sdata, | |||
| 331 | } | 369 | } |
| 332 | 370 | ||
| 333 | ieee80211_recalc_smps_chanctx(local, ctx); | 371 | ieee80211_recalc_smps_chanctx(local, ctx); |
| 372 | ieee80211_recalc_radar_chanctx(local, ctx); | ||
| 373 | out: | ||
| 374 | mutex_unlock(&local->chanctx_mtx); | ||
| 375 | return ret; | ||
| 376 | } | ||
| 377 | |||
| 378 | int ieee80211_vif_change_bandwidth(struct ieee80211_sub_if_data *sdata, | ||
| 379 | const struct cfg80211_chan_def *chandef, | ||
| 380 | u32 *changed) | ||
| 381 | { | ||
| 382 | struct ieee80211_local *local = sdata->local; | ||
| 383 | struct ieee80211_chanctx_conf *conf; | ||
| 384 | struct ieee80211_chanctx *ctx; | ||
| 385 | int ret; | ||
| 386 | |||
| 387 | if (!cfg80211_chandef_usable(sdata->local->hw.wiphy, chandef, | ||
| 388 | IEEE80211_CHAN_DISABLED)) | ||
| 389 | return -EINVAL; | ||
| 390 | |||
| 391 | mutex_lock(&local->chanctx_mtx); | ||
| 392 | if (cfg80211_chandef_identical(chandef, &sdata->vif.bss_conf.chandef)) { | ||
| 393 | ret = 0; | ||
| 394 | goto out; | ||
| 395 | } | ||
| 396 | |||
| 397 | if (chandef->width == NL80211_CHAN_WIDTH_20_NOHT || | ||
| 398 | sdata->vif.bss_conf.chandef.width == NL80211_CHAN_WIDTH_20_NOHT) { | ||
| 399 | ret = -EINVAL; | ||
| 400 | goto out; | ||
| 401 | } | ||
| 402 | |||
| 403 | conf = rcu_dereference_protected(sdata->vif.chanctx_conf, | ||
| 404 | lockdep_is_held(&local->chanctx_mtx)); | ||
| 405 | if (!conf) { | ||
| 406 | ret = -EINVAL; | ||
| 407 | goto out; | ||
| 408 | } | ||
| 409 | |||
| 410 | ctx = container_of(conf, struct ieee80211_chanctx, conf); | ||
| 411 | if (!cfg80211_chandef_compatible(&conf->def, chandef)) { | ||
| 412 | ret = -EINVAL; | ||
| 413 | goto out; | ||
| 414 | } | ||
| 415 | |||
| 416 | sdata->vif.bss_conf.chandef = *chandef; | ||
| 417 | |||
| 418 | ieee80211_recalc_chanctx_chantype(local, ctx); | ||
| 419 | |||
| 420 | *changed |= BSS_CHANGED_BANDWIDTH; | ||
| 421 | ret = 0; | ||
| 334 | out: | 422 | out: |
| 335 | mutex_unlock(&local->chanctx_mtx); | 423 | mutex_unlock(&local->chanctx_mtx); |
| 336 | return ret; | 424 | return ret; |
diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h index 2b08b9982d06..ee56d0779d8b 100644 --- a/net/mac80211/driver-ops.h +++ b/net/mac80211/driver-ops.h | |||
| @@ -207,13 +207,16 @@ static inline void drv_bss_info_changed(struct ieee80211_local *local, | |||
| 207 | { | 207 | { |
| 208 | might_sleep(); | 208 | might_sleep(); |
| 209 | 209 | ||
| 210 | WARN_ON_ONCE(changed & (BSS_CHANGED_BEACON | | 210 | if (WARN_ON_ONCE(changed & (BSS_CHANGED_BEACON | |
| 211 | BSS_CHANGED_BEACON_ENABLED) && | 211 | BSS_CHANGED_BEACON_ENABLED) && |
| 212 | sdata->vif.type != NL80211_IFTYPE_AP && | 212 | sdata->vif.type != NL80211_IFTYPE_AP && |
| 213 | sdata->vif.type != NL80211_IFTYPE_ADHOC && | 213 | sdata->vif.type != NL80211_IFTYPE_ADHOC && |
| 214 | sdata->vif.type != NL80211_IFTYPE_MESH_POINT); | 214 | sdata->vif.type != NL80211_IFTYPE_MESH_POINT)) |
| 215 | WARN_ON_ONCE(sdata->vif.type == NL80211_IFTYPE_P2P_DEVICE && | 215 | return; |
| 216 | changed & ~BSS_CHANGED_IDLE); | 216 | |
| 217 | if (WARN_ON_ONCE(sdata->vif.type == NL80211_IFTYPE_P2P_DEVICE || | ||
| 218 | sdata->vif.type == NL80211_IFTYPE_MONITOR)) | ||
| 219 | return; | ||
| 217 | 220 | ||
| 218 | check_sdata_in_driver(sdata); | 221 | check_sdata_in_driver(sdata); |
| 219 | 222 | ||
diff --git a/net/mac80211/ht.c b/net/mac80211/ht.c index 61ac7c48ac0c..0db25d4bb223 100644 --- a/net/mac80211/ht.c +++ b/net/mac80211/ht.c | |||
| @@ -37,6 +37,9 @@ void ieee80211_apply_htcap_overrides(struct ieee80211_sub_if_data *sdata, | |||
| 37 | u8 *smask = (u8 *)(&sdata->u.mgd.ht_capa_mask.mcs.rx_mask); | 37 | u8 *smask = (u8 *)(&sdata->u.mgd.ht_capa_mask.mcs.rx_mask); |
| 38 | int i; | 38 | int i; |
| 39 | 39 | ||
| 40 | if (!ht_cap->ht_supported) | ||
| 41 | return; | ||
| 42 | |||
| 40 | if (sdata->vif.type != NL80211_IFTYPE_STATION) { | 43 | if (sdata->vif.type != NL80211_IFTYPE_STATION) { |
| 41 | /* AP interfaces call this code when adding new stations, | 44 | /* AP interfaces call this code when adding new stations, |
| 42 | * so just silently ignore non station interfaces. | 45 | * so just silently ignore non station interfaces. |
| @@ -89,22 +92,24 @@ void ieee80211_apply_htcap_overrides(struct ieee80211_sub_if_data *sdata, | |||
| 89 | } | 92 | } |
| 90 | 93 | ||
| 91 | 94 | ||
| 92 | void ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_sub_if_data *sdata, | 95 | bool ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_sub_if_data *sdata, |
| 93 | struct ieee80211_supported_band *sband, | 96 | struct ieee80211_supported_band *sband, |
| 94 | struct ieee80211_ht_cap *ht_cap_ie, | 97 | const struct ieee80211_ht_cap *ht_cap_ie, |
| 95 | struct ieee80211_sta_ht_cap *ht_cap) | 98 | struct sta_info *sta) |
| 96 | { | 99 | { |
| 100 | struct ieee80211_sta_ht_cap ht_cap; | ||
| 97 | u8 ampdu_info, tx_mcs_set_cap; | 101 | u8 ampdu_info, tx_mcs_set_cap; |
| 98 | int i, max_tx_streams; | 102 | int i, max_tx_streams; |
| 103 | bool changed; | ||
| 104 | enum ieee80211_sta_rx_bandwidth bw; | ||
| 105 | enum ieee80211_smps_mode smps_mode; | ||
| 99 | 106 | ||
| 100 | BUG_ON(!ht_cap); | 107 | memset(&ht_cap, 0, sizeof(ht_cap)); |
| 101 | |||
| 102 | memset(ht_cap, 0, sizeof(*ht_cap)); | ||
| 103 | 108 | ||
| 104 | if (!ht_cap_ie || !sband->ht_cap.ht_supported) | 109 | if (!ht_cap_ie || !sband->ht_cap.ht_supported) |
| 105 | return; | 110 | goto apply; |
| 106 | 111 | ||
| 107 | ht_cap->ht_supported = true; | 112 | ht_cap.ht_supported = true; |
| 108 | 113 | ||
| 109 | /* | 114 | /* |
| 110 | * The bits listed in this expression should be | 115 | * The bits listed in this expression should be |
| @@ -112,7 +117,7 @@ void ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_sub_if_data *sdata, | |||
| 112 | * advertises more then we can't use those thus | 117 | * advertises more then we can't use those thus |
| 113 | * we mask them out. | 118 | * we mask them out. |
| 114 | */ | 119 | */ |
| 115 | ht_cap->cap = le16_to_cpu(ht_cap_ie->cap_info) & | 120 | ht_cap.cap = le16_to_cpu(ht_cap_ie->cap_info) & |
| 116 | (sband->ht_cap.cap | | 121 | (sband->ht_cap.cap | |
| 117 | ~(IEEE80211_HT_CAP_LDPC_CODING | | 122 | ~(IEEE80211_HT_CAP_LDPC_CODING | |
| 118 | IEEE80211_HT_CAP_SUP_WIDTH_20_40 | | 123 | IEEE80211_HT_CAP_SUP_WIDTH_20_40 | |
| @@ -121,44 +126,30 @@ void ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_sub_if_data *sdata, | |||
| 121 | IEEE80211_HT_CAP_SGI_40 | | 126 | IEEE80211_HT_CAP_SGI_40 | |
| 122 | IEEE80211_HT_CAP_DSSSCCK40)); | 127 | IEEE80211_HT_CAP_DSSSCCK40)); |
| 123 | 128 | ||
| 124 | /* Unset 40 MHz if we're not using a 40 MHz channel */ | ||
| 125 | switch (sdata->vif.bss_conf.chandef.width) { | ||
| 126 | case NL80211_CHAN_WIDTH_20_NOHT: | ||
| 127 | case NL80211_CHAN_WIDTH_20: | ||
| 128 | ht_cap->cap &= ~IEEE80211_HT_CAP_SGI_40; | ||
| 129 | ht_cap->cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40; | ||
| 130 | break; | ||
| 131 | case NL80211_CHAN_WIDTH_40: | ||
| 132 | case NL80211_CHAN_WIDTH_80: | ||
| 133 | case NL80211_CHAN_WIDTH_80P80: | ||
| 134 | case NL80211_CHAN_WIDTH_160: | ||
| 135 | break; | ||
| 136 | } | ||
| 137 | |||
| 138 | /* | 129 | /* |
| 139 | * The STBC bits are asymmetric -- if we don't have | 130 | * The STBC bits are asymmetric -- if we don't have |
| 140 | * TX then mask out the peer's RX and vice versa. | 131 | * TX then mask out the peer's RX and vice versa. |
| 141 | */ | 132 | */ |
| 142 | if (!(sband->ht_cap.cap & IEEE80211_HT_CAP_TX_STBC)) | 133 | if (!(sband->ht_cap.cap & IEEE80211_HT_CAP_TX_STBC)) |
| 143 | ht_cap->cap &= ~IEEE80211_HT_CAP_RX_STBC; | 134 | ht_cap.cap &= ~IEEE80211_HT_CAP_RX_STBC; |
| 144 | if (!(sband->ht_cap.cap & IEEE80211_HT_CAP_RX_STBC)) | 135 | if (!(sband->ht_cap.cap & IEEE80211_HT_CAP_RX_STBC)) |
| 145 | ht_cap->cap &= ~IEEE80211_HT_CAP_TX_STBC; | 136 | ht_cap.cap &= ~IEEE80211_HT_CAP_TX_STBC; |
| 146 | 137 | ||
| 147 | ampdu_info = ht_cap_ie->ampdu_params_info; | 138 | ampdu_info = ht_cap_ie->ampdu_params_info; |
| 148 | ht_cap->ampdu_factor = | 139 | ht_cap.ampdu_factor = |
| 149 | ampdu_info & IEEE80211_HT_AMPDU_PARM_FACTOR; | 140 | ampdu_info & IEEE80211_HT_AMPDU_PARM_FACTOR; |
| 150 | ht_cap->ampdu_density = | 141 | ht_cap.ampdu_density = |
| 151 | (ampdu_info & IEEE80211_HT_AMPDU_PARM_DENSITY) >> 2; | 142 | (ampdu_info & IEEE80211_HT_AMPDU_PARM_DENSITY) >> 2; |
| 152 | 143 | ||
| 153 | /* own MCS TX capabilities */ | 144 | /* own MCS TX capabilities */ |
| 154 | tx_mcs_set_cap = sband->ht_cap.mcs.tx_params; | 145 | tx_mcs_set_cap = sband->ht_cap.mcs.tx_params; |
| 155 | 146 | ||
| 156 | /* Copy peer MCS TX capabilities, the driver might need them. */ | 147 | /* Copy peer MCS TX capabilities, the driver might need them. */ |
| 157 | ht_cap->mcs.tx_params = ht_cap_ie->mcs.tx_params; | 148 | ht_cap.mcs.tx_params = ht_cap_ie->mcs.tx_params; |
| 158 | 149 | ||
| 159 | /* can we TX with MCS rates? */ | 150 | /* can we TX with MCS rates? */ |
| 160 | if (!(tx_mcs_set_cap & IEEE80211_HT_MCS_TX_DEFINED)) | 151 | if (!(tx_mcs_set_cap & IEEE80211_HT_MCS_TX_DEFINED)) |
| 161 | return; | 152 | goto apply; |
| 162 | 153 | ||
| 163 | /* Counting from 0, therefore +1 */ | 154 | /* Counting from 0, therefore +1 */ |
| 164 | if (tx_mcs_set_cap & IEEE80211_HT_MCS_TX_RX_DIFF) | 155 | if (tx_mcs_set_cap & IEEE80211_HT_MCS_TX_RX_DIFF) |
| @@ -176,25 +167,75 @@ void ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_sub_if_data *sdata, | |||
| 176 | * - remainder are multiple spatial streams using unequal modulation | 167 | * - remainder are multiple spatial streams using unequal modulation |
| 177 | */ | 168 | */ |
| 178 | for (i = 0; i < max_tx_streams; i++) | 169 | for (i = 0; i < max_tx_streams; i++) |
| 179 | ht_cap->mcs.rx_mask[i] = | 170 | ht_cap.mcs.rx_mask[i] = |
| 180 | sband->ht_cap.mcs.rx_mask[i] & ht_cap_ie->mcs.rx_mask[i]; | 171 | sband->ht_cap.mcs.rx_mask[i] & ht_cap_ie->mcs.rx_mask[i]; |
| 181 | 172 | ||
| 182 | if (tx_mcs_set_cap & IEEE80211_HT_MCS_TX_UNEQUAL_MODULATION) | 173 | if (tx_mcs_set_cap & IEEE80211_HT_MCS_TX_UNEQUAL_MODULATION) |
| 183 | for (i = IEEE80211_HT_MCS_UNEQUAL_MODULATION_START_BYTE; | 174 | for (i = IEEE80211_HT_MCS_UNEQUAL_MODULATION_START_BYTE; |
| 184 | i < IEEE80211_HT_MCS_MASK_LEN; i++) | 175 | i < IEEE80211_HT_MCS_MASK_LEN; i++) |
| 185 | ht_cap->mcs.rx_mask[i] = | 176 | ht_cap.mcs.rx_mask[i] = |
| 186 | sband->ht_cap.mcs.rx_mask[i] & | 177 | sband->ht_cap.mcs.rx_mask[i] & |
| 187 | ht_cap_ie->mcs.rx_mask[i]; | 178 | ht_cap_ie->mcs.rx_mask[i]; |
| 188 | 179 | ||
| 189 | /* handle MCS rate 32 too */ | 180 | /* handle MCS rate 32 too */ |
| 190 | if (sband->ht_cap.mcs.rx_mask[32/8] & ht_cap_ie->mcs.rx_mask[32/8] & 1) | 181 | if (sband->ht_cap.mcs.rx_mask[32/8] & ht_cap_ie->mcs.rx_mask[32/8] & 1) |
| 191 | ht_cap->mcs.rx_mask[32/8] |= 1; | 182 | ht_cap.mcs.rx_mask[32/8] |= 1; |
| 192 | 183 | ||
| 184 | apply: | ||
| 193 | /* | 185 | /* |
| 194 | * If user has specified capability over-rides, take care | 186 | * If user has specified capability over-rides, take care |
| 195 | * of that here. | 187 | * of that here. |
| 196 | */ | 188 | */ |
| 197 | ieee80211_apply_htcap_overrides(sdata, ht_cap); | 189 | ieee80211_apply_htcap_overrides(sdata, &ht_cap); |
| 190 | |||
| 191 | changed = memcmp(&sta->sta.ht_cap, &ht_cap, sizeof(ht_cap)); | ||
| 192 | |||
| 193 | memcpy(&sta->sta.ht_cap, &ht_cap, sizeof(ht_cap)); | ||
| 194 | |||
| 195 | switch (sdata->vif.bss_conf.chandef.width) { | ||
| 196 | default: | ||
| 197 | WARN_ON_ONCE(1); | ||
| 198 | /* fall through */ | ||
| 199 | case NL80211_CHAN_WIDTH_20_NOHT: | ||
| 200 | case NL80211_CHAN_WIDTH_20: | ||
| 201 | bw = IEEE80211_STA_RX_BW_20; | ||
| 202 | break; | ||
| 203 | case NL80211_CHAN_WIDTH_40: | ||
| 204 | case NL80211_CHAN_WIDTH_80: | ||
| 205 | case NL80211_CHAN_WIDTH_80P80: | ||
| 206 | case NL80211_CHAN_WIDTH_160: | ||
| 207 | bw = ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40 ? | ||
| 208 | IEEE80211_STA_RX_BW_40 : IEEE80211_STA_RX_BW_20; | ||
| 209 | break; | ||
| 210 | } | ||
| 211 | |||
| 212 | if (bw != sta->sta.bandwidth) | ||
| 213 | changed = true; | ||
| 214 | sta->sta.bandwidth = bw; | ||
| 215 | |||
| 216 | sta->cur_max_bandwidth = | ||
| 217 | ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40 ? | ||
| 218 | IEEE80211_STA_RX_BW_40 : IEEE80211_STA_RX_BW_20; | ||
| 219 | |||
| 220 | switch ((ht_cap.cap & IEEE80211_HT_CAP_SM_PS) | ||
| 221 | >> IEEE80211_HT_CAP_SM_PS_SHIFT) { | ||
| 222 | case WLAN_HT_CAP_SM_PS_INVALID: | ||
| 223 | case WLAN_HT_CAP_SM_PS_STATIC: | ||
| 224 | smps_mode = IEEE80211_SMPS_STATIC; | ||
| 225 | break; | ||
| 226 | case WLAN_HT_CAP_SM_PS_DYNAMIC: | ||
| 227 | smps_mode = IEEE80211_SMPS_DYNAMIC; | ||
| 228 | break; | ||
| 229 | case WLAN_HT_CAP_SM_PS_DISABLED: | ||
| 230 | smps_mode = IEEE80211_SMPS_OFF; | ||
| 231 | break; | ||
| 232 | } | ||
| 233 | |||
| 234 | if (smps_mode != sta->sta.smps_mode) | ||
| 235 | changed = true; | ||
| 236 | sta->sta.smps_mode = smps_mode; | ||
| 237 | |||
| 238 | return changed; | ||
| 198 | } | 239 | } |
| 199 | 240 | ||
| 200 | void ieee80211_sta_tear_down_BA_sessions(struct sta_info *sta, | 241 | void ieee80211_sta_tear_down_BA_sessions(struct sta_info *sta, |
| @@ -406,6 +447,9 @@ void ieee80211_request_smps(struct ieee80211_vif *vif, | |||
| 406 | if (WARN_ON(smps_mode == IEEE80211_SMPS_OFF)) | 447 | if (WARN_ON(smps_mode == IEEE80211_SMPS_OFF)) |
| 407 | smps_mode = IEEE80211_SMPS_AUTOMATIC; | 448 | smps_mode = IEEE80211_SMPS_AUTOMATIC; |
| 408 | 449 | ||
| 450 | if (sdata->u.mgd.driver_smps_mode == smps_mode) | ||
| 451 | return; | ||
| 452 | |||
| 409 | sdata->u.mgd.driver_smps_mode = smps_mode; | 453 | sdata->u.mgd.driver_smps_mode = smps_mode; |
| 410 | 454 | ||
| 411 | ieee80211_queue_work(&sdata->local->hw, | 455 | ieee80211_queue_work(&sdata->local->hw, |
diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c index 2db1f2b90bfe..40b71dfcc79d 100644 --- a/net/mac80211/ibss.c +++ b/net/mac80211/ibss.c | |||
| @@ -496,33 +496,26 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, | |||
| 496 | if (sta && elems->ht_operation && elems->ht_cap_elem && | 496 | if (sta && elems->ht_operation && elems->ht_cap_elem && |
| 497 | sdata->u.ibss.channel_type != NL80211_CHAN_NO_HT) { | 497 | sdata->u.ibss.channel_type != NL80211_CHAN_NO_HT) { |
| 498 | /* we both use HT */ | 498 | /* we both use HT */ |
| 499 | struct ieee80211_sta_ht_cap sta_ht_cap_new; | 499 | struct ieee80211_ht_cap htcap_ie; |
| 500 | struct cfg80211_chan_def chandef; | 500 | struct cfg80211_chan_def chandef; |
| 501 | 501 | ||
| 502 | ieee80211_ht_oper_to_chandef(channel, | 502 | ieee80211_ht_oper_to_chandef(channel, |
| 503 | elems->ht_operation, | 503 | elems->ht_operation, |
| 504 | &chandef); | 504 | &chandef); |
| 505 | 505 | ||
| 506 | ieee80211_ht_cap_ie_to_sta_ht_cap(sdata, sband, | 506 | memcpy(&htcap_ie, elems->ht_cap_elem, sizeof(htcap_ie)); |
| 507 | elems->ht_cap_elem, | ||
| 508 | &sta_ht_cap_new); | ||
| 509 | 507 | ||
| 510 | /* | 508 | /* |
| 511 | * fall back to HT20 if we don't use or use | 509 | * fall back to HT20 if we don't use or use |
| 512 | * the other extension channel | 510 | * the other extension channel |
| 513 | */ | 511 | */ |
| 514 | if (chandef.width != NL80211_CHAN_WIDTH_40 || | 512 | if (cfg80211_get_chandef_type(&chandef) != |
| 515 | cfg80211_get_chandef_type(&chandef) != | ||
| 516 | sdata->u.ibss.channel_type) | 513 | sdata->u.ibss.channel_type) |
| 517 | sta_ht_cap_new.cap &= | 514 | htcap_ie.cap_info &= |
| 518 | ~IEEE80211_HT_CAP_SUP_WIDTH_20_40; | 515 | cpu_to_le16(~IEEE80211_HT_CAP_SUP_WIDTH_20_40); |
| 519 | 516 | ||
| 520 | if (memcmp(&sta->sta.ht_cap, &sta_ht_cap_new, | 517 | rates_updated |= ieee80211_ht_cap_ie_to_sta_ht_cap( |
| 521 | sizeof(sta_ht_cap_new))) { | 518 | sdata, sband, &htcap_ie, sta); |
| 522 | memcpy(&sta->sta.ht_cap, &sta_ht_cap_new, | ||
| 523 | sizeof(sta_ht_cap_new)); | ||
| 524 | rates_updated = true; | ||
| 525 | } | ||
| 526 | } | 519 | } |
| 527 | 520 | ||
| 528 | if (sta && rates_updated) { | 521 | if (sta && rates_updated) { |
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 76cdcfcd614c..388580a1bada 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h | |||
| @@ -343,6 +343,7 @@ struct ieee80211_mgd_auth_data { | |||
| 343 | u8 key[WLAN_KEY_LEN_WEP104]; | 343 | u8 key[WLAN_KEY_LEN_WEP104]; |
| 344 | u8 key_len, key_idx; | 344 | u8 key_len, key_idx; |
| 345 | bool done; | 345 | bool done; |
| 346 | bool timeout_started; | ||
| 346 | 347 | ||
| 347 | u16 sae_trans, sae_status; | 348 | u16 sae_trans, sae_status; |
| 348 | size_t data_len; | 349 | size_t data_len; |
| @@ -364,6 +365,7 @@ struct ieee80211_mgd_assoc_data { | |||
| 364 | bool wmm, uapsd; | 365 | bool wmm, uapsd; |
| 365 | bool have_beacon, need_beacon; | 366 | bool have_beacon, need_beacon; |
| 366 | bool synced; | 367 | bool synced; |
| 368 | bool timeout_started; | ||
| 367 | 369 | ||
| 368 | u8 ap_ht_param; | 370 | u8 ap_ht_param; |
| 369 | 371 | ||
| @@ -578,6 +580,9 @@ struct ieee80211_if_mesh { | |||
| 578 | u32 mesh_seqnum; | 580 | u32 mesh_seqnum; |
| 579 | bool accepting_plinks; | 581 | bool accepting_plinks; |
| 580 | int num_gates; | 582 | int num_gates; |
| 583 | struct beacon_data __rcu *beacon; | ||
| 584 | /* just protects beacon updates for now */ | ||
| 585 | struct mutex mtx; | ||
| 581 | const u8 *ie; | 586 | const u8 *ie; |
| 582 | u8 ie_len; | 587 | u8 ie_len; |
| 583 | enum { | 588 | enum { |
| @@ -722,6 +727,9 @@ struct ieee80211_sub_if_data { | |||
| 722 | int user_power_level; /* in dBm */ | 727 | int user_power_level; /* in dBm */ |
| 723 | int ap_power_level; /* in dBm */ | 728 | int ap_power_level; /* in dBm */ |
| 724 | 729 | ||
| 730 | bool radar_required; | ||
| 731 | struct delayed_work dfs_cac_timer_work; | ||
| 732 | |||
| 725 | /* | 733 | /* |
| 726 | * AP this belongs to: self in AP mode and | 734 | * AP this belongs to: self in AP mode and |
| 727 | * corresponding AP in VLAN mode, NULL for | 735 | * corresponding AP in VLAN mode, NULL for |
| @@ -942,6 +950,10 @@ struct ieee80211_local { | |||
| 942 | /* wowlan is enabled -- don't reconfig on resume */ | 950 | /* wowlan is enabled -- don't reconfig on resume */ |
| 943 | bool wowlan; | 951 | bool wowlan; |
| 944 | 952 | ||
| 953 | /* DFS/radar detection is enabled */ | ||
| 954 | bool radar_detect_enabled; | ||
| 955 | struct work_struct radar_detected_work; | ||
| 956 | |||
| 945 | /* number of RX chains the hardware has */ | 957 | /* number of RX chains the hardware has */ |
| 946 | u8 rx_chains; | 958 | u8 rx_chains; |
| 947 | 959 | ||
| @@ -1154,41 +1166,41 @@ struct ieee80211_ra_tid { | |||
| 1154 | 1166 | ||
| 1155 | /* Parsed Information Elements */ | 1167 | /* Parsed Information Elements */ |
| 1156 | struct ieee802_11_elems { | 1168 | struct ieee802_11_elems { |
| 1157 | u8 *ie_start; | 1169 | const u8 *ie_start; |
| 1158 | size_t total_len; | 1170 | size_t total_len; |
| 1159 | 1171 | ||
| 1160 | /* pointers to IEs */ | 1172 | /* pointers to IEs */ |
| 1161 | u8 *ssid; | 1173 | const u8 *ssid; |
| 1162 | u8 *supp_rates; | 1174 | const u8 *supp_rates; |
| 1163 | u8 *fh_params; | 1175 | const u8 *fh_params; |
| 1164 | u8 *ds_params; | 1176 | const u8 *ds_params; |
| 1165 | u8 *cf_params; | 1177 | const u8 *cf_params; |
| 1166 | struct ieee80211_tim_ie *tim; | 1178 | const struct ieee80211_tim_ie *tim; |
| 1167 | u8 *ibss_params; | 1179 | const u8 *ibss_params; |
| 1168 | u8 *challenge; | 1180 | const u8 *challenge; |
| 1169 | u8 *wpa; | 1181 | const u8 *rsn; |
| 1170 | u8 *rsn; | 1182 | const u8 *erp_info; |
| 1171 | u8 *erp_info; | 1183 | const u8 *ext_supp_rates; |
| 1172 | u8 *ext_supp_rates; | 1184 | const u8 *wmm_info; |
| 1173 | u8 *wmm_info; | 1185 | const u8 *wmm_param; |
| 1174 | u8 *wmm_param; | 1186 | const struct ieee80211_ht_cap *ht_cap_elem; |
| 1175 | struct ieee80211_ht_cap *ht_cap_elem; | 1187 | const struct ieee80211_ht_operation *ht_operation; |
| 1176 | struct ieee80211_ht_operation *ht_operation; | 1188 | const struct ieee80211_vht_cap *vht_cap_elem; |
| 1177 | struct ieee80211_vht_cap *vht_cap_elem; | 1189 | const struct ieee80211_vht_operation *vht_operation; |
| 1178 | struct ieee80211_vht_operation *vht_operation; | 1190 | const struct ieee80211_meshconf_ie *mesh_config; |
| 1179 | struct ieee80211_meshconf_ie *mesh_config; | 1191 | const u8 *mesh_id; |
| 1180 | u8 *mesh_id; | 1192 | const u8 *peering; |
| 1181 | u8 *peering; | 1193 | const __le16 *awake_window; |
| 1182 | __le16 *awake_window; | 1194 | const u8 *preq; |
| 1183 | u8 *preq; | 1195 | const u8 *prep; |
| 1184 | u8 *prep; | 1196 | const u8 *perr; |
| 1185 | u8 *perr; | 1197 | const struct ieee80211_rann_ie *rann; |
| 1186 | struct ieee80211_rann_ie *rann; | 1198 | const struct ieee80211_channel_sw_ie *ch_switch_ie; |
| 1187 | struct ieee80211_channel_sw_ie *ch_switch_ie; | 1199 | const u8 *country_elem; |
| 1188 | u8 *country_elem; | 1200 | const u8 *pwr_constr_elem; |
| 1189 | u8 *pwr_constr_elem; | 1201 | const u8 *quiet_elem; /* first quite element */ |
| 1190 | u8 *quiet_elem; /* first quite element */ | 1202 | const u8 *timeout_int; |
| 1191 | u8 *timeout_int; | 1203 | const u8 *opmode_notif; |
| 1192 | 1204 | ||
| 1193 | /* length of them, respectively */ | 1205 | /* length of them, respectively */ |
| 1194 | u8 ssid_len; | 1206 | u8 ssid_len; |
| @@ -1199,7 +1211,6 @@ struct ieee802_11_elems { | |||
| 1199 | u8 tim_len; | 1211 | u8 tim_len; |
| 1200 | u8 ibss_params_len; | 1212 | u8 ibss_params_len; |
| 1201 | u8 challenge_len; | 1213 | u8 challenge_len; |
| 1202 | u8 wpa_len; | ||
| 1203 | u8 rsn_len; | 1214 | u8 rsn_len; |
| 1204 | u8 erp_info_len; | 1215 | u8 erp_info_len; |
| 1205 | u8 ext_supp_rates_len; | 1216 | u8 ext_supp_rates_len; |
| @@ -1268,10 +1279,10 @@ void ieee80211_recalc_ps_vif(struct ieee80211_sub_if_data *sdata); | |||
| 1268 | int ieee80211_max_network_latency(struct notifier_block *nb, | 1279 | int ieee80211_max_network_latency(struct notifier_block *nb, |
| 1269 | unsigned long data, void *dummy); | 1280 | unsigned long data, void *dummy); |
| 1270 | int ieee80211_set_arp_filter(struct ieee80211_sub_if_data *sdata); | 1281 | int ieee80211_set_arp_filter(struct ieee80211_sub_if_data *sdata); |
| 1271 | void ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata, | 1282 | void |
| 1272 | struct ieee80211_channel_sw_ie *sw_elem, | 1283 | ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata, |
| 1273 | struct ieee80211_bss *bss, | 1284 | const struct ieee80211_channel_sw_ie *sw_elem, |
| 1274 | u64 timestamp); | 1285 | struct ieee80211_bss *bss, u64 timestamp); |
| 1275 | void ieee80211_sta_quiesce(struct ieee80211_sub_if_data *sdata); | 1286 | void ieee80211_sta_quiesce(struct ieee80211_sub_if_data *sdata); |
| 1276 | void ieee80211_sta_restart(struct ieee80211_sub_if_data *sdata); | 1287 | void ieee80211_sta_restart(struct ieee80211_sub_if_data *sdata); |
| 1277 | void ieee80211_sta_work(struct ieee80211_sub_if_data *sdata); | 1288 | void ieee80211_sta_work(struct ieee80211_sub_if_data *sdata); |
| @@ -1377,10 +1388,10 @@ void ieee80211_purge_tx_queue(struct ieee80211_hw *hw, | |||
| 1377 | /* HT */ | 1388 | /* HT */ |
| 1378 | void ieee80211_apply_htcap_overrides(struct ieee80211_sub_if_data *sdata, | 1389 | void ieee80211_apply_htcap_overrides(struct ieee80211_sub_if_data *sdata, |
| 1379 | struct ieee80211_sta_ht_cap *ht_cap); | 1390 | struct ieee80211_sta_ht_cap *ht_cap); |
| 1380 | void ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_sub_if_data *sdata, | 1391 | bool ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_sub_if_data *sdata, |
| 1381 | struct ieee80211_supported_band *sband, | 1392 | struct ieee80211_supported_band *sband, |
| 1382 | struct ieee80211_ht_cap *ht_cap_ie, | 1393 | const struct ieee80211_ht_cap *ht_cap_ie, |
| 1383 | struct ieee80211_sta_ht_cap *ht_cap); | 1394 | struct sta_info *sta); |
| 1384 | void ieee80211_send_delba(struct ieee80211_sub_if_data *sdata, | 1395 | void ieee80211_send_delba(struct ieee80211_sub_if_data *sdata, |
| 1385 | const u8 *da, u16 tid, | 1396 | const u8 *da, u16 tid, |
| 1386 | u16 initiator, u16 reason_code); | 1397 | u16 initiator, u16 reason_code); |
| @@ -1420,10 +1431,17 @@ void ieee80211_release_reorder_timeout(struct sta_info *sta, int tid); | |||
| 1420 | u8 ieee80211_mcs_to_chains(const struct ieee80211_mcs_info *mcs); | 1431 | u8 ieee80211_mcs_to_chains(const struct ieee80211_mcs_info *mcs); |
| 1421 | 1432 | ||
| 1422 | /* VHT */ | 1433 | /* VHT */ |
| 1423 | void ieee80211_vht_cap_ie_to_sta_vht_cap(struct ieee80211_sub_if_data *sdata, | 1434 | void |
| 1424 | struct ieee80211_supported_band *sband, | 1435 | ieee80211_vht_cap_ie_to_sta_vht_cap(struct ieee80211_sub_if_data *sdata, |
| 1425 | struct ieee80211_vht_cap *vht_cap_ie, | 1436 | struct ieee80211_supported_band *sband, |
| 1426 | struct ieee80211_sta_vht_cap *vht_cap); | 1437 | const struct ieee80211_vht_cap *vht_cap_ie, |
| 1438 | struct sta_info *sta); | ||
| 1439 | enum ieee80211_sta_rx_bandwidth ieee80211_sta_cur_vht_bw(struct sta_info *sta); | ||
| 1440 | void ieee80211_sta_set_rx_nss(struct sta_info *sta); | ||
| 1441 | void ieee80211_vht_handle_opmode(struct ieee80211_sub_if_data *sdata, | ||
| 1442 | struct sta_info *sta, u8 opmode, | ||
| 1443 | enum ieee80211_band band, bool nss_only); | ||
| 1444 | |||
| 1427 | /* Spectrum management */ | 1445 | /* Spectrum management */ |
| 1428 | void ieee80211_process_measurement_req(struct ieee80211_sub_if_data *sdata, | 1446 | void ieee80211_process_measurement_req(struct ieee80211_sub_if_data *sdata, |
| 1429 | struct ieee80211_mgmt *mgmt, | 1447 | struct ieee80211_mgmt *mgmt, |
| @@ -1541,7 +1559,7 @@ static inline void ieee80211_add_pending_skbs(struct ieee80211_local *local, | |||
| 1541 | 1559 | ||
| 1542 | void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata, | 1560 | void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata, |
| 1543 | u16 transaction, u16 auth_alg, u16 status, | 1561 | u16 transaction, u16 auth_alg, u16 status, |
| 1544 | u8 *extra, size_t extra_len, const u8 *bssid, | 1562 | const u8 *extra, size_t extra_len, const u8 *bssid, |
| 1545 | const u8 *da, const u8 *key, u8 key_len, u8 key_idx, | 1563 | const u8 *da, const u8 *key, u8 key_len, u8 key_idx, |
| 1546 | u32 tx_flags); | 1564 | u32 tx_flags); |
| 1547 | void ieee80211_send_deauth_disassoc(struct ieee80211_sub_if_data *sdata, | 1565 | void ieee80211_send_deauth_disassoc(struct ieee80211_sub_if_data *sdata, |
| @@ -1592,13 +1610,17 @@ int ieee80211_add_ext_srates_ie(struct ieee80211_sub_if_data *sdata, | |||
| 1592 | 1610 | ||
| 1593 | /* channel management */ | 1611 | /* channel management */ |
| 1594 | void ieee80211_ht_oper_to_chandef(struct ieee80211_channel *control_chan, | 1612 | void ieee80211_ht_oper_to_chandef(struct ieee80211_channel *control_chan, |
| 1595 | struct ieee80211_ht_operation *ht_oper, | 1613 | const struct ieee80211_ht_operation *ht_oper, |
| 1596 | struct cfg80211_chan_def *chandef); | 1614 | struct cfg80211_chan_def *chandef); |
| 1597 | 1615 | ||
| 1598 | int __must_check | 1616 | int __must_check |
| 1599 | ieee80211_vif_use_channel(struct ieee80211_sub_if_data *sdata, | 1617 | ieee80211_vif_use_channel(struct ieee80211_sub_if_data *sdata, |
| 1600 | const struct cfg80211_chan_def *chandef, | 1618 | const struct cfg80211_chan_def *chandef, |
| 1601 | enum ieee80211_chanctx_mode mode); | 1619 | enum ieee80211_chanctx_mode mode); |
| 1620 | int __must_check | ||
| 1621 | ieee80211_vif_change_bandwidth(struct ieee80211_sub_if_data *sdata, | ||
| 1622 | const struct cfg80211_chan_def *chandef, | ||
| 1623 | u32 *changed); | ||
| 1602 | void ieee80211_vif_release_channel(struct ieee80211_sub_if_data *sdata); | 1624 | void ieee80211_vif_release_channel(struct ieee80211_sub_if_data *sdata); |
| 1603 | void ieee80211_vif_vlan_copy_chanctx(struct ieee80211_sub_if_data *sdata); | 1625 | void ieee80211_vif_vlan_copy_chanctx(struct ieee80211_sub_if_data *sdata); |
| 1604 | void ieee80211_vif_copy_chanctx_to_vlans(struct ieee80211_sub_if_data *sdata, | 1626 | void ieee80211_vif_copy_chanctx_to_vlans(struct ieee80211_sub_if_data *sdata, |
| @@ -1606,6 +1628,13 @@ void ieee80211_vif_copy_chanctx_to_vlans(struct ieee80211_sub_if_data *sdata, | |||
| 1606 | 1628 | ||
| 1607 | void ieee80211_recalc_smps_chanctx(struct ieee80211_local *local, | 1629 | void ieee80211_recalc_smps_chanctx(struct ieee80211_local *local, |
| 1608 | struct ieee80211_chanctx *chanctx); | 1630 | struct ieee80211_chanctx *chanctx); |
| 1631 | void ieee80211_recalc_radar_chanctx(struct ieee80211_local *local, | ||
| 1632 | struct ieee80211_chanctx *chanctx); | ||
| 1633 | |||
| 1634 | void ieee80211_dfs_cac_timer(unsigned long data); | ||
| 1635 | void ieee80211_dfs_cac_timer_work(struct work_struct *work); | ||
| 1636 | void ieee80211_dfs_cac_cancel(struct ieee80211_local *local); | ||
| 1637 | void ieee80211_dfs_radar_detected_work(struct work_struct *work); | ||
| 1609 | 1638 | ||
| 1610 | #ifdef CONFIG_MAC80211_NOINLINE | 1639 | #ifdef CONFIG_MAC80211_NOINLINE |
| 1611 | #define debug_noinline noinline | 1640 | #define debug_noinline noinline |
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index 40ff0307d089..86c83084542a 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c | |||
| @@ -680,6 +680,7 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, | |||
| 680 | struct sk_buff *skb, *tmp; | 680 | struct sk_buff *skb, *tmp; |
| 681 | u32 hw_reconf_flags = 0; | 681 | u32 hw_reconf_flags = 0; |
| 682 | int i, flushed; | 682 | int i, flushed; |
| 683 | struct ps_data *ps; | ||
| 683 | 684 | ||
| 684 | clear_bit(SDATA_STATE_RUNNING, &sdata->state); | 685 | clear_bit(SDATA_STATE_RUNNING, &sdata->state); |
| 685 | 686 | ||
| @@ -749,6 +750,16 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, | |||
| 749 | 750 | ||
| 750 | cancel_work_sync(&sdata->recalc_smps); | 751 | cancel_work_sync(&sdata->recalc_smps); |
| 751 | 752 | ||
| 753 | cancel_delayed_work_sync(&sdata->dfs_cac_timer_work); | ||
| 754 | |||
| 755 | if (sdata->wdev.cac_started) { | ||
| 756 | mutex_lock(&local->iflist_mtx); | ||
| 757 | ieee80211_vif_release_channel(sdata); | ||
| 758 | mutex_unlock(&local->iflist_mtx); | ||
| 759 | cfg80211_cac_event(sdata->dev, NL80211_RADAR_CAC_ABORTED, | ||
| 760 | GFP_KERNEL); | ||
| 761 | } | ||
| 762 | |||
| 752 | /* APs need special treatment */ | 763 | /* APs need special treatment */ |
| 753 | if (sdata->vif.type == NL80211_IFTYPE_AP) { | 764 | if (sdata->vif.type == NL80211_IFTYPE_AP) { |
| 754 | struct ieee80211_sub_if_data *vlan, *tmpsdata; | 765 | struct ieee80211_sub_if_data *vlan, *tmpsdata; |
| @@ -758,6 +769,19 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, | |||
| 758 | u.vlan.list) | 769 | u.vlan.list) |
| 759 | dev_close(vlan->dev); | 770 | dev_close(vlan->dev); |
| 760 | WARN_ON(!list_empty(&sdata->u.ap.vlans)); | 771 | WARN_ON(!list_empty(&sdata->u.ap.vlans)); |
| 772 | } else if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) { | ||
| 773 | /* remove all packets in parent bc_buf pointing to this dev */ | ||
| 774 | ps = &sdata->bss->ps; | ||
| 775 | |||
| 776 | spin_lock_irqsave(&ps->bc_buf.lock, flags); | ||
| 777 | skb_queue_walk_safe(&ps->bc_buf, skb, tmp) { | ||
| 778 | if (skb->dev == sdata->dev) { | ||
| 779 | __skb_unlink(skb, &ps->bc_buf); | ||
| 780 | local->total_ps_buffered--; | ||
| 781 | ieee80211_free_txskb(&local->hw, skb); | ||
| 782 | } | ||
| 783 | } | ||
| 784 | spin_unlock_irqrestore(&ps->bc_buf.lock, flags); | ||
| 761 | } else if (sdata->vif.type == NL80211_IFTYPE_STATION) { | 785 | } else if (sdata->vif.type == NL80211_IFTYPE_STATION) { |
| 762 | ieee80211_mgd_stop(sdata); | 786 | ieee80211_mgd_stop(sdata); |
| 763 | } | 787 | } |
| @@ -1513,6 +1537,8 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name, | |||
| 1513 | spin_lock_init(&sdata->cleanup_stations_lock); | 1537 | spin_lock_init(&sdata->cleanup_stations_lock); |
| 1514 | INIT_LIST_HEAD(&sdata->cleanup_stations); | 1538 | INIT_LIST_HEAD(&sdata->cleanup_stations); |
| 1515 | INIT_WORK(&sdata->cleanup_stations_wk, ieee80211_cleanup_sdata_stas_wk); | 1539 | INIT_WORK(&sdata->cleanup_stations_wk, ieee80211_cleanup_sdata_stas_wk); |
| 1540 | INIT_DELAYED_WORK(&sdata->dfs_cac_timer_work, | ||
| 1541 | ieee80211_dfs_cac_timer_work); | ||
| 1516 | 1542 | ||
| 1517 | for (i = 0; i < IEEE80211_NUM_BANDS; i++) { | 1543 | for (i = 0; i < IEEE80211_NUM_BANDS; i++) { |
| 1518 | struct ieee80211_supported_band *sband; | 1544 | struct ieee80211_supported_band *sband; |
diff --git a/net/mac80211/main.c b/net/mac80211/main.c index 38b3468bc515..f9747689d604 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c | |||
| @@ -501,6 +501,11 @@ static const struct ieee80211_ht_cap mac80211_ht_capa_mod_mask = { | |||
| 501 | }, | 501 | }, |
| 502 | }; | 502 | }; |
| 503 | 503 | ||
| 504 | static const u8 extended_capabilities[] = { | ||
| 505 | 0, 0, 0, 0, 0, 0, 0, | ||
| 506 | WLAN_EXT_CAPA8_OPMODE_NOTIF, | ||
| 507 | }; | ||
| 508 | |||
| 504 | struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, | 509 | struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, |
| 505 | const struct ieee80211_ops *ops) | 510 | const struct ieee80211_ops *ops) |
| 506 | { | 511 | { |
| @@ -557,14 +562,17 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, | |||
| 557 | WIPHY_FLAG_REPORTS_OBSS | | 562 | WIPHY_FLAG_REPORTS_OBSS | |
| 558 | WIPHY_FLAG_OFFCHAN_TX; | 563 | WIPHY_FLAG_OFFCHAN_TX; |
| 559 | 564 | ||
| 565 | wiphy->extended_capabilities = extended_capabilities; | ||
| 566 | wiphy->extended_capabilities_mask = extended_capabilities; | ||
| 567 | wiphy->extended_capabilities_len = ARRAY_SIZE(extended_capabilities); | ||
| 568 | |||
| 560 | if (ops->remain_on_channel) | 569 | if (ops->remain_on_channel) |
| 561 | wiphy->flags |= WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL; | 570 | wiphy->flags |= WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL; |
| 562 | 571 | ||
| 563 | wiphy->features |= NL80211_FEATURE_SK_TX_STATUS | | 572 | wiphy->features |= NL80211_FEATURE_SK_TX_STATUS | |
| 564 | NL80211_FEATURE_SAE | | 573 | NL80211_FEATURE_SAE | |
| 565 | NL80211_FEATURE_HT_IBSS | | 574 | NL80211_FEATURE_HT_IBSS | |
| 566 | NL80211_FEATURE_VIF_TXPOWER | | 575 | NL80211_FEATURE_VIF_TXPOWER; |
| 567 | NL80211_FEATURE_FULL_AP_CLIENT_STATE; | ||
| 568 | 576 | ||
| 569 | if (!ops->hw_scan) | 577 | if (!ops->hw_scan) |
| 570 | wiphy->features |= NL80211_FEATURE_LOW_PRIORITY_SCAN | | 578 | wiphy->features |= NL80211_FEATURE_LOW_PRIORITY_SCAN | |
| @@ -621,6 +629,9 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, | |||
| 621 | 629 | ||
| 622 | INIT_WORK(&local->restart_work, ieee80211_restart_work); | 630 | INIT_WORK(&local->restart_work, ieee80211_restart_work); |
| 623 | 631 | ||
| 632 | INIT_WORK(&local->radar_detected_work, | ||
| 633 | ieee80211_dfs_radar_detected_work); | ||
| 634 | |||
| 624 | INIT_WORK(&local->reconfig_filter, ieee80211_reconfig_filter); | 635 | INIT_WORK(&local->reconfig_filter, ieee80211_reconfig_filter); |
| 625 | local->smps_mode = IEEE80211_SMPS_OFF; | 636 | local->smps_mode = IEEE80211_SMPS_OFF; |
| 626 | 637 | ||
| @@ -713,6 +724,16 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) | |||
| 713 | */ | 724 | */ |
| 714 | if (local->hw.wiphy->interface_modes & BIT(NL80211_IFTYPE_WDS)) | 725 | if (local->hw.wiphy->interface_modes & BIT(NL80211_IFTYPE_WDS)) |
| 715 | return -EINVAL; | 726 | return -EINVAL; |
| 727 | |||
| 728 | /* DFS currently not supported with channel context drivers */ | ||
| 729 | for (i = 0; i < local->hw.wiphy->n_iface_combinations; i++) { | ||
| 730 | const struct ieee80211_iface_combination *comb; | ||
| 731 | |||
| 732 | comb = &local->hw.wiphy->iface_combinations[i]; | ||
| 733 | |||
| 734 | if (comb->radar_detect_widths) | ||
| 735 | return -EINVAL; | ||
| 736 | } | ||
| 716 | } | 737 | } |
| 717 | 738 | ||
| 718 | /* Only HW csum features are currently compatible with mac80211 */ | 739 | /* Only HW csum features are currently compatible with mac80211 */ |
diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c index 2bf0158c3f82..a77d40ed4e61 100644 --- a/net/mac80211/mesh.c +++ b/net/mac80211/mesh.c | |||
| @@ -171,7 +171,7 @@ void mesh_sta_cleanup(struct sta_info *sta) | |||
| 171 | } | 171 | } |
| 172 | 172 | ||
| 173 | if (changed) | 173 | if (changed) |
| 174 | ieee80211_bss_info_change_notify(sdata, changed); | 174 | ieee80211_mbss_info_change_notify(sdata, changed); |
| 175 | } | 175 | } |
| 176 | 176 | ||
| 177 | int mesh_rmc_init(struct ieee80211_sub_if_data *sdata) | 177 | int mesh_rmc_init(struct ieee80211_sub_if_data *sdata) |
| @@ -593,7 +593,7 @@ static void ieee80211_mesh_housekeeping(struct ieee80211_sub_if_data *sdata, | |||
| 593 | mesh_path_expire(sdata); | 593 | mesh_path_expire(sdata); |
| 594 | 594 | ||
| 595 | changed = mesh_accept_plinks_update(sdata); | 595 | changed = mesh_accept_plinks_update(sdata); |
| 596 | ieee80211_bss_info_change_notify(sdata, changed); | 596 | ieee80211_mbss_info_change_notify(sdata, changed); |
| 597 | 597 | ||
| 598 | mod_timer(&ifmsh->housekeeping_timer, | 598 | mod_timer(&ifmsh->housekeeping_timer, |
| 599 | round_jiffies(jiffies + IEEE80211_MESH_HOUSEKEEPING_INTERVAL)); | 599 | round_jiffies(jiffies + IEEE80211_MESH_HOUSEKEEPING_INTERVAL)); |
| @@ -644,7 +644,140 @@ void ieee80211_mesh_restart(struct ieee80211_sub_if_data *sdata) | |||
| 644 | } | 644 | } |
| 645 | #endif | 645 | #endif |
| 646 | 646 | ||
| 647 | void ieee80211_start_mesh(struct ieee80211_sub_if_data *sdata) | 647 | static int |
| 648 | ieee80211_mesh_build_beacon(struct ieee80211_if_mesh *ifmsh) | ||
| 649 | { | ||
| 650 | struct beacon_data *bcn; | ||
| 651 | int head_len, tail_len; | ||
| 652 | struct sk_buff *skb; | ||
| 653 | struct ieee80211_mgmt *mgmt; | ||
| 654 | struct ieee80211_chanctx_conf *chanctx_conf; | ||
| 655 | enum ieee80211_band band; | ||
| 656 | u8 *pos; | ||
| 657 | struct ieee80211_sub_if_data *sdata; | ||
| 658 | int hdr_len = offsetof(struct ieee80211_mgmt, u.beacon) + | ||
| 659 | sizeof(mgmt->u.beacon); | ||
| 660 | |||
| 661 | sdata = container_of(ifmsh, struct ieee80211_sub_if_data, u.mesh); | ||
| 662 | rcu_read_lock(); | ||
| 663 | chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); | ||
| 664 | band = chanctx_conf->def.chan->band; | ||
| 665 | rcu_read_unlock(); | ||
| 666 | |||
| 667 | head_len = hdr_len + | ||
| 668 | 2 + /* NULL SSID */ | ||
| 669 | 2 + 8 + /* supported rates */ | ||
| 670 | 2 + 3; /* DS params */ | ||
| 671 | tail_len = 2 + (IEEE80211_MAX_SUPP_RATES - 8) + | ||
| 672 | 2 + sizeof(struct ieee80211_ht_cap) + | ||
| 673 | 2 + sizeof(struct ieee80211_ht_operation) + | ||
| 674 | 2 + ifmsh->mesh_id_len + | ||
| 675 | 2 + sizeof(struct ieee80211_meshconf_ie) + | ||
| 676 | 2 + sizeof(__le16) + /* awake window */ | ||
| 677 | ifmsh->ie_len; | ||
| 678 | |||
| 679 | bcn = kzalloc(sizeof(*bcn) + head_len + tail_len, GFP_KERNEL); | ||
| 680 | /* need an skb for IE builders to operate on */ | ||
| 681 | skb = dev_alloc_skb(max(head_len, tail_len)); | ||
| 682 | |||
| 683 | if (!bcn || !skb) | ||
| 684 | goto out_free; | ||
| 685 | |||
| 686 | /* | ||
| 687 | * pointers go into the block we allocated, | ||
| 688 | * memory is | beacon_data | head | tail | | ||
| 689 | */ | ||
| 690 | bcn->head = ((u8 *) bcn) + sizeof(*bcn); | ||
| 691 | |||
| 692 | /* fill in the head */ | ||
| 693 | mgmt = (struct ieee80211_mgmt *) skb_put(skb, hdr_len); | ||
| 694 | memset(mgmt, 0, hdr_len); | ||
| 695 | mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | | ||
| 696 | IEEE80211_STYPE_BEACON); | ||
| 697 | eth_broadcast_addr(mgmt->da); | ||
| 698 | memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN); | ||
| 699 | memcpy(mgmt->bssid, sdata->vif.addr, ETH_ALEN); | ||
| 700 | ieee80211_mps_set_frame_flags(sdata, NULL, (void *) mgmt); | ||
| 701 | mgmt->u.beacon.beacon_int = | ||
| 702 | cpu_to_le16(sdata->vif.bss_conf.beacon_int); | ||
| 703 | mgmt->u.beacon.capab_info |= cpu_to_le16( | ||
| 704 | sdata->u.mesh.security ? WLAN_CAPABILITY_PRIVACY : 0); | ||
| 705 | |||
| 706 | pos = skb_put(skb, 2); | ||
| 707 | *pos++ = WLAN_EID_SSID; | ||
| 708 | *pos++ = 0x0; | ||
| 709 | |||
| 710 | if (ieee80211_add_srates_ie(sdata, skb, true, band) || | ||
| 711 | mesh_add_ds_params_ie(skb, sdata)) | ||
| 712 | goto out_free; | ||
| 713 | |||
| 714 | bcn->head_len = skb->len; | ||
| 715 | memcpy(bcn->head, skb->data, bcn->head_len); | ||
| 716 | |||
| 717 | /* now the tail */ | ||
| 718 | skb_trim(skb, 0); | ||
| 719 | bcn->tail = bcn->head + bcn->head_len; | ||
| 720 | |||
| 721 | if (ieee80211_add_ext_srates_ie(sdata, skb, true, band) || | ||
| 722 | mesh_add_rsn_ie(skb, sdata) || | ||
| 723 | mesh_add_ht_cap_ie(skb, sdata) || | ||
| 724 | mesh_add_ht_oper_ie(skb, sdata) || | ||
| 725 | mesh_add_meshid_ie(skb, sdata) || | ||
| 726 | mesh_add_meshconf_ie(skb, sdata) || | ||
| 727 | mesh_add_awake_window_ie(skb, sdata) || | ||
| 728 | mesh_add_vendor_ies(skb, sdata)) | ||
| 729 | goto out_free; | ||
| 730 | |||
| 731 | bcn->tail_len = skb->len; | ||
| 732 | memcpy(bcn->tail, skb->data, bcn->tail_len); | ||
| 733 | |||
| 734 | dev_kfree_skb(skb); | ||
| 735 | rcu_assign_pointer(ifmsh->beacon, bcn); | ||
| 736 | return 0; | ||
| 737 | out_free: | ||
| 738 | kfree(bcn); | ||
| 739 | dev_kfree_skb(skb); | ||
| 740 | return -ENOMEM; | ||
| 741 | } | ||
| 742 | |||
| 743 | static int | ||
| 744 | ieee80211_mesh_rebuild_beacon(struct ieee80211_if_mesh *ifmsh) | ||
| 745 | { | ||
| 746 | struct ieee80211_sub_if_data *sdata; | ||
| 747 | struct beacon_data *old_bcn; | ||
| 748 | int ret; | ||
| 749 | sdata = container_of(ifmsh, struct ieee80211_sub_if_data, u.mesh); | ||
| 750 | |||
| 751 | mutex_lock(&ifmsh->mtx); | ||
| 752 | |||
| 753 | old_bcn = rcu_dereference_protected(ifmsh->beacon, | ||
| 754 | lockdep_is_held(&ifmsh->mtx)); | ||
| 755 | ret = ieee80211_mesh_build_beacon(ifmsh); | ||
| 756 | if (ret) | ||
| 757 | /* just reuse old beacon */ | ||
| 758 | goto out; | ||
| 759 | |||
| 760 | if (old_bcn) | ||
| 761 | kfree_rcu(old_bcn, rcu_head); | ||
| 762 | out: | ||
| 763 | mutex_unlock(&ifmsh->mtx); | ||
| 764 | return ret; | ||
| 765 | } | ||
| 766 | |||
| 767 | void ieee80211_mbss_info_change_notify(struct ieee80211_sub_if_data *sdata, | ||
| 768 | u32 changed) | ||
| 769 | { | ||
| 770 | if (sdata->vif.bss_conf.enable_beacon && | ||
| 771 | (changed & (BSS_CHANGED_BEACON | | ||
| 772 | BSS_CHANGED_HT | | ||
| 773 | BSS_CHANGED_BASIC_RATES | | ||
| 774 | BSS_CHANGED_BEACON_INT))) | ||
| 775 | if (ieee80211_mesh_rebuild_beacon(&sdata->u.mesh)) | ||
| 776 | return; | ||
| 777 | ieee80211_bss_info_change_notify(sdata, changed); | ||
| 778 | } | ||
| 779 | |||
| 780 | int ieee80211_start_mesh(struct ieee80211_sub_if_data *sdata) | ||
| 648 | { | 781 | { |
| 649 | struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; | 782 | struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; |
| 650 | struct ieee80211_local *local = sdata->local; | 783 | struct ieee80211_local *local = sdata->local; |
| @@ -675,17 +808,24 @@ void ieee80211_start_mesh(struct ieee80211_sub_if_data *sdata) | |||
| 675 | sdata->vif.bss_conf.basic_rates = | 808 | sdata->vif.bss_conf.basic_rates = |
| 676 | ieee80211_mandatory_rates(local, band); | 809 | ieee80211_mandatory_rates(local, band); |
| 677 | 810 | ||
| 678 | ieee80211_mps_local_status_update(sdata); | 811 | changed |= ieee80211_mps_local_status_update(sdata); |
| 812 | |||
| 813 | if (ieee80211_mesh_build_beacon(ifmsh)) { | ||
| 814 | ieee80211_stop_mesh(sdata); | ||
| 815 | return -ENOMEM; | ||
| 816 | } | ||
| 679 | 817 | ||
| 680 | ieee80211_bss_info_change_notify(sdata, changed); | 818 | ieee80211_bss_info_change_notify(sdata, changed); |
| 681 | 819 | ||
| 682 | netif_carrier_on(sdata->dev); | 820 | netif_carrier_on(sdata->dev); |
| 821 | return 0; | ||
| 683 | } | 822 | } |
| 684 | 823 | ||
| 685 | void ieee80211_stop_mesh(struct ieee80211_sub_if_data *sdata) | 824 | void ieee80211_stop_mesh(struct ieee80211_sub_if_data *sdata) |
| 686 | { | 825 | { |
| 687 | struct ieee80211_local *local = sdata->local; | 826 | struct ieee80211_local *local = sdata->local; |
| 688 | struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; | 827 | struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; |
| 828 | struct beacon_data *bcn; | ||
| 689 | 829 | ||
| 690 | netif_carrier_off(sdata->dev); | 830 | netif_carrier_off(sdata->dev); |
| 691 | 831 | ||
| @@ -694,6 +834,12 @@ void ieee80211_stop_mesh(struct ieee80211_sub_if_data *sdata) | |||
| 694 | sdata->vif.bss_conf.enable_beacon = false; | 834 | sdata->vif.bss_conf.enable_beacon = false; |
| 695 | clear_bit(SDATA_STATE_OFFCHANNEL_BEACON_STOPPED, &sdata->state); | 835 | clear_bit(SDATA_STATE_OFFCHANNEL_BEACON_STOPPED, &sdata->state); |
| 696 | ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON_ENABLED); | 836 | ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON_ENABLED); |
| 837 | mutex_lock(&ifmsh->mtx); | ||
| 838 | bcn = rcu_dereference_protected(ifmsh->beacon, | ||
| 839 | lockdep_is_held(&ifmsh->mtx)); | ||
| 840 | rcu_assign_pointer(ifmsh->beacon, NULL); | ||
| 841 | kfree_rcu(bcn, rcu_head); | ||
| 842 | mutex_unlock(&ifmsh->mtx); | ||
| 697 | 843 | ||
| 698 | /* flush STAs and mpaths on this iface */ | 844 | /* flush STAs and mpaths on this iface */ |
| 699 | sta_info_flush(sdata); | 845 | sta_info_flush(sdata); |
| @@ -722,6 +868,63 @@ void ieee80211_stop_mesh(struct ieee80211_sub_if_data *sdata) | |||
| 722 | sdata->u.mesh.timers_running = 0; | 868 | sdata->u.mesh.timers_running = 0; |
| 723 | } | 869 | } |
| 724 | 870 | ||
| 871 | static void | ||
| 872 | ieee80211_mesh_rx_probe_req(struct ieee80211_sub_if_data *sdata, | ||
| 873 | struct ieee80211_mgmt *mgmt, size_t len) | ||
| 874 | { | ||
| 875 | struct ieee80211_local *local = sdata->local; | ||
| 876 | struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; | ||
| 877 | struct sk_buff *presp; | ||
| 878 | struct beacon_data *bcn; | ||
| 879 | struct ieee80211_mgmt *hdr; | ||
| 880 | struct ieee802_11_elems elems; | ||
| 881 | size_t baselen; | ||
| 882 | u8 *pos, *end; | ||
| 883 | |||
| 884 | end = ((u8 *) mgmt) + len; | ||
| 885 | pos = mgmt->u.probe_req.variable; | ||
| 886 | baselen = (u8 *) pos - (u8 *) mgmt; | ||
| 887 | if (baselen > len) | ||
| 888 | return; | ||
| 889 | |||
| 890 | ieee802_11_parse_elems(pos, len - baselen, &elems); | ||
| 891 | |||
| 892 | /* 802.11-2012 10.1.4.3.2 */ | ||
| 893 | if ((!ether_addr_equal(mgmt->da, sdata->vif.addr) && | ||
| 894 | !is_broadcast_ether_addr(mgmt->da)) || | ||
| 895 | elems.ssid_len != 0) | ||
| 896 | return; | ||
| 897 | |||
| 898 | if (elems.mesh_id_len != 0 && | ||
| 899 | (elems.mesh_id_len != ifmsh->mesh_id_len || | ||
| 900 | memcmp(elems.mesh_id, ifmsh->mesh_id, ifmsh->mesh_id_len))) | ||
| 901 | return; | ||
| 902 | |||
| 903 | rcu_read_lock(); | ||
| 904 | bcn = rcu_dereference(ifmsh->beacon); | ||
| 905 | |||
| 906 | if (!bcn) | ||
| 907 | goto out; | ||
| 908 | |||
| 909 | presp = dev_alloc_skb(local->tx_headroom + | ||
| 910 | bcn->head_len + bcn->tail_len); | ||
| 911 | if (!presp) | ||
| 912 | goto out; | ||
| 913 | |||
| 914 | skb_reserve(presp, local->tx_headroom); | ||
| 915 | memcpy(skb_put(presp, bcn->head_len), bcn->head, bcn->head_len); | ||
| 916 | memcpy(skb_put(presp, bcn->tail_len), bcn->tail, bcn->tail_len); | ||
| 917 | hdr = (struct ieee80211_mgmt *) presp->data; | ||
| 918 | hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | | ||
| 919 | IEEE80211_STYPE_PROBE_RESP); | ||
| 920 | memcpy(hdr->da, mgmt->sa, ETH_ALEN); | ||
| 921 | mpl_dbg(sdata, "sending probe resp. to %pM\n", hdr->da); | ||
| 922 | IEEE80211_SKB_CB(presp)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT; | ||
| 923 | ieee80211_tx_skb(sdata, presp); | ||
| 924 | out: | ||
| 925 | rcu_read_unlock(); | ||
| 926 | } | ||
| 927 | |||
| 725 | static void ieee80211_mesh_rx_bcn_presp(struct ieee80211_sub_if_data *sdata, | 928 | static void ieee80211_mesh_rx_bcn_presp(struct ieee80211_sub_if_data *sdata, |
| 726 | u16 stype, | 929 | u16 stype, |
| 727 | struct ieee80211_mgmt *mgmt, | 930 | struct ieee80211_mgmt *mgmt, |
| @@ -811,6 +1014,9 @@ void ieee80211_mesh_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata, | |||
| 811 | ieee80211_mesh_rx_bcn_presp(sdata, stype, mgmt, skb->len, | 1014 | ieee80211_mesh_rx_bcn_presp(sdata, stype, mgmt, skb->len, |
| 812 | rx_status); | 1015 | rx_status); |
| 813 | break; | 1016 | break; |
| 1017 | case IEEE80211_STYPE_PROBE_REQ: | ||
| 1018 | ieee80211_mesh_rx_probe_req(sdata, mgmt, skb->len); | ||
| 1019 | break; | ||
| 814 | case IEEE80211_STYPE_ACTION: | 1020 | case IEEE80211_STYPE_ACTION: |
| 815 | ieee80211_mesh_rx_mgmt_action(sdata, mgmt, skb->len, rx_status); | 1021 | ieee80211_mesh_rx_mgmt_action(sdata, mgmt, skb->len, rx_status); |
| 816 | break; | 1022 | break; |
| @@ -883,6 +1089,8 @@ void ieee80211_mesh_init_sdata(struct ieee80211_sub_if_data *sdata) | |||
| 883 | skb_queue_head_init(&ifmsh->ps.bc_buf); | 1089 | skb_queue_head_init(&ifmsh->ps.bc_buf); |
| 884 | spin_lock_init(&ifmsh->mesh_preq_queue_lock); | 1090 | spin_lock_init(&ifmsh->mesh_preq_queue_lock); |
| 885 | spin_lock_init(&ifmsh->sync_offset_lock); | 1091 | spin_lock_init(&ifmsh->sync_offset_lock); |
| 1092 | RCU_INIT_POINTER(ifmsh->beacon, NULL); | ||
| 1093 | mutex_init(&ifmsh->mtx); | ||
| 886 | 1094 | ||
| 887 | sdata->vif.bss_conf.bssid = zero_addr; | 1095 | sdata->vif.bss_conf.bssid = zero_addr; |
| 888 | } | 1096 | } |
diff --git a/net/mac80211/mesh.h b/net/mac80211/mesh.h index 3b9d862744ba..1a1da877b1d2 100644 --- a/net/mac80211/mesh.h +++ b/net/mac80211/mesh.h | |||
| @@ -239,15 +239,18 @@ void ieee80211s_update_metric(struct ieee80211_local *local, | |||
| 239 | struct sta_info *sta, struct sk_buff *skb); | 239 | struct sta_info *sta, struct sk_buff *skb); |
| 240 | void ieee80211s_stop(void); | 240 | void ieee80211s_stop(void); |
| 241 | void ieee80211_mesh_init_sdata(struct ieee80211_sub_if_data *sdata); | 241 | void ieee80211_mesh_init_sdata(struct ieee80211_sub_if_data *sdata); |
| 242 | void ieee80211_start_mesh(struct ieee80211_sub_if_data *sdata); | 242 | int ieee80211_start_mesh(struct ieee80211_sub_if_data *sdata); |
| 243 | void ieee80211_stop_mesh(struct ieee80211_sub_if_data *sdata); | 243 | void ieee80211_stop_mesh(struct ieee80211_sub_if_data *sdata); |
| 244 | void ieee80211_mesh_root_setup(struct ieee80211_if_mesh *ifmsh); | 244 | void ieee80211_mesh_root_setup(struct ieee80211_if_mesh *ifmsh); |
| 245 | const struct ieee80211_mesh_sync_ops *ieee80211_mesh_sync_ops_get(u8 method); | 245 | const struct ieee80211_mesh_sync_ops *ieee80211_mesh_sync_ops_get(u8 method); |
| 246 | /* wrapper for ieee80211_bss_info_change_notify() */ | ||
| 247 | void ieee80211_mbss_info_change_notify(struct ieee80211_sub_if_data *sdata, | ||
| 248 | u32 changed); | ||
| 246 | 249 | ||
| 247 | /* mesh power save */ | 250 | /* mesh power save */ |
| 248 | void ieee80211_mps_local_status_update(struct ieee80211_sub_if_data *sdata); | 251 | u32 ieee80211_mps_local_status_update(struct ieee80211_sub_if_data *sdata); |
| 249 | void ieee80211_mps_set_sta_local_pm(struct sta_info *sta, | 252 | u32 ieee80211_mps_set_sta_local_pm(struct sta_info *sta, |
| 250 | enum nl80211_mesh_power_mode pm); | 253 | enum nl80211_mesh_power_mode pm); |
| 251 | void ieee80211_mps_set_frame_flags(struct ieee80211_sub_if_data *sdata, | 254 | void ieee80211_mps_set_frame_flags(struct ieee80211_sub_if_data *sdata, |
| 252 | struct sta_info *sta, | 255 | struct sta_info *sta, |
| 253 | struct ieee80211_hdr *hdr); | 256 | struct ieee80211_hdr *hdr); |
| @@ -265,8 +268,8 @@ int mesh_nexthop_lookup(struct sk_buff *skb, | |||
| 265 | int mesh_nexthop_resolve(struct sk_buff *skb, | 268 | int mesh_nexthop_resolve(struct sk_buff *skb, |
| 266 | struct ieee80211_sub_if_data *sdata); | 269 | struct ieee80211_sub_if_data *sdata); |
| 267 | void mesh_path_start_discovery(struct ieee80211_sub_if_data *sdata); | 270 | void mesh_path_start_discovery(struct ieee80211_sub_if_data *sdata); |
| 268 | struct mesh_path *mesh_path_lookup(u8 *dst, | 271 | struct mesh_path *mesh_path_lookup(const u8 *dst, |
| 269 | struct ieee80211_sub_if_data *sdata); | 272 | struct ieee80211_sub_if_data *sdata); |
| 270 | struct mesh_path *mpp_path_lookup(u8 *dst, | 273 | struct mesh_path *mpp_path_lookup(u8 *dst, |
| 271 | struct ieee80211_sub_if_data *sdata); | 274 | struct ieee80211_sub_if_data *sdata); |
| 272 | int mpp_path_add(u8 *dst, u8 *mpp, struct ieee80211_sub_if_data *sdata); | 275 | int mpp_path_add(u8 *dst, u8 *mpp, struct ieee80211_sub_if_data *sdata); |
| @@ -276,7 +279,7 @@ void mesh_path_fix_nexthop(struct mesh_path *mpath, struct sta_info *next_hop); | |||
| 276 | void mesh_path_expire(struct ieee80211_sub_if_data *sdata); | 279 | void mesh_path_expire(struct ieee80211_sub_if_data *sdata); |
| 277 | void mesh_rx_path_sel_frame(struct ieee80211_sub_if_data *sdata, | 280 | void mesh_rx_path_sel_frame(struct ieee80211_sub_if_data *sdata, |
| 278 | struct ieee80211_mgmt *mgmt, size_t len); | 281 | struct ieee80211_mgmt *mgmt, size_t len); |
| 279 | int mesh_path_add(u8 *dst, struct ieee80211_sub_if_data *sdata); | 282 | int mesh_path_add(const u8 *dst, struct ieee80211_sub_if_data *sdata); |
| 280 | 283 | ||
| 281 | int mesh_path_add_gate(struct mesh_path *mpath); | 284 | int mesh_path_add_gate(struct mesh_path *mpath); |
| 282 | int mesh_path_send_to_gates(struct mesh_path *mpath); | 285 | int mesh_path_send_to_gates(struct mesh_path *mpath); |
| @@ -289,8 +292,8 @@ bool mesh_peer_accepts_plinks(struct ieee802_11_elems *ie); | |||
| 289 | u32 mesh_accept_plinks_update(struct ieee80211_sub_if_data *sdata); | 292 | u32 mesh_accept_plinks_update(struct ieee80211_sub_if_data *sdata); |
| 290 | void mesh_plink_broken(struct sta_info *sta); | 293 | void mesh_plink_broken(struct sta_info *sta); |
| 291 | u32 mesh_plink_deactivate(struct sta_info *sta); | 294 | u32 mesh_plink_deactivate(struct sta_info *sta); |
| 292 | int mesh_plink_open(struct sta_info *sta); | 295 | u32 mesh_plink_open(struct sta_info *sta); |
| 293 | void mesh_plink_block(struct sta_info *sta); | 296 | u32 mesh_plink_block(struct sta_info *sta); |
| 294 | void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, | 297 | void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, |
| 295 | struct ieee80211_mgmt *mgmt, size_t len, | 298 | struct ieee80211_mgmt *mgmt, size_t len, |
| 296 | struct ieee80211_rx_status *rx_status); | 299 | struct ieee80211_rx_status *rx_status); |
| @@ -301,8 +304,9 @@ void mesh_sta_cleanup(struct sta_info *sta); | |||
| 301 | void mesh_mpath_table_grow(void); | 304 | void mesh_mpath_table_grow(void); |
| 302 | void mesh_mpp_table_grow(void); | 305 | void mesh_mpp_table_grow(void); |
| 303 | /* Mesh paths */ | 306 | /* Mesh paths */ |
| 304 | int mesh_path_error_tx(u8 ttl, u8 *target, __le32 target_sn, __le16 target_rcode, | 307 | int mesh_path_error_tx(u8 ttl, const u8 *target, __le32 target_sn, |
| 305 | const u8 *ra, struct ieee80211_sub_if_data *sdata); | 308 | __le16 target_rcode, const u8 *ra, |
| 309 | struct ieee80211_sub_if_data *sdata); | ||
| 306 | void mesh_path_assign_nexthop(struct mesh_path *mpath, struct sta_info *sta); | 310 | void mesh_path_assign_nexthop(struct mesh_path *mpath, struct sta_info *sta); |
| 307 | void mesh_path_flush_pending(struct mesh_path *mpath); | 311 | void mesh_path_flush_pending(struct mesh_path *mpath); |
| 308 | void mesh_path_tx_pending(struct mesh_path *mpath); | 312 | void mesh_path_tx_pending(struct mesh_path *mpath); |
diff --git a/net/mac80211/mesh_hwmp.c b/net/mac80211/mesh_hwmp.c index f0dd8742ed42..585c1e26cca8 100644 --- a/net/mac80211/mesh_hwmp.c +++ b/net/mac80211/mesh_hwmp.c | |||
| @@ -30,14 +30,14 @@ | |||
| 30 | 30 | ||
| 31 | static void mesh_queue_preq(struct mesh_path *, u8); | 31 | static void mesh_queue_preq(struct mesh_path *, u8); |
| 32 | 32 | ||
| 33 | static inline u32 u32_field_get(u8 *preq_elem, int offset, bool ae) | 33 | static inline u32 u32_field_get(const u8 *preq_elem, int offset, bool ae) |
| 34 | { | 34 | { |
| 35 | if (ae) | 35 | if (ae) |
| 36 | offset += 6; | 36 | offset += 6; |
| 37 | return get_unaligned_le32(preq_elem + offset); | 37 | return get_unaligned_le32(preq_elem + offset); |
| 38 | } | 38 | } |
| 39 | 39 | ||
| 40 | static inline u32 u16_field_get(u8 *preq_elem, int offset, bool ae) | 40 | static inline u32 u16_field_get(const u8 *preq_elem, int offset, bool ae) |
| 41 | { | 41 | { |
| 42 | if (ae) | 42 | if (ae) |
| 43 | offset += 6; | 43 | offset += 6; |
| @@ -102,10 +102,13 @@ enum mpath_frame_type { | |||
| 102 | static const u8 broadcast_addr[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; | 102 | static const u8 broadcast_addr[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; |
| 103 | 103 | ||
| 104 | static int mesh_path_sel_frame_tx(enum mpath_frame_type action, u8 flags, | 104 | static int mesh_path_sel_frame_tx(enum mpath_frame_type action, u8 flags, |
| 105 | u8 *orig_addr, __le32 orig_sn, u8 target_flags, u8 *target, | 105 | const u8 *orig_addr, __le32 orig_sn, |
| 106 | __le32 target_sn, const u8 *da, u8 hop_count, u8 ttl, | 106 | u8 target_flags, const u8 *target, |
| 107 | __le32 lifetime, __le32 metric, __le32 preq_id, | 107 | __le32 target_sn, const u8 *da, |
| 108 | struct ieee80211_sub_if_data *sdata) | 108 | u8 hop_count, u8 ttl, |
| 109 | __le32 lifetime, __le32 metric, | ||
| 110 | __le32 preq_id, | ||
| 111 | struct ieee80211_sub_if_data *sdata) | ||
| 109 | { | 112 | { |
| 110 | struct ieee80211_local *local = sdata->local; | 113 | struct ieee80211_local *local = sdata->local; |
| 111 | struct sk_buff *skb; | 114 | struct sk_buff *skb; |
| @@ -235,7 +238,7 @@ static void prepare_frame_for_deferred_tx(struct ieee80211_sub_if_data *sdata, | |||
| 235 | * also acquires in the TX path. To avoid a deadlock we don't transmit the | 238 | * also acquires in the TX path. To avoid a deadlock we don't transmit the |
| 236 | * frame directly but add it to the pending queue instead. | 239 | * frame directly but add it to the pending queue instead. |
| 237 | */ | 240 | */ |
| 238 | int mesh_path_error_tx(u8 ttl, u8 *target, __le32 target_sn, | 241 | int mesh_path_error_tx(u8 ttl, const u8 *target, __le32 target_sn, |
| 239 | __le16 target_rcode, const u8 *ra, | 242 | __le16 target_rcode, const u8 *ra, |
| 240 | struct ieee80211_sub_if_data *sdata) | 243 | struct ieee80211_sub_if_data *sdata) |
| 241 | { | 244 | { |
| @@ -369,14 +372,14 @@ static u32 airtime_link_metric_get(struct ieee80211_local *local, | |||
| 369 | * path routing information is updated. | 372 | * path routing information is updated. |
| 370 | */ | 373 | */ |
| 371 | static u32 hwmp_route_info_get(struct ieee80211_sub_if_data *sdata, | 374 | static u32 hwmp_route_info_get(struct ieee80211_sub_if_data *sdata, |
| 372 | struct ieee80211_mgmt *mgmt, | 375 | struct ieee80211_mgmt *mgmt, |
| 373 | u8 *hwmp_ie, enum mpath_frame_type action) | 376 | const u8 *hwmp_ie, enum mpath_frame_type action) |
| 374 | { | 377 | { |
| 375 | struct ieee80211_local *local = sdata->local; | 378 | struct ieee80211_local *local = sdata->local; |
| 376 | struct mesh_path *mpath; | 379 | struct mesh_path *mpath; |
| 377 | struct sta_info *sta; | 380 | struct sta_info *sta; |
| 378 | bool fresh_info; | 381 | bool fresh_info; |
| 379 | u8 *orig_addr, *ta; | 382 | const u8 *orig_addr, *ta; |
| 380 | u32 orig_sn, orig_metric; | 383 | u32 orig_sn, orig_metric; |
| 381 | unsigned long orig_lifetime, exp_time; | 384 | unsigned long orig_lifetime, exp_time; |
| 382 | u32 last_hop_metric, new_metric; | 385 | u32 last_hop_metric, new_metric; |
| @@ -511,11 +514,11 @@ static u32 hwmp_route_info_get(struct ieee80211_sub_if_data *sdata, | |||
| 511 | 514 | ||
| 512 | static void hwmp_preq_frame_process(struct ieee80211_sub_if_data *sdata, | 515 | static void hwmp_preq_frame_process(struct ieee80211_sub_if_data *sdata, |
| 513 | struct ieee80211_mgmt *mgmt, | 516 | struct ieee80211_mgmt *mgmt, |
| 514 | u8 *preq_elem, u32 metric) | 517 | const u8 *preq_elem, u32 metric) |
| 515 | { | 518 | { |
| 516 | struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; | 519 | struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; |
| 517 | struct mesh_path *mpath = NULL; | 520 | struct mesh_path *mpath = NULL; |
| 518 | u8 *target_addr, *orig_addr; | 521 | const u8 *target_addr, *orig_addr; |
| 519 | const u8 *da; | 522 | const u8 *da; |
| 520 | u8 target_flags, ttl, flags; | 523 | u8 target_flags, ttl, flags; |
| 521 | u32 orig_sn, target_sn, lifetime, orig_metric; | 524 | u32 orig_sn, target_sn, lifetime, orig_metric; |
| @@ -648,11 +651,11 @@ next_hop_deref_protected(struct mesh_path *mpath) | |||
| 648 | 651 | ||
| 649 | static void hwmp_prep_frame_process(struct ieee80211_sub_if_data *sdata, | 652 | static void hwmp_prep_frame_process(struct ieee80211_sub_if_data *sdata, |
| 650 | struct ieee80211_mgmt *mgmt, | 653 | struct ieee80211_mgmt *mgmt, |
| 651 | u8 *prep_elem, u32 metric) | 654 | const u8 *prep_elem, u32 metric) |
| 652 | { | 655 | { |
| 653 | struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; | 656 | struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; |
| 654 | struct mesh_path *mpath; | 657 | struct mesh_path *mpath; |
| 655 | u8 *target_addr, *orig_addr; | 658 | const u8 *target_addr, *orig_addr; |
| 656 | u8 ttl, hopcount, flags; | 659 | u8 ttl, hopcount, flags; |
| 657 | u8 next_hop[ETH_ALEN]; | 660 | u8 next_hop[ETH_ALEN]; |
| 658 | u32 target_sn, orig_sn, lifetime; | 661 | u32 target_sn, orig_sn, lifetime; |
| @@ -711,12 +714,13 @@ fail: | |||
| 711 | } | 714 | } |
| 712 | 715 | ||
| 713 | static void hwmp_perr_frame_process(struct ieee80211_sub_if_data *sdata, | 716 | static void hwmp_perr_frame_process(struct ieee80211_sub_if_data *sdata, |
| 714 | struct ieee80211_mgmt *mgmt, u8 *perr_elem) | 717 | struct ieee80211_mgmt *mgmt, |
| 718 | const u8 *perr_elem) | ||
| 715 | { | 719 | { |
| 716 | struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; | 720 | struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; |
| 717 | struct mesh_path *mpath; | 721 | struct mesh_path *mpath; |
| 718 | u8 ttl; | 722 | u8 ttl; |
| 719 | u8 *ta, *target_addr; | 723 | const u8 *ta, *target_addr; |
| 720 | u32 target_sn; | 724 | u32 target_sn; |
| 721 | u16 target_rcode; | 725 | u16 target_rcode; |
| 722 | 726 | ||
| @@ -758,15 +762,15 @@ endperr: | |||
| 758 | } | 762 | } |
| 759 | 763 | ||
| 760 | static void hwmp_rann_frame_process(struct ieee80211_sub_if_data *sdata, | 764 | static void hwmp_rann_frame_process(struct ieee80211_sub_if_data *sdata, |
| 761 | struct ieee80211_mgmt *mgmt, | 765 | struct ieee80211_mgmt *mgmt, |
| 762 | struct ieee80211_rann_ie *rann) | 766 | const struct ieee80211_rann_ie *rann) |
| 763 | { | 767 | { |
| 764 | struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; | 768 | struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; |
| 765 | struct ieee80211_local *local = sdata->local; | 769 | struct ieee80211_local *local = sdata->local; |
| 766 | struct sta_info *sta; | 770 | struct sta_info *sta; |
| 767 | struct mesh_path *mpath; | 771 | struct mesh_path *mpath; |
| 768 | u8 ttl, flags, hopcount; | 772 | u8 ttl, flags, hopcount; |
| 769 | u8 *orig_addr; | 773 | const u8 *orig_addr; |
| 770 | u32 orig_sn, metric, metric_txsta, interval; | 774 | u32 orig_sn, metric, metric_txsta, interval; |
| 771 | bool root_is_gate; | 775 | bool root_is_gate; |
| 772 | 776 | ||
diff --git a/net/mac80211/mesh_pathtbl.c b/net/mac80211/mesh_pathtbl.c index d5786c3eaee2..2ce4c4023a97 100644 --- a/net/mac80211/mesh_pathtbl.c +++ b/net/mac80211/mesh_pathtbl.c | |||
| @@ -181,7 +181,7 @@ errcopy: | |||
| 181 | return -ENOMEM; | 181 | return -ENOMEM; |
| 182 | } | 182 | } |
| 183 | 183 | ||
| 184 | static u32 mesh_table_hash(u8 *addr, struct ieee80211_sub_if_data *sdata, | 184 | static u32 mesh_table_hash(const u8 *addr, struct ieee80211_sub_if_data *sdata, |
| 185 | struct mesh_table *tbl) | 185 | struct mesh_table *tbl) |
| 186 | { | 186 | { |
| 187 | /* Use last four bytes of hw addr and interface index as hash index */ | 187 | /* Use last four bytes of hw addr and interface index as hash index */ |
| @@ -326,8 +326,8 @@ static void mesh_path_move_to_queue(struct mesh_path *gate_mpath, | |||
| 326 | } | 326 | } |
| 327 | 327 | ||
| 328 | 328 | ||
| 329 | static struct mesh_path *mpath_lookup(struct mesh_table *tbl, u8 *dst, | 329 | static struct mesh_path *mpath_lookup(struct mesh_table *tbl, const u8 *dst, |
| 330 | struct ieee80211_sub_if_data *sdata) | 330 | struct ieee80211_sub_if_data *sdata) |
| 331 | { | 331 | { |
| 332 | struct mesh_path *mpath; | 332 | struct mesh_path *mpath; |
| 333 | struct hlist_node *n; | 333 | struct hlist_node *n; |
| @@ -359,7 +359,8 @@ static struct mesh_path *mpath_lookup(struct mesh_table *tbl, u8 *dst, | |||
| 359 | * | 359 | * |
| 360 | * Locking: must be called within a read rcu section. | 360 | * Locking: must be called within a read rcu section. |
| 361 | */ | 361 | */ |
| 362 | struct mesh_path *mesh_path_lookup(u8 *dst, struct ieee80211_sub_if_data *sdata) | 362 | struct mesh_path *mesh_path_lookup(const u8 *dst, |
| 363 | struct ieee80211_sub_if_data *sdata) | ||
| 363 | { | 364 | { |
| 364 | return mpath_lookup(rcu_dereference(mesh_paths), dst, sdata); | 365 | return mpath_lookup(rcu_dereference(mesh_paths), dst, sdata); |
| 365 | } | 366 | } |
| @@ -494,7 +495,7 @@ int mesh_gate_num(struct ieee80211_sub_if_data *sdata) | |||
| 494 | * | 495 | * |
| 495 | * State: the initial state of the new path is set to 0 | 496 | * State: the initial state of the new path is set to 0 |
| 496 | */ | 497 | */ |
| 497 | int mesh_path_add(u8 *dst, struct ieee80211_sub_if_data *sdata) | 498 | int mesh_path_add(const u8 *dst, struct ieee80211_sub_if_data *sdata) |
| 498 | { | 499 | { |
| 499 | struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; | 500 | struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; |
| 500 | struct ieee80211_local *local = sdata->local; | 501 | struct ieee80211_local *local = sdata->local; |
diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c index 56c9b318a97e..f7526e509aa8 100644 --- a/net/mac80211/mesh_plink.c +++ b/net/mac80211/mesh_plink.c | |||
| @@ -202,7 +202,7 @@ static u32 __mesh_plink_deactivate(struct sta_info *sta) | |||
| 202 | mesh_path_flush_by_nexthop(sta); | 202 | mesh_path_flush_by_nexthop(sta); |
| 203 | 203 | ||
| 204 | ieee80211_mps_sta_status_update(sta); | 204 | ieee80211_mps_sta_status_update(sta); |
| 205 | ieee80211_mps_local_status_update(sdata); | 205 | changed |= ieee80211_mps_local_status_update(sdata); |
| 206 | 206 | ||
| 207 | return changed; | 207 | return changed; |
| 208 | } | 208 | } |
| @@ -373,8 +373,7 @@ static void mesh_sta_info_init(struct ieee80211_sub_if_data *sdata, | |||
| 373 | if (elems->ht_cap_elem && | 373 | if (elems->ht_cap_elem && |
| 374 | sdata->vif.bss_conf.chandef.width != NL80211_CHAN_WIDTH_20_NOHT) | 374 | sdata->vif.bss_conf.chandef.width != NL80211_CHAN_WIDTH_20_NOHT) |
| 375 | ieee80211_ht_cap_ie_to_sta_ht_cap(sdata, sband, | 375 | ieee80211_ht_cap_ie_to_sta_ht_cap(sdata, sband, |
| 376 | elems->ht_cap_elem, | 376 | elems->ht_cap_elem, sta); |
| 377 | &sta->sta.ht_cap); | ||
| 378 | else | 377 | else |
| 379 | memset(&sta->sta.ht_cap, 0, sizeof(sta->sta.ht_cap)); | 378 | memset(&sta->sta.ht_cap, 0, sizeof(sta->sta.ht_cap)); |
| 380 | 379 | ||
| @@ -383,8 +382,7 @@ static void mesh_sta_info_init(struct ieee80211_sub_if_data *sdata, | |||
| 383 | 382 | ||
| 384 | if (!(elems->ht_operation->ht_param & | 383 | if (!(elems->ht_operation->ht_param & |
| 385 | IEEE80211_HT_PARAM_CHAN_WIDTH_ANY)) | 384 | IEEE80211_HT_PARAM_CHAN_WIDTH_ANY)) |
| 386 | sta->sta.ht_cap.cap &= | 385 | sta->sta.bandwidth = IEEE80211_STA_RX_BW_20; |
| 387 | ~IEEE80211_HT_CAP_SUP_WIDTH_20_40; | ||
| 388 | ieee80211_ht_oper_to_chandef(sdata->vif.bss_conf.chandef.chan, | 386 | ieee80211_ht_oper_to_chandef(sdata->vif.bss_conf.chandef.chan, |
| 389 | elems->ht_operation, &chandef); | 387 | elems->ht_operation, &chandef); |
| 390 | if (sta->ch_width != chandef.width) | 388 | if (sta->ch_width != chandef.width) |
| @@ -494,6 +492,7 @@ void mesh_neighbour_update(struct ieee80211_sub_if_data *sdata, | |||
| 494 | struct ieee802_11_elems *elems) | 492 | struct ieee802_11_elems *elems) |
| 495 | { | 493 | { |
| 496 | struct sta_info *sta; | 494 | struct sta_info *sta; |
| 495 | u32 changed = 0; | ||
| 497 | 496 | ||
| 498 | sta = mesh_sta_info_get(sdata, hw_addr, elems); | 497 | sta = mesh_sta_info_get(sdata, hw_addr, elems); |
| 499 | if (!sta) | 498 | if (!sta) |
| @@ -504,11 +503,12 @@ void mesh_neighbour_update(struct ieee80211_sub_if_data *sdata, | |||
| 504 | sdata->u.mesh.accepting_plinks && | 503 | sdata->u.mesh.accepting_plinks && |
| 505 | sdata->u.mesh.mshcfg.auto_open_plinks && | 504 | sdata->u.mesh.mshcfg.auto_open_plinks && |
| 506 | rssi_threshold_check(sta, sdata)) | 505 | rssi_threshold_check(sta, sdata)) |
| 507 | mesh_plink_open(sta); | 506 | changed = mesh_plink_open(sta); |
| 508 | 507 | ||
| 509 | ieee80211_mps_frame_release(sta, elems); | 508 | ieee80211_mps_frame_release(sta, elems); |
| 510 | out: | 509 | out: |
| 511 | rcu_read_unlock(); | 510 | rcu_read_unlock(); |
| 511 | ieee80211_mbss_info_change_notify(sdata, changed); | ||
| 512 | } | 512 | } |
| 513 | 513 | ||
| 514 | static void mesh_plink_timer(unsigned long data) | 514 | static void mesh_plink_timer(unsigned long data) |
| @@ -621,13 +621,14 @@ static inline void mesh_plink_timer_set(struct sta_info *sta, int timeout) | |||
| 621 | add_timer(&sta->plink_timer); | 621 | add_timer(&sta->plink_timer); |
| 622 | } | 622 | } |
| 623 | 623 | ||
| 624 | int mesh_plink_open(struct sta_info *sta) | 624 | u32 mesh_plink_open(struct sta_info *sta) |
| 625 | { | 625 | { |
| 626 | __le16 llid; | 626 | __le16 llid; |
| 627 | struct ieee80211_sub_if_data *sdata = sta->sdata; | 627 | struct ieee80211_sub_if_data *sdata = sta->sdata; |
| 628 | u32 changed; | ||
| 628 | 629 | ||
| 629 | if (!test_sta_flag(sta, WLAN_STA_AUTH)) | 630 | if (!test_sta_flag(sta, WLAN_STA_AUTH)) |
| 630 | return -EPERM; | 631 | return 0; |
| 631 | 632 | ||
| 632 | spin_lock_bh(&sta->lock); | 633 | spin_lock_bh(&sta->lock); |
| 633 | get_random_bytes(&llid, 2); | 634 | get_random_bytes(&llid, 2); |
| @@ -635,7 +636,7 @@ int mesh_plink_open(struct sta_info *sta) | |||
| 635 | if (sta->plink_state != NL80211_PLINK_LISTEN && | 636 | if (sta->plink_state != NL80211_PLINK_LISTEN && |
| 636 | sta->plink_state != NL80211_PLINK_BLOCKED) { | 637 | sta->plink_state != NL80211_PLINK_BLOCKED) { |
| 637 | spin_unlock_bh(&sta->lock); | 638 | spin_unlock_bh(&sta->lock); |
| 638 | return -EBUSY; | 639 | return 0; |
| 639 | } | 640 | } |
| 640 | sta->plink_state = NL80211_PLINK_OPN_SNT; | 641 | sta->plink_state = NL80211_PLINK_OPN_SNT; |
| 641 | mesh_plink_timer_set(sta, sdata->u.mesh.mshcfg.dot11MeshRetryTimeout); | 642 | mesh_plink_timer_set(sta, sdata->u.mesh.mshcfg.dot11MeshRetryTimeout); |
| @@ -645,15 +646,15 @@ int mesh_plink_open(struct sta_info *sta) | |||
| 645 | sta->sta.addr); | 646 | sta->sta.addr); |
| 646 | 647 | ||
| 647 | /* set the non-peer mode to active during peering */ | 648 | /* set the non-peer mode to active during peering */ |
| 648 | ieee80211_mps_local_status_update(sdata); | 649 | changed = ieee80211_mps_local_status_update(sdata); |
| 649 | 650 | ||
| 650 | return mesh_plink_frame_tx(sdata, WLAN_SP_MESH_PEERING_OPEN, | 651 | mesh_plink_frame_tx(sdata, WLAN_SP_MESH_PEERING_OPEN, |
| 651 | sta->sta.addr, llid, 0, 0); | 652 | sta->sta.addr, llid, 0, 0); |
| 653 | return changed; | ||
| 652 | } | 654 | } |
| 653 | 655 | ||
| 654 | void mesh_plink_block(struct sta_info *sta) | 656 | u32 mesh_plink_block(struct sta_info *sta) |
| 655 | { | 657 | { |
| 656 | struct ieee80211_sub_if_data *sdata = sta->sdata; | ||
| 657 | u32 changed; | 658 | u32 changed; |
| 658 | 659 | ||
| 659 | spin_lock_bh(&sta->lock); | 660 | spin_lock_bh(&sta->lock); |
| @@ -661,7 +662,7 @@ void mesh_plink_block(struct sta_info *sta) | |||
| 661 | sta->plink_state = NL80211_PLINK_BLOCKED; | 662 | sta->plink_state = NL80211_PLINK_BLOCKED; |
| 662 | spin_unlock_bh(&sta->lock); | 663 | spin_unlock_bh(&sta->lock); |
| 663 | 664 | ||
| 664 | ieee80211_bss_info_change_notify(sdata, changed); | 665 | return changed; |
| 665 | } | 666 | } |
| 666 | 667 | ||
| 667 | 668 | ||
| @@ -882,7 +883,7 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m | |||
| 882 | mshcfg->dot11MeshRetryTimeout); | 883 | mshcfg->dot11MeshRetryTimeout); |
| 883 | 884 | ||
| 884 | /* set the non-peer mode to active during peering */ | 885 | /* set the non-peer mode to active during peering */ |
| 885 | ieee80211_mps_local_status_update(sdata); | 886 | changed |= ieee80211_mps_local_status_update(sdata); |
| 886 | 887 | ||
| 887 | spin_unlock_bh(&sta->lock); | 888 | spin_unlock_bh(&sta->lock); |
| 888 | mesh_plink_frame_tx(sdata, | 889 | mesh_plink_frame_tx(sdata, |
| @@ -978,7 +979,7 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m | |||
| 978 | mpl_dbg(sdata, "Mesh plink with %pM ESTABLISHED\n", | 979 | mpl_dbg(sdata, "Mesh plink with %pM ESTABLISHED\n", |
| 979 | sta->sta.addr); | 980 | sta->sta.addr); |
| 980 | ieee80211_mps_sta_status_update(sta); | 981 | ieee80211_mps_sta_status_update(sta); |
| 981 | ieee80211_mps_set_sta_local_pm(sta, | 982 | changed |= ieee80211_mps_set_sta_local_pm(sta, |
| 982 | mshcfg->power_mode); | 983 | mshcfg->power_mode); |
| 983 | break; | 984 | break; |
| 984 | default: | 985 | default: |
| @@ -1020,8 +1021,8 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m | |||
| 1020 | WLAN_SP_MESH_PEERING_CONFIRM, | 1021 | WLAN_SP_MESH_PEERING_CONFIRM, |
| 1021 | sta->sta.addr, llid, plid, 0); | 1022 | sta->sta.addr, llid, plid, 0); |
| 1022 | ieee80211_mps_sta_status_update(sta); | 1023 | ieee80211_mps_sta_status_update(sta); |
| 1023 | ieee80211_mps_set_sta_local_pm(sta, | 1024 | changed |= ieee80211_mps_set_sta_local_pm(sta, |
| 1024 | mshcfg->power_mode); | 1025 | mshcfg->power_mode); |
| 1025 | break; | 1026 | break; |
| 1026 | default: | 1027 | default: |
| 1027 | spin_unlock_bh(&sta->lock); | 1028 | spin_unlock_bh(&sta->lock); |
| @@ -1089,5 +1090,5 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m | |||
| 1089 | rcu_read_unlock(); | 1090 | rcu_read_unlock(); |
| 1090 | 1091 | ||
| 1091 | if (changed) | 1092 | if (changed) |
| 1092 | ieee80211_bss_info_change_notify(sdata, changed); | 1093 | ieee80211_mbss_info_change_notify(sdata, changed); |
| 1093 | } | 1094 | } |
diff --git a/net/mac80211/mesh_ps.c b/net/mac80211/mesh_ps.c index b677962525ed..3b7bfc01ee36 100644 --- a/net/mac80211/mesh_ps.c +++ b/net/mac80211/mesh_ps.c | |||
| @@ -74,14 +74,17 @@ static void mps_qos_null_tx(struct sta_info *sta) | |||
| 74 | * @sdata: local mesh subif | 74 | * @sdata: local mesh subif |
| 75 | * | 75 | * |
| 76 | * sets the non-peer power mode and triggers the driver PS (re-)configuration | 76 | * sets the non-peer power mode and triggers the driver PS (re-)configuration |
| 77 | * Return BSS_CHANGED_BEACON if a beacon update is necessary. | ||
| 77 | */ | 78 | */ |
| 78 | void ieee80211_mps_local_status_update(struct ieee80211_sub_if_data *sdata) | 79 | u32 ieee80211_mps_local_status_update(struct ieee80211_sub_if_data *sdata) |
| 79 | { | 80 | { |
| 80 | struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; | 81 | struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; |
| 81 | struct sta_info *sta; | 82 | struct sta_info *sta; |
| 82 | bool peering = false; | 83 | bool peering = false; |
| 83 | int light_sleep_cnt = 0; | 84 | int light_sleep_cnt = 0; |
| 84 | int deep_sleep_cnt = 0; | 85 | int deep_sleep_cnt = 0; |
| 86 | u32 changed = 0; | ||
| 87 | enum nl80211_mesh_power_mode nonpeer_pm; | ||
| 85 | 88 | ||
| 86 | rcu_read_lock(); | 89 | rcu_read_lock(); |
| 87 | list_for_each_entry_rcu(sta, &sdata->local->sta_list, list) { | 90 | list_for_each_entry_rcu(sta, &sdata->local->sta_list, list) { |
| @@ -115,17 +118,26 @@ void ieee80211_mps_local_status_update(struct ieee80211_sub_if_data *sdata) | |||
| 115 | */ | 118 | */ |
| 116 | if (peering) { | 119 | if (peering) { |
| 117 | mps_dbg(sdata, "setting non-peer PM to active for peering\n"); | 120 | mps_dbg(sdata, "setting non-peer PM to active for peering\n"); |
| 118 | ifmsh->nonpeer_pm = NL80211_MESH_POWER_ACTIVE; | 121 | nonpeer_pm = NL80211_MESH_POWER_ACTIVE; |
| 119 | } else if (light_sleep_cnt || deep_sleep_cnt) { | 122 | } else if (light_sleep_cnt || deep_sleep_cnt) { |
| 120 | mps_dbg(sdata, "setting non-peer PM to deep sleep\n"); | 123 | mps_dbg(sdata, "setting non-peer PM to deep sleep\n"); |
| 121 | ifmsh->nonpeer_pm = NL80211_MESH_POWER_DEEP_SLEEP; | 124 | nonpeer_pm = NL80211_MESH_POWER_DEEP_SLEEP; |
| 122 | } else { | 125 | } else { |
| 123 | mps_dbg(sdata, "setting non-peer PM to user value\n"); | 126 | mps_dbg(sdata, "setting non-peer PM to user value\n"); |
| 124 | ifmsh->nonpeer_pm = ifmsh->mshcfg.power_mode; | 127 | nonpeer_pm = ifmsh->mshcfg.power_mode; |
| 125 | } | 128 | } |
| 126 | 129 | ||
| 130 | /* need update if sleep counts move between 0 and non-zero */ | ||
| 131 | if (ifmsh->nonpeer_pm != nonpeer_pm || | ||
| 132 | !ifmsh->ps_peers_light_sleep != !light_sleep_cnt || | ||
| 133 | !ifmsh->ps_peers_deep_sleep != !deep_sleep_cnt) | ||
| 134 | changed = BSS_CHANGED_BEACON; | ||
| 135 | |||
| 136 | ifmsh->nonpeer_pm = nonpeer_pm; | ||
| 127 | ifmsh->ps_peers_light_sleep = light_sleep_cnt; | 137 | ifmsh->ps_peers_light_sleep = light_sleep_cnt; |
| 128 | ifmsh->ps_peers_deep_sleep = deep_sleep_cnt; | 138 | ifmsh->ps_peers_deep_sleep = deep_sleep_cnt; |
| 139 | |||
| 140 | return changed; | ||
| 129 | } | 141 | } |
| 130 | 142 | ||
| 131 | /** | 143 | /** |
| @@ -133,9 +145,10 @@ void ieee80211_mps_local_status_update(struct ieee80211_sub_if_data *sdata) | |||
| 133 | * | 145 | * |
| 134 | * @sta: mesh STA | 146 | * @sta: mesh STA |
| 135 | * @pm: the power mode to set | 147 | * @pm: the power mode to set |
| 148 | * Return BSS_CHANGED_BEACON if a beacon update is in order. | ||
| 136 | */ | 149 | */ |
| 137 | void ieee80211_mps_set_sta_local_pm(struct sta_info *sta, | 150 | u32 ieee80211_mps_set_sta_local_pm(struct sta_info *sta, |
| 138 | enum nl80211_mesh_power_mode pm) | 151 | enum nl80211_mesh_power_mode pm) |
| 139 | { | 152 | { |
| 140 | struct ieee80211_sub_if_data *sdata = sta->sdata; | 153 | struct ieee80211_sub_if_data *sdata = sta->sdata; |
| 141 | 154 | ||
| @@ -151,7 +164,7 @@ void ieee80211_mps_set_sta_local_pm(struct sta_info *sta, | |||
| 151 | if (sta->plink_state == NL80211_PLINK_ESTAB) | 164 | if (sta->plink_state == NL80211_PLINK_ESTAB) |
| 152 | mps_qos_null_tx(sta); | 165 | mps_qos_null_tx(sta); |
| 153 | 166 | ||
| 154 | ieee80211_mps_local_status_update(sdata); | 167 | return ieee80211_mps_local_status_update(sdata); |
| 155 | } | 168 | } |
| 156 | 169 | ||
| 157 | /** | 170 | /** |
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 6e9de6f31d1c..9f6464f3e05f 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c | |||
| @@ -114,6 +114,9 @@ enum rx_mgmt_action { | |||
| 114 | 114 | ||
| 115 | /* caller must call cfg80211_send_assoc_timeout() */ | 115 | /* caller must call cfg80211_send_assoc_timeout() */ |
| 116 | RX_MGMT_CFG80211_ASSOC_TIMEOUT, | 116 | RX_MGMT_CFG80211_ASSOC_TIMEOUT, |
| 117 | |||
| 118 | /* used when a processed beacon causes a deauth */ | ||
| 119 | RX_MGMT_CFG80211_TX_DEAUTH, | ||
| 117 | }; | 120 | }; |
| 118 | 121 | ||
| 119 | /* utils */ | 122 | /* utils */ |
| @@ -174,79 +177,331 @@ static int ecw2cw(int ecw) | |||
| 174 | return (1 << ecw) - 1; | 177 | return (1 << ecw) - 1; |
| 175 | } | 178 | } |
| 176 | 179 | ||
| 177 | static u32 ieee80211_config_ht_tx(struct ieee80211_sub_if_data *sdata, | 180 | static u32 chandef_downgrade(struct cfg80211_chan_def *c) |
| 178 | struct ieee80211_ht_operation *ht_oper, | 181 | { |
| 179 | const u8 *bssid, bool reconfig) | 182 | u32 ret; |
| 183 | int tmp; | ||
| 184 | |||
| 185 | switch (c->width) { | ||
| 186 | case NL80211_CHAN_WIDTH_20: | ||
| 187 | c->width = NL80211_CHAN_WIDTH_20_NOHT; | ||
| 188 | ret = IEEE80211_STA_DISABLE_HT | IEEE80211_STA_DISABLE_VHT; | ||
| 189 | break; | ||
| 190 | case NL80211_CHAN_WIDTH_40: | ||
| 191 | c->width = NL80211_CHAN_WIDTH_20; | ||
| 192 | c->center_freq1 = c->chan->center_freq; | ||
| 193 | ret = IEEE80211_STA_DISABLE_40MHZ | | ||
| 194 | IEEE80211_STA_DISABLE_VHT; | ||
| 195 | break; | ||
| 196 | case NL80211_CHAN_WIDTH_80: | ||
| 197 | tmp = (30 + c->chan->center_freq - c->center_freq1)/20; | ||
| 198 | /* n_P40 */ | ||
| 199 | tmp /= 2; | ||
| 200 | /* freq_P40 */ | ||
| 201 | c->center_freq1 = c->center_freq1 - 20 + 40 * tmp; | ||
| 202 | c->width = NL80211_CHAN_WIDTH_40; | ||
| 203 | ret = IEEE80211_STA_DISABLE_VHT; | ||
| 204 | break; | ||
| 205 | case NL80211_CHAN_WIDTH_80P80: | ||
| 206 | c->center_freq2 = 0; | ||
| 207 | c->width = NL80211_CHAN_WIDTH_80; | ||
| 208 | ret = IEEE80211_STA_DISABLE_80P80MHZ | | ||
| 209 | IEEE80211_STA_DISABLE_160MHZ; | ||
| 210 | break; | ||
| 211 | case NL80211_CHAN_WIDTH_160: | ||
| 212 | /* n_P20 */ | ||
| 213 | tmp = (70 + c->chan->center_freq - c->center_freq1)/20; | ||
| 214 | /* n_P80 */ | ||
| 215 | tmp /= 4; | ||
| 216 | c->center_freq1 = c->center_freq1 - 40 + 80 * tmp; | ||
| 217 | c->width = NL80211_CHAN_WIDTH_80; | ||
| 218 | ret = IEEE80211_STA_DISABLE_80P80MHZ | | ||
| 219 | IEEE80211_STA_DISABLE_160MHZ; | ||
| 220 | break; | ||
| 221 | default: | ||
| 222 | case NL80211_CHAN_WIDTH_20_NOHT: | ||
| 223 | WARN_ON_ONCE(1); | ||
| 224 | c->width = NL80211_CHAN_WIDTH_20_NOHT; | ||
| 225 | ret = IEEE80211_STA_DISABLE_HT | IEEE80211_STA_DISABLE_VHT; | ||
| 226 | break; | ||
| 227 | } | ||
| 228 | |||
| 229 | WARN_ON_ONCE(!cfg80211_chandef_valid(c)); | ||
| 230 | |||
| 231 | return ret; | ||
| 232 | } | ||
| 233 | |||
| 234 | static u32 | ||
| 235 | ieee80211_determine_chantype(struct ieee80211_sub_if_data *sdata, | ||
| 236 | struct ieee80211_supported_band *sband, | ||
| 237 | struct ieee80211_channel *channel, | ||
| 238 | const struct ieee80211_ht_operation *ht_oper, | ||
| 239 | const struct ieee80211_vht_operation *vht_oper, | ||
| 240 | struct cfg80211_chan_def *chandef, bool verbose) | ||
| 241 | { | ||
| 242 | struct cfg80211_chan_def vht_chandef; | ||
| 243 | u32 ht_cfreq, ret; | ||
| 244 | |||
| 245 | chandef->chan = channel; | ||
| 246 | chandef->width = NL80211_CHAN_WIDTH_20_NOHT; | ||
| 247 | chandef->center_freq1 = channel->center_freq; | ||
| 248 | chandef->center_freq2 = 0; | ||
| 249 | |||
| 250 | if (!ht_oper || !sband->ht_cap.ht_supported) { | ||
| 251 | ret = IEEE80211_STA_DISABLE_HT | IEEE80211_STA_DISABLE_VHT; | ||
| 252 | goto out; | ||
| 253 | } | ||
| 254 | |||
| 255 | chandef->width = NL80211_CHAN_WIDTH_20; | ||
| 256 | |||
| 257 | ht_cfreq = ieee80211_channel_to_frequency(ht_oper->primary_chan, | ||
| 258 | channel->band); | ||
| 259 | /* check that channel matches the right operating channel */ | ||
| 260 | if (channel->center_freq != ht_cfreq) { | ||
| 261 | /* | ||
| 262 | * It's possible that some APs are confused here; | ||
| 263 | * Netgear WNDR3700 sometimes reports 4 higher than | ||
| 264 | * the actual channel in association responses, but | ||
| 265 | * since we look at probe response/beacon data here | ||
| 266 | * it should be OK. | ||
| 267 | */ | ||
| 268 | if (verbose) | ||
| 269 | sdata_info(sdata, | ||
| 270 | "Wrong control channel: center-freq: %d ht-cfreq: %d ht->primary_chan: %d band: %d - Disabling HT\n", | ||
| 271 | channel->center_freq, ht_cfreq, | ||
| 272 | ht_oper->primary_chan, channel->band); | ||
| 273 | ret = IEEE80211_STA_DISABLE_HT | IEEE80211_STA_DISABLE_VHT; | ||
| 274 | goto out; | ||
| 275 | } | ||
| 276 | |||
| 277 | /* check 40 MHz support, if we have it */ | ||
| 278 | if (sband->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) { | ||
| 279 | switch (ht_oper->ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET) { | ||
| 280 | case IEEE80211_HT_PARAM_CHA_SEC_ABOVE: | ||
| 281 | chandef->width = NL80211_CHAN_WIDTH_40; | ||
| 282 | chandef->center_freq1 += 10; | ||
| 283 | break; | ||
| 284 | case IEEE80211_HT_PARAM_CHA_SEC_BELOW: | ||
| 285 | chandef->width = NL80211_CHAN_WIDTH_40; | ||
| 286 | chandef->center_freq1 -= 10; | ||
| 287 | break; | ||
| 288 | } | ||
| 289 | } else { | ||
| 290 | /* 40 MHz (and 80 MHz) must be supported for VHT */ | ||
| 291 | ret = IEEE80211_STA_DISABLE_VHT; | ||
| 292 | goto out; | ||
| 293 | } | ||
| 294 | |||
| 295 | if (!vht_oper || !sband->vht_cap.vht_supported) { | ||
| 296 | ret = IEEE80211_STA_DISABLE_VHT; | ||
| 297 | goto out; | ||
| 298 | } | ||
| 299 | |||
| 300 | vht_chandef.chan = channel; | ||
| 301 | vht_chandef.center_freq1 = | ||
| 302 | ieee80211_channel_to_frequency(vht_oper->center_freq_seg1_idx, | ||
| 303 | channel->band); | ||
| 304 | vht_chandef.center_freq2 = 0; | ||
| 305 | |||
| 306 | if (vht_oper->center_freq_seg2_idx) | ||
| 307 | vht_chandef.center_freq2 = | ||
| 308 | ieee80211_channel_to_frequency( | ||
| 309 | vht_oper->center_freq_seg2_idx, | ||
| 310 | channel->band); | ||
| 311 | |||
| 312 | switch (vht_oper->chan_width) { | ||
| 313 | case IEEE80211_VHT_CHANWIDTH_USE_HT: | ||
| 314 | vht_chandef.width = chandef->width; | ||
| 315 | break; | ||
| 316 | case IEEE80211_VHT_CHANWIDTH_80MHZ: | ||
| 317 | vht_chandef.width = NL80211_CHAN_WIDTH_80; | ||
| 318 | break; | ||
| 319 | case IEEE80211_VHT_CHANWIDTH_160MHZ: | ||
| 320 | vht_chandef.width = NL80211_CHAN_WIDTH_160; | ||
| 321 | break; | ||
| 322 | case IEEE80211_VHT_CHANWIDTH_80P80MHZ: | ||
| 323 | vht_chandef.width = NL80211_CHAN_WIDTH_80P80; | ||
| 324 | break; | ||
| 325 | default: | ||
| 326 | if (verbose) | ||
| 327 | sdata_info(sdata, | ||
| 328 | "AP VHT operation IE has invalid channel width (%d), disable VHT\n", | ||
| 329 | vht_oper->chan_width); | ||
| 330 | ret = IEEE80211_STA_DISABLE_VHT; | ||
| 331 | goto out; | ||
| 332 | } | ||
| 333 | |||
| 334 | if (!cfg80211_chandef_valid(&vht_chandef)) { | ||
| 335 | if (verbose) | ||
| 336 | sdata_info(sdata, | ||
| 337 | "AP VHT information is invalid, disable VHT\n"); | ||
| 338 | ret = IEEE80211_STA_DISABLE_VHT; | ||
| 339 | goto out; | ||
| 340 | } | ||
| 341 | |||
| 342 | if (cfg80211_chandef_identical(chandef, &vht_chandef)) { | ||
| 343 | ret = 0; | ||
| 344 | goto out; | ||
| 345 | } | ||
| 346 | |||
| 347 | if (!cfg80211_chandef_compatible(chandef, &vht_chandef)) { | ||
| 348 | if (verbose) | ||
| 349 | sdata_info(sdata, | ||
| 350 | "AP VHT information doesn't match HT, disable VHT\n"); | ||
| 351 | ret = IEEE80211_STA_DISABLE_VHT; | ||
| 352 | goto out; | ||
| 353 | } | ||
| 354 | |||
| 355 | *chandef = vht_chandef; | ||
| 356 | |||
| 357 | ret = 0; | ||
| 358 | |||
| 359 | out: | ||
| 360 | /* don't print the message below for VHT mismatch if VHT is disabled */ | ||
| 361 | if (ret & IEEE80211_STA_DISABLE_VHT) | ||
| 362 | vht_chandef = *chandef; | ||
| 363 | |||
| 364 | while (!cfg80211_chandef_usable(sdata->local->hw.wiphy, chandef, | ||
| 365 | IEEE80211_CHAN_DISABLED)) { | ||
| 366 | if (WARN_ON(chandef->width == NL80211_CHAN_WIDTH_20_NOHT)) { | ||
| 367 | ret = IEEE80211_STA_DISABLE_HT | | ||
| 368 | IEEE80211_STA_DISABLE_VHT; | ||
| 369 | goto out; | ||
| 370 | } | ||
| 371 | |||
| 372 | ret |= chandef_downgrade(chandef); | ||
| 373 | } | ||
| 374 | |||
| 375 | if (chandef->width != vht_chandef.width && verbose) | ||
| 376 | sdata_info(sdata, | ||
| 377 | "capabilities/regulatory prevented using AP HT/VHT configuration, downgraded\n"); | ||
| 378 | |||
| 379 | WARN_ON_ONCE(!cfg80211_chandef_valid(chandef)); | ||
| 380 | return ret; | ||
| 381 | } | ||
| 382 | |||
| 383 | static int ieee80211_config_bw(struct ieee80211_sub_if_data *sdata, | ||
| 384 | struct sta_info *sta, | ||
| 385 | const struct ieee80211_ht_operation *ht_oper, | ||
| 386 | const struct ieee80211_vht_operation *vht_oper, | ||
| 387 | const u8 *bssid, u32 *changed) | ||
| 180 | { | 388 | { |
| 181 | struct ieee80211_local *local = sdata->local; | 389 | struct ieee80211_local *local = sdata->local; |
| 390 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | ||
| 182 | struct ieee80211_supported_band *sband; | 391 | struct ieee80211_supported_band *sband; |
| 183 | struct ieee80211_chanctx_conf *chanctx_conf; | ||
| 184 | struct ieee80211_channel *chan; | 392 | struct ieee80211_channel *chan; |
| 185 | struct sta_info *sta; | 393 | struct cfg80211_chan_def chandef; |
| 186 | u32 changed = 0; | ||
| 187 | u16 ht_opmode; | 394 | u16 ht_opmode; |
| 188 | bool disable_40 = false; | 395 | u32 flags; |
| 396 | enum ieee80211_sta_rx_bandwidth new_sta_bw; | ||
| 397 | int ret; | ||
| 189 | 398 | ||
| 190 | rcu_read_lock(); | 399 | /* if HT was/is disabled, don't track any bandwidth changes */ |
| 191 | chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); | 400 | if (ifmgd->flags & IEEE80211_STA_DISABLE_HT || !ht_oper) |
| 192 | if (WARN_ON(!chanctx_conf)) { | ||
| 193 | rcu_read_unlock(); | ||
| 194 | return 0; | 401 | return 0; |
| 195 | } | 402 | |
| 196 | chan = chanctx_conf->def.chan; | 403 | /* don't check VHT if we associated as non-VHT station */ |
| 197 | rcu_read_unlock(); | 404 | if (ifmgd->flags & IEEE80211_STA_DISABLE_VHT) |
| 405 | vht_oper = NULL; | ||
| 406 | |||
| 407 | if (WARN_ON_ONCE(!sta)) | ||
| 408 | return -EINVAL; | ||
| 409 | |||
| 410 | chan = sdata->vif.bss_conf.chandef.chan; | ||
| 198 | sband = local->hw.wiphy->bands[chan->band]; | 411 | sband = local->hw.wiphy->bands[chan->band]; |
| 199 | 412 | ||
| 200 | switch (sdata->vif.bss_conf.chandef.width) { | 413 | /* calculate new channel (type) based on HT/VHT operation IEs */ |
| 414 | flags = ieee80211_determine_chantype(sdata, sband, chan, ht_oper, | ||
| 415 | vht_oper, &chandef, false); | ||
| 416 | |||
| 417 | /* | ||
| 418 | * Downgrade the new channel if we associated with restricted | ||
| 419 | * capabilities. For example, if we associated as a 20 MHz STA | ||
| 420 | * to a 40 MHz AP (due to regulatory, capabilities or config | ||
| 421 | * reasons) then switching to a 40 MHz channel now won't do us | ||
| 422 | * any good -- we couldn't use it with the AP. | ||
| 423 | */ | ||
| 424 | if (ifmgd->flags & IEEE80211_STA_DISABLE_80P80MHZ && | ||
| 425 | chandef.width == NL80211_CHAN_WIDTH_80P80) | ||
| 426 | flags |= chandef_downgrade(&chandef); | ||
| 427 | if (ifmgd->flags & IEEE80211_STA_DISABLE_160MHZ && | ||
| 428 | chandef.width == NL80211_CHAN_WIDTH_160) | ||
| 429 | flags |= chandef_downgrade(&chandef); | ||
| 430 | if (ifmgd->flags & IEEE80211_STA_DISABLE_40MHZ && | ||
| 431 | chandef.width > NL80211_CHAN_WIDTH_20) | ||
| 432 | flags |= chandef_downgrade(&chandef); | ||
| 433 | |||
| 434 | if (cfg80211_chandef_identical(&chandef, &sdata->vif.bss_conf.chandef)) | ||
| 435 | return 0; | ||
| 436 | |||
| 437 | sdata_info(sdata, | ||
| 438 | "AP %pM changed bandwidth, new config is %d MHz, width %d (%d/%d MHz)\n", | ||
| 439 | ifmgd->bssid, chandef.chan->center_freq, chandef.width, | ||
| 440 | chandef.center_freq1, chandef.center_freq2); | ||
| 441 | |||
| 442 | if (flags != (ifmgd->flags & (IEEE80211_STA_DISABLE_HT | | ||
| 443 | IEEE80211_STA_DISABLE_VHT | | ||
| 444 | IEEE80211_STA_DISABLE_40MHZ | | ||
| 445 | IEEE80211_STA_DISABLE_80P80MHZ | | ||
| 446 | IEEE80211_STA_DISABLE_160MHZ)) || | ||
| 447 | !cfg80211_chandef_valid(&chandef)) { | ||
| 448 | sdata_info(sdata, | ||
| 449 | "AP %pM changed bandwidth in a way we can't support - disconnect\n", | ||
| 450 | ifmgd->bssid); | ||
| 451 | return -EINVAL; | ||
| 452 | } | ||
| 453 | |||
| 454 | switch (chandef.width) { | ||
| 455 | case NL80211_CHAN_WIDTH_20_NOHT: | ||
| 456 | case NL80211_CHAN_WIDTH_20: | ||
| 457 | new_sta_bw = IEEE80211_STA_RX_BW_20; | ||
| 458 | break; | ||
| 201 | case NL80211_CHAN_WIDTH_40: | 459 | case NL80211_CHAN_WIDTH_40: |
| 202 | if (sdata->vif.bss_conf.chandef.chan->center_freq > | 460 | new_sta_bw = IEEE80211_STA_RX_BW_40; |
| 203 | sdata->vif.bss_conf.chandef.center_freq1 && | ||
| 204 | chan->flags & IEEE80211_CHAN_NO_HT40MINUS) | ||
| 205 | disable_40 = true; | ||
| 206 | if (sdata->vif.bss_conf.chandef.chan->center_freq < | ||
| 207 | sdata->vif.bss_conf.chandef.center_freq1 && | ||
| 208 | chan->flags & IEEE80211_CHAN_NO_HT40PLUS) | ||
| 209 | disable_40 = true; | ||
| 210 | break; | 461 | break; |
| 211 | default: | 462 | case NL80211_CHAN_WIDTH_80: |
| 463 | new_sta_bw = IEEE80211_STA_RX_BW_80; | ||
| 464 | break; | ||
| 465 | case NL80211_CHAN_WIDTH_80P80: | ||
| 466 | case NL80211_CHAN_WIDTH_160: | ||
| 467 | new_sta_bw = IEEE80211_STA_RX_BW_160; | ||
| 212 | break; | 468 | break; |
| 469 | default: | ||
| 470 | return -EINVAL; | ||
| 213 | } | 471 | } |
| 214 | 472 | ||
| 215 | /* This can change during the lifetime of the BSS */ | 473 | if (new_sta_bw > sta->cur_max_bandwidth) |
| 216 | if (!(ht_oper->ht_param & IEEE80211_HT_PARAM_CHAN_WIDTH_ANY)) | 474 | new_sta_bw = sta->cur_max_bandwidth; |
| 217 | disable_40 = true; | ||
| 218 | |||
| 219 | mutex_lock(&local->sta_mtx); | ||
| 220 | sta = sta_info_get(sdata, bssid); | ||
| 221 | |||
| 222 | WARN_ON_ONCE(!sta); | ||
| 223 | |||
| 224 | if (sta && !sta->supports_40mhz) | ||
| 225 | disable_40 = true; | ||
| 226 | 475 | ||
| 227 | if (sta && (!reconfig || | 476 | if (new_sta_bw < sta->sta.bandwidth) { |
| 228 | (disable_40 != !(sta->sta.ht_cap.cap & | 477 | sta->sta.bandwidth = new_sta_bw; |
| 229 | IEEE80211_HT_CAP_SUP_WIDTH_20_40)))) { | 478 | rate_control_rate_update(local, sband, sta, |
| 479 | IEEE80211_RC_BW_CHANGED); | ||
| 480 | } | ||
| 230 | 481 | ||
| 231 | if (disable_40) | 482 | ret = ieee80211_vif_change_bandwidth(sdata, &chandef, changed); |
| 232 | sta->sta.ht_cap.cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40; | 483 | if (ret) { |
| 233 | else | 484 | sdata_info(sdata, |
| 234 | sta->sta.ht_cap.cap |= IEEE80211_HT_CAP_SUP_WIDTH_20_40; | 485 | "AP %pM changed bandwidth to incompatible one - disconnect\n", |
| 486 | ifmgd->bssid); | ||
| 487 | return ret; | ||
| 488 | } | ||
| 235 | 489 | ||
| 490 | if (new_sta_bw > sta->sta.bandwidth) { | ||
| 491 | sta->sta.bandwidth = new_sta_bw; | ||
| 236 | rate_control_rate_update(local, sband, sta, | 492 | rate_control_rate_update(local, sband, sta, |
| 237 | IEEE80211_RC_BW_CHANGED); | 493 | IEEE80211_RC_BW_CHANGED); |
| 238 | } | 494 | } |
| 239 | mutex_unlock(&local->sta_mtx); | ||
| 240 | 495 | ||
| 241 | ht_opmode = le16_to_cpu(ht_oper->operation_mode); | 496 | ht_opmode = le16_to_cpu(ht_oper->operation_mode); |
| 242 | 497 | ||
| 243 | /* if bss configuration changed store the new one */ | 498 | /* if bss configuration changed store the new one */ |
| 244 | if (!reconfig || (sdata->vif.bss_conf.ht_operation_mode != ht_opmode)) { | 499 | if (sdata->vif.bss_conf.ht_operation_mode != ht_opmode) { |
| 245 | changed |= BSS_CHANGED_HT; | 500 | *changed |= BSS_CHANGED_HT; |
| 246 | sdata->vif.bss_conf.ht_operation_mode = ht_opmode; | 501 | sdata->vif.bss_conf.ht_operation_mode = ht_opmode; |
| 247 | } | 502 | } |
| 248 | 503 | ||
| 249 | return changed; | 504 | return 0; |
| 250 | } | 505 | } |
| 251 | 506 | ||
| 252 | /* frame sending functions */ | 507 | /* frame sending functions */ |
| @@ -790,10 +1045,10 @@ static void ieee80211_chswitch_timer(unsigned long data) | |||
| 790 | ieee80211_queue_work(&sdata->local->hw, &ifmgd->chswitch_work); | 1045 | ieee80211_queue_work(&sdata->local->hw, &ifmgd->chswitch_work); |
| 791 | } | 1046 | } |
| 792 | 1047 | ||
| 793 | void ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata, | 1048 | void |
| 794 | struct ieee80211_channel_sw_ie *sw_elem, | 1049 | ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata, |
| 795 | struct ieee80211_bss *bss, | 1050 | const struct ieee80211_channel_sw_ie *sw_elem, |
| 796 | u64 timestamp) | 1051 | struct ieee80211_bss *bss, u64 timestamp) |
| 797 | { | 1052 | { |
| 798 | struct cfg80211_bss *cbss = | 1053 | struct cfg80211_bss *cbss = |
| 799 | container_of((void *)bss, struct cfg80211_bss, priv); | 1054 | container_of((void *)bss, struct cfg80211_bss, priv); |
| @@ -1212,16 +1467,30 @@ void ieee80211_dynamic_ps_timer(unsigned long data) | |||
| 1212 | ieee80211_queue_work(&local->hw, &local->dynamic_ps_enable_work); | 1467 | ieee80211_queue_work(&local->hw, &local->dynamic_ps_enable_work); |
| 1213 | } | 1468 | } |
| 1214 | 1469 | ||
| 1470 | void ieee80211_dfs_cac_timer_work(struct work_struct *work) | ||
| 1471 | { | ||
| 1472 | struct delayed_work *delayed_work = | ||
| 1473 | container_of(work, struct delayed_work, work); | ||
| 1474 | struct ieee80211_sub_if_data *sdata = | ||
| 1475 | container_of(delayed_work, struct ieee80211_sub_if_data, | ||
| 1476 | dfs_cac_timer_work); | ||
| 1477 | |||
| 1478 | ieee80211_vif_release_channel(sdata); | ||
| 1479 | |||
| 1480 | cfg80211_cac_event(sdata->dev, NL80211_RADAR_CAC_FINISHED, GFP_KERNEL); | ||
| 1481 | } | ||
| 1482 | |||
| 1215 | /* MLME */ | 1483 | /* MLME */ |
| 1216 | static bool ieee80211_sta_wmm_params(struct ieee80211_local *local, | 1484 | static bool ieee80211_sta_wmm_params(struct ieee80211_local *local, |
| 1217 | struct ieee80211_sub_if_data *sdata, | 1485 | struct ieee80211_sub_if_data *sdata, |
| 1218 | u8 *wmm_param, size_t wmm_param_len) | 1486 | const u8 *wmm_param, size_t wmm_param_len) |
| 1219 | { | 1487 | { |
| 1220 | struct ieee80211_tx_queue_params params; | 1488 | struct ieee80211_tx_queue_params params; |
| 1221 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | 1489 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
| 1222 | size_t left; | 1490 | size_t left; |
| 1223 | int count; | 1491 | int count; |
| 1224 | u8 *pos, uapsd_queues = 0; | 1492 | const u8 *pos; |
| 1493 | u8 uapsd_queues = 0; | ||
| 1225 | 1494 | ||
| 1226 | if (!local->ops->conf_tx) | 1495 | if (!local->ops->conf_tx) |
| 1227 | return false; | 1496 | return false; |
| @@ -1624,17 +1893,18 @@ void ieee80211_sta_tx_notify(struct ieee80211_sub_if_data *sdata, | |||
| 1624 | if (!ieee80211_is_data(hdr->frame_control)) | 1893 | if (!ieee80211_is_data(hdr->frame_control)) |
| 1625 | return; | 1894 | return; |
| 1626 | 1895 | ||
| 1627 | if (ack) | ||
| 1628 | ieee80211_sta_reset_conn_monitor(sdata); | ||
| 1629 | |||
| 1630 | if (ieee80211_is_nullfunc(hdr->frame_control) && | 1896 | if (ieee80211_is_nullfunc(hdr->frame_control) && |
| 1631 | sdata->u.mgd.probe_send_count > 0) { | 1897 | sdata->u.mgd.probe_send_count > 0) { |
| 1632 | if (ack) | 1898 | if (ack) |
| 1633 | sdata->u.mgd.probe_send_count = 0; | 1899 | ieee80211_sta_reset_conn_monitor(sdata); |
| 1634 | else | 1900 | else |
| 1635 | sdata->u.mgd.nullfunc_failed = true; | 1901 | sdata->u.mgd.nullfunc_failed = true; |
| 1636 | ieee80211_queue_work(&sdata->local->hw, &sdata->work); | 1902 | ieee80211_queue_work(&sdata->local->hw, &sdata->work); |
| 1903 | return; | ||
| 1637 | } | 1904 | } |
| 1905 | |||
| 1906 | if (ack) | ||
| 1907 | ieee80211_sta_reset_conn_monitor(sdata); | ||
| 1638 | } | 1908 | } |
| 1639 | 1909 | ||
| 1640 | static void ieee80211_mgd_probe_ap_send(struct ieee80211_sub_if_data *sdata) | 1910 | static void ieee80211_mgd_probe_ap_send(struct ieee80211_sub_if_data *sdata) |
| @@ -1805,6 +2075,8 @@ static void __ieee80211_disconnect(struct ieee80211_sub_if_data *sdata) | |||
| 1805 | WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY, | 2075 | WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY, |
| 1806 | true, frame_buf); | 2076 | true, frame_buf); |
| 1807 | ifmgd->flags &= ~IEEE80211_STA_CSA_RECEIVED; | 2077 | ifmgd->flags &= ~IEEE80211_STA_CSA_RECEIVED; |
| 2078 | ieee80211_wake_queues_by_reason(&sdata->local->hw, | ||
| 2079 | IEEE80211_QUEUE_STOP_REASON_CSA); | ||
| 1808 | mutex_unlock(&ifmgd->mtx); | 2080 | mutex_unlock(&ifmgd->mtx); |
| 1809 | 2081 | ||
| 1810 | /* | 2082 | /* |
| @@ -1845,8 +2117,6 @@ static void ieee80211_csa_connection_drop_work(struct work_struct *work) | |||
| 1845 | container_of(work, struct ieee80211_sub_if_data, | 2117 | container_of(work, struct ieee80211_sub_if_data, |
| 1846 | u.mgd.csa_connection_drop_work); | 2118 | u.mgd.csa_connection_drop_work); |
| 1847 | 2119 | ||
| 1848 | ieee80211_wake_queues_by_reason(&sdata->local->hw, | ||
| 1849 | IEEE80211_QUEUE_STOP_REASON_CSA); | ||
| 1850 | __ieee80211_disconnect(sdata); | 2120 | __ieee80211_disconnect(sdata); |
| 1851 | } | 2121 | } |
| 1852 | 2122 | ||
| @@ -1986,6 +2256,7 @@ ieee80211_rx_mgmt_auth(struct ieee80211_sub_if_data *sdata, | |||
| 1986 | sdata_info(sdata, "authenticated\n"); | 2256 | sdata_info(sdata, "authenticated\n"); |
| 1987 | ifmgd->auth_data->done = true; | 2257 | ifmgd->auth_data->done = true; |
| 1988 | ifmgd->auth_data->timeout = jiffies + IEEE80211_AUTH_WAIT_ASSOC; | 2258 | ifmgd->auth_data->timeout = jiffies + IEEE80211_AUTH_WAIT_ASSOC; |
| 2259 | ifmgd->auth_data->timeout_started = true; | ||
| 1989 | run_again(ifmgd, ifmgd->auth_data->timeout); | 2260 | run_again(ifmgd, ifmgd->auth_data->timeout); |
| 1990 | 2261 | ||
| 1991 | if (ifmgd->auth_data->algorithm == WLAN_AUTH_SAE && | 2262 | if (ifmgd->auth_data->algorithm == WLAN_AUTH_SAE && |
| @@ -2180,6 +2451,24 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata, | |||
| 2180 | 2451 | ||
| 2181 | ifmgd->aid = aid; | 2452 | ifmgd->aid = aid; |
| 2182 | 2453 | ||
| 2454 | /* | ||
| 2455 | * We previously checked these in the beacon/probe response, so | ||
| 2456 | * they should be present here. This is just a safety net. | ||
| 2457 | */ | ||
| 2458 | if (!(ifmgd->flags & IEEE80211_STA_DISABLE_HT) && | ||
| 2459 | (!elems.wmm_param || !elems.ht_cap_elem || !elems.ht_operation)) { | ||
| 2460 | sdata_info(sdata, | ||
| 2461 | "HT AP is missing WMM params or HT capability/operation in AssocResp\n"); | ||
| 2462 | return false; | ||
| 2463 | } | ||
| 2464 | |||
| 2465 | if (!(ifmgd->flags & IEEE80211_STA_DISABLE_VHT) && | ||
| 2466 | (!elems.vht_cap_elem || !elems.vht_operation)) { | ||
| 2467 | sdata_info(sdata, | ||
| 2468 | "VHT AP is missing VHT capability/operation in AssocResp\n"); | ||
| 2469 | return false; | ||
| 2470 | } | ||
| 2471 | |||
| 2183 | mutex_lock(&sdata->local->sta_mtx); | 2472 | mutex_lock(&sdata->local->sta_mtx); |
| 2184 | /* | 2473 | /* |
| 2185 | * station info was already allocated and inserted before | 2474 | * station info was already allocated and inserted before |
| @@ -2193,17 +2482,36 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata, | |||
| 2193 | 2482 | ||
| 2194 | sband = local->hw.wiphy->bands[ieee80211_get_sdata_band(sdata)]; | 2483 | sband = local->hw.wiphy->bands[ieee80211_get_sdata_band(sdata)]; |
| 2195 | 2484 | ||
| 2485 | /* Set up internal HT/VHT capabilities */ | ||
| 2196 | if (elems.ht_cap_elem && !(ifmgd->flags & IEEE80211_STA_DISABLE_HT)) | 2486 | if (elems.ht_cap_elem && !(ifmgd->flags & IEEE80211_STA_DISABLE_HT)) |
| 2197 | ieee80211_ht_cap_ie_to_sta_ht_cap(sdata, sband, | 2487 | ieee80211_ht_cap_ie_to_sta_ht_cap(sdata, sband, |
| 2198 | elems.ht_cap_elem, &sta->sta.ht_cap); | 2488 | elems.ht_cap_elem, sta); |
| 2199 | |||
| 2200 | sta->supports_40mhz = | ||
| 2201 | sta->sta.ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40; | ||
| 2202 | 2489 | ||
| 2203 | if (elems.vht_cap_elem && !(ifmgd->flags & IEEE80211_STA_DISABLE_VHT)) | 2490 | if (elems.vht_cap_elem && !(ifmgd->flags & IEEE80211_STA_DISABLE_VHT)) |
| 2204 | ieee80211_vht_cap_ie_to_sta_vht_cap(sdata, sband, | 2491 | ieee80211_vht_cap_ie_to_sta_vht_cap(sdata, sband, |
| 2205 | elems.vht_cap_elem, | 2492 | elems.vht_cap_elem, sta); |
| 2206 | &sta->sta.vht_cap); | 2493 | |
| 2494 | /* | ||
| 2495 | * Some APs, e.g. Netgear WNDR3700, report invalid HT operation data | ||
| 2496 | * in their association response, so ignore that data for our own | ||
| 2497 | * configuration. If it changed since the last beacon, we'll get the | ||
| 2498 | * next beacon and update then. | ||
| 2499 | */ | ||
| 2500 | |||
| 2501 | /* | ||
| 2502 | * If an operating mode notification IE is present, override the | ||
| 2503 | * NSS calculation (that would be done in rate_control_rate_init()) | ||
| 2504 | * and use the # of streams from that element. | ||
| 2505 | */ | ||
| 2506 | if (elems.opmode_notif && | ||
| 2507 | !(*elems.opmode_notif & IEEE80211_OPMODE_NOTIF_RX_NSS_TYPE_BF)) { | ||
| 2508 | u8 nss; | ||
| 2509 | |||
| 2510 | nss = *elems.opmode_notif & IEEE80211_OPMODE_NOTIF_RX_NSS_MASK; | ||
| 2511 | nss >>= IEEE80211_OPMODE_NOTIF_RX_NSS_SHIFT; | ||
| 2512 | nss += 1; | ||
| 2513 | sta->sta.rx_nss = nss; | ||
| 2514 | } | ||
| 2207 | 2515 | ||
| 2208 | rate_control_rate_init(sta); | 2516 | rate_control_rate_init(sta); |
| 2209 | 2517 | ||
| @@ -2242,11 +2550,6 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata, | |||
| 2242 | ieee80211_set_wmm_default(sdata, false); | 2550 | ieee80211_set_wmm_default(sdata, false); |
| 2243 | changed |= BSS_CHANGED_QOS; | 2551 | changed |= BSS_CHANGED_QOS; |
| 2244 | 2552 | ||
| 2245 | if (elems.ht_operation && elems.wmm_param && | ||
| 2246 | !(ifmgd->flags & IEEE80211_STA_DISABLE_HT)) | ||
| 2247 | changed |= ieee80211_config_ht_tx(sdata, elems.ht_operation, | ||
| 2248 | cbss->bssid, false); | ||
| 2249 | |||
| 2250 | /* set AID and assoc capability, | 2553 | /* set AID and assoc capability, |
| 2251 | * ieee80211_set_associated() will tell the driver */ | 2554 | * ieee80211_set_associated() will tell the driver */ |
| 2252 | bss_conf->aid = aid; | 2555 | bss_conf->aid = aid; |
| @@ -2320,6 +2623,7 @@ ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, | |||
| 2320 | "%pM rejected association temporarily; comeback duration %u TU (%u ms)\n", | 2623 | "%pM rejected association temporarily; comeback duration %u TU (%u ms)\n", |
| 2321 | mgmt->sa, tu, ms); | 2624 | mgmt->sa, tu, ms); |
| 2322 | assoc_data->timeout = jiffies + msecs_to_jiffies(ms); | 2625 | assoc_data->timeout = jiffies + msecs_to_jiffies(ms); |
| 2626 | assoc_data->timeout_started = true; | ||
| 2323 | if (ms > IEEE80211_ASSOC_TIMEOUT) | 2627 | if (ms > IEEE80211_ASSOC_TIMEOUT) |
| 2324 | run_again(ifmgd, assoc_data->timeout); | 2628 | run_again(ifmgd, assoc_data->timeout); |
| 2325 | return RX_MGMT_NONE; | 2629 | return RX_MGMT_NONE; |
| @@ -2371,7 +2675,7 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, | |||
| 2371 | need_ps = sdata->u.mgd.associated && !sdata->u.mgd.dtim_period; | 2675 | need_ps = sdata->u.mgd.associated && !sdata->u.mgd.dtim_period; |
| 2372 | 2676 | ||
| 2373 | if (elems->tim && !elems->parse_error) { | 2677 | if (elems->tim && !elems->parse_error) { |
| 2374 | struct ieee80211_tim_ie *tim_ie = elems->tim; | 2678 | const struct ieee80211_tim_ie *tim_ie = elems->tim; |
| 2375 | sdata->u.mgd.dtim_period = tim_ie->dtim_period; | 2679 | sdata->u.mgd.dtim_period = tim_ie->dtim_period; |
| 2376 | } | 2680 | } |
| 2377 | } | 2681 | } |
| @@ -2443,6 +2747,7 @@ static void ieee80211_rx_mgmt_probe_resp(struct ieee80211_sub_if_data *sdata, | |||
| 2443 | sdata_info(sdata, "direct probe responded\n"); | 2747 | sdata_info(sdata, "direct probe responded\n"); |
| 2444 | ifmgd->auth_data->tries = 0; | 2748 | ifmgd->auth_data->tries = 0; |
| 2445 | ifmgd->auth_data->timeout = jiffies; | 2749 | ifmgd->auth_data->timeout = jiffies; |
| 2750 | ifmgd->auth_data->timeout_started = true; | ||
| 2446 | run_again(ifmgd, ifmgd->auth_data->timeout); | 2751 | run_again(ifmgd, ifmgd->auth_data->timeout); |
| 2447 | } | 2752 | } |
| 2448 | } | 2753 | } |
| @@ -2468,10 +2773,10 @@ static const u64 care_about_ies = | |||
| 2468 | (1ULL << WLAN_EID_HT_CAPABILITY) | | 2773 | (1ULL << WLAN_EID_HT_CAPABILITY) | |
| 2469 | (1ULL << WLAN_EID_HT_OPERATION); | 2774 | (1ULL << WLAN_EID_HT_OPERATION); |
| 2470 | 2775 | ||
| 2471 | static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, | 2776 | static enum rx_mgmt_action |
| 2472 | struct ieee80211_mgmt *mgmt, | 2777 | ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, |
| 2473 | size_t len, | 2778 | struct ieee80211_mgmt *mgmt, size_t len, |
| 2474 | struct ieee80211_rx_status *rx_status) | 2779 | u8 *deauth_buf, struct ieee80211_rx_status *rx_status) |
| 2475 | { | 2780 | { |
| 2476 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | 2781 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
| 2477 | struct ieee80211_bss_conf *bss_conf = &sdata->vif.bss_conf; | 2782 | struct ieee80211_bss_conf *bss_conf = &sdata->vif.bss_conf; |
| @@ -2480,6 +2785,7 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, | |||
| 2480 | struct ieee80211_local *local = sdata->local; | 2785 | struct ieee80211_local *local = sdata->local; |
| 2481 | struct ieee80211_chanctx_conf *chanctx_conf; | 2786 | struct ieee80211_chanctx_conf *chanctx_conf; |
| 2482 | struct ieee80211_channel *chan; | 2787 | struct ieee80211_channel *chan; |
| 2788 | struct sta_info *sta; | ||
| 2483 | u32 changed = 0; | 2789 | u32 changed = 0; |
| 2484 | bool erp_valid; | 2790 | bool erp_valid; |
| 2485 | u8 erp_value = 0; | 2791 | u8 erp_value = 0; |
| @@ -2491,18 +2797,18 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, | |||
| 2491 | /* Process beacon from the current BSS */ | 2797 | /* Process beacon from the current BSS */ |
| 2492 | baselen = (u8 *) mgmt->u.beacon.variable - (u8 *) mgmt; | 2798 | baselen = (u8 *) mgmt->u.beacon.variable - (u8 *) mgmt; |
| 2493 | if (baselen > len) | 2799 | if (baselen > len) |
| 2494 | return; | 2800 | return RX_MGMT_NONE; |
| 2495 | 2801 | ||
| 2496 | rcu_read_lock(); | 2802 | rcu_read_lock(); |
| 2497 | chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); | 2803 | chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); |
| 2498 | if (!chanctx_conf) { | 2804 | if (!chanctx_conf) { |
| 2499 | rcu_read_unlock(); | 2805 | rcu_read_unlock(); |
| 2500 | return; | 2806 | return RX_MGMT_NONE; |
| 2501 | } | 2807 | } |
| 2502 | 2808 | ||
| 2503 | if (rx_status->freq != chanctx_conf->def.chan->center_freq) { | 2809 | if (rx_status->freq != chanctx_conf->def.chan->center_freq) { |
| 2504 | rcu_read_unlock(); | 2810 | rcu_read_unlock(); |
| 2505 | return; | 2811 | return RX_MGMT_NONE; |
| 2506 | } | 2812 | } |
| 2507 | chan = chanctx_conf->def.chan; | 2813 | chan = chanctx_conf->def.chan; |
| 2508 | rcu_read_unlock(); | 2814 | rcu_read_unlock(); |
| @@ -2528,13 +2834,14 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, | |||
| 2528 | } | 2834 | } |
| 2529 | /* continue assoc process */ | 2835 | /* continue assoc process */ |
| 2530 | ifmgd->assoc_data->timeout = jiffies; | 2836 | ifmgd->assoc_data->timeout = jiffies; |
| 2837 | ifmgd->assoc_data->timeout_started = true; | ||
| 2531 | run_again(ifmgd, ifmgd->assoc_data->timeout); | 2838 | run_again(ifmgd, ifmgd->assoc_data->timeout); |
| 2532 | return; | 2839 | return RX_MGMT_NONE; |
| 2533 | } | 2840 | } |
| 2534 | 2841 | ||
| 2535 | if (!ifmgd->associated || | 2842 | if (!ifmgd->associated || |
| 2536 | !ether_addr_equal(mgmt->bssid, ifmgd->associated->bssid)) | 2843 | !ether_addr_equal(mgmt->bssid, ifmgd->associated->bssid)) |
| 2537 | return; | 2844 | return RX_MGMT_NONE; |
| 2538 | bssid = ifmgd->associated->bssid; | 2845 | bssid = ifmgd->associated->bssid; |
| 2539 | 2846 | ||
| 2540 | /* Track average RSSI from the Beacon frames of the current AP */ | 2847 | /* Track average RSSI from the Beacon frames of the current AP */ |
| @@ -2672,7 +2979,7 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, | |||
| 2672 | } | 2979 | } |
| 2673 | 2980 | ||
| 2674 | if (ncrc == ifmgd->beacon_crc && ifmgd->beacon_crc_valid) | 2981 | if (ncrc == ifmgd->beacon_crc && ifmgd->beacon_crc_valid) |
| 2675 | return; | 2982 | return RX_MGMT_NONE; |
| 2676 | ifmgd->beacon_crc = ncrc; | 2983 | ifmgd->beacon_crc = ncrc; |
| 2677 | ifmgd->beacon_crc_valid = true; | 2984 | ifmgd->beacon_crc_valid = true; |
| 2678 | 2985 | ||
| @@ -2718,11 +3025,22 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, | |||
| 2718 | le16_to_cpu(mgmt->u.beacon.capab_info), | 3025 | le16_to_cpu(mgmt->u.beacon.capab_info), |
| 2719 | erp_valid, erp_value); | 3026 | erp_valid, erp_value); |
| 2720 | 3027 | ||
| 3028 | mutex_lock(&local->sta_mtx); | ||
| 3029 | sta = sta_info_get(sdata, bssid); | ||
| 2721 | 3030 | ||
| 2722 | if (elems.ht_cap_elem && elems.ht_operation && elems.wmm_param && | 3031 | if (ieee80211_config_bw(sdata, sta, elems.ht_operation, |
| 2723 | !(ifmgd->flags & IEEE80211_STA_DISABLE_HT)) | 3032 | elems.vht_operation, bssid, &changed)) { |
| 2724 | changed |= ieee80211_config_ht_tx(sdata, elems.ht_operation, | 3033 | mutex_unlock(&local->sta_mtx); |
| 2725 | bssid, true); | 3034 | ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DEAUTH, |
| 3035 | WLAN_REASON_DEAUTH_LEAVING, | ||
| 3036 | true, deauth_buf); | ||
| 3037 | return RX_MGMT_CFG80211_TX_DEAUTH; | ||
| 3038 | } | ||
| 3039 | |||
| 3040 | if (sta && elems.opmode_notif) | ||
| 3041 | ieee80211_vht_handle_opmode(sdata, sta, *elems.opmode_notif, | ||
| 3042 | rx_status->band, true); | ||
| 3043 | mutex_unlock(&local->sta_mtx); | ||
| 2726 | 3044 | ||
| 2727 | if (elems.country_elem && elems.pwr_constr_elem && | 3045 | if (elems.country_elem && elems.pwr_constr_elem && |
| 2728 | mgmt->u.probe_resp.capab_info & | 3046 | mgmt->u.probe_resp.capab_info & |
| @@ -2733,6 +3051,8 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, | |||
| 2733 | elems.pwr_constr_elem); | 3051 | elems.pwr_constr_elem); |
| 2734 | 3052 | ||
| 2735 | ieee80211_bss_info_change_notify(sdata, changed); | 3053 | ieee80211_bss_info_change_notify(sdata, changed); |
| 3054 | |||
| 3055 | return RX_MGMT_NONE; | ||
| 2736 | } | 3056 | } |
| 2737 | 3057 | ||
| 2738 | void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata, | 3058 | void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata, |
| @@ -2743,6 +3063,7 @@ void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata, | |||
| 2743 | struct ieee80211_mgmt *mgmt; | 3063 | struct ieee80211_mgmt *mgmt; |
| 2744 | struct cfg80211_bss *bss = NULL; | 3064 | struct cfg80211_bss *bss = NULL; |
| 2745 | enum rx_mgmt_action rma = RX_MGMT_NONE; | 3065 | enum rx_mgmt_action rma = RX_MGMT_NONE; |
| 3066 | u8 deauth_buf[IEEE80211_DEAUTH_FRAME_LEN]; | ||
| 2746 | u16 fc; | 3067 | u16 fc; |
| 2747 | 3068 | ||
| 2748 | rx_status = (struct ieee80211_rx_status *) skb->cb; | 3069 | rx_status = (struct ieee80211_rx_status *) skb->cb; |
| @@ -2753,7 +3074,8 @@ void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata, | |||
| 2753 | 3074 | ||
| 2754 | switch (fc & IEEE80211_FCTL_STYPE) { | 3075 | switch (fc & IEEE80211_FCTL_STYPE) { |
| 2755 | case IEEE80211_STYPE_BEACON: | 3076 | case IEEE80211_STYPE_BEACON: |
| 2756 | ieee80211_rx_mgmt_beacon(sdata, mgmt, skb->len, rx_status); | 3077 | rma = ieee80211_rx_mgmt_beacon(sdata, mgmt, skb->len, |
| 3078 | deauth_buf, rx_status); | ||
| 2757 | break; | 3079 | break; |
| 2758 | case IEEE80211_STYPE_PROBE_RESP: | 3080 | case IEEE80211_STYPE_PROBE_RESP: |
| 2759 | ieee80211_rx_mgmt_probe_resp(sdata, skb); | 3081 | ieee80211_rx_mgmt_probe_resp(sdata, skb); |
| @@ -2802,6 +3124,10 @@ void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata, | |||
| 2802 | case RX_MGMT_CFG80211_ASSOC_TIMEOUT: | 3124 | case RX_MGMT_CFG80211_ASSOC_TIMEOUT: |
| 2803 | cfg80211_send_assoc_timeout(sdata->dev, mgmt->bssid); | 3125 | cfg80211_send_assoc_timeout(sdata->dev, mgmt->bssid); |
| 2804 | break; | 3126 | break; |
| 3127 | case RX_MGMT_CFG80211_TX_DEAUTH: | ||
| 3128 | cfg80211_send_deauth(sdata->dev, deauth_buf, | ||
| 3129 | sizeof(deauth_buf)); | ||
| 3130 | break; | ||
| 2805 | default: | 3131 | default: |
| 2806 | WARN(1, "unexpected: %d", rma); | 3132 | WARN(1, "unexpected: %d", rma); |
| 2807 | } | 3133 | } |
| @@ -2920,7 +3246,10 @@ static int ieee80211_probe_auth(struct ieee80211_sub_if_data *sdata) | |||
| 2920 | 3246 | ||
| 2921 | if (!(local->hw.flags & IEEE80211_HW_REPORTS_TX_ACK_STATUS)) { | 3247 | if (!(local->hw.flags & IEEE80211_HW_REPORTS_TX_ACK_STATUS)) { |
| 2922 | auth_data->timeout = jiffies + IEEE80211_AUTH_TIMEOUT; | 3248 | auth_data->timeout = jiffies + IEEE80211_AUTH_TIMEOUT; |
| 3249 | ifmgd->auth_data->timeout_started = true; | ||
| 2923 | run_again(ifmgd, auth_data->timeout); | 3250 | run_again(ifmgd, auth_data->timeout); |
| 3251 | } else { | ||
| 3252 | auth_data->timeout_started = false; | ||
| 2924 | } | 3253 | } |
| 2925 | 3254 | ||
| 2926 | return 0; | 3255 | return 0; |
| @@ -2954,7 +3283,10 @@ static int ieee80211_do_assoc(struct ieee80211_sub_if_data *sdata) | |||
| 2954 | 3283 | ||
| 2955 | if (!(local->hw.flags & IEEE80211_HW_REPORTS_TX_ACK_STATUS)) { | 3284 | if (!(local->hw.flags & IEEE80211_HW_REPORTS_TX_ACK_STATUS)) { |
| 2956 | assoc_data->timeout = jiffies + IEEE80211_ASSOC_TIMEOUT; | 3285 | assoc_data->timeout = jiffies + IEEE80211_ASSOC_TIMEOUT; |
| 3286 | assoc_data->timeout_started = true; | ||
| 2957 | run_again(&sdata->u.mgd, assoc_data->timeout); | 3287 | run_again(&sdata->u.mgd, assoc_data->timeout); |
| 3288 | } else { | ||
| 3289 | assoc_data->timeout_started = false; | ||
| 2958 | } | 3290 | } |
| 2959 | 3291 | ||
| 2960 | return 0; | 3292 | return 0; |
| @@ -2993,6 +3325,7 @@ void ieee80211_sta_work(struct ieee80211_sub_if_data *sdata) | |||
| 2993 | } else { | 3325 | } else { |
| 2994 | ifmgd->auth_data->timeout = jiffies - 1; | 3326 | ifmgd->auth_data->timeout = jiffies - 1; |
| 2995 | } | 3327 | } |
| 3328 | ifmgd->auth_data->timeout_started = true; | ||
| 2996 | } else if (ifmgd->assoc_data && | 3329 | } else if (ifmgd->assoc_data && |
| 2997 | (ieee80211_is_assoc_req(fc) || | 3330 | (ieee80211_is_assoc_req(fc) || |
| 2998 | ieee80211_is_reassoc_req(fc))) { | 3331 | ieee80211_is_reassoc_req(fc))) { |
| @@ -3003,10 +3336,11 @@ void ieee80211_sta_work(struct ieee80211_sub_if_data *sdata) | |||
| 3003 | } else { | 3336 | } else { |
| 3004 | ifmgd->assoc_data->timeout = jiffies - 1; | 3337 | ifmgd->assoc_data->timeout = jiffies - 1; |
| 3005 | } | 3338 | } |
| 3339 | ifmgd->assoc_data->timeout_started = true; | ||
| 3006 | } | 3340 | } |
| 3007 | } | 3341 | } |
| 3008 | 3342 | ||
| 3009 | if (ifmgd->auth_data && | 3343 | if (ifmgd->auth_data && ifmgd->auth_data->timeout_started && |
| 3010 | time_after(jiffies, ifmgd->auth_data->timeout)) { | 3344 | time_after(jiffies, ifmgd->auth_data->timeout)) { |
| 3011 | if (ifmgd->auth_data->done) { | 3345 | if (ifmgd->auth_data->done) { |
| 3012 | /* | 3346 | /* |
| @@ -3025,10 +3359,10 @@ void ieee80211_sta_work(struct ieee80211_sub_if_data *sdata) | |||
| 3025 | cfg80211_send_auth_timeout(sdata->dev, bssid); | 3359 | cfg80211_send_auth_timeout(sdata->dev, bssid); |
| 3026 | mutex_lock(&ifmgd->mtx); | 3360 | mutex_lock(&ifmgd->mtx); |
| 3027 | } | 3361 | } |
| 3028 | } else if (ifmgd->auth_data) | 3362 | } else if (ifmgd->auth_data && ifmgd->auth_data->timeout_started) |
| 3029 | run_again(ifmgd, ifmgd->auth_data->timeout); | 3363 | run_again(ifmgd, ifmgd->auth_data->timeout); |
| 3030 | 3364 | ||
| 3031 | if (ifmgd->assoc_data && | 3365 | if (ifmgd->assoc_data && ifmgd->assoc_data->timeout_started && |
| 3032 | time_after(jiffies, ifmgd->assoc_data->timeout)) { | 3366 | time_after(jiffies, ifmgd->assoc_data->timeout)) { |
| 3033 | if ((ifmgd->assoc_data->need_beacon && | 3367 | if ((ifmgd->assoc_data->need_beacon && |
| 3034 | !ifmgd->assoc_data->have_beacon) || | 3368 | !ifmgd->assoc_data->have_beacon) || |
| @@ -3043,7 +3377,7 @@ void ieee80211_sta_work(struct ieee80211_sub_if_data *sdata) | |||
| 3043 | cfg80211_send_assoc_timeout(sdata->dev, bssid); | 3377 | cfg80211_send_assoc_timeout(sdata->dev, bssid); |
| 3044 | mutex_lock(&ifmgd->mtx); | 3378 | mutex_lock(&ifmgd->mtx); |
| 3045 | } | 3379 | } |
| 3046 | } else if (ifmgd->assoc_data) | 3380 | } else if (ifmgd->assoc_data && ifmgd->assoc_data->timeout_started) |
| 3047 | run_again(ifmgd, ifmgd->assoc_data->timeout); | 3381 | run_again(ifmgd, ifmgd->assoc_data->timeout); |
| 3048 | 3382 | ||
| 3049 | if (ifmgd->flags & (IEEE80211_STA_BEACON_POLL | | 3383 | if (ifmgd->flags & (IEEE80211_STA_BEACON_POLL | |
| @@ -3287,201 +3621,6 @@ int ieee80211_max_network_latency(struct notifier_block *nb, | |||
| 3287 | return 0; | 3621 | return 0; |
| 3288 | } | 3622 | } |
| 3289 | 3623 | ||
| 3290 | static u32 chandef_downgrade(struct cfg80211_chan_def *c) | ||
| 3291 | { | ||
| 3292 | u32 ret; | ||
| 3293 | int tmp; | ||
| 3294 | |||
| 3295 | switch (c->width) { | ||
| 3296 | case NL80211_CHAN_WIDTH_20: | ||
| 3297 | c->width = NL80211_CHAN_WIDTH_20_NOHT; | ||
| 3298 | ret = IEEE80211_STA_DISABLE_HT | IEEE80211_STA_DISABLE_VHT; | ||
| 3299 | break; | ||
| 3300 | case NL80211_CHAN_WIDTH_40: | ||
| 3301 | c->width = NL80211_CHAN_WIDTH_20; | ||
| 3302 | c->center_freq1 = c->chan->center_freq; | ||
| 3303 | ret = IEEE80211_STA_DISABLE_40MHZ | | ||
| 3304 | IEEE80211_STA_DISABLE_VHT; | ||
| 3305 | break; | ||
| 3306 | case NL80211_CHAN_WIDTH_80: | ||
| 3307 | tmp = (30 + c->chan->center_freq - c->center_freq1)/20; | ||
| 3308 | /* n_P40 */ | ||
| 3309 | tmp /= 2; | ||
| 3310 | /* freq_P40 */ | ||
| 3311 | c->center_freq1 = c->center_freq1 - 20 + 40 * tmp; | ||
| 3312 | c->width = NL80211_CHAN_WIDTH_40; | ||
| 3313 | ret = IEEE80211_STA_DISABLE_VHT; | ||
| 3314 | break; | ||
| 3315 | case NL80211_CHAN_WIDTH_80P80: | ||
| 3316 | c->center_freq2 = 0; | ||
| 3317 | c->width = NL80211_CHAN_WIDTH_80; | ||
| 3318 | ret = IEEE80211_STA_DISABLE_80P80MHZ | | ||
| 3319 | IEEE80211_STA_DISABLE_160MHZ; | ||
| 3320 | break; | ||
| 3321 | case NL80211_CHAN_WIDTH_160: | ||
| 3322 | /* n_P20 */ | ||
| 3323 | tmp = (70 + c->chan->center_freq - c->center_freq1)/20; | ||
| 3324 | /* n_P80 */ | ||
| 3325 | tmp /= 4; | ||
| 3326 | c->center_freq1 = c->center_freq1 - 40 + 80 * tmp; | ||
| 3327 | c->width = NL80211_CHAN_WIDTH_80; | ||
| 3328 | ret = IEEE80211_STA_DISABLE_80P80MHZ | | ||
| 3329 | IEEE80211_STA_DISABLE_160MHZ; | ||
| 3330 | break; | ||
| 3331 | default: | ||
| 3332 | case NL80211_CHAN_WIDTH_20_NOHT: | ||
| 3333 | WARN_ON_ONCE(1); | ||
| 3334 | c->width = NL80211_CHAN_WIDTH_20_NOHT; | ||
| 3335 | ret = IEEE80211_STA_DISABLE_HT | IEEE80211_STA_DISABLE_VHT; | ||
| 3336 | break; | ||
| 3337 | } | ||
| 3338 | |||
| 3339 | WARN_ON_ONCE(!cfg80211_chandef_valid(c)); | ||
| 3340 | |||
| 3341 | return ret; | ||
| 3342 | } | ||
| 3343 | |||
| 3344 | static u32 | ||
| 3345 | ieee80211_determine_chantype(struct ieee80211_sub_if_data *sdata, | ||
| 3346 | struct ieee80211_supported_band *sband, | ||
| 3347 | struct ieee80211_channel *channel, | ||
| 3348 | const struct ieee80211_ht_operation *ht_oper, | ||
| 3349 | const struct ieee80211_vht_operation *vht_oper, | ||
| 3350 | struct cfg80211_chan_def *chandef) | ||
| 3351 | { | ||
| 3352 | struct cfg80211_chan_def vht_chandef; | ||
| 3353 | u32 ht_cfreq, ret; | ||
| 3354 | |||
| 3355 | chandef->chan = channel; | ||
| 3356 | chandef->width = NL80211_CHAN_WIDTH_20_NOHT; | ||
| 3357 | chandef->center_freq1 = channel->center_freq; | ||
| 3358 | chandef->center_freq2 = 0; | ||
| 3359 | |||
| 3360 | if (!ht_oper || !sband->ht_cap.ht_supported) { | ||
| 3361 | ret = IEEE80211_STA_DISABLE_HT | IEEE80211_STA_DISABLE_VHT; | ||
| 3362 | goto out; | ||
| 3363 | } | ||
| 3364 | |||
| 3365 | chandef->width = NL80211_CHAN_WIDTH_20; | ||
| 3366 | |||
| 3367 | ht_cfreq = ieee80211_channel_to_frequency(ht_oper->primary_chan, | ||
| 3368 | channel->band); | ||
| 3369 | /* check that channel matches the right operating channel */ | ||
| 3370 | if (channel->center_freq != ht_cfreq) { | ||
| 3371 | /* | ||
| 3372 | * It's possible that some APs are confused here; | ||
| 3373 | * Netgear WNDR3700 sometimes reports 4 higher than | ||
| 3374 | * the actual channel in association responses, but | ||
| 3375 | * since we look at probe response/beacon data here | ||
| 3376 | * it should be OK. | ||
| 3377 | */ | ||
| 3378 | sdata_info(sdata, | ||
| 3379 | "Wrong control channel: center-freq: %d ht-cfreq: %d ht->primary_chan: %d band: %d - Disabling HT\n", | ||
| 3380 | channel->center_freq, ht_cfreq, | ||
| 3381 | ht_oper->primary_chan, channel->band); | ||
| 3382 | ret = IEEE80211_STA_DISABLE_HT | IEEE80211_STA_DISABLE_VHT; | ||
| 3383 | goto out; | ||
| 3384 | } | ||
| 3385 | |||
| 3386 | /* check 40 MHz support, if we have it */ | ||
| 3387 | if (sband->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) { | ||
| 3388 | switch (ht_oper->ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET) { | ||
| 3389 | case IEEE80211_HT_PARAM_CHA_SEC_ABOVE: | ||
| 3390 | chandef->width = NL80211_CHAN_WIDTH_40; | ||
| 3391 | chandef->center_freq1 += 10; | ||
| 3392 | break; | ||
| 3393 | case IEEE80211_HT_PARAM_CHA_SEC_BELOW: | ||
| 3394 | chandef->width = NL80211_CHAN_WIDTH_40; | ||
| 3395 | chandef->center_freq1 -= 10; | ||
| 3396 | break; | ||
| 3397 | } | ||
| 3398 | } else { | ||
| 3399 | /* 40 MHz (and 80 MHz) must be supported for VHT */ | ||
| 3400 | ret = IEEE80211_STA_DISABLE_VHT; | ||
| 3401 | goto out; | ||
| 3402 | } | ||
| 3403 | |||
| 3404 | if (!vht_oper || !sband->vht_cap.vht_supported) { | ||
| 3405 | ret = IEEE80211_STA_DISABLE_VHT; | ||
| 3406 | goto out; | ||
| 3407 | } | ||
| 3408 | |||
| 3409 | vht_chandef.chan = channel; | ||
| 3410 | vht_chandef.center_freq1 = | ||
| 3411 | ieee80211_channel_to_frequency(vht_oper->center_freq_seg1_idx, | ||
| 3412 | channel->band); | ||
| 3413 | vht_chandef.center_freq2 = 0; | ||
| 3414 | |||
| 3415 | if (vht_oper->center_freq_seg2_idx) | ||
| 3416 | vht_chandef.center_freq2 = | ||
| 3417 | ieee80211_channel_to_frequency( | ||
| 3418 | vht_oper->center_freq_seg2_idx, | ||
| 3419 | channel->band); | ||
| 3420 | |||
| 3421 | switch (vht_oper->chan_width) { | ||
| 3422 | case IEEE80211_VHT_CHANWIDTH_USE_HT: | ||
| 3423 | vht_chandef.width = chandef->width; | ||
| 3424 | break; | ||
| 3425 | case IEEE80211_VHT_CHANWIDTH_80MHZ: | ||
| 3426 | vht_chandef.width = NL80211_CHAN_WIDTH_80; | ||
| 3427 | break; | ||
| 3428 | case IEEE80211_VHT_CHANWIDTH_160MHZ: | ||
| 3429 | vht_chandef.width = NL80211_CHAN_WIDTH_160; | ||
| 3430 | break; | ||
| 3431 | case IEEE80211_VHT_CHANWIDTH_80P80MHZ: | ||
| 3432 | vht_chandef.width = NL80211_CHAN_WIDTH_80P80; | ||
| 3433 | break; | ||
| 3434 | default: | ||
| 3435 | sdata_info(sdata, | ||
| 3436 | "AP VHT operation IE has invalid channel width (%d), disable VHT\n", | ||
| 3437 | vht_oper->chan_width); | ||
| 3438 | ret = IEEE80211_STA_DISABLE_VHT; | ||
| 3439 | goto out; | ||
| 3440 | } | ||
| 3441 | |||
| 3442 | if (!cfg80211_chandef_valid(&vht_chandef)) { | ||
| 3443 | sdata_info(sdata, | ||
| 3444 | "AP VHT information is invalid, disable VHT\n"); | ||
| 3445 | ret = IEEE80211_STA_DISABLE_VHT; | ||
| 3446 | goto out; | ||
| 3447 | } | ||
| 3448 | |||
| 3449 | if (cfg80211_chandef_identical(chandef, &vht_chandef)) { | ||
| 3450 | ret = 0; | ||
| 3451 | goto out; | ||
| 3452 | } | ||
| 3453 | |||
| 3454 | if (!cfg80211_chandef_compatible(chandef, &vht_chandef)) { | ||
| 3455 | sdata_info(sdata, | ||
| 3456 | "AP VHT information doesn't match HT, disable VHT\n"); | ||
| 3457 | ret = IEEE80211_STA_DISABLE_VHT; | ||
| 3458 | goto out; | ||
| 3459 | } | ||
| 3460 | |||
| 3461 | *chandef = vht_chandef; | ||
| 3462 | |||
| 3463 | ret = 0; | ||
| 3464 | |||
| 3465 | out: | ||
| 3466 | while (!cfg80211_chandef_usable(sdata->local->hw.wiphy, chandef, | ||
| 3467 | IEEE80211_CHAN_DISABLED)) { | ||
| 3468 | if (WARN_ON(chandef->width == NL80211_CHAN_WIDTH_20_NOHT)) { | ||
| 3469 | ret = IEEE80211_STA_DISABLE_HT | | ||
| 3470 | IEEE80211_STA_DISABLE_VHT; | ||
| 3471 | goto out; | ||
| 3472 | } | ||
| 3473 | |||
| 3474 | ret |= chandef_downgrade(chandef); | ||
| 3475 | } | ||
| 3476 | |||
| 3477 | if (chandef->width != vht_chandef.width) | ||
| 3478 | sdata_info(sdata, | ||
| 3479 | "capabilities/regulatory prevented using AP HT/VHT configuration, downgraded\n"); | ||
| 3480 | |||
| 3481 | WARN_ON_ONCE(!cfg80211_chandef_valid(chandef)); | ||
| 3482 | return ret; | ||
| 3483 | } | ||
| 3484 | |||
| 3485 | static u8 ieee80211_ht_vht_rx_chains(struct ieee80211_sub_if_data *sdata, | 3624 | static u8 ieee80211_ht_vht_rx_chains(struct ieee80211_sub_if_data *sdata, |
| 3486 | struct cfg80211_bss *cbss) | 3625 | struct cfg80211_bss *cbss) |
| 3487 | { | 3626 | { |
| @@ -3547,16 +3686,22 @@ static int ieee80211_prep_channel(struct ieee80211_sub_if_data *sdata, | |||
| 3547 | 3686 | ||
| 3548 | if (!(ifmgd->flags & IEEE80211_STA_DISABLE_HT) && | 3687 | if (!(ifmgd->flags & IEEE80211_STA_DISABLE_HT) && |
| 3549 | sband->ht_cap.ht_supported) { | 3688 | sband->ht_cap.ht_supported) { |
| 3550 | const u8 *ht_oper_ie; | 3689 | const u8 *ht_oper_ie, *ht_cap; |
| 3551 | 3690 | ||
| 3552 | ht_oper_ie = ieee80211_bss_get_ie(cbss, WLAN_EID_HT_OPERATION); | 3691 | ht_oper_ie = ieee80211_bss_get_ie(cbss, WLAN_EID_HT_OPERATION); |
| 3553 | if (ht_oper_ie && ht_oper_ie[1] >= sizeof(*ht_oper)) | 3692 | if (ht_oper_ie && ht_oper_ie[1] >= sizeof(*ht_oper)) |
| 3554 | ht_oper = (void *)(ht_oper_ie + 2); | 3693 | ht_oper = (void *)(ht_oper_ie + 2); |
| 3694 | |||
| 3695 | ht_cap = ieee80211_bss_get_ie(cbss, WLAN_EID_HT_CAPABILITY); | ||
| 3696 | if (!ht_cap || ht_cap[1] < sizeof(struct ieee80211_ht_cap)) { | ||
| 3697 | ifmgd->flags |= IEEE80211_STA_DISABLE_HT; | ||
| 3698 | ht_oper = NULL; | ||
| 3699 | } | ||
| 3555 | } | 3700 | } |
| 3556 | 3701 | ||
| 3557 | if (!(ifmgd->flags & IEEE80211_STA_DISABLE_VHT) && | 3702 | if (!(ifmgd->flags & IEEE80211_STA_DISABLE_VHT) && |
| 3558 | sband->vht_cap.vht_supported) { | 3703 | sband->vht_cap.vht_supported) { |
| 3559 | const u8 *vht_oper_ie; | 3704 | const u8 *vht_oper_ie, *vht_cap; |
| 3560 | 3705 | ||
| 3561 | vht_oper_ie = ieee80211_bss_get_ie(cbss, | 3706 | vht_oper_ie = ieee80211_bss_get_ie(cbss, |
| 3562 | WLAN_EID_VHT_OPERATION); | 3707 | WLAN_EID_VHT_OPERATION); |
| @@ -3566,15 +3711,21 @@ static int ieee80211_prep_channel(struct ieee80211_sub_if_data *sdata, | |||
| 3566 | vht_oper = NULL; | 3711 | vht_oper = NULL; |
| 3567 | sdata_info(sdata, | 3712 | sdata_info(sdata, |
| 3568 | "AP advertised VHT without HT, disabling both\n"); | 3713 | "AP advertised VHT without HT, disabling both\n"); |
| 3569 | sdata->flags |= IEEE80211_STA_DISABLE_HT; | 3714 | ifmgd->flags |= IEEE80211_STA_DISABLE_HT; |
| 3570 | sdata->flags |= IEEE80211_STA_DISABLE_VHT; | 3715 | ifmgd->flags |= IEEE80211_STA_DISABLE_VHT; |
| 3716 | } | ||
| 3717 | |||
| 3718 | vht_cap = ieee80211_bss_get_ie(cbss, WLAN_EID_VHT_CAPABILITY); | ||
| 3719 | if (!vht_cap || vht_cap[1] < sizeof(struct ieee80211_vht_cap)) { | ||
| 3720 | ifmgd->flags |= IEEE80211_STA_DISABLE_VHT; | ||
| 3721 | vht_oper = NULL; | ||
| 3571 | } | 3722 | } |
| 3572 | } | 3723 | } |
| 3573 | 3724 | ||
| 3574 | ifmgd->flags |= ieee80211_determine_chantype(sdata, sband, | 3725 | ifmgd->flags |= ieee80211_determine_chantype(sdata, sband, |
| 3575 | cbss->channel, | 3726 | cbss->channel, |
| 3576 | ht_oper, vht_oper, | 3727 | ht_oper, vht_oper, |
| 3577 | &chandef); | 3728 | &chandef, true); |
| 3578 | 3729 | ||
| 3579 | sdata->needed_rx_chains = min(ieee80211_ht_vht_rx_chains(sdata, cbss), | 3730 | sdata->needed_rx_chains = min(ieee80211_ht_vht_rx_chains(sdata, cbss), |
| 3580 | local->rx_chains); | 3731 | local->rx_chains); |
| @@ -4021,6 +4172,7 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, | |||
| 4021 | sdata_info(sdata, "waiting for beacon from %pM\n", | 4172 | sdata_info(sdata, "waiting for beacon from %pM\n", |
| 4022 | ifmgd->bssid); | 4173 | ifmgd->bssid); |
| 4023 | assoc_data->timeout = TU_TO_EXP_TIME(req->bss->beacon_interval); | 4174 | assoc_data->timeout = TU_TO_EXP_TIME(req->bss->beacon_interval); |
| 4175 | assoc_data->timeout_started = true; | ||
| 4024 | assoc_data->need_beacon = true; | 4176 | assoc_data->need_beacon = true; |
| 4025 | } else if (beacon_ies) { | 4177 | } else if (beacon_ies) { |
| 4026 | const u8 *tim_ie = cfg80211_find_ie(WLAN_EID_TIM, | 4178 | const u8 *tim_ie = cfg80211_find_ie(WLAN_EID_TIM, |
| @@ -4036,6 +4188,7 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, | |||
| 4036 | } | 4188 | } |
| 4037 | assoc_data->have_beacon = true; | 4189 | assoc_data->have_beacon = true; |
| 4038 | assoc_data->timeout = jiffies; | 4190 | assoc_data->timeout = jiffies; |
| 4191 | assoc_data->timeout_started = true; | ||
| 4039 | 4192 | ||
| 4040 | if (local->hw.flags & IEEE80211_HW_TIMING_BEACON_ONLY) { | 4193 | if (local->hw.flags & IEEE80211_HW_TIMING_BEACON_ONLY) { |
| 4041 | sdata->vif.bss_conf.sync_tsf = beacon_ies->tsf; | 4194 | sdata->vif.bss_conf.sync_tsf = beacon_ies->tsf; |
| @@ -4045,6 +4198,7 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, | |||
| 4045 | } | 4198 | } |
| 4046 | } else { | 4199 | } else { |
| 4047 | assoc_data->timeout = jiffies; | 4200 | assoc_data->timeout = jiffies; |
| 4201 | assoc_data->timeout_started = true; | ||
| 4048 | } | 4202 | } |
| 4049 | rcu_read_unlock(); | 4203 | rcu_read_unlock(); |
| 4050 | 4204 | ||
diff --git a/net/mac80211/pm.c b/net/mac80211/pm.c index 53801d20176d..d0275f34bf70 100644 --- a/net/mac80211/pm.c +++ b/net/mac80211/pm.c | |||
| @@ -38,6 +38,8 @@ int __ieee80211_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan) | |||
| 38 | 38 | ||
| 39 | ieee80211_scan_cancel(local); | 39 | ieee80211_scan_cancel(local); |
| 40 | 40 | ||
| 41 | ieee80211_dfs_cac_cancel(local); | ||
| 42 | |||
| 41 | if (hw->flags & IEEE80211_HW_AMPDU_AGGREGATION) { | 43 | if (hw->flags & IEEE80211_HW_AMPDU_AGGREGATION) { |
| 42 | mutex_lock(&local->sta_mtx); | 44 | mutex_lock(&local->sta_mtx); |
| 43 | list_for_each_entry(sta, &local->sta_list, list) { | 45 | list_for_each_entry(sta, &local->sta_list, list) { |
diff --git a/net/mac80211/rate.h b/net/mac80211/rate.h index 301386dabf88..d35a5dd3fb13 100644 --- a/net/mac80211/rate.h +++ b/net/mac80211/rate.h | |||
| @@ -68,6 +68,8 @@ static inline void rate_control_rate_init(struct sta_info *sta) | |||
| 68 | sband = local->hw.wiphy->bands[chanctx_conf->def.chan->band]; | 68 | sband = local->hw.wiphy->bands[chanctx_conf->def.chan->band]; |
| 69 | rcu_read_unlock(); | 69 | rcu_read_unlock(); |
| 70 | 70 | ||
| 71 | ieee80211_sta_set_rx_nss(sta); | ||
| 72 | |||
| 71 | ref->ops->rate_init(ref->priv, sband, ista, priv_sta); | 73 | ref->ops->rate_init(ref->priv, sband, ista, priv_sta); |
| 72 | set_sta_flag(sta, WLAN_STA_RATE_CONTROL); | 74 | set_sta_flag(sta, WLAN_STA_RATE_CONTROL); |
| 73 | } | 75 | } |
diff --git a/net/mac80211/rc80211_minstrel.c b/net/mac80211/rc80211_minstrel.c index 8c5acdc06226..eea45a2c7c35 100644 --- a/net/mac80211/rc80211_minstrel.c +++ b/net/mac80211/rc80211_minstrel.c | |||
| @@ -494,6 +494,33 @@ minstrel_free_sta(void *priv, struct ieee80211_sta *sta, void *priv_sta) | |||
| 494 | kfree(mi); | 494 | kfree(mi); |
| 495 | } | 495 | } |
| 496 | 496 | ||
| 497 | static void | ||
| 498 | minstrel_init_cck_rates(struct minstrel_priv *mp) | ||
| 499 | { | ||
| 500 | static const int bitrates[4] = { 10, 20, 55, 110 }; | ||
| 501 | struct ieee80211_supported_band *sband; | ||
| 502 | int i, j; | ||
| 503 | |||
| 504 | sband = mp->hw->wiphy->bands[IEEE80211_BAND_2GHZ]; | ||
| 505 | if (!sband) | ||
| 506 | return; | ||
| 507 | |||
| 508 | for (i = 0, j = 0; i < sband->n_bitrates; i++) { | ||
| 509 | struct ieee80211_rate *rate = &sband->bitrates[i]; | ||
| 510 | |||
| 511 | if (rate->flags & IEEE80211_RATE_ERP_G) | ||
| 512 | continue; | ||
| 513 | |||
| 514 | for (j = 0; j < ARRAY_SIZE(bitrates); j++) { | ||
| 515 | if (rate->bitrate != bitrates[j]) | ||
| 516 | continue; | ||
| 517 | |||
| 518 | mp->cck_rates[j] = i; | ||
| 519 | break; | ||
| 520 | } | ||
| 521 | } | ||
| 522 | } | ||
| 523 | |||
| 497 | static void * | 524 | static void * |
| 498 | minstrel_alloc(struct ieee80211_hw *hw, struct dentry *debugfsdir) | 525 | minstrel_alloc(struct ieee80211_hw *hw, struct dentry *debugfsdir) |
| 499 | { | 526 | { |
| @@ -539,6 +566,8 @@ minstrel_alloc(struct ieee80211_hw *hw, struct dentry *debugfsdir) | |||
| 539 | S_IRUGO | S_IWUGO, debugfsdir, &mp->fixed_rate_idx); | 566 | S_IRUGO | S_IWUGO, debugfsdir, &mp->fixed_rate_idx); |
| 540 | #endif | 567 | #endif |
| 541 | 568 | ||
| 569 | minstrel_init_cck_rates(mp); | ||
| 570 | |||
| 542 | return mp; | 571 | return mp; |
| 543 | } | 572 | } |
| 544 | 573 | ||
diff --git a/net/mac80211/rc80211_minstrel.h b/net/mac80211/rc80211_minstrel.h index 5d278eccaef0..5ecf757817f2 100644 --- a/net/mac80211/rc80211_minstrel.h +++ b/net/mac80211/rc80211_minstrel.h | |||
| @@ -79,6 +79,8 @@ struct minstrel_priv { | |||
| 79 | unsigned int lookaround_rate; | 79 | unsigned int lookaround_rate; |
| 80 | unsigned int lookaround_rate_mrr; | 80 | unsigned int lookaround_rate_mrr; |
| 81 | 81 | ||
| 82 | u8 cck_rates[4]; | ||
| 83 | |||
| 82 | #ifdef CONFIG_MAC80211_DEBUGFS | 84 | #ifdef CONFIG_MAC80211_DEBUGFS |
| 83 | /* | 85 | /* |
| 84 | * enable fixed rate processing per RC | 86 | * enable fixed rate processing per RC |
diff --git a/net/mac80211/rc80211_minstrel_ht.c b/net/mac80211/rc80211_minstrel_ht.c index 5bb316aff21a..3af141c69712 100644 --- a/net/mac80211/rc80211_minstrel_ht.c +++ b/net/mac80211/rc80211_minstrel_ht.c | |||
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * Copyright (C) 2010 Felix Fietkau <nbd@openwrt.org> | 2 | * Copyright (C) 2010-2013 Felix Fietkau <nbd@openwrt.org> |
| 3 | * | 3 | * |
| 4 | * This program is free software; you can redistribute it and/or modify | 4 | * This program is free software; you can redistribute it and/or modify |
| 5 | * it under the terms of the GNU General Public License version 2 as | 5 | * it under the terms of the GNU General Public License version 2 as |
| @@ -63,6 +63,30 @@ | |||
| 63 | } \ | 63 | } \ |
| 64 | } | 64 | } |
| 65 | 65 | ||
| 66 | #define CCK_DURATION(_bitrate, _short, _len) \ | ||
| 67 | (10 /* SIFS */ + \ | ||
| 68 | (_short ? 72 + 24 : 144 + 48 ) + \ | ||
| 69 | (8 * (_len + 4) * 10) / (_bitrate)) | ||
| 70 | |||
| 71 | #define CCK_ACK_DURATION(_bitrate, _short) \ | ||
| 72 | (CCK_DURATION((_bitrate > 10 ? 20 : 10), false, 60) + \ | ||
| 73 | CCK_DURATION(_bitrate, _short, AVG_PKT_SIZE)) | ||
| 74 | |||
| 75 | #define CCK_DURATION_LIST(_short) \ | ||
| 76 | CCK_ACK_DURATION(10, _short), \ | ||
| 77 | CCK_ACK_DURATION(20, _short), \ | ||
| 78 | CCK_ACK_DURATION(55, _short), \ | ||
| 79 | CCK_ACK_DURATION(110, _short) | ||
| 80 | |||
| 81 | #define CCK_GROUP \ | ||
| 82 | [MINSTREL_MAX_STREAMS * MINSTREL_STREAM_GROUPS] = { \ | ||
| 83 | .streams = 0, \ | ||
| 84 | .duration = { \ | ||
| 85 | CCK_DURATION_LIST(false), \ | ||
| 86 | CCK_DURATION_LIST(true) \ | ||
| 87 | } \ | ||
| 88 | } | ||
| 89 | |||
| 66 | /* | 90 | /* |
| 67 | * To enable sufficiently targeted rate sampling, MCS rates are divided into | 91 | * To enable sufficiently targeted rate sampling, MCS rates are divided into |
| 68 | * groups, based on the number of streams and flags (HT40, SGI) that they | 92 | * groups, based on the number of streams and flags (HT40, SGI) that they |
| @@ -95,8 +119,13 @@ const struct mcs_group minstrel_mcs_groups[] = { | |||
| 95 | #if MINSTREL_MAX_STREAMS >= 3 | 119 | #if MINSTREL_MAX_STREAMS >= 3 |
| 96 | MCS_GROUP(3, 1, 1), | 120 | MCS_GROUP(3, 1, 1), |
| 97 | #endif | 121 | #endif |
| 122 | |||
| 123 | /* must be last */ | ||
| 124 | CCK_GROUP | ||
| 98 | }; | 125 | }; |
| 99 | 126 | ||
| 127 | #define MINSTREL_CCK_GROUP (ARRAY_SIZE(minstrel_mcs_groups) - 1) | ||
| 128 | |||
| 100 | static u8 sample_table[SAMPLE_COLUMNS][MCS_GROUP_RATES]; | 129 | static u8 sample_table[SAMPLE_COLUMNS][MCS_GROUP_RATES]; |
| 101 | 130 | ||
| 102 | /* | 131 | /* |
| @@ -119,6 +148,29 @@ minstrel_ht_get_group_idx(struct ieee80211_tx_rate *rate) | |||
| 119 | !!(rate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH)); | 148 | !!(rate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH)); |
| 120 | } | 149 | } |
| 121 | 150 | ||
| 151 | static struct minstrel_rate_stats * | ||
| 152 | minstrel_ht_get_stats(struct minstrel_priv *mp, struct minstrel_ht_sta *mi, | ||
| 153 | struct ieee80211_tx_rate *rate) | ||
| 154 | { | ||
| 155 | int group, idx; | ||
| 156 | |||
| 157 | if (rate->flags & IEEE80211_TX_RC_MCS) { | ||
| 158 | group = minstrel_ht_get_group_idx(rate); | ||
| 159 | idx = rate->idx % MCS_GROUP_RATES; | ||
| 160 | } else { | ||
| 161 | group = MINSTREL_CCK_GROUP; | ||
| 162 | |||
| 163 | for (idx = 0; idx < ARRAY_SIZE(mp->cck_rates); idx++) | ||
| 164 | if (rate->idx == mp->cck_rates[idx]) | ||
| 165 | break; | ||
| 166 | |||
| 167 | /* short preamble */ | ||
| 168 | if (!(mi->groups[group].supported & BIT(idx))) | ||
| 169 | idx += 4; | ||
| 170 | } | ||
| 171 | return &mi->groups[group].rates[idx]; | ||
| 172 | } | ||
| 173 | |||
| 122 | static inline struct minstrel_rate_stats * | 174 | static inline struct minstrel_rate_stats * |
| 123 | minstrel_get_ratestats(struct minstrel_ht_sta *mi, int index) | 175 | minstrel_get_ratestats(struct minstrel_ht_sta *mi, int index) |
| 124 | { | 176 | { |
| @@ -159,7 +211,7 @@ static void | |||
| 159 | minstrel_ht_calc_tp(struct minstrel_ht_sta *mi, int group, int rate) | 211 | minstrel_ht_calc_tp(struct minstrel_ht_sta *mi, int group, int rate) |
| 160 | { | 212 | { |
| 161 | struct minstrel_rate_stats *mr; | 213 | struct minstrel_rate_stats *mr; |
| 162 | unsigned int usecs; | 214 | unsigned int usecs = 0; |
| 163 | 215 | ||
| 164 | mr = &mi->groups[group].rates[rate]; | 216 | mr = &mi->groups[group].rates[rate]; |
| 165 | 217 | ||
| @@ -168,7 +220,9 @@ minstrel_ht_calc_tp(struct minstrel_ht_sta *mi, int group, int rate) | |||
| 168 | return; | 220 | return; |
| 169 | } | 221 | } |
| 170 | 222 | ||
| 171 | usecs = mi->overhead / MINSTREL_TRUNC(mi->avg_ampdu_len); | 223 | if (group != MINSTREL_CCK_GROUP) |
| 224 | usecs = mi->overhead / MINSTREL_TRUNC(mi->avg_ampdu_len); | ||
| 225 | |||
| 172 | usecs += minstrel_mcs_groups[group].duration[rate]; | 226 | usecs += minstrel_mcs_groups[group].duration[rate]; |
| 173 | mr->cur_tp = MINSTREL_TRUNC((1000000 / usecs) * mr->probability); | 227 | mr->cur_tp = MINSTREL_TRUNC((1000000 / usecs) * mr->probability); |
| 174 | } | 228 | } |
| @@ -293,7 +347,7 @@ minstrel_ht_update_stats(struct minstrel_priv *mp, struct minstrel_ht_sta *mi) | |||
| 293 | } | 347 | } |
| 294 | 348 | ||
| 295 | static bool | 349 | static bool |
| 296 | minstrel_ht_txstat_valid(struct ieee80211_tx_rate *rate) | 350 | minstrel_ht_txstat_valid(struct minstrel_priv *mp, struct ieee80211_tx_rate *rate) |
| 297 | { | 351 | { |
| 298 | if (rate->idx < 0) | 352 | if (rate->idx < 0) |
| 299 | return false; | 353 | return false; |
| @@ -301,7 +355,13 @@ minstrel_ht_txstat_valid(struct ieee80211_tx_rate *rate) | |||
| 301 | if (!rate->count) | 355 | if (!rate->count) |
| 302 | return false; | 356 | return false; |
| 303 | 357 | ||
| 304 | return !!(rate->flags & IEEE80211_TX_RC_MCS); | 358 | if (rate->flags & IEEE80211_TX_RC_MCS) |
| 359 | return true; | ||
| 360 | |||
| 361 | return rate->idx == mp->cck_rates[0] || | ||
| 362 | rate->idx == mp->cck_rates[1] || | ||
| 363 | rate->idx == mp->cck_rates[2] || | ||
| 364 | rate->idx == mp->cck_rates[3]; | ||
| 305 | } | 365 | } |
| 306 | 366 | ||
| 307 | static void | 367 | static void |
| @@ -386,7 +446,6 @@ minstrel_ht_tx_status(void *priv, struct ieee80211_supported_band *sband, | |||
| 386 | struct minstrel_rate_stats *rate, *rate2; | 446 | struct minstrel_rate_stats *rate, *rate2; |
| 387 | struct minstrel_priv *mp = priv; | 447 | struct minstrel_priv *mp = priv; |
| 388 | bool last; | 448 | bool last; |
| 389 | int group; | ||
| 390 | int i; | 449 | int i; |
| 391 | 450 | ||
| 392 | if (!msp->is_ht) | 451 | if (!msp->is_ht) |
| @@ -415,13 +474,12 @@ minstrel_ht_tx_status(void *priv, struct ieee80211_supported_band *sband, | |||
| 415 | if (info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE) | 474 | if (info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE) |
| 416 | mi->sample_packets += info->status.ampdu_len; | 475 | mi->sample_packets += info->status.ampdu_len; |
| 417 | 476 | ||
| 418 | last = !minstrel_ht_txstat_valid(&ar[0]); | 477 | last = !minstrel_ht_txstat_valid(mp, &ar[0]); |
| 419 | for (i = 0; !last; i++) { | 478 | for (i = 0; !last; i++) { |
| 420 | last = (i == IEEE80211_TX_MAX_RATES - 1) || | 479 | last = (i == IEEE80211_TX_MAX_RATES - 1) || |
| 421 | !minstrel_ht_txstat_valid(&ar[i + 1]); | 480 | !minstrel_ht_txstat_valid(mp, &ar[i + 1]); |
| 422 | 481 | ||
| 423 | group = minstrel_ht_get_group_idx(&ar[i]); | 482 | rate = minstrel_ht_get_stats(mp, mi, &ar[i]); |
| 424 | rate = &mi->groups[group].rates[ar[i].idx % 8]; | ||
| 425 | 483 | ||
| 426 | if (last) | 484 | if (last) |
| 427 | rate->success += info->status.ampdu_ack_len; | 485 | rate->success += info->status.ampdu_ack_len; |
| @@ -447,7 +505,8 @@ minstrel_ht_tx_status(void *priv, struct ieee80211_supported_band *sband, | |||
| 447 | 505 | ||
| 448 | if (time_after(jiffies, mi->stats_update + (mp->update_interval / 2 * HZ) / 1000)) { | 506 | if (time_after(jiffies, mi->stats_update + (mp->update_interval / 2 * HZ) / 1000)) { |
| 449 | minstrel_ht_update_stats(mp, mi); | 507 | minstrel_ht_update_stats(mp, mi); |
| 450 | if (!(info->flags & IEEE80211_TX_CTL_AMPDU)) | 508 | if (!(info->flags & IEEE80211_TX_CTL_AMPDU) && |
| 509 | mi->max_prob_rate / MCS_GROUP_RATES != MINSTREL_CCK_GROUP) | ||
| 451 | minstrel_aggr_check(sta, skb); | 510 | minstrel_aggr_check(sta, skb); |
| 452 | } | 511 | } |
| 453 | } | 512 | } |
| @@ -463,6 +522,7 @@ minstrel_calc_retransmit(struct minstrel_priv *mp, struct minstrel_ht_sta *mi, | |||
| 463 | unsigned int ctime = 0; | 522 | unsigned int ctime = 0; |
| 464 | unsigned int t_slot = 9; /* FIXME */ | 523 | unsigned int t_slot = 9; /* FIXME */ |
| 465 | unsigned int ampdu_len = MINSTREL_TRUNC(mi->avg_ampdu_len); | 524 | unsigned int ampdu_len = MINSTREL_TRUNC(mi->avg_ampdu_len); |
| 525 | unsigned int overhead = 0, overhead_rtscts = 0; | ||
| 466 | 526 | ||
| 467 | mr = minstrel_get_ratestats(mi, index); | 527 | mr = minstrel_get_ratestats(mi, index); |
| 468 | if (mr->probability < MINSTREL_FRAC(1, 10)) { | 528 | if (mr->probability < MINSTREL_FRAC(1, 10)) { |
| @@ -484,9 +544,14 @@ minstrel_calc_retransmit(struct minstrel_priv *mp, struct minstrel_ht_sta *mi, | |||
| 484 | ctime += (t_slot * cw) >> 1; | 544 | ctime += (t_slot * cw) >> 1; |
| 485 | cw = min((cw << 1) | 1, mp->cw_max); | 545 | cw = min((cw << 1) | 1, mp->cw_max); |
| 486 | 546 | ||
| 547 | if (index / MCS_GROUP_RATES != MINSTREL_CCK_GROUP) { | ||
| 548 | overhead = mi->overhead; | ||
| 549 | overhead_rtscts = mi->overhead_rtscts; | ||
| 550 | } | ||
| 551 | |||
| 487 | /* Total TX time for data and Contention after first 2 tries */ | 552 | /* Total TX time for data and Contention after first 2 tries */ |
| 488 | tx_time = ctime + 2 * (mi->overhead + tx_time_data); | 553 | tx_time = ctime + 2 * (overhead + tx_time_data); |
| 489 | tx_time_rtscts = ctime + 2 * (mi->overhead_rtscts + tx_time_data); | 554 | tx_time_rtscts = ctime + 2 * (overhead_rtscts + tx_time_data); |
| 490 | 555 | ||
| 491 | /* See how many more tries we can fit inside segment size */ | 556 | /* See how many more tries we can fit inside segment size */ |
| 492 | do { | 557 | do { |
| @@ -495,8 +560,8 @@ minstrel_calc_retransmit(struct minstrel_priv *mp, struct minstrel_ht_sta *mi, | |||
| 495 | cw = min((cw << 1) | 1, mp->cw_max); | 560 | cw = min((cw << 1) | 1, mp->cw_max); |
| 496 | 561 | ||
| 497 | /* Total TX time after this try */ | 562 | /* Total TX time after this try */ |
| 498 | tx_time += ctime + mi->overhead + tx_time_data; | 563 | tx_time += ctime + overhead + tx_time_data; |
| 499 | tx_time_rtscts += ctime + mi->overhead_rtscts + tx_time_data; | 564 | tx_time_rtscts += ctime + overhead_rtscts + tx_time_data; |
| 500 | 565 | ||
| 501 | if (tx_time_rtscts < mp->segment_size) | 566 | if (tx_time_rtscts < mp->segment_size) |
| 502 | mr->retry_count_rtscts++; | 567 | mr->retry_count_rtscts++; |
| @@ -526,9 +591,16 @@ minstrel_ht_set_rate(struct minstrel_priv *mp, struct minstrel_ht_sta *mi, | |||
| 526 | else | 591 | else |
| 527 | rate->count = mr->retry_count; | 592 | rate->count = mr->retry_count; |
| 528 | 593 | ||
| 529 | rate->flags = IEEE80211_TX_RC_MCS | group->flags; | 594 | rate->flags = 0; |
| 530 | if (rtscts) | 595 | if (rtscts) |
| 531 | rate->flags |= IEEE80211_TX_RC_USE_RTS_CTS; | 596 | rate->flags |= IEEE80211_TX_RC_USE_RTS_CTS; |
| 597 | |||
| 598 | if (index / MCS_GROUP_RATES == MINSTREL_CCK_GROUP) { | ||
| 599 | rate->idx = mp->cck_rates[index % ARRAY_SIZE(mp->cck_rates)]; | ||
| 600 | return; | ||
| 601 | } | ||
| 602 | |||
| 603 | rate->flags |= IEEE80211_TX_RC_MCS | group->flags; | ||
| 532 | rate->idx = index % MCS_GROUP_RATES + (group->streams - 1) * MCS_GROUP_RATES; | 604 | rate->idx = index % MCS_GROUP_RATES + (group->streams - 1) * MCS_GROUP_RATES; |
| 533 | } | 605 | } |
| 534 | 606 | ||
| @@ -592,6 +664,22 @@ minstrel_get_sample_rate(struct minstrel_priv *mp, struct minstrel_ht_sta *mi) | |||
| 592 | } | 664 | } |
| 593 | 665 | ||
| 594 | static void | 666 | static void |
| 667 | minstrel_ht_check_cck_shortpreamble(struct minstrel_priv *mp, | ||
| 668 | struct minstrel_ht_sta *mi, bool val) | ||
| 669 | { | ||
| 670 | u8 supported = mi->groups[MINSTREL_CCK_GROUP].supported; | ||
| 671 | |||
| 672 | if (!supported || !mi->cck_supported_short) | ||
| 673 | return; | ||
| 674 | |||
| 675 | if (supported & (mi->cck_supported_short << (val * 4))) | ||
| 676 | return; | ||
| 677 | |||
| 678 | supported ^= mi->cck_supported_short | (mi->cck_supported_short << 4); | ||
| 679 | mi->groups[MINSTREL_CCK_GROUP].supported = supported; | ||
| 680 | } | ||
| 681 | |||
| 682 | static void | ||
| 595 | minstrel_ht_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta, | 683 | minstrel_ht_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta, |
| 596 | struct ieee80211_tx_rate_control *txrc) | 684 | struct ieee80211_tx_rate_control *txrc) |
| 597 | { | 685 | { |
| @@ -610,6 +698,7 @@ minstrel_ht_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta, | |||
| 610 | return mac80211_minstrel.get_rate(priv, sta, &msp->legacy, txrc); | 698 | return mac80211_minstrel.get_rate(priv, sta, &msp->legacy, txrc); |
| 611 | 699 | ||
| 612 | info->flags |= mi->tx_flags; | 700 | info->flags |= mi->tx_flags; |
| 701 | minstrel_ht_check_cck_shortpreamble(mp, mi, txrc->short_preamble); | ||
| 613 | 702 | ||
| 614 | /* Don't use EAPOL frames for sampling on non-mrr hw */ | 703 | /* Don't use EAPOL frames for sampling on non-mrr hw */ |
| 615 | if (mp->hw->max_rates == 1 && | 704 | if (mp->hw->max_rates == 1 && |
| @@ -683,6 +772,30 @@ minstrel_ht_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta, | |||
| 683 | } | 772 | } |
| 684 | 773 | ||
| 685 | static void | 774 | static void |
| 775 | minstrel_ht_update_cck(struct minstrel_priv *mp, struct minstrel_ht_sta *mi, | ||
| 776 | struct ieee80211_supported_band *sband, | ||
| 777 | struct ieee80211_sta *sta) | ||
| 778 | { | ||
| 779 | int i; | ||
| 780 | |||
| 781 | if (sband->band != IEEE80211_BAND_2GHZ) | ||
| 782 | return; | ||
| 783 | |||
| 784 | mi->cck_supported = 0; | ||
| 785 | mi->cck_supported_short = 0; | ||
| 786 | for (i = 0; i < 4; i++) { | ||
| 787 | if (!rate_supported(sta, sband->band, mp->cck_rates[i])) | ||
| 788 | continue; | ||
| 789 | |||
| 790 | mi->cck_supported |= BIT(i); | ||
| 791 | if (sband->bitrates[i].flags & IEEE80211_RATE_SHORT_PREAMBLE) | ||
| 792 | mi->cck_supported_short |= BIT(i); | ||
| 793 | } | ||
| 794 | |||
| 795 | mi->groups[MINSTREL_CCK_GROUP].supported = mi->cck_supported; | ||
| 796 | } | ||
| 797 | |||
| 798 | static void | ||
| 686 | minstrel_ht_update_caps(void *priv, struct ieee80211_supported_band *sband, | 799 | minstrel_ht_update_caps(void *priv, struct ieee80211_supported_band *sband, |
| 687 | struct ieee80211_sta *sta, void *priv_sta) | 800 | struct ieee80211_sta *sta, void *priv_sta) |
| 688 | { | 801 | { |
| @@ -695,14 +808,13 @@ minstrel_ht_update_caps(void *priv, struct ieee80211_supported_band *sband, | |||
| 695 | int ack_dur; | 808 | int ack_dur; |
| 696 | int stbc; | 809 | int stbc; |
| 697 | int i; | 810 | int i; |
| 698 | unsigned int smps; | ||
| 699 | 811 | ||
| 700 | /* fall back to the old minstrel for legacy stations */ | 812 | /* fall back to the old minstrel for legacy stations */ |
| 701 | if (!sta->ht_cap.ht_supported) | 813 | if (!sta->ht_cap.ht_supported) |
| 702 | goto use_legacy; | 814 | goto use_legacy; |
| 703 | 815 | ||
| 704 | BUILD_BUG_ON(ARRAY_SIZE(minstrel_mcs_groups) != | 816 | BUILD_BUG_ON(ARRAY_SIZE(minstrel_mcs_groups) != |
| 705 | MINSTREL_MAX_STREAMS * MINSTREL_STREAM_GROUPS); | 817 | MINSTREL_MAX_STREAMS * MINSTREL_STREAM_GROUPS + 1); |
| 706 | 818 | ||
| 707 | msp->is_ht = true; | 819 | msp->is_ht = true; |
| 708 | memset(mi, 0, sizeof(*mi)); | 820 | memset(mi, 0, sizeof(*mi)); |
| @@ -731,28 +843,29 @@ minstrel_ht_update_caps(void *priv, struct ieee80211_supported_band *sband, | |||
| 731 | if (sta_cap & IEEE80211_HT_CAP_LDPC_CODING) | 843 | if (sta_cap & IEEE80211_HT_CAP_LDPC_CODING) |
| 732 | mi->tx_flags |= IEEE80211_TX_CTL_LDPC; | 844 | mi->tx_flags |= IEEE80211_TX_CTL_LDPC; |
| 733 | 845 | ||
| 734 | smps = (sta_cap & IEEE80211_HT_CAP_SM_PS) >> | ||
| 735 | IEEE80211_HT_CAP_SM_PS_SHIFT; | ||
| 736 | |||
| 737 | for (i = 0; i < ARRAY_SIZE(mi->groups); i++) { | 846 | for (i = 0; i < ARRAY_SIZE(mi->groups); i++) { |
| 738 | u16 req = 0; | ||
| 739 | |||
| 740 | mi->groups[i].supported = 0; | 847 | mi->groups[i].supported = 0; |
| 741 | if (minstrel_mcs_groups[i].flags & IEEE80211_TX_RC_SHORT_GI) { | 848 | if (i == MINSTREL_CCK_GROUP) { |
| 742 | if (minstrel_mcs_groups[i].flags & IEEE80211_TX_RC_40_MHZ_WIDTH) | 849 | minstrel_ht_update_cck(mp, mi, sband, sta); |
| 743 | req |= IEEE80211_HT_CAP_SGI_40; | 850 | continue; |
| 744 | else | ||
| 745 | req |= IEEE80211_HT_CAP_SGI_20; | ||
| 746 | } | 851 | } |
| 747 | 852 | ||
| 748 | if (minstrel_mcs_groups[i].flags & IEEE80211_TX_RC_40_MHZ_WIDTH) | 853 | if (minstrel_mcs_groups[i].flags & IEEE80211_TX_RC_SHORT_GI) { |
| 749 | req |= IEEE80211_HT_CAP_SUP_WIDTH_20_40; | 854 | if (minstrel_mcs_groups[i].flags & IEEE80211_TX_RC_40_MHZ_WIDTH) { |
| 855 | if (!(sta_cap & IEEE80211_HT_CAP_SGI_40)) | ||
| 856 | continue; | ||
| 857 | } else { | ||
| 858 | if (!(sta_cap & IEEE80211_HT_CAP_SGI_20)) | ||
| 859 | continue; | ||
| 860 | } | ||
| 861 | } | ||
| 750 | 862 | ||
| 751 | if ((sta_cap & req) != req) | 863 | if (minstrel_mcs_groups[i].flags & IEEE80211_TX_RC_40_MHZ_WIDTH && |
| 864 | sta->bandwidth < IEEE80211_STA_RX_BW_40) | ||
| 752 | continue; | 865 | continue; |
| 753 | 866 | ||
| 754 | /* Mark MCS > 7 as unsupported if STA is in static SMPS mode */ | 867 | /* Mark MCS > 7 as unsupported if STA is in static SMPS mode */ |
| 755 | if (smps == WLAN_HT_CAP_SM_PS_STATIC && | 868 | if (sta->smps_mode == IEEE80211_SMPS_STATIC && |
| 756 | minstrel_mcs_groups[i].streams > 1) | 869 | minstrel_mcs_groups[i].streams > 1) |
| 757 | continue; | 870 | continue; |
| 758 | 871 | ||
diff --git a/net/mac80211/rc80211_minstrel_ht.h b/net/mac80211/rc80211_minstrel_ht.h index 462d2b227ed5..302dbd52180d 100644 --- a/net/mac80211/rc80211_minstrel_ht.h +++ b/net/mac80211/rc80211_minstrel_ht.h | |||
| @@ -107,8 +107,11 @@ struct minstrel_ht_sta { | |||
| 107 | /* current MCS group to be sampled */ | 107 | /* current MCS group to be sampled */ |
| 108 | u8 sample_group; | 108 | u8 sample_group; |
| 109 | 109 | ||
| 110 | u8 cck_supported; | ||
| 111 | u8 cck_supported_short; | ||
| 112 | |||
| 110 | /* MCS rate group info and statistics */ | 113 | /* MCS rate group info and statistics */ |
| 111 | struct minstrel_mcs_group_data groups[MINSTREL_MAX_STREAMS * MINSTREL_STREAM_GROUPS]; | 114 | struct minstrel_mcs_group_data groups[MINSTREL_MAX_STREAMS * MINSTREL_STREAM_GROUPS + 1]; |
| 112 | }; | 115 | }; |
| 113 | 116 | ||
| 114 | struct minstrel_ht_sta_priv { | 117 | struct minstrel_ht_sta_priv { |
diff --git a/net/mac80211/rc80211_minstrel_ht_debugfs.c b/net/mac80211/rc80211_minstrel_ht_debugfs.c index f2b7d26370f0..df44a5ad8270 100644 --- a/net/mac80211/rc80211_minstrel_ht_debugfs.c +++ b/net/mac80211/rc80211_minstrel_ht_debugfs.c | |||
| @@ -15,13 +15,76 @@ | |||
| 15 | #include "rc80211_minstrel.h" | 15 | #include "rc80211_minstrel.h" |
| 16 | #include "rc80211_minstrel_ht.h" | 16 | #include "rc80211_minstrel_ht.h" |
| 17 | 17 | ||
| 18 | static char * | ||
| 19 | minstrel_ht_stats_dump(struct minstrel_ht_sta *mi, int i, char *p) | ||
| 20 | { | ||
| 21 | unsigned int max_mcs = MINSTREL_MAX_STREAMS * MINSTREL_STREAM_GROUPS; | ||
| 22 | const struct mcs_group *mg; | ||
| 23 | unsigned int j, tp, prob, eprob; | ||
| 24 | char htmode = '2'; | ||
| 25 | char gimode = 'L'; | ||
| 26 | |||
| 27 | if (!mi->groups[i].supported) | ||
| 28 | return p; | ||
| 29 | |||
| 30 | mg = &minstrel_mcs_groups[i]; | ||
| 31 | if (mg->flags & IEEE80211_TX_RC_40_MHZ_WIDTH) | ||
| 32 | htmode = '4'; | ||
| 33 | if (mg->flags & IEEE80211_TX_RC_SHORT_GI) | ||
| 34 | gimode = 'S'; | ||
| 35 | |||
| 36 | for (j = 0; j < MCS_GROUP_RATES; j++) { | ||
| 37 | struct minstrel_rate_stats *mr = &mi->groups[i].rates[j]; | ||
| 38 | static const int bitrates[4] = { 10, 20, 55, 110 }; | ||
| 39 | int idx = i * MCS_GROUP_RATES + j; | ||
| 40 | |||
| 41 | if (!(mi->groups[i].supported & BIT(j))) | ||
| 42 | continue; | ||
| 43 | |||
| 44 | if (i == max_mcs) | ||
| 45 | p += sprintf(p, "CCK/%cP ", j < 4 ? 'L' : 'S'); | ||
| 46 | else | ||
| 47 | p += sprintf(p, "HT%c0/%cGI ", htmode, gimode); | ||
| 48 | |||
| 49 | *(p++) = (idx == mi->max_tp_rate) ? 'T' : ' '; | ||
| 50 | *(p++) = (idx == mi->max_tp_rate2) ? 't' : ' '; | ||
| 51 | *(p++) = (idx == mi->max_prob_rate) ? 'P' : ' '; | ||
| 52 | |||
| 53 | if (i == max_mcs) { | ||
| 54 | int r = bitrates[j % 4]; | ||
| 55 | p += sprintf(p, " %2u.%1uM", r / 10, r % 10); | ||
| 56 | } else { | ||
| 57 | p += sprintf(p, " MCS%-2u", (mg->streams - 1) * | ||
| 58 | MCS_GROUP_RATES + j); | ||
| 59 | } | ||
| 60 | |||
| 61 | tp = mr->cur_tp / 10; | ||
| 62 | prob = MINSTREL_TRUNC(mr->cur_prob * 1000); | ||
| 63 | eprob = MINSTREL_TRUNC(mr->probability * 1000); | ||
| 64 | |||
| 65 | p += sprintf(p, " %6u.%1u %6u.%1u %6u.%1u " | ||
| 66 | "%3u %3u(%3u) %8llu %8llu\n", | ||
| 67 | tp / 10, tp % 10, | ||
| 68 | eprob / 10, eprob % 10, | ||
| 69 | prob / 10, prob % 10, | ||
| 70 | mr->retry_count, | ||
| 71 | mr->last_success, | ||
| 72 | mr->last_attempts, | ||
| 73 | (unsigned long long)mr->succ_hist, | ||
| 74 | (unsigned long long)mr->att_hist); | ||
| 75 | } | ||
| 76 | |||
| 77 | return p; | ||
| 78 | } | ||
| 79 | |||
| 18 | static int | 80 | static int |
| 19 | minstrel_ht_stats_open(struct inode *inode, struct file *file) | 81 | minstrel_ht_stats_open(struct inode *inode, struct file *file) |
| 20 | { | 82 | { |
| 21 | struct minstrel_ht_sta_priv *msp = inode->i_private; | 83 | struct minstrel_ht_sta_priv *msp = inode->i_private; |
| 22 | struct minstrel_ht_sta *mi = &msp->ht; | 84 | struct minstrel_ht_sta *mi = &msp->ht; |
| 23 | struct minstrel_debugfs_info *ms; | 85 | struct minstrel_debugfs_info *ms; |
| 24 | unsigned int i, j, tp, prob, eprob; | 86 | unsigned int i; |
| 87 | unsigned int max_mcs = MINSTREL_MAX_STREAMS * MINSTREL_STREAM_GROUPS; | ||
| 25 | char *p; | 88 | char *p; |
| 26 | int ret; | 89 | int ret; |
| 27 | 90 | ||
| @@ -40,49 +103,11 @@ minstrel_ht_stats_open(struct inode *inode, struct file *file) | |||
| 40 | p = ms->buf; | 103 | p = ms->buf; |
| 41 | p += sprintf(p, "type rate throughput ewma prob this prob " | 104 | p += sprintf(p, "type rate throughput ewma prob this prob " |
| 42 | "retry this succ/attempt success attempts\n"); | 105 | "retry this succ/attempt success attempts\n"); |
| 43 | for (i = 0; i < MINSTREL_MAX_STREAMS * MINSTREL_STREAM_GROUPS; i++) { | ||
| 44 | char htmode = '2'; | ||
| 45 | char gimode = 'L'; | ||
| 46 | |||
| 47 | if (!mi->groups[i].supported) | ||
| 48 | continue; | ||
| 49 | |||
| 50 | if (minstrel_mcs_groups[i].flags & IEEE80211_TX_RC_40_MHZ_WIDTH) | ||
| 51 | htmode = '4'; | ||
| 52 | if (minstrel_mcs_groups[i].flags & IEEE80211_TX_RC_SHORT_GI) | ||
| 53 | gimode = 'S'; | ||
| 54 | 106 | ||
| 55 | for (j = 0; j < MCS_GROUP_RATES; j++) { | 107 | p = minstrel_ht_stats_dump(mi, max_mcs, p); |
| 56 | struct minstrel_rate_stats *mr = &mi->groups[i].rates[j]; | 108 | for (i = 0; i < max_mcs; i++) |
| 57 | int idx = i * MCS_GROUP_RATES + j; | 109 | p = minstrel_ht_stats_dump(mi, i, p); |
| 58 | 110 | ||
| 59 | if (!(mi->groups[i].supported & BIT(j))) | ||
| 60 | continue; | ||
| 61 | |||
| 62 | p += sprintf(p, "HT%c0/%cGI ", htmode, gimode); | ||
| 63 | |||
| 64 | *(p++) = (idx == mi->max_tp_rate) ? 'T' : ' '; | ||
| 65 | *(p++) = (idx == mi->max_tp_rate2) ? 't' : ' '; | ||
| 66 | *(p++) = (idx == mi->max_prob_rate) ? 'P' : ' '; | ||
| 67 | p += sprintf(p, " MCS%-2u", (minstrel_mcs_groups[i].streams - 1) * | ||
| 68 | MCS_GROUP_RATES + j); | ||
| 69 | |||
| 70 | tp = mr->cur_tp / 10; | ||
| 71 | prob = MINSTREL_TRUNC(mr->cur_prob * 1000); | ||
| 72 | eprob = MINSTREL_TRUNC(mr->probability * 1000); | ||
| 73 | |||
| 74 | p += sprintf(p, " %6u.%1u %6u.%1u %6u.%1u " | ||
| 75 | "%3u %3u(%3u) %8llu %8llu\n", | ||
| 76 | tp / 10, tp % 10, | ||
| 77 | eprob / 10, eprob % 10, | ||
| 78 | prob / 10, prob % 10, | ||
| 79 | mr->retry_count, | ||
| 80 | mr->last_success, | ||
| 81 | mr->last_attempts, | ||
| 82 | (unsigned long long)mr->succ_hist, | ||
| 83 | (unsigned long long)mr->att_hist); | ||
| 84 | } | ||
| 85 | } | ||
| 86 | p += sprintf(p, "\nTotal packet count:: ideal %d " | 111 | p += sprintf(p, "\nTotal packet count:: ideal %d " |
| 87 | "lookaround %d\n", | 112 | "lookaround %d\n", |
| 88 | max(0, (int) mi->total_packets - (int) mi->sample_packets), | 113 | max(0, (int) mi->total_packets - (int) mi->sample_packets), |
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index b5f1bba7ffe1..3acb70b73e22 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c | |||
| @@ -2375,31 +2375,27 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx) | |||
| 2375 | switch (mgmt->u.action.u.ht_smps.action) { | 2375 | switch (mgmt->u.action.u.ht_smps.action) { |
| 2376 | case WLAN_HT_ACTION_SMPS: { | 2376 | case WLAN_HT_ACTION_SMPS: { |
| 2377 | struct ieee80211_supported_band *sband; | 2377 | struct ieee80211_supported_band *sband; |
| 2378 | u8 smps; | 2378 | enum ieee80211_smps_mode smps_mode; |
| 2379 | 2379 | ||
| 2380 | /* convert to HT capability */ | 2380 | /* convert to HT capability */ |
| 2381 | switch (mgmt->u.action.u.ht_smps.smps_control) { | 2381 | switch (mgmt->u.action.u.ht_smps.smps_control) { |
| 2382 | case WLAN_HT_SMPS_CONTROL_DISABLED: | 2382 | case WLAN_HT_SMPS_CONTROL_DISABLED: |
| 2383 | smps = WLAN_HT_CAP_SM_PS_DISABLED; | 2383 | smps_mode = IEEE80211_SMPS_OFF; |
| 2384 | break; | 2384 | break; |
| 2385 | case WLAN_HT_SMPS_CONTROL_STATIC: | 2385 | case WLAN_HT_SMPS_CONTROL_STATIC: |
| 2386 | smps = WLAN_HT_CAP_SM_PS_STATIC; | 2386 | smps_mode = IEEE80211_SMPS_STATIC; |
| 2387 | break; | 2387 | break; |
| 2388 | case WLAN_HT_SMPS_CONTROL_DYNAMIC: | 2388 | case WLAN_HT_SMPS_CONTROL_DYNAMIC: |
| 2389 | smps = WLAN_HT_CAP_SM_PS_DYNAMIC; | 2389 | smps_mode = IEEE80211_SMPS_DYNAMIC; |
| 2390 | break; | 2390 | break; |
| 2391 | default: | 2391 | default: |
| 2392 | goto invalid; | 2392 | goto invalid; |
| 2393 | } | 2393 | } |
| 2394 | smps <<= IEEE80211_HT_CAP_SM_PS_SHIFT; | ||
| 2395 | 2394 | ||
| 2396 | /* if no change do nothing */ | 2395 | /* if no change do nothing */ |
| 2397 | if ((rx->sta->sta.ht_cap.cap & | 2396 | if (rx->sta->sta.smps_mode == smps_mode) |
| 2398 | IEEE80211_HT_CAP_SM_PS) == smps) | ||
| 2399 | goto handled; | 2397 | goto handled; |
| 2400 | 2398 | rx->sta->sta.smps_mode = smps_mode; | |
| 2401 | rx->sta->sta.ht_cap.cap &= ~IEEE80211_HT_CAP_SM_PS; | ||
| 2402 | rx->sta->sta.ht_cap.cap |= smps; | ||
| 2403 | 2399 | ||
| 2404 | sband = rx->local->hw.wiphy->bands[status->band]; | 2400 | sband = rx->local->hw.wiphy->bands[status->band]; |
| 2405 | 2401 | ||
| @@ -2410,26 +2406,21 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx) | |||
| 2410 | case WLAN_HT_ACTION_NOTIFY_CHANWIDTH: { | 2406 | case WLAN_HT_ACTION_NOTIFY_CHANWIDTH: { |
| 2411 | struct ieee80211_supported_band *sband; | 2407 | struct ieee80211_supported_band *sband; |
| 2412 | u8 chanwidth = mgmt->u.action.u.ht_notify_cw.chanwidth; | 2408 | u8 chanwidth = mgmt->u.action.u.ht_notify_cw.chanwidth; |
| 2413 | bool old_40mhz, new_40mhz; | 2409 | enum ieee80211_sta_rx_bandwidth new_bw; |
| 2414 | 2410 | ||
| 2415 | /* If it doesn't support 40 MHz it can't change ... */ | 2411 | /* If it doesn't support 40 MHz it can't change ... */ |
| 2416 | if (!rx->sta->supports_40mhz) | 2412 | if (!(rx->sta->sta.ht_cap.cap & |
| 2413 | IEEE80211_HT_CAP_SUP_WIDTH_20_40)) | ||
| 2417 | goto handled; | 2414 | goto handled; |
| 2418 | 2415 | ||
| 2419 | old_40mhz = rx->sta->sta.ht_cap.cap & | 2416 | if (chanwidth == IEEE80211_HT_CHANWIDTH_20MHZ) |
| 2420 | IEEE80211_HT_CAP_SUP_WIDTH_20_40; | 2417 | new_bw = IEEE80211_STA_RX_BW_20; |
| 2421 | new_40mhz = chanwidth == IEEE80211_HT_CHANWIDTH_ANY; | 2418 | else |
| 2419 | new_bw = ieee80211_sta_cur_vht_bw(rx->sta); | ||
| 2422 | 2420 | ||
| 2423 | if (old_40mhz == new_40mhz) | 2421 | if (rx->sta->sta.bandwidth == new_bw) |
| 2424 | goto handled; | 2422 | goto handled; |
| 2425 | 2423 | ||
| 2426 | if (new_40mhz) | ||
| 2427 | rx->sta->sta.ht_cap.cap |= | ||
| 2428 | IEEE80211_HT_CAP_SUP_WIDTH_20_40; | ||
| 2429 | else | ||
| 2430 | rx->sta->sta.ht_cap.cap &= | ||
| 2431 | ~IEEE80211_HT_CAP_SUP_WIDTH_20_40; | ||
| 2432 | |||
| 2433 | sband = rx->local->hw.wiphy->bands[status->band]; | 2424 | sband = rx->local->hw.wiphy->bands[status->band]; |
| 2434 | 2425 | ||
| 2435 | rate_control_rate_update(local, sband, rx->sta, | 2426 | rate_control_rate_update(local, sband, rx->sta, |
| @@ -2441,6 +2432,37 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx) | |||
| 2441 | } | 2432 | } |
| 2442 | 2433 | ||
| 2443 | break; | 2434 | break; |
| 2435 | case WLAN_CATEGORY_VHT: | ||
| 2436 | if (sdata->vif.type != NL80211_IFTYPE_STATION && | ||
| 2437 | sdata->vif.type != NL80211_IFTYPE_MESH_POINT && | ||
| 2438 | sdata->vif.type != NL80211_IFTYPE_AP_VLAN && | ||
| 2439 | sdata->vif.type != NL80211_IFTYPE_AP && | ||
| 2440 | sdata->vif.type != NL80211_IFTYPE_ADHOC) | ||
| 2441 | break; | ||
| 2442 | |||
| 2443 | /* verify action code is present */ | ||
| 2444 | if (len < IEEE80211_MIN_ACTION_SIZE + 1) | ||
| 2445 | goto invalid; | ||
| 2446 | |||
| 2447 | switch (mgmt->u.action.u.vht_opmode_notif.action_code) { | ||
| 2448 | case WLAN_VHT_ACTION_OPMODE_NOTIF: { | ||
| 2449 | u8 opmode; | ||
| 2450 | |||
| 2451 | /* verify opmode is present */ | ||
| 2452 | if (len < IEEE80211_MIN_ACTION_SIZE + 2) | ||
| 2453 | goto invalid; | ||
| 2454 | |||
| 2455 | opmode = mgmt->u.action.u.vht_opmode_notif.operating_mode; | ||
| 2456 | |||
| 2457 | ieee80211_vht_handle_opmode(rx->sdata, rx->sta, | ||
| 2458 | opmode, status->band, | ||
| 2459 | false); | ||
| 2460 | goto handled; | ||
| 2461 | } | ||
| 2462 | default: | ||
| 2463 | break; | ||
| 2464 | } | ||
| 2465 | break; | ||
| 2444 | case WLAN_CATEGORY_BACK: | 2466 | case WLAN_CATEGORY_BACK: |
| 2445 | if (sdata->vif.type != NL80211_IFTYPE_STATION && | 2467 | if (sdata->vif.type != NL80211_IFTYPE_STATION && |
| 2446 | sdata->vif.type != NL80211_IFTYPE_MESH_POINT && | 2468 | sdata->vif.type != NL80211_IFTYPE_MESH_POINT && |
| @@ -2692,8 +2714,9 @@ ieee80211_rx_h_mgmt(struct ieee80211_rx_data *rx) | |||
| 2692 | return RX_DROP_MONITOR; | 2714 | return RX_DROP_MONITOR; |
| 2693 | break; | 2715 | break; |
| 2694 | case cpu_to_le16(IEEE80211_STYPE_PROBE_REQ): | 2716 | case cpu_to_le16(IEEE80211_STYPE_PROBE_REQ): |
| 2695 | /* process only for ibss */ | 2717 | /* process only for ibss and mesh */ |
| 2696 | if (sdata->vif.type != NL80211_IFTYPE_ADHOC) | 2718 | if (sdata->vif.type != NL80211_IFTYPE_ADHOC && |
| 2719 | sdata->vif.type != NL80211_IFTYPE_MESH_POINT) | ||
| 2697 | return RX_DROP_MONITOR; | 2720 | return RX_DROP_MONITOR; |
| 2698 | break; | 2721 | break; |
| 2699 | default: | 2722 | default: |
diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c index 6d0b89e4aa31..43a45cf00e06 100644 --- a/net/mac80211/scan.c +++ b/net/mac80211/scan.c | |||
| @@ -351,6 +351,9 @@ static int ieee80211_start_sw_scan(struct ieee80211_local *local) | |||
| 351 | static bool ieee80211_can_scan(struct ieee80211_local *local, | 351 | static bool ieee80211_can_scan(struct ieee80211_local *local, |
| 352 | struct ieee80211_sub_if_data *sdata) | 352 | struct ieee80211_sub_if_data *sdata) |
| 353 | { | 353 | { |
| 354 | if (local->radar_detect_enabled) | ||
| 355 | return false; | ||
| 356 | |||
| 354 | if (!list_empty(&local->roc_list)) | 357 | if (!list_empty(&local->roc_list)) |
| 355 | return false; | 358 | return false; |
| 356 | 359 | ||
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index 19db20a58e23..a79ce820cb50 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c | |||
| @@ -375,6 +375,8 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata, | |||
| 375 | for (i = 0; i < IEEE80211_NUM_TIDS; i++) | 375 | for (i = 0; i < IEEE80211_NUM_TIDS; i++) |
| 376 | sta->last_seq_ctrl[i] = cpu_to_le16(USHRT_MAX); | 376 | sta->last_seq_ctrl[i] = cpu_to_le16(USHRT_MAX); |
| 377 | 377 | ||
| 378 | sta->sta.smps_mode = IEEE80211_SMPS_OFF; | ||
| 379 | |||
| 378 | sta_dbg(sdata, "Allocated STA %pM\n", sta->sta.addr); | 380 | sta_dbg(sdata, "Allocated STA %pM\n", sta->sta.addr); |
| 379 | 381 | ||
| 380 | return sta; | 382 | return sta; |
| @@ -571,7 +573,6 @@ void sta_info_recalc_tim(struct sta_info *sta) | |||
| 571 | { | 573 | { |
| 572 | struct ieee80211_local *local = sta->local; | 574 | struct ieee80211_local *local = sta->local; |
| 573 | struct ps_data *ps; | 575 | struct ps_data *ps; |
| 574 | unsigned long flags; | ||
| 575 | bool indicate_tim = false; | 576 | bool indicate_tim = false; |
| 576 | u8 ignore_for_tim = sta->sta.uapsd_queues; | 577 | u8 ignore_for_tim = sta->sta.uapsd_queues; |
| 577 | int ac; | 578 | int ac; |
| @@ -628,7 +629,7 @@ void sta_info_recalc_tim(struct sta_info *sta) | |||
| 628 | } | 629 | } |
| 629 | 630 | ||
| 630 | done: | 631 | done: |
| 631 | spin_lock_irqsave(&local->tim_lock, flags); | 632 | spin_lock_bh(&local->tim_lock); |
| 632 | 633 | ||
| 633 | if (indicate_tim) | 634 | if (indicate_tim) |
| 634 | __bss_tim_set(ps->tim, id); | 635 | __bss_tim_set(ps->tim, id); |
| @@ -641,7 +642,7 @@ void sta_info_recalc_tim(struct sta_info *sta) | |||
| 641 | local->tim_in_locked_section = false; | 642 | local->tim_in_locked_section = false; |
| 642 | } | 643 | } |
| 643 | 644 | ||
| 644 | spin_unlock_irqrestore(&local->tim_lock, flags); | 645 | spin_unlock_bh(&local->tim_lock); |
| 645 | } | 646 | } |
| 646 | 647 | ||
| 647 | static bool sta_info_buffer_expired(struct sta_info *sta, struct sk_buff *skb) | 648 | static bool sta_info_buffer_expired(struct sta_info *sta, struct sk_buff *skb) |
| @@ -1120,6 +1121,8 @@ static void ieee80211_send_null_response(struct ieee80211_sub_if_data *sdata, | |||
| 1120 | 1121 | ||
| 1121 | drv_allow_buffered_frames(local, sta, BIT(tid), 1, reason, false); | 1122 | drv_allow_buffered_frames(local, sta, BIT(tid), 1, reason, false); |
| 1122 | 1123 | ||
| 1124 | skb->dev = sdata->dev; | ||
| 1125 | |||
| 1123 | rcu_read_lock(); | 1126 | rcu_read_lock(); |
| 1124 | chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); | 1127 | chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); |
| 1125 | if (WARN_ON(!chanctx_conf)) { | 1128 | if (WARN_ON(!chanctx_conf)) { |
diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index 350578c396c0..63dfdb5e91da 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h | |||
| @@ -296,9 +296,9 @@ struct sta_ampdu_mlme { | |||
| 296 | * @sta: station information we share with the driver | 296 | * @sta: station information we share with the driver |
| 297 | * @sta_state: duplicates information about station state (for debug) | 297 | * @sta_state: duplicates information about station state (for debug) |
| 298 | * @beacon_loss_count: number of times beacon loss has triggered | 298 | * @beacon_loss_count: number of times beacon loss has triggered |
| 299 | * @supports_40mhz: tracks whether the station advertised 40 MHz support | ||
| 300 | * as we overwrite its HT parameters with the currently used value | ||
| 301 | * @rcu_head: RCU head used for freeing this station struct | 299 | * @rcu_head: RCU head used for freeing this station struct |
| 300 | * @cur_max_bandwidth: maximum bandwidth to use for TX to the station, | ||
| 301 | * taken from HT/VHT capabilities or VHT operating mode notification | ||
| 302 | */ | 302 | */ |
| 303 | struct sta_info { | 303 | struct sta_info { |
| 304 | /* General information, mostly static */ | 304 | /* General information, mostly static */ |
| @@ -400,11 +400,11 @@ struct sta_info { | |||
| 400 | } debugfs; | 400 | } debugfs; |
| 401 | #endif | 401 | #endif |
| 402 | 402 | ||
| 403 | enum ieee80211_sta_rx_bandwidth cur_max_bandwidth; | ||
| 404 | |||
| 403 | unsigned int lost_packets; | 405 | unsigned int lost_packets; |
| 404 | unsigned int beacon_loss_count; | 406 | unsigned int beacon_loss_count; |
| 405 | 407 | ||
| 406 | bool supports_40mhz; | ||
| 407 | |||
| 408 | /* keep last! */ | 408 | /* keep last! */ |
| 409 | struct ieee80211_sta sta; | 409 | struct ieee80211_sta sta; |
| 410 | }; | 410 | }; |
diff --git a/net/mac80211/tkip.c b/net/mac80211/tkip.c index 57e14d59e12f..3ed801d90f1e 100644 --- a/net/mac80211/tkip.c +++ b/net/mac80211/tkip.c | |||
| @@ -177,12 +177,11 @@ void ieee80211_get_tkip_p1k_iv(struct ieee80211_key_conf *keyconf, | |||
| 177 | struct ieee80211_key *key = (struct ieee80211_key *) | 177 | struct ieee80211_key *key = (struct ieee80211_key *) |
| 178 | container_of(keyconf, struct ieee80211_key, conf); | 178 | container_of(keyconf, struct ieee80211_key, conf); |
| 179 | struct tkip_ctx *ctx = &key->u.tkip.tx; | 179 | struct tkip_ctx *ctx = &key->u.tkip.tx; |
| 180 | unsigned long flags; | ||
| 181 | 180 | ||
| 182 | spin_lock_irqsave(&key->u.tkip.txlock, flags); | 181 | spin_lock_bh(&key->u.tkip.txlock); |
| 183 | ieee80211_compute_tkip_p1k(key, iv32); | 182 | ieee80211_compute_tkip_p1k(key, iv32); |
| 184 | memcpy(p1k, ctx->p1k, sizeof(ctx->p1k)); | 183 | memcpy(p1k, ctx->p1k, sizeof(ctx->p1k)); |
| 185 | spin_unlock_irqrestore(&key->u.tkip.txlock, flags); | 184 | spin_unlock_bh(&key->u.tkip.txlock); |
| 186 | } | 185 | } |
| 187 | EXPORT_SYMBOL(ieee80211_get_tkip_p1k_iv); | 186 | EXPORT_SYMBOL(ieee80211_get_tkip_p1k_iv); |
| 188 | 187 | ||
| @@ -208,12 +207,11 @@ void ieee80211_get_tkip_p2k(struct ieee80211_key_conf *keyconf, | |||
| 208 | const u8 *data = (u8 *)hdr + ieee80211_hdrlen(hdr->frame_control); | 207 | const u8 *data = (u8 *)hdr + ieee80211_hdrlen(hdr->frame_control); |
| 209 | u32 iv32 = get_unaligned_le32(&data[4]); | 208 | u32 iv32 = get_unaligned_le32(&data[4]); |
| 210 | u16 iv16 = data[2] | (data[0] << 8); | 209 | u16 iv16 = data[2] | (data[0] << 8); |
| 211 | unsigned long flags; | ||
| 212 | 210 | ||
| 213 | spin_lock_irqsave(&key->u.tkip.txlock, flags); | 211 | spin_lock_bh(&key->u.tkip.txlock); |
| 214 | ieee80211_compute_tkip_p1k(key, iv32); | 212 | ieee80211_compute_tkip_p1k(key, iv32); |
| 215 | tkip_mixing_phase2(tk, ctx, iv16, p2k); | 213 | tkip_mixing_phase2(tk, ctx, iv16, p2k); |
| 216 | spin_unlock_irqrestore(&key->u.tkip.txlock, flags); | 214 | spin_unlock_bh(&key->u.tkip.txlock); |
| 217 | } | 215 | } |
| 218 | EXPORT_SYMBOL(ieee80211_get_tkip_p2k); | 216 | EXPORT_SYMBOL(ieee80211_get_tkip_p2k); |
| 219 | 217 | ||
diff --git a/net/mac80211/trace.h b/net/mac80211/trace.h index 0bdd7aeb8958..1183c4a4fee5 100644 --- a/net/mac80211/trace.h +++ b/net/mac80211/trace.h | |||
| @@ -1862,6 +1862,25 @@ TRACE_EVENT(drv_set_default_unicast_key, | |||
| 1862 | LOCAL_PR_ARG, VIF_PR_ARG, __entry->key_idx) | 1862 | LOCAL_PR_ARG, VIF_PR_ARG, __entry->key_idx) |
| 1863 | ); | 1863 | ); |
| 1864 | 1864 | ||
| 1865 | TRACE_EVENT(api_radar_detected, | ||
| 1866 | TP_PROTO(struct ieee80211_local *local), | ||
| 1867 | |||
| 1868 | TP_ARGS(local), | ||
| 1869 | |||
| 1870 | TP_STRUCT__entry( | ||
| 1871 | LOCAL_ENTRY | ||
| 1872 | ), | ||
| 1873 | |||
| 1874 | TP_fast_assign( | ||
| 1875 | LOCAL_ASSIGN; | ||
| 1876 | ), | ||
| 1877 | |||
| 1878 | TP_printk( | ||
| 1879 | LOCAL_PR_FMT " radar detected", | ||
| 1880 | LOCAL_PR_ARG | ||
| 1881 | ) | ||
| 1882 | ); | ||
| 1883 | |||
| 1865 | #ifdef CONFIG_MAC80211_MESSAGE_TRACING | 1884 | #ifdef CONFIG_MAC80211_MESSAGE_TRACING |
| 1866 | #undef TRACE_SYSTEM | 1885 | #undef TRACE_SYSTEM |
| 1867 | #define TRACE_SYSTEM mac80211_msg | 1886 | #define TRACE_SYSTEM mac80211_msg |
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index f476aa6a771d..fe644f91ae05 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c | |||
| @@ -2364,11 +2364,9 @@ static int ieee80211_beacon_add_tim(struct ieee80211_sub_if_data *sdata, | |||
| 2364 | if (local->tim_in_locked_section) { | 2364 | if (local->tim_in_locked_section) { |
| 2365 | __ieee80211_beacon_add_tim(sdata, ps, skb); | 2365 | __ieee80211_beacon_add_tim(sdata, ps, skb); |
| 2366 | } else { | 2366 | } else { |
| 2367 | unsigned long flags; | 2367 | spin_lock(&local->tim_lock); |
| 2368 | |||
| 2369 | spin_lock_irqsave(&local->tim_lock, flags); | ||
| 2370 | __ieee80211_beacon_add_tim(sdata, ps, skb); | 2368 | __ieee80211_beacon_add_tim(sdata, ps, skb); |
| 2371 | spin_unlock_irqrestore(&local->tim_lock, flags); | 2369 | spin_unlock(&local->tim_lock); |
| 2372 | } | 2370 | } |
| 2373 | 2371 | ||
| 2374 | return 0; | 2372 | return 0; |
| @@ -2446,71 +2444,26 @@ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw, | |||
| 2446 | hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | | 2444 | hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | |
| 2447 | IEEE80211_STYPE_BEACON); | 2445 | IEEE80211_STYPE_BEACON); |
| 2448 | } else if (ieee80211_vif_is_mesh(&sdata->vif)) { | 2446 | } else if (ieee80211_vif_is_mesh(&sdata->vif)) { |
| 2449 | struct ieee80211_mgmt *mgmt; | ||
| 2450 | struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; | 2447 | struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; |
| 2451 | u8 *pos; | 2448 | struct beacon_data *bcn = rcu_dereference(ifmsh->beacon); |
| 2452 | int hdr_len = offsetof(struct ieee80211_mgmt, u.beacon) + | ||
| 2453 | sizeof(mgmt->u.beacon); | ||
| 2454 | 2449 | ||
| 2455 | #ifdef CONFIG_MAC80211_MESH | 2450 | if (!bcn) |
| 2456 | if (!sdata->u.mesh.mesh_id_len) | ||
| 2457 | goto out; | 2451 | goto out; |
| 2458 | #endif | ||
| 2459 | 2452 | ||
| 2460 | if (ifmsh->sync_ops) | 2453 | if (ifmsh->sync_ops) |
| 2461 | ifmsh->sync_ops->adjust_tbtt( | 2454 | ifmsh->sync_ops->adjust_tbtt( |
| 2462 | sdata); | 2455 | sdata); |
| 2463 | 2456 | ||
| 2464 | skb = dev_alloc_skb(local->tx_headroom + | 2457 | skb = dev_alloc_skb(local->tx_headroom + |
| 2465 | hdr_len + | 2458 | bcn->head_len + |
| 2466 | 2 + /* NULL SSID */ | ||
| 2467 | 2 + 8 + /* supported rates */ | ||
| 2468 | 2 + 3 + /* DS params */ | ||
| 2469 | 256 + /* TIM IE */ | 2459 | 256 + /* TIM IE */ |
| 2470 | 2 + (IEEE80211_MAX_SUPP_RATES - 8) + | 2460 | bcn->tail_len); |
| 2471 | 2 + sizeof(struct ieee80211_ht_cap) + | ||
| 2472 | 2 + sizeof(struct ieee80211_ht_operation) + | ||
| 2473 | 2 + sdata->u.mesh.mesh_id_len + | ||
| 2474 | 2 + sizeof(struct ieee80211_meshconf_ie) + | ||
| 2475 | sdata->u.mesh.ie_len + | ||
| 2476 | 2 + sizeof(__le16)); /* awake window */ | ||
| 2477 | if (!skb) | 2461 | if (!skb) |
| 2478 | goto out; | 2462 | goto out; |
| 2479 | 2463 | skb_reserve(skb, local->tx_headroom); | |
| 2480 | skb_reserve(skb, local->hw.extra_tx_headroom); | 2464 | memcpy(skb_put(skb, bcn->head_len), bcn->head, bcn->head_len); |
| 2481 | mgmt = (struct ieee80211_mgmt *) skb_put(skb, hdr_len); | 2465 | ieee80211_beacon_add_tim(sdata, &ifmsh->ps, skb); |
| 2482 | memset(mgmt, 0, hdr_len); | 2466 | memcpy(skb_put(skb, bcn->tail_len), bcn->tail, bcn->tail_len); |
| 2483 | mgmt->frame_control = | ||
| 2484 | cpu_to_le16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_BEACON); | ||
| 2485 | eth_broadcast_addr(mgmt->da); | ||
| 2486 | memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN); | ||
| 2487 | memcpy(mgmt->bssid, sdata->vif.addr, ETH_ALEN); | ||
| 2488 | ieee80211_mps_set_frame_flags(sdata, NULL, (void *) mgmt); | ||
| 2489 | mgmt->u.beacon.beacon_int = | ||
| 2490 | cpu_to_le16(sdata->vif.bss_conf.beacon_int); | ||
| 2491 | mgmt->u.beacon.capab_info |= cpu_to_le16( | ||
| 2492 | sdata->u.mesh.security ? WLAN_CAPABILITY_PRIVACY : 0); | ||
| 2493 | |||
| 2494 | pos = skb_put(skb, 2); | ||
| 2495 | *pos++ = WLAN_EID_SSID; | ||
| 2496 | *pos++ = 0x0; | ||
| 2497 | |||
| 2498 | band = chanctx_conf->def.chan->band; | ||
| 2499 | |||
| 2500 | if (ieee80211_add_srates_ie(sdata, skb, true, band) || | ||
| 2501 | mesh_add_ds_params_ie(skb, sdata) || | ||
| 2502 | ieee80211_beacon_add_tim(sdata, &ifmsh->ps, skb) || | ||
| 2503 | ieee80211_add_ext_srates_ie(sdata, skb, true, band) || | ||
| 2504 | mesh_add_rsn_ie(skb, sdata) || | ||
| 2505 | mesh_add_ht_cap_ie(skb, sdata) || | ||
| 2506 | mesh_add_ht_oper_ie(skb, sdata) || | ||
| 2507 | mesh_add_meshid_ie(skb, sdata) || | ||
| 2508 | mesh_add_meshconf_ie(skb, sdata) || | ||
| 2509 | mesh_add_awake_window_ie(skb, sdata) || | ||
| 2510 | mesh_add_vendor_ies(skb, sdata)) { | ||
| 2511 | pr_err("o11s: couldn't add ies!\n"); | ||
| 2512 | goto out; | ||
| 2513 | } | ||
| 2514 | } else { | 2467 | } else { |
| 2515 | WARN_ON(1); | 2468 | WARN_ON(1); |
| 2516 | goto out; | 2469 | goto out; |
| @@ -2785,6 +2738,7 @@ ieee80211_get_buffered_bc(struct ieee80211_hw *hw, | |||
| 2785 | cpu_to_le16(IEEE80211_FCTL_MOREDATA); | 2738 | cpu_to_le16(IEEE80211_FCTL_MOREDATA); |
| 2786 | } | 2739 | } |
| 2787 | 2740 | ||
| 2741 | sdata = IEEE80211_DEV_TO_SUB_IF(skb->dev); | ||
| 2788 | if (!ieee80211_tx_prepare(sdata, &tx, skb)) | 2742 | if (!ieee80211_tx_prepare(sdata, &tx, skb)) |
| 2789 | break; | 2743 | break; |
| 2790 | dev_kfree_skb_any(skb); | 2744 | dev_kfree_skb_any(skb); |
| @@ -2817,6 +2771,8 @@ void __ieee80211_tx_skb_tid_band(struct ieee80211_sub_if_data *sdata, | |||
| 2817 | skb_set_queue_mapping(skb, ac); | 2771 | skb_set_queue_mapping(skb, ac); |
| 2818 | skb->priority = tid; | 2772 | skb->priority = tid; |
| 2819 | 2773 | ||
| 2774 | skb->dev = sdata->dev; | ||
| 2775 | |||
| 2820 | /* | 2776 | /* |
| 2821 | * The other path calling ieee80211_xmit is from the tasklet, | 2777 | * The other path calling ieee80211_xmit is from the tasklet, |
| 2822 | * and while we can handle concurrent transmissions locking | 2778 | * and while we can handle concurrent transmissions locking |
diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 6cb71a350edd..0f38f43ac62e 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c | |||
| @@ -739,11 +739,7 @@ u32 ieee802_11_parse_elems_crc(u8 *start, size_t len, | |||
| 739 | if (calc_crc) | 739 | if (calc_crc) |
| 740 | crc = crc32_be(crc, pos - 2, elen + 2); | 740 | crc = crc32_be(crc, pos - 2, elen + 2); |
| 741 | 741 | ||
| 742 | if (pos[3] == 1) { | 742 | if (elen >= 5 && pos[3] == 2) { |
| 743 | /* OUI Type 1 - WPA IE */ | ||
| 744 | elems->wpa = pos; | ||
| 745 | elems->wpa_len = elen; | ||
| 746 | } else if (elen >= 5 && pos[3] == 2) { | ||
| 747 | /* OUI Type 2 - WMM IE */ | 743 | /* OUI Type 2 - WMM IE */ |
| 748 | if (pos[4] == 0) { | 744 | if (pos[4] == 0) { |
| 749 | elems->wmm_info = pos; | 745 | elems->wmm_info = pos; |
| @@ -791,6 +787,12 @@ u32 ieee802_11_parse_elems_crc(u8 *start, size_t len, | |||
| 791 | else | 787 | else |
| 792 | elem_parse_failed = true; | 788 | elem_parse_failed = true; |
| 793 | break; | 789 | break; |
| 790 | case WLAN_EID_OPMODE_NOTIF: | ||
| 791 | if (elen > 0) | ||
| 792 | elems->opmode_notif = pos; | ||
| 793 | else | ||
| 794 | elem_parse_failed = true; | ||
| 795 | break; | ||
| 794 | case WLAN_EID_MESH_ID: | 796 | case WLAN_EID_MESH_ID: |
| 795 | elems->mesh_id = pos; | 797 | elems->mesh_id = pos; |
| 796 | elems->mesh_id_len = elen; | 798 | elems->mesh_id_len = elen; |
| @@ -1033,7 +1035,7 @@ u32 ieee80211_mandatory_rates(struct ieee80211_local *local, | |||
| 1033 | 1035 | ||
| 1034 | void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata, | 1036 | void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata, |
| 1035 | u16 transaction, u16 auth_alg, u16 status, | 1037 | u16 transaction, u16 auth_alg, u16 status, |
| 1036 | u8 *extra, size_t extra_len, const u8 *da, | 1038 | const u8 *extra, size_t extra_len, const u8 *da, |
| 1037 | const u8 *bssid, const u8 *key, u8 key_len, u8 key_idx, | 1039 | const u8 *bssid, const u8 *key, u8 key_len, u8 key_idx, |
| 1038 | u32 tx_flags) | 1040 | u32 tx_flags) |
| 1039 | { | 1041 | { |
| @@ -1945,7 +1947,7 @@ u8 *ieee80211_ie_build_ht_oper(u8 *pos, struct ieee80211_sta_ht_cap *ht_cap, | |||
| 1945 | } | 1947 | } |
| 1946 | 1948 | ||
| 1947 | void ieee80211_ht_oper_to_chandef(struct ieee80211_channel *control_chan, | 1949 | void ieee80211_ht_oper_to_chandef(struct ieee80211_channel *control_chan, |
| 1948 | struct ieee80211_ht_operation *ht_oper, | 1950 | const struct ieee80211_ht_operation *ht_oper, |
| 1949 | struct cfg80211_chan_def *chandef) | 1951 | struct cfg80211_chan_def *chandef) |
| 1950 | { | 1952 | { |
| 1951 | enum nl80211_channel_type channel_type; | 1953 | enum nl80211_channel_type channel_type; |
| @@ -2133,3 +2135,49 @@ u64 ieee80211_calculate_rx_timestamp(struct ieee80211_local *local, | |||
| 2133 | 2135 | ||
| 2134 | return ts; | 2136 | return ts; |
| 2135 | } | 2137 | } |
| 2138 | |||
| 2139 | void ieee80211_dfs_cac_cancel(struct ieee80211_local *local) | ||
| 2140 | { | ||
| 2141 | struct ieee80211_sub_if_data *sdata; | ||
| 2142 | |||
| 2143 | mutex_lock(&local->iflist_mtx); | ||
| 2144 | list_for_each_entry(sdata, &local->interfaces, list) { | ||
| 2145 | cancel_delayed_work_sync(&sdata->dfs_cac_timer_work); | ||
| 2146 | |||
| 2147 | if (sdata->wdev.cac_started) { | ||
| 2148 | ieee80211_vif_release_channel(sdata); | ||
| 2149 | cfg80211_cac_event(sdata->dev, | ||
| 2150 | NL80211_RADAR_CAC_ABORTED, | ||
| 2151 | GFP_KERNEL); | ||
| 2152 | } | ||
| 2153 | } | ||
| 2154 | mutex_unlock(&local->iflist_mtx); | ||
| 2155 | } | ||
| 2156 | |||
| 2157 | void ieee80211_dfs_radar_detected_work(struct work_struct *work) | ||
| 2158 | { | ||
| 2159 | struct ieee80211_local *local = | ||
| 2160 | container_of(work, struct ieee80211_local, radar_detected_work); | ||
| 2161 | struct cfg80211_chan_def chandef; | ||
| 2162 | |||
| 2163 | ieee80211_dfs_cac_cancel(local); | ||
| 2164 | |||
| 2165 | if (local->use_chanctx) | ||
| 2166 | /* currently not handled */ | ||
| 2167 | WARN_ON(1); | ||
| 2168 | else { | ||
| 2169 | cfg80211_chandef_create(&chandef, local->hw.conf.channel, | ||
| 2170 | local->hw.conf.channel_type); | ||
| 2171 | cfg80211_radar_event(local->hw.wiphy, &chandef, GFP_KERNEL); | ||
| 2172 | } | ||
| 2173 | } | ||
| 2174 | |||
| 2175 | void ieee80211_radar_detected(struct ieee80211_hw *hw) | ||
| 2176 | { | ||
| 2177 | struct ieee80211_local *local = hw_to_local(hw); | ||
| 2178 | |||
| 2179 | trace_api_radar_detected(local); | ||
| 2180 | |||
| 2181 | ieee80211_queue_work(hw, &local->radar_detected_work); | ||
| 2182 | } | ||
| 2183 | EXPORT_SYMBOL(ieee80211_radar_detected); | ||
diff --git a/net/mac80211/vht.c b/net/mac80211/vht.c index f311388aeedf..a2c2258bc84e 100644 --- a/net/mac80211/vht.c +++ b/net/mac80211/vht.c | |||
| @@ -10,21 +10,29 @@ | |||
| 10 | #include <linux/export.h> | 10 | #include <linux/export.h> |
| 11 | #include <net/mac80211.h> | 11 | #include <net/mac80211.h> |
| 12 | #include "ieee80211_i.h" | 12 | #include "ieee80211_i.h" |
| 13 | #include "rate.h" | ||
| 13 | 14 | ||
| 14 | 15 | ||
| 15 | void ieee80211_vht_cap_ie_to_sta_vht_cap(struct ieee80211_sub_if_data *sdata, | 16 | void |
| 16 | struct ieee80211_supported_band *sband, | 17 | ieee80211_vht_cap_ie_to_sta_vht_cap(struct ieee80211_sub_if_data *sdata, |
| 17 | struct ieee80211_vht_cap *vht_cap_ie, | 18 | struct ieee80211_supported_band *sband, |
| 18 | struct ieee80211_sta_vht_cap *vht_cap) | 19 | const struct ieee80211_vht_cap *vht_cap_ie, |
| 20 | struct sta_info *sta) | ||
| 19 | { | 21 | { |
| 20 | if (WARN_ON_ONCE(!vht_cap)) | 22 | struct ieee80211_sta_vht_cap *vht_cap = &sta->sta.vht_cap; |
| 21 | return; | ||
| 22 | 23 | ||
| 23 | memset(vht_cap, 0, sizeof(*vht_cap)); | 24 | memset(vht_cap, 0, sizeof(*vht_cap)); |
| 24 | 25 | ||
| 26 | if (!sta->sta.ht_cap.ht_supported) | ||
| 27 | return; | ||
| 28 | |||
| 25 | if (!vht_cap_ie || !sband->vht_cap.vht_supported) | 29 | if (!vht_cap_ie || !sband->vht_cap.vht_supported) |
| 26 | return; | 30 | return; |
| 27 | 31 | ||
| 32 | /* A VHT STA must support 40 MHz */ | ||
| 33 | if (!(sta->sta.ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40)) | ||
| 34 | return; | ||
| 35 | |||
| 28 | vht_cap->vht_supported = true; | 36 | vht_cap->vht_supported = true; |
| 29 | 37 | ||
| 30 | vht_cap->cap = le32_to_cpu(vht_cap_ie->vht_cap_info); | 38 | vht_cap->cap = le32_to_cpu(vht_cap_ie->vht_cap_info); |
| @@ -32,4 +40,156 @@ void ieee80211_vht_cap_ie_to_sta_vht_cap(struct ieee80211_sub_if_data *sdata, | |||
| 32 | /* Copy peer MCS info, the driver might need them. */ | 40 | /* Copy peer MCS info, the driver might need them. */ |
| 33 | memcpy(&vht_cap->vht_mcs, &vht_cap_ie->supp_mcs, | 41 | memcpy(&vht_cap->vht_mcs, &vht_cap_ie->supp_mcs, |
| 34 | sizeof(struct ieee80211_vht_mcs_info)); | 42 | sizeof(struct ieee80211_vht_mcs_info)); |
| 43 | |||
| 44 | switch (vht_cap->cap & IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK) { | ||
| 45 | case IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ: | ||
| 46 | case IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ: | ||
| 47 | sta->cur_max_bandwidth = IEEE80211_STA_RX_BW_160; | ||
| 48 | break; | ||
| 49 | default: | ||
| 50 | sta->cur_max_bandwidth = IEEE80211_STA_RX_BW_80; | ||
| 51 | } | ||
| 52 | |||
| 53 | sta->sta.bandwidth = ieee80211_sta_cur_vht_bw(sta); | ||
| 54 | } | ||
| 55 | |||
| 56 | enum ieee80211_sta_rx_bandwidth ieee80211_sta_cur_vht_bw(struct sta_info *sta) | ||
| 57 | { | ||
| 58 | struct ieee80211_sub_if_data *sdata = sta->sdata; | ||
| 59 | u32 cap = sta->sta.vht_cap.cap; | ||
| 60 | enum ieee80211_sta_rx_bandwidth bw; | ||
| 61 | |||
| 62 | if (!sta->sta.vht_cap.vht_supported) { | ||
| 63 | bw = sta->sta.ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40 ? | ||
| 64 | IEEE80211_STA_RX_BW_40 : IEEE80211_STA_RX_BW_20; | ||
| 65 | goto check_max; | ||
| 66 | } | ||
| 67 | |||
| 68 | switch (sdata->vif.bss_conf.chandef.width) { | ||
| 69 | default: | ||
| 70 | WARN_ON_ONCE(1); | ||
| 71 | /* fall through */ | ||
| 72 | case NL80211_CHAN_WIDTH_20_NOHT: | ||
| 73 | case NL80211_CHAN_WIDTH_20: | ||
| 74 | case NL80211_CHAN_WIDTH_40: | ||
| 75 | bw = sta->sta.ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40 ? | ||
| 76 | IEEE80211_STA_RX_BW_40 : IEEE80211_STA_RX_BW_20; | ||
| 77 | break; | ||
| 78 | case NL80211_CHAN_WIDTH_160: | ||
| 79 | if ((cap & IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK) == | ||
| 80 | IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ) { | ||
| 81 | bw = IEEE80211_STA_RX_BW_160; | ||
| 82 | break; | ||
| 83 | } | ||
| 84 | /* fall through */ | ||
| 85 | case NL80211_CHAN_WIDTH_80P80: | ||
| 86 | if ((cap & IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK) == | ||
| 87 | IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ) { | ||
| 88 | bw = IEEE80211_STA_RX_BW_160; | ||
| 89 | break; | ||
| 90 | } | ||
| 91 | /* fall through */ | ||
| 92 | case NL80211_CHAN_WIDTH_80: | ||
| 93 | bw = IEEE80211_STA_RX_BW_80; | ||
| 94 | } | ||
| 95 | |||
| 96 | check_max: | ||
| 97 | if (bw > sta->cur_max_bandwidth) | ||
| 98 | bw = sta->cur_max_bandwidth; | ||
| 99 | return bw; | ||
| 100 | } | ||
| 101 | |||
| 102 | void ieee80211_sta_set_rx_nss(struct sta_info *sta) | ||
| 103 | { | ||
| 104 | u8 ht_rx_nss = 0, vht_rx_nss = 0; | ||
| 105 | |||
| 106 | /* if we received a notification already don't overwrite it */ | ||
| 107 | if (sta->sta.rx_nss) | ||
| 108 | return; | ||
| 109 | |||
| 110 | if (sta->sta.ht_cap.ht_supported) { | ||
| 111 | if (sta->sta.ht_cap.mcs.rx_mask[0]) | ||
| 112 | ht_rx_nss++; | ||
| 113 | if (sta->sta.ht_cap.mcs.rx_mask[1]) | ||
| 114 | ht_rx_nss++; | ||
| 115 | if (sta->sta.ht_cap.mcs.rx_mask[2]) | ||
| 116 | ht_rx_nss++; | ||
| 117 | if (sta->sta.ht_cap.mcs.rx_mask[3]) | ||
| 118 | ht_rx_nss++; | ||
| 119 | /* FIXME: consider rx_highest? */ | ||
| 120 | } | ||
| 121 | |||
| 122 | if (sta->sta.vht_cap.vht_supported) { | ||
| 123 | int i; | ||
| 124 | u16 rx_mcs_map; | ||
| 125 | |||
| 126 | rx_mcs_map = le16_to_cpu(sta->sta.vht_cap.vht_mcs.rx_mcs_map); | ||
| 127 | |||
| 128 | for (i = 7; i >= 0; i--) { | ||
| 129 | u8 mcs = (rx_mcs_map >> (2 * i)) & 3; | ||
| 130 | |||
| 131 | if (mcs != IEEE80211_VHT_MCS_NOT_SUPPORTED) { | ||
| 132 | vht_rx_nss = i + 1; | ||
| 133 | break; | ||
| 134 | } | ||
| 135 | } | ||
| 136 | /* FIXME: consider rx_highest? */ | ||
| 137 | } | ||
| 138 | |||
| 139 | ht_rx_nss = max(ht_rx_nss, vht_rx_nss); | ||
| 140 | sta->sta.rx_nss = max_t(u8, 1, ht_rx_nss); | ||
| 141 | } | ||
| 142 | |||
| 143 | void ieee80211_vht_handle_opmode(struct ieee80211_sub_if_data *sdata, | ||
| 144 | struct sta_info *sta, u8 opmode, | ||
| 145 | enum ieee80211_band band, bool nss_only) | ||
| 146 | { | ||
| 147 | struct ieee80211_local *local = sdata->local; | ||
| 148 | struct ieee80211_supported_band *sband; | ||
| 149 | enum ieee80211_sta_rx_bandwidth new_bw; | ||
| 150 | u32 changed = 0; | ||
| 151 | u8 nss; | ||
| 152 | |||
| 153 | sband = local->hw.wiphy->bands[band]; | ||
| 154 | |||
| 155 | /* ignore - no support for BF yet */ | ||
| 156 | if (opmode & IEEE80211_OPMODE_NOTIF_RX_NSS_TYPE_BF) | ||
| 157 | return; | ||
| 158 | |||
| 159 | nss = opmode & IEEE80211_OPMODE_NOTIF_RX_NSS_MASK; | ||
| 160 | nss >>= IEEE80211_OPMODE_NOTIF_RX_NSS_SHIFT; | ||
| 161 | nss += 1; | ||
| 162 | |||
| 163 | if (sta->sta.rx_nss != nss) { | ||
| 164 | sta->sta.rx_nss = nss; | ||
| 165 | changed |= IEEE80211_RC_NSS_CHANGED; | ||
| 166 | } | ||
| 167 | |||
| 168 | if (nss_only) | ||
| 169 | goto change; | ||
| 170 | |||
| 171 | switch (opmode & IEEE80211_OPMODE_NOTIF_CHANWIDTH_MASK) { | ||
| 172 | case IEEE80211_OPMODE_NOTIF_CHANWIDTH_20MHZ: | ||
| 173 | sta->cur_max_bandwidth = IEEE80211_STA_RX_BW_20; | ||
| 174 | break; | ||
| 175 | case IEEE80211_OPMODE_NOTIF_CHANWIDTH_40MHZ: | ||
| 176 | sta->cur_max_bandwidth = IEEE80211_STA_RX_BW_40; | ||
| 177 | break; | ||
| 178 | case IEEE80211_OPMODE_NOTIF_CHANWIDTH_80MHZ: | ||
| 179 | sta->cur_max_bandwidth = IEEE80211_STA_RX_BW_80; | ||
| 180 | break; | ||
| 181 | case IEEE80211_OPMODE_NOTIF_CHANWIDTH_160MHZ: | ||
| 182 | sta->cur_max_bandwidth = IEEE80211_STA_RX_BW_160; | ||
| 183 | break; | ||
| 184 | } | ||
| 185 | |||
| 186 | new_bw = ieee80211_sta_cur_vht_bw(sta); | ||
| 187 | if (new_bw != sta->sta.bandwidth) { | ||
| 188 | sta->sta.bandwidth = new_bw; | ||
| 189 | changed |= IEEE80211_RC_NSS_CHANGED; | ||
| 190 | } | ||
| 191 | |||
| 192 | change: | ||
| 193 | if (changed) | ||
| 194 | rate_control_rate_update(local, sband, sta, changed); | ||
| 35 | } | 195 | } |
diff --git a/net/mac80211/wpa.c b/net/mac80211/wpa.c index c175ee866ff4..c7c6d644486f 100644 --- a/net/mac80211/wpa.c +++ b/net/mac80211/wpa.c | |||
| @@ -181,7 +181,6 @@ static int tkip_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb) | |||
| 181 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; | 181 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; |
| 182 | struct ieee80211_key *key = tx->key; | 182 | struct ieee80211_key *key = tx->key; |
| 183 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); | 183 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); |
| 184 | unsigned long flags; | ||
| 185 | unsigned int hdrlen; | 184 | unsigned int hdrlen; |
| 186 | int len, tail; | 185 | int len, tail; |
| 187 | u8 *pos; | 186 | u8 *pos; |
| @@ -216,12 +215,12 @@ static int tkip_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb) | |||
| 216 | return 0; | 215 | return 0; |
| 217 | 216 | ||
| 218 | /* Increase IV for the frame */ | 217 | /* Increase IV for the frame */ |
| 219 | spin_lock_irqsave(&key->u.tkip.txlock, flags); | 218 | spin_lock(&key->u.tkip.txlock); |
| 220 | key->u.tkip.tx.iv16++; | 219 | key->u.tkip.tx.iv16++; |
| 221 | if (key->u.tkip.tx.iv16 == 0) | 220 | if (key->u.tkip.tx.iv16 == 0) |
| 222 | key->u.tkip.tx.iv32++; | 221 | key->u.tkip.tx.iv32++; |
| 223 | pos = ieee80211_tkip_add_iv(pos, key); | 222 | pos = ieee80211_tkip_add_iv(pos, key); |
| 224 | spin_unlock_irqrestore(&key->u.tkip.txlock, flags); | 223 | spin_unlock(&key->u.tkip.txlock); |
| 225 | 224 | ||
| 226 | /* hwaccel - with software IV */ | 225 | /* hwaccel - with software IV */ |
| 227 | if (info->control.hw_key) | 226 | if (info->control.hw_key) |
diff --git a/net/wireless/chan.c b/net/wireless/chan.c index 396373f3ec26..fd556ac05fdb 100644 --- a/net/wireless/chan.c +++ b/net/wireless/chan.c | |||
| @@ -147,6 +147,32 @@ static void chandef_primary_freqs(const struct cfg80211_chan_def *c, | |||
| 147 | } | 147 | } |
| 148 | } | 148 | } |
| 149 | 149 | ||
| 150 | static int cfg80211_chandef_get_width(const struct cfg80211_chan_def *c) | ||
| 151 | { | ||
| 152 | int width; | ||
| 153 | |||
| 154 | switch (c->width) { | ||
| 155 | case NL80211_CHAN_WIDTH_20: | ||
| 156 | case NL80211_CHAN_WIDTH_20_NOHT: | ||
| 157 | width = 20; | ||
| 158 | break; | ||
| 159 | case NL80211_CHAN_WIDTH_40: | ||
| 160 | width = 40; | ||
| 161 | break; | ||
| 162 | case NL80211_CHAN_WIDTH_80P80: | ||
| 163 | case NL80211_CHAN_WIDTH_80: | ||
| 164 | width = 80; | ||
| 165 | break; | ||
| 166 | case NL80211_CHAN_WIDTH_160: | ||
| 167 | width = 160; | ||
| 168 | break; | ||
| 169 | default: | ||
| 170 | WARN_ON_ONCE(1); | ||
| 171 | return -1; | ||
| 172 | } | ||
| 173 | return width; | ||
| 174 | } | ||
| 175 | |||
| 150 | const struct cfg80211_chan_def * | 176 | const struct cfg80211_chan_def * |
| 151 | cfg80211_chandef_compatible(const struct cfg80211_chan_def *c1, | 177 | cfg80211_chandef_compatible(const struct cfg80211_chan_def *c1, |
| 152 | const struct cfg80211_chan_def *c2) | 178 | const struct cfg80211_chan_def *c2) |
| @@ -192,6 +218,93 @@ cfg80211_chandef_compatible(const struct cfg80211_chan_def *c1, | |||
| 192 | } | 218 | } |
| 193 | EXPORT_SYMBOL(cfg80211_chandef_compatible); | 219 | EXPORT_SYMBOL(cfg80211_chandef_compatible); |
| 194 | 220 | ||
| 221 | static void cfg80211_set_chans_dfs_state(struct wiphy *wiphy, u32 center_freq, | ||
| 222 | u32 bandwidth, | ||
| 223 | enum nl80211_dfs_state dfs_state) | ||
| 224 | { | ||
| 225 | struct ieee80211_channel *c; | ||
| 226 | u32 freq; | ||
| 227 | |||
| 228 | for (freq = center_freq - bandwidth/2 + 10; | ||
| 229 | freq <= center_freq + bandwidth/2 - 10; | ||
| 230 | freq += 20) { | ||
| 231 | c = ieee80211_get_channel(wiphy, freq); | ||
| 232 | if (!c || !(c->flags & IEEE80211_CHAN_RADAR)) | ||
| 233 | continue; | ||
| 234 | |||
| 235 | c->dfs_state = dfs_state; | ||
| 236 | c->dfs_state_entered = jiffies; | ||
| 237 | } | ||
| 238 | } | ||
| 239 | |||
| 240 | void cfg80211_set_dfs_state(struct wiphy *wiphy, | ||
| 241 | const struct cfg80211_chan_def *chandef, | ||
| 242 | enum nl80211_dfs_state dfs_state) | ||
| 243 | { | ||
| 244 | int width; | ||
| 245 | |||
| 246 | if (WARN_ON(!cfg80211_chandef_valid(chandef))) | ||
| 247 | return; | ||
| 248 | |||
| 249 | width = cfg80211_chandef_get_width(chandef); | ||
| 250 | if (width < 0) | ||
| 251 | return; | ||
| 252 | |||
| 253 | cfg80211_set_chans_dfs_state(wiphy, chandef->center_freq1, | ||
| 254 | width, dfs_state); | ||
| 255 | |||
| 256 | if (!chandef->center_freq2) | ||
| 257 | return; | ||
| 258 | cfg80211_set_chans_dfs_state(wiphy, chandef->center_freq2, | ||
| 259 | width, dfs_state); | ||
| 260 | } | ||
| 261 | |||
| 262 | static int cfg80211_get_chans_dfs_required(struct wiphy *wiphy, | ||
| 263 | u32 center_freq, | ||
| 264 | u32 bandwidth) | ||
| 265 | { | ||
| 266 | struct ieee80211_channel *c; | ||
| 267 | u32 freq; | ||
| 268 | |||
| 269 | for (freq = center_freq - bandwidth/2 + 10; | ||
| 270 | freq <= center_freq + bandwidth/2 - 10; | ||
| 271 | freq += 20) { | ||
| 272 | c = ieee80211_get_channel(wiphy, freq); | ||
| 273 | if (!c) | ||
| 274 | return -EINVAL; | ||
| 275 | |||
| 276 | if (c->flags & IEEE80211_CHAN_RADAR) | ||
| 277 | return 1; | ||
| 278 | } | ||
| 279 | return 0; | ||
| 280 | } | ||
| 281 | |||
| 282 | |||
| 283 | int cfg80211_chandef_dfs_required(struct wiphy *wiphy, | ||
| 284 | const struct cfg80211_chan_def *chandef) | ||
| 285 | { | ||
| 286 | int width; | ||
| 287 | int r; | ||
| 288 | |||
| 289 | if (WARN_ON(!cfg80211_chandef_valid(chandef))) | ||
| 290 | return -EINVAL; | ||
| 291 | |||
| 292 | width = cfg80211_chandef_get_width(chandef); | ||
| 293 | if (width < 0) | ||
| 294 | return -EINVAL; | ||
| 295 | |||
| 296 | r = cfg80211_get_chans_dfs_required(wiphy, chandef->center_freq1, | ||
| 297 | width); | ||
| 298 | if (r) | ||
| 299 | return r; | ||
| 300 | |||
| 301 | if (!chandef->center_freq2) | ||
| 302 | return 0; | ||
| 303 | |||
| 304 | return cfg80211_get_chans_dfs_required(wiphy, chandef->center_freq2, | ||
| 305 | width); | ||
| 306 | } | ||
| 307 | |||
| 195 | static bool cfg80211_secondary_chans_ok(struct wiphy *wiphy, | 308 | static bool cfg80211_secondary_chans_ok(struct wiphy *wiphy, |
| 196 | u32 center_freq, u32 bandwidth, | 309 | u32 center_freq, u32 bandwidth, |
| 197 | u32 prohibited_flags) | 310 | u32 prohibited_flags) |
| @@ -203,7 +316,16 @@ static bool cfg80211_secondary_chans_ok(struct wiphy *wiphy, | |||
| 203 | freq <= center_freq + bandwidth/2 - 10; | 316 | freq <= center_freq + bandwidth/2 - 10; |
| 204 | freq += 20) { | 317 | freq += 20) { |
| 205 | c = ieee80211_get_channel(wiphy, freq); | 318 | c = ieee80211_get_channel(wiphy, freq); |
| 206 | if (!c || c->flags & prohibited_flags) | 319 | if (!c) |
| 320 | return false; | ||
| 321 | |||
| 322 | /* check for radar flags */ | ||
| 323 | if ((prohibited_flags & c->flags & IEEE80211_CHAN_RADAR) && | ||
| 324 | (c->dfs_state != NL80211_DFS_AVAILABLE)) | ||
| 325 | return false; | ||
| 326 | |||
| 327 | /* check for the other flags */ | ||
| 328 | if (c->flags & prohibited_flags & ~IEEE80211_CHAN_RADAR) | ||
| 207 | return false; | 329 | return false; |
| 208 | } | 330 | } |
| 209 | 331 | ||
| @@ -253,6 +375,7 @@ bool cfg80211_chandef_usable(struct wiphy *wiphy, | |||
| 253 | case NL80211_CHAN_WIDTH_80: | 375 | case NL80211_CHAN_WIDTH_80: |
| 254 | if (!vht_cap->vht_supported) | 376 | if (!vht_cap->vht_supported) |
| 255 | return false; | 377 | return false; |
| 378 | prohibited_flags |= IEEE80211_CHAN_NO_80MHZ; | ||
| 256 | width = 80; | 379 | width = 80; |
| 257 | break; | 380 | break; |
| 258 | case NL80211_CHAN_WIDTH_160: | 381 | case NL80211_CHAN_WIDTH_160: |
| @@ -260,6 +383,7 @@ bool cfg80211_chandef_usable(struct wiphy *wiphy, | |||
| 260 | return false; | 383 | return false; |
| 261 | if (!(vht_cap->cap & IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ)) | 384 | if (!(vht_cap->cap & IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ)) |
| 262 | return false; | 385 | return false; |
| 386 | prohibited_flags |= IEEE80211_CHAN_NO_160MHZ; | ||
| 263 | width = 160; | 387 | width = 160; |
| 264 | break; | 388 | break; |
| 265 | default: | 389 | default: |
| @@ -267,7 +391,16 @@ bool cfg80211_chandef_usable(struct wiphy *wiphy, | |||
| 267 | return false; | 391 | return false; |
| 268 | } | 392 | } |
| 269 | 393 | ||
| 270 | /* TODO: missing regulatory check on 80/160 bandwidth */ | 394 | /* |
| 395 | * TODO: What if there are only certain 80/160/80+80 MHz channels | ||
| 396 | * allowed by the driver, or only certain combinations? | ||
| 397 | * For 40 MHz the driver can set the NO_HT40 flags, but for | ||
| 398 | * 80/160 MHz and in particular 80+80 MHz this isn't really | ||
| 399 | * feasible and we only have NO_80MHZ/NO_160MHZ so far but | ||
| 400 | * no way to cover 80+80 MHz or more complex restrictions. | ||
| 401 | * Note that such restrictions also need to be advertised to | ||
| 402 | * userspace, for example for P2P channel selection. | ||
| 403 | */ | ||
| 271 | 404 | ||
| 272 | if (width > 20) | 405 | if (width > 20) |
| 273 | prohibited_flags |= IEEE80211_CHAN_NO_OFDM; | 406 | prohibited_flags |= IEEE80211_CHAN_NO_OFDM; |
| @@ -344,7 +477,10 @@ cfg80211_get_chan_state(struct wireless_dev *wdev, | |||
| 344 | break; | 477 | break; |
| 345 | case NL80211_IFTYPE_AP: | 478 | case NL80211_IFTYPE_AP: |
| 346 | case NL80211_IFTYPE_P2P_GO: | 479 | case NL80211_IFTYPE_P2P_GO: |
| 347 | if (wdev->beacon_interval) { | 480 | if (wdev->cac_started) { |
| 481 | *chan = wdev->channel; | ||
| 482 | *chanmode = CHAN_MODE_SHARED; | ||
| 483 | } else if (wdev->beacon_interval) { | ||
| 348 | *chan = wdev->channel; | 484 | *chan = wdev->channel; |
| 349 | *chanmode = CHAN_MODE_SHARED; | 485 | *chanmode = CHAN_MODE_SHARED; |
| 350 | } | 486 | } |
diff --git a/net/wireless/core.c b/net/wireless/core.c index f0a1bbe95cff..33b75b9b8efa 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c | |||
| @@ -324,6 +324,8 @@ struct wiphy *wiphy_new(const struct cfg80211_ops *ops, int sizeof_priv) | |||
| 324 | INIT_LIST_HEAD(&rdev->bss_list); | 324 | INIT_LIST_HEAD(&rdev->bss_list); |
| 325 | INIT_WORK(&rdev->scan_done_wk, __cfg80211_scan_done); | 325 | INIT_WORK(&rdev->scan_done_wk, __cfg80211_scan_done); |
| 326 | INIT_WORK(&rdev->sched_scan_results_wk, __cfg80211_sched_scan_results); | 326 | INIT_WORK(&rdev->sched_scan_results_wk, __cfg80211_sched_scan_results); |
| 327 | INIT_DELAYED_WORK(&rdev->dfs_update_channels_wk, | ||
| 328 | cfg80211_dfs_channels_update_work); | ||
| 327 | #ifdef CONFIG_CFG80211_WEXT | 329 | #ifdef CONFIG_CFG80211_WEXT |
| 328 | rdev->wiphy.wext = &cfg80211_wext_handler; | 330 | rdev->wiphy.wext = &cfg80211_wext_handler; |
| 329 | #endif | 331 | #endif |
| @@ -365,7 +367,8 @@ struct wiphy *wiphy_new(const struct cfg80211_ops *ops, int sizeof_priv) | |||
| 365 | rdev->wiphy.rts_threshold = (u32) -1; | 367 | rdev->wiphy.rts_threshold = (u32) -1; |
| 366 | rdev->wiphy.coverage_class = 0; | 368 | rdev->wiphy.coverage_class = 0; |
| 367 | 369 | ||
| 368 | rdev->wiphy.features = NL80211_FEATURE_SCAN_FLUSH; | 370 | rdev->wiphy.features = NL80211_FEATURE_SCAN_FLUSH | |
| 371 | NL80211_FEATURE_ADVERTISE_CHAN_LIMITS; | ||
| 369 | 372 | ||
| 370 | return &rdev->wiphy; | 373 | return &rdev->wiphy; |
| 371 | } | 374 | } |
| @@ -695,6 +698,7 @@ void wiphy_unregister(struct wiphy *wiphy) | |||
| 695 | flush_work(&rdev->scan_done_wk); | 698 | flush_work(&rdev->scan_done_wk); |
| 696 | cancel_work_sync(&rdev->conn_work); | 699 | cancel_work_sync(&rdev->conn_work); |
| 697 | flush_work(&rdev->event_work); | 700 | flush_work(&rdev->event_work); |
| 701 | cancel_delayed_work_sync(&rdev->dfs_update_channels_wk); | ||
| 698 | 702 | ||
| 699 | if (rdev->wowlan && rdev->ops->set_wakeup) | 703 | if (rdev->wowlan && rdev->ops->set_wakeup) |
| 700 | rdev_set_wakeup(rdev, false); | 704 | rdev_set_wakeup(rdev, false); |
diff --git a/net/wireless/core.h b/net/wireless/core.h index 37d70dc2fe82..3aec0e429d8a 100644 --- a/net/wireless/core.h +++ b/net/wireless/core.h | |||
| @@ -86,6 +86,8 @@ struct cfg80211_registered_device { | |||
| 86 | 86 | ||
| 87 | struct cfg80211_wowlan *wowlan; | 87 | struct cfg80211_wowlan *wowlan; |
| 88 | 88 | ||
| 89 | struct delayed_work dfs_update_channels_wk; | ||
| 90 | |||
| 89 | /* must be last because of the way we do wiphy_priv(), | 91 | /* must be last because of the way we do wiphy_priv(), |
| 90 | * and it should at least be aligned to NETDEV_ALIGN */ | 92 | * and it should at least be aligned to NETDEV_ALIGN */ |
| 91 | struct wiphy wiphy __aligned(NETDEV_ALIGN); | 93 | struct wiphy wiphy __aligned(NETDEV_ALIGN); |
| @@ -108,6 +110,9 @@ cfg80211_rdev_free_wowlan(struct cfg80211_registered_device *rdev) | |||
| 108 | for (i = 0; i < rdev->wowlan->n_patterns; i++) | 110 | for (i = 0; i < rdev->wowlan->n_patterns; i++) |
| 109 | kfree(rdev->wowlan->patterns[i].mask); | 111 | kfree(rdev->wowlan->patterns[i].mask); |
| 110 | kfree(rdev->wowlan->patterns); | 112 | kfree(rdev->wowlan->patterns); |
| 113 | if (rdev->wowlan->tcp && rdev->wowlan->tcp->sock) | ||
| 114 | sock_release(rdev->wowlan->tcp->sock); | ||
| 115 | kfree(rdev->wowlan->tcp); | ||
| 111 | kfree(rdev->wowlan); | 116 | kfree(rdev->wowlan); |
| 112 | } | 117 | } |
| 113 | 118 | ||
| @@ -428,6 +433,22 @@ int cfg80211_can_use_iftype_chan(struct cfg80211_registered_device *rdev, | |||
| 428 | enum cfg80211_chan_mode chanmode, | 433 | enum cfg80211_chan_mode chanmode, |
| 429 | u8 radar_detect); | 434 | u8 radar_detect); |
| 430 | 435 | ||
| 436 | /** | ||
| 437 | * cfg80211_chandef_dfs_required - checks if radar detection is required | ||
| 438 | * @wiphy: the wiphy to validate against | ||
| 439 | * @chandef: the channel definition to check | ||
| 440 | * Return: 1 if radar detection is required, 0 if it is not, < 0 on error | ||
| 441 | */ | ||
| 442 | int cfg80211_chandef_dfs_required(struct wiphy *wiphy, | ||
| 443 | const struct cfg80211_chan_def *c); | ||
| 444 | |||
| 445 | void cfg80211_set_dfs_state(struct wiphy *wiphy, | ||
| 446 | const struct cfg80211_chan_def *chandef, | ||
| 447 | enum nl80211_dfs_state dfs_state); | ||
| 448 | |||
| 449 | void cfg80211_dfs_channels_update_work(struct work_struct *work); | ||
| 450 | |||
| 451 | |||
| 431 | static inline int | 452 | static inline int |
| 432 | cfg80211_can_change_interface(struct cfg80211_registered_device *rdev, | 453 | cfg80211_can_change_interface(struct cfg80211_registered_device *rdev, |
| 433 | struct wireless_dev *wdev, | 454 | struct wireless_dev *wdev, |
| @@ -454,6 +475,16 @@ cfg80211_can_use_chan(struct cfg80211_registered_device *rdev, | |||
| 454 | chan, chanmode, 0); | 475 | chan, chanmode, 0); |
| 455 | } | 476 | } |
| 456 | 477 | ||
| 478 | static inline unsigned int elapsed_jiffies_msecs(unsigned long start) | ||
| 479 | { | ||
| 480 | unsigned long end = jiffies; | ||
| 481 | |||
| 482 | if (end >= start) | ||
| 483 | return jiffies_to_msecs(end - start); | ||
| 484 | |||
| 485 | return jiffies_to_msecs(end + (MAX_JIFFY_OFFSET - start) + 1); | ||
| 486 | } | ||
| 487 | |||
| 457 | void | 488 | void |
| 458 | cfg80211_get_chan_state(struct wireless_dev *wdev, | 489 | cfg80211_get_chan_state(struct wireless_dev *wdev, |
| 459 | struct ieee80211_channel **chan, | 490 | struct ieee80211_channel **chan, |
diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c index 8e6920728c43..caddca35d686 100644 --- a/net/wireless/mlme.c +++ b/net/wireless/mlme.c | |||
| @@ -987,3 +987,123 @@ void cfg80211_pmksa_candidate_notify(struct net_device *dev, int index, | |||
| 987 | nl80211_pmksa_candidate_notify(rdev, dev, index, bssid, preauth, gfp); | 987 | nl80211_pmksa_candidate_notify(rdev, dev, index, bssid, preauth, gfp); |
| 988 | } | 988 | } |
| 989 | EXPORT_SYMBOL(cfg80211_pmksa_candidate_notify); | 989 | EXPORT_SYMBOL(cfg80211_pmksa_candidate_notify); |
| 990 | |||
| 991 | void cfg80211_dfs_channels_update_work(struct work_struct *work) | ||
| 992 | { | ||
| 993 | struct delayed_work *delayed_work; | ||
| 994 | struct cfg80211_registered_device *rdev; | ||
| 995 | struct cfg80211_chan_def chandef; | ||
| 996 | struct ieee80211_supported_band *sband; | ||
| 997 | struct ieee80211_channel *c; | ||
| 998 | struct wiphy *wiphy; | ||
| 999 | bool check_again = false; | ||
| 1000 | unsigned long timeout, next_time = 0; | ||
| 1001 | int bandid, i; | ||
| 1002 | |||
| 1003 | delayed_work = container_of(work, struct delayed_work, work); | ||
| 1004 | rdev = container_of(delayed_work, struct cfg80211_registered_device, | ||
| 1005 | dfs_update_channels_wk); | ||
| 1006 | wiphy = &rdev->wiphy; | ||
| 1007 | |||
| 1008 | mutex_lock(&cfg80211_mutex); | ||
| 1009 | for (bandid = 0; bandid < IEEE80211_NUM_BANDS; bandid++) { | ||
| 1010 | sband = wiphy->bands[bandid]; | ||
| 1011 | if (!sband) | ||
| 1012 | continue; | ||
| 1013 | |||
| 1014 | for (i = 0; i < sband->n_channels; i++) { | ||
| 1015 | c = &sband->channels[i]; | ||
| 1016 | |||
| 1017 | if (c->dfs_state != NL80211_DFS_UNAVAILABLE) | ||
| 1018 | continue; | ||
| 1019 | |||
| 1020 | timeout = c->dfs_state_entered + | ||
| 1021 | IEEE80211_DFS_MIN_NOP_TIME_MS; | ||
| 1022 | |||
| 1023 | if (time_after_eq(jiffies, timeout)) { | ||
| 1024 | c->dfs_state = NL80211_DFS_USABLE; | ||
| 1025 | cfg80211_chandef_create(&chandef, c, | ||
| 1026 | NL80211_CHAN_NO_HT); | ||
| 1027 | |||
| 1028 | nl80211_radar_notify(rdev, &chandef, | ||
| 1029 | NL80211_RADAR_NOP_FINISHED, | ||
| 1030 | NULL, GFP_ATOMIC); | ||
| 1031 | continue; | ||
| 1032 | } | ||
| 1033 | |||
| 1034 | if (!check_again) | ||
| 1035 | next_time = timeout - jiffies; | ||
| 1036 | else | ||
| 1037 | next_time = min(next_time, timeout - jiffies); | ||
| 1038 | check_again = true; | ||
| 1039 | } | ||
| 1040 | } | ||
| 1041 | mutex_unlock(&cfg80211_mutex); | ||
| 1042 | |||
| 1043 | /* reschedule if there are other channels waiting to be cleared again */ | ||
| 1044 | if (check_again) | ||
| 1045 | queue_delayed_work(cfg80211_wq, &rdev->dfs_update_channels_wk, | ||
| 1046 | next_time); | ||
| 1047 | } | ||
| 1048 | |||
| 1049 | |||
| 1050 | void cfg80211_radar_event(struct wiphy *wiphy, | ||
| 1051 | struct cfg80211_chan_def *chandef, | ||
| 1052 | gfp_t gfp) | ||
| 1053 | { | ||
| 1054 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); | ||
| 1055 | unsigned long timeout; | ||
| 1056 | |||
| 1057 | trace_cfg80211_radar_event(wiphy, chandef); | ||
| 1058 | |||
| 1059 | /* only set the chandef supplied channel to unavailable, in | ||
| 1060 | * case the radar is detected on only one of multiple channels | ||
| 1061 | * spanned by the chandef. | ||
| 1062 | */ | ||
| 1063 | cfg80211_set_dfs_state(wiphy, chandef, NL80211_DFS_UNAVAILABLE); | ||
| 1064 | |||
| 1065 | timeout = msecs_to_jiffies(IEEE80211_DFS_MIN_NOP_TIME_MS); | ||
| 1066 | queue_delayed_work(cfg80211_wq, &rdev->dfs_update_channels_wk, | ||
| 1067 | timeout); | ||
| 1068 | |||
| 1069 | nl80211_radar_notify(rdev, chandef, NL80211_RADAR_DETECTED, NULL, gfp); | ||
| 1070 | } | ||
| 1071 | EXPORT_SYMBOL(cfg80211_radar_event); | ||
| 1072 | |||
| 1073 | void cfg80211_cac_event(struct net_device *netdev, | ||
| 1074 | enum nl80211_radar_event event, gfp_t gfp) | ||
| 1075 | { | ||
| 1076 | struct wireless_dev *wdev = netdev->ieee80211_ptr; | ||
| 1077 | struct wiphy *wiphy = wdev->wiphy; | ||
| 1078 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); | ||
| 1079 | struct cfg80211_chan_def chandef; | ||
| 1080 | unsigned long timeout; | ||
| 1081 | |||
| 1082 | trace_cfg80211_cac_event(netdev, event); | ||
| 1083 | |||
| 1084 | if (WARN_ON(!wdev->cac_started)) | ||
| 1085 | return; | ||
| 1086 | |||
| 1087 | if (WARN_ON(!wdev->channel)) | ||
| 1088 | return; | ||
| 1089 | |||
| 1090 | cfg80211_chandef_create(&chandef, wdev->channel, NL80211_CHAN_NO_HT); | ||
| 1091 | |||
| 1092 | switch (event) { | ||
| 1093 | case NL80211_RADAR_CAC_FINISHED: | ||
| 1094 | timeout = wdev->cac_start_time + | ||
| 1095 | msecs_to_jiffies(IEEE80211_DFS_MIN_CAC_TIME_MS); | ||
| 1096 | WARN_ON(!time_after_eq(jiffies, timeout)); | ||
| 1097 | cfg80211_set_dfs_state(wiphy, &chandef, NL80211_DFS_AVAILABLE); | ||
| 1098 | break; | ||
| 1099 | case NL80211_RADAR_CAC_ABORTED: | ||
| 1100 | break; | ||
| 1101 | default: | ||
| 1102 | WARN_ON(1); | ||
| 1103 | return; | ||
| 1104 | } | ||
| 1105 | wdev->cac_started = false; | ||
| 1106 | |||
| 1107 | nl80211_radar_notify(rdev, &chandef, event, netdev, gfp); | ||
| 1108 | } | ||
| 1109 | EXPORT_SYMBOL(cfg80211_cac_event); | ||
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 93bc63eae076..580ffeaef3d5 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c | |||
| @@ -19,6 +19,7 @@ | |||
| 19 | #include <net/genetlink.h> | 19 | #include <net/genetlink.h> |
| 20 | #include <net/cfg80211.h> | 20 | #include <net/cfg80211.h> |
| 21 | #include <net/sock.h> | 21 | #include <net/sock.h> |
| 22 | #include <net/inet_connection_sock.h> | ||
| 22 | #include "core.h" | 23 | #include "core.h" |
| 23 | #include "nl80211.h" | 24 | #include "nl80211.h" |
| 24 | #include "reg.h" | 25 | #include "reg.h" |
| @@ -367,6 +368,8 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = { | |||
| 367 | [NL80211_ATTR_P2P_OPPPS] = { .type = NLA_U8 }, | 368 | [NL80211_ATTR_P2P_OPPPS] = { .type = NLA_U8 }, |
| 368 | [NL80211_ATTR_ACL_POLICY] = {. type = NLA_U32 }, | 369 | [NL80211_ATTR_ACL_POLICY] = {. type = NLA_U32 }, |
| 369 | [NL80211_ATTR_MAC_ADDRS] = { .type = NLA_NESTED }, | 370 | [NL80211_ATTR_MAC_ADDRS] = { .type = NLA_NESTED }, |
| 371 | [NL80211_ATTR_STA_CAPABILITY] = { .type = NLA_U16 }, | ||
| 372 | [NL80211_ATTR_STA_EXT_CAPABILITY] = { .type = NLA_BINARY, }, | ||
| 370 | }; | 373 | }; |
| 371 | 374 | ||
| 372 | /* policy for the key attributes */ | 375 | /* policy for the key attributes */ |
| @@ -399,6 +402,26 @@ nl80211_wowlan_policy[NUM_NL80211_WOWLAN_TRIG] = { | |||
| 399 | [NL80211_WOWLAN_TRIG_EAP_IDENT_REQUEST] = { .type = NLA_FLAG }, | 402 | [NL80211_WOWLAN_TRIG_EAP_IDENT_REQUEST] = { .type = NLA_FLAG }, |
| 400 | [NL80211_WOWLAN_TRIG_4WAY_HANDSHAKE] = { .type = NLA_FLAG }, | 403 | [NL80211_WOWLAN_TRIG_4WAY_HANDSHAKE] = { .type = NLA_FLAG }, |
| 401 | [NL80211_WOWLAN_TRIG_RFKILL_RELEASE] = { .type = NLA_FLAG }, | 404 | [NL80211_WOWLAN_TRIG_RFKILL_RELEASE] = { .type = NLA_FLAG }, |
| 405 | [NL80211_WOWLAN_TRIG_TCP_CONNECTION] = { .type = NLA_NESTED }, | ||
| 406 | }; | ||
| 407 | |||
| 408 | static const struct nla_policy | ||
| 409 | nl80211_wowlan_tcp_policy[NUM_NL80211_WOWLAN_TCP] = { | ||
| 410 | [NL80211_WOWLAN_TCP_SRC_IPV4] = { .type = NLA_U32 }, | ||
| 411 | [NL80211_WOWLAN_TCP_DST_IPV4] = { .type = NLA_U32 }, | ||
| 412 | [NL80211_WOWLAN_TCP_DST_MAC] = { .len = ETH_ALEN }, | ||
| 413 | [NL80211_WOWLAN_TCP_SRC_PORT] = { .type = NLA_U16 }, | ||
| 414 | [NL80211_WOWLAN_TCP_DST_PORT] = { .type = NLA_U16 }, | ||
| 415 | [NL80211_WOWLAN_TCP_DATA_PAYLOAD] = { .len = 1 }, | ||
| 416 | [NL80211_WOWLAN_TCP_DATA_PAYLOAD_SEQ] = { | ||
| 417 | .len = sizeof(struct nl80211_wowlan_tcp_data_seq) | ||
| 418 | }, | ||
| 419 | [NL80211_WOWLAN_TCP_DATA_PAYLOAD_TOKEN] = { | ||
| 420 | .len = sizeof(struct nl80211_wowlan_tcp_data_token) | ||
| 421 | }, | ||
| 422 | [NL80211_WOWLAN_TCP_DATA_INTERVAL] = { .type = NLA_U32 }, | ||
| 423 | [NL80211_WOWLAN_TCP_WAKE_PAYLOAD] = { .len = 1 }, | ||
| 424 | [NL80211_WOWLAN_TCP_WAKE_MASK] = { .len = 1 }, | ||
| 402 | }; | 425 | }; |
| 403 | 426 | ||
| 404 | /* policy for GTK rekey offload attributes */ | 427 | /* policy for GTK rekey offload attributes */ |
| @@ -531,8 +554,27 @@ static int nl80211_msg_put_channel(struct sk_buff *msg, | |||
| 531 | if ((chan->flags & IEEE80211_CHAN_NO_IBSS) && | 554 | if ((chan->flags & IEEE80211_CHAN_NO_IBSS) && |
| 532 | nla_put_flag(msg, NL80211_FREQUENCY_ATTR_NO_IBSS)) | 555 | nla_put_flag(msg, NL80211_FREQUENCY_ATTR_NO_IBSS)) |
| 533 | goto nla_put_failure; | 556 | goto nla_put_failure; |
| 534 | if ((chan->flags & IEEE80211_CHAN_RADAR) && | 557 | if (chan->flags & IEEE80211_CHAN_RADAR) { |
| 535 | nla_put_flag(msg, NL80211_FREQUENCY_ATTR_RADAR)) | 558 | u32 time = elapsed_jiffies_msecs(chan->dfs_state_entered); |
| 559 | if (nla_put_flag(msg, NL80211_FREQUENCY_ATTR_RADAR)) | ||
| 560 | goto nla_put_failure; | ||
| 561 | if (nla_put_u32(msg, NL80211_FREQUENCY_ATTR_DFS_STATE, | ||
| 562 | chan->dfs_state)) | ||
| 563 | goto nla_put_failure; | ||
| 564 | if (nla_put_u32(msg, NL80211_FREQUENCY_ATTR_DFS_TIME, time)) | ||
| 565 | goto nla_put_failure; | ||
| 566 | } | ||
| 567 | if ((chan->flags & IEEE80211_CHAN_NO_HT40MINUS) && | ||
| 568 | nla_put_flag(msg, NL80211_FREQUENCY_ATTR_NO_HT40_MINUS)) | ||
| 569 | goto nla_put_failure; | ||
| 570 | if ((chan->flags & IEEE80211_CHAN_NO_HT40PLUS) && | ||
| 571 | nla_put_flag(msg, NL80211_FREQUENCY_ATTR_NO_HT40_PLUS)) | ||
| 572 | goto nla_put_failure; | ||
| 573 | if ((chan->flags & IEEE80211_CHAN_NO_80MHZ) && | ||
| 574 | nla_put_flag(msg, NL80211_FREQUENCY_ATTR_NO_80MHZ)) | ||
| 575 | goto nla_put_failure; | ||
| 576 | if ((chan->flags & IEEE80211_CHAN_NO_160MHZ) && | ||
| 577 | nla_put_flag(msg, NL80211_FREQUENCY_ATTR_NO_160MHZ)) | ||
| 536 | goto nla_put_failure; | 578 | goto nla_put_failure; |
| 537 | 579 | ||
| 538 | if (nla_put_u32(msg, NL80211_FREQUENCY_ATTR_MAX_TX_POWER, | 580 | if (nla_put_u32(msg, NL80211_FREQUENCY_ATTR_MAX_TX_POWER, |
| @@ -872,6 +914,48 @@ nla_put_failure: | |||
| 872 | return -ENOBUFS; | 914 | return -ENOBUFS; |
| 873 | } | 915 | } |
| 874 | 916 | ||
| 917 | #ifdef CONFIG_PM | ||
| 918 | static int nl80211_send_wowlan_tcp_caps(struct cfg80211_registered_device *rdev, | ||
| 919 | struct sk_buff *msg) | ||
| 920 | { | ||
| 921 | const struct wiphy_wowlan_tcp_support *tcp = rdev->wiphy.wowlan.tcp; | ||
| 922 | struct nlattr *nl_tcp; | ||
| 923 | |||
| 924 | if (!tcp) | ||
| 925 | return 0; | ||
| 926 | |||
| 927 | nl_tcp = nla_nest_start(msg, NL80211_WOWLAN_TRIG_TCP_CONNECTION); | ||
| 928 | if (!nl_tcp) | ||
| 929 | return -ENOBUFS; | ||
| 930 | |||
| 931 | if (nla_put_u32(msg, NL80211_WOWLAN_TCP_DATA_PAYLOAD, | ||
| 932 | tcp->data_payload_max)) | ||
| 933 | return -ENOBUFS; | ||
| 934 | |||
| 935 | if (nla_put_u32(msg, NL80211_WOWLAN_TCP_DATA_PAYLOAD, | ||
| 936 | tcp->data_payload_max)) | ||
| 937 | return -ENOBUFS; | ||
| 938 | |||
| 939 | if (tcp->seq && nla_put_flag(msg, NL80211_WOWLAN_TCP_DATA_PAYLOAD_SEQ)) | ||
| 940 | return -ENOBUFS; | ||
| 941 | |||
| 942 | if (tcp->tok && nla_put(msg, NL80211_WOWLAN_TCP_DATA_PAYLOAD_TOKEN, | ||
| 943 | sizeof(*tcp->tok), tcp->tok)) | ||
| 944 | return -ENOBUFS; | ||
| 945 | |||
| 946 | if (nla_put_u32(msg, NL80211_WOWLAN_TCP_DATA_INTERVAL, | ||
| 947 | tcp->data_interval_max)) | ||
| 948 | return -ENOBUFS; | ||
| 949 | |||
| 950 | if (nla_put_u32(msg, NL80211_WOWLAN_TCP_WAKE_PAYLOAD, | ||
| 951 | tcp->wake_payload_max)) | ||
| 952 | return -ENOBUFS; | ||
| 953 | |||
| 954 | nla_nest_end(msg, nl_tcp); | ||
| 955 | return 0; | ||
| 956 | } | ||
| 957 | #endif | ||
| 958 | |||
| 875 | static int nl80211_send_wiphy(struct sk_buff *msg, u32 portid, u32 seq, int flags, | 959 | static int nl80211_send_wiphy(struct sk_buff *msg, u32 portid, u32 seq, int flags, |
| 876 | struct cfg80211_registered_device *dev) | 960 | struct cfg80211_registered_device *dev) |
| 877 | { | 961 | { |
| @@ -1238,12 +1322,17 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 portid, u32 seq, int flag | |||
| 1238 | dev->wiphy.wowlan.pattern_min_len, | 1322 | dev->wiphy.wowlan.pattern_min_len, |
| 1239 | .max_pattern_len = | 1323 | .max_pattern_len = |
| 1240 | dev->wiphy.wowlan.pattern_max_len, | 1324 | dev->wiphy.wowlan.pattern_max_len, |
| 1325 | .max_pkt_offset = | ||
| 1326 | dev->wiphy.wowlan.max_pkt_offset, | ||
| 1241 | }; | 1327 | }; |
| 1242 | if (nla_put(msg, NL80211_WOWLAN_TRIG_PKT_PATTERN, | 1328 | if (nla_put(msg, NL80211_WOWLAN_TRIG_PKT_PATTERN, |
| 1243 | sizeof(pat), &pat)) | 1329 | sizeof(pat), &pat)) |
| 1244 | goto nla_put_failure; | 1330 | goto nla_put_failure; |
| 1245 | } | 1331 | } |
| 1246 | 1332 | ||
| 1333 | if (nl80211_send_wowlan_tcp_caps(dev, msg)) | ||
| 1334 | goto nla_put_failure; | ||
| 1335 | |||
| 1247 | nla_nest_end(msg, nl_wowlan); | 1336 | nla_nest_end(msg, nl_wowlan); |
| 1248 | } | 1337 | } |
| 1249 | #endif | 1338 | #endif |
| @@ -1276,6 +1365,15 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 portid, u32 seq, int flag | |||
| 1276 | dev->wiphy.max_acl_mac_addrs)) | 1365 | dev->wiphy.max_acl_mac_addrs)) |
| 1277 | goto nla_put_failure; | 1366 | goto nla_put_failure; |
| 1278 | 1367 | ||
| 1368 | if (dev->wiphy.extended_capabilities && | ||
| 1369 | (nla_put(msg, NL80211_ATTR_EXT_CAPA, | ||
| 1370 | dev->wiphy.extended_capabilities_len, | ||
| 1371 | dev->wiphy.extended_capabilities) || | ||
| 1372 | nla_put(msg, NL80211_ATTR_EXT_CAPA_MASK, | ||
| 1373 | dev->wiphy.extended_capabilities_len, | ||
| 1374 | dev->wiphy.extended_capabilities_mask))) | ||
| 1375 | goto nla_put_failure; | ||
| 1376 | |||
| 1279 | return genlmsg_end(msg, hdr); | 1377 | return genlmsg_end(msg, hdr); |
| 1280 | 1378 | ||
| 1281 | nla_put_failure: | 1379 | nla_put_failure: |
| @@ -2707,6 +2805,7 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info) | |||
| 2707 | struct wireless_dev *wdev = dev->ieee80211_ptr; | 2805 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
| 2708 | struct cfg80211_ap_settings params; | 2806 | struct cfg80211_ap_settings params; |
| 2709 | int err; | 2807 | int err; |
| 2808 | u8 radar_detect_width = 0; | ||
| 2710 | 2809 | ||
| 2711 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP && | 2810 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP && |
| 2712 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) | 2811 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) |
| @@ -2825,9 +2924,19 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info) | |||
| 2825 | if (!cfg80211_reg_can_beacon(&rdev->wiphy, ¶ms.chandef)) | 2924 | if (!cfg80211_reg_can_beacon(&rdev->wiphy, ¶ms.chandef)) |
| 2826 | return -EINVAL; | 2925 | return -EINVAL; |
| 2827 | 2926 | ||
| 2927 | err = cfg80211_chandef_dfs_required(wdev->wiphy, ¶ms.chandef); | ||
| 2928 | if (err < 0) | ||
| 2929 | return err; | ||
| 2930 | if (err) { | ||
| 2931 | radar_detect_width = BIT(params.chandef.width); | ||
| 2932 | params.radar_required = true; | ||
| 2933 | } | ||
| 2934 | |||
| 2828 | mutex_lock(&rdev->devlist_mtx); | 2935 | mutex_lock(&rdev->devlist_mtx); |
| 2829 | err = cfg80211_can_use_chan(rdev, wdev, params.chandef.chan, | 2936 | err = cfg80211_can_use_iftype_chan(rdev, wdev, wdev->iftype, |
| 2830 | CHAN_MODE_SHARED); | 2937 | params.chandef.chan, |
| 2938 | CHAN_MODE_SHARED, | ||
| 2939 | radar_detect_width); | ||
| 2831 | mutex_unlock(&rdev->devlist_mtx); | 2940 | mutex_unlock(&rdev->devlist_mtx); |
| 2832 | 2941 | ||
| 2833 | if (err) | 2942 | if (err) |
| @@ -3300,6 +3409,63 @@ static struct net_device *get_vlan(struct genl_info *info, | |||
| 3300 | return ERR_PTR(ret); | 3409 | return ERR_PTR(ret); |
| 3301 | } | 3410 | } |
| 3302 | 3411 | ||
| 3412 | static struct nla_policy | ||
| 3413 | nl80211_sta_wme_policy[NL80211_STA_WME_MAX + 1] __read_mostly = { | ||
| 3414 | [NL80211_STA_WME_UAPSD_QUEUES] = { .type = NLA_U8 }, | ||
| 3415 | [NL80211_STA_WME_MAX_SP] = { .type = NLA_U8 }, | ||
| 3416 | }; | ||
| 3417 | |||
| 3418 | static int nl80211_set_station_tdls(struct genl_info *info, | ||
| 3419 | struct station_parameters *params) | ||
| 3420 | { | ||
| 3421 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; | ||
| 3422 | struct nlattr *tb[NL80211_STA_WME_MAX + 1]; | ||
| 3423 | struct nlattr *nla; | ||
| 3424 | int err; | ||
| 3425 | |||
| 3426 | /* Can only set if TDLS ... */ | ||
| 3427 | if (!(rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_TDLS)) | ||
| 3428 | return -EOPNOTSUPP; | ||
| 3429 | |||
| 3430 | /* ... with external setup is supported */ | ||
| 3431 | if (!(rdev->wiphy.flags & WIPHY_FLAG_TDLS_EXTERNAL_SETUP)) | ||
| 3432 | return -EOPNOTSUPP; | ||
| 3433 | |||
| 3434 | /* Dummy STA entry gets updated once the peer capabilities are known */ | ||
| 3435 | if (info->attrs[NL80211_ATTR_HT_CAPABILITY]) | ||
| 3436 | params->ht_capa = | ||
| 3437 | nla_data(info->attrs[NL80211_ATTR_HT_CAPABILITY]); | ||
| 3438 | if (info->attrs[NL80211_ATTR_VHT_CAPABILITY]) | ||
| 3439 | params->vht_capa = | ||
| 3440 | nla_data(info->attrs[NL80211_ATTR_VHT_CAPABILITY]); | ||
| 3441 | |||
| 3442 | /* parse WME attributes if present */ | ||
| 3443 | if (!info->attrs[NL80211_ATTR_STA_WME]) | ||
| 3444 | return 0; | ||
| 3445 | |||
| 3446 | nla = info->attrs[NL80211_ATTR_STA_WME]; | ||
| 3447 | err = nla_parse_nested(tb, NL80211_STA_WME_MAX, nla, | ||
| 3448 | nl80211_sta_wme_policy); | ||
| 3449 | if (err) | ||
| 3450 | return err; | ||
| 3451 | |||
| 3452 | if (tb[NL80211_STA_WME_UAPSD_QUEUES]) | ||
| 3453 | params->uapsd_queues = nla_get_u8( | ||
| 3454 | tb[NL80211_STA_WME_UAPSD_QUEUES]); | ||
| 3455 | if (params->uapsd_queues & ~IEEE80211_WMM_IE_STA_QOSINFO_AC_MASK) | ||
| 3456 | return -EINVAL; | ||
| 3457 | |||
| 3458 | if (tb[NL80211_STA_WME_MAX_SP]) | ||
| 3459 | params->max_sp = nla_get_u8(tb[NL80211_STA_WME_MAX_SP]); | ||
| 3460 | |||
| 3461 | if (params->max_sp & ~IEEE80211_WMM_IE_STA_QOSINFO_SP_MASK) | ||
| 3462 | return -EINVAL; | ||
| 3463 | |||
| 3464 | params->sta_modify_mask |= STATION_PARAM_APPLY_UAPSD; | ||
| 3465 | |||
| 3466 | return 0; | ||
| 3467 | } | ||
| 3468 | |||
| 3303 | static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info) | 3469 | static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info) |
| 3304 | { | 3470 | { |
| 3305 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; | 3471 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
| @@ -3328,8 +3494,20 @@ static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info) | |||
| 3328 | nla_len(info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES]); | 3494 | nla_len(info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES]); |
| 3329 | } | 3495 | } |
| 3330 | 3496 | ||
| 3331 | if (info->attrs[NL80211_ATTR_STA_LISTEN_INTERVAL] || | 3497 | if (info->attrs[NL80211_ATTR_STA_CAPABILITY]) { |
| 3332 | info->attrs[NL80211_ATTR_HT_CAPABILITY]) | 3498 | params.capability = |
| 3499 | nla_get_u16(info->attrs[NL80211_ATTR_STA_CAPABILITY]); | ||
| 3500 | params.sta_modify_mask |= STATION_PARAM_APPLY_CAPABILITY; | ||
| 3501 | } | ||
| 3502 | |||
| 3503 | if (info->attrs[NL80211_ATTR_STA_EXT_CAPABILITY]) { | ||
| 3504 | params.ext_capab = | ||
| 3505 | nla_data(info->attrs[NL80211_ATTR_STA_EXT_CAPABILITY]); | ||
| 3506 | params.ext_capab_len = | ||
| 3507 | nla_len(info->attrs[NL80211_ATTR_STA_EXT_CAPABILITY]); | ||
| 3508 | } | ||
| 3509 | |||
| 3510 | if (info->attrs[NL80211_ATTR_STA_LISTEN_INTERVAL]) | ||
| 3333 | return -EINVAL; | 3511 | return -EINVAL; |
| 3334 | 3512 | ||
| 3335 | if (!rdev->ops->change_station) | 3513 | if (!rdev->ops->change_station) |
| @@ -3398,6 +3576,13 @@ static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info) | |||
| 3398 | /* reject other things that can't change */ | 3576 | /* reject other things that can't change */ |
| 3399 | if (params.supported_rates) | 3577 | if (params.supported_rates) |
| 3400 | return -EINVAL; | 3578 | return -EINVAL; |
| 3579 | if (info->attrs[NL80211_ATTR_STA_CAPABILITY]) | ||
| 3580 | return -EINVAL; | ||
| 3581 | if (info->attrs[NL80211_ATTR_STA_EXT_CAPABILITY]) | ||
| 3582 | return -EINVAL; | ||
| 3583 | if (info->attrs[NL80211_ATTR_HT_CAPABILITY] || | ||
| 3584 | info->attrs[NL80211_ATTR_VHT_CAPABILITY]) | ||
| 3585 | return -EINVAL; | ||
| 3401 | 3586 | ||
| 3402 | /* must be last in here for error handling */ | 3587 | /* must be last in here for error handling */ |
| 3403 | params.vlan = get_vlan(info, rdev); | 3588 | params.vlan = get_vlan(info, rdev); |
| @@ -3413,13 +3598,29 @@ static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info) | |||
| 3413 | * to change the flag. | 3598 | * to change the flag. |
| 3414 | */ | 3599 | */ |
| 3415 | params.sta_flags_mask &= ~BIT(NL80211_STA_FLAG_TDLS_PEER); | 3600 | params.sta_flags_mask &= ~BIT(NL80211_STA_FLAG_TDLS_PEER); |
| 3416 | /* fall through */ | 3601 | /* Include parameters for TDLS peer (driver will check) */ |
| 3602 | err = nl80211_set_station_tdls(info, ¶ms); | ||
| 3603 | if (err) | ||
| 3604 | return err; | ||
| 3605 | /* disallow things sta doesn't support */ | ||
| 3606 | if (params.plink_action) | ||
| 3607 | return -EINVAL; | ||
| 3608 | if (params.local_pm) | ||
| 3609 | return -EINVAL; | ||
| 3610 | /* reject any changes other than AUTHORIZED or WME (for TDLS) */ | ||
| 3611 | if (params.sta_flags_mask & ~(BIT(NL80211_STA_FLAG_AUTHORIZED) | | ||
| 3612 | BIT(NL80211_STA_FLAG_WME))) | ||
| 3613 | return -EINVAL; | ||
| 3614 | break; | ||
| 3417 | case NL80211_IFTYPE_ADHOC: | 3615 | case NL80211_IFTYPE_ADHOC: |
| 3418 | /* disallow things sta doesn't support */ | 3616 | /* disallow things sta doesn't support */ |
| 3419 | if (params.plink_action) | 3617 | if (params.plink_action) |
| 3420 | return -EINVAL; | 3618 | return -EINVAL; |
| 3421 | if (params.local_pm) | 3619 | if (params.local_pm) |
| 3422 | return -EINVAL; | 3620 | return -EINVAL; |
| 3621 | if (info->attrs[NL80211_ATTR_HT_CAPABILITY] || | ||
| 3622 | info->attrs[NL80211_ATTR_VHT_CAPABILITY]) | ||
| 3623 | return -EINVAL; | ||
| 3423 | /* reject any changes other than AUTHORIZED */ | 3624 | /* reject any changes other than AUTHORIZED */ |
| 3424 | if (params.sta_flags_mask & ~BIT(NL80211_STA_FLAG_AUTHORIZED)) | 3625 | if (params.sta_flags_mask & ~BIT(NL80211_STA_FLAG_AUTHORIZED)) |
| 3425 | return -EINVAL; | 3626 | return -EINVAL; |
| @@ -3430,6 +3631,13 @@ static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info) | |||
| 3430 | return -EINVAL; | 3631 | return -EINVAL; |
| 3431 | if (params.supported_rates) | 3632 | if (params.supported_rates) |
| 3432 | return -EINVAL; | 3633 | return -EINVAL; |
| 3634 | if (info->attrs[NL80211_ATTR_STA_CAPABILITY]) | ||
| 3635 | return -EINVAL; | ||
| 3636 | if (info->attrs[NL80211_ATTR_STA_EXT_CAPABILITY]) | ||
| 3637 | return -EINVAL; | ||
| 3638 | if (info->attrs[NL80211_ATTR_HT_CAPABILITY] || | ||
| 3639 | info->attrs[NL80211_ATTR_VHT_CAPABILITY]) | ||
| 3640 | return -EINVAL; | ||
| 3433 | /* | 3641 | /* |
| 3434 | * No special handling for TDLS here -- the userspace | 3642 | * No special handling for TDLS here -- the userspace |
| 3435 | * mesh code doesn't have this bug. | 3643 | * mesh code doesn't have this bug. |
| @@ -3454,12 +3662,6 @@ static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info) | |||
| 3454 | return err; | 3662 | return err; |
| 3455 | } | 3663 | } |
| 3456 | 3664 | ||
| 3457 | static struct nla_policy | ||
| 3458 | nl80211_sta_wme_policy[NL80211_STA_WME_MAX + 1] __read_mostly = { | ||
| 3459 | [NL80211_STA_WME_UAPSD_QUEUES] = { .type = NLA_U8 }, | ||
| 3460 | [NL80211_STA_WME_MAX_SP] = { .type = NLA_U8 }, | ||
| 3461 | }; | ||
| 3462 | |||
| 3463 | static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info) | 3665 | static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info) |
| 3464 | { | 3666 | { |
| 3465 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; | 3667 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
| @@ -3494,6 +3696,19 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info) | |||
| 3494 | if (!params.aid || params.aid > IEEE80211_MAX_AID) | 3696 | if (!params.aid || params.aid > IEEE80211_MAX_AID) |
| 3495 | return -EINVAL; | 3697 | return -EINVAL; |
| 3496 | 3698 | ||
| 3699 | if (info->attrs[NL80211_ATTR_STA_CAPABILITY]) { | ||
| 3700 | params.capability = | ||
| 3701 | nla_get_u16(info->attrs[NL80211_ATTR_STA_CAPABILITY]); | ||
| 3702 | params.sta_modify_mask |= STATION_PARAM_APPLY_CAPABILITY; | ||
| 3703 | } | ||
| 3704 | |||
| 3705 | if (info->attrs[NL80211_ATTR_STA_EXT_CAPABILITY]) { | ||
| 3706 | params.ext_capab = | ||
| 3707 | nla_data(info->attrs[NL80211_ATTR_STA_EXT_CAPABILITY]); | ||
| 3708 | params.ext_capab_len = | ||
| 3709 | nla_len(info->attrs[NL80211_ATTR_STA_EXT_CAPABILITY]); | ||
| 3710 | } | ||
| 3711 | |||
| 3497 | if (info->attrs[NL80211_ATTR_HT_CAPABILITY]) | 3712 | if (info->attrs[NL80211_ATTR_HT_CAPABILITY]) |
| 3498 | params.ht_capa = | 3713 | params.ht_capa = |
| 3499 | nla_data(info->attrs[NL80211_ATTR_HT_CAPABILITY]); | 3714 | nla_data(info->attrs[NL80211_ATTR_HT_CAPABILITY]); |
| @@ -4987,6 +5202,54 @@ static int nl80211_stop_sched_scan(struct sk_buff *skb, | |||
| 4987 | return err; | 5202 | return err; |
| 4988 | } | 5203 | } |
| 4989 | 5204 | ||
| 5205 | static int nl80211_start_radar_detection(struct sk_buff *skb, | ||
| 5206 | struct genl_info *info) | ||
| 5207 | { | ||
| 5208 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; | ||
| 5209 | struct net_device *dev = info->user_ptr[1]; | ||
| 5210 | struct wireless_dev *wdev = dev->ieee80211_ptr; | ||
| 5211 | struct cfg80211_chan_def chandef; | ||
| 5212 | int err; | ||
| 5213 | |||
| 5214 | err = nl80211_parse_chandef(rdev, info, &chandef); | ||
| 5215 | if (err) | ||
| 5216 | return err; | ||
| 5217 | |||
| 5218 | if (wdev->cac_started) | ||
| 5219 | return -EBUSY; | ||
| 5220 | |||
| 5221 | err = cfg80211_chandef_dfs_required(wdev->wiphy, &chandef); | ||
| 5222 | if (err < 0) | ||
| 5223 | return err; | ||
| 5224 | |||
| 5225 | if (err == 0) | ||
| 5226 | return -EINVAL; | ||
| 5227 | |||
| 5228 | if (chandef.chan->dfs_state != NL80211_DFS_USABLE) | ||
| 5229 | return -EINVAL; | ||
| 5230 | |||
| 5231 | if (!rdev->ops->start_radar_detection) | ||
| 5232 | return -EOPNOTSUPP; | ||
| 5233 | |||
| 5234 | mutex_lock(&rdev->devlist_mtx); | ||
| 5235 | err = cfg80211_can_use_iftype_chan(rdev, wdev, wdev->iftype, | ||
| 5236 | chandef.chan, CHAN_MODE_SHARED, | ||
| 5237 | BIT(chandef.width)); | ||
| 5238 | if (err) | ||
| 5239 | goto err_locked; | ||
| 5240 | |||
| 5241 | err = rdev->ops->start_radar_detection(&rdev->wiphy, dev, &chandef); | ||
| 5242 | if (!err) { | ||
| 5243 | wdev->channel = chandef.chan; | ||
| 5244 | wdev->cac_started = true; | ||
| 5245 | wdev->cac_start_time = jiffies; | ||
| 5246 | } | ||
| 5247 | err_locked: | ||
| 5248 | mutex_unlock(&rdev->devlist_mtx); | ||
| 5249 | |||
| 5250 | return err; | ||
| 5251 | } | ||
| 5252 | |||
| 4990 | static int nl80211_send_bss(struct sk_buff *msg, struct netlink_callback *cb, | 5253 | static int nl80211_send_bss(struct sk_buff *msg, struct netlink_callback *cb, |
| 4991 | u32 seq, int flags, | 5254 | u32 seq, int flags, |
| 4992 | struct cfg80211_registered_device *rdev, | 5255 | struct cfg80211_registered_device *rdev, |
| @@ -6895,16 +7158,100 @@ static int nl80211_leave_mesh(struct sk_buff *skb, struct genl_info *info) | |||
| 6895 | } | 7158 | } |
| 6896 | 7159 | ||
| 6897 | #ifdef CONFIG_PM | 7160 | #ifdef CONFIG_PM |
| 7161 | static int nl80211_send_wowlan_patterns(struct sk_buff *msg, | ||
| 7162 | struct cfg80211_registered_device *rdev) | ||
| 7163 | { | ||
| 7164 | struct nlattr *nl_pats, *nl_pat; | ||
| 7165 | int i, pat_len; | ||
| 7166 | |||
| 7167 | if (!rdev->wowlan->n_patterns) | ||
| 7168 | return 0; | ||
| 7169 | |||
| 7170 | nl_pats = nla_nest_start(msg, NL80211_WOWLAN_TRIG_PKT_PATTERN); | ||
| 7171 | if (!nl_pats) | ||
| 7172 | return -ENOBUFS; | ||
| 7173 | |||
| 7174 | for (i = 0; i < rdev->wowlan->n_patterns; i++) { | ||
| 7175 | nl_pat = nla_nest_start(msg, i + 1); | ||
| 7176 | if (!nl_pat) | ||
| 7177 | return -ENOBUFS; | ||
| 7178 | pat_len = rdev->wowlan->patterns[i].pattern_len; | ||
| 7179 | if (nla_put(msg, NL80211_WOWLAN_PKTPAT_MASK, | ||
| 7180 | DIV_ROUND_UP(pat_len, 8), | ||
| 7181 | rdev->wowlan->patterns[i].mask) || | ||
| 7182 | nla_put(msg, NL80211_WOWLAN_PKTPAT_PATTERN, | ||
| 7183 | pat_len, rdev->wowlan->patterns[i].pattern) || | ||
| 7184 | nla_put_u32(msg, NL80211_WOWLAN_PKTPAT_OFFSET, | ||
| 7185 | rdev->wowlan->patterns[i].pkt_offset)) | ||
| 7186 | return -ENOBUFS; | ||
| 7187 | nla_nest_end(msg, nl_pat); | ||
| 7188 | } | ||
| 7189 | nla_nest_end(msg, nl_pats); | ||
| 7190 | |||
| 7191 | return 0; | ||
| 7192 | } | ||
| 7193 | |||
| 7194 | static int nl80211_send_wowlan_tcp(struct sk_buff *msg, | ||
| 7195 | struct cfg80211_wowlan_tcp *tcp) | ||
| 7196 | { | ||
| 7197 | struct nlattr *nl_tcp; | ||
| 7198 | |||
| 7199 | if (!tcp) | ||
| 7200 | return 0; | ||
| 7201 | |||
| 7202 | nl_tcp = nla_nest_start(msg, NL80211_WOWLAN_TRIG_TCP_CONNECTION); | ||
| 7203 | if (!nl_tcp) | ||
| 7204 | return -ENOBUFS; | ||
| 7205 | |||
| 7206 | if (nla_put_be32(msg, NL80211_WOWLAN_TCP_SRC_IPV4, tcp->src) || | ||
| 7207 | nla_put_be32(msg, NL80211_WOWLAN_TCP_DST_IPV4, tcp->dst) || | ||
| 7208 | nla_put(msg, NL80211_WOWLAN_TCP_DST_MAC, ETH_ALEN, tcp->dst_mac) || | ||
| 7209 | nla_put_u16(msg, NL80211_WOWLAN_TCP_SRC_PORT, tcp->src_port) || | ||
| 7210 | nla_put_u16(msg, NL80211_WOWLAN_TCP_DST_PORT, tcp->dst_port) || | ||
| 7211 | nla_put(msg, NL80211_WOWLAN_TCP_DATA_PAYLOAD, | ||
| 7212 | tcp->payload_len, tcp->payload) || | ||
| 7213 | nla_put_u32(msg, NL80211_WOWLAN_TCP_DATA_INTERVAL, | ||
| 7214 | tcp->data_interval) || | ||
| 7215 | nla_put(msg, NL80211_WOWLAN_TCP_WAKE_PAYLOAD, | ||
| 7216 | tcp->wake_len, tcp->wake_data) || | ||
| 7217 | nla_put(msg, NL80211_WOWLAN_TCP_WAKE_MASK, | ||
| 7218 | DIV_ROUND_UP(tcp->wake_len, 8), tcp->wake_mask)) | ||
| 7219 | return -ENOBUFS; | ||
| 7220 | |||
| 7221 | if (tcp->payload_seq.len && | ||
| 7222 | nla_put(msg, NL80211_WOWLAN_TCP_DATA_PAYLOAD_SEQ, | ||
| 7223 | sizeof(tcp->payload_seq), &tcp->payload_seq)) | ||
| 7224 | return -ENOBUFS; | ||
| 7225 | |||
| 7226 | if (tcp->payload_tok.len && | ||
| 7227 | nla_put(msg, NL80211_WOWLAN_TCP_DATA_PAYLOAD_TOKEN, | ||
| 7228 | sizeof(tcp->payload_tok) + tcp->tokens_size, | ||
| 7229 | &tcp->payload_tok)) | ||
| 7230 | return -ENOBUFS; | ||
| 7231 | |||
| 7232 | return 0; | ||
| 7233 | } | ||
| 7234 | |||
| 6898 | static int nl80211_get_wowlan(struct sk_buff *skb, struct genl_info *info) | 7235 | static int nl80211_get_wowlan(struct sk_buff *skb, struct genl_info *info) |
| 6899 | { | 7236 | { |
| 6900 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; | 7237 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
| 6901 | struct sk_buff *msg; | 7238 | struct sk_buff *msg; |
| 6902 | void *hdr; | 7239 | void *hdr; |
| 7240 | u32 size = NLMSG_DEFAULT_SIZE; | ||
| 6903 | 7241 | ||
| 6904 | if (!rdev->wiphy.wowlan.flags && !rdev->wiphy.wowlan.n_patterns) | 7242 | if (!rdev->wiphy.wowlan.flags && !rdev->wiphy.wowlan.n_patterns && |
| 7243 | !rdev->wiphy.wowlan.tcp) | ||
| 6905 | return -EOPNOTSUPP; | 7244 | return -EOPNOTSUPP; |
| 6906 | 7245 | ||
| 6907 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); | 7246 | if (rdev->wowlan && rdev->wowlan->tcp) { |
| 7247 | /* adjust size to have room for all the data */ | ||
| 7248 | size += rdev->wowlan->tcp->tokens_size + | ||
| 7249 | rdev->wowlan->tcp->payload_len + | ||
| 7250 | rdev->wowlan->tcp->wake_len + | ||
| 7251 | rdev->wowlan->tcp->wake_len / 8; | ||
| 7252 | } | ||
| 7253 | |||
| 7254 | msg = nlmsg_new(size, GFP_KERNEL); | ||
| 6908 | if (!msg) | 7255 | if (!msg) |
| 6909 | return -ENOMEM; | 7256 | return -ENOMEM; |
| 6910 | 7257 | ||
| @@ -6935,31 +7282,12 @@ static int nl80211_get_wowlan(struct sk_buff *skb, struct genl_info *info) | |||
| 6935 | (rdev->wowlan->rfkill_release && | 7282 | (rdev->wowlan->rfkill_release && |
| 6936 | nla_put_flag(msg, NL80211_WOWLAN_TRIG_RFKILL_RELEASE))) | 7283 | nla_put_flag(msg, NL80211_WOWLAN_TRIG_RFKILL_RELEASE))) |
| 6937 | goto nla_put_failure; | 7284 | goto nla_put_failure; |
| 6938 | if (rdev->wowlan->n_patterns) { | ||
| 6939 | struct nlattr *nl_pats, *nl_pat; | ||
| 6940 | int i, pat_len; | ||
| 6941 | 7285 | ||
| 6942 | nl_pats = nla_nest_start(msg, | 7286 | if (nl80211_send_wowlan_patterns(msg, rdev)) |
| 6943 | NL80211_WOWLAN_TRIG_PKT_PATTERN); | 7287 | goto nla_put_failure; |
| 6944 | if (!nl_pats) | ||
| 6945 | goto nla_put_failure; | ||
| 6946 | 7288 | ||
| 6947 | for (i = 0; i < rdev->wowlan->n_patterns; i++) { | 7289 | if (nl80211_send_wowlan_tcp(msg, rdev->wowlan->tcp)) |
| 6948 | nl_pat = nla_nest_start(msg, i + 1); | 7290 | goto nla_put_failure; |
| 6949 | if (!nl_pat) | ||
| 6950 | goto nla_put_failure; | ||
| 6951 | pat_len = rdev->wowlan->patterns[i].pattern_len; | ||
| 6952 | if (nla_put(msg, NL80211_WOWLAN_PKTPAT_MASK, | ||
| 6953 | DIV_ROUND_UP(pat_len, 8), | ||
| 6954 | rdev->wowlan->patterns[i].mask) || | ||
| 6955 | nla_put(msg, NL80211_WOWLAN_PKTPAT_PATTERN, | ||
| 6956 | pat_len, | ||
| 6957 | rdev->wowlan->patterns[i].pattern)) | ||
| 6958 | goto nla_put_failure; | ||
| 6959 | nla_nest_end(msg, nl_pat); | ||
| 6960 | } | ||
| 6961 | nla_nest_end(msg, nl_pats); | ||
| 6962 | } | ||
| 6963 | 7291 | ||
| 6964 | nla_nest_end(msg, nl_wowlan); | 7292 | nla_nest_end(msg, nl_wowlan); |
| 6965 | } | 7293 | } |
| @@ -6972,6 +7300,150 @@ nla_put_failure: | |||
| 6972 | return -ENOBUFS; | 7300 | return -ENOBUFS; |
| 6973 | } | 7301 | } |
| 6974 | 7302 | ||
| 7303 | static int nl80211_parse_wowlan_tcp(struct cfg80211_registered_device *rdev, | ||
| 7304 | struct nlattr *attr, | ||
| 7305 | struct cfg80211_wowlan *trig) | ||
| 7306 | { | ||
| 7307 | struct nlattr *tb[NUM_NL80211_WOWLAN_TCP]; | ||
| 7308 | struct cfg80211_wowlan_tcp *cfg; | ||
| 7309 | struct nl80211_wowlan_tcp_data_token *tok = NULL; | ||
| 7310 | struct nl80211_wowlan_tcp_data_seq *seq = NULL; | ||
| 7311 | u32 size; | ||
| 7312 | u32 data_size, wake_size, tokens_size = 0, wake_mask_size; | ||
| 7313 | int err, port; | ||
| 7314 | |||
| 7315 | if (!rdev->wiphy.wowlan.tcp) | ||
| 7316 | return -EINVAL; | ||
| 7317 | |||
| 7318 | err = nla_parse(tb, MAX_NL80211_WOWLAN_TCP, | ||
| 7319 | nla_data(attr), nla_len(attr), | ||
| 7320 | nl80211_wowlan_tcp_policy); | ||
| 7321 | if (err) | ||
| 7322 | return err; | ||
| 7323 | |||
| 7324 | if (!tb[NL80211_WOWLAN_TCP_SRC_IPV4] || | ||
| 7325 | !tb[NL80211_WOWLAN_TCP_DST_IPV4] || | ||
| 7326 | !tb[NL80211_WOWLAN_TCP_DST_MAC] || | ||
| 7327 | !tb[NL80211_WOWLAN_TCP_DST_PORT] || | ||
| 7328 | !tb[NL80211_WOWLAN_TCP_DATA_PAYLOAD] || | ||
| 7329 | !tb[NL80211_WOWLAN_TCP_DATA_INTERVAL] || | ||
| 7330 | !tb[NL80211_WOWLAN_TCP_WAKE_PAYLOAD] || | ||
| 7331 | !tb[NL80211_WOWLAN_TCP_WAKE_MASK]) | ||
| 7332 | return -EINVAL; | ||
| 7333 | |||
| 7334 | data_size = nla_len(tb[NL80211_WOWLAN_TCP_DATA_PAYLOAD]); | ||
| 7335 | if (data_size > rdev->wiphy.wowlan.tcp->data_payload_max) | ||
| 7336 | return -EINVAL; | ||
| 7337 | |||
| 7338 | if (nla_get_u32(tb[NL80211_WOWLAN_TCP_DATA_INTERVAL]) > | ||
| 7339 | rdev->wiphy.wowlan.tcp->data_interval_max) | ||
| 7340 | return -EINVAL; | ||
| 7341 | |||
| 7342 | wake_size = nla_len(tb[NL80211_WOWLAN_TCP_WAKE_PAYLOAD]); | ||
| 7343 | if (wake_size > rdev->wiphy.wowlan.tcp->wake_payload_max) | ||
| 7344 | return -EINVAL; | ||
| 7345 | |||
| 7346 | wake_mask_size = nla_len(tb[NL80211_WOWLAN_TCP_WAKE_MASK]); | ||
| 7347 | if (wake_mask_size != DIV_ROUND_UP(wake_size, 8)) | ||
| 7348 | return -EINVAL; | ||
| 7349 | |||
| 7350 | if (tb[NL80211_WOWLAN_TCP_DATA_PAYLOAD_TOKEN]) { | ||
| 7351 | u32 tokln = nla_len(tb[NL80211_WOWLAN_TCP_DATA_PAYLOAD_TOKEN]); | ||
| 7352 | |||
| 7353 | tok = nla_data(tb[NL80211_WOWLAN_TCP_DATA_PAYLOAD_TOKEN]); | ||
| 7354 | tokens_size = tokln - sizeof(*tok); | ||
| 7355 | |||
| 7356 | if (!tok->len || tokens_size % tok->len) | ||
| 7357 | return -EINVAL; | ||
| 7358 | if (!rdev->wiphy.wowlan.tcp->tok) | ||
| 7359 | return -EINVAL; | ||
| 7360 | if (tok->len > rdev->wiphy.wowlan.tcp->tok->max_len) | ||
| 7361 | return -EINVAL; | ||
| 7362 | if (tok->len < rdev->wiphy.wowlan.tcp->tok->min_len) | ||
| 7363 | return -EINVAL; | ||
| 7364 | if (tokens_size > rdev->wiphy.wowlan.tcp->tok->bufsize) | ||
| 7365 | return -EINVAL; | ||
| 7366 | if (tok->offset + tok->len > data_size) | ||
| 7367 | return -EINVAL; | ||
| 7368 | } | ||
| 7369 | |||
| 7370 | if (tb[NL80211_WOWLAN_TCP_DATA_PAYLOAD_SEQ]) { | ||
| 7371 | seq = nla_data(tb[NL80211_WOWLAN_TCP_DATA_PAYLOAD_SEQ]); | ||
| 7372 | if (!rdev->wiphy.wowlan.tcp->seq) | ||
| 7373 | return -EINVAL; | ||
| 7374 | if (seq->len == 0 || seq->len > 4) | ||
| 7375 | return -EINVAL; | ||
| 7376 | if (seq->len + seq->offset > data_size) | ||
| 7377 | return -EINVAL; | ||
| 7378 | } | ||
| 7379 | |||
| 7380 | size = sizeof(*cfg); | ||
| 7381 | size += data_size; | ||
| 7382 | size += wake_size + wake_mask_size; | ||
| 7383 | size += tokens_size; | ||
| 7384 | |||
| 7385 | cfg = kzalloc(size, GFP_KERNEL); | ||
| 7386 | if (!cfg) | ||
| 7387 | return -ENOMEM; | ||
| 7388 | cfg->src = nla_get_be32(tb[NL80211_WOWLAN_TCP_SRC_IPV4]); | ||
| 7389 | cfg->dst = nla_get_be32(tb[NL80211_WOWLAN_TCP_DST_IPV4]); | ||
| 7390 | memcpy(cfg->dst_mac, nla_data(tb[NL80211_WOWLAN_TCP_DST_MAC]), | ||
| 7391 | ETH_ALEN); | ||
| 7392 | if (tb[NL80211_WOWLAN_TCP_SRC_PORT]) | ||
| 7393 | port = nla_get_u16(tb[NL80211_WOWLAN_TCP_SRC_PORT]); | ||
| 7394 | else | ||
| 7395 | port = 0; | ||
| 7396 | #ifdef CONFIG_INET | ||
| 7397 | /* allocate a socket and port for it and use it */ | ||
| 7398 | err = __sock_create(wiphy_net(&rdev->wiphy), PF_INET, SOCK_STREAM, | ||
| 7399 | IPPROTO_TCP, &cfg->sock, 1); | ||
| 7400 | if (err) { | ||
| 7401 | kfree(cfg); | ||
| 7402 | return err; | ||
| 7403 | } | ||
| 7404 | if (inet_csk_get_port(cfg->sock->sk, port)) { | ||
| 7405 | sock_release(cfg->sock); | ||
| 7406 | kfree(cfg); | ||
| 7407 | return -EADDRINUSE; | ||
| 7408 | } | ||
| 7409 | cfg->src_port = inet_sk(cfg->sock->sk)->inet_num; | ||
| 7410 | #else | ||
| 7411 | if (!port) { | ||
| 7412 | kfree(cfg); | ||
| 7413 | return -EINVAL; | ||
| 7414 | } | ||
| 7415 | cfg->src_port = port; | ||
| 7416 | #endif | ||
| 7417 | |||
| 7418 | cfg->dst_port = nla_get_u16(tb[NL80211_WOWLAN_TCP_DST_PORT]); | ||
| 7419 | cfg->payload_len = data_size; | ||
| 7420 | cfg->payload = (u8 *)cfg + sizeof(*cfg) + tokens_size; | ||
| 7421 | memcpy((void *)cfg->payload, | ||
| 7422 | nla_data(tb[NL80211_WOWLAN_TCP_DATA_PAYLOAD]), | ||
| 7423 | data_size); | ||
| 7424 | if (seq) | ||
| 7425 | cfg->payload_seq = *seq; | ||
| 7426 | cfg->data_interval = nla_get_u32(tb[NL80211_WOWLAN_TCP_DATA_INTERVAL]); | ||
| 7427 | cfg->wake_len = wake_size; | ||
| 7428 | cfg->wake_data = (u8 *)cfg + sizeof(*cfg) + tokens_size + data_size; | ||
| 7429 | memcpy((void *)cfg->wake_data, | ||
| 7430 | nla_data(tb[NL80211_WOWLAN_TCP_WAKE_PAYLOAD]), | ||
| 7431 | wake_size); | ||
| 7432 | cfg->wake_mask = (u8 *)cfg + sizeof(*cfg) + tokens_size + | ||
| 7433 | data_size + wake_size; | ||
| 7434 | memcpy((void *)cfg->wake_mask, | ||
| 7435 | nla_data(tb[NL80211_WOWLAN_TCP_WAKE_MASK]), | ||
| 7436 | wake_mask_size); | ||
| 7437 | if (tok) { | ||
| 7438 | cfg->tokens_size = tokens_size; | ||
| 7439 | memcpy(&cfg->payload_tok, tok, sizeof(*tok) + tokens_size); | ||
| 7440 | } | ||
| 7441 | |||
| 7442 | trig->tcp = cfg; | ||
| 7443 | |||
| 7444 | return 0; | ||
| 7445 | } | ||
| 7446 | |||
| 6975 | static int nl80211_set_wowlan(struct sk_buff *skb, struct genl_info *info) | 7447 | static int nl80211_set_wowlan(struct sk_buff *skb, struct genl_info *info) |
| 6976 | { | 7448 | { |
| 6977 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; | 7449 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
| @@ -6982,7 +7454,8 @@ static int nl80211_set_wowlan(struct sk_buff *skb, struct genl_info *info) | |||
| 6982 | int err, i; | 7454 | int err, i; |
| 6983 | bool prev_enabled = rdev->wowlan; | 7455 | bool prev_enabled = rdev->wowlan; |
| 6984 | 7456 | ||
| 6985 | if (!rdev->wiphy.wowlan.flags && !rdev->wiphy.wowlan.n_patterns) | 7457 | if (!rdev->wiphy.wowlan.flags && !rdev->wiphy.wowlan.n_patterns && |
| 7458 | !rdev->wiphy.wowlan.tcp) | ||
| 6986 | return -EOPNOTSUPP; | 7459 | return -EOPNOTSUPP; |
| 6987 | 7460 | ||
| 6988 | if (!info->attrs[NL80211_ATTR_WOWLAN_TRIGGERS]) { | 7461 | if (!info->attrs[NL80211_ATTR_WOWLAN_TRIGGERS]) { |
| @@ -7046,7 +7519,7 @@ static int nl80211_set_wowlan(struct sk_buff *skb, struct genl_info *info) | |||
| 7046 | if (tb[NL80211_WOWLAN_TRIG_PKT_PATTERN]) { | 7519 | if (tb[NL80211_WOWLAN_TRIG_PKT_PATTERN]) { |
| 7047 | struct nlattr *pat; | 7520 | struct nlattr *pat; |
| 7048 | int n_patterns = 0; | 7521 | int n_patterns = 0; |
| 7049 | int rem, pat_len, mask_len; | 7522 | int rem, pat_len, mask_len, pkt_offset; |
| 7050 | struct nlattr *pat_tb[NUM_NL80211_WOWLAN_PKTPAT]; | 7523 | struct nlattr *pat_tb[NUM_NL80211_WOWLAN_PKTPAT]; |
| 7051 | 7524 | ||
| 7052 | nla_for_each_nested(pat, tb[NL80211_WOWLAN_TRIG_PKT_PATTERN], | 7525 | nla_for_each_nested(pat, tb[NL80211_WOWLAN_TRIG_PKT_PATTERN], |
| @@ -7081,6 +7554,15 @@ static int nl80211_set_wowlan(struct sk_buff *skb, struct genl_info *info) | |||
| 7081 | pat_len < wowlan->pattern_min_len) | 7554 | pat_len < wowlan->pattern_min_len) |
| 7082 | goto error; | 7555 | goto error; |
| 7083 | 7556 | ||
| 7557 | if (!pat_tb[NL80211_WOWLAN_PKTPAT_OFFSET]) | ||
| 7558 | pkt_offset = 0; | ||
| 7559 | else | ||
| 7560 | pkt_offset = nla_get_u32( | ||
| 7561 | pat_tb[NL80211_WOWLAN_PKTPAT_OFFSET]); | ||
| 7562 | if (pkt_offset > wowlan->max_pkt_offset) | ||
| 7563 | goto error; | ||
| 7564 | new_triggers.patterns[i].pkt_offset = pkt_offset; | ||
| 7565 | |||
| 7084 | new_triggers.patterns[i].mask = | 7566 | new_triggers.patterns[i].mask = |
| 7085 | kmalloc(mask_len + pat_len, GFP_KERNEL); | 7567 | kmalloc(mask_len + pat_len, GFP_KERNEL); |
| 7086 | if (!new_triggers.patterns[i].mask) { | 7568 | if (!new_triggers.patterns[i].mask) { |
| @@ -7100,6 +7582,14 @@ static int nl80211_set_wowlan(struct sk_buff *skb, struct genl_info *info) | |||
| 7100 | } | 7582 | } |
| 7101 | } | 7583 | } |
| 7102 | 7584 | ||
| 7585 | if (tb[NL80211_WOWLAN_TRIG_TCP_CONNECTION]) { | ||
| 7586 | err = nl80211_parse_wowlan_tcp( | ||
| 7587 | rdev, tb[NL80211_WOWLAN_TRIG_TCP_CONNECTION], | ||
| 7588 | &new_triggers); | ||
| 7589 | if (err) | ||
| 7590 | goto error; | ||
| 7591 | } | ||
| 7592 | |||
| 7103 | ntrig = kmemdup(&new_triggers, sizeof(new_triggers), GFP_KERNEL); | 7593 | ntrig = kmemdup(&new_triggers, sizeof(new_triggers), GFP_KERNEL); |
| 7104 | if (!ntrig) { | 7594 | if (!ntrig) { |
| 7105 | err = -ENOMEM; | 7595 | err = -ENOMEM; |
| @@ -7117,6 +7607,9 @@ static int nl80211_set_wowlan(struct sk_buff *skb, struct genl_info *info) | |||
| 7117 | for (i = 0; i < new_triggers.n_patterns; i++) | 7607 | for (i = 0; i < new_triggers.n_patterns; i++) |
| 7118 | kfree(new_triggers.patterns[i].mask); | 7608 | kfree(new_triggers.patterns[i].mask); |
| 7119 | kfree(new_triggers.patterns); | 7609 | kfree(new_triggers.patterns); |
| 7610 | if (new_triggers.tcp && new_triggers.tcp->sock) | ||
| 7611 | sock_release(new_triggers.tcp->sock); | ||
| 7612 | kfree(new_triggers.tcp); | ||
| 7120 | return err; | 7613 | return err; |
| 7121 | } | 7614 | } |
| 7122 | #endif | 7615 | #endif |
| @@ -8007,6 +8500,14 @@ static struct genl_ops nl80211_ops[] = { | |||
| 8007 | .internal_flags = NL80211_FLAG_NEED_NETDEV | | 8500 | .internal_flags = NL80211_FLAG_NEED_NETDEV | |
| 8008 | NL80211_FLAG_NEED_RTNL, | 8501 | NL80211_FLAG_NEED_RTNL, |
| 8009 | }, | 8502 | }, |
| 8503 | { | ||
| 8504 | .cmd = NL80211_CMD_RADAR_DETECT, | ||
| 8505 | .doit = nl80211_start_radar_detection, | ||
| 8506 | .policy = nl80211_policy, | ||
| 8507 | .flags = GENL_ADMIN_PERM, | ||
| 8508 | .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | | ||
| 8509 | NL80211_FLAG_NEED_RTNL, | ||
| 8510 | }, | ||
| 8010 | }; | 8511 | }; |
| 8011 | 8512 | ||
| 8012 | static struct genl_multicast_group nl80211_mlme_mcgrp = { | 8513 | static struct genl_multicast_group nl80211_mlme_mcgrp = { |
| @@ -9204,6 +9705,57 @@ nl80211_send_cqm_txe_notify(struct cfg80211_registered_device *rdev, | |||
| 9204 | } | 9705 | } |
| 9205 | 9706 | ||
| 9206 | void | 9707 | void |
| 9708 | nl80211_radar_notify(struct cfg80211_registered_device *rdev, | ||
| 9709 | struct cfg80211_chan_def *chandef, | ||
| 9710 | enum nl80211_radar_event event, | ||
| 9711 | struct net_device *netdev, gfp_t gfp) | ||
| 9712 | { | ||
| 9713 | struct sk_buff *msg; | ||
| 9714 | void *hdr; | ||
| 9715 | |||
| 9716 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp); | ||
| 9717 | if (!msg) | ||
| 9718 | return; | ||
| 9719 | |||
| 9720 | hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_RADAR_DETECT); | ||
| 9721 | if (!hdr) { | ||
| 9722 | nlmsg_free(msg); | ||
| 9723 | return; | ||
| 9724 | } | ||
| 9725 | |||
| 9726 | if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx)) | ||
| 9727 | goto nla_put_failure; | ||
| 9728 | |||
| 9729 | /* NOP and radar events don't need a netdev parameter */ | ||
| 9730 | if (netdev) { | ||
| 9731 | struct wireless_dev *wdev = netdev->ieee80211_ptr; | ||
| 9732 | |||
| 9733 | if (nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex) || | ||
| 9734 | nla_put_u64(msg, NL80211_ATTR_WDEV, wdev_id(wdev))) | ||
| 9735 | goto nla_put_failure; | ||
| 9736 | } | ||
| 9737 | |||
| 9738 | if (nla_put_u32(msg, NL80211_ATTR_RADAR_EVENT, event)) | ||
| 9739 | goto nla_put_failure; | ||
| 9740 | |||
| 9741 | if (nl80211_send_chandef(msg, chandef)) | ||
| 9742 | goto nla_put_failure; | ||
| 9743 | |||
| 9744 | if (genlmsg_end(msg, hdr) < 0) { | ||
| 9745 | nlmsg_free(msg); | ||
| 9746 | return; | ||
| 9747 | } | ||
| 9748 | |||
| 9749 | genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, | ||
| 9750 | nl80211_mlme_mcgrp.id, gfp); | ||
| 9751 | return; | ||
| 9752 | |||
| 9753 | nla_put_failure: | ||
| 9754 | genlmsg_cancel(msg, hdr); | ||
| 9755 | nlmsg_free(msg); | ||
| 9756 | } | ||
| 9757 | |||
| 9758 | void | ||
| 9207 | nl80211_send_cqm_pktloss_notify(struct cfg80211_registered_device *rdev, | 9759 | nl80211_send_cqm_pktloss_notify(struct cfg80211_registered_device *rdev, |
| 9208 | struct net_device *netdev, const u8 *peer, | 9760 | struct net_device *netdev, const u8 *peer, |
| 9209 | u32 num_packets, gfp_t gfp) | 9761 | u32 num_packets, gfp_t gfp) |
| @@ -9398,6 +9950,17 @@ void cfg80211_report_wowlan_wakeup(struct wireless_dev *wdev, | |||
| 9398 | wakeup->pattern_idx)) | 9950 | wakeup->pattern_idx)) |
| 9399 | goto free_msg; | 9951 | goto free_msg; |
| 9400 | 9952 | ||
| 9953 | if (wakeup->tcp_match) | ||
| 9954 | nla_put_flag(msg, NL80211_WOWLAN_TRIG_WAKEUP_TCP_MATCH); | ||
| 9955 | |||
| 9956 | if (wakeup->tcp_connlost) | ||
| 9957 | nla_put_flag(msg, | ||
| 9958 | NL80211_WOWLAN_TRIG_WAKEUP_TCP_CONNLOST); | ||
| 9959 | |||
| 9960 | if (wakeup->tcp_nomoretokens) | ||
| 9961 | nla_put_flag(msg, | ||
| 9962 | NL80211_WOWLAN_TRIG_WAKEUP_TCP_NOMORETOKENS); | ||
| 9963 | |||
| 9401 | if (wakeup->packet) { | 9964 | if (wakeup->packet) { |
| 9402 | u32 pkt_attr = NL80211_WOWLAN_TRIG_WAKEUP_PKT_80211; | 9965 | u32 pkt_attr = NL80211_WOWLAN_TRIG_WAKEUP_PKT_80211; |
| 9403 | u32 len_attr = NL80211_WOWLAN_TRIG_WAKEUP_PKT_80211_LEN; | 9966 | u32 len_attr = NL80211_WOWLAN_TRIG_WAKEUP_PKT_80211_LEN; |
diff --git a/net/wireless/nl80211.h b/net/wireless/nl80211.h index 2acba8477e9d..b061da4919e1 100644 --- a/net/wireless/nl80211.h +++ b/net/wireless/nl80211.h | |||
| @@ -108,6 +108,13 @@ nl80211_send_cqm_rssi_notify(struct cfg80211_registered_device *rdev, | |||
| 108 | struct net_device *netdev, | 108 | struct net_device *netdev, |
| 109 | enum nl80211_cqm_rssi_threshold_event rssi_event, | 109 | enum nl80211_cqm_rssi_threshold_event rssi_event, |
| 110 | gfp_t gfp); | 110 | gfp_t gfp); |
| 111 | |||
| 112 | void | ||
| 113 | nl80211_radar_notify(struct cfg80211_registered_device *rdev, | ||
| 114 | struct cfg80211_chan_def *chandef, | ||
| 115 | enum nl80211_radar_event event, | ||
| 116 | struct net_device *netdev, gfp_t gfp); | ||
| 117 | |||
| 111 | void | 118 | void |
| 112 | nl80211_send_cqm_pktloss_notify(struct cfg80211_registered_device *rdev, | 119 | nl80211_send_cqm_pktloss_notify(struct cfg80211_registered_device *rdev, |
| 113 | struct net_device *netdev, const u8 *peer, | 120 | struct net_device *netdev, const u8 *peer, |
diff --git a/net/wireless/reg.c b/net/wireless/reg.c index 08d3da2c70ab..93ab840957a0 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c | |||
| @@ -866,6 +866,10 @@ static void handle_channel(struct wiphy *wiphy, | |||
| 866 | 866 | ||
| 867 | if (freq_range->max_bandwidth_khz < MHZ_TO_KHZ(40)) | 867 | if (freq_range->max_bandwidth_khz < MHZ_TO_KHZ(40)) |
| 868 | bw_flags = IEEE80211_CHAN_NO_HT40; | 868 | bw_flags = IEEE80211_CHAN_NO_HT40; |
| 869 | if (freq_range->max_bandwidth_khz < MHZ_TO_KHZ(80)) | ||
| 870 | bw_flags |= IEEE80211_CHAN_NO_80MHZ; | ||
| 871 | if (freq_range->max_bandwidth_khz < MHZ_TO_KHZ(160)) | ||
| 872 | bw_flags |= IEEE80211_CHAN_NO_160MHZ; | ||
| 869 | 873 | ||
| 870 | if (lr->initiator == NL80211_REGDOM_SET_BY_DRIVER && | 874 | if (lr->initiator == NL80211_REGDOM_SET_BY_DRIVER && |
| 871 | request_wiphy && request_wiphy == wiphy && | 875 | request_wiphy && request_wiphy == wiphy && |
| @@ -884,6 +888,9 @@ static void handle_channel(struct wiphy *wiphy, | |||
| 884 | return; | 888 | return; |
| 885 | } | 889 | } |
| 886 | 890 | ||
| 891 | chan->dfs_state = NL80211_DFS_USABLE; | ||
| 892 | chan->dfs_state_entered = jiffies; | ||
| 893 | |||
| 887 | chan->beacon_found = false; | 894 | chan->beacon_found = false; |
| 888 | chan->flags = flags | bw_flags | map_regdom_flags(reg_rule->flags); | 895 | chan->flags = flags | bw_flags | map_regdom_flags(reg_rule->flags); |
| 889 | chan->max_antenna_gain = | 896 | chan->max_antenna_gain = |
| @@ -1261,6 +1268,10 @@ static void handle_channel_custom(struct wiphy *wiphy, | |||
| 1261 | 1268 | ||
| 1262 | if (freq_range->max_bandwidth_khz < MHZ_TO_KHZ(40)) | 1269 | if (freq_range->max_bandwidth_khz < MHZ_TO_KHZ(40)) |
| 1263 | bw_flags = IEEE80211_CHAN_NO_HT40; | 1270 | bw_flags = IEEE80211_CHAN_NO_HT40; |
| 1271 | if (freq_range->max_bandwidth_khz < MHZ_TO_KHZ(80)) | ||
| 1272 | bw_flags |= IEEE80211_CHAN_NO_80MHZ; | ||
| 1273 | if (freq_range->max_bandwidth_khz < MHZ_TO_KHZ(160)) | ||
| 1274 | bw_flags |= IEEE80211_CHAN_NO_160MHZ; | ||
| 1264 | 1275 | ||
| 1265 | chan->flags |= map_regdom_flags(reg_rule->flags) | bw_flags; | 1276 | chan->flags |= map_regdom_flags(reg_rule->flags) | bw_flags; |
| 1266 | chan->max_antenna_gain = (int) MBI_TO_DBI(power_rule->max_antenna_gain); | 1277 | chan->max_antenna_gain = (int) MBI_TO_DBI(power_rule->max_antenna_gain); |
diff --git a/net/wireless/scan.c b/net/wireless/scan.c index 2ac6787f6a42..674aadca0079 100644 --- a/net/wireless/scan.c +++ b/net/wireless/scan.c | |||
| @@ -365,14 +365,18 @@ const u8 *cfg80211_find_vendor_ie(unsigned int oui, u8 oui_type, | |||
| 365 | if (!pos) | 365 | if (!pos) |
| 366 | return NULL; | 366 | return NULL; |
| 367 | 367 | ||
| 368 | if (end - pos < sizeof(*ie)) | ||
| 369 | return NULL; | ||
| 370 | |||
| 371 | ie = (struct ieee80211_vendor_ie *)pos; | 368 | ie = (struct ieee80211_vendor_ie *)pos; |
| 369 | |||
| 370 | /* make sure we can access ie->len */ | ||
| 371 | BUILD_BUG_ON(offsetof(struct ieee80211_vendor_ie, len) != 1); | ||
| 372 | |||
| 373 | if (ie->len < sizeof(*ie)) | ||
| 374 | goto cont; | ||
| 375 | |||
| 372 | ie_oui = ie->oui[0] << 16 | ie->oui[1] << 8 | ie->oui[2]; | 376 | ie_oui = ie->oui[0] << 16 | ie->oui[1] << 8 | ie->oui[2]; |
| 373 | if (ie_oui == oui && ie->oui_type == oui_type) | 377 | if (ie_oui == oui && ie->oui_type == oui_type) |
| 374 | return pos; | 378 | return pos; |
| 375 | 379 | cont: | |
| 376 | pos += 2 + ie->len; | 380 | pos += 2 + ie->len; |
| 377 | } | 381 | } |
| 378 | return NULL; | 382 | return NULL; |
| @@ -1206,16 +1210,6 @@ static void ieee80211_scan_add_ies(struct iw_request_info *info, | |||
| 1206 | } | 1210 | } |
| 1207 | } | 1211 | } |
| 1208 | 1212 | ||
| 1209 | static inline unsigned int elapsed_jiffies_msecs(unsigned long start) | ||
| 1210 | { | ||
| 1211 | unsigned long end = jiffies; | ||
| 1212 | |||
| 1213 | if (end >= start) | ||
| 1214 | return jiffies_to_msecs(end - start); | ||
| 1215 | |||
| 1216 | return jiffies_to_msecs(end + (MAX_JIFFY_OFFSET - start) + 1); | ||
| 1217 | } | ||
| 1218 | |||
| 1219 | static char * | 1213 | static char * |
| 1220 | ieee80211_bss(struct wiphy *wiphy, struct iw_request_info *info, | 1214 | ieee80211_bss(struct wiphy *wiphy, struct iw_request_info *info, |
| 1221 | struct cfg80211_internal_bss *bss, char *current_ev, | 1215 | struct cfg80211_internal_bss *bss, char *current_ev, |
diff --git a/net/wireless/trace.h b/net/wireless/trace.h index c9cafb0ea95f..b7a531380e19 100644 --- a/net/wireless/trace.h +++ b/net/wireless/trace.h | |||
| @@ -2051,6 +2051,21 @@ TRACE_EVENT(cfg80211_reg_can_beacon, | |||
| 2051 | WIPHY_PR_ARG, CHAN_DEF_PR_ARG) | 2051 | WIPHY_PR_ARG, CHAN_DEF_PR_ARG) |
| 2052 | ); | 2052 | ); |
| 2053 | 2053 | ||
| 2054 | TRACE_EVENT(cfg80211_chandef_dfs_required, | ||
| 2055 | TP_PROTO(struct wiphy *wiphy, struct cfg80211_chan_def *chandef), | ||
| 2056 | TP_ARGS(wiphy, chandef), | ||
| 2057 | TP_STRUCT__entry( | ||
| 2058 | WIPHY_ENTRY | ||
| 2059 | CHAN_DEF_ENTRY | ||
| 2060 | ), | ||
| 2061 | TP_fast_assign( | ||
| 2062 | WIPHY_ASSIGN; | ||
| 2063 | CHAN_DEF_ASSIGN(chandef); | ||
| 2064 | ), | ||
| 2065 | TP_printk(WIPHY_PR_FMT ", " CHAN_DEF_PR_FMT, | ||
| 2066 | WIPHY_PR_ARG, CHAN_DEF_PR_ARG) | ||
| 2067 | ); | ||
| 2068 | |||
| 2054 | TRACE_EVENT(cfg80211_ch_switch_notify, | 2069 | TRACE_EVENT(cfg80211_ch_switch_notify, |
| 2055 | TP_PROTO(struct net_device *netdev, | 2070 | TP_PROTO(struct net_device *netdev, |
| 2056 | struct cfg80211_chan_def *chandef), | 2071 | struct cfg80211_chan_def *chandef), |
| @@ -2067,6 +2082,36 @@ TRACE_EVENT(cfg80211_ch_switch_notify, | |||
| 2067 | NETDEV_PR_ARG, CHAN_DEF_PR_ARG) | 2082 | NETDEV_PR_ARG, CHAN_DEF_PR_ARG) |
| 2068 | ); | 2083 | ); |
| 2069 | 2084 | ||
| 2085 | TRACE_EVENT(cfg80211_radar_event, | ||
| 2086 | TP_PROTO(struct wiphy *wiphy, struct cfg80211_chan_def *chandef), | ||
| 2087 | TP_ARGS(wiphy, chandef), | ||
| 2088 | TP_STRUCT__entry( | ||
| 2089 | WIPHY_ENTRY | ||
| 2090 | CHAN_DEF_ENTRY | ||
| 2091 | ), | ||
| 2092 | TP_fast_assign( | ||
| 2093 | WIPHY_ASSIGN; | ||
| 2094 | CHAN_DEF_ASSIGN(chandef); | ||
| 2095 | ), | ||
| 2096 | TP_printk(WIPHY_PR_FMT ", " CHAN_DEF_PR_FMT, | ||
| 2097 | WIPHY_PR_ARG, CHAN_DEF_PR_ARG) | ||
| 2098 | ); | ||
| 2099 | |||
| 2100 | TRACE_EVENT(cfg80211_cac_event, | ||
| 2101 | TP_PROTO(struct net_device *netdev, enum nl80211_radar_event evt), | ||
| 2102 | TP_ARGS(netdev, evt), | ||
| 2103 | TP_STRUCT__entry( | ||
| 2104 | NETDEV_ENTRY | ||
| 2105 | __field(enum nl80211_radar_event, evt) | ||
| 2106 | ), | ||
| 2107 | TP_fast_assign( | ||
| 2108 | NETDEV_ASSIGN; | ||
| 2109 | __entry->evt = evt; | ||
| 2110 | ), | ||
| 2111 | TP_printk(NETDEV_PR_FMT ", event: %d", | ||
| 2112 | NETDEV_PR_ARG, __entry->evt) | ||
| 2113 | ); | ||
| 2114 | |||
| 2070 | DECLARE_EVENT_CLASS(cfg80211_rx_evt, | 2115 | DECLARE_EVENT_CLASS(cfg80211_rx_evt, |
| 2071 | TP_PROTO(struct net_device *netdev, const u8 *addr), | 2116 | TP_PROTO(struct net_device *netdev, const u8 *addr), |
| 2072 | TP_ARGS(netdev, addr), | 2117 | TP_ARGS(netdev, addr), |
