]> bbs.cooldavid.org Git - net-next-2.6.git/blobdiff - net/core/rtnetlink.c
[NETLINK]: Correctly set NLM_F_MULTI without checking the pid
[net-next-2.6.git] / net / core / rtnetlink.c
index 15e968c697cce165a242b693608e221e3b0c6b66..63bd88665182c7746736ad4f55b3970d45086397 100644 (file)
@@ -22,7 +22,6 @@
 #include <linux/types.h>
 #include <linux/socket.h>
 #include <linux/kernel.h>
-#include <linux/major.h>
 #include <linux/sched.h>
 #include <linux/timer.h>
 #include <linux/string.h>
@@ -87,30 +86,35 @@ struct sock *rtnl;
 
 struct rtnetlink_link * rtnetlink_links[NPROTO];
 
-static const int rtm_min[(RTM_MAX+1-RTM_BASE)/4] =
+static const int rtm_min[RTM_NR_FAMILIES] =
 {
-       NLMSG_LENGTH(sizeof(struct ifinfomsg)),
-       NLMSG_LENGTH(sizeof(struct ifaddrmsg)),
-       NLMSG_LENGTH(sizeof(struct rtmsg)),
-       NLMSG_LENGTH(sizeof(struct ndmsg)),
-       NLMSG_LENGTH(sizeof(struct rtmsg)),
-       NLMSG_LENGTH(sizeof(struct tcmsg)),
-       NLMSG_LENGTH(sizeof(struct tcmsg)),
-       NLMSG_LENGTH(sizeof(struct tcmsg)),
-       NLMSG_LENGTH(sizeof(struct tcamsg))
+       [RTM_FAM(RTM_NEWLINK)]      = NLMSG_LENGTH(sizeof(struct ifinfomsg)),
+       [RTM_FAM(RTM_NEWADDR)]      = NLMSG_LENGTH(sizeof(struct ifaddrmsg)),
+       [RTM_FAM(RTM_NEWROUTE)]     = NLMSG_LENGTH(sizeof(struct rtmsg)),
+       [RTM_FAM(RTM_NEWNEIGH)]     = NLMSG_LENGTH(sizeof(struct ndmsg)),
+       [RTM_FAM(RTM_NEWRULE)]      = NLMSG_LENGTH(sizeof(struct rtmsg)),
+       [RTM_FAM(RTM_NEWQDISC)]     = NLMSG_LENGTH(sizeof(struct tcmsg)),
+       [RTM_FAM(RTM_NEWTCLASS)]    = NLMSG_LENGTH(sizeof(struct tcmsg)),
+       [RTM_FAM(RTM_NEWTFILTER)]   = NLMSG_LENGTH(sizeof(struct tcmsg)),
+       [RTM_FAM(RTM_NEWACTION)]    = NLMSG_LENGTH(sizeof(struct tcamsg)),
+       [RTM_FAM(RTM_NEWPREFIX)]    = NLMSG_LENGTH(sizeof(struct rtgenmsg)),
+       [RTM_FAM(RTM_GETMULTICAST)] = NLMSG_LENGTH(sizeof(struct rtgenmsg)),
+       [RTM_FAM(RTM_GETANYCAST)]   = NLMSG_LENGTH(sizeof(struct rtgenmsg)),
+       [RTM_FAM(RTM_NEWNEIGHTBL)]  = NLMSG_LENGTH(sizeof(struct ndtmsg)),
 };
 
-static const int rta_max[(RTM_MAX+1-RTM_BASE)/4] =
+static const int rta_max[RTM_NR_FAMILIES] =
 {
-       IFLA_MAX,
-       IFA_MAX,
-       RTA_MAX,
-       NDA_MAX,
-       RTA_MAX,
-       TCA_MAX,
-       TCA_MAX,
-       TCA_MAX,
-       TCAA_MAX
+       [RTM_FAM(RTM_NEWLINK)]      = IFLA_MAX,
+       [RTM_FAM(RTM_NEWADDR)]      = IFA_MAX,
+       [RTM_FAM(RTM_NEWROUTE)]     = RTA_MAX,
+       [RTM_FAM(RTM_NEWNEIGH)]     = NDA_MAX,
+       [RTM_FAM(RTM_NEWRULE)]      = RTA_MAX,
+       [RTM_FAM(RTM_NEWQDISC)]     = TCA_MAX,
+       [RTM_FAM(RTM_NEWTCLASS)]    = TCA_MAX,
+       [RTM_FAM(RTM_NEWTFILTER)]   = TCA_MAX,
+       [RTM_FAM(RTM_NEWACTION)]    = TCAA_MAX,
+       [RTM_FAM(RTM_NEWNEIGHTBL)]  = NDTA_MAX,
 };
 
 void __rta_fill(struct sk_buff *skb, int attrtype, int attrlen, const void *data)
@@ -174,14 +178,14 @@ rtattr_failure:
 
 
 static int rtnetlink_fill_ifinfo(struct sk_buff *skb, struct net_device *dev,
-                                int type, u32 pid, u32 seq, u32 change)
+                                int type, u32 pid, u32 seq, u32 change, 
+                                unsigned int flags)
 {
        struct ifinfomsg *r;
        struct nlmsghdr  *nlh;
        unsigned char    *b = skb->tail;
 
-       nlh = NLMSG_PUT(skb, pid, seq, type, sizeof(*r));
-       if (pid) nlh->nlmsg_flags |= NLM_F_MULTI;
+       nlh = NLMSG_NEW(skb, pid, seq, type, sizeof(*r), flags);
        r = NLMSG_DATA(nlh);
        r->ifi_family = AF_UNSPEC;
        r->ifi_type = dev->type;
@@ -271,7 +275,10 @@ static int rtnetlink_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *c
        for (dev=dev_base, idx=0; dev; dev = dev->next, idx++) {
                if (idx < s_idx)
                        continue;
-               if (rtnetlink_fill_ifinfo(skb, dev, RTM_NEWLINK, NETLINK_CB(cb->skb).pid, cb->nlh->nlmsg_seq, 0) <= 0)
+               if (rtnetlink_fill_ifinfo(skb, dev, RTM_NEWLINK,
+                                         NETLINK_CB(cb->skb).pid,
+                                         cb->nlh->nlmsg_seq, 0,
+                                         NLM_F_MULTI) <= 0)
                        break;
        }
        read_unlock(&dev_base_lock);
@@ -445,7 +452,7 @@ void rtmsg_ifinfo(int type, struct net_device *dev, unsigned change)
        if (!skb)
                return;
 
-       if (rtnetlink_fill_ifinfo(skb, dev, type, 0, 0, change) < 0) {
+       if (rtnetlink_fill_ifinfo(skb, dev, type, 0, 0, change, 0) < 0) {
                kfree_skb(skb);
                return;
        }
@@ -607,27 +614,33 @@ static inline int rtnetlink_rcv_skb(struct sk_buff *skb)
 
 /*
  *  rtnetlink input queue processing routine:
- *     - try to acquire shared lock. If it is failed, defer processing.
+ *     - process as much as there was in the queue upon entry.
  *     - feed skbs to rtnetlink_rcv_skb, until it refuse a message,
- *       that will occur, when a dump started and/or acquisition of
- *       exclusive lock failed.
+ *       that will occur, when a dump started.
  */
 
 static void rtnetlink_rcv(struct sock *sk, int len)
 {
+       unsigned int qlen = skb_queue_len(&sk->sk_receive_queue);
+
        do {
                struct sk_buff *skb;
 
-               if (rtnl_shlock_nowait())
-                       return;
+               rtnl_lock();
+
+               if (qlen > skb_queue_len(&sk->sk_receive_queue))
+                       qlen = skb_queue_len(&sk->sk_receive_queue);
 
-               while ((skb = skb_dequeue(&sk->sk_receive_queue)) != NULL) {
+               for (; qlen; qlen--) {
+                       skb = skb_dequeue(&sk->sk_receive_queue);
                        if (rtnetlink_rcv_skb(skb)) {
                                if (skb->len)
                                        skb_queue_head(&sk->sk_receive_queue,
                                                       skb);
-                               else
+                               else {
                                        kfree_skb(skb);
+                                       qlen--;
+                               }
                                break;
                        }
                        kfree_skb(skb);
@@ -636,19 +649,21 @@ static void rtnetlink_rcv(struct sock *sk, int len)
                up(&rtnl_sem);
 
                netdev_run_todo();
-       } while (rtnl && rtnl->sk_receive_queue.qlen);
+       } while (qlen);
 }
 
-static struct rtnetlink_link link_rtnetlink_table[RTM_MAX-RTM_BASE+1] =
+static struct rtnetlink_link link_rtnetlink_table[RTM_NR_MSGTYPES] =
 {
-       [RTM_GETLINK  - RTM_BASE] = { .dumpit = rtnetlink_dump_ifinfo },
-       [RTM_SETLINK  - RTM_BASE] = { .doit   = do_setlink            },
-       [RTM_GETADDR  - RTM_BASE] = { .dumpit = rtnetlink_dump_all    },
-       [RTM_GETROUTE - RTM_BASE] = { .dumpit = rtnetlink_dump_all    },
-       [RTM_NEWNEIGH - RTM_BASE] = { .doit   = neigh_add             },
-       [RTM_DELNEIGH - RTM_BASE] = { .doit   = neigh_delete          },
-       [RTM_GETNEIGH - RTM_BASE] = { .dumpit = neigh_dump_info       },
-       [RTM_GETRULE  - RTM_BASE] = { .dumpit = rtnetlink_dump_all    }
+       [RTM_GETLINK     - RTM_BASE] = { .dumpit = rtnetlink_dump_ifinfo },
+       [RTM_SETLINK     - RTM_BASE] = { .doit   = do_setlink            },
+       [RTM_GETADDR     - RTM_BASE] = { .dumpit = rtnetlink_dump_all    },
+       [RTM_GETROUTE    - RTM_BASE] = { .dumpit = rtnetlink_dump_all    },
+       [RTM_NEWNEIGH    - RTM_BASE] = { .doit   = neigh_add             },
+       [RTM_DELNEIGH    - RTM_BASE] = { .doit   = neigh_delete          },
+       [RTM_GETNEIGH    - RTM_BASE] = { .dumpit = neigh_dump_info       },
+       [RTM_GETRULE     - RTM_BASE] = { .dumpit = rtnetlink_dump_all    },
+       [RTM_GETNEIGHTBL - RTM_BASE] = { .dumpit = neightbl_dump_info    },
+       [RTM_SETNEIGHTBL - RTM_BASE] = { .doit   = neightbl_set          },
 };
 
 static int rtnetlink_event(struct notifier_block *this, unsigned long event, void *ptr)