本人正在把2.4.18的网关,防火墙,等公司的代码从2.4.18移植到2.6.18linux内核上去.本日志会不断更新,希望能让同在进行2.4到2.6内核移植
的朋友们一些帮助.
IPMAC部分改动
1. 2.4内核:
Save_flags();保存标志
cli();关闭中断
Restore_flags();还原标志打开中断.
在2.6内核中由:
local_irq_save(flags);
local_irq_restore(flags);
取代。功能完全一样.
要使用save_flags功能需要删除CONFIG_SMP宏
在/include/linux/autoconf.h 2125行定义.
2. 修改后的nf_hook_ops结构体
static struct nf_hook_ops ipmac_rcv_ops= {
{NULL, NULL},
my_ipmac_rcv,
NULL, /2.4.18没有这个元素,2.6.21此参数原型为:struct module *owner;*、
PF_INET,
NF_IP_PRE_ROUTING,
SE_PRI_PRERT_IPMAC_BIND
};
3.
2.4 内核下,缺省情况时模块中的非静态全局变量及函数在模块加载后会输出到内核
空间。2.6 内核下,缺省情况时模块中的非静态全局变量及函数在模块加载后不会输出到内
核空间,需要显式调用宏EXPORT_SYMBOL才能输出。所以在2.6 内核的模块下,EXPORT_NO_SYMBOLS宏的调用没有意义,是空操作。在同时支持2.4与2.6内核的设备
驱动中,可以通过以下代码段来输出模块的内核符号
EXPORT_NO_SYMBOLS在2.6.21内核中没有这个东西了.因为没有必要存在了,已近删除.
.
4.
(int) *buf_p = IPMAC_ADD
这种类型的代码编译报错了.是无法赋值的,提示左值无法赋值.
全部改为:*((int*)buf_p) = IPMAC_ADD此种类型
还有函数原型不带参数声明会带警告,我都加了void
如下:int get_index()改为int get_index(void);
一些声明了没有初始化就使用的变量也给了警告我也都初始化了.
比如flags;
PF(包过滤)改动部分
1.
2.4内核中,模块自身通过 MOD_INC_USE_COUNT, MOD_DEC_USE_COUNT宏来管理自己被使用的计数。
2.6内核提供了更健壮、灵活的模块计数管理接口 try_module_get(&module), module_put(&module)取代2.4中的模块使用计数管理宏;模块的使用计数不必由自身管理,而且在管理模块使用计数时考虑到 SMP与PREEMPT机制的影响。
int try_module_get(struct module *module); 用于增加模块使用计数;若返回为0,表示调用失败,希望使用的模块没有被加载或正在被卸载中。
void module_put(struct module *module); 减少模块使用计数。
try_module_get与module_put 的引入与使用与2.6内核下的设备模型密切相关。模块是用来管理硬件设备的,2.6内核为不同类型的设备定义了struct module *owner 域,用来指向管理此设备的模块。如字符设备的定义:
struct cdev
{
struct kobject kobj;
struct module *owner;
struct file_operations *ops;
struct list_head list;
dev_t dev;
unsigned int count;
};
从设备使用的角度出发,当需要打开、开始使用某个设备时,使用 try_module_get(dev->owner)去增加管理此设备的 owner模块的使用计数;当关闭、不再使用此设备时,使用module_put(dev->owner)减少对管理此设备的owner模块的使用 计数。这样,当设备在使用时,管理此设备的模块就不能被卸载;只有设备不再使用时模块才能被卸载。
2.6内核下,对于为具体设备写驱动的开发人员而言,基本无需使用 try_module_get与module_put,因为此时开发人员所写的驱动通常为支持某具体设备的owner模块,对此设备owner模块的计数管理由内核里更底层的代码如总线驱动或是此类设备共用的核心模块来实现,从而简化了设备驱动开发。
4.
2.4 .18内核 :skb_linearize(skb, GFP_ATOMIC)
2.6.21 内核 : skb_linearize(skb)
skb_is_nonlinear函数用于测试一个缓冲区是否是分片的,而skb_linearize可以把分片组合成一个单一的缓冲区。组合分片涉及到数据拷贝,它将严重影响系统性能。
5.
EXPORT_SYMBOL_NOVERS 2.6内核中已近没有这个宏.我只知道EXPORT_SYMBOL是内核模块向其它的模块倒出可用的函数,
2.6内核中只有EXPORT_SYMBOL这个宏,而且用的很多.
我把代码里的
EXPORT_SYMBOL_NOVERS全部改为EXPORT_SYMBOL了.
6.
2.6内核中没有.for_each_task
替换为如下宏:
#define for_each_process(p) \
for (p = &init_task ; (p = next_task(p)) != &init_task ; )
在2.6.21内核中定义的.
2.
2.6内核 :Struct sk_buff *ip_defrag(struct sk_buff *skb,u32 user);
这个函数的第二个参数是2.6内核增加的,目的好像是是说明sk_buff数据包的来源.
第二个参数的全部可取值如下,此结构在内核中被定义.
enum ip_defrag_users
{
IP_DEFRAG_LOCAL_DELIVER,(sk_buff代表的数据包是本机ip地址发送出去的,)
IP_DEFRAG_CALL_RA_CHAIN,(在ip_call_ra_chain函数中被调用,sk_buff来源参数被设置为这个,说明这个数据包是遍历那个什么链表找到的?)
IP_DEFRAG_CONNTRACK_IN,(当hook节点的值为NF_IP_PRE_ROUTING时,参数为这个值,不是为下面的值)
IP_DEFRAG_CONNTRACK_OUT,
IP_DEFRAG_VS_IN,(hook节点值为NF_IP_LOCAL_IN时,参数为这个,不是参数为NF_IP_LOCAL_FWD)
IP_DEFRAG_VS_OUT,(在ip_vs_out和ip_vs_out_icmp里被调用,sk_buff来源参数被设置为IP_DEFRAG_VS_OUT)
IP_DEFRAG_VS_FWD
};
我查找了下.内核中对这5个参数的用法.对参数意思的总结如上.
3.
2.4内核中,通过内核监听的套接口返回套接口结构的方法:
Struct sock sk2;
sk2 = tcp_listening_hash[i]已近行不通.
2.6内核中 要返回监听端口需要; tcp_hashinfo.listening_hash[i].first
但是返回的不是struct sock 而是 struct hlist_node结构体.这个结构体里除了下一个这个结构的指针什么也没.内核中维护监听的套接口,是一个哈希表,每个哈希元素又是一个链表.
所以2.4内核中想要通过返回的sock结构直接取出源目的的ip以及端口在2.6内核中已近无法做到.而且2.6内核中的sock结构也没有地址端口这些信息.
想要通过监听列表获得监听的套接口的地址端口信息必须通过,inet_sock结构.这个结构的第一个元素为strock sock,它封装了sock结构,如下
struct inet_sock {
/* sk and pinet6 has to be the first two members of inet_sock */
struct sock sk;
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
struct ipv6_pinfo *pinet6;
#endif
/* Socket demultiplex comparisons on incoming packets. */
__be32 daddr;
__be32 rcv_saddr;
__be16 dport;
__u16 num;
__be32 saddr;
__s16 uc_ttl;
__u16 cmsg_flags;
struct ip_options *opt;
__be16 sport;
__u16 id;
__u8 tos;
__u8 mc_ttl;
__u8 pmtudisc;
__u8 recverr:1,
is_icsk:1,
freebind:1,
hdrincl:1,
mc_loop:1;
int mc_index;
__be32 mc_addr;
struct ip_mc_socklist *mc_list;
struct {
unsigned int flags;
unsigned int fragsize;
struct ip_options *opt;
struct rtable *rt;
int length; /* Total length of all frames */
__be32 addr;
struct flowi fl;
} cork;
};
但是想用这个结构体加进头文件也用不了.必须要这样:
#undef _INET_SOCK_H
#include <net/inet_sock.h>
才可以使用,具体见这个头文件里的宏开关.
想要通过返回的hlist_node指针找到这个套接口的inet_sock结构只能这样:
Struct hlist_node list;
Struct inet_sock sk2;
...
.....
list = tcp_hashinfo.listening_hash[i].first;
sk2 = container_of(list,struct inet_sock,sk.sk_node);
(编译是过了...没测试过.不保证%100对...)