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