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,
114 static int finish_handler(struct nl_msg *msg _U_, void *arg)
121 static int ack_handler(struct nl_msg *msg _U_, void *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, &err);
142 nl_cb_set(cb, NL_CB_FINISH, NL_CB_CUSTOM, finish_handler, &err);
143 nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, ack_handler, &err);
146 nl_recvmsgs(nl_state.nl_sock, cb);
153 struct nliface_cookie
159 static int get_phys_handler(struct nl_msg *msg, void *arg)
161 struct nlattr *tb_msg[NL80211_ATTR_MAX + 1];
162 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
164 struct nliface_cookie *cookie = arg;
166 struct nlattr *tb_band[NL80211_BAND_ATTR_MAX + 1];
168 struct nlattr *tb_freq[NL80211_FREQUENCY_ATTR_MAX + 1];
169 static struct nla_policy freq_policy[NL80211_FREQUENCY_ATTR_MAX + 1] = {
170 [NL80211_FREQUENCY_ATTR_FREQ] = { .type = NLA_U32 },
171 [NL80211_FREQUENCY_ATTR_DISABLED] = { .type = NLA_FLAG },
172 [NL80211_FREQUENCY_ATTR_PASSIVE_SCAN] = { .type = NLA_FLAG },
173 [NL80211_FREQUENCY_ATTR_NO_IBSS] = { .type = NLA_FLAG },
174 [NL80211_FREQUENCY_ATTR_RADAR] = { .type = NLA_FLAG },
175 [NL80211_FREQUENCY_ATTR_MAX_TX_POWER] = { .type = NLA_U32 },
178 struct nlattr *nl_band;
179 struct nlattr *nl_freq;
180 struct nlattr *nl_mode;
182 int rem_band, rem_freq, rem_mode;
183 struct ws80211_interface *iface;
186 nla_parse(tb_msg, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
187 genlmsg_attrlen(gnlh, 0), NULL);
189 if (!tb_msg[NL80211_ATTR_WIPHY_BANDS])
192 if (tb_msg[NL80211_ATTR_SUPPORTED_IFTYPES]) {
193 nla_for_each_nested(nl_mode, tb_msg[NL80211_ATTR_SUPPORTED_IFTYPES], rem_mode) {
194 if (nla_type(nl_mode) == NL80211_IFTYPE_MONITOR)
201 iface = g_malloc0(sizeof(*iface));
205 iface->frequencies = g_array_new(FALSE, FALSE, sizeof(int));
206 iface->channel_types = 1 << WS80211_CHAN_NO_HT;
208 if (tb_msg[NL80211_ATTR_WIPHY_NAME]) {
209 iface->ifname = g_strdup_printf("%s.mon",
210 nla_get_string(tb_msg[NL80211_ATTR_WIPHY_NAME]));
213 nla_for_each_nested(nl_band, tb_msg[NL80211_ATTR_WIPHY_BANDS], rem_band) {
216 nla_parse(tb_band, NL80211_BAND_ATTR_MAX, nla_data(nl_band),
217 nla_len(nl_band), NULL);
219 #ifdef NL80211_BAND_ATTR_HT_CAPA
220 if (tb_band[NL80211_BAND_ATTR_HT_CAPA]) {
222 iface->channel_types |= 1 << WS80211_CHAN_HT20;
223 ht40 = !!(nla_get_u16(tb_band[NL80211_BAND_ATTR_HT_CAPA]) & 0x02);
225 iface->channel_types |= 1 << WS80211_CHAN_HT40MINUS;
226 iface->channel_types |= 1 << WS80211_CHAN_HT40PLUS;
229 #endif /* NL80211_BAND_ATTR_HT_CAPA */
231 nla_for_each_nested(nl_freq, tb_band[NL80211_BAND_ATTR_FREQS], rem_freq) {
233 nla_parse(tb_freq, NL80211_FREQUENCY_ATTR_MAX, nla_data(nl_freq),
234 nla_len(nl_freq), freq_policy);
235 if (!tb_freq[NL80211_FREQUENCY_ATTR_FREQ])
237 if (tb_freq[NL80211_FREQUENCY_ATTR_DISABLED])
240 freq = nla_get_u32(tb_freq[NL80211_FREQUENCY_ATTR_FREQ]);
241 g_array_append_val(iface->frequencies, freq);
245 /* Can frequency be set? Only newer versions of cfg80211 supports this */
246 #ifdef HAVE_NL80211_CMD_SET_CHANNEL
247 if (tb_msg[NL80211_ATTR_SUPPORTED_COMMANDS]) {
249 struct nlattr *nl_cmd;
250 nla_for_each_nested(nl_cmd, tb_msg[NL80211_ATTR_SUPPORTED_COMMANDS], cmd) {
251 if(nla_get_u32(nl_cmd) == NL80211_CMD_SET_CHANNEL)
252 iface->can_set_freq = TRUE;
256 iface->can_set_freq = TRUE;
258 g_array_append_val(cookie->interfaces, iface);
264 static int ws80211_get_phys(GArray *interfaces)
266 struct nliface_cookie cookie;
271 fprintf(stderr, "failed to allocate netlink message\n");
275 cb = nl_cb_alloc(NL_CB_DEFAULT);
277 cookie.interfaces = interfaces;
279 genlmsg_put(msg, 0, 0, nl_state.nl80211_id, 0,
280 NLM_F_DUMP, NL80211_CMD_GET_WIPHY, 0);
282 nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, get_phys_handler, &cookie);
284 return nl80211_do_cmd(msg, cb);
288 static int get_freq_wext(const char *ifname)
292 /* Ugly hack to avoid incuding wireless.h */
294 char name1[IFNAMSIZ];
301 fd = socket(AF_INET, SOCK_DGRAM, 0);
305 g_strlcpy(wrq.name1, ifname, IFNAMSIZ);
307 if (ioctl(fd, 0x8B05, &wrq) == 0) {
317 struct ws80211_iface_info *pub;
322 static int get_iface_info_handler(struct nl_msg *msg, void *arg)
324 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
325 struct nlattr *tb_msg[NL80211_ATTR_MAX + 1];
326 struct __iface_info *iface_info = arg;
328 nla_parse(tb_msg, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
329 genlmsg_attrlen(gnlh, 0), NULL);
331 if (tb_msg[NL80211_ATTR_IFTYPE]) {
332 iface_info->type = nla_get_u32(tb_msg[NL80211_ATTR_IFTYPE]);
334 if (tb_msg[NL80211_ATTR_WIPHY]) {
335 iface_info->phyidx = nla_get_u32(tb_msg[NL80211_ATTR_WIPHY]);
338 if (tb_msg[NL80211_ATTR_WIPHY_FREQ]) {
339 iface_info->pub->current_freq = nla_get_u32(tb_msg[NL80211_ATTR_WIPHY_FREQ]);
340 iface_info->pub->current_chan_type = NL80211_CHAN_NO_HT;
342 if (tb_msg[NL80211_ATTR_WIPHY_CHANNEL_TYPE])
343 iface_info->pub->current_chan_type = nla_get_u32(tb_msg[NL80211_ATTR_WIPHY_CHANNEL_TYPE]);
350 static int __ws80211_get_iface_info(const char *name, struct __iface_info *iface_info)
357 fprintf(stderr, "failed to allocate netlink message\n");
361 cb = nl_cb_alloc(NL_CB_DEFAULT);
363 devidx = if_nametoindex(name);
365 genlmsg_put(msg, 0, 0, nl_state.nl80211_id, 0,
366 0, NL80211_CMD_GET_INTERFACE, 0);
367 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, devidx);
369 nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, get_iface_info_handler, iface_info);
371 if (nl80211_do_cmd(msg, cb))
374 /* Old kernels cant get the current freq via netlink. Try WEXT too :( */
375 if (iface_info->pub->current_freq == -1)
376 iface_info->pub->current_freq = get_freq_wext(name);
380 fprintf(stderr, "building message failed\n");
384 int ws80211_get_iface_info(const char *name, struct ws80211_iface_info *iface_info)
386 struct __iface_info __iface_info;
388 memset(iface_info, 0, sizeof(*iface_info));
389 __iface_info.pub = iface_info;
390 __iface_info.type = -1;
391 __iface_info.phyidx= -1;
392 __iface_info.pub->current_freq = -1;
393 __iface_info.pub->current_chan_type = -1;
395 return __ws80211_get_iface_info(name, &__iface_info);
398 static int ws80211_populate_devices(GArray *interfaces)
408 struct ws80211_iface_info pub;
409 struct __iface_info iface_info;
410 struct ws80211_interface *iface;
412 /* Get a list of phy's that can handle monitor mode */
413 ws80211_get_phys(interfaces);
415 fh = g_fopen("/proc/net/dev", "r");
417 fprintf(stderr, "Cannot open /proc/net/dev");
421 /* Skip the first two lines */
422 for (i = 0; i < 2; i++) {
423 ret = fgets(line, sizeof(line), fh);
425 fprintf(stderr, "Error parsing /proc/net/dev");
431 /* Update names of user created monitor interfaces */
432 while(fgets(line, sizeof(line), fh)) {
433 t = index(line, ':');
438 while (*t && *t == ' ')
440 memset(&iface_info, 0, sizeof(iface_info));
441 iface_info.pub = &pub;
442 __ws80211_get_iface_info(t, &iface_info);
444 if (iface_info.type == NL80211_IFTYPE_MONITOR) {
445 for (j = 0; j < interfaces->len; j++) {
446 iface = g_array_index(interfaces, struct ws80211_interface *, j);
447 t2 = g_strdup_printf("phy%d.mon", iface_info.phyidx);
449 if (!strcmp(t2, iface->ifname)) {
450 g_free(iface->ifname);
451 iface->ifname = g_strdup(t);
462 static int ws80211_iface_up(const char *ifname)
467 sock = socket(AF_PACKET, SOCK_RAW, 0);
471 g_strlcpy(ifreq.ifr_name, ifname, sizeof(ifreq.ifr_name));
473 if (ioctl(sock, SIOCGIFFLAGS, &ifreq))
476 ifreq.ifr_flags |= IFF_UP;
478 if (ioctl(sock, SIOCSIFFLAGS, &ifreq))
489 static int ws80211_create_on_demand_interface(const char *name)
491 int devidx, phyidx, err;
495 devidx = if_nametoindex(name);
497 return ws80211_iface_up(name);
499 if (sscanf(name, "phy%d.mon", &phyidx) != 1)
502 cb = nl_cb_alloc(NL_CB_DEFAULT);
505 fprintf(stderr, "failed to allocate netlink message\n");
509 genlmsg_put(msg, 0, 0, nl_state.nl80211_id, 0,
510 0, NL80211_CMD_NEW_INTERFACE, 0);
511 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, phyidx);
513 NLA_PUT_STRING(msg, NL80211_ATTR_IFNAME, name);
514 NLA_PUT_U32(msg, NL80211_ATTR_IFTYPE, NL80211_IFTYPE_MONITOR);
516 err = nl80211_do_cmd(msg, cb);
519 return ws80211_iface_up(name);
522 fprintf(stderr, "building message failed\n");
526 int ws80211_set_freq(const char *name, int freq, int chan_type)
532 err = ws80211_create_on_demand_interface(name);
538 fprintf(stderr, "failed to allocate netlink message\n");
542 cb = nl_cb_alloc(NL_CB_DEFAULT);
544 devidx = if_nametoindex(name);
546 #ifdef HAVE_NL80211_CMD_SET_CHANNEL
547 genlmsg_put(msg, 0, 0, nl_state.nl80211_id, 0,
548 0, NL80211_CMD_SET_CHANNEL, 0);
550 genlmsg_put(msg, 0, 0, nl_state.nl80211_id, 0,
551 0, NL80211_CMD_SET_WIPHY, 0);
554 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, devidx);
555 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, freq);
559 #ifdef NL80211_BAND_ATTR_HT_CAPA
560 case WS80211_CHAN_NO_HT:
561 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE, NL80211_CHAN_NO_HT);
564 case WS80211_CHAN_HT20:
565 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE, NL80211_CHAN_HT20);
568 case WS80211_CHAN_HT40MINUS:
569 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE, NL80211_CHAN_HT40MINUS);
572 case WS80211_CHAN_HT40PLUS:
573 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE, NL80211_CHAN_HT40PLUS);
580 err = nl80211_do_cmd(msg, cb);
584 fprintf(stderr, "building message failed\n");
589 void ws80211_free_interfaces(GArray *interfaces)
591 struct ws80211_interface *iface;
596 while (interfaces->len) {
597 iface = g_array_index(interfaces, struct ws80211_interface *, 0);
598 g_array_remove_index(interfaces, 0);
599 g_array_free(iface->frequencies, TRUE);
600 g_free(iface->ifname);
603 g_array_free(interfaces, TRUE);
606 GArray* ws80211_find_interfaces(void)
610 if (!nl_state.nl_sock)
613 interfaces = g_array_new(FALSE, FALSE, sizeof(struct ws80211_interface *));
617 if (ws80211_populate_devices(interfaces)) {
618 ws80211_free_interfaces(interfaces);
624 int ws80211_frequency_to_channel(int freq)
630 return (freq - 2407) / 5;
632 return freq / 5 - 1000;
636 ws80211_str_to_chan_type(const gchar *s)
642 if (!strcmp(s, CHAN_NO_HT))
643 ret = WS80211_CHAN_NO_HT;
644 if (!strcmp(s, CHAN_HT20))
645 ret = WS80211_CHAN_HT20;
646 if (!strcmp(s, CHAN_HT40MINUS))
647 ret = WS80211_CHAN_HT40MINUS;
648 if (!strcmp(s, CHAN_HT40PLUS))
649 ret = WS80211_CHAN_HT40PLUS;
654 *ws80211_chan_type_to_str(int type)
657 case WS80211_CHAN_NO_HT:
659 case WS80211_CHAN_HT20:
661 case WS80211_CHAN_HT40MINUS:
662 return CHAN_HT40MINUS;
663 case WS80211_CHAN_HT40PLUS:
664 return CHAN_HT40PLUS;
669 #else /* HAVE_LIBNL */
670 int ws80211_init(void)
675 GArray* ws80211_find_interfaces(void)
680 int ws80211_get_iface_info(const char *name _U_, struct ws80211_iface_info *iface_info _U_)
685 void ws80211_free_interfaces(GArray *interfaces _U_)
689 int ws80211_frequency_to_channel(int freq _U_)
694 int ws80211_set_freq(const char *name _U_, int freq _U_, int chan_type _U_)
699 int ws80211_str_to_chan_type(const gchar *s _U_)
704 const gchar *ws80211_chan_type_to_str(int type _U_)
708 #endif /* HAVE_LIBNL && HAVE_NL80211 */