xfrm: clean up xfrm protocol checks
[sfrench/cifs-2.6.git] / include / net / xfrm.h
index da588def3c61d45767ebc7a68994fe3958469b50..902437dfbce7797023e36fc58fe85ce65f80e819 100644 (file)
@@ -577,6 +577,7 @@ struct xfrm_policy {
        /* This lock only affects elements except for entry. */
        rwlock_t                lock;
        refcount_t              refcnt;
+       u32                     pos;
        struct timer_list       timer;
 
        atomic_t                genid;
@@ -589,6 +590,7 @@ struct xfrm_policy {
        struct xfrm_lifetime_cur curlft;
        struct xfrm_policy_walk_entry walk;
        struct xfrm_policy_queue polq;
+       bool                    bydst_reinsert;
        u8                      type;
        u8                      action;
        u8                      flags;
@@ -596,6 +598,7 @@ struct xfrm_policy {
        u16                     family;
        struct xfrm_sec_ctx     *security;
        struct xfrm_tmpl        xfrm_vec[XFRM_MAX_DEPTH];
+       struct hlist_node       bydst_inexact_list;
        struct rcu_head         rcu;
 };
 
@@ -850,7 +853,7 @@ static inline void xfrm_pols_put(struct xfrm_policy **pols, int npols)
                xfrm_pol_put(pols[i]);
 }
 
-void __xfrm_state_destroy(struct xfrm_state *);
+void __xfrm_state_destroy(struct xfrm_state *, bool);
 
 static inline void __xfrm_state_put(struct xfrm_state *x)
 {
@@ -860,7 +863,13 @@ static inline void __xfrm_state_put(struct xfrm_state *x)
 static inline void xfrm_state_put(struct xfrm_state *x)
 {
        if (refcount_dec_and_test(&x->refcnt))
-               __xfrm_state_destroy(x);
+               __xfrm_state_destroy(x, false);
+}
+
+static inline void xfrm_state_put_sync(struct xfrm_state *x)
+{
+       if (refcount_dec_and_test(&x->refcnt))
+               __xfrm_state_destroy(x, true);
 }
 
 static inline void xfrm_state_hold(struct xfrm_state *x)
@@ -1093,7 +1102,6 @@ struct xfrm_offload {
 };
 
 struct sec_path {
-       refcount_t              refcnt;
        int                     len;
        int                     olen;
 
@@ -1101,41 +1109,13 @@ struct sec_path {
        struct xfrm_offload     ovec[XFRM_MAX_OFFLOAD_DEPTH];
 };
 
-static inline int secpath_exists(struct sk_buff *skb)
-{
-#ifdef CONFIG_XFRM
-       return skb->sp != NULL;
-#else
-       return 0;
-#endif
-}
-
-static inline struct sec_path *
-secpath_get(struct sec_path *sp)
-{
-       if (sp)
-               refcount_inc(&sp->refcnt);
-       return sp;
-}
-
-void __secpath_destroy(struct sec_path *sp);
-
-static inline void
-secpath_put(struct sec_path *sp)
-{
-       if (sp && refcount_dec_and_test(&sp->refcnt))
-               __secpath_destroy(sp);
-}
-
-struct sec_path *secpath_dup(struct sec_path *src);
-int secpath_set(struct sk_buff *skb);
+struct sec_path *secpath_set(struct sk_buff *skb);
 
 static inline void
 secpath_reset(struct sk_buff *skb)
 {
 #ifdef CONFIG_XFRM
-       secpath_put(skb->sp);
-       skb->sp = NULL;
+       skb_ext_del(skb, SKB_EXT_SEC_PATH);
 #endif
 }
 
@@ -1191,7 +1171,7 @@ static inline int __xfrm_policy_check2(struct sock *sk, int dir,
        if (sk && sk->sk_policy[XFRM_POLICY_IN])
                return __xfrm_policy_check(sk, ndir, skb, family);
 
-       return  (!net->xfrm.policy_count[dir] && !skb->sp) ||
+       return  (!net->xfrm.policy_count[dir] && !secpath_exists(skb)) ||
                (skb_dst(skb)->flags & DST_NOPOLICY) ||
                __xfrm_policy_check(sk, ndir, skb, family);
 }
@@ -1424,6 +1404,23 @@ static inline int xfrm_state_kern(const struct xfrm_state *x)
        return atomic_read(&x->tunnel_users);
 }
 
+static inline bool xfrm_id_proto_valid(u8 proto)
+{
+       switch (proto) {
+       case IPPROTO_AH:
+       case IPPROTO_ESP:
+       case IPPROTO_COMP:
+#if IS_ENABLED(CONFIG_IPV6)
+       case IPPROTO_ROUTING:
+       case IPPROTO_DSTOPTS:
+#endif
+               return true;
+       default:
+               return false;
+       }
+}
+
+/* IPSEC_PROTO_ANY only matches 3 IPsec protocols, 0 could match all. */
 static inline int xfrm_id_proto_match(u8 proto, u8 userproto)
 {
        return (!userproto || proto == userproto ||
@@ -1616,7 +1613,7 @@ struct xfrmk_spdinfo {
 
 struct xfrm_state *xfrm_find_acq_byseq(struct net *net, u32 mark, u32 seq);
 int xfrm_state_delete(struct xfrm_state *x);
-int xfrm_state_flush(struct net *net, u8 proto, bool task_valid);
+int xfrm_state_flush(struct net *net, u8 proto, bool task_valid, bool sync);
 int xfrm_dev_state_flush(struct net *net, struct net_device *dev, bool task_valid);
 void xfrm_sad_getinfo(struct net *net, struct xfrmk_sadinfo *si);
 void xfrm_spd_getinfo(struct net *net, struct xfrmk_spdinfo *si);
@@ -1903,14 +1900,16 @@ static inline void xfrm_states_delete(struct xfrm_state **states, int n)
 #ifdef CONFIG_XFRM
 static inline struct xfrm_state *xfrm_input_state(struct sk_buff *skb)
 {
-       return skb->sp->xvec[skb->sp->len - 1];
+       struct sec_path *sp = skb_sec_path(skb);
+
+       return sp->xvec[sp->len - 1];
 }
 #endif
 
 static inline struct xfrm_offload *xfrm_offload(struct sk_buff *skb)
 {
 #ifdef CONFIG_XFRM
-       struct sec_path *sp = skb->sp;
+       struct sec_path *sp = skb_sec_path(skb);
 
        if (!sp || !sp->olen || sp->len != sp->olen)
                return NULL;
@@ -1968,7 +1967,7 @@ static inline void xfrm_dev_state_delete(struct xfrm_state *x)
 static inline void xfrm_dev_state_free(struct xfrm_state *x)
 {
        struct xfrm_state_offload *xso = &x->xso;
-        struct net_device *dev = xso->dev;
+       struct net_device *dev = xso->dev;
 
        if (dev && dev->xfrmdev_ops) {
                if (dev->xfrmdev_ops->xdo_dev_state_free)