Disable unused RTNL address handling for now
[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/if.h>
33 #include <linux/netlink.h>
34 #include <linux/rtnetlink.h>
35
36 #include <glib.h>
37
38 #include "connman.h"
39
40 struct rtnl_data {
41         unsigned ifi_flags;
42 };
43
44 static struct rtnl_data *get_rtnl_data(struct connman_iface *iface)
45 {
46         if ((iface->flags & CONNMAN_IFACE_FLAG_RTNL) == 0)
47                 return NULL;
48
49         if (iface->rtnl_data == NULL)
50                 iface->rtnl_data = g_try_new0(struct rtnl_data, 1);
51
52         return iface->rtnl_data;
53 }
54
55 static inline void print_inet(struct rtattr *attr, const char *name, int family)
56 {
57         if (family == AF_INET) {
58                 struct in_addr addr;
59                 addr = *((struct in_addr *) RTA_DATA(attr));
60                 printf("  attr %s (len %jd) %s\n",
61                                 name, RTA_PAYLOAD(attr), inet_ntoa(addr));
62         } else
63                 printf("  attr %s (len %jd)\n", name, RTA_PAYLOAD(attr));
64 }
65
66 static inline void print_char(struct rtattr *attr, const char *name)
67 {
68         printf("  attr %s (len %jd) %s\n", name, RTA_PAYLOAD(attr),
69                                                 (char *) RTA_DATA(attr));
70 }
71
72 static inline void print_byte(struct rtattr *attr, const char *name)
73 {
74         printf("  attr %s (len %jd) 0x%02x\n", name, RTA_PAYLOAD(attr),
75                                         *((unsigned char *) RTA_DATA(attr)));
76 }
77
78 static inline void print_attr(struct rtattr *attr, const char *name)
79 {
80         if (name)
81                 printf("  attr %s (len %jd)\n", name, RTA_PAYLOAD(attr));
82         else
83                 printf("  attr %d (len %jd)\n",
84                                         attr->rta_type, RTA_PAYLOAD(attr));
85 }
86
87 static void rtnl_link(struct nlmsghdr *hdr)
88 {
89         struct connman_iface *iface;
90         struct rtnl_data *data;
91         struct ifinfomsg *msg;
92         struct rtattr *attr;
93         int bytes;
94
95         msg = (struct ifinfomsg *) NLMSG_DATA(hdr);
96         bytes = IFLA_PAYLOAD(hdr);
97
98         DBG("ifi_index %d ifi_flags 0x%04x", msg->ifi_index, msg->ifi_flags);
99
100         iface = __connman_iface_find(msg->ifi_index);
101         if (iface == NULL)
102                 return;
103
104         data = get_rtnl_data(iface);
105         if (data == NULL)
106                 return;
107
108         if ((data->ifi_flags & IFF_RUNNING) != (msg->ifi_flags & IFF_RUNNING)) {
109                 if (msg->ifi_flags & IFF_RUNNING)
110                         connman_iface_indicate_carrier_on(iface);
111                 else
112                         connman_iface_indicate_carrier_off(iface);
113         }
114
115         if ((data->ifi_flags & IFF_UP) != (msg->ifi_flags & IFF_UP)) {
116                 if (msg->ifi_flags & IFF_UP)
117                         connman_iface_indicate_enabled(iface);
118                 else
119                         connman_iface_indicate_disabled(iface);
120         }
121
122         data->ifi_flags = msg->ifi_flags;
123
124         for (attr = IFLA_RTA(msg); RTA_OK(attr, bytes);
125                                         attr = RTA_NEXT(attr, bytes)) {
126                 switch (attr->rta_type) {
127                 case IFLA_ADDRESS:
128                         print_attr(attr, "address");
129                         break;
130                 case IFLA_BROADCAST:
131                         print_attr(attr, "broadcast");
132                         break;
133                 case IFLA_IFNAME:
134                         print_char(attr, "ifname");
135                         break;
136                 case IFLA_MTU:
137                         print_attr(attr, "mtu");
138                         break;
139                 case IFLA_LINK:
140                         print_attr(attr, "link");
141                         break;
142                 case IFLA_QDISC:
143                         print_attr(attr, "qdisc");
144                         break;
145                 case IFLA_STATS:
146                         print_attr(attr, "stats");
147                         break;
148                 case IFLA_COST:
149                         print_attr(attr, "cost");
150                         break;
151                 case IFLA_PRIORITY:
152                         print_attr(attr, "priority");
153                         break;
154                 case IFLA_MASTER:
155                         print_attr(attr, "master");
156                         break;
157                 case IFLA_WIRELESS:
158                         if (iface->driver->rtnl_wireless)
159                                 iface->driver->rtnl_wireless(iface,
160                                         RTA_DATA(attr), RTA_PAYLOAD(attr));
161                         break;
162                 case IFLA_PROTINFO:
163                         print_attr(attr, "protinfo");
164                         break;
165                 case IFLA_TXQLEN:
166                         print_attr(attr, "txqlen");
167                         break;
168                 case IFLA_MAP:
169                         print_attr(attr, "map");
170                         break;
171                 case IFLA_WEIGHT:
172                         print_attr(attr, "weight");
173                         break;
174                 case IFLA_OPERSTATE:
175                         print_byte(attr, "operstate");
176                         break;
177                 case IFLA_LINKMODE:
178                         print_byte(attr, "linkmode");
179                         break;
180                 default:
181                         print_attr(attr, NULL);
182                         break;
183                 }
184         }
185 }
186
187 static void rtnl_addr(struct nlmsghdr *hdr)
188 {
189         struct connman_iface *iface;
190         struct rtnl_data *data;
191         struct ifaddrmsg *msg;
192         struct rtattr *attr;
193         int bytes;
194
195         msg = (struct ifaddrmsg *) NLMSG_DATA(hdr);
196         bytes = IFA_PAYLOAD(hdr);
197
198         DBG("ifa_family %d ifa_index %d", msg->ifa_family, msg->ifa_index);
199
200         iface = __connman_iface_find(msg->ifa_index);
201         if (iface == NULL)
202                 return;
203
204         data = get_rtnl_data(iface);
205         if (data == NULL)
206                 return;
207
208         for (attr = IFA_RTA(msg); RTA_OK(attr, bytes);
209                                         attr = RTA_NEXT(attr, bytes)) {
210                 switch (attr->rta_type) {
211                 case IFA_ADDRESS:
212                         print_inet(attr, "address", msg->ifa_family);
213                         break;
214                 case IFA_LOCAL:
215                         print_inet(attr, "local", msg->ifa_family);
216                         break;
217                 case IFA_LABEL:
218                         print_char(attr, "label");
219                         break;
220                 case IFA_BROADCAST:
221                         print_inet(attr, "broadcast", msg->ifa_family);
222                         break;
223                 case IFA_ANYCAST:
224                         print_attr(attr, "anycast");
225                         break;
226                 case IFA_CACHEINFO:
227                         print_attr(attr, "cacheinfo");
228                         break;
229                 case IFA_MULTICAST:
230                         print_attr(attr, "multicast");
231                         break;
232                 default:
233                         print_attr(attr, NULL);
234                         break;
235                 }
236         }
237 }
238
239 static void rtnl_route(struct nlmsghdr *hdr)
240 {
241         struct rtmsg *msg;
242         struct rtattr *attr;
243         int bytes;
244
245         msg = (struct rtmsg *) NLMSG_DATA(hdr);
246         bytes = RTM_PAYLOAD(hdr);
247
248         DBG("rtm_family %d rtm_flags 0x%04x", msg->rtm_family, msg->rtm_flags);
249
250         for (attr = RTM_RTA(msg); RTA_OK(attr, bytes);
251                                         attr = RTA_NEXT(attr, bytes)) {
252                 switch (attr->rta_type) {
253                 case RTA_DST:
254                         print_inet(attr, "dst", msg->rtm_family);
255                         break;
256                 case RTA_SRC:
257                         print_inet(attr, "src", msg->rtm_family);
258                         break;
259                 case RTA_IIF:
260                         print_char(attr, "iif");
261                         break;
262                 case RTA_OIF:
263                         print_attr(attr, "oif");
264                         break;
265                 case RTA_GATEWAY:
266                         print_inet(attr, "gateway", msg->rtm_family);
267                         break;
268                 case RTA_PRIORITY:
269                         print_attr(attr, "priority");
270                         break;
271                 case RTA_PREFSRC:
272                         print_inet(attr, "prefsrc", msg->rtm_family);
273                         break;
274                 case RTA_METRICS:
275                         print_attr(attr, "metrics");
276                         break;
277                 case RTA_TABLE:
278                         print_attr(attr, "table");
279                         break;
280                 default:
281                         print_attr(attr, NULL);
282                         break;
283                 }
284         }
285 }
286
287 static void rtnl_message(void *buf, size_t len)
288 {
289         DBG("buf %p len %zd", buf, len);
290
291         while (len > 0) {
292                 struct nlmsghdr *hdr = buf;
293                 struct nlmsgerr *err;
294
295                 if (!NLMSG_OK(hdr, len))
296                         break;
297
298                 DBG("len %d type %d flags 0x%04x seq %d",
299                                         hdr->nlmsg_len, hdr->nlmsg_type,
300                                         hdr->nlmsg_flags, hdr->nlmsg_seq);
301
302                 switch (hdr->nlmsg_type) {
303                 case NLMSG_NOOP:
304                         DBG("NOOP");
305                         return;
306                 case NLMSG_ERROR:
307                         err = NLMSG_DATA(hdr);
308                         DBG("ERROR %d (%s)", -err->error,
309                                                 strerror(-err->error));
310                         return;
311                 case NLMSG_DONE:
312                         DBG("DONE");
313                         return;
314                 case NLMSG_OVERRUN:
315                         DBG("OVERRUN");
316                         return;
317                 case RTM_NEWLINK:
318                         DBG("NEWLINK");
319                         rtnl_link(hdr);
320                         break;
321                 case RTM_DELLINK:
322                         DBG("DELLINK");
323                         rtnl_link(hdr);
324                         break;
325                 case RTM_NEWADDR:
326                         DBG("NEWADDR");
327                         rtnl_addr(hdr);
328                         break;
329                 case RTM_DELADDR:
330                         DBG("DELADDR");
331                         rtnl_addr(hdr);
332                         break;
333                 case RTM_NEWROUTE:
334                         DBG("NEWROUTE");
335                         rtnl_route(hdr);
336                         break;
337                 case RTM_DELROUTE:
338                         DBG("DELROUTE");
339                         rtnl_route(hdr);
340                         break;
341                 default:
342                         DBG("type %d", hdr->nlmsg_type);
343                         break;
344                 }
345
346                 len -= hdr->nlmsg_len;
347                 buf += hdr->nlmsg_len;
348         }
349 }
350
351 static gboolean netlink_event(GIOChannel *chan,
352                                 GIOCondition cond, gpointer data)
353 {
354         unsigned char buf[256];
355         gsize len;
356         GIOError err;
357
358         if (cond & (G_IO_NVAL | G_IO_HUP | G_IO_ERR))
359                 return FALSE;
360
361         memset(buf, 0, sizeof(buf));
362
363         err = g_io_channel_read(chan, (gchar *) buf, sizeof(buf), &len);
364         if (err) {
365                 if (err == G_IO_ERROR_AGAIN)
366                         return TRUE;
367                 return FALSE;
368         }
369
370         rtnl_message(buf, len);
371
372         return TRUE;
373 }
374
375 static GIOChannel *channel = NULL;
376
377 int __connman_rtnl_send(const void *buf, size_t len)
378 {
379         struct sockaddr_nl addr;
380         int sk;
381
382         DBG("buf %p len %zd", buf, len);
383
384         sk = g_io_channel_unix_get_fd(channel);
385
386         memset(&addr, 0, sizeof(addr));
387         addr.nl_family = AF_NETLINK;
388
389         return sendto(sk, buf, len, 0,
390                         (struct sockaddr *) &addr, sizeof(addr));
391 }
392
393 int __connman_rtnl_init(void)
394 {
395         struct sockaddr_nl addr;
396         int sk;
397
398         DBG("");
399
400         sk = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE);
401         if (sk < 0)
402                 return -1;
403
404         memset(&addr, 0, sizeof(addr));
405         addr.nl_family = AF_NETLINK;
406         addr.nl_groups = RTMGRP_LINK;
407         //addr.nl_groups = RTMGRP_LINK | RTMGRP_IPV4_IFADDR;
408         //addr.nl_groups = RTMGRP_LINK | RTMGRP_IPV4_IFADDR | RTMGRP_IPV4_ROUTE;
409
410         if (bind(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
411                 close(sk);
412                 return -1;
413         }
414
415         channel = g_io_channel_unix_new(sk);
416         g_io_channel_set_close_on_unref(channel, TRUE);
417
418         g_io_add_watch(channel,
419                         G_IO_IN | G_IO_NVAL | G_IO_HUP | G_IO_ERR,
420                                                 netlink_event, NULL);
421
422         return 0;
423 }
424
425 void __connman_rtnl_cleanup(void)
426 {
427         DBG("");
428
429         g_io_channel_shutdown(channel, TRUE, NULL);
430         g_io_channel_unref(channel);
431
432         channel = NULL;
433 }