| From fd165c3bd24e6e60aad9c76570494f951818c69b Mon Sep 17 00:00:00 2001 |
| From: Taehee Yoo <ap420073@gmail.com> |
| Date: Fri, 13 Mar 2020 06:50:24 +0000 |
| Subject: [PATCH] hsr: add restart routine into hsr_get_node_list() |
| |
| commit ca19c70f5225771c05bcdcb832b4eb84d7271c5e upstream. |
| |
| The hsr_get_node_list() is to send node addresses to the userspace. |
| If there are so many nodes, it could fail because of buffer size. |
| In order to avoid this failure, the restart routine is added. |
| |
| Fixes: f421436a591d ("net/hsr: Add support for the High-availability Seamless Redundancy protocol (HSRv0)") |
| Signed-off-by: Taehee Yoo <ap420073@gmail.com> |
| Signed-off-by: David S. Miller <davem@davemloft.net> |
| Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com> |
| |
| diff --git a/net/hsr/hsr_netlink.c b/net/hsr/hsr_netlink.c |
| index d6760df2ad1f..726bfe923999 100644 |
| --- a/net/hsr/hsr_netlink.c |
| +++ b/net/hsr/hsr_netlink.c |
| @@ -360,16 +360,14 @@ static int hsr_get_node_status(struct sk_buff *skb_in, struct genl_info *info) |
| */ |
| static int hsr_get_node_list(struct sk_buff *skb_in, struct genl_info *info) |
| { |
| - /* For receiving */ |
| - struct nlattr *na; |
| + unsigned char addr[ETH_ALEN]; |
| struct net_device *hsr_dev; |
| - |
| - /* For sending */ |
| struct sk_buff *skb_out; |
| - void *msg_head; |
| struct hsr_priv *hsr; |
| - void *pos; |
| - unsigned char addr[ETH_ALEN]; |
| + bool restart = false; |
| + struct nlattr *na; |
| + void *pos = NULL; |
| + void *msg_head; |
| int res; |
| |
| if (!info) |
| @@ -387,8 +385,9 @@ static int hsr_get_node_list(struct sk_buff *skb_in, struct genl_info *info) |
| if (!is_hsr_master(hsr_dev)) |
| goto rcu_unlock; |
| |
| +restart: |
| /* Send reply */ |
| - skb_out = genlmsg_new(NLMSG_GOODSIZE, GFP_ATOMIC); |
| + skb_out = genlmsg_new(GENLMSG_DEFAULT_SIZE, GFP_ATOMIC); |
| if (!skb_out) { |
| res = -ENOMEM; |
| goto fail; |
| @@ -402,17 +401,28 @@ static int hsr_get_node_list(struct sk_buff *skb_in, struct genl_info *info) |
| goto nla_put_failure; |
| } |
| |
| - res = nla_put_u32(skb_out, HSR_A_IFINDEX, hsr_dev->ifindex); |
| - if (res < 0) |
| - goto nla_put_failure; |
| + if (!restart) { |
| + res = nla_put_u32(skb_out, HSR_A_IFINDEX, hsr_dev->ifindex); |
| + if (res < 0) |
| + goto nla_put_failure; |
| + } |
| |
| hsr = netdev_priv(hsr_dev); |
| |
| - pos = hsr_get_next_node(hsr, NULL, addr); |
| + if (!pos) |
| + pos = hsr_get_next_node(hsr, NULL, addr); |
| while (pos) { |
| res = nla_put(skb_out, HSR_A_NODE_ADDR, ETH_ALEN, addr); |
| - if (res < 0) |
| + if (res < 0) { |
| + if (res == -EMSGSIZE) { |
| + genlmsg_end(skb_out, msg_head); |
| + genlmsg_unicast(genl_info_net(info), skb_out, |
| + info->snd_portid); |
| + restart = true; |
| + goto restart; |
| + } |
| goto nla_put_failure; |
| + } |
| pos = hsr_get_next_node(hsr, pos, addr); |
| } |
| rcu_read_unlock(); |
| @@ -429,7 +439,7 @@ static int hsr_get_node_list(struct sk_buff *skb_in, struct genl_info *info) |
| return 0; |
| |
| nla_put_failure: |
| - kfree_skb(skb_out); |
| + nlmsg_free(skb_out); |
| /* Fall through */ |
| |
| fail: |
| -- |
| 2.7.4 |
| |