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