|
@@ -254,9 +254,10 @@ unsigned int arpt_do_table(struct sk_buff *skb,
|
|
|
static const char nulldevname[IFNAMSIZ] __attribute__((aligned(sizeof(long))));
|
|
|
unsigned int verdict = NF_DROP;
|
|
|
const struct arphdr *arp;
|
|
|
- struct arpt_entry *e, *back;
|
|
|
+ struct arpt_entry *e, **jumpstack;
|
|
|
const char *indev, *outdev;
|
|
|
const void *table_base;
|
|
|
+ unsigned int cpu, stackidx = 0;
|
|
|
const struct xt_table_info *private;
|
|
|
struct xt_action_param acpar;
|
|
|
unsigned int addend;
|
|
@@ -270,15 +271,16 @@ unsigned int arpt_do_table(struct sk_buff *skb,
|
|
|
local_bh_disable();
|
|
|
addend = xt_write_recseq_begin();
|
|
|
private = table->private;
|
|
|
+ cpu = smp_processor_id();
|
|
|
/*
|
|
|
* Ensure we load private-> members after we've fetched the base
|
|
|
* pointer.
|
|
|
*/
|
|
|
smp_read_barrier_depends();
|
|
|
table_base = private->entries;
|
|
|
+ jumpstack = (struct arpt_entry **)private->jumpstack[cpu];
|
|
|
|
|
|
e = get_entry(table_base, private->hook_entry[hook]);
|
|
|
- back = get_entry(table_base, private->underflow[hook]);
|
|
|
|
|
|
acpar.in = state->in;
|
|
|
acpar.out = state->out;
|
|
@@ -312,18 +314,23 @@ unsigned int arpt_do_table(struct sk_buff *skb,
|
|
|
verdict = (unsigned int)(-v) - 1;
|
|
|
break;
|
|
|
}
|
|
|
- e = back;
|
|
|
- back = get_entry(table_base, back->comefrom);
|
|
|
+ if (stackidx == 0) {
|
|
|
+ e = get_entry(table_base,
|
|
|
+ private->underflow[hook]);
|
|
|
+ } else {
|
|
|
+ e = jumpstack[--stackidx];
|
|
|
+ e = arpt_next_entry(e);
|
|
|
+ }
|
|
|
continue;
|
|
|
}
|
|
|
if (table_base + v
|
|
|
!= arpt_next_entry(e)) {
|
|
|
- /* Save old back ptr in next entry */
|
|
|
- struct arpt_entry *next = arpt_next_entry(e);
|
|
|
- next->comefrom = (void *)back - table_base;
|
|
|
|
|
|
- /* set back pointer to next entry */
|
|
|
- back = next;
|
|
|
+ if (stackidx >= private->stacksize) {
|
|
|
+ verdict = NF_DROP;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ jumpstack[stackidx++] = e;
|
|
|
}
|
|
|
|
|
|
e = get_entry(table_base, v);
|