diff options
Diffstat (limited to 'net/core/rtnetlink.c')
| -rw-r--r-- | net/core/rtnetlink.c | 378 |
1 files changed, 281 insertions, 97 deletions
diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index eb42873f2a3a..31e85d327aa2 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c | |||
| @@ -35,10 +35,10 @@ | |||
| 35 | #include <linux/security.h> | 35 | #include <linux/security.h> |
| 36 | #include <linux/mutex.h> | 36 | #include <linux/mutex.h> |
| 37 | #include <linux/if_addr.h> | 37 | #include <linux/if_addr.h> |
| 38 | #include <linux/pci.h> | ||
| 38 | 39 | ||
| 39 | #include <asm/uaccess.h> | 40 | #include <asm/uaccess.h> |
| 40 | #include <asm/system.h> | 41 | #include <asm/system.h> |
| 41 | #include <asm/string.h> | ||
| 42 | 42 | ||
| 43 | #include <linux/inet.h> | 43 | #include <linux/inet.h> |
| 44 | #include <linux/netdevice.h> | 44 | #include <linux/netdevice.h> |
| @@ -53,8 +53,7 @@ | |||
| 53 | #include <net/rtnetlink.h> | 53 | #include <net/rtnetlink.h> |
| 54 | #include <net/net_namespace.h> | 54 | #include <net/net_namespace.h> |
| 55 | 55 | ||
| 56 | struct rtnl_link | 56 | struct rtnl_link { |
| 57 | { | ||
| 58 | rtnl_doit_func doit; | 57 | rtnl_doit_func doit; |
| 59 | rtnl_dumpit_func dumpit; | 58 | rtnl_dumpit_func dumpit; |
| 60 | }; | 59 | }; |
| @@ -65,6 +64,7 @@ void rtnl_lock(void) | |||
| 65 | { | 64 | { |
| 66 | mutex_lock(&rtnl_mutex); | 65 | mutex_lock(&rtnl_mutex); |
| 67 | } | 66 | } |
| 67 | EXPORT_SYMBOL(rtnl_lock); | ||
| 68 | 68 | ||
| 69 | void __rtnl_unlock(void) | 69 | void __rtnl_unlock(void) |
| 70 | { | 70 | { |
| @@ -76,16 +76,27 @@ void rtnl_unlock(void) | |||
| 76 | /* This fellow will unlock it for us. */ | 76 | /* This fellow will unlock it for us. */ |
| 77 | netdev_run_todo(); | 77 | netdev_run_todo(); |
| 78 | } | 78 | } |
| 79 | EXPORT_SYMBOL(rtnl_unlock); | ||
| 79 | 80 | ||
| 80 | int rtnl_trylock(void) | 81 | int rtnl_trylock(void) |
| 81 | { | 82 | { |
| 82 | return mutex_trylock(&rtnl_mutex); | 83 | return mutex_trylock(&rtnl_mutex); |
| 83 | } | 84 | } |
| 85 | EXPORT_SYMBOL(rtnl_trylock); | ||
| 84 | 86 | ||
| 85 | int rtnl_is_locked(void) | 87 | int rtnl_is_locked(void) |
| 86 | { | 88 | { |
| 87 | return mutex_is_locked(&rtnl_mutex); | 89 | return mutex_is_locked(&rtnl_mutex); |
| 88 | } | 90 | } |
| 91 | EXPORT_SYMBOL(rtnl_is_locked); | ||
| 92 | |||
| 93 | #ifdef CONFIG_PROVE_LOCKING | ||
| 94 | int lockdep_rtnl_is_held(void) | ||
| 95 | { | ||
| 96 | return lockdep_is_held(&rtnl_mutex); | ||
| 97 | } | ||
| 98 | EXPORT_SYMBOL(lockdep_rtnl_is_held); | ||
| 99 | #endif /* #ifdef CONFIG_PROVE_LOCKING */ | ||
| 89 | 100 | ||
| 90 | static struct rtnl_link *rtnl_msg_handlers[NPROTO]; | 101 | static struct rtnl_link *rtnl_msg_handlers[NPROTO]; |
| 91 | 102 | ||
| @@ -168,7 +179,6 @@ int __rtnl_register(int protocol, int msgtype, | |||
| 168 | 179 | ||
| 169 | return 0; | 180 | return 0; |
| 170 | } | 181 | } |
| 171 | |||
| 172 | EXPORT_SYMBOL_GPL(__rtnl_register); | 182 | EXPORT_SYMBOL_GPL(__rtnl_register); |
| 173 | 183 | ||
| 174 | /** | 184 | /** |
| @@ -188,7 +198,6 @@ void rtnl_register(int protocol, int msgtype, | |||
| 188 | "protocol = %d, message type = %d\n", | 198 | "protocol = %d, message type = %d\n", |
| 189 | protocol, msgtype); | 199 | protocol, msgtype); |
| 190 | } | 200 | } |
| 191 | |||
| 192 | EXPORT_SYMBOL_GPL(rtnl_register); | 201 | EXPORT_SYMBOL_GPL(rtnl_register); |
| 193 | 202 | ||
| 194 | /** | 203 | /** |
| @@ -213,7 +222,6 @@ int rtnl_unregister(int protocol, int msgtype) | |||
| 213 | 222 | ||
| 214 | return 0; | 223 | return 0; |
| 215 | } | 224 | } |
| 216 | |||
| 217 | EXPORT_SYMBOL_GPL(rtnl_unregister); | 225 | EXPORT_SYMBOL_GPL(rtnl_unregister); |
| 218 | 226 | ||
| 219 | /** | 227 | /** |
| @@ -230,7 +238,6 @@ void rtnl_unregister_all(int protocol) | |||
| 230 | kfree(rtnl_msg_handlers[protocol]); | 238 | kfree(rtnl_msg_handlers[protocol]); |
| 231 | rtnl_msg_handlers[protocol] = NULL; | 239 | rtnl_msg_handlers[protocol] = NULL; |
| 232 | } | 240 | } |
| 233 | |||
| 234 | EXPORT_SYMBOL_GPL(rtnl_unregister_all); | 241 | EXPORT_SYMBOL_GPL(rtnl_unregister_all); |
| 235 | 242 | ||
| 236 | static LIST_HEAD(link_ops); | 243 | static LIST_HEAD(link_ops); |
| @@ -248,12 +255,11 @@ static LIST_HEAD(link_ops); | |||
| 248 | int __rtnl_link_register(struct rtnl_link_ops *ops) | 255 | int __rtnl_link_register(struct rtnl_link_ops *ops) |
| 249 | { | 256 | { |
| 250 | if (!ops->dellink) | 257 | if (!ops->dellink) |
| 251 | ops->dellink = unregister_netdevice; | 258 | ops->dellink = unregister_netdevice_queue; |
| 252 | 259 | ||
| 253 | list_add_tail(&ops->list, &link_ops); | 260 | list_add_tail(&ops->list, &link_ops); |
| 254 | return 0; | 261 | return 0; |
| 255 | } | 262 | } |
| 256 | |||
| 257 | EXPORT_SYMBOL_GPL(__rtnl_link_register); | 263 | EXPORT_SYMBOL_GPL(__rtnl_link_register); |
| 258 | 264 | ||
| 259 | /** | 265 | /** |
| @@ -271,19 +277,18 @@ int rtnl_link_register(struct rtnl_link_ops *ops) | |||
| 271 | rtnl_unlock(); | 277 | rtnl_unlock(); |
| 272 | return err; | 278 | return err; |
| 273 | } | 279 | } |
| 274 | |||
| 275 | EXPORT_SYMBOL_GPL(rtnl_link_register); | 280 | EXPORT_SYMBOL_GPL(rtnl_link_register); |
| 276 | 281 | ||
| 277 | static void __rtnl_kill_links(struct net *net, struct rtnl_link_ops *ops) | 282 | static void __rtnl_kill_links(struct net *net, struct rtnl_link_ops *ops) |
| 278 | { | 283 | { |
| 279 | struct net_device *dev; | 284 | struct net_device *dev; |
| 280 | restart: | 285 | LIST_HEAD(list_kill); |
| 286 | |||
| 281 | for_each_netdev(net, dev) { | 287 | for_each_netdev(net, dev) { |
| 282 | if (dev->rtnl_link_ops == ops) { | 288 | if (dev->rtnl_link_ops == ops) |
| 283 | ops->dellink(dev); | 289 | ops->dellink(dev, &list_kill); |
| 284 | goto restart; | ||
| 285 | } | ||
| 286 | } | 290 | } |
| 291 | unregister_netdevice_many(&list_kill); | ||
| 287 | } | 292 | } |
| 288 | 293 | ||
| 289 | void rtnl_kill_links(struct net *net, struct rtnl_link_ops *ops) | 294 | void rtnl_kill_links(struct net *net, struct rtnl_link_ops *ops) |
| @@ -309,7 +314,6 @@ void __rtnl_link_unregister(struct rtnl_link_ops *ops) | |||
| 309 | } | 314 | } |
| 310 | list_del(&ops->list); | 315 | list_del(&ops->list); |
| 311 | } | 316 | } |
| 312 | |||
| 313 | EXPORT_SYMBOL_GPL(__rtnl_link_unregister); | 317 | EXPORT_SYMBOL_GPL(__rtnl_link_unregister); |
| 314 | 318 | ||
| 315 | /** | 319 | /** |
| @@ -322,7 +326,6 @@ void rtnl_link_unregister(struct rtnl_link_ops *ops) | |||
| 322 | __rtnl_link_unregister(ops); | 326 | __rtnl_link_unregister(ops); |
| 323 | rtnl_unlock(); | 327 | rtnl_unlock(); |
| 324 | } | 328 | } |
| 325 | |||
| 326 | EXPORT_SYMBOL_GPL(rtnl_link_unregister); | 329 | EXPORT_SYMBOL_GPL(rtnl_link_unregister); |
| 327 | 330 | ||
| 328 | static const struct rtnl_link_ops *rtnl_link_ops_get(const char *kind) | 331 | static const struct rtnl_link_ops *rtnl_link_ops_get(const char *kind) |
| @@ -427,12 +430,13 @@ void __rta_fill(struct sk_buff *skb, int attrtype, int attrlen, const void *data | |||
| 427 | struct rtattr *rta; | 430 | struct rtattr *rta; |
| 428 | int size = RTA_LENGTH(attrlen); | 431 | int size = RTA_LENGTH(attrlen); |
| 429 | 432 | ||
| 430 | rta = (struct rtattr*)skb_put(skb, RTA_ALIGN(size)); | 433 | rta = (struct rtattr *)skb_put(skb, RTA_ALIGN(size)); |
| 431 | rta->rta_type = attrtype; | 434 | rta->rta_type = attrtype; |
| 432 | rta->rta_len = size; | 435 | rta->rta_len = size; |
| 433 | memcpy(RTA_DATA(rta), data, attrlen); | 436 | memcpy(RTA_DATA(rta), data, attrlen); |
| 434 | memset(RTA_DATA(rta) + attrlen, 0, RTA_ALIGN(size) - size); | 437 | memset(RTA_DATA(rta) + attrlen, 0, RTA_ALIGN(size) - size); |
| 435 | } | 438 | } |
| 439 | EXPORT_SYMBOL(__rta_fill); | ||
| 436 | 440 | ||
| 437 | int rtnetlink_send(struct sk_buff *skb, struct net *net, u32 pid, unsigned group, int echo) | 441 | int rtnetlink_send(struct sk_buff *skb, struct net *net, u32 pid, unsigned group, int echo) |
| 438 | { | 442 | { |
| @@ -454,6 +458,7 @@ int rtnl_unicast(struct sk_buff *skb, struct net *net, u32 pid) | |||
| 454 | 458 | ||
| 455 | return nlmsg_unicast(rtnl, skb, pid); | 459 | return nlmsg_unicast(rtnl, skb, pid); |
| 456 | } | 460 | } |
| 461 | EXPORT_SYMBOL(rtnl_unicast); | ||
| 457 | 462 | ||
| 458 | void rtnl_notify(struct sk_buff *skb, struct net *net, u32 pid, u32 group, | 463 | void rtnl_notify(struct sk_buff *skb, struct net *net, u32 pid, u32 group, |
| 459 | struct nlmsghdr *nlh, gfp_t flags) | 464 | struct nlmsghdr *nlh, gfp_t flags) |
| @@ -466,6 +471,7 @@ void rtnl_notify(struct sk_buff *skb, struct net *net, u32 pid, u32 group, | |||
| 466 | 471 | ||
| 467 | nlmsg_notify(rtnl, skb, pid, group, report, flags); | 472 | nlmsg_notify(rtnl, skb, pid, group, report, flags); |
| 468 | } | 473 | } |
| 474 | EXPORT_SYMBOL(rtnl_notify); | ||
| 469 | 475 | ||
| 470 | void rtnl_set_sk_err(struct net *net, u32 group, int error) | 476 | void rtnl_set_sk_err(struct net *net, u32 group, int error) |
| 471 | { | 477 | { |
| @@ -473,6 +479,7 @@ void rtnl_set_sk_err(struct net *net, u32 group, int error) | |||
| 473 | 479 | ||
| 474 | netlink_set_err(rtnl, 0, group, error); | 480 | netlink_set_err(rtnl, 0, group, error); |
| 475 | } | 481 | } |
| 482 | EXPORT_SYMBOL(rtnl_set_sk_err); | ||
| 476 | 483 | ||
| 477 | int rtnetlink_put_metrics(struct sk_buff *skb, u32 *metrics) | 484 | int rtnetlink_put_metrics(struct sk_buff *skb, u32 *metrics) |
| 478 | { | 485 | { |
| @@ -501,6 +508,7 @@ nla_put_failure: | |||
| 501 | nla_nest_cancel(skb, mx); | 508 | nla_nest_cancel(skb, mx); |
| 502 | return -EMSGSIZE; | 509 | return -EMSGSIZE; |
| 503 | } | 510 | } |
| 511 | EXPORT_SYMBOL(rtnetlink_put_metrics); | ||
| 504 | 512 | ||
| 505 | int rtnl_put_cacheinfo(struct sk_buff *skb, struct dst_entry *dst, u32 id, | 513 | int rtnl_put_cacheinfo(struct sk_buff *skb, struct dst_entry *dst, u32 id, |
| 506 | u32 ts, u32 tsage, long expires, u32 error) | 514 | u32 ts, u32 tsage, long expires, u32 error) |
| @@ -520,14 +528,13 @@ int rtnl_put_cacheinfo(struct sk_buff *skb, struct dst_entry *dst, u32 id, | |||
| 520 | 528 | ||
| 521 | return nla_put(skb, RTA_CACHEINFO, sizeof(ci), &ci); | 529 | return nla_put(skb, RTA_CACHEINFO, sizeof(ci), &ci); |
| 522 | } | 530 | } |
| 523 | |||
| 524 | EXPORT_SYMBOL_GPL(rtnl_put_cacheinfo); | 531 | EXPORT_SYMBOL_GPL(rtnl_put_cacheinfo); |
| 525 | 532 | ||
| 526 | static void set_operstate(struct net_device *dev, unsigned char transition) | 533 | static void set_operstate(struct net_device *dev, unsigned char transition) |
| 527 | { | 534 | { |
| 528 | unsigned char operstate = dev->operstate; | 535 | unsigned char operstate = dev->operstate; |
| 529 | 536 | ||
| 530 | switch(transition) { | 537 | switch (transition) { |
| 531 | case IF_OPER_UP: | 538 | case IF_OPER_UP: |
| 532 | if ((operstate == IF_OPER_DORMANT || | 539 | if ((operstate == IF_OPER_DORMANT || |
| 533 | operstate == IF_OPER_UNKNOWN) && | 540 | operstate == IF_OPER_UNKNOWN) && |
| @@ -550,6 +557,19 @@ static void set_operstate(struct net_device *dev, unsigned char transition) | |||
| 550 | } | 557 | } |
| 551 | } | 558 | } |
| 552 | 559 | ||
| 560 | static unsigned int rtnl_dev_combine_flags(const struct net_device *dev, | ||
| 561 | const struct ifinfomsg *ifm) | ||
| 562 | { | ||
| 563 | unsigned int flags = ifm->ifi_flags; | ||
| 564 | |||
| 565 | /* bugwards compatibility: ifi_change == 0 is treated as ~0 */ | ||
| 566 | if (ifm->ifi_change) | ||
| 567 | flags = (flags & ifm->ifi_change) | | ||
| 568 | (dev->flags & ~ifm->ifi_change); | ||
| 569 | |||
| 570 | return flags; | ||
| 571 | } | ||
| 572 | |||
| 553 | static void copy_rtnl_link_stats(struct rtnl_link_stats *a, | 573 | static void copy_rtnl_link_stats(struct rtnl_link_stats *a, |
| 554 | const struct net_device_stats *b) | 574 | const struct net_device_stats *b) |
| 555 | { | 575 | { |
| @@ -582,6 +602,22 @@ static void copy_rtnl_link_stats(struct rtnl_link_stats *a, | |||
| 582 | a->tx_compressed = b->tx_compressed; | 602 | a->tx_compressed = b->tx_compressed; |
| 583 | }; | 603 | }; |
| 584 | 604 | ||
| 605 | /* All VF info */ | ||
| 606 | static inline int rtnl_vfinfo_size(const struct net_device *dev) | ||
| 607 | { | ||
| 608 | if (dev->dev.parent && dev_is_pci(dev->dev.parent)) { | ||
| 609 | |||
| 610 | int num_vfs = dev_num_vf(dev->dev.parent); | ||
| 611 | size_t size = nlmsg_total_size(sizeof(struct nlattr)); | ||
| 612 | size += nlmsg_total_size(num_vfs * sizeof(struct nlattr)); | ||
| 613 | size += num_vfs * (sizeof(struct ifla_vf_mac) + | ||
| 614 | sizeof(struct ifla_vf_vlan) + | ||
| 615 | sizeof(struct ifla_vf_tx_rate)); | ||
| 616 | return size; | ||
| 617 | } else | ||
| 618 | return 0; | ||
| 619 | } | ||
| 620 | |||
| 585 | static inline size_t if_nlmsg_size(const struct net_device *dev) | 621 | static inline size_t if_nlmsg_size(const struct net_device *dev) |
| 586 | { | 622 | { |
| 587 | return NLMSG_ALIGN(sizeof(struct ifinfomsg)) | 623 | return NLMSG_ALIGN(sizeof(struct ifinfomsg)) |
| @@ -599,6 +635,8 @@ static inline size_t if_nlmsg_size(const struct net_device *dev) | |||
| 599 | + nla_total_size(4) /* IFLA_MASTER */ | 635 | + nla_total_size(4) /* IFLA_MASTER */ |
| 600 | + nla_total_size(1) /* IFLA_OPERSTATE */ | 636 | + nla_total_size(1) /* IFLA_OPERSTATE */ |
| 601 | + nla_total_size(1) /* IFLA_LINKMODE */ | 637 | + nla_total_size(1) /* IFLA_LINKMODE */ |
| 638 | + nla_total_size(4) /* IFLA_NUM_VF */ | ||
| 639 | + rtnl_vfinfo_size(dev) /* IFLA_VFINFO_LIST */ | ||
| 602 | + rtnl_link_get_size(dev); /* IFLA_LINKINFO */ | 640 | + rtnl_link_get_size(dev); /* IFLA_LINKINFO */ |
| 603 | } | 641 | } |
| 604 | 642 | ||
| @@ -667,6 +705,40 @@ static int rtnl_fill_ifinfo(struct sk_buff *skb, struct net_device *dev, | |||
| 667 | stats = dev_get_stats(dev); | 705 | stats = dev_get_stats(dev); |
| 668 | copy_rtnl_link_stats(nla_data(attr), stats); | 706 | copy_rtnl_link_stats(nla_data(attr), stats); |
| 669 | 707 | ||
| 708 | if (dev->netdev_ops->ndo_get_vf_config && dev->dev.parent) { | ||
| 709 | int i; | ||
| 710 | |||
| 711 | struct nlattr *vfinfo, *vf; | ||
| 712 | int num_vfs = dev_num_vf(dev->dev.parent); | ||
| 713 | |||
| 714 | NLA_PUT_U32(skb, IFLA_NUM_VF, num_vfs); | ||
| 715 | vfinfo = nla_nest_start(skb, IFLA_VFINFO_LIST); | ||
| 716 | if (!vfinfo) | ||
| 717 | goto nla_put_failure; | ||
| 718 | for (i = 0; i < num_vfs; i++) { | ||
| 719 | struct ifla_vf_info ivi; | ||
| 720 | struct ifla_vf_mac vf_mac; | ||
| 721 | struct ifla_vf_vlan vf_vlan; | ||
| 722 | struct ifla_vf_tx_rate vf_tx_rate; | ||
| 723 | if (dev->netdev_ops->ndo_get_vf_config(dev, i, &ivi)) | ||
| 724 | break; | ||
| 725 | vf_mac.vf = vf_vlan.vf = vf_tx_rate.vf = ivi.vf; | ||
| 726 | memcpy(vf_mac.mac, ivi.mac, sizeof(ivi.mac)); | ||
| 727 | vf_vlan.vlan = ivi.vlan; | ||
| 728 | vf_vlan.qos = ivi.qos; | ||
| 729 | vf_tx_rate.rate = ivi.tx_rate; | ||
| 730 | vf = nla_nest_start(skb, IFLA_VF_INFO); | ||
| 731 | if (!vf) { | ||
| 732 | nla_nest_cancel(skb, vfinfo); | ||
| 733 | goto nla_put_failure; | ||
| 734 | } | ||
| 735 | NLA_PUT(skb, IFLA_VF_MAC, sizeof(vf_mac), &vf_mac); | ||
| 736 | NLA_PUT(skb, IFLA_VF_VLAN, sizeof(vf_vlan), &vf_vlan); | ||
| 737 | NLA_PUT(skb, IFLA_VF_TX_RATE, sizeof(vf_tx_rate), &vf_tx_rate); | ||
| 738 | nla_nest_end(skb, vf); | ||
| 739 | } | ||
| 740 | nla_nest_end(skb, vfinfo); | ||
| 741 | } | ||
| 670 | if (dev->rtnl_link_ops) { | 742 | if (dev->rtnl_link_ops) { |
| 671 | if (rtnl_link_fill(skb, dev) < 0) | 743 | if (rtnl_link_fill(skb, dev) < 0) |
| 672 | goto nla_put_failure; | 744 | goto nla_put_failure; |
| @@ -682,22 +754,33 @@ nla_put_failure: | |||
| 682 | static int rtnl_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb) | 754 | static int rtnl_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb) |
| 683 | { | 755 | { |
| 684 | struct net *net = sock_net(skb->sk); | 756 | struct net *net = sock_net(skb->sk); |
| 685 | int idx; | 757 | int h, s_h; |
| 686 | int s_idx = cb->args[0]; | 758 | int idx = 0, s_idx; |
| 687 | struct net_device *dev; | 759 | struct net_device *dev; |
| 688 | 760 | struct hlist_head *head; | |
| 689 | idx = 0; | 761 | struct hlist_node *node; |
| 690 | for_each_netdev(net, dev) { | 762 | |
| 691 | if (idx < s_idx) | 763 | s_h = cb->args[0]; |
| 692 | goto cont; | 764 | s_idx = cb->args[1]; |
| 693 | if (rtnl_fill_ifinfo(skb, dev, RTM_NEWLINK, | 765 | |
| 694 | NETLINK_CB(cb->skb).pid, | 766 | for (h = s_h; h < NETDEV_HASHENTRIES; h++, s_idx = 0) { |
| 695 | cb->nlh->nlmsg_seq, 0, NLM_F_MULTI) <= 0) | 767 | idx = 0; |
| 696 | break; | 768 | head = &net->dev_index_head[h]; |
| 769 | hlist_for_each_entry(dev, node, head, index_hlist) { | ||
| 770 | if (idx < s_idx) | ||
| 771 | goto cont; | ||
| 772 | if (rtnl_fill_ifinfo(skb, dev, RTM_NEWLINK, | ||
| 773 | NETLINK_CB(cb->skb).pid, | ||
| 774 | cb->nlh->nlmsg_seq, 0, | ||
| 775 | NLM_F_MULTI) <= 0) | ||
| 776 | goto out; | ||
| 697 | cont: | 777 | cont: |
| 698 | idx++; | 778 | idx++; |
| 779 | } | ||
| 699 | } | 780 | } |
| 700 | cb->args[0] = idx; | 781 | out: |
| 782 | cb->args[1] = idx; | ||
| 783 | cb->args[0] = h; | ||
| 701 | 784 | ||
| 702 | return skb->len; | 785 | return skb->len; |
| 703 | } | 786 | } |
| @@ -716,13 +799,42 @@ const struct nla_policy ifla_policy[IFLA_MAX+1] = { | |||
| 716 | [IFLA_LINKINFO] = { .type = NLA_NESTED }, | 799 | [IFLA_LINKINFO] = { .type = NLA_NESTED }, |
| 717 | [IFLA_NET_NS_PID] = { .type = NLA_U32 }, | 800 | [IFLA_NET_NS_PID] = { .type = NLA_U32 }, |
| 718 | [IFLA_IFALIAS] = { .type = NLA_STRING, .len = IFALIASZ-1 }, | 801 | [IFLA_IFALIAS] = { .type = NLA_STRING, .len = IFALIASZ-1 }, |
| 802 | [IFLA_VFINFO_LIST] = {. type = NLA_NESTED }, | ||
| 719 | }; | 803 | }; |
| 804 | EXPORT_SYMBOL(ifla_policy); | ||
| 720 | 805 | ||
| 721 | static const struct nla_policy ifla_info_policy[IFLA_INFO_MAX+1] = { | 806 | static const struct nla_policy ifla_info_policy[IFLA_INFO_MAX+1] = { |
| 722 | [IFLA_INFO_KIND] = { .type = NLA_STRING }, | 807 | [IFLA_INFO_KIND] = { .type = NLA_STRING }, |
| 723 | [IFLA_INFO_DATA] = { .type = NLA_NESTED }, | 808 | [IFLA_INFO_DATA] = { .type = NLA_NESTED }, |
| 724 | }; | 809 | }; |
| 725 | 810 | ||
| 811 | static const struct nla_policy ifla_vfinfo_policy[IFLA_VF_INFO_MAX+1] = { | ||
| 812 | [IFLA_VF_INFO] = { .type = NLA_NESTED }, | ||
| 813 | }; | ||
| 814 | |||
| 815 | static const struct nla_policy ifla_vf_policy[IFLA_VF_MAX+1] = { | ||
| 816 | [IFLA_VF_MAC] = { .type = NLA_BINARY, | ||
| 817 | .len = sizeof(struct ifla_vf_mac) }, | ||
| 818 | [IFLA_VF_VLAN] = { .type = NLA_BINARY, | ||
| 819 | .len = sizeof(struct ifla_vf_vlan) }, | ||
| 820 | [IFLA_VF_TX_RATE] = { .type = NLA_BINARY, | ||
| 821 | .len = sizeof(struct ifla_vf_tx_rate) }, | ||
| 822 | }; | ||
| 823 | |||
| 824 | struct net *rtnl_link_get_net(struct net *src_net, struct nlattr *tb[]) | ||
| 825 | { | ||
| 826 | struct net *net; | ||
| 827 | /* Examine the link attributes and figure out which | ||
| 828 | * network namespace we are talking about. | ||
| 829 | */ | ||
| 830 | if (tb[IFLA_NET_NS_PID]) | ||
| 831 | net = get_net_ns_by_pid(nla_get_u32(tb[IFLA_NET_NS_PID])); | ||
| 832 | else | ||
| 833 | net = get_net(src_net); | ||
| 834 | return net; | ||
| 835 | } | ||
| 836 | EXPORT_SYMBOL(rtnl_link_get_net); | ||
| 837 | |||
| 726 | static int validate_linkmsg(struct net_device *dev, struct nlattr *tb[]) | 838 | static int validate_linkmsg(struct net_device *dev, struct nlattr *tb[]) |
| 727 | { | 839 | { |
| 728 | if (dev) { | 840 | if (dev) { |
| @@ -738,6 +850,52 @@ static int validate_linkmsg(struct net_device *dev, struct nlattr *tb[]) | |||
| 738 | return 0; | 850 | return 0; |
| 739 | } | 851 | } |
| 740 | 852 | ||
| 853 | static int do_setvfinfo(struct net_device *dev, struct nlattr *attr) | ||
| 854 | { | ||
| 855 | int rem, err = -EINVAL; | ||
| 856 | struct nlattr *vf; | ||
| 857 | const struct net_device_ops *ops = dev->netdev_ops; | ||
| 858 | |||
| 859 | nla_for_each_nested(vf, attr, rem) { | ||
| 860 | switch (nla_type(vf)) { | ||
| 861 | case IFLA_VF_MAC: { | ||
| 862 | struct ifla_vf_mac *ivm; | ||
| 863 | ivm = nla_data(vf); | ||
| 864 | err = -EOPNOTSUPP; | ||
| 865 | if (ops->ndo_set_vf_mac) | ||
| 866 | err = ops->ndo_set_vf_mac(dev, ivm->vf, | ||
| 867 | ivm->mac); | ||
| 868 | break; | ||
| 869 | } | ||
| 870 | case IFLA_VF_VLAN: { | ||
| 871 | struct ifla_vf_vlan *ivv; | ||
| 872 | ivv = nla_data(vf); | ||
| 873 | err = -EOPNOTSUPP; | ||
| 874 | if (ops->ndo_set_vf_vlan) | ||
| 875 | err = ops->ndo_set_vf_vlan(dev, ivv->vf, | ||
| 876 | ivv->vlan, | ||
| 877 | ivv->qos); | ||
| 878 | break; | ||
| 879 | } | ||
| 880 | case IFLA_VF_TX_RATE: { | ||
| 881 | struct ifla_vf_tx_rate *ivt; | ||
| 882 | ivt = nla_data(vf); | ||
| 883 | err = -EOPNOTSUPP; | ||
| 884 | if (ops->ndo_set_vf_tx_rate) | ||
| 885 | err = ops->ndo_set_vf_tx_rate(dev, ivt->vf, | ||
| 886 | ivt->rate); | ||
| 887 | break; | ||
| 888 | } | ||
| 889 | default: | ||
| 890 | err = -EINVAL; | ||
| 891 | break; | ||
| 892 | } | ||
| 893 | if (err) | ||
| 894 | break; | ||
| 895 | } | ||
| 896 | return err; | ||
| 897 | } | ||
| 898 | |||
| 741 | static int do_setlink(struct net_device *dev, struct ifinfomsg *ifm, | 899 | static int do_setlink(struct net_device *dev, struct ifinfomsg *ifm, |
| 742 | struct nlattr **tb, char *ifname, int modified) | 900 | struct nlattr **tb, char *ifname, int modified) |
| 743 | { | 901 | { |
| @@ -746,8 +904,7 @@ static int do_setlink(struct net_device *dev, struct ifinfomsg *ifm, | |||
| 746 | int err; | 904 | int err; |
| 747 | 905 | ||
| 748 | if (tb[IFLA_NET_NS_PID]) { | 906 | if (tb[IFLA_NET_NS_PID]) { |
| 749 | struct net *net; | 907 | struct net *net = rtnl_link_get_net(dev_net(dev), tb); |
| 750 | net = get_net_ns_by_pid(nla_get_u32(tb[IFLA_NET_NS_PID])); | ||
| 751 | if (IS_ERR(net)) { | 908 | if (IS_ERR(net)) { |
| 752 | err = PTR_ERR(net); | 909 | err = PTR_ERR(net); |
| 753 | goto errout; | 910 | goto errout; |
| @@ -852,13 +1009,7 @@ static int do_setlink(struct net_device *dev, struct ifinfomsg *ifm, | |||
| 852 | } | 1009 | } |
| 853 | 1010 | ||
| 854 | if (ifm->ifi_flags || ifm->ifi_change) { | 1011 | if (ifm->ifi_flags || ifm->ifi_change) { |
| 855 | unsigned int flags = ifm->ifi_flags; | 1012 | err = dev_change_flags(dev, rtnl_dev_combine_flags(dev, ifm)); |
| 856 | |||
| 857 | /* bugwards compatibility: ifi_change == 0 is treated as ~0 */ | ||
| 858 | if (ifm->ifi_change) | ||
| 859 | flags = (flags & ifm->ifi_change) | | ||
| 860 | (dev->flags & ~ifm->ifi_change); | ||
| 861 | err = dev_change_flags(dev, flags); | ||
| 862 | if (err < 0) | 1013 | if (err < 0) |
| 863 | goto errout; | 1014 | goto errout; |
| 864 | } | 1015 | } |
| @@ -875,6 +1026,18 @@ static int do_setlink(struct net_device *dev, struct ifinfomsg *ifm, | |||
| 875 | write_unlock_bh(&dev_base_lock); | 1026 | write_unlock_bh(&dev_base_lock); |
| 876 | } | 1027 | } |
| 877 | 1028 | ||
| 1029 | if (tb[IFLA_VFINFO_LIST]) { | ||
| 1030 | struct nlattr *attr; | ||
| 1031 | int rem; | ||
| 1032 | nla_for_each_nested(attr, tb[IFLA_VFINFO_LIST], rem) { | ||
| 1033 | if (nla_type(attr) != IFLA_VF_INFO) | ||
| 1034 | goto errout; | ||
| 1035 | err = do_setvfinfo(dev, attr); | ||
| 1036 | if (err < 0) | ||
| 1037 | goto errout; | ||
| 1038 | modified = 1; | ||
| 1039 | } | ||
| 1040 | } | ||
| 878 | err = 0; | 1041 | err = 0; |
| 879 | 1042 | ||
| 880 | errout: | 1043 | errout: |
| @@ -910,9 +1073,9 @@ static int rtnl_setlink(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) | |||
| 910 | err = -EINVAL; | 1073 | err = -EINVAL; |
| 911 | ifm = nlmsg_data(nlh); | 1074 | ifm = nlmsg_data(nlh); |
| 912 | if (ifm->ifi_index > 0) | 1075 | if (ifm->ifi_index > 0) |
| 913 | dev = dev_get_by_index(net, ifm->ifi_index); | 1076 | dev = __dev_get_by_index(net, ifm->ifi_index); |
| 914 | else if (tb[IFLA_IFNAME]) | 1077 | else if (tb[IFLA_IFNAME]) |
| 915 | dev = dev_get_by_name(net, ifname); | 1078 | dev = __dev_get_by_name(net, ifname); |
| 916 | else | 1079 | else |
| 917 | goto errout; | 1080 | goto errout; |
| 918 | 1081 | ||
| @@ -921,12 +1084,11 @@ static int rtnl_setlink(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) | |||
| 921 | goto errout; | 1084 | goto errout; |
| 922 | } | 1085 | } |
| 923 | 1086 | ||
| 924 | if ((err = validate_linkmsg(dev, tb)) < 0) | 1087 | err = validate_linkmsg(dev, tb); |
| 925 | goto errout_dev; | 1088 | if (err < 0) |
| 1089 | goto errout; | ||
| 926 | 1090 | ||
| 927 | err = do_setlink(dev, ifm, tb, ifname, 0); | 1091 | err = do_setlink(dev, ifm, tb, ifname, 0); |
| 928 | errout_dev: | ||
| 929 | dev_put(dev); | ||
| 930 | errout: | 1092 | errout: |
| 931 | return err; | 1093 | return err; |
| 932 | } | 1094 | } |
| @@ -963,12 +1125,32 @@ static int rtnl_dellink(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) | |||
| 963 | if (!ops) | 1125 | if (!ops) |
| 964 | return -EOPNOTSUPP; | 1126 | return -EOPNOTSUPP; |
| 965 | 1127 | ||
| 966 | ops->dellink(dev); | 1128 | ops->dellink(dev, NULL); |
| 967 | return 0; | 1129 | return 0; |
| 968 | } | 1130 | } |
| 969 | 1131 | ||
| 970 | struct net_device *rtnl_create_link(struct net *net, char *ifname, | 1132 | int rtnl_configure_link(struct net_device *dev, const struct ifinfomsg *ifm) |
| 971 | const struct rtnl_link_ops *ops, struct nlattr *tb[]) | 1133 | { |
| 1134 | unsigned int old_flags; | ||
| 1135 | int err; | ||
| 1136 | |||
| 1137 | old_flags = dev->flags; | ||
| 1138 | if (ifm && (ifm->ifi_flags || ifm->ifi_change)) { | ||
| 1139 | err = __dev_change_flags(dev, rtnl_dev_combine_flags(dev, ifm)); | ||
| 1140 | if (err < 0) | ||
| 1141 | return err; | ||
| 1142 | } | ||
| 1143 | |||
| 1144 | dev->rtnl_link_state = RTNL_LINK_INITIALIZED; | ||
| 1145 | rtmsg_ifinfo(RTM_NEWLINK, dev, ~0U); | ||
| 1146 | |||
| 1147 | __dev_notify_flags(dev, old_flags); | ||
| 1148 | return 0; | ||
| 1149 | } | ||
| 1150 | EXPORT_SYMBOL(rtnl_configure_link); | ||
| 1151 | |||
| 1152 | struct net_device *rtnl_create_link(struct net *src_net, struct net *net, | ||
| 1153 | char *ifname, const struct rtnl_link_ops *ops, struct nlattr *tb[]) | ||
| 972 | { | 1154 | { |
| 973 | int err; | 1155 | int err; |
| 974 | struct net_device *dev; | 1156 | struct net_device *dev; |
| @@ -976,7 +1158,8 @@ struct net_device *rtnl_create_link(struct net *net, char *ifname, | |||
| 976 | unsigned int real_num_queues = 1; | 1158 | unsigned int real_num_queues = 1; |
| 977 | 1159 | ||
| 978 | if (ops->get_tx_queues) { | 1160 | if (ops->get_tx_queues) { |
| 979 | err = ops->get_tx_queues(net, tb, &num_queues, &real_num_queues); | 1161 | err = ops->get_tx_queues(src_net, tb, &num_queues, |
| 1162 | &real_num_queues); | ||
| 980 | if (err) | 1163 | if (err) |
| 981 | goto err; | 1164 | goto err; |
| 982 | } | 1165 | } |
| @@ -985,16 +1168,17 @@ struct net_device *rtnl_create_link(struct net *net, char *ifname, | |||
| 985 | if (!dev) | 1168 | if (!dev) |
| 986 | goto err; | 1169 | goto err; |
| 987 | 1170 | ||
| 1171 | dev_net_set(dev, net); | ||
| 1172 | dev->rtnl_link_ops = ops; | ||
| 1173 | dev->rtnl_link_state = RTNL_LINK_INITIALIZING; | ||
| 988 | dev->real_num_tx_queues = real_num_queues; | 1174 | dev->real_num_tx_queues = real_num_queues; |
| 1175 | |||
| 989 | if (strchr(dev->name, '%')) { | 1176 | if (strchr(dev->name, '%')) { |
| 990 | err = dev_alloc_name(dev, dev->name); | 1177 | err = dev_alloc_name(dev, dev->name); |
| 991 | if (err < 0) | 1178 | if (err < 0) |
| 992 | goto err_free; | 1179 | goto err_free; |
| 993 | } | 1180 | } |
| 994 | 1181 | ||
| 995 | dev_net_set(dev, net); | ||
| 996 | dev->rtnl_link_ops = ops; | ||
| 997 | |||
| 998 | if (tb[IFLA_MTU]) | 1182 | if (tb[IFLA_MTU]) |
| 999 | dev->mtu = nla_get_u32(tb[IFLA_MTU]); | 1183 | dev->mtu = nla_get_u32(tb[IFLA_MTU]); |
| 1000 | if (tb[IFLA_ADDRESS]) | 1184 | if (tb[IFLA_ADDRESS]) |
| @@ -1017,6 +1201,7 @@ err_free: | |||
| 1017 | err: | 1201 | err: |
| 1018 | return ERR_PTR(err); | 1202 | return ERR_PTR(err); |
| 1019 | } | 1203 | } |
| 1204 | EXPORT_SYMBOL(rtnl_create_link); | ||
| 1020 | 1205 | ||
| 1021 | static int rtnl_newlink(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) | 1206 | static int rtnl_newlink(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) |
| 1022 | { | 1207 | { |
| @@ -1050,7 +1235,8 @@ replay: | |||
| 1050 | else | 1235 | else |
| 1051 | dev = NULL; | 1236 | dev = NULL; |
| 1052 | 1237 | ||
| 1053 | if ((err = validate_linkmsg(dev, tb)) < 0) | 1238 | err = validate_linkmsg(dev, tb); |
| 1239 | if (err < 0) | ||
| 1054 | return err; | 1240 | return err; |
| 1055 | 1241 | ||
| 1056 | if (tb[IFLA_LINKINFO]) { | 1242 | if (tb[IFLA_LINKINFO]) { |
| @@ -1071,6 +1257,7 @@ replay: | |||
| 1071 | 1257 | ||
| 1072 | if (1) { | 1258 | if (1) { |
| 1073 | struct nlattr *attr[ops ? ops->maxtype + 1 : 0], **data = NULL; | 1259 | struct nlattr *attr[ops ? ops->maxtype + 1 : 0], **data = NULL; |
| 1260 | struct net *dest_net; | ||
| 1074 | 1261 | ||
| 1075 | if (ops) { | 1262 | if (ops) { |
| 1076 | if (ops->maxtype && linkinfo[IFLA_INFO_DATA]) { | 1263 | if (ops->maxtype && linkinfo[IFLA_INFO_DATA]) { |
| @@ -1113,7 +1300,7 @@ replay: | |||
| 1113 | if (!(nlh->nlmsg_flags & NLM_F_CREATE)) | 1300 | if (!(nlh->nlmsg_flags & NLM_F_CREATE)) |
| 1114 | return -ENODEV; | 1301 | return -ENODEV; |
| 1115 | 1302 | ||
| 1116 | if (ifm->ifi_index || ifm->ifi_flags || ifm->ifi_change) | 1303 | if (ifm->ifi_index) |
| 1117 | return -EOPNOTSUPP; | 1304 | return -EOPNOTSUPP; |
| 1118 | if (tb[IFLA_MAP] || tb[IFLA_MASTER] || tb[IFLA_PROTINFO]) | 1305 | if (tb[IFLA_MAP] || tb[IFLA_MASTER] || tb[IFLA_PROTINFO]) |
| 1119 | return -EOPNOTSUPP; | 1306 | return -EOPNOTSUPP; |
| @@ -1135,17 +1322,26 @@ replay: | |||
| 1135 | if (!ifname[0]) | 1322 | if (!ifname[0]) |
| 1136 | snprintf(ifname, IFNAMSIZ, "%s%%d", ops->kind); | 1323 | snprintf(ifname, IFNAMSIZ, "%s%%d", ops->kind); |
| 1137 | 1324 | ||
| 1138 | dev = rtnl_create_link(net, ifname, ops, tb); | 1325 | dest_net = rtnl_link_get_net(net, tb); |
| 1326 | dev = rtnl_create_link(net, dest_net, ifname, ops, tb); | ||
| 1139 | 1327 | ||
| 1140 | if (IS_ERR(dev)) | 1328 | if (IS_ERR(dev)) |
| 1141 | err = PTR_ERR(dev); | 1329 | err = PTR_ERR(dev); |
| 1142 | else if (ops->newlink) | 1330 | else if (ops->newlink) |
| 1143 | err = ops->newlink(dev, tb, data); | 1331 | err = ops->newlink(net, dev, tb, data); |
| 1144 | else | 1332 | else |
| 1145 | err = register_netdevice(dev); | 1333 | err = register_netdevice(dev); |
| 1146 | 1334 | ||
| 1147 | if (err < 0 && !IS_ERR(dev)) | 1335 | if (err < 0 && !IS_ERR(dev)) |
| 1148 | free_netdev(dev); | 1336 | free_netdev(dev); |
| 1337 | if (err < 0) | ||
| 1338 | goto out; | ||
| 1339 | |||
| 1340 | err = rtnl_configure_link(dev, ifm); | ||
| 1341 | if (err < 0) | ||
| 1342 | unregister_netdevice(dev); | ||
| 1343 | out: | ||
| 1344 | put_net(dest_net); | ||
| 1149 | return err; | 1345 | return err; |
| 1150 | } | 1346 | } |
| 1151 | } | 1347 | } |
| @@ -1154,6 +1350,7 @@ static int rtnl_getlink(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg) | |||
| 1154 | { | 1350 | { |
| 1155 | struct net *net = sock_net(skb->sk); | 1351 | struct net *net = sock_net(skb->sk); |
| 1156 | struct ifinfomsg *ifm; | 1352 | struct ifinfomsg *ifm; |
| 1353 | char ifname[IFNAMSIZ]; | ||
| 1157 | struct nlattr *tb[IFLA_MAX+1]; | 1354 | struct nlattr *tb[IFLA_MAX+1]; |
| 1158 | struct net_device *dev = NULL; | 1355 | struct net_device *dev = NULL; |
| 1159 | struct sk_buff *nskb; | 1356 | struct sk_buff *nskb; |
| @@ -1163,19 +1360,23 @@ static int rtnl_getlink(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg) | |||
| 1163 | if (err < 0) | 1360 | if (err < 0) |
| 1164 | return err; | 1361 | return err; |
| 1165 | 1362 | ||
| 1363 | if (tb[IFLA_IFNAME]) | ||
| 1364 | nla_strlcpy(ifname, tb[IFLA_IFNAME], IFNAMSIZ); | ||
| 1365 | |||
| 1166 | ifm = nlmsg_data(nlh); | 1366 | ifm = nlmsg_data(nlh); |
| 1167 | if (ifm->ifi_index > 0) { | 1367 | if (ifm->ifi_index > 0) |
| 1168 | dev = dev_get_by_index(net, ifm->ifi_index); | 1368 | dev = __dev_get_by_index(net, ifm->ifi_index); |
| 1169 | if (dev == NULL) | 1369 | else if (tb[IFLA_IFNAME]) |
| 1170 | return -ENODEV; | 1370 | dev = __dev_get_by_name(net, ifname); |
| 1171 | } else | 1371 | else |
| 1172 | return -EINVAL; | 1372 | return -EINVAL; |
| 1173 | 1373 | ||
| 1374 | if (dev == NULL) | ||
| 1375 | return -ENODEV; | ||
| 1376 | |||
| 1174 | nskb = nlmsg_new(if_nlmsg_size(dev), GFP_KERNEL); | 1377 | nskb = nlmsg_new(if_nlmsg_size(dev), GFP_KERNEL); |
| 1175 | if (nskb == NULL) { | 1378 | if (nskb == NULL) |
| 1176 | err = -ENOBUFS; | 1379 | return -ENOBUFS; |
| 1177 | goto errout; | ||
| 1178 | } | ||
| 1179 | 1380 | ||
| 1180 | err = rtnl_fill_ifinfo(nskb, dev, RTM_NEWLINK, NETLINK_CB(skb).pid, | 1381 | err = rtnl_fill_ifinfo(nskb, dev, RTM_NEWLINK, NETLINK_CB(skb).pid, |
| 1181 | nlh->nlmsg_seq, 0, 0); | 1382 | nlh->nlmsg_seq, 0, 0); |
| @@ -1183,11 +1384,8 @@ static int rtnl_getlink(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg) | |||
| 1183 | /* -EMSGSIZE implies BUG in if_nlmsg_size */ | 1384 | /* -EMSGSIZE implies BUG in if_nlmsg_size */ |
| 1184 | WARN_ON(err == -EMSGSIZE); | 1385 | WARN_ON(err == -EMSGSIZE); |
| 1185 | kfree_skb(nskb); | 1386 | kfree_skb(nskb); |
| 1186 | goto errout; | 1387 | } else |
| 1187 | } | 1388 | err = rtnl_unicast(nskb, net, NETLINK_CB(skb).pid); |
| 1188 | err = rtnl_unicast(nskb, net, NETLINK_CB(skb).pid); | ||
| 1189 | errout: | ||
| 1190 | dev_put(dev); | ||
| 1191 | 1389 | ||
| 1192 | return err; | 1390 | return err; |
| 1193 | } | 1391 | } |
| @@ -1199,7 +1397,7 @@ static int rtnl_dump_all(struct sk_buff *skb, struct netlink_callback *cb) | |||
| 1199 | 1397 | ||
| 1200 | if (s_idx == 0) | 1398 | if (s_idx == 0) |
| 1201 | s_idx = 1; | 1399 | s_idx = 1; |
| 1202 | for (idx=1; idx<NPROTO; idx++) { | 1400 | for (idx = 1; idx < NPROTO; idx++) { |
| 1203 | int type = cb->nlh->nlmsg_type-RTM_BASE; | 1401 | int type = cb->nlh->nlmsg_type-RTM_BASE; |
| 1204 | if (idx < s_idx || idx == PF_PACKET) | 1402 | if (idx < s_idx || idx == PF_PACKET) |
| 1205 | continue; | 1403 | continue; |
| @@ -1266,7 +1464,7 @@ static int rtnetlink_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) | |||
| 1266 | if (nlh->nlmsg_len < NLMSG_LENGTH(sizeof(struct rtgenmsg))) | 1464 | if (nlh->nlmsg_len < NLMSG_LENGTH(sizeof(struct rtgenmsg))) |
| 1267 | return 0; | 1465 | return 0; |
| 1268 | 1466 | ||
| 1269 | family = ((struct rtgenmsg*)NLMSG_DATA(nlh))->rtgen_family; | 1467 | family = ((struct rtgenmsg *)NLMSG_DATA(nlh))->rtgen_family; |
| 1270 | if (family >= NPROTO) | 1468 | if (family >= NPROTO) |
| 1271 | return -EAFNOSUPPORT; | 1469 | return -EAFNOSUPPORT; |
| 1272 | 1470 | ||
| @@ -1299,7 +1497,7 @@ static int rtnetlink_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) | |||
| 1299 | 1497 | ||
| 1300 | if (nlh->nlmsg_len > min_len) { | 1498 | if (nlh->nlmsg_len > min_len) { |
| 1301 | int attrlen = nlh->nlmsg_len - NLMSG_ALIGN(min_len); | 1499 | int attrlen = nlh->nlmsg_len - NLMSG_ALIGN(min_len); |
| 1302 | struct rtattr *attr = (void*)nlh + NLMSG_ALIGN(min_len); | 1500 | struct rtattr *attr = (void *)nlh + NLMSG_ALIGN(min_len); |
| 1303 | 1501 | ||
| 1304 | while (RTA_OK(attr, attrlen)) { | 1502 | while (RTA_OK(attr, attrlen)) { |
| 1305 | unsigned flavor = attr->rta_type; | 1503 | unsigned flavor = attr->rta_type; |
| @@ -1331,18 +1529,15 @@ static int rtnetlink_event(struct notifier_block *this, unsigned long event, voi | |||
| 1331 | struct net_device *dev = ptr; | 1529 | struct net_device *dev = ptr; |
| 1332 | 1530 | ||
| 1333 | switch (event) { | 1531 | switch (event) { |
| 1334 | case NETDEV_UNREGISTER: | ||
| 1335 | rtmsg_ifinfo(RTM_DELLINK, dev, ~0U); | ||
| 1336 | break; | ||
| 1337 | case NETDEV_REGISTER: | ||
| 1338 | rtmsg_ifinfo(RTM_NEWLINK, dev, ~0U); | ||
| 1339 | break; | ||
| 1340 | case NETDEV_UP: | 1532 | case NETDEV_UP: |
| 1341 | case NETDEV_DOWN: | 1533 | case NETDEV_DOWN: |
| 1342 | rtmsg_ifinfo(RTM_NEWLINK, dev, IFF_UP|IFF_RUNNING); | 1534 | case NETDEV_PRE_UP: |
| 1343 | break; | 1535 | case NETDEV_POST_INIT: |
| 1536 | case NETDEV_REGISTER: | ||
| 1344 | case NETDEV_CHANGE: | 1537 | case NETDEV_CHANGE: |
| 1345 | case NETDEV_GOING_DOWN: | 1538 | case NETDEV_GOING_DOWN: |
| 1539 | case NETDEV_UNREGISTER: | ||
| 1540 | case NETDEV_UNREGISTER_BATCH: | ||
| 1346 | break; | 1541 | break; |
| 1347 | default: | 1542 | default: |
| 1348 | rtmsg_ifinfo(RTM_NEWLINK, dev, 0); | 1543 | rtmsg_ifinfo(RTM_NEWLINK, dev, 0); |
| @@ -1356,7 +1551,7 @@ static struct notifier_block rtnetlink_dev_notifier = { | |||
| 1356 | }; | 1551 | }; |
| 1357 | 1552 | ||
| 1358 | 1553 | ||
| 1359 | static int rtnetlink_net_init(struct net *net) | 1554 | static int __net_init rtnetlink_net_init(struct net *net) |
| 1360 | { | 1555 | { |
| 1361 | struct sock *sk; | 1556 | struct sock *sk; |
| 1362 | sk = netlink_kernel_create(net, NETLINK_ROUTE, RTNLGRP_MAX, | 1557 | sk = netlink_kernel_create(net, NETLINK_ROUTE, RTNLGRP_MAX, |
| @@ -1367,7 +1562,7 @@ static int rtnetlink_net_init(struct net *net) | |||
| 1367 | return 0; | 1562 | return 0; |
| 1368 | } | 1563 | } |
| 1369 | 1564 | ||
| 1370 | static void rtnetlink_net_exit(struct net *net) | 1565 | static void __net_exit rtnetlink_net_exit(struct net *net) |
| 1371 | { | 1566 | { |
| 1372 | netlink_kernel_release(net->rtnl); | 1567 | netlink_kernel_release(net->rtnl); |
| 1373 | net->rtnl = NULL; | 1568 | net->rtnl = NULL; |
| @@ -1405,14 +1600,3 @@ void __init rtnetlink_init(void) | |||
| 1405 | rtnl_register(PF_UNSPEC, RTM_GETROUTE, NULL, rtnl_dump_all); | 1600 | rtnl_register(PF_UNSPEC, RTM_GETROUTE, NULL, rtnl_dump_all); |
| 1406 | } | 1601 | } |
| 1407 | 1602 | ||
| 1408 | EXPORT_SYMBOL(__rta_fill); | ||
| 1409 | EXPORT_SYMBOL(rtnetlink_put_metrics); | ||
| 1410 | EXPORT_SYMBOL(rtnl_lock); | ||
| 1411 | EXPORT_SYMBOL(rtnl_trylock); | ||
| 1412 | EXPORT_SYMBOL(rtnl_unlock); | ||
| 1413 | EXPORT_SYMBOL(rtnl_is_locked); | ||
| 1414 | EXPORT_SYMBOL(rtnl_unicast); | ||
| 1415 | EXPORT_SYMBOL(rtnl_notify); | ||
| 1416 | EXPORT_SYMBOL(rtnl_set_sk_err); | ||
| 1417 | EXPORT_SYMBOL(rtnl_create_link); | ||
| 1418 | EXPORT_SYMBOL(ifla_policy); | ||
