Add generic wrapper for INET based device creation
[connman] / src / inet.c
1 /*
2  *
3  *  Connection Manager
4  *
5  *  Copyright (C) 2007-2009  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 "connman.h"
39
40 static char *index2name(int index)
41 {
42         struct ifreq ifr;
43         int sk, err;
44
45         if (index < 0)
46                 return NULL;
47
48         sk = socket(PF_INET, SOCK_DGRAM, 0);
49         if (sk < 0)
50                 return NULL;
51
52         memset(&ifr, 0, sizeof(ifr));
53         ifr.ifr_ifindex = index;
54
55         err = ioctl(sk, SIOCGIFNAME, &ifr);
56
57         close(sk);
58
59         if (err < 0)
60                 return NULL;
61
62         return strdup(ifr.ifr_name);
63 }
64
65 static unsigned short index2type(int index)
66 {
67         struct ifreq ifr;
68         int sk, err;
69
70         if (index < 0)
71                 return ARPHRD_VOID;
72
73         sk = socket(PF_INET, SOCK_DGRAM, 0);
74         if (sk < 0)
75                 return ARPHRD_VOID;
76
77         memset(&ifr, 0, sizeof(ifr));
78         ifr.ifr_ifindex = index;
79
80         err = ioctl(sk, SIOCGIFNAME, &ifr);
81
82         if (err == 0)
83                 err = ioctl(sk, SIOCGIFHWADDR, &ifr);
84
85         close(sk);
86
87         if (err < 0)
88                 return ARPHRD_VOID;
89
90         return ifr.ifr_hwaddr.sa_family;
91 }
92
93 static char *index2addr(int index)
94 {
95         struct ifreq ifr;
96         struct ether_addr *eth;
97         char *str;
98         int sk, err;
99
100         if (index < 0)
101                 return NULL;
102
103         sk = socket(PF_INET, SOCK_DGRAM, 0);
104         if (sk < 0)
105                 return NULL;
106
107         memset(&ifr, 0, sizeof(ifr));
108         ifr.ifr_ifindex = index;
109
110         err = ioctl(sk, SIOCGIFNAME, &ifr);
111
112         if (err == 0)
113                 err = ioctl(sk, SIOCGIFHWADDR, &ifr);
114
115         close(sk);
116
117         if (err < 0)
118                 return NULL;
119
120         str = malloc(18);
121         if (!str)
122                 return NULL;
123
124         eth = (void *) &ifr.ifr_hwaddr.sa_data;
125         snprintf(str, 18, "%02X:%02X:%02X:%02X:%02X:%02X",
126                                                 eth->ether_addr_octet[0],
127                                                 eth->ether_addr_octet[1],
128                                                 eth->ether_addr_octet[2],
129                                                 eth->ether_addr_octet[3],
130                                                 eth->ether_addr_octet[4],
131                                                 eth->ether_addr_octet[5]);
132
133         return str;
134 }
135
136 static char *index2ident(int index, const char *prefix)
137 {
138         struct ifreq ifr;
139         struct ether_addr *eth;
140         char *str;
141         int sk, err, len;
142
143         if (index < 0)
144                 return NULL;
145
146         sk = socket(PF_INET, SOCK_DGRAM, 0);
147         if (sk < 0)
148                 return NULL;
149
150         memset(&ifr, 0, sizeof(ifr));
151         ifr.ifr_ifindex = index;
152
153         err = ioctl(sk, SIOCGIFNAME, &ifr);
154
155         if (err == 0)
156                 err = ioctl(sk, SIOCGIFHWADDR, &ifr);
157
158         close(sk);
159
160         if (err < 0)
161                 return NULL;
162
163         len = prefix ? strlen(prefix) + 18 : 18;
164
165         str = malloc(len);
166         if (!str)
167                 return NULL;
168
169         eth = (void *) &ifr.ifr_hwaddr.sa_data;
170         snprintf(str, len, "%s%02x%02x%02x%02x%02x%02x",
171                                                 prefix ? prefix : "",
172                                                 eth->ether_addr_octet[0],
173                                                 eth->ether_addr_octet[1],
174                                                 eth->ether_addr_octet[2],
175                                                 eth->ether_addr_octet[3],
176                                                 eth->ether_addr_octet[4],
177                                                 eth->ether_addr_octet[5]);
178
179         return str;
180 }
181
182 struct connman_device *connman_inet_create_device(int index)
183 {
184         enum connman_device_type devtype = CONNMAN_DEVICE_TYPE_UNKNOWN;
185         enum connman_device_mode mode = CONNMAN_DEVICE_MODE_UNKNOWN;
186         struct connman_device *device;
187         unsigned short type = index2type(index);
188         char *addr, *name, *devname, *ident = NULL;
189
190         if (index < 0)
191                 return NULL;
192
193         devname = index2name(index);
194         if (devname == NULL)
195                 return NULL;
196
197         if (type == ARPHRD_ETHER) {
198                 char bridge_path[PATH_MAX], wimax_path[PATH_MAX];
199                 struct stat st;
200                 struct iwreq iwr;
201                 int sk;
202
203                 snprintf(bridge_path, PATH_MAX,
204                                         "/sys/class/net/%s/bridge", devname);
205                 snprintf(wimax_path, PATH_MAX,
206                                         "/sys/class/net/%s/wimax", devname);
207
208                 memset(&iwr, 0, sizeof(iwr));
209                 strncpy(iwr.ifr_ifrn.ifrn_name, devname, IFNAMSIZ);
210
211                 sk = socket(PF_INET, SOCK_DGRAM, 0);
212
213                 if (g_str_has_prefix(devname, "vmnet") == TRUE ||
214                                 g_str_has_prefix(devname, "vboxnet") == TRUE) {
215                         connman_info("Ignoring network interface %s", devname);
216                         devtype = CONNMAN_DEVICE_TYPE_UNKNOWN;
217                 } else if (g_str_has_prefix(devname, "bnep") == TRUE)
218                         devtype = CONNMAN_DEVICE_TYPE_UNKNOWN;
219                 else if (g_str_has_prefix(devname, "wmx") == TRUE)
220                         devtype = CONNMAN_DEVICE_TYPE_UNKNOWN;
221                 else if (stat(wimax_path, &st) == 0 && (st.st_mode & S_IFDIR))
222                         devtype = CONNMAN_DEVICE_TYPE_UNKNOWN;
223                 else if (stat(bridge_path, &st) == 0 && (st.st_mode & S_IFDIR))
224                         devtype = CONNMAN_DEVICE_TYPE_UNKNOWN;
225                 else if (ioctl(sk, SIOCGIWNAME, &iwr) == 0)
226                         devtype = CONNMAN_DEVICE_TYPE_WIFI;
227                 else
228                         devtype = CONNMAN_DEVICE_TYPE_ETHERNET;
229
230                 close(sk);
231         } else if (type == ARPHRD_NONE) {
232                 if (g_str_has_prefix(devname, "hso") == TRUE)
233                         devtype = CONNMAN_DEVICE_TYPE_HSO;
234         }
235
236         switch (devtype) {
237         case CONNMAN_DEVICE_TYPE_UNKNOWN:
238                 g_free(devname);
239                 return NULL;
240         case CONNMAN_DEVICE_TYPE_ETHERNET:
241         case CONNMAN_DEVICE_TYPE_WIFI:
242         case CONNMAN_DEVICE_TYPE_WIMAX:
243                 name = index2ident(index, "");
244                 addr = index2addr(index);
245                 break;
246         case CONNMAN_DEVICE_TYPE_BLUETOOTH:
247         case CONNMAN_DEVICE_TYPE_GPS:
248         case CONNMAN_DEVICE_TYPE_HSO:
249         case CONNMAN_DEVICE_TYPE_NOZOMI:
250         case CONNMAN_DEVICE_TYPE_HUAWEI:
251         case CONNMAN_DEVICE_TYPE_NOVATEL:
252         case CONNMAN_DEVICE_TYPE_VENDOR:
253                 name = strdup(devname);
254                 addr = NULL;
255                 break;
256         }
257
258         device = connman_device_create(name, devtype);
259         if (device == NULL) {
260                 g_free(devname);
261                 g_free(name);
262                 g_free(addr);
263                 return NULL;
264         }
265
266         switch (devtype) {
267         case CONNMAN_DEVICE_TYPE_UNKNOWN:
268         case CONNMAN_DEVICE_TYPE_VENDOR:
269         case CONNMAN_DEVICE_TYPE_NOZOMI:
270         case CONNMAN_DEVICE_TYPE_HUAWEI:
271         case CONNMAN_DEVICE_TYPE_NOVATEL:
272         case CONNMAN_DEVICE_TYPE_GPS:
273                 mode = CONNMAN_DEVICE_MODE_UNKNOWN;
274                 break;
275         case CONNMAN_DEVICE_TYPE_ETHERNET:
276                 mode = CONNMAN_DEVICE_MODE_TRANSPORT_IP;
277                 ident = index2ident(index, NULL);
278                 break;
279         case CONNMAN_DEVICE_TYPE_WIFI:
280         case CONNMAN_DEVICE_TYPE_WIMAX:
281                 mode = CONNMAN_DEVICE_MODE_NETWORK_SINGLE;
282                 ident = index2ident(index, NULL);
283                 break;
284         case CONNMAN_DEVICE_TYPE_BLUETOOTH:
285                 mode = CONNMAN_DEVICE_MODE_NETWORK_MULTIPLE;
286                 break;
287         case CONNMAN_DEVICE_TYPE_HSO:
288                 mode = CONNMAN_DEVICE_MODE_NETWORK_SINGLE;
289                 connman_device_set_policy(device, CONNMAN_DEVICE_POLICY_MANUAL);
290                 break;
291         }
292
293         connman_device_set_mode(device, mode);
294
295         connman_device_set_index(device, index);
296         connman_device_set_interface(device, devname);
297
298         if (ident != NULL) {
299                 connman_device_set_ident(device, ident);
300                 g_free(ident);
301         }
302
303         connman_device_set_string(device, "Address", addr);
304
305         g_free(devname);
306         g_free(name);
307         g_free(addr);
308
309         return device;
310 }