diff options
29 files changed, 1267 insertions, 313 deletions
@@ -15,5 +15,6 @@ Makefile.in /libtool /stamp-h1 -/doxygen.cfg /libmnl.pc + +/libmnl-*.tar.bz2 diff --git a/Makefile.am b/Makefile.am index dec85d0..94e6935 100644 --- a/Makefile.am +++ b/Makefile.am @@ -2,8 +2,8 @@ include $(top_srcdir)/Make_global.am ACLOCAL_AMFLAGS = -I m4 -SUBDIRS = src include examples -DIST_SUBDIRS = src include examples +SUBDIRS = src include examples doxygen +DIST_SUBDIRS = src include examples doxygen pkgconfigdir = $(libdir)/pkgconfig pkgconfig_DATA = libmnl.pc diff --git a/configure.ac b/configure.ac index 35b2531..4698aec 100644 --- a/configure.ac +++ b/configure.ac @@ -1,11 +1,11 @@ dnl Process this file with autoconf to create configure. -AC_INIT([libmnl], [1.0.4]) +AC_INIT([libmnl], [1.0.5]) AC_CONFIG_AUX_DIR([build-aux]) AC_CANONICAL_HOST AC_CONFIG_MACRO_DIR([m4]) AC_CONFIG_HEADERS([config.h]) -AM_INIT_AUTOMAKE([foreign tar-pax no-dist-gzip dist-bzip2 1.6 subdir-objects]) +AM_INIT_AUTOMAKE([foreign tar-pax no-dist-gzip dist-xz 1.6 subdir-objects]) dnl kernel style compile messages m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])]) @@ -27,5 +27,44 @@ regular_CFLAGS="-Wall -Waggregate-return -Wmissing-declarations \ -Wformat=2 -pipe" AC_SUBST([regular_CPPFLAGS]) AC_SUBST([regular_CFLAGS]) -AC_CONFIG_FILES([Makefile src/Makefile include/Makefile include/libmnl/Makefile include/linux/Makefile include/linux/netfilter/Makefile examples/Makefile examples/genl/Makefile examples/kobject/Makefile examples/netfilter/Makefile examples/rtnl/Makefile libmnl.pc doxygen.cfg]) +AC_CONFIG_FILES([Makefile + src/Makefile + include/Makefile + include/libmnl/Makefile + include/linux/Makefile + include/linux/can/Makefile + include/linux/netfilter/Makefile + examples/Makefile + examples/genl/Makefile + examples/kobject/Makefile + examples/netfilter/Makefile + examples/rtnl/Makefile + libmnl.pc + doxygen/doxygen.cfg + doxygen/Makefile]) + +AC_ARG_WITH([doxygen], [AS_HELP_STRING([--with-doxygen], + [create doxygen documentation])], + [with_doxygen="$withval"], [with_doxygen=yes]) + +AS_IF([test "x$with_doxygen" != xno], [ + AC_CHECK_PROGS([DOXYGEN], [doxygen]) + AC_CHECK_PROGS([DOT], [dot], [""]) + AS_IF([test "x$DOT" != "x"], + [AC_SUBST(HAVE_DOT, YES)], + [AC_SUBST(HAVE_DOT, NO)]) +]) + +AM_CONDITIONAL([HAVE_DOXYGEN], [test -n "$DOXYGEN"]) +AS_IF([test "x$DOXYGEN" = x], [ + AS_IF([test "x$with_doxygen" != xno], [ + dnl Only run doxygen Makefile if doxygen installed + AC_MSG_WARN([Doxygen not found - continuing without Doxygen support]) + with_doxygen=no + ]) +]) AC_OUTPUT + +echo " +libmnl configuration: + doxygen: ${with_doxygen}" diff --git a/doxygen.cfg.in b/doxygen.cfg.in deleted file mode 100644 index 31f0102..0000000 --- a/doxygen.cfg.in +++ /dev/null @@ -1,184 +0,0 @@ -DOXYFILE_ENCODING = UTF-8 -PROJECT_NAME = @PACKAGE@ -PROJECT_NUMBER = @VERSION@ -OUTPUT_DIRECTORY = doxygen -CREATE_SUBDIRS = NO -OUTPUT_LANGUAGE = English -BRIEF_MEMBER_DESC = YES -REPEAT_BRIEF = YES -ABBREVIATE_BRIEF = -ALWAYS_DETAILED_SEC = NO -INLINE_INHERITED_MEMB = NO -FULL_PATH_NAMES = NO -STRIP_FROM_PATH = -STRIP_FROM_INC_PATH = -SHORT_NAMES = NO -JAVADOC_AUTOBRIEF = NO -QT_AUTOBRIEF = NO -MULTILINE_CPP_IS_BRIEF = NO -INHERIT_DOCS = YES -SEPARATE_MEMBER_PAGES = NO -TAB_SIZE = 8 -ALIASES = -OPTIMIZE_OUTPUT_FOR_C = YES -OPTIMIZE_OUTPUT_JAVA = NO -OPTIMIZE_FOR_FORTRAN = NO -OPTIMIZE_OUTPUT_VHDL = NO -BUILTIN_STL_SUPPORT = NO -CPP_CLI_SUPPORT = NO -SIP_SUPPORT = NO -DISTRIBUTE_GROUP_DOC = NO -SUBGROUPING = YES -TYPEDEF_HIDES_STRUCT = NO -EXTRACT_ALL = NO -EXTRACT_PRIVATE = NO -EXTRACT_STATIC = NO -EXTRACT_LOCAL_CLASSES = YES -EXTRACT_LOCAL_METHODS = NO -EXTRACT_ANON_NSPACES = NO -HIDE_UNDOC_MEMBERS = NO -HIDE_UNDOC_CLASSES = NO -HIDE_FRIEND_COMPOUNDS = NO -HIDE_IN_BODY_DOCS = NO -INTERNAL_DOCS = NO -CASE_SENSE_NAMES = YES -HIDE_SCOPE_NAMES = NO -SHOW_INCLUDE_FILES = YES -INLINE_INFO = YES -SORT_MEMBER_DOCS = YES -SORT_BRIEF_DOCS = NO -SORT_GROUP_NAMES = NO -SORT_BY_SCOPE_NAME = NO -GENERATE_TODOLIST = YES -GENERATE_TESTLIST = YES -GENERATE_BUGLIST = YES -GENERATE_DEPRECATEDLIST= YES -ENABLED_SECTIONS = -MAX_INITIALIZER_LINES = 30 -SHOW_USED_FILES = YES -SHOW_DIRECTORIES = NO -FILE_VERSION_FILTER = -QUIET = NO -WARNINGS = YES -WARN_IF_UNDOCUMENTED = YES -WARN_IF_DOC_ERROR = YES -WARN_NO_PARAMDOC = NO -WARN_FORMAT = "$file:$line: $text" -WARN_LOGFILE = -INPUT = . -INPUT_ENCODING = UTF-8 -FILE_PATTERNS = *.c libmnl.h -RECURSIVE = YES -EXCLUDE = -EXCLUDE_SYMLINKS = NO -EXCLUDE_PATTERNS = */.git/* .*.d -EXCLUDE_SYMBOLS = EXPORT_SYMBOL -EXAMPLE_PATH = -EXAMPLE_PATTERNS = -EXAMPLE_RECURSIVE = NO -IMAGE_PATH = -INPUT_FILTER = "sed 's/EXPORT_SYMBOL//g'" -FILTER_PATTERNS = -FILTER_SOURCE_FILES = NO -SOURCE_BROWSER = YES -INLINE_SOURCES = NO -STRIP_CODE_COMMENTS = YES -REFERENCED_BY_RELATION = NO -REFERENCES_RELATION = NO -REFERENCES_LINK_SOURCE = YES -USE_HTAGS = NO -VERBATIM_HEADERS = YES -ALPHABETICAL_INDEX = NO -COLS_IN_ALPHA_INDEX = 5 -IGNORE_PREFIX = -GENERATE_HTML = YES -HTML_OUTPUT = html -HTML_FILE_EXTENSION = .html -HTML_HEADER = -HTML_STYLESHEET = -HTML_ALIGN_MEMBERS = YES -GENERATE_HTMLHELP = NO -GENERATE_DOCSET = NO -DOCSET_FEEDNAME = "Doxygen generated docs" -DOCSET_BUNDLE_ID = org.doxygen.Project -HTML_DYNAMIC_SECTIONS = NO -CHM_FILE = -HHC_LOCATION = -GENERATE_CHI = NO -BINARY_TOC = NO -TOC_EXPAND = NO -DISABLE_INDEX = NO -ENUM_VALUES_PER_LINE = 4 -GENERATE_TREEVIEW = NO -TREEVIEW_WIDTH = 250 -GENERATE_LATEX = NO -LATEX_OUTPUT = latex -LATEX_CMD_NAME = latex -MAKEINDEX_CMD_NAME = makeindex -COMPACT_LATEX = NO -PAPER_TYPE = a4wide -EXTRA_PACKAGES = -LATEX_HEADER = -PDF_HYPERLINKS = YES -USE_PDFLATEX = YES -LATEX_BATCHMODE = NO -LATEX_HIDE_INDICES = NO -GENERATE_RTF = NO -RTF_OUTPUT = rtf -COMPACT_RTF = NO -RTF_HYPERLINKS = NO -RTF_STYLESHEET_FILE = -RTF_EXTENSIONS_FILE = -GENERATE_MAN = YES -MAN_OUTPUT = man -MAN_EXTENSION = .3 -MAN_LINKS = NO -GENERATE_XML = NO -XML_OUTPUT = xml -XML_SCHEMA = -XML_DTD = -XML_PROGRAMLISTING = YES -GENERATE_AUTOGEN_DEF = NO -GENERATE_PERLMOD = NO -PERLMOD_LATEX = NO -PERLMOD_PRETTY = YES -PERLMOD_MAKEVAR_PREFIX = -ENABLE_PREPROCESSING = YES -MACRO_EXPANSION = NO -EXPAND_ONLY_PREDEF = NO -SEARCH_INCLUDES = YES -INCLUDE_PATH = -INCLUDE_FILE_PATTERNS = -PREDEFINED = -EXPAND_AS_DEFINED = -SKIP_FUNCTION_MACROS = YES -TAGFILES = -GENERATE_TAGFILE = -ALLEXTERNALS = NO -EXTERNAL_GROUPS = YES -PERL_PATH = /usr/bin/perl -CLASS_DIAGRAMS = YES -MSCGEN_PATH = -HIDE_UNDOC_RELATIONS = YES -HAVE_DOT = YES -CLASS_GRAPH = YES -COLLABORATION_GRAPH = YES -GROUP_GRAPHS = YES -UML_LOOK = NO -TEMPLATE_RELATIONS = NO -INCLUDE_GRAPH = YES -INCLUDED_BY_GRAPH = YES -CALL_GRAPH = NO -CALLER_GRAPH = NO -GRAPHICAL_HIERARCHY = YES -DIRECTORY_GRAPH = YES -DOT_IMAGE_FORMAT = png -DOT_PATH = -DOTFILE_DIRS = -DOT_GRAPH_MAX_NODES = 50 -MAX_DOT_GRAPH_DEPTH = 0 -DOT_TRANSPARENT = YES -DOT_MULTI_TARGETS = NO -GENERATE_LEGEND = YES -DOT_CLEANUP = YES -SEARCHENGINE = NO diff --git a/doxygen/.gitignore b/doxygen/.gitignore new file mode 100644 index 0000000..2196cf8 --- /dev/null +++ b/doxygen/.gitignore @@ -0,0 +1,4 @@ +doxyfile.stamp +doxygen.cfg +html/ +man/ diff --git a/doxygen/Makefile.am b/doxygen/Makefile.am new file mode 100644 index 0000000..4770fc7 --- /dev/null +++ b/doxygen/Makefile.am @@ -0,0 +1,25 @@ +if HAVE_DOXYGEN +doc_srcs = $(shell find $(top_srcdir)/src -name '*.c') + +doxyfile.stamp: $(doc_srcs) Makefile.am + rm -rf html man + doxygen doxygen.cfg >/dev/null + $(SHELL) $(top_srcdir)/doxygen/finalize_manpages.sh + touch doxyfile.stamp + +CLEANFILES = doxyfile.stamp + +all-local: doxyfile.stamp +clean-local: + rm -rf $(top_srcdir)/doxygen/man $(top_srcdir)/doxygen/html +install-data-local: + mkdir -p $(DESTDIR)$(mandir)/man3 + cp --no-dereference --preserve=links,mode,timestamps man/man3/*.3\ + $(DESTDIR)$(mandir)/man3/ + +# make distcheck needs uninstall-local +uninstall-local: + rm -r $(DESTDIR)$(mandir) man html doxyfile.stamp +endif + +EXTRA_DIST = finalize_manpages.sh diff --git a/doxygen/doxygen.cfg.in b/doxygen/doxygen.cfg.in new file mode 100644 index 0000000..24089ac --- /dev/null +++ b/doxygen/doxygen.cfg.in @@ -0,0 +1,23 @@ +# Difference with default Doxyfile 1.8.20 +PROJECT_NAME = @PACKAGE@ +PROJECT_NUMBER = @VERSION@ +OUTPUT_DIRECTORY = . +ABBREVIATE_BRIEF = +FULL_PATH_NAMES = NO +TAB_SIZE = 8 +OPTIMIZE_OUTPUT_FOR_C = YES +INPUT = @top_srcdir@ +FILE_PATTERNS = */src/*.c +RECURSIVE = YES +EXCLUDE_SYMBOLS = EXPORT_SYMBOL mnl_nlmsg_batch mnl_socket +EXAMPLE_PATTERNS = +INPUT_FILTER = "sed 's/EXPORT_SYMBOL//g'" +SOURCE_BROWSER = YES +ALPHABETICAL_INDEX = NO +SEARCHENGINE = NO +GENERATE_LATEX = NO +LATEX_CMD_NAME = latex +GENERATE_MAN = YES +MAN_LINKS = YES +HAVE_DOT = @HAVE_DOT@ +DOT_TRANSPARENT = YES diff --git a/doxygen/finalize_manpages.sh b/doxygen/finalize_manpages.sh new file mode 100644 index 0000000..6f230b1 --- /dev/null +++ b/doxygen/finalize_manpages.sh @@ -0,0 +1,40 @@ +# +# We need to use bash for its associative array facility +# +[ "$BASH" ] || exec bash $0 +# +# (`bash -p` prevents import of functions from the environment). +# +set -p + +declare -A renamed_page + +main(){ set -e; cd man/man3; rm -f _* + count_real_pages + rename_real_pages + make_symlinks +} + +count_real_pages(){ page_count=0 + for i in $(ls -S) + do head -n1 $i | grep -E -q '^\.so' && break + page_count=$(($page_count + 1)) + done + first_link=$(($page_count + 1)) +} + +rename_real_pages(){ for i in $(ls -S | head -n$page_count) + do for j in $(ls -S | tail -n+$first_link) + do grep -E -q $i$ $j && break + done + mv -f $i $j + renamed_page[$i]=$j + done +} + +make_symlinks(){ for j in $(ls -S | tail -n+$first_link) + do ln -sf ${renamed_page[$(cat $j | cut -f2 -d/)]} $j + done +} + +main diff --git a/examples/genl/.gitignore b/examples/genl/.gitignore index 57f0ca9..a7d8966 100644 --- a/examples/genl/.gitignore +++ b/examples/genl/.gitignore @@ -1 +1,2 @@ /genl-family-get +/genl-group-events
\ No newline at end of file diff --git a/examples/kobject/.gitignore b/examples/kobject/.gitignore new file mode 100644 index 0000000..4d95e59 --- /dev/null +++ b/examples/kobject/.gitignore @@ -0,0 +1 @@ +/kobject-event diff --git a/examples/netfilter/.gitignore b/examples/netfilter/.gitignore index f2f863f..bbeb031 100644 --- a/examples/netfilter/.gitignore +++ b/examples/netfilter/.gitignore @@ -1,3 +1,6 @@ /nf-log /nf-queue +/nfct-create-batch +/nfct-daemon +/nfct-dump /nfct-event diff --git a/examples/netfilter/nfct-dump.c b/examples/netfilter/nfct-dump.c index 114af61..cb8e52c 100644 --- a/examples/netfilter/nfct-dump.c +++ b/examples/netfilter/nfct-dump.c @@ -263,8 +263,8 @@ static int data_cb(const struct nlmsghdr *nlh, void *data) int main(void) { + char buf[MNL_SOCKET_DUMP_SIZE]; struct mnl_socket *nl; - char buf[MNL_SOCKET_BUFFER_SIZE]; struct nlmsghdr *nlh; struct nfgenmsg *nfh; uint32_t seq, portid; diff --git a/examples/rtnl/.gitignore b/examples/rtnl/.gitignore index 24ac633..4b16c53 100644 --- a/examples/rtnl/.gitignore +++ b/examples/rtnl/.gitignore @@ -1,8 +1,12 @@ /rtnl-addr-add +/rtnl-addr-dump +/rtnl-link-can /rtnl-link-dump /rtnl-link-dump2 /rtnl-link-dump3 /rtnl-link-event /rtnl-link-set +/rtnl-neigh-dump +/rtnl-route-event /rtnl-route-add /rtnl-route-dump diff --git a/examples/rtnl/Makefile.am b/examples/rtnl/Makefile.am index dd8a77d..5a28e09 100644 --- a/examples/rtnl/Makefile.am +++ b/examples/rtnl/Makefile.am @@ -2,6 +2,7 @@ include $(top_srcdir)/Make_global.am check_PROGRAMS = rtnl-addr-add \ rtnl-addr-dump \ + rtnl-link-can \ rtnl-link-dump rtnl-link-dump2 rtnl-link-dump3 \ rtnl-link-event \ rtnl-link-set \ @@ -13,6 +14,9 @@ check_PROGRAMS = rtnl-addr-add \ rtnl_addr_add_SOURCES = rtnl-addr-add.c rtnl_addr_add_LDADD = ../../src/libmnl.la +rtnl_link_can_SOURCES = rtnl-link-can.c +rtnl_link_can_LDADD = ../../src/libmnl.la + rtnl_addr_dump_SOURCES = rtnl-addr-dump.c rtnl_addr_dump_LDADD = ../../src/libmnl.la diff --git a/examples/rtnl/rtnl-addr-dump.c b/examples/rtnl/rtnl-addr-dump.c index b92b75f..675e9b0 100644 --- a/examples/rtnl/rtnl-addr-dump.c +++ b/examples/rtnl/rtnl-addr-dump.c @@ -76,12 +76,12 @@ static int data_cb(const struct nlmsghdr *nlh, void *data) int main(int argc, char *argv[]) { + char buf[MNL_SOCKET_DUMP_SIZE]; + unsigned int seq, portid; struct mnl_socket *nl; - char buf[MNL_SOCKET_BUFFER_SIZE]; struct nlmsghdr *nlh; struct rtgenmsg *rt; int ret; - unsigned int seq, portid; if (argc != 2) { fprintf(stderr, "Usage: %s <inet|inet6>\n", argv[0]); diff --git a/examples/rtnl/rtnl-link-can.c b/examples/rtnl/rtnl-link-can.c new file mode 100644 index 0000000..8ed70d1 --- /dev/null +++ b/examples/rtnl/rtnl-link-can.c @@ -0,0 +1,452 @@ +/* This example is placed in the public domain. */ +#include <errno.h> +#include <limits.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <time.h> + +#include <libmnl/libmnl.h> +#include <linux/can/netlink.h> +#include <linux/if.h> +#include <linux/if_link.h> +#include <linux/rtnetlink.h> + +static void incomplete_command(void) __attribute__((noreturn)); + +#define NEXT_ARG() \ + do { \ + if (argc <= 0) incomplete_command(); \ + argv++; \ + argc--; \ + } while (0) + +static void duparg2(const char *key, const char *arg) +{ + fprintf(stderr, + "Error: either \"%s\" is duplicate, or \"%s\" is a garbage.\n", + key, arg); + exit(-1); +} + +static void incomplete_command(void) +{ + fprintf(stderr, "Command line is not complete. Try option \"help\"\n"); + exit(EXIT_FAILURE); +} + +/* Returns false if 'prefix' is a not empty prefix of 'string'. + */ +static bool matches(const char *prefix, const char *string) +{ + if (!*prefix) + return true; + + while (*string && *prefix == *string) { + prefix++; + string++; + } + + return !!*prefix; +} + +static int get_u16(__u16 *val, const char *arg, int base) +{ + unsigned long res; + char *ptr; + + if (!arg || !*arg) + return -1; + + res = strtoul(arg, &ptr, base); + + /* empty string or trailing non-digits */ + if (!ptr || ptr == arg || *ptr) + return -1; + + /* overflow */ + if (res == ULONG_MAX && errno == ERANGE) + return -1; + + if (res > 0xFFFFUL) + return -1; + + *val = res; + return 0; +} + +static int get_u32(__u32 *val, const char *arg, int base) +{ + unsigned long res; + char *ptr; + + if (!arg || !*arg) + return -1; + + res = strtoul(arg, &ptr, base); + + /* empty string or trailing non-digits */ + if (!ptr || ptr == arg || *ptr) + return -1; + + /* overflow */ + if (res == ULONG_MAX && errno == ERANGE) + return -1; + + /* in case UL > 32 bits */ + if (res > 0xFFFFFFFFUL) + return -1; + + *val = res; + return 0; +} + +static int get_float(float *val, const char *arg) +{ + float res; + char *ptr; + + if (!arg || !*arg) + return -1; + + res = strtof(arg, &ptr); + if (!ptr || ptr == arg || *ptr) + return -1; + + *val = res; + return 0; +} + +static void set_ctrlmode(char *name, char *arg, + struct can_ctrlmode *cm, __u32 flags) +{ + if (strcmp(arg, "on") == 0) { + cm->flags |= flags; + } else if (strcmp(arg, "off") != 0) { + fprintf(stderr, + "Error: argument of \"%s\" must be \"on\" or \"off\", not \"%s\"\n", + name, arg); + exit(EXIT_FAILURE); + } + + cm->mask |= flags; +} + +static void invarg(const char *msg, const char *arg) +{ + fprintf(stderr, "Error: argument \"%s\" is wrong: %s\n", arg, msg); + exit(-1); +} + +static void print_usage(FILE *f) +{ + fprintf(f, + "Usage: ip link set DEVICE type can\n" + "\t[ bitrate BITRATE [ sample-point SAMPLE-POINT] ] |\n" + "\t[ tq TQ prop-seg PROP_SEG phase-seg1 PHASE-SEG1\n \t phase-seg2 PHASE-SEG2 [ sjw SJW ] ]\n" + "\n" + "\t[ dbitrate BITRATE [ dsample-point SAMPLE-POINT] ] |\n" + "\t[ dtq TQ dprop-seg PROP_SEG dphase-seg1 PHASE-SEG1\n \t dphase-seg2 PHASE-SEG2 [ dsjw SJW ] ]\n" + "\n" + "\t[ loopback { on | off } ]\n" + "\t[ listen-only { on | off } ]\n" + "\t[ triple-sampling { on | off } ]\n" + "\t[ one-shot { on | off } ]\n" + "\t[ berr-reporting { on | off } ]\n" + "\t[ fd { on | off } ]\n" + "\t[ fd-non-iso { on | off } ]\n" + "\t[ presume-ack { on | off } ]\n" + "\t[ cc-len8-dlc { on | off } ]\n" + "\n" + "\t[ restart-ms TIME-MS ]\n" + "\t[ restart ]\n" + "\n" + "\t[ termination { 0..65535 } ]\n" + "\n" + "\tWhere: BITRATE := { 1..1000000 }\n" + "\t SAMPLE-POINT := { 0.000..0.999 }\n" + "\t TQ := { NUMBER }\n" + "\t PROP-SEG := { 1..8 }\n" + "\t PHASE-SEG1 := { 1..8 }\n" + "\t PHASE-SEG2 := { 1..8 }\n" + "\t SJW := { 1..4 }\n" + "\t RESTART-MS := { 0 | NUMBER }\n" + ); +} + +static void usage(void) +{ + print_usage(stderr); +} + +static int iplink_set_can_parse(int argc, char **argv, struct nlmsghdr *nlh) +{ + struct can_bittiming bt = {}, dbt = {}; + struct can_ctrlmode cm = {}; + + while (argc > 0) { + if (matches(*argv, "bitrate") == 0) { + NEXT_ARG(); + if (get_u32(&bt.bitrate, *argv, 0)) + invarg("invalid \"bitrate\" value\n", *argv); + } else if (matches(*argv, "sample-point") == 0) { + float sp; + + NEXT_ARG(); + if (get_float(&sp, *argv)) + invarg("invalid \"sample-point\" value\n", + *argv); + + bt.sample_point = (__u32)(sp * 1000); + } else if (matches(*argv, "tq") == 0) { + NEXT_ARG(); + if (get_u32(&bt.tq, *argv, 0)) + invarg("invalid \"tq\" value\n", *argv); + } else if (matches(*argv, "prop-seg") == 0) { + NEXT_ARG(); + if (get_u32(&bt.prop_seg, *argv, 0)) + invarg("invalid \"prop-seg\" value\n", *argv); + } else if (matches(*argv, "phase-seg1") == 0) { + NEXT_ARG(); + if (get_u32(&bt.phase_seg1, *argv, 0)) + invarg("invalid \"phase-seg1\" value\n", *argv); + } else if (matches(*argv, "phase-seg2") == 0) { + NEXT_ARG(); + if (get_u32(&bt.phase_seg2, *argv, 0)) + invarg("invalid \"phase-seg2\" value\n", *argv); + } else if (matches(*argv, "sjw") == 0) { + NEXT_ARG(); + if (get_u32(&bt.sjw, *argv, 0)) + invarg("invalid \"sjw\" value\n", *argv); + } else if (matches(*argv, "dbitrate") == 0) { + NEXT_ARG(); + if (get_u32(&dbt.bitrate, *argv, 0)) + invarg("invalid \"dbitrate\" value\n", *argv); + } else if (matches(*argv, "dsample-point") == 0) { + float sp; + + NEXT_ARG(); + if (get_float(&sp, *argv)) + invarg("invalid \"dsample-point\" value\n", *argv); + dbt.sample_point = (__u32)(sp * 1000); + } else if (matches(*argv, "dtq") == 0) { + NEXT_ARG(); + if (get_u32(&dbt.tq, *argv, 0)) + invarg("invalid \"dtq\" value\n", *argv); + } else if (matches(*argv, "dprop-seg") == 0) { + NEXT_ARG(); + if (get_u32(&dbt.prop_seg, *argv, 0)) + invarg("invalid \"dprop-seg\" value\n", *argv); + } else if (matches(*argv, "dphase-seg1") == 0) { + NEXT_ARG(); + if (get_u32(&dbt.phase_seg1, *argv, 0)) + invarg("invalid \"dphase-seg1\" value\n", *argv); + } else if (matches(*argv, "dphase-seg2") == 0) { + NEXT_ARG(); + if (get_u32(&dbt.phase_seg2, *argv, 0)) + invarg("invalid \"dphase-seg2\" value\n", *argv); + } else if (matches(*argv, "dsjw") == 0) { + NEXT_ARG(); + if (get_u32(&dbt.sjw, *argv, 0)) + invarg("invalid \"dsjw\" value\n", *argv); + } else if (matches(*argv, "loopback") == 0) { + NEXT_ARG(); + set_ctrlmode("loopback", *argv, &cm, + CAN_CTRLMODE_LOOPBACK); + } else if (matches(*argv, "listen-only") == 0) { + NEXT_ARG(); + set_ctrlmode("listen-only", *argv, &cm, + CAN_CTRLMODE_LISTENONLY); + } else if (matches(*argv, "triple-sampling") == 0) { + NEXT_ARG(); + set_ctrlmode("triple-sampling", *argv, &cm, + CAN_CTRLMODE_3_SAMPLES); + } else if (matches(*argv, "one-shot") == 0) { + NEXT_ARG(); + set_ctrlmode("one-shot", *argv, &cm, + CAN_CTRLMODE_ONE_SHOT); + } else if (matches(*argv, "berr-reporting") == 0) { + NEXT_ARG(); + set_ctrlmode("berr-reporting", *argv, &cm, + CAN_CTRLMODE_BERR_REPORTING); + } else if (matches(*argv, "fd") == 0) { + NEXT_ARG(); + set_ctrlmode("fd", *argv, &cm, + CAN_CTRLMODE_FD); + } else if (matches(*argv, "fd-non-iso") == 0) { + NEXT_ARG(); + set_ctrlmode("fd-non-iso", *argv, &cm, + CAN_CTRLMODE_FD_NON_ISO); + } else if (matches(*argv, "presume-ack") == 0) { + NEXT_ARG(); + set_ctrlmode("presume-ack", *argv, &cm, + CAN_CTRLMODE_PRESUME_ACK); +#if defined(CAN_CTRLMODE_CC_LEN8_DLC) + } else if (matches(*argv, "cc-len8-dlc") == 0) { + NEXT_ARG(); + set_ctrlmode("cc-len8-dlc", *argv, &cm, + CAN_CTRLMODE_CC_LEN8_DLC); +#endif + } else if (matches(*argv, "restart") == 0) { + __u32 val = 1; + + mnl_attr_put(nlh, IFLA_CAN_RESTART, sizeof(val), &val); + } else if (matches(*argv, "restart-ms") == 0) { + __u32 val; + + NEXT_ARG(); + if (get_u32(&val, *argv, 0)) + invarg("invalid \"restart-ms\" value\n", *argv); + + mnl_attr_put(nlh, IFLA_CAN_RESTART_MS, sizeof(val), &val); + } else if (matches(*argv, "termination") == 0) { + __u16 val; + + NEXT_ARG(); + if (get_u16(&val, *argv, 0)) + invarg("invalid \"termination\" value\n", + *argv); + + mnl_attr_put(nlh, IFLA_CAN_TERMINATION, sizeof(val), &val); + } else { + fprintf(stderr, "unknown option \"%s\"\n", *argv); + usage(); + return -1; + } + + NEXT_ARG(); + } + + if (bt.bitrate || bt.tq) + mnl_attr_put(nlh, IFLA_CAN_BITTIMING, sizeof(bt), &bt); + + if (cm.mask) + mnl_attr_put(nlh, IFLA_CAN_CTRLMODE, sizeof(cm), &cm); + + return 0; +} + +int main(int argc, char *argv[]) +{ + char buf[MNL_SOCKET_BUFFER_SIZE]; + struct mnl_socket *nl; + struct nlmsghdr *nlh; + struct ifinfomsg *ifm; + int ret; + unsigned int seq, portid; + struct nlattr *linkinfo, *data; + const char *signatures[] = { + "ip", "link", "set", "" + }; + char *type = NULL; + char *dev = NULL; + int i; + + NEXT_ARG(); + for (i = 0; argc > 0 && signatures[i][0];) { + if (matches(*argv, signatures[i])) + incomplete_command(); + + NEXT_ARG(); + i++; + } + + if (argc == 0) + incomplete_command(); + + nlh = mnl_nlmsg_put_header(buf); + nlh->nlmsg_type = RTM_NEWLINK; + nlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK; + nlh->nlmsg_seq = seq = time(NULL); + ifm = mnl_nlmsg_put_extra_header(nlh, sizeof(*ifm)); + ifm->ifi_family = AF_UNSPEC; + ifm->ifi_change = 0; + ifm->ifi_flags = 0; + + while (argc > 0) { + if (matches(*argv, "up") == 0) { + ifm->ifi_change |= IFF_UP; + ifm->ifi_flags |= IFF_UP; + } else if (matches(*argv, "down") == 0) { + ifm->ifi_change |= IFF_UP; + ifm->ifi_flags &= ~IFF_UP; + } else if (matches(*argv, "type") == 0) { + NEXT_ARG(); + type = *argv; + NEXT_ARG(); + break; + } else if (matches(*argv, "help") == 0) { + usage(); + exit(EXIT_FAILURE); + } else { + if (matches(*argv, "dev") == 0) + NEXT_ARG(); + + if (dev) + duparg2("dev", *argv); + + dev = *argv; + } + + NEXT_ARG(); + } + + if (dev) + mnl_attr_put_str(nlh, IFLA_IFNAME, dev); + + if (type) { + if (matches(type, "can")) { + fprintf(stderr, "unknown type \"%s\"\n", type); + usage(); + exit(EXIT_FAILURE); + } + + linkinfo = mnl_attr_nest_start(nlh, IFLA_LINKINFO); + mnl_attr_put_str(nlh, IFLA_INFO_KIND, "can"); + data = mnl_attr_nest_start(nlh, IFLA_INFO_DATA); + + if (iplink_set_can_parse(argc, argv, nlh)) + return -1; + + mnl_attr_nest_end(nlh, data); + mnl_attr_nest_end(nlh, linkinfo); + } + + nl = mnl_socket_open(NETLINK_ROUTE); + if (nl == NULL) { + perror("mnl_socket_open"); + exit(EXIT_FAILURE); + } + + if (mnl_socket_bind(nl, 0, MNL_SOCKET_AUTOPID) < 0) { + perror("mnl_socket_bind"); + exit(EXIT_FAILURE); + } + + portid = mnl_socket_get_portid(nl); + + mnl_nlmsg_fprintf(stdout, nlh, nlh->nlmsg_len, + sizeof(struct ifinfomsg)); + + if (mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) < 0) { + perror("mnl_socket_sendto"); + exit(EXIT_FAILURE); + } + + ret = mnl_socket_recvfrom(nl, buf, sizeof(buf)); + if (ret == -1) { + perror("mnl_socket_recvfrom"); + exit(EXIT_FAILURE); + } + + ret = mnl_cb_run(buf, ret, seq, portid, NULL, NULL); + if (ret == -1) { + perror("mnl_cb_run"); + exit(EXIT_FAILURE); + } + + mnl_socket_close(nl); + + return 0; +} diff --git a/examples/rtnl/rtnl-link-dump.c b/examples/rtnl/rtnl-link-dump.c index f5d6312..031346f 100644 --- a/examples/rtnl/rtnl-link-dump.c +++ b/examples/rtnl/rtnl-link-dump.c @@ -81,12 +81,12 @@ static int data_cb(const struct nlmsghdr *nlh, void *data) int main(void) { + char buf[MNL_SOCKET_DUMP_SIZE]; + unsigned int seq, portid; struct mnl_socket *nl; - char buf[MNL_SOCKET_BUFFER_SIZE]; struct nlmsghdr *nlh; struct rtgenmsg *rt; int ret; - unsigned int seq, portid; nlh = mnl_nlmsg_put_header(buf); nlh->nlmsg_type = RTM_GETLINK; diff --git a/examples/rtnl/rtnl-link-dump2.c b/examples/rtnl/rtnl-link-dump2.c index b3ca3fa..890e51a 100644 --- a/examples/rtnl/rtnl-link-dump2.c +++ b/examples/rtnl/rtnl-link-dump2.c @@ -54,12 +54,12 @@ static int data_cb(const struct nlmsghdr *nlh, void *data) int main(void) { + char buf[MNL_SOCKET_DUMP_SIZE]; + unsigned int seq, portid; struct mnl_socket *nl; - char buf[MNL_SOCKET_BUFFER_SIZE]; struct nlmsghdr *nlh; struct rtgenmsg *rt; int ret; - unsigned int seq, portid; nlh = mnl_nlmsg_put_header(buf); nlh->nlmsg_type = RTM_GETLINK; diff --git a/examples/rtnl/rtnl-link-dump3.c b/examples/rtnl/rtnl-link-dump3.c index 2521214..a381da1 100644 --- a/examples/rtnl/rtnl-link-dump3.c +++ b/examples/rtnl/rtnl-link-dump3.c @@ -54,12 +54,12 @@ static int data_cb(const struct nlmsghdr *nlh, void *data) int main(void) { + char buf[MNL_SOCKET_DUMP_SIZE]; + unsigned int seq, portid; struct mnl_socket *nl; - char buf[MNL_SOCKET_BUFFER_SIZE]; struct nlmsghdr *nlh; struct rtgenmsg *rt; int ret; - unsigned int seq, portid; nlh = mnl_nlmsg_put_header(buf); nlh->nlmsg_type = RTM_GETLINK; diff --git a/examples/rtnl/rtnl-neigh-dump.c b/examples/rtnl/rtnl-neigh-dump.c index f4d5000..8dd5f7e 100644 --- a/examples/rtnl/rtnl-neigh-dump.c +++ b/examples/rtnl/rtnl-neigh-dump.c @@ -99,12 +99,12 @@ static int data_cb(const struct nlmsghdr *nlh, void *data) int main(int argc, char *argv[]) { + char buf[MNL_SOCKET_DUMP_SIZE]; + unsigned int seq, portid; struct mnl_socket *nl; - char buf[MNL_SOCKET_BUFFER_SIZE]; struct nlmsghdr *nlh; - struct rtgenmsg *rt; + struct ndmsg *nd; int ret; - unsigned int seq, portid; if (argc != 2) { fprintf(stderr, "Usage: %s <inet|inet6>\n", argv[0]); @@ -116,11 +116,11 @@ int main(int argc, char *argv[]) nlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP; nlh->nlmsg_seq = seq = time(NULL); - rt = mnl_nlmsg_put_extra_header(nlh, sizeof(struct rtgenmsg)); + nd = mnl_nlmsg_put_extra_header(nlh, sizeof(struct ndmsg)); if (strcmp(argv[1], "inet") == 0) - rt->rtgen_family = AF_INET; + nd->ndm_family = AF_INET; else if (strcmp(argv[1], "inet6") == 0) - rt->rtgen_family = AF_INET6; + nd->ndm_family = AF_INET6; nl = mnl_socket_open(NETLINK_ROUTE); if (nl == NULL) { diff --git a/examples/rtnl/rtnl-route-dump.c b/examples/rtnl/rtnl-route-dump.c index 17da80b..02ac6b2 100644 --- a/examples/rtnl/rtnl-route-dump.c +++ b/examples/rtnl/rtnl-route-dump.c @@ -298,12 +298,12 @@ static int data_cb(const struct nlmsghdr *nlh, void *data) int main(int argc, char *argv[]) { + char buf[MNL_SOCKET_DUMP_SIZE]; + unsigned int seq, portid; struct mnl_socket *nl; - char buf[MNL_SOCKET_BUFFER_SIZE]; struct nlmsghdr *nlh; struct rtmsg *rtm; int ret; - unsigned int seq, portid; if (argc != 2) { fprintf(stderr, "Usage: %s <inet|inet6>\n", argv[0]); diff --git a/include/libmnl/libmnl.h b/include/libmnl/libmnl.h index 0331da7..4bd0b92 100644 --- a/include/libmnl/libmnl.h +++ b/include/libmnl/libmnl.h @@ -18,6 +18,7 @@ extern "C" { #define MNL_SOCKET_AUTOPID 0 #define MNL_SOCKET_BUFFER_SIZE (sysconf(_SC_PAGESIZE) < 8192L ? sysconf(_SC_PAGESIZE) : 8192L) +#define MNL_SOCKET_DUMP_SIZE 32768 struct mnl_socket; diff --git a/include/linux/Makefile.am b/include/linux/Makefile.am index 08c600b..ee0993d 100644 --- a/include/linux/Makefile.am +++ b/include/linux/Makefile.am @@ -1,2 +1,2 @@ -SUBDIRS = netfilter -noinst_HEADERS = netlink.h socket.h +SUBDIRS = can netfilter +noinst_HEADERS = can.h netlink.h socket.h diff --git a/include/linux/can.h b/include/linux/can.h new file mode 100644 index 0000000..2c6a3ee --- /dev/null +++ b/include/linux/can.h @@ -0,0 +1,298 @@ +/* SPDX-License-Identifier: ((GPL-2.0-only WITH Linux-syscall-note) OR BSD-3-Clause) */ +/* + * linux/can.h + * + * Definitions for CAN network layer (socket addr / CAN frame / CAN filter) + * + * Authors: Oliver Hartkopp <oliver.hartkopp@volkswagen.de> + * Urs Thuermann <urs.thuermann@volkswagen.de> + * Copyright (c) 2002-2007 Volkswagen Group Electronic Research + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Volkswagen nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * Alternatively, provided that this notice is retained in full, this + * software may be distributed under the terms of the GNU General + * Public License ("GPL") version 2, in which case the provisions of the + * GPL apply INSTEAD OF those given above. + * + * The provided data structures and external interfaces from this code + * are not restricted to be used by modules with a GPL compatible license. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + */ + +#ifndef _UAPI_CAN_H +#define _UAPI_CAN_H + +#include <linux/types.h> +#include <linux/socket.h> +#include <linux/stddef.h> /* for offsetof */ + +/* controller area network (CAN) kernel definitions */ + +/* special address description flags for the CAN_ID */ +#define CAN_EFF_FLAG 0x80000000U /* EFF/SFF is set in the MSB */ +#define CAN_RTR_FLAG 0x40000000U /* remote transmission request */ +#define CAN_ERR_FLAG 0x20000000U /* error message frame */ + +/* valid bits in CAN ID for frame formats */ +#define CAN_SFF_MASK 0x000007FFU /* standard frame format (SFF) */ +#define CAN_EFF_MASK 0x1FFFFFFFU /* extended frame format (EFF) */ +#define CAN_ERR_MASK 0x1FFFFFFFU /* omit EFF, RTR, ERR flags */ +#define CANXL_PRIO_MASK CAN_SFF_MASK /* 11 bit priority mask */ + +/* + * Controller Area Network Identifier structure + * + * bit 0-28 : CAN identifier (11/29 bit) + * bit 29 : error message frame flag (0 = data frame, 1 = error message) + * bit 30 : remote transmission request flag (1 = rtr frame) + * bit 31 : frame format flag (0 = standard 11 bit, 1 = extended 29 bit) + */ +typedef __u32 canid_t; + +#define CAN_SFF_ID_BITS 11 +#define CAN_EFF_ID_BITS 29 +#define CANXL_PRIO_BITS CAN_SFF_ID_BITS + +/* + * Controller Area Network Error Message Frame Mask structure + * + * bit 0-28 : error class mask (see include/uapi/linux/can/error.h) + * bit 29-31 : set to zero + */ +typedef __u32 can_err_mask_t; + +/* CAN payload length and DLC definitions according to ISO 11898-1 */ +#define CAN_MAX_DLC 8 +#define CAN_MAX_RAW_DLC 15 +#define CAN_MAX_DLEN 8 + +/* CAN FD payload length and DLC definitions according to ISO 11898-7 */ +#define CANFD_MAX_DLC 15 +#define CANFD_MAX_DLEN 64 + +/* + * CAN XL payload length and DLC definitions according to ISO 11898-1 + * CAN XL DLC ranges from 0 .. 2047 => data length from 1 .. 2048 byte + */ +#define CANXL_MIN_DLC 0 +#define CANXL_MAX_DLC 2047 +#define CANXL_MAX_DLC_MASK 0x07FF +#define CANXL_MIN_DLEN 1 +#define CANXL_MAX_DLEN 2048 + +/** + * struct can_frame - Classical CAN frame structure (aka CAN 2.0B) + * @can_id: CAN ID of the frame and CAN_*_FLAG flags, see canid_t definition + * @len: CAN frame payload length in byte (0 .. 8) + * @can_dlc: deprecated name for CAN frame payload length in byte (0 .. 8) + * @__pad: padding + * @__res0: reserved / padding + * @len8_dlc: optional DLC value (9 .. 15) at 8 byte payload length + * len8_dlc contains values from 9 .. 15 when the payload length is + * 8 bytes but the DLC value (see ISO 11898-1) is greater then 8. + * CAN_CTRLMODE_CC_LEN8_DLC flag has to be enabled in CAN driver. + * @data: CAN frame payload (up to 8 byte) + */ +struct can_frame { + canid_t can_id; /* 32 bit CAN_ID + EFF/RTR/ERR flags */ + union { + /* CAN frame payload length in byte (0 .. CAN_MAX_DLEN) + * was previously named can_dlc so we need to carry that + * name for legacy support + */ + __u8 len; + __u8 can_dlc; /* deprecated */ + } __attribute__((packed)); /* disable padding added in some ABIs */ + __u8 __pad; /* padding */ + __u8 __res0; /* reserved / padding */ + __u8 len8_dlc; /* optional DLC for 8 byte payload length (9 .. 15) */ + __u8 data[CAN_MAX_DLEN] __attribute__((aligned(8))); +}; + +/* + * defined bits for canfd_frame.flags + * + * The use of struct canfd_frame implies the FD Frame (FDF) bit to + * be set in the CAN frame bitstream on the wire. The FDF bit switch turns + * the CAN controllers bitstream processor into the CAN FD mode which creates + * two new options within the CAN FD frame specification: + * + * Bit Rate Switch - to indicate a second bitrate is/was used for the payload + * Error State Indicator - represents the error state of the transmitting node + * + * As the CANFD_ESI bit is internally generated by the transmitting CAN + * controller only the CANFD_BRS bit is relevant for real CAN controllers when + * building a CAN FD frame for transmission. Setting the CANFD_ESI bit can make + * sense for virtual CAN interfaces to test applications with echoed frames. + * + * The struct can_frame and struct canfd_frame intentionally share the same + * layout to be able to write CAN frame content into a CAN FD frame structure. + * When this is done the former differentiation via CAN_MTU / CANFD_MTU gets + * lost. CANFD_FDF allows programmers to mark CAN FD frames in the case of + * using struct canfd_frame for mixed CAN / CAN FD content (dual use). + * Since the introduction of CAN XL the CANFD_FDF flag is set in all CAN FD + * frame structures provided by the CAN subsystem of the Linux kernel. + */ +#define CANFD_BRS 0x01 /* bit rate switch (second bitrate for payload data) */ +#define CANFD_ESI 0x02 /* error state indicator of the transmitting node */ +#define CANFD_FDF 0x04 /* mark CAN FD for dual use of struct canfd_frame */ + +/** + * struct canfd_frame - CAN flexible data rate frame structure + * @can_id: CAN ID of the frame and CAN_*_FLAG flags, see canid_t definition + * @len: frame payload length in byte (0 .. CANFD_MAX_DLEN) + * @flags: additional flags for CAN FD + * @__res0: reserved / padding + * @__res1: reserved / padding + * @data: CAN FD frame payload (up to CANFD_MAX_DLEN byte) + */ +struct canfd_frame { + canid_t can_id; /* 32 bit CAN_ID + EFF/RTR/ERR flags */ + __u8 len; /* frame payload length in byte */ + __u8 flags; /* additional flags for CAN FD */ + __u8 __res0; /* reserved / padding */ + __u8 __res1; /* reserved / padding */ + __u8 data[CANFD_MAX_DLEN] __attribute__((aligned(8))); +}; + +/* + * defined bits for canxl_frame.flags + * + * The canxl_frame.flags element contains two bits CANXL_XLF and CANXL_SEC + * and shares the relative position of the struct can[fd]_frame.len element. + * The CANXL_XLF bit ALWAYS needs to be set to indicate a valid CAN XL frame. + * As a side effect setting this bit intentionally breaks the length checks + * for Classical CAN and CAN FD frames. + * + * Undefined bits in canxl_frame.flags are reserved and shall be set to zero. + */ +#define CANXL_XLF 0x80 /* mandatory CAN XL frame flag (must always be set!) */ +#define CANXL_SEC 0x01 /* Simple Extended Content (security/segmentation) */ + +/** + * struct canxl_frame - CAN with e'X'tended frame 'L'ength frame structure + * @prio: 11 bit arbitration priority with zero'ed CAN_*_FLAG flags + * @flags: additional flags for CAN XL + * @sdt: SDU (service data unit) type + * @len: frame payload length in byte (CANXL_MIN_DLEN .. CANXL_MAX_DLEN) + * @af: acceptance field + * @data: CAN XL frame payload (CANXL_MIN_DLEN .. CANXL_MAX_DLEN byte) + * + * @prio shares the same position as @can_id from struct can[fd]_frame. + */ +struct canxl_frame { + canid_t prio; /* 11 bit priority for arbitration (canid_t) */ + __u8 flags; /* additional flags for CAN XL */ + __u8 sdt; /* SDU (service data unit) type */ + __u16 len; /* frame payload length in byte */ + __u32 af; /* acceptance field */ + __u8 data[CANXL_MAX_DLEN]; +}; + +#define CAN_MTU (sizeof(struct can_frame)) +#define CANFD_MTU (sizeof(struct canfd_frame)) +#define CANXL_MTU (sizeof(struct canxl_frame)) +#define CANXL_HDR_SIZE (offsetof(struct canxl_frame, data)) +#define CANXL_MIN_MTU (CANXL_HDR_SIZE + 64) +#define CANXL_MAX_MTU CANXL_MTU + +/* particular protocols of the protocol family PF_CAN */ +#define CAN_RAW 1 /* RAW sockets */ +#define CAN_BCM 2 /* Broadcast Manager */ +#define CAN_TP16 3 /* VAG Transport Protocol v1.6 */ +#define CAN_TP20 4 /* VAG Transport Protocol v2.0 */ +#define CAN_MCNET 5 /* Bosch MCNet */ +#define CAN_ISOTP 6 /* ISO 15765-2 Transport Protocol */ +#define CAN_J1939 7 /* SAE J1939 */ +#define CAN_NPROTO 8 + +#define SOL_CAN_BASE 100 + +/* + * This typedef was introduced in Linux v3.1-rc2 + * (commit 6602a4b net: Make userland include of netlink.h more sane) + * in <linux/socket.h>. It must be duplicated here to make the CAN + * headers self-contained. + */ +typedef unsigned short __kernel_sa_family_t; + +/** + * struct sockaddr_can - the sockaddr structure for CAN sockets + * @can_family: address family number AF_CAN. + * @can_ifindex: CAN network interface index. + * @can_addr: protocol specific address information + */ +struct sockaddr_can { + __kernel_sa_family_t can_family; + int can_ifindex; + union { + /* transport protocol class address information (e.g. ISOTP) */ + struct { canid_t rx_id, tx_id; } tp; + + /* J1939 address information */ + struct { + /* 8 byte name when using dynamic addressing */ + __u64 name; + + /* pgn: + * 8 bit: PS in PDU2 case, else 0 + * 8 bit: PF + * 1 bit: DP + * 1 bit: reserved + */ + __u32 pgn; + + /* 1 byte address */ + __u8 addr; + } j1939; + + /* reserved for future CAN protocols address information */ + } can_addr; +}; + +/** + * struct can_filter - CAN ID based filter in can_register(). + * @can_id: relevant bits of CAN ID which are not masked out. + * @can_mask: CAN mask (see description) + * + * Description: + * A filter matches, when + * + * <received_can_id> & mask == can_id & mask + * + * The filter can be inverted (CAN_INV_FILTER bit set in can_id) or it can + * filter for error message frames (CAN_ERR_FLAG bit set in mask). + */ +struct can_filter { + canid_t can_id; + canid_t can_mask; +}; + +#define CAN_INV_FILTER 0x20000000U /* to be set in can_filter.can_id */ +#define CAN_RAW_FILTER_MAX 512 /* maximum number of can_filter set via setsockopt() */ + +#endif /* !_UAPI_CAN_H */ diff --git a/include/linux/can/Makefile.am b/include/linux/can/Makefile.am new file mode 100644 index 0000000..2d02887 --- /dev/null +++ b/include/linux/can/Makefile.am @@ -0,0 +1 @@ +noinst_HEADERS = netlink.h diff --git a/include/linux/can/netlink.h b/include/linux/can/netlink.h new file mode 100644 index 0000000..02ec32d --- /dev/null +++ b/include/linux/can/netlink.h @@ -0,0 +1,185 @@ +/* SPDX-License-Identifier: GPL-2.0-only WITH Linux-syscall-note */ +/* + * linux/can/netlink.h + * + * Definitions for the CAN netlink interface + * + * Copyright (c) 2009 Wolfgang Grandegger <wg@grandegger.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the version 2 of the GNU General Public License + * as published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef _UAPI_CAN_NETLINK_H +#define _UAPI_CAN_NETLINK_H + +#include <linux/types.h> + +/* + * CAN bit-timing parameters + * + * For further information, please read chapter "8 BIT TIMING + * REQUIREMENTS" of the "Bosch CAN Specification version 2.0" + * at http://www.semiconductors.bosch.de/pdf/can2spec.pdf. + */ +struct can_bittiming { + __u32 bitrate; /* Bit-rate in bits/second */ + __u32 sample_point; /* Sample point in one-tenth of a percent */ + __u32 tq; /* Time quanta (TQ) in nanoseconds */ + __u32 prop_seg; /* Propagation segment in TQs */ + __u32 phase_seg1; /* Phase buffer segment 1 in TQs */ + __u32 phase_seg2; /* Phase buffer segment 2 in TQs */ + __u32 sjw; /* Synchronisation jump width in TQs */ + __u32 brp; /* Bit-rate prescaler */ +}; + +/* + * CAN hardware-dependent bit-timing constant + * + * Used for calculating and checking bit-timing parameters + */ +struct can_bittiming_const { + char name[16]; /* Name of the CAN controller hardware */ + __u32 tseg1_min; /* Time segment 1 = prop_seg + phase_seg1 */ + __u32 tseg1_max; + __u32 tseg2_min; /* Time segment 2 = phase_seg2 */ + __u32 tseg2_max; + __u32 sjw_max; /* Synchronisation jump width */ + __u32 brp_min; /* Bit-rate prescaler */ + __u32 brp_max; + __u32 brp_inc; +}; + +/* + * CAN clock parameters + */ +struct can_clock { + __u32 freq; /* CAN system clock frequency in Hz */ +}; + +/* + * CAN operational and error states + */ +enum can_state { + CAN_STATE_ERROR_ACTIVE = 0, /* RX/TX error count < 96 */ + CAN_STATE_ERROR_WARNING, /* RX/TX error count < 128 */ + CAN_STATE_ERROR_PASSIVE, /* RX/TX error count < 256 */ + CAN_STATE_BUS_OFF, /* RX/TX error count >= 256 */ + CAN_STATE_STOPPED, /* Device is stopped */ + CAN_STATE_SLEEPING, /* Device is sleeping */ + CAN_STATE_MAX +}; + +/* + * CAN bus error counters + */ +struct can_berr_counter { + __u16 txerr; + __u16 rxerr; +}; + +/* + * CAN controller mode + */ +struct can_ctrlmode { + __u32 mask; + __u32 flags; +}; + +#define CAN_CTRLMODE_LOOPBACK 0x01 /* Loopback mode */ +#define CAN_CTRLMODE_LISTENONLY 0x02 /* Listen-only mode */ +#define CAN_CTRLMODE_3_SAMPLES 0x04 /* Triple sampling mode */ +#define CAN_CTRLMODE_ONE_SHOT 0x08 /* One-Shot mode */ +#define CAN_CTRLMODE_BERR_REPORTING 0x10 /* Bus-error reporting */ +#define CAN_CTRLMODE_FD 0x20 /* CAN FD mode */ +#define CAN_CTRLMODE_PRESUME_ACK 0x40 /* Ignore missing CAN ACKs */ +#define CAN_CTRLMODE_FD_NON_ISO 0x80 /* CAN FD in non-ISO mode */ +#define CAN_CTRLMODE_CC_LEN8_DLC 0x100 /* Classic CAN DLC option */ +#define CAN_CTRLMODE_TDC_AUTO 0x200 /* CAN transiver automatically calculates TDCV */ +#define CAN_CTRLMODE_TDC_MANUAL 0x400 /* TDCV is manually set up by user */ + +/* + * CAN device statistics + */ +struct can_device_stats { + __u32 bus_error; /* Bus errors */ + __u32 error_warning; /* Changes to error warning state */ + __u32 error_passive; /* Changes to error passive state */ + __u32 bus_off; /* Changes to bus off state */ + __u32 arbitration_lost; /* Arbitration lost errors */ + __u32 restarts; /* CAN controller re-starts */ +}; + +/* + * CAN netlink interface + */ +enum { + IFLA_CAN_UNSPEC, + IFLA_CAN_BITTIMING, + IFLA_CAN_BITTIMING_CONST, + IFLA_CAN_CLOCK, + IFLA_CAN_STATE, + IFLA_CAN_CTRLMODE, + IFLA_CAN_RESTART_MS, + IFLA_CAN_RESTART, + IFLA_CAN_BERR_COUNTER, + IFLA_CAN_DATA_BITTIMING, + IFLA_CAN_DATA_BITTIMING_CONST, + IFLA_CAN_TERMINATION, + IFLA_CAN_TERMINATION_CONST, + IFLA_CAN_BITRATE_CONST, + IFLA_CAN_DATA_BITRATE_CONST, + IFLA_CAN_BITRATE_MAX, + IFLA_CAN_TDC, + IFLA_CAN_CTRLMODE_EXT, + + /* add new constants above here */ + __IFLA_CAN_MAX, + IFLA_CAN_MAX = __IFLA_CAN_MAX - 1 +}; + +/* + * CAN FD Transmitter Delay Compensation (TDC) + * + * Please refer to struct can_tdc_const and can_tdc in + * include/linux/can/bittiming.h for further details. + */ +enum { + IFLA_CAN_TDC_UNSPEC, + IFLA_CAN_TDC_TDCV_MIN, /* u32 */ + IFLA_CAN_TDC_TDCV_MAX, /* u32 */ + IFLA_CAN_TDC_TDCO_MIN, /* u32 */ + IFLA_CAN_TDC_TDCO_MAX, /* u32 */ + IFLA_CAN_TDC_TDCF_MIN, /* u32 */ + IFLA_CAN_TDC_TDCF_MAX, /* u32 */ + IFLA_CAN_TDC_TDCV, /* u32 */ + IFLA_CAN_TDC_TDCO, /* u32 */ + IFLA_CAN_TDC_TDCF, /* u32 */ + + /* add new constants above here */ + __IFLA_CAN_TDC, + IFLA_CAN_TDC_MAX = __IFLA_CAN_TDC - 1 +}; + +/* + * IFLA_CAN_CTRLMODE_EXT nest: controller mode extended parameters + */ +enum { + IFLA_CAN_CTRLMODE_UNSPEC, + IFLA_CAN_CTRLMODE_SUPPORTED, /* u32 */ + + /* add new constants above here */ + __IFLA_CAN_CTRLMODE, + IFLA_CAN_CTRLMODE_MAX = __IFLA_CAN_CTRLMODE - 1 +}; + +/* u16 termination range: 1..65535 Ohms */ +#define CAN_TERMINATION_DISABLED 0 + +#endif /* !_UAPI_CAN_NETLINK_H */ @@ -33,7 +33,7 @@ * mnl_attr_get_type - get type of netlink attribute * \param attr pointer to netlink attribute * - * This function returns the attribute type. + * \return the attribute type */ EXPORT_SYMBOL uint16_t mnl_attr_get_type(const struct nlattr *attr) { @@ -44,8 +44,11 @@ EXPORT_SYMBOL uint16_t mnl_attr_get_type(const struct nlattr *attr) * mnl_attr_get_len - get length of netlink attribute * \param attr pointer to netlink attribute * - * This function returns the attribute length that is the attribute header - * plus the attribute payload. + * \return the attribute length + * + * The attribute length is the length of the attribute header plus the + * attribute payload. + * */ EXPORT_SYMBOL uint16_t mnl_attr_get_len(const struct nlattr *attr) { @@ -56,7 +59,7 @@ EXPORT_SYMBOL uint16_t mnl_attr_get_len(const struct nlattr *attr) * mnl_attr_get_payload_len - get the attribute payload-value length * \param attr pointer to netlink attribute * - * This function returns the attribute payload-value length. + * \return the attribute payload-value length */ EXPORT_SYMBOL uint16_t mnl_attr_get_payload_len(const struct nlattr *attr) { @@ -67,7 +70,7 @@ EXPORT_SYMBOL uint16_t mnl_attr_get_payload_len(const struct nlattr *attr) * mnl_attr_get_payload - get pointer to the attribute payload * \param attr pointer to netlink attribute * - * This function return a pointer to the attribute payload. + * \return pointer to the attribute payload */ EXPORT_SYMBOL void *mnl_attr_get_payload(const struct nlattr *attr) { @@ -85,10 +88,12 @@ EXPORT_SYMBOL void *mnl_attr_get_payload(const struct nlattr *attr) * truncated. * * This function does not set errno in case of error since it is intended - * for iterations. Thus, it returns true on success and false on error. + * for iterations. * * The len parameter may be negative in the case of malformed messages during * attribute iteration, that is why we use a signed integer. + * + * \return true if there is room for the attribute, false otherwise */ EXPORT_SYMBOL bool mnl_attr_ok(const struct nlattr *attr, int len) { @@ -101,9 +106,11 @@ EXPORT_SYMBOL bool mnl_attr_ok(const struct nlattr *attr, int len) * mnl_attr_next - get the next attribute in the payload of a netlink message * \param attr pointer to the current attribute * - * This function returns a pointer to the next attribute after the one passed - * as parameter. You have to use mnl_attr_ok() to ensure that the next - * attribute is valid. + * \return a pointer to the next attribute after the one passed in + * + * You have to use mnl_attr_ok() on the returned attribute to ensure that the + * next attribute is valid. + * */ EXPORT_SYMBOL struct nlattr *mnl_attr_next(const struct nlattr *attr) { @@ -115,14 +122,18 @@ EXPORT_SYMBOL struct nlattr *mnl_attr_next(const struct nlattr *attr) * \param attr pointer to attribute to be checked * \param max maximum attribute type * - * This function allows to check if the attribute type is higher than the - * maximum supported type. If the attribute type is invalid, this function - * returns -1 and errno is explicitly set. On success, this function returns 1. + * This function allows one to check if the attribute type is higher than the + * maximum supported type. * * Strict attribute checking in user-space is not a good idea since you may * run an old application with a newer kernel that supports new attributes. * This leads to backward compatibility breakages in user-space. Better check * if you support an attribute, if not, skip it. + * + * On an error, errno is explicitly set. + * + * \return 1 if the attribute is valid, -1 otherwise + * */ EXPORT_SYMBOL int mnl_attr_type_valid(const struct nlattr *attr, uint16_t max) { @@ -201,8 +212,11 @@ static const size_t mnl_attr_data_type_len[MNL_TYPE_MAX] = { * \param type data type (see enum mnl_attr_data_type) * * The validation is based on the data type. Specifically, it checks that - * integers (u8, u16, u32 and u64) have enough room for them. This function - * returns -1 in case of error, and errno is explicitly set. + * integers (u8, u16, u32 and u64) have enough room for them. + * + * On an error, errno is explicitly set. + * + * \return 0 on success, -1 on error */ EXPORT_SYMBOL int mnl_attr_validate(const struct nlattr *attr, enum mnl_attr_data_type type) { @@ -222,9 +236,13 @@ EXPORT_SYMBOL int mnl_attr_validate(const struct nlattr *attr, enum mnl_attr_dat * \param type attribute type (see enum mnl_attr_data_type) * \param exp_len expected attribute data size * - * This function allows to perform a more accurate validation for attributes - * whose size is variable. If the size of the attribute is not what we expect, - * this functions returns -1 and errno is explicitly set. + * This function allows one to perform a more accurate validation for attributes + * whose size is variable. + * + * On an error, errno is explicitly set. + * + * \return 0 if the attribute is valid and fits within the expected length, -1 + * otherwise */ EXPORT_SYMBOL int mnl_attr_validate2(const struct nlattr *attr, enum mnl_attr_data_type type, @@ -244,13 +262,13 @@ EXPORT_SYMBOL int mnl_attr_validate2(const struct nlattr *attr, * \param cb callback function that is called for each attribute * \param data pointer to data that is passed to the callback function * - * This function allows to iterate over the sequence of attributes that compose - * the Netlink message. You can then put the attribute in an array as it + * This function allows you to iterate over the sequence of attributes that + * compose the Netlink message. You can then put the attribute in an array as it * usually happens at this stage or you can use any other data structure (such * as lists or trees). * - * This function propagates the return value of the callback, which can be - * MNL_CB_ERROR, MNL_CB_OK or MNL_CB_STOP. + * \return propagated value from callback, one of MNL_CB_ERROR, MNL_CB_STOP + * or MNL_CB_OK */ EXPORT_SYMBOL int mnl_attr_parse(const struct nlmsghdr *nlh, unsigned int offset, mnl_attr_cb_t cb, @@ -271,13 +289,13 @@ EXPORT_SYMBOL int mnl_attr_parse(const struct nlmsghdr *nlh, * \param cb callback function that is called for each attribute in the nest * \param data pointer to data passed to the callback function * - * This function allows to iterate over the sequence of attributes that compose - * the Netlink message. You can then put the attribute in an array as it + * This function allows you to iterate over the sequence of attributes that + * compose the Netlink message. You can then put the attribute in an array as it * usually happens at this stage or you can use any other data structure (such * as lists or trees). * - * This function propagates the return value of the callback, which can be - * MNL_CB_ERROR, MNL_CB_OK or MNL_CB_STOP. +* \return propagated value from callback, one of MNL_CB_ERROR, MNL_CB_STOP +* or MNL_CB_OK */ EXPORT_SYMBOL int mnl_attr_parse_nested(const struct nlattr *nested, mnl_attr_cb_t cb, void *data) @@ -307,8 +325,8 @@ EXPORT_SYMBOL int mnl_attr_parse_nested(const struct nlattr *nested, * located at some payload offset. You can then put the attributes in one array * as usual, or you can use any other data structure (such as lists or trees). * - * This function propagates the return value of the callback, which can be - * MNL_CB_ERROR, MNL_CB_OK or MNL_CB_STOP. + * \return propagated value from callback, one of MNL_CB_ERROR, MNL_CB_STOP + * or MNL_CB_OK */ EXPORT_SYMBOL int mnl_attr_parse_payload(const void *payload, size_t payload_len, @@ -324,10 +342,10 @@ EXPORT_SYMBOL int mnl_attr_parse_payload(const void *payload, } /** - * mnl_attr_get_u8 - returns 8-bit unsigned integer attribute payload + * mnl_attr_get_u8 - get 8-bit unsigned integer attribute payload * \param attr pointer to netlink attribute * - * This function returns the 8-bit value of the attribute payload. + * \return 8-bit value of the attribute payload */ EXPORT_SYMBOL uint8_t mnl_attr_get_u8(const struct nlattr *attr) { @@ -335,10 +353,10 @@ EXPORT_SYMBOL uint8_t mnl_attr_get_u8(const struct nlattr *attr) } /** - * mnl_attr_get_u16 - returns 16-bit unsigned integer attribute payload + * mnl_attr_get_u16 - get 16-bit unsigned integer attribute payload * \param attr pointer to netlink attribute * - * This function returns the 16-bit value of the attribute payload. + * \return 16-bit value of the attribute payload */ EXPORT_SYMBOL uint16_t mnl_attr_get_u16(const struct nlattr *attr) { @@ -346,10 +364,10 @@ EXPORT_SYMBOL uint16_t mnl_attr_get_u16(const struct nlattr *attr) } /** - * mnl_attr_get_u32 - returns 32-bit unsigned integer attribute payload + * mnl_attr_get_u32 - get 32-bit unsigned integer attribute payload * \param attr pointer to netlink attribute * - * This function returns the 32-bit value of the attribute payload. + * \return 32-bit value of the attribute payload */ EXPORT_SYMBOL uint32_t mnl_attr_get_u32(const struct nlattr *attr) { @@ -357,12 +375,12 @@ EXPORT_SYMBOL uint32_t mnl_attr_get_u32(const struct nlattr *attr) } /** - * mnl_attr_get_u64 - returns 64-bit unsigned integer attribute. + * mnl_attr_get_u64 - get 64-bit unsigned integer attribute * \param attr pointer to netlink attribute * - * This function returns the 64-bit value of the attribute payload. This - * function is align-safe, since accessing 64-bit Netlink attributes is a - * common source of alignment issues. + * This function reads the 64-bit nlattr payload in an alignment safe manner. + * + * \return 64-bit value of the attribute payload */ EXPORT_SYMBOL uint64_t mnl_attr_get_u64(const struct nlattr *attr) { @@ -372,10 +390,10 @@ EXPORT_SYMBOL uint64_t mnl_attr_get_u64(const struct nlattr *attr) } /** - * mnl_attr_get_str - returns pointer to string attribute. + * mnl_attr_get_str - get pointer to string attribute * \param attr pointer to netlink attribute * - * This function returns the payload of string attribute value. + * \return string pointer of the attribute payload */ EXPORT_SYMBOL const char *mnl_attr_get_str(const struct nlattr *attr) { @@ -508,8 +526,9 @@ EXPORT_SYMBOL void mnl_attr_put_strz(struct nlmsghdr *nlh, uint16_t type, * \param type netlink attribute type * * This function adds the attribute header that identifies the beginning of - * an attribute nest. This function always returns a valid pointer to the - * beginning of the nest. + * an attribute nest. + * + * \return valid pointer to the beginning of the nest */ EXPORT_SYMBOL struct nlattr *mnl_attr_nest_start(struct nlmsghdr *nlh, uint16_t type) @@ -534,8 +553,9 @@ EXPORT_SYMBOL struct nlattr *mnl_attr_nest_start(struct nlmsghdr *nlh, * This function first checks that the data can be added to the message * (fits into the buffer) and then updates the length field of the Netlink * message (nlmsg_len) by adding the size (header + payload) of the new - * attribute. The function returns true if the attribute could be added - * to the message, otherwise false is returned. + * attribute. + * + * \return true if the attribute could be added, false otherwise */ EXPORT_SYMBOL bool mnl_attr_put_check(struct nlmsghdr *nlh, size_t buflen, uint16_t type, size_t len, @@ -557,8 +577,9 @@ EXPORT_SYMBOL bool mnl_attr_put_check(struct nlmsghdr *nlh, size_t buflen, * This function first checks that the data can be added to the message * (fits into the buffer) and then updates the length field of the Netlink * message (nlmsg_len) by adding the size (header + payload) of the new - * attribute. The function returns true if the attribute could be added - * to the message, otherwise false is returned. + * attribute. + * + * \return true if the attribute could be added, false otherwise */ EXPORT_SYMBOL bool mnl_attr_put_u8_check(struct nlmsghdr *nlh, size_t buflen, uint16_t type, uint8_t data) @@ -576,10 +597,9 @@ EXPORT_SYMBOL bool mnl_attr_put_u8_check(struct nlmsghdr *nlh, size_t buflen, * This function first checks that the data can be added to the message * (fits into the buffer) and then updates the length field of the Netlink * message (nlmsg_len) by adding the size (header + payload) of the new - * attribute. The function returns true if the attribute could be added - * to the message, otherwise false is returned. - * This function updates the length field of the Netlink message (nlmsg_len) - * by adding the size (header + payload) of the new attribute. + * attribute. + * + * \return true if the attribute could be added, false otherwise */ EXPORT_SYMBOL bool mnl_attr_put_u16_check(struct nlmsghdr *nlh, size_t buflen, uint16_t type, uint16_t data) @@ -597,10 +617,9 @@ EXPORT_SYMBOL bool mnl_attr_put_u16_check(struct nlmsghdr *nlh, size_t buflen, * This function first checks that the data can be added to the message * (fits into the buffer) and then updates the length field of the Netlink * message (nlmsg_len) by adding the size (header + payload) of the new - * attribute. The function returns true if the attribute could be added - * to the message, otherwise false is returned. - * This function updates the length field of the Netlink message (nlmsg_len) - * by adding the size (header + payload) of the new attribute. + * attribute. + * + * \return true if the attribute could be added, false otherwise */ EXPORT_SYMBOL bool mnl_attr_put_u32_check(struct nlmsghdr *nlh, size_t buflen, uint16_t type, uint32_t data) @@ -618,10 +637,9 @@ EXPORT_SYMBOL bool mnl_attr_put_u32_check(struct nlmsghdr *nlh, size_t buflen, * This function first checks that the data can be added to the message * (fits into the buffer) and then updates the length field of the Netlink * message (nlmsg_len) by adding the size (header + payload) of the new - * attribute. The function returns true if the attribute could be added - * to the message, otherwise false is returned. - * This function updates the length field of the Netlink message (nlmsg_len) - * by adding the size (header + payload) of the new attribute. + * attribute. + * + * \return true if the attribute could be added, false otherwise */ EXPORT_SYMBOL bool mnl_attr_put_u64_check(struct nlmsghdr *nlh, size_t buflen, uint16_t type, uint64_t data) @@ -639,10 +657,9 @@ EXPORT_SYMBOL bool mnl_attr_put_u64_check(struct nlmsghdr *nlh, size_t buflen, * This function first checks that the data can be added to the message * (fits into the buffer) and then updates the length field of the Netlink * message (nlmsg_len) by adding the size (header + payload) of the new - * attribute. The function returns true if the attribute could be added - * to the message, otherwise false is returned. - * This function updates the length field of the Netlink message (nlmsg_len) - * by adding the size (header + payload) of the new attribute. + * attribute. + * + * \return true if the attribute could be added, false otherwise */ EXPORT_SYMBOL bool mnl_attr_put_str_check(struct nlmsghdr *nlh, size_t buflen, uint16_t type, const char *data) @@ -663,8 +680,9 @@ EXPORT_SYMBOL bool mnl_attr_put_str_check(struct nlmsghdr *nlh, size_t buflen, * This function first checks that the data can be added to the message * (fits into the buffer) and then updates the length field of the Netlink * message (nlmsg_len) by adding the size (header + payload) of the new - * attribute. The function returns true if the attribute could be added - * to the message, otherwise false is returned. + * attribute. + * + * \return true if the attribute could be added, false otherwise */ EXPORT_SYMBOL bool mnl_attr_put_strz_check(struct nlmsghdr *nlh, size_t buflen, uint16_t type, const char *data) @@ -679,8 +697,10 @@ EXPORT_SYMBOL bool mnl_attr_put_strz_check(struct nlmsghdr *nlh, size_t buflen, * \param type netlink attribute type * * This function adds the attribute header that identifies the beginning of - * an attribute nest. If the nested attribute cannot be added then NULL, - * otherwise valid pointer to the beginning of the nest is returned. + * an attribute nest. + * + * \return NULL if the attribute cannot be added, otherwise a pointer to the + * beginning of the nest */ EXPORT_SYMBOL struct nlattr *mnl_attr_nest_start_check(struct nlmsghdr *nlh, size_t buflen, diff --git a/src/nlmsg.c b/src/nlmsg.c index d398e63..30a7e63 100644 --- a/src/nlmsg.c +++ b/src/nlmsg.c @@ -12,6 +12,7 @@ #include <ctype.h> #include <errno.h> #include <string.h> +#include <unistd.h> #include <libmnl/libmnl.h> #include "internal.h" @@ -151,9 +152,14 @@ EXPORT_SYMBOL void *mnl_nlmsg_get_payload_offset(const struct nlmsghdr *nlh, */ EXPORT_SYMBOL bool mnl_nlmsg_ok(const struct nlmsghdr *nlh, int len) { - return len >= (int)sizeof(struct nlmsghdr) && + size_t ulen = len; + + if (len < 0) + return false; + + return ulen >= sizeof(struct nlmsghdr) && nlh->nlmsg_len >= sizeof(struct nlmsghdr) && - (int)nlh->nlmsg_len <= len; + nlh->nlmsg_len <= ulen; } /** @@ -244,11 +250,57 @@ static void mnl_nlmsg_fprintf_header(FILE *fd, const struct nlmsghdr *nlh) fprintf(fd, "----------------\t------------------\n"); } +static void mnl_fprintf_attr_color(FILE *fd, const struct nlattr *attr) +{ + fprintf(fd, "|%c[%d;%dm" + "%.5u" + "%c[%dm" + "|" + "%c[%d;%dm" + "%c%c" + "%c[%dm" + "|" + "%c[%d;%dm" + "%.5u" + "%c[%dm|\t", + 27, 1, 31, + attr->nla_len, + 27, 0, + 27, 1, 32, + attr->nla_type & NLA_F_NESTED ? 'N' : '-', + attr->nla_type & NLA_F_NET_BYTEORDER ? 'B' : '-', + 27, 0, + 27, 1, 34, + attr->nla_type & NLA_TYPE_MASK, + 27, 0); +} + +static void mnl_fprintf_attr_raw(FILE *fd, const struct nlattr *attr) +{ + fprintf(fd, "|" + "%.5u" + "|" + "%c%c" + "|" + "%.5u" + "|\t", + attr->nla_len, + attr->nla_type & NLA_F_NESTED ? 'N' : '-', + attr->nla_type & NLA_F_NET_BYTEORDER ? 'B' : '-', + attr->nla_type & NLA_TYPE_MASK); +} + static void mnl_nlmsg_fprintf_payload(FILE *fd, const struct nlmsghdr *nlh, size_t extra_header_size) { - int rem = 0; + int colorize = 0; unsigned int i; + int rem = 0; + int fdnum; + + fdnum = fileno(fd); + if (fdnum != -1) + colorize = isatty(fdnum); for (i=sizeof(struct nlmsghdr); i<nlh->nlmsg_len; i+=4) { char *b = (char *) nlh; @@ -269,28 +321,11 @@ static void mnl_nlmsg_fprintf_payload(FILE *fd, const struct nlmsghdr *nlh, fprintf(fd, "| extra header |\n"); /* this seems like an attribute header. */ } else if (rem == 0 && (attr->nla_type & NLA_TYPE_MASK) != 0) { - fprintf(fd, "|%c[%d;%dm" - "%.5u" - "%c[%dm" - "|" - "%c[%d;%dm" - "%c%c" - "%c[%dm" - "|" - "%c[%d;%dm" - "%.5u" - "%c[%dm|\t", - 27, 1, 31, - attr->nla_len, - 27, 0, - 27, 1, 32, - attr->nla_type & NLA_F_NESTED ? 'N' : '-', - attr->nla_type & - NLA_F_NET_BYTEORDER ? 'B' : '-', - 27, 0, - 27, 1, 34, - attr->nla_type & NLA_TYPE_MASK, - 27, 0); + if (colorize) { + mnl_fprintf_attr_color(fd, attr); + } else { + mnl_fprintf_attr_raw(fd, attr); + } fprintf(fd, "|len |flags| type|\n"); if (!(attr->nla_type & NLA_F_NESTED)) { @@ -381,15 +416,16 @@ EXPORT_SYMBOL void mnl_nlmsg_fprintf(FILE *fd, const void *data, size_t datalen, * datagram. These helpers do not perform strict memory boundary checkings. * * The following figure represents a Netlink message batch: - * - * |<-------------- MNL_SOCKET_BUFFER_SIZE ------------->| - * |<-------------------- batch ------------------>| | - * |-----------|-----------|-----------|-----------|-----------| - * |<- nlmsg ->|<- nlmsg ->|<- nlmsg ->|<- nlmsg ->|<- nlmsg ->| - * |-----------|-----------|-----------|-----------|-----------| - * ^ ^ - * | | - * message N message N+1 + *\verbatim + |<-------------- MNL_SOCKET_BUFFER_SIZE ------------->| + |<-------------------- batch ------------------>| | + |-----------|-----------|-----------|-----------|-----------| + |<- nlmsg ->|<- nlmsg ->|<- nlmsg ->|<- nlmsg ->|<- nlmsg ->| + |-----------|-----------|-----------|-----------|-----------| + ^ ^ + | | + message N message N+1 +\endverbatim * * To start the batch, you have to call mnl_nlmsg_batch_start() and you can * use mnl_nlmsg_batch_stop() to release it. @@ -487,9 +523,9 @@ EXPORT_SYMBOL bool mnl_nlmsg_batch_next(struct mnl_nlmsg_batch *b) * mnl_nlmsg_batch_reset - reset the batch * \param b pointer to batch * - * This function allows to reset a batch, so you can reuse it to create a - * new one. This function moves the last message which does not fit the - * batch to the head of the buffer, if any. + * This function allows you to reset a batch, so you can reuse it to create a + * new one. This function moves the last message which does not fit the batch to + * the head of the buffer, if any. */ EXPORT_SYMBOL void mnl_nlmsg_batch_reset(struct mnl_nlmsg_batch *b) { diff --git a/src/socket.c b/src/socket.c index d7c67a8..85b6bcc 100644 --- a/src/socket.c +++ b/src/socket.c @@ -59,7 +59,7 @@ * * \section scm Git Tree * The current development version of libmnl can be accessed at: - * http://git.netfilter.org/cgi-bin/gitweb.cgi?p=libmnl.git;a=summary + * https://git.netfilter.org/libmnl/ * * \section using Using libmnl * You can access several example files under examples/ in the libmnl source @@ -135,7 +135,7 @@ EXPORT_SYMBOL struct mnl_socket *mnl_socket_open(int bus) * \param bus the netlink socket bus ID (see NETLINK_* constants) * \param flags the netlink socket flags (see SOCK_* constants in socket(2)) * - * This is similar to mnl_socket_open(), but allows to set flags like + * This is similar to mnl_socket_open(), but allows one to set flags like * SOCK_CLOEXEC at socket creation time (useful for multi-threaded programs * performing exec calls). * |