From 1967c333d49237d8fc9d52f1f3c874639a7bbc2d Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Fri, 23 Nov 2007 15:24:37 -0500 Subject: [PATCH] Linux 2.2.24-rc3 o Backport the ethernet padding fixes (Alan Cox) | All done except 8139too, rtl8139] --- Makefile | 2 +- drivers/net/3c501.c | 16 +++++++- drivers/net/3c505.c | 5 ++- drivers/net/3c507.c | 13 ++++--- drivers/net/3c523.c | 4 +- drivers/net/3c527.c | 7 ++++ drivers/net/7990.c | 2 + drivers/net/82596.c | 12 +++++- drivers/net/8390.c | 22 +++++++++-- drivers/net/a2065.c | 12 +++++- drivers/net/am79c961a.c | 15 +++++++- drivers/net/ariadne.c | 15 +++++++- drivers/net/at1700.c | 13 ++++++- drivers/net/atarilance.c | 21 ++++++++--- drivers/net/atp.c | 20 +++++++--- drivers/net/bagetlance.c | 19 +++++++--- drivers/net/de600.c | 5 ++- drivers/net/de620.c | 7 +++- drivers/net/declance.c | 13 ++++++- drivers/net/depca.c | 7 ++++ drivers/net/eepro.c | 10 ++++- drivers/net/eexpress.c | 11 +++++- drivers/net/epic100.c | 7 ++++ drivers/net/eth16i.c | 12 +++++- drivers/net/fmv18x.c | 13 ++++++- drivers/net/hp100.c | 7 ++++ drivers/net/lance.c | 12 +++++- drivers/net/lp486e.c | 15 +++++++- drivers/net/ni5010.c | 13 ++++--- drivers/net/ni52.c | 7 +++- drivers/net/ni65.c | 2 + drivers/net/seeq8005.c | 13 ++++++- drivers/net/sgiseeq.c | 2 + drivers/net/sk_g16.c | 3 ++ drivers/net/smc9194.c | 14 ++++++- drivers/net/via-rhine.c | 9 +++++ drivers/net/znet.c | 10 ++++- include/linux/skbuff.h | 21 +++++++++++ net/core/skbuff.c | 79 ++++++++++++++++++++++++++++++++++++++++ 39 files changed, 431 insertions(+), 59 deletions(-) diff --git a/Makefile b/Makefile index fd26aed5d48e..a5fa1980fc79 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ VERSION = 2 PATCHLEVEL = 2 SUBLEVEL = 24 -EXTRAVERSION = -rc2 +EXTRAVERSION = -rc3 ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ -e s/arm.*/arm/ -e s/sa110/arm/) diff --git a/drivers/net/3c501.c b/drivers/net/3c501.c index 6c2a672ec392..05c6498bd244 100644 --- a/drivers/net/3c501.c +++ b/drivers/net/3c501.c @@ -422,8 +422,15 @@ static int el_start_xmit(struct sk_buff *skb, struct device *dev) } else { - int gp_start = 0x800 - (ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN); + int len = skb->len; + int pad = 0; + int gp_start; unsigned char *buf = skb->data; + + if(len < ETH_ZLEN) + pad = ETH_ZLEN - len; + + gp_start = 0x800 - ( len + pad ); load_it_again_sam: lp->tx_pkt_start = gp_start; @@ -451,7 +458,12 @@ load_it_again_sam: outw(0x00, RX_BUF_CLR); /* Set rx packet area to 0. */ outw(gp_start, GP_LOW); /* aim - packet will be loaded into buffer start */ - outsb(DATAPORT,buf,skb->len); /* load buffer (usual thing each byte increments the pointer) */ + outsb(DATAPORT,buf,len); /* load buffer (usual thing each byte increments the pointer) */ + if(pad) + { + while(pad--) /* Zero fill buffer tail */ + outb(0, DATAPORT); + } outw(gp_start, GP_LOW); /* the board reuses the same register */ if(lp->loading==2) /* A receive upset our load, despite our best efforts */ diff --git a/drivers/net/3c505.c b/drivers/net/3c505.c index ac6819446050..b4ec16d3bcb8 100644 --- a/drivers/net/3c505.c +++ b/drivers/net/3c505.c @@ -1062,8 +1062,9 @@ static int send_packet(struct device *dev, struct sk_buff *skb) adapter->current_dma.direction = 1; adapter->current_dma.start_time = jiffies; - if ((unsigned long)(skb->data + nlen) >= MAX_DMA_ADDRESS) { - memcpy(adapter->dma_buffer, skb->data, nlen); + if ((unsigned long)(skb->data + nlen) >= MAX_DMA_ADDRESS || nlen != skb->len) { + memcpy(adapter->dma_buffer, skb->data, skb->len); + memset(adapter->dma_buffer+skb->len, 0, nlen-skb->len); target = virt_to_bus(adapter->dma_buffer); } else { diff --git a/drivers/net/3c507.c b/drivers/net/3c507.c index 8d6e20ccce7e..50030a0a89d1 100644 --- a/drivers/net/3c507.c +++ b/drivers/net/3c507.c @@ -290,7 +290,7 @@ static void el16_rx(struct device *dev); static int el16_close(struct device *dev); static struct net_device_stats *el16_get_stats(struct device *dev); -static void hardware_send_packet(struct device *dev, void *buf, short length); +static void hardware_send_packet(struct device *dev, void *buf, short length, short pad); static void init_82586_mem(struct device *dev); @@ -495,10 +495,10 @@ static int el16_send_packet(struct sk_buff *skb, struct device *dev) outb(0x80, ioaddr + MISC_CTRL); #ifdef CONFIG_SMP spin_lock_irqsave(&lp->lock, flags); - hardware_send_packet(dev, buf, length); + hardware_send_packet(dev, buf, skb->len, length - skb->len); spin_unlock_irqrestore(&lp->lock, flags); #else - hardware_send_packet(dev, buf, length); + hardware_send_packet(dev, buf, skb->len, length - skb->len); #endif dev->trans_start = jiffies; /* Enable the 82586 interrupt input. */ @@ -758,12 +758,13 @@ static void init_82586_mem(struct device *dev) return; } -static void hardware_send_packet(struct device *dev, void *buf, short length) +static void hardware_send_packet(struct device *dev, void *buf, short length, short pad) { struct net_local *lp = (struct net_local *)dev->priv; short ioaddr = dev->base_addr; ushort tx_block = lp->tx_head; unsigned long write_ptr = dev->mem_start + tx_block; + static char padding[ETH_ZLEN]; /* Set the write pointer to the Tx block, and put out the header. */ writew(0x0000,write_ptr); /* Tx status */ @@ -772,7 +773,7 @@ static void hardware_send_packet(struct device *dev, void *buf, short length) writew(tx_block+8,write_ptr+=2); /* Data Buffer offset. */ /* Output the data buffer descriptor. */ - writew(length | 0x8000,write_ptr+=2); /* Byte count parameter. */ + writew((pad + length) | 0x8000,write_ptr+=2); /* Byte count parameter. */ writew(-1,write_ptr+=2); /* No next data buffer. */ writew(tx_block+22+SCB_BASE,write_ptr+=2); /* Buffer follows the NoOp command. */ writew(0x0000,write_ptr+=2); /* Buffer address high bits (always zero). */ @@ -784,6 +785,8 @@ static void hardware_send_packet(struct device *dev, void *buf, short length) /* Output the packet at the write pointer. */ memcpy_toio(write_ptr+2, buf, length); + if(pad) + memcpy_toio(write_ptr+length+2, padding, pad); /* Set the old command link pointing to this send packet. */ writew(tx_block,dev->mem_start + lp->tx_cmd_link); diff --git a/drivers/net/3c523.c b/drivers/net/3c523.c index b010a95093e0..1dee4227198a 100644 --- a/drivers/net/3c523.c +++ b/drivers/net/3c523.c @@ -1118,8 +1118,10 @@ static int elmc_send_packet(struct sk_buff *skb, struct device *dev) if (test_and_set_bit(0, (void *) &dev->tbusy) != 0) { printk("%s: Transmitter access conflict.\n", dev->name); } else { - memcpy((char *) p->xmit_cbuffs[p->xmit_count], (char *) (skb->data), skb->len); len = (ETH_ZLEN < skb->len) ? skb->len : ETH_ZLEN; + if(len != skb->len) + memset((char *) p->xmit_cbuffs[p->xmit_count], 0, ETH_ZLEN); + memcpy((char *) p->xmit_cbuffs[p->xmit_count], (char *) (skb->data), skb->len); #if (NUM_XMIT_BUFFS == 1) #ifdef NO_NOPCOMMANDS diff --git a/drivers/net/3c527.c b/drivers/net/3c527.c index 5a155d45b18b..9b7ab67e5f32 100644 --- a/drivers/net/3c527.c +++ b/drivers/net/3c527.c @@ -1087,6 +1087,12 @@ static int mc32_send_packet(struct sk_buff *skb, struct device *dev) /* We will need this to flush the buffer out */ lp->tx_ring[lp->tx_ring_head].skb=skb; + if(skb->len < ETH_ZLEN) + { + skb = skb_padto(skb, ETH_ZLEN); + if(skb == NULL) + goto out; + } np->length = (skb->len < ETH_ZLEN) ? ETH_ZLEN : skb->len; np->data = virt_to_bus(skb->data); @@ -1096,6 +1102,7 @@ static int mc32_send_packet(struct sk_buff *skb, struct device *dev) p->control &= ~CONTROL_EOL; /* Clear EOL on p */ +out: dev->tbusy = 0; /* Keep feeding me */ restore_flags(flags); diff --git a/drivers/net/7990.c b/drivers/net/7990.c index 1991659f0071..a0a6c0a3cab1 100644 --- a/drivers/net/7990.c +++ b/drivers/net/7990.c @@ -542,6 +542,8 @@ int lance_start_xmit (struct sk_buff *skb, struct device *dev) ib->btx_ring [entry].length = (-len) | 0xf000; ib->btx_ring [entry].misc = 0; + if(skb->len < ETH_ZLEN) + memset((char *)&ib->tx_buf[entry][0], 0, ETH_ZLEN); memcpy ((char *)&ib->tx_buf [entry][0], skb->data, skblen); /* Now, give the packet to the lance */ diff --git a/drivers/net/82596.c b/drivers/net/82596.c index 720d10fb2c65..6e6fe2cb082b 100644 --- a/drivers/net/82596.c +++ b/drivers/net/82596.c @@ -1045,9 +1045,19 @@ static int i596_start_xmit(struct sk_buff *skb, struct device *dev) if (test_and_set_bit(0, (void *) &dev->tbusy) != 0) printk("%s: Transmitter access conflict.\n", dev->name); else { - short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN; + short length = skb->len; dev->trans_start = jiffies; + if(skb->len < ETH_ZLEN) + { + skb = skb_padto(skb, ETH_ZLEN); + if(skb == NULL) + { + dev->tbusy = 0; + return 0; + } + length = ETH_ZLEN; + } tx_cmd = lp->tx_cmds + lp->next_tx_cmd; tbd = lp->tbds + lp->next_tx_cmd; diff --git a/drivers/net/8390.c b/drivers/net/8390.c index 5ce7fbc3d5db..a2ea9d32fad5 100644 --- a/drivers/net/8390.c +++ b/drivers/net/8390.c @@ -196,6 +196,7 @@ static int ei_start_xmit(struct sk_buff *skb, struct device *dev) struct ei_device *ei_local = (struct ei_device *) dev->priv; int length, send_length, output_page; unsigned long flags; + char scratch[ETH_ZLEN]; /* * We normally shouldn't be called if dev->tbusy is set, but the @@ -348,8 +349,16 @@ static int ei_start_xmit(struct sk_buff *skb, struct device *dev) * isn't already sending. If it is busy, the interrupt handler will * trigger the send later, upon receiving a Tx done interrupt. */ - - ei_block_output(dev, length, skb->data, output_page); + + if(length == send_length) + ei_block_output(dev, length, skb->data, output_page); + else + { + memset(scratch, 0, ETH_ZLEN); + memcpy(scratch, skb->data, skb->len); + ei_block_output(dev, ETH_ZLEN, scratch, output_page); + } + if (! ei_local->txing) { ei_local->txing = 1; @@ -378,7 +387,14 @@ static int ei_start_xmit(struct sk_buff *skb, struct device *dev) * reasonable hardware if you only use one Tx buffer. */ - ei_block_output(dev, length, skb->data, ei_local->tx_start_page); + if(length == send_length) + ei_block_output(dev, length, skb->data, ei_local->tx_start_page); + else + { + memset(scratch, 0, ETH_ZLEN); + memcpy(scratch, skb->data, skb->len); + ei_block_output(dev, ETH_ZLEN, scratch, ei_local->tx_start_page); + } ei_local->txing = 1; NS8390_trigger_send(dev, send_length, ei_local->tx_start_page); dev->trans_start = jiffies; diff --git a/drivers/net/a2065.c b/drivers/net/a2065.c index 88cd28749420..ee4b4dcc7160 100644 --- a/drivers/net/a2065.c +++ b/drivers/net/a2065.c @@ -594,7 +594,16 @@ static int lance_start_xmit (struct sk_buff *skb, struct device *dev) } skblen = skb->len; - + len = skblen; + + if(len < ETH_ZLEN) + { + len = ETH_ZLEN; + skb = skb_padto(skb, ETH_ZLEN); + if(skb == NULL) + return 0; + } + save_flags(flags); cli(); @@ -615,7 +624,6 @@ static int lance_start_xmit (struct sk_buff *skb, struct device *dev) } } #endif - len = (skblen <= ETH_ZLEN) ? ETH_ZLEN : skblen; entry = lp->tx_new & lp->tx_ring_mod_mask; ib->btx_ring [entry].length = (-len) | 0xf000; ib->btx_ring [entry].misc = 0; diff --git a/drivers/net/am79c961a.c b/drivers/net/am79c961a.c index 92f1dbd59b85..7c82c44ae179 100644 --- a/drivers/net/am79c961a.c +++ b/drivers/net/am79c961a.c @@ -524,11 +524,24 @@ am79c961_sendpacket(struct sk_buff *skb, struct device *dev) if (!dev->tbusy) { again: if (!test_and_set_bit(0, (void*)&dev->tbusy)) { - unsigned int length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN; + unsigned int length = skb->len; unsigned int hdraddr, bufaddr; unsigned int head; unsigned long flags; + + /* FIXME: I thought the 79c961 could do padding - RMK ??? */ + if(length < ETH_ZLEN) + { + skb = skb_padto(skb, ETH_ZLEN); + if(skb == NULL) + { + dev->tbusy = 0; + return 0; + } + length = ETH_ZLEN; + } + head = priv->txhead; hdraddr = priv->txhdr + (head << 3); bufaddr = priv->txbuffer[head]; diff --git a/drivers/net/ariadne.c b/drivers/net/ariadne.c index 92075a95f92f..3d878256bd8b 100644 --- a/drivers/net/ariadne.c +++ b/drivers/net/ariadne.c @@ -547,6 +547,7 @@ static int ariadne_start_xmit(struct sk_buff *skb, struct device *dev) struct AriadneBoard *board = priv->board; int entry; unsigned long flags; + int len = skb->len; /* Transmitter timeout, serious problems. */ if (dev->tbusy) { @@ -608,6 +609,18 @@ static int ariadne_start_xmit(struct sk_buff *skb, struct device *dev) } /* Fill in a Tx ring entry */ + /* FIXME: is the 79C960 new enough to do its own padding right ? */ + if(skb->len < ETH_ZLEN) + { + skb = skb_padto(skb, ETH_ZLEN); + if(skb == NULL) + { + dev->tbusy = 0; + return 0; + } + len = ETH_ZLEN; + } ++ #if 0 printk("TX pkt type 0x%04x from ", ((u_short *)skb->data)[6]); @@ -637,7 +650,7 @@ static int ariadne_start_xmit(struct sk_buff *skb, struct device *dev) priv->tx_ring[entry]->TMD2 = swapw((u_short)-skb->len); priv->tx_ring[entry]->TMD3 = 0x0000; - memcpyw(priv->tx_buff[entry], (u_short *)skb->data, skb->len); + memcpyw(priv->tx_buff[entry], (u_short *)skb->data, len); #if 0 { diff --git a/drivers/net/at1700.c b/drivers/net/at1700.c index 0acbfc09d48d..50d0a53d53db 100644 --- a/drivers/net/at1700.c +++ b/drivers/net/at1700.c @@ -576,7 +576,8 @@ net_send_packet(struct sk_buff *skb, struct device *dev) if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) printk("%s: Transmitter access conflict.\n", dev->name); else { - short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN; + short length = skb->len; + static u8 pad[ETH_ZLEN]; unsigned char *buf = skb->data; /* We may not start transmitting unless we finish transferring @@ -587,7 +588,17 @@ net_send_packet(struct sk_buff *skb, struct device *dev) lp->tx_queue_ready = 0; { outw(length, ioaddr + DATAPORT); + /* Packet data */ outsw(ioaddr + DATAPORT, buf, (length + 1) >> 1); + /* Check for dribble byte */ + if(length & 1) + { + outw(skb->data[skb->len-1], ioaddr + DATAPORT); + length--; + } + /* Check for packet padding */ + if(length != skb->len) + outsw(ioaddr + DATAPORT, pad, (length - skb->len + 1) >> 1); lp->tx_queue++; lp->tx_queue_len += length + 2; diff --git a/drivers/net/atarilance.c b/drivers/net/atarilance.c index c79fd581e0a1..888a7e40ab53 100644 --- a/drivers/net/atarilance.c +++ b/drivers/net/atarilance.c @@ -766,6 +766,21 @@ static int lance_start_xmit( struct sk_buff *skb, struct device *dev ) DPRINTK( 2, ( "%s: lance_start_xmit() called, csr0 %4.4x.\n", dev->name, DREG )); + /* The old LANCE chips doesn't automatically pad buffers to min. size. */ + len = skb->len; + if(len < ETH_ZLEN) + len = ETH_ZLEN; + /* PAM-Card has a bug: Can only send packets with even number of bytes! */ + else if (lp->cardtype == PAM_CARD && (len & 1)) + ++len; + + if(len > skb->len) + { + skb = skb_padto(skb, len); + if(skb == NULL) + return 0; + } + /* Block a timer-based transmit from overlapping. This could better be done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */ if (test_and_set_bit( 0, (void*)&dev->tbusy ) != 0) { @@ -807,12 +822,6 @@ static int lance_start_xmit( struct sk_buff *skb, struct device *dev ) * last. */ - /* The old LANCE chips doesn't automatically pad buffers to min. size. */ - len = (ETH_ZLEN < skb->len) ? skb->len : ETH_ZLEN; - /* PAM-Card has a bug: Can only send packets with even number of bytes! */ - if (lp->cardtype == PAM_CARD && (len & 1)) - ++len; - head->length = -len; head->misc = 0; lp->memcpy_f( PKTBUF_ADDR(head), (void *)skb->data, skb->len ); diff --git a/drivers/net/atp.c b/drivers/net/atp.c index 89ca21cfea95..9cb6a193c596 100644 --- a/drivers/net/atp.c +++ b/drivers/net/atp.c @@ -133,7 +133,7 @@ static void get_node_ID(struct device *dev); static unsigned short eeprom_op(short ioaddr, unsigned int cmd); static int net_open(struct device *dev); static void hardware_init(struct device *dev); -static void write_packet(short ioaddr, int length, unsigned char *packet, int mode); +static void write_packet(short ioaddr, int length, unsigned char *packet, int pad, int mode); static void trigger_send(short ioaddr, int length); static int net_send_packet(struct sk_buff *skb, struct device *dev); static void net_interrupt(int irq, void *dev_id, struct pt_regs *regs); @@ -381,15 +381,23 @@ static void trigger_send(short ioaddr, int length) write_reg(ioaddr, CMR1, CMR1_Xmit); } -static void write_packet(short ioaddr, int length, unsigned char *packet, int data_mode) +static void write_packet(short ioaddr, int length, unsigned char *packet, int pad_len, int data_mode) { - length = (length + 1) & ~1; /* Round up to word length. */ + if(length & 1) + { + length++; + pad_len++; + } + outb(EOC+MAR, ioaddr + PAR_DATA); if ((data_mode & 1) == 0) { /* Write the packet out, starting with the write addr. */ outb(WrAddr+MAR, ioaddr + PAR_DATA); do { write_byte_mode0(ioaddr, *packet++); + } while (--length > pad_len) ; + do { + write_byte_mode0(ioaddr, 0); } while (--length > 0) ; } else { /* Write the packet out in slow mode. */ @@ -403,8 +411,10 @@ static void write_packet(short ioaddr, int length, unsigned char *packet, int da outbyte >>= 4; outb(outbyte & 0x0f, ioaddr + PAR_DATA); outb(Ctrl_HNibWrite + Ctrl_IRQEN, ioaddr + PAR_CONTROL); - while (--length > 0) + while (--length > pad_len) write_byte_mode1(ioaddr, *packet++); + while (--length > 0) + write_byte_mode1(ioaddr, 0); } /* Terminate the Tx frame. End of write: ECB. */ outb(0xff, ioaddr + PAR_DATA); @@ -450,7 +460,7 @@ net_send_packet(struct sk_buff *skb, struct device *dev) write_reg_high(ioaddr, IMR, 0); restore_flags(flags); - write_packet(ioaddr, length, buf, dev->if_port); + write_packet(ioaddr, length, buf, length-skb->len, dev->if_port); lp->pac_cnt_in_tx_buf++; if (lp->tx_unit_busy == 0) { diff --git a/drivers/net/bagetlance.c b/drivers/net/bagetlance.c index 5a6f8fd4aecd..8e7bc16331d6 100644 --- a/drivers/net/bagetlance.c +++ b/drivers/net/bagetlance.c @@ -831,6 +831,19 @@ static int lance_start_xmit( struct sk_buff *skb, struct device *dev ) struct lance_tx_head *head; unsigned long flags; + /* The old LANCE chips doesn't automatically pad buffers to min. size. */ + len = (ETH_ZLEN < skb->len) ? skb->len : ETH_ZLEN; + /* PAM-Card has a bug: Can only send packets with even number of bytes! */ + if (lp->cardtype == PAM_CARD && (len & 1)) + ++len; + + if (len > skb->len) + { + skb = skb_padto(skb, len); + if(skb == NULL) + return 0; + } + /* Transmitter timeout, serious problems. */ if (dev->tbusy) { int tickssofar = jiffies - dev->trans_start; @@ -917,12 +930,6 @@ static int lance_start_xmit( struct sk_buff *skb, struct device *dev ) * last. */ - /* The old LANCE chips doesn't automatically pad buffers to min. size. */ - len = (ETH_ZLEN < skb->len) ? skb->len : ETH_ZLEN; - /* PAM-Card has a bug: Can only send packets with even number of bytes! */ - if (lp->cardtype == PAM_CARD && (len & 1)) - ++len; - head->length = -len; head->misc = 0; lp->memcpy_f( PKTBUF_ADDR(head), (void *)skb->data, skb->len ); diff --git a/drivers/net/de600.c b/drivers/net/de600.c index 03a3205ed8a4..593d50d4f353 100644 --- a/drivers/net/de600.c +++ b/drivers/net/de600.c @@ -404,6 +404,7 @@ de600_start_xmit(struct sk_buff *skb, struct device *dev) int len; int tickssofar; byte *buffer = skb->data; + int i; if (free_tx_pages <= 0) { /* Do timeouts, to avoid hangs. */ tickssofar = jiffies - dev->trans_start; @@ -447,8 +448,10 @@ de600_start_xmit(struct sk_buff *skb, struct device *dev) #endif de600_setup_address(transmit_from, RW_ADDR); - for ( ; len > 0; --len, ++buffer) + for (i = 0; i < skb->len ; ++i, ++buffer) de600_put_byte(*buffer); + for (; i < len; ++i) + de600_put_byte(0); if (free_tx_pages-- == TX_PAGES) { /* No transmission going on */ dev->trans_start = jiffies; diff --git a/drivers/net/de620.c b/drivers/net/de620.c index 80d7a119133b..297c2be9ba8d 100644 --- a/drivers/net/de620.c +++ b/drivers/net/de620.c @@ -310,7 +310,7 @@ de620_read_byte(struct device *dev) } static inline void -de620_write_block(struct device *dev, byte *buffer, int count) +de620_write_block(struct device *dev, byte *buffer, int count, int pad) { #ifndef LOWSPEED byte uflip = NIC_Cmd ^ (DS0 | DS1); @@ -329,6 +329,9 @@ de620_write_block(struct device *dev, byte *buffer, int count) for ( ; count > 0; --count, ++buffer) { de620_put_byte(dev,*buffer); } + for ( count = pad ; count > 0; --count, ++buffer) { + de620_put_byte(dev, 0); + } de620_send_command(dev,W_DUMMY); #ifdef COUNT_LOOPS /* trial debug output: loops per byte in de620_ready() */ @@ -570,7 +573,7 @@ de620_start_xmit(struct sk_buff *skb, struct device *dev) return 1; break; } - de620_write_block(dev, buffer, len); + de620_write_block(dev, buffer, skb->len, len-skb->len); dev->trans_start = jiffies; dev->tbusy = (using_txbuf == (TXBF0 | TXBF1)); /* Boolean! */ diff --git a/drivers/net/declance.c b/drivers/net/declance.c index b0183061c8d1..780458e366c8 100644 --- a/drivers/net/declance.c +++ b/drivers/net/declance.c @@ -873,12 +873,23 @@ static int lance_start_xmit(struct sk_buff *skb, struct device *dev) return -1; } skblen = skb->len; + len = skblen; + + if(len < ETH_ZLEN) + { + skb = skb_padto(skb, ETH_ZLEN); + if(skb == NULL) + { + dev->tbusy = 0; + return 0; + } + len = ETH_ZLEN; + } save_and_cli(flags); if (!TX_BUFFS_AVAIL) { restore_flags(flags); return -1; } - len = (skblen <= ETH_ZLEN) ? ETH_ZLEN : skblen; lp->stats.tx_bytes += len; diff --git a/drivers/net/depca.c b/drivers/net/depca.c index 6062a282fd7a..b6a596af5285 100644 --- a/drivers/net/depca.c +++ b/drivers/net/depca.c @@ -836,6 +836,13 @@ static int depca_start_xmit(struct sk_buff *skb, struct device *dev) } return status; } else if (skb->len > 0) { + if(skb->len < ETH_ZLEN) + { + skb = skb_padto(skb, ETH_ZLEN); + if(skb == NULL) + return 0; + } + /* Enforce 1 process per h/w access */ if (test_and_set_bit(0, (void *) &dev->tbusy) != 0) { printk("%s: Transmitter access conflict.\n", dev->name); diff --git a/drivers/net/eepro.c b/drivers/net/eepro.c index 72859cb14608..b03bfc11db34 100644 --- a/drivers/net/eepro.c +++ b/drivers/net/eepro.c @@ -1067,12 +1067,21 @@ static int eepro_send_packet(struct sk_buff *skb, struct device *dev) { struct eepro_local *lp = (struct eepro_local *)dev->priv; int ioaddr = dev->base_addr; + short length = skb->len; unsigned long flags; if (net_debug > 5) printk(KERN_DEBUG "%s: entering eepro_send_packet routine.\n", dev->name); + if(length < ETH_ZLEN) + { + skb = skb_padto(skb, ETH_ZLEN); + if(skb == NULL) + return 0; + length = ETH_ZLEN; + } + eepro_dis_int(ioaddr); spin_lock_irqsave(&lp->lock, flags); @@ -1094,7 +1103,6 @@ static int eepro_send_packet(struct sk_buff *skb, struct device *dev) printk(KERN_WARNING "%s: Transmitter access conflict.\n", dev->name); lp->stats.tx_aborted_errors++; } else { - short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN; if (hardware_send_packet(dev, skb->data, length)) /* we won't unset tbusy because we're out of space. */ diff --git a/drivers/net/eexpress.c b/drivers/net/eexpress.c index 8e03023c9e31..0fb3f94d900c 100644 --- a/drivers/net/eexpress.c +++ b/drivers/net/eexpress.c @@ -522,12 +522,21 @@ static void unstick_cu(struct device *dev) static int eexp_xmit(struct sk_buff *buf, struct device *dev) { struct net_local *lp = (struct net_local *)dev->priv; + short length = buf->len; unsigned long flags; #if NET_DEBUG > 6 printk(KERN_DEBUG "%s: eexp_xmit()\n", dev->name); #endif + if(buf->len < ETH_ZLEN) + { + buf = skb_padto(buf, ETH_ZLEN); + if(buf == NULL) + return 0; + length = buf->len; + } + disable_irq(dev->irq); /* @@ -571,8 +580,6 @@ static int eexp_xmit(struct sk_buff *buf, struct device *dev) } else { - unsigned short length = (ETH_ZLEN < buf->len) ? buf->len : - ETH_ZLEN; unsigned short *data = (unsigned short *)buf->data; lp->stats.tx_bytes += length; diff --git a/drivers/net/epic100.c b/drivers/net/epic100.c index 445d72c6770c..4571e06c48db 100644 --- a/drivers/net/epic100.c +++ b/drivers/net/epic100.c @@ -879,6 +879,13 @@ epic_start_xmit(struct sk_buff *skb, struct device *dev) int entry, free_count; u32 ctrl_word; long flags; + + if(skb->len < ETH_ZLEN) + { + skb = skb_padto(skb, ETH_ZLEN); + if(skb == NULL) + return 0; + } /* Block a timer-based transmit from overlapping. This could better be done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */ diff --git a/drivers/net/eth16i.c b/drivers/net/eth16i.c index 0f6e95bb6365..6fc3d0b525a7 100644 --- a/drivers/net/eth16i.c +++ b/drivers/net/eth16i.c @@ -1122,9 +1122,19 @@ static int eth16i_tx(struct sk_buff *skb, struct device *dev) status = -1; } else { - ushort length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN; + ushort length = skb->len; unsigned char *buf = skb->data; + if(length < ETH_ZLEN) + { + skb = skb_padto(skb, ETH_ZLEN); + if(skb == NULL) + { + dev->tbusy = 0; + return 0; + } + length = ETH_ZLEN; + } if( (length + 2) > (lp->tx_buf_size - lp->tx_queue_len)) { if(eth16i_debug > 0) printk(KERN_WARNING "%s: Transmit buffer full.\n", dev->name); diff --git a/drivers/net/fmv18x.c b/drivers/net/fmv18x.c index 749e1f1239c2..ce6e8ff1e366 100644 --- a/drivers/net/fmv18x.c +++ b/drivers/net/fmv18x.c @@ -369,7 +369,7 @@ net_send_packet(struct sk_buff *skb, struct device *dev) if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) printk("%s: Transmitter access conflict.\n", dev->name); else { - short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN; + short length = skb->len; unsigned char *buf = skb->data; if (length > ETH_FRAME_LEN) { @@ -378,6 +378,17 @@ net_send_packet(struct sk_buff *skb, struct device *dev) dev->name, length); return 1; } + + if (length < ETH_ZLEN) + { + skb = skb_padto(skb, ETH_ZLEN); + if(skb == NULL) + { + dev->tbusy = 0; + return 0; + } + length = ETH_ZLEN; + } if (net_debug > 4) printk("%s: Transmitting a packet of length %lu.\n", dev->name, diff --git a/drivers/net/hp100.c b/drivers/net/hp100.c index 5ac9da0a3051..663c8bd45800 100644 --- a/drivers/net/hp100.c +++ b/drivers/net/hp100.c @@ -1658,6 +1658,13 @@ static int hp100_start_xmit_bm( struct sk_buff *skb, struct device *dev ) if ( skb->len <= 0 ) return 0; + if (skb->len < ETH_ZLEN && lp->chip == HP100_CHIPID_SHASTA) + { + skb = skb_padto(skb, ETH_ZLEN); + if(skb == NULL) + return 0; + } + /* Get Tx ring tail pointer */ if( lp->txrtail->next==lp->txrhead ) { diff --git a/drivers/net/lance.c b/drivers/net/lance.c index 19b5ca7005f4..6ee6403470d4 100644 --- a/drivers/net/lance.c +++ b/drivers/net/lance.c @@ -919,8 +919,15 @@ static int lance_start_xmit(struct sk_buff *skb, struct device *dev) /* The old LANCE chips doesn't automatically pad buffers to min. size. */ if (chip_table[lp->chip_version].flags & LANCE_MUST_PAD) { - lp->tx_ring[entry].length = - -(ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN); + if(skb->len < ETH_ZLEN) + { + skb = skb_padto(skb, ETH_ZLEN); + if(skb == NULL) + goto out; + lp->tx_ring[entry].length = -ETH_ZLEN; + } + else + lp->tx_ring[entry].length = -skb->len; } else lp->tx_ring[entry].length = -skb->len; @@ -950,6 +957,7 @@ static int lance_start_xmit(struct sk_buff *skb, struct device *dev) dev->trans_start = jiffies; +out: save_flags(flags); cli(); lp->lock = 0; diff --git a/drivers/net/lp486e.c b/drivers/net/lp486e.c index 5daaf80b0e48..25ba8f4f9b8d 100644 --- a/drivers/net/lp486e.c +++ b/drivers/net/lp486e.c @@ -932,9 +932,22 @@ i596_start_xmit(struct sk_buff *skb, struct device *dev) { if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) { printk("%s: Transmitter access conflict.\n", dev->name); } else { - short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN; + short length; dev->trans_start = jiffies; + length = skb->len; + + if(length < ETH_ZLEN) + { + skb = skb_padto(skb, ETH_ZLEN); + if(skb == NULL) + { + dev->tbusy = 0; + return 0; + } + length = ETH_ZLEN; + } + tx_cmd = (struct tx_cmd *) kmalloc ((sizeof (struct tx_cmd) + sizeof (struct i596_tbd)), GFP_ATOMIC); diff --git a/drivers/net/ni5010.c b/drivers/net/ni5010.c index b5e959dddeda..060f1bd9586c 100644 --- a/drivers/net/ni5010.c +++ b/drivers/net/ni5010.c @@ -113,7 +113,7 @@ static void reset_receiver(struct device *dev); static int process_xmt_interrupt(struct device *dev); #define tx_done(dev) 1 -extern void hardware_send_packet(struct device *dev, char *buf, int length); +extern void hardware_send_packet(struct device *dev, char *buf, int length, int pad); extern void chipset_init(struct device *dev, int startp); static void dump_packet(void *buf, int len); static void show_registers(struct device *dev); @@ -457,7 +457,7 @@ static int ni5010_send_packet(struct sk_buff *skb, struct device *dev) } else { int length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN; - hardware_send_packet(dev, (unsigned char *)skb->data, length); + hardware_send_packet(dev, (unsigned char *)skb->data, length, length-skb->len); dev->trans_start = jiffies; } dev_kfree_skb (skb); @@ -702,7 +702,7 @@ ni5010_set_multicast_list(struct device *dev) } } -extern void hardware_send_packet(struct device *dev, char *buf, int length) +extern void hardware_send_packet(struct device *dev, char *buf, int length, int pad) { struct ni5010_local *lp = (struct ni5010_local *)dev->priv; int ioaddr = dev->base_addr; @@ -727,8 +727,8 @@ extern void hardware_send_packet(struct device *dev, char *buf, int length) if (NI5010_DEBUG > 3) dump_packet(buf, length); - buf_offs = NI5010_BUFSIZE - length; - lp->o_pkt_size = length; + buf_offs = NI5010_BUFSIZE - length - pad ; + lp->o_pkt_size = length + pad ; save_flags(flags); cli(); @@ -739,6 +739,9 @@ extern void hardware_send_packet(struct device *dev, char *buf, int length) outw(buf_offs, IE_GP); /* Point GP at start of packet */ outsb(IE_XBUF, buf, length); /* Put data in buffer */ + while(pad--) + outb(0, IE_XBUF); + outw(buf_offs, IE_GP); /* Rewrite where packet starts */ /* should work without that outb() (Crynwr used it) */ diff --git a/drivers/net/ni52.c b/drivers/net/ni52.c index 2035907fae96..c762300ee40d 100644 --- a/drivers/net/ni52.c +++ b/drivers/net/ni52.c @@ -1174,8 +1174,13 @@ static int ni52_send_packet(struct sk_buff *skb, struct device *dev) #endif else { + len = skb->len; + if(len < ETH_ZLEN) + { + len = ETH_ZLEN; + memset((char *)p->xmit_cbuffs[p->xmit_count]+skb->len, 0, len - skb->len); + } memcpy((char *)p->xmit_cbuffs[p->xmit_count],(char *)(skb->data),skb->len); - len = (ETH_ZLEN < skb->len) ? skb->len : ETH_ZLEN; #if (NUM_XMIT_BUFFS == 1) # ifdef NO_NOPCOMMANDS diff --git a/drivers/net/ni65.c b/drivers/net/ni65.c index 9e22ce1a412d..98a0a6d6634f 100644 --- a/drivers/net/ni65.c +++ b/drivers/net/ni65.c @@ -1124,6 +1124,8 @@ static int ni65_send_packet(struct sk_buff *skb, struct device *dev) memcpy((char *) p->tmdbounce[p->tmdbouncenum] ,(char *)skb->data, (skb->len > T_BUF_SIZE) ? T_BUF_SIZE : skb->len); + if(len > skb->len) + memset((char *)p->tmdbounce[p->tmdbouncenum]+skb->len, 0, len-skb->len); dev_kfree_skb (skb); save_flags(flags); diff --git a/drivers/net/seeq8005.c b/drivers/net/seeq8005.c index 3e183948b822..1ed48ca7aab0 100644 --- a/drivers/net/seeq8005.c +++ b/drivers/net/seeq8005.c @@ -393,9 +393,20 @@ seeq8005_send_packet(struct sk_buff *skb, struct device *dev) if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) printk("%s: Transmitter access conflict.\n", dev->name); else { - short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN; + short length = skb->len; unsigned char *buf = skb->data; + if(length < ETH_ZLEN) + { + skb = skb_padto(skb, ETH_ZLEN); + if(skb == NULL) + { + dev->tbusy = 0; + return 0; + } + length = ETH_ZLEN; + } + hardware_send_packet(dev, buf, length); dev->trans_start = jiffies; lp->stats.tx_bytes += length; diff --git a/drivers/net/sgiseeq.c b/drivers/net/sgiseeq.c index 89db13ed42c9..3febed9b5421 100644 --- a/drivers/net/sgiseeq.c +++ b/drivers/net/sgiseeq.c @@ -562,6 +562,8 @@ static int sgiseeq_start_xmit(struct sk_buff *skb, struct device *dev) * added this new entry and restarted it. */ memcpy((char *)td->buf_vaddr, skb->data, skblen); + if(len != skblen) + memset((char *)(long)td->buf_vaddr + skb->len, 0, len-skblen); td->tdma.cntinfo = ((len) & HPCDMA_BCNT) | (HPCDMA_XIU | HPCDMA_EOXP | HPCDMA_XIE | HPCDMA_EOX); if(sp->tx_old != sp->tx_new) { diff --git a/drivers/net/sk_g16.c b/drivers/net/sk_g16.c index 244df754479c..0fdbb9c21187 100644 --- a/drivers/net/sk_g16.c +++ b/drivers/net/sk_g16.c @@ -1175,6 +1175,7 @@ static int SK_send_packet(struct sk_buff *skb, struct device *dev) { struct priv *p = (struct priv *) dev->priv; struct tmd *tmdp; + static char pad[64]; if (dev->tbusy) { @@ -1221,6 +1222,8 @@ static int SK_send_packet(struct sk_buff *skb, struct device *dev) /* Copy data into dual ported ram */ memcpy_toio((tmdp->u.buffer & 0x00ffffff), skb->data, skb->len); + if(len != skb->len) + memcpy_toio((tmdp->u.buffer & 0x00ffffff) + skb->len, pad, len-skb->len); writew(-len, tmdp->blen); /* set length to transmit */ diff --git a/drivers/net/smc9194.c b/drivers/net/smc9194.c index 6ffedd115965..39f5128028ae 100644 --- a/drivers/net/smc9194.c +++ b/drivers/net/smc9194.c @@ -563,10 +563,20 @@ static int smc_wait_to_send_packet( struct sk_buff * skb, struct device * dev ) printk(CARDNAME": Bad Craziness - sent packet while busy.\n" ); return 1; } - lp->saved_skb = skb; - length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN; + length = skb->len; + if(length < ETH_ZLEN) + { + skb = skb_padto(skb, ETH_ZLEN); + if(skb == NULL) + { + netif_wake_queue(dev); + return 0; + } + length = ETH_ZLEN; + } + lp->saved_skb = skb; /* ** The MMU wants the number of pages to be the number of 256 bytes diff --git a/drivers/net/via-rhine.c b/drivers/net/via-rhine.c index 1c2cddbf3644..a55ed1bd04a5 100644 --- a/drivers/net/via-rhine.c +++ b/drivers/net/via-rhine.c @@ -969,6 +969,15 @@ static int start_tx(struct sk_buff *skb, struct device *dev) /* Calculate the next Tx descriptor entry. */ entry = np->cur_tx % TX_RING_SIZE; + if (skb->len < ETH_ZLEN) { + skb = skb_padto(skb, ETH_ZLEN); + if(skb == NULL) + { + dev->tbusy = 0; + return 0; + } + } + np->tx_skbuff[entry] = skb; if ((np->drv_flags & ReqTxAlign) && ((long)skb->data & 3)) { diff --git a/drivers/net/znet.c b/drivers/net/znet.c index 0884cb0d8440..6a692797fbd7 100644 --- a/drivers/net/znet.c +++ b/drivers/net/znet.c @@ -318,10 +318,19 @@ static int znet_send_packet(struct sk_buff *skb, struct device *dev) { int ioaddr = dev->base_addr; struct net_local *lp = (struct net_local *)dev->priv; + short length = skb->len; if (znet_debug > 4) printk(KERN_DEBUG "%s: ZNet_send_packet(%ld).\n", dev->name, dev->tbusy); + if(length < ETH_ZLEN) + { + skb = skb_padto(skb, ETH_ZLEN); + if(skb == NULL) + return 0; + length = ETH_ZLEN; + } + /* Transmitter timeout, likely just recovery after suspending the machine. */ if (dev->tbusy) { ushort event, tx_status, rx_offset, state; @@ -353,7 +362,6 @@ static int znet_send_packet(struct sk_buff *skb, struct device *dev) if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) printk(KERN_WARNING "%s: Transmitter access conflict.\n", dev->name); else { - short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN; unsigned char *buf = (void *)skb->data; ushort *tx_link = zn.tx_cur - 1; ushort rnd_len = (length + 1)>>1; diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index 1090e35a3b03..07aa1f490c98 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -149,6 +149,7 @@ extern void kfree_skbmem(struct sk_buff *skb); extern struct sk_buff * skb_clone(struct sk_buff *skb, int priority); extern struct sk_buff * skb_copy(struct sk_buff *skb, int priority); extern struct sk_buff * skb_realloc_headroom(struct sk_buff *skb, int newheadroom); +extern struct sk_buff * skb_pad(struct sk_buff *skb, int pad); #define dev_kfree_skb(a) kfree_skb(a) extern unsigned char * skb_put(struct sk_buff *skb, unsigned int len); extern unsigned char * skb_push(struct sk_buff *skb, unsigned int len); @@ -576,6 +577,26 @@ skb_cow(struct sk_buff *skb, unsigned int headroom) return skb; } +/** + * skb_padto - pad an skbuff up to a minimal size + * @skb: buffer to pad + * @len: minimal length + * + * Pads up a buffer to ensure the trailing bytes exist and are + * blanked. If the buffer already contains sufficient data it + * is untouched. Returns the buffer, which may be a replacement + * for the original, or NULL for out of memory - in which case + * the original buffer is still freed. + */ + +static inline struct sk_buff *skb_padto(struct sk_buff *skb, unsigned int len) +{ + unsigned int size = skb->len; + if(size >= len) + return skb; + return skb_pad(skb, len-size); +} + extern struct sk_buff * skb_recv_datagram(struct sock *sk,unsigned flags,int noblock, int *err); extern unsigned int datagram_poll(struct file *file, struct socket *sock, struct poll_table_struct *wait); extern int skb_copy_datagram(struct sk_buff *from, int offset, char *to,int size); diff --git a/net/core/skbuff.c b/net/core/skbuff.c index 93b757c98017..e2f3c941ad0e 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -312,6 +312,55 @@ struct sk_buff *skb_copy(struct sk_buff *skb, int gfp_mask) return n; } +struct sk_buff *skb_copy_grow(struct sk_buff *skb, int pad, int gfp_mask) +{ + struct sk_buff *n; + unsigned long offset; + + /* + * Allocate the copy buffer + */ + + n=alloc_skb(skb->end - skb->head + pad, gfp_mask); + if(n==NULL) + return NULL; + + /* + * Shift between the two data areas in bytes + */ + + offset=n->head-skb->head; + + /* Set the data pointer */ + skb_reserve(n,skb->data-skb->head); + /* Set the tail pointer and length */ + skb_put(n,skb->len); + /* Copy the bytes */ + memcpy(n->head,skb->head,skb->end-skb->head); + n->csum = skb->csum; + n->list=NULL; + n->sk=NULL; + n->dev=skb->dev; + n->priority=skb->priority; + n->protocol=skb->protocol; + n->dst=dst_clone(skb->dst); + n->h.raw=skb->h.raw+offset; + n->nh.raw=skb->nh.raw+offset; + n->mac.raw=skb->mac.raw+offset; + memcpy(n->cb, skb->cb, sizeof(skb->cb)); + n->used=skb->used; + n->is_clone=0; + atomic_set(&n->users, 1); + n->pkt_type=skb->pkt_type; + n->stamp=skb->stamp; + n->destructor = NULL; + n->security=skb->security; +#ifdef CONFIG_IP_FIREWALL + n->fwmark = skb->fwmark; +#endif + return n; +} + struct sk_buff *skb_realloc_headroom(struct sk_buff *skb, int newheadroom) { struct sk_buff *n; @@ -362,6 +411,36 @@ struct sk_buff *skb_realloc_headroom(struct sk_buff *skb, int newheadroom) return n; } +/** + * skb_pad - zero pad the tail of an skb + * @skb: buffer to pad + * @pad: space to pad + * + * Ensure that a buffer is followed by a padding area that is zero + * filled. Used by network drivers which may DMA or transfer data + * beyond the buffer end onto the wire. + * + * May return NULL in out of memory cases. + */ + +struct sk_buff *skb_pad(struct sk_buff *skb, int pad) +{ + struct sk_buff *nskb; + + /* If the skbuff is non linear tailroom is always zero.. */ + if(skb_tailroom(skb) >= pad) + { + memset(skb->data+skb->len, 0, pad); + return skb; + } + + nskb = skb_copy_grow(skb, pad, GFP_ATOMIC); + kfree_skb(skb); + if(nskb) + memset(nskb->data+nskb->len, 0, pad); + return nskb; +} + #if 0 /* * Tune the memory allocator for a new MTU size. -- 2.39.5