- 论坛徽章:
- 0
|
本帖最后由 leonwang202 于 2011-07-13 19:49 编辑
小弟最近写了个测试程序
1.通过dev_add_pack() 加入了自己的钩子函数,
2.软中断里调用钩子函数,把从eth1网卡上来的skb放入到一个接收队列中,
3.当用户调read的时候,从队列上取出skb,将skb->data传给用户空间。
模块程序跑在 linux-2.6.18 smp 上,总是panic 死在skb_queue_tail() 这个函数上。。。
各位大牛看一下,哪里出的问题,下面是主要代码- #define IF_NAME "eth1"
- struct net_device *netdev; //eth1所对应的网卡
- int hack_recv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt, struct net_device *orig_dev)
- {
- if(netdev != dev){ //只接受eth1网卡上的skb
- kfree_skb(skb);
- return 0;
- }
- nskb = skb_clone(skb, GFP_ATOMIC);
- kfree_skb(skb);
- skb_queue_tail(&rcv_queue, nskb); //将skb加入到接收队列
- if( waitqueue_active(&rcv_waitqueue) ) //唤醒阻塞的进程
- wake_up_interruptible(&rcv_waitqueue);
- return 0;
- }
- static struct packet_type net_hack_type =
- {
- .type = __constant_htons(ETH_P_IP), //只把IP包传给用户空间
- .func = hack_recv, //钩子函数
- };
- int my_open(struct inode *inode, struct file *filp) //字符设备对应的open操作
- {
- netdev = dev_get_by_name(IF_NAME); //找到eth1对应的netdev
- skb_queue_head_init(&rcv_queue); //初始化接收队列
- dev_add_pack(&net_hack_type); //添加自己的钩子函数
- return 0;
- }
- int my_release(struct inode * inode, struct file * filp) //字符设备对应的release操作
- {
- dev_remove_pack(&net_hack_type);
- skb_queue_purge(&rcv_queue);
- return 0;
- }
- ssize_t my_read(struct file *filp, char __user *buf, size_t len, loff_t *f_pos)//字符设备对应的read操作
- {
- ssize_t copied = 0;
- ssize_t to_copy = 0;
- struct sk_buff *skb = NULL;
- char *tmp = buf;
- do{
- wait_event_interruptible(rcv_waitqueue,!skb_queue_empty(&rcv_queue)); //接收队列没包的话,阻塞在这里
- skb = skb_dequeue(&rcv_queue); //取包
- if(!skb)
- goto out;
- to_copy = skb->len;
- if( to_copy > (len - copied)) { //用户空间buf不足
- skb_queue_head(&rcv_queue, skb);
- goto out;
- }
- copy_to_user(tmp, skb->data, skb->len);
- kfree_skb(skb);
- copied += to_copy;
- tmp = buf + copied;
- } while(copied < len);
- out:
- return copied;
- }
复制代码 模块程序运行后,总是随机panic在 skb_queue_tail()
BUG: unable to handle kernel NULL pointer dereference at virtual address 00000000
EIP is at skb_queue_tail+0x17/0x2d
初步怀疑是同步没做好,
接收队列rcv_queue 只在软中断和用户进程上下文中共享
我看了下skb_queue_tail() 和skb_dequeue()的实现,操作接收队列时,用spin_lock_irqsave()和spin_unlock_irqrestore()保护了啊,为什么还会出现上面的panic 呢? |
|