1 /* 2 * connection tracking event cache. 3 */ 4 5 #ifndef _NF_CONNTRACK_ECACHE_H 6 #define _NF_CONNTRACK_ECACHE_H 7 #include <net/netfilter/nf_conntrack.h> 8 9 #include <net/net_namespace.h> 10 #include <net/netfilter/nf_conntrack_expect.h> 11 #include <linux/netfilter/nf_conntrack_common.h> 12 #include <linux/netfilter/nf_conntrack_tuple_common.h> 13 #include <net/netfilter/nf_conntrack_extend.h> 14 15 struct nf_conntrack_ecache { 16 unsigned long cache; /* bitops want long */ 17 unsigned long missed; /* missed events */ 18 u16 ctmask; /* bitmask of ct events to be delivered */ 19 u16 expmask; /* bitmask of expect events to be delivered */ 20 u32 pid; /* netlink pid of destroyer */ 21 }; 22 23 static inline struct nf_conntrack_ecache * 24 nf_ct_ecache_find(const struct nf_conn *ct) 25 { 26 #ifdef CONFIG_NF_CONNTRACK_EVENTS 27 return nf_ct_ext_find(ct, NF_CT_EXT_ECACHE); 28 #else 29 return NULL; 30 #endif 31 } 32 33 static inline struct nf_conntrack_ecache * 34 nf_ct_ecache_ext_add(struct nf_conn *ct, u16 ctmask, u16 expmask, gfp_t gfp) 35 { 36 #ifdef CONFIG_NF_CONNTRACK_EVENTS 37 struct net *net = nf_ct_net(ct); 38 struct nf_conntrack_ecache *e; 39 40 if (!ctmask && !expmask && net->ct.sysctl_events) { 41 ctmask = ~0; 42 expmask = ~0; 43 } 44 if (!ctmask && !expmask) 45 return NULL; 46 47 e = nf_ct_ext_add(ct, NF_CT_EXT_ECACHE, gfp); 48 if (e) { 49 e->ctmask = ctmask; 50 e->expmask = expmask; 51 } 52 return e; 53 #else 54 return NULL; 55 #endif 56 }; 57 58 #ifdef CONFIG_NF_CONNTRACK_EVENTS 59 /* This structure is passed to event handler */ 60 struct nf_ct_event { 61 struct nf_conn *ct; 62 u32 pid; 63 int report; 64 }; 65 66 struct nf_ct_event_notifier { 67 int (*fcn)(unsigned int events, struct nf_ct_event *item); 68 }; 69 70 extern int nf_conntrack_register_notifier(struct net *net, struct nf_ct_event_notifier *nb); 71 extern void nf_conntrack_unregister_notifier(struct net *net, struct nf_ct_event_notifier *nb); 72 73 extern void nf_ct_deliver_cached_events(struct nf_conn *ct); 74 75 static inline void 76 nf_conntrack_event_cache(enum ip_conntrack_events event, struct nf_conn *ct) 77 { 78 struct net *net = nf_ct_net(ct); 79 struct nf_conntrack_ecache *e; 80 81 if (net->ct.nf_conntrack_event_cb == NULL) 82 return; 83 84 e = nf_ct_ecache_find(ct); 85 if (e == NULL) 86 return; 87 88 set_bit(event, &e->cache); 89 } 90 91 static inline int 92 nf_conntrack_eventmask_report(unsigned int eventmask, 93 struct nf_conn *ct, 94 u32 pid, 95 int report) 96 { 97 int ret = 0; 98 struct net *net = nf_ct_net(ct); 99 struct nf_ct_event_notifier *notify; 100 struct nf_conntrack_ecache *e; 101 102 rcu_read_lock(); 103 notify = rcu_dereference(net->ct.nf_conntrack_event_cb); 104 if (notify == NULL) 105 goto out_unlock; 106 107 e = nf_ct_ecache_find(ct); 108 if (e == NULL) 109 goto out_unlock; 110 111 if (nf_ct_is_confirmed(ct) && !nf_ct_is_dying(ct)) { 112 struct nf_ct_event item = { 113 .ct = ct, 114 .pid = e->pid ? e->pid : pid, 115 .report = report 116 }; 117 /* This is a resent of a destroy event? If so, skip missed */ 118 unsigned long missed = e->pid ? 0 : e->missed; 119 120 if (!((eventmask | missed) & e->ctmask)) 121 goto out_unlock; 122 123 ret = notify->fcn(eventmask | missed, &item); 124 if (unlikely(ret < 0 || missed)) { 125 spin_lock_bh(&ct->lock); 126 if (ret < 0) { 127 /* This is a destroy event that has been 128 * triggered by a process, we store the PID 129 * to include it in the retransmission. */ 130 if (eventmask & (1 << IPCT_DESTROY) && 131 e->pid == 0 && pid != 0) 132 e->pid = pid; 133 else 134 e->missed |= eventmask; 135 } else 136 e->missed &= ~missed; 137 spin_unlock_bh(&ct->lock); 138 } 139 } 140 out_unlock: 141 rcu_read_unlock(); 142 return ret; 143 } 144 145 static inline int 146 nf_conntrack_event_report(enum ip_conntrack_events event, struct nf_conn *ct, 147 u32 pid, int report) 148 { 149 return nf_conntrack_eventmask_report(1 << event, ct, pid, report); 150 } 151 152 static inline int 153 nf_conntrack_event(enum ip_conntrack_events event, struct nf_conn *ct) 154 { 155 return nf_conntrack_eventmask_report(1 << event, ct, 0, 0); 156 } 157 158 struct nf_exp_event { 159 struct nf_conntrack_expect *exp; 160 u32 pid; 161 int report; 162 }; 163 164 struct nf_exp_event_notifier { 165 int (*fcn)(unsigned int events, struct nf_exp_event *item); 166 }; 167 168 extern int nf_ct_expect_register_notifier(struct net *net, struct nf_exp_event_notifier *nb); 169 extern void nf_ct_expect_unregister_notifier(struct net *net, struct nf_exp_event_notifier *nb); 170 171 static inline void 172 nf_ct_expect_event_report(enum ip_conntrack_expect_events event, 173 struct nf_conntrack_expect *exp, 174 u32 pid, 175 int report) 176 { 177 struct net *net = nf_ct_exp_net(exp); 178 struct nf_exp_event_notifier *notify; 179 struct nf_conntrack_ecache *e; 180 181 rcu_read_lock(); 182 notify = rcu_dereference(net->ct.nf_expect_event_cb); 183 if (notify == NULL) 184 goto out_unlock; 185 186 e = nf_ct_ecache_find(exp->master); 187 if (e == NULL) 188 goto out_unlock; 189 190 if (e->expmask & (1 << event)) { 191 struct nf_exp_event item = { 192 .exp = exp, 193 .pid = pid, 194 .report = report 195 }; 196 notify->fcn(1 << event, &item); 197 } 198 out_unlock: 199 rcu_read_unlock(); 200 } 201 202 static inline void 203 nf_ct_expect_event(enum ip_conntrack_expect_events event, 204 struct nf_conntrack_expect *exp) 205 { 206 nf_ct_expect_event_report(event, exp, 0, 0); 207 } 208 209 extern int nf_conntrack_ecache_init(struct net *net); 210 extern void nf_conntrack_ecache_fini(struct net *net); 211 212 #else /* CONFIG_NF_CONNTRACK_EVENTS */ 213 214 static inline void nf_conntrack_event_cache(enum ip_conntrack_events event, 215 struct nf_conn *ct) {} 216 static inline int nf_conntrack_eventmask_report(unsigned int eventmask, 217 struct nf_conn *ct, 218 u32 pid, 219 int report) { return 0; } 220 static inline int nf_conntrack_event(enum ip_conntrack_events event, 221 struct nf_conn *ct) { return 0; } 222 static inline int nf_conntrack_event_report(enum ip_conntrack_events event, 223 struct nf_conn *ct, 224 u32 pid, 225 int report) { return 0; } 226 static inline void nf_ct_deliver_cached_events(const struct nf_conn *ct) {} 227 static inline void nf_ct_expect_event(enum ip_conntrack_expect_events event, 228 struct nf_conntrack_expect *exp) {} 229 static inline void nf_ct_expect_event_report(enum ip_conntrack_expect_events e, 230 struct nf_conntrack_expect *exp, 231 u32 pid, 232 int report) {} 233 234 static inline int nf_conntrack_ecache_init(struct net *net) 235 { 236 return 0; 237 } 238 239 static inline void nf_conntrack_ecache_fini(struct net *net) 240 { 241 } 242 #endif /* CONFIG_NF_CONNTRACK_EVENTS */ 243 244 #endif /*_NF_CONNTRACK_ECACHE_H*/ 245 246