Merge tag 'drivers-5.15' of git://git.kernel.org/pub/scm/linux/kernel/git/soc/soc
[linux-2.6-microblaze.git] / net / netfilter / nf_conntrack_ecache.c
index 3f1e0ad..41768ff 100644 (file)
@@ -130,27 +130,57 @@ static void ecache_work(struct work_struct *work)
                schedule_delayed_work(&cnet->ecache_dwork, delay);
 }
 
-int nf_conntrack_eventmask_report(unsigned int eventmask, struct nf_conn *ct,
-                                 u32 portid, int report)
+static int __nf_conntrack_eventmask_report(struct nf_conntrack_ecache *e,
+                                          const unsigned int events,
+                                          const unsigned long missed,
+                                          const struct nf_ct_event *item)
 {
-       struct net *net = nf_ct_net(ct);
+       struct nf_conn *ct = item->ct;
+       struct net *net = nf_ct_net(item->ct);
        struct nf_ct_event_notifier *notify;
+       int ret;
+
+       if (!((events | missed) & e->ctmask))
+               return 0;
+
+       rcu_read_lock();
+
+       notify = rcu_dereference(net->ct.nf_conntrack_event_cb);
+       if (!notify) {
+               rcu_read_unlock();
+               return 0;
+       }
+
+       ret = notify->ct_event(events | missed, item);
+       rcu_read_unlock();
+
+       if (likely(ret >= 0 && missed == 0))
+               return 0;
+
+       spin_lock_bh(&ct->lock);
+       if (ret < 0)
+               e->missed |= events;
+       else
+               e->missed &= ~missed;
+       spin_unlock_bh(&ct->lock);
+
+       return ret;
+}
+
+int nf_conntrack_eventmask_report(unsigned int events, struct nf_conn *ct,
+                                 u32 portid, int report)
+{
        struct nf_conntrack_ecache *e;
        struct nf_ct_event item;
        unsigned long missed;
-       int ret = 0;
+       int ret;
 
        if (!nf_ct_is_confirmed(ct))
-               return ret;
-
-       rcu_read_lock();
-       notify = rcu_dereference(net->ct.nf_conntrack_event_cb);
-       if (!notify)
-               goto out_unlock;
+               return 0;
 
        e = nf_ct_ecache_find(ct);
        if (!e)
-               goto out_unlock;
+               return 0;
 
        memset(&item, 0, sizeof(item));
 
@@ -161,31 +191,16 @@ int nf_conntrack_eventmask_report(unsigned int eventmask, struct nf_conn *ct,
        /* This is a resent of a destroy event? If so, skip missed */
        missed = e->portid ? 0 : e->missed;
 
-       if (!((eventmask | missed) & e->ctmask))
-               goto out_unlock;
-
-       ret = notify->fcn(eventmask | missed, &item);
-       if (unlikely(ret < 0 || missed)) {
-               spin_lock_bh(&ct->lock);
-               if (ret < 0) {
-                       /* This is a destroy event that has been
-                        * triggered by a process, we store the PORTID
-                        * to include it in the retransmission.
-                        */
-                       if (eventmask & (1 << IPCT_DESTROY)) {
-                               if (e->portid == 0 && portid != 0)
-                                       e->portid = portid;
-                               e->state = NFCT_ECACHE_DESTROY_FAIL;
-                       } else {
-                               e->missed |= eventmask;
-                       }
-               } else {
-                       e->missed &= ~missed;
-               }
-               spin_unlock_bh(&ct->lock);
+       ret = __nf_conntrack_eventmask_report(e, events, missed, &item);
+       if (unlikely(ret < 0 && (events & (1 << IPCT_DESTROY)))) {
+               /* This is a destroy event that has been triggered by a process,
+                * we store the PORTID to include it in the retransmission.
+                */
+               if (e->portid == 0 && portid != 0)
+                       e->portid = portid;
+               e->state = NFCT_ECACHE_DESTROY_FAIL;
        }
-out_unlock:
-       rcu_read_unlock();
+
        return ret;
 }
 EXPORT_SYMBOL_GPL(nf_conntrack_eventmask_report);
@@ -194,53 +209,28 @@ EXPORT_SYMBOL_GPL(nf_conntrack_eventmask_report);
  * disabled softirqs */
 void nf_ct_deliver_cached_events(struct nf_conn *ct)
 {
-       struct net *net = nf_ct_net(ct);
-       unsigned long events, missed;
-       struct nf_ct_event_notifier *notify;
        struct nf_conntrack_ecache *e;
        struct nf_ct_event item;
-       int ret;
-
-       rcu_read_lock();
-       notify = rcu_dereference(net->ct.nf_conntrack_event_cb);
-       if (notify == NULL)
-               goto out_unlock;
+       unsigned long events;
 
        if (!nf_ct_is_confirmed(ct) || nf_ct_is_dying(ct))
-               goto out_unlock;
+               return;
 
        e = nf_ct_ecache_find(ct);
        if (e == NULL)
-               goto out_unlock;
+               return;
 
        events = xchg(&e->cache, 0);
 
-       /* We make a copy of the missed event cache without taking
-        * the lock, thus we may send missed events twice. However,
-        * this does not harm and it happens very rarely. */
-       missed = e->missed;
-
-       if (!((events | missed) & e->ctmask))
-               goto out_unlock;
-
        item.ct = ct;
        item.portid = 0;
        item.report = 0;
 
-       ret = notify->fcn(events | missed, &item);
-
-       if (likely(ret == 0 && !missed))
-               goto out_unlock;
-
-       spin_lock_bh(&ct->lock);
-       if (ret < 0)
-               e->missed |= events;
-       else
-               e->missed &= ~missed;
-       spin_unlock_bh(&ct->lock);
-
-out_unlock:
-       rcu_read_unlock();
+       /* We make a copy of the missed event cache without taking
+        * the lock, thus we may send missed events twice. However,
+        * this does not harm and it happens very rarely.
+        */
+       __nf_conntrack_eventmask_report(e, events, e->missed, &item);
 }
 EXPORT_SYMBOL_GPL(nf_ct_deliver_cached_events);
 
@@ -250,11 +240,11 @@ void nf_ct_expect_event_report(enum ip_conntrack_expect_events event,
 
 {
        struct net *net = nf_ct_exp_net(exp);
-       struct nf_exp_event_notifier *notify;
+       struct nf_ct_event_notifier *notify;
        struct nf_conntrack_ecache *e;
 
        rcu_read_lock();
-       notify = rcu_dereference(net->ct.nf_expect_event_cb);
+       notify = rcu_dereference(net->ct.nf_conntrack_event_cb);
        if (!notify)
                goto out_unlock;
 
@@ -268,86 +258,35 @@ void nf_ct_expect_event_report(enum ip_conntrack_expect_events event,
                        .portid = portid,
                        .report = report
                };
-               notify->fcn(1 << event, &item);
+               notify->exp_event(1 << event, &item);
        }
 out_unlock:
        rcu_read_unlock();
 }
 
-int nf_conntrack_register_notifier(struct net *net,
-                                  struct nf_ct_event_notifier *new)
+void nf_conntrack_register_notifier(struct net *net,
+                                   const struct nf_ct_event_notifier *new)
 {
-       int ret;
        struct nf_ct_event_notifier *notify;
 
        mutex_lock(&nf_ct_ecache_mutex);
        notify = rcu_dereference_protected(net->ct.nf_conntrack_event_cb,
                                           lockdep_is_held(&nf_ct_ecache_mutex));
-       if (notify != NULL) {
-               ret = -EBUSY;
-               goto out_unlock;
-       }
+       WARN_ON_ONCE(notify);
        rcu_assign_pointer(net->ct.nf_conntrack_event_cb, new);
-       ret = 0;
-
-out_unlock:
        mutex_unlock(&nf_ct_ecache_mutex);
-       return ret;
 }
 EXPORT_SYMBOL_GPL(nf_conntrack_register_notifier);
 
-void nf_conntrack_unregister_notifier(struct net *net,
-                                     struct nf_ct_event_notifier *new)
+void nf_conntrack_unregister_notifier(struct net *net)
 {
-       struct nf_ct_event_notifier *notify;
-
        mutex_lock(&nf_ct_ecache_mutex);
-       notify = rcu_dereference_protected(net->ct.nf_conntrack_event_cb,
-                                          lockdep_is_held(&nf_ct_ecache_mutex));
-       BUG_ON(notify != new);
        RCU_INIT_POINTER(net->ct.nf_conntrack_event_cb, NULL);
        mutex_unlock(&nf_ct_ecache_mutex);
-       /* synchronize_rcu() is called from ctnetlink_exit. */
+       /* synchronize_rcu() is called after netns pre_exit */
 }
 EXPORT_SYMBOL_GPL(nf_conntrack_unregister_notifier);
 
-int nf_ct_expect_register_notifier(struct net *net,
-                                  struct nf_exp_event_notifier *new)
-{
-       int ret;
-       struct nf_exp_event_notifier *notify;
-
-       mutex_lock(&nf_ct_ecache_mutex);
-       notify = rcu_dereference_protected(net->ct.nf_expect_event_cb,
-                                          lockdep_is_held(&nf_ct_ecache_mutex));
-       if (notify != NULL) {
-               ret = -EBUSY;
-               goto out_unlock;
-       }
-       rcu_assign_pointer(net->ct.nf_expect_event_cb, new);
-       ret = 0;
-
-out_unlock:
-       mutex_unlock(&nf_ct_ecache_mutex);
-       return ret;
-}
-EXPORT_SYMBOL_GPL(nf_ct_expect_register_notifier);
-
-void nf_ct_expect_unregister_notifier(struct net *net,
-                                     struct nf_exp_event_notifier *new)
-{
-       struct nf_exp_event_notifier *notify;
-
-       mutex_lock(&nf_ct_ecache_mutex);
-       notify = rcu_dereference_protected(net->ct.nf_expect_event_cb,
-                                          lockdep_is_held(&nf_ct_ecache_mutex));
-       BUG_ON(notify != new);
-       RCU_INIT_POINTER(net->ct.nf_expect_event_cb, NULL);
-       mutex_unlock(&nf_ct_ecache_mutex);
-       /* synchronize_rcu() is called from ctnetlink_exit. */
-}
-EXPORT_SYMBOL_GPL(nf_ct_expect_unregister_notifier);
-
 void nf_conntrack_ecache_work(struct net *net, enum nf_ct_ecache_state state)
 {
        struct nf_conntrack_net *cnet = nf_ct_pernet(net);