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