X-Git-Url: http://git.onelab.eu/?p=libnl.git;a=blobdiff_plain;f=lib%2Fattr.c;fp=lib%2Fattr.c;h=0000000000000000000000000000000000000000;hp=dd47b6e3b23af789b468c25b03ff0fc65a589383;hb=332c8b7561dcac7ac95cc0d07328b1cb22d780a6;hpb=eabdd897b75ecc1fac5e255229a899126085e57a diff --git a/lib/attr.c b/lib/attr.c deleted file mode 100644 index dd47b6e..0000000 --- a/lib/attr.c +++ /dev/null @@ -1,762 +0,0 @@ -/* - * lib/attr.c Netlink Attributes - * - * 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-2006 Thomas Graf - */ - -#include -#include -#include -#include -#include -#include -#include - -/** - * @ingroup nl - * @defgroup attr Attributes - * Netlink Attributes Construction/Parsing Interface - * @par 0) Introduction - * Netlink attributes are chained together following each other: - * @code - * <------- nla_total_size(payload) -------> - * <---- nla_attr_size(payload) -----> - * +----------+- - -+- - - - - - - - - +- - -+-------- - - - * | Header | Pad | Payload | Pad | Header - * +----------+- - -+- - - - - - - - - +- - -+-------- - - - * <- nla_len(nla) -> ^ - * nla_data(nla)----^ | - * nla_next(nla)-----------------------------' - * @endcode - * - * @par - * The attribute header and payload must be aligned properly: - * @code - * <------- NLA_HDRLEN ------> <-- NLA_ALIGN(payload)--> - * +---------------------+- - -+- - - - - - - - - -+- - -+ - * | Header | Pad | Payload | Pad | - * | (struct nlattr) | ing | | ing | - * +---------------------+- - -+- - - - - - - - - -+- - -+ - * <-------------- nlattr->nla_len --------------> - * @endcode - * - * @par Nested TLVs: - * Nested TLVs are an array of TLVs nested into another TLV. This can be useful - * to allow subsystems to have their own formatting rules without the need to - * make the underlying layer be aware of it. It can also be useful to transfer - * arrays, lists and flattened trees. - * \code - * <-------------------- NLA_ALIGN(...) -------------------> - * +---------------+- - - - - - - - - - - - - - - - - -+- - -+ - * | |+---------+---------+- - -+-------+| | - * | TLV Header || TLV 1 | TLV 2 | | TLV n || Pad | - * | |+---------+---------+- - -+-------+| | - * +---------------+- - - - - - - - - - - - - - - - - -+- - -+ - * <--------- nla_data(nla) ---------> - * \endcode - * - * @par 1) Constructing a message with attributes - * @code - * int param1 = 10; - * char *param2 = "parameter text"; - * struct nlmsghdr hdr = { - * .nlmsg_type = MY_ACTION, - * }; - * struct nl_msg *m = nlmsg_build(&hdr); - * nla_put_u32(m, 1, param1); - * nla_put_string(m, 2, param2); - * - * nl_send_auto_complete(handle, nl_msg_get(m)); - * nlmsg_free(m); - * @endcode - * - * @par 2) Constructing nested attributes - * @code - * struct nl_msg * nested_config(void) - * { - * int a = 5, int b = 10; - * struct nl_msg *n = nlmsg_build(NULL); - * nla_put_u32(n, 10, a); - * nla_put_u32(n, 20, b); - * return n; - * } - * - * ... - * struct nl_msg *m = nlmsg_build(&hdr); - * struct nl_msg *nest = nested_config(); - * nla_put_nested(m, 1, nest); - * - * nl_send_auto_complete(handle, nl_msg_get(m)); - * nlmsg_free(nest); - * nlmsg_free(m); - * @endcode - * @{ - */ - -/** - * @name Size Calculations - * @{ - */ - -/** - * length of attribute not including padding - * @arg payload length of payload - */ -int nla_attr_size(int payload) -{ - return NLA_HDRLEN + payload; -} - -/** - * total length of attribute including padding - * @arg payload length of payload - */ -int nla_total_size(int payload) -{ - return NLA_ALIGN(nla_attr_size(payload)); -} - -/** - * length of padding at the tail of the attribute - * @arg payload length of payload - */ -int nla_padlen(int payload) -{ - return nla_total_size(payload) - nla_attr_size(payload); -} - -/** @} */ - -/** - * @name Payload Access - * @{ - */ - -/** - * head of payload - * @arg nla netlink attribute - */ -void *nla_data(const struct nlattr *nla) -{ - return (char *) nla + NLA_HDRLEN; -} - -/** - * length of payload - * @arg nla netlink attribute - */ -int nla_len(const struct nlattr *nla) -{ - return nla->nla_len - NLA_HDRLEN; -} - -/** @} */ - -/** - * @name Attribute Parsing - * @{ - */ - -/** - * check if the netlink attribute fits into the remaining bytes - * @arg nla netlink attribute - * @arg remaining number of bytes remaining in attribute stream - */ -int nla_ok(const struct nlattr *nla, int remaining) -{ - return remaining >= sizeof(*nla) && - nla->nla_len >= sizeof(*nla) && - nla->nla_len <= remaining; -} - -/** - * next netlink attribte in attribute stream - * @arg nla netlink attribute - * @arg remaining number of bytes remaining in attribute stream - * - * @return the next netlink attribute in the attribute stream and - * decrements remaining by the size of the current attribute. - */ -struct nlattr *nla_next(const struct nlattr *nla, int *remaining) -{ - int totlen = NLA_ALIGN(nla->nla_len); - - *remaining -= totlen; - return (struct nlattr *) ((char *) nla + totlen); -} - -static uint16_t nla_attr_minlen[NLA_TYPE_MAX+1] = { - [NLA_U8] = sizeof(uint8_t), - [NLA_U16] = sizeof(uint16_t), - [NLA_U32] = sizeof(uint32_t), - [NLA_U64] = sizeof(uint64_t), - [NLA_STRING] = 1, - [NLA_NESTED] = NLA_HDRLEN, -}; - -static int validate_nla(struct nlattr *nla, int maxtype, - struct nla_policy *policy) -{ - struct nla_policy *pt; - int minlen = 0; - - if (nla->nla_type <= 0 || nla->nla_type > maxtype) - return 0; - - pt = &policy[nla->nla_type]; - - if (pt->type > NLA_TYPE_MAX) - BUG(); - - if (pt->minlen) - minlen = pt->minlen; - else if (pt->type != NLA_UNSPEC) - minlen = nla_attr_minlen[pt->type]; - - if (pt->type == NLA_FLAG && nla_len(nla) > 0) - return -ERANGE; - - if (nla_len(nla) < minlen) - return -ERANGE; - - if (pt->maxlen && nla_len(nla) > pt->maxlen) - return -ERANGE; - - if (pt->type == NLA_STRING) { - char *data = nla_data(nla); - if (data[nla_len(nla) - 1] != '\0') - return -EINVAL; - } - - return 0; -} - - -/** - * Parse a stream of attributes into a tb buffer - * @arg tb destination array with maxtype+1 elements - * @arg maxtype maximum attribute type to be expected - * @arg head head of attribute stream - * @arg len length of attribute stream - * @arg policy validation policy - * - * Parses a stream of attributes and stores a pointer to each attribute in - * the tb array accessable via the attribute type. Attributes with a type - * exceeding maxtype will be silently ignored for backwards compatibility - * reasons. policy may be set to NULL if no validation is required. - * - * @return 0 on success or a negative error code. - */ -int nla_parse(struct nlattr *tb[], int maxtype, struct nlattr *head, int len, - struct nla_policy *policy) -{ - struct nlattr *nla; - int rem, err; - - memset(tb, 0, sizeof(struct nlattr *) * (maxtype + 1)); - - nla_for_each_attr(nla, head, len, rem) { - uint16_t type = nla->nla_type; - - if (type == 0) { - fprintf(stderr, "Illegal nla->nla_type == 0\n"); - continue; - } - - if (type <= maxtype) { - if (policy) { - err = validate_nla(nla, maxtype, policy); - if (err < 0) - goto errout; - } - - tb[type] = nla; - } - } - - if (rem > 0) - fprintf(stderr, "netlink: %d bytes leftover after parsing " - "attributes.\n", rem); - - err = 0; -errout: - return err; -} - - -/** - * parse nested attributes - * @arg tb destination array with maxtype+1 elements - * @arg maxtype maximum attribute type to be expected - * @arg nla attribute containing the nested attributes - * @arg policy validation policy - * - * @see nla_parse() - */ -int nla_parse_nested(struct nlattr *tb[], int maxtype, struct nlattr *nla, - struct nla_policy *policy) -{ - return nla_parse(tb, maxtype, nla_data(nla), nla_len(nla), policy); -} - -/** - * Validate a stream of attributes - * @arg head head of attribute stream - * @arg len length of attribute stream - * @arg maxtype maximum attribute type to be expected - * @arg policy validation policy - * - * Validates all attributes in the specified attribute stream - * against the specified policy. Attributes with a type exceeding - * maxtype will be ignored. See documenation of struct nla_policy - * for more details. - * - * @return 0 on success or a negative error code. - */ -int nla_validate(struct nlattr *head, int len, int maxtype, - struct nla_policy *policy) -{ - struct nlattr *nla; - int rem, err; - - nla_for_each_attr(nla, head, len, rem) { - err = validate_nla(nla, maxtype, policy); - if (err < 0) - goto errout; - } - - err = 0; -errout: - return err; -} - -/** - * Find a specific attribute in a stream of attributes - * @arg head head of attribute stream - * @arg len length of attribute stream - * @arg attrtype type of attribute to look for - * - * @return the first attribute in the stream matching the specified type. - */ -struct nlattr *nla_find(struct nlattr *head, int len, int attrtype) -{ - struct nlattr *nla; - int rem; - - nla_for_each_attr(nla, head, len, rem) - if (nla->nla_type == attrtype) - return nla; - - return NULL; -} - -/** @} */ - -/** - * @name Utilities - * @{ - */ - -/** - * Copy a netlink attribute into another memory area - * @arg dest where to copy to memcpy - * @arg src netlink attribute to copy from - * @arg count size of the destination area - * - * Note: The number of bytes copied is limited by the length of - * attribute's payload. memcpy - * - * @return the number of bytes copied. - */ -int nla_memcpy(void *dest, struct nlattr *src, int count) -{ - int minlen; - - if (!src) - return 0; - - minlen = min_t(int, count, nla_len(src)); - memcpy(dest, nla_data(src), minlen); - - return minlen; -} - -/** - * Copy string attribute payload into a sized buffer - * @arg dst where to copy the string to - * @arg nla attribute to copy the string from - * @arg dstsize size of destination buffer - * - * Copies at most dstsize - 1 bytes into the destination buffer. - * The result is always a valid NUL-terminated string. Unlike - * strlcpy the destination buffer is always padded out. - * - * @return the length of the source buffer. - */ -size_t nla_strlcpy(char *dst, const struct nlattr *nla, size_t dstsize) -{ - size_t srclen = nla_len(nla); - char *src = nla_data(nla); - - if (srclen > 0 && src[srclen - 1] == '\0') - srclen--; - - if (dstsize > 0) { - size_t len = (srclen >= dstsize) ? dstsize - 1 : srclen; - - memset(dst, 0, dstsize); - memcpy(dst, src, len); - } - - return srclen; -} - -/** - * Compare an attribute with sized memory area - * @arg nla netlink attribute - * @arg data memory area - * @arg size size of memory area - */ -int nla_memcmp(const struct nlattr *nla, const void *data, - size_t size) -{ - int d = nla_len(nla) - size; - - if (d == 0) - d = memcmp(nla_data(nla), data, size); - - return d; -} - -/** - * Compare a string attribute against a string - * @arg nla netlink string attribute - * @arg str another string - */ -int nla_strcmp(const struct nlattr *nla, const char *str) -{ - int len = strlen(str) + 1; - int d = nla_len(nla) - len; - - if (d == 0) - d = memcmp(nla_data(nla), str, len); - - return d; -} - -/** @} */ - -/** - * @name Attribute Construction - * @{ - */ - -/** - * reserve room for attribute on the skb - * @arg n netlink message - * @arg attrtype attribute type - * @arg attrlen length of attribute payload - * - * Adds a netlink attribute header to a netlink message and reserves - * room for the payload but does not copy it. - */ -struct nlattr *nla_reserve(struct nl_msg *n, int attrtype, int attrlen) -{ - struct nlattr *nla; - int tlen; - - 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); - return NULL; - } - - nla = (struct nlattr *) nlmsg_tail(n->nm_nlh); - nla->nla_type = attrtype; - nla->nla_len = nla_attr_size(attrlen); - - memset((unsigned char *) nla + nla->nla_len, 0, nla_padlen(attrlen)); - n->nm_nlh->nlmsg_len = tlen; - - return nla; -} - -/** - * Add a netlink attribute to a netlink message - * @arg n netlink message - * @arg attrtype attribute type - * @arg attrlen length of attribute payload - * @arg data head of attribute payload - * - * @return -1 if the tailroom of the skb is insufficient to store - * the attribute header and payload. - */ -int nla_put(struct nl_msg *n, int attrtype, int attrlen, const void *data) -{ - struct nlattr *nla; - - nla = nla_reserve(n, attrtype, attrlen); - if (!nla) - return nl_errno(ENOMEM); - - memcpy(nla_data(nla), data, attrlen); - - return 0; -} - -/** - * Add a nested netlink attribute to a netlink message - * @arg n netlink message - * @arg attrtype attribute type - * @arg nested netlink attribute to nest - * - * @return -1 if the tailroom of the skb is insufficient to store - * the attribute header and payload. - */ -int nla_put_nested(struct nl_msg *n, int attrtype, struct nl_msg *nested) -{ - return nla_put(n, attrtype, nlmsg_len(nested->nm_nlh), - nlmsg_data(nested->nm_nlh)); -} - -/** - * Add a u16 netlink attribute to a netlink message - * @arg n netlink message - * @arg attrtype attribute type - * @arg value numeric value - */ -int nla_put_u8(struct nl_msg *n, int attrtype, uint8_t value) -{ - return nla_put(n, attrtype, sizeof(uint8_t), &value); -} - -/** - * Add a u16 netlink attribute to a netlink message - * @arg n netlink message - * @arg attrtype attribute type - * @arg value numeric value - */ -int nla_put_u16(struct nl_msg *n, int attrtype, uint16_t value) -{ - return nla_put(n, attrtype, sizeof(uint16_t), &value); -} - -/** - * Add a u32 netlink attribute to a netlink message - * @arg n netlink message - * @arg attrtype attribute type - * @arg value numeric value - */ -int nla_put_u32(struct nl_msg *n, int attrtype, uint32_t value) -{ - return nla_put(n, attrtype, sizeof(uint32_t), &value); -} - -/** - * Add a u64 netlink attribute to a netlink message - * @arg n netlink message - * @arg attrtype attribute type - * @arg value numeric value - */ -int nla_put_u64(struct nl_msg *n, int attrtype, uint64_t value) -{ - return nla_put(n, attrtype, sizeof(uint64_t), &value); -} - -/** - * Add a string netlink attribute to a netlink message - * @arg n netlink message - * @arg attrtype attribute type - * @arg str NUL terminated string - */ -int nla_put_string(struct nl_msg *n, int attrtype, const char *str) -{ - return nla_put(n, attrtype, strlen(str) + 1, str); -} - -/** - * Add a flag netlink attribute to a netlink message - * @arg n netlink message - * @arg attrtype attribute type - */ -int nla_put_flag(struct nl_msg *n, int attrtype) -{ - return nla_put(n, attrtype, 0, NULL); -} - -/** - * Add a msecs netlink attribute to a netlink message - * @arg n netlink message - * @arg attrtype attribute type - * @arg msecs number of msecs - */ -int nla_put_msecs(struct nl_msg *n, int attrtype, unsigned long msecs) -{ - return nla_put_u64(n, attrtype, msecs); -} - -/** - * Add an abstract data netlink attribute to a netlink message - * @arg n netlink message - * @arg attrtype attribute type - * @arg data abstract data - */ -int nla_put_data(struct nl_msg *n, int attrtype, struct nl_data *data) -{ - return nla_put(n, attrtype, nl_data_get_size(data), - nl_data_get(data)); -} - -/** - * Add an abstract address netlink attribute to a netlink message - * @arg n netlink message - * @arg attrtype attribute type - * @arg addr abstract address - */ -int nla_put_addr(struct nl_msg *n, int attrtype, struct nl_addr *addr) -{ - return nla_put(n, attrtype, nl_addr_get_len(addr), - nl_addr_get_binary_addr(addr)); -} - -/** @} */ - -/** - * @name Attribute Nesting - * @{ - */ - -/** - * Start a new level of nested attributes - * @arg n netlink message - * @arg attrtype attribute type of container - * - * @return the container attribute - */ -struct nlattr *nla_nest_start(struct nl_msg *n, int attrtype) -{ - struct nlattr *start = (struct nlattr *) nlmsg_tail(n->nm_nlh); - - if (nla_put(n, attrtype, 0, NULL) < 0) - return NULL; - - return start; -} - -/** - * Finalize nesting of attributes - * @arg n netlink message - * @arg start container attribute - * - * Corrects the container attribute header to include the all - * appeneded attributes. - * - * @return the total data length of the skb. - */ -int nla_nest_end(struct nl_msg *n, struct nlattr *start) -{ - start->nla_len = (unsigned char *) nlmsg_tail(n->nm_nlh) - - (unsigned char *) start; - return 0; -} - -/** @} */ - -/** - * @name Attribute Reading - * @{ - */ - -/** - * Return payload of u32 attribute - * @arg nla u32 netlink attribute - */ -uint32_t nla_get_u32(struct nlattr *nla) -{ - return *(uint32_t *) nla_data(nla); -} - -/** - * Return payload of u16 attribute - * @arg nla u16 netlink attribute - */ -uint16_t nla_get_u16(struct nlattr *nla) -{ - return *(uint16_t *) nla_data(nla); -} - -/** - * Return payload of u8 attribute - * @arg nla u8 netlink attribute - */ -uint8_t nla_get_u8(struct nlattr *nla) -{ - return *(uint8_t *) nla_data(nla); -} - -/** - * Return payload of u64 attribute - * @arg nla u64 netlink attribute - */ -uint64_t nla_get_u64(struct nlattr *nla) -{ - uint64_t tmp; - - nla_memcpy(&tmp, nla, sizeof(tmp)); - - return tmp; -} - -/** - * Return payload of flag attribute - * @arg nla flag netlink attribute - */ -int nla_get_flag(struct nlattr *nla) -{ - return !!nla; -} - -/** - * Return payload of msecs attribute - * @arg nla msecs netlink attribute - * - * @return the number of milliseconds. - */ -unsigned long nla_get_msecs(struct nlattr *nla) -{ - return nla_get_u64(nla); -} - -/** - * Return payload of address attribute - * @arg nla address netlink attribute - * @arg family address family - * - * @return Newly allocated address handle or NULL - */ -struct nl_addr *nla_get_addr(struct nlattr *nla, int family) -{ - return nl_addr_build(family, nla_data(nla), nla_len(nla)); -} - -/** - * Return payload of abstract data attribute - * @arg nla abstract data netlink attribute - * - * @return Newly allocated abstract data handle or NULL - */ -struct nl_data *nla_get_data(struct nlattr *nla) -{ - return nl_data_alloc(nla_data(nla), nla_len(nla)); -} - -/** @} */ - -/** @} */