.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
---|
1 | 2 | /* |
---|
2 | 3 | * Copyright (c) 2008, 2009 open80211s Ltd. |
---|
| 4 | + * Copyright (C) 2019 Intel Corporation |
---|
3 | 5 | * Author: Luis Carlos Cobo <luisca@cozybit.com> |
---|
4 | | - * |
---|
5 | | - * This program is free software; you can redistribute it and/or modify |
---|
6 | | - * it under the terms of the GNU General Public License version 2 as |
---|
7 | | - * published by the Free Software Foundation. |
---|
8 | 6 | */ |
---|
9 | 7 | #include <linux/gfp.h> |
---|
10 | 8 | #include <linux/kernel.h> |
---|
.. | .. |
---|
146 | 144 | |
---|
147 | 145 | /** |
---|
148 | 146 | * mesh_set_ht_prot_mode - set correct HT protection mode |
---|
| 147 | + * @sdata: the (mesh) interface to handle |
---|
149 | 148 | * |
---|
150 | 149 | * Section 9.23.3.5 of IEEE 80211-2012 describes the protection rules for HT |
---|
151 | 150 | * mesh STA in a MBSS. Three HT protection modes are supported for now, non-HT |
---|
.. | .. |
---|
220 | 219 | bool include_plid = false; |
---|
221 | 220 | u16 peering_proto = 0; |
---|
222 | 221 | u8 *pos, ie_len = 4; |
---|
| 222 | + u8 ie_len_he_cap; |
---|
223 | 223 | int hdr_len = offsetofend(struct ieee80211_mgmt, u.action.u.self_prot); |
---|
224 | 224 | int err = -ENOMEM; |
---|
225 | 225 | |
---|
| 226 | + ie_len_he_cap = ieee80211_ie_len_he_cap(sdata, |
---|
| 227 | + NL80211_IFTYPE_MESH_POINT); |
---|
226 | 228 | skb = dev_alloc_skb(local->tx_headroom + |
---|
227 | 229 | hdr_len + |
---|
228 | 230 | 2 + /* capability info */ |
---|
.. | .. |
---|
235 | 237 | 2 + sizeof(struct ieee80211_ht_operation) + |
---|
236 | 238 | 2 + sizeof(struct ieee80211_vht_cap) + |
---|
237 | 239 | 2 + sizeof(struct ieee80211_vht_operation) + |
---|
| 240 | + ie_len_he_cap + |
---|
| 241 | + 2 + 1 + sizeof(struct ieee80211_he_operation) + |
---|
| 242 | + sizeof(struct ieee80211_he_6ghz_oper) + |
---|
| 243 | + 2 + 1 + sizeof(struct ieee80211_he_6ghz_capa) + |
---|
238 | 244 | 2 + 8 + /* peering IE */ |
---|
239 | 245 | sdata->u.mesh.ie_len); |
---|
240 | 246 | if (!skb) |
---|
.. | .. |
---|
323 | 329 | if (mesh_add_ht_cap_ie(sdata, skb) || |
---|
324 | 330 | mesh_add_ht_oper_ie(sdata, skb) || |
---|
325 | 331 | mesh_add_vht_cap_ie(sdata, skb) || |
---|
326 | | - mesh_add_vht_oper_ie(sdata, skb)) |
---|
| 332 | + mesh_add_vht_oper_ie(sdata, skb) || |
---|
| 333 | + mesh_add_he_cap_ie(sdata, skb, ie_len_he_cap) || |
---|
| 334 | + mesh_add_he_oper_ie(sdata, skb) || |
---|
| 335 | + mesh_add_he_6ghz_cap_ie(sdata, skb)) |
---|
327 | 336 | goto free; |
---|
328 | 337 | } |
---|
329 | 338 | |
---|
.. | .. |
---|
435 | 444 | ieee80211_vht_cap_ie_to_sta_vht_cap(sdata, sband, |
---|
436 | 445 | elems->vht_cap_elem, sta); |
---|
437 | 446 | |
---|
| 447 | + ieee80211_he_cap_ie_to_sta_he_cap(sdata, sband, elems->he_cap, |
---|
| 448 | + elems->he_cap_len, |
---|
| 449 | + elems->he_6ghz_capa, |
---|
| 450 | + sta); |
---|
| 451 | + |
---|
438 | 452 | if (bw != sta->sta.bandwidth) |
---|
439 | 453 | changed |= IEEE80211_RC_BW_CHANGED; |
---|
440 | 454 | |
---|
.. | .. |
---|
513 | 527 | |
---|
514 | 528 | static struct sta_info * |
---|
515 | 529 | mesh_sta_info_alloc(struct ieee80211_sub_if_data *sdata, u8 *addr, |
---|
516 | | - struct ieee802_11_elems *elems) |
---|
| 530 | + struct ieee802_11_elems *elems, |
---|
| 531 | + struct ieee80211_rx_status *rx_status) |
---|
517 | 532 | { |
---|
518 | 533 | struct sta_info *sta = NULL; |
---|
519 | 534 | |
---|
.. | .. |
---|
521 | 536 | if (sdata->u.mesh.user_mpm || |
---|
522 | 537 | sdata->u.mesh.security & IEEE80211_MESH_SEC_AUTHED) { |
---|
523 | 538 | if (mesh_peer_accepts_plinks(elems) && |
---|
524 | | - mesh_plink_availables(sdata)) |
---|
| 539 | + mesh_plink_availables(sdata)) { |
---|
| 540 | + int sig = 0; |
---|
| 541 | + |
---|
| 542 | + if (ieee80211_hw_check(&sdata->local->hw, SIGNAL_DBM)) |
---|
| 543 | + sig = rx_status->signal; |
---|
| 544 | + |
---|
525 | 545 | cfg80211_notify_new_peer_candidate(sdata->dev, addr, |
---|
526 | 546 | elems->ie_start, |
---|
527 | 547 | elems->total_len, |
---|
528 | | - GFP_KERNEL); |
---|
| 548 | + sig, GFP_KERNEL); |
---|
| 549 | + } |
---|
529 | 550 | } else |
---|
530 | 551 | sta = __mesh_sta_info_alloc(sdata, addr); |
---|
531 | 552 | |
---|
.. | .. |
---|
538 | 559 | * @sdata: local meshif |
---|
539 | 560 | * @addr: peer's address |
---|
540 | 561 | * @elems: IEs from beacon or mesh peering frame. |
---|
| 562 | + * @rx_status: rx status for the frame for signal reporting |
---|
541 | 563 | * |
---|
542 | 564 | * Return existing or newly allocated sta_info under RCU read lock. |
---|
543 | 565 | * (re)initialize with given IEs. |
---|
544 | 566 | */ |
---|
545 | 567 | static struct sta_info * |
---|
546 | 568 | mesh_sta_info_get(struct ieee80211_sub_if_data *sdata, |
---|
547 | | - u8 *addr, struct ieee802_11_elems *elems) __acquires(RCU) |
---|
| 569 | + u8 *addr, struct ieee802_11_elems *elems, |
---|
| 570 | + struct ieee80211_rx_status *rx_status) __acquires(RCU) |
---|
548 | 571 | { |
---|
549 | 572 | struct sta_info *sta = NULL; |
---|
550 | 573 | |
---|
.. | .. |
---|
555 | 578 | } else { |
---|
556 | 579 | rcu_read_unlock(); |
---|
557 | 580 | /* can't run atomic */ |
---|
558 | | - sta = mesh_sta_info_alloc(sdata, addr, elems); |
---|
| 581 | + sta = mesh_sta_info_alloc(sdata, addr, elems, rx_status); |
---|
559 | 582 | if (!sta) { |
---|
560 | 583 | rcu_read_lock(); |
---|
561 | 584 | return NULL; |
---|
.. | .. |
---|
576 | 599 | * @sdata: local meshif |
---|
577 | 600 | * @addr: peer's address |
---|
578 | 601 | * @elems: IEs from beacon or mesh peering frame |
---|
| 602 | + * @rx_status: rx status for the frame for signal reporting |
---|
579 | 603 | * |
---|
580 | 604 | * Initiates peering if appropriate. |
---|
581 | 605 | */ |
---|
582 | 606 | void mesh_neighbour_update(struct ieee80211_sub_if_data *sdata, |
---|
583 | 607 | u8 *hw_addr, |
---|
584 | | - struct ieee802_11_elems *elems) |
---|
| 608 | + struct ieee802_11_elems *elems, |
---|
| 609 | + struct ieee80211_rx_status *rx_status) |
---|
585 | 610 | { |
---|
586 | 611 | struct sta_info *sta; |
---|
587 | 612 | u32 changed = 0; |
---|
588 | 613 | |
---|
589 | | - sta = mesh_sta_info_get(sdata, hw_addr, elems); |
---|
| 614 | + sta = mesh_sta_info_get(sdata, hw_addr, elems, rx_status); |
---|
590 | 615 | if (!sta) |
---|
591 | 616 | goto out; |
---|
| 617 | + |
---|
| 618 | + sta->mesh->connected_to_gate = elems->mesh_config->meshconf_form & |
---|
| 619 | + IEEE80211_MESHCONF_FORM_CONNECTED_TO_GATE; |
---|
592 | 620 | |
---|
593 | 621 | if (mesh_peer_accepts_plinks(elems) && |
---|
594 | 622 | sta->mesh->plink_state == NL80211_PLINK_LISTEN && |
---|
.. | .. |
---|
672 | 700 | break; |
---|
673 | 701 | } |
---|
674 | 702 | reason = WLAN_REASON_MESH_MAX_RETRIES; |
---|
675 | | - /* fall through */ |
---|
| 703 | + fallthrough; |
---|
676 | 704 | case NL80211_PLINK_CNF_RCVD: |
---|
677 | 705 | /* confirm timer */ |
---|
678 | 706 | if (!reason) |
---|
.. | .. |
---|
1069 | 1097 | static void |
---|
1070 | 1098 | mesh_process_plink_frame(struct ieee80211_sub_if_data *sdata, |
---|
1071 | 1099 | struct ieee80211_mgmt *mgmt, |
---|
1072 | | - struct ieee802_11_elems *elems) |
---|
| 1100 | + struct ieee802_11_elems *elems, |
---|
| 1101 | + struct ieee80211_rx_status *rx_status) |
---|
1073 | 1102 | { |
---|
1074 | 1103 | |
---|
1075 | 1104 | struct sta_info *sta; |
---|
.. | .. |
---|
1134 | 1163 | if (event == OPN_ACPT) { |
---|
1135 | 1164 | rcu_read_unlock(); |
---|
1136 | 1165 | /* allocate sta entry if necessary and update info */ |
---|
1137 | | - sta = mesh_sta_info_get(sdata, mgmt->sa, elems); |
---|
| 1166 | + sta = mesh_sta_info_get(sdata, mgmt->sa, elems, rx_status); |
---|
1138 | 1167 | if (!sta) { |
---|
1139 | 1168 | mpl_dbg(sdata, "Mesh plink: failed to init peer!\n"); |
---|
1140 | 1169 | goto unlock_rcu; |
---|
.. | .. |
---|
1199 | 1228 | if (baselen > len) |
---|
1200 | 1229 | return; |
---|
1201 | 1230 | } |
---|
1202 | | - ieee802_11_parse_elems(baseaddr, len - baselen, true, &elems); |
---|
1203 | | - mesh_process_plink_frame(sdata, mgmt, &elems); |
---|
| 1231 | + ieee802_11_parse_elems(baseaddr, len - baselen, true, &elems, |
---|
| 1232 | + mgmt->bssid, NULL); |
---|
| 1233 | + mesh_process_plink_frame(sdata, mgmt, &elems, rx_status); |
---|
1204 | 1234 | } |
---|