A bunch of "{Mac} OS X" -> "macOS" changes.
[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
34 #if defined(HAVE_LIBNL) && defined(HAVE_NL80211)
35 #include <string.h>
36 #include <errno.h>
37 #include <unistd.h>
38
39 #include <net/if.h>
40 #include <sys/ioctl.h>
41
42 DIAG_OFF(pedantic)
43 #include <netlink/genl/genl.h>
44 DIAG_ON(pedantic)
45 #include <netlink/genl/family.h>
46 #include <netlink/genl/ctrl.h>
47 DIAG_OFF(pedantic)
48 #include <netlink/msg.h>
49 DIAG_ON(pedantic)
50 #include <netlink/attr.h>
51
52 #include <linux/nl80211.h>
53
54 #ifdef HAVE_NL80211_SPLIT_WIPHY_DUMP
55 static int ws80211_get_protocol_features(int* features);
56 #endif /* HAVE_NL80211_SPLIT_WIPHY_DUMP */
57
58 /* libnl 1.x compatibility code */
59 #ifdef HAVE_LIBNL1
60 #define nl_sock nl_handle
61 static inline struct nl_handle *nl_socket_alloc(void)
62 {
63         return nl_handle_alloc();
64 }
65
66 static inline void nl_socket_free(struct nl_sock *h)
67 {
68         nl_handle_destroy(h);
69 }
70 #endif /* HAVE_LIBNL1 */
71
72 struct nl80211_state {
73         struct nl_sock *nl_sock;
74         int nl80211_id;
75         int have_split_wiphy;
76 };
77
78 static struct nl80211_state nl_state;
79
80 int ws80211_init(void)
81 {
82         int err;
83 #ifdef HAVE_NL80211_SPLIT_WIPHY_DUMP
84         int features = 0;
85 #endif /* HAVE_NL80211_SPLIT_WIPHY_DUMP */
86
87         struct nl80211_state *state = &nl_state;
88
89         state->nl_sock = nl_socket_alloc();
90         if (!state->nl_sock) {
91                 fprintf(stderr, "Failed to allocate netlink socket.\n");
92                 return -ENOMEM;
93         }
94
95         if (genl_connect(state->nl_sock)) {
96                 fprintf(stderr, "Failed to connect to generic netlink.\n");
97                 err = -ENOLINK;
98                 goto out_handle_destroy;
99         }
100
101         state->nl80211_id = genl_ctrl_resolve(state->nl_sock, "nl80211");
102         if (state->nl80211_id < 0) {
103                 fprintf(stderr, "nl80211 not found.\n");
104                 err = -ENOENT;
105                 goto out_handle_destroy;
106         }
107 #ifdef HAVE_NL80211_SPLIT_WIPHY_DUMP
108         ws80211_get_protocol_features(&features);
109         if (features & NL80211_PROTOCOL_FEATURE_SPLIT_WIPHY_DUMP)
110                 state->have_split_wiphy = TRUE;
111 #endif /* HAVE_NL80211_SPLIT_WIPHY_DUMP */
112
113         return 0;
114
115  out_handle_destroy:
116         nl_socket_free(state->nl_sock);
117         state->nl_sock = 0;
118         return err;
119 }
120
121 static int error_handler(struct sockaddr_nl *nla _U_, struct nlmsgerr *err,
122                          void *arg)
123 {
124         int *ret = (int *)arg;
125         *ret = err->error;
126         return NL_STOP;
127 }
128
129 static int finish_handler(struct nl_msg *msg _U_, void *arg)
130 {
131         int *ret = (int *)arg;
132         *ret = 0;
133         return NL_SKIP;
134 }
135
136 static int ack_handler(struct nl_msg *msg _U_, void *arg)
137 {
138         int *ret = (int *)arg;
139         *ret = 0;
140         return NL_STOP;
141 }
142
143 static int nl80211_do_cmd(struct nl_msg *msg, struct nl_cb *cb)
144 {
145         volatile int err;
146
147         if (!nl_state.nl_sock)
148                 return -ENOLINK;
149
150         err = nl_send_auto_complete(nl_state.nl_sock, msg);
151         if (err < 0)
152                 goto out;
153
154         err = 1;
155
156         nl_cb_err(cb, NL_CB_CUSTOM, error_handler, (void *)&err);
157         nl_cb_set(cb, NL_CB_FINISH, NL_CB_CUSTOM, finish_handler, (void *)&err);
158         nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, ack_handler, (void *)&err);
159
160         while (err > 0)
161                 nl_recvmsgs(nl_state.nl_sock, cb);
162  out:
163         nl_cb_put(cb);
164
165         return err;
166 }
167
168 struct nliface_cookie
169 {
170         char *ifname;
171         GArray *interfaces;
172 };
173
174 static struct ws80211_interface *
175         get_interface_by_name(GArray *interfaces,
176                               char* ifname)
177 {
178         unsigned int i;
179         struct ws80211_interface *iface;
180
181         for (i = 0; i < interfaces->len; i++) {
182                 iface = g_array_index(interfaces, struct ws80211_interface *, i);
183                 if (!strcmp(iface->ifname, ifname))
184                         return iface;
185         }
186         return NULL;
187 }
188
189 /*
190  * And now for a steaming heap of suck.
191  *
192  * The nla_for_each_nested() macro defined by at least some versions of the
193  * Linux kernel's headers doesn't do the casting required when compiling
194  * with a C++ compiler or with -Wc++-compat, so we get warnings, and those
195  * warnings are fatal when we compile this file.
196  *
197  * So we replace it with our own version, which does the requisite cast.
198  */
199
200 /**
201  * nla_for_each_nested - iterate over nested attributes
202  * @pos: loop counter, set to current attribute
203  * @nla: attribute containing the nested attributes
204  * @rem: initialized to len, holds bytes currently remaining in stream
205  */
206 #undef nla_for_each_nested
207 #define nla_for_each_nested(pos, nla, rem) \
208         nla_for_each_attr(pos, (struct nlattr *)nla_data(nla), nla_len(nla), rem)
209
210 #ifdef HAVE_NL80211_SPLIT_WIPHY_DUMP
211 static int get_features_handler(struct nl_msg *msg, void *arg)
212 {
213         int *feat = (int*) arg;
214         struct nlattr *tb_msg[NL80211_ATTR_MAX + 1];
215         struct genlmsghdr *gnlh = (struct genlmsghdr *)nlmsg_data(nlmsg_hdr(msg));
216
217         nla_parse(tb_msg, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
218                   genlmsg_attrlen(gnlh, 0), NULL);
219
220         if (tb_msg[NL80211_ATTR_PROTOCOL_FEATURES])
221                 *feat = nla_get_u32(tb_msg[NL80211_ATTR_PROTOCOL_FEATURES]);
222
223         return NL_SKIP;
224 }
225
226 static int ws80211_get_protocol_features(int* features)
227 {
228         struct nl_msg *msg;
229         struct nl_cb *cb;
230         int ret;
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         ret = nl80211_do_cmd(msg, cb);
246         nlmsg_free(msg);
247         return ret;
248 }
249 #endif /* HAVE_NL80211_SPLIT_WIPHY_DUMP */
250
251 #ifdef NL80211_BAND_ATTR_HT_CAPA
252 static void parse_band_ht_capa(struct ws80211_interface *iface,
253                                struct nlattr *tb)
254 {
255         gboolean ht40;
256
257         if (!tb) return;
258
259         iface->channel_types |= 1 << WS80211_CHAN_HT20;
260         ht40 = !!(nla_get_u16(tb) & 0x02);
261         if (ht40) {
262                 iface->channel_types |= 1 << WS80211_CHAN_HT40MINUS;
263                 iface->channel_types |= 1 << WS80211_CHAN_HT40PLUS;
264         }
265 }
266 #endif /* NL80211_BAND_ATTR_HT_CAPA */
267
268 #ifdef HAVE_NL80211_VHT_CAPABILITY
269 static void parse_band_vht_capa(struct ws80211_interface *iface,
270                                 struct nlattr *tb)
271 {
272         guint32 chan_capa;
273         if (!tb) return;
274
275         chan_capa = (nla_get_u32(tb) >> 2) & 3;
276         if (chan_capa == 1) {
277                 iface->channel_types |= 1 << WS80211_CHAN_VHT160;
278         }
279         if (chan_capa == 2) {
280                 iface->channel_types |= 1 << WS80211_CHAN_VHT160;
281                 iface->channel_types |= 1 << WS80211_CHAN_VHT80P80;
282         }
283         iface->channel_types |= 1 << WS80211_CHAN_VHT80;
284 }
285 #endif /* HAVE_NL80211_VHT_CAPABILITY */
286
287 static void parse_supported_iftypes(struct ws80211_interface *iface,
288                                     struct nlattr *tb)
289 {
290         struct nlattr *nl_mode;
291         int rem_mode;
292
293         if (!tb) return;
294
295         nla_for_each_nested(nl_mode, tb, rem_mode) {
296                 if (nla_type(nl_mode) == NL80211_IFTYPE_MONITOR)
297                         iface->cap_monitor = 1;
298         }
299 }
300
301 static void parse_band_freqs(struct ws80211_interface *iface,
302                              struct nlattr *tb)
303 {
304         struct nlattr *nl_freq;
305         struct nlattr *tb_freq[NL80211_FREQUENCY_ATTR_MAX + 1];
306         static struct nla_policy freq_policy[NL80211_FREQUENCY_ATTR_MAX + 1] = {
307                 {NLA_UNSPEC, 0, 0},             /* __NL80211_FREQUENCY_ATTR_INVALID */
308                 {NLA_U32, 0, 0},                /* NL80211_FREQUENCY_ATTR_FREQ */
309                 {NLA_FLAG, 0, 0},               /* NL80211_FREQUENCY_ATTR_DISABLED */
310                 {NLA_FLAG, 0, 0},               /* NL80211_FREQUENCY_ATTR_PASSIVE_SCAN */
311                 {NLA_FLAG, 0, 0},               /* NL80211_FREQUENCY_ATTR_NO_IBSS */
312                 {NLA_FLAG, 0, 0},               /* NL80211_FREQUENCY_ATTR_RADAR */
313                 {NLA_U32, 0, 0}                 /* NL80211_FREQUENCY_ATTR_MAX_TX_POWER */
314         };
315         int rem_freq;
316
317         if (!tb) return;
318
319         nla_for_each_nested(nl_freq, tb, rem_freq) {
320                 uint32_t freq;
321                 nla_parse(tb_freq, NL80211_FREQUENCY_ATTR_MAX,
322                           (struct nlattr *)nla_data(nl_freq),
323                           nla_len(nl_freq), freq_policy);
324                 if (!tb_freq[NL80211_FREQUENCY_ATTR_FREQ])
325                         continue;
326                 if (tb_freq[NL80211_FREQUENCY_ATTR_DISABLED])
327                         continue;
328
329                 freq = nla_get_u32(tb_freq[NL80211_FREQUENCY_ATTR_FREQ]);
330                 g_array_append_val(iface->frequencies, freq);
331         }
332 }
333
334 static void parse_wiphy_bands(struct ws80211_interface *iface,
335                              struct nlattr *tb)
336 {
337         struct nlattr *nl_band;
338         struct nlattr *tb_band[NL80211_BAND_ATTR_MAX + 1];
339         int bandidx = 1;
340         int rem_band;
341
342         if (!tb) return;
343
344         nla_for_each_nested(nl_band, tb, rem_band) {
345                 bandidx++;
346
347                 nla_parse(tb_band, NL80211_BAND_ATTR_MAX,
348                           (struct nlattr *)nla_data(nl_band),
349                           nla_len(nl_band), NULL);
350
351 #ifdef NL80211_BAND_ATTR_HT_CAPA
352                 parse_band_ht_capa(iface, tb_band[NL80211_BAND_ATTR_HT_CAPA]);
353 #endif /* NL80211_BAND_ATTR_HT_CAPA */
354 #ifdef HAVE_NL80211_VHT_CAPABILITY
355                 parse_band_vht_capa(iface, tb_band[NL80211_BAND_ATTR_VHT_CAPA]);
356 #endif /* HAVE_NL80211_VHT_CAPABILITY */
357                 parse_band_freqs(iface, tb_band[NL80211_BAND_ATTR_FREQS]);
358         }
359 }
360
361 static void parse_supported_commands(struct ws80211_interface *iface,
362                                      struct nlattr *tb)
363 {
364         /* Can frequency be set? Only newer versions of cfg80211 supports this */
365 #ifdef HAVE_NL80211_CMD_SET_CHANNEL
366         int cmd;
367         struct nlattr *nl_cmd;
368
369         if (!tb) return;
370
371         nla_for_each_nested(nl_cmd, tb, cmd) {
372                 if(nla_get_u32(nl_cmd) == NL80211_CMD_SET_CHANNEL)
373                         iface->can_set_freq = TRUE;
374         }
375 #else
376         iface->can_set_freq = TRUE;
377 #endif
378 }
379
380 static int get_phys_handler(struct nl_msg *msg, void *arg)
381 {
382         struct nlattr *tb_msg[NL80211_ATTR_MAX + 1];
383         struct genlmsghdr *gnlh = (struct genlmsghdr *)nlmsg_data(nlmsg_hdr(msg));
384
385         struct nliface_cookie *cookie = (struct nliface_cookie *)arg;
386
387         struct ws80211_interface *iface;
388         char* ifname;
389         int added = 0;
390
391         nla_parse(tb_msg, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
392                   genlmsg_attrlen(gnlh, 0), NULL);
393
394         if (!tb_msg[NL80211_ATTR_WIPHY_NAME])
395                 return NL_SKIP;
396
397         ifname = g_strdup_printf("%s.mon", nla_get_string(tb_msg[NL80211_ATTR_WIPHY_NAME]));
398         iface = get_interface_by_name(cookie->interfaces, ifname);
399
400         if (!iface) {
401                 iface = (struct ws80211_interface *)g_malloc0(sizeof(*iface));
402                 if (!iface) {
403                         g_free(ifname);
404                         return NL_SKIP;
405                 }
406                 added = 1;
407                 iface->ifname = ifname;
408                 iface->frequencies = g_array_new(FALSE, FALSE, sizeof(uint32_t));
409                 iface->channel_types = 1 << WS80211_CHAN_NO_HT;
410         } else {
411                 g_free(ifname);
412         }
413
414         parse_supported_iftypes(iface, tb_msg[NL80211_ATTR_SUPPORTED_IFTYPES]);
415         parse_wiphy_bands(iface, tb_msg[NL80211_ATTR_WIPHY_BANDS]);
416         parse_supported_commands(iface, tb_msg[NL80211_ATTR_SUPPORTED_COMMANDS]);
417
418         if (added)
419                 g_array_append_val(cookie->interfaces, iface);
420
421         return NL_SKIP;
422 }
423
424 static int ws80211_get_phys(GArray *interfaces)
425 {
426         struct nliface_cookie cookie;
427         struct nl_msg *msg;
428         struct nl_cb *cb;
429         int ret;
430         msg = nlmsg_alloc();
431         if (!msg) {
432                 fprintf(stderr, "failed to allocate netlink message\n");
433                 return 2;
434         }
435
436         cb = nl_cb_alloc(NL_CB_DEFAULT);
437
438         cookie.interfaces = interfaces;
439
440         genlmsg_put(msg, 0, 0, nl_state.nl80211_id, 0,
441                     NLM_F_DUMP, NL80211_CMD_GET_WIPHY, 0);
442
443 #ifdef HAVE_NL80211_SPLIT_WIPHY_DUMP
444         if (nl_state.have_split_wiphy) {
445                 NLA_PUT_FLAG(msg, NL80211_ATTR_SPLIT_WIPHY_DUMP);
446         }
447 #endif /* #ifdef HAVE_NL80211_SPLIT_WIPHY_DUMP */
448         nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, get_phys_handler, &cookie);
449
450         ret = nl80211_do_cmd(msg, cb);
451         nlmsg_free(msg);
452         return ret;
453
454 #ifdef HAVE_NL80211_SPLIT_WIPHY_DUMP
455 nla_put_failure:
456         nlmsg_free(msg);
457         fprintf(stderr, "building message failed\n");
458         return -1;
459 #endif /* HAVE_NL80211_SPLIT_WIPHY_DUMP */
460 }
461
462 static int get_freq_wext(const char *ifname)
463 {
464         int fd;
465         int ret = -1;
466         /* Ugly hack to avoid including wireless.h */
467         struct {
468                 char name1[IFNAMSIZ];
469                 __s32 m;
470                 __s16 e;
471                 __u8 i;
472                 __u8 flags;
473         } wrq;
474
475         fd = socket(AF_INET, SOCK_DGRAM, 0);
476         if (fd == -1)
477                 return -1;
478
479         g_strlcpy(wrq.name1, ifname, IFNAMSIZ);
480         /* SIOCGIWFREQ */
481         if (ioctl(fd, 0x8B05, &wrq) == 0) {
482                 if (wrq.e == 6)
483                         ret = wrq.m;
484         }
485         close(fd);
486         return ret;
487 }
488
489 struct __iface_info
490 {
491         struct ws80211_iface_info *pub;
492         int type;
493         int phyidx;
494 };
495
496 static int get_iface_info_handler(struct nl_msg *msg, void *arg)
497 {
498         struct genlmsghdr *gnlh = (struct genlmsghdr *)nlmsg_data(nlmsg_hdr(msg));
499         struct nlattr *tb_msg[NL80211_ATTR_MAX + 1];
500         struct __iface_info *iface_info = (struct __iface_info *)arg;
501
502         nla_parse(tb_msg, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
503                   genlmsg_attrlen(gnlh, 0), NULL);
504
505         if (tb_msg[NL80211_ATTR_IFTYPE]) {
506                 iface_info->type = nla_get_u32(tb_msg[NL80211_ATTR_IFTYPE]);
507         }
508         if (tb_msg[NL80211_ATTR_WIPHY]) {
509                 iface_info->phyidx = nla_get_u32(tb_msg[NL80211_ATTR_WIPHY]);
510         }
511
512         if (tb_msg[NL80211_ATTR_WIPHY_FREQ]) {
513                 gboolean found_ch_width = FALSE;
514                 iface_info->pub->current_freq = nla_get_u32(tb_msg[NL80211_ATTR_WIPHY_FREQ]);
515                 iface_info->pub->current_chan_type = WS80211_CHAN_NO_HT;
516 #ifdef HAVE_NL80211_VHT_CAPABILITY
517                 if (tb_msg[NL80211_ATTR_CHANNEL_WIDTH]) {
518                         switch (nla_get_u32(tb_msg[NL80211_ATTR_CHANNEL_WIDTH])) {
519                         case NL80211_CHAN_WIDTH_80:
520                                 iface_info->pub->current_chan_type = WS80211_CHAN_VHT80;
521                                 found_ch_width = TRUE;
522                                 break;
523                         case NL80211_CHAN_WIDTH_80P80:
524                                 iface_info->pub->current_chan_type = WS80211_CHAN_VHT80P80;
525                                 found_ch_width = TRUE;
526                                 break;
527                         case NL80211_CHAN_WIDTH_160:
528                                 iface_info->pub->current_chan_type = WS80211_CHAN_VHT160;
529                                 found_ch_width = TRUE;
530                                 break;
531                         }
532                 }
533                 if (tb_msg[NL80211_ATTR_CENTER_FREQ1]) {
534                         iface_info->pub->current_center_freq1 =
535                                 nla_get_u32(tb_msg[NL80211_ATTR_CENTER_FREQ1]);
536                 }
537                 if (tb_msg[NL80211_ATTR_CENTER_FREQ2]) {
538                         iface_info->pub->current_center_freq2 =
539                                 nla_get_u32(tb_msg[NL80211_ATTR_CENTER_FREQ2]);
540                 }
541 #endif
542                 if (!found_ch_width && tb_msg[NL80211_ATTR_WIPHY_CHANNEL_TYPE]) {
543                         switch (nla_get_u32(tb_msg[NL80211_ATTR_WIPHY_CHANNEL_TYPE])) {
544
545                         case NL80211_CHAN_NO_HT:
546                                 iface_info->pub->current_chan_type = WS80211_CHAN_NO_HT;
547                                 break;
548
549                         case NL80211_CHAN_HT20:
550                                 iface_info->pub->current_chan_type = WS80211_CHAN_HT20;
551                                 break;
552
553                         case NL80211_CHAN_HT40MINUS:
554                                 iface_info->pub->current_chan_type = WS80211_CHAN_HT40MINUS;
555                                 break;
556
557                         case NL80211_CHAN_HT40PLUS:
558                                 iface_info->pub->current_chan_type = WS80211_CHAN_HT40PLUS;
559                                 break;
560                         }
561                 }
562
563         }
564         return NL_SKIP;
565 }
566
567
568 static int __ws80211_get_iface_info(const char *name, struct __iface_info *iface_info)
569 {
570         int devidx;
571         struct nl_msg *msg;
572         struct nl_cb *cb;
573         msg = nlmsg_alloc();
574         if (!msg) {
575                 fprintf(stderr, "failed to allocate netlink message\n");
576                 return 2;
577         }
578
579         cb = nl_cb_alloc(NL_CB_DEFAULT);
580
581         devidx = if_nametoindex(name);
582
583         genlmsg_put(msg, 0, 0, nl_state.nl80211_id, 0,
584                     0, NL80211_CMD_GET_INTERFACE, 0);
585         NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, devidx);
586
587         nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, get_iface_info_handler, iface_info);
588
589         if (nl80211_do_cmd(msg, cb)) {
590                 nlmsg_free(msg);
591                 return -1;
592         }
593
594         /* Old kernels can't get the current freq via netlink. Try WEXT too :( */
595         if (iface_info->pub->current_freq == -1)
596                 iface_info->pub->current_freq = get_freq_wext(name);
597         nlmsg_free(msg);
598         return 0;
599
600 nla_put_failure:
601         nlmsg_free(msg);
602         fprintf(stderr, "building message failed\n");
603         return -1;
604 }
605
606 int ws80211_get_iface_info(const char *name, struct ws80211_iface_info *iface_info)
607 {
608         struct __iface_info __iface_info;
609
610         memset(iface_info, 0, sizeof(*iface_info));
611         __iface_info.pub = iface_info;
612         __iface_info.type = -1;
613         __iface_info.phyidx= -1;
614         __iface_info.pub->current_freq = -1;
615         __iface_info.pub->current_chan_type = WS80211_CHAN_NO_HT;
616
617         return __ws80211_get_iface_info(name, &__iface_info);
618 }
619
620 static int ws80211_keep_only_monitor(GArray *interfaces)
621 {
622         unsigned int j;
623         struct ws80211_interface *iface;
624 restart:
625         for (j = 0; j < interfaces->len; j++) {
626                 iface = g_array_index(interfaces, struct ws80211_interface *, j);
627                 if (!iface->cap_monitor) {
628                         g_array_remove_index(interfaces, j);
629                         g_array_free(iface->frequencies, TRUE);
630                         g_free(iface->ifname);
631                         g_free(iface);
632                         goto restart;
633                 }
634         }
635         return 0;
636 }
637
638 static int ws80211_populate_devices(GArray *interfaces)
639 {
640         FILE *fh;
641         char line[200];
642         char *t;
643         gchar *t2;
644         char *ret;
645         int i;
646         unsigned int j;
647
648         struct ws80211_iface_info pub = {-1, WS80211_CHAN_NO_HT, -1, -1, WS80211_FCS_ALL};
649         struct __iface_info iface_info;
650         struct ws80211_interface *iface;
651
652         /* Get a list of phy's that can handle monitor mode */
653         ws80211_get_phys(interfaces);
654         ws80211_keep_only_monitor(interfaces);
655
656         fh = g_fopen("/proc/net/dev", "r");
657         if(!fh) {
658                 fprintf(stderr, "Cannot open /proc/net/dev");
659                 return -ENOENT;
660         }
661
662         /* Skip the first two lines */
663         for (i = 0; i < 2; i++) {
664                 ret = fgets(line, sizeof(line), fh);
665                 if (ret == NULL) {
666                         fprintf(stderr, "Error parsing /proc/net/dev");
667                         fclose(fh);
668                         return -1;
669                 }
670         }
671
672         /* Update names of user created monitor interfaces */
673         while(fgets(line, sizeof(line), fh)) {
674                 t = index(line, ':');
675                 if (!t)
676                         continue;
677                 *t = 0;
678                 t = line;
679                 while (*t && *t == ' ')
680                         t++;
681                 memset(&iface_info, 0, sizeof(iface_info));
682                 iface_info.pub = &pub;
683                 __ws80211_get_iface_info(t, &iface_info);
684
685                 if (iface_info.type == NL80211_IFTYPE_MONITOR) {
686                         for (j = 0; j < interfaces->len; j++) {
687                                 iface = g_array_index(interfaces, struct ws80211_interface *, j);
688                                 t2 = g_strdup_printf("phy%d.mon", iface_info.phyidx);
689                                 if (t2) {
690                                         if (!strcmp(t2, iface->ifname)) {
691                                                 g_free(iface->ifname);
692                                                 iface->ifname = g_strdup(t);
693                                         }
694                                         g_free(t2);
695                                 }
696                         }
697                 }
698         }
699         fclose(fh);
700         return 0;
701 }
702
703 static int ws80211_iface_up(const char *ifname)
704 {
705         int sock;
706         struct ifreq ifreq;
707
708         sock = socket(AF_PACKET, SOCK_RAW, 0);
709         if (sock == -1)
710                 return -1;
711
712         g_strlcpy(ifreq.ifr_name, ifname, sizeof(ifreq.ifr_name));
713
714         if (ioctl(sock, SIOCGIFFLAGS, &ifreq))
715                 goto out_err;
716
717         ifreq.ifr_flags |= IFF_UP;
718
719         if (ioctl(sock, SIOCSIFFLAGS, &ifreq))
720                 goto out_err;
721
722         close(sock);
723         return 0;
724
725 out_err:
726         close(sock);
727         return -1;
728 }
729
730 /* Needed for NLA_PUT_STRING, which passes strlen as an int */
731 DIAG_OFF_CLANG(shorten-64-to-32)
732 static int ws80211_create_on_demand_interface(const char *name)
733 {
734         int devidx, phyidx, err;
735         struct nl_msg *msg;
736         struct nl_cb *cb;
737
738         devidx = if_nametoindex(name);
739         if (devidx)
740                 return ws80211_iface_up(name);
741
742         if (sscanf(name, "phy%d.mon", &phyidx) != 1)
743                 return -EINVAL;
744
745         cb = nl_cb_alloc(NL_CB_DEFAULT);
746         msg = nlmsg_alloc();
747         if (!msg) {
748                 fprintf(stderr, "failed to allocate netlink message\n");
749                 return 2;
750         }
751
752         genlmsg_put(msg, 0, 0, nl_state.nl80211_id, 0,
753                     0, NL80211_CMD_NEW_INTERFACE, 0);
754         NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, phyidx);
755
756         NLA_PUT_STRING(msg, NL80211_ATTR_IFNAME, name);
757         NLA_PUT_U32(msg, NL80211_ATTR_IFTYPE, NL80211_IFTYPE_MONITOR);
758
759         err = nl80211_do_cmd(msg, cb);
760         nlmsg_free(msg);
761         if (err)
762                 return err;
763         return ws80211_iface_up(name);
764
765 nla_put_failure:
766         nlmsg_free(msg);
767         fprintf(stderr, "building message failed\n");
768         return 2;
769 }
770 DIAG_ON_CLANG(shorten-64-to-32)
771
772 int ws80211_set_freq(const char *name, guint32 freq, int chan_type, guint32 _U_ center_freq, guint32 _U_ center_freq2)
773 {
774         int devidx, err;
775         struct nl_msg *msg;
776         struct nl_cb *cb;
777
778         err = ws80211_create_on_demand_interface(name);
779         if (err)
780                 return err;
781
782         msg = nlmsg_alloc();
783         if (!msg) {
784                 fprintf(stderr, "failed to allocate netlink message\n");
785                 return 2;
786         }
787
788         cb = nl_cb_alloc(NL_CB_DEFAULT);
789
790         devidx = if_nametoindex(name);
791
792 #ifdef HAVE_NL80211_CMD_SET_CHANNEL
793         genlmsg_put(msg, 0, 0, nl_state.nl80211_id, 0,
794                     0, NL80211_CMD_SET_CHANNEL, 0);
795 #else
796         genlmsg_put(msg, 0, 0, nl_state.nl80211_id, 0,
797                     0, NL80211_CMD_SET_WIPHY, 0);
798 #endif
799
800         NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, devidx);
801         NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, freq);
802
803         switch (chan_type) {
804
805 #ifdef NL80211_BAND_ATTR_HT_CAPA
806         case WS80211_CHAN_NO_HT:
807                 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE, NL80211_CHAN_NO_HT);
808                 break;
809
810         case WS80211_CHAN_HT20:
811                 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE, NL80211_CHAN_HT20);
812                 break;
813
814         case WS80211_CHAN_HT40MINUS:
815                 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE, NL80211_CHAN_HT40MINUS);
816                 break;
817
818         case WS80211_CHAN_HT40PLUS:
819                 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE, NL80211_CHAN_HT40PLUS);
820                 break;
821 #endif
822 #ifdef HAVE_NL80211_VHT_CAPABILITY
823         case WS80211_CHAN_VHT80:
824                 NLA_PUT_U32(msg, NL80211_ATTR_CHANNEL_WIDTH, NL80211_CHAN_WIDTH_80);
825                 NLA_PUT_U32(msg, NL80211_ATTR_CENTER_FREQ1, center_freq);
826                 break;
827
828         case WS80211_CHAN_VHT80P80:
829                 NLA_PUT_U32(msg, NL80211_ATTR_CHANNEL_WIDTH, NL80211_CHAN_WIDTH_80P80);
830                 NLA_PUT_U32(msg, NL80211_ATTR_CENTER_FREQ1, center_freq);
831                 NLA_PUT_U32(msg, NL80211_ATTR_CENTER_FREQ2, center_freq2);
832                 break;
833
834         case WS80211_CHAN_VHT160:
835                 NLA_PUT_U32(msg, NL80211_ATTR_CHANNEL_WIDTH, NL80211_CHAN_WIDTH_160);
836                 NLA_PUT_U32(msg, NL80211_ATTR_CENTER_FREQ1, center_freq);
837                 break;
838 #endif
839         default:
840                 break;
841         }
842         err = nl80211_do_cmd(msg, cb);
843         nlmsg_free(msg);
844         return err;
845
846 nla_put_failure:
847         nlmsg_free(msg);
848         fprintf(stderr, "building message failed\n");
849         return 2;
850
851 }
852
853 GArray* ws80211_find_interfaces(void)
854 {
855         GArray *interfaces;
856
857         if (!nl_state.nl_sock)
858                 return NULL;
859
860         interfaces = g_array_new(FALSE, FALSE, sizeof(struct ws80211_interface *));
861         if (!interfaces)
862                 return NULL;
863
864         if (ws80211_populate_devices(interfaces)) {
865                 ws80211_free_interfaces(interfaces);
866                 return NULL;
867         }
868         return interfaces;
869 }
870
871 int
872 ws80211_str_to_chan_type(const gchar *s)
873 {
874         int ret = -1;
875         if (!s)
876                 return -1;
877
878         if (!strcmp(s, CHAN_NO_HT))
879                 ret = WS80211_CHAN_NO_HT;
880         if (!strcmp(s, CHAN_HT20))
881                 ret = WS80211_CHAN_HT20;
882         if (!strcmp(s, CHAN_HT40MINUS))
883                 ret = WS80211_CHAN_HT40MINUS;
884         if (!strcmp(s, CHAN_HT40PLUS))
885                 ret = WS80211_CHAN_HT40PLUS;
886         if (!strcmp(s, CHAN_VHT80))
887                 ret = WS80211_CHAN_VHT80;
888         if (!strcmp(s, CHAN_VHT80P80))
889                 ret = WS80211_CHAN_VHT80P80;
890         if (!strcmp(s, CHAN_VHT160))
891                 ret = WS80211_CHAN_VHT160;
892
893         return ret;
894 }
895
896 const gchar
897 *ws80211_chan_type_to_str(int type)
898 {
899         switch (type) {
900         case WS80211_CHAN_NO_HT:
901                 return CHAN_NO_HT;
902         case WS80211_CHAN_HT20:
903                 return CHAN_HT20;
904         case WS80211_CHAN_HT40MINUS:
905                 return CHAN_HT40MINUS;
906         case WS80211_CHAN_HT40PLUS:
907                 return CHAN_HT40PLUS;
908         case WS80211_CHAN_VHT80:
909                 return CHAN_VHT80;
910         case WS80211_CHAN_VHT80P80:
911                 return CHAN_VHT80P80;
912         case WS80211_CHAN_VHT160:
913                 return CHAN_VHT160;
914         }
915         return NULL;
916 }
917
918 gboolean ws80211_has_fcs_filter(void)
919 {
920         return FALSE;
921 }
922
923 int ws80211_set_fcs_validation(const char *name _U_, enum ws80211_fcs_validation fcs_validation _U_)
924 {
925         return -1;
926 }
927
928 const char *network_manager_path = "/usr/sbin/NetworkManager"; /* Is this correct? */
929 const char *ws80211_get_helper_path(void) {
930         if (g_file_test(network_manager_path, G_FILE_TEST_IS_EXECUTABLE)) {
931                 return network_manager_path;
932         }
933         return NULL;
934 }
935
936 #elif defined(HAVE_AIRPCAP)
937
938 #include <wsutil/unicode-utils.h>
939
940 #include "airpcap.h"
941 #include "airpcap_loader.h"
942
943 int ws80211_init(void)
944 {
945         if (airpcap_get_dll_state() == AIRPCAP_DLL_OK) {
946                 return 0;
947         }
948         return -1;
949 }
950
951 static const char *airpcap_dev_prefix_ = "\\\\.\\";
952
953 GArray* ws80211_find_interfaces(void)
954 {
955         GArray *interfaces;
956         GList *airpcap_if_list, *cur_if;
957         int err;
958         gchar *err_str = NULL;
959
960         interfaces = g_array_new(FALSE, FALSE, sizeof(struct ws80211_interface *));
961         if (!interfaces)
962                 return NULL;
963
964         airpcap_if_list = get_airpcap_interface_list(&err, &err_str);
965
966         if (airpcap_if_list == NULL || g_list_length(airpcap_if_list) == 0){
967                 g_free(err_str);
968                 g_array_free(interfaces, TRUE);
969                 return NULL;
970         }
971
972         for (cur_if = airpcap_if_list; cur_if; cur_if = g_list_next(cur_if)) {
973                 struct ws80211_interface *iface;
974                 airpcap_if_info_t *airpcap_if_info = (airpcap_if_info_t *) cur_if->data;
975                 char *ifname;
976                 guint32 chan;
977                 guint32 i;
978
979                 if (!airpcap_if_info) continue;
980                 ifname = airpcap_if_info->name;
981                 if (strlen(ifname) > 4 && g_str_has_prefix(ifname, airpcap_dev_prefix_)) ifname += 4;
982
983                 iface = (struct ws80211_interface *)g_malloc0(sizeof(*iface));
984                 iface->ifname = g_strdup(ifname);
985                 iface->can_set_freq = TRUE;
986                 iface->frequencies = g_array_new(FALSE, FALSE, sizeof(guint32));
987
988                 iface->channel_types = 1 << WS80211_CHAN_NO_HT;
989                 /*
990                  * AirPcap stores per-channel capabilities. We should probably
991                  * do the same. */
992                 for (i = 0; i < airpcap_if_info->numSupportedChannels; i++) {
993                         if (airpcap_if_info->pSupportedChannels[i].Flags & FLAG_CAN_BE_HIGH) {
994                                 iface->channel_types |= 1 << WS80211_CHAN_HT40MINUS;
995                                 iface->channel_types |= 1 << WS80211_CHAN_HT40PLUS;
996                                 break;
997                         }
998                 }
999
1000                 iface->cap_monitor = 1;
1001
1002                 for (chan = 0; chan < airpcap_if_info->numSupportedChannels; chan++) {
1003                         g_array_append_val(iface->frequencies, airpcap_if_info->pSupportedChannels[chan].Frequency);
1004                 }
1005
1006                 g_array_append_val(interfaces, iface);
1007         }
1008
1009         return interfaces;
1010 }
1011
1012 int ws80211_get_iface_info(const char *name, struct ws80211_iface_info *iface_info)
1013 {
1014         GList *airpcap_if_list;
1015         int err;
1016         gchar *err_str = NULL;
1017         airpcap_if_info_t *airpcap_if_info;
1018
1019         if (!iface_info) return -1;
1020
1021         airpcap_if_list = get_airpcap_interface_list(&err, &err_str);
1022
1023         if (airpcap_if_list == NULL || g_list_length(airpcap_if_list) == 0){
1024                 g_free(err_str);
1025                 return -1;
1026         }
1027
1028         airpcap_if_info = get_airpcap_if_from_name(airpcap_if_list, name);
1029
1030         if (!airpcap_if_info) {
1031                 free_airpcap_interface_list(airpcap_if_list);
1032                 return -1;
1033         }
1034
1035         memset(iface_info, 0, sizeof(*iface_info));
1036         iface_info->current_freq = airpcap_if_info->channelInfo.Frequency;
1037         switch (airpcap_if_info->channelInfo.ExtChannel) {
1038                 case 0:
1039                         iface_info->current_chan_type = WS80211_CHAN_NO_HT;
1040                         break;
1041                 case -1:
1042                         iface_info->current_chan_type = WS80211_CHAN_HT40MINUS;
1043                         break;
1044                 case 1:
1045                         iface_info->current_chan_type = WS80211_CHAN_HT40PLUS;
1046                         break;
1047                 default:
1048                         return -1;
1049         }
1050
1051         switch (airpcap_if_info->CrcValidationOn) {
1052                 case AIRPCAP_VT_ACCEPT_CORRECT_FRAMES:
1053                         iface_info->current_fcs_validation = WS80211_FCS_VALID;
1054                         break;
1055                 case AIRPCAP_VT_ACCEPT_CORRUPT_FRAMES:
1056                         iface_info->current_fcs_validation = WS80211_FCS_INVALID;
1057                         break;
1058                 default:
1059                         iface_info->current_fcs_validation = WS80211_FCS_ALL;
1060                         break;
1061         }
1062
1063         return 0;
1064 }
1065
1066 int ws80211_set_freq(const char *name, guint32 freq, int chan_type, guint32 _U_ center_freq, guint32 _U_ center_freq2)
1067 {
1068         GList *airpcap_if_list;
1069         int err;
1070         gchar *err_str = NULL;
1071         airpcap_if_info_t *airpcap_if_info;
1072         gchar err_buf[AIRPCAP_ERRBUF_SIZE];
1073         PAirpcapHandle adapter;
1074         int ret_val = -1;
1075
1076         airpcap_if_list = get_airpcap_interface_list(&err, &err_str);
1077
1078         if (airpcap_if_list == NULL || g_list_length(airpcap_if_list) == 0){
1079                 g_free(err_str);
1080                 return ret_val;
1081         }
1082
1083         airpcap_if_info = get_airpcap_if_from_name(airpcap_if_list, name);
1084
1085         if (!airpcap_if_info) {
1086                 free_airpcap_interface_list(airpcap_if_list);
1087                 return ret_val;
1088         }
1089
1090         adapter = airpcap_if_open(airpcap_if_info->name, err_buf);
1091         if (adapter) {
1092                 airpcap_if_info->channelInfo.Frequency = freq;
1093                 switch (chan_type) {
1094                         case WS80211_CHAN_HT40MINUS:
1095                                 airpcap_if_info->channelInfo.ExtChannel = -1;
1096                                 break;
1097                         case WS80211_CHAN_HT40PLUS:
1098                                 airpcap_if_info->channelInfo.ExtChannel = 1;
1099                                 break;
1100                         default:
1101                                 airpcap_if_info->channelInfo.ExtChannel = 0;
1102                                 break;
1103                 }
1104
1105                 if (airpcap_if_set_device_channel_ex(adapter, airpcap_if_info->channelInfo)) {
1106                         ret_val = 0;
1107                 }
1108                 airpcap_if_close(adapter);
1109         }
1110
1111         free_airpcap_interface_list(airpcap_if_list);
1112         return ret_val;
1113 }
1114
1115 int ws80211_str_to_chan_type(const gchar *s _U_)
1116 {
1117         return -1;
1118 }
1119
1120 const gchar *ws80211_chan_type_to_str(int type _U_)
1121 {
1122         return NULL;
1123 }
1124
1125 gboolean ws80211_has_fcs_filter(void)
1126 {
1127         return TRUE;
1128 }
1129
1130 int ws80211_set_fcs_validation(const char *name, enum ws80211_fcs_validation fcs_validation)
1131 {
1132         GList *airpcap_if_list;
1133         int err;
1134         gchar *err_str = NULL;
1135         airpcap_if_info_t *airpcap_if_info;
1136         gchar err_buf[AIRPCAP_ERRBUF_SIZE];
1137         PAirpcapHandle adapter;
1138         int ret_val = -1;
1139
1140         airpcap_if_list = get_airpcap_interface_list(&err, &err_str);
1141
1142         if (airpcap_if_list == NULL || g_list_length(airpcap_if_list) == 0){
1143                 g_free(err_str);
1144                 return ret_val;
1145         }
1146
1147         airpcap_if_info = get_airpcap_if_from_name(airpcap_if_list, name);
1148
1149         if (!airpcap_if_info) {
1150                 free_airpcap_interface_list(airpcap_if_list);
1151                 return ret_val;
1152         }
1153
1154         adapter = airpcap_if_open(airpcap_if_info->name, err_buf);
1155         if (adapter) {
1156                 AirpcapValidationType val_type = AIRPCAP_VT_ACCEPT_EVERYTHING;
1157                 switch (fcs_validation) {
1158                         case WS80211_FCS_VALID:
1159                                 val_type = AIRPCAP_VT_ACCEPT_CORRECT_FRAMES;
1160                                 break;
1161                         case WS80211_FCS_INVALID:
1162                                 val_type = AIRPCAP_VT_ACCEPT_CORRUPT_FRAMES;
1163                                 break;
1164                         default:
1165                                 break;
1166                 }
1167
1168                 if (airpcap_if_set_fcs_validation(adapter, val_type)) {
1169                         /* Appears to be necessary for this to take effect. */
1170                         airpcap_if_store_cur_config_as_adapter_default(adapter);
1171                         ret_val = 0;
1172                 }
1173                 airpcap_if_close(adapter);
1174         }
1175
1176         free_airpcap_interface_list(airpcap_if_list);
1177         return ret_val;
1178 }
1179
1180 static char *airpcap_conf_path = NULL;
1181 const char *ws80211_get_helper_path(void)
1182 {
1183         HKEY h_key = NULL;
1184
1185         if (!airpcap_conf_path && RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T("SOFTWARE\\AirPcap"), 0, KEY_QUERY_VALUE|KEY_WOW64_32KEY, &h_key) == ERROR_SUCCESS) {
1186                 DWORD reg_ret;
1187                 TCHAR airpcap_dir_utf16[MAX_PATH];
1188                 DWORD ad_size = sizeof(airpcap_dir_utf16)/sizeof(TCHAR);
1189
1190                 reg_ret = RegQueryValueEx(h_key, NULL, NULL, NULL,
1191                                 (LPBYTE) &airpcap_dir_utf16, &ad_size);
1192
1193                 if (reg_ret == ERROR_SUCCESS) {
1194                         airpcap_dir_utf16[ad_size-1] = L'\0';
1195                         g_free(airpcap_conf_path);
1196                         airpcap_conf_path = g_strdup_printf("%s\\AirpcapConf.exe", utf_16to8(airpcap_dir_utf16));
1197
1198                         if (!g_file_test(airpcap_conf_path, G_FILE_TEST_IS_EXECUTABLE)) {
1199                                 g_free(airpcap_conf_path);
1200                                 airpcap_conf_path = NULL;
1201                         }
1202                 }
1203         }
1204
1205         return airpcap_conf_path;
1206 }
1207
1208 #else /* Everyone else. */
1209 int ws80211_init(void)
1210 {
1211         return -1;
1212 }
1213
1214 GArray* ws80211_find_interfaces(void)
1215 {
1216         return NULL;
1217 }
1218
1219 int ws80211_get_iface_info(const char *name _U_, struct ws80211_iface_info *iface_info _U_)
1220 {
1221         return -1;
1222 }
1223
1224 int ws80211_set_freq(const char *name _U_, guint32 freq _U_, int _U_ chan_type, guint32 _U_ center_freq, guint32 _U_ center_freq2)
1225 {
1226         return -1;
1227 }
1228
1229 int ws80211_str_to_chan_type(const gchar *s _U_)
1230 {
1231         return -1;
1232 }
1233
1234 const gchar *ws80211_chan_type_to_str(int type _U_)
1235 {
1236         return NULL;
1237 }
1238
1239 gboolean ws80211_has_fcs_filter(void)
1240 {
1241         return FALSE;
1242 }
1243
1244 int ws80211_set_fcs_validation(const char *name _U_, enum ws80211_fcs_validation fcs_validation _U_)
1245 {
1246         return -1;
1247 }
1248
1249 const char *ws80211_get_helper_path(void) {
1250         return NULL;
1251 }
1252
1253 #endif /* HAVE_LIBNL && HAVE_NL80211 */
1254
1255 /* Common to everyone */
1256
1257 void ws80211_free_interfaces(GArray *interfaces)
1258 {
1259         struct ws80211_interface *iface;
1260
1261         if (!interfaces)
1262                 return;
1263
1264         while (interfaces->len) {
1265                 iface = g_array_index(interfaces, struct ws80211_interface *, 0);
1266                 g_array_remove_index(interfaces, 0);
1267                 g_array_free(iface->frequencies, TRUE);
1268                 g_free(iface->ifname);
1269                 g_free(iface);
1270         }
1271         g_array_free(interfaces, TRUE);
1272 }
1273
1274 /*
1275  * Editor modelines  -  http://www.wireshark.org/tools/modelines.html
1276  *
1277  * Local variables:
1278  * c-basic-offset: 8
1279  * tab-width: 8
1280  * indent-tabs-mode: t
1281  * End:
1282  *
1283  * vi: set shiftwidth=8 tabstop=8 noexpandtab:
1284  * :indentSize=8:tabSize=8:noTabs=false:
1285  */