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