blob: 117399c63ec898cb20cb830ccc531992a02f0271 [file] [log] [blame]
Johannes Bergcad53b32007-09-28 22:11:34 +02001/*
2 * nl80211 userspace tool
3 *
Johannes Berg2a1fced2008-01-16 00:39:55 +01004 * Copyright 2007, 2008 Johannes Berg <johannes@sipsolutions.net>
Johannes Bergcad53b32007-09-28 22:11:34 +02005 */
6
7#include <errno.h>
8#include <stdio.h>
Johannes Bergd5ac8ad2008-04-03 15:24:13 +02009#include <string.h>
Johannes Bergbd396f22008-09-16 16:56:09 +020010#include <net/if.h>
11#include <sys/types.h>
12#include <sys/stat.h>
13#include <fcntl.h>
14#include <unistd.h>
15
Johannes Bergcad53b32007-09-28 22:11:34 +020016#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>
Johannes Bergcad53b32007-09-28 22:11:34 +020021
Johannes Bergf408e012008-09-18 19:32:11 +020022#include "nl80211.h"
Johannes Bergcad53b32007-09-28 22:11:34 +020023#include "iw.h"
Johannes Bergd711f012008-09-16 21:56:25 +020024#include "version.h"
Johannes Bergcad53b32007-09-28 22:11:34 +020025
Pat Erleydfd13ee2008-12-13 01:04:05 +010026#ifndef CONFIG_LIBNL20
27/* libnl 2.0 compatibility code */
28
29static inline struct nl_handle *nl_socket_alloc(void)
30{
31 return nl_handle_alloc();
32}
33
34static inline void nl_socket_free(struct nl_handle *h)
35{
36 nl_handle_destroy(h);
37}
38
39static inline int __genl_ctrl_alloc_cache(struct nl_handle *h, struct nl_cache **cache)
40{
41 struct nl_cache *tmp = genl_ctrl_alloc_cache(h);
42 if (!tmp)
43 return -ENOMEM;
44 *cache = tmp;
45 return 0;
46}
47#define genl_ctrl_alloc_cache __genl_ctrl_alloc_cache
48#endif /* CONFIG_LIBNL20 */
49
Johannes Berg656aa242008-12-08 18:30:22 +010050static int debug = 0;
Johannes Bergcad53b32007-09-28 22:11:34 +020051
52static int nl80211_init(struct nl80211_state *state)
53{
54 int err;
55
Pat Erleydfd13ee2008-12-13 01:04:05 +010056 state->nl_handle = nl_socket_alloc();
Johannes Bergcad53b32007-09-28 22:11:34 +020057 if (!state->nl_handle) {
58 fprintf(stderr, "Failed to allocate netlink handle.\n");
59 return -ENOMEM;
60 }
61
62 if (genl_connect(state->nl_handle)) {
63 fprintf(stderr, "Failed to connect to generic netlink.\n");
64 err = -ENOLINK;
65 goto out_handle_destroy;
66 }
67
Pat Erleydfd13ee2008-12-13 01:04:05 +010068 if (genl_ctrl_alloc_cache(state->nl_handle, &state->nl_cache)) {
Johannes Bergcad53b32007-09-28 22:11:34 +020069 fprintf(stderr, "Failed to allocate generic netlink cache.\n");
70 err = -ENOMEM;
71 goto out_handle_destroy;
72 }
73
74 state->nl80211 = genl_ctrl_search_by_name(state->nl_cache, "nl80211");
75 if (!state->nl80211) {
76 fprintf(stderr, "nl80211 not found.\n");
77 err = -ENOENT;
78 goto out_cache_free;
79 }
80
81 return 0;
82
83 out_cache_free:
84 nl_cache_free(state->nl_cache);
85 out_handle_destroy:
Pat Erleydfd13ee2008-12-13 01:04:05 +010086 nl_socket_free(state->nl_handle);
Johannes Bergcad53b32007-09-28 22:11:34 +020087 return err;
88}
89
90static void nl80211_cleanup(struct nl80211_state *state)
91{
92 genl_family_put(state->nl80211);
93 nl_cache_free(state->nl_cache);
Pat Erleydfd13ee2008-12-13 01:04:05 +010094 nl_socket_free(state->nl_handle);
Johannes Bergcad53b32007-09-28 22:11:34 +020095}
96
Johannes Bergce5af552008-09-17 13:27:04 +020097__COMMAND(NULL, NULL, NULL, 0, 0, 0, CIB_NONE, NULL);
98__COMMAND(NULL, NULL, NULL, 1, 0, 0, CIB_NONE, NULL);
Johannes Berg403b9c82008-09-17 00:19:53 +020099
100static int cmd_size;
101
Johannes Bergbd396f22008-09-16 16:56:09 +0200102static void usage(const char *argv0)
Johannes Berg45c72122007-09-28 23:47:38 +0200103{
Johannes Bergbd396f22008-09-16 16:56:09 +0200104 struct cmd *cmd;
Johannes Berg45c72122007-09-28 23:47:38 +0200105
Johannes Berg59c49f02008-09-16 21:00:32 +0200106 fprintf(stderr, "Usage:\t%s [options] command\n", argv0);
107 fprintf(stderr, "Options:\n");
Johannes Bergd711f012008-09-16 21:56:25 +0200108 fprintf(stderr, "\t--debug\t\tenable netlink debugging\n");
109 fprintf(stderr, "\t--version\tshow version\n");
Johannes Berg59c49f02008-09-16 21:00:32 +0200110 fprintf(stderr, "Commands:\n");
Johannes Berg2c61ba62008-10-24 20:24:44 +0200111 fprintf(stderr, "\thelp\n");
112 fprintf(stderr, "\tevent\n");
Johannes Berg403b9c82008-09-17 00:19:53 +0200113 for (cmd = &__start___cmd; cmd < &__stop___cmd;
114 cmd = (struct cmd *)((char *)cmd + cmd_size)) {
Johannes Bergce5af552008-09-17 13:27:04 +0200115 if (!cmd->handler || cmd->hidden)
Johannes Berg403b9c82008-09-17 00:19:53 +0200116 continue;
Johannes Bergbd396f22008-09-16 16:56:09 +0200117 switch (cmd->idby) {
118 case CIB_NONE:
Johannes Berg59c49f02008-09-16 21:00:32 +0200119 fprintf(stderr, "\t");
Johannes Bergd6316502008-09-16 17:05:33 +0200120 /* fall through */
Johannes Bergbd396f22008-09-16 16:56:09 +0200121 case CIB_PHY:
Johannes Bergd6316502008-09-16 17:05:33 +0200122 if (cmd->idby == CIB_PHY)
Johannes Berg59c49f02008-09-16 21:00:32 +0200123 fprintf(stderr, "\tphy <phyname> ");
Johannes Bergbd396f22008-09-16 16:56:09 +0200124 /* fall through */
125 case CIB_NETDEV:
126 if (cmd->idby == CIB_NETDEV)
Johannes Berg59c49f02008-09-16 21:00:32 +0200127 fprintf(stderr, "\tdev <devname> ");
Johannes Bergbd396f22008-09-16 16:56:09 +0200128 if (cmd->section)
129 fprintf(stderr, "%s ", cmd->section);
130 fprintf(stderr, "%s", cmd->name);
131 if (cmd->args)
132 fprintf(stderr, " %s", cmd->args);
133 fprintf(stderr, "\n");
134 break;
135 }
136 }
Johannes Berg45c72122007-09-28 23:47:38 +0200137}
138
Johannes Bergd711f012008-09-16 21:56:25 +0200139static void version(void)
140{
Johannes Berg2dc285b2008-09-16 22:12:48 +0200141 printf("iw version " IW_VERSION "\n");
Johannes Bergd711f012008-09-16 21:56:25 +0200142}
143
Johannes Bergbd396f22008-09-16 16:56:09 +0200144static int phy_lookup(char *name)
Mike Kershaw1cdd9012007-09-29 19:17:20 -0400145{
Johannes Bergbd396f22008-09-16 16:56:09 +0200146 char buf[200];
147 int fd, pos;
148
149 snprintf(buf, sizeof(buf), "/sys/class/ieee80211/%s/index", name);
150
151 fd = open(buf, O_RDONLY);
152 pos = read(fd, buf, sizeof(buf) - 1);
153 if (pos < 0)
154 return -1;
155 buf[pos] = '\0';
156 return atoi(buf);
157}
158
Johannes Berg70391cc2008-09-16 18:35:06 +0200159static int error_handler(struct sockaddr_nl *nla, struct nlmsgerr *err,
160 void *arg)
161{
162 int *ret = arg;
163 *ret = err->error;
164 return NL_STOP;
165}
166
Johannes Berg561c5b72008-09-16 19:06:53 +0200167static int finish_handler(struct nl_msg *msg, void *arg)
168{
Johannes Berg59c418c2008-10-24 21:45:01 +0200169 int *ret = arg;
170 *ret = 0;
Johannes Berg561c5b72008-09-16 19:06:53 +0200171 return NL_SKIP;
172}
173
174static int ack_handler(struct nl_msg *msg, void *arg)
Johannes Berg70391cc2008-09-16 18:35:06 +0200175{
176 int *ret = arg;
177 *ret = 0;
178 return NL_STOP;
179}
180
Johannes Bergd6316502008-09-16 17:05:33 +0200181static int handle_cmd(struct nl80211_state *state,
182 enum command_identify_by idby,
183 int argc, char **argv)
Johannes Bergbd396f22008-09-16 16:56:09 +0200184{
185 struct cmd *cmd;
Johannes Berg70391cc2008-09-16 18:35:06 +0200186 struct nl_cb *cb = NULL;
Johannes Bergbd396f22008-09-16 16:56:09 +0200187 struct nl_msg *msg;
188 int devidx = 0;
Johannes Berg70391cc2008-09-16 18:35:06 +0200189 int err;
Johannes Bergbd396f22008-09-16 16:56:09 +0200190 const char *command, *section;
191
Johannes Bergd6316502008-09-16 17:05:33 +0200192 if (argc <= 1 && idby != CIB_NONE)
Johannes Berg5e75fd02008-09-16 18:13:12 +0200193 return 1;
Johannes Bergbd396f22008-09-16 16:56:09 +0200194
195 switch (idby) {
196 case CIB_PHY:
197 devidx = phy_lookup(*argv);
198 argc--;
199 argv++;
200 break;
201 case CIB_NETDEV:
202 devidx = if_nametoindex(*argv);
203 argc--;
204 argv++;
205 break;
206 default:
207 break;
208 }
209
210 section = command = *argv;
211 argc--;
212 argv++;
213
Johannes Berg403b9c82008-09-17 00:19:53 +0200214 for (cmd = &__start___cmd; cmd < &__stop___cmd;
215 cmd = (struct cmd *)((char *)cmd + cmd_size)) {
216 if (!cmd->handler)
217 continue;
Johannes Bergbd396f22008-09-16 16:56:09 +0200218 if (cmd->idby != idby)
219 continue;
220 if (cmd->section) {
221 if (strcmp(cmd->section, section))
222 continue;
223 /* this is a bit icky ... */
224 if (command == section) {
225 if (argc <= 0)
Johannes Berg5e75fd02008-09-16 18:13:12 +0200226 return 1;
Johannes Bergbd396f22008-09-16 16:56:09 +0200227 command = *argv;
228 argc--;
229 argv++;
230 }
231 } else if (section != command)
232 continue;
233 if (strcmp(cmd->name, command))
234 continue;
235 if (argc && !cmd->args)
236 continue;
237 break;
238 }
239
Johannes Berg74701032008-09-17 10:20:09 +0200240 if (cmd >= &__stop___cmd)
Johannes Berg5e75fd02008-09-16 18:13:12 +0200241 return 1;
Johannes Bergbd396f22008-09-16 16:56:09 +0200242
243 msg = nlmsg_alloc();
244 if (!msg) {
Johannes Berg70391cc2008-09-16 18:35:06 +0200245 fprintf(stderr, "failed to allocate netlink message\n");
246 return 2;
247 }
248
Johannes Berg59c49f02008-09-16 21:00:32 +0200249 cb = nl_cb_alloc(debug ? NL_CB_DEBUG : NL_CB_DEFAULT);
Johannes Berg70391cc2008-09-16 18:35:06 +0200250 if (!cb) {
251 fprintf(stderr, "failed to allocate netlink callbacks\n");
252 err = 2;
253 goto out_free_msg;
Johannes Bergbd396f22008-09-16 16:56:09 +0200254 }
255
256 genlmsg_put(msg, 0, 0, genl_family_get_id(state->nl80211), 0,
257 cmd->nl_msg_flags, cmd->cmd, 0);
258
259 switch (idby) {
260 case CIB_PHY:
261 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, devidx);
262 break;
263 case CIB_NETDEV:
264 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, devidx);
265 break;
266 default:
267 break;
268 }
269
Johannes Berg70391cc2008-09-16 18:35:06 +0200270 err = cmd->handler(cb, msg, argc, argv);
271 if (err)
272 goto out;
273
274 err = nl_send_auto_complete(state->nl_handle, msg);
275 if (err < 0)
276 goto out;
277
Johannes Bergc5c44712008-09-29 16:49:06 +0200278 err = 1;
279
Johannes Berg70391cc2008-09-16 18:35:06 +0200280 nl_cb_err(cb, NL_CB_CUSTOM, error_handler, &err);
Johannes Berg59c418c2008-10-24 21:45:01 +0200281 nl_cb_set(cb, NL_CB_FINISH, NL_CB_CUSTOM, finish_handler, &err);
Johannes Berg561c5b72008-09-16 19:06:53 +0200282 nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, ack_handler, &err);
Johannes Berg70391cc2008-09-16 18:35:06 +0200283
Johannes Bergc5c44712008-09-29 16:49:06 +0200284 while (err > 0)
285 nl_recvmsgs(state->nl_handle, cb);
Johannes Berg70391cc2008-09-16 18:35:06 +0200286 out:
287 nl_cb_put(cb);
288 out_free_msg:
289 nlmsg_free(msg);
290 return err;
Johannes Bergbd396f22008-09-16 16:56:09 +0200291 nla_put_failure:
292 fprintf(stderr, "building message failed\n");
Johannes Berg70391cc2008-09-16 18:35:06 +0200293 return 2;
Johannes Bergbd396f22008-09-16 16:56:09 +0200294}
295
Johannes Berg2c61ba62008-10-24 20:24:44 +0200296static int no_seq_check(struct nl_msg *msg, void *arg)
297{
298 return NL_OK;
299}
300
301static int print_event(struct nl_msg *msg, void *arg)
302{
303 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
304 struct nlattr *tb[NL80211_ATTR_MAX + 1];
305
306 nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
307 genlmsg_attrlen(gnlh, 0), NULL);
308
309 switch (gnlh->cmd) {
Johannes Berg03109dc2008-12-08 18:32:43 +0100310 case NL80211_CMD_NEW_WIPHY:
Johannes Berg2c61ba62008-10-24 20:24:44 +0200311 printf("wiphy rename: phy #%d to %s\n",
312 nla_get_u32(tb[NL80211_ATTR_WIPHY]),
313 nla_get_string(tb[NL80211_ATTR_WIPHY_NAME]));
314 break;
Johannes Berg03109dc2008-12-08 18:32:43 +0100315 default:
316 printf("unknown event: %d\n", gnlh->cmd);
317 break;
Johannes Berg2c61ba62008-10-24 20:24:44 +0200318 }
319
320 return NL_SKIP;
321}
322
323static int listen_events(struct nl80211_state *state,
324 int argc, char **argv)
325{
326 int mcid, ret;
327 struct nl_cb *cb = nl_cb_alloc(debug ? NL_CB_DEBUG : NL_CB_DEFAULT);
328
329 if (!cb) {
330 fprintf(stderr, "failed to allocate netlink callbacks\n");
331 return -ENOMEM;
332 }
333
334 mcid = nl_get_multicast_id(state->nl_handle, "nl80211", "config");
335 if (mcid < 0)
336 return mcid;
337
338 ret = nl_socket_add_membership(state->nl_handle, mcid);
339 if (ret)
340 return ret;
341
342 /* no sequence checking for multicast messages */
343 nl_cb_set(cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM, no_seq_check, NULL);
344 nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, print_event, NULL);
345
346 while (1)
347 nl_recvmsgs(state->nl_handle, cb);
348
349 nl_cb_put(cb);
350
351 return 0;
352}
353
Johannes Bergcad53b32007-09-28 22:11:34 +0200354int main(int argc, char **argv)
355{
356 struct nl80211_state nlstate;
Johannes Bergbd396f22008-09-16 16:56:09 +0200357 int err;
358 const char *argv0;
Johannes Bergcad53b32007-09-28 22:11:34 +0200359
Johannes Bergf408e012008-09-18 19:32:11 +0200360 /* calculate command size including padding */
Johannes Bergce5af552008-09-17 13:27:04 +0200361 cmd_size = abs((long)&__cmd_NULL_1_CIB_NONE_0
362 - (long)&__cmd_NULL_0_CIB_NONE_0);
Johannes Berg45c72122007-09-28 23:47:38 +0200363 /* strip off self */
364 argc--;
Mike Kershaw1cdd9012007-09-29 19:17:20 -0400365 argv0 = *argv++;
366
Johannes Berg59c49f02008-09-16 21:00:32 +0200367 if (argc > 0 && strcmp(*argv, "--debug") == 0) {
368 debug = 1;
369 argc--;
370 argv++;
371 }
372
Johannes Bergd711f012008-09-16 21:56:25 +0200373 if (argc > 0 && strcmp(*argv, "--version") == 0) {
374 version();
375 return 0;
376 }
377
Johannes Bergbd396f22008-09-16 16:56:09 +0200378 if (argc == 0 || strcmp(*argv, "help") == 0) {
Mike Kershaw1cdd9012007-09-29 19:17:20 -0400379 usage(argv0);
Johannes Berg4a972f82008-09-16 23:21:56 +0200380 return 0;
Mike Kershaw1cdd9012007-09-29 19:17:20 -0400381 }
Johannes Bergcad53b32007-09-28 22:11:34 +0200382
Johannes Berg2bdb6bd2008-09-16 23:20:20 +0200383 err = nl80211_init(&nlstate);
384 if (err)
385 return 1;
386
Johannes Berg2c61ba62008-10-24 20:24:44 +0200387 if (strcmp(*argv, "event") == 0) {
388 err = listen_events(&nlstate, argc, argv);
389 } else if (strcmp(*argv, "dev") == 0) {
Luis R. Rodriguez14a03802008-08-29 16:01:56 -0700390 argc--;
391 argv++;
Johannes Bergd6316502008-09-16 17:05:33 +0200392 err = handle_cmd(&nlstate, CIB_NETDEV, argc, argv);
Johannes Bergbd396f22008-09-16 16:56:09 +0200393 } else if (strcmp(*argv, "phy") == 0) {
394 argc--;
395 argv++;
Johannes Bergd6316502008-09-16 17:05:33 +0200396 err = handle_cmd(&nlstate, CIB_PHY, argc, argv);
Johannes Bergbd396f22008-09-16 16:56:09 +0200397 } else
Johannes Bergd6316502008-09-16 17:05:33 +0200398 err = handle_cmd(&nlstate, CIB_NONE, argc, argv);
Luis R. Rodriguez14a03802008-08-29 16:01:56 -0700399
Johannes Berg5e75fd02008-09-16 18:13:12 +0200400 if (err == 1)
Johannes Bergbd396f22008-09-16 16:56:09 +0200401 usage(argv0);
Johannes Berg5e75fd02008-09-16 18:13:12 +0200402 if (err < 0)
Johannes Bergb49be3e2008-09-16 18:54:39 +0200403 fprintf(stderr, "command failed: %s (%d)\n", strerror(-err), err);
Johannes Berg45c72122007-09-28 23:47:38 +0200404
Johannes Bergcad53b32007-09-28 22:11:34 +0200405 nl80211_cleanup(&nlstate);
406
Johannes Berg45c72122007-09-28 23:47:38 +0200407 return err;
Johannes Bergcad53b32007-09-28 22:11:34 +0200408}