Linux内核中的IPSEC实现(4)

146 篇文章 12 订阅
81 篇文章 0 订阅
Java代码   收藏代码
  1. 6. XFRM的其他操作  
  2.   
  3. 6.1 HASH处理  
  4.   
  5. 关于HASH值的计算方法主要在net/xfrm/xfrm_hash.h中定义:  
  6. // IPV4地址HASH  
  7. static inline unsigned int __xfrm4_addr_hash(xfrm_address_t *addr)  
  8. {  
  9. // 就是地址本身  
  10.  return ntohl(addr->a4);  
  11. }  
  12. // IPV6地址HASH  
  13. static inline unsigned int __xfrm6_addr_hash(xfrm_address_t *addr)  
  14. {  
  15. // 取后2个32位数异或  
  16.  return ntohl(addr->a6[2] ^ addr->a6[3]);  
  17. }  
  18. // IPV4源,目的地址HASH  
  19. static inline unsigned int __xfrm4_daddr_saddr_hash(xfrm_address_t *daddr, xfrm_address_t *saddr)  
  20. {  
  21. // 将两个地址异或  
  22.  return ntohl(daddr->a4 ^ saddr->a4);  
  23. }  
  24. // IPV4源,目的地址HASH  
  25. static inline unsigned int __xfrm6_daddr_saddr_hash(xfrm_address_t *daddr, xfrm_address_t *saddr)  
  26. {  
  27. // 两个V6地址都取后2个32位数异或  
  28.  return ntohl(daddr->a6[2] ^ daddr->a6[3] ^  
  29.        saddr->a6[2] ^ saddr->a6[3]);  
  30. }  
  31. // 目的地址HASH  
  32. static inline unsigned int __xfrm_dst_hash(xfrm_address_t *daddr, xfrm_address_t *saddr,  
  33.         u32 reqid, unsigned short family,  
  34.         unsigned int hmask)  
  35. {  
  36. // 协议族和请求ID异或  
  37.  unsigned int h = family ^ reqid;  
  38.  switch (family) {  
  39. // HASH值再和源目的地址HASH结果进行异或  
  40.  case AF_INET:  
  41.   h ^= __xfrm4_daddr_saddr_hash(daddr, saddr);  
  42.   break;  
  43.  case AF_INET6:  
  44.   h ^= __xfrm6_daddr_saddr_hash(daddr, saddr);  
  45.   break;  
  46.  }  
  47. // 将HASH结果高低16位异或存低16位,高16位不动, 然后用HASH掩码相与  
  48.  return (h ^ (h >> 16)) & hmask;  
  49. }  
  50.   
  51. // 源地址HASH, 只是没有请求ID项, 其他HASH过程和上面相同  
  52. static inline unsigned __xfrm_src_hash(xfrm_address_t *daddr,  
  53.            xfrm_address_t *saddr,  
  54.            unsigned short family,  
  55.            unsigned int hmask)  
  56. {  
  57.  unsigned int h = family;  
  58.  switch (family) {  
  59.  case AF_INET:  
  60.   h ^= __xfrm4_daddr_saddr_hash(daddr, saddr);  
  61.   break;  
  62.  case AF_INET6:  
  63.   h ^= __xfrm6_daddr_saddr_hash(daddr, saddr);  
  64.   break;  
  65.  };  
  66.  return (h ^ (h >> 16)) & hmask;  
  67. }  
  68.   
  69. // 根据SPI计算HASH值  
  70. static inline unsigned int  
  71. __xfrm_spi_hash(xfrm_address_t *daddr, __be32 spi, u8 proto, unsigned short family,  
  72.   unsigned int hmask)  
  73. {  
  74. // 先将SPI和协议进行异或  
  75.  unsigned int h = (__force u32)spi ^ proto;  
  76.  switch (family) {  
  77. // HASH值再和目的地址进行单一地址HASH值异或  
  78.  case AF_INET:  
  79.   h ^= __xfrm4_addr_hash(daddr);  
  80.   break;  
  81.  case AF_INET6:  
  82.   h ^= __xfrm6_addr_hash(daddr);  
  83.   break;  
  84.  }  
  85. // HASH值再和本身的高22位, 高12位异或后再和掩码相与  
  86.  return (h ^ (h >> 10) ^ (h >> 20)) & hmask;  
  87. }  
  88.   
  89. // 索引号HASH  
  90. static inline unsigned int __idx_hash(u32 index, unsigned int hmask)  
  91. {  
  92. // 低24位和高24位异或, 高8位不动, 再和掩码相与  
  93.  return (index ^ (index >> 8)) & hmask;  
  94. }  
  95.   
  96. // 选择子HASH  
  97. static inline unsigned int __sel_hash(struct xfrm_selector *sel, unsigned short family, unsigned int hmask)  
  98. {  
  99. // 提前源和目的地址  
  100.  xfrm_address_t *daddr = &sel->daddr;  
  101.  xfrm_address_t *saddr = &sel->saddr;  
  102.  unsigned int h = 0;  
  103.  switch (family) {  
  104. // 用源,目的地址同时进行HASH  
  105.  case AF_INET:  
  106.   if (sel->prefixlen_d != 32 ||  
  107.       sel->prefixlen_s != 32)  
  108.    return hmask + 1;  
  109.   h = __xfrm4_daddr_saddr_hash(daddr, saddr);  
  110.   break;  
  111.  case AF_INET6:  
  112.   if (sel->prefixlen_d != 128 ||  
  113.       sel->prefixlen_s != 128)  
  114.    return hmask + 1;  
  115.   h = __xfrm6_daddr_saddr_hash(daddr, saddr);  
  116.   break;  
  117.  };  
  118. // 高16位与低16位异或,高16位不变  
  119.  h ^= (h >> 16);  
  120. // 与掩码相与, 其实HASH值中不带协议族因素, 因为地址本身就包含了  
  121.  return h & hmask;  
  122. }  
  123. // 地址HASH  
  124. static inline unsigned int __addr_hash(xfrm_address_t *daddr, xfrm_address_t *saddr, unsigned short family, unsigned int hmask)  
  125. {  
  126.  unsigned int h = 0;  
  127.  switch (family) {  
  128. // 用源,目的地址同时进行HASH  
  129.  case AF_INET:  
  130.   h = __xfrm4_daddr_saddr_hash(daddr, saddr);  
  131.   break;  
  132.  case AF_INET6:  
  133.   h = __xfrm6_daddr_saddr_hash(daddr, saddr);  
  134.   break;  
  135.  };  
  136. // 高16位与低16位异或,高16位不变  
  137.  h ^= (h >> 16);  
  138. // 与掩码相与  
  139.  return h & hmask;  
  140. }  
  141.   
  142. 在net/xfrm/xfrm_hash.c 文件中定义了HASH表的分配和释放函数:  
  143.   
  144. struct hlist_head *xfrm_hash_alloc(unsigned int sz)  
  145. {  
  146.  struct hlist_head *n;  
  147. // 根据HASH表大小选择合适的分配方法  
  148. // 大小不超过PAGE_SIZE, 用kmalloc分配  
  149.  if (sz <= PAGE_SIZE)  
  150.   n = kmalloc(sz, GFP_KERNEL);  
  151. // 这是在内核定义NUMA和IA64下用vmalloc分配  
  152.  else if (hashdist)  
  153.   n = __vmalloc(sz, GFP_KERNEL, PAGE_KERNEL);  
  154.  else  
  155. // 其他类型的内核用get_free_page分配  
  156.   n = (struct hlist_head *)  
  157.    __get_free_pages(GFP_KERNEL, get_order(sz));  
  158. // 空间清零  
  159.  if (n)  
  160.   memset(n, 0, sz);  
  161.  return n;  
  162. }  
  163. // 释放HASH表空间  
  164. void xfrm_hash_free(struct hlist_head *n, unsigned int sz)  
  165. {  
  166.  if (sz <= PAGE_SIZE)  
  167.   kfree(n);  
  168.  else if (hashdist)  
  169.   vfree(n);  
  170.  else  
  171.   free_pages((unsigned long)n, get_order(sz));  
  172. }  
  173.   
  174. 6.2 算法操作  
  175.   
  176. IPSEC操作中用到的认证, 加密, 压缩等算法具体实现是在crypto目录下, 而在xfrm中只是定义这些算法的说明, 表示最大可以支持这些算法, 在使用时会探测这些算法是否在内核中存在从而确定可使用的算法.  
  177. 关于算法的数据结构如下:  
  178. /* include/net/xfrm.h */  
  179. // 认证算法参数  
  180. struct xfrm_algo_auth_info {  
  181.  u16 icv_truncbits; // 初始向量截断位数  
  182.  u16 icv_fullbits;  // 初始向量总的位数  
  183. };  
  184. // 加密算法参数  
  185. struct xfrm_algo_encr_info {  
  186.  u16 blockbits;  // 块位数  
  187.  u16 defkeybits; // 密钥长度位数  
  188. };  
  189. // 压缩算法参数  
  190. struct xfrm_algo_comp_info {  
  191.  u16 threshold;  // 阈值  
  192. };  
  193. // xfrm算法描述  
  194. struct xfrm_algo_desc {  
  195.  char *name;  // 名称  
  196.  char *compat; // 名称缩写  
  197.  u8 available:1// 算法是否可用(是否在内核中)  
  198.  union {  
  199.   struct xfrm_algo_auth_info auth;  
  200.   struct xfrm_algo_encr_info encr;  
  201.   struct xfrm_algo_comp_info comp;  
  202.  } uinfo; // 算法信息联合  
  203.  struct sadb_alg desc; // 通用算法描述  
  204. };  
  205.   
  206. 6.2.1 认证算法  
  207. 可用的认证算法通过下面的数组来描述, 包含NULL, MD5, SHA1, SHA256, RIPEMD160等认证算法:  
  208. static struct xfrm_algo_desc aalg_list[] = {  
  209. ......  
  210. {  
  211.  .name = "hmac(sha1)",  
  212.  .compat = "sha1",  
  213.  .uinfo = {  
  214.   .auth = {  
  215.    .icv_truncbits = 96,// 96位截断  
  216.    .icv_fullbits = 160// 总共160位  
  217.   }  
  218.  },  
  219.  .desc = { // 这是对SHA1认证算法的标准描述参数  
  220.   .sadb_alg_id = SADB_AALG_SHA1HMAC, // 算法ID值  
  221.   .sadb_alg_ivlen = 0,  
  222.   .sadb_alg_minbits = 160,  
  223.   .sadb_alg_maxbits = 160  
  224.  }  
  225. },  
  226. ......  
  227.   
  228. 相关操作函数:  
  229. // 通过算法ID查找认证算法  
  230. struct xfrm_algo_desc *xfrm_aalg_get_byid(int alg_id)  
  231. {  
  232.  int i;  
  233. // 遍历认证数组  
  234.  for (i = 0; i < aalg_entries(); i++) {  
  235. // 查找和指定算法ID相同的算法  
  236.   if (aalg_list[i].desc.sadb_alg_id == alg_id) {  
  237. // 检查该算法是否可用  
  238.    if (aalg_list[i].available)  
  239.     return &aalg_list[i];  
  240.    else  
  241.     break;  
  242.   }  
  243.  }  
  244.  return NULL;  
  245. }  
  246. EXPORT_SYMBOL_GPL(xfrm_aalg_get_byid);  
  247.   
  248. // 统计可用的认证算法数量, 就是available的认证算法数量累加  
  249. int xfrm_count_auth_supported(void)  
  250. {  
  251.  int i, n;  
  252.  for (i = 0, n = 0; i < aalg_entries(); i++)  
  253.   if (aalg_list[i].available)  
  254.    n++;  
  255.  return n;  
  256. }  
  257. EXPORT_SYMBOL_GPL(xfrm_count_auth_supported);  
  258. 6.2.2 加密算法  
  259.   
  260. 可用的认证算法通过下面的数组来描述, 包含NULL, DES, 3DES, CAST, AES, BLOWFISH, TWOFISH, SERPENT等加密算法:  
  261. static struct xfrm_algo_desc ealg_list[] = {  
  262. ......  
  263. {  
  264.  .name = "cbc(des3_ede)",  
  265.  .compat = "des3_ede",  
  266.  .uinfo = {  
  267.   .encr = {  
  268.    .blockbits = 64,  
  269.    .defkeybits = 192,  
  270.   }  
  271.  },  
  272.  .desc = {  
  273.   .sadb_alg_id = SADB_EALG_3DESCBC,  
  274.   .sadb_alg_ivlen = 8,  
  275.   .sadb_alg_minbits = 192,  
  276.   .sadb_alg_maxbits = 192  
  277.  }  
  278. },  
  279. ......  
  280.   
  281. // 通过算法ID查找加密算法, 和认证算法查找类似  
  282. struct xfrm_algo_desc *xfrm_ealg_get_byid(int alg_id)  
  283. {  
  284.  int i;  
  285.  for (i = 0; i < ealg_entries(); i++) {  
  286.   if (ealg_list[i].desc.sadb_alg_id == alg_id) {  
  287.    if (ealg_list[i].available)  
  288.     return &ealg_list[i];  
  289.    else  
  290.     break;  
  291.   }  
  292.  }  
  293.  return NULL;  
  294. }  
  295. EXPORT_SYMBOL_GPL(xfrm_ealg_get_byid);  
  296.   
  297. // 统计可用的加密算法数量, 就是available的加密算法数量累加  
  298. int xfrm_count_enc_supported(void)  
  299. {  
  300.  int i, n;  
  301.  for (i = 0, n = 0; i < ealg_entries(); i++)  
  302.   if (ealg_list[i].available)  
  303.    n++;  
  304.  return n;  
  305. }  
  306. EXPORT_SYMBOL_GPL(xfrm_count_enc_supported);  
  307.   
  308. 6.2.3 压缩算法  
  309.   
  310. 可用的压缩算法通过下面的数组来描述, 包含DELFATE, LZS, LZJH等压缩算法:  
  311. static struct xfrm_algo_desc calg_list[] = {  
  312. ......  
  313. {  
  314.  .name = "lzs",  
  315.  .uinfo = {  
  316.   .comp = {  
  317.    .threshold = 90,  
  318.   }  
  319.  },  
  320.  .desc = { .sadb_alg_id = SADB_X_CALG_LZS }  
  321. },  
  322. ......  
  323.   
  324. // 通过算法ID查找加密算法, 和认证算法查找类似  
  325. struct xfrm_algo_desc *xfrm_calg_get_byid(int alg_id)  
  326. {  
  327.  int i;  
  328.  for (i = 0; i < calg_entries(); i++) {  
  329.   if (calg_list[i].desc.sadb_alg_id == alg_id) {  
  330.    if (calg_list[i].available)  
  331.     return &calg_list[i];  
  332.    else  
  333.     break;  
  334.   }  
  335.  }  
  336.  return NULL;  
  337. }  
  338. EXPORT_SYMBOL_GPL(xfrm_calg_get_byid);  
  339.   
  340. 6.2.4 通过名称查找算法  
  341.   
  342. // 输入参数为算法数组, 数组元素个数, 类型, 掩码, 名称和是否探测在内核中存在  
  343. static struct xfrm_algo_desc *xfrm_get_byname(struct xfrm_algo_desc *list,  
  344.            int entries, u32 type, u32 mask,  
  345.            char *name, int probe)  
  346. {  
  347.  int i, status;  
  348.  if (!name)  
  349.   return NULL;  
  350. // 遍历数组  
  351.  for (i = 0; i < entries; i++) {  
  352. // 比较算法名称或缩写名称是否和指定名称相同  
  353.   if (strcmp(name, list[i].name) &&  
  354.       (!list[i].compat || strcmp(name, list[i].compat)))  
  355.    continue;  
  356. // 找到算法结构  
  357. // 检查算法是否在内核可用, 可用的话成功返回  
  358.   if (list[i].available)  
  359.    return &list[i];  
  360. // 如果不需要探测, 将返回空  
  361.   if (!probe)  
  362.    break;  
  363. // 需要探测算法算法存在内核, 调用crypto_has_alg()函数探测  
  364. // 返回0表示失败, 非0表示成功  
  365.   status = crypto_has_alg(name, type, mask | CRYPTO_ALG_ASYNC);  
  366.   if (!status)  
  367.    break;  
  368. // 算法可用, 返回  
  369.   list[i].available = status;  
  370.   return &list[i];  
  371.  }  
  372.  return NULL;  
  373. }  
  374.   
  375. /* crypto/api.c */  
  376. // 算法探测  
  377. int crypto_has_alg(const char *name, u32 type, u32 mask)  
  378. {  
  379.  int ret = 0;  
  380. // 根据名称, 类型和掩码探测算法模块  
  381.  struct crypto_alg *alg = crypto_alg_mod_lookup(name, type, mask);  
  382. // 正确返回找到   
  383.  if (!IS_ERR(alg)) {  
  384. // 减少模块计数, 返回1  
  385.   crypto_mod_put(alg);  
  386.   ret = 1;  
  387.  }  
  388.    
  389.  return ret;  
  390. }  
  391.   
  392. 有了xfrm_get_byname()这个通用基本函数, 具体类型的算法查找函数就很简单了:  
  393.   
  394. // 通过名称查找认证算法  
  395. struct xfrm_algo_desc *xfrm_aalg_get_byname(char *name, int probe)  
  396. {  
  397.  return xfrm_get_byname(aalg_list, aalg_entries(),  
  398.           CRYPTO_ALG_TYPE_HASH, CRYPTO_ALG_TYPE_HASH_MASK,  
  399.           name, probe);  
  400. }  
  401. EXPORT_SYMBOL_GPL(xfrm_aalg_get_byname);  
  402. // 通过名称查找加密算法  
  403. struct xfrm_algo_desc *xfrm_ealg_get_byname(char *name, int probe)  
  404. {  
  405.  return xfrm_get_byname(ealg_list, ealg_entries(),  
  406.           CRYPTO_ALG_TYPE_BLKCIPHER, CRYPTO_ALG_TYPE_MASK,  
  407.           name, probe);  
  408. }  
  409. EXPORT_SYMBOL_GPL(xfrm_ealg_get_byname);  
  410. // 通过名称查找压缩算法  
  411. struct xfrm_algo_desc *xfrm_calg_get_byname(char *name, int probe)  
  412. {  
  413.  return xfrm_get_byname(calg_list, calg_entries(),  
  414.           CRYPTO_ALG_TYPE_COMPRESS, CRYPTO_ALG_TYPE_MASK,  
  415.           name, probe);  
  416. }  
  417. EXPORT_SYMBOL_GPL(xfrm_calg_get_byname);  
  418.    
  419. 以下是通过索引号来查找算法, 就是直接返回相应数组指定位置的算法:  
  420.   
  421. struct xfrm_algo_desc *xfrm_aalg_get_byidx(unsigned int idx)  
  422. {  
  423.  if (idx >= aalg_entries())  
  424.   return NULL;  
  425.  return &aalg_list[idx];  
  426. }  
  427. EXPORT_SYMBOL_GPL(xfrm_aalg_get_byidx);  
  428. struct xfrm_algo_desc *xfrm_ealg_get_byidx(unsigned int idx)  
  429. {  
  430.  if (idx >= ealg_entries())  
  431.   return NULL;  
  432.  return &ealg_list[idx];  
  433. }  
  434. EXPORT_SYMBOL_GPL(xfrm_ealg_get_byidx);  
  435.   
  436. 6.2.5 xfrm算法探测  
  437.   
  438. 该函数在SA进行调整时会调用来查看当前内核中支持的各种算法  
  439. /* 
  440.  * Probe for the availability of crypto algorithms, and set the available 
  441.  * flag for any algorithms found on the system.  This is typically called by 
  442.  * pfkey during userspace SA add, update or register. 
  443.  */  
  444. void xfrm_probe_algs(void)  
  445. {  
  446. // 内核必须定义CRYPTO选项, 否则就是空函数了  
  447. #ifdef CONFIG_CRYPTO  
  448.  int i, status;  
  449.    
  450.  BUG_ON(in_softirq());  
  451. // 遍历认证算法数组  
  452.  for (i = 0; i < aalg_entries(); i++) {  
  453. // 根据算法名称确定该HASH算法是否存在, 返回0不存在, 非0存在  
  454.   status = crypto_has_hash(aalg_list[i].name, 0,  
  455.       CRYPTO_ALG_ASYNC);  
  456. // 如果状态和原来的状态不同, 更改  
  457.   if (aalg_list[i].available != status)  
  458.    aalg_list[i].available = status;  
  459.  }  
  460.    
  461. // 遍历加密算法数组  
  462.  for (i = 0; i < ealg_entries(); i++) {  
  463. // 根据算法名称确定该加密算法是否存在, 返回0不存在, 非0存在  
  464.   status = crypto_has_blkcipher(ealg_list[i].name, 0,  
  465.            CRYPTO_ALG_ASYNC);  
  466. // 如果状态和原来的状态不同, 更改  
  467.   if (ealg_list[i].available != status)  
  468.    ealg_list[i].available = status;  
  469.  }  
  470.    
  471. // 遍历压缩算法数组  
  472.  for (i = 0; i < calg_entries(); i++) {  
  473. // 根据算法名称确定该压缩算法是否存在, 返回0不存在, 非0存在  
  474.   status = crypto_has_comp(calg_list[i].name, 0,  
  475.       CRYPTO_ALG_ASYNC);  
  476. // 如果状态和原来的状态不同, 更改  
  477.   if (calg_list[i].available != status)  
  478.    calg_list[i].available = status;  
  479.  }  
  480. #endif  
  481. }  
  482. EXPORT_SYMBOL_GPL(xfrm_probe_algs);  
  483.   
  484. 6.3 通过netlink套接口访问xfrm  
  485.   
  486. 通过netlink套接口访问xfrm的处理函数在net/xfrm/xfrm_user.c中, 提供了Linux特色的非标准PF_KEY接口的SA, SP控制方法, 能完成和PF_KEY一样控制功能, 目前iproute2中的ip工具中新增加的xfrm命令就是通过这种netlink接口来完成的, 因为netlink操作以前已经介绍过, xfrm的操作又都是一样的, 因此本文不再分析其实现过程.  
  487.   
  488. 6.4 xfrm_input  
  489.   
  490. 在net/xfrm/xfrm_input.c文件中定义了关于安全路径(struct sec_path)的几个处理函数, 用于对输入的IPSEC包进行解析构造安全路径使用.  
  491. // 释放安全路径  
  492. void __secpath_destroy(struct sec_path *sp)  
  493. {  
  494.  int i;  
  495. // 减少安全路径中所有SA的使用计数  
  496.  for (i = 0; i < sp->len; i++)  
  497.   xfrm_state_put(sp->xvec[i]);  
  498. // 释放安全路径空间  
  499.  kmem_cache_free(secpath_cachep, sp);  
  500. }  
  501. EXPORT_SYMBOL(__secpath_destroy);  
  502. // 安全路径复制  
  503. struct sec_path *secpath_dup(struct sec_path *src)  
  504. {  
  505.  struct sec_path *sp;  
  506. // 先分配安全路径结构  
  507.  sp = kmem_cache_alloc(secpath_cachep, SLAB_ATOMIC);  
  508.  if (!sp)  
  509.   return NULL;  
  510.  sp->len = 0;  
  511.  if (src) {  
  512.   int i;  
  513. // 如果源安全路径结构非空, 将其全部复制到新结构中  
  514.   memcpy(sp, src, sizeof(*sp));  
  515. // 增加安全路径中所有SA的使用计数  
  516.   for (i = 0; i < sp->len; i++)  
  517.    xfrm_state_hold(sp->xvec[i]);  
  518.  }  
  519. // 设置该引用计数初始值位1  
  520.  atomic_set(&sp->refcnt, 1);  
  521.  return sp;  
  522. }  
  523. EXPORT_SYMBOL(secpath_dup);  
  524.    
  525. /* Fetch spi and seq from ipsec header */  
  526. // 从数据包中解析SPI和序号, 返回值是网络序的  
  527. int xfrm_parse_spi(struct sk_buff *skb, u8 nexthdr, __be32 *spi, __be32 *seq)  
  528. {  
  529.  int offset, offset_seq;  
  530. // 通过nexthdr参数来判断协议类型, nexthdr是IPV6里的说法, 在IPV4中就是IP头里的协议字段  
  531. // 根据不同协议确定数据中SPI和序列号相对数据起始点的偏移  
  532.  switch (nexthdr) {  
  533.  case IPPROTO_AH:  
  534.   offset = offsetof(struct ip_auth_hdr, spi);  
  535.   offset_seq = offsetof(struct ip_auth_hdr, seq_no);  
  536.   break;  
  537.  case IPPROTO_ESP:  
  538.   offset = offsetof(struct ip_esp_hdr, spi);  
  539.   offset_seq = offsetof(struct ip_esp_hdr, seq_no);  
  540.   break;  
  541.  case IPPROTO_COMP:  
  542. // 对应压缩协议单独处理  
  543. // 数据头准备出IP压缩头结构长度  
  544.   if (!pskb_may_pull(skb, sizeof(struct ip_comp_hdr)))  
  545.    return -EINVAL;  
  546. // SPI值取第3,4字节的数据, 序号为0  
  547.   *spi = htonl(ntohs(*(__be16*)(skb->h.raw + 2)));  
  548.   *seq = 0;  
  549.   return 0;  
  550.  default:  
  551.   return 1;  
  552.  }  
  553. // 数据头准备16字节空间, 这是ip_auth_hdr和ip_esp_hdr结构最小长度  
  554.  if (!pskb_may_pull(skb, 16))  
  555.   return -EINVAL;  
  556. // 根据偏移获取SPI和序号, 注意是网络序的值  
  557.  *spi = *(__be32*)(skb->h.raw + offset);  
  558.  *seq = *(__be32*)(skb->h.raw + offset_seq);  
  559.  return 0;  
  560. }  
  561. EXPORT_SYMBOL(xfrm_parse_spi);  
  562.   
  563. ...... 待续 ......  
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值