如何在Linux内核中为IPv6添加一种新的扩展头

如何在Linux内核中为IPv6添加一种新的扩展头,第1张

IPv6头部的设计是一个简洁型拿的基本头部后面根据需要加上多种不同类型的扩展头部,这种设计可以将不常用的功能通过选择性的添加不同的扩展头部实现,从而在保证了基本头部的简洁和处理的快速性。以Linux2.6.28版本内核为例,IPv6扩展首部的定义在Linux-2.6.28/include/linux/in6.h和linux-2.6.28/include/net/ipv6.h两个目录下,我们以添加一种IPPROTO_MY类型的扩展头为例:

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


欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/tougao/12256451.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-05-24
下一篇 2023-05-24

发表评论

登录后才能评论

评论列表(0条)

保存