ethernet: Do not connect network on LOWER_UP
[platform/upstream/connman.git] / plugins / ethernet.c
1 /*
2  *
3  *  Connection Manager
4  *
5  *  Copyright (C) 2007-2010  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 <net/if.h>
28
29 #ifndef IFF_LOWER_UP
30 #define IFF_LOWER_UP    0x10000
31 #endif
32
33 #include <glib.h>
34
35 #define CONNMAN_API_SUBJECT_TO_CHANGE
36 #include <connman/technology.h>
37 #include <connman/plugin.h>
38 #include <connman/device.h>
39 #include <connman/inet.h>
40 #include <connman/rtnl.h>
41 #include <connman/log.h>
42
43 struct ethernet_data {
44         int index;
45         unsigned flags;
46         unsigned int watch;
47         struct connman_network *network;
48 };
49
50 static int cable_probe(struct connman_network *network)
51 {
52         DBG("network %p", network);
53
54         return 0;
55 }
56
57 static void cable_remove(struct connman_network *network)
58 {
59         DBG("network %p", network);
60 }
61
62 static int cable_connect(struct connman_network *network)
63 {
64         DBG("network %p", network);
65
66         connman_network_set_connected(network, TRUE);
67
68         return 0;
69 }
70
71 static int cable_disconnect(struct connman_network *network)
72 {
73         DBG("network %p", network);
74
75         connman_network_set_connected(network, FALSE);
76
77         return 0;
78 }
79
80 static struct connman_network_driver cable_driver = {
81         .name           = "cable",
82         .type           = CONNMAN_NETWORK_TYPE_ETHERNET,
83         .probe          = cable_probe,
84         .remove         = cable_remove,
85         .connect        = cable_connect,
86         .disconnect     = cable_disconnect,
87 };
88
89 static void add_network(struct connman_device *device,
90                         struct ethernet_data *ethernet)
91 {
92         struct connman_network *network;
93         int index;
94
95         network = connman_network_create("carrier",
96                                         CONNMAN_NETWORK_TYPE_ETHERNET);
97         if (network == NULL)
98                 return;
99
100         index = connman_device_get_index(device);
101         connman_network_set_index(network, index);
102
103         connman_network_set_name(network, "Wired");
104
105         if (connman_device_add_network(device, network) < 0) {
106                 connman_network_unref(network);
107                 return;
108         }
109
110         connman_network_set_available(network, TRUE);
111
112         connman_network_set_group(network, "cable");
113
114         ethernet->network = network;
115 }
116
117 static void remove_network(struct connman_device *device,
118                                 struct ethernet_data *ethernet)
119 {
120         if (ethernet->network == NULL)
121                 return;
122
123         connman_device_remove_network(device, ethernet->network);
124         connman_network_unref(ethernet->network);
125
126         ethernet->network = NULL;
127 }
128
129 static void ethernet_newlink(unsigned flags, unsigned change, void *user_data)
130 {
131         struct connman_device *device = user_data;
132         struct ethernet_data *ethernet = connman_device_get_data(device);
133
134         DBG("index %d flags %d change %d", ethernet->index, flags, change);
135
136         if ((ethernet->flags & IFF_UP) != (flags & IFF_UP)) {
137                 if (flags & IFF_UP) {
138                         DBG("power on");
139                         connman_device_set_powered(device, TRUE);
140                 } else {
141                         DBG("power off");
142                         connman_device_set_powered(device, FALSE);
143                 }
144         }
145
146         if ((ethernet->flags & IFF_LOWER_UP) != (flags & IFF_LOWER_UP)) {
147                 if (flags & IFF_LOWER_UP) {
148                         DBG("carrier on");
149                         add_network(device, ethernet);
150                 } else {
151                         DBG("carrier off");
152                         remove_network(device, ethernet);
153                 }
154         }
155
156         ethernet->flags = flags;
157 }
158
159 static int ethernet_probe(struct connman_device *device)
160 {
161         struct ethernet_data *ethernet;
162
163         DBG("device %p", device);
164
165         ethernet = g_try_new0(struct ethernet_data, 1);
166         if (ethernet == NULL)
167                 return -ENOMEM;
168
169         connman_device_set_data(device, ethernet);
170
171         ethernet->index = connman_device_get_index(device);
172         ethernet->flags = 0;
173
174         ethernet->watch = connman_rtnl_add_newlink_watch(ethernet->index,
175                                                 ethernet_newlink, device);
176
177         return 0;
178 }
179
180 static void ethernet_remove(struct connman_device *device)
181 {
182         struct ethernet_data *ethernet = connman_device_get_data(device);
183
184         DBG("device %p", device);
185
186         connman_device_set_data(device, NULL);
187
188         connman_rtnl_remove_watch(ethernet->watch);
189
190         remove_network(device, ethernet);
191
192         g_free(ethernet);
193 }
194
195 static int ethernet_enable(struct connman_device *device)
196 {
197         struct ethernet_data *ethernet = connman_device_get_data(device);
198
199         DBG("device %p", device);
200
201         return connman_inet_ifup(ethernet->index);
202 }
203
204 static int ethernet_disable(struct connman_device *device)
205 {
206         struct ethernet_data *ethernet = connman_device_get_data(device);
207
208         DBG("device %p", device);
209
210         return connman_inet_ifdown(ethernet->index);
211 }
212
213 static struct connman_device_driver ethernet_driver = {
214         .name           = "ethernet",
215         .type           = CONNMAN_DEVICE_TYPE_ETHERNET,
216         .probe          = ethernet_probe,
217         .remove         = ethernet_remove,
218         .enable         = ethernet_enable,
219         .disable        = ethernet_disable,
220 };
221
222 static GList *cdc_interface_list = NULL;
223
224 static void tech_add_interface(struct connman_technology *technology,
225                         int index, const char *name, const char *ident)
226 {
227         DBG("index %d name %s ident %s", index, name, ident);
228
229         if (g_list_find(cdc_interface_list,
230                         GINT_TO_POINTER((int) index)) != NULL)
231                 return;
232
233         cdc_interface_list = g_list_prepend(cdc_interface_list,
234                                         (GINT_TO_POINTER((int) index)));
235 }
236
237 static void tech_remove_interface(struct connman_technology *technology,
238                                                                 int index)
239 {
240         DBG("index %d", index);
241
242         cdc_interface_list = g_list_remove(cdc_interface_list,
243                                         GINT_TO_POINTER((int) index));
244 }
245
246 static void enable_tethering(struct connman_technology *technology,
247                                                 const char *bridge)
248 {
249         GList *list;
250
251         for (list = cdc_interface_list; list; list = list->next) {
252                 int index = GPOINTER_TO_INT(list->data);
253
254                 connman_technology_tethering_notify(technology, TRUE);
255
256                 connman_inet_ifup(index);
257
258                 connman_inet_add_to_bridge(index, bridge);
259         }
260 }
261
262 static void disable_tethering(struct connman_technology *technology,
263                                                 const char *bridge)
264 {
265         GList *list;
266
267         for (list = cdc_interface_list; list; list = list->next) {
268                 int index = GPOINTER_TO_INT(list->data);
269
270                 connman_inet_remove_from_bridge(index, bridge);
271
272                 connman_inet_ifdown(index);
273
274                 connman_technology_tethering_notify(technology, FALSE);
275         }
276 }
277
278 static int tech_set_tethering(struct connman_technology *technology,
279                                 const char *identifier, const char *passphrase,
280                                 const char *bridge, connman_bool_t enabled)
281 {
282         DBG("bridge %s enabled %d", bridge, enabled);
283
284         if (enabled)
285                 enable_tethering(technology, bridge);
286         else
287                 disable_tethering(technology, bridge);
288
289         return 0;
290 }
291
292 static int tech_probe(struct connman_technology *technology)
293 {
294         return 0;
295 }
296
297 static void tech_remove(struct connman_technology *technology)
298 {
299         g_list_free(cdc_interface_list);
300
301         cdc_interface_list = NULL;
302 }
303
304 static struct connman_technology_driver tech_driver = {
305         .name                   = "cdc_ethernet",
306         .type                   = CONNMAN_SERVICE_TYPE_GADGET,
307         .probe                  = tech_probe,
308         .remove                 = tech_remove,
309         .add_interface          = tech_add_interface,
310         .remove_interface       = tech_remove_interface,
311         .set_tethering          = tech_set_tethering,
312 };
313
314 static int eth_probe(struct connman_technology *technology)
315 {
316         return 0;
317 }
318
319 static void eth_remove(struct connman_technology *technology)
320 {
321         DBG("");
322 }
323
324 static struct connman_technology_driver eth_driver = {
325         .name                   = "ethernet",
326         .type                   = CONNMAN_SERVICE_TYPE_ETHERNET,
327         .probe                  = eth_probe,
328         .remove                 = eth_remove,
329 };
330
331 static int ethernet_init(void)
332 {
333         int err;
334
335         err = connman_technology_driver_register(&eth_driver);
336         if (err < 0)
337                 return err;
338
339         err = connman_network_driver_register(&cable_driver);
340         if (err < 0)
341                 return err;
342
343         err = connman_device_driver_register(&ethernet_driver);
344         if (err < 0) {
345                 connman_network_driver_unregister(&cable_driver);
346                 return err;
347         }
348
349         err = connman_technology_driver_register(&tech_driver);
350         if (err < 0) {
351                 connman_device_driver_unregister(&ethernet_driver);
352                 connman_network_driver_unregister(&cable_driver);
353                 return err;
354         }
355
356         return 0;
357 }
358
359 static void ethernet_exit(void)
360 {
361         connman_technology_driver_unregister(&eth_driver);
362
363         connman_technology_driver_unregister(&tech_driver);
364
365         connman_network_driver_unregister(&cable_driver);
366
367         connman_device_driver_unregister(&ethernet_driver);
368 }
369
370 CONNMAN_PLUGIN_DEFINE(ethernet, "Ethernet interface plugin", VERSION,
371                 CONNMAN_PLUGIN_PRIORITY_DEFAULT, ethernet_init, ethernet_exit)