Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit fe4944e5 authored by Thomas Graf's avatar Thomas Graf Committed by David S. Miller
Browse files

[NETLINK]: Extend netlink messaging interface



Adds:
 nlmsg_get_pos()                 return current position in message
 nlmsg_trim()                    trim part of message
 nla_reserve_nohdr(skb, len)     reserve room for an attribute w/o hdr
 nla_put_nohdr(skb, len, data)   add attribute w/o hdr
 nla_find_nested()               find attribute in nested attributes

Fixes nlmsg_new() to take allocation flags and consider size.

Signed-off-by: default avatarThomas Graf <tgraf@suug.ch>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent e1ef4bf2
Loading
Loading
Loading
Loading
+64 −10
Original line number Diff line number Diff line
@@ -35,6 +35,8 @@
 *   nlmsg_put()			add a netlink message to an skb
 *   nlmsg_put_answer()			callback based nlmsg_put()
 *   nlmsg_end()			finanlize netlink message
 *   nlmsg_get_pos()			return current position in message
 *   nlmsg_trim()			trim part of message
 *   nlmsg_cancel()			cancel message construction
 *   nlmsg_free()			free a netlink message
 *
@@ -80,8 +82,10 @@
 *   struct nlattr			netlink attribtue header
 *
 * Attribute Construction:
 *   nla_reserve(skb, type, len)	reserve skb tailroom for an attribute
 *   nla_reserve(skb, type, len)	reserve room for an attribute
 *   nla_reserve_nohdr(skb, len)	reserve room for an attribute w/o hdr
 *   nla_put(skb, type, len, data)	add attribute to skb
 *   nla_put_nohdr(skb, len, data)	add attribute w/o hdr
 *
 * Attribute Construction for Basic Types:
 *   nla_put_u8(skb, type, value)	add u8 attribute to skb
@@ -139,6 +143,7 @@
 *   nla_next(nla, remaining)		get next netlink attribute
 *   nla_validate()			validate a stream of attributes
 *   nla_find()				find attribute in stream of attributes
 *   nla_find_nested()			find attribute in nested attributes
 *   nla_parse()			parse and validate stream of attrs
 *   nla_parse_nested()			parse nested attribuets
 *   nla_for_each_attr()		loop over all attributes
@@ -203,12 +208,18 @@ extern int nla_memcmp(const struct nlattr *nla, const void *data,
extern int		nla_strcmp(const struct nlattr *nla, const char *str);
extern struct nlattr *	__nla_reserve(struct sk_buff *skb, int attrtype,
				      int attrlen);
extern void *		__nla_reserve_nohdr(struct sk_buff *skb, int attrlen);
extern struct nlattr *	nla_reserve(struct sk_buff *skb, int attrtype,
				    int attrlen);
extern void *		nla_reserve_nohdr(struct sk_buff *skb, int attrlen);
extern void		__nla_put(struct sk_buff *skb, int attrtype,
				  int attrlen, const void *data);
extern void		__nla_put_nohdr(struct sk_buff *skb, int attrlen,
					const void *data);
extern int		nla_put(struct sk_buff *skb, int attrtype,
				int attrlen, const void *data);
extern int		nla_put_nohdr(struct sk_buff *skb, int attrlen,
				      const void *data);

/**************************************************************************
 * Netlink Messages
@@ -453,12 +464,13 @@ static inline struct nlmsghdr *nlmsg_put_answer(struct sk_buff *skb,
/**
 * nlmsg_new - Allocate a new netlink message
 * @size: maximum size of message
 * @flags: the type of memory to allocate.
 *
 * Use NLMSG_GOODSIZE if size isn't know and you need a good default size.
 */
static inline struct sk_buff *nlmsg_new(int size)
static inline struct sk_buff *nlmsg_new(int size, gfp_t flags)
{
	return alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL);
	return alloc_skb(size, flags);
}

/**
@@ -479,6 +491,32 @@ static inline int nlmsg_end(struct sk_buff *skb, struct nlmsghdr *nlh)
	return skb->len;
}

/**
 * nlmsg_get_pos - return current position in netlink message
 * @skb: socket buffer the message is stored in
 *
 * Returns a pointer to the current tail of the message.
 */
static inline void *nlmsg_get_pos(struct sk_buff *skb)
{
	return skb->tail;
}

/**
 * nlmsg_trim - Trim message to a mark
 * @skb: socket buffer the message is stored in
 * @mark: mark to trim to
 *
 * Trims the message to the provided mark. Returns -1.
 */
static inline int nlmsg_trim(struct sk_buff *skb, void *mark)
{
	if (mark)
		skb_trim(skb, (unsigned char *) mark - skb->data);

	return -1;
}

/**
 * nlmsg_cancel - Cancel construction of a netlink message
 * @skb: socket buffer the message is stored in
@@ -489,9 +527,7 @@ static inline int nlmsg_end(struct sk_buff *skb, struct nlmsghdr *nlh)
 */
static inline int nlmsg_cancel(struct sk_buff *skb, struct nlmsghdr *nlh)
{
	skb_trim(skb, (unsigned char *) nlh - skb->data);

	return -1;
	return nlmsg_trim(skb, nlh);
}

/**
@@ -630,6 +666,18 @@ static inline struct nlattr *nla_next(const struct nlattr *nla, int *remaining)
	return (struct nlattr *) ((char *) nla + totlen);
}

/**
 * nla_find_nested - find attribute in a set of nested attributes
 * @nla: attribute containing the nested attributes
 * @attrtype: type of attribute to look for
 *
 * Returns the first attribute which matches the specified type.
 */
static inline struct nlattr *nla_find_nested(struct nlattr *nla, int attrtype)
{
	return nla_find(nla_data(nla), nla_len(nla), attrtype);
}

/**
 * nla_parse_nested - parse nested attributes
 * @tb: destination array with maxtype+1 elements
@@ -862,10 +910,7 @@ static inline int nla_nest_end(struct sk_buff *skb, struct nlattr *start)
 */
static inline int nla_nest_cancel(struct sk_buff *skb, struct nlattr *start)
{
	if (start)
		skb_trim(skb, (unsigned char *) start - skb->data);

	return -1;
	return nlmsg_trim(skb, start);
}

/**
@@ -880,4 +925,13 @@ static inline int nla_nest_cancel(struct sk_buff *skb, struct nlattr *start)
	     nla_ok(pos, rem); \
	     pos = nla_next(pos, &(rem)))

/**
 * nla_for_each_nested - iterate over nested attributes
 * @pos: loop counter, set to current attribute
 * @nla: attribute containing the nested attributes
 * @rem: initialized to len, holds bytes currently remaining in stream
 */
#define nla_for_each_nested(pos, nla, rem) \
	nla_for_each_attr(pos, nla_data(nla), nla_len(nla), rem)

#endif
+1 −1
Original line number Diff line number Diff line
@@ -75,7 +75,7 @@ static int prepare_reply(struct genl_info *info, u8 cmd, struct sk_buff **skbp,
	/*
	 * If new attributes are added, please revisit this allocation
	 */
	skb = nlmsg_new(size);
	skb = nlmsg_new(size, GFP_KERNEL);
	if (!skb)
		return -ENOMEM;

+75 −0
Original line number Diff line number Diff line
@@ -254,6 +254,26 @@ struct nlattr *__nla_reserve(struct sk_buff *skb, int attrtype, int attrlen)
	return nla;
}

/**
 * __nla_reserve_nohdr - reserve room for attribute without header
 * @skb: socket buffer to reserve room on
 * @attrlen: length of attribute payload
 *
 * Reserves room for attribute payload without a header.
 *
 * The caller is responsible to ensure that the skb provides enough
 * tailroom for the payload.
 */
void *__nla_reserve_nohdr(struct sk_buff *skb, int attrlen)
{
	void *start;

	start = skb_put(skb, NLA_ALIGN(attrlen));
	memset(start, 0, NLA_ALIGN(attrlen));

	return start;
}

/**
 * nla_reserve - reserve room for attribute on the skb
 * @skb: socket buffer to reserve room on
@@ -274,6 +294,24 @@ struct nlattr *nla_reserve(struct sk_buff *skb, int attrtype, int attrlen)
	return __nla_reserve(skb, attrtype, attrlen);
}

/**
 * nla_reserve - reserve room for attribute without header
 * @skb: socket buffer to reserve room on
 * @len: length of attribute payload
 *
 * Reserves room for attribute payload without a header.
 *
 * Returns NULL if the tailroom of the skb is insufficient to store
 * the attribute payload.
 */
void *nla_reserve_nohdr(struct sk_buff *skb, int attrlen)
{
	if (unlikely(skb_tailroom(skb) < NLA_ALIGN(attrlen)))
		return NULL;

	return __nla_reserve_nohdr(skb, attrlen);
}

/**
 * __nla_put - Add a netlink attribute to a socket buffer
 * @skb: socket buffer to add attribute to
@@ -293,6 +331,22 @@ void __nla_put(struct sk_buff *skb, int attrtype, int attrlen,
	memcpy(nla_data(nla), data, attrlen);
}

/**
 * __nla_put_nohdr - Add a netlink attribute without header
 * @skb: socket buffer to add attribute to
 * @attrlen: length of attribute payload
 * @data: head of attribute payload
 *
 * The caller is responsible to ensure that the skb provides enough
 * tailroom for the attribute payload.
 */
void __nla_put_nohdr(struct sk_buff *skb, int attrlen, const void *data)
{
	void *start;

	start = __nla_reserve_nohdr(skb, attrlen);
	memcpy(start, data, attrlen);
}

/**
 * nla_put - Add a netlink attribute to a socket buffer
@@ -313,15 +367,36 @@ int nla_put(struct sk_buff *skb, int attrtype, int attrlen, const void *data)
	return 0;
}

/**
 * nla_put_nohdr - Add a netlink attribute without header
 * @skb: socket buffer to add attribute to
 * @attrlen: length of attribute payload
 * @data: head of attribute payload
 *
 * Returns -1 if the tailroom of the skb is insufficient to store
 * the attribute payload.
 */
int nla_put_nohdr(struct sk_buff *skb, int attrlen, const void *data)
{
	if (unlikely(skb_tailroom(skb) < NLA_ALIGN(attrlen)))
		return -1;

	__nla_put_nohdr(skb, attrlen, data);
	return 0;
}

EXPORT_SYMBOL(nla_validate);
EXPORT_SYMBOL(nla_parse);
EXPORT_SYMBOL(nla_find);
EXPORT_SYMBOL(nla_strlcpy);
EXPORT_SYMBOL(__nla_reserve);
EXPORT_SYMBOL(__nla_reserve_nohdr);
EXPORT_SYMBOL(nla_reserve);
EXPORT_SYMBOL(nla_reserve_nohdr);
EXPORT_SYMBOL(__nla_put);
EXPORT_SYMBOL(__nla_put_nohdr);
EXPORT_SYMBOL(nla_put);
EXPORT_SYMBOL(nla_put_nohdr);
EXPORT_SYMBOL(nla_memcpy);
EXPORT_SYMBOL(nla_memcmp);
EXPORT_SYMBOL(nla_strcmp);
+1 −1
Original line number Diff line number Diff line
@@ -440,7 +440,7 @@ static struct sk_buff *ctrl_build_msg(struct genl_family *family, u32 pid,
	struct sk_buff *skb;
	int err;

	skb = nlmsg_new(NLMSG_GOODSIZE);
	skb = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
	if (skb == NULL)
		return ERR_PTR(-ENOBUFS);