如何计算kmalloc 大小所申请空间的大小

Linux内存管理基础教程
关于Linux的内存管理,本文分别从内核空间和用户空间两个视角来阐述
一、内核空间
页(page)是内核的内存管理基本单位。
==& linux/mm_types.h
struct page {
page_flags_t
atomic_t _
页引用计数
atomic_t _
页映射计数
unsigned long private;
私有数据指针
struct address_space *
该页所在地址空间描述结构指针,用于内容为文件的页帧
该页描述结构在地址空间radix树page_tree中的对象索引号即页号
struct list_
最近最久未使用struct slab结构指针链表头变量
void *virtual;
页虚拟地址
flags:页标志包含是不是脏的,是否被锁定等等,每一位单独表示一种状态,可同时表示出32种不同状态,定义在&linux/page-flags.h&
_count:计数值为-1表示未被使用。
virtual:页在虚拟内存中的地址,对于不能永久映射到内核空间的内存(比如高端内存),该值为NULL;需要事必须动态映射这些内存。
尽管处理器的最小可寻址单位通常为字或字节,但内存管理单元(MMU,把虚拟地址转换为物理地址的硬件设备)通常以页为单位处理。内核用struct page结构体表示每个物理页,struct page结构体占40个字节,假定系统物理页大小为4KB,对于4GB物理内存,1M个页面,故所有的页面page结构体共占有内存大小为40MB,相对系统4G,这个代价并不高。
内核把页划分在不同的区(zone)
总共3个区,具体如下:
物理内存(MB)
DMA使用的页
ZONE_NORMAL
可正常寻址的页
ZONE_HIGHMEM
动态映射的页
执行DMA操作的内存必须从ZONE_DMA区分配
一般内存,既可从ZONE_DMA,也可从ZONE_NORMAL分配,但不能同时从两个区分配;
1.3 页分配与释放
下面列举所有的页为单位进行连续物理内存分配,也称为低级页分配器:
页分配函数
alloc_pages(gfp_mask, order)
分配2^order个页,返回指向第一页的指针
alloc_pages(gfp_mask)
分配一页,返回指向页的指针
__get_free_pages(gfp_mask, order)
分配2^order个页,返回指向其逻辑地址的指针
__get_free_pages(gfp_mask)
分配一页,返回指向其逻辑地址的指针
get_zeroed_page(gfp_mask)
分配一页,并填充内容为0,返回指向其逻辑地址的指针
get_zeroed_page:对于用户空间,这个方法能保障系统敏感数据不会泄露
page_address: 把给定的页转换成逻辑地址
页释放函数
__free_pages(page, order)
从page开始,释放2^order个页
free_pages(addr, order)
从地址addr开始,释放2^order个页
free_page(addr)
释放addr所在的那一页
1.4 字节分配与释放
kmalloc,vmalloc分配都是以字节为单位
(1) kmalloc
void * kmalloc(size_t size, gfp_t flags)
该函数返回的是一个指向内存块的指针,其内存块大小至少为size,所分配的内存在物理内存中连续且保持原有的数据(不清零)
其中部分flags取值说明:
GFP_USER: 用于用户空间的分配内存,可能休眠;
GFP_KERNEL:用于内核空间的内存分配,可能休眠;
GFP_ATOMIC:用于原子性的内存分配,不会休眠;典型原子性场景有中断处理程序,软中断,tasklet等
kmalloc内存分配最终总是调用__get_free_pages 来进行实际的分配,故前缀都是GFP_开头。 kmalloc分最多只能分配32个page大小的内存,每个page=4k,也就是128K大小,其中16个字节用来记录页描述结构。kmalloc分配的是常驻内存,不会被交换到文件中。最小分配单位是32或64字节。
kzalloc()等价于先用 kmalloc() 申请空间, 再用memset()来初始化,所有申请的元素都被初始化为0。
static inline void *kzalloc(size_t size, gfp_t flags)
return kmalloc(size, flags | __GFP_ZERO);
(2) vmalloc
void * vmalloc(unsigned long size)
该函数返回的是一个指向内存块的指针,其内存块大小至少为size,所分配的内存是逻辑上连续的。
kmalloc不同,该函数乜有flags,默认是可以休眠的。
物理地址连续
最大值128K-16
虚拟地址连续
更易分配大内存
虚拟地址连续
1.5 slab层
slab分配器的作用:
对于频繁地分配和释放的数据结构,会缓存它;
频繁分配和回收比如导致内存碎片,为了避免,空闲链表的缓存会连续的存放,已释放的数据结构又会放回空闲链表,不会导致碎片;
让部分缓存专属单个处理器,分配和释放操作可以不加SMP锁;
slab层把不同的对象划分为高速缓存组,每个高速缓存组都存放不同类型的对象,每个对象类型对应一个高速缓存。kmalloc接口监理在slab层只是,使用一组通用高速缓存。
每个高速缓存都是用kmem_cache结构来表示
kmem_cache_crreate:创建高速缓存
kmem_cache_destroy: 撤销高速缓存
kmem_cache_alloc: 从高速缓存中返回一个指向对象的指针
kmem_cache_free:释放一个对象
实例分析: 内核初始化期间,/kernel/fork.c的fork_init()中会创建一个名叫task_struct的高速缓存; 每当进程调用fork()时,会通过dup_task_struct()创建一个新的进程描述符,并调用do_fork(),完成从高速缓存中获取对象。
1.6 栈的静态分配
当设置单页内核栈,那么每个进程的内核栈只有一页大小,这取决于编译时配置选项。 好处:
可以减少每个进程内存的消耗;
随着机器运行时间的增加,寻找两个未分配的、连续的页越来越困难,物理内存碎片化不断加重,那么给每个新进程分配虚拟内存的压力也增大;
每个进程的调用链在自己的内核栈中,当单页栈选项被激活时,中断处理程序可获得自己的栈;
任意函数必须尽量节省栈资源, 方法就是所有函数让局部变量所占空间之和不要超过几百字节。
1.7 高端内存的映射
高端内存中的页不能永久地映射到内核地址空间。
kmap:把给定page结构映射到内核地址空间;
当page位于低端内存,函数返回该页的虚拟地址
当page位于高端内存,建立一个永久映射,再返回地址
kunmap: 永久映射的数量有限,应通过kunmap及时解除映射
kmap_atomic: 临时映射
kunmap_atomic: 解除临时映射
1.8 每个CPU数据
alloc_percpu: 给系统的每个处理器分配一个指定类型对象的实例,以单字节对齐;
free_percpu: 释放每个处理器的对象实例;
get_cpu_var: 返回一个执行当前处理器数据的特殊实例,同时会禁止内核抢占
put_cpu_var: 会重新激活内核抢占
使用每个CPU数据好处:
减少了数据锁定,每个CPU访问自己CPU数据
大大减少缓存失效,失效往往发生在一个处理器操作某个数据,而其他处理器缓存了该数据,那么必须清理或刷新缓存。持续不断的缓存失效称为缓存抖动。
分配函数选择:
连续的物理页,使用低级页分配器 或kmalloc();
高端内存分配,使用alloc_pages(),返回page结构指针; 想获取地址指针,应使用kmap(),把高端内存映射到内核的逻辑地址空间;
仅仅需要虚拟地址连续页,使用vmalloc(),性能有所损失;
频繁创建和撤销大量数据结构,考虑建立slab高速缓存。
二、用户空间
用户空间中进程的内存,往往称为进程地址空间。Linux采用虚拟内存技术
2.1 地址空间
每个进程都有一个32位或64位的地址空间,取决于体系结构。 一个进程的地址空间与另一个进程的地址空间即使有相同的内存地址,也彼此互不相干,对于这种共享地址空间的进程称之为线程。一个进程可寻址4GB的虚拟内存(32位地址空间中),但不是所有虚拟地址都有权访问。对于进程可访问的地址空间称为内存区域。每个内存区域都具有对相关进程的可读、可写、可执行属性等相关权限设置。
内存区域可包含的对象:
代码段(text section): 可执行文件代码
数据段(data section): 可执行文件的已初始化全局变量(静态分配的变量和全局变量)。
bss段:程序中未初始化的全局变量,零页映射(页面的信息全部为0值)。
进程用户空间栈的零页映射(进程的内核栈独立存在并由内核维护)
每一个诸如C库或动态连接程序等共享库的代码段、数据段和bss也会被载入进程的地址空间
任何内存映射文件
任何共享内存段
任何匿名的内存映射(比如由malloc()分配的内存)
这些内存区域不能相互覆盖,每一个进程都有不同的内存片段。
2.2 内存描述符
内存描述符由mm_struct结构体表示,
==& linux/sched.h
struct mm_struct
struct vm_area_struct *
rb_root_t mm_
atomic_t mm_
atomic_t mm_
struct list_
mm_users:代表正在使用该地址的进程数目,当该值为0时mm_count也变为0;
mm_count: 代表mm_struct的主引用计数,当该值为0说明没有任何指向该mm_struct结构体的引用,结构体会被撤销。
mmap和mm_rb:描述的对象都是相同的
mmap以链表形式存放, 利于高效地遍历所有元素
mm_rb以红黑树形式存放,适合搜索指定元素
mmlist:所有的mm_struct结构体都通过mmlist连接在一个双向链表中,该链表的首元素是init_mm内存描述符,它代表init进程的地址空间。
在进程的进程描述符(&linux/sched.h&中定义的task_struct结构体)中,mm域记录该进程使用的内存描述符。故current-&mm代表当前进程的内存描述符。
fork()函数 利用copy_mm函数复制父进程的内存描述符,子进程中的mm_struct结构体通过allcote_mm()从高速缓存中分配得到。通常,每个进程都有唯一的mm_struct结构体,即唯一的进程地址空间。
当子进程与父进程是共享地址空间,可调用clone(),那么不再调用allcote_mm(),而是仅仅是将mm域指向父进程的mm,即 tsk-&mm = current-&mm。
相反地,撤销内存是exit_mm()函数,该函数会进行常规的撤销工作,更新一些统计量。
没有进程地址空间,即内核线程对应的进程描述符中mm=NULL
内核线程直接使用前一个进程的内存描述符,仅仅使用地址空间中和内核内存相关的信息
标签(Tag):
------分隔线----------------------------
------分隔线----------------------------
Linux 引导文件存放在 /boot/grub/目录下的 grub.conf 配置文件里面 1.default=0#defa...
在这里我将讲一下 Linux 中如何用命令如何测试硬盘的读写输入,在搭建服务器和购买服...
DNS(Domain Name System,域名系统),因特网上作为域名和IP地址相互映射的一个分布...
Linux服务器会死机吗?当然会,笔者就接触到过某种型号的服务器安装Red Hat Enterpris...
LVM是通过将物理的磁盘或磁盘分区创建成物理卷(PV),多个物理卷添加创建为一个卷组...
关于Linux的内存管理,本文分别从内核空间和用户空间两个视角来阐述 一、内核空间 1.1...博主最新文章
博主热门文章
您举报文章:
举报原因:
原文地址:
原因补充:
(最多只允许输入30个字)malloc一次性最大能申请多大内存空间? - 知乎65被浏览<strong class="NumberBoard-itemValue" title="2分享邀请回答101 条评论分享收藏感谢收起224 条评论分享收藏感谢收起写回答linux内核之用户空间内存分配
用户空间内存分配
. malloc/free: 按字节分配内存
. valloc/vfree: 分配字节内存对齐
内核空间内存分配
. kmalloc/kree: 分配的内存物理上连续,只能在低端内存分配
. get_zeroed_page/free_page:分配一个页面(4K),并且该页面内容被清零,
& 只能在低端内存分配
. _gete_free_pages/free_pages: 分配指定页数的低端内存
. alloc_pages/_free_pages:分配指定页数的内存,可以从高端内存,也可以从低端
& 内存分配
. valloc/vfree:分配的内存在内核空间中连续,物理上无需连续。vmalloc由于不需要
& 物理上也连续,所以性能很差,一般只有在必须申请大块内存进才使用,例如动态
& 插入模块时
. 对于申请的内存必须释放,否则将导致系统错误。
. void *kmalloc(size_t size, gfp_t flags);
待分配内存大小(按字节计)
&-flags:分配标志,用于控制kmalloc行为
&-返回:分配到内核的虚拟地址,失败返回NULL
. void kfree(const void *objp)
& &-objp : 由kmalloc
返回的内核虚拟地址
. unsigned long get_zeroed_page(ftp_t gfp_mask);
& &- fgp_mask
:分配标志,用于控制kmalloc行为
返回:指向分配到的已经被清零的内存页面第一个字节的指针,失败返回NULL
. void free_page(unsigned long addr);&
& -addr:由get_zeroed_page返回的内核虚拟地址
_get_free_pages函数
. unsigned long _get_free_pages(gfp_t gft_mask, unsigned int
&- gfp_maks:分配标志, 用于控制_get_free_pages行为
请求或释放的页数的2的幂,例如:操作1页该值为0,操作16页该值为4,
如果该值太大会导致分配失败,该值允许的最大值依赖于体系结构
&- 返回: 指向分配到连续内存区第一个字节的指针,失败返回NULL
free_pages函数
. void free_pages(unsigned long addr, unsigned int order);
& -addr: 由_get_free_pages返回的内核虚拟地址
& -order: _get_free_pages分配内在时使用的值
. int get_order(unsigned long size);
& -size: 需要计算order值的大小(按字节计算)
& -返回:_get_free_pages等函数需要的order值
vmalloc函数/vfree函数
. void *vmalloc(unsigned long size);
& -size: 待分配的内在的大小,自动按页对齐
& -返回: 分配到的内核虚拟地址, 失败返回NULL
. void vfree(const void *addr);
& - addr: 由vmalloc返回的内核虚拟地址
内核内存分配标志
. GFP_KERNEL : 表示该次内存分配由内核态进程调用,返回是内核内存的正常分配,
该分配方式最常用。如果空闲空间不够,该次分配将使得进程进入睡眠,等待空闲
&& 页的出现。
. GFP_ATOMIC: 用于分配请求不是来自于进程上下文,而是来自于中断,任务队列处理、
&& 内核定时器等中断上下文的情况,此时不能进入睡眠。
虚拟地址和物理地址转换
.定义在arch/arm/include/asm/memory.h中
. unsigned long virt_to_phys(void *x);
& - 虚拟地址转换为物理地址
. void *phys_to_virt(unsigned long x);
& - 物理地址转换为虚拟地址
3.内核分配内存的方法:
&kmalloc/kfree
&get_zeroed_page/free_page
&_get_free_pages/free_pages
&分配的内存物理上连续,虚拟上也连续,在低端内存分配
&vmalloc/vfree
&分配的内存虚拟上连续,物理上不一定连续,一般用于分配较大的内存
&分配内存的行为的标志:
&GFP_KERNEL:如查使用这个宏,告诉内核请努力为我分配好内在,如果内存不足,进入休眠状态,
&等待空闲页的出现。所以不能用在中断上下文,不能用在中断屏蔽保护的临界区,不能用在自旋锁
&保护的临界区
&GFP_ATOMIC:如果使用这个宏,内存不足时(空闲不够),内核分配内存就会立即返回,所以用在中断
已投稿到:
以上网友发言只代表其个人观点,不代表新浪网的观点或立场。I have to split large packets into smaller ones in PRE_ROUTING hook. I have done the necessary steps for splitting a packet into smaller ones, creating skb, setting ip and udp header etc, etc. But what I am not understanding is how to route the packets? I can append data in packets now (that can be seen in my previous question: ). But now I am stuck with routing splitted packets. Thanks in advance.
I am giving my codes (so far I can write) below.
Let us imagine the module runs on the server machine. The server runs on port 6000. The client then sends a message "ThisIsUsedForTesting". According to the code, the server should get "ThisI": a smaller packet. I am not concerning with the second packet right now. I can easily mangle packet size. But now there can be two or more packets.
After running this module, the server gets the message: "ThisI". But when echoing it back,
the packet does not go out of the box. I write the module for PRE_ROUTING, and the machine should oops right then, but the server process gets the message, and the machine then oops.
I do not understand these scenario. Any help/suggestion is welcome. If I can manage the first splitted packet, I think, the rest can be handled automatically, so the code for them is not given here:
#include &linux/kernel.h&
#include &linux/module.h&
#include &linux/skbuff.h&
#include &linux/netfilter.h&
#include &linux/netdevice.h&
#include &linux/ip.h&
#include &linux/udp.h&
#include &linux/mm.h&
#include &linux/err.h&
#include &linux/crypto.h&
#include &linux/init.h&
#include &linux/crypto.h&
#include &linux/scatterlist.h&
#include &net/ip.h&
#include &net/udp.h&
#include &net/route.h&
#include &linux/netfilter_ipv4.h&
#define IP_HDR_LEN 20
#define UDP_HDR_LEN 8
#define TOT_HDR_LEN 28
static unsigned int pkt_split_begin(unsigned int hooknum,
struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
int (*okfn)(struct sk_buff *));
static void skb_print_info(const struct sk_buff *skb);
static void ip_print_info(struct iphdr *iph);
static void udp_print_info(struct udphdr *udph);
static void data_print_info(unsigned char *data, int len);
static struct nf_hook_ops pkt_split_ops __read_mostly = {
.pf = NFPROTO_IPV4,
.priority = 1,
.hooknum = NF_INET_PRE_ROUTING,
.hook = pkt_split_begin,
static int __init pkt_split_init(void)
printk(KERN_ALERT "\npkt_split module started ...");
return nf_register_hook(&pkt_split_ops);
static void __exit pkt_split_exit(void)
nf_unregister_hook(&pkt_split_ops);
printk(KERN_ALERT "pkt_split module stopped ...");
static unsigned int pkt_split_begin (unsigned int hooknum,
struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
int (*okfn)(struct sk_buff *))
struct iphdr *
struct udphdr *
unsigned char *
unsigned int data_
unsigned char *
unsigned char *temp1, *temp2;
unsigned char *
__u16 dst_port, src_
if (skb) {
iph = (struct iphdr *) skb_header_pointer (skb, 0, 0, NULL);
if (iph && iph-&protocol &&(iph-&protocol == IPPROTO_UDP)) {
udph = (struct udphdr *) skb_header_pointer (skb, IP_HDR_LEN, 0, NULL);
src_port = ntohs (udph-&source);
dst_port = ntohs (udph-&dest);
if (dst_port == 6000) {
printk(KERN_ALERT "\nUDP packet goes in");
data = (unsigned char *) skb_header_pointer (skb, IP_HDR_LEN+UDP_HDR_LEN, 0, NULL);
data_len = skb-&len - TOT_HDR_LEN;
temp = kmalloc(50 * sizeof(char), GFP_ATOMIC);
memcpy(temp, data, data_len);
temp1 = kmalloc(50 * sizeof(char), GFP_ATOMIC);
temp2 = kmalloc(50 * sizeof(char), GFP_ATOMIC);
unsigned int len1, len2;
len2 = data_len - len1;
memcpy(temp1, temp, len1);
temp1[len1] = '\0';
printk(KERN_ALERT "temp1: %s", temp1);
ptr = temp + len1;
memcpy(temp2, ptr, len2);
printk(KERN_ALERT "temp2: %s", temp2);
struct sk_buff *skb1, *skb2;
struct iphdr *iph1, *iph2;
struct udphdr *udph1, *udph2;
unsigned char *data1, *data2;
int data_len1, data_len2;
skb1 = skb_copy(skb, GFP_ATOMIC);
skb2 = skb_copy(skb, GFP_ATOMIC);
iph1 = (struct iphdr *) skb_header_pointer(skb1, 0, 0, NULL);
udph1 = (struct udphdr *) skb_header_pointer(skb1, IP_HDR_LEN, 0, NULL);
data1 = (unsigned char *) skb_header_pointer(skb1, TOT_HDR_LEN, 0, NULL);
data_len1 = skb1-&len - len2 - TOT_HDR_LEN + 1;
memset(data1, 0, data_len);
memcpy(data1, temp1, data_len1);
skb1-&len = data_len1 + TOT_HDR_LEN;
iph1-&tot_len = htons(data_len1 + TOT_HDR_LEN);
udph1-&len = htons(data_len1 + UDP_HDR_LEN);
skb1-&tail = skb1-&tail - data_len2 + 1;
/* Calculation of IP header checksum */
iph1-&check = 0;
ip_send_check (iph1);
/* Calculation of UDP checksum */
udph1-&check = 0;
int offset = skb_transport_offset(skb1);
int len = skb1-&len -
udph1-&check = ~csum_tcpudp_magic((iph1-&saddr), (iph1-&daddr), len, IPPROTO_UDP, 0);
struct sk_buff *
tempskb = skb_copy(skb, GFP_ATOMIC);
*tempskb = *
*skb = *skb1;
(*okfn)(skb);
skb_print_info(skb1);
ip_print_info(iph1);
udp_print_info(udph1);
data_print_info(data1, data_len1);
kfree_skb(skb1);
return NF_DROP;
static void skb_print_info (const struct sk_buff *skb)
printk(KERN_ALERT "\nPrinting SKB info: ");
printk(KERN_ALERT "len: %d", skb-&len);
printk(KERN_ALERT "tail: %d", skb-&tail);
printk(KERN_ALERT "end: %d", skb-&end);
printk(KERN_ALERT "head: %x", skb-&head);
printk(KERN_ALERT "data: %x", skb-&data);
printk(KERN_ALERT "\ntail pointer = %x", skb_tail_pointer(skb));
printk(KERN_ALERT "end pointer = %x", skb_end_pointer(skb));
printk(KERN_ALERT "\nheadroom = %d", skb_headroom(skb));
printk(KERN_ALERT "\ntailroom = %d", skb_tailroom(skb));
void ip_print_info (struct iphdr *iph)
printk(KERN_ALERT "\nPrinting IP header info:");
printk(KERN_ALERT "ihl = %d", iph-&ihl);
printk(KERN_ALERT "version = %d", iph-&version);
printk(KERN_ALERT "tos = %d", iph-&tos);
printk(KERN_ALERT "tot_len = %d", ntohs(iph-&tot_len));
printk(KERN_ALERT "id = %d", ntohs(iph-&id));
printk(KERN_ALERT "frag_off = %d", ntohs(iph-&frag_off));
printk(KERN_ALERT "ttl = %d", iph-&ttl);
printk(KERN_ALERT "protocol = %d", iph-&protocol);
printk(KERN_ALERT "check = %x", ntohs(iph-&check));
printk(KERN_ALERT "saddr = %x", ntohl(iph-&saddr));
printk(KERN_ALERT "daddr = %x", ntohl(iph-&daddr));
void udp_print_info (struct udphdr *udph)
printk(KERN_ALERT "\nPrinting UDP header info: ");
printk(KERN_ALERT "source = %d", ntohs(udph-&source));
printk(KERN_ALERT "dest = %d", ntohs(udph-&dest));
printk(KERN_ALERT "len = %d", ntohs(udph-&len));
printk(KERN_ALERT "check = %x", ntohs(udph-&check));
void data_print_info (unsigned char *data, int len)
printk(KERN_ALERT "\nPrinting data info: ");
printk(KERN_ALERT "Data: %s", data);
printk(KERN_ALERT "data_len: %d", len);
module_init(pkt_split_init);
module_exit(pkt_split_exit);
MODULE_AUTHOR("Rifat Rahman Ovi: &&");
MODULE_DESCRIPTION("Outward Packet Mangling and Decryption in Kernel Space");
MODULE_LICENSE("GPL");
解决方案 This time I found the solution. It is also a simple case like the previous one (http://stackoverflow.com/questions//how-to-append-data-on-a-packet-from-kernel-space). I am presenting the code. But something I need to explain.
must be called like
okfn(skb);
And it will free the skb itself. And my problem in the question was about doubly freeing an skb. Look in the following code and it will be understood what is needed to get it done.
The code is just used for testing purpose. The first 5 bytes (and plus a '\0') will be used
to build a new packet, and rest of the data is used to create the second one. So, here we go. Necessary helper functions for printing skb info, ip header info etc. are provided for convenience (which I used for understanding what is going on).
#include &linux/kernel.h&
#include &linux/module.h&
#include &linux/skbuff.h&
#include &linux/netfilter.h&
#include &linux/netdevice.h&
#include &linux/ip.h&
#include &linux/udp.h&
#include &linux/mm.h&
#include &linux/err.h&
#include &linux/crypto.h&
#include &linux/init.h&
#include &linux/crypto.h&
#include &linux/scatterlist.h&
#include &net/ip.h&
#include &net/udp.h&
#include &net/route.h&
#include &linux/netfilter_ipv4.h&
#define IP_HDR_LEN 20
#define UDP_HDR_LEN 8
#define TOT_HDR_LEN 28
static unsigned int pkt_split_begin(unsigned int hooknum,
struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
int (*okfn)(struct sk_buff *));
static void skb_print_info(const struct sk_buff *skb);
static void ip_print_info(struct iphdr *iph);
static void udp_print_info(struct udphdr *udph);
static void data_print_info(unsigned char *data, int len);
static struct nf_hook_ops pkt_split_ops __read_mostly = {
.pf = NFPROTO_IPV4,
.priority = 1,
.hooknum = NF_INET_PRE_ROUTING,
.hook = pkt_split_begin,
static int __init pkt_split_init(void)
printk(KERN_ALERT "\npkt_split module started ...");
return nf_register_hook(&pkt_split_ops);
static void __exit pkt_split_exit(void)
nf_unregister_hook(&pkt_split_ops);
printk(KERN_ALERT "pkt_split module stopped ...");
static unsigned int pkt_split_begin (unsigned int hooknum,
struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
int (*okfn)(struct sk_buff *))
struct iphdr *
struct udphdr *
unsigned char *
unsigned int data_
unsigned char *
unsigned char *temp1, *temp2;
unsigned char *
__u16 dst_port, src_
if (skb) {
iph = (struct iphdr *) skb_header_pointer (skb, 0, 0, NULL);
if (iph && iph-&protocol &&(iph-&protocol == IPPROTO_UDP)) {
udph = (struct udphdr *) skb_header_pointer (skb, IP_HDR_LEN, 0, NULL);
src_port = ntohs (udph-&source);
dst_port = ntohs (udph-&dest);
if (dst_port == 6000) {
printk(KERN_ALERT "\nUDP packet goes in");
data = (unsigned char *) skb_header_pointer (skb, IP_HDR_LEN+UDP_HDR_LEN, 0, NULL);
data_len = skb-&len - TOT_HDR_LEN;
temp = kmalloc(50 * sizeof(char), GFP_ATOMIC);
memcpy(temp, data, data_len);
temp1 = kmalloc(50 * sizeof(char), GFP_ATOMIC);
temp2 = kmalloc(50 * sizeof(char), GFP_ATOMIC);
unsigned int len1, len2;
len2 = data_len - len1;
memcpy(temp1, temp, len1);
temp1[len1] = '\0';
printk(KERN_ALERT "temp1: %s", temp1);
ptr = temp + len1;
memcpy(temp2, ptr, len2);
printk(KERN_ALERT "temp2: %s", temp2);
struct sk_buff *skb1, *skb2;
struct iphdr *iph1, *iph2;
struct udphdr *udph1, *udph2;
unsigned char *data1, *data2;
int data_len1, data_len2;
skb1 = skb_copy(skb, GFP_ATOMIC);
skb2 = skb_copy(skb, GFP_ATOMIC);
iph1 = (struct iphdr *) skb_header_pointer(skb1, 0, 0, NULL);
udph1 = (struct udphdr *) skb_header_pointer(skb1, IP_HDR_LEN, 0, NULL);
data1 = (unsigned char *) skb_header_pointer(skb1, TOT_HDR_LEN, 0, NULL);
data_len1 = skb1-&len - len2 -TOT_HDR_LEN + 1;
memset(data1, 0, data_len);
memcpy(data1, temp1, data_len1);
skb1-&len = data_len1 + TOT_HDR_LEN;
iph1-&tot_len = htons(data_len1 + TOT_HDR_LEN);
udph1-&len = htons(data_len1 + UDP_HDR_LEN);
skb1-&tail = skb1-&tail - data_len2 + 1;
/* Calculation of IP header checksum */
iph1-&check = 0;
ip_send_check (iph1);
/* Calculation of UDP checksum */
udph1-&check = 0;
int offset = skb_transport_offset(skb1);
int len = skb1-&len -
udph1-&check = ~csum_tcpudp_magic((iph1-&saddr), (iph1-&daddr), len, IPPROTO_UDP, 0);
/* Dealing with the second packet */
iph2 = (struct iphdr *) skb_header_pointer(skb2, 0, 0, NULL);
udph2 = (struct udphdr *) skb_header_pointer(skb2, IP_HDR_LEN, 0, NULL);
data2 = (unsigned char *) skb_header_pointer(skb2, TOT_HDR_LEN, 0, NULL);
data_len2 = skb2-&len - len1 - TOT_HDR_LEN;
memset(data2, 0, data_len);
memcpy(data2, temp2, data_len2);
skb2-&len = data_len2 + TOT_HDR_LEN;
iph2-&tot_len = htons(data_len2 + TOT_HDR_LEN);
udph2-&len = htons(data_len2 + UDP_HDR_LEN);
skb2-&tail = skb2-&tail - data_len1;
/* Calculation of IP header checksum */
iph2-&check = 0;
ip_send_check (iph2);
/* Calculation of UDP checksum */
udph2-&check = 0;
offset = skb_transport_offset(skb1);
len = skb2-&len -
udph2-&check = ~csum_tcpudp_magic((iph2-&saddr), (iph2-&daddr), len, IPPROTO_UDP, 0);
okfn(skb1);
okfn(skb2);
return NF_DROP;
static void skb_print_info (const struct sk_buff *skb)
printk(KERN_ALERT "\nPrinting SKB info: ");
printk(KERN_ALERT "len: %d", skb-&len);
printk(KERN_ALERT "tail: %d", skb-&tail);
printk(KERN_ALERT "end: %d", skb-&end);
printk(KERN_ALERT "head: %x", skb-&head);
printk(KERN_ALERT "data: %x", skb-&data);
printk(KERN_ALERT "\ntail pointer = %x", skb_tail_pointer(skb));
printk(KERN_ALERT "end pointer = %x", skb_end_pointer(skb));
printk(KERN_ALERT "\nheadroom = %d", skb_headroom(skb));
printk(KERN_ALERT "\ntailroom = %d", skb_tailroom(skb));
void ip_print_info (struct iphdr *iph)
printk(KERN_ALERT "\nPrinting IP header info:");
printk(KERN_ALERT "ihl = %d", iph-&ihl);
printk(KERN_ALERT "version = %d", iph-&version);
printk(KERN_ALERT "tos = %d", iph-&tos);
printk(KERN_ALERT "tot_len = %d", ntohs(iph-&tot_len));
printk(KERN_ALERT "id = %d", ntohs(iph-&id));
printk(KERN_ALERT "frag_off = %d", ntohs(iph-&frag_off));
printk(KERN_ALERT "ttl = %d", iph-&ttl);
printk(KERN_ALERT "protocol = %d", iph-&protocol);
printk(KERN_ALERT "check = %x", ntohs(iph-&check));
printk(KERN_ALERT "saddr = %x", ntohl(iph-&saddr));
printk(KERN_ALERT "daddr = %x", ntohl(iph-&daddr));
void udp_print_info (struct udphdr *udph)
printk(KERN_ALERT "\nPrinting UDP header info: ");
printk(KERN_ALERT "source = %d", ntohs(udph-&source));
printk(KERN_ALERT "dest = %d", ntohs(udph-&dest));
printk(KERN_ALERT "len = %d", ntohs(udph-&len));
printk(KERN_ALERT "check = %x", ntohs(udph-&check));
void data_print_info (unsigned char *data, int len)
printk(KERN_ALERT "\nPrinting data info: ");
printk(KERN_ALERT "Data: %s", data);
printk(KERN_ALERT "data_len: %d", len);
module_init(pkt_split_init);
module_exit(pkt_split_exit);
MODULE_AUTHOR("Rifat Rahman Ovi: &&");
MODULE_DESCRIPTION("Inward Packet Splitting in kernel space");
MODULE_LICENSE("GPL");
So...As I am new in kernel space programming, any suggestions are welcome for improvement.
本文地址: &
我要大包拆分为pre_ROUTING挂钩较小。我也做了必要的步骤拆分包成小的,创造SKB,设置IP和UDP报头等等,等等。但我不理解的是如何路由数据包?我可以追加在现在的分组数据(即可以在我的previous问题可以看出:How追加从内核空间分组数据?)。但现在我坚持路由分裂包。提前致谢。 我给我的codeS以下(到目前为止我可以写)。让我们想象一下在服务器计算机上运行的模块。在服务器上的端口6000的客户端然后发送消息“ThisIsUsedForTesting”运行。根据code时,服务器应该得到“ThisI”:小的数据包。我不与第二包现在有关。我可以很容易裂伤包大小。但是,现在可以有两个或多个分组。 运行这个模块后,服务器收到消息:“ThisI”。但它呼应回来的时候,包不出去的盒子。我写了pre_ROUTING模块,机器应哎呀那么好吧,但是服务器进程得到的消息,本机,然后哎呀。我不明白这些场景。任何帮助/建议是值得欢迎的。如果我能管理第一分裂包,我想,其余的可以被自动处理,所以对他们的code未这里给出: 的#include&LT;的Linux / kernel.h&GT;
#包括LT&; Linux的/
module.h中GT;
#包括LT&; Linux的/ skbuff.h中&GT;
#包括LT&; Linux的/ netfilter.h中&GT;
#包括LT&; Linux的/ netdevice.h&GT;
#包括LT&; Linux的/ ip.h&GT;
#包括LT&; Linux的/ udp.h&GT;
#包括LT&; Linux的/ mm.h&GT;
#包括LT&; Linux的/ err.h&GT;
#包括LT&; Linux的/ crypto.h&GT;
#包括LT&; Linux的/ init.h中&GT;
#包括LT&; Linux的/ crypto.h&GT;
#包括LT&; Linux的/ scatterlist.h&GT;
#包括LT&;净/ ip.h&GT;
#包括LT&;净/ udp.h&GT;
#包括LT&;净/ route.h&GT;
#包括LT&; Linux的/ netfilter_ipv4.h&GT;
#定义IP_HDR_LEN 20
#定义UDP_HDR_LEN 8
#定义TOT_HDR_LEN 28
静态unsigned int类型pkt_split_begin(unsigned int类型hooknum,
结构的sk_buff * SKB,
常量结构的net_device *中,
常量结构的net_device *出来,
INT(* okfn)(结构的sk_buff *));
静态无效skb_print_info(常量结构的sk_buff * SKB);
静态无效ip_print_info(结构iphdr * IPH);
静态无效udp_print_info(结构udphdr * UDPH);
静态无效data_print_info(unsigned char型*数据,INT LEN);
静态结构nf_hook_ops pkt_split_ops __read_mostly = {
.PF = NFPROTO_IPV4,
.priority = 1,
.hooknum = NF_INET_ pre_ROUTING,
.hook = pkt_split_begin,
};静态INT __init pkt_split_init(无效){
printk的(KERN_ALERT“\\ npkt_split模块开始......”);
返回nf_register_hook(安培; pkt_split_ops);}静态无效__exit pkt_split_exit(无效){
nf_unregister_hook(安培; pkt_split_ops);
printk的(KERN_ALERT“pkt_split模块停止......”);}静态unsigned int类型pkt_split_begin(unsigned int类型hooknum,
结构的sk_buff * SKB,
常量结构的net_device *中,
常量结构的net_device *出来,
INT(* okfn)(结构的sk_buff *)){
结构iphdr * IPH;
结构udphdr * UDPH;
无符号字符*的数据;
无符号整型DATA_LEN;
无符号整型我;
无符号字符*温度;
无符号字符* temp1中,* TEMP2;
无符号字符* PTR;
__u16 dst_port,src_
如果(SKB){
IPH =(结构iphdr *)skb_header_pointer(SKB,0,0,NULL);
如果(IPH&放大器;&放大器; iph-&GT;协议&放大器;及(iph-&GT;协议== IPPROTO_UDP)){
UDPH =(结构udphdr *)skb_header_pointer(SKB,IP_HDR_LEN,0,NULL);
src_port = ntohs和(udph-&GT;源);
dst_port = ntohs和(udph-&GT; DEST);
如果(dst_port == 6000){
printk的(KERN_ALERT“\\ nUDP包进去”);
数据=(无符号字符*)skb_header_pointer(SKB,IP_HDR_LEN + UDP_HDR_LEN,0,NULL);
DATA_LEN =&是skb- GT; LEN
TOT_HDR_LEN;
TEMP = kmalloc的(50 * sizeof的(炭),GFP_ATOMIC);
的memcpy(温度,数据,DATA_LEN);
temp1中的kmalloc =(50 * sizeof的(炭),GFP_ATOMIC);
TEMP2 = kmalloc的(50 * sizeof的(炭),GFP_ATOMIC);
unsigned int类型LEN1,LEN2;
LEN2 = DATA_LEN
的memcpy(temp1中,温度,LEN1);
temp1中[LEN1] ='\\ 0';
printk的(KERN_ALERT的“TEMP1:%S”,temp1中);
PTR =温度+ LEN1;
的memcpy(TEMP2,PTR,LEN2);
printk的(KERN_ALERT“TEMP2:%S”,TEMP2);
结构的sk_buff * skb1,* SKB2;
结构iphdr * IPH1,* iph2;
结构udphdr * udph1,* udph2;
无符号字符*数据1,*数据2;
INT data_len1,data_len2;
skb1 = skb_copy(SKB,GFP_ATOMIC);
SKB2 = skb_copy(SKB,GFP_ATOMIC);
IPH1 =(结构iphdr *)skb_header_pointer(skb1,0,0,NULL);
udph1 =(结构udphdr *)skb_header_pointer(skb1,IP_HDR_LEN,0,NULL);
数据1 =(无符号字符*)skb_header_pointer(skb1,TOT_HDR_LEN,0,NULL);
data_len1 = skb1-&GT; LEN
TOT_HDR_LEN + 1;
memset的(DATA1,0,DATA_LEN);
的memcpy(DATA1,temp1中,data_len1);
skb1-&GT; LEN = data_len1 + TOT_HDR_LEN;
iph1-&GT; tot_len = htons(data_len1 + TOT_HDR_LEN);
udph1-&GT; LEN = htons(data_len1 + UDP_HDR_LEN);
skb1-&GT;尾= skb1-&GT;尾 -
data_len2 + 1;
/ * IP头校验和计算* /
iph1-&GT;检查= 0;
ip_send_check(IPH1);
/ * UDP校验和的计算* /
udph1-&GT;检查= 0;
诠释偏移量= skb_transport_offset(skb1);
INT LEN = skb1-&GT; LEN
udph1-&GT;检查=?csum_tcpudp_magic((iph1-&GT; SADDR),(iph1-&GT; DADDR),LEN,IPPROTO_UDP,0);
结构的sk_buff *
tempskb = skb_copy(SKB,GFP_ATOMIC);
* tempskb = * SKB;
* SKB = * skb1;
* skb1 = *
(* okfn)(SKB);
skb_print_info(skb1);
ip_print_info(IPH1);
udp_print_info(udph1);
data_print_info(DATA1,data_len1);
的kfree_skb(skb1);
返回NF_DROP;}静态无效skb_print_info(常量结构的sk_buff * SKB){
printk的(KERN_ALERT“\\ nPrinting SKB信息:”);
printk的(KERN_ALERT“LEN数:%d”,&是skb- GT; LEN);
printk的(KERN_ALERT“尾巴数:%d”,&是skb- GT;尾);
printk的(KERN_ALERT“结束数:%d”,&是skb- GT端);
printk的(KERN_ALERT“头:%X”,与是skb- GT;头);
printk的(KERN_ALERT“数据:%X”,与是skb- GT;数据);
printk的(KERN_ALERT“\\ ntail指针=%×”,skb_tail_pointer(SKB));
printk的(KERN_ALERT“结束指针=%X”,skb_end_pointer(SKB));
printk的(KERN_ALERT“\\ nheadroom =%d个”,skb_headroom(SKB));
printk的(KERN_ALERT“\\ ntailroom =%d个”,skb_tailroom(SKB));}无效ip_print_info(结构iphdr * IPH){
printk的(KERN_ALERT“\\ nPrinting IP报头信息:”);
printk的(KERN_ALERT“国际人道法=%d个”,iph-&GT;国际人道法);
printk的(KERN_ALERT“版本=%d个”,iph-&GT;的版本);
printk的(KERN_ALERT“TOS =%d个”,iph-&GT; TOS);
printk的(KERN_ALERT“tot_len =%d个”,还有ntohs(iph-&GT; tot_len));
printk的(KERN_ALERT“ID =%D”,还有ntohs(iph-&GT; ID));
printk的(KERN_ALERT“frag_off =%d个”,还有ntohs(iph-&GT; frag_off));
printk的(KERN_ALERT“TTL =%d个”,iph-&GT; TTL);
printk的(KERN_ALERT“协议=%d个”,iph-&GT;协议);
printk的(KERN_ALERT“检查=%X”,还有ntohs(iph-&GT;检查));
printk的(KERN_ALERT“SADDR =%X”,ntohl(iph-&GT; SADDR));
printk的(KERN_ALERT“DADDR =%X”,ntohl(iph-&GT; DADDR));}无效udp_print_info(结构udphdr * UDPH){
printk的(KERN_ALERT“\\ nPrinting UDP报头信息:”);
printk的(KERN_ALERT“来源=%d个”,还有ntohs(udph-&GT;源));
printk的(KERN_ALERT“目标=%d个”,还有ntohs(udph-&GT; DEST));
printk的(KERN_ALERT为“len =%d个”,还有ntohs(udph-&GT; LEN));
printk的(KERN_ALERT“检查=%X”,还有ntohs(udph-&GT;检查));}无效data_print_info(unsigned char型*数据,INT LEN){
printk的(KERN_ALERT“\\ nPrinting数据信息:”);
printk的(KERN_ALERT“数据:%S”,数据);
printk的(KERN_ALERT“DATA_LEN数:%d”,LEN);}宏module_init(pkt_split_init);宏module_exit(pkt_split_exit);MODULE_AUTHOR(“瑞法特拉赫曼Ovi全:其中,&”);MODULE_DESCRIPTION(“对外包分割和解密在内核空间”);MODULE_LICENSE(“GPL”); 解决方案 这一次,我找到了解决办法。它也是一个简单的例子,如previous酮(http://stackoverflow.com/questions//how-to-append-data-on-a-packet-from-kernel-space)。我是presenting的code。但有些事情我需要解释一下。
okfn 必须调用像
okfn(SKB); 和它会释放SKB本身。而我在这个问题问题有关双重释放的SKB。看看在下面的code和将理解什么是需要完成它。在code只是用于测试目的。前5个字节(以及加上一个'\\ 0')将被使用建立一个新的分组,并且该数据的其余部分被用来创建第二个。所以,在这里我们去。提供了方便(这是我用来理解到底是怎么回事)打印SKB信息,IP报头信息等必要的辅助函数。 的#include&LT;的Linux / kernel.h&GT;#包括LT&; Linux的/
module.h中GT;#包括LT&; Linux的/ skbuff.h中&GT;#包括LT&; Linux的/ netfilter.h中&GT;#包括LT&; Linux的/ netdevice.h&GT;#包括LT&; Linux的/ ip.h&GT;#包括LT&; Linux的/ udp.h&GT;#包括LT&; Linux的/ mm.h&GT;#包括LT&; Linux的/ err.h&GT;#包括LT&; Linux的/ crypto.h&GT;#包括LT&; Linux的/ init.h中&GT;#包括LT&; Linux的/ crypto.h&GT;#包括LT&; Linux的/ scatterlist.h&GT;#包括LT&;净/ ip.h&GT;#包括LT&;净/ udp.h&GT;#包括LT&;净/ route.h&GT;#包括LT&; Linux的/ netfilter_ipv4.h&GT;#定义IP_HDR_LEN 20#定义UDP_HDR_LEN 8#定义TOT_HDR_LEN 28静态unsigned int类型pkt_split_begin(unsigned int类型hooknum,
结构的sk_buff * SKB,
常量结构的net_device *中,
常量结构的net_device *出来,
INT(* okfn)(结构的sk_buff *));静态无效skb_print_info(常量结构的sk_buff * SKB);静态无效ip_print_info(结构iphdr * IPH);静态无效udp_print_info(结构udphdr * UDPH);静态无效data_print_info(unsigned char型*数据,INT LEN);静态结构nf_hook_ops pkt_split_ops __read_mostly = {
.PF = NFPROTO_IPV4,
.priority = 1,
.hooknum = NF_INET_ pre_ROUTING,
.hook = pkt_split_begin,};静态INT __init pkt_split_init(无效){
printk的(KERN_ALERT“\\ npkt_split模块开始......”);
返回nf_register_hook(安培; pkt_split_ops);}静态无效__exit pkt_split_exit(无效){
nf_unregister_hook(安培; pkt_split_ops);
printk的(KERN_ALERT“pkt_split模块停止......”);}静态unsigned int类型pkt_split_begin(unsigned int类型hooknum,
结构的sk_buff * SKB,
常量结构的net_device *中,
常量结构的net_device *出来,
INT(* okfn)(结构的sk_buff *)){
结构iphdr * IPH;
结构udphdr * UDPH;
无符号字符*的数据;
无符号整型DATA_LEN;
无符号整型我;
无符号字符*温度;
无符号字符* temp1中,* TEMP2;
无符号字符* PTR;
__u16 dst_port,src_
如果(SKB){
IPH =(结构iphdr *)skb_header_pointer(SKB,0,0,NULL);
如果(IPH&放大器;&放大器; iph-&GT;协议&放大器;及(iph-&GT;协议== IPPROTO_UDP)){
UDPH =(结构udphdr *)skb_header_pointer(SKB,IP_HDR_LEN,0,NULL);
src_port = ntohs和(udph-&GT;源);
dst_port = ntohs和(udph-&GT; DEST);
如果(dst_port == 6000){
printk的(KERN_ALERT“\\ nUDP包进去”);
数据=(无符号字符*)skb_header_pointer(SKB,IP_HDR_LEN + UDP_HDR_LEN,0,NULL);
DATA_LEN =&是skb- GT; LEN
TOT_HDR_LEN;
TEMP = kmalloc的(50 * sizeof的(炭),GFP_ATOMIC);
的memcpy(温度,数据,DATA_LEN);
temp1中的kmalloc =(50 * sizeof的(炭),GFP_ATOMIC);
TEMP2 = kmalloc的(50 * sizeof的(炭),GFP_ATOMIC);
unsigned int类型LEN1,LEN2;
LEN2 = DATA_LEN
的memcpy(temp1中,温度,LEN1);
temp1中[LEN1] ='\\ 0';
printk的(KERN_ALERT的“TEMP1:%S”,temp1中);
PTR =温度+ LEN1;
的memcpy(TEMP2,PTR,LEN2);
printk的(KERN_ALERT“TEMP2:%S”,TEMP2);
结构的sk_buff * skb1,* SKB2;
结构iphdr * IPH1,* iph2;
结构udphdr * udph1,* udph2;
无符号字符*数据1,*数据2;
INT data_len1,data_len2;
skb1 = skb_copy(SKB,GFP_ATOMIC);
SKB2 = skb_copy(SKB,GFP_ATOMIC);
IPH1 =(结构iphdr *)skb_header_pointer(skb1,0,0,NULL);
udph1 =(结构udphdr *)skb_header_pointer(skb1,IP_HDR_LEN,0,NULL);
数据1 =(无符号字符*)skb_header_pointer(skb1,TOT_HDR_LEN,0,NULL);
data_len1 = skb1-&GT; LEN
LEN2 -TOT_HDR_LEN + 1;
memset的(DATA1,0,DATA_LEN);
的memcpy(DATA1,temp1中,data_len1);
skb1-&GT; LEN = data_len1 + TOT_HDR_LEN;
iph1-&GT; tot_len = htons(data_len1 + TOT_HDR_LEN);
udph1-&GT; LEN = htons(data_len1 + UDP_HDR_LEN);
skb1-&GT;尾= skb1-&GT;尾 -
data_len2 + 1;
/ * IP头校验和计算* /
iph1-&GT;检查= 0;
ip_send_check(IPH1);
/ * UDP校验和的计算* /
udph1-&GT;检查= 0;
诠释偏移量= skb_transport_offset(skb1);
INT LEN = skb1-&GT; LEN
udph1-&GT;检查=?csum_tcpudp_magic((iph1-&GT; SADDR),(iph1-&GT; DADDR),LEN,IPPROTO_UDP,0);
/ *与第二包处理* /
iph2 =(结构iphdr *)skb_header_pointer(SKB2,0,0,NULL);
udph2 =(结构udphdr *)skb_header_pointer(SKB2,IP_HDR_LEN,0,NULL);
数据2 =(无符号字符*)skb_header_pointer(SKB2,TOT_HDR_LEN,0,NULL);
data_len2 = skb2-&GT; LEN
TOT_HDR_LEN;
memset的(数据2,0,DATA_LEN);
的memcpy(DATA2,TEMP2,data_len2);
skb2-&GT; LEN = data_len2 + TOT_HDR_LEN;
iph2-&GT; tot_len = htons(data_len2 + TOT_HDR_LEN);
udph2-&GT; LEN = htons(data_len2 + UDP_HDR_LEN);
skb2-&GT;尾= skb2-&GT;尾 -
data_len1;
/ * IP头校验和计算* /
iph2-&GT;检查= 0;
ip_send_check(iph2);
/ * UDP校验和的计算* /
udph2-&GT;检查= 0;
偏移量= skb_transport_offset(skb1);
LEN = skb2-&GT; LEN
udph2-&GT;检查=?csum_tcpudp_magic((iph2-&GT; SADDR),(iph2-&GT; DADDR),LEN,IPPROTO_UDP,0);
okfn(skb1);
okfn(SKB2);
返回NF_DROP;}静态无效skb_print_info(常量结构的sk_buff * SKB){
printk的(KERN_ALERT“\\ nPrinting SKB信息:”);
printk的(KERN_ALERT“LEN数:%d”,&是skb- GT; LEN);
printk的(KERN_ALERT“尾巴数:%d”,&是skb- GT;尾);
printk的(KERN_ALERT“结束数:%d”,&是skb- GT端);
printk的(KERN_ALERT“头:%X”,与是skb- GT;头);
printk的(KERN_ALERT“数据:%X”,与是skb- GT;数据);
printk的(KERN_ALERT“\\ ntail指针=%×”,skb_tail_pointer(SKB));
printk的(KERN_ALERT“结束指针=%X”,skb_end_pointer(SKB));
printk的(KERN_ALERT“\\ nheadroom =%d个”,skb_headroom(SKB));
printk的(KERN_ALERT“\\ ntailroom =%d个”,skb_tailroom(SKB));}无效ip_print_info(结构iphdr * IPH){
printk的(KERN_ALERT“\\ nPrinting IP报头信息:”);
printk的(KERN_ALERT“国际人道法=%d个”,iph-&GT;国际人道法);
printk的(KERN_ALERT“版本=%d个”,iph-&GT;的版本);
printk的(KERN_ALERT“TOS =%d个”,iph-&GT; TOS);
printk的(KERN_ALERT“tot_len =%d个”,还有ntohs(iph-&GT; tot_len));
printk的(KERN_ALERT“ID =%D”,还有ntohs(iph-&GT; ID));
printk的(KERN_ALERT“frag_off =%d个”,还有ntohs(iph-&GT; frag_off));
printk的(KERN_ALERT“TTL =%d个”,iph-&GT; TTL);
printk的(KERN_ALERT“协议=%d个”,iph-&GT;协议);
printk的(KERN_ALERT“检查=%X”,还有ntohs(iph-&GT;检查));
printk的(KERN_ALERT“SADDR =%X”,ntohl(iph-&GT; SADDR));
printk的(KERN_ALERT“DADDR =%X”,ntohl(iph-&GT; DADDR));}无效udp_print_info(结构udphdr * UDPH){
printk的(KERN_ALERT“\\ nPrinting UDP报头信息:”);
printk的(KERN_ALERT“来源=%d个”,还有ntohs(udph-&GT;源));
printk的(KERN_ALERT“目标=%d个”,还有ntohs(udph-&GT; DEST));
printk的(KERN_ALERT为“len =%d个”,还有ntohs(udph-&GT; LEN));
printk的(KERN_ALERT“检查=%X”,还有ntohs(udph-&GT;检查));}无效data_print_info(unsigned char型*数据,INT LEN){
printk的(KERN_ALERT“\\ nPrinting数据信息:”);
printk的(KERN_ALERT“数据:%S”,数据);
printk的(KERN_ALERT“DATA_LEN数:%d”,LEN);}宏module_init(pkt_split_init);宏module_exit(pkt_split_exit);MODULE_AUTHOR(“瑞法特拉赫曼Ovi全:其中,&”);MODULE_DESCRIPTION(“向内包拆分在内核空间”);MODULE_LICENSE(“GPL”); 所以...我在内核空间编程是新的,有什么建议,欢迎改进。
本文地址: &
扫一扫关注官方微信}

我要回帖

更多关于 raid空间大小计算公司 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信