Imported Upstream version 1.42
[platform/upstream/connman.git] / src / rtnl.c
index c9e84da..e8a8325 100644 (file)
@@ -886,7 +886,7 @@ static inline void print_attr(struct rtattr *attr, const char *name)
                print("  attr %d (len %d)\n", attr->rta_type, len);
 }
 
-static void rtnl_link(struct nlmsghdr *hdr)
+static void rtnl_link(struct nlmsghdr *hdr, bool *has_master)
 {
        struct ifinfomsg *msg;
        struct rtattr *attr;
@@ -928,6 +928,7 @@ static void rtnl_link(struct nlmsghdr *hdr)
                        print_attr(attr, "priority");
                        break;
                case IFLA_MASTER:
+                       *has_master = true;
                        print_attr(attr, "master");
                        break;
                case IFLA_WIRELESS:
@@ -960,22 +961,32 @@ static void rtnl_link(struct nlmsghdr *hdr)
 
 static void rtnl_newlink(struct nlmsghdr *hdr)
 {
+       bool has_master = false;
        struct ifinfomsg *msg = (struct ifinfomsg *) NLMSG_DATA(hdr);
 
-       rtnl_link(hdr);
+       rtnl_link(hdr, &has_master);
 
        if (hdr->nlmsg_type == IFLA_WIRELESS)
                connman_warn_once("Obsolete WEXT WiFi driver detected");
 
+       /* ignore RTM_NEWLINK when adding interface to bridge */
+       if (has_master)
+               return;
+
        process_newlink(msg->ifi_type, msg->ifi_index, msg->ifi_flags,
                                msg->ifi_change, msg, IFA_PAYLOAD(hdr));
 }
 
 static void rtnl_dellink(struct nlmsghdr *hdr)
 {
+       bool has_master = false;
        struct ifinfomsg *msg = (struct ifinfomsg *) NLMSG_DATA(hdr);
 
-       rtnl_link(hdr);
+       rtnl_link(hdr, &has_master);
+
+       /* ignore RTM_DELLINK when removing interface from bridge */
+       if (has_master)
+               return;
 
        process_dellink(msg->ifi_type, msg->ifi_index, msg->ifi_flags,
                                msg->ifi_change, msg, IFA_PAYLOAD(hdr));
@@ -1308,75 +1319,71 @@ static const char *type2string(uint16_t type)
 static GIOChannel *channel = NULL;
 static guint channel_watch = 0;
 
-struct rtnl_request {
-       struct nlmsghdr hdr;
-       struct rtgenmsg msg;
-};
-#define RTNL_REQUEST_SIZE  (sizeof(struct nlmsghdr) + sizeof(struct rtgenmsg))
+#define RTNL_REQUEST_SIZE (NLMSG_HDRLEN + NLMSG_ALIGN(sizeof(struct rtgenmsg)))
 
 static GSList *request_list = NULL;
 static guint32 request_seq = 0;
 
-static struct rtnl_request *find_request(guint32 seq)
+static struct nlmsghdr *find_request(guint32 seq)
 {
        GSList *list;
 
        for (list = request_list; list; list = list->next) {
-               struct rtnl_request *req = list->data;
+               struct nlmsghdr *hdr = list->data;
 
-               if (req->hdr.nlmsg_seq == seq)
-                       return req;
+               if (hdr->nlmsg_seq == seq)
+                       return hdr;
        }
 
        return NULL;
 }
 
-static int send_request(struct rtnl_request *req)
+static int send_request(struct nlmsghdr *hdr)
 {
        struct sockaddr_nl addr;
        int sk;
 
        DBG("%s len %d type %d flags 0x%04x seq %d",
-                               type2string(req->hdr.nlmsg_type),
-                               req->hdr.nlmsg_len, req->hdr.nlmsg_type,
-                               req->hdr.nlmsg_flags, req->hdr.nlmsg_seq);
+                               type2string(hdr->nlmsg_type),
+                               hdr->nlmsg_len, hdr->nlmsg_type,
+                               hdr->nlmsg_flags, hdr->nlmsg_seq);
 
        sk = g_io_channel_unix_get_fd(channel);
 
        memset(&addr, 0, sizeof(addr));
        addr.nl_family = AF_NETLINK;
 
-       return sendto(sk, req, req->hdr.nlmsg_len, 0,
+       return sendto(sk, hdr, hdr->nlmsg_len, 0,
                                (struct sockaddr *) &addr, sizeof(addr));
 }
 
-static int queue_request(struct rtnl_request *req)
+static int queue_request(struct nlmsghdr *hdr)
 {
-       request_list = g_slist_append(request_list, req);
+       request_list = g_slist_append(request_list, hdr);
 
        if (g_slist_length(request_list) > 1)
                return 0;
 
-       return send_request(req);
+       return send_request(hdr);
 }
 
 static int process_response(guint32 seq)
 {
-       struct rtnl_request *req;
+       struct nlmsghdr *hdr;
 
        DBG("seq %d", seq);
 
-       req = find_request(seq);
-       if (req) {
-               request_list = g_slist_remove(request_list, req);
-               g_free(req);
+       hdr = find_request(seq);
+       if (hdr) {
+               request_list = g_slist_remove(request_list, hdr);
+               g_free(hdr);
        }
 
-       req = g_slist_nth_data(request_list, 0);
-       if (!req)
+       hdr = g_slist_nth_data(request_list, 0);
+       if (!hdr)
                return 0;
 
-       return send_request(req);
+       return send_request(hdr);
 }
 
 static void rtnl_message(void *buf, size_t len)
@@ -1474,62 +1481,65 @@ static gboolean netlink_event(GIOChannel *chan, GIOCondition cond, gpointer data
 
 static int send_getlink(void)
 {
-       struct rtnl_request *req;
+       struct nlmsghdr *hdr;
+       struct rtgenmsg *msg;
 
        DBG("");
 
-       req = g_try_malloc0(RTNL_REQUEST_SIZE);
-       if (!req)
-               return -ENOMEM;
+       hdr = g_malloc0(RTNL_REQUEST_SIZE);
+
+       hdr->nlmsg_len = RTNL_REQUEST_SIZE;
+       hdr->nlmsg_type = RTM_GETLINK;
+       hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP;
+       hdr->nlmsg_pid = 0;
+       hdr->nlmsg_seq = request_seq++;
 
-       req->hdr.nlmsg_len = RTNL_REQUEST_SIZE;
-       req->hdr.nlmsg_type = RTM_GETLINK;
-       req->hdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP;
-       req->hdr.nlmsg_pid = 0;
-       req->hdr.nlmsg_seq = request_seq++;
-       req->msg.rtgen_family = AF_INET;
+       msg = (struct rtgenmsg *) NLMSG_DATA(hdr);
+       msg->rtgen_family = AF_INET;
 
-       return queue_request(req);
+       return queue_request(hdr);
 }
 
 static int send_getaddr(void)
 {
-       struct rtnl_request *req;
+       struct nlmsghdr *hdr;
+       struct rtgenmsg *msg;
 
        DBG("");
 
-       req = g_try_malloc0(RTNL_REQUEST_SIZE);
-       if (!req)
-               return -ENOMEM;
+       hdr = g_malloc0(RTNL_REQUEST_SIZE);
 
-       req->hdr.nlmsg_len = RTNL_REQUEST_SIZE;
-       req->hdr.nlmsg_type = RTM_GETADDR;
-       req->hdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP;
-       req->hdr.nlmsg_pid = 0;
-       req->hdr.nlmsg_seq = request_seq++;
-       req->msg.rtgen_family = AF_INET;
+       hdr->nlmsg_len = RTNL_REQUEST_SIZE;
+       hdr->nlmsg_type = RTM_GETADDR;
+       hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP;
+       hdr->nlmsg_pid = 0;
+       hdr->nlmsg_seq = request_seq++;
 
-       return queue_request(req);
+       msg = (struct rtgenmsg *) NLMSG_DATA(hdr);
+       msg->rtgen_family = AF_INET;
+
+       return queue_request(hdr);
 }
 
 static int send_getroute(void)
 {
-       struct rtnl_request *req;
+       struct nlmsghdr *hdr;
+       struct rtgenmsg *msg;
 
        DBG("");
 
-       req = g_try_malloc0(RTNL_REQUEST_SIZE);
-       if (!req)
-               return -ENOMEM;
+       hdr = g_malloc0(RTNL_REQUEST_SIZE);
+
+       hdr->nlmsg_len = RTNL_REQUEST_SIZE;
+       hdr->nlmsg_type = RTM_GETROUTE;
+       hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP;
+       hdr->nlmsg_pid = 0;
+       hdr->nlmsg_seq = request_seq++;
 
-       req->hdr.nlmsg_len = RTNL_REQUEST_SIZE;
-       req->hdr.nlmsg_type = RTM_GETROUTE;
-       req->hdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP;
-       req->hdr.nlmsg_pid = 0;
-       req->hdr.nlmsg_seq = request_seq++;
-       req->msg.rtgen_family = AF_INET;
+       msg = (struct rtgenmsg *) NLMSG_DATA(hdr);
+       msg->rtgen_family = AF_INET;
 
-       return queue_request(req);
+       return queue_request(hdr);
 }
 
 static gboolean update_timeout_cb(gpointer user_data)
@@ -1673,14 +1683,14 @@ void __connman_rtnl_cleanup(void)
        update_list = NULL;
 
        for (list = request_list; list; list = list->next) {
-               struct rtnl_request *req = list->data;
+               struct nlmsghdr *hdr= list->data;
 
                DBG("%s len %d type %d flags 0x%04x seq %d",
-                               type2string(req->hdr.nlmsg_type),
-                               req->hdr.nlmsg_len, req->hdr.nlmsg_type,
-                               req->hdr.nlmsg_flags, req->hdr.nlmsg_seq);
+                               type2string(hdr->nlmsg_type),
+                               hdr->nlmsg_len, hdr->nlmsg_type,
+                               hdr->nlmsg_flags, hdr->nlmsg_seq);
 
-               g_free(req);
+               g_free(hdr);
                list->data = NULL;
        }