mirror of
https://github.com/immortalwrt/immortalwrt
synced 2025-01-09 04:29:03 +08:00
Merge Official Source
Signed-off-by: Tianling Shen <cnsztl@immortalwrt.org>
This commit is contained in:
commit
134c057fd0
@ -424,3 +424,33 @@
|
||||
}
|
||||
|
||||
|
||||
--- a/src/ap/wnm_ap.c
|
||||
+++ b/src/ap/wnm_ap.c
|
||||
@@ -463,7 +463,7 @@ static void ieee802_11_rx_bss_trans_mgmt
|
||||
size_t len)
|
||||
{
|
||||
u8 dialog_token, status_code, bss_termination_delay;
|
||||
- const u8 *pos, *end;
|
||||
+ const u8 *pos, *end, *target_bssid;
|
||||
int enabled = hapd->conf->bss_transition;
|
||||
struct sta_info *sta;
|
||||
|
||||
@@ -510,6 +510,7 @@ static void ieee802_11_rx_bss_trans_mgmt
|
||||
wpa_printf(MSG_DEBUG, "WNM: not enough room for Target BSSID field");
|
||||
return;
|
||||
}
|
||||
+ target_bssid = pos;
|
||||
sta->agreed_to_steer = 1;
|
||||
eloop_cancel_timeout(ap_sta_reset_steer_flag_timer, hapd, sta);
|
||||
eloop_register_timeout(2, 0, ap_sta_reset_steer_flag_timer,
|
||||
@@ -529,6 +530,10 @@ static void ieee802_11_rx_bss_trans_mgmt
|
||||
MAC2STR(addr), status_code, bss_termination_delay);
|
||||
}
|
||||
|
||||
+ hostapd_ubus_notify_bss_transition_response(hapd, sta->addr, dialog_token,
|
||||
+ status_code, bss_termination_delay,
|
||||
+ target_bssid, pos, end - pos);
|
||||
+
|
||||
wpa_hexdump(MSG_DEBUG, "WNM: BSS Transition Candidate List Entries",
|
||||
pos, end - pos);
|
||||
}
|
||||
|
@ -318,6 +318,16 @@ hostapd_bss_get_clients(struct ubus_context *ctx, struct ubus_object *obj,
|
||||
for (i = 0; i < ARRAY_SIZE(sta->rrm_enabled_capa); i++)
|
||||
blobmsg_add_u32(&b, "", sta->rrm_enabled_capa[i]);
|
||||
blobmsg_close_array(&b, r);
|
||||
|
||||
r = blobmsg_open_array(&b, "extended_capabilities");
|
||||
/* Check if client advertises extended capabilities */
|
||||
if (sta->ext_capability && sta->ext_capability[0] > 0) {
|
||||
for (i = 0; i < sta->ext_capability[0]; i++) {
|
||||
blobmsg_add_u32(&b, "", sta->ext_capability[1 + i]);
|
||||
}
|
||||
}
|
||||
blobmsg_close_array(&b, r);
|
||||
|
||||
blobmsg_add_u32(&b, "aid", sta->aid);
|
||||
#ifdef CONFIG_TAXONOMY
|
||||
r = blobmsg_alloc_string_buffer(&b, "signature", 1024);
|
||||
@ -372,6 +382,32 @@ hostapd_bss_get_features(struct ubus_context *ctx, struct ubus_object *obj,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Imported from iw/util.c
|
||||
* https://git.kernel.org/pub/scm/linux/kernel/git/jberg/iw.git/tree/util.c?id=4b25ae3537af48dbf9d0abf94132e5ba01b32c18#n200
|
||||
*/
|
||||
int ieee80211_frequency_to_channel(int freq)
|
||||
{
|
||||
/* see 802.11-2007 17.3.8.3.2 and Annex J */
|
||||
if (freq == 2484)
|
||||
return 14;
|
||||
/* see 802.11ax D6.1 27.3.23.2 and Annex E */
|
||||
else if (freq == 5935)
|
||||
return 2;
|
||||
else if (freq < 2484)
|
||||
return (freq - 2407) / 5;
|
||||
else if (freq >= 4910 && freq <= 4980)
|
||||
return (freq - 4000) / 5;
|
||||
else if (freq < 5950)
|
||||
return (freq - 5000) / 5;
|
||||
else if (freq <= 45000) /* DMG band lower limit */
|
||||
/* see 802.11ax D6.1 27.3.23.2 */
|
||||
return (freq - 5950) / 5;
|
||||
else if (freq >= 58320 && freq <= 70200)
|
||||
return (freq - 56160) / 2160;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
hostapd_bss_get_status(struct ubus_context *ctx, struct ubus_object *obj,
|
||||
struct ubus_request_data *req, const char *method,
|
||||
@ -380,12 +416,31 @@ hostapd_bss_get_status(struct ubus_context *ctx, struct ubus_object *obj,
|
||||
struct hostapd_data *hapd = container_of(obj, struct hostapd_data, ubus.obj);
|
||||
void *airtime_table, *dfs_table;
|
||||
struct os_reltime now;
|
||||
char ssid[SSID_MAX_LEN + 1];
|
||||
char phy_name[17];
|
||||
char mac_buf[20];
|
||||
size_t ssid_len = SSID_MAX_LEN;
|
||||
u8 channel = 0, op_class = 0;
|
||||
|
||||
if (hapd->conf->ssid.ssid_len < SSID_MAX_LEN)
|
||||
ssid_len = hapd->conf->ssid.ssid_len;
|
||||
|
||||
ieee80211_freq_to_channel_ext(hapd->iface->freq,
|
||||
hapd->iconf->secondary_channel,
|
||||
hostapd_get_oper_chwidth(hapd->iconf),
|
||||
&op_class, &channel);
|
||||
|
||||
blob_buf_init(&b, 0);
|
||||
blobmsg_add_string(&b, "status", hostapd_state_text(hapd->iface->state));
|
||||
blobmsg_printf(&b, "bssid", MACSTR, MAC2STR(hapd->conf->bssid));
|
||||
|
||||
memset(ssid, 0, SSID_MAX_LEN + 1);
|
||||
memcpy(ssid, hapd->conf->ssid.ssid, ssid_len);
|
||||
blobmsg_add_string(&b, "ssid", ssid);
|
||||
|
||||
blobmsg_add_u32(&b, "freq", hapd->iface->freq);
|
||||
blobmsg_add_u32(&b, "channel", channel);
|
||||
blobmsg_add_u32(&b, "op_class", op_class);
|
||||
blobmsg_add_u32(&b, "beacon_interval", hapd->iconf->beacon_int);
|
||||
|
||||
snprintf(phy_name, 17, "%s", hapd->iface->phy);
|
||||
blobmsg_add_string(&b, "phy", phy_name);
|
||||
@ -1185,6 +1240,129 @@ hostapd_rrm_beacon_req(struct ubus_context *ctx, struct ubus_object *obj,
|
||||
|
||||
|
||||
#ifdef CONFIG_WNM_AP
|
||||
|
||||
static int
|
||||
hostapd_bss_tr_send(struct hostapd_data *hapd, u8 *addr, bool disassoc_imminent, bool abridged,
|
||||
u16 disassoc_timer, u8 validity_period, struct blob_attr *neighbors)
|
||||
{
|
||||
struct blob_attr *cur;
|
||||
struct sta_info *sta;
|
||||
int nr_len = 0;
|
||||
int rem;
|
||||
u8 *nr = NULL;
|
||||
u8 req_mode = 0;
|
||||
|
||||
sta = ap_get_sta(hapd, addr);
|
||||
if (!sta)
|
||||
return UBUS_STATUS_NOT_FOUND;
|
||||
|
||||
if (neighbors) {
|
||||
u8 *nr_cur;
|
||||
|
||||
if (blobmsg_check_array(neighbors,
|
||||
BLOBMSG_TYPE_STRING) < 0)
|
||||
return UBUS_STATUS_INVALID_ARGUMENT;
|
||||
|
||||
blobmsg_for_each_attr(cur, neighbors, rem) {
|
||||
int len = strlen(blobmsg_get_string(cur));
|
||||
|
||||
if (len % 2)
|
||||
return UBUS_STATUS_INVALID_ARGUMENT;
|
||||
|
||||
nr_len += (len / 2) + 2;
|
||||
}
|
||||
|
||||
if (nr_len) {
|
||||
nr = os_zalloc(nr_len);
|
||||
if (!nr)
|
||||
return UBUS_STATUS_UNKNOWN_ERROR;
|
||||
}
|
||||
|
||||
nr_cur = nr;
|
||||
blobmsg_for_each_attr(cur, neighbors, rem) {
|
||||
int len = strlen(blobmsg_get_string(cur)) / 2;
|
||||
|
||||
*nr_cur++ = WLAN_EID_NEIGHBOR_REPORT;
|
||||
*nr_cur++ = (u8) len;
|
||||
if (hexstr2bin(blobmsg_data(cur), nr_cur, len)) {
|
||||
free(nr);
|
||||
return UBUS_STATUS_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
nr_cur += len;
|
||||
}
|
||||
}
|
||||
|
||||
if (nr)
|
||||
req_mode |= WNM_BSS_TM_REQ_PREF_CAND_LIST_INCLUDED;
|
||||
|
||||
if (abridged)
|
||||
req_mode |= WNM_BSS_TM_REQ_ABRIDGED;
|
||||
|
||||
if (disassoc_imminent)
|
||||
req_mode |= WNM_BSS_TM_REQ_DISASSOC_IMMINENT;
|
||||
|
||||
if (wnm_send_bss_tm_req(hapd, sta, req_mode, disassoc_timer, validity_period, NULL,
|
||||
NULL, nr, nr_len, NULL, 0))
|
||||
return UBUS_STATUS_UNKNOWN_ERROR;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
enum {
|
||||
BSS_TR_ADDR,
|
||||
BSS_TR_DA_IMMINENT,
|
||||
BSS_TR_DA_TIMER,
|
||||
BSS_TR_VALID_PERIOD,
|
||||
BSS_TR_NEIGHBORS,
|
||||
BSS_TR_ABRIDGED,
|
||||
__BSS_TR_DISASSOC_MAX
|
||||
};
|
||||
|
||||
static const struct blobmsg_policy bss_tr_policy[__BSS_TR_DISASSOC_MAX] = {
|
||||
[BSS_TR_ADDR] = { "addr", BLOBMSG_TYPE_STRING },
|
||||
[BSS_TR_DA_IMMINENT] = { "disassociation_imminent", BLOBMSG_TYPE_BOOL },
|
||||
[BSS_TR_DA_TIMER] = { "disassociation_timer", BLOBMSG_TYPE_INT32 },
|
||||
[BSS_TR_VALID_PERIOD] = { "validity_period", BLOBMSG_TYPE_INT32 },
|
||||
[BSS_TR_NEIGHBORS] = { "neighbors", BLOBMSG_TYPE_ARRAY },
|
||||
[BSS_TR_ABRIDGED] = { "abridged", BLOBMSG_TYPE_BOOL },
|
||||
};
|
||||
|
||||
static int
|
||||
hostapd_bss_transition_request(struct ubus_context *ctx, struct ubus_object *obj,
|
||||
struct ubus_request_data *ureq, const char *method,
|
||||
struct blob_attr *msg)
|
||||
{
|
||||
struct hostapd_data *hapd = container_of(obj, struct hostapd_data, ubus.obj);
|
||||
struct blob_attr *tb[__BSS_TR_DISASSOC_MAX];
|
||||
struct sta_info *sta;
|
||||
u32 da_timer = 0;
|
||||
u32 valid_period = 0;
|
||||
u8 addr[ETH_ALEN];
|
||||
bool abridged;
|
||||
bool da_imminent;
|
||||
|
||||
blobmsg_parse(bss_tr_policy, __BSS_TR_DISASSOC_MAX, tb, blob_data(msg), blob_len(msg));
|
||||
|
||||
if (!tb[BSS_TR_ADDR])
|
||||
return UBUS_STATUS_INVALID_ARGUMENT;
|
||||
|
||||
if (hwaddr_aton(blobmsg_data(tb[BSS_TR_ADDR]), addr))
|
||||
return UBUS_STATUS_INVALID_ARGUMENT;
|
||||
|
||||
if (tb[BSS_TR_DA_TIMER])
|
||||
da_timer = blobmsg_get_u32(tb[BSS_TR_DA_TIMER]);
|
||||
|
||||
if (tb[BSS_TR_VALID_PERIOD])
|
||||
valid_period = blobmsg_get_u32(tb[BSS_TR_VALID_PERIOD]);
|
||||
|
||||
da_imminent = !!(tb[BSS_TR_DA_IMMINENT] && blobmsg_get_bool(tb[BSS_TR_DA_IMMINENT]));
|
||||
abridged = !!(tb[BSS_TR_ABRIDGED] && blobmsg_get_bool(tb[BSS_TR_ABRIDGED]));
|
||||
|
||||
return hostapd_bss_tr_send(hapd, addr, da_imminent, abridged, da_timer, valid_period,
|
||||
tb[BSS_TR_NEIGHBORS]);
|
||||
}
|
||||
|
||||
enum {
|
||||
WNM_DISASSOC_ADDR,
|
||||
WNM_DISASSOC_DURATION,
|
||||
@ -1207,14 +1385,10 @@ hostapd_wnm_disassoc_imminent(struct ubus_context *ctx, struct ubus_object *obj,
|
||||
{
|
||||
struct hostapd_data *hapd = container_of(obj, struct hostapd_data, ubus.obj);
|
||||
struct blob_attr *tb[__WNM_DISASSOC_MAX];
|
||||
struct blob_attr *cur;
|
||||
struct sta_info *sta;
|
||||
int duration = 10;
|
||||
int rem;
|
||||
int nr_len = 0;
|
||||
u8 *nr = NULL;
|
||||
u8 req_mode = WNM_BSS_TM_REQ_DISASSOC_IMMINENT;
|
||||
u8 addr[ETH_ALEN];
|
||||
bool abridged;
|
||||
|
||||
blobmsg_parse(wnm_disassoc_policy, __WNM_DISASSOC_MAX, tb, blob_data(msg), blob_len(msg));
|
||||
|
||||
@ -1224,61 +1398,13 @@ hostapd_wnm_disassoc_imminent(struct ubus_context *ctx, struct ubus_object *obj,
|
||||
if (hwaddr_aton(blobmsg_data(tb[WNM_DISASSOC_ADDR]), addr))
|
||||
return UBUS_STATUS_INVALID_ARGUMENT;
|
||||
|
||||
if ((cur = tb[WNM_DISASSOC_DURATION]) != NULL)
|
||||
duration = blobmsg_get_u32(cur);
|
||||
if (tb[WNM_DISASSOC_DURATION])
|
||||
duration = blobmsg_get_u32(tb[WNM_DISASSOC_DURATION]);
|
||||
|
||||
sta = ap_get_sta(hapd, addr);
|
||||
if (!sta)
|
||||
return UBUS_STATUS_NOT_FOUND;
|
||||
abridged = !!(tb[WNM_DISASSOC_ABRIDGED] && blobmsg_get_bool(tb[WNM_DISASSOC_ABRIDGED]));
|
||||
|
||||
if (tb[WNM_DISASSOC_NEIGHBORS]) {
|
||||
u8 *nr_cur;
|
||||
|
||||
if (blobmsg_check_array(tb[WNM_DISASSOC_NEIGHBORS],
|
||||
BLOBMSG_TYPE_STRING) < 0)
|
||||
return UBUS_STATUS_INVALID_ARGUMENT;
|
||||
|
||||
blobmsg_for_each_attr(cur, tb[WNM_DISASSOC_NEIGHBORS], rem) {
|
||||
int len = strlen(blobmsg_get_string(cur));
|
||||
|
||||
if (len % 2)
|
||||
return UBUS_STATUS_INVALID_ARGUMENT;
|
||||
|
||||
nr_len += (len / 2) + 2;
|
||||
}
|
||||
|
||||
if (nr_len) {
|
||||
nr = os_zalloc(nr_len);
|
||||
if (!nr)
|
||||
return UBUS_STATUS_UNKNOWN_ERROR;
|
||||
}
|
||||
|
||||
nr_cur = nr;
|
||||
blobmsg_for_each_attr(cur, tb[WNM_DISASSOC_NEIGHBORS], rem) {
|
||||
int len = strlen(blobmsg_get_string(cur)) / 2;
|
||||
|
||||
*nr_cur++ = WLAN_EID_NEIGHBOR_REPORT;
|
||||
*nr_cur++ = (u8) len;
|
||||
if (hexstr2bin(blobmsg_data(cur), nr_cur, len)) {
|
||||
free(nr);
|
||||
return UBUS_STATUS_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
nr_cur += len;
|
||||
}
|
||||
}
|
||||
|
||||
if (nr)
|
||||
req_mode |= WNM_BSS_TM_REQ_PREF_CAND_LIST_INCLUDED;
|
||||
|
||||
if (tb[WNM_DISASSOC_ABRIDGED] && blobmsg_get_bool(tb[WNM_DISASSOC_ABRIDGED]))
|
||||
req_mode |= WNM_BSS_TM_REQ_ABRIDGED;
|
||||
|
||||
if (wnm_send_bss_tm_req(hapd, sta, req_mode, duration, duration, NULL,
|
||||
NULL, nr, nr_len, NULL, 0))
|
||||
return UBUS_STATUS_UNKNOWN_ERROR;
|
||||
|
||||
return 0;
|
||||
return hostapd_bss_tr_send(hapd, addr, true, abridged, duration, duration,
|
||||
tb[WNM_DISASSOC_NEIGHBORS]);
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -1307,6 +1433,7 @@ static const struct ubus_method bss_methods[] = {
|
||||
UBUS_METHOD("rrm_beacon_req", hostapd_rrm_beacon_req, beacon_req_policy),
|
||||
#ifdef CONFIG_WNM_AP
|
||||
UBUS_METHOD("wnm_disassoc_imminent", hostapd_wnm_disassoc_imminent, wnm_disassoc_policy),
|
||||
UBUS_METHOD("bss_transition_request", hostapd_bss_transition_request, bss_tr_policy),
|
||||
#endif
|
||||
};
|
||||
|
||||
@ -1555,3 +1682,36 @@ void hostapd_ubus_notify_beacon_report(
|
||||
|
||||
ubus_notify(ctx, &hapd->ubus.obj, "beacon-report", b.head, -1);
|
||||
}
|
||||
|
||||
void hostapd_ubus_notify_bss_transition_response(
|
||||
struct hostapd_data *hapd, const u8 *addr, u8 dialog_token, u8 status_code,
|
||||
u8 bss_termination_delay, const u8 *target_bssid,
|
||||
const u8 *candidate_list, u16 candidate_list_len)
|
||||
{
|
||||
#ifdef CONFIG_WNM_AP
|
||||
char *cl_str;
|
||||
u16 i;
|
||||
|
||||
if (!hapd->ubus.obj.has_subscribers)
|
||||
return;
|
||||
|
||||
if (!addr)
|
||||
return;
|
||||
|
||||
blob_buf_init(&b, 0);
|
||||
blobmsg_add_macaddr(&b, "address", addr);
|
||||
blobmsg_add_u8(&b, "dialog-token", dialog_token);
|
||||
blobmsg_add_u8(&b, "status-code", status_code);
|
||||
blobmsg_add_u8(&b, "bss-termination-delay", bss_termination_delay);
|
||||
if (target_bssid)
|
||||
blobmsg_add_macaddr(&b, "target-bssid", target_bssid);
|
||||
if (candidate_list_len > 0) {
|
||||
cl_str = blobmsg_alloc_string_buffer(&b, "candidate-list", candidate_list_len * 2 + 1);
|
||||
for (i = 0; i < candidate_list_len; i++)
|
||||
snprintf(&cl_str[i*2], 3, "%02X", candidate_list[i]);
|
||||
blobmsg_add_string_buffer(&b);
|
||||
}
|
||||
|
||||
ubus_notify(ctx, &hapd->ubus.obj, "bss-transition-response", b.head, -1);
|
||||
#endif
|
||||
}
|
||||
|
@ -51,6 +51,10 @@ void hostapd_ubus_notify_beacon_report(struct hostapd_data *hapd,
|
||||
struct rrm_measurement_beacon_report *rep,
|
||||
size_t len);
|
||||
|
||||
void hostapd_ubus_notify_bss_transition_response(
|
||||
struct hostapd_data *hapd, const u8 *addr, u8 dialog_token, u8 status_code,
|
||||
u8 bss_termination_delay, const u8 *target_bssid,
|
||||
const u8 *candidate_list, u16 candidate_list_len);
|
||||
void hostapd_ubus_add(struct hapd_interfaces *interfaces);
|
||||
void hostapd_ubus_free(struct hapd_interfaces *interfaces);
|
||||
|
||||
@ -91,6 +95,13 @@ static inline void hostapd_ubus_notify_beacon_report(struct hostapd_data *hapd,
|
||||
{
|
||||
}
|
||||
|
||||
static inline void hostapd_ubus_notify_bss_transition_response(
|
||||
struct hostapd_data *hapd, const u8 *addr, u8 dialog_token, u8 status_code,
|
||||
u8 bss_termination_delay, const u8 *target_bssid,
|
||||
const u8 *candidate_list, u16 candidate_list_len)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void hostapd_ubus_add(struct hapd_interfaces *interfaces)
|
||||
{
|
||||
}
|
||||
|
@ -0,0 +1,80 @@
|
||||
From dee0f71c39afdaa30af7b94af420ca1d5c0f0349 Mon Sep 17 00:00:00 2001
|
||||
From: Tobias Waldekranz <tobias@waldekranz.com>
|
||||
Date: Mon, 24 Jan 2022 22:09:43 +0100
|
||||
Subject: [PATCH 5.4 1/2] net: dsa: Move VLAN filtering syncing out of
|
||||
dsa_switch_bridge_leave
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
commit 381a730182f1d174e1950cd4e63e885b1c302051 upstream.
|
||||
|
||||
Most of dsa_switch_bridge_leave was, in fact, dealing with the syncing
|
||||
of VLAN filtering for switches on which that is a global
|
||||
setting. Separate the two phases to prepare for the cross-chip related
|
||||
bugfix in the following commit.
|
||||
|
||||
Signed-off-by: Tobias Waldekranz <tobias@waldekranz.com>
|
||||
Reviewed-by: Vladimir Oltean <olteanv@gmail.com>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
Signed-off-by: Marek Behún <kabel@kernel.org>
|
||||
---
|
||||
net/dsa/switch.c | 31 ++++++++++++++++++++++---------
|
||||
1 file changed, 22 insertions(+), 9 deletions(-)
|
||||
|
||||
diff --git a/net/dsa/switch.c b/net/dsa/switch.c
|
||||
index 6a9607518823..dd71e3301b27 100644
|
||||
--- a/net/dsa/switch.c
|
||||
+++ b/net/dsa/switch.c
|
||||
@@ -65,19 +65,12 @@ static int dsa_switch_bridge_join(struct dsa_switch *ds,
|
||||
return 0;
|
||||
}
|
||||
|
||||
-static int dsa_switch_bridge_leave(struct dsa_switch *ds,
|
||||
- struct dsa_notifier_bridge_info *info)
|
||||
+static int dsa_switch_sync_vlan_filtering(struct dsa_switch *ds,
|
||||
+ struct dsa_notifier_bridge_info *info)
|
||||
{
|
||||
bool unset_vlan_filtering = br_vlan_enabled(info->br);
|
||||
int err, i;
|
||||
|
||||
- if (ds->index == info->sw_index && ds->ops->port_bridge_leave)
|
||||
- ds->ops->port_bridge_leave(ds, info->port, info->br);
|
||||
-
|
||||
- if (ds->index != info->sw_index && ds->ops->crosschip_bridge_leave)
|
||||
- ds->ops->crosschip_bridge_leave(ds, info->sw_index, info->port,
|
||||
- info->br);
|
||||
-
|
||||
/* If the bridge was vlan_filtering, the bridge core doesn't trigger an
|
||||
* event for changing vlan_filtering setting upon slave ports leaving
|
||||
* it. That is a good thing, because that lets us handle it and also
|
||||
@@ -103,6 +96,26 @@ static int dsa_switch_bridge_leave(struct dsa_switch *ds,
|
||||
if (err && err != EOPNOTSUPP)
|
||||
return err;
|
||||
}
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int dsa_switch_bridge_leave(struct dsa_switch *ds,
|
||||
+ struct dsa_notifier_bridge_info *info)
|
||||
+{
|
||||
+ int err;
|
||||
+
|
||||
+ if (ds->index == info->sw_index && ds->ops->port_bridge_leave)
|
||||
+ ds->ops->port_bridge_leave(ds, info->port, info->br);
|
||||
+
|
||||
+ if (ds->index != info->sw_index && ds->ops->crosschip_bridge_leave)
|
||||
+ ds->ops->crosschip_bridge_leave(ds, info->sw_index, info->port,
|
||||
+ info->br);
|
||||
+
|
||||
+ err = dsa_switch_sync_vlan_filtering(ds, info);
|
||||
+ if (err)
|
||||
+ return err;
|
||||
+
|
||||
return 0;
|
||||
}
|
||||
|
||||
--
|
||||
2.34.1
|
||||
|
@ -0,0 +1,63 @@
|
||||
From f6edb463510bd936f143907468fc0bf0762b87bf Mon Sep 17 00:00:00 2001
|
||||
From: Tobias Waldekranz <tobias@waldekranz.com>
|
||||
Date: Mon, 24 Jan 2022 22:09:44 +0100
|
||||
Subject: [PATCH 5.4 2/2] net: dsa: Avoid cross-chip syncing of VLAN filtering
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
commit 108dc8741c203e9d6ce4e973367f1bac20c7192b upstream.
|
||||
|
||||
Changes to VLAN filtering are not applicable to cross-chip
|
||||
notifications.
|
||||
|
||||
On a system like this:
|
||||
|
||||
.-----. .-----. .-----.
|
||||
| sw1 +---+ sw2 +---+ sw3 |
|
||||
'-1-2-' '-1-2-' '-1-2-'
|
||||
|
||||
Before this change, upon sw1p1 leaving a bridge, a call to
|
||||
dsa_port_vlan_filtering would also be made to sw2p1 and sw3p1.
|
||||
|
||||
In this scenario:
|
||||
|
||||
.---------. .-----. .-----.
|
||||
| sw1 +---+ sw2 +---+ sw3 |
|
||||
'-1-2-3-4-' '-1-2-' '-1-2-'
|
||||
|
||||
When sw1p4 would leave a bridge, dsa_port_vlan_filtering would be
|
||||
called for sw2 and sw3 with a non-existing port - leading to array
|
||||
out-of-bounds accesses and crashes on mv88e6xxx.
|
||||
|
||||
Fixes: d371b7c92d19 ("net: dsa: Unset vlan_filtering when ports leave the bridge")
|
||||
Signed-off-by: Tobias Waldekranz <tobias@waldekranz.com>
|
||||
Reviewed-by: Vladimir Oltean <olteanv@gmail.com>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
Signed-off-by: Marek Behún <kabel@kernel.org>
|
||||
---
|
||||
net/dsa/switch.c | 8 +++++---
|
||||
1 file changed, 5 insertions(+), 3 deletions(-)
|
||||
|
||||
diff --git a/net/dsa/switch.c b/net/dsa/switch.c
|
||||
index dd71e3301b27..f517d6d7efa2 100644
|
||||
--- a/net/dsa/switch.c
|
||||
+++ b/net/dsa/switch.c
|
||||
@@ -112,9 +112,11 @@ static int dsa_switch_bridge_leave(struct dsa_switch *ds,
|
||||
ds->ops->crosschip_bridge_leave(ds, info->sw_index, info->port,
|
||||
info->br);
|
||||
|
||||
- err = dsa_switch_sync_vlan_filtering(ds, info);
|
||||
- if (err)
|
||||
- return err;
|
||||
+ if (ds->index == info->sw_index) {
|
||||
+ err = dsa_switch_sync_vlan_filtering(ds, info);
|
||||
+ if (err)
|
||||
+ return err;
|
||||
+ }
|
||||
|
||||
return 0;
|
||||
}
|
||||
--
|
||||
2.34.1
|
||||
|
Loading…
Reference in New Issue
Block a user