diff --git a/include/netlink-types.h b/include/netlink-types.h index f273da3..f7c6437 100644 --- a/include/netlink-types.h +++ b/include/netlink-types.h @@ -137,6 +137,7 @@ struct nl_msg struct sockaddr_nl nm_dst; struct ucred nm_creds; struct nlmsghdr * nm_nlh; + size_t nm_size; }; struct rtnl_link_map diff --git a/include/netlink/msg.h b/include/netlink/msg.h index 263503a..5d0ecd2 100644 --- a/include/netlink/msg.h +++ b/include/netlink/msg.h @@ -74,7 +74,9 @@ extern int nlmsg_validate(struct nlmsghdr *, int, int, #define nlmsg_build(ptr) nlmsg_inherit(ptr) extern struct nl_msg * nlmsg_alloc(void); +extern struct nl_msg * nlmsg_alloc_size(size_t); extern struct nl_msg * nlmsg_alloc_simple(int, int); +extern void nlmsg_set_default_size(size_t); extern struct nl_msg * nlmsg_inherit(struct nlmsghdr *); extern struct nl_msg * nlmsg_convert(struct nlmsghdr *); extern void * nlmsg_reserve(struct nl_msg *, size_t, int); diff --git a/lib/attr.c b/lib/attr.c index aa77ca5..8d9fdfa 100644 --- a/lib/attr.c +++ b/lib/attr.c @@ -481,9 +481,8 @@ struct nlattr *nla_reserve(struct nl_msg *n, int attrtype, int attrlen) tlen = NLMSG_ALIGN(n->nm_nlh->nlmsg_len) + nla_total_size(attrlen); - n->nm_nlh = realloc(n->nm_nlh, tlen); - if (!n->nm_nlh) { - nl_errno(ENOMEM); + if ((tlen + n->nm_nlh->nlmsg_len) > n->nm_size) { + nl_errno(ENOBUFS); return NULL; } diff --git a/lib/msg.c b/lib/msg.c index 3ae8909..80b689f 100644 --- a/lib/msg.c +++ b/lib/msg.c @@ -164,6 +164,13 @@ #include #include +static size_t default_msg_size; + +static void __init init_msg_size(void) +{ + default_msg_size = getpagesize(); +} + /** * @name Size Calculations * @{ @@ -369,9 +376,10 @@ static struct nl_msg *__nlmsg_alloc(size_t len) goto errout; nm->nm_protocol = -1; - nm->nm_nlh->nlmsg_len = len; + nm->nm_size = len; + nm->nm_nlh->nlmsg_len = nlmsg_total_size(0); - NL_DBG(2, "msg %p: Allocated new message, nlmsg_len=%zu\n", nm, len); + NL_DBG(2, "msg %p: Allocated new message, maxlen=%zu\n", nm, len); return nm; errout: @@ -381,25 +389,34 @@ errout: } /** - * Allocate a new netlink message + * Allocate a new netlink message with the default maximum payload size. * - * Allocates a new netlink message without any further payload. + * Allocates a new netlink message without any further payload. The + * maximum payload size defaults to PAGESIZE or as otherwise specified + * with nlmsg_set_default_size(). * * @return Newly allocated netlink message or NULL. */ struct nl_msg *nlmsg_alloc(void) { - return __nlmsg_alloc(nlmsg_total_size(0)); + return __nlmsg_alloc(default_msg_size); +} + +/** + * Allocate a new netlink message with maximum payload size specified. + */ +struct nl_msg *nlmsg_alloc_size(size_t max) +{ + return __nlmsg_alloc(max); } /** * Allocate a new netlink message and inherit netlink message header * @arg hdr Netlink message header template * - * Allocates a new netlink message with a tailroom for the netlink - * message header. If \a hdr is not NULL it will be used as a - * template for the netlink message header, otherwise the header - * is left blank. + * Allocates a new netlink message and inherits the original message + * header. If \a hdr is not NULL it will be used as a template for + * the netlink message header, otherwise the header is left blank. * * @return Newly allocated netlink message or NULL */ @@ -442,6 +459,18 @@ struct nl_msg *nlmsg_alloc_simple(int nlmsgtype, int flags) return msg; } +/** + * Set the default maximum message payload size for allocated messages + * @arg max Size of payload in bytes. + */ +void nlmsg_set_default_size(size_t max) +{ + if (max < nlmsg_total_size(0)) + max = nlmsg_total_size(0); + + default_msg_size = max; +} + /** * Convert a netlink message received from a netlink socket to a nl_msg * @arg hdr Netlink message received from netlink socket. @@ -477,35 +506,31 @@ errout: * existing netlink message. Eventual padding required will * be zeroed out. * - * @note All existing pointers into the old data section may have - * become obsolete and illegal to reference after this call. - * * @return Pointer to start of additional data tailroom or NULL. */ void *nlmsg_reserve(struct nl_msg *n, size_t len, int pad) { - void *tmp; + void *buf = n->nm_nlh; + size_t nlmsg_len = n->nm_nlh->nlmsg_len; size_t tlen; tlen = pad ? ((len + (pad - 1)) & ~(pad - 1)) : len; - tmp = realloc(n->nm_nlh, n->nm_nlh->nlmsg_len + tlen); - if (!tmp) { - nl_errno(ENOMEM); + if ((tlen + nlmsg_len) > n->nm_size) { + nl_errno(ENOBUFS); return NULL; } - n->nm_nlh = tmp; - tmp += n->nm_nlh->nlmsg_len; + buf += nlmsg_len; n->nm_nlh->nlmsg_len += tlen; if (tlen > len) - memset(tmp + len, 0, tlen - len); + memset(buf + len, 0, tlen - len); NL_DBG(2, "msg %p: Reserved %zu bytes, pad=%d, nlmsg_len=%d\n", n, len, pad, n->nm_nlh->nlmsg_len); - return tmp; + return buf; } /** @@ -518,9 +543,6 @@ void *nlmsg_reserve(struct nl_msg *n, size_t len, int pad) * Extends the netlink message as needed and appends the data of given * length to the message. * - * @note All existing pointers into the old data section may have - * become obsolete and illegal to reference after this call. - * * @return 0 on success or a negative error code */ int nlmsg_append(struct nl_msg *n, void *data, size_t len, int pad) diff --git a/lib/nl.c b/lib/nl.c index fd69de7..b425302 100644 --- a/lib/nl.c +++ b/lib/nl.c @@ -417,10 +417,15 @@ int nl_send_simple(struct nl_handle *handle, int type, int flags, void *buf, if (!msg) return nl_errno(ENOMEM); - if (buf && size) - nlmsg_append(msg, buf, size, NLMSG_ALIGNTO); + if (buf && size) { + err = nlmsg_append(msg, buf, size, NLMSG_ALIGNTO); + if (err < 0) + goto errout; + } + err = nl_send_auto_complete(handle, msg); +errout: nlmsg_free(msg); return err;