2005-11-10 04:25:51 +03:00
/*
* NETLINK Netlink attributes
*
* Authors : Thomas Graf < tgraf @ suug . ch >
* Alexey Kuznetsov < kuznet @ ms2 . inr . ac . ru >
*/
2011-11-17 06:29:17 +04:00
# include <linux/export.h>
2005-11-10 04:25:51 +03:00
# include <linux/kernel.h>
# include <linux/errno.h>
# include <linux/jiffies.h>
# include <linux/netdevice.h>
# include <linux/skbuff.h>
# include <linux/string.h>
# include <linux/types.h>
# include <net/netlink.h>
2010-11-16 20:52:32 +03:00
static const u16 nla_attr_minlen [ NLA_TYPE_MAX + 1 ] = {
2005-11-10 04:25:51 +03:00
[ NLA_U8 ] = sizeof ( u8 ) ,
[ NLA_U16 ] = sizeof ( u16 ) ,
[ NLA_U32 ] = sizeof ( u32 ) ,
[ NLA_U64 ] = sizeof ( u64 ) ,
2011-11-03 04:07:32 +04:00
[ NLA_MSECS ] = sizeof ( u64 ) ,
2005-11-10 04:25:51 +03:00
[ NLA_NESTED ] = NLA_HDRLEN ,
2012-08-26 02:47:57 +04:00
[ NLA_S8 ] = sizeof ( s8 ) ,
[ NLA_S16 ] = sizeof ( s16 ) ,
[ NLA_S32 ] = sizeof ( s32 ) ,
[ NLA_S64 ] = sizeof ( s64 ) ,
2005-11-10 04:25:51 +03:00
} ;
2010-11-16 20:52:32 +03:00
static int validate_nla ( const struct nlattr * nla , int maxtype ,
2007-06-05 23:38:30 +04:00
const struct nla_policy * policy )
2005-11-10 04:25:51 +03:00
{
2007-06-05 23:38:30 +04:00
const struct nla_policy * pt ;
2007-09-12 16:44:36 +04:00
int minlen = 0 , attrlen = nla_len ( nla ) , type = nla_type ( nla ) ;
2005-11-10 04:25:51 +03:00
2007-09-12 16:44:36 +04:00
if ( type < = 0 | | type > maxtype )
2005-11-10 04:25:51 +03:00
return 0 ;
2007-09-12 16:44:36 +04:00
pt = & policy [ type ] ;
2005-11-10 04:25:51 +03:00
BUG_ON ( pt - > type > NLA_TYPE_MAX ) ;
2006-08-27 07:11:47 +04:00
switch ( pt - > type ) {
case NLA_FLAG :
if ( attrlen > 0 )
return - ERANGE ;
break ;
2005-11-10 04:25:51 +03:00
2006-08-27 07:11:47 +04:00
case NLA_NUL_STRING :
if ( pt - > len )
minlen = min_t ( int , attrlen , pt - > len + 1 ) ;
else
minlen = attrlen ;
2005-11-10 04:25:51 +03:00
2006-08-27 07:11:47 +04:00
if ( ! minlen | | memchr ( nla_data ( nla ) , ' \0 ' , minlen ) = = NULL )
return - EINVAL ;
/* fall through */
case NLA_STRING :
if ( attrlen < 1 )
return - ERANGE ;
if ( pt - > len ) {
char * buf = nla_data ( nla ) ;
if ( buf [ attrlen - 1 ] = = ' \0 ' )
attrlen - - ;
if ( attrlen > pt - > len )
return - ERANGE ;
}
break ;
2007-03-23 21:37:48 +03:00
case NLA_BINARY :
if ( pt - > len & & attrlen > pt - > len )
return - ERANGE ;
break ;
2007-06-26 00:49:35 +04:00
case NLA_NESTED_COMPAT :
if ( attrlen < pt - > len )
return - ERANGE ;
if ( attrlen < NLA_ALIGN ( pt - > len ) )
break ;
if ( attrlen < NLA_ALIGN ( pt - > len ) + NLA_HDRLEN )
return - ERANGE ;
nla = nla_data ( nla ) + NLA_ALIGN ( pt - > len ) ;
if ( attrlen < NLA_ALIGN ( pt - > len ) + NLA_HDRLEN + nla_len ( nla ) )
return - ERANGE ;
break ;
2008-11-28 14:05:19 +03:00
case NLA_NESTED :
/* a nested attributes is allowed to be empty; if its not,
* it must have a size of at least NLA_HDRLEN .
*/
if ( attrlen = = 0 )
break ;
2006-08-27 07:11:47 +04:00
default :
if ( pt - > len )
minlen = pt - > len ;
else if ( pt - > type ! = NLA_UNSPEC )
minlen = nla_attr_minlen [ pt - > type ] ;
if ( attrlen < minlen )
return - ERANGE ;
}
2005-11-10 04:25:51 +03:00
return 0 ;
}
/**
* nla_validate - Validate a stream of attributes
* @ head : head of attribute stream
* @ len : length of attribute stream
* @ maxtype : maximum attribute type to be expected
* @ 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 .
*
* Returns 0 on success or a negative error code .
*/
2010-11-16 20:52:32 +03:00
int nla_validate ( const struct nlattr * head , int len , int maxtype ,
2007-06-05 23:38:30 +04:00
const struct nla_policy * policy )
2005-11-10 04:25:51 +03:00
{
2010-11-16 20:52:32 +03:00
const struct nlattr * nla ;
2005-11-10 04:25:51 +03:00
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 ;
}
2014-06-05 03:11:57 +04:00
EXPORT_SYMBOL ( nla_validate ) ;
2005-11-10 04:25:51 +03:00
2009-03-25 20:26:30 +03:00
/**
* nla_policy_len - Determin the max . length of a policy
* @ policy : policy to use
* @ n : number of policies
*
* Determines the max . length of the policy . It is currently used
* to allocated Netlink buffers roughly the size of the actual
* message .
*
* Returns 0 on success or a negative error code .
*/
int
nla_policy_len ( const struct nla_policy * p , int n )
{
int i , len = 0 ;
2011-02-28 23:38:25 +03:00
for ( i = 0 ; i < n ; i + + , p + + ) {
2009-03-25 20:26:30 +03:00
if ( p - > len )
len + = nla_total_size ( p - > len ) ;
else if ( nla_attr_minlen [ p - > type ] )
len + = nla_total_size ( nla_attr_minlen [ p - > type ] ) ;
}
return len ;
}
2014-06-05 03:11:57 +04:00
EXPORT_SYMBOL ( nla_policy_len ) ;
2009-03-25 20:26:30 +03:00
2005-11-10 04:25:51 +03:00
/**
* nla_parse - Parse a stream of attributes into a tb buffer
* @ tb : destination array with maxtype + 1 elements
* @ maxtype : maximum attribute type to be expected
* @ head : head of attribute stream
* @ len : length of attribute stream
2008-06-28 07:02:14 +04:00
* @ policy : validation policy
2005-11-10 04:25:51 +03:00
*
* Parses a stream of attributes and stores a pointer to each attribute in
tree-wide: fix comment/printk typos
"gadget", "through", "command", "maintain", "maintain", "controller", "address",
"between", "initiali[zs]e", "instead", "function", "select", "already",
"equal", "access", "management", "hierarchy", "registration", "interest",
"relative", "memory", "offset", "already",
Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
Signed-off-by: Jiri Kosina <jkosina@suse.cz>
2010-11-01 22:38:34 +03:00
* the tb array accessible via the attribute type . Attributes with a type
2005-11-10 04:25:51 +03:00
* exceeding maxtype will be silently ignored for backwards compatibility
* reasons . policy may be set to NULL if no validation is required .
*
* Returns 0 on success or a negative error code .
*/
2010-11-16 20:52:32 +03:00
int nla_parse ( struct nlattr * * tb , int maxtype , const struct nlattr * head ,
int len , const struct nla_policy * policy )
2005-11-10 04:25:51 +03:00
{
2010-11-16 20:52:32 +03:00
const struct nlattr * nla ;
2005-11-10 04:25:51 +03:00
int rem , err ;
memset ( tb , 0 , sizeof ( struct nlattr * ) * ( maxtype + 1 ) ) ;
nla_for_each_attr ( nla , head , len , rem ) {
2007-09-12 16:44:36 +04:00
u16 type = nla_type ( nla ) ;
2005-11-10 04:25:51 +03:00
if ( type > 0 & & type < = maxtype ) {
if ( policy ) {
err = validate_nla ( nla , maxtype , policy ) ;
if ( err < 0 )
goto errout ;
}
2010-11-16 20:52:32 +03:00
tb [ type ] = ( struct nlattr * ) nla ;
2005-11-10 04:25:51 +03:00
}
}
if ( unlikely ( rem > 0 ) )
2014-06-02 20:25:02 +04:00
pr_warn_ratelimited ( " netlink: %d bytes leftover after parsing attributes in process `%s'. \n " ,
rem , current - > comm ) ;
2005-11-10 04:25:51 +03:00
err = 0 ;
errout :
return err ;
}
2014-06-05 03:11:57 +04:00
EXPORT_SYMBOL ( nla_parse ) ;
2005-11-10 04:25:51 +03:00
/**
* nla_find - Find a specific attribute in a stream of attributes
* @ head : head of attribute stream
* @ len : length of attribute stream
* @ attrtype : type of attribute to look for
*
* Returns the first attribute in the stream matching the specified type .
*/
2010-11-16 20:52:32 +03:00
struct nlattr * nla_find ( const struct nlattr * head , int len , int attrtype )
2005-11-10 04:25:51 +03:00
{
2010-11-16 20:52:32 +03:00
const struct nlattr * nla ;
2005-11-10 04:25:51 +03:00
int rem ;
nla_for_each_attr ( nla , head , len , rem )
2007-09-12 16:44:36 +04:00
if ( nla_type ( nla ) = = attrtype )
2010-11-16 20:52:32 +03:00
return ( struct nlattr * ) nla ;
2005-11-10 04:25:51 +03:00
return NULL ;
}
2014-06-05 03:11:57 +04:00
EXPORT_SYMBOL ( nla_find ) ;
2005-11-10 04:25:51 +03:00
/**
* nla_strlcpy - Copy string attribute payload into a sized buffer
* @ dst : where to copy the string to
2008-06-28 07:02:14 +04:00
* @ nla : attribute to copy the string from
2005-11-10 04:25:51 +03:00
* @ 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 .
*
* Returns 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 ;
}
2014-06-05 03:11:57 +04:00
EXPORT_SYMBOL ( nla_strlcpy ) ;
2005-11-10 04:25:51 +03:00
/**
* nla_memcpy - Copy a netlink attribute into another memory area
* @ dest : where to copy to memcpy
* @ src : netlink attribute to copy from
* @ count : size of the destination area
*
* Note : The number of bytes copied is limited by the length of
* attribute ' s payload . memcpy
*
* Returns the number of bytes copied .
*/
2008-10-28 21:59:11 +03:00
int nla_memcpy ( void * dest , const struct nlattr * src , int count )
2005-11-10 04:25:51 +03:00
{
int minlen = min_t ( int , count , nla_len ( src ) ) ;
memcpy ( dest , nla_data ( src ) , minlen ) ;
return minlen ;
}
2014-06-05 03:11:57 +04:00
EXPORT_SYMBOL ( nla_memcpy ) ;
2005-11-10 04:25:51 +03:00
/**
* nla_memcmp - Compare an attribute with sized memory area
* @ nla : netlink attribute
* @ data : memory area
* @ 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 ;
}
2014-06-05 03:11:57 +04:00
EXPORT_SYMBOL ( nla_memcmp ) ;
2005-11-10 04:25:51 +03:00
/**
* nla_strcmp - Compare a string attribute against a string
* @ nla : netlink string attribute
* @ str : another string
*/
int nla_strcmp ( const struct nlattr * nla , const char * str )
{
2014-04-01 21:38:44 +04:00
int len = strlen ( str ) ;
char * buf = nla_data ( nla ) ;
int attrlen = nla_len ( nla ) ;
int d ;
2005-11-10 04:25:51 +03:00
2014-04-01 21:38:44 +04:00
if ( attrlen > 0 & & buf [ attrlen - 1 ] = = ' \0 ' )
attrlen - - ;
d = attrlen - len ;
2005-11-10 04:25:51 +03:00
if ( d = = 0 )
d = memcmp ( nla_data ( nla ) , str , len ) ;
return d ;
}
2014-06-05 03:11:57 +04:00
EXPORT_SYMBOL ( nla_strcmp ) ;
2005-11-10 04:25:51 +03:00
2009-03-11 18:18:32 +03:00
# ifdef CONFIG_NET
2005-11-10 04:25:51 +03:00
/**
* __nla_reserve - reserve room for attribute on the skb
* @ skb : socket buffer to reserve room on
* @ attrtype : attribute type
* @ attrlen : length of attribute payload
*
* Adds a netlink attribute header to a socket buffer and reserves
* room for the payload but does not copy it .
*
* The caller is responsible to ensure that the skb provides enough
* tailroom for the attribute header and payload .
*/
struct nlattr * __nla_reserve ( struct sk_buff * skb , int attrtype , int attrlen )
{
struct nlattr * nla ;
nla = ( struct nlattr * ) skb_put ( skb , nla_total_size ( attrlen ) ) ;
nla - > nla_type = attrtype ;
nla - > nla_len = nla_attr_size ( attrlen ) ;
memset ( ( unsigned char * ) nla + nla - > nla_len , 0 , nla_padlen ( attrlen ) ) ;
return nla ;
}
2009-03-11 18:18:32 +03:00
EXPORT_SYMBOL ( __nla_reserve ) ;
2005-11-10 04:25:51 +03:00
2006-08-05 10:03:05 +04:00
/**
* __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 ;
}
2009-03-11 18:18:32 +03:00
EXPORT_SYMBOL ( __nla_reserve_nohdr ) ;
2006-08-05 10:03:05 +04:00
2005-11-10 04:25:51 +03:00
/**
* nla_reserve - reserve room for attribute on the skb
* @ skb : socket buffer to reserve room on
* @ attrtype : attribute type
* @ attrlen : length of attribute payload
*
* Adds a netlink attribute header to a socket buffer and reserves
* room for the payload but does not copy it .
*
* Returns NULL if the tailroom of the skb is insufficient to store
* the attribute header and payload .
*/
struct nlattr * nla_reserve ( struct sk_buff * skb , int attrtype , int attrlen )
{
if ( unlikely ( skb_tailroom ( skb ) < nla_total_size ( attrlen ) ) )
return NULL ;
return __nla_reserve ( skb , attrtype , attrlen ) ;
}
2009-03-11 18:18:32 +03:00
EXPORT_SYMBOL ( nla_reserve ) ;
2005-11-10 04:25:51 +03:00
2006-08-05 10:03:05 +04:00
/**
2008-06-28 07:02:14 +04:00
* nla_reserve_nohdr - reserve room for attribute without header
2006-08-05 10:03:05 +04:00
* @ skb : socket buffer to reserve room on
2008-06-28 07:02:14 +04:00
* @ attrlen : length of attribute payload
2006-08-05 10:03:05 +04:00
*
* 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 ) ;
}
2009-03-11 18:18:32 +03:00
EXPORT_SYMBOL ( nla_reserve_nohdr ) ;
2006-08-05 10:03:05 +04:00
2005-11-10 04:25:51 +03:00
/**
* __nla_put - Add a netlink attribute to a socket buffer
* @ skb : socket buffer to add attribute to
* @ attrtype : attribute type
* @ 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 header and payload .
*/
void __nla_put ( struct sk_buff * skb , int attrtype , int attrlen ,
const void * data )
{
struct nlattr * nla ;
nla = __nla_reserve ( skb , attrtype , attrlen ) ;
memcpy ( nla_data ( nla ) , data , attrlen ) ;
}
2009-03-11 18:18:32 +03:00
EXPORT_SYMBOL ( __nla_put ) ;
2005-11-10 04:25:51 +03:00
2006-08-05 10:03:05 +04:00
/**
* __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 ) ;
}
2009-03-11 18:18:32 +03:00
EXPORT_SYMBOL ( __nla_put_nohdr ) ;
2005-11-10 04:25:51 +03:00
/**
* nla_put - Add a netlink attribute to a socket buffer
* @ skb : socket buffer to add attribute to
* @ attrtype : attribute type
* @ attrlen : length of attribute payload
* @ data : head of attribute payload
*
2008-06-04 03:36:54 +04:00
* Returns - EMSGSIZE if the tailroom of the skb is insufficient to store
2005-11-10 04:25:51 +03:00
* the attribute header and payload .
*/
int nla_put ( struct sk_buff * skb , int attrtype , int attrlen , const void * data )
{
if ( unlikely ( skb_tailroom ( skb ) < nla_total_size ( attrlen ) ) )
2008-06-04 03:36:54 +04:00
return - EMSGSIZE ;
2005-11-10 04:25:51 +03:00
__nla_put ( skb , attrtype , attrlen , data ) ;
return 0 ;
}
2009-03-11 18:18:32 +03:00
EXPORT_SYMBOL ( nla_put ) ;
2005-11-10 04:25:51 +03:00
2006-08-05 10:03:05 +04:00
/**
* 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
*
2008-06-04 03:36:54 +04:00
* Returns - EMSGSIZE if the tailroom of the skb is insufficient to store
2006-08-05 10:03:05 +04:00
* the attribute payload .
*/
int nla_put_nohdr ( struct sk_buff * skb , int attrlen , const void * data )
{
if ( unlikely ( skb_tailroom ( skb ) < NLA_ALIGN ( attrlen ) ) )
2008-06-04 03:36:54 +04:00
return - EMSGSIZE ;
2006-08-05 10:03:05 +04:00
__nla_put_nohdr ( skb , attrlen , data ) ;
return 0 ;
}
2009-03-11 18:18:32 +03:00
EXPORT_SYMBOL ( nla_put_nohdr ) ;
2005-11-10 04:25:51 +03:00
2008-01-23 09:10:59 +03:00
/**
* nla_append - Add a netlink attribute without header or padding
* @ skb : socket buffer to add attribute to
* @ attrlen : length of attribute payload
* @ data : head of attribute payload
*
2008-06-04 03:36:54 +04:00
* Returns - EMSGSIZE if the tailroom of the skb is insufficient to store
2008-01-23 09:10:59 +03:00
* the attribute payload .
*/
int nla_append ( struct sk_buff * skb , int attrlen , const void * data )
{
if ( unlikely ( skb_tailroom ( skb ) < NLA_ALIGN ( attrlen ) ) )
2008-06-04 03:36:54 +04:00
return - EMSGSIZE ;
2008-01-23 09:10:59 +03:00
memcpy ( skb_put ( skb , attrlen ) , data , attrlen ) ;
return 0 ;
}
2009-03-11 18:18:32 +03:00
EXPORT_SYMBOL ( nla_append ) ;
# endif