读书人

写一个以太网驱动在hard_start_xmit

发布时间: 2012-03-23 12:06:21 作者: rapoo

写一个以太网驱动,在hard_start_xmit中访问dev->priv中的成员,出现崩溃
struct net_device *veth_devs[VETH_NUM];

static int
veth_open(struct net_device *dev)
{
veth_private_s *vep ;

vep = (veth_private_s *)dev->priv;

vep->dev = dev; /*Remember dev in veth_private_s*/

queue_delayed_work(vep->rx_poll, &vep->rx_poll_task, POLL_SPEED);

netif_start_queue(dev);

printk(KERN_ALERT "%s: %s \r\n", dev->name, __FUNCTION__);

return 0;/* Always succeed */
}

static int
veth_close(struct net_device *dev)
{
veth_private_s *vep ;

vep = (veth_private_s *)dev->priv;

netif_stop_queue(dev);

flush_workqueue(vep->rx_poll);
cancel_delayed_work(&vep->rx_poll_task);

printk(KERN_ALERT "%s: %s \r\n", dev->name, __FUNCTION__);

return 0;
}

#if 1
static int
veth_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
int i;
char *p;
char tmp[4];

veth_private_s*vep = (veth_private_s *)dev->priv;

printk(KERN_ALERT "%s: %s \r\n", dev->name, __FUNCTION__);

vep->rx_buff = (unsigned char *)kmalloc(VETH_RX_BUFFSIZE, GFP_KERNEL);

memset(vep->rx_buff, 0, VETH_RX_BUFFSIZE);

memcpy(vep->rx_buff, skb->data, skb->len); //这里出现崩溃,系统重启
#if 0
p = vep->rx_buff;
//p = skb->data;

if(skb->len > 0){
printk(KERN_ALERT "%s: veth_start_xmit len=%d \r\n", dev->name, skb->len);

for(i=0; i<skb->len; i++){
if(i%20 == 0)
printk(KERN_ALERT "\r\n");
else{
memset(tmp, 0, 4);
sprintf(tmp, "%d", vep->rx_buff[i]);
printk(KERN_ALERT "%d,%s,%d ", i, tmp, vep->rx_buff[i]);
}
}
printk("\r\n");
}
#endif

dev_kfree_skb(skb);

return 0; /* Our simple device can not fail */
}
#endif

static void veth_rx_poll(struct work_struct *work)
{
veth_private_s *vep =
container_of(work, veth_private_s, rx_poll_task.work);

struct net_device *dev = vep->dev;

printk(KERN_ALERT "%s: %s \r\n", dev->name, __FUNCTION__);

//dev_kfree_skb(skb);

queue_delayed_work(vep->rx_poll, &vep->rx_poll_task, POLL_SPEED);
}

void veth_init(struct net_device *dev)
{
veth_private_s*vep;
bd_t*bd;
inti;
static charmc_addr4= 0x0;
static charmc_addr5= 0x0;

bd = (bd_t *)__res;

/*
* Make the usual checks: check_region(), probe irq, ... -ENODEV
* should be returned if no device found. No resource should be
* grabbed: this is done on open().
*/

ether_setup(dev); /* assign some of the fields */

dev->open= veth_open;
dev->stop= veth_close;
dev->hard_start_xmit= veth_start_xmit;
dev->watchdog_timeo = TX_TIMEOUT;

/*
dev->set_config= snull_config;
dev->do_ioctl= snull_ioctl;
dev->get_stats= snull_stats;
dev->change_mtu= snull_change_mtu;
dev->rebuild_header= snull_rebuild_header;
dev->hard_header= snull_header;
dev->tx_timeout= snull_tx_timeout;
dev->watchdog_timeo= timeout;
*/

/* keep the default flags, just add NOARP */
dev->flags|= IFF_NOARP;
dev->features|= NETIF_F_NO_CSUM;
dev->hard_header_cache= NULL; /* Disable caching */

vep = netdev_priv(dev);
//vep->rx_buff = (unsigned char *)kmalloc(VETH_RX_BUFFSIZE, GFP_KERNEL);

memset(vep, 0, sizeof(veth_private_s));
spin_lock_init(&vep->lock);


vep->rx_poll = create_singlethread_workqueue("rx_poll");
INIT_DELAYED_WORK(&vep->rx_poll_task, veth_rx_poll);

for (i=5; i>=0; i--)
dev->dev_addr[i] = bd->bi_enetaddr[i];

mc_addr4++;
mc_addr5++;

dev->dev_addr[4] += mc_addr4;
dev->dev_addr[5] += mc_addr5;
}

static void __exit veth_exit_module(void)
{
int i;

for (i=0; i<VETH_NUM; i++) {
if (veth_devs[i]) {
unregister_netdev(veth_devs[i]);
free_netdev(veth_devs[i]);
}
}

return;
}

static int __init veth_init_module(void)
{
int result, i, ret = -ENOMEM;

for(i=0; i<VETH_NUM; i++){
veth_devs[i] = alloc_netdev(sizeof(struct veth_private), VETH_NAME_FORMAT,
veth_init);
}

for(i=0; i<VETH_NUM; i++){
if (veth_devs[i] == NULL)
goto out;
}

for (i=0; i<VETH_NUM; i++){
if ((result = register_netdev(veth_devs[i]))){
printk("veth: error %i registering device \"%s\"\n",
result, veth_devs[i]->name);
ret = -ENODEV;
}else{
ret = 0;
}
}

out:

if (ret)
veth_exit_module();
else
printk(KERN_ALERT "veth: %s \r\n", __FUNCTION__);

return 0;
}

module_init(veth_init_module);
module_exit(veth_exit_module);


崩溃时打印如下信息:
PING 192.168.1.0 (192.168.1.0): 56 data bytes
veth0: veth_start_xmit
Oops: kernel access of bad area, sig: 11 [#1]
NIP: C000AE78 LR: C3069278 CTR: 0000000C
REGS: c1cd7ac0 TRAP: 0300 Not tainted (2.6.20)
MSR: 00009032 <EE,ME,IR,DR> CR: 24000028 XER: 00000000
DAR: 00000001, DSISR: C0000000
TASK = c1c6a450[19917] 'ping' THREAD: c1cd6000
GPR00: 00000000 C1CD7B70 C1C6A450 C1F093A0 FFFFFFFD 00000062 C1F0939C 0000000C
GPR08: FF002900 00000001 00001006 C000AE5C 24000028 100E423C 01FFF200 00000000
GPR16: 01FF67E4 00000000 1008E7C8 10099E89 100E025C 7FDA64F8 100E023C 00000000
GPR24: 00000040 00000000 00000000 C01B9A64 C1AC9260 C14497A0 C14497A0 C1AC9000
Call Trace:
[C1CD7B70] [C3069258] (unreliable)
[C1CD7B90] [C0126D0C]
[C1CD7BB0] [C0134C5C]
[C1CD7BD0] [C0128FD8]
[C1CD7BF0] [C012C990]
[C1CD7C10] [C0144570]
[C1CD7C50] [C01430A0]
[C1CD7C80] [C015E7DC]
[C1CD7D10] [C01667D0]
[C1CD7D30] [C011C164]
[C1CD7E20] [C011C4A4]
[C1CD7F00] [C011CE10]
[C1CD7F40] [C0002A84]
Instruction dump:
38c60001 4200fff0 4e800020 7c032040 418100a0 54a7e8ff 38c3fffc 3884fffc
41820028 70c00003 7ce903a6 40820054 <80e40004> 85040008 90e60004 95060008
Kernel panic - not syncing: Aiee, killing interrupt handler!
<0>Rebooting in 1 seconds..

[解决办法]
疑问:alloc_netdev函数分配了标准结构和私有结构,然后调用netdev_priv获取私有结构指针,问题是你怎么就能确定标准结构的priv域指向了私有结构指针呢?为什么不调用netdev_priv函数来获取私有结构指针呢?
alloc_netdev和netdev_priv好像并没有对priv域进行初始化工作。
[解决办法]
kmalloc(VETH_RX_BUFFSIZE

这个需要判断返回是否为空吧,你这个好像会有内存泄漏,最后肯定会失败。
还有长度够了没有吧,调一下mtu测试看看
你现在一上来就在这里失败?
[解决办法]
试试比较一下VETH_RX_BUFFSIZE和skb->len两者大小!!!
[解决办法]
驱动运行的处理器体系结构是?!
[解决办法]

探讨
引用:


如果是RISC体系结构,可能存在地址对齐问题,即memcpy的目标drs和源地址src,请查看一下。


CPU是是PowerPC的MPC852
请问该如何查看目标drs和源地址src呢,怎么知道这两个地址是否有问题?

读书人网 >UNIXLINUX

热点推荐