3 * Copyright 2012, Pontus Fuchs <pontus.fuchs@gmail.com>
5 Parts of this file was copied from iw:
7 Copyright (c) 2007, 2008 Johannes Berg
8 Copyright (c) 2007 Andy Lutomirski
9 Copyright (c) 2007 Mike Kershaw
10 Copyright (c) 2008-2009 Luis R. Rodriguez
12 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.
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.
30 #include <glib/gstdio.h>
32 #include "ws80211_utils.h"
33 #include "wsutil/ws_diag_control.h"
35 #if defined(HAVE_LIBNL) && defined(HAVE_NL80211)
41 #include <sys/ioctl.h>
44 #include <netlink/genl/genl.h>
46 #include <netlink/genl/family.h>
47 #include <netlink/genl/ctrl.h>
49 #include <netlink/msg.h>
51 #include <netlink/attr.h>
53 #include <linux/nl80211.h>
55 #ifdef HAVE_NL80211_SPLIT_WIPHY_DUMP
56 static int ws80211_get_protocol_features(int* features);
57 #endif /* HAVE_NL80211_SPLIT_WIPHY_DUMP */
59 /* libnl 1.x compatibility code */
61 #define nl_sock nl_handle
62 static inline struct nl_handle *nl_socket_alloc(void)
64 return nl_handle_alloc();
67 static inline void nl_socket_free(struct nl_sock *h)
71 #endif /* HAVE_LIBNL1 */
73 struct nl80211_state {
74 struct nl_sock *nl_sock;
79 static struct nl80211_state nl_state;
81 int ws80211_init(void)
84 #ifdef HAVE_NL80211_SPLIT_WIPHY_DUMP
86 #endif /* HAVE_NL80211_SPLIT_WIPHY_DUMP */
88 struct nl80211_state *state = &nl_state;
90 state->nl_sock = nl_socket_alloc();
91 if (!state->nl_sock) {
92 fprintf(stderr, "Failed to allocate netlink socket.\n");
96 if (genl_connect(state->nl_sock)) {
97 fprintf(stderr, "Failed to connect to generic netlink.\n");
99 goto out_handle_destroy;
102 state->nl80211_id = genl_ctrl_resolve(state->nl_sock, "nl80211");
103 if (state->nl80211_id < 0) {
104 fprintf(stderr, "nl80211 not found.\n");
106 goto out_handle_destroy;
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 */
117 nl_socket_free(state->nl_sock);
122 static int error_handler(struct sockaddr_nl *nla _U_, struct nlmsgerr *err,
125 int *ret = (int *)arg;
130 static int finish_handler(struct nl_msg *msg _U_, void *arg)
132 int *ret = (int *)arg;
137 static int ack_handler(struct nl_msg *msg _U_, void *arg)
139 int *ret = (int *)arg;
144 static int nl80211_do_cmd(struct nl_msg *msg, struct nl_cb *cb)
148 if (!nl_state.nl_sock)
151 err = nl_send_auto_complete(nl_state.nl_sock, msg);
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);
162 nl_recvmsgs(nl_state.nl_sock, cb);
169 struct nliface_cookie
175 static struct ws80211_interface *
176 get_interface_by_name(GArray *interfaces,
180 struct ws80211_interface *iface;
182 for (i = 0; i < interfaces->len; i++) {
183 iface = g_array_index(interfaces, struct ws80211_interface *, i);
184 if (!strcmp(iface->ifname, ifname))
191 * And now for a steaming heap of suck.
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.
198 * So we replace it with our own version, which does the requisite cast.
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
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)
211 #ifdef HAVE_NL80211_SPLIT_WIPHY_DUMP
212 static int get_features_handler(struct nl_msg *msg, void *arg)
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));
218 nla_parse(tb_msg, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
219 genlmsg_attrlen(gnlh, 0), NULL);
221 if (tb_msg[NL80211_ATTR_PROTOCOL_FEATURES])
222 *feat = nla_get_u32(tb_msg[NL80211_ATTR_PROTOCOL_FEATURES]);
227 static int ws80211_get_protocol_features(int* features)
234 fprintf(stderr, "failed to allocate netlink message\n");
238 cb = nl_cb_alloc(NL_CB_DEFAULT);
240 genlmsg_put(msg, 0, 0, nl_state.nl80211_id, 0, 0,
241 NL80211_CMD_GET_PROTOCOL_FEATURES, 0);
243 nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, get_features_handler, features);
245 return nl80211_do_cmd(msg, cb);
247 #endif /* HAVE_NL80211_SPLIT_WIPHY_DUMP */
249 #ifdef NL80211_BAND_ATTR_HT_CAPA
250 static void parse_band_ht_capa(struct ws80211_interface *iface,
257 iface->channel_types |= 1 << WS80211_CHAN_HT20;
258 ht40 = !!(nla_get_u16(tb) & 0x02);
260 iface->channel_types |= 1 << WS80211_CHAN_HT40MINUS;
261 iface->channel_types |= 1 << WS80211_CHAN_HT40PLUS;
264 #endif /* NL80211_BAND_ATTR_HT_CAPA */
266 static void parse_supported_iftypes(struct ws80211_interface *iface,
269 struct nlattr *nl_mode;
274 nla_for_each_nested(nl_mode, tb, rem_mode) {
275 if (nla_type(nl_mode) == NL80211_IFTYPE_MONITOR)
276 iface->cap_monitor = 1;
280 static void parse_band_freqs(struct ws80211_interface *iface,
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 */
298 nla_for_each_nested(nl_freq, tb, rem_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])
305 if (tb_freq[NL80211_FREQUENCY_ATTR_DISABLED])
308 freq = nla_get_u32(tb_freq[NL80211_FREQUENCY_ATTR_FREQ]);
309 g_array_append_val(iface->frequencies, freq);
313 static void parse_wiphy_bands(struct ws80211_interface *iface,
316 struct nlattr *nl_band;
317 struct nlattr *tb_band[NL80211_BAND_ATTR_MAX + 1];
323 nla_for_each_nested(nl_band, tb, rem_band) {
326 nla_parse(tb_band, NL80211_BAND_ATTR_MAX,
327 (struct nlattr *)nla_data(nl_band),
328 nla_len(nl_band), NULL);
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]);
337 static void parse_supported_commands(struct ws80211_interface *iface,
340 /* Can frequency be set? Only newer versions of cfg80211 supports this */
341 #ifdef HAVE_NL80211_CMD_SET_CHANNEL
343 struct nlattr *nl_cmd;
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;
352 iface->can_set_freq = TRUE;
356 static int get_phys_handler(struct nl_msg *msg, void *arg)
358 struct nlattr *tb_msg[NL80211_ATTR_MAX + 1];
359 struct genlmsghdr *gnlh = (struct genlmsghdr *)nlmsg_data(nlmsg_hdr(msg));
361 struct nliface_cookie *cookie = (struct nliface_cookie *)arg;
363 struct ws80211_interface *iface;
367 nla_parse(tb_msg, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
368 genlmsg_attrlen(gnlh, 0), NULL);
370 if (!tb_msg[NL80211_ATTR_WIPHY_NAME])
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);
377 iface = (struct ws80211_interface *)g_malloc0(sizeof(*iface));
383 iface->ifname = ifname;
384 iface->frequencies = g_array_new(FALSE, FALSE, sizeof(int));
385 iface->channel_types = 1 << WS80211_CHAN_NO_HT;
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]);
395 g_array_append_val(cookie->interfaces, iface);
400 static int ws80211_get_phys(GArray *interfaces)
402 struct nliface_cookie cookie;
407 fprintf(stderr, "failed to allocate netlink message\n");
411 cb = nl_cb_alloc(NL_CB_DEFAULT);
413 cookie.interfaces = interfaces;
415 genlmsg_put(msg, 0, 0, nl_state.nl80211_id, 0,
416 NLM_F_DUMP, NL80211_CMD_GET_WIPHY, 0);
418 #ifdef HAVE_NL80211_SPLIT_WIPHY_DUMP
419 if (nl_state.have_split_wiphy) {
420 NLA_PUT_FLAG(msg, NL80211_ATTR_SPLIT_WIPHY_DUMP);
422 #endif /* #ifdef HAVE_NL80211_SPLIT_WIPHY_DUMP */
423 nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, get_phys_handler, &cookie);
425 return nl80211_do_cmd(msg, cb);
427 #ifdef HAVE_NL80211_SPLIT_WIPHY_DUMP
429 fprintf(stderr, "building message failed\n");
431 #endif /* HAVE_NL80211_SPLIT_WIPHY_DUMP */
434 static int get_freq_wext(const char *ifname)
438 /* Ugly hack to avoid including wireless.h */
440 char name1[IFNAMSIZ];
447 fd = socket(AF_INET, SOCK_DGRAM, 0);
451 g_strlcpy(wrq.name1, ifname, IFNAMSIZ);
453 if (ioctl(fd, 0x8B05, &wrq) == 0) {
463 struct ws80211_iface_info *pub;
468 static int get_iface_info_handler(struct nl_msg *msg, void *arg)
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;
474 nla_parse(tb_msg, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
475 genlmsg_attrlen(gnlh, 0), NULL);
477 if (tb_msg[NL80211_ATTR_IFTYPE]) {
478 iface_info->type = nla_get_u32(tb_msg[NL80211_ATTR_IFTYPE]);
480 if (tb_msg[NL80211_ATTR_WIPHY]) {
481 iface_info->phyidx = nla_get_u32(tb_msg[NL80211_ATTR_WIPHY]);
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;
488 if (tb_msg[NL80211_ATTR_WIPHY_CHANNEL_TYPE]) {
489 switch (nla_get_u32(tb_msg[NL80211_ATTR_WIPHY_CHANNEL_TYPE])) {
491 case NL80211_CHAN_NO_HT:
492 iface_info->pub->current_chan_type = WS80211_CHAN_NO_HT;
495 case NL80211_CHAN_HT20:
496 iface_info->pub->current_chan_type = WS80211_CHAN_HT20;
499 case NL80211_CHAN_HT40MINUS:
500 iface_info->pub->current_chan_type = WS80211_CHAN_HT40MINUS;
503 case NL80211_CHAN_HT40PLUS:
504 iface_info->pub->current_chan_type = WS80211_CHAN_HT40PLUS;
514 static int __ws80211_get_iface_info(const char *name, struct __iface_info *iface_info)
521 fprintf(stderr, "failed to allocate netlink message\n");
525 cb = nl_cb_alloc(NL_CB_DEFAULT);
527 devidx = if_nametoindex(name);
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);
533 nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, get_iface_info_handler, iface_info);
535 if (nl80211_do_cmd(msg, cb))
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);
544 fprintf(stderr, "building message failed\n");
548 int ws80211_get_iface_info(const char *name, struct ws80211_iface_info *iface_info)
550 struct __iface_info __iface_info;
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;
559 return __ws80211_get_iface_info(name, &__iface_info);
562 static int ws80211_keep_only_monitor(GArray *interfaces)
565 struct ws80211_interface *iface;
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);
580 static int ws80211_populate_devices(GArray *interfaces)
590 struct ws80211_iface_info pub = {-1, WS80211_CHAN_NO_HT};
591 struct __iface_info iface_info;
592 struct ws80211_interface *iface;
594 /* Get a list of phy's that can handle monitor mode */
595 ws80211_get_phys(interfaces);
596 ws80211_keep_only_monitor(interfaces);
598 fh = g_fopen("/proc/net/dev", "r");
600 fprintf(stderr, "Cannot open /proc/net/dev");
604 /* Skip the first two lines */
605 for (i = 0; i < 2; i++) {
606 ret = fgets(line, sizeof(line), fh);
608 fprintf(stderr, "Error parsing /proc/net/dev");
614 /* Update names of user created monitor interfaces */
615 while(fgets(line, sizeof(line), fh)) {
616 t = index(line, ':');
621 while (*t && *t == ' ')
623 memset(&iface_info, 0, sizeof(iface_info));
624 iface_info.pub = &pub;
625 __ws80211_get_iface_info(t, &iface_info);
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);
632 if (!strcmp(t2, iface->ifname)) {
633 g_free(iface->ifname);
634 iface->ifname = g_strdup(t);
645 static int ws80211_iface_up(const char *ifname)
650 sock = socket(AF_PACKET, SOCK_RAW, 0);
654 g_strlcpy(ifreq.ifr_name, ifname, sizeof(ifreq.ifr_name));
656 if (ioctl(sock, SIOCGIFFLAGS, &ifreq))
659 ifreq.ifr_flags |= IFF_UP;
661 if (ioctl(sock, SIOCSIFFLAGS, &ifreq))
672 static int ws80211_create_on_demand_interface(const char *name)
674 int devidx, phyidx, err;
678 devidx = if_nametoindex(name);
680 return ws80211_iface_up(name);
682 if (sscanf(name, "phy%d.mon", &phyidx) != 1)
685 cb = nl_cb_alloc(NL_CB_DEFAULT);
688 fprintf(stderr, "failed to allocate netlink message\n");
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);
696 NLA_PUT_STRING(msg, NL80211_ATTR_IFNAME, name);
697 NLA_PUT_U32(msg, NL80211_ATTR_IFTYPE, NL80211_IFTYPE_MONITOR);
699 err = nl80211_do_cmd(msg, cb);
702 return ws80211_iface_up(name);
705 fprintf(stderr, "building message failed\n");
709 int ws80211_set_freq(const char *name, int freq, int chan_type)
715 err = ws80211_create_on_demand_interface(name);
721 fprintf(stderr, "failed to allocate netlink message\n");
725 cb = nl_cb_alloc(NL_CB_DEFAULT);
727 devidx = if_nametoindex(name);
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);
733 genlmsg_put(msg, 0, 0, nl_state.nl80211_id, 0,
734 0, NL80211_CMD_SET_WIPHY, 0);
737 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, devidx);
738 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, freq);
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);
747 case WS80211_CHAN_HT20:
748 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE, NL80211_CHAN_HT20);
751 case WS80211_CHAN_HT40MINUS:
752 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE, NL80211_CHAN_HT40MINUS);
755 case WS80211_CHAN_HT40PLUS:
756 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE, NL80211_CHAN_HT40PLUS);
763 err = nl80211_do_cmd(msg, cb);
767 fprintf(stderr, "building message failed\n");
772 void ws80211_free_interfaces(GArray *interfaces)
774 struct ws80211_interface *iface;
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);
786 g_array_free(interfaces, TRUE);
789 GArray* ws80211_find_interfaces(void)
793 if (!nl_state.nl_sock)
796 interfaces = g_array_new(FALSE, FALSE, sizeof(struct ws80211_interface *));
800 if (ws80211_populate_devices(interfaces)) {
801 ws80211_free_interfaces(interfaces);
807 int ws80211_frequency_to_channel(int freq)
813 return (freq - 2407) / 5;
815 return freq / 5 - 1000;
819 ws80211_str_to_chan_type(const gchar *s)
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;
837 *ws80211_chan_type_to_str(int type)
840 case WS80211_CHAN_NO_HT:
842 case WS80211_CHAN_HT20:
844 case WS80211_CHAN_HT40MINUS:
845 return CHAN_HT40MINUS;
846 case WS80211_CHAN_HT40PLUS:
847 return CHAN_HT40PLUS;
852 #else /* HAVE_LIBNL */
853 int ws80211_init(void)
858 GArray* ws80211_find_interfaces(void)
863 int ws80211_get_iface_info(const char *name _U_, struct ws80211_iface_info *iface_info _U_)
868 void ws80211_free_interfaces(GArray *interfaces _U_)
872 int ws80211_frequency_to_channel(int freq _U_)
877 int ws80211_set_freq(const char *name _U_, int freq _U_, int chan_type _U_)
882 int ws80211_str_to_chan_type(const gchar *s _U_)
887 const gchar *ws80211_chan_type_to_str(int type _U_)
891 #endif /* HAVE_LIBNL && HAVE_NL80211 */
894 * Editor modelines - http://www.wireshark.org/tools/modelines.html
899 * indent-tabs-mode: t
902 * vi: set shiftwidth=8 tabstop=8 noexpandtab:
903 * :indentSize=8:tabSize=8:noTabs=false: