]> git.pld-linux.org Git - packages/kernel.git/blob - pom-ng-ACCOUNT-20060504.patch
- release 4
[packages/kernel.git] / pom-ng-ACCOUNT-20060504.patch
1  include/linux/netfilter_ipv4/ipt_ACCOUNT.h |  100 ++
2  net/ipv4/netfilter/Makefile                |    1 
3  net/ipv4/netfilter/ipt_ACCOUNT.c           | 1103 +++++++++++++++++++++++++++++
4  3 files changed, 1204 insertions(+)
5
6 diff -Nur --exclude '*.orig' linux.org/include/linux/netfilter_ipv4/ipt_ACCOUNT.h linux/include/linux/netfilter_ipv4/ipt_ACCOUNT.h
7 --- linux.org/include/linux/netfilter_ipv4/ipt_ACCOUNT.h        1970-01-01 01:00:00.000000000 +0100
8 +++ linux/include/linux/netfilter_ipv4/ipt_ACCOUNT.h    2006-05-04 11:39:36.000000000 +0200
9 @@ -0,0 +1,100 @@
10 +/***************************************************************************
11 + *   Copyright (C) 2004 by Intra2net AG                                    *
12 + *   opensource@intra2net.com                                              *
13 + *                                                                         *
14 + *   This program is free software; you can redistribute it and/or modify  *
15 + *   it under the terms of the GNU General Public License                  *
16 + *   version 2 as published by the Free Software Foundation;               *
17 + *                                                                         *
18 + ***************************************************************************/
19 +
20 +#ifndef _IPT_ACCOUNT_H
21 +#define _IPT_ACCOUNT_H
22 +
23 +#define ACCOUNT_MAX_TABLES 32
24 +#define ACCOUNT_TABLE_NAME_LEN 32
25 +#define ACCOUNT_MAX_HANDLES 10
26 +
27 +/* Structure for the userspace part of ipt_ACCOUNT */
28 +struct ipt_acc_info {
29 +    u_int32_t net_ip;
30 +    u_int32_t net_mask;
31 +    char table_name[ACCOUNT_TABLE_NAME_LEN];
32 +    int32_t table_nr;
33 +};
34 +
35 +/* Internal table structure, generated by check_entry() */
36 +struct ipt_acc_table {
37 +    char name[ACCOUNT_TABLE_NAME_LEN];     /* name of the table */
38 +    u_int32_t ip;                          /* base IP of network */
39 +    u_int32_t netmask;                     /* netmask of the network */
40 +    unsigned char depth;                   /* size of network:
41 +                                                 0: 8 bit, 1: 16bit, 2: 24 bit */
42 +    u_int32_t refcount;                    /* refcount of this table.
43 +                                                 if zero, destroy it */
44 +    u_int32_t itemcount;                   /* number of IPs in this table */
45 +    void *data;                            /* pointer to the actual data,
46 +                                                 depending on netmask */
47 +};
48 +
49 +/* Internal handle structure */
50 +struct ipt_acc_handle {
51 +    u_int32_t ip;                          /* base IP of network. Used for
52 +                                                 caculating the final IP during
53 +                                                 get_data() */
54 +    unsigned char depth;                   /* size of network. See above for
55 +                                                 details */
56 +    u_int32_t itemcount;                   /* number of IPs in this table */
57 +    void *data;                            /* pointer to the actual data,
58 +                                                 depending on size */
59 +};
60 +
61 +/* Handle structure for communication with the userspace library */
62 +struct ipt_acc_handle_sockopt {
63 +    u_int32_t handle_nr;                   /* Used for HANDLE_FREE */
64 +    char name[ACCOUNT_TABLE_NAME_LEN];     /* Used for HANDLE_PREPARE_READ/
65 +                                                 HANDLE_READ_FLUSH */
66 +    u_int32_t itemcount;                   /* Used for HANDLE_PREPARE_READ/
67 +                                                 HANDLE_READ_FLUSH */
68 +};
69 +
70 +/* Used for every IP entry
71 +   Size is 16 bytes so that 256 (class C network) * 16
72 +   fits in one kernel (zero) page */
73 +struct ipt_acc_ip {
74 +    u_int32_t src_packets;
75 +    u_int32_t src_bytes;
76 +    u_int32_t dst_packets;
77 +    u_int32_t dst_bytes;
78 +};
79 +
80 +/*
81 +    Used for every IP when returning data
82 +*/
83 +struct ipt_acc_handle_ip {
84 +    u_int32_t ip;
85 +    u_int32_t src_packets;
86 +    u_int32_t src_bytes;
87 +    u_int32_t dst_packets;
88 +    u_int32_t dst_bytes;
89 +};
90 +
91 +/*
92 +    The IPs are organized as an array so that direct slot
93 +    calculations are possible.
94 +    Only 8 bit networks are preallocated, 16/24 bit networks
95 +    allocate their slots when needed -> very efficent.
96 +*/
97 +struct ipt_acc_mask_24 {
98 +    struct ipt_acc_ip ip[256];
99 +};
100 +
101 +struct ipt_acc_mask_16 {
102 +    struct ipt_acc_mask_24 *mask_24[256];
103 +};
104 +
105 +struct ipt_acc_mask_8 {
106 +    struct ipt_acc_mask_16 *mask_16[256];
107 +};
108 +
109 +#endif /*_IPT_ACCOUNT_H*/
110 diff -Nur --exclude '*.orig' linux.org/net/ipv4/netfilter/Makefile linux/net/ipv4/netfilter/Makefile
111 --- linux.org/net/ipv4/netfilter/Makefile       2006-05-02 23:38:44.000000000 +0200
112 +++ linux/net/ipv4/netfilter/Makefile   2006-05-04 11:39:36.000000000 +0200
113 @@ -0,0 +0,1 @@
114 +obj-$(CONFIG_IP_NF_TARGET_ACCOUNT) += ipt_ACCOUNT.o
115 diff -Nur --exclude '*.orig' linux.org/net/ipv4/netfilter/ipt_ACCOUNT.c linux/net/ipv4/netfilter/ipt_ACCOUNT.c
116 --- linux.org/net/ipv4/netfilter/ipt_ACCOUNT.c  1970-01-01 01:00:00.000000000 +0100
117 +++ linux/net/ipv4/netfilter/ipt_ACCOUNT.c      2006-05-04 11:39:36.000000000 +0200
118 @@ -0,0 +1,1103 @@
119 +/***************************************************************************
120 + *   This is a module which is used for counting packets.                  *
121 + *   See http://www.intra2net.com/opensource/ipt_account                   *
122 + *   for further information                                               *
123 + *                                                                         * 
124 + *   Copyright (C) 2004-2005 by Intra2net AG                               *
125 + *   opensource@intra2net.com                                              *
126 + *                                                                         *
127 + *   This program is free software; you can redistribute it and/or modify  *
128 + *   it under the terms of the GNU General Public License                  *
129 + *   version 2 as published by the Free Software Foundation;               *
130 + *                                                                         *
131 + ***************************************************************************/
132 +
133 +#include <linux/module.h>
134 +#include <linux/skbuff.h>
135 +#include <linux/ip.h>
136 +#include <net/icmp.h>
137 +#include <net/udp.h>
138 +#include <net/tcp.h>
139 +#include <linux/netfilter_ipv4/ip_tables.h>
140 +#include <linux/netfilter_ipv4/lockhelp.h>
141 +#include <asm/semaphore.h>
142 +#include <linux/kernel.h>
143 +#include <linux/mm.h>
144 +#include <linux/string.h>
145 +#include <asm/uaccess.h>
146 +
147 +#include <net/route.h>
148 +#include <linux/netfilter_ipv4/ipt_ACCOUNT.h>
149 +
150 +#if 0
151 +#define DEBUGP printk
152 +#else
153 +#define DEBUGP(format, args...)
154 +#endif
155 +
156 +#if (PAGE_SIZE < 4096)
157 +#error "ipt_ACCOUNT needs at least a PAGE_SIZE of 4096"
158 +#endif
159 +
160 +static struct ipt_acc_table *ipt_acc_tables = NULL;
161 +static struct ipt_acc_handle *ipt_acc_handles = NULL;
162 +static void *ipt_acc_tmpbuf = NULL;
163 +
164 +/* Spinlock used for manipulating the current accounting tables/data */
165 +DECLARE_LOCK(ipt_acc_lock);
166 +/* Mutex (semaphore) used for manipulating userspace handles/snapshot data */
167 +static struct semaphore ipt_acc_userspace_mutex;
168 +
169 +
170 +/* Recursive free of all data structures */
171 +static void ipt_acc_data_free(void *data, unsigned char depth)
172 +{
173 +    /* Empty data set */
174 +    if (!data)
175 +        return;
176 +
177 +    /* Free for 8 bit network */
178 +    if (depth == 0) {
179 +        free_page((unsigned long)data);
180 +        return;
181 +    }
182 +
183 +    /* Free for 16 bit network */
184 +    if (depth == 1) {
185 +        struct ipt_acc_mask_16 *mask_16 = (struct ipt_acc_mask_16 *)data;
186 +        u_int32_t b;
187 +        for (b=0; b <= 255; b++) {
188 +            if (mask_16->mask_24[b] != 0) {
189 +                free_page((unsigned long)mask_16->mask_24[b]);
190 +            }
191 +        }
192 +        free_page((unsigned long)data);
193 +        return;
194 +    }
195 +
196 +    /* Free for 24 bit network */
197 +    if (depth == 2) {
198 +        u_int32_t a, b;
199 +        for (a=0; a <= 255; a++) {
200 +            if (((struct ipt_acc_mask_8 *)data)->mask_16[a]) {
201 +                struct ipt_acc_mask_16 *mask_16 = (struct ipt_acc_mask_16*)
202 +                                   ((struct ipt_acc_mask_8 *)data)->mask_16[a];
203 +                
204 +                for (b=0; b <= 255; b++) {
205 +                    if (mask_16->mask_24[b]) {
206 +                        free_page((unsigned long)mask_16->mask_24[b]);
207 +                    }
208 +                }
209 +                free_page((unsigned long)mask_16);
210 +            }
211 +        }
212 +        free_page((unsigned long)data);
213 +        return;
214 +    }
215 +
216 +    printk("ACCOUNT: ipt_acc_data_free called with unknown depth: %d\n", 
217 +           depth);
218 +    return;
219 +}
220 +
221 +/* Look for existing table / insert new one. 
222 +   Return internal ID or -1 on error */
223 +static int ipt_acc_table_insert(char *name, u_int32_t ip, u_int32_t netmask)
224 +{
225 +    u_int32_t i;
226 +
227 +    DEBUGP("ACCOUNT: ipt_acc_table_insert: %s, %u.%u.%u.%u/%u.%u.%u.%u\n",
228 +                                         name, NIPQUAD(ip), NIPQUAD(netmask));
229 +
230 +    /* Look for existing table */
231 +    for (i = 0; i < ACCOUNT_MAX_TABLES; i++) {
232 +        if (strncmp(ipt_acc_tables[i].name, name, 
233 +                    ACCOUNT_TABLE_NAME_LEN) == 0) {
234 +            DEBUGP("ACCOUNT: Found existing slot: %d - "
235 +                   "%u.%u.%u.%u/%u.%u.%u.%u\n", i, 
236 +                   NIPQUAD(ipt_acc_tables[i].ip), 
237 +                   NIPQUAD(ipt_acc_tables[i].netmask));
238 +
239 +            if (ipt_acc_tables[i].ip != ip 
240 +                || ipt_acc_tables[i].netmask != netmask) {
241 +                printk("ACCOUNT: Table %s found, but IP/netmask mismatch. "
242 +                       "IP/netmask found: %u.%u.%u.%u/%u.%u.%u.%u\n",
243 +                       name, NIPQUAD(ipt_acc_tables[i].ip), 
244 +                       NIPQUAD(ipt_acc_tables[i].netmask));
245 +                return -1;
246 +            }
247 +
248 +            ipt_acc_tables[i].refcount++;
249 +            DEBUGP("ACCOUNT: Refcount: %d\n", ipt_acc_tables[i].refcount);
250 +            return i;
251 +        }
252 +    }
253 +
254 +    /* Insert new table */
255 +    for (i = 0; i < ACCOUNT_MAX_TABLES; i++) {
256 +        /* Found free slot */
257 +        if (ipt_acc_tables[i].name[0] == 0) {
258 +            u_int32_t calc_mask, netsize=0;
259 +            int j;  /* needs to be signed, otherwise we risk endless loop */
260 +            
261 +            DEBUGP("ACCOUNT: Found free slot: %d\n", i);
262 +            strncpy (ipt_acc_tables[i].name, name, ACCOUNT_TABLE_NAME_LEN-1);
263 +
264 +            ipt_acc_tables[i].ip = ip;
265 +            ipt_acc_tables[i].netmask = netmask;
266 +
267 +            /* Calculate netsize */
268 +            calc_mask = htonl(netmask);
269 +            for (j = 31; j >= 0; j--) {
270 +                if (calc_mask&(1<<j))
271 +                    netsize++;
272 +                else
273 +                    break;
274 +            }
275 +
276 +            /* Calculate depth from netsize */
277 +            if (netsize >= 24)
278 +                ipt_acc_tables[i].depth = 0;
279 +            else if (netsize >= 16)
280 +                ipt_acc_tables[i].depth = 1;
281 +            else if(netsize >= 8)
282 +                ipt_acc_tables[i].depth = 2;
283 +
284 +            DEBUGP("ACCOUNT: calculated netsize: %u -> "
285 +                   "ipt_acc_table depth %u\n", netsize, 
286 +                   ipt_acc_tables[i].depth);
287 +
288 +            ipt_acc_tables[i].refcount++;
289 +            if ((ipt_acc_tables[i].data
290 +                = (void *)get_zeroed_page(GFP_ATOMIC)) == NULL) {
291 +                printk("ACCOUNT: out of memory for data of table: %s\n", name);
292 +                memset(&ipt_acc_tables[i], 0, 
293 +                       sizeof(struct ipt_acc_table));
294 +                return -1;
295 +            }
296 +
297 +            return i;
298 +        }
299 +    }
300 +
301 +    /* No free slot found */
302 +    printk("ACCOUNT: No free table slot found (max: %d). "
303 +           "Please increase ACCOUNT_MAX_TABLES.\n", ACCOUNT_MAX_TABLES);
304 +    return -1;
305 +}
306 +
307 +static int ipt_acc_checkentry(const char *tablename,
308 +                                  const struct ipt_entry *e,
309 +                                  void *targinfo,
310 +                                  unsigned int targinfosize,
311 +                                  unsigned int hook_mask)
312 +{
313 +    struct ipt_acc_info *info = targinfo;
314 +    int table_nr;
315 +
316 +    if (targinfosize != IPT_ALIGN(sizeof(struct ipt_acc_info))) {
317 +        DEBUGP("ACCOUNT: targinfosize %u != %u\n",
318 +               targinfosize, IPT_ALIGN(sizeof(struct ipt_acc_info)));
319 +        return 0;
320 +    }
321 +
322 +    LOCK_BH(&ipt_acc_lock);
323 +    table_nr = ipt_acc_table_insert(info->table_name, info->net_ip,
324 +                                                      info->net_mask);
325 +    UNLOCK_BH(&ipt_acc_lock);
326 +    
327 +    if (table_nr == -1) {
328 +        printk("ACCOUNT: Table insert problem. Aborting\n");
329 +        return 0;
330 +    }
331 +    /* Table nr caching so we don't have to do an extra string compare 
332 +       for every packet */
333 +    info->table_nr = table_nr;
334 +
335 +    return 1;
336 +}
337 +
338 +static void ipt_acc_deleteentry(void *targinfo, unsigned int targinfosize)
339 +{
340 +    u_int32_t i;
341 +    struct ipt_acc_info *info = targinfo;
342 +
343 +    if (targinfosize != IPT_ALIGN(sizeof(struct ipt_acc_info))) {
344 +        DEBUGP("ACCOUNT: targinfosize %u != %u\n",
345 +               targinfosize, IPT_ALIGN(sizeof(struct ipt_acc_info)));
346 +    }
347 +
348 +    LOCK_BH(&ipt_acc_lock);
349 +
350 +    DEBUGP("ACCOUNT: ipt_acc_deleteentry called for table: %s (#%d)\n", 
351 +           info->table_name, info->table_nr);
352 +
353 +    info->table_nr = -1;    /* Set back to original state */
354 +
355 +    /* Look for table */
356 +    for (i = 0; i < ACCOUNT_MAX_TABLES; i++) {
357 +        if (strncmp(ipt_acc_tables[i].name, info->table_name, 
358 +                    ACCOUNT_TABLE_NAME_LEN) == 0) {
359 +            DEBUGP("ACCOUNT: Found table at slot: %d\n", i);
360 +
361 +            ipt_acc_tables[i].refcount--;
362 +            DEBUGP("ACCOUNT: Refcount left: %d\n", 
363 +                   ipt_acc_tables[i].refcount);
364 +
365 +            /* Table not needed anymore? */
366 +            if (ipt_acc_tables[i].refcount == 0) {
367 +                DEBUGP("ACCOUNT: Destroying table at slot: %d\n", i);
368 +                ipt_acc_data_free(ipt_acc_tables[i].data, 
369 +                                      ipt_acc_tables[i].depth);
370 +                memset(&ipt_acc_tables[i], 0, 
371 +                       sizeof(struct ipt_acc_table));
372 +            }
373 +
374 +            UNLOCK_BH(&ipt_acc_lock);
375 +            return;
376 +        }
377 +    }
378 +
379 +    /* Table not found */
380 +    printk("ACCOUNT: Table %s not found for destroy\n", info->table_name);
381 +    UNLOCK_BH(&ipt_acc_lock);
382 +}
383 +
384 +static void ipt_acc_depth0_insert(struct ipt_acc_mask_24 *mask_24,
385 +                               u_int32_t net_ip, u_int32_t netmask,
386 +                               u_int32_t src_ip, u_int32_t dst_ip,
387 +                               u_int32_t size, u_int32_t *itemcount)
388 +{
389 +    unsigned char is_src = 0, is_dst = 0, src_slot, dst_slot;
390 +    char is_src_new_ip = 0, is_dst_new_ip = 0; /* Check if this entry is new */
391 +
392 +    DEBUGP("ACCOUNT: ipt_acc_depth0_insert: %u.%u.%u.%u/%u.%u.%u.%u "
393 +           "for net %u.%u.%u.%u/%u.%u.%u.%u, size: %u\n", NIPQUAD(src_ip), 
394 +           NIPQUAD(dst_ip), NIPQUAD(net_ip), NIPQUAD(netmask), size);
395 +
396 +    /* Check if src/dst is inside our network. */
397 +    /* Special: net_ip = 0.0.0.0/0 gets stored as src in slot 0 */
398 +    if (!netmask)
399 +        src_ip = 0;
400 +    if ((net_ip&netmask) == (src_ip&netmask))
401 +        is_src = 1;
402 +    if ((net_ip&netmask) == (dst_ip&netmask) && netmask)
403 +        is_dst = 1;
404 +
405 +    if (!is_src && !is_dst) {
406 +        DEBUGP("ACCOUNT: Skipping packet %u.%u.%u.%u/%u.%u.%u.%u "
407 +               "for net %u.%u.%u.%u/%u.%u.%u.%u\n", NIPQUAD(src_ip), 
408 +               NIPQUAD(dst_ip), NIPQUAD(net_ip), NIPQUAD(netmask));
409 +        return;
410 +    }
411 +
412 +    /* Calculate array positions */
413 +    src_slot = (unsigned char)((src_ip&0xFF000000) >> 24);
414 +    dst_slot = (unsigned char)((dst_ip&0xFF000000) >> 24);
415 +
416 +    /* Increase size counters */
417 +    if (is_src) {
418 +        /* Calculate network slot */
419 +        DEBUGP("ACCOUNT: Calculated SRC 8 bit network slot: %d\n", src_slot);
420 +        if (!mask_24->ip[src_slot].src_packets 
421 +            && !mask_24->ip[src_slot].dst_packets)
422 +            is_src_new_ip = 1;
423 +
424 +        mask_24->ip[src_slot].src_packets++;
425 +        mask_24->ip[src_slot].src_bytes+=size;
426 +    }
427 +    if (is_dst) {
428 +        DEBUGP("ACCOUNT: Calculated DST 8 bit network slot: %d\n", dst_slot);
429 +        if (!mask_24->ip[dst_slot].src_packets 
430 +            && !mask_24->ip[dst_slot].dst_packets)
431 +            is_dst_new_ip = 1;
432 +
433 +        mask_24->ip[dst_slot].dst_packets++;
434 +        mask_24->ip[dst_slot].dst_bytes+=size;
435 +    }
436 +
437 +    /* Increase itemcounter */
438 +    DEBUGP("ACCOUNT: Itemcounter before: %d\n", *itemcount);
439 +    if (src_slot == dst_slot) {
440 +        if (is_src_new_ip || is_dst_new_ip) {
441 +            DEBUGP("ACCOUNT: src_slot == dst_slot: %d, %d\n", 
442 +                   is_src_new_ip, is_dst_new_ip);
443 +            (*itemcount)++;
444 +        }
445 +    } else {
446 +        if (is_src_new_ip) {
447 +            DEBUGP("ACCOUNT: New src_ip: %u.%u.%u.%u\n", NIPQUAD(src_ip));
448 +            (*itemcount)++;
449 +        }
450 +        if (is_dst_new_ip) {
451 +            DEBUGP("ACCOUNT: New dst_ip: %u.%u.%u.%u\n", NIPQUAD(dst_ip));
452 +            (*itemcount)++;
453 +        }
454 +    }
455 +    DEBUGP("ACCOUNT: Itemcounter after: %d\n", *itemcount);
456 +}
457 +
458 +static void ipt_acc_depth1_insert(struct ipt_acc_mask_16 *mask_16, 
459 +                               u_int32_t net_ip, u_int32_t netmask, 
460 +                               u_int32_t src_ip, u_int32_t dst_ip,
461 +                               u_int32_t size, u_int32_t *itemcount)
462 +{
463 +    /* Do we need to process src IP? */
464 +    if ((net_ip&netmask) == (src_ip&netmask)) {
465 +        unsigned char slot = (unsigned char)((src_ip&0x00FF0000) >> 16);
466 +        DEBUGP("ACCOUNT: Calculated SRC 16 bit network slot: %d\n", slot);
467 +
468 +        /* Do we need to create a new mask_24 bucket? */
469 +        if (!mask_16->mask_24[slot] && (mask_16->mask_24[slot] = 
470 +             (void *)get_zeroed_page(GFP_ATOMIC)) == NULL) {
471 +            printk("ACCOUNT: Can't process packet because out of memory!\n");
472 +            return;
473 +        }
474 +
475 +        ipt_acc_depth0_insert((struct ipt_acc_mask_24 *)mask_16->mask_24[slot],
476 +                                  net_ip, netmask, src_ip, 0, size, itemcount);
477 +    }
478 +
479 +    /* Do we need to process dst IP? */
480 +    if ((net_ip&netmask) == (dst_ip&netmask)) {
481 +        unsigned char slot = (unsigned char)((dst_ip&0x00FF0000) >> 16);
482 +        DEBUGP("ACCOUNT: Calculated DST 16 bit network slot: %d\n", slot);
483 +
484 +        /* Do we need to create a new mask_24 bucket? */
485 +        if (!mask_16->mask_24[slot] && (mask_16->mask_24[slot] 
486 +            = (void *)get_zeroed_page(GFP_ATOMIC)) == NULL) {
487 +            printk("ACCOUT: Can't process packet because out of memory!\n");
488 +            return;
489 +        }
490 +
491 +        ipt_acc_depth0_insert((struct ipt_acc_mask_24 *)mask_16->mask_24[slot],
492 +                                  net_ip, netmask, 0, dst_ip, size, itemcount);
493 +    }
494 +}
495 +
496 +static void ipt_acc_depth2_insert(struct ipt_acc_mask_8 *mask_8, 
497 +                               u_int32_t net_ip, u_int32_t netmask,
498 +                               u_int32_t src_ip, u_int32_t dst_ip,
499 +                               u_int32_t size, u_int32_t *itemcount)
500 +{
501 +    /* Do we need to process src IP? */
502 +    if ((net_ip&netmask) == (src_ip&netmask)) {
503 +        unsigned char slot = (unsigned char)((src_ip&0x0000FF00) >> 8);
504 +        DEBUGP("ACCOUNT: Calculated SRC 24 bit network slot: %d\n", slot);
505 +
506 +        /* Do we need to create a new mask_24 bucket? */
507 +        if (!mask_8->mask_16[slot] && (mask_8->mask_16[slot] 
508 +            = (void *)get_zeroed_page(GFP_ATOMIC)) == NULL) {
509 +            printk("ACCOUNT: Can't process packet because out of memory!\n");
510 +            return;
511 +        }
512 +
513 +        ipt_acc_depth1_insert((struct ipt_acc_mask_16 *)mask_8->mask_16[slot],
514 +                                  net_ip, netmask, src_ip, 0, size, itemcount);
515 +    }
516 +
517 +    /* Do we need to process dst IP? */
518 +    if ((net_ip&netmask) == (dst_ip&netmask)) {
519 +        unsigned char slot = (unsigned char)((dst_ip&0x0000FF00) >> 8);
520 +        DEBUGP("ACCOUNT: Calculated DST 24 bit network slot: %d\n", slot);
521 +
522 +        /* Do we need to create a new mask_24 bucket? */
523 +        if (!mask_8->mask_16[slot] && (mask_8->mask_16[slot] 
524 +            = (void *)get_zeroed_page(GFP_ATOMIC)) == NULL) {
525 +            printk("ACCOUNT: Can't process packet because out of memory!\n");
526 +            return;
527 +        }
528 +
529 +        ipt_acc_depth1_insert((struct ipt_acc_mask_16 *)mask_8->mask_16[slot],
530 +                                  net_ip, netmask, 0, dst_ip, size, itemcount);
531 +    }
532 +}
533 +
534 +static unsigned int ipt_acc_target(struct sk_buff **pskb,
535 +                                       const struct net_device *in,
536 +                                       const struct net_device *out,
537 +                                       unsigned int hooknum,
538 +                                       const void *targinfo,
539 +                                       void *userinfo)
540 +{
541 +    const struct ipt_acc_info *info = 
542 +        (const struct ipt_acc_info *)targinfo;
543 +    u_int32_t src_ip = (*pskb)->nh.iph->saddr;
544 +    u_int32_t dst_ip = (*pskb)->nh.iph->daddr;
545 +    u_int32_t size = ntohs((*pskb)->nh.iph->tot_len);
546 +
547 +    LOCK_BH(&ipt_acc_lock);
548 +
549 +    if (ipt_acc_tables[info->table_nr].name[0] == 0) {
550 +        printk("ACCOUNT: ipt_acc_target: Invalid table id %u. "
551 +               "IPs %u.%u.%u.%u/%u.%u.%u.%u\n", info->table_nr, 
552 +               NIPQUAD(src_ip), NIPQUAD(dst_ip));
553 +        UNLOCK_BH(&ipt_acc_lock);
554 +        return IPT_CONTINUE;
555 +    }
556 +
557 +    /* 8 bit network or "any" network */
558 +    if (ipt_acc_tables[info->table_nr].depth == 0) {
559 +        /* Count packet and check if the IP is new */
560 +        ipt_acc_depth0_insert(
561 +            (struct ipt_acc_mask_24 *)ipt_acc_tables[info->table_nr].data,
562 +            ipt_acc_tables[info->table_nr].ip, 
563 +            ipt_acc_tables[info->table_nr].netmask,
564 +            src_ip, dst_ip, size, &ipt_acc_tables[info->table_nr].itemcount);
565 +        UNLOCK_BH(&ipt_acc_lock);
566 +        return IPT_CONTINUE;
567 +    }
568 +
569 +    /* 16 bit network */
570 +    if (ipt_acc_tables[info->table_nr].depth == 1) {
571 +        ipt_acc_depth1_insert(
572 +            (struct ipt_acc_mask_16 *)ipt_acc_tables[info->table_nr].data,
573 +            ipt_acc_tables[info->table_nr].ip, 
574 +            ipt_acc_tables[info->table_nr].netmask,
575 +            src_ip, dst_ip, size, &ipt_acc_tables[info->table_nr].itemcount);
576 +        UNLOCK_BH(&ipt_acc_lock);
577 +        return IPT_CONTINUE;
578 +    }
579 +
580 +    /* 24 bit network */
581 +    if (ipt_acc_tables[info->table_nr].depth == 2) {
582 +        ipt_acc_depth2_insert(
583 +            (struct ipt_acc_mask_8 *)ipt_acc_tables[info->table_nr].data,
584 +            ipt_acc_tables[info->table_nr].ip, 
585 +            ipt_acc_tables[info->table_nr].netmask,
586 +            src_ip, dst_ip, size, &ipt_acc_tables[info->table_nr].itemcount);
587 +        UNLOCK_BH(&ipt_acc_lock);
588 +        return IPT_CONTINUE;
589 +    }
590 +
591 +    printk("ACCOUNT: ipt_acc_target: Unable to process packet. "
592 +           "Table id %u. IPs %u.%u.%u.%u/%u.%u.%u.%u\n", 
593 +           info->table_nr, NIPQUAD(src_ip), NIPQUAD(dst_ip));
594 +
595 +    UNLOCK_BH(&ipt_acc_lock);
596 +    return IPT_CONTINUE;
597 +}
598 +
599 +/*
600 +    Functions dealing with "handles":
601 +    Handles are snapshots of a accounting state.
602 +    
603 +    read snapshots are only for debugging the code
604 +    and are very expensive concerning speed/memory
605 +    compared to read_and_flush.
606 +    
607 +    The functions aren't protected by spinlocks themselves
608 +    as this is done in the ioctl part of the code.
609 +*/
610 +
611 +/*
612 +    Find a free handle slot. Normally only one should be used,
613 +    but there could be two or more applications accessing the data
614 +    at the same time.
615 +*/
616 +static int ipt_acc_handle_find_slot(void)
617 +{
618 +    u_int32_t i;
619 +    /* Insert new table */
620 +    for (i = 0; i < ACCOUNT_MAX_HANDLES; i++) {
621 +        /* Found free slot */
622 +        if (ipt_acc_handles[i].data == NULL) {
623 +            /* Don't "mark" data as used as we are protected by a spinlock 
624 +               by the calling function. handle_find_slot() is only a function
625 +               to prevent code duplication. */
626 +            return i;
627 +        }
628 +    }
629 +
630 +    /* No free slot found */
631 +    printk("ACCOUNT: No free handle slot found (max: %u). "
632 +           "Please increase ACCOUNT_MAX_HANDLES.\n", ACCOUNT_MAX_HANDLES);
633 +    return -1;
634 +}
635 +
636 +static int ipt_acc_handle_free(u_int32_t handle)
637 +{
638 +    if (handle >= ACCOUNT_MAX_HANDLES) {
639 +        printk("ACCOUNT: Invalid handle for ipt_acc_handle_free() specified:"
640 +               " %u\n", handle);
641 +        return -EINVAL;
642 +    }
643 +
644 +    ipt_acc_data_free(ipt_acc_handles[handle].data, 
645 +                          ipt_acc_handles[handle].depth);
646 +    memset (&ipt_acc_handles[handle], 0, sizeof (struct ipt_acc_handle));
647 +    return 0;
648 +}
649 +
650 +/* Prepare data for read without flush. Use only for debugging!
651 +   Real applications should use read&flush as it's way more efficent */
652 +static int ipt_acc_handle_prepare_read(char *tablename,
653 +         struct ipt_acc_handle *dest, u_int32_t *count)
654 +{
655 +    int table_nr=-1;
656 +    unsigned char depth;
657 +
658 +    for (table_nr = 0; table_nr < ACCOUNT_MAX_TABLES; table_nr++)
659 +        if (strncmp(ipt_acc_tables[table_nr].name, tablename, 
660 +            ACCOUNT_TABLE_NAME_LEN) == 0)
661 +                break;
662 +
663 +    if (table_nr == ACCOUNT_MAX_TABLES) {
664 +        printk("ACCOUNT: ipt_acc_handle_prepare_read(): "
665 +               "Table %s not found\n", tablename);
666 +        return -1;
667 +    }
668 +
669 +    /* Fill up handle structure */
670 +    dest->ip = ipt_acc_tables[table_nr].ip;
671 +    dest->depth = ipt_acc_tables[table_nr].depth;
672 +    dest->itemcount = ipt_acc_tables[table_nr].itemcount;
673 +
674 +    /* allocate "root" table */
675 +    if ((dest->data = (void*)get_zeroed_page(GFP_ATOMIC)) == NULL) {
676 +        printk("ACCOUNT: out of memory for root table "
677 +               "in ipt_acc_handle_prepare_read()\n");
678 +        return -1;
679 +    }
680 +
681 +    /* Recursive copy of complete data structure */
682 +    depth = dest->depth;
683 +    if (depth == 0) {
684 +        memcpy(dest->data, 
685 +               ipt_acc_tables[table_nr].data, 
686 +               sizeof(struct ipt_acc_mask_24));
687 +    } else if (depth == 1) {
688 +        struct ipt_acc_mask_16 *src_16 = 
689 +            (struct ipt_acc_mask_16 *)ipt_acc_tables[table_nr].data;
690 +        struct ipt_acc_mask_16 *network_16 =
691 +            (struct ipt_acc_mask_16 *)dest->data;
692 +        u_int32_t b;
693 +
694 +        for (b = 0; b <= 255; b++) {
695 +            if (src_16->mask_24[b]) {
696 +                if ((network_16->mask_24[b] = 
697 +                     (void*)get_zeroed_page(GFP_ATOMIC)) == NULL) {
698 +                    printk("ACCOUNT: out of memory during copy of 16 bit "
699 +                           "network in ipt_acc_handle_prepare_read()\n");
700 +                    ipt_acc_data_free(dest->data, depth);
701 +                    return -1;
702 +                }
703 +
704 +                memcpy(network_16->mask_24[b], src_16->mask_24[b], 
705 +                       sizeof(struct ipt_acc_mask_24));
706 +            }
707 +        }
708 +    } else if(depth == 2) {
709 +        struct ipt_acc_mask_8 *src_8 = 
710 +            (struct ipt_acc_mask_8 *)ipt_acc_tables[table_nr].data;
711 +        struct ipt_acc_mask_8 *network_8 = 
712 +            (struct ipt_acc_mask_8 *)dest->data;
713 +        struct ipt_acc_mask_16 *src_16, *network_16;
714 +        u_int32_t a, b;
715 +
716 +        for (a = 0; a <= 255; a++) {
717 +            if (src_8->mask_16[a]) {
718 +                if ((network_8->mask_16[a] = 
719 +                     (void*)get_zeroed_page(GFP_ATOMIC)) == NULL) {
720 +                    printk("ACCOUNT: out of memory during copy of 24 bit network"
721 +                           " in ipt_acc_handle_prepare_read()\n");
722 +                    ipt_acc_data_free(dest->data, depth);
723 +                    return -1;
724 +                }
725 +
726 +                memcpy(network_8->mask_16[a], src_8->mask_16[a], 
727 +                       sizeof(struct ipt_acc_mask_16));
728 +
729 +                src_16 = src_8->mask_16[a];
730 +                network_16 = network_8->mask_16[a];
731 +
732 +                for (b = 0; b <= 255; b++) {
733 +                    if (src_16->mask_24[b]) {
734 +                        if ((network_16->mask_24[b] = 
735 +                             (void*)get_zeroed_page(GFP_ATOMIC)) == NULL) {
736 +                            printk("ACCOUNT: out of memory during copy of 16 bit"
737 +                                   " network in ipt_acc_handle_prepare_read()\n");
738 +                            ipt_acc_data_free(dest->data, depth);
739 +                            return -1;
740 +                        }
741 +
742 +                        memcpy(network_16->mask_24[b], src_16->mask_24[b], 
743 +                               sizeof(struct ipt_acc_mask_24));
744 +                    }
745 +                }
746 +            }
747 +        }
748 +    }
749 +
750 +    *count = ipt_acc_tables[table_nr].itemcount;
751 +    
752 +    return 0;
753 +}
754 +
755 +/* Prepare data for read and flush it */
756 +static int ipt_acc_handle_prepare_read_flush(char *tablename,
757 +               struct ipt_acc_handle *dest, u_int32_t *count)
758 +{
759 +    int table_nr;
760 +    void *new_data_page;
761 +
762 +    for (table_nr = 0; table_nr < ACCOUNT_MAX_TABLES; table_nr++)
763 +        if (strncmp(ipt_acc_tables[table_nr].name, tablename, 
764 +            ACCOUNT_TABLE_NAME_LEN) == 0)
765 +                break;
766 +
767 +    if (table_nr == ACCOUNT_MAX_TABLES) {
768 +        printk("ACCOUNT: ipt_acc_handle_prepare_read_flush(): "
769 +               "Table %s not found\n", tablename);
770 +        return -1;
771 +    }
772 +
773 +    /* Try to allocate memory */
774 +    if (!(new_data_page = (void*)get_zeroed_page(GFP_ATOMIC))) {
775 +        printk("ACCOUNT: ipt_acc_handle_prepare_read_flush(): "
776 +               "Out of memory!\n");
777 +        return -1;
778 +    }
779 +
780 +    /* Fill up handle structure */
781 +    dest->ip = ipt_acc_tables[table_nr].ip;
782 +    dest->depth = ipt_acc_tables[table_nr].depth;
783 +    dest->itemcount = ipt_acc_tables[table_nr].itemcount;
784 +    dest->data = ipt_acc_tables[table_nr].data;
785 +    *count = ipt_acc_tables[table_nr].itemcount;
786 +
787 +    /* "Flush" table data */
788 +    ipt_acc_tables[table_nr].data = new_data_page;
789 +    ipt_acc_tables[table_nr].itemcount = 0;
790 +
791 +    return 0;
792 +}
793 +
794 +/* Copy 8 bit network data into a prepared buffer.
795 +   We only copy entries != 0 to increase performance.
796 +*/
797 +static int ipt_acc_handle_copy_data(void *to_user, u_int32_t *to_user_pos,
798 +                                  u_int32_t *tmpbuf_pos, 
799 +                                  struct ipt_acc_mask_24 *data,
800 +                                  u_int32_t net_ip, u_int32_t net_OR_mask)
801 +{
802 +    struct ipt_acc_handle_ip handle_ip;
803 +    u_int32_t handle_ip_size = sizeof (struct ipt_acc_handle_ip);
804 +    u_int32_t i;
805 +    
806 +    for (i = 0; i <= 255; i++) {
807 +        if (data->ip[i].src_packets || data->ip[i].dst_packets) {
808 +            handle_ip.ip = net_ip | net_OR_mask | (i<<24);
809 +            
810 +            handle_ip.src_packets = data->ip[i].src_packets;
811 +            handle_ip.src_bytes = data->ip[i].src_bytes;
812 +            handle_ip.dst_packets = data->ip[i].dst_packets;
813 +            handle_ip.dst_bytes = data->ip[i].dst_bytes;
814 +
815 +            /* Temporary buffer full? Flush to userspace */
816 +            if (*tmpbuf_pos+handle_ip_size >= PAGE_SIZE) {
817 +                if (copy_to_user(to_user + *to_user_pos, ipt_acc_tmpbuf,
818 +                                                           *tmpbuf_pos))
819 +                    return -EFAULT;
820 +                *to_user_pos = *to_user_pos + *tmpbuf_pos;
821 +                *tmpbuf_pos = 0;
822 +            }
823 +            memcpy(ipt_acc_tmpbuf+*tmpbuf_pos, &handle_ip, handle_ip_size);
824 +            *tmpbuf_pos += handle_ip_size;
825 +        }
826 +    }
827 +    
828 +    return 0;
829 +}
830 +   
831 +/* Copy the data from our internal structure 
832 +   We only copy entries != 0 to increase performance.
833 +   Overwrites ipt_acc_tmpbuf.
834 +*/
835 +static int ipt_acc_handle_get_data(u_int32_t handle, void *to_user)
836 +{
837 +    u_int32_t to_user_pos=0, tmpbuf_pos=0, net_ip;
838 +    unsigned char depth;
839 +
840 +    if (handle >= ACCOUNT_MAX_HANDLES) {
841 +        printk("ACCOUNT: invalid handle for ipt_acc_handle_get_data() "
842 +               "specified: %u\n", handle);
843 +        return -1;
844 +    }
845 +
846 +    if (ipt_acc_handles[handle].data == NULL) {
847 +        printk("ACCOUNT: handle %u is BROKEN: Contains no data\n", handle);
848 +        return -1;
849 +    }
850 +
851 +    net_ip = ipt_acc_handles[handle].ip;
852 +    depth = ipt_acc_handles[handle].depth;
853 +
854 +    /* 8 bit network */
855 +    if (depth == 0) {
856 +        struct ipt_acc_mask_24 *network = 
857 +            (struct ipt_acc_mask_24*)ipt_acc_handles[handle].data;
858 +        if (ipt_acc_handle_copy_data(to_user, &to_user_pos, &tmpbuf_pos,
859 +                                     network, net_ip, 0))
860 +            return -1;
861 +        
862 +        /* Flush remaining data to userspace */
863 +        if (tmpbuf_pos)
864 +            if (copy_to_user(to_user+to_user_pos, ipt_acc_tmpbuf, tmpbuf_pos))
865 +                return -1;
866 +
867 +        return 0;
868 +    }
869 +
870 +    /* 16 bit network */
871 +    if (depth == 1) {
872 +        struct ipt_acc_mask_16 *network_16 = 
873 +            (struct ipt_acc_mask_16*)ipt_acc_handles[handle].data;
874 +        u_int32_t b;
875 +        for (b = 0; b <= 255; b++) {
876 +            if (network_16->mask_24[b]) {
877 +                struct ipt_acc_mask_24 *network = 
878 +                    (struct ipt_acc_mask_24*)network_16->mask_24[b];
879 +                if (ipt_acc_handle_copy_data(to_user, &to_user_pos,
880 +                                      &tmpbuf_pos, network, net_ip, (b << 16)))
881 +                    return -1;
882 +            }
883 +        }
884 +
885 +        /* Flush remaining data to userspace */
886 +        if (tmpbuf_pos)
887 +            if (copy_to_user(to_user+to_user_pos, ipt_acc_tmpbuf, tmpbuf_pos))
888 +                return -1;
889 +
890 +        return 0;
891 +    }
892 +
893 +    /* 24 bit network */
894 +    if (depth == 2) {
895 +        struct ipt_acc_mask_8 *network_8 = 
896 +            (struct ipt_acc_mask_8*)ipt_acc_handles[handle].data;
897 +        u_int32_t a, b;
898 +        for (a = 0; a <= 255; a++) {
899 +            if (network_8->mask_16[a]) {
900 +                struct ipt_acc_mask_16 *network_16 = 
901 +                    (struct ipt_acc_mask_16*)network_8->mask_16[a];
902 +                for (b = 0; b <= 255; b++) {
903 +                    if (network_16->mask_24[b]) {
904 +                        struct ipt_acc_mask_24 *network = 
905 +                            (struct ipt_acc_mask_24*)network_16->mask_24[b];
906 +                        if (ipt_acc_handle_copy_data(to_user,
907 +                                       &to_user_pos, &tmpbuf_pos,
908 +                                       network, net_ip, (a << 8) | (b << 16)))
909 +                            return -1;
910 +                    }
911 +                }
912 +            }
913 +        }
914 +
915 +        /* Flush remaining data to userspace */
916 +        if (tmpbuf_pos)
917 +            if (copy_to_user(to_user+to_user_pos, ipt_acc_tmpbuf, tmpbuf_pos))
918 +                return -1;
919 +
920 +        return 0;
921 +    }
922 +    
923 +    return -1;
924 +}
925 +
926 +static int ipt_acc_set_ctl(struct sock *sk, int cmd, 
927 +                               void *user, u_int32_t len)
928 +{
929 +    struct ipt_acc_handle_sockopt handle;
930 +    int ret = -EINVAL;
931 +
932 +    if (!capable(CAP_NET_ADMIN))
933 +        return -EPERM;
934 +
935 +    switch (cmd) {
936 +    case IPT_SO_SET_ACCOUNT_HANDLE_FREE:
937 +        if (len != sizeof(struct ipt_acc_handle_sockopt)) {
938 +            printk("ACCOUNT: ipt_acc_set_ctl: wrong data size (%u != %u) "
939 +                   "for IPT_SO_SET_HANDLE_FREE\n", 
940 +                   len, sizeof(struct ipt_acc_handle_sockopt));
941 +            break;
942 +        }
943 +
944 +        if (copy_from_user (&handle, user, len)) {
945 +            printk("ACCOUNT: ipt_acc_set_ctl: copy_from_user failed for "
946 +                   "IPT_SO_SET_HANDLE_FREE\n");
947 +            break;
948 +        }
949 +
950 +        down(&ipt_acc_userspace_mutex);
951 +        ret = ipt_acc_handle_free(handle.handle_nr);
952 +        up(&ipt_acc_userspace_mutex);
953 +        break;
954 +    case IPT_SO_SET_ACCOUNT_HANDLE_FREE_ALL: {
955 +            u_int32_t i;
956 +            down(&ipt_acc_userspace_mutex);
957 +            for (i = 0; i < ACCOUNT_MAX_HANDLES; i++)
958 +                ipt_acc_handle_free(i);
959 +            up(&ipt_acc_userspace_mutex);
960 +            ret = 0;
961 +            break;
962 +        }
963 +    default:
964 +        printk("ACCOUNT: ipt_acc_set_ctl: unknown request %i\n", cmd);
965 +    }
966 +
967 +    return ret;
968 +}
969 +
970 +static int ipt_acc_get_ctl(struct sock *sk, int cmd, void *user, int *len)
971 +{
972 +    struct ipt_acc_handle_sockopt handle;
973 +    int ret = -EINVAL;
974 +
975 +    if (!capable(CAP_NET_ADMIN))
976 +        return -EPERM;
977 +
978 +    switch (cmd) {
979 +    case IPT_SO_GET_ACCOUNT_PREPARE_READ_FLUSH:
980 +    case IPT_SO_GET_ACCOUNT_PREPARE_READ: {
981 +            struct ipt_acc_handle dest;
982 +    
983 +            if (*len < sizeof(struct ipt_acc_handle_sockopt)) {
984 +                printk("ACCOUNT: ipt_acc_get_ctl: wrong data size (%u != %u) "
985 +                    "for IPT_SO_GET_ACCOUNT_PREPARE_READ/READ_FLUSH\n",
986 +                    *len, sizeof(struct ipt_acc_handle_sockopt));
987 +                break;
988 +            }
989 +    
990 +            if (copy_from_user (&handle, user, 
991 +                                sizeof(struct ipt_acc_handle_sockopt))) {
992 +                return -EFAULT;
993 +                break;
994 +            }
995 +    
996 +            LOCK_BH(&ipt_acc_lock);
997 +            if (cmd == IPT_SO_GET_ACCOUNT_PREPARE_READ_FLUSH)
998 +                ret = ipt_acc_handle_prepare_read_flush(
999 +                                    handle.name, &dest, &handle.itemcount);
1000 +            else
1001 +                ret = ipt_acc_handle_prepare_read(
1002 +                                    handle.name, &dest, &handle.itemcount);
1003 +            UNLOCK_BH(&ipt_acc_lock);
1004 +            // Error occured during prepare_read?
1005 +           if (ret == -1)
1006 +                return -EINVAL;
1007 +            
1008 +            /* Allocate a userspace handle */
1009 +            down(&ipt_acc_userspace_mutex);
1010 +            if ((handle.handle_nr = ipt_acc_handle_find_slot()) == -1) {
1011 +                ipt_acc_data_free(dest.data, dest.depth);
1012 +                up(&ipt_acc_userspace_mutex);
1013 +                return -EINVAL;
1014 +            }
1015 +            memcpy(&ipt_acc_handles[handle.handle_nr], &dest,
1016 +                             sizeof(struct ipt_acc_handle));
1017 +            up(&ipt_acc_userspace_mutex);
1018 +            
1019 +            if (copy_to_user(user, &handle, 
1020 +                            sizeof(struct ipt_acc_handle_sockopt))) {
1021 +                return -EFAULT;
1022 +                break;
1023 +            }
1024 +            ret = 0;
1025 +            break;
1026 +        }
1027 +    case IPT_SO_GET_ACCOUNT_GET_DATA:
1028 +        if (*len < sizeof(struct ipt_acc_handle_sockopt)) {
1029 +            printk("ACCOUNT: ipt_acc_get_ctl: wrong data size (%u != %u)"
1030 +                   " for IPT_SO_GET_ACCOUNT_PREPARE_READ/READ_FLUSH\n",
1031 +                   *len, sizeof(struct ipt_acc_handle_sockopt));
1032 +            break;
1033 +        }
1034 +
1035 +        if (copy_from_user (&handle, user, 
1036 +                            sizeof(struct ipt_acc_handle_sockopt))) {
1037 +            return -EFAULT;
1038 +            break;
1039 +        }
1040 +
1041 +        if (handle.handle_nr >= ACCOUNT_MAX_HANDLES) {
1042 +            return -EINVAL;
1043 +            break;
1044 +        }
1045 +
1046 +        if (*len < ipt_acc_handles[handle.handle_nr].itemcount
1047 +                   * sizeof(struct ipt_acc_handle_ip)) {
1048 +            printk("ACCOUNT: ipt_acc_get_ctl: not enough space (%u < %u)"
1049 +                   " to store data from IPT_SO_GET_ACCOUNT_GET_DATA\n",
1050 +                   *len, ipt_acc_handles[handle.handle_nr].itemcount
1051 +                   * sizeof(struct ipt_acc_handle_ip));
1052 +            ret = -ENOMEM;
1053 +            break;
1054 +        }
1055 +
1056 +        down(&ipt_acc_userspace_mutex);
1057 +        ret = ipt_acc_handle_get_data(handle.handle_nr, user);
1058 +        up(&ipt_acc_userspace_mutex);
1059 +        if (ret) {
1060 +            printk("ACCOUNT: ipt_acc_get_ctl: ipt_acc_handle_get_data"
1061 +                   " failed for handle %u\n", handle.handle_nr);
1062 +            break;
1063 +        }
1064 +
1065 +        ret = 0;
1066 +        break;
1067 +    case IPT_SO_GET_ACCOUNT_GET_HANDLE_USAGE: {
1068 +            u_int32_t i;
1069 +            if (*len < sizeof(struct ipt_acc_handle_sockopt)) {
1070 +                printk("ACCOUNT: ipt_acc_get_ctl: wrong data size (%u != %u)"
1071 +                       " for IPT_SO_GET_ACCOUNT_GET_HANDLE_USAGE\n",
1072 +                       *len, sizeof(struct ipt_acc_handle_sockopt));
1073 +                break;
1074 +            }
1075 +
1076 +            /* Find out how many handles are in use */
1077 +            handle.itemcount = 0;
1078 +            down(&ipt_acc_userspace_mutex);
1079 +            for (i = 0; i < ACCOUNT_MAX_HANDLES; i++)
1080 +                if (ipt_acc_handles[i].data)
1081 +                    handle.itemcount++;
1082 +            up(&ipt_acc_userspace_mutex);
1083 +
1084 +            if (copy_to_user(user, &handle, 
1085 +                             sizeof(struct ipt_acc_handle_sockopt))) {
1086 +                return -EFAULT;
1087 +                break;
1088 +            }
1089 +            ret = 0;
1090 +            break;
1091 +        }
1092 +    case IPT_SO_GET_ACCOUNT_GET_TABLE_NAMES: {
1093 +            u_int32_t size = 0, i, name_len;
1094 +            char *tnames;
1095 +
1096 +            LOCK_BH(&ipt_acc_lock);
1097 +
1098 +            /* Determine size of table names */
1099 +            for (i = 0; i < ACCOUNT_MAX_TABLES; i++) {
1100 +                if (ipt_acc_tables[i].name[0] != 0)
1101 +                    size += strlen (ipt_acc_tables[i].name) + 1;
1102 +            }
1103 +            size += 1;    /* Terminating NULL character */
1104 +
1105 +            if (*len < size || size > PAGE_SIZE) {
1106 +                UNLOCK_BH(&ipt_acc_lock);
1107 +                printk("ACCOUNT: ipt_acc_get_ctl: not enough space (%u < %u < %lu)"
1108 +                       " to store table names\n", *len, size, PAGE_SIZE);
1109 +                ret = -ENOMEM;
1110 +                break;
1111 +            }
1112 +            /* Copy table names to userspace */
1113 +            tnames = ipt_acc_tmpbuf;
1114 +            for (i = 0; i < ACCOUNT_MAX_TABLES; i++) {
1115 +                if (ipt_acc_tables[i].name[0] != 0) {
1116 +                    name_len = strlen (ipt_acc_tables[i].name) + 1;
1117 +                    memcpy(tnames, ipt_acc_tables[i].name, name_len);
1118 +                    tnames += name_len;
1119 +                }
1120 +            }
1121 +            UNLOCK_BH(&ipt_acc_lock);
1122 +            
1123 +            /* Terminating NULL character */
1124 +            *tnames = 0;
1125 +            
1126 +            /* Transfer to userspace */                    
1127 +            if (copy_to_user(user, ipt_acc_tmpbuf, size))
1128 +                return -EFAULT;
1129 +            
1130 +            ret = 0;
1131 +            break;
1132 +        }
1133 +    default:
1134 +        printk("ACCOUNT: ipt_acc_get_ctl: unknown request %i\n", cmd);
1135 +    }
1136 +
1137 +    return ret;
1138 +}
1139 +
1140 +static struct ipt_target ipt_acc_reg = {
1141 +    .name = "ACCOUNT",
1142 +    .target = ipt_acc_target,
1143 +    .checkentry = ipt_acc_checkentry,
1144 +    .destroy = ipt_acc_deleteentry,
1145 +    .me = THIS_MODULE
1146 +};
1147 +
1148 +static struct nf_sockopt_ops ipt_acc_sockopts = {
1149 +    .pf = PF_INET,
1150 +    .set_optmin = IPT_SO_SET_ACCOUNT_HANDLE_FREE,
1151 +    .set_optmax = IPT_SO_SET_ACCOUNT_MAX+1,
1152 +    .set = ipt_acc_set_ctl,
1153 +    .get_optmin = IPT_SO_GET_ACCOUNT_PREPARE_READ,
1154 +    .get_optmax = IPT_SO_GET_ACCOUNT_MAX+1,
1155 +    .get = ipt_acc_get_ctl
1156 +};
1157 +
1158 +static int __init init(void)
1159 +{
1160 +    init_MUTEX(&ipt_acc_userspace_mutex);    
1161 +
1162 +    if ((ipt_acc_tables = 
1163 +         kmalloc(ACCOUNT_MAX_TABLES * 
1164 +                 sizeof(struct ipt_acc_table), GFP_KERNEL)) == NULL) {
1165 +        printk("ACCOUNT: Out of memory allocating account_tables structure");
1166 +        goto error_cleanup;
1167 +    }
1168 +    memset(ipt_acc_tables, 0, 
1169 +           ACCOUNT_MAX_TABLES * sizeof(struct ipt_acc_table));
1170 +
1171 +    if ((ipt_acc_handles = 
1172 +         kmalloc(ACCOUNT_MAX_HANDLES * 
1173 +                 sizeof(struct ipt_acc_handle), GFP_KERNEL)) == NULL) {
1174 +        printk("ACCOUNT: Out of memory allocating account_handles structure");
1175 +        goto error_cleanup;
1176 +    }
1177 +    memset(ipt_acc_handles, 0, 
1178 +           ACCOUNT_MAX_HANDLES * sizeof(struct ipt_acc_handle));
1179 +
1180 +    /* Allocate one page as temporary storage */
1181 +    if ((ipt_acc_tmpbuf = (void*)__get_free_page(GFP_KERNEL)) == NULL) {
1182 +        printk("ACCOUNT: Out of memory for temporary buffer page\n");
1183 +        goto error_cleanup;
1184 +    }
1185 +
1186 +    /* Register setsockopt */
1187 +    if (nf_register_sockopt(&ipt_acc_sockopts) < 0) {
1188 +        printk("ACCOUNT: Can't register sockopts. Aborting\n");
1189 +        goto error_cleanup;
1190 +    }
1191 +
1192 +    if (ipt_register_target(&ipt_acc_reg))
1193 +        goto error_cleanup;
1194 +        
1195 +    return 0;
1196 +        
1197 +error_cleanup:
1198 +    if(ipt_acc_tables)
1199 +        kfree(ipt_acc_tables);
1200 +    if(ipt_acc_handles)
1201 +        kfree(ipt_acc_handles);
1202 +    if (ipt_acc_tmpbuf)
1203 +        free_page((unsigned long)ipt_acc_tmpbuf);
1204 +        
1205 +    return -EINVAL;
1206 +}
1207 +
1208 +static void __exit fini(void)
1209 +{
1210 +    ipt_unregister_target(&ipt_acc_reg);
1211 +
1212 +    nf_unregister_sockopt(&ipt_acc_sockopts);
1213 +
1214 +    kfree(ipt_acc_tables);
1215 +    kfree(ipt_acc_handles);
1216 +    free_page((unsigned long)ipt_acc_tmpbuf);
1217 +}
1218 +
1219 +module_init(init);
1220 +module_exit(fini);
1221 +MODULE_LICENSE("GPL");
This page took 0.144537 seconds and 3 git commands to generate.