c559f070e87fc423182561bcf4c4f9ded3b6a242
[openwrt/staging/ldir.git] /
1 From: Felix Fietkau <nbd@nbd.name>
2 Date: Wed, 5 Jun 2024 18:39:55 +0200
3 Subject: [PATCH] wifi: mac80211: add wiphy radio assignment and
4 validation
5
6 Validate number of channels and interface combinations per radio.
7 Assign each channel context to a radio.
8
9 Signed-off-by: Felix Fietkau <nbd@nbd.name>
10 ---
11
12 --- a/net/mac80211/chan.c
13 +++ b/net/mac80211/chan.c
14 @@ -680,14 +680,15 @@ static int ieee80211_add_chanctx(struct
15 static struct ieee80211_chanctx *
16 ieee80211_new_chanctx(struct ieee80211_local *local,
17 const struct ieee80211_chan_req *chanreq,
18 - enum ieee80211_chanctx_mode mode)
19 + enum ieee80211_chanctx_mode mode,
20 + int radio_idx)
21 {
22 struct ieee80211_chanctx *ctx;
23 int err;
24
25 lockdep_assert_wiphy(local->hw.wiphy);
26
27 - ctx = ieee80211_alloc_chanctx(local, chanreq, mode, -1);
28 + ctx = ieee80211_alloc_chanctx(local, chanreq, mode, radio_idx);
29 if (!ctx)
30 return ERR_PTR(-ENOMEM);
31
32 @@ -1040,6 +1041,8 @@ ieee80211_replace_chanctx(struct ieee802
33 struct ieee80211_chanctx *curr_ctx)
34 {
35 struct ieee80211_chanctx *new_ctx, *ctx;
36 + struct wiphy *wiphy = local->hw.wiphy;
37 + const struct wiphy_radio *radio;
38
39 if (!curr_ctx || (curr_ctx->replace_state ==
40 IEEE80211_CHANCTX_WILL_BE_REPLACED) ||
41 @@ -1069,6 +1072,12 @@ ieee80211_replace_chanctx(struct ieee802
42 if (!list_empty(&ctx->reserved_links))
43 continue;
44
45 + if (ctx->conf.radio_idx >= 0) {
46 + radio = &wiphy->radio[ctx->conf.radio_idx];
47 + if (!cfg80211_radio_chandef_valid(radio, &chanreq->oper))
48 + continue;
49 + }
50 +
51 curr_ctx = ctx;
52 break;
53 }
54 @@ -1098,6 +1107,34 @@ ieee80211_replace_chanctx(struct ieee802
55 return new_ctx;
56 }
57
58 +static bool
59 +ieee80211_find_available_radio(struct ieee80211_local *local,
60 + const struct ieee80211_chan_req *chanreq,
61 + int *radio_idx)
62 +{
63 + struct wiphy *wiphy = local->hw.wiphy;
64 + const struct wiphy_radio *radio;
65 + int i;
66 +
67 + *radio_idx = -1;
68 + if (!wiphy->n_radio)
69 + return true;
70 +
71 + for (i = 0; i < wiphy->n_radio; i++) {
72 + radio = &wiphy->radio[i];
73 + if (!cfg80211_radio_chandef_valid(radio, &chanreq->oper))
74 + continue;
75 +
76 + if (!ieee80211_can_create_new_chanctx(local, i))
77 + continue;
78 +
79 + *radio_idx = i;
80 + return true;
81 + }
82 +
83 + return false;
84 +}
85 +
86 int ieee80211_link_reserve_chanctx(struct ieee80211_link_data *link,
87 const struct ieee80211_chan_req *chanreq,
88 enum ieee80211_chanctx_mode mode,
89 @@ -1106,6 +1143,7 @@ int ieee80211_link_reserve_chanctx(struc
90 struct ieee80211_sub_if_data *sdata = link->sdata;
91 struct ieee80211_local *local = sdata->local;
92 struct ieee80211_chanctx *new_ctx, *curr_ctx;
93 + int radio_idx;
94
95 lockdep_assert_wiphy(local->hw.wiphy);
96
97 @@ -1115,8 +1153,10 @@ int ieee80211_link_reserve_chanctx(struc
98
99 new_ctx = ieee80211_find_reservation_chanctx(local, chanreq, mode);
100 if (!new_ctx) {
101 - if (ieee80211_can_create_new_chanctx(local, -1))
102 - new_ctx = ieee80211_new_chanctx(local, chanreq, mode);
103 + if (ieee80211_can_create_new_chanctx(local, -1) &&
104 + ieee80211_find_available_radio(local, chanreq, &radio_idx))
105 + new_ctx = ieee80211_new_chanctx(local, chanreq, mode,
106 + radio_idx);
107 else
108 new_ctx = ieee80211_replace_chanctx(local, chanreq,
109 mode, curr_ctx);
110 @@ -1724,6 +1764,7 @@ int ieee80211_link_use_channel(struct ie
111 struct ieee80211_local *local = sdata->local;
112 struct ieee80211_chanctx *ctx;
113 u8 radar_detect_width = 0;
114 + int radio_idx;
115 int ret;
116
117 lockdep_assert_wiphy(local->hw.wiphy);
118 @@ -1751,8 +1792,12 @@ int ieee80211_link_use_channel(struct ie
119 __ieee80211_link_release_channel(link);
120
121 ctx = ieee80211_find_chanctx(local, chanreq, mode);
122 - if (!ctx)
123 - ctx = ieee80211_new_chanctx(local, chanreq, mode);
124 + if (!ctx) {
125 + if (!ieee80211_find_available_radio(local, chanreq, &radio_idx))
126 + ctx = ERR_PTR(-EBUSY);
127 + else
128 + ctx = ieee80211_new_chanctx(local, chanreq, mode, radio_idx);
129 + }
130 if (IS_ERR(ctx)) {
131 ret = PTR_ERR(ctx);
132 goto out;