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 14 #include <net/xfrm.h> 15 #include <linux/pfkeyv2.h> 16 #include <linux/ipsec.h> 17 #include <net/ipv6.h> 18 #include <net/addrconf.h> 19 20 static struct xfrm_state_afinfo xfrm6_state_afinfo; 21 22 static void 23 __xfrm6_init_tempsel(struct xfrm_state *x, struct flowi *fl, 24 struct xfrm_tmpl *tmpl, 25 xfrm_address_t *daddr, xfrm_address_t *saddr) 26 { 27 /* Initialize temporary selector matching only 28 * to current session. */ 29 ipv6_addr_copy((struct in6_addr *)&x->sel.daddr, &fl->fl6_dst); 30 ipv6_addr_copy((struct in6_addr *)&x->sel.saddr, &fl->fl6_src); 31 x->sel.dport = xfrm_flowi_dport(fl); 32 x->sel.dport_mask = ~0; 33 x->sel.sport = xfrm_flowi_sport(fl); 34 x->sel.sport_mask = ~0; 35 x->sel.prefixlen_d = 128; 36 x->sel.prefixlen_s = 128; 37 x->sel.proto = fl->proto; 38 x->sel.ifindex = fl->oif; 39 x->id = tmpl->id; 40 if (ipv6_addr_any((struct in6_addr*)&x->id.daddr)) 41 memcpy(&x->id.daddr, daddr, sizeof(x->sel.daddr)); 42 memcpy(&x->props.saddr, &tmpl->saddr, sizeof(x->props.saddr)); 43 if (ipv6_addr_any((struct in6_addr*)&x->props.saddr)) 44 memcpy(&x->props.saddr, saddr, sizeof(x->props.saddr)); 45 if (tmpl->mode && ipv6_addr_any((struct in6_addr*)&x->props.saddr)) { 46 struct rt6_info *rt; 47 struct flowi fl_tunnel = { 48 .nl_u = { 49 .ip6_u = { 50 .daddr = *(struct in6_addr *)daddr, 51 } 52 } 53 }; 54 if (!xfrm_dst_lookup((struct xfrm_dst **)&rt, 55 &fl_tunnel, AF_INET6)) { 56 ipv6_get_saddr(&rt->u.dst, (struct in6_addr *)daddr, 57 (struct in6_addr *)&x->props.saddr); 58 dst_release(&rt->u.dst); 59 } 60 } 61 x->props.mode = tmpl->mode; 62 x->props.reqid = tmpl->reqid; 63 x->props.family = AF_INET6; 64 } 65 66 static struct xfrm_state * 67 __xfrm6_state_lookup(xfrm_address_t *daddr, u32 spi, u8 proto) 68 { 69 unsigned h = __xfrm6_spi_hash(daddr, spi, proto); 70 struct xfrm_state *x; 71 72 list_for_each_entry(x, xfrm6_state_afinfo.state_byspi+h, byspi) { 73 if (x->props.family == AF_INET6 && 74 spi == x->id.spi && 75 ipv6_addr_equal((struct in6_addr *)daddr, (struct in6_addr *)x->id.daddr.a6) && 76 proto == x->id.proto) { 77 xfrm_state_hold(x); 78 return x; 79 } 80 } 81 return NULL; 82 } 83 84 static struct xfrm_state * 85 __xfrm6_find_acq(u8 mode, u32 reqid, u8 proto, 86 xfrm_address_t *daddr, xfrm_address_t *saddr, 87 int create) 88 { 89 struct xfrm_state *x, *x0; 90 unsigned h = __xfrm6_dst_hash(daddr); 91 92 x0 = NULL; 93 94 list_for_each_entry(x, xfrm6_state_afinfo.state_bydst+h, bydst) { 95 if (x->props.family == AF_INET6 && 96 ipv6_addr_equal((struct in6_addr *)daddr, (struct in6_addr *)x->id.daddr.a6) && 97 mode == x->props.mode && 98 proto == x->id.proto && 99 ipv6_addr_equal((struct in6_addr *)saddr, (struct in6_addr *)x->props.saddr.a6) && 100 reqid == x->props.reqid && 101 x->km.state == XFRM_STATE_ACQ && 102 !x->id.spi) { 103 x0 = x; 104 break; 105 } 106 } 107 if (!x0 && create && (x0 = xfrm_state_alloc()) != NULL) { 108 ipv6_addr_copy((struct in6_addr *)x0->sel.daddr.a6, 109 (struct in6_addr *)daddr); 110 ipv6_addr_copy((struct in6_addr *)x0->sel.saddr.a6, 111 (struct in6_addr *)saddr); 112 x0->sel.prefixlen_d = 128; 113 x0->sel.prefixlen_s = 128; 114 ipv6_addr_copy((struct in6_addr *)x0->props.saddr.a6, 115 (struct in6_addr *)saddr); 116 x0->km.state = XFRM_STATE_ACQ; 117 ipv6_addr_copy((struct in6_addr *)x0->id.daddr.a6, 118 (struct in6_addr *)daddr); 119 x0->id.proto = proto; 120 x0->props.family = AF_INET6; 121 x0->props.mode = mode; 122 x0->props.reqid = reqid; 123 x0->lft.hard_add_expires_seconds = XFRM_ACQ_EXPIRES; 124 xfrm_state_hold(x0); 125 x0->timer.expires = jiffies + XFRM_ACQ_EXPIRES*HZ; 126 add_timer(&x0->timer); 127 xfrm_state_hold(x0); 128 list_add_tail(&x0->bydst, xfrm6_state_afinfo.state_bydst+h); 129 wake_up(&km_waitq); 130 } 131 if (x0) 132 xfrm_state_hold(x0); 133 return x0; 134 } 135 136 static struct xfrm_state_afinfo xfrm6_state_afinfo = { 137 .family = AF_INET6, 138 .init_tempsel = __xfrm6_init_tempsel, 139 .state_lookup = __xfrm6_state_lookup, 140 .find_acq = __xfrm6_find_acq, 141 }; 142 143 void __init xfrm6_state_init(void) 144 { 145 xfrm_state_register_afinfo(&xfrm6_state_afinfo); 146 } 147 148 void xfrm6_state_fini(void) 149 { 150 xfrm_state_unregister_afinfo(&xfrm6_state_afinfo); 151 } 152 153