Blame view
net/xfrm/xfrm_policy.c
106 KB
457c89965 treewide: Add SPD... |
1 |
// SPDX-License-Identifier: GPL-2.0-only |
a716c1197 [NET] XFRM: Fix w... |
2 |
/* |
1da177e4c Linux-2.6.12-rc2 |
3 4 5 6 7 8 9 10 11 12 13 |
* xfrm_policy.c * * Changes: * Mitsuru KANDA @USAGI * Kazunori MIYAZAWA @USAGI * Kunihiro Ishiguro <kunihiro@ipinfusion.com> * IPv6 support * Kazunori MIYAZAWA @USAGI * YOSHIFUJI Hideaki * Split up af-specific portion * Derek Atkins <derek@ihtfp.com> Add the post_input processor |
df71837d5 [LSM-IPSec]: Secu... |
14 |
* |
1da177e4c Linux-2.6.12-rc2 |
15 |
*/ |
66cdb3ca2 [IPSEC]: Move flo... |
16 |
#include <linux/err.h> |
1da177e4c Linux-2.6.12-rc2 |
17 18 19 20 21 22 23 |
#include <linux/slab.h> #include <linux/kmod.h> #include <linux/list.h> #include <linux/spinlock.h> #include <linux/workqueue.h> #include <linux/notifier.h> #include <linux/netdevice.h> |
eb9c7ebe6 [NETFILTER]: Hand... |
24 |
#include <linux/netfilter.h> |
1da177e4c Linux-2.6.12-rc2 |
25 |
#include <linux/module.h> |
2518c7c2b [XFRM]: Hash poli... |
26 |
#include <linux/cache.h> |
ec30d78c1 xfrm: add xdst pc... |
27 |
#include <linux/cpu.h> |
68277accb [XFRM]: Assorted ... |
28 |
#include <linux/audit.h> |
24969facd xfrm: policy: sto... |
29 |
#include <linux/rhashtable.h> |
c53ac41e3 xfrm: remove deco... |
30 |
#include <linux/if_tunnel.h> |
25ee3286d [IPSEC]: Merge co... |
31 |
#include <net/dst.h> |
6ce74ec75 SELinux: include ... |
32 |
#include <net/flow.h> |
1da177e4c Linux-2.6.12-rc2 |
33 34 |
#include <net/xfrm.h> #include <net/ip.h> |
c53ac41e3 xfrm: remove deco... |
35 36 37 |
#if IS_ENABLED(CONFIG_IPV6_MIP6) #include <net/mip6.h> #endif |
558f82ef6 [XFRM]: Define pa... |
38 39 40 |
#ifdef CONFIG_XFRM_STATISTICS #include <net/snmp.h> #endif |
95a35b42b xfrm: policy: fix... |
41 |
#ifdef CONFIG_XFRM_ESPINTCP |
e27cca96c xfrm: add espintc... |
42 43 |
#include <net/espintcp.h> #endif |
1da177e4c Linux-2.6.12-rc2 |
44 |
|
44e36b42a [XFRM]: Extract c... |
45 |
#include "xfrm_hash.h" |
a0073fe18 xfrm: Add a state... |
46 47 48 |
#define XFRM_QUEUE_TMO_MIN ((unsigned)(HZ/10)) #define XFRM_QUEUE_TMO_MAX ((unsigned)(60*HZ)) #define XFRM_MAX_QUEUE_LEN 100 |
b8c203b2d xfrm: Generate qu... |
49 50 51 52 |
struct xfrm_flo { struct dst_entry *dst_orig; u8 flags; }; |
6be3b0db6 xfrm: policy: add... |
53 54 55 |
/* prefixes smaller than this are stored in lists, not trees. */ #define INEXACT_PREFIXLEN_IPV4 16 #define INEXACT_PREFIXLEN_IPV6 48 |
9cf545ebd xfrm: policy: sto... |
56 57 58 59 60 61 62 63 |
struct xfrm_pol_inexact_node { struct rb_node node; union { xfrm_address_t addr; struct rcu_head rcu; }; u8 prefixlen; |
6ac098b2a xfrm: policy: add... |
64 |
struct rb_root root; |
9cf545ebd xfrm: policy: sto... |
65 66 67 68 69 70 71 72 73 74 75 |
/* the policies matching this node, can be empty list */ struct hlist_head hhead; }; /* xfrm inexact policy search tree: * xfrm_pol_inexact_bin = hash(dir,type,family,if_id); * | * +---- root_d: sorted by daddr:prefix * | | * | xfrm_pol_inexact_node * | | |
6ac098b2a xfrm: policy: add... |
76 77 78 79 80 81 82 83 |
* | +- root: sorted by saddr/prefix * | | | * | | xfrm_pol_inexact_node * | | | * | | + root: unused * | | | * | | + hhead: saddr:daddr policies * | | |
9cf545ebd xfrm: policy: sto... |
84 85 |
* | +- coarse policies and all any:daddr policies * | |
64a09a7bf xfrm: policy: sto... |
86 87 88 89 90 91 92 93 |
* +---- root_s: sorted by saddr:prefix * | | * | xfrm_pol_inexact_node * | | * | + root: unused * | | * | + hhead: saddr:any policies * | |
9cf545ebd xfrm: policy: sto... |
94 95 |
* +---- coarse policies and all any:any policies * |
6ac098b2a xfrm: policy: add... |
96 |
* Lookups return four candidate lists: |
9cf545ebd xfrm: policy: sto... |
97 98 |
* 1. any:any list from top-level xfrm_pol_inexact_bin * 2. any:daddr list from daddr tree |
6ac098b2a xfrm: policy: add... |
99 100 |
* 3. saddr:daddr list from 2nd level daddr tree * 4. saddr:any list from saddr tree |
9cf545ebd xfrm: policy: sto... |
101 102 103 104 |
* * This result set then needs to be searched for the policy with * the lowest priority. If two results have same prio, youngest one wins. */ |
24969facd xfrm: policy: sto... |
105 106 |
struct xfrm_pol_inexact_key { possible_net_t net; |
b5fe22e23 xfrm: policy: con... |
107 |
u32 if_id; |
24969facd xfrm: policy: sto... |
108 109 110 111 112 113 114 |
u16 family; u8 dir, type; }; struct xfrm_pol_inexact_bin { struct xfrm_pol_inexact_key k; struct rhash_head head; |
6be3b0db6 xfrm: policy: add... |
115 |
/* list containing '*:*' policies */ |
24969facd xfrm: policy: sto... |
116 |
struct hlist_head hhead; |
77cc278f7 xfrm: policy: Use... |
117 |
seqcount_spinlock_t count; |
9cf545ebd xfrm: policy: sto... |
118 119 |
/* tree sorted by daddr/prefix */ struct rb_root root_d; |
64a09a7bf xfrm: policy: sto... |
120 121 |
/* tree sorted by saddr/prefix */ struct rb_root root_s; |
24969facd xfrm: policy: sto... |
122 123 124 125 |
/* slow path below */ struct list_head inexact_bins; struct rcu_head rcu; }; |
6be3b0db6 xfrm: policy: add... |
126 |
enum xfrm_pol_inexact_candidate_type { |
6ac098b2a xfrm: policy: add... |
127 |
XFRM_POL_CAND_BOTH, |
64a09a7bf xfrm: policy: sto... |
128 |
XFRM_POL_CAND_SADDR, |
9cf545ebd xfrm: policy: sto... |
129 |
XFRM_POL_CAND_DADDR, |
6be3b0db6 xfrm: policy: add... |
130 131 132 133 134 135 136 137 |
XFRM_POL_CAND_ANY, XFRM_POL_CAND_MAX, }; struct xfrm_pol_inexact_candidates { struct hlist_head *res[XFRM_POL_CAND_MAX]; }; |
f203b76d7 xfrm: Add virtual... |
138 139 |
static DEFINE_SPINLOCK(xfrm_if_cb_lock); static struct xfrm_if_cb const __rcu *xfrm_if_cb __read_mostly; |
418a99ac6 Replace rwlock on... |
140 |
static DEFINE_SPINLOCK(xfrm_policy_afinfo_lock); |
37b103830 xfrm: policy: mak... |
141 |
static struct xfrm_policy_afinfo const __rcu *xfrm_policy_afinfo[AF_INET6 + 1] |
418a99ac6 Replace rwlock on... |
142 |
__read_mostly; |
1da177e4c Linux-2.6.12-rc2 |
143 |
|
f8c3d0dda xfrm: mark kmem_c... |
144 |
static struct kmem_cache *xfrm_dst_cache __ro_after_init; |
77cc278f7 xfrm: policy: Use... |
145 |
static __read_mostly seqcount_mutex_t xfrm_policy_hash_generation; |
1da177e4c Linux-2.6.12-rc2 |
146 |
|
24969facd xfrm: policy: sto... |
147 148 |
static struct rhashtable xfrm_policy_inexact_table; static const struct rhashtable_params xfrm_pol_inexact_params; |
5492093dc xfrm: Stop using ... |
149 |
static void xfrm_init_pmtu(struct xfrm_dst **bundle, int nr); |
80c802f30 xfrm: cache bundl... |
150 |
static int stale_bundle(struct dst_entry *dst); |
12fdb4d3b xfrm: Remove fami... |
151 |
static int xfrm_bundle_ok(struct xfrm_dst *xdst); |
c3aed7095 xfrm: Convert tim... |
152 |
static void xfrm_policy_queue_process(struct timer_list *t); |
1da177e4c Linux-2.6.12-rc2 |
153 |
|
12bfa8bdb xfrm: Use __xfrm_... |
154 |
static void __xfrm_policy_link(struct xfrm_policy *pol, int dir); |
29fa0b301 xfrm: Cleanup for... |
155 156 |
static struct xfrm_policy *__xfrm_policy_unlink(struct xfrm_policy *pol, int dir); |
24969facd xfrm: policy: sto... |
157 |
static struct xfrm_pol_inexact_bin * |
b5fe22e23 xfrm: policy: con... |
158 159 |
xfrm_policy_inexact_lookup(struct net *net, u8 type, u16 family, u8 dir, u32 if_id); |
24969facd xfrm: policy: sto... |
160 161 162 |
static struct xfrm_pol_inexact_bin * xfrm_policy_inexact_lookup_rcu(struct net *net, |
b5fe22e23 xfrm: policy: con... |
163 |
u8 type, u16 family, u8 dir, u32 if_id); |
24969facd xfrm: policy: sto... |
164 165 166 167 168 |
static struct xfrm_policy * xfrm_policy_insert_list(struct hlist_head *chain, struct xfrm_policy *policy, bool excl); static void xfrm_policy_insert_inexact_list(struct hlist_head *chain, struct xfrm_policy *policy); |
6be3b0db6 xfrm: policy: add... |
169 170 171 172 173 |
static bool xfrm_policy_find_inexact_candidates(struct xfrm_pol_inexact_candidates *cand, struct xfrm_pol_inexact_bin *b, const xfrm_address_t *saddr, const xfrm_address_t *daddr); |
e37cc8ade xfrm: policy: use... |
174 175 |
static inline bool xfrm_pol_hold_rcu(struct xfrm_policy *policy) { |
850a6212c net, xfrm: conver... |
176 |
return refcount_inc_not_zero(&policy->refcnt); |
e37cc8ade xfrm: policy: use... |
177 |
} |
bc9b35ad4 xfrm: Convert sev... |
178 |
static inline bool |
200ce96e5 xfrm: Const'ify s... |
179 |
__xfrm4_selector_match(const struct xfrm_selector *sel, const struct flowi *fl) |
776810217 [XFRM]: uninline ... |
180 |
{ |
7e1dc7b6f net: Use flowi4 a... |
181 |
const struct flowi4 *fl4 = &fl->u.ip4; |
26bff940d xfrm: optimize ip... |
182 183 |
return addr4_match(fl4->daddr, sel->daddr.a4, sel->prefixlen_d) && addr4_match(fl4->saddr, sel->saddr.a4, sel->prefixlen_s) && |
7e1dc7b6f net: Use flowi4 a... |
184 185 186 187 |
!((xfrm_flowi_dport(fl, &fl4->uli) ^ sel->dport) & sel->dport_mask) && !((xfrm_flowi_sport(fl, &fl4->uli) ^ sel->sport) & sel->sport_mask) && (fl4->flowi4_proto == sel->proto || !sel->proto) && (fl4->flowi4_oif == sel->ifindex || !sel->ifindex); |
776810217 [XFRM]: uninline ... |
188 |
} |
bc9b35ad4 xfrm: Convert sev... |
189 |
static inline bool |
200ce96e5 xfrm: Const'ify s... |
190 |
__xfrm6_selector_match(const struct xfrm_selector *sel, const struct flowi *fl) |
776810217 [XFRM]: uninline ... |
191 |
{ |
7e1dc7b6f net: Use flowi4 a... |
192 193 194 195 196 197 198 199 |
const struct flowi6 *fl6 = &fl->u.ip6; return addr_match(&fl6->daddr, &sel->daddr, sel->prefixlen_d) && addr_match(&fl6->saddr, &sel->saddr, sel->prefixlen_s) && !((xfrm_flowi_dport(fl, &fl6->uli) ^ sel->dport) & sel->dport_mask) && !((xfrm_flowi_sport(fl, &fl6->uli) ^ sel->sport) & sel->sport_mask) && (fl6->flowi6_proto == sel->proto || !sel->proto) && (fl6->flowi6_oif == sel->ifindex || !sel->ifindex); |
776810217 [XFRM]: uninline ... |
200 |
} |
bc9b35ad4 xfrm: Convert sev... |
201 202 |
bool xfrm_selector_match(const struct xfrm_selector *sel, const struct flowi *fl, unsigned short family) |
776810217 [XFRM]: uninline ... |
203 204 205 206 207 208 209 |
{ switch (family) { case AF_INET: return __xfrm4_selector_match(sel, fl); case AF_INET6: return __xfrm6_selector_match(sel, fl); } |
bc9b35ad4 xfrm: Convert sev... |
210 |
return false; |
776810217 [XFRM]: uninline ... |
211 |
} |
a2817d8b2 xfrm: policy: rem... |
212 |
static const struct xfrm_policy_afinfo *xfrm_policy_get_afinfo(unsigned short family) |
ef8531b64 xfrm: fix RCU bugs |
213 |
{ |
a2817d8b2 xfrm: policy: rem... |
214 |
const struct xfrm_policy_afinfo *afinfo; |
ef8531b64 xfrm: fix RCU bugs |
215 |
|
a2817d8b2 xfrm: policy: rem... |
216 |
if (unlikely(family >= ARRAY_SIZE(xfrm_policy_afinfo))) |
ef8531b64 xfrm: fix RCU bugs |
217 218 219 220 221 222 223 |
return NULL; rcu_read_lock(); afinfo = rcu_dereference(xfrm_policy_afinfo[family]); if (unlikely(!afinfo)) rcu_read_unlock(); return afinfo; } |
f203b76d7 xfrm: Add virtual... |
224 225 226 227 228 |
/* Called with rcu_read_lock(). */ static const struct xfrm_if_cb *xfrm_if_get_cb(void) { return rcu_dereference(xfrm_if_cb); } |
d77e38e61 xfrm: Add an IPse... |
229 230 231 |
struct dst_entry *__xfrm_dst_lookup(struct net *net, int tos, int oif, const xfrm_address_t *saddr, const xfrm_address_t *daddr, |
077fbac40 net: xfrm: suppor... |
232 |
int family, u32 mark) |
9bb182a70 [XFRM] MIP6: Fix ... |
233 |
{ |
37b103830 xfrm: policy: mak... |
234 |
const struct xfrm_policy_afinfo *afinfo; |
9bb182a70 [XFRM] MIP6: Fix ... |
235 236 237 238 239 |
struct dst_entry *dst; afinfo = xfrm_policy_get_afinfo(family); if (unlikely(afinfo == NULL)) return ERR_PTR(-EAFNOSUPPORT); |
077fbac40 net: xfrm: suppor... |
240 |
dst = afinfo->dst_lookup(net, tos, oif, saddr, daddr, mark); |
9bb182a70 [XFRM] MIP6: Fix ... |
241 |
|
bdba9fe01 xfrm: policy: rem... |
242 |
rcu_read_unlock(); |
9bb182a70 [XFRM] MIP6: Fix ... |
243 244 245 |
return dst; } |
d77e38e61 xfrm: Add an IPse... |
246 |
EXPORT_SYMBOL(__xfrm_dst_lookup); |
9bb182a70 [XFRM] MIP6: Fix ... |
247 |
|
42a7b32b7 xfrm: Add oif to ... |
248 249 |
static inline struct dst_entry *xfrm_dst_lookup(struct xfrm_state *x, int tos, int oif, |
9bb182a70 [XFRM] MIP6: Fix ... |
250 251 |
xfrm_address_t *prev_saddr, xfrm_address_t *prev_daddr, |
077fbac40 net: xfrm: suppor... |
252 |
int family, u32 mark) |
1da177e4c Linux-2.6.12-rc2 |
253 |
{ |
c5b3cf46e netns xfrm: ->dst... |
254 |
struct net *net = xs_net(x); |
66cdb3ca2 [IPSEC]: Move flo... |
255 256 |
xfrm_address_t *saddr = &x->props.saddr; xfrm_address_t *daddr = &x->id.daddr; |
66cdb3ca2 [IPSEC]: Move flo... |
257 |
struct dst_entry *dst; |
9bb182a70 [XFRM] MIP6: Fix ... |
258 |
if (x->type->flags & XFRM_TYPE_LOCAL_COADDR) { |
66cdb3ca2 [IPSEC]: Move flo... |
259 |
saddr = x->coaddr; |
9bb182a70 [XFRM] MIP6: Fix ... |
260 261 262 263 |
daddr = prev_daddr; } if (x->type->flags & XFRM_TYPE_REMOTE_COADDR) { saddr = prev_saddr; |
66cdb3ca2 [IPSEC]: Move flo... |
264 |
daddr = x->coaddr; |
9bb182a70 [XFRM] MIP6: Fix ... |
265 |
} |
1da177e4c Linux-2.6.12-rc2 |
266 |
|
077fbac40 net: xfrm: suppor... |
267 |
dst = __xfrm_dst_lookup(net, tos, oif, saddr, daddr, family, mark); |
9bb182a70 [XFRM] MIP6: Fix ... |
268 269 270 271 272 273 274 |
if (!IS_ERR(dst)) { if (prev_saddr != saddr) memcpy(prev_saddr, saddr, sizeof(*prev_saddr)); if (prev_daddr != daddr) memcpy(prev_daddr, daddr, sizeof(*prev_daddr)); } |
1da177e4c Linux-2.6.12-rc2 |
275 |
|
66cdb3ca2 [IPSEC]: Move flo... |
276 |
return dst; |
1da177e4c Linux-2.6.12-rc2 |
277 |
} |
1da177e4c Linux-2.6.12-rc2 |
278 |
|
1da177e4c Linux-2.6.12-rc2 |
279 280 281 282 283 |
static inline unsigned long make_jiffies(long secs) { if (secs >= (MAX_SCHEDULE_TIMEOUT-1)/HZ) return MAX_SCHEDULE_TIMEOUT-1; else |
a716c1197 [NET] XFRM: Fix w... |
284 |
return secs*HZ; |
1da177e4c Linux-2.6.12-rc2 |
285 |
} |
c3aed7095 xfrm: Convert tim... |
286 |
static void xfrm_policy_timer(struct timer_list *t) |
1da177e4c Linux-2.6.12-rc2 |
287 |
{ |
c3aed7095 xfrm: Convert tim... |
288 |
struct xfrm_policy *xp = from_timer(xp, t, timer); |
386c5680e xfrm: use time64_... |
289 290 |
time64_t now = ktime_get_real_seconds(); time64_t next = TIME64_MAX; |
1da177e4c Linux-2.6.12-rc2 |
291 292 293 294 |
int warn = 0; int dir; read_lock(&xp->lock); |
ea2dea9da xfrm: remove poli... |
295 |
if (unlikely(xp->walk.dead)) |
1da177e4c Linux-2.6.12-rc2 |
296 |
goto out; |
77d8d7a68 [IPSEC]: Document... |
297 |
dir = xfrm_policy_id2dir(xp->index); |
1da177e4c Linux-2.6.12-rc2 |
298 299 |
if (xp->lft.hard_add_expires_seconds) { |
386c5680e xfrm: use time64_... |
300 |
time64_t tmo = xp->lft.hard_add_expires_seconds + |
1da177e4c Linux-2.6.12-rc2 |
301 302 303 304 305 306 307 |
xp->curlft.add_time - now; if (tmo <= 0) goto expired; if (tmo < next) next = tmo; } if (xp->lft.hard_use_expires_seconds) { |
386c5680e xfrm: use time64_... |
308 |
time64_t tmo = xp->lft.hard_use_expires_seconds + |
1da177e4c Linux-2.6.12-rc2 |
309 310 311 312 313 314 315 |
(xp->curlft.use_time ? : xp->curlft.add_time) - now; if (tmo <= 0) goto expired; if (tmo < next) next = tmo; } if (xp->lft.soft_add_expires_seconds) { |
386c5680e xfrm: use time64_... |
316 |
time64_t tmo = xp->lft.soft_add_expires_seconds + |
1da177e4c Linux-2.6.12-rc2 |
317 318 319 320 321 322 323 324 325 |
xp->curlft.add_time - now; if (tmo <= 0) { warn = 1; tmo = XFRM_KM_TIMEOUT; } if (tmo < next) next = tmo; } if (xp->lft.soft_use_expires_seconds) { |
386c5680e xfrm: use time64_... |
326 |
time64_t tmo = xp->lft.soft_use_expires_seconds + |
1da177e4c Linux-2.6.12-rc2 |
327 328 329 330 331 332 333 334 335 336 |
(xp->curlft.use_time ? : xp->curlft.add_time) - now; if (tmo <= 0) { warn = 1; tmo = XFRM_KM_TIMEOUT; } if (tmo < next) next = tmo; } if (warn) |
6c5c8ca7f [IPSEC]: Sync ser... |
337 |
km_policy_expired(xp, dir, 0, 0); |
386c5680e xfrm: use time64_... |
338 |
if (next != TIME64_MAX && |
1da177e4c Linux-2.6.12-rc2 |
339 340 341 342 343 344 345 346 347 348 |
!mod_timer(&xp->timer, jiffies + make_jiffies(next))) xfrm_pol_hold(xp); out: read_unlock(&xp->lock); xfrm_pol_put(xp); return; expired: read_unlock(&xp->lock); |
4666faab0 [IPSEC] Kill spur... |
349 |
if (!xfrm_policy_delete(xp, dir)) |
6c5c8ca7f [IPSEC]: Sync ser... |
350 |
km_policy_expired(xp, dir, 1, 0); |
1da177e4c Linux-2.6.12-rc2 |
351 352 |
xfrm_pol_put(xp); } |
1da177e4c Linux-2.6.12-rc2 |
353 354 355 |
/* Allocate xfrm_policy. Not used here, it is supposed to be used by pfkeyv2 * SPD calls. */ |
0331b1f38 netns xfrm: add s... |
356 |
struct xfrm_policy *xfrm_policy_alloc(struct net *net, gfp_t gfp) |
1da177e4c Linux-2.6.12-rc2 |
357 358 |
{ struct xfrm_policy *policy; |
0da974f4f [NET]: Conversion... |
359 |
policy = kzalloc(sizeof(struct xfrm_policy), gfp); |
1da177e4c Linux-2.6.12-rc2 |
360 361 |
if (policy) { |
0331b1f38 netns xfrm: add s... |
362 |
write_pnet(&policy->xp_net, net); |
12a169e7d ipsec: Put dumper... |
363 |
INIT_LIST_HEAD(&policy->walk.all); |
24969facd xfrm: policy: sto... |
364 |
INIT_HLIST_NODE(&policy->bydst_inexact_list); |
2518c7c2b [XFRM]: Hash poli... |
365 366 |
INIT_HLIST_NODE(&policy->bydst); INIT_HLIST_NODE(&policy->byidx); |
1da177e4c Linux-2.6.12-rc2 |
367 |
rwlock_init(&policy->lock); |
850a6212c net, xfrm: conver... |
368 |
refcount_set(&policy->refcnt, 1); |
a0073fe18 xfrm: Add a state... |
369 |
skb_queue_head_init(&policy->polq.hold_queue); |
c3aed7095 xfrm: Convert tim... |
370 371 372 |
timer_setup(&policy->timer, xfrm_policy_timer, 0); timer_setup(&policy->polq.hold_timer, xfrm_policy_queue_process, 0); |
1da177e4c Linux-2.6.12-rc2 |
373 374 375 376 |
} return policy; } EXPORT_SYMBOL(xfrm_policy_alloc); |
56f047305 xfrm: add rcu gra... |
377 378 379 380 381 382 383 |
static void xfrm_policy_destroy_rcu(struct rcu_head *head) { struct xfrm_policy *policy = container_of(head, struct xfrm_policy, rcu); security_xfrm_policy_free(policy->security); kfree(policy); } |
1da177e4c Linux-2.6.12-rc2 |
384 |
/* Destroy xfrm_policy: descendant resources must be released to this moment. */ |
64c31b3f7 [XFRM] xfrm_polic... |
385 |
void xfrm_policy_destroy(struct xfrm_policy *policy) |
1da177e4c Linux-2.6.12-rc2 |
386 |
{ |
12a169e7d ipsec: Put dumper... |
387 |
BUG_ON(!policy->walk.dead); |
1da177e4c Linux-2.6.12-rc2 |
388 |
|
0659eea91 xfrm: Delete hold... |
389 |
if (del_timer(&policy->timer) || del_timer(&policy->polq.hold_timer)) |
1da177e4c Linux-2.6.12-rc2 |
390 |
BUG(); |
56f047305 xfrm: add rcu gra... |
391 |
call_rcu(&policy->rcu, xfrm_policy_destroy_rcu); |
1da177e4c Linux-2.6.12-rc2 |
392 |
} |
64c31b3f7 [XFRM] xfrm_polic... |
393 |
EXPORT_SYMBOL(xfrm_policy_destroy); |
1da177e4c Linux-2.6.12-rc2 |
394 |
|
1365e547c xfrm: trivial typos |
395 |
/* Rule must be locked. Release descendant resources, announce |
1da177e4c Linux-2.6.12-rc2 |
396 397 398 399 400 |
* entry dead. The rule must be unlinked from lists to the moment. */ static void xfrm_policy_kill(struct xfrm_policy *policy) { |
4c59406ed xfrm: policy: Fix... |
401 |
write_lock_bh(&policy->lock); |
12a169e7d ipsec: Put dumper... |
402 |
policy->walk.dead = 1; |
4c59406ed xfrm: policy: Fix... |
403 |
write_unlock_bh(&policy->lock); |
1da177e4c Linux-2.6.12-rc2 |
404 |
|
285ead175 xfrm: remove poli... |
405 |
atomic_inc(&policy->genid); |
1da177e4c Linux-2.6.12-rc2 |
406 |
|
e7d8f6cb2 xfrm: Add refcoun... |
407 408 |
if (del_timer(&policy->polq.hold_timer)) xfrm_pol_put(policy); |
1ee5e6676 xfrm: remove the ... |
409 |
skb_queue_purge(&policy->polq.hold_queue); |
a0073fe18 xfrm: Add a state... |
410 |
|
285ead175 xfrm: remove poli... |
411 412 413 414 |
if (del_timer(&policy->timer)) xfrm_pol_put(policy); xfrm_pol_put(policy); |
1da177e4c Linux-2.6.12-rc2 |
415 |
} |
2518c7c2b [XFRM]: Hash poli... |
416 |
static unsigned int xfrm_policy_hashmax __read_mostly = 1 * 1024 * 1024; |
e92303f87 netns xfrm: propa... |
417 |
static inline unsigned int idx_hash(struct net *net, u32 index) |
2518c7c2b [XFRM]: Hash poli... |
418 |
{ |
e92303f87 netns xfrm: propa... |
419 |
return __idx_hash(index, net->xfrm.policy_idx_hmask); |
2518c7c2b [XFRM]: Hash poli... |
420 |
} |
b58555f17 xfrm: hash prefix... |
421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 |
/* calculate policy hash thresholds */ static void __get_hash_thresh(struct net *net, unsigned short family, int dir, u8 *dbits, u8 *sbits) { switch (family) { case AF_INET: *dbits = net->xfrm.policy_bydst[dir].dbits4; *sbits = net->xfrm.policy_bydst[dir].sbits4; break; case AF_INET6: *dbits = net->xfrm.policy_bydst[dir].dbits6; *sbits = net->xfrm.policy_bydst[dir].sbits6; break; default: *dbits = 0; *sbits = 0; } } |
5f803b58c xfrm: Const'ify a... |
442 443 444 |
static struct hlist_head *policy_hash_bysel(struct net *net, const struct xfrm_selector *sel, unsigned short family, int dir) |
2518c7c2b [XFRM]: Hash poli... |
445 |
{ |
1121994c8 netns xfrm: polic... |
446 |
unsigned int hmask = net->xfrm.policy_bydst[dir].hmask; |
b58555f17 xfrm: hash prefix... |
447 448 449 450 451 452 |
unsigned int hash; u8 dbits; u8 sbits; __get_hash_thresh(net, family, dir, &dbits, &sbits); hash = __sel_hash(sel, family, hmask, dbits, sbits); |
2518c7c2b [XFRM]: Hash poli... |
453 |
|
e1e551bc5 xfrm: policy: pre... |
454 |
if (hash == hmask + 1) |
cc1bb845a xfrm: policy: ret... |
455 |
return NULL; |
e1e551bc5 xfrm: policy: pre... |
456 457 458 |
return rcu_dereference_check(net->xfrm.policy_bydst[dir].table, lockdep_is_held(&net->xfrm.xfrm_policy_lock)) + hash; |
2518c7c2b [XFRM]: Hash poli... |
459 |
} |
5f803b58c xfrm: Const'ify a... |
460 461 462 463 |
static struct hlist_head *policy_hash_direct(struct net *net, const xfrm_address_t *daddr, const xfrm_address_t *saddr, unsigned short family, int dir) |
2518c7c2b [XFRM]: Hash poli... |
464 |
{ |
1121994c8 netns xfrm: polic... |
465 |
unsigned int hmask = net->xfrm.policy_bydst[dir].hmask; |
b58555f17 xfrm: hash prefix... |
466 467 468 469 470 471 |
unsigned int hash; u8 dbits; u8 sbits; __get_hash_thresh(net, family, dir, &dbits, &sbits); hash = __addr_hash(daddr, saddr, family, hmask, dbits, sbits); |
2518c7c2b [XFRM]: Hash poli... |
472 |
|
e1e551bc5 xfrm: policy: pre... |
473 474 |
return rcu_dereference_check(net->xfrm.policy_bydst[dir].table, lockdep_is_held(&net->xfrm.xfrm_policy_lock)) + hash; |
2518c7c2b [XFRM]: Hash poli... |
475 |
} |
b58555f17 xfrm: hash prefix... |
476 477 |
static void xfrm_dst_hash_transfer(struct net *net, struct hlist_head *list, |
2518c7c2b [XFRM]: Hash poli... |
478 |
struct hlist_head *ndsttable, |
b58555f17 xfrm: hash prefix... |
479 480 |
unsigned int nhashmask, int dir) |
2518c7c2b [XFRM]: Hash poli... |
481 |
{ |
b67bfe0d4 hlist: drop the n... |
482 |
struct hlist_node *tmp, *entry0 = NULL; |
2518c7c2b [XFRM]: Hash poli... |
483 |
struct xfrm_policy *pol; |
b791160b5 [XFRM]: Fix order... |
484 |
unsigned int h0 = 0; |
b58555f17 xfrm: hash prefix... |
485 486 |
u8 dbits; u8 sbits; |
2518c7c2b [XFRM]: Hash poli... |
487 |
|
b791160b5 [XFRM]: Fix order... |
488 |
redo: |
b67bfe0d4 hlist: drop the n... |
489 |
hlist_for_each_entry_safe(pol, tmp, list, bydst) { |
2518c7c2b [XFRM]: Hash poli... |
490 |
unsigned int h; |
b58555f17 xfrm: hash prefix... |
491 |
__get_hash_thresh(net, pol->family, dir, &dbits, &sbits); |
2518c7c2b [XFRM]: Hash poli... |
492 |
h = __addr_hash(&pol->selector.daddr, &pol->selector.saddr, |
b58555f17 xfrm: hash prefix... |
493 |
pol->family, nhashmask, dbits, sbits); |
b791160b5 [XFRM]: Fix order... |
494 |
if (!entry0) { |
a5eefc1df xfrm: policy: use... |
495 496 |
hlist_del_rcu(&pol->bydst); hlist_add_head_rcu(&pol->bydst, ndsttable + h); |
b791160b5 [XFRM]: Fix order... |
497 498 499 500 |
h0 = h; } else { if (h != h0) continue; |
a5eefc1df xfrm: policy: use... |
501 502 |
hlist_del_rcu(&pol->bydst); hlist_add_behind_rcu(&pol->bydst, entry0); |
b791160b5 [XFRM]: Fix order... |
503 |
} |
b67bfe0d4 hlist: drop the n... |
504 |
entry0 = &pol->bydst; |
b791160b5 [XFRM]: Fix order... |
505 506 507 508 |
} if (!hlist_empty(list)) { entry0 = NULL; goto redo; |
2518c7c2b [XFRM]: Hash poli... |
509 510 511 512 513 514 515 |
} } static void xfrm_idx_hash_transfer(struct hlist_head *list, struct hlist_head *nidxtable, unsigned int nhashmask) { |
b67bfe0d4 hlist: drop the n... |
516 |
struct hlist_node *tmp; |
2518c7c2b [XFRM]: Hash poli... |
517 |
struct xfrm_policy *pol; |
b67bfe0d4 hlist: drop the n... |
518 |
hlist_for_each_entry_safe(pol, tmp, list, byidx) { |
2518c7c2b [XFRM]: Hash poli... |
519 520 521 522 523 524 525 526 527 528 529 |
unsigned int h; h = __idx_hash(pol->index, nhashmask); hlist_add_head(&pol->byidx, nidxtable+h); } } static unsigned long xfrm_new_hash_mask(unsigned int old_hmask) { return ((old_hmask + 1) << 1) - 1; } |
66caf628c netns xfrm: per-n... |
530 |
static void xfrm_bydst_resize(struct net *net, int dir) |
2518c7c2b [XFRM]: Hash poli... |
531 |
{ |
66caf628c netns xfrm: per-n... |
532 |
unsigned int hmask = net->xfrm.policy_bydst[dir].hmask; |
2518c7c2b [XFRM]: Hash poli... |
533 534 |
unsigned int nhashmask = xfrm_new_hash_mask(hmask); unsigned int nsize = (nhashmask + 1) * sizeof(struct hlist_head); |
44e36b42a [XFRM]: Extract c... |
535 |
struct hlist_head *ndst = xfrm_hash_alloc(nsize); |
e1e551bc5 xfrm: policy: pre... |
536 |
struct hlist_head *odst; |
2518c7c2b [XFRM]: Hash poli... |
537 538 539 540 |
int i; if (!ndst) return; |
9d0380df6 xfrm: policy: con... |
541 |
spin_lock_bh(&net->xfrm.xfrm_policy_lock); |
30846090a xfrm: policy: add... |
542 543 544 545 |
write_seqcount_begin(&xfrm_policy_hash_generation); odst = rcu_dereference_protected(net->xfrm.policy_bydst[dir].table, lockdep_is_held(&net->xfrm.xfrm_policy_lock)); |
2518c7c2b [XFRM]: Hash poli... |
546 547 |
for (i = hmask; i >= 0; i--) |
b58555f17 xfrm: hash prefix... |
548 |
xfrm_dst_hash_transfer(net, odst + i, ndst, nhashmask, dir); |
2518c7c2b [XFRM]: Hash poli... |
549 |
|
e1e551bc5 xfrm: policy: pre... |
550 |
rcu_assign_pointer(net->xfrm.policy_bydst[dir].table, ndst); |
66caf628c netns xfrm: per-n... |
551 |
net->xfrm.policy_bydst[dir].hmask = nhashmask; |
2518c7c2b [XFRM]: Hash poli... |
552 |
|
30846090a xfrm: policy: add... |
553 |
write_seqcount_end(&xfrm_policy_hash_generation); |
9d0380df6 xfrm: policy: con... |
554 |
spin_unlock_bh(&net->xfrm.xfrm_policy_lock); |
2518c7c2b [XFRM]: Hash poli... |
555 |
|
e1e551bc5 xfrm: policy: pre... |
556 |
synchronize_rcu(); |
44e36b42a [XFRM]: Extract c... |
557 |
xfrm_hash_free(odst, (hmask + 1) * sizeof(struct hlist_head)); |
2518c7c2b [XFRM]: Hash poli... |
558 |
} |
66caf628c netns xfrm: per-n... |
559 |
static void xfrm_byidx_resize(struct net *net, int total) |
2518c7c2b [XFRM]: Hash poli... |
560 |
{ |
66caf628c netns xfrm: per-n... |
561 |
unsigned int hmask = net->xfrm.policy_idx_hmask; |
2518c7c2b [XFRM]: Hash poli... |
562 563 |
unsigned int nhashmask = xfrm_new_hash_mask(hmask); unsigned int nsize = (nhashmask + 1) * sizeof(struct hlist_head); |
66caf628c netns xfrm: per-n... |
564 |
struct hlist_head *oidx = net->xfrm.policy_byidx; |
44e36b42a [XFRM]: Extract c... |
565 |
struct hlist_head *nidx = xfrm_hash_alloc(nsize); |
2518c7c2b [XFRM]: Hash poli... |
566 567 568 569 |
int i; if (!nidx) return; |
9d0380df6 xfrm: policy: con... |
570 |
spin_lock_bh(&net->xfrm.xfrm_policy_lock); |
2518c7c2b [XFRM]: Hash poli... |
571 572 573 |
for (i = hmask; i >= 0; i--) xfrm_idx_hash_transfer(oidx + i, nidx, nhashmask); |
66caf628c netns xfrm: per-n... |
574 575 |
net->xfrm.policy_byidx = nidx; net->xfrm.policy_idx_hmask = nhashmask; |
2518c7c2b [XFRM]: Hash poli... |
576 |
|
9d0380df6 xfrm: policy: con... |
577 |
spin_unlock_bh(&net->xfrm.xfrm_policy_lock); |
2518c7c2b [XFRM]: Hash poli... |
578 |
|
44e36b42a [XFRM]: Extract c... |
579 |
xfrm_hash_free(oidx, (hmask + 1) * sizeof(struct hlist_head)); |
2518c7c2b [XFRM]: Hash poli... |
580 |
} |
66caf628c netns xfrm: per-n... |
581 |
static inline int xfrm_bydst_should_resize(struct net *net, int dir, int *total) |
2518c7c2b [XFRM]: Hash poli... |
582 |
{ |
66caf628c netns xfrm: per-n... |
583 584 |
unsigned int cnt = net->xfrm.policy_count[dir]; unsigned int hmask = net->xfrm.policy_bydst[dir].hmask; |
2518c7c2b [XFRM]: Hash poli... |
585 586 587 588 589 590 591 592 593 594 |
if (total) *total += cnt; if ((hmask + 1) < xfrm_policy_hashmax && cnt > hmask) return 1; return 0; } |
66caf628c netns xfrm: per-n... |
595 |
static inline int xfrm_byidx_should_resize(struct net *net, int total) |
2518c7c2b [XFRM]: Hash poli... |
596 |
{ |
66caf628c netns xfrm: per-n... |
597 |
unsigned int hmask = net->xfrm.policy_idx_hmask; |
2518c7c2b [XFRM]: Hash poli... |
598 599 600 601 602 603 604 |
if ((hmask + 1) < xfrm_policy_hashmax && total > hmask) return 1; return 0; } |
e071041be netns xfrm: fix "... |
605 |
void xfrm_spd_getinfo(struct net *net, struct xfrmk_spdinfo *si) |
ecfd6b183 [XFRM]: Export SP... |
606 |
{ |
e071041be netns xfrm: fix "... |
607 608 609 610 611 612 613 |
si->incnt = net->xfrm.policy_count[XFRM_POLICY_IN]; si->outcnt = net->xfrm.policy_count[XFRM_POLICY_OUT]; si->fwdcnt = net->xfrm.policy_count[XFRM_POLICY_FWD]; si->inscnt = net->xfrm.policy_count[XFRM_POLICY_IN+XFRM_POLICY_MAX]; si->outscnt = net->xfrm.policy_count[XFRM_POLICY_OUT+XFRM_POLICY_MAX]; si->fwdscnt = net->xfrm.policy_count[XFRM_POLICY_FWD+XFRM_POLICY_MAX]; si->spdhcnt = net->xfrm.policy_idx_hmask; |
ecfd6b183 [XFRM]: Export SP... |
614 |
si->spdhmcnt = xfrm_policy_hashmax; |
ecfd6b183 [XFRM]: Export SP... |
615 616 |
} EXPORT_SYMBOL(xfrm_spd_getinfo); |
2518c7c2b [XFRM]: Hash poli... |
617 |
|
ecfd6b183 [XFRM]: Export SP... |
618 |
static DEFINE_MUTEX(hash_resize_mutex); |
66caf628c netns xfrm: per-n... |
619 |
static void xfrm_hash_resize(struct work_struct *work) |
2518c7c2b [XFRM]: Hash poli... |
620 |
{ |
66caf628c netns xfrm: per-n... |
621 |
struct net *net = container_of(work, struct net, xfrm.policy_hash_work); |
2518c7c2b [XFRM]: Hash poli... |
622 623 624 625 626 |
int dir, total; mutex_lock(&hash_resize_mutex); total = 0; |
53c2e285f xfrm: Do not hash... |
627 |
for (dir = 0; dir < XFRM_POLICY_MAX; dir++) { |
66caf628c netns xfrm: per-n... |
628 629 |
if (xfrm_bydst_should_resize(net, dir, &total)) xfrm_bydst_resize(net, dir); |
2518c7c2b [XFRM]: Hash poli... |
630 |
} |
66caf628c netns xfrm: per-n... |
631 632 |
if (xfrm_byidx_should_resize(net, total)) xfrm_byidx_resize(net, total); |
2518c7c2b [XFRM]: Hash poli... |
633 634 635 |
mutex_unlock(&hash_resize_mutex); } |
24969facd xfrm: policy: sto... |
636 637 638 639 640 641 642 643 644 645 646 647 |
/* Make sure *pol can be inserted into fastbin. * Useful to check that later insert requests will be sucessful * (provided xfrm_policy_lock is held throughout). */ static struct xfrm_pol_inexact_bin * xfrm_policy_inexact_alloc_bin(const struct xfrm_policy *pol, u8 dir) { struct xfrm_pol_inexact_bin *bin, *prev; struct xfrm_pol_inexact_key k = { .family = pol->family, .type = pol->type, .dir = dir, |
b5fe22e23 xfrm: policy: con... |
648 |
.if_id = pol->if_id, |
24969facd xfrm: policy: sto... |
649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 |
}; struct net *net = xp_net(pol); lockdep_assert_held(&net->xfrm.xfrm_policy_lock); write_pnet(&k.net, net); bin = rhashtable_lookup_fast(&xfrm_policy_inexact_table, &k, xfrm_pol_inexact_params); if (bin) return bin; bin = kzalloc(sizeof(*bin), GFP_ATOMIC); if (!bin) return NULL; bin->k = k; INIT_HLIST_HEAD(&bin->hhead); |
9cf545ebd xfrm: policy: sto... |
666 |
bin->root_d = RB_ROOT; |
64a09a7bf xfrm: policy: sto... |
667 |
bin->root_s = RB_ROOT; |
77cc278f7 xfrm: policy: Use... |
668 |
seqcount_spinlock_init(&bin->count, &net->xfrm.xfrm_policy_lock); |
24969facd xfrm: policy: sto... |
669 670 671 672 673 674 675 676 677 678 679 680 681 |
prev = rhashtable_lookup_get_insert_key(&xfrm_policy_inexact_table, &bin->k, &bin->head, xfrm_pol_inexact_params); if (!prev) { list_add(&bin->inexact_bins, &net->xfrm.inexact_bins); return bin; } kfree(bin); return IS_ERR(prev) ? NULL : prev; } |
6be3b0db6 xfrm: policy: add... |
682 683 |
static bool xfrm_pol_inexact_addr_use_any_list(const xfrm_address_t *addr, int family, u8 prefixlen) |
24969facd xfrm: policy: sto... |
684 |
{ |
6be3b0db6 xfrm: policy: add... |
685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 |
if (xfrm_addr_any(addr, family)) return true; if (family == AF_INET6 && prefixlen < INEXACT_PREFIXLEN_IPV6) return true; if (family == AF_INET && prefixlen < INEXACT_PREFIXLEN_IPV4) return true; return false; } static bool xfrm_policy_inexact_insert_use_any_list(const struct xfrm_policy *policy) { const xfrm_address_t *addr; bool saddr_any, daddr_any; u8 prefixlen; addr = &policy->selector.saddr; prefixlen = policy->selector.prefixlen_s; |
24969facd xfrm: policy: sto... |
706 |
|
6be3b0db6 xfrm: policy: add... |
707 708 709 710 711 712 713 714 715 716 |
saddr_any = xfrm_pol_inexact_addr_use_any_list(addr, policy->family, prefixlen); addr = &policy->selector.daddr; prefixlen = policy->selector.prefixlen_d; daddr_any = xfrm_pol_inexact_addr_use_any_list(addr, policy->family, prefixlen); return saddr_any && daddr_any; } |
9cf545ebd xfrm: policy: sto... |
717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 |
static void xfrm_pol_inexact_node_init(struct xfrm_pol_inexact_node *node, const xfrm_address_t *addr, u8 prefixlen) { node->addr = *addr; node->prefixlen = prefixlen; } static struct xfrm_pol_inexact_node * xfrm_pol_inexact_node_alloc(const xfrm_address_t *addr, u8 prefixlen) { struct xfrm_pol_inexact_node *node; node = kzalloc(sizeof(*node), GFP_ATOMIC); if (node) xfrm_pol_inexact_node_init(node, addr, prefixlen); return node; } static int xfrm_policy_addr_delta(const xfrm_address_t *a, const xfrm_address_t *b, u8 prefixlen, u16 family) { unsigned int pdw, pbi; int delta = 0; switch (family) { case AF_INET: if (sizeof(long) == 4 && prefixlen == 0) return ntohl(a->a4) - ntohl(b->a4); return (ntohl(a->a4) & ((~0UL << (32 - prefixlen)))) - (ntohl(b->a4) & ((~0UL << (32 - prefixlen)))); case AF_INET6: pdw = prefixlen >> 5; pbi = prefixlen & 0x1f; if (pdw) { delta = memcmp(a->a6, b->a6, pdw << 2); if (delta) return delta; } if (pbi) { u32 mask = ~0u << (32 - pbi); delta = (ntohl(a->a6[pdw]) & mask) - (ntohl(b->a6[pdw]) & mask); } break; default: break; } return delta; } static void xfrm_policy_inexact_list_reinsert(struct net *net, struct xfrm_pol_inexact_node *n, u16 family) { |
e901cbc29 xfrm: policy: che... |
776 |
unsigned int matched_s, matched_d; |
9cf545ebd xfrm: policy: sto... |
777 |
struct xfrm_policy *policy, *p; |
e901cbc29 xfrm: policy: che... |
778 779 |
matched_s = 0; matched_d = 0; |
9cf545ebd xfrm: policy: sto... |
780 |
list_for_each_entry_reverse(policy, &net->xfrm.policy_all, walk.all) { |
1d38900cb xfrm: policy: fix... |
781 |
struct hlist_node *newpos = NULL; |
e901cbc29 xfrm: policy: che... |
782 |
bool matches_s, matches_d; |
9cf545ebd xfrm: policy: sto... |
783 784 785 786 787 788 789 |
if (!policy->bydst_reinsert) continue; WARN_ON_ONCE(policy->family != family); policy->bydst_reinsert = false; hlist_for_each_entry(p, &n->hhead, bydst) { |
1d38900cb xfrm: policy: fix... |
790 791 792 793 |
if (policy->priority > p->priority) newpos = &p->bydst; else if (policy->priority == p->priority && policy->pos > p->pos) |
9cf545ebd xfrm: policy: sto... |
794 795 796 797 798 799 |
newpos = &p->bydst; else break; } if (newpos) |
355b00d1e xfrm: policy: use... |
800 |
hlist_add_behind_rcu(&policy->bydst, newpos); |
9cf545ebd xfrm: policy: sto... |
801 |
else |
355b00d1e xfrm: policy: use... |
802 |
hlist_add_head_rcu(&policy->bydst, &n->hhead); |
e901cbc29 xfrm: policy: che... |
803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 |
/* paranoia checks follow. * Check that the reinserted policy matches at least * saddr or daddr for current node prefix. * * Matching both is fine, matching saddr in one policy * (but not daddr) and then matching only daddr in another * is a bug. */ matches_s = xfrm_policy_addr_delta(&policy->selector.saddr, &n->addr, n->prefixlen, family) == 0; matches_d = xfrm_policy_addr_delta(&policy->selector.daddr, &n->addr, n->prefixlen, family) == 0; if (matches_s && matches_d) continue; WARN_ON_ONCE(!matches_s && !matches_d); if (matches_s) matched_s++; if (matches_d) matched_d++; WARN_ON_ONCE(matched_s && matched_d); |
9cf545ebd xfrm: policy: sto... |
829 830 |
} } |
6ac098b2a xfrm: policy: add... |
831 832 833 834 835 |
static void xfrm_policy_inexact_node_reinsert(struct net *net, struct xfrm_pol_inexact_node *n, struct rb_root *new, u16 family) { |
6ac098b2a xfrm: policy: add... |
836 |
struct xfrm_pol_inexact_node *node; |
12750abad xfrm: policy: fix... |
837 |
struct rb_node **p, *parent; |
6ac098b2a xfrm: policy: add... |
838 839 840 |
/* we should not have another subtree here */ WARN_ON_ONCE(!RB_EMPTY_ROOT(&n->root)); |
12750abad xfrm: policy: fix... |
841 842 |
restart: parent = NULL; |
6ac098b2a xfrm: policy: add... |
843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 |
p = &new->rb_node; while (*p) { u8 prefixlen; int delta; parent = *p; node = rb_entry(*p, struct xfrm_pol_inexact_node, node); prefixlen = min(node->prefixlen, n->prefixlen); delta = xfrm_policy_addr_delta(&n->addr, &node->addr, prefixlen, family); if (delta < 0) { p = &parent->rb_left; } else if (delta > 0) { p = &parent->rb_right; } else { |
769a807d0 xfrm: policy: avo... |
860 |
bool same_prefixlen = node->prefixlen == n->prefixlen; |
6ac098b2a xfrm: policy: add... |
861 |
struct xfrm_policy *tmp; |
12750abad xfrm: policy: fix... |
862 |
hlist_for_each_entry(tmp, &n->hhead, bydst) { |
6ac098b2a xfrm: policy: add... |
863 |
tmp->bydst_reinsert = true; |
12750abad xfrm: policy: fix... |
864 865 |
hlist_del_rcu(&tmp->bydst); } |
6ac098b2a xfrm: policy: add... |
866 |
|
769a807d0 xfrm: policy: avo... |
867 |
node->prefixlen = prefixlen; |
6ac098b2a xfrm: policy: add... |
868 |
xfrm_policy_inexact_list_reinsert(net, node, family); |
769a807d0 xfrm: policy: avo... |
869 |
if (same_prefixlen) { |
6ac098b2a xfrm: policy: add... |
870 871 872 873 874 875 876 |
kfree_rcu(n, rcu); return; } rb_erase(*p, new); kfree_rcu(n, rcu); n = node; |
12750abad xfrm: policy: fix... |
877 |
goto restart; |
6ac098b2a xfrm: policy: add... |
878 879 880 881 882 883 |
} } rb_link_node_rcu(&n->node, parent, p); rb_insert_color(&n->node, new); } |
9cf545ebd xfrm: policy: sto... |
884 885 886 887 888 889 |
/* merge nodes v and n */ static void xfrm_policy_inexact_node_merge(struct net *net, struct xfrm_pol_inexact_node *v, struct xfrm_pol_inexact_node *n, u16 family) { |
6ac098b2a xfrm: policy: add... |
890 |
struct xfrm_pol_inexact_node *node; |
9cf545ebd xfrm: policy: sto... |
891 |
struct xfrm_policy *tmp; |
6ac098b2a xfrm: policy: add... |
892 893 894 895 896 897 898 899 900 901 902 903 |
struct rb_node *rnode; /* To-be-merged node v has a subtree. * * Dismantle it and insert its nodes to n->root. */ while ((rnode = rb_first(&v->root)) != NULL) { node = rb_entry(rnode, struct xfrm_pol_inexact_node, node); rb_erase(&node->node, &v->root); xfrm_policy_inexact_node_reinsert(net, node, &n->root, family); } |
9cf545ebd xfrm: policy: sto... |
904 |
|
1d38900cb xfrm: policy: fix... |
905 |
hlist_for_each_entry(tmp, &v->hhead, bydst) { |
9cf545ebd xfrm: policy: sto... |
906 |
tmp->bydst_reinsert = true; |
1d38900cb xfrm: policy: fix... |
907 908 |
hlist_del_rcu(&tmp->bydst); } |
9cf545ebd xfrm: policy: sto... |
909 |
|
9cf545ebd xfrm: policy: sto... |
910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 |
xfrm_policy_inexact_list_reinsert(net, n, family); } static struct xfrm_pol_inexact_node * xfrm_policy_inexact_insert_node(struct net *net, struct rb_root *root, xfrm_address_t *addr, u16 family, u8 prefixlen, u8 dir) { struct xfrm_pol_inexact_node *cached = NULL; struct rb_node **p, *parent = NULL; struct xfrm_pol_inexact_node *node; p = &root->rb_node; while (*p) { int delta; parent = *p; node = rb_entry(*p, struct xfrm_pol_inexact_node, node); delta = xfrm_policy_addr_delta(addr, &node->addr, node->prefixlen, family); if (delta == 0 && prefixlen >= node->prefixlen) { WARN_ON_ONCE(cached); /* ipsec policies got lost */ return node; } if (delta < 0) p = &parent->rb_left; else p = &parent->rb_right; if (prefixlen < node->prefixlen) { delta = xfrm_policy_addr_delta(addr, &node->addr, prefixlen, family); if (delta) continue; /* This node is a subnet of the new prefix. It needs * to be removed and re-inserted with the smaller * prefix and all nodes that are now also covered * by the reduced prefixlen. */ rb_erase(&node->node, root); if (!cached) { xfrm_pol_inexact_node_init(node, addr, prefixlen); cached = node; } else { /* This node also falls within the new * prefixlen. Merge the to-be-reinserted * node and this one. */ xfrm_policy_inexact_node_merge(net, node, cached, family); kfree_rcu(node, rcu); } /* restart */ p = &root->rb_node; parent = NULL; } } node = cached; if (!node) { node = xfrm_pol_inexact_node_alloc(addr, prefixlen); if (!node) return NULL; } rb_link_node_rcu(&node->node, parent, p); rb_insert_color(&node->node, root); return node; } static void xfrm_policy_inexact_gc_tree(struct rb_root *r, bool rm) { struct xfrm_pol_inexact_node *node; struct rb_node *rn = rb_first(r); while (rn) { node = rb_entry(rn, struct xfrm_pol_inexact_node, node); |
6ac098b2a xfrm: policy: add... |
997 |
xfrm_policy_inexact_gc_tree(&node->root, rm); |
9cf545ebd xfrm: policy: sto... |
998 |
rn = rb_next(rn); |
6ac098b2a xfrm: policy: add... |
999 |
if (!hlist_empty(&node->hhead) || !RB_EMPTY_ROOT(&node->root)) { |
9cf545ebd xfrm: policy: sto... |
1000 1001 1002 1003 1004 1005 1006 1007 |
WARN_ON_ONCE(rm); continue; } rb_erase(&node->node, r); kfree_rcu(node, rcu); } } |
6be3b0db6 xfrm: policy: add... |
1008 1009 |
static void __xfrm_policy_inexact_prune_bin(struct xfrm_pol_inexact_bin *b, bool net_exit) { |
9cf545ebd xfrm: policy: sto... |
1010 1011 |
write_seqcount_begin(&b->count); xfrm_policy_inexact_gc_tree(&b->root_d, net_exit); |
64a09a7bf xfrm: policy: sto... |
1012 |
xfrm_policy_inexact_gc_tree(&b->root_s, net_exit); |
9cf545ebd xfrm: policy: sto... |
1013 |
write_seqcount_end(&b->count); |
64a09a7bf xfrm: policy: sto... |
1014 |
if (!RB_EMPTY_ROOT(&b->root_d) || !RB_EMPTY_ROOT(&b->root_s) || |
9cf545ebd xfrm: policy: sto... |
1015 |
!hlist_empty(&b->hhead)) { |
6be3b0db6 xfrm: policy: add... |
1016 |
WARN_ON_ONCE(net_exit); |
24969facd xfrm: policy: sto... |
1017 |
return; |
6be3b0db6 xfrm: policy: add... |
1018 |
} |
24969facd xfrm: policy: sto... |
1019 1020 1021 1022 1023 1024 1025 |
if (rhashtable_remove_fast(&xfrm_policy_inexact_table, &b->head, xfrm_pol_inexact_params) == 0) { list_del(&b->inexact_bins); kfree_rcu(b, rcu); } } |
6be3b0db6 xfrm: policy: add... |
1026 1027 1028 1029 1030 1031 1032 1033 |
static void xfrm_policy_inexact_prune_bin(struct xfrm_pol_inexact_bin *b) { struct net *net = read_pnet(&b->k.net); spin_lock_bh(&net->xfrm.xfrm_policy_lock); __xfrm_policy_inexact_prune_bin(b, false); spin_unlock_bh(&net->xfrm.xfrm_policy_lock); } |
24969facd xfrm: policy: sto... |
1034 1035 |
static void __xfrm_policy_inexact_flush(struct net *net) { |
6be3b0db6 xfrm: policy: add... |
1036 |
struct xfrm_pol_inexact_bin *bin, *t; |
24969facd xfrm: policy: sto... |
1037 1038 |
lockdep_assert_held(&net->xfrm.xfrm_policy_lock); |
6be3b0db6 xfrm: policy: add... |
1039 1040 |
list_for_each_entry_safe(bin, t, &net->xfrm.inexact_bins, inexact_bins) __xfrm_policy_inexact_prune_bin(bin, false); |
24969facd xfrm: policy: sto... |
1041 |
} |
9cf545ebd xfrm: policy: sto... |
1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 |
static struct hlist_head * xfrm_policy_inexact_alloc_chain(struct xfrm_pol_inexact_bin *bin, struct xfrm_policy *policy, u8 dir) { struct xfrm_pol_inexact_node *n; struct net *net; net = xp_net(policy); lockdep_assert_held(&net->xfrm.xfrm_policy_lock); if (xfrm_policy_inexact_insert_use_any_list(policy)) return &bin->hhead; |
64a09a7bf xfrm: policy: sto... |
1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 |
if (xfrm_pol_inexact_addr_use_any_list(&policy->selector.daddr, policy->family, policy->selector.prefixlen_d)) { write_seqcount_begin(&bin->count); n = xfrm_policy_inexact_insert_node(net, &bin->root_s, &policy->selector.saddr, policy->family, policy->selector.prefixlen_s, dir); write_seqcount_end(&bin->count); if (!n) return NULL; return &n->hhead; } |
9cf545ebd xfrm: policy: sto... |
1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 |
/* daddr is fixed */ write_seqcount_begin(&bin->count); n = xfrm_policy_inexact_insert_node(net, &bin->root_d, &policy->selector.daddr, policy->family, policy->selector.prefixlen_d, dir); write_seqcount_end(&bin->count); if (!n) return NULL; |
6ac098b2a xfrm: policy: add... |
1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 |
/* saddr is wildcard */ if (xfrm_pol_inexact_addr_use_any_list(&policy->selector.saddr, policy->family, policy->selector.prefixlen_s)) return &n->hhead; write_seqcount_begin(&bin->count); n = xfrm_policy_inexact_insert_node(net, &n->root, &policy->selector.saddr, policy->family, policy->selector.prefixlen_s, dir); write_seqcount_end(&bin->count); if (!n) return NULL; |
9cf545ebd xfrm: policy: sto... |
1096 1097 |
return &n->hhead; } |
24969facd xfrm: policy: sto... |
1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 |
static struct xfrm_policy * xfrm_policy_inexact_insert(struct xfrm_policy *policy, u8 dir, int excl) { struct xfrm_pol_inexact_bin *bin; struct xfrm_policy *delpol; struct hlist_head *chain; struct net *net; bin = xfrm_policy_inexact_alloc_bin(policy, dir); if (!bin) return ERR_PTR(-ENOMEM); |
6be3b0db6 xfrm: policy: add... |
1109 1110 |
net = xp_net(policy); lockdep_assert_held(&net->xfrm.xfrm_policy_lock); |
9cf545ebd xfrm: policy: sto... |
1111 1112 1113 1114 |
chain = xfrm_policy_inexact_alloc_chain(bin, policy, dir); if (!chain) { __xfrm_policy_inexact_prune_bin(bin, false); return ERR_PTR(-ENOMEM); |
6be3b0db6 xfrm: policy: add... |
1115 |
} |
6be3b0db6 xfrm: policy: add... |
1116 1117 1118 |
delpol = xfrm_policy_insert_list(chain, policy, excl); if (delpol && excl) { __xfrm_policy_inexact_prune_bin(bin, false); |
24969facd xfrm: policy: sto... |
1119 |
return ERR_PTR(-EEXIST); |
6be3b0db6 xfrm: policy: add... |
1120 |
} |
24969facd xfrm: policy: sto... |
1121 |
|
24969facd xfrm: policy: sto... |
1122 1123 |
chain = &net->xfrm.policy_inexact[dir]; xfrm_policy_insert_inexact_list(chain, policy); |
6be3b0db6 xfrm: policy: add... |
1124 1125 |
if (delpol) __xfrm_policy_inexact_prune_bin(bin, false); |
24969facd xfrm: policy: sto... |
1126 1127 |
return delpol; } |
880a6fab8 xfrm: configure p... |
1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 |
static void xfrm_hash_rebuild(struct work_struct *work) { struct net *net = container_of(work, struct net, xfrm.policy_hthresh.work); unsigned int hmask; struct xfrm_policy *pol; struct xfrm_policy *policy; struct hlist_head *chain; struct hlist_head *odst; struct hlist_node *newpos; int i; int dir; unsigned seq; u8 lbits4, rbits4, lbits6, rbits6; mutex_lock(&hash_resize_mutex); /* read selector prefixlen thresholds */ do { seq = read_seqbegin(&net->xfrm.policy_hthresh.lock); lbits4 = net->xfrm.policy_hthresh.lbits4; rbits4 = net->xfrm.policy_hthresh.rbits4; lbits6 = net->xfrm.policy_hthresh.lbits6; rbits6 = net->xfrm.policy_hthresh.rbits6; } while (read_seqretry(&net->xfrm.policy_hthresh.lock, seq)); |
9d0380df6 xfrm: policy: con... |
1154 |
spin_lock_bh(&net->xfrm.xfrm_policy_lock); |
7a474c365 xfrm: policy: inc... |
1155 |
write_seqcount_begin(&xfrm_policy_hash_generation); |
880a6fab8 xfrm: configure p... |
1156 |
|
24969facd xfrm: policy: sto... |
1157 1158 1159 1160 |
/* make sure that we can insert the indirect policies again before * we start with destructive action. */ list_for_each_entry(policy, &net->xfrm.policy_all, walk.all) { |
6be3b0db6 xfrm: policy: add... |
1161 |
struct xfrm_pol_inexact_bin *bin; |
24969facd xfrm: policy: sto... |
1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 |
u8 dbits, sbits; dir = xfrm_policy_id2dir(policy->index); if (policy->walk.dead || dir >= XFRM_POLICY_MAX) continue; if ((dir & XFRM_POLICY_MASK) == XFRM_POLICY_OUT) { if (policy->family == AF_INET) { dbits = rbits4; sbits = lbits4; } else { dbits = rbits6; sbits = lbits6; } } else { if (policy->family == AF_INET) { dbits = lbits4; sbits = rbits4; } else { dbits = lbits6; sbits = rbits6; } } if (policy->selector.prefixlen_d < dbits || policy->selector.prefixlen_s < sbits) continue; |
6be3b0db6 xfrm: policy: add... |
1189 1190 |
bin = xfrm_policy_inexact_alloc_bin(policy, dir); if (!bin) |
24969facd xfrm: policy: sto... |
1191 |
goto out_unlock; |
9cf545ebd xfrm: policy: sto... |
1192 1193 1194 |
if (!xfrm_policy_inexact_alloc_chain(bin, policy, dir)) goto out_unlock; |
24969facd xfrm: policy: sto... |
1195 |
} |
880a6fab8 xfrm: configure p... |
1196 |
/* reset the bydst and inexact table in all directions */ |
53c2e285f xfrm: Do not hash... |
1197 |
for (dir = 0; dir < XFRM_POLICY_MAX; dir++) { |
1548bc4e0 xfrm: policy: del... |
1198 1199 1200 1201 |
struct hlist_node *n; hlist_for_each_entry_safe(policy, n, &net->xfrm.policy_inexact[dir], |
fd7097213 xfrm: policy: fix... |
1202 1203 |
bydst_inexact_list) { hlist_del_rcu(&policy->bydst); |
1548bc4e0 xfrm: policy: del... |
1204 |
hlist_del_init(&policy->bydst_inexact_list); |
fd7097213 xfrm: policy: fix... |
1205 |
} |
1548bc4e0 xfrm: policy: del... |
1206 |
|
880a6fab8 xfrm: configure p... |
1207 1208 |
hmask = net->xfrm.policy_bydst[dir].hmask; odst = net->xfrm.policy_bydst[dir].table; |
fd7097213 xfrm: policy: fix... |
1209 1210 1211 1212 |
for (i = hmask; i >= 0; i--) { hlist_for_each_entry_safe(policy, n, odst + i, bydst) hlist_del_rcu(&policy->bydst); } |
880a6fab8 xfrm: configure p... |
1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 |
if ((dir & XFRM_POLICY_MASK) == XFRM_POLICY_OUT) { /* dir out => dst = remote, src = local */ net->xfrm.policy_bydst[dir].dbits4 = rbits4; net->xfrm.policy_bydst[dir].sbits4 = lbits4; net->xfrm.policy_bydst[dir].dbits6 = rbits6; net->xfrm.policy_bydst[dir].sbits6 = lbits6; } else { /* dir in/fwd => dst = local, src = remote */ net->xfrm.policy_bydst[dir].dbits4 = lbits4; net->xfrm.policy_bydst[dir].sbits4 = rbits4; net->xfrm.policy_bydst[dir].dbits6 = lbits6; net->xfrm.policy_bydst[dir].sbits6 = rbits6; } } /* re-insert all policies by order of creation */ list_for_each_entry_reverse(policy, &net->xfrm.policy_all, walk.all) { |
88584c30e xfrm: policy: fix... |
1230 1231 1232 1233 |
if (policy->walk.dead) continue; dir = xfrm_policy_id2dir(policy->index); if (dir >= XFRM_POLICY_MAX) { |
6916fb3b1 xfrm: Ignore sock... |
1234 1235 1236 |
/* skip socket policies */ continue; } |
880a6fab8 xfrm: configure p... |
1237 1238 |
newpos = NULL; chain = policy_hash_bysel(net, &policy->selector, |
88584c30e xfrm: policy: fix... |
1239 |
policy->family, dir); |
1548bc4e0 xfrm: policy: del... |
1240 |
|
24969facd xfrm: policy: sto... |
1241 1242 1243 1244 1245 1246 1247 |
if (!chain) { void *p = xfrm_policy_inexact_insert(policy, dir, 0); WARN_ONCE(IS_ERR(p), "reinsert: %ld ", PTR_ERR(p)); continue; } |
880a6fab8 xfrm: configure p... |
1248 1249 1250 1251 1252 1253 1254 |
hlist_for_each_entry(pol, chain, bydst) { if (policy->priority >= pol->priority) newpos = &pol->bydst; else break; } if (newpos) |
9dffff200 xfrm: policy: use... |
1255 |
hlist_add_behind_rcu(&policy->bydst, newpos); |
880a6fab8 xfrm: configure p... |
1256 |
else |
9dffff200 xfrm: policy: use... |
1257 |
hlist_add_head_rcu(&policy->bydst, chain); |
880a6fab8 xfrm: configure p... |
1258 |
} |
24969facd xfrm: policy: sto... |
1259 |
out_unlock: |
6be3b0db6 xfrm: policy: add... |
1260 |
__xfrm_policy_inexact_flush(net); |
7a474c365 xfrm: policy: inc... |
1261 |
write_seqcount_end(&xfrm_policy_hash_generation); |
9d0380df6 xfrm: policy: con... |
1262 |
spin_unlock_bh(&net->xfrm.xfrm_policy_lock); |
880a6fab8 xfrm: configure p... |
1263 1264 1265 1266 1267 1268 1269 1270 1271 |
mutex_unlock(&hash_resize_mutex); } void xfrm_policy_hash_rebuild(struct net *net) { schedule_work(&net->xfrm.policy_hthresh.work); } EXPORT_SYMBOL(xfrm_policy_hash_rebuild); |
1da177e4c Linux-2.6.12-rc2 |
1272 1273 |
/* Generate new index... KAME seems to generate them ordered by cost * of an absolute inpredictability of ordering of rules. This will not pass. */ |
e682adf02 xfrm: Try to hono... |
1274 |
static u32 xfrm_gen_index(struct net *net, int dir, u32 index) |
1da177e4c Linux-2.6.12-rc2 |
1275 |
{ |
1da177e4c Linux-2.6.12-rc2 |
1276 1277 1278 |
static u32 idx_generator; for (;;) { |
2518c7c2b [XFRM]: Hash poli... |
1279 1280 1281 1282 |
struct hlist_head *list; struct xfrm_policy *p; u32 idx; int found; |
e682adf02 xfrm: Try to hono... |
1283 1284 1285 1286 1287 1288 1289 |
if (!index) { idx = (idx_generator | dir); idx_generator += 8; } else { idx = index; index = 0; } |
1da177e4c Linux-2.6.12-rc2 |
1290 1291 |
if (idx == 0) idx = 8; |
1121994c8 netns xfrm: polic... |
1292 |
list = net->xfrm.policy_byidx + idx_hash(net, idx); |
2518c7c2b [XFRM]: Hash poli... |
1293 |
found = 0; |
b67bfe0d4 hlist: drop the n... |
1294 |
hlist_for_each_entry(p, list, byidx) { |
2518c7c2b [XFRM]: Hash poli... |
1295 1296 |
if (p->index == idx) { found = 1; |
1da177e4c Linux-2.6.12-rc2 |
1297 |
break; |
2518c7c2b [XFRM]: Hash poli... |
1298 |
} |
1da177e4c Linux-2.6.12-rc2 |
1299 |
} |
2518c7c2b [XFRM]: Hash poli... |
1300 |
if (!found) |
1da177e4c Linux-2.6.12-rc2 |
1301 1302 1303 |
return idx; } } |
2518c7c2b [XFRM]: Hash poli... |
1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 |
static inline int selector_cmp(struct xfrm_selector *s1, struct xfrm_selector *s2) { u32 *p1 = (u32 *) s1; u32 *p2 = (u32 *) s2; int len = sizeof(struct xfrm_selector) / sizeof(u32); int i; for (i = 0; i < len; i++) { if (p1[i] != p2[i]) return 1; } return 0; } |
a0073fe18 xfrm: Add a state... |
1318 1319 1320 1321 1322 |
static void xfrm_policy_requeue(struct xfrm_policy *old, struct xfrm_policy *new) { struct xfrm_policy_queue *pq = &old->polq; struct sk_buff_head list; |
de2ad486c xfrm: move the ch... |
1323 1324 |
if (skb_queue_empty(&pq->hold_queue)) return; |
a0073fe18 xfrm: Add a state... |
1325 1326 1327 1328 |
__skb_queue_head_init(&list); spin_lock_bh(&pq->hold_queue.lock); skb_queue_splice_init(&pq->hold_queue, &list); |
e7d8f6cb2 xfrm: Add refcoun... |
1329 1330 |
if (del_timer(&pq->hold_timer)) xfrm_pol_put(old); |
a0073fe18 xfrm: Add a state... |
1331 |
spin_unlock_bh(&pq->hold_queue.lock); |
a0073fe18 xfrm: Add a state... |
1332 1333 1334 1335 1336 |
pq = &new->polq; spin_lock_bh(&pq->hold_queue.lock); skb_queue_splice(&list, &pq->hold_queue); pq->timeout = XFRM_QUEUE_TMO_MIN; |
e7d8f6cb2 xfrm: Add refcoun... |
1337 1338 |
if (!mod_timer(&pq->hold_timer, jiffies)) xfrm_pol_hold(new); |
a0073fe18 xfrm: Add a state... |
1339 1340 |
spin_unlock_bh(&pq->hold_queue.lock); } |
4f47e8ab6 xfrm: policy: mat... |
1341 1342 |
static inline bool xfrm_policy_mark_match(const struct xfrm_mark *mark, struct xfrm_policy *pol) |
7cb8a9396 xfrm: Allow inser... |
1343 |
{ |
4f47e8ab6 xfrm: policy: mat... |
1344 |
return mark->v == pol->mark.v && mark->m == pol->mark.m; |
7cb8a9396 xfrm: Allow inser... |
1345 |
} |
24969facd xfrm: policy: sto... |
1346 1347 1348 1349 |
static u32 xfrm_pol_bin_key(const void *data, u32 len, u32 seed) { const struct xfrm_pol_inexact_key *k = data; u32 a = k->type << 24 | k->dir << 16 | k->family; |
b5fe22e23 xfrm: policy: con... |
1350 1351 |
return jhash_3words(a, k->if_id, net_hash_mix(read_pnet(&k->net)), seed); |
24969facd xfrm: policy: sto... |
1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 |
} static u32 xfrm_pol_bin_obj(const void *data, u32 len, u32 seed) { const struct xfrm_pol_inexact_bin *b = data; return xfrm_pol_bin_key(&b->k, 0, seed); } static int xfrm_pol_bin_cmp(struct rhashtable_compare_arg *arg, const void *ptr) { const struct xfrm_pol_inexact_key *key = arg->key; const struct xfrm_pol_inexact_bin *b = ptr; int ret; if (!net_eq(read_pnet(&b->k.net), read_pnet(&key->net))) return -1; ret = b->k.dir ^ key->dir; if (ret) return ret; ret = b->k.type ^ key->type; if (ret) return ret; ret = b->k.family ^ key->family; if (ret) return ret; |
b5fe22e23 xfrm: policy: con... |
1382 |
return b->k.if_id ^ key->if_id; |
24969facd xfrm: policy: sto... |
1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 |
} static const struct rhashtable_params xfrm_pol_inexact_params = { .head_offset = offsetof(struct xfrm_pol_inexact_bin, head), .hashfn = xfrm_pol_bin_key, .obj_hashfn = xfrm_pol_bin_obj, .obj_cmpfn = xfrm_pol_bin_cmp, .automatic_shrinking = true, }; static void xfrm_policy_insert_inexact_list(struct hlist_head *chain, struct xfrm_policy *policy) { struct xfrm_policy *pol, *delpol = NULL; struct hlist_node *newpos = NULL; |
6be3b0db6 xfrm: policy: add... |
1398 |
int i = 0; |
24969facd xfrm: policy: sto... |
1399 1400 1401 1402 1403 |
hlist_for_each_entry(pol, chain, bydst_inexact_list) { if (pol->type == policy->type && pol->if_id == policy->if_id && !selector_cmp(&pol->selector, &policy->selector) && |
4f47e8ab6 xfrm: policy: mat... |
1404 |
xfrm_policy_mark_match(&policy->mark, pol) && |
24969facd xfrm: policy: sto... |
1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 |
xfrm_sec_ctx_match(pol->security, policy->security) && !WARN_ON(delpol)) { delpol = pol; if (policy->priority > pol->priority) continue; } else if (policy->priority >= pol->priority) { newpos = &pol->bydst_inexact_list; continue; } if (delpol) break; } if (newpos) hlist_add_behind_rcu(&policy->bydst_inexact_list, newpos); else hlist_add_head_rcu(&policy->bydst_inexact_list, chain); |
6be3b0db6 xfrm: policy: add... |
1422 1423 1424 1425 1426 |
hlist_for_each_entry(pol, chain, bydst_inexact_list) { pol->pos = i; i++; } |
24969facd xfrm: policy: sto... |
1427 |
} |
a927d6af5 xfrm: policy: spl... |
1428 1429 1430 |
static struct xfrm_policy *xfrm_policy_insert_list(struct hlist_head *chain, struct xfrm_policy *policy, bool excl) |
1da177e4c Linux-2.6.12-rc2 |
1431 |
{ |
a927d6af5 xfrm: policy: spl... |
1432 |
struct xfrm_policy *pol, *newpos = NULL, *delpol = NULL; |
1da177e4c Linux-2.6.12-rc2 |
1433 |
|
b67bfe0d4 hlist: drop the n... |
1434 |
hlist_for_each_entry(pol, chain, bydst) { |
a6c7ab55d [IPSEC]: Policy l... |
1435 |
if (pol->type == policy->type && |
7e6526404 xfrm: Add a new l... |
1436 |
pol->if_id == policy->if_id && |
2518c7c2b [XFRM]: Hash poli... |
1437 |
!selector_cmp(&pol->selector, &policy->selector) && |
4f47e8ab6 xfrm: policy: mat... |
1438 |
xfrm_policy_mark_match(&policy->mark, pol) && |
a6c7ab55d [IPSEC]: Policy l... |
1439 1440 |
xfrm_sec_ctx_match(pol->security, policy->security) && !WARN_ON(delpol)) { |
a927d6af5 xfrm: policy: spl... |
1441 1442 |
if (excl) return ERR_PTR(-EEXIST); |
1da177e4c Linux-2.6.12-rc2 |
1443 1444 1445 1446 |
delpol = pol; if (policy->priority > pol->priority) continue; } else if (policy->priority >= pol->priority) { |
a927d6af5 xfrm: policy: spl... |
1447 |
newpos = pol; |
1da177e4c Linux-2.6.12-rc2 |
1448 1449 |
continue; } |
1da177e4c Linux-2.6.12-rc2 |
1450 1451 |
if (delpol) break; |
1da177e4c Linux-2.6.12-rc2 |
1452 |
} |
24969facd xfrm: policy: sto... |
1453 |
|
1da177e4c Linux-2.6.12-rc2 |
1454 |
if (newpos) |
a927d6af5 xfrm: policy: spl... |
1455 |
hlist_add_behind_rcu(&policy->bydst, &newpos->bydst); |
2518c7c2b [XFRM]: Hash poli... |
1456 |
else |
9dffff200 xfrm: policy: use... |
1457 |
hlist_add_head_rcu(&policy->bydst, chain); |
a927d6af5 xfrm: policy: spl... |
1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 |
return delpol; } int xfrm_policy_insert(int dir, struct xfrm_policy *policy, int excl) { struct net *net = xp_net(policy); struct xfrm_policy *delpol; struct hlist_head *chain; spin_lock_bh(&net->xfrm.xfrm_policy_lock); chain = policy_hash_bysel(net, &policy->selector, policy->family, dir); |
24969facd xfrm: policy: sto... |
1470 |
if (chain) |
cc1bb845a xfrm: policy: ret... |
1471 |
delpol = xfrm_policy_insert_list(chain, policy, excl); |
24969facd xfrm: policy: sto... |
1472 1473 |
else delpol = xfrm_policy_inexact_insert(policy, dir, excl); |
a927d6af5 xfrm: policy: spl... |
1474 1475 1476 1477 1478 |
if (IS_ERR(delpol)) { spin_unlock_bh(&net->xfrm.xfrm_policy_lock); return PTR_ERR(delpol); } |
12bfa8bdb xfrm: Use __xfrm_... |
1479 |
__xfrm_policy_link(policy, dir); |
ca4c3fc24 net: split rt_gen... |
1480 1481 1482 1483 1484 1485 |
/* After previous checking, family can either be AF_INET or AF_INET6 */ if (policy->family == AF_INET) rt_genid_bump_ipv4(net); else rt_genid_bump_ipv6(net); |
a0073fe18 xfrm: Add a state... |
1486 1487 |
if (delpol) { xfrm_policy_requeue(delpol, policy); |
29fa0b301 xfrm: Cleanup for... |
1488 |
__xfrm_policy_unlink(delpol, dir); |
a0073fe18 xfrm: Add a state... |
1489 |
} |
e682adf02 xfrm: Try to hono... |
1490 |
policy->index = delpol ? delpol->index : xfrm_gen_index(net, dir, policy->index); |
1121994c8 netns xfrm: polic... |
1491 |
hlist_add_head(&policy->byidx, net->xfrm.policy_byidx+idx_hash(net, policy->index)); |
386c5680e xfrm: use time64_... |
1492 |
policy->curlft.add_time = ktime_get_real_seconds(); |
1da177e4c Linux-2.6.12-rc2 |
1493 1494 1495 |
policy->curlft.use_time = 0; if (!mod_timer(&policy->timer, jiffies + HZ)) xfrm_pol_hold(policy); |
9d0380df6 xfrm: policy: con... |
1496 |
spin_unlock_bh(&net->xfrm.xfrm_policy_lock); |
1da177e4c Linux-2.6.12-rc2 |
1497 |
|
9b78a82c1 [IPSEC]: Fix poli... |
1498 |
if (delpol) |
1da177e4c Linux-2.6.12-rc2 |
1499 |
xfrm_policy_kill(delpol); |
1121994c8 netns xfrm: polic... |
1500 1501 |
else if (xfrm_bydst_should_resize(net, dir, NULL)) schedule_work(&net->xfrm.policy_hash_work); |
9b78a82c1 [IPSEC]: Fix poli... |
1502 |
|
1da177e4c Linux-2.6.12-rc2 |
1503 1504 1505 |
return 0; } EXPORT_SYMBOL(xfrm_policy_insert); |
6be3b0db6 xfrm: policy: add... |
1506 |
static struct xfrm_policy * |
4f47e8ab6 xfrm: policy: mat... |
1507 1508 |
__xfrm_policy_bysel_ctx(struct hlist_head *chain, const struct xfrm_mark *mark, u32 if_id, u8 type, int dir, struct xfrm_selector *sel, |
6be3b0db6 xfrm: policy: add... |
1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 |
struct xfrm_sec_ctx *ctx) { struct xfrm_policy *pol; if (!chain) return NULL; hlist_for_each_entry(pol, chain, bydst) { if (pol->type == type && pol->if_id == if_id && |
4f47e8ab6 xfrm: policy: mat... |
1519 |
xfrm_policy_mark_match(mark, pol) && |
6be3b0db6 xfrm: policy: add... |
1520 1521 1522 1523 1524 1525 1526 |
!selector_cmp(sel, &pol->selector) && xfrm_sec_ctx_match(ctx, pol->security)) return pol; } return NULL; } |
4f47e8ab6 xfrm: policy: mat... |
1527 1528 1529 1530 |
struct xfrm_policy * xfrm_policy_bysel_ctx(struct net *net, const struct xfrm_mark *mark, u32 if_id, u8 type, int dir, struct xfrm_selector *sel, struct xfrm_sec_ctx *ctx, int delete, int *err) |
1da177e4c Linux-2.6.12-rc2 |
1531 |
{ |
24969facd xfrm: policy: sto... |
1532 1533 |
struct xfrm_pol_inexact_bin *bin = NULL; struct xfrm_policy *pol, *ret = NULL; |
2518c7c2b [XFRM]: Hash poli... |
1534 |
struct hlist_head *chain; |
1da177e4c Linux-2.6.12-rc2 |
1535 |
|
ef41aaa0b [IPSEC]: xfrm_pol... |
1536 |
*err = 0; |
9d0380df6 xfrm: policy: con... |
1537 |
spin_lock_bh(&net->xfrm.xfrm_policy_lock); |
8d1211a6a netns xfrm: findi... |
1538 |
chain = policy_hash_bysel(net, sel, sel->family, dir); |
24969facd xfrm: policy: sto... |
1539 |
if (!chain) { |
6be3b0db6 xfrm: policy: add... |
1540 1541 |
struct xfrm_pol_inexact_candidates cand; int i; |
24969facd xfrm: policy: sto... |
1542 |
bin = xfrm_policy_inexact_lookup(net, type, |
b5fe22e23 xfrm: policy: con... |
1543 |
sel->family, dir, if_id); |
24969facd xfrm: policy: sto... |
1544 1545 1546 1547 |
if (!bin) { spin_unlock_bh(&net->xfrm.xfrm_policy_lock); return NULL; } |
6be3b0db6 xfrm: policy: add... |
1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 |
if (!xfrm_policy_find_inexact_candidates(&cand, bin, &sel->saddr, &sel->daddr)) { spin_unlock_bh(&net->xfrm.xfrm_policy_lock); return NULL; } pol = NULL; for (i = 0; i < ARRAY_SIZE(cand.res); i++) { struct xfrm_policy *tmp; tmp = __xfrm_policy_bysel_ctx(cand.res[i], mark, if_id, type, dir, sel, ctx); |
39aa6928d xfrm: policy: fix... |
1562 1563 1564 1565 |
if (!tmp) continue; if (!pol || tmp->pos < pol->pos) |
6be3b0db6 xfrm: policy: add... |
1566 1567 1568 1569 1570 |
pol = tmp; } } else { pol = __xfrm_policy_bysel_ctx(chain, mark, if_id, type, dir, sel, ctx); |
24969facd xfrm: policy: sto... |
1571 |
} |
6be3b0db6 xfrm: policy: add... |
1572 1573 1574 1575 1576 1577 1578 |
if (pol) { xfrm_pol_hold(pol); if (delete) { *err = security_xfrm_policy_delete(pol->security); if (*err) { spin_unlock_bh(&net->xfrm.xfrm_policy_lock); return pol; |
2518c7c2b [XFRM]: Hash poli... |
1579 |
} |
6be3b0db6 xfrm: policy: add... |
1580 |
__xfrm_policy_unlink(pol, dir); |
1da177e4c Linux-2.6.12-rc2 |
1581 |
} |
6be3b0db6 xfrm: policy: add... |
1582 |
ret = pol; |
1da177e4c Linux-2.6.12-rc2 |
1583 |
} |
9d0380df6 xfrm: policy: con... |
1584 |
spin_unlock_bh(&net->xfrm.xfrm_policy_lock); |
1da177e4c Linux-2.6.12-rc2 |
1585 |
|
fe1a5f031 flow: virtualize ... |
1586 |
if (ret && delete) |
2518c7c2b [XFRM]: Hash poli... |
1587 |
xfrm_policy_kill(ret); |
6be3b0db6 xfrm: policy: add... |
1588 1589 |
if (bin && delete) xfrm_policy_inexact_prune_bin(bin); |
2518c7c2b [XFRM]: Hash poli... |
1590 |
return ret; |
1da177e4c Linux-2.6.12-rc2 |
1591 |
} |
df71837d5 [LSM-IPSec]: Secu... |
1592 |
EXPORT_SYMBOL(xfrm_policy_bysel_ctx); |
1da177e4c Linux-2.6.12-rc2 |
1593 |
|
4f47e8ab6 xfrm: policy: mat... |
1594 1595 1596 |
struct xfrm_policy * xfrm_policy_byid(struct net *net, const struct xfrm_mark *mark, u32 if_id, u8 type, int dir, u32 id, int delete, int *err) |
1da177e4c Linux-2.6.12-rc2 |
1597 |
{ |
2518c7c2b [XFRM]: Hash poli... |
1598 1599 |
struct xfrm_policy *pol, *ret; struct hlist_head *chain; |
1da177e4c Linux-2.6.12-rc2 |
1600 |
|
b5505c6e1 [IPSEC]: Check va... |
1601 1602 1603 |
*err = -ENOENT; if (xfrm_policy_id2dir(id) != dir) return NULL; |
ef41aaa0b [IPSEC]: xfrm_pol... |
1604 |
*err = 0; |
9d0380df6 xfrm: policy: con... |
1605 |
spin_lock_bh(&net->xfrm.xfrm_policy_lock); |
8d1211a6a netns xfrm: findi... |
1606 |
chain = net->xfrm.policy_byidx + idx_hash(net, id); |
2518c7c2b [XFRM]: Hash poli... |
1607 |
ret = NULL; |
b67bfe0d4 hlist: drop the n... |
1608 |
hlist_for_each_entry(pol, chain, byidx) { |
34f8d8846 xfrm: SP lookups ... |
1609 |
if (pol->type == type && pol->index == id && |
4f47e8ab6 xfrm: policy: mat... |
1610 |
pol->if_id == if_id && xfrm_policy_mark_match(mark, pol)) { |
1da177e4c Linux-2.6.12-rc2 |
1611 |
xfrm_pol_hold(pol); |
2518c7c2b [XFRM]: Hash poli... |
1612 |
if (delete) { |
03e1ad7b5 LSM: Make the Lab... |
1613 1614 |
*err = security_xfrm_policy_delete( pol->security); |
ef41aaa0b [IPSEC]: xfrm_pol... |
1615 |
if (*err) { |
9d0380df6 xfrm: policy: con... |
1616 |
spin_unlock_bh(&net->xfrm.xfrm_policy_lock); |
ef41aaa0b [IPSEC]: xfrm_pol... |
1617 1618 |
return pol; } |
29fa0b301 xfrm: Cleanup for... |
1619 |
__xfrm_policy_unlink(pol, dir); |
2518c7c2b [XFRM]: Hash poli... |
1620 1621 |
} ret = pol; |
1da177e4c Linux-2.6.12-rc2 |
1622 1623 1624 |
break; } } |
9d0380df6 xfrm: policy: con... |
1625 |
spin_unlock_bh(&net->xfrm.xfrm_policy_lock); |
1da177e4c Linux-2.6.12-rc2 |
1626 |
|
fe1a5f031 flow: virtualize ... |
1627 |
if (ret && delete) |
2518c7c2b [XFRM]: Hash poli... |
1628 |
xfrm_policy_kill(ret); |
2518c7c2b [XFRM]: Hash poli... |
1629 |
return ret; |
1da177e4c Linux-2.6.12-rc2 |
1630 1631 |
} EXPORT_SYMBOL(xfrm_policy_byid); |
4aa2e62c4 xfrm: Add securit... |
1632 1633 |
#ifdef CONFIG_SECURITY_NETWORK_XFRM static inline int |
2e71029e2 xfrm: Remove usel... |
1634 |
xfrm_policy_flush_secctx_check(struct net *net, u8 type, bool task_valid) |
1da177e4c Linux-2.6.12-rc2 |
1635 |
{ |
ceb159e30 xfrm: security: i... |
1636 1637 |
struct xfrm_policy *pol; int err = 0; |
4aa2e62c4 xfrm: Add securit... |
1638 |
|
ceb159e30 xfrm: security: i... |
1639 1640 1641 1642 1643 |
list_for_each_entry(pol, &net->xfrm.policy_all, walk.all) { if (pol->walk.dead || xfrm_policy_id2dir(pol->index) >= XFRM_POLICY_MAX || pol->type != type) continue; |
4aa2e62c4 xfrm: Add securit... |
1644 |
|
ceb159e30 xfrm: security: i... |
1645 1646 1647 1648 |
err = security_xfrm_policy_delete(pol->security); if (err) { xfrm_audit_policy_delete(pol, 0, task_valid); return err; |
4aa2e62c4 xfrm: Add securit... |
1649 1650 1651 1652 1653 1654 |
} } return err; } #else static inline int |
2e71029e2 xfrm: Remove usel... |
1655 |
xfrm_policy_flush_secctx_check(struct net *net, u8 type, bool task_valid) |
4aa2e62c4 xfrm: Add securit... |
1656 1657 1658 1659 |
{ return 0; } #endif |
2e71029e2 xfrm: Remove usel... |
1660 |
int xfrm_policy_flush(struct net *net, u8 type, bool task_valid) |
4aa2e62c4 xfrm: Add securit... |
1661 |
{ |
2f1eb65f3 xfrm: Flushing em... |
1662 |
int dir, err = 0, cnt = 0; |
ceb159e30 xfrm: security: i... |
1663 |
struct xfrm_policy *pol; |
1da177e4c Linux-2.6.12-rc2 |
1664 |
|
9d0380df6 xfrm: policy: con... |
1665 |
spin_lock_bh(&net->xfrm.xfrm_policy_lock); |
4aa2e62c4 xfrm: Add securit... |
1666 |
|
2e71029e2 xfrm: Remove usel... |
1667 |
err = xfrm_policy_flush_secctx_check(net, type, task_valid); |
4aa2e62c4 xfrm: Add securit... |
1668 1669 |
if (err) goto out; |
ceb159e30 xfrm: security: i... |
1670 1671 1672 1673 1674 1675 1676 |
again: list_for_each_entry(pol, &net->xfrm.policy_all, walk.all) { dir = xfrm_policy_id2dir(pol->index); if (pol->walk.dead || dir >= XFRM_POLICY_MAX || pol->type != type) continue; |
2518c7c2b [XFRM]: Hash poli... |
1677 |
|
ceb159e30 xfrm: security: i... |
1678 1679 1680 1681 1682 1683 1684 |
__xfrm_policy_unlink(pol, dir); spin_unlock_bh(&net->xfrm.xfrm_policy_lock); cnt++; xfrm_audit_policy_delete(pol, 1, task_valid); xfrm_policy_kill(pol); spin_lock_bh(&net->xfrm.xfrm_policy_lock); goto again; |
1da177e4c Linux-2.6.12-rc2 |
1685 |
} |
24969facd xfrm: policy: sto... |
1686 1687 1688 |
if (cnt) __xfrm_policy_inexact_flush(net); else |
2f1eb65f3 xfrm: Flushing em... |
1689 |
err = -ESRCH; |
4aa2e62c4 xfrm: Add securit... |
1690 |
out: |
9d0380df6 xfrm: policy: con... |
1691 |
spin_unlock_bh(&net->xfrm.xfrm_policy_lock); |
4aa2e62c4 xfrm: Add securit... |
1692 |
return err; |
1da177e4c Linux-2.6.12-rc2 |
1693 1694 |
} EXPORT_SYMBOL(xfrm_policy_flush); |
cdcbca7c1 netns xfrm: polic... |
1695 |
int xfrm_policy_walk(struct net *net, struct xfrm_policy_walk *walk, |
4c563f766 [XFRM]: Speed up ... |
1696 |
int (*func)(struct xfrm_policy *, int, int, void*), |
1da177e4c Linux-2.6.12-rc2 |
1697 1698 |
void *data) { |
12a169e7d ipsec: Put dumper... |
1699 1700 |
struct xfrm_policy *pol; struct xfrm_policy_walk_entry *x; |
4c563f766 [XFRM]: Speed up ... |
1701 1702 1703 1704 1705 |
int error = 0; if (walk->type >= XFRM_POLICY_TYPE_MAX && walk->type != XFRM_POLICY_TYPE_ANY) return -EINVAL; |
1da177e4c Linux-2.6.12-rc2 |
1706 |
|
12a169e7d ipsec: Put dumper... |
1707 |
if (list_empty(&walk->walk.all) && walk->seq != 0) |
4c563f766 [XFRM]: Speed up ... |
1708 |
return 0; |
9d0380df6 xfrm: policy: con... |
1709 |
spin_lock_bh(&net->xfrm.xfrm_policy_lock); |
12a169e7d ipsec: Put dumper... |
1710 |
if (list_empty(&walk->walk.all)) |
cdcbca7c1 netns xfrm: polic... |
1711 |
x = list_first_entry(&net->xfrm.policy_all, struct xfrm_policy_walk_entry, all); |
12a169e7d ipsec: Put dumper... |
1712 |
else |
800777026 xfrm: optimise th... |
1713 1714 |
x = list_first_entry(&walk->walk.all, struct xfrm_policy_walk_entry, all); |
cdcbca7c1 netns xfrm: polic... |
1715 |
list_for_each_entry_from(x, &net->xfrm.policy_all, all) { |
12a169e7d ipsec: Put dumper... |
1716 |
if (x->dead) |
4c563f766 [XFRM]: Speed up ... |
1717 |
continue; |
12a169e7d ipsec: Put dumper... |
1718 1719 1720 1721 1722 1723 1724 1725 1726 |
pol = container_of(x, struct xfrm_policy, walk); if (walk->type != XFRM_POLICY_TYPE_ANY && walk->type != pol->type) continue; error = func(pol, xfrm_policy_id2dir(pol->index), walk->seq, data); if (error) { list_move_tail(&walk->walk.all, &x->all); goto out; |
2518c7c2b [XFRM]: Hash poli... |
1727 |
} |
12a169e7d ipsec: Put dumper... |
1728 |
walk->seq++; |
1da177e4c Linux-2.6.12-rc2 |
1729 |
} |
12a169e7d ipsec: Put dumper... |
1730 |
if (walk->seq == 0) { |
baf5d743d [XFRM] Optimize p... |
1731 1732 1733 |
error = -ENOENT; goto out; } |
12a169e7d ipsec: Put dumper... |
1734 |
list_del_init(&walk->walk.all); |
1da177e4c Linux-2.6.12-rc2 |
1735 |
out: |
9d0380df6 xfrm: policy: con... |
1736 |
spin_unlock_bh(&net->xfrm.xfrm_policy_lock); |
1da177e4c Linux-2.6.12-rc2 |
1737 1738 1739 |
return error; } EXPORT_SYMBOL(xfrm_policy_walk); |
12a169e7d ipsec: Put dumper... |
1740 1741 1742 1743 1744 1745 1746 1747 |
void xfrm_policy_walk_init(struct xfrm_policy_walk *walk, u8 type) { INIT_LIST_HEAD(&walk->walk.all); walk->walk.dead = 1; walk->type = type; walk->seq = 0; } EXPORT_SYMBOL(xfrm_policy_walk_init); |
283bc9f35 xfrm: Namespacify... |
1748 |
void xfrm_policy_walk_done(struct xfrm_policy_walk *walk, struct net *net) |
12a169e7d ipsec: Put dumper... |
1749 1750 1751 |
{ if (list_empty(&walk->walk.all)) return; |
9d0380df6 xfrm: policy: con... |
1752 |
spin_lock_bh(&net->xfrm.xfrm_policy_lock); /*FIXME where is net? */ |
12a169e7d ipsec: Put dumper... |
1753 |
list_del(&walk->walk.all); |
9d0380df6 xfrm: policy: con... |
1754 |
spin_unlock_bh(&net->xfrm.xfrm_policy_lock); |
12a169e7d ipsec: Put dumper... |
1755 1756 |
} EXPORT_SYMBOL(xfrm_policy_walk_done); |
134b0fc54 IPsec: propagate ... |
1757 1758 1759 1760 1761 |
/* * Find policy to apply to this flow. * * Returns 0 if policy found, else an -errno. */ |
f299d557c xfrm: Const'ify p... |
1762 1763 |
static int xfrm_policy_match(const struct xfrm_policy *pol, const struct flowi *fl, |
bc56b3340 xfrm: Remove xfrm... |
1764 |
u8 type, u16 family, int dir, u32 if_id) |
1da177e4c Linux-2.6.12-rc2 |
1765 |
{ |
f299d557c xfrm: Const'ify p... |
1766 |
const struct xfrm_selector *sel = &pol->selector; |
bc9b35ad4 xfrm: Convert sev... |
1767 1768 |
int ret = -ESRCH; bool match; |
1da177e4c Linux-2.6.12-rc2 |
1769 |
|
2518c7c2b [XFRM]: Hash poli... |
1770 |
if (pol->family != family || |
bc56b3340 xfrm: Remove xfrm... |
1771 |
pol->if_id != if_id || |
1d28f42c1 net: Put flowi_* ... |
1772 |
(fl->flowi_mark & pol->mark.m) != pol->mark.v || |
2518c7c2b [XFRM]: Hash poli... |
1773 |
pol->type != type) |
134b0fc54 IPsec: propagate ... |
1774 |
return ret; |
1da177e4c Linux-2.6.12-rc2 |
1775 |
|
2518c7c2b [XFRM]: Hash poli... |
1776 |
match = xfrm_selector_match(sel, fl, family); |
134b0fc54 IPsec: propagate ... |
1777 |
if (match) |
1d28f42c1 net: Put flowi_* ... |
1778 |
ret = security_xfrm_policy_lookup(pol->security, fl->flowi_secid, |
03e1ad7b5 LSM: Make the Lab... |
1779 |
dir); |
134b0fc54 IPsec: propagate ... |
1780 |
return ret; |
2518c7c2b [XFRM]: Hash poli... |
1781 |
} |
1da177e4c Linux-2.6.12-rc2 |
1782 |
|
9cf545ebd xfrm: policy: sto... |
1783 1784 |
static struct xfrm_pol_inexact_node * xfrm_policy_lookup_inexact_addr(const struct rb_root *r, |
77cc278f7 xfrm: policy: Use... |
1785 |
seqcount_spinlock_t *count, |
9cf545ebd xfrm: policy: sto... |
1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 |
const xfrm_address_t *addr, u16 family) { const struct rb_node *parent; int seq; again: seq = read_seqcount_begin(count); parent = rcu_dereference_raw(r->rb_node); while (parent) { struct xfrm_pol_inexact_node *node; int delta; node = rb_entry(parent, struct xfrm_pol_inexact_node, node); delta = xfrm_policy_addr_delta(addr, &node->addr, node->prefixlen, family); if (delta < 0) { parent = rcu_dereference_raw(parent->rb_left); continue; } else if (delta > 0) { parent = rcu_dereference_raw(parent->rb_right); continue; } return node; } if (read_seqcount_retry(count, seq)) goto again; return NULL; } |
6be3b0db6 xfrm: policy: add... |
1819 1820 1821 1822 1823 1824 |
static bool xfrm_policy_find_inexact_candidates(struct xfrm_pol_inexact_candidates *cand, struct xfrm_pol_inexact_bin *b, const xfrm_address_t *saddr, const xfrm_address_t *daddr) { |
9cf545ebd xfrm: policy: sto... |
1825 1826 |
struct xfrm_pol_inexact_node *n; u16 family; |
6be3b0db6 xfrm: policy: add... |
1827 1828 |
if (!b) return false; |
9cf545ebd xfrm: policy: sto... |
1829 |
family = b->k.family; |
6be3b0db6 xfrm: policy: add... |
1830 1831 |
memset(cand, 0, sizeof(*cand)); cand->res[XFRM_POL_CAND_ANY] = &b->hhead; |
9cf545ebd xfrm: policy: sto... |
1832 1833 1834 |
n = xfrm_policy_lookup_inexact_addr(&b->root_d, &b->count, daddr, family); |
6ac098b2a xfrm: policy: add... |
1835 |
if (n) { |
9cf545ebd xfrm: policy: sto... |
1836 |
cand->res[XFRM_POL_CAND_DADDR] = &n->hhead; |
6ac098b2a xfrm: policy: add... |
1837 1838 1839 1840 1841 |
n = xfrm_policy_lookup_inexact_addr(&n->root, &b->count, saddr, family); if (n) cand->res[XFRM_POL_CAND_BOTH] = &n->hhead; } |
9cf545ebd xfrm: policy: sto... |
1842 |
|
64a09a7bf xfrm: policy: sto... |
1843 1844 1845 1846 |
n = xfrm_policy_lookup_inexact_addr(&b->root_s, &b->count, saddr, family); if (n) cand->res[XFRM_POL_CAND_SADDR] = &n->hhead; |
6be3b0db6 xfrm: policy: add... |
1847 1848 |
return true; } |
24969facd xfrm: policy: sto... |
1849 |
static struct xfrm_pol_inexact_bin * |
b5fe22e23 xfrm: policy: con... |
1850 1851 |
xfrm_policy_inexact_lookup_rcu(struct net *net, u8 type, u16 family, u8 dir, u32 if_id) |
24969facd xfrm: policy: sto... |
1852 1853 1854 1855 1856 |
{ struct xfrm_pol_inexact_key k = { .family = family, .type = type, .dir = dir, |
b5fe22e23 xfrm: policy: con... |
1857 |
.if_id = if_id, |
24969facd xfrm: policy: sto... |
1858 1859 1860 1861 1862 1863 1864 1865 1866 |
}; write_pnet(&k.net, net); return rhashtable_lookup(&xfrm_policy_inexact_table, &k, xfrm_pol_inexact_params); } static struct xfrm_pol_inexact_bin * |
b5fe22e23 xfrm: policy: con... |
1867 1868 |
xfrm_policy_inexact_lookup(struct net *net, u8 type, u16 family, u8 dir, u32 if_id) |
24969facd xfrm: policy: sto... |
1869 1870 1871 1872 1873 1874 |
{ struct xfrm_pol_inexact_bin *bin; lockdep_assert_held(&net->xfrm.xfrm_policy_lock); rcu_read_lock(); |
b5fe22e23 xfrm: policy: con... |
1875 |
bin = xfrm_policy_inexact_lookup_rcu(net, type, family, dir, if_id); |
24969facd xfrm: policy: sto... |
1876 1877 1878 1879 |
rcu_read_unlock(); return bin; } |
6be3b0db6 xfrm: policy: add... |
1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 |
static struct xfrm_policy * __xfrm_policy_eval_candidates(struct hlist_head *chain, struct xfrm_policy *prefer, const struct flowi *fl, u8 type, u16 family, int dir, u32 if_id) { u32 priority = prefer ? prefer->priority : ~0u; struct xfrm_policy *pol; if (!chain) return NULL; hlist_for_each_entry_rcu(pol, chain, bydst) { int err; if (pol->priority > priority) break; err = xfrm_policy_match(pol, fl, type, family, dir, if_id); if (err) { if (err != -ESRCH) return ERR_PTR(err); continue; } if (prefer) { /* matches. Is it older than *prefer? */ if (pol->priority == priority && prefer->pos < pol->pos) return prefer; } return pol; } return NULL; } static struct xfrm_policy * xfrm_policy_eval_candidates(struct xfrm_pol_inexact_candidates *cand, struct xfrm_policy *prefer, const struct flowi *fl, u8 type, u16 family, int dir, u32 if_id) { struct xfrm_policy *tmp; int i; for (i = 0; i < ARRAY_SIZE(cand->res); i++) { tmp = __xfrm_policy_eval_candidates(cand->res[i], prefer, fl, type, family, dir, if_id); if (!tmp) continue; if (IS_ERR(tmp)) return tmp; prefer = tmp; } return prefer; } |
52479b623 netns xfrm: looku... |
1943 |
static struct xfrm_policy *xfrm_policy_lookup_bytype(struct net *net, u8 type, |
062cdb43b xfrm: Mark flowi ... |
1944 |
const struct flowi *fl, |
bc56b3340 xfrm: Remove xfrm... |
1945 1946 |
u16 family, u8 dir, u32 if_id) |
2518c7c2b [XFRM]: Hash poli... |
1947 |
{ |
6be3b0db6 xfrm: policy: add... |
1948 |
struct xfrm_pol_inexact_candidates cand; |
0b597e7ed xfrm: Const'ify l... |
1949 |
const xfrm_address_t *daddr, *saddr; |
24969facd xfrm: policy: sto... |
1950 1951 |
struct xfrm_pol_inexact_bin *bin; struct xfrm_policy *pol, *ret; |
2518c7c2b [XFRM]: Hash poli... |
1952 |
struct hlist_head *chain; |
30846090a xfrm: policy: add... |
1953 |
unsigned int sequence; |
24969facd xfrm: policy: sto... |
1954 |
int err; |
df71837d5 [LSM-IPSec]: Secu... |
1955 |
|
2518c7c2b [XFRM]: Hash poli... |
1956 1957 1958 1959 |
daddr = xfrm_flowi_daddr(fl, family); saddr = xfrm_flowi_saddr(fl, family); if (unlikely(!daddr || !saddr)) return NULL; |
a7c44247f xfrm: policy: mak... |
1960 |
rcu_read_lock(); |
30846090a xfrm: policy: add... |
1961 1962 1963 1964 1965 |
retry: do { sequence = read_seqcount_begin(&xfrm_policy_hash_generation); chain = policy_hash_direct(net, daddr, saddr, family, dir); } while (read_seqcount_retry(&xfrm_policy_hash_generation, sequence)); |
2518c7c2b [XFRM]: Hash poli... |
1966 |
ret = NULL; |
a5eefc1df xfrm: policy: use... |
1967 |
hlist_for_each_entry_rcu(pol, chain, bydst) { |
bc56b3340 xfrm: Remove xfrm... |
1968 |
err = xfrm_policy_match(pol, fl, type, family, dir, if_id); |
134b0fc54 IPsec: propagate ... |
1969 1970 1971 1972 1973 1974 1975 1976 |
if (err) { if (err == -ESRCH) continue; else { ret = ERR_PTR(err); goto fail; } } else { |
2518c7c2b [XFRM]: Hash poli... |
1977 1978 1979 1980 |
ret = pol; break; } } |
b5fe22e23 xfrm: policy: con... |
1981 |
bin = xfrm_policy_inexact_lookup_rcu(net, type, family, dir, if_id); |
6be3b0db6 xfrm: policy: add... |
1982 1983 |
if (!bin || !xfrm_policy_find_inexact_candidates(&cand, bin, saddr, daddr)) |
24969facd xfrm: policy: sto... |
1984 |
goto skip_inexact; |
8faf491e6 xfrm: optimise to... |
1985 |
|
6be3b0db6 xfrm: policy: add... |
1986 1987 1988 1989 1990 1991 |
pol = xfrm_policy_eval_candidates(&cand, ret, fl, type, family, dir, if_id); if (pol) { ret = pol; if (IS_ERR(pol)) goto fail; |
1da177e4c Linux-2.6.12-rc2 |
1992 |
} |
586f2eb41 xfrm: remove the ... |
1993 |
|
24969facd xfrm: policy: sto... |
1994 |
skip_inexact: |
30846090a xfrm: policy: add... |
1995 1996 |
if (read_seqcount_retry(&xfrm_policy_hash_generation, sequence)) goto retry; |
e37cc8ade xfrm: policy: use... |
1997 1998 |
if (ret && !xfrm_pol_hold_rcu(ret)) goto retry; |
134b0fc54 IPsec: propagate ... |
1999 |
fail: |
a7c44247f xfrm: policy: mak... |
2000 |
rcu_read_unlock(); |
4e81bb833 [XFRM] POLICY: su... |
2001 |
|
2518c7c2b [XFRM]: Hash poli... |
2002 |
return ret; |
4e81bb833 [XFRM] POLICY: su... |
2003 |
} |
bc56b3340 xfrm: Remove xfrm... |
2004 2005 2006 |
static struct xfrm_policy *xfrm_policy_lookup(struct net *net, const struct flowi *fl, u16 family, u8 dir, u32 if_id) |
80c802f30 xfrm: cache bundl... |
2007 2008 2009 |
{ #ifdef CONFIG_XFRM_SUB_POLICY struct xfrm_policy *pol; |
bc56b3340 xfrm: Remove xfrm... |
2010 2011 |
pol = xfrm_policy_lookup_bytype(net, XFRM_POLICY_TYPE_SUB, fl, family, dir, if_id); |
80c802f30 xfrm: cache bundl... |
2012 2013 2014 |
if (pol != NULL) return pol; #endif |
bc56b3340 xfrm: Remove xfrm... |
2015 2016 |
return xfrm_policy_lookup_bytype(net, XFRM_POLICY_TYPE_MAIN, fl, family, dir, if_id); |
80c802f30 xfrm: cache bundl... |
2017 |
} |
6f9c96154 inet: constify ip... |
2018 |
static struct xfrm_policy *xfrm_sk_policy_lookup(const struct sock *sk, int dir, |
bc56b3340 xfrm: Remove xfrm... |
2019 2020 |
const struct flowi *fl, u16 family, u32 if_id) |
1da177e4c Linux-2.6.12-rc2 |
2021 2022 |
{ struct xfrm_policy *pol; |
d188ba86d xfrm: add rcu pro... |
2023 |
rcu_read_lock(); |
ae33786f7 xfrm: policy: onl... |
2024 |
again: |
d188ba86d xfrm: add rcu pro... |
2025 2026 |
pol = rcu_dereference(sk->sk_policy[dir]); if (pol != NULL) { |
ddc47e440 xfrm: Fix stack-o... |
2027 |
bool match; |
a716c1197 [NET] XFRM: Fix w... |
2028 |
int err = 0; |
df71837d5 [LSM-IPSec]: Secu... |
2029 |
|
ddc47e440 xfrm: Fix stack-o... |
2030 2031 2032 2033 2034 2035 |
if (pol->family != family) { pol = NULL; goto out; } match = xfrm_selector_match(&pol->selector, fl, family); |
3bccfbc7a IPsec: fix handli... |
2036 |
if (match) { |
7e6526404 xfrm: Add a new l... |
2037 |
if ((sk->sk_mark & pol->mark.m) != pol->mark.v || |
bc56b3340 xfrm: Remove xfrm... |
2038 |
pol->if_id != if_id) { |
34f8d8846 xfrm: SP lookups ... |
2039 2040 2041 |
pol = NULL; goto out; } |
03e1ad7b5 LSM: Make the Lab... |
2042 |
err = security_xfrm_policy_lookup(pol->security, |
1d28f42c1 net: Put flowi_* ... |
2043 |
fl->flowi_secid, |
aff669bc2 xfrm_policy: kill... |
2044 |
dir); |
330e832ab xfrm: unbreak xfr... |
2045 2046 2047 2048 |
if (!err) { if (!xfrm_pol_hold_rcu(pol)) goto again; } else if (err == -ESRCH) { |
3bccfbc7a IPsec: fix handli... |
2049 |
pol = NULL; |
330e832ab xfrm: unbreak xfr... |
2050 |
} else { |
3bccfbc7a IPsec: fix handli... |
2051 |
pol = ERR_PTR(err); |
330e832ab xfrm: unbreak xfr... |
2052 |
} |
3bccfbc7a IPsec: fix handli... |
2053 |
} else |
1da177e4c Linux-2.6.12-rc2 |
2054 2055 |
pol = NULL; } |
34f8d8846 xfrm: SP lookups ... |
2056 |
out: |
d188ba86d xfrm: add rcu pro... |
2057 |
rcu_read_unlock(); |
1da177e4c Linux-2.6.12-rc2 |
2058 2059 2060 2061 2062 |
return pol; } static void __xfrm_policy_link(struct xfrm_policy *pol, int dir) { |
98806f75b netns xfrm: trivi... |
2063 |
struct net *net = xp_net(pol); |
4e81bb833 [XFRM] POLICY: su... |
2064 |
|
98806f75b netns xfrm: trivi... |
2065 |
list_add(&pol->walk.all, &net->xfrm.policy_all); |
98806f75b netns xfrm: trivi... |
2066 |
net->xfrm.policy_count[dir]++; |
1da177e4c Linux-2.6.12-rc2 |
2067 2068 2069 2070 2071 2072 |
xfrm_pol_hold(pol); } static struct xfrm_policy *__xfrm_policy_unlink(struct xfrm_policy *pol, int dir) { |
98806f75b netns xfrm: trivi... |
2073 |
struct net *net = xp_net(pol); |
53c2e285f xfrm: Do not hash... |
2074 |
if (list_empty(&pol->walk.all)) |
2518c7c2b [XFRM]: Hash poli... |
2075 |
return NULL; |
1da177e4c Linux-2.6.12-rc2 |
2076 |
|
53c2e285f xfrm: Do not hash... |
2077 2078 |
/* Socket policies are not hashed. */ if (!hlist_unhashed(&pol->bydst)) { |
a5eefc1df xfrm: policy: use... |
2079 |
hlist_del_rcu(&pol->bydst); |
24969facd xfrm: policy: sto... |
2080 |
hlist_del_init(&pol->bydst_inexact_list); |
53c2e285f xfrm: Do not hash... |
2081 2082 2083 2084 |
hlist_del(&pol->byidx); } list_del_init(&pol->walk.all); |
98806f75b netns xfrm: trivi... |
2085 |
net->xfrm.policy_count[dir]--; |
2518c7c2b [XFRM]: Hash poli... |
2086 2087 |
return pol; |
1da177e4c Linux-2.6.12-rc2 |
2088 |
} |
53c2e285f xfrm: Do not hash... |
2089 2090 2091 2092 2093 2094 2095 2096 2097 |
static void xfrm_sk_policy_link(struct xfrm_policy *pol, int dir) { __xfrm_policy_link(pol, XFRM_POLICY_MAX + dir); } static void xfrm_sk_policy_unlink(struct xfrm_policy *pol, int dir) { __xfrm_policy_unlink(pol, XFRM_POLICY_MAX + dir); } |
4666faab0 [IPSEC] Kill spur... |
2098 |
int xfrm_policy_delete(struct xfrm_policy *pol, int dir) |
1da177e4c Linux-2.6.12-rc2 |
2099 |
{ |
283bc9f35 xfrm: Namespacify... |
2100 |
struct net *net = xp_net(pol); |
9d0380df6 xfrm: policy: con... |
2101 |
spin_lock_bh(&net->xfrm.xfrm_policy_lock); |
1da177e4c Linux-2.6.12-rc2 |
2102 |
pol = __xfrm_policy_unlink(pol, dir); |
9d0380df6 xfrm: policy: con... |
2103 |
spin_unlock_bh(&net->xfrm.xfrm_policy_lock); |
1da177e4c Linux-2.6.12-rc2 |
2104 |
if (pol) { |
1da177e4c Linux-2.6.12-rc2 |
2105 |
xfrm_policy_kill(pol); |
4666faab0 [IPSEC] Kill spur... |
2106 |
return 0; |
1da177e4c Linux-2.6.12-rc2 |
2107 |
} |
4666faab0 [IPSEC] Kill spur... |
2108 |
return -ENOENT; |
1da177e4c Linux-2.6.12-rc2 |
2109 |
} |
a70fcb0ba [XFRM]: Add some ... |
2110 |
EXPORT_SYMBOL(xfrm_policy_delete); |
1da177e4c Linux-2.6.12-rc2 |
2111 2112 2113 |
int xfrm_sk_policy_insert(struct sock *sk, int dir, struct xfrm_policy *pol) { |
be8f8284c net: xfrm: allow ... |
2114 |
struct net *net = sock_net(sk); |
1da177e4c Linux-2.6.12-rc2 |
2115 |
struct xfrm_policy *old_pol; |
4e81bb833 [XFRM] POLICY: su... |
2116 2117 2118 2119 |
#ifdef CONFIG_XFRM_SUB_POLICY if (pol && pol->type != XFRM_POLICY_TYPE_MAIN) return -EINVAL; #endif |
9d0380df6 xfrm: policy: con... |
2120 |
spin_lock_bh(&net->xfrm.xfrm_policy_lock); |
d188ba86d xfrm: add rcu pro... |
2121 2122 |
old_pol = rcu_dereference_protected(sk->sk_policy[dir], lockdep_is_held(&net->xfrm.xfrm_policy_lock)); |
1da177e4c Linux-2.6.12-rc2 |
2123 |
if (pol) { |
386c5680e xfrm: use time64_... |
2124 |
pol->curlft.add_time = ktime_get_real_seconds(); |
e682adf02 xfrm: Try to hono... |
2125 |
pol->index = xfrm_gen_index(net, XFRM_POLICY_MAX+dir, 0); |
53c2e285f xfrm: Do not hash... |
2126 |
xfrm_sk_policy_link(pol, dir); |
1da177e4c Linux-2.6.12-rc2 |
2127 |
} |
d188ba86d xfrm: add rcu pro... |
2128 |
rcu_assign_pointer(sk->sk_policy[dir], pol); |
a0073fe18 xfrm: Add a state... |
2129 2130 2131 |
if (old_pol) { if (pol) xfrm_policy_requeue(old_pol, pol); |
ea2dea9da xfrm: remove poli... |
2132 2133 2134 |
/* Unlinking succeeds always. This is the only function * allowed to delete or replace socket policy. */ |
53c2e285f xfrm: Do not hash... |
2135 |
xfrm_sk_policy_unlink(old_pol, dir); |
a0073fe18 xfrm: Add a state... |
2136 |
} |
9d0380df6 xfrm: policy: con... |
2137 |
spin_unlock_bh(&net->xfrm.xfrm_policy_lock); |
1da177e4c Linux-2.6.12-rc2 |
2138 2139 2140 2141 2142 2143 |
if (old_pol) { xfrm_policy_kill(old_pol); } return 0; } |
d3e40a9f5 xfrm: Const'ify p... |
2144 |
static struct xfrm_policy *clone_policy(const struct xfrm_policy *old, int dir) |
1da177e4c Linux-2.6.12-rc2 |
2145 |
{ |
0331b1f38 netns xfrm: add s... |
2146 |
struct xfrm_policy *newp = xfrm_policy_alloc(xp_net(old), GFP_ATOMIC); |
283bc9f35 xfrm: Namespacify... |
2147 |
struct net *net = xp_net(old); |
1da177e4c Linux-2.6.12-rc2 |
2148 2149 2150 |
if (newp) { newp->selector = old->selector; |
03e1ad7b5 LSM: Make the Lab... |
2151 2152 |
if (security_xfrm_policy_clone(old->security, &newp->security)) { |
df71837d5 [LSM-IPSec]: Secu... |
2153 2154 2155 |
kfree(newp); return NULL; /* ENOMEM */ } |
1da177e4c Linux-2.6.12-rc2 |
2156 2157 |
newp->lft = old->lft; newp->curlft = old->curlft; |
fb977e2ca xfrm: clone mark ... |
2158 |
newp->mark = old->mark; |
7e6526404 xfrm: Add a new l... |
2159 |
newp->if_id = old->if_id; |
1da177e4c Linux-2.6.12-rc2 |
2160 2161 2162 2163 |
newp->action = old->action; newp->flags = old->flags; newp->xfrm_nr = old->xfrm_nr; newp->index = old->index; |
4e81bb833 [XFRM] POLICY: su... |
2164 |
newp->type = old->type; |
0e74aa1d7 xfrm: Copy policy... |
2165 |
newp->family = old->family; |
1da177e4c Linux-2.6.12-rc2 |
2166 2167 |
memcpy(newp->xfrm_vec, old->xfrm_vec, newp->xfrm_nr*sizeof(struct xfrm_tmpl)); |
9d0380df6 xfrm: policy: con... |
2168 |
spin_lock_bh(&net->xfrm.xfrm_policy_lock); |
53c2e285f xfrm: Do not hash... |
2169 |
xfrm_sk_policy_link(newp, dir); |
9d0380df6 xfrm: policy: con... |
2170 |
spin_unlock_bh(&net->xfrm.xfrm_policy_lock); |
1da177e4c Linux-2.6.12-rc2 |
2171 2172 2173 2174 |
xfrm_pol_put(newp); } return newp; } |
d188ba86d xfrm: add rcu pro... |
2175 |
int __xfrm_sk_clone_policy(struct sock *sk, const struct sock *osk) |
1da177e4c Linux-2.6.12-rc2 |
2176 |
{ |
d188ba86d xfrm: add rcu pro... |
2177 2178 2179 2180 2181 2182 2183 2184 2185 2186 2187 2188 2189 2190 2191 2192 2193 2194 |
const struct xfrm_policy *p; struct xfrm_policy *np; int i, ret = 0; rcu_read_lock(); for (i = 0; i < 2; i++) { p = rcu_dereference(osk->sk_policy[i]); if (p) { np = clone_policy(p, i); if (unlikely(!np)) { ret = -ENOMEM; break; } rcu_assign_pointer(sk->sk_policy[i], np); } } rcu_read_unlock(); return ret; |
1da177e4c Linux-2.6.12-rc2 |
2195 |
} |
a1e59abf8 [XFRM]: Fix wildc... |
2196 |
static int |
42a7b32b7 xfrm: Add oif to ... |
2197 |
xfrm_get_saddr(struct net *net, int oif, xfrm_address_t *local, |
077fbac40 net: xfrm: suppor... |
2198 |
xfrm_address_t *remote, unsigned short family, u32 mark) |
a1e59abf8 [XFRM]: Fix wildc... |
2199 2200 |
{ int err; |
37b103830 xfrm: policy: mak... |
2201 |
const struct xfrm_policy_afinfo *afinfo = xfrm_policy_get_afinfo(family); |
a1e59abf8 [XFRM]: Fix wildc... |
2202 2203 2204 |
if (unlikely(afinfo == NULL)) return -EINVAL; |
077fbac40 net: xfrm: suppor... |
2205 |
err = afinfo->get_saddr(net, oif, local, remote, mark); |
bdba9fe01 xfrm: policy: rem... |
2206 |
rcu_read_unlock(); |
a1e59abf8 [XFRM]: Fix wildc... |
2207 2208 |
return err; } |
1da177e4c Linux-2.6.12-rc2 |
2209 2210 2211 |
/* Resolve list of templates for the flow, given policy. */ static int |
a6c2e6111 xfrm: Mark flowi ... |
2212 2213 |
xfrm_tmpl_resolve_one(struct xfrm_policy *policy, const struct flowi *fl, struct xfrm_state **xfrm, unsigned short family) |
1da177e4c Linux-2.6.12-rc2 |
2214 |
{ |
fbda33b2b netns xfrm: ->get... |
2215 |
struct net *net = xp_net(policy); |
1da177e4c Linux-2.6.12-rc2 |
2216 2217 |
int nx; int i, error; |
948021518 Revert "xfrm: Fix... |
2218 2219 |
xfrm_address_t *daddr = xfrm_flowi_daddr(fl, family); xfrm_address_t *saddr = xfrm_flowi_saddr(fl, family); |
a1e59abf8 [XFRM]: Fix wildc... |
2220 |
xfrm_address_t tmp; |
1da177e4c Linux-2.6.12-rc2 |
2221 |
|
9b7a787d0 xfrm: checkpatch ... |
2222 |
for (nx = 0, i = 0; i < policy->xfrm_nr; i++) { |
1da177e4c Linux-2.6.12-rc2 |
2223 |
struct xfrm_state *x; |
948021518 Revert "xfrm: Fix... |
2224 2225 |
xfrm_address_t *remote = daddr; xfrm_address_t *local = saddr; |
1da177e4c Linux-2.6.12-rc2 |
2226 |
struct xfrm_tmpl *tmpl = &policy->xfrm_vec[i]; |
948021518 Revert "xfrm: Fix... |
2227 2228 2229 2230 2231 2232 2233 2234 2235 2236 2237 2238 |
if (tmpl->mode == XFRM_MODE_TUNNEL || tmpl->mode == XFRM_MODE_BEET) { remote = &tmpl->id.daddr; local = &tmpl->saddr; if (xfrm_addr_any(local, tmpl->encap_family)) { error = xfrm_get_saddr(net, fl->flowi_oif, &tmp, remote, tmpl->encap_family, 0); if (error) goto fail; local = &tmp; } |
1da177e4c Linux-2.6.12-rc2 |
2239 |
} |
bc56b3340 xfrm: Remove xfrm... |
2240 2241 |
x = xfrm_state_find(remote, local, fl, tmpl, policy, &error, family, policy->if_id); |
1da177e4c Linux-2.6.12-rc2 |
2242 2243 2244 |
if (x && x->km.state == XFRM_STATE_VALID) { xfrm[nx++] = x; |
948021518 Revert "xfrm: Fix... |
2245 2246 |
daddr = remote; saddr = local; |
1da177e4c Linux-2.6.12-rc2 |
2247 2248 2249 2250 2251 2252 |
continue; } if (x) { error = (x->km.state == XFRM_STATE_ERROR ? -EINVAL : -EAGAIN); xfrm_state_put(x); |
42054569f xfrm: fix checkpa... |
2253 |
} else if (error == -ESRCH) { |
a43222661 xfrm: do not leak... |
2254 |
error = -EAGAIN; |
42054569f xfrm: fix checkpa... |
2255 |
} |
1da177e4c Linux-2.6.12-rc2 |
2256 2257 2258 2259 2260 2261 2262 |
if (!tmpl->optional) goto fail; } return nx; fail: |
9b7a787d0 xfrm: checkpatch ... |
2263 |
for (nx--; nx >= 0; nx--) |
1da177e4c Linux-2.6.12-rc2 |
2264 2265 2266 |
xfrm_state_put(xfrm[nx]); return error; } |
4e81bb833 [XFRM] POLICY: su... |
2267 |
static int |
a6c2e6111 xfrm: Mark flowi ... |
2268 2269 |
xfrm_tmpl_resolve(struct xfrm_policy **pols, int npols, const struct flowi *fl, struct xfrm_state **xfrm, unsigned short family) |
4e81bb833 [XFRM] POLICY: su... |
2270 |
{ |
41a49cc3c [XFRM]: Add sorti... |
2271 2272 |
struct xfrm_state *tp[XFRM_MAX_DEPTH]; struct xfrm_state **tpp = (npols > 1) ? tp : xfrm; |
4e81bb833 [XFRM] POLICY: su... |
2273 2274 2275 2276 2277 2278 2279 2280 2281 2282 |
int cnx = 0; int error; int ret; int i; for (i = 0; i < npols; i++) { if (cnx + pols[i]->xfrm_nr >= XFRM_MAX_DEPTH) { error = -ENOBUFS; goto fail; } |
41a49cc3c [XFRM]: Add sorti... |
2283 2284 |
ret = xfrm_tmpl_resolve_one(pols[i], fl, &tpp[cnx], family); |
4e81bb833 [XFRM] POLICY: su... |
2285 2286 2287 2288 2289 2290 |
if (ret < 0) { error = ret; goto fail; } else cnx += ret; } |
41a49cc3c [XFRM]: Add sorti... |
2291 2292 2293 |
/* found states are sorted for outbound processing */ if (npols > 1) xfrm_state_sort(xfrm, tpp, cnx, family); |
4e81bb833 [XFRM] POLICY: su... |
2294 2295 2296 |
return cnx; fail: |
9b7a787d0 xfrm: checkpatch ... |
2297 |
for (cnx--; cnx >= 0; cnx--) |
41a49cc3c [XFRM]: Add sorti... |
2298 |
xfrm_state_put(tpp[cnx]); |
4e81bb833 [XFRM] POLICY: su... |
2299 2300 2301 |
return error; } |
f5e2bb4f5 xfrm: policy: xfr... |
2302 |
static int xfrm_get_tos(const struct flowi *fl, int family) |
25ee3286d [IPSEC]: Merge co... |
2303 |
{ |
f24ea5287 xfrm: remove tos ... |
2304 2305 |
if (family == AF_INET) return IPTOS_RT_MASK & fl->u.ip4.flowi4_tos; |
143a4454d xfrm: do not call... |
2306 |
|
f24ea5287 xfrm: remove tos ... |
2307 |
return 0; |
25ee3286d [IPSEC]: Merge co... |
2308 |
} |
d7c7544c3 netns xfrm: deal ... |
2309 |
static inline struct xfrm_dst *xfrm_alloc_dst(struct net *net, int family) |
1da177e4c Linux-2.6.12-rc2 |
2310 |
{ |
37b103830 xfrm: policy: mak... |
2311 |
const struct xfrm_policy_afinfo *afinfo = xfrm_policy_get_afinfo(family); |
d7c7544c3 netns xfrm: deal ... |
2312 |
struct dst_ops *dst_ops; |
25ee3286d [IPSEC]: Merge co... |
2313 2314 2315 2316 |
struct xfrm_dst *xdst; if (!afinfo) return ERR_PTR(-EINVAL); |
d7c7544c3 netns xfrm: deal ... |
2317 2318 2319 2320 |
switch (family) { case AF_INET: dst_ops = &net->xfrm.xfrm4_dst_ops; break; |
dfd56b8b3 net: use IS_ENABL... |
2321 |
#if IS_ENABLED(CONFIG_IPV6) |
d7c7544c3 netns xfrm: deal ... |
2322 2323 2324 2325 2326 2327 2328 |
case AF_INET6: dst_ops = &net->xfrm.xfrm6_dst_ops; break; #endif default: BUG(); } |
b2a9c0ed7 net: remove DST_N... |
2329 |
xdst = dst_alloc(dst_ops, NULL, 1, DST_OBSOLETE_NONE, 0); |
25ee3286d [IPSEC]: Merge co... |
2330 |
|
d4cae5621 net: check return... |
2331 |
if (likely(xdst)) { |
141e369de xfrm: Initialize ... |
2332 2333 2334 |
struct dst_entry *dst = &xdst->u.dst; memset(dst + 1, 0, sizeof(*xdst) - sizeof(*dst)); |
d4cae5621 net: check return... |
2335 |
} else |
0b1509321 xfrm: avoid possi... |
2336 |
xdst = ERR_PTR(-ENOBUFS); |
80c802f30 xfrm: cache bundl... |
2337 |
|
bdba9fe01 xfrm: policy: rem... |
2338 |
rcu_read_unlock(); |
d4cae5621 net: check return... |
2339 |
|
25ee3286d [IPSEC]: Merge co... |
2340 2341 |
return xdst; } |
2e8b4aa81 xfrm: remove init... |
2342 2343 |
static void xfrm_init_path(struct xfrm_dst *path, struct dst_entry *dst, int nfheader_len) |
a1b051405 [XFRM] IPv6: Fix ... |
2344 |
{ |
2e8b4aa81 xfrm: remove init... |
2345 2346 2347 2348 2349 |
if (dst->ops->family == AF_INET6) { struct rt6_info *rt = (struct rt6_info *)dst; path->path_cookie = rt6_get_cookie(rt); path->u.rt6.rt6i_nfheader_len = nfheader_len; } |
a1b051405 [XFRM] IPv6: Fix ... |
2350 |
} |
87c1e12b5 ipsec: Fix bogus ... |
2351 |
static inline int xfrm_fill_dst(struct xfrm_dst *xdst, struct net_device *dev, |
0c7b3eefb xfrm: Mark flowi ... |
2352 |
const struct flowi *fl) |
25ee3286d [IPSEC]: Merge co... |
2353 |
{ |
37b103830 xfrm: policy: mak... |
2354 |
const struct xfrm_policy_afinfo *afinfo = |
25ee3286d [IPSEC]: Merge co... |
2355 2356 2357 2358 |
xfrm_policy_get_afinfo(xdst->u.dst.ops->family); int err; if (!afinfo) |
1da177e4c Linux-2.6.12-rc2 |
2359 |
return -EINVAL; |
25ee3286d [IPSEC]: Merge co... |
2360 |
|
87c1e12b5 ipsec: Fix bogus ... |
2361 |
err = afinfo->fill_dst(xdst, dev, fl); |
25ee3286d [IPSEC]: Merge co... |
2362 |
|
bdba9fe01 xfrm: policy: rem... |
2363 |
rcu_read_unlock(); |
25ee3286d [IPSEC]: Merge co... |
2364 |
|
1da177e4c Linux-2.6.12-rc2 |
2365 2366 |
return err; } |
80c802f30 xfrm: cache bundl... |
2367 |
|
25ee3286d [IPSEC]: Merge co... |
2368 2369 2370 2371 2372 |
/* Allocate chain of dst_entry's, attach known xfrm's, calculate * all the metrics... Shortly, bundle a bundle. */ static struct dst_entry *xfrm_bundle_create(struct xfrm_policy *policy, |
5492093dc xfrm: Stop using ... |
2373 2374 2375 |
struct xfrm_state **xfrm, struct xfrm_dst **bundle, int nx, |
98313adaa xfrm: Mark flowi ... |
2376 |
const struct flowi *fl, |
25ee3286d [IPSEC]: Merge co... |
2377 2378 |
struct dst_entry *dst) { |
733a5fac2 xfrm: remove afin... |
2379 |
const struct xfrm_state_afinfo *afinfo; |
4c145dce2 xfrm: make xfrm m... |
2380 |
const struct xfrm_mode *inner_mode; |
d7c7544c3 netns xfrm: deal ... |
2381 |
struct net *net = xp_net(policy); |
25ee3286d [IPSEC]: Merge co... |
2382 2383 |
unsigned long now = jiffies; struct net_device *dev; |
45b018bed ipsec: Create and... |
2384 2385 |
struct xfrm_dst *xdst_prev = NULL; struct xfrm_dst *xdst0 = NULL; |
25ee3286d [IPSEC]: Merge co... |
2386 2387 2388 |
int i = 0; int err; int header_len = 0; |
a1b051405 [XFRM] IPv6: Fix ... |
2389 |
int nfheader_len = 0; |
25ee3286d [IPSEC]: Merge co... |
2390 2391 2392 |
int trailer_len = 0; int tos; int family = policy->selector.family; |
9bb182a70 [XFRM] MIP6: Fix ... |
2393 2394 2395 |
xfrm_address_t saddr, daddr; xfrm_flowi_addr_get(fl, &saddr, &daddr, family); |
25ee3286d [IPSEC]: Merge co... |
2396 2397 |
tos = xfrm_get_tos(fl, family); |
25ee3286d [IPSEC]: Merge co... |
2398 2399 2400 2401 |
dst_hold(dst); for (; i < nx; i++) { |
d7c7544c3 netns xfrm: deal ... |
2402 |
struct xfrm_dst *xdst = xfrm_alloc_dst(net, family); |
25ee3286d [IPSEC]: Merge co... |
2403 2404 2405 2406 2407 2408 2409 |
struct dst_entry *dst1 = &xdst->u.dst; err = PTR_ERR(xdst); if (IS_ERR(xdst)) { dst_release(dst); goto put_states; } |
5492093dc xfrm: Stop using ... |
2410 |
bundle[i] = xdst; |
45b018bed ipsec: Create and... |
2411 2412 |
if (!xdst_prev) xdst0 = xdst; |
10a7ef336 ipsec: Fix dst le... |
2413 2414 2415 2416 |
else /* Ref count is taken during xfrm_alloc_dst() * No need to do dst_clone() on dst1 */ |
45b018bed ipsec: Create and... |
2417 |
xfrm_dst_set_child(xdst_prev, &xdst->u.dst); |
10a7ef336 ipsec: Fix dst le... |
2418 |
|
43a4dea4c xfrm: Assign the ... |
2419 2420 2421 2422 2423 2424 2425 2426 2427 |
if (xfrm[i]->sel.family == AF_UNSPEC) { inner_mode = xfrm_ip2inner_mode(xfrm[i], xfrm_af2proto(family)); if (!inner_mode) { err = -EAFNOSUPPORT; dst_release(dst); goto put_states; } } else |
c9500d7b7 xfrm: store xfrm_... |
2428 |
inner_mode = &xfrm[i]->inner_mode; |
43a4dea4c xfrm: Assign the ... |
2429 |
|
25ee3286d [IPSEC]: Merge co... |
2430 |
xdst->route = dst; |
defb3519a net: Abstract awa... |
2431 |
dst_copy_metrics(dst1, dst); |
25ee3286d [IPSEC]: Merge co... |
2432 2433 |
if (xfrm[i]->props.mode != XFRM_MODE_TRANSPORT) { |
e2612cd49 xfrm: Make set-ma... |
2434 2435 2436 2437 |
__u32 mark = 0; if (xfrm[i]->props.smark.v || xfrm[i]->props.smark.m) mark = xfrm_smark_get(fl->flowi_mark, xfrm[i]); |
9b42c1f17 xfrm: Extend the ... |
2438 |
|
25ee3286d [IPSEC]: Merge co... |
2439 |
family = xfrm[i]->props.family; |
42a7b32b7 xfrm: Add oif to ... |
2440 |
dst = xfrm_dst_lookup(xfrm[i], tos, fl->flowi_oif, |
9b42c1f17 xfrm: Extend the ... |
2441 |
&saddr, &daddr, family, mark); |
25ee3286d [IPSEC]: Merge co... |
2442 2443 2444 2445 2446 2447 2448 |
err = PTR_ERR(dst); if (IS_ERR(dst)) goto put_states; } else dst_hold(dst); dst1->xfrm = xfrm[i]; |
80c802f30 xfrm: cache bundl... |
2449 |
xdst->xfrm_genid = xfrm[i]->genid; |
25ee3286d [IPSEC]: Merge co... |
2450 |
|
f5b0a8743 net: Document dst... |
2451 |
dst1->obsolete = DST_OBSOLETE_FORCE_CHK; |
25ee3286d [IPSEC]: Merge co... |
2452 2453 2454 |
dst1->lastuse = now; dst1->input = dst_discard; |
733a5fac2 xfrm: remove afin... |
2455 2456 2457 2458 2459 2460 2461 2462 |
rcu_read_lock(); afinfo = xfrm_state_afinfo_get_rcu(inner_mode->family); if (likely(afinfo)) dst1->output = afinfo->output; else dst1->output = dst_discard_out; rcu_read_unlock(); |
25ee3286d [IPSEC]: Merge co... |
2463 |
|
45b018bed ipsec: Create and... |
2464 |
xdst_prev = xdst; |
25ee3286d [IPSEC]: Merge co... |
2465 2466 |
header_len += xfrm[i]->props.header_len; |
a1b051405 [XFRM] IPv6: Fix ... |
2467 2468 |
if (xfrm[i]->type->flags & XFRM_TYPE_NON_FRAGMENT) nfheader_len += xfrm[i]->props.header_len; |
25ee3286d [IPSEC]: Merge co... |
2469 2470 |
trailer_len += xfrm[i]->props.trailer_len; } |
45b018bed ipsec: Create and... |
2471 |
xfrm_dst_set_child(xdst_prev, dst); |
0f6c480f2 xfrm: Move dst->p... |
2472 |
xdst0->path = dst; |
25ee3286d [IPSEC]: Merge co... |
2473 2474 2475 2476 2477 |
err = -ENODEV; dev = dst->dev; if (!dev) goto free_dst; |
45b018bed ipsec: Create and... |
2478 |
xfrm_init_path(xdst0, dst, nfheader_len); |
5492093dc xfrm: Stop using ... |
2479 |
xfrm_init_pmtu(bundle, nx); |
25ee3286d [IPSEC]: Merge co... |
2480 |
|
45b018bed ipsec: Create and... |
2481 2482 2483 |
for (xdst_prev = xdst0; xdst_prev != (struct xfrm_dst *)dst; xdst_prev = (struct xfrm_dst *) xfrm_dst_child(&xdst_prev->u.dst)) { err = xfrm_fill_dst(xdst_prev, dev, fl); |
25ee3286d [IPSEC]: Merge co... |
2484 2485 |
if (err) goto free_dst; |
45b018bed ipsec: Create and... |
2486 2487 2488 2489 |
xdst_prev->u.dst.header_len = header_len; xdst_prev->u.dst.trailer_len = trailer_len; header_len -= xdst_prev->u.dst.xfrm->props.header_len; trailer_len -= xdst_prev->u.dst.xfrm->props.trailer_len; |
25ee3286d [IPSEC]: Merge co... |
2490 |
} |
45b018bed ipsec: Create and... |
2491 |
return &xdst0->u.dst; |
25ee3286d [IPSEC]: Merge co... |
2492 2493 2494 2495 2496 |
put_states: for (; i < nx; i++) xfrm_state_put(xfrm[i]); free_dst: |
45b018bed ipsec: Create and... |
2497 2498 |
if (xdst0) dst_release_immediate(&xdst0->u.dst); |
38369f54d xfrm Fix potentia... |
2499 2500 |
return ERR_PTR(err); |
25ee3286d [IPSEC]: Merge co... |
2501 |
} |
73ff93cd0 xfrm: Mark flowi ... |
2502 |
static int xfrm_expand_policies(const struct flowi *fl, u16 family, |
80c802f30 xfrm: cache bundl... |
2503 2504 2505 2506 2507 2508 2509 2510 2511 2512 2513 2514 2515 2516 2517 2518 2519 2520 2521 2522 2523 |
struct xfrm_policy **pols, int *num_pols, int *num_xfrms) { int i; if (*num_pols == 0 || !pols[0]) { *num_pols = 0; *num_xfrms = 0; return 0; } if (IS_ERR(pols[0])) return PTR_ERR(pols[0]); *num_xfrms = pols[0]->xfrm_nr; #ifdef CONFIG_XFRM_SUB_POLICY if (pols[0] && pols[0]->action == XFRM_POLICY_ALLOW && pols[0]->type != XFRM_POLICY_TYPE_MAIN) { pols[1] = xfrm_policy_lookup_bytype(xp_net(pols[0]), XFRM_POLICY_TYPE_MAIN, fl, family, |
bc56b3340 xfrm: Remove xfrm... |
2524 2525 |
XFRM_POLICY_OUT, pols[0]->if_id); |
80c802f30 xfrm: cache bundl... |
2526 2527 2528 2529 2530 |
if (pols[1]) { if (IS_ERR(pols[1])) { xfrm_pols_put(pols, *num_pols); return PTR_ERR(pols[1]); } |
02d0892f9 xfrm: checkpatch ... |
2531 |
(*num_pols)++; |
80c802f30 xfrm: cache bundl... |
2532 2533 2534 2535 2536 2537 2538 2539 2540 2541 2542 2543 2544 2545 2546 2547 2548 |
(*num_xfrms) += pols[1]->xfrm_nr; } } #endif for (i = 0; i < *num_pols; i++) { if (pols[i]->action != XFRM_POLICY_ALLOW) { *num_xfrms = -1; break; } } return 0; } static struct xfrm_dst * xfrm_resolve_and_create_bundle(struct xfrm_policy **pols, int num_pols, |
4ca2e6851 xfrm: Mark flowi ... |
2549 |
const struct flowi *fl, u16 family, |
80c802f30 xfrm: cache bundl... |
2550 2551 2552 2553 |
struct dst_entry *dst_orig) { struct net *net = xp_net(pols[0]); struct xfrm_state *xfrm[XFRM_MAX_DEPTH]; |
5492093dc xfrm: Stop using ... |
2554 |
struct xfrm_dst *bundle[XFRM_MAX_DEPTH]; |
e4db5b61c xfrm: policy: rem... |
2555 |
struct xfrm_dst *xdst; |
80c802f30 xfrm: cache bundl... |
2556 |
struct dst_entry *dst; |
80c802f30 xfrm: cache bundl... |
2557 |
int err; |
cf3796675 xfrm: do uncondit... |
2558 2559 2560 |
/* Try to instantiate a bundle */ err = xfrm_tmpl_resolve(pols, num_pols, fl, xfrm, family); if (err <= 0) { |
934ffce13 xfrm: fix 'passin... |
2561 2562 2563 2564 |
if (err == 0) return NULL; if (err != -EAGAIN) |
cf3796675 xfrm: do uncondit... |
2565 2566 2567 |
XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTPOLERROR); return ERR_PTR(err); } |
5492093dc xfrm: Stop using ... |
2568 |
dst = xfrm_bundle_create(pols[0], xfrm, bundle, err, fl, dst_orig); |
80c802f30 xfrm: cache bundl... |
2569 2570 2571 2572 2573 2574 2575 |
if (IS_ERR(dst)) { XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTBUNDLEGENERROR); return ERR_CAST(dst); } xdst = (struct xfrm_dst *)dst; xdst->num_xfrms = err; |
80c802f30 xfrm: cache bundl... |
2576 |
xdst->num_pols = num_pols; |
3e94c2dcf xfrm: checkpatch ... |
2577 |
memcpy(xdst->pols, pols, sizeof(struct xfrm_policy *) * num_pols); |
80c802f30 xfrm: cache bundl... |
2578 2579 2580 2581 |
xdst->policy_genid = atomic_read(&pols[0]->genid); return xdst; } |
c3aed7095 xfrm: Convert tim... |
2582 |
static void xfrm_policy_queue_process(struct timer_list *t) |
a0073fe18 xfrm: Add a state... |
2583 |
{ |
a0073fe18 xfrm: Add a state... |
2584 2585 2586 |
struct sk_buff *skb; struct sock *sk; struct dst_entry *dst; |
c3aed7095 xfrm: Convert tim... |
2587 |
struct xfrm_policy *pol = from_timer(pol, t, polq.hold_timer); |
3f5312ae6 xfrm: Only comput... |
2588 |
struct net *net = xp_net(pol); |
a0073fe18 xfrm: Add a state... |
2589 2590 2591 |
struct xfrm_policy_queue *pq = &pol->polq; struct flowi fl; struct sk_buff_head list; |
b328ecc46 xfrm: Make the po... |
2592 |
__u32 skb_mark; |
a0073fe18 xfrm: Add a state... |
2593 2594 2595 |
spin_lock(&pq->hold_queue.lock); skb = skb_peek(&pq->hold_queue); |
2bb53e255 xfrm: check for a... |
2596 2597 2598 2599 |
if (!skb) { spin_unlock(&pq->hold_queue.lock); goto out; } |
a0073fe18 xfrm: Add a state... |
2600 2601 |
dst = skb_dst(skb); sk = skb->sk; |
b328ecc46 xfrm: Make the po... |
2602 2603 2604 2605 |
/* Fixup the mark to support VTI. */ skb_mark = skb->mark; skb->mark = pol->mark.v; |
a0073fe18 xfrm: Add a state... |
2606 |
xfrm_decode_session(skb, &fl, dst->ops->family); |
b328ecc46 xfrm: Make the po... |
2607 |
skb->mark = skb_mark; |
a0073fe18 xfrm: Add a state... |
2608 |
spin_unlock(&pq->hold_queue.lock); |
0f6c480f2 xfrm: Move dst->p... |
2609 |
dst_hold(xfrm_dst_path(dst)); |
2471c9816 xfrm: Fix policy ... |
2610 |
dst = xfrm_lookup(net, xfrm_dst_path(dst), &fl, sk, XFRM_LOOKUP_QUEUE); |
a0073fe18 xfrm: Add a state... |
2611 2612 2613 2614 2615 2616 2617 2618 2619 2620 |
if (IS_ERR(dst)) goto purge_queue; if (dst->flags & DST_XFRM_QUEUE) { dst_release(dst); if (pq->timeout >= XFRM_QUEUE_TMO_MAX) goto purge_queue; pq->timeout = pq->timeout << 1; |
e7d8f6cb2 xfrm: Add refcoun... |
2621 2622 |
if (!mod_timer(&pq->hold_timer, jiffies + pq->timeout)) xfrm_pol_hold(pol); |
7759d6a83 xfrm: policy: add... |
2623 |
goto out; |
a0073fe18 xfrm: Add a state... |
2624 2625 2626 2627 2628 2629 2630 2631 2632 2633 2634 2635 2636 |
} dst_release(dst); __skb_queue_head_init(&list); spin_lock(&pq->hold_queue.lock); pq->timeout = 0; skb_queue_splice_init(&pq->hold_queue, &list); spin_unlock(&pq->hold_queue.lock); while (!skb_queue_empty(&list)) { skb = __skb_dequeue(&list); |
b328ecc46 xfrm: Make the po... |
2637 2638 2639 |
/* Fixup the mark to support VTI. */ skb_mark = skb->mark; skb->mark = pol->mark.v; |
a0073fe18 xfrm: Add a state... |
2640 |
xfrm_decode_session(skb, &fl, skb_dst(skb)->ops->family); |
b328ecc46 xfrm: Make the po... |
2641 |
skb->mark = skb_mark; |
0f6c480f2 xfrm: Move dst->p... |
2642 2643 |
dst_hold(xfrm_dst_path(skb_dst(skb))); dst = xfrm_lookup(net, xfrm_dst_path(skb_dst(skb)), &fl, skb->sk, 0); |
a0073fe18 xfrm: Add a state... |
2644 |
if (IS_ERR(dst)) { |
a0073fe18 xfrm: Add a state... |
2645 2646 2647 |
kfree_skb(skb); continue; } |
895b5c9f2 netfilter: drop b... |
2648 |
nf_reset_ct(skb); |
a0073fe18 xfrm: Add a state... |
2649 2650 |
skb_dst_drop(skb); skb_dst_set(skb, dst); |
13206b6bf net: Pass net int... |
2651 |
dst_output(net, skb->sk, skb); |
a0073fe18 xfrm: Add a state... |
2652 |
} |
e7d8f6cb2 xfrm: Add refcoun... |
2653 2654 |
out: xfrm_pol_put(pol); |
a0073fe18 xfrm: Add a state... |
2655 2656 2657 2658 |
return; purge_queue: pq->timeout = 0; |
1ee5e6676 xfrm: remove the ... |
2659 |
skb_queue_purge(&pq->hold_queue); |
e7d8f6cb2 xfrm: Add refcoun... |
2660 |
xfrm_pol_put(pol); |
a0073fe18 xfrm: Add a state... |
2661 |
} |
ede2059db dst: Pass net int... |
2662 |
static int xdst_queue_output(struct net *net, struct sock *sk, struct sk_buff *skb) |
a0073fe18 xfrm: Add a state... |
2663 2664 2665 2666 |
{ unsigned long sched_next; struct dst_entry *dst = skb_dst(skb); struct xfrm_dst *xdst = (struct xfrm_dst *) dst; |
e7d8f6cb2 xfrm: Add refcoun... |
2667 2668 |
struct xfrm_policy *pol = xdst->pols[0]; struct xfrm_policy_queue *pq = &pol->polq; |
4d53eff48 xfrm: Don't queue... |
2669 |
|
39bb5e628 net: skb_fclone_b... |
2670 |
if (unlikely(skb_fclone_busy(sk, skb))) { |
4d53eff48 xfrm: Don't queue... |
2671 2672 2673 |
kfree_skb(skb); return 0; } |
a0073fe18 xfrm: Add a state... |
2674 2675 2676 2677 2678 2679 2680 |
if (pq->hold_queue.qlen > XFRM_MAX_QUEUE_LEN) { kfree_skb(skb); return -EAGAIN; } skb_dst_force(skb); |
a0073fe18 xfrm: Add a state... |
2681 2682 2683 2684 2685 2686 2687 2688 2689 2690 2691 |
spin_lock_bh(&pq->hold_queue.lock); if (!pq->timeout) pq->timeout = XFRM_QUEUE_TMO_MIN; sched_next = jiffies + pq->timeout; if (del_timer(&pq->hold_timer)) { if (time_before(pq->hold_timer.expires, sched_next)) sched_next = pq->hold_timer.expires; |
e7d8f6cb2 xfrm: Add refcoun... |
2692 |
xfrm_pol_put(pol); |
a0073fe18 xfrm: Add a state... |
2693 2694 2695 |
} __skb_queue_tail(&pq->hold_queue, skb); |
e7d8f6cb2 xfrm: Add refcoun... |
2696 2697 |
if (!mod_timer(&pq->hold_timer, sched_next)) xfrm_pol_hold(pol); |
a0073fe18 xfrm: Add a state... |
2698 2699 2700 2701 2702 2703 2704 |
spin_unlock_bh(&pq->hold_queue.lock); return 0; } static struct xfrm_dst *xfrm_create_dummy_bundle(struct net *net, |
b8c203b2d xfrm: Generate qu... |
2705 |
struct xfrm_flo *xflo, |
a0073fe18 xfrm: Add a state... |
2706 2707 2708 2709 2710 2711 |
const struct flowi *fl, int num_xfrms, u16 family) { int err; struct net_device *dev; |
b8c203b2d xfrm: Generate qu... |
2712 |
struct dst_entry *dst; |
a0073fe18 xfrm: Add a state... |
2713 2714 2715 2716 2717 2718 |
struct dst_entry *dst1; struct xfrm_dst *xdst; xdst = xfrm_alloc_dst(net, family); if (IS_ERR(xdst)) return xdst; |
b8c203b2d xfrm: Generate qu... |
2719 2720 2721 |
if (!(xflo->flags & XFRM_LOOKUP_QUEUE) || net->xfrm.sysctl_larval_drop || num_xfrms <= 0) |
a0073fe18 xfrm: Add a state... |
2722 |
return xdst; |
b8c203b2d xfrm: Generate qu... |
2723 |
dst = xflo->dst_orig; |
a0073fe18 xfrm: Add a state... |
2724 2725 2726 2727 2728 2729 2730 |
dst1 = &xdst->u.dst; dst_hold(dst); xdst->route = dst; dst_copy_metrics(dst1, dst); dst1->obsolete = DST_OBSOLETE_FORCE_CHK; |
af13b3c33 Remove DST_HOST |
2731 |
dst1->flags |= DST_XFRM_QUEUE; |
a0073fe18 xfrm: Add a state... |
2732 2733 2734 2735 2736 2737 |
dst1->lastuse = jiffies; dst1->input = dst_discard; dst1->output = xdst_queue_output; dst_hold(dst); |
45b018bed ipsec: Create and... |
2738 |
xfrm_dst_set_child(xdst, dst); |
0f6c480f2 xfrm: Move dst->p... |
2739 |
xdst->path = dst; |
a0073fe18 xfrm: Add a state... |
2740 2741 2742 2743 2744 2745 2746 2747 2748 2749 2750 2751 2752 2753 2754 2755 2756 2757 2758 2759 |
xfrm_init_path((struct xfrm_dst *)dst1, dst, 0); err = -ENODEV; dev = dst->dev; if (!dev) goto free_dst; err = xfrm_fill_dst(xdst, dev, fl); if (err) goto free_dst; out: return xdst; free_dst: dst_release(dst1); xdst = ERR_PTR(err); goto out; } |
bc56b3340 xfrm: Remove xfrm... |
2760 2761 2762 2763 |
static struct xfrm_dst *xfrm_bundle_lookup(struct net *net, const struct flowi *fl, u16 family, u8 dir, struct xfrm_flo *xflo, u32 if_id) |
80c802f30 xfrm: cache bundl... |
2764 |
{ |
80c802f30 xfrm: cache bundl... |
2765 |
struct xfrm_policy *pols[XFRM_POLICY_TYPE_MAX]; |
855dad99c xfrm_policy: remo... |
2766 |
int num_pols = 0, num_xfrms = 0, err; |
bd45c539b xfrm_policy: make... |
2767 |
struct xfrm_dst *xdst; |
80c802f30 xfrm: cache bundl... |
2768 |
|
80c802f30 xfrm: cache bundl... |
2769 2770 |
/* Resolve policies to use if we couldn't get them from * previous cache entry */ |
855dad99c xfrm_policy: remo... |
2771 |
num_pols = 1; |
bc56b3340 xfrm: Remove xfrm... |
2772 |
pols[0] = xfrm_policy_lookup(net, fl, family, dir, if_id); |
855dad99c xfrm_policy: remo... |
2773 |
err = xfrm_expand_policies(fl, family, pols, |
80c802f30 xfrm: cache bundl... |
2774 |
&num_pols, &num_xfrms); |
855dad99c xfrm_policy: remo... |
2775 2776 2777 2778 2779 2780 |
if (err < 0) goto inc_error; if (num_pols == 0) return NULL; if (num_xfrms <= 0) goto make_dummy_bundle; |
80c802f30 xfrm: cache bundl... |
2781 |
|
bd45c539b xfrm_policy: make... |
2782 |
xdst = xfrm_resolve_and_create_bundle(pols, num_pols, fl, family, |
76a420119 xfrm: Fix a race ... |
2783 |
xflo->dst_orig); |
bd45c539b xfrm_policy: make... |
2784 2785 |
if (IS_ERR(xdst)) { err = PTR_ERR(xdst); |
f203b76d7 xfrm: Add virtual... |
2786 2787 2788 2789 |
if (err == -EREMOTE) { xfrm_pols_put(pols, num_pols); return NULL; } |
80c802f30 xfrm: cache bundl... |
2790 2791 |
if (err != -EAGAIN) goto error; |
855dad99c xfrm_policy: remo... |
2792 |
goto make_dummy_bundle; |
bd45c539b xfrm_policy: make... |
2793 |
} else if (xdst == NULL) { |
d809ec895 xfrm: do not assu... |
2794 |
num_xfrms = 0; |
855dad99c xfrm_policy: remo... |
2795 |
goto make_dummy_bundle; |
80c802f30 xfrm: cache bundl... |
2796 |
} |
bd45c539b xfrm_policy: make... |
2797 |
return xdst; |
80c802f30 xfrm: cache bundl... |
2798 2799 2800 2801 2802 |
make_dummy_bundle: /* We found policies, but there's no bundles to instantiate: * either because the policy blocks, has no transformations or * we could not build template (no xfrm_states).*/ |
b8c203b2d xfrm: Generate qu... |
2803 |
xdst = xfrm_create_dummy_bundle(net, xflo, fl, num_xfrms, family); |
80c802f30 xfrm: cache bundl... |
2804 2805 2806 2807 2808 2809 |
if (IS_ERR(xdst)) { xfrm_pols_put(pols, num_pols); return ERR_CAST(xdst); } xdst->num_pols = num_pols; xdst->num_xfrms = num_xfrms; |
3e94c2dcf xfrm: checkpatch ... |
2810 |
memcpy(xdst->pols, pols, sizeof(struct xfrm_policy *) * num_pols); |
80c802f30 xfrm: cache bundl... |
2811 |
|
bd45c539b xfrm_policy: make... |
2812 |
return xdst; |
80c802f30 xfrm: cache bundl... |
2813 2814 2815 2816 |
inc_error: XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTPOLERROR); error: |
855dad99c xfrm_policy: remo... |
2817 |
xfrm_pols_put(pols, num_pols); |
80c802f30 xfrm: cache bundl... |
2818 2819 |
return ERR_PTR(err); } |
1da177e4c Linux-2.6.12-rc2 |
2820 |
|
2774c131b xfrm: Handle blac... |
2821 2822 2823 |
static struct dst_entry *make_blackhole(struct net *net, u16 family, struct dst_entry *dst_orig) { |
37b103830 xfrm: policy: mak... |
2824 |
const struct xfrm_policy_afinfo *afinfo = xfrm_policy_get_afinfo(family); |
2774c131b xfrm: Handle blac... |
2825 2826 2827 2828 |
struct dst_entry *ret; if (!afinfo) { dst_release(dst_orig); |
433a19548 xfrm: fix a read ... |
2829 |
return ERR_PTR(-EINVAL); |
2774c131b xfrm: Handle blac... |
2830 2831 2832 |
} else { ret = afinfo->blackhole_route(net, dst_orig); } |
bdba9fe01 xfrm: policy: rem... |
2833 |
rcu_read_unlock(); |
2774c131b xfrm: Handle blac... |
2834 2835 2836 |
return ret; } |
bc56b3340 xfrm: Remove xfrm... |
2837 |
/* Finds/creates a bundle for given flow and if_id |
1da177e4c Linux-2.6.12-rc2 |
2838 2839 2840 |
* * At the moment we eat a raw IP route. Mostly to speed up lookups * on interfaces with disabled IPsec. |
bc56b3340 xfrm: Remove xfrm... |
2841 2842 2843 |
* * xfrm_lookup uses an if_id of 0 by default, and is provided for * compatibility |
1da177e4c Linux-2.6.12-rc2 |
2844 |
*/ |
bc56b3340 xfrm: Remove xfrm... |
2845 2846 2847 2848 2849 |
struct dst_entry *xfrm_lookup_with_ifid(struct net *net, struct dst_entry *dst_orig, const struct flowi *fl, const struct sock *sk, int flags, u32 if_id) |
1da177e4c Linux-2.6.12-rc2 |
2850 |
{ |
4e81bb833 [XFRM] POLICY: su... |
2851 |
struct xfrm_policy *pols[XFRM_POLICY_TYPE_MAX]; |
80c802f30 xfrm: cache bundl... |
2852 |
struct xfrm_dst *xdst; |
452edd598 xfrm: Return dst ... |
2853 |
struct dst_entry *dst, *route; |
80c802f30 xfrm: cache bundl... |
2854 |
u16 family = dst_orig->ops->family; |
aff669bc2 xfrm_policy: kill... |
2855 |
u8 dir = XFRM_POLICY_OUT; |
4b021628b xfrm: potential u... |
2856 |
int i, err, num_pols, num_xfrms = 0, drop_pols = 0; |
e0d1caa7b [MLSXFRM]: Flow b... |
2857 |
|
80c802f30 xfrm: cache bundl... |
2858 2859 2860 |
dst = NULL; xdst = NULL; route = NULL; |
4e81bb833 [XFRM] POLICY: su... |
2861 |
|
bd5eb35f1 xfrm: take care o... |
2862 |
sk = sk_const_to_full_sk(sk); |
f7944fb19 [XFRM] policy: Re... |
2863 |
if (sk && sk->sk_policy[XFRM_POLICY_OUT]) { |
80c802f30 xfrm: cache bundl... |
2864 |
num_pols = 1; |
bc56b3340 xfrm: Remove xfrm... |
2865 2866 |
pols[0] = xfrm_sk_policy_lookup(sk, XFRM_POLICY_OUT, fl, family, if_id); |
80c802f30 xfrm: cache bundl... |
2867 2868 2869 |
err = xfrm_expand_policies(fl, family, pols, &num_pols, &num_xfrms); if (err < 0) |
75b8c1332 [IPSEC]: Fix pote... |
2870 |
goto dropdst; |
80c802f30 xfrm: cache bundl... |
2871 2872 2873 2874 2875 2876 2877 2878 2879 2880 |
if (num_pols) { if (num_xfrms <= 0) { drop_pols = num_pols; goto no_transform; } xdst = xfrm_resolve_and_create_bundle( pols, num_pols, fl, family, dst_orig); |
76a420119 xfrm: Fix a race ... |
2881 |
|
80c802f30 xfrm: cache bundl... |
2882 2883 2884 |
if (IS_ERR(xdst)) { xfrm_pols_put(pols, num_pols); err = PTR_ERR(xdst); |
f203b76d7 xfrm: Add virtual... |
2885 2886 |
if (err == -EREMOTE) goto nopol; |
80c802f30 xfrm: cache bundl... |
2887 |
goto dropdst; |
d809ec895 xfrm: do not assu... |
2888 2889 2890 2891 |
} else if (xdst == NULL) { num_xfrms = 0; drop_pols = num_pols; goto no_transform; |
80c802f30 xfrm: cache bundl... |
2892 |
} |
80c802f30 xfrm: cache bundl... |
2893 |
route = xdst->route; |
0aa647746 [XFRM]: Support t... |
2894 |
} |
3bccfbc7a IPsec: fix handli... |
2895 |
} |
1da177e4c Linux-2.6.12-rc2 |
2896 |
|
80c802f30 xfrm: cache bundl... |
2897 |
if (xdst == NULL) { |
b8c203b2d xfrm: Generate qu... |
2898 2899 2900 2901 |
struct xfrm_flo xflo; xflo.dst_orig = dst_orig; xflo.flags = flags; |
1da177e4c Linux-2.6.12-rc2 |
2902 |
/* To accelerate a bit... */ |
2518c7c2b [XFRM]: Hash poli... |
2903 |
if ((dst_orig->flags & DST_NOXFRM) || |
52479b623 netns xfrm: looku... |
2904 |
!net->xfrm.policy_count[XFRM_POLICY_OUT]) |
8b7817f3a [IPSEC]: Add ICMP... |
2905 |
goto nopol; |
1da177e4c Linux-2.6.12-rc2 |
2906 |
|
bc56b3340 xfrm: Remove xfrm... |
2907 |
xdst = xfrm_bundle_lookup(net, fl, family, dir, &xflo, if_id); |
bd45c539b xfrm_policy: make... |
2908 |
if (xdst == NULL) |
80c802f30 xfrm: cache bundl... |
2909 |
goto nopol; |
bd45c539b xfrm_policy: make... |
2910 2911 |
if (IS_ERR(xdst)) { err = PTR_ERR(xdst); |
75b8c1332 [IPSEC]: Fix pote... |
2912 |
goto dropdst; |
d66e37a99 [XFRM] Statistics... |
2913 |
} |
80c802f30 xfrm: cache bundl... |
2914 2915 2916 |
num_pols = xdst->num_pols; num_xfrms = xdst->num_xfrms; |
3e94c2dcf xfrm: checkpatch ... |
2917 |
memcpy(pols, xdst->pols, sizeof(struct xfrm_policy *) * num_pols); |
80c802f30 xfrm: cache bundl... |
2918 2919 2920 2921 2922 2923 2924 2925 2926 2927 2928 2929 |
route = xdst->route; } dst = &xdst->u.dst; if (route == NULL && num_xfrms > 0) { /* The only case when xfrm_bundle_lookup() returns a * bundle with null route, is when the template could * not be resolved. It means policies are there, but * bundle could not be created, since we don't yet * have the xfrm_state's. We need to wait for KM to * negotiate new SA's or bail out with error.*/ if (net->xfrm.sysctl_larval_drop) { |
80c802f30 xfrm: cache bundl... |
2930 |
XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTNOSTATES); |
ac37e2515 xfrm: release dst... |
2931 2932 |
err = -EREMOTE; goto error; |
80c802f30 xfrm: cache bundl... |
2933 |
} |
80c802f30 xfrm: cache bundl... |
2934 |
|
5b8ef3415 xfrm: Remove anci... |
2935 |
err = -EAGAIN; |
80c802f30 xfrm: cache bundl... |
2936 2937 2938 |
XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTNOSTATES); goto error; |
1da177e4c Linux-2.6.12-rc2 |
2939 |
} |
80c802f30 xfrm: cache bundl... |
2940 2941 |
no_transform: if (num_pols == 0) |
8b7817f3a [IPSEC]: Add ICMP... |
2942 |
goto nopol; |
1da177e4c Linux-2.6.12-rc2 |
2943 |
|
80c802f30 xfrm: cache bundl... |
2944 2945 2946 |
if ((flags & XFRM_LOOKUP_ICMP) && !(pols[0]->flags & XFRM_POLICY_ICMP)) { err = -ENOENT; |
8b7817f3a [IPSEC]: Add ICMP... |
2947 |
goto error; |
80c802f30 xfrm: cache bundl... |
2948 |
} |
8b7817f3a [IPSEC]: Add ICMP... |
2949 |
|
80c802f30 xfrm: cache bundl... |
2950 |
for (i = 0; i < num_pols; i++) |
386c5680e xfrm: use time64_... |
2951 |
pols[i]->curlft.use_time = ktime_get_real_seconds(); |
8b7817f3a [IPSEC]: Add ICMP... |
2952 |
|
80c802f30 xfrm: cache bundl... |
2953 |
if (num_xfrms < 0) { |
1da177e4c Linux-2.6.12-rc2 |
2954 |
/* Prohibit the flow */ |
59c9940ed netns xfrm: per-n... |
2955 |
XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTPOLBLOCK); |
e104411b8 [XFRM]: Always re... |
2956 2957 |
err = -EPERM; goto error; |
80c802f30 xfrm: cache bundl... |
2958 2959 |
} else if (num_xfrms > 0) { /* Flow transformed */ |
80c802f30 xfrm: cache bundl... |
2960 2961 2962 2963 |
dst_release(dst_orig); } else { /* Flow passes untransformed */ dst_release(dst); |
452edd598 xfrm: Return dst ... |
2964 |
dst = dst_orig; |
1da177e4c Linux-2.6.12-rc2 |
2965 |
} |
80c802f30 xfrm: cache bundl... |
2966 2967 |
ok: xfrm_pols_put(pols, drop_pols); |
0c1833797 ipv6: fix incorre... |
2968 2969 2970 |
if (dst && dst->xfrm && dst->xfrm->props.mode == XFRM_MODE_TUNNEL) dst->flags |= DST_XFRM_TUNNEL; |
452edd598 xfrm: Return dst ... |
2971 |
return dst; |
1da177e4c Linux-2.6.12-rc2 |
2972 |
|
80c802f30 xfrm: cache bundl... |
2973 |
nopol: |
452edd598 xfrm: Return dst ... |
2974 2975 |
if (!(flags & XFRM_LOOKUP_ICMP)) { dst = dst_orig; |
80c802f30 xfrm: cache bundl... |
2976 |
goto ok; |
452edd598 xfrm: Return dst ... |
2977 |
} |
80c802f30 xfrm: cache bundl... |
2978 |
err = -ENOENT; |
1da177e4c Linux-2.6.12-rc2 |
2979 |
error: |
80c802f30 xfrm: cache bundl... |
2980 |
dst_release(dst); |
75b8c1332 [IPSEC]: Fix pote... |
2981 |
dropdst: |
ac37e2515 xfrm: release dst... |
2982 2983 |
if (!(flags & XFRM_LOOKUP_KEEP_DST_REF)) dst_release(dst_orig); |
80c802f30 xfrm: cache bundl... |
2984 |
xfrm_pols_put(pols, drop_pols); |
452edd598 xfrm: Return dst ... |
2985 |
return ERR_PTR(err); |
1da177e4c Linux-2.6.12-rc2 |
2986 |
} |
bc56b3340 xfrm: Remove xfrm... |
2987 2988 2989 2990 2991 2992 2993 2994 2995 2996 2997 2998 2999 |
EXPORT_SYMBOL(xfrm_lookup_with_ifid); /* Main function: finds/creates a bundle for given flow. * * At the moment we eat a raw IP route. Mostly to speed up lookups * on interfaces with disabled IPsec. */ struct dst_entry *xfrm_lookup(struct net *net, struct dst_entry *dst_orig, const struct flowi *fl, const struct sock *sk, int flags) { return xfrm_lookup_with_ifid(net, dst_orig, fl, sk, flags, 0); } |
1da177e4c Linux-2.6.12-rc2 |
3000 |
EXPORT_SYMBOL(xfrm_lookup); |
f92ee6198 xfrm: Generate bl... |
3001 3002 3003 3004 3005 |
/* Callers of xfrm_lookup_route() must ensure a call to dst_output(). * Otherwise we may send out blackholed packets. */ struct dst_entry *xfrm_lookup_route(struct net *net, struct dst_entry *dst_orig, const struct flowi *fl, |
6f9c96154 inet: constify ip... |
3006 |
const struct sock *sk, int flags) |
f92ee6198 xfrm: Generate bl... |
3007 |
{ |
b8c203b2d xfrm: Generate qu... |
3008 |
struct dst_entry *dst = xfrm_lookup(net, dst_orig, fl, sk, |
ac37e2515 xfrm: release dst... |
3009 3010 |
flags | XFRM_LOOKUP_QUEUE | XFRM_LOOKUP_KEEP_DST_REF); |
f92ee6198 xfrm: Generate bl... |
3011 |
|
45586c707 treewide: remove ... |
3012 |
if (PTR_ERR(dst) == -EREMOTE) |
f92ee6198 xfrm: Generate bl... |
3013 |
return make_blackhole(net, dst_orig->ops->family, dst_orig); |
8cc887738 xfrm: fix missing... |
3014 3015 |
if (IS_ERR(dst)) dst_release(dst_orig); |
f92ee6198 xfrm: Generate bl... |
3016 3017 3018 |
return dst; } EXPORT_SYMBOL(xfrm_lookup_route); |
df0ba92a9 [XFRM]: Trace whi... |
3019 |
static inline int |
8f029de28 xfrm: Mark flowi ... |
3020 |
xfrm_secpath_reject(int idx, struct sk_buff *skb, const struct flowi *fl) |
df0ba92a9 [XFRM]: Trace whi... |
3021 |
{ |
2294be0f1 net: use skb_sec_... |
3022 |
struct sec_path *sp = skb_sec_path(skb); |
df0ba92a9 [XFRM]: Trace whi... |
3023 |
struct xfrm_state *x; |
df0ba92a9 [XFRM]: Trace whi... |
3024 |
|
2294be0f1 net: use skb_sec_... |
3025 |
if (!sp || idx < 0 || idx >= sp->len) |
df0ba92a9 [XFRM]: Trace whi... |
3026 |
return 0; |
2294be0f1 net: use skb_sec_... |
3027 |
x = sp->xvec[idx]; |
df0ba92a9 [XFRM]: Trace whi... |
3028 3029 |
if (!x->type->reject) return 0; |
1ecafede8 [IPSEC]: Remove b... |
3030 |
return x->type->reject(x, skb, fl); |
df0ba92a9 [XFRM]: Trace whi... |
3031 |
} |
1da177e4c Linux-2.6.12-rc2 |
3032 3033 3034 3035 3036 3037 3038 |
/* When skb is transformed back to its "native" form, we have to * check policy restrictions. At the moment we make this in maximally * stupid way. Shame on me. :-) Of course, connected sockets must * have policy cached at them. */ static inline int |
7db454b91 xfrm: Const'ify p... |
3039 |
xfrm_state_ok(const struct xfrm_tmpl *tmpl, const struct xfrm_state *x, |
1da177e4c Linux-2.6.12-rc2 |
3040 3041 3042 |
unsigned short family) { if (xfrm_state_kern(x)) |
928ba4169 [IPSEC]: Fix the ... |
3043 |
return tmpl->optional && !xfrm_state_addr_cmp(tmpl, x, tmpl->encap_family); |
1da177e4c Linux-2.6.12-rc2 |
3044 3045 3046 3047 |
return x->id.proto == tmpl->id.proto && (x->id.spi == tmpl->id.spi || !tmpl->id.spi) && (x->props.reqid == tmpl->reqid || !tmpl->reqid) && x->props.mode == tmpl->mode && |
c5d18e984 [IPSEC]: Fix catc... |
3048 |
(tmpl->allalgs || (tmpl->aalgos & (1<<x->props.aalgo)) || |
f3bd48402 [XFRM]: Restrict ... |
3049 |
!(xfrm_id_proto_match(tmpl->id.proto, IPSEC_PROTO_ANY))) && |
7e49e6de3 [XFRM]: Add XFRM_... |
3050 3051 |
!(x->props.mode != XFRM_MODE_TRANSPORT && xfrm_state_addr_cmp(tmpl, x, family)); |
1da177e4c Linux-2.6.12-rc2 |
3052 |
} |
df0ba92a9 [XFRM]: Trace whi... |
3053 3054 3055 3056 3057 3058 3059 |
/* * 0 or more than 0 is returned when validation is succeeded (either bypass * because of optional transport mode, or next index of the mathced secpath * state with the template. * -1 is returned when no matching template is found. * Otherwise "-2 - errored_index" is returned. */ |
1da177e4c Linux-2.6.12-rc2 |
3060 |
static inline int |
22cccb7e0 xfrm: Const'ify p... |
3061 |
xfrm_policy_ok(const struct xfrm_tmpl *tmpl, const struct sec_path *sp, int start, |
1da177e4c Linux-2.6.12-rc2 |
3062 3063 3064 3065 3066 |
unsigned short family) { int idx = start; if (tmpl->optional) { |
7e49e6de3 [XFRM]: Add XFRM_... |
3067 |
if (tmpl->mode == XFRM_MODE_TRANSPORT) |
1da177e4c Linux-2.6.12-rc2 |
3068 3069 3070 3071 |
return start; } else start = -1; for (; idx < sp->len; idx++) { |
dbe5b4aaa [IPSEC]: Kill unu... |
3072 |
if (xfrm_state_ok(tmpl, sp->xvec[idx], family)) |
1da177e4c Linux-2.6.12-rc2 |
3073 |
return ++idx; |
df0ba92a9 [XFRM]: Trace whi... |
3074 3075 3076 |
if (sp->xvec[idx]->props.mode != XFRM_MODE_TRANSPORT) { if (start == -1) start = -2-idx; |
1da177e4c Linux-2.6.12-rc2 |
3077 |
break; |
df0ba92a9 [XFRM]: Trace whi... |
3078 |
} |
1da177e4c Linux-2.6.12-rc2 |
3079 3080 3081 |
} return start; } |
c53ac41e3 xfrm: remove deco... |
3082 3083 3084 3085 |
static void decode_session4(struct sk_buff *skb, struct flowi *fl, bool reverse) { const struct iphdr *iph = ip_hdr(skb); |
858e5400e xfrm: ressurrect ... |
3086 3087 |
int ihl = iph->ihl; u8 *xprth = skb_network_header(skb) + ihl * 4; |
c53ac41e3 xfrm: remove deco... |
3088 3089 |
struct flowi4 *fl4 = &fl->u.ip4; int oif = 0; |
c3b4c3a47 xfrm/xfrm_policy:... |
3090 |
if (skb_dst(skb) && skb_dst(skb)->dev) |
c53ac41e3 xfrm: remove deco... |
3091 3092 3093 3094 3095 |
oif = skb_dst(skb)->dev->ifindex; memset(fl4, 0, sizeof(struct flowi4)); fl4->flowi4_mark = skb->mark; fl4->flowi4_oif = reverse ? skb->skb_iif : oif; |
858e5400e xfrm: ressurrect ... |
3096 3097 3098 3099 |
fl4->flowi4_proto = iph->protocol; fl4->daddr = reverse ? iph->saddr : iph->daddr; fl4->saddr = reverse ? iph->daddr : iph->saddr; fl4->flowi4_tos = iph->tos; |
c53ac41e3 xfrm: remove deco... |
3100 3101 3102 3103 3104 3105 3106 3107 3108 3109 |
if (!ip_is_fragment(iph)) { switch (iph->protocol) { case IPPROTO_UDP: case IPPROTO_UDPLITE: case IPPROTO_TCP: case IPPROTO_SCTP: case IPPROTO_DCCP: if (xprth + 4 < skb->data || pskb_may_pull(skb, xprth + 4 - skb->data)) { __be16 *ports; |
858e5400e xfrm: ressurrect ... |
3110 |
xprth = skb_network_header(skb) + ihl * 4; |
c53ac41e3 xfrm: remove deco... |
3111 3112 3113 3114 3115 3116 3117 3118 3119 3120 |
ports = (__be16 *)xprth; fl4->fl4_sport = ports[!!reverse]; fl4->fl4_dport = ports[!reverse]; } break; case IPPROTO_ICMP: if (xprth + 2 < skb->data || pskb_may_pull(skb, xprth + 2 - skb->data)) { u8 *icmp; |
858e5400e xfrm: ressurrect ... |
3121 |
xprth = skb_network_header(skb) + ihl * 4; |
c53ac41e3 xfrm: remove deco... |
3122 3123 3124 3125 3126 3127 3128 3129 3130 3131 |
icmp = xprth; fl4->fl4_icmp_type = icmp[0]; fl4->fl4_icmp_code = icmp[1]; } break; case IPPROTO_ESP: if (xprth + 4 < skb->data || pskb_may_pull(skb, xprth + 4 - skb->data)) { __be32 *ehdr; |
858e5400e xfrm: ressurrect ... |
3132 |
xprth = skb_network_header(skb) + ihl * 4; |
c53ac41e3 xfrm: remove deco... |
3133 3134 3135 3136 3137 3138 3139 3140 3141 |
ehdr = (__be32 *)xprth; fl4->fl4_ipsec_spi = ehdr[0]; } break; case IPPROTO_AH: if (xprth + 8 < skb->data || pskb_may_pull(skb, xprth + 8 - skb->data)) { __be32 *ah_hdr; |
858e5400e xfrm: ressurrect ... |
3142 |
xprth = skb_network_header(skb) + ihl * 4; |
c53ac41e3 xfrm: remove deco... |
3143 3144 3145 3146 3147 3148 3149 3150 3151 |
ah_hdr = (__be32 *)xprth; fl4->fl4_ipsec_spi = ah_hdr[1]; } break; case IPPROTO_COMP: if (xprth + 4 < skb->data || pskb_may_pull(skb, xprth + 4 - skb->data)) { __be16 *ipcomp_hdr; |
858e5400e xfrm: ressurrect ... |
3152 |
xprth = skb_network_header(skb) + ihl * 4; |
c53ac41e3 xfrm: remove deco... |
3153 3154 3155 3156 3157 3158 3159 3160 3161 3162 |
ipcomp_hdr = (__be16 *)xprth; fl4->fl4_ipsec_spi = htonl(ntohs(ipcomp_hdr[1])); } break; case IPPROTO_GRE: if (xprth + 12 < skb->data || pskb_may_pull(skb, xprth + 12 - skb->data)) { __be16 *greflags; __be32 *gre_hdr; |
858e5400e xfrm: ressurrect ... |
3163 |
xprth = skb_network_header(skb) + ihl * 4; |
c53ac41e3 xfrm: remove deco... |
3164 3165 3166 3167 3168 3169 3170 3171 3172 3173 3174 3175 3176 3177 3178 |
greflags = (__be16 *)xprth; gre_hdr = (__be32 *)xprth; if (greflags[0] & GRE_KEY) { if (greflags[0] & GRE_CSUM) gre_hdr++; fl4->fl4_gre_key = gre_hdr[1]; } } break; default: fl4->fl4_ipsec_spi = 0; break; } } |
c53ac41e3 xfrm: remove deco... |
3179 3180 3181 3182 3183 3184 3185 3186 3187 3188 3189 3190 3191 3192 3193 3194 3195 3196 3197 3198 |
} #if IS_ENABLED(CONFIG_IPV6) static void decode_session6(struct sk_buff *skb, struct flowi *fl, bool reverse) { struct flowi6 *fl6 = &fl->u.ip6; int onlyproto = 0; const struct ipv6hdr *hdr = ipv6_hdr(skb); u32 offset = sizeof(*hdr); struct ipv6_opt_hdr *exthdr; const unsigned char *nh = skb_network_header(skb); u16 nhoff = IP6CB(skb)->nhoff; int oif = 0; u8 nexthdr; if (!nhoff) nhoff = offsetof(struct ipv6hdr, nexthdr); nexthdr = nh[nhoff]; |
c3b4c3a47 xfrm/xfrm_policy:... |
3199 |
if (skb_dst(skb) && skb_dst(skb)->dev) |
c53ac41e3 xfrm: remove deco... |
3200 3201 3202 3203 3204 3205 3206 3207 3208 3209 3210 3211 3212 3213 3214 3215 3216 |
oif = skb_dst(skb)->dev->ifindex; memset(fl6, 0, sizeof(struct flowi6)); fl6->flowi6_mark = skb->mark; fl6->flowi6_oif = reverse ? skb->skb_iif : oif; fl6->daddr = reverse ? hdr->saddr : hdr->daddr; fl6->saddr = reverse ? hdr->daddr : hdr->saddr; while (nh + offset + sizeof(*exthdr) < skb->data || pskb_may_pull(skb, nh + offset + sizeof(*exthdr) - skb->data)) { nh = skb_network_header(skb); exthdr = (struct ipv6_opt_hdr *)(nh + offset); switch (nexthdr) { case NEXTHDR_FRAGMENT: onlyproto = 1; |
df561f668 treewide: Use fal... |
3217 |
fallthrough; |
c53ac41e3 xfrm: remove deco... |
3218 3219 3220 3221 3222 3223 3224 3225 3226 3227 3228 3229 3230 3231 3232 3233 3234 3235 3236 3237 3238 3239 3240 3241 3242 3243 3244 3245 3246 3247 3248 3249 3250 3251 3252 3253 3254 3255 3256 3257 3258 3259 3260 3261 3262 3263 3264 3265 3266 3267 3268 3269 3270 3271 3272 3273 3274 3275 3276 3277 3278 |
case NEXTHDR_ROUTING: case NEXTHDR_HOP: case NEXTHDR_DEST: offset += ipv6_optlen(exthdr); nexthdr = exthdr->nexthdr; exthdr = (struct ipv6_opt_hdr *)(nh + offset); break; case IPPROTO_UDP: case IPPROTO_UDPLITE: case IPPROTO_TCP: case IPPROTO_SCTP: case IPPROTO_DCCP: if (!onlyproto && (nh + offset + 4 < skb->data || pskb_may_pull(skb, nh + offset + 4 - skb->data))) { __be16 *ports; nh = skb_network_header(skb); ports = (__be16 *)(nh + offset); fl6->fl6_sport = ports[!!reverse]; fl6->fl6_dport = ports[!reverse]; } fl6->flowi6_proto = nexthdr; return; case IPPROTO_ICMPV6: if (!onlyproto && (nh + offset + 2 < skb->data || pskb_may_pull(skb, nh + offset + 2 - skb->data))) { u8 *icmp; nh = skb_network_header(skb); icmp = (u8 *)(nh + offset); fl6->fl6_icmp_type = icmp[0]; fl6->fl6_icmp_code = icmp[1]; } fl6->flowi6_proto = nexthdr; return; #if IS_ENABLED(CONFIG_IPV6_MIP6) case IPPROTO_MH: offset += ipv6_optlen(exthdr); if (!onlyproto && (nh + offset + 3 < skb->data || pskb_may_pull(skb, nh + offset + 3 - skb->data))) { struct ip6_mh *mh; nh = skb_network_header(skb); mh = (struct ip6_mh *)(nh + offset); fl6->fl6_mh_type = mh->ip6mh_type; } fl6->flowi6_proto = nexthdr; return; #endif /* XXX Why are there these headers? */ case IPPROTO_AH: case IPPROTO_ESP: case IPPROTO_COMP: default: fl6->fl6_ipsec_spi = 0; fl6->flowi6_proto = nexthdr; return; } } } #endif |
d5422efe6 [IPSEC]: Added xf... |
3279 3280 |
int __xfrm_decode_session(struct sk_buff *skb, struct flowi *fl, unsigned int family, int reverse) |
1da177e4c Linux-2.6.12-rc2 |
3281 |
{ |
c53ac41e3 xfrm: remove deco... |
3282 3283 3284 3285 3286 3287 3288 3289 3290 3291 |
switch (family) { case AF_INET: decode_session4(skb, fl, reverse); break; #if IS_ENABLED(CONFIG_IPV6) case AF_INET6: decode_session6(skb, fl, reverse); break; #endif default: |
1da177e4c Linux-2.6.12-rc2 |
3292 |
return -EAFNOSUPPORT; |
c53ac41e3 xfrm: remove deco... |
3293 |
} |
1da177e4c Linux-2.6.12-rc2 |
3294 |
|
c53ac41e3 xfrm: remove deco... |
3295 |
return security_xfrm_decode_session(skb, &fl->flowi_secid); |
1da177e4c Linux-2.6.12-rc2 |
3296 |
} |
d5422efe6 [IPSEC]: Added xf... |
3297 |
EXPORT_SYMBOL(__xfrm_decode_session); |
1da177e4c Linux-2.6.12-rc2 |
3298 |
|
9a7386ec9 xfrm: Const'ify s... |
3299 |
static inline int secpath_has_nontransport(const struct sec_path *sp, int k, int *idxp) |
1da177e4c Linux-2.6.12-rc2 |
3300 3301 |
{ for (; k < sp->len; k++) { |
df0ba92a9 [XFRM]: Trace whi... |
3302 |
if (sp->xvec[k]->props.mode != XFRM_MODE_TRANSPORT) { |
d1d9facfd [XFRM]: remove xe... |
3303 |
*idxp = k; |
1da177e4c Linux-2.6.12-rc2 |
3304 |
return 1; |
df0ba92a9 [XFRM]: Trace whi... |
3305 |
} |
1da177e4c Linux-2.6.12-rc2 |
3306 3307 3308 3309 |
} return 0; } |
a716c1197 [NET] XFRM: Fix w... |
3310 |
int __xfrm_policy_check(struct sock *sk, int dir, struct sk_buff *skb, |
1da177e4c Linux-2.6.12-rc2 |
3311 3312 |
unsigned short family) { |
f6e1e25d7 netns xfrm: xfrm_... |
3313 |
struct net *net = dev_net(skb->dev); |
1da177e4c Linux-2.6.12-rc2 |
3314 |
struct xfrm_policy *pol; |
4e81bb833 [XFRM] POLICY: su... |
3315 3316 3317 3318 |
struct xfrm_policy *pols[XFRM_POLICY_TYPE_MAX]; int npols = 0; int xfrm_nr; int pi; |
d5422efe6 [IPSEC]: Added xf... |
3319 |
int reverse; |
1da177e4c Linux-2.6.12-rc2 |
3320 |
struct flowi fl; |
df0ba92a9 [XFRM]: Trace whi... |
3321 |
int xerr_idx = -1; |
bc56b3340 xfrm: Remove xfrm... |
3322 |
const struct xfrm_if_cb *ifcb; |
2294be0f1 net: use skb_sec_... |
3323 |
struct sec_path *sp; |
bc56b3340 xfrm: Remove xfrm... |
3324 3325 3326 3327 3328 3329 3330 |
struct xfrm_if *xi; u32 if_id = 0; rcu_read_lock(); ifcb = xfrm_if_get_cb(); if (ifcb) { |
025c65e11 xfrm: Honor origi... |
3331 |
xi = ifcb->decode_session(skb, family); |
660899ddf xfrm: Fix inbound... |
3332 |
if (xi) { |
bc56b3340 xfrm: Remove xfrm... |
3333 |
if_id = xi->p.if_id; |
660899ddf xfrm: Fix inbound... |
3334 3335 |
net = xi->net; } |
bc56b3340 xfrm: Remove xfrm... |
3336 3337 |
} rcu_read_unlock(); |
1da177e4c Linux-2.6.12-rc2 |
3338 |
|
d5422efe6 [IPSEC]: Added xf... |
3339 3340 |
reverse = dir & ~XFRM_POLICY_MASK; dir &= XFRM_POLICY_MASK; |
d5422efe6 [IPSEC]: Added xf... |
3341 |
|
0aa647746 [XFRM]: Support t... |
3342 |
if (__xfrm_decode_session(skb, &fl, family, reverse) < 0) { |
59c9940ed netns xfrm: per-n... |
3343 |
XFRM_INC_STATS(net, LINUX_MIB_XFRMINHDRERROR); |
1da177e4c Linux-2.6.12-rc2 |
3344 |
return 0; |
0aa647746 [XFRM]: Support t... |
3345 |
} |
eb9c7ebe6 [NETFILTER]: Hand... |
3346 |
nf_nat_decode_session(skb, &fl, family); |
1da177e4c Linux-2.6.12-rc2 |
3347 3348 |
/* First, check used SA against their selectors. */ |
2294be0f1 net: use skb_sec_... |
3349 3350 |
sp = skb_sec_path(skb); if (sp) { |
1da177e4c Linux-2.6.12-rc2 |
3351 |
int i; |
2294be0f1 net: use skb_sec_... |
3352 3353 |
for (i = sp->len - 1; i >= 0; i--) { struct xfrm_state *x = sp->xvec[i]; |
0aa647746 [XFRM]: Support t... |
3354 |
if (!xfrm_selector_match(&x->sel, &fl, family)) { |
59c9940ed netns xfrm: per-n... |
3355 |
XFRM_INC_STATS(net, LINUX_MIB_XFRMINSTATEMISMATCH); |
1da177e4c Linux-2.6.12-rc2 |
3356 |
return 0; |
0aa647746 [XFRM]: Support t... |
3357 |
} |
1da177e4c Linux-2.6.12-rc2 |
3358 3359 3360 3361 |
} } pol = NULL; |
bd5eb35f1 xfrm: take care o... |
3362 |
sk = sk_to_full_sk(sk); |
3bccfbc7a IPsec: fix handli... |
3363 |
if (sk && sk->sk_policy[dir]) { |
bc56b3340 xfrm: Remove xfrm... |
3364 |
pol = xfrm_sk_policy_lookup(sk, dir, &fl, family, if_id); |
0aa647746 [XFRM]: Support t... |
3365 |
if (IS_ERR(pol)) { |
59c9940ed netns xfrm: per-n... |
3366 |
XFRM_INC_STATS(net, LINUX_MIB_XFRMINPOLERROR); |
3bccfbc7a IPsec: fix handli... |
3367 |
return 0; |
0aa647746 [XFRM]: Support t... |
3368 |
} |
3bccfbc7a IPsec: fix handli... |
3369 |
} |
1da177e4c Linux-2.6.12-rc2 |
3370 |
|
86dc8ee0b xfrm_policy: remo... |
3371 |
if (!pol) |
bc56b3340 xfrm: Remove xfrm... |
3372 |
pol = xfrm_policy_lookup(net, &fl, family, dir, if_id); |
1da177e4c Linux-2.6.12-rc2 |
3373 |
|
0aa647746 [XFRM]: Support t... |
3374 |
if (IS_ERR(pol)) { |
59c9940ed netns xfrm: per-n... |
3375 |
XFRM_INC_STATS(net, LINUX_MIB_XFRMINPOLERROR); |
134b0fc54 IPsec: propagate ... |
3376 |
return 0; |
0aa647746 [XFRM]: Support t... |
3377 |
} |
134b0fc54 IPsec: propagate ... |
3378 |
|
df0ba92a9 [XFRM]: Trace whi... |
3379 |
if (!pol) { |
2294be0f1 net: use skb_sec_... |
3380 |
if (sp && secpath_has_nontransport(sp, 0, &xerr_idx)) { |
df0ba92a9 [XFRM]: Trace whi... |
3381 |
xfrm_secpath_reject(xerr_idx, skb, &fl); |
59c9940ed netns xfrm: per-n... |
3382 |
XFRM_INC_STATS(net, LINUX_MIB_XFRMINNOPOLS); |
df0ba92a9 [XFRM]: Trace whi... |
3383 3384 3385 3386 |
return 0; } return 1; } |
1da177e4c Linux-2.6.12-rc2 |
3387 |
|
386c5680e xfrm: use time64_... |
3388 |
pol->curlft.use_time = ktime_get_real_seconds(); |
1da177e4c Linux-2.6.12-rc2 |
3389 |
|
4e81bb833 [XFRM] POLICY: su... |
3390 |
pols[0] = pol; |
02d0892f9 xfrm: checkpatch ... |
3391 |
npols++; |
4e81bb833 [XFRM] POLICY: su... |
3392 3393 |
#ifdef CONFIG_XFRM_SUB_POLICY if (pols[0]->type != XFRM_POLICY_TYPE_MAIN) { |
f6e1e25d7 netns xfrm: xfrm_... |
3394 |
pols[1] = xfrm_policy_lookup_bytype(net, XFRM_POLICY_TYPE_MAIN, |
4e81bb833 [XFRM] POLICY: su... |
3395 |
&fl, family, |
bc56b3340 xfrm: Remove xfrm... |
3396 |
XFRM_POLICY_IN, if_id); |
4e81bb833 [XFRM] POLICY: su... |
3397 |
if (pols[1]) { |
0aa647746 [XFRM]: Support t... |
3398 |
if (IS_ERR(pols[1])) { |
59c9940ed netns xfrm: per-n... |
3399 |
XFRM_INC_STATS(net, LINUX_MIB_XFRMINPOLERROR); |
134b0fc54 IPsec: propagate ... |
3400 |
return 0; |
0aa647746 [XFRM]: Support t... |
3401 |
} |
386c5680e xfrm: use time64_... |
3402 |
pols[1]->curlft.use_time = ktime_get_real_seconds(); |
02d0892f9 xfrm: checkpatch ... |
3403 |
npols++; |
4e81bb833 [XFRM] POLICY: su... |
3404 3405 3406 |
} } #endif |
1da177e4c Linux-2.6.12-rc2 |
3407 |
if (pol->action == XFRM_POLICY_ALLOW) { |
1da177e4c Linux-2.6.12-rc2 |
3408 |
static struct sec_path dummy; |
4e81bb833 [XFRM] POLICY: su... |
3409 |
struct xfrm_tmpl *tp[XFRM_MAX_DEPTH]; |
41a49cc3c [XFRM]: Add sorti... |
3410 |
struct xfrm_tmpl *stp[XFRM_MAX_DEPTH]; |
4e81bb833 [XFRM] POLICY: su... |
3411 3412 |
struct xfrm_tmpl **tpp = tp; int ti = 0; |
1da177e4c Linux-2.6.12-rc2 |
3413 |
int i, k; |
2294be0f1 net: use skb_sec_... |
3414 3415 |
sp = skb_sec_path(skb); if (!sp) |
1da177e4c Linux-2.6.12-rc2 |
3416 |
sp = &dummy; |
4e81bb833 [XFRM] POLICY: su... |
3417 3418 |
for (pi = 0; pi < npols; pi++) { if (pols[pi] != pol && |
0aa647746 [XFRM]: Support t... |
3419 |
pols[pi]->action != XFRM_POLICY_ALLOW) { |
59c9940ed netns xfrm: per-n... |
3420 |
XFRM_INC_STATS(net, LINUX_MIB_XFRMINPOLBLOCK); |
4e81bb833 [XFRM] POLICY: su... |
3421 |
goto reject; |
0aa647746 [XFRM]: Support t... |
3422 3423 |
} if (ti + pols[pi]->xfrm_nr >= XFRM_MAX_DEPTH) { |
59c9940ed netns xfrm: per-n... |
3424 |
XFRM_INC_STATS(net, LINUX_MIB_XFRMINBUFFERERROR); |
4e81bb833 [XFRM] POLICY: su... |
3425 |
goto reject_error; |
0aa647746 [XFRM]: Support t... |
3426 |
} |
4e81bb833 [XFRM] POLICY: su... |
3427 3428 3429 3430 |
for (i = 0; i < pols[pi]->xfrm_nr; i++) tpp[ti++] = &pols[pi]->xfrm_vec[i]; } xfrm_nr = ti; |
41a49cc3c [XFRM]: Add sorti... |
3431 |
if (npols > 1) { |
3aaf3915a xfrm: remove stat... |
3432 |
xfrm_tmpl_sort(stp, tpp, xfrm_nr, family); |
41a49cc3c [XFRM]: Add sorti... |
3433 3434 |
tpp = stp; } |
4e81bb833 [XFRM] POLICY: su... |
3435 |
|
1da177e4c Linux-2.6.12-rc2 |
3436 3437 3438 3439 3440 3441 |
/* For each tunnel xfrm, find the first matching tmpl. * For each tmpl before that, find corresponding xfrm. * Order is _important_. Later we will implement * some barriers, but at the moment barriers * are implied between each two transformations. */ |
4e81bb833 [XFRM] POLICY: su... |
3442 3443 |
for (i = xfrm_nr-1, k = 0; i >= 0; i--) { k = xfrm_policy_ok(tpp[i], sp, k, family); |
df0ba92a9 [XFRM]: Trace whi... |
3444 |
if (k < 0) { |
d1d9facfd [XFRM]: remove xe... |
3445 3446 3447 |
if (k < -1) /* "-2 - errored_index" returned */ xerr_idx = -(2+k); |
59c9940ed netns xfrm: per-n... |
3448 |
XFRM_INC_STATS(net, LINUX_MIB_XFRMINTMPLMISMATCH); |
1da177e4c Linux-2.6.12-rc2 |
3449 |
goto reject; |
df0ba92a9 [XFRM]: Trace whi... |
3450 |
} |
1da177e4c Linux-2.6.12-rc2 |
3451 |
} |
0aa647746 [XFRM]: Support t... |
3452 |
if (secpath_has_nontransport(sp, k, &xerr_idx)) { |
59c9940ed netns xfrm: per-n... |
3453 |
XFRM_INC_STATS(net, LINUX_MIB_XFRMINTMPLMISMATCH); |
1da177e4c Linux-2.6.12-rc2 |
3454 |
goto reject; |
0aa647746 [XFRM]: Support t... |
3455 |
} |
1da177e4c Linux-2.6.12-rc2 |
3456 |
|
4e81bb833 [XFRM] POLICY: su... |
3457 |
xfrm_pols_put(pols, npols); |
1da177e4c Linux-2.6.12-rc2 |
3458 3459 |
return 1; } |
59c9940ed netns xfrm: per-n... |
3460 |
XFRM_INC_STATS(net, LINUX_MIB_XFRMINPOLBLOCK); |
1da177e4c Linux-2.6.12-rc2 |
3461 3462 |
reject: |
df0ba92a9 [XFRM]: Trace whi... |
3463 |
xfrm_secpath_reject(xerr_idx, skb, &fl); |
4e81bb833 [XFRM] POLICY: su... |
3464 3465 |
reject_error: xfrm_pols_put(pols, npols); |
1da177e4c Linux-2.6.12-rc2 |
3466 3467 3468 3469 3470 3471 |
return 0; } EXPORT_SYMBOL(__xfrm_policy_check); int __xfrm_route_forward(struct sk_buff *skb, unsigned short family) { |
99a66657b netns xfrm: xfrm_... |
3472 |
struct net *net = dev_net(skb->dev); |
1da177e4c Linux-2.6.12-rc2 |
3473 |
struct flowi fl; |
adf30907d net: skb->dst acc... |
3474 |
struct dst_entry *dst; |
731371477 xfrm: fix __xfrm_... |
3475 |
int res = 1; |
1da177e4c Linux-2.6.12-rc2 |
3476 |
|
0aa647746 [XFRM]: Support t... |
3477 |
if (xfrm_decode_session(skb, &fl, family) < 0) { |
72032fdbc xfrm: Introduce L... |
3478 |
XFRM_INC_STATS(net, LINUX_MIB_XFRMFWDHDRERROR); |
1da177e4c Linux-2.6.12-rc2 |
3479 |
return 0; |
0aa647746 [XFRM]: Support t... |
3480 |
} |
1da177e4c Linux-2.6.12-rc2 |
3481 |
|
fafeeb6c8 xfrm: force a dst... |
3482 |
skb_dst_force(skb); |
9e1437937 xfrm: Fix NULL po... |
3483 3484 3485 3486 |
if (!skb_dst(skb)) { XFRM_INC_STATS(net, LINUX_MIB_XFRMFWDHDRERROR); return 0; } |
adf30907d net: skb->dst acc... |
3487 |
|
b8c203b2d xfrm: Generate qu... |
3488 |
dst = xfrm_lookup(net, skb_dst(skb), &fl, NULL, XFRM_LOOKUP_QUEUE); |
452edd598 xfrm: Return dst ... |
3489 |
if (IS_ERR(dst)) { |
731371477 xfrm: fix __xfrm_... |
3490 |
res = 0; |
452edd598 xfrm: Return dst ... |
3491 3492 |
dst = NULL; } |
adf30907d net: skb->dst acc... |
3493 3494 |
skb_dst_set(skb, dst); return res; |
1da177e4c Linux-2.6.12-rc2 |
3495 3496 |
} EXPORT_SYMBOL(__xfrm_route_forward); |
d49c73c72 [IPSEC]: Validate... |
3497 |
/* Optimize later using cookies and generation ids. */ |
1da177e4c Linux-2.6.12-rc2 |
3498 3499 |
static struct dst_entry *xfrm_dst_check(struct dst_entry *dst, u32 cookie) { |
d49c73c72 [IPSEC]: Validate... |
3500 |
/* Code (such as __xfrm4_bundle_create()) sets dst->obsolete |
f5b0a8743 net: Document dst... |
3501 3502 3503 3504 3505 3506 3507 |
* to DST_OBSOLETE_FORCE_CHK to force all XFRM destinations to * get validated by dst_ops->check on every use. We do this * because when a normal route referenced by an XFRM dst is * obsoleted we do not go looking around for all parent * referencing XFRM dsts so that we can invalidate them. It * is just too much work. Instead we make the checks here on * every use. For example: |
d49c73c72 [IPSEC]: Validate... |
3508 3509 3510 3511 3512 3513 3514 3515 |
* * XFRM dst A --> IPv4 dst X * * X is the "xdst->route" of A (X is also the "dst->path" of A * in this example). If X is marked obsolete, "A" will not * notice. That's what we are validating here via the * stale_bundle() check. * |
52df157f1 xfrm: take refcnt... |
3516 3517 |
* When a dst is removed from the fib tree, DST_OBSOLETE_DEAD will * be marked on it. |
09c757048 xfrm: remove flow... |
3518 |
* This will force stale_bundle() to fail on any xdst bundle with |
52df157f1 xfrm: take refcnt... |
3519 |
* this dst linked in it. |
399c180ac [IPSEC]: Perform ... |
3520 |
*/ |
d49c73c72 [IPSEC]: Validate... |
3521 3522 |
if (dst->obsolete < 0 && !stale_bundle(dst)) return dst; |
1da177e4c Linux-2.6.12-rc2 |
3523 3524 3525 3526 3527 |
return NULL; } static int stale_bundle(struct dst_entry *dst) { |
12fdb4d3b xfrm: Remove fami... |
3528 |
return !xfrm_bundle_ok((struct xfrm_dst *)dst); |
1da177e4c Linux-2.6.12-rc2 |
3529 |
} |
aabc9761b [IPSEC]: Store id... |
3530 |
void xfrm_dst_ifdown(struct dst_entry *dst, struct net_device *dev) |
1da177e4c Linux-2.6.12-rc2 |
3531 |
{ |
b92cf4aab net: Create and u... |
3532 |
while ((dst = xfrm_dst_child(dst)) && dst->xfrm && dst->dev == dev) { |
c346dca10 [NET] NETNS: Omit... |
3533 |
dst->dev = dev_net(dev)->loopback_dev; |
de3cb747f [NET]: Dynamicall... |
3534 |
dev_hold(dst->dev); |
1da177e4c Linux-2.6.12-rc2 |
3535 3536 3537 |
dev_put(dev); } } |
aabc9761b [IPSEC]: Store id... |
3538 |
EXPORT_SYMBOL(xfrm_dst_ifdown); |
1da177e4c Linux-2.6.12-rc2 |
3539 3540 3541 3542 |
static void xfrm_link_failure(struct sk_buff *skb) { /* Impossible. Such dst must be popped before reaches point of failure. */ |
1da177e4c Linux-2.6.12-rc2 |
3543 3544 3545 3546 3547 3548 3549 3550 3551 3552 3553 3554 |
} static struct dst_entry *xfrm_negative_advice(struct dst_entry *dst) { if (dst) { if (dst->obsolete) { dst_release(dst); dst = NULL; } } return dst; } |
5492093dc xfrm: Stop using ... |
3555 |
static void xfrm_init_pmtu(struct xfrm_dst **bundle, int nr) |
1da177e4c Linux-2.6.12-rc2 |
3556 |
{ |
5492093dc xfrm: Stop using ... |
3557 3558 |
while (nr--) { struct xfrm_dst *xdst = bundle[nr]; |
1da177e4c Linux-2.6.12-rc2 |
3559 |
u32 pmtu, route_mtu_cached; |
5492093dc xfrm: Stop using ... |
3560 |
struct dst_entry *dst; |
1da177e4c Linux-2.6.12-rc2 |
3561 |
|
5492093dc xfrm: Stop using ... |
3562 |
dst = &xdst->u.dst; |
b92cf4aab net: Create and u... |
3563 |
pmtu = dst_mtu(xfrm_dst_child(dst)); |
1da177e4c Linux-2.6.12-rc2 |
3564 3565 3566 3567 3568 3569 3570 3571 3572 |
xdst->child_mtu_cached = pmtu; pmtu = xfrm_state_mtu(dst->xfrm, pmtu); route_mtu_cached = dst_mtu(xdst->route); xdst->route_mtu_cached = route_mtu_cached; if (pmtu > route_mtu_cached) pmtu = route_mtu_cached; |
defb3519a net: Abstract awa... |
3573 |
dst_metric_set(dst, RTAX_MTU, pmtu); |
5492093dc xfrm: Stop using ... |
3574 |
} |
1da177e4c Linux-2.6.12-rc2 |
3575 |
} |
1da177e4c Linux-2.6.12-rc2 |
3576 3577 3578 |
/* Check that the bundle accepts the flow and its components are * still valid. */ |
12fdb4d3b xfrm: Remove fami... |
3579 |
static int xfrm_bundle_ok(struct xfrm_dst *first) |
1da177e4c Linux-2.6.12-rc2 |
3580 |
{ |
5492093dc xfrm: Stop using ... |
3581 |
struct xfrm_dst *bundle[XFRM_MAX_DEPTH]; |
1da177e4c Linux-2.6.12-rc2 |
3582 |
struct dst_entry *dst = &first->u.dst; |
5492093dc xfrm: Stop using ... |
3583 3584 |
struct xfrm_dst *xdst; int start_from, nr; |
1da177e4c Linux-2.6.12-rc2 |
3585 |
u32 mtu; |
0f6c480f2 xfrm: Move dst->p... |
3586 |
if (!dst_check(xfrm_dst_path(dst), ((struct xfrm_dst *)dst)->path_cookie) || |
1da177e4c Linux-2.6.12-rc2 |
3587 3588 |
(dst->dev && !netif_running(dst->dev))) return 0; |
a0073fe18 xfrm: Add a state... |
3589 3590 |
if (dst->flags & DST_XFRM_QUEUE) return 1; |
5492093dc xfrm: Stop using ... |
3591 |
start_from = nr = 0; |
1da177e4c Linux-2.6.12-rc2 |
3592 3593 |
do { struct xfrm_dst *xdst = (struct xfrm_dst *)dst; |
1da177e4c Linux-2.6.12-rc2 |
3594 3595 |
if (dst->xfrm->km.state != XFRM_STATE_VALID) return 0; |
80c802f30 xfrm: cache bundl... |
3596 3597 |
if (xdst->xfrm_genid != dst->xfrm->genid) return 0; |
b1312c89f xfrm: check bundl... |
3598 3599 |
if (xdst->num_pols > 0 && xdst->policy_genid != atomic_read(&xdst->pols[0]->genid)) |
9d4a706d8 [XFRM]: Add gener... |
3600 |
return 0; |
e53820de0 [XFRM] IPV6: Rest... |
3601 |
|
5492093dc xfrm: Stop using ... |
3602 |
bundle[nr++] = xdst; |
b92cf4aab net: Create and u... |
3603 |
mtu = dst_mtu(xfrm_dst_child(dst)); |
1da177e4c Linux-2.6.12-rc2 |
3604 |
if (xdst->child_mtu_cached != mtu) { |
5492093dc xfrm: Stop using ... |
3605 |
start_from = nr; |
1da177e4c Linux-2.6.12-rc2 |
3606 3607 |
xdst->child_mtu_cached = mtu; } |
92d63decc From: Kazunori Mi... |
3608 |
if (!dst_check(xdst->route, xdst->route_cookie)) |
1da177e4c Linux-2.6.12-rc2 |
3609 3610 3611 |
return 0; mtu = dst_mtu(xdst->route); if (xdst->route_mtu_cached != mtu) { |
5492093dc xfrm: Stop using ... |
3612 |
start_from = nr; |
1da177e4c Linux-2.6.12-rc2 |
3613 3614 |
xdst->route_mtu_cached = mtu; } |
b92cf4aab net: Create and u... |
3615 |
dst = xfrm_dst_child(dst); |
1da177e4c Linux-2.6.12-rc2 |
3616 |
} while (dst->xfrm); |
5492093dc xfrm: Stop using ... |
3617 |
if (likely(!start_from)) |
1da177e4c Linux-2.6.12-rc2 |
3618 |
return 1; |
5492093dc xfrm: Stop using ... |
3619 3620 3621 3622 |
xdst = bundle[start_from - 1]; mtu = xdst->child_mtu_cached; while (start_from--) { dst = &xdst->u.dst; |
1da177e4c Linux-2.6.12-rc2 |
3623 3624 |
mtu = xfrm_state_mtu(dst->xfrm, mtu); |
5492093dc xfrm: Stop using ... |
3625 3626 |
if (mtu > xdst->route_mtu_cached) mtu = xdst->route_mtu_cached; |
defb3519a net: Abstract awa... |
3627 |
dst_metric_set(dst, RTAX_MTU, mtu); |
5492093dc xfrm: Stop using ... |
3628 |
if (!start_from) |
1da177e4c Linux-2.6.12-rc2 |
3629 |
break; |
5492093dc xfrm: Stop using ... |
3630 3631 |
xdst = bundle[start_from - 1]; xdst->child_mtu_cached = mtu; |
1da177e4c Linux-2.6.12-rc2 |
3632 3633 3634 3635 |
} return 1; } |
0dbaee3b3 net: Abstract def... |
3636 3637 |
static unsigned int xfrm_default_advmss(const struct dst_entry *dst) { |
0f6c480f2 xfrm: Move dst->p... |
3638 |
return dst_metric_advmss(xfrm_dst_path(dst)); |
0dbaee3b3 net: Abstract def... |
3639 |
} |
ebb762f27 net: Rename the d... |
3640 |
static unsigned int xfrm_mtu(const struct dst_entry *dst) |
d33e45533 net: Abstract def... |
3641 |
{ |
618f9bc74 net: Move mtu han... |
3642 |
unsigned int mtu = dst_metric_raw(dst, RTAX_MTU); |
0f6c480f2 xfrm: Move dst->p... |
3643 |
return mtu ? : dst_mtu(xfrm_dst_path(dst)); |
d33e45533 net: Abstract def... |
3644 |
} |
1ecc9ad02 xfrm: provide cor... |
3645 3646 |
static const void *xfrm_get_dst_nexthop(const struct dst_entry *dst, const void *daddr) |
63fca65d0 net: add confirm_... |
3647 |
{ |
0f6c480f2 xfrm: Move dst->p... |
3648 |
while (dst->xfrm) { |
63fca65d0 net: add confirm_... |
3649 |
const struct xfrm_state *xfrm = dst->xfrm; |
013cb81e8 xfrm: Fix infinit... |
3650 |
dst = xfrm_dst_child(dst); |
63fca65d0 net: add confirm_... |
3651 3652 3653 3654 3655 3656 3657 |
if (xfrm->props.mode == XFRM_MODE_TRANSPORT) continue; if (xfrm->type->flags & XFRM_TYPE_REMOTE_COADDR) daddr = xfrm->coaddr; else if (!(xfrm->type->flags & XFRM_TYPE_LOCAL_COADDR)) daddr = &xfrm->id.daddr; } |
1ecc9ad02 xfrm: provide cor... |
3658 3659 3660 3661 3662 3663 3664 |
return daddr; } static struct neighbour *xfrm_neigh_lookup(const struct dst_entry *dst, struct sk_buff *skb, const void *daddr) { |
0f6c480f2 xfrm: Move dst->p... |
3665 |
const struct dst_entry *path = xfrm_dst_path(dst); |
1ecc9ad02 xfrm: provide cor... |
3666 3667 3668 3669 3670 3671 3672 3673 |
if (!skb) daddr = xfrm_get_dst_nexthop(dst, daddr); return path->ops->neigh_lookup(path, skb, daddr); } static void xfrm_confirm_neigh(const struct dst_entry *dst, const void *daddr) { |
0f6c480f2 xfrm: Move dst->p... |
3674 |
const struct dst_entry *path = xfrm_dst_path(dst); |
1ecc9ad02 xfrm: provide cor... |
3675 3676 |
daddr = xfrm_get_dst_nexthop(dst, daddr); |
63fca65d0 net: add confirm_... |
3677 3678 |
path->ops->confirm_neigh(path, daddr); } |
a2817d8b2 xfrm: policy: rem... |
3679 |
int xfrm_policy_register_afinfo(const struct xfrm_policy_afinfo *afinfo, int family) |
1da177e4c Linux-2.6.12-rc2 |
3680 3681 |
{ int err = 0; |
a2817d8b2 xfrm: policy: rem... |
3682 3683 |
if (WARN_ON(family >= ARRAY_SIZE(xfrm_policy_afinfo))) |
1da177e4c Linux-2.6.12-rc2 |
3684 |
return -EAFNOSUPPORT; |
a2817d8b2 xfrm: policy: rem... |
3685 |
|
ef8531b64 xfrm: fix RCU bugs |
3686 |
spin_lock(&xfrm_policy_afinfo_lock); |
a2817d8b2 xfrm: policy: rem... |
3687 |
if (unlikely(xfrm_policy_afinfo[family] != NULL)) |
f31e8d4f7 xfrm: fix the ret... |
3688 |
err = -EEXIST; |
1da177e4c Linux-2.6.12-rc2 |
3689 3690 3691 3692 3693 3694 |
else { struct dst_ops *dst_ops = afinfo->dst_ops; if (likely(dst_ops->kmem_cachep == NULL)) dst_ops->kmem_cachep = xfrm_dst_cache; if (likely(dst_ops->check == NULL)) dst_ops->check = xfrm_dst_check; |
0dbaee3b3 net: Abstract def... |
3695 3696 |
if (likely(dst_ops->default_advmss == NULL)) dst_ops->default_advmss = xfrm_default_advmss; |
ebb762f27 net: Rename the d... |
3697 3698 |
if (likely(dst_ops->mtu == NULL)) dst_ops->mtu = xfrm_mtu; |
1da177e4c Linux-2.6.12-rc2 |
3699 3700 3701 3702 |
if (likely(dst_ops->negative_advice == NULL)) dst_ops->negative_advice = xfrm_negative_advice; if (likely(dst_ops->link_failure == NULL)) dst_ops->link_failure = xfrm_link_failure; |
d3aaeb38c net: Add ->neigh_... |
3703 3704 |
if (likely(dst_ops->neigh_lookup == NULL)) dst_ops->neigh_lookup = xfrm_neigh_lookup; |
63fca65d0 net: add confirm_... |
3705 3706 |
if (likely(!dst_ops->confirm_neigh)) dst_ops->confirm_neigh = xfrm_confirm_neigh; |
a2817d8b2 xfrm: policy: rem... |
3707 |
rcu_assign_pointer(xfrm_policy_afinfo[family], afinfo); |
1da177e4c Linux-2.6.12-rc2 |
3708 |
} |
ef8531b64 xfrm: fix RCU bugs |
3709 |
spin_unlock(&xfrm_policy_afinfo_lock); |
d7c7544c3 netns xfrm: deal ... |
3710 |
|
1da177e4c Linux-2.6.12-rc2 |
3711 3712 3713 |
return err; } EXPORT_SYMBOL(xfrm_policy_register_afinfo); |
a2817d8b2 xfrm: policy: rem... |
3714 |
void xfrm_policy_unregister_afinfo(const struct xfrm_policy_afinfo *afinfo) |
1da177e4c Linux-2.6.12-rc2 |
3715 |
{ |
2b61997aa xfrm: policy: xfr... |
3716 |
struct dst_ops *dst_ops = afinfo->dst_ops; |
a2817d8b2 xfrm: policy: rem... |
3717 |
int i; |
2b61997aa xfrm: policy: xfr... |
3718 |
|
a2817d8b2 xfrm: policy: rem... |
3719 3720 3721 3722 3723 |
for (i = 0; i < ARRAY_SIZE(xfrm_policy_afinfo); i++) { if (xfrm_policy_afinfo[i] != afinfo) continue; RCU_INIT_POINTER(xfrm_policy_afinfo[i], NULL); break; |
ef8531b64 xfrm: fix RCU bugs |
3724 |
} |
ef8531b64 xfrm: fix RCU bugs |
3725 |
|
2b61997aa xfrm: policy: xfr... |
3726 |
synchronize_rcu(); |
ef8531b64 xfrm: fix RCU bugs |
3727 |
|
2b61997aa xfrm: policy: xfr... |
3728 3729 3730 3731 |
dst_ops->kmem_cachep = NULL; dst_ops->check = NULL; dst_ops->negative_advice = NULL; dst_ops->link_failure = NULL; |
1da177e4c Linux-2.6.12-rc2 |
3732 3733 |
} EXPORT_SYMBOL(xfrm_policy_unregister_afinfo); |
f203b76d7 xfrm: Add virtual... |
3734 3735 3736 3737 3738 3739 3740 3741 3742 3743 3744 3745 3746 3747 |
void xfrm_if_register_cb(const struct xfrm_if_cb *ifcb) { spin_lock(&xfrm_if_cb_lock); rcu_assign_pointer(xfrm_if_cb, ifcb); spin_unlock(&xfrm_if_cb_lock); } EXPORT_SYMBOL(xfrm_if_register_cb); void xfrm_if_unregister_cb(void) { RCU_INIT_POINTER(xfrm_if_cb, NULL); synchronize_rcu(); } EXPORT_SYMBOL(xfrm_if_unregister_cb); |
558f82ef6 [XFRM]: Define pa... |
3748 |
#ifdef CONFIG_XFRM_STATISTICS |
59c9940ed netns xfrm: per-n... |
3749 |
static int __net_init xfrm_statistics_init(struct net *net) |
558f82ef6 [XFRM]: Define pa... |
3750 |
{ |
c68cd1a01 netns xfrm: /proc... |
3751 |
int rv; |
698365fa1 net: clean up snm... |
3752 3753 |
net->mib.xfrm_statistics = alloc_percpu(struct linux_xfrm_mib); if (!net->mib.xfrm_statistics) |
558f82ef6 [XFRM]: Define pa... |
3754 |
return -ENOMEM; |
c68cd1a01 netns xfrm: /proc... |
3755 3756 |
rv = xfrm_proc_init(net); if (rv < 0) |
698365fa1 net: clean up snm... |
3757 |
free_percpu(net->mib.xfrm_statistics); |
c68cd1a01 netns xfrm: /proc... |
3758 |
return rv; |
558f82ef6 [XFRM]: Define pa... |
3759 |
} |
59c9940ed netns xfrm: per-n... |
3760 3761 3762 |
static void xfrm_statistics_fini(struct net *net) { |
c68cd1a01 netns xfrm: /proc... |
3763 |
xfrm_proc_fini(net); |
698365fa1 net: clean up snm... |
3764 |
free_percpu(net->mib.xfrm_statistics); |
59c9940ed netns xfrm: per-n... |
3765 3766 3767 3768 3769 3770 3771 3772 3773 3774 |
} #else static int __net_init xfrm_statistics_init(struct net *net) { return 0; } static void xfrm_statistics_fini(struct net *net) { } |
558f82ef6 [XFRM]: Define pa... |
3775 |
#endif |
d62ddc21b netns xfrm: add n... |
3776 |
static int __net_init xfrm_policy_init(struct net *net) |
1da177e4c Linux-2.6.12-rc2 |
3777 |
{ |
2518c7c2b [XFRM]: Hash poli... |
3778 |
unsigned int hmask, sz; |
24969facd xfrm: policy: sto... |
3779 |
int dir, err; |
2518c7c2b [XFRM]: Hash poli... |
3780 |
|
24969facd xfrm: policy: sto... |
3781 |
if (net_eq(net, &init_net)) { |
d62ddc21b netns xfrm: add n... |
3782 |
xfrm_dst_cache = kmem_cache_create("xfrm_dst_cache", |
1da177e4c Linux-2.6.12-rc2 |
3783 |
sizeof(struct xfrm_dst), |
e5d679f33 [NET]: Use SLAB_P... |
3784 |
0, SLAB_HWCACHE_ALIGN|SLAB_PANIC, |
20c2df83d mm: Remove slab d... |
3785 |
NULL); |
24969facd xfrm: policy: sto... |
3786 3787 3788 3789 |
err = rhashtable_init(&xfrm_policy_inexact_table, &xfrm_pol_inexact_params); BUG_ON(err); } |
1da177e4c Linux-2.6.12-rc2 |
3790 |
|
2518c7c2b [XFRM]: Hash poli... |
3791 3792 |
hmask = 8 - 1; sz = (hmask+1) * sizeof(struct hlist_head); |
93b851c1c netns xfrm: per-n... |
3793 3794 3795 |
net->xfrm.policy_byidx = xfrm_hash_alloc(sz); if (!net->xfrm.policy_byidx) goto out_byidx; |
8100bea7d netns xfrm: per-n... |
3796 |
net->xfrm.policy_idx_hmask = hmask; |
2518c7c2b [XFRM]: Hash poli... |
3797 |
|
53c2e285f xfrm: Do not hash... |
3798 |
for (dir = 0; dir < XFRM_POLICY_MAX; dir++) { |
2518c7c2b [XFRM]: Hash poli... |
3799 |
struct xfrm_policy_hash *htab; |
dc2caba7b netns xfrm: per-n... |
3800 |
net->xfrm.policy_count[dir] = 0; |
53c2e285f xfrm: Do not hash... |
3801 |
net->xfrm.policy_count[XFRM_POLICY_MAX + dir] = 0; |
8b18f8eaf netns xfrm: per-n... |
3802 |
INIT_HLIST_HEAD(&net->xfrm.policy_inexact[dir]); |
2518c7c2b [XFRM]: Hash poli... |
3803 |
|
a35f6c5de netns xfrm: per-n... |
3804 |
htab = &net->xfrm.policy_bydst[dir]; |
44e36b42a [XFRM]: Extract c... |
3805 |
htab->table = xfrm_hash_alloc(sz); |
2518c7c2b [XFRM]: Hash poli... |
3806 |
if (!htab->table) |
a35f6c5de netns xfrm: per-n... |
3807 3808 |
goto out_bydst; htab->hmask = hmask; |
b58555f17 xfrm: hash prefix... |
3809 3810 3811 3812 |
htab->dbits4 = 32; htab->sbits4 = 32; htab->dbits6 = 128; htab->sbits6 = 128; |
2518c7c2b [XFRM]: Hash poli... |
3813 |
} |
880a6fab8 xfrm: configure p... |
3814 3815 3816 3817 3818 3819 |
net->xfrm.policy_hthresh.lbits4 = 32; net->xfrm.policy_hthresh.rbits4 = 32; net->xfrm.policy_hthresh.lbits6 = 128; net->xfrm.policy_hthresh.rbits6 = 128; seqlock_init(&net->xfrm.policy_hthresh.lock); |
2518c7c2b [XFRM]: Hash poli... |
3820 |
|
adfcf0b27 netns xfrm: per-n... |
3821 |
INIT_LIST_HEAD(&net->xfrm.policy_all); |
24969facd xfrm: policy: sto... |
3822 |
INIT_LIST_HEAD(&net->xfrm.inexact_bins); |
66caf628c netns xfrm: per-n... |
3823 |
INIT_WORK(&net->xfrm.policy_hash_work, xfrm_hash_resize); |
880a6fab8 xfrm: configure p... |
3824 |
INIT_WORK(&net->xfrm.policy_hthresh.work, xfrm_hash_rebuild); |
d62ddc21b netns xfrm: add n... |
3825 |
return 0; |
93b851c1c netns xfrm: per-n... |
3826 |
|
a35f6c5de netns xfrm: per-n... |
3827 3828 3829 3830 3831 3832 3833 3834 |
out_bydst: for (dir--; dir >= 0; dir--) { struct xfrm_policy_hash *htab; htab = &net->xfrm.policy_bydst[dir]; xfrm_hash_free(htab->table, sz); } xfrm_hash_free(net->xfrm.policy_byidx, sz); |
93b851c1c netns xfrm: per-n... |
3835 3836 |
out_byidx: return -ENOMEM; |
d62ddc21b netns xfrm: add n... |
3837 3838 3839 3840 |
} static void xfrm_policy_fini(struct net *net) { |
6be3b0db6 xfrm: policy: add... |
3841 |
struct xfrm_pol_inexact_bin *b, *t; |
93b851c1c netns xfrm: per-n... |
3842 |
unsigned int sz; |
8b18f8eaf netns xfrm: per-n... |
3843 |
int dir; |
93b851c1c netns xfrm: per-n... |
3844 |
|
7c2776ee2 netns xfrm: flush... |
3845 3846 |
flush_work(&net->xfrm.policy_hash_work); #ifdef CONFIG_XFRM_SUB_POLICY |
2e71029e2 xfrm: Remove usel... |
3847 |
xfrm_policy_flush(net, XFRM_POLICY_TYPE_SUB, false); |
7c2776ee2 netns xfrm: flush... |
3848 |
#endif |
2e71029e2 xfrm: Remove usel... |
3849 |
xfrm_policy_flush(net, XFRM_POLICY_TYPE_MAIN, false); |
7c2776ee2 netns xfrm: flush... |
3850 |
|
adfcf0b27 netns xfrm: per-n... |
3851 |
WARN_ON(!list_empty(&net->xfrm.policy_all)); |
93b851c1c netns xfrm: per-n... |
3852 |
|
53c2e285f xfrm: Do not hash... |
3853 |
for (dir = 0; dir < XFRM_POLICY_MAX; dir++) { |
a35f6c5de netns xfrm: per-n... |
3854 |
struct xfrm_policy_hash *htab; |
8b18f8eaf netns xfrm: per-n... |
3855 |
WARN_ON(!hlist_empty(&net->xfrm.policy_inexact[dir])); |
a35f6c5de netns xfrm: per-n... |
3856 3857 |
htab = &net->xfrm.policy_bydst[dir]; |
5b653b2a1 xfrm: fix freed b... |
3858 |
sz = (htab->hmask + 1) * sizeof(struct hlist_head); |
a35f6c5de netns xfrm: per-n... |
3859 3860 |
WARN_ON(!hlist_empty(htab->table)); xfrm_hash_free(htab->table, sz); |
8b18f8eaf netns xfrm: per-n... |
3861 |
} |
8100bea7d netns xfrm: per-n... |
3862 |
sz = (net->xfrm.policy_idx_hmask + 1) * sizeof(struct hlist_head); |
93b851c1c netns xfrm: per-n... |
3863 3864 |
WARN_ON(!hlist_empty(net->xfrm.policy_byidx)); xfrm_hash_free(net->xfrm.policy_byidx, sz); |
24969facd xfrm: policy: sto... |
3865 |
|
6be3b0db6 xfrm: policy: add... |
3866 3867 3868 3869 |
spin_lock_bh(&net->xfrm.xfrm_policy_lock); list_for_each_entry_safe(b, t, &net->xfrm.inexact_bins, inexact_bins) __xfrm_policy_inexact_prune_bin(b, true); spin_unlock_bh(&net->xfrm.xfrm_policy_lock); |
1da177e4c Linux-2.6.12-rc2 |
3870 |
} |
d62ddc21b netns xfrm: add n... |
3871 3872 3873 |
static int __net_init xfrm_net_init(struct net *net) { int rv; |
c282222a4 xfrm: policy: ini... |
3874 3875 3876 3877 |
/* Initialize the per-net locks here */ spin_lock_init(&net->xfrm.xfrm_state_lock); spin_lock_init(&net->xfrm.xfrm_policy_lock); mutex_init(&net->xfrm.xfrm_cfg_mutex); |
59c9940ed netns xfrm: per-n... |
3878 3879 3880 |
rv = xfrm_statistics_init(net); if (rv < 0) goto out_statistics; |
d62ddc21b netns xfrm: add n... |
3881 3882 3883 3884 3885 3886 |
rv = xfrm_state_init(net); if (rv < 0) goto out_state; rv = xfrm_policy_init(net); if (rv < 0) goto out_policy; |
b27aeadb5 netns xfrm: per-n... |
3887 3888 3889 |
rv = xfrm_sysctl_init(net); if (rv < 0) goto out_sysctl; |
283bc9f35 xfrm: Namespacify... |
3890 |
|
d62ddc21b netns xfrm: add n... |
3891 |
return 0; |
b27aeadb5 netns xfrm: per-n... |
3892 3893 |
out_sysctl: xfrm_policy_fini(net); |
d62ddc21b netns xfrm: add n... |
3894 3895 3896 |
out_policy: xfrm_state_fini(net); out_state: |
59c9940ed netns xfrm: per-n... |
3897 3898 |
xfrm_statistics_fini(net); out_statistics: |
d62ddc21b netns xfrm: add n... |
3899 3900 3901 3902 3903 |
return rv; } static void __net_exit xfrm_net_exit(struct net *net) { |
b27aeadb5 netns xfrm: per-n... |
3904 |
xfrm_sysctl_fini(net); |
d62ddc21b netns xfrm: add n... |
3905 3906 |
xfrm_policy_fini(net); xfrm_state_fini(net); |
59c9940ed netns xfrm: per-n... |
3907 |
xfrm_statistics_fini(net); |
d62ddc21b netns xfrm: add n... |
3908 3909 3910 3911 3912 3913 |
} static struct pernet_operations __net_initdata xfrm_net_ops = { .init = xfrm_net_init, .exit = xfrm_net_exit, }; |
1da177e4c Linux-2.6.12-rc2 |
3914 3915 |
void __init xfrm_init(void) { |
d62ddc21b netns xfrm: add n... |
3916 |
register_pernet_subsys(&xfrm_net_ops); |
e9a441b6e xfrm: Register xf... |
3917 |
xfrm_dev_init(); |
77cc278f7 xfrm: policy: Use... |
3918 |
seqcount_mutex_init(&xfrm_policy_hash_generation, &hash_resize_mutex); |
1da177e4c Linux-2.6.12-rc2 |
3919 |
xfrm_input_init(); |
f203b76d7 xfrm: Add virtual... |
3920 |
|
95a35b42b xfrm: policy: fix... |
3921 |
#ifdef CONFIG_XFRM_ESPINTCP |
e27cca96c xfrm: add espintc... |
3922 3923 |
espintcp_init(); #endif |
f203b76d7 xfrm: Add virtual... |
3924 3925 |
RCU_INIT_POINTER(xfrm_if_cb, NULL); synchronize_rcu(); |
1da177e4c Linux-2.6.12-rc2 |
3926 |
} |
ab5f5e8b1 [XFRM]: xfrm audi... |
3927 |
#ifdef CONFIG_AUDITSYSCALL |
1486cbd77 [XFRM] xfrm_polic... |
3928 3929 |
static void xfrm_audit_common_policyinfo(struct xfrm_policy *xp, struct audit_buffer *audit_buf) |
ab5f5e8b1 [XFRM]: xfrm audi... |
3930 |
{ |
875179fa6 [IPSEC]: SPD audi... |
3931 3932 3933 3934 |
struct xfrm_sec_ctx *ctx = xp->security; struct xfrm_selector *sel = &xp->selector; if (ctx) |
ab5f5e8b1 [XFRM]: xfrm audi... |
3935 |
audit_log_format(audit_buf, " sec_alg=%u sec_doi=%u sec_obj=%s", |
875179fa6 [IPSEC]: SPD audi... |
3936 |
ctx->ctx_alg, ctx->ctx_doi, ctx->ctx_str); |
ab5f5e8b1 [XFRM]: xfrm audi... |
3937 |
|
9b7a787d0 xfrm: checkpatch ... |
3938 |
switch (sel->family) { |
ab5f5e8b1 [XFRM]: xfrm audi... |
3939 |
case AF_INET: |
21454aaad net: replace NIPQ... |
3940 |
audit_log_format(audit_buf, " src=%pI4", &sel->saddr.a4); |
875179fa6 [IPSEC]: SPD audi... |
3941 3942 3943 |
if (sel->prefixlen_s != 32) audit_log_format(audit_buf, " src_prefixlen=%d", sel->prefixlen_s); |
21454aaad net: replace NIPQ... |
3944 |
audit_log_format(audit_buf, " dst=%pI4", &sel->daddr.a4); |
875179fa6 [IPSEC]: SPD audi... |
3945 3946 3947 |
if (sel->prefixlen_d != 32) audit_log_format(audit_buf, " dst_prefixlen=%d", sel->prefixlen_d); |
ab5f5e8b1 [XFRM]: xfrm audi... |
3948 3949 |
break; case AF_INET6: |
5b095d989 net: replace %p6 ... |
3950 |
audit_log_format(audit_buf, " src=%pI6", sel->saddr.a6); |
875179fa6 [IPSEC]: SPD audi... |
3951 3952 3953 |
if (sel->prefixlen_s != 128) audit_log_format(audit_buf, " src_prefixlen=%d", sel->prefixlen_s); |
5b095d989 net: replace %p6 ... |
3954 |
audit_log_format(audit_buf, " dst=%pI6", sel->daddr.a6); |
875179fa6 [IPSEC]: SPD audi... |
3955 3956 3957 |
if (sel->prefixlen_d != 128) audit_log_format(audit_buf, " dst_prefixlen=%d", sel->prefixlen_d); |
ab5f5e8b1 [XFRM]: xfrm audi... |
3958 3959 3960 |
break; } } |
2e71029e2 xfrm: Remove usel... |
3961 |
void xfrm_audit_policy_add(struct xfrm_policy *xp, int result, bool task_valid) |
ab5f5e8b1 [XFRM]: xfrm audi... |
3962 3963 |
{ struct audit_buffer *audit_buf; |
ab5f5e8b1 [XFRM]: xfrm audi... |
3964 |
|
afeb14b49 [XFRM]: RFC4303 c... |
3965 |
audit_buf = xfrm_audit_start("SPD-add"); |
ab5f5e8b1 [XFRM]: xfrm audi... |
3966 3967 |
if (audit_buf == NULL) return; |
2e71029e2 xfrm: Remove usel... |
3968 |
xfrm_audit_helper_usrinfo(task_valid, audit_buf); |
afeb14b49 [XFRM]: RFC4303 c... |
3969 |
audit_log_format(audit_buf, " res=%u", result); |
ab5f5e8b1 [XFRM]: xfrm audi... |
3970 3971 3972 3973 |
xfrm_audit_common_policyinfo(xp, audit_buf); audit_log_end(audit_buf); } EXPORT_SYMBOL_GPL(xfrm_audit_policy_add); |
68277accb [XFRM]: Assorted ... |
3974 |
void xfrm_audit_policy_delete(struct xfrm_policy *xp, int result, |
2e71029e2 xfrm: Remove usel... |
3975 |
bool task_valid) |
ab5f5e8b1 [XFRM]: xfrm audi... |
3976 3977 |
{ struct audit_buffer *audit_buf; |
ab5f5e8b1 [XFRM]: xfrm audi... |
3978 |
|
afeb14b49 [XFRM]: RFC4303 c... |
3979 |
audit_buf = xfrm_audit_start("SPD-delete"); |
ab5f5e8b1 [XFRM]: xfrm audi... |
3980 3981 |
if (audit_buf == NULL) return; |
2e71029e2 xfrm: Remove usel... |
3982 |
xfrm_audit_helper_usrinfo(task_valid, audit_buf); |
afeb14b49 [XFRM]: RFC4303 c... |
3983 |
audit_log_format(audit_buf, " res=%u", result); |
ab5f5e8b1 [XFRM]: xfrm audi... |
3984 3985 3986 3987 3988 |
xfrm_audit_common_policyinfo(xp, audit_buf); audit_log_end(audit_buf); } EXPORT_SYMBOL_GPL(xfrm_audit_policy_delete); #endif |
80c9abaab [XFRM]: Extension... |
3989 |
#ifdef CONFIG_XFRM_MIGRATE |
bc9b35ad4 xfrm: Convert sev... |
3990 3991 |
static bool xfrm_migrate_selector_match(const struct xfrm_selector *sel_cmp, const struct xfrm_selector *sel_tgt) |
80c9abaab [XFRM]: Extension... |
3992 3993 3994 |
{ if (sel_cmp->proto == IPSEC_ULPROTO_ANY) { if (sel_tgt->family == sel_cmp->family && |
70e94e66a xfrm: Convert xfr... |
3995 3996 3997 3998 |
xfrm_addr_equal(&sel_tgt->daddr, &sel_cmp->daddr, sel_cmp->family) && xfrm_addr_equal(&sel_tgt->saddr, &sel_cmp->saddr, sel_cmp->family) && |
80c9abaab [XFRM]: Extension... |
3999 4000 |
sel_tgt->prefixlen_d == sel_cmp->prefixlen_d && sel_tgt->prefixlen_s == sel_cmp->prefixlen_s) { |
bc9b35ad4 xfrm: Convert sev... |
4001 |
return true; |
80c9abaab [XFRM]: Extension... |
4002 4003 4004 |
} } else { if (memcmp(sel_tgt, sel_cmp, sizeof(*sel_tgt)) == 0) { |
bc9b35ad4 xfrm: Convert sev... |
4005 |
return true; |
80c9abaab [XFRM]: Extension... |
4006 4007 |
} } |
bc9b35ad4 xfrm: Convert sev... |
4008 |
return false; |
80c9abaab [XFRM]: Extension... |
4009 |
} |
3e94c2dcf xfrm: checkpatch ... |
4010 4011 |
static struct xfrm_policy *xfrm_migrate_policy_find(const struct xfrm_selector *sel, u8 dir, u8 type, struct net *net) |
80c9abaab [XFRM]: Extension... |
4012 4013 |
{ struct xfrm_policy *pol, *ret = NULL; |
80c9abaab [XFRM]: Extension... |
4014 4015 |
struct hlist_head *chain; u32 priority = ~0U; |
9d0380df6 xfrm: policy: con... |
4016 |
spin_lock_bh(&net->xfrm.xfrm_policy_lock); |
8d549c4f5 xfrm: Using the r... |
4017 |
chain = policy_hash_direct(net, &sel->daddr, &sel->saddr, sel->family, dir); |
b67bfe0d4 hlist: drop the n... |
4018 |
hlist_for_each_entry(pol, chain, bydst) { |
80c9abaab [XFRM]: Extension... |
4019 4020 4021 4022 4023 4024 4025 |
if (xfrm_migrate_selector_match(sel, &pol->selector) && pol->type == type) { ret = pol; priority = ret->priority; break; } } |
8d549c4f5 xfrm: Using the r... |
4026 |
chain = &net->xfrm.policy_inexact[dir]; |
24969facd xfrm: policy: sto... |
4027 |
hlist_for_each_entry(pol, chain, bydst_inexact_list) { |
8faf491e6 xfrm: optimise to... |
4028 4029 |
if ((pol->priority >= priority) && ret) break; |
80c9abaab [XFRM]: Extension... |
4030 |
if (xfrm_migrate_selector_match(sel, &pol->selector) && |
8faf491e6 xfrm: optimise to... |
4031 |
pol->type == type) { |
80c9abaab [XFRM]: Extension... |
4032 4033 4034 4035 |
ret = pol; break; } } |
586f2eb41 xfrm: remove the ... |
4036 |
xfrm_pol_hold(ret); |
80c9abaab [XFRM]: Extension... |
4037 |
|
9d0380df6 xfrm: policy: con... |
4038 |
spin_unlock_bh(&net->xfrm.xfrm_policy_lock); |
80c9abaab [XFRM]: Extension... |
4039 4040 4041 |
return ret; } |
dd701754e xfrm: Const'ify p... |
4042 |
static int migrate_tmpl_match(const struct xfrm_migrate *m, const struct xfrm_tmpl *t) |
80c9abaab [XFRM]: Extension... |
4043 4044 4045 4046 4047 4048 4049 4050 |
{ int match = 0; if (t->mode == m->mode && t->id.proto == m->proto && (m->reqid == 0 || t->reqid == m->reqid)) { switch (t->mode) { case XFRM_MODE_TUNNEL: case XFRM_MODE_BEET: |
70e94e66a xfrm: Convert xfr... |
4051 4052 4053 4054 |
if (xfrm_addr_equal(&t->id.daddr, &m->old_daddr, m->old_family) && xfrm_addr_equal(&t->saddr, &m->old_saddr, m->old_family)) { |
80c9abaab [XFRM]: Extension... |
4055 4056 4057 4058 4059 4060 4061 4062 4063 4064 4065 4066 4067 4068 4069 4070 4071 4072 4073 4074 4075 |
match = 1; } break; case XFRM_MODE_TRANSPORT: /* in case of transport mode, template does not store any IP addresses, hence we just compare mode and protocol */ match = 1; break; default: break; } } return match; } /* update endpoint address(es) of template(s) */ static int xfrm_policy_migrate(struct xfrm_policy *pol, struct xfrm_migrate *m, int num_migrate) { struct xfrm_migrate *mp; |
80c9abaab [XFRM]: Extension... |
4076 4077 4078 |
int i, j, n = 0; write_lock_bh(&pol->lock); |
12a169e7d ipsec: Put dumper... |
4079 |
if (unlikely(pol->walk.dead)) { |
80c9abaab [XFRM]: Extension... |
4080 4081 4082 4083 4084 4085 4086 4087 4088 4089 |
/* target policy has been deleted */ write_unlock_bh(&pol->lock); return -ENOENT; } for (i = 0; i < pol->xfrm_nr; i++) { for (j = 0, mp = m; j < num_migrate; j++, mp++) { if (!migrate_tmpl_match(mp, &pol->xfrm_vec[i])) continue; n++; |
1bfcb10f6 [IPSEC]: Add miss... |
4090 4091 |
if (pol->xfrm_vec[i].mode != XFRM_MODE_TUNNEL && pol->xfrm_vec[i].mode != XFRM_MODE_BEET) |
80c9abaab [XFRM]: Extension... |
4092 4093 4094 4095 4096 4097 4098 4099 |
continue; /* update endpoints */ memcpy(&pol->xfrm_vec[i].id.daddr, &mp->new_daddr, sizeof(pol->xfrm_vec[i].id.daddr)); memcpy(&pol->xfrm_vec[i].saddr, &mp->new_saddr, sizeof(pol->xfrm_vec[i].saddr)); pol->xfrm_vec[i].encap_family = mp->new_family; /* flush bundles */ |
80c802f30 xfrm: cache bundl... |
4100 |
atomic_inc(&pol->genid); |
80c9abaab [XFRM]: Extension... |
4101 4102 4103 4104 4105 4106 4107 4108 4109 4110 |
} } write_unlock_bh(&pol->lock); if (!n) return -ENODATA; return 0; } |
dd701754e xfrm: Const'ify p... |
4111 |
static int xfrm_migrate_check(const struct xfrm_migrate *m, int num_migrate) |
80c9abaab [XFRM]: Extension... |
4112 4113 4114 4115 4116 4117 4118 |
{ int i, j; if (num_migrate < 1 || num_migrate > XFRM_MAX_DEPTH) return -EINVAL; for (i = 0; i < num_migrate; i++) { |
80c9abaab [XFRM]: Extension... |
4119 4120 4121 4122 4123 4124 4125 4126 4127 4128 4129 4130 4131 4132 4133 4134 4135 4136 4137 4138 |
if (xfrm_addr_any(&m[i].new_daddr, m[i].new_family) || xfrm_addr_any(&m[i].new_saddr, m[i].new_family)) return -EINVAL; /* check if there is any duplicated entry */ for (j = i + 1; j < num_migrate; j++) { if (!memcmp(&m[i].old_daddr, &m[j].old_daddr, sizeof(m[i].old_daddr)) && !memcmp(&m[i].old_saddr, &m[j].old_saddr, sizeof(m[i].old_saddr)) && m[i].proto == m[j].proto && m[i].mode == m[j].mode && m[i].reqid == m[j].reqid && m[i].old_family == m[j].old_family) return -EINVAL; } } return 0; } |
b4b7c0b38 xfrm: Const'ify s... |
4139 |
int xfrm_migrate(const struct xfrm_selector *sel, u8 dir, u8 type, |
13c1d1893 xfrm: MIGRATE enh... |
4140 |
struct xfrm_migrate *m, int num_migrate, |
4ab47d47a xfrm: extend MIGR... |
4141 4142 |
struct xfrm_kmaddress *k, struct net *net, struct xfrm_encap_tmpl *encap) |
80c9abaab [XFRM]: Extension... |
4143 4144 4145 4146 4147 4148 4149 |
{ int i, err, nx_cur = 0, nx_new = 0; struct xfrm_policy *pol = NULL; struct xfrm_state *x, *xc; struct xfrm_state *x_cur[XFRM_MAX_DEPTH]; struct xfrm_state *x_new[XFRM_MAX_DEPTH]; struct xfrm_migrate *mp; |
7bab09631 xfrm: policy: che... |
4150 |
/* Stage 0 - sanity checks */ |
80c9abaab [XFRM]: Extension... |
4151 4152 |
if ((err = xfrm_migrate_check(m, num_migrate)) < 0) goto out; |
7bab09631 xfrm: policy: che... |
4153 4154 4155 4156 |
if (dir >= XFRM_POLICY_MAX) { err = -EINVAL; goto out; } |
80c9abaab [XFRM]: Extension... |
4157 |
/* Stage 1 - find policy */ |
8d549c4f5 xfrm: Using the r... |
4158 |
if ((pol = xfrm_migrate_policy_find(sel, dir, type, net)) == NULL) { |
80c9abaab [XFRM]: Extension... |
4159 4160 4161 4162 4163 4164 |
err = -ENOENT; goto out; } /* Stage 2 - find and update state(s) */ for (i = 0, mp = m; i < num_migrate; i++, mp++) { |
283bc9f35 xfrm: Namespacify... |
4165 |
if ((x = xfrm_migrate_state_find(mp, net))) { |
80c9abaab [XFRM]: Extension... |
4166 4167 |
x_cur[nx_cur] = x; nx_cur++; |
4ab47d47a xfrm: extend MIGR... |
4168 4169 |
xc = xfrm_state_migrate(x, mp, encap); if (xc) { |
80c9abaab [XFRM]: Extension... |
4170 4171 4172 4173 4174 4175 4176 4177 4178 4179 4180 4181 4182 4183 4184 4185 4186 4187 4188 4189 |
x_new[nx_new] = xc; nx_new++; } else { err = -ENODATA; goto restore_state; } } } /* Stage 3 - update policy */ if ((err = xfrm_policy_migrate(pol, m, num_migrate)) < 0) goto restore_state; /* Stage 4 - delete old state(s) */ if (nx_cur) { xfrm_states_put(x_cur, nx_cur); xfrm_states_delete(x_cur, nx_cur); } /* Stage 5 - announce */ |
8bafd7309 xfrm: add UDP enc... |
4190 |
km_migrate(sel, dir, type, m, num_migrate, k, encap); |
80c9abaab [XFRM]: Extension... |
4191 4192 4193 4194 4195 4196 4197 4198 4199 4200 4201 4202 4203 4204 4205 4206 4207 |
xfrm_pol_put(pol); return 0; out: return err; restore_state: if (pol) xfrm_pol_put(pol); if (nx_cur) xfrm_states_put(x_cur, nx_cur); if (nx_new) xfrm_states_delete(x_new, nx_new); return err; } |
e610e679d [XFRM]: xfrm_migr... |
4208 |
EXPORT_SYMBOL(xfrm_migrate); |
80c9abaab [XFRM]: Extension... |
4209 |
#endif |