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