2005-04-17 02:20:36 +04:00
/*********************************************************************
*
* Filename : parameters . c
* Version : 1.0
* Description : A more general way to handle ( pi , pl , pv ) parameters
* Status : Experimental .
* Author : Dag Brattli < dagb @ cs . uit . no >
* Created at : Mon Jun 7 10 : 25 : 11 1999
* Modified at : Sun Jan 30 14 : 08 : 39 2000
* Modified by : Dag Brattli < dagb @ cs . uit . no >
*
* Copyright ( c ) 1999 - 2000 Dag Brattli , All Rights Reserved .
*
* This program is free software ; you can redistribute it and / or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation ; either version 2 of
* the License , or ( at your option ) any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
2013-12-06 21:13:43 +04:00
* along with this program ; if not , see < http : //www.gnu.org/licenses/>.
2005-04-17 02:20:36 +04:00
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
# include <linux/types.h>
# include <linux/module.h>
# include <asm/unaligned.h>
# include <asm/byteorder.h>
# include <net/irda/irda.h>
# include <net/irda/parameters.h>
static int irda_extract_integer ( void * self , __u8 * buf , int len , __u8 pi ,
PV_TYPE type , PI_HANDLER func ) ;
static int irda_extract_string ( void * self , __u8 * buf , int len , __u8 pi ,
PV_TYPE type , PI_HANDLER func ) ;
static int irda_extract_octseq ( void * self , __u8 * buf , int len , __u8 pi ,
PV_TYPE type , PI_HANDLER func ) ;
static int irda_extract_no_value ( void * self , __u8 * buf , int len , __u8 pi ,
PV_TYPE type , PI_HANDLER func ) ;
static int irda_insert_integer ( void * self , __u8 * buf , int len , __u8 pi ,
PV_TYPE type , PI_HANDLER func ) ;
static int irda_insert_no_value ( void * self , __u8 * buf , int len , __u8 pi ,
PV_TYPE type , PI_HANDLER func ) ;
static int irda_param_unpack ( __u8 * buf , char * fmt , . . . ) ;
/* Parameter value call table. Must match PV_TYPE */
2014-12-10 21:28:58 +03:00
static const PV_HANDLER pv_extract_table [ ] = {
2005-04-17 02:20:36 +04:00
irda_extract_integer , /* Handler for any length integers */
irda_extract_integer , /* Handler for 8 bits integers */
irda_extract_integer , /* Handler for 16 bits integers */
irda_extract_string , /* Handler for strings */
irda_extract_integer , /* Handler for 32 bits integers */
irda_extract_octseq , /* Handler for octet sequences */
irda_extract_no_value /* Handler for no value parameters */
} ;
2014-12-10 21:28:58 +03:00
static const PV_HANDLER pv_insert_table [ ] = {
2005-04-17 02:20:36 +04:00
irda_insert_integer , /* Handler for any length integers */
irda_insert_integer , /* Handler for 8 bits integers */
irda_insert_integer , /* Handler for 16 bits integers */
NULL , /* Handler for strings */
irda_insert_integer , /* Handler for 32 bits integers */
NULL , /* Handler for octet sequences */
irda_insert_no_value /* Handler for no value parameters */
} ;
/*
* Function irda_insert_no_value ( self , buf , len , pi , type , func )
*/
static int irda_insert_no_value ( void * self , __u8 * buf , int len , __u8 pi ,
PV_TYPE type , PI_HANDLER func )
{
irda_param_t p ;
int ret ;
p . pi = pi ;
p . pl = 0 ;
/* Call handler for this parameter */
ret = ( * func ) ( self , & p , PV_GET ) ;
/* Extract values anyway, since handler may need them */
irda_param_pack ( buf , " bb " , p . pi , p . pl ) ;
if ( ret < 0 )
return ret ;
return 2 ; /* Inserted pl+2 bytes */
}
/*
* Function irda_extract_no_value ( self , buf , len , type , func )
*
* Extracts a parameter without a pv field ( pl = 0 )
*
*/
static int irda_extract_no_value ( void * self , __u8 * buf , int len , __u8 pi ,
PV_TYPE type , PI_HANDLER func )
{
irda_param_t p ;
int ret ;
/* Extract values anyway, since handler may need them */
irda_param_unpack ( buf , " bb " , & p . pi , & p . pl ) ;
/* Call handler for this parameter */
ret = ( * func ) ( self , & p , PV_PUT ) ;
if ( ret < 0 )
return ret ;
return 2 ; /* Extracted pl+2 bytes */
}
/*
* Function irda_insert_integer ( self , buf , len , pi , type , func )
*/
static int irda_insert_integer ( void * self , __u8 * buf , int len , __u8 pi ,
PV_TYPE type , PI_HANDLER func )
{
irda_param_t p ;
int n = 0 ;
int err ;
p . pi = pi ; /* In case handler needs to know */
2007-12-21 01:00:51 +03:00
p . pl = type & PV_MASK ; /* The integer type codes the length as well */
2005-04-17 02:20:36 +04:00
p . pv . i = 0 ; /* Clear value */
/* Call handler for this parameter */
err = ( * func ) ( self , & p , PV_GET ) ;
if ( err < 0 )
return err ;
/*
2007-12-21 01:00:51 +03:00
* If parameter length is still 0 , then ( 1 ) this is an any length
2005-04-17 02:20:36 +04:00
* integer , and ( 2 ) the handler function does not care which length
* we choose to use , so we pick the one the gives the fewest bytes .
*/
if ( p . pl = = 0 ) {
if ( p . pv . i < 0xff ) {
2014-11-12 01:44:57 +03:00
pr_debug ( " %s(), using 1 byte \n " , __func__ ) ;
2005-04-17 02:20:36 +04:00
p . pl = 1 ;
} else if ( p . pv . i < 0xffff ) {
2014-11-12 01:44:57 +03:00
pr_debug ( " %s(), using 2 bytes \n " , __func__ ) ;
2005-04-17 02:20:36 +04:00
p . pl = 2 ;
} else {
2014-11-12 01:44:57 +03:00
pr_debug ( " %s(), using 4 bytes \n " , __func__ ) ;
2005-04-17 02:20:36 +04:00
p . pl = 4 ; /* Default length */
}
}
/* Check if buffer is long enough for insertion */
if ( len < ( 2 + p . pl ) ) {
2014-11-12 00:37:30 +03:00
net_warn_ratelimited ( " %s: buffer too short for insertion! \n " ,
__func__ ) ;
2005-04-17 02:20:36 +04:00
return - 1 ;
}
2014-11-12 01:44:57 +03:00
pr_debug ( " %s(), pi=%#x, pl=%d, pi=%d \n " , __func__ ,
p . pi , p . pl , p . pv . i ) ;
2005-04-17 02:20:36 +04:00
switch ( p . pl ) {
case 1 :
n + = irda_param_pack ( buf , " bbb " , p . pi , p . pl , ( __u8 ) p . pv . i ) ;
break ;
case 2 :
if ( type & PV_BIG_ENDIAN )
p . pv . i = cpu_to_be16 ( ( __u16 ) p . pv . i ) ;
else
p . pv . i = cpu_to_le16 ( ( __u16 ) p . pv . i ) ;
n + = irda_param_pack ( buf , " bbs " , p . pi , p . pl , ( __u16 ) p . pv . i ) ;
break ;
case 4 :
if ( type & PV_BIG_ENDIAN )
cpu_to_be32s ( & p . pv . i ) ;
else
cpu_to_le32s ( & p . pv . i ) ;
n + = irda_param_pack ( buf , " bbi " , p . pi , p . pl , p . pv . i ) ;
break ;
default :
2014-11-12 00:37:30 +03:00
net_warn_ratelimited ( " %s: length %d not supported \n " ,
__func__ , p . pl ) ;
2005-04-17 02:20:36 +04:00
/* Skip parameter */
return - 1 ;
}
return p . pl + 2 ; /* Inserted pl+2 bytes */
}
/*
* Function irda_extract integer ( self , buf , len , pi , type , func )
*
* Extract a possibly variable length integer from buffer , and call
* handler for processing of the parameter
*/
static int irda_extract_integer ( void * self , __u8 * buf , int len , __u8 pi ,
PV_TYPE type , PI_HANDLER func )
{
irda_param_t p ;
int n = 0 ;
2007-12-21 01:00:51 +03:00
int extract_len ; /* Real length we extract */
2005-04-17 02:20:36 +04:00
int err ;
p . pi = pi ; /* In case handler needs to know */
2007-12-21 01:00:51 +03:00
p . pl = buf [ 1 ] ; /* Extract length of value */
2005-04-17 02:20:36 +04:00
p . pv . i = 0 ; /* Clear value */
extract_len = p . pl ; /* Default : extract all */
/* Check if buffer is long enough for parsing */
if ( len < ( 2 + p . pl ) ) {
2014-11-12 00:37:30 +03:00
net_warn_ratelimited ( " %s: buffer too short for parsing! Need %d bytes, but len is only %d \n " ,
__func__ , p . pl , len ) ;
2005-04-17 02:20:36 +04:00
return - 1 ;
}
/*
* Check that the integer length is what we expect it to be . If the
* handler want a 16 bits integer then a 32 bits is not good enough
* PV_INTEGER means that the handler is flexible .
*/
if ( ( ( type & PV_MASK ) ! = PV_INTEGER ) & & ( ( type & PV_MASK ) ! = p . pl ) ) {
2014-11-12 00:37:30 +03:00
net_err_ratelimited ( " %s: invalid parameter length! Expected %d bytes, but value had %d bytes! \n " ,
__func__ , type & PV_MASK , p . pl ) ;
2005-04-17 02:20:36 +04:00
/* Most parameters are bit/byte fields or little endian,
* so it ' s ok to only extract a subset of it ( the subset
* that the handler expect ) . This is necessary , as some
* broken implementations seems to add extra undefined bits .
* If the parameter is shorter than we expect or is big
* endian , we can ' t play those tricks . Jean II */
if ( ( p . pl < ( type & PV_MASK ) ) | | ( type & PV_BIG_ENDIAN ) ) {
/* Skip parameter */
return p . pl + 2 ;
} else {
/* Extract subset of it, fallthrough */
extract_len = type & PV_MASK ;
}
}
switch ( extract_len ) {
case 1 :
n + = irda_param_unpack ( buf + 2 , " b " , & p . pv . i ) ;
break ;
case 2 :
n + = irda_param_unpack ( buf + 2 , " s " , & p . pv . i ) ;
if ( type & PV_BIG_ENDIAN )
p . pv . i = be16_to_cpu ( ( __u16 ) p . pv . i ) ;
else
p . pv . i = le16_to_cpu ( ( __u16 ) p . pv . i ) ;
break ;
case 4 :
n + = irda_param_unpack ( buf + 2 , " i " , & p . pv . i ) ;
if ( type & PV_BIG_ENDIAN )
be32_to_cpus ( & p . pv . i ) ;
else
le32_to_cpus ( & p . pv . i ) ;
break ;
default :
2014-11-12 00:37:30 +03:00
net_warn_ratelimited ( " %s: length %d not supported \n " ,
__func__ , p . pl ) ;
2005-04-17 02:20:36 +04:00
/* Skip parameter */
return p . pl + 2 ;
}
2014-11-12 01:44:57 +03:00
pr_debug ( " %s(), pi=%#x, pl=%d, pi=%d \n " , __func__ ,
p . pi , p . pl , p . pv . i ) ;
2005-04-17 02:20:36 +04:00
/* Call handler for this parameter */
err = ( * func ) ( self , & p , PV_PUT ) ;
if ( err < 0 )
return err ;
return p . pl + 2 ; /* Extracted pl+2 bytes */
}
/*
* Function irda_extract_string ( self , buf , len , type , func )
*/
static int irda_extract_string ( void * self , __u8 * buf , int len , __u8 pi ,
PV_TYPE type , PI_HANDLER func )
{
char str [ 33 ] ;
irda_param_t p ;
int err ;
p . pi = pi ; /* In case handler needs to know */
2007-12-21 01:00:51 +03:00
p . pl = buf [ 1 ] ; /* Extract length of value */
2010-10-11 03:17:56 +04:00
if ( p . pl > 32 )
p . pl = 32 ;
2005-04-17 02:20:36 +04:00
2014-11-12 01:44:57 +03:00
pr_debug ( " %s(), pi=%#x, pl=%d \n " , __func__ ,
p . pi , p . pl ) ;
2005-04-17 02:20:36 +04:00
/* Check if buffer is long enough for parsing */
if ( len < ( 2 + p . pl ) ) {
2014-11-12 00:37:30 +03:00
net_warn_ratelimited ( " %s: buffer too short for parsing! Need %d bytes, but len is only %d \n " ,
__func__ , p . pl , len ) ;
2005-04-17 02:20:36 +04:00
return - 1 ;
}
/* Should be safe to copy string like this since we have already
* checked that the buffer is long enough */
strncpy ( str , buf + 2 , p . pl ) ;
2014-11-12 01:44:57 +03:00
pr_debug ( " %s(), str=0x%02x 0x%02x \n " ,
__func__ , ( __u8 ) str [ 0 ] , ( __u8 ) str [ 1 ] ) ;
2005-04-17 02:20:36 +04:00
/* Null terminate string */
2010-10-11 03:17:56 +04:00
str [ p . pl ] = ' \0 ' ;
2005-04-17 02:20:36 +04:00
p . pv . c = str ; /* Handler will need to take a copy */
/* Call handler for this parameter */
err = ( * func ) ( self , & p , PV_PUT ) ;
if ( err < 0 )
return err ;
return p . pl + 2 ; /* Extracted pl+2 bytes */
}
/*
* Function irda_extract_octseq ( self , buf , len , type , func )
*/
static int irda_extract_octseq ( void * self , __u8 * buf , int len , __u8 pi ,
PV_TYPE type , PI_HANDLER func )
{
irda_param_t p ;
p . pi = pi ; /* In case handler needs to know */
2007-12-21 01:00:51 +03:00
p . pl = buf [ 1 ] ; /* Extract length of value */
2005-04-17 02:20:36 +04:00
/* Check if buffer is long enough for parsing */
if ( len < ( 2 + p . pl ) ) {
2014-11-12 00:37:30 +03:00
net_warn_ratelimited ( " %s: buffer too short for parsing! Need %d bytes, but len is only %d \n " ,
__func__ , p . pl , len ) ;
2005-04-17 02:20:36 +04:00
return - 1 ;
}
2014-11-12 01:44:57 +03:00
pr_debug ( " %s(), not impl \n " , __func__ ) ;
2005-04-17 02:20:36 +04:00
return p . pl + 2 ; /* Extracted pl+2 bytes */
}
/*
* Function irda_param_pack ( skb , fmt , . . . )
*
* Format :
* ' i ' = 32 bits integer
* ' s ' = string
*
*/
int irda_param_pack ( __u8 * buf , char * fmt , . . . )
{
irda_pv_t arg ;
va_list args ;
char * p ;
int n = 0 ;
va_start ( args , fmt ) ;
for ( p = fmt ; * p ! = ' \0 ' ; p + + ) {
switch ( * p ) {
case ' b ' : /* 8 bits unsigned byte */
buf [ n + + ] = ( __u8 ) va_arg ( args , int ) ;
break ;
case ' s ' : /* 16 bits unsigned short */
arg . i = ( __u16 ) va_arg ( args , int ) ;
put_unaligned ( ( __u16 ) arg . i , ( __u16 * ) ( buf + n ) ) ; n + = 2 ;
break ;
case ' i ' : /* 32 bits unsigned integer */
arg . i = va_arg ( args , __u32 ) ;
put_unaligned ( arg . i , ( __u32 * ) ( buf + n ) ) ; n + = 4 ;
break ;
#if 0
case ' c ' : /* \0 terminated string */
arg . c = va_arg ( args , char * ) ;
strcpy ( buf + n , arg . c ) ;
n + = strlen ( arg . c ) + 1 ;
break ;
# endif
default :
va_end ( args ) ;
return - 1 ;
}
}
va_end ( args ) ;
return 0 ;
}
EXPORT_SYMBOL ( irda_param_pack ) ;
/*
* Function irda_param_unpack ( skb , fmt , . . . )
*/
static int irda_param_unpack ( __u8 * buf , char * fmt , . . . )
{
irda_pv_t arg ;
va_list args ;
char * p ;
int n = 0 ;
va_start ( args , fmt ) ;
for ( p = fmt ; * p ! = ' \0 ' ; p + + ) {
switch ( * p ) {
case ' b ' : /* 8 bits byte */
arg . ip = va_arg ( args , __u32 * ) ;
* arg . ip = buf [ n + + ] ;
break ;
case ' s ' : /* 16 bits short */
arg . ip = va_arg ( args , __u32 * ) ;
* arg . ip = get_unaligned ( ( __u16 * ) ( buf + n ) ) ; n + = 2 ;
break ;
case ' i ' : /* 32 bits unsigned integer */
arg . ip = va_arg ( args , __u32 * ) ;
* arg . ip = get_unaligned ( ( __u32 * ) ( buf + n ) ) ; n + = 4 ;
break ;
#if 0
case ' c ' : /* \0 terminated string */
arg . c = va_arg ( args , char * ) ;
strcpy ( arg . c , buf + n ) ;
n + = strlen ( arg . c ) + 1 ;
break ;
# endif
default :
va_end ( args ) ;
return - 1 ;
}
}
va_end ( args ) ;
return 0 ;
}
/*
* Function irda_param_insert ( self , pi , buf , len , info )
*
* Insert the specified parameter ( pi ) into buffer . Returns number of
* bytes inserted
*/
int irda_param_insert ( void * self , __u8 pi , __u8 * buf , int len ,
pi_param_info_t * info )
{
2014-12-10 21:28:58 +03:00
const pi_minor_info_t * pi_minor_info ;
2005-04-17 02:20:36 +04:00
__u8 pi_minor ;
__u8 pi_major ;
int type ;
int ret = - 1 ;
int n = 0 ;
IRDA_ASSERT ( buf ! = NULL , return ret ; ) ;
2007-12-17 01:10:33 +03:00
IRDA_ASSERT ( info ! = NULL , return ret ; ) ;
2005-04-17 02:20:36 +04:00
pi_minor = pi & info - > pi_mask ;
pi_major = pi > > info - > pi_major_offset ;
/* Check if the identifier value (pi) is valid */
if ( ( pi_major > info - > len - 1 ) | |
( pi_minor > info - > tables [ pi_major ] . len - 1 ) )
{
2014-11-12 01:44:57 +03:00
pr_debug ( " %s(), no handler for parameter=0x%02x \n " ,
__func__ , pi ) ;
2005-04-17 02:20:36 +04:00
/* Skip this parameter */
return - 1 ;
}
/* Lookup the info on how to parse this parameter */
pi_minor_info = & info - > tables [ pi_major ] . pi_minor_call_table [ pi_minor ] ;
/* Find expected data type for this parameter identifier (pi)*/
type = pi_minor_info - > type ;
/* Check if handler has been implemented */
if ( ! pi_minor_info - > func ) {
2014-11-12 00:37:30 +03:00
net_info_ratelimited ( " %s: no handler for pi=%#x \n " ,
__func__ , pi ) ;
2005-04-17 02:20:36 +04:00
/* Skip this parameter */
return - 1 ;
}
/* Insert parameter value */
ret = ( * pv_insert_table [ type & PV_MASK ] ) ( self , buf + n , len , pi , type ,
pi_minor_info - > func ) ;
return ret ;
}
EXPORT_SYMBOL ( irda_param_insert ) ;
/*
* Function irda_param_extract ( self , buf , len , info )
*
* Parse all parameters . If len is correct , then everything should be
* safe . Returns the number of bytes that was parsed
*
*/
static int irda_param_extract ( void * self , __u8 * buf , int len ,
pi_param_info_t * info )
{
2014-12-10 21:28:58 +03:00
const pi_minor_info_t * pi_minor_info ;
2005-04-17 02:20:36 +04:00
__u8 pi_minor ;
__u8 pi_major ;
int type ;
int ret = - 1 ;
int n = 0 ;
IRDA_ASSERT ( buf ! = NULL , return ret ; ) ;
2007-12-17 01:10:33 +03:00
IRDA_ASSERT ( info ! = NULL , return ret ; ) ;
2005-04-17 02:20:36 +04:00
pi_minor = buf [ n ] & info - > pi_mask ;
pi_major = buf [ n ] > > info - > pi_major_offset ;
/* Check if the identifier value (pi) is valid */
if ( ( pi_major > info - > len - 1 ) | |
( pi_minor > info - > tables [ pi_major ] . len - 1 ) )
{
2014-11-12 01:44:57 +03:00
pr_debug ( " %s(), no handler for parameter=0x%02x \n " ,
__func__ , buf [ 0 ] ) ;
2005-04-17 02:20:36 +04:00
/* Skip this parameter */
return 2 + buf [ n + 1 ] ; /* Continue */
}
/* Lookup the info on how to parse this parameter */
pi_minor_info = & info - > tables [ pi_major ] . pi_minor_call_table [ pi_minor ] ;
/* Find expected data type for this parameter identifier (pi)*/
type = pi_minor_info - > type ;
2014-11-12 01:44:57 +03:00
pr_debug ( " %s(), pi=[%d,%d], type=%d \n " , __func__ ,
pi_major , pi_minor , type ) ;
2005-04-17 02:20:36 +04:00
/* Check if handler has been implemented */
if ( ! pi_minor_info - > func ) {
2014-11-12 00:37:30 +03:00
net_info_ratelimited ( " %s: no handler for pi=%#x \n " ,
__func__ , buf [ n ] ) ;
2005-04-17 02:20:36 +04:00
/* Skip this parameter */
return 2 + buf [ n + 1 ] ; /* Continue */
}
/* Parse parameter value */
ret = ( * pv_extract_table [ type & PV_MASK ] ) ( self , buf + n , len , buf [ n ] ,
type , pi_minor_info - > func ) ;
return ret ;
}
/*
* Function irda_param_extract_all ( self , buf , len , info )
*
* Parse all parameters . If len is correct , then everything should be
* safe . Returns the number of bytes that was parsed
*
*/
2007-02-09 17:24:53 +03:00
int irda_param_extract_all ( void * self , __u8 * buf , int len ,
2005-04-17 02:20:36 +04:00
pi_param_info_t * info )
{
int ret = - 1 ;
int n = 0 ;
IRDA_ASSERT ( buf ! = NULL , return ret ; ) ;
2007-12-17 01:10:33 +03:00
IRDA_ASSERT ( info ! = NULL , return ret ; ) ;
2005-04-17 02:20:36 +04:00
/*
* Parse all parameters . Each parameter must be at least two bytes
* long or else there is no point in trying to parse it
*/
while ( len > 2 ) {
ret = irda_param_extract ( self , buf + n , len , info ) ;
if ( ret < 0 )
return ret ;
n + = ret ;
len - = ret ;
}
return n ;
}
EXPORT_SYMBOL ( irda_param_extract_all ) ;