]> git.ipfire.org Git - thirdparty/iw.git/blame - iw.c
remove obsolete build information
[thirdparty/iw.git] / iw.c
CommitLineData
cad53b3f
JB
1/*
2 * nl80211 userspace tool
3 *
2a1fced2 4 * Copyright 2007, 2008 Johannes Berg <johannes@sipsolutions.net>
cad53b3f
JB
5 */
6
7#include <errno.h>
8#include <stdio.h>
d5ac8ad3 9#include <string.h>
bd396f2a
JB
10#include <net/if.h>
11#include <sys/types.h>
12#include <sys/stat.h>
13#include <fcntl.h>
14#include <unistd.h>
15
cad53b3f
JB
16#include <netlink/genl/genl.h>
17#include <netlink/genl/family.h>
18#include <netlink/genl/ctrl.h>
19#include <netlink/msg.h>
20#include <netlink/attr.h>
cad53b3f 21
f408e01b 22#include "nl80211.h"
cad53b3f 23#include "iw.h"
d711f013 24#include "version.h"
cad53b3f 25
59c49f09 26int debug = 0;
cad53b3f
JB
27
28static int nl80211_init(struct nl80211_state *state)
29{
30 int err;
31
32 state->nl_handle = nl_handle_alloc();
33 if (!state->nl_handle) {
34 fprintf(stderr, "Failed to allocate netlink handle.\n");
35 return -ENOMEM;
36 }
37
38 if (genl_connect(state->nl_handle)) {
39 fprintf(stderr, "Failed to connect to generic netlink.\n");
40 err = -ENOLINK;
41 goto out_handle_destroy;
42 }
43
44 state->nl_cache = genl_ctrl_alloc_cache(state->nl_handle);
45 if (!state->nl_cache) {
46 fprintf(stderr, "Failed to allocate generic netlink cache.\n");
47 err = -ENOMEM;
48 goto out_handle_destroy;
49 }
50
51 state->nl80211 = genl_ctrl_search_by_name(state->nl_cache, "nl80211");
52 if (!state->nl80211) {
53 fprintf(stderr, "nl80211 not found.\n");
54 err = -ENOENT;
55 goto out_cache_free;
56 }
57
58 return 0;
59
60 out_cache_free:
61 nl_cache_free(state->nl_cache);
62 out_handle_destroy:
63 nl_handle_destroy(state->nl_handle);
64 return err;
65}
66
67static void nl80211_cleanup(struct nl80211_state *state)
68{
69 genl_family_put(state->nl80211);
70 nl_cache_free(state->nl_cache);
71 nl_handle_destroy(state->nl_handle);
72}
73
ce5af55c
JB
74__COMMAND(NULL, NULL, NULL, 0, 0, 0, CIB_NONE, NULL);
75__COMMAND(NULL, NULL, NULL, 1, 0, 0, CIB_NONE, NULL);
403b9c83
JB
76
77static int cmd_size;
78
bd396f2a
JB
79static void usage(const char *argv0)
80{
81 struct cmd *cmd;
82
59c49f09
JB
83 fprintf(stderr, "Usage:\t%s [options] command\n", argv0);
84 fprintf(stderr, "Options:\n");
d711f013
JB
85 fprintf(stderr, "\t--debug\t\tenable netlink debugging\n");
86 fprintf(stderr, "\t--version\tshow version\n");
59c49f09 87 fprintf(stderr, "Commands:\n");
2c61ba61
JB
88 fprintf(stderr, "\thelp\n");
89 fprintf(stderr, "\tevent\n");
403b9c83
JB
90 for (cmd = &__start___cmd; cmd < &__stop___cmd;
91 cmd = (struct cmd *)((char *)cmd + cmd_size)) {
ce5af55c 92 if (!cmd->handler || cmd->hidden)
403b9c83 93 continue;
bd396f2a
JB
94 switch (cmd->idby) {
95 case CIB_NONE:
59c49f09 96 fprintf(stderr, "\t");
d631650b 97 /* fall through */
bd396f2a 98 case CIB_PHY:
d631650b 99 if (cmd->idby == CIB_PHY)
59c49f09 100 fprintf(stderr, "\tphy <phyname> ");
bd396f2a
JB
101 /* fall through */
102 case CIB_NETDEV:
103 if (cmd->idby == CIB_NETDEV)
59c49f09 104 fprintf(stderr, "\tdev <devname> ");
bd396f2a
JB
105 if (cmd->section)
106 fprintf(stderr, "%s ", cmd->section);
107 fprintf(stderr, "%s", cmd->name);
108 if (cmd->args)
109 fprintf(stderr, " %s", cmd->args);
110 fprintf(stderr, "\n");
111 break;
112 }
113 }
114}
115
d711f013
JB
116static void version(void)
117{
2dc285b7 118 printf("iw version " IW_VERSION "\n");
d711f013
JB
119}
120
bd396f2a
JB
121static int phy_lookup(char *name)
122{
123 char buf[200];
124 int fd, pos;
125
126 snprintf(buf, sizeof(buf), "/sys/class/ieee80211/%s/index", name);
127
128 fd = open(buf, O_RDONLY);
129 pos = read(fd, buf, sizeof(buf) - 1);
130 if (pos < 0)
131 return -1;
132 buf[pos] = '\0';
133 return atoi(buf);
134}
135
70391ccf
JB
136static int error_handler(struct sockaddr_nl *nla, struct nlmsgerr *err,
137 void *arg)
138{
139 int *ret = arg;
140 *ret = err->error;
141 return NL_STOP;
142}
143
561c5b7e
JB
144static int finish_handler(struct nl_msg *msg, void *arg)
145{
59c418c0
JB
146 int *ret = arg;
147 *ret = 0;
561c5b7e
JB
148 return NL_SKIP;
149}
150
151static int ack_handler(struct nl_msg *msg, void *arg)
70391ccf
JB
152{
153 int *ret = arg;
154 *ret = 0;
155 return NL_STOP;
156}
157
d631650b
JB
158static int handle_cmd(struct nl80211_state *state,
159 enum command_identify_by idby,
160 int argc, char **argv)
45c7212c 161{
bd396f2a 162 struct cmd *cmd;
70391ccf 163 struct nl_cb *cb = NULL;
bd396f2a
JB
164 struct nl_msg *msg;
165 int devidx = 0;
70391ccf 166 int err;
bd396f2a 167 const char *command, *section;
45c7212c 168
d631650b 169 if (argc <= 1 && idby != CIB_NONE)
5e75fd04 170 return 1;
45c7212c 171
bd396f2a
JB
172 switch (idby) {
173 case CIB_PHY:
174 devidx = phy_lookup(*argv);
175 argc--;
176 argv++;
177 break;
178 case CIB_NETDEV:
179 devidx = if_nametoindex(*argv);
180 argc--;
181 argv++;
182 break;
183 default:
184 break;
185 }
186
187 section = command = *argv;
188 argc--;
189 argv++;
190
403b9c83
JB
191 for (cmd = &__start___cmd; cmd < &__stop___cmd;
192 cmd = (struct cmd *)((char *)cmd + cmd_size)) {
193 if (!cmd->handler)
194 continue;
bd396f2a
JB
195 if (cmd->idby != idby)
196 continue;
197 if (cmd->section) {
198 if (strcmp(cmd->section, section))
199 continue;
200 /* this is a bit icky ... */
201 if (command == section) {
202 if (argc <= 0)
5e75fd04 203 return 1;
bd396f2a
JB
204 command = *argv;
205 argc--;
206 argv++;
207 }
208 } else if (section != command)
209 continue;
210 if (strcmp(cmd->name, command))
211 continue;
212 if (argc && !cmd->args)
213 continue;
214 break;
215 }
45c7212c 216
74701031 217 if (cmd >= &__stop___cmd)
5e75fd04 218 return 1;
45c7212c 219
bd396f2a
JB
220 msg = nlmsg_alloc();
221 if (!msg) {
70391ccf
JB
222 fprintf(stderr, "failed to allocate netlink message\n");
223 return 2;
224 }
225
59c49f09 226 cb = nl_cb_alloc(debug ? NL_CB_DEBUG : NL_CB_DEFAULT);
70391ccf
JB
227 if (!cb) {
228 fprintf(stderr, "failed to allocate netlink callbacks\n");
229 err = 2;
230 goto out_free_msg;
bd396f2a 231 }
45c7212c 232
bd396f2a
JB
233 genlmsg_put(msg, 0, 0, genl_family_get_id(state->nl80211), 0,
234 cmd->nl_msg_flags, cmd->cmd, 0);
235
236 switch (idby) {
237 case CIB_PHY:
238 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, devidx);
239 break;
240 case CIB_NETDEV:
241 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, devidx);
242 break;
243 default:
244 break;
245 }
246
70391ccf
JB
247 err = cmd->handler(cb, msg, argc, argv);
248 if (err)
249 goto out;
250
251 err = nl_send_auto_complete(state->nl_handle, msg);
252 if (err < 0)
253 goto out;
254
c5c4471a
JB
255 err = 1;
256
70391ccf 257 nl_cb_err(cb, NL_CB_CUSTOM, error_handler, &err);
59c418c0 258 nl_cb_set(cb, NL_CB_FINISH, NL_CB_CUSTOM, finish_handler, &err);
561c5b7e 259 nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, ack_handler, &err);
70391ccf 260
c5c4471a
JB
261 while (err > 0)
262 nl_recvmsgs(state->nl_handle, cb);
70391ccf
JB
263 out:
264 nl_cb_put(cb);
265 out_free_msg:
266 nlmsg_free(msg);
267 return err;
bd396f2a
JB
268 nla_put_failure:
269 fprintf(stderr, "building message failed\n");
70391ccf 270 return 2;
45c7212c
JB
271}
272
2c61ba61
JB
273static int no_seq_check(struct nl_msg *msg, void *arg)
274{
275 return NL_OK;
276}
277
278static int print_event(struct nl_msg *msg, void *arg)
279{
280 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
281 struct nlattr *tb[NL80211_ATTR_MAX + 1];
282
283 nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
284 genlmsg_attrlen(gnlh, 0), NULL);
285
286 switch (gnlh->cmd) {
287 case NL80211_CMD_NEW_WIPHY: {
288 printf("wiphy rename: phy #%d to %s\n",
289 nla_get_u32(tb[NL80211_ATTR_WIPHY]),
290 nla_get_string(tb[NL80211_ATTR_WIPHY_NAME]));
291 break;
292 }
293 }
294
295 return NL_SKIP;
296}
297
298static int listen_events(struct nl80211_state *state,
299 int argc, char **argv)
300{
301 int mcid, ret;
302 struct nl_cb *cb = nl_cb_alloc(debug ? NL_CB_DEBUG : NL_CB_DEFAULT);
303
304 if (!cb) {
305 fprintf(stderr, "failed to allocate netlink callbacks\n");
306 return -ENOMEM;
307 }
308
309 mcid = nl_get_multicast_id(state->nl_handle, "nl80211", "config");
310 if (mcid < 0)
311 return mcid;
312
313 ret = nl_socket_add_membership(state->nl_handle, mcid);
314 if (ret)
315 return ret;
316
317 /* no sequence checking for multicast messages */
318 nl_cb_set(cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM, no_seq_check, NULL);
319 nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, print_event, NULL);
320
321 while (1)
322 nl_recvmsgs(state->nl_handle, cb);
323
324 nl_cb_put(cb);
325
326 return 0;
327}
328
cad53b3f
JB
329int main(int argc, char **argv)
330{
331 struct nl80211_state nlstate;
bd396f2a
JB
332 int err;
333 const char *argv0;
cad53b3f 334
f408e01b 335 /* calculate command size including padding */
ce5af55c
JB
336 cmd_size = abs((long)&__cmd_NULL_1_CIB_NONE_0
337 - (long)&__cmd_NULL_0_CIB_NONE_0);
45c7212c
JB
338 /* strip off self */
339 argc--;
1cdd9016
MK
340 argv0 = *argv++;
341
59c49f09
JB
342 if (argc > 0 && strcmp(*argv, "--debug") == 0) {
343 debug = 1;
344 argc--;
345 argv++;
346 }
347
d711f013
JB
348 if (argc > 0 && strcmp(*argv, "--version") == 0) {
349 version();
350 return 0;
351 }
352
bd396f2a 353 if (argc == 0 || strcmp(*argv, "help") == 0) {
1cdd9016 354 usage(argv0);
4a972f80 355 return 0;
1cdd9016 356 }
45c7212c 357
2bdb6bd1
JB
358 err = nl80211_init(&nlstate);
359 if (err)
360 return 1;
361
2c61ba61
JB
362 if (strcmp(*argv, "event") == 0) {
363 err = listen_events(&nlstate, argc, argv);
364 } else if (strcmp(*argv, "dev") == 0) {
14a0380d
LR
365 argc--;
366 argv++;
d631650b 367 err = handle_cmd(&nlstate, CIB_NETDEV, argc, argv);
bd396f2a
JB
368 } else if (strcmp(*argv, "phy") == 0) {
369 argc--;
370 argv++;
d631650b 371 err = handle_cmd(&nlstate, CIB_PHY, argc, argv);
bd396f2a 372 } else
d631650b 373 err = handle_cmd(&nlstate, CIB_NONE, argc, argv);
45c7212c 374
5e75fd04 375 if (err == 1)
bd396f2a 376 usage(argv0);
5e75fd04 377 if (err < 0)
b49be3e1 378 fprintf(stderr, "command failed: %s (%d)\n", strerror(-err), err);
cad53b3f
JB
379
380 nl80211_cleanup(&nlstate);
381
45c7212c 382 return err;
cad53b3f 383}