int (*set_mac_address)(struct device *dev, void *addr); #ifndef NET_21
void (*header_cache_bind)(struct hh_cache **hhp, struct device *dev, unsigned short htype, __u32 daddr); #endif /* !NET_21 */
void (*header_cache_update)(struct hh_cache *hh, struct device *dev, unsigned char * haddr);
struct enet_statistics *(*get_stats)(struct device *dev); struct enet_statistics mystats; int mtu; };
3.2.2.3函数说明
3.2.2.3.1 int ipsec_tunnel_init_devices(void) 目的: 登记ipsec虚接口。 参数:
无
/* What is the desired MTU? */
返回值: 0 ―― 登记成功,非0值――登记未成功 算法描述:
调用系统调用register_netdev(&dev_ipsec0~3),向系统登记4个ipsec虚接口。 3.2.2.3.2 int ipsec_tunnel_init(struct device *dev) 目的: 参数: 返回值:
初始化ipsec虚接口,完成device中变量的初始化和系统资源的申请。
0 ―― 清除成功,非0值――清除未成功
算法描述:
1.填充device结构中的几个函数,如:
a) dev->open = ipsec_tunnel_open; b) dev->stop = ipsec_tunnel_stop; c) dev->hard_start_xmit d) dev->get_stats
= ipsec_tunnel_start_xmit;
= ipsec_tunnel_get_stats;
2.给dev配空间,dev->priv = kmalloc(sizeof(struct ipsecpriv),GFP_KERNEL); 3.初始化dev结构:skb_queue_head_init(&dev->buffs[i]); 4.填充dev结构的其它值,如:dev->set_mac_address = NULL等等。
3.2.2.3.3 int ipsec_tunnel_attach (struct device* tndev, struct ipsecpriv* prv,struct device *dev)
目的: 将某个虚接口绑定到指定的物理接口上。 参数:
返回值: 0 ―― 绑定成功,非0值――绑定未成功 算法描述:
3.2.2.3.4 int ipsec_open(struct device *dev) 目的: 参数:
要open的device
返回值: 0 ―― open成功,非0值――open未成功 算法描述:
此方法在网络设备驱动程序里是网络设备被激活的时候被调用(即设备状态由down->up)。
驱动程序作为一个模块被装入:如果虚接口尚未绑定到物理接口,返回错误信息;否则调用MOD_INC_USE_COUNT宏,以防止模块卸载是设备处于打开状态。
3.2.2.3.5 int ipsec_tunnel_start_xmit(struct sk_buff *skb,struct device *dev) 目的: 假定此函数由dev_queue_xmit()函数调用,主要负责发送从tcp/udp协议层传来的数据包 参数: 返回值:
由dev_queue_xmit()函数填充好的skb,及要发往的网络接口 0 ―― open成功,非0值――open未成功
算法描述:
1. skb, dev 有效吗? 有效继续,无效返回;prv = dev->priv 获取ipsec接口私有数据;若prv为空,返回;获取系列参数:物理接口参数physdev, physmtu, stats; 2. 如果需要,拷贝skb:Ifdef NET_21, then skb_cloned(skb); 3. 获取Ip头iph,判断该包是否是IPV4,若不是则丢弃; 4. 计算硬件头长度(hard_header_len); 5. 将ip包的ttl减小,并计算校验和。
6. 填充查找键键值,根据键值查找eroute表,获取eroute,若找到,取出SA,即outgonging_said;
7. 判断此IP包是否是IKE协商包(UDP port 500),若是,则跳出;
8. 进入封装处理大循环(几乎一切处理都由outgoing_said决定,一个said对应一个或多个tdb(通道描述块),根据每个tdb对其进行处理): (1) check for DROP or missing eroute
(2) check for REJECT eroute (3) check for PASS eroute (4) check for HOLD eroute
(5) check for TRAP eroute, signal PF_KEY, swap to HOLD eroute (6) acquire lock for walking tdb chain (7) calculate headroom required for chain 1) check if SA is in larval, drop 2) check if SA is dead, drop
3) check if replay overflowed, expire SA
4) check if lifetime counters have overflowed, expire SA 5) switch on protocol type, to calculate headroom size.
I. if ESP switch on protocol type to calculate tailroom size. (8) alculate mtudiff, send ICMP fragment needed. Mark ``note2'' (9) ack MSS if desired
(10) copy upper (layer 2) header to safety if it was present (11) check if data fits in existing skb, else expand. (12) apply grouped transforms 1) apply disaster of #ifdefs.
2) switch by protocol type, calculate headroom for this stage I. if ESP, then switch by cipher get headroom II. if ESP, then switch by hash to get tailroom
3) double check (not in NDEBUG) if there is enough headroom 4) push the data ahead
5) double check (not in NDEBUG) if there is enough tailroom 6) extend the data behind
7) see if packet has become too long (bigger than 64K) 8) finally move the plaintext as appropriate 9) switch on protocol type 10) case: ESP
I. switch on cipher type, prepare IV II. prepare self-describing padding III. switch on cipher type, do encryption IV. switch on cipher type, update IV V. switch on hash type, do authentication
11) case: AH
I. prep replay info, headroom
II. switch on hash type, do authentication 12) case: IPIP, apply encap 13) case: IPCOMP
I. call skb_compress II. do some debugging 14) recalculate header checksum
⒀lookup eroute by new outer header, if we found something and the src/dst have changed
9. end ICMP if packet has become too big
10. re-apply link layer header if there was one. 11. attempt to re-route the packet
12. drop packet if new route leads to us again. 13. do connection tracking
14. do netfilter localout output call
15. call ip_send or IP_SEND depending on kernel version
⑴. 取得一些初始值, 如dst, src, iphlen, pyldsz,
⑵. 接下来是一系列合法性和安全性检查,对不合理部分有两种处理方法: 1) 不进行安全处理,直接从物理接口上发送并返回; 2) 丢弃数据包,返回。
⑶. 有eroute吗? 没有,则从physdev发送数据包并返回,有则继续; ⑷. 若指定隧道模式,却找不到spi,不做处理,按1)发送,返回; ⑸. 根据said取得tdbp链,和sa_len,若tdbp链为空,报错返回; ⑹. 进入tdb处理循环,求出ipsec处理所需的headroom和tailroom; 对tdbp链中每一个tdb进行如下处理:
① 大量的合法性判断,包括tdb状态是否对,SA是否过时,PFKEYv2处理等; ② 根据tdbp->tdb_said.proto计算headroom和tailroom。方法是,根据tdb_said.proto不同而算法不同:
IPPROTO_AH: headroom += sizeof(struct ah); IPPROTO_ESP:
Ⅰ.tdbp->tdb_encalg(加密算法)
ESP_DES: headroom += sizeof(struct esp);