~mdz/network-manager/ubuntu.0.7

« back to all changes in this revision

Viewing changes to src/NetworkManagerDevice.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 <errno.h>
 
23
#include <glib.h>
 
24
#include <dbus/dbus-glib.h>
 
25
#include <hal/libhal.h>
 
26
#include <iwlib.h>
 
27
#include <linux/netlink.h>
 
28
#include <linux/rtnetlink.h>
 
29
 
 
30
#include "NetworkManager.h"
 
31
#include "NetworkManagerDevice.h"
 
32
#include "NetworkManagerUtils.h"
 
33
 
 
34
extern gboolean debug;
 
35
 
 
36
static gboolean mii_get_link (NMDevice *dev);
 
37
static void nm_device_link_detection_init (NMDevice *dev);
 
38
 
 
39
/*
 
40
 * nm_device_is_wireless
 
41
 *
 
42
 * Test whether a given device is a wireless one or not.
 
43
 *
 
44
 */
 
45
static gboolean nm_device_is_wireless (NMDevice *dev)
 
46
{
 
47
        int             iwlib_socket;
 
48
        int             error;
 
49
        iwstats stats;
 
50
        
 
51
        g_return_val_if_fail (dev != NULL, FALSE);
 
52
        
 
53
        iwlib_socket = iw_sockets_open ();
 
54
        error = iw_get_stats (iwlib_socket, nm_device_get_iface (dev), &stats, NULL, FALSE);
 
55
        close (iwlib_socket);
 
56
        return (error == 0);
 
57
}
 
58
 
 
59
 
 
60
/*
 
61
 * nm_device_supports_wireless_scan
 
62
 *
 
63
 * Test whether a given device is a wireless one or not.
 
64
 *
 
65
 */
 
66
static gboolean nm_device_supports_wireless_scan (NMDevice *dev)
 
67
{
 
68
        int                                     iwlib_socket;
 
69
        int                                     error;
 
70
        iwstats                         stats;
 
71
        gboolean                                can_scan = TRUE;
 
72
        wireless_scan_head              scan_data;
 
73
        
 
74
        g_return_val_if_fail (dev != NULL, FALSE);
 
75
        
 
76
        iwlib_socket = iw_sockets_open ();
 
77
        error = iw_scan (iwlib_socket, nm_device_get_iface (dev), WIRELESS_EXT, &scan_data);
 
78
        nm_dispose_scan_results (scan_data.result);
 
79
        if ((error == -1) && (errno == EOPNOTSUPP))
 
80
                can_scan = FALSE;
 
81
        close (iwlib_socket);
 
82
        return (can_scan);
 
83
}
 
84
 
 
85
 
 
86
/*
 
87
 * nm_get_device_by_udi
 
88
 *
 
89
 * Search through the device list for a device with a given UDI.
 
90
 *
 
91
 * NOTE: the caller MUST hold the device list mutex already to make
 
92
 * this routine thread-safe.
 
93
 *
 
94
 */
 
95
NMDevice *nm_get_device_by_udi (NMData *data, const char *udi)
 
96
{
 
97
        NMDevice        *dev = NULL;
 
98
        GSList  *element;
 
99
        
 
100
        g_return_val_if_fail (data != NULL, NULL);
 
101
        g_return_val_if_fail (udi  != NULL, NULL);
 
102
 
 
103
        element = data->dev_list;
 
104
        while (element)
 
105
        {
 
106
                dev = (NMDevice *)(element->data);
 
107
                if (dev)
 
108
                {
 
109
                        if (nm_null_safe_strcmp (nm_device_get_udi (dev), udi) == 0)
 
110
                                break;
 
111
                }
 
112
 
 
113
                element = g_slist_next (element);
 
114
        }
 
115
 
 
116
        return (dev);
 
117
}
 
118
 
 
119
 
 
120
/*
 
121
 * nm_get_device_by_iface
 
122
 *
 
123
 * Search through the device list for a device with a given iface.
 
124
 *
 
125
 * NOTE: the caller MUST hold the device list mutex already to make
 
126
 * this routine thread-safe.
 
127
 *
 
128
 */
 
129
NMDevice *nm_get_device_by_iface (NMData *data, const char *iface)
 
130
{
 
131
        NMDevice        *iter_dev = NULL;
 
132
        NMDevice        *found_dev = NULL;
 
133
        GSList  *element;
 
134
        
 
135
        g_return_val_if_fail (data  != NULL, NULL);
 
136
        g_return_val_if_fail (iface != NULL, NULL);
 
137
 
 
138
        element = data->dev_list;
 
139
        while (element)
 
140
        {
 
141
                iter_dev = (NMDevice *)(element->data);
 
142
                if (iter_dev)
 
143
                {
 
144
                        if (nm_null_safe_strcmp (nm_device_get_iface (iter_dev), iface) == 0)
 
145
                        {
 
146
                                found_dev = iter_dev;
 
147
                                break;
 
148
                        }
 
149
                }
 
150
 
 
151
                element = g_slist_next (element);
 
152
        }
 
153
 
 
154
        return (found_dev);
 
155
}
 
156
 
 
157
 
 
158
/*****************************************************************************/
 
159
/* NMDevice object routines                                      */
 
160
/*****************************************************************************/
 
161
 
 
162
typedef struct NMDeviceWirelessOptions
 
163
{
 
164
        gchar                           *cur_essid;
 
165
        gboolean                                 supports_wireless_scan;
 
166
        GMutex                          *ap_list_mutex;
 
167
        GSList                          *ap_list;
 
168
} NMDeviceWirelessOptions;
 
169
 
 
170
typedef struct NMDeviceWiredOptions
 
171
{
 
172
        int     foo;
 
173
} NMDeviceWiredOptions;
 
174
 
 
175
typedef union NMDeviceOptions
 
176
{
 
177
        NMDeviceWirelessOptions wireless;
 
178
        NMDeviceWiredOptions    wired;
 
179
} NMDeviceOptions;
 
180
 
 
181
/*
 
182
 * NetworkManager device structure
 
183
 */
 
184
struct NMDevice
 
185
{
 
186
        guint                    refcount;
 
187
        gchar                   *udi;
 
188
        gchar                   *iface;
 
189
        NMIfaceType              iface_type;
 
190
        gboolean                         link_active;
 
191
        NMDeviceOptions  dev_options;
 
192
};
 
193
 
 
194
 
 
195
/*
 
196
 * nm_device_new
 
197
 *
 
198
 * Creates and initializes the structure representation of an NLM device.
 
199
 *
 
200
 */
 
201
NMDevice *nm_device_new (const char *iface)
 
202
{
 
203
        NMDevice        *dev;
 
204
 
 
205
        g_return_val_if_fail (iface != NULL, NULL);
 
206
        
 
207
        dev = g_new0 (NMDevice, 1);
 
208
        if (!dev)
 
209
        {
 
210
                NM_DEBUG_PRINT("nm_device_new() could not allocate a new device...  Not enough memory?\n");
 
211
                return (NULL);
 
212
        }
 
213
 
 
214
        dev->refcount = 1;
 
215
        dev->iface = g_strdup (iface);
 
216
        dev->iface_type = nm_device_is_wireless (dev) ?
 
217
                                                NM_IFACE_TYPE_WIRELESS_ETHERNET : NM_IFACE_TYPE_WIRED_ETHERNET;
 
218
 
 
219
        if (dev->iface_type == NM_IFACE_TYPE_WIRELESS_ETHERNET)
 
220
        {
 
221
                dev->dev_options.wireless.supports_wireless_scan = nm_device_supports_wireless_scan (dev);
 
222
 
 
223
                dev->dev_options.wireless.ap_list_mutex = g_mutex_new();
 
224
                if (!dev->dev_options.wireless.ap_list_mutex)
 
225
                {
 
226
                        g_free (dev->iface);
 
227
                        return (NULL);
 
228
                }
 
229
        }
 
230
 
 
231
        /* Have to bring the device up before checking link status.  */
 
232
        if (!nm_device_is_up (dev))
 
233
                nm_device_bring_up (dev);
 
234
        nm_device_update_link_active (dev, TRUE);
 
235
 
 
236
        return (dev);
 
237
}
 
238
 
 
239
 
 
240
/*
 
241
 * Refcounting functions
 
242
 */
 
243
void nm_device_ref (NMDevice *dev)
 
244
{
 
245
        g_return_if_fail (dev != NULL);
 
246
 
 
247
        dev->refcount++;
 
248
}
 
249
 
 
250
void nm_device_unref (NMDevice *dev)
 
251
{
 
252
        g_return_if_fail (dev != NULL);
 
253
 
 
254
        dev->refcount--;
 
255
        if (dev->refcount == 0)
 
256
        {
 
257
                nm_device_ap_list_clear (dev);
 
258
                dev->dev_options.wireless.ap_list = NULL;
 
259
 
 
260
                g_free (dev->udi);
 
261
                g_free (dev->iface);
 
262
                if (dev->iface_type == NM_IFACE_TYPE_WIRELESS_ETHERNET)
 
263
                {
 
264
                        g_free (dev->dev_options.wireless.cur_essid);
 
265
                        g_mutex_free (dev->dev_options.wireless.ap_list_mutex);
 
266
                }
 
267
 
 
268
                dev->udi = NULL;
 
269
                dev->iface = NULL;
 
270
        }
 
271
}
 
272
 
 
273
 
 
274
/*
 
275
 * Get/set functions for UDI
 
276
 */
 
277
char * nm_device_get_udi (NMDevice *dev)
 
278
{
 
279
        g_return_val_if_fail (dev != NULL, NULL);
 
280
 
 
281
        return (dev->udi);
 
282
}
 
283
 
 
284
void nm_device_set_udi (NMDevice *dev, const char *udi)
 
285
{
 
286
        g_return_if_fail (dev != NULL);
 
287
        g_return_if_fail (udi != NULL);
 
288
 
 
289
        if (dev->udi)
 
290
                g_free (dev->udi);
 
291
 
 
292
        dev->udi = g_strdup (udi);
 
293
}
 
294
 
 
295
 
 
296
/*
 
297
 * Get/set functions for iface
 
298
 */
 
299
char * nm_device_get_iface (NMDevice *dev)
 
300
{
 
301
        g_return_val_if_fail (dev != NULL, NULL);
 
302
 
 
303
        return (dev->iface);
 
304
}
 
305
 
 
306
 
 
307
/*
 
308
 * Get/set functions for iface_type
 
309
 */
 
310
guint nm_device_get_iface_type (NMDevice *dev)
 
311
{
 
312
        g_return_val_if_fail (dev != NULL, NM_IFACE_TYPE_DONT_KNOW);
 
313
 
 
314
        return (dev->iface_type);
 
315
}
 
316
 
 
317
 
 
318
/*
 
319
 * Get/set functions for link_active
 
320
 */
 
321
gboolean nm_device_get_link_active (NMDevice *dev)
 
322
{
 
323
        g_return_val_if_fail (dev != NULL, FALSE);
 
324
 
 
325
        return (dev->link_active);
 
326
}
 
327
 
 
328
void nm_device_set_link_active (NMDevice *dev, const gboolean link_active)
 
329
{
 
330
        g_return_if_fail (dev != NULL);
 
331
 
 
332
        dev->link_active = link_active;
 
333
}
 
334
 
 
335
 
 
336
/*
 
337
 * Get function for supports_wireless_scan
 
338
 */
 
339
gboolean nm_device_get_supports_wireless_scan (NMDevice *dev)
 
340
{
 
341
        g_return_val_if_fail (dev != NULL, FALSE);
 
342
 
 
343
        return (dev->dev_options.wireless.supports_wireless_scan);
 
344
}
 
345
 
 
346
 
 
347
/*
 
348
 * nm_device_update_link_active
 
349
 *
 
350
 * Updates the link state for a particular device.
 
351
 *
 
352
 */
 
353
gboolean nm_device_update_link_active (NMDevice *dev, gboolean check_mii)
 
354
{
 
355
        gboolean                link_active = FALSE;
 
356
 
 
357
        g_return_val_if_fail (dev  != NULL, FALSE);
 
358
 
 
359
        /* FIXME
 
360
         * For wireless cards, the best indicator of a "link" at this time
 
361
         * seems to be whether the card has a valid access point MAC address.
 
362
         * Is there a better way?
 
363
         */
 
364
 
 
365
        switch (nm_device_get_iface_type (dev))
 
366
        {
 
367
                case NM_IFACE_TYPE_WIRELESS_ETHERNET:
 
368
                {
 
369
                        struct iwreq            wrq;
 
370
                        int                             iwlib_socket;
 
371
 
 
372
                        iwlib_socket = iw_sockets_open ();
 
373
                        if (iw_get_ext (iwlib_socket, nm_device_get_iface (dev), SIOCGIWAP, &wrq) >= 0)
 
374
                        {
 
375
                                struct ether_addr       invalid_addr1;
 
376
                                struct ether_addr       invalid_addr2;
 
377
                                struct ether_addr       invalid_addr3;
 
378
                                struct ether_addr       ap_addr;
 
379
 
 
380
                                /* Compare the AP address the card has with invalid ethernet MAC addresses.
 
381
                                 */
 
382
                                memcpy (&ap_addr, &(wrq.u.ap_addr.sa_data), sizeof (struct ether_addr));
 
383
                                memset (&invalid_addr1, 0xFF, sizeof(struct ether_addr));
 
384
                                memset (&invalid_addr2, 0x00, sizeof(struct ether_addr));
 
385
                                memset (&invalid_addr2, 0x44, sizeof(struct ether_addr));
 
386
                                if (    (memcmp(&ap_addr, &invalid_addr1, sizeof(struct ether_addr)) != 0)
 
387
                                        && (memcmp(&ap_addr, &invalid_addr2, sizeof(struct ether_addr)) != 0)
 
388
                                        && (memcmp(&ap_addr, &invalid_addr3, sizeof(struct ether_addr)) != 0))
 
389
                                        link_active = TRUE;
 
390
                        }
 
391
                        close (iwlib_socket);
 
392
                        break;
 
393
                }
 
394
 
 
395
                case NM_IFACE_TYPE_WIRED_ETHERNET:
 
396
                {
 
397
                        if (check_mii)
 
398
                                link_active = mii_get_link (dev);
 
399
                        else
 
400
                                if (hal_device_property_exists (nm_get_global_data()->hal_ctx, nm_device_get_udi (dev), "net.ethernet.link"))
 
401
                                        link_active = hal_device_get_property_bool (nm_get_global_data()->hal_ctx, nm_device_get_udi (dev), "net.ethernet.link");
 
402
                        break;
 
403
                }
 
404
 
 
405
                default:
 
406
                        link_active = nm_device_get_link_active (dev);  /* Can't get link info for this device, so don't change link status */
 
407
                        break;
 
408
        }
 
409
 
 
410
        /* Update device link status and global state variable if the status changed */
 
411
        if (link_active != nm_device_get_link_active (dev))
 
412
        {
 
413
                nm_device_set_link_active (dev, link_active);
 
414
                nm_data_set_state_modified (nm_get_global_data(), TRUE);
 
415
        }
 
416
        return (link_active);
 
417
}
 
418
 
 
419
 
 
420
/*
 
421
 * nm_device_get_essid
 
422
 *
 
423
 * If a device is wireless, return the essid that it is attempting
 
424
 * to use.
 
425
 *
 
426
 * Returns:     allocated string containing essid.  Must be freed by caller.
 
427
 *
 
428
 */
 
429
char * nm_device_get_essid (NMDevice *dev)
 
430
{
 
431
        int                             iwlib_socket;
 
432
        int                             err;
 
433
        struct iwreq            wreq;
 
434
        char                            essid[IW_ESSID_MAX_SIZE + 1];
 
435
        
 
436
        g_return_val_if_fail (dev != NULL, NULL);
 
437
        g_return_val_if_fail (dev->iface_type == NM_IFACE_TYPE_WIRELESS_ETHERNET, NULL);
 
438
        
 
439
        iwlib_socket = iw_sockets_open ();
 
440
        if (iwlib_socket >= 0)
 
441
        {
 
442
                wreq.u.essid.pointer = (caddr_t) essid;
 
443
                wreq.u.essid.length = IW_ESSID_MAX_SIZE + 1;
 
444
                wreq.u.essid.flags = 0;
 
445
                err = iw_get_ext (iwlib_socket, nm_device_get_iface (dev), SIOCGIWESSID, &wreq);
 
446
                if (err >= 0)
 
447
                {
 
448
                        if (dev->dev_options.wireless.cur_essid)
 
449
                                g_free (dev->dev_options.wireless.cur_essid);
 
450
                        dev->dev_options.wireless.cur_essid = g_strdup (essid);
 
451
                }
 
452
                else
 
453
                        NM_DEBUG_PRINT_2 ("nm_device_get_essid(): error setting ESSID for device %s.  errno = %d\n", nm_device_get_iface (dev), errno);
 
454
 
 
455
                close (iwlib_socket);
 
456
        }
 
457
 
 
458
        return (dev->dev_options.wireless.cur_essid);
 
459
}
 
460
 
 
461
 
 
462
/*
 
463
 * nm_device_set_essid
 
464
 *
 
465
 * If a device is wireless, set the essid that it should use.
 
466
 */
 
467
void nm_device_set_essid (NMDevice *dev, const char *essid)
 
468
{
 
469
        int                             iwlib_socket;
 
470
        int                             err;
 
471
        struct iwreq            wreq;
 
472
        unsigned char           safe_essid[IW_ESSID_MAX_SIZE + 1] = "\0";
 
473
        
 
474
        g_return_if_fail (dev != NULL);
 
475
        g_return_if_fail (dev->iface_type == NM_IFACE_TYPE_WIRELESS_ETHERNET);
 
476
 
 
477
        /* Make sure the essid we get passed is a valid size */
 
478
        if (!essid)
 
479
                safe_essid[0] = '\0';
 
480
        else
 
481
        {
 
482
                strncpy (safe_essid, essid, IW_ESSID_MAX_SIZE);
 
483
                safe_essid[IW_ESSID_MAX_SIZE] = '\0';
 
484
        }
 
485
 
 
486
        iwlib_socket = iw_sockets_open ();
 
487
        if (iwlib_socket >= 0)
 
488
        {
 
489
                wreq.u.essid.pointer = (caddr_t) safe_essid;
 
490
                wreq.u.essid.length      = strlen (safe_essid) + 1;
 
491
                wreq.u.essid.flags       = 1;   /* Enable essid on card */
 
492
        
 
493
                err = iw_set_ext (iwlib_socket, nm_device_get_iface (dev), SIOCSIWESSID, &wreq);
 
494
                if (err == -1)
 
495
                        NM_DEBUG_PRINT_2 ("nm_device_set_essid(): error setting ESSID for device %s.  errno = %d\n", nm_device_get_iface (dev), errno);
 
496
 
 
497
                close (iwlib_socket);
 
498
        }
 
499
}
 
500
 
 
501
 
 
502
/*
 
503
 * nm_device_set_wep_key
 
504
 *
 
505
 * If a device is wireless, set the WEP key that it should use.
 
506
 *
 
507
 * wep_key:             WEP key to use, or NULL or "" to disable WEP
 
508
 */
 
509
void nm_device_set_wep_key (NMDevice *dev, const char *wep_key)
 
510
{
 
511
        int                             iwlib_socket;
 
512
        int                             err;
 
513
        struct iwreq            wreq;
 
514
        int                             keylen;
 
515
        unsigned char           safe_key[IW_ENCODING_TOKEN_MAX];
 
516
        gboolean                        set_key = FALSE;
 
517
        
 
518
        char *it = NULL;
 
519
        
 
520
        g_return_if_fail (dev != NULL);
 
521
        g_return_if_fail (dev->iface_type == NM_IFACE_TYPE_WIRELESS_ETHERNET);
 
522
 
 
523
        /* Make sure the essid we get passed is a valid size */
 
524
        if (!wep_key)
 
525
                safe_key[0] = '\0';
 
526
        else
 
527
        {
 
528
                strncpy (safe_key, wep_key, IW_ENCODING_TOKEN_MAX);
 
529
                safe_key[IW_ENCODING_TOKEN_MAX] = '\0';
 
530
        }
 
531
 
 
532
        iwlib_socket = iw_sockets_open ();
 
533
        if (iwlib_socket >= 0)
 
534
        {
 
535
                wreq.u.data.pointer = (caddr_t) NULL;
 
536
                wreq.u.data.flags = IW_ENCODE_ENABLED;
 
537
                wreq.u.data.length = 0;
 
538
 
 
539
                if (strlen (safe_key) == 0)
 
540
                {
 
541
                        wreq.u.data.flags = IW_ENCODE_DISABLED | IW_ENCODE_NOKEY;       /* Disable WEP */
 
542
                        set_key = TRUE;
 
543
                }
 
544
                else
 
545
                {
 
546
                        keylen = iw_in_key_full(iwlib_socket, nm_device_get_iface (dev), "", safe_key, &wreq.u.data.flags);
 
547
                        if (keylen > 0)
 
548
                        {
 
549
                                wreq.u.data.pointer     =  (caddr_t) safe_key;
 
550
                                wreq.u.data.length      =  keylen;
 
551
                                set_key = TRUE;
 
552
                        }
 
553
                }
 
554
 
 
555
                if (set_key)
 
556
                {
 
557
                        err = iw_set_ext (iwlib_socket, nm_device_get_iface (dev), SIOCSIWENCODE, &wreq);
 
558
                        if (err == -1)
 
559
                                NM_DEBUG_PRINT_2 ("nm_device_set_wep_key(): error setting key for device %s.  errno = %d\n", nm_device_get_iface (dev), errno);
 
560
                }
 
561
 
 
562
                close (iwlib_socket);
 
563
        }
 
564
}
 
565
 
 
566
 
 
567
/*
 
568
 * nm_device_set_up_down
 
569
 *
 
570
 * Set the up flag on the device on or off
 
571
 *
 
572
 */
 
573
static void nm_device_set_up_down (NMDevice *dev, gboolean up)
 
574
{
 
575
        struct ifreq    ifr;
 
576
        int                     iface_fd;
 
577
        int                     err;
 
578
        guint32         flags = up ? IFF_UP : ~IFF_UP;
 
579
 
 
580
        g_return_if_fail (dev != NULL);
 
581
 
 
582
        iface_fd = nm_get_network_control_socket ();
 
583
        if (iface_fd < 0)
 
584
                return;
 
585
 
 
586
        /* Get flags already there */
 
587
        strcpy (ifr.ifr_name, nm_device_get_iface (dev));
 
588
        err = ioctl (iface_fd, SIOCGIFFLAGS, &ifr);
 
589
        if (!err)
 
590
        {
 
591
                /* If the interface doesn't have those flags already,
 
592
                 * set them on it.
 
593
                 */
 
594
                if ((ifr.ifr_flags^flags) & IFF_UP)
 
595
                {
 
596
                        ifr.ifr_flags &= ~IFF_UP;
 
597
                        ifr.ifr_flags |= IFF_UP & flags;
 
598
                        err = ioctl (iface_fd, SIOCSIFFLAGS, &ifr);
 
599
                        if (err)
 
600
                                NM_DEBUG_PRINT_3 ("nm_device_set_up_down() could not bring device %s %s.  errno = %d\n", nm_device_get_iface (dev), (up ? "up" : "down"), errno );
 
601
                }
 
602
        }
 
603
        else
 
604
                NM_DEBUG_PRINT_2 ("nm_device_set_up_down() could not get flags for device %s.  errno = %d\n", nm_device_get_iface (dev), errno );
 
605
 
 
606
        close (iface_fd);
 
607
}
 
608
 
 
609
 
 
610
/*
 
611
 * Interface state functions: bring up, down, check
 
612
 *
 
613
 */
 
614
void nm_device_bring_up (NMDevice *dev)
 
615
{
 
616
        g_return_if_fail (dev != NULL);
 
617
 
 
618
        nm_device_set_up_down (dev, TRUE);
 
619
}
 
620
 
 
621
void nm_device_bring_down (NMDevice *dev)
 
622
{
 
623
        int                                      fd;
 
624
 
 
625
        g_return_if_fail (dev != NULL);
 
626
 
 
627
        nm_device_set_up_down (dev, FALSE);
 
628
}
 
629
 
 
630
gboolean nm_device_is_up (NMDevice *dev)
 
631
{
 
632
        int                     iface_fd;
 
633
        struct ifreq    ifr;
 
634
        int                     err;
 
635
 
 
636
        g_return_if_fail (dev != NULL);
 
637
 
 
638
        iface_fd = nm_get_network_control_socket ();
 
639
        if (iface_fd < 0)
 
640
                return (FALSE);
 
641
 
 
642
        /* Get device's flags */
 
643
        strcpy (ifr.ifr_name, nm_device_get_iface (dev));
 
644
        err = ioctl (iface_fd, SIOCGIFFLAGS, &ifr);
 
645
        close (iface_fd);
 
646
        if (!err)
 
647
                return (!((ifr.ifr_flags^IFF_UP) & IFF_UP));
 
648
 
 
649
        NM_DEBUG_PRINT_2 ("nm_device_is_up() could not get flags for device %s.  errno = %d\n", nm_device_get_iface (dev), errno );
 
650
        return (FALSE);
 
651
}
 
652
 
 
653
 
 
654
/*
 
655
 * nm_device_ap_list_add
 
656
 *
 
657
 * Add an access point to the devices internal AP list.
 
658
 *
 
659
 */
 
660
void    nm_device_ap_list_add (NMDevice *dev, NMAccessPoint *ap)
 
661
{
 
662
        g_return_if_fail (dev != NULL);
 
663
        g_return_if_fail (ap  != NULL);
 
664
        g_return_if_fail (dev->iface_type == NM_IFACE_TYPE_WIRELESS_ETHERNET);
 
665
 
 
666
        if (nm_try_acquire_mutex (dev->dev_options.wireless.ap_list_mutex, __FUNCTION__))
 
667
        {
 
668
                nm_ap_ref (ap);
 
669
                dev->dev_options.wireless.ap_list = g_slist_append (dev->dev_options.wireless.ap_list, ap);
 
670
 
 
671
                nm_unlock_mutex (dev->dev_options.wireless.ap_list_mutex, __FUNCTION__);
 
672
        }
 
673
}
 
674
 
 
675
 
 
676
/*
 
677
 * nm_device_ap_list_clear
 
678
 *
 
679
 * Clears out the device's internal list of available access points.
 
680
 *
 
681
 */
 
682
void    nm_device_ap_list_clear (NMDevice *dev)
 
683
{
 
684
        GSList  *element;
 
685
 
 
686
        g_return_if_fail (dev != NULL);
 
687
        g_return_if_fail (dev->iface_type == NM_IFACE_TYPE_WIRELESS_ETHERNET);
 
688
 
 
689
        if (!dev->dev_options.wireless.ap_list)
 
690
                return;
 
691
 
 
692
        if (nm_try_acquire_mutex (dev->dev_options.wireless.ap_list_mutex, __FUNCTION__))
 
693
        {
 
694
                element = dev->dev_options.wireless.ap_list;
 
695
                while (element)
 
696
                {
 
697
                        if (element->data)
 
698
                        {
 
699
                                nm_ap_unref (element->data);
 
700
                                element->data = NULL;
 
701
                        }
 
702
 
 
703
                        element = g_slist_next (element);
 
704
                }
 
705
 
 
706
                g_slist_free (dev->dev_options.wireless.ap_list);
 
707
                dev->dev_options.wireless.ap_list = NULL;
 
708
 
 
709
                nm_unlock_mutex (dev->dev_options.wireless.ap_list_mutex, __FUNCTION__);
 
710
        }
 
711
}
 
712
 
 
713
 
 
714
/*
 
715
 * nm_device_ap_list_get_copy
 
716
 *
 
717
 * Copy the list of ESSIDs
 
718
 *
 
719
 */
 
720
NMAccessPoint *nm_device_ap_list_get_ap (NMDevice *dev, int index)
 
721
{
 
722
        GSList          *element;
 
723
        NMAccessPoint   *ap = NULL;
 
724
 
 
725
        g_return_val_if_fail (dev != NULL, NULL);
 
726
        g_return_val_if_fail (dev->iface_type == NM_IFACE_TYPE_WIRELESS_ETHERNET, NULL);
 
727
 
 
728
        if (!dev->dev_options.wireless.ap_list)
 
729
                return;
 
730
 
 
731
        if (nm_try_acquire_mutex (dev->dev_options.wireless.ap_list_mutex, __FUNCTION__))
 
732
        {
 
733
                int     i = 0;
 
734
 
 
735
                element = dev->dev_options.wireless.ap_list;
 
736
                while (element)
 
737
                {
 
738
                        if (element->data && (index == i))
 
739
                        {
 
740
                                ap = (NMAccessPoint *)(element->data);
 
741
                                break;
 
742
                        }
 
743
 
 
744
                        i++;
 
745
                        element = g_slist_next (element);
 
746
                }
 
747
                nm_unlock_mutex (dev->dev_options.wireless.ap_list_mutex, __FUNCTION__);
 
748
        }
 
749
 
 
750
        return (ap);
 
751
}
 
752
 
 
753
 
 
754
/****************************************/
 
755
/* Code ripped from HAL                 */
 
756
/*   minor modifications made for       */
 
757
/* integration with NLM                 */
 
758
/****************************************/
 
759
 
 
760
/** Read a word from the MII transceiver management registers 
 
761
 *
 
762
 *  @param  iface               Which interface
 
763
 *  @param  location            Which register
 
764
 *  @return                     Word that is read
 
765
 */
 
766
static guint16 mdio_read (int sockfd, struct ifreq *ifr, int location, gboolean new_ioctl_nums)
 
767
{
 
768
        guint16 *data = (guint16 *) &(ifr->ifr_data);
 
769
 
 
770
        data[1] = location;
 
771
        if (ioctl (sockfd, new_ioctl_nums ? 0x8948 : SIOCDEVPRIVATE + 1, ifr) < 0)
 
772
        {
 
773
                NM_DEBUG_PRINT_2("SIOCGMIIREG on %s failed: %s\n", ifr->ifr_name, strerror (errno));
 
774
                return -1;
 
775
        }
 
776
        return data[3];
 
777
}
 
778
 
 
779
static gboolean mii_get_link (NMDevice *dev)
 
780
{
 
781
        int                     sockfd;
 
782
        struct ifreq    ifr;
 
783
        gboolean                new_ioctl_nums;
 
784
        guint16         status_word;
 
785
        gboolean                link_active = FALSE;
 
786
 
 
787
        sockfd = socket (AF_INET, SOCK_DGRAM, 0);
 
788
        if (sockfd < 0)
 
789
        {
 
790
                NM_DEBUG_PRINT_2("cannot open socket on interface %s; errno=%d", nm_device_get_iface (dev), errno);
 
791
                return (FALSE);
 
792
        }
 
793
 
 
794
        snprintf (ifr.ifr_name, IFNAMSIZ, nm_device_get_iface (dev));
 
795
        if (ioctl (sockfd, 0x8947, &ifr) >= 0)
 
796
                new_ioctl_nums = TRUE;
 
797
        else if (ioctl (sockfd, SIOCDEVPRIVATE, &ifr) >= 0)
 
798
                new_ioctl_nums = FALSE;
 
799
        else
 
800
        {
 
801
                NM_DEBUG_PRINT_2("SIOCGMIIPHY on %s failed: %s", ifr.ifr_name, strerror (errno));
 
802
                close (sockfd);
 
803
                return (FALSE);
 
804
        }
 
805
 
 
806
        /* Refer to http://www.scyld.com/diag/mii-status.html for
 
807
         * the full explanation of the numbers
 
808
         *
 
809
         * 0x8000  Capable of 100baseT4.
 
810
         * 0x7800  Capable of 10/100 HD/FD (most common).
 
811
         * 0x0040  Preamble suppression permitted.
 
812
         * 0x0020  Autonegotiation complete.
 
813
         * 0x0010  Remote fault.
 
814
         * 0x0008  Capable of Autonegotiation.
 
815
         * 0x0004  Link established ("sticky"* on link failure)
 
816
         * 0x0002  Jabber detected ("sticky"* on transmit jabber)
 
817
         * 0x0001  Extended MII register exist.
 
818
         *
 
819
         */
 
820
 
 
821
        /* We have to read it twice to clear any "sticky" bits */
 
822
        status_word = mdio_read (sockfd, &ifr, 1, new_ioctl_nums);
 
823
        status_word = mdio_read (sockfd, &ifr, 1, new_ioctl_nums);
 
824
 
 
825
        if ((status_word & 0x0016) == 0x0004)
 
826
                link_active = TRUE;
 
827
        else
 
828
                link_active = FALSE;
 
829
 
 
830
        close (sockfd);
 
831
 
 
832
        return (link_active);
 
833
}
 
834
 
 
835
/****************************************/
 
836
/* End Code ripped from HAL             */
 
837
/****************************************/