decryption works, but addid doesn't because of unique pointer layers
[wireshark-sm.git] / capture / ws80211_utils.c
blobd74d7b26b7b28f73a80de493d237f4ebf571f72c
1 /*
2 * ws80211 utilities
3 * Copyright 2012, Pontus Fuchs <pontus.fuchs@gmail.com>
5 Parts of this file was copied from iw:
7 Copyright (c) 2007, 2008 Johannes Berg
8 Copyright (c) 2007 Andy Lutomirski
9 Copyright (c) 2007 Mike Kershaw
10 Copyright (c) 2008-2009 Luis R. Rodriguez
12 SPDX-License-Identifier: ISC
15 #include "config.h"
16 #include "ws80211_utils.h"
18 #include <stdio.h>
20 #include <glib.h>
21 #include <glib/gstdio.h>
23 #include <wsutil/array.h>
25 #if defined(HAVE_LIBNL) && defined(HAVE_NL80211)
26 #include <string.h>
27 #include <errno.h>
28 #include <unistd.h>
30 #include <net/if.h>
31 #include <sys/ioctl.h>
33 #include <netlink/genl/genl.h>
34 #include <netlink/genl/family.h>
35 #include <netlink/genl/ctrl.h>
36 #include <netlink/msg.h>
37 #include <netlink/attr.h>
39 #include <linux/nl80211.h>
41 #ifdef HAVE_NL80211_SPLIT_WIPHY_DUMP
42 static int ws80211_get_protocol_features(int* features);
43 #endif /* HAVE_NL80211_SPLIT_WIPHY_DUMP */
45 /* libnl 1.x compatibility code */
46 #ifdef HAVE_LIBNL1
47 #define nl_sock nl_handle
48 static inline struct nl_handle *nl_socket_alloc(void)
50 return nl_handle_alloc();
53 static inline void nl_socket_free(struct nl_sock *h)
55 nl_handle_destroy(h);
57 #endif /* HAVE_LIBNL1 */
59 struct nl80211_state {
60 struct nl_sock *nl_sock;
61 int nl80211_id;
62 int have_split_wiphy;
65 static struct nl80211_state nl_state;
67 int ws80211_init(void)
69 int err;
70 #ifdef HAVE_NL80211_SPLIT_WIPHY_DUMP
71 int features = 0;
72 #endif /* HAVE_NL80211_SPLIT_WIPHY_DUMP */
74 struct nl80211_state *state = &nl_state;
76 state->nl_sock = nl_socket_alloc();
77 if (!state->nl_sock) {
78 fprintf(stderr, "Failed to allocate netlink socket.\n");
79 return -ENOMEM;
82 if (genl_connect(state->nl_sock)) {
83 fprintf(stderr, "Failed to connect to generic netlink.\n");
84 err = -ENOLINK;
85 goto out_handle_destroy;
88 state->nl80211_id = genl_ctrl_resolve(state->nl_sock, "nl80211");
89 if (state->nl80211_id < 0) {
90 fprintf(stderr, "nl80211 not found.\n");
91 err = -ENOENT;
92 goto out_handle_destroy;
94 #ifdef HAVE_NL80211_SPLIT_WIPHY_DUMP
95 ws80211_get_protocol_features(&features);
96 if (features & NL80211_PROTOCOL_FEATURE_SPLIT_WIPHY_DUMP)
97 state->have_split_wiphy = true;
98 #endif /* HAVE_NL80211_SPLIT_WIPHY_DUMP */
100 return WS80211_INIT_OK;
102 out_handle_destroy:
103 nl_socket_free(state->nl_sock);
104 state->nl_sock = 0;
105 return err;
108 static int error_handler(struct sockaddr_nl *nla _U_, struct nlmsgerr *err,
109 void *arg)
111 int *ret = (int *)arg;
112 *ret = err->error;
113 return NL_STOP;
116 static int finish_handler(struct nl_msg *msg _U_, void *arg)
118 int *ret = (int *)arg;
119 *ret = 0;
120 return NL_SKIP;
123 static int ack_handler(struct nl_msg *msg _U_, void *arg)
125 int *ret = (int *)arg;
126 *ret = 0;
127 return NL_STOP;
130 static int nl80211_do_cmd(struct nl_msg *msg, struct nl_cb *cb)
133 * XXX - Coverity doesn't understand how libnl works, so it
134 * doesn't know that nl_recvmsgs() calls the callback, and
135 * that the callback has had a pointer to err registered
136 * with it, and therefore that nl_recvmsgs() can change
137 * err as a side-effect, so it thinks this can loop
138 * infinitely.
140 * The proper way to address this is to help Coverity to
141 * understand the behaviour of nl_recvmsgs(), in that it
142 * does call the callback, setting err. This help would be
143 * provided through a so called 'model' of this function.
144 * We declare err to be volatile to work around it.
146 * XXX - that workaround provokes a compiler complaint that
147 * casting a pointer to it to "void *" discards the
148 * volatile qualifier. Perhaps we should just re-close
149 * Coverity CID 997052 as "false positive".
151 volatile int err;
153 if (!nl_state.nl_sock)
154 return -ENOLINK;
156 err = nl_send_auto_complete(nl_state.nl_sock, msg);
157 if (err < 0)
158 goto out;
160 err = 1;
162 nl_cb_err(cb, NL_CB_CUSTOM, error_handler, (void *)&err);
163 nl_cb_set(cb, NL_CB_FINISH, NL_CB_CUSTOM, finish_handler, (void *)&err);
164 nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, ack_handler, (void *)&err);
166 while (err > 0)
167 nl_recvmsgs(nl_state.nl_sock, cb);
168 out:
169 nl_cb_put(cb);
171 return err;
174 struct nliface_cookie
176 char *ifname;
177 GArray *interfaces;
180 static struct ws80211_interface *
181 get_interface_by_name(GArray *interfaces,
182 char* ifname)
184 unsigned int i;
185 struct ws80211_interface *iface;
187 for (i = 0; i < interfaces->len; i++) {
188 iface = g_array_index(interfaces, struct ws80211_interface *, i);
189 if (!strcmp(iface->ifname, ifname))
190 return iface;
192 return NULL;
195 #ifdef HAVE_NL80211_SPLIT_WIPHY_DUMP
196 static int get_features_handler(struct nl_msg *msg, void *arg)
198 int *feat = (int*) arg;
199 struct nlattr *tb_msg[NL80211_ATTR_MAX + 1];
200 struct genlmsghdr *gnlh = (struct genlmsghdr *)nlmsg_data(nlmsg_hdr(msg));
202 nla_parse(tb_msg, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
203 genlmsg_attrlen(gnlh, 0), NULL);
205 if (tb_msg[NL80211_ATTR_PROTOCOL_FEATURES])
206 *feat = nla_get_u32(tb_msg[NL80211_ATTR_PROTOCOL_FEATURES]);
208 return NL_SKIP;
211 static int ws80211_get_protocol_features(int* features)
213 struct nl_msg *msg;
214 struct nl_cb *cb;
215 int ret;
217 msg = nlmsg_alloc();
218 if (!msg) {
219 fprintf(stderr, "failed to allocate netlink message\n");
220 return 2;
223 cb = nl_cb_alloc(NL_CB_DEFAULT);
225 genlmsg_put(msg, 0, 0, nl_state.nl80211_id, 0, 0,
226 NL80211_CMD_GET_PROTOCOL_FEATURES, 0);
228 nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, get_features_handler, features);
230 ret = nl80211_do_cmd(msg, cb);
231 nlmsg_free(msg);
232 return ret;
234 #endif /* HAVE_NL80211_SPLIT_WIPHY_DUMP */
236 #ifdef NL80211_BAND_ATTR_HT_CAPA
237 static void parse_band_ht_capa(struct ws80211_interface *iface,
238 struct nlattr *tb)
240 bool ht40;
242 if (!tb) return;
244 iface->channel_types |= 1 << WS80211_CHAN_HT20;
245 ht40 = !!(nla_get_u16(tb) & 0x02);
246 if (ht40) {
247 iface->channel_types |= 1 << WS80211_CHAN_HT40MINUS;
248 iface->channel_types |= 1 << WS80211_CHAN_HT40PLUS;
251 #endif /* NL80211_BAND_ATTR_HT_CAPA */
253 #ifdef HAVE_NL80211_VHT_CAPABILITY
254 static void parse_band_vht_capa(struct ws80211_interface *iface,
255 struct nlattr *tb)
257 uint32_t chan_capa;
258 if (!tb) return;
260 chan_capa = (nla_get_u32(tb) >> 2) & 3;
261 if (chan_capa == 1) {
262 iface->channel_types |= 1 << WS80211_CHAN_VHT160;
264 if (chan_capa == 2) {
265 iface->channel_types |= 1 << WS80211_CHAN_VHT160;
266 iface->channel_types |= 1 << WS80211_CHAN_VHT80P80;
268 iface->channel_types |= 1 << WS80211_CHAN_VHT80;
270 #endif /* HAVE_NL80211_VHT_CAPABILITY */
272 static void parse_supported_iftypes(struct ws80211_interface *iface,
273 struct nlattr *tb)
275 struct nlattr *nl_mode;
276 int rem_mode;
278 if (!tb) return;
280 nla_for_each_nested(nl_mode, tb, rem_mode) {
281 if (nla_type(nl_mode) == NL80211_IFTYPE_MONITOR)
282 iface->cap_monitor = 1;
286 static void parse_band_freqs(struct ws80211_interface *iface,
287 struct nlattr *tb)
289 struct nlattr *nl_freq;
290 struct nlattr *tb_freq[NL80211_FREQUENCY_ATTR_MAX + 1];
291 static struct nla_policy freq_policy[NL80211_FREQUENCY_ATTR_MAX + 1] = {
292 {NLA_UNSPEC, 0, 0}, /* __NL80211_FREQUENCY_ATTR_INVALID */
293 {NLA_U32, 0, 0}, /* NL80211_FREQUENCY_ATTR_FREQ */
294 {NLA_FLAG, 0, 0}, /* NL80211_FREQUENCY_ATTR_DISABLED */
295 {NLA_FLAG, 0, 0}, /* NL80211_FREQUENCY_ATTR_PASSIVE_SCAN */
296 {NLA_FLAG, 0, 0}, /* NL80211_FREQUENCY_ATTR_NO_IBSS */
297 {NLA_FLAG, 0, 0}, /* NL80211_FREQUENCY_ATTR_RADAR */
298 {NLA_U32, 0, 0} /* NL80211_FREQUENCY_ATTR_MAX_TX_POWER */
300 int rem_freq;
302 if (!tb) return;
304 nla_for_each_nested(nl_freq, tb, rem_freq) {
305 uint32_t freq;
306 nla_parse(tb_freq, NL80211_FREQUENCY_ATTR_MAX,
307 (struct nlattr *)nla_data(nl_freq),
308 nla_len(nl_freq), freq_policy);
309 if (!tb_freq[NL80211_FREQUENCY_ATTR_FREQ])
310 continue;
311 if (tb_freq[NL80211_FREQUENCY_ATTR_DISABLED])
312 continue;
314 freq = nla_get_u32(tb_freq[NL80211_FREQUENCY_ATTR_FREQ]);
315 g_array_append_val(iface->frequencies, freq);
319 static void parse_wiphy_bands(struct ws80211_interface *iface,
320 struct nlattr *tb)
322 struct nlattr *nl_band;
323 struct nlattr *tb_band[NL80211_BAND_ATTR_MAX + 1];
324 int rem_band;
326 if (!tb) return;
328 nla_for_each_nested(nl_band, tb, rem_band) {
329 nla_parse(tb_band, NL80211_BAND_ATTR_MAX,
330 (struct nlattr *)nla_data(nl_band),
331 nla_len(nl_band), NULL);
333 #ifdef NL80211_BAND_ATTR_HT_CAPA
334 parse_band_ht_capa(iface, tb_band[NL80211_BAND_ATTR_HT_CAPA]);
335 #endif /* NL80211_BAND_ATTR_HT_CAPA */
336 #ifdef HAVE_NL80211_VHT_CAPABILITY
337 parse_band_vht_capa(iface, tb_band[NL80211_BAND_ATTR_VHT_CAPA]);
338 #endif /* HAVE_NL80211_VHT_CAPABILITY */
339 parse_band_freqs(iface, tb_band[NL80211_BAND_ATTR_FREQS]);
343 static void parse_supported_commands(struct ws80211_interface *iface,
344 struct nlattr *tb)
346 /* Can frequency be set? Only newer versions of cfg80211 supports this */
347 #ifdef HAVE_NL80211_CMD_SET_CHANNEL
348 int cmd;
349 struct nlattr *nl_cmd;
351 if (!tb) return;
353 nla_for_each_nested(nl_cmd, tb, cmd) {
354 if(nla_get_u32(nl_cmd) == NL80211_CMD_SET_CHANNEL)
355 iface->can_set_freq = true;
357 #else
358 iface->can_set_freq = true;
359 #endif
362 static int get_phys_handler(struct nl_msg *msg, void *arg)
364 struct nlattr *tb_msg[NL80211_ATTR_MAX + 1];
365 struct genlmsghdr *gnlh = (struct genlmsghdr *)nlmsg_data(nlmsg_hdr(msg));
367 struct nliface_cookie *cookie = (struct nliface_cookie *)arg;
369 struct ws80211_interface *iface;
370 char* ifname;
371 int added = 0;
373 nla_parse(tb_msg, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
374 genlmsg_attrlen(gnlh, 0), NULL);
376 if (!tb_msg[NL80211_ATTR_WIPHY_NAME])
377 return NL_SKIP;
379 ifname = ws_strdup_printf("%s.mon", nla_get_string(tb_msg[NL80211_ATTR_WIPHY_NAME]));
380 iface = get_interface_by_name(cookie->interfaces, ifname);
382 if (!iface) {
383 iface = (struct ws80211_interface *)g_malloc0(sizeof(*iface));
384 if (!iface) {
385 g_free(ifname);
386 return NL_SKIP;
388 added = 1;
389 iface->ifname = ifname;
390 iface->frequencies = g_array_new(false, false, sizeof(uint32_t));
391 iface->channel_types = 1 << WS80211_CHAN_NO_HT;
392 } else {
393 g_free(ifname);
396 parse_supported_iftypes(iface, tb_msg[NL80211_ATTR_SUPPORTED_IFTYPES]);
397 parse_wiphy_bands(iface, tb_msg[NL80211_ATTR_WIPHY_BANDS]);
398 parse_supported_commands(iface, tb_msg[NL80211_ATTR_SUPPORTED_COMMANDS]);
400 if (added)
401 g_array_append_val(cookie->interfaces, iface);
403 return NL_SKIP;
406 static int ws80211_get_phys(GArray *interfaces)
408 struct nliface_cookie cookie;
409 struct nl_msg *msg;
410 struct nl_cb *cb;
411 int ret;
412 msg = nlmsg_alloc();
413 if (!msg) {
414 fprintf(stderr, "failed to allocate netlink message\n");
415 return 2;
418 cb = nl_cb_alloc(NL_CB_DEFAULT);
420 cookie.interfaces = interfaces;
422 genlmsg_put(msg, 0, 0, nl_state.nl80211_id, 0,
423 NLM_F_DUMP, NL80211_CMD_GET_WIPHY, 0);
425 #ifdef HAVE_NL80211_SPLIT_WIPHY_DUMP
426 if (nl_state.have_split_wiphy) {
427 NLA_PUT_FLAG(msg, NL80211_ATTR_SPLIT_WIPHY_DUMP);
429 #endif /* #ifdef HAVE_NL80211_SPLIT_WIPHY_DUMP */
430 nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, get_phys_handler, &cookie);
432 ret = nl80211_do_cmd(msg, cb);
433 nlmsg_free(msg);
434 return ret;
436 #ifdef HAVE_NL80211_SPLIT_WIPHY_DUMP
437 nla_put_failure:
438 nlmsg_free(msg);
439 fprintf(stderr, "building message failed\n");
440 return -1;
441 #endif /* HAVE_NL80211_SPLIT_WIPHY_DUMP */
444 static int get_freq_wext(const char *ifname)
446 int fd;
447 int ret = -1;
448 /* Ugly hack to avoid including wireless.h */
449 struct {
450 char name1[IFNAMSIZ];
451 __s32 m;
452 __s16 e;
453 __u8 i;
454 __u8 flags;
455 } wrq;
457 fd = socket(AF_INET, SOCK_DGRAM, 0);
458 if (fd == -1)
459 return -1;
461 (void) g_strlcpy(wrq.name1, ifname, IFNAMSIZ);
462 /* SIOCGIWFREQ */
463 if (ioctl(fd, 0x8B05, &wrq) == 0) {
464 if (wrq.e == 6)
465 ret = wrq.m;
467 close(fd);
468 return ret;
471 struct __iface_info
473 struct ws80211_iface_info *pub;
474 int type;
475 int phyidx;
478 static int get_iface_info_handler(struct nl_msg *msg, void *arg)
480 struct genlmsghdr *gnlh = (struct genlmsghdr *)nlmsg_data(nlmsg_hdr(msg));
481 struct nlattr *tb_msg[NL80211_ATTR_MAX + 1];
482 struct __iface_info *iface_info = (struct __iface_info *)arg;
484 nla_parse(tb_msg, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
485 genlmsg_attrlen(gnlh, 0), NULL);
487 if (tb_msg[NL80211_ATTR_IFTYPE]) {
488 iface_info->type = nla_get_u32(tb_msg[NL80211_ATTR_IFTYPE]);
490 if (tb_msg[NL80211_ATTR_WIPHY]) {
491 iface_info->phyidx = nla_get_u32(tb_msg[NL80211_ATTR_WIPHY]);
494 if (tb_msg[NL80211_ATTR_WIPHY_FREQ]) {
495 bool found_ch_width = false;
496 iface_info->pub->current_freq = nla_get_u32(tb_msg[NL80211_ATTR_WIPHY_FREQ]);
497 iface_info->pub->current_chan_type = WS80211_CHAN_NO_HT;
498 #ifdef HAVE_NL80211_VHT_CAPABILITY
499 if (tb_msg[NL80211_ATTR_CHANNEL_WIDTH]) {
500 switch (nla_get_u32(tb_msg[NL80211_ATTR_CHANNEL_WIDTH])) {
501 case NL80211_CHAN_WIDTH_80:
502 iface_info->pub->current_chan_type = WS80211_CHAN_VHT80;
503 found_ch_width = true;
504 break;
505 case NL80211_CHAN_WIDTH_80P80:
506 iface_info->pub->current_chan_type = WS80211_CHAN_VHT80P80;
507 found_ch_width = true;
508 break;
509 case NL80211_CHAN_WIDTH_160:
510 iface_info->pub->current_chan_type = WS80211_CHAN_VHT160;
511 found_ch_width = true;
512 break;
515 if (tb_msg[NL80211_ATTR_CENTER_FREQ1]) {
516 iface_info->pub->current_center_freq1 =
517 nla_get_u32(tb_msg[NL80211_ATTR_CENTER_FREQ1]);
519 if (tb_msg[NL80211_ATTR_CENTER_FREQ2]) {
520 iface_info->pub->current_center_freq2 =
521 nla_get_u32(tb_msg[NL80211_ATTR_CENTER_FREQ2]);
523 #endif
524 if (!found_ch_width && tb_msg[NL80211_ATTR_WIPHY_CHANNEL_TYPE]) {
525 switch (nla_get_u32(tb_msg[NL80211_ATTR_WIPHY_CHANNEL_TYPE])) {
527 case NL80211_CHAN_NO_HT:
528 iface_info->pub->current_chan_type = WS80211_CHAN_NO_HT;
529 break;
531 case NL80211_CHAN_HT20:
532 iface_info->pub->current_chan_type = WS80211_CHAN_HT20;
533 break;
535 case NL80211_CHAN_HT40MINUS:
536 iface_info->pub->current_chan_type = WS80211_CHAN_HT40MINUS;
537 break;
539 case NL80211_CHAN_HT40PLUS:
540 iface_info->pub->current_chan_type = WS80211_CHAN_HT40PLUS;
541 break;
546 return NL_SKIP;
550 static int __ws80211_get_iface_info(const char *name, struct __iface_info *iface_info)
552 int devidx;
553 struct nl_msg *msg;
554 struct nl_cb *cb;
555 msg = nlmsg_alloc();
556 if (!msg) {
557 fprintf(stderr, "failed to allocate netlink message\n");
558 return 2;
561 cb = nl_cb_alloc(NL_CB_DEFAULT);
563 devidx = if_nametoindex(name);
565 genlmsg_put(msg, 0, 0, nl_state.nl80211_id, 0,
566 0, NL80211_CMD_GET_INTERFACE, 0);
567 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, devidx);
569 nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, get_iface_info_handler, iface_info);
571 if (nl80211_do_cmd(msg, cb)) {
572 nlmsg_free(msg);
573 return -1;
576 /* Old kernels can't get the current freq via netlink. Try WEXT too :( */
577 if (iface_info->pub->current_freq == -1)
578 iface_info->pub->current_freq = get_freq_wext(name);
579 nlmsg_free(msg);
580 return 0;
582 nla_put_failure:
583 nlmsg_free(msg);
584 fprintf(stderr, "building message failed\n");
585 return -1;
588 int ws80211_get_iface_info(const char *name, struct ws80211_iface_info *iface_info)
590 struct __iface_info __iface_info;
592 memset(iface_info, 0, sizeof(*iface_info));
593 __iface_info.pub = iface_info;
594 __iface_info.type = -1;
595 __iface_info.phyidx= -1;
596 __iface_info.pub->current_freq = -1;
597 __iface_info.pub->current_chan_type = WS80211_CHAN_NO_HT;
599 return __ws80211_get_iface_info(name, &__iface_info);
602 static int ws80211_keep_only_monitor(GArray *interfaces)
604 unsigned int j;
605 struct ws80211_interface *iface;
606 restart:
607 for (j = 0; j < interfaces->len; j++) {
608 iface = g_array_index(interfaces, struct ws80211_interface *, j);
609 if (!iface->cap_monitor) {
610 g_array_remove_index(interfaces, j);
611 g_array_free(iface->frequencies, true);
612 g_free(iface->ifname);
613 g_free(iface);
614 goto restart;
617 return 0;
620 static int ws80211_populate_devices(GArray *interfaces)
622 FILE *fh;
623 char line[200];
624 char *t;
625 char *t2;
626 char *ret;
627 int i;
628 unsigned int j;
630 struct ws80211_iface_info pub = {-1, WS80211_CHAN_NO_HT, -1, -1, WS80211_FCS_ALL};
631 struct __iface_info iface_info;
632 struct ws80211_interface *iface;
634 /* Get a list of phy's that can handle monitor mode */
635 ws80211_get_phys(interfaces);
636 ws80211_keep_only_monitor(interfaces);
638 fh = g_fopen("/proc/net/dev", "r");
639 if(!fh) {
640 fprintf(stderr, "Cannot open /proc/net/dev");
641 return -ENOENT;
644 /* Skip the first two lines */
645 for (i = 0; i < 2; i++) {
646 ret = fgets(line, sizeof(line), fh);
647 if (ret == NULL) {
648 fprintf(stderr, "Error parsing /proc/net/dev");
649 fclose(fh);
650 return -1;
654 /* Update names of user created monitor interfaces */
655 while(fgets(line, sizeof(line), fh)) {
656 t = index(line, ':');
657 if (!t)
658 continue;
659 *t = 0;
660 t = line;
661 while (*t == ' ')
662 t++;
663 memset(&iface_info, 0, sizeof(iface_info));
664 iface_info.pub = &pub;
665 __ws80211_get_iface_info(t, &iface_info);
667 if (iface_info.type == NL80211_IFTYPE_MONITOR) {
668 for (j = 0; j < interfaces->len; j++) {
669 iface = g_array_index(interfaces, struct ws80211_interface *, j);
670 t2 = ws_strdup_printf("phy%d.mon", iface_info.phyidx);
671 if (t2) {
672 if (!strcmp(t2, iface->ifname)) {
673 g_free(iface->ifname);
674 iface->ifname = g_strdup(t);
676 g_free(t2);
681 fclose(fh);
682 return 0;
685 static int ws80211_iface_up(const char *ifname)
687 int sock;
688 struct ifreq ifreq;
690 sock = socket(AF_PACKET, SOCK_RAW, 0);
691 if (sock == -1)
692 return -1;
694 (void) g_strlcpy(ifreq.ifr_name, ifname, sizeof(ifreq.ifr_name));
696 if (ioctl(sock, SIOCGIFFLAGS, &ifreq))
697 goto out_err;
699 ifreq.ifr_flags |= IFF_UP;
701 if (ioctl(sock, SIOCSIFFLAGS, &ifreq))
702 goto out_err;
704 close(sock);
705 return 0;
707 out_err:
708 close(sock);
709 return -1;
712 /* Needed for NLA_PUT_STRING, which passes strlen as an int */
713 DIAG_OFF_CLANG(shorten-64-to-32)
714 static int ws80211_create_on_demand_interface(const char *name)
716 int devidx, phyidx, err;
717 struct nl_msg *msg;
718 struct nl_cb *cb;
720 devidx = if_nametoindex(name);
721 if (devidx)
722 return ws80211_iface_up(name);
724 if (sscanf(name, "phy%d.mon", &phyidx) != 1)
725 return -EINVAL;
727 cb = nl_cb_alloc(NL_CB_DEFAULT);
728 msg = nlmsg_alloc();
729 if (!msg) {
730 fprintf(stderr, "failed to allocate netlink message\n");
731 return 2;
734 genlmsg_put(msg, 0, 0, nl_state.nl80211_id, 0,
735 0, NL80211_CMD_NEW_INTERFACE, 0);
736 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, phyidx);
738 NLA_PUT_STRING(msg, NL80211_ATTR_IFNAME, name);
739 NLA_PUT_U32(msg, NL80211_ATTR_IFTYPE, NL80211_IFTYPE_MONITOR);
741 err = nl80211_do_cmd(msg, cb);
742 nlmsg_free(msg);
743 if (err)
744 return err;
745 return ws80211_iface_up(name);
747 nla_put_failure:
748 nlmsg_free(msg);
749 fprintf(stderr, "building message failed\n");
750 return 2;
752 DIAG_ON_CLANG(shorten-64-to-32)
754 int ws80211_set_freq(const char *name, uint32_t freq, int chan_type, uint32_t _U_ center_freq, uint32_t _U_ center_freq2)
756 int devidx, err;
757 struct nl_msg *msg;
758 struct nl_cb *cb;
760 err = ws80211_create_on_demand_interface(name);
761 if (err)
762 return err;
764 msg = nlmsg_alloc();
765 if (!msg) {
766 fprintf(stderr, "failed to allocate netlink message\n");
767 return 2;
770 cb = nl_cb_alloc(NL_CB_DEFAULT);
772 devidx = if_nametoindex(name);
774 #ifdef HAVE_NL80211_CMD_SET_CHANNEL
775 genlmsg_put(msg, 0, 0, nl_state.nl80211_id, 0,
776 0, NL80211_CMD_SET_CHANNEL, 0);
777 #else
778 genlmsg_put(msg, 0, 0, nl_state.nl80211_id, 0,
779 0, NL80211_CMD_SET_WIPHY, 0);
780 #endif
782 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, devidx);
783 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, freq);
785 switch (chan_type) {
787 #ifdef NL80211_BAND_ATTR_HT_CAPA
788 case WS80211_CHAN_NO_HT:
789 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE, NL80211_CHAN_NO_HT);
790 break;
792 case WS80211_CHAN_HT20:
793 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE, NL80211_CHAN_HT20);
794 break;
796 case WS80211_CHAN_HT40MINUS:
797 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE, NL80211_CHAN_HT40MINUS);
798 break;
800 case WS80211_CHAN_HT40PLUS:
801 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE, NL80211_CHAN_HT40PLUS);
802 break;
803 #endif
804 #ifdef HAVE_NL80211_VHT_CAPABILITY
805 case WS80211_CHAN_VHT80:
806 NLA_PUT_U32(msg, NL80211_ATTR_CHANNEL_WIDTH, NL80211_CHAN_WIDTH_80);
807 NLA_PUT_U32(msg, NL80211_ATTR_CENTER_FREQ1, center_freq);
808 break;
810 case WS80211_CHAN_VHT80P80:
811 NLA_PUT_U32(msg, NL80211_ATTR_CHANNEL_WIDTH, NL80211_CHAN_WIDTH_80P80);
812 NLA_PUT_U32(msg, NL80211_ATTR_CENTER_FREQ1, center_freq);
813 NLA_PUT_U32(msg, NL80211_ATTR_CENTER_FREQ2, center_freq2);
814 break;
816 case WS80211_CHAN_VHT160:
817 NLA_PUT_U32(msg, NL80211_ATTR_CHANNEL_WIDTH, NL80211_CHAN_WIDTH_160);
818 NLA_PUT_U32(msg, NL80211_ATTR_CENTER_FREQ1, center_freq);
819 break;
820 #endif
821 default:
822 break;
824 err = nl80211_do_cmd(msg, cb);
825 nlmsg_free(msg);
826 return err;
828 nla_put_failure:
829 nlmsg_free(msg);
830 fprintf(stderr, "building message failed\n");
831 return 2;
835 GArray* ws80211_find_interfaces(void)
837 GArray *interfaces;
839 if (!nl_state.nl_sock)
840 return NULL;
842 interfaces = g_array_new(false, false, sizeof(struct ws80211_interface *));
843 if (!interfaces)
844 return NULL;
846 if (ws80211_populate_devices(interfaces)) {
847 ws80211_free_interfaces(interfaces);
848 return NULL;
850 return interfaces;
854 ws80211_str_to_chan_type(const char *s)
856 int ret = -1;
857 if (!s)
858 return -1;
860 if (!strcmp(s, CHAN_NO_HT))
861 ret = WS80211_CHAN_NO_HT;
862 if (!strcmp(s, CHAN_HT20))
863 ret = WS80211_CHAN_HT20;
864 if (!strcmp(s, CHAN_HT40MINUS))
865 ret = WS80211_CHAN_HT40MINUS;
866 if (!strcmp(s, CHAN_HT40PLUS))
867 ret = WS80211_CHAN_HT40PLUS;
868 if (!strcmp(s, CHAN_VHT80))
869 ret = WS80211_CHAN_VHT80;
870 if (!strcmp(s, CHAN_VHT80P80))
871 ret = WS80211_CHAN_VHT80P80;
872 if (!strcmp(s, CHAN_VHT160))
873 ret = WS80211_CHAN_VHT160;
875 return ret;
878 const char
879 *ws80211_chan_type_to_str(int type)
881 switch (type) {
882 case WS80211_CHAN_NO_HT:
883 return CHAN_NO_HT;
884 case WS80211_CHAN_HT20:
885 return CHAN_HT20;
886 case WS80211_CHAN_HT40MINUS:
887 return CHAN_HT40MINUS;
888 case WS80211_CHAN_HT40PLUS:
889 return CHAN_HT40PLUS;
890 case WS80211_CHAN_VHT80:
891 return CHAN_VHT80;
892 case WS80211_CHAN_VHT80P80:
893 return CHAN_VHT80P80;
894 case WS80211_CHAN_VHT160:
895 return CHAN_VHT160;
897 return NULL;
900 bool ws80211_has_fcs_filter(void)
902 return false;
905 int ws80211_set_fcs_validation(const char *name _U_, enum ws80211_fcs_validation fcs_validation _U_)
907 return -1;
910 const char *network_manager_path = "/usr/sbin/NetworkManager"; /* Is this correct? */
911 const char *ws80211_get_helper_path(void) {
912 if (g_file_test(network_manager_path, G_FILE_TEST_IS_EXECUTABLE)) {
913 return network_manager_path;
915 return NULL;
918 #else /* Everyone else. */
919 int ws80211_init(void)
921 return WS80211_INIT_NOT_SUPPORTED;
924 GArray* ws80211_find_interfaces(void)
926 return NULL;
929 int ws80211_get_iface_info(const char *name _U_, struct ws80211_iface_info *iface_info _U_)
931 return -1;
934 int ws80211_set_freq(const char *name _U_, uint32_t freq _U_, int _U_ chan_type, uint32_t _U_ center_freq, uint32_t _U_ center_freq2)
936 return -1;
939 int ws80211_str_to_chan_type(const char *s _U_)
941 return -1;
944 const char *ws80211_chan_type_to_str(int type _U_)
946 return NULL;
949 bool ws80211_has_fcs_filter(void)
951 return false;
954 int ws80211_set_fcs_validation(const char *name _U_, enum ws80211_fcs_validation fcs_validation _U_)
956 return -1;
959 const char *ws80211_get_helper_path(void) {
960 return NULL;
963 #endif /* HAVE_LIBNL && HAVE_NL80211 */
965 /* Common to everyone */
967 void ws80211_free_interfaces(GArray *interfaces)
969 struct ws80211_interface *iface;
971 if (!interfaces)
972 return;
974 while (interfaces->len) {
975 iface = g_array_index(interfaces, struct ws80211_interface *, 0);
976 g_array_remove_index(interfaces, 0);
977 g_array_free(iface->frequencies, true);
978 g_free(iface->ifname);
979 g_free(iface);
981 g_array_free(interfaces, true);
985 * Editor modelines - https://www.wireshark.org/tools/modelines.html
987 * Local variables:
988 * c-basic-offset: 8
989 * tab-width: 8
990 * indent-tabs-mode: t
991 * End:
993 * vi: set shiftwidth=8 tabstop=8 noexpandtab:
994 * :indentSize=8:tabSize=8:noTabs=false: