summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGravatar Ramūnas Mažeikis <ramunasnezinomas@gmail.com> 2019-06-04 10:21:03 +0300
committerGravatar Ramūnas Mažeikis <ramunasnezinomas@gmail.com> 2019-06-04 10:21:03 +0300
commit9d8c56601d37e420143ef5aeec98d9ab9c5a60fd (patch)
tree3c63662c9562eba85cbad17c2db698a31f7a5b88
parente801c0c7204df9c566b503a7c4c2d828166796f8 (diff)
downloadusurpation-9d8c56601d37e420143ef5aeec98d9ab9c5a60fd.tar.gz
usurpation-9d8c56601d37e420143ef5aeec98d9ab9c5a60fd.tar.bz2
usurpation-9d8c56601d37e420143ef5aeec98d9ab9c5a60fd.zip
Protocol: reimplementation of tlv_get according to new spec.
Signed-off-by: Ramūnas Mažeikis <ramunasnezinomas@gmail.com>
-rw-r--r--include/tlv.h34
-rwxr-xr-xsrc/common/tlv.c77
2 files changed, 93 insertions, 18 deletions
diff --git a/include/tlv.h b/include/tlv.h
index 63507c1..75aa133 100644
--- a/include/tlv.h
+++ b/include/tlv.h
@@ -62,6 +62,8 @@ A few things to note:
#include <errno.h>
+#include <stdint.h>
+#include <limits.h>
#define E_TLV_OVERFLOW (1 << 0)
#define E_UNKNOWN_TYPE (1 << 1)
@@ -79,8 +81,19 @@ extern "C" {
*/
typedef unsigned int msg_idx_t;
+#if INT32_MAX == INT_MAX
+#define READ_ENUM(data) htonl((data))
+#else INT_MAX == INT16_MAX
+#define READ_ENUM(data) htons((data))
+#endif
+
enum tlv_type {
/**
+ * Explicitly states that this tlv is no longer valid for reading.
+ */
+ INVALID = 0,
+
+ /**
* NULL-terminated string. To be put in a queue to display on the
* screen.
*/
@@ -132,8 +145,8 @@ enum tlv_type {
* */
struct tlv {
enum tlv_type type;
- size_t length;
- void *data;
+ uint16_t length;
+ const void *data;
};
/**
@@ -142,12 +155,19 @@ struct tlv {
* Related functions return one tlv at a time.
*/
struct tlv_parser {
- char *data;
- size_t offset;
- size_t size;
+ const char *data;
+ uint16_t offset;
};
/**
+ * Initialises parser to begin parsing the data.
+ *
+ * Returns the first tlv which should be a meta-tlv. If it is not --- you got
+ * problems.
+ */
+int tlv_parser_init(struct tlv_parser *parser, char *data, struct tlv *ret);
+
+/**
* Fills tlv structure to represent the next tlv in the packet.
*
* Returns END_OF_PACKET if all tlv's were read or E_TLV_OVERFLOW, if the last
@@ -175,14 +195,14 @@ size_t tlv_raw_size(const struct tlv *t);
* Pushes tlv to buffer as contiguous data. Check tlv size with tlv_raw_size
* beforehand. If you don't do that and overflow --- tough tiddy.
*/
-int tlv_get_raw(struct tlv *t, char *buf);
+int tlv_get_raw(const struct tlv *t, char *buf);
/**
* Pushes data to tlv. Returns E_TLV_OVERFLOW if pushing data would cause the
* final size to be greater than TLV_SZ_MAX_RAW. In case of such error the data is left
* untouched.
*/
-int tlv_push_data(struct tlv *t, const char *data, size_t size);
+int tlv_push_data(struct tlv *t, const char *data, uint16_t size);
/**
* Pushes a sub-tlv into the packet. 't' can only be REGURAL, HEARTBEAT or
diff --git a/src/common/tlv.c b/src/common/tlv.c
index 5b5ca5e..f02b714 100755
--- a/src/common/tlv.c
+++ b/src/common/tlv.c
@@ -27,32 +27,87 @@
#include <stdlib.h>
#include <string.h>
#include <time.h>
+#include <arpa/inet.h>
#include "tlv.h"
#include "net.h"
#include "utils.h"
+struct tlv_header {
+ enum tlv_type type;
+ uint16_t size;
+};
+
+/**
+ * Returns tlv_size from packet
+ */
+uint16_t tlv_size(char *buf);
+
+/**
+ * Returns tlv_type from packet.
+ */
+enum tlv_type tlv_get_type(char *buf);
+
+/* Changes to be made:
+ * * Trust tlv size from raw data
+ * * Don't fail on 0 length. In that case data points to NULL
+ * * tlv_parser should be opaque.
+ * * Make a constructor that takes a user-supplied buffer.
+ */
int tlv_get(struct tlv_parser *parser, struct tlv *ret)
{
int retval = 0;
- if (parser->offset + sizeof(ret->type) + sizeof(ret->length) >= parser->size) {
- retval = E_TLV_OVERFLOW;
- } else if (parser -> offset == parser->size) {
- retval = END_OF_PACKET;
+ size_t packet_size;
+ size_t final_size;
+ struct tlv *crr_tlv = parser->data + parser->offset;
+
+ packet_size = tlv_size(parser->data);
+ final_size = parser->offset + crr_tlv->length + sizeof(struct tlv_header);
+ if (final_size >= packet_size) {
+ return retval = E_TLV_OVERFLOW;
} else {
- memcpy(&ret->type, parser->data + parser->offset, sizeof(ret->type));
- parser->offset += sizeof(ret->type);
- ret->length = memcpy(&ret->length, parser->data + parser->offset, sizeof(ret->length));
- parser->offset += sizeof(ret->length);
- if (parser->offset + ret->length >= parser->size) {
- retval = E_TLV_OVERFLOW;
+ if (crr_tlv->length != 0) {
+ ret->data = parser->data + parser->offset + sizeof(struct tlv_header);
} else {
- memcpy(ret->data, parser->data, ret->length);
+ ret->data = NULL;
+ }
+ ret->type = crr_tlv->type;
+ ret->length = crr_tlv->length;
+ parser->offset += sizeof(struct tlv_header) + ret->length;
+ if (final_size == packet_size) {
+ retval = END_OF_PACKET;
}
}
+
return retval;
}
+int tlv_parser_init(struct tlv_parser *parser, char *buf, struct tlv *ret)
+{
+ /* Data points to the beggining of the buffer for size and
+ * type acquisition purposes.
+ * */
+ struct tlv_header *data = buf;
+ /* It is known that the first tlv will be of the meta kind.
+ * We can safely skip the header.
+ * */
+ parser->data = buf + sizeof(struct tlv_header);
+ ret->type = data->type;
+ ret->length = data->size;
+}
+
+uint16_t tlv_size(char *buf)
+{
+ struct tlv_header *data = buf;
+ return htons(data->size);
+}
+
+enum tlv_type tlv_get_type(char *buf)
+{
+ struct tlv_header *data = buf;
+ return READ_ENUM(data->type);
+}
+
size_t tlv_data_size(struct tlv_parser *parser)
{
size_t size;