`
shaojiashuai123456
  • 浏览: 257201 次
  • 性别: Icon_minigender_1
  • 来自: 吉林
社区版块
存档分类
最新评论

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);
// 增加状态总数
  xfrm_state_num++;
// 检查是否需要扩大HASH表数量
  xfrm_hash_grow_check(x->bydst.next != NULL);
 }

 return x;
}


4.6.5 按序号查找ACQUIRE类型的状态


// 只是__xfrm_find_acq_byseq()的包裹函数
struct xfrm_state *xfrm_find_acq_byseq(u32 seq)
{
 struct xfrm_state *x;

 spin_lock_bh(&xfrm_state_lock);
 x = __xfrm_find_acq_byseq(seq);
 spin_unlock_bh(&xfrm_state_lock);
 return x;
}
EXPORT_SYMBOL(xfrm_find_acq_byseq);


static struct xfrm_state *__xfrm_find_acq_byseq(u32 seq)
{
 int i;

// 循环所有HASH链表
 for (i = 0; i <= xfrm_state_hmask; i++) {
  struct hlist_node *entry;
  struct xfrm_state *x;
// 循环链表
  hlist_for_each_entry(x, entry, xfrm_state_bydst+i, bydst) {
// 序号比较, 状态类型也必须是XFRM_STATE_ACQ
   if (x->km.seq == seq &&
       x->km.state == XFRM_STATE_ACQ) {
    xfrm_state_hold(x);
    return x;
   }
  }
 }
 return NULL;
}

 

4.6.6 xfrm_state_find()


xfrm_state_find()函数根据地址, 路由流参数, xfrm模板, xfrm策略等参数来查询状态,在现有的状态中找不到时会新分配一个。该函数被xfrm_tmpl_resolve_one()函数调用, 调用该函数的情景是内核发现一个包符合安全策略需要进行加密处理时会查找是否有相应的SA, 如果有则返回; 如果没找到, 则会通知用户空间的IKE进行进行协商, 生成新的SA, 而xfrm_state_find()函数生成的SA就是ACQUIRE类型的SA, 不是真实可用的。


struct xfrm_state *
xfrm_state_find(xfrm_address_t *daddr, xfrm_address_t *saddr,
  struct flowi *fl, struct xfrm_tmpl *tmpl,
  struct xfrm_policy *pol, int *err,
  unsigned short family)
{
// 根据地址进行HASH
 unsigned int h = xfrm_dst_hash(daddr, saddr, tmpl->reqid, family);
 struct hlist_node *entry;
 struct xfrm_state *x, *x0;
 int acquire_in_progress = 0;
 int error = 0;
 struct xfrm_state *best = NULL;
 
 spin_lock_bh(&xfrm_state_lock);
// 循环链表, 找一个最匹配的状态
 hlist_for_each_entry(x, entry, xfrm_state_bydst+h, bydst) {
// 协议族匹配
  if (x->props.family == family &&
// 请求ID匹配
      x->props.reqid == tmpl->reqid &&
// 无WILDRECV标志
      !(x->props.flags & XFRM_STATE_WILDRECV) &&
// 源目的地址匹配
      xfrm_state_addr_check(x, daddr, saddr, family) &&
// 模式匹配
      tmpl->mode == x->props.mode &&
// 协议匹配
      tmpl->id.proto == x->id.proto &&
// SPI匹配
      (tmpl->id.spi == x->id.spi || !tmpl->id.spi)) {
   /* Resolution logic:
      1. There is a valid state with matching selector.
         Done.
      2. Valid state with inappropriate selector. Skip.

      Entering area of "sysdeps".

      3. If state is not valid, selector is temporary,
         it selects only session which triggered
         previous resolution. Key manager will do
         something to install a state with proper
         selector.
    */
// 如果是合法状态
   if (x->km.state == XFRM_STATE_VALID) {
// 如果选择子不匹配, 跳过
    if (!xfrm_selector_match(&x->sel, fl, family) ||
        !security_xfrm_state_pol_flow_match(x, pol, fl))
     continue;
// 如果还没找到或原来找到的状态的可用时间比新的小, 将找到的状态置为best
    if (!best ||
        best->km.dying > x->km.dying ||
        (best->km.dying == x->km.dying &&
         best->curlft.add_time < x->curlft.add_time))
     best = x;
// 如果是ACQUIRE的状态
   } else if (x->km.state == XFRM_STATE_ACQ) {
// 设置个ACQ标志
    acquire_in_progress = 1;
// 如果是错误或到期的状态
   } else if (x->km.state == XFRM_STATE_ERROR ||
       x->km.state == XFRM_STATE_EXPIRED) {
// 如果选择子反而匹配了, 设置错误号
     if (xfrm_selector_match(&x->sel, fl, family) &&
        security_xfrm_state_pol_flow_match(x, pol, fl))
     error = -ESRCH;
   }
  }
 }

 x = best;
// 没找到, 没错误, 没ACQ的情况
 if (!x && !error && !acquire_in_progress) {
// 根据模块的SPI, 地址, 协议进行查找, 不过应该是找不到才对, 因为SPI是唯一的
  if (tmpl->id.spi &&
      (x0 = __xfrm_state_lookup(daddr, tmpl->id.spi,
           tmpl->id.proto, family)) != NULL) {
// 本应找不到, 如果找到了说明该SPI值已经被使用, 再使用此SPI是错误的
   xfrm_state_put(x0);
   error = -EEXIST;
   goto out;
  }
// 分配新状态
  x = xfrm_state_alloc();
  if (x == NULL) {
   error = -ENOMEM;
   goto out;
  }
  /* Initialize temporary selector matching only
   * to current session. */
// 用模板参数初始化状态
  xfrm_init_tempsel(x, fl, tmpl, daddr, saddr, family);

  error = security_xfrm_state_alloc_acquire(x, pol->security, fl->secid);
  if (error) {
   x->km.state = XFRM_STATE_DEAD;
   xfrm_state_put(x);
   x = NULL;
   goto out;
  }
// 将新状态发送给用户空间程序, 在其中调用了pfkey_acquire函数让用户空间进程进行
// IKE协商生成新SA
  if (km_query(x, tmpl, pol) == 0) {
// 状态类型设置为ACQ
   x->km.state = XFRM_STATE_ACQ;
// 添加到按目的地址HASH的链表
   hlist_add_head(&x->bydst, xfrm_state_bydst+h);
   h = xfrm_src_hash(daddr, saddr, family);
// 添加到按源地址HASH的链表
   hlist_add_head(&x->bysrc, xfrm_state_bysrc+h);
   if (x->id.spi) {
    h = xfrm_spi_hash(&x->id.daddr, x->id.spi, x->id.proto, family);
// 添加到按SPI进行HASH的链表
    hlist_add_head(&x->byspi, xfrm_state_byspi+h);
   }
// 设置定时器
   x->lft.hard_add_expires_seconds = XFRM_ACQ_EXPIRES;
   x->timer.expires = jiffies + XFRM_ACQ_EXPIRES*HZ;
   add_timer(&x->timer);
// 状态总数增加
   xfrm_state_num++;
// 检查是否需要扩大HASH表数量
   xfrm_hash_grow_check(x->bydst.next != NULL);
  } else {
// 发送失败, 状态类型置为DEAD, 放弃
   x->km.state = XFRM_STATE_DEAD;
   xfrm_state_put(x);
   x = NULL;
   error = -ESRCH;
  }
 }
out:

 if (x)
  xfrm_state_hold(x);
 else
  *err = acquire_in_progress ? -EAGAIN : error;
 spin_unlock_bh(&xfrm_state_lock);
 return x;
}


// 初始化xfrm
static int
xfrm_init_tempsel(struct xfrm_state *x, struct flowi *fl,
    struct xfrm_tmpl *tmpl,
    xfrm_address_t *daddr, xfrm_address_t *saddr,
    unsigned short family)
{
 struct xfrm_state_afinfo *afinfo = xfrm_state_get_afinfo(family);
 if (!afinfo)
  return -1;
// 调用网络层协议的init_tempsel函数来初始化, 对于IPV4协议来说是
// __xfrm4_init_tempsel()函数(net/ipv4/xfrm4_state.c)
 afinfo->init_tempsel(x, fl, tmpl, daddr, saddr);
 xfrm_state_put_afinfo(afinfo);
 return 0;
}


static void
__xfrm4_init_tempsel(struct xfrm_state *x, struct flowi *fl,
       struct xfrm_tmpl *tmpl,
       xfrm_address_t *daddr, xfrm_address_t *saddr)
{
// 状态中的选择子参数赋值
// 目的地址
 x->sel.daddr.a4 = fl->fl4_dst;
// 源地址
 x->sel.saddr.a4 = fl->fl4_src;
// 目的端口
 x->sel.dport = xfrm_flowi_dport(fl);
// 目的端口掩码
 x->sel.dport_mask = htons(0xffff);
// 源端口
 x->sel.sport = xfrm_flowi_sport(fl);
// 源端口掩码
 x->sel.sport_mask = htons(0xffff);
// 目的地址长度
 x->sel.prefixlen_d = 32;
// 源地址长度
 x->sel.prefixlen_s = 32;
// 协议
 x->sel.proto = fl->proto;
// 网卡位置
 x->sel.ifindex = fl->oif;
// 状态ID
 x->id = tmpl->id;
// 地址参数
 if (x->id.daddr.a4 == 0)
  x->id.daddr.a4 = daddr->a4;
 x->props.saddr = tmpl->saddr;
 if (x->props.saddr.a4 == 0)
  x->props.saddr.a4 = saddr->a4;
// 模式
 x->props.mode = tmpl->mode;
// 请求ID
 x->props.reqid = tmpl->reqid;
// 协议族
 x->props.family = AF_INET;
}


4.7 遍历状态


状态遍历函数为xfrm_state_walk(), 该函数被pfkey_dump()函数调用


// 遍历状态HASH表, 通过参数func函数指针确定对每个节点进行的操作
// 该函数循环了所有状态两次
int xfrm_state_walk(u8 proto, int (*func)(struct xfrm_state *, int, void*),
      void *data)
{
 int i;
 struct xfrm_state *x;
 struct hlist_node *entry;
 int count = 0;
 int err = 0;

 spin_lock_bh(&xfrm_state_lock);
// 统计要发送多少个符合协议的SA, 这是要将数量作为SA的序号发送给用户空间
// 循环所有HASH表
 for (i = 0; i <= xfrm_state_hmask; i++) {
// 循环单个链表
  hlist_for_each_entry(x, entry, xfrm_state_bydst+i, bydst) {
// 检查协议是否匹配
   if (xfrm_id_proto_match(x->id.proto, proto))
    count++;
  }
 }
 if (count == 0) {
  err = -ENOENT;
  goto out;
 }

// 再次循环进行指定的SA操作, count作为SA的序号, 递减到0
 for (i = 0; i <= xfrm_state_hmask; i++) {
  hlist_for_each_entry(x, entry, xfrm_state_bydst+i, bydst) {
   if (!xfrm_id_proto_match(x->id.proto, proto))
    continue;
// 调用操作函数发送SA
   err = func(x, --count, data);
   if (err)
    goto out;
  }
 }
out:
 spin_unlock_bh(&xfrm_state_lock);
 return err;
}
EXPORT_SYMBOL(xfrm_state_walk);


4.8 状态检查


状态遍历函数为xfrm_state_check(), 该函数被xfrm4_output_one()函数调用

// 返回0表示状态合法, 小于0的数表示状态异常
int xfrm_state_check(struct xfrm_state *x, struct sk_buff *skb)
{
// 检查状态是否到期
 int err = xfrm_state_check_expire(x);
 if (err < 0)
  goto err;
// 检查状态空间
 err = xfrm_state_check_space(x, skb);
err:
 return err;
}
EXPORT_SYMBOL(xfrm_state_check);


int xfrm_state_check_expire(struct xfrm_state *x)
{
// 当前生命期初始时间
 if (!x->curlft.use_time)
  x->curlft.use_time = (unsigned long)xtime.tv_sec;

// 如果状态不是处于VALID状态, 返回错误
 if (x->km.state != XFRM_STATE_VALID)
  return -EINVAL;

// 检查使用该状态的包数字节数是否已经超过硬限制值
 if (x->curlft.bytes >= x->lft.hard_byte_limit ||
     x->curlft.packets >= x->lft.hard_packet_limit) {
// 设置为状态到期
  x->km.state = XFRM_STATE_EXPIRED;
// 立即调用定时器超时函数
  mod_timer(&x->timer, jiffies);
// 返回错误
  return -EINVAL;
 }

// 检查使用该状态的包数字节数是否已经超过软限制值
 if (!x->km.dying &&
     (x->curlft.bytes >= x->lft.soft_byte_limit ||
      x->curlft.packets >= x->lft.soft_packet_limit)) {
// 已经超过软限制标志
  x->km.dying = 1;
// 状态到期通知
  km_state_expired(x, 0, 0);
// 但不返回错误
 }
 return 0;
}
EXPORT_SYMBOL(xfrm_state_check_expire);


static int xfrm_state_check_space(struct xfrm_state *x, struct sk_buff *skb)
{
// 检查skb头部空间是否足够大能容纳增加的协议头和相关的网卡保留参数
 int nhead = x->props.header_len + LL_RESERVED_SPACE(skb->dst->dev)
  - skb_headroom(skb);

// 不够大,进行skb头部扩展, 该函数同样返回0表示成功
 if (nhead > 0)
  return pskb_expand_head(skb, nhead, 0, GFP_ATOMIC);

 /* Check tail too... */
// 理论上也最好检查一下skb尾部空间, 不过也无所谓了, 返回成功
 return 0;
}


4.9 状态HASH表扩展


// 参数have_hash_collision说明已经发生的HASH碰撞, 这是扩展HASH表大小的前提之一
static void xfrm_hash_grow_check(int have_hash_collision)
{
// 发生碰撞
 if (have_hash_collision &&
// HASH掩码不论如何不能超过极限, xfrm_state_hashmax为2^20
     (xfrm_state_hmask + 1) < xfrm_state_hashmax &&
// 当前状态总数已经大于HASH掩码
     xfrm_state_num > xfrm_state_hmask)
// 调度一个work结构
  schedule_work(&xfrm_hash_work);
}

// xfrm_hash_work工作结构定义如下, 调用xfrm_hash_resize函数
static DECLARE_WORK(xfrm_hash_work, xfrm_hash_resize, NULL);


// 改变HASH表大小
static void xfrm_hash_resize(void *__unused)
{
 struct hlist_head *ndst, *nsrc, *nspi, *odst, *osrc, *ospi;
 unsigned long nsize, osize;
 unsigned int nhashmask, ohashmask;
 int i;
// 加resize锁
 mutex_lock(&hash_resize_mutex);
// 计算新的HASH表大小
 nsize = xfrm_hash_new_size();
// 分配按目的地址HASH的HASH表空间
 ndst = xfrm_hash_alloc(nsize);
 if (!ndst)
  goto out_unlock;
// 分配按源地址HASH的HASH表空间
 nsrc = xfrm_hash_alloc(nsize);
 if (!nsrc) {
  xfrm_hash_free(ndst, nsize);
  goto out_unlock;
 }
// 分配按SPI进行HASH的HASH表空间
 nspi = xfrm_hash_alloc(nsize);
 if (!nspi) {
  xfrm_hash_free(ndst, nsize);
  xfrm_hash_free(nsrc, nsize);
  goto out_unlock;
 }
// 加xfrm状态锁
 spin_lock_bh(&xfrm_state_lock);
// 新的HASH表数量
 nhashmask = (nsize / sizeof(struct hlist_head)) - 1U;
// 遍历当前所有HASH表
 for (i = xfrm_state_hmask; i >= 0; i--)
// 将链表中每个状态重新插入新的目的地址, 源地址, SPI的HASH表
  xfrm_hash_transfer(xfrm_state_bydst+i, ndst, nsrc, nspi,
       nhashmask);
// 保留老HASH表参数
 odst = xfrm_state_bydst;
 osrc = xfrm_state_bysrc;
 ospi = xfrm_state_byspi;
 ohashmask = xfrm_state_hmask;

// 将新的HASH表地址赋值给系统的HASH表地址
 xfrm_state_bydst = ndst;
 xfrm_state_bysrc = nsrc;
 xfrm_state_byspi = nspi;
 xfrm_state_hmask = nhashmask;
// 解xfrm状态锁
 spin_unlock_bh(&xfrm_state_lock);

// 释放老的HASH表空间
 osize = (ohashmask + 1) * sizeof(struct hlist_head);
 xfrm_hash_free(odst, osize);
 xfrm_hash_free(osrc, osize);
 xfrm_hash_free(ospi, osize);

out_unlock:
 mutex_unlock(&hash_resize_mutex);
}


static void xfrm_hash_transfer(struct hlist_head *list,
          struct hlist_head *ndsttable,
          struct hlist_head *nsrctable,
          struct hlist_head *nspitable,
          unsigned int nhashmask)
{
 struct hlist_node *entry, *tmp;
 struct xfrm_state *x;
// 循环状态链表
 hlist_for_each_entry_safe(x, entry, tmp, list, bydst) {
  unsigned int h;
  h = __xfrm_dst_hash(&x->id.daddr, &x->props.saddr,
        x->props.reqid, x->props.family,
        nhashmask);
// 将状态插入目的HASH链表, hlist_add_head函数在节点插入前会将其从原链表中断开
  hlist_add_head(&x->bydst, ndsttable+h);

  h = __xfrm_src_hash(&x->id.daddr, &x->props.saddr,
        x->props.family,
        nhashmask);
// 将状态插入源HASH链表, hlist_add_head函数在节点插入前会将其从原链表中断开
  hlist_add_head(&x->bysrc, nsrctable+h);

  if (x->id.spi) {
   h = __xfrm_spi_hash(&x->id.daddr, x->id.spi,
         x->id.proto, x->props.family,
         nhashmask);
// 将状态插入SPI的HASH链表, hlist_add_head函数在节点插入前会将其从原链表中断开
   hlist_add_head(&x->byspi, nspitable+h);
  }
 }
}

static unsigned long xfrm_hash_new_size(void)
{
// 新HASH表数量是原大小加1乘2
 return ((xfrm_state_hmask + 1) << 1) *
  sizeof(struct hlist_head);
}


4.11 垃圾搜集


在状态初始化函数中定义了状态垃圾搜集和释放的工作结构, 相关处理函数为xfrm_state_gc_task

static void xfrm_state_gc_task(void *data)
{
 struct xfrm_state *x;
 struct hlist_node *entry, *tmp;
 struct hlist_head gc_list;

 spin_lock_bh(&xfrm_state_gc_lock);
// 将系统当前的状态垃圾链表节点赋值给gc_list
 gc_list.first = xfrm_state_gc_list.first;
// 重新初始化状态垃圾链表
 INIT_HLIST_HEAD(&xfrm_state_gc_list);
 spin_unlock_bh(&xfrm_state_gc_lock);

// 释放当前的垃圾链表中的各个状态
 hlist_for_each_entry_safe(x, entry, tmp, &gc_list, bydst)
  xfrm_state_gc_destroy(x);

 wake_up(&km_waitq);
}

static void xfrm_state_gc_destroy(struct xfrm_state *x)
{
// 删除定时器
 del_timer_sync(&x->timer);
 del_timer_sync(&x->rtimer);
// 释放算法结构
 kfree(x->aalg);
 kfree(x->ealg);
 kfree(x->calg);
 kfree(x->encap);
 kfree(x->coaddr);
// 释放模式
 if (x->mode)
  xfrm_put_mode(x->mode);
// 释放协议
 if (x->type) {
  x->type->destructor(x);
  xfrm_put_type(x->type);
 }
 security_xfrm_state_free(x);
// 释放状态
 kfree(x);
}


4.12 回调处理


4.12.1  登记和拆除

static struct list_head xfrm_km_list = LIST_HEAD_INIT(xfrm_km_list);
static DEFINE_RWLOCK(xfrm_km_lock);

// 登记xfrm_mgr结构, 就是将结构挂到xfrm_km_list链表
int xfrm_register_km(struct xfrm_mgr *km)
{
 write_lock_bh(&xfrm_km_lock);
 list_add_tail(&km->list, &xfrm_km_list);
 write_unlock_bh(&xfrm_km_lock);
 return 0;
}
EXPORT_SYMBOL(xfrm_register_km);

// 拆除xfrm_mgr结构, 就是将结构从xfrm_km_list链表拆除
int xfrm_unregister_km(struct xfrm_mgr *km)
{
 write_lock_bh(&xfrm_km_lock);
 list_del(&km->list);
 write_unlock_bh(&xfrm_km_lock);
 return 0;
}
EXPORT_SYMBOL(xfrm_unregister_km);


4.12.2 xfrm策略处理的回调通知

以下各回调函数就是遍历xfrm_km_list链表, 调用xfrm_mgr结构中各个成员函数.

void km_policy_notify(struct xfrm_policy *xp, int dir, struct km_event *c)
{
 struct xfrm_mgr *km;

 read_lock(&xfrm_km_lock);
 list_for_each_entry(km, &xfrm_km_list, list)
  if (km->notify_policy)
   km->notify_policy(xp, dir, c);
 read_unlock(&xfrm_km_lock);
}


4.12.3 xfrm状态处理的回调通知

void km_state_notify(struct xfrm_state *x, struct km_event *c)
{
 struct xfrm_mgr *km;
 read_lock(&xfrm_km_lock);
 list_for_each_entry(km, &xfrm_km_list, list)
  if (km->notify)
   km->notify(x, c);
 read_unlock(&xfrm_km_lock);
}

EXPORT_SYMBOL(km_policy_notify);
EXPORT_SYMBOL(km_state_notify);

4.12.4 xfrm策略到期的回调通知

void km_state_expired(struct xfrm_state *x, int hard, u32 pid)
{
 struct km_event c;

 c.data.hard = hard;
 c.pid = pid;
 c.event = XFRM_MSG_EXPIRE;
 km_state_notify(x, &c);

 if (hard)
  wake_up(&km_waitq);
}

EXPORT_SYMBOL(km_state_expired);


4.12.5 xfrm状态获取的回调通知

/*
 * We send to all registered managers regardless of failure
 * We are happy with one success
*/
int km_query(struct xfrm_state *x, struct xfrm_tmpl *t, struct xfrm_policy *pol)
{
 int err = -EINVAL, acqret;
 struct xfrm_mgr *km;

 read_lock(&xfrm_km_lock);
 list_for_each_entry(km, &xfrm_km_list, list) {
  acqret = km->acquire(x, t, pol, XFRM_POLICY_OUT);
  if (!acqret)
   err = acqret;
 }
 read_unlock(&xfrm_km_lock);
 return err;
}
EXPORT_SYMBOL(km_query);


4.12.6 xfrm状态映射处理的回调通知

int km_new_mapping(struct xfrm_state *x, xfrm_address_t *ipaddr, u16 sport)
{
 int err = -EINVAL;
 struct xfrm_mgr *km;

 read_lock(&xfrm_km_lock);
 list_for_each_entry(km, &xfrm_km_list, list) {
  if (km->new_mapping)
   err = km->new_mapping(x, ipaddr, sport);
  if (!err)
   break;
 }
 read_unlock(&xfrm_km_lock);
 return err;
}
EXPORT_SYMBOL(km_new_mapping);


4.12.7 xfrm策略到期的回调通知

void km_policy_expired(struct xfrm_policy *pol, int dir, int hard, u32 pid)
{
 struct km_event c;

 c.data.hard = hard;
 c.pid = pid;
 c.event = XFRM_MSG_POLEXPIRE;
// 实际是调用策略通知回调
 km_policy_notify(pol, dir, &c);

 if (hard)
  wake_up(&km_waitq);
}
EXPORT_SYMBOL(km_policy_expired);


4.12.8 xfrm报告的回调通知

int km_report(u8 proto, struct xfrm_selector *sel, xfrm_address_t *addr)
{
 int err = -EINVAL;
 int ret;
 struct xfrm_mgr *km;

 read_lock(&xfrm_km_lock);
 list_for_each_entry(km, &xfrm_km_list, list) {
  if (km->report) {
   ret = km->report(proto, sel, addr);
   if (!ret)
    err = ret;
  }
 }
 read_unlock(&xfrm_km_lock);
 return err;
}
EXPORT_SYMBOL(km_report);

 

4.13 小结


xfrm_state相关函数的调用被调用关系可如下简单表示:

 
ipcomp_tunnel_attack
  -> xfrm_state_lookup
  -> xfrm_state_insert
    -> __xfrm_state_bump_genids
    -> __xfrm_state_insert

 
pfkey_add
  -> xfrm_state_update
    -> __xfrm_state_locate
      -> __xfrm_state_lookup
      -> __xfrm_state_lookup_byaddr
  -> xfrm_state_add
    -> __xfrm_state_locate
    -> __xfrm_find_acq_byseq
    -> __find_acq_core
      -> xfrm_state_alloc


xfrm4_output_one
  -> xfrm_state_check
    -> xfrm_state_check_expire
    -> xfrm_state_check_space


xfrm_state_find
  -> km_query
    -> pfkey_acquire
      -> xfrm_find_acq_byseq
        -> __xfrm_find_acq_byseq


pfkey_getspi
  -> xfrm_find_acq_byseq
    -> __xfrm_find_acq_byseq
  -> xfrm_find_acq


pfkey_dump
  -> xfrm_state_walk


__xfrm_route_forward
ip_route_output_flow
  -> xfrm_lookup
    -> xfrm_tmpl_resolve
      -> xfrm_tmpl_resolve_one
        -> xfrm_state_find


tunnel4_protocol->handler == tunnel4_rcv
  ->tunnel->handler == xfrm4_rcv == esp4/ah4/ipcomp4_protocol->handler
    ->xfrm4_rcv_encap
      -> xfrm4_parse_spi
      -> xfrm_state_lookup
      -> xfrm_replay_check
      -> x->type->input
      -> xfrm_replay_advance
   -> x->mode->input

...... 待续 ......

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics