Add support for storing default gateway information
[framework/connectivity/connman.git] / src / rtnl.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 <unistd.h>
27 #include <string.h>
28 #include <sys/socket.h>
29 #include <arpa/inet.h>
30
31 #include <linux/if.h>
32 #include <linux/if_arp.h>
33 #include <linux/netlink.h>
34 #include <linux/rtnetlink.h>
35
36 #include <glib.h>
37
38 #include "connman.h"
39
40 #define print(arg...) do { } while (0)
41 //#define print(arg...) connman_info(arg)
42
43 struct watch_data {
44         unsigned int id;
45         int index;
46         connman_rtnl_link_cb_t newlink;
47         void *user_data;
48 };
49
50 static GSList *watch_list = NULL;
51 static unsigned int watch_id = 0;
52
53 static GHashTable *ipconfig_hash = NULL;
54 static GSList *ipconfig_list = NULL;
55
56 static void register_ipconfig(struct connman_ipconfig *ipconfig)
57 {
58         ipconfig_list = g_slist_append(ipconfig_list, ipconfig);
59 }
60
61 static void unregister_ipconfig(struct connman_ipconfig *ipconfig)
62 {
63         ipconfig_list = g_slist_remove(ipconfig_list, ipconfig);
64 }
65
66 static void free_ipconfig(gpointer data)
67 {
68         struct connman_ipconfig *ipconfig = data;
69
70         unregister_ipconfig(ipconfig);
71
72         connman_ipconfig_unref(ipconfig);
73 }
74
75 /**
76  * connman_rtnl_add_newlink_watch:
77  * @index: network device index
78  * @callback: callback function
79  * @user_data: callback data;
80  *
81  * Add a new RTNL watch for newlink events
82  *
83  * Returns: %0 on failure and a unique id on success
84  */
85 unsigned int connman_rtnl_add_newlink_watch(int index,
86                         connman_rtnl_link_cb_t callback, void *user_data)
87 {
88         struct connman_ipconfig *ipconfig;
89         struct watch_data *watch;
90
91         watch = g_try_new0(struct watch_data, 1);
92         if (watch == NULL)
93                 return 0;
94
95         watch->id = ++watch_id;
96         watch->index = index;
97
98         watch->newlink = callback;
99         watch->user_data = user_data;
100
101         watch_list = g_slist_prepend(watch_list, watch);
102
103         DBG("id %d", watch->id);
104
105         ipconfig = g_hash_table_lookup(ipconfig_hash, GINT_TO_POINTER(index));
106         if (ipconfig != NULL) {
107                 unsigned int flags = __connman_ipconfig_get_flags(ipconfig);
108
109                 if (callback)
110                         callback(flags, 0, user_data);
111         }
112
113         return watch->id;
114 }
115
116 /**
117  * connman_rtnl_remove_watch:
118  * @id: watch identifier
119  *
120  * Remove the RTNL watch for the identifier
121  */
122 void connman_rtnl_remove_watch(unsigned int id)
123 {
124         GSList *list;
125
126         DBG("id %d", id);
127
128         if (id == 0)
129                 return;
130
131         for (list = watch_list; list; list = list->next) {
132                 struct watch_data *watch = list->data;
133
134                 if (watch->id  == id) {
135                         watch_list = g_slist_remove(watch_list, watch);
136                         g_free(watch);
137                         break;
138                 }
139         }
140 }
141
142 static void trigger_rtnl(gpointer key, gpointer value, gpointer user_data)
143 {
144         struct connman_rtnl *rtnl = user_data;
145         struct connman_ipconfig *ipconfig = value;
146         int index = GPOINTER_TO_INT(key);
147
148         if (index < 0 || ipconfig == NULL)
149                 return;
150
151         if (rtnl->newlink) {
152                 unsigned short type = __connman_ipconfig_get_type(ipconfig);
153                 unsigned int flags = __connman_ipconfig_get_flags(ipconfig);
154
155                 rtnl->newlink(type, index, flags, 0);
156         }
157
158         if (rtnl->newgateway) {
159                 const char *gateway = __connman_ipconfig_get_gateway(ipconfig);
160
161                 if (gateway != NULL)
162                         rtnl->newgateway(index, gateway);
163         }
164 }
165
166 static GSList *rtnl_list = NULL;
167
168 static gint compare_priority(gconstpointer a, gconstpointer b)
169 {
170         const struct connman_rtnl *rtnl1 = a;
171         const struct connman_rtnl *rtnl2 = b;
172
173         return rtnl2->priority - rtnl1->priority;
174 }
175
176 /**
177  * connman_rtnl_register:
178  * @rtnl: RTNL module
179  *
180  * Register a new RTNL module
181  *
182  * Returns: %0 on success
183  */
184 int connman_rtnl_register(struct connman_rtnl *rtnl)
185 {
186         DBG("rtnl %p name %s", rtnl, rtnl->name);
187
188         rtnl_list = g_slist_insert_sorted(rtnl_list, rtnl,
189                                                         compare_priority);
190
191         g_hash_table_foreach(ipconfig_hash, trigger_rtnl, rtnl);
192
193         return 0;
194 }
195
196 /**
197  * connman_rtnl_unregister:
198  * @rtnl: RTNL module
199  *
200  * Remove a previously registered RTNL module
201  */
202 void connman_rtnl_unregister(struct connman_rtnl *rtnl)
203 {
204         DBG("rtnl %p name %s", rtnl, rtnl->name);
205
206         rtnl_list = g_slist_remove(rtnl_list, rtnl);
207 }
208
209 static void process_newlink(unsigned short type, int index,
210                                         unsigned flags, unsigned change)
211 {
212         struct connman_ipconfig *ipconfig;
213         GSList *list;
214
215         switch (type) {
216         case ARPHRD_ETHER:
217         case ARPHRD_LOOPBACK:
218         case ARPHRD_NONE:
219                 ipconfig = g_hash_table_lookup(ipconfig_hash,
220                                                 GINT_TO_POINTER(index));
221                 if (ipconfig == NULL) {
222                         ipconfig = connman_ipconfig_create(index);
223                         if (ipconfig != NULL) {
224                                 g_hash_table_insert(ipconfig_hash,
225                                         GINT_TO_POINTER(index), ipconfig);
226
227                                 register_ipconfig(ipconfig);
228                         }
229                 }
230
231                 if (ipconfig != NULL)
232                         __connman_ipconfig_update_link(ipconfig,
233                                                         flags, change);
234                 break;
235         }
236
237         for (list = rtnl_list; list; list = list->next) {
238                 struct connman_rtnl *rtnl = list->data;
239
240                 if (rtnl->newlink)
241                         rtnl->newlink(type, index, flags, change);
242         }
243
244         for (list = watch_list; list; list = list->next) {
245                 struct watch_data *watch = list->data;
246
247                 if (watch->index != index)
248                         continue;
249
250                 if (watch->newlink)
251                         watch->newlink(flags, change, watch->user_data);
252         }
253 }
254
255 static void process_dellink(unsigned short type, int index,
256                                         unsigned flags, unsigned change)
257 {
258         GSList *list;
259
260         for (list = rtnl_list; list; list = list->next) {
261                 struct connman_rtnl *rtnl = list->data;
262
263                 if (rtnl->dellink)
264                         rtnl->dellink(type, index, flags, change);
265         }
266
267         switch (type) {
268         case ARPHRD_ETHER:
269         case ARPHRD_LOOPBACK:
270         case ARPHRD_NONE:
271                 g_hash_table_remove(ipconfig_hash, GINT_TO_POINTER(index));
272                 break;
273         }
274 }
275
276 static void extract_addr(struct ifaddrmsg *msg, int bytes,
277                                                 const char **label,
278                                                 struct in_addr *local,
279                                                 struct in_addr *address,
280                                                 struct in_addr *broadcast)
281 {
282         struct rtattr *attr;
283
284         for (attr = IFA_RTA(msg); RTA_OK(attr, bytes);
285                                         attr = RTA_NEXT(attr, bytes)) {
286                 switch (attr->rta_type) {
287                 case IFA_ADDRESS:
288                         if (address != NULL)
289                                 *address = *((struct in_addr *) RTA_DATA(attr));
290                         break;
291                 case IFA_LOCAL:
292                         if (local != NULL)
293                                 *local = *((struct in_addr *) RTA_DATA(attr));
294                         break;
295                 case IFA_BROADCAST:
296                         if (broadcast != NULL)
297                                 *broadcast = *((struct in_addr *) RTA_DATA(attr));
298                         break;
299                 case IFA_LABEL:
300                         if (label != NULL)
301                                 *label = RTA_DATA(attr);
302                         break;
303                 }
304         }
305 }
306
307 static void process_newaddr(unsigned char family, unsigned char prefixlen,
308                                 int index, struct ifaddrmsg *msg, int bytes)
309 {
310         GSList *list;
311         const char *label;
312         struct in_addr address = { INADDR_ANY };
313
314         if (family != AF_INET)
315                 return;
316
317         extract_addr(msg, bytes, &label, &address, NULL, NULL);
318
319         for (list = ipconfig_list; list; list = list->next) {
320                 struct connman_ipconfig *ipconfig = list->data;
321
322                 if (__connman_ipconfig_get_index(ipconfig) != index)
323                         continue;
324
325                 __connman_ipconfig_add_address(ipconfig, label, prefixlen,
326                                                 inet_ntoa(address), NULL);
327         }
328 }
329
330 static void process_deladdr(unsigned char family, unsigned char prefixlen,
331                                 int index, struct ifaddrmsg *msg, int bytes)
332 {
333         GSList *list;
334         const char *label;
335         struct in_addr address = { INADDR_ANY };
336
337         if (family != AF_INET)
338                 return;
339
340         extract_addr(msg, bytes, &label, &address, NULL, NULL);
341
342         for (list = ipconfig_list; list; list = list->next) {
343                 struct connman_ipconfig *ipconfig = list->data;
344
345                 if (__connman_ipconfig_get_index(ipconfig) != index)
346                         continue;
347
348                 __connman_ipconfig_del_address(ipconfig, label, prefixlen,
349                                                 inet_ntoa(address), NULL);
350         }
351 }
352
353 static void extract_route(struct rtmsg *msg, int bytes, int *index,
354                                                 struct in_addr *dst,
355                                                 struct in_addr *gateway)
356 {
357         struct rtattr *attr;
358
359         for (attr = RTM_RTA(msg); RTA_OK(attr, bytes);
360                                         attr = RTA_NEXT(attr, bytes)) {
361                 switch (attr->rta_type) {
362                 case RTA_DST:
363                         if (dst != NULL)
364                                 *dst = *((struct in_addr *) RTA_DATA(attr));
365                         break;
366                 case RTA_GATEWAY:
367                         if (gateway != NULL)
368                                 *gateway = *((struct in_addr *) RTA_DATA(attr));
369                         break;
370                 case RTA_OIF:
371                         if (index != NULL)
372                                 *index = *((int *) RTA_DATA(attr));
373                         break;
374                 }
375         }
376 }
377
378 static void process_newroute(unsigned char family, unsigned char scope,
379                                                 struct rtmsg *msg, int bytes)
380 {
381         GSList *list;
382         struct in_addr dst = { INADDR_ANY }, gateway = { INADDR_ANY };
383         char dststr[16], gatewaystr[16];
384         int index = -1;
385
386         if (family != AF_INET)
387                 return;
388
389         extract_route(msg, bytes, &index, &dst, &gateway);
390
391         inet_ntop(family, &dst, dststr, sizeof(dststr));
392         inet_ntop(family, &gateway, gatewaystr, sizeof(gatewaystr));
393
394         for (list = ipconfig_list; list; list = list->next) {
395                 struct connman_ipconfig *ipconfig = list->data;
396
397                 if (__connman_ipconfig_get_index(ipconfig) != index)
398                         continue;
399
400                 __connman_ipconfig_add_route(ipconfig, scope,
401                                                         dststr, gatewaystr);
402         }
403
404         if (scope != RT_SCOPE_UNIVERSE || dst.s_addr != INADDR_ANY)
405                 return;
406
407         for (list = rtnl_list; list; list = list->next) {
408                 struct connman_rtnl *rtnl = list->data;
409
410                 if (rtnl->newgateway)
411                         rtnl->newgateway(index, gatewaystr);
412         }
413 }
414
415 static void process_delroute(unsigned char family, unsigned char scope,
416                                                 struct rtmsg *msg, int bytes)
417 {
418         GSList *list;
419         struct in_addr dst = { INADDR_ANY }, gateway = { INADDR_ANY };
420         char dststr[16], gatewaystr[16];
421         int index = -1;
422
423         if (family != AF_INET)
424                 return;
425
426         extract_route(msg, bytes, &index, &dst, &gateway);
427
428         inet_ntop(family, &dst, dststr, sizeof(dststr));
429         inet_ntop(family, &gateway, gatewaystr, sizeof(gatewaystr));
430
431         for (list = ipconfig_list; list; list = list->next) {
432                 struct connman_ipconfig *ipconfig = list->data;
433
434                 if (__connman_ipconfig_get_index(ipconfig) != index)
435                         continue;
436
437                 __connman_ipconfig_del_route(ipconfig, scope,
438                                                         dststr, gatewaystr);
439         }
440
441         if (scope != RT_SCOPE_UNIVERSE || dst.s_addr != INADDR_ANY)
442                 return;
443
444         for (list = rtnl_list; list; list = list->next) {
445                 struct connman_rtnl *rtnl = list->data;
446
447                 if (rtnl->delgateway)
448                         rtnl->delgateway(index, gatewaystr);
449         }
450 }
451
452 static inline void print_inet(struct rtattr *attr, const char *name,
453                                                         unsigned char family)
454 {
455         if (family == AF_INET) {
456                 struct in_addr addr;
457                 addr = *((struct in_addr *) RTA_DATA(attr));
458                 print("  attr %s (len %d) %s\n", name,
459                                 (int) RTA_PAYLOAD(attr), inet_ntoa(addr));
460         } else
461                 print("  attr %s (len %d)\n", name, (int) RTA_PAYLOAD(attr));
462 }
463
464 static inline void print_string(struct rtattr *attr, const char *name)
465 {
466         print("  attr %s (len %d) %s\n", name, (int) RTA_PAYLOAD(attr),
467                                                 (char *) RTA_DATA(attr));
468 }
469
470 static inline void print_byte(struct rtattr *attr, const char *name)
471 {
472         print("  attr %s (len %d) 0x%02x\n", name, (int) RTA_PAYLOAD(attr),
473                                         *((unsigned char *) RTA_DATA(attr)));
474 }
475
476 static inline void print_integer(struct rtattr *attr, const char *name)
477 {
478         print("  attr %s (len %d) %d\n", name, (int) RTA_PAYLOAD(attr),
479                                                 *((int *) RTA_DATA(attr)));
480 }
481
482 static inline void print_attr(struct rtattr *attr, const char *name)
483 {
484         if (name)
485                 print("  attr %s (len %d)\n", name, (int) RTA_PAYLOAD(attr));
486         else
487                 print("  attr %d (len %d)\n",
488                                 attr->rta_type, (int) RTA_PAYLOAD(attr));
489 }
490
491 static void rtnl_link(struct nlmsghdr *hdr)
492 {
493         struct ifinfomsg *msg;
494         struct rtattr *attr;
495         int bytes;
496
497         msg = (struct ifinfomsg *) NLMSG_DATA(hdr);
498         bytes = IFLA_PAYLOAD(hdr);
499
500         print("ifi_index %d ifi_flags 0x%04x", msg->ifi_index, msg->ifi_flags);
501
502         for (attr = IFLA_RTA(msg); RTA_OK(attr, bytes);
503                                         attr = RTA_NEXT(attr, bytes)) {
504                 switch (attr->rta_type) {
505                 case IFLA_ADDRESS:
506                         print_attr(attr, "address");
507                         break;
508                 case IFLA_BROADCAST:
509                         print_attr(attr, "broadcast");
510                         break;
511                 case IFLA_IFNAME:
512                         print_string(attr, "ifname");
513                         break;
514                 case IFLA_MTU:
515                         print_integer(attr, "mtu");
516                         break;
517                 case IFLA_LINK:
518                         print_attr(attr, "link");
519                         break;
520                 case IFLA_QDISC:
521                         print_attr(attr, "qdisc");
522                         break;
523                 case IFLA_STATS:
524                         print_attr(attr, "stats");
525                         break;
526                 case IFLA_COST:
527                         print_attr(attr, "cost");
528                         break;
529                 case IFLA_PRIORITY:
530                         print_attr(attr, "priority");
531                         break;
532                 case IFLA_MASTER:
533                         print_attr(attr, "master");
534                         break;
535                 case IFLA_WIRELESS:
536                         print_attr(attr, "wireless");
537                         break;
538                 case IFLA_PROTINFO:
539                         print_attr(attr, "protinfo");
540                         break;
541                 case IFLA_TXQLEN:
542                         print_attr(attr, "txqlen");
543                         break;
544                 case IFLA_MAP:
545                         print_attr(attr, "map");
546                         break;
547                 case IFLA_WEIGHT:
548                         print_attr(attr, "weight");
549                         break;
550                 case IFLA_OPERSTATE:
551                         print_byte(attr, "operstate");
552                         break;
553                 case IFLA_LINKMODE:
554                         print_byte(attr, "linkmode");
555                         break;
556                 default:
557                         print_attr(attr, NULL);
558                         break;
559                 }
560         }
561 }
562
563 static void rtnl_newlink(struct nlmsghdr *hdr)
564 {
565         struct ifinfomsg *msg = (struct ifinfomsg *) NLMSG_DATA(hdr);
566
567         rtnl_link(hdr);
568
569         process_newlink(msg->ifi_type, msg->ifi_index,
570                                         msg->ifi_flags, msg->ifi_change);
571 }
572
573 static void rtnl_dellink(struct nlmsghdr *hdr)
574 {
575         struct ifinfomsg *msg = (struct ifinfomsg *) NLMSG_DATA(hdr);
576
577         rtnl_link(hdr);
578
579         process_dellink(msg->ifi_type, msg->ifi_index,
580                                         msg->ifi_flags, msg->ifi_change);
581 }
582
583 static void rtnl_addr(struct nlmsghdr *hdr)
584 {
585         struct ifaddrmsg *msg;
586         struct rtattr *attr;
587         int bytes;
588
589         msg = (struct ifaddrmsg *) NLMSG_DATA(hdr);
590         bytes = IFA_PAYLOAD(hdr);
591
592         print("ifa_family %d ifa_index %d", msg->ifa_family, msg->ifa_index);
593
594         for (attr = IFA_RTA(msg); RTA_OK(attr, bytes);
595                                         attr = RTA_NEXT(attr, bytes)) {
596                 switch (attr->rta_type) {
597                 case IFA_ADDRESS:
598                         print_inet(attr, "address", msg->ifa_family);
599                         break;
600                 case IFA_LOCAL:
601                         print_inet(attr, "local", msg->ifa_family);
602                         break;
603                 case IFA_LABEL:
604                         print_string(attr, "label");
605                         break;
606                 case IFA_BROADCAST:
607                         print_inet(attr, "broadcast", msg->ifa_family);
608                         break;
609                 case IFA_ANYCAST:
610                         print_attr(attr, "anycast");
611                         break;
612                 case IFA_CACHEINFO:
613                         print_attr(attr, "cacheinfo");
614                         break;
615                 case IFA_MULTICAST:
616                         print_attr(attr, "multicast");
617                         break;
618                 default:
619                         print_attr(attr, NULL);
620                         break;
621                 }
622         }
623 }
624
625 static void rtnl_newaddr(struct nlmsghdr *hdr)
626 {
627         struct ifaddrmsg *msg = (struct ifaddrmsg *) NLMSG_DATA(hdr);
628
629         rtnl_addr(hdr);
630
631         process_newaddr(msg->ifa_family, msg->ifa_prefixlen, msg->ifa_index,
632                                                 msg, IFA_PAYLOAD(hdr));
633 }
634
635 static void rtnl_deladdr(struct nlmsghdr *hdr)
636 {
637         struct ifaddrmsg *msg = (struct ifaddrmsg *) NLMSG_DATA(hdr);
638
639         rtnl_addr(hdr);
640
641         process_deladdr(msg->ifa_family, msg->ifa_prefixlen, msg->ifa_index,
642                                                 msg, IFA_PAYLOAD(hdr));
643 }
644
645 static void rtnl_route(struct nlmsghdr *hdr)
646 {
647         struct rtmsg *msg;
648         struct rtattr *attr;
649         int bytes;
650
651         msg = (struct rtmsg *) NLMSG_DATA(hdr);
652         bytes = RTM_PAYLOAD(hdr);
653
654         print("rtm_family %d rtm_table %d rtm_protocol %d",
655                         msg->rtm_family, msg->rtm_table, msg->rtm_protocol);
656         print("rtm_scope %d rtm_type %d rtm_flags 0x%04x",
657                                 msg->rtm_scope, msg->rtm_type, msg->rtm_flags);
658
659         for (attr = RTM_RTA(msg); RTA_OK(attr, bytes);
660                                         attr = RTA_NEXT(attr, bytes)) {
661                 switch (attr->rta_type) {
662                 case RTA_DST:
663                         print_inet(attr, "dst", msg->rtm_family);
664                         break;
665                 case RTA_SRC:
666                         print_inet(attr, "src", msg->rtm_family);
667                         break;
668                 case RTA_IIF:
669                         print_string(attr, "iif");
670                         break;
671                 case RTA_OIF:
672                         print_integer(attr, "oif");
673                         break;
674                 case RTA_GATEWAY:
675                         print_inet(attr, "gateway", msg->rtm_family);
676                         break;
677                 case RTA_PRIORITY:
678                         print_attr(attr, "priority");
679                         break;
680                 case RTA_PREFSRC:
681                         print_inet(attr, "prefsrc", msg->rtm_family);
682                         break;
683                 case RTA_METRICS:
684                         print_attr(attr, "metrics");
685                         break;
686                 case RTA_TABLE:
687                         print_integer(attr, "table");
688                         break;
689                 default:
690                         print_attr(attr, NULL);
691                         break;
692                 }
693         }
694 }
695
696 static void rtnl_newroute(struct nlmsghdr *hdr)
697 {
698         struct rtmsg *msg = (struct rtmsg *) NLMSG_DATA(hdr);
699
700         rtnl_route(hdr);
701
702         if (msg->rtm_table == RT_TABLE_MAIN &&
703                                 msg->rtm_protocol == RTPROT_BOOT &&
704                                                 msg->rtm_type == RTN_UNICAST)
705                 process_newroute(msg->rtm_family, msg->rtm_scope,
706                                                 msg, RTM_PAYLOAD(hdr));
707 }
708
709 static void rtnl_delroute(struct nlmsghdr *hdr)
710 {
711         struct rtmsg *msg = (struct rtmsg *) NLMSG_DATA(hdr);
712
713         rtnl_route(hdr);
714
715         if (msg->rtm_table == RT_TABLE_MAIN &&
716                                 msg->rtm_protocol == RTPROT_BOOT &&
717                                                 msg->rtm_type == RTN_UNICAST)
718                 process_delroute(msg->rtm_family, msg->rtm_scope,
719                                                 msg, RTM_PAYLOAD(hdr));
720 }
721
722 static const char *type2string(uint16_t type)
723 {
724         switch (type) {
725         case NLMSG_NOOP:
726                 return "NOOP";
727         case NLMSG_ERROR:
728                 return "ERROR";
729         case NLMSG_DONE:
730                 return "DONE";
731         case NLMSG_OVERRUN:
732                 return "OVERRUN";
733         case RTM_GETLINK:
734                 return "GETLINK";
735         case RTM_NEWLINK:
736                 return "NEWLINK";
737         case RTM_DELLINK:
738                 return "DELLINK";
739         case RTM_NEWADDR:
740                 return "NEWADDR";
741         case RTM_DELADDR:
742                 return "DELADDR";
743         case RTM_GETROUTE:
744                 return "GETROUTE";
745         case RTM_NEWROUTE:
746                 return "NEWROUTE";
747         case RTM_DELROUTE:
748                 return "DELROUTE";
749         default:
750                 return "UNKNOWN";
751         }
752 }
753
754 static GIOChannel *channel = NULL;
755
756 struct rtnl_request {
757         struct nlmsghdr hdr;
758         struct rtgenmsg msg;
759 };
760 #define RTNL_REQUEST_SIZE  (sizeof(struct nlmsghdr) + sizeof(struct rtgenmsg))
761
762 static GSList *request_list = NULL;
763 static guint32 request_seq = 0;
764
765 static struct rtnl_request *find_request(guint32 seq)
766 {
767         GSList *list;
768
769         for (list = request_list; list; list = list->next) {
770                 struct rtnl_request *req = list->data;
771
772                 if (req->hdr.nlmsg_seq == seq)
773                         return req;
774         }
775
776         return NULL;
777 }
778
779 static int send_request(struct rtnl_request *req)
780 {
781         struct sockaddr_nl addr;
782         int sk;
783
784         DBG("%s len %d type %d flags 0x%04x seq %d",
785                                 type2string(req->hdr.nlmsg_type),
786                                 req->hdr.nlmsg_len, req->hdr.nlmsg_type,
787                                 req->hdr.nlmsg_flags, req->hdr.nlmsg_seq);
788
789         sk = g_io_channel_unix_get_fd(channel);
790
791         memset(&addr, 0, sizeof(addr));
792         addr.nl_family = AF_NETLINK;
793
794         return sendto(sk, req, req->hdr.nlmsg_len, 0,
795                                 (struct sockaddr *) &addr, sizeof(addr));
796 }
797
798 static int queue_request(struct rtnl_request *req)
799 {
800         request_list = g_slist_append(request_list, req);
801
802         if (g_slist_length(request_list) > 1)
803                 return 0;
804
805         return send_request(req);
806 }
807
808 static int process_response(guint32 seq)
809 {
810         struct rtnl_request *req;
811
812         DBG("seq %d", seq);
813
814         req = find_request(seq);
815         if (req != NULL) {
816                 request_list = g_slist_remove(request_list, req);
817                 g_free(req);
818         }
819
820         req = g_slist_nth_data(request_list, 0);
821         if (req == NULL)
822                 return 0;
823
824         return send_request(req);
825 }
826
827 static void rtnl_message(void *buf, size_t len)
828 {
829         DBG("buf %p len %zd", buf, len);
830
831         while (len > 0) {
832                 struct nlmsghdr *hdr = buf;
833                 struct nlmsgerr *err;
834
835                 if (!NLMSG_OK(hdr, len))
836                         break;
837
838                 DBG("%s len %d type %d flags 0x%04x seq %d",
839                                         type2string(hdr->nlmsg_type),
840                                         hdr->nlmsg_len, hdr->nlmsg_type,
841                                         hdr->nlmsg_flags, hdr->nlmsg_seq);
842
843                 switch (hdr->nlmsg_type) {
844                 case NLMSG_NOOP:
845                 case NLMSG_OVERRUN:
846                         return;
847                 case NLMSG_DONE:
848                         process_response(hdr->nlmsg_seq);
849                         return;
850                 case NLMSG_ERROR:
851                         err = NLMSG_DATA(hdr);
852                         DBG("error %d (%s)", -err->error,
853                                                 strerror(-err->error));
854                         return;
855                 case RTM_NEWLINK:
856                         rtnl_newlink(hdr);
857                         break;
858                 case RTM_DELLINK:
859                         rtnl_dellink(hdr);
860                         break;
861                 case RTM_NEWADDR:
862                         rtnl_newaddr(hdr);
863                         break;
864                 case RTM_DELADDR:
865                         rtnl_deladdr(hdr);
866                         break;
867                 case RTM_NEWROUTE:
868                         rtnl_newroute(hdr);
869                         break;
870                 case RTM_DELROUTE:
871                         rtnl_delroute(hdr);
872                         break;
873                 }
874
875                 len -= hdr->nlmsg_len;
876                 buf += hdr->nlmsg_len;
877         }
878 }
879
880 static gboolean netlink_event(GIOChannel *chan,
881                                 GIOCondition cond, gpointer data)
882 {
883         unsigned char buf[4096];
884         gsize len;
885         GIOError err;
886
887         if (cond & (G_IO_NVAL | G_IO_HUP | G_IO_ERR))
888                 return FALSE;
889
890         memset(buf, 0, sizeof(buf));
891
892         err = g_io_channel_read(chan, (gchar *) buf, sizeof(buf), &len);
893         if (err) {
894                 if (err == G_IO_ERROR_AGAIN)
895                         return TRUE;
896                 return FALSE;
897         }
898
899         rtnl_message(buf, len);
900
901         return TRUE;
902 }
903
904 static int send_getlink(void)
905 {
906         struct rtnl_request *req;
907
908         DBG("");
909
910         req = g_try_malloc0(RTNL_REQUEST_SIZE);
911         if (req == NULL)
912                 return -ENOMEM;
913
914         req->hdr.nlmsg_len = RTNL_REQUEST_SIZE;
915         req->hdr.nlmsg_type = RTM_GETLINK;
916         req->hdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP;
917         req->hdr.nlmsg_pid = 0;
918         req->hdr.nlmsg_seq = request_seq++;
919         req->msg.rtgen_family = AF_INET;
920
921         return queue_request(req);
922 }
923
924 static int send_getaddr(void)
925 {
926         struct rtnl_request *req;
927
928         DBG("");
929
930         req = g_try_malloc0(RTNL_REQUEST_SIZE);
931         if (req == NULL)
932                 return -ENOMEM;
933
934         req->hdr.nlmsg_len = RTNL_REQUEST_SIZE;
935         req->hdr.nlmsg_type = RTM_GETADDR;
936         req->hdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP;
937         req->hdr.nlmsg_pid = 0;
938         req->hdr.nlmsg_seq = request_seq++;
939         req->msg.rtgen_family = AF_INET;
940
941         return queue_request(req);
942 }
943
944 static int send_getroute(void)
945 {
946         struct rtnl_request *req;
947
948         DBG("");
949
950         req = g_try_malloc0(RTNL_REQUEST_SIZE);
951         if (req == NULL)
952                 return -ENOMEM;
953
954         req->hdr.nlmsg_len = RTNL_REQUEST_SIZE;
955         req->hdr.nlmsg_type = RTM_GETROUTE;
956         req->hdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP;
957         req->hdr.nlmsg_pid = 0;
958         req->hdr.nlmsg_seq = request_seq++;
959         req->msg.rtgen_family = AF_INET;
960
961         return queue_request(req);
962 }
963
964 int __connman_rtnl_init(void)
965 {
966         struct sockaddr_nl addr;
967         int sk;
968
969         DBG("");
970
971         ipconfig_hash = g_hash_table_new_full(g_direct_hash, g_direct_equal,
972                                                         NULL, free_ipconfig);
973
974         sk = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE);
975         if (sk < 0)
976                 return -1;
977
978         memset(&addr, 0, sizeof(addr));
979         addr.nl_family = AF_NETLINK;
980         addr.nl_groups = RTMGRP_LINK | RTMGRP_IPV4_IFADDR | RTMGRP_IPV4_ROUTE;
981
982         if (bind(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
983                 close(sk);
984                 return -1;
985         }
986
987         channel = g_io_channel_unix_new(sk);
988         g_io_channel_set_close_on_unref(channel, TRUE);
989
990         g_io_add_watch(channel, G_IO_IN | G_IO_NVAL | G_IO_HUP | G_IO_ERR,
991                                                         netlink_event, NULL);
992
993         return 0;
994 }
995
996 void __connman_rtnl_start(void)
997 {
998         DBG("");
999
1000         send_getlink();
1001         send_getaddr();
1002         send_getroute();
1003 }
1004
1005 void __connman_rtnl_cleanup(void)
1006 {
1007         GSList *list;
1008
1009         DBG("");
1010
1011         g_slist_free(ipconfig_list);
1012         ipconfig_list = NULL;
1013
1014         g_hash_table_destroy(ipconfig_hash);
1015         ipconfig_hash = NULL;
1016
1017         for (list = watch_list; list; list = list->next) {
1018                 struct watch_data *watch = list->data;
1019
1020                 DBG("removing watch %d", watch->id);
1021
1022                 g_free(watch);
1023                 list->data = NULL;
1024         }
1025
1026         g_slist_free(watch_list);
1027         watch_list = NULL;
1028
1029         for (list = request_list; list; list = list->next) {
1030                 struct rtnl_request *req = list->data;
1031
1032                 DBG("%s len %d type %d flags 0x%04x seq %d",
1033                                 type2string(req->hdr.nlmsg_type),
1034                                 req->hdr.nlmsg_len, req->hdr.nlmsg_type,
1035                                 req->hdr.nlmsg_flags, req->hdr.nlmsg_seq);
1036
1037                 g_free(req);
1038                 list->data = NULL;
1039         }
1040
1041         g_slist_free(request_list);
1042         request_list = NULL;
1043
1044         g_io_channel_shutdown(channel, TRUE, NULL);
1045         g_io_channel_unref(channel);
1046
1047         channel = NULL;
1048 }