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