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

[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
...@@ -35,6 +35,8 @@ ...@@ -35,6 +35,8 @@
* nlmsg_put() add a netlink message to an skb * nlmsg_put() add a netlink message to an skb
* nlmsg_put_answer() callback based nlmsg_put() * nlmsg_put_answer() callback based nlmsg_put()
* nlmsg_end() finanlize netlink message * 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_cancel() cancel message construction
* nlmsg_free() free a netlink message * nlmsg_free() free a netlink message
* *
...@@ -80,8 +82,10 @@ ...@@ -80,8 +82,10 @@
* struct nlattr netlink attribtue header * struct nlattr netlink attribtue header
* *
* Attribute Construction: * 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(skb, type, len, data) add attribute to skb
* nla_put_nohdr(skb, len, data) add attribute w/o hdr
* *
* Attribute Construction for Basic Types: * Attribute Construction for Basic Types:
* nla_put_u8(skb, type, value) add u8 attribute to skb * nla_put_u8(skb, type, value) add u8 attribute to skb
...@@ -139,6 +143,7 @@ ...@@ -139,6 +143,7 @@
* nla_next(nla, remaining) get next netlink attribute * nla_next(nla, remaining) get next netlink attribute
* nla_validate() validate a stream of attributes * nla_validate() validate a stream of attributes
* nla_find() find attribute in 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() parse and validate stream of attrs
* nla_parse_nested() parse nested attribuets * nla_parse_nested() parse nested attribuets
* nla_for_each_attr() loop over all attributes * nla_for_each_attr() loop over all attributes
...@@ -203,12 +208,18 @@ extern int nla_memcmp(const struct nlattr *nla, const void *data, ...@@ -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 int nla_strcmp(const struct nlattr *nla, const char *str);
extern struct nlattr * __nla_reserve(struct sk_buff *skb, int attrtype, extern struct nlattr * __nla_reserve(struct sk_buff *skb, int attrtype,
int attrlen); int attrlen);
extern void * __nla_reserve_nohdr(struct sk_buff *skb, int attrlen);
extern struct nlattr * nla_reserve(struct sk_buff *skb, int attrtype, extern struct nlattr * nla_reserve(struct sk_buff *skb, int attrtype,
int attrlen); int attrlen);
extern void * nla_reserve_nohdr(struct sk_buff *skb, int attrlen);
extern void __nla_put(struct sk_buff *skb, int attrtype, extern void __nla_put(struct sk_buff *skb, int attrtype,
int attrlen, const void *data); 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, extern int nla_put(struct sk_buff *skb, int attrtype,
int attrlen, const void *data); int attrlen, const void *data);
extern int nla_put_nohdr(struct sk_buff *skb, int attrlen,
const void *data);
/************************************************************************** /**************************************************************************
* Netlink Messages * Netlink Messages
...@@ -453,12 +464,13 @@ static inline struct nlmsghdr *nlmsg_put_answer(struct sk_buff *skb, ...@@ -453,12 +464,13 @@ static inline struct nlmsghdr *nlmsg_put_answer(struct sk_buff *skb,
/** /**
* nlmsg_new - Allocate a new netlink message * nlmsg_new - Allocate a new netlink message
* @size: maximum size of 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. * 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) ...@@ -479,6 +491,32 @@ static inline int nlmsg_end(struct sk_buff *skb, struct nlmsghdr *nlh)
return skb->len; 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 * nlmsg_cancel - Cancel construction of a netlink message
* @skb: socket buffer the message is stored in * @skb: socket buffer the message is stored in
...@@ -489,9 +527,7 @@ static inline int nlmsg_end(struct sk_buff *skb, struct nlmsghdr *nlh) ...@@ -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) static inline int nlmsg_cancel(struct sk_buff *skb, struct nlmsghdr *nlh)
{ {
skb_trim(skb, (unsigned char *) nlh - skb->data); return nlmsg_trim(skb, nlh);
return -1;
} }
/** /**
...@@ -630,6 +666,18 @@ static inline struct nlattr *nla_next(const struct nlattr *nla, int *remaining) ...@@ -630,6 +666,18 @@ static inline struct nlattr *nla_next(const struct nlattr *nla, int *remaining)
return (struct nlattr *) ((char *) nla + totlen); 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 * nla_parse_nested - parse nested attributes
* @tb: destination array with maxtype+1 elements * @tb: destination array with maxtype+1 elements
...@@ -862,10 +910,7 @@ static inline int nla_nest_end(struct sk_buff *skb, struct nlattr *start) ...@@ -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) static inline int nla_nest_cancel(struct sk_buff *skb, struct nlattr *start)
{ {
if (start) return nlmsg_trim(skb, start);
skb_trim(skb, (unsigned char *) start - skb->data);
return -1;
} }
/** /**
...@@ -880,4 +925,13 @@ static inline int nla_nest_cancel(struct sk_buff *skb, struct nlattr *start) ...@@ -880,4 +925,13 @@ static inline int nla_nest_cancel(struct sk_buff *skb, struct nlattr *start)
nla_ok(pos, rem); \ nla_ok(pos, rem); \
pos = nla_next(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 #endif
...@@ -75,7 +75,7 @@ static int prepare_reply(struct genl_info *info, u8 cmd, struct sk_buff **skbp, ...@@ -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 * If new attributes are added, please revisit this allocation
*/ */
skb = nlmsg_new(size); skb = nlmsg_new(size, GFP_KERNEL);
if (!skb) if (!skb)
return -ENOMEM; return -ENOMEM;
......
...@@ -254,6 +254,26 @@ struct nlattr *__nla_reserve(struct sk_buff *skb, int attrtype, int attrlen) ...@@ -254,6 +254,26 @@ struct nlattr *__nla_reserve(struct sk_buff *skb, int attrtype, int attrlen)
return nla; 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 * nla_reserve - reserve room for attribute on the skb
* @skb: socket buffer to reserve room on * @skb: socket buffer to reserve room on
...@@ -274,6 +294,24 @@ struct nlattr *nla_reserve(struct sk_buff *skb, int attrtype, int attrlen) ...@@ -274,6 +294,24 @@ struct nlattr *nla_reserve(struct sk_buff *skb, int attrtype, int attrlen)
return __nla_reserve(skb, attrtype, 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 * __nla_put - Add a netlink attribute to a socket buffer
* @skb: socket buffer to add attribute to * @skb: socket buffer to add attribute to
...@@ -293,6 +331,22 @@ void __nla_put(struct sk_buff *skb, int attrtype, int attrlen, ...@@ -293,6 +331,22 @@ void __nla_put(struct sk_buff *skb, int attrtype, int attrlen,
memcpy(nla_data(nla), data, 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 * 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) ...@@ -313,15 +367,36 @@ int nla_put(struct sk_buff *skb, int attrtype, int attrlen, const void *data)
return 0; 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_validate);
EXPORT_SYMBOL(nla_parse); EXPORT_SYMBOL(nla_parse);
EXPORT_SYMBOL(nla_find); EXPORT_SYMBOL(nla_find);
EXPORT_SYMBOL(nla_strlcpy); EXPORT_SYMBOL(nla_strlcpy);
EXPORT_SYMBOL(__nla_reserve); EXPORT_SYMBOL(__nla_reserve);
EXPORT_SYMBOL(__nla_reserve_nohdr);
EXPORT_SYMBOL(nla_reserve); EXPORT_SYMBOL(nla_reserve);
EXPORT_SYMBOL(nla_reserve_nohdr);
EXPORT_SYMBOL(__nla_put); EXPORT_SYMBOL(__nla_put);
EXPORT_SYMBOL(__nla_put_nohdr);
EXPORT_SYMBOL(nla_put); EXPORT_SYMBOL(nla_put);
EXPORT_SYMBOL(nla_put_nohdr);
EXPORT_SYMBOL(nla_memcpy); EXPORT_SYMBOL(nla_memcpy);
EXPORT_SYMBOL(nla_memcmp); EXPORT_SYMBOL(nla_memcmp);
EXPORT_SYMBOL(nla_strcmp); EXPORT_SYMBOL(nla_strcmp);
...@@ -440,7 +440,7 @@ static struct sk_buff *ctrl_build_msg(struct genl_family *family, u32 pid, ...@@ -440,7 +440,7 @@ static struct sk_buff *ctrl_build_msg(struct genl_family *family, u32 pid,
struct sk_buff *skb; struct sk_buff *skb;
int err; int err;
skb = nlmsg_new(NLMSG_GOODSIZE); skb = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
if (skb == NULL) if (skb == NULL)
return ERR_PTR(-ENOBUFS); return ERR_PTR(-ENOBUFS);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment