Tethering: Add hidden access point support in technology
[platform/upstream/connman.git] / plugins / gadget.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/rtnl.h>
40 #include <connman/inet.h>
41 #include <connman/log.h>
42
43 static bool gadget_tethering = false;
44
45 struct gadget_data {
46         int index;
47         unsigned flags;
48         unsigned int watch;
49         struct connman_network *network;
50 };
51
52 static int gadget_network_probe(struct connman_network *network)
53 {
54         DBG("network %p", network);
55
56         return 0;
57 }
58
59 static void gadget_network_remove(struct connman_network *network)
60 {
61         DBG("network %p", network);
62 }
63
64 static int gadget_network_connect(struct connman_network *network)
65 {
66         DBG("network %p", network);
67
68         connman_network_set_connected(network, true);
69
70         return 0;
71 }
72
73 static int gadget_network_disconnect(struct connman_network *network)
74 {
75         DBG("network %p", network);
76
77         connman_network_set_connected(network, false);
78
79         return 0;
80 }
81
82 static struct connman_network_driver gadget_network_driver = {
83         .name           = "usb",
84         .type           = CONNMAN_NETWORK_TYPE_GADGET,
85         .probe          = gadget_network_probe,
86         .remove         = gadget_network_remove,
87         .connect        = gadget_network_connect,
88         .disconnect     = gadget_network_disconnect,
89 };
90
91 static void add_network(struct connman_device *device,
92                         struct gadget_data *gadget)
93 {
94         struct connman_network *network;
95         int index;
96
97         network = connman_network_create("gadget",
98                                         CONNMAN_NETWORK_TYPE_GADGET);
99         if (!network)
100                 return;
101
102         index = connman_device_get_index(device);
103         connman_network_set_index(network, index);
104
105         connman_network_set_name(network, "Wired");
106
107         if (connman_device_add_network(device, network) < 0) {
108                 connman_network_unref(network);
109                 return;
110         }
111
112         if (!gadget_tethering)
113                 /*
114                  * Prevent service from starting the reconnect
115                  * procedure as we do not want the DHCP client
116                  * to run when tethering.
117                  */
118                 connman_network_set_group(network, "usb");
119
120         gadget->network = network;
121 }
122
123 static void remove_network(struct connman_device *device,
124                                 struct gadget_data *gadget)
125 {
126         if (!gadget->network)
127                 return;
128
129         connman_device_remove_network(device, gadget->network);
130         connman_network_unref(gadget->network);
131
132         gadget->network = NULL;
133 }
134
135 static void gadget_newlink(unsigned flags, unsigned change, void *user_data)
136 {
137         struct connman_device *device = user_data;
138         struct gadget_data *gadget = connman_device_get_data(device);
139
140         DBG("index %d flags %d change %d", gadget->index, flags, change);
141
142         if ((gadget->flags & IFF_UP) != (flags & IFF_UP)) {
143                 if (flags & IFF_UP) {
144                         DBG("power on");
145                         connman_device_set_powered(device, true);
146                 } else {
147                         DBG("power off");
148                         connman_device_set_powered(device, false);
149                 }
150         }
151
152         if ((gadget->flags & IFF_LOWER_UP) != (flags & IFF_LOWER_UP)) {
153                 if (flags & IFF_LOWER_UP) {
154                         DBG("carrier on");
155                         add_network(device, gadget);
156                 } else {
157                         DBG("carrier off");
158                         remove_network(device, gadget);
159                 }
160         }
161
162         gadget->flags = flags;
163 }
164
165 static int gadget_dev_probe(struct connman_device *device)
166 {
167         struct gadget_data *gadget;
168
169         DBG("device %p", device);
170
171         gadget = g_try_new0(struct gadget_data, 1);
172         if (!gadget)
173                 return -ENOMEM;
174
175         connman_device_set_data(device, gadget);
176
177         gadget->index = connman_device_get_index(device);
178         gadget->flags = 0;
179
180         gadget->watch = connman_rtnl_add_newlink_watch(gadget->index,
181                                                 gadget_newlink, device);
182
183         return 0;
184 }
185
186 static void gadget_dev_remove(struct connman_device *device)
187 {
188         struct gadget_data *gadget = connman_device_get_data(device);
189
190         DBG("device %p", device);
191
192         connman_device_set_data(device, NULL);
193
194         connman_rtnl_remove_watch(gadget->watch);
195
196         remove_network(device, gadget);
197
198         g_free(gadget);
199 }
200
201 static int gadget_dev_enable(struct connman_device *device)
202 {
203         struct gadget_data *gadget = connman_device_get_data(device);
204
205         DBG("device %p", device);
206
207         return connman_inet_ifup(gadget->index);
208 }
209
210 static int gadget_dev_disable(struct connman_device *device)
211 {
212         struct gadget_data *gadget = connman_device_get_data(device);
213
214         DBG("device %p", device);
215
216         return connman_inet_ifdown(gadget->index);
217 }
218
219 static struct connman_device_driver gadget_dev_driver = {
220         .name           = "gadget",
221         .type           = CONNMAN_DEVICE_TYPE_GADGET,
222         .probe          = gadget_dev_probe,
223         .remove         = gadget_dev_remove,
224         .enable         = gadget_dev_enable,
225         .disable        = gadget_dev_disable,
226 };
227
228 static GList *cdc_interface_list = NULL;
229
230 static void gadget_tech_add_interface(struct connman_technology *technology,
231                         int index, const char *name, const char *ident)
232 {
233         DBG("index %d name %s ident %s", index, name, ident);
234
235         if (g_list_find(cdc_interface_list, GINT_TO_POINTER((int)index)))
236                 return;
237
238         cdc_interface_list = g_list_prepend(cdc_interface_list,
239                                         (GINT_TO_POINTER((int) index)));
240 }
241
242 static void gadget_tech_remove_interface(struct connman_technology *technology,
243                                                                 int index)
244 {
245         DBG("index %d", index);
246
247         cdc_interface_list = g_list_remove(cdc_interface_list,
248                                         GINT_TO_POINTER((int) index));
249 }
250
251 static void gadget_tech_enable_tethering(struct connman_technology *technology,
252                                                 const char *bridge)
253 {
254         GList *list;
255
256         for (list = cdc_interface_list; list; list = list->next) {
257                 int index = GPOINTER_TO_INT(list->data);
258                 struct connman_device *device =
259                         connman_device_find_by_index(index);
260                 struct gadget_data *gadget;
261
262                 if (device) {
263                         gadget = connman_device_get_data(device);
264                         if (gadget)
265                                 remove_network(device, gadget);
266                 }
267
268                 connman_technology_tethering_notify(technology, true);
269
270                 connman_inet_ifup(index);
271
272                 connman_inet_add_to_bridge(index, bridge);
273         }
274 }
275
276 static void gadget_tech_disable_tethering(struct connman_technology *technology,
277                                                 const char *bridge)
278 {
279         GList *list;
280
281         for (list = cdc_interface_list; list; list = list->next) {
282                 int index = GPOINTER_TO_INT(list->data);
283
284                 connman_inet_remove_from_bridge(index, bridge);
285
286                 connman_inet_ifdown(index);
287
288                 connman_technology_tethering_notify(technology, false);
289         }
290 }
291
292 static int gadget_tech_set_tethering(struct connman_technology *technology,
293                                 const char *identifier, const char *passphrase,
294                                 const char *bridge, bool enabled, bool hidden)
295 {
296         DBG("bridge %s enabled %d", bridge, enabled);
297
298         if (enabled)
299                 gadget_tech_enable_tethering(technology, bridge);
300         else
301                 gadget_tech_disable_tethering(technology, bridge);
302
303         return 0;
304 }
305
306 static int gadget_tech_probe(struct connman_technology *technology)
307 {
308         return 0;
309 }
310
311 static void gadget_tech_remove(struct connman_technology *technology)
312 {
313         g_list_free(cdc_interface_list);
314
315         cdc_interface_list = NULL;
316 }
317
318 static struct connman_technology_driver gadget_tech_driver = {
319         .name                   = "cdc_ethernet",
320         .type                   = CONNMAN_SERVICE_TYPE_GADGET,
321         .probe                  = gadget_tech_probe,
322         .remove                 = gadget_tech_remove,
323         .add_interface          = gadget_tech_add_interface,
324         .remove_interface       = gadget_tech_remove_interface,
325         .set_tethering          = gadget_tech_set_tethering,
326 };
327
328 static int gadget_init(void)
329 {
330         int err;
331
332         err = connman_technology_driver_register(&gadget_tech_driver);
333         if (err < 0) {
334                 return err;
335         }
336
337         err = connman_network_driver_register(&gadget_network_driver);
338         if (err < 0)
339                 return err;
340
341         err = connman_device_driver_register(&gadget_dev_driver);
342         if (err < 0) {
343                 connman_technology_driver_unregister(&gadget_tech_driver);
344                 return err;
345         }
346
347         return 0;
348 }
349
350 static void gadget_exit(void)
351 {
352         connman_technology_driver_unregister(&gadget_tech_driver);
353         connman_network_driver_unregister(&gadget_network_driver);
354         connman_device_driver_unregister(&gadget_dev_driver);
355 }
356
357 CONNMAN_PLUGIN_DEFINE(gadget, "Gadget interface plugin", VERSION,
358                 CONNMAN_PLUGIN_PRIORITY_DEFAULT, gadget_init, gadget_exit)