Add device type for Nozomi based hardware
[connman] / 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/netlink.h>
33 #include <linux/rtnetlink.h>
34
35 #include <glib.h>
36
37 #include "connman.h"
38
39 static GSList *rtnl_list = NULL;
40
41 static gint compare_priority(gconstpointer a, gconstpointer b)
42 {
43         const struct connman_rtnl *rtnl1 = a;
44         const struct connman_rtnl *rtnl2 = b;
45
46         return rtnl2->priority - rtnl1->priority;
47 }
48
49 /**
50  * connman_rtnl_register:
51  * @rtnl: RTNL module
52  *
53  * Register a new RTNL module
54  *
55  * Returns: %0 on success
56  */
57 int connman_rtnl_register(struct connman_rtnl *rtnl)
58 {
59         DBG("rtnl %p name %s", rtnl, rtnl->name);
60
61         rtnl_list = g_slist_insert_sorted(rtnl_list, rtnl,
62                                                         compare_priority);
63
64         return 0;
65 }
66
67 /**
68  * connman_rtnl_unregister:
69  * @rtnl: RTNL module
70  *
71  * Remove a previously registered RTNL module
72  */
73 void connman_rtnl_unregister(struct connman_rtnl *rtnl)
74 {
75         DBG("rtnl %p name %s", rtnl, rtnl->name);
76
77         rtnl_list = g_slist_remove(rtnl_list, rtnl);
78 }
79
80 static void process_newlink(unsigned short type, int index,
81                                         unsigned flags, unsigned change)
82 {
83         GSList *list;
84
85         for (list = rtnl_list; list; list = list->next) {
86                 struct connman_rtnl *rtnl = list->data;
87
88                 if (rtnl->newlink)
89                         rtnl->newlink(type, index, flags, change);
90         }
91 }
92
93 static void process_dellink(unsigned short type, int index,
94                                         unsigned flags, unsigned change)
95 {
96         GSList *list;
97
98         for (list = rtnl_list; list; list = list->next) {
99                 struct connman_rtnl *rtnl = list->data;
100
101                 if (rtnl->dellink)
102                         rtnl->dellink(type, index, flags, change);
103         }
104 }
105
106 static char *extract_gateway(struct rtmsg *msg, int bytes, int *index)
107 {
108         char *gateway = NULL;
109         struct in_addr addr;
110         struct rtattr *attr;
111
112         for (attr = RTM_RTA(msg); RTA_OK(attr, bytes);
113                                         attr = RTA_NEXT(attr, bytes)) {
114                 switch (attr->rta_type) {
115                 case RTA_GATEWAY:
116                         addr = *((struct in_addr *) RTA_DATA(attr));
117                         g_free(gateway);
118                         gateway = g_strdup(inet_ntoa(addr));
119                         break;
120                 case RTA_OIF:
121                         *index = *((int *) RTA_DATA(attr));
122                         break;
123                 }
124         }
125
126         return gateway;
127 }
128
129 static void process_newgateway(struct rtmsg *msg, int bytes)
130 {
131         int index = -1;
132         char *gateway;
133         GSList *list;
134
135         gateway = extract_gateway(msg, bytes, &index);
136         if (gateway == NULL || index < 0)
137                 return;
138
139         for (list = rtnl_list; list; list = list->next) {
140                 struct connman_rtnl *rtnl = list->data;
141
142                 if (rtnl->newgateway)
143                         rtnl->newgateway(index, gateway);
144         }
145
146         g_free(gateway);
147 }
148
149 static void process_delgateway(struct rtmsg *msg, int bytes)
150 {
151         int index = -1;
152         char *gateway;
153         GSList *list;
154
155         gateway = extract_gateway(msg, bytes, &index);
156         if (gateway == NULL || index < 0)
157                 return;
158
159         for (list = rtnl_list; list; list = list->next) {
160                 struct connman_rtnl *rtnl = list->data;
161
162                 if (rtnl->delgateway)
163                         rtnl->delgateway(index, gateway);
164         }
165
166         g_free(gateway);
167 }
168
169 static inline void print_inet(struct rtattr *attr, const char *name, int family)
170 {
171         if (family == AF_INET) {
172                 struct in_addr addr;
173                 addr = *((struct in_addr *) RTA_DATA(attr));
174                 DBG("  attr %s (len %jd) %s\n",
175                                 name, RTA_PAYLOAD(attr), inet_ntoa(addr));
176         } else
177                 DBG("  attr %s (len %jd)\n", name, RTA_PAYLOAD(attr));
178 }
179
180 static inline void print_char(struct rtattr *attr, const char *name)
181 {
182         DBG("  attr %s (len %jd) %s\n", name, RTA_PAYLOAD(attr),
183                                                 (char *) RTA_DATA(attr));
184 }
185
186 static inline void print_byte(struct rtattr *attr, const char *name)
187 {
188         DBG("  attr %s (len %jd) 0x%02x\n", name, RTA_PAYLOAD(attr),
189                                         *((unsigned char *) RTA_DATA(attr)));
190 }
191
192 static inline void print_attr(struct rtattr *attr, const char *name)
193 {
194         if (name)
195                 DBG("  attr %s (len %jd)\n", name, RTA_PAYLOAD(attr));
196         else
197                 DBG("  attr %d (len %jd)\n",
198                                         attr->rta_type, RTA_PAYLOAD(attr));
199 }
200
201 static void rtnl_link(struct nlmsghdr *hdr)
202 {
203 #if 0
204         struct ifinfomsg *msg;
205         struct rtattr *attr;
206         int bytes;
207
208         msg = (struct ifinfomsg *) NLMSG_DATA(hdr);
209         bytes = IFLA_PAYLOAD(hdr);
210
211         DBG("ifi_index %d ifi_flags 0x%04x", msg->ifi_index, msg->ifi_flags);
212
213         for (attr = IFLA_RTA(msg); RTA_OK(attr, bytes);
214                                         attr = RTA_NEXT(attr, bytes)) {
215                 switch (attr->rta_type) {
216                 case IFLA_ADDRESS:
217                         print_attr(attr, "address");
218                         break;
219                 case IFLA_BROADCAST:
220                         print_attr(attr, "broadcast");
221                         break;
222                 case IFLA_IFNAME:
223                         print_char(attr, "ifname");
224                         break;
225                 case IFLA_MTU:
226                         print_attr(attr, "mtu");
227                         break;
228                 case IFLA_LINK:
229                         print_attr(attr, "link");
230                         break;
231                 case IFLA_QDISC:
232                         print_attr(attr, "qdisc");
233                         break;
234                 case IFLA_STATS:
235                         print_attr(attr, "stats");
236                         break;
237                 case IFLA_COST:
238                         print_attr(attr, "cost");
239                         break;
240                 case IFLA_PRIORITY:
241                         print_attr(attr, "priority");
242                         break;
243                 case IFLA_MASTER:
244                         print_attr(attr, "master");
245                         break;
246                 case IFLA_WIRELESS:
247                         print_attr(attr, "wireless");
248                         break;
249                 case IFLA_PROTINFO:
250                         print_attr(attr, "protinfo");
251                         break;
252                 case IFLA_TXQLEN:
253                         print_attr(attr, "txqlen");
254                         break;
255                 case IFLA_MAP:
256                         print_attr(attr, "map");
257                         break;
258                 case IFLA_WEIGHT:
259                         print_attr(attr, "weight");
260                         break;
261                 case IFLA_OPERSTATE:
262                         print_byte(attr, "operstate");
263                         break;
264                 case IFLA_LINKMODE:
265                         print_byte(attr, "linkmode");
266                         break;
267                 default:
268                         print_attr(attr, NULL);
269                         break;
270                 }
271         }
272 #endif
273 }
274
275 static void rtnl_newlink(struct nlmsghdr *hdr)
276 {
277         struct ifinfomsg *msg;
278
279         msg = (struct ifinfomsg *) NLMSG_DATA(hdr);
280
281         DBG("ifi_type %d ifi_index %d ifi_flags 0x%04x ifi_change 0x%04x",
282                                         msg->ifi_type, msg->ifi_index,
283                                         msg->ifi_flags, msg->ifi_change);
284
285         process_newlink(msg->ifi_type, msg->ifi_index,
286                                         msg->ifi_flags, msg->ifi_change);
287
288         rtnl_link(hdr);
289 }
290
291 static void rtnl_dellink(struct nlmsghdr *hdr)
292 {
293         struct ifinfomsg *msg;
294
295         msg = (struct ifinfomsg *) NLMSG_DATA(hdr);
296
297         DBG("ifi_type %d ifi_index %d ifi_flags 0x%04x ifi_change 0x%04x",
298                                         msg->ifi_type, msg->ifi_index,
299                                         msg->ifi_flags, msg->ifi_change);
300
301         process_dellink(msg->ifi_type, msg->ifi_index,
302                                         msg->ifi_flags, msg->ifi_change);
303
304         rtnl_link(hdr);
305 }
306
307 static void rtnl_addr(struct nlmsghdr *hdr)
308 {
309         struct ifaddrmsg *msg;
310         struct rtattr *attr;
311         int bytes;
312
313         msg = (struct ifaddrmsg *) NLMSG_DATA(hdr);
314         bytes = IFA_PAYLOAD(hdr);
315
316         DBG("ifa_family %d ifa_index %d", msg->ifa_family, msg->ifa_index);
317
318         for (attr = IFA_RTA(msg); RTA_OK(attr, bytes);
319                                         attr = RTA_NEXT(attr, bytes)) {
320                 switch (attr->rta_type) {
321                 case IFA_ADDRESS:
322                         print_inet(attr, "address", msg->ifa_family);
323                         break;
324                 case IFA_LOCAL:
325                         print_inet(attr, "local", msg->ifa_family);
326                         break;
327                 case IFA_LABEL:
328                         print_char(attr, "label");
329                         break;
330                 case IFA_BROADCAST:
331                         print_inet(attr, "broadcast", msg->ifa_family);
332                         break;
333                 case IFA_ANYCAST:
334                         print_attr(attr, "anycast");
335                         break;
336                 case IFA_CACHEINFO:
337                         print_attr(attr, "cacheinfo");
338                         break;
339                 case IFA_MULTICAST:
340                         print_attr(attr, "multicast");
341                         break;
342                 default:
343                         print_attr(attr, NULL);
344                         break;
345                 }
346         }
347 }
348
349 static void rtnl_route(struct nlmsghdr *hdr)
350 {
351 #if 0
352         struct rtmsg *msg;
353         struct rtattr *attr;
354         int bytes;
355
356         msg = (struct rtmsg *) NLMSG_DATA(hdr);
357         bytes = RTM_PAYLOAD(hdr);
358
359         DBG("rtm_family %d rtm_flags 0x%04x", msg->rtm_family, msg->rtm_flags);
360
361         for (attr = RTM_RTA(msg); RTA_OK(attr, bytes);
362                                         attr = RTA_NEXT(attr, bytes)) {
363                 switch (attr->rta_type) {
364                 case RTA_DST:
365                         print_inet(attr, "dst", msg->rtm_family);
366                         break;
367                 case RTA_SRC:
368                         print_inet(attr, "src", msg->rtm_family);
369                         break;
370                 case RTA_IIF:
371                         print_char(attr, "iif");
372                         break;
373                 case RTA_OIF:
374                         print_attr(attr, "oif");
375                         break;
376                 case RTA_GATEWAY:
377                         print_inet(attr, "gateway", msg->rtm_family);
378                         break;
379                 case RTA_PRIORITY:
380                         print_attr(attr, "priority");
381                         break;
382                 case RTA_PREFSRC:
383                         print_inet(attr, "prefsrc", msg->rtm_family);
384                         break;
385                 case RTA_METRICS:
386                         print_attr(attr, "metrics");
387                         break;
388                 case RTA_TABLE:
389                         print_attr(attr, "table");
390                         break;
391                 default:
392                         print_attr(attr, NULL);
393                         break;
394                 }
395         }
396 #endif
397 }
398
399 static void rtnl_newroute(struct nlmsghdr *hdr)
400 {
401         struct rtmsg *msg;
402
403         msg = (struct rtmsg *) NLMSG_DATA(hdr);
404
405         if (msg->rtm_type == RTN_UNICAST && msg->rtm_table == RT_TABLE_MAIN &&
406                                         msg->rtm_scope == RT_SCOPE_UNIVERSE) {
407                 DBG("rtm_table %d rtm_scope %d rtm_type %d rtm_flags 0x%04x",
408                                         msg->rtm_table, msg->rtm_scope,
409                                         msg->rtm_type, msg->rtm_flags);
410                 process_newgateway(msg, RTM_PAYLOAD(hdr));
411         }
412
413         rtnl_route(hdr);
414 }
415
416 static void rtnl_delroute(struct nlmsghdr *hdr)
417 {
418         struct rtmsg *msg;
419
420         msg = (struct rtmsg *) NLMSG_DATA(hdr);
421
422         if (msg->rtm_type == RTN_UNICAST && msg->rtm_table == RT_TABLE_MAIN &&
423                                         msg->rtm_scope == RT_SCOPE_UNIVERSE) {
424                 DBG("rtm_table %d rtm_scope %d rtm_type %d rtm_flags 0x%04x",
425                                         msg->rtm_table, msg->rtm_scope,
426                                         msg->rtm_type, msg->rtm_flags);
427                 process_delgateway(msg, RTM_PAYLOAD(hdr));
428         }
429
430         rtnl_route(hdr);
431 }
432
433 static const char *type2string(uint16_t type)
434 {
435         switch (type) {
436         case NLMSG_NOOP:
437                 return "NOOP";
438         case NLMSG_ERROR:
439                 return "ERROR";
440         case NLMSG_DONE:
441                 return "DONE";
442         case NLMSG_OVERRUN:
443                 return "OVERRUN";
444         case RTM_GETLINK:
445                 return "GETLINK";
446         case RTM_NEWLINK:
447                 return "NEWLINK";
448         case RTM_DELLINK:
449                 return "DELLINK";
450         case RTM_NEWADDR:
451                 return "NEWADDR";
452         case RTM_DELADDR:
453                 return "DELADDR";
454         case RTM_GETROUTE:
455                 return "GETROUTE";
456         case RTM_NEWROUTE:
457                 return "NEWROUTE";
458         case RTM_DELROUTE:
459                 return "DELROUTE";
460         default:
461                 return "UNKNOWN";
462         }
463 }
464
465 static GIOChannel *channel = NULL;
466
467 struct rtnl_request {
468         struct nlmsghdr hdr;
469         struct rtgenmsg msg;
470 };
471 #define RTNL_REQUEST_SIZE  (sizeof(struct nlmsghdr) + sizeof(struct rtgenmsg))
472
473 static GSList *request_list = NULL;
474 static guint32 request_seq = 0;
475
476 static struct rtnl_request *find_request(guint32 seq)
477 {
478         GSList *list;
479
480         for (list = request_list; list; list = list->next) {
481                 struct rtnl_request *req = list->data;
482
483                 if (req->hdr.nlmsg_seq == seq)
484                         return req;
485         }
486
487         return NULL;
488 }
489
490 static int send_request(struct rtnl_request *req)
491 {
492         struct sockaddr_nl addr;
493         int sk;
494
495         DBG("%s len %d type %d flags 0x%04x seq %d",
496                                 type2string(req->hdr.nlmsg_type),
497                                 req->hdr.nlmsg_len, req->hdr.nlmsg_type,
498                                 req->hdr.nlmsg_flags, req->hdr.nlmsg_seq);
499
500         sk = g_io_channel_unix_get_fd(channel);
501
502         memset(&addr, 0, sizeof(addr));
503         addr.nl_family = AF_NETLINK;
504
505         return sendto(sk, req, req->hdr.nlmsg_len, 0,
506                                 (struct sockaddr *) &addr, sizeof(addr));
507 }
508
509 static int queue_request(struct rtnl_request *req)
510 {
511         request_list = g_slist_append(request_list, req);
512
513         if (g_slist_length(request_list) > 1)
514                 return 0;
515
516         return send_request(req);
517 }
518
519 static int process_response(guint32 seq)
520 {
521         struct rtnl_request *req;
522
523         DBG("seq %d", seq);
524
525         req = find_request(seq);
526         if (req != NULL) {
527                 request_list = g_slist_remove(request_list, req);
528                 g_free(req);
529         }
530
531         req = g_slist_nth_data(request_list, 0);
532         if (req == NULL)
533                 return 0;
534
535         return send_request(req);
536 }
537
538 static void rtnl_message(void *buf, size_t len)
539 {
540         DBG("buf %p len %zd", buf, len);
541
542         while (len > 0) {
543                 struct nlmsghdr *hdr = buf;
544                 struct nlmsgerr *err;
545
546                 if (!NLMSG_OK(hdr, len))
547                         break;
548
549                 DBG("%s len %d type %d flags 0x%04x seq %d",
550                                         type2string(hdr->nlmsg_type),
551                                         hdr->nlmsg_len, hdr->nlmsg_type,
552                                         hdr->nlmsg_flags, hdr->nlmsg_seq);
553
554                 switch (hdr->nlmsg_type) {
555                 case NLMSG_NOOP:
556                 case NLMSG_OVERRUN:
557                         return;
558                 case NLMSG_DONE:
559                         process_response(hdr->nlmsg_seq);
560                         return;
561                 case NLMSG_ERROR:
562                         err = NLMSG_DATA(hdr);
563                         DBG("error %d (%s)", -err->error,
564                                                 strerror(-err->error));
565                         return;
566                 case RTM_NEWLINK:
567                         rtnl_newlink(hdr);
568                         break;
569                 case RTM_DELLINK:
570                         rtnl_dellink(hdr);
571                         break;
572                 case RTM_NEWADDR:
573                 case RTM_DELADDR:
574                         rtnl_addr(hdr);
575                         break;
576                 case RTM_NEWROUTE:
577                         rtnl_newroute(hdr);
578                         break;
579                 case RTM_DELROUTE:
580                         rtnl_delroute(hdr);
581                         break;
582                 }
583
584                 len -= hdr->nlmsg_len;
585                 buf += hdr->nlmsg_len;
586         }
587 }
588
589 static gboolean netlink_event(GIOChannel *chan,
590                                 GIOCondition cond, gpointer data)
591 {
592         unsigned char buf[4096];
593         gsize len;
594         GIOError err;
595
596         if (cond & (G_IO_NVAL | G_IO_HUP | G_IO_ERR))
597                 return FALSE;
598
599         memset(buf, 0, sizeof(buf));
600
601         err = g_io_channel_read(chan, (gchar *) buf, sizeof(buf), &len);
602         if (err) {
603                 if (err == G_IO_ERROR_AGAIN)
604                         return TRUE;
605                 return FALSE;
606         }
607
608         rtnl_message(buf, len);
609
610         return TRUE;
611 }
612
613 int connman_rtnl_send_getlink(void)
614 {
615         struct rtnl_request *req;
616
617         DBG("");
618
619         req = g_try_malloc0(RTNL_REQUEST_SIZE);
620         if (req == NULL)
621                 return -ENOMEM;
622
623         req->hdr.nlmsg_len = RTNL_REQUEST_SIZE;
624         req->hdr.nlmsg_type = RTM_GETLINK;
625         req->hdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP;
626         req->hdr.nlmsg_pid = 0;
627         req->hdr.nlmsg_seq = request_seq++;
628         req->msg.rtgen_family = AF_INET;
629
630         return queue_request(req);
631 }
632
633 int connman_rtnl_send_getroute(void)
634 {
635         struct rtnl_request *req;
636
637         DBG("");
638
639         req = g_try_malloc0(RTNL_REQUEST_SIZE);
640         if (req == NULL)
641                 return -ENOMEM;
642
643         req->hdr.nlmsg_len = RTNL_REQUEST_SIZE;
644         req->hdr.nlmsg_type = RTM_GETROUTE;
645         req->hdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP;
646         req->hdr.nlmsg_pid = 0;
647         req->hdr.nlmsg_seq = request_seq++;
648         req->msg.rtgen_family = AF_INET;
649
650         return queue_request(req);
651 }
652
653 int __connman_rtnl_init(void)
654 {
655         struct sockaddr_nl addr;
656         int sk;
657
658         DBG("");
659
660         sk = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE);
661         if (sk < 0)
662                 return -1;
663
664         memset(&addr, 0, sizeof(addr));
665         addr.nl_family = AF_NETLINK;
666         addr.nl_groups = RTMGRP_LINK | RTMGRP_IPV4_ROUTE;
667         //addr.nl_groups = RTMGRP_LINK | RTMGRP_IPV4_IFADDR;
668         //addr.nl_groups = RTMGRP_LINK | RTMGRP_IPV4_IFADDR | RTMGRP_IPV4_ROUTE;
669
670         if (bind(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
671                 close(sk);
672                 return -1;
673         }
674
675         channel = g_io_channel_unix_new(sk);
676         g_io_channel_set_close_on_unref(channel, TRUE);
677
678         g_io_add_watch(channel, G_IO_IN | G_IO_NVAL | G_IO_HUP | G_IO_ERR,
679                                                         netlink_event, NULL);
680
681         return 0;
682 }
683
684 void __connman_rtnl_cleanup(void)
685 {
686         GSList *list;
687
688         DBG("");
689
690         for (list = request_list; list; list = list->next) {
691                 struct rtnl_request *req = list->data;
692
693                 DBG("%s len %d type %d flags 0x%04x seq %d",
694                                 type2string(req->hdr.nlmsg_type),
695                                 req->hdr.nlmsg_len, req->hdr.nlmsg_type,
696                                 req->hdr.nlmsg_flags, req->hdr.nlmsg_seq);
697
698                 g_free(req);
699                 list->data = NULL;
700         }
701
702         g_slist_free(request_list);
703         request_list = NULL;
704
705         g_io_channel_shutdown(channel, TRUE, NULL);
706         g_io_channel_unref(channel);
707
708         channel = NULL;
709 }