diff options
-rw-r--r-- | net/mac80211/cfg.c | 21 | ||||
-rw-r--r-- | net/mac80211/ibss.c | 54 | ||||
-rw-r--r-- | net/mac80211/ieee80211_i.h | 2 | ||||
-rw-r--r-- | net/mac80211/util.c | 87 | ||||
-rw-r--r-- | net/wireless/nl80211.c | 1 |
5 files changed, 111 insertions, 54 deletions
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 67f62dac54f5..8cdbd29cbc45 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c | |||
@@ -3014,6 +3014,7 @@ static int ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev, | |||
3014 | struct ieee80211_local *local = sdata->local; | 3014 | struct ieee80211_local *local = sdata->local; |
3015 | struct ieee80211_chanctx_conf *chanctx_conf; | 3015 | struct ieee80211_chanctx_conf *chanctx_conf; |
3016 | struct ieee80211_chanctx *chanctx; | 3016 | struct ieee80211_chanctx *chanctx; |
3017 | struct ieee80211_if_mesh __maybe_unused *ifmsh; | ||
3017 | int err, num_chanctx; | 3018 | int err, num_chanctx; |
3018 | 3019 | ||
3019 | if (!list_empty(&local->roc_list) || local->scanning) | 3020 | if (!list_empty(&local->roc_list) || local->scanning) |
@@ -3097,6 +3098,26 @@ static int ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev, | |||
3097 | if (err < 0) | 3098 | if (err < 0) |
3098 | return err; | 3099 | return err; |
3099 | break; | 3100 | break; |
3101 | #ifdef CONFIG_MAC80211_MESH | ||
3102 | case NL80211_IFTYPE_MESH_POINT: | ||
3103 | ifmsh = &sdata->u.mesh; | ||
3104 | |||
3105 | if (!ifmsh->mesh_id) | ||
3106 | return -EINVAL; | ||
3107 | |||
3108 | if (params->chandef.width != sdata->vif.bss_conf.chandef.width) | ||
3109 | return -EINVAL; | ||
3110 | |||
3111 | /* changes into another band are not supported */ | ||
3112 | if (sdata->vif.bss_conf.chandef.chan->band != | ||
3113 | params->chandef.chan->band) | ||
3114 | return -EINVAL; | ||
3115 | |||
3116 | err = ieee80211_send_action_csa(sdata, params); | ||
3117 | if (err < 0) | ||
3118 | return err; | ||
3119 | break; | ||
3120 | #endif | ||
3100 | default: | 3121 | default: |
3101 | return -EOPNOTSUPP; | 3122 | return -EOPNOTSUPP; |
3102 | } | 3123 | } |
diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c index a0ae02760139..531be040b9ae 100644 --- a/net/mac80211/ibss.c +++ b/net/mac80211/ibss.c | |||
@@ -464,60 +464,6 @@ static void ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, | |||
464 | tsf, false); | 464 | tsf, false); |
465 | } | 465 | } |
466 | 466 | ||
467 | static int ieee80211_send_action_csa(struct ieee80211_sub_if_data *sdata, | ||
468 | struct cfg80211_csa_settings *csa_settings) | ||
469 | { | ||
470 | struct sk_buff *skb; | ||
471 | struct ieee80211_mgmt *mgmt; | ||
472 | struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; | ||
473 | struct ieee80211_local *local = sdata->local; | ||
474 | int freq; | ||
475 | int hdr_len = offsetof(struct ieee80211_mgmt, u.action.u.chan_switch) + | ||
476 | sizeof(mgmt->u.action.u.chan_switch); | ||
477 | u8 *pos; | ||
478 | |||
479 | skb = dev_alloc_skb(local->tx_headroom + hdr_len + | ||
480 | 5 + /* channel switch announcement element */ | ||
481 | 3); /* secondary channel offset element */ | ||
482 | if (!skb) | ||
483 | return -1; | ||
484 | |||
485 | skb_reserve(skb, local->tx_headroom); | ||
486 | mgmt = (struct ieee80211_mgmt *)skb_put(skb, hdr_len); | ||
487 | memset(mgmt, 0, hdr_len); | ||
488 | mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | | ||
489 | IEEE80211_STYPE_ACTION); | ||
490 | |||
491 | eth_broadcast_addr(mgmt->da); | ||
492 | memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN); | ||
493 | memcpy(mgmt->bssid, ifibss->bssid, ETH_ALEN); | ||
494 | mgmt->u.action.category = WLAN_CATEGORY_SPECTRUM_MGMT; | ||
495 | mgmt->u.action.u.chan_switch.action_code = WLAN_ACTION_SPCT_CHL_SWITCH; | ||
496 | pos = skb_put(skb, 5); | ||
497 | *pos++ = WLAN_EID_CHANNEL_SWITCH; /* EID */ | ||
498 | *pos++ = 3; /* IE length */ | ||
499 | *pos++ = csa_settings->block_tx ? 1 : 0; /* CSA mode */ | ||
500 | freq = csa_settings->chandef.chan->center_freq; | ||
501 | *pos++ = ieee80211_frequency_to_channel(freq); /* channel */ | ||
502 | *pos++ = csa_settings->count; /* count */ | ||
503 | |||
504 | if (csa_settings->chandef.width == NL80211_CHAN_WIDTH_40) { | ||
505 | enum nl80211_channel_type ch_type; | ||
506 | |||
507 | skb_put(skb, 3); | ||
508 | *pos++ = WLAN_EID_SECONDARY_CHANNEL_OFFSET; /* EID */ | ||
509 | *pos++ = 1; /* IE length */ | ||
510 | ch_type = cfg80211_get_chandef_type(&csa_settings->chandef); | ||
511 | if (ch_type == NL80211_CHAN_HT40PLUS) | ||
512 | *pos++ = IEEE80211_HT_PARAM_CHA_SEC_ABOVE; | ||
513 | else | ||
514 | *pos++ = IEEE80211_HT_PARAM_CHA_SEC_BELOW; | ||
515 | } | ||
516 | |||
517 | ieee80211_tx_skb(sdata, skb); | ||
518 | return 0; | ||
519 | } | ||
520 | |||
521 | int ieee80211_ibss_csa_beacon(struct ieee80211_sub_if_data *sdata, | 467 | int ieee80211_ibss_csa_beacon(struct ieee80211_sub_if_data *sdata, |
522 | struct cfg80211_csa_settings *csa_settings) | 468 | struct cfg80211_csa_settings *csa_settings) |
523 | { | 469 | { |
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 4ebbcc6f67e0..9aad167e2ebc 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h | |||
@@ -1731,6 +1731,8 @@ void ieee80211_dfs_cac_timer(unsigned long data); | |||
1731 | void ieee80211_dfs_cac_timer_work(struct work_struct *work); | 1731 | void ieee80211_dfs_cac_timer_work(struct work_struct *work); |
1732 | void ieee80211_dfs_cac_cancel(struct ieee80211_local *local); | 1732 | void ieee80211_dfs_cac_cancel(struct ieee80211_local *local); |
1733 | void ieee80211_dfs_radar_detected_work(struct work_struct *work); | 1733 | void ieee80211_dfs_radar_detected_work(struct work_struct *work); |
1734 | int ieee80211_send_action_csa(struct ieee80211_sub_if_data *sdata, | ||
1735 | struct cfg80211_csa_settings *csa_settings); | ||
1734 | 1736 | ||
1735 | #ifdef CONFIG_MAC80211_NOINLINE | 1737 | #ifdef CONFIG_MAC80211_NOINLINE |
1736 | #define debug_noinline noinline | 1738 | #define debug_noinline noinline |
diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 523783cedf6e..a38d58231af8 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c | |||
@@ -2384,3 +2384,90 @@ bool ieee80211_smps_is_restrictive(enum ieee80211_smps_mode smps_mode_old, | |||
2384 | 2384 | ||
2385 | return false; | 2385 | return false; |
2386 | } | 2386 | } |
2387 | |||
2388 | int ieee80211_send_action_csa(struct ieee80211_sub_if_data *sdata, | ||
2389 | struct cfg80211_csa_settings *csa_settings) | ||
2390 | { | ||
2391 | struct sk_buff *skb; | ||
2392 | struct ieee80211_mgmt *mgmt; | ||
2393 | struct ieee80211_local *local = sdata->local; | ||
2394 | int freq; | ||
2395 | int hdr_len = offsetof(struct ieee80211_mgmt, u.action.u.chan_switch) + | ||
2396 | sizeof(mgmt->u.action.u.chan_switch); | ||
2397 | u8 *pos; | ||
2398 | |||
2399 | if (sdata->vif.type != NL80211_IFTYPE_ADHOC && | ||
2400 | sdata->vif.type != NL80211_IFTYPE_MESH_POINT) | ||
2401 | return -EOPNOTSUPP; | ||
2402 | |||
2403 | skb = dev_alloc_skb(local->tx_headroom + hdr_len + | ||
2404 | 5 + /* channel switch announcement element */ | ||
2405 | 3 + /* secondary channel offset element */ | ||
2406 | 8); /* mesh channel switch parameters element */ | ||
2407 | if (!skb) | ||
2408 | return -ENOMEM; | ||
2409 | |||
2410 | skb_reserve(skb, local->tx_headroom); | ||
2411 | mgmt = (struct ieee80211_mgmt *)skb_put(skb, hdr_len); | ||
2412 | memset(mgmt, 0, hdr_len); | ||
2413 | mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | | ||
2414 | IEEE80211_STYPE_ACTION); | ||
2415 | |||
2416 | eth_broadcast_addr(mgmt->da); | ||
2417 | memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN); | ||
2418 | if (ieee80211_vif_is_mesh(&sdata->vif)) { | ||
2419 | memcpy(mgmt->bssid, sdata->vif.addr, ETH_ALEN); | ||
2420 | } else { | ||
2421 | struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; | ||
2422 | memcpy(mgmt->bssid, ifibss->bssid, ETH_ALEN); | ||
2423 | } | ||
2424 | mgmt->u.action.category = WLAN_CATEGORY_SPECTRUM_MGMT; | ||
2425 | mgmt->u.action.u.chan_switch.action_code = WLAN_ACTION_SPCT_CHL_SWITCH; | ||
2426 | pos = skb_put(skb, 5); | ||
2427 | *pos++ = WLAN_EID_CHANNEL_SWITCH; /* EID */ | ||
2428 | *pos++ = 3; /* IE length */ | ||
2429 | *pos++ = csa_settings->block_tx ? 1 : 0; /* CSA mode */ | ||
2430 | freq = csa_settings->chandef.chan->center_freq; | ||
2431 | *pos++ = ieee80211_frequency_to_channel(freq); /* channel */ | ||
2432 | *pos++ = csa_settings->count; /* count */ | ||
2433 | |||
2434 | if (csa_settings->chandef.width == NL80211_CHAN_WIDTH_40) { | ||
2435 | enum nl80211_channel_type ch_type; | ||
2436 | |||
2437 | skb_put(skb, 3); | ||
2438 | *pos++ = WLAN_EID_SECONDARY_CHANNEL_OFFSET; /* EID */ | ||
2439 | *pos++ = 1; /* IE length */ | ||
2440 | ch_type = cfg80211_get_chandef_type(&csa_settings->chandef); | ||
2441 | if (ch_type == NL80211_CHAN_HT40PLUS) | ||
2442 | *pos++ = IEEE80211_HT_PARAM_CHA_SEC_ABOVE; | ||
2443 | else | ||
2444 | *pos++ = IEEE80211_HT_PARAM_CHA_SEC_BELOW; | ||
2445 | } | ||
2446 | |||
2447 | if (ieee80211_vif_is_mesh(&sdata->vif)) { | ||
2448 | struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; | ||
2449 | __le16 pre_value; | ||
2450 | |||
2451 | skb_put(skb, 8); | ||
2452 | *pos++ = WLAN_EID_CHAN_SWITCH_PARAM; /* EID */ | ||
2453 | *pos++ = 6; /* IE length */ | ||
2454 | *pos++ = sdata->u.mesh.mshcfg.dot11MeshTTL; /* Mesh TTL */ | ||
2455 | *pos = 0x00; /* Mesh Flag: Tx Restrict, Initiator, Reason */ | ||
2456 | *pos |= WLAN_EID_CHAN_SWITCH_PARAM_INITIATOR; | ||
2457 | *pos++ |= csa_settings->block_tx ? | ||
2458 | WLAN_EID_CHAN_SWITCH_PARAM_TX_RESTRICT : 0x00; | ||
2459 | put_unaligned_le16(WLAN_REASON_MESH_CHAN, pos); /* Reason Cd */ | ||
2460 | pos += 2; | ||
2461 | if (!ifmsh->pre_value) | ||
2462 | ifmsh->pre_value = 1; | ||
2463 | else | ||
2464 | ifmsh->pre_value++; | ||
2465 | pre_value = cpu_to_le16(ifmsh->pre_value); | ||
2466 | memcpy(pos, &pre_value, 2); /* Precedence Value */ | ||
2467 | pos += 2; | ||
2468 | ifmsh->chsw_init = true; | ||
2469 | } | ||
2470 | |||
2471 | ieee80211_tx_skb(sdata, skb); | ||
2472 | return 0; | ||
2473 | } | ||
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 7502d33a3a70..b8d6f101378a 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c | |||
@@ -5700,6 +5700,7 @@ static int nl80211_channel_switch(struct sk_buff *skb, struct genl_info *info) | |||
5700 | return -EINVAL; | 5700 | return -EINVAL; |
5701 | break; | 5701 | break; |
5702 | case NL80211_IFTYPE_ADHOC: | 5702 | case NL80211_IFTYPE_ADHOC: |
5703 | case NL80211_IFTYPE_MESH_POINT: | ||
5703 | break; | 5704 | break; |
5704 | default: | 5705 | default: |
5705 | return -EOPNOTSUPP; | 5706 | return -EOPNOTSUPP; |