|
@@ -1603,6 +1603,23 @@ unlock:
|
|
|
}
|
|
|
EXPORT_SYMBOL(xfrm_alloc_spi);
|
|
|
|
|
|
+static bool __xfrm_state_filter_match(struct xfrm_state *x,
|
|
|
+ struct xfrm_filter *filter)
|
|
|
+{
|
|
|
+ if (filter) {
|
|
|
+ if ((filter->family == AF_INET ||
|
|
|
+ filter->family == AF_INET6) &&
|
|
|
+ x->props.family != filter->family)
|
|
|
+ return false;
|
|
|
+
|
|
|
+ return addr_match(&x->props.saddr, &filter->saddr,
|
|
|
+ filter->splen) &&
|
|
|
+ addr_match(&x->id.daddr, &filter->daddr,
|
|
|
+ filter->dplen);
|
|
|
+ }
|
|
|
+ return true;
|
|
|
+}
|
|
|
+
|
|
|
int xfrm_state_walk(struct net *net, struct xfrm_state_walk *walk,
|
|
|
int (*func)(struct xfrm_state *, int, void*),
|
|
|
void *data)
|
|
@@ -1625,6 +1642,8 @@ int xfrm_state_walk(struct net *net, struct xfrm_state_walk *walk,
|
|
|
state = container_of(x, struct xfrm_state, km);
|
|
|
if (!xfrm_id_proto_match(state->id.proto, walk->proto))
|
|
|
continue;
|
|
|
+ if (!__xfrm_state_filter_match(state, walk->filter))
|
|
|
+ continue;
|
|
|
err = func(state, walk->seq, data);
|
|
|
if (err) {
|
|
|
list_move_tail(&walk->all, &x->all);
|
|
@@ -1643,17 +1662,21 @@ out:
|
|
|
}
|
|
|
EXPORT_SYMBOL(xfrm_state_walk);
|
|
|
|
|
|
-void xfrm_state_walk_init(struct xfrm_state_walk *walk, u8 proto)
|
|
|
+void xfrm_state_walk_init(struct xfrm_state_walk *walk, u8 proto,
|
|
|
+ struct xfrm_filter *filter)
|
|
|
{
|
|
|
INIT_LIST_HEAD(&walk->all);
|
|
|
walk->proto = proto;
|
|
|
walk->state = XFRM_STATE_DEAD;
|
|
|
walk->seq = 0;
|
|
|
+ walk->filter = filter;
|
|
|
}
|
|
|
EXPORT_SYMBOL(xfrm_state_walk_init);
|
|
|
|
|
|
void xfrm_state_walk_done(struct xfrm_state_walk *walk, struct net *net)
|
|
|
{
|
|
|
+ kfree(walk->filter);
|
|
|
+
|
|
|
if (list_empty(&walk->all))
|
|
|
return;
|
|
|
|