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