blob: ce8240ce6b5fc0ed5d1925cc14bb421b70d6c9e5 [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>
21#include <linux/nl80211.h>
22
23#include "iw.h"
Johannes Bergd711f012008-09-16 21:56:25 +020024#include "version.h"
Johannes Bergcad53b32007-09-28 22:11:34 +020025
Johannes Berg59c49f02008-09-16 21:00:32 +020026int debug = 0;
Johannes Bergcad53b32007-09-28 22:11:34 +020027
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
Johannes Bergbd396f22008-09-16 16:56:09 +020074static void usage(const char *argv0)
Johannes Berg45c72122007-09-28 23:47:38 +020075{
Johannes Bergbd396f22008-09-16 16:56:09 +020076 struct cmd *cmd;
Johannes Berg45c72122007-09-28 23:47:38 +020077
Johannes Berg59c49f02008-09-16 21:00:32 +020078 fprintf(stderr, "Usage:\t%s [options] command\n", argv0);
79 fprintf(stderr, "Options:\n");
Johannes Bergd711f012008-09-16 21:56:25 +020080 fprintf(stderr, "\t--debug\t\tenable netlink debugging\n");
81 fprintf(stderr, "\t--version\tshow version\n");
Johannes Berg59c49f02008-09-16 21:00:32 +020082 fprintf(stderr, "Commands:\n");
Johannes Bergbd396f22008-09-16 16:56:09 +020083 for (cmd = &__start___cmd; cmd < &__stop___cmd; cmd++) {
84 switch (cmd->idby) {
85 case CIB_NONE:
Johannes Berg59c49f02008-09-16 21:00:32 +020086 fprintf(stderr, "\t");
Johannes Bergd6316502008-09-16 17:05:33 +020087 /* fall through */
Johannes Bergbd396f22008-09-16 16:56:09 +020088 case CIB_PHY:
Johannes Bergd6316502008-09-16 17:05:33 +020089 if (cmd->idby == CIB_PHY)
Johannes Berg59c49f02008-09-16 21:00:32 +020090 fprintf(stderr, "\tphy <phyname> ");
Johannes Bergbd396f22008-09-16 16:56:09 +020091 /* fall through */
92 case CIB_NETDEV:
93 if (cmd->idby == CIB_NETDEV)
Johannes Berg59c49f02008-09-16 21:00:32 +020094 fprintf(stderr, "\tdev <devname> ");
Johannes Bergbd396f22008-09-16 16:56:09 +020095 if (cmd->section)
96 fprintf(stderr, "%s ", cmd->section);
97 fprintf(stderr, "%s", cmd->name);
98 if (cmd->args)
99 fprintf(stderr, " %s", cmd->args);
100 fprintf(stderr, "\n");
101 break;
102 }
103 }
Johannes Berg45c72122007-09-28 23:47:38 +0200104}
105
Johannes Bergd711f012008-09-16 21:56:25 +0200106static void version(void)
107{
Johannes Berg2dc285b2008-09-16 22:12:48 +0200108 printf("iw version " IW_VERSION "\n");
Johannes Bergd711f012008-09-16 21:56:25 +0200109}
110
Johannes Bergbd396f22008-09-16 16:56:09 +0200111static int phy_lookup(char *name)
Mike Kershaw1cdd9012007-09-29 19:17:20 -0400112{
Johannes Bergbd396f22008-09-16 16:56:09 +0200113 char buf[200];
114 int fd, pos;
115
116 snprintf(buf, sizeof(buf), "/sys/class/ieee80211/%s/index", name);
117
118 fd = open(buf, O_RDONLY);
119 pos = read(fd, buf, sizeof(buf) - 1);
120 if (pos < 0)
121 return -1;
122 buf[pos] = '\0';
123 return atoi(buf);
124}
125
Johannes Berg70391cc2008-09-16 18:35:06 +0200126static int error_handler(struct sockaddr_nl *nla, struct nlmsgerr *err,
127 void *arg)
128{
129 int *ret = arg;
130 *ret = err->error;
131 return NL_STOP;
132}
133
Johannes Berg561c5b72008-09-16 19:06:53 +0200134static int finish_handler(struct nl_msg *msg, void *arg)
135{
136 return NL_SKIP;
137}
138
139static int ack_handler(struct nl_msg *msg, void *arg)
Johannes Berg70391cc2008-09-16 18:35:06 +0200140{
141 int *ret = arg;
142 *ret = 0;
143 return NL_STOP;
144}
145
Johannes Bergd6316502008-09-16 17:05:33 +0200146static int handle_cmd(struct nl80211_state *state,
147 enum command_identify_by idby,
148 int argc, char **argv)
Johannes Bergbd396f22008-09-16 16:56:09 +0200149{
150 struct cmd *cmd;
Johannes Berg70391cc2008-09-16 18:35:06 +0200151 struct nl_cb *cb = NULL;
Johannes Bergbd396f22008-09-16 16:56:09 +0200152 struct nl_msg *msg;
153 int devidx = 0;
Johannes Berg70391cc2008-09-16 18:35:06 +0200154 int err;
Johannes Bergbd396f22008-09-16 16:56:09 +0200155 const char *command, *section;
156
Johannes Bergd6316502008-09-16 17:05:33 +0200157 if (argc <= 1 && idby != CIB_NONE)
Johannes Berg5e75fd02008-09-16 18:13:12 +0200158 return 1;
Johannes Bergbd396f22008-09-16 16:56:09 +0200159
160 switch (idby) {
161 case CIB_PHY:
162 devidx = phy_lookup(*argv);
163 argc--;
164 argv++;
165 break;
166 case CIB_NETDEV:
167 devidx = if_nametoindex(*argv);
168 argc--;
169 argv++;
170 break;
171 default:
172 break;
173 }
174
175 section = command = *argv;
176 argc--;
177 argv++;
178
179 for (cmd = &__start___cmd; cmd < &__stop___cmd; cmd++) {
180 if (cmd->idby != idby)
181 continue;
182 if (cmd->section) {
183 if (strcmp(cmd->section, section))
184 continue;
185 /* this is a bit icky ... */
186 if (command == section) {
187 if (argc <= 0)
Johannes Berg5e75fd02008-09-16 18:13:12 +0200188 return 1;
Johannes Bergbd396f22008-09-16 16:56:09 +0200189 command = *argv;
190 argc--;
191 argv++;
192 }
193 } else if (section != command)
194 continue;
195 if (strcmp(cmd->name, command))
196 continue;
197 if (argc && !cmd->args)
198 continue;
199 break;
200 }
201
Johannes Bergbd396f22008-09-16 16:56:09 +0200202 if (cmd == &__stop___cmd)
Johannes Berg5e75fd02008-09-16 18:13:12 +0200203 return 1;
Johannes Bergbd396f22008-09-16 16:56:09 +0200204
205 msg = nlmsg_alloc();
206 if (!msg) {
Johannes Berg70391cc2008-09-16 18:35:06 +0200207 fprintf(stderr, "failed to allocate netlink message\n");
208 return 2;
209 }
210
Johannes Berg59c49f02008-09-16 21:00:32 +0200211 cb = nl_cb_alloc(debug ? NL_CB_DEBUG : NL_CB_DEFAULT);
Johannes Berg70391cc2008-09-16 18:35:06 +0200212 if (!cb) {
213 fprintf(stderr, "failed to allocate netlink callbacks\n");
214 err = 2;
215 goto out_free_msg;
Johannes Bergbd396f22008-09-16 16:56:09 +0200216 }
217
218 genlmsg_put(msg, 0, 0, genl_family_get_id(state->nl80211), 0,
219 cmd->nl_msg_flags, cmd->cmd, 0);
220
221 switch (idby) {
222 case CIB_PHY:
223 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, devidx);
224 break;
225 case CIB_NETDEV:
226 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, devidx);
227 break;
228 default:
229 break;
230 }
231
Johannes Berg70391cc2008-09-16 18:35:06 +0200232 err = cmd->handler(cb, msg, argc, argv);
233 if (err)
234 goto out;
235
236 err = nl_send_auto_complete(state->nl_handle, msg);
237 if (err < 0)
238 goto out;
239
240 nl_cb_err(cb, NL_CB_CUSTOM, error_handler, &err);
Johannes Berg561c5b72008-09-16 19:06:53 +0200241 nl_cb_set(cb, NL_CB_FINISH, NL_CB_CUSTOM, finish_handler, NULL);
242 nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, ack_handler, &err);
Johannes Berg70391cc2008-09-16 18:35:06 +0200243
Johannes Berg70391cc2008-09-16 18:35:06 +0200244 nl_recvmsgs(state->nl_handle, cb);
Johannes Berg70391cc2008-09-16 18:35:06 +0200245 out:
246 nl_cb_put(cb);
247 out_free_msg:
248 nlmsg_free(msg);
249 return err;
Johannes Bergbd396f22008-09-16 16:56:09 +0200250 nla_put_failure:
251 fprintf(stderr, "building message failed\n");
Johannes Berg70391cc2008-09-16 18:35:06 +0200252 return 2;
Johannes Bergbd396f22008-09-16 16:56:09 +0200253}
254
Johannes Bergcad53b32007-09-28 22:11:34 +0200255int main(int argc, char **argv)
256{
257 struct nl80211_state nlstate;
Johannes Bergbd396f22008-09-16 16:56:09 +0200258 int err;
259 const char *argv0;
Johannes Bergcad53b32007-09-28 22:11:34 +0200260
Johannes Berg45c72122007-09-28 23:47:38 +0200261 /* strip off self */
262 argc--;
Mike Kershaw1cdd9012007-09-29 19:17:20 -0400263 argv0 = *argv++;
264
Johannes Berg59c49f02008-09-16 21:00:32 +0200265 if (argc > 0 && strcmp(*argv, "--debug") == 0) {
266 debug = 1;
267 argc--;
268 argv++;
269 }
270
Johannes Bergd711f012008-09-16 21:56:25 +0200271 if (argc > 0 && strcmp(*argv, "--version") == 0) {
272 version();
273 return 0;
274 }
275
Johannes Bergbd396f22008-09-16 16:56:09 +0200276 if (argc == 0 || strcmp(*argv, "help") == 0) {
Mike Kershaw1cdd9012007-09-29 19:17:20 -0400277 usage(argv0);
278 goto out;
279 }
Johannes Bergcad53b32007-09-28 22:11:34 +0200280
Johannes Berg2bdb6bd2008-09-16 23:20:20 +0200281 err = nl80211_init(&nlstate);
282 if (err)
283 return 1;
284
Johannes Bergbd396f22008-09-16 16:56:09 +0200285 if (strcmp(*argv, "dev") == 0) {
Luis R. Rodriguez14a03802008-08-29 16:01:56 -0700286 argc--;
287 argv++;
Johannes Bergd6316502008-09-16 17:05:33 +0200288 err = handle_cmd(&nlstate, CIB_NETDEV, argc, argv);
Johannes Bergbd396f22008-09-16 16:56:09 +0200289 } else if (strcmp(*argv, "phy") == 0) {
290 argc--;
291 argv++;
Johannes Bergd6316502008-09-16 17:05:33 +0200292 err = handle_cmd(&nlstate, CIB_PHY, argc, argv);
Johannes Bergbd396f22008-09-16 16:56:09 +0200293 } else
Johannes Bergd6316502008-09-16 17:05:33 +0200294 err = handle_cmd(&nlstate, CIB_NONE, argc, argv);
Luis R. Rodriguez14a03802008-08-29 16:01:56 -0700295
Johannes Berg5e75fd02008-09-16 18:13:12 +0200296 if (err == 1)
Johannes Bergbd396f22008-09-16 16:56:09 +0200297 usage(argv0);
Johannes Berg5e75fd02008-09-16 18:13:12 +0200298 if (err < 0)
Johannes Bergb49be3e2008-09-16 18:54:39 +0200299 fprintf(stderr, "command failed: %s (%d)\n", strerror(-err), err);
Johannes Berg45c72122007-09-28 23:47:38 +0200300
301 out:
Johannes Bergcad53b32007-09-28 22:11:34 +0200302 nl80211_cleanup(&nlstate);
303
Johannes Berg45c72122007-09-28 23:47:38 +0200304 return err;
Johannes Bergcad53b32007-09-28 22:11:34 +0200305}