* Re: [PATCH] netfilter: per netns nf_conntrack_cachep
From: Patrick McHardy @ 2010-02-02 16:48 UTC (permalink / raw)
To: Jon Masters
Cc: Eric Dumazet, Alexey Dobriyan, linux-kernel, netdev,
netfilter-devel, Paul E. McKenney
In-Reply-To: <1265129192.2861.141.camel@tonnant>
Jon Masters wrote:
> On Tue, 2010-02-02 at 06:35 -0500, Jon Masters wrote:
>
>> I think there's something more fundamental going on here.
>
> What happens is the conntrack code attempts to free
> nf_conntrack_untracked back into the SL[U]B cache from which it
> allocates other ct's.
That shouldn't happen, the untracked conntrack is initialized to a
refcount of 1, which is never released.
> There's just one problem...that's a static struct
> not from the cache. So, this is why we end up with the SLAB being
> corrupted and the address immediately following the
> nf_conntrack_untracked being corrupted.
>
> I shoved some debug comments into the destroy code to see if we were
> trying to free nf_conntrack_untracked, and bingo. I have shoved a panic
> in there now, will send you a backtrace.
Thanks.
^ permalink raw reply
* Re: IP: Send an ICMP "Fragment Reassembly Timeout" message when enabling connection track
From: Patrick McHardy @ 2010-02-02 16:46 UTC (permalink / raw)
To: Jamie Iles; +Cc: netdev, shanwei
In-Reply-To: <20100202162228.GC4305@wear.picochip.com>
[-- Attachment #1: Type: text/plain, Size: 3446 bytes --]
Jamie Iles wrote:
> Hi,
>
> I have an ARM based board that I'm running off of today's next tree. When
> booting with a rootfs over NFS I regularly see a crash with the following log:
>
> huh, entered c0237b8c with preempt_count 00000103, exited with 00000102?
> kernel BUG at kernel/timer.c:1035!
> Unable to handle kernel NULL pointer dereference at virtual address 00000000
> pgd = c0004000
> [00000000] *pgd=00000000
> Internal error: Oops: 817 [#1] PREEMPT
> last sysfs file: /sys/class/mtd/mtd6ro/dev
> Modules linked in:
> CPU: 0 Not tainted (2.6.33-rc6-next-20100202-picochip-arm2009q3+ #46)
> PC is at __bug+0x18/0x24
> LR is at __bug+0x14/0x24
> pc : [<c0024240>] lr : [<c002423c>] psr: 60000113
> sp : c03a3ec8 ip : c03cb880 fp : c03ef9c8
> r10: c03efdc8 r9 : c03efbc8 r8 : c03effc8
> r7 : c7e171b4 r6 : c03ef1a0 r5 : c03a2000 r4 : 00000000
> r3 : 00000000 r2 : c03a3ebc r1 : c033ae76 r0 : 00000029
> Flags: nZCv IRQs on FIQs on Mode SVC_32 ISA ARM Segment kernel
> Control: 00c5387d Table: 07e58008 DAC: 00000017
> Process swapper (pid: 0, stack limit = 0xc03a2268)
> Stack: (0xc03a3ec8 to 0xc03a4000)
> 3ec0: 00000000 c0046a54 00000002 00000000 c00468d8 00000000
> 3ee0: 00000000 00000103 c7e17180 c0237b8c 00000002 c095601c 00000000 c036c3df
> 3f00: c03a3f00 c03a3f00 00000000 00000000 c03a2000 00000004 c03ef004 00000103
> 3f20: 0000000a 00000101 00000001 c003fdf4 c03ad92c 00000000 c03a73c0 00000000
> 3f40: 00000024 c03a2000 00000000 00000010 00000002 00000001 c03a2000 0001bf40
> 3f60: 00000000 c003ff64 00000024 c0020070 ffffffff fe060000 00000010 c02a6170
> 3f80: c0021a70 00000000 00000000 c03a2000 c03a2000 c001d3bc c001d3b8 c03a6a18
> 3fa0: 0001bfa8 410fb767 0001bf40 00000000 c03a73e8 c03a3fc8 c0021a70 c0021a74
> 3fc0: 60000013 ffffffff c03a2000 c0021f40 c094b0e8 c0008920 c0008490 00000000
> 3fe0: 00000000 c001d3bc 00000000 00c5387d c03ce470 00008034 00000000 00000000
> [<c0024240>] (__bug+0x18/0x24) from [<c0046a54>] (run_timer_softirq+0x308/0x36c)
> [<c0046a54>] (run_timer_softirq+0x308/0x36c) from [<c003fdf4>] (__do_softirq+0x1
> 08/0x220)
> [<c003fdf4>] (__do_softirq+0x108/0x220) from [<c003ff64>] (irq_exit+0x58/0xb0)
> [<c003ff64>] (irq_exit+0x58/0xb0) from [<c0020070>] (asm_do_IRQ+0x70/0x8c)
> [<c0020070>] (asm_do_IRQ+0x70/0x8c) from [<c02a6170>] (__irq_svc+0x50/0xd4)
> Exception stack(0xc03a3f80 to 0xc03a3fc8)
> 3f80: c0021a70 00000000 00000000 c03a2000 c03a2000 c001d3bc c001d3b8 c03a6a18
> 3fa0: 0001bfa8 410fb767 0001bf40 00000000 c03a73e8 c03a3fc8 c0021a70 c0021a74
> 3fc0: 60000013 ffffffff
> [<c02a6170>] (__irq_svc+0x50/0xd4) from [<c0021a74>] (default_idle+0x28/0x2c)
> [<c0021a74>] (default_idle+0x28/0x2c) from [<c0021f40>] (cpu_idle+0x50/0xa4)
> [<c0021f40>] (cpu_idle+0x50/0xa4) from [<c0008920>] (start_kernel+0x248/0x29c)
> [<c0008920>] (start_kernel+0x248/0x29c) from [<00008034>] (0x8034)
> Code: e1a01000 e59f000c eb09f9bf e3a03000 (e5833000)
>
> The function the timer called was ip_expire():
>
> [jamiei@wear linux-2.6]$ arm-none-linux-gnueabi-addr2line -e vmlinux c0237b8c
> /home/jamiei/linux-2.6/net/ipv4/ip_fragment.c:190
>
> Reverting the commit (e9017b55189355e9e6569990a18919e83f35bccb) makes this
> crash go away. The kernel is built with preempt debugging but I don't get any
> other warnings.
This patch should fix it.
ipv4: ip_fragment: fix unbalanced rcu_read_unlock()
Signed-off-by: Patrick McHardy <kaber@trash.net>
[-- Attachment #2: x --]
[-- Type: text/plain, Size: 455 bytes --]
diff --git a/net/ipv4/ip_fragment.c b/net/ipv4/ip_fragment.c
index 9f41bd3..b59430b 100644
--- a/net/ipv4/ip_fragment.c
+++ b/net/ipv4/ip_fragment.c
@@ -234,10 +234,9 @@ static void ip_expire(unsigned long arg)
/* Send an ICMP "Fragment Reassembly Timeout" message. */
icmp_send(head, ICMP_TIME_EXCEEDED, ICMP_EXC_FRAGTIME, 0);
- }
-
out_rcu_unlock:
- rcu_read_unlock();
+ rcu_read_unlock();
+ }
out:
spin_unlock(&qp->q.lock);
ipq_put(qp);
^ permalink raw reply related
* RE: [net-next-2.6 PATCH 2/5] if_link: Add SR-IOV configuration methods
From: Williams, Mitch A @ 2010-02-02 16:45 UTC (permalink / raw)
To: Or Gerlitz, shemminger@vyatta.com
Cc: Kirsher, Jeffrey T, davem@davemloft.net, netdev@vger.kernel.org,
gospo@redhat.com
In-Reply-To: <15ddcffd1002012116la5ae23ct7754e4e9287a1a1f@mail.gmail.com>
>From: Or Gerlitz [mailto:or.gerlitz@gmail.com]
>
>Williams, Mitch A <mitch.a.williams@intel.com> wrote:
>
>> To be honest, Or, this completely slipped my mind. I'll add it to my
>to-do list.
>> If it's OK with you, I'd prefer to get this set of patches in as-is and
>> add the egress qos stuff later. A lot of people have been asking for
>> these patches, so I'd rather not delay for this feature.
>
>Mitch, looking on the patch series I see that except for two patches
>([PATCH 1/5] pci: Add SR-IOV convenience functions and macros and
>[PATCH 2/4] libnetlink: Modify parser to track the first duplicated
>attributes) seven other patches have to be changed/enhanced to
>incorporate the egress qos mapping. If you prefer to do that later
>rather then now I am fine with that, but lets not leave that a side.
>
>Or.
Yeah, now that I've had a while to think about it, I agree. It's much
less painful to make the change now.
Dave and Stephen, please drop these patches. I'll update with the priority
stuff and resubmit.
Thanks for your help, Or.
-Mitch
^ permalink raw reply
* Re: [PATCH] netfilter: per netns nf_conntrack_cachep
From: Jon Masters @ 2010-02-02 16:46 UTC (permalink / raw)
To: Eric Dumazet
Cc: Alexey Dobriyan, Patrick McHardy, linux-kernel, netdev,
netfilter-devel, Paul E. McKenney
In-Reply-To: <1265110504.2861.135.camel@tonnant>
On Tue, 2010-02-02 at 06:35 -0500, Jon Masters wrote:
> I think there's something more fundamental going on here.
What happens is the conntrack code attempts to free
nf_conntrack_untracked back into the SL[U]B cache from which it
allocates other ct's. There's just one problem...that's a static struct
not from the cache. So, this is why we end up with the SLAB being
corrupted and the address immediately following the
nf_conntrack_untracked being corrupted.
I shoved some debug comments into the destroy code to see if we were
trying to free nf_conntrack_untracked, and bingo. I have shoved a panic
in there now, will send you a backtrace.
Jon.
^ permalink raw reply
* [PATCH v5 7/7] TCPCT part 2g: parse cookie pair and 64-bit timestamp
From: William Allen Simpson @ 2010-02-02 16:41 UTC (permalink / raw)
To: Linux Kernel Developers, Linux Kernel Network Developers; +Cc: Andrew Morton
In-Reply-To: <4B684DE7.3020601@gmail.com>
[-- Attachment #1: Type: text/plain, Size: 687 bytes --]
Parse cookie pair extended option (previously defined).
Define and parse 64-bit timestamp extended option (and minor cleanup).
However, only 32-bits are used at this time (permitted by specification).
Every bit is sacred. Use as few bits as possible in the tcp_sock
structure, at the expense of performance.
Requires:
net: tcp_header_len_th and tcp_option_len_th
TCPCT part 2f: cleanup tcp_parse_options
Signed-off-by: William.Allen.Simpson@gmail.com
---
include/linux/tcp.h | 10 ++++-
include/net/tcp.h | 45 ++++++++++---------
net/ipv4/tcp_input.c | 119 ++++++++++++++++++++++++++++++++++++++++++++++----
3 files changed, 142 insertions(+), 32 deletions(-)
[-- Attachment #2: TCPCT+2g5+2.6.33-rc6.patch --]
[-- Type: text/plain, Size: 10020 bytes --]
diff --git a/include/linux/tcp.h b/include/linux/tcp.h
index 2987ee8..b71be6c 100644
--- a/include/linux/tcp.h
+++ b/include/linux/tcp.h
@@ -260,13 +260,21 @@ struct tcp_options_received {
u8 num_sacks; /* Number of SACK blocks */
u16 user_mss; /* mss requested by user in ioctl */
u16 mss_clamp; /* Maximal mss, negotiated at connection setup */
+
+ /* When the options are extended beyond the maximum 40 bytes,
+ * then this holds the additional data offset (in 32-bit words).
+ */
+ u16 extended:12, /* Up to 3,315 = 13 (40/3) by 255 */
+ saw_tstamp64:1, /* Seen on recent packet */
+ tstamp64_ok:1, /* Verified with cookie pair */
+ __unused:2;
};
static inline void tcp_clear_options(struct tcp_options_received *rx_opt)
{
rx_opt->tstamp_ok = rx_opt->sack_ok = 0;
rx_opt->wscale_ok = rx_opt->snd_wscale = 0;
- rx_opt->cookie_plus = 0;
+ rx_opt->tstamp64_ok = 0;
}
/* This is the max number of SACKS that we'll generate and process. It's safe
diff --git a/include/net/tcp.h b/include/net/tcp.h
index 420e872..157c97b 100644
--- a/include/net/tcp.h
+++ b/include/net/tcp.h
@@ -156,9 +156,8 @@ extern void tcp_time_wait(struct sock *sk, int state, int timeo);
/*
* TCP option
*/
-
-#define TCPOPT_NOP 1 /* Padding */
#define TCPOPT_EOL 0 /* End of options */
+#define TCPOPT_NOP 1 /* Padding */
#define TCPOPT_MSS 2 /* Segment size negotiating */
#define TCPOPT_WINDOW 3 /* Window scaling */
#define TCPOPT_SACK_PERM 4 /* SACK Permitted */
@@ -166,30 +165,32 @@ extern void tcp_time_wait(struct sock *sk, int state, int timeo);
#define TCPOPT_TIMESTAMP 8 /* Better RTT estimations/PAWS */
#define TCPOPT_MD5SIG 19 /* MD5 Signature (RFC2385) */
#define TCPOPT_COOKIE 253 /* Cookie extension (experimental) */
-
-/*
- * TCP option lengths
- */
-
-#define TCPOLEN_MSS 4
-#define TCPOLEN_WINDOW 3
-#define TCPOLEN_SACK_PERM 2
-#define TCPOLEN_TIMESTAMP 10
-#define TCPOLEN_MD5SIG 18
-#define TCPOLEN_COOKIE_BASE 2 /* Cookie-less header extension */
-#define TCPOLEN_COOKIE_PAIR 3 /* Cookie pair header extension */
-#define TCPOLEN_COOKIE_MIN (TCPOLEN_COOKIE_BASE+TCP_COOKIE_MIN)
-#define TCPOLEN_COOKIE_MAX (TCPOLEN_COOKIE_BASE+TCP_COOKIE_MAX)
-
-/* But this is what stacks really send out. */
-#define TCPOLEN_TSTAMP_ALIGNED 12
+#define TCPOPT_TSTAMP64 254 /* 64-bit extension (experimental) */
+
+/* TCP option lengths (same order as above) */
+#define TCPOLEN_MSS 4
+#define TCPOLEN_WINDOW 3
+#define TCPOLEN_SACK_PERM 2
+#define TCPOLEN_SACK_BASE 2
+#define TCPOLEN_SACK_PERBLOCK 8
+#define TCPOLEN_TIMESTAMP 10
+#define TCPOLEN_MD5SIG 18
+#define TCPOLEN_COOKIE_BASE 2 /* Cookie-less header extension */
+#define TCPOLEN_COOKIE_PAIR 3 /* Cookie pair header extension */
+#define TCPOLEN_COOKIE_MIN (TCPOLEN_COOKIE_BASE+TCP_COOKIE_MIN)
+#define TCPOLEN_COOKIE_MAX (TCPOLEN_COOKIE_BASE+TCP_COOKIE_MAX)
+#define TCPOLEN_TSTAMP64 3
+
+/* TCP options 32-bit aligned (same order as above) */
+#define TCPOLEN_MSS_ALIGNED 4
#define TCPOLEN_WSCALE_ALIGNED 4
#define TCPOLEN_SACKPERM_ALIGNED 4
-#define TCPOLEN_SACK_BASE 2
#define TCPOLEN_SACK_BASE_ALIGNED 4
-#define TCPOLEN_SACK_PERBLOCK 8
+#define TCPOLEN_TSTAMP_ALIGNED 12
#define TCPOLEN_MD5SIG_ALIGNED 20
-#define TCPOLEN_MSS_ALIGNED 4
+
+/* TCP option extensions (same order as above) */
+#define TCPOEXT_TSTAMP64 16
/* Flags in tp->nonagle */
#define TCP_NAGLE_OFF 1 /* Nagle's algo is disabled */
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
index d3c6c7a..df38cef 100644
--- a/net/ipv4/tcp_input.c
+++ b/net/ipv4/tcp_input.c
@@ -3722,9 +3722,71 @@ old_ack:
return 0;
}
+/* Process option extension data.
+ *
+ * Extension data in nonlinear skb is Not Yet Implemented!!!
+ *
+ * Returns:
+ * 0 on success
+ * - on failure
+ */
+int tcp_parse_extension(struct sk_buff *skb, const struct tcphdr *th,
+ struct tcp_options_received *opt_rx, u8 **hvpp)
+{
+ __be32 *tsp = (__be32 *)th + th->doff;
+ int remainder = skb_headlen(skb);
+
+ if (unlikely(th->syn)) {
+ /* Extended options are ignored on SYN or SYNACK, just as other
+ * malformed or unrecognized options. Leave the data in place.
+ */
+ opt_rx->extended = 0;
+ return 0;
+ }
+
+ /* Adjust end_seq, set in tcp_v[4,6]_rcv() */
+ TCP_SKB_CB(skb)->end_seq -= (opt_rx->extended * 4);
+
+ /* If present, always first, aligned */
+ if (opt_rx->saw_tstamp64) {
+ if (unlikely(remainder < TCPOEXT_TSTAMP64)) {
+ /* insufficient data */
+ opt_rx->saw_tstamp64 = 0 /* false */;
+ opt_rx->saw_tstamp = 0 /* false */;
+ } else {
+ /* 64-bits not yet implemented */
+ tsp++;
+ opt_rx->rcv_tsval = ntohl(*tsp);
+ tsp += 2;
+ opt_rx->rcv_tsecr = ntohl(*tsp);
+ tsp++;
+ }
+ remainder -= TCPOEXT_TSTAMP64;
+ }
+
+ /* If present, TCPOLEN_COOKIE_PAIR makes this an odd value */
+ if (opt_rx->cookie_plus & 0x1) {
+ int cookie_size = opt_rx->cookie_plus - TCPOLEN_COOKIE_PAIR;
+
+ if (unlikely(remainder < cookie_size)) {
+ /* insufficient data */
+ opt_rx->cookie_plus = 0;
+ } else {
+ *hvpp = (u8 *)tsp;
+ tsp += (cookie_size / 4);
+ }
+ remainder -= cookie_size;
+ }
+ return (remainder < 0) ? remainder : 0;
+}
+
/* Look for tcp options. Normally only called on SYN and SYNACK packets.
* But, this can also be called on packets in the established flow when
* the fast version below fails.
+ *
+ * Returns:
+ * 0 on success
+ * - on failure
*/
int tcp_parse_options(struct sk_buff *skb, const struct tcphdr *th,
struct tcp_options_received *opt_rx, u8 **hvpp, int estab)
@@ -3733,6 +3795,8 @@ int tcp_parse_options(struct sk_buff *skb, const struct tcphdr *th,
int length = tcp_option_len_th(th);
opt_rx->cookie_plus = 0;
+ opt_rx->extended = 0;
+ opt_rx->saw_tstamp64 = 0; /* false */
opt_rx->saw_tstamp = 0; /* false */
while (length > 0) {
@@ -3741,6 +3805,9 @@ int tcp_parse_options(struct sk_buff *skb, const struct tcphdr *th,
switch (opcode) {
case TCPOPT_EOL:
+ if (opt_rx->extended > 0)
+ return tcp_parse_extension(skb, th, opt_rx,
+ hvpp);
return 0;
case TCPOPT_NOP: /* Ref: RFC 793 section 3.1 */
length--;
@@ -3753,6 +3820,9 @@ int tcp_parse_options(struct sk_buff *skb, const struct tcphdr *th,
opsize = *ptr++;
if (opsize < 2 || opsize > length) {
/* don't parse partial options */
+ if (opt_rx->extended > 0)
+ return tcp_parse_extension(skb, th, opt_rx,
+ hvpp);
return 0;
}
@@ -3829,7 +3899,16 @@ int tcp_parse_options(struct sk_buff *skb, const struct tcphdr *th,
/* not yet implemented */
break;
case TCPOLEN_COOKIE_PAIR:
- /* not yet implemented */
+ if (*ptr >= (TCPOLEN_COOKIE_MIN / 4) &&
+ *ptr <= (TCPOLEN_COOKIE_MAX / 4) &&
+ !th->syn && opt_rx->saw_tstamp &&
+ opt_rx->cookie_plus == 0 &&
+ (opt_rx->extended == 0 ||
+ (opt_rx->extended == (TCPOEXT_TSTAMP64 / 4) &&
+ opt_rx->saw_tstamp64))) {
+ opt_rx->cookie_plus = opsize + *ptr * 4;
+ }
+ opt_rx->extended += *ptr;
break;
case TCPOLEN_COOKIE_MIN+0:
case TCPOLEN_COOKIE_MIN+2:
@@ -3849,6 +3928,18 @@ int tcp_parse_options(struct sk_buff *skb, const struct tcphdr *th,
};
break;
+ case TCPOPT_TSTAMP64:
+ if (opsize == TCPOLEN_TSTAMP64) {
+ if (*ptr == (TCPOEXT_TSTAMP64 / 4) &&
+ !th->syn && !opt_rx->saw_tstamp &&
+ opt_rx->extended == 0) {
+ opt_rx->saw_tstamp64 = 1; /* true */
+ opt_rx->saw_tstamp = 1; /* true */
+ }
+ opt_rx->extended += *ptr;
+ }
+ break;
+
default:
/* skip unrecognized options */
break;
@@ -3857,6 +3948,8 @@ int tcp_parse_options(struct sk_buff *skb, const struct tcphdr *th,
ptr += opsize - 2;
length -= opsize;
}
+ if (opt_rx->extended > 0)
+ return tcp_parse_extension(skb, th, opt_rx, hvpp);
return 0;
}
@@ -3883,6 +3976,11 @@ static int tcp_parse_aligned_timestamp(struct tcp_sock *tp, struct tcphdr *th)
/* Fast parse options. This hopes to only see timestamps.
* If it is wrong it falls back on tcp_parse_options().
+ *
+ * Returns:
+ * 1 on success, fast
+ * 0 on success, slow
+ * - on failure
*/
static int tcp_fast_parse_options(struct sk_buff *skb, struct tcphdr *th,
struct tcp_sock *tp, u8 **hvpp)
@@ -3892,11 +3990,14 @@ static int tcp_fast_parse_options(struct sk_buff *skb, struct tcphdr *th,
*/
if (th->doff == (sizeof(*th) / 4)) {
tp->rx_opt.saw_tstamp = 0;
+ tp->rx_opt.extended = 0;
return 0;
- } else if (tp->rx_opt.tstamp_ok &&
- th->doff == ((sizeof(*th) + TCPOLEN_TSTAMP_ALIGNED) / 4)) {
- if (tcp_parse_aligned_timestamp(tp, th))
- return 1;
+ }
+ if (th->doff == ((sizeof(*th) + TCPOLEN_TSTAMP_ALIGNED) / 4) &&
+ tp->rx_opt.tstamp_ok &&
+ tcp_parse_aligned_timestamp(tp, th)) {
+ tp->rx_opt.extended = 0;
+ return 1;
}
return tcp_parse_options(skb, th, &tp->rx_opt, hvpp, 1);
}
@@ -3907,8 +4008,8 @@ static int tcp_fast_parse_options(struct sk_buff *skb, struct tcphdr *th,
*/
u8 *tcp_parse_md5sig_option(struct tcphdr *th)
{
- int length = (th->doff << 2) - sizeof (*th);
u8 *ptr = (u8*)(th + 1);
+ int length = tcp_option_len_th(th);
/* If the TCP option is too short, we can short cut */
if (length < TCPOLEN_MD5SIG)
@@ -4373,7 +4474,7 @@ static void tcp_data_queue(struct sock *sk, struct sk_buff *skb)
if (TCP_SKB_CB(skb)->seq == TCP_SKB_CB(skb)->end_seq)
goto drop;
- __skb_pull(skb, th->doff * 4);
+ __skb_pull(skb, (th->doff + tp->rx_opt.extended) * 4);
TCP_ECN_accept_cwr(tp, skb);
@@ -5034,8 +5135,8 @@ static void tcp_urg(struct sock *sk, struct sk_buff *skb, struct tcphdr *th)
/* Do we wait for any urgent data? - normally not... */
if (tp->urg_data == TCP_URG_NOTYET) {
- u32 ptr = tp->urg_seq - ntohl(th->seq) + (th->doff * 4) -
- th->syn;
+ u32 ptr = ((th->doff + tp->rx_opt.extended) * 4)
+ + tp->urg_seq - ntohl(th->seq) - th->syn;
/* Is the urgent pointer pointing into this packet? */
if (ptr < skb->len) {
--
1.6.3.3
^ permalink raw reply related
* IP: Send an ICMP "Fragment Reassembly Timeout" message when enabling connection track
From: Jamie Iles @ 2010-02-02 16:22 UTC (permalink / raw)
To: netdev, shanwei
Hi,
I have an ARM based board that I'm running off of today's next tree. When
booting with a rootfs over NFS I regularly see a crash with the following log:
huh, entered c0237b8c with preempt_count 00000103, exited with 00000102?
kernel BUG at kernel/timer.c:1035!
Unable to handle kernel NULL pointer dereference at virtual address 00000000
pgd = c0004000
[00000000] *pgd=00000000
Internal error: Oops: 817 [#1] PREEMPT
last sysfs file: /sys/class/mtd/mtd6ro/dev
Modules linked in:
CPU: 0 Not tainted (2.6.33-rc6-next-20100202-picochip-arm2009q3+ #46)
PC is at __bug+0x18/0x24
LR is at __bug+0x14/0x24
pc : [<c0024240>] lr : [<c002423c>] psr: 60000113
sp : c03a3ec8 ip : c03cb880 fp : c03ef9c8
r10: c03efdc8 r9 : c03efbc8 r8 : c03effc8
r7 : c7e171b4 r6 : c03ef1a0 r5 : c03a2000 r4 : 00000000
r3 : 00000000 r2 : c03a3ebc r1 : c033ae76 r0 : 00000029
Flags: nZCv IRQs on FIQs on Mode SVC_32 ISA ARM Segment kernel
Control: 00c5387d Table: 07e58008 DAC: 00000017
Process swapper (pid: 0, stack limit = 0xc03a2268)
Stack: (0xc03a3ec8 to 0xc03a4000)
3ec0: 00000000 c0046a54 00000002 00000000 c00468d8 00000000
3ee0: 00000000 00000103 c7e17180 c0237b8c 00000002 c095601c 00000000 c036c3df
3f00: c03a3f00 c03a3f00 00000000 00000000 c03a2000 00000004 c03ef004 00000103
3f20: 0000000a 00000101 00000001 c003fdf4 c03ad92c 00000000 c03a73c0 00000000
3f40: 00000024 c03a2000 00000000 00000010 00000002 00000001 c03a2000 0001bf40
3f60: 00000000 c003ff64 00000024 c0020070 ffffffff fe060000 00000010 c02a6170
3f80: c0021a70 00000000 00000000 c03a2000 c03a2000 c001d3bc c001d3b8 c03a6a18
3fa0: 0001bfa8 410fb767 0001bf40 00000000 c03a73e8 c03a3fc8 c0021a70 c0021a74
3fc0: 60000013 ffffffff c03a2000 c0021f40 c094b0e8 c0008920 c0008490 00000000
3fe0: 00000000 c001d3bc 00000000 00c5387d c03ce470 00008034 00000000 00000000
[<c0024240>] (__bug+0x18/0x24) from [<c0046a54>] (run_timer_softirq+0x308/0x36c)
[<c0046a54>] (run_timer_softirq+0x308/0x36c) from [<c003fdf4>] (__do_softirq+0x1
08/0x220)
[<c003fdf4>] (__do_softirq+0x108/0x220) from [<c003ff64>] (irq_exit+0x58/0xb0)
[<c003ff64>] (irq_exit+0x58/0xb0) from [<c0020070>] (asm_do_IRQ+0x70/0x8c)
[<c0020070>] (asm_do_IRQ+0x70/0x8c) from [<c02a6170>] (__irq_svc+0x50/0xd4)
Exception stack(0xc03a3f80 to 0xc03a3fc8)
3f80: c0021a70 00000000 00000000 c03a2000 c03a2000 c001d3bc c001d3b8 c03a6a18
3fa0: 0001bfa8 410fb767 0001bf40 00000000 c03a73e8 c03a3fc8 c0021a70 c0021a74
3fc0: 60000013 ffffffff
[<c02a6170>] (__irq_svc+0x50/0xd4) from [<c0021a74>] (default_idle+0x28/0x2c)
[<c0021a74>] (default_idle+0x28/0x2c) from [<c0021f40>] (cpu_idle+0x50/0xa4)
[<c0021f40>] (cpu_idle+0x50/0xa4) from [<c0008920>] (start_kernel+0x248/0x29c)
[<c0008920>] (start_kernel+0x248/0x29c) from [<00008034>] (0x8034)
Code: e1a01000 e59f000c eb09f9bf e3a03000 (e5833000)
The function the timer called was ip_expire():
[jamiei@wear linux-2.6]$ arm-none-linux-gnueabi-addr2line -e vmlinux c0237b8c
/home/jamiei/linux-2.6/net/ipv4/ip_fragment.c:190
Reverting the commit (e9017b55189355e9e6569990a18919e83f35bccb) makes this
crash go away. The kernel is built with preempt debugging but I don't get any
other warnings.
Jamie
^ permalink raw reply
* [PATCH v3 6/7] TCPCT part 2f: cleanup tcp_parse_options
From: William Allen Simpson @ 2010-02-02 16:37 UTC (permalink / raw)
To: Linux Kernel Developers, Linux Kernel Network Developers; +Cc: Andrew Morton
In-Reply-To: <4B684DE7.3020601@gmail.com>
[-- Attachment #1: Type: text/plain, Size: 623 bytes --]
Split switch, shift cases to the left, fix most lines beyond column 80.
Prepare (future) error return.
Requires:
TCPCT part 1g: Responder Cookie => Initiator
net: tcp_header_len_th and tcp_option_len_th
Signed-off-by: William.Allen.Simpson@gmail.com
---
include/net/tcp.h | 3 +-
net/ipv4/syncookies.c | 5 +-
net/ipv4/tcp_input.c | 217 ++++++++++++++++++++++++++--------------------
net/ipv4/tcp_ipv4.c | 10 ++-
net/ipv4/tcp_minisocks.c | 14 ++-
net/ipv6/syncookies.c | 5 +-
net/ipv6/tcp_ipv6.c | 6 +-
7 files changed, 154 insertions(+), 106 deletions(-)
[-- Attachment #2: TCPCT+2f3+2.6.33-rc6.patch --]
[-- Type: text/plain, Size: 13523 bytes --]
diff --git a/include/net/tcp.h b/include/net/tcp.h
index 6b0d7e9..420e872 100644
--- a/include/net/tcp.h
+++ b/include/net/tcp.h
@@ -403,7 +403,8 @@ extern int tcp_recvmsg(struct kiocb *iocb, struct sock *sk,
size_t len, int nonblock,
int flags, int *addr_len);
-extern void tcp_parse_options(struct sk_buff *skb,
+extern int tcp_parse_options(struct sk_buff *skb,
+ const struct tcphdr *th,
struct tcp_options_received *opt_rx,
u8 **hvpp,
int estab);
diff --git a/net/ipv4/syncookies.c b/net/ipv4/syncookies.c
index 66fd80e..3bed530 100644
--- a/net/ipv4/syncookies.c
+++ b/net/ipv4/syncookies.c
@@ -254,6 +254,7 @@ struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb,
struct ip_options *opt)
{
struct tcp_options_received tcp_opt;
+ int parsed;
u8 *hash_location;
struct inet_request_sock *ireq;
struct tcp_request_sock *treq;
@@ -279,7 +280,9 @@ struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb,
/* check for timestamp cookie support */
memset(&tcp_opt, 0, sizeof(tcp_opt));
- tcp_parse_options(skb, &tcp_opt, &hash_location, 0);
+ parsed = tcp_parse_options(skb, th, &tcp_opt, &hash_location, 0);
+ if (parsed < 0)
+ goto out;
if (tcp_opt.saw_tstamp)
cookie_check_timestamp(&tcp_opt);
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
index 165040e..d3c6c7a 100644
--- a/net/ipv4/tcp_input.c
+++ b/net/ipv4/tcp_input.c
@@ -3726,15 +3726,14 @@ old_ack:
* But, this can also be called on packets in the established flow when
* the fast version below fails.
*/
-void tcp_parse_options(struct sk_buff *skb, struct tcp_options_received *opt_rx,
- u8 **hvpp, int estab)
+int tcp_parse_options(struct sk_buff *skb, const struct tcphdr *th,
+ struct tcp_options_received *opt_rx, u8 **hvpp, int estab)
{
- unsigned char *ptr;
- struct tcphdr *th = tcp_hdr(skb);
- int length = (th->doff * 4) - sizeof(struct tcphdr);
+ unsigned char *ptr = (unsigned char *)(th + 1);
+ int length = tcp_option_len_th(th);
- ptr = (unsigned char *)(th + 1);
- opt_rx->saw_tstamp = 0;
+ opt_rx->cookie_plus = 0;
+ opt_rx->saw_tstamp = 0; /* false */
while (length > 0) {
int opcode = *ptr++;
@@ -3742,106 +3741,130 @@ void tcp_parse_options(struct sk_buff *skb, struct tcp_options_received *opt_rx,
switch (opcode) {
case TCPOPT_EOL:
- return;
+ return 0;
case TCPOPT_NOP: /* Ref: RFC 793 section 3.1 */
length--;
continue;
default:
- opsize = *ptr++;
- if (opsize < 2) /* "silly options" */
- return;
- if (opsize > length)
- return; /* don't parse partial options */
- switch (opcode) {
- case TCPOPT_MSS:
- if (opsize == TCPOLEN_MSS && th->syn && !estab) {
- u16 in_mss = get_unaligned_be16(ptr);
- if (in_mss) {
- if (opt_rx->user_mss &&
- opt_rx->user_mss < in_mss)
- in_mss = opt_rx->user_mss;
- opt_rx->mss_clamp = in_mss;
- }
- }
- break;
- case TCPOPT_WINDOW:
- if (opsize == TCPOLEN_WINDOW && th->syn &&
- !estab && sysctl_tcp_window_scaling) {
- __u8 snd_wscale = *(__u8 *)ptr;
- opt_rx->wscale_ok = 1;
- if (snd_wscale > 14) {
- if (net_ratelimit())
- printk(KERN_INFO "tcp_parse_options: Illegal window "
- "scaling value %d >14 received.\n",
- snd_wscale);
- snd_wscale = 14;
- }
- opt_rx->snd_wscale = snd_wscale;
- }
- break;
- case TCPOPT_TIMESTAMP:
- if ((opsize == TCPOLEN_TIMESTAMP) &&
- ((estab && opt_rx->tstamp_ok) ||
- (!estab && sysctl_tcp_timestamps))) {
- opt_rx->saw_tstamp = 1;
- opt_rx->rcv_tsval = get_unaligned_be32(ptr);
- opt_rx->rcv_tsecr = get_unaligned_be32(ptr + 4);
- }
- break;
- case TCPOPT_SACK_PERM:
- if (opsize == TCPOLEN_SACK_PERM && th->syn &&
- !estab && sysctl_tcp_sack) {
- opt_rx->sack_ok = 1;
- tcp_sack_reset(opt_rx);
+ /* fallthru */
+ break;
+ };
+
+ opsize = *ptr++;
+ if (opsize < 2 || opsize > length) {
+ /* don't parse partial options */
+ return 0;
+ }
+
+ switch (opcode) {
+ case TCPOPT_MSS:
+ if (opsize == TCPOLEN_MSS && th->syn && !estab) {
+ u16 in_mss = get_unaligned_be16(ptr);
+ if (in_mss) {
+ if (opt_rx->user_mss &&
+ opt_rx->user_mss < in_mss)
+ in_mss = opt_rx->user_mss;
+ opt_rx->mss_clamp = in_mss;
}
- break;
+ }
+ break;
- case TCPOPT_SACK:
- if ((opsize >= (TCPOLEN_SACK_BASE + TCPOLEN_SACK_PERBLOCK)) &&
- !((opsize - TCPOLEN_SACK_BASE) % TCPOLEN_SACK_PERBLOCK) &&
- opt_rx->sack_ok) {
- TCP_SKB_CB(skb)->sacked = (ptr - 2) - (unsigned char *)th;
+ case TCPOPT_WINDOW:
+ if (opsize == TCPOLEN_WINDOW && th->syn &&
+ !estab && sysctl_tcp_window_scaling) {
+ __u8 snd_wscale = *(__u8 *)ptr;
+ opt_rx->wscale_ok = 1;
+ if (snd_wscale > 14) {
+ if (net_ratelimit())
+ printk(KERN_INFO
+ "tcp_parse_options: "
+ "window scaling value "
+ "%d > 14 received.\n",
+ snd_wscale);
+ snd_wscale = 14;
}
- break;
+ opt_rx->snd_wscale = snd_wscale;
+ }
+ break;
+
+ case TCPOPT_SACK_PERM:
+ if (opsize == TCPOLEN_SACK_PERM && th->syn &&
+ !estab && sysctl_tcp_sack) {
+ opt_rx->sack_ok = 1;
+ tcp_sack_reset(opt_rx);
+ }
+ break;
+
+ case TCPOPT_SACK:
+ if ((opsize >= (TCPOLEN_SACK_BASE + TCPOLEN_SACK_PERBLOCK)) &&
+ !((opsize - TCPOLEN_SACK_BASE) % TCPOLEN_SACK_PERBLOCK) &&
+ opt_rx->sack_ok) {
+ TCP_SKB_CB(skb)->sacked = (ptr - 2)
+ - (unsigned char *)th;
+ }
+ break;
+
+ case TCPOPT_TIMESTAMP:
+ if ((opsize == TCPOLEN_TIMESTAMP) &&
+ ((estab && opt_rx->tstamp_ok) ||
+ (!estab && sysctl_tcp_timestamps))) {
+ opt_rx->saw_tstamp = 1;
+ opt_rx->rcv_tsval = get_unaligned_be32(ptr);
+ opt_rx->rcv_tsecr = get_unaligned_be32(ptr + 4);
+ }
+ break;
#ifdef CONFIG_TCP_MD5SIG
- case TCPOPT_MD5SIG:
- /*
- * The MD5 Hash has already been
- * checked (see tcp_v{4,6}_do_rcv()).
- */
- break;
+ case TCPOPT_MD5SIG:
+ /*
+ * The MD5 Hash has already been
+ * checked (see tcp_v{4,6}_do_rcv()).
+ */
+ break;
#endif
- case TCPOPT_COOKIE:
- /* This option is variable length.
- */
- switch (opsize) {
- case TCPOLEN_COOKIE_BASE:
- /* not yet implemented */
- break;
- case TCPOLEN_COOKIE_PAIR:
- /* not yet implemented */
- break;
- case TCPOLEN_COOKIE_MIN+0:
- case TCPOLEN_COOKIE_MIN+2:
- case TCPOLEN_COOKIE_MIN+4:
- case TCPOLEN_COOKIE_MIN+6:
- case TCPOLEN_COOKIE_MAX:
- /* 16-bit multiple */
+ case TCPOPT_COOKIE:
+ /* This option is variable length.
+ */
+ switch (opsize) {
+ case TCPOLEN_COOKIE_BASE:
+ /* not yet implemented */
+ break;
+ case TCPOLEN_COOKIE_PAIR:
+ /* not yet implemented */
+ break;
+ case TCPOLEN_COOKIE_MIN+0:
+ case TCPOLEN_COOKIE_MIN+2:
+ case TCPOLEN_COOKIE_MIN+4:
+ case TCPOLEN_COOKIE_MIN+6:
+ case TCPOLEN_COOKIE_MAX:
+ /* 16-bit multiple */
+ if (th->syn && opt_rx->saw_tstamp &&
+ opt_rx->cookie_plus == 0) {
opt_rx->cookie_plus = opsize;
*hvpp = ptr;
- default:
- /* ignore option */
- break;
- };
+ }
+ break;
+ default:
+ /* ignore option */
break;
};
+ break;
- ptr += opsize-2;
- length -= opsize;
- }
+ default:
+ /* skip unrecognized options */
+ break;
+ };
+
+ ptr += opsize - 2;
+ length -= opsize;
}
+ return 0;
}
+/*
+ * Returns:
+ * 1 on success
+ * 0 on failure
+ */
static int tcp_parse_aligned_timestamp(struct tcp_sock *tp, struct tcphdr *th)
{
__be32 *ptr = (__be32 *)(th + 1);
@@ -3875,8 +3898,7 @@ static int tcp_fast_parse_options(struct sk_buff *skb, struct tcphdr *th,
if (tcp_parse_aligned_timestamp(tp, th))
return 1;
}
- tcp_parse_options(skb, &tp->rx_opt, hvpp, 1);
- return 1;
+ return tcp_parse_options(skb, th, &tp->rx_opt, hvpp, 1);
}
#ifdef CONFIG_TCP_MD5SIG
@@ -5127,10 +5149,13 @@ static int tcp_validate_incoming(struct sock *sk, struct sk_buff *skb,
{
u8 *hash_location;
struct tcp_sock *tp = tcp_sk(sk);
+ int parsed = tcp_fast_parse_options(skb, th, tp, &hash_location);
+
+ if (parsed < 0)
+ goto discard;
/* RFC1323: H1. Apply PAWS check first. */
- if (tcp_fast_parse_options(skb, th, tp, &hash_location) &&
- tp->rx_opt.saw_tstamp &&
+ if (tp->rx_opt.saw_tstamp &&
tcp_paws_discard(sk, skb)) {
if (!th->rst) {
NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_PAWSESTABREJECTED);
@@ -5410,8 +5435,10 @@ static int tcp_rcv_synsent_state_process(struct sock *sk, struct sk_buff *skb,
struct tcp_cookie_values *cvp = tp->cookie_values;
int saved_clamp = tp->rx_opt.mss_clamp;
int queued = 0;
+ int parsed = tcp_parse_options(skb, th, &tp->rx_opt, &hash_location, 0);
- tcp_parse_options(skb, &tp->rx_opt, &hash_location, 0);
+ if (parsed < 0)
+ goto discard;
if (th->ack) {
/* rfc793:
diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
index f999e06..3f0813f 100644
--- a/net/ipv4/tcp_ipv4.c
+++ b/net/ipv4/tcp_ipv4.c
@@ -1215,6 +1215,7 @@ int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb)
{
struct tcp_extend_values tmp_ext;
struct tcp_options_received tmp_opt;
+ int parsed;
u8 *hash_location;
struct request_sock *req;
struct inet_request_sock *ireq;
@@ -1265,7 +1266,10 @@ int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb)
tcp_clear_options(&tmp_opt);
tmp_opt.mss_clamp = TCP_MSS_DEFAULT;
tmp_opt.user_mss = tp->rx_opt.user_mss;
- tcp_parse_options(skb, &tmp_opt, &hash_location, 0);
+ parsed = tcp_parse_options(skb, tcp_hdr(skb), &tmp_opt, &hash_location,
+ 0);
+ if (parsed < 0)
+ goto drop_and_free;
if (tmp_opt.cookie_plus > 0 &&
tmp_opt.saw_tstamp &&
@@ -1278,7 +1282,7 @@ int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb)
int l = tmp_opt.cookie_plus - TCPOLEN_COOKIE_BASE;
if (tcp_cookie_generator(&tmp_ext.cookie_bakery[0]) != 0)
- goto drop_and_release;
+ goto drop_and_free;
/* Secret recipe starts with IP addresses */
*mess++ ^= daddr;
@@ -1299,7 +1303,7 @@ int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb)
tmp_ext.cookie_out_never = 1; /* true */
tmp_ext.cookie_plus = 0;
} else {
- goto drop_and_release;
+ goto drop_and_free;
}
tmp_ext.cookie_in_always = tp->rx_opt.cookie_in_always;
diff --git a/net/ipv4/tcp_minisocks.c b/net/ipv4/tcp_minisocks.c
index 37b7536..0d42635 100644
--- a/net/ipv4/tcp_minisocks.c
+++ b/net/ipv4/tcp_minisocks.c
@@ -97,9 +97,12 @@ tcp_timewait_state_process(struct inet_timewait_sock *tw, struct sk_buff *skb,
tmp_opt.saw_tstamp = 0;
if (th->doff > (sizeof(*th) >> 2) && tcptw->tw_ts_recent_stamp) {
- tcp_parse_options(skb, &tmp_opt, &hash_location, 0);
+ int parsed = tcp_parse_options(skb, th, &tmp_opt,
+ &hash_location, 0);
- if (tmp_opt.saw_tstamp) {
+ if (parsed < 0) {
+ paws_reject = 1; /* true */
+ } else if (tmp_opt.saw_tstamp) {
tmp_opt.ts_recent = tcptw->tw_ts_recent;
tmp_opt.ts_recent_stamp = tcptw->tw_ts_recent_stamp;
paws_reject = tcp_paws_reject(&tmp_opt, th->rst);
@@ -528,9 +531,12 @@ struct sock *tcp_check_req(struct sock *sk, struct sk_buff *skb,
tmp_opt.saw_tstamp = 0;
if (th->doff > (sizeof(struct tcphdr)>>2)) {
- tcp_parse_options(skb, &tmp_opt, &hash_location, 0);
+ int parsed = tcp_parse_options(skb, th, &tmp_opt,
+ &hash_location, 0);
- if (tmp_opt.saw_tstamp) {
+ if (parsed < 0) {
+ paws_reject = 1; /* true */
+ } else if (tmp_opt.saw_tstamp) {
tmp_opt.ts_recent = req->ts_recent;
/* We do not store true stamp, but it is not required,
* it can be estimated (approximately)
diff --git a/net/ipv6/syncookies.c b/net/ipv6/syncookies.c
index 7208a06..3072500 100644
--- a/net/ipv6/syncookies.c
+++ b/net/ipv6/syncookies.c
@@ -160,6 +160,7 @@ static inline int cookie_check(struct sk_buff *skb, __u32 cookie)
struct sock *cookie_v6_check(struct sock *sk, struct sk_buff *skb)
{
struct tcp_options_received tcp_opt;
+ int parsed;
u8 *hash_location;
struct inet_request_sock *ireq;
struct inet6_request_sock *ireq6;
@@ -187,7 +188,9 @@ struct sock *cookie_v6_check(struct sock *sk, struct sk_buff *skb)
/* check for timestamp cookie support */
memset(&tcp_opt, 0, sizeof(tcp_opt));
- tcp_parse_options(skb, &tcp_opt, &hash_location, 0);
+ parsed = tcp_parse_options(skb, th, &tcp_opt, &hash_location, 0);
+ if (parsed < 0)
+ goto out;
if (tcp_opt.saw_tstamp)
cookie_check_timestamp(&tcp_opt);
diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c
index 3d08a4d..e15e4f6 100644
--- a/net/ipv6/tcp_ipv6.c
+++ b/net/ipv6/tcp_ipv6.c
@@ -1164,6 +1164,7 @@ static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb)
{
struct tcp_extend_values tmp_ext;
struct tcp_options_received tmp_opt;
+ int parsed;
u8 *hash_location;
struct request_sock *req;
struct inet6_request_sock *treq;
@@ -1207,7 +1208,10 @@ static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb)
tcp_clear_options(&tmp_opt);
tmp_opt.mss_clamp = IPV6_MIN_MTU - sizeof(struct tcphdr) - sizeof(struct ipv6hdr);
tmp_opt.user_mss = tp->rx_opt.user_mss;
- tcp_parse_options(skb, &tmp_opt, &hash_location, 0);
+ parsed = tcp_parse_options(skb, tcp_hdr(skb), &tmp_opt, &hash_location,
+ 0);
+ if (parsed < 0)
+ goto drop_and_free;
if (tmp_opt.cookie_plus > 0 &&
tmp_opt.saw_tstamp &&
--
1.6.3.3
^ permalink raw reply related
* [PATCH v3 5/7] TCPCT part 2e: accept SYNACK data
From: William Allen Simpson @ 2010-02-02 16:33 UTC (permalink / raw)
To: Linux Kernel Developers, Linux Kernel Network Developers; +Cc: Andrew Morton
In-Reply-To: <4B684DE7.3020601@gmail.com>
[-- Attachment #1: Type: text/plain, Size: 709 bytes --]
When accompanied by cookie option, Initiator (client) queues incoming
SYNACK transaction data.
This is a straightforward re-implementation of an earlier (year-old)
patch that no longer applies cleanly, with permission of the original
author (Adam Langley). The patch was previously reviewed:
http://thread.gmane.org/gmane.linux.network/102586
This function will also be used in subsequent patches that implement
additional features.
Requires:
TCPCT part 1g: Responder Cookie => Initiator
net: tcp_header_len_th and tcp_option_len_th
Signed-off-by: William.Allen.Simpson@gmail.com
---
net/ipv4/tcp_input.c | 26 +++++++++++++++++++++++++-
1 files changed, 25 insertions(+), 1 deletions(-)
[-- Attachment #2: TCPCT+2e3+2.6.33-rc6.patch --]
[-- Type: text/plain, Size: 2057 bytes --]
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
index 8e0f6ae..165040e 100644
--- a/net/ipv4/tcp_input.c
+++ b/net/ipv4/tcp_input.c
@@ -5395,6 +5395,12 @@ discard:
return 0;
}
+/*
+ * Returns:
+ * +1 on reset,
+ * 0 success and/or SYNACK data,
+ * -1 on discard.
+ */
static int tcp_rcv_synsent_state_process(struct sock *sk, struct sk_buff *skb,
struct tcphdr *th)
{
@@ -5403,6 +5409,7 @@ static int tcp_rcv_synsent_state_process(struct sock *sk, struct sk_buff *skb,
struct tcp_sock *tp = tcp_sk(sk);
struct tcp_cookie_values *cvp = tp->cookie_values;
int saved_clamp = tp->rx_opt.mss_clamp;
+ int queued = 0;
tcp_parse_options(skb, &tp->rx_opt, &hash_location, 0);
@@ -5509,6 +5516,7 @@ static int tcp_rcv_synsent_state_process(struct sock *sk, struct sk_buff *skb,
- TCPOLEN_COOKIE_BASE;
int cookie_pair_size = cookie_size
+ cvp->cookie_desired;
+ int tcp_header_len = tcp_header_len_th(th);
/* A cookie extension option was sent and returned.
* Note that each incoming SYNACK replaces the
@@ -5524,6 +5532,19 @@ static int tcp_rcv_synsent_state_process(struct sock *sk, struct sk_buff *skb,
hash_location, cookie_size);
cvp->cookie_pair_size = cookie_pair_size;
}
+
+ queued = skb->len - tcp_header_len;
+ if (queued > 0) {
+ /* Queue incoming transaction data. */
+ __skb_pull(skb, tcp_header_len);
+ __skb_queue_tail(&sk->sk_receive_queue, skb);
+ skb_set_owner_r(skb, sk);
+ sk->sk_data_ready(sk, 0);
+ cvp->s_data_in = 1; /* true */
+ tp->rcv_nxt = TCP_SKB_CB(skb)->end_seq;
+ tp->rcv_wup = TCP_SKB_CB(skb)->end_seq;
+ tp->copied_seq = TCP_SKB_CB(skb)->seq + 1;
+ }
}
smp_mb();
@@ -5577,11 +5598,14 @@ static int tcp_rcv_synsent_state_process(struct sock *sk, struct sk_buff *skb,
TCP_DELACK_MAX, TCP_RTO_MAX);
discard:
- __kfree_skb(skb);
+ if (queued <= 0)
+ __kfree_skb(skb);
return 0;
} else {
tcp_send_ack(sk);
}
+ if (queued > 0)
+ return 0;
return -1;
}
--
1.6.3.3
^ permalink raw reply related
* Re: [PATCH net-next-2.6] net: use helpers to access mc list
From: Jiri Pirko @ 2010-02-02 16:31 UTC (permalink / raw)
To: David Miller; +Cc: netdev
In-Reply-To: <20100202.080601.255528829.davem@davemloft.net>
Tue, Feb 02, 2010 at 05:06:01PM CET, davem@davemloft.net wrote:
>From: Jiri Pirko <jpirko@redhat.com>
>Date: Tue, 2 Feb 2010 17:03:48 +0100
>
>> You mean "struct dev_mc_list"? But that would solve nothing. If I would still
>> use current structure in drivers, then still the migration to struct_hw_addr
>> would be all-at-once for all drivers :( This patch was exacly made to avoid
>> this.
>
>I think changing the iterator type will have to be done
>wholesale in one changeset, there is no reasonable way
>to avoid it.
So what you are proposing is to change drivers' code to use macro to iterate
through lists as step n1 and then change the iterator type as step n2 right?
If we would use my patch, we would have this done in single step. But I understand
that a kind of ugliness patch introduces is simply not acceptable not even for a
short time period, right?
Thanks
Jirka
^ permalink raw reply
* [PATCH v4 4/7] tcp: input header length, prediction, and timestamp bugs
From: William Allen Simpson @ 2010-02-02 16:28 UTC (permalink / raw)
To: Linux Kernel Developers, Linux Kernel Network Developers
Cc: Andrew Morton, Andi Kleen
In-Reply-To: <4B684DE7.3020601@gmail.com>
[-- Attachment #1: Type: text/plain, Size: 1871 bytes --]
Fix incorrect header prediction flags documentation.
Relieve register pressure in (the i386) fast path by accessing skb->len
directly, instead of carrying a rarely used len parameter.
Eliminate unused len parameters in two other functions.
Don't use output calculated tp->tcp_header_len for input decisions.
While the output header is usually the same as the input (same options
in both directions), that's a poor assumption. In particular, Sack will
be different. Newer options are not guaranteed.
Moreover, in the fast path, that only saved a shift or two. The other
efficiencies in this patch more than make up the difference.
Instead, use tp->rx_opt.tstamp_ok to accurately predict header length.
Likewise, use tp->rx_opt.tstamp_ok for received MSS calculations.
Don't use "sizeof(struct tcphdr) + TCPOLEN_TSTAMP_ALIGNED" to guess that
the timestamp is present. This may have been OK in the days with fewer
possible options, but various combinations of newer options may yield
the same header length. (This bug is in 3 places.)
Instead, use tp->rx_opt.saw_tstamp to determine a timestamp is present.
There's no need to test buffer length against header length, already
checked by tcp_v[4,6]_rcv(). Straighten code for minor efficiency gain.
Stand-alone patch, originally developed for TCPCT.
Requires:
net: tcp_header_len_th and tcp_option_len_th
tcp: harmonize tcp_vx_rcv header length assumptions
Signed-off-by: William.Allen.Simpson@gmail.com
CC: Andi Kleen <andi@firstfloor.org>
---
include/linux/tcp.h | 6 ++-
include/net/tcp.h | 15 +++++--
net/ipv4/tcp_input.c | 94 ++++++++++++++++++----------------------------
net/ipv4/tcp_ipv4.c | 4 +-
net/ipv4/tcp_minisocks.c | 3 +-
net/ipv4/tcp_probe.c | 2 +-
net/ipv6/tcp_ipv6.c | 4 +-
7 files changed, 58 insertions(+), 70 deletions(-)
[-- Attachment #2: len_th+2d4+2.6.33-rc6.patch --]
[-- Type: text/plain, Size: 9932 bytes --]
diff --git a/include/linux/tcp.h b/include/linux/tcp.h
index 74728f7..2987ee8 100644
--- a/include/linux/tcp.h
+++ b/include/linux/tcp.h
@@ -301,7 +301,11 @@ struct tcp_sock {
/*
* Header prediction flags
- * 0x5?10 << 16 + snd_wnd in net byte order
+ * S << 28 + TCP_FLAG_ACK + snd_wnd, in net byte order
+ * (PSH flag is ignored)
+ * S is 5 (no options), or 8 (timestamp aligned)
+ * otherwise, 0 to turn it off -- for instance, when there are
+ * holes in receive space.
*/
__be32 pred_flags;
diff --git a/include/net/tcp.h b/include/net/tcp.h
index 34f5cc2..6b0d7e9 100644
--- a/include/net/tcp.h
+++ b/include/net/tcp.h
@@ -310,13 +310,11 @@ extern int tcp_ioctl(struct sock *sk,
extern int tcp_rcv_state_process(struct sock *sk,
struct sk_buff *skb,
- struct tcphdr *th,
- unsigned len);
+ struct tcphdr *th);
extern int tcp_rcv_established(struct sock *sk,
struct sk_buff *skb,
- struct tcphdr *th,
- unsigned len);
+ struct tcphdr *th);
extern void tcp_rcv_space_adjust(struct sock *sk);
@@ -533,9 +531,16 @@ static inline u32 __tcp_set_rto(const struct tcp_sock *tp)
return (tp->srtt >> 3) + tp->rttvar;
}
+static inline u16 __tcp_fast_path_header_length(const struct tcp_sock *tp)
+{
+ return tp->rx_opt.tstamp_ok
+ ? sizeof(struct tcphdr) + TCPOLEN_TSTAMP_ALIGNED
+ : sizeof(struct tcphdr);
+}
+
static inline void __tcp_fast_path_on(struct tcp_sock *tp, u32 snd_wnd)
{
- tp->pred_flags = htonl((tp->tcp_header_len << 26) |
+ tp->pred_flags = htonl((__tcp_fast_path_header_length(tp) << (28 - 2)) |
ntohl(TCP_FLAG_ACK) |
snd_wnd);
}
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
index 28e0296..8e0f6ae 100644
--- a/net/ipv4/tcp_input.c
+++ b/net/ipv4/tcp_input.c
@@ -152,7 +152,7 @@ static void tcp_measure_rcv_mss(struct sock *sk, const struct sk_buff *skb)
* tcp header plus fixed timestamp option length.
* Resulting "len" is MSS free of SACK jitter.
*/
- len -= tcp_sk(sk)->tcp_header_len;
+ len -= __tcp_fast_path_header_length(tcp_sk(sk));
icsk->icsk_ack.last_seg_size = len;
if (len == lss) {
icsk->icsk_ack.rcv_mss = len;
@@ -5206,7 +5206,7 @@ discard:
* tcp_data_queue when everything is OK.
*/
int tcp_rcv_established(struct sock *sk, struct sk_buff *skb,
- struct tcphdr *th, unsigned len)
+ struct tcphdr *th)
{
struct tcp_sock *tp = tcp_sk(sk);
int res;
@@ -5225,31 +5225,15 @@ int tcp_rcv_established(struct sock *sk, struct sk_buff *skb,
* extra cost of the net_bh soft interrupt processing...
* We do checksum and copy also but from device to kernel.
*/
-
- tp->rx_opt.saw_tstamp = 0;
-
- /* pred_flags is 0xS?10 << 16 + snd_wnd
- * if header_prediction is to be made
- * 'S' will always be tp->tcp_header_len >> 2
- * '?' will be 0 for the fast path, otherwise pred_flags is 0 to
- * turn it off (when there are holes in the receive
- * space for instance)
- * PSH flag is ignored.
- */
-
if ((tcp_flag_word(th) & TCP_HP_BITS) == tp->pred_flags &&
TCP_SKB_CB(skb)->seq == tp->rcv_nxt &&
!after(TCP_SKB_CB(skb)->ack_seq, tp->snd_nxt)) {
- int tcp_header_len = tp->tcp_header_len;
-
- /* Timestamp header prediction: tcp_header_len
- * is automatically equal to th->doff*4 due to pred_flags
- * match.
- */
+ int tcp_header_len = tcp_header_len_th(th);
- /* Check timestamp */
- if (tcp_header_len == sizeof(struct tcphdr) + TCPOLEN_TSTAMP_ALIGNED) {
- /* No? Slow path! */
+ /* Timestamp header prediction */
+ if (tcp_header_len != sizeof(*th) + TCPOLEN_TSTAMP_ALIGNED) {
+ tp->rx_opt.saw_tstamp = 0; /* false */
+ } else {
if (!tcp_parse_aligned_timestamp(tp, th))
goto slow_path;
@@ -5264,35 +5248,12 @@ int tcp_rcv_established(struct sock *sk, struct sk_buff *skb,
*/
}
- if (len <= tcp_header_len) {
- /* Bulk data transfer: sender */
- if (len == tcp_header_len) {
- /* Predicted packet is in window by definition.
- * seq == rcv_nxt and rcv_wup <= rcv_nxt.
- * Hence, check seq<=rcv_wup reduces to:
- */
- if (tcp_header_len ==
- (sizeof(struct tcphdr) + TCPOLEN_TSTAMP_ALIGNED) &&
- tp->rcv_nxt == tp->rcv_wup)
- tcp_store_ts_recent(tp);
-
- /* We know that such packets are checksummed
- * on entry.
- */
- tcp_ack(sk, skb, 0);
- __kfree_skb(skb);
- tcp_data_snd_check(sk);
- return 0;
- } else { /* Header too small */
- TCP_INC_STATS_BH(sock_net(sk), TCP_MIB_INERRS);
- goto discard;
- }
- } else {
+ if (tcp_header_len < skb->len) {
int eaten = 0;
int copied_early = 0;
if (tp->copied_seq == tp->rcv_nxt &&
- len - tcp_header_len <= tp->ucopy.len) {
+ skb->len - tcp_header_len <= tp->ucopy.len) {
#ifdef CONFIG_NET_DMA
if (tcp_dma_try_early_copy(sk, skb, tcp_header_len)) {
copied_early = 1;
@@ -5311,9 +5272,7 @@ int tcp_rcv_established(struct sock *sk, struct sk_buff *skb,
* seq == rcv_nxt and rcv_wup <= rcv_nxt.
* Hence, check seq<=rcv_wup reduces to:
*/
- if (tcp_header_len ==
- (sizeof(struct tcphdr) +
- TCPOLEN_TSTAMP_ALIGNED) &&
+ if (tp->rx_opt.saw_tstamp &&
tp->rcv_nxt == tp->rcv_wup)
tcp_store_ts_recent(tp);
@@ -5334,8 +5293,7 @@ int tcp_rcv_established(struct sock *sk, struct sk_buff *skb,
* seq == rcv_nxt and rcv_wup <= rcv_nxt.
* Hence, check seq<=rcv_wup reduces to:
*/
- if (tcp_header_len ==
- (sizeof(struct tcphdr) + TCPOLEN_TSTAMP_ALIGNED) &&
+ if (tp->rx_opt.saw_tstamp &&
tp->rcv_nxt == tp->rcv_wup)
tcp_store_ts_recent(tp);
@@ -5376,11 +5334,33 @@ no_ack:
else
sk->sk_data_ready(sk, 0);
return 0;
+ } else {
+ /* Bulk data transfer: sender
+ *
+ * tcp_header_len > skb->len never happens,
+ * already checked by tcp_v[4,6]_rcv()
+ *
+ * Predicted packet is in window by definition.
+ * seq == rcv_nxt and rcv_wup <= rcv_nxt.
+ * Hence, check seq<=rcv_wup reduces to:
+ */
+ if (tp->rx_opt.saw_tstamp &&
+ tp->rcv_nxt == tp->rcv_wup)
+ tcp_store_ts_recent(tp);
+
+ /* We know that such packets are checksummed
+ * on entry.
+ */
+ tcp_ack(sk, skb, 0);
+ __kfree_skb(skb);
+ tcp_data_snd_check(sk);
+ return 0;
}
}
slow_path:
- if (len < (th->doff << 2) || tcp_checksum_complete_user(sk, skb))
+ /* Assumes header and options unchanged since checksum_init() */
+ if (tcp_checksum_complete_user(sk, skb))
goto csum_error;
/*
@@ -5416,7 +5396,7 @@ discard:
}
static int tcp_rcv_synsent_state_process(struct sock *sk, struct sk_buff *skb,
- struct tcphdr *th, unsigned len)
+ struct tcphdr *th)
{
u8 *hash_location;
struct inet_connection_sock *icsk = inet_csk(sk);
@@ -5693,7 +5673,7 @@ reset_and_undo:
*/
int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb,
- struct tcphdr *th, unsigned len)
+ struct tcphdr *th)
{
struct tcp_sock *tp = tcp_sk(sk);
struct inet_connection_sock *icsk = inet_csk(sk);
@@ -5740,7 +5720,7 @@ int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb,
goto discard;
case TCP_SYN_SENT:
- queued = tcp_rcv_synsent_state_process(sk, skb, th, len);
+ queued = tcp_rcv_synsent_state_process(sk, skb, th);
if (queued >= 0)
return queued;
diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
index 0a76e41..f999e06 100644
--- a/net/ipv4/tcp_ipv4.c
+++ b/net/ipv4/tcp_ipv4.c
@@ -1551,7 +1551,7 @@ int tcp_v4_do_rcv(struct sock *sk, struct sk_buff *skb)
if (sk->sk_state == TCP_ESTABLISHED) { /* Fast path */
TCP_CHECK_TIMER(sk);
- if (tcp_rcv_established(sk, skb, tcp_hdr(skb), skb->len)) {
+ if (tcp_rcv_established(sk, skb, tcp_hdr(skb))) {
rsk = sk;
goto reset;
}
@@ -1578,7 +1578,7 @@ int tcp_v4_do_rcv(struct sock *sk, struct sk_buff *skb)
}
TCP_CHECK_TIMER(sk);
- if (tcp_rcv_state_process(sk, skb, tcp_hdr(skb), skb->len)) {
+ if (tcp_rcv_state_process(sk, skb, tcp_hdr(skb))) {
rsk = sk;
goto reset;
}
diff --git a/net/ipv4/tcp_minisocks.c b/net/ipv4/tcp_minisocks.c
index f206ee5..37b7536 100644
--- a/net/ipv4/tcp_minisocks.c
+++ b/net/ipv4/tcp_minisocks.c
@@ -718,8 +718,7 @@ int tcp_child_process(struct sock *parent, struct sock *child,
int state = child->sk_state;
if (!sock_owned_by_user(child)) {
- ret = tcp_rcv_state_process(child, skb, tcp_hdr(skb),
- skb->len);
+ ret = tcp_rcv_state_process(child, skb, tcp_hdr(skb));
/* Wakeup parent, send SIGIO */
if (state == TCP_SYN_RECV && child->sk_state != state)
parent->sk_data_ready(parent, 0);
diff --git a/net/ipv4/tcp_probe.c b/net/ipv4/tcp_probe.c
index 9bc805d..de2a32e 100644
--- a/net/ipv4/tcp_probe.c
+++ b/net/ipv4/tcp_probe.c
@@ -88,7 +88,7 @@ static inline int tcp_probe_avail(void)
* Note: arguments must match tcp_rcv_established()!
*/
static int jtcp_rcv_established(struct sock *sk, struct sk_buff *skb,
- struct tcphdr *th, unsigned len)
+ struct tcphdr *th)
{
const struct tcp_sock *tp = tcp_sk(sk);
const struct inet_sock *inet = inet_sk(sk);
diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c
index b76939a..3d08a4d 100644
--- a/net/ipv6/tcp_ipv6.c
+++ b/net/ipv6/tcp_ipv6.c
@@ -1586,7 +1586,7 @@ static int tcp_v6_do_rcv(struct sock *sk, struct sk_buff *skb)
if (sk->sk_state == TCP_ESTABLISHED) { /* Fast path */
TCP_CHECK_TIMER(sk);
- if (tcp_rcv_established(sk, skb, tcp_hdr(skb), skb->len))
+ if (tcp_rcv_established(sk, skb, tcp_hdr(skb)))
goto reset;
TCP_CHECK_TIMER(sk);
if (opt_skb)
@@ -1618,7 +1618,7 @@ static int tcp_v6_do_rcv(struct sock *sk, struct sk_buff *skb)
}
TCP_CHECK_TIMER(sk);
- if (tcp_rcv_state_process(sk, skb, tcp_hdr(skb), skb->len))
+ if (tcp_rcv_state_process(sk, skb, tcp_hdr(skb)))
goto reset;
TCP_CHECK_TIMER(sk);
if (opt_skb)
--
1.6.3.3
^ permalink raw reply related
* netfilter 02/02: ctnetlink: fix expectation mask dump
From: Patrick McHardy @ 2010-02-02 16:27 UTC (permalink / raw)
To: davem; +Cc: netdev, Patrick McHardy, netfilter-devel
In-Reply-To: <20100202162736.24867.67227.sendpatchset@x2.localnet>
commit e578756c35859a459d78d8416195bc5f5ff897d0
Author: Patrick McHardy <kaber@trash.net>
Date: Tue Jan 26 17:04:02 2010 +0100
netfilter: ctnetlink: fix expectation mask dump
The protocol number is not initialized, so userspace can't interpret
the layer 4 data properly.
Signed-off-by: Patrick McHardy <kaber@trash.net>
diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c
index 59d8064..42f21c0 100644
--- a/net/netfilter/nf_conntrack_netlink.c
+++ b/net/netfilter/nf_conntrack_netlink.c
@@ -1437,8 +1437,9 @@ ctnetlink_exp_dump_mask(struct sk_buff *skb,
struct nlattr *nest_parms;
memset(&m, 0xFF, sizeof(m));
- m.src.u.all = mask->src.u.all;
memcpy(&m.src.u3, &mask->src.u3, sizeof(m.src.u3));
+ m.src.u.all = mask->src.u.all;
+ m.dst.protonum = tuple->dst.protonum;
nest_parms = nla_nest_start(skb, CTA_EXPECT_MASK | NLA_F_NESTED);
if (!nest_parms)
^ permalink raw reply related
* netfilter 01/02: nf_conntrack_sip: fix off-by-one in compact header parsing
From: Patrick McHardy @ 2010-02-02 16:27 UTC (permalink / raw)
To: davem; +Cc: netdev, Patrick McHardy, netfilter-devel
In-Reply-To: <20100202162736.24867.67227.sendpatchset@x2.localnet>
commit 135d01899b1fba17045961febff7e5141db6048f
Author: Patrick McHardy <kaber@trash.net>
Date: Tue Jan 19 19:06:59 2010 +0100
netfilter: nf_conntrack_sip: fix off-by-one in compact header parsing
In a string like "v:SIP/2.0..." it was checking for !isalpha('S') when it
meant to be inspecting the ':'.
Patch by Greg Alexander <greqcs@galexander.org>
Signed-off-by: Patrick McHardy <kaber@trash.net>
diff --git a/net/netfilter/nf_conntrack_sip.c b/net/netfilter/nf_conntrack_sip.c
index 4b57216..023966b 100644
--- a/net/netfilter/nf_conntrack_sip.c
+++ b/net/netfilter/nf_conntrack_sip.c
@@ -376,7 +376,7 @@ int ct_sip_get_header(const struct nf_conn *ct, const char *dptr,
dptr += hdr->len;
else if (hdr->cname && limit - dptr >= hdr->clen + 1 &&
strnicmp(dptr, hdr->cname, hdr->clen) == 0 &&
- !isalpha(*(dptr + hdr->clen + 1)))
+ !isalpha(*(dptr + hdr->clen)))
dptr += hdr->clen;
else
continue;
^ permalink raw reply related
* netfilter 00/02: netfilter fixes
From: Patrick McHardy @ 2010-02-02 16:27 UTC (permalink / raw)
To: davem; +Cc: netdev, Patrick McHardy, netfilter-devel
Hi Dave,
the following two patches fix two bugs in netfilter:
- an off-by-one in SIP conntrack short header parsing, causing mismatches
with UAs not inserting a space after the colon
- a missing initialization in ctnetlink when dumping an expectation mask,
causing an invalid layer 4 protocol number to be used
Please apply or pull from:
git://git.kernel.org/pub/scm/linux/kernel/git/kaber/nf-2.6.git master
Thanks!
net/netfilter/nf_conntrack_netlink.c | 3 ++-
net/netfilter/nf_conntrack_sip.c | 2 +-
2 files changed, 3 insertions(+), 2 deletions(-)
Patrick McHardy (2):
netfilter: nf_conntrack_sip: fix off-by-one in compact header parsing
netfilter: ctnetlink: fix expectation mask dump
^ permalink raw reply
* [PATCH v5 3/7] tcp: harmonize tcp_vx_rcv header length assumptions
From: William Allen Simpson @ 2010-02-02 16:24 UTC (permalink / raw)
To: Linux Kernel Developers, Linux Kernel Network Developers
Cc: Andrew Morton, Andi Kleen
In-Reply-To: <4B684DE7.3020601@gmail.com>
[-- Attachment #1: Type: text/plain, Size: 825 bytes --]
Harmonize tcp_v4_rcv() and tcp_v6_rcv() -- better document tcp doff
and header length assumptions, and carefully compare implementations.
Reduces multiply/shifts, marginally improving speed.
Removes redundant tcp header length checks before checksumming.
Instead, assumes (and documents) that any backlog processing and
transform policies will carefully preserve the header, and will
ensure the socket buffer length remains >= the header size.
Stand-alone patch, originally developed for TCPCT.
Signed-off-by: William.Allen.Simpson@gmail.com
CC: Andi Kleen <andi@firstfloor.org>
---
include/net/xfrm.h | 7 ++++++
net/ipv4/tcp_ipv4.c | 45 +++++++++++++++++++++-----------------
net/ipv6/tcp_ipv6.c | 59 ++++++++++++++++++++++++++++----------------------
3 files changed, 65 insertions(+), 46 deletions(-)
[-- Attachment #2: len_th+2c5+2.6.33-rc6.patch --]
[-- Type: text/plain, Size: 8037 bytes --]
diff --git a/include/net/xfrm.h b/include/net/xfrm.h
index 60c2770..81492a1 100644
--- a/include/net/xfrm.h
+++ b/include/net/xfrm.h
@@ -975,6 +975,13 @@ xfrm_state_addr_cmp(struct xfrm_tmpl *tmpl, struct xfrm_state *x, unsigned short
}
#ifdef CONFIG_XFRM
+/*
+ * For transport, the policy is checked before the presumed more expensive
+ * checksum. The transport header has already been checked for size, and is
+ * guaranteed to be contiguous. These policies must not alter the header or
+ * its position in the buffer, and should not shorten the buffer length
+ * without ensuring the length remains >= the header size.
+ */
extern int __xfrm_policy_check(struct sock *, int dir, struct sk_buff *skb, unsigned short family);
static inline int __xfrm_policy_check2(struct sock *sk, int dir,
diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
index 65b8ebf..0a76e41 100644
--- a/net/ipv4/tcp_ipv4.c
+++ b/net/ipv4/tcp_ipv4.c
@@ -1559,7 +1559,8 @@ int tcp_v4_do_rcv(struct sock *sk, struct sk_buff *skb)
return 0;
}
- if (skb->len < tcp_hdrlen(skb) || tcp_checksum_complete(skb))
+ /* Assumes header and options unchanged since checksum_init() */
+ if (tcp_checksum_complete(skb))
goto csum_err;
if (sk->sk_state == TCP_LISTEN) {
@@ -1601,14 +1602,13 @@ csum_err:
}
/*
- * From tcp_input.c
+ * Called by ip_input.c: ip_local_deliver_finish()
*/
-
int tcp_v4_rcv(struct sk_buff *skb)
{
- const struct iphdr *iph;
struct tcphdr *th;
struct sock *sk;
+ int tcp_header_len;
int ret;
struct net *net = dev_net(skb->dev);
@@ -1618,31 +1618,33 @@ int tcp_v4_rcv(struct sk_buff *skb)
/* Count it even if it's bad */
TCP_INC_STATS_BH(net, TCP_MIB_INSEGS);
+ /* Check too short header */
if (!pskb_may_pull(skb, sizeof(struct tcphdr)))
goto discard_it;
- th = tcp_hdr(skb);
-
- if (th->doff < sizeof(struct tcphdr) / 4)
+ /* Check bad doff, compare doff directly to constant value */
+ tcp_header_len = tcp_hdr(skb)->doff;
+ if (tcp_header_len < (sizeof(struct tcphdr) / 4))
goto bad_packet;
- if (!pskb_may_pull(skb, th->doff * 4))
+
+ /* Check too short header and options */
+ tcp_header_len *= 4;
+ if (!pskb_may_pull(skb, tcp_header_len))
goto discard_it;
- /* An explanation is required here, I think.
- * Packet length and doff are validated by header prediction,
- * provided case of th->doff==0 is eliminated.
- * So, we defer the checks. */
+ /* Packet length and doff are validated by header prediction,
+ * provided case of th->doff == 0 is eliminated (above).
+ */
if (!skb_csum_unnecessary(skb) && tcp_v4_checksum_init(skb))
goto bad_packet;
th = tcp_hdr(skb);
- iph = ip_hdr(skb);
TCP_SKB_CB(skb)->seq = ntohl(th->seq);
TCP_SKB_CB(skb)->end_seq = (TCP_SKB_CB(skb)->seq + th->syn + th->fin +
- skb->len - th->doff * 4);
+ skb->len - tcp_header_len);
TCP_SKB_CB(skb)->ack_seq = ntohl(th->ack_seq);
TCP_SKB_CB(skb)->when = 0;
- TCP_SKB_CB(skb)->flags = iph->tos;
+ TCP_SKB_CB(skb)->flags = ip_hdr(skb)->tos;
TCP_SKB_CB(skb)->sacked = 0;
sk = __inet_lookup_skb(&tcp_hashinfo, skb, th->source, th->dest);
@@ -1682,14 +1684,14 @@ process:
bh_unlock_sock(sk);
sock_put(sk);
-
return ret;
no_tcp_socket:
if (!xfrm4_policy_check(NULL, XFRM_POLICY_IN, skb))
goto discard_it;
- if (skb->len < (th->doff << 2) || tcp_checksum_complete(skb)) {
+ /* Assumes header and options unchanged since checksum_init() */
+ if (tcp_checksum_complete(skb)) {
bad_packet:
TCP_INC_STATS_BH(net, TCP_MIB_INERRS);
} else {
@@ -1711,18 +1713,21 @@ do_time_wait:
goto discard_it;
}
- if (skb->len < (th->doff << 2) || tcp_checksum_complete(skb)) {
+ /* Assumes header and options unchanged since checksum_init() */
+ if (tcp_checksum_complete(skb)) {
TCP_INC_STATS_BH(net, TCP_MIB_INERRS);
inet_twsk_put(inet_twsk(sk));
goto discard_it;
}
+
switch (tcp_timewait_state_process(inet_twsk(sk), skb, th)) {
case TCP_TW_SYN: {
struct sock *sk2 = inet_lookup_listener(dev_net(skb->dev),
&tcp_hashinfo,
- iph->daddr, th->dest,
+ ip_hdr(skb)->daddr,
+ th->dest,
inet_iif(skb));
- if (sk2) {
+ if (sk2 != NULL) {
inet_twsk_deschedule(inet_twsk(sk), &tcp_death_row);
inet_twsk_put(inet_twsk(sk));
sk = sk2;
diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c
index febfd59..b76939a 100644
--- a/net/ipv6/tcp_ipv6.c
+++ b/net/ipv6/tcp_ipv6.c
@@ -1594,7 +1594,8 @@ static int tcp_v6_do_rcv(struct sock *sk, struct sk_buff *skb)
return 0;
}
- if (skb->len < tcp_hdrlen(skb) || tcp_checksum_complete(skb))
+ /* Assumes header and options unchanged since checksum_init() */
+ if (tcp_checksum_complete(skb))
goto csum_err;
if (sk->sk_state == TCP_LISTEN) {
@@ -1664,38 +1665,47 @@ ipv6_pktoptions:
return 0;
}
+/*
+ * Called by ip6_input.c: ip6_input_finish()
+ */
static int tcp_v6_rcv(struct sk_buff *skb)
{
struct tcphdr *th;
struct sock *sk;
+ int tcp_header_len;
int ret;
struct net *net = dev_net(skb->dev);
if (skb->pkt_type != PACKET_HOST)
goto discard_it;
- /*
- * Count it even if it's bad.
- */
+ /* Count it even if it's bad */
TCP_INC_STATS_BH(net, TCP_MIB_INSEGS);
+ /* Check too short header */
if (!pskb_may_pull(skb, sizeof(struct tcphdr)))
goto discard_it;
- th = tcp_hdr(skb);
-
- if (th->doff < sizeof(struct tcphdr)/4)
+ /* Check bad doff, compare doff directly to constant value */
+ tcp_header_len = tcp_hdr(skb)->doff;
+ if (tcp_header_len < (sizeof(struct tcphdr) / 4))
goto bad_packet;
- if (!pskb_may_pull(skb, th->doff*4))
+
+ /* Check too short header and options */
+ tcp_header_len *= 4;
+ if (!pskb_may_pull(skb, tcp_header_len))
goto discard_it;
+ /* Packet length and doff are validated by header prediction,
+ * provided case of th->doff == 0 is eliminated (above).
+ */
if (!skb_csum_unnecessary(skb) && tcp_v6_checksum_init(skb))
goto bad_packet;
th = tcp_hdr(skb);
TCP_SKB_CB(skb)->seq = ntohl(th->seq);
TCP_SKB_CB(skb)->end_seq = (TCP_SKB_CB(skb)->seq + th->syn + th->fin +
- skb->len - th->doff*4);
+ skb->len - tcp_header_len);
TCP_SKB_CB(skb)->ack_seq = ntohl(th->ack_seq);
TCP_SKB_CB(skb)->when = 0;
TCP_SKB_CB(skb)->flags = ipv6_get_dsfield(ipv6_hdr(skb));
@@ -1711,6 +1721,7 @@ process:
if (!xfrm6_policy_check(sk, XFRM_POLICY_IN, skb))
goto discard_and_relse;
+ /* nf_reset(skb); in ip6_input.c ip6_input_finish() */
if (sk_filter(sk, skb))
goto discard_and_relse;
@@ -1743,7 +1754,8 @@ no_tcp_socket:
if (!xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb))
goto discard_it;
- if (skb->len < (th->doff<<2) || tcp_checksum_complete(skb)) {
+ /* Assumes header and options unchanged since checksum_init() */
+ if (tcp_checksum_complete(skb)) {
bad_packet:
TCP_INC_STATS_BH(net, TCP_MIB_INERRS);
} else {
@@ -1751,11 +1763,7 @@ bad_packet:
}
discard_it:
-
- /*
- * Discard frame
- */
-
+ /* Discard frame. */
kfree_skb(skb);
return 0;
@@ -1769,24 +1777,23 @@ do_time_wait:
goto discard_it;
}
- if (skb->len < (th->doff<<2) || tcp_checksum_complete(skb)) {
+ /* Assumes header and options unchanged since checksum_init() */
+ if (tcp_checksum_complete(skb)) {
TCP_INC_STATS_BH(net, TCP_MIB_INERRS);
inet_twsk_put(inet_twsk(sk));
goto discard_it;
}
switch (tcp_timewait_state_process(inet_twsk(sk), skb, th)) {
- case TCP_TW_SYN:
- {
- struct sock *sk2;
-
- sk2 = inet6_lookup_listener(dev_net(skb->dev), &tcp_hashinfo,
- &ipv6_hdr(skb)->daddr,
- ntohs(th->dest), inet6_iif(skb));
+ case TCP_TW_SYN: {
+ struct sock *sk2 = inet6_lookup_listener(dev_net(skb->dev),
+ &tcp_hashinfo,
+ &ipv6_hdr(skb)->daddr,
+ ntohs(th->dest),
+ inet6_iif(skb));
if (sk2 != NULL) {
- struct inet_timewait_sock *tw = inet_twsk(sk);
- inet_twsk_deschedule(tw, &tcp_death_row);
- inet_twsk_put(tw);
+ inet_twsk_deschedule(inet_twsk(sk), &tcp_death_row);
+ inet_twsk_put(inet_twsk(sk));
sk = sk2;
goto process;
}
--
1.6.3.3
^ permalink raw reply related
* transmit timed out with tulip on sparc64
From: Meelis Roos @ 2010-02-02 15:51 UTC (permalink / raw)
To: netdev, sparclinux
(Found a postponed mesasage from some time ago and restested - still a
problem with 2.6.33-rc6)
I have a Sun Fire V100 running bleeding-edge kernels.
I usually do not transfer large amounts of data - updating debian
unstable is the most stressing one. However, today I tried to copy
gigabytes of data over scp to this machine and it dropped out of the
network. Reson unknown, attaching serial console after that gave the
following transmit timeout message that may or may not be the primary
reason.
2.6.32-rc3-00052-g0eca52a:
[130930.573930] ------------[ cut here ]------------
[130930.635834] WARNING: at net/sched/sch_generic.c:261 dev_watchdog+0x258/0x280()
[130930.731919] NETDEV WATCHDOG: eth0 (tulip): transmit queue 0 timed out
[130930.817722] Modules linked in: ipv6 fuse loop usbhid ohci_hcd sg sr_mod usbcore cdrom
[130930.921905] Call Trace:
[130930.955091] [0000000000454230] warn_slowpath_common+0x50/0xa0
[130931.032922] [00000000004542f4] warn_slowpath_fmt+0x34/0x60
[130931.107316] [000000000064a658] dev_watchdog+0x258/0x280
[130931.178289] [000000000045f6f4] run_timer_softirq+0x1b4/0x240
[130931.254975] [000000000045a484] __do_softirq+0xa4/0x140
[130931.324798] [000000000042a93c] do_softirq+0x7c/0xa0
[130931.391189] [000000000045a0cc] irq_exit+0x8c/0xc0
[130931.455303] [000000000042fcc4] timer_interrupt+0x64/0xa0
[130931.527412] [00000000004209d4] tl0_irq14+0x14/0x20
[130931.592671] [000000000043af60] touch_nmi_watchdog+0x0/0x60
[130931.667064] [00000000006b59a8] rest_init+0x68/0x80
[130931.732321] [00000000008247c4] start_kernel+0x2ac/0x2e8
[130931.803280] [00000000006b5924] tlb_fixup_done+0x80/0x9c
[130931.874243] [0000000000000000] (null)
[130931.924635] ---[ end trace 70d1b6d12c0cb235 ]---
I restared the computer and reran the test to see whether something
appears on the console before - no, it doesn't, this is the first log
snippet and is basically the same.
[ 105.701102] eth0: no IPv6 routers present
[ 473.311090] ------------[ cut here ]------------
[ 473.371799] WARNING: at net/sched/sch_generic.c:261 dev_watchdog+0x258/0x280()
[ 473.466747] NETDEV WATCHDOG: eth0 (tulip): transmit queue 0 timed out
[ 473.551407] Modules linked in: ipv6 fuse loop usbhid ohci_hcd sg sr_mod cdrom usbcore
[ 473.654446] Call Trace:
[ 473.686491] [0000000000454230] warn_slowpath_common+0x50/0xa0
[ 473.763176] [00000000004542f4] warn_slowpath_fmt+0x34/0x60
[ 473.836430] [000000000064a658] dev_watchdog+0x258/0x280
[ 473.906265] [000000000045f6f4] run_timer_softirq+0x1b4/0x240
[ 473.981806] [000000000045a484] __do_softirq+0xa4/0x140
[ 474.050479] [000000000042a93c] do_softirq+0x7c/0xa0
[ 474.115728] [000000000045a0cc] irq_exit+0x8c/0xc0
[ 474.178699] [000000000042fcc4] timer_interrupt+0x64/0xa0
[ 474.249666] [00000000004209d4] tl0_irq14+0x14/0x20
[ 474.313784] [0000000000590c80] mcount+0xc0/0xe0
[ 474.374457] [000000000042c94c] cpu_idle+0x4c/0x100
[ 474.438568] [00000000006b59a8] rest_init+0x68/0x80
[ 474.502683] [00000000008247c4] start_kernel+0x2ac/0x2e8
[ 474.572503] [00000000006b5924] tlb_fixup_done+0x80/0x9c
[ 474.642320] [0000000000000000] (null)
Now verified that the same happens with selfcompiled 2.6.31.
Freshly tested that it also happens with 2.6.33-rc6:
[247694.931852] ------------[ cut here ]------------
[247694.993771] WARNING: at net/sched/sch_generic.c:255 dev_watchdog+0x240/0x260()
[247695.089865] NETDEV WATCHDOG: eth0 (tulip): transmit queue 0 timed out
[247695.175667] Modules linked in: ipv6 fuse loop ohci_hcd sg sr_mod usbcore cdrom
[247695.271857] Call Trace:
[247695.305135] [0000000000454aac] warn_slowpath_common+0x4c/0x80
[247695.382967] [0000000000454b4c] warn_slowpath_fmt+0x2c/0x40
[247695.457360] [0000000000645160] dev_watchdog+0x240/0x260
[247695.528334] [000000000046008c] run_timer_softirq+0x18c/0x240
[247695.605020] [000000000045abb8] __do_softirq+0x98/0x140
[247695.674842] [000000000042a758] do_softirq+0x78/0xa0
[247695.741234] [000000000045a830] irq_exit+0x90/0xa0
[247695.805347] [000000000042f860] timer_interrupt+0x60/0xa0
[247695.877460] [00000000004209d4] tl0_irq14+0x14/0x20
[247695.942710] [000000000058b944] mcount+0x4/0xe0
[247696.003387] [000000000042c764] cpu_idle+0x44/0xe0
[247696.067502] [00000000006b025c] rest_init+0x5c/0x80
[247696.132758] [0000000000810794] start_kernel+0x2d4/0x2e4
[247696.203720] [00000000006b01e4] tlb_fixup_done+0x80/0x9c
[247696.274682] [0000000000000000] (null)
[247696.325070] ---[ end trace 27a08f024f3aa132 ]---
--
Meelis Roos (mroos@linux.ee)
^ permalink raw reply
* [PATCH 2/7] net: remove old tcp_optlen function
From: William Allen Simpson @ 2010-02-02 16:17 UTC (permalink / raw)
To: Linux Kernel Developers, Linux Kernel Network Developers
Cc: Andrew Morton, Michael Chan
In-Reply-To: <4B684DE7.3020601@gmail.com>
[-- Attachment #1: Type: text/plain, Size: 1081 bytes --]
The tcp_optlen() function returns a potential *negative* unsigned.
In the only two existing files using the old tcp_optlen() function,
clean up confusing and inconsistent mixing of both byte and word
offsets, and other coding style issues. Document assumptions.
Quoth David Miller:
This is transmit, and the packets can only come from the Linux
TCP stack, not some external entity.
You're being way too anal here, and adding these checks to
drivers would be just a lot of rediculious bloat. [sic]
Therefore, there are *no* checks for bad TCP and IP header sizes, nor
any semantic changes. The drivers should function exactly as existing.
Untested. No response from testers in 15+ weeks.
Requires:
net: tcp_header_len_th and tcp_option_len_th
Signed-off-by: William.Allen.Simpson@gmail.com
CC: Michael Chan <mchan@broadcom.com>
---
drivers/net/bnx2.c | 29 +++++++++++++-----------
drivers/net/tg3.c | 60 +++++++++++++++++++++++---------------------------
include/linux/tcp.h | 5 ----
3 files changed, 44 insertions(+), 50 deletions(-)
[-- Attachment #2: len_th+2b3+2.6.33-rc6.patch --]
[-- Type: text/plain, Size: 6936 bytes --]
diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c
index 65df1de..45452c5 100644
--- a/drivers/net/bnx2.c
+++ b/drivers/net/bnx2.c
@@ -6352,6 +6352,8 @@ bnx2_vlan_rx_register(struct net_device *dev, struct vlan_group *vlgrp)
/* Called with netif_tx_lock.
* bnx2_tx_int() runs without netif_tx_lock unless it needs to call
* netif_wake_queue().
+ *
+ * No TCP or IP length checking, per David Miller (see commit log).
*/
static netdev_tx_t
bnx2_start_xmit(struct sk_buff *skb, struct net_device *dev)
@@ -6396,19 +6398,19 @@ bnx2_start_xmit(struct sk_buff *skb, struct net_device *dev)
(TX_BD_FLAGS_VLAN_TAG | (vlan_tx_tag_get(skb) << 16));
}
#endif
- if ((mss = skb_shinfo(skb)->gso_size)) {
- u32 tcp_opt_len;
- struct iphdr *iph;
+ mss = skb_shinfo(skb)->gso_size;
+ if (mss != 0) {
+ struct tcphdr *th = tcp_hdr(skb);
+ int tcp_opt_words = th->doff - (sizeof(*th) >> 2);
+ /* assumes positive tcp_opt_words without checking */
vlan_tag_flags |= TX_BD_FLAGS_SW_LSO;
- tcp_opt_len = tcp_optlen(skb);
-
if (skb_shinfo(skb)->gso_type & SKB_GSO_TCPV6) {
u32 tcp_off = skb_transport_offset(skb) -
sizeof(struct ipv6hdr) - ETH_HLEN;
- vlan_tag_flags |= ((tcp_opt_len >> 2) << 8) |
+ vlan_tag_flags |= (tcp_opt_words << 8) |
TX_BD_FLAGS_SW_FLAGS;
if (likely(tcp_off == 0))
vlan_tag_flags &= ~TX_BD_FLAGS_TCP6_OFF0_MSK;
@@ -6421,14 +6423,15 @@ bnx2_start_xmit(struct sk_buff *skb, struct net_device *dev)
mss |= (tcp_off & 0xc) << TX_BD_TCP6_OFF2_SHL;
}
} else {
- iph = ip_hdr(skb);
- if (tcp_opt_len || (iph->ihl > 5)) {
- vlan_tag_flags |= ((iph->ihl - 5) +
- (tcp_opt_len >> 2)) << 8;
- }
+ struct iphdr *iph = ip_hdr(skb);
+ int ip_opt_words = iph->ihl - (sizeof(*iph) >> 2);
+ /* assumes positive ip_opt_words without checking */
+ int opt_words = ip_opt_words + tcp_opt_words;
+
+ if (opt_words > 0)
+ vlan_tag_flags |= opt_words << 8;
}
- } else
- mss = 0;
+ }
mapping = pci_map_single(bp->pdev, skb->data, len, PCI_DMA_TODEVICE);
if (pci_dma_mapping_error(bp->pdev, mapping)) {
diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c
index 7f82b02..c20c800 100644
--- a/drivers/net/tg3.c
+++ b/drivers/net/tg3.c
@@ -5426,6 +5426,8 @@ static void tg3_set_txd(struct tg3_napi *tnapi, int entry,
/* hard_start_xmit for devices that don't have any bugs and
* support TG3_FLG2_HW_TSO_2 and TG3_FLG2_HW_TSO_3 only.
+ *
+ * No TCP or IP length checking, per David Miller (see commit log).
*/
static netdev_tx_t tg3_start_xmit(struct sk_buff *skb,
struct net_device *dev)
@@ -5461,9 +5463,9 @@ static netdev_tx_t tg3_start_xmit(struct sk_buff *skb,
entry = tnapi->tx_prod;
base_flags = 0;
- mss = 0;
- if ((mss = skb_shinfo(skb)->gso_size) != 0) {
- int tcp_opt_len, ip_tcp_len;
+ mss = skb_shinfo(skb)->gso_size;
+ if (mss != 0) {
+ struct tcphdr *th;
u32 hdrlen;
if (skb_header_cloned(skb) &&
@@ -5471,18 +5473,16 @@ static netdev_tx_t tg3_start_xmit(struct sk_buff *skb,
dev_kfree_skb(skb);
goto out_unlock;
}
+ th = tcp_hdr(skb);
if (skb_shinfo(skb)->gso_type & SKB_GSO_TCPV6)
hdrlen = skb_headlen(skb) - ETH_HLEN;
else {
struct iphdr *iph = ip_hdr(skb);
- tcp_opt_len = tcp_optlen(skb);
- ip_tcp_len = ip_hdrlen(skb) + sizeof(struct tcphdr);
-
+ hdrlen = ip_hdrlen(skb) + tcp_header_len_th(th);
+ iph->tot_len = htons(mss + hdrlen);
iph->check = 0;
- iph->tot_len = htons(mss + ip_tcp_len + tcp_opt_len);
- hdrlen = ip_tcp_len + tcp_opt_len;
}
if (tp->tg3_flags2 & TG3_FLG2_HW_TSO_3) {
@@ -5496,7 +5496,7 @@ static netdev_tx_t tg3_start_xmit(struct sk_buff *skb,
base_flags |= (TXD_FLAG_CPU_PRE_DMA |
TXD_FLAG_CPU_POST_DMA);
- tcp_hdr(skb)->check = 0;
+ th->check = 0;
}
else if (skb->ip_summed == CHECKSUM_PARTIAL)
@@ -5629,6 +5629,8 @@ tg3_tso_bug_end:
/* hard_start_xmit for devices that have the 4G bug and/or 40-bit bug and
* support TG3_FLG2_HW_TSO_1 or firmware TSO only.
+ *
+ * No TCP or IP length checking, per David Miller (see commit log).
*/
static netdev_tx_t tg3_start_xmit_dma_bug(struct sk_buff *skb,
struct net_device *dev)
@@ -5668,20 +5670,21 @@ static netdev_tx_t tg3_start_xmit_dma_bug(struct sk_buff *skb,
if (skb->ip_summed == CHECKSUM_PARTIAL)
base_flags |= TXD_FLAG_TCPUDP_CSUM;
- if ((mss = skb_shinfo(skb)->gso_size) != 0) {
+ mss = skb_shinfo(skb)->gso_size;
+ if (mss != 0) {
struct iphdr *iph;
- u32 tcp_opt_len, ip_tcp_len, hdr_len;
+ struct tcphdr *th;
+ u32 hdr_len;
+ int opt_bytes;
if (skb_header_cloned(skb) &&
pskb_expand_head(skb, 0, 0, GFP_ATOMIC)) {
dev_kfree_skb(skb);
goto out_unlock;
}
+ th = tcp_hdr(skb);
+ hdr_len = ip_hdrlen(skb) + tcp_header_len_th(th);
- tcp_opt_len = tcp_optlen(skb);
- ip_tcp_len = ip_hdrlen(skb) + sizeof(struct tcphdr);
-
- hdr_len = ip_tcp_len + tcp_opt_len;
if (unlikely((ETH_HLEN + hdr_len) > 80) &&
(tp->tg3_flags2 & TG3_FLG2_TSO_BUG))
return (tg3_tso_bug(tp, skb));
@@ -5693,13 +5696,14 @@ static netdev_tx_t tg3_start_xmit_dma_bug(struct sk_buff *skb,
iph->check = 0;
iph->tot_len = htons(mss + hdr_len);
if (tp->tg3_flags2 & TG3_FLG2_HW_TSO) {
- tcp_hdr(skb)->check = 0;
+ th->check = 0;
base_flags &= ~TXD_FLAG_TCPUDP_CSUM;
} else
- tcp_hdr(skb)->check = ~csum_tcpudp_magic(iph->saddr,
- iph->daddr, 0,
- IPPROTO_TCP,
- 0);
+ th->check = ~csum_tcpudp_magic(iph->saddr, iph->daddr,
+ 0, IPPROTO_TCP, 0);
+
+ opt_bytes = hdr_len - sizeof(*iph) - sizeof(*th);
+ /* assumes positive opt_bytes without checking */
if (tp->tg3_flags2 & TG3_FLG2_HW_TSO_3) {
mss |= (hdr_len & 0xc) << 12;
@@ -5710,19 +5714,11 @@ static netdev_tx_t tg3_start_xmit_dma_bug(struct sk_buff *skb,
mss |= hdr_len << 9;
else if ((tp->tg3_flags2 & TG3_FLG2_HW_TSO_1) ||
GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705) {
- if (tcp_opt_len || iph->ihl > 5) {
- int tsflags;
-
- tsflags = (iph->ihl - 5) + (tcp_opt_len >> 2);
- mss |= (tsflags << 11);
- }
+ if (opt_bytes > 0)
+ mss |= opt_bytes << (11 - 2);
} else {
- if (tcp_opt_len || iph->ihl > 5) {
- int tsflags;
-
- tsflags = (iph->ihl - 5) + (tcp_opt_len >> 2);
- base_flags |= tsflags << 12;
- }
+ if (opt_bytes > 0)
+ base_flags |= opt_bytes << (12 - 2);
}
}
#if TG3_VLAN_TAG_USED
diff --git a/include/linux/tcp.h b/include/linux/tcp.h
index d0133cf..74728f7 100644
--- a/include/linux/tcp.h
+++ b/include/linux/tcp.h
@@ -218,11 +218,6 @@ static inline unsigned int tcp_hdrlen(const struct sk_buff *skb)
return tcp_hdr(skb)->doff * 4;
}
-static inline unsigned int tcp_optlen(const struct sk_buff *skb)
-{
- return (tcp_hdr(skb)->doff - 5) * 4;
-}
-
/* Length of fixed header plus standard options. */
static inline unsigned int tcp_header_len_th(const struct tcphdr *th)
{
--
1.6.3.3
^ permalink raw reply related
* [PATCH 1/7] net: tcp_header_len_th and tcp_option_len_th
From: William Allen Simpson @ 2010-02-02 16:12 UTC (permalink / raw)
To: Linux Kernel Developers, Linux Kernel Network Developers; +Cc: Andrew Morton
In-Reply-To: <4B684DE7.3020601@gmail.com>
[-- Attachment #1: Type: text/plain, Size: 359 bytes --]
Redefine two TCP header functions to accept TCP header pointer.
When subtracting, return signed int to allow error checking.
These functions will be used in subsequent patches that implement
additional features.
Signed-off-by: William.Allen.Simpson@gmail.com
---
include/linux/tcp.h | 12 ++++++++++++
1 files changed, 12 insertions(+), 0 deletions(-)
[-- Attachment #2: len_th+2a3+2.6.33-rc6.patch --]
[-- Type: text/plain, Size: 719 bytes --]
diff --git a/include/linux/tcp.h b/include/linux/tcp.h
index 7fee8a4..d0133cf 100644
--- a/include/linux/tcp.h
+++ b/include/linux/tcp.h
@@ -223,6 +223,18 @@ static inline unsigned int tcp_optlen(const struct sk_buff *skb)
return (tcp_hdr(skb)->doff - 5) * 4;
}
+/* Length of fixed header plus standard options. */
+static inline unsigned int tcp_header_len_th(const struct tcphdr *th)
+{
+ return th->doff * 4;
+}
+
+/* Length of standard options only. This could be negative. */
+static inline int tcp_option_len_th(const struct tcphdr *th)
+{
+ return (int)(th->doff * 4) - sizeof(*th);
+}
+
/* This defines a selective acknowledgement block. */
struct tcp_sack_block_wire {
__be32 start_seq;
--
1.6.3.3
^ permalink raw reply related
* [PATCH 0/7] tcp: bugs and cleanup updated to 2.6.33-rc6
From: William Allen Simpson @ 2010-02-02 16:08 UTC (permalink / raw)
To: Linux Kernel Developers, Linux Kernel Network Developers; +Cc: Andrew Morton
Combination of patches reported in October, November, December, and
January. These patches fix perceived bugs, and other cleanup.
This code has had previous review and several months of limited testing.
Some portions were removed during the various TCPCT part 1 patch splits,
then were cut off by the sudden unexpected end of that merge window.
[03 Dec 2009] I've restarted the sub-numbering (again).
Of particular interest are the TCPCT header extensions that already
appear in the next phase of testing with other platforms. These patches
allow correct reception without data corruption.
The remainder of the original TCPCT part 2 will be merged with part 3.
These patches are against the current linux-2.6 tree.
[No substantive changes from previous submission of January 23rd.]
^ permalink raw reply
* Re: [PATCH net-next-2.6] net: use helpers to access mc list
From: David Miller @ 2010-02-02 16:06 UTC (permalink / raw)
To: jpirko; +Cc: netdev
In-Reply-To: <20100202160347.GB2601@psychotron.lab.eng.brq.redhat.com>
From: Jiri Pirko <jpirko@redhat.com>
Date: Tue, 2 Feb 2010 17:03:48 +0100
> You mean "struct dev_mc_list"? But that would solve nothing. If I would still
> use current structure in drivers, then still the migration to struct_hw_addr
> would be all-at-once for all drivers :( This patch was exacly made to avoid
> this.
I think changing the iterator type will have to be done
wholesale in one changeset, there is no reasonable way
to avoid it.
^ permalink raw reply
* Re: [PATCH net-next-2.6] net: use helpers to access mc list
From: Jiri Pirko @ 2010-02-02 16:03 UTC (permalink / raw)
To: David Miller; +Cc: netdev
In-Reply-To: <20100202.072533.52179643.davem@davemloft.net>
Tue, Feb 02, 2010 at 04:25:33PM CET, davem@davemloft.net wrote:
>From: Jiri Pirko <jpirko@redhat.com>
>Date: Tue, 26 Jan 2010 15:57:39 +0100
>
>> Temporary macro "netdev_for_each_mc_addr" works in the ugly way, I'm aware, but
>> it will be replaced. It uses iterator stored in "struct net_device". In every
>> iteration, it copies addr from the list to "struct netdev_hw_addr" instance
>> (also stored in "struct net_device"). Driver reads address stored in this
>> structure. All is protected by addr_list_lock held by a caller.
>
>This kind of ugly hack is rarely necessary, so I'm not applying
>this, sorry.
Well, I admit it's ugly but it's only temporary. It would go away once all
drivers would be converted to use it (a matter of weeks/month tops I hope).
>
>In the macros, use the iterator type the driver instances already use,
>which is the mcaddr entry pointer.
You mean "struct dev_mc_list"? But that would solve nothing. If I would still
use current structure in drivers, then still the migration to struct_hw_addr
would be all-at-once for all drivers :( This patch was exacly made to avoid
this.
>
>Then by using list_for_each_entry() things should "just work".
Maybe I do not uderstand you correctly. Would you please explain?
Thanks a lot.
Jirka
^ permalink raw reply
* Re: [PATCH] be2net: use eq-id to calculate cev-isr reg offset
From: David Miller @ 2010-02-02 15:48 UTC (permalink / raw)
To: sathyap; +Cc: netdev
In-Reply-To: <20100129070836.GA21744@serverengines.com>
From: Sathya Perla <sathyap@serverengines.com>
Date: Fri, 29 Jan 2010 12:38:36 +0530
> cev-isr reg offset for each function is better calculated using (any) eq-id
> alloted to that function instead of using pci-func number(which
> does not work in some configurations...)
>
> Signed-off-by: Sathya Perla <sathyap@serverengines.com>
Applied to net-2.6, thanks.
^ permalink raw reply
* Re: [PATCH v2] net/irda: sh_sir: Add SuperH IrDA driver
From: David Miller @ 2010-02-02 15:48 UTC (permalink / raw)
To: morimoto.kuninori; +Cc: netdev, samuel
In-Reply-To: <uwrz1vjg3.wl%morimoto.kuninori@renesas.com>
From: Kuninori Morimoto <morimoto.kuninori@renesas.com>
Date: Thu, 28 Jan 2010 17:06:49 +0900
> This is very simple IrDA SIR driver for SuperH.
> This driver was tested by irdaping/ircp on SH7724 EcoVec24 board
>
> Signed-off-by: Kuninori Morimoto <morimoto.kuninori@renesas.com>
Applied to net-next-2.6, thank you.
^ permalink raw reply
* Re: [PATCH net-next-2.6] virtio_net: Set vlan_features to enable offloads on vlan devices
From: David Miller @ 2010-02-02 15:46 UTC (permalink / raw)
To: sri; +Cc: herbert, rusty, netdev
In-Reply-To: <1264454176.28852.129.camel@w-sridhar.beaverton.ibm.com>
From: Sridhar Samudrala <sri@us.ibm.com>
Date: Mon, 25 Jan 2010 13:16:16 -0800
> Set vlan_features in virtnet_probe() so that all the available offloads
> are enabled on vlan devices attached to virtio_net devices.
>
> Signed-off-by: Sridhar Samudrala <sri@us.ibm.com>
I can't apply this because I'm not going to apply your
patch which erroneously pops the VLAN header during GRO
processing. And this patch is useless without that.
^ permalink raw reply
* Re: [PATCH net-next-2.6] net: Handle vlan packets in skb_gso_segment()
From: David Miller @ 2010-02-02 15:45 UTC (permalink / raw)
To: sri; +Cc: herbert, netdev
In-Reply-To: <1264454194.28852.130.camel@w-sridhar.beaverton.ibm.com>
From: Sridhar Samudrala <sri@us.ibm.com>
Date: Mon, 25 Jan 2010 13:16:34 -0800
> Handle VLAN packets in skb_gso_segment(). Currently, when large
> VLAN packets are sent via virtio_net on guest and tun on host,
> skb_gso_segment() fails with EPROTONOSUPPORT.
>
> Signed-off-by: Sridhar Samudrala <sri@us.ibm.com>
...
> @@ -1672,6 +1672,12 @@ struct sk_buff *skb_gso_segment(struct sk_buff *skb, int features)
>
> skb_reset_mac_header(skb);
> skb->mac_len = skb->network_header - skb->mac_header;
> + if (ntohs(type) == ETH_P_8021Q) {
> + skb->protocol = vlan_eth_hdr(skb)->h_vlan_encapsulated_proto;
> + type = skb->protocol;
> + skb->mac_len += VLAN_HLEN;
> + skb_set_network_header(skb, skb->mac_len);
> + }
> __skb_pull(skb, skb->mac_len);
>
You can't do this.
Now, VLAN packets that are GSO handled will show up differently to
sniffers than those which do not get GSO handling.
You really can't pop the MAC header and modify the skb->protocol
here.
^ permalink raw reply
* Re: [PATCH 02/86] dccp: revert buggy auto-loading of dccp module
From: Neil Horman @ 2010-02-02 15:39 UTC (permalink / raw)
To: gerrit; +Cc: davem, dccp, netdev
In-Reply-To: <53767.148.187.160.35.1265123175.squirrel@148.187.160.35>
On Tue, Feb 02, 2010 at 03:06:15PM -0000, gerrit@erg.abdn.ac.uk wrote:
> > --- a/net/dccp/probe.c
> > +++ b/net/dccp/probe.c
> > @@ -161,7 +161,8 @@ static __init int dccpprobe_init(void)
> > if (!proc_net_fops_create(&init_net, procname, S_IRUSR,
> > &dccpprobe_fops))
> > goto err0;
> >
> > - ret = try_then_request_module((register_jprobe(&dccp_send_probe) == 0),
> > + try_then_request_module(
> > + ((ret = register_jprobe(&dccp_send_probe)) == 0),
> > "dccp");
> > if (ret)
> > goto err1;
>
> Apologies for the late response -- delays are sometimes possible due to
> day job. The only problem that I had with this patch was that it was
> apparently not tested, causing the described problems.
>
>
> > I've not tested it, but this should do it,
> > without re-breaking the silent dependency.
>
> I will test it and get back to you until tomorrow morning (GMT),
> if it works I'll also push it out in the test tree.
>
> Thanks a lot for getting back and devising a different route.
>
Thanks, and apologies for being brusque. I just didn't want to fix what is
clearly a problem in what you describe by rebreaking a previously seen problem.
I expect this should work just fine. Let me know if it doesn't and I'll
resurrect my test bed here and take a look
Neil
>
> --
> To unsubscribe from this list: send the line "unsubscribe netdev" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
>
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox