summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--doc/Doxyfile.in13
-rw-r--r--doc/libnl.css888
-rw-r--r--doc/src/core.c812
-rw-r--r--doc/src/genl.c10
-rw-r--r--doc/src/nf.c10
-rw-r--r--doc/src/route.c10
-rw-r--r--doc/src/toc.c66
-rw-r--r--lib/doc.c487
8 files changed, 1442 insertions, 854 deletions
diff --git a/doc/Doxyfile.in b/doc/Doxyfile.in
index 190fe39..8c87c64 100644
--- a/doc/Doxyfile.in
+++ b/doc/Doxyfile.in
@@ -92,7 +92,7 @@ ABBREVIATE_BRIEF =
# Doxygen will generate a detailed section even if there is only a brief
# description.
-ALWAYS_DETAILED_SEC = YES
+ALWAYS_DETAILED_SEC = NO
# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all
# inherited members of a class in the documentation of that class as if those
@@ -583,7 +583,8 @@ WARN_LOGFILE =
INPUT = ../lib \
../src/lib \
- ../include/netlink
+ ../include/netlink \
+ src
# This tag can be used to specify the character encoding of the source files
# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is
@@ -815,7 +816,7 @@ HTML_TIMESTAMP = NO
# the style sheet file to the HTML output directory, so don't put your own
# stylesheet in the HTML output directory as well, or it will be erased!
-HTML_STYLESHEET =
+HTML_STYLESHEET = libnl.css
# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output.
# Doxygen will adjust the colors in the stylesheet and background images
@@ -1022,7 +1023,7 @@ DISABLE_INDEX = NO
# This tag can be used to set the number of enum values (range [1..20])
# that doxygen will group on one line in the generated HTML documentation.
-ENUM_VALUES_PER_LINE = 4
+ENUM_VALUES_PER_LINE = 1
# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index
# structure should be generated to display hierarchical information.
@@ -1037,7 +1038,7 @@ GENERATE_TREEVIEW = NO
# By enabling USE_INLINE_TREES, doxygen will generate the Groups, Directories,
# and Class Hierarchy pages using a tree view instead of an ordered list.
-USE_INLINE_TREES = NO
+USE_INLINE_TREES = YES
# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be
# used to set the initial width (in pixels) of the frame in which the tree
@@ -1571,7 +1572,7 @@ GRAPHICAL_HIERARCHY = YES
# in a graphical way. The dependency relations are determined by the #include
# relations between the files in the directories.
-DIRECTORY_GRAPH = NO
+DIRECTORY_GRAPH = YES
# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
# generated by dot. Possible values are png, jpg, or gif
diff --git a/doc/libnl.css b/doc/libnl.css
index 22c4843..b92bafc 100644
--- a/doc/libnl.css
+++ b/doc/libnl.css
@@ -1,473 +1,639 @@
-BODY,H1,H2,H3,H4,H5,H6,P,CENTER,TD,TH,UL,DL,DIV {
- font-family: Geneva, Arial, Helvetica, sans-serif;
+/* The standard CSS for doxygen */
+
+body, table, div, p, dl {
+ font-family: Lucida Grande, Verdana, Geneva, Arial, sans-serif;
+ font-size: 12px;
}
-BODY,TD {
- font-size: 90%;
+
+/* @group Heading Levels */
+
+h1 {
+ font-size: 180%;
}
-H1 {
- text-align: center;
- font-size: 160%;
+
+h2 {
+ font-size: 140%;
}
-H2 {
+
+h3 {
font-size: 120%;
}
-H3 {
- font-size: 100%;
+
+dt {
+ font-weight: bold;
}
-CAPTION {
- font-weight: bold
+
+div.multicol {
+ -moz-column-gap: 1em;
+ -webkit-column-gap: 1em;
+ -moz-column-count: 3;
+ -webkit-column-count: 3;
}
-DIV.qindex {
- width: 100%;
- background-color: #e8eef2;
- border: 1px solid #84b0c7;
+
+p.startli, p.startdd, p.starttd {
+ margin-top: 2px;
+}
+
+p.endli {
+ margin-bottom: 0px;
+}
+
+p.enddd {
+ margin-bottom: 4px;
+}
+
+p.endtd {
+ margin-bottom: 2px;
+}
+
+/* @end */
+
+caption {
+ font-weight: bold;
+}
+
+span.legend {
+ font-size: 70%;
+ text-align: center;
+}
+
+h3.version {
+ font-size: 90%;
+ text-align: center;
+}
+
+div.qindex, div.navtab{
+ background-color: #EBEFF6;
+ border: 1px solid #A3B4D7;
text-align: center;
margin: 2px;
padding: 2px;
- line-height: 140%;
}
-DIV.navpath {
+
+div.qindex, div.navpath {
width: 100%;
- background-color: #e8eef2;
- border: 1px solid #84b0c7;
- text-align: center;
- margin: 2px;
- padding: 2px;
line-height: 140%;
}
-DIV.navtab {
- background-color: #e8eef2;
- border: 1px solid #84b0c7;
- text-align: center;
- margin: 2px;
- margin-right: 15px;
- padding: 2px;
-}
-TD.navtab {
- font-size: 70%;
+
+div.navtab {
+ margin-right: 15px;
}
-A.qindex {
- text-decoration: none;
- font-weight: bold;
- color: #1A419D;
+
+/* @group Link Styling */
+
+a {
+ color: #3D578C;
+ font-weight: normal;
+ text-decoration: none;
}
-A.qindex:visited {
- text-decoration: none;
- font-weight: bold;
- color: #1A419D
+
+.contents a:visited {
+ color: #4665A2;
}
-A.qindex:hover {
- text-decoration: none;
- background-color: #ddddff;
+
+a:hover {
+ text-decoration: underline;
}
-A.qindexHL {
- text-decoration: none;
+
+a.qindex {
font-weight: bold;
- background-color: #6666cc;
- color: #ffffff;
- border: 1px double #9295C2;
}
-A.qindexHL:hover {
- text-decoration: none;
- background-color: #6666cc;
+
+a.qindexHL {
+ font-weight: bold;
+ background-color: #9CAFD4;
color: #ffffff;
+ border: 1px double #869DCA;
}
-A.qindexHL:visited {
- text-decoration: none;
- background-color: #6666cc;
- color: #ffffff
-}
-A.el {
- text-decoration: none;
- font-weight: bold
-}
-A.elRef {
- font-weight: bold
-}
-A.code:link {
- text-decoration: none;
- font-weight: normal;
- color: #0000FF
+
+.contents a.qindexHL:visited {
+ color: #ffffff;
}
-A.code:visited {
- text-decoration: none;
- font-weight: normal;
- color: #0000FF
+
+a.el {
+ font-weight: bold;
}
-A.codeRef:link {
- font-weight: normal;
- color: #0000FF
+
+a.elRef {
}
-A.codeRef:visited {
- font-weight: normal;
- color: #0000FF
+
+a.code {
+ color: #4665A2;
}
-A:hover {
- text-decoration: none;
- background-color: #f2f2ff
+
+a.codeRef {
+ color: #4665A2;
}
-DL.el {
- margin-left: -1cm
+
+/* @end */
+
+dl.el {
+ margin-left: -1cm;
}
+
.fragment {
- font-family: monospace, fixed;
- font-size: 95%;
+ font-family: monospace, fixed;
+ font-size: 105%;
}
-PRE.fragment {
- border: 1px solid #CCCCCC;
- background-color: #f5f5f5;
- margin-top: 4px;
- margin-bottom: 4px;
- margin-left: 2px;
- margin-right: 8px;
- padding-left: 6px;
- padding-right: 6px;
- padding-top: 4px;
- padding-bottom: 4px;
+
+pre.fragment {
+ border: 1px solid #C4CFE5;
+ background-color: #FBFCFD;
+ padding: 4px 6px;
+ margin: 4px 8px 4px 2px;
+ overflow: auto;
+ word-wrap: break-word;
+ font-size: 9pt;
+ line-height: 125%;
}
-DIV.ah {
- background-color: black;
- font-weight: bold;
- color: #ffffff;
- margin-bottom: 3px;
- margin-top: 3px
+
+div.ah {
+ background-color: black;
+ font-weight: bold;
+ color: #ffffff;
+ margin-bottom: 3px;
+ margin-top: 3px;
+ padding: 0.2em;
+ border: solid thin #333;
+ border-radius: 0.5em;
+ -webkit-border-radius: .5em;
+ -moz-border-radius: .5em;
+ -webkit-box-shadow: 2px 2px 3px #999;
+ -moz-box-shadow: rgba(0, 0, 0, 0.15) 2px 2px 2px;
+ background-image: -webkit-gradient(linear, left top, left bottom, from(#eee), to(#000),color-stop(0.3, #444));
+ background-image: -moz-linear-gradient(center top, #eee 0%, #444 40%, #000);
}
-DIV.groupHeader {
- margin-left: 16px;
- margin-top: 12px;
- margin-bottom: 6px;
- font-weight: bold;
+div.groupHeader {
+ margin-left: 16px;
+ margin-top: 12px;
+ margin-bottom: 6px;
+ font-weight: bold;
}
-DIV.groupText {
- margin-left: 16px;
- font-style: italic;
- font-size: 90%
+
+div.groupText {
+ margin-left: 16px;
+ font-style: italic;
}
-BODY {
+
+body {
background: white;
color: black;
+ margin: 0;
+}
+
+div.contents {
+ margin-top: 10px;
+ margin-left: 10px;
+ margin-right: 10px;
+}
+
+div.contents p {
+ margin-left: 30px;
+}
+
+div.contents .fragment {
+ margin-left: 30px;
margin-right: 20px;
- margin-left: 20px;
}
-TD.indexkey {
- background-color: #e8eef2;
+
+td.indexkey {
+ background-color: #EBEFF6;
font-weight: bold;
- padding-right : 10px;
- padding-top : 2px;
- padding-left : 10px;
- padding-bottom : 2px;
- margin-left : 0px;
- margin-right : 0px;
- margin-top : 2px;
- margin-bottom : 2px;
- border: 1px solid #CCCCCC;
-}
-TD.indexvalue {
- background-color: #e8eef2;
- font-style: italic;
- padding-right : 10px;
- padding-top : 2px;
- padding-left : 10px;
- padding-bottom : 2px;
- margin-left : 0px;
- margin-right : 0px;
- margin-top : 2px;
- margin-bottom : 2px;
- border: 1px solid #CCCCCC;
-}
-TR.memlist {
- background-color: #f0f0f0;
-}
-P.formulaDsp {
- text-align: center;
-}
-IMG.formulaDsp {
-}
-IMG.formulaInl {
- vertical-align: middle;
-}
-SPAN.keyword { color: #008000 }
-SPAN.keywordtype { color: #604020 }
-SPAN.keywordflow { color: #e08000 }
-SPAN.comment { color: #800000 }
-SPAN.preprocessor { color: #806020 }
-SPAN.stringliteral { color: #002080 }
-SPAN.charliteral { color: #008080 }
-SPAN.vhdldigit { color: #ff00ff }
-SPAN.vhdlchar { color: #000000 }
-SPAN.vhdlkeyword { color: #700070 }
-SPAN.vhdllogic { color: #ff0000 }
-
-.mdescLeft {
- padding: 0px 8px 4px 8px;
- font-size: 80%;
- font-style: italic;
- background-color: #FAFAFA;
- border-top: 1px none #E0E0E0;
- border-right: 1px none #E0E0E0;
- border-bottom: 1px none #E0E0E0;
- border-left: 1px none #E0E0E0;
- margin: 0px;
+ border: 1px solid #C4CFE5;
+ margin: 2px 0px 2px 0;
+ padding: 2px 10px;
}
-.mdescRight {
- padding: 0px 8px 4px 8px;
- font-size: 80%;
- font-style: italic;
- background-color: #FAFAFA;
- border-top: 1px none #E0E0E0;
- border-right: 1px none #E0E0E0;
- border-bottom: 1px none #E0E0E0;
- border-left: 1px none #E0E0E0;
- margin: 0px;
+
+td.indexvalue {
+ background-color: #EBEFF6;
+ border: 1px solid #C4CFE5;
+ padding: 2px 10px;
+ margin: 2px 0px;
}
-.memItemLeft {
- padding: 1px 0px 0px 8px;
- margin: 4px;
- border-top-width: 1px;
- border-right-width: 1px;
- border-bottom-width: 1px;
- border-left-width: 1px;
- border-top-color: #E0E0E0;
- border-right-color: #E0E0E0;
- border-bottom-color: #E0E0E0;
- border-left-color: #E0E0E0;
- border-top-style: solid;
- border-right-style: none;
- border-bottom-style: none;
- border-left-style: none;
- background-color: #FAFAFA;
- font-size: 80%;
-}
-.memItemRight {
- padding: 1px 8px 0px 8px;
- margin: 4px;
- border-top-width: 1px;
- border-right-width: 1px;
- border-bottom-width: 1px;
- border-left-width: 1px;
- border-top-color: #E0E0E0;
- border-right-color: #E0E0E0;
- border-bottom-color: #E0E0E0;
- border-left-color: #E0E0E0;
- border-top-style: solid;
- border-right-style: none;
- border-bottom-style: none;
- border-left-style: none;
- background-color: #FAFAFA;
- font-size: 80%;
-}
-.memTemplItemLeft {
- padding: 1px 0px 0px 8px;
- margin: 4px;
- border-top-width: 1px;
- border-right-width: 1px;
- border-bottom-width: 1px;
- border-left-width: 1px;
- border-top-color: #E0E0E0;
- border-right-color: #E0E0E0;
- border-bottom-color: #E0E0E0;
- border-left-color: #E0E0E0;
- border-top-style: none;
- border-right-style: none;
- border-bottom-style: none;
- border-left-style: none;
- background-color: #FAFAFA;
- font-size: 80%;
-}
-.memTemplItemRight {
- padding: 1px 8px 0px 8px;
- margin: 4px;
- border-top-width: 1px;
- border-right-width: 1px;
- border-bottom-width: 1px;
- border-left-width: 1px;
- border-top-color: #E0E0E0;
- border-right-color: #E0E0E0;
- border-bottom-color: #E0E0E0;
- border-left-color: #E0E0E0;
- border-top-style: none;
- border-right-style: none;
- border-bottom-style: none;
- border-left-style: none;
- background-color: #FAFAFA;
- font-size: 80%;
+
+tr.memlist {
+ background-color: #EEF1F7;
}
-.memTemplParams {
- padding: 1px 0px 0px 8px;
- margin: 4px;
- border-top-width: 1px;
- border-right-width: 1px;
- border-bottom-width: 1px;
- border-left-width: 1px;
- border-top-color: #E0E0E0;
- border-right-color: #E0E0E0;
- border-bottom-color: #E0E0E0;
- border-left-color: #E0E0E0;
- border-top-style: solid;
- border-right-style: none;
- border-bottom-style: none;
- border-left-style: none;
- color: #606060;
- background-color: #FAFAFA;
- font-size: 80%;
-}
-.search {
+
+p.formulaDsp {
+ text-align: center;
+}
+
+img.formulaDsp {
+
+}
+
+img.formulaInl {
+ vertical-align: middle;
+}
+
+div.center {
+ text-align: center;
+ margin-top: 0px;
+ margin-bottom: 0px;
+ padding: 0px;
+}
+
+div.center img {
+ border: 0px;
+}
+
+address.footer {
+ text-align: right;
+ padding-right: 12px;
+}
+
+img.footer {
+ border: 0px;
+ vertical-align: middle;
+}
+
+/* @group Code Colorization */
+
+span.keyword {
+ color: #008000
+}
+
+span.keywordtype {
+ color: #604020
+}
+
+span.keywordflow {
+ color: #e08000
+}
+
+span.comment {
+ color: #800000
+}
+
+span.preprocessor {
+ color: #806020
+}
+
+span.stringliteral {
+ color: #002080
+}
+
+span.charliteral {
+ color: #008080
+}
+
+span.vhdldigit {
+ color: #ff00ff
+}
+
+span.vhdlchar {
+ color: #000000
+}
+
+span.vhdlkeyword {
+ color: #700070
+}
+
+span.vhdllogic {
+ color: #ff0000
+}
+
+/* @end */
+
+/*
+.search {
color: #003399;
font-weight: bold;
}
-FORM.search {
+
+form.search {
margin-bottom: 0px;
margin-top: 0px;
}
-INPUT.search {
+
+input.search {
font-size: 75%;
color: #000080;
font-weight: normal;
background-color: #e8eef2;
}
-TD.tiny {
+*/
+
+td.tiny {
font-size: 75%;
}
-a {
- color: #1A41A8;
-}
-a:visited {
- color: #2A3798;
-}
-.dirtab {
+
+.dirtab {
padding: 4px;
border-collapse: collapse;
- border: 1px solid #84b0c7;
+ border: 1px solid #A3B4D7;
}
-TH.dirtab {
- background: #e8eef2;
+
+th.dirtab {
+ background: #EBEFF6;
font-weight: bold;
}
-HR {
+
+hr {
+ height: 0px;
+ border: none;
+ border-top: 1px solid #4A6AAA;
+}
+
+hr.footer {
height: 1px;
+}
+
+/* @group Member Descriptions */
+
+table.memberdecls {
+ border-spacing: 0px;
+ padding: 0px;
+}
+
+.mdescLeft, .mdescRight,
+.memItemLeft, .memItemRight,
+.memTemplItemLeft, .memTemplItemRight, .memTemplParams {
+ background-color: #F9FAFC;
border: none;
- border-top: 1px solid black;
+ margin: 4px;
+ padding: 1px 0 0 8px;
+}
+
+.mdescLeft, .mdescRight {
+ padding: 0px 8px 4px 8px;
+ color: #555;
+}
+
+.memItemLeft, .memItemRight, .memTemplParams {
+ border-top: 1px solid #C4CFE5;
+}
+
+.memItemLeft, .memTemplItemLeft {
+ white-space: nowrap;
+}
+
+.memTemplParams {
+ color: #4665A2;
+ white-space: nowrap;
}
-/* Style for detailed member documentation */
+/* @end */
+
+/* @group Member Details */
+
+/* Styles for detailed member documentation */
+
.memtemplate {
- font-size: 80%;
- color: #606060;
+ font-size: 100%;
+ color: #4665A2;
font-weight: normal;
margin-left: 3px;
-}
-.memnav {
- background-color: #e8eef2;
- border: 1px solid #84b0c7;
+}
+
+.memnav {
+ background-color: #EBEFF6;
+ border: 1px solid #A3B4D7;
text-align: center;
margin: 2px;
margin-right: 15px;
padding: 2px;
}
+
.memitem {
- padding: 4px;
- background-color: #eef3f5;
- border-width: 1px;
- border-style: solid;
- border-color: #dedeee;
- -moz-border-radius: 8px 8px 8px 8px;
+ padding: 0;
+ border: 1px solid #C4CFE5;
+ margin-bottom: 30px;
}
+
.memname {
- white-space: nowrap;
- font-weight: bold;
-}
-.memdoc{
- padding-left: 10px;
+ white-space: nowrap;
+ font-weight: bold;
+ margin-left: 6px;
}
+
.memproto {
- background-color: #d5e1e8;
- width: 100%;
- border-width: 1px;
- border-style: solid;
- border-color: #84b0c7;
- font-weight: bold;
- -moz-border-radius: 8px 8px 8px 8px;
+ background-color: #F9FAFC;
+ border-bottom: 1px solid #A3B4D7;
+ padding: 6px 0px 6px 0px;
+ color: #000000;
+ font-weight: bold;
+
+}
+
+.memdoc {
+ padding: 2px 5px;
+ margin-left: 30px;
}
+
.paramkey {
text-align: right;
}
+
.paramtype {
white-space: nowrap;
}
+
.paramname {
color: #602020;
- font-style: italic;
white-space: nowrap;
}
-/* End Styling for detailed member documentation */
+.paramname em {
+ font-style: normal;
+}
+
+/* @end */
+
+/* @group Directory (tree) */
/* for the tree view */
+
.ftvtree {
font-family: sans-serif;
- margin:0.5em;
+ margin: 0px;
}
+
/* these are for tree view when used as main index */
-.directory {
- font-size: 9pt;
- font-weight: bold;
+
+.directory {
+ font-size: 9pt;
+ font-weight: bold;
+ margin: 5px;
}
-.directory h3 {
- margin: 0px;
- margin-top: 1em;
- font-size: 11pt;
+
+.directory h3 {
+ margin: 0px;
+ margin-top: 1em;
+ font-size: 11pt;
}
-/* The following two styles can be used to replace the root node title */
-/* with an image of your choice. Simply uncomment the next two styles, */
-/* specify the name of your image and be sure to set 'height' to the */
-/* proper pixel height of your image. */
+/*
+The following two styles can be used to replace the root node title
+with an image of your choice. Simply uncomment the next two styles,
+specify the name of your image and be sure to set 'height' to the
+proper pixel height of your image.
+*/
-/* .directory h3.swap { */
-/* height: 61px; */
-/* background-repeat: no-repeat; */
-/* background-image: url("yourimage.gif"); */
-/* } */
-/* .directory h3.swap span { */
-/* display: none; */
-/* } */
+/*
+.directory h3.swap {
+ height: 61px;
+ background-repeat: no-repeat;
+ background-image: url("yourimage.gif");
+}
+.directory h3.swap span {
+ display: none;
+}
+*/
-.directory > h3 {
- margin-top: 0;
+.directory > h3 {
+ margin-top: 0;
}
-.directory p {
- margin: 0px;
- white-space: nowrap;
+
+.directory p {
+ margin: 0px;
+ white-space: nowrap;
}
-.directory div {
- display: none;
- margin: 0px;
+
+.directory div {
+ display: none;
+ margin: 0px;
}
-.directory img {
- vertical-align: -30%;
+
+.directory img {
+ vertical-align: -30%;
}
+
/* these are for tree view when not used as main index */
-.directory-alt {
- font-size: 100%;
- font-weight: bold;
+
+.directory-alt {
+ font-size: 100%;
+ font-weight: bold;
+}
+
+.directory-alt h3 {
+ margin: 0px;
+ margin-top: 1em;
+ font-size: 11pt;
}
-.directory-alt h3 {
- margin: 0px;
- margin-top: 1em;
- font-size: 11pt;
+
+.directory-alt > h3 {
+ margin-top: 0;
}
-.directory-alt > h3 {
- margin-top: 0;
+
+.directory-alt p {
+ margin: 0px;
+ white-space: nowrap;
}
-.directory-alt p {
- margin: 0px;
- white-space: nowrap;
+
+.directory-alt div {
+ display: none;
+ margin: 0px;
}
-.directory-alt div {
- display: none;
- margin: 0px;
+
+.directory-alt img {
+ vertical-align: -30%;
}
-.directory-alt img {
- vertical-align: -30%;
+
+/* @end */
+
+div.dynheader {
+ margin-top: 8px;
+}
+
+address {
+ font-style: normal;
+ color: #2A3D61;
+}
+
+table.doxtable {
+ border-collapse:collapse;
+}
+
+table.doxtable td, table.doxtable th {
+ border: 1px solid #2D4068;
+ padding: 3px 7px 2px;
+}
+
+table.doxtable th {
+ background-color: #374F7F;
+ color: #FFFFFF;
+ font-size: 110%;
+ padding-bottom: 4px;
+ padding-top: 5px;
+ text-align:left;
+}
+
+.tabsearch {
+ top: 0px;
+ left: 10px;
+ height: 36px;
+ background-image: url('tab_b.png');
+ z-index: 101;
+ overflow: hidden;
+ font-size: 13px;
+}
+
+.navpath ul
+{
+ font-size: 11px;
+ background-image:url('tab_b.png');
+ background-repeat:repeat-x;
+ height:30px;
+ line-height:30px;
+ color:#8AA0CC;
+ border:solid 1px #C2CDE4;
+ overflow:hidden;
+ margin:0px;
+ padding:0px;
+}
+
+.navpath li
+{
+ list-style-type:none;
+ float:left;
+ padding-left:10px;
+ padding-right: 15px;
+ background-image:url('bc_s.png');
+ background-repeat:no-repeat;
+ background-position:right;
+ color:#364D7C;
+}
+
+.navpath a
+{
+ height:32px;
+ display:block;
+ text-decoration: none;
+ outline: none;
+}
+
+.navpath a:hover
+{
+ color:#6884BD;
+}
+
+div.summary
+{
+ float: right;
+ font-size: 8pt;
+ padding-right: 5px;
+ width: 50%;
+ text-align: right;
+}
+
+div.summary a
+{
+ white-space: nowrap;
+}
+
+div.header
+{
+ background-image:url('nav_h.png');
+ background-repeat:repeat-x;
+ background-color: #F9FAFC;
+ margin: 0px;
+ border-bottom: 1px solid #C4CFE5;
+}
+
+div.headertitle
+{
+ padding: 5px 5px 5px 10px;
}
diff --git a/doc/src/core.c b/doc/src/core.c
new file mode 100644
index 0000000..9520730
--- /dev/null
+++ b/doc/src/core.c
@@ -0,0 +1,812 @@
+/**
+ * \cond skip
+ * vim:syntax=doxygen
+ * \endcond
+
+\page core_doc Netlink Core Library (-lnl)
+
+\section core_intro Introduction
+
+The core library contains the fundamentals required to communicate over
+netlink sockets. It deals with connecting and disconnectng of sockets,
+sending and receiving of data, provides a customizeable receiving state
+machine, and provides a abstract data type framework which eases the
+implementation of object based netlink protocols where objects are added,
+removed, or modified with the help of netlink messages.
+
+\section core_toc Table of Contents
+
+- \ref proto_fund
+ - \ref core_format
+ - \ref core_msgtype
+ - \ref core_multipart
+ - \ref core_errmsg
+ - \ref core_ack
+- \ref sk_doc
+ - \ref core_sk_alloc
+ - \ref core_sk_local_port
+ - \ref core_sk_peer_port
+ - \ref core_sk_fd
+ - \ref core_sk_buffer_size
+ - \ref core_sk_groups
+- \ref core_send_recv
+ - \ref core_send
+ - \ref core_recv
+- \ref core_msg
+- \ref core_cb
+
+\section proto_fund 1. Netlink Protocol Fundamentals
+
+The netlink protocol is a socket based IPC mechanism used for communication
+between any number of userspace processes and the kernel. The netlink
+protocol is based on BSD sockets and uses the \c AF_NETLINK address family.
+It uses a protocol type for each subsystem protocol (e.g. NETLINK_ROUTE,
+NETLINK_NETFILTER, etc). Its addressing schema is based on a 32 bit port
+number, formerly referred to as PID, which uniquely identifies each peer.
+
+\subsection core_format 1.1 Message Format
+
+A netlink protocol is typicall based on messages and consists of the
+netlink message header (struct nlmsghdr) plus the payload attached to it.
+The payload can consist of arbitary data but usually contains a fixed
+size protocol specific header followed by a stream of attributes.
+
+The netlink message header (struct nlmsghdr) has the following format:
+\code
+0 1 2 3
+0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
++-------------------------------------------------------------+
+| Length |
++------------------------------+------------------------------+
+| Type | Flags |
++------------------------------+------------------------------+
+| Sequence Number |
++-------------------------------------------------------------+
+| Port (Address) |
++-------------------------------------------------------------+
+\endcode
+
+\subsection core_msgtype 1.2 Message Types
+
+Netlink differs between requests, notifications, and replies. Requests
+are messages which have the \c NLM_F_REQUEST flag set and are meant to
+request an action from the receiver. A request is typically sent from
+a userspace process to the kernel. While not strictly enforced, requests
+should carry a sequence number incremented for each request sent.
+
+Depending on the nature of the request, the receiver may reply to the
+request with another netlink message. The sequence number of a reply
+must match the sequence number of the request it relates to.
+
+Notifications are of informal nature and no reply is expected, therefore
+the sequence number is typically set to 0. It should be noted that unlike
+in protocols such as TCP there is no strict enforcment of the sequence
+number. The sole purpose of sequence numbers is to assist a sender in
+relating replies to the corresponding requests.
+
+\msc
+A,B;
+A=>B [label="GET (seq=1, NLM_F_REQUEST)"];
+A<=B [label="PUT (seq=1)"];
+...;
+A<=B [label="NOTIFY (seq=0)"];
+\endmsc
+
+\subsection core_multipart 1.3 Multipart Messages (NLM_F_MULTI)
+
+If the size of a reply exceeds the size of a memory page and thus exceeds
+the maximum message size, the reply can be split into a series of multipart
+messages. A multipart message has the \c flag NLM_F_MULTI set and the
+receiver is expected to continue parsing the reply until the special
+message type \c NLMSG_DONE is received.
+
+Multipart messages unlike fragmented ip packets must not be reassmbled
+even though it is perfectly legal to do so if the protocols wishes to
+work this way. Often multipart message are used to send lists or trees
+of objects were each multipart message simply carries multiple objects
+allow for each message to be parsed independently.
+
+\msc
+A,B;
+A=>B [label="GET (seq=1, NLM_F_REQUEST)"];
+A<=B [label="PUT (seq=1, NLM_F_MULTI)"];
+...;
+A<=B [label="PUT (seq=1, NLM_F_MULTI)"];
+A<=B [label="NLMSG_DONE (seq=1)"];
+\endmsc
+
+\subsection core_errmsg 1.4 Error Message
+
+Error messages can be sent in response to a request. Error messages must
+use the standard message type \c NLMSG_ERROR. The payload consists of a
+error code and the original netlink mesage header of the request. Error
+messages should set the sequence number to the sequence number of the
+request which caused the error.
+
+\msc
+A,B;
+A=>B [label="GET (seq=1, NLM_F_REQUEST)"];
+A<=B [label="NLMSG_ERROR code=EINVAL (seq=1)"];
+\endmsc
+
+\subsection core_ack 1.5 ACKs
+
+A sender can request an ACK message to be sent back for each request
+processed by setting the \c NLM_F_ACK flag in the request. This is typically
+used to allow the sender to synchronize further processing until the
+request has been processed by the receiver.
+
+ACK messages also use the message type \c NLMSG_ERROR and payload format
+but the error code is set to 0.
+
+\msc
+A,B;
+A=>B [label="GET (seq=1, NLM_F_REQUEST | NLM_F_ACK)"];
+A<=B [label="ACK (seq=1)"];
+\endmsc
+
+\section sk_doc 2. Netlink Sockets
+
+In order to use the netlink protocol, a netlink socket is required. Each
+socket defines a completely independent context for sending and receiving
+of messages. An application may use multiple sockets for the same netlink
+protocol, e.g. one socket to send requests and receive replies and another
+socket subscribed to a multicast group to receive notifications.
+
+\subsection core_sk_alloc 2.1 Socket Allocation & Freeing
+
+The netlink socket and all its related attributes are represented by
+struct nl_sock.
+
+\code
+struct nl_sock *nl_socket_alloc(void)
+void nl_socket_free(struct nl_sock *sk)
+\endcode
+
+
+\subsection core_sk_local_port 2.2 Local Port
+
+The local port number uniquely identifies the socket and is used to
+address it. A unique local port is generated automatically when the socket
+is allocated. It will consist of the Process ID (22 bits) and a random
+number (10 bits) thus allowing up to 1024 sockets per process.
+
+\code
+uint32_t nl_socket_get_local_port(const struct nl_sock *sk);
+void nl_socket_set_local_port(struct nl_sock *sk, uint32_t port);
+\endcode
+
+\b Note: Overwriting the local port is possible but you have to ensure
+that the provided value is unique and no other socket in any other
+application is using the same value.
+
+\subsection core_sk_peer_port 2.3 Peer Port
+
+A peer port can be assigned to the socket which will result in all unicast
+messages sent over the socket to be addresses to the peer. If no peer is
+specified, the message is sent to the kernel which will try to automatically
+bind the socket to a kernel side socket of the same netlink protocol family.
+It is common practice not to bind the socket to a peer port as typically
+only one kernel side socket exists per netlink protocol family.
+
+\code
+uint32_t nl_socket_get_peer_port(const struct nl_sock *sk);
+void nl_socket_set_peer_port(struct nl_sock *sk, uint32_t port);
+\endcode
+
+\subsection core_sk_fd 2.4 File Descriptor
+
+Netlink uses the BSD socket interface, therefore a file descriptor
+is behind each socket and you may use it directly.
+
+\code
+int nl_socket_get_fd(const struct nl_sock *sk);
+\endcode
+
+If a socket is used to only receive notifications it usually is best
+to put the socket in non-blocking mode and periodically poll for new
+notifications.
+
+\code
+int nl_socket_set_nonblocking(const struct nl_sock *sk);
+\endcode
+
+\subsection core_sk_buffer_size 2.5 Buffer Size
+
+The socket buffer is used to queue netlink messages between sender
+and receiver. The size of these buffers specifies the maximum size
+you will be able to write() to a netlink socket, i.e. it will indirectly
+define the maximum message size. The default is 32KiB.
+
+\code
+int nl_socket_set_buffer_size(struct nl_sock *sk, int rx, int tx);
+\endcode
+
+\subsection core_sk_seq_num 2.6 Sequence Numbers
+
+The library will automatically take care of sequence number handling for
+the application. A sequence number counter is stored in struct nl_sock which
+is meant to be used when sending messages which will produce a reply.
+
+The following function will return the sequence number counter and increment
+it afterwards.
+
+\code
+unsigned int nl_socket_use_seq(struct nl_sock *sk);
+\endcode
+
+
+if nl_send_auto_complete() is used to send messages.
+
+See \ref core_send_recv.
+
+
+
+It will return the current sequence number and increment the counter
+afterwards.
+
+When receiving netlink messages on a socket, the sequence number of
+each received message will be automatically compared to the last
+sequence number used, therefore ensuring that each reply relates to
+a request.
+
+This behaviour can and must be disabled if the netlink protocol
+implemented does not use a request/reply model:
+
+\code
+void nl_socket_disable_seq_check(struct nl_sock *sk);
+\endcode
+
+\subsection core_sk_groups 2.6 Multicast Groups
+
+Each socket can subscribe to any number of multicast groups of the
+netlink protocol it is connected to. The socket will then receive a copy
+of each message sent to any of the groups. Multicast groups are commonly
+used to implement event notifications.
+
+Prior to kernel 2.6.14 the group subscription was performed using a bitmask
+which limited the number of groups per protocol family to 32. This outdated
+interface can still be accessed via the function nl_join_groups even though
+it is not recommended for new code.
+
+\code
+void nl_join_groups(struct nl_sock *sk, int bitmask); /* obsolete */
+\endcode
+
+Starting with 2.6.14 a new method was introduced which supports subscribing
+to an almost infinite number of multicast groups.
+
+\code
+int nl_socket_add_memberships(struct nl_sock *sk, int group, ...);
+int nl_socket_drop_memberships(struct nl_sock *sk, int group, ...);
+\endcode
+
+\subsubsection core_sk_group_example 2.6.1 Multicast Example
+
+\code
+// This function will be called for each valid netlink message received
+// in nl_recvmsgs_default()
+static int my_func(struct nl_msg *msg, void *arg)
+{
+ return 0;
+}
+
+struct nl_sock *sk;
+
+// Allocate a new socket
+sk = nl_socket_alloc();
+
+// Notifications do not use sequence numbers, disable sequence number
+// checking.
+nl_socket_disable_seq_check(sk);
+
+// Define a callback function, which will be called for each notification
+// received
+nl_socket_modify_cb(sk, NL_CB_VALID, NL_CB_CUSTOM, my_func, NULL);
+
+// Connect to routing netlink protocol
+nl_connect(sk, NETLINK_ROUTE);
+
+// Subscribe to link notifications group
+nl_socket_add_memberships(sk, RTNLGRP_LINK);
+
+// Start receiving messages. The function nl_recvmsgs_default() will block
+// until one or more netlink messages (notification) are received which
+// will be passed on to my_func().
+while (1)
+ nl_recvmsgs_default(sock);
+\endcode
+
+
+\subsection core_sk_cb 2.7 Callback Configuration
+Every socket is associated a callback configuration which enables the
+applications to hook into various internal functions and control the
+receiving and sendings semantics. For more information, see section
+\ref core_cb.
+
+\code
+nl_socket_alloc_cb(cb) Allocate socket based on callback set.
+nl_socket_get_cb(sk) Return callback configuration.
+nl_socket_set_cb(sk, cb) Replace callback configuration.
+nl_socket_modify_cb(sk, ...) Modify a specific callback function.
+\endcode
+
+\subsection core_sk_cred 2.8 Credentials
+
+\subsection sk_other Other Functions
+\code
+nl_socket_enable_auto_ack(sock) Enable automatic request of ACK.
+nl_socket_disable_auto_ack(sock) Disable automatic request of ACK.
+nl_socket_enable_msg_peek(sock) Enable message peeking.
+nl_socket_disable_msg_peek(sock) Disable message peeking.
+nl_socket_set_passcred(sk, state) Enable/disable credential passing.
+nl_socket_recv_pktinfo(sk, state) Enable/disable packet information.
+\endcode
+
+\section core_send_recv 3. Sending and Receiving of Messages / Data
+
+- \ref core_send
+ - \ref core_nl_send
+ - \ref core_nl_send_iovec
+ - \ref core_nl_sendmsg
+ - \ref core_send_raw
+ - \ref core_send_simple
+- \ref core_recv
+ - \ref core_nl_recvmsgs
+ - \ref core_recvmsgs
+ - \ref core_recv_parse
+
+\subsection core_send 3.1 Sending Netlink Messages
+
+The standard method of sending a netlink message over a netlink socket
+is to use the function nl_send_auto(). It will automatically complete
+the netlink message by filling the missing bits and pieces in the
+netlink message header and will deal with addressing based on the
+options and address set in the netlink socket. The message is then based
+on to nl_send().
+
+If the default sending semantics implemented by nl_send() do not suit the
+application, it may overwrite the sending function nl_send() by
+specifying an own implementation using the function nl_cb_overwrite_send().
+
+\code
+ nl_send_auto(sk, msg)
+ |
+ |-----> nl_complete_msg(sk, msg)
+ |
+ |
+ | Own send function specified via nl_cb_overwrite_send()
+ |- - - - - - - - - - - - - - - - - - - -
+ v v
+ nl_send(sk, msg) send_func()
+\endcode
+
+\subsubsection core_nl_send 3.1.1 Using nl_send()
+
+If you do not require any of the automatic message completion functionality
+you may use nl_send() directly but beware that any internal calls to
+nl_send_auto() by the library to send netlink messages will still use
+nl_send(). Therefore if you wish to use any higher level interfaces and the
+behaviour of nl_send() is to your dislike then you must overwrite the
+nl_send() function via nl_cb_overwrite_send()
+
+The purpose of nl_send() is to embed the netlink message into a iovec
+structure and pass it on to nl_send_iovec().
+
+\code
+ nl_send(sk, msg)
+ |
+ v
+ nl_send_iovec(sk, msg, iov, iovlen)
+\endcode
+
+\subsubsection core_nl_send_iovec 3.1.2 Using nl_send_iovec()
+
+nl_send_iovec() expects a finalized netlink message and fills out the
+struct msghdr used for addressing. It will first check if the struct nl_msg
+is addressed to a specific peer (see nlmsg_set_dst()). If not, it will try
+to fall back to the peer address specified in the socket (see
+nl_socket_set_peer_port(). Otherwise the message will be sent unaddressed
+and it is left to the kernel to find the correct peer.
+
+nl_send_iovec() also adds credentials if present and enabled
+(see \ref core_sk_cred).
+
+The message is then passed on to nl_sendmsg().
+
+\code
+ nl_send_iovec(sk, msg, iov, iovlen)
+ |
+ v
+ nl_sendmsg(sk, msg, msghdr)
+ |- - - - - - - - - - - - - - - - - - - - v
+ | NL_CB_MSG_OUT()
+ |<- - - - - - - - - - - - - - - - - - - -+
+ v
+ sendmsg()
+\endcode
+
+\subsubsection core_nl_sendmsg 3.1.3 Using nl_sendmsg()
+
+nl_sendmsg() expects a finalized netlink message and an optional struct
+msghdr containing the peer address. It will copy the local address as
+defined in the socket (see nl_socket_set_local_port()) into the netlink
+message header.
+
+At this point, construction of the message finished and it is ready to
+be sent.
+
+Before sending the application has one last chance to modify the message.
+It is passed to the NL_CB_MSG_OUT callback function which may inspect or
+modify the message and return an error code. If this error code is NL_OK
+the message is sent using sendmsg() resulting in the number of bytes
+written being returned. Otherwise the message sending process is aborted
+and the error code specified by the callback function is returned. See
+\ref core_sk_cb for more information on how to set callbacks.
+
+\subsubsection core_send_raw 3.1.4 Sending Raw Data with nl_sendto()
+
+If you wish to send raw data over a netlink socket, the following
+function will pass on any buffer provided to it directly to sendto():
+
+\code
+int nl_sendto(struct nl_sock *sk, void *buf, size_t size);
+\endcode
+
+\subsubsection core_send_simple 3.1.5 Sending of Simple Messages
+
+A special interface exists for sending of trivial messages. The function
+expects the netlink message type, optional netlink message flags, and an
+optional data buffer and data length.
+\code
+int nl_send_simple(struct nl_sock *sk, int type, int flags,
+ void *buf, size_t size);
+\endcode
+
+The function will construct a netlink message header based on the message
+type and flags provided and append the data buffer as message payload. The
+newly constructed message is sent with nl_send_auto().
+
+The following example will send a netlink request message causing the
+kernel to dump a list of all network links to userspace:
+\code
+struct nl_sock *sk;
+struct rtgenmsg rt_hdr = {
+ .rtgen_family = AF_UNSPEC,
+};
+
+sk = nl_socket_alloc();
+nl_connect(sk, NETLINK_ROUTE);
+
+nl_send_simple(sock, RTM_GETLINK, NLM_F_DUMP, &rt_hdr, sizeof(rt_hdr));
+\endcode
+
+\subsection core_recv 3.2 Receiving Netlink Messages
+
+The easiest method to receive netlink messages is to call nl_recvmsgs_default().
+It will receive messages based on the semantics defined in the socket. The
+application may customize these in detail although the default behaviour will
+probably suit most applications.
+
+nl_recvmsgs_default() will also be called internally by the library whenever
+it needs to receive and parse a netlink message.
+
+The function will fetch the callback configuration stored in the socket and
+call nl_recvmsgs():
+
+\code
+ nl_recvmsgs_default(sk)
+ |
+ | cb = nl_socket_get_cb(sk)
+ v
+ nl_recvmsgs(sk, cb)
+\endcode
+
+\subsubsection core_nl_recvmsgs 3.2.1 Using nl_recvmsgs()
+
+nl_recvmsgs() implements the actual receiving loop, it blocks until a
+netlink message has been received unless the socket has been put into
+non-blocking mode.
+
+See \ref core_recvmsgs for more information on the behaviour of
+nl_recvmsgs().
+
+For the unlikely scenario that certain required receive characteristics
+can not be achieved by fine tuning the internal recvmsgs function using
+the callback configuration (see \ref core_sk_cb) the application may
+provide a complete own implementation of it and overwrite all calls to
+nl_recvmsgs() with the function nl_cb_overwrite_recvmsgs().
+
+\code
+ nl_recvmsgs(sk, cb)
+ |
+ | Own recvmsgs function specified via nl_cb_overwrite_recvmsgs()
+ |- - - - - - - - - - - - - - - - - - - -
+ v v
+ internal_recvmsgs() my_recvmsgs()
+\endcode
+
+\subsubsection core_recvmsgs 3.2.2 Receive Characteristics
+
+If the application does not provide its own recvmsgs() implementation
+with the function nl_cb_overwrite_recvmsgs() the following characteristics
+apply while receiving data from a netlink socket:
+
+\code
+ internal_recvmsgs()
+ |
++-------------->| Own recv function specified with nl_cb_overwrite_recv()
+| |- - - - - - - - - - - - - - - -
+| v v
+| nl_recv() my_recv()
+| |<- - - - - - - - - - - - - - -+
+| |<-------------+
+| v | More data to parse? (nlmsg_next())
+| Parse Message |
+| |--------------+
+| v
++------- NLM_F_MULTI set?
+ |
+ v
+ (SUCCESS)
+\endcode
+
+The function nl_recv() is invoked first to receive data from the netlink
+socket. This function may be overwritten by the application by an own
+implementation using the function nl_cb_overwrite_recv(). This may be
+useful if the netlink byte stream is in fact not received from a socket
+directly but is read from a file or another source.
+
+If data has been read, it will be attemped to parse the data
+(see \ref core_recv_parse). This will be done repeately until the parser
+returns NL_STOP, an error was returned or all data has been parsed.
+
+In case the last message parsed successfully was a multipart message
+(see \ref core_multipart) and the parser did not quit due to either an
+error or NL_STOP nl_recv() respectively the applications own implementation
+will be called again and the parser starts all over.
+
+See \ref core_recv_parse for information on how to extract valid netlink
+messages from the parser and on how to control the behaviour of it.
+
+\subsubsection core_recv_parse 3.2.3 Parsing Characteristics
+
+The internal parser is invoked for each netlink message received from a
+netlink socket. It is typically fed by nl_recv() (see \ref core_recvmsgs).
+
+The parser will first ensure that the length of the data stream provided
+is sufficient to contain a netlink message header and that the message
+length as specified in the message header does not exceed it.
+
+If this criteria is met, a new struct nl_msg is allocated and the message
+is passed on to the the callback function NL_CB_MSG_IN if one is set. Like
+any other callback function, it may return NL_SKIP to skip the current
+message but continue parsing the next message or NL_STOP to stop parsing
+completely.
+
+The next step is to check the sequence number of the message against the
+currently expected sequence number. The application may provide its own
+sequence number checking algorithm by setting the callback function
+NL_CB_SEQ_CHECK to its own implementation. In fact, calling
+nl_socket_disable_seq_check() to disable sequence number checking will
+do nothing more than set the NL_CB_SEQ_CHECK hook to a function which
+always returns NL_OK.
+
+Another callback hook NL_CB_SEND_ACK exists which is called if the
+message has the NLM_F_ACK flag set. Although I am not aware of any
+userspace netlink socket doing this, the application may want to send
+an ACK message back to the sender (see \ref core_ack).
+
+\code
+ parse()
+ |
+ v
+ nlmsg_ok() --> Ignore
+ |
+ |- - - - - - - - - - - - - - - v
+ | NL_CB_MSG_IN()
+ |<- - - - - - - - - - - - - - -+
+ |
+ |- - - - - - - - - - - - - - - v
+ Sequence Check NL_CB_SEQ_CHECK()
+ |<- - - - - - - - - - - - - - -+
+ |
+ | Message has NLM_F_ACK set
+ |- - - - - - - - - - - - - - - v
+ | NL_CB_SEND_ACK()
+ |<- - - - - - - - - - - - - - -+
+ |
+ Handle Message Type
+\endcode
+
+\section core_msg 4. Message Construction & Parsing
+
+\subsection core_msg_format 4.1 Message Format
+
+\section core_cb 5. Callback Configurations
+
+Callback hooks and overwriting capabilities are provided in various places
+inside library code to control the behaviour of several functions. All
+the callback and overwrite functions are packed together in struct nl_cb
+which is attached to a netlink socket or passed on to functions directly.
+
+\subsection cb_func 5.1 Callback Function Formats
+
+\subsubsection cb_func_recvmsgs 5.1.1 Callbacks for nl_recvmsgs() and nl_sendmsg()
+
+Both nl_recvmsgs() and nl_sendmsg() provide callback hooks for functions to
+control their behaviour. Every callback function must have the following
+prototype:
+
+\code
+typedef int(* nl_recvmsg_msg_cb_t)(struct nl_msg *msg, void *arg);
+\endcode
+
+nl_sendmsg() callback hooks:
+\code
+Callback ID | Description | Default Return Value
+-----------------------------------------------------------------------------
+NL_CB_MSG_OUT | Each message sent | NL_OK
+\endcode
+
+Any function called by NL_CB_MSG_OUT may return a negative error code to
+prevent the message from being sent and the error code being returned.
+
+nl_recvmsgs() callback hooks (ordered by priority):
+\code
+Callback ID | Description | Default Return Value
+-----------------------------------------------------------------------------
+NL_CB_MSG_IN | Each message received | NL_OK
+NL_CB_SEQ_CHECK | May overwrite sequence check algo | NL_OK
+NL_CB_INVALID | Invalid messages | NL_STOP
+NL_CB_SEND_ACK | Messages with NLM_F_ACK flag set | NL_OK
+NL_CB_FINISH | Messages of type NLMSG_DONE | NL_STOP
+NL_CB_SKIPPED | Messages of type NLMSG_NOOP | NL_SKIP
+NL_CB_OVERRUN | Messages of type NLMSG_OVERRUN | NL_STOP
+NL_CB_ACK | ACK Messages | NL_STOP
+NL_CB_VALID | Each valid message | NL_OK
+\endcode
+
+All these callback hooks can control the flow of the callee by returning
+appropriate error codes:
+\code
+Return Code | Description
+-------------------------------------------------------------------------
+NL_OK | Proceed.
+NL_SKIP | Skip message currently being processed and continue
+ | parsing the receive buffer.
+NL_STOP | Stop parsing and discard all remaining data in the
+ | receive buffer.
+\endcode
+
+\subsubsection cb_func_error 5.1.2 Callback for Error Messages
+
+A special function prototype is used for the error message callback hook:
+
+\code
+typedef int(* nl_recvmsg_err_cb_t)(struct sockaddr_nl *nla, struct nlmsgerr *nlerr, void *arg);
+\endcode
+
+\subsubsection cb_cb_set 5.1.3 Setting Callback Functions
+
+In order to simplify typical usages of the library, different sets of
+default callback implementations exist:
+\code
+NL_CB_DEFAULT: No additional actions
+NL_CB_VERBOSE: Automatically print warning and error messages to a file
+ descriptor as appropriate. This is useful for CLI based
+ applications.
+NL_CB_DEBUG: Print informal debugging information for each message
+ received. This will result in every message beint sent or
+ received to be printed to the screen in a decoded,
+ human-readable format.
+\endcode
+
+\subsubsection core_cb_example 5.1.4 Example: Setting up a callback set
+\code
+// Allocate a callback set and initialize it to the verbose default set
+struct nl_cb *cb = nl_cb_alloc(NL_CB_VERBOSE);
+
+// Modify the set to call my_func() for all valid messages
+nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, my_func, NULL);
+
+// Set the error message handler to the verbose default implementation
+// and direct it to print all errors to the given file descriptor.
+FILE *file = fopen(...);
+nl_cb_err(cb, NL_CB_VERBOSE, NULL, file);
+\endcode
+
+\section remarks Remarks
+
+\subsection cache_alloc Allocation of Caches
+
+Almost all subsystem provide a function to allocate a new cache
+of some form. The function usually looks like this:
+\code
+struct nl_cache *<object name>_alloc_cache(struct nl_sock *sk);
+\endcode
+
+These functions allocate a new cache for the own object type,
+initializes it properly and updates it to represent the current
+state of their master, e.g. a link cache would include all
+links currently configured in the kernel.
+
+Some of the allocation functions may take additional arguments
+to further specify what will be part of the cache.
+
+All such functions return a newly allocated cache or NULL
+in case of an error.
+
+\subsection addr Setting of Addresses
+\code
+int <object name>_set_addr(struct nl_object *, struct nl_addr *)
+\endcode
+
+All attribute functions avaiable for assigning addresses to objects
+take a struct nl_addr argument. The provided address object is
+validated against the address family of the object if known already.
+The assignment fails if the address families mismatch. In case the
+address family has not been specified yet, the address family of
+the new address is elected to be the new requirement.
+
+The function will acquire a new reference on the address object
+before assignment, the caller is NOT responsible for this.
+
+All functions return 0 on success or a negative error code.
+
+\subsection flags Flags to Character StringTranslations
+All functions converting a set of flags to a character string follow
+the same principles, therefore, the following information applies
+to all functions convertings flags to a character string and vice versa.
+
+\subsubsection flags2str Flags to Character String
+\code
+char *<object name>_flags2str(int flags, char *buf, size_t len)
+\endcode
+\arg flags Flags.
+\arg buf Destination buffer.
+\arg len Buffer length.
+
+Converts the specified flags to a character string separated by
+commas and stores it in the specified destination buffer.
+
+\return The destination buffer
+
+\subsubsection str2flags Character String to Flags
+\code
+int <object name>_str2flags(const char *name)
+\endcode
+\arg name Name of flag.
+
+Converts the provided character string specifying a flag
+to the corresponding numeric value.
+
+\return Link flag or a negative value if none was found.
+
+\subsubsection type2str Type to Character String
+\code
+char *<object name>_<type>2str(int type, char *buf, size_t len)
+\endcode
+\arg type Type as numeric value
+\arg buf Destination buffer.
+\arg len Buffer length.
+
+Converts an identifier (type) to a character string and stores
+it in the specified destination buffer.
+
+\return The destination buffer or the type encoded in hexidecimal
+ form if the identifier is unknown.
+
+\subsubsection str2type Character String to Type
+\code
+int <object name>_str2<type>(const char *name)
+\endcode
+\arg name Name of identifier (type).
+
+Converts the provided character string specifying a identifier
+to the corresponding numeric value.
+
+\return Identifier as numeric value or a negative value if none was found.
+
+
+*/
diff --git a/doc/src/genl.c b/doc/src/genl.c
new file mode 100644
index 0000000..8585c62
--- /dev/null
+++ b/doc/src/genl.c
@@ -0,0 +1,10 @@
+/**
+ * \cond skip
+ * vim:syntax=doxygen
+ * \endcond
+
+\page genl_doc Generic Netlink Library (-lnl-genl)
+
+\section genl_intro Introduction
+
+*/
diff --git a/doc/src/nf.c b/doc/src/nf.c
new file mode 100644
index 0000000..006500d
--- /dev/null
+++ b/doc/src/nf.c
@@ -0,0 +1,10 @@
+/**
+ * \cond skip
+ * vim:syntax=doxygen
+ * \endcond
+
+\page nf_doc Netfilter Netlink Library (-lnl-nf)
+
+\section nf_intro Introduction
+
+*/
diff --git a/doc/src/route.c b/doc/src/route.c
new file mode 100644
index 0000000..2c042db
--- /dev/null
+++ b/doc/src/route.c
@@ -0,0 +1,10 @@
+/**
+ * \cond skip
+ * vim:syntax=doxygen
+ * \endcond
+
+\page route_doc Routing Netlink Library (-lnl-route)
+
+\section route_intro Introduction
+
+*/
diff --git a/doc/src/toc.c b/doc/src/toc.c
new file mode 100644
index 0000000..c33727c
--- /dev/null
+++ b/doc/src/toc.c
@@ -0,0 +1,66 @@
+/**
+ * \cond skip
+ * vim:syntax=doxygen
+ * \endcond
+
+\mainpage
+
+\section main_intro Introduction
+
+libnl is a set of libraries to deal with the netlink protocol and some
+of the high level protocols implemented on top of it. The goal is to
+provide APIs on different levels of abstraction. The core library libnl.so
+provides a fundamental set of functions to deal with sockets, construct
+messages, and send/receive those messages. Additional high level interfaces
+for several individual netlink protocols are provided in separate
+libraries (e.g. \ref route_doc "nl-route.so", \ref genl_doc "nl-genl.so", ...).
+
+The library is designed to ensure that all components are optional, i.e.
+even though the core library provides a caching system which allows to
+easly manage objects of any kind, no application is required to use this
+caching system if it has no need for it.
+
+The library was developed and tested on 2.6.x kernel releases. It may
+or may not work with older kernel series. Also, although all netlink
+protocols are required to maintain backwards compatibility, this has not
+always achieved and undesired side effects can occur if a recent libnl
+version is used with a considerably older kernel.
+
+\section main_toc Table of Contents
+
+- \subpage core_doc "1. Netlink Core Library (-lnl)"
+- \subpage route_doc "2. Routing Netlink Library (-lnl-route)"
+- \subpage genl_doc "3. Generic Netlink Library (-lnl-genl)"
+- \subpage nf_doc "4. Netfilter Netlink Library (-lnl-nf)"
+
+\section main_trees GIT Trees
+
+\subsection tree_dev Development Tree
+
+@code
+git://git.kernel.org/pub/scm/libs/netlink/libnl.git
+@endcode
+- Web: http://www.kernel.org/pub/scm/libs/netlink/libnl.git
+
+\subsection tree_stable Stable Tree
+
+@code
+git://git.kernel.org/pub/scm/libs/netlink/libnl-stable.git
+@endcode
+- Web: http://www.kernel.org/pub/scm/libs/netlink/libnl-stable.git
+
+\section main_website Website
+
+- http://www.infradead.org/~tgr/libnl/
+
+\section main_mailinglist Mailinglist
+
+Please post question and patches to the libnl mailinglist:
+
+@code
+libnl@lists.infradead.org
+@endcode
+
+- Archives: http://canuck.infradead.org/pipermail/libnl/
+
+*/
diff --git a/lib/doc.c b/lib/doc.c
deleted file mode 100644
index 4272a59..0000000
--- a/lib/doc.c
+++ /dev/null
@@ -1,487 +0,0 @@
-/*
- * lib/doc.c Documentation Purpose
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation version 2.1
- * of the License.
- *
- * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch>
- */
-
-/**
- * @mainpage
- *
- * @section intro Introduction
- *
- * libnl is a set of libraries to deal with the netlink protocol and some
- * of the high level protocols implemented on top of it. Its goal is to
- * simplify netlink protocol usage and to create an abstraction layer using
- * object based interfaces for various netlink based subsystems.The library
- * was developed and tested on the 2.6.x kernel releases but it may work with
- * older kernel series.
- *
- * @section toc Table of Contents
- *
- * - \subpage core_doc
- * - \subpage route_doc
- * - \subpage genl_doc
- * - \subpage nf_doc
- *
- * @section remarks Remarks
- *
- * @subsection cache_alloc Allocation of Caches
- *
- * Almost all subsystem provide a function to allocate a new cache
- * of some form. The function usually looks like this:
- * @code
- * struct nl_cache *<object name>_alloc_cache(struct nl_sock *sk);
- * @endcode
- *
- * These functions allocate a new cache for the own object type,
- * initializes it properly and updates it to represent the current
- * state of their master, e.g. a link cache would include all
- * links currently configured in the kernel.
- *
- * Some of the allocation functions may take additional arguments
- * to further specify what will be part of the cache.
- *
- * All such functions return a newly allocated cache or NULL
- * in case of an error.
- *
- * @subsection addr Setting of Addresses
- * @code
- * int <object name>_set_addr(struct nl_object *, struct nl_addr *)
- * @endcode
- *
- * All attribute functions avaiable for assigning addresses to objects
- * take a struct nl_addr argument. The provided address object is
- * validated against the address family of the object if known already.
- * The assignment fails if the address families mismatch. In case the
- * address family has not been specified yet, the address family of
- * the new address is elected to be the new requirement.
- *
- * The function will acquire a new reference on the address object
- * before assignment, the caller is NOT responsible for this.
- *
- * All functions return 0 on success or a negative error code.
- *
- * @subsection flags Flags to Character StringTranslations
- * All functions converting a set of flags to a character string follow
- * the same principles, therefore, the following information applies
- * to all functions convertings flags to a character string and vice versa.
- *
- * @subsubsection flags2str Flags to Character String
- * @code
- * char *<object name>_flags2str(int flags, char *buf, size_t len)
- * @endcode
- * @arg flags Flags.
- * @arg buf Destination buffer.
- * @arg len Buffer length.
- *
- * Converts the specified flags to a character string separated by
- * commas and stores it in the specified destination buffer.
- *
- * @return The destination buffer
- *
- * @subsubsection str2flags Character String to Flags
- * @code
- * int <object name>_str2flags(const char *name)
- * @endcode
- * @arg name Name of flag.
- *
- * Converts the provided character string specifying a flag
- * to the corresponding numeric value.
- *
- * @return Link flag or a negative value if none was found.
- *
- * @subsubsection type2str Type to Character String
- * @code
- * char *<object name>_<type>2str(int type, char *buf, size_t len)
- * @endcode
- * @arg type Type as numeric value
- * @arg buf Destination buffer.
- * @arg len Buffer length.
- *
- * Converts an identifier (type) to a character string and stores
- * it in the specified destination buffer.
- *
- * @return The destination buffer or the type encoded in hexidecimal
- * form if the identifier is unknown.
- *
- * @subsubsection str2type Character String to Type
- * @code
- * int <object name>_str2<type>(const char *name)
- * @endcode
- * @arg name Name of identifier (type).
- *
- * Converts the provided character string specifying a identifier
- * to the corresponding numeric value.
- *
- * @return Identifier as numeric value or a negative value if none was found.
- *
- * @page core_doc Core Library (-lnl)
- *
- * @section core_intro Introduction
- *
- * The core library contains the fundamentals required to communicate over
- * netlink sockets. It deals with connecting and unconnecting of sockets,
- * sending and receiving of data, provides a customizeable receiving state
- * machine, and provides a abstract data type framework which eases the
- * implementation of object based netlink protocols where objects are added,
- * removed, or modified with the help of netlink messages.
- *
- * @section core_toc Table of Contents
- *
- * - \ref proto_fund
- * - \ref sk_doc
- * - \ref rxtx_doc
- * - \ref cb_doc
- *
- * @section proto_fund Netlink Protocol Fundamentals
- *
- * The netlink protocol is a socket based IPC mechanism used for communication
- * between userspace processes and the kernel. The netlink protocol uses the
- * \c AF_NETLINK address family and defines a protocol type for each subsystem
- * protocol (e.g. NETLINK_ROUTE, NETLINK_NETFILTER, etc). Its addressing
- * schema is based on a 32 bit port number, formerly referred to as PID, which
- * uniquely identifies each peer.
- *
- * The netlink protocol is based on messages each limited to the size of a
- * memory page and consists of the netlink message header (struct nlmsghdr)
- * plus the payload attached to it. The payload can consist of arbitary data
- * but often contains a fixed sized family specifc header followed by a
- * stream of \ref attr_doc. The use of attributes dramatically increases
- * the flexibility of the protocol and allows for the protocol to be
- * extended while maintaining backwards compatibility.
- *
- * The netlink message header (struct nlmsghdr):
- * @code
- * 0 1 2 3
- * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
- * +-------------------------------------------------------------+
- * | Length |
- * +------------------------------+------------------------------+
- * | Type | Flags |
- * +------------------------------+------------------------------+
- * | Sequence Number |
- * +-------------------------------------------------------------+
- * | Port (Address) |
- * +-------------------------------------------------------------+
- * @endcode
- *
- * Netlink differs between requests, notifications, and replies. Requests
- * are messages which have the \c NLM_F_REQUEST flag set and are meant to
- * request an action from the receiver. A request is typically sent from
- * a userspace process to the kernel. Every request should be assigned a
- * sequence number which should be incremented for each request sent on the
- * sending side. Depending on the nature of the request, the receiver may
- * reply to the request with regular netlink messages which should contain
- * the same sequence number as the request it relates to. Notifications are
- * of informal nature and don't expect a reply, therefore the sequence number
- * is typically set to 0. It should be noted that unlike in protocols such as
- * TCP there is no strict enforcment of the sequence number. The sole purpose
- * of sequence numbers is to assist a sender in relating replies to the
- * corresponding requests.
- *
- * @msc
- * A,B;
- * A=>B [label="GET (seq=1, NLM_F_REQUEST)"];
- * A<=B [label="PUT (seq=1)"];
- * ...;
- * A<=B [label="NOTIFY (seq=0)"];
- * @endmsc
- *
- * If the size of a reply exceeds the size of a memory page and thus exceeds
- * the maximum message size, the reply can be split into a series of multipart
- * messages. A multipart message has the \c flag NLM_F_MULTI set and the
- * receiver is expected to continue parsing the reply until the special
- * message type \c NLMSG_DONE is received.
- *
- * @msc
- * A,B;
- * A=>B [label="GET (seq=1, NLM_F_REQUEST)"];
- * A<=B [label="PUT (seq=1, NLM_F_MULTI)"];
- * ...;
- * A<=B [label="PUT (seq=1, NLM_F_MULTI)"];
- * A<=B [label="NLMSG_DONE (seq=1)"];
- * @endmsc
- *
- * Errors can be reported using the standard message type \c NLMSG_ERROR which
- * can carry an error code and the netlink mesage header of the request.
- * Error messages should set their sequence number to the sequence number
- * of the message which caused the error.
- *
- * @msc
- * A,B;
- * A=>B [label="GET (seq=1, NLM_F_REQUEST)"];
- * A<=B [label="NLMSG_ERROR code=EINVAL (seq=1)"];
- * @endmsc
- *
- * The \c NLMSG_ERROR message type is also used to send acknowledge messages.
- * An acknowledge message can be requested by setting the \c NLM_F_ACK flag
- * message except that the error code is set to 0.
- *
- * @msc
- * A,B;
- * A=>B [label="GET (seq=1, NLM_F_REQUEST | NLM_F_ACK)"];
- * A<=B [label="ACK (seq=1)"];
- * @endmsc
- *
- * @section sk_doc Dealing with Netlink Sockets
- *
- * In order to use the netlink protocol, a netlink socket is required. Each
- * socket defines a completely independent context for sending and receiving
- * of messages. The netlink socket and all its related attributes are
- * represented by struct nl_sock.
- *
- * @code
- * nl_socket_alloc() Allocate new socket structure.
- * nl_socket_free(s) Free socket structure.
- * @endcode
- *
- * @subsection local_port Local Port
- * The local port number uniquely identifies the socket and is used to
- * address it. A unique local port is generated automatically when the socket
- * is allocated. It will consist of the Process ID (22 bits) and a random
- * number (10 bits) to allow up to 1024 sockets per process.
- *
- * @code
- * nl_socket_get_local_port(sk) Return the peer's port number.
- * nl_socket_set_local_port(sk, port) Set the peer's port number.
- * @endcode
- *
- * @subsection peer_port Peer Port
- * A peer port can be assigned to the socket which will result in all unicast
- * messages sent over the socket to be addresses to the corresponding peer. If
- * no peer is specified, the kernel will try to automatically bind the socket
- * to a kernel side socket of the same netlink protocol family. It is common
- * practice not to bind the socket to a peer port as typically only one kernel
- * side socket exists per netlink protocol family.
- *
- * @code
- * nl_socket_get_peer_port(sk) Return the local port number.
- * nl_socket_set_peer_port(sk, port) Set the local port number.
- * @endcode
- *
- * @subsection sock_fd File Descriptor
- * The file descriptor of the socket(2).
- *
- * @code
- * nl_socket_get_fd(sk) Return file descriptor.
- * nl_socket_set_buffer_size(sk, rx, tx) Set buffer size of socket.
- * nl_socket_set_nonblocking(sk) Set socket to non-blocking state.
- * @endcode
- *
- * @subsection group_sub Group Subscriptions
- * Each socket can subscribe to multicast groups of the netlink protocol
- * family it is bound to. The socket will then receive a copy of each
- * message sent to any of the groups. Multicast groups are commonly used
- * to implement event notifications. Prior to kernel 2.6.14 the group
- * subscription was performed using a bitmask which limited the number of
- * groups per protocol family to 32. This outdated interface can still be
- * accessed via the function nl_join_groups even though it is not recommended
- * for new code. Starting with 2.6.14 a new method was introduced which
- * supports subscribing to an almost unlimited number of multicast groups.
- *
- * @code
- * nl_socket_add_membership(sk, group) Become a member of a multicast group.
- * nl_socket_drop_membership(sk, group) Drop multicast group membership.
- * nl_join_groups(sk, groupmask) Join a multicast group (obsolete).
- * @endcode
- *
- * @subsection seq_num Sequence Numbers
- * The socket keeps track of the sequence numbers used. The library will
- * automatically verify the sequence number of messages received unless
- * the check was disabled using the function nl_socket_disable_seq_check().
- * When a message is sent using nl_send_auto_complete(), the sequence number
- * is automatically filled in, and replies will be verified correctly.
- *
- * @code
- * nl_socket_disable_seq_check(sk) Disable checking of sequece numbers.
- * nl_socket_use_seq(sk) Use sequence number and bump to next.
- * @endcode
- *
- * @subsection sock_cb Callback Configuration
- * Every socket is associated a callback configuration which enables the
- * applications to hook into various internal functions and control the
- * receiving and sendings semantics. For more information, see section
- * \ref cb_doc.
- *
- * @code
- * nl_socket_alloc_cb(cb) Allocate socket based on callback set.
- * nl_socket_get_cb(sk) Return callback configuration.
- * nl_socket_set_cb(sk, cb) Replace callback configuration.
- * nl_socket_modify_cb(sk, ...) Modify a specific callback function.
- * @endcode
- *
- * @subsection sk_other Other Functions
- * @code
- * nl_socket_enable_auto_ack(sock) Enable automatic request of ACK.
- * nl_socket_disable_auto_ack(sock) Disable automatic request of ACK.
- * nl_socket_enable_msg_peek(sock) Enable message peeking.
- * nl_socket_disable_msg_peek(sock) Disable message peeking.
- * nl_socket_set_passcred(sk, state) Enable/disable credential passing.
- * nl_socket_recv_pktinfo(sk, state) Enable/disable packet information.
- * @endcode
- *
- * @section rxtx_doc Sending and Receiving of Data
- *
- * @subsection recv_semantisc Receiving Semantics
- * @code
- * nl_recvmsgs_default(set)
- * | cb = nl_socket_get_cb(sk)
- * v
- * nl_recvmsgs(sk, cb)
- * | [Application provides nl_recvmsgs() replacement]
- * |- - - - - - - - - - - - - - - v
- * | cb->cb_recvmsgs_ow()
- * |
- * | [Application provides nl_recv() replacement]
- * +-------------->|- - - - - - - - - - - - - - - v
- * | nl_recv() cb->cb_recv_ow()
- * | +----------->|<- - - - - - - - - - - - - - -+
- * | | v
- * | | Parse Message
- * | | |- - - - - - - - - - - - - - - v
- * | | | NL_CB_MSG_IN()
- * | | |<- - - - - - - - - - - - - - -+
- * | | |
- * | | |- - - - - - - - - - - - - - - v
- * | | Sequence Check NL_CB_SEQ_CHECK()
- * | | |<- - - - - - - - - - - - - - -+
- * | | |
- * | | |- - - - - - - - - - - - - - - v [ NLM_F_ACK is set ]
- * | | | NL_CB_SEND_ACK()
- * | | |<- - - - - - - - - - - - - - -+
- * | | |
- * | | +-----+------+--------------+----------------+--------------+
- * | | v v v v v
- * | | Valid Message ACK NO-OP Message End of Multipart Error
- * | | | | | | |
- * | | v v v v v
- * | |NL_CB_VALID() NL_CB_ACK() NL_CB_SKIPPED() NL_CB_FINISH() cb->cb_err()
- * | | | | | | |
- * | | +------------+--------------+----------------+ v
- * | | | (FAILURE)
- * | | | [Callback returned NL_SKIP]
- * | | [More messages to be parsed] |<-----------
- * | +----------------------------------|
- * | |
- * | [is Multipart message] |
- * +-------------------------------------| [Callback returned NL_STOP]
- * |<-----------
- * v
- * (SUCCESS)
- *
- * At any time:
- * Message Format Error
- * |- - - - - - - - - - - - v
- * v NL_CB_INVALID()
- * (FAILURE)
- *
- * Message Overrun (Kernel Lost Data)
- * |- - - - - - - - - - - - v
- * v NL_CB_OVERRUN()
- * (FAILURE)
- *
- * Callback returned negative error code
- * (FAILURE)
- * @endcode
- *
- * @subsection send_semantics Sending Semantisc
- *
- * @code
- * nl_send_auto_complete(sk, msg)
- * | [Automatically completes netlink message header]
- * | [(local port, sequence number) ]
- * |
- * | [Application provies nl_send() replacement]
- * |- - - - - - - - - - - - - - - - - - - - v
- * v cb->cb_send_ow()
- * nl_send(sk, msg)
- * |
- * v
- * nl_send_iovec()
- * | [If available, add peer port and credentials]
- * v
- * nl_sendmsg(sk, msg, msghdr)
- * |- - - - - - - - - - - - - - - - - - - - v
- * | NL_CB_MSG_OUT()
- * |<- - - - - - - - - - - - - - - - - - - -+
- * v
- * sendmsg()
- * @endcode
- *
- * @section cb_doc Callback Configurations
- * Callbacks and overwriting capabilities are provided to control various
- * semantics of the library. All callback functions are packed together in
- * struct nl_cb which is attached to a netlink socket or passed on to
- * the respective functions directly.
- *
- * @subsection cb_ret_doc Callback Return Values
- * Callback functions can control the flow of the calling layer by returning
- * appropriate error codes:
- * @code
- * Action ID | Description
- * -----------------+-------------------------------------------------------
- * NL_OK | Proceed with whatever comes next.
- * NL_SKIP | Skip message currently being processed and continue
- * | with next message.
- * NL_STOP | Stop parsing and discard all remaining messages in
- * | this set of messages.
- * @endcode
- *
- * All callbacks are optional and a default action is performed if no
- * application specific implementation is provided:
- *
- * @code
- * Callback ID | Default Return Value
- * ------------------+----------------------
- * NL_CB_VALID | NL_OK
- * NL_CB_FINISH | NL_STOP
- * NL_CB_OVERRUN | NL_STOP
- * NL_CB_SKIPPED | NL_SKIP
- * NL_CB_ACK | NL_STOP
- * NL_CB_MSG_IN | NL_OK
- * NL_CB_MSG_OUT | NL_OK
- * NL_CB_INVALID | NL_STOP
- * NL_CB_SEQ_CHECK | NL_OK
- * NL_CB_SEND_ACK | NL_OK
- * |
- * Error Callback | NL_STOP
- * @endcode
- *
- * In order to simplify typical usages of the library, different sets of
- * default callback implementations exist:
- * @code
- * NL_CB_DEFAULT: No additional actions
- * NL_CB_VERBOSE: Automatically print warning and error messages to a file
- * descriptor as appropriate. This is useful for CLI based
- * applications.
- * NL_CB_DEBUG: Print informal debugging information for each message
- * received. This will result in every message beint sent or
- * received to be printed to the screen in a decoded,
- * human-readable format.
- * @endcode
- *
- * @par 1) Setting up a callback set
- * @code
- * // Allocate a callback set and initialize it to the verbose default set
- * struct nl_cb *cb = nl_cb_alloc(NL_CB_VERBOSE);
- *
- * // Modify the set to call my_func() for all valid messages
- * nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, my_func, NULL);
- *
- * // Set the error message handler to the verbose default implementation
- * // and direct it to print all errors to the given file descriptor.
- * FILE *file = fopen(...);
- * nl_cb_err(cb, NL_CB_VERBOSE, NULL, file);
- * @endcode
- *
- * @page route_doc Routing Family
- *
- * @page genl_doc Generic Netlink Family
- *
- * @page nf_doc Netfilter Subsystem
- */