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