~ubuntu-branches/ubuntu/utopic/network-manager-applet/utopic-proposed

« back to all changes in this revision

Viewing changes to src/connection-editor/page-bond.c

  • Committer: Package Import Robot
  • Author(s): Mathieu Trudel-Lapierre
  • Date: 2012-11-19 14:46:29 UTC
  • mfrom: (1.2.31)
  • Revision ID: package-import@ubuntu.com-20121119144629-5423hii02a4vrh2n
Tags: 0.9.6.2+git201211052130.2d666bc-0ubuntu1
* upstream snapshot 2012-11-05 21:30:03 (GMT)
  + 2d666bc7aa6f0b731d131319b36f07b0f2bdce16
* debian/patches/git_fix_some_leaks_80ef61b.patch,
  debian/patches/git_indicate_hspa+_lte_tech_dbe3b12.patch,
  debian/patches/git_mac_addr_string_leakage_6dae878.patch: dropped, included
  in upstream tarball.
* debian/patches/lp328572-dxteam-connect-text.patch: refreshed.
* debian/patches/lp330571_dxteam_wired_connect_text.patch: refreshed.
* debian/patches/lp337960_dxteam_notification_icon_names.diff,
  debian/patches/lp337960_dxteam_notification_icon_names_part2-images.diff:
  disabled patches, they don't seem to be used (the icons don't match up with
  what is currently observable on the desktop). Let's see if someone screams.
* debian/patches/applet-wifi-menu-before-vpn.patch: refreshed.
* debian/patches/lp830178_adhoc_ip6_ignore.patch: refreshed.
* debian/patches/lp829673_gconf_hide_applet.patch: refreshed.
* debian/patches/nm-applet-use-indicator.patch: refreshed.
* debian/patches/hide_policy_items_env_var.patch: refreshed.
* debian/patches/applet_adhoc_use_wpa_rsn_part1.patch: refreshed.
* debian/patches/lp341684_device_sensitive_disconnect_notify.patch:
  refreshed.
* debian/patches/lp460144_correctly_update_notification.patch: refreshed.
* debian/patches/make_menu_items_insensitive_based_on_permissions.patch:
  refreshed.
* debian/control:
  - add gobject-introspection to Build-Depends.
  - add gudev-dev to Build-Depends.
  - bump network-manager and libnm-* Build-Depends and Depends to require
    at least 0.9.6.0+git201211131441.e9e2c56-0ubuntu1.
* debian/rules:
  - use autogen.sh with dh_autoreconf instead of calling intltoolize and
    gtkdocize manually.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
 
2
/* NetworkManager Connection editor -- Connection editor for NetworkManager
 
3
 *
 
4
 * This program is free software; you can redistribute it and/or modify
 
5
 * it under the terms of the GNU General Public License as published by
 
6
 * the Free Software Foundation; either version 2 of the License, or
 
7
 * (at your option) any later version.
 
8
 *
 
9
 * This program is distributed in the hope that it will be useful,
 
10
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
11
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
12
 * GNU General Public License for more details.
 
13
 *
 
14
 * You should have received a copy of the GNU General Public License along
 
15
 * with this program; if not, write to the Free Software Foundation, Inc.,
 
16
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 
17
 *
 
18
 * Copyright 2012 Red Hat, Inc.
 
19
 */
 
20
 
 
21
#include "config.h"
 
22
 
 
23
#include <stdlib.h>
 
24
#include <gtk/gtk.h>
 
25
#include <glib/gi18n.h>
 
26
 
 
27
#include <nm-setting-connection.h>
 
28
#include <nm-setting-bond.h>
 
29
 
 
30
#include "page-bond.h"
 
31
#include "page-ethernet.h"
 
32
#include "page-infiniband.h"
 
33
#include "nm-connection-editor.h"
 
34
#include "new-connection.h"
 
35
 
 
36
G_DEFINE_TYPE (CEPageBond, ce_page_bond, CE_TYPE_PAGE)
 
37
 
 
38
#define CE_PAGE_BOND_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), CE_TYPE_PAGE_BOND, CEPageBondPrivate))
 
39
 
 
40
typedef struct {
 
41
        NMRemoteConnection *connection;
 
42
        NMClient *client;
 
43
        NMRemoteSettings *settings;
 
44
 
 
45
        NMSettingBond *setting;
 
46
        const char *uuid;
 
47
 
 
48
        GType slave_type;
 
49
        PageNewConnectionFunc new_slave_func;
 
50
 
 
51
        GtkWindow *toplevel;
 
52
 
 
53
        GtkEntry *interface_name;
 
54
        GtkComboBox *mode;
 
55
        GtkComboBox *monitoring;
 
56
        GtkSpinButton *frequency;
 
57
        GtkSpinButton *updelay;
 
58
        GtkWidget *updelay_label;
 
59
        GtkWidget *updelay_box;
 
60
        GtkSpinButton *downdelay;
 
61
        GtkWidget *downdelay_label;
 
62
        GtkWidget *downdelay_box;
 
63
        GtkEntry *arp_targets;
 
64
        GtkWidget *arp_targets_label;
 
65
 
 
66
        GtkTable *table;
 
67
        int table_row_spacing;
 
68
        int updelay_row;
 
69
        int downdelay_row;
 
70
        int arp_targets_row;
 
71
 
 
72
        GtkTreeView *connections;
 
73
        GtkTreeModel *connections_model;
 
74
        GtkButton *add, *edit, *delete;
 
75
 
 
76
} CEPageBondPrivate;
 
77
 
 
78
#define MODE_BALANCE_RR    0
 
79
#define MODE_ACTIVE_BACKUP 1
 
80
#define MODE_BALANCE_XOR   2
 
81
#define MODE_BROADCAST     3
 
82
#define MODE_802_3AD       4
 
83
#define MODE_BALANCE_TLB   5
 
84
#define MODE_BALANCE_ALB   6
 
85
 
 
86
#define MONITORING_MII 0
 
87
#define MONITORING_ARP 1
 
88
 
 
89
enum {
 
90
        COL_CONNECTION,
 
91
        COL_NAME
 
92
};
 
93
 
 
94
static int
 
95
name_sort_func (GtkTreeModel *model, GtkTreeIter *a, GtkTreeIter *b, gpointer user_data)
 
96
{
 
97
        NMConnection *conn_a, *conn_b;
 
98
        int ret;
 
99
 
 
100
        /* We fetch COL_CONNECTION rather than COL_NAME to avoid a strdup/free. */
 
101
        gtk_tree_model_get (model, a, COL_CONNECTION, &conn_a, -1);
 
102
        gtk_tree_model_get (model, b, COL_CONNECTION, &conn_b, -1);
 
103
        ret = strcmp (nm_connection_get_id (conn_a), nm_connection_get_id (conn_b));
 
104
        g_object_unref (conn_a);
 
105
        g_object_unref (conn_b);
 
106
 
 
107
        return ret;
 
108
}
 
109
 
 
110
static void
 
111
bond_private_init (CEPageBond *self)
 
112
{
 
113
        CEPageBondPrivate *priv = CE_PAGE_BOND_GET_PRIVATE (self);
 
114
        GtkBuilder *builder;
 
115
 
 
116
        builder = CE_PAGE (self)->builder;
 
117
 
 
118
        priv->interface_name = GTK_ENTRY (gtk_builder_get_object (builder, "bond_interface"));
 
119
        priv->connections = GTK_TREE_VIEW (gtk_builder_get_object (builder, "bond_connections"));
 
120
        priv->connections_model = GTK_TREE_MODEL (gtk_builder_get_object (builder, "bond_connections_model"));
 
121
        gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE (priv->connections_model),
 
122
                                         COL_NAME, name_sort_func,
 
123
                                         NULL, NULL);
 
124
        gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (priv->connections_model),
 
125
                                              COL_NAME, GTK_SORT_ASCENDING);
 
126
 
 
127
        priv->mode = GTK_COMBO_BOX (gtk_builder_get_object (builder, "bond_mode"));
 
128
        priv->monitoring = GTK_COMBO_BOX (gtk_builder_get_object (builder, "bond_monitoring"));
 
129
        priv->frequency = GTK_SPIN_BUTTON (gtk_builder_get_object (builder, "bond_frequency"));
 
130
        priv->updelay = GTK_SPIN_BUTTON (gtk_builder_get_object (builder, "bond_updelay"));
 
131
        priv->updelay_label = GTK_WIDGET (gtk_builder_get_object (builder, "bond_updelay_label"));
 
132
        priv->updelay_box = GTK_WIDGET (gtk_builder_get_object (builder, "bond_updelay_box"));
 
133
        priv->downdelay = GTK_SPIN_BUTTON (gtk_builder_get_object (builder, "bond_downdelay"));
 
134
        priv->downdelay_label = GTK_WIDGET (gtk_builder_get_object (builder, "bond_downdelay_label"));
 
135
        priv->downdelay_box = GTK_WIDGET (gtk_builder_get_object (builder, "bond_downdelay_box"));
 
136
        priv->arp_targets = GTK_ENTRY (gtk_builder_get_object (builder, "bond_arp_targets"));
 
137
        priv->arp_targets_label = GTK_WIDGET (gtk_builder_get_object (builder, "bond_arp_targets_label"));
 
138
        priv->add = GTK_BUTTON (gtk_builder_get_object (builder, "bond_connection_add"));
 
139
        priv->edit = GTK_BUTTON (gtk_builder_get_object (builder, "bond_connection_edit"));
 
140
        priv->delete = GTK_BUTTON (gtk_builder_get_object (builder, "bond_connection_delete"));
 
141
 
 
142
        priv->toplevel = GTK_WINDOW (gtk_widget_get_ancestor (GTK_WIDGET (priv->connections),
 
143
                                                              GTK_TYPE_WINDOW));
 
144
 
 
145
        priv->table = GTK_TABLE (gtk_builder_get_object (builder, "BondPage"));
 
146
        priv->table_row_spacing = gtk_table_get_default_row_spacing (priv->table);
 
147
        gtk_container_child_get (GTK_CONTAINER (priv->table), priv->updelay_label,
 
148
                                 "top-attach", &priv->updelay_row,
 
149
                                 NULL);
 
150
        gtk_container_child_get (GTK_CONTAINER (priv->table), priv->downdelay_label,
 
151
                                 "top-attach", &priv->downdelay_row,
 
152
                                 NULL);
 
153
        gtk_container_child_get (GTK_CONTAINER (priv->table), priv->arp_targets_label,
 
154
                                 "top-attach", &priv->arp_targets_row,
 
155
                                 NULL);
 
156
}
 
157
 
 
158
static void
 
159
dispose (GObject *object)
 
160
{
 
161
        CEPageBond *self = CE_PAGE_BOND (object);
 
162
        CEPageBondPrivate *priv = CE_PAGE_BOND_GET_PRIVATE (self);
 
163
        GtkTreeIter iter;
 
164
 
 
165
        if (priv->settings) {
 
166
                g_signal_handlers_disconnect_matched (priv->settings, G_SIGNAL_MATCH_DATA,
 
167
                                                      0, 0, NULL, NULL, self);
 
168
                g_object_unref (priv->settings);
 
169
                priv->settings = NULL;
 
170
        }
 
171
        if (priv->client) {
 
172
                g_object_unref (priv->client);
 
173
                priv->client = NULL;
 
174
        }
 
175
        if (priv->connection) {
 
176
                g_object_unref (priv->connection);
 
177
                priv->connection = NULL;
 
178
        }
 
179
 
 
180
        if (gtk_tree_model_get_iter_first (priv->connections_model, &iter)) {
 
181
                do {
 
182
                        NMRemoteConnection *connection = NULL;
 
183
 
 
184
                        gtk_tree_model_get (priv->connections_model, &iter,
 
185
                                            COL_CONNECTION, &connection,
 
186
                                            -1);
 
187
                        g_signal_handlers_disconnect_matched (connection, G_SIGNAL_MATCH_DATA,
 
188
                                                              0, 0, NULL, NULL, self);
 
189
                        g_object_unref (connection);
 
190
                } while (gtk_tree_model_iter_next (priv->connections_model, &iter));
 
191
        }
 
192
 
 
193
        G_OBJECT_CLASS (ce_page_bond_parent_class)->dispose (object);
 
194
}
 
195
 
 
196
static void
 
197
stuff_changed (GtkWidget *w, gpointer user_data)
 
198
{
 
199
        ce_page_changed (CE_PAGE (user_data));
 
200
}
 
201
 
 
202
static void
 
203
connection_removed (NMRemoteConnection *connection, gpointer user_data)
 
204
{
 
205
        CEPageBond *self = CE_PAGE_BOND (user_data);
 
206
        CEPageBondPrivate *priv = CE_PAGE_BOND_GET_PRIVATE (self);
 
207
        GtkTreeIter iter;
 
208
 
 
209
        if (!gtk_tree_model_get_iter_first (priv->connections_model, &iter))
 
210
                return;
 
211
 
 
212
        do {
 
213
                NMRemoteConnection *candidate = NULL;
 
214
 
 
215
                gtk_tree_model_get (priv->connections_model, &iter,
 
216
                                    COL_CONNECTION, &candidate,
 
217
                                    -1);
 
218
                if (candidate == connection) {
 
219
                        gtk_list_store_remove (GTK_LIST_STORE (priv->connections_model), &iter);
 
220
                        stuff_changed (NULL, self);
 
221
 
 
222
                        if (!gtk_tree_model_get_iter_first (priv->connections_model, &iter)) {
 
223
                                priv->slave_type = G_TYPE_INVALID;
 
224
                                priv->new_slave_func = NULL;
 
225
                        }
 
226
                        return;
 
227
                }
 
228
        } while (gtk_tree_model_iter_next (priv->connections_model, &iter));
 
229
}
 
230
 
 
231
static void
 
232
connection_added (NMRemoteSettings *settings,
 
233
                  NMRemoteConnection *connection,
 
234
                  gpointer user_data)
 
235
{
 
236
        CEPageBond *self = CE_PAGE_BOND (user_data);
 
237
        CEPageBondPrivate *priv = CE_PAGE_BOND_GET_PRIVATE (self);
 
238
        NMSettingConnection *s_con;
 
239
        const char *slave_type, *master;
 
240
        const char *interface_name;
 
241
        GtkTreeIter iter;
 
242
 
 
243
        s_con = nm_connection_get_setting_connection (NM_CONNECTION (connection));
 
244
        if (!s_con)
 
245
                return;
 
246
 
 
247
        slave_type = nm_setting_connection_get_slave_type (s_con);
 
248
        if (!slave_type || strcmp (slave_type, NM_SETTING_BOND_SETTING_NAME) != 0)
 
249
                return;
 
250
 
 
251
        master = nm_setting_connection_get_master (s_con);
 
252
        if (!master)
 
253
                return;
 
254
 
 
255
        interface_name = nm_setting_bond_get_interface_name (priv->setting);
 
256
        if (!strcmp (master, interface_name)) {
 
257
                /* Ugh. Fix that... */
 
258
                g_object_set (G_OBJECT (connection),
 
259
                              NM_SETTING_CONNECTION_MASTER, priv->uuid,
 
260
                              NULL);
 
261
                nm_remote_connection_commit_changes (connection, NULL, NULL);
 
262
        } else if (strcmp (master, priv->uuid) != 0)
 
263
                return;
 
264
 
 
265
        gtk_list_store_append (GTK_LIST_STORE (priv->connections_model), &iter);
 
266
        gtk_list_store_set (GTK_LIST_STORE (priv->connections_model), &iter,
 
267
                            COL_CONNECTION, connection,
 
268
                            COL_NAME, nm_setting_connection_get_id (s_con),
 
269
                            -1);
 
270
        stuff_changed (NULL, self);
 
271
 
 
272
        /* FIXME: a bit kludgy */
 
273
        if (nm_connection_is_type (NM_CONNECTION (connection), NM_SETTING_INFINIBAND_SETTING_NAME)) {
 
274
                priv->slave_type = NM_TYPE_SETTING_INFINIBAND;
 
275
                priv->new_slave_func = infiniband_connection_new;
 
276
                gtk_combo_box_set_active (priv->mode, MODE_ACTIVE_BACKUP);
 
277
                gtk_widget_set_sensitive (GTK_WIDGET (priv->mode), FALSE);
 
278
        } else {
 
279
                priv->slave_type = NM_TYPE_SETTING_WIRED;
 
280
                priv->new_slave_func = ethernet_connection_new;
 
281
                gtk_widget_set_sensitive (GTK_WIDGET (priv->mode), TRUE);
 
282
        }
 
283
 
 
284
        g_signal_connect (connection, NM_REMOTE_CONNECTION_REMOVED,
 
285
                          G_CALLBACK (connection_removed), self);
 
286
}
 
287
 
 
288
static void
 
289
monitoring_mode_changed (GtkComboBox *combo, gpointer user_data)
 
290
{
 
291
        CEPageBond *self = user_data;
 
292
        CEPageBondPrivate *priv = CE_PAGE_BOND_GET_PRIVATE (self);
 
293
 
 
294
        if (gtk_combo_box_get_active (combo) == MONITORING_MII) {
 
295
                gtk_widget_show (GTK_WIDGET (priv->updelay));
 
296
                gtk_widget_show (priv->updelay_label);
 
297
                gtk_widget_show (priv->updelay_box);
 
298
                gtk_widget_show (GTK_WIDGET (priv->downdelay));
 
299
                gtk_widget_show (priv->downdelay_label);
 
300
                gtk_widget_show (priv->downdelay_box);
 
301
                gtk_widget_hide (GTK_WIDGET (priv->arp_targets));
 
302
                gtk_widget_hide (priv->arp_targets_label);
 
303
 
 
304
                gtk_table_set_row_spacing (priv->table, priv->updelay_row, priv->table_row_spacing);
 
305
                gtk_table_set_row_spacing (priv->table, priv->downdelay_row, priv->table_row_spacing);
 
306
                gtk_table_set_row_spacing (priv->table, priv->arp_targets_row, 0);
 
307
        } else {
 
308
                gtk_widget_hide (GTK_WIDGET (priv->updelay));
 
309
                gtk_widget_hide (priv->updelay_label);
 
310
                gtk_widget_hide (priv->updelay_box);
 
311
                gtk_widget_hide (GTK_WIDGET (priv->downdelay));
 
312
                gtk_widget_hide (priv->downdelay_label);
 
313
                gtk_widget_hide (priv->downdelay_box);
 
314
                gtk_widget_show (GTK_WIDGET (priv->arp_targets));
 
315
                gtk_widget_show (priv->arp_targets_label);
 
316
 
 
317
                gtk_table_set_row_spacing (priv->table, priv->updelay_row, 0);
 
318
                gtk_table_set_row_spacing (priv->table, priv->downdelay_row, 0);
 
319
                gtk_table_set_row_spacing (priv->table, priv->arp_targets_row, priv->table_row_spacing);
 
320
        }
 
321
}
 
322
 
 
323
static void
 
324
frequency_changed (GtkSpinButton *button, gpointer user_data)
 
325
{
 
326
        CEPageBond *self = user_data;
 
327
        CEPageBondPrivate *priv = CE_PAGE_BOND_GET_PRIVATE (self);
 
328
        int frequency, delay;
 
329
 
 
330
        frequency = gtk_spin_button_get_value_as_int (priv->frequency);
 
331
 
 
332
        /* Round updelay and downdelay up to a multiple of frequency */
 
333
 
 
334
        delay = gtk_spin_button_get_value_as_int (priv->updelay);
 
335
        if (frequency == 0) {
 
336
                if (delay != 0)
 
337
                        gtk_spin_button_set_value (priv->updelay, 0.0);
 
338
        } else if (delay % frequency) {
 
339
                delay += frequency - (delay % frequency);
 
340
                gtk_spin_button_set_value (priv->updelay, delay);
 
341
        }
 
342
        gtk_spin_button_set_increments (priv->updelay, frequency, frequency);
 
343
 
 
344
        delay = gtk_spin_button_get_value_as_int (priv->downdelay);
 
345
        if (frequency == 0) {
 
346
                if (delay != 0)
 
347
                        gtk_spin_button_set_value (priv->downdelay, 0.0);
 
348
        } else if (delay % frequency) {
 
349
                delay += frequency - (delay % frequency);
 
350
                gtk_spin_button_set_value (priv->downdelay, (gdouble)delay);
 
351
        }
 
352
        gtk_spin_button_set_increments (priv->downdelay, frequency, frequency);
 
353
}
 
354
 
 
355
static void
 
356
delay_changed (GtkSpinButton *button, gpointer user_data)
 
357
{
 
358
        CEPageBond *self = user_data;
 
359
        CEPageBondPrivate *priv = CE_PAGE_BOND_GET_PRIVATE (self);
 
360
        int frequency, delay;
 
361
 
 
362
        /* Clamp to nearest multiple of frequency */
 
363
 
 
364
        frequency = gtk_spin_button_get_value_as_int (priv->frequency);
 
365
        delay = gtk_spin_button_get_value_as_int (button);
 
366
        if (frequency == 0) {
 
367
                if (delay != 0)
 
368
                        gtk_spin_button_set_value (button, 0.0);
 
369
        } else if (delay % frequency) {
 
370
                if (delay % frequency < frequency / 2)
 
371
                        delay -= delay % frequency;
 
372
                else
 
373
                        delay += frequency - (delay % frequency);
 
374
                gtk_spin_button_set_value (button, (gdouble)delay);
 
375
        }
 
376
}
 
377
 
 
378
static char *
 
379
prettify_targets (const char *text)
 
380
{
 
381
        char **addrs, *targets;
 
382
 
 
383
        if (!text || !*text)
 
384
                return NULL;
 
385
 
 
386
        addrs = g_strsplit (text, ",", -1);
 
387
        targets = g_strjoinv (", ", addrs);
 
388
        g_strfreev (addrs);
 
389
 
 
390
        return targets;
 
391
}
 
392
 
 
393
static char *
 
394
uglify_targets (const char *text)
 
395
{
 
396
        char **addrs, *targets;
 
397
        int i;
 
398
 
 
399
        if (!text || !*text)
 
400
                return NULL;
 
401
 
 
402
        addrs = g_strsplit (text, ",", -1);
 
403
        for (i = 0; addrs[i]; i++)
 
404
                g_strstrip (addrs[i]);
 
405
        targets = g_strjoinv (",", addrs);
 
406
        g_strfreev (addrs);
 
407
 
 
408
        return targets;
 
409
}
 
410
 
 
411
static void
 
412
populate_ui (CEPageBond *self)
 
413
{
 
414
        CEPageBondPrivate *priv = CE_PAGE_BOND_GET_PRIVATE (self);
 
415
        NMSettingBond *setting = priv->setting;
 
416
        NMSettingConnection *s_con;
 
417
        const char *iface;
 
418
        GSList *connections, *c;
 
419
        const char *mode, *frequency, *updelay, *downdelay, *raw_targets;
 
420
        char *targets;
 
421
        int mode_idx = MODE_BALANCE_RR;
 
422
 
 
423
        s_con = nm_connection_get_setting_connection (NM_CONNECTION (priv->connection));
 
424
        g_return_if_fail (s_con != NULL);
 
425
 
 
426
        /* Interface name */
 
427
        iface = nm_setting_bond_get_interface_name (setting);
 
428
        gtk_entry_set_text (priv->interface_name, iface ? iface : "");
 
429
 
 
430
        /* Bonded connections */
 
431
        connections = nm_remote_settings_list_connections (priv->settings);
 
432
        for (c = connections; c; c = c->next)
 
433
                connection_added (priv->settings, c->data, self);
 
434
 
 
435
        /* Mode */
 
436
        mode = nm_setting_bond_get_option_by_name (setting, NM_SETTING_BOND_OPTION_MODE);
 
437
        if (mode) {
 
438
                if (!strcmp (mode, "balance-rr"))
 
439
                        mode_idx = MODE_BALANCE_RR;
 
440
                else if (!strcmp (mode, "active-backup"))
 
441
                        mode_idx = MODE_ACTIVE_BACKUP;
 
442
                else if (!strcmp (mode, "balance-xor"))
 
443
                        mode_idx = MODE_BALANCE_XOR;
 
444
                else if (!strcmp (mode, "broadcast"))
 
445
                        mode_idx = MODE_BROADCAST;
 
446
                else if (!strcmp (mode, "802.3ad"))
 
447
                        mode_idx = MODE_802_3AD;
 
448
                else if (!strcmp (mode, "balance-tlb"))
 
449
                        mode_idx = MODE_BALANCE_TLB;
 
450
                else if (!strcmp (mode, "balance-alb"))
 
451
                        mode_idx = MODE_BALANCE_ALB;
 
452
        }
 
453
        gtk_combo_box_set_active (priv->mode, mode_idx);
 
454
 
 
455
        /* Monitoring mode/frequency */
 
456
        frequency = nm_setting_bond_get_option_by_name (setting, NM_SETTING_BOND_OPTION_ARP_INTERVAL);
 
457
        if (frequency) {
 
458
                gtk_combo_box_set_active (priv->monitoring, MONITORING_ARP);
 
459
        } else {
 
460
                gtk_combo_box_set_active (priv->monitoring, MONITORING_MII);
 
461
                frequency = nm_setting_bond_get_option_by_name (setting, NM_SETTING_BOND_OPTION_MIIMON);
 
462
        }
 
463
        g_signal_connect (priv->monitoring, "changed",
 
464
                          G_CALLBACK (monitoring_mode_changed),
 
465
                          self);
 
466
        monitoring_mode_changed (priv->monitoring, self);
 
467
 
 
468
        if (frequency)
 
469
                gtk_spin_button_set_value (priv->frequency, (gdouble) atoi (frequency));
 
470
        else
 
471
                gtk_spin_button_set_value (priv->frequency, 0.0);
 
472
        g_signal_connect (priv->frequency, "value-changed",
 
473
                          G_CALLBACK (frequency_changed),
 
474
                          self);
 
475
 
 
476
        updelay = nm_setting_bond_get_option_by_name (setting, NM_SETTING_BOND_OPTION_UPDELAY);
 
477
        if (updelay)
 
478
                gtk_spin_button_set_value (priv->updelay, (gdouble) atoi (updelay));
 
479
        else
 
480
                gtk_spin_button_set_value (priv->updelay, 0.0);
 
481
        g_signal_connect (priv->updelay, "value-changed",
 
482
                          G_CALLBACK (delay_changed),
 
483
                          self);
 
484
        downdelay = nm_setting_bond_get_option_by_name (setting, NM_SETTING_BOND_OPTION_DOWNDELAY);
 
485
        if (downdelay)
 
486
                gtk_spin_button_set_value (priv->downdelay, (gdouble) atoi (downdelay));
 
487
        else
 
488
                gtk_spin_button_set_value (priv->downdelay, 0.0);
 
489
        g_signal_connect (priv->downdelay, "value-changed",
 
490
                          G_CALLBACK (delay_changed),
 
491
                          self);
 
492
 
 
493
        /* ARP targets */
 
494
        raw_targets = nm_setting_bond_get_option_by_name (setting, NM_SETTING_BOND_OPTION_ARP_IP_TARGET);
 
495
        targets = prettify_targets (raw_targets);
 
496
        if (targets) {
 
497
                gtk_entry_set_text (priv->arp_targets, targets);
 
498
                g_free (targets);
 
499
        }
 
500
}
 
501
 
 
502
static void
 
503
connections_selection_changed_cb (GtkTreeSelection *selection, gpointer user_data)
 
504
{
 
505
        CEPageBond *self = user_data;
 
506
        CEPageBondPrivate *priv = CE_PAGE_BOND_GET_PRIVATE (self);
 
507
        GtkTreeIter iter;
 
508
        GtkTreeModel *model;
 
509
        NMRemoteConnection *connection;
 
510
        NMSettingConnection *s_con;
 
511
        gboolean sensitive = FALSE;
 
512
 
 
513
        if (gtk_tree_selection_get_selected (selection, &model, &iter)) {
 
514
                gtk_tree_model_get (model, &iter,
 
515
                                    0, &connection,
 
516
                                    -1);
 
517
                s_con = nm_connection_get_setting_connection (NM_CONNECTION (connection));
 
518
                g_assert (s_con);
 
519
        
 
520
                sensitive = !nm_setting_connection_get_read_only (s_con);
 
521
        }
 
522
 
 
523
        gtk_widget_set_sensitive (GTK_WIDGET (priv->edit), sensitive);
 
524
        gtk_widget_set_sensitive (GTK_WIDGET (priv->delete), sensitive);
 
525
}
 
526
 
 
527
static void
 
528
add_response_cb (NMConnectionEditor *editor, NMRemoteConnection *connection,
 
529
                 gboolean added, gpointer user_data)
 
530
{
 
531
        g_object_unref (editor);
 
532
}
 
533
 
 
534
static void
 
535
add_bond_connection (NMConnection *connection,
 
536
                     gpointer user_data)
 
537
{
 
538
        CEPageBond *self = user_data;
 
539
        CEPageBondPrivate *priv = CE_PAGE_BOND_GET_PRIVATE (self);
 
540
        NMSettingConnection *s_con;
 
541
        NMConnectionEditor *editor;
 
542
        const char *iface_name;
 
543
        char *name;
 
544
 
 
545
        if (!connection)
 
546
                return;
 
547
 
 
548
        /* Mark the connection as a bond slave so that the editor knows not
 
549
         * to add IPv4 and IPv6 pages, and rename it.
 
550
         */
 
551
        s_con = nm_connection_get_setting_connection (connection);
 
552
        g_assert (s_con != NULL);
 
553
 
 
554
        iface_name = gtk_entry_get_text (priv->interface_name);
 
555
        if (!*iface_name)
 
556
                iface_name = nm_setting_bond_get_interface_name (priv->setting);
 
557
        if (!*iface_name)
 
558
                iface_name = "bond";
 
559
        name = g_strdup_printf (_("%s slave %d"), iface_name,
 
560
                                gtk_tree_model_iter_n_children (priv->connections_model, NULL) + 1);
 
561
 
 
562
        g_object_set (G_OBJECT (s_con),
 
563
                      NM_SETTING_CONNECTION_ID, name,
 
564
                      NM_SETTING_CONNECTION_MASTER, priv->uuid,
 
565
                      NM_SETTING_CONNECTION_SLAVE_TYPE, NM_SETTING_BOND_SETTING_NAME,
 
566
                      NM_SETTING_CONNECTION_AUTOCONNECT, FALSE,
 
567
                      NULL);
 
568
        g_free (name);
 
569
 
 
570
        editor = nm_connection_editor_new (priv->toplevel,
 
571
                                           connection,
 
572
                                           priv->client,
 
573
                                           priv->settings);
 
574
        if (!editor) {
 
575
                g_object_unref (connection);
 
576
                return;
 
577
        }
 
578
 
 
579
        g_signal_connect (editor, "done", G_CALLBACK (add_response_cb), self);
 
580
        nm_connection_editor_run (editor);
 
581
}
 
582
 
 
583
static gboolean
 
584
connection_type_filter (GType type, gpointer user_data)
 
585
{
 
586
        if (type == NM_TYPE_SETTING_WIRED ||
 
587
            type == NM_TYPE_SETTING_INFINIBAND)
 
588
                return TRUE;
 
589
        else
 
590
                return FALSE;
 
591
}
 
592
 
 
593
static void
 
594
add_clicked (GtkButton *button, gpointer user_data)
 
595
{
 
596
        CEPageBond *self = user_data;
 
597
        CEPageBondPrivate *priv = CE_PAGE_BOND_GET_PRIVATE (self);
 
598
 
 
599
        if (priv->new_slave_func) {
 
600
                new_connection_of_type (priv->toplevel,
 
601
                                        NULL,
 
602
                                        priv->settings,
 
603
                                        priv->new_slave_func,
 
604
                                        add_bond_connection,
 
605
                                        self);
 
606
        } else {
 
607
                new_connection_dialog (priv->toplevel,
 
608
                                       priv->settings,
 
609
                                       connection_type_filter,
 
610
                                       add_bond_connection,
 
611
                                       self);
 
612
        }
 
613
}
 
614
 
 
615
static NMRemoteConnection *
 
616
get_selected_connection (CEPageBond *self)
 
617
{
 
618
        CEPageBondPrivate *priv = CE_PAGE_BOND_GET_PRIVATE (self);
 
619
        GtkTreeSelection *selection;
 
620
        GList *selected_rows;
 
621
        GtkTreeModel *model = NULL;
 
622
        GtkTreeIter iter;
 
623
        NMRemoteConnection *connection = NULL;
 
624
 
 
625
        selection = gtk_tree_view_get_selection (priv->connections);
 
626
        selected_rows = gtk_tree_selection_get_selected_rows (selection, &model);
 
627
        if (!selected_rows)
 
628
                return NULL;
 
629
 
 
630
        if (gtk_tree_model_get_iter (model, &iter, (GtkTreePath *) selected_rows->data))
 
631
                gtk_tree_model_get (model, &iter, 0, &connection, -1);
 
632
 
 
633
        /* free memory */
 
634
        g_list_foreach (selected_rows, (GFunc) gtk_tree_path_free, NULL);
 
635
        g_list_free (selected_rows);
 
636
 
 
637
        return connection;
 
638
}
 
639
 
 
640
static void
 
641
edit_done_cb (NMConnectionEditor *editor, GtkResponseType response, gpointer user_data)
 
642
{
 
643
        g_object_unref (editor);
 
644
}
 
645
 
 
646
static void
 
647
edit_clicked (GtkButton *button, gpointer user_data)
 
648
{
 
649
        CEPageBond *self = user_data;
 
650
        CEPageBondPrivate *priv = CE_PAGE_BOND_GET_PRIVATE (self);
 
651
        NMConnectionEditor *editor;
 
652
        NMRemoteConnection *connection;
 
653
 
 
654
        connection = get_selected_connection (self);
 
655
        if (!connection)
 
656
                return;
 
657
 
 
658
        editor = nm_connection_editor_get (NM_CONNECTION (connection));
 
659
        if (editor) {
 
660
                nm_connection_editor_present (editor);
 
661
                return;
 
662
        }
 
663
 
 
664
        editor = nm_connection_editor_new (priv->toplevel,
 
665
                                           NM_CONNECTION (connection),
 
666
                                           priv->client,
 
667
                                           priv->settings);
 
668
        if (!editor)
 
669
                return;
 
670
 
 
671
        g_signal_connect (editor, "done", G_CALLBACK (edit_done_cb), self);
 
672
        nm_connection_editor_run (editor);
 
673
}
 
674
 
 
675
static void
 
676
connection_double_clicked_cb (GtkTreeView *tree_view,
 
677
                              GtkTreePath *path,
 
678
                              GtkTreeViewColumn *column,
 
679
                              gpointer user_data)
 
680
{
 
681
        edit_clicked (NULL, user_data);
 
682
}
 
683
 
 
684
static void
 
685
delete_clicked (GtkButton *button, gpointer user_data)
 
686
{
 
687
        CEPageBond *self = user_data;
 
688
        CEPageBondPrivate *priv = CE_PAGE_BOND_GET_PRIVATE (self);
 
689
        NMRemoteConnection *connection;
 
690
 
 
691
        connection = get_selected_connection (self);
 
692
        if (!connection)
 
693
                return;
 
694
 
 
695
        delete_connection (priv->toplevel, connection, NULL, NULL);
 
696
}
 
697
 
 
698
static void
 
699
finish_setup (CEPageBond *self, gpointer unused, GError *error, gpointer user_data)
 
700
{
 
701
        CEPageBondPrivate *priv = CE_PAGE_BOND_GET_PRIVATE (self);
 
702
        GtkTreeSelection *selection;
 
703
 
 
704
        if (error)
 
705
                return;
 
706
 
 
707
        populate_ui (self);
 
708
 
 
709
        g_signal_connect (priv->interface_name, "changed", G_CALLBACK (stuff_changed), self);
 
710
        g_signal_connect (priv->mode, "changed", G_CALLBACK (stuff_changed), self);
 
711
        g_signal_connect (priv->monitoring, "changed", G_CALLBACK (stuff_changed), self);
 
712
        g_signal_connect (priv->frequency, "value-changed", G_CALLBACK (stuff_changed), self);
 
713
        g_signal_connect (priv->updelay, "value-changed", G_CALLBACK (stuff_changed), self);
 
714
        g_signal_connect (priv->downdelay, "value-changed", G_CALLBACK (stuff_changed), self);
 
715
        g_signal_connect (priv->arp_targets, "changed", G_CALLBACK (stuff_changed), self);
 
716
 
 
717
        g_signal_connect (priv->add, "clicked", G_CALLBACK (add_clicked), self);
 
718
        g_signal_connect (priv->edit, "clicked", G_CALLBACK (edit_clicked), self);
 
719
        g_signal_connect (priv->delete, "clicked", G_CALLBACK (delete_clicked), self);
 
720
 
 
721
        g_signal_connect (priv->connections, "row-activated", G_CALLBACK (connection_double_clicked_cb), self);
 
722
 
 
723
        selection = gtk_tree_view_get_selection (priv->connections);
 
724
        g_signal_connect (selection, "changed", G_CALLBACK (connections_selection_changed_cb), self);
 
725
        connections_selection_changed_cb (selection, self);
 
726
}
 
727
 
 
728
CEPage *
 
729
ce_page_bond_new (NMConnection *connection,
 
730
                                  GtkWindow *parent_window,
 
731
                                  NMClient *client,
 
732
                  NMRemoteSettings *settings,
 
733
                                  const char **out_secrets_setting_name,
 
734
                                  GError **error)
 
735
{
 
736
        CEPageBond *self;
 
737
        CEPageBondPrivate *priv;
 
738
        NMSettingConnection *s_con;
 
739
 
 
740
        self = CE_PAGE_BOND (ce_page_new (CE_TYPE_PAGE_BOND,
 
741
                                          connection,
 
742
                                          parent_window,
 
743
                                          client,
 
744
                                          settings,
 
745
                                          UIDIR "/ce-page-bond.ui",
 
746
                                          "BondPage",
 
747
                                          _("Bond")));
 
748
        if (!self) {
 
749
                g_set_error_literal (error, NMA_ERROR, NMA_ERROR_GENERIC,
 
750
                                     _("Could not load bond user interface."));
 
751
                return NULL;
 
752
        }
 
753
 
 
754
        bond_private_init (self);
 
755
        priv = CE_PAGE_BOND_GET_PRIVATE (self);
 
756
 
 
757
        priv->connection = g_object_ref (connection);
 
758
        priv->client = g_object_ref (client);
 
759
        priv->settings = g_object_ref (settings);
 
760
 
 
761
        s_con = nm_connection_get_setting_connection (connection);
 
762
        priv->uuid = nm_setting_connection_get_uuid (s_con);
 
763
 
 
764
        g_signal_connect (settings, NM_REMOTE_SETTINGS_NEW_CONNECTION,
 
765
                          G_CALLBACK (connection_added), self);
 
766
 
 
767
        priv->setting = (NMSettingBond *) nm_connection_get_setting (connection, NM_TYPE_SETTING_BOND);
 
768
        if (!priv->setting) {
 
769
                priv->setting = NM_SETTING_BOND (nm_setting_bond_new ());
 
770
                nm_connection_add_setting (connection, NM_SETTING (priv->setting));
 
771
        }
 
772
 
 
773
        g_signal_connect (self, "initialized", G_CALLBACK (finish_setup), NULL);
 
774
 
 
775
        return CE_PAGE (self);
 
776
}
 
777
 
 
778
static void
 
779
ui_to_setting (CEPageBond *self)
 
780
{
 
781
        CEPageBondPrivate *priv = CE_PAGE_BOND_GET_PRIVATE (self);
 
782
        const char *interface_name;
 
783
        const char *mode;
 
784
        const char *frequency;
 
785
        const char *updelay;
 
786
        const char *downdelay;
 
787
        char *targets;
 
788
 
 
789
        /* Interface name */
 
790
        interface_name = gtk_entry_get_text (priv->interface_name);
 
791
        g_object_set (priv->setting,
 
792
                      NM_SETTING_BOND_INTERFACE_NAME, interface_name,
 
793
                      NULL);
 
794
 
 
795
        /* Mode */
 
796
        switch (gtk_combo_box_get_active (priv->mode)) {
 
797
        case MODE_BALANCE_RR:
 
798
                mode = "balance-rr";
 
799
                break;
 
800
        case MODE_ACTIVE_BACKUP:
 
801
                mode = "active-backup";
 
802
                break;
 
803
        case MODE_BALANCE_XOR:
 
804
                mode = "balance-xor";
 
805
                break;
 
806
        case MODE_BROADCAST:
 
807
                mode = "broadcast";
 
808
                break;
 
809
        case MODE_802_3AD:
 
810
                mode = "802.3ad";
 
811
                break;
 
812
        case MODE_BALANCE_TLB:
 
813
                mode = "balance-tlb";
 
814
                break;
 
815
        case MODE_BALANCE_ALB:
 
816
                mode = "balance-alb";
 
817
                break;
 
818
        default:
 
819
                g_assert_not_reached ();
 
820
                break;
 
821
        }
 
822
 
 
823
        /* Monitoring mode/frequency */
 
824
        frequency = gtk_entry_get_text (GTK_ENTRY (priv->frequency));
 
825
        updelay = gtk_entry_get_text (GTK_ENTRY (priv->updelay));
 
826
        downdelay = gtk_entry_get_text (GTK_ENTRY (priv->downdelay));
 
827
        targets = uglify_targets (gtk_entry_get_text (priv->arp_targets));
 
828
 
 
829
        switch (gtk_combo_box_get_active (priv->monitoring)) {
 
830
        case MONITORING_MII:
 
831
                nm_setting_bond_add_option (priv->setting, NM_SETTING_BOND_OPTION_MIIMON, frequency);
 
832
                nm_setting_bond_add_option (priv->setting, NM_SETTING_BOND_OPTION_UPDELAY, updelay);
 
833
                nm_setting_bond_add_option (priv->setting, NM_SETTING_BOND_OPTION_DOWNDELAY, downdelay);
 
834
                nm_setting_bond_remove_option (priv->setting, NM_SETTING_BOND_OPTION_ARP_INTERVAL);
 
835
                nm_setting_bond_remove_option (priv->setting, NM_SETTING_BOND_OPTION_ARP_IP_TARGET);
 
836
                break;
 
837
        case MONITORING_ARP:
 
838
                nm_setting_bond_add_option (priv->setting, NM_SETTING_BOND_OPTION_ARP_INTERVAL, frequency);
 
839
                if (targets)
 
840
                        nm_setting_bond_add_option (priv->setting, NM_SETTING_BOND_OPTION_ARP_IP_TARGET, targets);
 
841
                else
 
842
                        nm_setting_bond_remove_option (priv->setting, NM_SETTING_BOND_OPTION_ARP_IP_TARGET);
 
843
                nm_setting_bond_remove_option (priv->setting, NM_SETTING_BOND_OPTION_MIIMON);
 
844
                nm_setting_bond_remove_option (priv->setting, NM_SETTING_BOND_OPTION_UPDELAY);
 
845
                nm_setting_bond_remove_option (priv->setting, NM_SETTING_BOND_OPTION_DOWNDELAY);
 
846
                break;
 
847
        default:
 
848
                g_assert_not_reached ();
 
849
                break;
 
850
        }
 
851
 
 
852
        g_free (targets);
 
853
 
 
854
        /* Slaves are updated as they're edited, so nothing to do */
 
855
}
 
856
 
 
857
static gboolean
 
858
validate (CEPage *page, NMConnection *connection, GError **error)
 
859
{
 
860
        CEPageBond *self = CE_PAGE_BOND (page);
 
861
        CEPageBondPrivate *priv = CE_PAGE_BOND_GET_PRIVATE (self);
 
862
        GtkTreeIter iter;
 
863
 
 
864
        /* Need at least one slave connection; we don't need to
 
865
         * recursively check that the connections are valid because they
 
866
         * can't end up in the table if they're not.
 
867
         */
 
868
        if (!gtk_tree_model_get_iter_first (priv->connections_model, &iter))
 
869
                return FALSE;
 
870
 
 
871
        ui_to_setting (self);
 
872
        return nm_setting_verify (NM_SETTING (priv->setting), NULL, error);
 
873
}
 
874
 
 
875
static void
 
876
ce_page_bond_init (CEPageBond *self)
 
877
{
 
878
}
 
879
 
 
880
static void
 
881
ce_page_bond_class_init (CEPageBondClass *bond_class)
 
882
{
 
883
        GObjectClass *object_class = G_OBJECT_CLASS (bond_class);
 
884
        CEPageClass *parent_class = CE_PAGE_CLASS (bond_class);
 
885
 
 
886
        g_type_class_add_private (object_class, sizeof (CEPageBondPrivate));
 
887
 
 
888
        /* virtual methods */
 
889
        object_class->dispose = dispose;
 
890
 
 
891
        parent_class->validate = validate;
 
892
}
 
893
 
 
894
 
 
895
void
 
896
bond_connection_new (GtkWindow *parent,
 
897
                     const char *detail,
 
898
                     NMRemoteSettings *settings,
 
899
                     PageNewConnectionResultFunc result_func,
 
900
                     gpointer user_data)
 
901
{
 
902
        NMConnection *connection;
 
903
        int bond_num, max_bond_num, num;
 
904
        GSList *connections, *iter;
 
905
        NMConnection *conn2;
 
906
        NMSettingBond *s_bond;
 
907
        const char *iface;
 
908
        char *my_iface;
 
909
 
 
910
        connection = ce_page_new_connection (_("Bond connection %d"),
 
911
                                             NM_SETTING_BOND_SETTING_NAME,
 
912
                                             TRUE,
 
913
                                             settings,
 
914
                                             user_data);
 
915
        nm_connection_add_setting (connection, nm_setting_bond_new ());
 
916
 
 
917
        /* Find an available interface name */
 
918
        bond_num = max_bond_num = 0;
 
919
        connections = nm_remote_settings_list_connections (settings);
 
920
        for (iter = connections; iter; iter = iter->next) {
 
921
                conn2 = iter->data;
 
922
 
 
923
                if (!nm_connection_is_type (conn2, NM_SETTING_BOND_SETTING_NAME))
 
924
                        continue;
 
925
                s_bond = nm_connection_get_setting_bond (conn2);
 
926
                if (!s_bond)
 
927
                        continue;
 
928
                iface = nm_setting_bond_get_interface_name (s_bond);
 
929
                if (!iface || strncmp (iface, "bond", 4) != 0 || !g_ascii_isdigit (iface[4]))
 
930
                        continue;
 
931
 
 
932
                num = atoi (iface + 4);
 
933
                if (num > max_bond_num)
 
934
                        max_bond_num = num;
 
935
                if (num == bond_num)
 
936
                        bond_num = max_bond_num + 1;
 
937
        }
 
938
        g_slist_free (connections);
 
939
 
 
940
        my_iface = g_strdup_printf ("bond%d", bond_num);
 
941
        s_bond = nm_connection_get_setting_bond (connection);
 
942
        g_object_set (G_OBJECT (s_bond),
 
943
                      NM_SETTING_BOND_INTERFACE_NAME, my_iface,
 
944
                      NULL);
 
945
        g_free (my_iface);
 
946
 
 
947
        (*result_func) (connection, FALSE, NULL, user_data);
 
948
}
 
949