diff options
Diffstat (limited to 'net/xfrm/xfrm_user.c')
| -rw-r--r-- | net/xfrm/xfrm_user.c | 67 | 
1 files changed, 55 insertions, 12 deletions
diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c index 03b66d154b2b..3a3cb09eec12 100644 --- a/net/xfrm/xfrm_user.c +++ b/net/xfrm/xfrm_user.c @@ -1961,24 +1961,65 @@ static struct sk_buff *xfrm_policy_netlink(struct sk_buff *in_skb,  	return skb;  } +static int xfrm_notify_userpolicy(struct net *net) +{ +	struct xfrm_userpolicy_default *up; +	int len = NLMSG_ALIGN(sizeof(*up)); +	struct nlmsghdr *nlh; +	struct sk_buff *skb; +	int err; + +	skb = nlmsg_new(len, GFP_ATOMIC); +	if (skb == NULL) +		return -ENOMEM; + +	nlh = nlmsg_put(skb, 0, 0, XFRM_MSG_GETDEFAULT, sizeof(*up), 0); +	if (nlh == NULL) { +		kfree_skb(skb); +		return -EMSGSIZE; +	} + +	up = nlmsg_data(nlh); +	up->in = net->xfrm.policy_default & XFRM_POL_DEFAULT_IN ? +			XFRM_USERPOLICY_BLOCK : XFRM_USERPOLICY_ACCEPT; +	up->fwd = net->xfrm.policy_default & XFRM_POL_DEFAULT_FWD ? +			XFRM_USERPOLICY_BLOCK : XFRM_USERPOLICY_ACCEPT; +	up->out = net->xfrm.policy_default & XFRM_POL_DEFAULT_OUT ? +			XFRM_USERPOLICY_BLOCK : XFRM_USERPOLICY_ACCEPT; + +	nlmsg_end(skb, nlh); + +	rcu_read_lock(); +	err = xfrm_nlmsg_multicast(net, skb, 0, XFRMNLGRP_POLICY); +	rcu_read_unlock(); + +	return err; +} +  static int xfrm_set_default(struct sk_buff *skb, struct nlmsghdr *nlh,  			    struct nlattr **attrs)  {  	struct net *net = sock_net(skb->sk);  	struct xfrm_userpolicy_default *up = nlmsg_data(nlh); -	u8 dirmask; -	u8 old_default = net->xfrm.policy_default; -	if (up->dirmask >= XFRM_USERPOLICY_DIRMASK_MAX) -		return -EINVAL; +	if (up->in == XFRM_USERPOLICY_BLOCK) +		net->xfrm.policy_default |= XFRM_POL_DEFAULT_IN; +	else if (up->in == XFRM_USERPOLICY_ACCEPT) +		net->xfrm.policy_default &= ~XFRM_POL_DEFAULT_IN; -	dirmask = (1 << up->dirmask) & XFRM_POL_DEFAULT_MASK; +	if (up->fwd == XFRM_USERPOLICY_BLOCK) +		net->xfrm.policy_default |= XFRM_POL_DEFAULT_FWD; +	else if (up->fwd == XFRM_USERPOLICY_ACCEPT) +		net->xfrm.policy_default &= ~XFRM_POL_DEFAULT_FWD; -	net->xfrm.policy_default = (old_default & (0xff ^ dirmask)) -				    | (up->action << up->dirmask); +	if (up->out == XFRM_USERPOLICY_BLOCK) +		net->xfrm.policy_default |= XFRM_POL_DEFAULT_OUT; +	else if (up->out == XFRM_USERPOLICY_ACCEPT) +		net->xfrm.policy_default &= ~XFRM_POL_DEFAULT_OUT;  	rt_genid_bump_all(net); +	xfrm_notify_userpolicy(net);  	return 0;  } @@ -1988,13 +2029,11 @@ static int xfrm_get_default(struct sk_buff *skb, struct nlmsghdr *nlh,  	struct sk_buff *r_skb;  	struct nlmsghdr *r_nlh;  	struct net *net = sock_net(skb->sk); -	struct xfrm_userpolicy_default *r_up, *up; +	struct xfrm_userpolicy_default *r_up;  	int len = NLMSG_ALIGN(sizeof(struct xfrm_userpolicy_default));  	u32 portid = NETLINK_CB(skb).portid;  	u32 seq = nlh->nlmsg_seq; -	up = nlmsg_data(nlh); -  	r_skb = nlmsg_new(len, GFP_ATOMIC);  	if (!r_skb)  		return -ENOMEM; @@ -2007,8 +2046,12 @@ static int xfrm_get_default(struct sk_buff *skb, struct nlmsghdr *nlh,  	r_up = nlmsg_data(r_nlh); -	r_up->action = ((net->xfrm.policy_default & (1 << up->dirmask)) >> up->dirmask); -	r_up->dirmask = up->dirmask; +	r_up->in = net->xfrm.policy_default & XFRM_POL_DEFAULT_IN ? +			XFRM_USERPOLICY_BLOCK : XFRM_USERPOLICY_ACCEPT; +	r_up->fwd = net->xfrm.policy_default & XFRM_POL_DEFAULT_FWD ? +			XFRM_USERPOLICY_BLOCK : XFRM_USERPOLICY_ACCEPT; +	r_up->out = net->xfrm.policy_default & XFRM_POL_DEFAULT_OUT ? +			XFRM_USERPOLICY_BLOCK : XFRM_USERPOLICY_ACCEPT;  	nlmsg_end(r_skb, r_nlh);  	return nlmsg_unicast(net->xfrm.nlsk, r_skb, portid);  | 
