aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv6/xfrm6_state.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/ipv6/xfrm6_state.c')
-rw-r--r--net/ipv6/xfrm6_state.c189
1 files changed, 111 insertions, 78 deletions
diff --git a/net/ipv6/xfrm6_state.c b/net/ipv6/xfrm6_state.c
index b33296b3f6de..711bfafb2472 100644
--- a/net/ipv6/xfrm6_state.c
+++ b/net/ipv6/xfrm6_state.c
@@ -42,102 +42,135 @@ __xfrm6_init_tempsel(struct xfrm_state *x, struct flowi *fl,
42 memcpy(&x->props.saddr, &tmpl->saddr, sizeof(x->props.saddr)); 42 memcpy(&x->props.saddr, &tmpl->saddr, sizeof(x->props.saddr));
43 if (ipv6_addr_any((struct in6_addr*)&x->props.saddr)) 43 if (ipv6_addr_any((struct in6_addr*)&x->props.saddr))
44 memcpy(&x->props.saddr, saddr, sizeof(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; 45 x->props.mode = tmpl->mode;
62 x->props.reqid = tmpl->reqid; 46 x->props.reqid = tmpl->reqid;
63 x->props.family = AF_INET6; 47 x->props.family = AF_INET6;
64} 48}
65 49
66static struct xfrm_state * 50static int
67__xfrm6_state_lookup(xfrm_address_t *daddr, u32 spi, u8 proto) 51__xfrm6_state_sort(struct xfrm_state **dst, struct xfrm_state **src, int n)
68{ 52{
69 unsigned h = __xfrm6_spi_hash(daddr, spi, proto); 53 int i;
70 struct xfrm_state *x; 54 int j = 0;
71 55
72 list_for_each_entry(x, xfrm6_state_afinfo.state_byspi+h, byspi) { 56 /* Rule 1: select IPsec transport except AH */
73 if (x->props.family == AF_INET6 && 57 for (i = 0; i < n; i++) {
74 spi == x->id.spi && 58 if (src[i]->props.mode == XFRM_MODE_TRANSPORT &&
75 ipv6_addr_equal((struct in6_addr *)daddr, (struct in6_addr *)x->id.daddr.a6) && 59 src[i]->id.proto != IPPROTO_AH) {
76 proto == x->id.proto) { 60 dst[j++] = src[i];
77 xfrm_state_hold(x); 61 src[i] = NULL;
78 return x; 62 }
63 }
64 if (j == n)
65 goto end;
66
67 /* Rule 2: select MIPv6 RO or inbound trigger */
68#ifdef CONFIG_IPV6_MIP6
69 for (i = 0; i < n; i++) {
70 if (src[i] &&
71 (src[i]->props.mode == XFRM_MODE_ROUTEOPTIMIZATION ||
72 src[i]->props.mode == XFRM_MODE_IN_TRIGGER)) {
73 dst[j++] = src[i];
74 src[i] = NULL;
75 }
76 }
77 if (j == n)
78 goto end;
79#endif
80
81 /* Rule 3: select IPsec transport AH */
82 for (i = 0; i < n; i++) {
83 if (src[i] &&
84 src[i]->props.mode == XFRM_MODE_TRANSPORT &&
85 src[i]->id.proto == IPPROTO_AH) {
86 dst[j++] = src[i];
87 src[i] = NULL;
79 } 88 }
80 } 89 }
81 return NULL; 90 if (j == n)
91 goto end;
92
93 /* Rule 4: select IPsec tunnel */
94 for (i = 0; i < n; i++) {
95 if (src[i] &&
96 src[i]->props.mode == XFRM_MODE_TUNNEL) {
97 dst[j++] = src[i];
98 src[i] = NULL;
99 }
100 }
101 if (likely(j == n))
102 goto end;
103
104 /* Final rule */
105 for (i = 0; i < n; i++) {
106 if (src[i]) {
107 dst[j++] = src[i];
108 src[i] = NULL;
109 }
110 }
111
112 end:
113 return 0;
82} 114}
83 115
84static struct xfrm_state * 116static int
85__xfrm6_find_acq(u8 mode, u32 reqid, u8 proto, 117__xfrm6_tmpl_sort(struct xfrm_tmpl **dst, struct xfrm_tmpl **src, int n)
86 xfrm_address_t *daddr, xfrm_address_t *saddr,
87 int create)
88{ 118{
89 struct xfrm_state *x, *x0; 119 int i;
90 unsigned h = __xfrm6_dst_hash(daddr); 120 int j = 0;
91 121
92 x0 = NULL; 122 /* Rule 1: select IPsec transport */
93 123 for (i = 0; i < n; i++) {
94 list_for_each_entry(x, xfrm6_state_afinfo.state_bydst+h, bydst) { 124 if (src[i]->mode == XFRM_MODE_TRANSPORT) {
95 if (x->props.family == AF_INET6 && 125 dst[j++] = src[i];
96 ipv6_addr_equal((struct in6_addr *)daddr, (struct in6_addr *)x->id.daddr.a6) && 126 src[i] = NULL;
97 mode == x->props.mode && 127 }
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 } 128 }
107 if (!x0 && create && (x0 = xfrm_state_alloc()) != NULL) { 129 if (j == n)
108 ipv6_addr_copy((struct in6_addr *)x0->sel.daddr.a6, 130 goto end;
109 (struct in6_addr *)daddr); 131
110 ipv6_addr_copy((struct in6_addr *)x0->sel.saddr.a6, 132 /* Rule 2: select MIPv6 RO or inbound trigger */
111 (struct in6_addr *)saddr); 133#ifdef CONFIG_IPV6_MIP6
112 x0->sel.prefixlen_d = 128; 134 for (i = 0; i < n; i++) {
113 x0->sel.prefixlen_s = 128; 135 if (src[i] &&
114 ipv6_addr_copy((struct in6_addr *)x0->props.saddr.a6, 136 (src[i]->mode == XFRM_MODE_ROUTEOPTIMIZATION ||
115 (struct in6_addr *)saddr); 137 src[i]->mode == XFRM_MODE_IN_TRIGGER)) {
116 x0->km.state = XFRM_STATE_ACQ; 138 dst[j++] = src[i];
117 ipv6_addr_copy((struct in6_addr *)x0->id.daddr.a6, 139 src[i] = NULL;
118 (struct in6_addr *)daddr); 140 }
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 } 141 }
131 if (x0) 142 if (j == n)
132 xfrm_state_hold(x0); 143 goto end;
133 return x0; 144#endif
145
146 /* Rule 3: select IPsec tunnel */
147 for (i = 0; i < n; i++) {
148 if (src[i] &&
149 src[i]->mode == XFRM_MODE_TUNNEL) {
150 dst[j++] = src[i];
151 src[i] = NULL;
152 }
153 }
154 if (likely(j == n))
155 goto end;
156
157 /* Final rule */
158 for (i = 0; i < n; i++) {
159 if (src[i]) {
160 dst[j++] = src[i];
161 src[i] = NULL;
162 }
163 }
164
165 end:
166 return 0;
134} 167}
135 168
136static struct xfrm_state_afinfo xfrm6_state_afinfo = { 169static struct xfrm_state_afinfo xfrm6_state_afinfo = {
137 .family = AF_INET6, 170 .family = AF_INET6,
138 .init_tempsel = __xfrm6_init_tempsel, 171 .init_tempsel = __xfrm6_init_tempsel,
139 .state_lookup = __xfrm6_state_lookup, 172 .tmpl_sort = __xfrm6_tmpl_sort,
140 .find_acq = __xfrm6_find_acq, 173 .state_sort = __xfrm6_state_sort,
141}; 174};
142 175
143void __init xfrm6_state_init(void) 176void __init xfrm6_state_init(void)