linux/net/irda/parameters.c
Jeff Kirsher d37705092f net/irda: Fix FSF address in file headers
Several files refer to an old address for the Free Software Foundation
in the file header comment.  Resolve by replacing the address with
the URL <http://www.gnu.org/licenses/> so that we do not have to keep
updating the header comments anytime the address changes.

CC: Samuel Ortiz <samuel@sortiz.org>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2013-12-06 12:37:57 -05:00

590 lines
15 KiB
C

/*********************************************************************
*
* 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
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*
********************************************************************/
#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 */
static PV_HANDLER pv_extract_table[] = {
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 */
};
static PV_HANDLER pv_insert_table[] = {
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 */
p.pl = type & PV_MASK; /* The integer type codes the length as well */
p.pv.i = 0; /* Clear value */
/* Call handler for this parameter */
err = (*func)(self, &p, PV_GET);
if (err < 0)
return err;
/*
* If parameter length is still 0, then (1) this is an any length
* 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) {
IRDA_DEBUG(2, "%s(), using 1 byte\n", __func__);
p.pl = 1;
} else if (p.pv.i < 0xffff) {
IRDA_DEBUG(2, "%s(), using 2 bytes\n", __func__);
p.pl = 2;
} else {
IRDA_DEBUG(2, "%s(), using 4 bytes\n", __func__);
p.pl = 4; /* Default length */
}
}
/* Check if buffer is long enough for insertion */
if (len < (2+p.pl)) {
IRDA_WARNING("%s: buffer too short for insertion!\n",
__func__);
return -1;
}
IRDA_DEBUG(2, "%s(), pi=%#x, pl=%d, pi=%d\n", __func__,
p.pi, p.pl, p.pv.i);
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:
IRDA_WARNING("%s: length %d not supported\n",
__func__, p.pl);
/* 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;
int extract_len; /* Real length we extract */
int err;
p.pi = pi; /* In case handler needs to know */
p.pl = buf[1]; /* Extract length of value */
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)) {
IRDA_WARNING("%s: buffer too short for parsing! "
"Need %d bytes, but len is only %d\n",
__func__, p.pl, len);
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)) {
IRDA_ERROR("%s: invalid parameter length! "
"Expected %d bytes, but value had %d bytes!\n",
__func__, type & PV_MASK, p.pl);
/* 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:
IRDA_WARNING("%s: length %d not supported\n",
__func__, p.pl);
/* Skip parameter */
return p.pl+2;
}
IRDA_DEBUG(2, "%s(), pi=%#x, pl=%d, pi=%d\n", __func__,
p.pi, p.pl, p.pv.i);
/* 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;
IRDA_DEBUG(2, "%s()\n", __func__);
p.pi = pi; /* In case handler needs to know */
p.pl = buf[1]; /* Extract length of value */
if (p.pl > 32)
p.pl = 32;
IRDA_DEBUG(2, "%s(), pi=%#x, pl=%d\n", __func__,
p.pi, p.pl);
/* Check if buffer is long enough for parsing */
if (len < (2+p.pl)) {
IRDA_WARNING("%s: buffer too short for parsing! "
"Need %d bytes, but len is only %d\n",
__func__, p.pl, len);
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);
IRDA_DEBUG(2, "%s(), str=0x%02x 0x%02x\n", __func__,
(__u8) str[0], (__u8) str[1]);
/* Null terminate string */
str[p.pl] = '\0';
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 */
p.pl = buf[1]; /* Extract length of value */
/* Check if buffer is long enough for parsing */
if (len < (2+p.pl)) {
IRDA_WARNING("%s: buffer too short for parsing! "
"Need %d bytes, but len is only %d\n",
__func__, p.pl, len);
return -1;
}
IRDA_DEBUG(0, "%s(), not impl\n", __func__);
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)
{
pi_minor_info_t *pi_minor_info;
__u8 pi_minor;
__u8 pi_major;
int type;
int ret = -1;
int n = 0;
IRDA_ASSERT(buf != NULL, return ret;);
IRDA_ASSERT(info != NULL, return ret;);
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))
{
IRDA_DEBUG(0, "%s(), no handler for parameter=0x%02x\n",
__func__, pi);
/* 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) {
IRDA_MESSAGE("%s: no handler for pi=%#x\n", __func__, pi);
/* 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)
{
pi_minor_info_t *pi_minor_info;
__u8 pi_minor;
__u8 pi_major;
int type;
int ret = -1;
int n = 0;
IRDA_ASSERT(buf != NULL, return ret;);
IRDA_ASSERT(info != NULL, return ret;);
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))
{
IRDA_DEBUG(0, "%s(), no handler for parameter=0x%02x\n",
__func__, buf[0]);
/* 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;
IRDA_DEBUG(3, "%s(), pi=[%d,%d], type=%d\n", __func__,
pi_major, pi_minor, type);
/* Check if handler has been implemented */
if (!pi_minor_info->func) {
IRDA_MESSAGE("%s: no handler for pi=%#x\n",
__func__, buf[n]);
/* 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
*
*/
int irda_param_extract_all(void *self, __u8 *buf, int len,
pi_param_info_t *info)
{
int ret = -1;
int n = 0;
IRDA_ASSERT(buf != NULL, return ret;);
IRDA_ASSERT(info != NULL, return ret;);
/*
* 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);