blob: feb447a6f48a1d769ab979f81df1840b48e68a40 [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 Lanecdd542d2014-04-03 16:13:12 -070068 obj->owned = 1;
Rich Lanea06d0c32013-03-25 08:52:03 -070069 }
70
71 return obj;
72}
73
74/**
75 * The delete function for LOCI objects
76 *
77 * @param obj Pointer to the object to be deleted
78 *
79 * This can be called on any LOCI object; it should not need to be
80 * overridden.
81 */
82
83void
84of_object_delete(of_object_t *obj)
85{
86 if (obj == NULL) {
87 return;
88 }
89
Rich Lanecdd542d2014-04-03 16:13:12 -070090 if (obj->owned) {
91 of_wire_buffer_free(obj->wbuf);
Rich Lanea06d0c32013-03-25 08:52:03 -070092 }
93
94 FREE(obj);
95}
96
97/**
98 * Duplicate an object
99 * @param src The object to be duplicated
100 * @returns Pointer to the duplicate or NULL on error. Caller is responsible
101 * for freeing the returned object.
102 */
103
104of_object_t *
Rich Lanecd6ef152013-12-15 16:42:18 -0800105of_object_dup(of_object_t *src)
Rich Lanea06d0c32013-03-25 08:52:03 -0700106{
107 of_object_t *dst;
108 of_object_init_f init_fn;
109
Rich Lane671e7722013-12-15 16:48:54 -0800110 if ((dst = (of_object_t *)MALLOC(sizeof(*dst))) == NULL) {
Rich Lanea06d0c32013-03-25 08:52:03 -0700111 return NULL;
112 }
113
114 MEMSET(dst, 0, sizeof(*dst));
115
116 /* Allocate a minimal wire buffer assuming we will not write to it. */
Rich Lanecdd542d2014-04-03 16:13:12 -0700117 if ((dst->wbuf = of_wire_buffer_new(src->length)) == NULL) {
Rich Lanea06d0c32013-03-25 08:52:03 -0700118 FREE(dst);
119 return NULL;
120 }
121
Rich Lanecdd542d2014-04-03 16:13:12 -0700122 dst->owned = 1;
Rich Lanea06d0c32013-03-25 08:52:03 -0700123
124 init_fn = of_object_init_map[src->object_id];
125 init_fn(dst, src->version, src->length, 0);
126
127 MEMCPY(OF_OBJECT_BUFFER_INDEX(dst, 0),
128 OF_OBJECT_BUFFER_INDEX(src, 0),
129 src->length);
130
131 return dst;
132}
133
Rich Lanea06d0c32013-03-25 08:52:03 -0700134/**
135 * Generic new from message call
136 */
137
138of_object_t *
139of_object_new_from_message(of_message_t msg, int len)
140{
141 of_object_id_t object_id;
142 of_object_t *obj;
143 of_version_t version;
144
145 version = of_message_version_get(msg);
146 if (!OF_VERSION_OKAY(version)) {
147 return NULL;
148 }
149
150 if (of_validate_message(msg, len) != 0) {
151 LOCI_LOG_ERROR("message validation failed\n");
152 return NULL;
153 }
154
Rich Lanea06d0c32013-03-25 08:52:03 -0700155 if ((obj = of_object_new(-1)) == NULL) {
156 return NULL;
157 }
158
Rich Lanea06d0c32013-03-25 08:52:03 -0700159 if (of_object_buffer_bind(obj, OF_MESSAGE_TO_BUFFER(msg), len,
160 OF_MESSAGE_FREE_FUNCTION) < 0) {
161 FREE(obj);
162 return NULL;
163 }
Rich Lanea06d0c32013-03-25 08:52:03 -0700164 obj->version = version;
165
Rich Lane76f181e2014-03-04 23:23:36 -0800166 of_header_wire_object_id_get(obj, &object_id);
167 of_object_init_map[object_id](obj, version, len, 0);
168
Rich Lanea06d0c32013-03-25 08:52:03 -0700169 return obj;
170}
171
172/**
Rich Lanec73680c2014-02-22 10:44:28 -0800173 * Parse a message without allocating memory
174 *
175 * @param storage Pointer to an uninitialized of_object_storage_t
176 * @param buf Pointer to the buffer
177 * @param length Length of buf
178 * @returns Pointer to an initialized of_object_t
179 *
180 * The lifetime of the returned object is the minimum of the lifetimes of
181 * 'buf' and 'storage'.
182 */
183
184of_object_t *
185of_object_new_from_message_preallocated(of_object_storage_t *storage,
186 uint8_t *buf, int len)
187{
188 of_object_t *obj = &storage->obj;
189 of_wire_buffer_t *wbuf = &storage->wbuf;
190 of_message_t msg = buf;
191 of_version_t version;
192 of_object_id_t object_id;
193
194 memset(storage, 0, sizeof(*storage));
195
196 version = of_message_version_get(msg);
197 if (!OF_VERSION_OKAY(version)) {
198 return NULL;
199 }
200
201 if (of_validate_message(msg, len) != 0) {
202 LOCI_LOG_ERROR("message validation failed\n");
203 return NULL;
204 }
205
Rich Lane76f181e2014-03-04 23:23:36 -0800206 obj->version = version;
Rich Lanecdd542d2014-04-03 16:13:12 -0700207 obj->wbuf = wbuf;
Rich Lanec73680c2014-02-22 10:44:28 -0800208 wbuf->buf = msg;
209 wbuf->alloc_bytes = len;
210 wbuf->current_bytes = len;
211
Rich Lane76f181e2014-03-04 23:23:36 -0800212 of_header_wire_object_id_get(obj, &object_id);
213 of_object_init_map[object_id](obj, version, len, 0);
214
Rich Lanec73680c2014-02-22 10:44:28 -0800215 return obj;
216}
217
218/**
Rich Lanea06d0c32013-03-25 08:52:03 -0700219 * Bind an existing buffer to an LOCI object
220 *
221 * @param obj Pointer to the object to be updated
222 * @param buf Pointer to the buffer to bind to obj
223 * @param bytes Length of buf
224 * @param buf_free An optional free function to be applied to
225 * buf on deallocation
226 *
227 * This can be called on any LOCI object; it should not need to be
228 * overridden.
229 */
230
231int
232of_object_buffer_bind(of_object_t *obj, uint8_t *buf, int bytes,
233 of_buffer_free_f buf_free)
234{
Rich Lanea06d0c32013-03-25 08:52:03 -0700235 of_wire_buffer_t *wbuf;
236
Rich Lanee57f0432014-02-19 10:31:53 -0800237 LOCI_ASSERT(buf != NULL);
238 LOCI_ASSERT(bytes > 0);
Rich Lanea06d0c32013-03-25 08:52:03 -0700239
240 wbuf = of_wire_buffer_new_bind(buf, bytes, buf_free);
241 if (wbuf == NULL) {
242 return OF_ERROR_RESOURCE;
243 }
244
Rich Lanecdd542d2014-04-03 16:13:12 -0700245 obj->wbuf = wbuf;
246 obj->obj_offset = 0;
247 obj->owned = 1;
Rich Lanea06d0c32013-03-25 08:52:03 -0700248 obj->length = bytes;
249
250 return OF_ERROR_NONE;
251}
252
253/**
254 * Connect a child to a parent at the wire buffer level
255 *
256 * @param parent The top level object to bind to
257 * @param child The sub-object connecting to the parent
258 * @param offset The offset at which to attach the child RELATIVE
259 * TO THE PARENT in the buffer
260 * @param bytes The amount of the buffer dedicated to the child; see below
261 * @param inc_ref_count Should the ref count of the parent be incremented
262 *
263 * This is used for 'get' accessors for composite types as well as
264 * iterator functions for lists, both read (first/next) and write
265 * (append_init, append_advance).
266 *
267 * Connect a child object to a parent by setting up the child's
268 * wire_object to point to the parent's underlying buffer. The value
269 * of the parameter bytes is important in determining how the child
270 * is initialized:
271 * @li If bytes <= 0, the length and type of the child are not modified;
272 * no additional space is added to the buffer.
273 * @li If bytes > 0, the current wire buffer is grown to
274 * accomodate this many bytes. This is to support append operations.
275 *
276 * If an error is returned, future references to the child object
277 * (until it is reinitialized) are undefined.
278 */
279static void
280object_child_attach(of_object_t *parent, of_object_t *child,
281 int offset, int bytes)
282{
Rich Lanea06d0c32013-03-25 08:52:03 -0700283 of_wire_buffer_t *wbuf; /* Pointer to common wire buffer manager */
284
285 child->parent = parent;
Rich Lanecdd542d2014-04-03 16:13:12 -0700286 wbuf = parent->wbuf;
Rich Lanea06d0c32013-03-25 08:52:03 -0700287
288 /* Set up the child's wire buf to point to same as parent */
Rich Lanecdd542d2014-04-03 16:13:12 -0700289 child->wbuf = wbuf;
290 child->obj_offset = parent->obj_offset + offset;
291 child->owned = 0;
Rich Lanea06d0c32013-03-25 08:52:03 -0700292
293 /*
294 * bytes determines if this is a read or write setup.
295 * If > 0, grow the buffer to accomodate the space
296 * Otherwise do nothing
297 */
298 if (bytes > 0) { /* Set internal length, request buffer space */
299 int tot_bytes; /* Total bytes to request for buffer if updated */
300
301 /* Set up space for the child in the parent's buffer */
Rich Lanecdd542d2014-04-03 16:13:12 -0700302 tot_bytes = parent->obj_offset + offset + bytes;
Rich Lanea06d0c32013-03-25 08:52:03 -0700303
304 of_wire_buffer_grow(wbuf, tot_bytes);
305 child->length = bytes;
306 }
307 /* if bytes == 0 don't do anything */
308}
309
310/**
311 * Check for room in an object's wire buffer.
312 * @param obj The object being checked
313 * @param new_len The desired length
314 * @return Boolean
315 */
316
317int
318of_object_can_grow(of_object_t *obj, int new_len)
319{
320 return OF_OBJECT_ABSOLUTE_OFFSET(obj, new_len) <=
Rich Lanecdd542d2014-04-03 16:13:12 -0700321 WBUF_ALLOC_BYTES(obj->wbuf);
Rich Lanea06d0c32013-03-25 08:52:03 -0700322}
323
324/**
325 * Set the xid of a message object
326 * @param obj The object being accessed
327 * @param xid The xid value to store in the wire buffer
328 * @return OF_ERROR_
329 * Since the XID is common across all versions, this is used
330 * for all XID accessors.
331 */
332
333int
334of_object_xid_set(of_object_t *obj, uint32_t xid)
335{
336 of_wire_buffer_t *wbuf;
337
338 if ((wbuf = OF_OBJECT_TO_WBUF(obj)) == NULL) {
339 return OF_ERROR_PARAM;
340 }
341 of_wire_buffer_u32_set(wbuf,
342 OF_OBJECT_ABSOLUTE_OFFSET(obj, OF_MESSAGE_XID_OFFSET), xid);
343 return OF_ERROR_NONE;
344}
345
346/**
347 * Get the xid of a message object
348 * @param obj The object being accessed
349 * @param xid Pointer to where to store the xid value
350 * @return OF_ERROR_
351 * Since the XID is common across all versions, this is used
352 * for all XID accessors.
353 */
354
355int
356of_object_xid_get(of_object_t *obj, uint32_t *xid)
357{
358 of_wire_buffer_t *wbuf;
359
360 if ((wbuf = OF_OBJECT_TO_WBUF(obj)) == NULL) {
361 return OF_ERROR_PARAM;
362 }
363 of_wire_buffer_u32_get(wbuf,
364 OF_OBJECT_ABSOLUTE_OFFSET(obj, OF_MESSAGE_XID_OFFSET), xid);
365 return OF_ERROR_NONE;
366}
367
368/****************************************************************
369 *
370 * Generic list operation implementations
371 *
372 ****************************************************************/
373
374/**
375 * Set up a child for appending to a parent list
376 * @param parent The parent; must be a list object
377 * @param child The child object; must be of type list element
378 * @return OF_ERROR_
379 *
380 * Attaches the wire buffer of the parent to the child by pointing
381 * the child to the end of the parent.
382 *
383 * Set the wire length and type from the child.
384 * Update the parent length adding the current child length
385 *
386 * After calling this function, the child object may be updated
387 * resulting in changes to the parent's wire buffer
388 *
389 */
390
391int
392of_list_append_bind(of_object_t *parent, of_object_t *child)
393{
394 if (parent == NULL || child == NULL ||
Rich Lanecdd542d2014-04-03 16:13:12 -0700395 parent->wbuf == NULL) {
Rich Lanea06d0c32013-03-25 08:52:03 -0700396 return OF_ERROR_PARAM;
397 }
398
399 if (!of_object_can_grow(parent, parent->length + child->length)) {
400 return OF_ERROR_RESOURCE;
401 }
402
403 object_child_attach(parent, child, parent->length,
404 child->length);
405
406 /* Update the wire length and type if needed */
Rich Lanedc46fe22014-04-03 15:10:38 -0700407 of_object_wire_length_set(child, child->length);
408 of_object_wire_type_set(child);
Rich Lanea06d0c32013-03-25 08:52:03 -0700409
410 /* Update the parent's length */
411 of_object_parent_length_update(parent, child->length);
412
413 OF_LENGTH_CHECK_ASSERT(parent);
414
415 return OF_ERROR_NONE;
416}
417
418/**
419 * Generic atomic list append operation
420 * @param list The list to which an item is being appended
421 * @param item THe item to append to the list
422 *
423 * The contents of the item are copied to the end of the list.
424 * Currently assumes the list is at the end of its parent.
425 */
426int
427of_list_append(of_object_t *list, of_object_t *item)
428{
429 int new_len;
430
431 new_len = list->length + item->length;
432
433 if (!of_object_can_grow(list, new_len)) {
434 return OF_ERROR_RESOURCE;
435 }
436
Rich Lanecdd542d2014-04-03 16:13:12 -0700437 of_wire_buffer_grow(list->wbuf,
Rich Lanea06d0c32013-03-25 08:52:03 -0700438 OF_OBJECT_ABSOLUTE_OFFSET(list, new_len));
439
440 MEMCPY(OF_OBJECT_BUFFER_INDEX(list, list->length),
441 OF_OBJECT_BUFFER_INDEX(item, 0), item->length);
442
443 /* Update the list's length */
444 of_object_parent_length_update(list, item->length);
445
446 OF_LENGTH_CHECK_ASSERT(list);
447
448 return OF_ERROR_NONE;
449}
450
451/**
452 * Generic list first function
453 * @param parent The parent; must be a list object
454 * @param child The child object; must be of type list element
455 * @return OF_ERROR_RANGE if list is empty
456 * @return OF_ERROR_
457 *
458 * Sets up the child to point to the first element in the list
459 *
460 * Child init must be called before this is called.
461 *
462 * @note TREAT AS PRIVATE
463 * Does not fully initialized object
464 */
465int
466of_list_first(of_object_t *parent, of_object_t *child)
467{
468 if (parent->length == 0) { /* Empty list */
469 return OF_ERROR_RANGE;
470 }
471
472 object_child_attach(parent, child, 0, 0);
473
474 return OF_ERROR_NONE;
475}
476
477/**
478 * Return boolean indicating if child is pointing to last entry in parent
479 * @param parent The parent; must be a list object
480 * @param child The child object; must be of type list element
481 * @return OF_ERROR_RANGE if list is empty
482 * @return OF_ERROR_
483 *
484 */
485static int
486of_list_is_last(of_object_t *parent, of_object_t *child)
487{
Rich Lanecdd542d2014-04-03 16:13:12 -0700488 if (child->obj_offset + child->length >=
489 parent->obj_offset + parent->length) {
Rich Lanea06d0c32013-03-25 08:52:03 -0700490 return 1;
491 }
492
493 return 0;
494}
495
496/**
497 * Generic list next function
498 * @param parent The parent; must be a list object
499 * @param child The child object; must be of type list element
500 * @return OF_ERROR_RANGE if at end of list
501 * @return OF_ERROR_
502 *
503 * Advances the child to point to the subsequent element in the list.
504 * The wire buffer object must not have been modified since the
505 * previous call to _first or _next.
506 *
507 * @note TREAT AS PRIVATE
508 * Does not fully initialized object
509 */
510int
511of_list_next(of_object_t *parent, of_object_t *child)
512{
513 int offset;
514
Rich Lanee57f0432014-02-19 10:31:53 -0800515 LOCI_ASSERT(child->length > 0);
Rich Lanea06d0c32013-03-25 08:52:03 -0700516
517 /* Get offset of parent */
518 if (of_list_is_last(parent, child)) {
519 return OF_ERROR_RANGE; /* We were on the last object */
520 }
521
522 /* Offset is relative to parent start */
Rich Lanecdd542d2014-04-03 16:13:12 -0700523 offset = (child->obj_offset - parent->obj_offset) +
Rich Lanea06d0c32013-03-25 08:52:03 -0700524 child->length;
525 object_child_attach(parent, child, offset, 0);
526
527 return OF_ERROR_NONE;
528}
529
530void
531of_object_wire_buffer_steal(of_object_t *obj, uint8_t **buffer)
532{
Rich Lanee57f0432014-02-19 10:31:53 -0800533 LOCI_ASSERT(obj != NULL);
Rich Lanecdd542d2014-04-03 16:13:12 -0700534 of_wire_buffer_steal(obj->wbuf, buffer);
535 obj->wbuf = NULL;
Rich Lanea06d0c32013-03-25 08:52:03 -0700536}
537
Rich Lane50aa5942013-12-15 16:20:38 -0800538#define _MAX_PARENT_ITERATIONS 4
539/**
540 * Iteratively update parent lengths thru hierarchy
541 * @param obj The object whose length is being updated
542 * @param delta The difference between the current and new lengths
543 *
544 * Note that this includes updating the object itself. It will
545 * iterate thru parents.
546 *
547 * Assumes delta > 0.
548 */
549void
550of_object_parent_length_update(of_object_t *obj, int delta)
551{
552#ifndef NDEBUG
553 int count = 0;
554 of_wire_buffer_t *wbuf; /* For debug asserts only */
555#endif
556
557 while (obj != NULL) {
Rich Lanee57f0432014-02-19 10:31:53 -0800558 LOCI_ASSERT(count++ < _MAX_PARENT_ITERATIONS);
Rich Lane50aa5942013-12-15 16:20:38 -0800559 obj->length += delta;
Rich Lanedc46fe22014-04-03 15:10:38 -0700560 of_object_wire_length_set(obj, obj->length);
Rich Lane50aa5942013-12-15 16:20:38 -0800561#ifndef NDEBUG
Rich Lanecdd542d2014-04-03 16:13:12 -0700562 wbuf = obj->wbuf;
Rich Lane50aa5942013-12-15 16:20:38 -0800563#endif
564
565 /* Asserts for wire length checking */
Rich Lanecdd542d2014-04-03 16:13:12 -0700566 LOCI_ASSERT(obj->length + obj->obj_offset <=
Rich Lane50aa5942013-12-15 16:20:38 -0800567 WBUF_CURRENT_BYTES(wbuf));
568 if (obj->parent == NULL) {
Rich Lanecdd542d2014-04-03 16:13:12 -0700569 LOCI_ASSERT(obj->length + obj->obj_offset ==
Rich Lane50aa5942013-12-15 16:20:38 -0800570 WBUF_CURRENT_BYTES(wbuf));
571 }
572
573 obj = obj->parent;
574 }
575}
576
Rich Lanec0e20ff2013-12-15 23:40:31 -0800577/**
578 * Use the type/length from the wire buffer and init the object
579 * @param obj The object being initialized
580 * @param base_object_id If > 0, this indicates the base object
581 * @param max_len If > 0, the max length to expect for the obj
582 * type for inheritance checking
583 * @return OF_ERROR_
584 *
585 * Used for inheritance type objects such as actions and OXMs
586 * The type is checked and if valid, the object is initialized.
587 * Then the length is taken from the buffer.
588 *
589 * Note that the object version must already be properly set.
590 */
591int
592of_object_wire_init(of_object_t *obj, of_object_id_t base_object_id,
593 int max_len)
594{
Rich Lanedc46fe22014-04-03 15:10:38 -0700595 if (loci_class_metadata[obj->object_id].wire_type_get != NULL) {
Rich Lanec0e20ff2013-12-15 23:40:31 -0800596 of_object_id_t id;
Rich Lanedc46fe22014-04-03 15:10:38 -0700597 loci_class_metadata[obj->object_id].wire_type_get(obj, &id);
Rich Lanec0e20ff2013-12-15 23:40:31 -0800598 if (!of_wire_id_valid(id, base_object_id)) {
599 return OF_ERROR_PARSE;
600 }
601 obj->object_id = id;
602 /* Call the init function for this object type; do not push to wire */
603 of_object_init_map[id]((of_object_t *)(obj), obj->version, -1, 0);
604 }
Rich Lanedc46fe22014-04-03 15:10:38 -0700605 if (loci_class_metadata[obj->object_id].wire_length_get != NULL) {
Rich Lanec0e20ff2013-12-15 23:40:31 -0800606 int length;
Rich Lanedc46fe22014-04-03 15:10:38 -0700607 loci_class_metadata[obj->object_id].wire_length_get(obj, &length);
Rich Lanec0e20ff2013-12-15 23:40:31 -0800608 if (length < 0 || (max_len > 0 && length > max_len)) {
609 return OF_ERROR_PARSE;
610 }
611 obj->length = length;
612 } else {
613 /* @fixme Does this cover everything else? */
614 obj->length = of_object_fixed_len[obj->version][base_object_id];
615 }
616
617 return OF_ERROR_NONE;
618}
619
Rich Lanea06d0c32013-03-25 08:52:03 -0700620/*
621 * Set member:
622 * get_wbuf_extent
623 * find offset of start of member
624 * if offset is at wbuf_extent (append new data)
625 * copy data at extent
626 * update parent length
627 * else
628 * find length of current entry
629 * move from end of current to extent to create (or remove) space
630 * copy data to offset
631 * update my length -- NEED LOCAL INFO TO DO THIS for some cases
632 */
633
634/* Also need: get offset of member for all combinations */
635/* Also need: get length of member for all combinations */
636#if 0
637/**
638 * Append the wire buffer data from src to the end of dst's wire buffer
639 */
640int
641of_object_append_buffer(of_object_t *dst, of_object_t *src)
642{
643 of_wire_buffer_t *s_wbuf, *d_wbuf;
644 int orig_len, dst_offset, src_offset;
645
646 d_wbuf = OF_OBJECT_TO_WBUF(dst);
647 s_wbuf = OF_OBJECT_TO_WBUF(src);
Rich Lanecdd542d2014-04-03 16:13:12 -0700648 dst_offset = dst->obj_offset + dst_length;
649 src_offset = src->obj_offset;
Rich Lanea06d0c32013-03-25 08:52:03 -0700650 OF_WIRE_BUFFER_INIT_CHECK(d_wbuf, dst_offset + src->length);
651 MEMCPY(OF_WBUF_BUFFER_POINTER(d_wbuf, dst_offset),
652 OF_WBUF_BUFFER_POINTER(s_wbuf, 0), src->length);
653
654 orig_len = dst->length;
655 dst->length += src->length;
656
657 return OF_ERROR_NONE;
658}
659
660/**
661 * Set the length of the actions object in a packet_in object
662 */
663
664int
665of_packet_out_actions_length_set(of_packet_t *obj, int len)
666{
667 if (obj == NULL || obj->object_id != OF_PACKET_IN ||
Rich Lanecdd542d2014-04-03 16:13:12 -0700668 obj->wbuf == NULL) {
Rich Lanea06d0c32013-03-25 08:52:03 -0700669 return OF_ERROR_PARAM;
670 }
671
672 obj->actions_len_set(obj, len);
673}
674
675int
676_packet_out_data_offset_get(of_packet_t *obj)
677{
678 if (obj == NULL || obj->object_id != OF_PACKET_IN ||
Rich Lanecdd542d2014-04-03 16:13:12 -0700679 obj->wbuf == NULL) {
Rich Lanea06d0c32013-03-25 08:52:03 -0700680 return -1;
681 }
682
683 return OF_PACKET_OUT_FIXED_LENGTH + _packet_out_actions_length_get(obj);
684}
685
686
687/**
688 * Simple length derivation function
689 *
690 * Most variable length fields are alone at the end of a structure.
691 * Their length is a simple calculation, just the total length of
692 * the parent minus the length of the non-variable part of the
693 * parent's class type.
694 *
695 * @param parent The parent object
696 * @param length (out) Where to store the length of the final
697 * variable length member
698 */
699int
700of_object_simple_length_derive(of_object_t *obj, int *length)
701{
702
703}
704#endif