]> err.no Git - linux-2.6/blobdiff - net/ipv4/xfrm4_policy.c
[PATCH] handle errors returned by platform_get_irq*()
[linux-2.6] / net / ipv4 / xfrm4_policy.c
index 7fe2afd2e66954237f4d23a8bc35ea42392c34bf..f285bbf296e28d79099887afa2882be75ddf32bc 100644 (file)
@@ -8,7 +8,9 @@
  *     
  */
 
+#include <linux/compiler.h>
 #include <linux/config.h>
+#include <linux/inetdevice.h>
 #include <net/xfrm.h>
 #include <net/ip.h>
 
@@ -33,6 +35,7 @@ __xfrm4_find_bundle(struct flowi *fl, struct xfrm_policy *policy)
                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)) {
                        dst_clone(dst);
                        break;
@@ -59,7 +62,8 @@ __xfrm4_bundle_create(struct xfrm_policy *policy, struct xfrm_state **xfrm, int
                .nl_u = {
                        .ip4_u = {
                                .saddr = local,
-                               .daddr = remote
+                               .daddr = remote,
+                               .tos = fl->fl4_tos
                        }
                }
        };
@@ -152,6 +156,8 @@ __xfrm4_bundle_create(struct xfrm_policy *policy, struct xfrm_state **xfrm, int
                x->u.rt.rt_dst = rt0->rt_dst;
                x->u.rt.rt_gateway = rt->rt_gateway;
                x->u.rt.rt_spec_dst = rt0->rt_spec_dst;
+               x->u.rt.idev = rt0->idev;
+               in_dev_hold(rt0->idev);
                header_len -= x->u.dst.xfrm->props.header_len;
                trailer_len -= x->u.dst.xfrm->props.trailer_len;
        }
@@ -177,6 +183,7 @@ _decode_session4(struct sk_buff *skb, struct flowi *fl)
                case IPPROTO_UDP:
                case IPPROTO_TCP:
                case IPPROTO_SCTP:
+               case IPPROTO_DCCP:
                        if (pskb_may_pull(skb, xprth + 4 - skb->data)) {
                                u16 *ports = (u16 *)xprth;
 
@@ -225,6 +232,7 @@ _decode_session4(struct sk_buff *skb, struct flowi *fl)
        fl->proto = iph->protocol;
        fl->fl4_dst = iph->daddr;
        fl->fl4_src = iph->saddr;
+       fl->fl4_tos = iph->tos;
 }
 
 static inline int xfrm4_garbage_collect(void)
@@ -243,11 +251,48 @@ static void xfrm4_update_pmtu(struct dst_entry *dst, u32 mtu)
        path->ops->update_pmtu(path, mtu);
 }
 
+static void xfrm4_dst_destroy(struct dst_entry *dst)
+{
+       struct xfrm_dst *xdst = (struct xfrm_dst *)dst;
+
+       if (likely(xdst->u.rt.idev))
+               in_dev_put(xdst->u.rt.idev);
+       xfrm_dst_destroy(xdst);
+}
+
+static void xfrm4_dst_ifdown(struct dst_entry *dst, struct net_device *dev,
+                            int unregister)
+{
+       struct xfrm_dst *xdst;
+
+       if (!unregister)
+               return;
+
+       xdst = (struct xfrm_dst *)dst;
+       if (xdst->u.rt.idev->dev == dev) {
+               struct in_device *loopback_idev = in_dev_get(&loopback_dev);
+               BUG_ON(!loopback_idev);
+
+               do {
+                       in_dev_put(xdst->u.rt.idev);
+                       xdst->u.rt.idev = loopback_idev;
+                       in_dev_hold(loopback_idev);
+                       xdst = (struct xfrm_dst *)xdst->u.dst.child;
+               } while (xdst->u.dst.xfrm);
+
+               __in_dev_put(loopback_idev);
+       }
+
+       xfrm_dst_ifdown(dst, dev);
+}
+
 static struct dst_ops xfrm4_dst_ops = {
        .family =               AF_INET,
        .protocol =             __constant_htons(ETH_P_IP),
        .gc =                   xfrm4_garbage_collect,
        .update_pmtu =          xfrm4_update_pmtu,
+       .destroy =              xfrm4_dst_destroy,
+       .ifdown =               xfrm4_dst_ifdown,
        .gc_thresh =            1024,
        .entry_size =           sizeof(struct xfrm_dst),
 };