1 /*
2 * Copyright (C) 2020 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #define LOG_TAG "mac80211_create_radios"
18
19 #include <memory>
20 #include <log/log.h>
21 #include <netlink/genl/ctrl.h>
22 #include <netlink/genl/genl.h>
23 #include <netlink/netlink.h>
24 #include <net/ethernet.h>
25 #include <linux/nl80211.h>
26
27 #define RETURN(R) return (R);
28 #define RETURN_ERROR(C, R) \
29 do { \
30 ALOGE("%s:%d '%s' failed", __func__, __LINE__, C); \
31 return (R); \
32 } while (false);
33 #define RETURN_NL_ERROR(C, NLR, R) \
34 do { \
35 ALOGE("%s:%d '%s' failed with '%s'", __func__, __LINE__, C, nlErrStr((NLR))); \
36 return (R); \
37 } while (false);
38 #define BIT(x) (1 << (x))
39
40 enum {
41 HWSIM_CMD_UNSPEC,
42 HWSIM_CMD_REGISTER,
43 HWSIM_CMD_FRAME,
44 HWSIM_CMD_TX_INFO_FRAME,
45 HWSIM_CMD_NEW_RADIO,
46 HWSIM_CMD_DEL_RADIO,
47 HWSIM_CMD_GET_RADIO,
48 };
49
50 enum {
51 HWSIM_ATTR_UNSPEC,
52 HWSIM_ATTR_ADDR_RECEIVER,
53 HWSIM_ATTR_ADDR_TRANSMITTER,
54 HWSIM_ATTR_FRAME,
55 HWSIM_ATTR_FLAGS,
56 HWSIM_ATTR_RX_RATE,
57 HWSIM_ATTR_SIGNAL,
58 HWSIM_ATTR_TX_INFO,
59 HWSIM_ATTR_COOKIE,
60 HWSIM_ATTR_CHANNELS,
61 HWSIM_ATTR_RADIO_ID,
62 HWSIM_ATTR_REG_HINT_ALPHA2,
63 HWSIM_ATTR_REG_CUSTOM_REG,
64 HWSIM_ATTR_REG_STRICT_REG,
65 HWSIM_ATTR_SUPPORT_P2P_DEVICE,
66 HWSIM_ATTR_USE_CHANCTX,
67 HWSIM_ATTR_DESTROY_RADIO_ON_CLOSE,
68 HWSIM_ATTR_RADIO_NAME,
69 HWSIM_ATTR_NO_VIF,
70 HWSIM_ATTR_FREQ,
71 HWSIM_ATTR_PAD,
72 HWSIM_ATTR_TX_INFO_FLAGS,
73 HWSIM_ATTR_PERM_ADDR,
74 HWSIM_ATTR_IFTYPE_SUPPORT,
75 HWSIM_ATTR_CIPHER_SUPPORT,
76 HWSIM_ATTR_MLO_SUPPORT,
77 HWSIM_ATTR_PMSR_SUPPORT,
78 };
79
80 struct nl_sock_deleter {
operator ()nl_sock_deleter81 void operator()(struct nl_sock* x) const { nl_socket_free(x); }
82 };
83
84 struct nl_msg_deleter {
operator ()nl_msg_deleter85 void operator()(struct nl_msg* x) const { nlmsg_free(x); }
86 };
87
88 constexpr char kHwSimFamilyName[] = "MAC80211_HWSIM";
89 constexpr int kHwSimVersion = 1;
90 constexpr uint32_t kChannels = 2;
91 constexpr uint32_t kPmsrMaxPeers = 10;
92 constexpr uint32_t kFtmAllPreables = BIT(NL80211_PREAMBLE_LEGACY)
93 | BIT(NL80211_PREAMBLE_HT)
94 | BIT(NL80211_PREAMBLE_VHT)
95 | BIT(NL80211_PREAMBLE_DMG)
96 | BIT(NL80211_PREAMBLE_HE);
97 constexpr uint32_t kFtmAllBandwidths = BIT(NL80211_CHAN_WIDTH_20_NOHT)
98 | BIT(NL80211_CHAN_WIDTH_20)
99 | BIT(NL80211_CHAN_WIDTH_40)
100 | BIT(NL80211_CHAN_WIDTH_80)
101 | BIT(NL80211_CHAN_WIDTH_80P80)
102 | BIT(NL80211_CHAN_WIDTH_160)
103 | BIT(NL80211_CHAN_WIDTH_5)
104 | BIT(NL80211_CHAN_WIDTH_10)
105 | BIT(NL80211_CHAN_WIDTH_1)
106 | BIT(NL80211_CHAN_WIDTH_2)
107 | BIT(NL80211_CHAN_WIDTH_4)
108 | BIT(NL80211_CHAN_WIDTH_8)
109 | BIT(NL80211_CHAN_WIDTH_16)
110 | BIT(NL80211_CHAN_WIDTH_320);
111 constexpr uint8_t kFtmMaxBurstsExponent = 15;
112 constexpr uint8_t kFtmMaxFtmsPerBurst = 31;
113
nlErrStr(const int e)114 const char* nlErrStr(const int e) { return (e < 0) ? nl_geterror(e) : ""; }
115
parseInt(const char * str,int * result)116 int parseInt(const char* str, int* result) { return sscanf(str, "%d", result); }
117
createNlMessage(const int family,const int cmd)118 std::unique_ptr<struct nl_msg, nl_msg_deleter> createNlMessage(
119 const int family,
120 const int cmd) {
121 std::unique_ptr<struct nl_msg, nl_msg_deleter> msg(nlmsg_alloc());
122 if (!msg) { RETURN_ERROR("nlmsg_alloc", nullptr); }
123
124 void* user = genlmsg_put(msg.get(), NL_AUTO_PORT, NL_AUTO_SEQ, family, 0,
125 NLM_F_REQUEST, cmd, kHwSimVersion);
126 if (!user) { RETURN_ERROR("genlmsg_put", nullptr); }
127
128 RETURN(msg);
129 }
130
131 #define PUT_FLAG(MSG, TYPE, R) \
132 do { \
133 (R) = nla_put_flag((MSG).get(), TYPE); \
134 if (R) RETURN_NL_ERROR("nla_put_flag(" #TYPE ")", R, nullptr); \
135 } while (false);
136
137 #define PUT_DATA(MSG, TYPE, V, SIZE, R) \
138 do { \
139 (R) = nla_put((MSG).get(), TYPE, SIZE, V); \
140 if (R) RETURN_NL_ERROR("nla_put(" #TYPE ")", R, nullptr); \
141 } while (false);
142
143 #define PUT_VALUE(MSG, TYPE, V, R) PUT_DATA(MSG, TYPE, &(V), sizeof(V), (R))
144
145 #define NEST_START(MSG, TYPE, ATTR) \
146 do { \
147 (ATTR) = nla_nest_start((MSG).get(), TYPE); \
148 if (!(ATTR)) RETURN_ERROR("nla_nest_start(" #TYPE ")", nullptr); \
149 } while (false);
150
151 #define NEST_END(MSG, START, R) \
152 do { \
153 (R) = nla_nest_end((MSG).get(), START); \
154 if (R) RETURN_NL_ERROR("nla_nest_end(" #START ")", R, nullptr); \
155 } while (false);
156
157 std::unique_ptr<struct nl_msg, nl_msg_deleter>
buildCreateRadioMessage(const int family,const uint8_t mac[ETH_ALEN],const bool enablePmsr)158 buildCreateRadioMessage(const int family, const uint8_t mac[ETH_ALEN],
159 const bool enablePmsr) {
160 std::unique_ptr<struct nl_msg, nl_msg_deleter> msg =
161 createNlMessage(family, HWSIM_CMD_NEW_RADIO);
162 if (!msg) { RETURN(nullptr); }
163
164 int ret;
165 PUT_DATA(msg, HWSIM_ATTR_PERM_ADDR, mac, ETH_ALEN, ret);
166 PUT_FLAG(msg, HWSIM_ATTR_SUPPORT_P2P_DEVICE, ret);
167 PUT_VALUE(msg, HWSIM_ATTR_CHANNELS, kChannels, ret);
168
169 if (enablePmsr) {
170 struct nlattr* pmsr;
171 NEST_START(msg, HWSIM_ATTR_PMSR_SUPPORT, pmsr);
172
173 PUT_VALUE(msg, NL80211_PMSR_ATTR_MAX_PEERS, kPmsrMaxPeers, ret);
174
175 struct nlattr* pmsrType;
176 NEST_START(msg, NL80211_PMSR_ATTR_TYPE_CAPA, pmsrType);
177
178 struct nlattr* ftm;
179 NEST_START(msg, NL80211_PMSR_TYPE_FTM, ftm);
180
181 PUT_FLAG(msg, NL80211_PMSR_FTM_CAPA_ATTR_ASAP, ret);
182 PUT_FLAG(msg, NL80211_PMSR_FTM_CAPA_ATTR_NON_ASAP, ret);
183 PUT_FLAG(msg, NL80211_PMSR_FTM_CAPA_ATTR_REQ_LCI, ret);
184 PUT_FLAG(msg, NL80211_PMSR_FTM_CAPA_ATTR_REQ_CIVICLOC, ret);
185 PUT_VALUE(msg, NL80211_PMSR_FTM_CAPA_ATTR_PREAMBLES,
186 kFtmAllPreables, ret);
187 PUT_VALUE(msg, NL80211_PMSR_FTM_CAPA_ATTR_BANDWIDTHS,
188 kFtmAllBandwidths, ret);
189 PUT_VALUE(msg, NL80211_PMSR_FTM_CAPA_ATTR_MAX_BURSTS_EXPONENT,
190 kFtmMaxBurstsExponent, ret);
191 PUT_VALUE(msg, NL80211_PMSR_FTM_CAPA_ATTR_MAX_FTMS_PER_BURST,
192 kFtmMaxFtmsPerBurst, ret);
193 PUT_FLAG(msg, NL80211_PMSR_FTM_CAPA_ATTR_TRIGGER_BASED, ret);
194 PUT_FLAG(msg, NL80211_PMSR_FTM_CAPA_ATTR_NON_TRIGGER_BASED, ret);
195
196 NEST_END(msg, ftm, ret);
197 NEST_END(msg, pmsrType, ret);
198 NEST_END(msg, pmsr, ret);
199 }
200
201 RETURN(msg);
202 }
203
createRadios(struct nl_sock * socket,const int netlinkFamily,const int nRadios,const int macPrefix,const bool enablePmsr)204 int createRadios(struct nl_sock* socket, const int netlinkFamily,
205 const int nRadios, const int macPrefix,
206 const bool enablePmsr) {
207 uint8_t mac[ETH_ALEN] = {};
208 mac[0] = 0x02;
209 mac[1] = (macPrefix >> CHAR_BIT) & 0xFF;
210 mac[2] = macPrefix & 0xFF;
211
212 for (int idx = 0; idx < nRadios; ++idx) {
213 mac[4] = idx;
214
215 std::unique_ptr<struct nl_msg, nl_msg_deleter> msg =
216 buildCreateRadioMessage(netlinkFamily, mac, enablePmsr);
217 if (msg) {
218 int ret = nl_send_auto(socket, msg.get());
219 if (ret < 0) { RETURN_NL_ERROR("nl_send_auto", ret, 1); }
220 } else {
221 RETURN(1);
222 }
223 }
224
225 RETURN(0);
226 }
227
manageRadios(const int nRadios,const int macPrefix,const bool enablePmsr)228 int manageRadios(const int nRadios, const int macPrefix,
229 const bool enablePmsr) {
230 std::unique_ptr<struct nl_sock, nl_sock_deleter> socket(nl_socket_alloc());
231 if (!socket) { RETURN_ERROR("nl_socket_alloc", 1); }
232
233 int ret;
234 ret = genl_connect(socket.get());
235 if (ret) { RETURN_NL_ERROR("genl_connect", ret, 1); }
236
237 const int netlinkFamily = genl_ctrl_resolve(socket.get(), kHwSimFamilyName);
238 if (netlinkFamily < 0) { RETURN_NL_ERROR("genl_ctrl_resolve", ret, 1); }
239
240 ret = createRadios(socket.get(), netlinkFamily, nRadios, macPrefix,
241 enablePmsr);
242 if (ret) { RETURN(ret); }
243
244 RETURN(0);
245 }
246
printUsage(FILE * dst,const int ret)247 int printUsage(FILE* dst, const int ret) {
248 fprintf(dst, "%s",
249 "Usage:\n"
250 " mac80211_create_radios [options] n_radios mac_prefix\n"
251 " where\n"
252 " n_radios - int, [1,100], e.g. 2;\n"
253 " mac_prefix - int, [0, 65535], e.g. 5555.\n\n"
254 " mac80211_create_radios will create n_radios with MAC addresses\n"
255 " 02:pp:pp:00:nn:00, where nn is incremented (from zero)\n"
256 " and pp:pp is the mac_prefix specified.\n"
257 "\n"
258 " options:\n"
259 " --enable-pmsr: enable peer measurement for RTT support.\n");
260
261 return ret;
262 }
263
main(int argc,char * argv[])264 int main(int argc, char* argv[]) {
265 if (argc != 4 && argc != 3) { return printUsage(stdout, 0); }
266
267 int argIndex = 1;
268 bool enablePmsr = false;
269 if (!strcmp(argv[argIndex], "--enable-pmsr")) {
270 enablePmsr = true;
271 argIndex++;
272 }
273 int nRadios;
274 if (!parseInt(argv[argIndex++], &nRadios)) { return printUsage(stderr, 1); }
275 if (nRadios < 1) { return printUsage(stderr, 1); }
276 if (nRadios > 100) { return printUsage(stderr, 1); }
277
278 int macPrefix;
279 if (!parseInt(argv[argIndex], &macPrefix)) { return printUsage(stderr, 1); }
280 if (macPrefix < 0) { return printUsage(stderr, 1); }
281 if (macPrefix > UINT16_MAX) { return printUsage(stderr, 1); }
282
283 return manageRadios(nRadios, macPrefix, enablePmsr);
284 }
285