5 * Copyright (C) 2007-2010 Intel Corporation. All rights reserved.
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.
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.
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
29 #include <sys/socket.h>
30 #include <arpa/inet.h>
31 #include <netinet/ether.h>
32 #include <net/if_arp.h>
34 #include <linux/netlink.h>
35 #include <linux/rtnetlink.h>
41 #define print(arg...) do { } while (0)
42 //#define print(arg...) connman_info(arg)
47 connman_rtnl_operstate_cb_t operstate;
48 connman_rtnl_link_cb_t newlink;
52 static GSList *watch_list = NULL;
53 static unsigned int watch_id = 0;
56 * connman_rtnl_add_operstate_watch:
57 * @index: network device index
58 * @callback: callback function
59 * @user_data: callback data;
61 * Add a new RTNL watch for operation state events
63 * Returns: %0 on failure and a unique id on success
65 unsigned int connman_rtnl_add_operstate_watch(int index,
66 connman_rtnl_operstate_cb_t callback, void *user_data)
68 struct watch_data *watch;
70 watch = g_try_new0(struct watch_data, 1);
74 watch->id = ++watch_id;
77 watch->operstate = callback;
78 watch->user_data = user_data;
80 watch_list = g_slist_prepend(watch_list, watch);
82 DBG("id %d", watch->id);
85 unsigned char operstate = 0;
88 callback(operstate, user_data);
95 * connman_rtnl_add_newlink_watch:
96 * @index: network device index
97 * @callback: callback function
98 * @user_data: callback data;
100 * Add a new RTNL watch for newlink events
102 * Returns: %0 on failure and a unique id on success
104 unsigned int connman_rtnl_add_newlink_watch(int index,
105 connman_rtnl_link_cb_t callback, void *user_data)
107 struct watch_data *watch;
109 watch = g_try_new0(struct watch_data, 1);
113 watch->id = ++watch_id;
114 watch->index = index;
116 watch->newlink = callback;
117 watch->user_data = user_data;
119 watch_list = g_slist_prepend(watch_list, watch);
121 DBG("id %d", watch->id);
124 unsigned int flags = __connman_ipconfig_get_flags(index);
127 callback(flags, 0, user_data);
134 * connman_rtnl_remove_watch:
135 * @id: watch identifier
137 * Remove the RTNL watch for the identifier
139 void connman_rtnl_remove_watch(unsigned int id)
148 for (list = watch_list; list; list = list->next) {
149 struct watch_data *watch = list->data;
151 if (watch->id == id) {
152 watch_list = g_slist_remove(watch_list, watch);
159 static void trigger_rtnl(int index, void *user_data)
161 struct connman_rtnl *rtnl = user_data;
164 unsigned short type = __connman_ipconfig_get_type(index);
165 unsigned int flags = __connman_ipconfig_get_flags(index);
167 rtnl->newlink(type, index, flags, 0);
170 if (rtnl->newgateway) {
171 const char *gateway = __connman_ipconfig_get_gateway(index);
174 rtnl->newgateway(index, gateway);
178 static GSList *rtnl_list = NULL;
180 static gint compare_priority(gconstpointer a, gconstpointer b)
182 const struct connman_rtnl *rtnl1 = a;
183 const struct connman_rtnl *rtnl2 = b;
185 return rtnl2->priority - rtnl1->priority;
189 * connman_rtnl_register:
192 * Register a new RTNL module
194 * Returns: %0 on success
196 int connman_rtnl_register(struct connman_rtnl *rtnl)
198 DBG("rtnl %p name %s", rtnl, rtnl->name);
200 rtnl_list = g_slist_insert_sorted(rtnl_list, rtnl,
203 __connman_ipconfig_foreach(trigger_rtnl, rtnl);
209 * connman_rtnl_unregister:
212 * Remove a previously registered RTNL module
214 void connman_rtnl_unregister(struct connman_rtnl *rtnl)
216 DBG("rtnl %p name %s", rtnl, rtnl->name);
218 rtnl_list = g_slist_remove(rtnl_list, rtnl);
221 static const char *operstate2str(unsigned char operstate)
224 case IF_OPER_UNKNOWN:
226 case IF_OPER_NOTPRESENT:
227 return "NOT-PRESENT";
230 case IF_OPER_LOWERLAYERDOWN:
231 return "LOWER-LAYER-DOWN";
232 case IF_OPER_TESTING:
234 case IF_OPER_DORMANT:
243 static void extract_link(struct ifinfomsg *msg, int bytes,
244 struct ether_addr *address, const char **ifname,
245 unsigned int *mtu, unsigned char *operstate,
246 struct rtnl_link_stats *stats)
250 for (attr = IFLA_RTA(msg); RTA_OK(attr, bytes);
251 attr = RTA_NEXT(attr, bytes)) {
252 switch (attr->rta_type) {
255 memcpy(address, RTA_DATA(attr), ETH_ALEN);
259 *ifname = RTA_DATA(attr);
263 *mtu = *((unsigned int *) RTA_DATA(attr));
267 memcpy(stats, RTA_DATA(attr),
268 sizeof(struct rtnl_link_stats));
271 if (operstate != NULL)
272 *operstate = *((unsigned char *) RTA_DATA(attr));
280 static void process_newlink(unsigned short type, int index, unsigned flags,
281 unsigned change, struct ifinfomsg *msg, int bytes)
283 struct ether_addr address = {{ 0, 0, 0, 0, 0, 0 }};
284 struct ether_addr compare = {{ 0, 0, 0, 0, 0, 0 }};
285 struct rtnl_link_stats stats;
286 unsigned char operstate = 0xff;
287 const char *ifname = NULL;
288 unsigned int mtu = 0;
292 memset(&stats, 0, sizeof(stats));
293 extract_link(msg, bytes, &address, &ifname, &mtu, &operstate, &stats);
295 snprintf(str, 18, "%02X:%02X:%02X:%02X:%02X:%02X",
296 address.ether_addr_octet[0],
297 address.ether_addr_octet[1],
298 address.ether_addr_octet[2],
299 address.ether_addr_octet[3],
300 address.ether_addr_octet[4],
301 address.ether_addr_octet[5]);
305 case ARPHRD_LOOPBACK:
307 __connman_ipconfig_newlink(index, type, flags,
312 if (memcmp(&address, &compare, ETH_ALEN) != 0)
313 connman_info("%s {newlink} index %d address %s mtu %u",
314 ifname, index, str, mtu);
316 if (operstate != 0xff)
317 connman_info("%s {newlink} index %d operstate %u <%s>",
318 ifname, index, operstate,
319 operstate2str(operstate));
321 for (list = rtnl_list; list; list = list->next) {
322 struct connman_rtnl *rtnl = list->data;
325 rtnl->newlink(type, index, flags, change);
328 for (list = watch_list; list; list = list->next) {
329 struct watch_data *watch = list->data;
331 if (watch->index != index)
334 if (operstate != 0xff && watch->operstate)
335 watch->operstate(operstate, watch->user_data);
338 watch->newlink(flags, change, watch->user_data);
342 static void process_dellink(unsigned short type, int index, unsigned flags,
343 unsigned change, struct ifinfomsg *msg, int bytes)
345 struct rtnl_link_stats stats;
346 unsigned char operstate = 0xff;
347 const char *ifname = NULL;
350 memset(&stats, 0, sizeof(stats));
351 extract_link(msg, bytes, NULL, &ifname, NULL, &operstate, &stats);
353 if (operstate != 0xff)
354 connman_info("%s {dellink} index %d operstate %u <%s>",
355 ifname, index, operstate,
356 operstate2str(operstate));
358 for (list = watch_list; list; list = list->next) {
359 struct watch_data *watch = list->data;
361 if (watch->index != index)
364 if (operstate != 0xff && watch->operstate)
365 watch->operstate(operstate, watch->user_data);
368 for (list = rtnl_list; list; list = list->next) {
369 struct connman_rtnl *rtnl = list->data;
372 rtnl->dellink(type, index, flags, change);
377 case ARPHRD_LOOPBACK:
379 __connman_ipconfig_dellink(index, &stats);
384 static void extract_addr(struct ifaddrmsg *msg, int bytes,
386 struct in_addr *local,
387 struct in_addr *address,
388 struct in_addr *broadcast)
392 for (attr = IFA_RTA(msg); RTA_OK(attr, bytes);
393 attr = RTA_NEXT(attr, bytes)) {
394 switch (attr->rta_type) {
397 *address = *((struct in_addr *) RTA_DATA(attr));
401 *local = *((struct in_addr *) RTA_DATA(attr));
404 if (broadcast != NULL)
405 *broadcast = *((struct in_addr *) RTA_DATA(attr));
409 *label = RTA_DATA(attr);
415 static void process_newaddr(unsigned char family, unsigned char prefixlen,
416 int index, struct ifaddrmsg *msg, int bytes)
418 struct in_addr address = { INADDR_ANY };
419 const char *label = NULL;
421 if (family != AF_INET)
424 extract_addr(msg, bytes, &label, &address, NULL, NULL);
426 __connman_ipconfig_newaddr(index, label,
427 prefixlen, inet_ntoa(address));
430 static void process_deladdr(unsigned char family, unsigned char prefixlen,
431 int index, struct ifaddrmsg *msg, int bytes)
433 struct in_addr address = { INADDR_ANY };
434 const char *label = NULL;
436 if (family != AF_INET)
439 extract_addr(msg, bytes, &label, &address, NULL, NULL);
441 __connman_ipconfig_deladdr(index, label,
442 prefixlen, inet_ntoa(address));
445 static void extract_route(struct rtmsg *msg, int bytes, int *index,
447 struct in_addr *gateway)
451 for (attr = RTM_RTA(msg); RTA_OK(attr, bytes);
452 attr = RTA_NEXT(attr, bytes)) {
453 switch (attr->rta_type) {
456 *dst = *((struct in_addr *) RTA_DATA(attr));
460 *gateway = *((struct in_addr *) RTA_DATA(attr));
464 *index = *((int *) RTA_DATA(attr));
470 static void process_newroute(unsigned char family, unsigned char scope,
471 struct rtmsg *msg, int bytes)
474 struct in_addr dst = { INADDR_ANY }, gateway = { INADDR_ANY };
475 char dststr[16], gatewaystr[16];
478 if (family != AF_INET)
481 extract_route(msg, bytes, &index, &dst, &gateway);
483 inet_ntop(family, &dst, dststr, sizeof(dststr));
484 inet_ntop(family, &gateway, gatewaystr, sizeof(gatewaystr));
486 __connman_ipconfig_newroute(index, scope, dststr, gatewaystr);
488 if (scope != RT_SCOPE_UNIVERSE || dst.s_addr != INADDR_ANY)
491 for (list = rtnl_list; list; list = list->next) {
492 struct connman_rtnl *rtnl = list->data;
494 if (rtnl->newgateway)
495 rtnl->newgateway(index, gatewaystr);
499 static void process_delroute(unsigned char family, unsigned char scope,
500 struct rtmsg *msg, int bytes)
503 struct in_addr dst = { INADDR_ANY }, gateway = { INADDR_ANY };
504 char dststr[16], gatewaystr[16];
507 if (family != AF_INET)
510 extract_route(msg, bytes, &index, &dst, &gateway);
512 inet_ntop(family, &dst, dststr, sizeof(dststr));
513 inet_ntop(family, &gateway, gatewaystr, sizeof(gatewaystr));
515 __connman_ipconfig_delroute(index, scope, dststr, gatewaystr);
517 if (scope != RT_SCOPE_UNIVERSE || dst.s_addr != INADDR_ANY)
520 for (list = rtnl_list; list; list = list->next) {
521 struct connman_rtnl *rtnl = list->data;
523 if (rtnl->delgateway)
524 rtnl->delgateway(index, gatewaystr);
528 static inline void print_ether(struct rtattr *attr, const char *name)
530 int len = (int) RTA_PAYLOAD(attr);
532 if (len == ETH_ALEN) {
533 struct ether_addr eth;
534 memcpy(ð, RTA_DATA(attr), ETH_ALEN);
535 print(" attr %s (len %d) %s\n", name, len, ether_ntoa(ð));
537 print(" attr %s (len %d)\n", name, len);
540 static inline void print_inet(struct rtattr *attr, const char *name,
541 unsigned char family)
543 int len = (int) RTA_PAYLOAD(attr);
545 if (family == AF_INET && len == sizeof(struct in_addr)) {
547 addr = *((struct in_addr *) RTA_DATA(attr));
548 print(" attr %s (len %d) %s\n", name, len, inet_ntoa(addr));
550 print(" attr %s (len %d)\n", name, len);
553 static inline void print_string(struct rtattr *attr, const char *name)
555 print(" attr %s (len %d) %s\n", name, (int) RTA_PAYLOAD(attr),
556 (char *) RTA_DATA(attr));
559 static inline void print_byte(struct rtattr *attr, const char *name)
561 print(" attr %s (len %d) 0x%02x\n", name, (int) RTA_PAYLOAD(attr),
562 *((unsigned char *) RTA_DATA(attr)));
565 static inline void print_integer(struct rtattr *attr, const char *name)
567 print(" attr %s (len %d) %d\n", name, (int) RTA_PAYLOAD(attr),
568 *((int *) RTA_DATA(attr)));
571 static inline void print_attr(struct rtattr *attr, const char *name)
573 int len = (int) RTA_PAYLOAD(attr);
576 print(" attr %s (len %d)\n", name, len);
578 print(" attr %d (len %d)\n", attr->rta_type, len);
581 static void rtnl_link(struct nlmsghdr *hdr)
583 struct ifinfomsg *msg;
587 msg = (struct ifinfomsg *) NLMSG_DATA(hdr);
588 bytes = IFLA_PAYLOAD(hdr);
590 print("ifi_index %d ifi_flags 0x%04x", msg->ifi_index, msg->ifi_flags);
592 for (attr = IFLA_RTA(msg); RTA_OK(attr, bytes);
593 attr = RTA_NEXT(attr, bytes)) {
594 switch (attr->rta_type) {
596 print_ether(attr, "address");
599 print_ether(attr, "broadcast");
602 print_string(attr, "ifname");
605 print_integer(attr, "mtu");
608 print_attr(attr, "link");
611 print_attr(attr, "qdisc");
614 print_attr(attr, "stats");
617 print_attr(attr, "cost");
620 print_attr(attr, "priority");
623 print_attr(attr, "master");
626 print_attr(attr, "wireless");
629 print_attr(attr, "protinfo");
632 print_integer(attr, "txqlen");
635 print_attr(attr, "map");
638 print_attr(attr, "weight");
641 print_byte(attr, "operstate");
644 print_byte(attr, "linkmode");
647 print_attr(attr, NULL);
653 static void rtnl_newlink(struct nlmsghdr *hdr)
655 struct ifinfomsg *msg = (struct ifinfomsg *) NLMSG_DATA(hdr);
659 process_newlink(msg->ifi_type, msg->ifi_index, msg->ifi_flags,
660 msg->ifi_change, msg, IFA_PAYLOAD(hdr));
663 static void rtnl_dellink(struct nlmsghdr *hdr)
665 struct ifinfomsg *msg = (struct ifinfomsg *) NLMSG_DATA(hdr);
669 process_dellink(msg->ifi_type, msg->ifi_index, msg->ifi_flags,
670 msg->ifi_change, msg, IFA_PAYLOAD(hdr));
673 static void rtnl_addr(struct nlmsghdr *hdr)
675 struct ifaddrmsg *msg;
679 msg = (struct ifaddrmsg *) NLMSG_DATA(hdr);
680 bytes = IFA_PAYLOAD(hdr);
682 print("ifa_family %d ifa_index %d", msg->ifa_family, msg->ifa_index);
684 for (attr = IFA_RTA(msg); RTA_OK(attr, bytes);
685 attr = RTA_NEXT(attr, bytes)) {
686 switch (attr->rta_type) {
688 print_inet(attr, "address", msg->ifa_family);
691 print_inet(attr, "local", msg->ifa_family);
694 print_string(attr, "label");
697 print_inet(attr, "broadcast", msg->ifa_family);
700 print_attr(attr, "anycast");
703 print_attr(attr, "cacheinfo");
706 print_attr(attr, "multicast");
709 print_attr(attr, NULL);
715 static void rtnl_newaddr(struct nlmsghdr *hdr)
717 struct ifaddrmsg *msg = (struct ifaddrmsg *) NLMSG_DATA(hdr);
721 process_newaddr(msg->ifa_family, msg->ifa_prefixlen, msg->ifa_index,
722 msg, IFA_PAYLOAD(hdr));
725 static void rtnl_deladdr(struct nlmsghdr *hdr)
727 struct ifaddrmsg *msg = (struct ifaddrmsg *) NLMSG_DATA(hdr);
731 process_deladdr(msg->ifa_family, msg->ifa_prefixlen, msg->ifa_index,
732 msg, IFA_PAYLOAD(hdr));
735 static void rtnl_route(struct nlmsghdr *hdr)
741 msg = (struct rtmsg *) NLMSG_DATA(hdr);
742 bytes = RTM_PAYLOAD(hdr);
744 print("rtm_family %d rtm_table %d rtm_protocol %d",
745 msg->rtm_family, msg->rtm_table, msg->rtm_protocol);
746 print("rtm_scope %d rtm_type %d rtm_flags 0x%04x",
747 msg->rtm_scope, msg->rtm_type, msg->rtm_flags);
749 for (attr = RTM_RTA(msg); RTA_OK(attr, bytes);
750 attr = RTA_NEXT(attr, bytes)) {
751 switch (attr->rta_type) {
753 print_inet(attr, "dst", msg->rtm_family);
756 print_inet(attr, "src", msg->rtm_family);
759 print_string(attr, "iif");
762 print_integer(attr, "oif");
765 print_inet(attr, "gateway", msg->rtm_family);
768 print_attr(attr, "priority");
771 print_inet(attr, "prefsrc", msg->rtm_family);
774 print_attr(attr, "metrics");
777 print_integer(attr, "table");
780 print_attr(attr, NULL);
786 static void rtnl_newroute(struct nlmsghdr *hdr)
788 struct rtmsg *msg = (struct rtmsg *) NLMSG_DATA(hdr);
792 if (msg->rtm_table == RT_TABLE_MAIN &&
793 (msg->rtm_protocol == RTPROT_BOOT ||
794 msg->rtm_protocol == RTPROT_KERNEL) &&
795 msg->rtm_type == RTN_UNICAST)
796 process_newroute(msg->rtm_family, msg->rtm_scope,
797 msg, RTM_PAYLOAD(hdr));
800 static void rtnl_delroute(struct nlmsghdr *hdr)
802 struct rtmsg *msg = (struct rtmsg *) NLMSG_DATA(hdr);
806 if (msg->rtm_table == RT_TABLE_MAIN &&
807 (msg->rtm_protocol == RTPROT_BOOT ||
808 msg->rtm_protocol == RTPROT_KERNEL) &&
809 msg->rtm_type == RTN_UNICAST)
810 process_delroute(msg->rtm_family, msg->rtm_scope,
811 msg, RTM_PAYLOAD(hdr));
814 static const char *type2string(uint16_t type)
846 static GIOChannel *channel = NULL;
848 struct rtnl_request {
852 #define RTNL_REQUEST_SIZE (sizeof(struct nlmsghdr) + sizeof(struct rtgenmsg))
854 static GSList *request_list = NULL;
855 static guint32 request_seq = 0;
857 static struct rtnl_request *find_request(guint32 seq)
861 for (list = request_list; list; list = list->next) {
862 struct rtnl_request *req = list->data;
864 if (req->hdr.nlmsg_seq == seq)
871 static int send_request(struct rtnl_request *req)
873 struct sockaddr_nl addr;
876 DBG("%s len %d type %d flags 0x%04x seq %d",
877 type2string(req->hdr.nlmsg_type),
878 req->hdr.nlmsg_len, req->hdr.nlmsg_type,
879 req->hdr.nlmsg_flags, req->hdr.nlmsg_seq);
881 sk = g_io_channel_unix_get_fd(channel);
883 memset(&addr, 0, sizeof(addr));
884 addr.nl_family = AF_NETLINK;
886 return sendto(sk, req, req->hdr.nlmsg_len, 0,
887 (struct sockaddr *) &addr, sizeof(addr));
890 static int queue_request(struct rtnl_request *req)
892 request_list = g_slist_append(request_list, req);
894 if (g_slist_length(request_list) > 1)
897 return send_request(req);
900 static int process_response(guint32 seq)
902 struct rtnl_request *req;
906 req = find_request(seq);
908 request_list = g_slist_remove(request_list, req);
912 req = g_slist_nth_data(request_list, 0);
916 return send_request(req);
919 static void rtnl_message(void *buf, size_t len)
921 DBG("buf %p len %zd", buf, len);
924 struct nlmsghdr *hdr = buf;
925 struct nlmsgerr *err;
927 if (!NLMSG_OK(hdr, len))
930 DBG("%s len %d type %d flags 0x%04x seq %d",
931 type2string(hdr->nlmsg_type),
932 hdr->nlmsg_len, hdr->nlmsg_type,
933 hdr->nlmsg_flags, hdr->nlmsg_seq);
935 switch (hdr->nlmsg_type) {
940 process_response(hdr->nlmsg_seq);
943 err = NLMSG_DATA(hdr);
944 DBG("error %d (%s)", -err->error,
945 strerror(-err->error));
967 len -= hdr->nlmsg_len;
968 buf += hdr->nlmsg_len;
972 static gboolean netlink_event(GIOChannel *chan,
973 GIOCondition cond, gpointer data)
975 unsigned char buf[4096];
979 if (cond & (G_IO_NVAL | G_IO_HUP | G_IO_ERR))
982 memset(buf, 0, sizeof(buf));
984 err = g_io_channel_read(chan, (gchar *) buf, sizeof(buf), &len);
986 if (err == G_IO_ERROR_AGAIN)
991 rtnl_message(buf, len);
996 static int send_getlink(void)
998 struct rtnl_request *req;
1002 req = g_try_malloc0(RTNL_REQUEST_SIZE);
1006 req->hdr.nlmsg_len = RTNL_REQUEST_SIZE;
1007 req->hdr.nlmsg_type = RTM_GETLINK;
1008 req->hdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP;
1009 req->hdr.nlmsg_pid = 0;
1010 req->hdr.nlmsg_seq = request_seq++;
1011 req->msg.rtgen_family = AF_INET;
1013 return queue_request(req);
1016 static int send_getaddr(void)
1018 struct rtnl_request *req;
1022 req = g_try_malloc0(RTNL_REQUEST_SIZE);
1026 req->hdr.nlmsg_len = RTNL_REQUEST_SIZE;
1027 req->hdr.nlmsg_type = RTM_GETADDR;
1028 req->hdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP;
1029 req->hdr.nlmsg_pid = 0;
1030 req->hdr.nlmsg_seq = request_seq++;
1031 req->msg.rtgen_family = AF_INET;
1033 return queue_request(req);
1036 static int send_getroute(void)
1038 struct rtnl_request *req;
1042 req = g_try_malloc0(RTNL_REQUEST_SIZE);
1046 req->hdr.nlmsg_len = RTNL_REQUEST_SIZE;
1047 req->hdr.nlmsg_type = RTM_GETROUTE;
1048 req->hdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP;
1049 req->hdr.nlmsg_pid = 0;
1050 req->hdr.nlmsg_seq = request_seq++;
1051 req->msg.rtgen_family = AF_INET;
1053 return queue_request(req);
1056 int __connman_rtnl_request_update(void)
1058 return send_getlink();
1061 int __connman_rtnl_init(void)
1063 struct sockaddr_nl addr;
1068 sk = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE);
1072 memset(&addr, 0, sizeof(addr));
1073 addr.nl_family = AF_NETLINK;
1074 addr.nl_groups = RTMGRP_LINK | RTMGRP_IPV4_IFADDR | RTMGRP_IPV4_ROUTE;
1076 if (bind(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
1081 channel = g_io_channel_unix_new(sk);
1082 g_io_channel_set_close_on_unref(channel, TRUE);
1084 g_io_add_watch(channel, G_IO_IN | G_IO_NVAL | G_IO_HUP | G_IO_ERR,
1085 netlink_event, NULL);
1090 void __connman_rtnl_start(void)
1099 void __connman_rtnl_cleanup(void)
1105 for (list = watch_list; list; list = list->next) {
1106 struct watch_data *watch = list->data;
1108 DBG("removing watch %d", watch->id);
1114 g_slist_free(watch_list);
1117 for (list = request_list; list; list = list->next) {
1118 struct rtnl_request *req = list->data;
1120 DBG("%s len %d type %d flags 0x%04x seq %d",
1121 type2string(req->hdr.nlmsg_type),
1122 req->hdr.nlmsg_len, req->hdr.nlmsg_type,
1123 req->hdr.nlmsg_flags, req->hdr.nlmsg_seq);
1129 g_slist_free(request_list);
1130 request_list = NULL;
1132 g_io_channel_shutdown(channel, TRUE, NULL);
1133 g_io_channel_unref(channel);