2 * nl80211 userspace tool
4 * Copyright 2007, 2008 Johannes Berg <johannes@sipsolutions.net>
11 #include <sys/types.h>
17 #include <netlink/genl/genl.h>
18 #include <netlink/genl/family.h>
19 #include <netlink/genl/ctrl.h>
20 #include <netlink/msg.h>
21 #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_cmd(struct cmd
*cmd
)
106 fprintf(stderr
, "\t");
109 fprintf(stderr
, "\tphy <phyname> ");
112 fprintf(stderr
, "\tdev <devname> ");
116 fprintf(stderr
, "%s ", cmd
->section
);
117 fprintf(stderr
, "%s", cmd
->name
);
119 fprintf(stderr
, " %s", cmd
->args
);
120 fprintf(stderr
, "\n");
123 static void usage(const char *argv0
)
127 fprintf(stderr
, "Usage:\t%s [options] command\n", argv0
);
128 fprintf(stderr
, "Options:\n");
129 fprintf(stderr
, "\t--debug\t\tenable netlink debugging\n");
130 fprintf(stderr
, "\t--version\tshow version\n");
131 fprintf(stderr
, "Commands:\n");
132 fprintf(stderr
, "\thelp\n");
133 fprintf(stderr
, "\tevent [-t] [-f]\n");
134 for (cmd
= &__start___cmd
; cmd
< &__stop___cmd
;
135 cmd
= (struct cmd
*)((char *)cmd
+ cmd_size
)) {
136 if (!cmd
->handler
|| cmd
->hidden
)
142 static void version(void)
144 printf("iw version %s\n", iw_version
);
147 static int phy_lookup(char *name
)
152 snprintf(buf
, sizeof(buf
), "/sys/class/ieee80211/%s/index", name
);
154 fd
= open(buf
, O_RDONLY
);
157 pos
= read(fd
, buf
, sizeof(buf
) - 1);
164 static int error_handler(struct sockaddr_nl
*nla
, struct nlmsgerr
*err
,
172 static int finish_handler(struct nl_msg
*msg
, void *arg
)
179 static int ack_handler(struct nl_msg
*msg
, void *arg
)
186 int handle_cmd(struct nl80211_state
*state
, enum id_input idby
,
187 int argc
, char **argv
)
189 struct cmd
*cmd
, *match
= NULL
;
194 const char *command
, *section
;
196 enum command_identify_by command_idby
= CIB_NONE
;
198 if (argc
<= 1 && idby
!= II_NONE
)
206 command_idby
= CIB_PHY
;
207 devidx
= strtoul(*argv
+ 4, &tmp
, 0);
214 command_idby
= CIB_PHY
;
215 devidx
= phy_lookup(*argv
);
220 command_idby
= CIB_NETDEV
;
221 devidx
= if_nametoindex(*argv
);
234 section
= command
= *argv
;
238 for (cmd
= &__start___cmd
; cmd
< &__stop___cmd
;
239 cmd
= (struct cmd
*)((char *)cmd
+ cmd_size
)) {
242 if (cmd
->idby
!= command_idby
)
245 if (strcmp(cmd
->section
, section
))
247 /* this is a bit icky ... */
248 if (command
== section
) {
258 } else if (section
!= command
)
260 if (strcmp(cmd
->name
, command
))
262 if (argc
&& !cmd
->args
)
276 return cmd
->handler(state
, NULL
, NULL
, argc
, argv
);
281 fprintf(stderr
, "failed to allocate netlink message\n");
285 cb
= nl_cb_alloc(debug
? NL_CB_DEBUG
: NL_CB_DEFAULT
);
287 fprintf(stderr
, "failed to allocate netlink callbacks\n");
292 genlmsg_put(msg
, 0, 0, genl_family_get_id(state
->nl80211
), 0,
293 cmd
->nl_msg_flags
, cmd
->cmd
, 0);
295 switch (command_idby
) {
297 NLA_PUT_U32(msg
, NL80211_ATTR_WIPHY
, devidx
);
300 NLA_PUT_U32(msg
, NL80211_ATTR_IFINDEX
, devidx
);
306 err
= cmd
->handler(state
, cb
, msg
, argc
, argv
);
310 err
= nl_send_auto_complete(state
->nl_sock
, msg
);
316 nl_cb_err(cb
, NL_CB_CUSTOM
, error_handler
, &err
);
317 nl_cb_set(cb
, NL_CB_FINISH
, NL_CB_CUSTOM
, finish_handler
, &err
);
318 nl_cb_set(cb
, NL_CB_ACK
, NL_CB_CUSTOM
, ack_handler
, &err
);
321 nl_recvmsgs(state
->nl_sock
, cb
);
328 fprintf(stderr
, "building message failed\n");
332 static int no_seq_check(struct nl_msg
*msg
, void *arg
)
337 struct print_event_args
{
341 static void print_frame(struct print_event_args
*args
, struct nlattr
*attr
)
350 printf(" [no frame]");
352 frame
= nla_data(attr
);
356 printf(" [invalid frame: ");
360 mac_addr_n2a(macbuf
, frame
+ 10);
361 printf(" %s -> ", macbuf
);
362 mac_addr_n2a(macbuf
, frame
+ 4);
363 printf("%s", macbuf
);
365 switch (frame
[0] & 0xfc) {
366 case 0x10: /* assoc resp */
367 case 0x30: /* reassoc resp */
369 tmp
= (frame
[27] << 8) + frame
[26];
370 printf(" status: %d: %s", tmp
, get_status_str(tmp
));
372 case 0x00: /* assoc req */
373 case 0x20: /* reassoc req */
375 case 0xb0: /* auth */
377 tmp
= (frame
[29] << 8) + frame
[28];
378 printf(" status: %d: %s", tmp
, get_status_str(tmp
));
381 case 0xa0: /* disassoc */
382 case 0xc0: /* deauth */
384 tmp
= (frame
[25] << 8) + frame
[24];
385 printf(" reason %d: %s", tmp
, get_reason_str(tmp
));
395 for (i
= 0; i
< len
; i
++)
396 printf(" %.02x", frame
[i
]);
400 static int print_event(struct nl_msg
*msg
, void *arg
)
402 struct genlmsghdr
*gnlh
= nlmsg_data(nlmsg_hdr(msg
));
403 struct nlattr
*tb
[NL80211_ATTR_MAX
+ 1];
404 struct print_event_args
*args
= arg
;
411 gettimeofday(&tv
, NULL
);
412 printf("%ld.%06u: ", (long) tv
.tv_sec
, (unsigned int) tv
.tv_usec
);
415 nla_parse(tb
, NL80211_ATTR_MAX
, genlmsg_attrdata(gnlh
, 0),
416 genlmsg_attrlen(gnlh
, 0), NULL
);
418 if (tb
[NL80211_ATTR_IFINDEX
] && tb
[NL80211_ATTR_WIPHY
]) {
419 if_indextoname(nla_get_u32(tb
[NL80211_ATTR_IFINDEX
]), ifname
);
420 printf("%s (phy #%d): ", ifname
, nla_get_u32(tb
[NL80211_ATTR_WIPHY
]));
421 } else if (tb
[NL80211_ATTR_IFINDEX
]) {
422 if_indextoname(nla_get_u32(tb
[NL80211_ATTR_IFINDEX
]), ifname
);
423 printf("%s: ", ifname
);
424 } else if (tb
[NL80211_ATTR_WIPHY
]) {
425 printf("phy #%d: ", nla_get_u32(tb
[NL80211_ATTR_WIPHY
]));
429 case NL80211_CMD_NEW_WIPHY
:
430 printf("renamed to %s\n", nla_get_string(tb
[NL80211_ATTR_WIPHY_NAME
]));
432 case NL80211_CMD_NEW_SCAN_RESULTS
:
433 printf("scan finished\n");
435 case NL80211_CMD_SCAN_ABORTED
:
436 printf("scan aborted\n");
438 case NL80211_CMD_REG_CHANGE
:
439 printf("regulatory domain change: ");
441 reg_type
= nla_get_u8(tb
[NL80211_ATTR_REG_TYPE
]);
444 case NL80211_REGDOM_TYPE_COUNTRY
:
445 printf("set to %s by %s request",
446 nla_get_string(tb
[NL80211_ATTR_REG_ALPHA2
]),
447 reg_initiator_to_string(nla_get_u8(tb
[NL80211_ATTR_REG_INITIATOR
])));
448 if (tb
[NL80211_ATTR_WIPHY
])
449 printf(" on phy%d", nla_get_u32(tb
[NL80211_ATTR_WIPHY
]));
451 case NL80211_REGDOM_TYPE_WORLD
:
452 printf("set to world roaming by %s request",
453 reg_initiator_to_string(nla_get_u8(tb
[NL80211_ATTR_REG_INITIATOR
])));
455 case NL80211_REGDOM_TYPE_CUSTOM_WORLD
:
456 printf("custom world roaming rules in place on phy%d by %s request",
457 nla_get_u32(tb
[NL80211_ATTR_WIPHY
]),
458 reg_initiator_to_string(nla_get_u32(tb
[NL80211_ATTR_REG_INITIATOR
])));
460 case NL80211_REGDOM_TYPE_INTERSECTION
:
461 printf("intersection used due to a request made by %s",
462 reg_initiator_to_string(nla_get_u32(tb
[NL80211_ATTR_REG_INITIATOR
])));
463 if (tb
[NL80211_ATTR_WIPHY
])
464 printf(" on phy%d", nla_get_u32(tb
[NL80211_ATTR_WIPHY
]));
467 printf("unknown source (upgrade this utility)");
473 case NL80211_CMD_JOIN_IBSS
:
474 mac_addr_n2a(macbuf
, nla_data(tb
[NL80211_ATTR_MAC
]));
475 printf("IBSS %s joined\n", macbuf
);
477 case NL80211_CMD_AUTHENTICATE
:
479 print_frame(args
, tb
[NL80211_ATTR_FRAME
]);
482 case NL80211_CMD_ASSOCIATE
:
484 print_frame(args
, tb
[NL80211_ATTR_FRAME
]);
487 case NL80211_CMD_DEAUTHENTICATE
:
489 print_frame(args
, tb
[NL80211_ATTR_FRAME
]);
492 case NL80211_CMD_DISASSOCIATE
:
494 print_frame(args
, tb
[NL80211_ATTR_FRAME
]);
498 printf("unknown event %d\n", gnlh
->cmd
);
511 static int wait_event(struct nl_msg
*msg
, void *arg
)
513 struct wait_event
*wait
= arg
;
514 struct genlmsghdr
*gnlh
= nlmsg_data(nlmsg_hdr(msg
));
517 for (i
= 0; i
< wait
->n_cmds
; i
++) {
518 if (gnlh
->cmd
== wait
->cmds
[i
]) {
519 wait
->cmd
= gnlh
->cmd
;
526 static __u32
__listen_events(struct nl80211_state
*state
,
527 const int n_waits
, const __u32
*waits
,
528 struct print_event_args
*args
)
531 struct nl_cb
*cb
= nl_cb_alloc(debug
? NL_CB_DEBUG
: NL_CB_DEFAULT
);
532 struct wait_event wait_ev
;
535 fprintf(stderr
, "failed to allocate netlink callbacks\n");
539 /* Configuration multicast group */
540 mcid
= nl_get_multicast_id(state
->nl_sock
, "nl80211", "config");
544 ret
= nl_socket_add_membership(state
->nl_sock
, mcid
);
548 /* Scan multicast group */
549 mcid
= nl_get_multicast_id(state
->nl_sock
, "nl80211", "scan");
551 ret
= nl_socket_add_membership(state
->nl_sock
, mcid
);
556 /* Regulatory multicast group */
557 mcid
= nl_get_multicast_id(state
->nl_sock
, "nl80211", "regulatory");
559 ret
= nl_socket_add_membership(state
->nl_sock
, mcid
);
564 /* MLME multicast group */
565 mcid
= nl_get_multicast_id(state
->nl_sock
, "nl80211", "mlme");
567 ret
= nl_socket_add_membership(state
->nl_sock
, mcid
);
572 /* no sequence checking for multicast messages */
573 nl_cb_set(cb
, NL_CB_SEQ_CHECK
, NL_CB_CUSTOM
, no_seq_check
, NULL
);
575 if (n_waits
&& waits
) {
576 wait_ev
.cmds
= waits
;
577 wait_ev
.n_cmds
= n_waits
;
578 nl_cb_set(cb
, NL_CB_VALID
, NL_CB_CUSTOM
, wait_event
, &wait_ev
);
580 nl_cb_set(cb
, NL_CB_VALID
, NL_CB_CUSTOM
, print_event
, args
);
586 nl_recvmsgs(state
->nl_sock
, cb
);
593 __u32
listen_events(struct nl80211_state
*state
,
594 const int n_waits
, const __u32
*waits
)
596 return __listen_events(state
, n_waits
, waits
, NULL
);
599 static int print_events(struct nl80211_state
*state
, int argc
, char **argv
)
601 struct print_event_args args
;
603 memset(&args
, 0, sizeof(args
));
606 if (strcmp(argv
[0], "-f") == 0)
608 else if (strcmp(argv
[0], "-t") == 0)
619 return __listen_events(state
, 0, NULL
, &args
);
622 int main(int argc
, char **argv
)
624 struct nl80211_state nlstate
;
628 /* calculate command size including padding */
629 cmd_size
= abs((long)&__cmd_NULL_NULL_1_CIB_NONE_0
630 - (long)&__cmd_NULL_NULL_0_CIB_NONE_0
);
635 if (argc
> 0 && strcmp(*argv
, "--debug") == 0) {
641 if (argc
> 0 && strcmp(*argv
, "--version") == 0) {
646 if (argc
== 0 || strcmp(*argv
, "help") == 0) {
651 err
= nl80211_init(&nlstate
);
655 if (strcmp(*argv
, "event") == 0) {
658 err
= print_events(&nlstate
, argc
, argv
);
659 } else if (strcmp(*argv
, "dev") == 0 && argc
> 1) {
662 err
= handle_cmd(&nlstate
, II_NETDEV
, argc
, argv
);
663 } else if (strncmp(*argv
, "phy", 3) == 0 && argc
> 1) {
664 if (strlen(*argv
) == 3) {
667 err
= handle_cmd(&nlstate
, II_PHY_NAME
, argc
, argv
);
668 } else if (*(*argv
+ 3) == '#')
669 err
= handle_cmd(&nlstate
, II_PHY_IDX
, argc
, argv
);
673 err
= handle_cmd(&nlstate
, II_NONE
, argc
, argv
);
678 fprintf(stderr
, "command failed: %s (%d)\n", strerror(-err
), err
);
680 nl80211_cleanup(&nlstate
);