iw.c revision 4a972f80a40584eb0f119a204f0eb6568b3368f2
1/* 2 * nl80211 userspace tool 3 * 4 * Copyright 2007, 2008 Johannes Berg <johannes@sipsolutions.net> 5 */ 6 7#include <errno.h> 8#include <stdio.h> 9#include <string.h> 10#include <net/if.h> 11#include <sys/types.h> 12#include <sys/stat.h> 13#include <fcntl.h> 14#include <unistd.h> 15 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> 21#include <linux/nl80211.h> 22 23#include "iw.h" 24#include "version.h" 25 26int debug = 0; 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 74static void usage(const char *argv0) 75{ 76 struct cmd *cmd; 77 78 fprintf(stderr, "Usage:\t%s [options] command\n", argv0); 79 fprintf(stderr, "Options:\n"); 80 fprintf(stderr, "\t--debug\t\tenable netlink debugging\n"); 81 fprintf(stderr, "\t--version\tshow version\n"); 82 fprintf(stderr, "Commands:\n"); 83 for (cmd = &__start___cmd; cmd < &__stop___cmd; cmd++) { 84 switch (cmd->idby) { 85 case CIB_NONE: 86 fprintf(stderr, "\t"); 87 /* fall through */ 88 case CIB_PHY: 89 if (cmd->idby == CIB_PHY) 90 fprintf(stderr, "\tphy <phyname> "); 91 /* fall through */ 92 case CIB_NETDEV: 93 if (cmd->idby == CIB_NETDEV) 94 fprintf(stderr, "\tdev <devname> "); 95 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 } 104} 105 106static void version(void) 107{ 108 printf("iw version " IW_VERSION "\n"); 109} 110 111static int phy_lookup(char *name) 112{ 113 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 126static 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 134static 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) 140{ 141 int *ret = arg; 142 *ret = 0; 143 return NL_STOP; 144} 145 146static int handle_cmd(struct nl80211_state *state, 147 enum command_identify_by idby, 148 int argc, char **argv) 149{ 150 struct cmd *cmd; 151 struct nl_cb *cb = NULL; 152 struct nl_msg *msg; 153 int devidx = 0; 154 int err; 155 const char *command, *section; 156 157 if (argc <= 1 && idby != CIB_NONE) 158 return 1; 159 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) 188 return 1; 189 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 202 if (cmd == &__stop___cmd) 203 return 1; 204 205 msg = nlmsg_alloc(); 206 if (!msg) { 207 fprintf(stderr, "failed to allocate netlink message\n"); 208 return 2; 209 } 210 211 cb = nl_cb_alloc(debug ? NL_CB_DEBUG : NL_CB_DEFAULT); 212 if (!cb) { 213 fprintf(stderr, "failed to allocate netlink callbacks\n"); 214 err = 2; 215 goto out_free_msg; 216 } 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 232 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); 241 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); 243 244 nl_recvmsgs(state->nl_handle, cb); 245 out: 246 nl_cb_put(cb); 247 out_free_msg: 248 nlmsg_free(msg); 249 return err; 250 nla_put_failure: 251 fprintf(stderr, "building message failed\n"); 252 return 2; 253} 254 255int main(int argc, char **argv) 256{ 257 struct nl80211_state nlstate; 258 int err; 259 const char *argv0; 260 261 /* strip off self */ 262 argc--; 263 argv0 = *argv++; 264 265 if (argc > 0 && strcmp(*argv, "--debug") == 0) { 266 debug = 1; 267 argc--; 268 argv++; 269 } 270 271 if (argc > 0 && strcmp(*argv, "--version") == 0) { 272 version(); 273 return 0; 274 } 275 276 if (argc == 0 || strcmp(*argv, "help") == 0) { 277 usage(argv0); 278 return 0; 279 } 280 281 err = nl80211_init(&nlstate); 282 if (err) 283 return 1; 284 285 if (strcmp(*argv, "dev") == 0) { 286 argc--; 287 argv++; 288 err = handle_cmd(&nlstate, CIB_NETDEV, argc, argv); 289 } else if (strcmp(*argv, "phy") == 0) { 290 argc--; 291 argv++; 292 err = handle_cmd(&nlstate, CIB_PHY, argc, argv); 293 } else 294 err = handle_cmd(&nlstate, CIB_NONE, argc, argv); 295 296 if (err == 1) 297 usage(argv0); 298 if (err < 0) 299 fprintf(stderr, "command failed: %s (%d)\n", strerror(-err), err); 300 301 nl80211_cleanup(&nlstate); 302 303 return err; 304} 305