diff options
Diffstat (limited to 'net/tipc/link.c')
-rw-r--r-- | net/tipc/link.c | 337 |
1 files changed, 3 insertions, 334 deletions
diff --git a/net/tipc/link.c b/net/tipc/link.c index 1dda46e5dd83..c513a807b3a1 100644 --- a/net/tipc/link.c +++ b/net/tipc/link.c | |||
@@ -50,23 +50,6 @@ | |||
50 | */ | 50 | */ |
51 | static const char *link_co_err = "Link tunneling error, "; | 51 | static const char *link_co_err = "Link tunneling error, "; |
52 | static const char *link_rst_msg = "Resetting link "; | 52 | static const char *link_rst_msg = "Resetting link "; |
53 | static const char tipc_bclink_name[] = "broadcast-link"; | ||
54 | |||
55 | static const struct nla_policy tipc_nl_link_policy[TIPC_NLA_LINK_MAX + 1] = { | ||
56 | [TIPC_NLA_LINK_UNSPEC] = { .type = NLA_UNSPEC }, | ||
57 | [TIPC_NLA_LINK_NAME] = { | ||
58 | .type = NLA_STRING, | ||
59 | .len = TIPC_MAX_LINK_NAME | ||
60 | }, | ||
61 | [TIPC_NLA_LINK_MTU] = { .type = NLA_U32 }, | ||
62 | [TIPC_NLA_LINK_BROADCAST] = { .type = NLA_FLAG }, | ||
63 | [TIPC_NLA_LINK_UP] = { .type = NLA_FLAG }, | ||
64 | [TIPC_NLA_LINK_ACTIVE] = { .type = NLA_FLAG }, | ||
65 | [TIPC_NLA_LINK_PROP] = { .type = NLA_NESTED }, | ||
66 | [TIPC_NLA_LINK_STATS] = { .type = NLA_NESTED }, | ||
67 | [TIPC_NLA_LINK_RX] = { .type = NLA_U32 }, | ||
68 | [TIPC_NLA_LINK_TX] = { .type = NLA_U32 } | ||
69 | }; | ||
70 | 53 | ||
71 | /* Properties valid for media, bearar and link */ | 54 | /* Properties valid for media, bearar and link */ |
72 | static const struct nla_policy tipc_nl_prop_policy[TIPC_NLA_PROP_MAX + 1] = { | 55 | static const struct nla_policy tipc_nl_prop_policy[TIPC_NLA_PROP_MAX + 1] = { |
@@ -117,7 +100,6 @@ static int tipc_link_proto_rcv(struct tipc_link *l, struct sk_buff *skb, | |||
117 | static void tipc_link_build_proto_msg(struct tipc_link *l, int mtyp, bool probe, | 100 | static void tipc_link_build_proto_msg(struct tipc_link *l, int mtyp, bool probe, |
118 | u16 rcvgap, int tolerance, int priority, | 101 | u16 rcvgap, int tolerance, int priority, |
119 | struct sk_buff_head *xmitq); | 102 | struct sk_buff_head *xmitq); |
120 | static void link_reset_statistics(struct tipc_link *l_ptr); | ||
121 | static void link_print(struct tipc_link *l_ptr, const char *str); | 103 | static void link_print(struct tipc_link *l_ptr, const char *str); |
122 | static void tipc_link_build_nack_msg(struct tipc_link *l, | 104 | static void tipc_link_build_nack_msg(struct tipc_link *l, |
123 | struct sk_buff_head *xmitq); | 105 | struct sk_buff_head *xmitq); |
@@ -1527,49 +1509,11 @@ void tipc_link_set_queue_limits(struct tipc_link *l, u32 win) | |||
1527 | l->backlog[TIPC_SYSTEM_IMPORTANCE].limit = max_bulk; | 1509 | l->backlog[TIPC_SYSTEM_IMPORTANCE].limit = max_bulk; |
1528 | } | 1510 | } |
1529 | 1511 | ||
1530 | /* tipc_link_find_owner - locate owner node of link by link's name | ||
1531 | * @net: the applicable net namespace | ||
1532 | * @name: pointer to link name string | ||
1533 | * @bearer_id: pointer to index in 'node->links' array where the link was found. | ||
1534 | * | ||
1535 | * Returns pointer to node owning the link, or 0 if no matching link is found. | ||
1536 | */ | ||
1537 | static struct tipc_node *tipc_link_find_owner(struct net *net, | ||
1538 | const char *link_name, | ||
1539 | unsigned int *bearer_id) | ||
1540 | { | ||
1541 | struct tipc_net *tn = net_generic(net, tipc_net_id); | ||
1542 | struct tipc_link *l_ptr; | ||
1543 | struct tipc_node *n_ptr; | ||
1544 | struct tipc_node *found_node = NULL; | ||
1545 | int i; | ||
1546 | |||
1547 | *bearer_id = 0; | ||
1548 | rcu_read_lock(); | ||
1549 | list_for_each_entry_rcu(n_ptr, &tn->node_list, list) { | ||
1550 | tipc_node_read_lock(n_ptr); | ||
1551 | for (i = 0; i < MAX_BEARERS; i++) { | ||
1552 | l_ptr = n_ptr->links[i].link; | ||
1553 | if (l_ptr && !strcmp(l_ptr->name, link_name)) { | ||
1554 | *bearer_id = i; | ||
1555 | found_node = n_ptr; | ||
1556 | break; | ||
1557 | } | ||
1558 | } | ||
1559 | tipc_node_read_unlock(n_ptr); | ||
1560 | if (found_node) | ||
1561 | break; | ||
1562 | } | ||
1563 | rcu_read_unlock(); | ||
1564 | |||
1565 | return found_node; | ||
1566 | } | ||
1567 | |||
1568 | /** | 1512 | /** |
1569 | * link_reset_statistics - reset link statistics | 1513 | * link_reset_statistics - reset link statistics |
1570 | * @l_ptr: pointer to link | 1514 | * @l_ptr: pointer to link |
1571 | */ | 1515 | */ |
1572 | static void link_reset_statistics(struct tipc_link *l_ptr) | 1516 | void link_reset_statistics(struct tipc_link *l_ptr) |
1573 | { | 1517 | { |
1574 | memset(&l_ptr->stats, 0, sizeof(l_ptr->stats)); | 1518 | memset(&l_ptr->stats, 0, sizeof(l_ptr->stats)); |
1575 | l_ptr->stats.sent_info = l_ptr->snd_nxt; | 1519 | l_ptr->stats.sent_info = l_ptr->snd_nxt; |
@@ -1626,84 +1570,6 @@ int tipc_nl_parse_link_prop(struct nlattr *prop, struct nlattr *props[]) | |||
1626 | return 0; | 1570 | return 0; |
1627 | } | 1571 | } |
1628 | 1572 | ||
1629 | int tipc_nl_link_set(struct sk_buff *skb, struct genl_info *info) | ||
1630 | { | ||
1631 | int err; | ||
1632 | int res = 0; | ||
1633 | int bearer_id; | ||
1634 | char *name; | ||
1635 | struct tipc_link *link; | ||
1636 | struct tipc_node *node; | ||
1637 | struct nlattr *attrs[TIPC_NLA_LINK_MAX + 1]; | ||
1638 | struct net *net = sock_net(skb->sk); | ||
1639 | |||
1640 | if (!info->attrs[TIPC_NLA_LINK]) | ||
1641 | return -EINVAL; | ||
1642 | |||
1643 | err = nla_parse_nested(attrs, TIPC_NLA_LINK_MAX, | ||
1644 | info->attrs[TIPC_NLA_LINK], | ||
1645 | tipc_nl_link_policy); | ||
1646 | if (err) | ||
1647 | return err; | ||
1648 | |||
1649 | if (!attrs[TIPC_NLA_LINK_NAME]) | ||
1650 | return -EINVAL; | ||
1651 | |||
1652 | name = nla_data(attrs[TIPC_NLA_LINK_NAME]); | ||
1653 | |||
1654 | if (strcmp(name, tipc_bclink_name) == 0) | ||
1655 | return tipc_nl_bc_link_set(net, attrs); | ||
1656 | |||
1657 | node = tipc_link_find_owner(net, name, &bearer_id); | ||
1658 | if (!node) | ||
1659 | return -EINVAL; | ||
1660 | |||
1661 | tipc_node_read_lock(node); | ||
1662 | |||
1663 | link = node->links[bearer_id].link; | ||
1664 | if (!link) { | ||
1665 | res = -EINVAL; | ||
1666 | goto out; | ||
1667 | } | ||
1668 | |||
1669 | if (attrs[TIPC_NLA_LINK_PROP]) { | ||
1670 | struct nlattr *props[TIPC_NLA_PROP_MAX + 1]; | ||
1671 | |||
1672 | err = tipc_nl_parse_link_prop(attrs[TIPC_NLA_LINK_PROP], | ||
1673 | props); | ||
1674 | if (err) { | ||
1675 | res = err; | ||
1676 | goto out; | ||
1677 | } | ||
1678 | |||
1679 | if (props[TIPC_NLA_PROP_TOL]) { | ||
1680 | u32 tol; | ||
1681 | |||
1682 | tol = nla_get_u32(props[TIPC_NLA_PROP_TOL]); | ||
1683 | link->tolerance = tol; | ||
1684 | tipc_link_proto_xmit(link, STATE_MSG, 0, 0, tol, 0); | ||
1685 | } | ||
1686 | if (props[TIPC_NLA_PROP_PRIO]) { | ||
1687 | u32 prio; | ||
1688 | |||
1689 | prio = nla_get_u32(props[TIPC_NLA_PROP_PRIO]); | ||
1690 | link->priority = prio; | ||
1691 | tipc_link_proto_xmit(link, STATE_MSG, 0, 0, 0, prio); | ||
1692 | } | ||
1693 | if (props[TIPC_NLA_PROP_WIN]) { | ||
1694 | u32 win; | ||
1695 | |||
1696 | win = nla_get_u32(props[TIPC_NLA_PROP_WIN]); | ||
1697 | tipc_link_set_queue_limits(link, win); | ||
1698 | } | ||
1699 | } | ||
1700 | |||
1701 | out: | ||
1702 | tipc_node_read_unlock(node); | ||
1703 | |||
1704 | return res; | ||
1705 | } | ||
1706 | |||
1707 | static int __tipc_nl_add_stats(struct sk_buff *skb, struct tipc_stats *s) | 1573 | static int __tipc_nl_add_stats(struct sk_buff *skb, struct tipc_stats *s) |
1708 | { | 1574 | { |
1709 | int i; | 1575 | int i; |
@@ -1770,8 +1636,8 @@ msg_full: | |||
1770 | } | 1636 | } |
1771 | 1637 | ||
1772 | /* Caller should hold appropriate locks to protect the link */ | 1638 | /* Caller should hold appropriate locks to protect the link */ |
1773 | static int __tipc_nl_add_link(struct net *net, struct tipc_nl_msg *msg, | 1639 | int __tipc_nl_add_link(struct net *net, struct tipc_nl_msg *msg, |
1774 | struct tipc_link *link, int nlflags) | 1640 | struct tipc_link *link, int nlflags) |
1775 | { | 1641 | { |
1776 | int err; | 1642 | int err; |
1777 | void *hdr; | 1643 | void *hdr; |
@@ -1839,200 +1705,3 @@ msg_full: | |||
1839 | 1705 | ||
1840 | return -EMSGSIZE; | 1706 | return -EMSGSIZE; |
1841 | } | 1707 | } |
1842 | |||
1843 | /* Caller should hold node lock */ | ||
1844 | static int __tipc_nl_add_node_links(struct net *net, struct tipc_nl_msg *msg, | ||
1845 | struct tipc_node *node, u32 *prev_link) | ||
1846 | { | ||
1847 | u32 i; | ||
1848 | int err; | ||
1849 | |||
1850 | for (i = *prev_link; i < MAX_BEARERS; i++) { | ||
1851 | *prev_link = i; | ||
1852 | |||
1853 | if (!node->links[i].link) | ||
1854 | continue; | ||
1855 | |||
1856 | err = __tipc_nl_add_link(net, msg, | ||
1857 | node->links[i].link, NLM_F_MULTI); | ||
1858 | if (err) | ||
1859 | return err; | ||
1860 | } | ||
1861 | *prev_link = 0; | ||
1862 | |||
1863 | return 0; | ||
1864 | } | ||
1865 | |||
1866 | int tipc_nl_link_dump(struct sk_buff *skb, struct netlink_callback *cb) | ||
1867 | { | ||
1868 | struct net *net = sock_net(skb->sk); | ||
1869 | struct tipc_net *tn = net_generic(net, tipc_net_id); | ||
1870 | struct tipc_node *node; | ||
1871 | struct tipc_nl_msg msg; | ||
1872 | u32 prev_node = cb->args[0]; | ||
1873 | u32 prev_link = cb->args[1]; | ||
1874 | int done = cb->args[2]; | ||
1875 | int err; | ||
1876 | |||
1877 | if (done) | ||
1878 | return 0; | ||
1879 | |||
1880 | msg.skb = skb; | ||
1881 | msg.portid = NETLINK_CB(cb->skb).portid; | ||
1882 | msg.seq = cb->nlh->nlmsg_seq; | ||
1883 | |||
1884 | rcu_read_lock(); | ||
1885 | if (prev_node) { | ||
1886 | node = tipc_node_find(net, prev_node); | ||
1887 | if (!node) { | ||
1888 | /* We never set seq or call nl_dump_check_consistent() | ||
1889 | * this means that setting prev_seq here will cause the | ||
1890 | * consistence check to fail in the netlink callback | ||
1891 | * handler. Resulting in the last NLMSG_DONE message | ||
1892 | * having the NLM_F_DUMP_INTR flag set. | ||
1893 | */ | ||
1894 | cb->prev_seq = 1; | ||
1895 | goto out; | ||
1896 | } | ||
1897 | tipc_node_put(node); | ||
1898 | |||
1899 | list_for_each_entry_continue_rcu(node, &tn->node_list, | ||
1900 | list) { | ||
1901 | tipc_node_read_lock(node); | ||
1902 | err = __tipc_nl_add_node_links(net, &msg, node, | ||
1903 | &prev_link); | ||
1904 | tipc_node_read_unlock(node); | ||
1905 | if (err) | ||
1906 | goto out; | ||
1907 | |||
1908 | prev_node = node->addr; | ||
1909 | } | ||
1910 | } else { | ||
1911 | err = tipc_nl_add_bc_link(net, &msg); | ||
1912 | if (err) | ||
1913 | goto out; | ||
1914 | |||
1915 | list_for_each_entry_rcu(node, &tn->node_list, list) { | ||
1916 | tipc_node_read_lock(node); | ||
1917 | err = __tipc_nl_add_node_links(net, &msg, node, | ||
1918 | &prev_link); | ||
1919 | tipc_node_read_unlock(node); | ||
1920 | if (err) | ||
1921 | goto out; | ||
1922 | |||
1923 | prev_node = node->addr; | ||
1924 | } | ||
1925 | } | ||
1926 | done = 1; | ||
1927 | out: | ||
1928 | rcu_read_unlock(); | ||
1929 | |||
1930 | cb->args[0] = prev_node; | ||
1931 | cb->args[1] = prev_link; | ||
1932 | cb->args[2] = done; | ||
1933 | |||
1934 | return skb->len; | ||
1935 | } | ||
1936 | |||
1937 | int tipc_nl_link_get(struct sk_buff *skb, struct genl_info *info) | ||
1938 | { | ||
1939 | struct net *net = genl_info_net(info); | ||
1940 | struct tipc_nl_msg msg; | ||
1941 | char *name; | ||
1942 | int err; | ||
1943 | |||
1944 | msg.portid = info->snd_portid; | ||
1945 | msg.seq = info->snd_seq; | ||
1946 | |||
1947 | if (!info->attrs[TIPC_NLA_LINK_NAME]) | ||
1948 | return -EINVAL; | ||
1949 | name = nla_data(info->attrs[TIPC_NLA_LINK_NAME]); | ||
1950 | |||
1951 | msg.skb = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); | ||
1952 | if (!msg.skb) | ||
1953 | return -ENOMEM; | ||
1954 | |||
1955 | if (strcmp(name, tipc_bclink_name) == 0) { | ||
1956 | err = tipc_nl_add_bc_link(net, &msg); | ||
1957 | if (err) { | ||
1958 | nlmsg_free(msg.skb); | ||
1959 | return err; | ||
1960 | } | ||
1961 | } else { | ||
1962 | int bearer_id; | ||
1963 | struct tipc_node *node; | ||
1964 | struct tipc_link *link; | ||
1965 | |||
1966 | node = tipc_link_find_owner(net, name, &bearer_id); | ||
1967 | if (!node) | ||
1968 | return -EINVAL; | ||
1969 | |||
1970 | tipc_node_read_lock(node); | ||
1971 | link = node->links[bearer_id].link; | ||
1972 | if (!link) { | ||
1973 | tipc_node_read_unlock(node); | ||
1974 | nlmsg_free(msg.skb); | ||
1975 | return -EINVAL; | ||
1976 | } | ||
1977 | |||
1978 | err = __tipc_nl_add_link(net, &msg, link, 0); | ||
1979 | tipc_node_read_unlock(node); | ||
1980 | if (err) { | ||
1981 | nlmsg_free(msg.skb); | ||
1982 | return err; | ||
1983 | } | ||
1984 | } | ||
1985 | |||
1986 | return genlmsg_reply(msg.skb, info); | ||
1987 | } | ||
1988 | |||
1989 | int tipc_nl_link_reset_stats(struct sk_buff *skb, struct genl_info *info) | ||
1990 | { | ||
1991 | int err; | ||
1992 | char *link_name; | ||
1993 | unsigned int bearer_id; | ||
1994 | struct tipc_link *link; | ||
1995 | struct tipc_node *node; | ||
1996 | struct nlattr *attrs[TIPC_NLA_LINK_MAX + 1]; | ||
1997 | struct net *net = sock_net(skb->sk); | ||
1998 | struct tipc_link_entry *le; | ||
1999 | |||
2000 | if (!info->attrs[TIPC_NLA_LINK]) | ||
2001 | return -EINVAL; | ||
2002 | |||
2003 | err = nla_parse_nested(attrs, TIPC_NLA_LINK_MAX, | ||
2004 | info->attrs[TIPC_NLA_LINK], | ||
2005 | tipc_nl_link_policy); | ||
2006 | if (err) | ||
2007 | return err; | ||
2008 | |||
2009 | if (!attrs[TIPC_NLA_LINK_NAME]) | ||
2010 | return -EINVAL; | ||
2011 | |||
2012 | link_name = nla_data(attrs[TIPC_NLA_LINK_NAME]); | ||
2013 | |||
2014 | if (strcmp(link_name, tipc_bclink_name) == 0) { | ||
2015 | err = tipc_bclink_reset_stats(net); | ||
2016 | if (err) | ||
2017 | return err; | ||
2018 | return 0; | ||
2019 | } | ||
2020 | |||
2021 | node = tipc_link_find_owner(net, link_name, &bearer_id); | ||
2022 | if (!node) | ||
2023 | return -EINVAL; | ||
2024 | |||
2025 | le = &node->links[bearer_id]; | ||
2026 | tipc_node_read_lock(node); | ||
2027 | spin_lock_bh(&le->lock); | ||
2028 | link = le->link; | ||
2029 | if (!link) { | ||
2030 | spin_unlock_bh(&le->lock); | ||
2031 | tipc_node_read_unlock(node); | ||
2032 | return -EINVAL; | ||
2033 | } | ||
2034 | link_reset_statistics(link); | ||
2035 | spin_unlock_bh(&le->lock); | ||
2036 | tipc_node_read_unlock(node); | ||
2037 | return 0; | ||
2038 | } | ||