1 /**
2 * @file bfcp/attr.c BFCP Attributes
3 *
4 * Copyright (C) 2010 Creytiv.com
5 */
6 #include <string.h>
7 #include <re_types.h>
8 #include <re_fmt.h>
9 #include <re_mem.h>
10 #include <re_mbuf.h>
11 #include <re_sa.h>
12 #include <re_list.h>
13 #include <re_tmr.h>
14 #include <re_bfcp.h>
15 #include "bfcp.h"
16
17
18 enum {
19 BFCP_ATTR_HDR_SIZE = 2,
20 };
21
22
destructor(void * arg)23 static void destructor(void *arg)
24 {
25 struct bfcp_attr *attr = arg;
26
27 switch (attr->type) {
28
29 case BFCP_ERROR_CODE:
30 mem_deref(attr->v.errcode.details);
31 break;
32
33 case BFCP_ERROR_INFO:
34 case BFCP_PART_PROV_INFO:
35 case BFCP_STATUS_INFO:
36 case BFCP_USER_DISP_NAME:
37 case BFCP_USER_URI:
38 mem_deref(attr->v.str);
39 break;
40
41 case BFCP_SUPPORTED_ATTRS:
42 mem_deref(attr->v.supattr.attrv);
43 break;
44
45 case BFCP_SUPPORTED_PRIMS:
46 mem_deref(attr->v.supprim.primv);
47 break;
48
49 default:
50 break;
51 }
52
53 list_flush(&attr->attrl);
54 list_unlink(&attr->le);
55 }
56
57
attr_encode(struct mbuf * mb,bool mand,enum bfcp_attrib type,const void * v)58 static int attr_encode(struct mbuf *mb, bool mand, enum bfcp_attrib type,
59 const void *v)
60 {
61 const struct bfcp_reqstatus *reqstatus = v;
62 const struct bfcp_errcode *errcode = v;
63 const struct bfcp_supattr *supattr = v;
64 const struct bfcp_supprim *supprim = v;
65 const enum bfcp_priority *priority = v;
66 const uint16_t *u16 = v;
67 size_t start, len, i;
68 int err;
69
70 start = mb->pos;
71 mb->pos += BFCP_ATTR_HDR_SIZE;
72
73 switch (type) {
74
75 case BFCP_BENEFICIARY_ID:
76 case BFCP_FLOOR_ID:
77 case BFCP_FLOOR_REQUEST_ID:
78 case BFCP_BENEFICIARY_INFO:
79 case BFCP_FLOOR_REQ_INFO:
80 case BFCP_REQUESTED_BY_INFO:
81 case BFCP_FLOOR_REQ_STATUS:
82 case BFCP_OVERALL_REQ_STATUS:
83 err = mbuf_write_u16(mb, htons(*u16));
84 break;
85
86 case BFCP_PRIORITY:
87 err = mbuf_write_u8(mb, *priority << 5);
88 err |= mbuf_write_u8(mb, 0x00);
89 break;
90
91 case BFCP_REQUEST_STATUS:
92 err = mbuf_write_u8(mb, reqstatus->status);
93 err |= mbuf_write_u8(mb, reqstatus->qpos);
94 break;
95
96 case BFCP_ERROR_CODE:
97 err = mbuf_write_u8(mb, errcode->code);
98 if (errcode->details && errcode->len)
99 err |= mbuf_write_mem(mb, errcode->details,
100 errcode->len);
101 break;
102
103 case BFCP_ERROR_INFO:
104 case BFCP_PART_PROV_INFO:
105 case BFCP_STATUS_INFO:
106 case BFCP_USER_DISP_NAME:
107 case BFCP_USER_URI:
108 err = mbuf_write_str(mb, v);
109 break;
110
111 case BFCP_SUPPORTED_ATTRS:
112 for (i=0, err=0; i<supattr->attrc; i++)
113 err |= mbuf_write_u8(mb, supattr->attrv[i] << 1);
114 break;
115
116 case BFCP_SUPPORTED_PRIMS:
117 for (i=0, err=0; i<supprim->primc; i++)
118 err |= mbuf_write_u8(mb, supprim->primv[i]);
119 break;
120
121 default:
122 err = EINVAL;
123 break;
124 }
125
126 /* header */
127 len = mb->pos - start;
128
129 mb->pos = start;
130 err |= mbuf_write_u8(mb, (type<<1) | (mand ? 1 : 0));
131 err |= mbuf_write_u8(mb, len);
132 mb->pos += (len - BFCP_ATTR_HDR_SIZE);
133
134 /* padding */
135 while ((mb->pos - start) & 0x03)
136 err |= mbuf_write_u8(mb, 0x00);
137
138 return err;
139 }
140
141
142 /**
143 * Encode BFCP Attributes with variable arguments
144 *
145 * @param mb Mbuf to encode into
146 * @param attrc Number of attributes
147 * @param ap Variable argument of attributes
148 *
149 * @return 0 if success, otherwise errorcode
150 */
bfcp_attrs_vencode(struct mbuf * mb,unsigned attrc,va_list * ap)151 int bfcp_attrs_vencode(struct mbuf *mb, unsigned attrc, va_list *ap)
152 {
153 unsigned i;
154
155 if (!mb)
156 return EINVAL;
157
158 for (i=0; i<attrc; i++) {
159
160 int type = va_arg(*ap, int);
161 unsigned subc = va_arg(*ap, unsigned);
162 const void *v = va_arg(*ap, const void *);
163 size_t start, len;
164 int err;
165
166 if (!v)
167 continue;
168
169 start = mb->pos;
170
171 if (type == BFCP_ENCODE_HANDLER) {
172
173 const struct bfcp_encode *enc = v;
174
175 if (enc->ench) {
176 err = enc->ench(mb, enc->arg);
177 if (err)
178 return err;
179 }
180
181 continue;
182 }
183
184 err = attr_encode(mb, type>>7, type & 0x7f, v);
185 if (err)
186 return err;
187
188 if (subc == 0)
189 continue;
190
191 err = bfcp_attrs_vencode(mb, subc, ap);
192 if (err)
193 return err;
194
195 /* update total length for grouped attributes */
196 len = mb->pos - start;
197
198 mb->pos = start + 1;
199 err = mbuf_write_u8(mb, (uint8_t)len);
200 if (err)
201 return err;
202
203 mb->pos += (len - BFCP_ATTR_HDR_SIZE);
204 }
205
206 return 0;
207 }
208
209
210 /**
211 * Encode BFCP Attributes
212 *
213 * @param mb Mbuf to encode into
214 * @param attrc Number of attributes
215 *
216 * @return 0 if success, otherwise errorcode
217 */
bfcp_attrs_encode(struct mbuf * mb,unsigned attrc,...)218 int bfcp_attrs_encode(struct mbuf *mb, unsigned attrc, ...)
219 {
220 va_list ap;
221 int err;
222
223 va_start(ap, attrc);
224 err = bfcp_attrs_vencode(mb, attrc, &ap);
225 va_end(ap);
226
227 return err;
228 }
229
230
attr_decode(struct bfcp_attr ** attrp,struct mbuf * mb,struct bfcp_unknown_attr * uma)231 static int attr_decode(struct bfcp_attr **attrp, struct mbuf *mb,
232 struct bfcp_unknown_attr *uma)
233 {
234 struct bfcp_attr *attr;
235 union bfcp_union *v;
236 size_t i, start, len;
237 int err = 0;
238 uint8_t b;
239
240 if (mbuf_get_left(mb) < BFCP_ATTR_HDR_SIZE)
241 return EBADMSG;
242
243 attr = mem_zalloc(sizeof(*attr), destructor);
244 if (!attr)
245 return ENOMEM;
246
247 start = mb->pos;
248
249 b = mbuf_read_u8(mb);
250 attr->type = b >> 1;
251 attr->mand = b & 1;
252 len = mbuf_read_u8(mb);
253
254 if (len < BFCP_ATTR_HDR_SIZE)
255 goto badmsg;
256
257 len -= BFCP_ATTR_HDR_SIZE;
258
259 if (mbuf_get_left(mb) < len)
260 goto badmsg;
261
262 v = &attr->v;
263
264 switch (attr->type) {
265
266 case BFCP_BENEFICIARY_ID:
267 case BFCP_FLOOR_ID:
268 case BFCP_FLOOR_REQUEST_ID:
269 if (len < 2)
270 goto badmsg;
271
272 v->u16 = ntohs(mbuf_read_u16(mb));
273 break;
274
275 case BFCP_PRIORITY:
276 if (len < 2)
277 goto badmsg;
278
279 v->priority = mbuf_read_u8(mb) >> 5;
280 (void)mbuf_read_u8(mb);
281 break;
282
283 case BFCP_REQUEST_STATUS:
284 if (len < 2)
285 goto badmsg;
286
287 v->reqstatus.status = mbuf_read_u8(mb);
288 v->reqstatus.qpos = mbuf_read_u8(mb);
289 break;
290
291 case BFCP_ERROR_CODE:
292 if (len < 1)
293 goto badmsg;
294
295 v->errcode.code = mbuf_read_u8(mb);
296 v->errcode.len = len - 1;
297
298 if (v->errcode.len == 0)
299 break;
300
301 v->errcode.details = mem_alloc(v->errcode.len, NULL);
302 if (!v->errcode.details) {
303 err = ENOMEM;
304 goto error;
305 }
306
307 (void)mbuf_read_mem(mb, v->errcode.details,
308 v->errcode.len);
309 break;
310
311 case BFCP_ERROR_INFO:
312 case BFCP_PART_PROV_INFO:
313 case BFCP_STATUS_INFO:
314 case BFCP_USER_DISP_NAME:
315 case BFCP_USER_URI:
316 err = mbuf_strdup(mb, &v->str, len);
317 break;
318
319 case BFCP_SUPPORTED_ATTRS:
320 v->supattr.attrc = len;
321 v->supattr.attrv = mem_alloc(len*sizeof(*v->supattr.attrv),
322 NULL);
323 if (!v->supattr.attrv) {
324 err = ENOMEM;
325 goto error;
326 }
327
328 for (i=0; i<len; i++)
329 v->supattr.attrv[i] = mbuf_read_u8(mb) >> 1;
330 break;
331
332 case BFCP_SUPPORTED_PRIMS:
333 v->supprim.primc = len;
334 v->supprim.primv = mem_alloc(len * sizeof(*v->supprim.primv),
335 NULL);
336 if (!v->supprim.primv) {
337 err = ENOMEM;
338 goto error;
339 }
340
341 for (i=0; i<len; i++)
342 v->supprim.primv[i] = mbuf_read_u8(mb);
343 break;
344
345 /* grouped attributes */
346
347 case BFCP_BENEFICIARY_INFO:
348 case BFCP_FLOOR_REQ_INFO:
349 case BFCP_REQUESTED_BY_INFO:
350 case BFCP_FLOOR_REQ_STATUS:
351 case BFCP_OVERALL_REQ_STATUS:
352 if (len < 2)
353 goto badmsg;
354
355 v->u16 = ntohs(mbuf_read_u16(mb));
356 err = bfcp_attrs_decode(&attr->attrl, mb, len - 2, uma);
357 break;
358
359 default:
360 mb->pos += len;
361
362 if (!attr->mand)
363 break;
364
365 if (uma && uma->typec < ARRAY_SIZE(uma->typev))
366 uma->typev[uma->typec++] = attr->type<<1;
367 break;
368 }
369
370 if (err)
371 goto error;
372
373 /* padding */
374 while (((mb->pos - start) & 0x03) && mbuf_get_left(mb))
375 ++mb->pos;
376
377 *attrp = attr;
378
379 return 0;
380
381 badmsg:
382 err = EBADMSG;
383 error:
384 mem_deref(attr);
385
386 return err;
387 }
388
389
bfcp_attrs_decode(struct list * attrl,struct mbuf * mb,size_t len,struct bfcp_unknown_attr * uma)390 int bfcp_attrs_decode(struct list *attrl, struct mbuf *mb, size_t len,
391 struct bfcp_unknown_attr *uma)
392 {
393 int err = 0;
394 size_t end;
395
396 if (!attrl || !mb || mbuf_get_left(mb) < len)
397 return EINVAL;
398
399 end = mb->end;
400 mb->end = mb->pos + len;
401
402 while (mbuf_get_left(mb) >= BFCP_ATTR_HDR_SIZE) {
403
404 struct bfcp_attr *attr;
405
406 err = attr_decode(&attr, mb, uma);
407 if (err)
408 break;
409
410 list_append(attrl, &attr->le, attr);
411 }
412
413 mb->end = end;
414
415 return err;
416 }
417
418
bfcp_attrs_find(const struct list * attrl,enum bfcp_attrib type)419 struct bfcp_attr *bfcp_attrs_find(const struct list *attrl,
420 enum bfcp_attrib type)
421 {
422 struct le *le = list_head(attrl);
423
424 while (le) {
425 struct bfcp_attr *attr = le->data;
426
427 le = le->next;
428
429 if (attr->type == type)
430 return attr;
431 }
432
433 return NULL;
434 }
435
436
bfcp_attrs_apply(const struct list * attrl,bfcp_attr_h * h,void * arg)437 struct bfcp_attr *bfcp_attrs_apply(const struct list *attrl,
438 bfcp_attr_h *h, void *arg)
439 {
440 struct le *le = list_head(attrl);
441
442 while (le) {
443 struct bfcp_attr *attr = le->data;
444
445 le = le->next;
446
447 if (h && h(attr, arg))
448 return attr;
449 }
450
451 return NULL;
452 }
453
454
455 /**
456 * Get a BFCP sub-attribute from a BFCP attribute
457 *
458 * @param attr BFCP attribute
459 * @param type Attribute type
460 *
461 * @return Matching BFCP attribute if found, otherwise NULL
462 */
bfcp_attr_subattr(const struct bfcp_attr * attr,enum bfcp_attrib type)463 struct bfcp_attr *bfcp_attr_subattr(const struct bfcp_attr *attr,
464 enum bfcp_attrib type)
465 {
466 if (!attr)
467 return NULL;
468
469 return bfcp_attrs_find(&attr->attrl, type);
470 }
471
472
473 /**
474 * Apply a function handler to all sub-attributes in a BFCP attribute
475 *
476 * @param attr BFCP attribute
477 * @param h Handler
478 * @param arg Handler argument
479 *
480 * @return BFCP attribute returned by handler, or NULL
481 */
bfcp_attr_subattr_apply(const struct bfcp_attr * attr,bfcp_attr_h * h,void * arg)482 struct bfcp_attr *bfcp_attr_subattr_apply(const struct bfcp_attr *attr,
483 bfcp_attr_h *h, void *arg)
484 {
485 if (!attr)
486 return NULL;
487
488 return bfcp_attrs_apply(&attr->attrl, h, arg);
489 }
490
491
492 /**
493 * Print a BFCP attribute
494 *
495 * @param pf Print function
496 * @param attr BFCP attribute
497 *
498 * @return 0 if success, otherwise errorcode
499 */
bfcp_attr_print(struct re_printf * pf,const struct bfcp_attr * attr)500 int bfcp_attr_print(struct re_printf *pf, const struct bfcp_attr *attr)
501 {
502 const union bfcp_union *v;
503 size_t i;
504 int err;
505
506 if (!attr)
507 return 0;
508
509 err = re_hprintf(pf, "%c%-28s", attr->mand ? '*' : ' ',
510 bfcp_attr_name(attr->type));
511
512 v = &attr->v;
513
514 switch (attr->type) {
515
516 case BFCP_BENEFICIARY_ID:
517 case BFCP_FLOOR_ID:
518 case BFCP_FLOOR_REQUEST_ID:
519 err |= re_hprintf(pf, "%u", v->u16);
520 break;
521
522 case BFCP_PRIORITY:
523 err |= re_hprintf(pf, "%d", v->priority);
524 break;
525
526 case BFCP_REQUEST_STATUS:
527 err |= re_hprintf(pf, "%s (%d), qpos=%u",
528 bfcp_reqstatus_name(v->reqstatus.status),
529 v->reqstatus.status,
530 v->reqstatus.qpos);
531 break;
532
533 case BFCP_ERROR_CODE:
534 err |= re_hprintf(pf, "%d (%s)", v->errcode.code,
535 bfcp_errcode_name(v->errcode.code));
536
537 if (v->errcode.code == BFCP_UNKNOWN_MAND_ATTR) {
538
539 for (i=0; i<v->errcode.len; i++) {
540
541 uint8_t type = v->errcode.details[i] >> 1;
542
543 err |= re_hprintf(pf, " %s",
544 bfcp_attr_name(type));
545 }
546 }
547 break;
548
549 case BFCP_ERROR_INFO:
550 case BFCP_PART_PROV_INFO:
551 case BFCP_STATUS_INFO:
552 case BFCP_USER_DISP_NAME:
553 case BFCP_USER_URI:
554 err |= re_hprintf(pf, "\"%s\"", v->str);
555 break;
556
557 case BFCP_SUPPORTED_ATTRS:
558 err |= re_hprintf(pf, "%zu:", v->supattr.attrc);
559
560 for (i=0; i<v->supattr.attrc; i++) {
561
562 const enum bfcp_attrib type = v->supattr.attrv[i];
563
564 err |= re_hprintf(pf, " %s", bfcp_attr_name(type));
565 }
566 break;
567
568 case BFCP_SUPPORTED_PRIMS:
569 err |= re_hprintf(pf, "%zu:", v->supprim.primc);
570
571 for (i=0; i<v->supprim.primc; i++) {
572
573 const enum bfcp_prim prim = v->supprim.primv[i];
574
575 err |= re_hprintf(pf, " %s", bfcp_prim_name(prim));
576 }
577 break;
578
579 /* Grouped Attributes */
580
581 case BFCP_BENEFICIARY_INFO:
582 err |= re_hprintf(pf, "beneficiary-id=%u", v->beneficiaryid);
583 break;
584
585 case BFCP_FLOOR_REQ_INFO:
586 err |= re_hprintf(pf, "floor-request-id=%u", v->floorreqid);
587 break;
588
589 case BFCP_REQUESTED_BY_INFO:
590 err |= re_hprintf(pf, "requested-by-id=%u", v->reqbyid);
591 break;
592
593 case BFCP_FLOOR_REQ_STATUS:
594 err |= re_hprintf(pf, "floor-id=%u", v->floorid);
595 break;
596
597 case BFCP_OVERALL_REQ_STATUS:
598 err |= re_hprintf(pf, "floor-request-id=%u", v->floorreqid);
599 break;
600
601 default:
602 err |= re_hprintf(pf, "???");
603 break;
604 }
605
606 return err;
607 }
608
609
bfcp_attrs_print(struct re_printf * pf,const struct list * attrl,unsigned level)610 int bfcp_attrs_print(struct re_printf *pf, const struct list *attrl,
611 unsigned level)
612 {
613 struct le *le;
614 int err = 0;
615
616 for (le=list_head(attrl); le; le=le->next) {
617
618 const struct bfcp_attr *attr = le->data;
619 unsigned i;
620
621 for (i=0; i<level; i++)
622 err |= re_hprintf(pf, " ");
623
624 err |= re_hprintf(pf, "%H\n", bfcp_attr_print, attr);
625 err |= bfcp_attrs_print(pf, &attr->attrl, level + 1);
626 }
627
628 return err;
629 }
630
631
632 /**
633 * Get the BFCP attribute name
634 *
635 * @param type BFCP attribute type
636 *
637 * @return String with BFCP attribute name
638 */
bfcp_attr_name(enum bfcp_attrib type)639 const char *bfcp_attr_name(enum bfcp_attrib type)
640 {
641 switch (type) {
642
643 case BFCP_BENEFICIARY_ID: return "BENEFICIARY-ID";
644 case BFCP_FLOOR_ID: return "FLOOR-ID";
645 case BFCP_FLOOR_REQUEST_ID: return "FLOOR-REQUEST-ID";
646 case BFCP_PRIORITY: return "PRIORITY";
647 case BFCP_REQUEST_STATUS: return "REQUEST-STATUS";
648 case BFCP_ERROR_CODE: return "ERROR-CODE";
649 case BFCP_ERROR_INFO: return "ERROR-INFO";
650 case BFCP_PART_PROV_INFO: return "PARTICIPANT-PROVIDED-INFO";
651 case BFCP_STATUS_INFO: return "STATUS-INFO";
652 case BFCP_SUPPORTED_ATTRS: return "SUPPORTED-ATTRIBUTES";
653 case BFCP_SUPPORTED_PRIMS: return "SUPPORTED-PRIMITIVES";
654 case BFCP_USER_DISP_NAME: return "USER-DISPLAY-NAME";
655 case BFCP_USER_URI: return "USER-URI";
656 case BFCP_BENEFICIARY_INFO: return "BENEFICIARY-INFORMATION";
657 case BFCP_FLOOR_REQ_INFO: return "FLOOR-REQUEST-INFORMATION";
658 case BFCP_REQUESTED_BY_INFO: return "REQUESTED-BY-INFORMATION";
659 case BFCP_FLOOR_REQ_STATUS: return "FLOOR-REQUEST-STATUS";
660 case BFCP_OVERALL_REQ_STATUS: return "OVERALL-REQUEST-STATUS";
661 default: return "???";
662 }
663 }
664
665
666 /**
667 * Get the BFCP Request status name
668 *
669 * @param status Request status
670 *
671 * @return String with BFCP Request status name
672 */
bfcp_reqstatus_name(enum bfcp_reqstat status)673 const char *bfcp_reqstatus_name(enum bfcp_reqstat status)
674 {
675 switch (status) {
676
677 case BFCP_PENDING: return "Pending";
678 case BFCP_ACCEPTED: return "Accepted";
679 case BFCP_GRANTED: return "Granted";
680 case BFCP_DENIED: return "Denied";
681 case BFCP_CANCELLED: return "Cancelled";
682 case BFCP_RELEASED: return "Released";
683 case BFCP_REVOKED: return "Revoked";
684 default: return "???";
685 }
686 }
687
688
689 /**
690 * Get the BFCP Error code name
691 *
692 * @param code BFCP Error code
693 *
694 * @return String with error code
695 */
bfcp_errcode_name(enum bfcp_err code)696 const char *bfcp_errcode_name(enum bfcp_err code)
697 {
698 switch (code) {
699
700 case BFCP_CONF_NOT_EXIST:
701 return "Conference does not Exist";
702
703 case BFCP_USER_NOT_EXIST:
704 return "User does not Exist";
705
706 case BFCP_UNKNOWN_PRIM:
707 return "Unknown Primitive";
708
709 case BFCP_UNKNOWN_MAND_ATTR:
710 return "Unknown Mandatory Attribute";
711
712 case BFCP_UNAUTH_OPERATION:
713 return "Unauthorized Operation";
714
715 case BFCP_INVALID_FLOOR_ID:
716 return "Invalid Floor ID";
717
718 case BFCP_FLOOR_REQ_ID_NOT_EXIST:
719 return "Floor Request ID Does Not Exist";
720
721 case BFCP_MAX_FLOOR_REQ_REACHED:
722 return "You have Already Reached the Maximum Number "
723 "of Ongoing Floor Requests for this Floor";
724
725 case BFCP_USE_TLS:
726 return "Use TLS";
727
728 case BFCP_PARSE_ERROR:
729 return "Unable to Parse Message";
730
731 case BFCP_USE_DTLS:
732 return "Use DTLS";
733
734 case BFCP_UNSUPPORTED_VERSION:
735 return "Unsupported Version";
736
737 case BFCP_BAD_LENGTH:
738 return "Incorrect Message Length";
739
740 case BFCP_GENERIC_ERROR:
741 return "Generic Error";
742
743 default:
744 return "???";
745 }
746 }
747