Staging: Merge staging-next into Linus's tree
[sfrench/cifs-2.6.git] / net / ipv6 / exthdrs.c
index 8a659f92d17af2a271f1c4a0ba6e72af6f6bbea1..262f105d23b9399e3f6f043e307df3bf69535f6c 100644 (file)
@@ -312,6 +312,7 @@ static int ipv6_destopt_rcv(struct sk_buff *skb)
   Routing header.
  ********************************/
 
+/* called with rcu_read_lock() */
 static int ipv6_rthdr_rcv(struct sk_buff *skb)
 {
        struct inet6_skb_parm *opt = IP6CB(skb);
@@ -324,12 +325,9 @@ static int ipv6_rthdr_rcv(struct sk_buff *skb)
        struct net *net = dev_net(skb->dev);
        int accept_source_route = net->ipv6.devconf_all->accept_source_route;
 
-       idev = in6_dev_get(skb->dev);
-       if (idev) {
-               if (accept_source_route > idev->cnf.accept_source_route)
-                       accept_source_route = idev->cnf.accept_source_route;
-               in6_dev_put(idev);
-       }
+       idev = __in6_dev_get(skb->dev);
+       if (idev && accept_source_route > idev->cnf.accept_source_route)
+               accept_source_route = idev->cnf.accept_source_route;
 
        if (!pskb_may_pull(skb, skb_transport_offset(skb) + 8) ||
            !pskb_may_pull(skb, (skb_transport_offset(skb) +
@@ -874,3 +872,27 @@ struct ipv6_txoptions *ipv6_fixup_options(struct ipv6_txoptions *opt_space,
        return opt;
 }
 
+/**
+ * fl6_update_dst - update flowi destination address with info given
+ *                  by srcrt option, if any.
+ *
+ * @fl: flowi for which fl6_dst is to be updated
+ * @opt: struct ipv6_txoptions in which to look for srcrt opt
+ * @orig: copy of original fl6_dst address if modified
+ *
+ * Returns NULL if no txoptions or no srcrt, otherwise returns orig
+ * and initial value of fl->fl6_dst set in orig
+ */
+struct in6_addr *fl6_update_dst(struct flowi *fl,
+                               const struct ipv6_txoptions *opt,
+                               struct in6_addr *orig)
+{
+       if (!opt || !opt->srcrt)
+               return NULL;
+
+       ipv6_addr_copy(orig, &fl->fl6_dst);
+       ipv6_addr_copy(&fl->fl6_dst, ((struct rt0_hdr *)opt->srcrt)->addr);
+       return orig;
+}
+
+EXPORT_SYMBOL_GPL(fl6_update_dst);