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
16 #include "ws80211_utils.h"
21 #include <glib/gstdio.h>
23 #include <wsutil/array.h>
25 #if defined(HAVE_LIBNL) && defined(HAVE_NL80211)
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 */
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
)
57 #endif /* HAVE_LIBNL1 */
59 struct nl80211_state
{
60 struct nl_sock
*nl_sock
;
65 static struct nl80211_state nl_state
;
67 int ws80211_init(void)
70 #ifdef HAVE_NL80211_SPLIT_WIPHY_DUMP
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");
82 if (genl_connect(state
->nl_sock
)) {
83 fprintf(stderr
, "Failed to connect to generic netlink.\n");
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");
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
;
103 nl_socket_free(state
->nl_sock
);
108 static int error_handler(struct sockaddr_nl
*nla _U_
, struct nlmsgerr
*err
,
111 int *ret
= (int *)arg
;
116 static int finish_handler(struct nl_msg
*msg _U_
, void *arg
)
118 int *ret
= (int *)arg
;
123 static int ack_handler(struct nl_msg
*msg _U_
, void *arg
)
125 int *ret
= (int *)arg
;
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
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".
153 if (!nl_state
.nl_sock
)
156 err
= nl_send_auto_complete(nl_state
.nl_sock
, msg
);
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
);
167 nl_recvmsgs(nl_state
.nl_sock
, cb
);
174 struct nliface_cookie
180 static struct ws80211_interface
*
181 get_interface_by_name(GArray
*interfaces
,
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
))
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
]);
211 static int ws80211_get_protocol_features(int* features
)
219 fprintf(stderr
, "failed to allocate netlink message\n");
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
);
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
,
244 iface
->channel_types
|= 1 << WS80211_CHAN_HT20
;
245 ht40
= !!(nla_get_u16(tb
) & 0x02);
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
,
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
,
275 struct nlattr
*nl_mode
;
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
,
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 */
304 nla_for_each_nested(nl_freq
, tb
, rem_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
])
311 if (tb_freq
[NL80211_FREQUENCY_ATTR_DISABLED
])
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
,
322 struct nlattr
*nl_band
;
323 struct nlattr
*tb_band
[NL80211_BAND_ATTR_MAX
+ 1];
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
,
346 /* Can frequency be set? Only newer versions of cfg80211 supports this */
347 #ifdef HAVE_NL80211_CMD_SET_CHANNEL
349 struct nlattr
*nl_cmd
;
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;
358 iface
->can_set_freq
= true;
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
;
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
])
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
);
383 iface
= (struct ws80211_interface
*)g_malloc0(sizeof(*iface
));
389 iface
->ifname
= ifname
;
390 iface
->frequencies
= g_array_new(false, false, sizeof(uint32_t));
391 iface
->channel_types
= 1 << WS80211_CHAN_NO_HT
;
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
]);
401 g_array_append_val(cookie
->interfaces
, iface
);
406 static int ws80211_get_phys(GArray
*interfaces
)
408 struct nliface_cookie cookie
;
414 fprintf(stderr
, "failed to allocate netlink message\n");
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
);
436 #ifdef HAVE_NL80211_SPLIT_WIPHY_DUMP
439 fprintf(stderr
, "building message failed\n");
441 #endif /* HAVE_NL80211_SPLIT_WIPHY_DUMP */
444 static int get_freq_wext(const char *ifname
)
448 /* Ugly hack to avoid including wireless.h */
450 char name1
[IFNAMSIZ
];
457 fd
= socket(AF_INET
, SOCK_DGRAM
, 0);
461 (void) g_strlcpy(wrq
.name1
, ifname
, IFNAMSIZ
);
463 if (ioctl(fd
, 0x8B05, &wrq
) == 0) {
473 struct ws80211_iface_info
*pub
;
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;
505 case NL80211_CHAN_WIDTH_80P80
:
506 iface_info
->pub
->current_chan_type
= WS80211_CHAN_VHT80P80
;
507 found_ch_width
= true;
509 case NL80211_CHAN_WIDTH_160
:
510 iface_info
->pub
->current_chan_type
= WS80211_CHAN_VHT160
;
511 found_ch_width
= true;
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
]);
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
;
531 case NL80211_CHAN_HT20
:
532 iface_info
->pub
->current_chan_type
= WS80211_CHAN_HT20
;
535 case NL80211_CHAN_HT40MINUS
:
536 iface_info
->pub
->current_chan_type
= WS80211_CHAN_HT40MINUS
;
539 case NL80211_CHAN_HT40PLUS
:
540 iface_info
->pub
->current_chan_type
= WS80211_CHAN_HT40PLUS
;
550 static int __ws80211_get_iface_info(const char *name
, struct __iface_info
*iface_info
)
557 fprintf(stderr
, "failed to allocate netlink message\n");
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
)) {
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
);
584 fprintf(stderr
, "building message failed\n");
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
)
605 struct ws80211_interface
*iface
;
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
);
620 static int ws80211_populate_devices(GArray
*interfaces
)
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");
640 fprintf(stderr
, "Cannot open /proc/net/dev");
644 /* Skip the first two lines */
645 for (i
= 0; i
< 2; i
++) {
646 ret
= fgets(line
, sizeof(line
), fh
);
648 fprintf(stderr
, "Error parsing /proc/net/dev");
654 /* Update names of user created monitor interfaces */
655 while(fgets(line
, sizeof(line
), fh
)) {
656 t
= index(line
, ':');
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
);
672 if (!strcmp(t2
, iface
->ifname
)) {
673 g_free(iface
->ifname
);
674 iface
->ifname
= g_strdup(t
);
685 static int ws80211_iface_up(const char *ifname
)
690 sock
= socket(AF_PACKET
, SOCK_RAW
, 0);
694 (void) g_strlcpy(ifreq
.ifr_name
, ifname
, sizeof(ifreq
.ifr_name
));
696 if (ioctl(sock
, SIOCGIFFLAGS
, &ifreq
))
699 ifreq
.ifr_flags
|= IFF_UP
;
701 if (ioctl(sock
, SIOCSIFFLAGS
, &ifreq
))
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
;
720 devidx
= if_nametoindex(name
);
722 return ws80211_iface_up(name
);
724 if (sscanf(name
, "phy%d.mon", &phyidx
) != 1)
727 cb
= nl_cb_alloc(NL_CB_DEFAULT
);
730 fprintf(stderr
, "failed to allocate netlink message\n");
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
);
745 return ws80211_iface_up(name
);
749 fprintf(stderr
, "building message failed\n");
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
)
760 err
= ws80211_create_on_demand_interface(name
);
766 fprintf(stderr
, "failed to allocate netlink message\n");
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);
778 genlmsg_put(msg
, 0, 0, nl_state
.nl80211_id
, 0,
779 0, NL80211_CMD_SET_WIPHY
, 0);
782 NLA_PUT_U32(msg
, NL80211_ATTR_IFINDEX
, devidx
);
783 NLA_PUT_U32(msg
, NL80211_ATTR_WIPHY_FREQ
, freq
);
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
);
792 case WS80211_CHAN_HT20
:
793 NLA_PUT_U32(msg
, NL80211_ATTR_WIPHY_CHANNEL_TYPE
, NL80211_CHAN_HT20
);
796 case WS80211_CHAN_HT40MINUS
:
797 NLA_PUT_U32(msg
, NL80211_ATTR_WIPHY_CHANNEL_TYPE
, NL80211_CHAN_HT40MINUS
);
800 case WS80211_CHAN_HT40PLUS
:
801 NLA_PUT_U32(msg
, NL80211_ATTR_WIPHY_CHANNEL_TYPE
, NL80211_CHAN_HT40PLUS
);
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
);
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
);
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
);
824 err
= nl80211_do_cmd(msg
, cb
);
830 fprintf(stderr
, "building message failed\n");
835 GArray
* ws80211_find_interfaces(void)
839 if (!nl_state
.nl_sock
)
842 interfaces
= g_array_new(false, false, sizeof(struct ws80211_interface
*));
846 if (ws80211_populate_devices(interfaces
)) {
847 ws80211_free_interfaces(interfaces
);
854 ws80211_str_to_chan_type(const char *s
)
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
;
879 *ws80211_chan_type_to_str(int type
)
882 case WS80211_CHAN_NO_HT
:
884 case WS80211_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
:
892 case WS80211_CHAN_VHT80P80
:
893 return CHAN_VHT80P80
;
894 case WS80211_CHAN_VHT160
:
900 bool ws80211_has_fcs_filter(void)
905 int ws80211_set_fcs_validation(const char *name _U_
, enum ws80211_fcs_validation fcs_validation _U_
)
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
;
918 #else /* Everyone else. */
919 int ws80211_init(void)
921 return WS80211_INIT_NOT_SUPPORTED
;
924 GArray
* ws80211_find_interfaces(void)
929 int ws80211_get_iface_info(const char *name _U_
, struct ws80211_iface_info
*iface_info _U_
)
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
)
939 int ws80211_str_to_chan_type(const char *s _U_
)
944 const char *ws80211_chan_type_to_str(int type _U_
)
949 bool ws80211_has_fcs_filter(void)
954 int ws80211_set_fcs_validation(const char *name _U_
, enum ws80211_fcs_validation fcs_validation _U_
)
959 const char *ws80211_get_helper_path(void) {
963 #endif /* HAVE_LIBNL && HAVE_NL80211 */
965 /* Common to everyone */
967 void ws80211_free_interfaces(GArray
*interfaces
)
969 struct ws80211_interface
*iface
;
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
);
981 g_array_free(interfaces
, true);
985 * Editor modelines - https://www.wireshark.org/tools/modelines.html
990 * indent-tabs-mode: t
993 * vi: set shiftwidth=8 tabstop=8 noexpandtab:
994 * :indentSize=8:tabSize=8:noTabs=false: