naccyde / rpms / iproute

Forked from rpms/iproute 7 months ago
Clone

Blame SOURCES/0023-lib-libnetlink-update-rtnl_talk-to-support-malloc-bu.patch

36cfb7
From 3d76c7eea3caaddcc0608ad35a9e6fab3df11f8e Mon Sep 17 00:00:00 2001
36cfb7
From: Hangbin Liu <haliu@redhat.com>
36cfb7
Date: Wed, 8 Nov 2017 14:39:13 +0800
36cfb7
Subject: [PATCH] lib/libnetlink: update rtnl_talk to support malloc buff at
36cfb7
 run time
36cfb7
36cfb7
Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1380803
36cfb7
Upstream Status: iproute2.git net-next commit 86bf43c7c2fd
36cfb7
36cfb7
Conflicts:
36cfb7
- iplink_get@ip/iplink.c: no function open_json_object() due to missing
36cfb7
  e4a1216aeb2a ("ip: iplink.c: open/close json obj for ip -brief -json link
36cfb7
  show dev DEV"). Lack of last parameter for print_linkinfo_brief() due to
36cfb7
  missing 63891c70137f ("ip address: Change print_linkinfo_brief to take
36cfb7
  filter as an input")
36cfb7
- gre_parse_opt@ip/link_gre.c: context conflicts due to missing new
36cfb7
  flag IFLA_GRE_ERSPAN_INDEX.
36cfb7
- gre_parse_opt@ip/link_gre6.c: context conflicts due to missing new
36cfb7
  flag IFLA_GRE_FWMARK.
36cfb7
- ip6tunnel_parse_opt@ip/link_ip6tnl.c: context conflicts due to missing new
36cfb7
  flag IFLA_IPTUN_FWMARK.
36cfb7
- iptunnel_parse_opt@ip/link_iptnl.c: context conflicts due to missing new
36cfb7
  flag IFLA_IPTUN_FWMARK.
36cfb7
- vti_parse_opt@ip/link_vti.c: context conflicts due to missing new flag
36cfb7
  IFLA_VTI_FWMARK
36cfb7
- vti6_parse_opt@ip/link_vti6.c: context conflicts due to missing new flag
36cfb7
  IFLA_VTI_FWMARK
36cfb7
36cfb7
commit 86bf43c7c2fdc33d7c021b4a1add1c8facbca51c
36cfb7
Author: Hangbin Liu <liuhangbin@gmail.com>
36cfb7
Date:   Thu Oct 26 09:41:47 2017 +0800
36cfb7
36cfb7
    lib/libnetlink: update rtnl_talk to support malloc buff at run time
36cfb7
36cfb7
    This is an update for 460c03f3f3cc ("iplink: double the buffer size also in
36cfb7
    iplink_get()"). After update, we will not need to double the buffer size
36cfb7
    every time when VFs number increased.
36cfb7
36cfb7
    With call like rtnl_talk(&rth, &req.n, NULL, 0), we can simply remove the
36cfb7
    length parameter.
36cfb7
36cfb7
    With call like rtnl_talk(&rth, nlh, nlh, sizeof(req), I add a new variable
36cfb7
    answer to avoid overwrite data in nlh, because it may has more info after
36cfb7
    nlh. also this will avoid nlh buffer not enough issue.
36cfb7
36cfb7
    We need to free answer after using.
36cfb7
36cfb7
    Signed-off-by: Hangbin Liu <liuhangbin@gmail.com>
36cfb7
    Signed-off-by: Phil Sutter <phil@nwl.cc>
36cfb7
36cfb7
Signed-off-by: Hangbin Liu <haliu@redhat.com>
36cfb7
---
36cfb7
 bridge/fdb.c         |  2 +-
36cfb7
 bridge/link.c        |  2 +-
36cfb7
 bridge/mdb.c         |  2 +-
36cfb7
 bridge/vlan.c        |  2 +-
36cfb7
 genl/ctrl.c          | 19 ++++++++++++-------
36cfb7
 include/libnetlink.h |  6 +++---
36cfb7
 ip/ipaddress.c       |  4 ++--
36cfb7
 ip/ipaddrlabel.c     |  4 ++--
36cfb7
 ip/ipfou.c           |  4 ++--
36cfb7
 ip/ipila.c           |  4 ++--
36cfb7
 ip/ipl2tp.c          |  8 ++++----
36cfb7
 ip/iplink.c          | 38 +++++++++++++++++++-------------------
36cfb7
 ip/iplink_vrf.c      | 44 ++++++++++++++++++++------------------------
36cfb7
 ip/ipmacsec.c        |  2 +-
36cfb7
 ip/ipneigh.c         |  2 +-
36cfb7
 ip/ipnetns.c         | 23 ++++++++++++++---------
36cfb7
 ip/ipntable.c        |  2 +-
36cfb7
 ip/iproute.c         | 26 +++++++++++++++++---------
36cfb7
 ip/iprule.c          |  6 +++---
36cfb7
 ip/iptoken.c         |  2 +-
36cfb7
 ip/link_gre.c        | 11 +++++++----
36cfb7
 ip/link_gre6.c       | 11 +++++++----
36cfb7
 ip/link_ip6tnl.c     | 11 +++++++----
36cfb7
 ip/link_iptnl.c      | 11 +++++++----
36cfb7
 ip/link_vti.c        | 11 +++++++----
36cfb7
 ip/link_vti6.c       | 11 +++++++----
36cfb7
 ip/tcp_metrics.c     |  8 +++++---
36cfb7
 ip/xfrm_policy.c     | 25 +++++++++++++------------
36cfb7
 ip/xfrm_state.c      | 30 ++++++++++++++++--------------
36cfb7
 lib/libgenl.c        |  9 +++++++--
36cfb7
 lib/libnetlink.c     | 24 +++++++++++-------------
36cfb7
 misc/ss.c            |  2 +-
36cfb7
 tc/m_action.c        | 12 ++++++------
36cfb7
 tc/tc_class.c        |  2 +-
36cfb7
 tc/tc_filter.c       |  8 +++++---
36cfb7
 tc/tc_qdisc.c        |  2 +-
36cfb7
 36 files changed, 216 insertions(+), 174 deletions(-)
36cfb7
36cfb7
diff --git a/bridge/fdb.c b/bridge/fdb.c
e138d9
index a71a78f23b202..4859edb2473b7 100644
36cfb7
--- a/bridge/fdb.c
36cfb7
+++ b/bridge/fdb.c
36cfb7
@@ -529,7 +529,7 @@ static int fdb_modify(int cmd, int flags, int argc, char **argv)
36cfb7
 		return -1;
36cfb7
 	}
36cfb7
 
36cfb7
-	if (rtnl_talk(&rth, &req.n, NULL, 0) < 0)
36cfb7
+	if (rtnl_talk(&rth, &req.n, NULL) < 0)
36cfb7
 		return -1;
36cfb7
 
36cfb7
 	return 0;
36cfb7
diff --git a/bridge/link.c b/bridge/link.c
e138d9
index 93472ad3699e3..cc29a2adb2e01 100644
36cfb7
--- a/bridge/link.c
36cfb7
+++ b/bridge/link.c
36cfb7
@@ -426,7 +426,7 @@ static int brlink_modify(int argc, char **argv)
36cfb7
 		addattr_nest_end(&req.n, nest);
36cfb7
 	}
36cfb7
 
36cfb7
-	if (rtnl_talk(&rth, &req.n, NULL, 0) < 0)
36cfb7
+	if (rtnl_talk(&rth, &req.n, NULL) < 0)
36cfb7
 		return -1;
36cfb7
 
36cfb7
 	return 0;
36cfb7
diff --git a/bridge/mdb.c b/bridge/mdb.c
e138d9
index e60ff3ef3f485..fbd8184dacf85 100644
36cfb7
--- a/bridge/mdb.c
36cfb7
+++ b/bridge/mdb.c
36cfb7
@@ -298,7 +298,7 @@ static int mdb_modify(int cmd, int flags, int argc, char **argv)
36cfb7
 	entry.vid = vid;
36cfb7
 	addattr_l(&req.n, sizeof(req), MDBA_SET_ENTRY, &entry, sizeof(entry));
36cfb7
 
36cfb7
-	if (rtnl_talk(&rth, &req.n, NULL, 0) < 0)
36cfb7
+	if (rtnl_talk(&rth, &req.n, NULL) < 0)
36cfb7
 		return -1;
36cfb7
 
36cfb7
 	return 0;
36cfb7
diff --git a/bridge/vlan.c b/bridge/vlan.c
e138d9
index ebcdacee309bc..5d683595e0e32 100644
36cfb7
--- a/bridge/vlan.c
36cfb7
+++ b/bridge/vlan.c
36cfb7
@@ -133,7 +133,7 @@ static int vlan_modify(int cmd, int argc, char **argv)
36cfb7
 
36cfb7
 	addattr_nest_end(&req.n, afspec);
36cfb7
 
36cfb7
-	if (rtnl_talk(&rth, &req.n, NULL, 0) < 0)
36cfb7
+	if (rtnl_talk(&rth, &req.n, NULL) < 0)
36cfb7
 		return -1;
36cfb7
 
36cfb7
 	return 0;
36cfb7
diff --git a/genl/ctrl.c b/genl/ctrl.c
e138d9
index 6abd52582d0d3..21e857cfcfc25 100644
36cfb7
--- a/genl/ctrl.c
36cfb7
+++ b/genl/ctrl.c
36cfb7
@@ -55,6 +55,7 @@ int genl_ctrl_resolve_family(const char *family)
36cfb7
 	};
36cfb7
 	struct nlmsghdr *nlh = &req.n;
36cfb7
 	struct genlmsghdr *ghdr = &req.g;
36cfb7
+	struct nlmsghdr *answer = NULL;
36cfb7
 
36cfb7
 	if (rtnl_open_byproto(&rth, 0, NETLINK_GENERIC) < 0) {
36cfb7
 		fprintf(stderr, "Cannot open generic netlink socket\n");
36cfb7
@@ -63,19 +64,19 @@ int genl_ctrl_resolve_family(const char *family)
36cfb7
 
36cfb7
 	addattr_l(nlh, 128, CTRL_ATTR_FAMILY_NAME, family, strlen(family) + 1);
36cfb7
 
36cfb7
-	if (rtnl_talk(&rth, nlh, nlh, sizeof(req)) < 0) {
36cfb7
+	if (rtnl_talk(&rth, nlh, &answer) < 0) {
36cfb7
 		fprintf(stderr, "Error talking to the kernel\n");
36cfb7
 		goto errout;
36cfb7
 	}
36cfb7
 
36cfb7
 	{
36cfb7
 		struct rtattr *tb[CTRL_ATTR_MAX + 1];
36cfb7
-		int len = nlh->nlmsg_len;
36cfb7
+		int len = answer->nlmsg_len;
36cfb7
 		struct rtattr *attrs;
36cfb7
 
36cfb7
-		if (nlh->nlmsg_type !=  GENL_ID_CTRL) {
36cfb7
+		if (answer->nlmsg_type !=  GENL_ID_CTRL) {
36cfb7
 			fprintf(stderr, "Not a controller message, nlmsg_len=%d "
36cfb7
-				"nlmsg_type=0x%x\n", nlh->nlmsg_len, nlh->nlmsg_type);
36cfb7
+				"nlmsg_type=0x%x\n", answer->nlmsg_len, answer->nlmsg_type);
36cfb7
 			goto errout;
36cfb7
 		}
36cfb7
 
36cfb7
@@ -88,10 +89,11 @@ int genl_ctrl_resolve_family(const char *family)
36cfb7
 
36cfb7
 		if (len < 0) {
36cfb7
 			fprintf(stderr, "wrong controller message len %d\n", len);
36cfb7
+			free(answer);
36cfb7
 			return -1;
36cfb7
 		}
36cfb7
 
36cfb7
-		attrs = (struct rtattr *) ((char *) ghdr + GENL_HDRLEN);
36cfb7
+		attrs = (struct rtattr *) ((char *) answer + NLMSG_LENGTH(GENL_HDRLEN));
36cfb7
 		parse_rtattr(tb, CTRL_ATTR_MAX, attrs, len);
36cfb7
 
36cfb7
 		if (tb[CTRL_ATTR_FAMILY_ID] == NULL) {
36cfb7
@@ -103,6 +105,7 @@ int genl_ctrl_resolve_family(const char *family)
36cfb7
 	}
36cfb7
 
36cfb7
 errout:
36cfb7
+	free(answer);
36cfb7
 	rtnl_close(&rth);
36cfb7
 	return ret;
36cfb7
 }
36cfb7
@@ -299,6 +302,7 @@ static int ctrl_list(int cmd, int argc, char **argv)
36cfb7
 		.g.cmd = CTRL_CMD_GETFAMILY,
36cfb7
 	};
36cfb7
 	struct nlmsghdr *nlh = &req.n;
36cfb7
+	struct nlmsghdr *answer = NULL;
36cfb7
 
36cfb7
 	if (rtnl_open_byproto(&rth, 0, NETLINK_GENERIC) < 0) {
36cfb7
 		fprintf(stderr, "Cannot open generic netlink socket\n");
36cfb7
@@ -331,12 +335,12 @@ static int ctrl_list(int cmd, int argc, char **argv)
36cfb7
 			goto ctrl_done;
36cfb7
 		}
36cfb7
 
36cfb7
-		if (rtnl_talk(&rth, nlh, nlh, sizeof(req)) < 0) {
36cfb7
+		if (rtnl_talk(&rth, nlh, &answer) < 0) {
36cfb7
 			fprintf(stderr, "Error talking to the kernel\n");
36cfb7
 			goto ctrl_done;
36cfb7
 		}
36cfb7
 
36cfb7
-		if (print_ctrl2(NULL, nlh, (void *) stdout) < 0) {
36cfb7
+		if (print_ctrl2(NULL, answer, (void *) stdout) < 0) {
36cfb7
 			fprintf(stderr, "Dump terminated\n");
36cfb7
 			goto ctrl_done;
36cfb7
 		}
36cfb7
@@ -358,6 +362,7 @@ static int ctrl_list(int cmd, int argc, char **argv)
36cfb7
 
36cfb7
 	ret = 0;
36cfb7
 ctrl_done:
36cfb7
+	free(answer);
36cfb7
 	rtnl_close(&rth);
36cfb7
 	return ret;
36cfb7
 }
36cfb7
diff --git a/include/libnetlink.h b/include/libnetlink.h
e138d9
index 654aebc0f7632..2136d2bdd0379 100644
36cfb7
--- a/include/libnetlink.h
36cfb7
+++ b/include/libnetlink.h
36cfb7
@@ -82,13 +82,13 @@ int rtnl_dump_filter_nc(struct rtnl_handle *rth,
36cfb7
 #define rtnl_dump_filter(rth, filter, arg) \
36cfb7
 	rtnl_dump_filter_nc(rth, filter, arg, 0)
36cfb7
 int rtnl_talk(struct rtnl_handle *rtnl, struct nlmsghdr *n,
36cfb7
-	      struct nlmsghdr *answer, size_t len)
36cfb7
+	      struct nlmsghdr **answer)
36cfb7
 	__attribute__((warn_unused_result));
36cfb7
 int rtnl_talk_extack(struct rtnl_handle *rtnl, struct nlmsghdr *n,
36cfb7
-	      struct nlmsghdr *answer, size_t len, nl_ext_ack_fn_t errfn)
36cfb7
+	      struct nlmsghdr **answer, nl_ext_ack_fn_t errfn)
36cfb7
 	__attribute__((warn_unused_result));
36cfb7
 int rtnl_talk_suppress_rtnl_errmsg(struct rtnl_handle *rtnl, struct nlmsghdr *n,
36cfb7
-				   struct nlmsghdr *answer, size_t len)
36cfb7
+				   struct nlmsghdr **answer)
36cfb7
 	__attribute__((warn_unused_result));
36cfb7
 int rtnl_send(struct rtnl_handle *rth, const void *buf, int)
36cfb7
 	__attribute__((warn_unused_result));
36cfb7
diff --git a/ip/ipaddress.c b/ip/ipaddress.c
e138d9
index b8d9c7d917fe8..7492075687a9e 100644
36cfb7
--- a/ip/ipaddress.c
36cfb7
+++ b/ip/ipaddress.c
36cfb7
@@ -1356,7 +1356,7 @@ static int restore_handler(const struct sockaddr_nl *nl,
36cfb7
 
36cfb7
 	ll_init_map(&rth);
36cfb7
 
36cfb7
-	ret = rtnl_talk(&rth, n, n, sizeof(*n));
36cfb7
+	ret = rtnl_talk(&rth, n, NULL);
36cfb7
 	if ((ret < 0) && (errno == EEXIST))
36cfb7
 		ret = 0;
36cfb7
 
36cfb7
@@ -2064,7 +2064,7 @@ static int ipaddr_modify(int cmd, int flags, int argc, char **argv)
36cfb7
 		return -1;
36cfb7
 	}
36cfb7
 
36cfb7
-	if (rtnl_talk(&rth, &req.n, NULL, 0) < 0)
36cfb7
+	if (rtnl_talk(&rth, &req.n, NULL) < 0)
36cfb7
 		return -2;
36cfb7
 
36cfb7
 	return 0;
36cfb7
diff --git a/ip/ipaddrlabel.c b/ip/ipaddrlabel.c
e138d9
index 1d324dac02119..6ea9bfffdd0d1 100644
36cfb7
--- a/ip/ipaddrlabel.c
36cfb7
+++ b/ip/ipaddrlabel.c
36cfb7
@@ -176,7 +176,7 @@ static int ipaddrlabel_modify(int cmd, int argc, char **argv)
36cfb7
 	if (req.ifal.ifal_family == AF_UNSPEC)
36cfb7
 		req.ifal.ifal_family = AF_INET6;
36cfb7
 
36cfb7
-	if (rtnl_talk(&rth, &req.n, NULL, 0) < 0)
36cfb7
+	if (rtnl_talk(&rth, &req.n, NULL) < 0)
36cfb7
 		return -2;
36cfb7
 
36cfb7
 	return 0;
36cfb7
@@ -203,7 +203,7 @@ static int flush_addrlabel(const struct sockaddr_nl *who, struct nlmsghdr *n, vo
36cfb7
 		if (rtnl_open(&rth2, 0) < 0)
36cfb7
 			return -1;
36cfb7
 
36cfb7
-		if (rtnl_talk(&rth2, n, NULL, 0) < 0)
36cfb7
+		if (rtnl_talk(&rth2, n, NULL) < 0)
36cfb7
 			return -2;
36cfb7
 
36cfb7
 		rtnl_close(&rth2;;
36cfb7
diff --git a/ip/ipfou.c b/ip/ipfou.c
e138d9
index 00dbe150710d2..23000dc696d6a 100644
36cfb7
--- a/ip/ipfou.c
36cfb7
+++ b/ip/ipfou.c
36cfb7
@@ -116,7 +116,7 @@ static int do_add(int argc, char **argv)
36cfb7
 
36cfb7
 	fou_parse_opt(argc, argv, &req.n, true);
36cfb7
 
36cfb7
-	if (rtnl_talk(&genl_rth, &req.n, NULL, 0) < 0)
36cfb7
+	if (rtnl_talk(&genl_rth, &req.n, NULL) < 0)
36cfb7
 		return -2;
36cfb7
 
36cfb7
 	return 0;
36cfb7
@@ -128,7 +128,7 @@ static int do_del(int argc, char **argv)
36cfb7
 
36cfb7
 	fou_parse_opt(argc, argv, &req.n, false);
36cfb7
 
36cfb7
-	if (rtnl_talk(&genl_rth, &req.n, NULL, 0) < 0)
36cfb7
+	if (rtnl_talk(&genl_rth, &req.n, NULL) < 0)
36cfb7
 		return -2;
36cfb7
 
36cfb7
 	return 0;
36cfb7
diff --git a/ip/ipila.c b/ip/ipila.c
e138d9
index 843cc1652589f..0403fc4238b9d 100644
36cfb7
--- a/ip/ipila.c
36cfb7
+++ b/ip/ipila.c
36cfb7
@@ -220,7 +220,7 @@ static int do_add(int argc, char **argv)
36cfb7
 
36cfb7
 	ila_parse_opt(argc, argv, &req.n, true);
36cfb7
 
36cfb7
-	if (rtnl_talk(&genl_rth, &req.n, NULL, 0) < 0)
36cfb7
+	if (rtnl_talk(&genl_rth, &req.n, NULL) < 0)
36cfb7
 		return -2;
36cfb7
 
36cfb7
 	return 0;
36cfb7
@@ -232,7 +232,7 @@ static int do_del(int argc, char **argv)
36cfb7
 
36cfb7
 	ila_parse_opt(argc, argv, &req.n, false);
36cfb7
 
36cfb7
-	if (rtnl_talk(&genl_rth, &req.n, NULL, 0) < 0)
36cfb7
+	if (rtnl_talk(&genl_rth, &req.n, NULL) < 0)
36cfb7
 		return -2;
36cfb7
 
36cfb7
 	return 0;
36cfb7
diff --git a/ip/ipl2tp.c b/ip/ipl2tp.c
e138d9
index 88664c909e11f..742adbe4f9c3a 100644
36cfb7
--- a/ip/ipl2tp.c
36cfb7
+++ b/ip/ipl2tp.c
36cfb7
@@ -129,7 +129,7 @@ static int create_tunnel(struct l2tp_parm *p)
36cfb7
 			addattr(&req.n, 1024, L2TP_ATTR_UDP_ZERO_CSUM6_RX);
36cfb7
 	}
36cfb7
 
36cfb7
-	if (rtnl_talk(&genl_rth, &req.n, NULL, 0) < 0)
36cfb7
+	if (rtnl_talk(&genl_rth, &req.n, NULL) < 0)
36cfb7
 		return -2;
36cfb7
 
36cfb7
 	return 0;
36cfb7
@@ -142,7 +142,7 @@ static int delete_tunnel(struct l2tp_parm *p)
36cfb7
 
36cfb7
 	addattr32(&req.n, 128, L2TP_ATTR_CONN_ID, p->tunnel_id);
36cfb7
 
36cfb7
-	if (rtnl_talk(&genl_rth, &req.n, NULL, 0) < 0)
36cfb7
+	if (rtnl_talk(&genl_rth, &req.n, NULL) < 0)
36cfb7
 		return -2;
36cfb7
 
36cfb7
 	return 0;
36cfb7
@@ -185,7 +185,7 @@ static int create_session(struct l2tp_parm *p)
36cfb7
 	if (p->ifname && p->ifname[0])
36cfb7
 		addattrstrz(&req.n, 1024, L2TP_ATTR_IFNAME, p->ifname);
36cfb7
 
36cfb7
-	if (rtnl_talk(&genl_rth, &req.n, NULL, 0) < 0)
36cfb7
+	if (rtnl_talk(&genl_rth, &req.n, NULL) < 0)
36cfb7
 		return -2;
36cfb7
 
36cfb7
 	return 0;
36cfb7
@@ -198,7 +198,7 @@ static int delete_session(struct l2tp_parm *p)
36cfb7
 
36cfb7
 	addattr32(&req.n, 1024, L2TP_ATTR_CONN_ID, p->tunnel_id);
36cfb7
 	addattr32(&req.n, 1024, L2TP_ATTR_SESSION_ID, p->session_id);
36cfb7
-	if (rtnl_talk(&genl_rth, &req.n, NULL, 0) < 0)
36cfb7
+	if (rtnl_talk(&genl_rth, &req.n, NULL) < 0)
36cfb7
 		return -2;
36cfb7
 
36cfb7
 	return 0;
36cfb7
diff --git a/ip/iplink.c b/ip/iplink.c
e138d9
index 5afbadf0ce383..b08d227d44bee 100644
36cfb7
--- a/ip/iplink.c
36cfb7
+++ b/ip/iplink.c
36cfb7
@@ -247,19 +247,26 @@ static int nl_get_ll_addr_len(unsigned int dev_index)
36cfb7
 			.ifi_index = dev_index,
36cfb7
 		}
36cfb7
 	};
36cfb7
+	struct nlmsghdr *answer;
36cfb7
 	struct rtattr *tb[IFLA_MAX+1];
36cfb7
 
36cfb7
-	if (rtnl_talk(&rth, &req.n, &req.n, sizeof(req)) < 0)
36cfb7
+	if (rtnl_talk(&rth, &req.n, &answer) < 0)
36cfb7
 		return -1;
36cfb7
 
36cfb7
-	len = req.n.nlmsg_len - NLMSG_LENGTH(sizeof(req.i));
36cfb7
-	if (len < 0)
36cfb7
+	len = answer->nlmsg_len - NLMSG_LENGTH(sizeof(struct ifinfomsg));
36cfb7
+	if (len < 0) {
36cfb7
+		free(answer);
36cfb7
 		return -1;
36cfb7
+	}
36cfb7
 
36cfb7
-	parse_rtattr_flags(tb, IFLA_MAX, IFLA_RTA(&req.i), len, NLA_F_NESTED);
36cfb7
-	if (!tb[IFLA_ADDRESS])
36cfb7
+	parse_rtattr_flags(tb, IFLA_MAX, IFLA_RTA(NLMSG_DATA(answer)),
36cfb7
+			   len, NLA_F_NESTED);
36cfb7
+	if (!tb[IFLA_ADDRESS]) {
36cfb7
+		free(answer);
36cfb7
 		return -1;
36cfb7
+	}
36cfb7
 
36cfb7
+	free(answer);
36cfb7
 	return RTA_PAYLOAD(tb[IFLA_ADDRESS]);
36cfb7
 }
36cfb7
 
36cfb7
@@ -903,7 +910,7 @@ static int iplink_modify(int cmd, unsigned int flags, int argc, char **argv)
36cfb7
 
36cfb7
 			req.i.ifi_index = 0;
36cfb7
 			addattr32(&req.n, sizeof(req), IFLA_GROUP, group);
36cfb7
-			if (rtnl_talk(&rth, &req.n, NULL, 0) < 0)
36cfb7
+			if (rtnl_talk(&rth, &req.n, NULL) < 0)
36cfb7
 				return -2;
36cfb7
 			return 0;
36cfb7
 		}
36cfb7
@@ -998,7 +1005,7 @@ static int iplink_modify(int cmd, unsigned int flags, int argc, char **argv)
36cfb7
 		return -1;
36cfb7
 	}
36cfb7
 
36cfb7
-	if (rtnl_talk(&rth, &req.n, NULL, 0) < 0)
36cfb7
+	if (rtnl_talk(&rth, &req.n, NULL) < 0)
36cfb7
 		return -2;
36cfb7
 
36cfb7
 	return 0;
36cfb7
@@ -1013,10 +1020,7 @@ int iplink_get(unsigned int flags, char *name, __u32 filt_mask)
36cfb7
 		.n.nlmsg_type = RTM_GETLINK,
36cfb7
 		.i.ifi_family = preferred_family,
36cfb7
 	};
36cfb7
-	struct {
36cfb7
-		struct nlmsghdr n;
36cfb7
-		char buf[32768];
36cfb7
-	} answer;
36cfb7
+	struct nlmsghdr *answer;
36cfb7
 
36cfb7
 	if (name) {
36cfb7
 		len = strlen(name) + 1;
36cfb7
@@ -1029,19 +1033,15 @@ int iplink_get(unsigned int flags, char *name, __u32 filt_mask)
36cfb7
 	}
36cfb7
 	addattr32(&req.n, sizeof(req), IFLA_EXT_MASK, filt_mask);
36cfb7
 
36cfb7
-	if (rtnl_talk(&rth, &req.n, &answer.n, sizeof(answer)) < 0)
36cfb7
-		return -2;
36cfb7
-	if (answer.n.nlmsg_len > sizeof(answer.buf)) {
36cfb7
-		fprintf(stderr, "Message truncated from %u to %lu\n",
36cfb7
-			answer.n.nlmsg_len, sizeof(answer.buf));
36cfb7
+	if (rtnl_talk(&rth, &req.n, &answer) < 0)
36cfb7
 		return -2;
36cfb7
-	}
36cfb7
 
36cfb7
 	if (brief)
36cfb7
-		print_linkinfo_brief(NULL, &answer.n, stdout);
36cfb7
+		print_linkinfo_brief(NULL, answer, stdout);
36cfb7
 	else
36cfb7
-		print_linkinfo(NULL, &answer.n, stdout);
36cfb7
+		print_linkinfo(NULL, answer, stdout);
36cfb7
 
36cfb7
+	free(answer);
36cfb7
 	return 0;
36cfb7
 }
36cfb7
 
36cfb7
diff --git a/ip/iplink_vrf.c b/ip/iplink_vrf.c
e138d9
index 917630e853375..370bb86815a80 100644
36cfb7
--- a/ip/iplink_vrf.c
36cfb7
+++ b/ip/iplink_vrf.c
36cfb7
@@ -114,10 +114,7 @@ __u32 ipvrf_get_table(const char *name)
36cfb7
 			.ifi_family  = preferred_family,
36cfb7
 		},
36cfb7
 	};
36cfb7
-	struct {
36cfb7
-		struct nlmsghdr n;
36cfb7
-		char buf[8192];
36cfb7
-	} answer;
36cfb7
+	struct nlmsghdr *answer;
36cfb7
 	struct rtattr *tb[IFLA_MAX+1];
36cfb7
 	struct rtattr *li[IFLA_INFO_MAX+1];
36cfb7
 	struct rtattr *vrf_attr[IFLA_VRF_MAX + 1];
36cfb7
@@ -127,8 +124,7 @@ __u32 ipvrf_get_table(const char *name)
36cfb7
 
36cfb7
 	addattr_l(&req.n, sizeof(req), IFLA_IFNAME, name, strlen(name) + 1);
36cfb7
 
36cfb7
-	if (rtnl_talk_suppress_rtnl_errmsg(&rth, &req.n,
36cfb7
-					   &answer.n, sizeof(answer)) < 0) {
36cfb7
+	if (rtnl_talk_suppress_rtnl_errmsg(&rth, &req.n, &answer) < 0) {
36cfb7
 		/* special case "default" vrf to be the main table */
36cfb7
 		if (errno == ENODEV && !strcmp(name, "default"))
36cfb7
 			rtnl_rttable_a2n(&tb_id, "main");
36cfb7
@@ -136,25 +132,25 @@ __u32 ipvrf_get_table(const char *name)
36cfb7
 		return tb_id;
36cfb7
 	}
36cfb7
 
36cfb7
-	ifi = NLMSG_DATA(&answer.n);
36cfb7
-	len = answer.n.nlmsg_len - NLMSG_LENGTH(sizeof(*ifi));
36cfb7
+	ifi = NLMSG_DATA(answer);
36cfb7
+	len = answer->nlmsg_len - NLMSG_LENGTH(sizeof(*ifi));
36cfb7
 	if (len < 0) {
36cfb7
 		fprintf(stderr, "BUG: Invalid response to link query.\n");
36cfb7
-		return 0;
36cfb7
+		goto out;
36cfb7
 	}
36cfb7
 
36cfb7
 	parse_rtattr(tb, IFLA_MAX, IFLA_RTA(ifi), len);
36cfb7
 
36cfb7
 	if (!tb[IFLA_LINKINFO])
36cfb7
-		return 0;
36cfb7
+		goto out;
36cfb7
 
36cfb7
 	parse_rtattr_nested(li, IFLA_INFO_MAX, tb[IFLA_LINKINFO]);
36cfb7
 
36cfb7
 	if (!li[IFLA_INFO_KIND] || !li[IFLA_INFO_DATA])
36cfb7
-		return 0;
36cfb7
+		goto out;
36cfb7
 
36cfb7
 	if (strcmp(RTA_DATA(li[IFLA_INFO_KIND]), "vrf"))
36cfb7
-		return 0;
36cfb7
+		goto out;
36cfb7
 
36cfb7
 	parse_rtattr_nested(vrf_attr, IFLA_VRF_MAX, li[IFLA_INFO_DATA]);
36cfb7
 	if (vrf_attr[IFLA_VRF_TABLE])
36cfb7
@@ -163,6 +159,8 @@ __u32 ipvrf_get_table(const char *name)
36cfb7
 	if (!tb_id)
36cfb7
 		fprintf(stderr, "BUG: VRF %s is missing table id\n", name);
36cfb7
 
36cfb7
+out:
36cfb7
+	free(answer);
36cfb7
 	return tb_id;
36cfb7
 }
36cfb7
 
36cfb7
@@ -182,10 +180,7 @@ int name_is_vrf(const char *name)
36cfb7
 			.ifi_family  = preferred_family,
36cfb7
 		},
36cfb7
 	};
36cfb7
-	struct {
36cfb7
-		struct nlmsghdr n;
36cfb7
-		char buf[8192];
36cfb7
-	} answer;
36cfb7
+	struct nlmsghdr *answer;
36cfb7
 	struct rtattr *tb[IFLA_MAX+1];
36cfb7
 	struct rtattr *li[IFLA_INFO_MAX+1];
36cfb7
 	struct ifinfomsg *ifi;
36cfb7
@@ -193,29 +188,30 @@ int name_is_vrf(const char *name)
36cfb7
 
36cfb7
 	addattr_l(&req.n, sizeof(req), IFLA_IFNAME, name, strlen(name) + 1);
36cfb7
 
36cfb7
-	if (rtnl_talk_suppress_rtnl_errmsg(&rth, &req.n,
36cfb7
-					   &answer.n, sizeof(answer)) < 0)
36cfb7
+	if (rtnl_talk_suppress_rtnl_errmsg(&rth, &req.n, &answer) < 0)
36cfb7
 		return 0;
36cfb7
 
36cfb7
-	ifi = NLMSG_DATA(&answer.n);
36cfb7
-	len = answer.n.nlmsg_len - NLMSG_LENGTH(sizeof(*ifi));
36cfb7
+	ifi = NLMSG_DATA(answer);
36cfb7
+	len = answer->nlmsg_len - NLMSG_LENGTH(sizeof(*ifi));
36cfb7
 	if (len < 0) {
36cfb7
 		fprintf(stderr, "BUG: Invalid response to link query.\n");
36cfb7
-		return 0;
36cfb7
+		goto out;
36cfb7
 	}
36cfb7
 
36cfb7
 	parse_rtattr(tb, IFLA_MAX, IFLA_RTA(ifi), len);
36cfb7
 
36cfb7
 	if (!tb[IFLA_LINKINFO])
36cfb7
-		return 0;
36cfb7
+		goto out;
36cfb7
 
36cfb7
 	parse_rtattr_nested(li, IFLA_INFO_MAX, tb[IFLA_LINKINFO]);
36cfb7
 
36cfb7
 	if (!li[IFLA_INFO_KIND])
36cfb7
-		return 0;
36cfb7
+		goto out;
36cfb7
 
36cfb7
 	if (strcmp(RTA_DATA(li[IFLA_INFO_KIND]), "vrf"))
36cfb7
-		return 0;
36cfb7
+		goto out;
36cfb7
 
36cfb7
+out:
36cfb7
+	free(answer);
36cfb7
 	return ifi->ifi_index;
36cfb7
 }
36cfb7
diff --git a/ip/ipmacsec.c b/ip/ipmacsec.c
e138d9
index aa89a00f5aad6..9a2d0ebf82091 100644
36cfb7
--- a/ip/ipmacsec.c
36cfb7
+++ b/ip/ipmacsec.c
36cfb7
@@ -421,7 +421,7 @@ static int do_modify_nl(enum cmd c, enum macsec_nl_commands cmd, int ifindex,
36cfb7
 	addattr_nest_end(&req.n, attr_sa);
36cfb7
 
36cfb7
 talk:
36cfb7
-	if (rtnl_talk(&genl_rth, &req.n, NULL, 0) < 0)
36cfb7
+	if (rtnl_talk(&genl_rth, &req.n, NULL) < 0)
36cfb7
 		return -2;
36cfb7
 
36cfb7
 	return 0;
36cfb7
diff --git a/ip/ipneigh.c b/ip/ipneigh.c
e138d9
index 9c38a60ddf4fe..32f2d553c712f 100644
36cfb7
--- a/ip/ipneigh.c
36cfb7
+++ b/ip/ipneigh.c
36cfb7
@@ -184,7 +184,7 @@ static int ipneigh_modify(int cmd, int flags, int argc, char **argv)
36cfb7
 		return -1;
36cfb7
 	}
36cfb7
 
36cfb7
-	if (rtnl_talk(&rth, &req.n, NULL, 0) < 0)
36cfb7
+	if (rtnl_talk(&rth, &req.n, NULL) < 0)
36cfb7
 		exit(2);
36cfb7
 
36cfb7
 	return 0;
36cfb7
diff --git a/ip/ipnetns.c b/ip/ipnetns.c
e138d9
index 4254994442ccd..1c0ade90dee5e 100644
36cfb7
--- a/ip/ipnetns.c
36cfb7
+++ b/ip/ipnetns.c
36cfb7
@@ -95,12 +95,13 @@ static int get_netnsid_from_name(const char *name)
36cfb7
 		struct nlmsghdr n;
36cfb7
 		struct rtgenmsg g;
36cfb7
 		char            buf[1024];
36cfb7
-	} answer, req = {
36cfb7
+	} req = {
36cfb7
 		.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtgenmsg)),
36cfb7
 		.n.nlmsg_flags = NLM_F_REQUEST,
36cfb7
 		.n.nlmsg_type = RTM_GETNSID,
36cfb7
 		.g.rtgen_family = AF_UNSPEC,
36cfb7
 	};
36cfb7
+	struct nlmsghdr *answer;
36cfb7
 	struct rtattr *tb[NETNSA_MAX + 1];
36cfb7
 	struct rtgenmsg *rthdr;
36cfb7
 	int len, fd;
36cfb7
@@ -110,26 +111,30 @@ static int get_netnsid_from_name(const char *name)
36cfb7
 		return fd;
36cfb7
 
36cfb7
 	addattr32(&req.n, 1024, NETNSA_FD, fd);
36cfb7
-	if (rtnl_talk(&rtnsh, &req.n, &answer.n, sizeof(answer)) < 0) {
36cfb7
+	if (rtnl_talk(&rtnsh, &req.n, &answer) < 0) {
36cfb7
 		close(fd);
36cfb7
 		return -2;
36cfb7
 	}
36cfb7
 	close(fd);
36cfb7
 
36cfb7
 	/* Validate message and parse attributes */
36cfb7
-	if (answer.n.nlmsg_type == NLMSG_ERROR)
36cfb7
-		return -1;
36cfb7
+	if (answer->nlmsg_type == NLMSG_ERROR)
36cfb7
+		goto err_out;
36cfb7
 
36cfb7
-	rthdr = NLMSG_DATA(&answer.n);
36cfb7
-	len = answer.n.nlmsg_len - NLMSG_SPACE(sizeof(*rthdr));
36cfb7
+	rthdr = NLMSG_DATA(answer);
36cfb7
+	len = answer->nlmsg_len - NLMSG_SPACE(sizeof(*rthdr));
36cfb7
 	if (len < 0)
36cfb7
-		return -1;
36cfb7
+		goto err_out;
36cfb7
 
36cfb7
 	parse_rtattr(tb, NETNSA_MAX, NETNS_RTA(rthdr), len);
36cfb7
 
36cfb7
-	if (tb[NETNSA_NSID])
36cfb7
+	if (tb[NETNSA_NSID]) {
36cfb7
+		free(answer);
36cfb7
 		return rta_getattr_u32(tb[NETNSA_NSID]);
36cfb7
+	}
36cfb7
 
36cfb7
+err_out:
36cfb7
+	free(answer);
36cfb7
 	return -1;
36cfb7
 }
36cfb7
 
36cfb7
@@ -690,7 +695,7 @@ static int set_netnsid_from_name(const char *name, int nsid)
36cfb7
 
36cfb7
 	addattr32(&req.n, 1024, NETNSA_FD, fd);
36cfb7
 	addattr32(&req.n, 1024, NETNSA_NSID, nsid);
36cfb7
-	if (rtnl_talk(&rth, &req.n, NULL, 0) < 0)
36cfb7
+	if (rtnl_talk(&rth, &req.n, NULL) < 0)
36cfb7
 		err = -2;
36cfb7
 
36cfb7
 	close(fd);
36cfb7
diff --git a/ip/ipntable.c b/ip/ipntable.c
e138d9
index 879626ee4f491..65063321c85f8 100644
36cfb7
--- a/ip/ipntable.c
36cfb7
+++ b/ip/ipntable.c
36cfb7
@@ -306,7 +306,7 @@ static int ipntable_modify(int cmd, int flags, int argc, char **argv)
36cfb7
 			  RTA_PAYLOAD(parms_rta));
36cfb7
 	}
36cfb7
 
36cfb7
-	if (rtnl_talk(&rth, &req.n, NULL, 0) < 0)
36cfb7
+	if (rtnl_talk(&rth, &req.n, NULL) < 0)
36cfb7
 		exit(2);
36cfb7
 
36cfb7
 	return 0;
36cfb7
diff --git a/ip/iproute.c b/ip/iproute.c
e138d9
index 5e23613dadbaf..35fdce8a64f35 100644
36cfb7
--- a/ip/iproute.c
36cfb7
+++ b/ip/iproute.c
36cfb7
@@ -1271,7 +1271,7 @@ static int iproute_modify(int cmd, unsigned int flags, int argc, char **argv)
36cfb7
 	if (!type_ok && req.r.rtm_family == AF_MPLS)
36cfb7
 		req.r.rtm_type = RTN_UNICAST;
36cfb7
 
36cfb7
-	if (rtnl_talk(&rth, &req.n, NULL, 0) < 0)
36cfb7
+	if (rtnl_talk(&rth, &req.n, NULL) < 0)
36cfb7
 		return -2;
36cfb7
 
36cfb7
 	return 0;
36cfb7
@@ -1649,6 +1649,7 @@ static int iproute_get(int argc, char **argv)
36cfb7
 	};
36cfb7
 	char  *idev = NULL;
36cfb7
 	char  *odev = NULL;
36cfb7
+	struct nlmsghdr *answer;
36cfb7
 	int connected = 0;
36cfb7
 	int from_ok = 0;
36cfb7
 	unsigned int mark = 0;
36cfb7
@@ -1753,26 +1754,29 @@ static int iproute_get(int argc, char **argv)
36cfb7
 
36cfb7
 	req.r.rtm_flags |= RTM_F_LOOKUP_TABLE;
36cfb7
 
36cfb7
-	if (rtnl_talk(&rth, &req.n, &req.n, sizeof(req)) < 0)
36cfb7
+	if (rtnl_talk(&rth, &req.n, &answer) < 0)
36cfb7
 		return -2;
36cfb7
 
36cfb7
 	if (connected && !from_ok) {
36cfb7
-		struct rtmsg *r = NLMSG_DATA(&req.n);
36cfb7
-		int len = req.n.nlmsg_len;
36cfb7
+		struct rtmsg *r = NLMSG_DATA(answer);
36cfb7
+		int len = answer->nlmsg_len;
36cfb7
 		struct rtattr *tb[RTA_MAX+1];
36cfb7
 
36cfb7
-		if (print_route(NULL, &req.n, (void *)stdout) < 0) {
36cfb7
+		if (print_route(NULL, answer, (void *)stdout) < 0) {
36cfb7
 			fprintf(stderr, "An error :-)\n");
36cfb7
+			free(answer);
36cfb7
 			return -1;
36cfb7
 		}
36cfb7
 
36cfb7
-		if (req.n.nlmsg_type != RTM_NEWROUTE) {
36cfb7
+		if (answer->nlmsg_type != RTM_NEWROUTE) {
36cfb7
 			fprintf(stderr, "Not a route?\n");
36cfb7
+			free(answer);
36cfb7
 			return -1;
36cfb7
 		}
36cfb7
 		len -= NLMSG_LENGTH(sizeof(*r));
36cfb7
 		if (len < 0) {
36cfb7
 			fprintf(stderr, "Wrong len %d\n", len);
36cfb7
+			free(answer);
36cfb7
 			return -1;
36cfb7
 		}
36cfb7
 
36cfb7
@@ -1783,6 +1787,7 @@ static int iproute_get(int argc, char **argv)
36cfb7
 			r->rtm_src_len = 8*RTA_PAYLOAD(tb[RTA_PREFSRC]);
36cfb7
 		} else if (!tb[RTA_SRC]) {
36cfb7
 			fprintf(stderr, "Failed to connect the route\n");
36cfb7
+			free(answer);
36cfb7
 			return -1;
36cfb7
 		}
36cfb7
 		if (!odev && tb[RTA_OIF])
36cfb7
@@ -1796,15 +1801,18 @@ static int iproute_get(int argc, char **argv)
36cfb7
 		req.n.nlmsg_flags = NLM_F_REQUEST;
36cfb7
 		req.n.nlmsg_type = RTM_GETROUTE;
36cfb7
 
36cfb7
-		if (rtnl_talk(&rth, &req.n, &req.n, sizeof(req)) < 0)
36cfb7
+		free(answer);
36cfb7
+		if (rtnl_talk(&rth, &req.n, &answer) < 0)
36cfb7
 			return -2;
36cfb7
 	}
36cfb7
 
36cfb7
-	if (print_route(NULL, &req.n, (void *)stdout) < 0) {
36cfb7
+	if (print_route(NULL, answer, (void *)stdout) < 0) {
36cfb7
 		fprintf(stderr, "An error :-)\n");
36cfb7
+		free(answer);
36cfb7
 		return -1;
36cfb7
 	}
36cfb7
 
36cfb7
+	free(answer);
36cfb7
 	return 0;
36cfb7
 }
36cfb7
 
36cfb7
@@ -1848,7 +1856,7 @@ restore:
36cfb7
 
36cfb7
 	ll_init_map(&rth);
36cfb7
 
36cfb7
-	ret = rtnl_talk(&rth, n, n, sizeof(*n));
36cfb7
+	ret = rtnl_talk(&rth, n, NULL);
36cfb7
 	if ((ret < 0) && (errno == EEXIST))
36cfb7
 		ret = 0;
36cfb7
 
36cfb7
diff --git a/ip/iprule.c b/ip/iprule.c
e138d9
index 8313138db815f..e64b4d7db2815 100644
36cfb7
--- a/ip/iprule.c
36cfb7
+++ b/ip/iprule.c
36cfb7
@@ -393,7 +393,7 @@ static int flush_rule(const struct sockaddr_nl *who, struct nlmsghdr *n,
36cfb7
 		if (rtnl_open(&rth2, 0) < 0)
36cfb7
 			return -1;
36cfb7
 
36cfb7
-		if (rtnl_talk(&rth2, n, NULL, 0) < 0)
36cfb7
+		if (rtnl_talk(&rth2, n, NULL) < 0)
36cfb7
 			return -2;
36cfb7
 
36cfb7
 		rtnl_close(&rth2;;
36cfb7
@@ -553,7 +553,7 @@ static int restore_handler(const struct sockaddr_nl *nl,
36cfb7
 
36cfb7
 	ll_init_map(&rth);
36cfb7
 
36cfb7
-	ret = rtnl_talk(&rth, n, n, sizeof(*n));
36cfb7
+	ret = rtnl_talk(&rth, n, NULL);
36cfb7
 	if ((ret < 0) && (errno == EEXIST))
36cfb7
 		ret = 0;
36cfb7
 
36cfb7
@@ -760,7 +760,7 @@ static int iprule_modify(int cmd, int argc, char **argv)
36cfb7
 	if (!table_ok && cmd == RTM_NEWRULE)
36cfb7
 		req.r.rtm_table = RT_TABLE_MAIN;
36cfb7
 
36cfb7
-	if (rtnl_talk(&rth, &req.n, NULL, 0) < 0)
36cfb7
+	if (rtnl_talk(&rth, &req.n, NULL) < 0)
36cfb7
 		return -2;
36cfb7
 
36cfb7
 	return 0;
36cfb7
diff --git a/ip/iptoken.c b/ip/iptoken.c
e138d9
index 1869f764424ff..0528bad70a80e 100644
36cfb7
--- a/ip/iptoken.c
36cfb7
+++ b/ip/iptoken.c
36cfb7
@@ -166,7 +166,7 @@ static int iptoken_set(int argc, char **argv, bool delete)
36cfb7
 	addattr_nest_end(&req.n, afs6);
36cfb7
 	addattr_nest_end(&req.n, afs);
36cfb7
 
36cfb7
-	if (rtnl_talk(&rth, &req.n, NULL, 0) < 0)
36cfb7
+	if (rtnl_talk(&rth, &req.n, NULL) < 0)
36cfb7
 		return -2;
36cfb7
 
36cfb7
 	return 0;
36cfb7
diff --git a/ip/link_gre.c b/ip/link_gre.c
e138d9
index 35d437a15562c..ced993692e6f6 100644
36cfb7
--- a/ip/link_gre.c
36cfb7
+++ b/ip/link_gre.c
36cfb7
@@ -64,7 +64,6 @@ static int gre_parse_opt(struct link_util *lu, int argc, char **argv,
36cfb7
 	struct {
36cfb7
 		struct nlmsghdr n;
36cfb7
 		struct ifinfomsg i;
36cfb7
-		char buf[16384];
36cfb7
 	} req = {
36cfb7
 		.n.nlmsg_len = NLMSG_LENGTH(sizeof(*ifi)),
36cfb7
 		.n.nlmsg_flags = NLM_F_REQUEST,
36cfb7
@@ -72,6 +71,7 @@ static int gre_parse_opt(struct link_util *lu, int argc, char **argv,
36cfb7
 		.i.ifi_family = preferred_family,
36cfb7
 		.i.ifi_index = ifi->ifi_index,
36cfb7
 	};
36cfb7
+	struct nlmsghdr *answer = NULL;
36cfb7
 	struct rtattr *tb[IFLA_MAX + 1];
36cfb7
 	struct rtattr *linkinfo[IFLA_INFO_MAX+1];
36cfb7
 	struct rtattr *greinfo[IFLA_GRE_MAX + 1];
36cfb7
@@ -93,19 +93,20 @@ static int gre_parse_opt(struct link_util *lu, int argc, char **argv,
36cfb7
 	__u8 metadata = 0;
36cfb7
 
36cfb7
 	if (!(n->nlmsg_flags & NLM_F_CREATE)) {
36cfb7
-		if (rtnl_talk(&rth, &req.n, &req.n, sizeof(req)) < 0) {
36cfb7
+		if (rtnl_talk(&rth, &req.n, &answer) < 0) {
36cfb7
 get_failed:
36cfb7
 			fprintf(stderr,
36cfb7
 				"Failed to get existing tunnel info.\n");
36cfb7
+			free(answer);
36cfb7
 			return -1;
36cfb7
 		}
36cfb7
 
36cfb7
-		len = req.n.nlmsg_len;
36cfb7
+		len = answer->nlmsg_len;
36cfb7
 		len -= NLMSG_LENGTH(sizeof(*ifi));
36cfb7
 		if (len < 0)
36cfb7
 			goto get_failed;
36cfb7
 
36cfb7
-		parse_rtattr(tb, IFLA_MAX, IFLA_RTA(&req.i), len);
36cfb7
+		parse_rtattr(tb, IFLA_MAX, IFLA_RTA(NLMSG_DATA(answer)), len);
36cfb7
 
36cfb7
 		if (!tb[IFLA_LINKINFO])
36cfb7
 			goto get_failed;
36cfb7
@@ -160,6 +161,8 @@ get_failed:
36cfb7
 
36cfb7
 		if (greinfo[IFLA_GRE_COLLECT_METADATA])
36cfb7
 			metadata = 1;
36cfb7
+
36cfb7
+		free(answer);
36cfb7
 	}
36cfb7
 
36cfb7
 	while (argc > 0) {
36cfb7
diff --git a/ip/link_gre6.c b/ip/link_gre6.c
e138d9
index fe3ab641a86c2..932f9ee96124d 100644
36cfb7
--- a/ip/link_gre6.c
36cfb7
+++ b/ip/link_gre6.c
36cfb7
@@ -76,7 +76,6 @@ static int gre_parse_opt(struct link_util *lu, int argc, char **argv,
36cfb7
 	struct {
36cfb7
 		struct nlmsghdr n;
36cfb7
 		struct ifinfomsg i;
36cfb7
-		char buf[1024];
36cfb7
 	} req = {
36cfb7
 		.n.nlmsg_len = NLMSG_LENGTH(sizeof(*ifi)),
36cfb7
 		.n.nlmsg_flags = NLM_F_REQUEST,
36cfb7
@@ -84,6 +83,7 @@ static int gre_parse_opt(struct link_util *lu, int argc, char **argv,
36cfb7
 		.i.ifi_family = preferred_family,
36cfb7
 		.i.ifi_index = ifi->ifi_index,
36cfb7
 	};
36cfb7
+	struct nlmsghdr *answer = NULL;
36cfb7
 	struct rtattr *tb[IFLA_MAX + 1];
36cfb7
 	struct rtattr *linkinfo[IFLA_INFO_MAX+1];
36cfb7
 	struct rtattr *greinfo[IFLA_GRE_MAX + 1];
36cfb7
@@ -105,19 +105,20 @@ static int gre_parse_opt(struct link_util *lu, int argc, char **argv,
36cfb7
 	int len;
36cfb7
 
36cfb7
 	if (!(n->nlmsg_flags & NLM_F_CREATE)) {
36cfb7
-		if (rtnl_talk(&rth, &req.n, &req.n, sizeof(req)) < 0) {
36cfb7
+		if (rtnl_talk(&rth, &req.n, &answer) < 0) {
36cfb7
 get_failed:
36cfb7
 			fprintf(stderr,
36cfb7
 				"Failed to get existing tunnel info.\n");
36cfb7
+			free(answer);
36cfb7
 			return -1;
36cfb7
 		}
36cfb7
 
36cfb7
-		len = req.n.nlmsg_len;
36cfb7
+		len = answer->nlmsg_len;
36cfb7
 		len -= NLMSG_LENGTH(sizeof(*ifi));
36cfb7
 		if (len < 0)
36cfb7
 			goto get_failed;
36cfb7
 
36cfb7
-		parse_rtattr(tb, IFLA_MAX, IFLA_RTA(&req.i), len);
36cfb7
+		parse_rtattr(tb, IFLA_MAX, IFLA_RTA(NLMSG_DATA(answer)), len);
36cfb7
 
36cfb7
 		if (!tb[IFLA_LINKINFO])
36cfb7
 			goto get_failed;
36cfb7
@@ -174,6 +175,8 @@ get_failed:
36cfb7
 
36cfb7
 		if (greinfo[IFLA_GRE_ENCAP_DPORT])
36cfb7
 			encapdport = rta_getattr_u16(greinfo[IFLA_GRE_ENCAP_DPORT]);
36cfb7
+
36cfb7
+		free(answer);
36cfb7
 	}
36cfb7
 
36cfb7
 	while (argc > 0) {
36cfb7
diff --git a/ip/link_ip6tnl.c b/ip/link_ip6tnl.c
e138d9
index 6bb968d3c9189..230436437fffb 100644
36cfb7
--- a/ip/link_ip6tnl.c
36cfb7
+++ b/ip/link_ip6tnl.c
36cfb7
@@ -74,7 +74,6 @@ static int ip6tunnel_parse_opt(struct link_util *lu, int argc, char **argv,
36cfb7
 	struct {
36cfb7
 		struct nlmsghdr n;
36cfb7
 		struct ifinfomsg i;
36cfb7
-		char buf[2048];
36cfb7
 	} req = {
36cfb7
 		.n.nlmsg_len = NLMSG_LENGTH(sizeof(*ifi)),
36cfb7
 		.n.nlmsg_flags = NLM_F_REQUEST,
36cfb7
@@ -82,6 +81,7 @@ static int ip6tunnel_parse_opt(struct link_util *lu, int argc, char **argv,
36cfb7
 		.i.ifi_family = preferred_family,
36cfb7
 		.i.ifi_index = ifi->ifi_index,
36cfb7
 	};
36cfb7
+	struct nlmsghdr *answer = NULL;
36cfb7
 	struct rtattr *tb[IFLA_MAX + 1];
36cfb7
 	struct rtattr *linkinfo[IFLA_INFO_MAX+1];
36cfb7
 	struct rtattr *iptuninfo[IFLA_IPTUN_MAX + 1];
36cfb7
@@ -101,19 +101,20 @@ static int ip6tunnel_parse_opt(struct link_util *lu, int argc, char **argv,
36cfb7
 	__u8 metadata = 0;
36cfb7
 
36cfb7
 	if (!(n->nlmsg_flags & NLM_F_CREATE)) {
36cfb7
-		if (rtnl_talk(&rth, &req.n, &req.n, sizeof(req)) < 0) {
36cfb7
+		if (rtnl_talk(&rth, &req.n, &answer) < 0) {
36cfb7
 get_failed:
36cfb7
 			fprintf(stderr,
36cfb7
 				"Failed to get existing tunnel info.\n");
36cfb7
+			free(answer);
36cfb7
 			return -1;
36cfb7
 		}
36cfb7
 
36cfb7
-		len = req.n.nlmsg_len;
36cfb7
+		len = answer->nlmsg_len;
36cfb7
 		len -= NLMSG_LENGTH(sizeof(*ifi));
36cfb7
 		if (len < 0)
36cfb7
 			goto get_failed;
36cfb7
 
36cfb7
-		parse_rtattr(tb, IFLA_MAX, IFLA_RTA(&req.i), len);
36cfb7
+		parse_rtattr(tb, IFLA_MAX, IFLA_RTA(NLMSG_DATA(answer)), len);
36cfb7
 
36cfb7
 		if (!tb[IFLA_LINKINFO])
36cfb7
 			goto get_failed;
36cfb7
@@ -153,6 +154,8 @@ get_failed:
36cfb7
 			proto = rta_getattr_u8(iptuninfo[IFLA_IPTUN_PROTO]);
36cfb7
 		if (iptuninfo[IFLA_IPTUN_COLLECT_METADATA])
36cfb7
 			metadata = 1;
36cfb7
+
36cfb7
+		free(answer);
36cfb7
 	}
36cfb7
 
36cfb7
 	while (argc > 0) {
36cfb7
diff --git a/ip/link_iptnl.c b/ip/link_iptnl.c
e138d9
index f180b921e4710..528e287814f6b 100644
36cfb7
--- a/ip/link_iptnl.c
36cfb7
+++ b/ip/link_iptnl.c
36cfb7
@@ -72,7 +72,6 @@ static int iptunnel_parse_opt(struct link_util *lu, int argc, char **argv,
36cfb7
 	struct {
36cfb7
 		struct nlmsghdr n;
36cfb7
 		struct ifinfomsg i;
36cfb7
-		char buf[2048];
36cfb7
 	} req = {
36cfb7
 		.n.nlmsg_len = NLMSG_LENGTH(sizeof(*ifi)),
36cfb7
 		.n.nlmsg_flags = NLM_F_REQUEST,
36cfb7
@@ -80,6 +79,7 @@ static int iptunnel_parse_opt(struct link_util *lu, int argc, char **argv,
36cfb7
 		.i.ifi_family = preferred_family,
36cfb7
 		.i.ifi_index = ifi->ifi_index,
36cfb7
 	};
36cfb7
+	struct nlmsghdr *answer = NULL;
36cfb7
 	struct rtattr *tb[IFLA_MAX + 1];
36cfb7
 	struct rtattr *linkinfo[IFLA_INFO_MAX+1];
36cfb7
 	struct rtattr *iptuninfo[IFLA_IPTUN_MAX + 1];
36cfb7
@@ -103,19 +103,20 @@ static int iptunnel_parse_opt(struct link_util *lu, int argc, char **argv,
36cfb7
 	__u8 metadata = 0;
36cfb7
 
36cfb7
 	if (!(n->nlmsg_flags & NLM_F_CREATE)) {
36cfb7
-		if (rtnl_talk(&rth, &req.n, &req.n, sizeof(req)) < 0) {
36cfb7
+		if (rtnl_talk(&rth, &req.n, &answer) < 0) {
36cfb7
 get_failed:
36cfb7
 			fprintf(stderr,
36cfb7
 				"Failed to get existing tunnel info.\n");
36cfb7
+			free(answer);
36cfb7
 			return -1;
36cfb7
 		}
36cfb7
 
36cfb7
-		len = req.n.nlmsg_len;
36cfb7
+		len = answer->nlmsg_len;
36cfb7
 		len -= NLMSG_LENGTH(sizeof(*ifi));
36cfb7
 		if (len < 0)
36cfb7
 			goto get_failed;
36cfb7
 
36cfb7
-		parse_rtattr(tb, IFLA_MAX, IFLA_RTA(&req.i), len);
36cfb7
+		parse_rtattr(tb, IFLA_MAX, IFLA_RTA(NLMSG_DATA(answer)), len);
36cfb7
 
36cfb7
 		if (!tb[IFLA_LINKINFO])
36cfb7
 			goto get_failed;
36cfb7
@@ -179,6 +180,8 @@ get_failed:
36cfb7
 				rta_getattr_u16(iptuninfo[IFLA_IPTUN_6RD_RELAY_PREFIXLEN]);
36cfb7
 		if (iptuninfo[IFLA_IPTUN_COLLECT_METADATA])
36cfb7
 			metadata = 1;
36cfb7
+
36cfb7
+		free(answer);
36cfb7
 	}
36cfb7
 
36cfb7
 	while (argc > 0) {
36cfb7
diff --git a/ip/link_vti.c b/ip/link_vti.c
e138d9
index 95bc23e928972..d2aacbe78ded1 100644
36cfb7
--- a/ip/link_vti.c
36cfb7
+++ b/ip/link_vti.c
36cfb7
@@ -51,7 +51,6 @@ static int vti_parse_opt(struct link_util *lu, int argc, char **argv,
36cfb7
 	struct {
36cfb7
 		struct nlmsghdr n;
36cfb7
 		struct ifinfomsg i;
36cfb7
-		char buf[1024];
36cfb7
 	} req = {
36cfb7
 		.n.nlmsg_len = NLMSG_LENGTH(sizeof(*ifi)),
36cfb7
 		.n.nlmsg_flags = NLM_F_REQUEST,
36cfb7
@@ -59,6 +58,7 @@ static int vti_parse_opt(struct link_util *lu, int argc, char **argv,
36cfb7
 		.i.ifi_family = preferred_family,
36cfb7
 		.i.ifi_index = ifi->ifi_index,
36cfb7
 	};
36cfb7
+	struct nlmsghdr *answer = NULL;
36cfb7
 	struct rtattr *tb[IFLA_MAX + 1];
36cfb7
 	struct rtattr *linkinfo[IFLA_INFO_MAX+1];
36cfb7
 	struct rtattr *vtiinfo[IFLA_VTI_MAX + 1];
36cfb7
@@ -70,19 +70,20 @@ static int vti_parse_opt(struct link_util *lu, int argc, char **argv,
36cfb7
 	int len;
36cfb7
 
36cfb7
 	if (!(n->nlmsg_flags & NLM_F_CREATE)) {
36cfb7
-		if (rtnl_talk(&rth, &req.n, &req.n, sizeof(req)) < 0) {
36cfb7
+		if (rtnl_talk(&rth, &req.n, &answer) < 0) {
36cfb7
 get_failed:
36cfb7
 			fprintf(stderr,
36cfb7
 				"Failed to get existing tunnel info.\n");
36cfb7
+			free(answer);
36cfb7
 			return -1;
36cfb7
 		}
36cfb7
 
36cfb7
-		len = req.n.nlmsg_len;
36cfb7
+		len = answer->nlmsg_len;
36cfb7
 		len -= NLMSG_LENGTH(sizeof(*ifi));
36cfb7
 		if (len < 0)
36cfb7
 			goto get_failed;
36cfb7
 
36cfb7
-		parse_rtattr(tb, IFLA_MAX, IFLA_RTA(&req.i), len);
36cfb7
+		parse_rtattr(tb, IFLA_MAX, IFLA_RTA(NLMSG_DATA(answer)), len);
36cfb7
 
36cfb7
 		if (!tb[IFLA_LINKINFO])
36cfb7
 			goto get_failed;
36cfb7
@@ -109,6 +110,8 @@ get_failed:
36cfb7
 
36cfb7
 		if (vtiinfo[IFLA_VTI_LINK])
36cfb7
 			link = rta_getattr_u8(vtiinfo[IFLA_VTI_LINK]);
36cfb7
+
36cfb7
+		free(answer);
36cfb7
 	}
36cfb7
 
36cfb7
 	while (argc > 0) {
36cfb7
diff --git a/ip/link_vti6.c b/ip/link_vti6.c
e138d9
index 9ca127af8a5d5..aedfbeaeea0e1 100644
36cfb7
--- a/ip/link_vti6.c
36cfb7
+++ b/ip/link_vti6.c
36cfb7
@@ -46,7 +46,6 @@ static int vti6_parse_opt(struct link_util *lu, int argc, char **argv,
36cfb7
 	struct {
36cfb7
 		struct nlmsghdr n;
36cfb7
 		struct ifinfomsg i;
36cfb7
-		char buf[1024];
36cfb7
 	} req = {
36cfb7
 		.n.nlmsg_len = NLMSG_LENGTH(sizeof(*ifi)),
36cfb7
 		.n.nlmsg_flags = NLM_F_REQUEST,
36cfb7
@@ -54,6 +53,7 @@ static int vti6_parse_opt(struct link_util *lu, int argc, char **argv,
36cfb7
 		.i.ifi_family = preferred_family,
36cfb7
 		.i.ifi_index = ifi->ifi_index,
36cfb7
 	};
36cfb7
+	struct nlmsghdr *answer = NULL;
36cfb7
 	struct rtattr *tb[IFLA_MAX + 1];
36cfb7
 	struct rtattr *linkinfo[IFLA_INFO_MAX+1];
36cfb7
 	struct rtattr *vtiinfo[IFLA_VTI_MAX + 1];
36cfb7
@@ -65,19 +65,20 @@ static int vti6_parse_opt(struct link_util *lu, int argc, char **argv,
36cfb7
 	int len;
36cfb7
 
36cfb7
 	if (!(n->nlmsg_flags & NLM_F_CREATE)) {
36cfb7
-		if (rtnl_talk(&rth, &req.n, &req.n, sizeof(req)) < 0) {
36cfb7
+		if (rtnl_talk(&rth, &req.n, &answer) < 0) {
36cfb7
 get_failed:
36cfb7
 			fprintf(stderr,
36cfb7
 				"Failed to get existing tunnel info.\n");
36cfb7
+			free(answer);
36cfb7
 			return -1;
36cfb7
 		}
36cfb7
 
36cfb7
-		len = req.n.nlmsg_len;
36cfb7
+		len = answer->nlmsg_len;
36cfb7
 		len -= NLMSG_LENGTH(sizeof(*ifi));
36cfb7
 		if (len < 0)
36cfb7
 			goto get_failed;
36cfb7
 
36cfb7
-		parse_rtattr(tb, IFLA_MAX, IFLA_RTA(&req.i), len);
36cfb7
+		parse_rtattr(tb, IFLA_MAX, IFLA_RTA(NLMSG_DATA(answer)), len);
36cfb7
 
36cfb7
 		if (!tb[IFLA_LINKINFO])
36cfb7
 			goto get_failed;
36cfb7
@@ -104,6 +105,8 @@ get_failed:
36cfb7
 
36cfb7
 		if (vtiinfo[IFLA_VTI_LINK])
36cfb7
 			link = rta_getattr_u8(vtiinfo[IFLA_VTI_LINK]);
36cfb7
+
36cfb7
+		free(answer);
36cfb7
 	}
36cfb7
 
36cfb7
 	while (argc > 0) {
36cfb7
diff --git a/ip/tcp_metrics.c b/ip/tcp_metrics.c
e138d9
index 8972acd05fb28..3f9790e8fedde 100644
36cfb7
--- a/ip/tcp_metrics.c
36cfb7
+++ b/ip/tcp_metrics.c
36cfb7
@@ -306,6 +306,7 @@ static int process_msg(const struct sockaddr_nl *who, struct nlmsghdr *n,
36cfb7
 static int tcpm_do_cmd(int cmd, int argc, char **argv)
36cfb7
 {
36cfb7
 	TCPM_REQUEST(req, 1024, TCP_METRICS_CMD_GET, NLM_F_REQUEST);
36cfb7
+	struct nlmsghdr *answer;
36cfb7
 	int atype = -1, stype = -1;
36cfb7
 	int ack;
36cfb7
 
36cfb7
@@ -457,15 +458,16 @@ static int tcpm_do_cmd(int cmd, int argc, char **argv)
36cfb7
 	}
36cfb7
 
36cfb7
 	if (ack) {
36cfb7
-		if (rtnl_talk(&grth, &req.n, NULL, 0) < 0)
36cfb7
+		if (rtnl_talk(&grth, &req.n, NULL) < 0)
36cfb7
 			return -2;
36cfb7
 	} else if (atype >= 0) {
36cfb7
-		if (rtnl_talk(&grth, &req.n, &req.n, sizeof(req)) < 0)
36cfb7
+		if (rtnl_talk(&grth, &req.n, &answer) < 0)
36cfb7
 			return -2;
36cfb7
-		if (process_msg(NULL, &req.n, stdout) < 0) {
36cfb7
+		if (process_msg(NULL, answer, stdout) < 0) {
36cfb7
 			fprintf(stderr, "Dump terminated\n");
36cfb7
 			exit(1);
36cfb7
 		}
36cfb7
+		free(answer);
36cfb7
 	} else {
36cfb7
 		req.n.nlmsg_seq = grth.dump = ++grth.seq;
36cfb7
 		if (rtnl_send(&grth, &req, req.n.nlmsg_len) < 0) {
36cfb7
diff --git a/ip/xfrm_policy.c b/ip/xfrm_policy.c
e138d9
index de689c4d86c4d..98460a072bd4e 100644
36cfb7
--- a/ip/xfrm_policy.c
36cfb7
+++ b/ip/xfrm_policy.c
36cfb7
@@ -386,7 +386,7 @@ static int xfrm_policy_modify(int cmd, unsigned int flags, int argc, char **argv
36cfb7
 	if (req.xpinfo.sel.family == AF_UNSPEC)
36cfb7
 		req.xpinfo.sel.family = AF_INET;
36cfb7
 
36cfb7
-	if (rtnl_talk(&rth, &req.n, NULL, 0) < 0)
36cfb7
+	if (rtnl_talk(&rth, &req.n, NULL) < 0)
36cfb7
 		exit(2);
36cfb7
 
36cfb7
 	rtnl_close(&rth);
36cfb7
@@ -548,7 +548,7 @@ int xfrm_policy_print(const struct sockaddr_nl *who, struct nlmsghdr *n,
36cfb7
 }
36cfb7
 
36cfb7
 static int xfrm_policy_get_or_delete(int argc, char **argv, int delete,
36cfb7
-				     void *res_nlbuf, size_t res_size)
36cfb7
+				     struct nlmsghdr **answer)
36cfb7
 {
36cfb7
 	struct rtnl_handle rth;
36cfb7
 	struct {
36cfb7
@@ -659,7 +659,7 @@ static int xfrm_policy_get_or_delete(int argc, char **argv, int delete,
36cfb7
 			  (void *)&ctx, ctx.sctx.len);
36cfb7
 	}
36cfb7
 
36cfb7
-	if (rtnl_talk(&rth, &req.n, res_nlbuf, res_size) < 0)
36cfb7
+	if (rtnl_talk(&rth, &req.n, answer) < 0)
36cfb7
 		exit(2);
36cfb7
 
36cfb7
 	rtnl_close(&rth);
36cfb7
@@ -669,21 +669,21 @@ static int xfrm_policy_get_or_delete(int argc, char **argv, int delete,
36cfb7
 
36cfb7
 static int xfrm_policy_delete(int argc, char **argv)
36cfb7
 {
36cfb7
-	return xfrm_policy_get_or_delete(argc, argv, 1, NULL, 0);
36cfb7
+	return xfrm_policy_get_or_delete(argc, argv, 1, NULL);
36cfb7
 }
36cfb7
 
36cfb7
 static int xfrm_policy_get(int argc, char **argv)
36cfb7
 {
36cfb7
-	char buf[NLMSG_BUF_SIZE] = {};
36cfb7
-	struct nlmsghdr *n = (struct nlmsghdr *)buf;
36cfb7
+	struct nlmsghdr *n = NULL;
36cfb7
 
36cfb7
-	xfrm_policy_get_or_delete(argc, argv, 0, n, sizeof(buf));
36cfb7
+	xfrm_policy_get_or_delete(argc, argv, 0, &n);
36cfb7
 
36cfb7
 	if (xfrm_policy_print(NULL, n, (void *)stdout) < 0) {
36cfb7
 		fprintf(stderr, "An error :-)\n");
36cfb7
 		exit(1);
36cfb7
 	}
36cfb7
 
36cfb7
+	free(n);
36cfb7
 	return 0;
36cfb7
 }
36cfb7
 
36cfb7
@@ -1049,7 +1049,7 @@ static int xfrm_spd_setinfo(int argc, char **argv)
36cfb7
 	if (rtnl_open_byproto(&rth, 0, NETLINK_XFRM) < 0)
36cfb7
 		exit(1);
36cfb7
 
36cfb7
-	if (rtnl_talk(&rth, &req.n, NULL, 0) < 0)
36cfb7
+	if (rtnl_talk(&rth, &req.n, NULL) < 0)
36cfb7
 		exit(2);
36cfb7
 
36cfb7
 	rtnl_close(&rth);
36cfb7
@@ -1063,22 +1063,23 @@ static int xfrm_spd_getinfo(int argc, char **argv)
36cfb7
 	struct {
36cfb7
 		struct nlmsghdr			n;
36cfb7
 		__u32				flags;
36cfb7
-		char				ans[128];
36cfb7
 	} req = {
36cfb7
 		.n.nlmsg_len = NLMSG_LENGTH(sizeof(__u32)),
36cfb7
 		.n.nlmsg_flags = NLM_F_REQUEST,
36cfb7
 		.n.nlmsg_type = XFRM_MSG_GETSPDINFO,
36cfb7
 		.flags = 0XFFFFFFFF,
36cfb7
 	};
36cfb7
+	struct nlmsghdr *answer;
36cfb7
 
36cfb7
 	if (rtnl_open_byproto(&rth, 0, NETLINK_XFRM) < 0)
36cfb7
 		exit(1);
36cfb7
 
36cfb7
-	if (rtnl_talk(&rth, &req.n, &req.n, sizeof(req)) < 0)
36cfb7
+	if (rtnl_talk(&rth, &req.n, &answer) < 0)
36cfb7
 		exit(2);
36cfb7
 
36cfb7
-	print_spdinfo(&req.n, (void *)stdout);
36cfb7
+	print_spdinfo(answer, (void *)stdout);
36cfb7
 
36cfb7
+	free(answer);
36cfb7
 	rtnl_close(&rth);
36cfb7
 
36cfb7
 	return 0;
36cfb7
@@ -1123,7 +1124,7 @@ static int xfrm_policy_flush(int argc, char **argv)
36cfb7
 	if (show_stats > 1)
36cfb7
 		fprintf(stderr, "Flush policy\n");
36cfb7
 
36cfb7
-	if (rtnl_talk(&rth, &req.n, NULL, 0) < 0)
36cfb7
+	if (rtnl_talk(&rth, &req.n, NULL) < 0)
36cfb7
 		exit(2);
36cfb7
 
36cfb7
 	rtnl_close(&rth);
36cfb7
diff --git a/ip/xfrm_state.c b/ip/xfrm_state.c
e138d9
index ea7d4f3460578..04ed3492ad3b5 100644
36cfb7
--- a/ip/xfrm_state.c
36cfb7
+++ b/ip/xfrm_state.c
36cfb7
@@ -677,7 +677,7 @@ static int xfrm_state_modify(int cmd, unsigned int flags, int argc, char **argv)
36cfb7
 	if (req.xsinfo.family == AF_UNSPEC)
36cfb7
 		req.xsinfo.family = AF_INET;
36cfb7
 
36cfb7
-	if (rtnl_talk(&rth, &req.n, NULL, 0) < 0)
36cfb7
+	if (rtnl_talk(&rth, &req.n, NULL) < 0)
36cfb7
 		exit(2);
36cfb7
 
36cfb7
 	rtnl_close(&rth);
36cfb7
@@ -708,8 +708,7 @@ static int xfrm_state_allocspi(int argc, char **argv)
36cfb7
 	char *minp = NULL;
36cfb7
 	char *maxp = NULL;
36cfb7
 	struct xfrm_mark mark = {0, 0};
36cfb7
-	char res_buf[NLMSG_BUF_SIZE] = {};
36cfb7
-	struct nlmsghdr *res_n = (struct nlmsghdr *)res_buf;
36cfb7
+	struct nlmsghdr *answer;
36cfb7
 
36cfb7
 	while (argc > 0) {
36cfb7
 		if (strcmp(*argv, "mode") == 0) {
36cfb7
@@ -809,14 +808,15 @@ static int xfrm_state_allocspi(int argc, char **argv)
36cfb7
 		req.xspi.info.family = AF_INET;
36cfb7
 
36cfb7
 
36cfb7
-	if (rtnl_talk(&rth, &req.n, res_n, sizeof(res_buf)) < 0)
36cfb7
+	if (rtnl_talk(&rth, &req.n, &answer) < 0)
36cfb7
 		exit(2);
36cfb7
 
36cfb7
-	if (xfrm_state_print(NULL, res_n, (void *)stdout) < 0) {
36cfb7
+	if (xfrm_state_print(NULL, answer, (void *)stdout) < 0) {
36cfb7
 		fprintf(stderr, "An error :-)\n");
36cfb7
 		exit(1);
36cfb7
 	}
36cfb7
 
36cfb7
+	free(answer);
36cfb7
 	rtnl_close(&rth);
36cfb7
 
36cfb7
 	return 0;
36cfb7
@@ -997,19 +997,20 @@ static int xfrm_state_get_or_delete(int argc, char **argv, int delete)
36cfb7
 		req.xsid.family = AF_INET;
36cfb7
 
36cfb7
 	if (delete) {
36cfb7
-		if (rtnl_talk(&rth, &req.n, NULL, 0) < 0)
36cfb7
+		if (rtnl_talk(&rth, &req.n, NULL) < 0)
36cfb7
 			exit(2);
36cfb7
 	} else {
36cfb7
-		char buf[NLMSG_BUF_SIZE] = {};
36cfb7
-		struct nlmsghdr *res_n = (struct nlmsghdr *)buf;
36cfb7
+		struct nlmsghdr *answer;
36cfb7
 
36cfb7
-		if (rtnl_talk(&rth, &req.n, res_n, sizeof(req)) < 0)
36cfb7
+		if (rtnl_talk(&rth, &req.n, &answer) < 0)
36cfb7
 			exit(2);
36cfb7
 
36cfb7
-		if (xfrm_state_print(NULL, res_n, (void *)stdout) < 0) {
36cfb7
+		if (xfrm_state_print(NULL, answer, (void *)stdout) < 0) {
36cfb7
 			fprintf(stderr, "An error :-)\n");
36cfb7
 			exit(1);
36cfb7
 		}
36cfb7
+
36cfb7
+		free(answer);
36cfb7
 	}
36cfb7
 
36cfb7
 	rtnl_close(&rth);
36cfb7
@@ -1265,22 +1266,23 @@ static int xfrm_sad_getinfo(int argc, char **argv)
36cfb7
 	struct {
36cfb7
 		struct nlmsghdr			n;
36cfb7
 		__u32				flags;
36cfb7
-		char				ans[64];
36cfb7
 	} req = {
36cfb7
 		.n.nlmsg_len = NLMSG_LENGTH(sizeof(req.flags)),
36cfb7
 		.n.nlmsg_flags = NLM_F_REQUEST,
36cfb7
 		.n.nlmsg_type = XFRM_MSG_GETSADINFO,
36cfb7
 		.flags = 0XFFFFFFFF,
36cfb7
 	};
36cfb7
+	struct nlmsghdr *answer;
36cfb7
 
36cfb7
 	if (rtnl_open_byproto(&rth, 0, NETLINK_XFRM) < 0)
36cfb7
 		exit(1);
36cfb7
 
36cfb7
-	if (rtnl_talk(&rth, &req.n, &req.n, sizeof(req)) < 0)
36cfb7
+	if (rtnl_talk(&rth, &req.n, &answer) < 0)
36cfb7
 		exit(2);
36cfb7
 
36cfb7
-	print_sadinfo(&req.n, (void *)stdout);
36cfb7
+	print_sadinfo(answer, (void *)stdout);
36cfb7
 
36cfb7
+	free(answer);
36cfb7
 	rtnl_close(&rth);
36cfb7
 
36cfb7
 	return 0;
36cfb7
@@ -1327,7 +1329,7 @@ static int xfrm_state_flush(int argc, char **argv)
36cfb7
 		fprintf(stderr, "Flush state with XFRM-PROTO value \"%s\"\n",
36cfb7
 			strxf_xfrmproto(req.xsf.proto));
36cfb7
 
36cfb7
-	if (rtnl_talk(&rth, &req.n, NULL, 0) < 0)
36cfb7
+	if (rtnl_talk(&rth, &req.n, NULL) < 0)
36cfb7
 		exit(2);
36cfb7
 
36cfb7
 	rtnl_close(&rth);
36cfb7
diff --git a/lib/libgenl.c b/lib/libgenl.c
e138d9
index 50d2d9217dcbc..bb5fbb5f518d2 100644
36cfb7
--- a/lib/libgenl.c
36cfb7
+++ b/lib/libgenl.c
36cfb7
@@ -49,16 +49,21 @@ int genl_resolve_family(struct rtnl_handle *grth, const char *family)
36cfb7
 {
36cfb7
 	GENL_REQUEST(req, 1024, GENL_ID_CTRL, 0, 0, CTRL_CMD_GETFAMILY,
36cfb7
 		     NLM_F_REQUEST);
36cfb7
+	struct nlmsghdr *answer;
36cfb7
+	int fnum;
36cfb7
 
36cfb7
 	addattr_l(&req.n, sizeof(req), CTRL_ATTR_FAMILY_NAME,
36cfb7
 		  family, strlen(family) + 1);
36cfb7
 
36cfb7
-	if (rtnl_talk(grth, &req.n, &req.n, sizeof(req)) < 0) {
36cfb7
+	if (rtnl_talk(grth, &req.n, &answer) < 0) {
36cfb7
 		fprintf(stderr, "Error talking to the kernel\n");
36cfb7
 		return -2;
36cfb7
 	}
36cfb7
 
36cfb7
-	return genl_parse_getfamily(&req.n);
36cfb7
+	fnum = genl_parse_getfamily(answer);
36cfb7
+	free(answer);
36cfb7
+
36cfb7
+	return fnum;
36cfb7
 }
36cfb7
 
36cfb7
 int genl_init_handle(struct rtnl_handle *grth, const char *family,
36cfb7
diff --git a/lib/libnetlink.c b/lib/libnetlink.c
e138d9
index 446c9605ba19b..75e20abf0b97f 100644
36cfb7
--- a/lib/libnetlink.c
36cfb7
+++ b/lib/libnetlink.c
36cfb7
@@ -561,7 +561,7 @@ static void rtnl_talk_error(struct nlmsghdr *h, struct nlmsgerr *err,
36cfb7
 }
36cfb7
 
36cfb7
 static int __rtnl_talk(struct rtnl_handle *rtnl, struct nlmsghdr *n,
36cfb7
-		       struct nlmsghdr *answer, size_t maxlen,
36cfb7
+		       struct nlmsghdr **answer,
36cfb7
 		       bool show_rtnl_err, nl_ext_ack_fn_t errfn)
36cfb7
 {
36cfb7
 	int status;
36cfb7
@@ -635,9 +635,9 @@ static int __rtnl_talk(struct rtnl_handle *rtnl, struct nlmsghdr *n,
36cfb7
 					fprintf(stderr, "ERROR truncated\n");
36cfb7
 				} else if (!err->error) {
36cfb7
 					if (answer)
36cfb7
-						memcpy(answer, h,
36cfb7
-						       MIN(maxlen, h->nlmsg_len));
36cfb7
-					free(buf);
36cfb7
+						*answer = (struct nlmsghdr *)buf;
36cfb7
+					else
36cfb7
+						free(buf);
36cfb7
 					return 0;
36cfb7
 				}
36cfb7
 
36cfb7
@@ -651,9 +651,7 @@ static int __rtnl_talk(struct rtnl_handle *rtnl, struct nlmsghdr *n,
36cfb7
 			}
36cfb7
 
36cfb7
 			if (answer) {
36cfb7
-				memcpy(answer, h,
36cfb7
-				       MIN(maxlen, h->nlmsg_len));
36cfb7
-				free(buf);
36cfb7
+				*answer = (struct nlmsghdr *)buf;
36cfb7
 				return 0;
36cfb7
 			}
36cfb7
 
36cfb7
@@ -677,22 +675,22 @@ static int __rtnl_talk(struct rtnl_handle *rtnl, struct nlmsghdr *n,
36cfb7
 }
36cfb7
 
36cfb7
 int rtnl_talk(struct rtnl_handle *rtnl, struct nlmsghdr *n,
36cfb7
-	      struct nlmsghdr *answer, size_t maxlen)
36cfb7
+	      struct nlmsghdr **answer)
36cfb7
 {
36cfb7
-	return __rtnl_talk(rtnl, n, answer, maxlen, true, NULL);
36cfb7
+	return __rtnl_talk(rtnl, n, answer, true, NULL);
36cfb7
 }
36cfb7
 
36cfb7
 int rtnl_talk_extack(struct rtnl_handle *rtnl, struct nlmsghdr *n,
36cfb7
-		     struct nlmsghdr *answer, size_t maxlen,
36cfb7
+		     struct nlmsghdr **answer,
36cfb7
 		     nl_ext_ack_fn_t errfn)
36cfb7
 {
36cfb7
-	return __rtnl_talk(rtnl, n, answer, maxlen, true, errfn);
36cfb7
+	return __rtnl_talk(rtnl, n, answer, true, errfn);
36cfb7
 }
36cfb7
 
36cfb7
 int rtnl_talk_suppress_rtnl_errmsg(struct rtnl_handle *rtnl, struct nlmsghdr *n,
36cfb7
-				   struct nlmsghdr *answer, size_t maxlen)
36cfb7
+				   struct nlmsghdr **answer)
36cfb7
 {
36cfb7
-	return __rtnl_talk(rtnl, n, answer, maxlen, false, NULL);
36cfb7
+	return __rtnl_talk(rtnl, n, answer, false, NULL);
36cfb7
 }
36cfb7
 
36cfb7
 int rtnl_listen_all_nsid(struct rtnl_handle *rth)
36cfb7
diff --git a/misc/ss.c b/misc/ss.c
e138d9
index b84baf3b57fe5..d3fb9a751b3ab 100644
36cfb7
--- a/misc/ss.c
36cfb7
+++ b/misc/ss.c
36cfb7
@@ -2588,7 +2588,7 @@ static int kill_inet_sock(struct nlmsghdr *h, void *arg, struct sockstat *s)
36cfb7
 		raw->sdiag_raw_protocol = s->raw_prot;
36cfb7
 	}
36cfb7
 
36cfb7
-	return rtnl_talk(rth, &req.nlh, NULL, 0);
36cfb7
+	return rtnl_talk(rth, &req.nlh, NULL);
36cfb7
 }
36cfb7
 
36cfb7
 static int show_one_inet_sock(const struct sockaddr_nl *addr,
36cfb7
diff --git a/tc/m_action.c b/tc/m_action.c
e138d9
index 6ebe85e1cbe36..90b2a11e5d9e8 100644
36cfb7
--- a/tc/m_action.c
36cfb7
+++ b/tc/m_action.c
36cfb7
@@ -506,18 +506,18 @@ static int tc_action_gd(int cmd, unsigned int flags, int *argc_p, char ***argv_p
36cfb7
 	tail->rta_len = (void *) NLMSG_TAIL(&req.n) - (void *) tail;
36cfb7
 
36cfb7
 	req.n.nlmsg_seq = rth.dump = ++rth.seq;
36cfb7
-	if (cmd == RTM_GETACTION)
36cfb7
-		ans = &req.n;
36cfb7
 
36cfb7
-	if (rtnl_talk(&rth, &req.n, ans, MAX_MSG) < 0) {
36cfb7
+	if (rtnl_talk(&rth, &req.n, &ans) < 0) {
36cfb7
 		fprintf(stderr, "We have an error talking to the kernel\n");
36cfb7
 		return 1;
36cfb7
 	}
36cfb7
 
36cfb7
-	if (ans && print_action(NULL, &req.n, (void *)stdout) < 0) {
36cfb7
+	if (cmd == RTM_GETACTION && print_action(NULL, ans, stdout) < 0) {
36cfb7
 		fprintf(stderr, "Dump terminated\n");
36cfb7
+		free(ans);
36cfb7
 		return 1;
36cfb7
 	}
36cfb7
+	free(ans);
36cfb7
 
36cfb7
 	*argc_p = argc;
36cfb7
 	*argv_p = argv;
36cfb7
@@ -550,7 +550,7 @@ static int tc_action_modify(int cmd, unsigned int flags, int *argc_p, char ***ar
36cfb7
 	}
36cfb7
 	tail->rta_len = (void *) NLMSG_TAIL(&req.n) - (void *) tail;
36cfb7
 
36cfb7
-	if (rtnl_talk(&rth, &req.n, NULL, 0) < 0) {
36cfb7
+	if (rtnl_talk(&rth, &req.n, NULL) < 0) {
36cfb7
 		fprintf(stderr, "We have an error talking to the kernel\n");
36cfb7
 		ret = -1;
36cfb7
 	}
36cfb7
@@ -617,7 +617,7 @@ static int tc_act_list_or_flush(int argc, char **argv, int event)
36cfb7
 		req.n.nlmsg_type = RTM_DELACTION;
36cfb7
 		req.n.nlmsg_flags |= NLM_F_ROOT;
36cfb7
 		req.n.nlmsg_flags |= NLM_F_REQUEST;
36cfb7
-		if (rtnl_talk(&rth, &req.n, NULL, 0) < 0) {
36cfb7
+		if (rtnl_talk(&rth, &req.n, NULL) < 0) {
36cfb7
 			fprintf(stderr, "We have an error flushing\n");
36cfb7
 			return 1;
36cfb7
 		}
36cfb7
diff --git a/tc/tc_class.c b/tc/tc_class.c
e138d9
index 1a1f1fa225b40..0214775b95a6c 100644
36cfb7
--- a/tc/tc_class.c
36cfb7
+++ b/tc/tc_class.c
36cfb7
@@ -149,7 +149,7 @@ static int tc_class_modify(int cmd, unsigned int flags, int argc, char **argv)
36cfb7
 		}
36cfb7
 	}
36cfb7
 
36cfb7
-	if (rtnl_talk(&rth, &req.n, NULL, 0) < 0)
36cfb7
+	if (rtnl_talk(&rth, &req.n, NULL) < 0)
36cfb7
 		return 2;
36cfb7
 
36cfb7
 	return 0;
36cfb7
diff --git a/tc/tc_filter.c b/tc/tc_filter.c
e138d9
index ff8713b98e315..e640492b25ba6 100644
36cfb7
--- a/tc/tc_filter.c
36cfb7
+++ b/tc/tc_filter.c
36cfb7
@@ -181,7 +181,7 @@ static int tc_filter_modify(int cmd, unsigned int flags, int argc, char **argv)
36cfb7
 		}
36cfb7
 	}
36cfb7
 
36cfb7
-	if (rtnl_talk(&rth, &req.n, NULL, 0) < 0) {
36cfb7
+	if (rtnl_talk(&rth, &req.n, NULL) < 0) {
36cfb7
 		fprintf(stderr, "We have an error talking to the kernel\n");
36cfb7
 		return 2;
36cfb7
 	}
36cfb7
@@ -307,6 +307,7 @@ static int tc_filter_get(int cmd, unsigned int flags, int argc, char **argv)
36cfb7
 		.t.tcm_parent = TC_H_UNSPEC,
36cfb7
 		.t.tcm_family = AF_UNSPEC,
36cfb7
 	};
36cfb7
+	struct nlmsghdr *answer;
36cfb7
 	struct filter_util *q = NULL;
36cfb7
 	__u32 prio = 0;
36cfb7
 	__u32 protocol = 0;
36cfb7
@@ -445,13 +446,14 @@ static int tc_filter_get(int cmd, unsigned int flags, int argc, char **argv)
36cfb7
 		return -1;
36cfb7
 	}
36cfb7
 
36cfb7
-	if (rtnl_talk(&rth, &req.n, &req.n, MAX_MSG) < 0) {
36cfb7
+	if (rtnl_talk(&rth, &req.n, &answer) < 0) {
36cfb7
 		fprintf(stderr, "We have an error talking to the kernel\n");
36cfb7
 		return 2;
36cfb7
 	}
36cfb7
 
36cfb7
-	print_filter(NULL, &req.n, (void *)stdout);
36cfb7
+	print_filter(NULL, answer, (void *)stdout);
36cfb7
 
36cfb7
+	free(answer);
36cfb7
 	return 0;
36cfb7
 }
36cfb7
 
36cfb7
diff --git a/tc/tc_qdisc.c b/tc/tc_qdisc.c
e138d9
index 3a3701c204704..8b0c5c72dbad1 100644
36cfb7
--- a/tc/tc_qdisc.c
36cfb7
+++ b/tc/tc_qdisc.c
36cfb7
@@ -190,7 +190,7 @@ static int tc_qdisc_modify(int cmd, unsigned int flags, int argc, char **argv)
36cfb7
 		req.t.tcm_ifindex = idx;
36cfb7
 	}
36cfb7
 
36cfb7
-	if (rtnl_talk(&rth, &req.n, NULL, 0) < 0)
36cfb7
+	if (rtnl_talk(&rth, &req.n, NULL) < 0)
36cfb7
 		return 2;
36cfb7
 
36cfb7
 	return 0;
36cfb7
-- 
e138d9
2.21.0
36cfb7