iw.c revision 59c49f099cb590542a90347630951cef26f13fa7
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 25int debug = 0; 26 27static int nl80211_init(struct nl80211_state *state) 28{ 29 int err; 30 31 state->nl_handle = nl_handle_alloc(); 32 if (!state->nl_handle) { 33 fprintf(stderr, "Failed to allocate netlink handle.\n"); 34 return -ENOMEM; 35 } 36 37 if (genl_connect(state->nl_handle)) { 38 fprintf(stderr, "Failed to connect to generic netlink.\n"); 39 err = -ENOLINK; 40 goto out_handle_destroy; 41 } 42 43 state->nl_cache = genl_ctrl_alloc_cache(state->nl_handle); 44 if (!state->nl_cache) { 45 fprintf(stderr, "Failed to allocate generic netlink cache.\n"); 46 err = -ENOMEM; 47 goto out_handle_destroy; 48 } 49 50 state->nl80211 = genl_ctrl_search_by_name(state->nl_cache, "nl80211"); 51 if (!state->nl80211) { 52 fprintf(stderr, "nl80211 not found.\n"); 53 err = -ENOENT; 54 goto out_cache_free; 55 } 56 57 return 0; 58 59 out_cache_free: 60 nl_cache_free(state->nl_cache); 61 out_handle_destroy: 62 nl_handle_destroy(state->nl_handle); 63 return err; 64} 65 66static void nl80211_cleanup(struct nl80211_state *state) 67{ 68 genl_family_put(state->nl80211); 69 nl_cache_free(state->nl_cache); 70 nl_handle_destroy(state->nl_handle); 71} 72 73static void usage(const char *argv0) 74{ 75 struct cmd *cmd; 76 77 fprintf(stderr, "Usage:\t%s [options] command\n", argv0); 78 fprintf(stderr, "Options:\n"); 79 fprintf(stderr, "\t--debug\tenable netlink debugging\n"); 80 fprintf(stderr, "Commands:\n"); 81 for (cmd = &__start___cmd; cmd < &__stop___cmd; cmd++) { 82 switch (cmd->idby) { 83 case CIB_NONE: 84 fprintf(stderr, "\t"); 85 /* fall through */ 86 case CIB_PHY: 87 if (cmd->idby == CIB_PHY) 88 fprintf(stderr, "\tphy <phyname> "); 89 /* fall through */ 90 case CIB_NETDEV: 91 if (cmd->idby == CIB_NETDEV) 92 fprintf(stderr, "\tdev <devname> "); 93 if (cmd->section) 94 fprintf(stderr, "%s ", cmd->section); 95 fprintf(stderr, "%s", cmd->name); 96 if (cmd->args) 97 fprintf(stderr, " %s", cmd->args); 98 fprintf(stderr, "\n"); 99 break; 100 } 101 } 102} 103 104static int phy_lookup(char *name) 105{ 106 char buf[200]; 107 int fd, pos; 108 109 snprintf(buf, sizeof(buf), "/sys/class/ieee80211/%s/index", name); 110 111 fd = open(buf, O_RDONLY); 112 pos = read(fd, buf, sizeof(buf) - 1); 113 if (pos < 0) 114 return -1; 115 buf[pos] = '\0'; 116 return atoi(buf); 117} 118 119static int error_handler(struct sockaddr_nl *nla, struct nlmsgerr *err, 120 void *arg) 121{ 122 int *ret = arg; 123 *ret = err->error; 124 return NL_STOP; 125} 126 127static int finish_handler(struct nl_msg *msg, void *arg) 128{ 129 return NL_SKIP; 130} 131 132static int ack_handler(struct nl_msg *msg, void *arg) 133{ 134 int *ret = arg; 135 *ret = 0; 136 return NL_STOP; 137} 138 139static int handle_cmd(struct nl80211_state *state, 140 enum command_identify_by idby, 141 int argc, char **argv) 142{ 143 struct cmd *cmd; 144 struct nl_cb *cb = NULL; 145 struct nl_msg *msg; 146 int devidx = 0; 147 int err; 148 const char *command, *section; 149 150 if (argc <= 1 && idby != CIB_NONE) 151 return 1; 152 153 switch (idby) { 154 case CIB_PHY: 155 devidx = phy_lookup(*argv); 156 argc--; 157 argv++; 158 break; 159 case CIB_NETDEV: 160 devidx = if_nametoindex(*argv); 161 argc--; 162 argv++; 163 break; 164 default: 165 break; 166 } 167 168 section = command = *argv; 169 argc--; 170 argv++; 171 172 for (cmd = &__start___cmd; cmd < &__stop___cmd; cmd++) { 173 if (cmd->idby != idby) 174 continue; 175 if (cmd->section) { 176 if (strcmp(cmd->section, section)) 177 continue; 178 /* this is a bit icky ... */ 179 if (command == section) { 180 if (argc <= 0) 181 return 1; 182 command = *argv; 183 argc--; 184 argv++; 185 } 186 } else if (section != command) 187 continue; 188 if (strcmp(cmd->name, command)) 189 continue; 190 if (argc && !cmd->args) 191 continue; 192 break; 193 } 194 195 if (cmd == &__stop___cmd) 196 return 1; 197 198 msg = nlmsg_alloc(); 199 if (!msg) { 200 fprintf(stderr, "failed to allocate netlink message\n"); 201 return 2; 202 } 203 204 cb = nl_cb_alloc(debug ? NL_CB_DEBUG : NL_CB_DEFAULT); 205 if (!cb) { 206 fprintf(stderr, "failed to allocate netlink callbacks\n"); 207 err = 2; 208 goto out_free_msg; 209 } 210 211 genlmsg_put(msg, 0, 0, genl_family_get_id(state->nl80211), 0, 212 cmd->nl_msg_flags, cmd->cmd, 0); 213 214 switch (idby) { 215 case CIB_PHY: 216 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, devidx); 217 break; 218 case CIB_NETDEV: 219 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, devidx); 220 break; 221 default: 222 break; 223 } 224 225 err = cmd->handler(cb, msg, argc, argv); 226 if (err) 227 goto out; 228 229 err = nl_send_auto_complete(state->nl_handle, msg); 230 if (err < 0) 231 goto out; 232 233 nl_cb_err(cb, NL_CB_CUSTOM, error_handler, &err); 234 nl_cb_set(cb, NL_CB_FINISH, NL_CB_CUSTOM, finish_handler, NULL); 235 nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, ack_handler, &err); 236 237 nl_recvmsgs(state->nl_handle, cb); 238 out: 239 nl_cb_put(cb); 240 out_free_msg: 241 nlmsg_free(msg); 242 return err; 243 nla_put_failure: 244 fprintf(stderr, "building message failed\n"); 245 return 2; 246} 247 248int main(int argc, char **argv) 249{ 250 struct nl80211_state nlstate; 251 int err; 252 const char *argv0; 253 254 err = nl80211_init(&nlstate); 255 if (err) 256 return 1; 257 258 /* strip off self */ 259 argc--; 260 argv0 = *argv++; 261 262 if (argc > 0 && strcmp(*argv, "--debug") == 0) { 263 debug = 1; 264 argc--; 265 argv++; 266 } 267 268 if (argc == 0 || strcmp(*argv, "help") == 0) { 269 usage(argv0); 270 goto out; 271 } 272 273 if (strcmp(*argv, "dev") == 0) { 274 argc--; 275 argv++; 276 err = handle_cmd(&nlstate, CIB_NETDEV, argc, argv); 277 } else if (strcmp(*argv, "phy") == 0) { 278 argc--; 279 argv++; 280 err = handle_cmd(&nlstate, CIB_PHY, argc, argv); 281 } else 282 err = handle_cmd(&nlstate, CIB_NONE, argc, argv); 283 284 if (err == 1) 285 usage(argv0); 286 if (err < 0) 287 fprintf(stderr, "command failed: %s (%d)\n", strerror(-err), err); 288 289 out: 290 nl80211_cleanup(&nlstate); 291 292 return err; 293} 294