Add managed olsr packet sockets
authorHenning Rogge <henning.rogge@fkie.fraunhofer.de>
Fri, 16 Mar 2012 13:29:35 +0000 (14:29 +0100)
committerHenning Rogge <henning.rogge@fkie.fraunhofer.de>
Fri, 16 Mar 2012 13:29:35 +0000 (14:29 +0100)
Some fixes and optimizations for pbb api

13 files changed:
CMake.config
config.txt
src-api/core/olsr_packet_socket.c
src-api/core/olsr_packet_socket.h
src-api/core/olsr_stream_socket.c
src-api/core/olsr_stream_socket.h
src-api/packetbb/CMakeLists.txt
src-api/packetbb/pbb_context.c [new file with mode: 0644]
src-api/packetbb/pbb_context.h
src-api/packetbb/pbb_reader.c
src-api/packetbb/pbb_reader.h
tests/packetbb/test_packetbb_reader_blockcb.c
tests/packetbb/test_packetbb_reader_dropcontext.c

index 76385c8..92451cc 100644 (file)
@@ -45,18 +45,14 @@ set (OONF_STATIC_PLUGINS cfgparser_compact cfgio_file remotecontrol httptelnet)
 set (OONF_FRAMEWORD_DYNAMIC false)
 
 # set to true to stop application running without root privileges (true/false)
-set (OONF_NEED_ROOT true)
+set (OONF_NEED_ROOT false)
 
 # set to true if the application needs to set ip routes for traffic forwarding
-set (OONF_NEED_ROUTING true)
+set (OONF_NEED_ROUTING false)
 
 # set to true to link packetbb API to application
 set (OONF_NEED_PACKETBB true)
 
-# set port for packetbb scheduler
-# (default should be 269 according to RFC 5498)
-set (OONF_PACKETBB_PORT 269)
-
 ####################################
 #### PacketBB API configuration ####
 ####################################
index d42de80..c868d94 100644 (file)
@@ -29,3 +29,6 @@
 [nl80211]
        if           wlan0
        interval     3.0
+
+[dlep]
+
index 65793f0..c7c5246 100644 (file)
@@ -46,8 +46,9 @@
 #include "common/list.h"
 #include "common/autobuf.h"
 #include "common/netaddr.h"
-#include "olsr_logging.h"
 #include "os_net.h"
+#include "olsr_cfg.h"
+#include "olsr_logging.h"
 #include "olsr_packet_socket.h"
 #include "olsr.h"
 
@@ -57,6 +58,9 @@ static char input_buffer[65536];
 /* remember if initialized or not */
 OLSR_SUBSYSTEM_STATE(_packet_state);
 
+static int _apply_managed_socket(struct olsr_packet_managed *managed,
+    struct olsr_packet_socket *stream,
+    struct netaddr *bindto, uint16_t port);
 static void _cb_packet_event(int fd, void *data, bool r, bool w);
 
 /**
@@ -83,13 +87,13 @@ olsr_packet_cleanup(void) {
   while (!list_is_empty(&packet_sockets)) {
     skt = list_first_element(&packet_sockets, skt, node);
 
-    olsr_packet_remove(skt);
+    olsr_packet_remove(skt, true);
   }
 }
 
 /**
  * Add a new packet socket handler
- * @param pktsocket pointer to uninitialized packet socket struct
+ * @param pktsocket pointer to an initialized packet socket struct
  * @param local pointer local IP address of packet socket
  * @return -1 if an error happened, 0 otherwise
  */
@@ -98,8 +102,6 @@ olsr_packet_add(struct olsr_packet_socket *pktsocket,
     union netaddr_socket *local) {
   int s = -1;
 
-  memset(pktsocket, 0, sizeof(*pktsocket));
-
   /* Init socket */
   s = os_net_getsocket(local, OS_SOCKET_UDP | OS_SOCKET_MULTICAST, 0, LOG_SOCKET_PACKET);
   if (s < 0) {
@@ -109,7 +111,7 @@ olsr_packet_add(struct olsr_packet_socket *pktsocket,
   pktsocket->scheduler_entry.fd = s;
   pktsocket->scheduler_entry.process = _cb_packet_event;
   pktsocket->scheduler_entry.event_read = true;
-  pktsocket->scheduler_entry.event_write = true;
+  pktsocket->scheduler_entry.event_write = false;
   pktsocket->scheduler_entry.data = pktsocket;
 
   olsr_socket_add(&pktsocket->scheduler_entry);
@@ -118,8 +120,10 @@ olsr_packet_add(struct olsr_packet_socket *pktsocket,
   list_add_tail(&packet_sockets, &pktsocket->node);
   memcpy(&pktsocket->local_socket, local, sizeof(pktsocket->local_socket));
 
-  pktsocket->input_buffer = input_buffer;
-  pktsocket->input_buffer_length = sizeof(input_buffer);
+  if (pktsocket->config.input_buffer_length == 0) {
+    pktsocket->config.input_buffer = input_buffer;
+    pktsocket->config.input_buffer_length = sizeof(input_buffer);
+  }
   return 0;
 }
 
@@ -128,13 +132,14 @@ olsr_packet_add(struct olsr_packet_socket *pktsocket,
  * @param pktsocket pointer to packet socket
  */
 void
-olsr_packet_remove(struct olsr_packet_socket *pktsocket) {
+olsr_packet_remove(struct olsr_packet_socket *pktsocket,
+    bool force __attribute__((unused))) {
   if (list_is_node_added(&pktsocket->node)) {
     olsr_socket_remove(&pktsocket->scheduler_entry);
     os_close(pktsocket->scheduler_entry.fd);
-    list_remove(&pktsocket->node);
-
     abuf_free(&pktsocket->out);
+
+    list_remove(&pktsocket->node);
   }
 }
 
@@ -184,6 +189,87 @@ olsr_packet_send(struct olsr_packet_socket *pktsocket, union netaddr_socket *rem
   return 0;
 }
 
+void
+olsr_packet_add_managed(struct olsr_packet_managed *managed) {
+  if (managed->config.input_buffer_length == 0) {
+    managed->config.input_buffer = input_buffer;
+    managed->config.input_buffer_length = sizeof(input_buffer);
+  }
+}
+
+void
+olsr_packet_remove_managed(struct olsr_packet_managed *managed, bool forced) {
+  olsr_packet_remove(&managed->socket_v4, forced);
+  olsr_packet_remove(&managed->socket_v6, forced);
+
+  olsr_acl_remove(&managed->acl);
+}
+
+int
+olsr_packet_apply_managed(struct olsr_packet_managed *managed,
+    struct olsr_packet_managed_config *config) {
+  olsr_acl_copy(&managed->acl, &config->acl);
+
+  if (config_global.ipv4) {
+    if (_apply_managed_socket(managed,
+        &managed->socket_v4, &config->bindto_v4, config->port)) {
+      return -1;
+    }
+  }
+  else {
+    olsr_packet_remove(&managed->socket_v4, true);
+  }
+
+  if (config_global.ipv6) {
+    if (_apply_managed_socket(managed,
+        &managed->socket_v6, &config->bindto_v6, config->port)) {
+      return -1;
+    }
+  }
+  else {
+    olsr_packet_remove(&managed->socket_v6, true);
+  }
+  return 0;
+}
+
+/**
+ * Apply new configuration to a managed stream socket
+ * @param managed pointer to managed stream
+ * @param stream pointer to TCP stream to configure
+ * @param bindto local address to bind socket to
+ * @param port local port number
+ * @return -1 if an error happened, 0 otherwise.
+ */
+static int
+_apply_managed_socket(struct olsr_packet_managed *managed,
+    struct olsr_packet_socket *packet,
+    struct netaddr *bindto, uint16_t port) {
+  union netaddr_socket sock;
+#if !defined(REMOVE_LOG_WARN)
+  struct netaddr_str buf;
+#endif
+
+  if (netaddr_socket_init(&sock, bindto, port)) {
+    OLSR_WARN(LOG_SOCKET_STREAM, "Cannot create managed socket address: %s/%u",
+        netaddr_to_string(&buf, bindto), port);
+    return -1;
+  }
+
+  if (memcmp(&sock, &packet->local_socket, sizeof(sock)) == 0) {
+    /* nothing changed */
+    return 0;
+  }
+
+  olsr_packet_remove(packet, true);
+  if (olsr_packet_add(packet, &sock)) {
+    return -1;
+  }
+
+  /* copy configuration */
+  memcpy(&packet->config, &managed->config, sizeof(packet->config));
+  return 0;
+}
+
 /**
  * Callback to handle data from the olsr socket scheduler
  * @param fd filedescriptor to read data from
@@ -199,22 +285,28 @@ _cb_packet_event(int fd, void *data, bool event_read, bool event_write) {
   char *pkt;
   int result;
 #if !defined(REMOVE_LOG_WARN)
-  struct netaddr_str buf;
+  struct netaddr_str netbuf;
 #endif
 
+  OLSR_DEBUG(LOG_SOCKET_PACKET, "UDP event.");
+
   if (event_read) {
+    uint8_t *buf;
+
     /* handle incoming data */
-    result = os_recvfrom(fd, pktsocket->input_buffer, pktsocket->input_buffer_length-1, &sock);
-    if (result > 0 && pktsocket->receive_data != NULL) {
+    buf = pktsocket->config.input_buffer;
+
+    result = os_recvfrom(fd, buf, pktsocket->config.input_buffer_length-1, &sock);
+    if (result > 0 && pktsocket->config.receive_data != NULL) {
       /* null terminate it */
-      pktsocket->input_buffer[pktsocket->input_buffer_length-1] = 0;
+      buf[result] = 0;
 
       /* received valid packet */
-      pktsocket->receive_data(pktsocket, &sock, result);
+      pktsocket->config.receive_data(pktsocket, &sock, result);
     }
     else if (result < 0 && (errno != EINTR && errno != EAGAIN && errno != EWOULDBLOCK)) {
       OLSR_WARN(LOG_SOCKET_PACKET, "Cannot read packet from socket %s: %s (%d)",
-          netaddr_socket_to_string(&buf, &pktsocket->local_socket), strerror(errno), errno);
+          netaddr_socket_to_string(&netbuf, &pktsocket->local_socket), strerror(errno), errno);
     }
   }
 
@@ -241,7 +333,7 @@ _cb_packet_event(int fd, void *data, bool event_read, bool event_write) {
     if (result < 0) {
       /* display error message */
       OLSR_WARN(LOG_SOCKET_PACKET, "Cannot send UDP packet to %s: %s (%d)",
-          netaddr_socket_to_string(&buf, skt), strerror(errno), errno);
+          netaddr_socket_to_string(&netbuf, skt), strerror(errno), errno);
     }
 
     /* remove data from outgoing buffer (both for success and for final error */
index 58bb4b7..b134bcf 100644 (file)
 #include "common/list.h"
 #include "common/autobuf.h"
 #include "common/netaddr.h"
-
+#include "olsr_netaddr_acl.h"
 #include "olsr_socket.h"
 
-struct olsr_packet_socket {
-  struct list_entity node;
-  union netaddr_socket local_socket;
+struct olsr_packet_socket;
 
-  struct autobuf out;
-  char *input_buffer;
+struct olsr_packet_config {
+  void *input_buffer;
   size_t input_buffer_length;
 
-  struct olsr_socket_entry scheduler_entry;
   void (*receive_data)(struct olsr_packet_socket *,
       union netaddr_socket *from, size_t length);
 };
 
+struct olsr_packet_socket {
+  struct list_entity node;
+
+  struct olsr_socket_entry scheduler_entry;
+  union netaddr_socket local_socket;
+  struct autobuf out;
+
+  struct olsr_packet_config config;
+};
+
+struct olsr_packet_managed {
+  struct olsr_packet_socket socket_v4;
+  struct olsr_packet_socket socket_v6;
+  struct olsr_netaddr_acl acl;
+
+  struct olsr_packet_config config;
+};
+
+struct olsr_packet_managed_config {
+  struct olsr_netaddr_acl acl;
+  struct netaddr bindto_v4;
+  struct netaddr bindto_v6;
+  uint16_t port;
+};
+
 EXPORT void olsr_packet_init(void);
 EXPORT void olsr_packet_cleanup(void);
 
 EXPORT int olsr_packet_add(struct olsr_packet_socket *,
     union netaddr_socket *local);
-EXPORT void olsr_packet_remove(struct olsr_packet_socket *);
+EXPORT void olsr_packet_remove(struct olsr_packet_socket *, bool);
 
 EXPORT int olsr_packet_send(struct olsr_packet_socket *, union netaddr_socket *remove,
     const void *data, size_t length);
 
+EXPORT void olsr_packet_add_managed(struct olsr_packet_managed *);
+EXPORT int olsr_packet_apply_managed(struct olsr_packet_managed *,
+    struct olsr_packet_managed_config *);
+EXPORT void olsr_packet_remove_managed(struct olsr_packet_managed *, bool force);
+
 #endif /* OLSR_PACKET_SOCKET_H_ */
index ee51b26..34690dd 100644 (file)
@@ -325,14 +325,19 @@ olsr_stream_close(struct olsr_stream_session *session, bool force) {
 
 /**
  * Initialized a managed TCP stream
- * @param managed pointer to uninitialized managed stream
+ * @param managed pointer to initialized managed stream
  */
 void
 olsr_stream_add_managed(struct olsr_stream_managed *managed) {
-  memset(managed, 0, sizeof(*managed));
-  managed->config.allowed_sessions = 10;
-  managed->config.maximum_input_buffer = 65536;
-  managed->config.session_timeout = 120000;
+  if (managed->config.allowed_sessions == 0) {
+    managed->config.allowed_sessions = 10;
+  }
+  if (managed->config.maximum_input_buffer == 0) {
+    managed->config.maximum_input_buffer = 65536;
+  }
+  if (managed->config.session_timeout == 0) {
+    managed->config.session_timeout = 120000;
+  }
 }
 
 /**
index 28f5efd..bc90823 100644 (file)
@@ -157,6 +157,7 @@ struct olsr_stream_config {
    */
   enum olsr_stream_session_state (*receive_data)(struct olsr_stream_session *);
 };
+
 /*
  * Represents a TCP server socket or a configuration for a set of outgoing
  * TCP streams.
index 4966619..11dd7f9 100644 (file)
@@ -1,7 +1,8 @@
 # prepare packetbb API configuration
 configure_file (${CMAKE_CURRENT_SOURCE_DIR}/pbb_api_config.h.in ${CMAKE_BINARY_DIR}/packetbb/pbb_api_config.h)
 
-SET(OLSRD_PACKETBB_SRCS pbb_msg_generator.c
+SET(OLSRD_PACKETBB_SRCS pbb_context.c
+                        pbb_msg_generator.c
                         pbb_pkt_generator.c
                         pbb_reader.c
                         pbb_tlv_writer.c
diff --git a/src-api/packetbb/pbb_context.c b/src-api/packetbb/pbb_context.c
new file mode 100644 (file)
index 0000000..b64080d
--- /dev/null
@@ -0,0 +1,83 @@
+/*
+ * PacketBB handler library (see RFC 5444)
+ * Copyright (c) 2010 Henning Rogge <hrogge@googlemail.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in
+ *   the documentation and/or other materials provided with the
+ *   distribution.
+ * * Neither the name of olsr.org, olsrd nor the names of its
+ *   contributors may be used to endorse or promote products derived
+ *   from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Visit http://www.olsr.org/git for more information.
+ *
+ * If you find this software useful feel free to make a donation
+ * to the project. For more information see the website or contact
+ * the copyright holders.
+ */
+
+#include <packetbb/pbb_context.h>
+
+static const char *_pbb_positive_result_texts[] = {
+  [PBB_OKAY]                 = "Okay",
+  [PBB_DROP_TLV]             = "Drop TLV",
+  [PBB_DROP_MSG_BUT_FORWARD] = "Drop message but forward it",
+  [PBB_DROP_MESSAGE]         = "Drop message",
+  [PBB_DROP_PACKET]          = "Drop packet",
+};
+
+static const char *_pbb_negative_result_texts[] = {
+  [PBB_OKAY]                 = "Okay",
+  [-PBB_UNSUPPORTED_VERSION]  = "Version of packetbb not supported",
+  [-PBB_END_OF_BUFFER]        = "Early end of packet",
+  [-PBB_BAD_TLV_IDXFLAGS]     = "Bad combination of index flags",
+  [-PBB_BAD_TLV_VALUEFLAGS]   = "Bad combination of value flags",
+  [-PBB_BAD_TLV_LENGTH]       = "TLV length is no multiple of number of values",
+  [-PBB_OUT_OF_MEMORY]        = "Memory allocation failed",
+  [-PBB_EMPTY_ADDRBLOCK]      = "Address block with zero addresses",
+  [-PBB_BAD_MSG_TAILFLAGS]    = "Bad combination of address tail flags",
+  [-PBB_BAD_MSG_PREFIXFLAGS]  = "Bad combination of address prefix length flags",
+  [-PBB_DUPLICATE_TLV]        = "Duplicate address TLV",
+  [-PBB_OUT_OF_ADDRTLV_MEM]   = "Not enough memory for address-TLVs",
+  [-PBB_MTU_TOO_SMALL]        = "Configured MTU size too small",
+  [-PBB_NO_MSGCREATOR]        = "Cannot create message without message creator",
+  [-PBB_FW_MESSAGE_TOO_LONG]  = "Cannot forward message, content too long",
+  [-PBB_FW_BAD_SIZE]          = "Bad length field of message to be forwarded",
+};
+
+/**
+ * @param result pbb result code
+ * @return text message for result code
+ */
+const char *
+pbb_strerror(enum pbb_result result) {
+  const char *UNKNOWN = "Unknown pbb result";
+  if (result >= PBB_OKAY && result <= PBB_RESULT_MAX) {
+    return _pbb_positive_result_texts[result];
+  }
+  if (result < PBB_OKAY && result >= PBB_RESULT_MIN) {
+    return _pbb_negative_result_texts[-result];
+  }
+  return UNKNOWN;
+}
index 5a276a0..2f1f1fd 100644 (file)
@@ -63,6 +63,8 @@
  *   illegal combination of thassingleindex and thasmultiindex flags
  * PBB_BAD_TLV_VALUEFLAGS
  *   illegal combination of thasvalue and thasextlen flag
+ * PBB_BAD_TLV_LENGTH
+ *   length of tlv is no multiple of number of values
  * PBB_OUT_OF_MEMORY
  *   dynamic memory allocation failed
  * PBB_EMPTY_ADDRBLOCK
@@ -86,6 +88,7 @@
  */
 enum pbb_result {
 #if DISALLOW_CONSUMER_CONTEXT_DROP == false
+  PBB_RESULT_MAX           =  5,
   PBB_DROP_PACKET          =  5,
   PBB_DROP_MESSAGE         =  4,
   PBB_DROP_MSG_BUT_FORWARD =  3,
@@ -108,8 +111,11 @@ enum pbb_result {
   PBB_NO_MSGCREATOR        = -13,
   PBB_FW_MESSAGE_TOO_LONG  = -14,
   PBB_FW_BAD_SIZE          = -15,
+  PBB_RESULT_MIN           = -15,
 };
 
+EXPORT const char *pbb_strerror(enum pbb_result result);
+
 /* maximum address length */
 /* defined as a macro because it's used to define length of arrays */
 #define PBB_MAX_ADDRLEN ((int)16)
index ea54ee3..4b2a14b 100644 (file)
@@ -54,7 +54,8 @@
 #endif
 
 static int _consumer_avl_comp(const void *k1, const void *k2, void *ptr);
-static int _calc_tlv_intorder(uint8_t type, uint8_t exttype);
+static int _calc_tlvconsumer_intorder(struct pbb_reader_tlvblock_consumer_entry *entry);
+static int _calc_tlvblock_intorder(struct pbb_reader_tlvblock_entry *entry);
 static bool _has_same_tlvtype(int int_type1, int int_type2);
 static uint8_t _pbb_get_u8(uint8_t **ptr, uint8_t *end, enum pbb_result *result);
 static uint16_t _pbb_get_u16(uint8_t **ptr, uint8_t *end, enum pbb_result *result);
@@ -263,12 +264,11 @@ pbb_reader_add_packet_consumer(struct pbb_reader *parser,
  * Add a message consumer for a single message type to
  * the parser to process the message tlvs
  * @param parser pointer to parser context
+ * @param consumer pointer to tlvblock consumer
  * @param entries array of tlvblock_entries
  * @param entrycount number of elements in array
  * @param msg_id type of the message for the consumer
- * @param order
- * @return pointer to pbb_reader_tlvblock_consumer,
- *   NULL if an error happened
+ * @param order priority of message consumer
  */
 void
 pbb_reader_add_message_consumer(struct pbb_reader *parser,
@@ -388,13 +388,22 @@ _consumer_avl_comp(const void *k1, const void *k2, void *ptr __attribute__ ((unu
 
 /**
  * Calculate internal tlvtype from type and exttype
- * @param type
- * @param exttype
+ * @param entry pointer tlvblock entry
  * @return 256*type + exttype
  */
 static int
-_calc_tlv_intorder(uint8_t type, uint8_t exttype) {
-  return (((int)type) << 8) | ((int)exttype);
+_calc_tlvconsumer_intorder(struct pbb_reader_tlvblock_consumer_entry *entry) {
+  return (((int)entry->type) << 8) | ((int)entry->type_ext);
+}
+
+/**
+ * Calculate internal tlvtype from type and exttype
+ * @param entry pointer tlvblock entry
+ * @return 256*type + exttype
+ */
+static int
+_calc_tlvblock_intorder(struct pbb_reader_tlvblock_entry *entry) {
+  return (((int)entry->type) << 8) | ((int)entry->type_ext);
 }
 
 /**
@@ -491,7 +500,7 @@ _parse_tlv(struct pbb_reader_tlvblock_entry *entry, uint8_t **ptr, uint8_t *eob)
   }
 
   /* calculate internal combination of tlv type and extension */
-  entry->int_order = _calc_tlv_intorder(entry->type, entry->type_ext);
+  entry->int_order = _calc_tlvblock_intorder(entry);
 
   /* check for TLV index values */
   masked = entry->flags & (PBB_TLV_FLAG_SINGLE_IDX | PBB_TLV_FLAG_MULTI_IDX);
@@ -642,29 +651,30 @@ _schedule_tlvblock(struct pbb_reader_tlvblock_consumer *consumer, struct pbb_rea
     struct avl_tree *entries, uint8_t idx) {
   struct pbb_reader_tlvblock_entry *tlv = NULL;
   struct pbb_reader_tlvblock_consumer_entry *cons_entry;
-  bool mandatory_missing;
+  bool constraints_failed;
   int cons_order, tlv_order;
   enum pbb_result result = PBB_OKAY;
 
-  if (avl_is_empty(entries)) {
-    /* empty TLV block */
-    return PBB_OKAY;
-  }
-
-  mandatory_missing = false;
+  constraints_failed = false;
 
   /* initialize tlv pointers, there must be TLVs */
-  tlv = avl_first_element(entries, tlv, node);
-  tlv_order = tlv->int_order;
+  if (avl_is_empty(entries)) {
+    tlv = NULL;
+    tlv_order = TLVTYPE_ORDER_INFINITE;
+  }
+  else {
+    tlv = avl_first_element(entries, tlv, node);
+    tlv_order = tlv->int_order;
+  }
 
   /* initialize consumer pointer */
-  if (avl_is_empty(&consumer->consumer_entries)) {
+  if (list_is_empty(&consumer->_consumer_list)) {
     cons_entry = NULL;
     cons_order = TLVTYPE_ORDER_INFINITE;
   }
   else {
-    cons_entry = avl_first_element(&consumer->consumer_entries, cons_entry, node);
-    cons_order = cons_entry->int_order;
+    cons_entry = list_first_element(&consumer->_consumer_list, cons_entry, _node);
+    cons_order = _calc_tlvconsumer_intorder(cons_entry);
     cons_entry->tlv = NULL;
     cons_entry->duplicate_tlv = false;
   }
@@ -722,16 +732,22 @@ _schedule_tlvblock(struct pbb_reader_tlvblock_consumer *consumer, struct pbb_rea
 
     /* run through both sorted lists until finding a match */
     if (cons_order <= tlv_order) {
-      mandatory_missing |= cons_entry->mandatory && !match;
+      constraints_failed |= cons_entry->mandatory && !match;
 
       if (match) {
+        if (cons_entry->match_length &&
+            (tlv->length < cons_entry->min_length
+                || tlv->length > cons_entry->max_length)) {
+          constraints_failed = true;
+        }
+
         if (cons_entry->tlv == NULL) {
           /* remember new tlv */
           cons_entry->tlv = tlv;
 
           if (cons_entry->copy_value != NULL && tlv->length > 0) {
             /* copy value into private buffer */
-            uint16_t len = cons_entry->copy_value_maxlen;
+            uint16_t len = cons_entry->max_length;
 
             if (tlv->length < len) {
               len = tlv->length;
@@ -757,13 +773,13 @@ _schedule_tlvblock(struct pbb_reader_tlvblock_consumer *consumer, struct pbb_rea
     }
     if (cons_order < tlv_order) {
       /* advance consumer pointer */
-      if (avl_is_last(&consumer->consumer_entries, &cons_entry->node)) {
+      if (list_is_last(&consumer->_consumer_list, &cons_entry->_node)) {
         cons_entry = NULL;
         cons_order = TLVTYPE_ORDER_INFINITE;
       }
       else {
-        cons_entry = avl_next_element(cons_entry, node);
-        cons_order = cons_entry->int_order;
+        cons_entry = list_next_element(cons_entry, _node);
+        cons_order = _calc_tlvconsumer_intorder(cons_entry);
         cons_entry->tlv = NULL;
         cons_entry->duplicate_tlv = false;
       }
@@ -771,31 +787,36 @@ _schedule_tlvblock(struct pbb_reader_tlvblock_consumer *consumer, struct pbb_rea
   }
 
   /* call consumer for tlvblock */
-  if (consumer->block_callback != NULL) {
+  if (consumer->block_callback != NULL && !constraints_failed) {
 #if DISALLOW_CONSUMER_CONTEXT_DROP == false
     result =
 #endif
-        consumer->block_callback(consumer, context, mandatory_missing);
-
+        consumer->block_callback(consumer, context);
+  }
+  else if (consumer->block_callback_failed_constraints != NULL && constraints_failed) {
 #if DISALLOW_CONSUMER_CONTEXT_DROP == false
-    if (result == PBB_DROP_TLV) {
-      avl_for_each_element(&consumer->consumer_entries, cons_entry, node) {
-        if (cons_entry->tlv != NULL && cons_entry->drop) {
-          _set_addr_bitarray(&cons_entry->tlv->int_drop_tlv, idx);
-          cons_entry->drop = false;
-        }
+    result =
+#endif
+        consumer->block_callback_failed_constraints(consumer, context);
+  }
+#if DISALLOW_CONSUMER_CONTEXT_DROP == false
+  if (result == PBB_DROP_TLV) {
+    list_for_each_element(&consumer->_consumer_list, cons_entry, _node) {
+      if (cons_entry->tlv != NULL && cons_entry->drop) {
+        _set_addr_bitarray(&cons_entry->tlv->int_drop_tlv, idx);
+        cons_entry->drop = false;
       }
-
-      /* do not propagate tlv drops */
-      result = PBB_OKAY;
     }
-#endif
+
+    /* do not propagate tlv drops */
+    result = PBB_OKAY;
   }
+#endif
 #if DISALLOW_CONSUMER_CONTEXT_DROP == false
 cleanup_handle_tlvblock:
 #endif
 #if  DEBUG_CLEANUP == true
-  avl_for_each_element(&consumer->consumer_entries, cons_entry, node) {
+  list_for_each_element(&consumer->_consumer_list, cons_entry, _node) {
     cons_entry->tlv = NULL;
     cons_entry->drop = false;
   }
@@ -1263,14 +1284,36 @@ cleanup_parse_message:
 static struct pbb_reader_tlvblock_consumer *
 _add_consumer(struct pbb_reader_tlvblock_consumer *consumer, struct avl_tree *consumer_tree,
     struct pbb_reader_tlvblock_consumer_entry *entries, int entrycount, int order) {
-  int i;
+  struct pbb_reader_tlvblock_consumer_entry *e;
+  int i, o;
+  bool set;
+
+  list_init_head(&consumer->_consumer_list);
 
   /* generate sorted list of entries */
-  avl_init(&consumer->consumer_entries, avl_comp_uint32, false, NULL);
   for (i=0; i<entrycount; i++) {
-    entries[i].int_order = _calc_tlv_intorder(entries[i].type, entries[i].type_ext);
-    entries[i].node.key = &entries[i].int_order;
-    avl_insert(&consumer->consumer_entries, &entries[i].node);
+    o = _calc_tlvconsumer_intorder(&entries[i]);
+
+    if (i == 0) {
+      list_add_tail(&consumer->_consumer_list, &entries[i]._node);
+    }
+    else {
+      set = false;
+      list_for_each_element_reverse(&consumer->_consumer_list, e, _node) {
+        if (_calc_tlvconsumer_intorder(e) <= o) {
+          list_add_after(&e->_node, &entries[i]._node);
+          set = true;
+          break;
+        }
+      }
+      if (!set) {
+        list_add_head(&consumer->_consumer_list, &entries[i]._node);
+      }
+    }
+
+    if (entries[i].min_length > entries[i].max_length) {
+      entries[i].max_length = entries[i].min_length;
+    }
   }
 
   /* initialize order */
index 021810d..3b54c89 100644 (file)
@@ -57,7 +57,7 @@ enum pbb_reader_tlvblock_context_type {
 };
 
 /**
- * This structs temporary holds the content of a decoded TLV.
+ * This struct temporary holds the content of a decoded TLV.
  */
 struct pbb_reader_tlvblock_entry {
   /* single linked list of entries */
@@ -177,14 +177,8 @@ struct pbb_reader_addrblock_entry {
  * representation of a consumer for a tlv block and context
  */
 struct pbb_reader_tlvblock_consumer_entry {
-  /* set by initialization to create a sorted list */
-  struct avl_node node;
-
-  /*
-   * set by initialization, internal sorting order for types:
-   * tlvtype * 256 + exttype
-   */
-  int int_order;
+  /* sorted list of consumer entries */
+  struct list_entity _node;
 
   /* set by the consumer if the entry is mandatory */
   bool mandatory;
@@ -192,15 +186,27 @@ struct pbb_reader_tlvblock_consumer_entry {
   /* set by the consumer to define the type of the tlv */
   uint8_t type;
 
+  /* set by the consumer to define the required type extension */
+  uint8_t type_ext;
+
   /* set by the consumer to require a certain type extension */
   bool match_type_ext;
 
-  /* set by the consumer to define the required type extension */
-  uint8_t type_ext;
+  /* set by the consumer to define the minimum length of the TLVs value */
+  uint16_t min_length;
+
+  /*
+   * set by the consumer to define the maximum length of the TLVs value.
+   * If smaller than min_length, this value will be assumed the same as
+   * min_length.
+   */
+  uint16_t max_length;
+
+  /* set by consumer to activate length checking */
+  bool match_length;
 
   /* set by the consumer to make the parser copy the TLV value into a private buffer */
   void *copy_value;
-  uint16_t copy_value_maxlen;
 
   /* set by the parser to announce that the TLV was present multiple times */
   bool duplicate_tlv;
@@ -238,7 +244,7 @@ struct pbb_reader_tlvblock_consumer {
   bool addrblock_consumer;
 
   /* Tree of sorted consumer entries */
-  struct avl_tree consumer_entries;
+  struct list_entity _consumer_list;
 
   /* consumer for TLVblock context start and end*/
   enum pbb_result (*start_callback)(struct pbb_reader_tlvblock_consumer *,
@@ -252,8 +258,12 @@ struct pbb_reader_tlvblock_consumer {
       struct pbb_reader_tlvblock_context *context);
 
   /* consumer for tlv block and context */
-  enum pbb_result (*block_callback)(struct pbb_reader_tlvblock_consumer *,
-      struct pbb_reader_tlvblock_context *context, bool mandatory_missing);
+  enum pbb_result (*block_callback)(
+      struct pbb_reader_tlvblock_consumer *,
+      struct pbb_reader_tlvblock_context *context);
+  enum pbb_result (*block_callback_failed_constraints)(
+      struct pbb_reader_tlvblock_consumer *,
+      struct pbb_reader_tlvblock_context *context);
 
   /* private data pointer for API user */
   void *private;
index b692177..2fc3406 100644 (file)
@@ -54,7 +54,7 @@ static struct pbb_reader reader;
 struct pbb_reader_tlvblock_consumer consumer;
 static bool got_tlv[2];
 static bool got_multiple_times[2];
-static bool got_mandatory_missing;
+static bool got_failed_constraints;
 
 static enum pbb_result
 cb_blocktlv_packet(struct pbb_reader_tlvblock_consumer *cons __attribute__ ((unused)),
@@ -66,16 +66,28 @@ cb_blocktlv_packet(struct pbb_reader_tlvblock_consumer *cons __attribute__ ((unu
   got_tlv[1] = consumer_entries[1].tlv != NULL;
   got_multiple_times[1] = consumer_entries[1].duplicate_tlv;
 
-  got_mandatory_missing = mandatory_missing;
+  got_failed_constraints = mandatory_missing;
   return PBB_OKAY;
 }
 
+static enum pbb_result
+cb_blocktlv_packet_okay(struct pbb_reader_tlvblock_consumer *cons,
+      struct pbb_reader_tlvblock_context *cont) {
+  return cb_blocktlv_packet(cons, cont, false);
+}
+
+static enum pbb_result
+cb_blocktlv_packet_failed(struct pbb_reader_tlvblock_consumer *cons,
+      struct pbb_reader_tlvblock_context *cont) {
+  return cb_blocktlv_packet(cons, cont, true);
+}
+
 static void clear_elements(void) {
   got_tlv[0] = false;
   got_multiple_times[0] = false;
   got_tlv[1] = false;
   got_multiple_times[1] = false;
-  got_mandatory_missing = false;
+  got_failed_constraints = false;
 }
 
 static void test_packet1(void) {
@@ -89,7 +101,7 @@ static void test_packet1(void) {
   CHECK_TRUE(!got_multiple_times[0], "TLV 1 (duplicate)");
   CHECK_TRUE(!got_multiple_times[1], "TLV 2 (duplicate)");
 
-  CHECK_TRUE(got_mandatory_missing, "mandatory missing");
+  CHECK_TRUE(got_failed_constraints, "mandatory missing");
   END_TEST();
 }
 
@@ -104,7 +116,7 @@ static void test_packet12(void) {
   CHECK_TRUE(!got_multiple_times[0], "TLV 1 (duplicate)");
   CHECK_TRUE(!got_multiple_times[1], "TLV 2 (duplicate)");
 
-  CHECK_TRUE(!got_mandatory_missing, "mandatory missing");
+  CHECK_TRUE(!got_failed_constraints, "mandatory missing");
   END_TEST();
 }
 
@@ -119,7 +131,7 @@ static void test_packet121(void) {
   CHECK_TRUE(got_multiple_times[0], "TLV 1 (duplicate)");
   CHECK_TRUE(!got_multiple_times[1], "TLV 2 (duplicate)");
 
-  CHECK_TRUE(!got_mandatory_missing, "mandatory missing");
+  CHECK_TRUE(!got_failed_constraints, "mandatory missing");
   END_TEST();
 }
 
@@ -134,14 +146,15 @@ static void test_packet212(void) {
   CHECK_TRUE(!got_multiple_times[0], "TLV 1 (duplicate)");
   CHECK_TRUE(got_multiple_times[1], "TLV 2 (duplicate)");
 
-  CHECK_TRUE(!got_mandatory_missing, "mandatory missing");
+  CHECK_TRUE(!got_failed_constraints, "mandatory missing");
   END_TEST();
 }
 
 int main(int argc __attribute__ ((unused)), char **argv __attribute__ ((unused))) {
   pbb_reader_init(&reader);
   pbb_reader_add_packet_consumer(&reader, &consumer, consumer_entries, ARRAYSIZE(consumer_entries), 1);
-  consumer.block_callback = cb_blocktlv_packet;
+  consumer.block_callback = cb_blocktlv_packet_okay;
+  consumer.block_callback_failed_constraints = cb_blocktlv_packet_failed;
 
   BEGIN_TESTING();
 
index 63b68a3..3a4ebf5 100644 (file)
@@ -130,8 +130,7 @@ static bool droptlv_blocktlv_address[2][2][2];
 
 static enum pbb_result
 cb_blocktlv_packet(struct pbb_reader_tlvblock_consumer *consumer,
-      struct pbb_reader_tlvblock_context *c __attribute__ ((unused)),
-      bool mandatory_missing __attribute__ ((unused))) {
+      struct pbb_reader_tlvblock_context *c __attribute__ ((unused))) {
   int oi = consumer->order - 1;
 
 #ifdef PRINT_CB
@@ -151,8 +150,7 @@ cb_blocktlv_packet(struct pbb_reader_tlvblock_consumer *consumer,
 
 static enum pbb_result
 cb_blocktlv_message(struct pbb_reader_tlvblock_consumer *consumer,
-      struct pbb_reader_tlvblock_context *c __attribute__ ((unused)),
-      bool mandatory_missing __attribute__ ((unused))) {
+      struct pbb_reader_tlvblock_context *c __attribute__ ((unused))) {
   int oi = consumer->order - 1;
 
 #ifdef PRINT_CB
@@ -172,8 +170,7 @@ cb_blocktlv_message(struct pbb_reader_tlvblock_consumer *consumer,
 
 static enum pbb_result
 cb_blocktlv_message2(struct pbb_reader_tlvblock_consumer *consumer __attribute__ ((unused)),
-      struct pbb_reader_tlvblock_context *c __attribute__ ((unused)),
-      bool mandatory_missing __attribute__ ((unused))) {
+      struct pbb_reader_tlvblock_context *c __attribute__ ((unused))) {
 #ifdef PRINT_CB
   printf("%s: message 2 blocktlv: %d\n", __func__, callback_index);
 #endif
@@ -183,8 +180,7 @@ cb_blocktlv_message2(struct pbb_reader_tlvblock_consumer *consumer __attribute__
 
 static enum pbb_result
 cb_blocktlv_address(struct pbb_reader_tlvblock_consumer *consumer,
-      struct pbb_reader_tlvblock_context *ctx,
-      bool mandatory_missing __attribute__ ((unused))) {
+      struct pbb_reader_tlvblock_context *ctx) {
   uint8_t ai = ctx->addr[3] - 1;
   int oi = consumer->order - 1;