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