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