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