• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
26 enum {
27     HWSIM_CMD_UNSPEC,
28     HWSIM_CMD_REGISTER,
29     HWSIM_CMD_FRAME,
30     HWSIM_CMD_TX_INFO_FRAME,
31     HWSIM_CMD_NEW_RADIO,
32     HWSIM_CMD_DEL_RADIO,
33     HWSIM_CMD_GET_RADIO,
34 };
35 
36 enum {
37     HWSIM_ATTR_UNSPEC,
38     HWSIM_ATTR_ADDR_RECEIVER,
39     HWSIM_ATTR_ADDR_TRANSMITTER,
40     HWSIM_ATTR_FRAME,
41     HWSIM_ATTR_FLAGS,
42     HWSIM_ATTR_RX_RATE,
43     HWSIM_ATTR_SIGNAL,
44     HWSIM_ATTR_TX_INFO,
45     HWSIM_ATTR_COOKIE,
46     HWSIM_ATTR_CHANNELS,
47     HWSIM_ATTR_RADIO_ID,
48     HWSIM_ATTR_REG_HINT_ALPHA2,
49     HWSIM_ATTR_REG_CUSTOM_REG,
50     HWSIM_ATTR_REG_STRICT_REG,
51     HWSIM_ATTR_SUPPORT_P2P_DEVICE,
52     HWSIM_ATTR_USE_CHANCTX,
53     HWSIM_ATTR_DESTROY_RADIO_ON_CLOSE,
54     HWSIM_ATTR_RADIO_NAME,
55     HWSIM_ATTR_NO_VIF,
56     HWSIM_ATTR_FREQ,
57     HWSIM_ATTR_PAD,
58     HWSIM_ATTR_TX_INFO_FLAGS,
59     HWSIM_ATTR_PERM_ADDR,
60     HWSIM_ATTR_IFTYPE_SUPPORT,
61     HWSIM_ATTR_CIPHER_SUPPORT,
62 };
63 
64 struct nl_sock_deleter {
operator ()nl_sock_deleter65     void operator()(struct nl_sock* x) const { nl_socket_free(x); }
66 };
67 
68 struct nl_msg_deleter {
operator ()nl_msg_deleter69     void operator()(struct nl_msg* x) const { nlmsg_free(x); }
70 };
71 
72 constexpr char kHwSimFamilyName[] = "MAC80211_HWSIM";
73 constexpr int kHwSimVersion = 1;
74 constexpr int kChannels = 2;
75 
nlErrStr(const int e)76 const char* nlErrStr(const int e) { return (e < 0) ? nl_geterror(e) : ""; }
77 
78 #define RETURN(R) return (R);
79 #define RETURN_ERROR(C, R) \
80     do { \
81         ALOGE("%s:%d '%s' failed", __func__, __LINE__, C); \
82         return (R); \
83     } while (false);
84 #define RETURN_NL_ERROR(C, NLR, R) \
85     do { \
86         ALOGE("%s:%d '%s' failed with '%s'", __func__, __LINE__, C, nlErrStr((NLR))); \
87         return (R); \
88     } while (false);
89 
parseInt(const char * str,int * result)90 int parseInt(const char* str, int* result) { return sscanf(str, "%d", result); }
91 
createNlMessage(const int family,const int cmd)92 std::unique_ptr<struct nl_msg, nl_msg_deleter> createNlMessage(
93         const int family,
94         const int cmd) {
95     std::unique_ptr<struct nl_msg, nl_msg_deleter> msg(nlmsg_alloc());
96     if (!msg) { RETURN_ERROR("nlmsg_alloc", nullptr); }
97 
98     void* user = genlmsg_put(msg.get(), NL_AUTO_PORT, NL_AUTO_SEQ, family, 0,
99                        NLM_F_REQUEST, cmd, kHwSimVersion);
100     if (!user) { RETURN_ERROR("genlmsg_put", nullptr); }
101 
102     RETURN(msg);
103 }
104 
105 std::unique_ptr<struct nl_msg, nl_msg_deleter>
buildCreateRadioMessage(const int family,const uint8_t mac[ETH_ALEN])106 buildCreateRadioMessage(const int family, const uint8_t mac[ETH_ALEN]) {
107     std::unique_ptr<struct nl_msg, nl_msg_deleter> msg =
108         createNlMessage(family, HWSIM_CMD_NEW_RADIO);
109     if (!msg) { RETURN(nullptr); }
110 
111     int ret;
112     ret = nla_put(msg.get(), HWSIM_ATTR_PERM_ADDR, ETH_ALEN, mac);
113     if (ret) { RETURN_NL_ERROR("nla_put(HWSIM_ATTR_PERM_ADDR)", ret, nullptr); }
114 
115     ret = nla_put_flag(msg.get(), HWSIM_ATTR_SUPPORT_P2P_DEVICE);
116     if (ret) { RETURN_NL_ERROR("nla_put(HWSIM_ATTR_SUPPORT_P2P_DEVICE)", ret, nullptr); }
117 
118     ret = nla_put_u32(msg.get(), HWSIM_ATTR_CHANNELS, kChannels);
119     if (ret) { RETURN_NL_ERROR("nla_put(HWSIM_ATTR_CHANNELS)", ret, nullptr); }
120 
121     RETURN(msg);
122 }
123 
createRadios(struct nl_sock * socket,const int netlinkFamily,const int nRadios,const int macPrefix)124 int createRadios(struct nl_sock* socket, const int netlinkFamily,
125                  const int nRadios, const int macPrefix) {
126     uint8_t mac[ETH_ALEN] = {};
127     mac[0] = 0x02;
128     mac[1] = (macPrefix >> CHAR_BIT) & 0xFF;
129     mac[2] = macPrefix & 0xFF;
130 
131     for (int idx = 0; idx < nRadios; ++idx) {
132         mac[4] = idx;
133 
134         std::unique_ptr<struct nl_msg, nl_msg_deleter> msg =
135             buildCreateRadioMessage(netlinkFamily, mac);
136         if (msg) {
137             int ret = nl_send_auto(socket, msg.get());
138             if (ret < 0) { RETURN_NL_ERROR("nl_send_auto", ret, 1); }
139         } else {
140             RETURN(1);
141         }
142     }
143 
144     RETURN(0);
145 }
146 
manageRadios(const int nRadios,const int macPrefix)147 int manageRadios(const int nRadios, const int macPrefix) {
148     std::unique_ptr<struct nl_sock, nl_sock_deleter> socket(nl_socket_alloc());
149     if (!socket) { RETURN_ERROR("nl_socket_alloc", 1); }
150 
151     int ret;
152     ret = genl_connect(socket.get());
153     if (ret) { RETURN_NL_ERROR("genl_connect", ret, 1); }
154 
155     const int netlinkFamily = genl_ctrl_resolve(socket.get(), kHwSimFamilyName);
156     if (netlinkFamily < 0) { RETURN_NL_ERROR("genl_ctrl_resolve", ret, 1); }
157 
158     ret = createRadios(socket.get(), netlinkFamily, nRadios, macPrefix);
159     if (ret) { RETURN(ret); }
160 
161     RETURN(0);
162 }
163 
printUsage(FILE * dst,const int ret)164 int printUsage(FILE* dst, const int ret) {
165     fprintf(dst, "%s",
166     "Usage:\n"
167     "   mac80211_create_radios n_radios mac_prefix\n"
168     "   where\n"
169     "       n_radios - int, [1,100], e.g. 2;\n"
170     "       mac_prefix - int, [0, 65535], e.g. 5555.\n\n"
171     "   mac80211_create_radios will delete all existing radios and\n"
172     "   create n_radios with MAC addresses\n"
173     "   02:pp:pp:00:nn:00, where nn is incremented (from zero)\n");
174 
175     return ret;
176 }
177 
main(int argc,char * argv[])178 int main(int argc, char* argv[]) {
179     if (argc != 3) { return printUsage(stdout, 0); }
180 
181     int nRadios;
182     if (!parseInt(argv[1], &nRadios)) { return printUsage(stderr, 1); }
183     if (nRadios < 1) { return printUsage(stderr, 1); }
184     if (nRadios > 100) { return printUsage(stderr, 1); }
185 
186     int macPrefix;
187     if (!parseInt(argv[2], &macPrefix)) { return printUsage(stderr, 1); }
188     if (macPrefix < 0) { return printUsage(stderr, 1); }
189     if (macPrefix > UINT16_MAX) { return printUsage(stderr, 1); }
190 
191     return manageRadios(nRadios, macPrefix);
192 }
193