3 * Copyright 2012, Pontus Fuchs <pontus.fuchs@gmail.com>
7 Parts of this file was copied from iw:
9 Copyright (c) 2007, 2008 Johannes Berg
10 Copyright (c) 2007 Andy Lutomirski
11 Copyright (c) 2007 Mike Kershaw
12 Copyright (c) 2008-2009 Luis R. Rodriguez
14 Permission to use, copy, modify, and/or distribute this software for any
15 purpose with or without fee is hereby granted, provided that the above
16 copyright notice and this permission notice appear in all copies.
18 THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
19 WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
20 MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
21 ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
22 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
23 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
24 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
32 #include <glib/gstdio.h>
34 #include "ws80211_utils.h"
36 #if defined(HAVE_LIBNL) && defined(HAVE_NL80211)
42 #include <sys/ioctl.h>
44 #include <netlink/genl/genl.h>
45 #include <netlink/genl/family.h>
46 #include <netlink/genl/ctrl.h>
47 #include <netlink/msg.h>
48 #include <netlink/attr.h>
50 #include <linux/nl80211.h>
52 /* libnl 1.x compatibility code */
54 #define nl_sock nl_handle
55 static inline struct nl_handle
*nl_socket_alloc(void)
57 return nl_handle_alloc();
60 static inline void nl_socket_free(struct nl_sock
*h
)
64 #endif /* HAVE_LIBNL1 */
66 struct nl80211_state
{
67 struct nl_sock
*nl_sock
;
71 static struct nl80211_state nl_state
;
73 int ws80211_init(void)
77 struct nl80211_state
*state
= &nl_state
;
79 state
->nl_sock
= nl_socket_alloc();
80 if (!state
->nl_sock
) {
81 fprintf(stderr
, "Failed to allocate netlink socket.\n");
85 if (genl_connect(state
->nl_sock
)) {
86 fprintf(stderr
, "Failed to connect to generic netlink.\n");
88 goto out_handle_destroy
;
91 state
->nl80211_id
= genl_ctrl_resolve(state
->nl_sock
, "nl80211");
92 if (state
->nl80211_id
< 0) {
93 fprintf(stderr
, "nl80211 not found.\n");
95 goto out_handle_destroy
;
101 nl_socket_free(state
->nl_sock
);
106 static int error_handler(struct sockaddr_nl
*nla _U_
, struct nlmsgerr
*err
,
109 int *ret
= (int *)arg
;
114 static int finish_handler(struct nl_msg
*msg _U_
, void *arg
)
116 int *ret
= (int *)arg
;
121 static int ack_handler(struct nl_msg
*msg _U_
, void *arg
)
123 int *ret
= (int *)arg
;
128 static int nl80211_do_cmd(struct nl_msg
*msg
, struct nl_cb
*cb
)
132 if (!nl_state
.nl_sock
)
135 err
= nl_send_auto_complete(nl_state
.nl_sock
, msg
);
141 nl_cb_err(cb
, NL_CB_CUSTOM
, error_handler
, (void *)&err
);
142 nl_cb_set(cb
, NL_CB_FINISH
, NL_CB_CUSTOM
, finish_handler
, (void *)&err
);
143 nl_cb_set(cb
, NL_CB_ACK
, NL_CB_CUSTOM
, ack_handler
, (void *)&err
);
146 nl_recvmsgs(nl_state
.nl_sock
, cb
);
153 struct nliface_cookie
160 * And now for a steaming heap of suck.
162 * The nla_for_each_nested() macro defined by at least some versions of the
163 * Linux kernel's headers doesn't do the casting required when compiling
164 * with a C++ compiler or with -Wc++-compat, so we get warnings, and those
165 * warnings are fatal when we compile this file.
167 * So we replace it with our own version, which does the requisite cast.
171 * nla_for_each_nested - iterate over nested attributes
172 * @pos: loop counter, set to current attribute
173 * @nla: attribute containing the nested attributes
174 * @rem: initialized to len, holds bytes currently remaining in stream
176 #undef nla_for_each_nested
177 #define nla_for_each_nested(pos, nla, rem) \
178 nla_for_each_attr(pos, (struct nlattr *)nla_data(nla), nla_len(nla), rem)
180 static int get_phys_handler(struct nl_msg
*msg
, void *arg
)
182 struct nlattr
*tb_msg
[NL80211_ATTR_MAX
+ 1];
183 struct genlmsghdr
*gnlh
= (struct genlmsghdr
*)nlmsg_data(nlmsg_hdr(msg
));
185 struct nliface_cookie
*cookie
= (struct nliface_cookie
*)arg
;
187 struct nlattr
*tb_band
[NL80211_BAND_ATTR_MAX
+ 1];
189 struct nlattr
*tb_freq
[NL80211_FREQUENCY_ATTR_MAX
+ 1];
190 static struct nla_policy freq_policy
[NL80211_FREQUENCY_ATTR_MAX
+ 1] = {
191 {NLA_UNSPEC
, 0, 0}, /* __NL80211_FREQUENCY_ATTR_INVALID */
192 {NLA_U32
, 0, 0}, /* NL80211_FREQUENCY_ATTR_FREQ */
193 {NLA_FLAG
, 0, 0}, /* NL80211_FREQUENCY_ATTR_DISABLED */
194 {NLA_FLAG
, 0, 0}, /* NL80211_FREQUENCY_ATTR_PASSIVE_SCAN */
195 {NLA_FLAG
, 0, 0}, /* NL80211_FREQUENCY_ATTR_NO_IBSS */
196 {NLA_FLAG
, 0, 0}, /* NL80211_FREQUENCY_ATTR_RADAR */
197 {NLA_U32
, 0, 0} /* NL80211_FREQUENCY_ATTR_MAX_TX_POWER */
200 struct nlattr
*nl_band
;
201 struct nlattr
*nl_freq
;
202 struct nlattr
*nl_mode
;
204 int rem_band
, rem_freq
, rem_mode
;
205 struct ws80211_interface
*iface
;
208 nla_parse(tb_msg
, NL80211_ATTR_MAX
, genlmsg_attrdata(gnlh
, 0),
209 genlmsg_attrlen(gnlh
, 0), NULL
);
211 if (!tb_msg
[NL80211_ATTR_WIPHY_BANDS
])
214 if (tb_msg
[NL80211_ATTR_SUPPORTED_IFTYPES
]) {
215 nla_for_each_nested(nl_mode
, tb_msg
[NL80211_ATTR_SUPPORTED_IFTYPES
], rem_mode
) {
216 if (nla_type(nl_mode
) == NL80211_IFTYPE_MONITOR
)
223 iface
= (struct ws80211_interface
*)g_malloc0(sizeof(*iface
));
227 iface
->frequencies
= g_array_new(FALSE
, FALSE
, sizeof(int));
228 iface
->channel_types
= 1 << WS80211_CHAN_NO_HT
;
230 if (tb_msg
[NL80211_ATTR_WIPHY_NAME
]) {
231 iface
->ifname
= g_strdup_printf("%s.mon",
232 nla_get_string(tb_msg
[NL80211_ATTR_WIPHY_NAME
]));
235 nla_for_each_nested(nl_band
, tb_msg
[NL80211_ATTR_WIPHY_BANDS
], rem_band
) {
238 nla_parse(tb_band
, NL80211_BAND_ATTR_MAX
,
239 (struct nlattr
*)nla_data(nl_band
),
240 nla_len(nl_band
), NULL
);
242 #ifdef NL80211_BAND_ATTR_HT_CAPA
243 if (tb_band
[NL80211_BAND_ATTR_HT_CAPA
]) {
245 iface
->channel_types
|= 1 << WS80211_CHAN_HT20
;
246 ht40
= !!(nla_get_u16(tb_band
[NL80211_BAND_ATTR_HT_CAPA
]) & 0x02);
248 iface
->channel_types
|= 1 << WS80211_CHAN_HT40MINUS
;
249 iface
->channel_types
|= 1 << WS80211_CHAN_HT40PLUS
;
252 #endif /* NL80211_BAND_ATTR_HT_CAPA */
254 nla_for_each_nested(nl_freq
, tb_band
[NL80211_BAND_ATTR_FREQS
], rem_freq
) {
256 nla_parse(tb_freq
, NL80211_FREQUENCY_ATTR_MAX
,
257 (struct nlattr
*)nla_data(nl_freq
),
258 nla_len(nl_freq
), freq_policy
);
259 if (!tb_freq
[NL80211_FREQUENCY_ATTR_FREQ
])
261 if (tb_freq
[NL80211_FREQUENCY_ATTR_DISABLED
])
264 freq
= nla_get_u32(tb_freq
[NL80211_FREQUENCY_ATTR_FREQ
]);
265 g_array_append_val(iface
->frequencies
, freq
);
269 /* Can frequency be set? Only newer versions of cfg80211 supports this */
270 #ifdef HAVE_NL80211_CMD_SET_CHANNEL
271 if (tb_msg
[NL80211_ATTR_SUPPORTED_COMMANDS
]) {
273 struct nlattr
*nl_cmd
;
274 nla_for_each_nested(nl_cmd
, tb_msg
[NL80211_ATTR_SUPPORTED_COMMANDS
], cmd
) {
275 if(nla_get_u32(nl_cmd
) == NL80211_CMD_SET_CHANNEL
)
276 iface
->can_set_freq
= TRUE
;
280 iface
->can_set_freq
= TRUE
;
282 g_array_append_val(cookie
->interfaces
, iface
);
288 static int ws80211_get_phys(GArray
*interfaces
)
290 struct nliface_cookie cookie
;
295 fprintf(stderr
, "failed to allocate netlink message\n");
299 cb
= nl_cb_alloc(NL_CB_DEFAULT
);
301 cookie
.interfaces
= interfaces
;
303 genlmsg_put(msg
, 0, 0, nl_state
.nl80211_id
, 0,
304 NLM_F_DUMP
, NL80211_CMD_GET_WIPHY
, 0);
306 nl_cb_set(cb
, NL_CB_VALID
, NL_CB_CUSTOM
, get_phys_handler
, &cookie
);
308 return nl80211_do_cmd(msg
, cb
);
312 static int get_freq_wext(const char *ifname
)
316 /* Ugly hack to avoid incuding wireless.h */
318 char name1
[IFNAMSIZ
];
325 fd
= socket(AF_INET
, SOCK_DGRAM
, 0);
329 g_strlcpy(wrq
.name1
, ifname
, IFNAMSIZ
);
331 if (ioctl(fd
, 0x8B05, &wrq
) == 0) {
341 struct ws80211_iface_info
*pub
;
346 static int get_iface_info_handler(struct nl_msg
*msg
, void *arg
)
348 struct genlmsghdr
*gnlh
= (struct genlmsghdr
*)nlmsg_data(nlmsg_hdr(msg
));
349 struct nlattr
*tb_msg
[NL80211_ATTR_MAX
+ 1];
350 struct __iface_info
*iface_info
= (struct __iface_info
*)arg
;
352 nla_parse(tb_msg
, NL80211_ATTR_MAX
, genlmsg_attrdata(gnlh
, 0),
353 genlmsg_attrlen(gnlh
, 0), NULL
);
355 if (tb_msg
[NL80211_ATTR_IFTYPE
]) {
356 iface_info
->type
= nla_get_u32(tb_msg
[NL80211_ATTR_IFTYPE
]);
358 if (tb_msg
[NL80211_ATTR_WIPHY
]) {
359 iface_info
->phyidx
= nla_get_u32(tb_msg
[NL80211_ATTR_WIPHY
]);
362 if (tb_msg
[NL80211_ATTR_WIPHY_FREQ
]) {
363 iface_info
->pub
->current_freq
= nla_get_u32(tb_msg
[NL80211_ATTR_WIPHY_FREQ
]);
364 iface_info
->pub
->current_chan_type
= WS80211_CHAN_NO_HT
;
366 if (tb_msg
[NL80211_ATTR_WIPHY_CHANNEL_TYPE
]) {
367 switch (nla_get_u32(tb_msg
[NL80211_ATTR_WIPHY_CHANNEL_TYPE
])) {
369 case NL80211_CHAN_NO_HT
:
370 iface_info
->pub
->current_chan_type
= WS80211_CHAN_NO_HT
;
373 case NL80211_CHAN_HT20
:
374 iface_info
->pub
->current_chan_type
= WS80211_CHAN_HT20
;
377 case NL80211_CHAN_HT40MINUS
:
378 iface_info
->pub
->current_chan_type
= WS80211_CHAN_HT40MINUS
;
381 case NL80211_CHAN_HT40PLUS
:
382 iface_info
->pub
->current_chan_type
= WS80211_CHAN_HT40PLUS
;
392 static int __ws80211_get_iface_info(const char *name
, struct __iface_info
*iface_info
)
399 fprintf(stderr
, "failed to allocate netlink message\n");
403 cb
= nl_cb_alloc(NL_CB_DEFAULT
);
405 devidx
= if_nametoindex(name
);
407 genlmsg_put(msg
, 0, 0, nl_state
.nl80211_id
, 0,
408 0, NL80211_CMD_GET_INTERFACE
, 0);
409 NLA_PUT_U32(msg
, NL80211_ATTR_IFINDEX
, devidx
);
411 nl_cb_set(cb
, NL_CB_VALID
, NL_CB_CUSTOM
, get_iface_info_handler
, iface_info
);
413 if (nl80211_do_cmd(msg
, cb
))
416 /* Old kernels cant get the current freq via netlink. Try WEXT too :( */
417 if (iface_info
->pub
->current_freq
== -1)
418 iface_info
->pub
->current_freq
= get_freq_wext(name
);
422 fprintf(stderr
, "building message failed\n");
426 int ws80211_get_iface_info(const char *name
, struct ws80211_iface_info
*iface_info
)
428 struct __iface_info __iface_info
;
430 memset(iface_info
, 0, sizeof(*iface_info
));
431 __iface_info
.pub
= iface_info
;
432 __iface_info
.type
= -1;
433 __iface_info
.phyidx
= -1;
434 __iface_info
.pub
->current_freq
= -1;
435 __iface_info
.pub
->current_chan_type
= WS80211_CHAN_NO_HT
;
437 return __ws80211_get_iface_info(name
, &__iface_info
);
440 static int ws80211_populate_devices(GArray
*interfaces
)
450 struct ws80211_iface_info pub
;
451 struct __iface_info iface_info
;
452 struct ws80211_interface
*iface
;
454 /* Get a list of phy's that can handle monitor mode */
455 ws80211_get_phys(interfaces
);
457 fh
= g_fopen("/proc/net/dev", "r");
459 fprintf(stderr
, "Cannot open /proc/net/dev");
463 /* Skip the first two lines */
464 for (i
= 0; i
< 2; i
++) {
465 ret
= fgets(line
, sizeof(line
), fh
);
467 fprintf(stderr
, "Error parsing /proc/net/dev");
473 /* Update names of user created monitor interfaces */
474 while(fgets(line
, sizeof(line
), fh
)) {
475 t
= index(line
, ':');
480 while (*t
&& *t
== ' ')
482 memset(&iface_info
, 0, sizeof(iface_info
));
483 iface_info
.pub
= &pub
;
484 __ws80211_get_iface_info(t
, &iface_info
);
486 if (iface_info
.type
== NL80211_IFTYPE_MONITOR
) {
487 for (j
= 0; j
< interfaces
->len
; j
++) {
488 iface
= g_array_index(interfaces
, struct ws80211_interface
*, j
);
489 t2
= g_strdup_printf("phy%d.mon", iface_info
.phyidx
);
491 if (!strcmp(t2
, iface
->ifname
)) {
492 g_free(iface
->ifname
);
493 iface
->ifname
= g_strdup(t
);
504 static int ws80211_iface_up(const char *ifname
)
509 sock
= socket(AF_PACKET
, SOCK_RAW
, 0);
513 g_strlcpy(ifreq
.ifr_name
, ifname
, sizeof(ifreq
.ifr_name
));
515 if (ioctl(sock
, SIOCGIFFLAGS
, &ifreq
))
518 ifreq
.ifr_flags
|= IFF_UP
;
520 if (ioctl(sock
, SIOCSIFFLAGS
, &ifreq
))
531 static int ws80211_create_on_demand_interface(const char *name
)
533 int devidx
, phyidx
, err
;
537 devidx
= if_nametoindex(name
);
539 return ws80211_iface_up(name
);
541 if (sscanf(name
, "phy%d.mon", &phyidx
) != 1)
544 cb
= nl_cb_alloc(NL_CB_DEFAULT
);
547 fprintf(stderr
, "failed to allocate netlink message\n");
551 genlmsg_put(msg
, 0, 0, nl_state
.nl80211_id
, 0,
552 0, NL80211_CMD_NEW_INTERFACE
, 0);
553 NLA_PUT_U32(msg
, NL80211_ATTR_WIPHY
, phyidx
);
555 NLA_PUT_STRING(msg
, NL80211_ATTR_IFNAME
, name
);
556 NLA_PUT_U32(msg
, NL80211_ATTR_IFTYPE
, NL80211_IFTYPE_MONITOR
);
558 err
= nl80211_do_cmd(msg
, cb
);
561 return ws80211_iface_up(name
);
564 fprintf(stderr
, "building message failed\n");
568 int ws80211_set_freq(const char *name
, int freq
, int chan_type
)
574 err
= ws80211_create_on_demand_interface(name
);
580 fprintf(stderr
, "failed to allocate netlink message\n");
584 cb
= nl_cb_alloc(NL_CB_DEFAULT
);
586 devidx
= if_nametoindex(name
);
588 #ifdef HAVE_NL80211_CMD_SET_CHANNEL
589 genlmsg_put(msg
, 0, 0, nl_state
.nl80211_id
, 0,
590 0, NL80211_CMD_SET_CHANNEL
, 0);
592 genlmsg_put(msg
, 0, 0, nl_state
.nl80211_id
, 0,
593 0, NL80211_CMD_SET_WIPHY
, 0);
596 NLA_PUT_U32(msg
, NL80211_ATTR_IFINDEX
, devidx
);
597 NLA_PUT_U32(msg
, NL80211_ATTR_WIPHY_FREQ
, freq
);
601 #ifdef NL80211_BAND_ATTR_HT_CAPA
602 case WS80211_CHAN_NO_HT
:
603 NLA_PUT_U32(msg
, NL80211_ATTR_WIPHY_CHANNEL_TYPE
, NL80211_CHAN_NO_HT
);
606 case WS80211_CHAN_HT20
:
607 NLA_PUT_U32(msg
, NL80211_ATTR_WIPHY_CHANNEL_TYPE
, NL80211_CHAN_HT20
);
610 case WS80211_CHAN_HT40MINUS
:
611 NLA_PUT_U32(msg
, NL80211_ATTR_WIPHY_CHANNEL_TYPE
, NL80211_CHAN_HT40MINUS
);
614 case WS80211_CHAN_HT40PLUS
:
615 NLA_PUT_U32(msg
, NL80211_ATTR_WIPHY_CHANNEL_TYPE
, NL80211_CHAN_HT40PLUS
);
622 err
= nl80211_do_cmd(msg
, cb
);
626 fprintf(stderr
, "building message failed\n");
631 void ws80211_free_interfaces(GArray
*interfaces
)
633 struct ws80211_interface
*iface
;
638 while (interfaces
->len
) {
639 iface
= g_array_index(interfaces
, struct ws80211_interface
*, 0);
640 g_array_remove_index(interfaces
, 0);
641 g_array_free(iface
->frequencies
, TRUE
);
642 g_free(iface
->ifname
);
645 g_array_free(interfaces
, TRUE
);
648 GArray
* ws80211_find_interfaces(void)
652 if (!nl_state
.nl_sock
)
655 interfaces
= g_array_new(FALSE
, FALSE
, sizeof(struct ws80211_interface
*));
659 if (ws80211_populate_devices(interfaces
)) {
660 ws80211_free_interfaces(interfaces
);
666 int ws80211_frequency_to_channel(int freq
)
672 return (freq
- 2407) / 5;
674 return freq
/ 5 - 1000;
678 ws80211_str_to_chan_type(const gchar
*s
)
684 if (!strcmp(s
, CHAN_NO_HT
))
685 ret
= WS80211_CHAN_NO_HT
;
686 if (!strcmp(s
, CHAN_HT20
))
687 ret
= WS80211_CHAN_HT20
;
688 if (!strcmp(s
, CHAN_HT40MINUS
))
689 ret
= WS80211_CHAN_HT40MINUS
;
690 if (!strcmp(s
, CHAN_HT40PLUS
))
691 ret
= WS80211_CHAN_HT40PLUS
;
696 *ws80211_chan_type_to_str(int type
)
699 case WS80211_CHAN_NO_HT
:
701 case WS80211_CHAN_HT20
:
703 case WS80211_CHAN_HT40MINUS
:
704 return CHAN_HT40MINUS
;
705 case WS80211_CHAN_HT40PLUS
:
706 return CHAN_HT40PLUS
;
711 #else /* HAVE_LIBNL */
712 int ws80211_init(void)
717 GArray
* ws80211_find_interfaces(void)
722 int ws80211_get_iface_info(const char *name _U_
, struct ws80211_iface_info
*iface_info _U_
)
727 void ws80211_free_interfaces(GArray
*interfaces _U_
)
731 int ws80211_frequency_to_channel(int freq _U_
)
736 int ws80211_set_freq(const char *name _U_
, int freq _U_
, int chan_type _U_
)
741 int ws80211_str_to_chan_type(const gchar
*s _U_
)
746 const gchar
*ws80211_chan_type_to_str(int type _U_
)
750 #endif /* HAVE_LIBNL && HAVE_NL80211 */