1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31#include <linux/types.h>
32#include <linux/module.h>
33
34#include <asm/unaligned.h>
35#include <asm/byteorder.h>
36
37#include <net/irda/irda.h>
38#include <net/irda/parameters.h>
39
40static int irda_extract_integer(void *self, __u8 *buf, int len, __u8 pi,
41 PV_TYPE type, PI_HANDLER func);
42static int irda_extract_string(void *self, __u8 *buf, int len, __u8 pi,
43 PV_TYPE type, PI_HANDLER func);
44static int irda_extract_octseq(void *self, __u8 *buf, int len, __u8 pi,
45 PV_TYPE type, PI_HANDLER func);
46static int irda_extract_no_value(void *self, __u8 *buf, int len, __u8 pi,
47 PV_TYPE type, PI_HANDLER func);
48
49static int irda_insert_integer(void *self, __u8 *buf, int len, __u8 pi,
50 PV_TYPE type, PI_HANDLER func);
51static int irda_insert_no_value(void *self, __u8 *buf, int len, __u8 pi,
52 PV_TYPE type, PI_HANDLER func);
53
54static int irda_param_unpack(__u8 *buf, char *fmt, ...);
55
56
57static PV_HANDLER pv_extract_table[] = {
58 irda_extract_integer,
59 irda_extract_integer,
60 irda_extract_integer,
61 irda_extract_string,
62 irda_extract_integer,
63 irda_extract_octseq,
64 irda_extract_no_value
65};
66
67static PV_HANDLER pv_insert_table[] = {
68 irda_insert_integer,
69 irda_insert_integer,
70 irda_insert_integer,
71 NULL,
72 irda_insert_integer,
73 NULL,
74 irda_insert_no_value
75};
76
77
78
79
80static int irda_insert_no_value(void *self, __u8 *buf, int len, __u8 pi,
81 PV_TYPE type, PI_HANDLER func)
82{
83 irda_param_t p;
84 int ret;
85
86 p.pi = pi;
87 p.pl = 0;
88
89
90 ret = (*func)(self, &p, PV_GET);
91
92
93 irda_param_pack(buf, "bb", p.pi, p.pl);
94
95 if (ret < 0)
96 return ret;
97
98 return 2;
99}
100
101
102
103
104
105
106
107static int irda_extract_no_value(void *self, __u8 *buf, int len, __u8 pi,
108 PV_TYPE type, PI_HANDLER func)
109{
110 irda_param_t p;
111 int ret;
112
113
114 irda_param_unpack(buf, "bb", &p.pi, &p.pl);
115
116
117 ret = (*func)(self, &p, PV_PUT);
118
119 if (ret < 0)
120 return ret;
121
122 return 2;
123}
124
125
126
127
128static int irda_insert_integer(void *self, __u8 *buf, int len, __u8 pi,
129 PV_TYPE type, PI_HANDLER func)
130{
131 irda_param_t p;
132 int n = 0;
133 int err;
134
135 p.pi = pi;
136 p.pl = type & PV_MASK;
137 p.pv.i = 0;
138
139
140 err = (*func)(self, &p, PV_GET);
141 if (err < 0)
142 return err;
143
144
145
146
147
148
149 if (p.pl == 0) {
150 if (p.pv.i < 0xff) {
151 IRDA_DEBUG(2, "%s(), using 1 byte\n", __FUNCTION__);
152 p.pl = 1;
153 } else if (p.pv.i < 0xffff) {
154 IRDA_DEBUG(2, "%s(), using 2 bytes\n", __FUNCTION__);
155 p.pl = 2;
156 } else {
157 IRDA_DEBUG(2, "%s(), using 4 bytes\n", __FUNCTION__);
158 p.pl = 4;
159 }
160 }
161
162 if (len < (2+p.pl)) {
163 WARNING("%s: buffer to short for insertion!\n", __FUNCTION__);
164 return -1;
165 }
166 IRDA_DEBUG(2, "%s(), pi=%#x, pl=%d, pi=%d\n", __FUNCTION__,
167 p.pi, p.pl, p.pv.i);
168 switch (p.pl) {
169 case 1:
170 n += irda_param_pack(buf, "bbb", p.pi, p.pl, (__u8) p.pv.i);
171 break;
172 case 2:
173 if (type & PV_BIG_ENDIAN)
174 p.pv.i = cpu_to_be16((__u16) p.pv.i);
175 else
176 p.pv.i = cpu_to_le16((__u16) p.pv.i);
177 n += irda_param_pack(buf, "bbs", p.pi, p.pl, (__u16) p.pv.i);
178 break;
179 case 4:
180 if (type & PV_BIG_ENDIAN)
181 cpu_to_be32s(&p.pv.i);
182 else
183 cpu_to_le32s(&p.pv.i);
184 n += irda_param_pack(buf, "bbi", p.pi, p.pl, p.pv.i);
185
186 break;
187 default:
188 WARNING("%s: length %d not supported\n", __FUNCTION__, p.pl);
189
190 return -1;
191 }
192
193 return p.pl+2;
194}
195
196
197
198
199
200
201
202static int irda_extract_integer(void *self, __u8 *buf, int len, __u8 pi,
203 PV_TYPE type, PI_HANDLER func)
204{
205 irda_param_t p;
206 int n = 0;
207 int extract_len;
208 int err;
209
210 p.pi = pi;
211 p.pl = buf[1];
212 p.pv.i = 0;
213 extract_len = p.pl;
214
215
216 if (len < (2+p.pl)) {
217 WARNING("%s: buffer to short for parsing! "
218 "Need %d bytes, but len is only %d\n",
219 __FUNCTION__, p.pl, len);
220 return -1;
221 }
222
223
224
225
226
227
228 if (((type & PV_MASK) != PV_INTEGER) && ((type & PV_MASK) != p.pl)) {
229 ERROR("%s: invalid parameter length! "
230 "Expected %d bytes, but value had %d bytes!\n",
231 __FUNCTION__, type & PV_MASK, p.pl);
232
233
234
235
236
237
238
239 if((p.pl < (type & PV_MASK)) || (type & PV_BIG_ENDIAN)) {
240
241 return p.pl+2;
242 } else {
243
244 extract_len = type & PV_MASK;
245 }
246 }
247
248
249 switch (extract_len) {
250 case 1:
251 n += irda_param_unpack(buf+2, "b", &p.pv.i);
252 break;
253 case 2:
254 n += irda_param_unpack(buf+2, "s", &p.pv.i);
255 if (type & PV_BIG_ENDIAN)
256 p.pv.i = be16_to_cpu((__u16) p.pv.i);
257 else
258 p.pv.i = le16_to_cpu((__u16) p.pv.i);
259 break;
260 case 4:
261 n += irda_param_unpack(buf+2, "i", &p.pv.i);
262 if (type & PV_BIG_ENDIAN)
263 be32_to_cpus(&p.pv.i);
264 else
265 le32_to_cpus(&p.pv.i);
266 break;
267 default:
268 WARNING("%s: length %d not supported\n", __FUNCTION__, p.pl);
269
270
271 return p.pl+2;
272 }
273
274 IRDA_DEBUG(2, "%s(), pi=%#x, pl=%d, pi=%d\n", __FUNCTION__,
275 p.pi, p.pl, p.pv.i);
276
277 err = (*func)(self, &p, PV_PUT);
278 if (err < 0)
279 return err;
280
281 return p.pl+2;
282}
283
284
285
286
287static int irda_extract_string(void *self, __u8 *buf, int len, __u8 pi,
288 PV_TYPE type, PI_HANDLER func)
289{
290 char str[33];
291 irda_param_t p;
292 int err;
293
294 IRDA_DEBUG(2, "%s()\n", __FUNCTION__);
295
296 p.pi = pi;
297 p.pl = buf[1];
298
299 IRDA_DEBUG(2, "%s(), pi=%#x, pl=%d\n", __FUNCTION__,
300 p.pi, p.pl);
301
302
303 if (len < (2+p.pl)) {
304 WARNING("%s: buffer to short for parsing! "
305 "Need %d bytes, but len is only %d\n",
306 __FUNCTION__, p.pl, len);
307 return -1;
308 }
309
310
311
312 strncpy(str, buf+2, p.pl);
313
314 IRDA_DEBUG(2, "%s(), str=0x%02x 0x%02x\n", __FUNCTION__,
315 (__u8) str[0], (__u8) str[1]);
316
317
318 str[p.pl+1] = '\0';
319
320 p.pv.c = str;
321
322
323 err = (*func)(self, &p, PV_PUT);
324 if (err < 0)
325 return err;
326
327 return p.pl+2;
328}
329
330
331
332
333static int irda_extract_octseq(void *self, __u8 *buf, int len, __u8 pi,
334 PV_TYPE type, PI_HANDLER func)
335{
336 irda_param_t p;
337
338 p.pi = pi;
339 p.pl = buf[1];
340
341
342 if (len < (2+p.pl)) {
343 WARNING("%s: buffer to short for parsing! "
344 "Need %d bytes, but len is only %d\n",
345 __FUNCTION__, p.pl, len);
346 return -1;
347 }
348
349 IRDA_DEBUG(0, "%s(), not impl\n", __FUNCTION__);
350
351 return p.pl+2;
352}
353
354
355
356
357
358
359
360
361
362int irda_param_pack(__u8 *buf, char *fmt, ...)
363{
364 irda_pv_t arg;
365 va_list args;
366 char *p;
367 int n = 0;
368
369 va_start(args, fmt);
370
371 for (p = fmt; *p != '\0'; p++) {
372 switch (*p) {
373 case 'b':
374 buf[n++] = (__u8)va_arg(args, int);
375 break;
376 case 's':
377 arg.i = (__u16)va_arg(args, int);
378 put_unaligned((__u16)arg.i, (__u16 *)(buf+n)); n+=2;
379 break;
380 case 'i':
381 arg.i = va_arg(args, __u32);
382 put_unaligned(arg.i, (__u32 *)(buf+n)); n+=4;
383 break;
384#if 0
385 case 'c':
386 arg.c = va_arg(args, char *);
387 strcpy(buf+n, arg.c);
388 n += strlen(arg.c) + 1;
389 break;
390#endif
391 default:
392 va_end(args);
393 return -1;
394 }
395 }
396 va_end(args);
397
398 return 0;
399}
400EXPORT_SYMBOL(irda_param_pack);
401
402
403
404
405static int irda_param_unpack(__u8 *buf, char *fmt, ...)
406{
407 irda_pv_t arg;
408 va_list args;
409 char *p;
410 int n = 0;
411
412 va_start(args, fmt);
413
414 for (p = fmt; *p != '\0'; p++) {
415 switch (*p) {
416 case 'b':
417 arg.ip = va_arg(args, __u32 *);
418 *arg.ip = buf[n++];
419 break;
420 case 's':
421 arg.ip = va_arg(args, __u32 *);
422 *arg.ip = get_unaligned((__u16 *)(buf+n)); n+=2;
423 break;
424 case 'i':
425 arg.ip = va_arg(args, __u32 *);
426 *arg.ip = get_unaligned((__u32 *)(buf+n)); n+=4;
427 break;
428#if 0
429 case 'c':
430 arg.c = va_arg(args, char *);
431 strcpy(arg.c, buf+n);
432 n += strlen(arg.c) + 1;
433 break;
434#endif
435 default:
436 va_end(args);
437 return -1;
438 }
439
440 }
441 va_end(args);
442
443 return 0;
444}
445
446
447
448
449
450
451
452int irda_param_insert(void *self, __u8 pi, __u8 *buf, int len,
453 pi_param_info_t *info)
454{
455 pi_minor_info_t *pi_minor_info;
456 __u8 pi_minor;
457 __u8 pi_major;
458 int type;
459 int ret = -1;
460 int n = 0;
461
462 ASSERT(buf != NULL, return ret;);
463 ASSERT(info != 0, return ret;);
464
465 pi_minor = pi & info->pi_mask;
466 pi_major = pi >> info->pi_major_offset;
467
468
469 if ((pi_major > info->len-1) ||
470 (pi_minor > info->tables[pi_major].len-1))
471 {
472 IRDA_DEBUG(0, "%s(), no handler for parameter=0x%02x\n",
473 __FUNCTION__, pi);
474
475
476 return -1;
477 }
478
479
480 pi_minor_info = &info->tables[pi_major].pi_minor_call_table[pi_minor];
481
482
483 type = pi_minor_info->type;
484
485
486 if (!pi_minor_info->func) {
487 MESSAGE("%s: no handler for pi=%#x\n", __FUNCTION__, pi);
488
489 return -1;
490 }
491
492
493 ret = (*pv_insert_table[type & PV_MASK])(self, buf+n, len, pi, type,
494 pi_minor_info->func);
495 return ret;
496}
497EXPORT_SYMBOL(irda_param_insert);
498
499
500
501
502
503
504
505
506static int irda_param_extract(void *self, __u8 *buf, int len,
507 pi_param_info_t *info)
508{
509 pi_minor_info_t *pi_minor_info;
510 __u8 pi_minor;
511 __u8 pi_major;
512 int type;
513 int ret = -1;
514 int n = 0;
515
516 ASSERT(buf != NULL, return ret;);
517 ASSERT(info != 0, return ret;);
518
519 pi_minor = buf[n] & info->pi_mask;
520 pi_major = buf[n] >> info->pi_major_offset;
521
522
523 if ((pi_major > info->len-1) ||
524 (pi_minor > info->tables[pi_major].len-1))
525 {
526 IRDA_DEBUG(0, "%s(), no handler for parameter=0x%02x\n",
527 __FUNCTION__, buf[0]);
528
529
530 return 2 + buf[n + 1];
531 }
532
533
534 pi_minor_info = &info->tables[pi_major].pi_minor_call_table[pi_minor];
535
536
537 type = pi_minor_info->type;
538
539 IRDA_DEBUG(3, "%s(), pi=[%d,%d], type=%d\n", __FUNCTION__,
540 pi_major, pi_minor, type);
541
542
543 if (!pi_minor_info->func) {
544 MESSAGE("%s: no handler for pi=%#x\n", __FUNCTION__, buf[n]);
545
546 return 2 + buf[n + 1];
547 }
548
549
550 ret = (*pv_extract_table[type & PV_MASK])(self, buf+n, len, buf[n],
551 type, pi_minor_info->func);
552 return ret;
553}
554
555
556
557
558
559
560
561
562int irda_param_extract_all(void *self, __u8 *buf, int len,
563 pi_param_info_t *info)
564{
565 int ret = -1;
566 int n = 0;
567
568 ASSERT(buf != NULL, return ret;);
569 ASSERT(info != 0, return ret;);
570
571
572
573
574
575 while (len > 2) {
576 ret = irda_param_extract(self, buf+n, len, info);
577 if (ret < 0)
578 return ret;
579
580 n += ret;
581 len -= ret;
582 }
583 return n;
584}
585EXPORT_SYMBOL(irda_param_extract_all);
586