2 * communication.c, v2.0 July 2002
4 * Author: Bart De Schuymer
9 * All the userspace/kernel communication is in this file.
10 * The other code should not have to know anything about the way the
11 * kernel likes the structure of the table data.
12 * The other code works with linked lists. So, the translation is done here.
22 #include <sys/socket.h>
23 #include "include/ebtables_u.h"
25 extern char* hooknames
[NF_BR_NUMHOOKS
];
27 #ifdef KERNEL_64_USERSPACE_32
28 #define sparc_cast (uint64_t)
35 static int get_sockfd()
39 sockfd
= socket(AF_INET
, SOCK_RAW
, PF_INET
);
41 ebt_print_error("Problem getting a socket, "
42 "you probably don't have the right "
50 static struct ebt_replace
*translate_user2kernel(struct ebt_u_replace
*u_repl
)
52 struct ebt_replace
*new;
53 struct ebt_u_entry
*e
;
54 struct ebt_u_match_list
*m_l
;
55 struct ebt_u_watcher_list
*w_l
;
56 struct ebt_u_entries
*entries
;
59 unsigned int entries_size
= 0, *chain_offsets
;
61 new = (struct ebt_replace
*)malloc(sizeof(struct ebt_replace
));
64 new->valid_hooks
= u_repl
->valid_hooks
;
65 strcpy(new->name
, u_repl
->name
);
66 new->nentries
= u_repl
->nentries
;
67 new->num_counters
= u_repl
->num_counters
;
68 new->counters
= sparc_cast u_repl
->counters
;
69 chain_offsets
= (unsigned int *)calloc(u_repl
->num_chains
, sizeof(unsigned int));
73 for (i
= 0; i
< u_repl
->num_chains
; i
++) {
74 if (!(entries
= u_repl
->chains
[i
]))
76 chain_offsets
[i
] = entries_size
;
77 entries_size
+= sizeof(struct ebt_entries
);
79 e
= entries
->entries
->next
;
80 while (e
!= entries
->entries
) {
82 entries_size
+= sizeof(struct ebt_entry
);
85 entries_size
+= m_l
->m
->match_size
+
86 sizeof(struct ebt_entry_match
);
91 entries_size
+= w_l
->w
->watcher_size
+
92 sizeof(struct ebt_entry_watcher
);
95 entries_size
+= e
->t
->target_size
+
96 sizeof(struct ebt_entry_target
);
99 /* A little sanity check */
100 if (j
!= entries
->nentries
)
101 ebt_print_bug("Wrong nentries: %d != %d, hook = %s", j
,
102 entries
->nentries
, entries
->name
);
105 new->entries_size
= entries_size
;
106 p
= (char *)malloc(entries_size
);
110 /* Put everything in one block */
111 new->entries
= sparc_cast p
;
112 for (i
= 0; i
< u_repl
->num_chains
; i
++) {
113 struct ebt_entries
*hlp
;
115 hlp
= (struct ebt_entries
*)p
;
116 if (!(entries
= u_repl
->chains
[i
]))
118 if (i
< NF_BR_NUMHOOKS
)
119 new->hook_entry
[i
] = sparc_cast hlp
;
120 hlp
->nentries
= entries
->nentries
;
121 hlp
->policy
= entries
->policy
;
122 strcpy(hlp
->name
, entries
->name
);
123 hlp
->counter_offset
= entries
->counter_offset
;
124 hlp
->distinguisher
= 0; /* Make the kernel see the light */
125 p
+= sizeof(struct ebt_entries
);
126 e
= entries
->entries
->next
;
127 while (e
!= entries
->entries
) {
128 struct ebt_entry
*tmp
= (struct ebt_entry
*)p
;
130 tmp
->bitmask
= e
->bitmask
| EBT_ENTRY_OR_ENTRIES
;
131 tmp
->invflags
= e
->invflags
;
132 tmp
->ethproto
= e
->ethproto
;
133 strcpy(tmp
->in
, e
->in
);
134 strcpy(tmp
->out
, e
->out
);
135 strcpy(tmp
->logical_in
, e
->logical_in
);
136 strcpy(tmp
->logical_out
, e
->logical_out
);
137 memcpy(tmp
->sourcemac
, e
->sourcemac
,
138 sizeof(tmp
->sourcemac
));
139 memcpy(tmp
->sourcemsk
, e
->sourcemsk
,
140 sizeof(tmp
->sourcemsk
));
141 memcpy(tmp
->destmac
, e
->destmac
, sizeof(tmp
->destmac
));
142 memcpy(tmp
->destmsk
, e
->destmsk
, sizeof(tmp
->destmsk
));
145 p
+= sizeof(struct ebt_entry
);
148 memcpy(p
, m_l
->m
, m_l
->m
->match_size
+
149 sizeof(struct ebt_entry_match
));
150 p
+= m_l
->m
->match_size
+
151 sizeof(struct ebt_entry_match
);
154 tmp
->watchers_offset
= p
- base
;
157 memcpy(p
, w_l
->w
, w_l
->w
->watcher_size
+
158 sizeof(struct ebt_entry_watcher
));
159 p
+= w_l
->w
->watcher_size
+
160 sizeof(struct ebt_entry_watcher
);
163 tmp
->target_offset
= p
- base
;
164 memcpy(p
, e
->t
, e
->t
->target_size
+
165 sizeof(struct ebt_entry_target
));
166 if (!strcmp(e
->t
->u
.name
, EBT_STANDARD_TARGET
)) {
167 struct ebt_standard_target
*st
=
168 (struct ebt_standard_target
*)p
;
169 /* Translate the jump to a udc */
170 if (st
->verdict
>= 0)
171 st
->verdict
= chain_offsets
172 [st
->verdict
+ NF_BR_NUMHOOKS
];
174 p
+= e
->t
->target_size
+
175 sizeof(struct ebt_entry_target
);
176 tmp
->next_offset
= p
- base
;
182 if (p
- (char *)new->entries
!= new->entries_size
)
183 ebt_print_bug("Entries_size bug");
188 static void store_table_in_file(char *filename
, struct ebt_replace
*repl
)
194 /* Start from an empty file with the correct priviliges */
195 if ((fd
= creat(filename
, 0600)) == -1) {
196 ebt_print_error("Couldn't create file %s", filename
);
200 size
= sizeof(struct ebt_replace
) + repl
->entries_size
+
201 repl
->nentries
* sizeof(struct ebt_counter
);
202 data
= (char *)malloc(size
);
205 memcpy(data
, repl
, sizeof(struct ebt_replace
));
206 memcpy(data
+ sizeof(struct ebt_replace
), (char *)repl
->entries
,
208 /* Initialize counters to zero, deliver_counters() can update them */
209 memset(data
+ sizeof(struct ebt_replace
) + repl
->entries_size
,
210 0, repl
->nentries
* sizeof(struct ebt_counter
));
211 if (write(fd
, data
, size
) != size
)
212 ebt_print_error("Couldn't write everything to file %s",
218 void ebt_deliver_table(struct ebt_u_replace
*u_repl
)
221 struct ebt_replace
*repl
;
223 /* Translate the struct ebt_u_replace to a struct ebt_replace */
224 repl
= translate_user2kernel(u_repl
);
225 if (u_repl
->filename
!= NULL
) {
226 store_table_in_file(u_repl
->filename
, repl
);
229 /* Give the data to the kernel */
230 optlen
= sizeof(struct ebt_replace
) + repl
->entries_size
;
233 if (!setsockopt(sockfd
, IPPROTO_IP
, EBT_SO_SET_ENTRIES
, repl
, optlen
))
235 if (u_repl
->command
== 8) { /* The ebtables module may not
236 * yet be loaded with --atomic-commit */
237 ebtables_insmod("ebtables");
238 if (!setsockopt(sockfd
, IPPROTO_IP
, EBT_SO_SET_ENTRIES
,
243 ebt_print_error("Unable to update the kernel. Two possible causes:\n"
244 "1. Multiple ebtables programs were executing simultaneously. The ebtables\n"
245 " userspace tool doesn't by default support multiple ebtables programs running\n"
246 " concurrently. The ebtables option --concurrent or a tool like flock can be\n"
247 " used to support concurrent scripts that update the ebtables kernel tables.\n"
248 "2. The kernel doesn't support a certain ebtables extension, consider\n"
249 " recompiling your kernel or insmod the extension.\n");
257 static int store_counters_in_file(char *filename
, struct ebt_u_replace
*repl
)
259 int size
= repl
->nentries
* sizeof(struct ebt_counter
), ret
= 0;
260 unsigned int entries_size
;
261 struct ebt_replace hlp
;
264 if (!(file
= fopen(filename
, "r+b"))) {
265 ebt_print_error("Could not open file %s", filename
);
268 /* Find out entries_size and then set the file pointer to the
270 if (fseek(file
, (char *)(&hlp
.entries_size
) - (char *)(&hlp
), SEEK_SET
)
271 || fread(&entries_size
, sizeof(char), sizeof(unsigned int), file
) !=
272 sizeof(unsigned int) ||
273 fseek(file
, entries_size
+ sizeof(struct ebt_replace
), SEEK_SET
)) {
274 ebt_print_error("File %s is corrupt", filename
);
278 if (fwrite(repl
->counters
, sizeof(char), size
, file
) != size
) {
279 ebt_print_error("Could not write everything to file %s",
288 /* Gets executed after ebt_deliver_table. Delivers the counters to the kernel
289 * and resets the counterchanges to CNT_NORM */
290 void ebt_deliver_counters(struct ebt_u_replace
*u_repl
)
292 struct ebt_counter
*old
, *new, *newcounters
;
294 struct ebt_replace repl
;
295 struct ebt_cntchanges
*cc
= u_repl
->cc
->next
, *cc2
;
296 struct ebt_u_entries
*entries
= NULL
;
297 struct ebt_u_entry
*next
= NULL
;
300 if (u_repl
->nentries
== 0)
303 newcounters
= (struct ebt_counter
*)
304 malloc(u_repl
->nentries
* sizeof(struct ebt_counter
));
307 memset(newcounters
, 0, u_repl
->nentries
* sizeof(struct ebt_counter
));
308 old
= u_repl
->counters
;
310 while (cc
!= u_repl
->cc
) {
311 if (!next
|| next
== entries
->entries
) {
312 while (chainnr
< u_repl
->num_chains
&& (!(entries
= u_repl
->chains
[chainnr
]) ||
313 (next
= entries
->entries
->next
) == entries
->entries
))
315 if (chainnr
== u_repl
->num_chains
)
319 ebt_print_bug("next == NULL");
320 if (cc
->type
== CNT_NORM
) {
321 /* 'Normal' rule, meaning we didn't do anything to it
322 * So, we just copy */
325 next
->cnt_surplus
.pcnt
= next
->cnt_surplus
.bcnt
= 0;
326 old
++; /* We've used an old counter */
327 new++; /* We've set a new counter */
329 } else if (cc
->type
== CNT_DEL
) {
330 old
++; /* Don't use this old counter */
332 if (cc
->type
== CNT_CHANGE
) {
333 if (cc
->change
% 3 == 1)
334 new->pcnt
= old
->pcnt
+ next
->cnt_surplus
.pcnt
;
335 else if (cc
->change
% 3 == 2)
336 new->pcnt
= old
->pcnt
- next
->cnt_surplus
.pcnt
;
338 new->pcnt
= next
->cnt
.pcnt
;
339 if (cc
->change
/ 3 == 1)
340 new->bcnt
= old
->bcnt
+ next
->cnt_surplus
.bcnt
;
341 else if (cc
->change
/ 3 == 2)
342 new->bcnt
= old
->bcnt
- next
->cnt_surplus
.bcnt
;
344 new->bcnt
= next
->cnt
.bcnt
;
348 next
->cnt_surplus
.pcnt
= next
->cnt_surplus
.bcnt
= 0;
349 if (cc
->type
== CNT_ADD
)
360 free(u_repl
->counters
);
361 u_repl
->counters
= newcounters
;
362 u_repl
->num_counters
= u_repl
->nentries
;
363 /* Reset the counterchanges to CNT_NORM and delete the unused cc */
365 cc
= u_repl
->cc
->next
;
366 while (cc
!= u_repl
->cc
) {
367 if (cc
->type
== CNT_DEL
) {
368 cc
->prev
->next
= cc
->next
;
369 cc
->next
->prev
= cc
->prev
;
380 if (i
!= u_repl
->nentries
)
381 ebt_print_bug("i != u_repl->nentries");
382 if (u_repl
->filename
!= NULL
) {
383 store_counters_in_file(u_repl
->filename
, u_repl
);
386 optlen
= u_repl
->nentries
* sizeof(struct ebt_counter
) +
387 sizeof(struct ebt_replace
);
388 /* Now put the stuff in the kernel's struct ebt_replace */
389 repl
.counters
= sparc_cast u_repl
->counters
;
390 repl
.num_counters
= u_repl
->num_counters
;
391 memcpy(repl
.name
, u_repl
->name
, sizeof(repl
.name
));
395 if (setsockopt(sockfd
, IPPROTO_IP
, EBT_SO_SET_COUNTERS
, &repl
, optlen
))
396 ebt_print_bug("Couldn't update kernel counters");
400 ebt_translate_match(struct ebt_entry_match
*m
, struct ebt_u_match_list
***l
)
402 struct ebt_u_match_list
*new;
405 new = (struct ebt_u_match_list
*)
406 malloc(sizeof(struct ebt_u_match_list
));
409 new->m
= (struct ebt_entry_match
*)
410 malloc(m
->match_size
+ sizeof(struct ebt_entry_match
));
413 memcpy(new->m
, m
, m
->match_size
+ sizeof(struct ebt_entry_match
));
417 if (ebt_find_match(new->m
->u
.name
) == NULL
) {
418 ebt_print_error("Kernel match %s unsupported by userspace tool",
426 ebt_translate_watcher(struct ebt_entry_watcher
*w
,
427 struct ebt_u_watcher_list
***l
)
429 struct ebt_u_watcher_list
*new;
432 new = (struct ebt_u_watcher_list
*)
433 malloc(sizeof(struct ebt_u_watcher_list
));
436 new->w
= (struct ebt_entry_watcher
*)
437 malloc(w
->watcher_size
+ sizeof(struct ebt_entry_watcher
));
440 memcpy(new->w
, w
, w
->watcher_size
+ sizeof(struct ebt_entry_watcher
));
444 if (ebt_find_watcher(new->w
->u
.name
) == NULL
) {
445 ebt_print_error("Kernel watcher %s unsupported by userspace "
446 "tool", new->w
->u
.name
);
453 ebt_translate_entry(struct ebt_entry
*e
, int *hook
, int *n
, int *cnt
,
454 int *totalcnt
, struct ebt_u_entry
**u_e
, struct ebt_u_replace
*u_repl
,
455 unsigned int valid_hooks
, char *base
, struct ebt_cntchanges
**cc
)
458 if (e
->bitmask
& EBT_ENTRY_OR_ENTRIES
) {
459 struct ebt_u_entry
*new;
460 struct ebt_u_match_list
**m_l
;
461 struct ebt_u_watcher_list
**w_l
;
462 struct ebt_entry_target
*t
;
464 new = (struct ebt_u_entry
*)malloc(sizeof(struct ebt_u_entry
));
467 new->bitmask
= e
->bitmask
;
469 * Plain userspace code doesn't know about
470 * EBT_ENTRY_OR_ENTRIES
472 new->bitmask
&= ~EBT_ENTRY_OR_ENTRIES
;
473 new->invflags
= e
->invflags
;
474 new->ethproto
= e
->ethproto
;
475 strcpy(new->in
, e
->in
);
476 strcpy(new->out
, e
->out
);
477 strcpy(new->logical_in
, e
->logical_in
);
478 strcpy(new->logical_out
, e
->logical_out
);
479 memcpy(new->sourcemac
, e
->sourcemac
, sizeof(new->sourcemac
));
480 memcpy(new->sourcemsk
, e
->sourcemsk
, sizeof(new->sourcemsk
));
481 memcpy(new->destmac
, e
->destmac
, sizeof(new->destmac
));
482 memcpy(new->destmsk
, e
->destmsk
, sizeof(new->destmsk
));
483 if (*totalcnt
>= u_repl
->nentries
)
484 ebt_print_bug("*totalcnt >= u_repl->nentries");
485 new->cnt
= u_repl
->counters
[*totalcnt
];
486 new->cnt_surplus
.pcnt
= new->cnt_surplus
.bcnt
= 0;
491 new->next
= (*u_e
)->next
;
492 new->next
->prev
= new;
497 EBT_MATCH_ITERATE(e
, ebt_translate_match
, &m_l
);
499 EBT_WATCHER_ITERATE(e
, ebt_translate_watcher
, &w_l
);
501 t
= (struct ebt_entry_target
*)(((char *)e
) + e
->target_offset
);
502 new->t
= (struct ebt_entry_target
*)
503 malloc(t
->target_size
+ sizeof(struct ebt_entry_target
));
506 if (ebt_find_target(t
->u
.name
) == NULL
) {
507 ebt_print_error("Kernel target %s unsupported by "
508 "userspace tool", t
->u
.name
);
511 memcpy(new->t
, t
, t
->target_size
+
512 sizeof(struct ebt_entry_target
));
513 /* Deal with jumps to udc */
514 if (!strcmp(t
->u
.name
, EBT_STANDARD_TARGET
)) {
516 int verdict
= ((struct ebt_standard_target
*)t
)->verdict
;
521 for (i
= NF_BR_NUMHOOKS
; i
< u_repl
->num_chains
; i
++)
522 if (u_repl
->chains
[i
]->kernel_start
== tmp
)
524 if (i
== u_repl
->num_chains
)
525 ebt_print_bug("Can't find udc for jump");
526 ((struct ebt_standard_target
*)new->t
)->verdict
= i
-NF_BR_NUMHOOKS
;
533 } else { /* A new chain */
535 struct ebt_entries
*entries
= (struct ebt_entries
*)e
;
538 ebt_print_bug("Nr of entries in the chain is wrong");
539 *n
= entries
->nentries
;
541 for (i
= *hook
+ 1; i
< NF_BR_NUMHOOKS
; i
++)
542 if (valid_hooks
& (1 << i
))
545 *u_e
= u_repl
->chains
[*hook
]->entries
;
550 /* Initialize all chain headers */
552 ebt_translate_chains(struct ebt_entry
*e
, int *hook
,
553 struct ebt_u_replace
*u_repl
, unsigned int valid_hooks
)
556 struct ebt_entries
*entries
= (struct ebt_entries
*)e
;
557 struct ebt_u_entries
*new;
559 if (!(e
->bitmask
& EBT_ENTRY_OR_ENTRIES
)) {
560 for (i
= *hook
+ 1; i
< NF_BR_NUMHOOKS
; i
++)
561 if (valid_hooks
& (1 << i
))
563 new = (struct ebt_u_entries
*)malloc(sizeof(struct ebt_u_entries
));
566 if (i
== u_repl
->max_chains
)
567 ebt_double_chains(u_repl
);
568 u_repl
->chains
[i
] = new;
569 if (i
>= NF_BR_NUMHOOKS
)
570 new->kernel_start
= (char *)e
;
572 new->nentries
= entries
->nentries
;
573 new->policy
= entries
->policy
;
574 new->entries
= (struct ebt_u_entry
*)malloc(sizeof(struct ebt_u_entry
));
577 new->entries
->next
= new->entries
->prev
= new->entries
;
578 new->counter_offset
= entries
->counter_offset
;
579 strcpy(new->name
, entries
->name
);
584 static int retrieve_from_file(char *filename
, struct ebt_replace
*repl
,
588 char *hlp
= NULL
, *entries
;
589 struct ebt_counter
*counters
;
592 if (!(file
= fopen(filename
, "r+b"))) {
593 ebt_print_error("Could not open file %s", filename
);
596 /* Make sure table name is right if command isn't -L or --atomic-commit */
597 if (command
!= 'L' && command
!= 8) {
598 hlp
= (char *)malloc(strlen(repl
->name
) + 1);
601 strcpy(hlp
, repl
->name
);
603 if (fread(repl
, sizeof(char), sizeof(struct ebt_replace
), file
)
604 != sizeof(struct ebt_replace
)) {
605 ebt_print_error("File %s is corrupt", filename
);
609 if (command
!= 'L' && command
!= 8 && strcmp(hlp
, repl
->name
)) {
610 ebt_print_error("File %s contains wrong table name or is "
611 "corrupt", filename
);
614 } else if (!ebt_find_table(repl
->name
)) {
615 ebt_print_error("File %s contains invalid table name",
621 size
= sizeof(struct ebt_replace
) +
622 repl
->nentries
* sizeof(struct ebt_counter
) + repl
->entries_size
;
623 fseek(file
, 0, SEEK_END
);
624 if (size
!= ftell(file
)) {
625 ebt_print_error("File %s has wrong size", filename
);
629 entries
= (char *)malloc(repl
->entries_size
);
632 repl
->entries
= sparc_cast entries
;
633 if (repl
->nentries
) {
634 counters
= (struct ebt_counter
*)
635 malloc(repl
->nentries
* sizeof(struct ebt_counter
));
636 repl
->counters
= sparc_cast counters
;
640 repl
->counters
= sparc_cast NULL
;
641 /* Copy entries and counters */
642 if (fseek(file
, sizeof(struct ebt_replace
), SEEK_SET
) ||
643 fread((char *)repl
->entries
, sizeof(char), repl
->entries_size
, file
)
644 != repl
->entries_size
||
645 fseek(file
, sizeof(struct ebt_replace
) + repl
->entries_size
,
647 || (repl
->counters
&& fread((char *)repl
->counters
, sizeof(char),
648 repl
->nentries
* sizeof(struct ebt_counter
), file
)
649 != repl
->nentries
* sizeof(struct ebt_counter
))) {
650 ebt_print_error("File %s is corrupt", filename
);
652 repl
->entries
= NULL
;
661 static int retrieve_from_kernel(struct ebt_replace
*repl
, char command
,
668 optlen
= sizeof(struct ebt_replace
);
671 /* --atomic-init || --init-table */
673 optname
= EBT_SO_GET_INIT_INFO
;
675 optname
= EBT_SO_GET_INFO
;
676 if (getsockopt(sockfd
, IPPROTO_IP
, optname
, repl
, &optlen
))
679 if ( !(entries
= (char *)malloc(repl
->entries_size
)) )
681 repl
->entries
= sparc_cast entries
;
682 if (repl
->nentries
) {
683 struct ebt_counter
*counters
;
685 if (!(counters
= (struct ebt_counter
*)
686 malloc(repl
->nentries
* sizeof(struct ebt_counter
))) )
688 repl
->counters
= sparc_cast counters
;
691 repl
->counters
= sparc_cast NULL
;
693 /* We want to receive the counters */
694 repl
->num_counters
= repl
->nentries
;
695 optlen
+= repl
->entries_size
+ repl
->num_counters
*
696 sizeof(struct ebt_counter
);
698 optname
= EBT_SO_GET_INIT_ENTRIES
;
700 optname
= EBT_SO_GET_ENTRIES
;
701 if (getsockopt(sockfd
, IPPROTO_IP
, optname
, repl
, &optlen
))
702 ebt_print_bug("Hmm, what is wrong??? bug#1");
707 int ebt_get_table(struct ebt_u_replace
*u_repl
, int init
)
710 struct ebt_replace repl
;
711 struct ebt_u_entry
*u_e
= NULL
;
712 struct ebt_cntchanges
*new_cc
= NULL
, *cc
;
714 strcpy(repl
.name
, u_repl
->name
);
715 if (u_repl
->filename
!= NULL
) {
717 ebt_print_bug("Getting initial table data from a file is impossible");
718 if (retrieve_from_file(u_repl
->filename
, &repl
, u_repl
->command
))
720 /* -L with a wrong table name should be dealt with silently */
721 strcpy(u_repl
->name
, repl
.name
);
722 } else if (retrieve_from_kernel(&repl
, u_repl
->command
, init
))
725 /* Translate the struct ebt_replace to a struct ebt_u_replace */
726 u_repl
->valid_hooks
= repl
.valid_hooks
;
727 u_repl
->nentries
= repl
.nentries
;
728 u_repl
->num_counters
= repl
.num_counters
;
729 u_repl
->counters
= repl
.counters
;
730 u_repl
->cc
= (struct ebt_cntchanges
*)malloc(sizeof(struct ebt_cntchanges
));
733 u_repl
->cc
->next
= u_repl
->cc
->prev
= u_repl
->cc
;
735 for (i
= 0; i
< repl
.nentries
; i
++) {
736 new_cc
= (struct ebt_cntchanges
*)malloc(sizeof(struct ebt_cntchanges
));
739 new_cc
->type
= CNT_NORM
;
746 new_cc
->next
= u_repl
->cc
;
747 u_repl
->cc
->prev
= new_cc
;
749 u_repl
->chains
= (struct ebt_u_entries
**)calloc(EBT_ORI_MAX_CHAINS
, sizeof(void *));
750 u_repl
->max_chains
= EBT_ORI_MAX_CHAINS
;
752 /* FIXME: Clean up when an error is encountered */
753 EBT_ENTRY_ITERATE(repl
.entries
, repl
.entries_size
, ebt_translate_chains
,
754 &hook
, u_repl
, u_repl
->valid_hooks
);
755 if (hook
>= NF_BR_NUMHOOKS
)
756 u_repl
->num_chains
= hook
+ 1;
758 u_repl
->num_chains
= NF_BR_NUMHOOKS
;
759 i
= 0; /* Holds the expected nr. of entries for the chain */
760 j
= 0; /* Holds the up to now counted entries for the chain */
761 k
= 0; /* Holds the total nr. of entries, should equal u_repl->nentries afterwards */
762 cc
= u_repl
->cc
->next
;
764 EBT_ENTRY_ITERATE((char *)repl
.entries
, repl
.entries_size
,
765 ebt_translate_entry
, &hook
, &i
, &j
, &k
, &u_e
, u_repl
,
766 u_repl
->valid_hooks
, (char *)repl
.entries
, &cc
);
767 if (k
!= u_repl
->nentries
)
768 ebt_print_bug("Wrong total nentries");