Add experimental netlink support
[framework/connectivity/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 = IFA_PAYLOAD(hdr);
187
188         DBG("rtm_family %d rtm_flags %d", msg->rtm_family, msg->rtm_flags);
189
190         for (attr = RTA_DATA(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                         break;
198                 case RTA_SRC:
199                         DBG("  rta_type src len %d", len);
200                         break;
201                 case RTA_IIF:
202                         DBG("  rta_type iff len %d", len);
203                         break;
204                 case RTA_OIF:
205                         DBG("  rta_type oif len %d", len);
206                         break;
207                 case RTA_GATEWAY:
208                         DBG("  rta_type gateway len %d", len);
209                         break;
210                 default:
211                         DBG("  rta_type %d len %d", attr->rta_type, len);
212                         break;
213                 }
214         }
215 }
216
217 static void parse_message(unsigned char *buf, size_t size)
218 {
219         struct nlmsghdr *hdr = (void *) buf;
220
221         if (!NLMSG_OK(hdr, size))
222                 return;
223
224         switch (hdr->nlmsg_type) {
225         case NLMSG_DONE:
226                 DBG("nlmsg_type done");
227                 return;
228         case NLMSG_NOOP:
229                 DBG("nlmsg_type noop");
230                 return;
231         case NLMSG_OVERRUN:
232                 DBG("nlmsg_type overrun");
233                 return;
234         case NLMSG_ERROR:
235                 DBG("nlmsg_type error");
236                 return;
237         case RTM_NEWLINK:
238                 DBG("nlmsg_type RTM_NEWLINK");
239                 parse_link(hdr);
240                 break;
241         case RTM_DELLINK:
242                 DBG("nlmsg_type RTM_DELLINK");
243                 parse_link(hdr);
244                 break;
245         case RTM_NEWADDR:
246                 DBG("nlmsg_type RTM_NEWADDR");
247                 parse_addr(hdr);
248                 break;
249         case RTM_DELADDR:
250                 DBG("nlmsg_type RTM_DELADDR");
251                 parse_addr(hdr);
252                 break;
253         case RTM_NEWROUTE:
254                 DBG("nlmsg_type RTM_NEWROUTE");
255                 parse_route(hdr);
256                 break;
257         case RTM_DELROUTE:
258                 DBG("nlmsg_type RTM_DELROUTE");
259                 parse_route(hdr);
260                 break;
261         default:
262                 DBG("nlmsg_type %d", hdr->nlmsg_type);
263                 break;
264         }
265 }
266
267 static gboolean netlink_event(GIOChannel *chan,
268                                 GIOCondition cond, gpointer data)
269 {
270         unsigned char buf[256];
271         gsize len;
272         GIOError err;
273
274         if (cond & (G_IO_NVAL | G_IO_HUP | G_IO_ERR)) {
275                 g_io_channel_unref(chan);
276                 return FALSE;
277         }
278
279         memset(buf, 0, sizeof(buf));
280
281         err = g_io_channel_read(chan, (gchar *) buf, sizeof(buf), &len);
282         if (err) {
283                 if (err == G_IO_ERROR_AGAIN)
284                         return TRUE;
285                 g_io_channel_unref(chan);
286                 return FALSE;
287         }
288
289         parse_message(buf, len);
290
291         return TRUE;
292 }
293
294 static GIOChannel *channel = NULL;
295
296 int __connman_rtnl_init(void)
297 {
298         struct sockaddr_nl addr;
299         int sk;
300
301         DBG("");
302
303         sk = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE);
304         if (sk < 0)
305                 return -1;
306
307         memset(&addr, 0, sizeof(addr));
308         addr.nl_family = AF_NETLINK;
309         addr.nl_groups = RTMGRP_LINK | RTMGRP_IPV4_IFADDR | RTMGRP_IPV4_ROUTE;
310         addr.nl_pid = getpid();
311
312         if (bind(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
313                 close(sk);
314                 return -1;
315         }
316
317         channel = g_io_channel_unix_new(sk);
318         g_io_channel_set_close_on_unref(channel, TRUE);
319
320         g_io_add_watch(channel,
321                         G_IO_IN | G_IO_NVAL | G_IO_HUP | G_IO_ERR,
322                                                 netlink_event, NULL);
323
324         g_io_channel_unref(channel);
325
326         return 0;
327 }
328
329 void __connman_rtnl_cleanup(void)
330 {
331         DBG("");
332
333         g_io_channel_unref(channel);
334
335         channel = NULL;
336 }