Add support for Update method via D-Bus
[platform/upstream/connman.git] / src / iface-inet.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 <string.h>
30 #include <sys/ioctl.h>
31 #include <sys/socket.h>
32 #include <net/if.h>
33 #include <net/ethernet.h>
34
35 #include "connman.h"
36
37 int __connman_iface_create_identifier(struct connman_iface *iface)
38 {
39         struct ifreq ifr;
40         struct ether_addr *eth;
41         int sk, err;
42
43         DBG("iface %p", iface);
44
45         sk = socket(PF_INET, SOCK_DGRAM, 0);
46         if (sk < 0)
47                 return -EIO;
48
49         memset(&ifr, 0, sizeof(ifr));
50         ifr.ifr_ifindex = iface->index;
51
52         err = ioctl(sk, SIOCGIFNAME, &ifr);
53
54         if (err == 0)
55                 err = ioctl(sk, SIOCGIFHWADDR, &ifr);
56
57         close(sk);
58
59         if (err < 0)
60                 return -EIO;
61
62         iface->identifier = malloc(18);
63         if (iface->identifier == NULL)
64                 return -ENOMEM;
65
66         eth = (void *) &ifr.ifr_hwaddr.sa_data;
67         sprintf(iface->identifier, "%02X-%02X-%02X-%02X-%02X-%02X",
68                                                 eth->ether_addr_octet[0],
69                                                 eth->ether_addr_octet[1],
70                                                 eth->ether_addr_octet[2],
71                                                 eth->ether_addr_octet[3],
72                                                 eth->ether_addr_octet[4],
73                                                 eth->ether_addr_octet[5]);
74
75         return 0;
76 }
77
78 int __connman_iface_init_via_inet(struct connman_iface *iface)
79 {
80         struct ifreq ifr;
81         int sk, err;
82
83         DBG("iface %p", iface);
84
85         sk = socket(PF_INET, SOCK_DGRAM, 0);
86         if (sk < 0)
87                 return -EIO;
88
89         memset(&ifr, 0, sizeof(ifr));
90         ifr.ifr_ifindex = iface->index;
91
92         err = ioctl(sk, SIOCGIFNAME, &ifr);
93
94         if (err == 0)
95                 err = ioctl(sk, SIOCGIFFLAGS, &ifr);
96
97         close(sk);
98
99         if (err < 0)
100                 return -EIO;
101
102         if (ifr.ifr_flags & IFF_UP)
103                 iface->state = CONNMAN_IFACE_STATE_ENABLED;
104         else
105                 iface->state = CONNMAN_IFACE_STATE_OFF;
106
107         if (ifr.ifr_flags & IFF_RUNNING) {
108                 if (!(iface->flags & CONNMAN_IFACE_FLAG_NOCARRIER))
109                         iface->state = CONNMAN_IFACE_STATE_CARRIER;
110         }
111
112         return 0;
113 }
114
115 static int __connman_iface_up(struct connman_iface *iface)
116 {
117         struct ifreq ifr;
118         int sk, err;
119
120         DBG("iface %p", iface);
121
122         sk = socket(PF_INET, SOCK_DGRAM, 0);
123         if (sk < 0)
124                 return -errno;
125
126         memset(&ifr, 0, sizeof(ifr));
127         ifr.ifr_ifindex = iface->index;
128
129         if (ioctl(sk, SIOCGIFNAME, &ifr) < 0) {
130                 err = -errno;
131                 goto done;
132         }
133
134         if (ioctl(sk, SIOCGIFFLAGS, &ifr) < 0) {
135                 err = -errno;
136                 goto done;
137         }
138
139         if (ifr.ifr_flags & IFF_UP) {
140                 err = -EALREADY;
141                 goto done;
142         }
143
144         ifr.ifr_flags |= IFF_UP;
145
146         if (ioctl(sk, SIOCSIFFLAGS, &ifr) < 0) {
147                 err = -errno;
148                 goto done;
149         }
150
151         err = 0;
152
153 done:
154         close(sk);
155
156         return err;
157 }
158
159 static int __connman_iface_down(struct connman_iface *iface)
160 {
161         struct ifreq ifr;
162         int sk, err;
163
164         DBG("iface %p", iface);
165
166         sk = socket(PF_INET, SOCK_DGRAM, 0);
167         if (sk < 0)
168                 return -errno;
169
170         memset(&ifr, 0, sizeof(ifr));
171         ifr.ifr_ifindex = iface->index;
172
173         if (ioctl(sk, SIOCGIFNAME, &ifr) < 0) {
174                 err = -errno;
175                 goto done;
176         }
177
178         if (ioctl(sk, SIOCGIFFLAGS, &ifr) < 0) {
179                 err = -errno;
180                 goto done;
181         }
182
183         if (!(ifr.ifr_flags & IFF_UP)) {
184                 err = -EALREADY;
185                 goto done;
186         }
187
188         ifr.ifr_flags &= ~IFF_UP;
189
190         if (ioctl(sk, SIOCSIFFLAGS, &ifr) < 0)
191                 err = -errno;
192         else
193                 err = 0;
194
195 done:
196         close(sk);
197
198         return err;
199 }
200
201 int __connman_iface_start(struct connman_iface *iface)
202 {
203         int err;
204
205         DBG("iface %p", iface);
206
207         if (iface->flags & CONNMAN_IFACE_FLAG_STARTED)
208                 return -EALREADY;
209
210         err = __connman_iface_up(iface);
211
212         if (iface->driver->start) {
213                 err = iface->driver->start(iface);
214                 if (err < 0)
215                         return err;
216         }
217
218         iface->flags |= CONNMAN_IFACE_FLAG_STARTED;
219
220         return 0;
221 }
222
223 int __connman_iface_stop(struct connman_iface *iface)
224 {
225         int err;
226
227         DBG("iface %p", iface);
228
229         __connman_dhcp_release(iface);
230
231         connman_iface_clear_ipv4(iface);
232
233         if (iface->flags & CONNMAN_IFACE_FLAG_RUNNING) {
234                 if (iface->driver->disconnect)
235                         iface->driver->disconnect(iface);
236                 iface->flags &= ~CONNMAN_IFACE_FLAG_RUNNING;
237         }
238
239         if (!(iface->flags & CONNMAN_IFACE_FLAG_STARTED))
240                 return -EINVAL;
241
242         if (iface->driver->stop) {
243                 err = iface->driver->stop(iface);
244                 if (err < 0)
245                         return err;
246         }
247
248         iface->flags &= ~CONNMAN_IFACE_FLAG_STARTED;
249
250         err = __connman_iface_down(iface);
251         if (err < 0)
252                 return err;
253
254         return 0;
255 }
256
257 int __connman_iface_connect(struct connman_iface *iface,
258                                         struct connman_network *network)
259 {
260         DBG("iface %p name %s passphrase %s", iface,
261                                 network->identifier, network->passphrase);
262
263         if (iface->flags & CONNMAN_IFACE_FLAG_RUNNING) {
264                 __connman_dhcp_release(iface);
265
266                 connman_iface_clear_ipv4(iface);
267
268                 if (iface->driver->disconnect)
269                         iface->driver->disconnect(iface);
270
271                 iface->flags &= ~CONNMAN_IFACE_FLAG_RUNNING;
272         }
273
274         if (iface->driver->connect)
275                 iface->driver->connect(iface, network);
276
277         iface->flags |= CONNMAN_IFACE_FLAG_RUNNING;
278
279         return 0;
280 }
281
282 int __connman_iface_disconnect(struct connman_iface *iface)
283 {
284         DBG("iface %p", iface);
285
286         __connman_dhcp_release(iface);
287
288         connman_iface_clear_ipv4(iface);
289
290         if (!(iface->flags & CONNMAN_IFACE_FLAG_RUNNING))
291                 return -EINVAL;
292
293         if (iface->driver->disconnect)
294                 iface->driver->disconnect(iface);
295
296         iface->flags &= ~CONNMAN_IFACE_FLAG_RUNNING;
297
298         return 0;
299 }