23#include "nl-default.h"
27#include <linux/socket.h>
29#include <netlink/netlink.h>
30#include <netlink/utils.h>
31#include <netlink/cache.h>
32#include <netlink/attr.h>
35#include "nl-priv-dynamic-core/nl-core.h"
36#include "nl-priv-dynamic-core/cache-api.h"
37#include "nl-aux-core/nl-core.h"
39static size_t default_msg_size;
41static void _nl_init init_msg_size(
void)
43 default_msg_size = getpagesize();
59 return NLMSG_HDRLEN + payload;
62static int nlmsg_msg_size(
int payload)
77 return NLMSG_ALIGN(nlmsg_msg_size(payload));
110 return (
unsigned char *) nlh + NLMSG_HDRLEN;
113void *nlmsg_tail(
const struct nlmsghdr *nlh)
115 return (
unsigned char *) nlh + NLMSG_ALIGN(nlh->nlmsg_len);
126 return nlh->nlmsg_len - NLMSG_HDRLEN;
129static int nlmsg_len(
const struct nlmsghdr *nlh)
149 return (
struct nlattr *) (data + NLMSG_ALIGN(hdrlen));
159 return _NL_MAX(nlmsg_len(nlh) - NLMSG_ALIGN(hdrlen), 0u);
169int nlmsg_valid_hdr(
const struct nlmsghdr *nlh,
int hdrlen)
173 s = nlmsg_msg_size(hdrlen);
174 if (s < 0 || nlh->nlmsg_len < ((
unsigned)s))
185int nlmsg_ok(
const struct nlmsghdr *nlh,
int remaining)
187 return (remaining >= (
int)
sizeof(
struct nlmsghdr) &&
188 nlh->nlmsg_len >=
sizeof(
struct nlmsghdr) &&
189 nlh->nlmsg_len <= ((
unsigned)remaining));
200struct nlmsghdr *
nlmsg_next(
struct nlmsghdr *nlh,
int *remaining)
202 int totlen = NLMSG_ALIGN(nlh->nlmsg_len);
204 *remaining -= totlen;
206 return (
struct nlmsghdr *) ((
unsigned char *) nlh + totlen);
219int nlmsg_parse(
struct nlmsghdr *nlh,
int hdrlen,
struct nlattr *tb[],
222 if (!nlmsg_valid_hdr(nlh, hdrlen))
223 return -NLE_MSG_TOOSHORT;
253 if (!nlmsg_valid_hdr(nlh, hdrlen))
254 return -NLE_MSG_TOOSHORT;
267static struct nl_msg *__nlmsg_alloc(
size_t len)
271 if (len <
sizeof(
struct nlmsghdr))
272 len =
sizeof(
struct nlmsghdr);
274 nm = calloc(1,
sizeof(*nm));
280 nm->nm_nlh = calloc(1, len);
284 nm->nm_protocol = -1;
288 NL_DBG(2,
"msg %p: Allocated new message, maxlen=%zu\n", nm, len);
307 return __nlmsg_alloc(default_msg_size);
315 return __nlmsg_alloc(max);
334 struct nlmsghdr *
new = nm->nm_nlh;
336 new->nlmsg_type = hdr->nlmsg_type;
337 new->nlmsg_flags = hdr->nlmsg_flags;
338 new->nlmsg_seq = hdr->nlmsg_seq;
339 new->nlmsg_pid = hdr->nlmsg_pid;
355 struct nlmsghdr nlh = {
356 .nlmsg_type = nlmsgtype,
357 .nlmsg_flags = flags,
359 .nlmsg_pid = NL_AUTO_PID,
364 NL_DBG(2,
"msg %p: Allocated new simple message\n", msg);
381 default_msg_size = max;
397 nm = __nlmsg_alloc(NLMSG_ALIGN(hdr->nlmsg_len));
401 memcpy(nm->nm_nlh, hdr, hdr->nlmsg_len);
420 char *buf = (
char *) n->nm_nlh;
421 size_t nlmsg_len = n->nm_nlh->nlmsg_len;
424 if (len > n->nm_size)
427 tlen = pad ? ((len + (pad - 1)) & ~(pad - 1)) : len;
429 if ((tlen + nlmsg_len) > n->nm_size)
433 n->nm_nlh->nlmsg_len += tlen;
436 memset(buf + len, 0, tlen - len);
438 NL_DBG(2,
"msg %p: Reserved %zu (%zu) bytes, pad=%d, nlmsg_len=%d\n",
439 n, tlen, len, pad, n->nm_nlh->nlmsg_len);
464 memcpy(tmp, data, len);
465 NL_DBG(2,
"msg %p: Appended %zu bytes with padding %d\n", n, len, pad);
488 if (newlen <= n->nm_size)
491 tmp = realloc(n->nm_nlh, newlen);
517struct nlmsghdr *
nlmsg_put(
struct nl_msg *n, uint32_t pid, uint32_t seq,
518 int type,
int payload,
int flags)
520 struct nlmsghdr *nlh;
522 if (n->nm_nlh->nlmsg_len < NLMSG_HDRLEN)
525 nlh = (
struct nlmsghdr *) n->nm_nlh;
526 nlh->nlmsg_type = type;
527 nlh->nlmsg_flags = flags;
528 nlh->nlmsg_pid = pid;
529 nlh->nlmsg_seq = seq;
531 NL_DBG(2,
"msg %p: Added netlink header type=%d, flags=%d, pid=%d, "
532 "seq=%d\n", n, type, flags, pid, seq);
562 NL_DBG(4,
"New reference to message %p, total %d\n",
563 msg, msg->nm_refcnt);
578 NL_DBG(4,
"Returned message reference %p, %d remaining\n",
579 msg, msg->nm_refcnt);
581 if (msg->nm_refcnt < 0)
584 if (msg->nm_refcnt <= 0) {
586 NL_DBG(2,
"msg %p: Freed\n", msg);
598void nlmsg_set_proto(
struct nl_msg *msg,
int protocol)
600 msg->nm_protocol = protocol;
603int nlmsg_get_proto(
struct nl_msg *msg)
605 return msg->nm_protocol;
608size_t nlmsg_get_max_size(
struct nl_msg *msg)
613void nlmsg_set_src(
struct nl_msg *msg,
struct sockaddr_nl *addr)
615 memcpy(&msg->nm_src, addr,
sizeof(*addr));
618struct sockaddr_nl *nlmsg_get_src(
struct nl_msg *msg)
623void nlmsg_set_dst(
struct nl_msg *msg,
struct sockaddr_nl *addr)
625 memcpy(&msg->nm_dst, addr,
sizeof(*addr));
628struct sockaddr_nl *nlmsg_get_dst(
struct nl_msg *msg)
633void nlmsg_set_creds(
struct nl_msg *msg,
struct ucred *creds)
635 memcpy(&msg->nm_creds, creds,
sizeof(*creds));
636 msg->nm_flags |= NL_MSG_CRED_PRESENT;
639struct ucred *nlmsg_get_creds(
struct nl_msg *msg)
641 if (msg->nm_flags & NL_MSG_CRED_PRESENT)
642 return &msg->nm_creds;
653static const struct trans_tbl nl_msgtypes[] = {
654 __ADD(NLMSG_NOOP,NOOP),
655 __ADD(NLMSG_ERROR,ERROR),
656 __ADD(NLMSG_DONE,DONE),
657 __ADD(NLMSG_OVERRUN,OVERRUN),
660char *nl_nlmsgtype2str(
int type,
char *buf,
size_t size)
662 return __type2str(type, buf, size, nl_msgtypes,
663 ARRAY_SIZE(nl_msgtypes));
666int nl_str2nlmsgtype(
const char *name)
668 return __str2type(name, nl_msgtypes, ARRAY_SIZE(nl_msgtypes));
678char *nl_nlmsg_flags2str(
int flags,
char *buf,
size_t len)
682#define PRINT_FLAG(f) \
683 if (flags & NLM_F_##f) { \
684 flags &= ~NLM_F_##f; \
685 strncat(buf, #f, len - strlen(buf) - 1); \
687 strncat(buf, ",", len - strlen(buf) - 1); \
704 snprintf(s,
sizeof(s),
"0x%x", flags);
705 strncat(buf, s, len - strlen(buf) - 1);
721 void (*cb)(
struct nl_object *,
void *);
726static int parse_cb(
struct nl_object *obj,
struct nl_parser_param *p)
728 struct dp_xdata *x = p->pp_arg;
734int nl_msg_parse(
struct nl_msg *msg,
void (*cb)(
struct nl_object *,
void *),
737 struct nl_cache_ops *ops;
738 struct nl_parser_param p = {
741 struct dp_xdata x = {
750 return -NLE_MSGTYPE_NOSUPPORT;
753 err = nl_cache_parse(ops, NULL,
nlmsg_hdr(msg), &p);
766static void prefix_line(FILE *ofd,
int prefix)
770 for (i = 0; i < prefix; i++)
774static inline void dump_hex(FILE *ofd,
char *start,
int len,
int prefix)
777 char ascii[21] = {0};
779 limit = 16 - (prefix * 2);
780 prefix_line(ofd, prefix);
783 for (i = 0, a = 0, c = 0; i < len; i++) {
784 int v = *(uint8_t *) (start + i);
786 fprintf(ofd,
"%02x ", v);
787 ascii[a++] = isprint(v) ? v :
'.';
790 fprintf(ofd,
"%s\n", ascii);
792 prefix_line(ofd, prefix);
796 memset(ascii, 0,
sizeof(ascii));
801 for (i = 0; i < (limit - c); i++)
803 fprintf(ofd,
"%s\n", ascii);
807static void print_hdr(FILE *ofd,
struct nl_msg *msg)
810 struct nl_cache_ops *ops;
811 struct nl_msgtype *mt;
814 fprintf(ofd,
" .nlmsg_len = %d\n", nlh->nlmsg_len);
822 snprintf(buf,
sizeof(buf),
"%s::%s", ops->co_name, mt->mt_name);
825 nl_nlmsgtype2str(nlh->nlmsg_type, buf,
sizeof(buf));
827 fprintf(ofd,
" .type = %d <%s>\n", nlh->nlmsg_type, buf);
828 fprintf(ofd,
" .flags = %d <%s>\n", nlh->nlmsg_flags,
829 nl_nlmsg_flags2str(nlh->nlmsg_flags, buf,
sizeof(buf)));
830 fprintf(ofd,
" .seq = %d\n", nlh->nlmsg_seq);
831 fprintf(ofd,
" .port = %d\n", nlh->nlmsg_pid);
835static void print_genl_hdr(FILE *ofd,
void *start)
837 struct genlmsghdr *ghdr = start;
839 fprintf(ofd,
" [GENERIC NETLINK HEADER] %zu octets\n", GENL_HDRLEN);
840 fprintf(ofd,
" .cmd = %u\n", ghdr->cmd);
841 fprintf(ofd,
" .version = %u\n", ghdr->version);
842 fprintf(ofd,
" .unused = %#x\n", ghdr->reserved);
845static void *print_genl_msg(
struct nl_msg *msg, FILE *ofd,
struct nlmsghdr *hdr,
846 struct nl_cache_ops *ops,
int *payloadlen)
850 if (*payloadlen < (
int)GENL_HDRLEN)
853 print_genl_hdr(ofd, data);
855 *payloadlen -= GENL_HDRLEN;
859 int hdrsize = ops->co_hdrsize - GENL_HDRLEN;
862 if (*payloadlen < hdrsize)
865 fprintf(ofd,
" [HEADER] %d octets\n", hdrsize);
866 dump_hex(ofd, data, hdrsize, 0);
868 *payloadlen -= hdrsize;
876static void dump_attr(FILE *ofd,
struct nlattr *attr,
int prefix)
880 dump_hex(ofd,
nla_data(attr), len, prefix);
883static void dump_attrs(FILE *ofd,
struct nlattr *attrs,
int attrlen,
890 int padlen, alen =
nla_len(nla);
892 prefix_line(ofd, prefix);
894 if (nla->nla_type == 0)
895 fprintf(ofd,
" [ATTR PADDING] %d octets\n", alen);
897 fprintf(ofd,
" [ATTR %02d%s] %d octets\n",
nla_type(nla),
902 dump_attrs(ofd,
nla_data(nla), alen, prefix+1);
904 dump_attr(ofd, nla, prefix);
908 prefix_line(ofd, prefix);
909 fprintf(ofd,
" [PADDING] %d octets\n",
911 dump_hex(ofd, (
char *)
nla_data(nla) + alen,
917 prefix_line(ofd, prefix);
918 fprintf(ofd,
" [LEFTOVER] %d octets\n", rem);
922static void dump_error_msg(
struct nl_msg *msg, FILE *ofd)
928 fprintf(ofd,
" [ERRORMSG] %zu octets\n",
sizeof(*err));
931 if (l >= 0 && ((
unsigned)l) >=
sizeof(*err)) {
932 struct nl_msg *errmsg;
934 fprintf(ofd,
" .error = %d \"%s\"\n", err->error,
935 nl_strerror_l(-err->error));
936 fprintf(ofd,
" [ORIGINAL MESSAGE] %zu octets\n",
sizeof(*hdr));
939 print_hdr(ofd, errmsg);
944static void print_msg(
struct nl_msg *msg, FILE *ofd,
struct nlmsghdr *hdr)
946 struct nl_cache_ops *ops;
947 int payloadlen = nlmsg_len(hdr);
956 payloadlen -= attrlen;
959 if (msg->nm_protocol == NETLINK_GENERIC)
960 data = print_genl_msg(msg, ofd, hdr, ops, &payloadlen);
963 fprintf(ofd,
" [PAYLOAD] %d octets\n", payloadlen);
964 dump_hex(ofd, data, payloadlen, 0);
968 struct nlattr *attrs;
973 dump_attrs(ofd, attrs, attrlen, 0);
990 "-------------------------- BEGIN NETLINK MESSAGE ---------------------------\n");
992 fprintf(ofd,
" [NETLINK HEADER] %zu octets\n",
sizeof(
struct nlmsghdr));
995 if (hdr->nlmsg_type == NLMSG_ERROR)
996 dump_error_msg(msg, ofd);
997 else if (nlmsg_len(hdr) > 0)
998 print_msg(msg, ofd, hdr);
1001 "--------------------------- END NETLINK MESSAGE ---------------------------\n");
int nla_validate(const struct nlattr *head, int len, int maxtype, const struct nla_policy *policy)
Validate a stream of attributes.
int nla_parse(struct nlattr *tb[], int maxtype, struct nlattr *head, int len, const struct nla_policy *policy)
Create attribute index based on a stream of attributes.
int nla_type(const struct nlattr *nla)
Return type of the attribute.
void * nla_data(const struct nlattr *nla)
Return pointer to the payload section.
int nla_is_nested(const struct nlattr *attr)
Return true if attribute has NLA_F_NESTED flag set.
#define nla_for_each_attr(pos, head, len, rem)
Iterate over a stream of attributes.
int nla_len(const struct nlattr *nla)
Return length of the payload .
struct nlattr * nla_find(const struct nlattr *head, int len, int attrtype)
Find a single attribute in a stream of attributes.
int nla_padlen(int payload)
Return length of padding at the tail of the attribute.
struct nl_msgtype * nl_msgtype_lookup(struct nl_cache_ops *ops, int msgtype)
Lookup message type cache association.
struct nl_cache_ops * nl_cache_ops_associate_safe(int protocol, int msgtype)
Associate protocol and message type to cache operations.
void nl_cache_ops_put(struct nl_cache_ops *ops)
Decrement reference counter.
int nlmsg_ok(const struct nlmsghdr *nlh, int remaining)
check if the netlink message fits into the remaining bytes
void nl_msg_dump(struct nl_msg *msg, FILE *ofd)
Dump message in human readable format to file descriptor.
int nlmsg_total_size(int payload)
Calculates size of netlink message including padding based on payload length.
struct nlmsghdr * nlmsg_hdr(struct nl_msg *n)
Return actual netlink message.
struct nl_msg * nlmsg_alloc_simple(int nlmsgtype, int flags)
Allocate a new netlink message.
void * nlmsg_data(const struct nlmsghdr *nlh)
Return pointer to message payload.
void nlmsg_get(struct nl_msg *msg)
Acquire a reference on a netlink message.
struct nlmsghdr * nlmsg_next(struct nlmsghdr *nlh, int *remaining)
next netlink message in message stream
int nlmsg_validate(struct nlmsghdr *nlh, int hdrlen, int maxtype, const struct nla_policy *policy)
nlmsg_validate - validate a netlink message including attributes
void * nlmsg_reserve(struct nl_msg *n, size_t len, int pad)
Reserve room for additional data in a netlink message.
struct nl_msg * nlmsg_convert(struct nlmsghdr *hdr)
Convert a netlink message received from a netlink socket to a nl_msg.
void nlmsg_free(struct nl_msg *msg)
Release a reference from an netlink message.
int nlmsg_parse(struct nlmsghdr *nlh, int hdrlen, struct nlattr *tb[], int maxtype, const struct nla_policy *policy)
parse attributes of a netlink message
struct nl_msg * nlmsg_alloc_size(size_t max)
Allocate a new netlink message with maximum payload size specified.
int nlmsg_expand(struct nl_msg *n, size_t newlen)
Expand maximum payload size of a netlink message.
struct nlattr * nlmsg_find_attr(struct nlmsghdr *nlh, int hdrlen, int attrtype)
nlmsg_find_attr - find a specific attribute in a netlink message
struct nl_msg * nlmsg_alloc(void)
Allocate a new netlink message with the default maximum payload size.
int nlmsg_datalen(const struct nlmsghdr *nlh)
Return length of message payload.
struct nlmsghdr * nlmsg_put(struct nl_msg *n, uint32_t pid, uint32_t seq, int type, int payload, int flags)
Add a netlink message header to a netlink message.
int nlmsg_attrlen(const struct nlmsghdr *nlh, int hdrlen)
length of attributes data
void nlmsg_set_default_size(size_t max)
Set the default maximum message payload size for allocated messages.
#define NL_AUTO_SEQ
May be used to refer to a sequence number which should be automatically set just before sending the m...
int nlmsg_append(struct nl_msg *n, void *data, size_t len, int pad)
Append data to tail of a netlink message.
int nlmsg_padlen(int payload)
Size of padding that needs to be added at end of message.
struct nlattr * nlmsg_attrdata(const struct nlmsghdr *nlh, int hdrlen)
head of attributes data
int nlmsg_size(int payload)
Calculates size of netlink message based on payload length.
struct nl_msg * nlmsg_inherit(struct nlmsghdr *hdr)
Allocate a new netlink message and inherit netlink message header.
Attribute validation policy.