Remove provider PassphraseRequired property
[framework/connectivity/connman.git] / src / provider.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 <stdio.h>
27 #include <string.h>
28 #include <gdbus.h>
29
30 #include "connman.h"
31
32 static DBusConnection *connection = NULL;
33
34 static GHashTable *provider_hash = NULL;
35
36 static GSList *driver_list = NULL;
37
38 struct connman_provider {
39         struct connman_element element;
40         struct connman_service *vpn_service;
41         char *identifier;
42         char *name;
43         char *type;
44         char *dns;
45         char *domain;
46         struct connman_provider_driver *driver;
47         void *driver_data;
48 };
49
50 void __connman_provider_append_properties(struct connman_provider *provider,
51                                                         DBusMessageIter *iter)
52 {
53         if (provider->name != NULL)
54                 connman_dbus_dict_append_basic(iter, "Name",
55                                         DBUS_TYPE_STRING, &provider->name);
56
57         if (provider->type != NULL)
58                 connman_dbus_dict_append_basic(iter, "Type", DBUS_TYPE_STRING,
59                                                  &provider->type);
60 }
61
62 static void append_path(gpointer key, gpointer value, gpointer user_data)
63 {
64         struct connman_provider *provider = value;
65         DBusMessageIter *iter = user_data;
66         const char *service_path;
67
68         service_path = __connman_service_get_path(provider->vpn_service);
69         if (service_path == NULL)
70                 return;
71
72         dbus_message_iter_append_basic(iter, DBUS_TYPE_OBJECT_PATH,
73                                                         &service_path);
74 }
75
76 void __connman_provider_list(DBusMessageIter *iter, void *user_data)
77 {
78         g_hash_table_foreach(provider_hash, append_path, iter);
79 }
80
81 static struct connman_provider *connman_provider_lookup(const char *identifier)
82 {
83         struct connman_provider *provider = NULL;
84
85         provider = g_hash_table_lookup(provider_hash, identifier);
86
87         return provider;
88 }
89
90 static void connman_provider_setup_vpn_ipv4(struct connman_provider *provider,
91                                                 struct connman_element *element)
92 {
93         if (element == NULL || provider == NULL)
94                 return;
95
96         DBG("set vpn type %d", element->type);
97
98         if (provider == NULL)
99                 return;
100
101         g_free(element->ipv4.address);
102         element->ipv4.address = g_strdup(provider->element.ipv4.address);
103
104         g_free(element->ipv4.netmask);
105         element->ipv4.netmask = g_strdup(provider->element.ipv4.netmask);
106
107         g_free(element->ipv4.gateway);
108         element->ipv4.gateway = g_strdup(provider->element.ipv4.gateway);
109
110         g_free(element->ipv4.broadcast);
111         element->ipv4.broadcast = g_strdup(provider->element.ipv4.broadcast);
112
113         g_free(element->ipv4.pac);
114         element->ipv4.pac = g_strdup(provider->element.ipv4.pac);
115
116         DBG("VPN exist");
117 }
118
119 struct connman_provider *connman_provider_ref(struct connman_provider *provider)
120 {
121         DBG("provider %p", provider);
122
123         if (connman_element_ref(&provider->element) == NULL)
124                 return NULL;
125
126         return provider;
127 }
128
129 void connman_provider_unref(struct connman_provider *provider)
130 {
131         DBG("provider %p", provider);
132
133         connman_element_unref(&provider->element);
134 }
135
136 static gboolean match_driver(struct connman_provider *provider,
137                                 struct connman_provider_driver *driver)
138 {
139         if (g_strcmp0(driver->name, provider->type) == 0)
140                 return TRUE;
141
142         return FALSE;
143 }
144
145 static int provider_probe(struct connman_provider *provider)
146 {
147         GSList *list;
148
149         DBG("provider %p name %s", provider, provider->name);
150
151         if (provider->driver != NULL)
152                 return -EALREADY;
153
154         for (list = driver_list; list; list = list->next) {
155                 struct connman_provider_driver *driver = list->data;
156
157                 if (match_driver(provider, driver) == FALSE)
158                         continue;
159
160                 DBG("driver %p name %s", driver, driver->name);
161
162                 if (driver->probe != NULL && driver->probe(provider) == 0) {
163                         provider->driver = driver;
164                         break;
165                 }
166         }
167
168         if (provider->driver == NULL)
169                 return -ENODEV;
170
171         return 0;
172 }
173
174 int __connman_provider_disconnect(struct connman_provider *provider)
175 {
176         int err;
177
178         DBG("provider %p", provider);
179
180         if (provider->driver != NULL && provider->driver->disconnect != NULL)
181                 err = provider->driver->disconnect(provider);
182         else
183                 return -EOPNOTSUPP;
184
185         __connman_service_indicate_state(provider->vpn_service,
186                                         CONNMAN_SERVICE_STATE_DISCONNECT);
187         if (err < 0) {
188                 if (err != -EINPROGRESS)
189                         return err;
190
191                 return -EINPROGRESS;
192         }
193
194         return 0;
195 }
196
197 int __connman_provider_connect(struct connman_provider *provider)
198 {
199         int err;
200
201         DBG("provider %p", provider);
202
203         g_free(provider->element.ipv4.address);
204         g_free(provider->element.ipv4.netmask);
205         g_free(provider->element.ipv4.gateway);
206         g_free(provider->element.ipv4.broadcast);
207         g_free(provider->element.ipv4.pac);
208
209         provider->element.ipv4.address = NULL;
210         provider->element.ipv4.netmask = NULL;
211         provider->element.ipv4.gateway = NULL;
212         provider->element.ipv4.broadcast = NULL;
213         provider->element.ipv4.pac = NULL;
214
215         if (provider->driver != NULL && provider->driver->connect != NULL)
216                 err = provider->driver->connect(provider);
217         else
218                 return -EOPNOTSUPP;
219
220         if (err < 0) {
221                 if (err != -EINPROGRESS)
222                         return err;
223
224                 __connman_service_indicate_state(provider->vpn_service,
225                                         CONNMAN_SERVICE_STATE_ASSOCIATION);
226                 return -EINPROGRESS;
227         }
228
229         return 0;
230 }
231
232 int __connman_provider_remove(const char *path)
233 {
234         struct connman_provider *provider;
235
236         DBG("path %s", path);
237
238         provider = g_hash_table_lookup(provider_hash, path);
239         if (provider == NULL) {
240                 DBG("patch %s not found", path);
241                 return -ENXIO;
242         }
243
244         g_hash_table_remove(provider_hash, path);
245
246         return 0;
247 }
248
249 int connman_provider_set_connected(struct connman_provider *provider,
250                                                 connman_bool_t connected)
251 {
252         if (connected == TRUE) {
253                 enum connman_element_type type = CONNMAN_ELEMENT_TYPE_UNKNOWN;
254                 struct connman_element *element;
255
256                 type = CONNMAN_ELEMENT_TYPE_IPV4;
257
258                 element = connman_element_create(NULL);
259                 if (element != NULL) {
260                         element->type  = type;
261                         element->index = provider->element.index;
262
263                         connman_provider_setup_vpn_ipv4(provider, element);
264
265                         if (connman_element_register(element,
266                                         &provider->element) < 0)
267                                 connman_element_unref(element);
268                         else {
269                                 char *nameservers = NULL;
270                                 const char *value;
271                                 char *name = NULL;
272
273                                 DBG("set dns");
274                                 nameservers = g_strdup(provider->dns);
275                                 value = nameservers;
276                                 name = connman_inet_ifname(
277                                                 provider->element.index);
278                                 while (value) {
279                                         char *next = strchr(value, ' ');
280                                         if (next)
281                                                 *(next++) = 0;
282
283                                         connman_resolver_append(name,
284                                                         provider->domain,
285                                                         value);
286                                         value = next;
287                                 }
288                                 DBG("free extra");
289                                 g_free(nameservers);
290                                 g_free(name);
291                         }
292
293                 }
294                 __connman_service_indicate_state(provider->vpn_service,
295                                                 CONNMAN_SERVICE_STATE_READY);
296         } else {
297                 connman_element_unregister_children(&provider->element);
298                 __connman_service_indicate_state(provider->vpn_service,
299                                                 CONNMAN_SERVICE_STATE_IDLE);
300         }
301
302         return 0;
303 }
304
305 static void provider_free(gpointer user_data)
306 {
307         struct connman_provider *provider = user_data;
308
309         DBG("provider %p", provider);
310
311         g_free(provider->name);
312         g_free(provider->type);
313         g_free(provider->domain);
314         g_free(provider->identifier);
315         g_free(provider->dns);
316         __connman_service_put(provider->vpn_service);
317 }
318
319 static void unregister_provider(gpointer data)
320 {
321         struct connman_provider *provider = data;
322
323         DBG("provider %p", provider);
324
325         __connman_provider_disconnect(provider);
326
327         connman_element_unregister(&provider->element);
328         connman_provider_unref(provider);
329 }
330
331 static void provider_destruct(struct connman_element *element)
332 {
333         struct connman_provider *provider = element->private;
334
335         DBG("provider %p", provider);
336
337         provider_free(provider);
338 }
339
340 static void __connman_provider_initialize(struct connman_provider *provider)
341 {
342         DBG("provider %p", provider);
343
344         __connman_element_initialize(&provider->element);
345
346         provider->element.private = provider;
347         provider->element.destruct = provider_destruct;
348
349         provider->element.ipv4.address = NULL;
350         provider->element.ipv4.netmask = NULL;
351         provider->element.ipv4.gateway = NULL;
352         provider->element.ipv4.broadcast = NULL;
353         provider->element.ipv4.pac = NULL;
354
355         provider->name = NULL;
356         provider->type = NULL;
357         provider->dns = NULL;
358         provider->domain = NULL;
359         provider->identifier = NULL;
360 }
361
362 static struct connman_provider *connman_provider_new(void)
363 {
364         struct connman_provider *provider;
365
366         provider = g_try_new0(struct connman_provider, 1);
367         if (provider == NULL)
368                 return NULL;
369
370         DBG("provider %p", provider);
371         __connman_provider_initialize(provider);
372
373         return provider;
374 }
375
376 static int provider_register(struct connman_provider *provider)
377 {
378         DBG("provider %p", provider);
379
380         return 0;
381 }
382
383 static struct connman_provider *connman_provider_get(const char *identifier)
384 {
385         struct connman_provider *provider;
386
387         provider = g_hash_table_lookup(provider_hash, identifier);
388         if (provider != NULL)
389                 return provider;
390
391         provider = connman_provider_new();
392         if (provider == NULL)
393                 return NULL;
394
395         DBG("provider %p", provider);
396
397         provider->identifier = g_strdup(identifier);
398
399         g_hash_table_insert(provider_hash, provider->identifier, provider);
400
401         provider->element.name = g_strdup(identifier);
402         connman_element_register(&provider->element, NULL);
403
404         return provider;
405 }
406
407 static struct connman_provider *connman_provider_create(const char *name)
408 {
409         struct connman_provider *provider;
410
411         provider = connman_provider_get(name);
412
413         if (provider == NULL)
414                 return NULL;
415
416         provider_register(provider);
417
418         return provider;
419 }
420
421 int __connman_provider_create_and_connect(DBusMessage *msg)
422 {
423         struct connman_provider *provider;
424         DBusMessageIter iter, array;
425         const char *type = NULL, *name = NULL, *service_path = NULL;
426         char *ident;
427         gboolean created = FALSE;
428         int err;
429
430         dbus_message_iter_init(msg, &iter);
431         dbus_message_iter_recurse(&iter, &array);
432
433         while (dbus_message_iter_get_arg_type(&array) == DBUS_TYPE_DICT_ENTRY) {
434                 DBusMessageIter entry, value;
435                 const char *key;
436
437                 dbus_message_iter_recurse(&array, &entry);
438                 dbus_message_iter_get_basic(&entry, &key);
439
440                 dbus_message_iter_next(&entry);
441                 dbus_message_iter_recurse(&entry, &value);
442
443                 switch (dbus_message_iter_get_arg_type(&value)) {
444                 case DBUS_TYPE_STRING:
445                         if (g_str_equal(key, "Type") == TRUE)
446                                 dbus_message_iter_get_basic(&value, &type);
447                         else if (g_str_equal(key, "Name") == TRUE)
448                                 dbus_message_iter_get_basic(&value, &name);
449                         break;
450                 }
451
452                 if (type != NULL && name != NULL)
453                         break;
454
455                 dbus_message_iter_next(&array);
456         }
457
458         DBG("Type %s name %s", type, name);
459
460         if (type == NULL || name == NULL) {
461                 err = -EOPNOTSUPP;
462                 goto failed;
463         }
464
465         ident = g_strdup_printf("%s_%s", type, name);
466
467         provider = connman_provider_lookup(ident);
468
469         if (provider == NULL) {
470                 created = TRUE;
471                 provider = connman_provider_create(ident);
472                 if (provider) {
473                         provider->name = g_strdup(name);
474                         provider->type = g_strdup(type);
475                 }
476         }
477
478         if (provider == NULL) {
479                 DBG("can not create provider");
480                 err = -EOPNOTSUPP;
481                 goto failed;
482         }
483         dbus_message_iter_init(msg, &iter);
484         dbus_message_iter_recurse(&iter, &array);
485
486         while (dbus_message_iter_get_arg_type(&array) == DBUS_TYPE_DICT_ENTRY) {
487                 DBusMessageIter entry, value;
488                 const char *key, *str;
489
490                 dbus_message_iter_recurse(&array, &entry);
491                 dbus_message_iter_get_basic(&entry, &key);
492
493                 dbus_message_iter_next(&entry);
494                 dbus_message_iter_recurse(&entry, &value);
495
496                 switch (dbus_message_iter_get_arg_type(&value)) {
497                 case DBUS_TYPE_STRING:
498                         dbus_message_iter_get_basic(&value, &str);
499                         connman_provider_set_string(provider, key, str);
500                         break;
501                 }
502
503                 dbus_message_iter_next(&array);
504         }
505
506         g_free(ident);
507
508         if (provider == NULL) {
509                 err = -EOPNOTSUPP;
510                 goto failed;
511         }
512
513         if (created == TRUE)
514                 provider_probe(provider);
515
516         provider->vpn_service =
517                         __connman_service_create_from_provider(provider);
518         if (provider->vpn_service == NULL) {
519                 err = -EOPNOTSUPP;
520                 goto failed;
521         }
522
523         err = __connman_service_connect(provider->vpn_service);
524         if (err < 0 && err != -EINPROGRESS)
525                 goto failed;
526
527         service_path = __connman_service_get_path(provider->vpn_service);
528         g_dbus_send_reply(connection, msg,
529                                 DBUS_TYPE_OBJECT_PATH, &service_path,
530                                                         DBUS_TYPE_INVALID);
531         return 0;
532
533 failed:
534         if (provider != NULL && created == TRUE) {
535                 DBG("can not connect delete provider");
536                 connman_provider_unref(provider);
537
538                 if (provider->vpn_service != NULL)
539                         __connman_service_put(provider->vpn_service);
540         }
541
542         return err;
543 }
544
545 const char * __connman_provider_get_ident(struct connman_provider *provider)
546 {
547         if (provider == NULL)
548                 return NULL;
549
550         return provider->identifier;
551 }
552
553 int connman_provider_set_string(struct connman_provider *provider,
554                                         const char *key, const char *value)
555 {
556         DBG("provider %p key %s value %s", provider, key, value);
557
558         if (g_str_equal(key, "Type") == TRUE) {
559                 g_free(provider->type);
560                 provider->type = g_strdup(value);
561         } else if (g_str_equal(key, "Name") == TRUE) {
562                 g_free(provider->name);
563                 provider->name = g_strdup(value);
564         } else if (g_str_equal(key, "Gateway") == TRUE) {
565                 g_free(provider->element.ipv4.gateway);
566                 provider->element.ipv4.gateway = g_strdup(value);
567         } else if (g_str_equal(key, "Address") == TRUE) {
568                 g_free(provider->element.ipv4.address);
569                 provider->element.ipv4.address = g_strdup(value);
570         } else if (g_str_equal(key, "Netmask") == TRUE) {
571                 g_free(provider->element.ipv4.netmask);
572                 provider->element.ipv4.netmask = g_strdup(value);
573         } else if (g_str_equal(key, "PAC") == TRUE) {
574                 g_free(provider->element.ipv4.pac);
575                 provider->element.ipv4.pac = g_strdup(value);
576         } else if (g_str_equal(key, "DNS") == TRUE) {
577                 g_free(provider->dns);
578                 provider->dns = g_strdup(value);
579         } else if (g_str_equal(key, "Domain") == TRUE) {
580                 g_free(provider->domain);
581                 provider->domain = g_strdup(value);
582         }
583
584         return connman_element_set_string(&provider->element, key, value);
585 }
586
587 const char *connman_provider_get_string(struct connman_provider *provider,
588                                                         const char *key)
589 {
590         DBG("provider %p key %s", provider, key);
591
592         if (g_str_equal(key, "Type") == TRUE)
593                 return provider->type;
594         else if (g_str_equal(key, "Name") == TRUE)
595                 return provider->name;
596
597         return connman_element_get_string(&provider->element, key);
598 }
599
600 void *connman_provider_get_data(struct connman_provider *provider)
601 {
602         return provider->driver_data;
603 }
604
605 void connman_provider_set_data(struct connman_provider *provider, void *data)
606 {
607         provider->driver_data = data;
608 }
609
610 void connman_provider_set_index(struct connman_provider *provider, int index)
611 {
612         provider->element.index = index;
613 }
614
615 int connman_provider_get_index(struct connman_provider *provider)
616 {
617         return provider->element.index;
618 }
619
620 static gint compare_priority(gconstpointer a, gconstpointer b)
621 {
622         return 0;
623 }
624
625 static void clean_provider(gpointer key, gpointer value, gpointer user_data)
626 {
627         struct connman_provider *provider = value;
628
629         if (provider->driver != NULL && provider->driver->remove)
630                 provider->driver->remove(provider);
631 }
632
633 int connman_provider_driver_register(struct connman_provider_driver *driver)
634 {
635         DBG("driver %p name %s", driver, driver->name);
636
637         driver_list = g_slist_insert_sorted(driver_list, driver,
638                                                         compare_priority);
639         return 0;
640 }
641
642 void connman_provider_driver_unregister(struct connman_provider_driver *driver)
643 {
644         DBG("driver %p name %s", driver, driver->name);
645
646         driver_list = g_slist_remove(driver_list, driver);
647 }
648
649 int __connman_provider_init(void)
650 {
651         DBG("");
652
653         connection = connman_dbus_get_connection();
654
655         provider_hash = g_hash_table_new_full(g_str_hash, g_str_equal,
656                                                 NULL, unregister_provider);
657         return 0;
658 }
659
660 void __connman_provider_cleanup(void)
661 {
662         DBG("");
663
664         g_hash_table_foreach(provider_hash, clean_provider, NULL);
665
666         g_hash_table_destroy(provider_hash);
667         provider_hash = NULL;
668
669         dbus_connection_unref(connection);
670 }