ICMP(v4): Remove proto_tree_add_text
[metze/wireshark/wip.git] / caputils / ws80211_utils.c
1 /*
2  * ws80211 utilities
3  * Copyright 2012, Pontus Fuchs <pontus.fuchs@gmail.com>
4
5 Parts of this file was copied from iw:
6
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
11
12 Permission to use, copy, modify, and/or distribute this software for any
13 purpose with or without fee is hereby granted, provided that the above
14 copyright notice and this permission notice appear in all copies.
15
16 THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
17 WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
18 MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
19 ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
20 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
21 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
22 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
23 */
24
25 #include "config.h"
26
27 #include <stdio.h>
28
29 #include <glib.h>
30 #include <glib/gstdio.h>
31
32 #include "ws80211_utils.h"
33 #include "wsutil/ws_diag_control.h"
34
35 #if defined(HAVE_LIBNL) && defined(HAVE_NL80211)
36 #include <string.h>
37 #include <errno.h>
38 #include <unistd.h>
39
40 #include <net/if.h>
41 #include <sys/ioctl.h>
42
43 DIAG_OFF(pedantic)
44 #include <netlink/genl/genl.h>
45 DIAG_ON(pedantic)
46 #include <netlink/genl/family.h>
47 #include <netlink/genl/ctrl.h>
48 DIAG_OFF(pedantic)
49 #include <netlink/msg.h>
50 DIAG_ON(pedantic)
51 #include <netlink/attr.h>
52
53 #include <linux/nl80211.h>
54
55 #ifdef HAVE_NL80211_SPLIT_WIPHY_DUMP
56 static int ws80211_get_protocol_features(int* features);
57 #endif /* HAVE_NL80211_SPLIT_WIPHY_DUMP */
58
59 /* libnl 1.x compatibility code */
60 #ifdef HAVE_LIBNL1
61 #define nl_sock nl_handle
62 static inline struct nl_handle *nl_socket_alloc(void)
63 {
64         return nl_handle_alloc();
65 }
66
67 static inline void nl_socket_free(struct nl_sock *h)
68 {
69         nl_handle_destroy(h);
70 }
71 #endif /* HAVE_LIBNL1 */
72
73 struct nl80211_state {
74         struct nl_sock *nl_sock;
75         int nl80211_id;
76         int have_split_wiphy;
77 };
78
79 static struct nl80211_state nl_state;
80
81 int ws80211_init(void)
82 {
83         int err;
84 #ifdef HAVE_NL80211_SPLIT_WIPHY_DUMP
85         int features = 0;
86 #endif /* HAVE_NL80211_SPLIT_WIPHY_DUMP */
87
88         struct nl80211_state *state = &nl_state;
89
90         state->nl_sock = nl_socket_alloc();
91         if (!state->nl_sock) {
92                 fprintf(stderr, "Failed to allocate netlink socket.\n");
93                 return -ENOMEM;
94         }
95
96         if (genl_connect(state->nl_sock)) {
97                 fprintf(stderr, "Failed to connect to generic netlink.\n");
98                 err = -ENOLINK;
99                 goto out_handle_destroy;
100         }
101
102         state->nl80211_id = genl_ctrl_resolve(state->nl_sock, "nl80211");
103         if (state->nl80211_id < 0) {
104                 fprintf(stderr, "nl80211 not found.\n");
105                 err = -ENOENT;
106                 goto out_handle_destroy;
107         }
108 #ifdef HAVE_NL80211_SPLIT_WIPHY_DUMP
109         ws80211_get_protocol_features(&features);
110         if (features & NL80211_PROTOCOL_FEATURE_SPLIT_WIPHY_DUMP)
111                 state->have_split_wiphy = TRUE;
112 #endif /* HAVE_NL80211_SPLIT_WIPHY_DUMP */
113
114         return 0;
115
116  out_handle_destroy:
117         nl_socket_free(state->nl_sock);
118         state->nl_sock = 0;
119         return err;
120 }
121
122 static int error_handler(struct sockaddr_nl *nla _U_, struct nlmsgerr *err,
123                          void *arg)
124 {
125         int *ret = (int *)arg;
126         *ret = err->error;
127         return NL_STOP;
128 }
129
130 static int finish_handler(struct nl_msg *msg _U_, void *arg)
131 {
132         int *ret = (int *)arg;
133         *ret = 0;
134         return NL_SKIP;
135 }
136
137 static int ack_handler(struct nl_msg *msg _U_, void *arg)
138 {
139         int *ret = (int *)arg;
140         *ret = 0;
141         return NL_STOP;
142 }
143
144 static int nl80211_do_cmd(struct nl_msg *msg, struct nl_cb *cb)
145 {
146         volatile int err;
147
148         if (!nl_state.nl_sock)
149                 return -ENOLINK;
150
151         err = nl_send_auto_complete(nl_state.nl_sock, msg);
152         if (err < 0)
153                 goto out;
154
155         err = 1;
156
157         nl_cb_err(cb, NL_CB_CUSTOM, error_handler, (void *)&err);
158         nl_cb_set(cb, NL_CB_FINISH, NL_CB_CUSTOM, finish_handler, (void *)&err);
159         nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, ack_handler, (void *)&err);
160
161         while (err > 0)
162                 nl_recvmsgs(nl_state.nl_sock, cb);
163  out:
164         nl_cb_put(cb);
165
166         return err;
167 }
168
169 struct nliface_cookie
170 {
171         char *ifname;
172         GArray *interfaces;
173 };
174
175 static struct ws80211_interface *
176         get_interface_by_name(GArray *interfaces,
177                               char* ifname)
178 {
179         unsigned int i;
180         struct ws80211_interface *iface;
181
182         for (i = 0; i < interfaces->len; i++) {
183                 iface = g_array_index(interfaces, struct ws80211_interface *, i);
184                 if (!strcmp(iface->ifname, ifname))
185                         return iface;
186         }
187         return NULL;
188 }
189
190 /*
191  * And now for a steaming heap of suck.
192  *
193  * The nla_for_each_nested() macro defined by at least some versions of the
194  * Linux kernel's headers doesn't do the casting required when compiling
195  * with a C++ compiler or with -Wc++-compat, so we get warnings, and those
196  * warnings are fatal when we compile this file.
197  *
198  * So we replace it with our own version, which does the requisite cast.
199  */
200
201 /**
202  * nla_for_each_nested - iterate over nested attributes
203  * @pos: loop counter, set to current attribute
204  * @nla: attribute containing the nested attributes
205  * @rem: initialized to len, holds bytes currently remaining in stream
206  */
207 #undef nla_for_each_nested
208 #define nla_for_each_nested(pos, nla, rem) \
209         nla_for_each_attr(pos, (struct nlattr *)nla_data(nla), nla_len(nla), rem)
210
211 #ifdef HAVE_NL80211_SPLIT_WIPHY_DUMP
212 static int get_features_handler(struct nl_msg *msg, void *arg)
213 {
214         int *feat = (int*) arg;
215         struct nlattr *tb_msg[NL80211_ATTR_MAX + 1];
216         struct genlmsghdr *gnlh = (struct genlmsghdr *)nlmsg_data(nlmsg_hdr(msg));
217
218         nla_parse(tb_msg, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
219                   genlmsg_attrlen(gnlh, 0), NULL);
220
221         if (tb_msg[NL80211_ATTR_PROTOCOL_FEATURES])
222                 *feat = nla_get_u32(tb_msg[NL80211_ATTR_PROTOCOL_FEATURES]);
223
224         return NL_SKIP;
225 }
226
227 static int ws80211_get_protocol_features(int* features)
228 {
229         struct nl_msg *msg;
230         struct nl_cb *cb;
231
232         msg = nlmsg_alloc();
233         if (!msg) {
234                 fprintf(stderr, "failed to allocate netlink message\n");
235                 return 2;
236         }
237
238         cb = nl_cb_alloc(NL_CB_DEFAULT);
239
240         genlmsg_put(msg, 0, 0, nl_state.nl80211_id, 0, 0,
241                     NL80211_CMD_GET_PROTOCOL_FEATURES, 0);
242
243         nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, get_features_handler, features);
244
245         return nl80211_do_cmd(msg, cb);
246 }
247 #endif /* HAVE_NL80211_SPLIT_WIPHY_DUMP */
248
249 #ifdef NL80211_BAND_ATTR_HT_CAPA
250 static void parse_band_ht_capa(struct ws80211_interface *iface,
251                                struct nlattr *tb)
252 {
253         gboolean ht40;
254
255         if (!tb) return;
256
257         iface->channel_types |= 1 << WS80211_CHAN_HT20;
258         ht40 = !!(nla_get_u16(tb) & 0x02);
259         if (ht40) {
260                 iface->channel_types |= 1 << WS80211_CHAN_HT40MINUS;
261                 iface->channel_types |= 1 << WS80211_CHAN_HT40PLUS;
262         }
263 }
264 #endif /* NL80211_BAND_ATTR_HT_CAPA */
265
266 static void parse_supported_iftypes(struct ws80211_interface *iface,
267                                     struct nlattr *tb)
268 {
269         struct nlattr *nl_mode;
270         int rem_mode;
271
272         if (!tb) return;
273
274         nla_for_each_nested(nl_mode, tb, rem_mode) {
275                 if (nla_type(nl_mode) == NL80211_IFTYPE_MONITOR)
276                         iface->cap_monitor = 1;
277         }
278 }
279
280 static void parse_band_freqs(struct ws80211_interface *iface,
281                              struct nlattr *tb)
282 {
283         struct nlattr *nl_freq;
284         struct nlattr *tb_freq[NL80211_FREQUENCY_ATTR_MAX + 1];
285         static struct nla_policy freq_policy[NL80211_FREQUENCY_ATTR_MAX + 1] = {
286                 {NLA_UNSPEC, 0, 0},             /* __NL80211_FREQUENCY_ATTR_INVALID */
287                 {NLA_U32, 0, 0},                /* NL80211_FREQUENCY_ATTR_FREQ */
288                 {NLA_FLAG, 0, 0},               /* NL80211_FREQUENCY_ATTR_DISABLED */
289                 {NLA_FLAG, 0, 0},               /* NL80211_FREQUENCY_ATTR_PASSIVE_SCAN */
290                 {NLA_FLAG, 0, 0},               /* NL80211_FREQUENCY_ATTR_NO_IBSS */
291                 {NLA_FLAG, 0, 0},               /* NL80211_FREQUENCY_ATTR_RADAR */
292                 {NLA_U32, 0, 0}                 /* NL80211_FREQUENCY_ATTR_MAX_TX_POWER */
293         };
294         int rem_freq;
295
296         if (!tb) return;
297
298         nla_for_each_nested(nl_freq, tb, rem_freq) {
299                 uint32_t freq;
300                 nla_parse(tb_freq, NL80211_FREQUENCY_ATTR_MAX,
301                           (struct nlattr *)nla_data(nl_freq),
302                           nla_len(nl_freq), freq_policy);
303                 if (!tb_freq[NL80211_FREQUENCY_ATTR_FREQ])
304                         continue;
305                 if (tb_freq[NL80211_FREQUENCY_ATTR_DISABLED])
306                         continue;
307
308                 freq = nla_get_u32(tb_freq[NL80211_FREQUENCY_ATTR_FREQ]);
309                 g_array_append_val(iface->frequencies, freq);
310         }
311 }
312
313 static void parse_wiphy_bands(struct ws80211_interface *iface,
314                              struct nlattr *tb)
315 {
316         struct nlattr *nl_band;
317         struct nlattr *tb_band[NL80211_BAND_ATTR_MAX + 1];
318         int bandidx = 1;
319         int rem_band;
320
321         if (!tb) return;
322
323         nla_for_each_nested(nl_band, tb, rem_band) {
324                 bandidx++;
325
326                 nla_parse(tb_band, NL80211_BAND_ATTR_MAX,
327                           (struct nlattr *)nla_data(nl_band),
328                           nla_len(nl_band), NULL);
329
330 #ifdef NL80211_BAND_ATTR_HT_CAPA
331                 parse_band_ht_capa(iface, tb_band[NL80211_BAND_ATTR_HT_CAPA]);
332 #endif /* NL80211_BAND_ATTR_HT_CAPA */
333                 parse_band_freqs(iface, tb_band[NL80211_BAND_ATTR_FREQS]);
334         }
335 }
336
337 static void parse_supported_commands(struct ws80211_interface *iface,
338                                      struct nlattr *tb)
339 {
340         /* Can frequency be set? Only newer versions of cfg80211 supports this */
341 #ifdef HAVE_NL80211_CMD_SET_CHANNEL
342         int cmd;
343         struct nlattr *nl_cmd;
344
345         if (!tb) return;
346
347         nla_for_each_nested(nl_cmd, tb, cmd) {
348                 if(nla_get_u32(nl_cmd) == NL80211_CMD_SET_CHANNEL)
349                         iface->can_set_freq = TRUE;
350         }
351 #else
352         iface->can_set_freq = TRUE;
353 #endif
354 }
355
356 static int get_phys_handler(struct nl_msg *msg, void *arg)
357 {
358         struct nlattr *tb_msg[NL80211_ATTR_MAX + 1];
359         struct genlmsghdr *gnlh = (struct genlmsghdr *)nlmsg_data(nlmsg_hdr(msg));
360
361         struct nliface_cookie *cookie = (struct nliface_cookie *)arg;
362
363         struct ws80211_interface *iface;
364         char* ifname;
365         int added = 0;
366
367         nla_parse(tb_msg, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
368                   genlmsg_attrlen(gnlh, 0), NULL);
369
370         if (!tb_msg[NL80211_ATTR_WIPHY_NAME])
371                 return NL_SKIP;
372
373         ifname = g_strdup_printf("%s.mon", nla_get_string(tb_msg[NL80211_ATTR_WIPHY_NAME]));
374         iface = get_interface_by_name(cookie->interfaces, ifname);
375
376         if (!iface) {
377                 iface = (struct ws80211_interface *)g_malloc0(sizeof(*iface));
378                 if (!iface) {
379                         g_free(ifname);
380                         return NL_SKIP;
381                 }
382                 added = 1;
383                 iface->ifname = ifname;
384                 iface->frequencies = g_array_new(FALSE, FALSE, sizeof(int));
385                 iface->channel_types = 1 << WS80211_CHAN_NO_HT;
386         } else {
387                 g_free(ifname);
388         }
389
390         parse_supported_iftypes(iface, tb_msg[NL80211_ATTR_SUPPORTED_IFTYPES]);
391         parse_wiphy_bands(iface, tb_msg[NL80211_ATTR_WIPHY_BANDS]);
392         parse_supported_commands(iface, tb_msg[NL80211_ATTR_SUPPORTED_COMMANDS]);
393
394         if (added)
395                 g_array_append_val(cookie->interfaces, iface);
396
397         return NL_SKIP;
398 }
399
400 static int ws80211_get_phys(GArray *interfaces)
401 {
402         struct nliface_cookie cookie;
403         struct nl_msg *msg;
404         struct nl_cb *cb;
405         msg = nlmsg_alloc();
406         if (!msg) {
407                 fprintf(stderr, "failed to allocate netlink message\n");
408                 return 2;
409         }
410
411         cb = nl_cb_alloc(NL_CB_DEFAULT);
412
413         cookie.interfaces = interfaces;
414
415         genlmsg_put(msg, 0, 0, nl_state.nl80211_id, 0,
416                     NLM_F_DUMP, NL80211_CMD_GET_WIPHY, 0);
417
418 #ifdef HAVE_NL80211_SPLIT_WIPHY_DUMP
419         if (nl_state.have_split_wiphy) {
420                 NLA_PUT_FLAG(msg, NL80211_ATTR_SPLIT_WIPHY_DUMP);
421         }
422 #endif /* #ifdef HAVE_NL80211_SPLIT_WIPHY_DUMP */
423         nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, get_phys_handler, &cookie);
424
425         return nl80211_do_cmd(msg, cb);
426
427 #ifdef HAVE_NL80211_SPLIT_WIPHY_DUMP
428 nla_put_failure:
429         fprintf(stderr, "building message failed\n");
430         return -1;
431 #endif /* HAVE_NL80211_SPLIT_WIPHY_DUMP */
432 }
433
434 static int get_freq_wext(const char *ifname)
435 {
436         int fd;
437         int ret = -1;
438         /* Ugly hack to avoid including wireless.h */
439         struct {
440                 char name1[IFNAMSIZ];
441                 __s32 m;
442                 __s16 e;
443                 __u8 i;
444                 __u8 flags;
445         } wrq;
446
447         fd = socket(AF_INET, SOCK_DGRAM, 0);
448         if (fd == -1)
449                 return -1;
450
451         g_strlcpy(wrq.name1, ifname, IFNAMSIZ);
452         /* SIOCGIWFREQ */
453         if (ioctl(fd, 0x8B05, &wrq) == 0) {
454                 if (wrq.e == 6)
455                         ret = wrq.m;
456         }
457         close(fd);
458         return ret;
459 }
460
461 struct __iface_info
462 {
463         struct ws80211_iface_info *pub;
464         int type;
465         int phyidx;
466 };
467
468 static int get_iface_info_handler(struct nl_msg *msg, void *arg)
469 {
470         struct genlmsghdr *gnlh = (struct genlmsghdr *)nlmsg_data(nlmsg_hdr(msg));
471         struct nlattr *tb_msg[NL80211_ATTR_MAX + 1];
472         struct __iface_info *iface_info = (struct __iface_info *)arg;
473
474         nla_parse(tb_msg, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
475                   genlmsg_attrlen(gnlh, 0), NULL);
476
477         if (tb_msg[NL80211_ATTR_IFTYPE]) {
478                 iface_info->type = nla_get_u32(tb_msg[NL80211_ATTR_IFTYPE]);
479         }
480         if (tb_msg[NL80211_ATTR_WIPHY]) {
481                 iface_info->phyidx = nla_get_u32(tb_msg[NL80211_ATTR_WIPHY]);
482         }
483
484         if (tb_msg[NL80211_ATTR_WIPHY_FREQ]) {
485                 iface_info->pub->current_freq = nla_get_u32(tb_msg[NL80211_ATTR_WIPHY_FREQ]);
486                 iface_info->pub->current_chan_type = WS80211_CHAN_NO_HT;
487
488                 if (tb_msg[NL80211_ATTR_WIPHY_CHANNEL_TYPE]) {
489                         switch (nla_get_u32(tb_msg[NL80211_ATTR_WIPHY_CHANNEL_TYPE])) {
490
491                         case NL80211_CHAN_NO_HT:
492                                 iface_info->pub->current_chan_type = WS80211_CHAN_NO_HT;
493                                 break;
494
495                         case NL80211_CHAN_HT20:
496                                 iface_info->pub->current_chan_type = WS80211_CHAN_HT20;
497                                 break;
498
499                         case NL80211_CHAN_HT40MINUS:
500                                 iface_info->pub->current_chan_type = WS80211_CHAN_HT40MINUS;
501                                 break;
502
503                         case NL80211_CHAN_HT40PLUS:
504                                 iface_info->pub->current_chan_type = WS80211_CHAN_HT40PLUS;
505                                 break;
506                         }
507                 }
508
509         }
510         return NL_SKIP;
511 }
512
513
514 static int __ws80211_get_iface_info(const char *name, struct __iface_info *iface_info)
515 {
516         int devidx;
517         struct nl_msg *msg;
518         struct nl_cb *cb;
519         msg = nlmsg_alloc();
520         if (!msg) {
521                 fprintf(stderr, "failed to allocate netlink message\n");
522                 return 2;
523         }
524
525         cb = nl_cb_alloc(NL_CB_DEFAULT);
526
527         devidx = if_nametoindex(name);
528
529         genlmsg_put(msg, 0, 0, nl_state.nl80211_id, 0,
530                     0, NL80211_CMD_GET_INTERFACE, 0);
531         NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, devidx);
532
533         nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, get_iface_info_handler, iface_info);
534
535         if (nl80211_do_cmd(msg, cb))
536                 return -1;
537
538         /* Old kernels can't get the current freq via netlink. Try WEXT too :( */
539         if (iface_info->pub->current_freq == -1)
540                 iface_info->pub->current_freq = get_freq_wext(name);
541         return 0;
542
543 nla_put_failure:
544         fprintf(stderr, "building message failed\n");
545         return -1;
546 }
547
548 int ws80211_get_iface_info(const char *name, struct ws80211_iface_info *iface_info)
549 {
550         struct __iface_info __iface_info;
551
552         memset(iface_info, 0, sizeof(*iface_info));
553         __iface_info.pub = iface_info;
554         __iface_info.type = -1;
555         __iface_info.phyidx= -1;
556         __iface_info.pub->current_freq = -1;
557         __iface_info.pub->current_chan_type = WS80211_CHAN_NO_HT;
558
559         return __ws80211_get_iface_info(name, &__iface_info);
560 }
561
562 static int ws80211_keep_only_monitor(GArray *interfaces)
563 {
564         unsigned int j;
565         struct ws80211_interface *iface;
566 restart:
567         for (j = 0; j < interfaces->len; j++) {
568                 iface = g_array_index(interfaces, struct ws80211_interface *, j);
569                 if (!iface->cap_monitor) {
570                         g_array_remove_index(interfaces, j);
571                         g_array_free(iface->frequencies, TRUE);
572                         g_free(iface->ifname);
573                         g_free(iface);
574                         goto restart;
575                 }
576         }
577         return 0;
578 }
579
580 static int ws80211_populate_devices(GArray *interfaces)
581 {
582         FILE *fh;
583         char line[200];
584         char *t;
585         gchar *t2;
586         char *ret;
587         int i;
588         unsigned int j;
589
590         struct ws80211_iface_info pub = {-1, WS80211_CHAN_NO_HT};
591         struct __iface_info iface_info;
592         struct ws80211_interface *iface;
593
594         /* Get a list of phy's that can handle monitor mode */
595         ws80211_get_phys(interfaces);
596         ws80211_keep_only_monitor(interfaces);
597
598         fh = g_fopen("/proc/net/dev", "r");
599         if(!fh) {
600                 fprintf(stderr, "Cannot open /proc/net/dev");
601                 return -ENOENT;
602         }
603
604         /* Skip the first two lines */
605         for (i = 0; i < 2; i++) {
606                 ret = fgets(line, sizeof(line), fh);
607                 if (ret == NULL) {
608                         fprintf(stderr, "Error parsing /proc/net/dev");
609                         fclose(fh);
610                         return -1;
611                 }
612         }
613
614         /* Update names of user created monitor interfaces */
615         while(fgets(line, sizeof(line), fh)) {
616                 t = index(line, ':');
617                 if (!t)
618                         continue;
619                 *t = 0;
620                 t = line;
621                 while (*t && *t == ' ')
622                         t++;
623                 memset(&iface_info, 0, sizeof(iface_info));
624                 iface_info.pub = &pub;
625                 __ws80211_get_iface_info(t, &iface_info);
626
627                 if (iface_info.type == NL80211_IFTYPE_MONITOR) {
628                         for (j = 0; j < interfaces->len; j++) {
629                                 iface = g_array_index(interfaces, struct ws80211_interface *, j);
630                                 t2 = g_strdup_printf("phy%d.mon", iface_info.phyidx);
631                                 if (t2) {
632                                         if (!strcmp(t2, iface->ifname)) {
633                                                 g_free(iface->ifname);
634                                                 iface->ifname = g_strdup(t);
635                                         }
636                                         g_free(t2);
637                                 }
638                         }
639                 }
640         }
641         fclose(fh);
642         return 0;
643 }
644
645 static int ws80211_iface_up(const char *ifname)
646 {
647         int sock;
648         struct ifreq ifreq;
649
650         sock = socket(AF_PACKET, SOCK_RAW, 0);
651         if (sock == -1)
652                 return -1;
653
654         g_strlcpy(ifreq.ifr_name, ifname, sizeof(ifreq.ifr_name));
655
656         if (ioctl(sock, SIOCGIFFLAGS, &ifreq))
657                 goto out_err;
658
659         ifreq.ifr_flags |= IFF_UP;
660
661         if (ioctl(sock, SIOCSIFFLAGS, &ifreq))
662                 goto out_err;
663
664         close(sock);
665         return 0;
666
667 out_err:
668         close(sock);
669         return -1;
670 }
671
672 static int ws80211_create_on_demand_interface(const char *name)
673 {
674         int devidx, phyidx, err;
675         struct nl_msg *msg;
676         struct nl_cb *cb;
677
678         devidx = if_nametoindex(name);
679         if (devidx)
680                 return ws80211_iface_up(name);
681
682         if (sscanf(name, "phy%d.mon", &phyidx) != 1)
683                 return -EINVAL;
684
685         cb = nl_cb_alloc(NL_CB_DEFAULT);
686         msg = nlmsg_alloc();
687         if (!msg) {
688                 fprintf(stderr, "failed to allocate netlink message\n");
689                 return 2;
690         }
691
692         genlmsg_put(msg, 0, 0, nl_state.nl80211_id, 0,
693                     0, NL80211_CMD_NEW_INTERFACE, 0);
694         NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, phyidx);
695
696         NLA_PUT_STRING(msg, NL80211_ATTR_IFNAME, name);
697         NLA_PUT_U32(msg, NL80211_ATTR_IFTYPE, NL80211_IFTYPE_MONITOR);
698
699         err = nl80211_do_cmd(msg, cb);
700         if (err)
701                 return err;
702         return ws80211_iface_up(name);
703
704 nla_put_failure:
705         fprintf(stderr, "building message failed\n");
706         return 2;
707 }
708
709 int ws80211_set_freq(const char *name, int freq, int chan_type)
710 {
711         int devidx, err;
712         struct nl_msg *msg;
713         struct nl_cb *cb;
714
715         err = ws80211_create_on_demand_interface(name);
716         if (err)
717                 return err;
718
719         msg = nlmsg_alloc();
720         if (!msg) {
721                 fprintf(stderr, "failed to allocate netlink message\n");
722                 return 2;
723         }
724
725         cb = nl_cb_alloc(NL_CB_DEFAULT);
726
727         devidx = if_nametoindex(name);
728
729 #ifdef HAVE_NL80211_CMD_SET_CHANNEL
730         genlmsg_put(msg, 0, 0, nl_state.nl80211_id, 0,
731                     0, NL80211_CMD_SET_CHANNEL, 0);
732 #else
733         genlmsg_put(msg, 0, 0, nl_state.nl80211_id, 0,
734                     0, NL80211_CMD_SET_WIPHY, 0);
735 #endif
736
737         NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, devidx);
738         NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, freq);
739
740         switch (chan_type) {
741
742 #ifdef NL80211_BAND_ATTR_HT_CAPA
743         case WS80211_CHAN_NO_HT:
744                 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE, NL80211_CHAN_NO_HT);
745                 break;
746
747         case WS80211_CHAN_HT20:
748                 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE, NL80211_CHAN_HT20);
749                 break;
750
751         case WS80211_CHAN_HT40MINUS:
752                 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE, NL80211_CHAN_HT40MINUS);
753                 break;
754
755         case WS80211_CHAN_HT40PLUS:
756                 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE, NL80211_CHAN_HT40PLUS);
757                 break;
758 #endif
759
760         default:
761                 break;
762         }
763         err = nl80211_do_cmd(msg, cb);
764         return err;
765
766 nla_put_failure:
767         fprintf(stderr, "building message failed\n");
768         return 2;
769
770 }
771
772 void ws80211_free_interfaces(GArray *interfaces)
773 {
774         struct ws80211_interface *iface;
775
776         if (!interfaces)
777                 return;
778
779         while (interfaces->len) {
780                 iface = g_array_index(interfaces, struct ws80211_interface *, 0);
781                 g_array_remove_index(interfaces, 0);
782                 g_array_free(iface->frequencies, TRUE);
783                 g_free(iface->ifname);
784                 g_free(iface);
785         }
786         g_array_free(interfaces, TRUE);
787 }
788
789 GArray* ws80211_find_interfaces(void)
790 {
791         GArray *interfaces;
792
793         if (!nl_state.nl_sock)
794                 return NULL;
795
796         interfaces = g_array_new(FALSE, FALSE, sizeof(struct ws80211_interface *));
797         if (!interfaces)
798                 return NULL;
799
800         if (ws80211_populate_devices(interfaces)) {
801                 ws80211_free_interfaces(interfaces);
802                 return NULL;
803         }
804         return interfaces;
805 }
806
807 int ws80211_frequency_to_channel(int freq)
808 {
809         if (freq == 2484)
810                 return 14;
811
812         if (freq < 2484)
813                 return (freq - 2407) / 5;
814
815         return freq / 5 - 1000;
816 }
817
818 int
819 ws80211_str_to_chan_type(const gchar *s)
820 {
821         int ret = -1;
822         if (!s)
823                 return -1;
824
825         if (!strcmp(s, CHAN_NO_HT))
826                 ret = WS80211_CHAN_NO_HT;
827         if (!strcmp(s, CHAN_HT20))
828                 ret = WS80211_CHAN_HT20;
829         if (!strcmp(s, CHAN_HT40MINUS))
830                 ret = WS80211_CHAN_HT40MINUS;
831         if (!strcmp(s, CHAN_HT40PLUS))
832                 ret = WS80211_CHAN_HT40PLUS;
833         return ret;
834 }
835
836 const gchar
837 *ws80211_chan_type_to_str(int type)
838 {
839         switch (type) {
840         case WS80211_CHAN_NO_HT:
841                 return CHAN_NO_HT;
842         case WS80211_CHAN_HT20:
843                 return CHAN_HT20;
844         case WS80211_CHAN_HT40MINUS:
845                 return CHAN_HT40MINUS;
846         case WS80211_CHAN_HT40PLUS:
847                 return CHAN_HT40PLUS;
848         }
849         return NULL;
850 }
851
852 #else /* HAVE_LIBNL */
853 int ws80211_init(void)
854 {
855         return -1;
856 }
857
858 GArray* ws80211_find_interfaces(void)
859 {
860         return NULL;
861 }
862
863 int ws80211_get_iface_info(const char *name _U_, struct ws80211_iface_info *iface_info _U_)
864 {
865         return -1;
866 }
867
868 void ws80211_free_interfaces(GArray *interfaces _U_)
869 {
870 }
871
872 int ws80211_frequency_to_channel(int freq _U_)
873 {
874         return -1;
875 }
876
877 int ws80211_set_freq(const char *name _U_, int freq _U_, int chan_type _U_)
878 {
879         return -1;
880 }
881
882 int ws80211_str_to_chan_type(const gchar *s _U_)
883 {
884         return -1;
885 }
886
887 const gchar *ws80211_chan_type_to_str(int type _U_)
888 {
889         return NULL;
890 }
891 #endif /* HAVE_LIBNL && HAVE_NL80211 */
892
893 /*
894  * Editor modelines  -  http://www.wireshark.org/tools/modelines.html
895  *
896  * Local variables:
897  * c-basic-offset: 8
898  * tab-width: 8
899  * indent-tabs-mode: t
900  * End:
901  *
902  * vi: set shiftwidth=8 tabstop=8 noexpandtab:
903  * :indentSize=8:tabSize=8:noTabs=false:
904  */