Fix parsing of netlink messages for routing
[platform/upstream/connman.git] / src / rtnl.c
1 /*
2  *
3  *  Connection Manager
4  *
5  *  Copyright (C) 2007  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 <stdio.h>
27 #include <unistd.h>
28 #include <string.h>
29 #include <sys/socket.h>
30 #include <arpa/inet.h>
31
32 #include <linux/netlink.h>
33 #include <linux/rtnetlink.h>
34
35 #include <glib.h>
36
37 #include "connman.h"
38
39 static void parse_link(struct nlmsghdr *hdr)
40 {
41         struct ifinfomsg *msg;
42         struct rtattr *attr;
43         int bytes;
44
45         msg = (struct ifinfomsg *) NLMSG_DATA(hdr);
46         bytes = IFLA_PAYLOAD(hdr);
47
48         DBG("ifi_index %d ifi_flags %d", msg->ifi_index, msg->ifi_flags);
49
50         for (attr = IFLA_RTA(msg); RTA_OK(attr, bytes);
51                                         attr = RTA_NEXT(attr, bytes)) {
52                 int len = RTA_PAYLOAD(attr);
53
54                 switch (attr->rta_type) {
55                 case IFLA_ADDRESS:
56                         DBG("  rta_type address len %d", len);
57                         break;
58                 case IFLA_BROADCAST:
59                         DBG("  rta_type broadcast len %d", len);
60                         break;
61                 case IFLA_IFNAME:
62                         DBG("  rta_type ifname %s", (char *) RTA_DATA(attr));
63                         break;
64                 case IFLA_MTU:
65                         DBG("  rta_type mtu len %d", len);
66                         break;
67                 case IFLA_LINK:
68                         DBG("  rta_type link len %d", len);
69                         break;
70                 case IFLA_QDISC:
71                         DBG("  rta_type qdisc len %d", len);
72                         break;
73                 case IFLA_STATS:
74                         DBG("  rta_type stats len %d", len);
75                         break;
76                 case IFLA_COST:
77                         DBG("  rta_type cost len %d", len);
78                         break;
79                 case IFLA_PRIORITY:
80                         DBG("  rta_type priority len %d", len);
81                         break;
82                 case IFLA_MASTER:
83                         DBG("  rta_type master len %d", len);
84                         break;
85                 case IFLA_WIRELESS:
86                         DBG("  rta_type wireless len %d", len);
87                         {
88                                 unsigned char *data = RTA_DATA(attr);
89                                 int i;
90                                 for (i = 0; i < len; i++)
91                                         printf(" %02x", data[i]);
92                                 printf("\n");
93                         }
94                         break;
95                 case IFLA_PROTINFO:
96                         DBG("  rta_type protinfo len %d", len);
97                         break;
98                 case IFLA_TXQLEN:
99                         DBG("  rta_type txqlen len %d", len);
100                         break;
101                 case IFLA_MAP:
102                         DBG("  rta_type map len %d", len);
103                         break;
104                 case IFLA_WEIGHT:
105                         DBG("  rta_type widght len %d", len);
106                         break;
107                 case IFLA_OPERSTATE:
108                         DBG("  rta_type operstate len %d", len);
109                         break;
110                 case IFLA_LINKMODE:
111                         DBG("  rta_type linkmode len %d", len);
112                         break;
113                 default:
114                         DBG("  rta_type %d len %d", attr->rta_type, len);
115                         break;
116                 }
117         }
118 }
119
120 static void parse_addr(struct nlmsghdr *hdr)
121 {
122         struct ifaddrmsg *msg;
123         struct rtattr *attr;
124         int bytes;
125
126         msg = (struct ifaddrmsg *) NLMSG_DATA(hdr);
127         bytes = IFA_PAYLOAD(hdr);
128
129         DBG("ifa_family %d ifa_index %d", msg->ifa_family, msg->ifa_index);
130
131         for (attr = IFA_RTA(msg); RTA_OK(attr, bytes);
132                                         attr = RTA_NEXT(attr, bytes)) {
133                 int len = RTA_PAYLOAD(attr);
134
135                 switch (attr->rta_type) {
136                 case IFA_ADDRESS:
137                         DBG("  rta_type address len %d", len);
138                         if (msg->ifa_family == AF_INET) {
139                                 struct in_addr addr;
140                                 addr = *((struct in_addr *) RTA_DATA(attr));
141                                 DBG("    address %s", inet_ntoa(addr));
142                         }
143                         break;
144                 case IFA_LOCAL:
145                         DBG("  rta_type local len %d", len);
146                         if (msg->ifa_family == AF_INET) {
147                                 struct in_addr addr;
148                                 addr = *((struct in_addr *) RTA_DATA(attr));
149                                 DBG("    address %s", inet_ntoa(addr));
150                         }
151                         break;
152                 case IFA_LABEL:
153                         DBG("  rta_type label %s", (char *) RTA_DATA(attr));
154                         break;
155                 case IFA_BROADCAST:
156                         DBG("  rta_type broadcast len %d", len);
157                         if (msg->ifa_family == AF_INET) {
158                                 struct in_addr addr;
159                                 addr = *((struct in_addr *) RTA_DATA(attr));
160                                 DBG("    address %s", inet_ntoa(addr));
161                         }
162                         break;
163                 case IFA_ANYCAST:
164                         DBG("  rta_type anycast len %d", len);
165                         break;
166                 case IFA_CACHEINFO:
167                         DBG("  rta_type cacheinfo len %d", len);
168                         break;
169                 case IFA_MULTICAST:
170                         DBG("  rta_type multicast len %d", len);
171                         break;
172                 default:
173                         DBG("  rta_type %d len %d", attr->rta_type, len);
174                         break;
175                 }
176         }
177 }
178
179 static void parse_route(struct nlmsghdr *hdr)
180 {
181         struct rtmsg *msg;
182         struct rtattr *attr;
183         int bytes;
184
185         msg = (struct rtmsg *) NLMSG_DATA(hdr);
186         bytes = RTM_PAYLOAD(hdr);
187
188         DBG("rtm_family %d rtm_flags %d", msg->rtm_family, msg->rtm_flags);
189
190         for (attr = RTM_RTA(msg); RTA_OK(attr, bytes);
191                                         attr = RTA_NEXT(attr, bytes)) {
192                 int len = RTA_PAYLOAD(attr);
193
194                 switch (attr->rta_type) {
195                 case RTA_DST:
196                         DBG("  rta_type dst len %d", len);
197                         if (msg->rtm_family == AF_INET) {
198                                 struct in_addr addr;
199                                 addr = *((struct in_addr *) RTA_DATA(attr));
200                                 DBG("    address %s", inet_ntoa(addr));
201                         }
202                         break;
203                 case RTA_SRC:
204                         DBG("  rta_type src len %d", len);
205                         if (msg->rtm_family == AF_INET) {
206                                 struct in_addr addr;
207                                 addr = *((struct in_addr *) RTA_DATA(attr));
208                                 DBG("    address %s", inet_ntoa(addr));
209                         }
210                         break;
211                 case RTA_IIF:
212                         DBG("  rta_type iff len %d", len);
213                         break;
214                 case RTA_OIF:
215                         DBG("  rta_type oif len %d", len);
216                         break;
217                 case RTA_GATEWAY:
218                         DBG("  rta_type gateway len %d", len);
219                         if (msg->rtm_family == AF_INET) {
220                                 struct in_addr addr;
221                                 addr = *((struct in_addr *) RTA_DATA(attr));
222                                 DBG("    address %s", inet_ntoa(addr));
223                         }
224                         break;
225                 case RTA_PRIORITY:
226                         DBG("  rta_type priority len %d", len);
227                         break;
228                 case RTA_PREFSRC:
229                         DBG("  rta_type prefsrc len %d", len);
230                         if (msg->rtm_family == AF_INET) {
231                                 struct in_addr addr;
232                                 addr = *((struct in_addr *) RTA_DATA(attr));
233                                 DBG("    address %s", inet_ntoa(addr));
234                         }
235                         break;
236                 case RTA_METRICS:
237                         DBG("  rta_type metrics len %d", len);
238                         break;
239                 case RTA_TABLE:
240                         DBG("  rta_type table len %d", len);
241                         break;
242                 default:
243                         DBG("  rta_type %d len %d", attr->rta_type, len);
244                         break;
245                 }
246         }
247 }
248
249 static void parse_message(unsigned char *buf, size_t size)
250 {
251         struct nlmsghdr *hdr = (void *) buf;
252
253         if (!NLMSG_OK(hdr, size))
254                 return;
255
256         switch (hdr->nlmsg_type) {
257         case NLMSG_DONE:
258                 DBG("nlmsg_type done");
259                 return;
260         case NLMSG_NOOP:
261                 DBG("nlmsg_type noop");
262                 return;
263         case NLMSG_OVERRUN:
264                 DBG("nlmsg_type overrun");
265                 return;
266         case NLMSG_ERROR:
267                 DBG("nlmsg_type error");
268                 return;
269         case RTM_NEWLINK:
270                 DBG("nlmsg_type RTM_NEWLINK");
271                 parse_link(hdr);
272                 break;
273         case RTM_DELLINK:
274                 DBG("nlmsg_type RTM_DELLINK");
275                 parse_link(hdr);
276                 break;
277         case RTM_NEWADDR:
278                 DBG("nlmsg_type RTM_NEWADDR");
279                 parse_addr(hdr);
280                 break;
281         case RTM_DELADDR:
282                 DBG("nlmsg_type RTM_DELADDR");
283                 parse_addr(hdr);
284                 break;
285         case RTM_NEWROUTE:
286                 DBG("nlmsg_type RTM_NEWROUTE");
287                 parse_route(hdr);
288                 break;
289         case RTM_DELROUTE:
290                 DBG("nlmsg_type RTM_DELROUTE");
291                 parse_route(hdr);
292                 break;
293         default:
294                 DBG("nlmsg_type %d", hdr->nlmsg_type);
295                 break;
296         }
297 }
298
299 static gboolean netlink_event(GIOChannel *chan,
300                                 GIOCondition cond, gpointer data)
301 {
302         unsigned char buf[256];
303         gsize len;
304         GIOError err;
305
306         if (cond & (G_IO_NVAL | G_IO_HUP | G_IO_ERR)) {
307                 g_io_channel_unref(chan);
308                 return FALSE;
309         }
310
311         memset(buf, 0, sizeof(buf));
312
313         err = g_io_channel_read(chan, (gchar *) buf, sizeof(buf), &len);
314         if (err) {
315                 if (err == G_IO_ERROR_AGAIN)
316                         return TRUE;
317                 g_io_channel_unref(chan);
318                 return FALSE;
319         }
320
321         parse_message(buf, len);
322
323         return TRUE;
324 }
325
326 static GIOChannel *channel = NULL;
327
328 int __connman_rtnl_init(void)
329 {
330         struct sockaddr_nl addr;
331         int sk;
332
333         DBG("");
334
335         sk = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE);
336         if (sk < 0)
337                 return -1;
338
339         memset(&addr, 0, sizeof(addr));
340         addr.nl_family = AF_NETLINK;
341         addr.nl_groups = RTMGRP_LINK | RTMGRP_IPV4_IFADDR | RTMGRP_IPV4_ROUTE;
342         addr.nl_pid = getpid();
343
344         if (bind(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
345                 close(sk);
346                 return -1;
347         }
348
349         channel = g_io_channel_unix_new(sk);
350         g_io_channel_set_close_on_unref(channel, TRUE);
351
352         g_io_add_watch(channel,
353                         G_IO_IN | G_IO_NVAL | G_IO_HUP | G_IO_ERR,
354                                                 netlink_event, NULL);
355
356         g_io_channel_unref(channel);
357
358         return 0;
359 }
360
361 void __connman_rtnl_cleanup(void)
362 {
363         DBG("");
364
365         g_io_channel_unref(channel);
366
367         channel = NULL;
368 }