diff options
-rw-r--r-- | net/ipv4/devinet.c | 53 |
1 files changed, 37 insertions, 16 deletions
diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c index 398e7b9ca66b..0487677729cf 100644 --- a/net/ipv4/devinet.c +++ b/net/ipv4/devinet.c | |||
@@ -88,7 +88,7 @@ static struct nla_policy ifa_ipv4_policy[IFA_MAX+1] __read_mostly = { | |||
88 | [IFA_LABEL] = { .type = NLA_STRING }, | 88 | [IFA_LABEL] = { .type = NLA_STRING }, |
89 | }; | 89 | }; |
90 | 90 | ||
91 | static void rtmsg_ifa(int event, struct in_ifaddr *); | 91 | static void rtmsg_ifa(int event, struct in_ifaddr *, struct nlmsghdr *, u32); |
92 | 92 | ||
93 | static BLOCKING_NOTIFIER_HEAD(inetaddr_chain); | 93 | static BLOCKING_NOTIFIER_HEAD(inetaddr_chain); |
94 | static void inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap, | 94 | static void inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap, |
@@ -239,8 +239,8 @@ int inet_addr_onlink(struct in_device *in_dev, u32 a, u32 b) | |||
239 | return 0; | 239 | return 0; |
240 | } | 240 | } |
241 | 241 | ||
242 | static void inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap, | 242 | static void __inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap, |
243 | int destroy) | 243 | int destroy, struct nlmsghdr *nlh, u32 pid) |
244 | { | 244 | { |
245 | struct in_ifaddr *promote = NULL; | 245 | struct in_ifaddr *promote = NULL; |
246 | struct in_ifaddr *ifa, *ifa1 = *ifap; | 246 | struct in_ifaddr *ifa, *ifa1 = *ifap; |
@@ -273,7 +273,7 @@ static void inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap, | |||
273 | if (!do_promote) { | 273 | if (!do_promote) { |
274 | *ifap1 = ifa->ifa_next; | 274 | *ifap1 = ifa->ifa_next; |
275 | 275 | ||
276 | rtmsg_ifa(RTM_DELADDR, ifa); | 276 | rtmsg_ifa(RTM_DELADDR, ifa, nlh, pid); |
277 | blocking_notifier_call_chain(&inetaddr_chain, | 277 | blocking_notifier_call_chain(&inetaddr_chain, |
278 | NETDEV_DOWN, ifa); | 278 | NETDEV_DOWN, ifa); |
279 | inet_free_ifa(ifa); | 279 | inet_free_ifa(ifa); |
@@ -298,7 +298,7 @@ static void inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap, | |||
298 | is valid, it will try to restore deleted routes... Grr. | 298 | is valid, it will try to restore deleted routes... Grr. |
299 | So that, this order is correct. | 299 | So that, this order is correct. |
300 | */ | 300 | */ |
301 | rtmsg_ifa(RTM_DELADDR, ifa1); | 301 | rtmsg_ifa(RTM_DELADDR, ifa1, nlh, pid); |
302 | blocking_notifier_call_chain(&inetaddr_chain, NETDEV_DOWN, ifa1); | 302 | blocking_notifier_call_chain(&inetaddr_chain, NETDEV_DOWN, ifa1); |
303 | 303 | ||
304 | if (promote) { | 304 | if (promote) { |
@@ -310,7 +310,7 @@ static void inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap, | |||
310 | } | 310 | } |
311 | 311 | ||
312 | promote->ifa_flags &= ~IFA_F_SECONDARY; | 312 | promote->ifa_flags &= ~IFA_F_SECONDARY; |
313 | rtmsg_ifa(RTM_NEWADDR, promote); | 313 | rtmsg_ifa(RTM_NEWADDR, promote, nlh, pid); |
314 | blocking_notifier_call_chain(&inetaddr_chain, | 314 | blocking_notifier_call_chain(&inetaddr_chain, |
315 | NETDEV_UP, promote); | 315 | NETDEV_UP, promote); |
316 | for (ifa = promote->ifa_next; ifa; ifa = ifa->ifa_next) { | 316 | for (ifa = promote->ifa_next; ifa; ifa = ifa->ifa_next) { |
@@ -329,7 +329,14 @@ static void inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap, | |||
329 | } | 329 | } |
330 | } | 330 | } |
331 | 331 | ||
332 | static int inet_insert_ifa(struct in_ifaddr *ifa) | 332 | static void inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap, |
333 | int destroy) | ||
334 | { | ||
335 | __inet_del_ifa(in_dev, ifap, destroy, NULL, 0); | ||
336 | } | ||
337 | |||
338 | static int __inet_insert_ifa(struct in_ifaddr *ifa, struct nlmsghdr *nlh, | ||
339 | u32 pid) | ||
333 | { | 340 | { |
334 | struct in_device *in_dev = ifa->ifa_dev; | 341 | struct in_device *in_dev = ifa->ifa_dev; |
335 | struct in_ifaddr *ifa1, **ifap, **last_primary; | 342 | struct in_ifaddr *ifa1, **ifap, **last_primary; |
@@ -374,12 +381,17 @@ static int inet_insert_ifa(struct in_ifaddr *ifa) | |||
374 | /* Send message first, then call notifier. | 381 | /* Send message first, then call notifier. |
375 | Notifier will trigger FIB update, so that | 382 | Notifier will trigger FIB update, so that |
376 | listeners of netlink will know about new ifaddr */ | 383 | listeners of netlink will know about new ifaddr */ |
377 | rtmsg_ifa(RTM_NEWADDR, ifa); | 384 | rtmsg_ifa(RTM_NEWADDR, ifa, nlh, pid); |
378 | blocking_notifier_call_chain(&inetaddr_chain, NETDEV_UP, ifa); | 385 | blocking_notifier_call_chain(&inetaddr_chain, NETDEV_UP, ifa); |
379 | 386 | ||
380 | return 0; | 387 | return 0; |
381 | } | 388 | } |
382 | 389 | ||
390 | static int inet_insert_ifa(struct in_ifaddr *ifa) | ||
391 | { | ||
392 | return __inet_insert_ifa(ifa, NULL, 0); | ||
393 | } | ||
394 | |||
383 | static int inet_set_ifa(struct net_device *dev, struct in_ifaddr *ifa) | 395 | static int inet_set_ifa(struct net_device *dev, struct in_ifaddr *ifa) |
384 | { | 396 | { |
385 | struct in_device *in_dev = __in_dev_get_rtnl(dev); | 397 | struct in_device *in_dev = __in_dev_get_rtnl(dev); |
@@ -466,7 +478,7 @@ static int inet_rtm_deladdr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg | |||
466 | !inet_ifa_match(nla_get_u32(tb[IFA_ADDRESS]), ifa))) | 478 | !inet_ifa_match(nla_get_u32(tb[IFA_ADDRESS]), ifa))) |
467 | continue; | 479 | continue; |
468 | 480 | ||
469 | inet_del_ifa(in_dev, ifap, 1); | 481 | __inet_del_ifa(in_dev, ifap, 1, nlh, NETLINK_CB(skb).pid); |
470 | return 0; | 482 | return 0; |
471 | } | 483 | } |
472 | 484 | ||
@@ -558,7 +570,7 @@ static int inet_rtm_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg | |||
558 | if (IS_ERR(ifa)) | 570 | if (IS_ERR(ifa)) |
559 | return PTR_ERR(ifa); | 571 | return PTR_ERR(ifa); |
560 | 572 | ||
561 | return inet_insert_ifa(ifa); | 573 | return __inet_insert_ifa(ifa, nlh, NETLINK_CB(skb).pid); |
562 | } | 574 | } |
563 | 575 | ||
564 | /* | 576 | /* |
@@ -1189,18 +1201,27 @@ done: | |||
1189 | return skb->len; | 1201 | return skb->len; |
1190 | } | 1202 | } |
1191 | 1203 | ||
1192 | static void rtmsg_ifa(int event, struct in_ifaddr* ifa) | 1204 | static void rtmsg_ifa(int event, struct in_ifaddr* ifa, struct nlmsghdr *nlh, |
1205 | u32 pid) | ||
1193 | { | 1206 | { |
1194 | struct sk_buff *skb; | 1207 | struct sk_buff *skb; |
1208 | u32 seq = nlh ? nlh->nlmsg_seq : 0; | ||
1209 | int err = -ENOBUFS; | ||
1195 | 1210 | ||
1196 | skb = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); | 1211 | skb = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); |
1197 | if (skb == NULL) | 1212 | if (skb == NULL) |
1198 | netlink_set_err(rtnl, 0, RTNLGRP_IPV4_IFADDR, ENOBUFS); | 1213 | goto errout; |
1199 | else if (inet_fill_ifaddr(skb, ifa, 0, 0, event, 0) < 0) { | 1214 | |
1215 | err = inet_fill_ifaddr(skb, ifa, pid, seq, event, 0); | ||
1216 | if (err < 0) { | ||
1200 | kfree_skb(skb); | 1217 | kfree_skb(skb); |
1201 | netlink_set_err(rtnl, 0, RTNLGRP_IPV4_IFADDR, EINVAL); | 1218 | goto errout; |
1202 | } else | 1219 | } |
1203 | netlink_broadcast(rtnl, skb, 0, RTNLGRP_IPV4_IFADDR, GFP_KERNEL); | 1220 | |
1221 | err = rtnl_notify(skb, pid, RTNLGRP_IPV4_IFADDR, nlh, GFP_KERNEL); | ||
1222 | errout: | ||
1223 | if (err < 0) | ||
1224 | rtnl_set_sk_err(RTNLGRP_IPV4_IFADDR, err); | ||
1204 | } | 1225 | } |
1205 | 1226 | ||
1206 | static struct rtnetlink_link inet_rtnetlink_table[RTM_NR_MSGTYPES] = { | 1227 | static struct rtnetlink_link inet_rtnetlink_table[RTM_NR_MSGTYPES] = { |