From patchwork Sat Jul 8 17:38:39 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dario Binacchi X-Patchwork-Id: 2935 Return-Path: X-Original-To: linux-amarula@patchwork.amarulasolutions.com Delivered-To: linux-amarula@patchwork.amarulasolutions.com Received: from mail-lj1-f198.google.com (mail-lj1-f198.google.com [209.85.208.198]) by ganimede.amarulasolutions.com (Postfix) with ESMTPS id F32153F1F2 for ; Sat, 8 Jul 2023 19:39:01 +0200 (CEST) Received: by mail-lj1-f198.google.com with SMTP id 38308e7fff4ca-2b708d79112sf26037141fa.1 for ; Sat, 08 Jul 2023 10:39:01 -0700 (PDT) ARC-Seal: i=2; a=rsa-sha256; t=1688837941; cv=pass; d=google.com; s=arc-20160816; b=fcYt3WQNQgmutz9fkhG+sbTG1Q1cZUDJtgoA4o9+mmPBwtVDHwfM+zOun1wVzzFWPP 3xkFltLkM0RoKKLALqAk67pIKnpv4mKM3e/4lEPjfQ380VCIkyZW1Z/+m2Xdq2i5J1um H9JtGsxnttVDETZlbUQAzIyHe4bQT4/nJ/q60PTHWTn2XC1kKuVxUwRjSGOaOl4MdV/+ euMqbp/FmC4ulEnqdarjntn96HvjDVYGSF5JkmHOAbYd0eYjmL/73RzlCmGq3NAC42pL o2U2lvnHm2fVTHa5JcHhvpwrVBZLAFk149kBvK1K2DSWwyr07npDpckKXMRSTF4PrB7t ypOw== ARC-Message-Signature: i=2; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-unsubscribe:list-archive:list-help:list-post:list-id :mailing-list:precedence:mime-version:message-id:date:subject:cc:to :from:dkim-signature; bh=bIeHJNi5BVduNs4Qak2HU9q1MR2WUtY7yh8Guf/0HzU=; fh=6TF/HSQWd0Blst7+145vN6c8U0d55zp/T1B5UGVaHp4=; b=zay9JnTDNPLRGF6HhheiHKV0ool0R/VGHSjOnM8U8FYQ9wzieWudLdI9Yh0zM9NbTS Saj0Hr9VR/mw6+/1wdrwtR0OUt9/VEKveC5ttGYTs7xNLG4Bz2dppdGbaJmOhaBrKhdo lYywuwoEcprK23X05F3VJpfNGk5Dv7p4iwRROFvsmzNQjEGfYNgfNU6o+jhphh+E/vKr Qy1/9VqdqbQeWZTClpeImTyoOWFZ29MZ4uJFSjTnTeJNosXlz+Mpuc6hmFUCFM+goBv3 nStBDejJ3ucuefYia6FmmoRNq6hrWkD0LgGVZZpluYokzBg8s3P12jbZfa/d/R5yvds8 QVRg== ARC-Authentication-Results: i=2; mx.google.com; dkim=pass header.i=@amarulasolutions.com header.s=google header.b="h/yzkiIP"; spf=pass (google.com: domain of dario.binacchi@amarulasolutions.com designates 209.85.220.41 as permitted sender) smtp.mailfrom=dario.binacchi@amarulasolutions.com; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=amarulasolutions.com DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=amarulasolutions.com; s=google; t=1688837941; x=1691429941; h=list-unsubscribe:list-archive:list-help:list-post:list-id :mailing-list:precedence:x-original-authentication-results :x-original-sender:mime-version:message-id:date:subject:cc:to:from :from:to:cc:subject:date:message-id:reply-to; bh=bIeHJNi5BVduNs4Qak2HU9q1MR2WUtY7yh8Guf/0HzU=; b=TCsGuc3sZY/3QMeJkbGowpDkUlWCXVvTHuKQAqk6R1bsIfagn0z0OHOwTe29kXuG2h neKPYpphoIPGKPnpR9NOMQcl8KVNWIkxz53+Xo+OQHGaeNmcEee4BG010PYC/0Sxtiqu 3aOryL4UaFCscjaDW8JuUoyIK+Bdva1ibr078= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20221208; t=1688837941; x=1691429941; h=list-unsubscribe:list-archive:list-help:list-post :x-spam-checked-in-group:list-id:mailing-list:precedence :x-original-authentication-results:x-original-sender:mime-version :message-id:date:subject:cc:to:from:x-beenthere:x-gm-message-state :from:to:cc:subject:date:message-id:reply-to; bh=bIeHJNi5BVduNs4Qak2HU9q1MR2WUtY7yh8Guf/0HzU=; b=HTXuwjOJCPodPHOYlmlloHMYDuwQVBlGpTFhp2aX2fCifNpNz0Yie5LDo2rDbQEyar pUHQzxGcmAsiUusHLChL+xgqmjEufYldPMzLH+MMGYtf8935ELytK69UBvM/yHtD9FRK hmBwnU4k6aa49IV2RBuMoqjxZV+edFemZHEc2ngOg2pLpmZ1M+Zz0B+BBbbV4VZoGDLv 3UL5bnmJocc7dy6aw4mqMH5nKCjOlHGxlHlZBPDuza77L5isfZ7SVdcW7b/dBh7uId2y ZHHYiKEV5xzAkhQ31n7WHZIgoXeb8cG7lVbkzZmkMn11EM3kgmTOx2zSW2B6KvqNHWpH 5Ivw== X-Gm-Message-State: ABy/qLZhz+IO8AfvKON2ZZIXoLQZ0m2zawmPymUCmisbVXmJ77T6jXCK 7v0XdYv2Pkx7Advb4kGkSOD6exlF X-Google-Smtp-Source: APBJJlEaJds0TW30zctLgJ6sYr2aqxXck94V322MiUD44ikppdFEu3KxfhZxW9jK/NhL7KfZa1P9Vw== X-Received: by 2002:a2e:7c18:0:b0:2b6:e651:8591 with SMTP id x24-20020a2e7c18000000b002b6e6518591mr5979523ljc.37.1688837940478; Sat, 08 Jul 2023 10:39:00 -0700 (PDT) X-BeenThere: linux-amarula@amarulasolutions.com Received: by 2002:a2e:bcc4:0:b0:2b6:d598:b815 with SMTP id z4-20020a2ebcc4000000b002b6d598b815ls503232ljp.2.-pod-prod-08-eu; Sat, 08 Jul 2023 10:38:59 -0700 (PDT) X-Received: by 2002:a2e:2405:0:b0:2b6:e0d3:45b5 with SMTP id k5-20020a2e2405000000b002b6e0d345b5mr6502714ljk.3.1688837938531; Sat, 08 Jul 2023 10:38:58 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1688837938; cv=none; d=google.com; s=arc-20160816; b=hsirfUzNsidceLqp6Jvt9dMOFOnVYd9dT15PBWmCiB30PkuN2Wk2xEr3kgwsJ3VJ6Q Sc5PUs7dGijsWL28ATRzSL+0PijPHqq2RlW1at0wiMMtOBNxjEnSHd/Ka61SMJIqCIQD m5PvvRUh0Y+h/KH/WxlfrC9e1r9GD3hYSIepbnI37Jntr6ZOxusmbnquKbeLK+Eq31vQ /xjhYkCXUSDoaA1Vc8GqRVdz9Ai7VZUPvRYY/NIXoVyFkbrjXV5hGBwwf9Tb/9MdhESD 51X2ACEt0Nb89SIyb6/+PhAvio+cSpyt9He4uB1kKbDSoAYgTEuSLkr7zD7KBunGIa0o CTYQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=content-transfer-encoding:mime-version:message-id:date:subject:cc :to:from:dkim-signature; bh=z2c2rGR/k58fe+nPk0Pf8zX18ea+IICp07ntjcs2CiM=; fh=6TF/HSQWd0Blst7+145vN6c8U0d55zp/T1B5UGVaHp4=; b=RTZbl+O2GlfqqURFcS+UrdarsZ8J3/FkOJN4ORHjScLXIFldTOh9HRamPpjC+stN8B KG7FVs3hxp+kEG1MZ8Mksq3aCY5G+kP0PhI7f+WsP7LpG8xhdTbMCM6NmYyfrA65iias f+R/G7LypG2KQakgmWXlTTIbvkqymwnJGUIUz8YdBeGg/56IqpoikDNVKSmrKtO9zSBD iMmgjnUPQ6uBnb0BSNHDdvpsxHxkd2FfdWJ/GgXfMzryVDgWTysHTH8nPIVP3AP9iVSt GRCbmtW5i1ZfWKcHifRrSICg3AYbXlsvZP+MS197lRuIQmUaR9QY6Mzd2R6JOb0chUzx Cm8A== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@amarulasolutions.com header.s=google header.b="h/yzkiIP"; spf=pass (google.com: domain of dario.binacchi@amarulasolutions.com designates 209.85.220.41 as permitted sender) smtp.mailfrom=dario.binacchi@amarulasolutions.com; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=amarulasolutions.com Received: from mail-sor-f41.google.com (mail-sor-f41.google.com. [209.85.220.41]) by mx.google.com with SMTPS id a23-20020a05651c031700b002b6f9839fd5sor1288346ljp.8.2023.07.08.10.38.58 for (Google Transport Security); Sat, 08 Jul 2023 10:38:58 -0700 (PDT) Received-SPF: pass (google.com: domain of dario.binacchi@amarulasolutions.com designates 209.85.220.41 as permitted sender) client-ip=209.85.220.41; X-Received: by 2002:a2e:964e:0:b0:2b6:fa3f:9233 with SMTP id z14-20020a2e964e000000b002b6fa3f9233mr2816515ljh.46.1688837937928; Sat, 08 Jul 2023 10:38:57 -0700 (PDT) Received: from dario-ThinkPad-T14s-Gen-2i.steri.wh.com (host-82-58-49-236.retail.telecomitalia.it. [82.58.49.236]) by smtp.gmail.com with ESMTPSA id g21-20020a1709063b1500b00988781076e2sm3711916ejf.78.2023.07.08.10.38.56 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sat, 08 Jul 2023 10:38:57 -0700 (PDT) From: Dario Binacchi To: busybox@busybox.net Cc: Denys Vlasenko , linux-amarula@amarulasolutions.com, Michael Trimarchi , Bernhard Reutner-Fischer , Dario Binacchi , Marc Kleine-Budde Subject: [RESEND, RFC PATCH] ip link: support for the CAN netlink Date: Sat, 8 Jul 2023 19:38:39 +0200 Message-Id: <20230708173839.686922-1-dario.binacchi@amarulasolutions.com> X-Mailer: git-send-email 2.32.0 MIME-Version: 1.0 X-Original-Sender: dario.binacchi@amarulasolutions.com X-Original-Authentication-Results: mx.google.com; dkim=pass header.i=@amarulasolutions.com header.s=google header.b="h/yzkiIP"; spf=pass (google.com: domain of dario.binacchi@amarulasolutions.com designates 209.85.220.41 as permitted sender) smtp.mailfrom=dario.binacchi@amarulasolutions.com; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=amarulasolutions.com Content-Type: text/plain; charset="UTF-8" Precedence: list Mailing-list: list linux-amarula@amarulasolutions.com; contact linux-amarula+owners@amarulasolutions.com List-ID: X-Spam-Checked-In-Group: linux-amarula@amarulasolutions.com X-Google-Group-Id: 476853432473 List-Post: , List-Help: , List-Archive: List-Unsubscribe: , I developed this application to test the Linux kernel series [1]. As described in the cover letter I could not use the iproute2 package since the microcontroller is without MMU. cc: Marc Kleine-Budde [1] https://marc.info/?l=linux-netdev&m=167999323611710&w=2 Signed-off-by: Dario Binacchi --- configs/TEST_nommu_defconfig | 1 + networking/ip.c | 84 ++++++++++ networking/libiproute/iplink.c | 298 ++++++++++++++++++++++++++++++++- 3 files changed, 374 insertions(+), 9 deletions(-) diff --git a/configs/TEST_nommu_defconfig b/configs/TEST_nommu_defconfig index 415f5a8027f9..fa3e9632622a 100644 --- a/configs/TEST_nommu_defconfig +++ b/configs/TEST_nommu_defconfig @@ -703,6 +703,7 @@ CONFIG_FEATURE_INETD_RPC=y CONFIG_IP=y CONFIG_FEATURE_IP_ADDRESS=y CONFIG_FEATURE_IP_LINK=y +CONFIG_FEATURE_IP_LINK_CAN=y CONFIG_FEATURE_IP_ROUTE=y CONFIG_FEATURE_IP_TUNNEL=y CONFIG_FEATURE_IP_RULE=y diff --git a/networking/ip.c b/networking/ip.c index 7c320869958a..4959e9f25288 100644 --- a/networking/ip.c +++ b/networking/ip.c @@ -32,6 +32,14 @@ //config: help //config: Short form of "ip link" //config: +//config:config IPLINK_CAN +//config: bool "iplink for CAN (4.6 kb)" +//config: default n +//config: depends on IPLINK +//config: select FEATURE_IP_LINK_CAN +//config: help +//config: Short form of "ip link" for CAN +//config: //config:config IPROUTE //config: bool "iproute (15 kb)" //config: default y @@ -74,6 +82,13 @@ //config: help //config: Configure network devices with "ip". //config: +//config:config FEATURE_IP_LINK_CAN +//config: bool "ip link can" +//config: default n +//config: depends on IP_LINK_CAN +//config: help +//config: Configure CAN devices with "ip". +//config: //config:config FEATURE_IP_ROUTE //config: bool "ip route" //config: default y @@ -122,6 +137,7 @@ //applet:IF_IP( APPLET_NOEXEC(ip , ip , BB_DIR_SBIN, BB_SUID_DROP, ip )) //applet:IF_IPADDR( APPLET_NOEXEC(ipaddr , ipaddr , BB_DIR_SBIN, BB_SUID_DROP, ipaddr )) //applet:IF_IPLINK( APPLET_NOEXEC(iplink , iplink , BB_DIR_SBIN, BB_SUID_DROP, iplink )) +//applet:IF_IPLINK_CAN(APPLET_NOEXEC(iplinkcan , iplinkcan , BB_DIR_SBIN, BB_SUID_DROP, iplinkcan)) //applet:IF_IPROUTE( APPLET_NOEXEC(iproute , iproute , BB_DIR_SBIN, BB_SUID_DROP, iproute )) //applet:IF_IPRULE( APPLET_NOEXEC(iprule , iprule , BB_DIR_SBIN, BB_SUID_DROP, iprule )) //applet:IF_IPTUNNEL(APPLET_NOEXEC(iptunnel, iptunnel, BB_DIR_SBIN, BB_SUID_DROP, iptunnel)) @@ -130,6 +146,7 @@ //kbuild:lib-$(CONFIG_IP) += ip.o //kbuild:lib-$(CONFIG_IPADDR) += ip.o //kbuild:lib-$(CONFIG_IPLINK) += ip.o +//kbuild:lib-$(CONFIG_IPLINK_CAN) += ip.o //kbuild:lib-$(CONFIG_IPROUTE) += ip.o //kbuild:lib-$(CONFIG_IPRULE) += ip.o //kbuild:lib-$(CONFIG_IPTUNNEL) += ip.o @@ -149,10 +166,16 @@ //usage: "ipaddr show|flush [dev IFACE] [scope SCOPE] [to PREFIX] [label PATTERN]" //usage: //--------------123456789.123456789.123456789.123456789.123456789.123456789.123456789.123....79 +//usage:#if ENABLE_FEATURE_IP_LINK_CAN +//usage:#define iplink_type_usage "\n [type TYPE ARGS]" +//usage:#else +//usage:#define iplink_type_usage "" +//usage:#endif //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: IF_FEATURE_IP_LINK(iplink_type_usage) // * short help shows only "set" command, long help continues (with just one "\n") // * and shows all other commands: //usage:#define iplink_full_usage "\n" @@ -207,6 +230,59 @@ // bond_slave | ipvlan | geneve | bridge_slave | vrf } //usage: //--------------123456789.123456789.123456789.123456789.123456789.123456789.123456789.123....79 +//usage:#define iplinkcan_trivial_usage +//usage: /*Usage:iplinkcan*/"set DEVICE type can" +//usage:#define iplinkcan_full_usage "\n\n" +//usage: " [bitrate BITRATE [sample-point SAMPLE-POINT]] |\n" +//usage: " [tq TQ prop-seg PROP_SEG phase-seg1 PHASE-SEG1\n" +//usage: " phase-seg2 PHASE-SEG2 [sjw SJW]]\n" +//usage: "\n" +//usage: " [dbitrate BITRATE [dsample-point SAMPLE-POINT]] |\n" +//usage: " [dtq TQ dprop-seg PROP_SEG dphase-seg1 PHASE-SEG1\n" +//usage: " dphase-seg2 PHASE-SEG2 [dsjw SJW]]\n" +//usage: "\n" +//usage: " [loopback on|off] [listen-only on|off] [triple-sampling on|off]\n" +//usage: " [one-shot on|off] [berr-reporting on|off]\n" +//usage: " [fd on|off] [fd-non-iso on|off] [presume-ack on|off]\n" +//usage: "\n" +//usage: " [restart-ms TIME-MS] [restart]\n" +//usage: "\n" +//usage: " [termination 0..65535]\n" +//usage: +//upstream man ip-link-can: +//Usage: ip link set DEVICE type can +// [ bitrate BITRATE [ sample-point SAMPLE-POINT] ] | +// [ tq TQ prop-seg PROP_SEG phase-seg1 PHASE-SEG1 +// phase-seg2 PHASE-SEG2 [ sjw SJW ] ] +// +// [ dbitrate BITRATE [ dsample-point SAMPLE-POINT] ] | +// [ dtq TQ dprop-seg PROP_SEG dphase-seg1 PHASE-SEG1 +// dphase-seg2 PHASE-SEG2 [ dsjw SJW ] ] +// +// [ loopback { on | off } ] +// [ listen-only { on | off } ] +// [ triple-sampling { on | off } ] +// [ one-shot { on | off } ] +// [ berr-reporting { on | off } ] +// [ fd { on | off } ] +// [ fd-non-iso { on | off } ] +// [ presume-ack { on | off } ] +// +// [ restart-ms TIME-MS ] +// [ restart ] +// +// [ termination { 0..65535 } ] +// +// Where: BITRATE := { 1..1000000 } +// SAMPLE-POINT := { 0.000..0.999 } +// TQ := { NUMBER } +// PROP-SEG := { 1..8 } +// PHASE-SEG1 := { 1..8 } +// PHASE-SEG2 := { 1..8 } +// SJW := { 1..4 } +// RESTART-MS := { 0 | NUMBER } +//usage: +//--------------123456789.123456789.123456789.123456789.123456789.123456789.123456789.123....79 //usage:#define iproute_trivial_usage //usage: "list|flush|add|del|change|append|replace|test ROUTE" //usage:#define iproute_full_usage "\n\n" @@ -327,6 +403,7 @@ typedef int FAST_FUNC (*ip_func_ptr_t)(char**); #if ENABLE_IPADDR \ || ENABLE_IPLINK \ + || ENABLE_IPLINK_CAN \ || ENABLE_IPROUTE \ || ENABLE_IPRULE \ || ENABLE_IPTUNNEL \ @@ -352,6 +429,13 @@ int iplink_main(int argc UNUSED_PARAM, char **argv) return ip_do(do_iplink, argv); } #endif +#if ENABLE_IPLINK_CAN +int iplinkcan_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int iplinkcan_main(int argc UNUSED_PARAM, char **argv) +{ + return ip_do(do_iplink, argv); +} +#endif #if ENABLE_IPROUTE int iproute_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int iproute_main(int argc UNUSED_PARAM, char **argv) diff --git a/networking/libiproute/iplink.c b/networking/libiproute/iplink.c index 68d1990445fe..f97169714d0f 100644 --- a/networking/libiproute/iplink.c +++ b/networking/libiproute/iplink.c @@ -11,10 +11,17 @@ #include #include +#include #include "ip_common.h" /* #include "libbb.h" is inside */ #include "rt_names.h" #include "utils.h" +#if ENABLE_FEATURE_IP_LINK_CAN +#define ENABLE_FEATURE_IP_LINK_IFACE 1 +#else +#define ENABLE_FEATURE_IP_LINK_IFACE 0 +#endif + #undef ETH_P_8021AD #define ETH_P_8021AD 0x88A8 #undef VLAN_FLAG_REORDER_HDR @@ -28,6 +35,11 @@ #undef IFLA_VLAN_PROTOCOL #define IFLA_VLAN_PROTOCOL 5 +#ifndef NLMSG_TAIL +#define NLMSG_TAIL(nmsg) \ + ((struct rtattr *) (((void *) (nmsg)) + NLMSG_ALIGN((nmsg)->nlmsg_len))) +#endif + #ifndef IFLA_LINKINFO # define IFLA_LINKINFO 18 # define IFLA_INFO_KIND 1 @@ -55,6 +67,13 @@ struct ifla_vlan_flags { #define str_on_off "on\0""off\0" +enum { + PARM_on = 0, + PARM_off +}; + +typedef void FAST_FUNC(*ip_type_set_func_ptr_t)(char*, char**); + /* Exits on error */ static int get_ctl_fd(void) { @@ -241,10 +260,261 @@ static void die_must_be_on_off(const char *msg) bb_error_msg_and_die("argument of \"%s\" must be \"on\" or \"off\"", msg); } +#if ENABLE_FEATURE_IP_LINK_CAN +static float FAST_FUNC get_float(char *arg, const char *errmsg) +{ + float ret; + char *ptr; + + if (!arg || !*arg) + invarg_1_to_2(arg, errmsg); /* does not return */ + + ret = strtof(arg, &ptr); + if (!ptr || ptr == arg || *ptr) + invarg_1_to_2(arg, errmsg); /* does not return */ + + return ret; +} + +static void do_set_can(char *dev, char **argv) +{ + struct can_bittiming bt = {}, dbt = {}; + struct can_ctrlmode cm = {}; + char *keyword; + static const char keywords[] ALIGN1 = + "bitrate\0""sample-point\0""tq\0" + "prop-seg\0""phase-seg1\0""phase-seg2\0""sjw\0" + "dbitrate\0""dsample-point\0""dtq\0" + "dprop-seg\0""dphase-seg1\0""dphase-seg2\0""dsjw\0" + "loopback\0""listen-only\0""triple-sampling\0" + "one-shot\0""berr-reporting\0" + "fd\0""fd-non-iso\0""presume-ack\0" + "cc-len8-dlc\0""restart\0""restart-ms\0" + "termination\0"; + enum { ARG_bitrate = 0, ARG_sample_point, ARG_tq, + ARG_prop_seg, ARG_phase_seg1, ARG_phase_seg2, ARG_sjw, + ARG_dbitrate, ARG_dsample_point, ARG_dtq, + ARG_dprop_seg, ARG_dphase_seg1, ARG_dphase_seg2, ARG_dsjw, + ARG_loopback, ARG_listen_only, ARG_triple_sampling, + ARG_one_shot, ARG_berr_reporting, + ARG_fd, ARG_fd_non_iso, ARG_presume_ack, + ARG_cc_len8_dlc, ARG_restart, ARG_restart_ms, + ARG_termination }; + struct rtnl_handle rth; + struct { + struct nlmsghdr n; + struct ifinfomsg i; + char buf[1024]; + } req; + size_t dev_len; + struct rtattr *linkinfo, *data; + smalluint key, param; + + 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); + dev_len = strlen(dev); + if (dev_len < 2 || dev_len > IFNAMSIZ) + invarg_1_to_2(dev, "dev"); + + addattr_l(&req.n, sizeof(req), IFLA_IFNAME, dev, dev_len); + linkinfo = NLMSG_TAIL(&req.n); + addattr_l(&req.n, sizeof(req), IFLA_LINKINFO, NULL, 0); + addattr_l(&req.n, sizeof(req), IFLA_INFO_KIND, (void *)"can", + strlen("can")); + data = NLMSG_TAIL(&req.n); + addattr_l(&req.n, sizeof(req), IFLA_INFO_DATA, NULL, 0); + while (*argv) { + key = index_in_substrings(keywords, *argv); + keyword = *argv; + //printf("%s: key: %d, *argv: %s\n", __func__, key, *argv); + switch (key) { + case ARG_bitrate: + case ARG_tq: + case ARG_prop_seg: + case ARG_phase_seg1: + case ARG_phase_seg2: + case ARG_sjw: { + __u32 *val; + + NEXT_ARG(); + if (key == ARG_bitrate) + val = &bt.bitrate; + else if (key == ARG_tq) + val = &bt.tq; + else if (key == ARG_prop_seg) + val = &bt.prop_seg; + else if (key == ARG_phase_seg1) + val = &bt.phase_seg1; + else if (key == ARG_phase_seg2) + val = &bt.phase_seg2; + else + val = &bt.sjw; + + *val = get_u32(*argv, keyword); + break; + } + case ARG_sample_point: { + float sp; + + NEXT_ARG(); + sp = get_float(*argv, keyword); + bt.sample_point = (__u32)(sp * 1000); + break; + } + case ARG_dbitrate: + case ARG_dtq: + case ARG_dprop_seg: + case ARG_dphase_seg1: + case ARG_dphase_seg2: + case ARG_dsjw: { + __u32 *val; + + NEXT_ARG(); + if (key == ARG_dbitrate) + val = &dbt.bitrate; + else if (key == ARG_dtq) + val = &dbt.tq; + else if (key == ARG_dprop_seg) + val = &dbt.prop_seg; + else if (key == ARG_dphase_seg1) + val = &dbt.phase_seg1; + else if (key == ARG_dphase_seg2) + val = &dbt.phase_seg2; + else + val = &dbt.sjw; + + *val = get_u32(*argv, keyword); + break; + } + case ARG_dsample_point: { + float sp; + + NEXT_ARG(); + sp = get_float(*argv, keyword); + dbt.sample_point = (__u32)(sp * 1000); + break; + } + case ARG_loopback: + case ARG_listen_only: + case ARG_triple_sampling: + case ARG_one_shot: + case ARG_berr_reporting: + case ARG_fd: + case ARG_fd_non_iso: + case ARG_presume_ack: + case ARG_cc_len8_dlc: { + __u32 flag = 0; + + NEXT_ARG(); + param = index_in_strings(str_on_off, *argv); + if (param < 0) + die_must_be_on_off(keyword); + + if (key == ARG_loopback) + flag = CAN_CTRLMODE_LOOPBACK; + else if (key == ARG_listen_only) + flag = CAN_CTRLMODE_LISTENONLY; + else if (key == ARG_triple_sampling) + flag = CAN_CTRLMODE_3_SAMPLES; + else if (key == ARG_one_shot) + flag = CAN_CTRLMODE_ONE_SHOT; + else if (key == ARG_berr_reporting) + flag = CAN_CTRLMODE_BERR_REPORTING; + else if (key == ARG_fd) + flag = CAN_CTRLMODE_FD; + else if (key == ARG_fd_non_iso) + flag = CAN_CTRLMODE_FD_NON_ISO; + else if (key == ARG_presume_ack) + flag = CAN_CTRLMODE_PRESUME_ACK; + else +#if defined(CAN_CTRLMODE_CC_LEN8_DLC) + flag = CAN_CTRLMODE_CC_LEN8_DLC; +#else + die_must_be_on_off(keyword); +#endif + cm.mask |= flag; + if (param == PARM_on) + cm.flags |= flag; + + break; + } + case ARG_restart: { + __u32 val = 1; + + NEXT_ARG(); + addattr_l(&req.n, sizeof(req), IFLA_CAN_RESTART, &val, sizeof(val)); + break; + } + case ARG_restart_ms: { + __u32 val; + + NEXT_ARG(); + val = get_u32(*argv, keyword); + addattr_l(&req.n, sizeof(req), IFLA_CAN_RESTART_MS, &val, sizeof(val)); + break; + } + case ARG_termination: { + __u16 val; + + NEXT_ARG(); + val = get_u16(*argv, keyword); + addattr_l(&req.n, sizeof(req), IFLA_CAN_TERMINATION, &val, sizeof(val)); + break; + } + default: + break; + } + + argv++; + } + + if (bt.bitrate || bt.tq) + addattr_l(&req.n, sizeof(req), IFLA_CAN_BITTIMING, &bt, sizeof(bt)); + + if (cm.mask) + addattr_l(&req.n, sizeof(req), IFLA_CAN_CTRLMODE, &cm, sizeof(cm)); + + data->rta_len = (void *)NLMSG_TAIL(&req.n) - (void *)data; + linkinfo->rta_len = (void *)NLMSG_TAIL(&req.n) - (void *)linkinfo; + + if (rtnl_talk(&rth, &req.n, 0, 0, NULL, NULL, NULL) < 0) + xfunc_die(); +} +#endif + +#if ENABLE_FEATURE_IP_LINK_IFACE +static void do_set_iface(char *type, char *dev, char **argv) +{ + static const char keywords[] ALIGN1 = "" + IF_FEATURE_IP_LINK_CAN("can\0") + ; + static const ip_type_set_func_ptr_t funcs[] ALIGN_PTR = { + IF_FEATURE_IP_LINK_CAN(do_set_can,) + }; + ip_type_set_func_ptr_t func; + int key; + + key = index_in_substrings(keywords, type); + if (key < 0) + return; + func = funcs[key]; + func(dev, argv); +} +#endif + /* Return value becomes exitcode. It's okay to not return at all */ static int do_set(char **argv) { char *dev = NULL; +#if ENABLE_FEATURE_IP_LINK_IFACE + char *type = NULL; +#endif uint32_t mask = 0; uint32_t flags = 0; int qlen = -1; @@ -261,18 +531,24 @@ static int do_set(char **argv) "up\0""down\0""name\0""mtu\0""qlen\0""multicast\0" "arp\0""promisc\0""address\0""netns\0" "master\0""nomaster\0" +#if ENABLE_FEATURE_IP_LINK_IFACE + "type\0" +#endif "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, +#if ENABLE_FEATURE_IP_LINK_IFACE + ARG_type, +#endif ARG_dev }; - enum { PARM_on = 0, PARM_off }; smalluint key; while (*argv) { /* substring search ensures that e.g. "addr" and "address" * are both accepted */ key = index_in_substrings(keywords, *argv); + //printf("%s: key: %d, *argv: %s\n", __func__, key, *argv); if (key == ARG_up) { mask |= IFF_UP; flags |= IFF_UP; @@ -304,6 +580,13 @@ static int do_set(char **argv) } else if (key == ARG_netns) { NEXT_ARG(); netns = get_unsigned(*argv, "netns"); +#if ENABLE_FEATURE_IP_LINK_IFACE + } else if (key == ARG_type) { + NEXT_ARG(); + type = *argv; + argv++; + break; +#endif } else if (key >= ARG_dev) { /* ^^^^^^ ">=" here results in "dev IFACE" treated as default */ if (key == ARG_dev) { @@ -311,6 +594,7 @@ static int do_set(char **argv) } if (dev) duparg2("dev", *argv); + dev = *argv; } else { /* "on|off" options */ @@ -496,6 +780,10 @@ static int do_set(char **argv) } if (mask) do_chflags(dev, flags, mask); +#if ENABLE_FEATURE_IP_LINK_IFACE + if (type) + do_set_iface(type, dev, argv); +#endif return 0; } @@ -531,10 +819,6 @@ static void vlan_parse_opt(char **argv, struct nlmsghdr *n, unsigned int size) PROTO_8021Q = 0, PROTO_8021AD, }; - enum { - PARM_on = 0, - PARM_off - }; int arg; uint16_t id, proto; struct ifla_vlan_flags flags = {}; @@ -610,10 +894,6 @@ static void vrf_parse_opt(char **argv, struct nlmsghdr *n, unsigned int size) addattr_l(n, size, IFLA_VRF_TABLE, &table, sizeof(table)); } -#ifndef NLMSG_TAIL -#define NLMSG_TAIL(nmsg) \ - ((struct rtattr *) (((void *) (nmsg)) + NLMSG_ALIGN((nmsg)->nlmsg_len))) -#endif /* Return value becomes exitcode. It's okay to not return at all */ static int do_add_or_delete(char **argv, const unsigned rtm) {