xfrm6_state.c 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153
  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 && 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(xfrm_address_t *daddr, u32 spi, u8 proto)
  64. {
  65. unsigned h = __xfrm6_spi_hash(daddr, spi, proto);
  66. struct xfrm_state *x;
  67. list_for_each_entry(x, xfrm6_state_afinfo.state_byspi+h, byspi) {
  68. if (x->props.family == AF_INET6 &&
  69. spi == x->id.spi &&
  70. ipv6_addr_equal((struct in6_addr *)daddr, (struct in6_addr *)x->id.daddr.a6) &&
  71. proto == x->id.proto) {
  72. xfrm_state_hold(x);
  73. return x;
  74. }
  75. }
  76. return NULL;
  77. }
  78. static struct xfrm_state *
  79. __xfrm6_find_acq(u8 mode, u32 reqid, u8 proto,
  80. xfrm_address_t *daddr, xfrm_address_t *saddr,
  81. int create)
  82. {
  83. struct xfrm_state *x, *x0;
  84. unsigned h = __xfrm6_dst_hash(daddr);
  85. x0 = NULL;
  86. list_for_each_entry(x, xfrm6_state_afinfo.state_bydst+h, bydst) {
  87. if (x->props.family == AF_INET6 &&
  88. ipv6_addr_equal((struct in6_addr *)daddr, (struct in6_addr *)x->id.daddr.a6) &&
  89. mode == x->props.mode &&
  90. proto == x->id.proto &&
  91. ipv6_addr_equal((struct in6_addr *)saddr, (struct in6_addr *)x->props.saddr.a6) &&
  92. reqid == x->props.reqid &&
  93. x->km.state == XFRM_STATE_ACQ &&
  94. !x->id.spi) {
  95. x0 = x;
  96. break;
  97. }
  98. }
  99. if (!x0 && create && (x0 = xfrm_state_alloc()) != NULL) {
  100. ipv6_addr_copy((struct in6_addr *)x0->sel.daddr.a6,
  101. (struct in6_addr *)daddr);
  102. ipv6_addr_copy((struct in6_addr *)x0->sel.saddr.a6,
  103. (struct in6_addr *)saddr);
  104. x0->sel.prefixlen_d = 128;
  105. x0->sel.prefixlen_s = 128;
  106. ipv6_addr_copy((struct in6_addr *)x0->props.saddr.a6,
  107. (struct in6_addr *)saddr);
  108. x0->km.state = XFRM_STATE_ACQ;
  109. ipv6_addr_copy((struct in6_addr *)x0->id.daddr.a6,
  110. (struct in6_addr *)daddr);
  111. x0->id.proto = proto;
  112. x0->props.family = AF_INET6;
  113. x0->props.mode = mode;
  114. x0->props.reqid = reqid;
  115. x0->lft.hard_add_expires_seconds = XFRM_ACQ_EXPIRES;
  116. xfrm_state_hold(x0);
  117. x0->timer.expires = jiffies + XFRM_ACQ_EXPIRES*HZ;
  118. add_timer(&x0->timer);
  119. xfrm_state_hold(x0);
  120. list_add_tail(&x0->bydst, xfrm6_state_afinfo.state_bydst+h);
  121. wake_up(&km_waitq);
  122. }
  123. if (x0)
  124. xfrm_state_hold(x0);
  125. return x0;
  126. }
  127. static struct xfrm_state_afinfo xfrm6_state_afinfo = {
  128. .family = AF_INET6,
  129. .lock = RW_LOCK_UNLOCKED,
  130. .init_tempsel = __xfrm6_init_tempsel,
  131. .state_lookup = __xfrm6_state_lookup,
  132. .find_acq = __xfrm6_find_acq,
  133. };
  134. void __init xfrm6_state_init(void)
  135. {
  136. xfrm_state_register_afinfo(&xfrm6_state_afinfo);
  137. }
  138. void xfrm6_state_fini(void)
  139. {
  140. xfrm_state_unregister_afinfo(&xfrm6_state_afinfo);
  141. }