1、在头文件中添加新类型扩展头的定义,在linux-2.6.28/include/linux/in6.h中
/*
* NextHeader field of IPv6 header
*/
#define NEXTHDR_HOP 0 /* Hop-by-hop option header. */
#define NEXTHDR_TCP 6 /* TCP segment. */
#define NEXTHDR_UDP 17 /* UDP message. */
#define NEXTHDR_IPV6 41 /* IPv6 in IPv6 */
#define NEXTHDR_ROUTING 43 /* Routing header. */
#define NEXTHDR_FRAGMENT 44 /* Fragmentation/reassembly header. */
#define NEXTHDR_ESP 50 /* Encapsulating security payload. */
#define NEXTHDR_AUTH 51 /* Authentication header. */
#define NEXTHDR_ICMP 58 /* ICMP for IPv6. */
#define NEXTHDR_NONE 59 /* No next header */
#define NEXTHDR_DEST 60 /* Destination options header. */
#define NEXTHDR_MOBILITY 135 /* Mobility header. */
#define IPPROTO_MY 200/*自己定义的头部类型 */
2、在linux-2.6.28/include/net/卜瞎搭ipv6.h中定义结构体
/*
* IPV6 extension headers
*/
#define IPPROTO_HOPOPTS 0 /* IPv6 hop-by-hop options */
#define IPPROTO_ROUTING 43 /* IPv6 routing header */
#define IPPROTO_FRAGMENT 44 /* IPv6 fragmentation header */
#define IPPROTO_ICMPV6 58 /* ICMPv6 */
#define IPPROTO_NONE 59 /* IPv6 no next header */
#define IPPROTO_DSTOPTS 60 /* IPv6 destination options */
#define IPPROTO_MH 135 /神前* IPv6 mobility header */
自己定义新的扩展头类型如:
#define NEXTHDR_INDEX200/*IPv6 next header */
自己定义新的扩展头类型:
struct index_hdr{ /*index扩展头结构*/
__u8nexthdr
__u8hdrlen
__u16 reserved
__u32 skb_index
}
3、在需要添加头部和删除头部的源文件中添加添加和删除函数,届时直接调用这两个函数即可
static void ip6_index_add(struct sk_buff *skb,unsigned char *data,unsigned int len)
{
struct ipv6hdr *tmp_hdr
struct ipv6hdr *old_hdr
struct index_hdr *ih
u8 prevhdr
unsigned int hlen
unsigned int ilen
ilen=sizeof(struct index_hdr)
hlen=sizeof(struct ipv6hdr)
old_hdr=skb_network_header(skb)
prevhdr=old_hdr->nexthdr
if(prevhdr!=200){
old_hdr->nexthdr=NEXTHDR_INDEX
tmp_hdr = kmemdup(skb_network_header(skb), hlen, GFP_ATOMIC)
__skb_pull(skb, hlen) /*使data指针下移hlen长度,将ipv6头部去掉*/
ih = (struct index_hdr*)__skb_push(skb, ilen) /*上移data指针,将index头部添加进去*/
__skb_push(skb, hlen) /*继续上移data指针,将原来的ipv6头部加进去*/
skb_reset_network_header(skb)
memcpy(skb_network_header(skb), tmp_hdr, hlen)
/*为index扩展头赋值*/
ih->nexthdr = prevhdr
ih->hdrlen = 8
ih->reserved = 0
ih->skb_index = htonl(skb->xfrm_index)
skb->truesize += ilen
ipv6_hdr(skb)->payload_len += ilen
data = skb->data
len = skb->len
kfree(tmp_hdr)
}
}
static void ip6_index_del(struct sk_buff *skb,unsigned char *data,unsigned int len)
{
struct ipv6hdr *tmp_hdr
struct ipv6hdr *old_hdr
struct index_hdr *ih
u8 prevhdr
unsigned int hlen
unsigned int ilen
ilen=sizeof(struct index_hdr)
hlen=sizeof(struct ipv6hdr)
if(ipv6_hdr(skb)->nexthdr == 200){
tmp_hdr = kmemdup(skb_network_header(skb), hlen, GFP_ATOMIC)/*保存ipv6头*/
__skb_pull(skb, hlen) /*下移data指针,去掉ipv6头*/
skb_reset_network_header(skb)
ih=(struct index_hdr *)skb_network_header(skb)
prevhdr = ih->nexthdr
tmp_hdr->nexthdr = prevhdr
__skb_pull(skb, ilen) /*下移data指针,去掉index扩展头*/
__skb_push(skb, hlen)/*上移data指针,将原来的ipv6头添加回去*/
skb_reset_network_header(skb)
memcpy(skb_network_header(skb), tmp_hdr, hlen)
skb_reset_network_header(skb)
skb->truesize -= ilen
ipv6_hdr(skb)->payload_len -= ilen
kfree(tmp_hdr)
}
}
你这个有点乱哦。。看得头晕得很。。 还有你这里错误的主要地方是。编写字符设备孝陵衫模块的时候不需要再制定交叉编译器。因为实行makemodules 的时候会找到你内核里面顶层makefile 里面的交叉编译器。我这里有一个简单的字符设备模块。不妨可以借鉴看一下。需要自己手动添加一个设备节点。我程序里面使用的是主设备号是240 次设备号是0.
原文地址 通过测试:不过还有一点小问题,就是 模块的卸载需要使用rmmod mymod 不加.ko 具体原因我也没弄明白。这里面包含了 字符设备file_operations 函数。但是用户层的应用需要你自己完成。
http://www.ebhou.com/post/chrcdev.html
#include <linux/init.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/mm.h>
#include <linux/sched.h>
#include <linux/cdev.h>
#include <asm/io.h>
#include <asm/system.h>
#include <asm/uaccess.h>
//设备驱动应该包含的头文件
#define MYMODE_SIZE 0x1000
#define MYMODE_MAJOR 240
#define MEM_CLEAR 0x1
static int mymode_major = MYMODE_MAJOR//设备主节点号
struct mymode_dev{ //定义 设备结构体
struct cdev cdev
unsigned char mem[MYMODE_SIZE]
}
struct mymode_dev *mymode//设备结构体指针
static ssize_t mymode_read(struct file * filp,char __user *buf,size_t size,loff_t *ppos) //设备读 *** 作函数
{
unsigned long p = *ppos
unsigned int count = size
int ret = 0
struct mymode_dev *modedev = filp->private_data
if(p>MYMODE_SIZE)
{
printk(KERN_INFO"err of poss %d\n",p)
return 0
}
if(count >(MYMODE_SIZE-p))
count = MYMODE_SIZE-p
if(copy_to_user(buf,(void *)(modedev->巧腔mem+p),count)){
ret = - EFAULT
}else{
*ppos +=count
ret = count
printk(KERN_INFO"read %d bytes from %d\n",count,p)
}
return ret
}
static ssize_t mymode_write(struct file *filp,const char __user *buf,size_t size,loff_t *ppos) //设备写 *** 作函数
{
unsigned long p = *ppos
unsigned int count = size
int ret = 0
struct mymode_dev *modedev = filp->private_data
if(count >(MYMODE_SIZE-p))
count = MYMODE_SIZE-p
if(copy_from_user((modedev->mem+p),buf,count)){
ret = - EFAULT
}else{
*ppos +=count
ret = count
printk(KERN_INFO"write %d bytes from %d\n"汪孙,count,p)
}
return ret
}
static loff_t mymode_llseek(struct file *filep,loff_t offset,int orig) //设置偏移定位 *** 作函数
{
loff_t ret = 0
switch(orig)
{
case 0:
if(offset <0 )
{
printk(KERN_INFO"ERR OFFSET\n")
ret = - EINVAL
break
}
if(offset >= MYMODE_SIZE)
{
filep->f_pos = MYMODE_SIZE-1
ret = MYMODE_SIZE-1
break
}
filep->f_pos = offset
ret = offset
break
case 1:
if(filep->f_pos + offset >MYMODE_SIZE-1)
{
filep->f_pos = MYMODE_SIZE-1
ret = MYMODE_SIZE-1
break
}else if(filep->f_pos + offset <0){
filep->f_pos = 0
ret = 0
break
}
filep->f_pos += offset
ret = offset
break
case 2:
if(filep->f_pos + offset >MYMODE_SIZE-1)
{
filep->f_pos = MYMODE_SIZE-1
ret = MYMODE_SIZE-1
break
}else if(filep->f_pos + offset <0){
filep->f_pos = 0
ret = 0
break
}
filep->f_pos += offset
ret = offset
break
default:
break
}
}
static int mymode_ioctl(struct inode *inodep,struct file *filep,unsigned int cmd ,unsigned long arg) //设备ioctl 函数只简单的实现了对内存区域的清0 当然你也可以自己添加一些你想要实现的功能。不管怎样你得电脑你做主。
{
struct mymode_dev *modedev = filep->private_data
switch(cmd)
{
case MEM_CLEAR:
memset(modedev->mem,0,MYMODE_SIZE)
printk(KERN_INFO"Clear the mem to be zero\n")
break
default:
printk(KERN_INFO"Clear the mem to be zero\n")
break
}
return 0
}
static int mymode_open(struct inode *inodep,struct file *filep)
{
filep->private_data = mymode
return 0
}
static int mymode_release(struct inode *inodep,struct file *filep)
{
return 0
}
static const struct file_operations mymode_fops={ // cdev 设备的file_operations 结构体 主要实现了 开关 读写 设置偏移量 和ioctl 函数
.owner = THIS_MODULE,
.llseek = mymode_llseek,
.read = mymode_read,
.write = mymode_write,
.ioctl = mymode_ioctl,
.open = mymode_open,
.release = mymode_release,
}
int mymode_init(void) //模块加载初始化函数。设备的入口函数
{
int err,res
dev_t devno = MKDEV(mymode_major,0)
if(mymode_major)
res = register_chrdev_region(&devno,1,"mymode")//register the cdev no
else{
res = alloc_chrdev_region(&devno,0,1,"mymode")
mymode_major = MAJOR(devno)
}
if(res <0)
return res
mymode = kmalloc(sizeof(struct mymode_dev),GFP_KERNEL)
if(mymode == NULL)
{
printk(KERN_INFO"kmalloc failed\n")
unregister_chrdev_region(MKDEV(MYMODE_MAJOR,0),1)
return -ENOMEM
}
memset(mymode,0,sizeof(struct mymode_dev))
cdev_init(&mymode->cdev,&mymode_fops)
mymode->cdev.owner = THIS_MODULE
err = cdev_add(&mymode->cdev,devno,1)
if(err){
printk("Error %d add mymode ",err)
unregister_chrdev_region(MKDEV(MYMODE_MAJOR,0),1)
}
printk("mymode insert\n")
return 0
}
void mymode_exit(void)//模块卸载函数 其主要内容是相对于设备初始化函数的反 *** 作。
{
cdev_del(&mymode->cdev)
kfree(mymode)
unregister_chrdev_region(MKDEV(MYMODE_MAJOR,0),1)
printk("mymode exit\n")
}
module_init(mymode_init)
module_exit(mymode_exit)
MODULE_AUTHOR("pink hou ")
MODULE_LICENSE("Dual BSD/GPL")
MODULE_DESCRIPTION("First Module")
MODULE_ALIAS("A simplest module")
这个是完整的C代码 具体的makefile 参考我的blog借鉴一下吧。这是我通过验证的 绝对没问题。
原文地址:http://www.ebhou.com/post/chrcdev.html
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)