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