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