+ if (__ip_route_output_key(net, &rt, &fl))
+ goto out_unlock;
+
+ /* No need to clone since we're just using its address. */
+ rt2 = rt;
+
+ err = xfrm_lookup((struct dst_entry **)&rt, &fl, NULL, 0);
+ switch (err) {
+ case 0:
+ if (rt != rt2)
+ goto route_done;
+ break;
+ case -EPERM:
+ rt = NULL;
+ break;
+ default:
+ goto out_unlock;
+ }
+
+ if (xfrm_decode_session_reverse(skb_in, &fl, AF_INET))
+ goto out_unlock;
+
+ if (inet_addr_type(net, fl.fl4_src) == RTN_LOCAL)
+ err = __ip_route_output_key(net, &rt2, &fl);
+ else {
+ struct flowi fl2 = {};
+ struct dst_entry *odst;
+
+ fl2.fl4_dst = fl.fl4_src;
+ if (ip_route_output_key(net, &rt2, &fl2))
+ goto out_unlock;
+
+ /* Ugh! */
+ odst = skb_in->dst;
+ err = ip_route_input(skb_in, fl.fl4_dst, fl.fl4_src,
+ RT_TOS(tos), rt2->u.dst.dev);
+
+ dst_release(&rt2->u.dst);
+ rt2 = skb_in->rtable;
+ skb_in->dst = odst;
+ }
+
+ if (err)
+ goto out_unlock;
+
+ err = xfrm_lookup((struct dst_entry **)&rt2, &fl, NULL,
+ XFRM_LOOKUP_ICMP);
+ if (err == -ENOENT) {
+ if (!rt)
+ goto out_unlock;
+ goto route_done;
+ }
+
+ dst_release(&rt->u.dst);
+ rt = rt2;
+
+ if (err)