Linux内核中的IPSEC实现(2)
本文档的Copyleft归yfydz所有,使用GPL发布,可以自由拷贝,转载,转载时请保持文档的完整性,严禁用于任何商业用途。
msn: yfydz_no1@hotmail.com
来源:http://yfydz.cublog.cn
4. 状态(xfrm_state)处理
本节所介绍的函数都在net/xfrm/xfrm_state.c中定义。
4.1 状态分配
状态分配函数为xfrm_state_alloc(), 该函数被pfkey_msg2xfrm_state()函数调用, pfkey_msg2xfrm_state()函数是将标准的pfkey_msg(SA结构)转换为xfrm状态, 同时该函数也被其他状态处理函数调用.
struct xfrm_state *xfrm_state_alloc(void)
{
struct xfrm_state *x;
// 分配空间
x = kzalloc(sizeof(struct xfrm_state), GFP_ATOMIC);
if (x) {
// 使用数初始化为1
atomic_set(&x->refcnt, 1);
// 被0个ipsec通道使用
atomic_set(&x->tunnel_users, 0);
// 初始化链表节点, 状态可按目的地址, 源地址和SPI挂接到不同链表
INIT_HLIST_NODE(&x->bydst);
INIT_HLIST_NODE(&x->bysrc);
INIT_HLIST_NODE(&x->byspi);
// 状态定时器
init_timer(&x->timer);
// 定时器处理函数
x->timer.function = xfrm_timer_handler;
x->timer.data = (unsigned long)x;
// 回放检测定时器
init_timer(&x->rtimer);
// 回放定时器处理函数
x->rtimer.function = xfrm_replay_timer_handler;
x->rtimer.data = (unsigned long)x;
x->curlft.add_time = (unsigned long)xtime.tv_sec;
// SA生命期参数
x->lft.soft_byte_limit = XFRM_INF;
x->lft.soft_packet_limit = XFRM_INF;
x->lft.hard_byte_limit = XFRM_INF;
x->lft.hard_packet_limit = XFRM_INF;
// 回放处理参数
x->replay_maxage = 0;
x->replay_maxdiff = 0;
// 初始化状态锁
spin_lock_init(&x->lock);
}
return x;
}
EXPORT_SYMBOL(xfrm_state_alloc);
// 状态定时器超时处理函数
static void xfrm_timer_handler(unsigned long data)
{
struct xfrm_state *x = (struct xfrm_state*)data;
unsigned long now = (unsigned long)xtime.tv_sec;
long next = LONG_MAX;
int warn = 0;
spin_lock(&x->lock);
// 如果该xfrm状态已经处于死亡状态, 可以返回了
if (x->km.state == XFRM_STATE_DEAD)
goto out;
// 如果处于生命期到期状态, 转到期处理
if (x->km.state == XFRM_STATE_EXPIRED)
goto expired;
// 如果到期了还要强制要增加一些时间
if (x->lft.hard_add_expires_seconds) {
// 计算强制增加的超时时间
long tmo = x->lft.hard_add_expires_seconds +
x->curlft.add_time - now;
// 没法增加超时了, 到期
if (tmo <= 0)
goto expired;
if (tmo < next)
next = tmo;
}
// 如果到期了还要强制要增加的使用时间
if (x->lft.hard_use_expires_seconds) {
// 计算强制增加的使用时间
long tmo = x->lft.hard_use_expires_seconds +
(x->curlft.use_time ? : now) - now;
// 没法增加超时了, 到期
if (tmo <= 0)
goto expired;
if (tmo < next)
next = tmo;
}
// dying表示软性增加超时已经不可用
if (x->km.dying)
goto resched;
// 如果到期了还要软性要增加一些时间
if (x->lft.soft_add_expires_seconds) {
// 计算软性增加的时间
long tmo = x->lft.soft_add_expires_seconds +
x->curlft.add_time - now;
// 软性增加超时不可用了
if (tmo <= 0)
warn = 1;
else if (tmo < next)
next = tmo;
}
// 如果到期了还要软性要增加的使用时间
if (x->lft.soft_use_expires_seconds) {
// 计算软性增加的使用时间
long tmo = x->lft.soft_use_expires_seconds +
(x->curlft.use_time ? : now) - now;
// 软性增加超时不可用了
if (tmo <= 0)
warn = 1;
else if (tmo < next)
next = tmo;
}
// dying即为软性增加超时是否可用标志
x->km.dying = warn;
// 软性增加超时已比不可用, 进行状态的超时到期通知
if (warn)
km_state_expired(x, 0, 0);
resched:
// 如果增加的超时有效, 修改定时器超时时间
if (next != LONG_MAX)
mod_timer(&x->timer, jiffies + make_jiffies(next));
goto out;
expired:
// 状态到期
if (x->km.state == XFRM_STATE_ACQ && x->id.spi == 0) {
// 如果这个状态是ACQ类型状态(不是用户空间主动建立的状态,而是内核根据策略主动要求
// 用户空间进行IKE协商建立的状态)
// 状态设置为到期
x->km.state = XFRM_STATE_EXPIRED;
// 唤醒等待队列准备进行垃圾搜集操作
wake_up(&km_waitq);
next = 2;
goto resched;
}
// 删除状态, 进行状态的到期通知
if (!__xfrm_state_delete(x) && x->id.spi)
// 1表示是硬性到期了
km_state_expired(x, 1, 0);
out:
spin_unlock(&x->lock);
}
// 回放定时器超时回调函数
static void xfrm_replay_timer_handler(unsigned long data)
{
struct xfrm_state *x = (struct xfrm_state*)data;
spin_lock(&x->lock);
// 只是状态为有效时才检查
if (x->km.state == XFRM_STATE_VALID) {
// 是否有NETLINK的监听者
if (xfrm_aevent_is_on())
// 通知回放超时事件
xfrm_replay_notify(x, XFRM_REPLAY_TIMEOUT);
else
// 设置通知推迟标志
x->xflags |= XFRM_TIME_DEFER;
}
spin_unlock(&x->lock);
}
状态初始化:
int xfrm_init_state(struct xfrm_state *x)
{
struct xfrm_state_afinfo *afinfo;
int family = x->props.family;
int err;
err = -EAFNOSUPPORT;
// 获取协议族信息结构
afinfo = xfrm_state_get_afinfo(family);
if (!afinfo)
goto error;
err = 0;
// 协议族信息初始化
if (afinfo->init_flags)
err = afinfo->init_flags(x);
xfrm_state_put_afinfo(afinfo);
if (err)
goto error;
err = -EPROTONOSUPPORT;
// 获取可用协议(ah, esp, ipcomp, ip)
x->type = xfrm_get_type(x->id.proto, family);
if (x->type == NULL)
goto error;
err = x->type->init_state(x);
if (err)
goto error;
// 获取可用模式(transport, tunnel)
x->mode = xfrm_get_mode(x->props.mode, family);
if (x->mode == NULL)
goto error;
// 状态设置为VALID
x->km.state = XFRM_STATE_VALID;
error:
return err;
}
EXPORT_SYMBOL(xfrm_init_state);
4.2 状态删除
状态删除函数为xfrm_state_delete(), 该函数被pfkey_delete函数调用.
// 这个函数只是__xfrm_state_delete()加锁的包裹函数
int xfrm_state_delete(struct xfrm_state *x)
{
int err;
spin_lock_bh(&x->lock);
err = __xfrm_state_delete(x);
spin_unlock_bh(&x->lock);
return err;
}
EXPORT_SYMBOL(xfrm_state_delete);
// 实际的相同删除操作函数, 必须保证在x->lock加锁状态下执行
int __xfrm_state_delete(struct xfrm_state *x)
{
int err = -ESRCH;
// 如果状态已经是DEAD就不操作了
if (x->km.state != XFRM_STATE_DEAD) {
// 设置状态为DEAD
x->km.state = XFRM_STATE_DEAD;
// xfrm_state_lock是全局的状态链表操作锁
spin_lock(&xfrm_state_lock);
// 从目的地址索引的链表中断开
hlist_del(&x->bydst);
// 从源地址索引的链表中断开
hlist_del(&x->bysrc);
// 从SPI索引的链表中断开
if (x->id.spi)
hlist_del(&x->byspi);
// xfrm状态总数减一
xfrm_state_num--;
spin_unlock(&xfrm_state_lock);
/* All xfrm_state objects are created by xfrm_state_alloc.
* The xfrm_state_alloc call gives a reference, and that
* is what we are dropping here.
*/
// 减少该状态引用计数
__xfrm_state_put(x);
err = 0;
}
return err;
}
EXPORT_SYMBOL(__xfrm_state_delete);
4.3 删除全部状态
删除全部状态函数为xfrm_state_flush(), 该函数被pfkey_flush函数调用.
// 删除某种协议proto的所有状态
void xfrm_state_flush(u8 proto)
{
int i;
spin_lock_bh(&xfrm_state_lock);
// 循环所有HASH链表
for (i = 0; i <= xfrm_state_hmask; i++) {
struct hlist_node *entry;
struct xfrm_state *x;
restart:
// 在按目的地址进行索引的链表中循环
hlist_for_each_entry(x, entry, xfrm_state_bydst+i, bydst) {
// 要满足两个条件:
// 非正在被ipsec通道使用的状态; 协议类型匹配
if (!xfrm_state_kern(x) &&
xfrm_id_proto_match(x->id.proto, proto)) {
// 先hold住状态,防止在解开xfrm_state_lock锁, 又没被进入xfrm_state_delete()前
// 被意外删除了, 此处考虑得比较仔细
xfrm_state_hold(x);
// 先解开xfrm_state_lock, 在xfrm_state_delete()中要重新上锁
spin_unlock_bh(&xfrm_state_lock);
// 删除状态
xfrm_state_delete(x);
// 减少刚才的引用计数
xfrm_state_put(x);
// 重新加锁, 循环
spin_lock_bh(&xfrm_state_lock);
goto restart;
}
}
}
spin_unlock_bh(&xfrm_state_lock);
wake_up(&km_waitq);
}
EXPORT_SYMBOL(xfrm_state_flush);
4.4 状态增加或更新
状态增加函数为xfrm_state_add(), 状态更新函数为xfrm_state_update(),这两个函数都被pfkey_add函数调用.
// 添加xfrm状态
int xfrm_state_add(struct xfrm_state *x)
{
struct xfrm_state *x1;
int family;
int err;
// 当协议为为ESP, AH, COMP以及ANY时为真, 其他为假
int use_spi = xfrm_id_proto_match(x->id.proto, IPSEC_PROTO_ANY);
family = x->props.family;
spin_lock_bh(&xfrm_state_lock);
// 根据xfrm的地址, SPI, 协议, 协议族等信息查找内核中是否已经存在相同的xfrm
x1 = __xfrm_state_locate(x, use_spi, family);
if (x1) {
// 确实已经存在, 返回错误
xfrm_state_put(x1);
x1 = NULL;
err = -EEXIST;
goto out;
}
if (use_spi && x->km.seq) {
// 如果序列号有效, 根据序列号查找内核中是否已经存在相同的xfrm
x1 = __xfrm_find_acq_byseq(x->km.seq);
// 找到, 但如果目的地址不符合的话, 仍试为没找到
if (x1 && xfrm_addr_cmp(&x1->id.daddr, &x->id.daddr, family)) {
xfrm_state_put(x1);
x1 = NULL;
}
}
// 如果没找到x1, 根据各种信息再查找xfrm
if (use_spi && !x1)
x1 = __find_acq_core(family, x->props.mode, x->props.reqid,
x->id.proto,
&x->id.daddr, &x->props.saddr, 0);
// 如果x和现在内核中的xfrm匹配的话为x生成genid参数
// 会用到一个静态单文件全局变量: xfrm_state_genid
__xfrm_state_bump_genids(x);
// 将新xfrm插入内核的各xfrm表, 这些表是以HASH表形式实现的, 分别根据
// 源地址, 目的地址形成两个HASH表
__xfrm_state_insert(x);
err = 0;
out:
spin_unlock_bh(&xfrm_state_lock);
// 如果按后来的条件找到x1, 删除之, 该状态不需要了
if (x1) {
// 将找到的x1从链表中删除,
xfrm_state_delete(x1);
// 释放x1
xfrm_state_put(x1);
}
return err;
}
EXPORT_SYMBOL(xfrm_state_add);
// 更新xfrm状态
int xfrm_state_update(struct xfrm_state *x)
{
struct xfrm_state *x1;
int err;
int use_spi = xfrm_id_proto_match(x->id.proto, IPSEC_PROTO_ANY);
spin_lock_bh(&xfrm_state_lock);
// 查找内核中相应的xfrm, 找不到的话出错
x1 = __xfrm_state_locate(x, use_spi, x->props.family);
err = -ESRCH;
if (!x1)
goto out;
// 如果该xfrm正在被IPSEC通道使用, 返回错误
if (xfrm_state_kern(x1)) {
xfrm_state_put(x1);
err = -EEXIST;
goto out;
}
// 找到的x1本来就是在acquire状态, 直接将x插入系统xfrm表就行了
if (x1->km.state == XFRM_STATE_ACQ) {
__xfrm_state_insert(x);
x = NULL;
}
err = 0;
out:
spin_unlock_bh(&xfrm_state_lock);
if (err)
return err;
if (!x) {
// 将找到的acquire状态的xfrm删除, 正确返回
xfrm_state_delete(x1);
xfrm_state_put(x1);
return 0;
}
// 找到了x1, 状态也不是acquire, 即进行正常的更新x1中的数据为x的数据
err = -EINVAL;
spin_lock_bh(&x1->lock);
if (likely(x1->km.state == XFRM_STATE_VALID)) {
// 拷贝封装处理
if (x->encap && x1->encap)
memcpy(x1->encap, x->encap, sizeof(*x1->encap));
// 拷贝care of的地址
if (x->coaddr && x1->coaddr) {
memcpy(x1->coaddr, x->coaddr, sizeof(*x1->coaddr));
}
// 没有SPI时拷贝选择子
if (!use_spi && memcmp(&x1->sel, &x->sel, sizeof(x1->sel)))
memcpy(&x1->sel, &x->sel, sizeof(x1->sel));
// 拷贝生命期
memcpy(&x1->lft, &x->lft, sizeof(x1->lft));
x1->km.dying = 0;
// 1秒钟的超时
mod_timer(&x1->timer, jiffies + HZ);
if (x1->curlft.use_time)
xfrm_state_check_expire(x1);
err = 0;
}
spin_unlock_bh(&x1->lock);
xfrm_state_put(x1);
return err;
}
EXPORT_SYMBOL(xfrm_state_update);
4.5 状态插入
状态插入函数为xfrm_state_insert(), 该函数被ipcomp_tunnel_attach()函数(net/ipv4/ipcomp.c)调用
// xfrm_state_insert只是个包裹函数, 加xfrm_state_lock锁后调用__xfrm_state_bump_genids和
// __xfrm_state_insert
void xfrm_state_insert(struct xfrm_state *x)
{
spin_lock_bh(&xfrm_state_lock);
__xfrm_state_bump_genids(x);
__xfrm_state_insert(x);
spin_unlock_bh(&xfrm_state_lock);
}
EXPORT_SYMBOL(xfrm_state_insert);
/* xfrm_state_lock is held */
// 碰撞检查, 看是否有多个连接状态, 要进行区别
static void __xfrm_state_bump_genids(struct xfrm_state *xnew)
{
unsigned short family = xnew->props.family;
u32 reqid = xnew->props.reqid;
struct xfrm_state *x;
struct hlist_node *entry;
unsigned int h;
// 计算状态HASH值来找相关链表
h = xfrm_dst_hash(&xnew->id.daddr, &xnew->props.saddr, reqid, family);
hlist_for_each_entry(x, entry, xfrm_state_bydst+h, bydst) {
// 如果已经在链表中的状态的协议族, 请求ID, 源地址, 目的地址都和新状态匹配
if (x->props.family == family &&
x->props.reqid == reqid &&
!xfrm_addr_cmp(&x->id.daddr, &xnew->id.daddr, family) &&
!xfrm_addr_cmp(&x->props.saddr, &xnew->props.saddr, family))
// 将这些状态的genid参数设置为当前xfrm_state_genid(全局变量)
x->genid = xfrm_state_genid;
}
}
static void __xfrm_state_insert(struct xfrm_state *x)
{
unsigned int h;
// 将新状态的genid设置为当前xfrm_state_genid值加一,和其他碰撞的状态区分开
x->genid = ++xfrm_state_genid;
// 添加到按目的地址HASH的链表
h = xfrm_dst_hash(&x->id.daddr, &x->props.saddr,
x->props.reqid, x->props.family);
hlist_add_head(&x->bydst, xfrm_state_bydst+h);
// 添加到按源地址HASH的链表
h = xfrm_src_hash(&x->id.daddr, &x->props.saddr, x->props.family);
hlist_add_head(&x->bysrc, xfrm_state_bysrc+h);
if (x->id.spi) {
// 添加到按SPI进行HASH的链表
h = xfrm_spi_hash(&x->id.daddr, x->id.spi, x->id.proto,
x->props.family);
hlist_add_head(&x->byspi, xfrm_state_byspi+h);
}
// 修改定时器, 超时仅1秒
mod_timer(&x->timer, jiffies + HZ);
// 如果设置了回放最大时间间隔, 超时改为该值
if (x->replay_maxage)
mod_timer(&x->rtimer, jiffies + x->replay_maxage);
// 唤醒等待队列
wake_up(&km_waitq);
// 状态总数加1
xfrm_state_num++;
// HASH扩大检查, 检查是否需要扩展HASH表数量
xfrm_hash_grow_check(x->bydst.next != NULL);
}
4.6 状态查找
状态查找函数有好几个, 分别按不同条件来查找状态, 注意找到状态后, 都会增加状态的引用计数.
4.6.1 xfrm_state_lookup
// 只是__xfrm_state_lookup的包裹函数, 是根据SPI进行HASH后查找
struct xfrm_state *
xfrm_state_lookup(xfrm_address_t *daddr, __be32 spi, u8 proto,
unsigned short family)
{
struct xfrm_state *x;
spin_lock_bh(&xfrm_state_lock);
x = __xfrm_state_lookup(daddr, spi, proto, family);
spin_unlock_bh(&xfrm_state_lock);
return x;
}
EXPORT_SYMBOL(xfrm_state_lookup);
static struct xfrm_state *__xfrm_state_lookup(xfrm_address_t *daddr, __be32 spi, u8 proto, unsigned short family)
{
// 根据SPI进行HASH
unsigned int h = xfrm_spi_hash(daddr, spi, proto, family);
struct xfrm_state *x;
struct hlist_node *entry;
// 循环相应的SPI链表
hlist_for_each_entry(x, entry, xfrm_state_byspi+h, byspi) {
// 比较协议族, SPI, 和协议是否相同
if (x->props.family != family ||
x->id.spi != spi ||
x->id.proto != proto)
continue;
// 比较目的地址是否相同
switch (family) {
case AF_INET:
if (x->id.daddr.a4 != daddr->a4)
continue;
break;
case AF_INET6:
if (!ipv6_addr_equal((struct in6_addr *)daddr,
(struct in6_addr *)
x->id.daddr.a6))
continue;
break;
};
// 找到, 增加状态引用计数, 返回
xfrm_state_hold(x);
return x;
}
return NULL;
}
4.6.2 按地址查找状态
// 只是__xfrm_state_lookup_byaddr的包裹函数,是根据目的地址进行HASH后查找
struct xfrm_state *
xfrm_state_lookup_byaddr(xfrm_address_t *daddr, xfrm_address_t *saddr,
u8 proto, unsigned short family)
{
struct xfrm_state *x;
spin_lock_bh(&xfrm_state_lock);
x = __xfrm_state_lookup_byaddr(daddr, saddr, proto, family);
spin_unlock_bh(&xfrm_state_lock);
return x;
}
EXPORT_SYMBOL(xfrm_state_lookup_byaddr);
static struct xfrm_state *__xfrm_state_lookup_byaddr(xfrm_address_t *daddr, xfrm_address_t *saddr, u8 proto, unsigned short family)
{
// 根据目的地址计算HASH值
unsigned int h = xfrm_src_hash(daddr, saddr, family);
struct xfrm_state *x;
struct hlist_node *entry;
// 循环相应的源地址链表
hlist_for_each_entry(x, entry, xfrm_state_bysrc+h, bysrc) {
// 比较协议族和协议是否相同
if (x->props.family != family ||
x->id.proto != proto)
continue;
// 比较源地址和目的地址是否相同
switch (family) {
case AF_INET:
if (x->id.daddr.a4 != daddr->a4 ||
x->props.saddr.a4 != saddr->a4)
continue;
break;
case AF_INET6:
if (!ipv6_addr_equal((struct in6_addr *)daddr,
(struct in6_addr *)
x->id.daddr.a6) ||
!ipv6_addr_equal((struct in6_addr *)saddr,
(struct in6_addr *)
x->props.saddr.a6))
continue;
break;
};
// 找到, 增加状态引用计数, 返回
xfrm_state_hold(x);
return x;
}
return NULL;
}
4.6.3 __xfrm_state_locate
这个函数只是__xfrm_state_lookup和__xfrm_state_lookup_byaddr的组合函数
static inline struct xfrm_state *
__xfrm_state_locate(struct xfrm_state *x, int use_spi, int family)
{
if (use_spi)
return __xfrm_state_lookup(&x->id.daddr, x->id.spi,
x->id.proto, family);
else
return __xfrm_state_lookup_byaddr(&x->id.daddr,
&x->props.saddr,
x->id.proto, family);
}
4.6.4 查找ACQUIRE类型的状态
ACQUIRE类型的SA的产生是内核发现数据需要进行保护, 但却没有找到相关的SA, 就向用户空间的IKE协商程序发送ACQUIRE请求, 并生成一个ACQUIRE类型的SA, 如果用户空间协议协商成功会生成合适的SA传内核, 内核就会替换此ACQUIRE的SA, 因此ACQUIRE不是真正可用的SA, 只是表示有此SA的需求, 等待用户空间程序协商结果。
// 只是__find_acq_core的包裹函数
struct xfrm_state *
xfrm_find_acq(u8 mode, u32 reqid, u8 proto,
xfrm_address_t *daddr, xfrm_address_t *saddr,
int create, unsigned short family)
{
struct xfrm_state *x;
spin_lock_bh(&xfrm_state_lock);
x = __find_acq_core(family, mode, reqid, proto, daddr, saddr, create);
spin_unlock_bh(&xfrm_state_lock);
return x;
}
EXPORT_SYMBOL(xfrm_find_acq);
/* xfrm_state_lock is held */
static struct xfrm_state *__find_acq_core(unsigned short family, u8 mode, u32 reqid, u8 proto, xfrm_address_t *daddr, xfrm_address_t *saddr, int create)
{
// 根据源地址,目的地址,请求ID进行目的地址类型HASH
unsigned int h = xfrm_dst_hash(daddr, saddr, reqid, family);
struct hlist_node *entry;
struct xfrm_state *x;
hlist_for_each_entry(x, entry, xfrm_state_bydst+h, bydst) {
// 比较请求ID,数据模式,协议族
// 要求状态的类型为XFRM_STATE_ACQ,SPI值为0
if (x->props.reqid != reqid ||
x->props.mode != mode ||
x->props.family != family ||
x->km.state != XFRM_STATE_ACQ ||
x->id.spi != 0)
continue;
// 再比较源地址和目的地址是否相同
switch (family) {
case AF_INET:
if (x->id.daddr.a4 != daddr->a4 ||
x->props.saddr.a4 != saddr->a4)
continue;
break;
case AF_INET6:
if (!ipv6_addr_equal((struct in6_addr *)x->id.daddr.a6,
(struct in6_addr *)daddr) ||
!ipv6_addr_equal((struct in6_addr *)
x->props.saddr.a6,
(struct in6_addr *)saddr))
continue;
break;
};
// 找到, 增加状态引用计数, 返回
xfrm_state_hold(x);
return x;
}
// 没找到
// 如果不需要创建, 返回NULL
if (!create)
return NULL;
// 创建ACQ类型的xfrm_state
// 分配空间
x = xfrm_state_alloc();
if (likely(x)) {
// 填写网络地址基本参数
switch (family) {
case AF_INET:
x->sel.daddr.a4 = daddr->a4;
x->sel.saddr.a4 = saddr->a4;
x->sel.prefixlen_d = 32;
x->sel.prefixlen_s = 32;
x->props.saddr.a4 = saddr->a4;
x->id.daddr.a4 = daddr->a4;
break;
case AF_INET6:
ipv6_addr_copy((struct in6_addr *)x->sel.daddr.a6,
(struct in6_addr *)daddr);
ipv6_addr_copy((struct in6_addr *)x->sel.saddr.a6,
(struct in6_addr *)saddr);
x->sel.prefixlen_d = 128;
x->sel.prefixlen_s = 128;
ipv6_addr_copy((struct in6_addr *)x->props.saddr.a6,
(struct in6_addr *)saddr);
ipv6_addr_copy((struct in6_addr *)x->id.daddr.a6,
(struct in6_addr *)daddr);
break;
};
// 状态类型设置为XFRM_STATE_ACQ
x->km.state = XFRM_STATE_ACQ;
// 状态其他参数赋值
x->id.proto = proto;
x->props.family = family;
x->props.mode = mode;
x->props.reqid = reqid;
// 硬性可增加的超时
x->lft.hard_add_expires_seconds = XFRM_ACQ_EXPIRES;
xfrm_state_hold(x);
// 超时XFRM_ACQ_EXPIRES秒
x->timer.expires = jiffies + XFRM_ACQ_EXPIRES*HZ;
add_timer(&x->timer);
// 添加到目的HASH链表
hlist_add_head(&x->bydst, xfrm_state_bydst+h);
// 添加到源地址HASH链表
h = xfrm_src_hash(daddr, saddr, family);
hlist_add_head(&x->bysrc, xfrm_state_bysrc+h);
wake_up(&km_waitq);
// 增加状态总数