static struct xfrm_policy_afinfo *xfrm_policy_lock_afinfo(unsigned int family);
static void xfrm_policy_unlock_afinfo(struct xfrm_policy_afinfo *afinfo);
+static inline int
+__xfrm4_selector_match(struct xfrm_selector *sel, struct flowi *fl)
+{
+ return addr_match(&fl->fl4_dst, &sel->daddr, sel->prefixlen_d) &&
+ addr_match(&fl->fl4_src, &sel->saddr, sel->prefixlen_s) &&
+ !((xfrm_flowi_dport(fl) ^ sel->dport) & sel->dport_mask) &&
+ !((xfrm_flowi_sport(fl) ^ sel->sport) & sel->sport_mask) &&
+ (fl->proto == sel->proto || !sel->proto) &&
+ (fl->oif == sel->ifindex || !sel->ifindex);
+}
+
+static inline int
+__xfrm6_selector_match(struct xfrm_selector *sel, struct flowi *fl)
+{
+ return addr_match(&fl->fl6_dst, &sel->daddr, sel->prefixlen_d) &&
+ addr_match(&fl->fl6_src, &sel->saddr, sel->prefixlen_s) &&
+ !((xfrm_flowi_dport(fl) ^ sel->dport) & sel->dport_mask) &&
+ !((xfrm_flowi_sport(fl) ^ sel->sport) & sel->sport_mask) &&
+ (fl->proto == sel->proto || !sel->proto) &&
+ (fl->oif == sel->ifindex || !sel->ifindex);
+}
+
+int xfrm_selector_match(struct xfrm_selector *sel, struct flowi *fl,
+ unsigned short family)
+{
+ switch (family) {
+ case AF_INET:
+ return __xfrm4_selector_match(sel, fl);
+ case AF_INET6:
+ return __xfrm6_selector_match(sel, fl);
+ }
+ return 0;
+}
+
int xfrm_register_type(struct xfrm_type *type, unsigned short family)
{
struct xfrm_policy_afinfo *afinfo = xfrm_policy_lock_afinfo(family);
if (tmpl->mode == XFRM_MODE_TUNNEL) {
remote = &tmpl->id.daddr;
local = &tmpl->saddr;
+ family = tmpl->encap_family;
if (xfrm_addr_any(local, family)) {
error = xfrm_get_saddr(&tmp, remote, family);
if (error)
if (fl && !xfrm_selector_match(&dst->xfrm->sel, fl, family))
return 0;
- if (fl && !security_xfrm_flow_state_match(fl, dst->xfrm, pol))
+ if (fl && pol &&
+ !security_xfrm_state_pol_flow_match(dst->xfrm, pol, fl))
return 0;
if (dst->xfrm->km.state != XFRM_STATE_VALID)
return 0;