/* * Usurpataion --- clinet-server protocol implementation. * * Copyright (C) 2019 Ramūnas Mažeikis * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; version 2.1 * of the License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ /** * Common parts of protocol implementation. Handling of anything that actually * deals with connection descriptor has to be implemented by device and daemon * separately. */ #include #include #include #include "tlv.h" #include "tlv_private.h" #include "net.h" #include "utils.h" 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; } else { ret->type = memcpy(&ret->type, parser->data + parser->offset, sizeof(ret->type)); parser->size += 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; } else { memcpy(ret->data, parser->data, ret->length); } } return retval; } size_t tlv_data_size(struct tlv_parser *parser) { size_t size; if (parser->offset + sizeof(enum tlv_type) + sizeof(size_t) >= parser->size) { size = 0; } else { memcpy(&size, parser->data + parser->offset + sizeof(enum tlv_type), sizeof(size_t)); } return size; } void tlv_destroy(struct tlv *t) { size_t i = 0; size_t tlv_count; struct tlv *arr; switch (t->type) { case REGURAL: case HEARTBEAT: case DISCOVERY: tlv_count = t->length / sizeof(struct tlv); arr = t->data; for (i = 0; i < tlv_count; i++) { tlv_destroy(&arr[i]); } default: free(t->data); t->length = 0; break; } } size_t tlv_raw_size(const struct tlv *t) { return sizeof(*t) + t->length; } int tlv_push_data(struct tlv *t, const char *data, size_t size) { int ret = 0; size_t final_size = tlv_raw_size(t) + size; if (final_size > TLV_SZ_MAX_RAW) { ret = E_TLV_OVERFLOW; } else { t->data = realloc(t->data, final_size); memcpy(t->data + t->length, data, size); t->length = final_size; } return ret; } void tlv_init(struct tlv *t, enum tlv_type type) { t->type = type; t->length = 0; t->data = NULL; } int tlv_push_tlv(struct tlv *t, const struct tlv *other) { int ret = 0; size_t other_size; size_t final_size; other_size = tlv_raw_size(other); final_size = tlv_raw_size(t) + other_size; if (final_size > TLV_SZ_MAX_RAW) { ret = E_TLV_OVERFLOW; } else { tlv_get_raw(other, t->data + t->length); t->length = final_size; } return ret; }