net: ipv4: fix RCU races on dst refcounts
[platform/adaptation/renesas_rcar/renesas_kernel.git] / net / decnet / dn_table.c
index 650f338..16c986a 100644 (file)
@@ -297,61 +297,75 @@ static int dn_fib_dump_info(struct sk_buff *skb, u32 pid, u32 seq, int event,
 {
        struct rtmsg *rtm;
        struct nlmsghdr *nlh;
-       unsigned char *b = skb_tail_pointer(skb);
 
-       nlh = NLMSG_NEW(skb, pid, seq, event, sizeof(*rtm), flags);
-       rtm = NLMSG_DATA(nlh);
+       nlh = nlmsg_put(skb, pid, seq, event, sizeof(*rtm), flags);
+       if (!nlh)
+               return -EMSGSIZE;
+
+       rtm = nlmsg_data(nlh);
        rtm->rtm_family = AF_DECnet;
        rtm->rtm_dst_len = dst_len;
        rtm->rtm_src_len = 0;
        rtm->rtm_tos = 0;
        rtm->rtm_table = tb_id;
-       RTA_PUT_U32(skb, RTA_TABLE, tb_id);
        rtm->rtm_flags = fi->fib_flags;
        rtm->rtm_scope = scope;
        rtm->rtm_type  = type;
-       if (rtm->rtm_dst_len)
-               RTA_PUT(skb, RTA_DST, 2, dst);
        rtm->rtm_protocol = fi->fib_protocol;
-       if (fi->fib_priority)
-               RTA_PUT(skb, RTA_PRIORITY, 4, &fi->fib_priority);
+
+       if (nla_put_u32(skb, RTA_TABLE, tb_id) < 0)
+               goto errout;
+
+       if (rtm->rtm_dst_len &&
+           nla_put(skb, RTA_DST, 2, dst) < 0)
+               goto errout;
+
+       if (fi->fib_priority &&
+           nla_put_u32(skb, RTA_PRIORITY, fi->fib_priority) < 0)
+               goto errout;
+
        if (rtnetlink_put_metrics(skb, fi->fib_metrics) < 0)
-               goto rtattr_failure;
+               goto errout;
+
        if (fi->fib_nhs == 1) {
-               if (fi->fib_nh->nh_gw)
-                       RTA_PUT(skb, RTA_GATEWAY, 2, &fi->fib_nh->nh_gw);
-               if (fi->fib_nh->nh_oif)
-                       RTA_PUT(skb, RTA_OIF, sizeof(int), &fi->fib_nh->nh_oif);
+               if (fi->fib_nh->nh_gw &&
+                   nla_put_le16(skb, RTA_GATEWAY, fi->fib_nh->nh_gw) < 0)
+                       goto errout;
+
+               if (fi->fib_nh->nh_oif &&
+                   nla_put_u32(skb, RTA_OIF, fi->fib_nh->nh_oif) < 0)
+                       goto errout;
        }
+
        if (fi->fib_nhs > 1) {
                struct rtnexthop *nhp;
-               struct rtattr *mp_head;
-               if (skb_tailroom(skb) <= RTA_SPACE(0))
-                       goto rtattr_failure;
-               mp_head = (struct rtattr *)skb_put(skb, RTA_SPACE(0));
+               struct nlattr *mp_head;
+
+               if (!(mp_head = nla_nest_start(skb, RTA_MULTIPATH)))
+                       goto errout;
 
                for_nexthops(fi) {
-                       if (skb_tailroom(skb) < RTA_ALIGN(RTA_ALIGN(sizeof(*nhp)) + 4))
-                               goto rtattr_failure;
-                       nhp = (struct rtnexthop *)skb_put(skb, RTA_ALIGN(sizeof(*nhp)));
+                       if (!(nhp = nla_reserve_nohdr(skb, sizeof(*nhp))))
+                               goto errout;
+
                        nhp->rtnh_flags = nh->nh_flags & 0xFF;
                        nhp->rtnh_hops = nh->nh_weight - 1;
                        nhp->rtnh_ifindex = nh->nh_oif;
-                       if (nh->nh_gw)
-                               RTA_PUT(skb, RTA_GATEWAY, 2, &nh->nh_gw);
+
+                       if (nh->nh_gw &&
+                           nla_put_le16(skb, RTA_GATEWAY, nh->nh_gw) < 0)
+                               goto errout;
+
                        nhp->rtnh_len = skb_tail_pointer(skb) - (unsigned char *)nhp;
                } endfor_nexthops(fi);
-               mp_head->rta_type = RTA_MULTIPATH;
-               mp_head->rta_len = skb_tail_pointer(skb) - (u8 *)mp_head;
-       }
 
-       nlh->nlmsg_len = skb_tail_pointer(skb) - b;
-       return skb->len;
+               nla_nest_end(skb, mp_head);
+       }
 
+       return nlmsg_end(skb, nlh);
 
-nlmsg_failure:
-rtattr_failure:
-       nlmsg_trim(skb, b);
+errout:
+       nlmsg_cancel(skb, nlh);
        return -EMSGSIZE;
 }
 
@@ -476,7 +490,7 @@ int dn_fib_dump(struct sk_buff *skb, struct netlink_callback *cb)
                return 0;
 
        if (NLMSG_PAYLOAD(cb->nlh, 0) >= sizeof(struct rtmsg) &&
-               ((struct rtmsg *)NLMSG_DATA(cb->nlh))->rtm_flags&RTM_F_CLONED)
+               ((struct rtmsg *)nlmsg_data(cb->nlh))->rtm_flags&RTM_F_CLONED)
                        return dn_cache_dump(skb, cb);
 
        s_h = cb->args[0];