vfs: rename block_fsync() to blkdev_fsync()
[safe/jmp/linux-2.6] / include / net / netfilter / nf_conntrack_ecache.h
index e7ae297..96ba5f7 100644 (file)
 #include <linux/netfilter/nf_conntrack_tuple_common.h>
 #include <net/netfilter/nf_conntrack_extend.h>
 
-/* Connection tracking event types */
-enum ip_conntrack_events
-{
-       IPCT_NEW                = 0,    /* new conntrack */
-       IPCT_RELATED            = 1,    /* related conntrack */
-       IPCT_DESTROY            = 2,    /* destroyed conntrack */
-       IPCT_STATUS             = 3,    /* status has changed */
-       IPCT_PROTOINFO          = 4,    /* protocol information has changed */
-       IPCT_HELPER             = 5,    /* new helper has been set */
-       IPCT_MARK               = 6,    /* new mark has been set */
-       IPCT_NATSEQADJ          = 7,    /* NAT is doing sequence adjustment */
-       IPCT_SECMARK            = 8,    /* new security mark has been set */
-};
-
-enum ip_conntrack_expect_events {
-       IPEXP_NEW               = 0,    /* new expectation */
-};
-
 struct nf_conntrack_ecache {
-       unsigned long cache;            /* bitops want long */
+       unsigned long cache;    /* bitops want long */
+       unsigned long missed;   /* missed events */
+       u16 ctmask;             /* bitmask of ct events to be delivered */
+       u16 expmask;            /* bitmask of expect events to be delivered */
+       u32 pid;                /* netlink pid of destroyer */
 };
 
 static inline struct nf_conntrack_ecache *
@@ -41,14 +27,24 @@ nf_ct_ecache_find(const struct nf_conn *ct)
 }
 
 static inline struct nf_conntrack_ecache *
-nf_ct_ecache_ext_add(struct nf_conn *ct, gfp_t gfp)
+nf_ct_ecache_ext_add(struct nf_conn *ct, u16 ctmask, u16 expmask, gfp_t gfp)
 {
        struct net *net = nf_ct_net(ct);
+       struct nf_conntrack_ecache *e;
 
-       if (!net->ct.sysctl_events)
+       if (!ctmask && !expmask && net->ct.sysctl_events) {
+               ctmask = ~0;
+               expmask = ~0;
+       }
+       if (!ctmask && !expmask)
                return NULL;
 
-       return nf_ct_ext_add(ct, NF_CT_EXT_ECACHE, gfp);
+       e = nf_ct_ext_add(ct, NF_CT_EXT_ECACHE, gfp);
+       if (e) {
+               e->ctmask  = ctmask;
+               e->expmask = expmask;
+       }
+       return e;
 };
 
 #ifdef CONFIG_NF_CONNTRACK_EVENTS
@@ -81,49 +77,76 @@ nf_conntrack_event_cache(enum ip_conntrack_events event, struct nf_conn *ct)
        if (e == NULL)
                return;
 
+       if (!(e->ctmask & (1 << event)))
+               return;
+
        set_bit(event, &e->cache);
 }
 
-static inline void
+static inline int
 nf_conntrack_eventmask_report(unsigned int eventmask,
                              struct nf_conn *ct,
                              u32 pid,
                              int report)
 {
-       struct net *net = nf_ct_net(ct);
+       int ret = 0;
        struct nf_ct_event_notifier *notify;
+       struct nf_conntrack_ecache *e;
 
        rcu_read_lock();
        notify = rcu_dereference(nf_conntrack_event_cb);
        if (notify == NULL)
                goto out_unlock;
 
-       if (!net->ct.sysctl_events)
+       e = nf_ct_ecache_find(ct);
+       if (e == NULL)
                goto out_unlock;
 
        if (nf_ct_is_confirmed(ct) && !nf_ct_is_dying(ct)) {
                struct nf_ct_event item = {
                        .ct     = ct,
-                       .pid    = pid,
+                       .pid    = e->pid ? e->pid : pid,
                        .report = report
                };
-               notify->fcn(eventmask, &item);
+               /* This is a resent of a destroy event? If so, skip missed */
+               unsigned long missed = e->pid ? 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 PID
+                                * to include it in the retransmission. */
+                               if (eventmask & (1 << IPCT_DESTROY) &&
+                                   e->pid == 0 && pid != 0)
+                                       e->pid = pid;
+                               else
+                                       e->missed |= eventmask;
+                       } else
+                               e->missed &= ~missed;
+                       spin_unlock_bh(&ct->lock);
+               }
        }
 out_unlock:
        rcu_read_unlock();
+       return ret;
 }
 
-static inline void
+static inline int
 nf_conntrack_event_report(enum ip_conntrack_events event, struct nf_conn *ct,
                          u32 pid, int report)
 {
-       nf_conntrack_eventmask_report(1 << event, ct, pid, report);
+       return nf_conntrack_eventmask_report(1 << event, ct, pid, report);
 }
 
-static inline void
+static inline int
 nf_conntrack_event(enum ip_conntrack_events event, struct nf_conn *ct)
 {
-       nf_conntrack_eventmask_report(1 << event, ct, 0, 0);
+       return nf_conntrack_eventmask_report(1 << event, ct, 0, 0);
 }
 
 struct nf_exp_event {
@@ -146,18 +169,19 @@ nf_ct_expect_event_report(enum ip_conntrack_expect_events event,
                          u32 pid,
                          int report)
 {
-       struct net *net = nf_ct_exp_net(exp);
        struct nf_exp_event_notifier *notify;
+       struct nf_conntrack_ecache *e;
 
        rcu_read_lock();
        notify = rcu_dereference(nf_expect_event_cb);
        if (notify == NULL)
                goto out_unlock;
 
-       if (!net->ct.sysctl_events)
+       e = nf_ct_ecache_find(exp->master);
+       if (e == NULL)
                goto out_unlock;
 
-       {
+       if (e->expmask & (1 << event)) {
                struct nf_exp_event item = {
                        .exp    = exp,
                        .pid    = pid,
@@ -183,16 +207,16 @@ extern void nf_conntrack_ecache_fini(struct net *net);
 
 static inline void nf_conntrack_event_cache(enum ip_conntrack_events event,
                                            struct nf_conn *ct) {}
-static inline void nf_conntrack_eventmask_report(unsigned int eventmask,
-                                                struct nf_conn *ct,
-                                                u32 pid,
-                                                int report) {}
-static inline void nf_conntrack_event(enum ip_conntrack_events event,
-                                     struct nf_conn *ct) {}
-static inline void nf_conntrack_event_report(enum ip_conntrack_events event,
-                                            struct nf_conn *ct,
-                                            u32 pid,
-                                            int report) {}
+static inline int nf_conntrack_eventmask_report(unsigned int eventmask,
+                                               struct nf_conn *ct,
+                                               u32 pid,
+                                               int report) { return 0; }
+static inline int nf_conntrack_event(enum ip_conntrack_events event,
+                                    struct nf_conn *ct) { return 0; }
+static inline int nf_conntrack_event_report(enum ip_conntrack_events event,
+                                           struct nf_conn *ct,
+                                           u32 pid,
+                                           int report) { return 0; }
 static inline void nf_ct_deliver_cached_events(const struct nf_conn *ct) {}
 static inline void nf_ct_expect_event(enum ip_conntrack_expect_events event,
                                      struct nf_conntrack_expect *exp) {}