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