if (saddr)
memcpy(&fl.fl6_src, saddr, sizeof(fl.fl6_src));
- dst = ip6_route_output(NULL, &fl);
+ dst = ip6_route_output(&init_net, NULL, &fl);
err = dst->error;
if (dst->error) {
if (IS_ERR(dst))
return -EHOSTUNREACH;
- ipv6_get_saddr(dst, (struct in6_addr *)&daddr->a6,
- (struct in6_addr *)&saddr->a6);
+ ipv6_dev_get_saddr(ip6_dst_idev(dst)->dev,
+ (struct in6_addr *)&daddr->a6,
+ (struct in6_addr *)&saddr->a6);
dst_release(dst);
return 0;
}
return 0;
}
+static int xfrm6_init_path(struct xfrm_dst *path, struct dst_entry *dst,
+ int nfheader_len)
+{
+ if (dst->ops->family == AF_INET6) {
+ struct rt6_info *rt = (struct rt6_info*)dst;
+ if (rt->rt6i_node)
+ path->path_cookie = rt->rt6i_node->fn_sernum;
+ }
+
+ path->u.rt6.rt6i_nfheader_len = nfheader_len;
+
+ return 0;
+}
+
static int xfrm6_fill_dst(struct xfrm_dst *xdst, struct net_device *dev)
{
struct rt6_info *rt = (struct rt6_info*)xdst->route;
RTF_LOCAL);
xdst->u.rt6.rt6i_metric = rt->rt6i_metric;
xdst->u.rt6.rt6i_node = rt->rt6i_node;
+ if (rt->rt6i_node)
+ xdst->route_cookie = rt->rt6i_node->fn_sernum;
xdst->u.rt6.rt6i_gateway = rt->rt6i_gateway;
xdst->u.rt6.rt6i_dst = rt->rt6i_dst;
xdst->u.rt6.rt6i_src = rt->rt6i_src;
}
static inline void
-_decode_session6(struct sk_buff *skb, struct flowi *fl)
+_decode_session6(struct sk_buff *skb, struct flowi *fl, int reverse)
{
u16 offset = skb_network_header_len(skb);
struct ipv6hdr *hdr = ipv6_hdr(skb);
u8 nexthdr = nh[IP6CB(skb)->nhoff];
memset(fl, 0, sizeof(struct flowi));
- ipv6_addr_copy(&fl->fl6_dst, &hdr->daddr);
- ipv6_addr_copy(&fl->fl6_src, &hdr->saddr);
+ ipv6_addr_copy(&fl->fl6_dst, reverse ? &hdr->saddr : &hdr->daddr);
+ ipv6_addr_copy(&fl->fl6_src, reverse ? &hdr->daddr : &hdr->saddr);
while (pskb_may_pull(skb, nh + offset + 1 - skb->data)) {
nh = skb_network_header(skb);
if (pskb_may_pull(skb, nh + offset + 4 - skb->data)) {
__be16 *ports = (__be16 *)exthdr;
- fl->fl_ip_sport = ports[0];
- fl->fl_ip_dport = ports[1];
+ fl->fl_ip_sport = ports[!!reverse];
+ fl->fl_ip_dport = ports[!reverse];
}
fl->proto = nexthdr;
return;
}
}
-static inline int xfrm6_garbage_collect(void)
+static inline int xfrm6_garbage_collect(struct dst_ops *ops)
{
xfrm6_policy_afinfo.garbage_collect();
return (atomic_read(&xfrm6_dst_ops.entries) > xfrm6_dst_ops.gc_thresh*2);
xdst = (struct xfrm_dst *)dst;
if (xdst->u.rt6.rt6i_idev->dev == dev) {
- struct inet6_dev *loopback_idev = in6_dev_get(init_net.loopback_dev);
+ struct inet6_dev *loopback_idev =
+ in6_dev_get(dev->nd_net->loopback_dev);
BUG_ON(!loopback_idev);
do {
.update_pmtu = xfrm6_update_pmtu,
.destroy = xfrm6_dst_destroy,
.ifdown = xfrm6_dst_ifdown,
+ .local_out = __ip6_local_out,
.gc_thresh = 1024,
.entry_size = sizeof(struct xfrm_dst),
+ .entries = ATOMIC_INIT(0),
};
static struct xfrm_policy_afinfo xfrm6_policy_afinfo = {
.find_bundle = __xfrm6_find_bundle,
.decode_session = _decode_session6,
.get_tos = xfrm6_get_tos,
+ .init_path = xfrm6_init_path,
.fill_dst = xfrm6_fill_dst,
};
-static void __init xfrm6_policy_init(void)
+static int __init xfrm6_policy_init(void)
{
- xfrm_policy_register_afinfo(&xfrm6_policy_afinfo);
+ return xfrm_policy_register_afinfo(&xfrm6_policy_afinfo);
}
static void xfrm6_policy_fini(void)
xfrm_policy_unregister_afinfo(&xfrm6_policy_afinfo);
}
-void __init xfrm6_init(void)
+int __init xfrm6_init(void)
{
- xfrm6_policy_init();
- xfrm6_state_init();
+ int ret;
+
+ ret = xfrm6_policy_init();
+ if (ret)
+ goto out;
+
+ ret = xfrm6_state_init();
+ if (ret)
+ goto out_policy;
+out:
+ return ret;
+out_policy:
+ xfrm6_policy_fini();
+ goto out;
}
void xfrm6_fini(void)