1 /* 2 * xfrm4_state.c 3 * 4 * Changes: 5 * YOSHIFUJI Hideaki @USAGI 6 * Split up af-specific portion 7 * 8 */ 9 10 #include <net/ip.h> 11 #include <net/xfrm.h> 12 #include <linux/pfkeyv2.h> 13 #include <linux/ipsec.h> 14 15 static struct xfrm_state_afinfo xfrm4_state_afinfo; 16 17 static int xfrm4_init_flags(struct xfrm_state *x) 18 { 19 if (ipv4_config.no_pmtu_disc) 20 x->props.flags |= XFRM_STATE_NOPMTUDISC; 21 return 0; 22 } 23 24 static void 25 __xfrm4_init_tempsel(struct xfrm_state *x, struct flowi *fl, 26 struct xfrm_tmpl *tmpl, 27 xfrm_address_t *daddr, xfrm_address_t *saddr) 28 { 29 x->sel.daddr.a4 = fl->fl4_dst; 30 x->sel.saddr.a4 = fl->fl4_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 = 32; 36 x->sel.prefixlen_s = 32; 37 x->sel.proto = fl->proto; 38 x->sel.ifindex = fl->oif; 39 x->id = tmpl->id; 40 if (x->id.daddr.a4 == 0) 41 x->id.daddr.a4 = daddr->a4; 42 x->props.saddr = tmpl->saddr; 43 if (x->props.saddr.a4 == 0) 44 x->props.saddr.a4 = saddr->a4; 45 if (tmpl->mode && x->props.saddr.a4 == 0) { 46 struct rtable *rt; 47 struct flowi fl_tunnel = { 48 .nl_u = { 49 .ip4_u = { 50 .daddr = x->id.daddr.a4, 51 } 52 } 53 }; 54 if (!xfrm_dst_lookup((struct xfrm_dst **)&rt, 55 &fl_tunnel, AF_INET)) { 56 x->props.saddr.a4 = rt->rt_src; 57 dst_release(&rt->u.dst); 58 } 59 } 60 x->props.mode = tmpl->mode; 61 x->props.reqid = tmpl->reqid; 62 x->props.family = AF_INET; 63 } 64 65 static struct xfrm_state * 66 __xfrm4_state_lookup(xfrm_address_t *daddr, u32 spi, u8 proto) 67 { 68 unsigned h = __xfrm4_spi_hash(daddr, spi, proto); 69 struct xfrm_state *x; 70 71 list_for_each_entry(x, xfrm4_state_afinfo.state_byspi+h, byspi) { 72 if (x->props.family == AF_INET && 73 spi == x->id.spi && 74 daddr->a4 == x->id.daddr.a4 && 75 proto == x->id.proto) { 76 xfrm_state_hold(x); 77 return x; 78 } 79 } 80 return NULL; 81 } 82 83 static struct xfrm_state * 84 __xfrm4_find_acq(u8 mode, u32 reqid, u8 proto, 85 xfrm_address_t *daddr, xfrm_address_t *saddr, 86 int create) 87 { 88 struct xfrm_state *x, *x0; 89 unsigned h = __xfrm4_dst_hash(daddr); 90 91 x0 = NULL; 92 93 list_for_each_entry(x, xfrm4_state_afinfo.state_bydst+h, bydst) { 94 if (x->props.family == AF_INET && 95 daddr->a4 == x->id.daddr.a4 && 96 mode == x->props.mode && 97 proto == x->id.proto && 98 saddr->a4 == x->props.saddr.a4 && 99 reqid == x->props.reqid && 100 x->km.state == XFRM_STATE_ACQ && 101 !x->id.spi) { 102 x0 = x; 103 break; 104 } 105 } 106 if (!x0 && create && (x0 = xfrm_state_alloc()) != NULL) { 107 x0->sel.daddr.a4 = daddr->a4; 108 x0->sel.saddr.a4 = saddr->a4; 109 x0->sel.prefixlen_d = 32; 110 x0->sel.prefixlen_s = 32; 111 x0->props.saddr.a4 = saddr->a4; 112 x0->km.state = XFRM_STATE_ACQ; 113 x0->id.daddr.a4 = daddr->a4; 114 x0->id.proto = proto; 115 x0->props.family = AF_INET; 116 x0->props.mode = mode; 117 x0->props.reqid = reqid; 118 x0->props.family = AF_INET; 119 x0->lft.hard_add_expires_seconds = XFRM_ACQ_EXPIRES; 120 xfrm_state_hold(x0); 121 x0->timer.expires = jiffies + XFRM_ACQ_EXPIRES*HZ; 122 add_timer(&x0->timer); 123 xfrm_state_hold(x0); 124 list_add_tail(&x0->bydst, xfrm4_state_afinfo.state_bydst+h); 125 wake_up(&km_waitq); 126 } 127 if (x0) 128 xfrm_state_hold(x0); 129 return x0; 130 } 131 132 static struct xfrm_state_afinfo xfrm4_state_afinfo = { 133 .family = AF_INET, 134 .init_flags = xfrm4_init_flags, 135 .init_tempsel = __xfrm4_init_tempsel, 136 .state_lookup = __xfrm4_state_lookup, 137 .find_acq = __xfrm4_find_acq, 138 }; 139 140 void __init xfrm4_state_init(void) 141 { 142 xfrm_state_register_afinfo(&xfrm4_state_afinfo); 143 } 144 145 #if 0 146 void __exit xfrm4_state_fini(void) 147 { 148 xfrm_state_unregister_afinfo(&xfrm4_state_afinfo); 149 } 150 #endif /* 0 */ 151 152