diff options
Diffstat (limited to 'net/mac80211')
-rw-r--r-- | net/mac80211/cfg.c | 151 | ||||
-rw-r--r-- | net/mac80211/debugfs_sta.c | 31 | ||||
-rw-r--r-- | net/mac80211/driver-ops.h | 7 | ||||
-rw-r--r-- | net/mac80211/ht.c | 52 | ||||
-rw-r--r-- | net/mac80211/ibss.c | 29 | ||||
-rw-r--r-- | net/mac80211/ieee80211_i.h | 26 | ||||
-rw-r--r-- | net/mac80211/iface.c | 14 | ||||
-rw-r--r-- | net/mac80211/key.c | 103 | ||||
-rw-r--r-- | net/mac80211/key.h | 5 | ||||
-rw-r--r-- | net/mac80211/main.c | 55 | ||||
-rw-r--r-- | net/mac80211/mesh.c | 59 | ||||
-rw-r--r-- | net/mac80211/mesh.h | 12 | ||||
-rw-r--r-- | net/mac80211/mesh_plink.c | 37 | ||||
-rw-r--r-- | net/mac80211/mlme.c | 100 | ||||
-rw-r--r-- | net/mac80211/offchannel.c | 2 | ||||
-rw-r--r-- | net/mac80211/pm.c | 117 | ||||
-rw-r--r-- | net/mac80211/rc80211_minstrel.c | 204 | ||||
-rw-r--r-- | net/mac80211/rc80211_minstrel.h | 31 | ||||
-rw-r--r-- | net/mac80211/rc80211_minstrel_debugfs.c | 12 | ||||
-rw-r--r-- | net/mac80211/rc80211_minstrel_ht.c | 79 | ||||
-rw-r--r-- | net/mac80211/rc80211_minstrel_ht.h | 6 | ||||
-rw-r--r-- | net/mac80211/rx.c | 61 | ||||
-rw-r--r-- | net/mac80211/sta_info.c | 12 | ||||
-rw-r--r-- | net/mac80211/sta_info.h | 2 | ||||
-rw-r--r-- | net/mac80211/trace.h | 11 | ||||
-rw-r--r-- | net/mac80211/tx.c | 2 | ||||
-rw-r--r-- | net/mac80211/util.c | 73 | ||||
-rw-r--r-- | net/mac80211/vht.c | 212 |
28 files changed, 762 insertions, 743 deletions
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index fb306814576a..1d1ddabd89ca 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c | |||
@@ -254,7 +254,7 @@ static int ieee80211_del_key(struct wiphy *wiphy, struct net_device *dev, | |||
254 | goto out_unlock; | 254 | goto out_unlock; |
255 | } | 255 | } |
256 | 256 | ||
257 | __ieee80211_key_free(key); | 257 | __ieee80211_key_free(key, true); |
258 | 258 | ||
259 | ret = 0; | 259 | ret = 0; |
260 | out_unlock: | 260 | out_unlock: |
@@ -1035,9 +1035,12 @@ static int ieee80211_stop_ap(struct wiphy *wiphy, struct net_device *dev) | |||
1035 | sta_info_flush_defer(vlan); | 1035 | sta_info_flush_defer(vlan); |
1036 | sta_info_flush_defer(sdata); | 1036 | sta_info_flush_defer(sdata); |
1037 | rcu_barrier(); | 1037 | rcu_barrier(); |
1038 | list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list) | 1038 | list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list) { |
1039 | sta_info_flush_cleanup(vlan); | 1039 | sta_info_flush_cleanup(vlan); |
1040 | ieee80211_free_keys(vlan); | ||
1041 | } | ||
1040 | sta_info_flush_cleanup(sdata); | 1042 | sta_info_flush_cleanup(sdata); |
1043 | ieee80211_free_keys(sdata); | ||
1041 | 1044 | ||
1042 | sdata->vif.bss_conf.enable_beacon = false; | 1045 | sdata->vif.bss_conf.enable_beacon = false; |
1043 | clear_bit(SDATA_STATE_OFFCHANNEL_BEACON_STOPPED, &sdata->state); | 1046 | clear_bit(SDATA_STATE_OFFCHANNEL_BEACON_STOPPED, &sdata->state); |
@@ -1177,6 +1180,18 @@ static int sta_apply_parameters(struct ieee80211_local *local, | |||
1177 | mask |= BIT(NL80211_STA_FLAG_ASSOCIATED); | 1180 | mask |= BIT(NL80211_STA_FLAG_ASSOCIATED); |
1178 | if (set & BIT(NL80211_STA_FLAG_AUTHENTICATED)) | 1181 | if (set & BIT(NL80211_STA_FLAG_AUTHENTICATED)) |
1179 | set |= BIT(NL80211_STA_FLAG_ASSOCIATED); | 1182 | set |= BIT(NL80211_STA_FLAG_ASSOCIATED); |
1183 | } else if (test_sta_flag(sta, WLAN_STA_TDLS_PEER)) { | ||
1184 | /* | ||
1185 | * TDLS -- everything follows authorized, but | ||
1186 | * only becoming authorized is possible, not | ||
1187 | * going back | ||
1188 | */ | ||
1189 | if (set & BIT(NL80211_STA_FLAG_AUTHORIZED)) { | ||
1190 | set |= BIT(NL80211_STA_FLAG_AUTHENTICATED) | | ||
1191 | BIT(NL80211_STA_FLAG_ASSOCIATED); | ||
1192 | mask |= BIT(NL80211_STA_FLAG_AUTHENTICATED) | | ||
1193 | BIT(NL80211_STA_FLAG_ASSOCIATED); | ||
1194 | } | ||
1180 | } | 1195 | } |
1181 | 1196 | ||
1182 | ret = sta_apply_auth_flags(local, sta, mask, set); | 1197 | ret = sta_apply_auth_flags(local, sta, mask, set); |
@@ -1261,7 +1276,8 @@ static int sta_apply_parameters(struct ieee80211_local *local, | |||
1261 | if (ieee80211_vif_is_mesh(&sdata->vif)) { | 1276 | if (ieee80211_vif_is_mesh(&sdata->vif)) { |
1262 | #ifdef CONFIG_MAC80211_MESH | 1277 | #ifdef CONFIG_MAC80211_MESH |
1263 | u32 changed = 0; | 1278 | u32 changed = 0; |
1264 | if (sdata->u.mesh.security & IEEE80211_MESH_SEC_SECURED) { | 1279 | |
1280 | if (params->sta_modify_mask & STATION_PARAM_APPLY_PLINK_STATE) { | ||
1265 | switch (params->plink_state) { | 1281 | switch (params->plink_state) { |
1266 | case NL80211_PLINK_ESTAB: | 1282 | case NL80211_PLINK_ESTAB: |
1267 | if (sta->plink_state != NL80211_PLINK_ESTAB) | 1283 | if (sta->plink_state != NL80211_PLINK_ESTAB) |
@@ -1292,15 +1308,18 @@ static int sta_apply_parameters(struct ieee80211_local *local, | |||
1292 | /* nothing */ | 1308 | /* nothing */ |
1293 | break; | 1309 | break; |
1294 | } | 1310 | } |
1295 | } else { | 1311 | } |
1296 | switch (params->plink_action) { | 1312 | |
1297 | case PLINK_ACTION_OPEN: | 1313 | switch (params->plink_action) { |
1298 | changed |= mesh_plink_open(sta); | 1314 | case NL80211_PLINK_ACTION_NO_ACTION: |
1299 | break; | 1315 | /* nothing */ |
1300 | case PLINK_ACTION_BLOCK: | 1316 | break; |
1301 | changed |= mesh_plink_block(sta); | 1317 | case NL80211_PLINK_ACTION_OPEN: |
1302 | break; | 1318 | changed |= mesh_plink_open(sta); |
1303 | } | 1319 | break; |
1320 | case NL80211_PLINK_ACTION_BLOCK: | ||
1321 | changed |= mesh_plink_block(sta); | ||
1322 | break; | ||
1304 | } | 1323 | } |
1305 | 1324 | ||
1306 | if (params->local_pm) | 1325 | if (params->local_pm) |
@@ -1346,8 +1365,10 @@ static int ieee80211_add_station(struct wiphy *wiphy, struct net_device *dev, | |||
1346 | * defaults -- if userspace wants something else we'll | 1365 | * defaults -- if userspace wants something else we'll |
1347 | * change it accordingly in sta_apply_parameters() | 1366 | * change it accordingly in sta_apply_parameters() |
1348 | */ | 1367 | */ |
1349 | sta_info_pre_move_state(sta, IEEE80211_STA_AUTH); | 1368 | if (!(params->sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER))) { |
1350 | sta_info_pre_move_state(sta, IEEE80211_STA_ASSOC); | 1369 | sta_info_pre_move_state(sta, IEEE80211_STA_AUTH); |
1370 | sta_info_pre_move_state(sta, IEEE80211_STA_ASSOC); | ||
1371 | } | ||
1351 | 1372 | ||
1352 | err = sta_apply_parameters(local, sta, params); | 1373 | err = sta_apply_parameters(local, sta, params); |
1353 | if (err) { | 1374 | if (err) { |
@@ -1356,8 +1377,8 @@ static int ieee80211_add_station(struct wiphy *wiphy, struct net_device *dev, | |||
1356 | } | 1377 | } |
1357 | 1378 | ||
1358 | /* | 1379 | /* |
1359 | * for TDLS, rate control should be initialized only when supported | 1380 | * for TDLS, rate control should be initialized only when |
1360 | * rates are known. | 1381 | * rates are known and station is marked authorized |
1361 | */ | 1382 | */ |
1362 | if (!test_sta_flag(sta, WLAN_STA_TDLS_PEER)) | 1383 | if (!test_sta_flag(sta, WLAN_STA_TDLS_PEER)) |
1363 | rate_control_rate_init(sta); | 1384 | rate_control_rate_init(sta); |
@@ -1394,50 +1415,67 @@ static int ieee80211_del_station(struct wiphy *wiphy, struct net_device *dev, | |||
1394 | } | 1415 | } |
1395 | 1416 | ||
1396 | static int ieee80211_change_station(struct wiphy *wiphy, | 1417 | static int ieee80211_change_station(struct wiphy *wiphy, |
1397 | struct net_device *dev, | 1418 | struct net_device *dev, u8 *mac, |
1398 | u8 *mac, | ||
1399 | struct station_parameters *params) | 1419 | struct station_parameters *params) |
1400 | { | 1420 | { |
1401 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 1421 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
1402 | struct ieee80211_local *local = wiphy_priv(wiphy); | 1422 | struct ieee80211_local *local = wiphy_priv(wiphy); |
1403 | struct sta_info *sta; | 1423 | struct sta_info *sta; |
1404 | struct ieee80211_sub_if_data *vlansdata; | 1424 | struct ieee80211_sub_if_data *vlansdata; |
1425 | enum cfg80211_station_type statype; | ||
1405 | int err; | 1426 | int err; |
1406 | 1427 | ||
1407 | mutex_lock(&local->sta_mtx); | 1428 | mutex_lock(&local->sta_mtx); |
1408 | 1429 | ||
1409 | sta = sta_info_get_bss(sdata, mac); | 1430 | sta = sta_info_get_bss(sdata, mac); |
1410 | if (!sta) { | 1431 | if (!sta) { |
1411 | mutex_unlock(&local->sta_mtx); | 1432 | err = -ENOENT; |
1412 | return -ENOENT; | 1433 | goto out_err; |
1413 | } | 1434 | } |
1414 | 1435 | ||
1415 | /* in station mode, some updates are only valid with TDLS */ | 1436 | switch (sdata->vif.type) { |
1416 | if (sdata->vif.type == NL80211_IFTYPE_STATION && | 1437 | case NL80211_IFTYPE_MESH_POINT: |
1417 | (params->supported_rates || params->ht_capa || params->vht_capa || | 1438 | if (sdata->u.mesh.user_mpm) |
1418 | params->sta_modify_mask || | 1439 | statype = CFG80211_STA_MESH_PEER_USER; |
1419 | (params->sta_flags_mask & BIT(NL80211_STA_FLAG_WME))) && | 1440 | else |
1420 | !test_sta_flag(sta, WLAN_STA_TDLS_PEER)) { | 1441 | statype = CFG80211_STA_MESH_PEER_KERNEL; |
1421 | mutex_unlock(&local->sta_mtx); | 1442 | break; |
1422 | return -EINVAL; | 1443 | case NL80211_IFTYPE_ADHOC: |
1444 | statype = CFG80211_STA_IBSS; | ||
1445 | break; | ||
1446 | case NL80211_IFTYPE_STATION: | ||
1447 | if (!test_sta_flag(sta, WLAN_STA_TDLS_PEER)) { | ||
1448 | statype = CFG80211_STA_AP_STA; | ||
1449 | break; | ||
1450 | } | ||
1451 | if (test_sta_flag(sta, WLAN_STA_AUTHORIZED)) | ||
1452 | statype = CFG80211_STA_TDLS_PEER_ACTIVE; | ||
1453 | else | ||
1454 | statype = CFG80211_STA_TDLS_PEER_SETUP; | ||
1455 | break; | ||
1456 | case NL80211_IFTYPE_AP: | ||
1457 | case NL80211_IFTYPE_AP_VLAN: | ||
1458 | statype = CFG80211_STA_AP_CLIENT; | ||
1459 | break; | ||
1460 | default: | ||
1461 | err = -EOPNOTSUPP; | ||
1462 | goto out_err; | ||
1423 | } | 1463 | } |
1424 | 1464 | ||
1465 | err = cfg80211_check_station_change(wiphy, params, statype); | ||
1466 | if (err) | ||
1467 | goto out_err; | ||
1468 | |||
1425 | if (params->vlan && params->vlan != sta->sdata->dev) { | 1469 | if (params->vlan && params->vlan != sta->sdata->dev) { |
1426 | bool prev_4addr = false; | 1470 | bool prev_4addr = false; |
1427 | bool new_4addr = false; | 1471 | bool new_4addr = false; |
1428 | 1472 | ||
1429 | vlansdata = IEEE80211_DEV_TO_SUB_IF(params->vlan); | 1473 | vlansdata = IEEE80211_DEV_TO_SUB_IF(params->vlan); |
1430 | 1474 | ||
1431 | if (vlansdata->vif.type != NL80211_IFTYPE_AP_VLAN && | ||
1432 | vlansdata->vif.type != NL80211_IFTYPE_AP) { | ||
1433 | mutex_unlock(&local->sta_mtx); | ||
1434 | return -EINVAL; | ||
1435 | } | ||
1436 | |||
1437 | if (params->vlan->ieee80211_ptr->use_4addr) { | 1475 | if (params->vlan->ieee80211_ptr->use_4addr) { |
1438 | if (vlansdata->u.vlan.sta) { | 1476 | if (vlansdata->u.vlan.sta) { |
1439 | mutex_unlock(&local->sta_mtx); | 1477 | err = -EBUSY; |
1440 | return -EBUSY; | 1478 | goto out_err; |
1441 | } | 1479 | } |
1442 | 1480 | ||
1443 | rcu_assign_pointer(vlansdata->u.vlan.sta, sta); | 1481 | rcu_assign_pointer(vlansdata->u.vlan.sta, sta); |
@@ -1464,12 +1502,12 @@ static int ieee80211_change_station(struct wiphy *wiphy, | |||
1464 | } | 1502 | } |
1465 | 1503 | ||
1466 | err = sta_apply_parameters(local, sta, params); | 1504 | err = sta_apply_parameters(local, sta, params); |
1467 | if (err) { | 1505 | if (err) |
1468 | mutex_unlock(&local->sta_mtx); | 1506 | goto out_err; |
1469 | return err; | ||
1470 | } | ||
1471 | 1507 | ||
1472 | if (test_sta_flag(sta, WLAN_STA_TDLS_PEER) && params->supported_rates) | 1508 | /* When peer becomes authorized, init rate control as well */ |
1509 | if (test_sta_flag(sta, WLAN_STA_TDLS_PEER) && | ||
1510 | test_sta_flag(sta, WLAN_STA_AUTHORIZED)) | ||
1473 | rate_control_rate_init(sta); | 1511 | rate_control_rate_init(sta); |
1474 | 1512 | ||
1475 | mutex_unlock(&local->sta_mtx); | 1513 | mutex_unlock(&local->sta_mtx); |
@@ -1479,7 +1517,11 @@ static int ieee80211_change_station(struct wiphy *wiphy, | |||
1479 | ieee80211_recalc_ps(local, -1); | 1517 | ieee80211_recalc_ps(local, -1); |
1480 | ieee80211_recalc_ps_vif(sdata); | 1518 | ieee80211_recalc_ps_vif(sdata); |
1481 | } | 1519 | } |
1520 | |||
1482 | return 0; | 1521 | return 0; |
1522 | out_err: | ||
1523 | mutex_unlock(&local->sta_mtx); | ||
1524 | return err; | ||
1483 | } | 1525 | } |
1484 | 1526 | ||
1485 | #ifdef CONFIG_MAC80211_MESH | 1527 | #ifdef CONFIG_MAC80211_MESH |
@@ -1687,6 +1729,7 @@ static int copy_mesh_setup(struct ieee80211_if_mesh *ifmsh, | |||
1687 | ifmsh->mesh_sp_id = setup->sync_method; | 1729 | ifmsh->mesh_sp_id = setup->sync_method; |
1688 | ifmsh->mesh_pp_id = setup->path_sel_proto; | 1730 | ifmsh->mesh_pp_id = setup->path_sel_proto; |
1689 | ifmsh->mesh_pm_id = setup->path_metric; | 1731 | ifmsh->mesh_pm_id = setup->path_metric; |
1732 | ifmsh->user_mpm = setup->user_mpm; | ||
1690 | ifmsh->security = IEEE80211_MESH_SEC_NONE; | 1733 | ifmsh->security = IEEE80211_MESH_SEC_NONE; |
1691 | if (setup->is_authenticated) | 1734 | if (setup->is_authenticated) |
1692 | ifmsh->security |= IEEE80211_MESH_SEC_AUTHED; | 1735 | ifmsh->security |= IEEE80211_MESH_SEC_AUTHED; |
@@ -1730,8 +1773,11 @@ static int ieee80211_update_mesh_config(struct wiphy *wiphy, | |||
1730 | conf->dot11MeshTTL = nconf->dot11MeshTTL; | 1773 | conf->dot11MeshTTL = nconf->dot11MeshTTL; |
1731 | if (_chg_mesh_attr(NL80211_MESHCONF_ELEMENT_TTL, mask)) | 1774 | if (_chg_mesh_attr(NL80211_MESHCONF_ELEMENT_TTL, mask)) |
1732 | conf->element_ttl = nconf->element_ttl; | 1775 | conf->element_ttl = nconf->element_ttl; |
1733 | if (_chg_mesh_attr(NL80211_MESHCONF_AUTO_OPEN_PLINKS, mask)) | 1776 | if (_chg_mesh_attr(NL80211_MESHCONF_AUTO_OPEN_PLINKS, mask)) { |
1777 | if (ifmsh->user_mpm) | ||
1778 | return -EBUSY; | ||
1734 | conf->auto_open_plinks = nconf->auto_open_plinks; | 1779 | conf->auto_open_plinks = nconf->auto_open_plinks; |
1780 | } | ||
1735 | if (_chg_mesh_attr(NL80211_MESHCONF_SYNC_OFFSET_MAX_NEIGHBOR, mask)) | 1781 | if (_chg_mesh_attr(NL80211_MESHCONF_SYNC_OFFSET_MAX_NEIGHBOR, mask)) |
1736 | conf->dot11MeshNbrOffsetMaxNeighbor = | 1782 | conf->dot11MeshNbrOffsetMaxNeighbor = |
1737 | nconf->dot11MeshNbrOffsetMaxNeighbor; | 1783 | nconf->dot11MeshNbrOffsetMaxNeighbor; |
@@ -2371,7 +2417,8 @@ static int ieee80211_start_roc_work(struct ieee80211_local *local, | |||
2371 | struct ieee80211_sub_if_data *sdata, | 2417 | struct ieee80211_sub_if_data *sdata, |
2372 | struct ieee80211_channel *channel, | 2418 | struct ieee80211_channel *channel, |
2373 | unsigned int duration, u64 *cookie, | 2419 | unsigned int duration, u64 *cookie, |
2374 | struct sk_buff *txskb) | 2420 | struct sk_buff *txskb, |
2421 | enum ieee80211_roc_type type) | ||
2375 | { | 2422 | { |
2376 | struct ieee80211_roc_work *roc, *tmp; | 2423 | struct ieee80211_roc_work *roc, *tmp; |
2377 | bool queued = false; | 2424 | bool queued = false; |
@@ -2390,6 +2437,7 @@ static int ieee80211_start_roc_work(struct ieee80211_local *local, | |||
2390 | roc->duration = duration; | 2437 | roc->duration = duration; |
2391 | roc->req_duration = duration; | 2438 | roc->req_duration = duration; |
2392 | roc->frame = txskb; | 2439 | roc->frame = txskb; |
2440 | roc->type = type; | ||
2393 | roc->mgmt_tx_cookie = (unsigned long)txskb; | 2441 | roc->mgmt_tx_cookie = (unsigned long)txskb; |
2394 | roc->sdata = sdata; | 2442 | roc->sdata = sdata; |
2395 | INIT_DELAYED_WORK(&roc->work, ieee80211_sw_roc_work); | 2443 | INIT_DELAYED_WORK(&roc->work, ieee80211_sw_roc_work); |
@@ -2420,7 +2468,7 @@ static int ieee80211_start_roc_work(struct ieee80211_local *local, | |||
2420 | if (!duration) | 2468 | if (!duration) |
2421 | duration = 10; | 2469 | duration = 10; |
2422 | 2470 | ||
2423 | ret = drv_remain_on_channel(local, sdata, channel, duration); | 2471 | ret = drv_remain_on_channel(local, sdata, channel, duration, type); |
2424 | if (ret) { | 2472 | if (ret) { |
2425 | kfree(roc); | 2473 | kfree(roc); |
2426 | return ret; | 2474 | return ret; |
@@ -2439,10 +2487,13 @@ static int ieee80211_start_roc_work(struct ieee80211_local *local, | |||
2439 | * | 2487 | * |
2440 | * If it hasn't started yet, just increase the duration | 2488 | * If it hasn't started yet, just increase the duration |
2441 | * and add the new one to the list of dependents. | 2489 | * and add the new one to the list of dependents. |
2490 | * If the type of the new ROC has higher priority, modify the | ||
2491 | * type of the previous one to match that of the new one. | ||
2442 | */ | 2492 | */ |
2443 | if (!tmp->started) { | 2493 | if (!tmp->started) { |
2444 | list_add_tail(&roc->list, &tmp->dependents); | 2494 | list_add_tail(&roc->list, &tmp->dependents); |
2445 | tmp->duration = max(tmp->duration, roc->duration); | 2495 | tmp->duration = max(tmp->duration, roc->duration); |
2496 | tmp->type = max(tmp->type, roc->type); | ||
2446 | queued = true; | 2497 | queued = true; |
2447 | break; | 2498 | break; |
2448 | } | 2499 | } |
@@ -2454,16 +2505,18 @@ static int ieee80211_start_roc_work(struct ieee80211_local *local, | |||
2454 | /* | 2505 | /* |
2455 | * In the offloaded ROC case, if it hasn't begun, add | 2506 | * In the offloaded ROC case, if it hasn't begun, add |
2456 | * this new one to the dependent list to be handled | 2507 | * this new one to the dependent list to be handled |
2457 | * when the the master one begins. If it has begun, | 2508 | * when the master one begins. If it has begun, |
2458 | * check that there's still a minimum time left and | 2509 | * check that there's still a minimum time left and |
2459 | * if so, start this one, transmitting the frame, but | 2510 | * if so, start this one, transmitting the frame, but |
2460 | * add it to the list directly after this one with a | 2511 | * add it to the list directly after this one with |
2461 | * a reduced time so we'll ask the driver to execute | 2512 | * a reduced time so we'll ask the driver to execute |
2462 | * it right after finishing the previous one, in the | 2513 | * it right after finishing the previous one, in the |
2463 | * hope that it'll also be executed right afterwards, | 2514 | * hope that it'll also be executed right afterwards, |
2464 | * effectively extending the old one. | 2515 | * effectively extending the old one. |
2465 | * If there's no minimum time left, just add it to the | 2516 | * If there's no minimum time left, just add it to the |
2466 | * normal list. | 2517 | * normal list. |
2518 | * TODO: the ROC type is ignored here, assuming that it | ||
2519 | * is better to immediately use the current ROC. | ||
2467 | */ | 2520 | */ |
2468 | if (!tmp->hw_begun) { | 2521 | if (!tmp->hw_begun) { |
2469 | list_add_tail(&roc->list, &tmp->dependents); | 2522 | list_add_tail(&roc->list, &tmp->dependents); |
@@ -2557,7 +2610,8 @@ static int ieee80211_remain_on_channel(struct wiphy *wiphy, | |||
2557 | 2610 | ||
2558 | mutex_lock(&local->mtx); | 2611 | mutex_lock(&local->mtx); |
2559 | ret = ieee80211_start_roc_work(local, sdata, chan, | 2612 | ret = ieee80211_start_roc_work(local, sdata, chan, |
2560 | duration, cookie, NULL); | 2613 | duration, cookie, NULL, |
2614 | IEEE80211_ROC_TYPE_NORMAL); | ||
2561 | mutex_unlock(&local->mtx); | 2615 | mutex_unlock(&local->mtx); |
2562 | 2616 | ||
2563 | return ret; | 2617 | return ret; |
@@ -2790,7 +2844,8 @@ static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev, | |||
2790 | 2844 | ||
2791 | /* This will handle all kinds of coalescing and immediate TX */ | 2845 | /* This will handle all kinds of coalescing and immediate TX */ |
2792 | ret = ieee80211_start_roc_work(local, sdata, chan, | 2846 | ret = ieee80211_start_roc_work(local, sdata, chan, |
2793 | wait, cookie, skb); | 2847 | wait, cookie, skb, |
2848 | IEEE80211_ROC_TYPE_MGMT_TX); | ||
2794 | if (ret) | 2849 | if (ret) |
2795 | kfree_skb(skb); | 2850 | kfree_skb(skb); |
2796 | out_unlock: | 2851 | out_unlock: |
diff --git a/net/mac80211/debugfs_sta.c b/net/mac80211/debugfs_sta.c index c7591f73dbc3..4f841fe559df 100644 --- a/net/mac80211/debugfs_sta.c +++ b/net/mac80211/debugfs_sta.c | |||
@@ -325,6 +325,36 @@ static ssize_t sta_ht_capa_read(struct file *file, char __user *userbuf, | |||
325 | } | 325 | } |
326 | STA_OPS(ht_capa); | 326 | STA_OPS(ht_capa); |
327 | 327 | ||
328 | static ssize_t sta_vht_capa_read(struct file *file, char __user *userbuf, | ||
329 | size_t count, loff_t *ppos) | ||
330 | { | ||
331 | char buf[128], *p = buf; | ||
332 | struct sta_info *sta = file->private_data; | ||
333 | struct ieee80211_sta_vht_cap *vhtc = &sta->sta.vht_cap; | ||
334 | |||
335 | p += scnprintf(p, sizeof(buf) + buf - p, "VHT %ssupported\n", | ||
336 | vhtc->vht_supported ? "" : "not "); | ||
337 | if (vhtc->vht_supported) { | ||
338 | p += scnprintf(p, sizeof(buf)+buf-p, "cap: %#.8x\n", vhtc->cap); | ||
339 | |||
340 | p += scnprintf(p, sizeof(buf)+buf-p, "RX MCS: %.4x\n", | ||
341 | le16_to_cpu(vhtc->vht_mcs.rx_mcs_map)); | ||
342 | if (vhtc->vht_mcs.rx_highest) | ||
343 | p += scnprintf(p, sizeof(buf)+buf-p, | ||
344 | "MCS RX highest: %d Mbps\n", | ||
345 | le16_to_cpu(vhtc->vht_mcs.rx_highest)); | ||
346 | p += scnprintf(p, sizeof(buf)+buf-p, "TX MCS: %.4x\n", | ||
347 | le16_to_cpu(vhtc->vht_mcs.tx_mcs_map)); | ||
348 | if (vhtc->vht_mcs.tx_highest) | ||
349 | p += scnprintf(p, sizeof(buf)+buf-p, | ||
350 | "MCS TX highest: %d Mbps\n", | ||
351 | le16_to_cpu(vhtc->vht_mcs.tx_highest)); | ||
352 | } | ||
353 | |||
354 | return simple_read_from_buffer(userbuf, count, ppos, buf, p - buf); | ||
355 | } | ||
356 | STA_OPS(vht_capa); | ||
357 | |||
328 | static ssize_t sta_current_tx_rate_read(struct file *file, char __user *userbuf, | 358 | static ssize_t sta_current_tx_rate_read(struct file *file, char __user *userbuf, |
329 | size_t count, loff_t *ppos) | 359 | size_t count, loff_t *ppos) |
330 | { | 360 | { |
@@ -405,6 +435,7 @@ void ieee80211_sta_debugfs_add(struct sta_info *sta) | |||
405 | DEBUGFS_ADD(dev); | 435 | DEBUGFS_ADD(dev); |
406 | DEBUGFS_ADD(last_signal); | 436 | DEBUGFS_ADD(last_signal); |
407 | DEBUGFS_ADD(ht_capa); | 437 | DEBUGFS_ADD(ht_capa); |
438 | DEBUGFS_ADD(vht_capa); | ||
408 | DEBUGFS_ADD(last_ack_signal); | 439 | DEBUGFS_ADD(last_ack_signal); |
409 | DEBUGFS_ADD(current_tx_rate); | 440 | DEBUGFS_ADD(current_tx_rate); |
410 | DEBUGFS_ADD(last_rx_rate); | 441 | DEBUGFS_ADD(last_rx_rate); |
diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h index ee56d0779d8b..832acea4a5cb 100644 --- a/net/mac80211/driver-ops.h +++ b/net/mac80211/driver-ops.h | |||
@@ -787,15 +787,16 @@ static inline int drv_get_antenna(struct ieee80211_local *local, | |||
787 | static inline int drv_remain_on_channel(struct ieee80211_local *local, | 787 | static inline int drv_remain_on_channel(struct ieee80211_local *local, |
788 | struct ieee80211_sub_if_data *sdata, | 788 | struct ieee80211_sub_if_data *sdata, |
789 | struct ieee80211_channel *chan, | 789 | struct ieee80211_channel *chan, |
790 | unsigned int duration) | 790 | unsigned int duration, |
791 | enum ieee80211_roc_type type) | ||
791 | { | 792 | { |
792 | int ret; | 793 | int ret; |
793 | 794 | ||
794 | might_sleep(); | 795 | might_sleep(); |
795 | 796 | ||
796 | trace_drv_remain_on_channel(local, sdata, chan, duration); | 797 | trace_drv_remain_on_channel(local, sdata, chan, duration, type); |
797 | ret = local->ops->remain_on_channel(&local->hw, &sdata->vif, | 798 | ret = local->ops->remain_on_channel(&local->hw, &sdata->vif, |
798 | chan, duration); | 799 | chan, duration, type); |
799 | trace_drv_return_int(local, ret); | 800 | trace_drv_return_int(local, ret); |
800 | 801 | ||
801 | return ret; | 802 | return ret; |
diff --git a/net/mac80211/ht.c b/net/mac80211/ht.c index 0db25d4bb223..af8cee06e4f3 100644 --- a/net/mac80211/ht.c +++ b/net/mac80211/ht.c | |||
@@ -40,13 +40,6 @@ void ieee80211_apply_htcap_overrides(struct ieee80211_sub_if_data *sdata, | |||
40 | if (!ht_cap->ht_supported) | 40 | if (!ht_cap->ht_supported) |
41 | return; | 41 | return; |
42 | 42 | ||
43 | if (sdata->vif.type != NL80211_IFTYPE_STATION) { | ||
44 | /* AP interfaces call this code when adding new stations, | ||
45 | * so just silently ignore non station interfaces. | ||
46 | */ | ||
47 | return; | ||
48 | } | ||
49 | |||
50 | /* NOTE: If you add more over-rides here, update register_hw | 43 | /* NOTE: If you add more over-rides here, update register_hw |
51 | * ht_capa_mod_msk logic in main.c as well. | 44 | * ht_capa_mod_msk logic in main.c as well. |
52 | * And, if this method can ever change ht_cap.ht_supported, fix | 45 | * And, if this method can ever change ht_cap.ht_supported, fix |
@@ -97,7 +90,7 @@ bool ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_sub_if_data *sdata, | |||
97 | const struct ieee80211_ht_cap *ht_cap_ie, | 90 | const struct ieee80211_ht_cap *ht_cap_ie, |
98 | struct sta_info *sta) | 91 | struct sta_info *sta) |
99 | { | 92 | { |
100 | struct ieee80211_sta_ht_cap ht_cap; | 93 | struct ieee80211_sta_ht_cap ht_cap, own_cap; |
101 | u8 ampdu_info, tx_mcs_set_cap; | 94 | u8 ampdu_info, tx_mcs_set_cap; |
102 | int i, max_tx_streams; | 95 | int i, max_tx_streams; |
103 | bool changed; | 96 | bool changed; |
@@ -111,6 +104,18 @@ bool ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_sub_if_data *sdata, | |||
111 | 104 | ||
112 | ht_cap.ht_supported = true; | 105 | ht_cap.ht_supported = true; |
113 | 106 | ||
107 | own_cap = sband->ht_cap; | ||
108 | |||
109 | /* | ||
110 | * If user has specified capability over-rides, take care | ||
111 | * of that if the station we're setting up is the AP that | ||
112 | * we advertised a restricted capability set to. Override | ||
113 | * our own capabilities and then use those below. | ||
114 | */ | ||
115 | if (sdata->vif.type == NL80211_IFTYPE_STATION && | ||
116 | !test_sta_flag(sta, WLAN_STA_TDLS_PEER)) | ||
117 | ieee80211_apply_htcap_overrides(sdata, &own_cap); | ||
118 | |||
114 | /* | 119 | /* |
115 | * The bits listed in this expression should be | 120 | * The bits listed in this expression should be |
116 | * the same for the peer and us, if the station | 121 | * the same for the peer and us, if the station |
@@ -118,21 +123,20 @@ bool ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_sub_if_data *sdata, | |||
118 | * we mask them out. | 123 | * we mask them out. |
119 | */ | 124 | */ |
120 | ht_cap.cap = le16_to_cpu(ht_cap_ie->cap_info) & | 125 | ht_cap.cap = le16_to_cpu(ht_cap_ie->cap_info) & |
121 | (sband->ht_cap.cap | | 126 | (own_cap.cap | ~(IEEE80211_HT_CAP_LDPC_CODING | |
122 | ~(IEEE80211_HT_CAP_LDPC_CODING | | 127 | IEEE80211_HT_CAP_SUP_WIDTH_20_40 | |
123 | IEEE80211_HT_CAP_SUP_WIDTH_20_40 | | 128 | IEEE80211_HT_CAP_GRN_FLD | |
124 | IEEE80211_HT_CAP_GRN_FLD | | 129 | IEEE80211_HT_CAP_SGI_20 | |
125 | IEEE80211_HT_CAP_SGI_20 | | 130 | IEEE80211_HT_CAP_SGI_40 | |
126 | IEEE80211_HT_CAP_SGI_40 | | 131 | IEEE80211_HT_CAP_DSSSCCK40)); |
127 | IEEE80211_HT_CAP_DSSSCCK40)); | ||
128 | 132 | ||
129 | /* | 133 | /* |
130 | * The STBC bits are asymmetric -- if we don't have | 134 | * The STBC bits are asymmetric -- if we don't have |
131 | * TX then mask out the peer's RX and vice versa. | 135 | * TX then mask out the peer's RX and vice versa. |
132 | */ | 136 | */ |
133 | if (!(sband->ht_cap.cap & IEEE80211_HT_CAP_TX_STBC)) | 137 | if (!(own_cap.cap & IEEE80211_HT_CAP_TX_STBC)) |
134 | ht_cap.cap &= ~IEEE80211_HT_CAP_RX_STBC; | 138 | ht_cap.cap &= ~IEEE80211_HT_CAP_RX_STBC; |
135 | if (!(sband->ht_cap.cap & IEEE80211_HT_CAP_RX_STBC)) | 139 | if (!(own_cap.cap & IEEE80211_HT_CAP_RX_STBC)) |
136 | ht_cap.cap &= ~IEEE80211_HT_CAP_TX_STBC; | 140 | ht_cap.cap &= ~IEEE80211_HT_CAP_TX_STBC; |
137 | 141 | ||
138 | ampdu_info = ht_cap_ie->ampdu_params_info; | 142 | ampdu_info = ht_cap_ie->ampdu_params_info; |
@@ -142,7 +146,7 @@ bool ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_sub_if_data *sdata, | |||
142 | (ampdu_info & IEEE80211_HT_AMPDU_PARM_DENSITY) >> 2; | 146 | (ampdu_info & IEEE80211_HT_AMPDU_PARM_DENSITY) >> 2; |
143 | 147 | ||
144 | /* own MCS TX capabilities */ | 148 | /* own MCS TX capabilities */ |
145 | tx_mcs_set_cap = sband->ht_cap.mcs.tx_params; | 149 | tx_mcs_set_cap = own_cap.mcs.tx_params; |
146 | 150 | ||
147 | /* Copy peer MCS TX capabilities, the driver might need them. */ | 151 | /* Copy peer MCS TX capabilities, the driver might need them. */ |
148 | ht_cap.mcs.tx_params = ht_cap_ie->mcs.tx_params; | 152 | ht_cap.mcs.tx_params = ht_cap_ie->mcs.tx_params; |
@@ -168,26 +172,20 @@ bool ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_sub_if_data *sdata, | |||
168 | */ | 172 | */ |
169 | for (i = 0; i < max_tx_streams; i++) | 173 | for (i = 0; i < max_tx_streams; i++) |
170 | ht_cap.mcs.rx_mask[i] = | 174 | ht_cap.mcs.rx_mask[i] = |
171 | sband->ht_cap.mcs.rx_mask[i] & ht_cap_ie->mcs.rx_mask[i]; | 175 | own_cap.mcs.rx_mask[i] & ht_cap_ie->mcs.rx_mask[i]; |
172 | 176 | ||
173 | if (tx_mcs_set_cap & IEEE80211_HT_MCS_TX_UNEQUAL_MODULATION) | 177 | if (tx_mcs_set_cap & IEEE80211_HT_MCS_TX_UNEQUAL_MODULATION) |
174 | for (i = IEEE80211_HT_MCS_UNEQUAL_MODULATION_START_BYTE; | 178 | for (i = IEEE80211_HT_MCS_UNEQUAL_MODULATION_START_BYTE; |
175 | i < IEEE80211_HT_MCS_MASK_LEN; i++) | 179 | i < IEEE80211_HT_MCS_MASK_LEN; i++) |
176 | ht_cap.mcs.rx_mask[i] = | 180 | ht_cap.mcs.rx_mask[i] = |
177 | sband->ht_cap.mcs.rx_mask[i] & | 181 | own_cap.mcs.rx_mask[i] & |
178 | ht_cap_ie->mcs.rx_mask[i]; | 182 | ht_cap_ie->mcs.rx_mask[i]; |
179 | 183 | ||
180 | /* handle MCS rate 32 too */ | 184 | /* handle MCS rate 32 too */ |
181 | if (sband->ht_cap.mcs.rx_mask[32/8] & ht_cap_ie->mcs.rx_mask[32/8] & 1) | 185 | if (own_cap.mcs.rx_mask[32/8] & ht_cap_ie->mcs.rx_mask[32/8] & 1) |
182 | ht_cap.mcs.rx_mask[32/8] |= 1; | 186 | ht_cap.mcs.rx_mask[32/8] |= 1; |
183 | 187 | ||
184 | apply: | 188 | apply: |
185 | /* | ||
186 | * If user has specified capability over-rides, take care | ||
187 | * of that here. | ||
188 | */ | ||
189 | ieee80211_apply_htcap_overrides(sdata, &ht_cap); | ||
190 | |||
191 | changed = memcmp(&sta->sta.ht_cap, &ht_cap, sizeof(ht_cap)); | 189 | changed = memcmp(&sta->sta.ht_cap, &ht_cap, sizeof(ht_cap)); |
192 | 190 | ||
193 | memcpy(&sta->sta.ht_cap, &ht_cap, sizeof(ht_cap)); | 191 | memcpy(&sta->sta.ht_cap, &ht_cap, sizeof(ht_cap)); |
diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c index 40b71dfcc79d..539d4a11b47b 100644 --- a/net/mac80211/ibss.c +++ b/net/mac80211/ibss.c | |||
@@ -985,36 +985,9 @@ static void ieee80211_ibss_timer(unsigned long data) | |||
985 | { | 985 | { |
986 | struct ieee80211_sub_if_data *sdata = | 986 | struct ieee80211_sub_if_data *sdata = |
987 | (struct ieee80211_sub_if_data *) data; | 987 | (struct ieee80211_sub_if_data *) data; |
988 | struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; | ||
989 | struct ieee80211_local *local = sdata->local; | ||
990 | |||
991 | if (local->quiescing) { | ||
992 | ifibss->timer_running = true; | ||
993 | return; | ||
994 | } | ||
995 | |||
996 | ieee80211_queue_work(&local->hw, &sdata->work); | ||
997 | } | ||
998 | |||
999 | #ifdef CONFIG_PM | ||
1000 | void ieee80211_ibss_quiesce(struct ieee80211_sub_if_data *sdata) | ||
1001 | { | ||
1002 | struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; | ||
1003 | 988 | ||
1004 | if (del_timer_sync(&ifibss->timer)) | 989 | ieee80211_queue_work(&sdata->local->hw, &sdata->work); |
1005 | ifibss->timer_running = true; | ||
1006 | } | ||
1007 | |||
1008 | void ieee80211_ibss_restart(struct ieee80211_sub_if_data *sdata) | ||
1009 | { | ||
1010 | struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; | ||
1011 | |||
1012 | if (ifibss->timer_running) { | ||
1013 | add_timer(&ifibss->timer); | ||
1014 | ifibss->timer_running = false; | ||
1015 | } | ||
1016 | } | 990 | } |
1017 | #endif | ||
1018 | 991 | ||
1019 | void ieee80211_ibss_setup_sdata(struct ieee80211_sub_if_data *sdata) | 992 | void ieee80211_ibss_setup_sdata(struct ieee80211_sub_if_data *sdata) |
1020 | { | 993 | { |
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 388580a1bada..f4433f081e77 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h | |||
@@ -315,6 +315,7 @@ struct ieee80211_roc_work { | |||
315 | u32 duration, req_duration; | 315 | u32 duration, req_duration; |
316 | struct sk_buff *frame; | 316 | struct sk_buff *frame; |
317 | u64 cookie, mgmt_tx_cookie; | 317 | u64 cookie, mgmt_tx_cookie; |
318 | enum ieee80211_roc_type type; | ||
318 | }; | 319 | }; |
319 | 320 | ||
320 | /* flags used in struct ieee80211_if_managed.flags */ | 321 | /* flags used in struct ieee80211_if_managed.flags */ |
@@ -400,7 +401,6 @@ struct ieee80211_if_managed { | |||
400 | 401 | ||
401 | u16 aid; | 402 | u16 aid; |
402 | 403 | ||
403 | unsigned long timers_running; /* used for quiesce/restart */ | ||
404 | bool powersave; /* powersave requested for this iface */ | 404 | bool powersave; /* powersave requested for this iface */ |
405 | bool broken_ap; /* AP is broken -- turn off powersave */ | 405 | bool broken_ap; /* AP is broken -- turn off powersave */ |
406 | u8 dtim_period; | 406 | u8 dtim_period; |
@@ -479,6 +479,8 @@ struct ieee80211_if_managed { | |||
479 | 479 | ||
480 | struct ieee80211_ht_cap ht_capa; /* configured ht-cap over-rides */ | 480 | struct ieee80211_ht_cap ht_capa; /* configured ht-cap over-rides */ |
481 | struct ieee80211_ht_cap ht_capa_mask; /* Valid parts of ht_capa */ | 481 | struct ieee80211_ht_cap ht_capa_mask; /* Valid parts of ht_capa */ |
482 | struct ieee80211_vht_cap vht_capa; /* configured VHT overrides */ | ||
483 | struct ieee80211_vht_cap vht_capa_mask; /* Valid parts of vht_capa */ | ||
482 | }; | 484 | }; |
483 | 485 | ||
484 | struct ieee80211_if_ibss { | 486 | struct ieee80211_if_ibss { |
@@ -490,8 +492,6 @@ struct ieee80211_if_ibss { | |||
490 | 492 | ||
491 | u32 basic_rates; | 493 | u32 basic_rates; |
492 | 494 | ||
493 | bool timer_running; | ||
494 | |||
495 | bool fixed_bssid; | 495 | bool fixed_bssid; |
496 | bool fixed_channel; | 496 | bool fixed_channel; |
497 | bool privacy; | 497 | bool privacy; |
@@ -543,8 +543,6 @@ struct ieee80211_if_mesh { | |||
543 | struct timer_list mesh_path_timer; | 543 | struct timer_list mesh_path_timer; |
544 | struct timer_list mesh_path_root_timer; | 544 | struct timer_list mesh_path_root_timer; |
545 | 545 | ||
546 | unsigned long timers_running; | ||
547 | |||
548 | unsigned long wrkq_flags; | 546 | unsigned long wrkq_flags; |
549 | 547 | ||
550 | u8 mesh_id[IEEE80211_MAX_MESH_ID_LEN]; | 548 | u8 mesh_id[IEEE80211_MAX_MESH_ID_LEN]; |
@@ -590,6 +588,7 @@ struct ieee80211_if_mesh { | |||
590 | IEEE80211_MESH_SEC_AUTHED = 0x1, | 588 | IEEE80211_MESH_SEC_AUTHED = 0x1, |
591 | IEEE80211_MESH_SEC_SECURED = 0x2, | 589 | IEEE80211_MESH_SEC_SECURED = 0x2, |
592 | } security; | 590 | } security; |
591 | bool user_mpm; | ||
593 | /* Extensible Synchronization Framework */ | 592 | /* Extensible Synchronization Framework */ |
594 | const struct ieee80211_mesh_sync_ops *sync_ops; | 593 | const struct ieee80211_mesh_sync_ops *sync_ops; |
595 | s64 sync_offset_clockdrift_max; | 594 | s64 sync_offset_clockdrift_max; |
@@ -682,6 +681,8 @@ struct ieee80211_sub_if_data { | |||
682 | 681 | ||
683 | /* count for keys needing tailroom space allocation */ | 682 | /* count for keys needing tailroom space allocation */ |
684 | int crypto_tx_tailroom_needed_cnt; | 683 | int crypto_tx_tailroom_needed_cnt; |
684 | int crypto_tx_tailroom_pending_dec; | ||
685 | struct delayed_work dec_tailroom_needed_wk; | ||
685 | 686 | ||
686 | struct net_device *dev; | 687 | struct net_device *dev; |
687 | struct ieee80211_local *local; | 688 | struct ieee80211_local *local; |
@@ -765,10 +766,6 @@ struct ieee80211_sub_if_data { | |||
765 | } debugfs; | 766 | } debugfs; |
766 | #endif | 767 | #endif |
767 | 768 | ||
768 | #ifdef CONFIG_PM | ||
769 | struct ieee80211_bss_conf suspend_bss_conf; | ||
770 | #endif | ||
771 | |||
772 | /* must be last, dynamically sized area in this! */ | 769 | /* must be last, dynamically sized area in this! */ |
773 | struct ieee80211_vif vif; | 770 | struct ieee80211_vif vif; |
774 | }; | 771 | }; |
@@ -1136,11 +1133,6 @@ struct ieee80211_local { | |||
1136 | 1133 | ||
1137 | struct ieee80211_sub_if_data __rcu *p2p_sdata; | 1134 | struct ieee80211_sub_if_data __rcu *p2p_sdata; |
1138 | 1135 | ||
1139 | /* dummy netdev for use w/ NAPI */ | ||
1140 | struct net_device napi_dev; | ||
1141 | |||
1142 | struct napi_struct napi; | ||
1143 | |||
1144 | /* virtual monitor interface */ | 1136 | /* virtual monitor interface */ |
1145 | struct ieee80211_sub_if_data __rcu *monitor_sdata; | 1137 | struct ieee80211_sub_if_data __rcu *monitor_sdata; |
1146 | struct cfg80211_chan_def monitor_chandef; | 1138 | struct cfg80211_chan_def monitor_chandef; |
@@ -1283,8 +1275,6 @@ void | |||
1283 | ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata, | 1275 | ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata, |
1284 | const struct ieee80211_channel_sw_ie *sw_elem, | 1276 | const struct ieee80211_channel_sw_ie *sw_elem, |
1285 | struct ieee80211_bss *bss, u64 timestamp); | 1277 | struct ieee80211_bss *bss, u64 timestamp); |
1286 | void ieee80211_sta_quiesce(struct ieee80211_sub_if_data *sdata); | ||
1287 | void ieee80211_sta_restart(struct ieee80211_sub_if_data *sdata); | ||
1288 | void ieee80211_sta_work(struct ieee80211_sub_if_data *sdata); | 1278 | void ieee80211_sta_work(struct ieee80211_sub_if_data *sdata); |
1289 | void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata, | 1279 | void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata, |
1290 | struct sk_buff *skb); | 1280 | struct sk_buff *skb); |
@@ -1302,8 +1292,6 @@ void ieee80211_ibss_rx_no_sta(struct ieee80211_sub_if_data *sdata, | |||
1302 | int ieee80211_ibss_join(struct ieee80211_sub_if_data *sdata, | 1292 | int ieee80211_ibss_join(struct ieee80211_sub_if_data *sdata, |
1303 | struct cfg80211_ibss_params *params); | 1293 | struct cfg80211_ibss_params *params); |
1304 | int ieee80211_ibss_leave(struct ieee80211_sub_if_data *sdata); | 1294 | int ieee80211_ibss_leave(struct ieee80211_sub_if_data *sdata); |
1305 | void ieee80211_ibss_quiesce(struct ieee80211_sub_if_data *sdata); | ||
1306 | void ieee80211_ibss_restart(struct ieee80211_sub_if_data *sdata); | ||
1307 | void ieee80211_ibss_work(struct ieee80211_sub_if_data *sdata); | 1295 | void ieee80211_ibss_work(struct ieee80211_sub_if_data *sdata); |
1308 | void ieee80211_ibss_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata, | 1296 | void ieee80211_ibss_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata, |
1309 | struct sk_buff *skb); | 1297 | struct sk_buff *skb); |
@@ -1441,6 +1429,8 @@ void ieee80211_sta_set_rx_nss(struct sta_info *sta); | |||
1441 | void ieee80211_vht_handle_opmode(struct ieee80211_sub_if_data *sdata, | 1429 | void ieee80211_vht_handle_opmode(struct ieee80211_sub_if_data *sdata, |
1442 | struct sta_info *sta, u8 opmode, | 1430 | struct sta_info *sta, u8 opmode, |
1443 | enum ieee80211_band band, bool nss_only); | 1431 | enum ieee80211_band band, bool nss_only); |
1432 | void ieee80211_apply_vhtcap_overrides(struct ieee80211_sub_if_data *sdata, | ||
1433 | struct ieee80211_sta_vht_cap *vht_cap); | ||
1444 | 1434 | ||
1445 | /* Spectrum management */ | 1435 | /* Spectrum management */ |
1446 | void ieee80211_process_measurement_req(struct ieee80211_sub_if_data *sdata, | 1436 | void ieee80211_process_measurement_req(struct ieee80211_sub_if_data *sdata, |
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index 3bfe2612c8c2..7530c60fe502 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c | |||
@@ -488,8 +488,6 @@ int ieee80211_do_open(struct wireless_dev *wdev, bool coming_up) | |||
488 | res = drv_start(local); | 488 | res = drv_start(local); |
489 | if (res) | 489 | if (res) |
490 | goto err_del_bss; | 490 | goto err_del_bss; |
491 | if (local->ops->napi_poll) | ||
492 | napi_enable(&local->napi); | ||
493 | /* we're brought up, everything changes */ | 491 | /* we're brought up, everything changes */ |
494 | hw_reconf_flags = ~0; | 492 | hw_reconf_flags = ~0; |
495 | ieee80211_led_radio(local, true); | 493 | ieee80211_led_radio(local, true); |
@@ -841,14 +839,16 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, | |||
841 | rcu_barrier(); | 839 | rcu_barrier(); |
842 | sta_info_flush_cleanup(sdata); | 840 | sta_info_flush_cleanup(sdata); |
843 | 841 | ||
844 | skb_queue_purge(&sdata->skb_queue); | ||
845 | |||
846 | /* | 842 | /* |
847 | * Free all remaining keys, there shouldn't be any, | 843 | * Free all remaining keys, there shouldn't be any, |
848 | * except maybe group keys in AP more or WDS? | 844 | * except maybe in WDS mode? |
849 | */ | 845 | */ |
850 | ieee80211_free_keys(sdata); | 846 | ieee80211_free_keys(sdata); |
851 | 847 | ||
848 | /* fall through */ | ||
849 | case NL80211_IFTYPE_AP: | ||
850 | skb_queue_purge(&sdata->skb_queue); | ||
851 | |||
852 | drv_remove_interface_debugfs(local, sdata); | 852 | drv_remove_interface_debugfs(local, sdata); |
853 | 853 | ||
854 | if (going_down) | 854 | if (going_down) |
@@ -860,8 +860,6 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, | |||
860 | ieee80211_recalc_ps(local, -1); | 860 | ieee80211_recalc_ps(local, -1); |
861 | 861 | ||
862 | if (local->open_count == 0) { | 862 | if (local->open_count == 0) { |
863 | if (local->ops->napi_poll) | ||
864 | napi_disable(&local->napi); | ||
865 | ieee80211_clear_tx_pending(local); | 863 | ieee80211_clear_tx_pending(local); |
866 | ieee80211_stop_device(local); | 864 | ieee80211_stop_device(local); |
867 | 865 | ||
@@ -1550,6 +1548,8 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name, | |||
1550 | INIT_WORK(&sdata->cleanup_stations_wk, ieee80211_cleanup_sdata_stas_wk); | 1548 | INIT_WORK(&sdata->cleanup_stations_wk, ieee80211_cleanup_sdata_stas_wk); |
1551 | INIT_DELAYED_WORK(&sdata->dfs_cac_timer_work, | 1549 | INIT_DELAYED_WORK(&sdata->dfs_cac_timer_work, |
1552 | ieee80211_dfs_cac_timer_work); | 1550 | ieee80211_dfs_cac_timer_work); |
1551 | INIT_DELAYED_WORK(&sdata->dec_tailroom_needed_wk, | ||
1552 | ieee80211_delayed_tailroom_dec); | ||
1553 | 1553 | ||
1554 | for (i = 0; i < IEEE80211_NUM_BANDS; i++) { | 1554 | for (i = 0; i < IEEE80211_NUM_BANDS; i++) { |
1555 | struct ieee80211_supported_band *sband; | 1555 | struct ieee80211_supported_band *sband; |
diff --git a/net/mac80211/key.c b/net/mac80211/key.c index ef252eb58c36..99e9f6ae6a54 100644 --- a/net/mac80211/key.c +++ b/net/mac80211/key.c | |||
@@ -397,7 +397,8 @@ struct ieee80211_key *ieee80211_key_alloc(u32 cipher, int idx, size_t key_len, | |||
397 | return key; | 397 | return key; |
398 | } | 398 | } |
399 | 399 | ||
400 | static void __ieee80211_key_destroy(struct ieee80211_key *key) | 400 | static void __ieee80211_key_destroy(struct ieee80211_key *key, |
401 | bool delay_tailroom) | ||
401 | { | 402 | { |
402 | if (!key) | 403 | if (!key) |
403 | return; | 404 | return; |
@@ -416,8 +417,18 @@ static void __ieee80211_key_destroy(struct ieee80211_key *key) | |||
416 | if (key->conf.cipher == WLAN_CIPHER_SUITE_AES_CMAC) | 417 | if (key->conf.cipher == WLAN_CIPHER_SUITE_AES_CMAC) |
417 | ieee80211_aes_cmac_key_free(key->u.aes_cmac.tfm); | 418 | ieee80211_aes_cmac_key_free(key->u.aes_cmac.tfm); |
418 | if (key->local) { | 419 | if (key->local) { |
420 | struct ieee80211_sub_if_data *sdata = key->sdata; | ||
421 | |||
419 | ieee80211_debugfs_key_remove(key); | 422 | ieee80211_debugfs_key_remove(key); |
420 | key->sdata->crypto_tx_tailroom_needed_cnt--; | 423 | |
424 | if (delay_tailroom) { | ||
425 | /* see ieee80211_delayed_tailroom_dec */ | ||
426 | sdata->crypto_tx_tailroom_pending_dec++; | ||
427 | schedule_delayed_work(&sdata->dec_tailroom_needed_wk, | ||
428 | HZ/2); | ||
429 | } else { | ||
430 | sdata->crypto_tx_tailroom_needed_cnt--; | ||
431 | } | ||
421 | } | 432 | } |
422 | 433 | ||
423 | kfree(key); | 434 | kfree(key); |
@@ -440,32 +451,6 @@ int ieee80211_key_link(struct ieee80211_key *key, | |||
440 | key->sdata = sdata; | 451 | key->sdata = sdata; |
441 | key->sta = sta; | 452 | key->sta = sta; |
442 | 453 | ||
443 | if (sta) { | ||
444 | /* | ||
445 | * some hardware cannot handle TKIP with QoS, so | ||
446 | * we indicate whether QoS could be in use. | ||
447 | */ | ||
448 | if (test_sta_flag(sta, WLAN_STA_WME)) | ||
449 | key->conf.flags |= IEEE80211_KEY_FLAG_WMM_STA; | ||
450 | } else { | ||
451 | if (sdata->vif.type == NL80211_IFTYPE_STATION) { | ||
452 | struct sta_info *ap; | ||
453 | |||
454 | /* | ||
455 | * We're getting a sta pointer in, so must be under | ||
456 | * appropriate locking for sta_info_get(). | ||
457 | */ | ||
458 | |||
459 | /* same here, the AP could be using QoS */ | ||
460 | ap = sta_info_get(key->sdata, key->sdata->u.mgd.bssid); | ||
461 | if (ap) { | ||
462 | if (test_sta_flag(ap, WLAN_STA_WME)) | ||
463 | key->conf.flags |= | ||
464 | IEEE80211_KEY_FLAG_WMM_STA; | ||
465 | } | ||
466 | } | ||
467 | } | ||
468 | |||
469 | mutex_lock(&sdata->local->key_mtx); | 454 | mutex_lock(&sdata->local->key_mtx); |
470 | 455 | ||
471 | if (sta && pairwise) | 456 | if (sta && pairwise) |
@@ -478,7 +463,7 @@ int ieee80211_key_link(struct ieee80211_key *key, | |||
478 | increment_tailroom_need_count(sdata); | 463 | increment_tailroom_need_count(sdata); |
479 | 464 | ||
480 | __ieee80211_key_replace(sdata, sta, pairwise, old_key, key); | 465 | __ieee80211_key_replace(sdata, sta, pairwise, old_key, key); |
481 | __ieee80211_key_destroy(old_key); | 466 | __ieee80211_key_destroy(old_key, true); |
482 | 467 | ||
483 | ieee80211_debugfs_key_add(key); | 468 | ieee80211_debugfs_key_add(key); |
484 | 469 | ||
@@ -489,7 +474,7 @@ int ieee80211_key_link(struct ieee80211_key *key, | |||
489 | return ret; | 474 | return ret; |
490 | } | 475 | } |
491 | 476 | ||
492 | void __ieee80211_key_free(struct ieee80211_key *key) | 477 | void __ieee80211_key_free(struct ieee80211_key *key, bool delay_tailroom) |
493 | { | 478 | { |
494 | if (!key) | 479 | if (!key) |
495 | return; | 480 | return; |
@@ -501,14 +486,14 @@ void __ieee80211_key_free(struct ieee80211_key *key) | |||
501 | __ieee80211_key_replace(key->sdata, key->sta, | 486 | __ieee80211_key_replace(key->sdata, key->sta, |
502 | key->conf.flags & IEEE80211_KEY_FLAG_PAIRWISE, | 487 | key->conf.flags & IEEE80211_KEY_FLAG_PAIRWISE, |
503 | key, NULL); | 488 | key, NULL); |
504 | __ieee80211_key_destroy(key); | 489 | __ieee80211_key_destroy(key, delay_tailroom); |
505 | } | 490 | } |
506 | 491 | ||
507 | void ieee80211_key_free(struct ieee80211_local *local, | 492 | void ieee80211_key_free(struct ieee80211_local *local, |
508 | struct ieee80211_key *key) | 493 | struct ieee80211_key *key) |
509 | { | 494 | { |
510 | mutex_lock(&local->key_mtx); | 495 | mutex_lock(&local->key_mtx); |
511 | __ieee80211_key_free(key); | 496 | __ieee80211_key_free(key, true); |
512 | mutex_unlock(&local->key_mtx); | 497 | mutex_unlock(&local->key_mtx); |
513 | } | 498 | } |
514 | 499 | ||
@@ -566,36 +551,60 @@ void ieee80211_iter_keys(struct ieee80211_hw *hw, | |||
566 | } | 551 | } |
567 | EXPORT_SYMBOL(ieee80211_iter_keys); | 552 | EXPORT_SYMBOL(ieee80211_iter_keys); |
568 | 553 | ||
569 | void ieee80211_disable_keys(struct ieee80211_sub_if_data *sdata) | ||
570 | { | ||
571 | struct ieee80211_key *key; | ||
572 | |||
573 | ASSERT_RTNL(); | ||
574 | |||
575 | mutex_lock(&sdata->local->key_mtx); | ||
576 | |||
577 | list_for_each_entry(key, &sdata->key_list, list) | ||
578 | ieee80211_key_disable_hw_accel(key); | ||
579 | |||
580 | mutex_unlock(&sdata->local->key_mtx); | ||
581 | } | ||
582 | |||
583 | void ieee80211_free_keys(struct ieee80211_sub_if_data *sdata) | 554 | void ieee80211_free_keys(struct ieee80211_sub_if_data *sdata) |
584 | { | 555 | { |
585 | struct ieee80211_key *key, *tmp; | 556 | struct ieee80211_key *key, *tmp; |
586 | 557 | ||
558 | cancel_delayed_work_sync(&sdata->dec_tailroom_needed_wk); | ||
559 | |||
587 | mutex_lock(&sdata->local->key_mtx); | 560 | mutex_lock(&sdata->local->key_mtx); |
588 | 561 | ||
562 | sdata->crypto_tx_tailroom_needed_cnt -= | ||
563 | sdata->crypto_tx_tailroom_pending_dec; | ||
564 | sdata->crypto_tx_tailroom_pending_dec = 0; | ||
565 | |||
589 | ieee80211_debugfs_key_remove_mgmt_default(sdata); | 566 | ieee80211_debugfs_key_remove_mgmt_default(sdata); |
590 | 567 | ||
591 | list_for_each_entry_safe(key, tmp, &sdata->key_list, list) | 568 | list_for_each_entry_safe(key, tmp, &sdata->key_list, list) |
592 | __ieee80211_key_free(key); | 569 | __ieee80211_key_free(key, false); |
593 | 570 | ||
594 | ieee80211_debugfs_key_update_default(sdata); | 571 | ieee80211_debugfs_key_update_default(sdata); |
595 | 572 | ||
573 | WARN_ON_ONCE(sdata->crypto_tx_tailroom_needed_cnt || | ||
574 | sdata->crypto_tx_tailroom_pending_dec); | ||
575 | |||
596 | mutex_unlock(&sdata->local->key_mtx); | 576 | mutex_unlock(&sdata->local->key_mtx); |
597 | } | 577 | } |
598 | 578 | ||
579 | void ieee80211_delayed_tailroom_dec(struct work_struct *wk) | ||
580 | { | ||
581 | struct ieee80211_sub_if_data *sdata; | ||
582 | |||
583 | sdata = container_of(wk, struct ieee80211_sub_if_data, | ||
584 | dec_tailroom_needed_wk.work); | ||
585 | |||
586 | /* | ||
587 | * The reason for the delayed tailroom needed decrementing is to | ||
588 | * make roaming faster: during roaming, all keys are first deleted | ||
589 | * and then new keys are installed. The first new key causes the | ||
590 | * crypto_tx_tailroom_needed_cnt to go from 0 to 1, which invokes | ||
591 | * the cost of synchronize_net() (which can be slow). Avoid this | ||
592 | * by deferring the crypto_tx_tailroom_needed_cnt decrementing on | ||
593 | * key removal for a while, so if we roam the value is larger than | ||
594 | * zero and no 0->1 transition happens. | ||
595 | * | ||
596 | * The cost is that if the AP switching was from an AP with keys | ||
597 | * to one without, we still allocate tailroom while it would no | ||
598 | * longer be needed. However, in the typical (fast) roaming case | ||
599 | * within an ESS this usually won't happen. | ||
600 | */ | ||
601 | |||
602 | mutex_lock(&sdata->local->key_mtx); | ||
603 | sdata->crypto_tx_tailroom_needed_cnt -= | ||
604 | sdata->crypto_tx_tailroom_pending_dec; | ||
605 | sdata->crypto_tx_tailroom_pending_dec = 0; | ||
606 | mutex_unlock(&sdata->local->key_mtx); | ||
607 | } | ||
599 | 608 | ||
600 | void ieee80211_gtk_rekey_notify(struct ieee80211_vif *vif, const u8 *bssid, | 609 | void ieee80211_gtk_rekey_notify(struct ieee80211_vif *vif, const u8 *bssid, |
601 | const u8 *replay_ctr, gfp_t gfp) | 610 | const u8 *replay_ctr, gfp_t gfp) |
diff --git a/net/mac80211/key.h b/net/mac80211/key.h index 382dc44ed330..2a682d81cee9 100644 --- a/net/mac80211/key.h +++ b/net/mac80211/key.h | |||
@@ -134,7 +134,7 @@ struct ieee80211_key *ieee80211_key_alloc(u32 cipher, int idx, size_t key_len, | |||
134 | int __must_check ieee80211_key_link(struct ieee80211_key *key, | 134 | int __must_check ieee80211_key_link(struct ieee80211_key *key, |
135 | struct ieee80211_sub_if_data *sdata, | 135 | struct ieee80211_sub_if_data *sdata, |
136 | struct sta_info *sta); | 136 | struct sta_info *sta); |
137 | void __ieee80211_key_free(struct ieee80211_key *key); | 137 | void __ieee80211_key_free(struct ieee80211_key *key, bool delay_tailroom); |
138 | void ieee80211_key_free(struct ieee80211_local *local, | 138 | void ieee80211_key_free(struct ieee80211_local *local, |
139 | struct ieee80211_key *key); | 139 | struct ieee80211_key *key); |
140 | void ieee80211_set_default_key(struct ieee80211_sub_if_data *sdata, int idx, | 140 | void ieee80211_set_default_key(struct ieee80211_sub_if_data *sdata, int idx, |
@@ -143,9 +143,10 @@ void ieee80211_set_default_mgmt_key(struct ieee80211_sub_if_data *sdata, | |||
143 | int idx); | 143 | int idx); |
144 | void ieee80211_free_keys(struct ieee80211_sub_if_data *sdata); | 144 | void ieee80211_free_keys(struct ieee80211_sub_if_data *sdata); |
145 | void ieee80211_enable_keys(struct ieee80211_sub_if_data *sdata); | 145 | void ieee80211_enable_keys(struct ieee80211_sub_if_data *sdata); |
146 | void ieee80211_disable_keys(struct ieee80211_sub_if_data *sdata); | ||
147 | 146 | ||
148 | #define key_mtx_dereference(local, ref) \ | 147 | #define key_mtx_dereference(local, ref) \ |
149 | rcu_dereference_protected(ref, lockdep_is_held(&((local)->key_mtx))) | 148 | rcu_dereference_protected(ref, lockdep_is_held(&((local)->key_mtx))) |
150 | 149 | ||
150 | void ieee80211_delayed_tailroom_dec(struct work_struct *wk); | ||
151 | |||
151 | #endif /* IEEE80211_KEY_H */ | 152 | #endif /* IEEE80211_KEY_H */ |
diff --git a/net/mac80211/main.c b/net/mac80211/main.c index 1a8591b77a13..5a53aa5ede80 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c | |||
@@ -399,30 +399,6 @@ static int ieee80211_ifa6_changed(struct notifier_block *nb, | |||
399 | } | 399 | } |
400 | #endif | 400 | #endif |
401 | 401 | ||
402 | static int ieee80211_napi_poll(struct napi_struct *napi, int budget) | ||
403 | { | ||
404 | struct ieee80211_local *local = | ||
405 | container_of(napi, struct ieee80211_local, napi); | ||
406 | |||
407 | return local->ops->napi_poll(&local->hw, budget); | ||
408 | } | ||
409 | |||
410 | void ieee80211_napi_schedule(struct ieee80211_hw *hw) | ||
411 | { | ||
412 | struct ieee80211_local *local = hw_to_local(hw); | ||
413 | |||
414 | napi_schedule(&local->napi); | ||
415 | } | ||
416 | EXPORT_SYMBOL(ieee80211_napi_schedule); | ||
417 | |||
418 | void ieee80211_napi_complete(struct ieee80211_hw *hw) | ||
419 | { | ||
420 | struct ieee80211_local *local = hw_to_local(hw); | ||
421 | |||
422 | napi_complete(&local->napi); | ||
423 | } | ||
424 | EXPORT_SYMBOL(ieee80211_napi_complete); | ||
425 | |||
426 | /* There isn't a lot of sense in it, but you can transmit anything you like */ | 402 | /* There isn't a lot of sense in it, but you can transmit anything you like */ |
427 | static const struct ieee80211_txrx_stypes | 403 | static const struct ieee80211_txrx_stypes |
428 | ieee80211_default_mgmt_stypes[NUM_NL80211_IFTYPES] = { | 404 | ieee80211_default_mgmt_stypes[NUM_NL80211_IFTYPES] = { |
@@ -501,6 +477,27 @@ static const struct ieee80211_ht_cap mac80211_ht_capa_mod_mask = { | |||
501 | }, | 477 | }, |
502 | }; | 478 | }; |
503 | 479 | ||
480 | static const struct ieee80211_vht_cap mac80211_vht_capa_mod_mask = { | ||
481 | .vht_cap_info = | ||
482 | cpu_to_le32(IEEE80211_VHT_CAP_RXLDPC | | ||
483 | IEEE80211_VHT_CAP_SHORT_GI_80 | | ||
484 | IEEE80211_VHT_CAP_SHORT_GI_160 | | ||
485 | IEEE80211_VHT_CAP_RXSTBC_1 | | ||
486 | IEEE80211_VHT_CAP_RXSTBC_2 | | ||
487 | IEEE80211_VHT_CAP_RXSTBC_3 | | ||
488 | IEEE80211_VHT_CAP_RXSTBC_4 | | ||
489 | IEEE80211_VHT_CAP_TXSTBC | | ||
490 | IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE | | ||
491 | IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE | | ||
492 | IEEE80211_VHT_CAP_TX_ANTENNA_PATTERN | | ||
493 | IEEE80211_VHT_CAP_RX_ANTENNA_PATTERN | | ||
494 | IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK), | ||
495 | .supp_mcs = { | ||
496 | .rx_mcs_map = cpu_to_le16(~0), | ||
497 | .tx_mcs_map = cpu_to_le16(~0), | ||
498 | }, | ||
499 | }; | ||
500 | |||
504 | static const u8 extended_capabilities[] = { | 501 | static const u8 extended_capabilities[] = { |
505 | 0, 0, 0, 0, 0, 0, 0, | 502 | 0, 0, 0, 0, 0, 0, 0, |
506 | WLAN_EXT_CAPA8_OPMODE_NOTIF, | 503 | WLAN_EXT_CAPA8_OPMODE_NOTIF, |
@@ -572,7 +569,8 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, | |||
572 | wiphy->features |= NL80211_FEATURE_SK_TX_STATUS | | 569 | wiphy->features |= NL80211_FEATURE_SK_TX_STATUS | |
573 | NL80211_FEATURE_SAE | | 570 | NL80211_FEATURE_SAE | |
574 | NL80211_FEATURE_HT_IBSS | | 571 | NL80211_FEATURE_HT_IBSS | |
575 | NL80211_FEATURE_VIF_TXPOWER; | 572 | NL80211_FEATURE_VIF_TXPOWER | |
573 | NL80211_FEATURE_USERSPACE_MPM; | ||
576 | 574 | ||
577 | if (!ops->hw_scan) | 575 | if (!ops->hw_scan) |
578 | wiphy->features |= NL80211_FEATURE_LOW_PRIORITY_SCAN | | 576 | wiphy->features |= NL80211_FEATURE_LOW_PRIORITY_SCAN | |
@@ -609,6 +607,7 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, | |||
609 | IEEE80211_RADIOTAP_VHT_KNOWN_BANDWIDTH; | 607 | IEEE80211_RADIOTAP_VHT_KNOWN_BANDWIDTH; |
610 | local->user_power_level = IEEE80211_UNSET_POWER_LEVEL; | 608 | local->user_power_level = IEEE80211_UNSET_POWER_LEVEL; |
611 | wiphy->ht_capa_mod_mask = &mac80211_ht_capa_mod_mask; | 609 | wiphy->ht_capa_mod_mask = &mac80211_ht_capa_mod_mask; |
610 | wiphy->vht_capa_mod_mask = &mac80211_vht_capa_mod_mask; | ||
612 | 611 | ||
613 | INIT_LIST_HEAD(&local->interfaces); | 612 | INIT_LIST_HEAD(&local->interfaces); |
614 | 613 | ||
@@ -664,9 +663,6 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, | |||
664 | skb_queue_head_init(&local->skb_queue); | 663 | skb_queue_head_init(&local->skb_queue); |
665 | skb_queue_head_init(&local->skb_queue_unreliable); | 664 | skb_queue_head_init(&local->skb_queue_unreliable); |
666 | 665 | ||
667 | /* init dummy netdev for use w/ NAPI */ | ||
668 | init_dummy_netdev(&local->napi_dev); | ||
669 | |||
670 | ieee80211_led_names(local); | 666 | ieee80211_led_names(local); |
671 | 667 | ||
672 | ieee80211_roc_setup(local); | 668 | ieee80211_roc_setup(local); |
@@ -1021,9 +1017,6 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) | |||
1021 | goto fail_ifa6; | 1017 | goto fail_ifa6; |
1022 | #endif | 1018 | #endif |
1023 | 1019 | ||
1024 | netif_napi_add(&local->napi_dev, &local->napi, ieee80211_napi_poll, | ||
1025 | local->hw.napi_weight); | ||
1026 | |||
1027 | return 0; | 1020 | return 0; |
1028 | 1021 | ||
1029 | #if IS_ENABLED(CONFIG_IPV6) | 1022 | #if IS_ENABLED(CONFIG_IPV6) |
diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c index 4749b3858695..77b5710db241 100644 --- a/net/mac80211/mesh.c +++ b/net/mac80211/mesh.c | |||
@@ -13,10 +13,6 @@ | |||
13 | #include "ieee80211_i.h" | 13 | #include "ieee80211_i.h" |
14 | #include "mesh.h" | 14 | #include "mesh.h" |
15 | 15 | ||
16 | #define TMR_RUNNING_HK 0 | ||
17 | #define TMR_RUNNING_MP 1 | ||
18 | #define TMR_RUNNING_MPR 2 | ||
19 | |||
20 | static int mesh_allocated; | 16 | static int mesh_allocated; |
21 | static struct kmem_cache *rm_cache; | 17 | static struct kmem_cache *rm_cache; |
22 | 18 | ||
@@ -50,11 +46,6 @@ static void ieee80211_mesh_housekeeping_timer(unsigned long data) | |||
50 | 46 | ||
51 | set_bit(MESH_WORK_HOUSEKEEPING, &ifmsh->wrkq_flags); | 47 | set_bit(MESH_WORK_HOUSEKEEPING, &ifmsh->wrkq_flags); |
52 | 48 | ||
53 | if (local->quiescing) { | ||
54 | set_bit(TMR_RUNNING_HK, &ifmsh->timers_running); | ||
55 | return; | ||
56 | } | ||
57 | |||
58 | ieee80211_queue_work(&local->hw, &sdata->work); | 49 | ieee80211_queue_work(&local->hw, &sdata->work); |
59 | } | 50 | } |
60 | 51 | ||
@@ -165,7 +156,7 @@ void mesh_sta_cleanup(struct sta_info *sta) | |||
165 | * an update. | 156 | * an update. |
166 | */ | 157 | */ |
167 | changed = mesh_accept_plinks_update(sdata); | 158 | changed = mesh_accept_plinks_update(sdata); |
168 | if (sdata->u.mesh.security == IEEE80211_MESH_SEC_NONE) { | 159 | if (!sdata->u.mesh.user_mpm) { |
169 | changed |= mesh_plink_deactivate(sta); | 160 | changed |= mesh_plink_deactivate(sta); |
170 | del_timer_sync(&sta->plink_timer); | 161 | del_timer_sync(&sta->plink_timer); |
171 | } | 162 | } |
@@ -479,15 +470,8 @@ static void ieee80211_mesh_path_timer(unsigned long data) | |||
479 | { | 470 | { |
480 | struct ieee80211_sub_if_data *sdata = | 471 | struct ieee80211_sub_if_data *sdata = |
481 | (struct ieee80211_sub_if_data *) data; | 472 | (struct ieee80211_sub_if_data *) data; |
482 | struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; | ||
483 | struct ieee80211_local *local = sdata->local; | ||
484 | |||
485 | if (local->quiescing) { | ||
486 | set_bit(TMR_RUNNING_MP, &ifmsh->timers_running); | ||
487 | return; | ||
488 | } | ||
489 | 473 | ||
490 | ieee80211_queue_work(&local->hw, &sdata->work); | 474 | ieee80211_queue_work(&sdata->local->hw, &sdata->work); |
491 | } | 475 | } |
492 | 476 | ||
493 | static void ieee80211_mesh_path_root_timer(unsigned long data) | 477 | static void ieee80211_mesh_path_root_timer(unsigned long data) |
@@ -495,16 +479,10 @@ static void ieee80211_mesh_path_root_timer(unsigned long data) | |||
495 | struct ieee80211_sub_if_data *sdata = | 479 | struct ieee80211_sub_if_data *sdata = |
496 | (struct ieee80211_sub_if_data *) data; | 480 | (struct ieee80211_sub_if_data *) data; |
497 | struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; | 481 | struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; |
498 | struct ieee80211_local *local = sdata->local; | ||
499 | 482 | ||
500 | set_bit(MESH_WORK_ROOT, &ifmsh->wrkq_flags); | 483 | set_bit(MESH_WORK_ROOT, &ifmsh->wrkq_flags); |
501 | 484 | ||
502 | if (local->quiescing) { | 485 | ieee80211_queue_work(&sdata->local->hw, &sdata->work); |
503 | set_bit(TMR_RUNNING_MPR, &ifmsh->timers_running); | ||
504 | return; | ||
505 | } | ||
506 | |||
507 | ieee80211_queue_work(&local->hw, &sdata->work); | ||
508 | } | 486 | } |
509 | 487 | ||
510 | void ieee80211_mesh_root_setup(struct ieee80211_if_mesh *ifmsh) | 488 | void ieee80211_mesh_root_setup(struct ieee80211_if_mesh *ifmsh) |
@@ -622,35 +600,6 @@ static void ieee80211_mesh_rootpath(struct ieee80211_sub_if_data *sdata) | |||
622 | round_jiffies(TU_TO_EXP_TIME(interval))); | 600 | round_jiffies(TU_TO_EXP_TIME(interval))); |
623 | } | 601 | } |
624 | 602 | ||
625 | #ifdef CONFIG_PM | ||
626 | void ieee80211_mesh_quiesce(struct ieee80211_sub_if_data *sdata) | ||
627 | { | ||
628 | struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; | ||
629 | |||
630 | /* use atomic bitops in case all timers fire at the same time */ | ||
631 | |||
632 | if (del_timer_sync(&ifmsh->housekeeping_timer)) | ||
633 | set_bit(TMR_RUNNING_HK, &ifmsh->timers_running); | ||
634 | if (del_timer_sync(&ifmsh->mesh_path_timer)) | ||
635 | set_bit(TMR_RUNNING_MP, &ifmsh->timers_running); | ||
636 | if (del_timer_sync(&ifmsh->mesh_path_root_timer)) | ||
637 | set_bit(TMR_RUNNING_MPR, &ifmsh->timers_running); | ||
638 | } | ||
639 | |||
640 | void ieee80211_mesh_restart(struct ieee80211_sub_if_data *sdata) | ||
641 | { | ||
642 | struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; | ||
643 | |||
644 | if (test_and_clear_bit(TMR_RUNNING_HK, &ifmsh->timers_running)) | ||
645 | add_timer(&ifmsh->housekeeping_timer); | ||
646 | if (test_and_clear_bit(TMR_RUNNING_MP, &ifmsh->timers_running)) | ||
647 | add_timer(&ifmsh->mesh_path_timer); | ||
648 | if (test_and_clear_bit(TMR_RUNNING_MPR, &ifmsh->timers_running)) | ||
649 | add_timer(&ifmsh->mesh_path_root_timer); | ||
650 | ieee80211_mesh_root_setup(ifmsh); | ||
651 | } | ||
652 | #endif | ||
653 | |||
654 | static int | 603 | static int |
655 | ieee80211_mesh_build_beacon(struct ieee80211_if_mesh *ifmsh) | 604 | ieee80211_mesh_build_beacon(struct ieee80211_if_mesh *ifmsh) |
656 | { | 605 | { |
@@ -871,8 +820,6 @@ void ieee80211_stop_mesh(struct ieee80211_sub_if_data *sdata) | |||
871 | local->fif_other_bss--; | 820 | local->fif_other_bss--; |
872 | atomic_dec(&local->iff_allmultis); | 821 | atomic_dec(&local->iff_allmultis); |
873 | ieee80211_configure_filter(local); | 822 | ieee80211_configure_filter(local); |
874 | |||
875 | sdata->u.mesh.timers_running = 0; | ||
876 | } | 823 | } |
877 | 824 | ||
878 | static void | 825 | static void |
diff --git a/net/mac80211/mesh.h b/net/mac80211/mesh.h index 336c88a16687..6ffabbe99c46 100644 --- a/net/mac80211/mesh.h +++ b/net/mac80211/mesh.h | |||
@@ -313,8 +313,6 @@ void mesh_path_timer(unsigned long data); | |||
313 | void mesh_path_flush_by_nexthop(struct sta_info *sta); | 313 | void mesh_path_flush_by_nexthop(struct sta_info *sta); |
314 | void mesh_path_discard_frame(struct ieee80211_sub_if_data *sdata, | 314 | void mesh_path_discard_frame(struct ieee80211_sub_if_data *sdata, |
315 | struct sk_buff *skb); | 315 | struct sk_buff *skb); |
316 | void mesh_path_quiesce(struct ieee80211_sub_if_data *sdata); | ||
317 | void mesh_path_restart(struct ieee80211_sub_if_data *sdata); | ||
318 | void mesh_path_tx_root_frame(struct ieee80211_sub_if_data *sdata); | 316 | void mesh_path_tx_root_frame(struct ieee80211_sub_if_data *sdata); |
319 | 317 | ||
320 | bool mesh_action_is_path_sel(struct ieee80211_mgmt *mgmt); | 318 | bool mesh_action_is_path_sel(struct ieee80211_mgmt *mgmt); |
@@ -359,22 +357,12 @@ static inline bool mesh_path_sel_is_hwmp(struct ieee80211_sub_if_data *sdata) | |||
359 | 357 | ||
360 | void ieee80211_mesh_notify_scan_completed(struct ieee80211_local *local); | 358 | void ieee80211_mesh_notify_scan_completed(struct ieee80211_local *local); |
361 | 359 | ||
362 | void ieee80211_mesh_quiesce(struct ieee80211_sub_if_data *sdata); | ||
363 | void ieee80211_mesh_restart(struct ieee80211_sub_if_data *sdata); | ||
364 | void mesh_plink_quiesce(struct sta_info *sta); | ||
365 | void mesh_plink_restart(struct sta_info *sta); | ||
366 | void mesh_path_flush_by_iface(struct ieee80211_sub_if_data *sdata); | 360 | void mesh_path_flush_by_iface(struct ieee80211_sub_if_data *sdata); |
367 | void mesh_sync_adjust_tbtt(struct ieee80211_sub_if_data *sdata); | 361 | void mesh_sync_adjust_tbtt(struct ieee80211_sub_if_data *sdata); |
368 | void ieee80211s_stop(void); | 362 | void ieee80211s_stop(void); |
369 | #else | 363 | #else |
370 | static inline void | 364 | static inline void |
371 | ieee80211_mesh_notify_scan_completed(struct ieee80211_local *local) {} | 365 | ieee80211_mesh_notify_scan_completed(struct ieee80211_local *local) {} |
372 | static inline void ieee80211_mesh_quiesce(struct ieee80211_sub_if_data *sdata) | ||
373 | {} | ||
374 | static inline void ieee80211_mesh_restart(struct ieee80211_sub_if_data *sdata) | ||
375 | {} | ||
376 | static inline void mesh_plink_quiesce(struct sta_info *sta) {} | ||
377 | static inline void mesh_plink_restart(struct sta_info *sta) {} | ||
378 | static inline bool mesh_path_sel_is_hwmp(struct ieee80211_sub_if_data *sdata) | 366 | static inline bool mesh_path_sel_is_hwmp(struct ieee80211_sub_if_data *sdata) |
379 | { return false; } | 367 | { return false; } |
380 | static inline void mesh_path_flush_by_iface(struct ieee80211_sub_if_data *sdata) | 368 | static inline void mesh_path_flush_by_iface(struct ieee80211_sub_if_data *sdata) |
diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c index 07d396d57079..937e06fe8f2a 100644 --- a/net/mac80211/mesh_plink.c +++ b/net/mac80211/mesh_plink.c | |||
@@ -420,7 +420,6 @@ __mesh_sta_info_alloc(struct ieee80211_sub_if_data *sdata, u8 *hw_addr) | |||
420 | return NULL; | 420 | return NULL; |
421 | 421 | ||
422 | sta->plink_state = NL80211_PLINK_LISTEN; | 422 | sta->plink_state = NL80211_PLINK_LISTEN; |
423 | init_timer(&sta->plink_timer); | ||
424 | 423 | ||
425 | sta_info_pre_move_state(sta, IEEE80211_STA_AUTH); | 424 | sta_info_pre_move_state(sta, IEEE80211_STA_AUTH); |
426 | sta_info_pre_move_state(sta, IEEE80211_STA_ASSOC); | 425 | sta_info_pre_move_state(sta, IEEE80211_STA_ASSOC); |
@@ -437,8 +436,9 @@ mesh_sta_info_alloc(struct ieee80211_sub_if_data *sdata, u8 *addr, | |||
437 | { | 436 | { |
438 | struct sta_info *sta = NULL; | 437 | struct sta_info *sta = NULL; |
439 | 438 | ||
440 | /* Userspace handles peer allocation when security is enabled */ | 439 | /* Userspace handles station allocation */ |
441 | if (sdata->u.mesh.security & IEEE80211_MESH_SEC_AUTHED) | 440 | if (sdata->u.mesh.user_mpm || |
441 | sdata->u.mesh.security & IEEE80211_MESH_SEC_AUTHED) | ||
442 | cfg80211_notify_new_peer_candidate(sdata->dev, addr, | 442 | cfg80211_notify_new_peer_candidate(sdata->dev, addr, |
443 | elems->ie_start, | 443 | elems->ie_start, |
444 | elems->total_len, | 444 | elems->total_len, |
@@ -534,10 +534,8 @@ static void mesh_plink_timer(unsigned long data) | |||
534 | */ | 534 | */ |
535 | sta = (struct sta_info *) data; | 535 | sta = (struct sta_info *) data; |
536 | 536 | ||
537 | if (sta->sdata->local->quiescing) { | 537 | if (sta->sdata->local->quiescing) |
538 | sta->plink_timer_was_running = true; | ||
539 | return; | 538 | return; |
540 | } | ||
541 | 539 | ||
542 | spin_lock_bh(&sta->lock); | 540 | spin_lock_bh(&sta->lock); |
543 | if (sta->ignore_plink_timer) { | 541 | if (sta->ignore_plink_timer) { |
@@ -598,29 +596,6 @@ static void mesh_plink_timer(unsigned long data) | |||
598 | } | 596 | } |
599 | } | 597 | } |
600 | 598 | ||
601 | #ifdef CONFIG_PM | ||
602 | void mesh_plink_quiesce(struct sta_info *sta) | ||
603 | { | ||
604 | if (!ieee80211_vif_is_mesh(&sta->sdata->vif)) | ||
605 | return; | ||
606 | |||
607 | /* no kernel mesh sta timers have been initialized */ | ||
608 | if (sta->sdata->u.mesh.security != IEEE80211_MESH_SEC_NONE) | ||
609 | return; | ||
610 | |||
611 | if (del_timer_sync(&sta->plink_timer)) | ||
612 | sta->plink_timer_was_running = true; | ||
613 | } | ||
614 | |||
615 | void mesh_plink_restart(struct sta_info *sta) | ||
616 | { | ||
617 | if (sta->plink_timer_was_running) { | ||
618 | add_timer(&sta->plink_timer); | ||
619 | sta->plink_timer_was_running = false; | ||
620 | } | ||
621 | } | ||
622 | #endif | ||
623 | |||
624 | static inline void mesh_plink_timer_set(struct sta_info *sta, int timeout) | 599 | static inline void mesh_plink_timer_set(struct sta_info *sta, int timeout) |
625 | { | 600 | { |
626 | sta->plink_timer.expires = jiffies + (HZ * timeout / 1000); | 601 | sta->plink_timer.expires = jiffies + (HZ * timeout / 1000); |
@@ -695,6 +670,10 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, | |||
695 | if (len < IEEE80211_MIN_ACTION_SIZE + 3) | 670 | if (len < IEEE80211_MIN_ACTION_SIZE + 3) |
696 | return; | 671 | return; |
697 | 672 | ||
673 | if (sdata->u.mesh.user_mpm) | ||
674 | /* userspace must register for these */ | ||
675 | return; | ||
676 | |||
698 | if (is_multicast_ether_addr(mgmt->da)) { | 677 | if (is_multicast_ether_addr(mgmt->da)) { |
699 | mpl_dbg(sdata, | 678 | mpl_dbg(sdata, |
700 | "Mesh plink: ignore frame from multicast address\n"); | 679 | "Mesh plink: ignore frame from multicast address\n"); |
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 82cc30318a86..167158646593 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c | |||
@@ -87,9 +87,6 @@ MODULE_PARM_DESC(probe_wait_ms, | |||
87 | */ | 87 | */ |
88 | #define IEEE80211_SIGNAL_AVE_MIN_COUNT 4 | 88 | #define IEEE80211_SIGNAL_AVE_MIN_COUNT 4 |
89 | 89 | ||
90 | #define TMR_RUNNING_TIMER 0 | ||
91 | #define TMR_RUNNING_CHANSW 1 | ||
92 | |||
93 | /* | 90 | /* |
94 | * All cfg80211 functions have to be called outside a locked | 91 | * All cfg80211 functions have to be called outside a locked |
95 | * section so that they can acquire a lock themselves... This | 92 | * section so that they can acquire a lock themselves... This |
@@ -609,6 +606,7 @@ static void ieee80211_add_vht_ie(struct ieee80211_sub_if_data *sdata, | |||
609 | BUILD_BUG_ON(sizeof(vht_cap) != sizeof(sband->vht_cap)); | 606 | BUILD_BUG_ON(sizeof(vht_cap) != sizeof(sband->vht_cap)); |
610 | 607 | ||
611 | memcpy(&vht_cap, &sband->vht_cap, sizeof(vht_cap)); | 608 | memcpy(&vht_cap, &sband->vht_cap, sizeof(vht_cap)); |
609 | ieee80211_apply_vhtcap_overrides(sdata, &vht_cap); | ||
612 | 610 | ||
613 | /* determine capability flags */ | 611 | /* determine capability flags */ |
614 | cap = vht_cap.cap; | 612 | cap = vht_cap.cap; |
@@ -1038,14 +1036,8 @@ static void ieee80211_chswitch_timer(unsigned long data) | |||
1038 | { | 1036 | { |
1039 | struct ieee80211_sub_if_data *sdata = | 1037 | struct ieee80211_sub_if_data *sdata = |
1040 | (struct ieee80211_sub_if_data *) data; | 1038 | (struct ieee80211_sub_if_data *) data; |
1041 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | ||
1042 | 1039 | ||
1043 | if (sdata->local->quiescing) { | 1040 | ieee80211_queue_work(&sdata->local->hw, &sdata->u.mgd.chswitch_work); |
1044 | set_bit(TMR_RUNNING_CHANSW, &ifmgd->timers_running); | ||
1045 | return; | ||
1046 | } | ||
1047 | |||
1048 | ieee80211_queue_work(&sdata->local->hw, &ifmgd->chswitch_work); | ||
1049 | } | 1041 | } |
1050 | 1042 | ||
1051 | void | 1043 | void |
@@ -1802,9 +1794,11 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, | |||
1802 | sdata->vif.bss_conf.p2p_ctwindow = 0; | 1794 | sdata->vif.bss_conf.p2p_ctwindow = 0; |
1803 | sdata->vif.bss_conf.p2p_oppps = false; | 1795 | sdata->vif.bss_conf.p2p_oppps = false; |
1804 | 1796 | ||
1805 | /* on the next assoc, re-program HT parameters */ | 1797 | /* on the next assoc, re-program HT/VHT parameters */ |
1806 | memset(&ifmgd->ht_capa, 0, sizeof(ifmgd->ht_capa)); | 1798 | memset(&ifmgd->ht_capa, 0, sizeof(ifmgd->ht_capa)); |
1807 | memset(&ifmgd->ht_capa_mask, 0, sizeof(ifmgd->ht_capa_mask)); | 1799 | memset(&ifmgd->ht_capa_mask, 0, sizeof(ifmgd->ht_capa_mask)); |
1800 | memset(&ifmgd->vht_capa, 0, sizeof(ifmgd->vht_capa)); | ||
1801 | memset(&ifmgd->vht_capa_mask, 0, sizeof(ifmgd->vht_capa_mask)); | ||
1808 | 1802 | ||
1809 | sdata->ap_power_level = IEEE80211_UNSET_POWER_LEVEL; | 1803 | sdata->ap_power_level = IEEE80211_UNSET_POWER_LEVEL; |
1810 | 1804 | ||
@@ -1830,8 +1824,6 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, | |||
1830 | del_timer_sync(&sdata->u.mgd.timer); | 1824 | del_timer_sync(&sdata->u.mgd.timer); |
1831 | del_timer_sync(&sdata->u.mgd.chswitch_timer); | 1825 | del_timer_sync(&sdata->u.mgd.chswitch_timer); |
1832 | 1826 | ||
1833 | sdata->u.mgd.timers_running = 0; | ||
1834 | |||
1835 | sdata->vif.bss_conf.dtim_period = 0; | 1827 | sdata->vif.bss_conf.dtim_period = 0; |
1836 | 1828 | ||
1837 | ifmgd->flags = 0; | 1829 | ifmgd->flags = 0; |
@@ -3140,15 +3132,8 @@ static void ieee80211_sta_timer(unsigned long data) | |||
3140 | { | 3132 | { |
3141 | struct ieee80211_sub_if_data *sdata = | 3133 | struct ieee80211_sub_if_data *sdata = |
3142 | (struct ieee80211_sub_if_data *) data; | 3134 | (struct ieee80211_sub_if_data *) data; |
3143 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | ||
3144 | struct ieee80211_local *local = sdata->local; | ||
3145 | |||
3146 | if (local->quiescing) { | ||
3147 | set_bit(TMR_RUNNING_TIMER, &ifmgd->timers_running); | ||
3148 | return; | ||
3149 | } | ||
3150 | 3135 | ||
3151 | ieee80211_queue_work(&local->hw, &sdata->work); | 3136 | ieee80211_queue_work(&sdata->local->hw, &sdata->work); |
3152 | } | 3137 | } |
3153 | 3138 | ||
3154 | static void ieee80211_sta_connection_lost(struct ieee80211_sub_if_data *sdata, | 3139 | static void ieee80211_sta_connection_lost(struct ieee80211_sub_if_data *sdata, |
@@ -3500,72 +3485,6 @@ static void ieee80211_restart_sta_timer(struct ieee80211_sub_if_data *sdata) | |||
3500 | } | 3485 | } |
3501 | } | 3486 | } |
3502 | 3487 | ||
3503 | #ifdef CONFIG_PM | ||
3504 | void ieee80211_sta_quiesce(struct ieee80211_sub_if_data *sdata) | ||
3505 | { | ||
3506 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | ||
3507 | |||
3508 | /* | ||
3509 | * Stop timers before deleting work items, as timers | ||
3510 | * could race and re-add the work-items. They will be | ||
3511 | * re-established on connection. | ||
3512 | */ | ||
3513 | del_timer_sync(&ifmgd->conn_mon_timer); | ||
3514 | del_timer_sync(&ifmgd->bcn_mon_timer); | ||
3515 | |||
3516 | /* | ||
3517 | * we need to use atomic bitops for the running bits | ||
3518 | * only because both timers might fire at the same | ||
3519 | * time -- the code here is properly synchronised. | ||
3520 | */ | ||
3521 | |||
3522 | cancel_work_sync(&ifmgd->request_smps_work); | ||
3523 | |||
3524 | cancel_work_sync(&ifmgd->monitor_work); | ||
3525 | cancel_work_sync(&ifmgd->beacon_connection_loss_work); | ||
3526 | cancel_work_sync(&ifmgd->csa_connection_drop_work); | ||
3527 | if (del_timer_sync(&ifmgd->timer)) | ||
3528 | set_bit(TMR_RUNNING_TIMER, &ifmgd->timers_running); | ||
3529 | |||
3530 | if (del_timer_sync(&ifmgd->chswitch_timer)) | ||
3531 | set_bit(TMR_RUNNING_CHANSW, &ifmgd->timers_running); | ||
3532 | cancel_work_sync(&ifmgd->chswitch_work); | ||
3533 | } | ||
3534 | |||
3535 | void ieee80211_sta_restart(struct ieee80211_sub_if_data *sdata) | ||
3536 | { | ||
3537 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | ||
3538 | |||
3539 | mutex_lock(&ifmgd->mtx); | ||
3540 | if (!ifmgd->associated) { | ||
3541 | mutex_unlock(&ifmgd->mtx); | ||
3542 | return; | ||
3543 | } | ||
3544 | |||
3545 | if (sdata->flags & IEEE80211_SDATA_DISCONNECT_RESUME) { | ||
3546 | sdata->flags &= ~IEEE80211_SDATA_DISCONNECT_RESUME; | ||
3547 | mlme_dbg(sdata, "driver requested disconnect after resume\n"); | ||
3548 | ieee80211_sta_connection_lost(sdata, | ||
3549 | ifmgd->associated->bssid, | ||
3550 | WLAN_REASON_UNSPECIFIED, | ||
3551 | true); | ||
3552 | mutex_unlock(&ifmgd->mtx); | ||
3553 | return; | ||
3554 | } | ||
3555 | mutex_unlock(&ifmgd->mtx); | ||
3556 | |||
3557 | if (test_and_clear_bit(TMR_RUNNING_TIMER, &ifmgd->timers_running)) | ||
3558 | add_timer(&ifmgd->timer); | ||
3559 | if (test_and_clear_bit(TMR_RUNNING_CHANSW, &ifmgd->timers_running)) | ||
3560 | add_timer(&ifmgd->chswitch_timer); | ||
3561 | ieee80211_sta_reset_beacon_monitor(sdata); | ||
3562 | |||
3563 | mutex_lock(&sdata->local->mtx); | ||
3564 | ieee80211_restart_sta_timer(sdata); | ||
3565 | mutex_unlock(&sdata->local->mtx); | ||
3566 | } | ||
3567 | #endif | ||
3568 | |||
3569 | /* interface setup */ | 3488 | /* interface setup */ |
3570 | void ieee80211_sta_setup_sdata(struct ieee80211_sub_if_data *sdata) | 3489 | void ieee80211_sta_setup_sdata(struct ieee80211_sub_if_data *sdata) |
3571 | { | 3490 | { |
@@ -4073,6 +3992,9 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, | |||
4073 | ifmgd->flags |= IEEE80211_STA_DISABLE_VHT; | 3992 | ifmgd->flags |= IEEE80211_STA_DISABLE_VHT; |
4074 | } | 3993 | } |
4075 | 3994 | ||
3995 | if (req->flags & ASSOC_REQ_DISABLE_VHT) | ||
3996 | ifmgd->flags |= IEEE80211_STA_DISABLE_VHT; | ||
3997 | |||
4076 | /* Also disable HT if we don't support it or the AP doesn't use WMM */ | 3998 | /* Also disable HT if we don't support it or the AP doesn't use WMM */ |
4077 | sband = local->hw.wiphy->bands[req->bss->channel->band]; | 3999 | sband = local->hw.wiphy->bands[req->bss->channel->band]; |
4078 | if (!sband->ht_cap.ht_supported || | 4000 | if (!sband->ht_cap.ht_supported || |
@@ -4096,6 +4018,10 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, | |||
4096 | memcpy(&ifmgd->ht_capa_mask, &req->ht_capa_mask, | 4018 | memcpy(&ifmgd->ht_capa_mask, &req->ht_capa_mask, |
4097 | sizeof(ifmgd->ht_capa_mask)); | 4019 | sizeof(ifmgd->ht_capa_mask)); |
4098 | 4020 | ||
4021 | memcpy(&ifmgd->vht_capa, &req->vht_capa, sizeof(ifmgd->vht_capa)); | ||
4022 | memcpy(&ifmgd->vht_capa_mask, &req->vht_capa_mask, | ||
4023 | sizeof(ifmgd->vht_capa_mask)); | ||
4024 | |||
4099 | if (req->ie && req->ie_len) { | 4025 | if (req->ie && req->ie_len) { |
4100 | memcpy(assoc_data->ie, req->ie, req->ie_len); | 4026 | memcpy(assoc_data->ie, req->ie, req->ie_len); |
4101 | assoc_data->ie_len = req->ie_len; | 4027 | assoc_data->ie_len = req->ie_len; |
diff --git a/net/mac80211/offchannel.c b/net/mac80211/offchannel.c index cc79b4a2e821..db547fceaeb9 100644 --- a/net/mac80211/offchannel.c +++ b/net/mac80211/offchannel.c | |||
@@ -277,7 +277,7 @@ void ieee80211_start_next_roc(struct ieee80211_local *local) | |||
277 | duration = 10; | 277 | duration = 10; |
278 | 278 | ||
279 | ret = drv_remain_on_channel(local, roc->sdata, roc->chan, | 279 | ret = drv_remain_on_channel(local, roc->sdata, roc->chan, |
280 | duration); | 280 | duration, roc->type); |
281 | 281 | ||
282 | roc->started = true; | 282 | roc->started = true; |
283 | 283 | ||
diff --git a/net/mac80211/pm.c b/net/mac80211/pm.c index d0275f34bf70..b471a67f224d 100644 --- a/net/mac80211/pm.c +++ b/net/mac80211/pm.c | |||
@@ -6,32 +6,11 @@ | |||
6 | #include "driver-ops.h" | 6 | #include "driver-ops.h" |
7 | #include "led.h" | 7 | #include "led.h" |
8 | 8 | ||
9 | /* return value indicates whether the driver should be further notified */ | ||
10 | static void ieee80211_quiesce(struct ieee80211_sub_if_data *sdata) | ||
11 | { | ||
12 | switch (sdata->vif.type) { | ||
13 | case NL80211_IFTYPE_STATION: | ||
14 | ieee80211_sta_quiesce(sdata); | ||
15 | break; | ||
16 | case NL80211_IFTYPE_ADHOC: | ||
17 | ieee80211_ibss_quiesce(sdata); | ||
18 | break; | ||
19 | case NL80211_IFTYPE_MESH_POINT: | ||
20 | ieee80211_mesh_quiesce(sdata); | ||
21 | break; | ||
22 | default: | ||
23 | break; | ||
24 | } | ||
25 | |||
26 | cancel_work_sync(&sdata->work); | ||
27 | } | ||
28 | |||
29 | int __ieee80211_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan) | 9 | int __ieee80211_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan) |
30 | { | 10 | { |
31 | struct ieee80211_local *local = hw_to_local(hw); | 11 | struct ieee80211_local *local = hw_to_local(hw); |
32 | struct ieee80211_sub_if_data *sdata; | 12 | struct ieee80211_sub_if_data *sdata; |
33 | struct sta_info *sta; | 13 | struct sta_info *sta; |
34 | struct ieee80211_chanctx *ctx; | ||
35 | 14 | ||
36 | if (!local->open_count) | 15 | if (!local->open_count) |
37 | goto suspend; | 16 | goto suspend; |
@@ -93,19 +72,12 @@ int __ieee80211_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan) | |||
93 | return err; | 72 | return err; |
94 | } else if (err > 0) { | 73 | } else if (err > 0) { |
95 | WARN_ON(err != 1); | 74 | WARN_ON(err != 1); |
96 | local->wowlan = false; | 75 | return err; |
97 | } else { | 76 | } else { |
98 | list_for_each_entry(sdata, &local->interfaces, list) | ||
99 | if (ieee80211_sdata_running(sdata)) | ||
100 | ieee80211_quiesce(sdata); | ||
101 | goto suspend; | 77 | goto suspend; |
102 | } | 78 | } |
103 | } | 79 | } |
104 | 80 | ||
105 | /* disable keys */ | ||
106 | list_for_each_entry(sdata, &local->interfaces, list) | ||
107 | ieee80211_disable_keys(sdata); | ||
108 | |||
109 | /* tear down aggregation sessions and remove STAs */ | 81 | /* tear down aggregation sessions and remove STAs */ |
110 | mutex_lock(&local->sta_mtx); | 82 | mutex_lock(&local->sta_mtx); |
111 | list_for_each_entry(sta, &local->sta_list, list) { | 83 | list_for_each_entry(sta, &local->sta_list, list) { |
@@ -117,100 +89,25 @@ int __ieee80211_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan) | |||
117 | WARN_ON(drv_sta_state(local, sta->sdata, sta, | 89 | WARN_ON(drv_sta_state(local, sta->sdata, sta, |
118 | state, state - 1)); | 90 | state, state - 1)); |
119 | } | 91 | } |
120 | |||
121 | mesh_plink_quiesce(sta); | ||
122 | } | 92 | } |
123 | mutex_unlock(&local->sta_mtx); | 93 | mutex_unlock(&local->sta_mtx); |
124 | 94 | ||
125 | /* remove all interfaces */ | 95 | /* remove all interfaces */ |
126 | list_for_each_entry(sdata, &local->interfaces, list) { | 96 | list_for_each_entry(sdata, &local->interfaces, list) { |
127 | static u8 zero_addr[ETH_ALEN] = {}; | ||
128 | u32 changed = 0; | ||
129 | |||
130 | if (!ieee80211_sdata_running(sdata)) | 97 | if (!ieee80211_sdata_running(sdata)) |
131 | continue; | 98 | continue; |
132 | |||
133 | switch (sdata->vif.type) { | ||
134 | case NL80211_IFTYPE_AP_VLAN: | ||
135 | case NL80211_IFTYPE_MONITOR: | ||
136 | /* skip these */ | ||
137 | continue; | ||
138 | case NL80211_IFTYPE_STATION: | ||
139 | if (sdata->vif.bss_conf.assoc) | ||
140 | changed = BSS_CHANGED_ASSOC | | ||
141 | BSS_CHANGED_BSSID | | ||
142 | BSS_CHANGED_IDLE; | ||
143 | break; | ||
144 | case NL80211_IFTYPE_AP: | ||
145 | case NL80211_IFTYPE_ADHOC: | ||
146 | case NL80211_IFTYPE_MESH_POINT: | ||
147 | if (sdata->vif.bss_conf.enable_beacon) | ||
148 | changed = BSS_CHANGED_BEACON_ENABLED; | ||
149 | break; | ||
150 | default: | ||
151 | break; | ||
152 | } | ||
153 | |||
154 | ieee80211_quiesce(sdata); | ||
155 | |||
156 | sdata->suspend_bss_conf = sdata->vif.bss_conf; | ||
157 | memset(&sdata->vif.bss_conf, 0, sizeof(sdata->vif.bss_conf)); | ||
158 | sdata->vif.bss_conf.idle = true; | ||
159 | if (sdata->suspend_bss_conf.bssid) | ||
160 | sdata->vif.bss_conf.bssid = zero_addr; | ||
161 | |||
162 | /* disable beaconing or remove association */ | ||
163 | ieee80211_bss_info_change_notify(sdata, changed); | ||
164 | |||
165 | if (sdata->vif.type == NL80211_IFTYPE_AP && | ||
166 | rcu_access_pointer(sdata->u.ap.beacon)) | ||
167 | drv_stop_ap(local, sdata); | ||
168 | |||
169 | if (local->use_chanctx) { | ||
170 | struct ieee80211_chanctx_conf *conf; | ||
171 | |||
172 | mutex_lock(&local->chanctx_mtx); | ||
173 | conf = rcu_dereference_protected( | ||
174 | sdata->vif.chanctx_conf, | ||
175 | lockdep_is_held(&local->chanctx_mtx)); | ||
176 | if (conf) { | ||
177 | ctx = container_of(conf, | ||
178 | struct ieee80211_chanctx, | ||
179 | conf); | ||
180 | drv_unassign_vif_chanctx(local, sdata, ctx); | ||
181 | } | ||
182 | |||
183 | mutex_unlock(&local->chanctx_mtx); | ||
184 | } | ||
185 | drv_remove_interface(local, sdata); | 99 | drv_remove_interface(local, sdata); |
186 | } | 100 | } |
187 | 101 | ||
188 | sdata = rtnl_dereference(local->monitor_sdata); | 102 | sdata = rtnl_dereference(local->monitor_sdata); |
189 | if (sdata) { | 103 | if (sdata) |
190 | if (local->use_chanctx) { | ||
191 | struct ieee80211_chanctx_conf *conf; | ||
192 | |||
193 | mutex_lock(&local->chanctx_mtx); | ||
194 | conf = rcu_dereference_protected( | ||
195 | sdata->vif.chanctx_conf, | ||
196 | lockdep_is_held(&local->chanctx_mtx)); | ||
197 | if (conf) { | ||
198 | ctx = container_of(conf, | ||
199 | struct ieee80211_chanctx, | ||
200 | conf); | ||
201 | drv_unassign_vif_chanctx(local, sdata, ctx); | ||
202 | } | ||
203 | |||
204 | mutex_unlock(&local->chanctx_mtx); | ||
205 | } | ||
206 | |||
207 | drv_remove_interface(local, sdata); | 104 | drv_remove_interface(local, sdata); |
208 | } | ||
209 | 105 | ||
210 | mutex_lock(&local->chanctx_mtx); | 106 | /* |
211 | list_for_each_entry(ctx, &local->chanctx_list, list) | 107 | * We disconnected on all interfaces before suspend, all channel |
212 | drv_remove_chanctx(local, ctx); | 108 | * contexts should be released. |
213 | mutex_unlock(&local->chanctx_mtx); | 109 | */ |
110 | WARN_ON(!list_empty(&local->chanctx_list)); | ||
214 | 111 | ||
215 | /* stop hardware - this must stop RX */ | 112 | /* stop hardware - this must stop RX */ |
216 | if (local->open_count) | 113 | if (local->open_count) |
diff --git a/net/mac80211/rc80211_minstrel.c b/net/mac80211/rc80211_minstrel.c index eea45a2c7c35..1c36c9b4fa4a 100644 --- a/net/mac80211/rc80211_minstrel.c +++ b/net/mac80211/rc80211_minstrel.c | |||
@@ -55,7 +55,6 @@ | |||
55 | #include "rate.h" | 55 | #include "rate.h" |
56 | #include "rc80211_minstrel.h" | 56 | #include "rc80211_minstrel.h" |
57 | 57 | ||
58 | #define SAMPLE_COLUMNS 10 | ||
59 | #define SAMPLE_TBL(_mi, _idx, _col) \ | 58 | #define SAMPLE_TBL(_mi, _idx, _col) \ |
60 | _mi->sample_table[(_idx * SAMPLE_COLUMNS) + _col] | 59 | _mi->sample_table[(_idx * SAMPLE_COLUMNS) + _col] |
61 | 60 | ||
@@ -70,16 +69,31 @@ rix_to_ndx(struct minstrel_sta_info *mi, int rix) | |||
70 | return i; | 69 | return i; |
71 | } | 70 | } |
72 | 71 | ||
72 | /* find & sort topmost throughput rates */ | ||
73 | static inline void | ||
74 | minstrel_sort_best_tp_rates(struct minstrel_sta_info *mi, int i, u8 *tp_list) | ||
75 | { | ||
76 | int j = MAX_THR_RATES; | ||
77 | |||
78 | while (j > 0 && mi->r[i].cur_tp > mi->r[tp_list[j - 1]].cur_tp) | ||
79 | j--; | ||
80 | if (j < MAX_THR_RATES - 1) | ||
81 | memmove(&tp_list[j + 1], &tp_list[j], MAX_THR_RATES - (j + 1)); | ||
82 | if (j < MAX_THR_RATES) | ||
83 | tp_list[j] = i; | ||
84 | } | ||
85 | |||
73 | static void | 86 | static void |
74 | minstrel_update_stats(struct minstrel_priv *mp, struct minstrel_sta_info *mi) | 87 | minstrel_update_stats(struct minstrel_priv *mp, struct minstrel_sta_info *mi) |
75 | { | 88 | { |
76 | u32 max_tp = 0, index_max_tp = 0, index_max_tp2 = 0; | 89 | u8 tmp_tp_rate[MAX_THR_RATES]; |
77 | u32 max_prob = 0, index_max_prob = 0; | 90 | u8 tmp_prob_rate = 0; |
78 | u32 usecs; | 91 | u32 usecs; |
79 | u32 p; | ||
80 | int i; | 92 | int i; |
81 | 93 | ||
82 | mi->stats_update = jiffies; | 94 | for (i=0; i < MAX_THR_RATES; i++) |
95 | tmp_tp_rate[i] = 0; | ||
96 | |||
83 | for (i = 0; i < mi->n_rates; i++) { | 97 | for (i = 0; i < mi->n_rates; i++) { |
84 | struct minstrel_rate *mr = &mi->r[i]; | 98 | struct minstrel_rate *mr = &mi->r[i]; |
85 | 99 | ||
@@ -87,27 +101,32 @@ minstrel_update_stats(struct minstrel_priv *mp, struct minstrel_sta_info *mi) | |||
87 | if (!usecs) | 101 | if (!usecs) |
88 | usecs = 1000000; | 102 | usecs = 1000000; |
89 | 103 | ||
90 | /* To avoid rounding issues, probabilities scale from 0 (0%) | 104 | if (unlikely(mr->attempts > 0)) { |
91 | * to 18000 (100%) */ | 105 | mr->sample_skipped = 0; |
92 | if (mr->attempts) { | 106 | mr->cur_prob = MINSTREL_FRAC(mr->success, mr->attempts); |
93 | p = (mr->success * 18000) / mr->attempts; | ||
94 | mr->succ_hist += mr->success; | 107 | mr->succ_hist += mr->success; |
95 | mr->att_hist += mr->attempts; | 108 | mr->att_hist += mr->attempts; |
96 | mr->cur_prob = p; | 109 | mr->probability = minstrel_ewma(mr->probability, |
97 | p = ((p * (100 - mp->ewma_level)) + (mr->probability * | 110 | mr->cur_prob, |
98 | mp->ewma_level)) / 100; | 111 | EWMA_LEVEL); |
99 | mr->probability = p; | 112 | } else |
100 | mr->cur_tp = p * (1000000 / usecs); | 113 | mr->sample_skipped++; |
101 | } | ||
102 | 114 | ||
103 | mr->last_success = mr->success; | 115 | mr->last_success = mr->success; |
104 | mr->last_attempts = mr->attempts; | 116 | mr->last_attempts = mr->attempts; |
105 | mr->success = 0; | 117 | mr->success = 0; |
106 | mr->attempts = 0; | 118 | mr->attempts = 0; |
107 | 119 | ||
120 | /* Update throughput per rate, reset thr. below 10% success */ | ||
121 | if (mr->probability < MINSTREL_FRAC(10, 100)) | ||
122 | mr->cur_tp = 0; | ||
123 | else | ||
124 | mr->cur_tp = mr->probability * (1000000 / usecs); | ||
125 | |||
108 | /* Sample less often below the 10% chance of success. | 126 | /* Sample less often below the 10% chance of success. |
109 | * Sample less often above the 95% chance of success. */ | 127 | * Sample less often above the 95% chance of success. */ |
110 | if ((mr->probability > 17100) || (mr->probability < 1800)) { | 128 | if (mr->probability > MINSTREL_FRAC(95, 100) || |
129 | mr->probability < MINSTREL_FRAC(10, 100)) { | ||
111 | mr->adjusted_retry_count = mr->retry_count >> 1; | 130 | mr->adjusted_retry_count = mr->retry_count >> 1; |
112 | if (mr->adjusted_retry_count > 2) | 131 | if (mr->adjusted_retry_count > 2) |
113 | mr->adjusted_retry_count = 2; | 132 | mr->adjusted_retry_count = 2; |
@@ -118,35 +137,30 @@ minstrel_update_stats(struct minstrel_priv *mp, struct minstrel_sta_info *mi) | |||
118 | } | 137 | } |
119 | if (!mr->adjusted_retry_count) | 138 | if (!mr->adjusted_retry_count) |
120 | mr->adjusted_retry_count = 2; | 139 | mr->adjusted_retry_count = 2; |
121 | } | ||
122 | 140 | ||
123 | for (i = 0; i < mi->n_rates; i++) { | 141 | minstrel_sort_best_tp_rates(mi, i, tmp_tp_rate); |
124 | struct minstrel_rate *mr = &mi->r[i]; | 142 | |
125 | if (max_tp < mr->cur_tp) { | 143 | /* To determine the most robust rate (max_prob_rate) used at |
126 | index_max_tp = i; | 144 | * 3rd mmr stage we distinct between two cases: |
127 | max_tp = mr->cur_tp; | 145 | * (1) if any success probabilitiy >= 95%, out of those rates |
128 | } | 146 | * choose the maximum throughput rate as max_prob_rate |
129 | if (max_prob < mr->probability) { | 147 | * (2) if all success probabilities < 95%, the rate with |
130 | index_max_prob = i; | 148 | * highest success probability is choosen as max_prob_rate */ |
131 | max_prob = mr->probability; | 149 | if (mr->probability >= MINSTREL_FRAC(95,100)) { |
150 | if (mr->cur_tp >= mi->r[tmp_prob_rate].cur_tp) | ||
151 | tmp_prob_rate = i; | ||
152 | } else { | ||
153 | if (mr->probability >= mi->r[tmp_prob_rate].probability) | ||
154 | tmp_prob_rate = i; | ||
132 | } | 155 | } |
133 | } | 156 | } |
134 | 157 | ||
135 | max_tp = 0; | 158 | /* Assign the new rate set */ |
136 | for (i = 0; i < mi->n_rates; i++) { | 159 | memcpy(mi->max_tp_rate, tmp_tp_rate, sizeof(mi->max_tp_rate)); |
137 | struct minstrel_rate *mr = &mi->r[i]; | 160 | mi->max_prob_rate = tmp_prob_rate; |
138 | |||
139 | if (i == index_max_tp) | ||
140 | continue; | ||
141 | 161 | ||
142 | if (max_tp < mr->cur_tp) { | 162 | /* Reset update timer */ |
143 | index_max_tp2 = i; | 163 | mi->stats_update = jiffies; |
144 | max_tp = mr->cur_tp; | ||
145 | } | ||
146 | } | ||
147 | mi->max_tp_rate = index_max_tp; | ||
148 | mi->max_tp_rate2 = index_max_tp2; | ||
149 | mi->max_prob_rate = index_max_prob; | ||
150 | } | 164 | } |
151 | 165 | ||
152 | static void | 166 | static void |
@@ -207,10 +221,10 @@ static int | |||
207 | minstrel_get_next_sample(struct minstrel_sta_info *mi) | 221 | minstrel_get_next_sample(struct minstrel_sta_info *mi) |
208 | { | 222 | { |
209 | unsigned int sample_ndx; | 223 | unsigned int sample_ndx; |
210 | sample_ndx = SAMPLE_TBL(mi, mi->sample_idx, mi->sample_column); | 224 | sample_ndx = SAMPLE_TBL(mi, mi->sample_row, mi->sample_column); |
211 | mi->sample_idx++; | 225 | mi->sample_row++; |
212 | if ((int) mi->sample_idx > (mi->n_rates - 2)) { | 226 | if ((int) mi->sample_row >= mi->n_rates) { |
213 | mi->sample_idx = 0; | 227 | mi->sample_row = 0; |
214 | mi->sample_column++; | 228 | mi->sample_column++; |
215 | if (mi->sample_column >= SAMPLE_COLUMNS) | 229 | if (mi->sample_column >= SAMPLE_COLUMNS) |
216 | mi->sample_column = 0; | 230 | mi->sample_column = 0; |
@@ -228,31 +242,37 @@ minstrel_get_rate(void *priv, struct ieee80211_sta *sta, | |||
228 | struct minstrel_priv *mp = priv; | 242 | struct minstrel_priv *mp = priv; |
229 | struct ieee80211_tx_rate *ar = info->control.rates; | 243 | struct ieee80211_tx_rate *ar = info->control.rates; |
230 | unsigned int ndx, sample_ndx = 0; | 244 | unsigned int ndx, sample_ndx = 0; |
231 | bool mrr; | 245 | bool mrr_capable; |
232 | bool sample_slower = false; | 246 | bool indirect_rate_sampling = false; |
233 | bool sample = false; | 247 | bool rate_sampling = false; |
234 | int i, delta; | 248 | int i, delta; |
235 | int mrr_ndx[3]; | 249 | int mrr_ndx[3]; |
236 | int sample_rate; | 250 | int sampling_ratio; |
237 | 251 | ||
252 | /* management/no-ack frames do not use rate control */ | ||
238 | if (rate_control_send_low(sta, priv_sta, txrc)) | 253 | if (rate_control_send_low(sta, priv_sta, txrc)) |
239 | return; | 254 | return; |
240 | 255 | ||
241 | mrr = mp->has_mrr && !txrc->rts && !txrc->bss_conf->use_cts_prot; | 256 | /* check multi-rate-retry capabilities & adjust lookaround_rate */ |
242 | 257 | mrr_capable = mp->has_mrr && | |
243 | ndx = mi->max_tp_rate; | 258 | !txrc->rts && |
244 | 259 | !txrc->bss_conf->use_cts_prot; | |
245 | if (mrr) | 260 | if (mrr_capable) |
246 | sample_rate = mp->lookaround_rate_mrr; | 261 | sampling_ratio = mp->lookaround_rate_mrr; |
247 | else | 262 | else |
248 | sample_rate = mp->lookaround_rate; | 263 | sampling_ratio = mp->lookaround_rate; |
264 | |||
265 | /* init rateindex [ndx] with max throughput rate */ | ||
266 | ndx = mi->max_tp_rate[0]; | ||
249 | 267 | ||
268 | /* increase sum packet counter */ | ||
250 | mi->packet_count++; | 269 | mi->packet_count++; |
251 | delta = (mi->packet_count * sample_rate / 100) - | 270 | |
271 | delta = (mi->packet_count * sampling_ratio / 100) - | ||
252 | (mi->sample_count + mi->sample_deferred / 2); | 272 | (mi->sample_count + mi->sample_deferred / 2); |
253 | 273 | ||
254 | /* delta > 0: sampling required */ | 274 | /* delta > 0: sampling required */ |
255 | if ((delta > 0) && (mrr || !mi->prev_sample)) { | 275 | if ((delta > 0) && (mrr_capable || !mi->prev_sample)) { |
256 | struct minstrel_rate *msr; | 276 | struct minstrel_rate *msr; |
257 | if (mi->packet_count >= 10000) { | 277 | if (mi->packet_count >= 10000) { |
258 | mi->sample_deferred = 0; | 278 | mi->sample_deferred = 0; |
@@ -271,21 +291,28 @@ minstrel_get_rate(void *priv, struct ieee80211_sta *sta, | |||
271 | mi->sample_count += (delta - mi->n_rates * 2); | 291 | mi->sample_count += (delta - mi->n_rates * 2); |
272 | } | 292 | } |
273 | 293 | ||
294 | /* get next random rate sample */ | ||
274 | sample_ndx = minstrel_get_next_sample(mi); | 295 | sample_ndx = minstrel_get_next_sample(mi); |
275 | msr = &mi->r[sample_ndx]; | 296 | msr = &mi->r[sample_ndx]; |
276 | sample = true; | 297 | rate_sampling = true; |
277 | sample_slower = mrr && (msr->perfect_tx_time > | 298 | |
278 | mi->r[ndx].perfect_tx_time); | 299 | /* Decide if direct ( 1st mrr stage) or indirect (2nd mrr stage) |
279 | 300 | * rate sampling method should be used. | |
280 | if (!sample_slower) { | 301 | * Respect such rates that are not sampled for 20 interations. |
302 | */ | ||
303 | if (mrr_capable && | ||
304 | msr->perfect_tx_time > mi->r[ndx].perfect_tx_time && | ||
305 | msr->sample_skipped < 20) | ||
306 | indirect_rate_sampling = true; | ||
307 | |||
308 | if (!indirect_rate_sampling) { | ||
281 | if (msr->sample_limit != 0) { | 309 | if (msr->sample_limit != 0) { |
282 | ndx = sample_ndx; | 310 | ndx = sample_ndx; |
283 | mi->sample_count++; | 311 | mi->sample_count++; |
284 | if (msr->sample_limit > 0) | 312 | if (msr->sample_limit > 0) |
285 | msr->sample_limit--; | 313 | msr->sample_limit--; |
286 | } else { | 314 | } else |
287 | sample = false; | 315 | rate_sampling = false; |
288 | } | ||
289 | } else { | 316 | } else { |
290 | /* Only use IEEE80211_TX_CTL_RATE_CTRL_PROBE to mark | 317 | /* Only use IEEE80211_TX_CTL_RATE_CTRL_PROBE to mark |
291 | * packets that have the sampling rate deferred to the | 318 | * packets that have the sampling rate deferred to the |
@@ -297,34 +324,39 @@ minstrel_get_rate(void *priv, struct ieee80211_sta *sta, | |||
297 | mi->sample_deferred++; | 324 | mi->sample_deferred++; |
298 | } | 325 | } |
299 | } | 326 | } |
300 | mi->prev_sample = sample; | 327 | mi->prev_sample = rate_sampling; |
301 | 328 | ||
302 | /* If we're not using MRR and the sampling rate already | 329 | /* If we're not using MRR and the sampling rate already |
303 | * has a probability of >95%, we shouldn't be attempting | 330 | * has a probability of >95%, we shouldn't be attempting |
304 | * to use it, as this only wastes precious airtime */ | 331 | * to use it, as this only wastes precious airtime */ |
305 | if (!mrr && sample && (mi->r[ndx].probability > 17100)) | 332 | if (!mrr_capable && rate_sampling && |
306 | ndx = mi->max_tp_rate; | 333 | (mi->r[ndx].probability > MINSTREL_FRAC(95, 100))) |
334 | ndx = mi->max_tp_rate[0]; | ||
307 | 335 | ||
336 | /* mrr setup for 1st stage */ | ||
308 | ar[0].idx = mi->r[ndx].rix; | 337 | ar[0].idx = mi->r[ndx].rix; |
309 | ar[0].count = minstrel_get_retry_count(&mi->r[ndx], info); | 338 | ar[0].count = minstrel_get_retry_count(&mi->r[ndx], info); |
310 | 339 | ||
311 | if (!mrr) { | 340 | /* non mrr setup for 2nd stage */ |
312 | if (!sample) | 341 | if (!mrr_capable) { |
342 | if (!rate_sampling) | ||
313 | ar[0].count = mp->max_retry; | 343 | ar[0].count = mp->max_retry; |
314 | ar[1].idx = mi->lowest_rix; | 344 | ar[1].idx = mi->lowest_rix; |
315 | ar[1].count = mp->max_retry; | 345 | ar[1].count = mp->max_retry; |
316 | return; | 346 | return; |
317 | } | 347 | } |
318 | 348 | ||
319 | /* MRR setup */ | 349 | /* mrr setup for 2nd stage */ |
320 | if (sample) { | 350 | if (rate_sampling) { |
321 | if (sample_slower) | 351 | if (indirect_rate_sampling) |
322 | mrr_ndx[0] = sample_ndx; | 352 | mrr_ndx[0] = sample_ndx; |
323 | else | 353 | else |
324 | mrr_ndx[0] = mi->max_tp_rate; | 354 | mrr_ndx[0] = mi->max_tp_rate[0]; |
325 | } else { | 355 | } else { |
326 | mrr_ndx[0] = mi->max_tp_rate2; | 356 | mrr_ndx[0] = mi->max_tp_rate[1]; |
327 | } | 357 | } |
358 | |||
359 | /* mrr setup for 3rd & 4th stage */ | ||
328 | mrr_ndx[1] = mi->max_prob_rate; | 360 | mrr_ndx[1] = mi->max_prob_rate; |
329 | mrr_ndx[2] = 0; | 361 | mrr_ndx[2] = 0; |
330 | for (i = 1; i < 4; i++) { | 362 | for (i = 1; i < 4; i++) { |
@@ -351,26 +383,21 @@ static void | |||
351 | init_sample_table(struct minstrel_sta_info *mi) | 383 | init_sample_table(struct minstrel_sta_info *mi) |
352 | { | 384 | { |
353 | unsigned int i, col, new_idx; | 385 | unsigned int i, col, new_idx; |
354 | unsigned int n_srates = mi->n_rates - 1; | ||
355 | u8 rnd[8]; | 386 | u8 rnd[8]; |
356 | 387 | ||
357 | mi->sample_column = 0; | 388 | mi->sample_column = 0; |
358 | mi->sample_idx = 0; | 389 | mi->sample_row = 0; |
359 | memset(mi->sample_table, 0, SAMPLE_COLUMNS * mi->n_rates); | 390 | memset(mi->sample_table, 0xff, SAMPLE_COLUMNS * mi->n_rates); |
360 | 391 | ||
361 | for (col = 0; col < SAMPLE_COLUMNS; col++) { | 392 | for (col = 0; col < SAMPLE_COLUMNS; col++) { |
362 | for (i = 0; i < n_srates; i++) { | 393 | for (i = 0; i < mi->n_rates; i++) { |
363 | get_random_bytes(rnd, sizeof(rnd)); | 394 | get_random_bytes(rnd, sizeof(rnd)); |
364 | new_idx = (i + rnd[i & 7]) % n_srates; | 395 | new_idx = (i + rnd[i & 7]) % mi->n_rates; |
365 | 396 | ||
366 | while (SAMPLE_TBL(mi, new_idx, col) != 0) | 397 | while (SAMPLE_TBL(mi, new_idx, col) != 0xff) |
367 | new_idx = (new_idx + 1) % n_srates; | 398 | new_idx = (new_idx + 1) % mi->n_rates; |
368 | 399 | ||
369 | /* Don't sample the slowest rate (i.e. slowest base | 400 | SAMPLE_TBL(mi, new_idx, col) = i; |
370 | * rate). We must presume that the slowest rate works | ||
371 | * fine, or else other management frames will also be | ||
372 | * failing and the link will break */ | ||
373 | SAMPLE_TBL(mi, new_idx, col) = i + 1; | ||
374 | } | 401 | } |
375 | } | 402 | } |
376 | } | 403 | } |
@@ -542,9 +569,6 @@ minstrel_alloc(struct ieee80211_hw *hw, struct dentry *debugfsdir) | |||
542 | mp->lookaround_rate = 5; | 569 | mp->lookaround_rate = 5; |
543 | mp->lookaround_rate_mrr = 10; | 570 | mp->lookaround_rate_mrr = 10; |
544 | 571 | ||
545 | /* moving average weight for EWMA */ | ||
546 | mp->ewma_level = 75; | ||
547 | |||
548 | /* maximum time that the hw is allowed to stay in one MRR segment */ | 572 | /* maximum time that the hw is allowed to stay in one MRR segment */ |
549 | mp->segment_size = 6000; | 573 | mp->segment_size = 6000; |
550 | 574 | ||
diff --git a/net/mac80211/rc80211_minstrel.h b/net/mac80211/rc80211_minstrel.h index 5ecf757817f2..85ebf42cb46d 100644 --- a/net/mac80211/rc80211_minstrel.h +++ b/net/mac80211/rc80211_minstrel.h | |||
@@ -9,6 +9,28 @@ | |||
9 | #ifndef __RC_MINSTREL_H | 9 | #ifndef __RC_MINSTREL_H |
10 | #define __RC_MINSTREL_H | 10 | #define __RC_MINSTREL_H |
11 | 11 | ||
12 | #define EWMA_LEVEL 75 /* ewma weighting factor [%] */ | ||
13 | #define SAMPLE_COLUMNS 10 /* number of columns in sample table */ | ||
14 | |||
15 | |||
16 | /* scaled fraction values */ | ||
17 | #define MINSTREL_SCALE 16 | ||
18 | #define MINSTREL_FRAC(val, div) (((val) << MINSTREL_SCALE) / div) | ||
19 | #define MINSTREL_TRUNC(val) ((val) >> MINSTREL_SCALE) | ||
20 | |||
21 | /* number of highest throughput rates to consider*/ | ||
22 | #define MAX_THR_RATES 4 | ||
23 | |||
24 | /* | ||
25 | * Perform EWMA (Exponentially Weighted Moving Average) calculation | ||
26 | */ | ||
27 | static inline int | ||
28 | minstrel_ewma(int old, int new, int weight) | ||
29 | { | ||
30 | return (new * (100 - weight) + old * weight) / 100; | ||
31 | } | ||
32 | |||
33 | |||
12 | struct minstrel_rate { | 34 | struct minstrel_rate { |
13 | int bitrate; | 35 | int bitrate; |
14 | int rix; | 36 | int rix; |
@@ -26,6 +48,7 @@ struct minstrel_rate { | |||
26 | u32 attempts; | 48 | u32 attempts; |
27 | u32 last_attempts; | 49 | u32 last_attempts; |
28 | u32 last_success; | 50 | u32 last_success; |
51 | u8 sample_skipped; | ||
29 | 52 | ||
30 | /* parts per thousand */ | 53 | /* parts per thousand */ |
31 | u32 cur_prob; | 54 | u32 cur_prob; |
@@ -45,14 +68,13 @@ struct minstrel_sta_info { | |||
45 | 68 | ||
46 | unsigned int lowest_rix; | 69 | unsigned int lowest_rix; |
47 | 70 | ||
48 | unsigned int max_tp_rate; | 71 | u8 max_tp_rate[MAX_THR_RATES]; |
49 | unsigned int max_tp_rate2; | 72 | u8 max_prob_rate; |
50 | unsigned int max_prob_rate; | ||
51 | unsigned int packet_count; | 73 | unsigned int packet_count; |
52 | unsigned int sample_count; | 74 | unsigned int sample_count; |
53 | int sample_deferred; | 75 | int sample_deferred; |
54 | 76 | ||
55 | unsigned int sample_idx; | 77 | unsigned int sample_row; |
56 | unsigned int sample_column; | 78 | unsigned int sample_column; |
57 | 79 | ||
58 | int n_rates; | 80 | int n_rates; |
@@ -73,7 +95,6 @@ struct minstrel_priv { | |||
73 | unsigned int cw_min; | 95 | unsigned int cw_min; |
74 | unsigned int cw_max; | 96 | unsigned int cw_max; |
75 | unsigned int max_retry; | 97 | unsigned int max_retry; |
76 | unsigned int ewma_level; | ||
77 | unsigned int segment_size; | 98 | unsigned int segment_size; |
78 | unsigned int update_interval; | 99 | unsigned int update_interval; |
79 | unsigned int lookaround_rate; | 100 | unsigned int lookaround_rate; |
diff --git a/net/mac80211/rc80211_minstrel_debugfs.c b/net/mac80211/rc80211_minstrel_debugfs.c index d5a56226e675..d1048348d399 100644 --- a/net/mac80211/rc80211_minstrel_debugfs.c +++ b/net/mac80211/rc80211_minstrel_debugfs.c | |||
@@ -73,15 +73,17 @@ minstrel_stats_open(struct inode *inode, struct file *file) | |||
73 | for (i = 0; i < mi->n_rates; i++) { | 73 | for (i = 0; i < mi->n_rates; i++) { |
74 | struct minstrel_rate *mr = &mi->r[i]; | 74 | struct minstrel_rate *mr = &mi->r[i]; |
75 | 75 | ||
76 | *(p++) = (i == mi->max_tp_rate) ? 'T' : ' '; | 76 | *(p++) = (i == mi->max_tp_rate[0]) ? 'A' : ' '; |
77 | *(p++) = (i == mi->max_tp_rate2) ? 't' : ' '; | 77 | *(p++) = (i == mi->max_tp_rate[1]) ? 'B' : ' '; |
78 | *(p++) = (i == mi->max_tp_rate[2]) ? 'C' : ' '; | ||
79 | *(p++) = (i == mi->max_tp_rate[3]) ? 'D' : ' '; | ||
78 | *(p++) = (i == mi->max_prob_rate) ? 'P' : ' '; | 80 | *(p++) = (i == mi->max_prob_rate) ? 'P' : ' '; |
79 | p += sprintf(p, "%3u%s", mr->bitrate / 2, | 81 | p += sprintf(p, "%3u%s", mr->bitrate / 2, |
80 | (mr->bitrate & 1 ? ".5" : " ")); | 82 | (mr->bitrate & 1 ? ".5" : " ")); |
81 | 83 | ||
82 | tp = mr->cur_tp / ((18000 << 10) / 96); | 84 | tp = MINSTREL_TRUNC(mr->cur_tp / 10); |
83 | prob = mr->cur_prob / 18; | 85 | prob = MINSTREL_TRUNC(mr->cur_prob * 1000); |
84 | eprob = mr->probability / 18; | 86 | eprob = MINSTREL_TRUNC(mr->probability * 1000); |
85 | 87 | ||
86 | p += sprintf(p, " %6u.%1u %6u.%1u %6u.%1u " | 88 | p += sprintf(p, " %6u.%1u %6u.%1u %6u.%1u " |
87 | "%3u(%3u) %8llu %8llu\n", | 89 | "%3u(%3u) %8llu %8llu\n", |
diff --git a/net/mac80211/rc80211_minstrel_ht.c b/net/mac80211/rc80211_minstrel_ht.c index 3af141c69712..749552bdcfe1 100644 --- a/net/mac80211/rc80211_minstrel_ht.c +++ b/net/mac80211/rc80211_minstrel_ht.c | |||
@@ -17,8 +17,6 @@ | |||
17 | #include "rc80211_minstrel_ht.h" | 17 | #include "rc80211_minstrel_ht.h" |
18 | 18 | ||
19 | #define AVG_PKT_SIZE 1200 | 19 | #define AVG_PKT_SIZE 1200 |
20 | #define SAMPLE_COLUMNS 10 | ||
21 | #define EWMA_LEVEL 75 | ||
22 | 20 | ||
23 | /* Number of bits for an average sized packet */ | 21 | /* Number of bits for an average sized packet */ |
24 | #define MCS_NBITS (AVG_PKT_SIZE << 3) | 22 | #define MCS_NBITS (AVG_PKT_SIZE << 3) |
@@ -26,11 +24,11 @@ | |||
26 | /* Number of symbols for a packet with (bps) bits per symbol */ | 24 | /* Number of symbols for a packet with (bps) bits per symbol */ |
27 | #define MCS_NSYMS(bps) ((MCS_NBITS + (bps) - 1) / (bps)) | 25 | #define MCS_NSYMS(bps) ((MCS_NBITS + (bps) - 1) / (bps)) |
28 | 26 | ||
29 | /* Transmission time for a packet containing (syms) symbols */ | 27 | /* Transmission time (nanoseconds) for a packet containing (syms) symbols */ |
30 | #define MCS_SYMBOL_TIME(sgi, syms) \ | 28 | #define MCS_SYMBOL_TIME(sgi, syms) \ |
31 | (sgi ? \ | 29 | (sgi ? \ |
32 | ((syms) * 18 + 4) / 5 : /* syms * 3.6 us */ \ | 30 | ((syms) * 18000 + 4000) / 5 : /* syms * 3.6 us */ \ |
33 | (syms) << 2 /* syms * 4 us */ \ | 31 | ((syms) * 1000) << 2 /* syms * 4 us */ \ |
34 | ) | 32 | ) |
35 | 33 | ||
36 | /* Transmit duration for the raw data part of an average sized packet */ | 34 | /* Transmit duration for the raw data part of an average sized packet */ |
@@ -64,9 +62,9 @@ | |||
64 | } | 62 | } |
65 | 63 | ||
66 | #define CCK_DURATION(_bitrate, _short, _len) \ | 64 | #define CCK_DURATION(_bitrate, _short, _len) \ |
67 | (10 /* SIFS */ + \ | 65 | (1000 * (10 /* SIFS */ + \ |
68 | (_short ? 72 + 24 : 144 + 48 ) + \ | 66 | (_short ? 72 + 24 : 144 + 48 ) + \ |
69 | (8 * (_len + 4) * 10) / (_bitrate)) | 67 | (8 * (_len + 4) * 10) / (_bitrate))) |
70 | 68 | ||
71 | #define CCK_ACK_DURATION(_bitrate, _short) \ | 69 | #define CCK_ACK_DURATION(_bitrate, _short) \ |
72 | (CCK_DURATION((_bitrate > 10 ? 20 : 10), false, 60) + \ | 70 | (CCK_DURATION((_bitrate > 10 ? 20 : 10), false, 60) + \ |
@@ -129,15 +127,6 @@ const struct mcs_group minstrel_mcs_groups[] = { | |||
129 | static u8 sample_table[SAMPLE_COLUMNS][MCS_GROUP_RATES]; | 127 | static u8 sample_table[SAMPLE_COLUMNS][MCS_GROUP_RATES]; |
130 | 128 | ||
131 | /* | 129 | /* |
132 | * Perform EWMA (Exponentially Weighted Moving Average) calculation | ||
133 | */ | ||
134 | static int | ||
135 | minstrel_ewma(int old, int new, int weight) | ||
136 | { | ||
137 | return (new * (100 - weight) + old * weight) / 100; | ||
138 | } | ||
139 | |||
140 | /* | ||
141 | * Look up an MCS group index based on mac80211 rate information | 130 | * Look up an MCS group index based on mac80211 rate information |
142 | */ | 131 | */ |
143 | static int | 132 | static int |
@@ -211,7 +200,8 @@ static void | |||
211 | minstrel_ht_calc_tp(struct minstrel_ht_sta *mi, int group, int rate) | 200 | minstrel_ht_calc_tp(struct minstrel_ht_sta *mi, int group, int rate) |
212 | { | 201 | { |
213 | struct minstrel_rate_stats *mr; | 202 | struct minstrel_rate_stats *mr; |
214 | unsigned int usecs = 0; | 203 | unsigned int nsecs = 0; |
204 | unsigned int tp; | ||
215 | 205 | ||
216 | mr = &mi->groups[group].rates[rate]; | 206 | mr = &mi->groups[group].rates[rate]; |
217 | 207 | ||
@@ -221,10 +211,12 @@ minstrel_ht_calc_tp(struct minstrel_ht_sta *mi, int group, int rate) | |||
221 | } | 211 | } |
222 | 212 | ||
223 | if (group != MINSTREL_CCK_GROUP) | 213 | if (group != MINSTREL_CCK_GROUP) |
224 | usecs = mi->overhead / MINSTREL_TRUNC(mi->avg_ampdu_len); | 214 | nsecs = 1000 * mi->overhead / MINSTREL_TRUNC(mi->avg_ampdu_len); |
225 | 215 | ||
226 | usecs += minstrel_mcs_groups[group].duration[rate]; | 216 | nsecs += minstrel_mcs_groups[group].duration[rate]; |
227 | mr->cur_tp = MINSTREL_TRUNC((1000000 / usecs) * mr->probability); | 217 | tp = 1000000 * ((mr->probability * 1000) / nsecs); |
218 | |||
219 | mr->cur_tp = MINSTREL_TRUNC(tp); | ||
228 | } | 220 | } |
229 | 221 | ||
230 | /* | 222 | /* |
@@ -308,8 +300,8 @@ minstrel_ht_update_stats(struct minstrel_priv *mp, struct minstrel_ht_sta *mi) | |||
308 | } | 300 | } |
309 | } | 301 | } |
310 | 302 | ||
311 | /* try to sample up to half of the available rates during each interval */ | 303 | /* try to sample all available rates during each interval */ |
312 | mi->sample_count *= 4; | 304 | mi->sample_count *= 8; |
313 | 305 | ||
314 | cur_prob = 0; | 306 | cur_prob = 0; |
315 | cur_prob_tp = 0; | 307 | cur_prob_tp = 0; |
@@ -320,20 +312,13 @@ minstrel_ht_update_stats(struct minstrel_priv *mp, struct minstrel_ht_sta *mi) | |||
320 | if (!mg->supported) | 312 | if (!mg->supported) |
321 | continue; | 313 | continue; |
322 | 314 | ||
323 | mr = minstrel_get_ratestats(mi, mg->max_prob_rate); | ||
324 | if (cur_prob_tp < mr->cur_tp && | ||
325 | minstrel_mcs_groups[group].streams == 1) { | ||
326 | mi->max_prob_rate = mg->max_prob_rate; | ||
327 | cur_prob = mr->cur_prob; | ||
328 | cur_prob_tp = mr->cur_tp; | ||
329 | } | ||
330 | |||
331 | mr = minstrel_get_ratestats(mi, mg->max_tp_rate); | 315 | mr = minstrel_get_ratestats(mi, mg->max_tp_rate); |
332 | if (cur_tp < mr->cur_tp) { | 316 | if (cur_tp < mr->cur_tp) { |
333 | mi->max_tp_rate2 = mi->max_tp_rate; | 317 | mi->max_tp_rate2 = mi->max_tp_rate; |
334 | cur_tp2 = cur_tp; | 318 | cur_tp2 = cur_tp; |
335 | mi->max_tp_rate = mg->max_tp_rate; | 319 | mi->max_tp_rate = mg->max_tp_rate; |
336 | cur_tp = mr->cur_tp; | 320 | cur_tp = mr->cur_tp; |
321 | mi->max_prob_streams = minstrel_mcs_groups[group].streams - 1; | ||
337 | } | 322 | } |
338 | 323 | ||
339 | mr = minstrel_get_ratestats(mi, mg->max_tp_rate2); | 324 | mr = minstrel_get_ratestats(mi, mg->max_tp_rate2); |
@@ -343,6 +328,23 @@ minstrel_ht_update_stats(struct minstrel_priv *mp, struct minstrel_ht_sta *mi) | |||
343 | } | 328 | } |
344 | } | 329 | } |
345 | 330 | ||
331 | if (mi->max_prob_streams < 1) | ||
332 | mi->max_prob_streams = 1; | ||
333 | |||
334 | for (group = 0; group < ARRAY_SIZE(minstrel_mcs_groups); group++) { | ||
335 | mg = &mi->groups[group]; | ||
336 | if (!mg->supported) | ||
337 | continue; | ||
338 | mr = minstrel_get_ratestats(mi, mg->max_prob_rate); | ||
339 | if (cur_prob_tp < mr->cur_tp && | ||
340 | minstrel_mcs_groups[group].streams <= mi->max_prob_streams) { | ||
341 | mi->max_prob_rate = mg->max_prob_rate; | ||
342 | cur_prob = mr->cur_prob; | ||
343 | cur_prob_tp = mr->cur_tp; | ||
344 | } | ||
345 | } | ||
346 | |||
347 | |||
346 | mi->stats_update = jiffies; | 348 | mi->stats_update = jiffies; |
347 | } | 349 | } |
348 | 350 | ||
@@ -467,7 +469,7 @@ minstrel_ht_tx_status(void *priv, struct ieee80211_supported_band *sband, | |||
467 | 469 | ||
468 | if (!mi->sample_wait && !mi->sample_tries && mi->sample_count > 0) { | 470 | if (!mi->sample_wait && !mi->sample_tries && mi->sample_count > 0) { |
469 | mi->sample_wait = 16 + 2 * MINSTREL_TRUNC(mi->avg_ampdu_len); | 471 | mi->sample_wait = 16 + 2 * MINSTREL_TRUNC(mi->avg_ampdu_len); |
470 | mi->sample_tries = 2; | 472 | mi->sample_tries = 1; |
471 | mi->sample_count--; | 473 | mi->sample_count--; |
472 | } | 474 | } |
473 | 475 | ||
@@ -536,7 +538,7 @@ minstrel_calc_retransmit(struct minstrel_priv *mp, struct minstrel_ht_sta *mi, | |||
536 | mr->retry_updated = true; | 538 | mr->retry_updated = true; |
537 | 539 | ||
538 | group = &minstrel_mcs_groups[index / MCS_GROUP_RATES]; | 540 | group = &minstrel_mcs_groups[index / MCS_GROUP_RATES]; |
539 | tx_time_data = group->duration[index % MCS_GROUP_RATES] * ampdu_len; | 541 | tx_time_data = group->duration[index % MCS_GROUP_RATES] * ampdu_len / 1000; |
540 | 542 | ||
541 | /* Contention time for first 2 tries */ | 543 | /* Contention time for first 2 tries */ |
542 | ctime = (t_slot * cw) >> 1; | 544 | ctime = (t_slot * cw) >> 1; |
@@ -616,6 +618,7 @@ minstrel_get_sample_rate(struct minstrel_priv *mp, struct minstrel_ht_sta *mi) | |||
616 | { | 618 | { |
617 | struct minstrel_rate_stats *mr; | 619 | struct minstrel_rate_stats *mr; |
618 | struct minstrel_mcs_group_data *mg; | 620 | struct minstrel_mcs_group_data *mg; |
621 | unsigned int sample_dur, sample_group; | ||
619 | int sample_idx = 0; | 622 | int sample_idx = 0; |
620 | 623 | ||
621 | if (mi->sample_wait > 0) { | 624 | if (mi->sample_wait > 0) { |
@@ -626,11 +629,11 @@ minstrel_get_sample_rate(struct minstrel_priv *mp, struct minstrel_ht_sta *mi) | |||
626 | if (!mi->sample_tries) | 629 | if (!mi->sample_tries) |
627 | return -1; | 630 | return -1; |
628 | 631 | ||
629 | mi->sample_tries--; | ||
630 | mg = &mi->groups[mi->sample_group]; | 632 | mg = &mi->groups[mi->sample_group]; |
631 | sample_idx = sample_table[mg->column][mg->index]; | 633 | sample_idx = sample_table[mg->column][mg->index]; |
632 | mr = &mg->rates[sample_idx]; | 634 | mr = &mg->rates[sample_idx]; |
633 | sample_idx += mi->sample_group * MCS_GROUP_RATES; | 635 | sample_group = mi->sample_group; |
636 | sample_idx += sample_group * MCS_GROUP_RATES; | ||
634 | minstrel_next_sample_idx(mi); | 637 | minstrel_next_sample_idx(mi); |
635 | 638 | ||
636 | /* | 639 | /* |
@@ -651,14 +654,18 @@ minstrel_get_sample_rate(struct minstrel_priv *mp, struct minstrel_ht_sta *mi) | |||
651 | * Make sure that lower rates get sampled only occasionally, | 654 | * Make sure that lower rates get sampled only occasionally, |
652 | * if the link is working perfectly. | 655 | * if the link is working perfectly. |
653 | */ | 656 | */ |
654 | if (minstrel_get_duration(sample_idx) > | 657 | sample_dur = minstrel_get_duration(sample_idx); |
655 | minstrel_get_duration(mi->max_tp_rate)) { | 658 | if (sample_dur >= minstrel_get_duration(mi->max_tp_rate2) && |
659 | (mi->max_prob_streams < | ||
660 | minstrel_mcs_groups[sample_group].streams || | ||
661 | sample_dur >= minstrel_get_duration(mi->max_prob_rate))) { | ||
656 | if (mr->sample_skipped < 20) | 662 | if (mr->sample_skipped < 20) |
657 | return -1; | 663 | return -1; |
658 | 664 | ||
659 | if (mi->sample_slow++ > 2) | 665 | if (mi->sample_slow++ > 2) |
660 | return -1; | 666 | return -1; |
661 | } | 667 | } |
668 | mi->sample_tries--; | ||
662 | 669 | ||
663 | return sample_idx; | 670 | return sample_idx; |
664 | } | 671 | } |
diff --git a/net/mac80211/rc80211_minstrel_ht.h b/net/mac80211/rc80211_minstrel_ht.h index 302dbd52180d..9b16e9de9923 100644 --- a/net/mac80211/rc80211_minstrel_ht.h +++ b/net/mac80211/rc80211_minstrel_ht.h | |||
@@ -16,11 +16,6 @@ | |||
16 | #define MINSTREL_MAX_STREAMS 3 | 16 | #define MINSTREL_MAX_STREAMS 3 |
17 | #define MINSTREL_STREAM_GROUPS 4 | 17 | #define MINSTREL_STREAM_GROUPS 4 |
18 | 18 | ||
19 | /* scaled fraction values */ | ||
20 | #define MINSTREL_SCALE 16 | ||
21 | #define MINSTREL_FRAC(val, div) (((val) << MINSTREL_SCALE) / div) | ||
22 | #define MINSTREL_TRUNC(val) ((val) >> MINSTREL_SCALE) | ||
23 | |||
24 | #define MCS_GROUP_RATES 8 | 19 | #define MCS_GROUP_RATES 8 |
25 | 20 | ||
26 | struct mcs_group { | 21 | struct mcs_group { |
@@ -85,6 +80,7 @@ struct minstrel_ht_sta { | |||
85 | 80 | ||
86 | /* best probability rate */ | 81 | /* best probability rate */ |
87 | unsigned int max_prob_rate; | 82 | unsigned int max_prob_rate; |
83 | unsigned int max_prob_streams; | ||
88 | 84 | ||
89 | /* time of last status update */ | 85 | /* time of last status update */ |
90 | unsigned long stats_update; | 86 | unsigned long stats_update; |
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index c6844ad080be..2528b5a4d6d4 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c | |||
@@ -648,24 +648,6 @@ static ieee80211_rx_result ieee80211_rx_mesh_check(struct ieee80211_rx_data *rx) | |||
648 | return RX_CONTINUE; | 648 | return RX_CONTINUE; |
649 | } | 649 | } |
650 | 650 | ||
651 | #define SEQ_MODULO 0x1000 | ||
652 | #define SEQ_MASK 0xfff | ||
653 | |||
654 | static inline int seq_less(u16 sq1, u16 sq2) | ||
655 | { | ||
656 | return ((sq1 - sq2) & SEQ_MASK) > (SEQ_MODULO >> 1); | ||
657 | } | ||
658 | |||
659 | static inline u16 seq_inc(u16 sq) | ||
660 | { | ||
661 | return (sq + 1) & SEQ_MASK; | ||
662 | } | ||
663 | |||
664 | static inline u16 seq_sub(u16 sq1, u16 sq2) | ||
665 | { | ||
666 | return (sq1 - sq2) & SEQ_MASK; | ||
667 | } | ||
668 | |||
669 | static void ieee80211_release_reorder_frame(struct ieee80211_sub_if_data *sdata, | 651 | static void ieee80211_release_reorder_frame(struct ieee80211_sub_if_data *sdata, |
670 | struct tid_ampdu_rx *tid_agg_rx, | 652 | struct tid_ampdu_rx *tid_agg_rx, |
671 | int index, | 653 | int index, |
@@ -687,7 +669,7 @@ static void ieee80211_release_reorder_frame(struct ieee80211_sub_if_data *sdata, | |||
687 | __skb_queue_tail(frames, skb); | 669 | __skb_queue_tail(frames, skb); |
688 | 670 | ||
689 | no_frame: | 671 | no_frame: |
690 | tid_agg_rx->head_seq_num = seq_inc(tid_agg_rx->head_seq_num); | 672 | tid_agg_rx->head_seq_num = ieee80211_sn_inc(tid_agg_rx->head_seq_num); |
691 | } | 673 | } |
692 | 674 | ||
693 | static void ieee80211_release_reorder_frames(struct ieee80211_sub_if_data *sdata, | 675 | static void ieee80211_release_reorder_frames(struct ieee80211_sub_if_data *sdata, |
@@ -699,8 +681,9 @@ static void ieee80211_release_reorder_frames(struct ieee80211_sub_if_data *sdata | |||
699 | 681 | ||
700 | lockdep_assert_held(&tid_agg_rx->reorder_lock); | 682 | lockdep_assert_held(&tid_agg_rx->reorder_lock); |
701 | 683 | ||
702 | while (seq_less(tid_agg_rx->head_seq_num, head_seq_num)) { | 684 | while (ieee80211_sn_less(tid_agg_rx->head_seq_num, head_seq_num)) { |
703 | index = seq_sub(tid_agg_rx->head_seq_num, tid_agg_rx->ssn) % | 685 | index = ieee80211_sn_sub(tid_agg_rx->head_seq_num, |
686 | tid_agg_rx->ssn) % | ||
704 | tid_agg_rx->buf_size; | 687 | tid_agg_rx->buf_size; |
705 | ieee80211_release_reorder_frame(sdata, tid_agg_rx, index, | 688 | ieee80211_release_reorder_frame(sdata, tid_agg_rx, index, |
706 | frames); | 689 | frames); |
@@ -727,8 +710,8 @@ static void ieee80211_sta_reorder_release(struct ieee80211_sub_if_data *sdata, | |||
727 | lockdep_assert_held(&tid_agg_rx->reorder_lock); | 710 | lockdep_assert_held(&tid_agg_rx->reorder_lock); |
728 | 711 | ||
729 | /* release the buffer until next missing frame */ | 712 | /* release the buffer until next missing frame */ |
730 | index = seq_sub(tid_agg_rx->head_seq_num, tid_agg_rx->ssn) % | 713 | index = ieee80211_sn_sub(tid_agg_rx->head_seq_num, |
731 | tid_agg_rx->buf_size; | 714 | tid_agg_rx->ssn) % tid_agg_rx->buf_size; |
732 | if (!tid_agg_rx->reorder_buf[index] && | 715 | if (!tid_agg_rx->reorder_buf[index] && |
733 | tid_agg_rx->stored_mpdu_num) { | 716 | tid_agg_rx->stored_mpdu_num) { |
734 | /* | 717 | /* |
@@ -756,19 +739,22 @@ static void ieee80211_sta_reorder_release(struct ieee80211_sub_if_data *sdata, | |||
756 | * Increment the head seq# also for the skipped slots. | 739 | * Increment the head seq# also for the skipped slots. |
757 | */ | 740 | */ |
758 | tid_agg_rx->head_seq_num = | 741 | tid_agg_rx->head_seq_num = |
759 | (tid_agg_rx->head_seq_num + skipped) & SEQ_MASK; | 742 | (tid_agg_rx->head_seq_num + |
743 | skipped) & IEEE80211_SN_MASK; | ||
760 | skipped = 0; | 744 | skipped = 0; |
761 | } | 745 | } |
762 | } else while (tid_agg_rx->reorder_buf[index]) { | 746 | } else while (tid_agg_rx->reorder_buf[index]) { |
763 | ieee80211_release_reorder_frame(sdata, tid_agg_rx, index, | 747 | ieee80211_release_reorder_frame(sdata, tid_agg_rx, index, |
764 | frames); | 748 | frames); |
765 | index = seq_sub(tid_agg_rx->head_seq_num, tid_agg_rx->ssn) % | 749 | index = ieee80211_sn_sub(tid_agg_rx->head_seq_num, |
750 | tid_agg_rx->ssn) % | ||
766 | tid_agg_rx->buf_size; | 751 | tid_agg_rx->buf_size; |
767 | } | 752 | } |
768 | 753 | ||
769 | if (tid_agg_rx->stored_mpdu_num) { | 754 | if (tid_agg_rx->stored_mpdu_num) { |
770 | j = index = seq_sub(tid_agg_rx->head_seq_num, | 755 | j = index = ieee80211_sn_sub(tid_agg_rx->head_seq_num, |
771 | tid_agg_rx->ssn) % tid_agg_rx->buf_size; | 756 | tid_agg_rx->ssn) % |
757 | tid_agg_rx->buf_size; | ||
772 | 758 | ||
773 | for (; j != (index - 1) % tid_agg_rx->buf_size; | 759 | for (; j != (index - 1) % tid_agg_rx->buf_size; |
774 | j = (j + 1) % tid_agg_rx->buf_size) { | 760 | j = (j + 1) % tid_agg_rx->buf_size) { |
@@ -809,7 +795,7 @@ static bool ieee80211_sta_manage_reorder_buf(struct ieee80211_sub_if_data *sdata | |||
809 | head_seq_num = tid_agg_rx->head_seq_num; | 795 | head_seq_num = tid_agg_rx->head_seq_num; |
810 | 796 | ||
811 | /* frame with out of date sequence number */ | 797 | /* frame with out of date sequence number */ |
812 | if (seq_less(mpdu_seq_num, head_seq_num)) { | 798 | if (ieee80211_sn_less(mpdu_seq_num, head_seq_num)) { |
813 | dev_kfree_skb(skb); | 799 | dev_kfree_skb(skb); |
814 | goto out; | 800 | goto out; |
815 | } | 801 | } |
@@ -818,8 +804,9 @@ static bool ieee80211_sta_manage_reorder_buf(struct ieee80211_sub_if_data *sdata | |||
818 | * If frame the sequence number exceeds our buffering window | 804 | * If frame the sequence number exceeds our buffering window |
819 | * size release some previous frames to make room for this one. | 805 | * size release some previous frames to make room for this one. |
820 | */ | 806 | */ |
821 | if (!seq_less(mpdu_seq_num, head_seq_num + buf_size)) { | 807 | if (!ieee80211_sn_less(mpdu_seq_num, head_seq_num + buf_size)) { |
822 | head_seq_num = seq_inc(seq_sub(mpdu_seq_num, buf_size)); | 808 | head_seq_num = ieee80211_sn_inc( |
809 | ieee80211_sn_sub(mpdu_seq_num, buf_size)); | ||
823 | /* release stored frames up to new head to stack */ | 810 | /* release stored frames up to new head to stack */ |
824 | ieee80211_release_reorder_frames(sdata, tid_agg_rx, | 811 | ieee80211_release_reorder_frames(sdata, tid_agg_rx, |
825 | head_seq_num, frames); | 812 | head_seq_num, frames); |
@@ -827,7 +814,8 @@ static bool ieee80211_sta_manage_reorder_buf(struct ieee80211_sub_if_data *sdata | |||
827 | 814 | ||
828 | /* Now the new frame is always in the range of the reordering buffer */ | 815 | /* Now the new frame is always in the range of the reordering buffer */ |
829 | 816 | ||
830 | index = seq_sub(mpdu_seq_num, tid_agg_rx->ssn) % tid_agg_rx->buf_size; | 817 | index = ieee80211_sn_sub(mpdu_seq_num, |
818 | tid_agg_rx->ssn) % tid_agg_rx->buf_size; | ||
831 | 819 | ||
832 | /* check if we already stored this frame */ | 820 | /* check if we already stored this frame */ |
833 | if (tid_agg_rx->reorder_buf[index]) { | 821 | if (tid_agg_rx->reorder_buf[index]) { |
@@ -843,7 +831,8 @@ static bool ieee80211_sta_manage_reorder_buf(struct ieee80211_sub_if_data *sdata | |||
843 | */ | 831 | */ |
844 | if (mpdu_seq_num == tid_agg_rx->head_seq_num && | 832 | if (mpdu_seq_num == tid_agg_rx->head_seq_num && |
845 | tid_agg_rx->stored_mpdu_num == 0) { | 833 | tid_agg_rx->stored_mpdu_num == 0) { |
846 | tid_agg_rx->head_seq_num = seq_inc(tid_agg_rx->head_seq_num); | 834 | tid_agg_rx->head_seq_num = |
835 | ieee80211_sn_inc(tid_agg_rx->head_seq_num); | ||
847 | ret = false; | 836 | ret = false; |
848 | goto out; | 837 | goto out; |
849 | } | 838 | } |
@@ -1894,8 +1883,10 @@ ieee80211_deliver_skb(struct ieee80211_rx_data *rx) | |||
1894 | * 'align' will only take the values 0 or 2 here | 1883 | * 'align' will only take the values 0 or 2 here |
1895 | * since all frames are required to be aligned | 1884 | * since all frames are required to be aligned |
1896 | * to 2-byte boundaries when being passed to | 1885 | * to 2-byte boundaries when being passed to |
1897 | * mac80211. That also explains the __skb_push() | 1886 | * mac80211; the code here works just as well if |
1898 | * below. | 1887 | * that isn't true, but mac80211 assumes it can |
1888 | * access fields as 2-byte aligned (e.g. for | ||
1889 | * compare_ether_addr) | ||
1899 | */ | 1890 | */ |
1900 | align = ((unsigned long)(skb->data + sizeof(struct ethhdr))) & 3; | 1891 | align = ((unsigned long)(skb->data + sizeof(struct ethhdr))) & 3; |
1901 | if (align) { | 1892 | if (align) { |
@@ -2552,7 +2543,7 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx) | |||
2552 | case WLAN_SP_MESH_PEERING_CONFIRM: | 2543 | case WLAN_SP_MESH_PEERING_CONFIRM: |
2553 | if (!ieee80211_vif_is_mesh(&sdata->vif)) | 2544 | if (!ieee80211_vif_is_mesh(&sdata->vif)) |
2554 | goto invalid; | 2545 | goto invalid; |
2555 | if (sdata->u.mesh.security != IEEE80211_MESH_SEC_NONE) | 2546 | if (sdata->u.mesh.user_mpm) |
2556 | /* userspace handles this frame */ | 2547 | /* userspace handles this frame */ |
2557 | break; | 2548 | break; |
2558 | goto queue; | 2549 | goto queue; |
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index 238a0cca320e..85458a28ffa0 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c | |||
@@ -342,6 +342,11 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata, | |||
342 | INIT_WORK(&sta->drv_unblock_wk, sta_unblock); | 342 | INIT_WORK(&sta->drv_unblock_wk, sta_unblock); |
343 | INIT_WORK(&sta->ampdu_mlme.work, ieee80211_ba_session_work); | 343 | INIT_WORK(&sta->ampdu_mlme.work, ieee80211_ba_session_work); |
344 | mutex_init(&sta->ampdu_mlme.mtx); | 344 | mutex_init(&sta->ampdu_mlme.mtx); |
345 | #ifdef CONFIG_MAC80211_MESH | ||
346 | if (ieee80211_vif_is_mesh(&sdata->vif) && | ||
347 | !sdata->u.mesh.user_mpm) | ||
348 | init_timer(&sta->plink_timer); | ||
349 | #endif | ||
345 | 350 | ||
346 | memcpy(sta->sta.addr, addr, ETH_ALEN); | 351 | memcpy(sta->sta.addr, addr, ETH_ALEN); |
347 | sta->local = local; | 352 | sta->local = local; |
@@ -795,13 +800,16 @@ int __must_check __sta_info_destroy(struct sta_info *sta) | |||
795 | 800 | ||
796 | mutex_lock(&local->key_mtx); | 801 | mutex_lock(&local->key_mtx); |
797 | for (i = 0; i < NUM_DEFAULT_KEYS; i++) { | 802 | for (i = 0; i < NUM_DEFAULT_KEYS; i++) { |
798 | __ieee80211_key_free(key_mtx_dereference(local, sta->gtk[i])); | 803 | __ieee80211_key_free(key_mtx_dereference(local, sta->gtk[i]), |
804 | true); | ||
799 | have_key = true; | 805 | have_key = true; |
800 | } | 806 | } |
801 | if (sta->ptk) { | 807 | if (sta->ptk) { |
802 | __ieee80211_key_free(key_mtx_dereference(local, sta->ptk)); | 808 | __ieee80211_key_free(key_mtx_dereference(local, sta->ptk), |
809 | true); | ||
803 | have_key = true; | 810 | have_key = true; |
804 | } | 811 | } |
812 | |||
805 | mutex_unlock(&local->key_mtx); | 813 | mutex_unlock(&local->key_mtx); |
806 | 814 | ||
807 | if (!have_key) | 815 | if (!have_key) |
diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index 4947341a2a82..e5868c32d1a3 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h | |||
@@ -281,7 +281,6 @@ struct sta_ampdu_mlme { | |||
281 | * @plink_state: peer link state | 281 | * @plink_state: peer link state |
282 | * @plink_timeout: timeout of peer link | 282 | * @plink_timeout: timeout of peer link |
283 | * @plink_timer: peer link watch timer | 283 | * @plink_timer: peer link watch timer |
284 | * @plink_timer_was_running: used by suspend/resume to restore timers | ||
285 | * @t_offset: timing offset relative to this host | 284 | * @t_offset: timing offset relative to this host |
286 | * @t_offset_setpoint: reference timing offset of this sta to be used when | 285 | * @t_offset_setpoint: reference timing offset of this sta to be used when |
287 | * calculating clockdrift | 286 | * calculating clockdrift |
@@ -379,7 +378,6 @@ struct sta_info { | |||
379 | __le16 reason; | 378 | __le16 reason; |
380 | u8 plink_retries; | 379 | u8 plink_retries; |
381 | bool ignore_plink_timer; | 380 | bool ignore_plink_timer; |
382 | bool plink_timer_was_running; | ||
383 | enum nl80211_plink_state plink_state; | 381 | enum nl80211_plink_state plink_state; |
384 | u32 plink_timeout; | 382 | u32 plink_timeout; |
385 | struct timer_list plink_timer; | 383 | struct timer_list plink_timer; |
diff --git a/net/mac80211/trace.h b/net/mac80211/trace.h index 3d7cd2a0582f..e7db2b804e0c 100644 --- a/net/mac80211/trace.h +++ b/net/mac80211/trace.h | |||
@@ -1042,15 +1042,17 @@ TRACE_EVENT(drv_remain_on_channel, | |||
1042 | TP_PROTO(struct ieee80211_local *local, | 1042 | TP_PROTO(struct ieee80211_local *local, |
1043 | struct ieee80211_sub_if_data *sdata, | 1043 | struct ieee80211_sub_if_data *sdata, |
1044 | struct ieee80211_channel *chan, | 1044 | struct ieee80211_channel *chan, |
1045 | unsigned int duration), | 1045 | unsigned int duration, |
1046 | enum ieee80211_roc_type type), | ||
1046 | 1047 | ||
1047 | TP_ARGS(local, sdata, chan, duration), | 1048 | TP_ARGS(local, sdata, chan, duration, type), |
1048 | 1049 | ||
1049 | TP_STRUCT__entry( | 1050 | TP_STRUCT__entry( |
1050 | LOCAL_ENTRY | 1051 | LOCAL_ENTRY |
1051 | VIF_ENTRY | 1052 | VIF_ENTRY |
1052 | __field(int, center_freq) | 1053 | __field(int, center_freq) |
1053 | __field(unsigned int, duration) | 1054 | __field(unsigned int, duration) |
1055 | __field(u32, type) | ||
1054 | ), | 1056 | ), |
1055 | 1057 | ||
1056 | TP_fast_assign( | 1058 | TP_fast_assign( |
@@ -1058,12 +1060,13 @@ TRACE_EVENT(drv_remain_on_channel, | |||
1058 | VIF_ASSIGN; | 1060 | VIF_ASSIGN; |
1059 | __entry->center_freq = chan->center_freq; | 1061 | __entry->center_freq = chan->center_freq; |
1060 | __entry->duration = duration; | 1062 | __entry->duration = duration; |
1063 | __entry->type = type; | ||
1061 | ), | 1064 | ), |
1062 | 1065 | ||
1063 | TP_printk( | 1066 | TP_printk( |
1064 | LOCAL_PR_FMT VIF_PR_FMT " freq:%dMHz duration:%dms", | 1067 | LOCAL_PR_FMT VIF_PR_FMT " freq:%dMHz duration:%dms type=%d", |
1065 | LOCAL_PR_ARG, VIF_PR_ARG, | 1068 | LOCAL_PR_ARG, VIF_PR_ARG, |
1066 | __entry->center_freq, __entry->duration | 1069 | __entry->center_freq, __entry->duration, __entry->type |
1067 | ) | 1070 | ) |
1068 | ); | 1071 | ); |
1069 | 1072 | ||
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 8914d2d2881a..4e8a86163fc7 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c | |||
@@ -2085,7 +2085,7 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, | |||
2085 | encaps_data = bridge_tunnel_header; | 2085 | encaps_data = bridge_tunnel_header; |
2086 | encaps_len = sizeof(bridge_tunnel_header); | 2086 | encaps_len = sizeof(bridge_tunnel_header); |
2087 | skip_header_bytes -= 2; | 2087 | skip_header_bytes -= 2; |
2088 | } else if (ethertype >= 0x600) { | 2088 | } else if (ethertype >= ETH_P_802_3_MIN) { |
2089 | encaps_data = rfc1042_header; | 2089 | encaps_data = rfc1042_header; |
2090 | encaps_len = sizeof(rfc1042_header); | 2090 | encaps_len = sizeof(rfc1042_header); |
2091 | skip_header_bytes -= 2; | 2091 | skip_header_bytes -= 2; |
diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 0f38f43ac62e..b7a856e3281b 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c | |||
@@ -1357,6 +1357,25 @@ void ieee80211_stop_device(struct ieee80211_local *local) | |||
1357 | drv_stop(local); | 1357 | drv_stop(local); |
1358 | } | 1358 | } |
1359 | 1359 | ||
1360 | static void ieee80211_assign_chanctx(struct ieee80211_local *local, | ||
1361 | struct ieee80211_sub_if_data *sdata) | ||
1362 | { | ||
1363 | struct ieee80211_chanctx_conf *conf; | ||
1364 | struct ieee80211_chanctx *ctx; | ||
1365 | |||
1366 | if (!local->use_chanctx) | ||
1367 | return; | ||
1368 | |||
1369 | mutex_lock(&local->chanctx_mtx); | ||
1370 | conf = rcu_dereference_protected(sdata->vif.chanctx_conf, | ||
1371 | lockdep_is_held(&local->chanctx_mtx)); | ||
1372 | if (conf) { | ||
1373 | ctx = container_of(conf, struct ieee80211_chanctx, conf); | ||
1374 | drv_assign_vif_chanctx(local, sdata, ctx); | ||
1375 | } | ||
1376 | mutex_unlock(&local->chanctx_mtx); | ||
1377 | } | ||
1378 | |||
1360 | int ieee80211_reconfig(struct ieee80211_local *local) | 1379 | int ieee80211_reconfig(struct ieee80211_local *local) |
1361 | { | 1380 | { |
1362 | struct ieee80211_hw *hw = &local->hw; | 1381 | struct ieee80211_hw *hw = &local->hw; |
@@ -1445,36 +1464,14 @@ int ieee80211_reconfig(struct ieee80211_local *local) | |||
1445 | } | 1464 | } |
1446 | 1465 | ||
1447 | list_for_each_entry(sdata, &local->interfaces, list) { | 1466 | list_for_each_entry(sdata, &local->interfaces, list) { |
1448 | struct ieee80211_chanctx_conf *ctx_conf; | ||
1449 | |||
1450 | if (!ieee80211_sdata_running(sdata)) | 1467 | if (!ieee80211_sdata_running(sdata)) |
1451 | continue; | 1468 | continue; |
1452 | 1469 | ieee80211_assign_chanctx(local, sdata); | |
1453 | mutex_lock(&local->chanctx_mtx); | ||
1454 | ctx_conf = rcu_dereference_protected(sdata->vif.chanctx_conf, | ||
1455 | lockdep_is_held(&local->chanctx_mtx)); | ||
1456 | if (ctx_conf) { | ||
1457 | ctx = container_of(ctx_conf, struct ieee80211_chanctx, | ||
1458 | conf); | ||
1459 | drv_assign_vif_chanctx(local, sdata, ctx); | ||
1460 | } | ||
1461 | mutex_unlock(&local->chanctx_mtx); | ||
1462 | } | 1470 | } |
1463 | 1471 | ||
1464 | sdata = rtnl_dereference(local->monitor_sdata); | 1472 | sdata = rtnl_dereference(local->monitor_sdata); |
1465 | if (sdata && local->use_chanctx && ieee80211_sdata_running(sdata)) { | 1473 | if (sdata && ieee80211_sdata_running(sdata)) |
1466 | struct ieee80211_chanctx_conf *ctx_conf; | 1474 | ieee80211_assign_chanctx(local, sdata); |
1467 | |||
1468 | mutex_lock(&local->chanctx_mtx); | ||
1469 | ctx_conf = rcu_dereference_protected(sdata->vif.chanctx_conf, | ||
1470 | lockdep_is_held(&local->chanctx_mtx)); | ||
1471 | if (ctx_conf) { | ||
1472 | ctx = container_of(ctx_conf, struct ieee80211_chanctx, | ||
1473 | conf); | ||
1474 | drv_assign_vif_chanctx(local, sdata, ctx); | ||
1475 | } | ||
1476 | mutex_unlock(&local->chanctx_mtx); | ||
1477 | } | ||
1478 | 1475 | ||
1479 | /* add STAs back */ | 1476 | /* add STAs back */ |
1480 | mutex_lock(&local->sta_mtx); | 1477 | mutex_lock(&local->sta_mtx); |
@@ -1534,11 +1531,6 @@ int ieee80211_reconfig(struct ieee80211_local *local) | |||
1534 | BSS_CHANGED_IDLE | | 1531 | BSS_CHANGED_IDLE | |
1535 | BSS_CHANGED_TXPOWER; | 1532 | BSS_CHANGED_TXPOWER; |
1536 | 1533 | ||
1537 | #ifdef CONFIG_PM | ||
1538 | if (local->resuming && !reconfig_due_to_wowlan) | ||
1539 | sdata->vif.bss_conf = sdata->suspend_bss_conf; | ||
1540 | #endif | ||
1541 | |||
1542 | switch (sdata->vif.type) { | 1534 | switch (sdata->vif.type) { |
1543 | case NL80211_IFTYPE_STATION: | 1535 | case NL80211_IFTYPE_STATION: |
1544 | changed |= BSS_CHANGED_ASSOC | | 1536 | changed |= BSS_CHANGED_ASSOC | |
@@ -1678,28 +1670,7 @@ int ieee80211_reconfig(struct ieee80211_local *local) | |||
1678 | mb(); | 1670 | mb(); |
1679 | local->resuming = false; | 1671 | local->resuming = false; |
1680 | 1672 | ||
1681 | list_for_each_entry(sdata, &local->interfaces, list) { | ||
1682 | switch(sdata->vif.type) { | ||
1683 | case NL80211_IFTYPE_STATION: | ||
1684 | ieee80211_sta_restart(sdata); | ||
1685 | break; | ||
1686 | case NL80211_IFTYPE_ADHOC: | ||
1687 | ieee80211_ibss_restart(sdata); | ||
1688 | break; | ||
1689 | case NL80211_IFTYPE_MESH_POINT: | ||
1690 | ieee80211_mesh_restart(sdata); | ||
1691 | break; | ||
1692 | default: | ||
1693 | break; | ||
1694 | } | ||
1695 | } | ||
1696 | |||
1697 | mod_timer(&local->sta_cleanup, jiffies + 1); | 1673 | mod_timer(&local->sta_cleanup, jiffies + 1); |
1698 | |||
1699 | mutex_lock(&local->sta_mtx); | ||
1700 | list_for_each_entry(sta, &local->sta_list, list) | ||
1701 | mesh_plink_restart(sta); | ||
1702 | mutex_unlock(&local->sta_mtx); | ||
1703 | #else | 1674 | #else |
1704 | WARN_ON(1); | 1675 | WARN_ON(1); |
1705 | #endif | 1676 | #endif |
diff --git a/net/mac80211/vht.c b/net/mac80211/vht.c index a2c2258bc84e..171344d4eb7c 100644 --- a/net/mac80211/vht.c +++ b/net/mac80211/vht.c | |||
@@ -13,6 +13,104 @@ | |||
13 | #include "rate.h" | 13 | #include "rate.h" |
14 | 14 | ||
15 | 15 | ||
16 | static void __check_vhtcap_disable(struct ieee80211_sub_if_data *sdata, | ||
17 | struct ieee80211_sta_vht_cap *vht_cap, | ||
18 | u32 flag) | ||
19 | { | ||
20 | __le32 le_flag = cpu_to_le32(flag); | ||
21 | |||
22 | if (sdata->u.mgd.vht_capa_mask.vht_cap_info & le_flag && | ||
23 | !(sdata->u.mgd.vht_capa.vht_cap_info & le_flag)) | ||
24 | vht_cap->cap &= ~flag; | ||
25 | } | ||
26 | |||
27 | void ieee80211_apply_vhtcap_overrides(struct ieee80211_sub_if_data *sdata, | ||
28 | struct ieee80211_sta_vht_cap *vht_cap) | ||
29 | { | ||
30 | int i; | ||
31 | u16 rxmcs_mask, rxmcs_cap, rxmcs_n, txmcs_mask, txmcs_cap, txmcs_n; | ||
32 | |||
33 | if (!vht_cap->vht_supported) | ||
34 | return; | ||
35 | |||
36 | if (sdata->vif.type != NL80211_IFTYPE_STATION) | ||
37 | return; | ||
38 | |||
39 | __check_vhtcap_disable(sdata, vht_cap, | ||
40 | IEEE80211_VHT_CAP_RXLDPC); | ||
41 | __check_vhtcap_disable(sdata, vht_cap, | ||
42 | IEEE80211_VHT_CAP_SHORT_GI_80); | ||
43 | __check_vhtcap_disable(sdata, vht_cap, | ||
44 | IEEE80211_VHT_CAP_SHORT_GI_160); | ||
45 | __check_vhtcap_disable(sdata, vht_cap, | ||
46 | IEEE80211_VHT_CAP_TXSTBC); | ||
47 | __check_vhtcap_disable(sdata, vht_cap, | ||
48 | IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE); | ||
49 | __check_vhtcap_disable(sdata, vht_cap, | ||
50 | IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE); | ||
51 | __check_vhtcap_disable(sdata, vht_cap, | ||
52 | IEEE80211_VHT_CAP_RX_ANTENNA_PATTERN); | ||
53 | __check_vhtcap_disable(sdata, vht_cap, | ||
54 | IEEE80211_VHT_CAP_TX_ANTENNA_PATTERN); | ||
55 | |||
56 | /* Allow user to decrease AMPDU length exponent */ | ||
57 | if (sdata->u.mgd.vht_capa_mask.vht_cap_info & | ||
58 | cpu_to_le32(IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK)) { | ||
59 | u32 cap, n; | ||
60 | |||
61 | n = le32_to_cpu(sdata->u.mgd.vht_capa.vht_cap_info) & | ||
62 | IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK; | ||
63 | n >>= IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_SHIFT; | ||
64 | cap = vht_cap->cap & IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK; | ||
65 | cap >>= IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_SHIFT; | ||
66 | |||
67 | if (n < cap) { | ||
68 | vht_cap->cap &= | ||
69 | ~IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK; | ||
70 | vht_cap->cap |= | ||
71 | n << IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_SHIFT; | ||
72 | } | ||
73 | } | ||
74 | |||
75 | /* Allow the user to decrease MCSes */ | ||
76 | rxmcs_mask = | ||
77 | le16_to_cpu(sdata->u.mgd.vht_capa_mask.supp_mcs.rx_mcs_map); | ||
78 | rxmcs_n = le16_to_cpu(sdata->u.mgd.vht_capa.supp_mcs.rx_mcs_map); | ||
79 | rxmcs_n &= rxmcs_mask; | ||
80 | rxmcs_cap = le16_to_cpu(vht_cap->vht_mcs.rx_mcs_map); | ||
81 | |||
82 | txmcs_mask = | ||
83 | le16_to_cpu(sdata->u.mgd.vht_capa_mask.supp_mcs.tx_mcs_map); | ||
84 | txmcs_n = le16_to_cpu(sdata->u.mgd.vht_capa.supp_mcs.tx_mcs_map); | ||
85 | txmcs_n &= txmcs_mask; | ||
86 | txmcs_cap = le16_to_cpu(vht_cap->vht_mcs.tx_mcs_map); | ||
87 | for (i = 0; i < 8; i++) { | ||
88 | u8 m, n, c; | ||
89 | |||
90 | m = (rxmcs_mask >> 2*i) & IEEE80211_VHT_MCS_NOT_SUPPORTED; | ||
91 | n = (rxmcs_n >> 2*i) & IEEE80211_VHT_MCS_NOT_SUPPORTED; | ||
92 | c = (rxmcs_cap >> 2*i) & IEEE80211_VHT_MCS_NOT_SUPPORTED; | ||
93 | |||
94 | if (m && ((c != IEEE80211_VHT_MCS_NOT_SUPPORTED && n < c) || | ||
95 | n == IEEE80211_VHT_MCS_NOT_SUPPORTED)) { | ||
96 | rxmcs_cap &= ~(3 << 2*i); | ||
97 | rxmcs_cap |= (rxmcs_n & (3 << 2*i)); | ||
98 | } | ||
99 | |||
100 | m = (txmcs_mask >> 2*i) & IEEE80211_VHT_MCS_NOT_SUPPORTED; | ||
101 | n = (txmcs_n >> 2*i) & IEEE80211_VHT_MCS_NOT_SUPPORTED; | ||
102 | c = (txmcs_cap >> 2*i) & IEEE80211_VHT_MCS_NOT_SUPPORTED; | ||
103 | |||
104 | if (m && ((c != IEEE80211_VHT_MCS_NOT_SUPPORTED && n < c) || | ||
105 | n == IEEE80211_VHT_MCS_NOT_SUPPORTED)) { | ||
106 | txmcs_cap &= ~(3 << 2*i); | ||
107 | txmcs_cap |= (txmcs_n & (3 << 2*i)); | ||
108 | } | ||
109 | } | ||
110 | vht_cap->vht_mcs.rx_mcs_map = cpu_to_le16(rxmcs_cap); | ||
111 | vht_cap->vht_mcs.tx_mcs_map = cpu_to_le16(txmcs_cap); | ||
112 | } | ||
113 | |||
16 | void | 114 | void |
17 | ieee80211_vht_cap_ie_to_sta_vht_cap(struct ieee80211_sub_if_data *sdata, | 115 | ieee80211_vht_cap_ie_to_sta_vht_cap(struct ieee80211_sub_if_data *sdata, |
18 | struct ieee80211_supported_band *sband, | 116 | struct ieee80211_supported_band *sband, |
@@ -20,6 +118,8 @@ ieee80211_vht_cap_ie_to_sta_vht_cap(struct ieee80211_sub_if_data *sdata, | |||
20 | struct sta_info *sta) | 118 | struct sta_info *sta) |
21 | { | 119 | { |
22 | struct ieee80211_sta_vht_cap *vht_cap = &sta->sta.vht_cap; | 120 | struct ieee80211_sta_vht_cap *vht_cap = &sta->sta.vht_cap; |
121 | struct ieee80211_sta_vht_cap own_cap; | ||
122 | u32 cap_info, i; | ||
23 | 123 | ||
24 | memset(vht_cap, 0, sizeof(*vht_cap)); | 124 | memset(vht_cap, 0, sizeof(*vht_cap)); |
25 | 125 | ||
@@ -35,12 +135,122 @@ ieee80211_vht_cap_ie_to_sta_vht_cap(struct ieee80211_sub_if_data *sdata, | |||
35 | 135 | ||
36 | vht_cap->vht_supported = true; | 136 | vht_cap->vht_supported = true; |
37 | 137 | ||
38 | vht_cap->cap = le32_to_cpu(vht_cap_ie->vht_cap_info); | 138 | own_cap = sband->vht_cap; |
139 | /* | ||
140 | * If user has specified capability overrides, take care | ||
141 | * of that if the station we're setting up is the AP that | ||
142 | * we advertised a restricted capability set to. Override | ||
143 | * our own capabilities and then use those below. | ||
144 | */ | ||
145 | if (sdata->vif.type == NL80211_IFTYPE_STATION && | ||
146 | !test_sta_flag(sta, WLAN_STA_TDLS_PEER)) | ||
147 | ieee80211_apply_vhtcap_overrides(sdata, &own_cap); | ||
148 | |||
149 | /* take some capabilities as-is */ | ||
150 | cap_info = le32_to_cpu(vht_cap_ie->vht_cap_info); | ||
151 | vht_cap->cap = cap_info; | ||
152 | vht_cap->cap &= IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_3895 | | ||
153 | IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_7991 | | ||
154 | IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454 | | ||
155 | IEEE80211_VHT_CAP_RXLDPC | | ||
156 | IEEE80211_VHT_CAP_VHT_TXOP_PS | | ||
157 | IEEE80211_VHT_CAP_HTC_VHT | | ||
158 | IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK | | ||
159 | IEEE80211_VHT_CAP_VHT_LINK_ADAPTATION_VHT_UNSOL_MFB | | ||
160 | IEEE80211_VHT_CAP_VHT_LINK_ADAPTATION_VHT_MRQ_MFB | | ||
161 | IEEE80211_VHT_CAP_RX_ANTENNA_PATTERN | | ||
162 | IEEE80211_VHT_CAP_TX_ANTENNA_PATTERN; | ||
163 | |||
164 | /* and some based on our own capabilities */ | ||
165 | switch (own_cap.cap & IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK) { | ||
166 | case IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ: | ||
167 | vht_cap->cap |= cap_info & | ||
168 | IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ; | ||
169 | break; | ||
170 | case IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ: | ||
171 | vht_cap->cap |= cap_info & | ||
172 | IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK; | ||
173 | break; | ||
174 | default: | ||
175 | /* nothing */ | ||
176 | break; | ||
177 | } | ||
178 | |||
179 | /* symmetric capabilities */ | ||
180 | vht_cap->cap |= cap_info & own_cap.cap & | ||
181 | (IEEE80211_VHT_CAP_SHORT_GI_80 | | ||
182 | IEEE80211_VHT_CAP_SHORT_GI_160); | ||
183 | |||
184 | /* remaining ones */ | ||
185 | if (own_cap.cap & IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE) { | ||
186 | vht_cap->cap |= cap_info & | ||
187 | (IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE | | ||
188 | IEEE80211_VHT_CAP_BEAMFORMER_ANTENNAS_MAX | | ||
189 | IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_MAX); | ||
190 | } | ||
191 | |||
192 | if (own_cap.cap & IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE) | ||
193 | vht_cap->cap |= cap_info & | ||
194 | IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE; | ||
195 | |||
196 | if (own_cap.cap & IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE) | ||
197 | vht_cap->cap |= cap_info & | ||
198 | IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE; | ||
199 | |||
200 | if (own_cap.cap & IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE) | ||
201 | vht_cap->cap |= cap_info & | ||
202 | IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE; | ||
203 | |||
204 | if (own_cap.cap & IEEE80211_VHT_CAP_TXSTBC) | ||
205 | vht_cap->cap |= cap_info & IEEE80211_VHT_CAP_RXSTBC_MASK; | ||
206 | |||
207 | if (own_cap.cap & IEEE80211_VHT_CAP_RXSTBC_MASK) | ||
208 | vht_cap->cap |= cap_info & IEEE80211_VHT_CAP_TXSTBC; | ||
39 | 209 | ||
40 | /* Copy peer MCS info, the driver might need them. */ | 210 | /* Copy peer MCS info, the driver might need them. */ |
41 | memcpy(&vht_cap->vht_mcs, &vht_cap_ie->supp_mcs, | 211 | memcpy(&vht_cap->vht_mcs, &vht_cap_ie->supp_mcs, |
42 | sizeof(struct ieee80211_vht_mcs_info)); | 212 | sizeof(struct ieee80211_vht_mcs_info)); |
43 | 213 | ||
214 | /* but also restrict MCSes */ | ||
215 | for (i = 0; i < 8; i++) { | ||
216 | u16 own_rx, own_tx, peer_rx, peer_tx; | ||
217 | |||
218 | own_rx = le16_to_cpu(own_cap.vht_mcs.rx_mcs_map); | ||
219 | own_rx = (own_rx >> i * 2) & IEEE80211_VHT_MCS_NOT_SUPPORTED; | ||
220 | |||
221 | own_tx = le16_to_cpu(own_cap.vht_mcs.tx_mcs_map); | ||
222 | own_tx = (own_tx >> i * 2) & IEEE80211_VHT_MCS_NOT_SUPPORTED; | ||
223 | |||
224 | peer_rx = le16_to_cpu(vht_cap->vht_mcs.rx_mcs_map); | ||
225 | peer_rx = (peer_rx >> i * 2) & IEEE80211_VHT_MCS_NOT_SUPPORTED; | ||
226 | |||
227 | peer_tx = le16_to_cpu(vht_cap->vht_mcs.tx_mcs_map); | ||
228 | peer_tx = (peer_tx >> i * 2) & IEEE80211_VHT_MCS_NOT_SUPPORTED; | ||
229 | |||
230 | if (peer_tx != IEEE80211_VHT_MCS_NOT_SUPPORTED) { | ||
231 | if (own_rx == IEEE80211_VHT_MCS_NOT_SUPPORTED) | ||
232 | peer_tx = IEEE80211_VHT_MCS_NOT_SUPPORTED; | ||
233 | else if (own_rx < peer_tx) | ||
234 | peer_tx = own_rx; | ||
235 | } | ||
236 | |||
237 | if (peer_rx != IEEE80211_VHT_MCS_NOT_SUPPORTED) { | ||
238 | if (own_tx == IEEE80211_VHT_MCS_NOT_SUPPORTED) | ||
239 | peer_rx = IEEE80211_VHT_MCS_NOT_SUPPORTED; | ||
240 | else if (own_tx < peer_rx) | ||
241 | peer_rx = own_tx; | ||
242 | } | ||
243 | |||
244 | vht_cap->vht_mcs.rx_mcs_map &= | ||
245 | ~cpu_to_le16(IEEE80211_VHT_MCS_NOT_SUPPORTED << i * 2); | ||
246 | vht_cap->vht_mcs.rx_mcs_map |= cpu_to_le16(peer_rx << i * 2); | ||
247 | |||
248 | vht_cap->vht_mcs.tx_mcs_map &= | ||
249 | ~cpu_to_le16(IEEE80211_VHT_MCS_NOT_SUPPORTED << i * 2); | ||
250 | vht_cap->vht_mcs.tx_mcs_map |= cpu_to_le16(peer_tx << i * 2); | ||
251 | } | ||
252 | |||
253 | /* finally set up the bandwidth */ | ||
44 | switch (vht_cap->cap & IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK) { | 254 | switch (vht_cap->cap & IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK) { |
45 | case IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ: | 255 | case IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ: |
46 | case IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ: | 256 | case IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ: |