Add function to get index value from DHCP structure
[framework/connectivity/connman.git] / src / ipconfig.c
1 /*
2  *
3  *  Connection Manager
4  *
5  *  Copyright (C) 2007-2009  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 <net/if.h>
27 #include <net/if_arp.h>
28
29 #ifndef IFF_LOWER_UP
30 #define IFF_LOWER_UP    0x10000
31 #endif
32
33 #include <gdbus.h>
34
35 #include "connman.h"
36
37 struct connman_ipconfig {
38         gint refcount;
39         int index;
40
41         struct connman_ipconfig *origin;
42
43         const struct connman_ipconfig_ops *ops;
44         void *ops_data;
45
46         enum connman_ipconfig_method method;
47         struct connman_ipaddress *address;
48 };
49
50 struct connman_ipdevice {
51         int index;
52         char *ifname;
53         unsigned short type;
54         unsigned int flags;
55
56         GSList *address_list;
57         char *gateway;
58
59         struct connman_ipconfig *config;
60
61         struct connman_ipconfig_driver *driver;
62         struct connman_ipconfig *driver_config;
63 };
64
65 static GHashTable *ipdevice_hash = NULL;
66 static GList *ipconfig_list = NULL;
67
68 struct connman_ipaddress *connman_ipaddress_alloc(void)
69 {
70         struct connman_ipaddress *ipaddress;
71
72         ipaddress = g_try_new0(struct connman_ipaddress, 1);
73         if (ipaddress == NULL)
74                 return NULL;
75
76         return ipaddress;
77 }
78
79 void connman_ipaddress_free(struct connman_ipaddress *ipaddress)
80 {
81         if (ipaddress == NULL)
82                 return;
83
84         g_free(ipaddress->broadcast);
85         g_free(ipaddress->peer);
86         g_free(ipaddress->local);
87         g_free(ipaddress);
88 }
89
90 void connman_ipaddress_copy(struct connman_ipaddress *ipaddress,
91                                         struct connman_ipaddress *source)
92 {
93         if (ipaddress == NULL || source == NULL)
94                 return;
95
96         ipaddress->prefixlen = source->prefixlen;
97
98         g_free(ipaddress->local);
99         ipaddress->local = g_strdup(source->local);
100
101         g_free(ipaddress->peer);
102         ipaddress->peer = g_strdup(source->peer);
103
104         g_free(ipaddress->broadcast);
105         ipaddress->broadcast = g_strdup(source->broadcast);
106 }
107
108 static void free_address_list(struct connman_ipdevice *ipdevice)
109 {
110         GSList *list;
111
112         for (list = ipdevice->address_list; list; list = list->next) {
113                 struct connman_ipaddress *ipaddress = list->data;
114
115                 connman_ipaddress_free(ipaddress);
116                 list->data = NULL;
117         }
118
119         g_slist_free(ipdevice->address_list);
120         ipdevice->address_list = NULL;
121 }
122
123 static struct connman_ipaddress *find_ipaddress(struct connman_ipdevice *ipdevice,
124                                 unsigned char prefixlen, const char *local)
125 {
126         GSList *list;
127
128         for (list = ipdevice->address_list; list; list = list->next) {
129                 struct connman_ipaddress *ipaddress = list->data;
130
131                 if (g_strcmp0(ipaddress->local, local) == 0 &&
132                                         ipaddress->prefixlen == prefixlen)
133                         return ipaddress;
134         }
135
136         return NULL;
137 }
138
139 static const char *type2str(unsigned short type)
140 {
141         switch (type) {
142         case ARPHRD_ETHER:
143                 return "ETHER";
144         case ARPHRD_LOOPBACK:
145                 return "LOOPBACK";
146         case ARPHRD_PPP:
147                 return "PPP";
148         case ARPHRD_NONE:
149                 return "NONE";
150         case ARPHRD_VOID:
151                 return "VOID";
152         }
153
154         return "";
155 }
156
157 static const char *scope2str(unsigned char scope)
158 {
159         switch (scope) {
160         case 0:
161                 return "UNIVERSE";
162         case 253:
163                 return "LINK";
164         }
165
166         return "";
167 }
168
169 static void free_ipdevice(gpointer data)
170 {
171         struct connman_ipdevice *ipdevice = data;
172
173         connman_info("%s {remove} index %d", ipdevice->ifname,
174                                                         ipdevice->index);
175
176         if (ipdevice->config != NULL)
177                 connman_ipconfig_unref(ipdevice->config);
178
179         free_address_list(ipdevice);
180         g_free(ipdevice->gateway);
181
182         g_free(ipdevice->ifname);
183         g_free(ipdevice);
184 }
185
186 static GSList *driver_list = NULL;
187
188 static gint compare_priority(gconstpointer a, gconstpointer b)
189 {
190         const struct connman_ipconfig_driver *driver1 = a;
191         const struct connman_ipconfig_driver *driver2 = b;
192
193         return driver2->priority - driver1->priority;
194 }
195
196 /**
197  * connman_ipconfig_driver_register:
198  * @driver: IP configuration driver
199  *
200  * Register a new IP configuration driver
201  *
202  * Returns: %0 on success
203  */
204 int connman_ipconfig_driver_register(struct connman_ipconfig_driver *driver)
205 {
206         DBG("driver %p name %s", driver, driver->name);
207
208         driver_list = g_slist_insert_sorted(driver_list, driver,
209                                                         compare_priority);
210
211         return 0;
212 }
213
214 /**
215  * connman_ipconfig_driver_unregister:
216  * @driver: IP configuration driver
217  *
218  * Remove a previously registered IP configuration driver.
219  */
220 void connman_ipconfig_driver_unregister(struct connman_ipconfig_driver *driver)
221 {
222         DBG("driver %p name %s", driver, driver->name);
223
224         driver_list = g_slist_remove(driver_list, driver);
225 }
226
227 static void __connman_ipconfig_lower_up(struct connman_ipdevice *ipdevice)
228 {
229         GSList *list;
230
231         DBG("ipconfig %p", ipdevice->config);
232
233         if (ipdevice->config == NULL)
234                 return;
235
236         switch (ipdevice->config->method) {
237         case CONNMAN_IPCONFIG_METHOD_UNKNOWN:
238         case CONNMAN_IPCONFIG_METHOD_IGNORE:
239         case CONNMAN_IPCONFIG_METHOD_STATIC:
240                 return;
241         case CONNMAN_IPCONFIG_METHOD_DHCP:
242                 break;
243         }
244
245         if (ipdevice->driver != NULL)
246                 return;
247
248         ipdevice->driver_config = connman_ipconfig_clone(ipdevice->config);
249         if (ipdevice->driver_config == NULL)
250                 return;
251
252         for (list = driver_list; list; list = list->next) {
253                 struct connman_ipconfig_driver *driver = list->data;
254
255                 if (driver->request(ipdevice->driver_config) == 0) {
256                         ipdevice->driver = driver;
257                         break;
258                 }
259         }
260
261         if (ipdevice->driver == NULL) {
262                 connman_ipconfig_unref(ipdevice->driver_config);
263                 ipdevice->driver_config = NULL;
264         }
265 }
266
267 static void __connman_ipconfig_lower_down(struct connman_ipdevice *ipdevice)
268 {
269         DBG("ipconfig %p", ipdevice->config);
270
271         if (ipdevice->config == NULL)
272                 return;
273
274         if (ipdevice->driver == NULL)
275                 return;
276
277         ipdevice->driver->release(ipdevice->driver_config);
278
279         ipdevice->driver = NULL;
280
281         connman_ipconfig_unref(ipdevice->driver_config);
282         ipdevice->driver_config = NULL;
283
284         connman_inet_clear_address(ipdevice->index);
285 }
286
287 void __connman_ipconfig_newlink(int index, unsigned short type,
288                                                         unsigned int flags)
289 {
290         struct connman_ipdevice *ipdevice;
291         GList *list;
292         GString *str;
293         gboolean up = FALSE, down = FALSE;
294         gboolean lower_up = FALSE, lower_down = FALSE;
295         char *ifname;
296
297         DBG("index %d", index);
298
299         if (type == ARPHRD_LOOPBACK)
300                 return;
301
302         ipdevice = g_hash_table_lookup(ipdevice_hash, GINT_TO_POINTER(index));
303         if (ipdevice != NULL)
304                 goto update;
305
306         ifname = connman_inet_ifname(index);
307
308         if (__connman_element_device_isfiltered(ifname) == TRUE) {
309                 connman_info("Ignoring interface %s (filtered)", ifname);
310                 g_free(ifname);
311                 return;
312         }
313
314         ipdevice = g_try_new0(struct connman_ipdevice, 1);
315         if (ipdevice == NULL) {
316                 g_free(ifname);
317                 return;
318         }
319
320         ipdevice->index = index;
321         ipdevice->ifname = ifname;
322         ipdevice->type = type;
323
324         g_hash_table_insert(ipdevice_hash, GINT_TO_POINTER(index), ipdevice);
325
326         connman_info("%s {create} index %d type %d <%s>", ipdevice->ifname,
327                                                 index, type, type2str(type));
328
329 update:
330         if (flags == ipdevice->flags)
331                 return;
332
333         if ((ipdevice->flags & IFF_UP) != (flags & IFF_UP)) {
334                 if (flags & IFF_UP)
335                         up = TRUE;
336                 else
337                         down = TRUE;
338         }
339
340         if ((ipdevice->flags & (IFF_RUNNING | IFF_LOWER_UP)) !=
341                                 (flags & (IFF_RUNNING | IFF_LOWER_UP))) {
342                 if ((flags & (IFF_RUNNING | IFF_LOWER_UP)) ==
343                                         (IFF_RUNNING | IFF_LOWER_UP))
344                         lower_up = TRUE;
345                 else if ((flags & (IFF_RUNNING | IFF_LOWER_UP)) == 0)
346                         lower_down = TRUE;
347         }
348
349         connman_inet_clear_address(index);
350
351         ipdevice->flags = flags;
352
353         str = g_string_new(NULL);
354         if (str == NULL)
355                 return;
356
357         if (flags & IFF_UP)
358                 g_string_append(str, "UP");
359         else
360                 g_string_append(str, "DOWN");
361
362         if (flags & IFF_RUNNING)
363                 g_string_append(str, ",RUNNING");
364
365         if (flags & IFF_LOWER_UP)
366                 g_string_append(str, ",LOWER_UP");
367
368         connman_info("%s {update} flags %u <%s>", ipdevice->ifname,
369                                                         flags, str->str);
370
371         g_string_free(str, TRUE);
372
373         for (list = g_list_first(ipconfig_list); list;
374                                                 list = g_list_next(list)) {
375                 struct connman_ipconfig *ipconfig = list->data;
376
377                 if (index != ipconfig->index)
378                         continue;
379
380                 if (up == TRUE && ipconfig->ops->up)
381                         ipconfig->ops->up(ipconfig);
382                 if (lower_up == TRUE && ipconfig->ops->lower_up)
383                         ipconfig->ops->lower_up(ipconfig);
384
385                 if (lower_down == TRUE && ipconfig->ops->lower_down)
386                         ipconfig->ops->lower_down(ipconfig);
387                 if (down == TRUE && ipconfig->ops->down)
388                         ipconfig->ops->down(ipconfig);
389         }
390
391         if (lower_up)
392                 __connman_ipconfig_lower_up(ipdevice);
393         if (lower_down)
394                 __connman_ipconfig_lower_down(ipdevice);
395 }
396
397 void __connman_ipconfig_dellink(int index)
398 {
399         struct connman_ipdevice *ipdevice;
400         GList *list;
401
402         DBG("index %d", index);
403
404         ipdevice = g_hash_table_lookup(ipdevice_hash, GINT_TO_POINTER(index));
405         if (ipdevice == NULL)
406                 return;
407
408         for (list = g_list_first(ipconfig_list); list;
409                                                 list = g_list_next(list)) {
410                 struct connman_ipconfig *ipconfig = list->data;
411
412                 if (index != ipconfig->index)
413                         continue;
414
415                 ipconfig->index = -1;
416
417                 if (ipconfig->ops->lower_down)
418                         ipconfig->ops->lower_down(ipconfig);
419                 if (ipconfig->ops->down)
420                         ipconfig->ops->down(ipconfig);
421         }
422
423         __connman_ipconfig_lower_down(ipdevice);
424
425         g_hash_table_remove(ipdevice_hash, GINT_TO_POINTER(index));
426 }
427
428 void __connman_ipconfig_newaddr(int index, const char *label,
429                                 unsigned char prefixlen, const char *address)
430 {
431         struct connman_ipdevice *ipdevice;
432         struct connman_ipaddress *ipaddress;
433         GList *list;
434
435         DBG("index %d", index);
436
437         ipdevice = g_hash_table_lookup(ipdevice_hash, GINT_TO_POINTER(index));
438         if (ipdevice == NULL)
439                 return;
440
441         ipaddress = connman_ipaddress_alloc();
442         if (ipaddress == NULL)
443                 return;
444
445         ipaddress->prefixlen = prefixlen;
446         ipaddress->local = g_strdup(address);
447
448         ipdevice->address_list = g_slist_append(ipdevice->address_list,
449                                                                 ipaddress);
450
451         connman_info("%s {add} address %s/%u label %s", ipdevice->ifname,
452                                                 address, prefixlen, label);
453
454         if ((ipdevice->flags & (IFF_RUNNING | IFF_LOWER_UP)) != (IFF_RUNNING | IFF_LOWER_UP))
455                 return;
456
457         if (g_slist_length(ipdevice->address_list) > 1)
458                 return;
459
460         for (list = g_list_first(ipconfig_list); list;
461                                                 list = g_list_next(list)) {
462                 struct connman_ipconfig *ipconfig = list->data;
463
464                 if (index != ipconfig->index)
465                         continue;
466
467                 if (ipconfig->ops->ip_bound)
468                         ipconfig->ops->ip_bound(ipconfig);
469         }
470 }
471
472 void __connman_ipconfig_deladdr(int index, const char *label,
473                                 unsigned char prefixlen, const char *address)
474 {
475         struct connman_ipdevice *ipdevice;
476         struct connman_ipaddress *ipaddress;
477         GList *list;
478
479         DBG("index %d", index);
480
481         ipdevice = g_hash_table_lookup(ipdevice_hash, GINT_TO_POINTER(index));
482         if (ipdevice == NULL)
483                 return;
484
485         ipaddress = find_ipaddress(ipdevice, prefixlen, address);
486         if (ipaddress == NULL)
487                 return;
488
489         ipdevice->address_list = g_slist_remove(ipdevice->address_list,
490                                                                 ipaddress);
491
492         connman_ipaddress_free(ipaddress);
493
494         connman_info("%s {del} address %s/%u label %s", ipdevice->ifname,
495                                                 address, prefixlen, label);
496
497         if ((ipdevice->flags & (IFF_RUNNING | IFF_LOWER_UP)) != (IFF_RUNNING | IFF_LOWER_UP))
498                 return;
499
500         if (g_slist_length(ipdevice->address_list) > 0)
501                 return;
502
503         for (list = g_list_first(ipconfig_list); list;
504                                                 list = g_list_next(list)) {
505                 struct connman_ipconfig *ipconfig = list->data;
506
507                 if (index != ipconfig->index)
508                         continue;
509
510                 if (ipconfig->ops->ip_release)
511                         ipconfig->ops->ip_release(ipconfig);
512         }
513 }
514
515 void __connman_ipconfig_newroute(int index, unsigned char scope,
516                                         const char *dst, const char *gateway)
517 {
518         struct connman_ipdevice *ipdevice;
519
520         DBG("index %d", index);
521
522         ipdevice = g_hash_table_lookup(ipdevice_hash, GINT_TO_POINTER(index));
523         if (ipdevice == NULL)
524                 return;
525
526         if (scope == 0 && g_strcmp0(dst, "0.0.0.0") == 0) {
527                 g_free(ipdevice->gateway);
528                 ipdevice->gateway = g_strdup(gateway);
529         }
530
531         connman_info("%s {add} route %s gw %s scope %u <%s>",
532                                         ipdevice->ifname, dst, gateway,
533                                                 scope, scope2str(scope));
534 }
535
536 void __connman_ipconfig_delroute(int index, unsigned char scope,
537                                         const char *dst, const char *gateway)
538 {
539         struct connman_ipdevice *ipdevice;
540
541         DBG("index %d", index);
542
543         ipdevice = g_hash_table_lookup(ipdevice_hash, GINT_TO_POINTER(index));
544         if (ipdevice == NULL)
545                 return;
546
547         if (scope == 0 && g_strcmp0(dst, "0.0.0.0") == 0) {
548                 g_free(ipdevice->gateway);
549                 ipdevice->gateway = NULL;
550         }
551
552         connman_info("%s {del} route %s gw %s scope %u <%s>",
553                                         ipdevice->ifname, dst, gateway,
554                                                 scope, scope2str(scope));
555 }
556
557 void __connman_ipconfig_foreach(void (*function) (int index, void *user_data),
558                                                         void *user_data)
559 {
560         GList *list, *keys;
561
562         keys = g_hash_table_get_keys(ipdevice_hash);
563         if (keys == NULL)
564                 return;
565
566         for (list = g_list_first(keys); list; list = g_list_next(list)) {
567                 int index = GPOINTER_TO_INT(list->data);
568
569                 function(index, user_data);
570         }
571
572         g_list_free(keys);
573 }
574
575 unsigned short __connman_ipconfig_get_type(int index)
576 {
577         struct connman_ipdevice *ipdevice;
578
579         ipdevice = g_hash_table_lookup(ipdevice_hash, GINT_TO_POINTER(index));
580         if (ipdevice == NULL)
581                 return ARPHRD_VOID;
582
583         return ipdevice->type;
584 }
585
586 unsigned int __connman_ipconfig_get_flags(int index)
587 {
588         struct connman_ipdevice *ipdevice;
589
590         ipdevice = g_hash_table_lookup(ipdevice_hash, GINT_TO_POINTER(index));
591         if (ipdevice == NULL)
592                 return 0;
593
594         return ipdevice->flags;
595 }
596
597 const char *__connman_ipconfig_get_gateway(int index)
598 {
599         struct connman_ipdevice *ipdevice;
600
601         ipdevice = g_hash_table_lookup(ipdevice_hash, GINT_TO_POINTER(index));
602         if (ipdevice == NULL)
603                 return NULL;
604
605         return ipdevice->gateway;
606 }
607
608 /**
609  * connman_ipconfig_create:
610  *
611  * Allocate a new ipconfig structure.
612  *
613  * Returns: a newly-allocated #connman_ipconfig structure
614  */
615 struct connman_ipconfig *connman_ipconfig_create(int index)
616 {
617         struct connman_ipconfig *ipconfig;
618
619         DBG("index %d", index);
620
621         ipconfig = g_try_new0(struct connman_ipconfig, 1);
622         if (ipconfig == NULL)
623                 return NULL;
624
625         ipconfig->refcount = 1;
626
627         ipconfig->index = index;
628
629         ipconfig->address = connman_ipaddress_alloc();
630         if (ipconfig->address == NULL) {
631                 g_free(ipconfig);
632                 return NULL;
633         }
634
635         DBG("ipconfig %p", ipconfig);
636
637         return ipconfig;
638 }
639
640 /**
641  * connman_ipconfig_clone:
642  *
643  * Clone an ipconfig structure and create new reference.
644  *
645  * Returns: a newly-allocated #connman_ipconfig structure
646  */
647 struct connman_ipconfig *connman_ipconfig_clone(struct connman_ipconfig *ipconfig)
648 {
649         struct connman_ipconfig *ipconfig_clone;
650
651         DBG("ipconfig %p", ipconfig);
652
653         ipconfig_clone = g_try_new0(struct connman_ipconfig, 1);
654         if (ipconfig_clone == NULL)
655                 return NULL;
656
657         ipconfig_clone->refcount = 1;
658
659         ipconfig_clone->origin = connman_ipconfig_ref(ipconfig);
660
661         ipconfig_clone->index = -1;
662
663         return ipconfig_clone;
664 }
665
666 /**
667  * connman_ipconfig_ref:
668  * @ipconfig: ipconfig structure
669  *
670  * Increase reference counter of ipconfig
671  */
672 struct connman_ipconfig *connman_ipconfig_ref(struct connman_ipconfig *ipconfig)
673 {
674         g_atomic_int_inc(&ipconfig->refcount);
675
676         return ipconfig;
677 }
678
679 /**
680  * connman_ipconfig_unref:
681  * @ipconfig: ipconfig structure
682  *
683  * Decrease reference counter of ipconfig
684  */
685 void connman_ipconfig_unref(struct connman_ipconfig *ipconfig)
686 {
687         if (g_atomic_int_dec_and_test(&ipconfig->refcount) == TRUE) {
688                 connman_ipconfig_set_ops(ipconfig, NULL);
689
690                 if (ipconfig->origin != NULL) {
691                         connman_ipconfig_unref(ipconfig->origin);
692                         ipconfig->origin = NULL;
693                 }
694
695                 connman_ipaddress_free(ipconfig->address);
696                 g_free(ipconfig);
697         }
698 }
699
700 /**
701  * connman_ipconfig_get_data:
702  * @ipconfig: ipconfig structure
703  *
704  * Get private data pointer
705  */
706 void *connman_ipconfig_get_data(struct connman_ipconfig *ipconfig)
707 {
708         return ipconfig->ops_data;
709 }
710
711 /**
712  * connman_ipconfig_set_data:
713  * @ipconfig: ipconfig structure
714  * @data: data pointer
715  *
716  * Set private data pointer
717  */
718 void connman_ipconfig_set_data(struct connman_ipconfig *ipconfig, void *data)
719 {
720         ipconfig->ops_data = data;
721 }
722
723 /**
724  * connman_ipconfig_get_index:
725  * @ipconfig: ipconfig structure
726  *
727  * Get interface index
728  */
729 int connman_ipconfig_get_index(struct connman_ipconfig *ipconfig)
730 {
731         if (ipconfig->origin != NULL)
732                 return ipconfig->origin->index;
733
734         return ipconfig->index;
735 }
736
737 /**
738  * connman_ipconfig_get_ifname:
739  * @ipconfig: ipconfig structure
740  *
741  * Get interface name
742  */
743 const char *connman_ipconfig_get_ifname(struct connman_ipconfig *ipconfig)
744 {
745         struct connman_ipdevice *ipdevice;
746
747         if (ipconfig->index < 0)
748                 return NULL;
749
750         ipdevice = g_hash_table_lookup(ipdevice_hash,
751                                         GINT_TO_POINTER(ipconfig->index));
752         if (ipdevice == NULL)
753                 return NULL;
754
755         return ipdevice->ifname;
756 }
757
758 /**
759  * connman_ipconfig_set_ops:
760  * @ipconfig: ipconfig structure
761  * @ops: operation callbacks
762  *
763  * Set the operation callbacks
764  */
765 void connman_ipconfig_set_ops(struct connman_ipconfig *ipconfig,
766                                 const struct connman_ipconfig_ops *ops)
767 {
768         if (ipconfig->ops != NULL)
769                 ipconfig_list = g_list_remove(ipconfig_list, ipconfig);
770
771         ipconfig->ops = ops;
772
773         if (ops != NULL)
774                 ipconfig_list = g_list_append(ipconfig_list, ipconfig);
775 }
776
777 /**
778  * connman_ipconfig_set_method:
779  * @ipconfig: ipconfig structure
780  * @method: configuration method
781  *
782  * Set the configuration method
783  */
784 int connman_ipconfig_set_method(struct connman_ipconfig *ipconfig,
785                                         enum connman_ipconfig_method method)
786 {
787         ipconfig->method = method;
788
789         return 0;
790 }
791
792 /**
793  * connman_ipconfig_bind:
794  * @ipconfig: ipconfig structure
795  * @ipaddress: ipaddress structure
796  *
797  * Bind IP address details to configuration
798  */
799 void connman_ipconfig_bind(struct connman_ipconfig *ipconfig,
800                                         struct connman_ipaddress *ipaddress)
801 {
802         struct connman_ipconfig *origin;
803
804         origin = ipconfig->origin ? ipconfig->origin : ipconfig;
805
806         connman_ipaddress_copy(origin->address, ipaddress);
807
808         connman_inet_set_address(origin->index, origin->address);
809 }
810
811 int __connman_ipconfig_enable(struct connman_ipconfig *ipconfig)
812 {
813         struct connman_ipdevice *ipdevice;
814
815         DBG("ipconfig %p", ipconfig);
816
817         if (ipconfig == NULL || ipconfig->index < 0)
818                 return -ENODEV;
819
820         ipdevice = g_hash_table_lookup(ipdevice_hash,
821                                         GINT_TO_POINTER(ipconfig->index));
822         if (ipdevice == NULL)
823                 return -ENXIO;
824
825         if (ipdevice->config != NULL)
826                 connman_ipconfig_unref(ipdevice->config);
827
828         ipdevice->config = connman_ipconfig_ref(ipconfig);
829
830         return 0;
831 }
832
833 int __connman_ipconfig_disable(struct connman_ipconfig *ipconfig)
834 {
835         struct connman_ipdevice *ipdevice;
836
837         DBG("ipconfig %p", ipconfig);
838
839         if (ipconfig == NULL || ipconfig->index < 0)
840                 return -ENODEV;
841
842         ipdevice = g_hash_table_lookup(ipdevice_hash,
843                                         GINT_TO_POINTER(ipconfig->index));
844         if (ipdevice == NULL)
845                 return -ENXIO;
846
847         if (ipdevice->config == NULL || ipdevice->config != ipconfig)
848                 return -EINVAL;
849
850         connman_ipconfig_unref(ipdevice->config);
851         ipdevice->config = NULL;
852
853         return 0;
854 }
855
856 const char *__connman_ipconfig_method2string(enum connman_ipconfig_method method)
857 {
858         switch (method) {
859         case CONNMAN_IPCONFIG_METHOD_UNKNOWN:
860                 break;
861         case CONNMAN_IPCONFIG_METHOD_IGNORE:
862                 return "ignore";
863         case CONNMAN_IPCONFIG_METHOD_STATIC:
864                 return "static";
865         case CONNMAN_IPCONFIG_METHOD_DHCP:
866                 return "dhcp";
867         }
868
869         return NULL;
870 }
871
872 enum connman_ipconfig_method __connman_ipconfig_string2method(const char *method)
873 {
874         if (g_strcmp0(method, "ignore") == 0)
875                 return CONNMAN_IPCONFIG_METHOD_IGNORE;
876         else if (g_strcmp0(method, "static") == 0)
877                 return CONNMAN_IPCONFIG_METHOD_STATIC;
878         else if (g_strcmp0(method, "dhcp") == 0)
879                 return CONNMAN_IPCONFIG_METHOD_DHCP;
880         else
881                 return CONNMAN_IPCONFIG_METHOD_UNKNOWN;
882 }
883
884 static void append_variant(DBusMessageIter *iter, const char *prefix,
885                                         const char *key, int type, void *val)
886 {
887         char *str;
888
889         if (prefix == NULL) {
890                 connman_dbus_dict_append_variant(iter, key, type, val);
891                 return;
892         }
893
894         str = g_strdup_printf("%s%s", prefix, key);
895         if (str != NULL)
896                 connman_dbus_dict_append_variant(iter, str, type, val);
897
898         g_free(str);
899 }
900
901 void __connman_ipconfig_append_ipv4(struct connman_ipconfig *ipconfig,
902                                 DBusMessageIter *iter, const char *prefix)
903 {
904         const char *str;
905
906         str = __connman_ipconfig_method2string(ipconfig->method);
907         if (str == NULL)
908                 return;
909
910         append_variant(iter, prefix, "Method", DBUS_TYPE_STRING, &str);
911 }
912
913 int __connman_ipconfig_set_ipv4(struct connman_ipconfig *ipconfig,
914                                 const char *key, DBusMessageIter *value)
915 {
916         int type = dbus_message_iter_get_arg_type(value);
917
918         DBG("ipconfig %p key %s type %d", ipconfig, key, type);
919
920         if (g_strcmp0(key, "Method") == 0) {
921                 const char *method;
922
923                 if (type != DBUS_TYPE_STRING)
924                         return -EINVAL;
925
926                 dbus_message_iter_get_basic(value, &method);
927
928                 ipconfig->method = __connman_ipconfig_string2method(method);
929         } else
930                 return -EINVAL;
931
932         return 0;
933 }
934
935 int __connman_ipconfig_load(struct connman_ipconfig *ipconfig,
936                 GKeyFile *keyfile, const char *identifier, const char *prefix)
937 {
938         DBG("ipconfig %p identifier %s", ipconfig, identifier);
939
940         return 0;
941 }
942
943 int __connman_ipconfig_save(struct connman_ipconfig *ipconfig,
944                 GKeyFile *keyfile, const char *identifier, const char *prefix)
945 {
946         DBG("ipconfig %p identifier %s", ipconfig, identifier);
947
948         return 0;
949 }
950
951 int __connman_ipconfig_init(void)
952 {
953         DBG("");
954
955         ipdevice_hash = g_hash_table_new_full(g_direct_hash, g_direct_equal,
956                                                         NULL, free_ipdevice);
957
958         return 0;
959 }
960
961 void __connman_ipconfig_cleanup(void)
962 {
963         DBG("");
964
965         g_hash_table_destroy(ipdevice_hash);
966         ipdevice_hash = NULL;
967 }