IP fragmented
Benedykt Kroplewski
mlody en popnet.pl
Sab Ene 29 11:46:50 CST 2000
Hi
I have written a driver to the new hardware. It is serial, synchronous,
ISA
based, communication card but it doesn't meter now. It is mmio driven with
IRQ's without DMA on the ISA.
I send pure TCP/IP packets without any hardware headers etc... It's like
point-to-point through completely transparent hardware.
When I send a packet which is smaller or equal to the actually set MTU
value then everything work perfectly.
The problem starts when I try to send a packet which is grater then
actually set MTU.
As expected, the larger packet is fragmented into smaller parts and it
goes to the second machine. It is received by the second machine but it is
lost in system. It looks like the second computer does not glue fragmented
packets....!
But if I send fragments with delay (udelay(1000)) or more then the second
computer recognizes it sometimes and responds properly.
Normal packets below MTU size don't need any delay.
When I set larger value of MTU I can ping with the packet size up to the
new MTU.
Again, when I send packets of a size less then MTU then it works great.
I attached source files here. Please look at it, maybe I miss something or
I don't know about some additional issues.
Please help.
Regards,
Benedykt Kroplewski
------------ próxima parte ------------
/* v35.c
* Copyright (C) 1999-2000 by Benedykt Kroplewski
* e-mail: mlody en popnet.pl ,tel. 0-501-853172
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/types.h>
#include <linux/fcntl.h>
#include <linux/interrupt.h>
#include <linux/ptrace.h>
#include <linux/ioport.h>
#include <linux/in.h>
#include <linux/malloc.h>
#include <linux/string.h>
#include <asm/system.h>
#include <asm/bitops.h>
#include <asm/io.h>
#include <asm/dma.h>
#include <linux/errno.h>
#include <linux/init.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/skbuff.h>
#include <linux/if_arp.h>
#include <linux/if_slip.h>
#include <linux/delay.h>
#define MTU 1500
#define DOFF 0x10 /* Data offset */
#define ROFF 0x8 /* Registers offset 0x8 */
static long base = 0x00000;
#include "bin.h"
#include "db.c"
int v35_init(struct device *dev);
static void v35_interrupt(int irq, void *dev_id, struct pt_regs * regs);
static int v35_open(struct device *dev);
static int v35_stop(struct device *dev);
static int v35_send(struct sk_buff *skb, struct device *dev);
static struct net_device_stats *v35_stat(struct device *dev);
static const char *version =
"v35.c:v1.0 1999 Benedykt Kroplewski (mlody en sic.popnet.pl)\n";
static const char* irqname = "v35card";
static char v35name[10] = {"wan0\0"};
static struct device v35dev = { v35name,0,0,0,0,0,0,0,0,0,NULL,v35_init };
static struct net_device_stats stats;
static int irq = 0;
MODULE_PARM(irq,"i");
MODULE_PARM(base,"i");
int v35_init(struct device *dev)
{
int irqval,i;
printk("v35_init(%s);\n",dev->name);
printk(KERN_DEBUG "%s", version);
irqval = request_irq(dev->irq, &v35_interrupt, 0, irqname, dev);
if (irqval) { printk("%s: unable to get IRQ %d (irqval=%d).\n",dev->name, dev->irq, irqval); return -EAGAIN; }
initcard(dev->base_addr);
for(i=0;i<20000;i++) readb(dev->base_addr+DOFF);
printk("read 20 000 bytes\n");
dev->open = v35_open;
dev->stop = v35_stop;
dev->hard_start_xmit = v35_send;
dev->get_stats = v35_stat;
dev->mtu = 1500;
dev->hard_header_len = 0;
dev->addr_len = 0;
dev->type = ARPHRD_SLIP;
dev->tx_queue_len = 10;
dev_init_buffers(dev);
dev->flags = IFF_NOARP|IFF_POINTOPOINT;
return 0;
}
static void v35_got(struct device *dev,int wielkosc)
{
struct sk_buff *skb;
int i;
stats.rx_bytes+=wielkosc-3;
skb = dev_alloc_skb(wielkosc-1);
skb_put(skb,wielkosc-1);
skb->dev = dev;
for(i=0;i<=wielkosc-3;i++)
*(skb->data+i) = readb(dev->base_addr+DOFF);
skb->pkt_type = PACKET_HOST;
skb->mac.raw=skb->data;
skb->protocol=htons(ETH_P_IP);
netif_rx(skb);
stats.rx_packets++;
}
/* numer = numer & BIN00111111; ---> zerowanie pierwszych 2 bitow */
/* numer = numer ^ BIN11000000; ---> zapalanie pierwszych 2 bitow */
static void v35_interrupt(int irq, void *dev_id, struct pt_regs * regs)
{
struct device *dev = dev_id;
unsigned char reg1,reg3,reg7,reg6,znak,tmp;
int what_irq=0;
int wielkosc=0;
int error=0;
/* long flags; */
dev->interrupt = 1;
/*
save_flags(flags);
cli();
*/
reg3 = readregister(3,dev->base_addr);
/******************************* IRQ RX ********************************************************/
if((reg3 & 0x20) == 0x20)
{ what_irq++;
readregister(2,dev->base_addr);
do {
reg7 = readregister(7,dev->base_addr);
reg6 = readregister(6,dev->base_addr);
reg1 = readregister(1,dev->base_addr);
if((reg1 & 0x10) == 0x10) /* bit 4 */
{ writeb(0x30,base+ROFF); error = 4; } /* E4 */
if((reg1 & 0x20) == 0x20) /* bit 5 */
{ writeb(0x30,base+ROFF); error = 5; } /* E5 */
if((reg1 & 0x40) == 0x40) /* bit 6 */
{ writeb(0x30,base+ROFF); error = 6; } /* E6 */
if((reg1 & 0x80) == 0x80) ; /* bit 7 */
tmp = reg7 & BIN00111111;
wielkosc = tmp << 8;
wielkosc = wielkosc + reg6;
v35_got(dev,wielkosc);
znak = readb(dev->base_addr+DOFF);
znak = readb(dev->base_addr+DOFF);
znak = readb(dev->base_addr+DOFF);
reg7 = readregister(7,dev->base_addr);
reg7 = readregister(7,dev->base_addr);
}
while( (reg7 & BIN01000000) == BIN01000000 );
if(error != 0) printk("RX error nr. %d\n",error);
writeb(0x38,base+ROFF);
printk("v35_interrupt(%s,Rx,%s,SIZE=%d,ERROR=%d);\n",dev->name,char2bin(reg3),wielkosc-3,error);
}
/************************************ IRQ TX *******************************************************/
if((reg3 & 0x8) == 0x8)
{ what_irq++;
stats.tx_packets++;
udelay(1000);
dev->tbusy = 0;
mark_bh(NET_BH);
readregister(2,dev->base_addr);
printk("v35_interrupt(%s,Tx,%s);\n",dev->name,char2bin(reg3));
writeb(0x10,base+ROFF);
writeb(0x10,base+ROFF);
writeb(0x38,base+ROFF);
}
/***************************** IRQ unknown *********************************************************/
if(what_irq == 0)
{
readregister(2,dev->base_addr);
printk("v35_interrupt(%s,UNKNOWN,%s);\n",dev->name,char2bin(reg3));
writeb(0x10,base+ROFF);
writeb(0x10,base+ROFF);
writeb(0x38,base+ROFF);
}
/*
restore_flags(flags);
*/
dev->interrupt = 0;
return;
}
static int v35_open(struct device *dev)
{
printk("v35_open(%s);\n",dev->name);
MOD_INC_USE_COUNT;
dev->start = 1;
dev->tbusy = 0;
return 0;
}
static int v35_stop(struct device *dev)
{
printk("v35_stop(%s);\n",dev->name);
dev->start = 0;
dev->tbusy = 1;
free_irq(dev->irq, dev);
MOD_DEC_USE_COUNT;
return 0;
}
long flags;
static int v35_send(struct sk_buff *skb, struct device *dev)
{
int len,i;
unsigned char *data;
dev->trans_start = jiffies;
len = skb->len;
data = skb->data;
if(!dev->interrupt)
{
save_flags(flags);
cli();
for(i=0;i<=len;i++)
writeb(*(data+i),dev->base_addr+DOFF);
dev->tbusy=1;
restore_flags(flags);
/* printk("%s: transmit %d bytes\n",dev->name,len); */
stats.tx_bytes+=skb->len;
dev->trans_start = jiffies;
dev_kfree_skb(skb);
}
return 0;
}
static struct net_device_stats *v35_stat(struct device *dev)
{
return &stats;
}
int init_module(void)
{
int result;
if(irq == 0) { printk("insmod v35.o irq=NUMER base=ADDRESS\n"); return 1; }
if(base == 0) { printk("insmod v35.o irq=NUMER base=ADDRESS\n"); return 1; }
v35dev.base_addr = base;
v35dev.irq = irq;
if((result = register_netdev(&v35dev)) != 0) return result;
return 0;
}
void cleanup_module(void)
{
printk("cleanup_module();\n");
unregister_netdev(&v35dev);
}
/* end. */
Más información sobre la lista de distribución Ayuda