6a20eb29376c3b757d42e275b8043fea5dc4e5eb
[platform/upstream/connman.git] / plugins / ethernet.c
1 /*
2  *
3  *  Connection Manager
4  *
5  *  Copyright (C) 2007-2012  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_group(network, "cable");
111
112         ethernet->network = network;
113 }
114
115 static void remove_network(struct connman_device *device,
116                                 struct ethernet_data *ethernet)
117 {
118         if (ethernet->network == NULL)
119                 return;
120
121         connman_device_remove_network(device, ethernet->network);
122         connman_network_unref(ethernet->network);
123
124         ethernet->network = NULL;
125 }
126
127 static void ethernet_newlink(unsigned flags, unsigned change, void *user_data)
128 {
129         struct connman_device *device = user_data;
130         struct ethernet_data *ethernet = connman_device_get_data(device);
131
132         DBG("index %d flags %d change %d", ethernet->index, flags, change);
133
134         if ((ethernet->flags & IFF_UP) != (flags & IFF_UP)) {
135                 if (flags & IFF_UP) {
136                         DBG("power on");
137                         connman_device_set_powered(device, TRUE);
138                 } else {
139                         DBG("power off");
140                         connman_device_set_powered(device, FALSE);
141                 }
142         }
143
144         if ((ethernet->flags & IFF_LOWER_UP) != (flags & IFF_LOWER_UP)) {
145                 if (flags & IFF_LOWER_UP) {
146                         DBG("carrier on");
147                         add_network(device, ethernet);
148                 } else {
149                         DBG("carrier off");
150                         remove_network(device, ethernet);
151                 }
152         }
153
154         ethernet->flags = flags;
155 }
156
157 static int ethernet_probe(struct connman_device *device)
158 {
159         struct ethernet_data *ethernet;
160
161         DBG("device %p", device);
162
163         ethernet = g_try_new0(struct ethernet_data, 1);
164         if (ethernet == NULL)
165                 return -ENOMEM;
166
167         connman_device_set_data(device, ethernet);
168
169         ethernet->index = connman_device_get_index(device);
170         ethernet->flags = 0;
171
172         ethernet->watch = connman_rtnl_add_newlink_watch(ethernet->index,
173                                                 ethernet_newlink, device);
174
175         return 0;
176 }
177
178 static void ethernet_remove(struct connman_device *device)
179 {
180         struct ethernet_data *ethernet = connman_device_get_data(device);
181
182         DBG("device %p", device);
183
184         connman_device_set_data(device, NULL);
185
186         connman_rtnl_remove_watch(ethernet->watch);
187
188         remove_network(device, ethernet);
189
190         g_free(ethernet);
191 }
192
193 static int ethernet_enable(struct connman_device *device)
194 {
195         struct ethernet_data *ethernet = connman_device_get_data(device);
196
197         DBG("device %p", device);
198
199         return connman_inet_ifup(ethernet->index);
200 }
201
202 static int ethernet_disable(struct connman_device *device)
203 {
204         struct ethernet_data *ethernet = connman_device_get_data(device);
205
206         DBG("device %p", device);
207
208         return connman_inet_ifdown(ethernet->index);
209 }
210
211 static struct connman_device_driver ethernet_driver = {
212         .name           = "ethernet",
213         .type           = CONNMAN_DEVICE_TYPE_ETHERNET,
214         .probe          = ethernet_probe,
215         .remove         = ethernet_remove,
216         .enable         = ethernet_enable,
217         .disable        = ethernet_disable,
218 };
219
220 static GList *cdc_interface_list = NULL;
221
222 static void tech_add_interface(struct connman_technology *technology,
223                         int index, const char *name, const char *ident)
224 {
225         DBG("index %d name %s ident %s", index, name, ident);
226
227         if (g_list_find(cdc_interface_list,
228                         GINT_TO_POINTER((int) index)) != NULL)
229                 return;
230
231         cdc_interface_list = g_list_prepend(cdc_interface_list,
232                                         (GINT_TO_POINTER((int) index)));
233 }
234
235 static void tech_remove_interface(struct connman_technology *technology,
236                                                                 int index)
237 {
238         DBG("index %d", index);
239
240         cdc_interface_list = g_list_remove(cdc_interface_list,
241                                         GINT_TO_POINTER((int) index));
242 }
243
244 static void enable_tethering(struct connman_technology *technology,
245                                                 const char *bridge)
246 {
247         GList *list;
248
249         for (list = cdc_interface_list; list; list = list->next) {
250                 int index = GPOINTER_TO_INT(list->data);
251
252                 connman_technology_tethering_notify(technology, TRUE);
253
254                 connman_inet_ifup(index);
255
256                 connman_inet_add_to_bridge(index, bridge);
257         }
258 }
259
260 static void disable_tethering(struct connman_technology *technology,
261                                                 const char *bridge)
262 {
263         GList *list;
264
265         for (list = cdc_interface_list; list; list = list->next) {
266                 int index = GPOINTER_TO_INT(list->data);
267
268                 connman_inet_remove_from_bridge(index, bridge);
269
270                 connman_inet_ifdown(index);
271
272                 connman_technology_tethering_notify(technology, FALSE);
273         }
274 }
275
276 static int tech_set_tethering(struct connman_technology *technology,
277                                 const char *identifier, const char *passphrase,
278                                 const char *bridge, connman_bool_t enabled)
279 {
280         DBG("bridge %s enabled %d", bridge, enabled);
281
282         if (enabled)
283                 enable_tethering(technology, bridge);
284         else
285                 disable_tethering(technology, bridge);
286
287         return 0;
288 }
289
290 static int tech_probe(struct connman_technology *technology)
291 {
292         return 0;
293 }
294
295 static void tech_remove(struct connman_technology *technology)
296 {
297         g_list_free(cdc_interface_list);
298
299         cdc_interface_list = NULL;
300 }
301
302 static struct connman_technology_driver tech_driver = {
303         .name                   = "cdc_ethernet",
304         .type                   = CONNMAN_SERVICE_TYPE_GADGET,
305         .probe                  = tech_probe,
306         .remove                 = tech_remove,
307         .add_interface          = tech_add_interface,
308         .remove_interface       = tech_remove_interface,
309         .set_tethering          = tech_set_tethering,
310 };
311
312 static int eth_probe(struct connman_technology *technology)
313 {
314         return 0;
315 }
316
317 static void eth_remove(struct connman_technology *technology)
318 {
319         DBG("");
320 }
321
322 static struct connman_technology_driver eth_driver = {
323         .name                   = "ethernet",
324         .type                   = CONNMAN_SERVICE_TYPE_ETHERNET,
325         .probe                  = eth_probe,
326         .remove                 = eth_remove,
327 };
328
329 static int ethernet_init(void)
330 {
331         int err;
332
333         err = connman_technology_driver_register(&eth_driver);
334         if (err < 0)
335                 return err;
336
337         err = connman_network_driver_register(&cable_driver);
338         if (err < 0)
339                 return err;
340
341         err = connman_device_driver_register(&ethernet_driver);
342         if (err < 0) {
343                 connman_network_driver_unregister(&cable_driver);
344                 return err;
345         }
346
347         err = connman_technology_driver_register(&tech_driver);
348         if (err < 0) {
349                 connman_device_driver_unregister(&ethernet_driver);
350                 connman_network_driver_unregister(&cable_driver);
351                 return err;
352         }
353
354         return 0;
355 }
356
357 static void ethernet_exit(void)
358 {
359         connman_technology_driver_unregister(&eth_driver);
360
361         connman_technology_driver_unregister(&tech_driver);
362
363         connman_network_driver_unregister(&cable_driver);
364
365         connman_device_driver_unregister(&ethernet_driver);
366 }
367
368 CONNMAN_PLUGIN_DEFINE(ethernet, "Ethernet interface plugin", VERSION,
369                 CONNMAN_PLUGIN_PRIORITY_DEFAULT, ethernet_init, ethernet_exit)