Add missing includes
[platform/upstream/connman.git] / src / detect.c
1 /*
2  *
3  *  Connection Manager
4  *
5  *  Copyright (C) 2007-2008  Intel Corporation. All rights reserved.
6  *
7  *  This program is free software; you can redistribute it and/or modify
8  *  it under the terms of the GNU General Public License version 2 as
9  *  published by the Free Software Foundation.
10  *
11  *  This program is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *  GNU General Public License for more details.
15  *
16  *  You should have received a copy of the GNU General Public License
17  *  along with this program; if not, write to the Free Software
18  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
19  *
20  */
21
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25
26 #include <stdio.h>
27 #include <errno.h>
28 #include <unistd.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <sys/stat.h>
32 #include <sys/ioctl.h>
33 #include <sys/socket.h>
34 #include <net/ethernet.h>
35 #include <linux/if_arp.h>
36 #include <linux/wireless.h>
37
38 #include <glib.h>
39
40 #include <connman/device.h>
41 #include <connman/rtnl.h>
42 #include <connman/log.h>
43
44 #include "connman.h"
45
46 static GSList *device_list = NULL;
47
48 static struct connman_device *find_device(int index)
49 {
50         GSList *list;
51
52         for (list = device_list; list; list = list->next) {
53                 struct connman_device *device = list->data;
54
55                 if (connman_device_get_index(device) == index)
56                         return device;
57         }
58
59         return NULL;
60 }
61
62 static char *index2name(int index)
63 {
64         struct ifreq ifr;
65         int sk, err;
66
67         if (index < 0)
68                 return NULL;
69
70         sk = socket(PF_INET, SOCK_DGRAM, 0);
71         if (sk < 0)
72                 return NULL;
73
74         memset(&ifr, 0, sizeof(ifr));
75         ifr.ifr_ifindex = index;
76
77         err = ioctl(sk, SIOCGIFNAME, &ifr);
78
79         close(sk);
80
81         if (err < 0)
82                 return NULL;
83
84         return strdup(ifr.ifr_name);
85 }
86
87 static char *index2ident(int index, const char *prefix)
88 {
89         struct ifreq ifr;
90         struct ether_addr *eth;
91         char *str;
92         int sk, err, len;
93
94         if (index < 0)
95                 return NULL;
96
97         sk = socket(PF_INET, SOCK_DGRAM, 0);
98         if (sk < 0)
99                 return NULL;
100
101         memset(&ifr, 0, sizeof(ifr));
102         ifr.ifr_ifindex = index;
103
104         err = ioctl(sk, SIOCGIFNAME, &ifr);
105
106         if (err == 0)
107                 err = ioctl(sk, SIOCGIFHWADDR, &ifr);
108
109         close(sk);
110
111         if (err < 0)
112                 return NULL;
113
114         len = prefix ? strlen(prefix) + 18 : 18;
115
116         str = malloc(len);
117         if (!str)
118                 return NULL;
119
120         eth = (void *) &ifr.ifr_hwaddr.sa_data;
121         snprintf(str, len, "%s%02X_%02X_%02X_%02X_%02X_%02X",
122                                                 prefix ? prefix : "",
123                                                 eth->ether_addr_octet[0],
124                                                 eth->ether_addr_octet[1],
125                                                 eth->ether_addr_octet[2],
126                                                 eth->ether_addr_octet[3],
127                                                 eth->ether_addr_octet[4],
128                                                 eth->ether_addr_octet[5]);
129
130         return str;
131 }
132
133 static void detect_newlink(unsigned short type, int index,
134                                         unsigned flags, unsigned change)
135 {
136         enum connman_device_type devtype = CONNMAN_DEVICE_TYPE_UNKNOWN;
137         struct connman_device *device;
138         gchar *name, *devname;
139
140         DBG("type %d index %d", type, index);
141
142         device = find_device(index);
143         if (device != NULL)
144                 return;
145
146         devname = index2name(index);
147
148         if (type == ARPHRD_ETHER) {
149                 char bridge_path[PATH_MAX], wimax_path[PATH_MAX];
150                 struct stat st;
151                 struct iwreq iwr;
152                 int sk;
153
154                 snprintf(bridge_path, PATH_MAX,
155                                         "/sys/class/net/%s/bridge", devname);
156                 snprintf(wimax_path, PATH_MAX,
157                                         "/sys/class/net/%s/wimax", devname);
158
159                 memset(&iwr, 0, sizeof(iwr));
160                 strncpy(iwr.ifr_ifrn.ifrn_name, devname, IFNAMSIZ);
161
162                 sk = socket(PF_INET, SOCK_DGRAM, 0);
163
164                 if (g_str_has_prefix(devname, "bnep") == TRUE)
165                         devtype = CONNMAN_DEVICE_TYPE_UNKNOWN;
166                 else if (stat(bridge_path, &st) == 0 && (st.st_mode & S_IFDIR))
167                         devtype = CONNMAN_DEVICE_TYPE_UNKNOWN;
168                 else if (stat(wimax_path, &st) == 0 && (st.st_mode & S_IFDIR))
169                         devtype = CONNMAN_DEVICE_TYPE_WIMAX;
170                 else if (ioctl(sk, SIOCGIWNAME, &iwr) == 0)
171                         devtype = CONNMAN_DEVICE_TYPE_UNKNOWN;
172                 else
173                         devtype = CONNMAN_DEVICE_TYPE_ETHERNET;
174
175                 close(sk);
176         } else if (type == ARPHRD_NONE) {
177                 if (g_str_has_prefix(devname, "hso") == TRUE)
178                         devtype = CONNMAN_DEVICE_TYPE_HSO;
179         }
180
181         if (devtype == CONNMAN_DEVICE_TYPE_UNKNOWN) {
182                 g_free(devname);
183                 return;
184         }
185
186         switch (devtype) {
187         case CONNMAN_DEVICE_TYPE_HSO:
188                 name = strdup(devname);
189                 break;
190         default:
191                 name = index2ident(index, "dev_");
192                 break;
193         }
194
195         device = connman_device_create(name, devtype);
196         if (device == NULL) {
197                 g_free(devname);
198                 g_free(name);
199                 return;
200         }
201
202         switch (devtype) {
203         case CONNMAN_DEVICE_TYPE_BLUETOOTH:
204         case CONNMAN_DEVICE_TYPE_HSO:
205                 connman_device_set_policy(device, CONNMAN_DEVICE_POLICY_MANUAL);
206                 break;
207         default:
208                 break;
209         }
210
211         connman_device_set_index(device, index);
212         connman_device_set_interface(device, devname);
213
214         g_free(devname);
215         g_free(name);
216
217         if (connman_device_register(device) < 0) {
218                 connman_device_unref(device);
219                 return;
220         }
221
222         device_list = g_slist_append(device_list, device);
223 }
224
225 static void detect_dellink(unsigned short type, int index,
226                                         unsigned flags, unsigned change)
227 {
228         struct connman_device *device;
229
230         DBG("type %d index %d", type, index);
231
232         device = find_device(index);
233         if (device == NULL)
234                 return;
235
236         device_list = g_slist_remove(device_list, device);
237
238         connman_device_unregister(device);
239         connman_device_unref(device);
240 }
241
242 static struct connman_rtnl detect_rtnl = {
243         .name           = "detect",
244         .priority       = CONNMAN_RTNL_PRIORITY_LOW,
245         .newlink        = detect_newlink,
246         .dellink        = detect_dellink,
247 };
248
249 int __connman_detect_init(void)
250 {
251         int err;
252
253         err = connman_rtnl_register(&detect_rtnl);
254         if (err < 0)
255                 return err;
256
257         connman_rtnl_send_getlink();
258
259         return 0;
260 }
261
262 void __connman_detect_cleanup(void)
263 {
264         GSList *list;
265
266         connman_rtnl_unregister(&detect_rtnl);
267
268         for (list = device_list; list; list = list->next) {
269                 struct connman_device *device = list->data;
270
271                 connman_device_unregister(device);
272                 connman_device_unref(device);
273         }
274
275         g_slist_free(device_list);
276         device_list = NULL;
277 }