Commit 7c8011895330d3069b137233e2673f40ee6f4c91

Authored by David S. Miller
1 parent 48f03bdad8

nfnetlink_acct: Stop using NLA_PUT*().

These macros contain a hidden goto, and are thus extremely error
prone and make code hard to audit.

Signed-off-by: David S. Miller <davem@davemloft.net>

Showing 1 changed file with 6 additions and 4 deletions Inline Diff

net/netfilter/nfnetlink_acct.c
1 /* 1 /*
2 * (C) 2011 Pablo Neira Ayuso <pablo@netfilter.org> 2 * (C) 2011 Pablo Neira Ayuso <pablo@netfilter.org>
3 * (C) 2011 Intra2net AG <http://www.intra2net.com> 3 * (C) 2011 Intra2net AG <http://www.intra2net.com>
4 * 4 *
5 * This program is free software; you can redistribute it and/or modify 5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 as 6 * it under the terms of the GNU General Public License version 2 as
7 * published by the Free Software Foundation (or any later at your option). 7 * published by the Free Software Foundation (or any later at your option).
8 */ 8 */
9 #include <linux/init.h> 9 #include <linux/init.h>
10 #include <linux/module.h> 10 #include <linux/module.h>
11 #include <linux/kernel.h> 11 #include <linux/kernel.h>
12 #include <linux/skbuff.h> 12 #include <linux/skbuff.h>
13 #include <linux/atomic.h> 13 #include <linux/atomic.h>
14 #include <linux/netlink.h> 14 #include <linux/netlink.h>
15 #include <linux/rculist.h> 15 #include <linux/rculist.h>
16 #include <linux/slab.h> 16 #include <linux/slab.h>
17 #include <linux/types.h> 17 #include <linux/types.h>
18 #include <linux/errno.h> 18 #include <linux/errno.h>
19 #include <net/netlink.h> 19 #include <net/netlink.h>
20 #include <net/sock.h> 20 #include <net/sock.h>
21 21
22 #include <linux/netfilter.h> 22 #include <linux/netfilter.h>
23 #include <linux/netfilter/nfnetlink.h> 23 #include <linux/netfilter/nfnetlink.h>
24 #include <linux/netfilter/nfnetlink_acct.h> 24 #include <linux/netfilter/nfnetlink_acct.h>
25 25
26 MODULE_LICENSE("GPL"); 26 MODULE_LICENSE("GPL");
27 MODULE_AUTHOR("Pablo Neira Ayuso <pablo@netfilter.org>"); 27 MODULE_AUTHOR("Pablo Neira Ayuso <pablo@netfilter.org>");
28 MODULE_DESCRIPTION("nfacct: Extended Netfilter accounting infrastructure"); 28 MODULE_DESCRIPTION("nfacct: Extended Netfilter accounting infrastructure");
29 29
30 static LIST_HEAD(nfnl_acct_list); 30 static LIST_HEAD(nfnl_acct_list);
31 31
32 struct nf_acct { 32 struct nf_acct {
33 atomic64_t pkts; 33 atomic64_t pkts;
34 atomic64_t bytes; 34 atomic64_t bytes;
35 struct list_head head; 35 struct list_head head;
36 atomic_t refcnt; 36 atomic_t refcnt;
37 char name[NFACCT_NAME_MAX]; 37 char name[NFACCT_NAME_MAX];
38 struct rcu_head rcu_head; 38 struct rcu_head rcu_head;
39 }; 39 };
40 40
41 static int 41 static int
42 nfnl_acct_new(struct sock *nfnl, struct sk_buff *skb, 42 nfnl_acct_new(struct sock *nfnl, struct sk_buff *skb,
43 const struct nlmsghdr *nlh, const struct nlattr * const tb[]) 43 const struct nlmsghdr *nlh, const struct nlattr * const tb[])
44 { 44 {
45 struct nf_acct *nfacct, *matching = NULL; 45 struct nf_acct *nfacct, *matching = NULL;
46 char *acct_name; 46 char *acct_name;
47 47
48 if (!tb[NFACCT_NAME]) 48 if (!tb[NFACCT_NAME])
49 return -EINVAL; 49 return -EINVAL;
50 50
51 acct_name = nla_data(tb[NFACCT_NAME]); 51 acct_name = nla_data(tb[NFACCT_NAME]);
52 52
53 list_for_each_entry(nfacct, &nfnl_acct_list, head) { 53 list_for_each_entry(nfacct, &nfnl_acct_list, head) {
54 if (strncmp(nfacct->name, acct_name, NFACCT_NAME_MAX) != 0) 54 if (strncmp(nfacct->name, acct_name, NFACCT_NAME_MAX) != 0)
55 continue; 55 continue;
56 56
57 if (nlh->nlmsg_flags & NLM_F_EXCL) 57 if (nlh->nlmsg_flags & NLM_F_EXCL)
58 return -EEXIST; 58 return -EEXIST;
59 59
60 matching = nfacct; 60 matching = nfacct;
61 break; 61 break;
62 } 62 }
63 63
64 if (matching) { 64 if (matching) {
65 if (nlh->nlmsg_flags & NLM_F_REPLACE) { 65 if (nlh->nlmsg_flags & NLM_F_REPLACE) {
66 /* reset counters if you request a replacement. */ 66 /* reset counters if you request a replacement. */
67 atomic64_set(&matching->pkts, 0); 67 atomic64_set(&matching->pkts, 0);
68 atomic64_set(&matching->bytes, 0); 68 atomic64_set(&matching->bytes, 0);
69 return 0; 69 return 0;
70 } 70 }
71 return -EBUSY; 71 return -EBUSY;
72 } 72 }
73 73
74 nfacct = kzalloc(sizeof(struct nf_acct), GFP_KERNEL); 74 nfacct = kzalloc(sizeof(struct nf_acct), GFP_KERNEL);
75 if (nfacct == NULL) 75 if (nfacct == NULL)
76 return -ENOMEM; 76 return -ENOMEM;
77 77
78 strncpy(nfacct->name, nla_data(tb[NFACCT_NAME]), NFACCT_NAME_MAX); 78 strncpy(nfacct->name, nla_data(tb[NFACCT_NAME]), NFACCT_NAME_MAX);
79 79
80 if (tb[NFACCT_BYTES]) { 80 if (tb[NFACCT_BYTES]) {
81 atomic64_set(&nfacct->bytes, 81 atomic64_set(&nfacct->bytes,
82 be64_to_cpu(nla_get_u64(tb[NFACCT_BYTES]))); 82 be64_to_cpu(nla_get_u64(tb[NFACCT_BYTES])));
83 } 83 }
84 if (tb[NFACCT_PKTS]) { 84 if (tb[NFACCT_PKTS]) {
85 atomic64_set(&nfacct->pkts, 85 atomic64_set(&nfacct->pkts,
86 be64_to_cpu(nla_get_u64(tb[NFACCT_PKTS]))); 86 be64_to_cpu(nla_get_u64(tb[NFACCT_PKTS])));
87 } 87 }
88 atomic_set(&nfacct->refcnt, 1); 88 atomic_set(&nfacct->refcnt, 1);
89 list_add_tail_rcu(&nfacct->head, &nfnl_acct_list); 89 list_add_tail_rcu(&nfacct->head, &nfnl_acct_list);
90 return 0; 90 return 0;
91 } 91 }
92 92
93 static int 93 static int
94 nfnl_acct_fill_info(struct sk_buff *skb, u32 pid, u32 seq, u32 type, 94 nfnl_acct_fill_info(struct sk_buff *skb, u32 pid, u32 seq, u32 type,
95 int event, struct nf_acct *acct) 95 int event, struct nf_acct *acct)
96 { 96 {
97 struct nlmsghdr *nlh; 97 struct nlmsghdr *nlh;
98 struct nfgenmsg *nfmsg; 98 struct nfgenmsg *nfmsg;
99 unsigned int flags = pid ? NLM_F_MULTI : 0; 99 unsigned int flags = pid ? NLM_F_MULTI : 0;
100 u64 pkts, bytes; 100 u64 pkts, bytes;
101 101
102 event |= NFNL_SUBSYS_ACCT << 8; 102 event |= NFNL_SUBSYS_ACCT << 8;
103 nlh = nlmsg_put(skb, pid, seq, event, sizeof(*nfmsg), flags); 103 nlh = nlmsg_put(skb, pid, seq, event, sizeof(*nfmsg), flags);
104 if (nlh == NULL) 104 if (nlh == NULL)
105 goto nlmsg_failure; 105 goto nlmsg_failure;
106 106
107 nfmsg = nlmsg_data(nlh); 107 nfmsg = nlmsg_data(nlh);
108 nfmsg->nfgen_family = AF_UNSPEC; 108 nfmsg->nfgen_family = AF_UNSPEC;
109 nfmsg->version = NFNETLINK_V0; 109 nfmsg->version = NFNETLINK_V0;
110 nfmsg->res_id = 0; 110 nfmsg->res_id = 0;
111 111
112 NLA_PUT_STRING(skb, NFACCT_NAME, acct->name); 112 if (nla_put_string(skb, NFACCT_NAME, acct->name))
113 goto nla_put_failure;
113 114
114 if (type == NFNL_MSG_ACCT_GET_CTRZERO) { 115 if (type == NFNL_MSG_ACCT_GET_CTRZERO) {
115 pkts = atomic64_xchg(&acct->pkts, 0); 116 pkts = atomic64_xchg(&acct->pkts, 0);
116 bytes = atomic64_xchg(&acct->bytes, 0); 117 bytes = atomic64_xchg(&acct->bytes, 0);
117 } else { 118 } else {
118 pkts = atomic64_read(&acct->pkts); 119 pkts = atomic64_read(&acct->pkts);
119 bytes = atomic64_read(&acct->bytes); 120 bytes = atomic64_read(&acct->bytes);
120 } 121 }
121 NLA_PUT_BE64(skb, NFACCT_PKTS, cpu_to_be64(pkts)); 122 if (nla_put_be64(skb, NFACCT_PKTS, cpu_to_be64(pkts)) ||
122 NLA_PUT_BE64(skb, NFACCT_BYTES, cpu_to_be64(bytes)); 123 nla_put_be64(skb, NFACCT_BYTES, cpu_to_be64(bytes)) ||
123 NLA_PUT_BE32(skb, NFACCT_USE, htonl(atomic_read(&acct->refcnt))); 124 nla_put_be32(skb, NFACCT_USE, htonl(atomic_read(&acct->refcnt))))
125 goto nla_put_failure;
124 126
125 nlmsg_end(skb, nlh); 127 nlmsg_end(skb, nlh);
126 return skb->len; 128 return skb->len;
127 129
128 nlmsg_failure: 130 nlmsg_failure:
129 nla_put_failure: 131 nla_put_failure:
130 nlmsg_cancel(skb, nlh); 132 nlmsg_cancel(skb, nlh);
131 return -1; 133 return -1;
132 } 134 }
133 135
134 static int 136 static int
135 nfnl_acct_dump(struct sk_buff *skb, struct netlink_callback *cb) 137 nfnl_acct_dump(struct sk_buff *skb, struct netlink_callback *cb)
136 { 138 {
137 struct nf_acct *cur, *last; 139 struct nf_acct *cur, *last;
138 140
139 if (cb->args[2]) 141 if (cb->args[2])
140 return 0; 142 return 0;
141 143
142 last = (struct nf_acct *)cb->args[1]; 144 last = (struct nf_acct *)cb->args[1];
143 if (cb->args[1]) 145 if (cb->args[1])
144 cb->args[1] = 0; 146 cb->args[1] = 0;
145 147
146 rcu_read_lock(); 148 rcu_read_lock();
147 list_for_each_entry_rcu(cur, &nfnl_acct_list, head) { 149 list_for_each_entry_rcu(cur, &nfnl_acct_list, head) {
148 if (last && cur != last) 150 if (last && cur != last)
149 continue; 151 continue;
150 152
151 if (nfnl_acct_fill_info(skb, NETLINK_CB(cb->skb).pid, 153 if (nfnl_acct_fill_info(skb, NETLINK_CB(cb->skb).pid,
152 cb->nlh->nlmsg_seq, 154 cb->nlh->nlmsg_seq,
153 NFNL_MSG_TYPE(cb->nlh->nlmsg_type), 155 NFNL_MSG_TYPE(cb->nlh->nlmsg_type),
154 NFNL_MSG_ACCT_NEW, cur) < 0) { 156 NFNL_MSG_ACCT_NEW, cur) < 0) {
155 cb->args[1] = (unsigned long)cur; 157 cb->args[1] = (unsigned long)cur;
156 break; 158 break;
157 } 159 }
158 } 160 }
159 if (!cb->args[1]) 161 if (!cb->args[1])
160 cb->args[2] = 1; 162 cb->args[2] = 1;
161 rcu_read_unlock(); 163 rcu_read_unlock();
162 return skb->len; 164 return skb->len;
163 } 165 }
164 166
165 static int 167 static int
166 nfnl_acct_get(struct sock *nfnl, struct sk_buff *skb, 168 nfnl_acct_get(struct sock *nfnl, struct sk_buff *skb,
167 const struct nlmsghdr *nlh, const struct nlattr * const tb[]) 169 const struct nlmsghdr *nlh, const struct nlattr * const tb[])
168 { 170 {
169 int ret = -ENOENT; 171 int ret = -ENOENT;
170 struct nf_acct *cur; 172 struct nf_acct *cur;
171 char *acct_name; 173 char *acct_name;
172 174
173 if (nlh->nlmsg_flags & NLM_F_DUMP) { 175 if (nlh->nlmsg_flags & NLM_F_DUMP) {
174 struct netlink_dump_control c = { 176 struct netlink_dump_control c = {
175 .dump = nfnl_acct_dump, 177 .dump = nfnl_acct_dump,
176 }; 178 };
177 return netlink_dump_start(nfnl, skb, nlh, &c); 179 return netlink_dump_start(nfnl, skb, nlh, &c);
178 } 180 }
179 181
180 if (!tb[NFACCT_NAME]) 182 if (!tb[NFACCT_NAME])
181 return -EINVAL; 183 return -EINVAL;
182 acct_name = nla_data(tb[NFACCT_NAME]); 184 acct_name = nla_data(tb[NFACCT_NAME]);
183 185
184 list_for_each_entry(cur, &nfnl_acct_list, head) { 186 list_for_each_entry(cur, &nfnl_acct_list, head) {
185 struct sk_buff *skb2; 187 struct sk_buff *skb2;
186 188
187 if (strncmp(cur->name, acct_name, NFACCT_NAME_MAX)!= 0) 189 if (strncmp(cur->name, acct_name, NFACCT_NAME_MAX)!= 0)
188 continue; 190 continue;
189 191
190 skb2 = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); 192 skb2 = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
191 if (skb2 == NULL) { 193 if (skb2 == NULL) {
192 ret = -ENOMEM; 194 ret = -ENOMEM;
193 break; 195 break;
194 } 196 }
195 197
196 ret = nfnl_acct_fill_info(skb2, NETLINK_CB(skb).pid, 198 ret = nfnl_acct_fill_info(skb2, NETLINK_CB(skb).pid,
197 nlh->nlmsg_seq, 199 nlh->nlmsg_seq,
198 NFNL_MSG_TYPE(nlh->nlmsg_type), 200 NFNL_MSG_TYPE(nlh->nlmsg_type),
199 NFNL_MSG_ACCT_NEW, cur); 201 NFNL_MSG_ACCT_NEW, cur);
200 if (ret <= 0) { 202 if (ret <= 0) {
201 kfree_skb(skb2); 203 kfree_skb(skb2);
202 break; 204 break;
203 } 205 }
204 ret = netlink_unicast(nfnl, skb2, NETLINK_CB(skb).pid, 206 ret = netlink_unicast(nfnl, skb2, NETLINK_CB(skb).pid,
205 MSG_DONTWAIT); 207 MSG_DONTWAIT);
206 if (ret > 0) 208 if (ret > 0)
207 ret = 0; 209 ret = 0;
208 210
209 /* this avoids a loop in nfnetlink. */ 211 /* this avoids a loop in nfnetlink. */
210 return ret == -EAGAIN ? -ENOBUFS : ret; 212 return ret == -EAGAIN ? -ENOBUFS : ret;
211 } 213 }
212 return ret; 214 return ret;
213 } 215 }
214 216
215 /* try to delete object, fail if it is still in use. */ 217 /* try to delete object, fail if it is still in use. */
216 static int nfnl_acct_try_del(struct nf_acct *cur) 218 static int nfnl_acct_try_del(struct nf_acct *cur)
217 { 219 {
218 int ret = 0; 220 int ret = 0;
219 221
220 /* we want to avoid races with nfnl_acct_find_get. */ 222 /* we want to avoid races with nfnl_acct_find_get. */
221 if (atomic_dec_and_test(&cur->refcnt)) { 223 if (atomic_dec_and_test(&cur->refcnt)) {
222 /* We are protected by nfnl mutex. */ 224 /* We are protected by nfnl mutex. */
223 list_del_rcu(&cur->head); 225 list_del_rcu(&cur->head);
224 kfree_rcu(cur, rcu_head); 226 kfree_rcu(cur, rcu_head);
225 } else { 227 } else {
226 /* still in use, restore reference counter. */ 228 /* still in use, restore reference counter. */
227 atomic_inc(&cur->refcnt); 229 atomic_inc(&cur->refcnt);
228 ret = -EBUSY; 230 ret = -EBUSY;
229 } 231 }
230 return ret; 232 return ret;
231 } 233 }
232 234
233 static int 235 static int
234 nfnl_acct_del(struct sock *nfnl, struct sk_buff *skb, 236 nfnl_acct_del(struct sock *nfnl, struct sk_buff *skb,
235 const struct nlmsghdr *nlh, const struct nlattr * const tb[]) 237 const struct nlmsghdr *nlh, const struct nlattr * const tb[])
236 { 238 {
237 char *acct_name; 239 char *acct_name;
238 struct nf_acct *cur; 240 struct nf_acct *cur;
239 int ret = -ENOENT; 241 int ret = -ENOENT;
240 242
241 if (!tb[NFACCT_NAME]) { 243 if (!tb[NFACCT_NAME]) {
242 list_for_each_entry(cur, &nfnl_acct_list, head) 244 list_for_each_entry(cur, &nfnl_acct_list, head)
243 nfnl_acct_try_del(cur); 245 nfnl_acct_try_del(cur);
244 246
245 return 0; 247 return 0;
246 } 248 }
247 acct_name = nla_data(tb[NFACCT_NAME]); 249 acct_name = nla_data(tb[NFACCT_NAME]);
248 250
249 list_for_each_entry(cur, &nfnl_acct_list, head) { 251 list_for_each_entry(cur, &nfnl_acct_list, head) {
250 if (strncmp(cur->name, acct_name, NFACCT_NAME_MAX) != 0) 252 if (strncmp(cur->name, acct_name, NFACCT_NAME_MAX) != 0)
251 continue; 253 continue;
252 254
253 ret = nfnl_acct_try_del(cur); 255 ret = nfnl_acct_try_del(cur);
254 if (ret < 0) 256 if (ret < 0)
255 return ret; 257 return ret;
256 258
257 break; 259 break;
258 } 260 }
259 return ret; 261 return ret;
260 } 262 }
261 263
262 static const struct nla_policy nfnl_acct_policy[NFACCT_MAX+1] = { 264 static const struct nla_policy nfnl_acct_policy[NFACCT_MAX+1] = {
263 [NFACCT_NAME] = { .type = NLA_NUL_STRING, .len = NFACCT_NAME_MAX-1 }, 265 [NFACCT_NAME] = { .type = NLA_NUL_STRING, .len = NFACCT_NAME_MAX-1 },
264 [NFACCT_BYTES] = { .type = NLA_U64 }, 266 [NFACCT_BYTES] = { .type = NLA_U64 },
265 [NFACCT_PKTS] = { .type = NLA_U64 }, 267 [NFACCT_PKTS] = { .type = NLA_U64 },
266 }; 268 };
267 269
268 static const struct nfnl_callback nfnl_acct_cb[NFNL_MSG_ACCT_MAX] = { 270 static const struct nfnl_callback nfnl_acct_cb[NFNL_MSG_ACCT_MAX] = {
269 [NFNL_MSG_ACCT_NEW] = { .call = nfnl_acct_new, 271 [NFNL_MSG_ACCT_NEW] = { .call = nfnl_acct_new,
270 .attr_count = NFACCT_MAX, 272 .attr_count = NFACCT_MAX,
271 .policy = nfnl_acct_policy }, 273 .policy = nfnl_acct_policy },
272 [NFNL_MSG_ACCT_GET] = { .call = nfnl_acct_get, 274 [NFNL_MSG_ACCT_GET] = { .call = nfnl_acct_get,
273 .attr_count = NFACCT_MAX, 275 .attr_count = NFACCT_MAX,
274 .policy = nfnl_acct_policy }, 276 .policy = nfnl_acct_policy },
275 [NFNL_MSG_ACCT_GET_CTRZERO] = { .call = nfnl_acct_get, 277 [NFNL_MSG_ACCT_GET_CTRZERO] = { .call = nfnl_acct_get,
276 .attr_count = NFACCT_MAX, 278 .attr_count = NFACCT_MAX,
277 .policy = nfnl_acct_policy }, 279 .policy = nfnl_acct_policy },
278 [NFNL_MSG_ACCT_DEL] = { .call = nfnl_acct_del, 280 [NFNL_MSG_ACCT_DEL] = { .call = nfnl_acct_del,
279 .attr_count = NFACCT_MAX, 281 .attr_count = NFACCT_MAX,
280 .policy = nfnl_acct_policy }, 282 .policy = nfnl_acct_policy },
281 }; 283 };
282 284
283 static const struct nfnetlink_subsystem nfnl_acct_subsys = { 285 static const struct nfnetlink_subsystem nfnl_acct_subsys = {
284 .name = "acct", 286 .name = "acct",
285 .subsys_id = NFNL_SUBSYS_ACCT, 287 .subsys_id = NFNL_SUBSYS_ACCT,
286 .cb_count = NFNL_MSG_ACCT_MAX, 288 .cb_count = NFNL_MSG_ACCT_MAX,
287 .cb = nfnl_acct_cb, 289 .cb = nfnl_acct_cb,
288 }; 290 };
289 291
290 MODULE_ALIAS_NFNL_SUBSYS(NFNL_SUBSYS_ACCT); 292 MODULE_ALIAS_NFNL_SUBSYS(NFNL_SUBSYS_ACCT);
291 293
292 struct nf_acct *nfnl_acct_find_get(const char *acct_name) 294 struct nf_acct *nfnl_acct_find_get(const char *acct_name)
293 { 295 {
294 struct nf_acct *cur, *acct = NULL; 296 struct nf_acct *cur, *acct = NULL;
295 297
296 rcu_read_lock(); 298 rcu_read_lock();
297 list_for_each_entry_rcu(cur, &nfnl_acct_list, head) { 299 list_for_each_entry_rcu(cur, &nfnl_acct_list, head) {
298 if (strncmp(cur->name, acct_name, NFACCT_NAME_MAX)!= 0) 300 if (strncmp(cur->name, acct_name, NFACCT_NAME_MAX)!= 0)
299 continue; 301 continue;
300 302
301 if (!try_module_get(THIS_MODULE)) 303 if (!try_module_get(THIS_MODULE))
302 goto err; 304 goto err;
303 305
304 if (!atomic_inc_not_zero(&cur->refcnt)) { 306 if (!atomic_inc_not_zero(&cur->refcnt)) {
305 module_put(THIS_MODULE); 307 module_put(THIS_MODULE);
306 goto err; 308 goto err;
307 } 309 }
308 310
309 acct = cur; 311 acct = cur;
310 break; 312 break;
311 } 313 }
312 err: 314 err:
313 rcu_read_unlock(); 315 rcu_read_unlock();
314 return acct; 316 return acct;
315 } 317 }
316 EXPORT_SYMBOL_GPL(nfnl_acct_find_get); 318 EXPORT_SYMBOL_GPL(nfnl_acct_find_get);
317 319
318 void nfnl_acct_put(struct nf_acct *acct) 320 void nfnl_acct_put(struct nf_acct *acct)
319 { 321 {
320 atomic_dec(&acct->refcnt); 322 atomic_dec(&acct->refcnt);
321 module_put(THIS_MODULE); 323 module_put(THIS_MODULE);
322 } 324 }
323 EXPORT_SYMBOL_GPL(nfnl_acct_put); 325 EXPORT_SYMBOL_GPL(nfnl_acct_put);
324 326
325 void nfnl_acct_update(const struct sk_buff *skb, struct nf_acct *nfacct) 327 void nfnl_acct_update(const struct sk_buff *skb, struct nf_acct *nfacct)
326 { 328 {
327 atomic64_inc(&nfacct->pkts); 329 atomic64_inc(&nfacct->pkts);
328 atomic64_add(skb->len, &nfacct->bytes); 330 atomic64_add(skb->len, &nfacct->bytes);
329 } 331 }
330 EXPORT_SYMBOL_GPL(nfnl_acct_update); 332 EXPORT_SYMBOL_GPL(nfnl_acct_update);
331 333
332 static int __init nfnl_acct_init(void) 334 static int __init nfnl_acct_init(void)
333 { 335 {
334 int ret; 336 int ret;
335 337
336 pr_info("nfnl_acct: registering with nfnetlink.\n"); 338 pr_info("nfnl_acct: registering with nfnetlink.\n");
337 ret = nfnetlink_subsys_register(&nfnl_acct_subsys); 339 ret = nfnetlink_subsys_register(&nfnl_acct_subsys);
338 if (ret < 0) { 340 if (ret < 0) {
339 pr_err("nfnl_acct_init: cannot register with nfnetlink.\n"); 341 pr_err("nfnl_acct_init: cannot register with nfnetlink.\n");
340 goto err_out; 342 goto err_out;
341 } 343 }
342 return 0; 344 return 0;
343 err_out: 345 err_out:
344 return ret; 346 return ret;
345 } 347 }
346 348
347 static void __exit nfnl_acct_exit(void) 349 static void __exit nfnl_acct_exit(void)
348 { 350 {
349 struct nf_acct *cur, *tmp; 351 struct nf_acct *cur, *tmp;
350 352
351 pr_info("nfnl_acct: unregistering from nfnetlink.\n"); 353 pr_info("nfnl_acct: unregistering from nfnetlink.\n");
352 nfnetlink_subsys_unregister(&nfnl_acct_subsys); 354 nfnetlink_subsys_unregister(&nfnl_acct_subsys);
353 355
354 list_for_each_entry_safe(cur, tmp, &nfnl_acct_list, head) { 356 list_for_each_entry_safe(cur, tmp, &nfnl_acct_list, head) {
355 list_del_rcu(&cur->head); 357 list_del_rcu(&cur->head);
356 /* We are sure that our objects have no clients at this point, 358 /* We are sure that our objects have no clients at this point,
357 * it's safe to release them all without checking refcnt. */ 359 * it's safe to release them all without checking refcnt. */
358 kfree_rcu(cur, rcu_head); 360 kfree_rcu(cur, rcu_head);
359 } 361 }
360 } 362 }
361 363
362 module_init(nfnl_acct_init); 364 module_init(nfnl_acct_init);
363 module_exit(nfnl_acct_exit); 365 module_exit(nfnl_acct_exit);
364 366