Merge tag 'sound-3.6' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound
[firefly-linux-kernel-4.4.55.git] / net / ipv4 / ipmr.c
index c94bbc6f2ba331bb9e261692151f55f78277258b..ebdf06f938bf040eebc91763c3e952c63d00f92b 100644 (file)
@@ -124,6 +124,8 @@ static DEFINE_SPINLOCK(mfc_unres_lock);
 static struct kmem_cache *mrt_cachep __read_mostly;
 
 static struct mr_table *ipmr_new_table(struct net *net, u32 id);
+static void ipmr_free_table(struct mr_table *mrt);
+
 static int ip_mr_forward(struct net *net, struct mr_table *mrt,
                         struct sk_buff *skb, struct mfc_cache *cache,
                         int local);
@@ -131,6 +133,7 @@ static int ipmr_cache_report(struct mr_table *mrt,
                             struct sk_buff *pkt, vifi_t vifi, int assert);
 static int __ipmr_fill_mroute(struct mr_table *mrt, struct sk_buff *skb,
                              struct mfc_cache *c, struct rtmsg *rtm);
+static void mroute_clean_tables(struct mr_table *mrt);
 static void ipmr_expire_process(unsigned long arg);
 
 #ifdef CONFIG_IP_MROUTE_MULTIPLE_TABLES
@@ -271,7 +274,7 @@ static void __net_exit ipmr_rules_exit(struct net *net)
 
        list_for_each_entry_safe(mrt, next, &net->ipv4.mr_tables, list) {
                list_del(&mrt->list);
-               kfree(mrt);
+               ipmr_free_table(mrt);
        }
        fib_rules_unregister(net->ipv4.mr_rules_ops);
 }
@@ -299,7 +302,7 @@ static int __net_init ipmr_rules_init(struct net *net)
 
 static void __net_exit ipmr_rules_exit(struct net *net)
 {
-       kfree(net->ipv4.mrt);
+       ipmr_free_table(net->ipv4.mrt);
 }
 #endif
 
@@ -336,6 +339,13 @@ static struct mr_table *ipmr_new_table(struct net *net, u32 id)
        return mrt;
 }
 
+static void ipmr_free_table(struct mr_table *mrt)
+{
+       del_timer_sync(&mrt->ipmr_expire_timer);
+       mroute_clean_tables(mrt);
+       kfree(mrt);
+}
+
 /* Service routines creating virtual interfaces: DVMRP tunnels and PIMREG */
 
 static void ipmr_del_tunnel(struct net_device *dev, struct vifctl *v)
@@ -524,8 +534,8 @@ failure:
 }
 #endif
 
-/*
- *     Delete a VIF entry
+/**
+ *     vif_delete - Delete a VIF entry
  *     @notify: Set to 1, if the caller is a notifier_call
  */
 
@@ -1795,9 +1805,12 @@ static struct mr_table *ipmr_rt_fib_lookup(struct net *net, struct sk_buff *skb)
                .daddr = iph->daddr,
                .saddr = iph->saddr,
                .flowi4_tos = RT_TOS(iph->tos),
-               .flowi4_oif = rt->rt_oif,
-               .flowi4_iif = rt->rt_iif,
-               .flowi4_mark = rt->rt_mark,
+               .flowi4_oif = (rt_is_output_route(rt) ?
+                              skb->dev->ifindex : 0),
+               .flowi4_iif = (rt_is_output_route(rt) ?
+                              net->loopback_dev->ifindex :
+                              skb->dev->ifindex),
+               .flowi4_mark = skb->mark,
        };
        struct mr_table *mrt;
        int err;
@@ -2006,37 +2019,37 @@ static int __ipmr_fill_mroute(struct mr_table *mrt, struct sk_buff *skb,
 {
        int ct;
        struct rtnexthop *nhp;
-       u8 *b = skb_tail_pointer(skb);
-       struct rtattr *mp_head;
+       struct nlattr *mp_attr;
 
        /* If cache is unresolved, don't try to parse IIF and OIF */
        if (c->mfc_parent >= MAXVIFS)
                return -ENOENT;
 
-       if (VIF_EXISTS(mrt, c->mfc_parent))
-               RTA_PUT(skb, RTA_IIF, 4, &mrt->vif_table[c->mfc_parent].dev->ifindex);
+       if (VIF_EXISTS(mrt, c->mfc_parent) &&
+           nla_put_u32(skb, RTA_IIF, mrt->vif_table[c->mfc_parent].dev->ifindex) < 0)
+               return -EMSGSIZE;
 
-       mp_head = (struct rtattr *)skb_put(skb, RTA_LENGTH(0));
+       if (!(mp_attr = nla_nest_start(skb, RTA_MULTIPATH)))
+               return -EMSGSIZE;
 
        for (ct = c->mfc_un.res.minvif; ct < c->mfc_un.res.maxvif; ct++) {
                if (VIF_EXISTS(mrt, ct) && c->mfc_un.res.ttls[ct] < 255) {
-                       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)))) {
+                               nla_nest_cancel(skb, mp_attr);
+                               return -EMSGSIZE;
+                       }
+
                        nhp->rtnh_flags = 0;
                        nhp->rtnh_hops = c->mfc_un.res.ttls[ct];
                        nhp->rtnh_ifindex = mrt->vif_table[ct].dev->ifindex;
                        nhp->rtnh_len = sizeof(*nhp);
                }
        }
-       mp_head->rta_type = RTA_MULTIPATH;
-       mp_head->rta_len = skb_tail_pointer(skb) - (u8 *)mp_head;
+
+       nla_nest_end(skb, mp_attr);
+
        rtm->rtm_type = RTN_MULTICAST;
        return 1;
-
-rtattr_failure:
-       nlmsg_trim(skb, b);
-       return -EMSGSIZE;
 }
 
 int ipmr_get_route(struct net *net, struct sk_buff *skb,