1 /**
2 *@internal
3 *
4 ** fbuf.c
5 ** IPFIX Message buffer implementation
6 **
7 ** ------------------------------------------------------------------------
8 ** Copyright (C) 2006-2019 Carnegie Mellon University. All Rights Reserved.
9 ** ------------------------------------------------------------------------
10 ** Authors: Brian Trammell, Dan Ruef, Emily Ecoff
11 ** ------------------------------------------------------------------------
12 ** @OPENSOURCE_LICENSE_START@
13 ** libfixbuf 2.0
14 **
15 ** Copyright 2018-2019 Carnegie Mellon University. All Rights Reserved.
16 **
17 ** NO WARRANTY. THIS CARNEGIE MELLON UNIVERSITY AND SOFTWARE
18 ** ENGINEERING INSTITUTE MATERIAL IS FURNISHED ON AN "AS-IS"
19 ** BASIS. CARNEGIE MELLON UNIVERSITY MAKES NO WARRANTIES OF ANY KIND,
20 ** EITHER EXPRESSED OR IMPLIED, AS TO ANY MATTER INCLUDING, BUT NOT
21 ** LIMITED TO, WARRANTY OF FITNESS FOR PURPOSE OR MERCHANTABILITY,
22 ** EXCLUSIVITY, OR RESULTS OBTAINED FROM USE OF THE
23 ** MATERIAL. CARNEGIE MELLON UNIVERSITY DOES NOT MAKE ANY WARRANTY OF
24 ** ANY KIND WITH RESPECT TO FREEDOM FROM PATENT, TRADEMARK, OR
25 ** COPYRIGHT INFRINGEMENT.
26 **
27 ** Released under a GNU-Lesser GPL 3.0-style license, please see
28 ** LICENSE.txt or contact permission@sei.cmu.edu for full terms.
29 **
30 ** [DISTRIBUTION STATEMENT A] This material has been approved for
31 ** public release and unlimited distribution. Please see Copyright
32 ** notice for non-US Government use and distribution.
33 **
34 ** Carnegie Mellon(R) and CERT(R) are registered in the U.S. Patent
35 ** and Trademark Office by Carnegie Mellon University.
36 **
37 ** DM18-0325
38 ** @OPENSOURCE_LICENSE_END@
39 ** ------------------------------------------------------------------------
40 */
41
42 #define _FIXBUF_SOURCE_
43 #include <fixbuf/private.h>
44
45
46 #define FB_MTU_MIN 32
47 #define FB_TCPLAN_NULL -1
48 #define FB_MAX_TEMPLATE_LEVELS 10
49
50 /* Debugger switches. We'll want to stick these in autoinc at some point. */
51 #define FB_DEBUG_TC 0
52 #define FB_DEBUG_TMPL 0
53 #define FB_DEBUG_WR 0
54 #define FB_DEBUG_RD 0
55 #define FB_DEBUG_LWR 0
56 #define FB_DEBUG_LRD 0
57
58 typedef struct fbTranscodePlan_st {
59 fbTemplate_t *s_tmpl;
60 fbTemplate_t *d_tmpl;
61 int32_t *si;
62 } fbTranscodePlan_t;
63
64 typedef struct fbDLL_st fbDLL_t;
65
66 struct fbDLL_st {
67 fbDLL_t *next;
68 fbDLL_t *prev;
69 };
70
71 typedef struct fbTCPlanEntry_st fbTCPlanEntry_t;
72 struct fbTCPlanEntry_st
73 {
74 fbTCPlanEntry_t *next;
75 fbTCPlanEntry_t *prev;
76 fbTranscodePlan_t *tcplan;
77 };
78
79 /**
80 *detachHeadOfDLL
81 *
82 * takes the head off of the dynamic linked list
83 *
84 * @param head
85 * @param tail
86 * @param toRemove
87 *
88 *
89 */
detachHeadOfDLL(fbDLL_t ** head,fbDLL_t ** tail,fbDLL_t ** toRemove)90 static void detachHeadOfDLL(
91 fbDLL_t **head,
92 fbDLL_t **tail,
93 fbDLL_t **toRemove)
94 {
95 /* assign the out pointer to the head */
96 *toRemove = *head;
97 /* move the head pointer to pointer to the next element*/
98 *head = (*head)->next;
99
100 /* if the new head's not NULL, set its prev to NULL */
101 if (*head) {
102 (*head)->prev = NULL;
103 } else {
104 /* if it's NULL, it means there are no more elements, if
105 * there's a tail pointer, set it to NULL too */
106 if (tail) {
107 *tail = NULL;
108 }
109 }
110 }
111
112 /**
113 *attachHeadToDLL
114 *
115 * puts a new element to the head of the dynamic linked list
116 *
117 * @param head
118 * @param tail
119 * @param newEntry
120 *
121 */
attachHeadToDLL(fbDLL_t ** head,fbDLL_t ** tail,fbDLL_t * newEntry)122 static void attachHeadToDLL(
123 fbDLL_t **head,
124 fbDLL_t **tail,
125 fbDLL_t *newEntry)
126 {
127 /* if this is NOT the first entry in the list */
128 if (*head) {
129 /* typical linked list attachements */
130 newEntry->next = *head;
131 newEntry->prev = NULL;
132 (*head)->prev = newEntry;
133 *head = newEntry;
134 } else {
135 /* the new entry is the only entry now, set head to it */
136 *head = newEntry;
137 newEntry->prev = NULL;
138 newEntry->next = NULL;
139 /* if we're keeping track of tail, assign that too */
140 if (tail) {
141 *tail = newEntry;
142 }
143 }
144 }
145
146 /**
147 *moveThisEntryToHeadOfDLL
148 *
149 * moves an entry within the dynamically linked list to the head of the list
150 *
151 * @param head - the head of the dynamic linked list
152 * @param tail - unused
153 * @param thisEntry - list element to move to the head
154 *
155 */
moveThisEntryToHeadOfDLL(fbDLL_t ** head,fbDLL_t ** tail,fbDLL_t * thisEntry)156 static void moveThisEntryToHeadOfDLL(
157 fbDLL_t **head,
158 fbDLL_t **tail __attribute__((unused)),
159 fbDLL_t *thisEntry)
160 {
161 if (thisEntry == *head) {
162 return;
163 }
164
165 if (thisEntry->prev) {
166 thisEntry->prev->next = thisEntry->next;
167 }
168
169 if (thisEntry->next) {
170 thisEntry->next->prev = thisEntry->prev;
171 }
172
173 thisEntry->prev = NULL;
174 thisEntry->next = *head;
175 (*head)->prev = thisEntry;
176 *head = thisEntry;
177 }
178
179 /**
180 *detachThisEntryOfDLL
181 *
182 * removes an entry from the dynamically linked list
183 *
184 * @param head
185 * @param tail
186 * @param entry
187 *
188 */
detachThisEntryOfDLL(fbDLL_t ** head,fbDLL_t ** tail,fbDLL_t * entry)189 static void detachThisEntryOfDLL(
190 fbDLL_t **head,
191 fbDLL_t **tail,
192 fbDLL_t *entry)
193 {
194 /* entry already points to the entry to remove, so we're good
195 * there */
196 /* if it's NOT the head of the list, patch up entry->prev */
197 if (entry->prev != NULL) {
198 entry->prev->next = entry->next;
199 } else {
200 /* if it's the head, reassign the head */
201 *head = entry->next;
202 }
203 /* if it's NOT the tail of the list, patch up entry->next */
204 if (entry->next != NULL) {
205 entry->next->prev = entry->prev;
206 } else {
207 /* it is the last entry in the list, if we're tracking the
208 * tail, reassign */
209 if (tail) {
210 *tail = entry->prev;
211 }
212 }
213
214 /* finish detaching by setting the next and prev pointers to
215 * null */
216 entry->prev = NULL;
217 entry->next = NULL;
218 }
219
220 struct fBuf_st {
221 /** Transport session. Contains template and sequence number state. */
222 fbSession_t *session;
223 /** Exporter. Writes messages to a remote endpoint on flush. */
224 fbExporter_t *exporter;
225 /** Collector. Reads messages from a remote endpoint on demand. */
226 fbCollector_t *collector;
227 /** Cached transcoder plan */
228 fbTCPlanEntry_t *latestTcplan;
229 /** Current internal template. */
230 fbTemplate_t *int_tmpl;
231 /** Current external template. */
232 fbTemplate_t *ext_tmpl;
233 /** Current internal template ID. */
234 uint16_t int_tid;
235 /** Current external template ID. */
236 uint16_t ext_tid;
237 /** Current special set ID. */
238 uint16_t spec_tid;
239 /** Automatic insert flag - tid of options tmpl */
240 uint16_t auto_insert_tid;
241 /** Automatic mode flag */
242 gboolean automatic;
243 /** Export time in seconds since 0UTC 1 Jan 1970 */
244 uint32_t extime;
245 /** Record counter. */
246 uint32_t rc;
247 /** length of buffer passed from app */
248 size_t buflen;
249 /**
250 * Current position pointer.
251 * Pointer to the next byte in the buffer to be written or read.
252 */
253 uint8_t *cp;
254 /**
255 * Pointer to first byte in the buffer in the current message.
256 * NULL if there is no current message.
257 */
258 uint8_t *msgbase;
259 /**
260 * Message end position pointer.
261 * Pointer to first byte in the buffer after the current message.
262 */
263 uint8_t *mep;
264 /**
265 * Pointer to first byte in the buffer in the current message.
266 * NULL if there is no current message.
267 */
268 uint8_t *setbase;
269 /**
270 * Set end position pointer.
271 * Valid only after a call to fBufNextSetHeader() (called by fBufNext()).
272 */
273 uint8_t *sep;
274 /** Message buffer. */
275 uint8_t buf[FB_MSGLEN_MAX+1];
276 };
277
278 int transcodeCount = 0;
279 /*==================================================================
280 *
281 * Debugger Functions
282 *
283 *==================================================================*/
284
285 #define FB_REM_MSG(_fbuf_) (_fbuf_->mep - _fbuf_->cp)
286
287 #define FB_REM_SET(_fbuf_) (_fbuf_->sep - _fbuf_->cp)
288
289 #if FB_DEBUG_WR || FB_DEBUG_RD || FB_DEBUG_TC
290
fBufDebugHexLine(GString * str,const char * lpfx,uint8_t * cp,uint32_t lineoff,uint32_t buflen)291 static uint32_t fBufDebugHexLine(
292 GString *str,
293 const char *lpfx,
294 uint8_t *cp,
295 uint32_t lineoff,
296 uint32_t buflen)
297 {
298 uint32_t cwr = 0, twr = 0;
299
300 /* stubbornly refuse to print nothing */
301 if (!buflen) return 0;
302
303 /* print line header */
304 g_string_append_printf(str, "%s %04x:", lpfx, lineoff);
305
306 /* print hex characters */
307 for (twr = 0; twr < 16; twr++) {
308 if (buflen) {
309 g_string_append_printf(str, " %02hhx", cp[twr]);
310 cwr++; buflen--;
311 } else {
312 g_string_append(str, " ");
313 }
314 }
315
316 /* print characters */
317 g_string_append_c(str, ' ');
318 for (twr = 0; twr < cwr; twr++) {
319 if (cp[twr] > 32 && cp[twr] < 128) {
320 g_string_append_c(str, cp[twr]);
321 } else {
322 g_string_append_c(str, '.');
323 }
324 }
325 g_string_append_c(str, '\n');
326
327 return cwr;
328 }
329
fBufDebugHex(const char * lpfx,uint8_t * buf,uint32_t len)330 static void fBufDebugHex(
331 const char *lpfx,
332 uint8_t *buf,
333 uint32_t len)
334 {
335 GString *str = g_string_new("");
336 uint32_t cwr = 0, lineoff = 0;
337
338 do {
339 cwr = fBufDebugHexLine(str, lpfx, buf, lineoff, len);
340 buf += cwr; len -= cwr; lineoff += cwr;
341 } while (cwr == 16);
342
343 fprintf(stderr,"%s", str->str);
344 g_string_free(str, TRUE);
345 }
346
347 #endif
348
349 #if FB_DEBUG_WR || FB_DEBUG_RD
350
351 #if FB_DEBUG_TC
352
fBufDebugTranscodePlan(fbTranscodePlan_t * tcplan)353 static void fBufDebugTranscodePlan(
354 fbTranscodePlan_t *tcplan)
355 {
356 int i;
357
358 fprintf(stderr, "transcode plan %p -> %p\n",
359 tcplan->s_tmpl, tcplan->d_tmpl);
360 for (i = 0; i < tcplan->d_tmpl->ie_count; i++) {
361 fprintf(stderr, "\td[%2u]=s[%2d]\n", i, tcplan->si[i]);
362 }
363 }
364
fBufDebugTranscodeOffsets(fbTemplate_t * tmpl,uint16_t * offsets)365 static void fBufDebugTranscodeOffsets(
366 fbTemplate_t *tmpl,
367 uint16_t *offsets)
368 {
369 int i;
370
371 fprintf(stderr, "offsets %p\n", tmpl);
372 for (i = 0; i < tmpl->ie_count; i++) {
373 fprintf(stderr, "\to[%2u]=%4x\n", i, offsets[i]);
374 }
375 }
376
377 #endif
378
fBufDebugBuffer(const char * label,fBuf_t * fbuf,size_t len,gboolean reverse)379 static void fBufDebugBuffer(
380 const char *label,
381 fBuf_t *fbuf,
382 size_t len,
383 gboolean reverse)
384 {
385 uint8_t *xcp = fbuf->cp - len;
386 uint8_t *rcp = reverse ? xcp : fbuf->cp;
387
388 fprintf(stderr, "%s len %5lu mp %5u (0x%04x) sp %5u mr %5u sr %5u\n",
389 label, len, rcp - fbuf->msgbase, rcp - fbuf->msgbase,
390 fbuf->setbase ? (rcp - fbuf->setbase) : 0,
391 fbuf->mep - fbuf->cp,
392 fbuf->sep ? (fbuf->sep - fbuf->cp) : 0);
393
394 fBufDebugHex(label, rcp, len);
395 }
396
397 #endif
398
399 /*==================================================================
400 *
401 * Transcoder Functions
402 *
403 *==================================================================*/
404
405 #define FB_TC_SBC_OFF(_need_) \
406 if (s_rem < (_need_)) { \
407 g_set_error(err, FB_ERROR_DOMAIN, FB_ERROR_EOM, \
408 "End of message. " \
409 "Underrun on transcode offset calculation " \
410 "(need %lu bytes, %lu available)", \
411 (unsigned long)(_need_), (unsigned long)s_rem); \
412 goto err; \
413 }
414
415 #define FB_TC_DBC_DEST(_need_, _op_, _dest_) \
416 if (*d_rem < (_need_)) { \
417 g_set_error(err, FB_ERROR_DOMAIN, FB_ERROR_EOM, \
418 "End of message. " \
419 "Overrun on %s (need %lu bytes, %lu available)", \
420 (_op_), (unsigned long)(_need_), (unsigned long)*d_rem);\
421 _dest_; \
422 }
423
424 #define FB_TC_DBC(_need_, _op_) \
425 FB_TC_DBC_DEST((_need_), (_op_), return FALSE)
426
427 #define FB_TC_DBC_ERR(_need_, _op_) \
428 FB_TC_DBC_DEST((_need_), (_op_), goto err)
429
430 /**
431 * fbTranscodePlan
432 *
433 * @param fbuf
434 * @param s_tmpl
435 * @param d_tmpl
436 *
437 */
438
fbTranscodePlan(fBuf_t * fbuf,fbTemplate_t * s_tmpl,fbTemplate_t * d_tmpl)439 static fbTranscodePlan_t *fbTranscodePlan(
440 fBuf_t *fbuf,
441 fbTemplate_t *s_tmpl,
442 fbTemplate_t *d_tmpl)
443 {
444 void *sik, *siv;
445 uint32_t i;
446 fbTCPlanEntry_t *entry;
447 fbTranscodePlan_t *tcplan;
448
449 /* check to see if plan is cached */
450 if (fbuf->latestTcplan) {
451 entry = fbuf->latestTcplan;
452 while (entry) {
453 tcplan = entry->tcplan;
454 if (tcplan->s_tmpl == s_tmpl &&
455 tcplan->d_tmpl == d_tmpl)
456 {
457 moveThisEntryToHeadOfDLL((fbDLL_t**)(void*)&(fbuf->latestTcplan),
458 NULL,
459 (fbDLL_t*)entry);
460 return tcplan;
461 }
462 entry = entry->next;
463 }
464 }
465
466 entry = g_slice_new0(fbTCPlanEntry_t);
467
468 /* create new transcode plan and cache it */
469 entry->tcplan = g_slice_new0(fbTranscodePlan_t);
470
471 tcplan = entry->tcplan;
472 /* fill in template refs */
473 tcplan->s_tmpl = s_tmpl;
474 tcplan->d_tmpl = d_tmpl;
475
476 tcplan->si = g_new0(int32_t, d_tmpl->ie_count);
477 /* for each destination element */
478 for (i = 0; i < d_tmpl->ie_count; i++) {
479 /* find source index */
480 if (g_hash_table_lookup_extended(s_tmpl->indices,
481 d_tmpl->ie_ary[i],
482 &sik, &siv)) {
483 tcplan->si[i] = GPOINTER_TO_INT(siv);
484 } else {
485 tcplan->si[i] = FB_TCPLAN_NULL;
486 }
487 }
488
489 attachHeadToDLL((fbDLL_t**)(void*)&(fbuf->latestTcplan),
490 NULL,
491 (fbDLL_t*)entry);
492 return tcplan;
493 }
494
495 /**
496 * fbTranscodeFreeVarlenOffsets
497 *
498 * @param s_tmpl
499 * @param offsets
500 *
501 */
fbTranscodeFreeVarlenOffsets(fbTemplate_t * s_tmpl,uint16_t * offsets)502 static void fbTranscodeFreeVarlenOffsets(
503 fbTemplate_t *s_tmpl,
504 uint16_t *offsets)
505 {
506 if (s_tmpl->is_varlen) g_free(offsets);
507 }
508
509 /**
510 *
511 * Macros for decode reading
512 */
513
514
515 #if HAVE_ALIGNED_ACCESS_REQUIRED
516
517 #define FB_READ_U16(_val_, _ptr_) { \
518 uint16_t _x; \
519 memcpy(&_x, _ptr_, sizeof(uint16_t)); \
520 _val_ = g_ntohs(_x); \
521 }
522
523 #define FB_READ_U32(_val_, _ptr_) { \
524 uint32_t _x; \
525 memcpy(&_x, _ptr_, sizeof(uint32_t)); \
526 _val_ = g_ntohl(_x); \
527 }
528
529 #define FB_WRITE_U16(_ptr_, _val_) { \
530 uint16_t _x = g_htons(_val_); \
531 memcpy(_ptr_, &_x, sizeof(uint16_t)); \
532 }
533
534 #define FB_WRITE_U32(_ptr_, _val_) { \
535 uint32_t _x = g_htonl(_val_); \
536 memcpy(_ptr_, &_x, sizeof(uint32_t)); \
537 }
538
539 #else
540
541 #define FB_READ_U16(_val_, _ptr_) { \
542 _val_ = g_ntohs(*((uint16_t *)_ptr_)); \
543 }
544
545 #define FB_READ_U32(_val_, _ptr_) { \
546 _val_ = g_ntohl(*((uint32_t *)_ptr_)); \
547 }
548
549 #define FB_WRITE_U16(_ptr_, _val_) \
550 *(uint16_t *)(_ptr_) = g_htons(_val_)
551
552 #define FB_WRITE_U32(_ptr_, _val_) \
553 *(uint32_t *)(_ptr_) = g_htonl(_val_)
554
555 #endif
556
557 #define FB_READ_U8(_val_, _ptr_) \
558 _val_ = *(_ptr_)
559
560 #define FB_WRITE_U8(_ptr_, _val_) \
561 (*(_ptr_)) = _val_
562
563 #define FB_READINC_U8(_val_, _ptr_) { \
564 FB_READ_U8(_val_, _ptr_); \
565 ++(_ptr_); \
566 }
567
568 #define FB_READINC_U16(_val_, _ptr_) { \
569 FB_READ_U16(_val_, _ptr_); \
570 (_ptr_) += sizeof(uint16_t); \
571 }
572
573 #define FB_READINC_U32(_val_, _ptr_) { \
574 FB_READ_U32(_val_, _ptr_); \
575 (_ptr_) += sizeof(uint32_t); \
576 }
577
578 #define FB_WRITEINC_U8(_ptr_, _val_) { \
579 FB_WRITE_U8(_ptr_, _val_); \
580 ++(_ptr_); \
581 }
582
583 #define FB_WRITEINC_U16(_ptr_, _val_) { \
584 FB_WRITE_U16(_ptr_, _val_); \
585 (_ptr_) += sizeof(uint16_t); \
586 }
587
588 #define FB_WRITEINC_U32(_ptr_, _val_) { \
589 FB_WRITE_U32(_ptr_, _val_); \
590 (_ptr_) += sizeof(uint32_t); \
591 }
592
593 #define FB_READINCREM_U8(_val_, _ptr_, _rem_) { \
594 FB_READINC_U8(_val_, _ptr_); \
595 --(_rem_); \
596 }
597
598 #define FB_READINCREM_U16(_val_, _ptr_, _rem_) { \
599 FB_READINC_U16(_val_, _ptr_); \
600 (_rem_) -= sizeof(uint16_t); \
601 }
602
603 #define FB_READINCREM_U32(_val_, _ptr_, _rem_) { \
604 FB_READINC_U32(_val_, _ptr_); \
605 (_rem_) -= sizeof(uint32_t); \
606 }
607
608 #define FB_WRITEINCREM_U8(_ptr_, _val_, _rem_) { \
609 FB_WRITEINC_U8(_ptr_, _val_); \
610 --(_rem_); \
611 }
612
613 #define FB_WRITEINCREM_U16(_ptr_, _val_, _rem_) { \
614 FB_WRITEINC_U16(_ptr_, _val_); \
615 (_rem_) -= sizeof(uint16_t); \
616 }
617
618 #define FB_WRITEINCREM_U32(_ptr_, _val_, _rem_) { \
619 FB_WRITEINC_U32(_ptr_, _val_); \
620 (_rem_) -= sizeof(uint32_t); \
621 }
622
623 #define FB_READ_LIST_LENGTH(_len_, _ptr_) { \
624 FB_READINC_U8(_len_, _ptr_); \
625 if ((_len_) == 255) { \
626 FB_READINC_U16(_len_, _ptr_); \
627 } \
628 }
629
630 #define FB_READ_LIST_LENGTH_REM(_len_, _ptr_, _rem_) { \
631 FB_READINCREM_U8(_len_, _ptr_, _rem_); \
632 if ((_len_) == 255) { \
633 FB_READINCREM_U16(_len_, _ptr_, _rem_); \
634 } \
635 }
636
637
638 /**
639 * fbTranscodeOffsets
640 *
641 * @param s_tmpl
642 * @param s_base
643 * @param s_rem
644 * @param decode
645 * @param offsets_out
646 * @param err - glib2 GError structure that returns the message on failure
647 *
648 * @return
649 *
650 */
fbTranscodeOffsets(fbTemplate_t * s_tmpl,uint8_t * s_base,uint32_t s_rem,gboolean decode,uint16_t ** offsets_out,GError ** err)651 static ssize_t fbTranscodeOffsets(
652 fbTemplate_t *s_tmpl,
653 uint8_t *s_base,
654 uint32_t s_rem,
655 gboolean decode,
656 uint16_t **offsets_out,
657 GError **err)
658 {
659 fbInfoElement_t *s_ie;
660 uint8_t *sp;
661 uint16_t *offsets;
662 uint32_t s_len, i;
663
664 /* short circuit - return offset cache if present in template */
665 if (s_tmpl->off_cache) {
666 if (offsets_out) *offsets_out = s_tmpl->off_cache;
667 return s_tmpl->off_cache[s_tmpl->ie_count];
668 }
669
670 /* create new offsets array */
671 offsets = g_new0(uint16_t, s_tmpl->ie_count + 1);
672
673 /* populate it */
674 for (i = 0, sp = s_base; i < s_tmpl->ie_count; i++) {
675 offsets[i] = sp - s_base;
676 s_ie = s_tmpl->ie_ary[i];
677 if (s_ie->len == FB_IE_VARLEN) {
678 if (decode) {
679 FB_TC_SBC_OFF((*sp == 255) ? 3 : 1);
680 FB_READ_LIST_LENGTH_REM(s_len, sp, s_rem);
681 FB_TC_SBC_OFF(s_len);
682 sp += s_len; s_rem -= s_len;
683 } else {
684 if (s_ie->type == FB_BASIC_LIST) {
685 FB_TC_SBC_OFF(sizeof(fbBasicList_t));
686 sp += sizeof(fbBasicList_t);
687 s_rem -= sizeof(fbBasicList_t);
688 } else if (s_ie->type == FB_SUB_TMPL_LIST) {
689 FB_TC_SBC_OFF(sizeof(fbSubTemplateList_t));
690 sp += sizeof(fbSubTemplateList_t);
691 s_rem -= sizeof(fbSubTemplateList_t);
692 } else if (s_ie->type == FB_SUB_TMPL_MULTI_LIST) {
693 FB_TC_SBC_OFF(sizeof(fbSubTemplateMultiList_t));
694 sp += sizeof(fbSubTemplateMultiList_t);
695 s_rem -= sizeof(fbSubTemplateMultiList_t);
696 } else {
697 FB_TC_SBC_OFF(sizeof(fbVarfield_t));
698 sp += sizeof(fbVarfield_t);
699 s_rem -= sizeof(fbVarfield_t);
700 }
701 }
702 } else {
703 FB_TC_SBC_OFF(s_ie->len);
704 sp += s_ie->len; s_rem -= s_ie->len;
705 }
706 }
707
708 /* get EOR offset */
709 s_len = offsets[i] = sp - s_base;
710
711 /* cache offsets if possible */
712 if (!s_tmpl->is_varlen && offsets_out) {
713 s_tmpl->off_cache = offsets;
714 }
715
716 /* return offsets if possible */
717 if (offsets_out) {
718 *offsets_out = offsets;
719 } else {
720 *offsets_out = NULL;
721 fbTranscodeFreeVarlenOffsets(s_tmpl, offsets);
722 }
723
724 /* return EOR offset */
725 return s_len;
726
727 err:
728 g_free(offsets);
729 return -1;
730 }
731
732
733 /**
734 * fbTranscodeZero
735 *
736 *
737 *
738 *
739 *
740 */
fbTranscodeZero(uint8_t ** dp,uint32_t * d_rem,uint32_t len,GError ** err)741 static gboolean fbTranscodeZero(
742 uint8_t **dp,
743 uint32_t *d_rem,
744 uint32_t len,
745 GError **err)
746 {
747 /* Check for write overrun */
748 FB_TC_DBC(len, "zero transcode");
749
750 /* fill zeroes */
751 memset(*dp, 0, len);
752
753 /* maintain counters */
754 *dp += len; *d_rem -= len;
755
756 return TRUE;
757 }
758
759
760
761 #if G_BYTE_ORDER == G_BIG_ENDIAN
762
763
764
765 /**
766 * fbTranscodeFixedBigEndian
767 *
768 *
769 *
770 *
771 *
772 */
fbTranscodeFixedBigEndian(uint8_t * sp,uint8_t ** dp,uint32_t * d_rem,uint32_t s_len,uint32_t d_len,uint32_t flags,GError ** err)773 static gboolean fbTranscodeFixedBigEndian(
774 uint8_t *sp,
775 uint8_t **dp,
776 uint32_t *d_rem,
777 uint32_t s_len,
778 uint32_t d_len,
779 uint32_t flags,
780 GError **err)
781 {
782 FB_TC_DBC(d_len, "fixed transcode");
783
784 if (s_len == d_len) {
785 memcpy(*dp, sp, d_len);
786 } else if (s_len > d_len) {
787 if (flags & FB_IE_F_ENDIAN) {
788 memcpy(*dp, sp + (s_len - d_len), d_len);
789 } else {
790 memcpy(*dp, sp, d_len);
791 }
792 } else {
793 memset(*dp, 0, d_len);
794 if (flags & FB_IE_F_ENDIAN) {
795 memcpy(*dp + (d_len - s_len), sp, s_len);
796 } else {
797 memcpy(*dp, sp, s_len);
798 }
799 }
800
801 /* maintain counters */
802 *dp += d_len; *d_rem -= d_len;
803
804 return TRUE;
805 }
806
807 #define fbEncodeFixed fbTranscodeFixedBigEndian
808 #define fbDecodeFixed fbTranscodeFixedBigEndian
809 #else
810
811 /**
812 * fbTranscodeSwap
813 *
814 *
815 *
816 *
817 *
818 */
fbTranscodeSwap(uint8_t * a,uint32_t len)819 static void fbTranscodeSwap(
820 uint8_t *a,
821 uint32_t len)
822 {
823 uint32_t i;
824 uint8_t t;
825 for (i = 0; i < len/2; i++) {
826 t = a[i];
827 a[i] = a[(len-1)-i];
828 a[(len-1)-i] = t;
829 }
830 }
831
832
833 /**
834 * fbEncodeFixedLittleEndian
835 *
836 *
837 *
838 *
839 *
840 */
fbEncodeFixedLittleEndian(uint8_t * sp,uint8_t ** dp,uint32_t * d_rem,uint32_t s_len,uint32_t d_len,uint32_t flags,GError ** err)841 static gboolean fbEncodeFixedLittleEndian(
842 uint8_t *sp,
843 uint8_t **dp,
844 uint32_t *d_rem,
845 uint32_t s_len,
846 uint32_t d_len,
847 uint32_t flags,
848 GError **err)
849 {
850 FB_TC_DBC(d_len, "fixed LE encode");
851
852 if (s_len == d_len) {
853 memcpy(*dp, sp, d_len);
854 } else if (s_len > d_len) {
855 if (flags & FB_IE_F_ENDIAN) {
856 memcpy(*dp, sp, d_len);
857 } else {
858 memcpy(*dp, sp + (s_len - d_len), d_len);
859 }
860 } else {
861 memset(*dp, 0, d_len);
862 if (flags & FB_IE_F_ENDIAN) {
863 memcpy(*dp, sp, s_len);
864 } else {
865 memcpy(*dp + (d_len - s_len), sp, s_len);
866 }
867 }
868
869 /* swap bytes at destination if necessary */
870 if (d_len > 1 && (flags & FB_IE_F_ENDIAN)) {
871 fbTranscodeSwap(*dp, d_len);
872 }
873
874 /* maintain counters */
875 *dp += d_len; *d_rem -= d_len;
876
877 return TRUE;
878 }
879
880
881 /**
882 * fbDecodeFixedLittleEndian
883 *
884 *
885 *
886 *
887 *
888 */
fbDecodeFixedLittleEndian(uint8_t * sp,uint8_t ** dp,uint32_t * d_rem,uint32_t s_len,uint32_t d_len,uint32_t flags,GError ** err)889 static gboolean fbDecodeFixedLittleEndian(
890 uint8_t *sp,
891 uint8_t **dp,
892 uint32_t *d_rem,
893 uint32_t s_len,
894 uint32_t d_len,
895 uint32_t flags,
896 GError **err)
897 {
898 FB_TC_DBC(d_len, "fixed LE decode");
899 if (s_len == d_len) {
900 memcpy(*dp, sp, d_len);
901
902 } else if (s_len > d_len) {
903 if (flags & FB_IE_F_ENDIAN) {
904 memcpy(*dp, sp + (s_len - d_len), d_len);
905 } else {
906 memcpy(*dp, sp, d_len);
907 }
908 } else {
909 memset(*dp, 0, d_len);
910 if (flags & FB_IE_F_ENDIAN) {
911 memcpy(*dp + (d_len - s_len), sp, s_len);
912 } else {
913 memcpy(*dp, sp, s_len);
914 }
915 }
916
917 /* swap bytes at destination if necessary */
918 if (d_len > 1 && (flags & FB_IE_F_ENDIAN)) {
919 fbTranscodeSwap(*dp, d_len);
920 }
921
922 /* maintain counters */
923 *dp += d_len; *d_rem -= d_len;
924 return TRUE;
925 }
926
927 #define fbEncodeFixed fbEncodeFixedLittleEndian
928 #define fbDecodeFixed fbDecodeFixedLittleEndian
929 #endif
930
931
932 /**
933 * fbEncodeVarfield
934 *
935 *
936 *
937 *
938 *
939 */
fbEncodeVarfield(uint8_t * sp,uint8_t ** dp,uint32_t * d_rem,uint32_t flags,GError ** err)940 static gboolean fbEncodeVarfield(
941 uint8_t *sp,
942 uint8_t **dp,
943 uint32_t *d_rem,
944 uint32_t flags __attribute__((unused)),
945 GError **err)
946 {
947 uint32_t d_len;
948 fbVarfield_t *sv;
949 #if HAVE_ALIGNED_ACCESS_REQUIRED
950 fbVarfield_t sv_local;
951 sv = &sv_local;
952 memcpy(sv, sp, sizeof(fbVarfield_t));
953 #else
954 sv = (fbVarfield_t *)sp;
955 #endif
956
957 /* calculate total destination length */
958 d_len = sv->len + ((sv->len < 255) ? 1 : 3);
959
960 /* Check buffer bounds */
961 FB_TC_DBC(d_len, "variable-length encode");
962
963 /* emit IPFIX variable length */
964 if (sv->len < 255) {
965 FB_WRITEINC_U8(*dp, sv->len);
966 } else {
967 FB_WRITEINC_U8(*dp, 255);
968 FB_WRITEINC_U16(*dp, sv->len);
969 }
970
971 /* emit buffer contents */
972 if (sv->len && sv->buf) memcpy(*dp, sv->buf, sv->len);
973 /* maintain counters */
974 *dp += sv->len; *d_rem -= d_len;
975
976 return TRUE;
977 }
978
979
980 /**
981 * fbDecodeVarfield
982 *
983 * decodes a variable length IPFIX element into its C structure location
984 *
985 * @param sp source pointer
986 * @param dp destination pointer
987 * @param d_rem destination amount remaining
988 * @param flags unused
989 * @param err glib2 error structure to return error information
990 *
991 * @return true on success, false on error, check err return param for details
992 *
993 */
fbDecodeVarfield(uint8_t * sp,uint8_t ** dp,uint32_t * d_rem,uint32_t flags,GError ** err)994 static gboolean fbDecodeVarfield(
995 uint8_t *sp,
996 uint8_t **dp,
997 uint32_t *d_rem,
998 uint32_t flags __attribute__((unused)),
999 GError **err)
1000 {
1001 uint16_t s_len;
1002 fbVarfield_t *dv;
1003 #if HAVE_ALIGNED_ACCESS_REQUIRED
1004 fbVarfield_t dv_local;
1005 dv = &dv_local;
1006 #else
1007 dv = (fbVarfield_t *)*dp;
1008 #endif
1009
1010 /* calculate total source length */
1011 FB_READ_LIST_LENGTH(s_len, sp);
1012
1013 /* Okay. We know how long the source is. Check buffer bounds. */
1014 FB_TC_DBC(sizeof(fbVarfield_t), "variable-length decode");
1015
1016 /* Do transcode. Don't copy; fbVarfield_t's semantics allow us just
1017 to return a pointer into the read buffer. */
1018 dv->len = (uint32_t)s_len;
1019 dv->buf = s_len ? sp : NULL;
1020
1021 #if HAVE_ALIGNED_ACCESS_REQUIRED
1022 memcpy(*dp, dv, sizeof(fbVarfield_t));
1023 #endif
1024
1025 /* maintain counters */
1026 *dp += sizeof(fbVarfield_t); *d_rem -= sizeof(fbVarfield_t);
1027
1028 return TRUE;
1029 }
1030
1031 /*static gboolean fbDecodeFixedToVarlen(
1032 uint8_t *sp,
1033 uint8_t **dp,
1034 uint32_t *d_rem,
1035 uint32_t flags __attribute__((unused)),
1036 GError **err)
1037 {
1038 return FALSE;
1039 }
1040
1041 static gboolean fbEncodeFixedToVarlen(
1042 uint8_t *sp,
1043 uint16_t s_len,
1044 uint8_t **dp,
1045 uint32_t *d_rem,
1046 uint32_t flags __attribute__((unused)),
1047 GError **err)
1048 {
1049 uint32_t d_len;
1050 uint16_t sll;
1051
1052 d_len = s_len + ((s_len < 255) ? 1 : 3);
1053 FB_TC_DBC(d_len, "fixed to variable lengthed encode");
1054 if (s_len < 255) {
1055 **dp = (uint8_t)s_len;
1056 *dp += 1;
1057 } else {
1058 **dp = 255;
1059 sll = g_htons(s_len);
1060 memcpy(*dp + 1, &sll, sizeof(uint16_t));
1061 *dp += 3;
1062 }
1063
1064 if (s_len) {
1065 memcpy(*dp, sp, s_len);
1066 *dp += s_len;
1067 *d_rem -= d_len;
1068 }
1069
1070 return TRUE;
1071 }
1072
1073 static gboolean fbDecodeVarlenToFixed(
1074 uint8_t *sp,
1075 uint8_t **dp,
1076 uint32_t *d_rem,
1077 uint32_t flags __attribute__((unused)),
1078 GError **err)
1079 {
1080 return FALSE;
1081 }
1082
1083 static gboolean fbEncodeVarlenToFixed(
1084 uint8_t *sp,
1085 uint16_t d_len,
1086 uint8_t **dp,
1087 uint32_t *d_rem,
1088 uint32_t flags __attribute__((unused)),
1089 GError **err)
1090 {
1091 uint16_t lenDiff;
1092 fbVarfield_t *sVar = (fbVarfield_t*)sp;
1093 FB_TC_DBC(d_len, "varlen to fixed encode");
1094 if (sVar->len < d_len) {
1095 lenDiff = d_len - sVar->len;
1096 memset(*dp, 0, lenDiff);
1097 memcpy(*dp + lenDiff, sVar->buf, sVar->len);
1098 } else { copy d_len bytes, truncating the varfield at d_len
1099 memcpy(*dp, sVar->buf, d_len);
1100 }
1101
1102 if (d_len > 1 && (flags & FB_IE_F_ENDIAN)) {
1103 fbTranscodeSwap(*dp, d_len);
1104 }
1105
1106 *dp += d_len; *d_rem -= d_len;
1107
1108 return TRUE;
1109 } */
1110
1111
1112 /*
1113 * Returns the size of the memory needed to hold an info element.
1114 *
1115 * For fixed-length elements, this is its length. For variables
1116 * length elements, it is the size of a struct, either fbVarfield_t
1117 * or one of the List structures.
1118 */
fbSizeofIE(const fbInfoElement_t * ie)1119 static uint16_t fbSizeofIE(
1120 const fbInfoElement_t *ie)
1121 {
1122 if (FB_IE_VARLEN != ie->len) {
1123 return ie->len;
1124 }
1125 switch (ie->type) {
1126 case FB_BASIC_LIST:
1127 return sizeof(fbBasicList_t);
1128 case FB_SUB_TMPL_LIST:
1129 return sizeof(fbSubTemplateList_t);
1130 case FB_SUB_TMPL_MULTI_LIST:
1131 return sizeof(fbSubTemplateMultiList_t);
1132 default:
1133 return sizeof(fbVarfield_t);
1134 }
1135 }
1136
validBasicList(fbBasicList_t * basicList,GError ** err)1137 static gboolean validBasicList(
1138 fbBasicList_t *basicList,
1139 GError **err)
1140 {
1141 if (!basicList) {
1142 g_set_error(err, FB_ERROR_DOMAIN, FB_ERROR_IPFIX,
1143 "Null basic list pointer passed to encode");
1144 return FALSE;
1145 } else if (!basicList->infoElement) {
1146 g_set_error(err, FB_ERROR_DOMAIN, FB_ERROR_IPFIX,
1147 "Null information element in basic list passed to encode");
1148 return FALSE;
1149 } else if (basicList->numElements && !basicList->dataLength) {
1150 g_set_error(err, FB_ERROR_DOMAIN, FB_ERROR_IPFIX,
1151 "Positive num elements, but zero data length in basiclist");
1152 return FALSE;
1153 } else if (basicList->dataLength && !basicList->dataPtr) {
1154 g_set_error(err, FB_ERROR_DOMAIN, FB_ERROR_IPFIX,
1155 "Positive data length but null data pointer in basiclist");
1156 return FALSE;
1157 }
1158 return TRUE;
1159 }
1160
validSubTemplateList(fbSubTemplateList_t * STL,GError ** err)1161 static gboolean validSubTemplateList(
1162 fbSubTemplateList_t *STL,
1163 GError **err)
1164 {
1165 if (!STL) {
1166 g_set_error(err, FB_ERROR_DOMAIN, FB_ERROR_IPFIX,
1167 "Null sub template list pointer passed to encode");
1168 return FALSE;
1169 } else if (!STL->tmpl || !STL->tmplID) {
1170 g_set_error(err, FB_ERROR_DOMAIN, FB_ERROR_IPFIX,
1171 "Invalid template pointer %p or ID %d passed to STL encode",
1172 (void *)STL->tmpl, STL->tmplID);
1173 return FALSE;
1174 } else if (STL->numElements && !STL->dataLength.length)
1175 {
1176 g_set_error(err, FB_ERROR_DOMAIN, FB_ERROR_IPFIX,
1177 "Positive num elements, but zero data length in STL");
1178 return FALSE;
1179 } else if (STL->dataLength.length && !STL->dataPtr)
1180 {
1181 g_set_error(err, FB_ERROR_DOMAIN, FB_ERROR_IPFIX,
1182 "Positive data length but null data pointer in STL");
1183 return FALSE;
1184 }
1185 return TRUE;
1186 }
1187
validSubTemplateMultiList(fbSubTemplateMultiList_t * sTML,GError ** err)1188 static gboolean validSubTemplateMultiList(
1189 fbSubTemplateMultiList_t *sTML,
1190 GError **err)
1191 {
1192 if (!sTML) {
1193 g_set_error(err, FB_ERROR_DOMAIN, FB_ERROR_IPFIX,
1194 "Null sub template multi list pointer passed to encode");
1195 return FALSE;
1196 } else if (sTML->numElements && !sTML->firstEntry)
1197 {
1198 g_set_error(err, FB_ERROR_DOMAIN, FB_ERROR_IPFIX,
1199 "Positive num elements, but NULL first Entry in STML");
1200 return FALSE;
1201 }
1202 return TRUE;
1203 }
1204
validSubTemplateMultiListEntry(fbSubTemplateMultiListEntry_t * entry,GError ** err)1205 static gboolean validSubTemplateMultiListEntry(
1206 fbSubTemplateMultiListEntry_t *entry,
1207 GError **err)
1208 {
1209 if (!entry) {
1210 g_set_error(err, FB_ERROR_DOMAIN, FB_ERROR_IPFIX,
1211 "Null sub template multi list entry pointer");
1212 return FALSE;
1213 } else if (!entry->tmpl || !entry->tmplID) {
1214 g_set_error(
1215 err, FB_ERROR_DOMAIN, FB_ERROR_IPFIX,
1216 "Invalid template pointer %p or ID %d passed to STML encode",
1217 (void *)entry->tmpl, entry->tmplID);
1218 return FALSE;
1219 } else if (entry->dataLength && !entry->dataPtr) {
1220 g_set_error(err, FB_ERROR_DOMAIN, FB_ERROR_IPFIX,
1221 "Positive data length but null data pointer in STML");
1222 return FALSE;
1223 }
1224 return TRUE;
1225 }
1226 /* parses the data according to the external template to determine the number
1227 of bytes in the src for this template instance
1228 this function is intended to be used in decoding
1229 and assumes the values are still in NETWORK byte order
1230 data: pointer to the data that came accross the wire
1231 ext_tmpl: external template...what the data looks like on arrival
1232 bytesInSrc: number of bytes in incoming data used by the ext_tmpl
1233 */
1234
bytesUsedBySrcTemplate(const uint8_t * data,const fbTemplate_t * ext_tmpl,uint16_t * bytesInSrc)1235 static void bytesUsedBySrcTemplate(
1236 const uint8_t *data,
1237 const fbTemplate_t *ext_tmpl,
1238 uint16_t *bytesInSrc)
1239 {
1240 fbInfoElement_t *ie;
1241 const uint8_t *srcWalker = data;
1242 uint16_t len;
1243 int i;
1244
1245 if (!ext_tmpl->is_varlen) {
1246 *bytesInSrc = ext_tmpl->ie_len;
1247 return;
1248 }
1249
1250 for (i = 0; i < ext_tmpl->ie_count; i++) {
1251 ie = ext_tmpl->ie_ary[i];
1252 if (ie->len == FB_IE_VARLEN) {
1253 FB_READ_LIST_LENGTH(len, srcWalker);
1254 srcWalker += len;
1255 } else {
1256 srcWalker += ie->len;
1257 }
1258 }
1259 *bytesInSrc = srcWalker - data;
1260 }
1261
1262 static gboolean fbTranscode(
1263 fBuf_t *fbuf,
1264 gboolean decode,
1265 uint8_t *s_base,
1266 uint8_t *d_base,
1267 size_t *s_len,
1268 size_t *d_len,
1269 GError **err);
1270
1271 static gboolean fbEncodeBasicList(
1272 uint8_t *src,
1273 uint8_t **dst,
1274 uint32_t *d_rem,
1275 fBuf_t *fbuf,
1276 GError **err);
1277
1278 static gboolean fbDecodeBasicList(
1279 fbInfoModel_t *model,
1280 uint8_t *src,
1281 uint8_t **dst,
1282 uint32_t *d_rem,
1283 fBuf_t *fbuf,
1284 GError **err);
1285
1286 static gboolean fbEncodeSubTemplateList(
1287 uint8_t *src,
1288 uint8_t **dst,
1289 uint32_t *d_rem,
1290 fBuf_t *fbuf,
1291 GError **err);
1292
1293 static gboolean fbDecodeSubTemplateList(
1294 uint8_t *src,
1295 uint8_t **dst,
1296 uint32_t *d_rem,
1297 fBuf_t *fbuf,
1298 GError **err);
1299
1300 static gboolean fbEncodeSubTemplateMultiList(
1301 uint8_t *src,
1302 uint8_t **dst,
1303 uint32_t *d_rem,
1304 fBuf_t *fbuf,
1305 GError **err);
1306
1307 static gboolean fbDecodeSubTemplateMultiList(
1308 uint8_t *src,
1309 uint8_t **dst,
1310 uint32_t *d_rem,
1311 fBuf_t *fbuf,
1312 GError **err);
1313
1314 static gboolean fBufSetDecodeSubTemplates(
1315 fBuf_t *fbuf,
1316 uint16_t ext_tid,
1317 uint16_t int_tid,
1318 GError **err);
1319
1320 static gboolean fBufSetEncodeSubTemplates(
1321 fBuf_t *fbuf,
1322 uint16_t ext_tid,
1323 uint16_t int_tid,
1324 GError **err);
1325
1326 static gboolean fBufResetExportTemplate(
1327 fBuf_t *fbuf,
1328 uint16_t tid,
1329 GError **err);
1330
1331
fbEncodeBasicList(uint8_t * src,uint8_t ** dst,uint32_t * d_rem,fBuf_t * fbuf,GError ** err)1332 static gboolean fbEncodeBasicList(
1333 uint8_t *src,
1334 uint8_t **dst,
1335 uint32_t *d_rem,
1336 fBuf_t *fbuf,
1337 GError **err)
1338 {
1339 uint16_t totalLength;
1340 uint16_t headerLength;
1341 uint16_t dataLength = 0;
1342 uint16_t ie_len;
1343 uint16_t ie_num;
1344 uint8_t *lengthPtr = NULL;
1345 uint16_t i;
1346 gboolean enterprise = FALSE;
1347 uint8_t *prevDst = NULL;
1348 fbBasicList_t *basicList;
1349 uint8_t *thisItem = NULL;
1350 gboolean retval = FALSE;
1351 #if HAVE_ALIGNED_ACCESS_REQUIRED
1352 fbBasicList_t basicList_local;
1353 basicList = &basicList_local;
1354 memcpy(basicList, src, sizeof(fbBasicList_t));
1355 #else
1356 basicList = (fbBasicList_t*)src;
1357 #endif
1358
1359 if (!validBasicList(basicList, err)) {
1360 return FALSE;
1361 }
1362
1363 /* we need to check the buffer bounds throughout the function at each
1364 stage then decrement d_rem as we go */
1365
1366 /* header is 5 bytes:
1367 1 for the semantic
1368 2 for the field id
1369 2 for the field length
1370 */
1371
1372 headerLength = 5;
1373 ie_len = basicList->infoElement->len;
1374
1375 /* get the info element number */
1376 ie_num = basicList->infoElement->num;
1377
1378 /* check for enterprise value in the information element, to set bit
1379 Need to know if IE is enterprise before adding totalLength for
1380 fixed length IE's */
1381
1382 if (basicList->infoElement->ent) {
1383 enterprise = TRUE;
1384 ie_num |= 0x8000;
1385 headerLength += 4;
1386 }
1387
1388 /* enter the total bytes */
1389 if (ie_len == FB_IE_VARLEN) {
1390 /* check for room for the header */
1391 FB_TC_DBC(headerLength, "basic list encode header");
1392 (*d_rem) -= headerLength;
1393 } else {
1394 /* fixed length info element. */
1395 dataLength = basicList->numElements * ie_len;
1396 totalLength = headerLength + dataLength;
1397
1398 /* we know how long the entire list will be, test its length */
1399 FB_TC_DBC(totalLength, "basic list encode fixed list");
1400 (*d_rem) -= totalLength;
1401 }
1402
1403 /* encode as variable length field */
1404 FB_TC_DBC(3, "basic list variable length encode header");
1405 FB_WRITEINCREM_U8(*dst, 255, *d_rem);
1406
1407 /* Mark location of length */
1408 lengthPtr = *dst;
1409 (*dst) += 2;
1410 (*d_rem) -= 2;
1411
1412 /* Mark beginning of element */
1413 prevDst = *dst;
1414
1415 /* add the semantic field */
1416 FB_WRITEINC_U8(*dst, basicList->semantic);
1417
1418 /* write the element number */
1419 FB_WRITEINC_U16(*dst, ie_num);
1420
1421 /* add the info element length */
1422 FB_WRITEINC_U16(*dst, ie_len);
1423
1424 /* if enterprise specific info element, add the enterprise number */
1425 if (enterprise) {
1426 /* we alredy check room above (headerLength) for enterprise field */
1427 FB_WRITEINC_U32(*dst, basicList->infoElement->ent);
1428 }
1429
1430 if (basicList->numElements) {
1431 /* add the data */
1432 if (ie_len == FB_IE_VARLEN) {
1433 /* all future length checks will be done by the called
1434 * encoding functions */
1435 thisItem = basicList->dataPtr;
1436 switch (basicList->infoElement->type) {
1437 case FB_BASIC_LIST:
1438 for (i = 0; i < basicList->numElements; i++) {
1439 if (!fbEncodeBasicList(thisItem, dst, d_rem, fbuf, err)) {
1440 goto err;
1441 }
1442 thisItem += sizeof(fbBasicList_t);
1443 }
1444 break;
1445 case FB_SUB_TMPL_LIST:
1446 for (i = 0; i < basicList->numElements; i++) {
1447 if (!fbEncodeSubTemplateList(thisItem, dst, d_rem,
1448 fbuf, err))
1449 {
1450 goto err;
1451 }
1452 thisItem += sizeof(fbSubTemplateList_t);
1453 }
1454 break;
1455 case FB_SUB_TMPL_MULTI_LIST:
1456 for (i = 0; i < basicList->numElements; i++) {
1457 if (!fbEncodeSubTemplateMultiList(thisItem, dst,
1458 d_rem, fbuf, err))
1459 {
1460 goto err;
1461 }
1462 thisItem += sizeof(fbSubTemplateMultiList_t);
1463 }
1464 break;
1465 default:
1466 /* add the varfields, adding up the length field */
1467 for (i = 0; i < basicList->numElements; i++) {
1468 if (!fbEncodeVarfield(thisItem, dst, d_rem, 0, err)) {
1469 goto err;
1470 }
1471 thisItem += sizeof(fbVarfield_t);
1472 }
1473 }
1474 } else {
1475 uint32_t ieFlags = basicList->infoElement->flags;
1476 thisItem = basicList->dataPtr;
1477 for (i = 0; i < basicList->numElements; i++) {
1478 if (!fbEncodeFixed(thisItem, dst, d_rem, ie_len, ie_len,
1479 ieFlags, err))
1480 {
1481 goto err;
1482 }
1483 thisItem += ie_len;
1484 }
1485 }
1486 }
1487
1488 retval = TRUE;
1489
1490 err:
1491 totalLength = (uint16_t)((*dst) - prevDst);
1492 FB_WRITE_U16(lengthPtr, totalLength);
1493
1494 return retval;
1495 }
1496
fbDecodeBasicList(fbInfoModel_t * model,uint8_t * src,uint8_t ** dst,uint32_t * d_rem,fBuf_t * fbuf,GError ** err)1497 static gboolean fbDecodeBasicList(
1498 fbInfoModel_t *model,
1499 uint8_t *src,
1500 uint8_t **dst,
1501 uint32_t *d_rem,
1502 fBuf_t *fbuf,
1503 GError **err)
1504 {
1505 uint16_t srcLen;
1506 uint16_t elementLen;
1507 fbInfoElement_t tempElement;
1508 fbBasicList_t *basicList;
1509 uint8_t *srcWalker = NULL;
1510 uint8_t *thisItem = NULL;
1511 fbVarfield_t *thisVarfield = NULL;
1512 uint16_t len;
1513 int i;
1514 #if HAVE_ALIGNED_ACCESS_REQUIRED
1515 fbBasicList_t basicList_local;
1516 basicList = &basicList_local;
1517 memcpy(basicList, *dst, sizeof(fbBasicList_t));
1518 #else
1519 basicList = (fbBasicList_t*)*dst;
1520 #endif
1521
1522 /* check buffer bounds */
1523 if (d_rem) {
1524 FB_TC_DBC(sizeof(fbBasicList_t), "basic-list decode");
1525 }
1526 memset(&tempElement, 0, sizeof(fbInfoElement_t));
1527
1528 /* decode the length field and move the Buf ptr up to the next field */
1529 FB_READ_LIST_LENGTH(srcLen, src);
1530
1531 if (srcLen < 5) {
1532 g_set_error(err, FB_ERROR_DOMAIN, FB_ERROR_EOM,
1533 "Not enough bytes for basic list header to decode");
1534 return FALSE;
1535 }
1536 /* add the semantic field */
1537 FB_READINCREM_U8(basicList->semantic, src, srcLen);
1538
1539 /* pull the field ID */
1540 FB_READINCREM_U16(tempElement.num, src, srcLen);
1541
1542 /* pull the element length */
1543 FB_READINCREM_U16(elementLen, src, srcLen);
1544
1545 /* if enterprise bit is set, pull this field */
1546 if (tempElement.num & 0x8000) {
1547 if (srcLen < 4) {
1548 g_set_error(err, FB_ERROR_DOMAIN, FB_ERROR_EOM,
1549 "Not enough bytes for basic list header enterprise no.");
1550 return FALSE;
1551 }
1552 FB_READINCREM_U32(tempElement.ent, src, srcLen);
1553 tempElement.num &= 0x7fff;
1554 } else {
1555 tempElement.ent = 0;
1556 }
1557
1558 /* find the proper info element pointer based on what we built */
1559 basicList->infoElement = fbInfoModelGetElement(model, &tempElement);
1560 if (!basicList->infoElement) {
1561 /* if infoElement does not exist - notes it's alien and add it */
1562 tempElement.len = elementLen;
1563 basicList->infoElement = fbInfoModelAddAlienElement(model,
1564 &tempElement);
1565 if (!basicList->infoElement) {
1566 g_log(G_LOG_DOMAIN, G_LOG_LEVEL_WARNING,
1567 "BasicList Decode Error: No Information Element with ID %d "
1568 "defined", tempElement.num);
1569 basicList->semantic = 0;
1570 basicList->infoElement = NULL;
1571 basicList->numElements = 0;
1572 basicList->dataLength = 0;
1573 basicList->dataPtr = NULL;
1574 goto err;
1575 }
1576 }
1577
1578 if (elementLen == FB_IE_VARLEN) {
1579 /* first we need to find out the number of elements */
1580 basicList->numElements = 0;
1581
1582 /* if there isn't memory allocated yet, figure out how much */
1583 srcWalker = src;
1584 /* while we haven't walked the entire list... */
1585 while (srcLen > (srcWalker - src)) {
1586 /* parse the length of each, and jump to the next */
1587 FB_READ_LIST_LENGTH(len, srcWalker);
1588 srcWalker += len;
1589 basicList->numElements++;
1590 }
1591
1592 /* now that we know the number of elements, we need to parse the
1593 specific varlen field */
1594
1595 switch (basicList->infoElement->type) {
1596 case FB_BASIC_LIST:
1597 if (!basicList->dataPtr) {
1598 basicList->dataLength =
1599 basicList->numElements * sizeof(fbBasicList_t);
1600 basicList->dataPtr = g_slice_alloc0(basicList->dataLength);
1601 }
1602 thisItem = basicList->dataPtr;
1603 /* thisItem will be incremented by DecodeBasicList's dst
1604 * double pointer */
1605 for (i = 0; i < basicList->numElements; i++) {
1606 if (!fbDecodeBasicList(
1607 model, src, &thisItem, NULL, fbuf, err))
1608 {
1609 return FALSE;
1610 }
1611 /* now figure out how much to increment src by and repeat */
1612 FB_READ_LIST_LENGTH(len, src);
1613 src += len;
1614 }
1615 break;
1616 case FB_SUB_TMPL_LIST:
1617 if (!basicList->dataPtr) {
1618 basicList->dataLength =
1619 basicList->numElements * sizeof(fbSubTemplateList_t);
1620 basicList->dataPtr = g_slice_alloc0(basicList->dataLength);
1621 }
1622 thisItem = basicList->dataPtr;
1623 /* thisItem will be incremented by DecodeSubTemplateList's
1624 * dst double pointer */
1625 for (i = 0; i < basicList->numElements; i++) {
1626 if (!fbDecodeSubTemplateList(src, &thisItem, NULL, fbuf, err))
1627 {
1628 return FALSE;
1629 }
1630 /* now figure out how much to increment src by and repeat */
1631 FB_READ_LIST_LENGTH(len, src);
1632 src += len;
1633 }
1634 break;
1635 case FB_SUB_TMPL_MULTI_LIST:
1636 if (!basicList->dataPtr) {
1637 basicList->dataLength =
1638 basicList->numElements * sizeof(fbSubTemplateMultiList_t);
1639 basicList->dataPtr = g_slice_alloc0(basicList->dataLength);
1640 }
1641 thisItem = basicList->dataPtr;
1642 /* thisItem will be incremented by DecodeSubTemplateMultiList's
1643 * dst double pointer */
1644 for (i = 0; i < basicList->numElements; i++) {
1645 if (!fbDecodeSubTemplateMultiList(src, &thisItem,
1646 NULL, fbuf, err))
1647 {
1648 return FALSE;
1649 }
1650 /* now figure out how much to increment src by and repeat */
1651 FB_READ_LIST_LENGTH(len, src);
1652 src += len;
1653 }
1654 break;
1655 default:
1656 if (!basicList->dataPtr) {
1657 basicList->dataLength =
1658 basicList->numElements * sizeof(fbVarfield_t);
1659 basicList->dataPtr = g_slice_alloc0(basicList->dataLength);
1660 }
1661
1662 /* now pull the data numElements times */
1663 thisVarfield = (fbVarfield_t*)basicList->dataPtr;
1664 for (i = 0; i < basicList->numElements; i++) {
1665 /* decode the length */
1666 FB_READ_LIST_LENGTH(thisVarfield->len, src);
1667 thisVarfield->buf = src;
1668 src += thisVarfield->len;
1669 ++thisVarfield;
1670 }
1671 }
1672 } else {
1673 if (srcLen) {
1674 /* fixed length field, allocate if needed, then copy */
1675 uint32_t ieFlags = basicList->infoElement->flags;
1676 uint32_t dRem = (uint32_t)srcLen;
1677
1678 basicList->numElements = srcLen / elementLen;
1679 if (!basicList->dataPtr) {
1680 basicList->dataLength = srcLen;
1681 basicList->dataPtr = g_slice_alloc0(basicList->dataLength);
1682 }
1683
1684 thisItem = basicList->dataPtr;
1685
1686 for (i = 0; i < basicList->numElements; i++) {
1687 if (!fbDecodeFixed(src, &thisItem, &dRem, elementLen,
1688 elementLen, ieFlags, err)) {
1689 return FALSE;
1690 }
1691
1692 src += elementLen;
1693 }
1694 }
1695 }
1696
1697 err:
1698 #if HAVE_ALIGNED_ACCESS_REQUIRED
1699 memcpy(*dst, basicList, sizeof(fbBasicList_t));
1700 #endif
1701 (*dst) += sizeof(fbBasicList_t);
1702 if (d_rem) {
1703 *d_rem -= sizeof(fbBasicList_t);
1704 }
1705 return TRUE;
1706 }
1707
fbEncodeSubTemplateList(uint8_t * src,uint8_t ** dst,uint32_t * d_rem,fBuf_t * fbuf,GError ** err)1708 static gboolean fbEncodeSubTemplateList(
1709 uint8_t *src,
1710 uint8_t **dst,
1711 uint32_t *d_rem,
1712 fBuf_t *fbuf,
1713 GError **err)
1714 {
1715 fbSubTemplateList_t *subTemplateList;
1716 uint16_t len;
1717 uint16_t i;
1718 size_t srcLen = 0;
1719 size_t dstLen = 0;
1720 uint8_t *lenPtr = NULL;
1721 uint16_t tempIntID;
1722 uint16_t tempExtID;
1723 uint16_t dataPtrOffset = 0;
1724 size_t srcRem = 0;
1725 gboolean retval = FALSE;
1726 GError *child_err = NULL;
1727 #if HAVE_ALIGNED_ACCESS_REQUIRED
1728 fbSubTemplateList_t subTemplateList_local;
1729 subTemplateList = &subTemplateList_local;
1730 memcpy(subTemplateList, src, sizeof(fbSubTemplateList_t));
1731 #else
1732 subTemplateList = (fbSubTemplateList_t *)src;
1733 #endif
1734
1735 if (!validSubTemplateList(subTemplateList, err)) {
1736 return FALSE;
1737 }
1738
1739 /* check that there are 7 bytes available in the buffer for the header */
1740 FB_TC_DBC(6, "sub template list header");
1741 (*d_rem) -= 6;
1742
1743 /* build the subtemplatelist metadata */
1744 /* encode as variable length */
1745 FB_WRITEINC_U8(*dst, 255);
1746
1747 /* Save a pointer to the length location in this subTemplateList */
1748 lenPtr = *dst;
1749 (*dst) += 2;
1750
1751 /* write the semantic value */
1752 FB_WRITEINC_U8(*dst, subTemplateList->semantic);
1753
1754 /* encode the template ID */
1755 FB_WRITEINC_U16(*dst, subTemplateList->tmplID);
1756
1757 /* store off the current template ids so we can put them back */
1758 tempIntID = fbuf->int_tid;
1759 tempExtID = fbuf->ext_tid;
1760
1761 /* set the templates to that used for this subTemplateList */
1762 if (!fBufSetEncodeSubTemplates(fbuf, subTemplateList->tmplID,
1763 subTemplateList->tmplID, err))
1764 {
1765 goto err;
1766 }
1767
1768 dataPtrOffset = 0;
1769 /* max source length is length of dataPtr */
1770 srcRem = subTemplateList->dataLength.length;
1771
1772 for (i = 0; i < subTemplateList->numElements; i++) {
1773 srcLen = srcRem;
1774 dstLen = *d_rem;
1775
1776 /* transcode the sub template multi list*/
1777 if (!fbTranscode(fbuf, FALSE, subTemplateList->dataPtr + dataPtrOffset,
1778 *dst, &srcLen, &dstLen, err))
1779 {
1780 goto err;
1781 }
1782 /* move up the dst pointer by how much we used in transcode */
1783 (*dst) += dstLen;
1784 /* subtract from d_rem the number of dst bytes used in transcode */
1785 *d_rem -= dstLen;
1786 /* more the src offset for the next transcode by src bytes used */
1787 dataPtrOffset += srcLen;
1788 /* subtract from the original data len for new max value */
1789 srcRem -= srcLen;
1790 }
1791
1792 retval = TRUE;
1793
1794 err:
1795 /* once transcoding is done, store the list length */
1796 len = ((*dst) - lenPtr) - 2;
1797 FB_WRITE_U16(lenPtr, len);
1798
1799 /* reset the templates */
1800 if (tempIntID == tempExtID) {
1801 /* if equal tempIntID is an external template */
1802 /* so calling setInternalTemplate with tempIntID won't find tmpl */
1803 fBufSetEncodeSubTemplates(fbuf, tempExtID, tempIntID, NULL);
1804 } else {
1805 if (!fBufSetInternalTemplate(fbuf, tempIntID, &child_err)) {
1806 if (retval) {
1807 g_propagate_error(err, child_err);
1808 } else {
1809 g_clear_error(&child_err);
1810 }
1811 return FALSE;
1812 }
1813 if (!fBufResetExportTemplate(fbuf, tempExtID, &child_err)) {
1814 if (retval) {
1815 g_propagate_error(err, child_err);
1816 } else {
1817 g_clear_error(&child_err);
1818 }
1819 return FALSE;
1820 }
1821 }
1822
1823 return retval;
1824 }
1825
fbDecodeSubTemplateList(uint8_t * src,uint8_t ** dst,uint32_t * d_rem,fBuf_t * fbuf,GError ** err)1826 static gboolean fbDecodeSubTemplateList(
1827 uint8_t *src,
1828 uint8_t **dst,
1829 uint32_t *d_rem,
1830 fBuf_t *fbuf,
1831 GError **err)
1832 {
1833 fbSubTemplateList_t *subTemplateList;
1834 fbTemplate_t *extTemplate = NULL;
1835 fbTemplate_t *intTemplate = NULL;
1836 size_t srcLen;
1837 size_t dstLen;
1838 uint16_t srcRem;
1839 uint16_t dstRem;
1840 uint16_t tempIntID;
1841 uint16_t tempExtID;
1842 fbTemplate_t *tempIntPtr;
1843 fbTemplate_t *tempExtPtr;
1844 uint32_t i;
1845 gboolean rc = TRUE;
1846 uint8_t *subTemplateDst = NULL;
1847 uint16_t offset = 0;
1848 uint16_t bytesInSrc;
1849 uint16_t int_tid = 0;
1850 uint16_t ext_tid;
1851 #if HAVE_ALIGNED_ACCESS_REQUIRED
1852 fbSubTemplateList_t subTemplateList_local;
1853 subTemplateList = &subTemplateList_local;
1854 memcpy(subTemplateList, *dst, sizeof(fbSubTemplateList_t));
1855 #else
1856 subTemplateList = (fbSubTemplateList_t *)*dst;
1857 #endif
1858
1859 /* decode the length of the list */
1860 FB_READ_LIST_LENGTH(srcLen, src);
1861
1862 if (srcLen < 3) {
1863 g_set_error(err, FB_ERROR_DOMAIN, FB_ERROR_EOM,
1864 "Not enough bytes for the sub template list header");
1865 return FALSE;
1866 }
1867
1868 if (d_rem) {
1869 FB_TC_DBC(sizeof(fbSubTemplateList_t), "sub-template-list decode");
1870 }
1871
1872 FB_READINCREM_U8(subTemplateList->semantic, src, srcLen);
1873 FB_READINCREM_U16(ext_tid, src, srcLen);
1874
1875 /* get the template */
1876 extTemplate = fbSessionGetTemplate(fbuf->session, FALSE, ext_tid, err);
1877
1878 if (extTemplate) {
1879 int_tid = fbSessionLookupTemplatePair(fbuf->session, ext_tid);
1880 if (int_tid == ext_tid) {
1881 /* is there an internal tid with the same tid as the
1882 external tid? If so, get it. If not, set
1883 the internal template to the external template */
1884 intTemplate = fbSessionGetTemplate(fbuf->session,
1885 TRUE,
1886 int_tid, err);
1887 if (!intTemplate) {
1888 g_clear_error(err);
1889 intTemplate = extTemplate;
1890 }
1891 } else if (int_tid != 0) {
1892 intTemplate = fbSessionGetTemplate(fbuf->session,
1893 TRUE,
1894 int_tid, err);
1895 if (!intTemplate) {
1896 return FALSE;
1897 }
1898 }
1899 }
1900
1901 if (!extTemplate || !intTemplate) {
1902 /* we need both to continue on this item*/
1903 if (!extTemplate) {
1904 g_clear_error(err);
1905 g_warning("Skipping SubTemplateList. No Template %#06x Present.",
1906 ext_tid);
1907 }
1908 /* if (!(extTemplate)) {
1909 g_clear_error(err);
1910 g_set_error(err, FB_ERROR_DOMAIN, FB_ERROR_IPFIX,
1911 "Template does not exist for template ID: %#06x",
1912 ext_tid);
1913 return FALSE;
1914 }
1915
1916 int_tid = fbSessionLookupTemplatePair(fbuf->session, ext_tid);
1917 if (int_tid == ext_tid) {
1918 intTemplate = extTemplate;
1919 } else if (int_tid != 0){
1920 intTemplate = fbSessionGetTemplate(fbuf->session,
1921 TRUE,
1922 int_tid,
1923 err);
1924 } else {*/
1925 /* the collector doesn't want this template...ever
1926 don't move the dst pointer at all!
1927 the source pointer will get moved up in fbTranscode(),
1928 which won't know we didn't do anything */
1929
1930 subTemplateList->semantic = 0;
1931 subTemplateList->tmplID = 0;
1932 subTemplateList->tmpl = NULL;
1933 subTemplateList->dataLength.length = 0;
1934 subTemplateList->dataPtr = NULL;
1935 subTemplateList->numElements = 0;
1936 goto end;
1937 }
1938
1939 subTemplateList->tmplID = int_tid;
1940 subTemplateList->tmpl = intTemplate;
1941
1942 /* now we wanna transcode length / templateSize elements */
1943 if (extTemplate->is_varlen) {
1944 uint8_t *srcWalker = src;
1945 subTemplateList->numElements = 0;
1946
1947 while (srcLen > (size_t)(srcWalker - src)) {
1948 bytesUsedBySrcTemplate(srcWalker, extTemplate, &bytesInSrc);
1949 srcWalker += bytesInSrc;
1950 subTemplateList->numElements++;
1951 }
1952
1953 if (!subTemplateList->dataPtr) {
1954
1955 subTemplateList->dataLength.length = intTemplate->ie_internal_len *
1956 subTemplateList->numElements;
1957 if (subTemplateList->dataLength.length) {
1958 subTemplateList->dataPtr =
1959 g_slice_alloc0(subTemplateList->dataLength.length);
1960 }
1961 dstRem = subTemplateList->dataLength.length;
1962 } else {
1963 if (subTemplateList->dataLength.length <
1964 (size_t)(intTemplate->ie_internal_len *
1965 subTemplateList->numElements))
1966 {
1967 subTemplateList->semantic = 0;
1968 subTemplateList->tmplID = 0;
1969 subTemplateList->tmpl = NULL;
1970 subTemplateList->dataLength.length = 0;
1971 subTemplateList->dataPtr = NULL;
1972 subTemplateList->numElements = 0;
1973 g_warning("SubTemplateList and Template Length mismatch. "
1974 "Was fbSubTemplateListCollectorInit() called "
1975 "during setup?");
1976
1977 goto end;
1978 }
1979
1980 dstRem =
1981 intTemplate->ie_internal_len * subTemplateList->numElements;
1982 }
1983 } else {
1984 subTemplateList->numElements = srcLen / extTemplate->ie_len;
1985 subTemplateList->dataLength.length = subTemplateList->numElements *
1986 intTemplate->ie_internal_len;
1987 if (!subTemplateList->dataPtr) {
1988 if (subTemplateList->dataLength.length) {
1989 subTemplateList->dataPtr =
1990 g_slice_alloc0(subTemplateList->dataLength.length);
1991 }
1992 }
1993 dstRem = subTemplateList->dataLength.length;
1994 }
1995
1996 tempExtID = fbuf->ext_tid;
1997 tempIntID = fbuf->int_tid;
1998 tempExtPtr = fbuf->ext_tmpl;
1999 tempIntPtr = fbuf->int_tmpl;
2000
2001 fBufSetDecodeSubTemplates(fbuf, ext_tid, int_tid, NULL);
2002
2003 subTemplateDst = subTemplateList->dataPtr;
2004 srcRem = srcLen;
2005 offset = 0;
2006 for (i = 0; i < subTemplateList->numElements && rc; i++) {
2007 srcLen = srcRem;
2008 dstLen = dstRem;
2009 rc = fbTranscode(fbuf, TRUE, src + offset, subTemplateDst, &srcLen,
2010 &dstLen, err);
2011 if (rc) {
2012 subTemplateDst += dstLen;
2013 dstRem -= dstLen;
2014 srcRem -= srcLen;
2015 offset += srcLen;
2016 } else {
2017 g_prefix_error(err, "Error Decoding SubTemplateList:");
2018 return FALSE;
2019 }
2020 /* transcode numElements number of records */
2021 }
2022
2023 if (tempIntPtr == tempExtPtr) {
2024 fBufSetDecodeSubTemplates(fbuf, tempExtID, tempIntID, NULL);
2025 } else {
2026 if (!fBufSetInternalTemplate(fbuf, tempIntID, err)) {
2027 return FALSE;
2028 }
2029 if (!fBufResetExportTemplate(fbuf, tempExtID, err)) {
2030 return FALSE;
2031 }
2032 }
2033
2034 end:
2035 #if HAVE_ALIGNED_ACCESS_REQUIRED
2036 memcpy(*dst, subTemplateList, sizeof(fbSubTemplateList_t));
2037 #endif
2038 *dst += sizeof(fbSubTemplateList_t);
2039 if (d_rem) {
2040 *d_rem -= sizeof(fbSubTemplateList_t);
2041 }
2042 return TRUE;
2043 }
2044
fbEncodeSubTemplateMultiList(uint8_t * src,uint8_t ** dst,uint32_t * d_rem,fBuf_t * fbuf,GError ** err)2045 static gboolean fbEncodeSubTemplateMultiList(
2046 uint8_t *src,
2047 uint8_t **dst,
2048 uint32_t *d_rem,
2049 fBuf_t *fbuf,
2050 GError **err)
2051 {
2052 fbSubTemplateMultiList_t *multiList;
2053 fbSubTemplateMultiListEntry_t *entry = NULL;
2054 uint16_t length;
2055 uint16_t i, j;
2056 size_t srcLen = 0;
2057 size_t dstLen = 0;
2058 uint8_t *lenPtr = NULL;
2059 uint8_t *entryLenPtr = NULL;
2060 uint16_t tempIntID;
2061 uint16_t tempExtID;
2062 uint16_t srcPtrOffset = 0;
2063 size_t srcRem = 0;
2064 gboolean retval = FALSE;
2065 GError *child_err = NULL;
2066 #if HAVE_ALIGNED_ACCESS_REQUIRED
2067 fbSubTemplateMultiList_t multiList_local;
2068 multiList = &multiList_local;
2069 memcpy(multiList, src, sizeof(fbSubTemplateMultiList_t));
2070 #else
2071 multiList = (fbSubTemplateMultiList_t *)src;
2072 #endif
2073
2074 /* calculate total destination length */
2075
2076 if (!validSubTemplateMultiList(multiList, err)) {
2077 return FALSE;
2078 }
2079 /* Check buffer bounds */
2080 FB_TC_DBC(4, "multi list header");
2081 (*d_rem) -= 4;
2082
2083 FB_WRITEINC_U8(*dst, 255);
2084
2085 /* set the pointer to the length of this subTemplateList */
2086 lenPtr = *dst;
2087 (*dst) += 2;
2088
2089 FB_WRITEINC_U8(*dst, multiList->semantic);
2090
2091 tempIntID = fbuf->int_tid;
2092 tempExtID = fbuf->ext_tid;
2093
2094 entry = multiList->firstEntry;
2095
2096 for (i = 0; i < multiList->numElements; i++) {
2097 if (!validSubTemplateMultiListEntry(entry, err)) {
2098 g_clear_error(err);
2099 entry++;
2100 continue;
2101 }
2102
2103 /* check to see if there's enough length for the entry header */
2104 FB_TC_DBC_ERR(4, "multi list entry header");
2105 (*d_rem) -= 4;
2106
2107 /* at this point, it's very similar to a subtemplatelist */
2108 /* template ID */
2109 FB_WRITEINC_U16(*dst, entry->tmplID);
2110
2111 /* save template data length location */
2112 entryLenPtr = *dst;
2113 (*dst) += 2;
2114
2115 if (!fBufSetEncodeSubTemplates(fbuf, entry->tmplID,entry->tmplID,err))
2116 {
2117 goto err;
2118 }
2119 srcRem = entry->dataLength;
2120
2121 srcPtrOffset = 0;
2122 for (j = 0; j < entry->numElements; j++) {
2123 srcLen = srcRem;
2124 dstLen = *d_rem;
2125 if (!fbTranscode(fbuf, FALSE, entry->dataPtr + srcPtrOffset, *dst,
2126 &srcLen, &dstLen, err))
2127 {
2128 goto err;
2129 }
2130 (*dst) += dstLen;
2131 (*d_rem) -= dstLen;
2132 srcPtrOffset += srcLen;
2133 *entryLenPtr += dstLen;
2134 srcRem -= srcLen;
2135 }
2136
2137 length = *dst - entryLenPtr + 2; /* +2 for template ID */
2138 FB_WRITE_U16(entryLenPtr, length);
2139 entry++;
2140 }
2141
2142 retval = TRUE;
2143
2144 err:
2145 /* Write length */
2146 length = ((*dst) - lenPtr) - 2;
2147 FB_WRITE_U16(lenPtr, length);
2148
2149 /* Put templates back */
2150 if (tempIntID == tempExtID) {
2151 fBufSetEncodeSubTemplates(fbuf, tempExtID, tempIntID, NULL);
2152 } else {
2153 if (!fBufSetInternalTemplate(fbuf, tempIntID, &child_err)) {
2154 if (retval) {
2155 g_propagate_error(err, child_err);
2156 } else {
2157 g_clear_error(&child_err);
2158 }
2159 return FALSE;
2160 }
2161 if (!fBufResetExportTemplate(fbuf, tempExtID, &child_err)) {
2162 if (retval) {
2163 g_propagate_error(err, child_err);
2164 } else {
2165 g_clear_error(&child_err);
2166 }
2167 return FALSE;
2168 }
2169 }
2170
2171 return retval;
2172 }
2173
fbDecodeSubTemplateMultiList(uint8_t * src,uint8_t ** dst,uint32_t * d_rem,fBuf_t * fbuf,GError ** err)2174 static gboolean fbDecodeSubTemplateMultiList(
2175 uint8_t *src,
2176 uint8_t **dst,
2177 uint32_t *d_rem,
2178 fBuf_t *fbuf,
2179 GError **err)
2180 {
2181 fbSubTemplateMultiList_t *multiList;
2182 fbTemplate_t *extTemplate = NULL, *intTemplate = NULL;
2183 size_t srcLen;
2184 uint16_t bytesInSrc;
2185 size_t dstLen;
2186 size_t srcRem;
2187 size_t dstRem;
2188 uint16_t tempIntID;
2189 fbTemplate_t *tempIntPtr;
2190 uint16_t tempExtID;
2191 fbTemplate_t *tempExtPtr;
2192 gboolean rc = TRUE;
2193 uint8_t *srcWalker = NULL;
2194 fbSubTemplateMultiListEntry_t *entry = NULL;
2195 uint16_t thisTemplateLength;
2196 uint16_t i;
2197 uint16_t j;
2198 uint16_t int_tid = 0;
2199 uint16_t ext_tid;
2200 uint8_t *thisTemplateDst;
2201 #if HAVE_ALIGNED_ACCESS_REQUIRED
2202 fbSubTemplateMultiList_t multiList_local;
2203 multiList = &multiList_local;
2204 memcpy(multiList, *dst, sizeof(fbSubTemplateMultiList_t));
2205 #else
2206 multiList = (fbSubTemplateMultiList_t *)*dst;
2207 #endif
2208
2209 FB_READ_LIST_LENGTH(srcLen, src);
2210
2211 if (d_rem) {
2212 FB_TC_DBC(sizeof(fbSubTemplateMultiList_t),
2213 "sub-template-multi-list decode");
2214 }
2215
2216 if (srcLen == 0) {
2217 g_set_error(err, FB_ERROR_DOMAIN, FB_ERROR_EOM,
2218 "Insufficient bytes for subTemplateMultiList header to "
2219 "decode");
2220 return FALSE;
2221 }
2222
2223 FB_READINCREM_U8(multiList->semantic, src, srcLen);
2224
2225 tempExtID = fbuf->ext_tid;
2226 tempIntID = fbuf->int_tid;
2227 tempExtPtr = fbuf->ext_tmpl;
2228 tempIntPtr = fbuf->int_tmpl;
2229 multiList->numElements = 0;
2230
2231 /* figure out how many elements are here */
2232 srcWalker = src;
2233 while (srcLen > (size_t)(srcWalker - src)) {
2234 /* jump over the template ID */
2235 srcWalker += 2;
2236 FB_READINC_U16(bytesInSrc, srcWalker);
2237 if (bytesInSrc < 4) {
2238 g_warning("Invalid Length (%d) in STML Record", bytesInSrc);
2239 break;
2240 }
2241 srcWalker += bytesInSrc - 4;
2242 multiList->numElements++;
2243 }
2244
2245 multiList->firstEntry = g_slice_alloc0(multiList->numElements *
2246 sizeof(fbSubTemplateMultiListEntry_t));
2247 entry = multiList->firstEntry;
2248
2249 for (i = 0; i < multiList->numElements; i++) {
2250 intTemplate = NULL;
2251 FB_READINC_U16(ext_tid, src);
2252 extTemplate = fbSessionGetTemplate(fbuf->session,
2253 FALSE,
2254 ext_tid,
2255 err);
2256 /* OLD WAY...
2257 if (!extTemplate) {
2258 return FALSE;
2259 }
2260 int_tid = fbSessionLookupTemplatePair(fbuf->session, ext_tid);
2261
2262 if (int_tid == ext_tid) {
2263 intTemplate = extTemplate;
2264 } else if (int_tid != 0) {
2265 intTemplate = fbSessionGetTemplate(fbuf->session,
2266 TRUE,
2267 int_tid,
2268 err);
2269 if (!intTemplate) {
2270 return FALSE;
2271 }
2272
2273 } else {
2274 entry->tmpl = NULL;
2275 entry->tmplID = 0;
2276 entry->dataLength = 0;
2277 entry->dataPtr = NULL;
2278
2279 FB_READ_U16(thisTemplateLength, src);
2280 thisTemplateLength -= 2;
2281
2282 src += thisTemplateLength;
2283 entry++;
2284
2285 continue;
2286 }*/
2287
2288 if (extTemplate) {
2289 int_tid = fbSessionLookupTemplatePair(fbuf->session, ext_tid);
2290 if (int_tid == ext_tid) {
2291 /* is it possible that there could be an internal
2292 template with the same template id as the external
2293 template? - check now */
2294 intTemplate = fbSessionGetTemplate(fbuf->session,
2295 TRUE,
2296 int_tid, err);
2297 if (!intTemplate) {
2298 g_clear_error(err);
2299 intTemplate = extTemplate;
2300 }
2301 } else if (int_tid != 0) {
2302 intTemplate = fbSessionGetTemplate(fbuf->session,
2303 TRUE,
2304 int_tid, err);
2305 if (!intTemplate) {
2306 return FALSE;
2307 }
2308 }
2309 }
2310 if (!extTemplate || !intTemplate) {
2311 /* we need both to continue on this item*/
2312 if (!extTemplate) {
2313 g_clear_error(err);
2314 g_warning("Skipping STML Item. No Template %#06x Present.",
2315 ext_tid);
2316 }
2317 entry->tmpl = NULL;
2318 entry->tmplID = 0;
2319 entry->dataLength = 0;
2320 entry->dataPtr = NULL;
2321 FB_READ_U16(thisTemplateLength, src);
2322 thisTemplateLength -= 2;
2323
2324 src += thisTemplateLength;
2325 entry++;
2326 continue;
2327 }
2328 entry->tmpl = intTemplate;
2329 entry->tmplID = int_tid;
2330 FB_READINC_U16(thisTemplateLength, src);
2331 thisTemplateLength -= 4; /* "removing" template id and length */
2332
2333 /* put src at the start of the content */
2334 if (!thisTemplateLength) {
2335 continue;
2336 }
2337
2338 if (extTemplate->is_varlen) {
2339
2340 srcWalker = src;
2341 entry->numElements = 0;
2342
2343 while (thisTemplateLength > (size_t)(srcWalker - src)) {
2344 bytesUsedBySrcTemplate(srcWalker, extTemplate, &bytesInSrc);
2345 srcWalker += bytesInSrc;
2346 entry->numElements++;
2347 }
2348
2349 entry->dataLength = intTemplate->ie_internal_len *
2350 entry->numElements;
2351 entry->dataPtr = g_slice_alloc0(entry->dataLength);
2352 } else {
2353 entry->numElements = thisTemplateLength / extTemplate->ie_len;
2354 entry->dataLength = entry->numElements *
2355 intTemplate->ie_internal_len;
2356 entry->dataPtr = g_slice_alloc0(entry->dataLength);
2357 }
2358
2359 dstRem = entry->dataLength;
2360
2361 dstLen = dstRem;
2362 srcRem = thisTemplateLength;
2363
2364 fBufSetDecodeSubTemplates(fbuf, ext_tid, int_tid, NULL);
2365
2366 thisTemplateDst = entry->dataPtr;
2367 for (j = 0; j < entry->numElements; j++) {
2368 srcLen = srcRem;
2369 dstLen = dstRem;
2370 rc = fbTranscode(fbuf, TRUE, src, thisTemplateDst, &srcLen,
2371 &dstLen, err);
2372 if (rc) {
2373 src += srcLen;
2374 thisTemplateDst += dstLen;
2375 srcRem -= srcLen;
2376 dstRem -= dstLen;
2377 } else {
2378 if (tempIntPtr == tempExtPtr) {
2379 fBufSetDecodeSubTemplates(fbuf, tempExtID, tempIntID, NULL);
2380 } else {
2381 fBufSetInternalTemplate(fbuf, tempIntID, NULL);
2382 fBufResetExportTemplate(fbuf, tempExtID, NULL);
2383 }
2384 return FALSE;
2385 }
2386 }
2387 entry++;
2388 }
2389
2390 if (tempIntPtr == tempExtPtr) {
2391 fBufSetDecodeSubTemplates(fbuf, tempExtID, tempIntID, NULL);
2392 } else {
2393 if (!fBufSetInternalTemplate(fbuf, tempIntID, err)) {
2394 return FALSE;
2395 }
2396 if (!fBufResetExportTemplate(fbuf, tempExtID, err)) {
2397 return FALSE;
2398 }
2399 }
2400
2401 #if HAVE_ALIGNED_ACCESS_REQUIRED
2402 memcpy(*dst, multiList, sizeof(fbSubTemplateMultiList_t));
2403 #endif
2404 *dst += sizeof(fbSubTemplateMultiList_t);
2405 if (d_rem) {
2406 *d_rem -= sizeof(fbSubTemplateMultiList_t);
2407 }
2408 return TRUE;
2409 }
2410
2411
2412 /**
2413 * fbTranscode
2414 *
2415 *
2416 *
2417 *
2418 *
2419 */
fbTranscode(fBuf_t * fbuf,gboolean decode,uint8_t * s_base,uint8_t * d_base,size_t * s_len,size_t * d_len,GError ** err)2420 static gboolean fbTranscode(
2421 fBuf_t *fbuf,
2422 gboolean decode,
2423 uint8_t *s_base,
2424 uint8_t *d_base,
2425 size_t *s_len,
2426 size_t *d_len,
2427 GError **err)
2428 {
2429 fbTranscodePlan_t *tcplan;
2430 fbTemplate_t *s_tmpl, *d_tmpl;
2431 ssize_t s_len_offset;
2432 uint16_t *offsets;
2433 uint8_t *dp;
2434 uint32_t s_off, d_rem, i;
2435 fbInfoElement_t *s_ie, *d_ie;
2436 gboolean ok = TRUE;
2437 uint8_t ie_type;
2438
2439 /* initialize walk of dest buffer */
2440 dp = d_base; d_rem = *d_len;
2441 /* select templates for transcode */
2442 if (decode) {
2443 s_tmpl = fbuf->ext_tmpl;
2444 d_tmpl = fbuf->int_tmpl;
2445 } else {
2446 s_tmpl = fbuf->int_tmpl;
2447 d_tmpl = fbuf->ext_tmpl;
2448 }
2449
2450 /* get a transcode plan */
2451 tcplan = fbTranscodePlan(fbuf, s_tmpl, d_tmpl);
2452
2453 /* get source record length and offsets */
2454 if ((s_len_offset = fbTranscodeOffsets(s_tmpl, s_base, *s_len,
2455 decode, &offsets, err)) < 0)
2456 {
2457 return FALSE;
2458 }
2459 *s_len = s_len_offset;
2460 #if FB_DEBUG_TC && FB_DEBUG_RD && FB_DEBUG_WR
2461 fBufDebugTranscodePlan(tcplan);
2462 if (offsets) fBufDebugTranscodeOffsets(s_tmpl, offsets);
2463 fBufDebugHex("tsrc", s_base, *s_len);
2464 #elif FB_DEBUG_TC && FB_DEBUG_RD
2465 if (decode) {
2466 fBufDebugTranscodePlan(tcplan);
2467 /* if (offsets) fBufDebugTranscodeOffsets(s_tmpl, offsets);
2468 fBufDebugHex("tsrc", s_base, *s_len);*/
2469 }
2470 if (!decode) {
2471 fBufDebugTranscodePlan(tcplan);
2472 if (offsets) fBufDebugTranscodeOffsets(s_tmpl, offsets);
2473 fBufDebugHex("tsrc", s_base, *s_len);
2474 }
2475 #endif
2476
2477 /* iterate over destination IEs, copying from source */
2478 for (i = 0; i < d_tmpl->ie_count; i++) {
2479 /* Get pointers to information elements and source offset */
2480 d_ie = d_tmpl->ie_ary[i];
2481 s_ie = (tcplan->si[i] == FB_TCPLAN_NULL) ? NULL : s_tmpl->ie_ary[tcplan->si[i]];
2482 s_off = s_ie ? offsets[tcplan->si[i]] : 0;
2483 if (s_ie == NULL) {
2484 /* Null source */
2485 uint32_t null_len;
2486 if (d_ie->len == FB_IE_VARLEN) {
2487 if (decode) {
2488 ie_type = d_ie->type;
2489 if (ie_type == FB_BASIC_LIST) {
2490 null_len = sizeof(fbBasicList_t);
2491 } else if (ie_type == FB_SUB_TMPL_LIST) {
2492 null_len = sizeof(fbSubTemplateList_t);
2493 } else if (ie_type == FB_SUB_TMPL_MULTI_LIST) {
2494 null_len = sizeof(fbSubTemplateMultiList_t);
2495 } else {
2496 null_len = sizeof(fbVarfield_t);
2497 }
2498 } else {
2499 null_len = 1;
2500 }
2501 } else {
2502 null_len = d_ie->len;
2503 }
2504 if (!(ok = fbTranscodeZero(&dp, &d_rem, null_len, err))) {
2505 goto end;
2506 }
2507 } else if (s_ie->len != FB_IE_VARLEN && d_ie->len != FB_IE_VARLEN) {
2508 if (decode) {
2509 ok = fbDecodeFixed(s_base + s_off, &dp, &d_rem,
2510 s_ie->len, d_ie->len,
2511 d_ie->flags, err);
2512 } else {
2513 ok = fbEncodeFixed(s_base + s_off, &dp, &d_rem,
2514 s_ie->len, d_ie->len,
2515 d_ie->flags, err);
2516 }
2517 if (!ok) {
2518 goto end;
2519 }
2520 } else if (s_ie->len == FB_IE_VARLEN && d_ie->len == FB_IE_VARLEN) {
2521 /* Varlen transcode */
2522 if (s_ie->type == FB_BASIC_LIST &&
2523 d_ie->type == FB_BASIC_LIST)
2524 {
2525 if (decode) {
2526 ok = fbDecodeBasicList(fbuf->ext_tmpl->model,
2527 s_base + s_off,
2528 &dp, &d_rem, fbuf,
2529 err);
2530 } else {
2531 ok = fbEncodeBasicList(s_base + s_off, &dp, &d_rem,
2532 fbuf, err);
2533 }
2534 if (!ok) {
2535 goto end;
2536 }
2537 }
2538 else if (s_ie->type == FB_SUB_TMPL_LIST &&
2539 d_ie->type == FB_SUB_TMPL_LIST)
2540 {
2541 if (decode) {
2542 ok = fbDecodeSubTemplateList(s_base + s_off,
2543 &dp,
2544 &d_rem,
2545 fbuf,
2546 err);
2547 } else {
2548 ok = fbEncodeSubTemplateList(s_base + s_off,
2549 &dp,
2550 &d_rem,
2551 fbuf,
2552 err);
2553 }
2554 if (!ok) {
2555 goto end;
2556 }
2557 }
2558 else if (s_ie->type == FB_SUB_TMPL_MULTI_LIST &&
2559 d_ie->type == FB_SUB_TMPL_MULTI_LIST)
2560 {
2561 if (decode) {
2562 ok = fbDecodeSubTemplateMultiList(s_base + s_off,
2563 &dp,
2564 &d_rem,
2565 fbuf,
2566 err);
2567 } else {
2568 ok = fbEncodeSubTemplateMultiList(s_base + s_off,
2569 &dp,
2570 &d_rem,
2571 fbuf,
2572 err);
2573 }
2574
2575 if (!ok) {
2576 goto end;
2577 }
2578 } else {
2579 if (decode) {
2580 ok = fbDecodeVarfield(s_base + s_off, &dp, &d_rem,
2581 d_ie->flags, err);
2582 } else {
2583 ok = fbEncodeVarfield(s_base + s_off, &dp, &d_rem,
2584 d_ie->flags, err);
2585 }
2586 }
2587 if (!ok) {
2588 goto end;
2589 }
2590 } else {
2591 /* Fixed to varlen or vice versa */
2592 g_set_error(err, FB_ERROR_DOMAIN, FB_ERROR_IMPL,
2593 "Transcoding between fixed and varlen IE "
2594 "not supported by this version of libfixbuf.");
2595 ok = FALSE;
2596 goto end;
2597
2598 /* if (s_ie->len == FB_IE_VARLEN && d_ie->len != FB_IE_VARLEN) {
2599 if (decode) {
2600 printf("decode varlen to fixed\n");
2601 ok = fbDecodeVarlenToFixed(s_base + s_off, &dp, &d_rem,
2602 d_ie->flags, err);
2603 } else {
2604 ok = fbEncodeVarlenToFixed(s_base + s_off, d_ie->len, &dp,
2605 &d_rem, d_ie->flags, err);
2606 }
2607 } else {
2608 if (decode) {
2609 printf("decode fixed to varlen\n");
2610 ok = fbDecodeFixedToVarlen(s_base + s_off, &dp, &d_rem,
2611 d_ie->flags, err);
2612 } else {
2613 ok = fbEncodeFixedToVarlen(s_base + s_off, s_ie->len, &dp,
2614 &d_rem, d_ie->flags, err);
2615 }
2616 }
2617 if (!ok) {
2618 goto end;
2619 }*/
2620 }
2621 }
2622
2623 /* Return destination length */
2624 *d_len = dp - d_base;
2625
2626 #if FB_DEBUG_TC && FB_DEBUG_RD && FB_DEBUG_WR
2627 fBufDebugHex("tdst", d_base, *d_len);
2628 #elif FB_DEBUG_TC && FB_DEBUG_RD
2629 if (decode) fBufDebugHex("tdst", d_base, *d_len);
2630 #elif FB_DEBUG_TC && FB_DEBUG_WR
2631 if (!decode) fBufDebugHex("tdst", d_base, *d_len);
2632 #endif
2633 /* All done */
2634 end:
2635 fbTranscodeFreeVarlenOffsets(s_tmpl, offsets);
2636 return ok;
2637 }
2638
2639 /*==================================================================
2640 *
2641 * Common Buffer Management Functions
2642 *
2643 *==================================================================*/
2644
2645
2646 /**
2647 * fBufRewind
2648 *
2649 *
2650 *
2651 *
2652 *
2653 */
fBufRewind(fBuf_t * fbuf)2654 void fBufRewind(
2655 fBuf_t *fbuf)
2656 {
2657 if (fbuf->collector || fbuf->exporter) {
2658 /* Reset the buffer */
2659 fbuf->cp = fbuf->buf;
2660 } else {
2661 /* set the buffer to the end of the message */
2662 fbuf->cp = fbuf->mep;
2663 }
2664 fbuf->mep = fbuf->cp;
2665
2666 /* No message or set headers in buffer */
2667 fbuf->msgbase = NULL;
2668 fbuf->setbase = NULL;
2669 fbuf->sep = NULL;
2670
2671 /* No records in buffer either */
2672 fbuf->rc = 0;
2673 }
2674
2675
2676
fBufGetInternalTemplate(fBuf_t * fbuf)2677 uint16_t fBufGetInternalTemplate(
2678 fBuf_t *fbuf)
2679
2680 {
2681 return fbuf->int_tid;
2682 }
2683
2684
2685
2686 /**
2687 * fBufSetInternalTemplate
2688 *
2689 *
2690 *
2691 *
2692 *
2693 */
fBufSetInternalTemplate(fBuf_t * fbuf,uint16_t int_tid,GError ** err)2694 gboolean fBufSetInternalTemplate(
2695 fBuf_t *fbuf,
2696 uint16_t int_tid,
2697 GError **err)
2698 {
2699 /* Look up new internal template if necessary */
2700 if (!fbuf->int_tmpl || fbuf->int_tid != int_tid ||
2701 fbSessionIntTmplTableFlagIsSet(fbuf->session))
2702 {
2703 fbSessionClearIntTmplTableFlag(fbuf->session);
2704 fbuf->int_tid = int_tid;
2705 fbuf->int_tmpl = fbSessionGetTemplate(fbuf->session, TRUE, int_tid,
2706 err);
2707 if (!fbuf->int_tmpl) {
2708 return FALSE;
2709 }
2710 if (fbuf->int_tmpl->default_length) {
2711 /* ERROR: Internal templates may not be created with
2712 * defaulted lengths. This is to ensure forward
2713 * compatibility with respect to default element size
2714 * changes. */
2715 #if FB_ABORT_ON_DEFAULTED_LENGTH
2716 g_error(("ERROR: Attempt to set internal template %#06" PRIx16
2717 ", which has a defaulted length\n"), int_tid);
2718 #endif
2719 g_set_error(err, FB_ERROR_DOMAIN, FB_ERROR_LAXSIZE,
2720 "Attempt to set internal template with"
2721 " defaulted element length");
2722 return FALSE;
2723 }
2724 }
2725
2726 #if FB_DEBUG_TMPL
2727 fbTemplateDebug("int", int_tid, fbuf->int_tmpl);
2728 #endif
2729 return TRUE;
2730 }
2731
2732 /**
2733 * fBufSetAutomaticMode
2734 *
2735 *
2736 *
2737 *
2738 *
2739 */
fBufSetAutomaticMode(fBuf_t * fbuf,gboolean automatic)2740 void fBufSetAutomaticMode(
2741 fBuf_t *fbuf,
2742 gboolean automatic)
2743 {
2744 fbuf->automatic = automatic;
2745 }
2746
2747 /**
2748 * fBufSetAutomaticInsert
2749 *
2750 *
2751 */
fBufSetAutomaticInsert(fBuf_t * fbuf,GError ** err)2752 gboolean fBufSetAutomaticInsert(
2753 fBuf_t *fbuf,
2754 GError **err)
2755 {
2756 /* need the info model */
2757 fbSession_t *session = fBufGetSession(fbuf);
2758 fbTemplate_t *tmpl = NULL;
2759
2760 tmpl = fbInfoElementAllocTypeTemplate(fbSessionGetInfoModel(session), err);
2761 if (!tmpl) {
2762 return FALSE;
2763 }
2764
2765 fbuf->auto_insert_tid = fbSessionAddTemplate(session, TRUE, FB_TID_AUTO,
2766 tmpl, err);
2767 if (fbuf->auto_insert_tid == 0) {
2768 return FALSE;
2769 }
2770
2771 return TRUE;
2772 }
2773
2774
2775 /**
2776 * fBufGetSession
2777 *
2778 *
2779 *
2780 *
2781 *
2782 */
fBufGetSession(fBuf_t * fbuf)2783 fbSession_t *fBufGetSession(
2784 fBuf_t *fbuf)
2785 {
2786 return fbuf->session;
2787 }
2788
2789
2790 /**
2791 * fBufFree
2792 *
2793 *
2794 *
2795 *
2796 *
2797 */
fBufFree(fBuf_t * fbuf)2798 void fBufFree(
2799 fBuf_t *fbuf)
2800 {
2801 fbTCPlanEntry_t *entry;
2802
2803 if (NULL == fbuf) {
2804 return;
2805 }
2806 /* free the tcplans */
2807 while (fbuf->latestTcplan) {
2808 entry = fbuf->latestTcplan;
2809
2810 detachHeadOfDLL((fbDLL_t**)(void*)&(fbuf->latestTcplan), NULL,
2811 (fbDLL_t**)(void*)&entry);
2812 g_free(entry->tcplan->si);
2813
2814 g_slice_free1(sizeof(fbTranscodePlan_t), entry->tcplan);
2815 g_slice_free1(sizeof(fbTCPlanEntry_t), entry);
2816 }
2817 if (fbuf->exporter) {
2818 fbExporterFree(fbuf->exporter);
2819 }
2820 if (fbuf->collector) {
2821 fbCollectorRemoveListenerLastBuf(fbuf, fbuf->collector);
2822 fbCollectorFree(fbuf->collector);
2823 }
2824
2825 fbSessionFree(fbuf->session);
2826 g_slice_free(fBuf_t, fbuf);
2827 }
2828
2829 /*==================================================================
2830 *
2831 * Buffer Append (Writer) Functions
2832 *
2833 *==================================================================*/
2834
2835 #define FB_APPEND_U16(_val_) FB_WRITEINC_U16(fbuf->cp, _val_);
2836
2837 #define FB_APPEND_U32(_val_) FB_WRITEINC_U32(fbuf->cp, _val_);
2838
2839
2840 /**
2841 * fBufAppendMessageHeader
2842 *
2843 *
2844 *
2845 *
2846 *
2847 */
fBufAppendMessageHeader(fBuf_t * fbuf)2848 static void fBufAppendMessageHeader(
2849 fBuf_t *fbuf)
2850 {
2851 /* can only append message header at start of buffer */
2852 g_assert(fbuf->cp == fbuf->buf);
2853
2854 /* can only append message header if we have an exporter */
2855 g_assert(fbuf->exporter);
2856
2857 /* get MTU from exporter */
2858 fbuf->mep += fbExporterGetMTU(fbuf->exporter);
2859 g_assert(FB_REM_MSG(fbuf) > FB_MTU_MIN);
2860
2861 /* set message base pointer to show we have an active message */
2862 fbuf->msgbase = fbuf->cp;
2863
2864 /* add version to buffer */
2865 FB_APPEND_U16(0x000A);
2866
2867 /* add message length to buffer */
2868 FB_APPEND_U16(0);
2869
2870 /* add export time to buffer */
2871 if (fbuf->extime) {
2872 FB_APPEND_U32(fbuf->extime);
2873 } else {
2874 FB_APPEND_U32(time(NULL));
2875 }
2876
2877 /* add sequence number to buffer */
2878 FB_APPEND_U32(fbSessionGetSequence(fbuf->session));
2879
2880 /* add observation domain ID to buffer */
2881 FB_APPEND_U32(fbSessionGetDomain(fbuf->session));
2882
2883 #if FB_DEBUG_WR
2884 fBufDebugBuffer("amsg", fbuf, 16, TRUE);
2885 #endif
2886
2887 }
2888
2889
2890 /**
2891 * fBufAppendSetHeader
2892 *
2893 *
2894 *
2895 *
2896 *
2897 */
fBufAppendSetHeader(fBuf_t * fbuf,GError ** err)2898 static gboolean fBufAppendSetHeader(
2899 fBuf_t *fbuf,
2900 GError **err)
2901 {
2902 uint16_t set_id, set_minlen;
2903
2904 /* Select set ID and minimum set size based on special TID */
2905 if (fbuf->spec_tid) {
2906 set_id = fbuf->spec_tid;
2907 set_minlen = 4;
2908 } else {
2909 set_id = fbuf->ext_tid;
2910 set_minlen = (fbuf->ext_tmpl->ie_len + 4);
2911 }
2912
2913 /* Need enough space in the message for a set header and a record */
2914 if (FB_REM_MSG(fbuf) < set_minlen) {
2915 g_set_error(err, FB_ERROR_DOMAIN, FB_ERROR_EOM,
2916 "End of message. "
2917 "Overrun on set header append "
2918 "(need %u bytes, %u available)",
2919 set_minlen, (uint32_t)FB_REM_MSG(fbuf));
2920 return FALSE;
2921 }
2922
2923 /* set set base pointer to show we have an active set */
2924 fbuf->setbase = fbuf->cp;
2925
2926 /* add set ID to buffer */
2927 FB_APPEND_U16(set_id);
2928 /* add set length to buffer */
2929 FB_APPEND_U16(0);
2930
2931 #if FB_DEBUG_WR
2932 fBufDebugBuffer("aset", fbuf, 4, TRUE);
2933 #endif
2934
2935 return TRUE;
2936 }
2937
2938
2939 /**
2940 * fBufAppendSetClose
2941 *
2942 *
2943 *
2944 *
2945 *
2946 */
fBufAppendSetClose(fBuf_t * fbuf)2947 static void fBufAppendSetClose(
2948 fBuf_t *fbuf)
2949 {
2950 uint16_t setlen;
2951
2952 /* If there's an active set... */
2953 if (fbuf->setbase) {
2954 /* store set length */
2955 setlen = g_htons(fbuf->cp - fbuf->setbase);
2956 memcpy(fbuf->setbase + 2, &setlen, sizeof(setlen));
2957
2958 #if FB_DEBUG_WR
2959 fBufDebugHex("cset", fbuf->setbase, 4);
2960 #endif
2961
2962 /* deactivate set */
2963 fbuf->setbase = NULL;
2964 }
2965 }
2966
2967 #if HAVE_SPREAD
2968 /**
2969 * fBufSetSpreadExportGroup
2970 *
2971 *
2972 */
fBufSetSpreadExportGroup(fBuf_t * fbuf,char ** groups,int num_groups,GError ** err)2973 void fBufSetSpreadExportGroup(
2974 fBuf_t *fbuf,
2975 char **groups,
2976 int num_groups,
2977 GError **err)
2978 {
2979 if (fbExporterCheckGroups(fbuf->exporter, groups, num_groups)) {
2980 /* need to set to 0 bc if the same tmpl_id is used between groups
2981 * it won't get set to the new group before using */
2982 fBufEmit(fbuf, err);
2983 g_clear_error(err);
2984 fbuf->ext_tid = 0;
2985 }
2986 fbSessionSetGroup(fbuf->session, (char *)groups[0]);
2987 fBufSetExportGroups(fbuf, groups, num_groups, NULL);
2988 }
2989
2990 /**
2991 *
2992 * fBufSetExportGroups
2993 *
2994 */
fBufSetExportGroups(fBuf_t * fbuf,char ** groups,int num_groups,GError ** err)2995 void fBufSetExportGroups(
2996 fBuf_t *fbuf,
2997 char **groups,
2998 int num_groups,
2999 GError **err)
3000 {
3001 (void) err;
3002
3003 fbExporterSetGroupsToSend(fbuf->exporter, groups, num_groups);
3004 }
3005
3006 #endif
3007
3008
fBufGetExportTemplate(fBuf_t * fbuf)3009 uint16_t fBufGetExportTemplate(
3010 fBuf_t *fbuf)
3011
3012 {
3013 return fbuf->ext_tid;
3014 }
3015
3016
3017 /**
3018 * fBufSetExportTemplate
3019 *
3020 *
3021 *
3022 *
3023 *
3024 */
fBufSetExportTemplate(fBuf_t * fbuf,uint16_t ext_tid,GError ** err)3025 gboolean fBufSetExportTemplate(
3026 fBuf_t *fbuf,
3027 uint16_t ext_tid,
3028 GError **err)
3029 {
3030 /* Look up new external template if necessary */
3031 if (!fbuf->ext_tmpl || fbuf->ext_tid != ext_tid ||
3032 fbSessionExtTmplTableFlagIsSet(fbuf->session))
3033 {
3034 fbSessionClearExtTmplTableFlag(fbuf->session);
3035
3036 fbuf->ext_tid = ext_tid;
3037 fbuf->ext_tmpl = fbSessionGetTemplate(fbuf->session, FALSE, ext_tid,
3038 err);
3039 if (!fbuf->ext_tmpl) return FALSE;
3040
3041 /* Change of template means new set */
3042 fBufAppendSetClose(fbuf);
3043 }
3044
3045 #if FB_DEBUG_TMPL
3046 fbTemplateDebug("ext", ext_tid, fbuf->ext_tmpl);
3047 #endif
3048
3049 /* If we're here we're done. */
3050 return TRUE;
3051 }
3052
3053 /** Set both the external and internal templates to the one referenced in tid.
3054 * Pull both template pointers from the external list as this template must
3055 * be external and thus on both sides of the connection
3056 */
fBufSetDecodeSubTemplates(fBuf_t * fbuf,uint16_t ext_tid,uint16_t int_tid,GError ** err)3057 static gboolean fBufSetDecodeSubTemplates(
3058 fBuf_t *fbuf,
3059 uint16_t ext_tid,
3060 uint16_t int_tid,
3061 GError **err)
3062 {
3063 fbuf->ext_tmpl = fbSessionGetTemplate(fbuf->session, FALSE, ext_tid, err);
3064 if (!fbuf->ext_tmpl) {
3065 return FALSE;
3066 }
3067 fbuf->ext_tid = ext_tid;
3068 if (ext_tid == int_tid) {
3069 fbuf->int_tid = int_tid;
3070 fbuf->int_tmpl = fbSessionGetTemplate(fbuf->session, TRUE, int_tid,
3071 err);
3072
3073 if (!fbuf->int_tmpl) {
3074 g_clear_error(err);
3075 fbuf->int_tmpl = fbuf->ext_tmpl;
3076 }
3077 } else {
3078 fbuf->int_tmpl = fbSessionGetTemplate(fbuf->session, TRUE, int_tid,
3079 err);
3080 if (!fbuf->int_tmpl) {
3081 return FALSE;
3082 }
3083 fbuf->int_tid = int_tid;
3084 }
3085
3086 return TRUE;
3087 }
3088
fBufSetEncodeSubTemplates(fBuf_t * fbuf,uint16_t ext_tid,uint16_t int_tid,GError ** err)3089 static gboolean fBufSetEncodeSubTemplates(
3090 fBuf_t *fbuf,
3091 uint16_t ext_tid,
3092 uint16_t int_tid,
3093 GError **err)
3094 {
3095 fbuf->ext_tmpl = fbSessionGetTemplate(fbuf->session, FALSE, ext_tid, err);
3096 if (!fbuf->ext_tmpl) {
3097 return FALSE;
3098 }
3099 fbuf->ext_tid = ext_tid;
3100 if (ext_tid == int_tid) {
3101 fbuf->int_tid = int_tid;
3102 fbuf->int_tmpl = fbuf->ext_tmpl;
3103 } else {
3104 fbuf->int_tmpl = fbSessionGetTemplate(fbuf->session, TRUE, int_tid,
3105 err);
3106 if (!fbuf->int_tmpl) {
3107 return FALSE;
3108 }
3109 fbuf->int_tid = int_tid;
3110 }
3111
3112 return TRUE;
3113 }
3114
3115
fBufResetExportTemplate(fBuf_t * fbuf,uint16_t ext_tid,GError ** err)3116 static gboolean fBufResetExportTemplate(
3117 fBuf_t *fbuf,
3118 uint16_t ext_tid,
3119 GError **err)
3120 {
3121 if (!fbuf->ext_tmpl || fbuf->ext_tid != ext_tid) {
3122 fbuf->ext_tid = ext_tid;
3123 fbuf->ext_tmpl = fbSessionGetTemplate(fbuf->session, FALSE, ext_tid,
3124 err);
3125 if (!fbuf->ext_tmpl) {
3126 return FALSE;
3127 }
3128 }
3129
3130 return TRUE;
3131 }
3132
3133 /**
3134 * fBufRemoveTemplateTcplan
3135 *
3136 */
fBufRemoveTemplateTcplan(fBuf_t * fbuf,fbTemplate_t * tmpl)3137 void fBufRemoveTemplateTcplan(
3138 fBuf_t *fbuf,
3139 fbTemplate_t *tmpl)
3140 {
3141 fbTCPlanEntry_t *entry;
3142 fbTCPlanEntry_t *otherEntry;
3143 if (!fbuf || !tmpl) {
3144 return;
3145 }
3146
3147 entry = fbuf->latestTcplan;
3148
3149 while (entry) {
3150 if (entry->tcplan->s_tmpl == tmpl ||
3151 entry->tcplan->d_tmpl == tmpl)
3152 {
3153 if (entry == fbuf->latestTcplan) {
3154 otherEntry = NULL;
3155 } else {
3156 otherEntry = entry->next;
3157 }
3158
3159 detachThisEntryOfDLL((fbDLL_t**)(void*)(&(fbuf->latestTcplan)),
3160 NULL,
3161 (fbDLL_t*)entry);
3162
3163 g_free(entry->tcplan->si);
3164
3165 g_slice_free1(sizeof(fbTranscodePlan_t), entry->tcplan);
3166 g_slice_free1(sizeof(fbTCPlanEntry_t), entry);
3167
3168 if (otherEntry) {
3169 entry = otherEntry;
3170 } else {
3171 entry = fbuf->latestTcplan;
3172 }
3173 } else {
3174 entry = entry->next;
3175 }
3176 }
3177 }
3178
3179 /**
3180 * fBufAppendTemplateSingle
3181 *
3182 *
3183 *
3184 *
3185 *
3186 */
fBufAppendTemplateSingle(fBuf_t * fbuf,uint16_t tmpl_id,fbTemplate_t * tmpl,gboolean revoked,GError ** err)3187 static gboolean fBufAppendTemplateSingle(
3188 fBuf_t *fbuf,
3189 uint16_t tmpl_id,
3190 fbTemplate_t *tmpl,
3191 gboolean revoked,
3192 GError **err)
3193 {
3194 uint16_t spec_tid, tmpl_len, ie_count, scope_count;
3195 int i;
3196
3197 /* Force message closed to start a new template message */
3198 if (!fbuf->spec_tid) {
3199 fbuf->spec_tid = (tmpl->scope_count) ? FB_TID_OTS : FB_TID_TS;
3200 g_set_error(err, FB_ERROR_DOMAIN, FB_ERROR_EOM,
3201 "End of message. "
3202 "Must start new message for template export.");
3203 return FALSE;
3204 }
3205
3206 /* Start a new message if necessary */
3207 if (!fbuf->msgbase) {
3208 fBufAppendMessageHeader(fbuf);
3209 }
3210
3211 /* Check for set ID change */
3212 spec_tid = (tmpl->scope_count) ? FB_TID_OTS : FB_TID_TS;
3213 if (fbuf->spec_tid != spec_tid) {
3214 fbuf->spec_tid = spec_tid;
3215 fBufAppendSetClose(fbuf);
3216 }
3217
3218 /* Start a new set if necessary */
3219 if (!fbuf->setbase) {
3220 if (!fBufAppendSetHeader(fbuf, err)) return FALSE;
3221 }
3222
3223 /*
3224 * Calculate template length and IE count based on whether this
3225 * is a revocation.
3226 */
3227 if (revoked) {
3228 tmpl_len = 4;
3229 ie_count = 0;
3230 scope_count = 0;
3231 } else {
3232 tmpl_len = tmpl->tmpl_len;
3233 ie_count = tmpl->ie_count;
3234 scope_count = tmpl->scope_count;
3235 }
3236
3237 /* Ensure we have enough space for the template in the message */
3238 if (FB_REM_MSG(fbuf) < tmpl_len) {
3239 g_set_error(err, FB_ERROR_DOMAIN, FB_ERROR_EOM,
3240 "End of message. "
3241 "Overrun on template append "
3242 "(need %u bytes, %u available)",
3243 tmpl_len, (uint32_t)FB_REM_MSG(fbuf));
3244 return FALSE;
3245 }
3246
3247 /* Copy the template header to the message */
3248 FB_APPEND_U16(tmpl_id);
3249
3250 FB_APPEND_U16(ie_count);
3251
3252 /* Copy scope IE count if present */
3253 if (scope_count) {
3254 FB_APPEND_U16(scope_count);
3255 }
3256
3257 /* Now copy information element specifiers to the buffer */
3258 for (i = 0; i < ie_count; i++) {
3259 if (tmpl->ie_ary[i]->ent) {
3260 FB_APPEND_U16(IPFIX_ENTERPRISE_BIT | tmpl->ie_ary[i]->num);
3261 FB_APPEND_U16(tmpl->ie_ary[i]->len);
3262 FB_APPEND_U32(tmpl->ie_ary[i]->ent);
3263 } else {
3264 FB_APPEND_U16(tmpl->ie_ary[i]->num);
3265 FB_APPEND_U16(tmpl->ie_ary[i]->len);
3266 }
3267 }
3268
3269 /* Template records are records too. Increment record count. */
3270 /* Actually, no they're not. Odd. */
3271 /* ++(fbuf->rc); */
3272
3273 #if FB_DEBUG_TMPL
3274 fbTemplateDebug("apd", tmpl_id, tmpl);
3275 #endif
3276
3277 #if FB_DEBUG_WR
3278 fBufDebugBuffer("atpl", fbuf, tmpl_len, TRUE);
3279 #endif
3280
3281 /* Done */
3282 return TRUE;
3283 }
3284
3285
3286 /**
3287 * fBufAppendTemplate
3288 *
3289 *
3290 *
3291 *
3292 *
3293 */
fBufAppendTemplate(fBuf_t * fbuf,uint16_t tmpl_id,fbTemplate_t * tmpl,gboolean revoked,GError ** err)3294 gboolean fBufAppendTemplate(
3295 fBuf_t *fbuf,
3296 uint16_t tmpl_id,
3297 fbTemplate_t *tmpl,
3298 gboolean revoked,
3299 GError **err)
3300 {
3301 g_assert(err);
3302
3303 /* printf("fBufAppendTemplate: %x\n", tmpl_id); */
3304 /* Attempt single append */
3305 if (fBufAppendTemplateSingle(fbuf, tmpl_id, tmpl, revoked, err)) {
3306 return TRUE;
3307 }
3308
3309 /* Fail if not EOM or not automatic */
3310 if (!g_error_matches(*err, FB_ERROR_DOMAIN, FB_ERROR_EOM) ||
3311 !fbuf->automatic) return FALSE;
3312
3313 /* Retryable. Clear error. */
3314 g_clear_error(err);
3315
3316 /* Emit message */
3317 if (!fBufEmit(fbuf, err)) return FALSE;
3318
3319 /* Retry single append */
3320 return fBufAppendTemplateSingle(fbuf, tmpl_id, tmpl, revoked, err);
3321 }
3322
3323
3324 /**
3325 * fBufAppendSingle
3326 *
3327 *
3328 *
3329 *
3330 *
3331 */
fBufAppendSingle(fBuf_t * fbuf,uint8_t * recbase,size_t recsize,GError ** err)3332 static gboolean fBufAppendSingle(
3333 fBuf_t *fbuf,
3334 uint8_t *recbase,
3335 size_t recsize,
3336 GError **err)
3337 {
3338 size_t bufsize;
3339
3340 /* Buffer must have active templates */
3341 g_assert(fbuf->int_tmpl);
3342 g_assert(fbuf->ext_tmpl);
3343
3344 /* Force message closed to finish any active template message */
3345 if (fbuf->spec_tid) {
3346 fbuf->spec_tid = 0;
3347 g_set_error(err, FB_ERROR_DOMAIN, FB_ERROR_EOM,
3348 "End of message. "
3349 "Must start new message after template export.");
3350 return FALSE;
3351 }
3352
3353 /* Start a new message if necessary */
3354 if (!fbuf->msgbase) {
3355 fBufAppendMessageHeader(fbuf);
3356 }
3357
3358 /* Cancel special set mode if necessary */
3359 if (fbuf->spec_tid) {
3360 fbuf->spec_tid = 0;
3361 fBufAppendSetClose(fbuf);
3362 }
3363
3364 /* Start a new set if necessary */
3365 if (!fbuf->setbase) {
3366 if (!fBufAppendSetHeader(fbuf, err))
3367 return FALSE;
3368 }
3369
3370 /* Transcode bytes into buffer */
3371 bufsize = FB_REM_MSG(fbuf);
3372
3373 if (!fbTranscode(fbuf, FALSE, recbase, fbuf->cp, &recsize, &bufsize, err))
3374 return FALSE;
3375
3376 /* Move current pointer forward by number of bytes written */
3377 fbuf->cp += bufsize;
3378 /* Increment record count */
3379 ++(fbuf->rc);
3380
3381 #if FB_DEBUG_WR
3382 fBufDebugBuffer("arec", fbuf, bufsize, TRUE);
3383 #endif
3384
3385 /* Done */
3386 return TRUE;
3387 }
3388
3389
3390 /**
3391 * fBufAppend
3392 *
3393 *
3394 *
3395 *
3396 *
3397 */
fBufAppend(fBuf_t * fbuf,uint8_t * recbase,size_t recsize,GError ** err)3398 gboolean fBufAppend(
3399 fBuf_t *fbuf,
3400 uint8_t *recbase,
3401 size_t recsize,
3402 GError **err)
3403 {
3404 g_assert(recbase);
3405 g_assert(err);
3406
3407 /* Attempt single append */
3408 if (fBufAppendSingle(fbuf, recbase, recsize, err)) return TRUE;
3409
3410 /* Fail if not EOM or not automatic */
3411 if (!g_error_matches(*err, FB_ERROR_DOMAIN, FB_ERROR_EOM) ||
3412 !fbuf->automatic) return FALSE;
3413
3414 /* Retryable. Clear error. */
3415 g_clear_error(err);
3416
3417 /* Emit message */
3418 if (!fBufEmit(fbuf, err)) return FALSE;
3419
3420 /* Retry single append */
3421 return fBufAppendSingle(fbuf, recbase, recsize, err);
3422 }
3423
3424
3425 /**
3426 * fBufEmit
3427 *
3428 *
3429 *
3430 *
3431 *
3432 */
fBufEmit(fBuf_t * fbuf,GError ** err)3433 gboolean fBufEmit(
3434 fBuf_t *fbuf,
3435 GError **err)
3436 {
3437 uint16_t msglen;
3438
3439 /* Short-circuit on no message available */
3440 if (!fbuf->msgbase) return TRUE;
3441
3442 /* Close current set */
3443 fBufAppendSetClose(fbuf);
3444
3445 /* Store message length */
3446 msglen = g_htons(fbuf->cp - fbuf->msgbase);
3447 memcpy(fbuf->msgbase + 2, &msglen, sizeof(msglen));
3448
3449 /* for (i = 0; i < g_ntohs(msglen); i++) {
3450 printf("%02x", fbuf->buf[i]);
3451 if ((i + 1) % 8 == 0) {
3452 printf("\n");
3453 }
3454 }
3455 printf("\n\n\n\n\n");*/
3456
3457 #if FB_DEBUG_WR
3458 fBufDebugHex("emit", fbuf->buf, fbuf->cp - fbuf->msgbase);
3459 #endif
3460 #if FB_DEBUG_LWR
3461 fprintf(stderr, "emit %u (%04x)\n",
3462 fbuf->cp - fbuf->msgbase, fbuf->cp - fbuf->msgbase);
3463 #endif
3464
3465 /* Hand the message content to the exporter */
3466 if (!fbExportMessage(fbuf->exporter, fbuf->buf,
3467 fbuf->cp - fbuf->msgbase, err))
3468 return FALSE;
3469
3470 /* Increment next record sequence number */
3471 fbSessionSetSequence(fbuf->session, fbSessionGetSequence(fbuf->session) +
3472 fbuf->rc);
3473
3474 /* Rewind message */
3475 fBufRewind(fbuf);
3476
3477 /* All done */
3478 return TRUE;
3479 }
3480
3481
3482 /**
3483 * fBufGetExporter
3484 *
3485 *
3486 *
3487 *
3488 *
3489 */
fBufGetExporter(fBuf_t * fbuf)3490 fbExporter_t *fBufGetExporter(
3491 fBuf_t *fbuf)
3492 {
3493 if (fbuf) {
3494 return fbuf->exporter;
3495 }
3496
3497 return NULL;
3498 }
3499
3500
3501 /**
3502 * fBufSetExporter
3503 *
3504 *
3505 *
3506 *
3507 *
3508 */
fBufSetExporter(fBuf_t * fbuf,fbExporter_t * exporter)3509 void fBufSetExporter(
3510 fBuf_t *fbuf,
3511 fbExporter_t *exporter)
3512 {
3513 g_assert(exporter);
3514
3515 if (fbuf->collector) {
3516 fbCollectorFree(fbuf->collector);
3517 fbuf->collector = NULL;
3518 }
3519
3520 if (fbuf->exporter) {
3521 fbExporterFree(fbuf->exporter);
3522 }
3523
3524 fbuf->exporter = exporter;
3525 fbSessionSetTemplateBuffer(fbuf->session, fbuf);
3526 fBufRewind(fbuf);
3527 }
3528
3529
3530 /**
3531 * fBufAllocForExport
3532 *
3533 *
3534 *
3535 *
3536 *
3537 */
fBufAllocForExport(fbSession_t * session,fbExporter_t * exporter)3538 fBuf_t *fBufAllocForExport(
3539 fbSession_t *session,
3540 fbExporter_t *exporter)
3541 {
3542 fBuf_t *fbuf = NULL;
3543
3544 g_assert(session);
3545
3546 /* Allocate a new buffer */
3547 fbuf = g_slice_new0(fBuf_t);
3548
3549 /* Store reference to session */
3550 fbuf->session = session;
3551
3552 /* Set up exporter */
3553 fBufSetExporter(fbuf, exporter);
3554
3555 /* Buffers are automatic by default */
3556 fbuf->automatic = TRUE;
3557
3558 return fbuf;
3559 }
3560
3561 /**
3562 * fBufSetExportTime
3563 *
3564 *
3565 *
3566 *
3567 *
3568 */
fBufSetExportTime(fBuf_t * fbuf,uint32_t extime)3569 void fBufSetExportTime(
3570 fBuf_t *fbuf,
3571 uint32_t extime)
3572 {
3573 fbuf->extime = extime;
3574 }
3575
3576 /*==================================================================
3577 *
3578 * Buffer Consume (Reader) Functions
3579 *
3580 *==================================================================*/
3581
3582 #define FB_CHECK_AVAIL(_op_, _size_) \
3583 if (_size_ > FB_REM_MSG(fbuf)) { \
3584 g_set_error(err, FB_ERROR_DOMAIN, FB_ERROR_EOM, \
3585 "End of message %s " \
3586 "(need %u bytes, %u available)", \
3587 (_op_), (_size_), (uint32_t)FB_REM_MSG(fbuf)); \
3588 return FALSE; \
3589 }
3590
3591
3592 #define FB_NEXT_U16(_val_) FB_READINC_U16(_val_, fbuf->cp)
3593
3594 #define FB_NEXT_U32(_val_) FB_READINC_U32(_val_, fbuf->cp)
3595
3596
3597 /**
3598 * fBufNextMessage
3599 *
3600 *
3601 *
3602 *
3603 *
3604 */
fBufNextMessage(fBuf_t * fbuf,GError ** err)3605 gboolean fBufNextMessage(
3606 fBuf_t *fbuf,
3607 GError **err)
3608 {
3609 size_t msglen;
3610 uint16_t mh_version, mh_len;
3611 uint32_t ex_sequence, mh_sequence, mh_domain;
3612
3613 /* Need a collector */
3614 /*g_assert(fbuf->collector);*/
3615 /* Clear external template */
3616 fbuf->ext_tid = 0;
3617 fbuf->ext_tmpl = NULL;
3618
3619 /* Rewind the buffer before reading a new message */
3620 fBufRewind(fbuf);
3621
3622 /* Read next message from the collector */
3623 if (fbuf->collector) {
3624 msglen = sizeof(fbuf->buf);
3625 if (!fbCollectMessage(fbuf->collector, fbuf->buf, &msglen, err)) {
3626 return FALSE;
3627 }
3628 } else {
3629 if (fbuf->buflen) {
3630 if (!fbCollectMessageBuffer(fbuf->cp, fbuf->buflen, &msglen, err))
3631 {
3632 return FALSE;
3633 }
3634 } else {
3635 g_set_error(err, FB_ERROR_DOMAIN, FB_ERROR_BUFSZ,
3636 "Buffer length = 0");
3637 return FALSE;
3638 }
3639 /* subtract the next message from the total buffer length */
3640 fbuf->buflen -= msglen;
3641 }
3642
3643 /* Set the message end pointer */
3644 fbuf->mep = fbuf->cp + msglen;
3645
3646 #if FB_DEBUG_RD
3647 fBufDebugHex("read", fbuf->buf, msglen);
3648 #endif
3649 #if FB_DEBUG_LWR
3650 fprintf(stderr, "read %lu (%04lx)\n", msglen, msglen);
3651 #endif
3652
3653 /* Make sure we have at least a message header */
3654 FB_CHECK_AVAIL("reading message header", 16);
3655
3656 #if FB_DEBUG_RD
3657 fBufDebugBuffer("rmsg", fbuf, 16, FALSE);
3658 #endif
3659 /* Read and verify version */
3660 FB_NEXT_U16(mh_version);
3661 if (mh_version != 0x000A) {
3662 g_set_error(err, FB_ERROR_DOMAIN, FB_ERROR_IPFIX,
3663 "Illegal IPFIX Message version 0x%04x; "
3664 "input is probably not an IPFIX Message stream.",
3665 mh_version);
3666 return FALSE;
3667 }
3668
3669 /* Read and verify message length */
3670 FB_NEXT_U16(mh_len);
3671
3672 if (mh_len != msglen) {
3673 if (NULL != fbuf->collector) {
3674 if (!fbCollectorHasTranslator(fbuf->collector)){
3675 g_set_error(err, FB_ERROR_DOMAIN, FB_ERROR_IPFIX,
3676 "IPFIX Message length mismatch "
3677 "(buffer has %u, read %u)",
3678 (uint32_t)msglen, mh_len);
3679 return FALSE;
3680
3681 }
3682 } else {
3683 g_set_error(err, FB_ERROR_DOMAIN, FB_ERROR_IPFIX,
3684 "IPFIX Message length mismatch "
3685 "(buffer has %u, read %u)",
3686 (uint32_t)msglen, mh_len);
3687 return FALSE;
3688 }
3689 }
3690
3691 /* Read and store export time */
3692 FB_NEXT_U32(fbuf->extime);
3693
3694 /* Read sequence number */
3695 FB_NEXT_U32(mh_sequence);
3696
3697 /* Read observation domain ID and reset domain if necessary */
3698 FB_NEXT_U32(mh_domain);
3699 fbSessionSetDomain(fbuf->session, mh_domain);
3700
3701 #if HAVE_SPREAD
3702 /* Only worry about sequence numbers for first group in list
3703 * of received groups & only if we subscribe to that group*/
3704 if (fbCollectorTestGroupMembership(fbuf->collector, 0)) {
3705 #endif
3706 /* Verify and update sequence number */
3707 ex_sequence = fbSessionGetSequence(fbuf->session);
3708
3709 if (ex_sequence != mh_sequence) {
3710 if (ex_sequence) {
3711 g_warning("IPFIX Message out of sequence "
3712 "(in domain %08x, expected %08x, got %08x)",
3713 fbSessionGetDomain(fbuf->session), ex_sequence,
3714 mh_sequence);
3715 }
3716 fbSessionSetSequence(fbuf->session, mh_sequence);
3717 }
3718
3719 #if HAVE_SPREAD
3720 }
3721 #endif
3722
3723 /*
3724 * We successfully read a message header.
3725 * Set message base pointer to start of message.
3726 */
3727 fbuf->msgbase = fbuf->cp - 16;
3728
3729 return TRUE;
3730 }
3731
3732
3733 /**
3734 * fBufSkipCurrentSet
3735 *
3736 *
3737 *
3738 *
3739 *
3740 */
fBufSkipCurrentSet(fBuf_t * fbuf)3741 static void fBufSkipCurrentSet(
3742 fBuf_t *fbuf)
3743 {
3744 if (fbuf->setbase) {
3745 fbuf->cp += FB_REM_SET(fbuf);
3746 fbuf->setbase = NULL;
3747 fbuf->sep = NULL;
3748 }
3749 }
3750
3751
3752 /**
3753 * fBufNextSetHeader
3754 *
3755 *
3756 *
3757 *
3758 *
3759 */
fBufNextSetHeader(fBuf_t * fbuf,GError ** err)3760 static gboolean fBufNextSetHeader(
3761 fBuf_t *fbuf,
3762 GError **err)
3763 {
3764 uint16_t set_id, setlen;
3765
3766 g_assert(err);
3767
3768 /* May loop over sets if we're missing templates */
3769 while (1) {
3770 /* Make sure we have at least a set header */
3771 FB_CHECK_AVAIL("reading set header", 4);
3772
3773 #if FB_DEBUG_RD
3774 fBufDebugBuffer("rset", fbuf, 4, FALSE);
3775 #endif
3776 /* Read set ID */
3777 FB_NEXT_U16(set_id);
3778 /* Read set length */
3779 FB_NEXT_U16(setlen);
3780 /* Verify set length is legal */
3781 if (setlen < 4) {
3782 g_set_error(err, FB_ERROR_DOMAIN, FB_ERROR_IPFIX,
3783 "Illegal IPFIX Set length %hu",
3784 setlen);
3785 return FALSE;
3786 }
3787
3788 /* Verify set body fits in the message */
3789 FB_CHECK_AVAIL("checking set length", setlen - 4);
3790 /* Set up special set ID or external templates */
3791 if (set_id < FB_TID_MIN_DATA) {
3792 if ((set_id != FB_TID_TS) &&
3793 (set_id != FB_TID_OTS)) {
3794 g_set_error(err, FB_ERROR_DOMAIN, FB_ERROR_IPFIX,
3795 "Illegal IPFIX Set ID %04hx", set_id);
3796 return FALSE;
3797 }
3798 fbuf->spec_tid = set_id;
3799 } else if (!fbuf->ext_tmpl || fbuf->ext_tid != set_id) {
3800 fbuf->spec_tid = 0;
3801 fbuf->ext_tid = set_id;
3802 fbuf->ext_tmpl = fbSessionGetTemplate(fbuf->session, FALSE,
3803 set_id, err);
3804 if (!fbuf->ext_tmpl) {
3805 if (g_error_matches(*err, FB_ERROR_DOMAIN, FB_ERROR_TMPL)) {
3806 /* Merely warn and skip on missing templates */
3807 g_warning("Skipping set: %s", (*err)->message);
3808 g_clear_error(err);
3809 fbuf->setbase = fbuf->cp - 4;
3810 fbuf->sep = fbuf->setbase + setlen;
3811 fBufSkipCurrentSet(fbuf);
3812 continue;
3813 }
3814 }
3815 }
3816
3817 /*
3818 * We successfully read a set header.
3819 * Set set base and end pointers.
3820 */
3821 fbuf->setbase = fbuf->cp - 4;
3822 fbuf->sep = fbuf->setbase + setlen;
3823
3824 return TRUE;
3825 }
3826 }
3827
3828
3829 /**
3830 * fBufConsumeTemplateSet
3831 *
3832 *
3833 *
3834 *
3835 *
3836 */
fBufConsumeTemplateSet(fBuf_t * fbuf,GError ** err)3837 static gboolean fBufConsumeTemplateSet(
3838 fBuf_t *fbuf,
3839 GError **err)
3840 {
3841 uint16_t mtl, tid, ie_count, scope_count;
3842 fbTemplate_t *tmpl;
3843 fbInfoElement_t ex_ie = FB_IE_NULL;
3844 int i;
3845
3846 /* Calculate minimum template record length based on type */
3847 /* FIXME handle revocation sets */
3848 mtl = (fbuf->spec_tid == FB_TID_OTS) ? 6 : 4;
3849
3850 /* Keep reading until the set contains only padding. */
3851 while (FB_REM_SET(fbuf) >= mtl) {
3852 /* Read template ID */
3853 FB_NEXT_U16(tid);
3854 /* Read template IE count */
3855 FB_NEXT_U16(ie_count);
3856 /* Read scope count if present */
3857 if (fbuf->spec_tid == FB_TID_OTS) {
3858 FB_NEXT_U16(scope_count);
3859 /* Check for illegal scope count */
3860 if (scope_count == 0) {
3861 g_set_error(err, FB_ERROR_DOMAIN, FB_ERROR_IPFIX,
3862 "Illegal IPFIX Options Template Scope Count 0");
3863 return FALSE;
3864 } else if (scope_count > ie_count) {
3865 g_set_error(err, FB_ERROR_DOMAIN, FB_ERROR_IPFIX,
3866 "Illegal IPFIX Options Template Scope Count "
3867 "(scope count %hu, element count %hu)",
3868 scope_count, ie_count);
3869 return FALSE;
3870 }
3871 } else {
3872 scope_count = 0;
3873 }
3874
3875 /* Allocate a new template */
3876 tmpl = fbTemplateAlloc(fbSessionGetInfoModel(fbuf->session));
3877
3878 /* Add information elements to the template */
3879 for (i = 0; i < ie_count; i++) {
3880 /* Read information element specifier from buffer */
3881 FB_NEXT_U16(ex_ie.num);
3882 FB_NEXT_U16(ex_ie.len);
3883 if (ex_ie.num & IPFIX_ENTERPRISE_BIT) {
3884 ex_ie.num &= ~IPFIX_ENTERPRISE_BIT;
3885 FB_NEXT_U32(ex_ie.ent);
3886 } else {
3887 ex_ie.ent = 0;
3888 }
3889
3890 /* Add information element to template */
3891 if (!fbTemplateAppend(tmpl, &ex_ie, err)) return FALSE;
3892 }
3893
3894 /* Set scope count in template */
3895 if (scope_count) {
3896 fbTemplateSetOptionsScope(tmpl, scope_count);
3897 }
3898
3899 /* Add template to session */
3900 if (!fbSessionAddTemplate(fbuf->session, FALSE, tid, tmpl, err)) {
3901 return FALSE;
3902 }
3903
3904 if (fbSessionNewTemplateCallback(fbuf->session)) {
3905 g_assert(tmpl->app_ctx == NULL);
3906 (fbSessionNewTemplateCallback(fbuf->session))(
3907 fbuf->session, tid, tmpl,
3908 fbSessionNewTemplateCallbackAppCtx(fbuf->session),
3909 &(tmpl->tmpl_ctx), &(tmpl->ctx_free));
3910 if (NULL == tmpl->app_ctx) {
3911 tmpl->app_ctx =
3912 fbSessionNewTemplateCallbackAppCtx(fbuf->session);
3913 }
3914 }
3915
3916 /* if the template set on the fbuf has the same tid, reset tmpl */
3917 /* so we don't reference the old one if a data set follows */
3918 if (fbuf->ext_tid == tid) {
3919 fbuf->ext_tmpl = NULL;
3920 fbuf->ext_tid = 0;
3921 }
3922
3923 #if FB_DEBUG_RD
3924 fBufDebugBuffer("rtpl", fbuf, tmpl->tmpl_len, TRUE);
3925 #endif
3926 }
3927
3928 /* Skip any padding at the end of the set */
3929 fBufSkipCurrentSet(fbuf);
3930
3931 /* Should set spec_tid to 0 so if next set is data */
3932 fbuf->spec_tid = 0;
3933
3934 /* All done */
3935 return TRUE;
3936 }
3937
3938
fBufConsumeInfoElementTypeRecord(fBuf_t * fbuf,GError ** err)3939 static gboolean fBufConsumeInfoElementTypeRecord(
3940 fBuf_t *fbuf,
3941 GError **err)
3942 {
3943 fbInfoElementOptRec_t rec;
3944 size_t len = sizeof(fbInfoElementOptRec_t);
3945 uint16_t tid = fbuf->int_tid;
3946 size_t bufsize;
3947
3948 if (!fBufSetInternalTemplate(fbuf, fbuf->auto_insert_tid, err)) {
3949 return FALSE;
3950 }
3951
3952 /* Keep reading until the set contains only padding. */
3953 while (FB_REM_SET(fbuf) >= fbuf->int_tmpl->tmpl_len) {
3954
3955 /* Transcode bytes out of buffer */
3956 bufsize = FB_REM_SET(fbuf);
3957
3958 if (!fbTranscode(fbuf, TRUE, fbuf->cp, (uint8_t *)&rec, &bufsize, &len,
3959 err))
3960 {
3961 return FALSE;
3962 }
3963
3964 if (!fbInfoElementAddOptRecElement(fbuf->int_tmpl->model, &rec)) {
3965 return FALSE;
3966 }
3967
3968 /* Advance current record pointer by bytes read */
3969 fbuf->cp += bufsize;
3970
3971 /* Increment record count */
3972 ++(fbuf->rc);
3973 }
3974
3975 if (tid) {
3976 if (!fBufSetInternalTemplate(fbuf, tid, err)) {
3977 return FALSE;
3978 }
3979 } else {
3980 fbuf->int_tid = tid;
3981 fbuf->int_tmpl = NULL;
3982 }
3983
3984
3985 return TRUE;
3986 }
3987
3988
3989
3990
3991 /**
3992 * fBufNextDataSet
3993 *
3994 *
3995 *
3996 *
3997 *
3998 */
fBufNextDataSet(fBuf_t * fbuf,GError ** err)3999 static gboolean fBufNextDataSet(
4000 fBuf_t *fbuf,
4001 GError **err)
4002 {
4003 /* May have to consume multiple template sets */
4004 while (1) {
4005 /* Read the next set header */
4006 if (!fBufNextSetHeader(fbuf, err)) {
4007 return FALSE;
4008 }
4009
4010 /* Check to see if we need to consume a template set */
4011 if (fbuf->spec_tid) {
4012 if (!fBufConsumeTemplateSet(fbuf, err)) {
4013 return FALSE;
4014 }
4015 continue;
4016 }
4017
4018 if (fbuf->auto_insert_tid) {
4019 if (fbTemplateGetOptionsScope(fbuf->ext_tmpl)) {
4020 if (fbInfoModelTypeInfoRecord(fbuf->ext_tmpl)) {
4021 if (!fBufConsumeInfoElementTypeRecord(fbuf, err)) {
4022 return FALSE;
4023 }
4024 continue;
4025 }
4026 }
4027 }
4028 /* All done. */
4029 return TRUE;
4030 }
4031 }
4032
4033
4034 /**
4035 * fBufGetCollectionTemplate
4036 *
4037 *
4038 *
4039 *
4040 *
4041 */
fBufGetCollectionTemplate(fBuf_t * fbuf,uint16_t * ext_tid)4042 fbTemplate_t *fBufGetCollectionTemplate(
4043 fBuf_t *fbuf,
4044 uint16_t *ext_tid)
4045 {
4046 if (fbuf->ext_tmpl) {
4047 if (ext_tid) *ext_tid = fbuf->ext_tid;
4048 }
4049 return fbuf->ext_tmpl;
4050 }
4051
4052
4053 /**
4054 * fBufNextCollectionTemplateSingle
4055 *
4056 *
4057 *
4058 *
4059 *
4060 */
fBufNextCollectionTemplateSingle(fBuf_t * fbuf,uint16_t * ext_tid,GError ** err)4061 static fbTemplate_t *fBufNextCollectionTemplateSingle(
4062 fBuf_t *fbuf,
4063 uint16_t *ext_tid,
4064 GError **err)
4065 {
4066 /* Read a new message if necessary */
4067 if (!fbuf->msgbase) {
4068 if (!fBufNextMessage(fbuf, err)) {
4069 return FALSE;
4070 }
4071 }
4072
4073 /* Skip any padding at end of current data set */
4074 if (fbuf->setbase &&
4075 (FB_REM_SET(fbuf) < fbuf->ext_tmpl->ie_len)) {
4076 fBufSkipCurrentSet(fbuf);
4077 }
4078
4079 /* Advance to the next data set if necessary */
4080 if (!fbuf->setbase) {
4081 if (!fBufNextDataSet(fbuf, err)) {
4082 return FALSE;
4083 }
4084 }
4085
4086 return fBufGetCollectionTemplate(fbuf, ext_tid);
4087 }
4088
4089
4090 /**
4091 * fBufNextCollectionTemplate
4092 *
4093 *
4094 *
4095 *
4096 *
4097 */
fBufNextCollectionTemplate(fBuf_t * fbuf,uint16_t * ext_tid,GError ** err)4098 fbTemplate_t *fBufNextCollectionTemplate(
4099 fBuf_t *fbuf,
4100 uint16_t *ext_tid,
4101 GError **err)
4102 {
4103 fbTemplate_t *tmpl;
4104
4105 g_assert(err);
4106
4107 while (1) {
4108 /* Attempt single record read */
4109 if ((tmpl = fBufNextCollectionTemplateSingle(fbuf, ext_tid, err)))
4110 return tmpl;
4111
4112 /* Finish the message at EOM */
4113 if (g_error_matches(*err, FB_ERROR_DOMAIN, FB_ERROR_EOM)) {
4114 /* Store next expected sequence number */
4115 #if HAVE_SPREAD
4116 /* Only worry about sequence numbers for first group in list
4117 * of received groups & only if we subscribe to that group*/
4118 if (fbCollectorTestGroupMembership(fbuf->collector, 0)) {
4119 #endif
4120
4121 fbSessionSetSequence(fbuf->session,
4122 fbSessionGetSequence(fbuf->session) +
4123 fbuf->rc);
4124 #if HAVE_SPREAD
4125 }
4126 #endif
4127 /* Rewind buffer to force next record read
4128 to consume a new message. */
4129 fBufRewind(fbuf);
4130
4131 /* Clear error and try again in automatic mode */
4132 if (fbuf->automatic) {
4133 g_clear_error(err);
4134 continue;
4135 }
4136 }
4137
4138 /* Error. Not EOM or not retryable. Fail. */
4139 return NULL;
4140 }
4141 }
4142
4143
4144 /**
4145 * fBufNextSingle
4146 *
4147 *
4148 *
4149 *
4150 *
4151 */
fBufNextSingle(fBuf_t * fbuf,uint8_t * recbase,size_t * recsize,GError ** err)4152 static gboolean fBufNextSingle(
4153 fBuf_t *fbuf,
4154 uint8_t *recbase,
4155 size_t *recsize,
4156 GError **err)
4157 {
4158 size_t bufsize;
4159
4160 /* Buffer must have active internal template */
4161 g_assert(fbuf->int_tmpl);
4162
4163 /* Read a new message if necessary */
4164 if (!fbuf->msgbase) {
4165 if (!fBufNextMessage(fbuf, err)) {
4166 return FALSE;
4167 }
4168 }
4169
4170 /* Skip any padding at end of current data set */
4171 if (fbuf->setbase &&
4172 (FB_REM_SET(fbuf) < fbuf->ext_tmpl->ie_len)) {
4173 fBufSkipCurrentSet(fbuf);
4174 }
4175
4176 /* Advance to the next data set if necessary */
4177 if (!fbuf->setbase) {
4178 if (!fBufNextDataSet(fbuf, err)) {
4179 return FALSE;
4180 }
4181 }
4182
4183 /* Transcode bytes out of buffer */
4184 bufsize = FB_REM_SET(fbuf);
4185
4186 if (!fbTranscode(fbuf, TRUE, fbuf->cp, recbase, &bufsize, recsize, err)) {
4187 return FALSE;
4188 }
4189
4190 /* Advance current record pointer by bytes read */
4191 fbuf->cp += bufsize;
4192 /* Increment record count */
4193 ++(fbuf->rc);
4194 #if FB_DEBUG_RD
4195 fBufDebugBuffer("rrec", fbuf, bufsize, TRUE);
4196 #endif
4197 /* Done */
4198 return TRUE;
4199 }
4200
4201
4202 /**
4203 * fBufNext
4204 *
4205 *
4206 *
4207 *
4208 *
4209 */
fBufNext(fBuf_t * fbuf,uint8_t * recbase,size_t * recsize,GError ** err)4210 gboolean fBufNext(
4211 fBuf_t *fbuf,
4212 uint8_t *recbase,
4213 size_t *recsize,
4214 GError **err)
4215 {
4216 g_assert(recbase);
4217 g_assert(recsize);
4218 g_assert(err);
4219
4220 for (;;) {
4221 /* Attempt single record read */
4222 if (fBufNextSingle(fbuf, recbase, recsize, err)) return TRUE;
4223 /* Finish the message at EOM */
4224 if (g_error_matches(*err, FB_ERROR_DOMAIN, FB_ERROR_EOM)) {
4225 #if HAVE_SPREAD
4226 /* Only worry about sequence numbers for first group in list
4227 * of received groups & only if we subscribe to that group*/
4228 if (fbCollectorTestGroupMembership(fbuf->collector, 0)) {
4229 #endif
4230 /* Store next expected sequence number */
4231 fbSessionSetSequence(fbuf->session,
4232 fbSessionGetSequence(fbuf->session) +
4233 fbuf->rc);
4234 #if HAVE_SPREAD
4235 }
4236 #endif
4237 /* Rewind buffer to force next record read
4238 to consume a new message. */
4239 fBufRewind(fbuf);
4240 /* Clear error and try again in automatic mode */
4241 if (fbuf->automatic) {
4242 g_clear_error(err);
4243 continue;
4244 }
4245 }
4246
4247 /* Error. Not EOM or not retryable. Fail. */
4248 return FALSE;
4249 }
4250 }
4251
4252
4253 /*
4254 *
4255 * fBufRemaining
4256 *
4257 */
fBufRemaining(fBuf_t * fbuf)4258 size_t fBufRemaining(
4259 fBuf_t *fbuf)
4260 {
4261 return fbuf->buflen;
4262 }
4263
4264
4265
4266
4267 /**
4268 * fBufSetBuffer
4269 *
4270 *
4271 */
fBufSetBuffer(fBuf_t * fbuf,uint8_t * buf,size_t buflen)4272 void fBufSetBuffer(
4273 fBuf_t *fbuf,
4274 uint8_t *buf,
4275 size_t buflen)
4276 {
4277 /* not sure if this is necessary, but if these are not null, the
4278 appropriate code will not execute*/
4279 fbuf->collector = NULL;
4280 fbuf->exporter = NULL;
4281
4282 fbuf->cp = buf;
4283 fbuf->mep = fbuf->cp;
4284 fbuf->buflen = buflen;
4285 }
4286
4287
4288 /**
4289 * fBufGetCollector
4290 *
4291 *
4292 *
4293 *
4294 *
4295 */
fBufGetCollector(fBuf_t * fbuf)4296 fbCollector_t *fBufGetCollector(
4297 fBuf_t *fbuf)
4298 {
4299 return fbuf->collector;
4300 }
4301
4302
4303 /**
4304 * fBufSetCollector
4305 *
4306 *
4307 *
4308 *
4309 *
4310 */
fBufSetCollector(fBuf_t * fbuf,fbCollector_t * collector)4311 void fBufSetCollector(
4312 fBuf_t *fbuf,
4313 fbCollector_t *collector)
4314 {
4315 if (fbuf->exporter) {
4316 fbSessionSetTemplateBuffer(fbuf->session, NULL);
4317 fbExporterFree(fbuf->exporter);
4318 fbuf->exporter = NULL;
4319 }
4320
4321 if (fbuf->collector) {
4322 fbCollectorFree(fbuf->collector);
4323 }
4324
4325 fbuf->collector = collector;
4326
4327 fbSessionSetTemplateBuffer(fbuf->session, fbuf);
4328
4329 fBufRewind(fbuf);
4330 }
4331
4332 /**
4333 * fBufAllocForCollection
4334 *
4335 *
4336 *
4337 *
4338 *
4339 */
fBufAllocForCollection(fbSession_t * session,fbCollector_t * collector)4340 fBuf_t *fBufAllocForCollection(
4341 fbSession_t *session,
4342 fbCollector_t *collector)
4343 {
4344 fBuf_t *fbuf = NULL;
4345
4346 g_assert(session);
4347
4348 /* Allocate a new buffer */
4349 fbuf = g_slice_new0(fBuf_t);
4350
4351 /* Store reference to session */
4352 fbuf->session = session;
4353
4354 fbSessionSetCollector(session, collector);
4355
4356 /* Set up collection */
4357 fBufSetCollector(fbuf, collector);
4358
4359 /* Buffers are automatic by default */
4360
4361 fbuf->automatic = TRUE;
4362
4363 return fbuf;
4364 }
4365
4366 /**
4367 * fBufSetSession
4368 *
4369 */
fBufSetSession(fBuf_t * fbuf,fbSession_t * session)4370 void fBufSetSession(
4371 fBuf_t *fbuf,
4372 fbSession_t *session)
4373 {
4374 fbuf->session = session;
4375 }
4376
4377 /**
4378 * fBufGetExportTime
4379 *
4380 */
fBufGetExportTime(fBuf_t * fbuf)4381 uint32_t fBufGetExportTime(
4382 fBuf_t *fbuf)
4383 {
4384 return fbuf->extime;
4385 }
4386
fBufInterruptSocket(fBuf_t * fbuf)4387 void fBufInterruptSocket(
4388 fBuf_t *fbuf)
4389 {
4390 fbCollectorInterruptSocket(fbuf->collector);
4391 }
4392
fbListValidSemantic(uint8_t semantic)4393 gboolean fbListValidSemantic(
4394 uint8_t semantic)
4395 {
4396 if (semantic <= 0x04 || semantic == 0xFF) {
4397 return TRUE;
4398 }
4399 return FALSE;
4400 }
4401
fbBasicListAlloc(void)4402 fbBasicList_t* fbBasicListAlloc(
4403 void)
4404 {
4405 fbBasicList_t *bl;
4406
4407 bl = g_slice_new0(fbBasicList_t);
4408 return bl;
4409 }
4410
fbBasicListInit(fbBasicList_t * basicList,uint8_t semantic,const fbInfoElement_t * infoElement,uint16_t numElements)4411 void* fbBasicListInit(
4412 fbBasicList_t *basicList,
4413 uint8_t semantic,
4414 const fbInfoElement_t *infoElement,
4415 uint16_t numElements)
4416 {
4417 basicList->semantic = semantic;
4418 basicList->infoElement = infoElement;
4419
4420 g_assert(infoElement);
4421 if (!infoElement) {
4422 return NULL;
4423 }
4424
4425 basicList->numElements = numElements;
4426 basicList->dataLength = numElements * fbSizeofIE(infoElement);
4427 basicList->dataPtr = g_slice_alloc0(basicList->dataLength);
4428 return (void*)basicList->dataPtr;
4429 }
4430
fbBasicListInitWithOwnBuffer(fbBasicList_t * basicList,uint8_t semantic,const fbInfoElement_t * infoElement,uint16_t numElements,uint16_t dataLength,uint8_t * dataPtr)4431 void *fbBasicListInitWithOwnBuffer(
4432 fbBasicList_t *basicList,
4433 uint8_t semantic,
4434 const fbInfoElement_t *infoElement,
4435 uint16_t numElements,
4436 uint16_t dataLength,
4437 uint8_t *dataPtr)
4438 {
4439 g_assert(infoElement);
4440 basicList->semantic = semantic;
4441 basicList->infoElement = infoElement;
4442 basicList->numElements = numElements;
4443 basicList->dataLength = dataLength;
4444 basicList->dataPtr = dataPtr;
4445
4446 return basicList->dataPtr;
4447 }
4448
fbBasicListCollectorInit(fbBasicList_t * basicList)4449 void fbBasicListCollectorInit(
4450 fbBasicList_t *basicList)
4451 {
4452 basicList->semantic = 0;
4453 basicList->infoElement = NULL;
4454 basicList->dataPtr = NULL;
4455 basicList->numElements = 0;
4456 basicList->dataLength = 0;
4457 }
4458
fbBasicListCountElements(const fbBasicList_t * basicList)4459 uint16_t fbBasicListCountElements(
4460 const fbBasicList_t *basicList)
4461 {
4462 return basicList->numElements;
4463 }
4464
fbBasicListGetSemantic(fbBasicList_t * basicList)4465 uint8_t fbBasicListGetSemantic(
4466 fbBasicList_t *basicList)
4467 {
4468 return basicList->semantic;
4469 }
4470
fbBasicListGetInfoElement(fbBasicList_t * basicList)4471 const fbInfoElement_t *fbBasicListGetInfoElement(
4472 fbBasicList_t *basicList)
4473 {
4474 return basicList->infoElement;
4475 }
4476
fbBasicListGetDataPtr(fbBasicList_t * basicList)4477 void *fbBasicListGetDataPtr(
4478 fbBasicList_t *basicList)
4479 {
4480 return (void*)basicList->dataPtr;
4481 }
4482
fbBasicListGetIndexedDataPtr(fbBasicList_t * basicList,uint16_t bl_index)4483 void *fbBasicListGetIndexedDataPtr(
4484 fbBasicList_t *basicList,
4485 uint16_t bl_index)
4486 {
4487 if (bl_index >= basicList->numElements) {
4488 return NULL;
4489 }
4490 return basicList->dataPtr + (bl_index * fbSizeofIE(basicList->infoElement));
4491 }
4492
fbBasicListGetNextPtr(fbBasicList_t * basicList,void * curPtr)4493 void *fbBasicListGetNextPtr(
4494 fbBasicList_t *basicList,
4495 void *curPtr)
4496 {
4497 uint16_t ie_len;
4498 uint8_t *currentPtr = curPtr;
4499
4500 if (!currentPtr) {
4501 return basicList->dataPtr;
4502 }
4503
4504 ie_len = fbSizeofIE(basicList->infoElement);
4505 currentPtr += ie_len;
4506
4507 if (((currentPtr - basicList->dataPtr) / ie_len) >=
4508 basicList->numElements)
4509 {
4510 return NULL;
4511 }
4512
4513 return (void*)currentPtr;
4514 }
4515
fbBasicListSetSemantic(fbBasicList_t * basicList,uint8_t semantic)4516 void fbBasicListSetSemantic(
4517 fbBasicList_t *basicList,
4518 uint8_t semantic)
4519 {
4520 basicList->semantic = semantic;
4521 }
4522
fbBasicListRealloc(fbBasicList_t * basicList,uint16_t newNumElements)4523 void *fbBasicListRealloc(
4524 fbBasicList_t *basicList,
4525 uint16_t newNumElements)
4526 {
4527 if (newNumElements == basicList->numElements) {
4528 return basicList->dataPtr;
4529 }
4530
4531 g_slice_free1(basicList->dataLength, basicList->dataPtr);
4532
4533 return fbBasicListInit(basicList, basicList->semantic,
4534 basicList->infoElement, newNumElements);
4535 }
4536
fbBasicListAddNewElements(fbBasicList_t * basicList,uint16_t numNewElements)4537 void* fbBasicListAddNewElements(
4538 fbBasicList_t *basicList,
4539 uint16_t numNewElements)
4540 {
4541 uint8_t *newDataPtr;
4542 uint16_t dataLength = 0;
4543 uint16_t numElements = basicList->numElements + numNewElements;
4544 const fbInfoElement_t *infoElement = basicList->infoElement;
4545 uint16_t offset = basicList->dataLength;
4546
4547 dataLength = numElements * fbSizeofIE(infoElement);
4548
4549 newDataPtr = g_slice_alloc0(dataLength);
4550 if (basicList->dataPtr) {
4551 memcpy(newDataPtr, basicList->dataPtr, basicList->dataLength);
4552 g_slice_free1(basicList->dataLength, basicList->dataPtr);
4553 }
4554 basicList->numElements = numElements;
4555 basicList->dataPtr = newDataPtr;
4556 basicList->dataLength = dataLength;
4557
4558 return basicList->dataPtr + offset;
4559 }
4560
fbBasicListClear(fbBasicList_t * basicList)4561 void fbBasicListClear(
4562 fbBasicList_t *basicList)
4563 {
4564 basicList->semantic = 0;
4565 basicList->infoElement = NULL;
4566 basicList->numElements = 0;
4567 g_slice_free1(basicList->dataLength, basicList->dataPtr);
4568 basicList->dataLength = 0;
4569 basicList->dataPtr = NULL;
4570 }
4571
fbBasicListClearWithoutFree(fbBasicList_t * basicList)4572 void fbBasicListClearWithoutFree(
4573 fbBasicList_t *basicList)
4574 {
4575 basicList->semantic = 0;
4576 basicList->infoElement = NULL;
4577 basicList->numElements = 0;
4578 }
4579
4580
fbBasicListFree(fbBasicList_t * basicList)4581 void fbBasicListFree(
4582 fbBasicList_t *basicList)
4583 {
4584 if (basicList) {
4585 fbBasicListClear(basicList);
4586 g_slice_free1(sizeof(fbBasicList_t), basicList);
4587 }
4588 }
4589
fbSubTemplateListAlloc(void)4590 fbSubTemplateList_t* fbSubTemplateListAlloc(
4591 void)
4592 {
4593 fbSubTemplateList_t *stl;
4594 stl = g_slice_new0(fbSubTemplateList_t);
4595 return stl;
4596 }
4597
fbSubTemplateListInit(fbSubTemplateList_t * subTemplateList,uint8_t semantic,uint16_t tmplID,const fbTemplate_t * tmpl,uint16_t numElements)4598 void* fbSubTemplateListInit(
4599 fbSubTemplateList_t *subTemplateList,
4600 uint8_t semantic,
4601 uint16_t tmplID,
4602 const fbTemplate_t *tmpl,
4603 uint16_t numElements)
4604 {
4605 g_assert(tmpl);
4606 g_assert(0 != tmplID);
4607
4608 subTemplateList->semantic = semantic;
4609 subTemplateList->tmplID = tmplID;
4610 subTemplateList->numElements = numElements;
4611 subTemplateList->tmpl = tmpl;
4612 if (!tmpl) {
4613 return NULL;
4614 }
4615 subTemplateList->dataLength.length = numElements * tmpl->ie_internal_len;
4616 subTemplateList->dataPtr =
4617 g_slice_alloc0(subTemplateList->dataLength.length);
4618 return (void*)subTemplateList->dataPtr;
4619 }
4620
fbSubTemplateListInitWithOwnBuffer(fbSubTemplateList_t * subTemplateList,uint8_t semantic,uint16_t tmplID,const fbTemplate_t * tmpl,uint16_t numElements,uint16_t dataLength,uint8_t * dataPtr)4621 void* fbSubTemplateListInitWithOwnBuffer(
4622 fbSubTemplateList_t *subTemplateList,
4623 uint8_t semantic,
4624 uint16_t tmplID,
4625 const fbTemplate_t *tmpl,
4626 uint16_t numElements,
4627 uint16_t dataLength,
4628 uint8_t *dataPtr)
4629 {
4630 g_assert(tmpl);
4631 g_assert(0 != tmplID);
4632
4633 subTemplateList->semantic = semantic;
4634 subTemplateList->tmplID = tmplID;
4635 subTemplateList->numElements = numElements;
4636 subTemplateList->tmpl = tmpl;
4637 subTemplateList->dataLength.length = dataLength;
4638 subTemplateList->dataPtr = dataPtr;
4639
4640 return (void*)subTemplateList->dataPtr;
4641 }
4642
fbSubTemplateListCollectorInit(fbSubTemplateList_t * STL)4643 void fbSubTemplateListCollectorInit(
4644 fbSubTemplateList_t *STL)
4645 {
4646 STL->semantic = 0;
4647 STL->numElements = 0;
4648 STL->dataLength.length = 0;
4649 STL->tmplID = 0;
4650 STL->tmpl = NULL;
4651 STL->dataPtr = NULL;
4652 }
4653
fbSubTemplateListClear(fbSubTemplateList_t * subTemplateList)4654 void fbSubTemplateListClear(
4655 fbSubTemplateList_t *subTemplateList)
4656 {
4657 subTemplateList->semantic = 0;
4658 subTemplateList->numElements = 0;
4659 subTemplateList->tmplID = 0;
4660 subTemplateList->tmpl = NULL;
4661 if (subTemplateList->dataLength.length) {
4662 g_slice_free1(subTemplateList->dataLength.length,
4663 subTemplateList->dataPtr);
4664 }
4665 subTemplateList->dataPtr = NULL;
4666 subTemplateList->dataLength.length = 0;
4667 }
4668
4669
fbSubTemplateListFree(fbSubTemplateList_t * subTemplateList)4670 void fbSubTemplateListFree(
4671 fbSubTemplateList_t *subTemplateList)
4672 {
4673 if (subTemplateList) {
4674 fbSubTemplateListClear(subTemplateList);
4675 g_slice_free1(sizeof(fbSubTemplateList_t), subTemplateList);
4676 }
4677 }
4678
fbSubTemplateListClearWithoutFree(fbSubTemplateList_t * subTemplateList)4679 void fbSubTemplateListClearWithoutFree(
4680 fbSubTemplateList_t *subTemplateList)
4681 {
4682 subTemplateList->semantic = 0;
4683 subTemplateList->tmplID = 0;
4684 subTemplateList->tmpl = NULL;
4685 subTemplateList->numElements = 0;
4686 }
4687
4688
fbSubTemplateListGetDataPtr(const fbSubTemplateList_t * sTL)4689 void* fbSubTemplateListGetDataPtr(
4690 const fbSubTemplateList_t *sTL)
4691 {
4692 return sTL->dataPtr;
4693 }
4694
4695 /* index is 0-based. Goes from 0 - (numElements-1) */
fbSubTemplateListGetIndexedDataPtr(const fbSubTemplateList_t * sTL,uint16_t stlIndex)4696 void* fbSubTemplateListGetIndexedDataPtr(
4697 const fbSubTemplateList_t *sTL,
4698 uint16_t stlIndex)
4699 {
4700 if (stlIndex >= sTL->numElements) {
4701 return NULL;
4702 }
4703
4704 /* removed reference to tmpl->ie_internal_len */
4705 return ((uint8_t*)(sTL->dataPtr) +
4706 stlIndex * (sTL->dataLength.length / sTL->numElements));
4707 }
4708
fbSubTemplateListGetNextPtr(const fbSubTemplateList_t * sTL,void * curPtr)4709 void* fbSubTemplateListGetNextPtr(
4710 const fbSubTemplateList_t *sTL,
4711 void *curPtr)
4712 {
4713 uint16_t tmplLen;
4714 uint8_t *currentPtr = curPtr;
4715
4716 if (!currentPtr) {
4717 return sTL->dataPtr;
4718 }
4719 if (!sTL->numElements || currentPtr < sTL->dataPtr) {
4720 return NULL;
4721 }
4722
4723 /* removed reference to tmpl->ie_internal_len */
4724 tmplLen = sTL->dataLength.length / sTL->numElements;
4725 currentPtr += tmplLen;
4726
4727 if (currentPtr >= (sTL->dataPtr + sTL->dataLength.length)) {
4728 return NULL;
4729 }
4730 return (void*)currentPtr;
4731 }
4732
fbSubTemplateListCountElements(const fbSubTemplateList_t * sTL)4733 uint16_t fbSubTemplateListCountElements(
4734 const fbSubTemplateList_t *sTL)
4735 {
4736 return sTL->numElements;
4737 }
4738
fbSubTemplateListSetSemantic(fbSubTemplateList_t * sTL,uint8_t semantic)4739 void fbSubTemplateListSetSemantic(
4740 fbSubTemplateList_t *sTL,
4741 uint8_t semantic)
4742 {
4743 sTL->semantic = semantic;
4744 }
4745
fbSubTemplateListGetSemantic(fbSubTemplateList_t * STL)4746 uint8_t fbSubTemplateListGetSemantic(
4747 fbSubTemplateList_t *STL)
4748 {
4749 return STL->semantic;
4750 }
4751
fbSubTemplateListGetTemplate(fbSubTemplateList_t * STL)4752 const fbTemplate_t* fbSubTemplateListGetTemplate(
4753 fbSubTemplateList_t *STL)
4754 {
4755 return STL->tmpl;
4756 }
4757
fbSubTemplateListGetTemplateID(fbSubTemplateList_t * STL)4758 uint16_t fbSubTemplateListGetTemplateID(
4759 fbSubTemplateList_t *STL)
4760 {
4761 return STL->tmplID;
4762 }
4763
fbSubTemplateListRealloc(fbSubTemplateList_t * subTemplateList,uint16_t newNumElements)4764 void* fbSubTemplateListRealloc(
4765 fbSubTemplateList_t *subTemplateList,
4766 uint16_t newNumElements)
4767 {
4768 uint16_t tmplLen;
4769
4770 if (newNumElements == subTemplateList->numElements) {
4771 return subTemplateList->dataPtr;
4772 }
4773 if (0 == subTemplateList->numElements) {
4774 tmplLen = subTemplateList->tmpl->ie_internal_len;
4775 } else {
4776 tmplLen = (subTemplateList->dataLength.length /
4777 subTemplateList->numElements);
4778 }
4779 g_slice_free1(subTemplateList->dataLength.length,
4780 subTemplateList->dataPtr);
4781 subTemplateList->numElements = newNumElements;
4782 subTemplateList->dataLength.length = subTemplateList->numElements * tmplLen;
4783 subTemplateList->dataPtr =
4784 g_slice_alloc0(subTemplateList->dataLength.length);
4785 return subTemplateList->dataPtr;
4786 }
4787
fbSubTemplateListAddNewElements(fbSubTemplateList_t * sTL,uint16_t numNewElements)4788 void* fbSubTemplateListAddNewElements(
4789 fbSubTemplateList_t *sTL,
4790 uint16_t numNewElements)
4791 {
4792 uint16_t offset = sTL->dataLength.length;
4793 uint16_t numElements = sTL->numElements + numNewElements;
4794 uint8_t *newDataPtr = NULL;
4795 uint16_t dataLength = 0;
4796
4797 dataLength = numElements * sTL->tmpl->ie_internal_len;
4798 newDataPtr = g_slice_alloc0(dataLength);
4799 if (sTL->dataPtr) {
4800 memcpy(newDataPtr, sTL->dataPtr, sTL->dataLength.length);
4801 g_slice_free1(sTL->dataLength.length, sTL->dataPtr);
4802 }
4803 sTL->numElements = numElements;
4804 sTL->dataPtr = newDataPtr;
4805 sTL->dataLength.length = dataLength;
4806
4807 return sTL->dataPtr + offset;
4808 }
4809
fbSubTemplateMultiListAlloc(void)4810 fbSubTemplateMultiList_t* fbSubTemplateMultiListAlloc(
4811 void)
4812 {
4813 fbSubTemplateMultiList_t *stml;
4814
4815 stml = g_slice_new0(fbSubTemplateMultiList_t);
4816 return stml;
4817 }
4818
fbSubTemplateMultiListInit(fbSubTemplateMultiList_t * sTML,uint8_t semantic,uint16_t numElements)4819 fbSubTemplateMultiListEntry_t* fbSubTemplateMultiListInit(
4820 fbSubTemplateMultiList_t *sTML,
4821 uint8_t semantic,
4822 uint16_t numElements)
4823 {
4824 sTML->semantic = semantic;
4825 sTML->numElements = numElements;
4826 sTML->firstEntry = g_slice_alloc0(sTML->numElements *
4827 sizeof(fbSubTemplateMultiListEntry_t));
4828 return sTML->firstEntry;
4829 }
4830
fbSubTemplateMultiListCountElements(const fbSubTemplateMultiList_t * STML)4831 uint16_t fbSubTemplateMultiListCountElements(
4832 const fbSubTemplateMultiList_t *STML)
4833 {
4834 return STML->numElements;
4835 }
4836
fbSubTemplateMultiListSetSemantic(fbSubTemplateMultiList_t * STML,uint8_t semantic)4837 void fbSubTemplateMultiListSetSemantic(
4838 fbSubTemplateMultiList_t *STML,
4839 uint8_t semantic)
4840 {
4841 STML->semantic = semantic;
4842 }
4843
fbSubTemplateMultiListGetSemantic(fbSubTemplateMultiList_t * STML)4844 uint8_t fbSubTemplateMultiListGetSemantic(
4845 fbSubTemplateMultiList_t *STML)
4846 {
4847 return STML->semantic;
4848 }
4849
fbSubTemplateMultiListClear(fbSubTemplateMultiList_t * sTML)4850 void fbSubTemplateMultiListClear(
4851 fbSubTemplateMultiList_t *sTML)
4852 {
4853 fbSubTemplateMultiListClearEntries(sTML);
4854
4855 g_slice_free1(sTML->numElements * sizeof(fbSubTemplateMultiListEntry_t),
4856 sTML->firstEntry);
4857 sTML->numElements = 0;
4858 sTML->firstEntry = NULL;
4859 }
4860
fbSubTemplateMultiListClearEntries(fbSubTemplateMultiList_t * sTML)4861 void fbSubTemplateMultiListClearEntries(
4862 fbSubTemplateMultiList_t *sTML)
4863 {
4864 fbSubTemplateMultiListEntry_t *entry = NULL;
4865 while ((entry = fbSubTemplateMultiListGetNextEntry(sTML, entry))) {
4866 fbSubTemplateMultiListEntryClear(entry);
4867 }
4868 }
4869
fbSubTemplateMultiListFree(fbSubTemplateMultiList_t * sTML)4870 void fbSubTemplateMultiListFree(
4871 fbSubTemplateMultiList_t *sTML)
4872 {
4873 if (sTML) {
4874 fbSubTemplateMultiListClear(sTML);
4875 g_slice_free1(sizeof(fbSubTemplateMultiList_t), sTML);
4876 }
4877 }
4878
fbSubTemplateMultiListRealloc(fbSubTemplateMultiList_t * sTML,uint16_t newNumElements)4879 fbSubTemplateMultiListEntry_t* fbSubTemplateMultiListRealloc(
4880 fbSubTemplateMultiList_t *sTML,
4881 uint16_t newNumElements)
4882 {
4883 fbSubTemplateMultiListClearEntries(sTML);
4884 if (newNumElements == sTML->numElements) {
4885 return sTML->firstEntry;
4886 }
4887 g_slice_free1(sTML->numElements * sizeof(fbSubTemplateMultiListEntry_t),
4888 sTML->firstEntry);
4889 sTML->numElements = newNumElements;
4890 sTML->firstEntry = g_slice_alloc0(sTML->numElements *
4891 sizeof(fbSubTemplateMultiListEntry_t));
4892 return sTML->firstEntry;
4893 }
4894
fbSubTemplateMultiListAddNewEntries(fbSubTemplateMultiList_t * sTML,uint16_t numNewEntries)4895 fbSubTemplateMultiListEntry_t* fbSubTemplateMultiListAddNewEntries(
4896 fbSubTemplateMultiList_t *sTML,
4897 uint16_t numNewEntries)
4898 {
4899 fbSubTemplateMultiListEntry_t *newFirstEntry;
4900 uint16_t newNumElements = sTML->numElements + numNewEntries;
4901 uint16_t oldNumElements = sTML->numElements;
4902
4903 newFirstEntry = g_slice_alloc0(newNumElements *
4904 sizeof(fbSubTemplateMultiListEntry_t));
4905 if (sTML->firstEntry) {
4906 memcpy(newFirstEntry, sTML->firstEntry,
4907 (sTML->numElements * sizeof(fbSubTemplateMultiListEntry_t)));
4908 g_slice_free1(sTML->numElements *
4909 sizeof(fbSubTemplateMultiListEntry_t), sTML->firstEntry);
4910 }
4911
4912 sTML->numElements = newNumElements;
4913 sTML->firstEntry = newFirstEntry;
4914 return sTML->firstEntry + oldNumElements;
4915 }
4916
fbSubTemplateMultiListGetFirstEntry(fbSubTemplateMultiList_t * sTML)4917 fbSubTemplateMultiListEntry_t* fbSubTemplateMultiListGetFirstEntry(
4918 fbSubTemplateMultiList_t *sTML)
4919 {
4920 return sTML->firstEntry;
4921 }
4922
fbSubTemplateMultiListGetIndexedEntry(fbSubTemplateMultiList_t * sTML,uint16_t stmlIndex)4923 fbSubTemplateMultiListEntry_t* fbSubTemplateMultiListGetIndexedEntry(
4924 fbSubTemplateMultiList_t *sTML,
4925 uint16_t stmlIndex)
4926 {
4927 if (stmlIndex >= sTML->numElements) {
4928 return NULL;
4929 }
4930
4931 return sTML->firstEntry + stmlIndex;
4932 }
4933
fbSubTemplateMultiListGetNextEntry(fbSubTemplateMultiList_t * sTML,fbSubTemplateMultiListEntry_t * currentEntry)4934 fbSubTemplateMultiListEntry_t* fbSubTemplateMultiListGetNextEntry(
4935 fbSubTemplateMultiList_t *sTML,
4936 fbSubTemplateMultiListEntry_t *currentEntry)
4937 {
4938 if (!currentEntry) {
4939 return sTML->firstEntry;
4940 }
4941
4942 currentEntry++;
4943
4944 if ((uint16_t)(currentEntry - sTML->firstEntry) >= sTML->numElements) {
4945 return NULL;
4946 }
4947 return currentEntry;
4948 }
4949
fbSubTemplateMultiListEntryClear(fbSubTemplateMultiListEntry_t * entry)4950 void fbSubTemplateMultiListEntryClear(
4951 fbSubTemplateMultiListEntry_t *entry)
4952 {
4953 g_slice_free1(entry->dataLength, entry->dataPtr);
4954 entry->dataLength = 0;
4955 entry->dataPtr = NULL;
4956 }
4957
fbSubTemplateMultiListEntryGetDataPtr(fbSubTemplateMultiListEntry_t * entry)4958 void* fbSubTemplateMultiListEntryGetDataPtr(
4959 fbSubTemplateMultiListEntry_t *entry)
4960 {
4961 return entry->dataPtr;
4962 }
4963
fbSubTemplateMultiListEntryInit(fbSubTemplateMultiListEntry_t * entry,uint16_t tmplID,fbTemplate_t * tmpl,uint16_t numElements)4964 void* fbSubTemplateMultiListEntryInit(
4965 fbSubTemplateMultiListEntry_t *entry,
4966 uint16_t tmplID,
4967 fbTemplate_t *tmpl,
4968 uint16_t numElements)
4969 {
4970 g_assert(tmpl);
4971 g_assert(0 != tmplID);
4972
4973 entry->tmplID = tmplID;
4974 entry->tmpl = tmpl;
4975 if (!tmpl) {
4976 return NULL;
4977 }
4978 entry->numElements = numElements;
4979 entry->dataLength = tmpl->ie_internal_len * numElements;
4980 entry->dataPtr = g_slice_alloc0(entry->dataLength);
4981
4982 return entry->dataPtr;
4983 }
4984
fbSubTemplateMultiListEntryCountElements(const fbSubTemplateMultiListEntry_t * entry)4985 uint16_t fbSubTemplateMultiListEntryCountElements(
4986 const fbSubTemplateMultiListEntry_t *entry)
4987 {
4988 return entry->numElements;
4989 }
4990
fbSubTemplateMultiListEntryGetTemplate(fbSubTemplateMultiListEntry_t * entry)4991 const fbTemplate_t* fbSubTemplateMultiListEntryGetTemplate(
4992 fbSubTemplateMultiListEntry_t *entry)
4993 {
4994 return entry->tmpl;
4995 }
4996
fbSubTemplateMultiListEntryGetTemplateID(fbSubTemplateMultiListEntry_t * entry)4997 uint16_t fbSubTemplateMultiListEntryGetTemplateID(
4998 fbSubTemplateMultiListEntry_t *entry)
4999 {
5000 return entry->tmplID;
5001 }
5002
fbSubTemplateMultiListEntryRealloc(fbSubTemplateMultiListEntry_t * entry,uint16_t newNumElements)5003 void *fbSubTemplateMultiListEntryRealloc(
5004 fbSubTemplateMultiListEntry_t *entry,
5005 uint16_t newNumElements)
5006 {
5007 if (newNumElements == entry->numElements) {
5008 return entry->dataPtr;
5009 }
5010 g_slice_free1(entry->dataLength, entry->dataPtr);
5011 entry->numElements = newNumElements;
5012 entry->dataLength = newNumElements * entry->tmpl->ie_internal_len;
5013 entry->dataPtr = g_slice_alloc0(entry->dataLength);
5014 return entry->dataPtr;
5015 }
5016
fbSubTemplateMultiListEntryAddNewElements(fbSubTemplateMultiListEntry_t * entry,uint16_t numNewElements)5017 void* fbSubTemplateMultiListEntryAddNewElements(
5018 fbSubTemplateMultiListEntry_t *entry,
5019 uint16_t numNewElements)
5020 {
5021 uint16_t offset = entry->dataLength;
5022 uint16_t numElements = entry->numElements + numNewElements;
5023 uint8_t *newDataPtr;
5024 uint16_t dataLength;
5025
5026 dataLength = numElements * entry->tmpl->ie_internal_len;
5027 newDataPtr = g_slice_alloc0(dataLength);
5028 if (entry->dataPtr) {
5029 memcpy(newDataPtr, entry->dataPtr, entry->dataLength);
5030 g_slice_free1(entry->dataLength, entry->dataPtr);
5031 }
5032 entry->numElements = numElements;
5033 entry->dataPtr = newDataPtr;
5034 entry->dataLength = dataLength;
5035
5036 return entry->dataPtr + offset;
5037 }
5038
fbSubTemplateMultiListEntryNextDataPtr(fbSubTemplateMultiListEntry_t * entry,void * curPtr)5039 void* fbSubTemplateMultiListEntryNextDataPtr(
5040 fbSubTemplateMultiListEntry_t *entry,
5041 void *curPtr)
5042 {
5043 uint16_t tmplLen;
5044 uint8_t *currentPtr = curPtr;
5045
5046 if (!currentPtr) {
5047 return entry->dataPtr;
5048 }
5049 if (!entry->numElements || currentPtr < entry->dataPtr) {
5050 return NULL;
5051 }
5052
5053 tmplLen = entry->dataLength / entry->numElements;
5054 currentPtr += tmplLen;
5055
5056 if ((uint16_t)(currentPtr - entry->dataPtr) >= entry->dataLength) {
5057 return NULL;
5058 }
5059
5060 return (void*)currentPtr;
5061 }
5062
fbSubTemplateMultiListEntryGetIndexedPtr(fbSubTemplateMultiListEntry_t * entry,uint16_t stmleIndex)5063 void* fbSubTemplateMultiListEntryGetIndexedPtr(
5064 fbSubTemplateMultiListEntry_t *entry,
5065 uint16_t stmleIndex)
5066 {
5067 if (stmleIndex >= entry->numElements) {
5068 return NULL;
5069 }
5070
5071 return ((uint8_t*)(entry->dataPtr) +
5072 (stmleIndex * entry->dataLength / entry->numElements));
5073 }
5074
5075
5076 /**
5077 * fBufSTMLEntryRecordFree
5078 *
5079 * Free all records within the STMLEntry
5080 *
5081 */
fBufSTMLEntryRecordFree(fbSubTemplateMultiListEntry_t * entry)5082 static void fBufSTMLEntryRecordFree(
5083 fbSubTemplateMultiListEntry_t *entry)
5084 {
5085 uint8_t *data = NULL;
5086
5087 while ((data = fbSubTemplateMultiListEntryNextDataPtr(entry, data))) {
5088 fBufListFree(entry->tmpl, data);
5089 }
5090 }
5091
5092
5093 /**
5094 * fBufSTMLRecordFree
5095 *
5096 * Access each entry in the STML and free the records in each
5097 * entry.
5098 *
5099 */
fBufSTMLRecordFree(uint8_t * record)5100 static void fBufSTMLRecordFree(
5101 uint8_t *record)
5102 {
5103 fbSubTemplateMultiList_t *stml = (fbSubTemplateMultiList_t *)record;
5104 fbSubTemplateMultiListEntry_t *entry = NULL;
5105
5106 while ((entry = fbSubTemplateMultiListGetNextEntry(stml, entry))) {
5107 fBufSTMLEntryRecordFree(entry);
5108 }
5109 }
5110
5111 /**
5112 * fBufSTLRecordFree
5113 *
5114 * Free all records within the subTemplateList
5115 *
5116 */
fBufSTLRecordFree(uint8_t * record)5117 static void fBufSTLRecordFree(
5118 uint8_t *record)
5119 {
5120 fbSubTemplateList_t *stl = (fbSubTemplateList_t *)record;
5121 uint8_t *data = NULL;
5122
5123 while ((data = fbSubTemplateListGetNextPtr(stl, data))) {
5124 fBufListFree((fbTemplate_t *)(stl->tmpl), data);
5125 }
5126 }
5127
5128 /**
5129 * fBufBLRecordFree
5130 *
5131 * Free any list elements nested within a basicList
5132 *
5133 */
fBufBLRecordFree(fbBasicList_t * bl)5134 static void fBufBLRecordFree(
5135 fbBasicList_t *bl)
5136 {
5137 uint8_t *data = NULL;
5138
5139 while ((data = fbBasicListGetNextPtr(bl, data))) {
5140 if (bl->infoElement->type == FB_SUB_TMPL_MULTI_LIST) {
5141 fBufSTMLRecordFree(data);
5142 fbSubTemplateMultiListClear((fbSubTemplateMultiList_t *)(data));
5143 } else if (bl->infoElement->type == FB_SUB_TMPL_LIST) {
5144 fBufSTLRecordFree(data);
5145 fbSubTemplateListClear((fbSubTemplateList_t *)(data));
5146 } else if (bl->infoElement->type == FB_BASIC_LIST) {
5147 fBufBLRecordFree((fbBasicList_t *)data);
5148 fbBasicListClear((fbBasicList_t *)(data));
5149 }
5150 }
5151 }
5152
5153 /**
5154 * fBufListFree
5155 *
5156 * This frees any list information elements that were allocated
5157 * either by fixbuf or the application during encode or decode.
5158 *
5159 * The template provided is the internal template and MUST match
5160 * the record exactly, or bad things will happen.
5161 * There is no way to check that the user is doing the right
5162 * thing.
5163 */
fBufListFree(fbTemplate_t * template,uint8_t * record)5164 void fBufListFree(
5165 fbTemplate_t *template,
5166 uint8_t *record)
5167 {
5168 uint32_t i;
5169 fbInfoElement_t *ie = NULL;
5170 uint16_t buf_walk = 0;
5171 uint32_t count = fbTemplateCountElements(template);
5172
5173 if (!template->is_varlen) {
5174 /* no variable length fields in this template */
5175 return;
5176 }
5177 g_assert(record);
5178
5179 for (i = 0; i < count; i++) {
5180 ie = fbTemplateGetIndexedIE(template, i);
5181
5182 if (ie->len != FB_IE_VARLEN) {
5183 buf_walk += ie->len;
5184 } else if (ie->type == FB_SUB_TMPL_MULTI_LIST) {
5185 fBufSTMLRecordFree(record + buf_walk);
5186 fbSubTemplateMultiListClear((fbSubTemplateMultiList_t *)
5187 (record + buf_walk));
5188 buf_walk += sizeof(fbSubTemplateMultiList_t);
5189 } else if (ie->type == FB_SUB_TMPL_LIST) {
5190 fBufSTLRecordFree(record + buf_walk);
5191 fbSubTemplateListClear((fbSubTemplateList_t *)(record + buf_walk));
5192 buf_walk += sizeof(fbSubTemplateList_t);
5193 } else if (ie->type == FB_BASIC_LIST) {
5194 fBufBLRecordFree((fbBasicList_t *)(record + buf_walk));
5195 fbBasicListClear((fbBasicList_t *)(record + buf_walk));
5196 buf_walk += sizeof(fbBasicList_t);
5197 } else {
5198 /* variable length */
5199 buf_walk += sizeof(fbVarfield_t);
5200 }
5201 }
5202 }
5203