Add support for decoding Ethernet addresses coming from 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 #include <netinet/ether.h>
31 #include <net/if.h>
32 #include <net/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_ether(struct rtattr *attr, const char *name)
453 {
454         int len = (int) RTA_PAYLOAD(attr);
455
456         if (len == ETH_ALEN) {
457                 struct ether_addr eth;
458                 memcpy(&eth, RTA_DATA(attr), ETH_ALEN);
459                 print("  attr %s (len %d) %s\n", name, len, ether_ntoa(&eth));
460         } else
461                 print("  attr %s (len %d)\n", name, len);
462 }
463
464 static inline void print_inet(struct rtattr *attr, const char *name,
465                                                         unsigned char family)
466 {
467         int len = (int) RTA_PAYLOAD(attr);
468
469         if (family == AF_INET && len == sizeof(struct in_addr)) {
470                 struct in_addr addr;
471                 addr = *((struct in_addr *) RTA_DATA(attr));
472                 print("  attr %s (len %d) %s\n", name, len, inet_ntoa(addr));
473         } else
474                 print("  attr %s (len %d)\n", name, len);
475 }
476
477 static inline void print_string(struct rtattr *attr, const char *name)
478 {
479         print("  attr %s (len %d) %s\n", name, (int) RTA_PAYLOAD(attr),
480                                                 (char *) RTA_DATA(attr));
481 }
482
483 static inline void print_byte(struct rtattr *attr, const char *name)
484 {
485         print("  attr %s (len %d) 0x%02x\n", name, (int) RTA_PAYLOAD(attr),
486                                         *((unsigned char *) RTA_DATA(attr)));
487 }
488
489 static inline void print_integer(struct rtattr *attr, const char *name)
490 {
491         print("  attr %s (len %d) %d\n", name, (int) RTA_PAYLOAD(attr),
492                                                 *((int *) RTA_DATA(attr)));
493 }
494
495 static inline void print_attr(struct rtattr *attr, const char *name)
496 {
497         int len = (int) RTA_PAYLOAD(attr);
498
499         if (name && len > 0)
500                 print("  attr %s (len %d)\n", name, len);
501         else
502                 print("  attr %d (len %d)\n", attr->rta_type, len);
503 }
504
505 static void rtnl_link(struct nlmsghdr *hdr)
506 {
507         struct ifinfomsg *msg;
508         struct rtattr *attr;
509         int bytes;
510
511         msg = (struct ifinfomsg *) NLMSG_DATA(hdr);
512         bytes = IFLA_PAYLOAD(hdr);
513
514         print("ifi_index %d ifi_flags 0x%04x", msg->ifi_index, msg->ifi_flags);
515
516         for (attr = IFLA_RTA(msg); RTA_OK(attr, bytes);
517                                         attr = RTA_NEXT(attr, bytes)) {
518                 switch (attr->rta_type) {
519                 case IFLA_ADDRESS:
520                         print_ether(attr, "address");
521                         break;
522                 case IFLA_BROADCAST:
523                         print_ether(attr, "broadcast");
524                         break;
525                 case IFLA_IFNAME:
526                         print_string(attr, "ifname");
527                         break;
528                 case IFLA_MTU:
529                         print_integer(attr, "mtu");
530                         break;
531                 case IFLA_LINK:
532                         print_attr(attr, "link");
533                         break;
534                 case IFLA_QDISC:
535                         print_attr(attr, "qdisc");
536                         break;
537                 case IFLA_STATS:
538                         print_attr(attr, "stats");
539                         break;
540                 case IFLA_COST:
541                         print_attr(attr, "cost");
542                         break;
543                 case IFLA_PRIORITY:
544                         print_attr(attr, "priority");
545                         break;
546                 case IFLA_MASTER:
547                         print_attr(attr, "master");
548                         break;
549                 case IFLA_WIRELESS:
550                         print_attr(attr, "wireless");
551                         break;
552                 case IFLA_PROTINFO:
553                         print_attr(attr, "protinfo");
554                         break;
555                 case IFLA_TXQLEN:
556                         print_integer(attr, "txqlen");
557                         break;
558                 case IFLA_MAP:
559                         print_attr(attr, "map");
560                         break;
561                 case IFLA_WEIGHT:
562                         print_attr(attr, "weight");
563                         break;
564                 case IFLA_OPERSTATE:
565                         print_byte(attr, "operstate");
566                         break;
567                 case IFLA_LINKMODE:
568                         print_byte(attr, "linkmode");
569                         break;
570                 default:
571                         print_attr(attr, NULL);
572                         break;
573                 }
574         }
575 }
576
577 static void rtnl_newlink(struct nlmsghdr *hdr)
578 {
579         struct ifinfomsg *msg = (struct ifinfomsg *) NLMSG_DATA(hdr);
580
581         rtnl_link(hdr);
582
583         process_newlink(msg->ifi_type, msg->ifi_index,
584                                         msg->ifi_flags, msg->ifi_change);
585 }
586
587 static void rtnl_dellink(struct nlmsghdr *hdr)
588 {
589         struct ifinfomsg *msg = (struct ifinfomsg *) NLMSG_DATA(hdr);
590
591         rtnl_link(hdr);
592
593         process_dellink(msg->ifi_type, msg->ifi_index,
594                                         msg->ifi_flags, msg->ifi_change);
595 }
596
597 static void rtnl_addr(struct nlmsghdr *hdr)
598 {
599         struct ifaddrmsg *msg;
600         struct rtattr *attr;
601         int bytes;
602
603         msg = (struct ifaddrmsg *) NLMSG_DATA(hdr);
604         bytes = IFA_PAYLOAD(hdr);
605
606         print("ifa_family %d ifa_index %d", msg->ifa_family, msg->ifa_index);
607
608         for (attr = IFA_RTA(msg); RTA_OK(attr, bytes);
609                                         attr = RTA_NEXT(attr, bytes)) {
610                 switch (attr->rta_type) {
611                 case IFA_ADDRESS:
612                         print_inet(attr, "address", msg->ifa_family);
613                         break;
614                 case IFA_LOCAL:
615                         print_inet(attr, "local", msg->ifa_family);
616                         break;
617                 case IFA_LABEL:
618                         print_string(attr, "label");
619                         break;
620                 case IFA_BROADCAST:
621                         print_inet(attr, "broadcast", msg->ifa_family);
622                         break;
623                 case IFA_ANYCAST:
624                         print_attr(attr, "anycast");
625                         break;
626                 case IFA_CACHEINFO:
627                         print_attr(attr, "cacheinfo");
628                         break;
629                 case IFA_MULTICAST:
630                         print_attr(attr, "multicast");
631                         break;
632                 default:
633                         print_attr(attr, NULL);
634                         break;
635                 }
636         }
637 }
638
639 static void rtnl_newaddr(struct nlmsghdr *hdr)
640 {
641         struct ifaddrmsg *msg = (struct ifaddrmsg *) NLMSG_DATA(hdr);
642
643         rtnl_addr(hdr);
644
645         process_newaddr(msg->ifa_family, msg->ifa_prefixlen, msg->ifa_index,
646                                                 msg, IFA_PAYLOAD(hdr));
647 }
648
649 static void rtnl_deladdr(struct nlmsghdr *hdr)
650 {
651         struct ifaddrmsg *msg = (struct ifaddrmsg *) NLMSG_DATA(hdr);
652
653         rtnl_addr(hdr);
654
655         process_deladdr(msg->ifa_family, msg->ifa_prefixlen, msg->ifa_index,
656                                                 msg, IFA_PAYLOAD(hdr));
657 }
658
659 static void rtnl_route(struct nlmsghdr *hdr)
660 {
661         struct rtmsg *msg;
662         struct rtattr *attr;
663         int bytes;
664
665         msg = (struct rtmsg *) NLMSG_DATA(hdr);
666         bytes = RTM_PAYLOAD(hdr);
667
668         print("rtm_family %d rtm_table %d rtm_protocol %d",
669                         msg->rtm_family, msg->rtm_table, msg->rtm_protocol);
670         print("rtm_scope %d rtm_type %d rtm_flags 0x%04x",
671                                 msg->rtm_scope, msg->rtm_type, msg->rtm_flags);
672
673         for (attr = RTM_RTA(msg); RTA_OK(attr, bytes);
674                                         attr = RTA_NEXT(attr, bytes)) {
675                 switch (attr->rta_type) {
676                 case RTA_DST:
677                         print_inet(attr, "dst", msg->rtm_family);
678                         break;
679                 case RTA_SRC:
680                         print_inet(attr, "src", msg->rtm_family);
681                         break;
682                 case RTA_IIF:
683                         print_string(attr, "iif");
684                         break;
685                 case RTA_OIF:
686                         print_integer(attr, "oif");
687                         break;
688                 case RTA_GATEWAY:
689                         print_inet(attr, "gateway", msg->rtm_family);
690                         break;
691                 case RTA_PRIORITY:
692                         print_attr(attr, "priority");
693                         break;
694                 case RTA_PREFSRC:
695                         print_inet(attr, "prefsrc", msg->rtm_family);
696                         break;
697                 case RTA_METRICS:
698                         print_attr(attr, "metrics");
699                         break;
700                 case RTA_TABLE:
701                         print_integer(attr, "table");
702                         break;
703                 default:
704                         print_attr(attr, NULL);
705                         break;
706                 }
707         }
708 }
709
710 static void rtnl_newroute(struct nlmsghdr *hdr)
711 {
712         struct rtmsg *msg = (struct rtmsg *) NLMSG_DATA(hdr);
713
714         rtnl_route(hdr);
715
716         if (msg->rtm_table == RT_TABLE_MAIN &&
717                                 msg->rtm_protocol == RTPROT_BOOT &&
718                                                 msg->rtm_type == RTN_UNICAST)
719                 process_newroute(msg->rtm_family, msg->rtm_scope,
720                                                 msg, RTM_PAYLOAD(hdr));
721 }
722
723 static void rtnl_delroute(struct nlmsghdr *hdr)
724 {
725         struct rtmsg *msg = (struct rtmsg *) NLMSG_DATA(hdr);
726
727         rtnl_route(hdr);
728
729         if (msg->rtm_table == RT_TABLE_MAIN &&
730                                 msg->rtm_protocol == RTPROT_BOOT &&
731                                                 msg->rtm_type == RTN_UNICAST)
732                 process_delroute(msg->rtm_family, msg->rtm_scope,
733                                                 msg, RTM_PAYLOAD(hdr));
734 }
735
736 static const char *type2string(uint16_t type)
737 {
738         switch (type) {
739         case NLMSG_NOOP:
740                 return "NOOP";
741         case NLMSG_ERROR:
742                 return "ERROR";
743         case NLMSG_DONE:
744                 return "DONE";
745         case NLMSG_OVERRUN:
746                 return "OVERRUN";
747         case RTM_GETLINK:
748                 return "GETLINK";
749         case RTM_NEWLINK:
750                 return "NEWLINK";
751         case RTM_DELLINK:
752                 return "DELLINK";
753         case RTM_NEWADDR:
754                 return "NEWADDR";
755         case RTM_DELADDR:
756                 return "DELADDR";
757         case RTM_GETROUTE:
758                 return "GETROUTE";
759         case RTM_NEWROUTE:
760                 return "NEWROUTE";
761         case RTM_DELROUTE:
762                 return "DELROUTE";
763         default:
764                 return "UNKNOWN";
765         }
766 }
767
768 static GIOChannel *channel = NULL;
769
770 struct rtnl_request {
771         struct nlmsghdr hdr;
772         struct rtgenmsg msg;
773 };
774 #define RTNL_REQUEST_SIZE  (sizeof(struct nlmsghdr) + sizeof(struct rtgenmsg))
775
776 static GSList *request_list = NULL;
777 static guint32 request_seq = 0;
778
779 static struct rtnl_request *find_request(guint32 seq)
780 {
781         GSList *list;
782
783         for (list = request_list; list; list = list->next) {
784                 struct rtnl_request *req = list->data;
785
786                 if (req->hdr.nlmsg_seq == seq)
787                         return req;
788         }
789
790         return NULL;
791 }
792
793 static int send_request(struct rtnl_request *req)
794 {
795         struct sockaddr_nl addr;
796         int sk;
797
798         DBG("%s len %d type %d flags 0x%04x seq %d",
799                                 type2string(req->hdr.nlmsg_type),
800                                 req->hdr.nlmsg_len, req->hdr.nlmsg_type,
801                                 req->hdr.nlmsg_flags, req->hdr.nlmsg_seq);
802
803         sk = g_io_channel_unix_get_fd(channel);
804
805         memset(&addr, 0, sizeof(addr));
806         addr.nl_family = AF_NETLINK;
807
808         return sendto(sk, req, req->hdr.nlmsg_len, 0,
809                                 (struct sockaddr *) &addr, sizeof(addr));
810 }
811
812 static int queue_request(struct rtnl_request *req)
813 {
814         request_list = g_slist_append(request_list, req);
815
816         if (g_slist_length(request_list) > 1)
817                 return 0;
818
819         return send_request(req);
820 }
821
822 static int process_response(guint32 seq)
823 {
824         struct rtnl_request *req;
825
826         DBG("seq %d", seq);
827
828         req = find_request(seq);
829         if (req != NULL) {
830                 request_list = g_slist_remove(request_list, req);
831                 g_free(req);
832         }
833
834         req = g_slist_nth_data(request_list, 0);
835         if (req == NULL)
836                 return 0;
837
838         return send_request(req);
839 }
840
841 static void rtnl_message(void *buf, size_t len)
842 {
843         DBG("buf %p len %zd", buf, len);
844
845         while (len > 0) {
846                 struct nlmsghdr *hdr = buf;
847                 struct nlmsgerr *err;
848
849                 if (!NLMSG_OK(hdr, len))
850                         break;
851
852                 DBG("%s len %d type %d flags 0x%04x seq %d",
853                                         type2string(hdr->nlmsg_type),
854                                         hdr->nlmsg_len, hdr->nlmsg_type,
855                                         hdr->nlmsg_flags, hdr->nlmsg_seq);
856
857                 switch (hdr->nlmsg_type) {
858                 case NLMSG_NOOP:
859                 case NLMSG_OVERRUN:
860                         return;
861                 case NLMSG_DONE:
862                         process_response(hdr->nlmsg_seq);
863                         return;
864                 case NLMSG_ERROR:
865                         err = NLMSG_DATA(hdr);
866                         DBG("error %d (%s)", -err->error,
867                                                 strerror(-err->error));
868                         return;
869                 case RTM_NEWLINK:
870                         rtnl_newlink(hdr);
871                         break;
872                 case RTM_DELLINK:
873                         rtnl_dellink(hdr);
874                         break;
875                 case RTM_NEWADDR:
876                         rtnl_newaddr(hdr);
877                         break;
878                 case RTM_DELADDR:
879                         rtnl_deladdr(hdr);
880                         break;
881                 case RTM_NEWROUTE:
882                         rtnl_newroute(hdr);
883                         break;
884                 case RTM_DELROUTE:
885                         rtnl_delroute(hdr);
886                         break;
887                 }
888
889                 len -= hdr->nlmsg_len;
890                 buf += hdr->nlmsg_len;
891         }
892 }
893
894 static gboolean netlink_event(GIOChannel *chan,
895                                 GIOCondition cond, gpointer data)
896 {
897         unsigned char buf[4096];
898         gsize len;
899         GIOError err;
900
901         if (cond & (G_IO_NVAL | G_IO_HUP | G_IO_ERR))
902                 return FALSE;
903
904         memset(buf, 0, sizeof(buf));
905
906         err = g_io_channel_read(chan, (gchar *) buf, sizeof(buf), &len);
907         if (err) {
908                 if (err == G_IO_ERROR_AGAIN)
909                         return TRUE;
910                 return FALSE;
911         }
912
913         rtnl_message(buf, len);
914
915         return TRUE;
916 }
917
918 static int send_getlink(void)
919 {
920         struct rtnl_request *req;
921
922         DBG("");
923
924         req = g_try_malloc0(RTNL_REQUEST_SIZE);
925         if (req == NULL)
926                 return -ENOMEM;
927
928         req->hdr.nlmsg_len = RTNL_REQUEST_SIZE;
929         req->hdr.nlmsg_type = RTM_GETLINK;
930         req->hdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP;
931         req->hdr.nlmsg_pid = 0;
932         req->hdr.nlmsg_seq = request_seq++;
933         req->msg.rtgen_family = AF_INET;
934
935         return queue_request(req);
936 }
937
938 static int send_getaddr(void)
939 {
940         struct rtnl_request *req;
941
942         DBG("");
943
944         req = g_try_malloc0(RTNL_REQUEST_SIZE);
945         if (req == NULL)
946                 return -ENOMEM;
947
948         req->hdr.nlmsg_len = RTNL_REQUEST_SIZE;
949         req->hdr.nlmsg_type = RTM_GETADDR;
950         req->hdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP;
951         req->hdr.nlmsg_pid = 0;
952         req->hdr.nlmsg_seq = request_seq++;
953         req->msg.rtgen_family = AF_INET;
954
955         return queue_request(req);
956 }
957
958 static int send_getroute(void)
959 {
960         struct rtnl_request *req;
961
962         DBG("");
963
964         req = g_try_malloc0(RTNL_REQUEST_SIZE);
965         if (req == NULL)
966                 return -ENOMEM;
967
968         req->hdr.nlmsg_len = RTNL_REQUEST_SIZE;
969         req->hdr.nlmsg_type = RTM_GETROUTE;
970         req->hdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP;
971         req->hdr.nlmsg_pid = 0;
972         req->hdr.nlmsg_seq = request_seq++;
973         req->msg.rtgen_family = AF_INET;
974
975         return queue_request(req);
976 }
977
978 int __connman_rtnl_init(void)
979 {
980         struct sockaddr_nl addr;
981         int sk;
982
983         DBG("");
984
985         ipconfig_hash = g_hash_table_new_full(g_direct_hash, g_direct_equal,
986                                                         NULL, free_ipconfig);
987
988         sk = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE);
989         if (sk < 0)
990                 return -1;
991
992         memset(&addr, 0, sizeof(addr));
993         addr.nl_family = AF_NETLINK;
994         addr.nl_groups = RTMGRP_LINK | RTMGRP_IPV4_IFADDR | RTMGRP_IPV4_ROUTE;
995
996         if (bind(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
997                 close(sk);
998                 return -1;
999         }
1000
1001         channel = g_io_channel_unix_new(sk);
1002         g_io_channel_set_close_on_unref(channel, TRUE);
1003
1004         g_io_add_watch(channel, G_IO_IN | G_IO_NVAL | G_IO_HUP | G_IO_ERR,
1005                                                         netlink_event, NULL);
1006
1007         return 0;
1008 }
1009
1010 void __connman_rtnl_start(void)
1011 {
1012         DBG("");
1013
1014         send_getlink();
1015         send_getaddr();
1016         send_getroute();
1017 }
1018
1019 void __connman_rtnl_cleanup(void)
1020 {
1021         GSList *list;
1022
1023         DBG("");
1024
1025         g_slist_free(ipconfig_list);
1026         ipconfig_list = NULL;
1027
1028         g_hash_table_destroy(ipconfig_hash);
1029         ipconfig_hash = NULL;
1030
1031         for (list = watch_list; list; list = list->next) {
1032                 struct watch_data *watch = list->data;
1033
1034                 DBG("removing watch %d", watch->id);
1035
1036                 g_free(watch);
1037                 list->data = NULL;
1038         }
1039
1040         g_slist_free(watch_list);
1041         watch_list = NULL;
1042
1043         for (list = request_list; list; list = list->next) {
1044                 struct rtnl_request *req = list->data;
1045
1046                 DBG("%s len %d type %d flags 0x%04x seq %d",
1047                                 type2string(req->hdr.nlmsg_type),
1048                                 req->hdr.nlmsg_len, req->hdr.nlmsg_type,
1049                                 req->hdr.nlmsg_flags, req->hdr.nlmsg_seq);
1050
1051                 g_free(req);
1052                 list->data = NULL;
1053         }
1054
1055         g_slist_free(request_list);
1056         request_list = NULL;
1057
1058         g_io_channel_shutdown(channel, TRUE, NULL);
1059         g_io_channel_unref(channel);
1060
1061         channel = NULL;
1062 }