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