]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - net/core/rtnetlink.c
Merge branch 'HEAD' of master.kernel.org:/pub/scm/linux/kernel/git/herbert/crypto-2.6
[linux-2.6-omap-h63xx.git] / net / core / rtnetlink.c
index f5300b5dd0fdc8339737159b390a80790ebcfdc6..9bf9ae05f1571ed5a474b06749cbdb8b743a4d4d 100644 (file)
@@ -58,6 +58,7 @@
 #endif /* CONFIG_NET_WIRELESS_RTNETLINK */
 
 static DEFINE_MUTEX(rtnl_mutex);
+static struct sock *rtnl;
 
 void rtnl_lock(void)
 {
@@ -95,8 +96,6 @@ int rtattr_parse(struct rtattr *tb[], int maxattr, struct rtattr *rta, int len)
        return 0;
 }
 
-struct sock *rtnl;
-
 struct rtnetlink_link * rtnetlink_links[NPROTO];
 
 static const int rtm_min[RTM_NR_FAMILIES] =
@@ -109,7 +108,6 @@ static const int rtm_min[RTM_NR_FAMILIES] =
        [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)),
 };
@@ -189,24 +187,51 @@ void rtnl_set_sk_err(u32 group, int error)
 
 int rtnetlink_put_metrics(struct sk_buff *skb, u32 *metrics)
 {
-       struct rtattr *mx = (struct rtattr*)skb->tail;
-       int i;
+       struct nlattr *mx;
+       int i, valid = 0;
+
+       mx = nla_nest_start(skb, RTA_METRICS);
+       if (mx == NULL)
+               return -ENOBUFS;
 
-       RTA_PUT(skb, RTA_METRICS, 0, NULL);
-       for (i=0; i<RTAX_MAX; i++) {
-               if (metrics[i])
-                       RTA_PUT(skb, i+1, sizeof(u32), metrics+i);
+       for (i = 0; i < RTAX_MAX; i++) {
+               if (metrics[i]) {
+                       valid++;
+                       NLA_PUT_U32(skb, i+1, metrics[i]);
+               }
        }
-       mx->rta_len = skb->tail - (u8*)mx;
-       if (mx->rta_len == RTA_LENGTH(0))
-               skb_trim(skb, (u8*)mx - skb->data);
-       return 0;
 
-rtattr_failure:
-       skb_trim(skb, (u8*)mx - skb->data);
-       return -1;
+       if (!valid) {
+               nla_nest_cancel(skb, mx);
+               return 0;
+       }
+
+       return nla_nest_end(skb, mx);
+
+nla_put_failure:
+       return nla_nest_cancel(skb, mx);
+}
+
+int rtnl_put_cacheinfo(struct sk_buff *skb, struct dst_entry *dst, u32 id,
+                      u32 ts, u32 tsage, long expires, u32 error)
+{
+       struct rta_cacheinfo ci = {
+               .rta_lastuse = jiffies_to_clock_t(jiffies - dst->lastuse),
+               .rta_used = dst->__use,
+               .rta_clntref = atomic_read(&(dst->__refcnt)),
+               .rta_error = error,
+               .rta_id =  id,
+               .rta_ts = ts,
+               .rta_tsage = tsage,
+       };
+
+       if (expires)
+               ci.rta_expires = jiffies_to_clock_t(expires);
+
+       return nla_put(skb, RTA_CACHEINFO, sizeof(ci), &ci);
 }
 
+EXPORT_SYMBOL_GPL(rtnl_put_cacheinfo);
 
 static void set_operstate(struct net_device *dev, unsigned char transition)
 {
@@ -267,6 +292,25 @@ static void copy_rtnl_link_stats(struct rtnl_link_stats *a,
        a->tx_compressed = b->tx_compressed;
 };
 
+static inline size_t if_nlmsg_size(int iwbuflen)
+{
+       return NLMSG_ALIGN(sizeof(struct ifinfomsg))
+              + nla_total_size(IFNAMSIZ) /* IFLA_IFNAME */
+              + nla_total_size(IFNAMSIZ) /* IFLA_QDISC */
+              + nla_total_size(sizeof(struct rtnl_link_ifmap))
+              + nla_total_size(sizeof(struct rtnl_link_stats))
+              + nla_total_size(MAX_ADDR_LEN) /* IFLA_ADDRESS */
+              + nla_total_size(MAX_ADDR_LEN) /* IFLA_BROADCAST */
+              + nla_total_size(4) /* IFLA_TXQLEN */
+              + nla_total_size(4) /* IFLA_WEIGHT */
+              + nla_total_size(4) /* IFLA_MTU */
+              + nla_total_size(4) /* IFLA_LINK */
+              + nla_total_size(4) /* IFLA_MASTER */
+              + nla_total_size(1) /* IFLA_OPERSTATE */
+              + nla_total_size(1) /* IFLA_LINKMODE */
+              + nla_total_size(iwbuflen);
+}
+
 static int rtnl_fill_ifinfo(struct sk_buff *skb, struct net_device *dev,
                            void *iwbuf, int iwbuflen, int type, u32 pid,
                            u32 seq, u32 change, unsigned int flags)
@@ -276,7 +320,7 @@ static int rtnl_fill_ifinfo(struct sk_buff *skb, struct net_device *dev,
 
        nlh = nlmsg_put(skb, pid, seq, type, sizeof(*ifm), flags);
        if (nlh == NULL)
-               return -ENOBUFS;
+               return -EMSGSIZE;
 
        ifm = nlmsg_data(nlh);
        ifm->ifi_family = AF_UNSPEC;
@@ -340,7 +384,8 @@ static int rtnl_fill_ifinfo(struct sk_buff *skb, struct net_device *dev,
        return nlmsg_end(skb, nlh);
 
 nla_put_failure:
-       return nlmsg_cancel(skb, nlh);
+       nlmsg_cancel(skb, nlh);
+       return -EMSGSIZE;
 }
 
 static int rtnl_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb)
@@ -365,8 +410,8 @@ static int rtnl_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb)
 }
 
 static struct nla_policy ifla_policy[IFLA_MAX+1] __read_mostly = {
-       [IFLA_IFNAME]           = { .type = NLA_STRING },
-       [IFLA_MAP]              = { .minlen = sizeof(struct rtnl_link_ifmap) },
+       [IFLA_IFNAME]           = { .type = NLA_STRING, .len = IFNAMSIZ-1 },
+       [IFLA_MAP]              = { .len = sizeof(struct rtnl_link_ifmap) },
        [IFLA_MTU]              = { .type = NLA_U32 },
        [IFLA_TXQLEN]           = { .type = NLA_U32 },
        [IFLA_WEIGHT]           = { .type = NLA_U32 },
@@ -386,9 +431,10 @@ static int rtnl_setlink(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
        if (err < 0)
                goto errout;
 
-       if (tb[IFLA_IFNAME] &&
-           nla_strlcpy(ifname, tb[IFLA_IFNAME], IFNAMSIZ) >= IFNAMSIZ)
-               return -EINVAL;
+       if (tb[IFLA_IFNAME])
+               nla_strlcpy(ifname, tb[IFLA_IFNAME], IFNAMSIZ);
+       else
+               ifname[0] = '\0';
 
        err = -EINVAL;
        ifm = nlmsg_data(nlh);
@@ -551,11 +597,11 @@ static int rtnl_getlink(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg)
        struct sk_buff *nskb;
        char *iw_buf = NULL, *iw = NULL;
        int iw_buf_len = 0;
-       int err, payload;
+       int err;
 
        err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFLA_MAX, ifla_policy);
        if (err < 0)
-               goto errout;
+               return err;
 
        ifm = nlmsg_data(nlh);
        if (ifm->ifi_index >= 0) {
@@ -580,9 +626,7 @@ static int rtnl_getlink(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg)
        }
 #endif /* CONFIG_NET_WIRELESS_RTNETLINK */
 
-       payload = NLMSG_ALIGN(sizeof(struct ifinfomsg) +
-                             nla_total_size(iw_buf_len));
-       nskb = nlmsg_new(nlmsg_total_size(payload), GFP_KERNEL);
+       nskb = nlmsg_new(if_nlmsg_size(iw_buf_len), GFP_KERNEL);
        if (nskb == NULL) {
                err = -ENOBUFS;
                goto errout;
@@ -590,12 +634,13 @@ static int rtnl_getlink(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg)
 
        err = rtnl_fill_ifinfo(nskb, dev, iw, iw_buf_len, RTM_NEWLINK,
                               NETLINK_CB(skb).pid, nlh->nlmsg_seq, 0, 0);
-       if (err <= 0) {
-               kfree_skb(skb);
+       if (err < 0) {
+               /* -EMSGSIZE implies BUG in if_nlmsg_size */
+               WARN_ON(err == -EMSGSIZE);
+               kfree_skb(nskb);
                goto errout;
        }
-
-       err = rtnl_unicast(skb, NETLINK_CB(skb).pid);
+       err = rtnl_unicast(nskb, NETLINK_CB(skb).pid);
 errout:
        kfree(iw_buf);
        dev_put(dev);
@@ -632,16 +677,17 @@ void rtmsg_ifinfo(int type, struct net_device *dev, unsigned change)
        struct sk_buff *skb;
        int err = -ENOBUFS;
 
-       skb = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
+       skb = nlmsg_new(if_nlmsg_size(0), GFP_KERNEL);
        if (skb == NULL)
                goto errout;
 
        err = rtnl_fill_ifinfo(skb, dev, NULL, 0, type, 0, 0, change, 0);
        if (err < 0) {
+               /* -EMSGSIZE implies BUG in if_nlmsg_size() */
+               WARN_ON(err == -EMSGSIZE);
                kfree_skb(skb);
                goto errout;
        }
-
        err = rtnl_notify(skb, 0, RTNLGRP_LINK, NULL, GFP_KERNEL);
 errout:
        if (err < 0)
@@ -842,7 +888,6 @@ EXPORT_SYMBOL(rtattr_strlcpy);
 EXPORT_SYMBOL(rtattr_parse);
 EXPORT_SYMBOL(rtnetlink_links);
 EXPORT_SYMBOL(rtnetlink_put_metrics);
-EXPORT_SYMBOL(rtnl);
 EXPORT_SYMBOL(rtnl_lock);
 EXPORT_SYMBOL(rtnl_trylock);
 EXPORT_SYMBOL(rtnl_unlock);