1 /*
2 ** fbtemplate.c
3 ** IPFIX Template implementation
4 **
5 ** ------------------------------------------------------------------------
6 ** Copyright (C) 2006-2019 Carnegie Mellon University. All Rights Reserved.
7 ** ------------------------------------------------------------------------
8 ** Authors: Brian Trammell
9 ** ------------------------------------------------------------------------
10 ** @OPENSOURCE_LICENSE_START@
11 ** libfixbuf 2.0
12 **
13 ** Copyright 2018-2019 Carnegie Mellon University. All Rights Reserved.
14 **
15 ** NO WARRANTY. THIS CARNEGIE MELLON UNIVERSITY AND SOFTWARE
16 ** ENGINEERING INSTITUTE MATERIAL IS FURNISHED ON AN "AS-IS"
17 ** BASIS. CARNEGIE MELLON UNIVERSITY MAKES NO WARRANTIES OF ANY KIND,
18 ** EITHER EXPRESSED OR IMPLIED, AS TO ANY MATTER INCLUDING, BUT NOT
19 ** LIMITED TO, WARRANTY OF FITNESS FOR PURPOSE OR MERCHANTABILITY,
20 ** EXCLUSIVITY, OR RESULTS OBTAINED FROM USE OF THE
21 ** MATERIAL. CARNEGIE MELLON UNIVERSITY DOES NOT MAKE ANY WARRANTY OF
22 ** ANY KIND WITH RESPECT TO FREEDOM FROM PATENT, TRADEMARK, OR
23 ** COPYRIGHT INFRINGEMENT.
24 **
25 ** Released under a GNU-Lesser GPL 3.0-style license, please see
26 ** LICENSE.txt or contact permission@sei.cmu.edu for full terms.
27 **
28 ** [DISTRIBUTION STATEMENT A] This material has been approved for
29 ** public release and unlimited distribution. Please see Copyright
30 ** notice for non-US Government use and distribution.
31 **
32 ** Carnegie Mellon(R) and CERT(R) are registered in the U.S. Patent
33 ** and Trademark Office by Carnegie Mellon University.
34 **
35 ** DM18-0325
36 ** @OPENSOURCE_LICENSE_END@
37 ** ------------------------------------------------------------------------
38 */
39
40 #define _FIXBUF_SOURCE_
41 #define DEFINE_TEMPLATE_METADATA_SPEC
42 #include <fixbuf/private.h>
43
44
45
fbTemplateDebug(const char * label,uint16_t tid,fbTemplate_t * tmpl)46 void fbTemplateDebug(
47 const char *label,
48 uint16_t tid,
49 fbTemplate_t *tmpl)
50 {
51 int i;
52
53 fprintf(stderr, "%s template %04x [%p] iec=%u sc=%u len=%u\n", label, tid,
54 (void *)tmpl, tmpl->ie_count, tmpl->scope_count, tmpl->ie_len);
55
56 for (i = 0; i < tmpl->ie_count; i++) {
57 fprintf(stderr,"\t%2u ", i);
58 fbInfoElementDebug(TRUE, tmpl->ie_ary[i]);
59 }
60 }
61
fbTemplateAlloc(fbInfoModel_t * model)62 fbTemplate_t *fbTemplateAlloc(
63 fbInfoModel_t *model)
64 {
65 fbTemplate_t *tmpl = NULL;
66
67 /* create a new template */
68 tmpl = g_slice_new0(fbTemplate_t);
69
70 /* fill it in */
71 tmpl->model = model;
72 tmpl->tmpl_len = 4;
73 tmpl->active = FALSE;
74
75 /* allocate indices table */
76 tmpl->indices = g_hash_table_new((GHashFunc)fbInfoElementHash,
77 (GEqualFunc)fbInfoElementEqual);
78 return tmpl;
79 }
80
81
fbTemplateRetain(fbTemplate_t * tmpl)82 void fbTemplateRetain(
83 fbTemplate_t *tmpl)
84 {
85 /* Increment reference count */
86 ++(tmpl->ref_count);
87 }
88
fbTemplateRelease(fbTemplate_t * tmpl)89 void fbTemplateRelease(
90 fbTemplate_t *tmpl)
91 {
92 /* Decrement reference count */
93 --(tmpl->ref_count);
94 /* Free if not referenced */
95 fbTemplateFreeUnused(tmpl);
96 }
97
fbTemplateFreeUnused(fbTemplate_t * tmpl)98 void fbTemplateFreeUnused(
99 fbTemplate_t *tmpl)
100 {
101 if (tmpl->ref_count <= 0) {
102 fbTemplateFree(tmpl);
103 }
104 }
105
fbTemplateFree(fbTemplate_t * tmpl)106 void fbTemplateFree(
107 fbTemplate_t *tmpl)
108 {
109 int i;
110
111 if (tmpl->ctx_free) {
112 tmpl->ctx_free(tmpl->tmpl_ctx, tmpl->app_ctx);
113 }
114 /* destroy index table if present */
115 if (tmpl->indices) g_hash_table_destroy(tmpl->indices);
116
117 /* destroy IE array */
118 for (i = 0; i < tmpl->ie_count; i++) {
119 g_slice_free(fbInfoElement_t, tmpl->ie_ary[i]);
120 }
121 g_free(tmpl->ie_ary);
122
123 if (tmpl->metadata_rec) {
124 g_free(tmpl->metadata_rec->template_name.buf);
125 g_free(tmpl->metadata_rec->template_description.buf);
126 g_slice_free(fbTemplateOptRec_t, tmpl->metadata_rec);
127 }
128 /* destroy offset cache if present */
129 if (tmpl->off_cache) g_free(tmpl->off_cache);
130 /* destroy template */
131 g_slice_free(fbTemplate_t, tmpl);
132
133 }
134
fbTemplateExtendElements(fbTemplate_t * tmpl)135 static fbInfoElement_t *fbTemplateExtendElements(
136 fbTemplate_t *tmpl)
137 {
138 if (tmpl->ie_count) {
139 tmpl->ie_ary =
140 g_renew(fbInfoElement_t*, tmpl->ie_ary, ++(tmpl->ie_count));
141 } else {
142 tmpl->ie_ary = g_new(fbInfoElement_t*, 1);
143 ++(tmpl->ie_count);
144 }
145
146 tmpl->ie_ary[tmpl->ie_count - 1] = g_slice_new0(fbInfoElement_t);
147
148 return tmpl->ie_ary[tmpl->ie_count - 1];
149 }
150
fbTemplateExtendIndices(fbTemplate_t * tmpl,fbInfoElement_t * tmpl_ie)151 static void fbTemplateExtendIndices(
152 fbTemplate_t *tmpl,
153 fbInfoElement_t *tmpl_ie)
154 {
155 void *ign0, *ign1;
156
157 /* search indices table for multiple IE index */
158 while (g_hash_table_lookup_extended(tmpl->indices, tmpl_ie, &ign0, &ign1)) {
159 ++(tmpl_ie->midx);
160 }
161
162 /* increment template lengths */
163 tmpl->tmpl_len += tmpl_ie->ent ? 8 : 4;
164 if (tmpl_ie->len == FB_IE_VARLEN) {
165 tmpl->is_varlen = TRUE;
166 tmpl->ie_len += 1;
167 if (tmpl_ie->type == FB_BASIC_LIST) {
168 tmpl->ie_internal_len += sizeof(fbBasicList_t);
169 } else if (tmpl_ie->type == FB_SUB_TMPL_LIST) {
170 tmpl->ie_internal_len += sizeof(fbSubTemplateList_t);
171 } else if (tmpl_ie->type == FB_SUB_TMPL_MULTI_LIST) {
172 tmpl->ie_internal_len += sizeof(fbSubTemplateMultiList_t);
173 } else {
174 tmpl->ie_internal_len += sizeof(fbVarfield_t);
175 }
176 } else {
177 tmpl->ie_len += tmpl_ie->len;
178 tmpl->ie_internal_len += tmpl_ie->len;
179 }
180
181 /* Add index of this information element to the indices table */
182 g_hash_table_insert(tmpl->indices, tmpl_ie,
183 GUINT_TO_POINTER(tmpl->ie_count - 1));
184 }
185
fbTemplateAppend(fbTemplate_t * tmpl,fbInfoElement_t * ex_ie,GError ** err)186 gboolean fbTemplateAppend(
187 fbTemplate_t *tmpl,
188 fbInfoElement_t *ex_ie,
189 GError **err)
190 {
191 fbInfoElement_t *tmpl_ie;
192
193 g_assert(ex_ie);
194
195 /* grow information element array */
196 tmpl_ie = fbTemplateExtendElements(tmpl);
197
198 /* copy information element out of the info model */
199 if (!fbInfoElementCopyToTemplate(tmpl->model, ex_ie, tmpl_ie)) {
200 g_set_error(err, FB_ERROR_DOMAIN, FB_ERROR_NOELEMENT,
201 "No such information element %08x:%04x",
202 ex_ie->ent, ex_ie->num);
203 return FALSE;
204 }
205
206 /* Handle index and counter updates */
207 fbTemplateExtendIndices(tmpl, tmpl_ie);
208
209 /* All done */
210 return TRUE;
211 }
212
fbTemplateAppendSpec(fbTemplate_t * tmpl,fbInfoElementSpec_t * spec,uint32_t flags,GError ** err)213 gboolean fbTemplateAppendSpec(
214 fbTemplate_t *tmpl,
215 fbInfoElementSpec_t *spec,
216 uint32_t flags,
217 GError **err)
218 {
219 fbInfoElement_t *tmpl_ie;
220
221 /* Short-circuit on app flags mismatch */
222 if (spec->flags && !((spec->flags & flags) == spec->flags)) {
223 return TRUE;
224 }
225
226 /* grow information element array */
227 tmpl_ie = fbTemplateExtendElements(tmpl);
228 /* copy information element out of the info model */
229
230 if (!fbInfoElementCopyToTemplateByName(tmpl->model, spec->name,
231 spec->len_override, tmpl_ie)) {
232 g_set_error(err, FB_ERROR_DOMAIN, FB_ERROR_NOELEMENT,
233 "No such information element %s", spec->name);
234 return FALSE;
235 }
236 if (spec->len_override == 0 && tmpl_ie->len != FB_IE_VARLEN) {
237 tmpl->default_length = TRUE;
238 }
239
240 /* Handle index and counter updates */
241 fbTemplateExtendIndices(tmpl, tmpl_ie);
242
243 /* All done */
244 return TRUE;
245 }
246
fbTemplateAppendSpecArray(fbTemplate_t * tmpl,fbInfoElementSpec_t * spec,uint32_t flags,GError ** err)247 gboolean fbTemplateAppendSpecArray(
248 fbTemplate_t *tmpl,
249 fbInfoElementSpec_t *spec,
250 uint32_t flags,
251 GError **err)
252 {
253 for (; spec->name; spec++) {
254 if (!fbTemplateAppendSpec(tmpl, spec, flags, err)) {
255 return FALSE;
256 }
257 }
258
259 return TRUE;
260 }
261
fbTemplateSetOptionsScope(fbTemplate_t * tmpl,uint16_t scope_count)262 void fbTemplateSetOptionsScope(
263 fbTemplate_t *tmpl,
264 uint16_t scope_count)
265 {
266 /* Cannot set options scope if we've already done so */
267 g_assert(!tmpl->scope_count);
268
269 /* Cannot set scope count higher than IE count */
270 g_assert(tmpl->ie_count && tmpl->ie_count >= tmpl->scope_count);
271
272 /* scope count of zero means make the last IE the end of scope */
273 tmpl->scope_count = scope_count ? scope_count : tmpl->ie_count;
274
275 /* account for scope count in output */
276 tmpl->tmpl_len += 2;
277 }
278
fbTemplateContainsElement(fbTemplate_t * tmpl,const fbInfoElement_t * ex_ie)279 gboolean fbTemplateContainsElement(
280 fbTemplate_t *tmpl,
281 const fbInfoElement_t *ex_ie)
282 {
283 int i;
284
285 if ( ex_ie == NULL || tmpl == NULL ) {
286 return FALSE;
287 }
288
289 for (i = 0; i < tmpl->ie_count; i++) {
290 if (fbInfoElementEqual(ex_ie, tmpl->ie_ary[i])) return TRUE;
291 }
292
293 return FALSE;
294 }
295
fbTemplateContainsElementByName(fbTemplate_t * tmpl,fbInfoElementSpec_t * spec)296 gboolean fbTemplateContainsElementByName(
297 fbTemplate_t *tmpl,
298 fbInfoElementSpec_t *spec)
299 {
300 return fbTemplateContainsElement(
301 tmpl, fbInfoModelGetElementByName(tmpl->model, spec->name));
302 }
303
fbTemplateContainsAllElementsByName(fbTemplate_t * tmpl,fbInfoElementSpec_t * spec)304 gboolean fbTemplateContainsAllElementsByName(
305 fbTemplate_t *tmpl,
306 fbInfoElementSpec_t *spec)
307 {
308 for (; spec->name; spec++) {
309 if (!fbTemplateContainsElementByName(tmpl, spec)) return FALSE;
310 }
311
312 return TRUE;
313 }
314
fbTemplateContainsAllFlaggedElementsByName(fbTemplate_t * tmpl,fbInfoElementSpec_t * spec,uint32_t flags)315 gboolean fbTemplateContainsAllFlaggedElementsByName(
316 fbTemplate_t *tmpl,
317 fbInfoElementSpec_t *spec,
318 uint32_t flags)
319 {
320 for (; spec->name; spec++) {
321 if (spec->flags && !((spec->flags & flags) == spec->flags)) {
322 continue;
323 }
324 if (!fbTemplateContainsElementByName(tmpl, spec)) return FALSE;
325 }
326
327 return TRUE;
328 }
329
fbTemplateCountElements(fbTemplate_t * tmpl)330 uint32_t fbTemplateCountElements(
331 fbTemplate_t *tmpl)
332 {
333 return tmpl->ie_count;
334 }
335
fbTemplateGetIndexedIE(fbTemplate_t * tmpl,uint32_t IEindex)336 fbInfoElement_t* fbTemplateGetIndexedIE(
337 fbTemplate_t *tmpl,
338 uint32_t IEindex)
339 {
340 if (IEindex < tmpl->ie_count) {
341 return tmpl->ie_ary[IEindex];
342 } else {
343 return NULL;
344 }
345 }
346
fbTemplateGetOptionsScope(fbTemplate_t * tmpl)347 uint32_t fbTemplateGetOptionsScope(
348 fbTemplate_t *tmpl)
349 {
350 return tmpl->scope_count;
351 }
352
fbTemplateGetContext(fbTemplate_t * tmpl)353 void *fbTemplateGetContext(
354 fbTemplate_t *tmpl)
355 {
356 return tmpl->tmpl_ctx;
357 }
358
fbTemplateGetIELenOfMemBuffer(fbTemplate_t * tmpl)359 uint16_t fbTemplateGetIELenOfMemBuffer(
360 fbTemplate_t *tmpl)
361 {
362 return tmpl->ie_internal_len;
363 }
364
fbTemplateGetInfoModel(fbTemplate_t * tmpl)365 fbInfoModel_t *fbTemplateGetInfoModel(
366 fbTemplate_t *tmpl)
367 {
368 return tmpl->model;
369 }
370
fbTemplateAllocTemplateMetadataTmpl(fbInfoModel_t * model,gboolean internal,GError ** err)371 fbTemplate_t *fbTemplateAllocTemplateMetadataTmpl(
372 fbInfoModel_t *model,
373 gboolean internal,
374 GError **err)
375 {
376 fbTemplate_t *tmpl;
377 uint32_t flags;
378
379 /* do not include padding when external */
380 flags = internal ? ~0 : 0;
381
382 tmpl = fbTemplateAlloc(model);
383 if (!fbTemplateAppendSpecArray(tmpl, template_metadata_spec, flags, err)) {
384 fbTemplateFreeUnused(tmpl);
385 return NULL;
386 }
387 fbTemplateSetOptionsScope(tmpl, 1);
388 return tmpl;
389 }
390
fbTemplateAddMetadataRecord(fbTemplate_t * tmpl,uint16_t tid,const char * name,const char * description)391 void fbTemplateAddMetadataRecord(
392 fbTemplate_t *tmpl,
393 uint16_t tid,
394 const char *name,
395 const char *description)
396 {
397 fbTemplateOptRec_t *metadata_rec;
398
399 metadata_rec = g_slice_new0(fbTemplateOptRec_t);
400 metadata_rec->template_id = tid;
401 metadata_rec->template_name.buf = (uint8_t *) g_strdup(name);
402 metadata_rec->template_name.len = strlen(name);
403
404 if (description) {
405 metadata_rec->template_description.buf =
406 (uint8_t *) g_strdup(description);
407 metadata_rec->template_description.len = strlen(description);
408 }
409
410 if (tmpl->metadata_rec) {
411 g_free(tmpl->metadata_rec->template_name.buf);
412 g_free(tmpl->metadata_rec->template_description.buf);
413 g_slice_free(fbTemplateOptRec_t, tmpl->metadata_rec);
414 }
415
416 tmpl->metadata_rec = metadata_rec;
417 }
418
419