diff options
author | Pablo Neira Ayuso <pablo@netfilter.org> | 2010-03-19 14:55:32 +0100 |
---|---|---|
committer | Pablo Neira Ayuso <pablo@netfilter.org> | 2010-03-19 14:55:32 +0100 |
commit | 74e7bb8b033640f7c4692c4ea0d5c231e3137b7b (patch) | |
tree | 4cc2125d00b83b5ac1b076da2c8e3eff7b08ddc3 /src | |
download | libmnl-74e7bb8b033640f7c4692c4ea0d5c231e3137b7b.tar.gz libmnl-74e7bb8b033640f7c4692c4ea0d5c231e3137b7b.zip |
initial libmnl import
Diffstat (limited to 'src')
-rw-r--r-- | src/Makefile.am | 9 | ||||
-rw-r--r-- | src/attr.c | 212 | ||||
-rw-r--r-- | src/callback.c | 119 | ||||
-rw-r--r-- | src/msg.c | 213 | ||||
-rw-r--r-- | src/socket.c | 255 |
5 files changed, 808 insertions, 0 deletions
diff --git a/src/Makefile.am b/src/Makefile.am new file mode 100644 index 0000000..1d3713f --- /dev/null +++ b/src/Makefile.am @@ -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 diff --git a/src/attr.c b/src/attr.c new file mode 100644 index 0000000..a724be0 --- /dev/null +++ b/src/attr.c @@ -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); +} diff --git a/src/callback.c b/src/callback.c new file mode 100644 index 0000000..3fc883e --- /dev/null +++ b/src/callback.c @@ -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); +} diff --git a/src/msg.c b/src/msg.c new file mode 100644 index 0000000..02f812b --- /dev/null +++ b/src/msg.c @@ -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); + } +} diff --git a/src/socket.c b/src/socket.c new file mode 100644 index 0000000..b439b8f --- /dev/null +++ b/src/socket.c @@ -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); +} |