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