1 /* 2 * xfrm4_state.c 3 * 4 * Changes: 5 * YOSHIFUJI Hideaki @USAGI 6 * Split up af-specific portion 7 * 8 */ 9 10 #include <net/xfrm.h> 11 #include <linux/pfkeyv2.h> 12 #include <linux/ipsec.h> 13 14 static struct xfrm_state_afinfo xfrm4_state_afinfo; 15 16 static void 17 __xfrm4_init_tempsel(struct xfrm_state *x, struct flowi *fl, 18 struct xfrm_tmpl *tmpl, 19 xfrm_address_t *daddr, xfrm_address_t *saddr) 20 { 21 x->sel.daddr.a4 = fl->fl4_dst; 22 x->sel.saddr.a4 = fl->fl4_src; 23 x->sel.dport = xfrm_flowi_dport(fl); 24 x->sel.dport_mask = ~0; 25 x->sel.sport = xfrm_flowi_sport(fl); 26 x->sel.sport_mask = ~0; 27 x->sel.prefixlen_d = 32; 28 x->sel.prefixlen_s = 32; 29 x->sel.proto = fl->proto; 30 x->sel.ifindex = fl->oif; 31 x->id = tmpl->id; 32 if (x->id.daddr.a4 == 0) 33 x->id.daddr.a4 = daddr->a4; 34 x->props.saddr = tmpl->saddr; 35 if (x->props.saddr.a4 == 0) 36 x->props.saddr.a4 = saddr->a4; 37 x->props.mode = tmpl->mode; 38 x->props.reqid = tmpl->reqid; 39 x->props.family = AF_INET; 40 } 41 42 static struct xfrm_state * 43 __xfrm4_state_lookup(xfrm_address_t *daddr, u32 spi, u8 proto) 44 { 45 unsigned h = __xfrm4_spi_hash(daddr, spi, proto); 46 struct xfrm_state *x; 47 48 list_for_each_entry(x, xfrm4_state_afinfo.state_byspi+h, byspi) { 49 if (x->props.family == AF_INET && 50 spi == x->id.spi && 51 daddr->a4 == x->id.daddr.a4 && 52 proto == x->id.proto) { 53 xfrm_state_hold(x); 54 return x; 55 } 56 } 57 return NULL; 58 } 59 60 static struct xfrm_state * 61 __xfrm4_find_acq(u8 mode, u32 reqid, u8 proto, 62 xfrm_address_t *daddr, xfrm_address_t *saddr, 63 int create) 64 { 65 struct xfrm_state *x, *x0; 66 unsigned h = __xfrm4_dst_hash(daddr); 67 68 x0 = NULL; 69 70 list_for_each_entry(x, xfrm4_state_afinfo.state_bydst+h, bydst) { 71 if (x->props.family == AF_INET && 72 daddr->a4 == x->id.daddr.a4 && 73 mode == x->props.mode && 74 proto == x->id.proto && 75 saddr->a4 == x->props.saddr.a4 && 76 reqid == x->props.reqid && 77 x->km.state == XFRM_STATE_ACQ && 78 !x->id.spi) { 79 x0 = x; 80 break; 81 } 82 } 83 if (!x0 && create && (x0 = xfrm_state_alloc()) != NULL) { 84 x0->sel.daddr.a4 = daddr->a4; 85 x0->sel.saddr.a4 = saddr->a4; 86 x0->sel.prefixlen_d = 32; 87 x0->sel.prefixlen_s = 32; 88 x0->props.saddr.a4 = saddr->a4; 89 x0->km.state = XFRM_STATE_ACQ; 90 x0->id.daddr.a4 = daddr->a4; 91 x0->id.proto = proto; 92 x0->props.family = AF_INET; 93 x0->props.mode = mode; 94 x0->props.reqid = reqid; 95 x0->props.family = AF_INET; 96 x0->lft.hard_add_expires_seconds = XFRM_ACQ_EXPIRES; 97 xfrm_state_hold(x0); 98 x0->timer.expires = jiffies + XFRM_ACQ_EXPIRES*HZ; 99 add_timer(&x0->timer); 100 xfrm_state_hold(x0); 101 list_add_tail(&x0->bydst, xfrm4_state_afinfo.state_bydst+h); 102 wake_up(&km_waitq); 103 } 104 if (x0) 105 xfrm_state_hold(x0); 106 return x0; 107 } 108 109 static struct xfrm_state_afinfo xfrm4_state_afinfo = { 110 .family = AF_INET, 111 .lock = RW_LOCK_UNLOCKED, 112 .init_tempsel = __xfrm4_init_tempsel, 113 .state_lookup = __xfrm4_state_lookup, 114 .find_acq = __xfrm4_find_acq, 115 }; 116 117 void __init xfrm4_state_init(void) 118 { 119 xfrm_state_register_afinfo(&xfrm4_state_afinfo); 120 } 121 122 void __exit xfrm4_state_fini(void) 123 { 124 xfrm_state_unregister_afinfo(&xfrm4_state_afinfo); 125 } 126 127