diff options
Diffstat (limited to 'net/core/rtnetlink.c')
-rw-r--r-- | net/core/rtnetlink.c | 205 |
1 files changed, 157 insertions, 48 deletions
diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index cf67144d3e3c..120eecc0f5a4 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c | |||
@@ -365,6 +365,22 @@ void rtnl_link_unregister(struct rtnl_link_ops *ops) | |||
365 | } | 365 | } |
366 | EXPORT_SYMBOL_GPL(rtnl_link_unregister); | 366 | EXPORT_SYMBOL_GPL(rtnl_link_unregister); |
367 | 367 | ||
368 | static size_t rtnl_link_get_slave_info_data_size(const struct net_device *dev) | ||
369 | { | ||
370 | struct net_device *master_dev; | ||
371 | const struct rtnl_link_ops *ops; | ||
372 | |||
373 | master_dev = netdev_master_upper_dev_get((struct net_device *) dev); | ||
374 | if (!master_dev) | ||
375 | return 0; | ||
376 | ops = master_dev->rtnl_link_ops; | ||
377 | if (!ops || !ops->get_slave_size) | ||
378 | return 0; | ||
379 | /* IFLA_INFO_SLAVE_DATA + nested data */ | ||
380 | return nla_total_size(sizeof(struct nlattr)) + | ||
381 | ops->get_slave_size(master_dev, dev); | ||
382 | } | ||
383 | |||
368 | static size_t rtnl_link_get_size(const struct net_device *dev) | 384 | static size_t rtnl_link_get_size(const struct net_device *dev) |
369 | { | 385 | { |
370 | const struct rtnl_link_ops *ops = dev->rtnl_link_ops; | 386 | const struct rtnl_link_ops *ops = dev->rtnl_link_ops; |
@@ -385,6 +401,8 @@ static size_t rtnl_link_get_size(const struct net_device *dev) | |||
385 | /* IFLA_INFO_XSTATS */ | 401 | /* IFLA_INFO_XSTATS */ |
386 | size += nla_total_size(ops->get_xstats_size(dev)); | 402 | size += nla_total_size(ops->get_xstats_size(dev)); |
387 | 403 | ||
404 | size += rtnl_link_get_slave_info_data_size(dev); | ||
405 | |||
388 | return size; | 406 | return size; |
389 | } | 407 | } |
390 | 408 | ||
@@ -403,34 +421,16 @@ static const struct rtnl_af_ops *rtnl_af_lookup(const int family) | |||
403 | } | 421 | } |
404 | 422 | ||
405 | /** | 423 | /** |
406 | * __rtnl_af_register - Register rtnl_af_ops with rtnetlink. | ||
407 | * @ops: struct rtnl_af_ops * to register | ||
408 | * | ||
409 | * The caller must hold the rtnl_mutex. | ||
410 | * | ||
411 | * Returns 0 on success or a negative error code. | ||
412 | */ | ||
413 | int __rtnl_af_register(struct rtnl_af_ops *ops) | ||
414 | { | ||
415 | list_add_tail(&ops->list, &rtnl_af_ops); | ||
416 | return 0; | ||
417 | } | ||
418 | EXPORT_SYMBOL_GPL(__rtnl_af_register); | ||
419 | |||
420 | /** | ||
421 | * rtnl_af_register - Register rtnl_af_ops with rtnetlink. | 424 | * rtnl_af_register - Register rtnl_af_ops with rtnetlink. |
422 | * @ops: struct rtnl_af_ops * to register | 425 | * @ops: struct rtnl_af_ops * to register |
423 | * | 426 | * |
424 | * Returns 0 on success or a negative error code. | 427 | * Returns 0 on success or a negative error code. |
425 | */ | 428 | */ |
426 | int rtnl_af_register(struct rtnl_af_ops *ops) | 429 | void rtnl_af_register(struct rtnl_af_ops *ops) |
427 | { | 430 | { |
428 | int err; | ||
429 | |||
430 | rtnl_lock(); | 431 | rtnl_lock(); |
431 | err = __rtnl_af_register(ops); | 432 | list_add_tail(&ops->list, &rtnl_af_ops); |
432 | rtnl_unlock(); | 433 | rtnl_unlock(); |
433 | return err; | ||
434 | } | 434 | } |
435 | EXPORT_SYMBOL_GPL(rtnl_af_register); | 435 | EXPORT_SYMBOL_GPL(rtnl_af_register); |
436 | 436 | ||
@@ -477,40 +477,100 @@ static size_t rtnl_link_get_af_size(const struct net_device *dev) | |||
477 | return size; | 477 | return size; |
478 | } | 478 | } |
479 | 479 | ||
480 | static int rtnl_link_fill(struct sk_buff *skb, const struct net_device *dev) | 480 | static bool rtnl_have_link_slave_info(const struct net_device *dev) |
481 | { | 481 | { |
482 | const struct rtnl_link_ops *ops = dev->rtnl_link_ops; | 482 | struct net_device *master_dev; |
483 | struct nlattr *linkinfo, *data; | ||
484 | int err = -EMSGSIZE; | ||
485 | 483 | ||
486 | linkinfo = nla_nest_start(skb, IFLA_LINKINFO); | 484 | master_dev = netdev_master_upper_dev_get((struct net_device *) dev); |
487 | if (linkinfo == NULL) | 485 | if (master_dev && master_dev->rtnl_link_ops) |
488 | goto out; | 486 | return true; |
487 | return false; | ||
488 | } | ||
489 | |||
490 | static int rtnl_link_slave_info_fill(struct sk_buff *skb, | ||
491 | const struct net_device *dev) | ||
492 | { | ||
493 | struct net_device *master_dev; | ||
494 | const struct rtnl_link_ops *ops; | ||
495 | struct nlattr *slave_data; | ||
496 | int err; | ||
497 | |||
498 | master_dev = netdev_master_upper_dev_get((struct net_device *) dev); | ||
499 | if (!master_dev) | ||
500 | return 0; | ||
501 | ops = master_dev->rtnl_link_ops; | ||
502 | if (!ops) | ||
503 | return 0; | ||
504 | if (nla_put_string(skb, IFLA_INFO_SLAVE_KIND, ops->kind) < 0) | ||
505 | return -EMSGSIZE; | ||
506 | if (ops->fill_slave_info) { | ||
507 | slave_data = nla_nest_start(skb, IFLA_INFO_SLAVE_DATA); | ||
508 | if (!slave_data) | ||
509 | return -EMSGSIZE; | ||
510 | err = ops->fill_slave_info(skb, master_dev, dev); | ||
511 | if (err < 0) | ||
512 | goto err_cancel_slave_data; | ||
513 | nla_nest_end(skb, slave_data); | ||
514 | } | ||
515 | return 0; | ||
489 | 516 | ||
517 | err_cancel_slave_data: | ||
518 | nla_nest_cancel(skb, slave_data); | ||
519 | return err; | ||
520 | } | ||
521 | |||
522 | static int rtnl_link_info_fill(struct sk_buff *skb, | ||
523 | const struct net_device *dev) | ||
524 | { | ||
525 | const struct rtnl_link_ops *ops = dev->rtnl_link_ops; | ||
526 | struct nlattr *data; | ||
527 | int err; | ||
528 | |||
529 | if (!ops) | ||
530 | return 0; | ||
490 | if (nla_put_string(skb, IFLA_INFO_KIND, ops->kind) < 0) | 531 | if (nla_put_string(skb, IFLA_INFO_KIND, ops->kind) < 0) |
491 | goto err_cancel_link; | 532 | return -EMSGSIZE; |
492 | if (ops->fill_xstats) { | 533 | if (ops->fill_xstats) { |
493 | err = ops->fill_xstats(skb, dev); | 534 | err = ops->fill_xstats(skb, dev); |
494 | if (err < 0) | 535 | if (err < 0) |
495 | goto err_cancel_link; | 536 | return err; |
496 | } | 537 | } |
497 | if (ops->fill_info) { | 538 | if (ops->fill_info) { |
498 | data = nla_nest_start(skb, IFLA_INFO_DATA); | 539 | data = nla_nest_start(skb, IFLA_INFO_DATA); |
499 | if (data == NULL) { | 540 | if (data == NULL) |
500 | err = -EMSGSIZE; | 541 | return -EMSGSIZE; |
501 | goto err_cancel_link; | ||
502 | } | ||
503 | err = ops->fill_info(skb, dev); | 542 | err = ops->fill_info(skb, dev); |
504 | if (err < 0) | 543 | if (err < 0) |
505 | goto err_cancel_data; | 544 | goto err_cancel_data; |
506 | nla_nest_end(skb, data); | 545 | nla_nest_end(skb, data); |
507 | } | 546 | } |
508 | |||
509 | nla_nest_end(skb, linkinfo); | ||
510 | return 0; | 547 | return 0; |
511 | 548 | ||
512 | err_cancel_data: | 549 | err_cancel_data: |
513 | nla_nest_cancel(skb, data); | 550 | nla_nest_cancel(skb, data); |
551 | return err; | ||
552 | } | ||
553 | |||
554 | static int rtnl_link_fill(struct sk_buff *skb, const struct net_device *dev) | ||
555 | { | ||
556 | struct nlattr *linkinfo; | ||
557 | int err = -EMSGSIZE; | ||
558 | |||
559 | linkinfo = nla_nest_start(skb, IFLA_LINKINFO); | ||
560 | if (linkinfo == NULL) | ||
561 | goto out; | ||
562 | |||
563 | err = rtnl_link_info_fill(skb, dev); | ||
564 | if (err < 0) | ||
565 | goto err_cancel_link; | ||
566 | |||
567 | err = rtnl_link_slave_info_fill(skb, dev); | ||
568 | if (err < 0) | ||
569 | goto err_cancel_link; | ||
570 | |||
571 | nla_nest_end(skb, linkinfo); | ||
572 | return 0; | ||
573 | |||
514 | err_cancel_link: | 574 | err_cancel_link: |
515 | nla_nest_cancel(skb, linkinfo); | 575 | nla_nest_cancel(skb, linkinfo); |
516 | out: | 576 | out: |
@@ -1019,7 +1079,7 @@ static int rtnl_fill_ifinfo(struct sk_buff *skb, struct net_device *dev, | |||
1019 | if (rtnl_port_fill(skb, dev)) | 1079 | if (rtnl_port_fill(skb, dev)) |
1020 | goto nla_put_failure; | 1080 | goto nla_put_failure; |
1021 | 1081 | ||
1022 | if (dev->rtnl_link_ops) { | 1082 | if (dev->rtnl_link_ops || rtnl_have_link_slave_info(dev)) { |
1023 | if (rtnl_link_fill(skb, dev) < 0) | 1083 | if (rtnl_link_fill(skb, dev) < 0) |
1024 | goto nla_put_failure; | 1084 | goto nla_put_failure; |
1025 | } | 1085 | } |
@@ -1142,6 +1202,8 @@ EXPORT_SYMBOL(ifla_policy); | |||
1142 | static const struct nla_policy ifla_info_policy[IFLA_INFO_MAX+1] = { | 1202 | static const struct nla_policy ifla_info_policy[IFLA_INFO_MAX+1] = { |
1143 | [IFLA_INFO_KIND] = { .type = NLA_STRING }, | 1203 | [IFLA_INFO_KIND] = { .type = NLA_STRING }, |
1144 | [IFLA_INFO_DATA] = { .type = NLA_NESTED }, | 1204 | [IFLA_INFO_DATA] = { .type = NLA_NESTED }, |
1205 | [IFLA_INFO_SLAVE_KIND] = { .type = NLA_STRING }, | ||
1206 | [IFLA_INFO_SLAVE_DATA] = { .type = NLA_NESTED }, | ||
1145 | }; | 1207 | }; |
1146 | 1208 | ||
1147 | static const struct nla_policy ifla_vfinfo_policy[IFLA_VF_INFO_MAX+1] = { | 1209 | static const struct nla_policy ifla_vfinfo_policy[IFLA_VF_INFO_MAX+1] = { |
@@ -1729,7 +1791,9 @@ static int rtnl_newlink(struct sk_buff *skb, struct nlmsghdr *nlh) | |||
1729 | { | 1791 | { |
1730 | struct net *net = sock_net(skb->sk); | 1792 | struct net *net = sock_net(skb->sk); |
1731 | const struct rtnl_link_ops *ops; | 1793 | const struct rtnl_link_ops *ops; |
1794 | const struct rtnl_link_ops *m_ops = NULL; | ||
1732 | struct net_device *dev; | 1795 | struct net_device *dev; |
1796 | struct net_device *master_dev = NULL; | ||
1733 | struct ifinfomsg *ifm; | 1797 | struct ifinfomsg *ifm; |
1734 | char kind[MODULE_NAME_LEN]; | 1798 | char kind[MODULE_NAME_LEN]; |
1735 | char ifname[IFNAMSIZ]; | 1799 | char ifname[IFNAMSIZ]; |
@@ -1759,6 +1823,12 @@ replay: | |||
1759 | dev = NULL; | 1823 | dev = NULL; |
1760 | } | 1824 | } |
1761 | 1825 | ||
1826 | if (dev) { | ||
1827 | master_dev = netdev_master_upper_dev_get(dev); | ||
1828 | if (master_dev) | ||
1829 | m_ops = master_dev->rtnl_link_ops; | ||
1830 | } | ||
1831 | |||
1762 | err = validate_linkmsg(dev, tb); | 1832 | err = validate_linkmsg(dev, tb); |
1763 | if (err < 0) | 1833 | if (err < 0) |
1764 | return err; | 1834 | return err; |
@@ -1780,7 +1850,10 @@ replay: | |||
1780 | } | 1850 | } |
1781 | 1851 | ||
1782 | if (1) { | 1852 | if (1) { |
1783 | struct nlattr *attr[ops ? ops->maxtype + 1 : 0], **data = NULL; | 1853 | struct nlattr *attr[ops ? ops->maxtype + 1 : 0]; |
1854 | struct nlattr *slave_attr[m_ops ? m_ops->slave_maxtype + 1 : 0]; | ||
1855 | struct nlattr **data = NULL; | ||
1856 | struct nlattr **slave_data = NULL; | ||
1784 | struct net *dest_net; | 1857 | struct net *dest_net; |
1785 | 1858 | ||
1786 | if (ops) { | 1859 | if (ops) { |
@@ -1799,6 +1872,24 @@ replay: | |||
1799 | } | 1872 | } |
1800 | } | 1873 | } |
1801 | 1874 | ||
1875 | if (m_ops) { | ||
1876 | if (m_ops->slave_maxtype && | ||
1877 | linkinfo[IFLA_INFO_SLAVE_DATA]) { | ||
1878 | err = nla_parse_nested(slave_attr, | ||
1879 | m_ops->slave_maxtype, | ||
1880 | linkinfo[IFLA_INFO_SLAVE_DATA], | ||
1881 | m_ops->slave_policy); | ||
1882 | if (err < 0) | ||
1883 | return err; | ||
1884 | slave_data = slave_attr; | ||
1885 | } | ||
1886 | if (m_ops->slave_validate) { | ||
1887 | err = m_ops->slave_validate(tb, slave_data); | ||
1888 | if (err < 0) | ||
1889 | return err; | ||
1890 | } | ||
1891 | } | ||
1892 | |||
1802 | if (dev) { | 1893 | if (dev) { |
1803 | int modified = 0; | 1894 | int modified = 0; |
1804 | 1895 | ||
@@ -1818,6 +1909,17 @@ replay: | |||
1818 | modified = 1; | 1909 | modified = 1; |
1819 | } | 1910 | } |
1820 | 1911 | ||
1912 | if (linkinfo[IFLA_INFO_SLAVE_DATA]) { | ||
1913 | if (!m_ops || !m_ops->slave_changelink) | ||
1914 | return -EOPNOTSUPP; | ||
1915 | |||
1916 | err = m_ops->slave_changelink(master_dev, dev, | ||
1917 | tb, slave_data); | ||
1918 | if (err < 0) | ||
1919 | return err; | ||
1920 | modified = 1; | ||
1921 | } | ||
1922 | |||
1821 | return do_setlink(dev, ifm, tb, ifname, modified); | 1923 | return do_setlink(dev, ifm, tb, ifname, modified); |
1822 | } | 1924 | } |
1823 | 1925 | ||
@@ -1861,16 +1963,21 @@ replay: | |||
1861 | 1963 | ||
1862 | dev->ifindex = ifm->ifi_index; | 1964 | dev->ifindex = ifm->ifi_index; |
1863 | 1965 | ||
1864 | if (ops->newlink) | 1966 | if (ops->newlink) { |
1865 | err = ops->newlink(net, dev, tb, data); | 1967 | err = ops->newlink(net, dev, tb, data); |
1866 | else | 1968 | /* Drivers should call free_netdev() in ->destructor |
1969 | * and unregister it on failure so that device could be | ||
1970 | * finally freed in rtnl_unlock. | ||
1971 | */ | ||
1972 | if (err < 0) | ||
1973 | goto out; | ||
1974 | } else { | ||
1867 | err = register_netdevice(dev); | 1975 | err = register_netdevice(dev); |
1868 | 1976 | if (err < 0) { | |
1869 | if (err < 0) { | 1977 | free_netdev(dev); |
1870 | free_netdev(dev); | 1978 | goto out; |
1871 | goto out; | 1979 | } |
1872 | } | 1980 | } |
1873 | |||
1874 | err = rtnl_configure_link(dev, ifm); | 1981 | err = rtnl_configure_link(dev, ifm); |
1875 | if (err < 0) | 1982 | if (err < 0) |
1876 | unregister_netdevice(dev); | 1983 | unregister_netdevice(dev); |
@@ -2014,12 +2121,13 @@ EXPORT_SYMBOL(rtmsg_ifinfo); | |||
2014 | static int nlmsg_populate_fdb_fill(struct sk_buff *skb, | 2121 | static int nlmsg_populate_fdb_fill(struct sk_buff *skb, |
2015 | struct net_device *dev, | 2122 | struct net_device *dev, |
2016 | u8 *addr, u32 pid, u32 seq, | 2123 | u8 *addr, u32 pid, u32 seq, |
2017 | int type, unsigned int flags) | 2124 | int type, unsigned int flags, |
2125 | int nlflags) | ||
2018 | { | 2126 | { |
2019 | struct nlmsghdr *nlh; | 2127 | struct nlmsghdr *nlh; |
2020 | struct ndmsg *ndm; | 2128 | struct ndmsg *ndm; |
2021 | 2129 | ||
2022 | nlh = nlmsg_put(skb, pid, seq, type, sizeof(*ndm), NLM_F_MULTI); | 2130 | nlh = nlmsg_put(skb, pid, seq, type, sizeof(*ndm), nlflags); |
2023 | if (!nlh) | 2131 | if (!nlh) |
2024 | return -EMSGSIZE; | 2132 | return -EMSGSIZE; |
2025 | 2133 | ||
@@ -2057,7 +2165,7 @@ static void rtnl_fdb_notify(struct net_device *dev, u8 *addr, int type) | |||
2057 | if (!skb) | 2165 | if (!skb) |
2058 | goto errout; | 2166 | goto errout; |
2059 | 2167 | ||
2060 | err = nlmsg_populate_fdb_fill(skb, dev, addr, 0, 0, type, NTF_SELF); | 2168 | err = nlmsg_populate_fdb_fill(skb, dev, addr, 0, 0, type, NTF_SELF, 0); |
2061 | if (err < 0) { | 2169 | if (err < 0) { |
2062 | kfree_skb(skb); | 2170 | kfree_skb(skb); |
2063 | goto errout; | 2171 | goto errout; |
@@ -2282,7 +2390,8 @@ static int nlmsg_populate_fdb(struct sk_buff *skb, | |||
2282 | 2390 | ||
2283 | err = nlmsg_populate_fdb_fill(skb, dev, ha->addr, | 2391 | err = nlmsg_populate_fdb_fill(skb, dev, ha->addr, |
2284 | portid, seq, | 2392 | portid, seq, |
2285 | RTM_NEWNEIGH, NTF_SELF); | 2393 | RTM_NEWNEIGH, NTF_SELF, |
2394 | NLM_F_MULTI); | ||
2286 | if (err < 0) | 2395 | if (err < 0) |
2287 | return err; | 2396 | return err; |
2288 | skip: | 2397 | skip: |