X-Git-Url: https://git.openpandora.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=net%2Fipv4%2Fxfrm4_policy.c;h=5d51a2af34c1a0edf334225326de78c384bbeb7c;hb=aef8811abbc9249a2bd59bd2331bbe523df05d17;hp=7a7a00147e55c7d63758d2d3bad84884d3b1a4c6;hpb=97d41e90fe61399b99d74820cb7f2d6e0fbac91d;p=pandora-kernel.git diff --git a/net/ipv4/xfrm4_policy.c b/net/ipv4/xfrm4_policy.c index 7a7a00147e55..5d51a2af34c1 100644 --- a/net/ipv4/xfrm4_policy.c +++ b/net/ipv4/xfrm4_policy.c @@ -1,11 +1,11 @@ -/* +/* * xfrm4_policy.c * * Changes: * Kazunori MIYAZAWA @USAGI * YOSHIFUJI Hideaki @USAGI * Split up af-specific portion - * + * */ #include @@ -50,9 +50,9 @@ __xfrm4_find_bundle(struct flowi *fl, struct xfrm_policy *policy) struct xfrm_dst *xdst = (struct xfrm_dst*)dst; if (xdst->u.rt.fl.oif == fl->oif && /*XXX*/ xdst->u.rt.fl.fl4_dst == fl->fl4_dst && - xdst->u.rt.fl.fl4_src == fl->fl4_src && - xdst->u.rt.fl.fl4_tos == fl->fl4_tos && - xfrm_bundle_ok(xdst, fl, AF_INET, 0)) { + xdst->u.rt.fl.fl4_src == fl->fl4_src && + xdst->u.rt.fl.fl4_tos == fl->fl4_tos && + xfrm_bundle_ok(policy, xdst, fl, AF_INET, 0)) { dst_clone(dst); break; } @@ -72,13 +72,11 @@ __xfrm4_bundle_create(struct xfrm_policy *policy, struct xfrm_state **xfrm, int struct dst_entry *dst, *dst_prev; struct rtable *rt0 = (struct rtable*)(*dst_p); struct rtable *rt = rt0; - u32 remote = fl->fl4_dst; - u32 local = fl->fl4_src; struct flowi fl_tunnel = { .nl_u = { .ip4_u = { - .saddr = local, - .daddr = remote, + .saddr = fl->fl4_src, + .daddr = fl->fl4_dst, .tos = fl->fl4_tos } } @@ -94,7 +92,6 @@ __xfrm4_bundle_create(struct xfrm_policy *policy, struct xfrm_state **xfrm, int for (i = 0; i < nx; i++) { struct dst_entry *dst1 = dst_alloc(&xfrm4_dst_ops); struct xfrm_dst *xdst; - int tunnel = 0; if (unlikely(dst1 == NULL)) { err = -ENOBUFS; @@ -116,19 +113,28 @@ __xfrm4_bundle_create(struct xfrm_policy *policy, struct xfrm_state **xfrm, int dst1->next = dst_prev; dst_prev = dst1; - if (xfrm[i]->props.mode != XFRM_MODE_TRANSPORT) { - remote = xfrm[i]->id.daddr.a4; - local = xfrm[i]->props.saddr.a4; - tunnel = 1; - } + header_len += xfrm[i]->props.header_len; trailer_len += xfrm[i]->props.trailer_len; - if (tunnel) { - fl_tunnel.fl4_src = local; - fl_tunnel.fl4_dst = remote; + if (xfrm[i]->props.mode == XFRM_MODE_TUNNEL) { + unsigned short encap_family = xfrm[i]->props.family; + switch(encap_family) { + case AF_INET: + fl_tunnel.fl4_dst = xfrm[i]->id.daddr.a4; + fl_tunnel.fl4_src = xfrm[i]->props.saddr.a4; + break; +#if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE) + case AF_INET6: + ipv6_addr_copy(&fl_tunnel.fl6_dst, (struct in6_addr*)&xfrm[i]->id.daddr.a6); + ipv6_addr_copy(&fl_tunnel.fl6_src, (struct in6_addr*)&xfrm[i]->props.saddr.a6); + break; +#endif + default: + BUG_ON(1); + } err = xfrm_dst_lookup((struct xfrm_dst **)&rt, - &fl_tunnel, AF_INET); + &fl_tunnel, encap_family); if (err) goto error; } else @@ -145,6 +151,7 @@ __xfrm4_bundle_create(struct xfrm_policy *policy, struct xfrm_state **xfrm, int i = 0; for (; dst_prev != &rt->u.dst; dst_prev = dst_prev->child) { struct xfrm_dst *x = (struct xfrm_dst*)dst_prev; + struct xfrm_state_afinfo *afinfo; x->u.rt.fl = *fl; dst_prev->xfrm = xfrm[i++]; @@ -162,8 +169,18 @@ __xfrm4_bundle_create(struct xfrm_policy *policy, struct xfrm_state **xfrm, int /* Copy neighbout for reachability confirmation */ dst_prev->neighbour = neigh_clone(rt->u.dst.neighbour); dst_prev->input = rt->u.dst.input; - dst_prev->output = xfrm4_output; - if (rt->peer) + /* XXX: When IPv6 module can be unloaded, we should manage reference + * to xfrm6_output in afinfo->output. Miyazawa + * */ + afinfo = xfrm_state_get_afinfo(dst_prev->xfrm->props.family); + if (!afinfo) { + dst = *dst_p; + err = -EAFNOSUPPORT; + goto error; + } + dst_prev->output = afinfo->output; + xfrm_state_put_afinfo(afinfo); + if (dst_prev->xfrm->props.family == AF_INET && rt->peer) atomic_inc(&rt->peer->refcnt); x->u.rt.peer = rt->peer; /* Sheit... I remember I did this right. Apparently, @@ -199,11 +216,12 @@ _decode_session4(struct sk_buff *skb, struct flowi *fl) if (!(iph->frag_off & htons(IP_MF | IP_OFFSET))) { switch (iph->protocol) { case IPPROTO_UDP: + case IPPROTO_UDPLITE: case IPPROTO_TCP: case IPPROTO_SCTP: case IPPROTO_DCCP: if (pskb_may_pull(skb, xprth + 4 - skb->data)) { - u16 *ports = (u16 *)xprth; + __be16 *ports = (__be16 *)xprth; fl->fl_ip_sport = ports[0]; fl->fl_ip_dport = ports[1]; @@ -273,6 +291,8 @@ static void xfrm4_dst_destroy(struct dst_entry *dst) if (likely(xdst->u.rt.idev)) in_dev_put(xdst->u.rt.idev); + if (dst->xfrm && dst->xfrm->props.family == AF_INET && likely(xdst->u.rt.peer)) + inet_putpeer(xdst->u.rt.peer); xfrm_dst_destroy(xdst); }