initial libmnl import

This commit is contained in:
Pablo Neira Ayuso 2010-03-19 14:55:32 +01:00
commit 74e7bb8b03
20 changed files with 1635 additions and 0 deletions

7
Make_global.am Normal file
View File

@ -0,0 +1,7 @@
# This is _NOT_ the library release version, it's an API version.
# Please read Chapter 6 "Library interface versions" of the libtool
# documentation before making any modification
# http://sources.redhat.com/autobook/autobook/autobook_91.html
LIBVERSION=0:0:0
INCLUDES=$(all_includes) -I$(top_srcdir)/include

14
Makefile.am Normal file
View File

@ -0,0 +1,14 @@
include $(top_srcdir)/Make_global.am
AUTOMAKE_OPTIONS = foreign dist-bzip2 1.6
ACLOCAL_AMFLAGS = -I m4
SUBDIRS = src include examples
DIST_SUBDIRS = src include examples
pkgconfigdir = $(libdir)/pkgconfig
pkgconfig_DATA = libmnl.pc
$(OBJECTS): libtool
libtool: $(LIBTOOL_DEPS)
$(SHELL) ./config.status --recheck

9
README Normal file
View File

@ -0,0 +1,9 @@
libmnl
Features:
- Minimalistic Netlink library
- Low-level: you have to know how Netlink works.
- Simplicity: as opposed to complexity.
- Very low abstraction: try to leak as less Netlink details as possible.
- Decoupling: the main bricks are decoupled to avoid inter-dependencies
(eg. socket handling and callbacks are not attached).

53
autogen.sh Executable file
View File

@ -0,0 +1,53 @@
#!/bin/sh
include ()
{
# If we keep a copy of the kernel header in the SVN tree, we'll have
# to worry about synchronization issues forever. Instead, we just copy
# the headers that we need from the lastest kernel version at autogen
# stage.
INCLUDEDIR=${KERNEL_DIR:-/lib/modules/`uname -r`/build}/include/linux
if [ -f $INCLUDEDIR/netfilter/nfnetlink.h ]
then
TARGET=include/libnfnetlink/linux_nfnetlink.h
echo "Copying nfnetlink.h to linux_nfnetlink.h"
cp $INCLUDEDIR/netfilter/nfnetlink.h $TARGET
TMP=`mktemp`
sed 's/__be16/u_int16_t/g' $TARGET > $TMP
cp $TMP $TARGET
sed 's/#include <linux\/netfilter\/nfnetlink_compat\.h>/#include <libnfnetlink\/linux_nfnetlink_compat\.h>/g' $TARGET > $TMP
cp $TMP $TARGET
else
echo "can't find nfnetlink.h kernel file in $INCLUDEDIR"
exit 1
fi
if [ -f $INCLUDEDIR/netfilter/nfnetlink_compat.h ]
then
TARGET=include/libnfnetlink/linux_nfnetlink_compat.h
echo "Copying nfnetlink_compat.h to linux_nfnetlink_compat.h"
cp $INCLUDEDIR/netfilter/nfnetlink_compat.h $TARGET
else
echo "can't find nfnetlink.h kernel file in $INCLUDEDIR, ignoring"
fi
}
run ()
{
echo "running: $*"
eval $*
if test $? != 0 ; then
echo "error: while running '$*'"
exit 1
fi
}
[ "x$1" = "xdistrib" ] && include
run aclocal
#run autoheader
run libtoolize -f
run automake -a
run autoconf

18
configure.in Normal file
View File

@ -0,0 +1,18 @@
dnl Process this file with autoconf to create configure.
AC_INIT
AC_CANONICAL_SYSTEM
AC_CONFIG_MACRO_DIR([m4])
AM_INIT_AUTOMAKE(libmnl, 1.0.0-beta0)
AC_PROG_CC
AC_EXEEXT
AM_PROG_LIBTOOL
AC_SUBST(LIBTOOL_DEPS)
case $target in
*-*-linux*) ;;
*) AC_MSG_ERROR([Linux only, dude!]);;
esac
AC_OUTPUT(Makefile src/Makefile include/Makefile include/libmnl/Makefile examples/Makefile libmnl.pc)

24
examples/Makefile.am Normal file
View File

@ -0,0 +1,24 @@
include $(top_srcdir)/Make_global.am
check_PROGRAMS = rtnl-link-dump rtnl-link-event rtnl-link-set \
rtnl-route-dump genl-family-get
rtnl_link_dump_SOURCES = rtnl-link-dump.c
rtnl_link_dump_LDADD = ../src/libmnl.la
rtnl_link_dump_LDFLAGS = -dynamic -ldl
rtnl_link_event_SOURCES = rtnl-link-event.c
rtnl_link_event_LDADD = ../src/libmnl.la
rtnl_link_event_LDFLAGS = -dynamic -ldl
rtnl_link_set_SOURCES = rtnl-link-set.c
rtnl_link_set_LDADD = ../src/libmnl.la
rtnl_link_set_LDFLAGS = -dynamic -ldl
rtnl_route_dump_SOURCES = rtnl-route-dump.c
rtnl_route_dump_LDADD = ../src/libmnl.la
rtnl_route_dump_LDFLAGS = -dynamic -ldl
genl_family_get_SOURCES = genl-family-get.c
genl_family_get_LDADD = ../src/libmnl.la
genl_family_get_LDFLAGS = -dynamic -ldl

143
examples/genl-family-get.c Normal file
View File

@ -0,0 +1,143 @@
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <libmnl/libmnl.h>
#include <linux/genetlink.h>
static void parse_genl_mc_grps(struct nlattr *nested)
{
struct nlattr *pos;
int len;
mnl_attr_for_each_nested(pos, nested, len) {
struct nlattr *tb[CTRL_ATTR_MCAST_GRP_MAX+1];
mnl_attr_parse_nested(pos, tb, CTRL_ATTR_MCAST_GRP_MAX);
if (tb[CTRL_ATTR_MCAST_GRP_ID]) {
printf("id-0x%x ",
mnl_attr_get_u32(tb[CTRL_ATTR_MCAST_GRP_ID]));
}
if (tb[CTRL_ATTR_MCAST_GRP_NAME]) {
printf("name: %s ",
mnl_attr_get_str(tb[CTRL_ATTR_MCAST_GRP_NAME]));
}
printf("\n");
}
}
static void parse_genl_family_ops(struct nlattr *nested)
{
struct nlattr *pos;
int len;
mnl_attr_for_each_nested(pos, nested, len) {
struct nlattr *tb[CTRL_ATTR_OP_MAX+1];
mnl_attr_parse_nested(pos, tb, CTRL_ATTR_OP_MAX);
if (tb[CTRL_ATTR_OP_ID]) {
printf("id-0x%x ",
mnl_attr_get_u32(tb[CTRL_ATTR_OP_ID]));
}
if (tb[CTRL_ATTR_OP_MAX]) {
printf("flags ");
}
printf("\n");
}
}
static int data_cb(const struct nlmsghdr *nlh, void *data)
{
struct nlattr *tb[CTRL_ATTR_MAX+1];
struct genlmsghdr *genl = mnl_nlmsg_get_data(nlh);
mnl_attr_parse_at_offset(nlh, sizeof(*genl), tb, CTRL_ATTR_MAX);
if (tb[CTRL_ATTR_FAMILY_NAME]) {
printf("name=%s\t",
mnl_attr_get_str(tb[CTRL_ATTR_FAMILY_NAME]));
}
if (tb[CTRL_ATTR_FAMILY_ID]) {
printf("id=%u\t",
mnl_attr_get_u16(tb[CTRL_ATTR_FAMILY_ID]));
}
if (tb[CTRL_ATTR_VERSION]) {
printf("version=%u\t",
mnl_attr_get_u32(tb[CTRL_ATTR_VERSION]));
}
if (tb[CTRL_ATTR_HDRSIZE]) {
printf("hdrsize=%u\t",
mnl_attr_get_u32(tb[CTRL_ATTR_HDRSIZE]));
}
if (tb[CTRL_ATTR_MAXATTR]) {
printf("maxattr=%u\t",
mnl_attr_get_u32(tb[CTRL_ATTR_MAXATTR]));
}
if (tb[CTRL_ATTR_OPS]) {
printf("\nops:\n");
parse_genl_family_ops(tb[CTRL_ATTR_OPS]);
}
if (tb[CTRL_ATTR_MCAST_GROUPS]) {
printf("\ngrps:\n");
parse_genl_mc_grps(tb[CTRL_ATTR_MCAST_GROUPS]);
}
return MNL_CB_OK;
}
int main(int argc, char *argv[])
{
struct mnl_socket *nl;
char buf[getpagesize()];
struct nlmsghdr *nlh;
struct genlmsghdr *genl;
int ret;
unsigned int seq;
if (argc != 2) {
printf("%s [family name]\n", argv[0]);
exit(EXIT_FAILURE);
}
nlh = mnl_nlmsg_put_header(buf);
nlh->nlmsg_type = GENL_ID_CTRL;
nlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
nlh->nlmsg_seq = seq = time(NULL);
genl = mnl_nlmsg_put_extra_header(nlh, sizeof(struct genlmsghdr));
genl->cmd = CTRL_CMD_GETFAMILY;
genl->version = 1;
mnl_attr_put_u32(nlh, CTRL_ATTR_FAMILY_ID, GENL_ID_CTRL);
mnl_attr_put_str_null(nlh, CTRL_ATTR_FAMILY_NAME, argv[1]);
nl = mnl_socket_open(NETLINK_GENERIC);
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);
}
if (mnl_socket_sendto(nl, nlh, mnl_nlmsg_get_len(nlh)) < 0) {
perror("mnl_socket_send");
exit(EXIT_FAILURE);
}
ret = mnl_socket_recvfrom(nl, buf, sizeof(buf));
while (ret > 0) {
ret = mnl_cb_run(buf, ret, seq, data_cb, NULL);
if (ret <= 0)
break;
ret = mnl_socket_recvfrom(nl, buf, sizeof(buf));
}
if (ret == -1) {
perror("error");
exit(EXIT_FAILURE);
}
mnl_socket_close(nl);
return 0;
}

84
examples/rtnl-link-dump.c Normal file
View File

@ -0,0 +1,84 @@
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <libmnl/libmnl.h>
#include <linux/if.h>
#include <linux/if_link.h>
#include <linux/rtnetlink.h>
static int data_cb(const struct nlmsghdr *nlh, void *data)
{
struct nlattr *tb[IFLA_MAX+1];
struct ifinfomsg *ifm = mnl_nlmsg_get_data(nlh);
int len = mnl_nlmsg_get_len(nlh);
struct nlattr *attr;
printf("index=%d type=%d flags=%d family=%d ",
ifm->ifi_index, ifm->ifi_type,
ifm->ifi_flags, ifm->ifi_family);
if (ifm->ifi_flags & IFF_RUNNING)
printf("[RUNNING] ");
else
printf("[NOT RUNNING] ");
mnl_attr_parse_at_offset(nlh, sizeof(*ifm), tb, IFLA_MAX);
if (tb[IFLA_MTU]) {
printf("mtu=%d ", mnl_attr_get_u32(tb[IFLA_MTU]));
}
if (tb[IFLA_IFNAME]) {
printf("name=%s", mnl_attr_get_str(tb[IFLA_IFNAME]));
}
printf("\n");
return MNL_CB_OK;
}
int main()
{
struct mnl_socket *nl;
char buf[getpagesize()];
struct nlmsghdr *nlh;
struct rtgenmsg *rt;
int ret;
unsigned int seq;
nlh = mnl_nlmsg_put_header(buf);
nlh->nlmsg_type = RTM_GETLINK;
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));
rt->rtgen_family = AF_PACKET;
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);
}
if (mnl_socket_sendto(nl, nlh, mnl_nlmsg_get_len(nlh)) < 0) {
perror("mnl_socket_send");
exit(EXIT_FAILURE);
}
ret = mnl_socket_recvfrom(nl, buf, sizeof(buf));
while (ret > 0) {
ret = mnl_cb_run(buf, ret, seq, data_cb, NULL);
if (ret <= MNL_CB_STOP)
break;
ret = mnl_socket_recvfrom(nl, buf, sizeof(buf));
}
if (ret == -1) {
perror("error");
exit(EXIT_FAILURE);
}
mnl_socket_close(nl);
return 0;
}

View File

@ -0,0 +1,70 @@
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <libmnl/libmnl.h>
#include <linux/if.h>
#include <linux/if_link.h>
#include <linux/rtnetlink.h>
static int data_cb(const struct nlmsghdr *nlh, void *data)
{
struct nlattr *tb[IFLA_MAX+1];
struct ifinfomsg *ifm = mnl_nlmsg_get_data(nlh);
int len = mnl_nlmsg_get_len(nlh);
struct nlattr *attr;
printf("index=%d type=%d flags=%d family=%d ",
ifm->ifi_index, ifm->ifi_type,
ifm->ifi_flags, ifm->ifi_family);
if (ifm->ifi_flags & IFF_RUNNING)
printf("[RUNNING] ");
else
printf("[NOT RUNNING] ");
mnl_attr_parse_at_offset(nlh, sizeof(*ifm), tb, IFLA_MAX);
if (tb[IFLA_MTU]) {
printf("mtu=%d ", mnl_attr_get_u32(tb[IFLA_MTU]));
}
if (tb[IFLA_IFNAME]) {
printf("name=%s", mnl_attr_get_str(tb[IFLA_IFNAME]));
}
printf("\n");
return MNL_CB_OK;
}
int main()
{
struct mnl_socket *nl;
char buf[getpagesize()];
struct nlmsghdr *nlh = (struct nlmsghdr *) buf;
int ret;
nl = mnl_socket_open(NETLINK_ROUTE);
if (nl == NULL) {
perror("mnl_socket_open");
exit(EXIT_FAILURE);
}
if (mnl_socket_bind(nl, RTMGRP_LINK, MNL_SOCKET_AUTOPID) < 0) {
perror("mnl_socket_bind");
exit(EXIT_FAILURE);
}
ret = mnl_socket_recvfrom(nl, buf, sizeof(buf));
while (ret > 0) {
ret = mnl_cb_run(buf, ret, 0, data_cb, NULL);
if (ret <= 0)
break;
ret = mnl_socket_recvfrom(nl, buf, sizeof(buf));
}
if (ret == -1) {
perror("error");
exit(EXIT_FAILURE);
}
mnl_socket_close(nl);
return 0;
}

76
examples/rtnl-link-set.c Normal file
View File

@ -0,0 +1,76 @@
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <libmnl/libmnl.h>
#include <linux/if.h>
#include <linux/if_link.h>
#include <linux/rtnetlink.h>
int main(int argc, char *argv[])
{
struct mnl_socket *nl;
char buf[getpagesize()];
struct nlmsghdr *nlh;
struct ifinfomsg *ifm;
int ret;
unsigned int seq, oper;
if (argc != 3) {
printf("Usage: %s [ifname] [up|down]\n", argv[0]);
exit(EXIT_FAILURE);
}
if (strncasecmp(argv[2], "up") == 0)
oper = IF_OPER_UP;
else if (strncasecmp(argv[2], "down") == 0)
oper = IF_OPER_DOWN;
else {
fprintf(stderr, "%s is not `up' nor `down'\n", argv[2]);
exit(EXIT_FAILURE);
}
nlh = mnl_nlmsg_put_header(buf);
nlh->nlmsg_type = RTM_SETLINK;
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_PACKET;
mnl_attr_put_u8(nlh, IFLA_OPERSTATE, oper);
mnl_attr_put_str(nlh, IFLA_IFNAME, argv[1]);
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);
}
mnl_nlmsg_print(nlh);
if (mnl_socket_sendto(nl, nlh, mnl_nlmsg_get_len(nlh)) < 0) {
perror("mnl_socket_send");
exit(EXIT_FAILURE);
}
ret = mnl_socket_recvfrom(nl, buf, sizeof(buf));
if (ret == -1) {
perror("read");
exit(EXIT_FAILURE);
}
ret = mnl_cb_run(buf, ret, seq, NULL, NULL);
if (ret == -1){
perror("callback");
exit(EXIT_FAILURE);
}
mnl_socket_close(nl);
return 0;
}

192
examples/rtnl-route-dump.c Normal file
View File

@ -0,0 +1,192 @@
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <libmnl/libmnl.h>
#include <linux/if.h>
#include <linux/if_link.h>
#include <linux/rtnetlink.h>
static void attributes_show_ipv4(struct nlattr *tb[])
{
if (tb[RTA_TABLE]) {
printf("table=%u ", mnl_attr_get_u32(tb[RTA_TABLE]));
}
if (tb[RTA_DST]) {
printf("dst=%s ", inet_ntoa(mnl_attr_get_u32(tb[RTA_DST])));
}
if (tb[RTA_SRC]) {
printf("src=%s ", inet_ntoa(mnl_attr_get_u32(tb[RTA_SRC])));
}
if (tb[RTA_OIF]) {
printf("oif=%u ", mnl_attr_get_u32(tb[RTA_OIF]));
}
if (tb[RTA_FLOW]) {
printf("flow=%u ", mnl_attr_get_u32(tb[RTA_FLOW]));
}
if (tb[RTA_PREFSRC]) {
printf("prefsrc=%s ",
inet_ntoa(mnl_attr_get_u32(tb[RTA_PREFSRC])));
}
if (tb[RTA_GATEWAY]) {
printf("gw=%s ", inet_ntoa(mnl_attr_get_u32(tb[RTA_GATEWAY])));
}
if (tb[RTA_METRICS]) {
int i;
struct nlattr *tbx[RTAX_MAX+1] = {};
mnl_attr_parse_nested(tb[RTA_METRICS], tbx, RTAX_MAX);
for (i=0; i<RTAX_MAX; i++) {
if (tbx[i]) {
printf("metrics[%d]=%u ",
mnl_attr_get_u32(tbx[i]));
}
}
}
printf("\n");
}
static int data_cb(const struct nlmsghdr *nlh, void *data)
{
/* parse() ya está inicializando este array, qué hacer ? */
struct nlattr *tb[RTA_MAX+1] = {};
struct rtmsg *rm = mnl_nlmsg_get_data(nlh);
int len = mnl_nlmsg_get_len(nlh);
struct nlattr *attr;
/* protocol family = AF_INET | AF_INET6 */
printf("family=%u ", rm->rtm_family);
/* destination CIDR, eg. 24 or 32 for IPv4 */
printf("dst_len=%u ", rm->rtm_dst_len);
/* source CIDR */
printf("src_len=%u ", rm->rtm_src_len);
/* type of service (TOS), eg. 0 */
printf("tos=%u ", rm->rtm_tos);
/* table id:
* RT_TABLE_UNSPEC = 0
*
* ... user defined values ...
*
* RT_TABLE_COMPAT = 252
* RT_TABLE_DEFAULT = 253
* RT_TABLE_MAIN = 254
* RT_TABLE_LOCAL = 255
* RT_TABLE_MAX = 0xFFFFFFFF
*
* Synonimous attribute: RTA_TABLE.
*/
printf("table=%u ", rm->rtm_table);
/* type:
* RTN_UNSPEC = 0
* RTN_UNICAST = 1
* RTN_LOCAL = 2
* RTN_BROADCAST = 3
* RTN_ANYCAST = 4
* RTN_MULTICAST = 5
* RTN_BLACKHOLE = 6
* RTN_UNREACHABLE = 7
* RTN_PROHIBIT = 8
* RTN_THROW = 9
* RTN_NAT = 10
* RTN_XRESOLVE = 11
* __RTN_MAX = 12
*/
printf("type=%u ", rm->rtm_type);
/* scope:
* RT_SCOPE_UNIVERSE = 0 : everywhere in the universe
*
* ... user defined values ...
*
* RT_SCOPE_SITE = 200
* RT_SCOPE_LINK = 253 : destination attached to link
* RT_SCOPE_HOST = 254 : local address
* RT_SCOPE_NOWHERE = 255 : not existing destination
*/
printf("scope=%u ", rm->rtm_scope);
/* protocol:
* RTPROT_UNSPEC = 0
* RTPROT_REDIRECT = 1
* RTPROT_KERNEL = 2 : route installed by kernel
* RTPROT_BOOT = 3 : route installed during boot
* RTPROT_STATIC = 4 : route installed by administrator
*
* Values >= RTPROT_STATIC are not interpreted by kernel, they are
* just user-defined.
*/
printf("proto=%u ", rm->rtm_protocol);
/* flags:
* RTM_F_NOTIFY = 0x100: notify user of route change
* RTM_F_CLONED = 0x200: this route is cloned
* RTM_F_EQUALIZE = 0x400: Multipath equalizer: NI
* RTM_F_PREFIX = 0x800: Prefix addresses
*/
printf("flags=%x\n", rm->rtm_flags);
mnl_attr_parse_at_offset(nlh, sizeof(*rm), tb, RTA_MAX);
switch(rm->rtm_family) {
case AF_INET:
attributes_show_ipv4(tb);
break;
}
return MNL_CB_OK;
}
int main()
{
struct mnl_socket *nl;
char buf[getpagesize()];
struct nlmsghdr *nlh;
struct rtmsg *rtm;
int ret;
unsigned int seq;
nlh = mnl_nlmsg_put_header(buf);
nlh->nlmsg_type = RTM_GETROUTE;
nlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP;
nlh->nlmsg_seq = seq = time(NULL);
rtm = mnl_nlmsg_put_extra_header(nlh, sizeof(struct rtmsg));
rtm->rtm_family = AF_INET;
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);
}
if (mnl_socket_sendto(nl, nlh, mnl_nlmsg_get_len(nlh)) < 0) {
perror("mnl_socket_send");
exit(EXIT_FAILURE);
}
ret = mnl_socket_recvfrom(nl, buf, sizeof(buf));
while (ret > 0) {
ret = mnl_cb_run(buf, ret, 0, data_cb, NULL);
if (ret <= MNL_CB_STOP)
break;
ret = mnl_socket_recvfrom(nl, buf, sizeof(buf));
}
if (ret == -1) {
perror("error");
exit(EXIT_FAILURE);
}
mnl_socket_close(nl);
return 0;
}

1
include/Makefile.am Normal file
View File

@ -0,0 +1 @@
SUBDIRS = libmnl

View File

@ -0,0 +1 @@
pkginclude_HEADERS = libmnl.h

120
include/libmnl/libmnl.h Normal file
View File

@ -0,0 +1,120 @@
#ifndef _LIBMNL_H_
#define _LIBMNL_H_
#include <sys/socket.h> /* for sa_family_t */
#include <linux/netlink.h>
/*
* generic netlink socket API
*/
#define MNL_SOCKET_AUTOPID 0
struct mnl_socket;
extern struct mnl_socket *mnl_socket_open(int type);
extern int mnl_socket_bind(struct mnl_socket *nl, int groups, int pid);
extern int mnl_socket_close(struct mnl_socket *nl);
extern int mnl_socket_get_fd(const struct mnl_socket *nl);
extern unsigned int mnl_socket_get_portid(const struct mnl_socket *nl);
extern int mnl_socket_sendto(struct mnl_socket *nl, const void *req, int siz);
extern int mnl_socket_sendmsg(struct mnl_socket *nl, struct msghdr *msg, int flags);
extern int mnl_socket_recvfrom(struct mnl_socket *nl, void *buf, int siz);
extern int mnl_socket_recvmsg(const struct mnl_socket *nl, struct msghdr *msg, int flags);
extern int mnl_socket_setsockopt(struct mnl_socket *nl, int type, void *buf, socklen_t len);
extern int mnl_socket_getsockopt(struct mnl_socket *nl, int type, void *buf, socklen_t *len);
/*
* generic netlink message API
*/
#define MNL_ALIGNTO 4
#define MNL_NLMSG_HDRLEN mnl_align(sizeof(struct nlmsghdr))
extern int mnl_align(int len);
extern size_t mnl_nlmsg_size(int len);
extern size_t mnl_nlmsg_total_size(int len);
extern size_t mnl_nlmsg_payload_size(const struct nlmsghdr *nlh);
/* Netlink message header builder */
extern struct nlmsghdr *mnl_nlmsg_put_header(void *buf);
extern void *mnl_nlmsg_put_extra_header(struct nlmsghdr *nlh, int size);
/* Netlink message iterators */
extern int mnl_nlmsg_ok(const struct nlmsghdr *nlh, int len);
extern struct nlmsghdr *mnl_nlmsg_next(const struct nlmsghdr *nlh, int *len);
/* Netlink sequence tracking */
extern int mnl_nlmsg_seq_ok(const struct nlmsghdr *nlh, unsigned int seq);
/* Netlink header getters */
extern u_int16_t mnl_nlmsg_get_len(const struct nlmsghdr *nlh);
extern void *mnl_nlmsg_get_data(const struct nlmsghdr *nlh);
extern void *mnl_nlmsg_get_data_offset(const struct nlmsghdr *nlh, int offset);
extern void *mnl_nlmsg_get_tail(const struct nlmsghdr *nlh);
/* Netlink dump message */
extern void mnl_nlmsg_print(const struct nlmsghdr *nlh);
/*
* generic netlink attributes API
*/
#define MNL_ATTR_HDRLEN mnl_align(sizeof(struct nlattr))
/* TLV attribute getters */
extern u_int16_t mnl_attr_get_type(const struct nlattr *attr);
extern u_int16_t mnl_attr_get_len(const struct nlattr *attr);
extern u_int16_t mnl_attr_get_payload_len(const struct nlattr *attr);
extern void *mnl_attr_get_data(const struct nlattr *attr);
extern u_int8_t mnl_attr_get_u8(const struct nlattr *attr);
extern u_int16_t mnl_attr_get_u16(const struct nlattr *attr);
extern u_int32_t mnl_attr_get_u32(const struct nlattr *attr);
extern u_int64_t mnl_attr_get_u64(const struct nlattr *attr);
extern const char *mnl_attr_get_str(const struct nlattr *attr);
/* TLV attribute putters */
extern void mnl_attr_put(struct nlmsghdr *nlh, int type, size_t len, const void *data);
extern void mnl_attr_put_u8(struct nlmsghdr *nlh, int type, u_int8_t data);
extern void mnl_attr_put_u16(struct nlmsghdr *nlh, int type, u_int16_t data);
extern void mnl_attr_put_u32(struct nlmsghdr *nlh, int type, u_int32_t data);
extern void mnl_attr_put_u64(struct nlmsghdr *nlh, int type, u_int64_t data);
extern void mnl_attr_put_str(struct nlmsghdr *nlh, int type, const void *data);
extern void mnl_attr_put_str_null(struct nlmsghdr *nlh, int type, const void *data);
/* TLV attribute parsers */
extern int mnl_attr_parse(const struct nlmsghdr *nlh, struct nlattr *tb[], int max);
extern int mnl_attr_parse_at_offset(const struct nlmsghdr *nlh, int offset, struct nlattr *tb[], int max);
extern int mnl_attr_parse_nested(const struct nlattr *attr, struct nlattr *tb[], int max);
extern int mnl_attr_ok(const struct nlattr *attr, int len);
extern struct nlattr *mnl_attr_next(const struct nlattr *attr, int *len);
#define mnl_attr_for_each_nested(pos, head, len) \
for (pos = mnl_attr_get_data(head), len = mnl_attr_get_len(head); \
mnl_attr_ok(pos, len); \
pos = mnl_attr_next(pos, &(len)))
/*
* callback API
*/
#define MNL_CB_ERROR -1
#define MNL_CB_STOP 0
#define MNL_CB_OK 1
typedef int (*mnl_cb_t)(const struct nlmsghdr *nlh, void *data);
extern int mnl_cb_run(const char *buf, int numbytes, unsigned int seq,
mnl_cb_t cb_data, void *data);
extern int mnl_cb_run2(const char *buf, int numbytes, unsigned int seq,
mnl_cb_t cb_data, void *data,
mnl_cb_t *cb_ctl_array, int cb_ctl_array_len);
/*
* other declarations
*/
#ifndef SOL_NETLINK
#define SOL_NETLINK 270
#endif
#endif

15
libmnl.pc.in Normal file
View File

@ -0,0 +1,15 @@
# libmnl pkg-config file
prefix=@prefix@
exec_prefix=@exec_prefix@
libdir=@libdir@
includedir=@includedir@
Name: libmnl
Description: Minimalistic Netlink communication library
URL: http://netfilter.org/projects/libmnl/
Version: @VERSION@
Requires:
Conflicts:
Libs: -L${libdir} -lmnl
Cflags: -I${includedir}

9
src/Makefile.am Normal file
View File

@ -0,0 +1,9 @@
include $(top_srcdir)/Make_global.am
AM_CFLAGS=-fPIC -Wall
LIBS=
lib_LTLIBRARIES = libmnl.la
libmnl_la_LDFLAGS = -Wc,-nostartfiles -version-info $(LIBVERSION)
libmnl_la_SOURCES = socket.c callback.c msg.c attr.c

212
src/attr.c Normal file
View File

@ -0,0 +1,212 @@
/*
* (C) 2008-2010 by Pablo Neira Ayuso <pablo@netfilter.org>
*
* This software may be used and distributed according to the terms
* of the GNU General Public License, incorporated herein by reference.
*/
#include <libmnl/libmnl.h>
#include <string.h>
/**
* Netlink attribute:
*
* |<-- 2 bytes -->|<-- 2 bytes -->|<-- variable -->|
* -------------------------------------------------
* | length | type | value |
* -------------------------------------------------
*/
/**
* mnl_attr_get_type - get the attribute type of a netlink message
*
* This function returns the attribute type.
*/
u_int16_t mnl_attr_get_type(const struct nlattr *attr)
{
return attr->nla_type & NLA_TYPE_MASK;
}
/**
* mnl_attr_get_len - get the attribute length
*
* This function returns the attribute length.
*/
u_int16_t mnl_attr_get_len(const struct nlattr *attr)
{
return attr->nla_len;
}
/**
* mnl_attr_get_payload_len - get the attribute payload length
*
* This function returns the attribute payload length.
*/
u_int16_t mnl_attr_get_payload_len(const struct nlattr *attr)
{
return attr->nla_len - MNL_ATTR_HDRLEN;
}
/**
* mnl_attr_get_data - get pointer to the attribute payload
*
* This function return a pointer to the attribute payload
*/
void *mnl_attr_get_data(const struct nlattr *attr)
{
return (void *)attr + MNL_ATTR_HDRLEN;
}
/**
* mnl_attr_ok - check a there is room for an attribute
* @nlh: attribute that we want to check
* @len: remaining bytes in a buffer that contains the attribute
*
* This function is used to check that a buffer that contains an attribute
* has enough room for the attribute that it stores, ie. this function can
* be used to verify that an attribute is not malformed nor truncated.
*/
int mnl_attr_ok(const struct nlattr *attr, int len)
{
return len >= sizeof(struct nlattr) &&
attr->nla_len >= sizeof(struct nlattr) &&
attr->nla_len <= len;
}
/**
* mnl_attr_next - get the next attribute in the payload of a netlink message
* @attr: pointer to the current attribute
* @len: pointer to the current remaining bytes in the buffer
*
* This function returns a pointer to the next attribute that is in the
* payload of a netlink message.
*/
struct nlattr *mnl_attr_next(const struct nlattr *attr, int *len)
{
*len -= mnl_align(attr->nla_len);
return (struct nlattr *)((void *)attr + mnl_align(attr->nla_len));
}
/**
* mnl_attr_parse - returns an array with the attributes in a message
* @tb: array of pointers to the attribute found
* @tb_size: size of the attribute array
* @attr: first attribute in the stream
* @len: remaining bytes in the buffer that contain attributes
*
* This function returns a table of pointers to the attributes that has been
* found in a netlink payload. This function return 0 on sucess, and >0 to
* indicate the number of bytes the remaining bytes.
*/
int mnl_attr_parse_at_offset(const struct nlmsghdr *nlh, int offset,
struct nlattr *tb[], int max)
{
struct nlattr *attr = mnl_nlmsg_get_data_offset(nlh, offset);
int len = mnl_nlmsg_get_len(nlh);
memset(tb, 0, sizeof(struct nlattr *) * (max + 1));
while (mnl_attr_ok(attr, len)) {
if (mnl_attr_get_type(attr) <= max)
tb[mnl_attr_get_type(attr)] = attr;
attr = mnl_attr_next(attr, &len);
}
return len;
}
int mnl_attr_parse(const struct nlmsghdr *nlh, struct nlattr *tb[], int max)
{
return mnl_attr_parse_at_offset(nlh, 0, tb, max);
}
int mnl_attr_parse_nested(const struct nlattr *nested,
struct nlattr *tb[], int max)
{
struct nlattr *attr = mnl_attr_get_data(nested);
int len = mnl_attr_get_payload_len(nested);
memset(tb, 0, sizeof(struct nlattr *) * (max + 1));
while (mnl_attr_ok(attr, len)) {
if (mnl_attr_get_type(attr) <= max)
tb[mnl_attr_get_type(attr)] = attr;
attr = mnl_attr_next(attr, &len);
}
return len;
}
u_int8_t mnl_attr_get_u8(const struct nlattr *attr)
{
return *((u_int8_t *)mnl_attr_get_data(attr));
}
u_int16_t mnl_attr_get_u16(const struct nlattr *attr)
{
return *((u_int16_t *)mnl_attr_get_data(attr));
}
u_int32_t mnl_attr_get_u32(const struct nlattr *attr)
{
return *((u_int32_t *)mnl_attr_get_data(attr));
}
/**
* mnl_attr_get_u64 - returns an arra
* @attr: netlink attribute
*
* This function returns the payload of a 64-bits attribute. This function
* is align-safe since accessing 64-bits Netlink attributes is a common
* source of alignment issues.
*/
u_int64_t mnl_attr_get_u64(const struct nlattr *attr)
{
u_int64_t tmp;
memcpy(&tmp, mnl_attr_get_data(attr), sizeof(tmp));
return tmp;
}
const char *mnl_attr_get_str(const struct nlattr *attr)
{
return (const char *)mnl_attr_get_data(attr);
}
void mnl_attr_put(struct nlmsghdr *nlh, int type, size_t len, const void *data)
{
struct nlattr *attr = mnl_nlmsg_get_tail(nlh);
int payload_len = mnl_align(sizeof(struct nlattr)) + len;
attr->nla_type = type;
attr->nla_len = payload_len;
memcpy(mnl_attr_get_data(attr), data, len);
nlh->nlmsg_len += mnl_align(payload_len);
}
void mnl_attr_put_u8(struct nlmsghdr *nlh, int type, u_int8_t data)
{
mnl_attr_put(nlh, type, sizeof(u_int8_t), &data);
}
void mnl_attr_put_u16(struct nlmsghdr *nlh, int type, u_int16_t data)
{
mnl_attr_put(nlh, type, sizeof(u_int16_t), &data);
}
void mnl_attr_put_u32(struct nlmsghdr *nlh, int type, u_int32_t data)
{
mnl_attr_put(nlh, type, sizeof(u_int32_t), &data);
}
void mnl_attr_put_u64(struct nlmsghdr *nlh, int type, u_int64_t data)
{
mnl_attr_put(nlh, type, sizeof(u_int64_t), &data);
}
void mnl_attr_put_str(struct nlmsghdr *nlh, int type, const void *data)
{
mnl_attr_put(nlh, type, strlen(data), data);
}
void mnl_attr_put_str_null(struct nlmsghdr *nlh, int type, const void *data)
{
mnl_attr_put(nlh, type, strlen(data)+1, data);
}

119
src/callback.c Normal file
View File

@ -0,0 +1,119 @@
/*
* (C) 2008-2010 by Pablo Neira Ayuso <pablo@netfilter.org>
*
* This software may be used and distributed according to the terms
* of the GNU General Public License, incorporated herein by reference.
*/
#include <errno.h>
#include <libmnl/libmnl.h>
static int mnl_cb_noop(const struct nlmsghdr *nlh, void *data)
{
return MNL_CB_OK;
}
static int mnl_cb_error(const struct nlmsghdr *nlh, void *data)
{
const struct nlmsgerr *err = mnl_nlmsg_get_data(nlh);
if (nlh->nlmsg_len < mnl_nlmsg_size(sizeof(struct nlmsgerr))) {
errno = EBADMSG;
return MNL_CB_ERROR;
}
/* Netlink subsystems returns the errno value with different signess */
if (err->error < 0)
errno = -err->error;
else
errno = err->error;
return err->error == 0 ? MNL_CB_STOP : MNL_CB_ERROR;
}
static int mnl_cb_stop(const struct nlmsghdr *nlh, void *data)
{
return MNL_CB_STOP;
}
static mnl_cb_t default_cb_array[NLMSG_MIN_TYPE] = {
[NLMSG_NOOP] = mnl_cb_noop,
[NLMSG_ERROR] = mnl_cb_error,
[NLMSG_DONE] = mnl_cb_stop,
[NLMSG_OVERRUN] = mnl_cb_noop,
};
/**
* mnl_cb_run2 - callback runqueue for netlink messages
* @buf: buffer that contains the netlink messages
* @numbytes: number of bytes stored in the buffer
* @seq: sequence number that we expect to receive (use zero to skip)
* @cb_data: callback handler for data messages
* @data: pointer to data that will be passed to the data callback handler
* @cb_ctl_array: array of custom callback handlers from control messages
* @cb_ctl_array_len: length of the array of custom control callback handlers
*
* You can set the cb_ctl_array to NULL if you want to use the default control
* callback handlers, in that case, the parameter cb_ctl_array_len is not
* checked.
*
* This function returns -1 in case of error, 0 if we have received a
* NLMSG_DONE message or the callback has explicitly returned MNL_CB_STOP.
*/
int mnl_cb_run2(const char *buf, int numbytes, unsigned int seq,
mnl_cb_t cb_data, void *data,
mnl_cb_t *cb_ctl_array, int cb_ctl_array_len)
{
int ret = MNL_CB_OK;
struct nlmsghdr *nlh = (struct nlmsghdr *)buf;
while (mnl_nlmsg_ok(nlh, numbytes)) {
/* perform sequence tracking */
if (!mnl_nlmsg_seq_ok(nlh, seq)) {
errno = EILSEQ;
return -1;
}
/* netlink data message handling */
if (nlh->nlmsg_type >= NLMSG_MIN_TYPE) {
if (cb_data){
ret = cb_data(nlh, data);
if (ret <= MNL_CB_STOP)
goto out;
}
} else if (nlh->nlmsg_type < cb_ctl_array_len) {
if (cb_ctl_array && cb_ctl_array[nlh->nlmsg_type]) {
ret = cb_ctl_array[nlh->nlmsg_type](nlh, data);
if (ret <= MNL_CB_STOP)
goto out;
}
} else if (default_cb_array[nlh->nlmsg_type]) {
ret = default_cb_array[nlh->nlmsg_type](nlh, data);
if (ret <= MNL_CB_STOP)
goto out;
}
nlh = mnl_nlmsg_next(nlh, &numbytes);
}
out:
return ret <= MNL_CB_ERROR ? -1 : 0;
}
/**
* mnl_cb_run - callback runqueue for netlink messages (simplified version)
* @buf: buffer that contains the netlink messages
* @numbytes: number of bytes stored in the buffer
* @seq: sequence number that we expect to receive (use zero to skip)
* @cb_data: callback handler for data messages
* @data: pointer to data that will be passed to the data callback handler
*
* This function is like mnl_cb_run2() but it does not allow you to set
* the control callback handlers.
*
* This function returns -1 in case of error, 0 if we have received a
* NLMSG_DONE message or the callback has explicitly returned MNL_CB_STOP.
*/
int mnl_cb_run(const char *buf, int numbytes, unsigned int seq,
mnl_cb_t cb_data, void *data)
{
return mnl_cb_run2(buf, numbytes, seq, cb_data, data, NULL, 0);
}

213
src/msg.c Normal file
View File

@ -0,0 +1,213 @@
/*
* (C) 2008-2010 by Pablo Neira Ayuso <pablo@netfilter.org>
*
* This software may be used and distributed according to the terms
* of the GNU General Public License, incorporated herein by reference.
*/
#include <stdio.h>
#include <ctype.h>
#include <errno.h>
#include <string.h>
#include <libmnl/libmnl.h>
/**
* mnl_align - align a value to four bytes
* @value: the value that we want to get aligned
*
* This function returns the value passed aligned to four bytes. Netlink
* message headers and its attributes are always aligned to four bytes.
*/
int mnl_align(int value)
{
return (value + MNL_ALIGNTO - 1) & ~(MNL_ALIGNTO - 1);
}
/**
* mnl_nlmsg_size - get size of the netlink messages (without alignment)
* @len: length of the netlink message
*
* This function returns the size of a netlink message (header plus payload)
* without alignment.
*/
size_t mnl_nlmsg_size(int len)
{
return len + mnl_align(MNL_NLMSG_HDRLEN);
}
/**
* mnl_nlmsg_aligned_size - get size of the netlink messages (with alignment)
* @len: length of the netlink message
*
* This function returns the size of a netlink message (header plus payload)
* with alignment.
*/
size_t mnl_nlmsg_aligned_size(int len)
{
return mnl_align(mnl_nlmsg_size(len));
}
/**
* mnl_nlmsg_payload_size - get the size of the payload
* @nlh: pointer to the header of the netlink message
*
* This function returns the size of the netlink payload
*/
size_t mnl_nlmsg_payload_size(const struct nlmsghdr *nlh)
{
return nlh->nlmsg_len - MNL_NLMSG_HDRLEN;
}
/**
* mnl_nlmsg_put_header - prepare room for Netlink header
* @buf: memory already allocated to store the Netlink message
*
* This function sets to zero the room that is required to put a Netlink
* header in the memory buffer passed as parameter. This function also
* initializes the nlmsg_len field. This function returns a pointer to the
* Netlink header structure.
*/
struct nlmsghdr *mnl_nlmsg_put_header(void *buf)
{
int len = mnl_align(sizeof(struct nlmsghdr));
struct nlmsghdr *nlh = buf;
memset(buf, 0, len);
nlh->nlmsg_len = len;
return nlh;
}
/**
* mnl_nlmsg_put_extra_header - prepare room for an extra header
* @nlh: pointer to Netlink header
* @size: size of the extra header that we want to put
*
* This function sets to zero the room that is required to put the extra
* header after the initial Netlink header. This function also increases
* the nlmsg_len field. This function returns a pointer to the extra
* header.
*/
void *mnl_nlmsg_put_extra_header(struct nlmsghdr *nlh, int size)
{
char *ptr = (char *)nlh + nlh->nlmsg_len;
nlh->nlmsg_len += mnl_align(size);
memset(ptr, 0, size);
return ptr;
}
/**
* mnl_nlmsg_get_len - get the length field from the netlink message
* @nlh: pointer to a netlink header
*
* This function returns the length of the netlink message by return the field
* nlmsg_len of the message.
*/
u_int16_t mnl_nlmsg_get_len(const struct nlmsghdr *nlh)
{
return nlh->nlmsg_len;
}
/**
* mnl_nlmsg_get_data - get a pointer to the payload of the netlink message
* @nlh: pointer to a netlink header
*
* This function returns a pointer to the payload of the netlink message.
*/
void *mnl_nlmsg_get_data(const struct nlmsghdr *nlh)
{
return (void *)nlh + MNL_NLMSG_HDRLEN;
}
/**
* mnl_nlmsg_get_data_offset - get a pointer to the payload of the message
* @nlh: pointer to a netlink header
* @offset: offset to the payload of the attributes TLV set
*
* This function returns a pointer to the payload of the netlink message plus
* a given offset.
*/
void *mnl_nlmsg_get_data_offset(const struct nlmsghdr *nlh, int offset)
{
return (void *)nlh + MNL_NLMSG_HDRLEN + mnl_align(offset);
}
/**
* mnl_nlmsg_ok - check a there is room for netlink message
* @nlh: netlink message that we want to check
* @len: remaining bytes in a buffer that contains the netlink message
*
* This function is used to check that a buffer that contains a netlink
* message has enough room for the netlink message that it stores, ie. this
* function can be used to verify that a netlink message is not malformed nor
* truncated.
*/
int mnl_nlmsg_ok(const struct nlmsghdr *nlh, int len)
{
return len >= sizeof(struct nlmsghdr) &&
nlh->nlmsg_len >= sizeof(struct nlmsghdr) &&
nlh->nlmsg_len <= len;
}
/**
* mnl_nlmsg_next - get the next netlink message in a multipart message
* @nlh: current netlink message that we are handling
* @len: pointer to the current remaining bytes in the buffer
*
* This function returns a pointer to the next netlink message that is part
* of a multi-part netlink message. Netlink can batches messages into a buffer
* so that the receiver has to iterate over the whole set of netlink
* messages.
*/
struct nlmsghdr *mnl_nlmsg_next(const struct nlmsghdr *nlh, int *len)
{
*len -= mnl_align(nlh->nlmsg_len);
return (struct nlmsghdr *)((void *)nlh + mnl_align(nlh->nlmsg_len));
}
void *mnl_nlmsg_get_tail(const struct nlmsghdr *nlh)
{
return (struct nlmsghdr *)((void *)nlh + mnl_align(nlh->nlmsg_len));
}
/**
* mnl_nlmsg_seq_ok - perform sequence tracking
* @nlh: current netlink message that we are handling
* @seq: last sequence number used to send a message
*
* This functions returns 1 if the sequence tracking is fulfilled, otherwise
* 0 is returned. If seq is 0, then the sequence tracking is skipped. This
* value is generally used by the kernel for asynchronous notifications,
* for that reason, this library consider that it is reserved.
*/
int mnl_nlmsg_seq_ok(const struct nlmsghdr *nlh, unsigned int seq)
{
return seq ? nlh->nlmsg_seq == seq : 1;
}
/* XXX: rework this, please */
void mnl_nlmsg_print(const struct nlmsghdr *nlh)
{
int i;
printf("========= netlink header ==========\n");
printf("length(32 bits)=%.08u\n", nlh->nlmsg_len);
printf("type(16 bits)=%.04u flags(16 bits)=%.04x\n",
nlh->nlmsg_type, nlh->nlmsg_flags);
printf("sequence number(32 bits)=%.08x\n", nlh->nlmsg_seq);
printf("port ID(32 bits)=%.08u\n", nlh->nlmsg_pid);
printf("===================================\n");
for (i=sizeof(struct nlmsghdr); i<mnl_nlmsg_get_len(nlh); i+=4) {
char *b = (char *) nlh;
printf("(%.3d) %.2x %.2x %.2x %.2x | ", i,
0xff & b[i], 0xff & b[i+1],
0xff & b[i+2], 0xff & b[i+3]);
printf("%c %c %c %c\n",
isalnum(b[i]) ? b[i] : 0,
isalnum(b[i+1]) ? b[i+1] : 0,
isalnum(b[i+2]) ? b[i+2] : 0,
isalnum(b[i+3]) ? b[i+3] : 0);
}
}

255
src/socket.c Normal file
View File

@ -0,0 +1,255 @@
/*
* (C) 2008-2010 by Pablo Neira Ayuso <pablo@netfilter.org>
*
* This software may be used and distributed according to the terms
* of the GNU General Public License, incorporated herein by reference.
*/
#include <libmnl/libmnl.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <stdlib.h>
#include <unistd.h>
#include <time.h>
#include <errno.h>
struct mnl_socket {
int fd;
struct sockaddr_nl addr;
};
/**
* mnl_socket_get_fd - obtain file descriptor from netlink socket
* @nl: netlink socket obtained via mnl_socket_open()
*
* This function returns the file descriptor of a given netlink socket.
*/
int mnl_socket_get_fd(const struct mnl_socket *nl)
{
return nl->fd;
}
/**
* mnl_socket_get_portid - obtain Netlink PortID from netlink socket
* @nl: netlink socket obtained via mnl_socket_open()
*
* This function returns the Netlink PortID of a given netlink socket.
* It's a common mistake to assume that this PortID equals the process ID
* which is not always true. This is the case if you open more than one
* socket that is binded to the same Netlink subsystem.
*/
unsigned int mnl_socket_get_portid(const struct mnl_socket *nl)
{
return nl->addr.nl_pid;
}
/**
* mnl_socket_open - open a netlink socket
* @unit: the netlink socket unit (see NETLINK_* constants)
*
* On error, it returns -1 and errno is appropriately set. Otherwise, it
* returns a valid pointer to the mnl_socket structure.
*/
struct mnl_socket *mnl_socket_open(int unit)
{
struct mnl_socket *nl;
nl = calloc(sizeof(struct mnl_socket), 1);
if (nl == NULL)
return NULL;
nl->fd = socket(AF_NETLINK, SOCK_RAW, unit);
if (nl->fd == -1)
return NULL;
return nl;
}
/**
* mnl_socket_bind - bind netlink socket
* @nl: netlink socket obtained via mnl_socket_open()
* @groups: the group of message you're interested in
* @pid: the port ID you want to use (use zero for automatic selection)
*
* On error, this function returns -1 and errno is appropriately set. On
* success, 0 is returned.
*/
int mnl_socket_bind(struct mnl_socket *nl, int groups, int pid)
{
int ret;
socklen_t addr_len;
nl->addr.nl_family = AF_NETLINK;
nl->addr.nl_groups = groups;
ret = bind(nl->fd, (struct sockaddr *) &nl->addr, sizeof (nl->addr));
if (ret < 0)
return ret;
addr_len = sizeof(nl->addr);
ret = getsockname(nl->fd, (struct sockaddr *) &nl->addr, &addr_len);
if (ret < 0)
return ret;
if (addr_len != sizeof(nl->addr)) {
errno = EINVAL;
return -1;
}
if (nl->addr.nl_family != AF_NETLINK) {
errno = EINVAL;
return -1;
}
return 0;
}
/**
* mnl_socket_sendto - send a netlink message of a certain size
* @nl: netlink socket obtained via mnl_socket_open()
* @buf: buffer containing the netlink message to be sent
* @bufsiz: number of bytes in the buffer that you want to send
*
* On error, it returns -1 and errno is appropriately set. Otherwise, it
* returns the number of bytes sent.
*/
int mnl_socket_sendto(struct mnl_socket *nl, const void *buf, int len)
{
struct sockaddr_nl snl = {
.nl_family = AF_NETLINK
};
return sendto(nl->fd, buf, len, 0,
(struct sockaddr *) &snl, sizeof(snl));
}
/**
* mnl_socket_sendmsg - send a netlink message of a certain size
* @nl: netlink socket obtained via mnl_socket_open()
* @msg: pointer to struct msghdr (must be initialized appropriately)
* @flags: flags passed to sendmsg()
*
* On error, it returns -1 and errno is appropriately set. Otherwise, it
* returns the number of bytes sent.
*/
int
mnl_socket_sendmsg(struct mnl_socket *nl, struct msghdr *msg, int flags)
{
return sendmsg(nl->fd, msg, flags);
}
/**
* mnl_socket_recvfrom - receive a netlink message
* @nl: netlink socket obtained via mnl_socket_open()
* @buf: buffer that you want to use to store the netlink message
* @bufsiz: size of the buffer passed to store the netlink message
*
* On error, it returns -1 and errno is appropriately set. If errno is set
* to ENOSPC, it means that the buffer that you have passed to store the
* netlink message is small so you have received a truncated message. Make
* sure your program set a buffer big enough to store the netlink message.
*/
int mnl_socket_recvfrom(struct mnl_socket *nl, void *buf, int bufsiz)
{
int ret;
struct sockaddr_nl addr;
struct iovec iov = {
.iov_base = buf,
.iov_len = bufsiz,
};
struct msghdr msg = {
.msg_name = (void *)&addr,
.msg_namelen = sizeof(struct sockaddr_nl),
.msg_iov = &iov,
.msg_iovlen = 1,
.msg_control = NULL,
.msg_controllen = 0,
.msg_flags = 0,
};
ret = recvmsg(nl->fd, &msg, 0);
if (ret == -1)
return ret;
if (msg.msg_flags & MSG_TRUNC) {
errno = ENOSPC;
return -1;
}
if (msg.msg_namelen != sizeof(struct sockaddr_nl)) {
errno = EINVAL;
return -1;
}
return ret;
}
/**
* mnl_socket_recvmsg- receive a netlink message
* @nl: netlink socket obtained via mnl_socket_open()
* @msg: pointer to struct msghdr (must be initialized appropriately)
* @flags: flags passed to recvmsg()
*
* On error, this function returns -1 and errno is appropriately set.
* On sucess, this function returns the number of bytes received.
*/
int
mnl_socket_recvmsg(const struct mnl_socket *nl, struct msghdr *msg, int flags)
{
return recvmsg(nl->fd, msg, flags);
}
/**
* mnl_socket_close - close a given netlink socket
* @nl: netlink socket obtained via mnl_socket_open()
*
* On error, this function returns -1 and errno is appropriately set.
* On success, it returns 0.
*/
int mnl_socket_close(struct mnl_socket *nl)
{
int ret = close(nl->fd);
free(nl);
nl = NULL;
return ret;
}
/**
* mnl_socket_setsockopt - set Netlink socket option
* @nl: netlink socket obtained via mnl_socket_open()
* @type: type of Netlink socket options
* @buf: the buffer that contains the data about this option
* @len: the size of the buffer passed
*
* This function allows you to set some Netlink socket option. As of writing
* this, the existing options are:
*
* #define NETLINK_ADD_MEMBERSHIP 1
* #define NETLINK_DROP_MEMBERSHIP 2
* #define NETLINK_PKTINFO 3
* #define NETLINK_BROADCAST_ERROR 4
* #define NETLINK_NO_ENOBUFS 5
*
* In the early days, Netlink only supported 32 groups expressed in a
* 32-bits mask. However, since 2.6.14, Netlink may have up to 2^32 multicast
* groups but you have to use setsockopt() with NETLINK_ADD_MEMBERSHIP to
* join a given multicast group. This function internally calls setsockopt()
* to join a given netlink multicast group. You can still use mnl_bind()
* and the 32-bit mask to join a set of Netlink multicast groups.
*
* On error, this function returns -1 and errno is appropriately set.
*/
int mnl_socket_setsockopt(struct mnl_socket *nl, int type,
void *buf, socklen_t len)
{
return setsockopt(nl->fd, SOL_NETLINK, type, buf, len);
}
/**
* mnl_socket_getsockopt - get a Netlink socket option
* @nl: netlink socket obtained via mnl_socket_open()
* @type: type of Netlink socket options
* @buf: pointer to the buffer to store the value of this option
* @len: size of the information written in the buffer
*
* On error, this function returns -1 and errno is appropriately set.
*/
int mnl_socket_getsockopt(struct mnl_socket *nl, int type,
void *buf, socklen_t *len)
{
return getsockopt(nl->fd, SOL_NETLINK, type, buf, len);
}