~cyphermox/ubuntu/natty/connman/release-0.64

« back to all changes in this revision

Viewing changes to src/rtnl.c

  • Committer: Mathieu Trudel-Lapierre
  • Date: 2010-11-30 15:51:10 UTC
  • mfrom: (1.1.13 upstream)
  • Revision ID: mathieu.trudel-lapierre@canonical.com-20101130155110-32g0usyc4jbl131x
New upstream release 0.64.

Show diffs side-by-side

added added

removed removed

Lines of Context:
27
27
#include <unistd.h>
28
28
#include <string.h>
29
29
#include <sys/socket.h>
 
30
#include <sys/ioctl.h>
30
31
#include <arpa/inet.h>
31
32
#include <netinet/ether.h>
32
33
#include <net/if_arp.h>
33
34
#include <linux/if.h>
34
35
#include <linux/netlink.h>
35
36
#include <linux/rtnetlink.h>
 
37
#include <linux/wireless.h>
36
38
 
37
39
#include <glib.h>
38
40
 
39
41
#include "connman.h"
40
42
 
 
43
#ifndef ARPHDR_PHONET_PIPE
 
44
#define ARPHDR_PHONET_PIPE (821)
 
45
#endif
 
46
 
41
47
#define print(arg...) do { } while (0)
42
48
//#define print(arg...) connman_info(arg)
43
49
 
44
50
struct watch_data {
45
51
        unsigned int id;
46
52
        int index;
47
 
        connman_rtnl_operstate_cb_t operstate;
48
53
        connman_rtnl_link_cb_t newlink;
49
54
        void *user_data;
50
55
};
60
65
        int index;
61
66
        char *name;
62
67
        char *ident;
63
 
        enum connman_service_type type;
 
68
        enum connman_service_type service_type;
 
69
        enum connman_device_type device_type;
64
70
};
65
71
 
66
72
static GHashTable *interface_list = NULL;
69
75
{
70
76
        struct interface_data *interface = data;
71
77
 
72
 
        __connman_technology_remove_interface(interface->type,
 
78
        __connman_technology_remove_interface(interface->service_type,
73
79
                        interface->index, interface->name, interface->ident);
74
80
 
75
81
        g_free(interface->ident);
90
96
        if (g_str_has_prefix(name, "vboxnet") == TRUE)
91
97
                return TRUE;
92
98
 
 
99
        /* virtual interface from Virtual Machine Manager */
 
100
        if (g_str_has_prefix(name, "virbr") == TRUE)
 
101
                return TRUE;
 
102
 
93
103
        return FALSE;
94
104
}
95
105
 
 
106
static connman_bool_t wext_interface(char *ifname)
 
107
{
 
108
        struct iwreq wrq;
 
109
        int fd, err;
 
110
 
 
111
        fd = socket(PF_INET, SOCK_DGRAM, 0);
 
112
        if (fd < 0)
 
113
                return FALSE;
 
114
 
 
115
        memset(&wrq, 0, sizeof(wrq));
 
116
        strncpy(wrq.ifr_name, ifname, IFNAMSIZ);
 
117
 
 
118
        err = ioctl(fd, SIOCGIWNAME, &wrq);
 
119
 
 
120
        close(fd);
 
121
 
 
122
        if (err < 0)
 
123
                return FALSE;
 
124
 
 
125
        return TRUE;
 
126
}
 
127
 
96
128
static void read_uevent(struct interface_data *interface)
97
129
{
98
130
        char *filename, line[128];
 
131
        connman_bool_t found_devtype;
99
132
        FILE *f;
100
133
 
101
 
        if (ether_blacklisted(interface->name) == TRUE)
102
 
                interface->type = CONNMAN_SERVICE_TYPE_UNKNOWN;
103
 
        else
104
 
                interface->type = CONNMAN_SERVICE_TYPE_ETHERNET;
 
134
        if (ether_blacklisted(interface->name) == TRUE) {
 
135
                interface->service_type = CONNMAN_SERVICE_TYPE_UNKNOWN;
 
136
                interface->device_type = CONNMAN_DEVICE_TYPE_UNKNOWN;
 
137
        } else {
 
138
                interface->service_type = CONNMAN_SERVICE_TYPE_ETHERNET;
 
139
                interface->device_type = CONNMAN_DEVICE_TYPE_ETHERNET;
 
140
        }
105
141
 
106
142
        filename = g_strdup_printf("/sys/class/net/%s/uevent",
107
143
                                                interface->name);
113
149
        if (f == NULL)
114
150
                return;
115
151
 
 
152
        found_devtype = FALSE;
116
153
        while (fgets(line, sizeof(line), f)) {
117
154
                char *pos;
118
155
 
124
161
                if (strncmp(line, "DEVTYPE=", 8) != 0)
125
162
                        continue;
126
163
 
127
 
                if (strcmp(line + 8, "wlan") == 0)
128
 
                        interface->type = CONNMAN_SERVICE_TYPE_WIFI;
129
 
                else if (strcmp(line + 8, "wwan") == 0)
130
 
                        interface->type = CONNMAN_SERVICE_TYPE_CELLULAR;
131
 
                else if (strcmp(line + 8, "bluetooth") == 0)
132
 
                        interface->type = CONNMAN_SERVICE_TYPE_BLUETOOTH;
133
 
                else if (strcmp(line + 8, "wimax") == 0)
134
 
                        interface->type = CONNMAN_SERVICE_TYPE_WIMAX;
135
 
                else
136
 
                        interface->type = CONNMAN_SERVICE_TYPE_UNKNOWN;
 
164
                found_devtype = TRUE;
 
165
 
 
166
                if (strcmp(line + 8, "wlan") == 0) {
 
167
                        interface->service_type = CONNMAN_SERVICE_TYPE_WIFI;
 
168
                        interface->device_type = CONNMAN_DEVICE_TYPE_WIFI;
 
169
                } else if (strcmp(line + 8, "wwan") == 0) {
 
170
                        interface->service_type = CONNMAN_SERVICE_TYPE_CELLULAR;
 
171
                        interface->device_type = CONNMAN_DEVICE_TYPE_CELLULAR;
 
172
                } else if (strcmp(line + 8, "bluetooth") == 0) {
 
173
                        interface->service_type = CONNMAN_SERVICE_TYPE_BLUETOOTH;
 
174
                        interface->device_type = CONNMAN_DEVICE_TYPE_BLUETOOTH;
 
175
                } else if (strcmp(line + 8, "wimax") == 0) {
 
176
                        interface->service_type = CONNMAN_SERVICE_TYPE_WIMAX;
 
177
                        interface->device_type = CONNMAN_DEVICE_TYPE_WIMAX;
 
178
                } else {
 
179
                        interface->service_type = CONNMAN_SERVICE_TYPE_UNKNOWN;
 
180
                        interface->device_type = CONNMAN_DEVICE_TYPE_UNKNOWN;
 
181
                }
137
182
        }
138
183
 
139
184
        fclose(f);
 
185
 
 
186
        if (found_devtype)
 
187
                return;
 
188
 
 
189
        /* We haven't got a DEVTYPE, let's check if it's a wireless device */
 
190
        if (wext_interface(interface->name)) {
 
191
                interface->service_type = CONNMAN_SERVICE_TYPE_WIFI;
 
192
                interface->device_type = CONNMAN_DEVICE_TYPE_WIFI;
 
193
 
 
194
                connman_error("%s runs an unsupported 802.11 driver",
 
195
                                interface->name);
 
196
        }
140
197
}
141
198
 
142
 
/**
143
 
 * connman_rtnl_add_operstate_watch:
144
 
 * @index: network device index
145
 
 * @callback: callback function
146
 
 * @user_data: callback data;
147
 
 *
148
 
 * Add a new RTNL watch for operation state events
149
 
 *
150
 
 * Returns: %0 on failure and a unique id on success
151
 
 */
152
 
unsigned int connman_rtnl_add_operstate_watch(int index,
153
 
                        connman_rtnl_operstate_cb_t callback, void *user_data)
 
199
enum connman_device_type __connman_rtnl_get_device_type(int index)
154
200
{
155
 
        struct watch_data *watch;
156
 
 
157
 
        watch = g_try_new0(struct watch_data, 1);
158
 
        if (watch == NULL)
159
 
                return 0;
160
 
 
161
 
        watch->id = ++watch_id;
162
 
        watch->index = index;
163
 
 
164
 
        watch->operstate = callback;
165
 
        watch->user_data = user_data;
166
 
 
167
 
        watch_list = g_slist_prepend(watch_list, watch);
168
 
 
169
 
        DBG("id %d", watch->id);
170
 
 
171
 
        if (callback) {
172
 
                unsigned char operstate = 0;
173
 
 
174
 
                if (operstate > 0)
175
 
                        callback(operstate, user_data);
176
 
        }
177
 
 
178
 
        return watch->id;
 
201
        struct interface_data *interface;
 
202
 
 
203
        interface = g_hash_table_lookup(interface_list,
 
204
                                        GINT_TO_POINTER(index));
 
205
        if (interface == NULL)
 
206
                return CONNMAN_DEVICE_TYPE_UNKNOWN;
 
207
 
 
208
        return interface->device_type;
179
209
}
180
210
 
181
211
/**
398
428
        switch (type) {
399
429
        case ARPHRD_ETHER:
400
430
        case ARPHRD_LOOPBACK:
 
431
        case ARPHDR_PHONET_PIPE:
401
432
        case ARPHRD_NONE:
402
433
                __connman_ipconfig_newlink(index, type, flags,
403
434
                                                        str, mtu, &stats);
428
459
                if (type == ARPHRD_ETHER)
429
460
                        read_uevent(interface);
430
461
 
431
 
                __connman_technology_add_interface(interface->type,
 
462
                __connman_technology_add_interface(interface->service_type,
432
463
                        interface->index, interface->name, interface->ident);
433
464
        }
434
465
 
445
476
                if (watch->index != index)
446
477
                        continue;
447
478
 
448
 
                if (operstate != 0xff && watch->operstate)
449
 
                        watch->operstate(operstate, watch->user_data);
450
 
 
451
479
                if (watch->newlink)
452
480
                        watch->newlink(flags, change, watch->user_data);
453
481
        }
469
497
                                                ifname, index, operstate,
470
498
                                                operstate2str(operstate));
471
499
 
472
 
        for (list = watch_list; list; list = list->next) {
473
 
                struct watch_data *watch = list->data;
474
 
 
475
 
                if (watch->index != index)
476
 
                        continue;
477
 
 
478
 
                if (operstate != 0xff && watch->operstate)
479
 
                        watch->operstate(operstate, watch->user_data);
480
 
        }
481
 
 
482
500
        for (list = rtnl_list; list; list = list->next) {
483
501
                struct connman_rtnl *rtnl = list->data;
484
502
 
497
515
        g_hash_table_remove(interface_list, GINT_TO_POINTER(index));
498
516
}
499
517
 
500
 
static void extract_addr(struct ifaddrmsg *msg, int bytes,
 
518
static void extract_ipv4_addr(struct ifaddrmsg *msg, int bytes,
501
519
                                                const char **label,
502
520
                                                struct in_addr *local,
503
521
                                                struct in_addr *address,
528
546
        }
529
547
}
530
548
 
 
549
static void extract_ipv6_addr(struct ifaddrmsg *msg, int bytes,
 
550
                                                struct in6_addr *addr,
 
551
                                                struct in6_addr *local)
 
552
{
 
553
        struct rtattr *attr;
 
554
 
 
555
        for (attr = IFA_RTA(msg); RTA_OK(attr, bytes);
 
556
                                        attr = RTA_NEXT(attr, bytes)) {
 
557
                switch (attr->rta_type) {
 
558
                case IFA_ADDRESS:
 
559
                        if (addr != NULL)
 
560
                                *addr = *((struct in6_addr *) RTA_DATA(attr));
 
561
                        break;
 
562
                case IFA_LOCAL:
 
563
                        if (local != NULL)
 
564
                                *local = *((struct in6_addr *) RTA_DATA(attr));
 
565
                        break;
 
566
                }
 
567
        }
 
568
}
 
569
 
531
570
static void process_newaddr(unsigned char family, unsigned char prefixlen,
532
571
                                int index, struct ifaddrmsg *msg, int bytes)
533
572
{
534
 
        struct in_addr address = { INADDR_ANY };
535
573
        const char *label = NULL;
536
 
 
537
 
        if (family != AF_INET)
538
 
                return;
539
 
 
540
 
        extract_addr(msg, bytes, &label, &address, NULL, NULL);
541
 
 
542
 
        __connman_ipconfig_newaddr(index, label,
543
 
                                        prefixlen, inet_ntoa(address));
 
574
        void *src;
 
575
        char ip_string[INET6_ADDRSTRLEN];
 
576
 
 
577
        if (family != AF_INET && family != AF_INET6)
 
578
                return;
 
579
 
 
580
        if (family == AF_INET) {
 
581
                struct in_addr ipv4_addr = { INADDR_ANY };
 
582
 
 
583
                extract_ipv4_addr(msg, bytes, &label, &ipv4_addr, NULL, NULL);
 
584
                src = &ipv4_addr;
 
585
        } else if (family == AF_INET6) {
 
586
                struct in6_addr ipv6_address, ipv6_local;
 
587
 
 
588
                extract_ipv6_addr(msg, bytes, &ipv6_address, &ipv6_local);
 
589
                if (IN6_IS_ADDR_LINKLOCAL(&ipv6_address))
 
590
                        return;
 
591
 
 
592
                src = &ipv6_address;
 
593
        }
 
594
 
 
595
        if (inet_ntop(family, src, ip_string, INET6_ADDRSTRLEN) == NULL)
 
596
                return;
 
597
 
 
598
        __connman_ipconfig_newaddr(index, family, label,
 
599
                                        prefixlen, ip_string);
544
600
}
545
601
 
546
602
static void process_deladdr(unsigned char family, unsigned char prefixlen,
547
603
                                int index, struct ifaddrmsg *msg, int bytes)
548
604
{
549
 
        struct in_addr address = { INADDR_ANY };
550
605
        const char *label = NULL;
551
 
 
552
 
        if (family != AF_INET)
553
 
                return;
554
 
 
555
 
        extract_addr(msg, bytes, &label, &address, NULL, NULL);
556
 
 
557
 
        __connman_ipconfig_deladdr(index, label,
558
 
                                        prefixlen, inet_ntoa(address));
 
606
        void *src;
 
607
        char ip_string[INET6_ADDRSTRLEN];
 
608
 
 
609
        if (family != AF_INET && family != AF_INET6)
 
610
                return;
 
611
 
 
612
        if (family == AF_INET) {
 
613
                struct in_addr ipv4_addr = { INADDR_ANY };
 
614
 
 
615
                extract_ipv4_addr(msg, bytes, &label, &ipv4_addr, NULL, NULL);
 
616
                src = &ipv4_addr;
 
617
        } else if (family == AF_INET6) {
 
618
                struct in6_addr ipv6_address, ipv6_local;
 
619
 
 
620
                extract_ipv6_addr(msg, bytes, &ipv6_address, &ipv6_local);
 
621
                if (IN6_IS_ADDR_LINKLOCAL(&ipv6_address))
 
622
                        return;
 
623
 
 
624
                src = &ipv6_address;
 
625
        }
 
626
 
 
627
        if (inet_ntop(family, src, ip_string, INET6_ADDRSTRLEN) == NULL)
 
628
                return;
 
629
 
 
630
        __connman_ipconfig_deladdr(index, family, label,
 
631
                                        prefixlen, ip_string);
559
632
}
560
633
 
561
634
static void extract_route(struct rtmsg *msg, int bytes, int *index,
599
672
        inet_ntop(family, &dst, dststr, sizeof(dststr));
600
673
        inet_ntop(family, &gateway, gatewaystr, sizeof(gatewaystr));
601
674
 
602
 
        __connman_ipconfig_newroute(index, scope, dststr, gatewaystr);
 
675
        __connman_ipconfig_newroute(index, family, scope, dststr, gatewaystr);
603
676
 
604
677
        /* skip host specific routes */
605
678
        if (scope != RT_SCOPE_UNIVERSE &&
633
706
        inet_ntop(family, &dst, dststr, sizeof(dststr));
634
707
        inet_ntop(family, &gateway, gatewaystr, sizeof(gatewaystr));
635
708
 
636
 
        __connman_ipconfig_delroute(index, scope, dststr, gatewaystr);
 
709
        __connman_ipconfig_delroute(index, family, scope, dststr, gatewaystr);
637
710
 
638
711
        /* skip host specific routes */
639
712
        if (scope != RT_SCOPE_UNIVERSE &&
1277
1350
 
1278
1351
        memset(&addr, 0, sizeof(addr));
1279
1352
        addr.nl_family = AF_NETLINK;
1280
 
        addr.nl_groups = RTMGRP_LINK | RTMGRP_IPV4_IFADDR | RTMGRP_IPV4_ROUTE;
 
1353
        addr.nl_groups = RTMGRP_LINK | RTMGRP_IPV4_IFADDR | RTMGRP_IPV4_ROUTE |
 
1354
                                RTMGRP_IPV6_IFADDR | RTMGRP_IPV6_ROUTE;
1281
1355
 
1282
1356
        if (bind(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
1283
1357
                close(sk);