2 * nl80211 userspace tool
4 * Copyright 2007, 2008 Johannes Berg <johannes@sipsolutions.net>
11 #include <sys/types.h>
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>
26 #ifndef CONFIG_LIBNL20
27 /* libnl 2.0 compatibility code */
29 static inline struct nl_handle
*nl_socket_alloc(void)
31 return nl_handle_alloc();
34 static inline void nl_socket_free(struct nl_sock
*h
)
39 static inline int __genl_ctrl_alloc_cache(struct nl_sock
*h
, struct nl_cache
**cache
)
41 struct nl_cache
*tmp
= genl_ctrl_alloc_cache(h
);
47 #define genl_ctrl_alloc_cache __genl_ctrl_alloc_cache
48 #endif /* CONFIG_LIBNL20 */
52 static int nl80211_init(struct nl80211_state
*state
)
56 state
->nl_sock
= nl_socket_alloc();
57 if (!state
->nl_sock
) {
58 fprintf(stderr
, "Failed to allocate netlink socket.\n");
62 if (genl_connect(state
->nl_sock
)) {
63 fprintf(stderr
, "Failed to connect to generic netlink.\n");
65 goto out_handle_destroy
;
68 if (genl_ctrl_alloc_cache(state
->nl_sock
, &state
->nl_cache
)) {
69 fprintf(stderr
, "Failed to allocate generic netlink cache.\n");
71 goto out_handle_destroy
;
74 state
->nl80211
= genl_ctrl_search_by_name(state
->nl_cache
, "nl80211");
75 if (!state
->nl80211
) {
76 fprintf(stderr
, "nl80211 not found.\n");
84 nl_cache_free(state
->nl_cache
);
86 nl_socket_free(state
->nl_sock
);
90 static void nl80211_cleanup(struct nl80211_state
*state
)
92 genl_family_put(state
->nl80211
);
93 nl_cache_free(state
->nl_cache
);
94 nl_socket_free(state
->nl_sock
);
97 __COMMAND(NULL
, NULL
, NULL
, 0, 0, 0, CIB_NONE
, NULL
);
98 __COMMAND(NULL
, NULL
, NULL
, 1, 0, 0, CIB_NONE
, NULL
);
102 static void usage(const char *argv0
)
106 fprintf(stderr
, "Usage:\t%s [options] command\n", argv0
);
107 fprintf(stderr
, "Options:\n");
108 fprintf(stderr
, "\t--debug\t\tenable netlink debugging\n");
109 fprintf(stderr
, "\t--version\tshow version\n");
110 fprintf(stderr
, "Commands:\n");
111 fprintf(stderr
, "\thelp\n");
112 fprintf(stderr
, "\tevent\n");
113 for (cmd
= &__start___cmd
; cmd
< &__stop___cmd
;
114 cmd
= (struct cmd
*)((char *)cmd
+ cmd_size
)) {
115 if (!cmd
->handler
|| cmd
->hidden
)
119 fprintf(stderr
, "\t");
122 if (cmd
->idby
== CIB_PHY
)
123 fprintf(stderr
, "\tphy <phyname> ");
126 if (cmd
->idby
== CIB_NETDEV
)
127 fprintf(stderr
, "\tdev <devname> ");
129 fprintf(stderr
, "%s ", cmd
->section
);
130 fprintf(stderr
, "%s", cmd
->name
);
132 fprintf(stderr
, " %s", cmd
->args
);
133 fprintf(stderr
, "\n");
139 static void version(void)
141 printf("iw version " IW_VERSION
"\n");
144 static int phy_lookup(char *name
)
149 snprintf(buf
, sizeof(buf
), "/sys/class/ieee80211/%s/index", name
);
151 fd
= open(buf
, O_RDONLY
);
152 pos
= read(fd
, buf
, sizeof(buf
) - 1);
159 static int error_handler(struct sockaddr_nl
*nla
, struct nlmsgerr
*err
,
167 static int finish_handler(struct nl_msg
*msg
, void *arg
)
174 static int ack_handler(struct nl_msg
*msg
, void *arg
)
181 static int handle_cmd(struct nl80211_state
*state
,
182 enum command_identify_by idby
,
183 int argc
, char **argv
)
186 struct nl_cb
*cb
= NULL
;
190 const char *command
, *section
;
192 if (argc
<= 1 && idby
!= CIB_NONE
)
197 devidx
= phy_lookup(*argv
);
202 devidx
= if_nametoindex(*argv
);
210 section
= command
= *argv
;
214 for (cmd
= &__start___cmd
; cmd
< &__stop___cmd
;
215 cmd
= (struct cmd
*)((char *)cmd
+ cmd_size
)) {
218 if (cmd
->idby
!= idby
)
221 if (strcmp(cmd
->section
, section
))
223 /* this is a bit icky ... */
224 if (command
== section
) {
231 } else if (section
!= command
)
233 if (strcmp(cmd
->name
, command
))
235 if (argc
&& !cmd
->args
)
240 if (cmd
>= &__stop___cmd
)
245 fprintf(stderr
, "failed to allocate netlink message\n");
249 cb
= nl_cb_alloc(debug
? NL_CB_DEBUG
: NL_CB_DEFAULT
);
251 fprintf(stderr
, "failed to allocate netlink callbacks\n");
256 genlmsg_put(msg
, 0, 0, genl_family_get_id(state
->nl80211
), 0,
257 cmd
->nl_msg_flags
, cmd
->cmd
, 0);
261 NLA_PUT_U32(msg
, NL80211_ATTR_WIPHY
, devidx
);
264 NLA_PUT_U32(msg
, NL80211_ATTR_IFINDEX
, devidx
);
270 err
= cmd
->handler(cb
, msg
, argc
, argv
);
274 err
= nl_send_auto_complete(state
->nl_sock
, msg
);
280 nl_cb_err(cb
, NL_CB_CUSTOM
, error_handler
, &err
);
281 nl_cb_set(cb
, NL_CB_FINISH
, NL_CB_CUSTOM
, finish_handler
, &err
);
282 nl_cb_set(cb
, NL_CB_ACK
, NL_CB_CUSTOM
, ack_handler
, &err
);
285 nl_recvmsgs(state
->nl_sock
, cb
);
292 fprintf(stderr
, "building message failed\n");
296 static int no_seq_check(struct nl_msg
*msg
, void *arg
)
301 static int print_event(struct nl_msg
*msg
, void *arg
)
303 struct genlmsghdr
*gnlh
= nlmsg_data(nlmsg_hdr(msg
));
304 struct nlattr
*tb
[NL80211_ATTR_MAX
+ 1];
308 nla_parse(tb
, NL80211_ATTR_MAX
, genlmsg_attrdata(gnlh
, 0),
309 genlmsg_attrlen(gnlh
, 0), NULL
);
312 case NL80211_CMD_NEW_WIPHY
:
313 printf("wiphy rename: phy #%d to %s\n",
314 nla_get_u32(tb
[NL80211_ATTR_WIPHY
]),
315 nla_get_string(tb
[NL80211_ATTR_WIPHY_NAME
]));
317 case NL80211_CMD_NEW_SCAN_RESULTS
:
318 if_indextoname(nla_get_u32(tb
[NL80211_ATTR_IFINDEX
]), ifname
);
319 printf("scan finished on %s (phy #%d)\n",
320 ifname
, nla_get_u32(tb
[NL80211_ATTR_WIPHY
]));
322 case NL80211_CMD_SCAN_ABORTED
:
323 if_indextoname(nla_get_u32(tb
[NL80211_ATTR_IFINDEX
]), ifname
);
324 printf("scan aborted on %s (phy #%d)\n",
325 ifname
, nla_get_u32(tb
[NL80211_ATTR_WIPHY
]));
327 case NL80211_CMD_REG_CHANGE
:
329 printf("regulatory domain change: ");
331 reg_type
= nla_get_u8(tb
[NL80211_ATTR_REG_TYPE
]);
334 case NL80211_REGDOM_TYPE_COUNTRY
:
335 printf("set to %s by %s request",
336 nla_get_string(tb
[NL80211_ATTR_REG_ALPHA2
]),
337 reg_initiator_to_string(nla_get_u8(tb
[NL80211_ATTR_REG_INITIATOR
])));
338 if (tb
[NL80211_ATTR_WIPHY
])
339 printf(" on phy%d", nla_get_u32(tb
[NL80211_ATTR_WIPHY
]));
341 case NL80211_REGDOM_TYPE_WORLD
:
342 printf("set to world roaming by %s request",
343 reg_initiator_to_string(nla_get_u8(tb
[NL80211_ATTR_REG_INITIATOR
])));
345 case NL80211_REGDOM_TYPE_CUSTOM_WORLD
:
346 printf("custom world roaming rules in place on phy%d by %s request",
347 nla_get_u32(tb
[NL80211_ATTR_WIPHY
]),
348 reg_initiator_to_string(nla_get_u32(tb
[NL80211_ATTR_REG_INITIATOR
])));
350 case NL80211_REGDOM_TYPE_INTERSECTION
:
351 printf("intersection used due to a request made by %s",
352 reg_initiator_to_string(nla_get_u32(tb
[NL80211_ATTR_REG_INITIATOR
])));
353 if (tb
[NL80211_ATTR_WIPHY
])
354 printf(" on phy%d", nla_get_u32(tb
[NL80211_ATTR_WIPHY
]));
357 printf("unknown source (upgrade this utility)");
364 printf("unknown event: %d\n", gnlh
->cmd
);
371 static int listen_events(struct nl80211_state
*state
,
372 int argc
, char **argv
)
375 struct nl_cb
*cb
= nl_cb_alloc(debug
? NL_CB_DEBUG
: NL_CB_DEFAULT
);
378 fprintf(stderr
, "failed to allocate netlink callbacks\n");
382 /* Configuration multicast group */
383 mcid
= nl_get_multicast_id(state
->nl_sock
, "nl80211", "config");
387 ret
= nl_socket_add_membership(state
->nl_sock
, mcid
);
391 /* Scan multicast group */
392 mcid
= nl_get_multicast_id(state
->nl_sock
, "nl80211", "scan");
394 ret
= nl_socket_add_membership(state
->nl_sock
, mcid
);
399 /* Regulatory multicast group */
400 mcid
= nl_get_multicast_id(state
->nl_sock
, "nl80211", "regulatory");
402 ret
= nl_socket_add_membership(state
->nl_sock
, mcid
);
407 /* no sequence checking for multicast messages */
408 nl_cb_set(cb
, NL_CB_SEQ_CHECK
, NL_CB_CUSTOM
, no_seq_check
, NULL
);
409 nl_cb_set(cb
, NL_CB_VALID
, NL_CB_CUSTOM
, print_event
, NULL
);
412 nl_recvmsgs(state
->nl_sock
, cb
);
419 int main(int argc
, char **argv
)
421 struct nl80211_state nlstate
;
425 /* calculate command size including padding */
426 cmd_size
= abs((long)&__cmd_NULL_1_CIB_NONE_0
427 - (long)&__cmd_NULL_0_CIB_NONE_0
);
432 if (argc
> 0 && strcmp(*argv
, "--debug") == 0) {
438 if (argc
> 0 && strcmp(*argv
, "--version") == 0) {
443 if (argc
== 0 || strcmp(*argv
, "help") == 0) {
448 err
= nl80211_init(&nlstate
);
452 if (strcmp(*argv
, "event") == 0) {
453 err
= listen_events(&nlstate
, argc
, argv
);
454 } else if (strcmp(*argv
, "dev") == 0) {
457 err
= handle_cmd(&nlstate
, CIB_NETDEV
, argc
, argv
);
458 } else if (strcmp(*argv
, "phy") == 0) {
461 err
= handle_cmd(&nlstate
, CIB_PHY
, argc
, argv
);
463 err
= handle_cmd(&nlstate
, CIB_NONE
, argc
, argv
);
468 fprintf(stderr
, "command failed: %s (%d)\n", strerror(-err
), err
);
470 nl80211_cleanup(&nlstate
);