summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.gitignore3
-rw-r--r--Makefile.am4
-rw-r--r--configure.ac45
-rw-r--r--doxygen.cfg.in184
-rw-r--r--doxygen/.gitignore4
-rw-r--r--doxygen/Makefile.am25
-rw-r--r--doxygen/doxygen.cfg.in23
-rw-r--r--doxygen/finalize_manpages.sh40
-rw-r--r--examples/genl/.gitignore1
-rw-r--r--examples/kobject/.gitignore1
-rw-r--r--examples/netfilter/.gitignore3
-rw-r--r--examples/netfilter/nfct-dump.c2
-rw-r--r--examples/rtnl/.gitignore4
-rw-r--r--examples/rtnl/Makefile.am4
-rw-r--r--examples/rtnl/rtnl-addr-dump.c4
-rw-r--r--examples/rtnl/rtnl-link-can.c452
-rw-r--r--examples/rtnl/rtnl-link-dump.c4
-rw-r--r--examples/rtnl/rtnl-link-dump2.c4
-rw-r--r--examples/rtnl/rtnl-link-dump3.c4
-rw-r--r--examples/rtnl/rtnl-neigh-dump.c12
-rw-r--r--examples/rtnl/rtnl-route-dump.c4
-rw-r--r--include/libmnl/libmnl.h1
-rw-r--r--include/linux/Makefile.am4
-rw-r--r--include/linux/can.h298
-rw-r--r--include/linux/can/Makefile.am1
-rw-r--r--include/linux/can/netlink.h185
-rw-r--r--src/attr.c150
-rw-r--r--src/nlmsg.c110
-rw-r--r--src/socket.c4
29 files changed, 1267 insertions, 313 deletions
diff --git a/.gitignore b/.gitignore
index 9a7d86c..b6b8d60 100644
--- a/.gitignore
+++ b/.gitignore
@@ -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 */
diff --git a/src/attr.c b/src/attr.c
index 838eab0..bc39df4 100644
--- a/src/attr.c
+++ b/src/attr.c
@@ -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).
*