Fix return value of getlink function
[framework/connectivity/connman.git] / src / rtnl.c
1 /*
2  *
3  *  Connection Manager
4  *
5  *  Copyright (C) 2007-2008  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 GStaticRWLock rtnl_lock = G_STATIC_RW_LOCK_INIT;
40 static GSList *rtnl_list = NULL;
41
42 static gint compare_priority(gconstpointer a, gconstpointer b)
43 {
44         const struct connman_rtnl *rtnl1 = a;
45         const struct connman_rtnl *rtnl2 = b;
46
47         return rtnl2->priority - rtnl1->priority;
48 }
49
50 /**
51  * connman_rtnl_register:
52  * @rtnl: RTNL module
53  *
54  * Register a new RTNL module
55  *
56  * Returns: %0 on success
57  */
58 int connman_rtnl_register(struct connman_rtnl *rtnl)
59 {
60         DBG("rtnl %p name %s", rtnl, rtnl->name);
61
62         g_static_rw_lock_writer_lock(&rtnl_lock);
63
64         rtnl_list = g_slist_insert_sorted(rtnl_list, rtnl,
65                                                         compare_priority);
66
67         g_static_rw_lock_writer_unlock(&rtnl_lock);
68
69         return 0;
70 }
71
72 /**
73  * connman_rtnl_unregister:
74  * @rtnl: RTNL module
75  *
76  * Remove a previously registered RTNL module
77  */
78 void connman_rtnl_unregister(struct connman_rtnl *rtnl)
79 {
80         DBG("rtnl %p name %s", rtnl, rtnl->name);
81
82         g_static_rw_lock_writer_lock(&rtnl_lock);
83
84         rtnl_list = g_slist_remove(rtnl_list, rtnl);
85
86         g_static_rw_lock_writer_unlock(&rtnl_lock);
87 }
88
89 static void process_newlink(unsigned short type, int index,
90                                         unsigned flags, unsigned change)
91 {
92         GSList *list;
93
94         DBG("idex %d", index);
95
96         g_static_rw_lock_reader_lock(&rtnl_lock);
97
98         for (list = rtnl_list; list; list = list->next) {
99                 struct connman_rtnl *rtnl = list->data;
100
101                 if (rtnl->newlink)
102                         rtnl->newlink(type, index, flags, change);
103         }
104
105         g_static_rw_lock_reader_unlock(&rtnl_lock);
106 }
107
108 static void process_dellink(unsigned short type, int index,
109                                         unsigned flags, unsigned change)
110 {
111         GSList *list;
112
113         DBG("idex %d", index);
114
115         g_static_rw_lock_reader_lock(&rtnl_lock);
116
117         for (list = rtnl_list; list; list = list->next) {
118                 struct connman_rtnl *rtnl = list->data;
119
120                 if (rtnl->dellink)
121                         rtnl->dellink(type, index, flags, change);
122         }
123
124         g_static_rw_lock_reader_unlock(&rtnl_lock);
125 }
126
127 static inline void print_inet(struct rtattr *attr, const char *name, int family)
128 {
129         if (family == AF_INET) {
130                 struct in_addr addr;
131                 addr = *((struct in_addr *) RTA_DATA(attr));
132                 DBG("  attr %s (len %jd) %s\n",
133                                 name, RTA_PAYLOAD(attr), inet_ntoa(addr));
134         } else
135                 DBG("  attr %s (len %jd)\n", name, RTA_PAYLOAD(attr));
136 }
137
138 static inline void print_char(struct rtattr *attr, const char *name)
139 {
140         DBG("  attr %s (len %jd) %s\n", name, RTA_PAYLOAD(attr),
141                                                 (char *) RTA_DATA(attr));
142 }
143
144 static inline void print_byte(struct rtattr *attr, const char *name)
145 {
146         DBG("  attr %s (len %jd) 0x%02x\n", name, RTA_PAYLOAD(attr),
147                                         *((unsigned char *) RTA_DATA(attr)));
148 }
149
150 static inline void print_attr(struct rtattr *attr, const char *name)
151 {
152         if (name)
153                 DBG("  attr %s (len %jd)\n", name, RTA_PAYLOAD(attr));
154         else
155                 DBG("  attr %d (len %jd)\n",
156                                         attr->rta_type, RTA_PAYLOAD(attr));
157 }
158
159 static void rtnl_link(struct nlmsghdr *hdr)
160 {
161         struct ifinfomsg *msg;
162         struct rtattr *attr;
163         int bytes;
164
165         msg = (struct ifinfomsg *) NLMSG_DATA(hdr);
166         bytes = IFLA_PAYLOAD(hdr);
167
168         DBG("ifi_index %d ifi_flags 0x%04x", msg->ifi_index, msg->ifi_flags);
169
170         for (attr = IFLA_RTA(msg); RTA_OK(attr, bytes);
171                                         attr = RTA_NEXT(attr, bytes)) {
172                 switch (attr->rta_type) {
173                 case IFLA_ADDRESS:
174                         print_attr(attr, "address");
175                         break;
176                 case IFLA_BROADCAST:
177                         print_attr(attr, "broadcast");
178                         break;
179                 case IFLA_IFNAME:
180                         print_char(attr, "ifname");
181                         break;
182                 case IFLA_MTU:
183                         print_attr(attr, "mtu");
184                         break;
185                 case IFLA_LINK:
186                         print_attr(attr, "link");
187                         break;
188                 case IFLA_QDISC:
189                         print_attr(attr, "qdisc");
190                         break;
191                 case IFLA_STATS:
192                         print_attr(attr, "stats");
193                         break;
194                 case IFLA_COST:
195                         print_attr(attr, "cost");
196                         break;
197                 case IFLA_PRIORITY:
198                         print_attr(attr, "priority");
199                         break;
200                 case IFLA_MASTER:
201                         print_attr(attr, "master");
202                         break;
203                 case IFLA_WIRELESS:
204                         print_attr(attr, "wireless");
205                         break;
206                 case IFLA_PROTINFO:
207                         print_attr(attr, "protinfo");
208                         break;
209                 case IFLA_TXQLEN:
210                         print_attr(attr, "txqlen");
211                         break;
212                 case IFLA_MAP:
213                         print_attr(attr, "map");
214                         break;
215                 case IFLA_WEIGHT:
216                         print_attr(attr, "weight");
217                         break;
218                 case IFLA_OPERSTATE:
219                         print_byte(attr, "operstate");
220                         break;
221                 case IFLA_LINKMODE:
222                         print_byte(attr, "linkmode");
223                         break;
224                 default:
225                         print_attr(attr, NULL);
226                         break;
227                 }
228         }
229 }
230
231 static void rtnl_newlink(struct nlmsghdr *hdr)
232 {
233         struct ifinfomsg *msg;
234
235         msg = (struct ifinfomsg *) NLMSG_DATA(hdr);
236
237         DBG("ifi_index %d ifi_flags 0x%04x", msg->ifi_index, msg->ifi_flags);
238
239         process_newlink(msg->ifi_type, msg->ifi_index,
240                                         msg->ifi_flags, msg->ifi_change);
241
242         rtnl_link(hdr);
243 }
244
245 static void rtnl_dellink(struct nlmsghdr *hdr)
246 {
247         struct ifinfomsg *msg;
248
249         msg = (struct ifinfomsg *) NLMSG_DATA(hdr);
250
251         DBG("ifi_index %d ifi_flags 0x%04x", msg->ifi_index, msg->ifi_flags);
252
253         process_dellink(msg->ifi_type, msg->ifi_index,
254                                         msg->ifi_flags, msg->ifi_change);
255
256         rtnl_link(hdr);
257 }
258
259 static void rtnl_addr(struct nlmsghdr *hdr)
260 {
261         struct ifaddrmsg *msg;
262         struct rtattr *attr;
263         int bytes;
264
265         msg = (struct ifaddrmsg *) NLMSG_DATA(hdr);
266         bytes = IFA_PAYLOAD(hdr);
267
268         DBG("ifa_family %d ifa_index %d", msg->ifa_family, msg->ifa_index);
269
270         for (attr = IFA_RTA(msg); RTA_OK(attr, bytes);
271                                         attr = RTA_NEXT(attr, bytes)) {
272                 switch (attr->rta_type) {
273                 case IFA_ADDRESS:
274                         print_inet(attr, "address", msg->ifa_family);
275                         break;
276                 case IFA_LOCAL:
277                         print_inet(attr, "local", msg->ifa_family);
278                         break;
279                 case IFA_LABEL:
280                         print_char(attr, "label");
281                         break;
282                 case IFA_BROADCAST:
283                         print_inet(attr, "broadcast", msg->ifa_family);
284                         break;
285                 case IFA_ANYCAST:
286                         print_attr(attr, "anycast");
287                         break;
288                 case IFA_CACHEINFO:
289                         print_attr(attr, "cacheinfo");
290                         break;
291                 case IFA_MULTICAST:
292                         print_attr(attr, "multicast");
293                         break;
294                 default:
295                         print_attr(attr, NULL);
296                         break;
297                 }
298         }
299 }
300
301 static void rtnl_route(struct nlmsghdr *hdr)
302 {
303         struct rtmsg *msg;
304         struct rtattr *attr;
305         int bytes;
306
307         msg = (struct rtmsg *) NLMSG_DATA(hdr);
308         bytes = RTM_PAYLOAD(hdr);
309
310         DBG("rtm_family %d rtm_flags 0x%04x", msg->rtm_family, msg->rtm_flags);
311
312         for (attr = RTM_RTA(msg); RTA_OK(attr, bytes);
313                                         attr = RTA_NEXT(attr, bytes)) {
314                 switch (attr->rta_type) {
315                 case RTA_DST:
316                         print_inet(attr, "dst", msg->rtm_family);
317                         break;
318                 case RTA_SRC:
319                         print_inet(attr, "src", msg->rtm_family);
320                         break;
321                 case RTA_IIF:
322                         print_char(attr, "iif");
323                         break;
324                 case RTA_OIF:
325                         print_attr(attr, "oif");
326                         break;
327                 case RTA_GATEWAY:
328                         print_inet(attr, "gateway", msg->rtm_family);
329                         break;
330                 case RTA_PRIORITY:
331                         print_attr(attr, "priority");
332                         break;
333                 case RTA_PREFSRC:
334                         print_inet(attr, "prefsrc", msg->rtm_family);
335                         break;
336                 case RTA_METRICS:
337                         print_attr(attr, "metrics");
338                         break;
339                 case RTA_TABLE:
340                         print_attr(attr, "table");
341                         break;
342                 default:
343                         print_attr(attr, NULL);
344                         break;
345                 }
346         }
347 }
348
349 static void rtnl_message(void *buf, size_t len)
350 {
351         DBG("buf %p len %zd", buf, len);
352
353         while (len > 0) {
354                 struct nlmsghdr *hdr = buf;
355                 struct nlmsgerr *err;
356
357                 if (!NLMSG_OK(hdr, len))
358                         break;
359
360                 DBG("len %d type %d flags 0x%04x seq %d",
361                                         hdr->nlmsg_len, hdr->nlmsg_type,
362                                         hdr->nlmsg_flags, hdr->nlmsg_seq);
363
364                 switch (hdr->nlmsg_type) {
365                 case NLMSG_NOOP:
366                         DBG("NOOP");
367                         return;
368                 case NLMSG_ERROR:
369                         err = NLMSG_DATA(hdr);
370                         DBG("ERROR %d (%s)", -err->error,
371                                                 strerror(-err->error));
372                         return;
373                 case NLMSG_DONE:
374                         DBG("DONE");
375                         return;
376                 case NLMSG_OVERRUN:
377                         DBG("OVERRUN");
378                         return;
379                 case RTM_NEWLINK:
380                         DBG("NEWLINK");
381                         rtnl_newlink(hdr);
382                         break;
383                 case RTM_DELLINK:
384                         DBG("DELLINK");
385                         rtnl_dellink(hdr);
386                         break;
387                 case RTM_NEWADDR:
388                         DBG("NEWADDR");
389                         rtnl_addr(hdr);
390                         break;
391                 case RTM_DELADDR:
392                         DBG("DELADDR");
393                         rtnl_addr(hdr);
394                         break;
395                 case RTM_NEWROUTE:
396                         DBG("NEWROUTE");
397                         rtnl_route(hdr);
398                         break;
399                 case RTM_DELROUTE:
400                         DBG("DELROUTE");
401                         rtnl_route(hdr);
402                         break;
403                 default:
404                         DBG("type %d", hdr->nlmsg_type);
405                         break;
406                 }
407
408                 len -= hdr->nlmsg_len;
409                 buf += hdr->nlmsg_len;
410         }
411 }
412
413 static gboolean netlink_event(GIOChannel *chan,
414                                 GIOCondition cond, gpointer data)
415 {
416         unsigned char buf[256];
417         gsize len;
418         GIOError err;
419
420         if (cond & (G_IO_NVAL | G_IO_HUP | G_IO_ERR))
421                 return FALSE;
422
423         memset(buf, 0, sizeof(buf));
424
425         err = g_io_channel_read(chan, (gchar *) buf, sizeof(buf), &len);
426         if (err) {
427                 if (err == G_IO_ERROR_AGAIN)
428                         return TRUE;
429                 return FALSE;
430         }
431
432         rtnl_message(buf, len);
433
434         return TRUE;
435 }
436
437 static GIOChannel *channel = NULL;
438
439 int __connman_rtnl_send(const void *buf, size_t len)
440 {
441         struct sockaddr_nl addr;
442         int sk;
443
444         DBG("buf %p len %zd", buf, len);
445
446         sk = g_io_channel_unix_get_fd(channel);
447
448         memset(&addr, 0, sizeof(addr));
449         addr.nl_family = AF_NETLINK;
450
451         return sendto(sk, buf, len, 0,
452                         (struct sockaddr *) &addr, sizeof(addr));
453 }
454
455 int connman_rtnl_send_getlink(void)
456 {
457         struct {
458                 struct nlmsghdr hdr;
459                 struct rtgenmsg msg;
460         } req;
461
462         DBG("");
463
464         memset(&req, 0, sizeof(req));
465         req.hdr.nlmsg_len = sizeof(req.hdr) + sizeof(req.msg);
466         req.hdr.nlmsg_type = RTM_GETLINK;
467         req.hdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP;
468         req.hdr.nlmsg_pid = 0;
469         req.hdr.nlmsg_seq = 42;
470         req.msg.rtgen_family = AF_INET;
471
472         return __connman_rtnl_send(&req, sizeof(req));
473 }
474
475 int __connman_rtnl_init(void)
476 {
477         struct sockaddr_nl addr;
478         int sk;
479
480         DBG("");
481
482         sk = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE);
483         if (sk < 0)
484                 return -1;
485
486         memset(&addr, 0, sizeof(addr));
487         addr.nl_family = AF_NETLINK;
488         addr.nl_groups = RTMGRP_LINK;
489         //addr.nl_groups = RTMGRP_LINK | RTMGRP_IPV4_IFADDR;
490         //addr.nl_groups = RTMGRP_LINK | RTMGRP_IPV4_IFADDR | RTMGRP_IPV4_ROUTE;
491
492         if (bind(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
493                 close(sk);
494                 return -1;
495         }
496
497         channel = g_io_channel_unix_new(sk);
498         g_io_channel_set_close_on_unref(channel, TRUE);
499
500         g_io_add_watch(channel, G_IO_IN | G_IO_NVAL | G_IO_HUP | G_IO_ERR,
501                                                         netlink_event, NULL);
502
503         return 0;
504 }
505
506 void __connman_rtnl_cleanup(void)
507 {
508         DBG("");
509
510         g_io_channel_shutdown(channel, TRUE, NULL);
511         g_io_channel_unref(channel);
512
513         channel = NULL;
514 }