summaryrefslogtreecommitdiffstats
path: root/net/ipv4
diff options
context:
space:
mode:
Diffstat (limited to 'net/ipv4')
-rw-r--r--net/ipv4/fib_rules.c27
1 files changed, 24 insertions, 3 deletions
diff --git a/net/ipv4/fib_rules.c b/net/ipv4/fib_rules.c
index 768e8f5d7da..ec566f3e66c 100644
--- a/net/ipv4/fib_rules.c
+++ b/net/ipv4/fib_rules.c
@@ -104,6 +104,8 @@ static struct hlist_head fib_rules;
/* writer func called from netlink -- rtnl_sem hold*/
+static void rtmsg_rule(int, struct fib_rule *);
+
int inet_rtm_delrule(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg)
{
struct rtattr **rta = arg;
@@ -131,6 +133,7 @@ int inet_rtm_delrule(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg)
hlist_del_rcu(&r->hlist);
r->r_dead = 1;
+ rtmsg_rule(RTM_DELRULE, r);
fib_rule_put(r);
err = 0;
break;
@@ -253,6 +256,7 @@ int inet_rtm_newrule(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg)
else
hlist_add_before_rcu(&new_r->hlist, &r->hlist);
+ rtmsg_rule(RTM_NEWRULE, new_r);
return 0;
}
@@ -382,14 +386,14 @@ static struct notifier_block fib_rules_notifier = {
static __inline__ int inet_fill_rule(struct sk_buff *skb,
struct fib_rule *r,
- struct netlink_callback *cb,
+ u32 pid, u32 seq, int event,
unsigned int flags)
{
struct rtmsg *rtm;
struct nlmsghdr *nlh;
unsigned char *b = skb->tail;
- nlh = NLMSG_NEW_ANSWER(skb, cb, RTM_NEWRULE, sizeof(*rtm), flags);
+ nlh = NLMSG_NEW(skb, pid, seq, event, sizeof(*rtm), flags);
rtm = NLMSG_DATA(nlh);
rtm->rtm_family = AF_INET;
rtm->rtm_dst_len = r->r_dst_len;
@@ -430,6 +434,21 @@ rtattr_failure:
/* callers should hold rtnl semaphore */
+static void rtmsg_rule(int event, struct fib_rule *r)
+{
+ int size = NLMSG_SPACE(sizeof(struct rtmsg) + 128);
+ struct sk_buff *skb = alloc_skb(size, GFP_KERNEL);
+
+ if (!skb)
+ netlink_set_err(rtnl, 0, RTNLGRP_IPV4_RULE, ENOBUFS);
+ else if (inet_fill_rule(skb, r, 0, 0, event, 0) < 0) {
+ kfree_skb(skb);
+ netlink_set_err(rtnl, 0, RTNLGRP_IPV4_RULE, EINVAL);
+ } else {
+ netlink_broadcast(rtnl, skb, 0, RTNLGRP_IPV4_RULE, GFP_KERNEL);
+ }
+}
+
int inet_dump_rules(struct sk_buff *skb, struct netlink_callback *cb)
{
int idx = 0;
@@ -442,7 +461,9 @@ int inet_dump_rules(struct sk_buff *skb, struct netlink_callback *cb)
if (idx < s_idx)
continue;
- if (inet_fill_rule(skb, r, cb, NLM_F_MULTI) < 0)
+ if (inet_fill_rule(skb, r, NETLINK_CB(cb->skb).pid,
+ cb->nlh->nlmsg_seq,
+ RTM_NEWRULE, NLM_F_MULTI) < 0)
break;
idx++;
}