Replace "svn" with "git" all over the place.
[metze/wireshark/wip.git] / ui / gtk / main_80211_toolbar.c
1 /* main_80211_toolbar.c
2  * The 802.11 toolbar by Pontus Fuchs <pontus.fuchs@gmail.com>
3  *
4  * $Id$
5  *
6  * Wireshark - Network traffic analyzer
7  * By Gerald Combs <gerald@wireshark.org>
8  * Copyright 1998 Gerald Combs
9  *
10  * This program is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU General Public License
12  * as published by the Free Software Foundation; either version 2
13  * of the License, or (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
23  */
24
25 /*
26  * This file implements the "80211" toolbar for Wireshark.
27  */
28
29 #include "config.h"
30
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <string.h>
34
35 #include <gtk/gtk.h>
36
37 #include "epan/prefs.h"
38
39 #include "gtkglobals.h"
40 #include "stock_icons.h"
41
42 #include "main.h"
43 #include "main_toolbar.h"
44
45 #include "ui/recent.h"
46 #include "ui/gtk/old-gtk-compat.h"
47 #include "ui/ui_util.h"
48 #include "ui/gtk/main_80211_toolbar.h"
49
50 #include "ws80211_utils.h"
51 #include "capture_session.h"
52 #include "capture_sync.h"
53
54 static GtkWidget *tb80211_tb, *tb80211_iface_list_box, *tb80211_freq_list_box, *tb80211_chan_type_box, *tb80211_info_label;
55
56 static GArray *tb80211_interfaces;
57 static struct ws80211_interface *tb80211_current_iface;
58 static gint32 tb80211_current_freq = -1;
59 static gint32 tb80211_current_type = -1;
60
61 static gboolean tb80211_dont_set_chan;
62 static gboolean tb80211_dont_set_iface;
63
64 static void tb80211_set_info(const char *errstr)
65 {
66     gtk_label_set_markup(GTK_LABEL(tb80211_info_label), errstr);
67 }
68
69 static
70 void add_channel_type(const char *type, int oldtype, int indx )
71 {
72     gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(tb80211_chan_type_box), type);
73
74     if (oldtype != -1 && oldtype == ws80211_str_to_chan_type(type)) {
75         gtk_combo_box_set_active(GTK_COMBO_BOX(tb80211_chan_type_box), indx);
76         tb80211_current_type = oldtype;
77     }
78 }
79
80 static
81 void tb80211_update_chan_type(void)
82 {
83     static unsigned int tb80211_type_cnt;
84     unsigned int i;
85     int oldtype = -1;
86     for (i = 0; i < tb80211_type_cnt; i++) {
87         gtk_combo_box_text_remove(GTK_COMBO_BOX_TEXT(tb80211_chan_type_box), 0);
88     }
89
90     if (!tb80211_current_iface) {
91         return;
92     }
93
94     oldtype = tb80211_current_type;
95     tb80211_current_type = -1;
96
97     i = 0;
98     add_channel_type(CHAN_NO_HT, oldtype, i++);
99
100     if (tb80211_current_iface->channel_types & (1 << WS80211_CHAN_HT20)) {
101         add_channel_type(CHAN_HT20, oldtype, i++);
102     }
103     if (tb80211_current_iface->channel_types & (1 << WS80211_CHAN_HT40MINUS)) {
104         add_channel_type(CHAN_HT40MINUS, oldtype, i++);
105     }
106     if (tb80211_current_iface->channel_types & (1 << WS80211_CHAN_HT40PLUS)) {
107         add_channel_type(CHAN_HT40PLUS, oldtype, i++);
108     }
109     tb80211_type_cnt = i;
110 }
111
112 static
113 void tb80211_update_freq(void)
114 {
115     static unsigned int tb80211_freq_cnt;
116     unsigned int i;
117     gchar *str;
118     gint32 oldfreq = 0;
119
120     for (i = 0; i < tb80211_freq_cnt; i++) {
121         gtk_combo_box_text_remove(GTK_COMBO_BOX_TEXT(tb80211_freq_list_box), 0);
122     }
123
124     oldfreq = tb80211_current_freq;
125     tb80211_current_freq = -1;
126
127     if (!tb80211_current_iface)
128         return;
129
130     tb80211_freq_cnt = tb80211_current_iface->frequencies->len;
131     for (i = 0; i < tb80211_freq_cnt; i++) {
132         int freq;
133         freq = g_array_index(tb80211_current_iface->frequencies, int, i);
134         str = g_strdup_printf("%d MHz (%d)", freq, ws80211_frequency_to_channel(freq));
135         gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(tb80211_freq_list_box), str);
136         g_free(str);
137
138         if (freq == oldfreq) {
139             gtk_combo_box_set_active(GTK_COMBO_BOX(tb80211_freq_list_box), i);
140             tb80211_current_freq = oldfreq;
141         }
142     }
143 }
144
145 static
146 void tb80211_update_freq_and_type(void)
147 {
148     tb80211_dont_set_chan = TRUE;
149     tb80211_update_freq();
150     tb80211_update_chan_type();
151     tb80211_dont_set_chan = FALSE;
152 }
153
154 #ifdef HAVE_LIBPCAP
155 /* Get currently selected channel type type enum */
156 static
157 int get_selected_channel_type(void)
158 {
159     int ret;
160     gchar *s = gtk_combo_box_text_get_active_text(GTK_COMBO_BOX_TEXT(tb80211_chan_type_box));
161
162     ret = ws80211_str_to_chan_type(s);
163
164     g_free(s);
165     return ret;
166 }
167
168 /* Invoke dumpcap to set channel */
169 static int
170 tb80211_do_set_channel(char *iface, int freq, int type)
171 {
172         gchar *freq_s;
173         const gchar *type_s;
174         gchar *data, *primary_msg, *secondary_msg;
175         int ret;
176
177         freq_s = g_strdup_printf("%d", freq);
178         type_s = ws80211_chan_type_to_str(type);
179         ret = sync_interface_set_80211_chan(iface, freq_s, type_s,
180                                             &data, &primary_msg, &secondary_msg, main_window_update);
181
182         /* Parse the error msg */
183         if (ret && primary_msg) {
184                 return atoi(primary_msg);
185         }
186         g_free(data);
187         g_free(primary_msg);
188         g_free(secondary_msg);
189         g_free(freq_s);
190         return ret;
191 }
192
193 /* Called on freq and type combo box change. */
194 static void
195 tb80211_set_channel(void)
196 {
197     gchar *info = NULL;
198     int err, selected_chan, new_type, new_freq;
199
200     GtkComboBox *freq_combo = GTK_COMBO_BOX(tb80211_freq_list_box);
201
202     GtkComboBox *type_combo = GTK_COMBO_BOX(tb80211_chan_type_box);
203
204     selected_chan = gtk_combo_box_get_active(freq_combo);
205     if (selected_chan < 0)
206         return;
207
208     new_freq = g_array_index(tb80211_current_iface->frequencies, int, selected_chan);
209     new_type = get_selected_channel_type();
210
211     err = tb80211_do_set_channel(tb80211_current_iface->ifname, new_freq, new_type);
212     if (err) {
213         info = g_strdup_printf("<b>Failed to set channel: %s</b>", g_strerror(abs(err)));
214         /* Try to set back to last working chan */
215         err = tb80211_do_set_channel(tb80211_current_iface->ifname, tb80211_current_freq, tb80211_current_type);
216         if (err) {
217             gtk_combo_box_set_active(freq_combo, -1);
218             gtk_combo_box_set_active(type_combo, -1);
219             tb80211_current_freq = -1;
220             tb80211_current_type = -1;
221         }
222         else {
223             tb80211_update_freq_and_type();
224         }
225     }
226     else {
227         info = g_strdup_printf("%s Switched to %d MHz (%d)", tb80211_current_iface->ifname, new_freq, ws80211_frequency_to_channel(new_freq));
228         tb80211_current_freq = new_freq;
229         tb80211_current_type = new_type;
230     }
231     tb80211_set_info(info);
232     g_free(info);
233 }
234
235 static void
236 tb80211_set_chan_cb(GtkWidget *widget _U_, gpointer data _U_)
237 {
238     if (!tb80211_current_iface || tb80211_dont_set_chan)
239         return;
240
241     tb80211_set_channel();
242 }
243 #endif
244
245 static void
246 tb80211_iface_changed_cb(GtkWidget *widget, gpointer data _U_)
247 {
248     unsigned int i;
249     int ret;
250     struct ws80211_interface *iface;
251     struct ws80211_iface_info iface_info;
252     gchar *active;
253
254     if (tb80211_dont_set_iface)
255         return;
256
257     active = gtk_combo_box_text_get_active_text(GTK_COMBO_BOX_TEXT(widget));
258
259     if (!active || tb80211_dont_set_chan)
260         goto out_free;
261
262     for (i = 0; i < tb80211_interfaces->len; i++) {
263         iface = g_array_index(tb80211_interfaces, struct ws80211_interface *, i);
264         if (strcmp(active, iface->ifname) == 0) {
265             tb80211_current_iface = iface;
266             break;
267         }
268     }
269
270     tb80211_current_freq = -1;
271     tb80211_current_type = -1;
272     if (tb80211_current_iface) {
273         ret = ws80211_get_iface_info(tb80211_current_iface->ifname, &iface_info);
274         if (!ret) {
275             tb80211_current_freq = iface_info.current_freq;
276             tb80211_current_type = iface_info.current_chan_type;
277         }
278     }
279     tb80211_update_freq_and_type();
280
281 out_free:
282     g_free(active);
283 }
284
285 void
286 tb80211_refresh_interfaces(void)
287 {
288     struct ws80211_interface *iface;
289     unsigned int i;
290     gboolean same = FALSE;
291     gchar *selected_iface = NULL, *info;
292
293     if (!tb80211_tb)
294         return;
295
296     if (tb80211_interfaces) {
297         selected_iface = gtk_combo_box_text_get_active_text(GTK_COMBO_BOX_TEXT(tb80211_iface_list_box));
298
299         for (i = 0; i < tb80211_interfaces->len; i++)
300                 gtk_combo_box_text_remove(GTK_COMBO_BOX_TEXT(tb80211_iface_list_box), 0);
301
302         ws80211_free_interfaces(tb80211_interfaces);
303         tb80211_interfaces = NULL;
304         tb80211_current_iface = NULL;
305     }
306     tb80211_interfaces = ws80211_find_interfaces();
307
308     if (!tb80211_interfaces) {
309         goto out_free;
310     }
311
312     tb80211_dont_set_iface = TRUE;
313     for (i = 0; i < tb80211_interfaces->len; i++) {
314         iface = g_array_index(tb80211_interfaces, struct ws80211_interface *, i);
315         gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(tb80211_iface_list_box), iface->ifname);
316
317         if (selected_iface && strcmp(selected_iface, iface->ifname) == 0) {
318             gtk_combo_box_set_active(GTK_COMBO_BOX(tb80211_iface_list_box), i);
319             tb80211_current_iface = iface;
320             same = TRUE;
321         }
322     }
323     tb80211_dont_set_iface = FALSE;
324
325     /* Reset selectors if interface disappeared */
326     if (!same) {
327         gtk_combo_box_set_active(GTK_COMBO_BOX(tb80211_iface_list_box), -1);
328         gtk_combo_box_set_active(GTK_COMBO_BOX(tb80211_freq_list_box), -1);
329         gtk_combo_box_set_active(GTK_COMBO_BOX(tb80211_chan_type_box), -1);
330     }
331
332     info = g_strdup_printf("%d monitor interfaces found", tb80211_interfaces->len);
333     tb80211_set_info(info);
334     g_free(info);
335 out_free:
336     g_free(selected_iface);
337 }
338
339 static void
340 tb80211_add_label(const gchar *text, GtkWidget *tb)
341 {
342     GtkWidget     *label;
343     GtkToolItem   *label_ti;
344
345     label_ti = gtk_tool_item_new();
346     gtk_widget_show(GTK_WIDGET (label_ti));
347     label = gtk_label_new(text);
348     gtk_widget_show(GTK_WIDGET (label));
349     gtk_container_add(GTK_CONTAINER(label_ti), label);
350     gtk_toolbar_insert(GTK_TOOLBAR(tb), label_ti, -1);
351 }
352
353 GtkWidget *
354 ws80211_toolbar_new(void)
355 {
356     GtkToolItem   *ti;
357     int ret;
358
359     /* filter toolbar */
360     tb80211_tb = gtk_toolbar_new();
361     gtk_orientable_set_orientation(GTK_ORIENTABLE(tb80211_tb),
362                                 GTK_ORIENTATION_HORIZONTAL);
363
364     gtk_widget_show(tb80211_tb);
365
366     tb80211_add_label(" Interface: ", tb80211_tb);
367
368     ti = gtk_tool_item_new();
369     gtk_widget_show(GTK_WIDGET (ti));
370     tb80211_iface_list_box = gtk_combo_box_text_new();
371     g_signal_connect(tb80211_iface_list_box, "changed", G_CALLBACK(tb80211_iface_changed_cb), NULL);
372     gtk_container_add(GTK_CONTAINER(ti), tb80211_iface_list_box);
373     gtk_widget_show(GTK_WIDGET (tb80211_iface_list_box));
374     gtk_toolbar_insert(GTK_TOOLBAR(tb80211_tb), ti, -1);
375
376     tb80211_add_label(" Frequency: ", tb80211_tb);
377
378     ti = gtk_tool_item_new();
379     gtk_widget_show(GTK_WIDGET (ti));
380     tb80211_freq_list_box = gtk_combo_box_text_new();
381 #ifdef HAVE_LIBPCAP
382     g_signal_connect(tb80211_freq_list_box, "changed", G_CALLBACK(tb80211_set_chan_cb), NULL);
383 #else
384     gtk_widget_set_sensitive(GTK_WIDGET(tb80211_freq_list_box), FALSE);
385 #endif
386     gtk_container_add(GTK_CONTAINER(ti), tb80211_freq_list_box);
387     gtk_widget_show(GTK_WIDGET (tb80211_freq_list_box));
388     gtk_toolbar_insert(GTK_TOOLBAR(tb80211_tb), ti, -1);
389
390     ti = gtk_tool_item_new();
391     gtk_widget_show(GTK_WIDGET (ti));
392     tb80211_chan_type_box = gtk_combo_box_text_new();
393 #ifdef HAVE_LIBPCAP
394     g_signal_connect(tb80211_chan_type_box, "changed", G_CALLBACK(tb80211_set_chan_cb), NULL);
395 #else
396     gtk_widget_set_sensitive(GTK_WIDGET(tb80211_freq_list_box), FALSE);
397 #endif
398     gtk_container_add(GTK_CONTAINER(ti), tb80211_chan_type_box);
399     gtk_widget_show(GTK_WIDGET (tb80211_chan_type_box));
400     gtk_toolbar_insert(GTK_TOOLBAR(tb80211_tb), ti, -1);
401
402     ti = gtk_separator_tool_item_new();
403     gtk_widget_show(GTK_WIDGET (ti));
404     gtk_toolbar_insert(GTK_TOOLBAR(tb80211_tb), ti, -1);
405
406     ti = gtk_tool_item_new();
407     gtk_widget_show(GTK_WIDGET (ti));
408     tb80211_info_label = gtk_label_new("");
409     gtk_container_add(GTK_CONTAINER(ti), tb80211_info_label);
410     gtk_widget_show(GTK_WIDGET (tb80211_info_label));
411     gtk_toolbar_insert(GTK_TOOLBAR(tb80211_tb), ti, -1);
412
413     /* make current preferences effective */
414     toolbar_redraw_all();
415
416     ret = ws80211_init();
417     if(ret) {
418         tb80211_set_info("<b>Failed to initialize ws80211</b>");
419     } else {
420         tb80211_refresh_interfaces();
421     }
422
423     return tb80211_tb;
424 }