Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

tulip: Fix for MTU problems with 802.1q tagged frames

The original patch was submitted last year but wasn't discussed or applied
because of missing maintainer's CCs. I only fixed some formatting errors,
but as I saw tulip is very badly formatted and needs further work.

Original description:
This patch fixes MTU problem, which occurs when using 802.1q VLANs. We
should allow receiving frames of up to 1518 bytes in length, instead of
1514.

Based on patch written by Ben McKeegan for 2.4.x kernels. It is archived
at http://www.candelatech.com/~greear/vlan/howto.html#tulip
I've adjusted a few things to make it apply on 2.6.x kernels.

Tested on D-Link DFE-570TX quad-fastethernet card.

Signed-off-by: Tomasz Lemiech <szpajder@staszic.waw.pl>
Signed-off-by: Ivan Vecera <ivecera@redhat.com>
Signed-off-by: Ben McKeegan <ben@netservers.co.uk>
Acked-by: Grant Grundler <grundler@parisc-linux.org>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Tomasz Lemiech and committed by
David S. Miller
1f8ae0a2 a390d1f3

+86 -30
+55 -29
drivers/net/tulip/interrupt.c
··· 140 140 /* If we own the next entry, it is a new packet. Send it up. */ 141 141 while ( ! (tp->rx_ring[entry].status & cpu_to_le32(DescOwned))) { 142 142 s32 status = le32_to_cpu(tp->rx_ring[entry].status); 143 + short pkt_len; 143 144 144 145 if (tp->dirty_rx + RX_RING_SIZE == tp->cur_rx) 145 146 break; ··· 152 151 if (++work_done >= budget) 153 152 goto not_done; 154 153 155 - if ((status & 0x38008300) != 0x0300) { 156 - if ((status & 0x38000300) != 0x0300) { 154 + /* 155 + * Omit the four octet CRC from the length. 156 + * (May not be considered valid until we have 157 + * checked status for RxLengthOver2047 bits) 158 + */ 159 + pkt_len = ((status >> 16) & 0x7ff) - 4; 160 + 161 + /* 162 + * Maximum pkt_len is 1518 (1514 + vlan header) 163 + * Anything higher than this is always invalid 164 + * regardless of RxLengthOver2047 bits 165 + */ 166 + 167 + if ((status & (RxLengthOver2047 | 168 + RxDescCRCError | 169 + RxDescCollisionSeen | 170 + RxDescRunt | 171 + RxDescDescErr | 172 + RxWholePkt)) != RxWholePkt 173 + || pkt_len > 1518) { 174 + if ((status & (RxLengthOver2047 | 175 + RxWholePkt)) != RxWholePkt) { 157 176 /* Ingore earlier buffers. */ 158 177 if ((status & 0xffff) != 0x7fff) { 159 178 if (tulip_debug > 1) ··· 182 161 dev->name, status); 183 162 tp->stats.rx_length_errors++; 184 163 } 185 - } else if (status & RxDescFatalErr) { 164 + } else { 186 165 /* There was a fatal error. */ 187 166 if (tulip_debug > 2) 188 167 printk(KERN_DEBUG "%s: Receive error, Rx status %8.8x.\n", 189 168 dev->name, status); 190 169 tp->stats.rx_errors++; /* end of a packet.*/ 191 - if (status & 0x0890) tp->stats.rx_length_errors++; 170 + if (pkt_len > 1518 || 171 + (status & RxDescRunt)) 172 + tp->stats.rx_length_errors++; 173 + 192 174 if (status & 0x0004) tp->stats.rx_frame_errors++; 193 175 if (status & 0x0002) tp->stats.rx_crc_errors++; 194 176 if (status & 0x0001) tp->stats.rx_fifo_errors++; 195 177 } 196 178 } else { 197 - /* Omit the four octet CRC from the length. */ 198 - short pkt_len = ((status >> 16) & 0x7ff) - 4; 199 179 struct sk_buff *skb; 200 180 201 - #ifndef final_version 202 - if (pkt_len > 1518) { 203 - printk(KERN_WARNING "%s: Bogus packet size of %d (%#x).\n", 204 - dev->name, pkt_len, pkt_len); 205 - pkt_len = 1518; 206 - tp->stats.rx_length_errors++; 207 - } 208 - #endif 209 181 /* Check if the packet is long enough to accept without copying 210 182 to a minimally-sized skbuff. */ 211 183 if (pkt_len < tulip_rx_copybreak ··· 370 356 /* If we own the next entry, it is a new packet. Send it up. */ 371 357 while ( ! (tp->rx_ring[entry].status & cpu_to_le32(DescOwned))) { 372 358 s32 status = le32_to_cpu(tp->rx_ring[entry].status); 359 + short pkt_len; 373 360 374 361 if (tulip_debug > 5) 375 362 printk(KERN_DEBUG "%s: In tulip_rx(), entry %d %8.8x.\n", 376 363 dev->name, entry, status); 377 364 if (--rx_work_limit < 0) 378 365 break; 379 - if ((status & 0x38008300) != 0x0300) { 380 - if ((status & 0x38000300) != 0x0300) { 366 + 367 + /* 368 + Omit the four octet CRC from the length. 369 + (May not be considered valid until we have 370 + checked status for RxLengthOver2047 bits) 371 + */ 372 + pkt_len = ((status >> 16) & 0x7ff) - 4; 373 + /* 374 + Maximum pkt_len is 1518 (1514 + vlan header) 375 + Anything higher than this is always invalid 376 + regardless of RxLengthOver2047 bits 377 + */ 378 + 379 + if ((status & (RxLengthOver2047 | 380 + RxDescCRCError | 381 + RxDescCollisionSeen | 382 + RxDescRunt | 383 + RxDescDescErr | 384 + RxWholePkt)) != RxWholePkt 385 + || pkt_len > 1518) { 386 + if ((status & (RxLengthOver2047 | 387 + RxWholePkt)) != RxWholePkt) { 381 388 /* Ingore earlier buffers. */ 382 389 if ((status & 0xffff) != 0x7fff) { 383 390 if (tulip_debug > 1) ··· 407 372 dev->name, status); 408 373 tp->stats.rx_length_errors++; 409 374 } 410 - } else if (status & RxDescFatalErr) { 375 + } else { 411 376 /* There was a fatal error. */ 412 377 if (tulip_debug > 2) 413 378 printk(KERN_DEBUG "%s: Receive error, Rx status %8.8x.\n", 414 379 dev->name, status); 415 380 tp->stats.rx_errors++; /* end of a packet.*/ 416 - if (status & 0x0890) tp->stats.rx_length_errors++; 381 + if (pkt_len > 1518 || 382 + (status & RxDescRunt)) 383 + tp->stats.rx_length_errors++; 417 384 if (status & 0x0004) tp->stats.rx_frame_errors++; 418 385 if (status & 0x0002) tp->stats.rx_crc_errors++; 419 386 if (status & 0x0001) tp->stats.rx_fifo_errors++; 420 387 } 421 388 } else { 422 - /* Omit the four octet CRC from the length. */ 423 - short pkt_len = ((status >> 16) & 0x7ff) - 4; 424 389 struct sk_buff *skb; 425 - 426 - #ifndef final_version 427 - if (pkt_len > 1518) { 428 - printk(KERN_WARNING "%s: Bogus packet size of %d (%#x).\n", 429 - dev->name, pkt_len, pkt_len); 430 - pkt_len = 1518; 431 - tp->stats.rx_length_errors++; 432 - } 433 - #endif 434 390 435 391 /* Check if the packet is long enough to accept without copying 436 392 to a minimally-sized skbuff. */
+31 -1
drivers/net/tulip/tulip.h
··· 201 201 DescStartPkt = 0x20000000, 202 202 DescEndRing = 0x02000000, 203 203 DescUseLink = 0x01000000, 204 - RxDescFatalErr = 0x008000, 204 + 205 + /* 206 + * Error summary flag is logical or of 'CRC Error', 'Collision Seen', 207 + * 'Frame Too Long', 'Runt' and 'Descriptor Error' flags generated 208 + * within tulip chip. 209 + */ 210 + RxDescErrorSummary = 0x8000, 211 + RxDescCRCError = 0x0002, 212 + RxDescCollisionSeen = 0x0040, 213 + 214 + /* 215 + * 'Frame Too Long' flag is set if packet length including CRC exceeds 216 + * 1518. However, a full sized VLAN tagged frame is 1522 bytes 217 + * including CRC. 218 + * 219 + * The tulip chip does not block oversized frames, and if this flag is 220 + * set on a receive descriptor it does not indicate the frame has been 221 + * truncated. The receive descriptor also includes the actual length. 222 + * Therefore we can safety ignore this flag and check the length 223 + * ourselves. 224 + */ 225 + RxDescFrameTooLong = 0x0080, 226 + RxDescRunt = 0x0800, 227 + RxDescDescErr = 0x4000, 205 228 RxWholePkt = 0x00000300, 229 + /* 230 + * Top three bits of 14 bit frame length (status bits 27-29) should 231 + * never be set as that would make frame over 2047 bytes. The Receive 232 + * Watchdog flag (bit 4) may indicate the length is over 2048 and the 233 + * length field is invalid. 234 + */ 235 + RxLengthOver2047 = 0x38000010 206 236 }; 207 237 208 238