diff options
99 files changed, 1565 insertions, 1277 deletions
diff --git a/Documentation/networking/proc_net_tcp.txt b/Documentation/networking/proc_net_tcp.txt new file mode 100644 index 000000000000..59cb915c3713 --- /dev/null +++ b/Documentation/networking/proc_net_tcp.txt @@ -0,0 +1,47 @@ +This document describes the interfaces /proc/net/tcp and /proc/net/tcp6. + +These /proc interfaces provide information about currently active TCP +connections, and are implemented by tcp_get_info() in net/ipv4/tcp_ipv4.c and +tcp6_get_info() in net/ipv6/tcp_ipv6.c, respectively. + +It will first list all listening TCP sockets, and next list all established +TCP connections. A typical entry of /proc/net/tcp would look like this (split +up into 3 parts because of the length of the line): + + 46: 010310AC:9C4C 030310AC:1770 01 + | | | | | |--> connection state + | | | | |------> remote TCP port number + | | | |-------------> remote IPv4 address + | | |--------------------> local TCP port number + | |---------------------------> local IPv4 address + |----------------------------------> number of entry + + 00000150:00000000 01:00000019 00000000 + | | | | |--> number of unrecovered RTO timeouts + | | | |----------> number of jiffies until timer expires + | | |----------------> timer_active (see below) + | |----------------------> receive-queue + |-------------------------------> transmit-queue + + 1000 0 54165785 4 cd1e6040 25 4 27 3 -1 + | | | | | | | | | |--> slow start size threshold, + | | | | | | | | | or -1 if the treshold + | | | | | | | | | is >= 0xFFFF + | | | | | | | | |----> sending congestion window + | | | | | | | |-------> (ack.quick<<1)|ack.pingpong + | | | | | | |---------> Predicted tick of soft clock + | | | | | | (delayed ACK control data) + | | | | | |------------> retransmit timeout + | | | | |------------------> location of socket in memory + | | | |-----------------------> socket reference count + | | |-----------------------------> inode + | |----------------------------------> unanswered 0-window probes + |---------------------------------------------> uid + +timer_active: + 0 no timer is pending + 1 retransmit-timer is pending + 2 another timer (e.g. delayed ack or keepalive) is pending + 3 this is a socket in TIME_WAIT state. Not all fields will contain + data (or even exist) + 4 zero window probe timer is pending diff --git a/arch/i386/crypto/aes-i586-asm.S b/arch/i386/crypto/aes-i586-asm.S index e8a04713df26..7b73c67cb4e8 100644 --- a/arch/i386/crypto/aes-i586-asm.S +++ b/arch/i386/crypto/aes-i586-asm.S @@ -61,7 +61,6 @@ #define r3 edx #define r4 esi #define r5 edi -#define r6 ebp #define eaxl al #define eaxh ah @@ -84,60 +83,63 @@ // output registers r0, r1, r4 or r5. // Parameters: +// table table base address // %1 out_state[0] // %2 out_state[1] // %3 out_state[2] // %4 out_state[3] -// %5 table base address -// %6 input register for the round (destroyed) -// %7 scratch register for the round - -#define do_col(a1, a2, a3, a4, a5, a6, a7) \ - movzx %l(a6),%a7; \ - xor a5(,%a7,4),%a1; \ - movzx %h(a6),%a7; \ - shr $16,%a6; \ - xor a5+tlen(,%a7,4),%a2; \ - movzx %l(a6),%a7; \ - movzx %h(a6),%a6; \ - xor a5+2*tlen(,%a7,4),%a3; \ - xor a5+3*tlen(,%a6,4),%a4; +// idx input register for the round (destroyed) +// tmp scratch register for the round +// sched key schedule + +#define do_col(table, a1,a2,a3,a4, idx, tmp) \ + movzx %l(idx),%tmp; \ + xor table(,%tmp,4),%a1; \ + movzx %h(idx),%tmp; \ + shr $16,%idx; \ + xor table+tlen(,%tmp,4),%a2; \ + movzx %l(idx),%tmp; \ + movzx %h(idx),%idx; \ + xor table+2*tlen(,%tmp,4),%a3; \ + xor table+3*tlen(,%idx,4),%a4; // initialise output registers from the key schedule - -#define do_fcol(a1, a2, a3, a4, a5, a6, a7, a8) \ - mov 0 a8,%a1; \ - movzx %l(a6),%a7; \ - mov 12 a8,%a2; \ - xor a5(,%a7,4),%a1; \ - mov 4 a8,%a4; \ - movzx %h(a6),%a7; \ - shr $16,%a6; \ - xor a5+tlen(,%a7,4),%a2; \ - movzx %l(a6),%a7; \ - movzx %h(a6),%a6; \ - xor a5+3*tlen(,%a6,4),%a4; \ - mov %a3,%a6; \ - mov 8 a8,%a3; \ - xor a5+2*tlen(,%a7,4),%a3; +// NB1: original value of a3 is in idx on exit +// NB2: original values of a1,a2,a4 aren't used +#define do_fcol(table, a1,a2,a3,a4, idx, tmp, sched) \ + mov 0 sched,%a1; \ + movzx %l(idx),%tmp; \ + mov 12 sched,%a2; \ + xor table(,%tmp,4),%a1; \ + mov 4 sched,%a4; \ + movzx %h(idx),%tmp; \ + shr $16,%idx; \ + xor table+tlen(,%tmp,4),%a2; \ + movzx %l(idx),%tmp; \ + movzx %h(idx),%idx; \ + xor table+3*tlen(,%idx,4),%a4; \ + mov %a3,%idx; \ + mov 8 sched,%a3; \ + xor table+2*tlen(,%tmp,4),%a3; // initialise output registers from the key schedule - -#define do_icol(a1, a2, a3, a4, a5, a6, a7, a8) \ - mov 0 a8,%a1; \ - movzx %l(a6),%a7; \ - mov 4 a8,%a2; \ - xor a5(,%a7,4),%a1; \ - mov 12 a8,%a4; \ - movzx %h(a6),%a7; \ - shr $16,%a6; \ - xor a5+tlen(,%a7,4),%a2; \ - movzx %l(a6),%a7; \ - movzx %h(a6),%a6; \ - xor a5+3*tlen(,%a6,4),%a4; \ - mov %a3,%a6; \ - mov 8 a8,%a3; \ - xor a5+2*tlen(,%a7,4),%a3; +// NB1: original value of a3 is in idx on exit +// NB2: original values of a1,a2,a4 aren't used +#define do_icol(table, a1,a2,a3,a4, idx, tmp, sched) \ + mov 0 sched,%a1; \ + movzx %l(idx),%tmp; \ + mov 4 sched,%a2; \ + xor table(,%tmp,4),%a1; \ + mov 12 sched,%a4; \ + movzx %h(idx),%tmp; \ + shr $16,%idx; \ + xor table+tlen(,%tmp,4),%a2; \ + movzx %l(idx),%tmp; \ + movzx %h(idx),%idx; \ + xor table+3*tlen(,%idx,4),%a4; \ + mov %a3,%idx; \ + mov 8 sched,%a3; \ + xor table+2*tlen(,%tmp,4),%a3; // original Gladman had conditional saves to MMX regs. @@ -147,44 +149,75 @@ #define restore(a1, a2) \ mov 4*a2(%esp),%a1 -// This macro performs a forward encryption cycle. It is entered with -// the first previous round column values in r0, r1, r4 and r5 and -// exits with the final values in the same registers, using the MMX -// registers mm0-mm1 or the stack for temporary storage - -// mov current column values into the MMX registers -#define fwd_rnd(arg, table) \ - /* mov current column values into the MMX registers */ \ - mov %r0,%r2; \ - save (0,r1); \ - save (1,r5); \ - \ - /* compute new column values */ \ - do_fcol(r0,r5,r4,r1,table, r2,r3, arg); \ - do_col (r4,r1,r0,r5,table, r2,r3); \ - restore(r2,0); \ - do_col (r1,r0,r5,r4,table, r2,r3); \ - restore(r2,1); \ - do_col (r5,r4,r1,r0,table, r2,r3); - -// This macro performs an inverse encryption cycle. It is entered with -// the first previous round column values in r0, r1, r4 and r5 and -// exits with the final values in the same registers, using the MMX -// registers mm0-mm1 or the stack for temporary storage - -#define inv_rnd(arg, table) \ - /* mov current column values into the MMX registers */ \ - mov %r0,%r2; \ - save (0,r1); \ - save (1,r5); \ - \ - /* compute new column values */ \ - do_icol(r0,r1,r4,r5, table, r2,r3, arg); \ - do_col (r4,r5,r0,r1, table, r2,r3); \ - restore(r2,0); \ - do_col (r1,r4,r5,r0, table, r2,r3); \ - restore(r2,1); \ - do_col (r5,r0,r1,r4, table, r2,r3); +// These macros perform a forward encryption cycle. They are entered with +// the first previous round column values in r0,r1,r4,r5 and +// exit with the final values in the same registers, using stack +// for temporary storage. + +// round column values +// on entry: r0,r1,r4,r5 +// on exit: r2,r1,r4,r5 +#define fwd_rnd1(arg, table) \ + save (0,r1); \ + save (1,r5); \ + \ + /* compute new column values */ \ + do_fcol(table, r2,r5,r4,r1, r0,r3, arg); /* idx=r0 */ \ + do_col (table, r4,r1,r2,r5, r0,r3); /* idx=r4 */ \ + restore(r0,0); \ + do_col (table, r1,r2,r5,r4, r0,r3); /* idx=r1 */ \ + restore(r0,1); \ + do_col (table, r5,r4,r1,r2, r0,r3); /* idx=r5 */ + +// round column values +// on entry: r2,r1,r4,r5 +// on exit: r0,r1,r4,r5 +#define fwd_rnd2(arg, table) \ + save (0,r1); \ + save (1,r5); \ + \ + /* compute new column values */ \ + do_fcol(table, r0,r5,r4,r1, r2,r3, arg); /* idx=r2 */ \ + do_col (table, r4,r1,r0,r5, r2,r3); /* idx=r4 */ \ + restore(r2,0); \ + do_col (table, r1,r0,r5,r4, r2,r3); /* idx=r1 */ \ + restore(r2,1); \ + do_col (table, r5,r4,r1,r0, r2,r3); /* idx=r5 */ + +// These macros performs an inverse encryption cycle. They are entered with +// the first previous round column values in r0,r1,r4,r5 and +// exit with the final values in the same registers, using stack +// for temporary storage + +// round column values +// on entry: r0,r1,r4,r5 +// on exit: r2,r1,r4,r5 +#define inv_rnd1(arg, table) \ + save (0,r1); \ + save (1,r5); \ + \ + /* compute new column values */ \ + do_icol(table, r2,r1,r4,r5, r0,r3, arg); /* idx=r0 */ \ + do_col (table, r4,r5,r2,r1, r0,r3); /* idx=r4 */ \ + restore(r0,0); \ + do_col (table, r1,r4,r5,r2, r0,r3); /* idx=r1 */ \ + restore(r0,1); \ + do_col (table, r5,r2,r1,r4, r0,r3); /* idx=r5 */ + +// round column values +// on entry: r2,r1,r4,r5 +// on exit: r0,r1,r4,r5 +#define inv_rnd2(arg, table) \ + save (0,r1); \ + save (1,r5); \ + \ + /* compute new column values */ \ + do_icol(table, r0,r1,r4,r5, r2,r3, arg); /* idx=r2 */ \ + do_col (table, r4,r5,r0,r1, r2,r3); /* idx=r4 */ \ + restore(r2,0); \ + do_col (table, r1,r4,r5,r0, r2,r3); /* idx=r1 */ \ + restore(r2,1); \ + do_col (table, r5,r0,r1,r4, r2,r3); /* idx=r5 */ // AES (Rijndael) Encryption Subroutine @@ -198,7 +231,6 @@ aes_enc_blk: push %ebp mov ctx(%esp),%ebp // pointer to context - xor %eax,%eax // CAUTION: the order and the values used in these assigns // rely on the register mappings @@ -208,7 +240,9 @@ aes_enc_blk: push %esi mov nrnd(%ebp),%r3 // number of rounds push %edi - lea ekey(%ebp),%r6 // key pointer +#if ekey != 0 + lea ekey(%ebp),%ebp // key pointer +#endif // input four columns and xor in first round key @@ -216,47 +250,47 @@ aes_enc_blk: mov 4(%r2),%r1 mov 8(%r2),%r4 mov 12(%r2),%r5 - xor (%r6),%r0 - xor 4(%r6),%r1 - xor 8(%r6),%r4 - xor 12(%r6),%r5 + xor (%ebp),%r0 + xor 4(%ebp),%r1 + xor 8(%ebp),%r4 + xor 12(%ebp),%r5 sub $8,%esp // space for register saves on stack - add $16,%r6 // increment to next round key + add $16,%ebp // increment to next round key sub $10,%r3 je 4f // 10 rounds for 128-bit key - add $32,%r6 + add $32,%ebp sub $2,%r3 je 3f // 12 rounds for 128-bit key - add $32,%r6 - -2: fwd_rnd( -64(%r6) ,ft_tab) // 14 rounds for 128-bit key - fwd_rnd( -48(%r6) ,ft_tab) -3: fwd_rnd( -32(%r6) ,ft_tab) // 12 rounds for 128-bit key - fwd_rnd( -16(%r6) ,ft_tab) -4: fwd_rnd( (%r6) ,ft_tab) // 10 rounds for 128-bit key - fwd_rnd( +16(%r6) ,ft_tab) - fwd_rnd( +32(%r6) ,ft_tab) - fwd_rnd( +48(%r6) ,ft_tab) - fwd_rnd( +64(%r6) ,ft_tab) - fwd_rnd( +80(%r6) ,ft_tab) - fwd_rnd( +96(%r6) ,ft_tab) - fwd_rnd(+112(%r6) ,ft_tab) - fwd_rnd(+128(%r6) ,ft_tab) - fwd_rnd(+144(%r6) ,fl_tab) // last round uses a different table + add $32,%ebp + +2: fwd_rnd1( -64(%ebp) ,ft_tab) // 14 rounds for 128-bit key + fwd_rnd2( -48(%ebp) ,ft_tab) +3: fwd_rnd1( -32(%ebp) ,ft_tab) // 12 rounds for 128-bit key + fwd_rnd2( -16(%ebp) ,ft_tab) +4: fwd_rnd1( (%ebp) ,ft_tab) // 10 rounds for 128-bit key + fwd_rnd2( +16(%ebp) ,ft_tab) + fwd_rnd1( +32(%ebp) ,ft_tab) + fwd_rnd2( +48(%ebp) ,ft_tab) + fwd_rnd1( +64(%ebp) ,ft_tab) + fwd_rnd2( +80(%ebp) ,ft_tab) + fwd_rnd1( +96(%ebp) ,ft_tab) + fwd_rnd2(+112(%ebp) ,ft_tab) + fwd_rnd1(+128(%ebp) ,ft_tab) + fwd_rnd2(+144(%ebp) ,fl_tab) // last round uses a different table // move final values to the output array. CAUTION: the // order of these assigns rely on the register mappings add $8,%esp - mov out_blk+12(%esp),%r6 - mov %r5,12(%r6) + mov out_blk+12(%esp),%ebp + mov %r5,12(%ebp) pop %edi - mov %r4,8(%r6) + mov %r4,8(%ebp) pop %esi - mov %r1,4(%r6) + mov %r1,4(%ebp) pop %ebx - mov %r0,(%r6) + mov %r0,(%ebp) pop %ebp mov $1,%eax ret @@ -273,7 +307,6 @@ aes_enc_blk: aes_dec_blk: push %ebp mov ctx(%esp),%ebp // pointer to context - xor %eax,%eax // CAUTION: the order and the values used in these assigns // rely on the register mappings @@ -283,10 +316,12 @@ aes_dec_blk: push %esi mov nrnd(%ebp),%r3 // number of rounds push %edi - lea dkey(%ebp),%r6 // key pointer +#if dkey != 0 + lea dkey(%ebp),%ebp // key pointer +#endif mov %r3,%r0 shl $4,%r0 - add %r0,%r6 + add %r0,%ebp // input four columns and xor in first round key @@ -294,47 +329,47 @@ aes_dec_blk: mov 4(%r2),%r1 mov 8(%r2),%r4 mov 12(%r2),%r5 - xor (%r6),%r0 - xor 4(%r6),%r1 - xor 8(%r6),%r4 - xor 12(%r6),%r5 + xor (%ebp),%r0 + xor 4(%ebp),%r1 + xor 8(%ebp),%r4 + xor 12(%ebp),%r5 - sub $8,%esp // space for register saves on stack - sub $16,%r6 // increment to next round key + sub $8,%esp // space for register saves on stack + sub $16,%ebp // increment to next round key sub $10,%r3 je 4f // 10 rounds for 128-bit key - sub $32,%r6 + sub $32,%ebp sub $2,%r3 je 3f // 12 rounds for 128-bit key - sub $32,%r6 - -2: inv_rnd( +64(%r6), it_tab) // 14 rounds for 128-bit key - inv_rnd( +48(%r6), it_tab) -3: inv_rnd( +32(%r6), it_tab) // 12 rounds for 128-bit key - inv_rnd( +16(%r6), it_tab) -4: inv_rnd( (%r6), it_tab) // 10 rounds for 128-bit key - inv_rnd( -16(%r6), it_tab) - inv_rnd( -32(%r6), it_tab) - inv_rnd( -48(%r6), it_tab) - inv_rnd( -64(%r6), it_tab) - inv_rnd( -80(%r6), it_tab) - inv_rnd( -96(%r6), it_tab) - inv_rnd(-112(%r6), it_tab) - inv_rnd(-128(%r6), it_tab) - inv_rnd(-144(%r6), il_tab) // last round uses a different table + sub $32,%ebp + +2: inv_rnd1( +64(%ebp), it_tab) // 14 rounds for 128-bit key + inv_rnd2( +48(%ebp), it_tab) +3: inv_rnd1( +32(%ebp), it_tab) // 12 rounds for 128-bit key + inv_rnd2( +16(%ebp), it_tab) +4: inv_rnd1( (%ebp), it_tab) // 10 rounds for 128-bit key + inv_rnd2( -16(%ebp), it_tab) + inv_rnd1( -32(%ebp), it_tab) + inv_rnd2( -48(%ebp), it_tab) + inv_rnd1( -64(%ebp), it_tab) + inv_rnd2( -80(%ebp), it_tab) + inv_rnd1( -96(%ebp), it_tab) + inv_rnd2(-112(%ebp), it_tab) + inv_rnd1(-128(%ebp), it_tab) + inv_rnd2(-144(%ebp), il_tab) // last round uses a different table // move final values to the output array. CAUTION: the // order of these assigns rely on the register mappings add $8,%esp - mov out_blk+12(%esp),%r6 - mov %r5,12(%r6) + mov out_blk+12(%esp),%ebp + mov %r5,12(%ebp) pop %edi - mov %r4,8(%r6) + mov %r4,8(%ebp) pop %esi - mov %r1,4(%r6) + mov %r1,4(%ebp) pop %ebx - mov %r0,(%r6) + mov %r0,(%ebp) pop %ebp mov $1,%eax ret diff --git a/crypto/sha256.c b/crypto/sha256.c index e8adf150d593..39f5a654709e 100644 --- a/crypto/sha256.c +++ b/crypto/sha256.c @@ -63,15 +63,7 @@ static inline u32 RORu32(u32 x, u32 y) static inline void LOAD_OP(int I, u32 *W, const u8 *input) { - u32 t1 = input[(4 * I)] & 0xff; - - t1 <<= 8; - t1 |= input[(4 * I) + 1] & 0xff; - t1 <<= 8; - t1 |= input[(4 * I) + 2] & 0xff; - t1 <<= 8; - t1 |= input[(4 * I) + 3] & 0xff; - W[I] = t1; + W[I] = __be32_to_cpu( ((u32*)(input))[I] ); } static inline void BLEND_OP(int I, u32 *W) diff --git a/crypto/sha512.c b/crypto/sha512.c index f1a8dc0aec47..6acaea9b7e2b 100644 --- a/crypto/sha512.c +++ b/crypto/sha512.c @@ -30,6 +30,7 @@ struct sha512_ctx { u64 state[8]; u32 count[4]; u8 buf[128]; + u64 W[80]; }; static inline u64 Ch(u64 x, u64 y, u64 z) @@ -104,34 +105,18 @@ const u64 sha512_K[80] = { static inline void LOAD_OP(int I, u64 *W, const u8 *input) { - u64 t1 = input[(8*I) ] & 0xff; - t1 <<= 8; - t1 |= input[(8*I)+1] & 0xff; - t1 <<= 8; - t1 |= input[(8*I)+2] & 0xff; - t1 <<= 8; - t1 |= input[(8*I)+3] & 0xff; - t1 <<= 8; - t1 |= input[(8*I)+4] & 0xff; - t1 <<= 8; - t1 |= input[(8*I)+5] & 0xff; - t1 <<= 8; - t1 |= input[(8*I)+6] & 0xff; - t1 <<= 8; - t1 |= input[(8*I)+7] & 0xff; - W[I] = t1; + W[I] = __be64_to_cpu( ((u64*)(input))[I] ); } static inline void BLEND_OP(int I, u64 *W) { - W[I] = s1(W[I-2]) + W[I-7] + s0(W[I-15]) + W[I-16]; + W[I] = s1(W[I-2]) + W[I-7] + s0(W[I-15]) + W[I-16]; } static void -sha512_transform(u64 *state, const u8 *input) +sha512_transform(u64 *state, u64 *W, const u8 *input) { u64 a, b, c, d, e, f, g, h, t1, t2; - u64 W[80]; int i; @@ -172,7 +157,6 @@ sha512_transform(u64 *state, const u8 *input) /* erase our data */ a = b = c = d = e = f = g = h = t1 = t2 = 0; - memset(W, 0, 80 * sizeof(u64)); } static void @@ -230,10 +214,10 @@ sha512_update(void *ctx, const u8 *data, unsigned int len) /* Transform as many times as possible. */ if (len >= part_len) { memcpy(&sctx->buf[index], data, part_len); - sha512_transform(sctx->state, sctx->buf); + sha512_transform(sctx->state, sctx->W, sctx->buf); for (i = part_len; i + 127 < len; i+=128) - sha512_transform(sctx->state, &data[i]); + sha512_transform(sctx->state, sctx->W, &data[i]); index = 0; } else { @@ -242,6 +226,9 @@ sha512_update(void *ctx, const u8 *data, unsigned int len) /* Buffer remaining input */ memcpy(&sctx->buf[index], &data[i], len - i); + + /* erase our data */ + memset(sctx->W, 0, sizeof(sctx->W)); } static void diff --git a/drivers/atm/horizon.c b/drivers/atm/horizon.c index 9ae4121aef47..a3f3c2413f2f 100644 --- a/drivers/atm/horizon.c +++ b/drivers/atm/horizon.c @@ -354,8 +354,7 @@ static inline void __init show_version (void) { /********** globals **********/ -static hrz_dev * hrz_devs = NULL; -static struct timer_list housekeeping; +static void do_housekeeping (unsigned long arg); static unsigned short debug = 0; static unsigned short vpi_bits = 0; @@ -1386,7 +1385,7 @@ static inline void rx_data_av_handler (hrz_dev * dev) { static irqreturn_t interrupt_handler(int irq, void *dev_id, struct pt_regs *pt_regs) { - hrz_dev * dev = hrz_devs; + hrz_dev * dev = (hrz_dev *) dev_id; u32 int_source; unsigned int irq_ok; (void) pt_regs; @@ -1397,16 +1396,6 @@ static irqreturn_t interrupt_handler(int irq, void *dev_id, PRINTD (DBG_IRQ|DBG_ERR, "irq with NULL dev_id: %d", irq); return IRQ_NONE; } - // Did one of our cards generate the interrupt? - while (dev) { - if (dev == dev_id) - break; - dev = dev->prev; - } - if (!dev) { - PRINTD (DBG_IRQ, "irq not for me: %d", irq); - return IRQ_NONE; - } if (irq != dev->irq) { PRINTD (DBG_IRQ|DBG_ERR, "irq mismatch: %d", irq); return IRQ_NONE; @@ -1462,28 +1451,18 @@ static irqreturn_t interrupt_handler(int irq, void *dev_id, /********** housekeeping **********/ -static void set_timer (struct timer_list * timer, unsigned int delay) { - timer->expires = jiffies + delay; - add_timer (timer); - return; -} - static void do_housekeeping (unsigned long arg) { // just stats at the moment - hrz_dev * dev = hrz_devs; - (void) arg; - // data is set to zero at module unload - if (housekeeping.data) { - while (dev) { - // collect device-specific (not driver/atm-linux) stats here - dev->tx_cell_count += rd_regw (dev, TX_CELL_COUNT_OFF); - dev->rx_cell_count += rd_regw (dev, RX_CELL_COUNT_OFF); - dev->hec_error_count += rd_regw (dev, HEC_ERROR_COUNT_OFF); - dev->unassigned_cell_count += rd_regw (dev, UNASSIGNED_CELL_COUNT_OFF); - dev = dev->prev; - } - set_timer (&housekeeping, HZ/10); - } + hrz_dev * dev = (hrz_dev *) arg; + + // collect device-specific (not driver/atm-linux) stats here + dev->tx_cell_count += rd_regw (dev, TX_CELL_COUNT_OFF); + dev->rx_cell_count += rd_regw (dev, RX_CELL_COUNT_OFF); + dev->hec_error_count += rd_regw (dev, HEC_ERROR_COUNT_OFF); + dev->unassigned_cell_count += rd_regw (dev, UNASSIGNED_CELL_COUNT_OFF); + + mod_timer (&dev->housekeeping, jiffies + HZ/10); + return; } @@ -2719,157 +2698,176 @@ static const struct atmdev_ops hrz_ops = { .owner = THIS_MODULE, }; -static int __init hrz_probe (void) { - struct pci_dev * pci_dev; - int devs; - - PRINTD (DBG_FLOW, "hrz_probe"); - - devs = 0; - pci_dev = NULL; - while ((pci_dev = pci_find_device - (PCI_VENDOR_ID_MADGE, PCI_DEVICE_ID_MADGE_HORIZON, pci_dev) - )) { - hrz_dev * dev; - - // adapter slot free, read resources from PCI configuration space - u32 iobase = pci_resource_start (pci_dev, 0); - u32 * membase = bus_to_virt (pci_resource_start (pci_dev, 1)); - u8 irq = pci_dev->irq; - - /* XXX DEV_LABEL is a guess */ - if (!request_region (iobase, HRZ_IO_EXTENT, DEV_LABEL)) - continue; +static int __devinit hrz_probe(struct pci_dev *pci_dev, const struct pci_device_id *pci_ent) +{ + hrz_dev * dev; + int err = 0; - if (pci_enable_device (pci_dev)) - continue; - - dev = kmalloc (sizeof(hrz_dev), GFP_KERNEL); - if (!dev) { - // perhaps we should be nice: deregister all adapters and abort? - PRINTD (DBG_ERR, "out of memory"); - continue; - } - - memset (dev, 0, sizeof(hrz_dev)); - - // grab IRQ and install handler - move this someplace more sensible - if (request_irq (irq, - interrupt_handler, - SA_SHIRQ, /* irqflags guess */ - DEV_LABEL, /* name guess */ - dev)) { - PRINTD (DBG_WARN, "request IRQ failed!"); - // free_irq is at "endif" - } else { - - PRINTD (DBG_INFO, "found Madge ATM adapter (hrz) at: IO %x, IRQ %u, MEM %p", - iobase, irq, membase); - - dev->atm_dev = atm_dev_register (DEV_LABEL, &hrz_ops, -1, NULL); - if (!(dev->atm_dev)) { - PRINTD (DBG_ERR, "failed to register Madge ATM adapter"); - } else { + // adapter slot free, read resources from PCI configuration space + u32 iobase = pci_resource_start (pci_dev, 0); + u32 * membase = bus_to_virt (pci_resource_start (pci_dev, 1)); + u8 irq = pci_dev->irq; unsigned char lat; - - PRINTD (DBG_INFO, "registered Madge ATM adapter (no. %d) (%p) at %p", - dev->atm_dev->number, dev, dev->atm_dev); + + PRINTD (DBG_FLOW, "hrz_probe"); + + /* XXX DEV_LABEL is a guess */ + if (!request_region(iobase, HRZ_IO_EXTENT, DEV_LABEL)) + return -EINVAL; + + if (pci_enable_device(pci_dev)) { + err = -EINVAL; + goto out_release; + } + + dev = kmalloc(sizeof(hrz_dev), GFP_KERNEL); + if (!dev) { + // perhaps we should be nice: deregister all adapters and abort? + PRINTD(DBG_ERR, "out of memory"); + err = -ENOMEM; + goto out_disable; + } + + memset(dev, 0, sizeof(hrz_dev)); + + pci_set_drvdata(pci_dev, dev); + + // grab IRQ and install handler - move this someplace more sensible + if (request_irq(irq, + interrupt_handler, + SA_SHIRQ, /* irqflags guess */ + DEV_LABEL, /* name guess */ + dev)) { + PRINTD(DBG_WARN, "request IRQ failed!"); + err = -EINVAL; + goto out_free; + } + + PRINTD(DBG_INFO, "found Madge ATM adapter (hrz) at: IO %x, IRQ %u, MEM %p", + iobase, irq, membase); + + dev->atm_dev = atm_dev_register(DEV_LABEL, &hrz_ops, -1, NULL); + if (!(dev->atm_dev)) { + PRINTD(DBG_ERR, "failed to register Madge ATM adapter"); + err = -EINVAL; + goto out_free_irq; + } + + PRINTD(DBG_INFO, "registered Madge ATM adapter (no. %d) (%p) at %p", + dev->atm_dev->number, dev, dev->atm_dev); dev->atm_dev->dev_data = (void *) dev; dev->pci_dev = pci_dev; - + // enable bus master accesses - pci_set_master (pci_dev); - + pci_set_master(pci_dev); + // frobnicate latency (upwards, usually) - pci_read_config_byte (pci_dev, PCI_LATENCY_TIMER, &lat); + pci_read_config_byte(pci_dev, PCI_LATENCY_TIMER, &lat); if (pci_lat) { - PRINTD (DBG_INFO, "%s PCI latency timer from %hu to %hu", - "changing", lat, pci_lat); - pci_write_config_byte (pci_dev, PCI_LATENCY_TIMER, pci_lat); + PRINTD(DBG_INFO, "%s PCI latency timer from %hu to %hu", + "changing", lat, pci_lat); + pci_write_config_byte(pci_dev, PCI_LATENCY_TIMER, pci_lat); } else if (lat < MIN_PCI_LATENCY) { - PRINTK (KERN_INFO, "%s PCI latency timer from %hu to %hu", - "increasing", lat, MIN_PCI_LATENCY); - pci_write_config_byte (pci_dev, PCI_LATENCY_TIMER, MIN_PCI_LATENCY); + PRINTK(KERN_INFO, "%s PCI latency timer from %hu to %hu", + "increasing", lat, MIN_PCI_LATENCY); + pci_write_config_byte(pci_dev, PCI_LATENCY_TIMER, MIN_PCI_LATENCY); } - + dev->iobase = iobase; dev->irq = irq; dev->membase = membase; - + dev->rx_q_entry = dev->rx_q_reset = &memmap->rx_q_entries[0]; dev->rx_q_wrap = &memmap->rx_q_entries[RX_CHANS-1]; - + // these next three are performance hacks dev->last_vc = -1; dev->tx_last = -1; dev->tx_idle = 0; - + dev->tx_regions = 0; dev->tx_bytes = 0; dev->tx_skb = NULL; dev->tx_iovec = NULL; - + dev->tx_cell_count = 0; dev->rx_cell_count = 0; dev->hec_error_count = 0; dev->unassigned_cell_count = 0; - + dev->noof_spare_buffers = 0; - + { - unsigned int i; - for (i = 0; i < TX_CHANS; ++i) - dev->tx_channel_record[i] = -1; + unsigned int i; + for (i = 0; i < TX_CHANS; ++i) + dev->tx_channel_record[i] = -1; } - + dev->flags = 0; - + // Allocate cell rates and remember ASIC version // Fibre: ATM_OC3_PCR = 1555200000/8/270*260/53 - 29/53 // Copper: (WRONG) we want 6 into the above, close to 25Mb/s // Copper: (plagarise!) 25600000/8/270*260/53 - n/53 - - if (hrz_init (dev)) { - // to be really pedantic, this should be ATM_OC3c_PCR - dev->tx_avail = ATM_OC3_PCR; - dev->rx_avail = ATM_OC3_PCR; - set_bit (ultra, &dev->flags); // NOT "|= ultra" ! + + if (hrz_init(dev)) { + // to be really pedantic, this should be ATM_OC3c_PCR + dev->tx_avail = ATM_OC3_PCR; + dev->rx_avail = ATM_OC3_PCR; + set_bit(ultra, &dev->flags); // NOT "|= ultra" ! } else { - dev->tx_avail = ((25600000/8)*26)/(27*53); - dev->rx_avail = ((25600000/8)*26)/(27*53); - PRINTD (DBG_WARN, "Buggy ASIC: no TX bus-mastering."); + dev->tx_avail = ((25600000/8)*26)/(27*53); + dev->rx_avail = ((25600000/8)*26)/(27*53); + PRINTD(DBG_WARN, "Buggy ASIC: no TX bus-mastering."); } - + // rate changes spinlock - spin_lock_init (&dev->rate_lock); - + spin_lock_init(&dev->rate_lock); + // on-board memory access spinlock; we want atomic reads and // writes to adapter memory (handles IRQ and SMP) - spin_lock_init (&dev->mem_lock); - - init_waitqueue_head (&dev->tx_queue); - + spin_lock_init(&dev->mem_lock); + + init_waitqueue_head(&dev->tx_queue); + // vpi in 0..4, vci in 6..10 dev->atm_dev->ci_range.vpi_bits = vpi_bits; dev->atm_dev->ci_range.vci_bits = 10-vpi_bits; - - // update count and linked list - ++devs; - dev->prev = hrz_devs; - hrz_devs = dev; - // success - continue; - - /* not currently reached */ - atm_dev_deregister (dev->atm_dev); - } /* atm_dev_register */ - free_irq (irq, dev); - - } /* request_irq */ - kfree (dev); - release_region(iobase, HRZ_IO_EXTENT); - } /* kmalloc and while */ - return devs; + + init_timer(&dev->housekeeping); + dev->housekeeping.function = do_housekeeping; + dev->housekeeping.data = (unsigned long) dev; + mod_timer(&dev->housekeeping, jiffies); + +out: + return err; + +out_free_irq: + free_irq(dev->irq, dev); +out_free: + kfree(dev); +out_disable: + pci_disable_device(pci_dev); +out_release: + release_region(iobase, HRZ_IO_EXTENT); + goto out; +} + +static void __devexit hrz_remove_one(struct pci_dev *pci_dev) +{ + hrz_dev *dev; + + dev = pci_get_drvdata(pci_dev); + + PRINTD(DBG_INFO, "closing %p (atm_dev = %p)", dev, dev->atm_dev); + del_timer_sync(&dev->housekeeping); + hrz_reset(dev); + atm_dev_deregister(dev->atm_dev); + free_irq(dev->irq, dev); + release_region(dev->iobase, HRZ_IO_EXTENT); + kfree(dev); + + pci_disable_device(pci_dev); } static void __init hrz_check_args (void) { @@ -2909,11 +2907,22 @@ MODULE_PARM_DESC(max_tx_size, "maximum size of TX AAL5 frames"); MODULE_PARM_DESC(max_rx_size, "maximum size of RX AAL5 frames"); MODULE_PARM_DESC(pci_lat, "PCI latency in bus cycles"); +static struct pci_device_id hrz_pci_tbl[] = { + { PCI_VENDOR_ID_MADGE, PCI_DEVICE_ID_MADGE_HORIZON, PCI_ANY_ID, PCI_ANY_ID, + 0, 0, 0 }, + { 0, } +}; + +static struct pci_driver hrz_driver = { + .name = "horizon", + .probe = hrz_probe, + .remove = __devexit_p(hrz_remove_one), + .id_table = hrz_pci_tbl, +}; + /********** module entry **********/ static int __init hrz_module_init (void) { - int devs; - // sanity check - cast is needed since printk does not support %Zu if (sizeof(struct MEMMAP) != 128*1024/4) { PRINTK (KERN_ERR, "Fix struct MEMMAP (is %lu fakewords).", @@ -2927,44 +2936,15 @@ static int __init hrz_module_init (void) { hrz_check_args(); // get the juice - devs = hrz_probe(); - - if (devs) { - init_timer (&housekeeping); - housekeeping.function = do_housekeeping; - // paranoia - housekeeping.data = 1; - set_timer (&housekeeping, 0); - } else { - PRINTK (KERN_ERR, "no (usable) adapters found"); - } - - return devs ? 0 : -ENODEV; + return pci_module_init(&hrz_driver); } /********** module exit **********/ static void __exit hrz_module_exit (void) { - hrz_dev * dev; PRINTD (DBG_FLOW, "cleanup_module"); - // paranoia - housekeeping.data = 0; - del_timer (&housekeeping); - - while (hrz_devs) { - dev = hrz_devs; - hrz_devs = dev->prev; - - PRINTD (DBG_INFO, "closing %p (atm_dev = %p)", dev, dev->atm_dev); - hrz_reset (dev); - atm_dev_deregister (dev->atm_dev); - free_irq (dev->irq, dev); - release_region (dev->iobase, HRZ_IO_EXTENT); - kfree (dev); - } - - return; + return pci_unregister_driver(&hrz_driver); } module_init(hrz_module_init); diff --git a/drivers/atm/horizon.h b/drivers/atm/horizon.h index ec5ba498df49..e2cc7020fa3b 100644 --- a/drivers/atm/horizon.h +++ b/drivers/atm/horizon.h @@ -457,7 +457,7 @@ struct hrz_dev { unsigned long unassigned_cell_count; struct pci_dev * pci_dev; - struct hrz_dev * prev; + struct timer_list housekeeping; }; typedef struct hrz_dev hrz_dev; diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index e1097f90c883..5769fdc4fdb0 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -4700,6 +4700,7 @@ static void __exit bonding_exit(void) module_init(bonding_init); module_exit(bonding_exit); MODULE_LICENSE("GPL"); +MODULE_VERSION(DRV_VERSION); MODULE_DESCRIPTION(DRV_DESCRIPTION ", v" DRV_VERSION); MODULE_AUTHOR("Thomas Davis, tadavis@lbl.gov and many others"); MODULE_SUPPORTED_DEVICE("most ethernet devices"); diff --git a/include/linux/atmdev.h b/include/linux/atmdev.h index 268da2732958..87a901c75370 100644 --- a/include/linux/atmdev.h +++ b/include/linux/atmdev.h @@ -395,7 +395,6 @@ struct atm_dev *atm_dev_lookup(int number); void atm_dev_deregister(struct atm_dev *dev); void shutdown_atm_dev(struct atm_dev *dev); void vcc_insert_socket(struct sock *sk); -void vcc_remove_socket(struct sock *sk); /* diff --git a/include/linux/ipv6_route.h b/include/linux/ipv6_route.h index 46d8b7e8b1aa..e2f935038013 100644 --- a/include/linux/ipv6_route.h +++ b/include/linux/ipv6_route.h @@ -14,7 +14,8 @@ #define _LINUX_IPV6_ROUTE_H #define RTF_DEFAULT 0x00010000 /* default - learned via ND */ -#define RTF_ALLONLINK 0x00020000 /* fallback, no routers on link */ +#define RTF_ALLONLINK 0x00020000 /* (deprecated and will be removed) + fallback, no routers on link */ #define RTF_ADDRCONF 0x00040000 /* addrconf route - RA */ #define RTF_PREFIX_RT 0x00080000 /* A prefix only route - RA */ diff --git a/include/linux/net.h b/include/linux/net.h index 2c4572f630a1..368b0f9d3006 100644 --- a/include/linux/net.h +++ b/include/linux/net.h @@ -176,7 +176,6 @@ struct kvec; extern int sock_wake_async(struct socket *sk, int how, int band); extern int sock_register(struct net_proto_family *fam); extern int sock_unregister(int family); -extern struct socket *sock_alloc(void); extern int sock_create(int family, int type, int proto, struct socket **res); extern int sock_create_kern(int family, int type, int proto, diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index c102cdce2ebe..79c65e9ac5a1 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -937,7 +937,7 @@ extern int weight_p; extern unsigned long netdev_fc_xoff; extern atomic_t netdev_dropping; extern int netdev_set_master(struct net_device *dev, struct net_device *master); -extern int skb_checksum_help(struct sk_buff **pskb, int inward); +extern int skb_checksum_help(struct sk_buff *skb, int inward); #ifdef CONFIG_SYSCTL extern char *net_sysctl_strdup(const char *s); diff --git a/include/linux/netfilter.h b/include/linux/netfilter.h index a9357be1ae41..ced66929126c 100644 --- a/include/linux/netfilter.h +++ b/include/linux/netfilter.h @@ -172,12 +172,6 @@ extern void nf_reinject(struct sk_buff *skb, struct nf_info *info, unsigned int verdict); -extern inline struct ipt_target * -ipt_find_target_lock(const char *name, int *error, struct semaphore *mutex); -extern inline struct ip6t_target * -ip6t_find_target_lock(const char *name, int *error, struct semaphore *mutex); -extern inline struct arpt_target * -arpt_find_target_lock(const char *name, int *error, struct semaphore *mutex); extern void (*ip_ct_attach)(struct sk_buff *, struct sk_buff *); #ifdef CONFIG_NETFILTER_DEBUG diff --git a/include/linux/netfilter_ipv4/ip_tables.h b/include/linux/netfilter_ipv4/ip_tables.h index 02a006f17ac4..defc7bc472d9 100644 --- a/include/linux/netfilter_ipv4/ip_tables.h +++ b/include/linux/netfilter_ipv4/ip_tables.h @@ -407,11 +407,6 @@ struct ipt_target struct module *me; }; -extern struct ipt_target * -ipt_find_target_lock(const char *name, int *error, struct semaphore *mutex); -extern struct arpt_target * -arpt_find_target_lock(const char *name, int *error, struct semaphore *mutex); - extern int ipt_register_target(struct ipt_target *target); extern void ipt_unregister_target(struct ipt_target *target); diff --git a/include/linux/netfilter_ipv6/ip6_tables.h b/include/linux/netfilter_ipv6/ip6_tables.h index 6f70cf3df39a..d6ac08c14dc1 100644 --- a/include/linux/netfilter_ipv6/ip6_tables.h +++ b/include/linux/netfilter_ipv6/ip6_tables.h @@ -355,13 +355,15 @@ struct ip6t_match /* Return true or false: return FALSE and set *hotdrop = 1 to force immediate packet drop. */ + /* Arguments changed since 2.6.9, as this must now handle + non-linear skb, using skb_header_pointer and + skb_ip_make_writable. */ int (*match)(const struct sk_buff *skb, const struct net_device *in, const struct net_device *out, const void *matchinfo, int offset, - const void *hdr, - u_int16_t datalen, + unsigned int protoff, int *hotdrop); /* Called when user tries to insert an entry of this type. */ @@ -386,11 +388,13 @@ struct ip6t_target const char name[IP6T_FUNCTION_MAXNAMELEN]; - /* Returns verdict. */ + /* Returns verdict. Argument order changed since 2.6.9, as this + must now handle non-linear skbs, using skb_copy_bits and + skb_ip_make_writable. */ unsigned int (*target)(struct sk_buff **pskb, - unsigned int hooknum, const struct net_device *in, const struct net_device *out, + unsigned int hooknum, const void *targinfo, void *userdata); diff --git a/include/linux/sctp.h b/include/linux/sctp.h index cff28345eacf..1ed3da0cb9d0 100644 --- a/include/linux/sctp.h +++ b/include/linux/sctp.h @@ -281,7 +281,11 @@ typedef struct sctp_ecn_capable_param { sctp_paramhdr_t param_hdr; } __attribute__((packed)) sctp_ecn_capable_param_t; - +/* ADDIP Section 3.2.6 Adaption Layer Indication */ +typedef struct sctp_adaption_ind_param { + struct sctp_paramhdr param_hdr; + __u32 adaption_ind; +} __attribute__((packed)) sctp_adaption_ind_param_t; /* RFC 2960. Section 3.3.3 Initiation Acknowledgement (INIT ACK) (2): * The INIT ACK chunk is used to acknowledge the initiation of an SCTP diff --git a/include/net/addrconf.h b/include/net/addrconf.h index 50f4c2c4df86..97c2a6121275 100644 --- a/include/net/addrconf.h +++ b/include/net/addrconf.h @@ -67,8 +67,7 @@ extern int ipv6_get_saddr(struct dst_entry *dst, struct in6_addr *saddr); extern int ipv6_dev_get_saddr(struct net_device *dev, struct in6_addr *daddr, - struct in6_addr *saddr, - int onlink); + struct in6_addr *saddr); extern int ipv6_get_lladdr(struct net_device *dev, struct in6_addr *); extern int ipv6_rcv_saddr_equal(const struct sock *sk, const struct sock *sk2); diff --git a/include/net/dst.h b/include/net/dst.h index 16da04466554..7ffb470d0e9a 100644 --- a/include/net/dst.h +++ b/include/net/dst.h @@ -67,7 +67,7 @@ struct dst_entry struct xfrm_state *xfrm; int (*input)(struct sk_buff*); - int (*output)(struct sk_buff**); + int (*output)(struct sk_buff*); #ifdef CONFIG_NET_CLS_ROUTE __u32 tclassid; @@ -222,7 +222,7 @@ static inline int dst_output(struct sk_buff *skb) int err; for (;;) { - err = skb->dst->output(&skb); + err = skb->dst->output(skb); if (likely(err == 0)) return err; diff --git a/include/net/ip.h b/include/net/ip.h index 0f633ff0b9b4..15a1c6a2e534 100644 --- a/include/net/ip.h +++ b/include/net/ip.h @@ -89,8 +89,8 @@ extern int ip_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt); extern int ip_local_deliver(struct sk_buff *skb); extern int ip_mr_input(struct sk_buff *skb); -extern int ip_output(struct sk_buff **pskb); -extern int ip_mc_output(struct sk_buff **pskb); +extern int ip_output(struct sk_buff *skb); +extern int ip_mc_output(struct sk_buff *skb); extern int ip_fragment(struct sk_buff *skb, int (*out)(struct sk_buff*)); extern int ip_do_nat(struct sk_buff *skb); extern void ip_send_check(struct iphdr *ip); diff --git a/include/net/ip6_route.h b/include/net/ip6_route.h index d859c4160eaa..d5d1dd10cdb8 100644 --- a/include/net/ip6_route.h +++ b/include/net/ip6_route.h @@ -70,7 +70,7 @@ extern struct rt6_info *rt6_lookup(struct in6_addr *daddr, extern struct dst_entry *ndisc_dst_alloc(struct net_device *dev, struct neighbour *neigh, struct in6_addr *addr, - int (*output)(struct sk_buff **)); + int (*output)(struct sk_buff *)); extern int ndisc_dst_gc(int *more); extern void fib6_force_start_gc(void); @@ -87,7 +87,7 @@ extern struct rt6_info * rt6_get_dflt_router(struct in6_addr *addr, extern struct rt6_info * rt6_add_dflt_router(struct in6_addr *gwaddr, struct net_device *dev); -extern void rt6_purge_dflt_routers(int lst_resort); +extern void rt6_purge_dflt_routers(void); extern void rt6_reset_dflt_pointer(struct rt6_info *rt); diff --git a/include/net/ipv6.h b/include/net/ipv6.h index a3f44754ac08..e0e3800a9560 100644 --- a/include/net/ipv6.h +++ b/include/net/ipv6.h @@ -355,7 +355,7 @@ extern int ip6_dst_lookup(struct sock *sk, * skb processing functions */ -extern int ip6_output(struct sk_buff **pskb); +extern int ip6_output(struct sk_buff *skb); extern int ip6_forward(struct sk_buff *skb); extern int ip6_input(struct sk_buff *skb); extern int ip6_mc_input(struct sk_buff *skb); diff --git a/include/net/ndisc.h b/include/net/ndisc.h index 61d7033bca7f..8f121905ea6d 100644 --- a/include/net/ndisc.h +++ b/include/net/ndisc.h @@ -45,6 +45,11 @@ struct nd_msg { __u8 opt[0]; }; +struct rs_msg { + struct icmp6hdr icmph; + __u8 opt[0]; +}; + struct ra_msg { struct icmp6hdr icmph; __u32 reachable_time; diff --git a/include/net/pkt_sched.h b/include/net/pkt_sched.h index 357be232a46c..d0ab0a3d10c5 100644 --- a/include/net/pkt_sched.h +++ b/include/net/pkt_sched.h @@ -79,7 +79,7 @@ struct Qdisc unsigned flags; #define TCQ_F_BUILTIN 1 #define TCQ_F_THROTTLED 2 -#define TCQ_F_INGRES 4 +#define TCQ_F_INGRESS 4 int padded; struct Qdisc_ops *ops; u32 handle; diff --git a/include/net/sctp/sctp.h b/include/net/sctp/sctp.h index 053a0ac270f9..ac856c13d354 100644 --- a/include/net/sctp/sctp.h +++ b/include/net/sctp/sctp.h @@ -335,7 +335,7 @@ static inline void sctp_v6_exit(void) { return; } /* Map an association to an assoc_id. */ static inline sctp_assoc_t sctp_assoc2id(const struct sctp_association *asoc) { - return (asoc?asoc->assoc_id:NULL); + return (asoc?asoc->assoc_id:0); } /* Look up the association by its id. */ diff --git a/include/net/sctp/structs.h b/include/net/sctp/structs.h index 26c97aa3a3c7..3bd04bc5b002 100644 --- a/include/net/sctp/structs.h +++ b/include/net/sctp/structs.h @@ -266,6 +266,7 @@ struct sctp_opt { __u8 disable_fragments; __u8 pd_mode; __u8 v4mapped; + __u32 adaption_ind; /* Receive to here while partial delivery is in effect. */ struct sk_buff_head pd_lobby; @@ -323,6 +324,8 @@ struct sctp_cookie { __u8 prsctp_capable; + __u32 adaption_ind; + /* This is a shim for my peer's INIT packet, followed by * a copy of the raw address list of the association. * The length of the raw address list is saved in the @@ -362,6 +365,7 @@ union sctp_params { struct sctp_ipv4addr_param *v4; struct sctp_ipv6addr_param *v6; union sctp_addr_param *addr; + struct sctp_adaption_ind_param *aind; }; /* RFC 2960. Section 3.3.5 Heartbeat. @@ -1395,6 +1399,8 @@ struct sctp_association { __u8 asconf_capable; /* Does peer support ADDIP? */ __u8 prsctp_capable; /* Can peer do PR-SCTP? */ + __u32 adaption_ind; /* Adaption Code point. */ + /* This mask is used to disable sending the ASCONF chunk * with specified parameter to peer. */ diff --git a/include/net/sctp/ulpevent.h b/include/net/sctp/ulpevent.h index ff9c7573063c..46a974464a84 100644 --- a/include/net/sctp/ulpevent.h +++ b/include/net/sctp/ulpevent.h @@ -121,6 +121,9 @@ struct sctp_ulpevent *sctp_ulpevent_make_pdapi( const struct sctp_association *asoc, __u32 indication, int gfp); +struct sctp_ulpevent *sctp_ulpevent_make_adaption_indication( + const struct sctp_association *asoc, int gfp); + struct sctp_ulpevent *sctp_ulpevent_make_rcvmsg(struct sctp_association *asoc, struct sctp_chunk *chunk, int gfp); diff --git a/include/net/sctp/user.h b/include/net/sctp/user.h index 04e99178015f..aa95f0099e64 100644 --- a/include/net/sctp/user.h +++ b/include/net/sctp/user.h @@ -55,7 +55,7 @@ #include <linux/types.h> #include <linux/socket.h> -typedef void * sctp_assoc_t; +typedef __s32 sctp_assoc_t; /* The following symbols come from the Sockets API Extensions for * SCTP <draft-ietf-tsvwg-sctpsocket-07.txt>. diff --git a/include/net/sock.h b/include/net/sock.h index 563096ab673a..bfad716ce409 100644 --- a/include/net/sock.h +++ b/include/net/sock.h @@ -746,7 +746,6 @@ extern void sk_send_sigurg(struct sock *sk); * Functions to fill in entries in struct proto_ops when a protocol * does not implement a particular function. */ -extern int sock_no_release(struct socket *); extern int sock_no_bind(struct socket *, struct sockaddr *, int); extern int sock_no_connect(struct socket *, @@ -1275,7 +1274,6 @@ static inline void sk_eat_skb(struct sock *sk, struct sk_buff *skb) extern atomic_t netstamp_needed; extern void sock_enable_timestamp(struct sock *sk); -extern void sock_disable_timestamp(struct sock *sk); static inline void net_timestamp(struct timeval *stamp) { diff --git a/include/net/tcp.h b/include/net/tcp.h index 28dca9b66467..4a7dc4157df4 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -159,7 +159,6 @@ extern struct tcp_bind_bucket *tcp_bucket_create(struct tcp_bind_hashbucket *hea extern void tcp_bucket_destroy(struct tcp_bind_bucket *tb); extern void tcp_bucket_unlock(struct sock *sk); extern int tcp_port_rover; -extern struct sock *tcp_v4_lookup_listener(u32 addr, unsigned short hnum, int dif); /* These are AF independent. */ static __inline__ int tcp_bhashfn(__u16 lport) diff --git a/include/net/xfrm.h b/include/net/xfrm.h index 2c89b019388a..7078e743b732 100644 --- a/include/net/xfrm.h +++ b/include/net/xfrm.h @@ -178,8 +178,6 @@ struct xfrm_policy_afinfo { extern int xfrm_policy_register_afinfo(struct xfrm_policy_afinfo *afinfo); extern int xfrm_policy_unregister_afinfo(struct xfrm_policy_afinfo *afinfo); -extern struct xfrm_policy_afinfo *xfrm_policy_get_afinfo(unsigned short family); -extern void xfrm_policy_put_afinfo(struct xfrm_policy_afinfo *afinfo); #define XFRM_ACQ_EXPIRES 30 @@ -200,8 +198,6 @@ struct xfrm_state_afinfo { extern int xfrm_state_register_afinfo(struct xfrm_state_afinfo *afinfo); extern int xfrm_state_unregister_afinfo(struct xfrm_state_afinfo *afinfo); -extern struct xfrm_state_afinfo *xfrm_state_get_afinfo(unsigned short family); -extern void xfrm_state_put_afinfo(struct xfrm_state_afinfo *afinfo); extern void xfrm_state_delete_tunnel(struct xfrm_state *x); @@ -805,17 +801,15 @@ extern int xfrm_state_check_expire(struct xfrm_state *x); extern void xfrm_state_insert(struct xfrm_state *x); extern int xfrm_state_add(struct xfrm_state *x); extern int xfrm_state_update(struct xfrm_state *x); -extern int xfrm_state_check_space(struct xfrm_state *x, struct sk_buff *skb); extern struct xfrm_state *xfrm_state_lookup(xfrm_address_t *daddr, u32 spi, u8 proto, unsigned short family); extern struct xfrm_state *xfrm_find_acq_byseq(u32 seq); extern void xfrm_state_delete(struct xfrm_state *x); extern void xfrm_state_flush(u8 proto); extern int xfrm_replay_check(struct xfrm_state *x, u32 seq); extern void xfrm_replay_advance(struct xfrm_state *x, u32 seq); -extern int xfrm_check_selectors(struct xfrm_state **x, int n, struct flowi *fl); extern int xfrm_state_check(struct xfrm_state *x, struct sk_buff *skb); extern int xfrm4_rcv(struct sk_buff *skb); -extern int xfrm4_output(struct sk_buff **pskb); +extern int xfrm4_output(struct sk_buff *skb); extern int xfrm4_tunnel_register(struct xfrm_tunnel *handler); extern int xfrm4_tunnel_deregister(struct xfrm_tunnel *handler); extern int xfrm6_rcv_spi(struct sk_buff **pskb, unsigned int *nhoffp, u32 spi); @@ -825,7 +819,7 @@ extern int xfrm6_tunnel_deregister(struct xfrm6_tunnel *handler); extern u32 xfrm6_tunnel_alloc_spi(xfrm_address_t *saddr); extern void xfrm6_tunnel_free_spi(xfrm_address_t *saddr); extern u32 xfrm6_tunnel_spi_lookup(xfrm_address_t *saddr); -extern int xfrm6_output(struct sk_buff **pskb); +extern int xfrm6_output(struct sk_buff *skb); #ifdef CONFIG_XFRM extern int xfrm4_rcv_encap(struct sk_buff *skb, __u16 encap_type); @@ -863,7 +857,6 @@ struct xfrm_state * xfrm_find_acq(u8 mode, u32 reqid, u8 proto, xfrm_address_t *daddr, xfrm_address_t *saddr, int create, unsigned short family); extern void xfrm_policy_flush(void); -extern void xfrm_policy_kill(struct xfrm_policy *); extern int xfrm_sk_policy_insert(struct sock *sk, int dir, struct xfrm_policy *pol); extern struct xfrm_policy *xfrm_sk_policy_lookup(struct sock *sk, int dir, struct flowi *fl); extern int xfrm_flush_bundles(void); diff --git a/net/8021q/vlan.c b/net/8021q/vlan.c index 3ee1dcd35e52..0d9ca98aee8f 100644 --- a/net/8021q/vlan.c +++ b/net/8021q/vlan.c @@ -35,6 +35,8 @@ #include "vlan.h" #include "vlanproc.h" +#define DRV_VERSION "1.8" + /* Global VLAN variables */ /* Our listing of VLAN group(s) */ @@ -42,8 +44,7 @@ struct hlist_head vlan_group_hash[VLAN_GRP_HASH_SIZE]; #define vlan_grp_hashfn(IDX) ((((IDX) >> VLAN_GRP_HASH_SHIFT) ^ (IDX)) & VLAN_GRP_HASH_MASK) static char vlan_fullname[] = "802.1Q VLAN Support"; -static unsigned int vlan_version = 1; -static unsigned int vlan_release = 8; +static char vlan_version[] = DRV_VERSION; static char vlan_copyright[] = "Ben Greear <greearb@candelatech.com>"; static char vlan_buggyright[] = "David S. Miller <davem@redhat.com>"; @@ -84,8 +85,8 @@ static int __init vlan_proto_init(void) { int err; - printk(VLAN_INF "%s v%u.%u %s\n", - vlan_fullname, vlan_version, vlan_release, vlan_copyright); + printk(VLAN_INF "%s v%s %s\n", + vlan_fullname, vlan_version, vlan_copyright); printk(VLAN_INF "All bugs added by %s\n", vlan_buggyright); @@ -735,3 +736,4 @@ static int vlan_ioctl_handler(void __user *arg) } MODULE_LICENSE("GPL"); +MODULE_VERSION(DRV_VERSION); diff --git a/net/atm/common.c b/net/atm/common.c index 56e34deef6c2..47f5413683c8 100644 --- a/net/atm/common.c +++ b/net/atm/common.c @@ -57,7 +57,7 @@ void vcc_insert_socket(struct sock *sk) write_unlock_irq(&vcc_sklist_lock); } -void vcc_remove_socket(struct sock *sk) +static void vcc_remove_socket(struct sock *sk) { write_lock_irq(&vcc_sklist_lock); sk_del_node_init(sk); @@ -86,7 +86,6 @@ static struct sk_buff *alloc_tx(struct atm_vcc *vcc,unsigned int size) EXPORT_SYMBOL(vcc_hash); EXPORT_SYMBOL(vcc_sklist_lock); EXPORT_SYMBOL(vcc_insert_socket); -EXPORT_SYMBOL(vcc_remove_socket); static void vcc_sock_destruct(struct sock *sk) { diff --git a/net/bridge/br_netfilter.c b/net/bridge/br_netfilter.c index 50e4df3559aa..b240ad4a6308 100644 --- a/net/bridge/br_netfilter.c +++ b/net/bridge/br_netfilter.c @@ -197,7 +197,7 @@ static int br_nf_pre_routing_finish_bridge(struct sk_buff *skb) skb_pull(skb, VLAN_HLEN); skb->nh.raw += VLAN_HLEN; } - skb->dst->output(&skb); + skb->dst->output(skb); return 0; } diff --git a/net/bridge/netfilter/ebtables.c b/net/bridge/netfilter/ebtables.c index 8352eec5bec4..38f82829c12c 100644 --- a/net/bridge/netfilter/ebtables.c +++ b/net/bridge/netfilter/ebtables.c @@ -109,11 +109,17 @@ static inline int ebt_do_match (struct ebt_entry_match *m, static inline int ebt_dev_check(char *entry, const struct net_device *device) { + int i = 0; + char *devname = device->name; + if (*entry == '\0') return 0; if (!device) return 1; - return !!strcmp(entry, device->name); + /* 1 is the wildcard token */ + while (entry[i] != '\0' && entry[i] != 1 && entry[i] == devname[i]) + i++; + return (devname[i] != entry[i] && entry[i] != 1); } #define FWINV2(bool,invflg) ((bool) ^ !!(e->invflags & invflg)) diff --git a/net/core/dev.c b/net/core/dev.c index df194c2067b8..9d39b2aa52ad 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -1106,34 +1106,34 @@ void dev_queue_xmit_nit(struct sk_buff *skb, struct net_device *dev) * Invalidate hardware checksum when packet is to be mangled, and * complete checksum manually on outgoing path. */ -int skb_checksum_help(struct sk_buff **pskb, int inward) +int skb_checksum_help(struct sk_buff *skb, int inward) { unsigned int csum; - int ret = 0, offset = (*pskb)->h.raw - (*pskb)->data; + int ret = 0, offset = skb->h.raw - skb->data; if (inward) { - (*pskb)->ip_summed = CHECKSUM_NONE; + skb->ip_summed = CHECKSUM_NONE; goto out; } - if (skb_cloned(*pskb)) { - ret = pskb_expand_head(*pskb, 0, 0, GFP_ATOMIC); + if (skb_cloned(skb)) { + ret = pskb_expand_head(skb, 0, 0, GFP_ATOMIC); if (ret) goto out; } - if (offset > (int)(*pskb)->len) + if (offset > (int)skb->len) BUG(); - csum = skb_checksum(*pskb, offset, (*pskb)->len-offset, 0); + csum = skb_checksum(skb, offset, skb->len-offset, 0); - offset = (*pskb)->tail - (*pskb)->h.raw; + offset = skb->tail - skb->h.raw; if (offset <= 0) BUG(); - if ((*pskb)->csum + 2 > offset) + if (skb->csum + 2 > offset) BUG(); - *(u16*)((*pskb)->h.raw + (*pskb)->csum) = csum_fold(csum); - (*pskb)->ip_summed = CHECKSUM_NONE; + *(u16*)(skb->h.raw + skb->csum) = csum_fold(csum); + skb->ip_summed = CHECKSUM_NONE; out: return ret; } @@ -1282,7 +1282,7 @@ int dev_queue_xmit(struct sk_buff *skb) (!(dev->features & (NETIF_F_HW_CSUM | NETIF_F_NO_CSUM)) && (!(dev->features & NETIF_F_IP_CSUM) || skb->protocol != htons(ETH_P_IP)))) - if (skb_checksum_help(&skb, 0)) + if (skb_checksum_help(skb, 0)) goto out_kfree_skb; diff --git a/net/core/dst.c b/net/core/dst.c index 42aeae5959f5..8755f0de86dc 100644 --- a/net/core/dst.c +++ b/net/core/dst.c @@ -106,9 +106,9 @@ static int dst_discard_in(struct sk_buff *skb) return 0; } -static int dst_discard_out(struct sk_buff **pskb) +static int dst_discard_out(struct sk_buff *skb) { - kfree_skb(*pskb); + kfree_skb(skb); return 0; } diff --git a/net/core/sock.c b/net/core/sock.c index 3582a0f0ab3d..79d7e32e347a 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -175,6 +175,15 @@ static void sock_warn_obsolete_bsdism(const char *name) } } +static void sock_disable_timestamp(struct sock *sk) +{ + if (sock_flag(sk, SOCK_TIMESTAMP)) { + sock_reset_flag(sk, SOCK_TIMESTAMP); + atomic_dec(&netstamp_needed); + } +} + + /* * This is meant for all protocols to use and covers goings on * at the socket level. Everything here is generic. @@ -972,11 +981,6 @@ EXPORT_SYMBOL(sk_wait_data); * function, some default processing is provided. */ -int sock_no_release(struct socket *sock) -{ - return 0; -} - int sock_no_bind(struct socket *sock, struct sockaddr *saddr, int len) { return -EOPNOTSUPP; @@ -1247,15 +1251,6 @@ void sock_enable_timestamp(struct sock *sk) } EXPORT_SYMBOL(sock_enable_timestamp); -void sock_disable_timestamp(struct sock *sk) -{ - if (sock_flag(sk, SOCK_TIMESTAMP)) { - sock_reset_flag(sk, SOCK_TIMESTAMP); - atomic_dec(&netstamp_needed); - } -} -EXPORT_SYMBOL(sock_disable_timestamp); - /* * Get a socket option on an socket. * @@ -1371,7 +1366,6 @@ EXPORT_SYMBOL(sk_free); EXPORT_SYMBOL(sk_send_sigurg); EXPORT_SYMBOL(sock_alloc_send_pskb); EXPORT_SYMBOL(sock_alloc_send_skb); -EXPORT_SYMBOL(sock_getsockopt); EXPORT_SYMBOL(sock_init_data); EXPORT_SYMBOL(sock_kfree_s); EXPORT_SYMBOL(sock_kmalloc); @@ -1385,14 +1379,12 @@ EXPORT_SYMBOL(sock_no_listen); EXPORT_SYMBOL(sock_no_mmap); EXPORT_SYMBOL(sock_no_poll); EXPORT_SYMBOL(sock_no_recvmsg); -EXPORT_SYMBOL(sock_no_release); EXPORT_SYMBOL(sock_no_sendmsg); EXPORT_SYMBOL(sock_no_sendpage); EXPORT_SYMBOL(sock_no_setsockopt); EXPORT_SYMBOL(sock_no_shutdown); EXPORT_SYMBOL(sock_no_socketpair); EXPORT_SYMBOL(sock_rfree); -EXPORT_SYMBOL(sock_rmalloc); EXPORT_SYMBOL(sock_setsockopt); EXPORT_SYMBOL(sock_wfree); EXPORT_SYMBOL(sock_wmalloc); diff --git a/net/decnet/dn_nsp_in.c b/net/decnet/dn_nsp_in.c index 05d84ed7e4e6..d8e24d47d044 100644 --- a/net/decnet/dn_nsp_in.c +++ b/net/decnet/dn_nsp_in.c @@ -419,6 +419,7 @@ static void dn_nsp_disc_init(struct sock *sk, struct sk_buff *skb) case DN_CI: case DN_CD: scp->state = DN_RJ; + sk->sk_err = ECONNREFUSED; break; case DN_RUN: sk->sk_shutdown |= SHUTDOWN_MASK; diff --git a/net/decnet/dn_route.c b/net/decnet/dn_route.c index 64bdf10b75b7..34f0b81e1784 100644 --- a/net/decnet/dn_route.c +++ b/net/decnet/dn_route.c @@ -683,9 +683,8 @@ out: return NET_RX_DROP; } -static int dn_output(struct sk_buff **pskb) +static int dn_output(struct sk_buff *skb) { - struct sk_buff *skb = *pskb; struct dst_entry *dst = skb->dst; struct dn_route *rt = (struct dn_route *)dst; struct net_device *dev = dst->dev; @@ -796,11 +795,6 @@ static int dn_rt_bug(struct sk_buff *skb) return NET_RX_BAD; } -static int dn_rt_bug_out(struct sk_buff **pskb) -{ - return dn_rt_bug(*pskb); -} - static int dn_rt_set_next_hop(struct dn_route *rt, struct dn_fib_res *res) { struct dn_fib_info *fi = res->fi; @@ -1392,7 +1386,7 @@ make_route: rt->u.dst.neighbour = neigh; rt->u.dst.dev = out_dev; rt->u.dst.lastuse = jiffies; - rt->u.dst.output = dn_rt_bug_out; + rt->u.dst.output = dn_rt_bug; switch(res.type) { case RTN_UNICAST: rt->u.dst.input = dn_forward; diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c index 57768575c82a..5befbf203fcf 100644 --- a/net/ipv4/af_inet.c +++ b/net/ipv4/af_inet.c @@ -1165,8 +1165,6 @@ EXPORT_SYMBOL(inet_stream_connect); EXPORT_SYMBOL(inet_stream_ops); EXPORT_SYMBOL(inet_unregister_protosw); EXPORT_SYMBOL(net_statistics); -EXPORT_SYMBOL(tcp_protocol); -EXPORT_SYMBOL(udp_protocol); #ifdef INET_REFCNT_DEBUG EXPORT_SYMBOL(inet_sock_nr); diff --git a/net/ipv4/fib_semantics.c b/net/ipv4/fib_semantics.c index ec1f08872f1d..a1349862a8ce 100644 --- a/net/ipv4/fib_semantics.c +++ b/net/ipv4/fib_semantics.c @@ -163,6 +163,8 @@ void fib_release_info(struct fib_info *fi) if (fi->fib_prefsrc) hlist_del(&fi->fib_lhash); change_nexthops(fi) { + if (!nh->nh_dev) + continue; hlist_del(&nh->nh_hash); } endfor_nexthops(fi) fi->fib_dead = 1; diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c index 8ef2b82630a2..062981affa1c 100644 --- a/net/ipv4/ip_output.c +++ b/net/ipv4/ip_output.c @@ -224,9 +224,8 @@ int ip_finish_output(struct sk_buff *skb) ip_finish_output2); } -int ip_mc_output(struct sk_buff **pskb) +int ip_mc_output(struct sk_buff *skb) { - struct sk_buff *skb = *pskb; struct sock *sk = skb->sk; struct rtable *rt = (struct rtable*)skb->dst; struct net_device *dev = rt->u.dst.dev; @@ -285,10 +284,8 @@ int ip_mc_output(struct sk_buff **pskb) return ip_finish_output(skb); } -int ip_output(struct sk_buff **pskb) +int ip_output(struct sk_buff *skb) { - struct sk_buff *skb = *pskb; - IP_INC_STATS(IPSTATS_MIB_OUTREQUESTS); if ((skb->len > dst_pmtu(skb->dst) || skb_shinfo(skb)->frag_list) && diff --git a/net/ipv4/netfilter/arp_tables.c b/net/ipv4/netfilter/arp_tables.c index f2b3e7e5bb18..b0d4ce63e973 100644 --- a/net/ipv4/netfilter/arp_tables.c +++ b/net/ipv4/netfilter/arp_tables.c @@ -395,7 +395,7 @@ static inline struct arpt_table *arpt_find_table_lock(const char *name, int *err return find_inlist_lock(&arpt_tables, name, "arptable_", error, mutex); } -struct arpt_target *arpt_find_target_lock(const char *name, int *error, struct semaphore *mutex) +static struct arpt_target *arpt_find_target_lock(const char *name, int *error, struct semaphore *mutex) { return find_inlist_lock(&arpt_target, name, "arpt_", error, mutex); } @@ -1325,7 +1325,6 @@ static void __exit fini(void) EXPORT_SYMBOL(arpt_register_table); EXPORT_SYMBOL(arpt_unregister_table); EXPORT_SYMBOL(arpt_do_table); -EXPORT_SYMBOL(arpt_find_target_lock); EXPORT_SYMBOL(arpt_register_target); EXPORT_SYMBOL(arpt_unregister_target); diff --git a/net/ipv4/netfilter/ip_conntrack_core.c b/net/ipv4/netfilter/ip_conntrack_core.c index 39e02a0a93b2..b3a6e6427c00 100644 --- a/net/ipv4/netfilter/ip_conntrack_core.c +++ b/net/ipv4/netfilter/ip_conntrack_core.c @@ -352,16 +352,14 @@ __ip_conntrack_find(const struct ip_conntrack_tuple *tuple, { struct ip_conntrack_tuple_hash *h; unsigned int hash = hash_conntrack(tuple); - /* use per_cpu() to avoid multiple calls to smp_processor_id() */ - unsigned int cpu = smp_processor_id(); MUST_BE_READ_LOCKED(&ip_conntrack_lock); list_for_each_entry(h, &ip_conntrack_hash[hash], list) { if (conntrack_tuple_cmp(h, tuple, ignored_conntrack)) { - per_cpu(ip_conntrack_stat, cpu).found++; + CONNTRACK_STAT_INC(found); return h; } - per_cpu(ip_conntrack_stat, cpu).searched++; + CONNTRACK_STAT_INC(searched); } return NULL; @@ -436,13 +434,14 @@ __ip_conntrack_confirm(struct sk_buff *skb) add_timer(&ct->timeout); atomic_inc(&ct->ct_general.use); set_bit(IPS_CONFIRMED_BIT, &ct->status); - WRITE_UNLOCK(&ip_conntrack_lock); CONNTRACK_STAT_INC(insert); + WRITE_UNLOCK(&ip_conntrack_lock); return NF_ACCEPT; } - WRITE_UNLOCK(&ip_conntrack_lock); CONNTRACK_STAT_INC(insert_failed); + WRITE_UNLOCK(&ip_conntrack_lock); + return NF_DROP; } diff --git a/net/ipv4/netfilter/ip_fw_compat.c b/net/ipv4/netfilter/ip_fw_compat.c index f7146f31b6c3..840643de241f 100644 --- a/net/ipv4/netfilter/ip_fw_compat.c +++ b/net/ipv4/netfilter/ip_fw_compat.c @@ -69,7 +69,7 @@ fw_in(unsigned int hooknum, /* Assume worse case: any hook could change packet */ (*pskb)->nfcache |= NFC_UNKNOWN | NFC_ALTERED; if ((*pskb)->ip_summed == CHECKSUM_HW) - if (skb_checksum_help(pskb, (out == NULL))) + if (skb_checksum_help(*pskb, (out == NULL))) return NF_DROP; switch (hooknum) { diff --git a/net/ipv4/netfilter/ip_nat_standalone.c b/net/ipv4/netfilter/ip_nat_standalone.c index e4e961225c5f..71bd2e05b0b2 100644 --- a/net/ipv4/netfilter/ip_nat_standalone.c +++ b/net/ipv4/netfilter/ip_nat_standalone.c @@ -86,7 +86,7 @@ ip_nat_fn(unsigned int hooknum, /* If we had a hardware checksum before, it's now invalid */ if ((*pskb)->ip_summed == CHECKSUM_HW) - if (skb_checksum_help(pskb, (out == NULL))) + if (skb_checksum_help(*pskb, (out == NULL))) return NF_DROP; ct = ip_conntrack_get(*pskb, &ctinfo); diff --git a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c index 8da90bdb37c2..3e601a80d580 100644 --- a/net/ipv4/netfilter/ip_tables.c +++ b/net/ipv4/netfilter/ip_tables.c @@ -471,7 +471,7 @@ find_match_lock(const char *name, int *error, struct semaphore *mutex) return find_inlist_lock(&ipt_match, name, "ipt_", error, mutex); } -struct ipt_target * +static struct ipt_target * ipt_find_target_lock(const char *name, int *error, struct semaphore *mutex) { return find_inlist_lock(&ipt_target, name, "ipt_", error, mutex); @@ -1877,7 +1877,6 @@ EXPORT_SYMBOL(ipt_unregister_match); EXPORT_SYMBOL(ipt_do_table); EXPORT_SYMBOL(ipt_register_target); EXPORT_SYMBOL(ipt_unregister_target); -EXPORT_SYMBOL(ipt_find_target_lock); module_init(init); module_exit(fini); diff --git a/net/ipv4/netfilter/ipt_CONNMARK.c b/net/ipv4/netfilter/ipt_CONNMARK.c index ef3d21703121..30ddd3e18eb7 100644 --- a/net/ipv4/netfilter/ipt_CONNMARK.c +++ b/net/ipv4/netfilter/ipt_CONNMARK.c @@ -60,7 +60,7 @@ target(struct sk_buff **pskb, break; case IPT_CONNMARK_RESTORE: nfmark = (*pskb)->nfmark; - diff = (ct->mark ^ nfmark & markinfo->mask); + diff = (ct->mark ^ nfmark) & markinfo->mask; if (diff != 0) { (*pskb)->nfmark = nfmark ^ diff; (*pskb)->nfcache |= NFC_ALTERED; diff --git a/net/ipv4/netfilter/ipt_ECN.c b/net/ipv4/netfilter/ipt_ECN.c index 120109cd294d..f659ec3c9278 100644 --- a/net/ipv4/netfilter/ipt_ECN.c +++ b/net/ipv4/netfilter/ipt_ECN.c @@ -86,7 +86,7 @@ set_ect_tcp(struct sk_buff **pskb, const struct ipt_ECN_info *einfo, int inward) memcpy((*pskb)->data + (*pskb)->nh.iph->ihl*4, &_tcph, sizeof(_tcph)); if ((*pskb)->ip_summed == CHECKSUM_HW) - if (skb_checksum_help(pskb, inward)) + if (skb_checksum_help(*pskb, inward)) return 0; (*pskb)->nfcache |= NFC_ALTERED; } diff --git a/net/ipv4/netfilter/ipt_MASQUERADE.c b/net/ipv4/netfilter/ipt_MASQUERADE.c index ea02a12d7625..6beaec1e1f2b 100644 --- a/net/ipv4/netfilter/ipt_MASQUERADE.c +++ b/net/ipv4/netfilter/ipt_MASQUERADE.c @@ -81,8 +81,8 @@ masquerade_target(struct sk_buff **pskb, enum ip_conntrack_info ctinfo; const struct ip_nat_multi_range *mr; struct ip_nat_multi_range newrange; - u_int32_t newsrc; struct rtable *rt; + u_int32_t newsrc; IP_NF_ASSERT(hooknum == NF_IP_POST_ROUTING); @@ -96,36 +96,13 @@ masquerade_target(struct sk_buff **pskb, || ctinfo == IP_CT_RELATED + IP_CT_IS_REPLY)); mr = targinfo; - - { - struct flowi fl = { .nl_u = { .ip4_u = - { .daddr = (*pskb)->nh.iph->daddr, - .tos = (RT_TOS((*pskb)->nh.iph->tos) | - RTO_CONN), -#ifdef CONFIG_IP_ROUTE_FWMARK - .fwmark = (*pskb)->nfmark -#endif - } } }; - if (ip_route_output_key(&rt, &fl) != 0) { - /* Funky routing can do this. */ - if (net_ratelimit()) - printk("MASQUERADE:" - " No route: Rusty's brain broke!\n"); - return NF_DROP; - } - if (rt->u.dst.dev != out) { - if (net_ratelimit()) - printk("MASQUERADE:" - " Route sent us somewhere else.\n"); - ip_rt_put(rt); - return NF_DROP; - } + rt = (struct rtable *)(*pskb)->dst; + newsrc = inet_select_addr(out, rt->rt_gateway, RT_SCOPE_UNIVERSE); + if (!newsrc) { + printk("MASQUERADE: %s ate my IP address\n", out->name); + return NF_DROP; } - newsrc = rt->rt_src; - DEBUGP("newsrc = %u.%u.%u.%u\n", NIPQUAD(newsrc)); - ip_rt_put(rt); - WRITE_LOCK(&masq_lock); ct->nat.masq_index = out->ifindex; WRITE_UNLOCK(&masq_lock); @@ -157,6 +134,18 @@ device_cmp(const struct ip_conntrack *i, void *_ina) return ret; } +static inline int +connect_unassure(const struct ip_conntrack *i, void *_ina) +{ + struct in_ifaddr *ina = _ina; + + /* We reset the ASSURED bit on all connections, so they will + * get reaped under memory pressure. */ + if (i->nat.masq_index == ina->ifa_dev->dev->ifindex) + clear_bit(IPS_ASSURED_BIT, (unsigned long *)&i->status); + return 0; +} + static int masq_inet_event(struct notifier_block *this, unsigned long event, void *ptr) @@ -166,6 +155,8 @@ static int masq_inet_event(struct notifier_block *this, * entries. */ if (event == NETDEV_UP) ip_ct_selective_cleanup(device_cmp, ptr); + else if (event == NETDEV_DOWN) + ip_ct_selective_cleanup(connect_unassure, ptr); return NOTIFY_DONE; } diff --git a/net/ipv4/netfilter/ipt_ULOG.c b/net/ipv4/netfilter/ipt_ULOG.c index 51d16d33bcbd..56d018940954 100644 --- a/net/ipv4/netfilter/ipt_ULOG.c +++ b/net/ipv4/netfilter/ipt_ULOG.c @@ -1,7 +1,7 @@ /* * netfilter module for userspace packet logging daemons * - * (C) 2000-2002 by Harald Welte <laforge@netfilter.org> + * (C) 2000-2004 by Harald Welte <laforge@netfilter.org> * * 2000/09/22 ulog-cprange feature added * 2001/01/04 in-kernel queue as proposed by Sebastian Zander @@ -13,6 +13,8 @@ * 2002/07/07 remove broken nflog_rcv() function -HW * 2002/08/29 fix shifted/unshifted nlgroup bug -HW * 2002/10/30 fix uninitialized mac_len field - <Anders K. Pedersen> + * 2004/10/25 fix erroneous calculation of 'len' parameter to NLMSG_PUT + * resulting in bogus 'error during NLMSG_PUT' messages. * * (C) 1999-2001 Paul `Rusty' Russell * (C) 2002-2004 Netfilter Core Team <coreteam@netfilter.org> @@ -212,7 +214,7 @@ static void ipt_ulog_packet(unsigned int hooknum, /* NLMSG_PUT contains a hidden goto nlmsg_failure !!! */ nlh = NLMSG_PUT(ub->skb, 0, ub->qlen, ULOG_NL_EVENT, - size - sizeof(*nlh)); + sizeof(*pm)+copy_len); ub->qlen++; pm = NLMSG_DATA(nlh); diff --git a/net/ipv4/raw.c b/net/ipv4/raw.c index 08b45abff125..2ec51e2d2973 100644 --- a/net/ipv4/raw.c +++ b/net/ipv4/raw.c @@ -407,7 +407,7 @@ static int raw_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, printk(KERN_INFO "%s forgot to set AF_INET in " "raw sendmsg. Fix it!\n", current->comm); - err = -EINVAL; + err = -EAFNOSUPPORT; if (usin->sin_family) goto out; } diff --git a/net/ipv4/route.c b/net/ipv4/route.c index fd023db82df9..27ce169f63b9 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c @@ -1367,10 +1367,8 @@ static void ipv4_link_failure(struct sk_buff *skb) dst_set_expires(&rt->u.dst, 0); } -static int ip_rt_bug(struct sk_buff **pskb) +static int ip_rt_bug(struct sk_buff *skb) { - struct sk_buff *skb = *pskb; - printk(KERN_DEBUG "ip_rt_bug: %u.%u.%u.%u -> %u.%u.%u.%u, %s\n", NIPQUAD(skb->nh.iph->saddr), NIPQUAD(skb->nh.iph->daddr), skb->dev ? skb->dev->name : "?"); diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index 462cbda0277f..67ddd1d9e066 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -2307,7 +2307,6 @@ void __init tcp_init(void) EXPORT_SYMBOL(tcp_accept); EXPORT_SYMBOL(tcp_close); -EXPORT_SYMBOL(tcp_close_state); EXPORT_SYMBOL(tcp_destroy_sock); EXPORT_SYMBOL(tcp_disconnect); EXPORT_SYMBOL(tcp_getsockopt); diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index ece320e60f71..e8769f30f0c6 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -2369,25 +2369,19 @@ static int tcp_tso_acked(struct sock *sk, struct sk_buff *skb, { struct tcp_opt *tp = tcp_sk(sk); struct tcp_skb_cb *scb = TCP_SKB_CB(skb); - __u32 mss = tcp_skb_mss(skb); - __u32 snd_una = tp->snd_una; - __u32 orig_seq, seq; - __u32 packets_acked = 0; + __u32 seq = tp->snd_una; + __u32 packets_acked; int acked = 0; /* If we get here, the whole TSO packet has not been * acked. */ - BUG_ON(!after(scb->end_seq, snd_una)); + BUG_ON(!after(scb->end_seq, seq)); - seq = orig_seq = scb->seq; - while (!after(seq + mss, snd_una)) { - packets_acked++; - seq += mss; - } - - if (tcp_trim_head(sk, skb, (seq - orig_seq))) + packets_acked = tcp_skb_pcount(skb); + if (tcp_trim_head(sk, skb, seq - scb->seq)) return 0; + packets_acked -= tcp_skb_pcount(skb); if (packets_acked) { __u8 sacked = scb->sacked; @@ -4963,7 +4957,6 @@ discard: EXPORT_SYMBOL(sysctl_tcp_ecn); EXPORT_SYMBOL(sysctl_tcp_reordering); -EXPORT_SYMBOL(tcp_cwnd_application_limited); EXPORT_SYMBOL(tcp_parse_options); EXPORT_SYMBOL(tcp_rcv_established); EXPORT_SYMBOL(tcp_rcv_state_process); diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index 96594f8a8088..3df3ada30e6c 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -448,8 +448,8 @@ static struct sock *__tcp_v4_lookup_listener(struct hlist_head *head, u32 daddr, } /* Optimize the common listener case. */ -inline struct sock *tcp_v4_lookup_listener(u32 daddr, unsigned short hnum, - int dif) +static inline struct sock *tcp_v4_lookup_listener(u32 daddr, + unsigned short hnum, int dif) { struct sock *sk = NULL; struct hlist_head *head; @@ -2653,7 +2653,6 @@ EXPORT_SYMBOL(tcp_unhash); EXPORT_SYMBOL(tcp_v4_conn_request); EXPORT_SYMBOL(tcp_v4_connect); EXPORT_SYMBOL(tcp_v4_do_rcv); -EXPORT_SYMBOL(tcp_v4_lookup_listener); EXPORT_SYMBOL(tcp_v4_rebuild_header); EXPORT_SYMBOL(tcp_v4_remember_stamp); EXPORT_SYMBOL(tcp_v4_send_check); diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index 10c49d779487..0b08a3499b29 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c @@ -588,7 +588,7 @@ int tcp_trim_head(struct sock *sk, struct sk_buff *skb, u32 len) /* Any change of skb->len requires recalculation of tso * factor and mss. */ - if (tcp_skb_mss(skb)) + if (tcp_skb_pcount(skb) > 1) tcp_set_skb_tso_segs(skb, tcp_skb_mss(skb)); return 0; @@ -1720,12 +1720,7 @@ void tcp_send_probe0(struct sock *sk) } } -EXPORT_SYMBOL(tcp_acceptable_seq); EXPORT_SYMBOL(tcp_connect); -EXPORT_SYMBOL(tcp_connect_init); EXPORT_SYMBOL(tcp_make_synack); -EXPORT_SYMBOL(tcp_send_synack); EXPORT_SYMBOL(tcp_simple_retransmit); EXPORT_SYMBOL(tcp_sync_mss); -EXPORT_SYMBOL(tcp_write_wakeup); -EXPORT_SYMBOL(tcp_write_xmit); diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index 8a4c26ed9712..6bd005dbd80c 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c @@ -531,7 +531,7 @@ int udp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, return -EINVAL; if (usin->sin_family != AF_INET) { if (usin->sin_family != AF_UNSPEC) - return -EINVAL; + return -EAFNOSUPPORT; } daddr = usin->sin_addr.s_addr; diff --git a/net/ipv4/xfrm4_output.c b/net/ipv4/xfrm4_output.c index 21832dfc376e..3c70b08f908c 100644 --- a/net/ipv4/xfrm4_output.c +++ b/net/ipv4/xfrm4_output.c @@ -91,16 +91,14 @@ out: return ret; } -int xfrm4_output(struct sk_buff **pskb) +int xfrm4_output(struct sk_buff *skb) { - struct sk_buff *skb = *pskb; struct dst_entry *dst = skb->dst; struct xfrm_state *x = dst->xfrm; int err; if (skb->ip_summed == CHECKSUM_HW) { - err = skb_checksum_help(pskb, 0); - skb = *pskb; + err = skb_checksum_help(skb, 0); if (err) goto error_nolock; } diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index 737937e4471b..2fbe96226000 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -404,6 +404,7 @@ static struct inet6_dev * ipv6_find_idev(struct net_device *dev) return idev; } +#ifdef CONFIG_SYSCTL static void dev_forward_change(struct inet6_dev *idev) { struct net_device *dev; @@ -449,7 +450,7 @@ static void addrconf_forward_change(void) } read_unlock(&dev_base_lock); } - +#endif /* Nobody refers to this ifaddr, destroy it */ @@ -760,7 +761,7 @@ static int inline ipv6_saddr_pref(const struct inet6_ifaddr *ifp, u8 invpref) #endif int ipv6_dev_get_saddr(struct net_device *dev, - struct in6_addr *daddr, struct in6_addr *saddr, int onlink) + struct in6_addr *daddr, struct in6_addr *saddr) { struct inet6_ifaddr *ifp = NULL; struct inet6_ifaddr *match = NULL; @@ -769,10 +770,7 @@ int ipv6_dev_get_saddr(struct net_device *dev, int err; int hiscore = -1, score; - if (!onlink) - scope = ipv6_addr_scope(daddr); - else - scope = IFA_LINK; + scope = ipv6_addr_scope(daddr); /* * known dev @@ -877,17 +875,7 @@ out: int ipv6_get_saddr(struct dst_entry *dst, struct in6_addr *daddr, struct in6_addr *saddr) { - struct rt6_info *rt; - struct net_device *dev = NULL; - int onlink; - - rt = (struct rt6_info *) dst; - if (rt) - dev = rt->rt6i_dev; - - onlink = (rt && (rt->rt6i_flags & RTF_ALLONLINK)); - - return ipv6_dev_get_saddr(dev, daddr, saddr, onlink); + return ipv6_dev_get_saddr(dst ? dst->dev : NULL, daddr, saddr); } @@ -3042,7 +3030,7 @@ int addrconf_sysctl_forward(ctl_table *ctl, int write, struct file * filp, addrconf_forward_change(); } if (*valp) - rt6_purge_dflt_routers(0); + rt6_purge_dflt_routers(); } return ret; @@ -3096,7 +3084,7 @@ static int addrconf_sysctl_forward_strategy(ctl_table *table, } if (*valp) - rt6_purge_dflt_routers(0); + rt6_purge_dflt_routers(); } else *valp = new; diff --git a/net/ipv6/ip6_fib.c b/net/ipv6/ip6_fib.c index 1816b81ae454..d394bd2d0285 100644 --- a/net/ipv6/ip6_fib.c +++ b/net/ipv6/ip6_fib.c @@ -433,7 +433,7 @@ static int fib6_add_rt2node(struct fib6_node *fn, struct rt6_info *rt, if (fn->fn_flags&RTN_TL_ROOT && fn->leaf == &ip6_null_entry && - !(rt->rt6i_flags & (RTF_DEFAULT | RTF_ADDRCONF | RTF_ALLONLINK)) ){ + !(rt->rt6i_flags & (RTF_DEFAULT | RTF_ADDRCONF)) ){ fn->leaf = rt; rt->u.next = NULL; goto out; diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index 33260cfacd35..e74a46201ef1 100644 --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c @@ -56,7 +56,7 @@ #include <net/xfrm.h> #include <net/checksum.h> -static int ip6_fragment(struct sk_buff **pskb, int (*output)(struct sk_buff**)); +static int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *)); static __inline__ void ipv6_select_ident(struct sk_buff *skb, struct frag_hdr *fhdr) { @@ -108,9 +108,8 @@ static int ip6_dev_loopback_xmit(struct sk_buff *newskb) } -static int ip6_output2(struct sk_buff **pskb) +static int ip6_output2(struct sk_buff *skb) { - struct sk_buff *skb = *pskb; struct dst_entry *dst = skb->dst; struct net_device *dev = dst->dev; @@ -146,14 +145,12 @@ static int ip6_output2(struct sk_buff **pskb) return NF_HOOK(PF_INET6, NF_IP6_POST_ROUTING, skb,NULL, skb->dev,ip6_output_finish); } -int ip6_output(struct sk_buff **pskb) +int ip6_output(struct sk_buff *skb) { - struct sk_buff *skb = *pskb; - if ((skb->len > dst_pmtu(skb->dst) || skb_shinfo(skb)->frag_list)) - return ip6_fragment(pskb, ip6_output2); + return ip6_fragment(skb, ip6_output2); else - return ip6_output2(pskb); + return ip6_output2(skb); } #ifdef CONFIG_NETFILTER @@ -518,10 +515,10 @@ int ip6_find_1stfragopt(struct sk_buff *skb, u8 **nexthdr) return offset; } -static int ip6_fragment(struct sk_buff **pskb, int (*output)(struct sk_buff**)) +static int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *)) { struct net_device *dev; - struct sk_buff *frag, *skb = *pskb; + struct sk_buff *frag; struct rt6_info *rt = (struct rt6_info*)skb->dst; struct ipv6hdr *tmp_hdr; struct frag_hdr *fh; @@ -610,7 +607,7 @@ static int ip6_fragment(struct sk_buff **pskb, int (*output)(struct sk_buff**)) ip6_copy_metadata(frag, skb); } - err = output(&skb); + err = output(skb); if (err || !frag) break; @@ -726,7 +723,7 @@ slow_path: IP6_INC_STATS(IPSTATS_MIB_FRAGCREATES); - err = output(&frag); + err = output(frag); if (err) goto fail; } diff --git a/net/ipv6/ipv6_syms.c b/net/ipv6/ipv6_syms.c index 122482817501..a2d9601f98d3 100644 --- a/net/ipv6/ipv6_syms.c +++ b/net/ipv6/ipv6_syms.c @@ -35,13 +35,9 @@ EXPORT_SYMBOL(ipv6_chk_addr); EXPORT_SYMBOL(in6addr_any); EXPORT_SYMBOL(in6addr_loopback); EXPORT_SYMBOL(in6_dev_finish_destroy); -EXPORT_SYMBOL(ip6_find_1stfragopt); #ifdef CONFIG_XFRM EXPORT_SYMBOL(xfrm6_rcv); #endif EXPORT_SYMBOL(rt6_lookup); EXPORT_SYMBOL(fl6_sock_lookup); -EXPORT_SYMBOL(ip6_append_data); -EXPORT_SYMBOL(ip6_flush_pending_frames); -EXPORT_SYMBOL(ip6_push_pending_frames); EXPORT_SYMBOL(ipv6_push_nfrag_opts); diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c index 685a02d2ebf5..30f77ff07781 100644 --- a/net/ipv6/ndisc.c +++ b/net/ipv6/ndisc.c @@ -396,7 +396,7 @@ static void ndisc_send_na(struct net_device *dev, struct neighbour *neigh, src_addr = solicited_addr; in6_ifa_put(ifp); } else { - if (ipv6_dev_get_saddr(dev, daddr, &tmpaddr, 0)) + if (ipv6_dev_get_saddr(dev, daddr, &tmpaddr)) return; src_addr = &tmpaddr; } @@ -921,6 +921,64 @@ static void ndisc_recv_na(struct sk_buff *skb) } } +static void ndisc_recv_rs(struct sk_buff *skb) +{ + struct rs_msg *rs_msg = (struct rs_msg *) skb->h.raw; + unsigned long ndoptlen = skb->len - sizeof(*rs_msg); + struct neighbour *neigh; + struct inet6_dev *idev; + struct in6_addr *saddr = &skb->nh.ipv6h->saddr; + struct ndisc_options ndopts; + u8 *lladdr = NULL; + int lladdrlen = 0; + + if (skb->len < sizeof(*rs_msg)) + return; + + idev = in6_dev_get(skb->dev); + if (!idev) { + if (net_ratelimit()) + ND_PRINTK1("ICMP6 RS: can't find in6 device\n"); + return; + } + + /* Don't accept RS if we're not in router mode */ + if (!idev->cnf.forwarding || idev->cnf.accept_ra) + goto out; + + /* + * Don't update NCE if src = ::; + * this implies that the source node has no ip address assigned yet. + */ + if (ipv6_addr_any(saddr)) + goto out; + + /* Parse ND options */ + if (!ndisc_parse_options(rs_msg->opt, ndoptlen, &ndopts)) { + if (net_ratelimit()) + ND_PRINTK2("ICMP6 NS: invalid ND option, ignored\n"); + goto out; + } + + if (ndopts.nd_opts_src_lladdr) { + lladdr = (u8 *)(ndopts.nd_opts_src_lladdr + 1); + lladdrlen = ndopts.nd_opts_src_lladdr->nd_opt_len << 3; + if (lladdrlen != NDISC_OPT_SPACE(skb->dev->addr_len)) + goto out; + } + + neigh = __neigh_lookup(&nd_tbl, saddr, skb->dev, 1); + if (neigh) { + neigh_update(neigh, lladdr, NUD_STALE, + NEIGH_UPDATE_F_WEAK_OVERRIDE| + NEIGH_UPDATE_F_OVERRIDE| + NEIGH_UPDATE_F_OVERRIDE_ISROUTER); + neigh_release(neigh); + } +out: + in6_dev_put(idev); +} + static void ndisc_router_discovery(struct sk_buff *skb) { struct ra_msg *ra_msg = (struct ra_msg *) skb->h.raw; @@ -1026,7 +1084,7 @@ static void ndisc_router_discovery(struct sk_buff *skb) * delete it */ - rt6_purge_dflt_routers(RTF_ALLONLINK); + rt6_purge_dflt_routers(); } if (rt) @@ -1395,6 +1453,10 @@ int ndisc_rcv(struct sk_buff *skb) ndisc_recv_na(skb); break; + case NDISC_ROUTER_SOLICITATION: + ndisc_recv_rs(skb); + break; + case NDISC_ROUTER_ADVERTISEMENT: ndisc_router_discovery(skb); break; diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c index 0cef15b866f5..80b3e3d301c0 100644 --- a/net/ipv6/netfilter/ip6_tables.c +++ b/net/ipv6/netfilter/ip6_tables.c @@ -158,14 +158,15 @@ ip6t_ext_hdr(u8 nexthdr) /* Returns whether matches rule or not. */ static inline int ip6_packet_match(const struct sk_buff *skb, - const struct ipv6hdr *ipv6, const char *indev, const char *outdev, const struct ip6t_ip6 *ip6info, - int isfrag) + unsigned int *protoff, + int *fragoff) { size_t i; unsigned long ret; + const struct ipv6hdr *ipv6 = skb->nh.ipv6h; #define FWINV(bool,invflg) ((bool) ^ !!(ip6info->invflags & invflg)) @@ -216,9 +217,10 @@ ip6_packet_match(const struct sk_buff *skb, /* look for the desired protocol header */ if((ip6info->flags & IP6T_F_PROTO)) { u_int8_t currenthdr = ipv6->nexthdr; - struct ipv6_opt_hdr *hdrptr; + struct ipv6_opt_hdr _hdr, *hp; u_int16_t ptr; /* Header offset in skb */ u_int16_t hdrlen; /* Header */ + u_int16_t _fragoff = 0, *fp = NULL; ptr = IPV6_HDR_LEN; @@ -234,23 +236,41 @@ ip6_packet_match(const struct sk_buff *skb, (currenthdr == IPPROTO_ESP)) return 0; - hdrptr = (struct ipv6_opt_hdr *)(skb->data + ptr); + hp = skb_header_pointer(skb, ptr, sizeof(_hdr), &_hdr); + BUG_ON(hp == NULL); /* Size calculation */ if (currenthdr == IPPROTO_FRAGMENT) { + fp = skb_header_pointer(skb, + ptr+offsetof(struct frag_hdr, + frag_off), + sizeof(_fragoff), + &_fragoff); + if (fp == NULL) + return 0; + + _fragoff = ntohs(*fp) & ~0x7; hdrlen = 8; } else if (currenthdr == IPPROTO_AH) - hdrlen = (hdrptr->hdrlen+2)<<2; + hdrlen = (hp->hdrlen+2)<<2; else - hdrlen = ipv6_optlen(hdrptr); + hdrlen = ipv6_optlen(hp); - currenthdr = hdrptr->nexthdr; + currenthdr = hp->nexthdr; ptr += hdrlen; /* ptr is too large */ if ( ptr > skb->len ) return 0; + if (_fragoff) { + if (ip6t_ext_hdr(currenthdr)) + return 0; + break; + } } + *protoff = ptr; + *fragoff = _fragoff; + /* currenthdr contains the protocol header */ dprintf("Packet protocol %hi ?= %s%hi.\n", @@ -292,9 +312,9 @@ ip6_checkentry(const struct ip6t_ip6 *ipv6) static unsigned int ip6t_error(struct sk_buff **pskb, - unsigned int hooknum, const struct net_device *in, const struct net_device *out, + unsigned int hooknum, const void *targinfo, void *userinfo) { @@ -310,13 +330,12 @@ int do_match(struct ip6t_entry_match *m, const struct net_device *in, const struct net_device *out, int offset, - const void *hdr, - u_int16_t datalen, + unsigned int protoff, int *hotdrop) { /* Stop iteration if it doesn't match */ if (!m->u.kernel.match->match(skb, in, out, m->data, - offset, hdr, datalen, hotdrop)) + offset, protoff, hotdrop)) return 1; else return 0; @@ -338,10 +357,8 @@ ip6t_do_table(struct sk_buff **pskb, void *userdata) { static const char nulldevname[IFNAMSIZ]; - u_int16_t offset = 0; - struct ipv6hdr *ipv6; - void *protohdr; - u_int16_t datalen; + int offset = 0; + unsigned int protoff = 0; int hotdrop = 0; /* Initializing verdict to NF_DROP keeps gcc happy. */ unsigned int verdict = NF_DROP; @@ -354,9 +371,6 @@ ip6t_do_table(struct sk_buff **pskb, return NF_DROP; /* Initialization */ - ipv6 = (*pskb)->nh.ipv6h; - protohdr = (u_int32_t *)((char *)ipv6 + IPV6_HDR_LEN); - datalen = (*pskb)->len - IPV6_HDR_LEN; indev = in ? in->name : nulldevname; outdev = out ? out->name : nulldevname; @@ -393,17 +407,19 @@ ip6t_do_table(struct sk_buff **pskb, IP_NF_ASSERT(e); IP_NF_ASSERT(back); (*pskb)->nfcache |= e->nfcache; - if (ip6_packet_match(*pskb, ipv6, indev, outdev, - &e->ipv6, offset)) { + if (ip6_packet_match(*pskb, indev, outdev, &e->ipv6, + &protoff, &offset)) { struct ip6t_entry_target *t; if (IP6T_MATCH_ITERATE(e, do_match, *pskb, in, out, - offset, protohdr, - datalen, &hotdrop) != 0) + offset, protoff, &hotdrop) != 0) goto no_match; - ADD_COUNTER(e->counters, ntohs(ipv6->payload_len) + IPV6_HDR_LEN, 1); + ADD_COUNTER(e->counters, + ntohs((*pskb)->nh.ipv6h->payload_len) + + IPV6_HDR_LEN, + 1); t = ip6t_get_target(e); IP_NF_ASSERT(t->u.kernel.target); @@ -443,8 +459,8 @@ ip6t_do_table(struct sk_buff **pskb, = 0xeeeeeeec; #endif verdict = t->u.kernel.target->target(pskb, - hook, in, out, + hook, t->data, userdata); @@ -459,11 +475,6 @@ ip6t_do_table(struct sk_buff **pskb, ((struct ip6t_entry *)table_base)->comefrom = 0x57acc001; #endif - /* Target might have changed stuff. */ - ipv6 = (*pskb)->nh.ipv6h; - protohdr = (u_int32_t *)((void *)ipv6 + IPV6_HDR_LEN); - datalen = (*pskb)->len - IPV6_HDR_LEN; - if (verdict == IP6T_CONTINUE) e = (void *)e + e->next_offset; else @@ -554,7 +565,7 @@ find_match_lock(const char *name, int *error, struct semaphore *mutex) return find_inlist_lock(&ip6t_match, name, "ip6t_", error, mutex); } -struct ip6t_target * +static struct ip6t_target * ip6t_find_target_lock(const char *name, int *error, struct semaphore *mutex) { return find_inlist_lock(&ip6t_target, name, "ip6t_", error, mutex); @@ -1535,26 +1546,31 @@ port_match(u_int16_t min, u_int16_t max, u_int16_t port, int invert) static int tcp_find_option(u_int8_t option, - const struct tcphdr *tcp, - u_int16_t datalen, + const struct sk_buff *skb, + unsigned int tcpoff, + unsigned int optlen, int invert, int *hotdrop) { - unsigned int i = sizeof(struct tcphdr); - const u_int8_t *opt = (u_int8_t *)tcp; + /* tcp.doff is only 4 bits, ie. max 15 * 4 bytes */ + u_int8_t _opt[60 - sizeof(struct tcphdr)], *op; + unsigned int i; duprintf("tcp_match: finding option\n"); + if (!optlen) + return invert; /* If we don't have the whole header, drop packet. */ - if (tcp->doff * 4 < sizeof(struct tcphdr) || - tcp->doff * 4 > datalen) { + op = skb_header_pointer(skb, tcpoff + sizeof(struct tcphdr), optlen, + _opt); + if (op == NULL) { *hotdrop = 1; return 0; } - while (i < tcp->doff * 4) { - if (opt[i] == option) return !invert; - if (opt[i] < 2) i++; - else i += opt[i+1]?:1; + for (i = 0; i < optlen; ) { + if (op[i] == option) return !invert; + if (op[i] < 2) i++; + else i += op[i+1]?:1; } return invert; @@ -1566,27 +1582,31 @@ tcp_match(const struct sk_buff *skb, const struct net_device *out, const void *matchinfo, int offset, - const void *hdr, - u_int16_t datalen, + unsigned int protoff, int *hotdrop) { - const struct tcphdr *tcp; + struct tcphdr _tcph, *th; const struct ip6t_tcp *tcpinfo = matchinfo; - int tcpoff; - u8 nexthdr = skb->nh.ipv6h->nexthdr; - - /* To quote Alan: - Don't allow a fragment of TCP 8 bytes in. Nobody normal - causes this. Its a cracker trying to break in by doing a - flag overwrite to pass the direction checks. - */ + if (offset) { + /* To quote Alan: - if (offset == 1) { - duprintf("Dropping evil TCP offset=1 frag.\n"); - *hotdrop = 1; + Don't allow a fragment of TCP 8 bytes in. Nobody normal + causes this. Its a cracker trying to break in by doing a + flag overwrite to pass the direction checks. + */ + if (offset == 1) { + duprintf("Dropping evil TCP offset=1 frag.\n"); + *hotdrop = 1; + } + /* Must not be a fragment. */ return 0; - } else if (offset == 0 && datalen < sizeof(struct tcphdr)) { + } + +#define FWINVTCP(bool,invflg) ((bool) ^ !!(tcpinfo->invflags & invflg)) + + th = skb_header_pointer(skb, protoff, sizeof(_tcph), &_tcph); + if (th == NULL) { /* We've been asked to examine this packet, and we can't. Hence, no choice but to drop. */ duprintf("Dropping evil TCP offset=0 tinygram.\n"); @@ -1594,45 +1614,30 @@ tcp_match(const struct sk_buff *skb, return 0; } - tcpoff = (u8*)(skb->nh.ipv6h + 1) - skb->data; - tcpoff = ipv6_skip_exthdr(skb, tcpoff, &nexthdr, skb->len - tcpoff); - if (tcpoff < 0 || tcpoff > skb->len) { - duprintf("tcp_match: cannot skip exthdr. Dropping.\n"); - *hotdrop = 1; + if (!port_match(tcpinfo->spts[0], tcpinfo->spts[1], + ntohs(th->source), + !!(tcpinfo->invflags & IP6T_TCP_INV_SRCPT))) return 0; - } else if (nexthdr == IPPROTO_FRAGMENT) + if (!port_match(tcpinfo->dpts[0], tcpinfo->dpts[1], + ntohs(th->dest), + !!(tcpinfo->invflags & IP6T_TCP_INV_DSTPT))) return 0; - else if (nexthdr != IPPROTO_TCP || - skb->len - tcpoff < sizeof(struct tcphdr)) { - /* cannot be occured */ - duprintf("tcp_match: cannot get TCP header. Dropping.\n"); - *hotdrop = 1; + if (!FWINVTCP((((unsigned char *)th)[13] & tcpinfo->flg_mask) + == tcpinfo->flg_cmp, + IP6T_TCP_INV_FLAGS)) return 0; + if (tcpinfo->option) { + if (th->doff * 4 < sizeof(_tcph)) { + *hotdrop = 1; + return 0; + } + if (!tcp_find_option(tcpinfo->option, skb, protoff, + th->doff*4 - sizeof(*th), + tcpinfo->invflags & IP6T_TCP_INV_OPTION, + hotdrop)) + return 0; } - - tcp = (struct tcphdr *)(skb->data + tcpoff); - - /* FIXME: Try tcp doff >> packet len against various stacks --RR */ - -#define FWINVTCP(bool,invflg) ((bool) ^ !!(tcpinfo->invflags & invflg)) - - /* Must not be a fragment. */ - return !offset - && port_match(tcpinfo->spts[0], tcpinfo->spts[1], - ntohs(tcp->source), - !!(tcpinfo->invflags & IP6T_TCP_INV_SRCPT)) - && port_match(tcpinfo->dpts[0], tcpinfo->dpts[1], - ntohs(tcp->dest), - !!(tcpinfo->invflags & IP6T_TCP_INV_DSTPT)) - && FWINVTCP((((unsigned char *)tcp)[13] - & tcpinfo->flg_mask) - == tcpinfo->flg_cmp, - IP6T_TCP_INV_FLAGS) - && (!tcpinfo->option - || tcp_find_option(tcpinfo->option, tcp, datalen, - tcpinfo->invflags - & IP6T_TCP_INV_OPTION, - hotdrop)); + return 1; } /* Called when user tries to insert an entry of this type. */ @@ -1658,16 +1663,18 @@ udp_match(const struct sk_buff *skb, const struct net_device *out, const void *matchinfo, int offset, - const void *hdr, - u_int16_t datalen, + unsigned int protoff, int *hotdrop) { - const struct udphdr *udp; + struct udphdr _udph, *uh; const struct ip6t_udp *udpinfo = matchinfo; - int udpoff; - u8 nexthdr = skb->nh.ipv6h->nexthdr; - if (offset == 0 && datalen < sizeof(struct udphdr)) { + /* Must not be a fragment. */ + if (offset) + return 0; + + uh = skb_header_pointer(skb, protoff, sizeof(_udph), &_udph); + if (uh == NULL) { /* We've been asked to examine this packet, and we can't. Hence, no choice but to drop. */ duprintf("Dropping evil UDP tinygram.\n"); @@ -1675,30 +1682,11 @@ udp_match(const struct sk_buff *skb, return 0; } - udpoff = (u8*)(skb->nh.ipv6h + 1) - skb->data; - udpoff = ipv6_skip_exthdr(skb, udpoff, &nexthdr, skb->len - udpoff); - if (udpoff < 0 || udpoff > skb->len) { - duprintf("udp_match: cannot skip exthdr. Dropping.\n"); - *hotdrop = 1; - return 0; - } else if (nexthdr == IPPROTO_FRAGMENT) - return 0; - else if (nexthdr != IPPROTO_UDP || - skb->len - udpoff < sizeof(struct udphdr)) { - duprintf("udp_match: cannot get UDP header. Dropping.\n"); - *hotdrop = 1; - return 0; - } - - udp = (struct udphdr *)(skb->data + udpoff); - - /* Must not be a fragment. */ - return !offset - && port_match(udpinfo->spts[0], udpinfo->spts[1], - ntohs(udp->source), - !!(udpinfo->invflags & IP6T_UDP_INV_SRCPT)) + return port_match(udpinfo->spts[0], udpinfo->spts[1], + ntohs(uh->source), + !!(udpinfo->invflags & IP6T_UDP_INV_SRCPT)) && port_match(udpinfo->dpts[0], udpinfo->dpts[1], - ntohs(udp->dest), + ntohs(uh->dest), !!(udpinfo->invflags & IP6T_UDP_INV_DSTPT)); } @@ -1748,14 +1736,18 @@ icmp6_match(const struct sk_buff *skb, const struct net_device *out, const void *matchinfo, int offset, - const void *hdr, - u_int16_t datalen, + unsigned int protoff, int *hotdrop) { - const struct icmp6hdr *icmp = hdr; + struct icmp6hdr _icmp, *ic; const struct ip6t_icmp *icmpinfo = matchinfo; - if (offset == 0 && datalen < 2) { + /* Must not be a fragment. */ + if (offset) + return 0; + + ic = skb_header_pointer(skb, protoff, sizeof(_icmp), &_icmp); + if (ic == NULL) { /* We've been asked to examine this packet, and we can't. Hence, no choice but to drop. */ duprintf("Dropping evil ICMP tinygram.\n"); @@ -1763,13 +1755,11 @@ icmp6_match(const struct sk_buff *skb, return 0; } - /* Must not be a fragment. */ - return !offset - && icmp6_type_code_match(icmpinfo->type, - icmpinfo->code[0], - icmpinfo->code[1], - icmp->icmp6_type, icmp->icmp6_code, - !!(icmpinfo->invflags&IP6T_ICMP_INV)); + return icmp6_type_code_match(icmpinfo->type, + icmpinfo->code[0], + icmpinfo->code[1], + ic->icmp6_type, ic->icmp6_code, + !!(icmpinfo->invflags&IP6T_ICMP_INV)); } /* Called when user tries to insert an entry of this type. */ @@ -1972,7 +1962,6 @@ static void __exit fini(void) EXPORT_SYMBOL(ip6t_register_table); EXPORT_SYMBOL(ip6t_unregister_table); EXPORT_SYMBOL(ip6t_do_table); -EXPORT_SYMBOL(ip6t_find_target_lock); EXPORT_SYMBOL(ip6t_register_match); EXPORT_SYMBOL(ip6t_unregister_match); EXPORT_SYMBOL(ip6t_register_target); diff --git a/net/ipv6/netfilter/ip6t_LOG.c b/net/ipv6/netfilter/ip6t_LOG.c index 0fc6b1750a54..9f5cfdbe26a5 100644 --- a/net/ipv6/netfilter/ip6t_LOG.c +++ b/net/ipv6/netfilter/ip6t_LOG.c @@ -40,120 +40,166 @@ struct in_device; #define DEBUGP(format, args...) #endif -struct esphdr { - __u32 spi; -}; /* FIXME evil kludge */ - /* Use lock to serialize, so printks don't overlap */ static spinlock_t log_lock = SPIN_LOCK_UNLOCKED; -/* takes in current header and pointer to the header */ -/* if another header exists, sets hdrptr to the next header - and returns the new header value, else returns IPPROTO_NONE */ -static u_int8_t ip6_nexthdr(u_int8_t currenthdr, u_int8_t **hdrptr) -{ - u_int8_t hdrlen, nexthdr = IPPROTO_NONE; - - switch(currenthdr){ - case IPPROTO_AH: - /* whoever decided to do the length of AUTH for ipv6 - in 32bit units unlike other headers should be beaten... - repeatedly...with a large stick...no, an even LARGER - stick...no, you're still not thinking big enough */ - nexthdr = **hdrptr; - hdrlen = (*hdrptr)[1] * 4 + 8; - *hdrptr = *hdrptr + hdrlen; - break; - /*stupid rfc2402 */ - case IPPROTO_DSTOPTS: - case IPPROTO_ROUTING: - case IPPROTO_HOPOPTS: - nexthdr = **hdrptr; - hdrlen = (*hdrptr)[1] * 8 + 8; - *hdrptr = *hdrptr + hdrlen; - break; - case IPPROTO_FRAGMENT: - nexthdr = **hdrptr; - *hdrptr = *hdrptr + 8; - break; - } - return nexthdr; -} - /* One level of recursion won't kill us */ static void dump_packet(const struct ip6t_log_info *info, - struct ipv6hdr *ipv6h, int recurse) + const struct sk_buff *skb, unsigned int ip6hoff, + int recurse) { - u_int8_t currenthdr = ipv6h->nexthdr; - u_int8_t *hdrptr; + u_int8_t currenthdr; int fragment; + struct ipv6hdr _ip6h, *ih; + unsigned int ptr; + unsigned int hdrlen = 0; + + ih = skb_header_pointer(skb, ip6hoff, sizeof(_ip6h), &_ip6h); + if (ih == NULL) { + printk("TRUNCATED"); + return; + } /* Max length: 88 "SRC=0000.0000.0000.0000.0000.0000.0000.0000 DST=0000.0000.0000.0000.0000.0000.0000.0000" */ - printk("SRC=%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x ", NIP6(ipv6h->saddr)); - printk("DST=%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x ", NIP6(ipv6h->daddr)); + printk("SRC=%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x ", NIP6(ih->saddr)); + printk("DST=%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x ", NIP6(ih->daddr)); /* Max length: 44 "LEN=65535 TC=255 HOPLIMIT=255 FLOWLBL=FFFFF " */ printk("LEN=%Zu TC=%u HOPLIMIT=%u FLOWLBL=%u ", - ntohs(ipv6h->payload_len) + sizeof(struct ipv6hdr), - (ntohl(*(u_int32_t *)ipv6h) & 0x0ff00000) >> 20, - ipv6h->hop_limit, - (ntohl(*(u_int32_t *)ipv6h) & 0x000fffff)); + ntohs(ih->payload_len) + sizeof(struct ipv6hdr), + (ntohl(*(u_int32_t *)ih) & 0x0ff00000) >> 20, + ih->hop_limit, + (ntohl(*(u_int32_t *)ih) & 0x000fffff)); fragment = 0; - hdrptr = (u_int8_t *)(ipv6h + 1); - while (currenthdr != IPPROTO_NONE) { - if ((currenthdr == IPPROTO_TCP) || - (currenthdr == IPPROTO_UDP) || - (currenthdr == IPPROTO_ICMPV6)) - break; + ptr = ip6hoff + sizeof(struct ipv6hdr); + currenthdr = ih->nexthdr; + while (currenthdr != NEXTHDR_NONE && ip6t_ext_hdr(currenthdr)) { + struct ipv6_opt_hdr _hdr, *hp; + + hp = skb_header_pointer(skb, ptr, sizeof(_hdr), &_hdr); + if (hp == NULL) { + printk("TRUNCATED"); + return; + } + /* Max length: 48 "OPT (...) " */ - printk("OPT ( "); + if (info->logflags & IP6T_LOG_IPOPT) + printk("OPT ( "); + switch (currenthdr) { case IPPROTO_FRAGMENT: { - struct frag_hdr *fhdr = (struct frag_hdr *)hdrptr; + struct frag_hdr _fhdr, *fh; + + printk("FRAG:"); + fh = skb_header_pointer(skb, ptr, sizeof(_fhdr), + &_fhdr); + if (fh == NULL) { + printk("TRUNCATED "); + return; + } - /* Max length: 11 "FRAG:65535 " */ - printk("FRAG:%u ", ntohs(fhdr->frag_off) & 0xFFF8); + /* Max length: 6 "65535 " */ + printk("%u ", ntohs(fh->frag_off) & 0xFFF8); /* Max length: 11 "INCOMPLETE " */ - if (fhdr->frag_off & htons(0x0001)) + if (fh->frag_off & htons(0x0001)) printk("INCOMPLETE "); - printk("ID:%08x ", fhdr->identification); + printk("ID:%08x ", ntohl(fh->identification)); - if (ntohs(fhdr->frag_off) & 0xFFF8) + if (ntohs(fh->frag_off) & 0xFFF8) fragment = 1; + hdrlen = 8; + break; } case IPPROTO_DSTOPTS: case IPPROTO_ROUTING: case IPPROTO_HOPOPTS: + if (fragment) { + if (info->logflags & IP6T_LOG_IPOPT) + printk(")"); + return; + } + hdrlen = ipv6_optlen(hp); break; /* Max Length */ case IPPROTO_AH: + if (info->logflags & IP6T_LOG_IPOPT) { + struct ip_auth_hdr _ahdr, *ah; + + /* Max length: 3 "AH " */ + printk("AH "); + + if (fragment) { + printk(")"); + return; + } + + ah = skb_header_pointer(skb, ptr, sizeof(_ahdr), + &_ahdr); + if (ah == NULL) { + /* + * Max length: 26 "INCOMPLETE [65535 + * bytes] )" + */ + printk("INCOMPLETE [%u bytes] )", + skb->len - ptr); + return; + } + + /* Length: 15 "SPI=0xF1234567 */ + printk("SPI=0x%x ", ntohl(ah->spi)); + + } + + hdrlen = (hp->hdrlen+2)<<2; + break; case IPPROTO_ESP: if (info->logflags & IP6T_LOG_IPOPT) { - struct esphdr *esph = (struct esphdr *)hdrptr; - int esp = (currenthdr == IPPROTO_ESP); + struct ip_esp_hdr _esph, *eh; /* Max length: 4 "ESP " */ - printk("%s ",esp ? "ESP" : "AH"); + printk("ESP "); + + if (fragment) { + printk(")"); + return; + } + + /* + * Max length: 26 "INCOMPLETE [65535 bytes] )" + */ + eh = skb_header_pointer(skb, ptr, sizeof(_esph), + &_esph); + if (eh == NULL) { + printk("INCOMPLETE [%u bytes] )", + skb->len - ptr); + return; + } + + /* Length: 16 "SPI=0xF1234567 )" */ + printk("SPI=0x%x )", ntohl(eh->spi) ); - /* Length: 15 "SPI=0xF1234567 " */ - printk("SPI=0x%x ", ntohl(esph->spi) ); - break; } + return; default: - break; + /* Max length: 20 "Unknown Ext Hdr 255" */ + printk("Unknown Ext Hdr %u", currenthdr); + return; } - printk(") "); - currenthdr = ip6_nexthdr(currenthdr, &hdrptr); + if (info->logflags & IP6T_LOG_IPOPT) + printk(") "); + + currenthdr = hp->nexthdr; + ptr += hdrlen; } switch (currenthdr) { case IPPROTO_TCP: { - struct tcphdr *tcph = (struct tcphdr *)hdrptr; + struct tcphdr _tcph, *th; /* Max length: 10 "PROTO=TCP " */ printk("PROTO=TCP "); @@ -161,51 +207,69 @@ static void dump_packet(const struct ip6t_log_info *info, if (fragment) break; + /* Max length: 25 "INCOMPLETE [65535 bytes] " */ + th = skb_header_pointer(skb, ptr, sizeof(_tcph), &_tcph); + if (th == NULL) { + printk("INCOMPLETE [%u bytes] ", skb->len - ptr); + return; + } + /* Max length: 20 "SPT=65535 DPT=65535 " */ printk("SPT=%u DPT=%u ", - ntohs(tcph->source), ntohs(tcph->dest)); + ntohs(th->source), ntohs(th->dest)); /* Max length: 30 "SEQ=4294967295 ACK=4294967295 " */ if (info->logflags & IP6T_LOG_TCPSEQ) printk("SEQ=%u ACK=%u ", - ntohl(tcph->seq), ntohl(tcph->ack_seq)); + ntohl(th->seq), ntohl(th->ack_seq)); /* Max length: 13 "WINDOW=65535 " */ - printk("WINDOW=%u ", ntohs(tcph->window)); - /* Max length: 9 "RES=0x3F " */ - printk("RES=0x%02x ", (u_int8_t)(ntohl(tcp_flag_word(tcph) & TCP_RESERVED_BITS) >> 22)); + printk("WINDOW=%u ", ntohs(th->window)); + /* Max length: 9 "RES=0x3C " */ + printk("RES=0x%02x ", (u_int8_t)(ntohl(tcp_flag_word(th) & TCP_RESERVED_BITS) >> 22)); /* Max length: 32 "CWR ECE URG ACK PSH RST SYN FIN " */ - if (tcph->cwr) + if (th->cwr) printk("CWR "); - if (tcph->ece) + if (th->ece) printk("ECE "); - if (tcph->urg) + if (th->urg) printk("URG "); - if (tcph->ack) + if (th->ack) printk("ACK "); - if (tcph->psh) + if (th->psh) printk("PSH "); - if (tcph->rst) + if (th->rst) printk("RST "); - if (tcph->syn) + if (th->syn) printk("SYN "); - if (tcph->fin) + if (th->fin) printk("FIN "); /* Max length: 11 "URGP=65535 " */ - printk("URGP=%u ", ntohs(tcph->urg_ptr)); + printk("URGP=%u ", ntohs(th->urg_ptr)); if ((info->logflags & IP6T_LOG_TCPOPT) - && tcph->doff * 4 != sizeof(struct tcphdr)) { + && th->doff * 4 > sizeof(struct tcphdr)) { + u_int8_t _opt[60 - sizeof(struct tcphdr)], *op; unsigned int i; + unsigned int optsize = th->doff * 4 + - sizeof(struct tcphdr); + + op = skb_header_pointer(skb, + ptr + sizeof(struct tcphdr), + optsize, _opt); + if (op == NULL) { + printk("OPT (TRUNCATED)"); + return; + } /* Max length: 127 "OPT (" 15*4*2chars ") " */ printk("OPT ("); - for (i =sizeof(struct tcphdr); i < tcph->doff * 4; i++) - printk("%02X", ((u_int8_t *)tcph)[i]); + for (i =0; i < optsize; i++) + printk("%02X", op[i]); printk(") "); } break; } case IPPROTO_UDP: { - struct udphdr *udph = (struct udphdr *)hdrptr; + struct udphdr _udph, *uh; /* Max length: 10 "PROTO=UDP " */ printk("PROTO=UDP "); @@ -213,14 +277,21 @@ static void dump_packet(const struct ip6t_log_info *info, if (fragment) break; + /* Max length: 25 "INCOMPLETE [65535 bytes] " */ + uh = skb_header_pointer(skb, ptr, sizeof(_udph), &_udph); + if (uh == NULL) { + printk("INCOMPLETE [%u bytes] ", skb->len - ptr); + return; + } + /* Max length: 20 "SPT=65535 DPT=65535 " */ printk("SPT=%u DPT=%u LEN=%u ", - ntohs(udph->source), ntohs(udph->dest), - ntohs(udph->len)); + ntohs(uh->source), ntohs(uh->dest), + ntohs(uh->len)); break; } case IPPROTO_ICMPV6: { - struct icmp6hdr *icmp6h = (struct icmp6hdr *)hdrptr; + struct icmp6hdr _icmp6h, *ic; /* Max length: 13 "PROTO=ICMPv6 " */ printk("PROTO=ICMPv6 "); @@ -228,16 +299,23 @@ static void dump_packet(const struct ip6t_log_info *info, if (fragment) break; + /* Max length: 25 "INCOMPLETE [65535 bytes] " */ + ic = skb_header_pointer(skb, ptr, sizeof(_icmp6h), &_icmp6h); + if (ic == NULL) { + printk("INCOMPLETE [%u bytes] ", skb->len - ptr); + return; + } + /* Max length: 18 "TYPE=255 CODE=255 " */ - printk("TYPE=%u CODE=%u ", icmp6h->icmp6_type, icmp6h->icmp6_code); + printk("TYPE=%u CODE=%u ", ic->icmp6_type, ic->icmp6_code); - switch (icmp6h->icmp6_type) { + switch (ic->icmp6_type) { case ICMPV6_ECHO_REQUEST: case ICMPV6_ECHO_REPLY: /* Max length: 19 "ID=65535 SEQ=65535 " */ printk("ID=%u SEQ=%u ", - ntohs(icmp6h->icmp6_identifier), - ntohs(icmp6h->icmp6_sequence)); + ntohs(ic->icmp6_identifier), + ntohs(ic->icmp6_sequence)); break; case ICMPV6_MGM_QUERY: case ICMPV6_MGM_REPORT: @@ -246,7 +324,7 @@ static void dump_packet(const struct ip6t_log_info *info, case ICMPV6_PARAMPROB: /* Max length: 17 "POINTER=ffffffff " */ - printk("POINTER=%08x ", ntohl(icmp6h->icmp6_pointer)); + printk("POINTER=%08x ", ntohl(ic->icmp6_pointer)); /* Fall through */ case ICMPV6_DEST_UNREACH: case ICMPV6_PKT_TOOBIG: @@ -254,13 +332,14 @@ static void dump_packet(const struct ip6t_log_info *info, /* Max length: 3+maxlen */ if (recurse) { printk("["); - dump_packet(info, (struct ipv6hdr *)(icmp6h + 1), 0); + dump_packet(info, skb, ptr + sizeof(_icmp6h), + 0); printk("] "); } /* Max length: 10 "MTU=65535 " */ - if (icmp6h->icmp6_type == ICMPV6_PKT_TOOBIG) - printk("MTU=%u ", ntohl(icmp6h->icmp6_mtu)); + if (ic->icmp6_type == ICMPV6_PKT_TOOBIG) + printk("MTU=%u ", ntohl(ic->icmp6_mtu)); } break; } @@ -328,16 +407,16 @@ ip6t_log_packet(unsigned int hooknum, printk(" "); } - dump_packet(loginfo, ipv6h, 1); + dump_packet(loginfo, skb, (u8*)skb->nh.ipv6h - skb->data, 1); printk("\n"); spin_unlock_bh(&log_lock); } static unsigned int ip6t_log_target(struct sk_buff **pskb, - unsigned int hooknum, const struct net_device *in, const struct net_device *out, + unsigned int hooknum, const void *targinfo, void *userinfo) { diff --git a/net/ipv6/netfilter/ip6t_MARK.c b/net/ipv6/netfilter/ip6t_MARK.c index ce287d2bef64..d09ceb05013a 100644 --- a/net/ipv6/netfilter/ip6t_MARK.c +++ b/net/ipv6/netfilter/ip6t_MARK.c @@ -20,9 +20,9 @@ MODULE_AUTHOR("Netfilter Core Team <coreteam@netfilter.org>"); static unsigned int target(struct sk_buff **pskb, - unsigned int hooknum, const struct net_device *in, const struct net_device *out, + unsigned int hooknum, const void *targinfo, void *userinfo) { diff --git a/net/ipv6/netfilter/ip6t_ah.c b/net/ipv6/netfilter/ip6t_ah.c index f5b9efd12674..d5b94f142bba 100644 --- a/net/ipv6/netfilter/ip6t_ah.c +++ b/net/ipv6/netfilter/ip6t_ah.c @@ -31,12 +31,12 @@ MODULE_AUTHOR("Andras Kis-Szabo <kisza@sch.bme.hu>"); static inline int spi_match(u_int32_t min, u_int32_t max, u_int32_t spi, int invert) { - int r=0; - DEBUGP("ah spi_match:%c 0x%x <= 0x%x <= 0x%x",invert? '!':' ', - min,spi,max); - r=(spi >= min && spi <= max) ^ invert; - DEBUGP(" result %s\n",r? "PASS\n" : "FAILED\n"); - return r; + int r=0; + DEBUGP("ah spi_match:%c 0x%x <= 0x%x <= 0x%x",invert? '!':' ', + min,spi,max); + r = (spi >= min && spi <= max) ^ invert; + DEBUGP(" result %s\n",r? "PASS\n" : "FAILED\n"); + return r; } static int @@ -45,125 +45,124 @@ match(const struct sk_buff *skb, const struct net_device *out, const void *matchinfo, int offset, - const void *protohdr, - u_int16_t datalen, + unsigned int protoff, int *hotdrop) { - struct ip_auth_hdr *ah = NULL; - const struct ip6t_ah *ahinfo = matchinfo; - unsigned int temp; - int len; - u8 nexthdr; - unsigned int ptr; - unsigned int hdrlen = 0; - - /*DEBUGP("IPv6 AH entered\n");*/ - /* if (opt->auth == 0) return 0; - * It does not filled on output */ - - /* type of the 1st exthdr */ - nexthdr = skb->nh.ipv6h->nexthdr; - /* pointer to the 1st exthdr */ - ptr = sizeof(struct ipv6hdr); - /* available length */ - len = skb->len - ptr; - temp = 0; - - while (ip6t_ext_hdr(nexthdr)) { - struct ipv6_opt_hdr *hdr; - - DEBUGP("ipv6_ah header iteration \n"); - - /* Is there enough space for the next ext header? */ - if (len < (int)sizeof(struct ipv6_opt_hdr)) - return 0; - /* No more exthdr -> evaluate */ - if (nexthdr == NEXTHDR_NONE) { - break; - } - /* ESP -> evaluate */ - if (nexthdr == NEXTHDR_ESP) { - break; - } - - hdr=(struct ipv6_opt_hdr *)skb->data+ptr; - - /* Calculate the header length */ - if (nexthdr == NEXTHDR_FRAGMENT) { - hdrlen = 8; - } else if (nexthdr == NEXTHDR_AUTH) - hdrlen = (hdr->hdrlen+2)<<2; - else - hdrlen = ipv6_optlen(hdr); - - /* AH -> evaluate */ - if (nexthdr == NEXTHDR_AUTH) { - temp |= MASK_AH; - break; - } - - - /* set the flag */ - switch (nexthdr){ - case NEXTHDR_HOP: - case NEXTHDR_ROUTING: - case NEXTHDR_FRAGMENT: - case NEXTHDR_AUTH: - case NEXTHDR_DEST: - break; - default: - DEBUGP("ipv6_ah match: unknown nextheader %u\n",nexthdr); - return 0; - break; - } - - nexthdr = hdr->nexthdr; - len -= hdrlen; - ptr += hdrlen; - if ( ptr > skb->len ) { + struct ip_auth_hdr *ah = NULL, _ah; + const struct ip6t_ah *ahinfo = matchinfo; + unsigned int temp; + int len; + u8 nexthdr; + unsigned int ptr; + unsigned int hdrlen = 0; + + /*DEBUGP("IPv6 AH entered\n");*/ + /* if (opt->auth == 0) return 0; + * It does not filled on output */ + + /* type of the 1st exthdr */ + nexthdr = skb->nh.ipv6h->nexthdr; + /* pointer to the 1st exthdr */ + ptr = sizeof(struct ipv6hdr); + /* available length */ + len = skb->len - ptr; + temp = 0; + + while (ip6t_ext_hdr(nexthdr)) { + struct ipv6_opt_hdr _hdr, *hp; + + DEBUGP("ipv6_ah header iteration \n"); + + /* Is there enough space for the next ext header? */ + if (len < sizeof(struct ipv6_opt_hdr)) + return 0; + /* No more exthdr -> evaluate */ + if (nexthdr == NEXTHDR_NONE) + break; + /* ESP -> evaluate */ + if (nexthdr == NEXTHDR_ESP) + break; + + hp = skb_header_pointer(skb, ptr, sizeof(_hdr), &_hdr); + BUG_ON(hp == NULL); + + /* Calculate the header length */ + if (nexthdr == NEXTHDR_FRAGMENT) + hdrlen = 8; + else if (nexthdr == NEXTHDR_AUTH) + hdrlen = (hp->hdrlen+2)<<2; + else + hdrlen = ipv6_optlen(hp); + + /* AH -> evaluate */ + if (nexthdr == NEXTHDR_AUTH) { + temp |= MASK_AH; + break; + } + + + /* set the flag */ + switch (nexthdr) { + case NEXTHDR_HOP: + case NEXTHDR_ROUTING: + case NEXTHDR_FRAGMENT: + case NEXTHDR_AUTH: + case NEXTHDR_DEST: + break; + default: + DEBUGP("ipv6_ah match: unknown nextheader %u\n",nexthdr); + return 0; + } + + nexthdr = hp->nexthdr; + len -= hdrlen; + ptr += hdrlen; + if (ptr > skb->len) { DEBUGP("ipv6_ah: new pointer too large! \n"); break; } - } - - /* AH header not found */ - if ( temp != MASK_AH ) return 0; - - if (len < (int)sizeof(struct ip_auth_hdr)){ - *hotdrop = 1; - return 0; - } - - ah = (struct ip_auth_hdr *) (skb->data + ptr); - - DEBUGP("IPv6 AH LEN %u %u ", hdrlen, ah->hdrlen); - DEBUGP("RES %04X ", ah->reserved); - DEBUGP("SPI %u %08X\n", ntohl(ah->spi), ntohl(ah->spi)); - - DEBUGP("IPv6 AH spi %02X ", - (spi_match(ahinfo->spis[0], ahinfo->spis[1], - ntohl(ah->spi), - !!(ahinfo->invflags & IP6T_AH_INV_SPI)))); - DEBUGP("len %02X %04X %02X ", - ahinfo->hdrlen, hdrlen, - (!ahinfo->hdrlen || - (ahinfo->hdrlen == hdrlen) ^ - !!(ahinfo->invflags & IP6T_AH_INV_LEN))); - DEBUGP("res %02X %04X %02X\n", - ahinfo->hdrres, ah->reserved, - !(ahinfo->hdrres && ah->reserved)); - - return (ah != NULL) - && - (spi_match(ahinfo->spis[0], ahinfo->spis[1], - ntohl(ah->spi), - !!(ahinfo->invflags & IP6T_AH_INV_SPI))) - && - (!ahinfo->hdrlen || - (ahinfo->hdrlen == hdrlen) ^ - !!(ahinfo->invflags & IP6T_AH_INV_LEN)) - && - !(ahinfo->hdrres && ah->reserved); + } + + /* AH header not found */ + if (temp != MASK_AH) + return 0; + + if (len < sizeof(struct ip_auth_hdr)){ + *hotdrop = 1; + return 0; + } + + ah = skb_header_pointer(skb, ptr, sizeof(_ah), &_ah); + BUG_ON(ah == NULL); + + DEBUGP("IPv6 AH LEN %u %u ", hdrlen, ah->hdrlen); + DEBUGP("RES %04X ", ah->reserved); + DEBUGP("SPI %u %08X\n", ntohl(ah->spi), ntohl(ah->spi)); + + DEBUGP("IPv6 AH spi %02X ", + (spi_match(ahinfo->spis[0], ahinfo->spis[1], + ntohl(ah->spi), + !!(ahinfo->invflags & IP6T_AH_INV_SPI)))); + DEBUGP("len %02X %04X %02X ", + ahinfo->hdrlen, hdrlen, + (!ahinfo->hdrlen || + (ahinfo->hdrlen == hdrlen) ^ + !!(ahinfo->invflags & IP6T_AH_INV_LEN))); + DEBUGP("res %02X %04X %02X\n", + ahinfo->hdrres, ah->reserved, + !(ahinfo->hdrres && ah->reserved)); + + return (ah != NULL) + && + (spi_match(ahinfo->spis[0], ahinfo->spis[1], + ntohl(ah->spi), + !!(ahinfo->invflags & IP6T_AH_INV_SPI))) + && + (!ahinfo->hdrlen || + (ahinfo->hdrlen == hdrlen) ^ + !!(ahinfo->invflags & IP6T_AH_INV_LEN)) + && + !(ahinfo->hdrres && ah->reserved); } /* Called when user tries to insert an entry of this type. */ @@ -174,20 +173,18 @@ checkentry(const char *tablename, unsigned int matchinfosize, unsigned int hook_mask) { - const struct ip6t_ah *ahinfo = matchinfo; - - if (matchinfosize != IP6T_ALIGN(sizeof(struct ip6t_ah))) { - DEBUGP("ip6t_ah: matchsize %u != %u\n", - matchinfosize, IP6T_ALIGN(sizeof(struct ip6t_ah))); - return 0; - } - if (ahinfo->invflags & ~IP6T_AH_INV_MASK) { - DEBUGP("ip6t_ah: unknown flags %X\n", - ahinfo->invflags); - return 0; - } - - return 1; + const struct ip6t_ah *ahinfo = matchinfo; + + if (matchinfosize != IP6T_ALIGN(sizeof(struct ip6t_ah))) { + DEBUGP("ip6t_ah: matchsize %u != %u\n", + matchinfosize, IP6T_ALIGN(sizeof(struct ip6t_ah))); + return 0; + } + if (ahinfo->invflags & ~IP6T_AH_INV_MASK) { + DEBUGP("ip6t_ah: unknown flags %X\n", ahinfo->invflags); + return 0; + } + return 1; } static struct ip6t_match ah_match = { @@ -199,12 +196,12 @@ static struct ip6t_match ah_match = { static int __init init(void) { - return ip6t_register_match(&ah_match); + return ip6t_register_match(&ah_match); } static void __exit cleanup(void) { - ip6t_unregister_match(&ah_match); + ip6t_unregister_match(&ah_match); } module_init(init); diff --git a/net/ipv6/netfilter/ip6t_dst.c b/net/ipv6/netfilter/ip6t_dst.c index 2d385038c663..540925e4a7a8 100644 --- a/net/ipv6/netfilter/ip6t_dst.c +++ b/net/ipv6/netfilter/ip6t_dst.c @@ -7,7 +7,6 @@ * published by the Free Software Foundation. */ - #include <linux/module.h> #include <linux/skbuff.h> #include <linux/ipv6.h> @@ -20,8 +19,6 @@ #include <linux/netfilter_ipv6/ip6_tables.h> #include <linux/netfilter_ipv6/ip6t_opts.h> -#define LOW(n) (n & 0x00FF) - #define HOPBYHOP 0 MODULE_LICENSE("GPL"); @@ -48,8 +45,8 @@ MODULE_AUTHOR("Andras Kis-Szabo <kisza@sch.bme.hu>"); * 0 -> invariant * 1 -> can change the routing * (Type & 0x1F) Type - * 0 -> PAD0 (only 1 byte!) - * 1 -> PAD1 LENGTH info (total length = length + 2) + * 0 -> Pad1 (only 1 byte!) + * 1 -> PadN LENGTH info (total length = length + 2) * C0 | 2 -> JUMBO 4 x x x x ( xxxx > 64k ) * 5 -> RTALERT 2 x x */ @@ -60,11 +57,10 @@ match(const struct sk_buff *skb, const struct net_device *out, const void *matchinfo, int offset, - const void *protohdr, - u_int16_t datalen, + unsigned int protoff, int *hotdrop) { - struct ipv6_opt_hdr *optsh = NULL; + struct ipv6_opt_hdr _optsh, *oh; const struct ip6t_opts *optinfo = matchinfo; unsigned int temp; unsigned int len; @@ -72,7 +68,9 @@ match(const struct sk_buff *skb, unsigned int ptr; unsigned int hdrlen = 0; unsigned int ret = 0; - u_int16_t *optdesc = NULL; + u8 _opttype, *tp = NULL; + u8 _optlen, *lp = NULL; + unsigned int optlen; /* type of the 1st exthdr */ nexthdr = skb->nh.ipv6h->nexthdr; @@ -83,7 +81,7 @@ match(const struct sk_buff *skb, temp = 0; while (ip6t_ext_hdr(nexthdr)) { - struct ipv6_opt_hdr *hdr; + struct ipv6_opt_hdr _hdr, *hp; DEBUGP("ipv6_opts header iteration \n"); @@ -99,15 +97,16 @@ match(const struct sk_buff *skb, break; } - hdr=(void *)(skb->data)+ptr; + hp = skb_header_pointer(skb, ptr, sizeof(_hdr), &_hdr); + BUG_ON(hp == NULL); /* Calculate the header length */ if (nexthdr == NEXTHDR_FRAGMENT) { hdrlen = 8; } else if (nexthdr == NEXTHDR_AUTH) - hdrlen = (hdr->hdrlen+2)<<2; + hdrlen = (hp->hdrlen+2)<<2; else - hdrlen = ipv6_optlen(hdr); + hdrlen = ipv6_optlen(hp); /* OPTS -> evaluate */ #if HOPBYHOP @@ -135,7 +134,7 @@ match(const struct sk_buff *skb, break; } - nexthdr = hdr->nexthdr; + nexthdr = hp->nexthdr; len -= hdrlen; ptr += hdrlen; if ( ptr > skb->len ) { @@ -161,9 +160,10 @@ match(const struct sk_buff *skb, return 0; } - optsh=(void *)(skb->data)+ptr; + oh = skb_header_pointer(skb, ptr, sizeof(_optsh), &_optsh); + BUG_ON(oh == NULL); - DEBUGP("IPv6 OPTS LEN %u %u ", hdrlen, optsh->hdrlen); + DEBUGP("IPv6 OPTS LEN %u %u ", hdrlen, oh->hdrlen); DEBUGP("len %02X %04X %02X ", optinfo->hdrlen, hdrlen, @@ -171,13 +171,12 @@ match(const struct sk_buff *skb, ((optinfo->hdrlen == hdrlen) ^ !!(optinfo->invflags & IP6T_OPTS_INV_LEN)))); - ret = (optsh != NULL) + ret = (oh != NULL) && (!(optinfo->flags & IP6T_OPTS_LEN) || ((optinfo->hdrlen == hdrlen) ^ !!(optinfo->invflags & IP6T_OPTS_INV_LEN))); - temp = len = 0; ptr += 2; hdrlen -= 2; if ( !(optinfo->flags & IP6T_OPTS_OPTS) ){ @@ -188,48 +187,59 @@ match(const struct sk_buff *skb, DEBUGP("Strict "); DEBUGP("#%d ",optinfo->optsnr); for(temp=0; temp<optinfo->optsnr; temp++){ - optdesc = (void *)(skb->data)+ptr; + /* type field exists ? */ + if (hdrlen < 1) + break; + tp = skb_header_pointer(skb, ptr, sizeof(_opttype), + &_opttype); + if (tp == NULL) + break; + /* Type check */ - if ( (unsigned char)*optdesc != - (optinfo->opts[temp] & 0xFF00)>>8 ){ + if (*tp != (optinfo->opts[temp] & 0xFF00)>>8){ DEBUGP("Tbad %02X %02X\n", - (unsigned char)*optdesc, - (optinfo->opts[temp] & - 0xFF00)>>8); + *tp, + (optinfo->opts[temp] & 0xFF00)>>8); return 0; } else { DEBUGP("Tok "); } /* Length check */ - if (((optinfo->opts[temp] & 0x00FF) != 0xFF) && - (unsigned char)*optdesc != 0){ - if ( ntohs((u16)*optdesc) != - optinfo->opts[temp] ){ - DEBUGP("Lbad %02X %04X %04X\n", - (unsigned char)*optdesc, - ntohs((u16)*optdesc), - optinfo->opts[temp]); + if (*tp) { + u16 spec_len; + + /* length field exists ? */ + if (hdrlen < 2) + break; + lp = skb_header_pointer(skb, ptr + 1, + sizeof(_optlen), + &_optlen); + if (lp == NULL) + break; + spec_len = optinfo->opts[temp] & 0x00FF; + + if (spec_len != 0x00FF && spec_len != *lp) { + DEBUGP("Lbad %02X %04X\n", *lp, + spec_len); return 0; - } else { - DEBUGP("Lok "); } - } - /* Step to the next */ - if ((unsigned char)*optdesc == 0){ - DEBUGP("PAD0 \n"); - ptr++; - hdrlen--; + DEBUGP("Lok "); + optlen = *lp + 2; } else { - ptr += LOW(ntohs(*optdesc)); - hdrlen -= LOW(ntohs(*optdesc)); - DEBUGP("len%04X \n", - LOW(ntohs(*optdesc))); + DEBUGP("Pad1\n"); + optlen = 1; } - if (ptr > skb->len || ( !hdrlen && - (temp != optinfo->optsnr - 1))) { + + /* Step to the next */ + DEBUGP("len%04X \n", optlen); + + if ((ptr > skb->len - optlen || hdrlen < optlen) && + (temp < optinfo->optsnr - 1)) { DEBUGP("new pointer is too large! \n"); break; } + ptr += optlen; + hdrlen -= optlen; } if (temp == optinfo->optsnr) return ret; @@ -271,6 +281,7 @@ static struct ip6t_match opts_match = { #endif .match = &match, .checkentry = &checkentry, + .me = THIS_MODULE, }; static int __init init(void) diff --git a/net/ipv6/netfilter/ip6t_esp.c b/net/ipv6/netfilter/ip6t_esp.c index ecdd48bba911..e39dd236fd8e 100644 --- a/net/ipv6/netfilter/ip6t_esp.c +++ b/net/ipv6/netfilter/ip6t_esp.c @@ -32,8 +32,8 @@ static inline int spi_match(u_int32_t min, u_int32_t max, u_int32_t spi, int invert) { int r=0; - DEBUGP("esp spi_match:%c 0x%x <= 0x%x <= 0x%x",invert? '!':' ', - min,spi,max); + DEBUGP("esp spi_match:%c 0x%x <= 0x%x <= 0x%x",invert? '!':' ', + min,spi,max); r=(spi >= min && spi <= max) ^ invert; DEBUGP(" result %s\n",r? "PASS\n" : "FAILED\n"); return r; @@ -45,11 +45,10 @@ match(const struct sk_buff *skb, const struct net_device *out, const void *matchinfo, int offset, - const void *protohdr, - u_int16_t datalen, + unsigned int protoff, int *hotdrop) { - struct ip_esp_hdr *esp = NULL; + struct ip_esp_hdr _esp, *eh = NULL; const struct ip6t_esp *espinfo = matchinfo; unsigned int temp; int len; @@ -67,73 +66,74 @@ match(const struct sk_buff *skb, len = skb->len - ptr; temp = 0; - while (ip6t_ext_hdr(nexthdr)) { - struct ipv6_opt_hdr *hdr; - int hdrlen; + while (ip6t_ext_hdr(nexthdr)) { + struct ipv6_opt_hdr _hdr, *hp; + int hdrlen; DEBUGP("ipv6_esp header iteration \n"); /* Is there enough space for the next ext header? */ - if (len < (int)sizeof(struct ipv6_opt_hdr)) - return 0; + if (len < sizeof(struct ipv6_opt_hdr)) + return 0; /* No more exthdr -> evaluate */ - if (nexthdr == NEXTHDR_NONE) { + if (nexthdr == NEXTHDR_NONE) break; - } /* ESP -> evaluate */ - if (nexthdr == NEXTHDR_ESP) { + if (nexthdr == NEXTHDR_ESP) { temp |= MASK_ESP; break; } - hdr=(struct ipv6_opt_hdr *)skb->data+ptr; + hp = skb_header_pointer(skb, ptr, sizeof(_hdr), &_hdr); + BUG_ON(hp == NULL); /* Calculate the header length */ - if (nexthdr == NEXTHDR_FRAGMENT) { - hdrlen = 8; - } else if (nexthdr == NEXTHDR_AUTH) - hdrlen = (hdr->hdrlen+2)<<2; - else - hdrlen = ipv6_optlen(hdr); + if (nexthdr == NEXTHDR_FRAGMENT) + hdrlen = 8; + else if (nexthdr == NEXTHDR_AUTH) + hdrlen = (hp->hdrlen+2)<<2; + else + hdrlen = ipv6_optlen(hp); /* set the flag */ - switch (nexthdr){ - case NEXTHDR_HOP: - case NEXTHDR_ROUTING: - case NEXTHDR_FRAGMENT: - case NEXTHDR_AUTH: - case NEXTHDR_DEST: - break; - default: - DEBUGP("ipv6_esp match: unknown nextheader %u\n",nexthdr); - return 0; - break; + switch (nexthdr) { + case NEXTHDR_HOP: + case NEXTHDR_ROUTING: + case NEXTHDR_FRAGMENT: + case NEXTHDR_AUTH: + case NEXTHDR_DEST: + break; + default: + DEBUGP("ipv6_esp match: unknown nextheader %u\n",nexthdr); + return 0; } - nexthdr = hdr->nexthdr; - len -= hdrlen; - ptr += hdrlen; - if ( ptr > skb->len ) { + nexthdr = hp->nexthdr; + len -= hdrlen; + ptr += hdrlen; + if (ptr > skb->len) { DEBUGP("ipv6_esp: new pointer too large! \n"); break; } - } + } /* ESP header not found */ - if ( temp != MASK_ESP ) return 0; + if (temp != MASK_ESP) + return 0; - if (len < (int)sizeof(struct ip_esp_hdr)){ - *hotdrop = 1; - return 0; - } + if (len < sizeof(struct ip_esp_hdr)) { + *hotdrop = 1; + return 0; + } - esp = (struct ip_esp_hdr *) (skb->data + ptr); + eh = skb_header_pointer(skb, ptr, sizeof(_esp), &_esp); + BUG_ON(eh == NULL); - DEBUGP("IPv6 ESP SPI %u %08X\n", ntohl(esp->spi), ntohl(esp->spi)); + DEBUGP("IPv6 ESP SPI %u %08X\n", ntohl(eh->spi), ntohl(eh->spi)); - return (esp != NULL) + return (eh != NULL) && spi_match(espinfo->spis[0], espinfo->spis[1], - ntohl(esp->spi), + ntohl(eh->spi), !!(espinfo->invflags & IP6T_ESP_INV_SPI)); } @@ -157,7 +157,6 @@ checkentry(const char *tablename, espinfo->invflags); return 0; } - return 1; } diff --git a/net/ipv6/netfilter/ip6t_eui64.c b/net/ipv6/netfilter/ip6t_eui64.c index 3b1340d26b5e..6d1c4e87effc 100644 --- a/net/ipv6/netfilter/ip6t_eui64.c +++ b/net/ipv6/netfilter/ip6t_eui64.c @@ -24,8 +24,7 @@ match(const struct sk_buff *skb, const struct net_device *out, const void *matchinfo, int offset, - const void *hdr, - u_int16_t datalen, + unsigned int protoff, int *hotdrop) { diff --git a/net/ipv6/netfilter/ip6t_frag.c b/net/ipv6/netfilter/ip6t_frag.c index 3496166b75e3..4bfa30a9bc80 100644 --- a/net/ipv6/netfilter/ip6t_frag.c +++ b/net/ipv6/netfilter/ip6t_frag.c @@ -45,11 +45,10 @@ match(const struct sk_buff *skb, const struct net_device *out, const void *matchinfo, int offset, - const void *protohdr, - u_int16_t datalen, + unsigned int protoff, int *hotdrop) { - struct frag_hdr *frag = NULL; + struct frag_hdr _frag, *fh = NULL; const struct ip6t_frag *fraginfo = matchinfo; unsigned int temp; int len; @@ -66,7 +65,7 @@ match(const struct sk_buff *skb, temp = 0; while (ip6t_ext_hdr(nexthdr)) { - struct ipv6_opt_hdr *hdr; + struct ipv6_opt_hdr _hdr, *hp; DEBUGP("ipv6_frag header iteration \n"); @@ -82,15 +81,16 @@ match(const struct sk_buff *skb, break; } - hdr=(struct ipv6_opt_hdr *)(skb->data+ptr); + hp = skb_header_pointer(skb, ptr, sizeof(_hdr), &_hdr); + BUG_ON(hp == NULL); /* Calculate the header length */ if (nexthdr == NEXTHDR_FRAGMENT) { hdrlen = 8; } else if (nexthdr == NEXTHDR_AUTH) - hdrlen = (hdr->hdrlen+2)<<2; + hdrlen = (hp->hdrlen+2)<<2; else - hdrlen = ipv6_optlen(hdr); + hdrlen = ipv6_optlen(hp); /* FRAG -> evaluate */ if (nexthdr == NEXTHDR_FRAGMENT) { @@ -113,7 +113,7 @@ match(const struct sk_buff *skb, break; } - nexthdr = hdr->nexthdr; + nexthdr = hp->nexthdr; len -= hdrlen; ptr += hdrlen; if ( ptr > skb->len ) { @@ -130,57 +130,58 @@ match(const struct sk_buff *skb, return 0; } - frag = (struct frag_hdr *) (skb->data + ptr); + fh = skb_header_pointer(skb, ptr, sizeof(_frag), &_frag); + BUG_ON(fh == NULL); - DEBUGP("INFO %04X ", frag->frag_off); - DEBUGP("OFFSET %04X ", ntohs(frag->frag_off) & ~0x7); - DEBUGP("RES %02X %04X", frag->reserved, ntohs(frag->frag_off) & 0x6); - DEBUGP("MF %04X ", frag->frag_off & htons(IP6_MF)); - DEBUGP("ID %u %08X\n", ntohl(frag->identification), - ntohl(frag->identification)); + DEBUGP("INFO %04X ", fh->frag_off); + DEBUGP("OFFSET %04X ", ntohs(fh->frag_off) & ~0x7); + DEBUGP("RES %02X %04X", fh->reserved, ntohs(fh->frag_off) & 0x6); + DEBUGP("MF %04X ", fh->frag_off & htons(IP6_MF)); + DEBUGP("ID %u %08X\n", ntohl(fh->identification), + ntohl(fh->identification)); DEBUGP("IPv6 FRAG id %02X ", (id_match(fraginfo->ids[0], fraginfo->ids[1], - ntohl(frag->identification), + ntohl(fh->identification), !!(fraginfo->invflags & IP6T_FRAG_INV_IDS)))); DEBUGP("res %02X %02X%04X %02X ", - (fraginfo->flags & IP6T_FRAG_RES), frag->reserved, - ntohs(frag->frag_off) & 0x6, + (fraginfo->flags & IP6T_FRAG_RES), fh->reserved, + ntohs(fh->frag_off) & 0x6, !((fraginfo->flags & IP6T_FRAG_RES) - && (frag->reserved || (ntohs(frag->frag_off) & 0x6)))); + && (fh->reserved || (ntohs(fh->frag_off) & 0x06)))); DEBUGP("first %02X %02X %02X ", (fraginfo->flags & IP6T_FRAG_FST), - ntohs(frag->frag_off) & ~0x7, + ntohs(fh->frag_off) & ~0x7, !((fraginfo->flags & IP6T_FRAG_FST) - && (ntohs(frag->frag_off) & ~0x7))); + && (ntohs(fh->frag_off) & ~0x7))); DEBUGP("mf %02X %02X %02X ", (fraginfo->flags & IP6T_FRAG_MF), - ntohs(frag->frag_off) & IP6_MF, + ntohs(fh->frag_off) & IP6_MF, !((fraginfo->flags & IP6T_FRAG_MF) - && !((ntohs(frag->frag_off) & IP6_MF)))); + && !((ntohs(fh->frag_off) & IP6_MF)))); DEBUGP("last %02X %02X %02X\n", (fraginfo->flags & IP6T_FRAG_NMF), - ntohs(frag->frag_off) & IP6_MF, + ntohs(fh->frag_off) & IP6_MF, !((fraginfo->flags & IP6T_FRAG_NMF) - && (ntohs(frag->frag_off) & IP6_MF))); + && (ntohs(fh->frag_off) & IP6_MF))); - return (frag != NULL) + return (fh != NULL) && (id_match(fraginfo->ids[0], fraginfo->ids[1], - ntohl(frag->identification), + ntohl(fh->identification), !!(fraginfo->invflags & IP6T_FRAG_INV_IDS))) && !((fraginfo->flags & IP6T_FRAG_RES) - && (frag->reserved || (ntohs(frag->frag_off) & 0x6))) + && (fh->reserved || (ntohs(fh->frag_off) & 0x6))) && !((fraginfo->flags & IP6T_FRAG_FST) - && (ntohs(frag->frag_off) & ~0x7)) + && (ntohs(fh->frag_off) & ~0x7)) && !((fraginfo->flags & IP6T_FRAG_MF) - && !(ntohs(frag->frag_off) & IP6_MF)) + && !(ntohs(fh->frag_off) & IP6_MF)) && !((fraginfo->flags & IP6T_FRAG_NMF) - && (ntohs(frag->frag_off) & IP6_MF)); + && (ntohs(fh->frag_off) & IP6_MF)); } /* Called when user tries to insert an entry of this type. */ diff --git a/net/ipv6/netfilter/ip6t_hbh.c b/net/ipv6/netfilter/ip6t_hbh.c index 6849122c37e9..27f3650d127e 100644 --- a/net/ipv6/netfilter/ip6t_hbh.c +++ b/net/ipv6/netfilter/ip6t_hbh.c @@ -19,8 +19,6 @@ #include <linux/netfilter_ipv6/ip6_tables.h> #include <linux/netfilter_ipv6/ip6t_opts.h> -#define LOW(n) (n & 0x00FF) - #define HOPBYHOP 1 MODULE_LICENSE("GPL"); @@ -47,8 +45,8 @@ MODULE_AUTHOR("Andras Kis-Szabo <kisza@sch.bme.hu>"); * 0 -> invariant * 1 -> can change the routing * (Type & 0x1F) Type - * 0 -> PAD0 (only 1 byte!) - * 1 -> PAD1 LENGTH info (total length = length + 2) + * 0 -> Pad1 (only 1 byte!) + * 1 -> PadN LENGTH info (total length = length + 2) * C0 | 2 -> JUMBO 4 x x x x ( xxxx > 64k ) * 5 -> RTALERT 2 x x */ @@ -59,11 +57,10 @@ match(const struct sk_buff *skb, const struct net_device *out, const void *matchinfo, int offset, - const void *protohdr, - u_int16_t datalen, + unsigned int protoff, int *hotdrop) { - struct ipv6_opt_hdr *optsh = NULL; + struct ipv6_opt_hdr _optsh, *oh; const struct ip6t_opts *optinfo = matchinfo; unsigned int temp; unsigned int len; @@ -71,7 +68,9 @@ match(const struct sk_buff *skb, unsigned int ptr; unsigned int hdrlen = 0; unsigned int ret = 0; - u_int16_t *optdesc = NULL; + u8 _opttype, *tp = NULL; + u8 _optlen, *lp = NULL; + unsigned int optlen; /* type of the 1st exthdr */ nexthdr = skb->nh.ipv6h->nexthdr; @@ -82,7 +81,7 @@ match(const struct sk_buff *skb, temp = 0; while (ip6t_ext_hdr(nexthdr)) { - struct ipv6_opt_hdr *hdr; + struct ipv6_opt_hdr _hdr, *hp; DEBUGP("ipv6_opts header iteration \n"); @@ -98,15 +97,16 @@ match(const struct sk_buff *skb, break; } - hdr=(void *)(skb->data)+ptr; + hp = skb_header_pointer(skb, ptr, sizeof(_hdr), &_hdr); + BUG_ON(hp == NULL); /* Calculate the header length */ if (nexthdr == NEXTHDR_FRAGMENT) { hdrlen = 8; } else if (nexthdr == NEXTHDR_AUTH) - hdrlen = (hdr->hdrlen+2)<<2; + hdrlen = (hp->hdrlen+2)<<2; else - hdrlen = ipv6_optlen(hdr); + hdrlen = ipv6_optlen(hp); /* OPTS -> evaluate */ #if HOPBYHOP @@ -134,7 +134,7 @@ match(const struct sk_buff *skb, break; } - nexthdr = hdr->nexthdr; + nexthdr = hp->nexthdr; len -= hdrlen; ptr += hdrlen; if ( ptr > skb->len ) { @@ -160,9 +160,10 @@ match(const struct sk_buff *skb, return 0; } - optsh=(void *)(skb->data)+ptr; + oh = skb_header_pointer(skb, ptr, sizeof(_optsh), &_optsh); + BUG_ON(oh == NULL); - DEBUGP("IPv6 OPTS LEN %u %u ", hdrlen, optsh->hdrlen); + DEBUGP("IPv6 OPTS LEN %u %u ", hdrlen, oh->hdrlen); DEBUGP("len %02X %04X %02X ", optinfo->hdrlen, hdrlen, @@ -170,13 +171,12 @@ match(const struct sk_buff *skb, ((optinfo->hdrlen == hdrlen) ^ !!(optinfo->invflags & IP6T_OPTS_INV_LEN)))); - ret = (optsh != NULL) + ret = (oh != NULL) && (!(optinfo->flags & IP6T_OPTS_LEN) || ((optinfo->hdrlen == hdrlen) ^ !!(optinfo->invflags & IP6T_OPTS_INV_LEN))); - temp = len = 0; ptr += 2; hdrlen -= 2; if ( !(optinfo->flags & IP6T_OPTS_OPTS) ){ @@ -187,48 +187,59 @@ match(const struct sk_buff *skb, DEBUGP("Strict "); DEBUGP("#%d ",optinfo->optsnr); for(temp=0; temp<optinfo->optsnr; temp++){ - optdesc = (void *)(skb->data)+ptr; + /* type field exists ? */ + if (hdrlen < 1) + break; + tp = skb_header_pointer(skb, ptr, sizeof(_opttype), + &_opttype); + if (tp == NULL) + break; + /* Type check */ - if ( (unsigned char)*optdesc != - (optinfo->opts[temp] & 0xFF00)>>8 ){ + if (*tp != (optinfo->opts[temp] & 0xFF00)>>8){ DEBUGP("Tbad %02X %02X\n", - (unsigned char)*optdesc, - (optinfo->opts[temp] & - 0xFF00)>>8); + *tp, + (optinfo->opts[temp] & 0xFF00)>>8); return 0; } else { DEBUGP("Tok "); } /* Length check */ - if (((optinfo->opts[temp] & 0x00FF) != 0xFF) && - (unsigned char)*optdesc != 0){ - if ( ntohs((u16)*optdesc) != - optinfo->opts[temp] ){ - DEBUGP("Lbad %02X %04X %04X\n", - (unsigned char)*optdesc, - ntohs((u16)*optdesc), - optinfo->opts[temp]); + if (*tp) { + u16 spec_len; + + /* length field exists ? */ + if (hdrlen < 2) + break; + lp = skb_header_pointer(skb, ptr + 1, + sizeof(_optlen), + &_optlen); + if (lp == NULL) + break; + spec_len = optinfo->opts[temp] & 0x00FF; + + if (spec_len != 0x00FF && spec_len != *lp) { + DEBUGP("Lbad %02X %04X\n", *lp, + spec_len); return 0; - } else { - DEBUGP("Lok "); } - } - /* Step to the next */ - if ((unsigned char)*optdesc == 0){ - DEBUGP("PAD0 \n"); - ptr++; - hdrlen--; + DEBUGP("Lok "); + optlen = *lp + 2; } else { - ptr += LOW(ntohs(*optdesc)); - hdrlen -= LOW(ntohs(*optdesc)); - DEBUGP("len%04X \n", - LOW(ntohs(*optdesc))); + DEBUGP("Pad1\n"); + optlen = 1; } - if (ptr > skb->len || ( !hdrlen && - (temp != optinfo->optsnr - 1))) { + + /* Step to the next */ + DEBUGP("len%04X \n", optlen); + + if ((ptr > skb->len - optlen || hdrlen < optlen) && + (temp < optinfo->optsnr - 1)) { DEBUGP("new pointer is too large! \n"); break; } + ptr += optlen; + hdrlen -= optlen; } if (temp == optinfo->optsnr) return ret; diff --git a/net/ipv6/netfilter/ip6t_hl.c b/net/ipv6/netfilter/ip6t_hl.c index e538f14bb394..0beaff5471dd 100644 --- a/net/ipv6/netfilter/ip6t_hl.c +++ b/net/ipv6/netfilter/ip6t_hl.c @@ -20,7 +20,7 @@ MODULE_LICENSE("GPL"); static int match(const struct sk_buff *skb, const struct net_device *in, const struct net_device *out, const void *matchinfo, - int offset, const void *hdr, u_int16_t datalen, + int offset, unsigned int protoff, int *hotdrop) { const struct ip6t_hl_info *info = matchinfo; diff --git a/net/ipv6/netfilter/ip6t_ipv6header.c b/net/ipv6/netfilter/ip6t_ipv6header.c index ae5d1c6c8002..b145beb0036e 100644 --- a/net/ipv6/netfilter/ip6t_ipv6header.c +++ b/net/ipv6/netfilter/ip6t_ipv6header.c @@ -31,8 +31,7 @@ ipv6header_match(const struct sk_buff *skb, const struct net_device *out, const void *matchinfo, int offset, - const void *protohdr, - u_int16_t datalen, + unsigned int protoff, int *hotdrop) { const struct ip6t_ipv6header_info *info = matchinfo; diff --git a/net/ipv6/netfilter/ip6t_length.c b/net/ipv6/netfilter/ip6t_length.c index 5a86722b1f0d..e0537d3811d5 100644 --- a/net/ipv6/netfilter/ip6t_length.c +++ b/net/ipv6/netfilter/ip6t_length.c @@ -23,8 +23,7 @@ match(const struct sk_buff *skb, const struct net_device *out, const void *matchinfo, int offset, - const void *hdr, - u_int16_t datalen, + unsigned int protoff, int *hotdrop) { const struct ip6t_length_info *info = matchinfo; diff --git a/net/ipv6/netfilter/ip6t_limit.c b/net/ipv6/netfilter/ip6t_limit.c index 4780c3a9a9db..a462b771066a 100644 --- a/net/ipv6/netfilter/ip6t_limit.c +++ b/net/ipv6/netfilter/ip6t_limit.c @@ -57,8 +57,7 @@ ip6t_limit_match(const struct sk_buff *skb, const struct net_device *out, const void *matchinfo, int offset, - const void *hdr, - u_int16_t datalen, + unsigned int protoff, int *hotdrop) { struct ip6t_rateinfo *r = ((struct ip6t_rateinfo *)matchinfo)->master; diff --git a/net/ipv6/netfilter/ip6t_mac.c b/net/ipv6/netfilter/ip6t_mac.c index ea874dd241dd..526d43e37234 100644 --- a/net/ipv6/netfilter/ip6t_mac.c +++ b/net/ipv6/netfilter/ip6t_mac.c @@ -25,8 +25,7 @@ match(const struct sk_buff *skb, const struct net_device *out, const void *matchinfo, int offset, - const void *hdr, - u_int16_t datalen, + unsigned int protoff, int *hotdrop) { const struct ip6t_mac_info *info = matchinfo; diff --git a/net/ipv6/netfilter/ip6t_mark.c b/net/ipv6/netfilter/ip6t_mark.c index dc8484eee289..affc3de364fc 100644 --- a/net/ipv6/netfilter/ip6t_mark.c +++ b/net/ipv6/netfilter/ip6t_mark.c @@ -24,8 +24,7 @@ match(const struct sk_buff *skb, const struct net_device *out, const void *matchinfo, int offset, - const void *hdr, - u_int16_t datalen, + unsigned int protoff, int *hotdrop) { const struct ip6t_mark_info *info = matchinfo; diff --git a/net/ipv6/netfilter/ip6t_multiport.c b/net/ipv6/netfilter/ip6t_multiport.c index 94c4dc3a957a..6e3246153fa3 100644 --- a/net/ipv6/netfilter/ip6t_multiport.c +++ b/net/ipv6/netfilter/ip6t_multiport.c @@ -53,28 +53,32 @@ match(const struct sk_buff *skb, const struct net_device *out, const void *matchinfo, int offset, - const void *hdr, - u_int16_t datalen, + unsigned int protoff, int *hotdrop) { - const struct udphdr *udp = hdr; + u16 _ports[2], *pptr; const struct ip6t_multiport *multiinfo = matchinfo; - /* Must be big enough to read ports. */ - if (offset == 0 && datalen < sizeof(struct udphdr)) { + /* Must not be a fragment. */ + if (offset) + return 0; + + /* Must be big enough to read ports (both UDP and TCP have + them at the start). */ + pptr = skb_header_pointer(skb, protoff, sizeof(_ports), &_ports[0]); + if (pptr == NULL) { /* We've been asked to examine this packet, and we - can't. Hence, no choice but to drop. */ - duprintf("ip6t_multiport:" - " Dropping evil offset=0 tinygram.\n"); - *hotdrop = 1; - return 0; + * can't. Hence, no choice but to drop. + */ + duprintf("ip6t_multiport:" + " Dropping evil offset=0 tinygram.\n"); + *hotdrop = 1; + return 0; } - /* Must not be a fragment. */ - return !offset - && ports_match(multiinfo->ports, - multiinfo->flags, multiinfo->count, - ntohs(udp->source), ntohs(udp->dest)); + return ports_match(multiinfo->ports, + multiinfo->flags, multiinfo->count, + ntohs(pptr[0]), ntohs(pptr[1])); } /* Called when user tries to insert an entry of this type. */ diff --git a/net/ipv6/netfilter/ip6t_owner.c b/net/ipv6/netfilter/ip6t_owner.c index 272257b3b637..ab0e32d3de46 100644 --- a/net/ipv6/netfilter/ip6t_owner.c +++ b/net/ipv6/netfilter/ip6t_owner.c @@ -92,8 +92,7 @@ match(const struct sk_buff *skb, const struct net_device *out, const void *matchinfo, int offset, - const void *hdr, - u_int16_t datalen, + unsigned int protoff, int *hotdrop) { const struct ip6t_owner_info *info = matchinfo; diff --git a/net/ipv6/netfilter/ip6t_physdev.c b/net/ipv6/netfilter/ip6t_physdev.c index f4eebb43d219..71515c86ece1 100644 --- a/net/ipv6/netfilter/ip6t_physdev.c +++ b/net/ipv6/netfilter/ip6t_physdev.c @@ -26,8 +26,7 @@ match(const struct sk_buff *skb, const struct net_device *out, const void *matchinfo, int offset, - const void *hdr, - u_int16_t datalen, + unsigned int protoff, int *hotdrop) { int i; diff --git a/net/ipv6/netfilter/ip6t_rt.c b/net/ipv6/netfilter/ip6t_rt.c index 4a7aae3a73c6..b5adc1057a9b 100644 --- a/net/ipv6/netfilter/ip6t_rt.c +++ b/net/ipv6/netfilter/ip6t_rt.c @@ -47,11 +47,10 @@ match(const struct sk_buff *skb, const struct net_device *out, const void *matchinfo, int offset, - const void *protohdr, - u_int16_t datalen, + unsigned int protoff, int *hotdrop) { - struct ipv6_rt_hdr *route = NULL; + struct ipv6_rt_hdr _route, *rh = NULL; const struct ip6t_rt *rtinfo = matchinfo; unsigned int temp; unsigned int len; @@ -59,6 +58,7 @@ match(const struct sk_buff *skb, unsigned int ptr; unsigned int hdrlen = 0; unsigned int ret = 0; + struct in6_addr *ap, _addr; /* type of the 1st exthdr */ nexthdr = skb->nh.ipv6h->nexthdr; @@ -69,7 +69,7 @@ match(const struct sk_buff *skb, temp = 0; while (ip6t_ext_hdr(nexthdr)) { - struct ipv6_opt_hdr *hdr; + struct ipv6_opt_hdr _hdr, *hp; DEBUGP("ipv6_rt header iteration \n"); @@ -85,15 +85,16 @@ match(const struct sk_buff *skb, break; } - hdr=(struct ipv6_opt_hdr *)(skb->data+ptr); + hp = skb_header_pointer(skb, ptr, sizeof(_hdr), &_hdr); + BUG_ON(hp == NULL); /* Calculate the header length */ if (nexthdr == NEXTHDR_FRAGMENT) { hdrlen = 8; } else if (nexthdr == NEXTHDR_AUTH) - hdrlen = (hdr->hdrlen+2)<<2; + hdrlen = (hp->hdrlen+2)<<2; else - hdrlen = ipv6_optlen(hdr); + hdrlen = ipv6_optlen(hp); /* ROUTING -> evaluate */ if (nexthdr == NEXTHDR_ROUTING) { @@ -116,7 +117,7 @@ match(const struct sk_buff *skb, break; } - nexthdr = hdr->nexthdr; + nexthdr = hp->nexthdr; len -= hdrlen; ptr += hdrlen; if ( ptr > skb->len ) { @@ -138,20 +139,21 @@ match(const struct sk_buff *skb, return 0; } - route = (struct ipv6_rt_hdr *) (skb->data + ptr); + rh = skb_header_pointer(skb, ptr, sizeof(_route), &_route); + BUG_ON(rh == NULL); - DEBUGP("IPv6 RT LEN %u %u ", hdrlen, route->hdrlen); - DEBUGP("TYPE %04X ", route->type); - DEBUGP("SGS_LEFT %u %02X\n", route->segments_left, route->segments_left); + DEBUGP("IPv6 RT LEN %u %u ", hdrlen, rh->hdrlen); + DEBUGP("TYPE %04X ", rh->type); + DEBUGP("SGS_LEFT %u %02X\n", rh->segments_left, rh->segments_left); DEBUGP("IPv6 RT segsleft %02X ", (segsleft_match(rtinfo->segsleft[0], rtinfo->segsleft[1], - route->segments_left, + rh->segments_left, !!(rtinfo->invflags & IP6T_RT_INV_SGS)))); DEBUGP("type %02X %02X %02X ", - rtinfo->rt_type, route->type, + rtinfo->rt_type, rh->type, (!(rtinfo->flags & IP6T_RT_TYP) || - ((rtinfo->rt_type == route->type) ^ + ((rtinfo->rt_type == rh->type) ^ !!(rtinfo->invflags & IP6T_RT_INV_TYP)))); DEBUGP("len %02X %04X %02X ", rtinfo->hdrlen, hdrlen, @@ -159,13 +161,13 @@ match(const struct sk_buff *skb, ((rtinfo->hdrlen == hdrlen) ^ !!(rtinfo->invflags & IP6T_RT_INV_LEN)))); DEBUGP("res %02X %02X %02X ", - (rtinfo->flags & IP6T_RT_RES), ((struct rt0_hdr *)route)->bitmap, - !((rtinfo->flags & IP6T_RT_RES) && (((struct rt0_hdr *)route)->bitmap))); + (rtinfo->flags & IP6T_RT_RES), ((struct rt0_hdr *)rh)->bitmap, + !((rtinfo->flags & IP6T_RT_RES) && (((struct rt0_hdr *)rh)->bitmap))); - ret = (route != NULL) + ret = (rh != NULL) && (segsleft_match(rtinfo->segsleft[0], rtinfo->segsleft[1], - route->segments_left, + rh->segments_left, !!(rtinfo->invflags & IP6T_RT_INV_SGS))) && (!(rtinfo->flags & IP6T_RT_LEN) || @@ -173,13 +175,19 @@ match(const struct sk_buff *skb, !!(rtinfo->invflags & IP6T_RT_INV_LEN))) && (!(rtinfo->flags & IP6T_RT_TYP) || - ((rtinfo->rt_type == route->type) ^ - !!(rtinfo->invflags & IP6T_RT_INV_TYP))) - && - !((rtinfo->flags & IP6T_RT_RES) && (((struct rt0_hdr *)route)->bitmap)); + ((rtinfo->rt_type == rh->type) ^ + !!(rtinfo->invflags & IP6T_RT_INV_TYP))); + + if (ret && (rtinfo->flags & IP6T_RT_RES)) { + u_int32_t *bp, _bitmap; + bp = skb_header_pointer(skb, + ptr + offsetof(struct rt0_hdr, bitmap), + sizeof(_bitmap), &_bitmap); + + ret = (*bp == 0); + } DEBUGP("#%d ",rtinfo->addrnr); - temp = len = ptr = 0; if ( !(rtinfo->flags & IP6T_RT_FST) ){ return ret; } else if (rtinfo->flags & IP6T_RT_FST_NSTRICT) { @@ -188,32 +196,27 @@ match(const struct sk_buff *skb, DEBUGP("There isn't enough space\n"); return 0; } else { + unsigned int i = 0; + DEBUGP("#%d ",rtinfo->addrnr); - ptr = 0; for(temp=0; temp<(unsigned int)((hdrlen-8)/16); temp++){ - len = 0; - while ((u8)(((struct rt0_hdr *)route)-> - addr[temp].s6_addr[len]) == - (u8)(rtinfo->addrs[ptr].s6_addr[len])){ - DEBUGP("%02X?%02X ", - (u8)(((struct rt0_hdr *)route)->addr[temp].s6_addr[len]), - (u8)(rtinfo->addrs[ptr].s6_addr[len])); - len++; - if ( len == 16 ) break; - } - if (len==16) { - DEBUGP("ptr=%d temp=%d;\n",ptr,temp); - ptr++; - } else { - DEBUGP("%02X?%02X ", - (u8)(((struct rt0_hdr *)route)->addr[temp].s6_addr[len]), - (u8)(rtinfo->addrs[ptr].s6_addr[len])); - DEBUGP("!ptr=%d temp=%d;\n",ptr,temp); + ap = skb_header_pointer(skb, + ptr + + sizeof(struct rt0_hdr) + + temp * sizeof(_addr), + sizeof(_addr), + &_addr); + + BUG_ON(ap == NULL); + + if (!ipv6_addr_cmp(ap, &rtinfo->addrs[i])) { + DEBUGP("i=%d temp=%d;\n",i,temp); + i++; } - if (ptr==rtinfo->addrnr) break; + if (i==rtinfo->addrnr) break; } - DEBUGP("ptr=%d len=%d #%d\n",ptr,len, rtinfo->addrnr); - if ( (len == 16) && (ptr == rtinfo->addrnr)) + DEBUGP("i=%d #%d\n", i, rtinfo->addrnr); + if (i == rtinfo->addrnr) return ret; else return 0; } @@ -225,26 +228,19 @@ match(const struct sk_buff *skb, } else { DEBUGP("#%d ",rtinfo->addrnr); for(temp=0; temp<rtinfo->addrnr; temp++){ - len = 0; - while ((u8)(((struct rt0_hdr *)route)-> - addr[temp].s6_addr[len]) == - (u8)(rtinfo->addrs[temp].s6_addr[len])){ - DEBUGP("%02X?%02X ", - (u8)(((struct rt0_hdr *)route)->addr[temp].s6_addr[len]), - (u8)(rtinfo->addrs[temp].s6_addr[len])); - len++; - if ( len == 16 ) break; - } - if (len!=16) { - DEBUGP("%02X?%02X ", - (u8)(((struct rt0_hdr *)route)->addr[temp].s6_addr[len]), - (u8)(rtinfo->addrs[temp].s6_addr[len])); - DEBUGP("!len=%d temp=%d;\n",len,temp); + ap = skb_header_pointer(skb, + ptr + + sizeof(struct rt0_hdr) + + temp * sizeof(_addr), + sizeof(_addr), + &_addr); + BUG_ON(ap == NULL); + + if (ipv6_addr_cmp(ap, &rtinfo->addrs[temp])) break; - } } - DEBUGP("temp=%d len=%d #%d\n",temp,len,rtinfo->addrnr); - if ( (len == 16) && (temp == rtinfo->addrnr) && (temp == (unsigned int)((hdrlen-8)/16))) + DEBUGP("temp=%d #%d\n", temp, rtinfo->addrnr); + if ((temp == rtinfo->addrnr) && (temp == (unsigned int)((hdrlen-8)/16))) return ret; else return 0; } diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c index c73d720114fa..ff920c712d01 100644 --- a/net/ipv6/raw.c +++ b/net/ipv6/raw.c @@ -639,7 +639,7 @@ static int rawv6_sendmsg(struct kiocb *iocb, struct sock *sk, return -EINVAL; if (sin6->sin6_family && sin6->sin6_family != AF_INET6) - return(-EINVAL); + return(-EAFNOSUPPORT); /* port is the proto value [0..255] carried in nexthdr */ proto = ntohs(sin6->sin6_port); diff --git a/net/ipv6/route.c b/net/ipv6/route.c index 70b9bb44dd93..886b7ccb3c3b 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -88,7 +88,7 @@ static void ip6_dst_ifdown(struct dst_entry *, int how); static int ip6_dst_gc(void); static int ip6_pkt_discard(struct sk_buff *skb); -static int ip6_pkt_discard_out(struct sk_buff **pskb); +static int ip6_pkt_discard_out(struct sk_buff *skb); static void ip6_link_failure(struct sk_buff *skb); static void ip6_rt_update_pmtu(struct dst_entry *dst, u32 mtu); @@ -638,7 +638,7 @@ static inline unsigned int ipv6_advmss(unsigned int mtu) struct dst_entry *ndisc_dst_alloc(struct net_device *dev, struct neighbour *neigh, struct in6_addr *addr, - int (*output)(struct sk_buff **)) + int (*output)(struct sk_buff *)) { struct rt6_info *rt; struct inet6_dev *idev = in6_dev_get(dev); @@ -1288,20 +1288,14 @@ struct rt6_info *rt6_add_dflt_router(struct in6_addr *gwaddr, return rt6_get_dflt_router(gwaddr, dev); } -void rt6_purge_dflt_routers(int last_resort) +void rt6_purge_dflt_routers(void) { struct rt6_info *rt; - u32 flags; - - if (last_resort) - flags = RTF_ALLONLINK; - else - flags = RTF_DEFAULT | RTF_ADDRCONF; restart: read_lock_bh(&rt6_lock); for (rt = ip6_routing_table.leaf; rt; rt = rt->u.next) { - if (rt->rt6i_flags & flags) { + if (rt->rt6i_flags & (RTF_DEFAULT | RTF_ADDRCONF)) { dst_hold(&rt->u.dst); rt6_reset_dflt_pointer(NULL); @@ -1362,11 +1356,10 @@ int ip6_pkt_discard(struct sk_buff *skb) return 0; } -int ip6_pkt_discard_out(struct sk_buff **pskb) +int ip6_pkt_discard_out(struct sk_buff *skb) { - (*pskb)->dev = (*pskb)->dst->dev; - BUG_ON(!(*pskb)->dev); - return ip6_pkt_discard(*pskb); + skb->dev = skb->dst->dev; + return ip6_pkt_discard(skb); } /* @@ -1592,7 +1585,7 @@ static int rt6_fill_node(struct sk_buff *skb, struct rt6_info *rt, rtm->rtm_protocol = rt->rt6i_protocol; if (rt->rt6i_flags&RTF_DYNAMIC) rtm->rtm_protocol = RTPROT_REDIRECT; - else if (rt->rt6i_flags&(RTF_ADDRCONF|RTF_ALLONLINK)) + else if (rt->rt6i_flags & RTF_ADDRCONF) rtm->rtm_protocol = RTPROT_KERNEL; else if (rt->rt6i_flags&RTF_DEFAULT) rtm->rtm_protocol = RTPROT_RA; diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index fa13a74492ab..7112e8406a28 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -1802,6 +1802,7 @@ static int tcp_v6_xmit(struct sk_buff *skb, int ipfragok) struct ipv6_pinfo *np = inet6_sk(sk); struct flowi fl; struct dst_entry *dst; + struct in6_addr *final_p = NULL, final; memset(&fl, 0, sizeof(fl)); fl.proto = IPPROTO_TCP; @@ -1815,7 +1816,9 @@ static int tcp_v6_xmit(struct sk_buff *skb, int ipfragok) if (np->opt && np->opt->srcrt) { struct rt0_hdr *rt0 = (struct rt0_hdr *) np->opt->srcrt; + ipv6_addr_copy(&final, &fl.fl6_dst); ipv6_addr_copy(&fl.fl6_dst, rt0->addr); + final_p = &final; } dst = __sk_dst_check(sk, np->dst_cookie); @@ -1828,6 +1831,9 @@ static int tcp_v6_xmit(struct sk_buff *skb, int ipfragok) return err; } + if (final_p) + ipv6_addr_copy(&fl.fl6_dst, final_p); + if ((err = xfrm_lookup(&dst, &fl, sk, 0)) < 0) { sk->sk_route_caps = 0; dst_release(dst); diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c index ff00dc49cdd8..8c18a474d5f0 100644 --- a/net/ipv6/udp.c +++ b/net/ipv6/udp.c @@ -699,7 +699,7 @@ do_udp_sendmsg: if (likely(up->pending)) { if (unlikely(up->pending != AF_INET6)) { release_sock(sk); - return -EINVAL; + return -EAFNOSUPPORT; } dst = NULL; goto do_append_data; diff --git a/net/ipv6/xfrm6_output.c b/net/ipv6/xfrm6_output.c index 40612ec54305..fbd3aa02d062 100644 --- a/net/ipv6/xfrm6_output.c +++ b/net/ipv6/xfrm6_output.c @@ -91,16 +91,14 @@ static int xfrm6_tunnel_check_size(struct sk_buff *skb) return ret; } -int xfrm6_output(struct sk_buff **pskb) +int xfrm6_output(struct sk_buff *skb) { - struct sk_buff *skb = *pskb; struct dst_entry *dst = skb->dst; struct xfrm_state *x = dst->xfrm; int err; if (skb->ip_summed == CHECKSUM_HW) { - err = skb_checksum_help(pskb, 0); - skb = *pskb; + err = skb_checksum_help(skb, 0); if (err) goto error_nolock; } diff --git a/net/sched/sch_api.c b/net/sched/sch_api.c index 4a1e9d237edc..551d8587c226 100644 --- a/net/sched/sch_api.c +++ b/net/sched/sch_api.c @@ -308,7 +308,7 @@ dev_graft_qdisc(struct net_device *dev, struct Qdisc *qdisc) dev_deactivate(dev); qdisc_lock_tree(dev); - if (qdisc && qdisc->flags&TCQ_F_INGRES) { + if (qdisc && qdisc->flags&TCQ_F_INGRESS) { oqdisc = dev->qdisc_ingress; /* Prune old scheduler */ if (oqdisc && atomic_read(&oqdisc->refcnt) <= 1) { @@ -357,7 +357,7 @@ int qdisc_graft(struct net_device *dev, struct Qdisc *parent, u32 classid, if (parent == NULL) { - if (q && q->flags&TCQ_F_INGRES) { + if (q && q->flags&TCQ_F_INGRESS) { *old = dev_graft_qdisc(dev, q); } else { *old = dev_graft_qdisc(dev, new); @@ -430,7 +430,7 @@ qdisc_create(struct net_device *dev, u32 handle, struct rtattr **tca, int *errp) skb_queue_head_init(&sch->q); if (handle == TC_H_INGRESS) - sch->flags |= TCQ_F_INGRES; + sch->flags |= TCQ_F_INGRESS; sch->ops = ops; sch->enqueue = ops->enqueue; diff --git a/net/sctp/associola.c b/net/sctp/associola.c index 16b718fa5172..3a64c225cb37 100644 --- a/net/sctp/associola.c +++ b/net/sctp/associola.c @@ -271,7 +271,7 @@ struct sctp_association *sctp_association_init(struct sctp_association *asoc, asoc->need_ecne = 0; - asoc->assoc_id = (sctp_assoc_t)-1L; + asoc->assoc_id = 0; /* Assume that peer would support both address types unless we are * told otherwise. @@ -374,9 +374,9 @@ static void sctp_association_destroy(struct sctp_association *asoc) sctp_endpoint_put(asoc->ep); sock_put(asoc->base.sk); - if ((long)asoc->assoc_id != -1L) { + if (asoc->assoc_id != 0) { spin_lock_bh(&sctp_assocs_id_lock); - idr_remove(&sctp_assocs_id, (long)asoc->assoc_id); + idr_remove(&sctp_assocs_id, asoc->assoc_id); spin_unlock_bh(&sctp_assocs_id_lock); } @@ -482,14 +482,15 @@ struct sctp_transport *sctp_assoc_add_peer(struct sctp_association *asoc, /* 7.2.1 Slow-Start * - * o The initial cwnd before data transmission or after a - * sufficiently long idle period MUST be <= 2*MTU. + * o The initial cwnd before DATA transmission or after a sufficiently + * long idle period MUST be set to + * min(4*MTU, max(2*MTU, 4380 bytes)) * * o The initial value of ssthresh MAY be arbitrarily high * (for example, implementations MAY use the size of the * receiver advertised window). */ - peer->cwnd = asoc->pmtu * 2; + peer->cwnd = min(4*asoc->pmtu, max_t(__u32, 2*asoc->pmtu, 4380)); /* At this point, we may not have the receiver's advertised window, * so initialize ssthresh to the default value and it will be set diff --git a/net/sctp/outqueue.c b/net/sctp/outqueue.c index 13fda7792e7c..8f2d18263792 100644 --- a/net/sctp/outqueue.c +++ b/net/sctp/outqueue.c @@ -706,10 +706,19 @@ int sctp_outq_flush(struct sctp_outq *q, int rtx_timeout) if (!new_transport) { new_transport = asoc->peer.active_path; } else if (!new_transport->active) { - /* If the chunk is Heartbeat, send it to - * chunk->transport, even it's inactive. + /* If the chunk is Heartbeat or Heartbeat Ack, + * send it to chunk->transport, even if it's + * inactive. + * + * 3.3.6 Heartbeat Acknowledgement: + * ... + * A HEARTBEAT ACK is always sent to the source IP + * address of the IP datagram containing the + * HEARTBEAT chunk to which this ack is responding. + * ... */ - if (chunk->chunk_hdr->type != SCTP_CID_HEARTBEAT) + if (chunk->chunk_hdr->type != SCTP_CID_HEARTBEAT && + chunk->chunk_hdr->type != SCTP_CID_HEARTBEAT_ACK) new_transport = asoc->peer.active_path; } diff --git a/net/sctp/sm_make_chunk.c b/net/sctp/sm_make_chunk.c index c2ca732595fa..1f0676d1ffbc 100644 --- a/net/sctp/sm_make_chunk.c +++ b/net/sctp/sm_make_chunk.c @@ -171,6 +171,7 @@ struct sctp_chunk *sctp_make_init(const struct sctp_association *asoc, struct sctp_opt *sp; sctp_supported_addrs_param_t sat; __u16 types[2]; + sctp_adaption_ind_param_t aiparam; /* RFC 2960 3.3.2 Initiation (INIT) (1) * @@ -196,6 +197,7 @@ struct sctp_chunk *sctp_make_init(const struct sctp_association *asoc, chunksize += sizeof(ecap_param); if (sctp_prsctp_enable) chunksize += sizeof(prsctp_param); + chunksize += sizeof(aiparam); chunksize += vparam_len; /* RFC 2960 3.3.2 Initiation (INIT) (1) @@ -234,6 +236,10 @@ struct sctp_chunk *sctp_make_init(const struct sctp_association *asoc, sctp_addto_chunk(retval, sizeof(ecap_param), &ecap_param); if (sctp_prsctp_enable) sctp_addto_chunk(retval, sizeof(prsctp_param), &prsctp_param); + aiparam.param_hdr.type = SCTP_PARAM_ADAPTION_LAYER_IND; + aiparam.param_hdr.length = htons(sizeof(aiparam)); + aiparam.adaption_ind = htonl(sp->adaption_ind); + sctp_addto_chunk(retval, sizeof(aiparam), &aiparam); nodata: if (addrs.v) kfree(addrs.v); @@ -251,6 +257,7 @@ struct sctp_chunk *sctp_make_init_ack(const struct sctp_association *asoc, sctp_cookie_param_t *cookie; int cookie_len; size_t chunksize; + sctp_adaption_ind_param_t aiparam; retval = NULL; @@ -284,6 +291,8 @@ struct sctp_chunk *sctp_make_init_ack(const struct sctp_association *asoc, if (asoc->peer.prsctp_capable) chunksize += sizeof(prsctp_param); + chunksize += sizeof(aiparam); + /* Now allocate and fill out the chunk. */ retval = sctp_make_chunk(asoc, SCTP_CID_INIT_ACK, 0, chunksize); if (!retval) @@ -302,6 +311,11 @@ struct sctp_chunk *sctp_make_init_ack(const struct sctp_association *asoc, if (asoc->peer.prsctp_capable) sctp_addto_chunk(retval, sizeof(prsctp_param), &prsctp_param); + aiparam.param_hdr.type = SCTP_PARAM_ADAPTION_LAYER_IND; + aiparam.param_hdr.length = htons(sizeof(aiparam)); + aiparam.adaption_ind = htonl(sctp_sk(asoc->base.sk)->adaption_ind); + sctp_addto_chunk(retval, sizeof(aiparam), &aiparam); + /* We need to remove the const qualifier at this point. */ retval->asoc = (struct sctp_association *) asoc; @@ -1297,6 +1311,9 @@ sctp_cookie_param_t *sctp_pack_cookie(const struct sctp_endpoint *ep, /* Remember PR-SCTP capability. */ cookie->c.prsctp_capable = asoc->peer.prsctp_capable; + /* Save adaption indication in the cookie. */ + cookie->c.adaption_ind = asoc->peer.adaption_ind; + /* Set an expiration time for the cookie. */ do_gettimeofday(&cookie->c.expiration); TIMEVAL_ADD(asoc->cookie_life, cookie->c.expiration); @@ -1455,6 +1472,7 @@ no_hmac: retval->addip_serial = retval->c.initial_tsn; retval->adv_peer_ack_point = retval->ctsn_ack_point; retval->peer.prsctp_capable = retval->c.prsctp_capable; + retval->peer.adaption_ind = retval->c.adaption_ind; /* The INIT stuff will be done by the side effects. */ return retval; @@ -1661,6 +1679,7 @@ static int sctp_verify_param(const struct sctp_association *asoc, case SCTP_PARAM_HEARTBEAT_INFO: case SCTP_PARAM_UNRECOGNIZED_PARAMETERS: case SCTP_PARAM_ECN_CAPABLE: + case SCTP_PARAM_ADAPTION_LAYER_IND: break; case SCTP_PARAM_HOST_NAME_ADDRESS: @@ -1989,6 +2008,10 @@ int sctp_process_param(struct sctp_association *asoc, union sctp_params param, asoc->peer.ecn_capable = 1; break; + case SCTP_PARAM_ADAPTION_LAYER_IND: + asoc->peer.adaption_ind = param.aind->adaption_ind; + break; + case SCTP_PARAM_FWD_TSN_SUPPORT: if (sctp_prsctp_enable) { asoc->peer.prsctp_capable = 1; @@ -2459,6 +2482,8 @@ static int sctp_asconf_param_success(struct sctp_association *asoc, union sctp_addr addr; struct sctp_bind_addr *bp = &asoc->base.bind_addr; union sctp_addr_param *addr_param; + struct list_head *pos; + struct sctp_transport *transport; int retval = 0; addr_param = (union sctp_addr_param *) @@ -2482,6 +2507,12 @@ static int sctp_asconf_param_success(struct sctp_association *asoc, retval = sctp_del_bind_addr(bp, &addr); sctp_write_unlock(&asoc->base.addr_lock); sctp_local_bh_enable(); + list_for_each(pos, &asoc->peer.transport_addr_list) { + transport = list_entry(pos, struct sctp_transport, + transports); + sctp_transport_route(transport, NULL, + sctp_sk(asoc->base.sk)); + } break; default: break; diff --git a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c index addb95d790cd..7871faa08378 100644 --- a/net/sctp/sm_statefuns.c +++ b/net/sctp/sm_statefuns.c @@ -629,6 +629,21 @@ sctp_disposition_t sctp_sf_do_5_1D_ce(const struct sctp_endpoint *ep, sctp_add_cmd_sf(commands, SCTP_CMD_EVENT_ULP, SCTP_ULPEVENT(ev)); + /* Sockets API Draft Section 5.3.1.6 + * When a peer sends a Adaption Layer Indication parameter , SCTP + * delivers this notification to inform the application that of the + * peers requested adaption layer. + */ + if (new_asoc->peer.adaption_ind) { + ev = sctp_ulpevent_make_adaption_indication(new_asoc, + GFP_ATOMIC); + if (!ev) + goto nomem_ev; + + sctp_add_cmd_sf(commands, SCTP_CMD_EVENT_ULP, + SCTP_ULPEVENT(ev)); + } + return SCTP_DISPOSITION_CONSUME; nomem_ev: @@ -713,6 +728,20 @@ sctp_disposition_t sctp_sf_do_5_1E_ca(const struct sctp_endpoint *ep, sctp_add_cmd_sf(commands, SCTP_CMD_EVENT_ULP, SCTP_ULPEVENT(ev)); + /* Sockets API Draft Section 5.3.1.6 + * When a peer sends a Adaption Layer Indication parameter , SCTP + * delivers this notification to inform the application that of the + * peers requested adaption layer. + */ + if (asoc->peer.adaption_ind) { + ev = sctp_ulpevent_make_adaption_indication(asoc, GFP_ATOMIC); + if (!ev) + goto nomem; + + sctp_add_cmd_sf(commands, SCTP_CMD_EVENT_ULP, + SCTP_ULPEVENT(ev)); + } + return SCTP_DISPOSITION_CONSUME; nomem: return SCTP_DISPOSITION_NOMEM; @@ -1532,6 +1561,21 @@ static sctp_disposition_t sctp_sf_do_dupcook_b(const struct sctp_endpoint *ep, goto nomem_ev; sctp_add_cmd_sf(commands, SCTP_CMD_EVENT_ULP, SCTP_ULPEVENT(ev)); + + /* Sockets API Draft Section 5.3.1.6 + * When a peer sends a Adaption Layer Indication parameter , SCTP + * delivers this notification to inform the application that of the + * peers requested adaption layer. + */ + if (asoc->peer.adaption_ind) { + ev = sctp_ulpevent_make_adaption_indication(asoc, GFP_ATOMIC); + if (!ev) + goto nomem_ev; + + sctp_add_cmd_sf(commands, SCTP_CMD_EVENT_ULP, + SCTP_ULPEVENT(ev)); + } + return SCTP_DISPOSITION_CONSUME; nomem_ev: @@ -1612,6 +1656,21 @@ static sctp_disposition_t sctp_sf_do_dupcook_d(const struct sctp_endpoint *ep, goto nomem; sctp_add_cmd_sf(commands, SCTP_CMD_EVENT_ULP, SCTP_ULPEVENT(ev)); + + /* Sockets API Draft Section 5.3.1.6 + * When a peer sends a Adaption Layer Indication parameter, + * SCTP delivers this notification to inform the application + * that of the peers requested adaption layer. + */ + if (new_asoc->peer.adaption_ind) { + ev = sctp_ulpevent_make_adaption_indication(new_asoc, + GFP_ATOMIC); + if (!ev) + goto nomem; + + sctp_add_cmd_sf(commands, SCTP_CMD_EVENT_ULP, + SCTP_ULPEVENT(ev)); + } } sctp_add_cmd_sf(commands, SCTP_CMD_TRANSMIT, SCTP_NULL()); diff --git a/net/sctp/socket.c b/net/sctp/socket.c index 0d1bc4507d6b..6e61bce2f97a 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c @@ -1063,7 +1063,7 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk, struct sctp_sndrcvinfo default_sinfo = { 0 }; struct sctp_sndrcvinfo *sinfo; struct sctp_initmsg *sinit; - sctp_assoc_t associd = NULL; + sctp_assoc_t associd = 0; sctp_cmsgs_t cmsgs = { NULL }; int err; sctp_scope_t scope; @@ -2120,6 +2120,20 @@ static int sctp_setsockopt_peer_primary_addr(struct sock *sk, char __user *optva return err; } +static int sctp_setsockopt_adaption_layer(struct sock *sk, char __user *optval, + int optlen) +{ + __u32 val; + + if (optlen < sizeof(__u32)) + return -EINVAL; + if (copy_from_user(&val, optval, sizeof(__u32))) + return -EFAULT; + + sctp_sk(sk)->adaption_ind = val; + + return 0; +} /* API 6.2 setsockopt(), getsockopt() * @@ -2219,6 +2233,10 @@ SCTP_STATIC int sctp_setsockopt(struct sock *sk, int level, int optname, case SCTP_MAXSEG: retval = sctp_setsockopt_maxseg(sk, optval, optlen); break; + case SCTP_ADAPTION_LAYER: + retval = sctp_setsockopt_adaption_layer(sk, optval, optlen); + break; + default: retval = -ENOPROTOOPT; break; @@ -2518,6 +2536,8 @@ SCTP_STATIC int sctp_init_sock(struct sock *sk) /* User specified fragmentation limit. */ sp->user_frag = 0; + sp->adaption_ind = 0; + sp->pf = sctp_get_pf_specific(sk->sk_family); /* Control variables for partial data delivery. */ @@ -3160,6 +3180,29 @@ static int sctp_getsockopt_primary_addr(struct sock *sk, int len, } /* + * 7.1.11 Set Adaption Layer Indicator (SCTP_ADAPTION_LAYER) + * + * Requests that the local endpoint set the specified Adaption Layer + * Indication parameter for all future INIT and INIT-ACK exchanges. + */ +static int sctp_getsockopt_adaption_layer(struct sock *sk, int len, + char __user *optval, int __user *optlen) +{ + __u32 val; + + if (len < sizeof(__u32)) + return -EINVAL; + + len = sizeof(__u32); + val = sctp_sk(sk)->adaption_ind; + if (put_user(len, optlen)) + return -EFAULT; + if (copy_to_user(optval, &val, len)) + return -EFAULT; + return 0; +} + +/* * * 7.1.14 Set default send parameters (SCTP_DEFAULT_SEND_PARAM) * @@ -3515,6 +3558,10 @@ SCTP_STATIC int sctp_getsockopt(struct sock *sk, int level, int optname, retval = sctp_getsockopt_peer_addr_info(sk, len, optval, optlen); break; + case SCTP_ADAPTION_LAYER: + retval = sctp_getsockopt_adaption_layer(sk, len, optval, + optlen); + break; default: retval = -ENOPROTOOPT; break; diff --git a/net/sctp/transport.c b/net/sctp/transport.c index 198ab7662c2e..c4a2370beb12 100644 --- a/net/sctp/transport.c +++ b/net/sctp/transport.c @@ -421,15 +421,15 @@ void sctp_transport_lower_cwnd(struct sctp_transport *transport, { switch (reason) { case SCTP_LOWER_CWND_T3_RTX: - /* RFC 2960 Section 7.2.3, sctpimpguide-05 Section 2.9.2 + /* RFC 2960 Section 7.2.3, sctpimpguide * When the T3-rtx timer expires on an address, SCTP should * perform slow start by: - * ssthresh = max(cwnd/2, 2*MTU) + * ssthresh = max(cwnd/2, 4*MTU) * cwnd = 1*MTU * partial_bytes_acked = 0 */ transport->ssthresh = max(transport->cwnd/2, - 2*transport->asoc->pmtu); + 4*transport->asoc->pmtu); transport->cwnd = transport->asoc->pmtu; break; @@ -439,15 +439,15 @@ void sctp_transport_lower_cwnd(struct sctp_transport *transport, * were last sent, according to the formula described in * Section 7.2.3. * - * RFC 2960 7.2.3, sctpimpguide-05 2.9.2 Upon detection of - * packet losses from SACK (see Section 7.2.4), An endpoint + * RFC 2960 7.2.3, sctpimpguide Upon detection of packet + * losses from SACK (see Section 7.2.4), An endpoint * should do the following: - * ssthresh = max(cwnd/2, 2*MTU) + * ssthresh = max(cwnd/2, 4*MTU) * cwnd = ssthresh * partial_bytes_acked = 0 */ transport->ssthresh = max(transport->cwnd/2, - 2*transport->asoc->pmtu); + 4*transport->asoc->pmtu); transport->cwnd = transport->ssthresh; break; @@ -467,23 +467,24 @@ void sctp_transport_lower_cwnd(struct sctp_transport *transport, if ((jiffies - transport->last_time_ecne_reduced) > transport->rtt) { transport->ssthresh = max(transport->cwnd/2, - 2*transport->asoc->pmtu); + 4*transport->asoc->pmtu); transport->cwnd = transport->ssthresh; transport->last_time_ecne_reduced = jiffies; } break; case SCTP_LOWER_CWND_INACTIVE: - /* RFC 2960 Section 7.2.1, sctpimpguide-05 Section 2.14.2 - * When the association does not transmit data on a given - * transport address within an RTO, the cwnd of the transport - * address should be adjusted to 2*MTU. + /* RFC 2960 Section 7.2.1, sctpimpguide + * When the endpoint does not transmit data on a given + * transport address, the cwnd of the transport address + * should be adjusted to max(cwnd/2, 4*MTU) per RTO. * NOTE: Although the draft recommends that this check needs * to be done every RTO interval, we do it every hearbeat * interval. */ if ((jiffies - transport->last_time_used) > transport->rto) - transport->cwnd = 2*transport->asoc->pmtu; + transport->cwnd = max(transport->cwnd/2, + 4*transport->asoc->pmtu); break; }; diff --git a/net/sctp/ulpevent.c b/net/sctp/ulpevent.c index e804d6ed8c0f..cd002b577e85 100644 --- a/net/sctp/ulpevent.c +++ b/net/sctp/ulpevent.c @@ -562,7 +562,7 @@ struct sctp_ulpevent *sctp_ulpevent_make_shutdown_event( struct sctp_shutdown_event *sse; struct sk_buff *skb; - event = sctp_ulpevent_new(sizeof(struct sctp_assoc_change), + event = sctp_ulpevent_new(sizeof(struct sctp_shutdown_event), MSG_NOTIFICATION, gfp); if (!event) goto fail; @@ -613,6 +613,40 @@ fail: return NULL; } +/* Create and initialize a SCTP_ADAPTION_INDICATION notification. + * + * Socket Extensions for SCTP + * 5.3.1.6 SCTP_ADAPTION_INDICATION + */ +struct sctp_ulpevent *sctp_ulpevent_make_adaption_indication( + const struct sctp_association *asoc, int gfp) +{ + struct sctp_ulpevent *event; + struct sctp_adaption_event *sai; + struct sk_buff *skb; + + event = sctp_ulpevent_new(sizeof(struct sctp_adaption_event), + MSG_NOTIFICATION, gfp); + if (!event) + goto fail; + + skb = sctp_event2skb(event); + sai = (struct sctp_adaption_event *) + skb_put(skb, sizeof(struct sctp_adaption_event)); + + sai->sai_type = SCTP_ADAPTION_INDICATION; + sai->sai_flags = 0; + sai->sai_length = sizeof(struct sctp_adaption_event); + sai->sai_adaption_ind = asoc->peer.adaption_ind; + sctp_ulpevent_set_owner(event, asoc); + sai->sai_assoc_id = sctp_assoc2id(asoc); + + return event; + +fail: + return NULL; +} + /* A message has been received. Package this message as a notification * to pass it to the upper layers. Go ahead and calculate the sndrcvinfo * even if filtered out later. @@ -689,7 +723,7 @@ struct sctp_ulpevent *sctp_ulpevent_make_pdapi( struct sctp_pdapi_event *pd; struct sk_buff *skb; - event = sctp_ulpevent_new(sizeof(struct sctp_assoc_change), + event = sctp_ulpevent_new(sizeof(struct sctp_pdapi_event), MSG_NOTIFICATION, gfp); if (!event) goto fail; diff --git a/net/socket.c b/net/socket.c index 275d8cf6d3be..102d2737c269 100644 --- a/net/socket.c +++ b/net/socket.c @@ -459,7 +459,7 @@ struct socket *sockfd_lookup(int fd, int *err) * NULL is returned. */ -struct socket *sock_alloc(void) +static struct socket *sock_alloc(void) { struct inode * inode; struct socket * sock; @@ -1354,7 +1354,7 @@ asmlinkage long sys_accept(int fd, struct sockaddr __user *upeer_sockaddr, int _ if (!sock) goto out; - err = -EMFILE; + err = -ENFILE; if (!(newsock = sock_alloc())) goto out_put; @@ -2089,8 +2089,6 @@ void socket_seq_show(struct seq_file *seq) /* ABI emulation layers need these two */ EXPORT_SYMBOL(move_addr_to_kernel); EXPORT_SYMBOL(move_addr_to_user); -EXPORT_SYMBOL(sock_alloc); -EXPORT_SYMBOL(sock_alloc_inode); EXPORT_SYMBOL(sock_create); EXPORT_SYMBOL(sock_create_kern); EXPORT_SYMBOL(sock_create_lite); diff --git a/net/xfrm/xfrm_export.c b/net/xfrm/xfrm_export.c index 9f335640d254..24dbc9a99b1b 100644 --- a/net/xfrm/xfrm_export.c +++ b/net/xfrm/xfrm_export.c @@ -12,22 +12,17 @@ EXPORT_SYMBOL(__xfrm_policy_check); EXPORT_SYMBOL(__xfrm_route_forward); EXPORT_SYMBOL(xfrm_state_alloc); EXPORT_SYMBOL(__xfrm_state_destroy); -EXPORT_SYMBOL(xfrm_state_find); EXPORT_SYMBOL(xfrm_state_insert); EXPORT_SYMBOL(xfrm_state_add); EXPORT_SYMBOL(xfrm_state_update); EXPORT_SYMBOL(xfrm_state_check_expire); -EXPORT_SYMBOL(xfrm_state_check_space); EXPORT_SYMBOL(xfrm_state_check); EXPORT_SYMBOL(xfrm_state_lookup); EXPORT_SYMBOL(xfrm_state_register_afinfo); EXPORT_SYMBOL(xfrm_state_unregister_afinfo); -EXPORT_SYMBOL(xfrm_state_get_afinfo); -EXPORT_SYMBOL(xfrm_state_put_afinfo); EXPORT_SYMBOL(xfrm_state_delete_tunnel); EXPORT_SYMBOL(xfrm_replay_check); EXPORT_SYMBOL(xfrm_replay_advance); -EXPORT_SYMBOL(xfrm_check_selectors); EXPORT_SYMBOL(__secpath_destroy); EXPORT_SYMBOL(secpath_dup); EXPORT_SYMBOL(xfrm_get_acqseq); @@ -44,7 +39,6 @@ EXPORT_SYMBOL(xfrm_find_acq_byseq); EXPORT_SYMBOL(xfrm_find_acq); EXPORT_SYMBOL(xfrm_alloc_spi); EXPORT_SYMBOL(xfrm_state_flush); -EXPORT_SYMBOL(xfrm_policy_kill); EXPORT_SYMBOL(xfrm_policy_bysel); EXPORT_SYMBOL(xfrm_policy_insert); EXPORT_SYMBOL(xfrm_policy_walk); @@ -54,8 +48,6 @@ EXPORT_SYMBOL(xfrm_policy_list); EXPORT_SYMBOL(xfrm_dst_lookup); EXPORT_SYMBOL(xfrm_policy_register_afinfo); EXPORT_SYMBOL(xfrm_policy_unregister_afinfo); -EXPORT_SYMBOL(xfrm_policy_get_afinfo); -EXPORT_SYMBOL(xfrm_policy_put_afinfo); EXPORT_SYMBOL_GPL(xfrm_probe_algs); EXPORT_SYMBOL_GPL(xfrm_count_auth_supported); diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c index 1708bf045a2b..452cb1647a8a 100644 --- a/net/xfrm/xfrm_policy.c +++ b/net/xfrm/xfrm_policy.c @@ -40,6 +40,9 @@ static struct list_head xfrm_policy_gc_list = LIST_HEAD_INIT(xfrm_policy_gc_list); static spinlock_t xfrm_policy_gc_lock = SPIN_LOCK_UNLOCKED; +static struct xfrm_policy_afinfo *xfrm_policy_get_afinfo(unsigned short family); +static void xfrm_policy_put_afinfo(struct xfrm_policy_afinfo *afinfo); + int xfrm_register_type(struct xfrm_type *type, unsigned short family) { struct xfrm_policy_afinfo *afinfo = xfrm_policy_get_afinfo(family); @@ -286,7 +289,7 @@ static void xfrm_policy_gc_task(void *data) * entry dead. The rule must be unlinked from lists to the moment. */ -void xfrm_policy_kill(struct xfrm_policy *policy) +static void xfrm_policy_kill(struct xfrm_policy *policy) { write_lock_bh(&policy->lock); if (policy->dead) @@ -1187,7 +1190,7 @@ int xfrm_policy_unregister_afinfo(struct xfrm_policy_afinfo *afinfo) return err; } -struct xfrm_policy_afinfo *xfrm_policy_get_afinfo(unsigned short family) +static struct xfrm_policy_afinfo *xfrm_policy_get_afinfo(unsigned short family) { struct xfrm_policy_afinfo *afinfo; if (unlikely(family >= NPROTO)) @@ -1200,7 +1203,7 @@ struct xfrm_policy_afinfo *xfrm_policy_get_afinfo(unsigned short family) return afinfo; } -void xfrm_policy_put_afinfo(struct xfrm_policy_afinfo *afinfo) +static void xfrm_policy_put_afinfo(struct xfrm_policy_afinfo *afinfo) { if (unlikely(afinfo == NULL)) return; diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c index 2317ae179be9..93a7693aa7c5 100644 --- a/net/xfrm/xfrm_state.c +++ b/net/xfrm/xfrm_state.c @@ -48,6 +48,9 @@ static spinlock_t xfrm_state_gc_lock = SPIN_LOCK_UNLOCKED; static void __xfrm_state_delete(struct xfrm_state *x); +static struct xfrm_state_afinfo *xfrm_state_get_afinfo(unsigned short family); +static void xfrm_state_put_afinfo(struct xfrm_state_afinfo *afinfo); + static void xfrm_state_gc_destroy(struct xfrm_state *x) { if (del_timer(&x->timer)) @@ -526,7 +529,7 @@ int xfrm_state_check_expire(struct xfrm_state *x) return 0; } -int xfrm_state_check_space(struct xfrm_state *x, struct sk_buff *skb) +static int xfrm_state_check_space(struct xfrm_state *x, struct sk_buff *skb) { int nhead = x->props.header_len + LL_RESERVED_SPACE(skb->dst->dev) - skb_headroom(skb); @@ -740,19 +743,6 @@ void xfrm_replay_advance(struct xfrm_state *x, u32 seq) } } -int xfrm_check_selectors(struct xfrm_state **x, int n, struct flowi *fl) -{ - int i; - - for (i=0; i<n; i++) { - int match; - match = xfrm_selector_match(&x[i]->sel, fl, x[i]->props.family); - if (!match) - return -EINVAL; - } - return 0; -} - static struct list_head xfrm_km_list = LIST_HEAD_INIT(xfrm_km_list); static rwlock_t xfrm_km_lock = RW_LOCK_UNLOCKED; @@ -914,7 +904,7 @@ int xfrm_state_unregister_afinfo(struct xfrm_state_afinfo *afinfo) return err; } -struct xfrm_state_afinfo *xfrm_state_get_afinfo(unsigned short family) +static struct xfrm_state_afinfo *xfrm_state_get_afinfo(unsigned short family) { struct xfrm_state_afinfo *afinfo; if (unlikely(family >= NPROTO)) @@ -927,7 +917,7 @@ struct xfrm_state_afinfo *xfrm_state_get_afinfo(unsigned short family) return afinfo; } -void xfrm_state_put_afinfo(struct xfrm_state_afinfo *afinfo) +static void xfrm_state_put_afinfo(struct xfrm_state_afinfo *afinfo) { if (unlikely(afinfo == NULL)) return; |
