~mdz/network-manager/ubuntu.0.7

« back to all changes in this revision

Viewing changes to src/NetworkManagerPolicy.c

  • Committer: dcbw
  • Date: 2004-06-24 14:18:37 UTC
  • Revision ID: vcs-imports@canonical.com-20040624141837-b23a721fd03ea23f
Initial revision

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* NetworkManager -- Network link manager
 
2
 *
 
3
 * Dan Williams <dcbw@redhat.com>
 
4
 *
 
5
 * This program is free software; you can redistribute it and/or modify
 
6
 * it under the terms of the GNU General Public License as published by
 
7
 * the Free Software Foundation; either version 2 of the License, or
 
8
 * (at your option) any later version.
 
9
 *
 
10
 * This program is distributed in the hope that it will be useful,
 
11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
13
 * GNU General Public License for more details.
 
14
 *
 
15
 * You should have received a copy of the GNU General Public License
 
16
 * along with this program; if not, write to the Free Software
 
17
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 
18
 *
 
19
 * (C) Copyright 2004 Red Hat, Inc.
 
20
 */
 
21
 
 
22
#include <stdio.h>
 
23
#include <unistd.h>
 
24
#include <errno.h>
 
25
#include <sys/types.h>
 
26
#include <sys/stat.h>
 
27
#include <fcntl.h>
 
28
 
 
29
#include "NetworkManagerPolicy.h"
 
30
#include "NetworkManagerUtils.h"
 
31
#include "NetworkManagerAP.h"
 
32
 
 
33
extern gboolean debug;
 
34
 
 
35
 
 
36
/*
 
37
 * nm_policy_activate_interface
 
38
 *
 
39
 * Performs interface switching and related networking goo.
 
40
 *
 
41
 */
 
42
static void nm_policy_switch_interface (NMData *data, NMDevice *switch_to_dev, NMDevice *old_dev)
 
43
{
 
44
        unsigned char                    buf[500];
 
45
        unsigned char                    hostname[500] = "\0";
 
46
        const unsigned char             *new_iface;
 
47
        int                                      host_err;
 
48
        int                                      dhclient_err;
 
49
        FILE                                    *pidfile;
 
50
        unsigned char                    pid[20];
 
51
 
 
52
        g_return_if_fail (data != NULL);
 
53
        g_return_if_fail (switch_to_dev != NULL);
 
54
        g_return_if_fail (nm_device_get_iface (switch_to_dev));
 
55
        g_return_if_fail (strlen (nm_device_get_iface (switch_to_dev)) >= 0);
 
56
 
 
57
        /* If its a wireless device, set the ESSID and WEP key */
 
58
        if (nm_device_get_iface_type (switch_to_dev) == NM_IFACE_TYPE_WIRELESS_ETHERNET)
 
59
        {
 
60
                /* If there is a desired AP to connect to, use that essid and possible WEP key */
 
61
                if (    data->desired_ap
 
62
                        && (nm_ap_get_essid (data->desired_ap) != NULL))
 
63
                {
 
64
                        nm_device_bring_down (switch_to_dev);
 
65
 
 
66
                        nm_device_set_essid (switch_to_dev, nm_ap_get_essid (data->desired_ap));
 
67
 
 
68
                        /* Disable WEP */
 
69
                        nm_device_set_wep_key (switch_to_dev, NULL);
 
70
                        if (nm_ap_get_wep_key (data->desired_ap))
 
71
                                nm_device_set_wep_key (switch_to_dev, nm_ap_get_wep_key (data->desired_ap));
 
72
                }
 
73
                else
 
74
                {
 
75
                        /* If the card isn't up, bring it up so that we can scan.  We may be too early here to have
 
76
                         * gotten all the scanning results, and therefore have no desired_ap.  Just wait.
 
77
                         */
 
78
                        if (!nm_device_is_up (switch_to_dev));
 
79
                                nm_device_bring_up (switch_to_dev);
 
80
 
 
81
                        NM_DEBUG_PRINT ("nm_policy_activate_interface() could not find a desired AP.  Card doesn't support scanning?\n");
 
82
                        return;         /* Don't associate with any non-allowed access points */
 
83
                }
 
84
 
 
85
                NM_DEBUG_PRINT_1 ("nm_policy_activate_interface() using essid '%s'\n", nm_ap_get_essid (data->desired_ap));
 
86
        }
 
87
 
 
88
        host_err = gethostname (hostname, 500);
 
89
 
 
90
        /* Take out any entries in the routing table and any IP address the old interface
 
91
         * had.
 
92
         */
 
93
        if (old_dev && strlen (nm_device_get_iface (old_dev)))
 
94
        {
 
95
                /* Remove routing table entries */
 
96
                snprintf (buf, 500, "/sbin/ip route flush dev %s", nm_device_get_iface (old_dev));
 
97
                system (buf);
 
98
 
 
99
                /* Remove ip address */
 
100
                snprintf (buf, 500, "/sbin/ip address flush dev %s", nm_device_get_iface (old_dev));
 
101
                system (buf);
 
102
        }
 
103
 
 
104
        /* Bring the device up */
 
105
        if (!nm_device_is_up (switch_to_dev));
 
106
                nm_device_bring_up (switch_to_dev);
 
107
 
 
108
        /* Kill the old default route */
 
109
        snprintf (buf, 500, "/sbin/ip route del default");
 
110
        system (buf);
 
111
 
 
112
        /* Find and kill the previous dhclient process for this interface */
 
113
        new_iface = nm_device_get_iface (switch_to_dev);
 
114
        snprintf (buf, 500, "/var/run/dhclient-%s.pid", new_iface);
 
115
        pidfile = fopen (buf, "r");
 
116
        if (pidfile)
 
117
        {
 
118
                int     len;
 
119
 
 
120
                fgets (pid, 20, pidfile);
 
121
                len = strnlen (buf, 20);
 
122
                if (len >= 20)
 
123
                        pid[0] = '\0';
 
124
                else
 
125
                        pid[len-1] = '\0';
 
126
                fclose (pidfile);
 
127
 
 
128
                snprintf (buf, 500, "kill -9 %s", pid);
 
129
                system (buf);
 
130
        }
 
131
 
 
132
        snprintf (buf, 500, "/sbin/dhclient -1 -q -lf /var/lib/dhcp/dhclient-%s.leases -pf /var/run/dhclient-%s.pid -cf /etc/dhclient-%s.conf %s\n",
 
133
                                        new_iface, new_iface, new_iface, new_iface);
 
134
        dhclient_err = system (buf);
 
135
        if (dhclient_err != 0)
 
136
        {
 
137
                /* Wireless devices cannot be down if they are the active interface,
 
138
                 * otherwise we cannot use them for scanning.
 
139
                 */
 
140
                if (nm_device_get_iface_type (switch_to_dev) == NM_IFACE_TYPE_WIRELESS_ETHERNET)
 
141
                {
 
142
                        nm_device_set_essid (switch_to_dev, "");
 
143
                        nm_device_set_wep_key (switch_to_dev, NULL);
 
144
                        nm_device_bring_up (switch_to_dev);
 
145
                }
 
146
        }
 
147
 
 
148
        /* Set the hostname back to what it was before so that X11 doesn't
 
149
         * puke when the hostname changes, so that users can actually launch stuff.
 
150
         */
 
151
        if (host_err >= 0)
 
152
                sethostname (hostname, strlen (hostname));
 
153
 
 
154
        /* Restart the nameservice caching daemon to make apps aware of new DNS servers */
 
155
        snprintf (buf, 500, "/sbin/service nscd restart");
 
156
        system (buf);
 
157
}
 
158
 
 
159
 
 
160
/*
 
161
 * nm_state_modification_monitor
 
162
 *
 
163
 * Called every 2s and figures out which interface to switch the active
 
164
 * network connection to if our global network state has changed.
 
165
 * Global network state changes are triggered by:
 
166
 *    1) insertion/deletion of interfaces
 
167
 *    2) link state change of an interface
 
168
 *    3) appearance/disappearance of an allowed wireless access point
 
169
 *
 
170
 */
 
171
gboolean nm_state_modification_monitor (gpointer user_data)
 
172
{
 
173
        NMData  *data = (NMData *)user_data;
 
174
        gboolean                         modified = FALSE;
 
175
 
 
176
        g_return_val_if_fail (data != NULL, TRUE);
 
177
 
 
178
        /* Check global state modified variable, and reset it with
 
179
         * appropriate locking.
 
180
         */
 
181
        g_mutex_lock (data->state_modified_mutex);
 
182
        modified = data->state_modified;
 
183
        if (data->state_modified)
 
184
                data->state_modified = FALSE;
 
185
        g_mutex_unlock (data->state_modified_mutex);
 
186
 
 
187
        /* If any modifications to the data model were made, update
 
188
         * network state based on policy applied to the data model.
 
189
         */
 
190
        if (modified)
 
191
        {
 
192
                if (nm_try_acquire_mutex (data->dev_list_mutex, __FUNCTION__))
 
193
                {
 
194
                        GSList          *element = data->dev_list;
 
195
                        NMDevice                *dev = NULL;
 
196
                        NMDevice                *best_wired_dev = NULL;
 
197
                        guint            best_wired_prio = 0;
 
198
                        NMDevice                *best_wireless_dev = NULL;
 
199
                        guint            best_wireless_prio = 0;
 
200
                        guint            highest_priority = 0;
 
201
                        NMDevice                *highest_priority_dev = NULL;
 
202
                        gboolean                 essid_change_needed = FALSE;
 
203
 
 
204
                        while (element)
 
205
                        {
 
206
                                guint   priority = 0;
 
207
                                guint   iface_type;
 
208
                                gboolean        link_active;
 
209
 
 
210
                                dev = (NMDevice *)(element->data);
 
211
 
 
212
                                iface_type = nm_device_get_iface_type (dev);
 
213
                                link_active = nm_device_get_link_active (dev);
 
214
 
 
215
                                if (iface_type == NM_IFACE_TYPE_WIRED_ETHERNET)
 
216
                                {
 
217
                                        guint   prio = 0;
 
218
 
 
219
                                        if (link_active)
 
220
                                                prio += 1;
 
221
 
 
222
                                        if (data->active_device
 
223
                                                && (dev == data->active_device)
 
224
                                                && link_active)
 
225
                                                prio += 1;
 
226
                                        if (prio > best_wired_prio)
 
227
                                        {
 
228
                                                best_wired_dev = dev;
 
229
                                                best_wired_prio = prio;
 
230
                                        }
 
231
                                }
 
232
                                else if (iface_type == NM_IFACE_TYPE_WIRELESS_ETHERNET)
 
233
                                {
 
234
                                        guint   prio = 0;
 
235
 
 
236
                                        if (link_active)
 
237
                                                prio += 1;
 
238
 
 
239
                                        if (nm_device_get_supports_wireless_scan (dev))
 
240
                                                prio += 2;
 
241
 
 
242
                                        if (    data->active_device
 
243
                                                && (dev == data->active_device)
 
244
                                                && link_active)
 
245
                                                prio += 3;
 
246
 
 
247
                                        if (prio > best_wireless_prio)
 
248
                                        {
 
249
                                                best_wireless_dev = dev;
 
250
                                                best_wireless_prio = prio;
 
251
                                        }
 
252
                                }
 
253
 
 
254
                                element = g_slist_next (element);
 
255
                        }
 
256
 
 
257
                        NM_DEBUG_PRINT_1 ("Best wired device = %s\n", best_wired_dev ? nm_device_get_iface (best_wired_dev) : "(null)");
 
258
                        NM_DEBUG_PRINT_1 ("Best wireless device = %s\n", best_wireless_dev ? nm_device_get_iface (best_wireless_dev) : "(null)");
 
259
 
 
260
                        if (best_wireless_dev || best_wired_dev)
 
261
                        {
 
262
                                if (best_wired_dev)
 
263
                                        highest_priority_dev = best_wired_dev;
 
264
                                else
 
265
                                        highest_priority_dev = best_wireless_dev;
 
266
                        }
 
267
                        else
 
268
                        {
 
269
                                /* No devices at all, wait for them to change status */
 
270
                                nm_unlock_mutex (data->dev_list_mutex, __FUNCTION__);
 
271
                                return (TRUE);
 
272
                        }
 
273
 
 
274
                        /* If the current essid of the wireless card and the desired ap's essid are different,
 
275
                         * trigger an interface switch.  We switch to the same interface, but we still need to bring
 
276
                         * the device up again to get a new DHCP address.  However, don't switch if there is no
 
277
                         * desired ap.
 
278
                         */
 
279
                        if (nm_device_get_iface_type (highest_priority_dev) == NM_IFACE_TYPE_WIRELESS_ETHERNET)
 
280
                        {
 
281
                                /* If we don't yet have a desired AP, attempt to get one. */
 
282
                                if (!data->desired_ap)
 
283
                                        nm_wireless_do_scan (data, highest_priority_dev);
 
284
 
 
285
                                if (    data->desired_ap
 
286
                                        && (nm_null_safe_strcmp (nm_device_get_essid (highest_priority_dev), nm_ap_get_essid (data->desired_ap)) != 0)
 
287
                                        && (strlen (nm_ap_get_essid (data->desired_ap)) > 0))
 
288
                                                essid_change_needed = TRUE;
 
289
                        }
 
290
 
 
291
                        /* If the highest priority device is different than data->active_device, switch the connection. */
 
292
                        if (    essid_change_needed
 
293
                                || (!data->active_device || (highest_priority_dev == data->active_device)))
 
294
                        {
 
295
 
 
296
                                NM_DEBUG_PRINT_2 ("**** Switching active interface from '%s' to '%s'\n",
 
297
                                                data->active_device ? nm_device_get_iface (data->active_device) : "(null)",
 
298
                                                nm_device_get_iface (highest_priority_dev));
 
299
 
 
300
                                /* FIXME
 
301
                                 * How long should we wait between the signal to the bus,
 
302
                                 * and deactivating the device?
 
303
                                 */
 
304
                                if (data->active_device)
 
305
                                {
 
306
                                        nm_dbus_signal_device_no_longer_active (data->dbus_connection, data->active_device);
 
307
                                        sleep (2);
 
308
                                }
 
309
 
 
310
                                nm_policy_switch_interface (data, highest_priority_dev, data->active_device);
 
311
 
 
312
                                if (data->active_device)
 
313
                                        nm_device_unref (data->active_device);
 
314
                                data->active_device = highest_priority_dev;
 
315
                                nm_device_ref (data->active_device);
 
316
 
 
317
                                nm_dbus_signal_device_now_active (data->dbus_connection, data->active_device);
 
318
 
 
319
                                NM_DEBUG_PRINT ("**** Switched.\n");
 
320
                        }
 
321
 
 
322
                        nm_unlock_mutex (data->dev_list_mutex, __FUNCTION__);
 
323
                }
 
324
                else
 
325
                        NM_DEBUG_PRINT("nm_state_modification_monitor() could not get device list mutex\n");
 
326
        }
 
327
 
 
328
        return (TRUE);
 
329
}
 
330
 
 
331
 
 
332
/*
 
333
 * nm_policy_update_allowed_access_points
 
334
 *
 
335
 * Grabs a list of allowed access points from the user's preferences
 
336
 *
 
337
 */
 
338
void nm_policy_update_allowed_access_points     (NMData *data)
 
339
{
 
340
#define NM_ALLOWED_AP_FILE              "/etc/sysconfig/networking/allowed_access_points"
 
341
 
 
342
        FILE            *ap_file;
 
343
 
 
344
        g_return_if_fail (data != NULL);
 
345
 
 
346
        if (nm_try_acquire_mutex (data->allowed_ap_list_mutex, NULL))
 
347
        {
 
348
                ap_file = fopen (NM_ALLOWED_AP_FILE, "r");
 
349
                if (ap_file)
 
350
                {
 
351
                        gchar   line[ 500 ];
 
352
                        gchar   prio[ 20 ];
 
353
                        gchar   essid[ 50 ];
 
354
                        gchar   wep_key[ 50 ];
 
355
                        
 
356
                        /* Free the old list of allowed access points */
 
357
                        nm_data_allowed_ap_list_free (data);
 
358
 
 
359
                        while (fgets (line, 499, ap_file))
 
360
                        {
 
361
                                guint    len = strnlen (line, 499);
 
362
                                gchar   *p = &line[0];
 
363
                                gchar   *end = strchr (line, '\n');
 
364
                                guint    op = 0;
 
365
 
 
366
                                strcpy (prio, "\0");
 
367
                                strcpy (essid, "\0");
 
368
                                strcpy (wep_key, "\0");
 
369
 
 
370
                                if (end)
 
371
                                        *end = '\0';
 
372
                                else
 
373
                                        end = p + len - 1;
 
374
 
 
375
                                while ((end-p > 0) && (*p=='\t'))
 
376
                                        p++;
 
377
 
 
378
                                while (end-p > 0)
 
379
                                {
 
380
                                        switch (op)
 
381
                                        {
 
382
                                                case 0:
 
383
                                                        strncat (prio, p, 1);
 
384
                                                        break;
 
385
                                                case 1:
 
386
                                                        strncat (essid, p, 1);
 
387
                                                        break;
 
388
                                                case 2:
 
389
                                                        strncat (wep_key, p, 1);
 
390
                                                        break;
 
391
                                                default:
 
392
                                                        break;
 
393
                                        }
 
394
                                        p++;
 
395
 
 
396
                                        if ((end-p > 0) && (*p=='\t'))
 
397
                                        {
 
398
                                                op++;
 
399
                                                while ((end-p > 0) && (*p=='\t'))
 
400
                                                        p++;
 
401
                                        }
 
402
                                }
 
403
 
 
404
                                /* Create a new entry for this essid */
 
405
                                if (strlen (essid) > 0)
 
406
                                {
 
407
                                        NMAccessPoint           *ap;
 
408
                                        guint                                            prio_num = atoi (prio);
 
409
 
 
410
                                        if (prio_num < 1)
 
411
                                                prio_num = NM_AP_PRIORITY_WORST;
 
412
                                        else if (prio_num > NM_AP_PRIORITY_WORST)
 
413
                                                prio_num = NM_AP_PRIORITY_WORST;
 
414
 
 
415
                                        ap = nm_ap_new ();
 
416
                                        nm_ap_set_priority (ap, prio_num);
 
417
                                        nm_ap_set_essid (ap, essid);
 
418
                                        nm_ap_set_wep_key (ap, wep_key);
 
419
 
 
420
                                        data->allowed_ap_list = g_slist_append (data->allowed_ap_list, ap);
 
421
                                        /*
 
422
                                        NM_DEBUG_PRINT_3( "FOUND: allowed ap, prio=%d  essid=%s  wep_key=%s\n", prio_num, essid, wep_key );
 
423
                                        */
 
424
                                }
 
425
                        }
 
426
 
 
427
                        fclose (ap_file);
 
428
                }
 
429
                else
 
430
                        NM_DEBUG_PRINT_1( "nm_policy_update_allowed_access_points() could not open and lock allowed ap list file %s.  errno %d\n", NM_ALLOWED_AP_FILE );
 
431
        
 
432
                nm_unlock_mutex (data->allowed_ap_list_mutex, NULL);
 
433
        }
 
434
        else
 
435
                NM_DEBUG_PRINT( "nm_policy_update_allowed_access_points() could not lock allowed ap list mutex\n" );
 
436
}
 
437