Hi Nikolaus, On Thu, Apr 27, 2023 at 11:28 AM Nikolaus Voss <[email protected]> wrote: > > Hi Dario, > > I posted a more minimalistic approach
This is the reason why I added the CONFIG_IPLINK_CAN option. My use case also required management of the 'loopback' and 'listenonly' options: ip link set can0 type can bitrate 125000 loopback on listen-only on https://lore.kernel.org/all/[email protected]/ Anyway, I think we both agree that busybox lacks a CAN-type management for the 'ip link' command Thanks and regards, Dario > some time ago: > > http://lists.busybox.net/pipermail/busybox/2022-August/089822.html > > Thanks, > Niko > > > On Thu, 20 Apr 2023, Dario Binacchi wrote: > > > 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 <[email protected]> > > [1] https://marc.info/?l=linux-netdev&m=167999323611710&w=2 > > Signed-off-by: Dario Binacchi <[email protected]> > > --- > > 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 <netinet/if_ether.h> > > > > #include <linux/if_vlan.h> > > +#include <linux/can/netlink.h> > > #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) > > { > > > -- Dario Binacchi Senior Embedded Linux Developer [email protected] __________________________________ Amarula Solutions SRL Via Le Canevare 30, 31100 Treviso, Veneto, IT T. +39 042 243 5310 [email protected] www.amarulasolutions.com _______________________________________________ busybox mailing list [email protected] http://lists.busybox.net/mailman/listinfo/busybox
