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 *)malloc(u_repl
->num_chains
* sizeof(unsigned int));
71 for (i
= 0; i
< u_repl
->num_chains
; i
++) {
72 if (!(entries
= u_repl
->chains
[i
]))
74 chain_offsets
[i
] = entries_size
;
75 entries_size
+= sizeof(struct ebt_entries
);
77 e
= entries
->entries
->next
;
78 while (e
!= entries
->entries
) {
80 entries_size
+= sizeof(struct ebt_entry
);
83 entries_size
+= m_l
->m
->match_size
+
84 sizeof(struct ebt_entry_match
);
89 entries_size
+= w_l
->w
->watcher_size
+
90 sizeof(struct ebt_entry_watcher
);
93 entries_size
+= e
->t
->target_size
+
94 sizeof(struct ebt_entry_target
);
97 /* A little sanity check */
98 if (j
!= entries
->nentries
)
99 ebt_print_bug("Wrong nentries: %d != %d, hook = %s", j
,
100 entries
->nentries
, entries
->name
);
103 new->entries_size
= entries_size
;
104 p
= (char *)malloc(entries_size
);
108 /* Put everything in one block */
109 new->entries
= sparc_cast p
;
110 for (i
= 0; i
< u_repl
->num_chains
; i
++) {
111 struct ebt_entries
*hlp
;
113 hlp
= (struct ebt_entries
*)p
;
114 if (!(entries
= u_repl
->chains
[i
]))
116 if (i
< NF_BR_NUMHOOKS
)
117 new->hook_entry
[i
] = sparc_cast hlp
;
118 hlp
->nentries
= entries
->nentries
;
119 hlp
->policy
= entries
->policy
;
120 strcpy(hlp
->name
, entries
->name
);
121 hlp
->counter_offset
= entries
->counter_offset
;
122 hlp
->distinguisher
= 0; /* Make the kernel see the light */
123 p
+= sizeof(struct ebt_entries
);
124 e
= entries
->entries
->next
;
125 while (e
!= entries
->entries
) {
126 struct ebt_entry
*tmp
= (struct ebt_entry
*)p
;
128 tmp
->bitmask
= e
->bitmask
| EBT_ENTRY_OR_ENTRIES
;
129 tmp
->invflags
= e
->invflags
;
130 tmp
->ethproto
= e
->ethproto
;
131 strcpy(tmp
->in
, e
->in
);
132 strcpy(tmp
->out
, e
->out
);
133 strcpy(tmp
->logical_in
, e
->logical_in
);
134 strcpy(tmp
->logical_out
, e
->logical_out
);
135 memcpy(tmp
->sourcemac
, e
->sourcemac
,
136 sizeof(tmp
->sourcemac
));
137 memcpy(tmp
->sourcemsk
, e
->sourcemsk
,
138 sizeof(tmp
->sourcemsk
));
139 memcpy(tmp
->destmac
, e
->destmac
, sizeof(tmp
->destmac
));
140 memcpy(tmp
->destmsk
, e
->destmsk
, sizeof(tmp
->destmsk
));
143 p
+= sizeof(struct ebt_entry
);
146 memcpy(p
, m_l
->m
, m_l
->m
->match_size
+
147 sizeof(struct ebt_entry_match
));
148 p
+= m_l
->m
->match_size
+
149 sizeof(struct ebt_entry_match
);
152 tmp
->watchers_offset
= p
- base
;
155 memcpy(p
, w_l
->w
, w_l
->w
->watcher_size
+
156 sizeof(struct ebt_entry_watcher
));
157 p
+= w_l
->w
->watcher_size
+
158 sizeof(struct ebt_entry_watcher
);
161 tmp
->target_offset
= p
- base
;
162 memcpy(p
, e
->t
, e
->t
->target_size
+
163 sizeof(struct ebt_entry_target
));
164 if (!strcmp(e
->t
->u
.name
, EBT_STANDARD_TARGET
)) {
165 struct ebt_standard_target
*st
=
166 (struct ebt_standard_target
*)p
;
167 /* Translate the jump to a udc */
168 if (st
->verdict
>= 0)
169 st
->verdict
= chain_offsets
170 [st
->verdict
+ NF_BR_NUMHOOKS
];
172 p
+= e
->t
->target_size
+
173 sizeof(struct ebt_entry_target
);
174 tmp
->next_offset
= p
- base
;
180 if (p
- (char *)new->entries
!= new->entries_size
)
181 ebt_print_bug("Entries_size bug");
186 static void store_table_in_file(char *filename
, struct ebt_replace
*repl
)
192 /* Start from an empty file with right priviliges */
193 if (!(fd
= creat(filename
, 0600))) {
194 ebt_print_error("Couldn't create file %s", filename
);
198 size
= sizeof(struct ebt_replace
) + repl
->entries_size
+
199 repl
->nentries
* sizeof(struct ebt_counter
);
200 data
= (char *)malloc(size
);
203 memcpy(data
, repl
, sizeof(struct ebt_replace
));
204 memcpy(data
+ sizeof(struct ebt_replace
), (char *)repl
->entries
,
206 /* Initialize counters to zero, deliver_counters() can update them */
207 memset(data
+ sizeof(struct ebt_replace
) + repl
->entries_size
,
208 0, repl
->nentries
* sizeof(struct ebt_counter
));
209 if (write(fd
, data
, size
) != size
)
210 ebt_print_error("Couldn't write everything to file %s",
216 void ebt_deliver_table(struct ebt_u_replace
*u_repl
)
219 struct ebt_replace
*repl
;
221 /* Translate the struct ebt_u_replace to a struct ebt_replace */
222 repl
= translate_user2kernel(u_repl
);
223 if (u_repl
->filename
!= NULL
) {
224 store_table_in_file(u_repl
->filename
, repl
);
227 /* Give the data to the kernel */
228 optlen
= sizeof(struct ebt_replace
) + repl
->entries_size
;
231 if (!setsockopt(sockfd
, IPPROTO_IP
, EBT_SO_SET_ENTRIES
, repl
, optlen
))
233 if (u_repl
->command
== 8) { /* The ebtables module may not
234 * yet be loaded with --atomic-commit */
235 ebtables_insmod("ebtables");
236 if (!setsockopt(sockfd
, IPPROTO_IP
, EBT_SO_SET_ENTRIES
,
241 ebt_print_error("The kernel doesn't support a certain ebtables"
242 " extension, consider recompiling your kernel or insmod"
251 static int store_counters_in_file(char *filename
, struct ebt_u_replace
*repl
)
253 int size
= repl
->nentries
* sizeof(struct ebt_counter
), ret
= 0;
254 unsigned int entries_size
;
255 struct ebt_replace hlp
;
258 if (!(file
= fopen(filename
, "r+b"))) {
259 ebt_print_error("Could not open file %s", filename
);
262 /* Find out entries_size and then set the file pointer to the
264 if (fseek(file
, (char *)(&hlp
.entries_size
) - (char *)(&hlp
), SEEK_SET
)
265 || fread(&entries_size
, sizeof(char), sizeof(unsigned int), file
) !=
266 sizeof(unsigned int) ||
267 fseek(file
, entries_size
+ sizeof(struct ebt_replace
), SEEK_SET
)) {
268 ebt_print_error("File %s is corrupt", filename
);
272 if (fwrite(repl
->counters
, sizeof(char), size
, file
) != size
) {
273 ebt_print_error("Could not write everything to file %s",
282 /* Gets executed after ebt_deliver_table. Delivers the counters to the kernel
283 * and resets the counterchanges to CNT_NORM */
284 void ebt_deliver_counters(struct ebt_u_replace
*u_repl
)
286 struct ebt_counter
*old
, *new, *newcounters
;
288 struct ebt_replace repl
;
289 struct ebt_cntchanges
*cc
= u_repl
->cc
->next
, *cc2
;
290 struct ebt_u_entries
*entries
;
291 struct ebt_u_entry
*next
= NULL
;
294 if (u_repl
->nentries
== 0)
297 newcounters
= (struct ebt_counter
*)
298 malloc(u_repl
->nentries
* sizeof(struct ebt_counter
));
301 memset(newcounters
, 0, u_repl
->nentries
* sizeof(struct ebt_counter
));
302 old
= u_repl
->counters
;
304 while (cc
!= u_repl
->cc
) {
305 if (!next
|| next
== entries
->entries
) {
306 while (chainnr
< u_repl
->num_chains
&& (!(entries
= u_repl
->chains
[chainnr
++]) ||
307 (next
= entries
->entries
->next
) == entries
->entries
));
308 if (chainnr
== u_repl
->num_chains
)
311 if (cc
->type
== CNT_NORM
) {
312 /* 'Normal' rule, meaning we didn't do anything to it
313 * So, we just copy */
316 next
->cnt_surplus
.pcnt
= next
->cnt_surplus
.bcnt
= 0;
317 old
++; /* We've used an old counter */
318 new++; /* We've set a new counter */
320 } else if (cc
->type
== CNT_DEL
) {
321 old
++; /* Don't use this old counter */
323 if (cc
->type
== CNT_CHANGE
) {
324 if (cc
->change
% 3 == 1)
325 new->pcnt
= old
->pcnt
+ next
->cnt_surplus
.pcnt
;
326 else if (cc
->change
% 3 == 2)
327 new->pcnt
= old
->pcnt
- next
->cnt_surplus
.pcnt
;
329 new->pcnt
= next
->cnt
.pcnt
;
330 if (cc
->change
/ 3 == 1)
331 new->bcnt
= old
->bcnt
+ next
->cnt_surplus
.bcnt
;
332 else if (cc
->change
/ 3 == 2)
333 new->bcnt
= old
->bcnt
- next
->cnt_surplus
.bcnt
;
335 new->bcnt
= next
->cnt
.bcnt
;
339 next
->cnt_surplus
.pcnt
= next
->cnt_surplus
.bcnt
= 0;
340 if (cc
->type
== CNT_ADD
)
351 free(u_repl
->counters
);
352 u_repl
->counters
= newcounters
;
353 u_repl
->num_counters
= u_repl
->nentries
;
354 /* Reset the counterchanges to CNT_NORM and delete the unused cc */
356 cc
= u_repl
->cc
->next
;
357 while (cc
!= u_repl
->cc
) {
358 if (cc
->type
== CNT_DEL
) {
359 cc
->prev
->next
= cc
->next
;
360 cc
->next
->prev
= cc
->prev
;
371 if (i
!= u_repl
->nentries
)
372 ebt_print_bug("i != u_repl->nentries");
373 if (u_repl
->filename
!= NULL
) {
374 store_counters_in_file(u_repl
->filename
, u_repl
);
377 optlen
= u_repl
->nentries
* sizeof(struct ebt_counter
) +
378 sizeof(struct ebt_replace
);
379 /* Now put the stuff in the kernel's struct ebt_replace */
380 repl
.counters
= sparc_cast u_repl
->counters
;
381 repl
.num_counters
= u_repl
->num_counters
;
382 memcpy(repl
.name
, u_repl
->name
, sizeof(repl
.name
));
386 if (setsockopt(sockfd
, IPPROTO_IP
, EBT_SO_SET_COUNTERS
, &repl
, optlen
))
387 ebt_print_bug("Couldn't update kernel counters");
391 ebt_translate_match(struct ebt_entry_match
*m
, struct ebt_u_match_list
***l
)
393 struct ebt_u_match_list
*new;
396 new = (struct ebt_u_match_list
*)
397 malloc(sizeof(struct ebt_u_match_list
));
400 new->m
= (struct ebt_entry_match
*)
401 malloc(m
->match_size
+ sizeof(struct ebt_entry_match
));
404 memcpy(new->m
, m
, m
->match_size
+ sizeof(struct ebt_entry_match
));
408 if (ebt_find_match(new->m
->u
.name
) == NULL
) {
409 ebt_print_error("Kernel match %s unsupported by userspace tool",
417 ebt_translate_watcher(struct ebt_entry_watcher
*w
,
418 struct ebt_u_watcher_list
***l
)
420 struct ebt_u_watcher_list
*new;
423 new = (struct ebt_u_watcher_list
*)
424 malloc(sizeof(struct ebt_u_watcher_list
));
427 new->w
= (struct ebt_entry_watcher
*)
428 malloc(w
->watcher_size
+ sizeof(struct ebt_entry_watcher
));
431 memcpy(new->w
, w
, w
->watcher_size
+ sizeof(struct ebt_entry_watcher
));
435 if (ebt_find_watcher(new->w
->u
.name
) == NULL
) {
436 ebt_print_error("Kernel watcher %s unsupported by userspace "
437 "tool", new->w
->u
.name
);
444 ebt_translate_entry(struct ebt_entry
*e
, int *hook
, int *n
, int *cnt
,
445 int *totalcnt
, struct ebt_u_entry
**u_e
, struct ebt_u_replace
*u_repl
,
446 unsigned int valid_hooks
, char *base
, struct ebt_cntchanges
**cc
)
449 if (e
->bitmask
& EBT_ENTRY_OR_ENTRIES
) {
450 struct ebt_u_entry
*new;
451 struct ebt_u_match_list
**m_l
;
452 struct ebt_u_watcher_list
**w_l
;
453 struct ebt_entry_target
*t
;
455 new = (struct ebt_u_entry
*)malloc(sizeof(struct ebt_u_entry
));
458 new->bitmask
= e
->bitmask
;
460 * Plain userspace code doesn't know about
461 * EBT_ENTRY_OR_ENTRIES
463 new->bitmask
&= ~EBT_ENTRY_OR_ENTRIES
;
464 new->invflags
= e
->invflags
;
465 new->ethproto
= e
->ethproto
;
466 strcpy(new->in
, e
->in
);
467 strcpy(new->out
, e
->out
);
468 strcpy(new->logical_in
, e
->logical_in
);
469 strcpy(new->logical_out
, e
->logical_out
);
470 memcpy(new->sourcemac
, e
->sourcemac
, sizeof(new->sourcemac
));
471 memcpy(new->sourcemsk
, e
->sourcemsk
, sizeof(new->sourcemsk
));
472 memcpy(new->destmac
, e
->destmac
, sizeof(new->destmac
));
473 memcpy(new->destmsk
, e
->destmsk
, sizeof(new->destmsk
));
474 if (*totalcnt
>= u_repl
->nentries
)
475 ebt_print_bug("*totalcnt >= u_repl->nentries");
476 new->cnt
= u_repl
->counters
[*totalcnt
];
477 new->cnt_surplus
.pcnt
= new->cnt_surplus
.bcnt
= 0;
482 new->next
= (*u_e
)->next
;
483 new->next
->prev
= new;
488 EBT_MATCH_ITERATE(e
, ebt_translate_match
, &m_l
);
490 EBT_WATCHER_ITERATE(e
, ebt_translate_watcher
, &w_l
);
492 t
= (struct ebt_entry_target
*)(((char *)e
) + e
->target_offset
);
493 new->t
= (struct ebt_entry_target
*)
494 malloc(t
->target_size
+ sizeof(struct ebt_entry_target
));
497 if (ebt_find_target(t
->u
.name
) == NULL
) {
498 ebt_print_error("Kernel target %s unsupported by "
499 "userspace tool", t
->u
.name
);
502 memcpy(new->t
, t
, t
->target_size
+
503 sizeof(struct ebt_entry_target
));
504 /* Deal with jumps to udc */
505 if (!strcmp(t
->u
.name
, EBT_STANDARD_TARGET
)) {
507 int verdict
= ((struct ebt_standard_target
*)t
)->verdict
;
512 for (i
= NF_BR_NUMHOOKS
; i
< u_repl
->num_chains
; i
++)
513 if (u_repl
->chains
[i
]->kernel_start
== tmp
)
515 if (i
== u_repl
->num_chains
)
516 ebt_print_bug("Can't find udc for jump");
517 ((struct ebt_standard_target
*)new->t
)->verdict
= i
-NF_BR_NUMHOOKS
;
524 } else { /* A new chain */
526 struct ebt_entries
*entries
= (struct ebt_entries
*)e
;
529 ebt_print_bug("Nr of entries in the chain is wrong");
530 *n
= entries
->nentries
;
532 for (i
= *hook
+ 1; i
< NF_BR_NUMHOOKS
; i
++)
533 if (valid_hooks
& (1 << i
))
536 *u_e
= u_repl
->chains
[*hook
]->entries
;
541 /* Initialize all chain headers */
543 ebt_translate_chains(struct ebt_entry
*e
, int *hook
,
544 struct ebt_u_replace
*u_repl
, unsigned int valid_hooks
)
547 struct ebt_entries
*entries
= (struct ebt_entries
*)e
;
548 struct ebt_u_entries
*new;
550 if (!(e
->bitmask
& EBT_ENTRY_OR_ENTRIES
)) {
551 for (i
= *hook
+ 1; i
< NF_BR_NUMHOOKS
; i
++)
552 if (valid_hooks
& (1 << i
))
554 new = (struct ebt_u_entries
*)malloc(sizeof(struct ebt_u_entries
));
557 if (i
== u_repl
->max_chains
)
558 ebt_double_chains(u_repl
);
559 u_repl
->chains
[i
] = new;
560 if (i
>= NF_BR_NUMHOOKS
)
561 new->kernel_start
= (char *)e
;
563 new->nentries
= entries
->nentries
;
564 new->policy
= entries
->policy
;
565 new->entries
= (struct ebt_u_entry
*)malloc(sizeof(struct ebt_u_entry
));
568 new->entries
->next
= new->entries
->prev
= new->entries
;
569 new->counter_offset
= entries
->counter_offset
;
570 strcpy(new->name
, entries
->name
);
575 static int retrieve_from_file(char *filename
, struct ebt_replace
*repl
,
579 char *hlp
= NULL
, *entries
;
580 struct ebt_counter
*counters
;
583 if (!(file
= fopen(filename
, "r+b"))) {
584 ebt_print_error("Could not open file %s", filename
);
587 /* Make sure table name is right if command isn't -L or --atomic-commit */
588 if (command
!= 'L' && command
!= 8) {
589 hlp
= (char *)malloc(strlen(repl
->name
) + 1);
592 strcpy(hlp
, repl
->name
);
594 if (fread(repl
, sizeof(char), sizeof(struct ebt_replace
), file
)
595 != sizeof(struct ebt_replace
)) {
596 ebt_print_error("File %s is corrupt", filename
);
600 if (command
!= 'L' && command
!= 8 && strcmp(hlp
, repl
->name
)) {
601 ebt_print_error("File %s contains wrong table name or is "
602 "corrupt", filename
);
605 } else if (!ebt_find_table(repl
->name
)) {
606 ebt_print_error("File %s contains invalid table name",
612 size
= sizeof(struct ebt_replace
) +
613 repl
->nentries
* sizeof(struct ebt_counter
) + repl
->entries_size
;
614 fseek(file
, 0, SEEK_END
);
615 if (size
!= ftell(file
)) {
616 ebt_print_error("File %s has wrong size", filename
);
620 entries
= (char *)malloc(repl
->entries_size
);
623 repl
->entries
= sparc_cast entries
;
624 if (repl
->nentries
) {
625 counters
= (struct ebt_counter
*)
626 malloc(repl
->nentries
* sizeof(struct ebt_counter
));
627 repl
->counters
= sparc_cast counters
;
631 repl
->counters
= sparc_cast NULL
;
632 /* Copy entries and counters */
633 if (fseek(file
, sizeof(struct ebt_replace
), SEEK_SET
) ||
634 fread((char *)repl
->entries
, sizeof(char), repl
->entries_size
, file
)
635 != repl
->entries_size
||
636 fseek(file
, sizeof(struct ebt_replace
) + repl
->entries_size
,
638 || fread((char *)repl
->counters
, sizeof(char),
639 repl
->nentries
* sizeof(struct ebt_counter
), file
)
640 != repl
->nentries
* sizeof(struct ebt_counter
)) {
641 ebt_print_error("File %s is corrupt", filename
);
643 repl
->entries
= NULL
;
652 static int retrieve_from_kernel(struct ebt_replace
*repl
, char command
,
659 optlen
= sizeof(struct ebt_replace
);
662 /* --atomic-init || --init-table */
664 optname
= EBT_SO_GET_INIT_INFO
;
666 optname
= EBT_SO_GET_INFO
;
667 if (getsockopt(sockfd
, IPPROTO_IP
, optname
, repl
, &optlen
))
670 if ( !(entries
= (char *)malloc(repl
->entries_size
)) )
672 repl
->entries
= sparc_cast entries
;
673 if (repl
->nentries
) {
674 struct ebt_counter
*counters
;
676 if (!(counters
= (struct ebt_counter
*)
677 malloc(repl
->nentries
* sizeof(struct ebt_counter
))) )
679 repl
->counters
= sparc_cast counters
;
682 repl
->counters
= sparc_cast NULL
;
684 /* We want to receive the counters */
685 repl
->num_counters
= repl
->nentries
;
686 optlen
+= repl
->entries_size
+ repl
->num_counters
*
687 sizeof(struct ebt_counter
);
689 optname
= EBT_SO_GET_INIT_ENTRIES
;
691 optname
= EBT_SO_GET_ENTRIES
;
692 if (getsockopt(sockfd
, IPPROTO_IP
, optname
, repl
, &optlen
))
693 ebt_print_bug("Hmm, what is wrong??? bug#1");
698 int ebt_get_table(struct ebt_u_replace
*u_repl
, int init
)
701 struct ebt_replace repl
;
702 struct ebt_u_entry
*u_e
;
703 struct ebt_cntchanges
*new_cc
, *cc
;
705 strcpy(repl
.name
, u_repl
->name
);
706 if (u_repl
->filename
!= NULL
) {
708 ebt_print_bug("Getting initial table data from a file is impossible");
709 if (retrieve_from_file(u_repl
->filename
, &repl
, u_repl
->command
))
711 /* -L with a wrong table name should be dealt with silently */
712 strcpy(u_repl
->name
, repl
.name
);
713 } else if (retrieve_from_kernel(&repl
, u_repl
->command
, init
))
716 /* Translate the struct ebt_replace to a struct ebt_u_replace */
717 u_repl
->valid_hooks
= repl
.valid_hooks
;
718 u_repl
->nentries
= repl
.nentries
;
719 u_repl
->num_counters
= repl
.num_counters
;
720 u_repl
->counters
= repl
.counters
;
721 u_repl
->cc
= (struct ebt_cntchanges
*)malloc(sizeof(struct ebt_cntchanges
));
724 u_repl
->cc
->next
= u_repl
->cc
->prev
= u_repl
->cc
;
726 for (i
= 0; i
< repl
.nentries
; i
++) {
727 new_cc
= (struct ebt_cntchanges
*)malloc(sizeof(struct ebt_cntchanges
));
730 new_cc
->type
= CNT_NORM
;
737 new_cc
->next
= u_repl
->cc
;
738 u_repl
->cc
->prev
= new_cc
;
740 u_repl
->chains
= (struct ebt_u_entries
**)calloc(EBT_ORI_MAX_CHAINS
, sizeof(void *));
741 u_repl
->max_chains
= EBT_ORI_MAX_CHAINS
;
743 /* FIXME: Clean up when an error is encountered */
744 EBT_ENTRY_ITERATE(repl
.entries
, repl
.entries_size
, ebt_translate_chains
,
745 &hook
, u_repl
, u_repl
->valid_hooks
);
746 if (hook
>= NF_BR_NUMHOOKS
)
747 u_repl
->num_chains
= hook
+ 1;
749 u_repl
->num_chains
= NF_BR_NUMHOOKS
;
750 i
= 0; /* Holds the expected nr. of entries for the chain */
751 j
= 0; /* Holds the up to now counted entries for the chain */
752 k
= 0; /* Holds the total nr. of entries, should equal u_repl->nentries afterwards */
753 cc
= u_repl
->cc
->next
;
755 EBT_ENTRY_ITERATE((char *)repl
.entries
, repl
.entries_size
,
756 ebt_translate_entry
, &hook
, &i
, &j
, &k
, &u_e
, u_repl
,
757 u_repl
->valid_hooks
, (char *)repl
.entries
, &cc
);
758 if (k
!= u_repl
->nentries
)
759 ebt_print_bug("Wrong total nentries");