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"
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_cmd;
181 struct nlattr *nl_mode;
183 int rem_band, rem_freq, rem_mode;
184 struct ws80211_interface *iface;
187 nla_parse(tb_msg, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
188 genlmsg_attrlen(gnlh, 0), NULL);
190 if (!tb_msg[NL80211_ATTR_WIPHY_BANDS])
193 if (tb_msg[NL80211_ATTR_SUPPORTED_IFTYPES]) {
194 nla_for_each_nested(nl_mode, tb_msg[NL80211_ATTR_SUPPORTED_IFTYPES], rem_mode) {
195 if (nla_type(nl_mode) == NL80211_IFTYPE_MONITOR)
202 iface = g_malloc0(sizeof(*iface));
206 iface->frequencies = g_array_new(FALSE, FALSE, sizeof(int));
207 iface->channel_types = 1 << WS80211_CHAN_NO_HT;
209 if (tb_msg[NL80211_ATTR_WIPHY_NAME]) {
211 phyname = g_strdup(nla_get_string(tb_msg[NL80211_ATTR_WIPHY_NAME]));
212 iface->ifname = g_strdup_printf("%s.mon", phyname);
215 nla_for_each_nested(nl_band, tb_msg[NL80211_ATTR_WIPHY_BANDS], rem_band) {
218 nla_parse(tb_band, NL80211_BAND_ATTR_MAX, nla_data(nl_band),
219 nla_len(nl_band), NULL);
221 #ifdef NL80211_BAND_ATTR_HT_CAPA
222 if (tb_band[NL80211_BAND_ATTR_HT_CAPA]) {
224 iface->channel_types |= 1 << WS80211_CHAN_HT20;
225 ht40 = !!(nla_get_u16(tb_band[NL80211_BAND_ATTR_HT_CAPA]) & 0x02);
227 iface->channel_types |= 1 << WS80211_CHAN_HT40MINUS;
228 iface->channel_types |= 1 << WS80211_CHAN_HT40PLUS;
231 #endif /* NL80211_BAND_ATTR_HT_CAPA */
233 nla_for_each_nested(nl_freq, tb_band[NL80211_BAND_ATTR_FREQS], rem_freq) {
235 nla_parse(tb_freq, NL80211_FREQUENCY_ATTR_MAX, nla_data(nl_freq),
236 nla_len(nl_freq), freq_policy);
237 if (!tb_freq[NL80211_FREQUENCY_ATTR_FREQ])
239 if (tb_freq[NL80211_FREQUENCY_ATTR_DISABLED])
242 freq = nla_get_u32(tb_freq[NL80211_FREQUENCY_ATTR_FREQ]);
243 g_array_append_val(iface->frequencies, freq);
247 /* Can frequency be set? */
248 if (tb_msg[NL80211_ATTR_SUPPORTED_COMMANDS]) {
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;
255 g_array_append_val(cookie->interfaces, iface);
261 static int ws80211_get_phys(GArray *interfaces)
263 struct nliface_cookie cookie;
268 fprintf(stderr, "failed to allocate netlink message\n");
272 cb = nl_cb_alloc(NL_CB_DEFAULT);
274 cookie.interfaces = interfaces;
276 genlmsg_put(msg, 0, 0, nl_state.nl80211_id, 0,
277 NLM_F_DUMP, NL80211_CMD_GET_WIPHY, 0);
279 nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, get_phys_handler, &cookie);
281 return nl80211_do_cmd(msg, cb);
285 static int get_freq_wext(const char *ifname)
289 /* Ugly hack to avoid incuding wireless.h */
291 char name1[IFNAMSIZ];
298 fd = socket(AF_INET, SOCK_DGRAM, 0);
302 g_strlcpy(wrq.name1, ifname, IFNAMSIZ);
304 if (ioctl(fd, 0x8B05, &wrq) == 0) {
314 struct ws80211_iface_info *pub;
319 static int get_iface_info_handler(struct nl_msg *msg, void *arg)
321 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
322 struct nlattr *tb_msg[NL80211_ATTR_MAX + 1];
323 struct __iface_info *iface_info = arg;
325 nla_parse(tb_msg, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
326 genlmsg_attrlen(gnlh, 0), NULL);
328 if (tb_msg[NL80211_ATTR_IFTYPE]) {
329 iface_info->type = nla_get_u32(tb_msg[NL80211_ATTR_IFTYPE]);
331 if (tb_msg[NL80211_ATTR_WIPHY]) {
332 iface_info->phyidx = nla_get_u32(tb_msg[NL80211_ATTR_WIPHY]);
335 if (tb_msg[NL80211_ATTR_WIPHY_FREQ]) {
336 iface_info->pub->current_freq = nla_get_u32(tb_msg[NL80211_ATTR_WIPHY_FREQ]);
337 iface_info->pub->current_chan_type = NL80211_CHAN_NO_HT;
339 if (tb_msg[NL80211_ATTR_WIPHY_CHANNEL_TYPE])
340 iface_info->pub->current_chan_type = nla_get_u32(tb_msg[NL80211_ATTR_WIPHY_CHANNEL_TYPE]);
347 static int __ws80211_get_iface_info(const char *name, struct __iface_info *iface_info)
354 fprintf(stderr, "failed to allocate netlink message\n");
358 cb = nl_cb_alloc(NL_CB_DEFAULT);
360 devidx = if_nametoindex(name);
362 genlmsg_put(msg, 0, 0, nl_state.nl80211_id, 0,
363 0, NL80211_CMD_GET_INTERFACE, 0);
364 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, devidx);
366 nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, get_iface_info_handler, iface_info);
368 if (nl80211_do_cmd(msg, cb))
371 /* Old kernels cant get the current freq via netlink. Try WEXT too :( */
372 if (iface_info->pub->current_freq == -1)
373 iface_info->pub->current_freq = get_freq_wext(name);
377 fprintf(stderr, "building message failed\n");
381 int ws80211_get_iface_info(const char *name, struct ws80211_iface_info *iface_info)
383 struct __iface_info __iface_info;
385 memset(iface_info, 0, sizeof(*iface_info));
386 __iface_info.pub = iface_info;
387 __iface_info.type = -1;
388 __iface_info.phyidx= -1;
389 __iface_info.pub->current_freq = -1;
390 __iface_info.pub->current_chan_type = -1;
392 return __ws80211_get_iface_info(name, &__iface_info);
395 static int ws80211_populate_devices(GArray *interfaces)
405 struct ws80211_iface_info pub;
406 struct __iface_info iface_info;
407 struct ws80211_interface *iface;
409 /* Get a list of phy's that can handle monitor mode */
410 ws80211_get_phys(interfaces);
412 fh = g_fopen("/proc/net/dev", "r");
414 fprintf(stderr, "Cannot open /proc/net/dev");
418 /* Skip the first two lines */
419 for (i = 0; i < 2; i++) {
420 ret = fgets(line, sizeof(line), fh);
422 fprintf(stderr, "Error parsing /proc/net/dev");
427 /* Update names of user created monitor interfaces */
428 while(fgets(line, sizeof(line), fh)) {
429 t = index(line, ':');
434 while (*t && *t == ' ')
436 memset(&iface_info, 0, sizeof(iface_info));
437 iface_info.pub = &pub;
438 __ws80211_get_iface_info(t, &iface_info);
440 if (iface_info.type == NL80211_IFTYPE_MONITOR) {
441 for (j = 0; j < interfaces->len; j++) {
442 iface = g_array_index(interfaces, struct ws80211_interface *, j);
443 t2 = g_strdup_printf("phy%d.mon", iface_info.phyidx);
445 if (!strcmp(t2, iface->ifname)) {
446 g_free(iface->ifname);
447 iface->ifname = g_strdup(t);
458 static int ws80211_iface_up(const char *ifname)
463 sock = socket(AF_PACKET, SOCK_RAW, 0);
467 g_strlcpy(ifreq.ifr_name, ifname, sizeof(ifreq.ifr_name));
469 if (ioctl(sock, SIOCGIFFLAGS, &ifreq))
472 ifreq.ifr_flags |= IFF_UP;
474 if (ioctl(sock, SIOCSIFFLAGS, &ifreq))
485 static int ws80211_create_on_demand_interface(const char *name)
487 int devidx, phyidx, err;
491 devidx = if_nametoindex(name);
495 if (sscanf(name, "phy%d.mon", &phyidx) != 1)
498 cb = nl_cb_alloc(NL_CB_DEFAULT);
501 fprintf(stderr, "failed to allocate netlink message\n");
505 genlmsg_put(msg, 0, 0, nl_state.nl80211_id, 0,
506 0, NL80211_CMD_NEW_INTERFACE, 0);
507 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, phyidx);
509 NLA_PUT_STRING(msg, NL80211_ATTR_IFNAME, name);
510 NLA_PUT_U32(msg, NL80211_ATTR_IFTYPE, NL80211_IFTYPE_MONITOR);
512 err = nl80211_do_cmd(msg, cb);
515 return ws80211_iface_up(name);
518 fprintf(stderr, "building message failed\n");
522 int ws80211_set_freq(const char *name, int freq, int chan_type)
528 err = ws80211_create_on_demand_interface(name);
534 fprintf(stderr, "failed to allocate netlink message\n");
538 cb = nl_cb_alloc(NL_CB_DEFAULT);
540 devidx = if_nametoindex(name);
542 genlmsg_put(msg, 0, 0, nl_state.nl80211_id, 0,
543 0, NL80211_CMD_SET_CHANNEL, 0);
544 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, devidx);
545 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, freq);
549 #ifdef NL80211_BAND_ATTR_HT_CAPA
550 case WS80211_CHAN_NO_HT:
551 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE, NL80211_CHAN_NO_HT);
554 case WS80211_CHAN_HT20:
555 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE, NL80211_CHAN_HT20);
558 case WS80211_CHAN_HT40MINUS:
559 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE, NL80211_CHAN_HT40MINUS);
562 case WS80211_CHAN_HT40PLUS:
563 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE, NL80211_CHAN_HT40PLUS);
570 err = nl80211_do_cmd(msg, cb);
574 fprintf(stderr, "building message failed\n");
579 void ws80211_free_interfaces(GArray *interfaces)
581 struct ws80211_interface *iface;
586 while (interfaces->len) {
587 iface = g_array_index(interfaces, struct ws80211_interface *, 0);
588 g_array_remove_index(interfaces, 0);
589 g_array_free(iface->frequencies, TRUE);
590 g_free(iface->ifname);
593 g_array_free(interfaces, TRUE);
596 GArray* ws80211_find_interfaces(void)
600 if (!nl_state.nl_sock)
603 interfaces = g_array_new(FALSE, FALSE, sizeof(struct ws80211_interface *));
607 if (ws80211_populate_devices(interfaces)) {
608 ws80211_free_interfaces(interfaces);
614 int ws80211_frequency_to_channel(int freq)
620 return (freq - 2407) / 5;
622 return freq / 5 - 1000;
626 ws80211_str_to_chan_type(gchar *s)
632 if (!strcmp(s, CHAN_NO_HT))
633 ret = WS80211_CHAN_NO_HT;
634 if (!strcmp(s, CHAN_HT20))
635 ret = WS80211_CHAN_HT20;
636 if (!strcmp(s, CHAN_HT40MINUS))
637 ret = WS80211_CHAN_HT40MINUS;
638 if (!strcmp(s, CHAN_HT40PLUS))
639 ret = WS80211_CHAN_HT40PLUS;
644 *ws80211_chan_type_to_str(int type)
647 case WS80211_CHAN_NO_HT:
649 case WS80211_CHAN_HT20:
651 case WS80211_CHAN_HT40MINUS:
652 return CHAN_HT40MINUS;
653 case WS80211_CHAN_HT40PLUS:
654 return CHAN_HT40PLUS;
659 #else /* HAVE_LIBNL */
660 int ws80211_init(void)
665 GArray* ws80211_find_interfaces(void)
670 int ws80211_get_iface_info(const char *name _U_, struct ws80211_iface_info *iface_info _U_)
675 void ws80211_free_interfaces(GArray *interfaces _U_)
679 int ws80211_frequency_to_channel(int freq _U_)
684 int ws80211_set_freq(const char *name _U_, int freq _U_, int chan_type _U_)
689 int ws80211_str_to_chan_type(gchar *s _U_)
694 gchar *ws80211_chan_type_to_str(int type _U_)
698 #endif /* HAVE_LIBNL */