blob: 39a679045bc1f639886c4f02043de9f16c76265e [file] [log] [blame]
Rich Lanea06d0c32013-03-25 08:52:03 -07001:: # Copyright 2013, Big Switch Networks, Inc.
2:: #
3:: # LoxiGen is licensed under the Eclipse Public License, version 1.0 (EPL), with
4:: # the following special exception:
5:: #
6:: # LOXI Exception
7:: #
8:: # As a special exception to the terms of the EPL, you may distribute libraries
9:: # generated by LoxiGen (LoxiGen Libraries) under the terms of your choice, provided
10:: # that copyright and licensing notices generated by LoxiGen are not altered or removed
11:: # from the LoxiGen Libraries and the notice provided below is (i) included in
12:: # the LoxiGen Libraries, if distributed in source code form and (ii) included in any
13:: # documentation for the LoxiGen Libraries, if distributed in binary form.
14:: #
15:: # Notice: "Copyright 2013, Big Switch Networks, Inc. This library was generated by the LoxiGen Compiler."
16:: #
17:: # You may not use this file except in compliance with the EPL or LOXI Exception. You may obtain
18:: # a copy of the EPL at:
19:: #
20:: # http://www.eclipse.org/legal/epl-v10.html
21:: #
22:: # Unless required by applicable law or agreed to in writing, software
23:: # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
24:: # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
25:: # EPL for the specific language governing permissions and limitations
26:: # under the EPL.
27::
Rich Laned983aa52013-06-13 11:48:37 -070028:: include('_copyright.c')
Rich Lanea06d0c32013-03-25 08:52:03 -070029
30/****************************************************************
31 *
32 * of_object.c
33 *
34 * These are the low level object constructor/destructor operators.
35 *
36 ****************************************************************/
37
38#include "loci_log.h"
39#include <loci/loci.h>
40#include <loci/loci_validator.h>
41
Rich Lanea06d0c32013-03-25 08:52:03 -070042/**
43 * Create a generic new object and possibly underlying wire buffer
44 * @param bytes The number of bytes to allocate in the underlying buffer
45 *
46 * If bytes <= 0, do not allocate a wire buffer.
47 *
48 * Note that this is an internal function. The class specific
49 * new functions should be called to properly initialize and track an
50 * OF object.
51 */
52
53of_object_t *
54of_object_new(int bytes)
55{
56 of_object_t *obj;
57
Rich Lane671e7722013-12-15 16:48:54 -080058 if ((obj = (of_object_t *)MALLOC(sizeof(*obj))) == NULL) {
Rich Lanea06d0c32013-03-25 08:52:03 -070059 return NULL;
60 }
Rich Lane671e7722013-12-15 16:48:54 -080061 MEMSET(obj, 0, sizeof(*obj));
Rich Lanea06d0c32013-03-25 08:52:03 -070062
63 if (bytes > 0) {
Rich Lanecdd542d2014-04-03 16:13:12 -070064 if ((obj->wbuf = of_wire_buffer_new(bytes)) == NULL) {
Rich Lanea06d0c32013-03-25 08:52:03 -070065 FREE(obj);
66 return NULL;
67 }
Rich Lanea06d0c32013-03-25 08:52:03 -070068 }
69
70 return obj;
71}
72
73/**
74 * The delete function for LOCI objects
75 *
76 * @param obj Pointer to the object to be deleted
77 *
78 * This can be called on any LOCI object; it should not need to be
79 * overridden.
80 */
81
82void
83of_object_delete(of_object_t *obj)
84{
85 if (obj == NULL) {
86 return;
87 }
88
Rich Lane3e431082014-04-03 16:21:30 -070089 if (obj->parent == NULL) {
Rich Lanecdd542d2014-04-03 16:13:12 -070090 of_wire_buffer_free(obj->wbuf);
Rich Lanea06d0c32013-03-25 08:52:03 -070091 }
92
93 FREE(obj);
94}
95
96/**
97 * Duplicate an object
98 * @param src The object to be duplicated
99 * @returns Pointer to the duplicate or NULL on error. Caller is responsible
100 * for freeing the returned object.
101 */
102
103of_object_t *
Rich Lanecd6ef152013-12-15 16:42:18 -0800104of_object_dup(of_object_t *src)
Rich Lanea06d0c32013-03-25 08:52:03 -0700105{
106 of_object_t *dst;
107 of_object_init_f init_fn;
108
Rich Lane671e7722013-12-15 16:48:54 -0800109 if ((dst = (of_object_t *)MALLOC(sizeof(*dst))) == NULL) {
Rich Lanea06d0c32013-03-25 08:52:03 -0700110 return NULL;
111 }
112
113 MEMSET(dst, 0, sizeof(*dst));
114
115 /* Allocate a minimal wire buffer assuming we will not write to it. */
Rich Lanecdd542d2014-04-03 16:13:12 -0700116 if ((dst->wbuf = of_wire_buffer_new(src->length)) == NULL) {
Rich Lanea06d0c32013-03-25 08:52:03 -0700117 FREE(dst);
118 return NULL;
119 }
120
Rich Lanea06d0c32013-03-25 08:52:03 -0700121 init_fn = of_object_init_map[src->object_id];
122 init_fn(dst, src->version, src->length, 0);
123
124 MEMCPY(OF_OBJECT_BUFFER_INDEX(dst, 0),
125 OF_OBJECT_BUFFER_INDEX(src, 0),
126 src->length);
127
128 return dst;
129}
130
Rich Lanea06d0c32013-03-25 08:52:03 -0700131/**
132 * Generic new from message call
133 */
134
135of_object_t *
136of_object_new_from_message(of_message_t msg, int len)
137{
138 of_object_id_t object_id;
139 of_object_t *obj;
140 of_version_t version;
141
142 version = of_message_version_get(msg);
143 if (!OF_VERSION_OKAY(version)) {
144 return NULL;
145 }
146
147 if (of_validate_message(msg, len) != 0) {
148 LOCI_LOG_ERROR("message validation failed\n");
149 return NULL;
150 }
151
Rich Lanea06d0c32013-03-25 08:52:03 -0700152 if ((obj = of_object_new(-1)) == NULL) {
153 return NULL;
154 }
155
Rich Lanea06d0c32013-03-25 08:52:03 -0700156 if (of_object_buffer_bind(obj, OF_MESSAGE_TO_BUFFER(msg), len,
157 OF_MESSAGE_FREE_FUNCTION) < 0) {
158 FREE(obj);
159 return NULL;
160 }
Rich Lanea06d0c32013-03-25 08:52:03 -0700161 obj->version = version;
162
Rich Lane76f181e2014-03-04 23:23:36 -0800163 of_header_wire_object_id_get(obj, &object_id);
164 of_object_init_map[object_id](obj, version, len, 0);
165
Rich Lanea06d0c32013-03-25 08:52:03 -0700166 return obj;
167}
168
169/**
Rich Lanec73680c2014-02-22 10:44:28 -0800170 * Parse a message without allocating memory
171 *
172 * @param storage Pointer to an uninitialized of_object_storage_t
173 * @param buf Pointer to the buffer
174 * @param length Length of buf
175 * @returns Pointer to an initialized of_object_t
176 *
177 * The lifetime of the returned object is the minimum of the lifetimes of
178 * 'buf' and 'storage'.
179 */
180
181of_object_t *
182of_object_new_from_message_preallocated(of_object_storage_t *storage,
183 uint8_t *buf, int len)
184{
185 of_object_t *obj = &storage->obj;
186 of_wire_buffer_t *wbuf = &storage->wbuf;
187 of_message_t msg = buf;
188 of_version_t version;
189 of_object_id_t object_id;
190
191 memset(storage, 0, sizeof(*storage));
192
193 version = of_message_version_get(msg);
194 if (!OF_VERSION_OKAY(version)) {
195 return NULL;
196 }
197
198 if (of_validate_message(msg, len) != 0) {
199 LOCI_LOG_ERROR("message validation failed\n");
200 return NULL;
201 }
202
Rich Lane76f181e2014-03-04 23:23:36 -0800203 obj->version = version;
Rich Lanecdd542d2014-04-03 16:13:12 -0700204 obj->wbuf = wbuf;
Rich Lanec73680c2014-02-22 10:44:28 -0800205 wbuf->buf = msg;
206 wbuf->alloc_bytes = len;
207 wbuf->current_bytes = len;
208
Rich Lane76f181e2014-03-04 23:23:36 -0800209 of_header_wire_object_id_get(obj, &object_id);
210 of_object_init_map[object_id](obj, version, len, 0);
211
Rich Lanec73680c2014-02-22 10:44:28 -0800212 return obj;
213}
214
215/**
Rich Lanea06d0c32013-03-25 08:52:03 -0700216 * Bind an existing buffer to an LOCI object
217 *
218 * @param obj Pointer to the object to be updated
219 * @param buf Pointer to the buffer to bind to obj
220 * @param bytes Length of buf
221 * @param buf_free An optional free function to be applied to
222 * buf on deallocation
223 *
224 * This can be called on any LOCI object; it should not need to be
225 * overridden.
226 */
227
228int
229of_object_buffer_bind(of_object_t *obj, uint8_t *buf, int bytes,
230 of_buffer_free_f buf_free)
231{
Rich Lanea06d0c32013-03-25 08:52:03 -0700232 of_wire_buffer_t *wbuf;
233
Rich Lanee57f0432014-02-19 10:31:53 -0800234 LOCI_ASSERT(buf != NULL);
235 LOCI_ASSERT(bytes > 0);
Rich Lanea06d0c32013-03-25 08:52:03 -0700236
237 wbuf = of_wire_buffer_new_bind(buf, bytes, buf_free);
238 if (wbuf == NULL) {
239 return OF_ERROR_RESOURCE;
240 }
241
Rich Lanecdd542d2014-04-03 16:13:12 -0700242 obj->wbuf = wbuf;
243 obj->obj_offset = 0;
Rich Lanea06d0c32013-03-25 08:52:03 -0700244 obj->length = bytes;
245
246 return OF_ERROR_NONE;
247}
248
249/**
250 * Connect a child to a parent at the wire buffer level
251 *
252 * @param parent The top level object to bind to
253 * @param child The sub-object connecting to the parent
254 * @param offset The offset at which to attach the child RELATIVE
255 * TO THE PARENT in the buffer
256 * @param bytes The amount of the buffer dedicated to the child; see below
257 * @param inc_ref_count Should the ref count of the parent be incremented
258 *
259 * This is used for 'get' accessors for composite types as well as
260 * iterator functions for lists, both read (first/next) and write
261 * (append_init, append_advance).
262 *
263 * Connect a child object to a parent by setting up the child's
264 * wire_object to point to the parent's underlying buffer. The value
265 * of the parameter bytes is important in determining how the child
266 * is initialized:
267 * @li If bytes <= 0, the length and type of the child are not modified;
268 * no additional space is added to the buffer.
269 * @li If bytes > 0, the current wire buffer is grown to
270 * accomodate this many bytes. This is to support append operations.
271 *
272 * If an error is returned, future references to the child object
273 * (until it is reinitialized) are undefined.
274 */
275static void
276object_child_attach(of_object_t *parent, of_object_t *child,
277 int offset, int bytes)
278{
Rich Lanea06d0c32013-03-25 08:52:03 -0700279 of_wire_buffer_t *wbuf; /* Pointer to common wire buffer manager */
280
281 child->parent = parent;
Rich Lanecdd542d2014-04-03 16:13:12 -0700282 wbuf = parent->wbuf;
Rich Lanea06d0c32013-03-25 08:52:03 -0700283
284 /* Set up the child's wire buf to point to same as parent */
Rich Lanecdd542d2014-04-03 16:13:12 -0700285 child->wbuf = wbuf;
286 child->obj_offset = parent->obj_offset + offset;
Rich Lanea06d0c32013-03-25 08:52:03 -0700287
288 /*
289 * bytes determines if this is a read or write setup.
290 * If > 0, grow the buffer to accomodate the space
291 * Otherwise do nothing
292 */
293 if (bytes > 0) { /* Set internal length, request buffer space */
294 int tot_bytes; /* Total bytes to request for buffer if updated */
295
296 /* Set up space for the child in the parent's buffer */
Rich Lanecdd542d2014-04-03 16:13:12 -0700297 tot_bytes = parent->obj_offset + offset + bytes;
Rich Lanea06d0c32013-03-25 08:52:03 -0700298
299 of_wire_buffer_grow(wbuf, tot_bytes);
300 child->length = bytes;
301 }
302 /* if bytes == 0 don't do anything */
303}
304
305/**
306 * Check for room in an object's wire buffer.
307 * @param obj The object being checked
308 * @param new_len The desired length
309 * @return Boolean
310 */
311
312int
313of_object_can_grow(of_object_t *obj, int new_len)
314{
315 return OF_OBJECT_ABSOLUTE_OFFSET(obj, new_len) <=
Rich Lanecdd542d2014-04-03 16:13:12 -0700316 WBUF_ALLOC_BYTES(obj->wbuf);
Rich Lanea06d0c32013-03-25 08:52:03 -0700317}
318
319/**
320 * Set the xid of a message object
321 * @param obj The object being accessed
322 * @param xid The xid value to store in the wire buffer
323 * @return OF_ERROR_
324 * Since the XID is common across all versions, this is used
325 * for all XID accessors.
326 */
327
328int
329of_object_xid_set(of_object_t *obj, uint32_t xid)
330{
331 of_wire_buffer_t *wbuf;
332
333 if ((wbuf = OF_OBJECT_TO_WBUF(obj)) == NULL) {
334 return OF_ERROR_PARAM;
335 }
336 of_wire_buffer_u32_set(wbuf,
337 OF_OBJECT_ABSOLUTE_OFFSET(obj, OF_MESSAGE_XID_OFFSET), xid);
338 return OF_ERROR_NONE;
339}
340
341/**
342 * Get the xid of a message object
343 * @param obj The object being accessed
344 * @param xid Pointer to where to store the xid value
345 * @return OF_ERROR_
346 * Since the XID is common across all versions, this is used
347 * for all XID accessors.
348 */
349
350int
351of_object_xid_get(of_object_t *obj, uint32_t *xid)
352{
353 of_wire_buffer_t *wbuf;
354
355 if ((wbuf = OF_OBJECT_TO_WBUF(obj)) == NULL) {
356 return OF_ERROR_PARAM;
357 }
358 of_wire_buffer_u32_get(wbuf,
359 OF_OBJECT_ABSOLUTE_OFFSET(obj, OF_MESSAGE_XID_OFFSET), xid);
360 return OF_ERROR_NONE;
361}
362
363/****************************************************************
364 *
365 * Generic list operation implementations
366 *
367 ****************************************************************/
368
369/**
370 * Set up a child for appending to a parent list
371 * @param parent The parent; must be a list object
372 * @param child The child object; must be of type list element
373 * @return OF_ERROR_
374 *
375 * Attaches the wire buffer of the parent to the child by pointing
376 * the child to the end of the parent.
377 *
378 * Set the wire length and type from the child.
379 * Update the parent length adding the current child length
380 *
381 * After calling this function, the child object may be updated
382 * resulting in changes to the parent's wire buffer
383 *
384 */
385
386int
387of_list_append_bind(of_object_t *parent, of_object_t *child)
388{
389 if (parent == NULL || child == NULL ||
Rich Lanecdd542d2014-04-03 16:13:12 -0700390 parent->wbuf == NULL) {
Rich Lanea06d0c32013-03-25 08:52:03 -0700391 return OF_ERROR_PARAM;
392 }
393
394 if (!of_object_can_grow(parent, parent->length + child->length)) {
395 return OF_ERROR_RESOURCE;
396 }
397
398 object_child_attach(parent, child, parent->length,
399 child->length);
400
401 /* Update the wire length and type if needed */
Rich Lanedc46fe22014-04-03 15:10:38 -0700402 of_object_wire_length_set(child, child->length);
403 of_object_wire_type_set(child);
Rich Lanea06d0c32013-03-25 08:52:03 -0700404
405 /* Update the parent's length */
406 of_object_parent_length_update(parent, child->length);
407
408 OF_LENGTH_CHECK_ASSERT(parent);
409
410 return OF_ERROR_NONE;
411}
412
413/**
414 * Generic atomic list append operation
415 * @param list The list to which an item is being appended
416 * @param item THe item to append to the list
417 *
418 * The contents of the item are copied to the end of the list.
419 * Currently assumes the list is at the end of its parent.
420 */
421int
422of_list_append(of_object_t *list, of_object_t *item)
423{
424 int new_len;
425
426 new_len = list->length + item->length;
427
428 if (!of_object_can_grow(list, new_len)) {
429 return OF_ERROR_RESOURCE;
430 }
431
Rich Lanecdd542d2014-04-03 16:13:12 -0700432 of_wire_buffer_grow(list->wbuf,
Rich Lanea06d0c32013-03-25 08:52:03 -0700433 OF_OBJECT_ABSOLUTE_OFFSET(list, new_len));
434
435 MEMCPY(OF_OBJECT_BUFFER_INDEX(list, list->length),
436 OF_OBJECT_BUFFER_INDEX(item, 0), item->length);
437
438 /* Update the list's length */
439 of_object_parent_length_update(list, item->length);
440
441 OF_LENGTH_CHECK_ASSERT(list);
442
443 return OF_ERROR_NONE;
444}
445
446/**
447 * Generic list first function
448 * @param parent The parent; must be a list object
449 * @param child The child object; must be of type list element
450 * @return OF_ERROR_RANGE if list is empty
451 * @return OF_ERROR_
452 *
453 * Sets up the child to point to the first element in the list
454 *
455 * Child init must be called before this is called.
456 *
457 * @note TREAT AS PRIVATE
458 * Does not fully initialized object
459 */
460int
461of_list_first(of_object_t *parent, of_object_t *child)
462{
463 if (parent->length == 0) { /* Empty list */
464 return OF_ERROR_RANGE;
465 }
466
467 object_child_attach(parent, child, 0, 0);
468
469 return OF_ERROR_NONE;
470}
471
472/**
473 * Return boolean indicating if child is pointing to last entry in parent
474 * @param parent The parent; must be a list object
475 * @param child The child object; must be of type list element
476 * @return OF_ERROR_RANGE if list is empty
477 * @return OF_ERROR_
478 *
479 */
480static int
481of_list_is_last(of_object_t *parent, of_object_t *child)
482{
Rich Lanecdd542d2014-04-03 16:13:12 -0700483 if (child->obj_offset + child->length >=
484 parent->obj_offset + parent->length) {
Rich Lanea06d0c32013-03-25 08:52:03 -0700485 return 1;
486 }
487
488 return 0;
489}
490
491/**
492 * Generic list next function
493 * @param parent The parent; must be a list object
494 * @param child The child object; must be of type list element
495 * @return OF_ERROR_RANGE if at end of list
496 * @return OF_ERROR_
497 *
498 * Advances the child to point to the subsequent element in the list.
499 * The wire buffer object must not have been modified since the
500 * previous call to _first or _next.
501 *
502 * @note TREAT AS PRIVATE
503 * Does not fully initialized object
504 */
505int
506of_list_next(of_object_t *parent, of_object_t *child)
507{
508 int offset;
509
Rich Lanee57f0432014-02-19 10:31:53 -0800510 LOCI_ASSERT(child->length > 0);
Rich Lanea06d0c32013-03-25 08:52:03 -0700511
512 /* Get offset of parent */
513 if (of_list_is_last(parent, child)) {
514 return OF_ERROR_RANGE; /* We were on the last object */
515 }
516
517 /* Offset is relative to parent start */
Rich Lanecdd542d2014-04-03 16:13:12 -0700518 offset = (child->obj_offset - parent->obj_offset) +
Rich Lanea06d0c32013-03-25 08:52:03 -0700519 child->length;
520 object_child_attach(parent, child, offset, 0);
521
522 return OF_ERROR_NONE;
523}
524
525void
526of_object_wire_buffer_steal(of_object_t *obj, uint8_t **buffer)
527{
Rich Lanee57f0432014-02-19 10:31:53 -0800528 LOCI_ASSERT(obj != NULL);
Rich Lanecdd542d2014-04-03 16:13:12 -0700529 of_wire_buffer_steal(obj->wbuf, buffer);
530 obj->wbuf = NULL;
Rich Lanea06d0c32013-03-25 08:52:03 -0700531}
532
Rich Lane50aa5942013-12-15 16:20:38 -0800533#define _MAX_PARENT_ITERATIONS 4
534/**
535 * Iteratively update parent lengths thru hierarchy
536 * @param obj The object whose length is being updated
537 * @param delta The difference between the current and new lengths
538 *
539 * Note that this includes updating the object itself. It will
540 * iterate thru parents.
541 *
542 * Assumes delta > 0.
543 */
544void
545of_object_parent_length_update(of_object_t *obj, int delta)
546{
547#ifndef NDEBUG
548 int count = 0;
549 of_wire_buffer_t *wbuf; /* For debug asserts only */
550#endif
551
552 while (obj != NULL) {
Rich Lanee57f0432014-02-19 10:31:53 -0800553 LOCI_ASSERT(count++ < _MAX_PARENT_ITERATIONS);
Rich Lane50aa5942013-12-15 16:20:38 -0800554 obj->length += delta;
Rich Lanedc46fe22014-04-03 15:10:38 -0700555 of_object_wire_length_set(obj, obj->length);
Rich Lane50aa5942013-12-15 16:20:38 -0800556#ifndef NDEBUG
Rich Lanecdd542d2014-04-03 16:13:12 -0700557 wbuf = obj->wbuf;
Rich Lane50aa5942013-12-15 16:20:38 -0800558#endif
559
560 /* Asserts for wire length checking */
Rich Lanecdd542d2014-04-03 16:13:12 -0700561 LOCI_ASSERT(obj->length + obj->obj_offset <=
Rich Lane50aa5942013-12-15 16:20:38 -0800562 WBUF_CURRENT_BYTES(wbuf));
563 if (obj->parent == NULL) {
Rich Lanecdd542d2014-04-03 16:13:12 -0700564 LOCI_ASSERT(obj->length + obj->obj_offset ==
Rich Lane50aa5942013-12-15 16:20:38 -0800565 WBUF_CURRENT_BYTES(wbuf));
566 }
567
568 obj = obj->parent;
569 }
570}
571
Rich Lanec0e20ff2013-12-15 23:40:31 -0800572/**
573 * Use the type/length from the wire buffer and init the object
574 * @param obj The object being initialized
575 * @param base_object_id If > 0, this indicates the base object
576 * @param max_len If > 0, the max length to expect for the obj
577 * type for inheritance checking
578 * @return OF_ERROR_
579 *
580 * Used for inheritance type objects such as actions and OXMs
581 * The type is checked and if valid, the object is initialized.
582 * Then the length is taken from the buffer.
583 *
584 * Note that the object version must already be properly set.
585 */
586int
587of_object_wire_init(of_object_t *obj, of_object_id_t base_object_id,
588 int max_len)
589{
Rich Lanedc46fe22014-04-03 15:10:38 -0700590 if (loci_class_metadata[obj->object_id].wire_type_get != NULL) {
Rich Lanec0e20ff2013-12-15 23:40:31 -0800591 of_object_id_t id;
Rich Lanedc46fe22014-04-03 15:10:38 -0700592 loci_class_metadata[obj->object_id].wire_type_get(obj, &id);
Rich Lanec0e20ff2013-12-15 23:40:31 -0800593 if (!of_wire_id_valid(id, base_object_id)) {
594 return OF_ERROR_PARSE;
595 }
596 obj->object_id = id;
597 /* Call the init function for this object type; do not push to wire */
598 of_object_init_map[id]((of_object_t *)(obj), obj->version, -1, 0);
599 }
Rich Lanedc46fe22014-04-03 15:10:38 -0700600 if (loci_class_metadata[obj->object_id].wire_length_get != NULL) {
Rich Lanec0e20ff2013-12-15 23:40:31 -0800601 int length;
Rich Lanedc46fe22014-04-03 15:10:38 -0700602 loci_class_metadata[obj->object_id].wire_length_get(obj, &length);
Rich Lanec0e20ff2013-12-15 23:40:31 -0800603 if (length < 0 || (max_len > 0 && length > max_len)) {
604 return OF_ERROR_PARSE;
605 }
606 obj->length = length;
607 } else {
608 /* @fixme Does this cover everything else? */
609 obj->length = of_object_fixed_len[obj->version][base_object_id];
610 }
611
612 return OF_ERROR_NONE;
613}
614
Rich Lanea06d0c32013-03-25 08:52:03 -0700615/*
616 * Set member:
617 * get_wbuf_extent
618 * find offset of start of member
619 * if offset is at wbuf_extent (append new data)
620 * copy data at extent
621 * update parent length
622 * else
623 * find length of current entry
624 * move from end of current to extent to create (or remove) space
625 * copy data to offset
626 * update my length -- NEED LOCAL INFO TO DO THIS for some cases
627 */
628
629/* Also need: get offset of member for all combinations */
630/* Also need: get length of member for all combinations */
631#if 0
632/**
633 * Append the wire buffer data from src to the end of dst's wire buffer
634 */
635int
636of_object_append_buffer(of_object_t *dst, of_object_t *src)
637{
638 of_wire_buffer_t *s_wbuf, *d_wbuf;
639 int orig_len, dst_offset, src_offset;
640
641 d_wbuf = OF_OBJECT_TO_WBUF(dst);
642 s_wbuf = OF_OBJECT_TO_WBUF(src);
Rich Lanecdd542d2014-04-03 16:13:12 -0700643 dst_offset = dst->obj_offset + dst_length;
644 src_offset = src->obj_offset;
Rich Lanea06d0c32013-03-25 08:52:03 -0700645 OF_WIRE_BUFFER_INIT_CHECK(d_wbuf, dst_offset + src->length);
646 MEMCPY(OF_WBUF_BUFFER_POINTER(d_wbuf, dst_offset),
647 OF_WBUF_BUFFER_POINTER(s_wbuf, 0), src->length);
648
649 orig_len = dst->length;
650 dst->length += src->length;
651
652 return OF_ERROR_NONE;
653}
654
655/**
656 * Set the length of the actions object in a packet_in object
657 */
658
659int
660of_packet_out_actions_length_set(of_packet_t *obj, int len)
661{
662 if (obj == NULL || obj->object_id != OF_PACKET_IN ||
Rich Lanecdd542d2014-04-03 16:13:12 -0700663 obj->wbuf == NULL) {
Rich Lanea06d0c32013-03-25 08:52:03 -0700664 return OF_ERROR_PARAM;
665 }
666
667 obj->actions_len_set(obj, len);
668}
669
670int
671_packet_out_data_offset_get(of_packet_t *obj)
672{
673 if (obj == NULL || obj->object_id != OF_PACKET_IN ||
Rich Lanecdd542d2014-04-03 16:13:12 -0700674 obj->wbuf == NULL) {
Rich Lanea06d0c32013-03-25 08:52:03 -0700675 return -1;
676 }
677
678 return OF_PACKET_OUT_FIXED_LENGTH + _packet_out_actions_length_get(obj);
679}
680
681
682/**
683 * Simple length derivation function
684 *
685 * Most variable length fields are alone at the end of a structure.
686 * Their length is a simple calculation, just the total length of
687 * the parent minus the length of the non-variable part of the
688 * parent's class type.
689 *
690 * @param parent The parent object
691 * @param length (out) Where to store the length of the final
692 * variable length member
693 */
694int
695of_object_simple_length_derive(of_object_t *obj, int *length)
696{
697
698}
699#endif