123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585 |
- /*********************************************************************
- *
- * 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 const 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 const 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) {
- pr_debug("%s(), using 1 byte\n", __func__);
- p.pl = 1;
- } else if (p.pv.i < 0xffff) {
- pr_debug("%s(), using 2 bytes\n", __func__);
- p.pl = 2;
- } else {
- pr_debug("%s(), using 4 bytes\n", __func__);
- p.pl = 4; /* Default length */
- }
- }
- /* Check if buffer is long enough for insertion */
- if (len < (2+p.pl)) {
- net_warn_ratelimited("%s: buffer too short for insertion!\n",
- __func__);
- return -1;
- }
- pr_debug("%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:
- net_warn_ratelimited("%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)) {
- net_warn_ratelimited("%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)) {
- net_err_ratelimited("%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:
- net_warn_ratelimited("%s: length %d not supported\n",
- __func__, p.pl);
- /* Skip parameter */
- return p.pl+2;
- }
- pr_debug("%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;
- p.pi = pi; /* In case handler needs to know */
- p.pl = buf[1]; /* Extract length of value */
- if (p.pl > 32)
- p.pl = 32;
- pr_debug("%s(), pi=%#x, pl=%d\n", __func__,
- p.pi, p.pl);
- /* Check if buffer is long enough for parsing */
- if (len < (2+p.pl)) {
- net_warn_ratelimited("%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);
- pr_debug("%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)) {
- net_warn_ratelimited("%s: buffer too short for parsing! Need %d bytes, but len is only %d\n",
- __func__, p.pl, len);
- return -1;
- }
- pr_debug("%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)
- {
- const 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))
- {
- pr_debug("%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) {
- net_info_ratelimited("%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)
- {
- const 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))
- {
- pr_debug("%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;
- pr_debug("%s(), pi=[%d,%d], type=%d\n", __func__,
- pi_major, pi_minor, type);
- /* Check if handler has been implemented */
- if (!pi_minor_info->func) {
- net_info_ratelimited("%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);
|