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