xfrm6_state.c 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241
  1. /*
  2. * xfrm6_state.c: based on xfrm4_state.c
  3. *
  4. * Authors:
  5. * Mitsuru KANDA @USAGI
  6. * Kazunori MIYAZAWA @USAGI
  7. * Kunihiro Ishiguro <kunihiro@ipinfusion.com>
  8. * IPv6 support
  9. * YOSHIFUJI Hideaki @USAGI
  10. * Split up af-specific portion
  11. *
  12. */
  13. #include <net/xfrm.h>
  14. #include <linux/pfkeyv2.h>
  15. #include <linux/ipsec.h>
  16. #include <net/ipv6.h>
  17. #include <net/addrconf.h>
  18. static struct xfrm_state_afinfo xfrm6_state_afinfo;
  19. static void
  20. __xfrm6_init_tempsel(struct xfrm_state *x, struct flowi *fl,
  21. struct xfrm_tmpl *tmpl,
  22. xfrm_address_t *daddr, xfrm_address_t *saddr)
  23. {
  24. /* Initialize temporary selector matching only
  25. * to current session. */
  26. ipv6_addr_copy((struct in6_addr *)&x->sel.daddr, &fl->fl6_dst);
  27. ipv6_addr_copy((struct in6_addr *)&x->sel.saddr, &fl->fl6_src);
  28. x->sel.dport = xfrm_flowi_dport(fl);
  29. x->sel.dport_mask = ~0;
  30. x->sel.sport = xfrm_flowi_sport(fl);
  31. x->sel.sport_mask = ~0;
  32. x->sel.prefixlen_d = 128;
  33. x->sel.prefixlen_s = 128;
  34. x->sel.proto = fl->proto;
  35. x->sel.ifindex = fl->oif;
  36. x->id = tmpl->id;
  37. if (ipv6_addr_any((struct in6_addr*)&x->id.daddr))
  38. memcpy(&x->id.daddr, daddr, sizeof(x->sel.daddr));
  39. memcpy(&x->props.saddr, &tmpl->saddr, sizeof(x->props.saddr));
  40. if (ipv6_addr_any((struct in6_addr*)&x->props.saddr))
  41. memcpy(&x->props.saddr, saddr, sizeof(x->props.saddr));
  42. if (tmpl->mode == XFRM_MODE_TUNNEL && ipv6_addr_any((struct in6_addr*)&x->props.saddr)) {
  43. struct rt6_info *rt;
  44. struct flowi fl_tunnel = {
  45. .nl_u = {
  46. .ip6_u = {
  47. .daddr = *(struct in6_addr *)daddr,
  48. }
  49. }
  50. };
  51. if (!xfrm_dst_lookup((struct xfrm_dst **)&rt,
  52. &fl_tunnel, AF_INET6)) {
  53. ipv6_get_saddr(&rt->u.dst, (struct in6_addr *)daddr,
  54. (struct in6_addr *)&x->props.saddr);
  55. dst_release(&rt->u.dst);
  56. }
  57. }
  58. x->props.mode = tmpl->mode;
  59. x->props.reqid = tmpl->reqid;
  60. x->props.family = AF_INET6;
  61. }
  62. static struct xfrm_state *
  63. __xfrm6_state_lookup_byaddr(xfrm_address_t *daddr, xfrm_address_t *saddr,
  64. u8 proto)
  65. {
  66. struct xfrm_state *x = NULL;
  67. unsigned h;
  68. h = __xfrm6_src_hash(saddr);
  69. list_for_each_entry(x, xfrm6_state_afinfo.state_bysrc+h, bysrc) {
  70. if (x->props.family == AF_INET6 &&
  71. ipv6_addr_equal((struct in6_addr *)daddr, (struct in6_addr *)x->id.daddr.a6) &&
  72. ipv6_addr_equal((struct in6_addr *)saddr, (struct in6_addr *)x->props.saddr.a6) &&
  73. proto == x->id.proto) {
  74. xfrm_state_hold(x);
  75. return x;
  76. }
  77. }
  78. return NULL;
  79. }
  80. static struct xfrm_state *
  81. __xfrm6_state_lookup(xfrm_address_t *daddr, u32 spi, u8 proto)
  82. {
  83. unsigned h = __xfrm6_spi_hash(daddr, spi, proto);
  84. struct xfrm_state *x;
  85. list_for_each_entry(x, xfrm6_state_afinfo.state_byspi+h, byspi) {
  86. if (x->props.family == AF_INET6 &&
  87. spi == x->id.spi &&
  88. ipv6_addr_equal((struct in6_addr *)daddr, (struct in6_addr *)x->id.daddr.a6) &&
  89. proto == x->id.proto) {
  90. xfrm_state_hold(x);
  91. return x;
  92. }
  93. }
  94. return NULL;
  95. }
  96. static int
  97. __xfrm6_state_sort(struct xfrm_state **dst, struct xfrm_state **src, int n)
  98. {
  99. int i;
  100. int j = 0;
  101. /* Rule 1: select IPsec transport except AH */
  102. for (i = 0; i < n; i++) {
  103. if (src[i]->props.mode == XFRM_MODE_TRANSPORT &&
  104. src[i]->id.proto != IPPROTO_AH) {
  105. dst[j++] = src[i];
  106. src[i] = NULL;
  107. }
  108. }
  109. if (j == n)
  110. goto end;
  111. /* Rule 2: select MIPv6 RO or inbound trigger */
  112. #ifdef CONFIG_IPV6_MIP6
  113. for (i = 0; i < n; i++) {
  114. if (src[i] &&
  115. (src[i]->props.mode == XFRM_MODE_ROUTEOPTIMIZATION ||
  116. src[i]->props.mode == XFRM_MODE_IN_TRIGGER)) {
  117. dst[j++] = src[i];
  118. src[i] = NULL;
  119. }
  120. }
  121. if (j == n)
  122. goto end;
  123. #endif
  124. /* Rule 3: select IPsec transport AH */
  125. for (i = 0; i < n; i++) {
  126. if (src[i] &&
  127. src[i]->props.mode == XFRM_MODE_TRANSPORT &&
  128. src[i]->id.proto == IPPROTO_AH) {
  129. dst[j++] = src[i];
  130. src[i] = NULL;
  131. }
  132. }
  133. if (j == n)
  134. goto end;
  135. /* Rule 4: select IPsec tunnel */
  136. for (i = 0; i < n; i++) {
  137. if (src[i] &&
  138. src[i]->props.mode == XFRM_MODE_TUNNEL) {
  139. dst[j++] = src[i];
  140. src[i] = NULL;
  141. }
  142. }
  143. if (likely(j == n))
  144. goto end;
  145. /* Final rule */
  146. for (i = 0; i < n; i++) {
  147. if (src[i]) {
  148. dst[j++] = src[i];
  149. src[i] = NULL;
  150. }
  151. }
  152. end:
  153. return 0;
  154. }
  155. static int
  156. __xfrm6_tmpl_sort(struct xfrm_tmpl **dst, struct xfrm_tmpl **src, int n)
  157. {
  158. int i;
  159. int j = 0;
  160. /* Rule 1: select IPsec transport */
  161. for (i = 0; i < n; i++) {
  162. if (src[i]->mode == XFRM_MODE_TRANSPORT) {
  163. dst[j++] = src[i];
  164. src[i] = NULL;
  165. }
  166. }
  167. if (j == n)
  168. goto end;
  169. /* Rule 2: select MIPv6 RO or inbound trigger */
  170. #ifdef CONFIG_IPV6_MIP6
  171. for (i = 0; i < n; i++) {
  172. if (src[i] &&
  173. (src[i]->mode == XFRM_MODE_ROUTEOPTIMIZATION ||
  174. src[i]->mode == XFRM_MODE_IN_TRIGGER)) {
  175. dst[j++] = src[i];
  176. src[i] = NULL;
  177. }
  178. }
  179. if (j == n)
  180. goto end;
  181. #endif
  182. /* Rule 3: select IPsec tunnel */
  183. for (i = 0; i < n; i++) {
  184. if (src[i] &&
  185. src[i]->mode == XFRM_MODE_TUNNEL) {
  186. dst[j++] = src[i];
  187. src[i] = NULL;
  188. }
  189. }
  190. if (likely(j == n))
  191. goto end;
  192. /* Final rule */
  193. for (i = 0; i < n; i++) {
  194. if (src[i]) {
  195. dst[j++] = src[i];
  196. src[i] = NULL;
  197. }
  198. }
  199. end:
  200. return 0;
  201. }
  202. static struct xfrm_state_afinfo xfrm6_state_afinfo = {
  203. .family = AF_INET6,
  204. .init_tempsel = __xfrm6_init_tempsel,
  205. .state_lookup = __xfrm6_state_lookup,
  206. .state_lookup_byaddr = __xfrm6_state_lookup_byaddr,
  207. .tmpl_sort = __xfrm6_tmpl_sort,
  208. .state_sort = __xfrm6_state_sort,
  209. };
  210. void __init xfrm6_state_init(void)
  211. {
  212. xfrm_state_register_afinfo(&xfrm6_state_afinfo);
  213. }
  214. void xfrm6_state_fini(void)
  215. {
  216. xfrm_state_unregister_afinfo(&xfrm6_state_afinfo);
  217. }