MSWSP: PropSpec: fix stringlen for PRSPEC_LPWSTR case
[wireshark-wip.git] / ws80211_utils.c
blob2137184b2b51e9a82eb012340e8347caac7eb58e
1 /*
2 * ws80211 utilities
3 * Copyright 2012, Pontus Fuchs <pontus.fuchs@gmail.com>
5 $Id$
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.
27 #include "config.h"
29 #include <stdio.h>
31 #include <glib.h>
32 #include <glib/gstdio.h>
34 #include "ws80211_utils.h"
36 #if defined(HAVE_LIBNL) && defined(HAVE_NL80211)
37 #include <string.h>
38 #include <errno.h>
39 #include <unistd.h>
41 #include <net/if.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 */
53 #ifdef HAVE_LIBNL1
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)
62 nl_handle_destroy(h);
64 #endif /* HAVE_LIBNL1 */
66 struct nl80211_state {
67 struct nl_sock *nl_sock;
68 int nl80211_id;
71 static struct nl80211_state nl_state;
73 int ws80211_init(void)
75 int err;
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");
82 return -ENOMEM;
85 if (genl_connect(state->nl_sock)) {
86 fprintf(stderr, "Failed to connect to generic netlink.\n");
87 err = -ENOLINK;
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");
94 err = -ENOENT;
95 goto out_handle_destroy;
98 return 0;
100 out_handle_destroy:
101 nl_socket_free(state->nl_sock);
102 state->nl_sock = 0;
103 return err;
106 static int error_handler(struct sockaddr_nl *nla _U_, struct nlmsgerr *err,
107 void *arg)
109 int *ret = (int *)arg;
110 *ret = err->error;
111 return NL_STOP;
114 static int finish_handler(struct nl_msg *msg _U_, void *arg)
116 int *ret = (int *)arg;
117 *ret = 0;
118 return NL_SKIP;
121 static int ack_handler(struct nl_msg *msg _U_, void *arg)
123 int *ret = (int *)arg;
124 *ret = 0;
125 return NL_STOP;
128 static int nl80211_do_cmd(struct nl_msg *msg, struct nl_cb *cb)
130 volatile int err;
132 if (!nl_state.nl_sock)
133 return -ENOLINK;
135 err = nl_send_auto_complete(nl_state.nl_sock, msg);
136 if (err < 0)
137 goto out;
139 err = 1;
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);
145 while (err > 0)
146 nl_recvmsgs(nl_state.nl_sock, cb);
147 out:
148 nl_cb_put(cb);
150 return err;
153 struct nliface_cookie
155 char *ifname;
156 GArray *interfaces;
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;
203 int bandidx = 1;
204 int rem_band, rem_freq, rem_mode;
205 struct ws80211_interface *iface;
206 int cap_monitor = 0;
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])
212 return NL_SKIP;
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)
217 cap_monitor = 1;
220 if (!cap_monitor)
221 return NL_SKIP;
223 iface = (struct ws80211_interface *)g_malloc0(sizeof(*iface));
224 if (!iface)
225 return NL_SKIP;
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) {
236 bandidx++;
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]) {
244 gboolean ht40;
245 iface->channel_types |= 1 << WS80211_CHAN_HT20;
246 ht40 = !!(nla_get_u16(tb_band[NL80211_BAND_ATTR_HT_CAPA]) & 0x02);
247 if (ht40) {
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) {
255 uint32_t 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])
260 continue;
261 if (tb_freq[NL80211_FREQUENCY_ATTR_DISABLED])
262 continue;
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]) {
272 int cmd;
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;
279 #else
280 iface->can_set_freq = TRUE;
281 #endif
282 g_array_append_val(cookie->interfaces, iface);
284 return NL_SKIP;
288 static int ws80211_get_phys(GArray *interfaces)
290 struct nliface_cookie cookie;
291 struct nl_msg *msg;
292 struct nl_cb *cb;
293 msg = nlmsg_alloc();
294 if (!msg) {
295 fprintf(stderr, "failed to allocate netlink message\n");
296 return 2;
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)
314 int fd;
315 int ret = -1;
316 /* Ugly hack to avoid incuding wireless.h */
317 struct {
318 char name1[IFNAMSIZ];
319 __s32 m;
320 __s16 e;
321 __u8 i;
322 __u8 flags;
323 } wrq;
325 fd = socket(AF_INET, SOCK_DGRAM, 0);
326 if (fd == -1)
327 return -1;
329 g_strlcpy(wrq.name1, ifname, IFNAMSIZ);
330 /* SIOCGIWFREQ */
331 if (ioctl(fd, 0x8B05, &wrq) == 0) {
332 if (wrq.e == 6)
333 ret = wrq.m;
335 close(fd);
336 return ret;
339 struct __iface_info
341 struct ws80211_iface_info *pub;
342 int type;
343 int phyidx;
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;
371 break;
373 case NL80211_CHAN_HT20:
374 iface_info->pub->current_chan_type = WS80211_CHAN_HT20;
375 break;
377 case NL80211_CHAN_HT40MINUS:
378 iface_info->pub->current_chan_type = WS80211_CHAN_HT40MINUS;
379 break;
381 case NL80211_CHAN_HT40PLUS:
382 iface_info->pub->current_chan_type = WS80211_CHAN_HT40PLUS;
383 break;
388 return NL_SKIP;
392 static int __ws80211_get_iface_info(const char *name, struct __iface_info *iface_info)
394 int devidx;
395 struct nl_msg *msg;
396 struct nl_cb *cb;
397 msg = nlmsg_alloc();
398 if (!msg) {
399 fprintf(stderr, "failed to allocate netlink message\n");
400 return 2;
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))
414 return -1;
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);
419 return 0;
421 nla_put_failure:
422 fprintf(stderr, "building message failed\n");
423 return -1;
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)
442 FILE *fh;
443 char line[200];
444 char *t;
445 gchar *t2;
446 char *ret;
447 int i;
448 unsigned int j;
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");
458 if(!fh) {
459 fprintf(stderr, "Cannot open /proc/net/dev");
460 return -ENOENT;
463 /* Skip the first two lines */
464 for (i = 0; i < 2; i++) {
465 ret = fgets(line, sizeof(line), fh);
466 if (ret == NULL) {
467 fprintf(stderr, "Error parsing /proc/net/dev");
468 fclose(fh);
469 return -1;
473 /* Update names of user created monitor interfaces */
474 while(fgets(line, sizeof(line), fh)) {
475 t = index(line, ':');
476 if (!t)
477 continue;
478 *t = 0;
479 t = line;
480 while (*t && *t == ' ')
481 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);
490 if (t2) {
491 if (!strcmp(t2, iface->ifname)) {
492 g_free(iface->ifname);
493 iface->ifname = g_strdup(t);
495 g_free(t2);
500 fclose(fh);
501 return 0;
504 static int ws80211_iface_up(const char *ifname)
506 int sock;
507 struct ifreq ifreq;
509 sock = socket(AF_PACKET, SOCK_RAW, 0);
510 if (sock == -1)
511 return -1;
513 g_strlcpy(ifreq.ifr_name, ifname, sizeof(ifreq.ifr_name));
515 if (ioctl(sock, SIOCGIFFLAGS, &ifreq))
516 goto out_err;
518 ifreq.ifr_flags |= IFF_UP;
520 if (ioctl(sock, SIOCSIFFLAGS, &ifreq))
521 goto out_err;
523 close(sock);
524 return 0;
526 out_err:
527 close(sock);
528 return -1;
531 static int ws80211_create_on_demand_interface(const char *name)
533 int devidx, phyidx, err;
534 struct nl_msg *msg;
535 struct nl_cb *cb;
537 devidx = if_nametoindex(name);
538 if (devidx)
539 return ws80211_iface_up(name);
541 if (sscanf(name, "phy%d.mon", &phyidx) != 1)
542 return -EINVAL;
544 cb = nl_cb_alloc(NL_CB_DEFAULT);
545 msg = nlmsg_alloc();
546 if (!msg) {
547 fprintf(stderr, "failed to allocate netlink message\n");
548 return 2;
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);
559 if (err)
560 return err;
561 return ws80211_iface_up(name);
563 nla_put_failure:
564 fprintf(stderr, "building message failed\n");
565 return 2;
568 int ws80211_set_freq(const char *name, int freq, int chan_type)
570 int devidx, err;
571 struct nl_msg *msg;
572 struct nl_cb *cb;
574 err = ws80211_create_on_demand_interface(name);
575 if (err)
576 return err;
578 msg = nlmsg_alloc();
579 if (!msg) {
580 fprintf(stderr, "failed to allocate netlink message\n");
581 return 2;
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);
591 #else
592 genlmsg_put(msg, 0, 0, nl_state.nl80211_id, 0,
593 0, NL80211_CMD_SET_WIPHY, 0);
594 #endif
596 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, devidx);
597 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, freq);
599 switch (chan_type) {
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);
604 break;
606 case WS80211_CHAN_HT20:
607 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE, NL80211_CHAN_HT20);
608 break;
610 case WS80211_CHAN_HT40MINUS:
611 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE, NL80211_CHAN_HT40MINUS);
612 break;
614 case WS80211_CHAN_HT40PLUS:
615 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE, NL80211_CHAN_HT40PLUS);
616 break;
617 #endif
619 default:
620 break;
622 err = nl80211_do_cmd(msg, cb);
623 return err;
625 nla_put_failure:
626 fprintf(stderr, "building message failed\n");
627 return 2;
631 void ws80211_free_interfaces(GArray *interfaces)
633 struct ws80211_interface *iface;
635 if (!interfaces)
636 return;
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);
643 g_free(iface);
645 g_array_free(interfaces, TRUE);
648 GArray* ws80211_find_interfaces(void)
650 GArray *interfaces;
652 if (!nl_state.nl_sock)
653 return NULL;
655 interfaces = g_array_new(FALSE, FALSE, sizeof(struct ws80211_interface *));
656 if (!interfaces)
657 return NULL;
659 if (ws80211_populate_devices(interfaces)) {
660 ws80211_free_interfaces(interfaces);
661 return NULL;
663 return interfaces;
666 int ws80211_frequency_to_channel(int freq)
668 if (freq == 2484)
669 return 14;
671 if (freq < 2484)
672 return (freq - 2407) / 5;
674 return freq / 5 - 1000;
678 ws80211_str_to_chan_type(const gchar *s)
680 int ret = -1;
681 if (!s)
682 return -1;
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;
692 return ret;
695 const gchar
696 *ws80211_chan_type_to_str(int type)
698 switch (type) {
699 case WS80211_CHAN_NO_HT:
700 return CHAN_NO_HT;
701 case WS80211_CHAN_HT20:
702 return CHAN_HT20;
703 case WS80211_CHAN_HT40MINUS:
704 return CHAN_HT40MINUS;
705 case WS80211_CHAN_HT40PLUS:
706 return CHAN_HT40PLUS;
708 return NULL;
711 #else /* HAVE_LIBNL */
712 int ws80211_init(void)
714 return -1;
717 GArray* ws80211_find_interfaces(void)
719 return NULL;
722 int ws80211_get_iface_info(const char *name _U_, struct ws80211_iface_info *iface_info _U_)
724 return -1;
727 void ws80211_free_interfaces(GArray *interfaces _U_)
731 int ws80211_frequency_to_channel(int freq _U_)
733 return -1;
736 int ws80211_set_freq(const char *name _U_, int freq _U_, int chan_type _U_)
738 return -1;
741 int ws80211_str_to_chan_type(const gchar *s _U_)
743 return -1;
746 const gchar *ws80211_chan_type_to_str(int type _U_)
748 return NULL;
750 #endif /* HAVE_LIBNL && HAVE_NL80211 */