[PATCH] ip link: support "type can bitrate NUM" argument

Nikolaus Voss nv at vosn.de
Tue Aug 9 14:01:00 UTC 2022


This is the minimum needed to set up SocketCAN interfaces.
Setting the bitrate is usually required before upping the device, e.g.

  ip link set can0 type can bitrate 1000000
  ip link set up can0

iproute2 supports more options to "type can" but these are not
mandatory for using the device.

Signed-off-by: Nikolaus Voss <nikolaus.voss at haag-streit.com>
---
 networking/ip.c                    |  2 +-
 networking/libiproute/iplink.c     | 57 ++++++++++++++++++++++++++++--
 networking/libiproute/libnetlink.c | 14 ++++++++
 networking/libiproute/libnetlink.h |  5 +++
 4 files changed, 75 insertions(+), 3 deletions(-)

diff --git a/networking/ip.c b/networking/ip.c
index 7c3208699..f0159912a 100644
--- a/networking/ip.c
+++ b/networking/ip.c
@@ -152,7 +152,7 @@
 //usage:#define iplink_trivial_usage
 //usage:       /*Usage:iplink*/"set IFACE [up|down] [arp on|off] [multicast on|off]\n"
 //usage:       "	[promisc on|off] [mtu NUM] [name NAME] [qlen NUM] [address MAC]\n"
-//usage:       "	[master IFACE | nomaster] [netns PID]"
+//usage:       "	[master IFACE | nomaster] [netns PID] [type can bitrate NUM]"
 // * short help shows only "set" command, long help continues (with just one "\n")
 // * and shows all other commands:
 //usage:#define iplink_full_usage "\n"
diff --git a/networking/libiproute/iplink.c b/networking/libiproute/iplink.c
index 68d199044..c751087d8 100644
--- a/networking/libiproute/iplink.c
+++ b/networking/libiproute/iplink.c
@@ -10,6 +10,7 @@
 #include <netpacket/packet.h>
 #include <netinet/if_ether.h>
 
+#include <linux/can/netlink.h>
 #include <linux/if_vlan.h>
 #include "ip_common.h"  /* #include "libbb.h" is inside */
 #include "rt_names.h"
@@ -241,6 +242,55 @@ static void die_must_be_on_off(const char *msg)
 	bb_error_msg_and_die("argument of \"%s\" must be \"on\" or \"off\"", msg);
 }
 
+/* Return value becomes exitcode. It's okay to not return at all */
+static int do_set_type(char **argv, char *dev)
+{
+	struct rtnl_handle rth;
+	struct {
+		struct nlmsghdr	 n;
+		struct ifinfomsg i;
+		char		 buf[1024];
+	} req;
+	struct rtattr *linkinfo;
+	struct rtattr *data;
+
+	memset(&req, 0, sizeof(req));
+	req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
+	req.n.nlmsg_flags = NLM_F_REQUEST;
+	req.n.nlmsg_type = RTM_NEWLINK;
+	req.i.ifi_family = preferred_family;
+
+	xrtnl_open(&rth);
+	req.i.ifi_index = xll_name_to_index(dev);
+	linkinfo = addattr_nest(&req.n, sizeof(req), IFLA_LINKINFO);
+
+	if (!strcmp(*argv, "can")) {
+		struct can_bittiming bt = { 0 };
+
+		addattr_l(&req.n, sizeof(req), IFLA_INFO_KIND, *argv,
+			  strlen(*argv));
+		data = addattr_nest(&req.n, sizeof(req), IFLA_INFO_DATA);
+		NEXT_ARG();
+		if (!strcmp(*argv, "bitrate")) {
+			NEXT_ARG();
+			bt.bitrate = get_u32(*argv, "bitrate");
+			addattr_l(&req.n, sizeof(req), IFLA_CAN_BITTIMING, &bt,
+				  sizeof(bt));
+		} else	{
+			bb_error_msg_and_die("arg \"%s\" unkown", *argv);
+		}
+		addattr_nest_end(&req.n, data);
+	} else {
+		invarg_1_to_2(*argv, "type");
+	}
+	addattr_nest_end(&req.n, linkinfo);
+
+	if (rtnl_talk(&rth, &req.n, 0, 0, NULL, NULL, NULL) < 0)
+		xfunc_die();
+
+	return 0;
+}
+
 /* Return value becomes exitcode. It's okay to not return at all */
 static int do_set(char **argv)
 {
@@ -260,11 +310,11 @@ static int do_set(char **argv)
 	static const char keywords[] ALIGN1 =
 		"up\0""down\0""name\0""mtu\0""qlen\0""multicast\0"
 		"arp\0""promisc\0""address\0""netns\0"
-		"master\0""nomaster\0"
+		"master\0""nomaster\0" "type\0"
 		"dev\0" /* must be last */;
 	enum { ARG_up = 0, ARG_down, ARG_name, ARG_mtu, ARG_qlen, ARG_multicast,
 		ARG_arp, ARG_promisc, ARG_addr, ARG_netns,
-		ARG_master, ARG_nomaster,
+		ARG_master, ARG_nomaster, ARG_type,
 		ARG_dev };
 	enum { PARM_on = 0, PARM_off };
 	smalluint key;
@@ -304,6 +354,9 @@ static int do_set(char **argv)
 		} else if (key == ARG_netns) {
 			NEXT_ARG();
 			netns = get_unsigned(*argv, "netns");
+		} else if (key == ARG_type) {
+			NEXT_ARG();
+			return do_set_type(argv, dev);
 		} else if (key >= ARG_dev) {
 			/* ^^^^^^ ">=" here results in "dev IFACE" treated as default */
 			if (key == ARG_dev) {
diff --git a/networking/libiproute/libnetlink.c b/networking/libiproute/libnetlink.c
index 7e3473a1c..5b6273245 100644
--- a/networking/libiproute/libnetlink.c
+++ b/networking/libiproute/libnetlink.c
@@ -390,6 +390,20 @@ int FAST_FUNC addattr_l(struct nlmsghdr *n, int maxlen, int type, void *data, in
 	return 0;
 }
 
+struct rtattr * FAST_FUNC addattr_nest(struct nlmsghdr *n, int maxlen, int type)
+{
+	struct rtattr *nest = NLMSG_TAIL(n);
+
+	addattr_l(n, maxlen, type, NULL, 0);
+	return nest;
+}
+
+int FAST_FUNC addattr_nest_end(struct nlmsghdr *n, struct rtattr *nest)
+{
+	nest->rta_len = (void *)NLMSG_TAIL(n) - (void *)nest;
+	return n->nlmsg_len;
+}
+
 int FAST_FUNC rta_addattr32(struct rtattr *rta, int maxlen, int type, uint32_t data)
 {
 	int len = RTA_LENGTH(4);
diff --git a/networking/libiproute/libnetlink.h b/networking/libiproute/libnetlink.h
index 1b082e019..b7eefa1e5 100644
--- a/networking/libiproute/libnetlink.h
+++ b/networking/libiproute/libnetlink.h
@@ -54,11 +54,16 @@ static ALWAYS_INLINE void rtnl_send(struct rtnl_handle *rth, const void *buf, in
 
 extern int addattr32(struct nlmsghdr *n, int maxlen, int type, uint32_t data) FAST_FUNC;
 extern int addattr_l(struct nlmsghdr *n, int maxlen, int type, void *data, int alen) FAST_FUNC;
+extern struct rtattr * addattr_nest(struct nlmsghdr *n, int maxlen, int type) FAST_FUNC;
+extern int addattr_nest_end(struct nlmsghdr *n, struct rtattr *nest) FAST_FUNC;
 extern int rta_addattr32(struct rtattr *rta, int maxlen, int type, uint32_t data) FAST_FUNC;
 extern int rta_addattr_l(struct rtattr *rta, int maxlen, int type, void *data, int alen) FAST_FUNC;
 
 extern void parse_rtattr(struct rtattr *tb[], int max, struct rtattr *rta, int len) FAST_FUNC;
 
+#define NLMSG_TAIL(nmsg) \
+	((struct rtattr *) (((void *) (nmsg)) + NLMSG_ALIGN((nmsg)->nlmsg_len)))
+
 POP_SAVED_FUNCTION_VISIBILITY
 
 #endif
-- 
2.34.1



More information about the busybox mailing list