#include <kern/zalloc.h>
#define NET_REG_EAX 0
#define NET_REG_EDX 1
#define NET_REG_EBX 2
#define NET_REG_ESI 3
#define NET_REG_EDI 4
#define NET_REG_MAX 5
struct net_opt {
filter_t val;
unsigned char reg;
unsigned char used;
};
boolean_t net_filter_enable = FALSE;
void net_filter_optimize(
struct net_opt net_o[],
unsigned net_len,
int reg[],
unsigned nbreg);
filter_fct_t
net_filter_alloc(
filter_t *fpstart,
unsigned int fplen,
unsigned int *len)
{
filter_t *fp;
unsigned int op;
unsigned int arg;
unsigned char *p;
filter_fct_t top;
unsigned char *pend;
unsigned char *pend_old;
unsigned int loop;
unsigned int use_header;
unsigned int use_data;
unsigned int push_ecx;
int reg[NET_REG_MAX];
struct net_opt net_o[NET_MAX_FILTER];
int net_i;
unsigned net_j;
unsigned i;
unsigned push;
unsigned false_pad;
struct net_opt *pn;
#define PEND_TRUE (pend_old - (11 + push + false_pad))
#define PEND_FALSE (pend_old - (4 + push))
if (!net_filter_enable) {
*len = 0;
return ((filter_fct_t)0);
}
loop = 0;
p = (unsigned char *)0;
pend = 0;
use_header = 0;
use_data = 0;
net_j = 0;
false_pad = sizeof(int) - 1;
for (;;) {
if (loop == 0)
pend += 14;
else if (loop == 1) {
if (reg[NET_REG_EBX] == -1) {
pend++;
push = 1;
} else
push = 0;
if (reg[NET_REG_ESI] == -1) {
pend++;
push++;
}
if (reg[NET_REG_EDI] == -1) {
pend++;
push++;
}
if (push) {
push += 3;
}
if (use_data)
pend += 3;
if (use_header)
pend += 3;
pend += 8;
} else {
*p++ = 0x55;
*p++ = 0x89;
*p++ = 0xE5;
if (reg[NET_REG_EBX] == -1)
*p++ = 0x53;
if (reg[NET_REG_ESI] == -1)
*p++ = 0x56;
if (reg[NET_REG_EDI] == -1)
*p++ = 0x57;
*p++ = 0xB9;
*p++ = 0x01;
*p++ = 0x00;
*p++ = 0x00;
*p++ = 0x00;
if (use_data) {
*p++ = 0x8B;
*p++ = 0x45;
*p++ = 0x08;
}
if (use_header) {
*p++ = 0x8B;
*p++ = 0x55;
*p++ = 0x10;
}
}
push_ecx = 1;
net_i = -1;
fp = fpstart;
while (fp - fpstart < fplen)
{
arg = *fp++;
op = NETF_OP(arg);
arg = NETF_ARG(arg);
switch (arg) {
case NETF_NOPUSH:
if (push_ecx) {
push_ecx = 0;
break;
}
if (loop < 2)
pend++;
else
*p++ = 0x59;
break;
case NETF_PUSHZERO:
if (loop < 2) {
if (push_ecx) {
pend++;
push_ecx = 0;
}
pend += 2;
} else {
if (push_ecx) {
*p++ = 0x51;
push_ecx = 0;
}
*p++ = 0x31;
*p++ = 0xC9;
}
break;
case NETF_PUSHLIT:
if (loop < 2) {
if (push_ecx) {
pend++;
push_ecx = 0;
}
pend += 5;
} else {
if (push_ecx) {
*p++ = 0x51;
push_ecx = 0;
}
*p++ = 0xB9;
*p++ = *(unsigned char *)fp;
*p++ = *(((unsigned char *)fp) + 1);
*p++ = 0x0;
*p++ = 0x0;
}
fp++;
break;
case NETF_PUSHIND:
if (loop < 2) {
if (push_ecx)
push_ecx = 0;
else
pend++;
if (loop == 0)
use_data = 1;
if (loop == 0 ||
PEND_FALSE - (pend + 5) >= 128)
pend += 14;
else
pend += 10;
break;
}
if (push_ecx)
push_ecx = 0;
else
*p++ = 0x59;
*p++ = 0x39;
*p++ = 0x4D;
*p++ = 0x0C;
if (PEND_FALSE - (p + 2) >= 128) {
*p++ = 0x0F;
*p++ = 0x8E;
*(p+0) = PEND_FALSE - (p + 4);
*(p+1) = (PEND_FALSE - (p + 4)) >> 8;
*(p+2) = (PEND_FALSE - (p + 4)) >> 16;
*(p+3) = (PEND_FALSE - (p + 4)) >> 24;
p += 4;
} else {
*p++ = 0x7E;
*p = PEND_FALSE - (p + 1);
p++;
}
*p++ = 0x0F;
*p++ = 0xB7;
*p++ = 0x4C;
*p++ = 0x48;
*p++ = 0x00;
break;
case NETF_PUSHHDRIND:
if (loop < 2) {
if (push_ecx)
push_ecx = 0;
else
pend++;
if (loop == 0)
use_header = 1;
if (loop == 0 ||
PEND_FALSE - (pend + 8) >= 128)
pend += 17;
else
pend += 13;
break;
}
if (push_ecx)
push_ecx = 0;
else
*p++ = 0x59;
*p++ = 0x81;
*p++ = 0xF9;
*p++ = NET_HDW_HDR_MAX /
sizeof(unsigned short);
*p++ = (NET_HDW_HDR_MAX /
sizeof(unsigned short)) >> 8;
*p++ = (NET_HDW_HDR_MAX /
sizeof(unsigned short)) >> 16;
*p++ = (NET_HDW_HDR_MAX /
sizeof(unsigned short)) >> 24;
if (PEND_FALSE - (p + 2) >= 128) {
*p++ = 0x0F;
*p++ = 0x8D;
*(p+0) = PEND_FALSE - (p + 4);
*(p+1) = (PEND_FALSE - (p + 4)) >> 8;
*(p+2) = (PEND_FALSE - (p + 4)) >> 16;
*(p+3) = (PEND_FALSE - (p + 4)) >> 24;
p += 4;
} else {
*p++ = 0x7D;
*p = PEND_FALSE - (p + 1);
p++;
}
*p++ = 0x0F;
*p++ = 0xB7;
*p++ = 0x4C;
*p++ = 0x4A;
*p++ = 0x00;
break;
default:
if (arg >= NETF_PUSHSTK) {
arg -= NETF_PUSHSTK;
arg <<= 2;
if (loop < 2) {
if (push_ecx) {
pend++;
push_ecx = 0;
}
pend += (arg < 128) ? 4 : 7;
break;
}
if (push_ecx) {
*p++ = 0x51;
push_ecx = 0;
}
*p++ = 0x8B;
if (arg < 128) {
*p++ = 0x4C;
*p++ = 0x24;
*p++ = arg;
} else {
*p++ = 0x8C;
*p++ = 0x24;
*p++ = arg;
*p++ = arg >> 8;
*p++ = arg >> 16;
*p++ = arg >> 24;
}
} else if (arg >= NETF_PUSHHDR) {
arg -= NETF_PUSHHDR;
arg <<= 1;
if (loop < 2) {
if (push_ecx) {
pend++;
push_ecx = 0;
}
if (loop == 0) {
use_header = 1;
net_o[net_j++].val =
arg + NETF_PUSHHDR;
} else {
net_i++;
assert(net_i < net_j);
pn = &net_o[net_i];
assert(reg[NET_REG_EDX]
== -2);
assert(pn->used == 0 ||
reg[pn->reg]
!= -2);
assert(pn->val == arg +
NETF_PUSHHDR);
if (pn->used > 0 &&
reg[pn->reg] >= 0 &&
net_o[reg[pn->reg]]
.val == pn->val) {
pend += 2;
break;
}
}
pend += (arg < 128) ? 5 : 8;
if (loop == 1 && pn->used > 1 &&
(reg[pn->reg] < 0 ||
net_o[reg[pn->reg]].val !=
pn->val)) {
reg[pn->reg] = net_i;
pend += 2;
}
break;
}
if (push_ecx) {
*p++ = 0x51;
push_ecx = 0;
}
net_i++;
assert(net_i < net_j);
pn = &net_o[net_i];
assert(reg[NET_REG_EDX] == -2);
assert(pn->used == 0 ||
reg[pn->reg] != -2);
assert(pn->val == arg + NETF_PUSHHDR);
if (pn->used > 0 &&
reg[pn->reg] >= 0 &&
net_o[reg[pn->reg]].val ==
pn->val) {
*p++ = 0x89;
switch (pn->reg) {
case NET_REG_EAX:
*p++ = 0xC1;
break;
case NET_REG_EBX:
*p++ = 0xD9;
break;
case NET_REG_ESI:
*p++ = 0xF1;
break;
case NET_REG_EDI:
*p++ = 0xF9;
break;
}
break;
}
*p++ = 0x0F;
*p++ = 0xB7;
if (arg < 128) {
*p++ = 0x4C;
*p++ = 0x22;
*p++ = arg;
} else {
*p++ = 0x8C;
*p++ = 0x22;
*p++ = arg;
*p++ = arg >> 8;
*p++ = arg >> 16;
*p++ = arg >> 24;
}
if (pn->used > 1 &&
(reg[pn->reg] == -1 ||
net_o[reg[pn->reg]].val !=
pn->val)) {
reg[pn->reg] = net_i;
*p++ = 0x89;
assert(net_o[net_i].reg !=
NET_REG_EDX);
switch (net_o[net_i].reg) {
case NET_REG_EAX:
*p++ = 0xC8;
break;
case NET_REG_EBX:
*p++ = 0xCB;
break;
case NET_REG_ESI:
*p++ = 0xCE;
break;
case NET_REG_EDI:
*p++ = 0xCF;
break;
}
}
} else {
arg -= NETF_PUSHWORD;
if (loop < 2) {
if (push_ecx) {
pend++;
push_ecx = 0;
}
if (loop == 0) {
use_data = 1;
net_o[net_j++].val =
arg + NETF_PUSHWORD;
} else {
net_i++;
assert(net_i < net_j);
pn = &net_o[net_i];
assert(reg[NET_REG_EAX]
== -2);
assert(pn->used == 0 ||
reg[pn->reg]
!= -2);
assert(pn->val == arg +
NETF_PUSHWORD);
if (pn->used > 0 &&
reg[pn->reg] >= 0 &&
net_o[reg[pn->reg]]
.val == pn->val) {
pend += 2;
break;
}
}
arg <<= 1;
pend += (arg < 128) ? 4 : 7;
if (loop == 0 ||
(PEND_FALSE -
(pend + 2)) >= 128)
pend += 6;
else
pend += 2;
if (arg < 128)
pend += 5;
else
pend += 8;
if (loop == 1 && pn->used > 1 &&
(reg[pn->reg] < 0 ||
net_o[reg[pn->reg]].val !=
pn->val)) {
reg[pn->reg] = net_i;
pend += 2;
}
break;
}
if (push_ecx) {
*p++ = 0x51;
push_ecx = 0;
}
net_i++;
assert(net_i < net_j);
pn = &net_o[net_i];
assert(reg[NET_REG_EAX] == -2);
assert(pn->used == 0 ||
reg[pn->reg] != -2);
assert(pn->val == arg + NETF_PUSHWORD);
if (pn->used > 0 &&
reg[pn->reg] >= 0 &&
net_o[reg[pn->reg]].val ==
pn->val) {
*p++ = 0x89;
switch (pn->reg) {
case NET_REG_EDX:
*p++ = 0xD1;
break;
case NET_REG_EBX:
*p++ = 0xD9;
break;
case NET_REG_ESI:
*p++ = 0xF1;
break;
case NET_REG_EDI:
*p++ = 0xF9;
break;
}
break;
}
arg <<= 1;
if (arg < 128) {
*p++ = 0x83;
*p++ = 0x7D;
*p++ = 0x0C;
*p++ = arg;
} else {
*p++ = 0x81;
*p++ = 0x7D;
*p++ = 0x0C;
*p++ = arg;
*p++ = arg >> 8;
*p++ = arg >> 16;
*p++ = arg >> 24;
}
if (PEND_FALSE - (p + 2) >= 128) {
*p++ = 0x0F;
*p++ = 0x8E;
*(p+0) = PEND_FALSE - (p + 4);
*(p+1) = (PEND_FALSE - (p + 4))
>> 8;
*(p+2) = (PEND_FALSE - (p + 4))
>> 16;
*(p+3) = (PEND_FALSE - (p + 4))
>> 24;
p += 4;
} else {
*p++ = 0x7E;
*p = PEND_FALSE - (p + 1);
p++;
}
*p++ = 0x0F;
*p++ = 0xB7;
if (arg < 128) {
*p++ = 0x4C;
*p++ = 0x20;
*p++ = arg;
} else {
*p++ = 0x8C;
*p++ = 0x20;
*p++ = arg;
*p++ = arg >> 8;
*p++ = arg >> 16;
*p++ = arg >> 24;
}
if (pn->used > 1 &&
(reg[pn->reg] == -1 ||
net_o[reg[pn->reg]].val !=
pn->val)) {
reg[pn->reg] = net_i;
*p++ = 0x89;
assert(net_o[net_i].reg !=
NET_REG_EAX);
switch (net_o[net_i].reg) {
case NET_REG_EDX:
*p++ = 0xCA;
break;
case NET_REG_EBX:
*p++ = 0xCB;
break;
case NET_REG_ESI:
*p++ = 0xCE;
break;
case NET_REG_EDI:
*p++ = 0xCF;
break;
}
}
}
break;
}
switch (op) {
case NETF_OP(NETF_NOP):
push_ecx = 1;
break;
case NETF_OP(NETF_AND):
if (loop < 2)
pend += 3;
else {
*p++ = 0x21;
*p++ = 0x0C;
*p++ = 0x24;
}
break;
case NETF_OP(NETF_OR):
if (loop < 2)
pend += 3;
else {
*p++ = 0x09;
*p++ = 0x0C;
*p++ = 0x24;
}
break;
case NETF_OP(NETF_XOR):
if (loop < 2)
pend += 3;
else {
*p++ = 0x31;
*p++ = 0x0C;
*p++ = 0x24;
}
break;
case NETF_OP(NETF_EQ):
if (loop < 2) {
pend += 14;
if (i = ((pend - (unsigned char *)0) &
(sizeof(int) - 1)))
pend += (sizeof(int) - i);
pend += 7;
break;
}
*p++ = 0x39;
*p++ = 0x0C;
*p++ = 0x24;
i = ((p - (unsigned char *)top) + 11) &
(sizeof(int) - 1);
*p++ = 0x74;
*p++ = 0x09 + (i ? sizeof(int) - i : 0);
*p++ = 0xC7;
*p++ = 0x04;
*p++ = 0x24;
*p++ = 0x00;
*p++ = 0x00;
*p++ = 0x00;
*p++ = 0x00;
i = ((p - (unsigned char *)top) + 2) &
(sizeof(int) - 1);
*p++ = 0xEB;
*p++ = 0x07 + (i ? sizeof(int) - i : 0);
if (i = (p - (unsigned char *)top) &
(sizeof(int) - 1))
while (i++ < sizeof(int))
*p++ = 0x90;
*p++ = 0xC7;
*p++ = 0x04;
*p++ = 0x24;
*p++ = 0x01;
*p++ = 0x00;
*p++ = 0x00;
*p++ = 0x00;
break;
case NETF_OP(NETF_NEQ):
if (loop < 2) {
pend += 14;
if (i = ((pend - (unsigned char *)0) &
(sizeof(int) - 1)))
pend += (sizeof(int) - i);
pend += 7;
break;
}
*p++ = 0x39;
*p++ = 0x0C;
*p++ = 0x24;
i = ((p - (unsigned char *)top) + 11) &
(sizeof(int) - 1);
*p++ = 0x75;
*p++ = 0x09 + (i ? sizeof(int) - i : 0);
*p++ = 0xC7;
*p++ = 0x04;
*p++ = 0x24;
*p++ = 0x00;
*p++ = 0x00;
*p++ = 0x00;
*p++ = 0x00;
i = ((p - (unsigned char *)top) + 2) &
(sizeof(int) - 1);
*p++ = 0xEB;
*p++ = 0x07 + (i ? sizeof(int) - i : 0);
if (i = (p - (unsigned char *)top) &
(sizeof(int) - 1))
while (i++ < sizeof(int))
*p++ = 0x90;
*p++ = 0xC7;
*p++ = 0x04;
*p++ = 0x24;
*p++ = 0x01;
*p++ = 0x00;
*p++ = 0x00;
*p++ = 0x00;
break;
case NETF_OP(NETF_LT):
if (loop < 2) {
pend += 14;
if (i = ((pend - (unsigned char *)0) &
(sizeof(int) - 1)))
pend += (sizeof(int) - i);
pend += 7;
break;
}
*p++ = 0x39;
*p++ = 0x0C;
*p++ = 0x24;
i = ((p - (unsigned char *)top) + 11) &
(sizeof(int) - 1);
*p++ = 0x7C;
*p++ = 0x09 + (i ? sizeof(int) - i : 0);
*p++ = 0xC7;
*p++ = 0x04;
*p++ = 0x24;
*p++ = 0x00;
*p++ = 0x00;
*p++ = 0x00;
*p++ = 0x00;
i = ((p - (unsigned char *)top) + 2) &
(sizeof(int) - 1);
*p++ = 0xEB;
*p++ = 0x07 + (i ? sizeof(int) - i : 0);
if (i = (p - (unsigned char *)top) &
(sizeof(int) - 1))
while (i++ < sizeof(int))
*p++ = 0x90;
*p++ = 0xC7;
*p++ = 0x04;
*p++ = 0x24;
*p++ = 0x01;
*p++ = 0x00;
*p++ = 0x00;
*p++ = 0x00;
break;
case NETF_OP(NETF_LE):
if (loop < 2) {
pend += 14;
if (i = ((pend - (unsigned char *)0) &
(sizeof(int) - 1)))
pend += (sizeof(int) - i);
pend += 7;
break;
}
*p++ = 0x39;
*p++ = 0x0C;
*p++ = 0x24;
i = ((p - (unsigned char *)top) + 11) &
(sizeof(int) - 1);
*p++ = 0x7E;
*p++ = 0x09 + (i ? sizeof(int) - i : 0);
*p++ = 0xC7;
*p++ = 0x04;
*p++ = 0x24;
*p++ = 0x00;
*p++ = 0x00;
*p++ = 0x00;
*p++ = 0x00;
i = ((p - (unsigned char *)top) + 2) &
(sizeof(int) - 1);
*p++ = 0xEB;
*p++ = 0x07 + (i ? sizeof(int) - i : 0);
if (i = (p - (unsigned char *)top) &
(sizeof(int) - 1))
while (i++ < sizeof(int))
*p++ = 0x90;
*p++ = 0xC7;
*p++ = 0x04;
*p++ = 0x24;
*p++ = 0x01;
*p++ = 0x00;
*p++ = 0x00;
*p++ = 0x00;
break;
case NETF_OP(NETF_GT):
if (loop < 2) {
pend += 14;
if (i = ((pend - (unsigned char *)0) &
(sizeof(int) - 1)))
pend += (sizeof(int) - i);
pend += 7;
break;
}
*p++ = 0x39;
*p++ = 0x0C;
*p++ = 0x24;
i = ((p - (unsigned char *)top) + 11) &
(sizeof(int) - 1);
*p++ = 0x7F;
*p++ = 0x09 + (i ? sizeof(int) - i : 0);
*p++ = 0xC7;
*p++ = 0x04;
*p++ = 0x24;
*p++ = 0x00;
*p++ = 0x00;
*p++ = 0x00;
*p++ = 0x00;
i = ((p - (unsigned char *)top) + 2) &
(sizeof(int) - 1);
*p++ = 0xEB;
*p++ = 0x07 + (i ? sizeof(int) - i : 0);
if (i = (p - (unsigned char *)top) &
(sizeof(int) - 1))
while (i++ < sizeof(int))
*p++ = 0x90;
*p++ = 0xC7;
*p++ = 0x04;
*p++ = 0x24;
*p++ = 0x01;
*p++ = 0x00;
*p++ = 0x00;
*p++ = 0x00;
break;
case NETF_OP(NETF_GE):
if (loop < 2) {
pend += 14;
if (i = ((pend - (unsigned char *)0) &
(sizeof(int) - 1)))
pend += (sizeof(int) - i);
pend += 7;
break;
}
*p++ = 0x39;
*p++ = 0x0C;
*p++ = 0x24;
i = ((p - (unsigned char *)top) + 11) &
(sizeof(int) - 1);
*p++ = 0x7D;
*p++ = 0x09 + (i ? sizeof(int) - i : 0);
*p++ = 0xC7;
*p++ = 0x04;
*p++ = 0x24;
*p++ = 0x00;
*p++ = 0x00;
*p++ = 0x00;
*p++ = 0x00;
i = ((p - (unsigned char *)top) + 2) &
(sizeof(int) - 1);
*p++ = 0xEB;
*p++ = 0x07 + (i ? sizeof(int) - i : 0);
if (i = (p - (unsigned char *)top) &
(sizeof(int) - 1))
while (i++ < sizeof(int))
*p++ = 0x90;
*p++ = 0xC7;
*p++ = 0x04;
*p++ = 0x24;
*p++ = 0x01;
*p++ = 0x00;
*p++ = 0x00;
*p++ = 0x00;
break;
case NETF_OP(NETF_COR):
if (loop < 2) {
if (loop == 0 ||
PEND_TRUE - (pend + 5) >= 128)
pend += 12;
else
pend += 8;
break;
}
*p++ = 0x39;
*p++ = 0x0C;
*p++ = 0x24;
if (PEND_TRUE - (p + 2) >= 128) {
*p++ = 0x0F;
*p++ = 0x84;
*(p+0) = PEND_TRUE - (p + 4);
*(p+1) = (PEND_TRUE - (p + 4)) >> 8;
*(p+2) = (PEND_TRUE - (p + 4)) >> 16;
*(p+3) = (PEND_TRUE - (p + 4)) >> 24;
p += 4;
} else {
*p++ = 0x74;
*p = PEND_TRUE - (p + 1);
p++;
}
*p++ = 0x83;
*p++ = 0xC4;
*p++ = 0x04;
break;
case NETF_OP(NETF_CAND):
if (loop < 2) {
if (loop == 0 ||
PEND_FALSE - (pend + 5) >= 128)
pend += 12;
else
pend += 8;
break;
}
*p++ = 0x39;
*p++ = 0x0C;
*p++ = 0x24;
if (PEND_FALSE - (p + 2) >= 128) {
*p++ = 0x0F;
*p++ = 0x85;
*(p+0) = PEND_FALSE - (p + 4);
*(p+1) = (PEND_FALSE - (p + 4)) >> 8;
*(p+2) = (PEND_FALSE - (p + 4)) >> 16;
*(p+3) = (PEND_FALSE - (p + 4)) >> 24;
p += 4;
} else {
*p++ = 0x75;
*p = PEND_FALSE - (p + 1);
p++;
}
*p++ = 0x83;
*p++ = 0xC4;
*p++ = 0x04;
break;
case NETF_OP(NETF_CNOR):
if (loop < 2) {
if (loop == 0 ||
PEND_FALSE - (pend + 5) >= 128)
pend += 12;
else
pend += 8;
break;
}
*p++ = 0x39;
*p++ = 0x0C;
*p++ = 0x24;
if (PEND_FALSE - (p + 2) >= 128) {
*p++ = 0x0F;
*p++ = 0x84;
*(p+0) = PEND_FALSE - (p + 4);
*(p+1) = (PEND_FALSE - (p + 4)) >> 8;
*(p+2) = (PEND_FALSE - (p + 4)) >> 16;
*(p+3) = (PEND_FALSE - (p + 4)) >> 24;
p += 4;
} else {
*p++ = 0x74;
*p = PEND_FALSE - (p + 1);
p++;
}
*p++ = 0x83;
*p++ = 0xC4;
*p++ = 0x04;
break;
case NETF_OP(NETF_CNAND):
if (loop < 2) {
if (loop == 0 ||
PEND_TRUE - (pend + 5) >= 128)
pend += 12;
else
pend += 8;
break;
}
*p++ = 0x39;
*p++ = 0x0C;
*p++ = 0x24;
if (PEND_TRUE - (p + 2) >= 128) {
*p++ = 0x0F;
*p++ = 0x85;
*(p+0) = PEND_TRUE - (p + 4);
*(p+1) = (PEND_TRUE - (p + 4)) >> 8;
*(p+2) = (PEND_TRUE - (p + 4)) >> 16;
*(p+3) = (PEND_TRUE - (p + 4)) >> 24;
p += 4;
} else {
*p++ = 0x75;
*p = PEND_TRUE - (p + 1);
p++;
}
*p++ = 0x83;
*p++ = 0xC4;
*p++ = 0x04;
break;
case NETF_OP(NETF_LSH):
if (loop < 2)
pend += 3;
else {
*p++ = 0xD3;
*p++ = 0x24;
*p++ = 0x24;
}
break;
case NETF_OP(NETF_RSH):
if (loop < 2)
pend += 3;
else {
*p++ = 0xD3;
*p++ = 0x3C;
*p++ = 0x24;
}
break;
case NETF_OP(NETF_ADD):
if (loop < 2)
pend += 3;
else {
*p++ = 0x01;
*p++ = 0x0C;
*p++ = 0x24;
}
break;
case NETF_OP(NETF_SUB):
if (loop < 2)
pend += 3;
else {
*p++ = 0x29;
*p++ = 0x0C;
*p++ = 0x24;
}
break;
}
}
if (loop < 2) {
if (push_ecx) {
pend += 12;
push_ecx = 0;
} else
pend += 13;
i = (pend - (unsigned char *)0) & (sizeof(int) - 1);
false_pad = i ? sizeof(int) - i : 0;
pend += 4 + push + false_pad;
} else {
if (push_ecx) {
*p++ = 0x83;
*p++ = 0xF9;
*p++ = 0x00;
push_ecx = 0;
} else {
*p++ = 0x83;
*p++ = 0x3C;
*p++ = 0x24;
*p++ = 0x00;
}
i = ((p - (unsigned char *)top) + 9) &
(sizeof(int) - 1);
false_pad = i ? sizeof(int) - i : 0;
*p++ = 0x74;
*p++ = 0x07 + false_pad;
*p++ = 0xB8;
*p++ = 0x01;
*p++ = 0x00;
*p++ = 0x00;
*p++ = 0x00;
*p++ = 0xEB;
*p++ = 0x02 + false_pad;
for (i = 0; i < false_pad; i++)
*p++ = 0x90;
*p++ = 0x31;
*p++ = 0xC0;
if (push) {
*p++ = 0x8D;
*p++ = 0x65;
*p++ = -((push - 3) * 4);
}
if (reg[NET_REG_EDI] >= 0)
*p++ = 0x5F;
if (reg[NET_REG_ESI] >= 0)
*p++ = 0x5E;
if (reg[NET_REG_EBX] >= 0)
*p++ = 0x5B;
*p++ = 0xC9;
*p++ = 0xC3;
}
if (loop == 2)
break;
if (loop == 1 && pend == pend_old) {
loop = 2;
*len = pend - (unsigned char *)0;
top = (filter_fct_t)kalloc(*len);
p = (unsigned char *)top;
pend_old = p + (pend - (unsigned char *)0);
} else {
if (loop == 0) {
loop = 1;
for (i = 0; i < NET_REG_MAX; i++)
reg[i] = -1;
if (use_data)
reg[NET_REG_EAX] = -2;
if (use_header)
reg[NET_REG_EDX] = -2;
net_filter_optimize(net_o, net_j,
reg, NET_REG_MAX);
}
pend_old = pend;
pend = 0;
}
for (i = 0; i < NET_REG_MAX; i++)
if (reg[i] != -2)
reg[i] = -1;
}
return (top);
}
void
net_filter_free(
filter_fct_t fp,
unsigned int len)
{
kfree((vm_offset_t)fp, len);
}
void
net_filter_optimize(
struct net_opt net_o[],
unsigned net_len,
int reg[],
unsigned nbreg)
{
unsigned i;
unsigned j;
unsigned nbnet;
unsigned avail;
unsigned used;
unsigned first;
unsigned max;
unsigned last;
struct net_opt *p;
struct net_opt *q;
avail = 0;
for (i = 0; i < nbreg; i++)
if (reg[i] != -2)
avail++;
if (avail == 0)
return;
p = &net_o[net_len];
while (p != net_o) {
for (q = p--; q < &net_o[net_len]; q++)
if (q->val == p->val) {
p->used = q->used + 1;
break;
}
if (q == &net_o[net_len])
p->used = 1;
}
if (net_len > 0) {
if (net_o[0].used == 1)
used = net_o[0].used = 0;
else {
net_o[0].reg = 0;
used = 1;
}
for (p = &net_o[1]; p < &net_o[net_len]; p++) {
max = 0;
first = avail;
for (i = 0; i < avail; i++) {
q = p;
j = 0;
while (q-- != net_o)
if (q->used > 0 && q->reg == i) {
if (q->used == 1)
first = i;
j = 1;
break;
}
if (j == 0)
continue;
if (q->val == p->val) {
p->reg = i;
break;
}
if (p->used == 1)
continue;
if (first == avail && used == avail) {
j = 1;
for (q = p+1; q->val != p->val; p++)
j++;
if (j > max) {
max = j;
last = i;
}
}
}
if (i < avail)
continue;
if (p->used > 1) {
if (first != avail)
p->reg = first;
else if (used < avail)
p->reg = used++;
else
p->reg = last;
} else
p->used = 0;
}
}
for (p = net_o; p < &net_o[net_len]; p++) {
if (p->used == 0)
continue;
i = first = 0;
for (;;) {
if (reg[i] != -2) {
if (first == p->reg) {
p->reg = i;
break;
}
first++;
}
i++;
}
}
if (net_len == 0) {
for (i = 0; i < nbreg; i++)
if (reg[i] != -2)
reg[i] = -2;
} else if (used < avail) {
first = 0;
for (i = 0; i < nbreg; i++)
if (reg[i] != -2)
if (first >= used)
reg[i] = -2;
else
first++;
}
}