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