int xfrm_unregister_type_offload(const struct xfrm_type_offload *type, unsigned short family);
 
 struct xfrm_mode {
-       struct xfrm_state_afinfo *afinfo;
        struct module *owner;
        u8 encap;
        u8 family;
 
 static int __xfrm4_output(struct net *net, struct sock *sk, struct sk_buff *skb)
 {
        struct xfrm_state *x = skb_dst(skb)->xfrm;
+       const struct xfrm_state_afinfo *afinfo;
+       int ret = -EAFNOSUPPORT;
 
 #ifdef CONFIG_NETFILTER
        if (!x) {
        }
 #endif
 
-       return x->outer_mode->afinfo->output_finish(sk, skb);
+       rcu_read_lock();
+       afinfo = xfrm_state_afinfo_get_rcu(x->outer_mode->family);
+       if (likely(afinfo))
+               ret = afinfo->output_finish(sk, skb);
+       else
+               kfree_skb(skb);
+       rcu_read_unlock();
+
+       return ret;
 }
 
 int xfrm4_output(struct net *net, struct sock *sk, struct sk_buff *skb)
 
        return xfrm_output(sk, skb);
 }
 
+static int __xfrm6_output_state_finish(struct xfrm_state *x, struct sock *sk,
+                                      struct sk_buff *skb)
+{
+       const struct xfrm_state_afinfo *afinfo;
+       int ret = -EAFNOSUPPORT;
+
+       rcu_read_lock();
+       afinfo = xfrm_state_afinfo_get_rcu(x->outer_mode->family);
+       if (likely(afinfo))
+               ret = afinfo->output_finish(sk, skb);
+       else
+               kfree_skb(skb);
+       rcu_read_unlock();
+
+       return ret;
+}
+
 static int __xfrm6_output_finish(struct net *net, struct sock *sk, struct sk_buff *skb)
 {
        struct xfrm_state *x = skb_dst(skb)->xfrm;
 
-       return x->outer_mode->afinfo->output_finish(sk, skb);
+       return __xfrm6_output_state_finish(x, sk, skb);
 }
 
 static int __xfrm6_output(struct net *net, struct sock *sk, struct sk_buff *skb)
                                    __xfrm6_output_finish);
 
 skip_frag:
-       return x->outer_mode->afinfo->output_finish(sk, skb);
+       return __xfrm6_output_state_finish(x, sk, skb);
 }
 
 int xfrm6_output(struct net *net, struct sock *sk, struct sk_buff *skb)
 
 static int xfrm_prepare_input(struct xfrm_state *x, struct sk_buff *skb)
 {
        struct xfrm_mode *inner_mode = x->inner_mode;
-       int err;
+       const struct xfrm_state_afinfo *afinfo;
+       int err = -EAFNOSUPPORT;
 
-       err = x->outer_mode->afinfo->extract_input(x, skb);
-       if (err)
+       rcu_read_lock();
+       afinfo = xfrm_state_afinfo_get_rcu(x->outer_mode->family);
+       if (likely(afinfo))
+               err = afinfo->extract_input(x, skb);
+
+       if (err) {
+               rcu_read_unlock();
                return err;
+       }
 
        if (x->sel.family == AF_UNSPEC) {
                inner_mode = xfrm_ip2inner_mode(x, XFRM_MODE_SKB_CB(skb)->protocol);
-               if (inner_mode == NULL)
+               if (!inner_mode) {
+                       rcu_read_unlock();
                        return -EAFNOSUPPORT;
+               }
        }
 
-       skb->protocol = inner_mode->afinfo->eth_proto;
+       afinfo = xfrm_state_afinfo_get_rcu(inner_mode->family);
+       if (unlikely(!afinfo)) {
+               rcu_read_unlock();
+               return -EAFNOSUPPORT;
+       }
+
+       skb->protocol = afinfo->eth_proto;
+       rcu_read_unlock();
        return xfrm_inner_mode_encap_remove(x, inner_mode, skb);
 }
 
 
 int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type)
 {
+       const struct xfrm_state_afinfo *afinfo;
        struct net *net = dev_net(skb->dev);
        int err;
        __be32 seq;
                if (xo)
                        xfrm_gro = xo->flags & XFRM_GRO;
 
-               err = x->inner_mode->afinfo->transport_finish(skb, xfrm_gro || async);
+               err = -EAFNOSUPPORT;
+               rcu_read_lock();
+               afinfo = xfrm_state_afinfo_get_rcu(x->inner_mode->family);
+               if (likely(afinfo))
+                       err = afinfo->transport_finish(skb, xfrm_gro || async);
+               rcu_read_unlock();
                if (xfrm_gro) {
                        sp = skb_sec_path(skb);
                        if (sp)
 
 
 static int xfrm_inner_extract_output(struct xfrm_state *x, struct sk_buff *skb)
 {
+       const struct xfrm_state_afinfo *afinfo;
        struct xfrm_mode *inner_mode;
+       int err = -EAFNOSUPPORT;
+
        if (x->sel.family == AF_UNSPEC)
                inner_mode = xfrm_ip2inner_mode(x,
                                xfrm_af2proto(skb_dst(skb)->ops->family));
 
        if (inner_mode == NULL)
                return -EAFNOSUPPORT;
-       return inner_mode->afinfo->extract_output(x, skb);
+
+       rcu_read_lock();
+       afinfo = xfrm_state_afinfo_get_rcu(inner_mode->family);
+       if (likely(afinfo))
+               err = afinfo->extract_output(x, skb);
+       rcu_read_unlock();
+
+       return err;
 }
 
 void xfrm_local_error(struct sk_buff *skb, int mtu)
 
                                            const struct flowi *fl,
                                            struct dst_entry *dst)
 {
+       const struct xfrm_state_afinfo *afinfo;
        struct net *net = xp_net(policy);
        unsigned long now = jiffies;
        struct net_device *dev;
                dst1->lastuse = now;
 
                dst1->input = dst_discard;
-               dst1->output = inner_mode->afinfo->output;
+
+               rcu_read_lock();
+               afinfo = xfrm_state_afinfo_get_rcu(inner_mode->family);
+               if (likely(afinfo))
+                       dst1->output = afinfo->output;
+               else
+                       dst1->output = dst_discard_out;
+               rcu_read_unlock();
 
                xdst_prev = xdst;
 
 
        if (!try_module_get(afinfo->owner))
                goto out;
 
-       mode->afinfo = afinfo;
        modemap[mode->encap] = mode;
        err = 0;
 
        spin_lock_bh(&xfrm_mode_lock);
        if (likely(modemap[mode->encap] == mode)) {
                modemap[mode->encap] = NULL;
-               module_put(mode->afinfo->owner);
+               module_put(afinfo->owner);
        }
 
        spin_unlock_bh(&xfrm_mode_lock);
 
        return rcu_dereference(xfrm_state_afinfo[family]);
 }
+EXPORT_SYMBOL_GPL(xfrm_state_afinfo_get_rcu);
 
 struct xfrm_state_afinfo *xfrm_state_get_afinfo(unsigned int family)
 {