diff --git a/meson.build b/meson.build index 924f28a..60224f9 100644 --- a/meson.build +++ b/meson.build @@ -34,6 +34,8 @@ lib_util = static_library('util', dep_libutil = declare_dependency(link_with: lib_util) src_libei = [ + 'src/brei-shared.h', + 'src/brei-shared.c', 'src/libei.h', 'src/libei.c', 'src/libei-device.c', @@ -63,6 +65,8 @@ pkgconfig.generate(lib_libei, ) lib_libeis = shared_library('eis', + 'src/brei-shared.h', + 'src/brei-shared.c', 'src/libeis.h', 'src/libeis.c', 'src/libeis-client.c', diff --git a/src/brei-shared.c b/src/brei-shared.c new file mode 100644 index 0000000..988094e --- /dev/null +++ b/src/brei-shared.c @@ -0,0 +1,122 @@ +/* + * Copyright © 2020 Red Hat, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#include "config.h" + +#include "util-mem.h" + +#include "proto/ei.pb-c.h" +#include "brei-shared.h" + + +static void frame_cleanup(Frame **f) { + if (*f) + frame__free_unpacked(*f, NULL); +} +#define _cleanup_frame_ _cleanup_(frame_cleanup) + +const unsigned char * +brei_next_message(const char *data, size_t *msglen, size_t *consumed) +{ + /* Every message is prefixed by a fixed-length Frame message which + * contains the length of the next message. Frames are always the + * same length, so we only need to calculate the size once. + */ + static size_t framelen = 0; + + if (framelen == 0) { + Frame f = FRAME__INIT; + f.length = 0xffff; + framelen = frame__get_packed_size(&f); + assert(framelen >= 5); + } + + _cleanup_frame_ Frame *frame = frame__unpack(NULL, framelen, (const unsigned char *)data); + if (!frame) + return NULL; + + *msglen = frame->length; + *consumed = framelen; + + return (const unsigned char*)data + framelen; +} + + +#ifdef _enable_tests_ +#include + +static MunitResult +test_proto_next_message(const MunitParameter params[], void *user_data) +{ + char data[64]; + + /* Invalid frame, rest can be random */ + data[0] = 0xaa; + + size_t msglen = 0xab; + size_t consumed = 0xbc; + + const unsigned char *rval = brei_next_message(data, &msglen, &consumed); + munit_assert_ptr_null(rval); + munit_assert_int(msglen, ==, 0xab); + munit_assert_int(consumed, ==, 0xbc); + + /* Now try a valid one */ + Frame f = FRAME__INIT; + f.length = 0xcd; + size_t framelen = frame__get_packed_size(&f); + + unsigned char buf[framelen * 4]; + for (int i = 0; i < 4; i++) + frame__pack(&f, buf + framelen * i); + + const char *ptr = (char*)buf; + for (int i = 0; i < 4; i++) { + const unsigned char *next_frame = brei_next_message(ptr, &msglen, &consumed); + munit_assert_ptr_equal(next_frame, buf + (i + 1) * framelen); + munit_assert_int(consumed, ==, framelen); + munit_assert_int(msglen, ==, 0xcd); + ptr += consumed; + } + + return MUNIT_OK; +} + +#define TEST(_func) \ + { .name = #_func, .test = _func } + +static MunitTest ei_tests[] = { + TEST(test_proto_next_message), + { NULL }, +}; + +static const MunitSuite libei_suite +__attribute__((used)) +__attribute__((section("test_section"))) = { + "brei", + ei_tests, + NULL, + 1, + MUNIT_SUITE_OPTION_NONE, +}; +#endif diff --git a/src/brei-shared.h b/src/brei-shared.h new file mode 100644 index 0000000..2dc2e2c --- /dev/null +++ b/src/brei-shared.h @@ -0,0 +1,39 @@ +/* + * Copyright © 2020 Red Hat, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#pragma once + +#include "config.h" + +/** + * The BREI (i.e. the EI protocol) is using Frames to separate the messages. + * This helper takes the data of length msglength and returns the position + * of the next actual message. + * + * @param msglen Length of data + * @param consumed The number of bytes consumed to advance to the next + * message + * @return The position of the next message + */ +const unsigned char * +brei_next_message(const char *data, size_t *msglen, size_t *consumed); diff --git a/src/libei-proto.c b/src/libei-proto.c index 0f3e48d..ecbf85e 100644 --- a/src/libei-proto.c +++ b/src/libei-proto.c @@ -31,6 +31,7 @@ #include "proto/ei.pb-c.h" #include "libei-proto.h" +#include "brei-shared.h" void message_free(struct message *msg) @@ -42,50 +43,18 @@ message_free(struct message *msg) free(msg); } -static void frame_cleanup(Frame **f) { - if (*f) - frame__free_unpacked(*f, NULL); -} - static void servermessage_cleanup(ServerMessage **m) { if (*m) server_message__free_unpacked(*m, NULL); } -#define _cleanup_frame_ _cleanup_(frame_cleanup) #define _cleanup_servermessage_ _cleanup_(servermessage_cleanup) -static const unsigned char * -next_message(const char *data, size_t *msglen, size_t *consumed) -{ - /* Every message is prefixed by a fixed-length Frame message which - * contains the length of the next message. Frames are always the - * same length, so we only need to calculate the size once. - */ - static size_t framelen = 0; - - if (framelen == 0) { - Frame f = FRAME__INIT; - f.length = 0xffff; - framelen = frame__get_packed_size(&f); - assert(framelen >= 5); - } - - _cleanup_frame_ Frame *frame = frame__unpack(NULL, framelen, (const unsigned char *)data); - if (!frame) - return NULL; - - *msglen = frame->length; - *consumed = framelen; - - return (const unsigned char*)data + framelen; -} - struct message * ei_proto_parse_message(const char *data, size_t len, size_t *consumed) { size_t headerbytes = 0; size_t msglen = 0; - const unsigned char *msgdata = next_message(data, &msglen, &headerbytes); + const unsigned char *msgdata = brei_next_message(data, &msglen, &headerbytes); _cleanup_servermessage_ ServerMessage *proto = server_message__unpack(NULL, msglen, msgdata); if (!proto) @@ -288,62 +257,3 @@ ei_proto_send_key(struct ei *ei, struct ei_device *device, return ei_proto_send_msg(ei, &msg); } - -#ifdef _enable_tests_ -#include - -static MunitResult -test_proto_next_message(const MunitParameter params[], void *user_data) -{ - char data[64]; - - /* Invalid frame, rest can be random */ - data[0] = 0xaa; - - size_t msglen = 0xab; - size_t consumed = 0xbc; - - const unsigned char *rval = next_message(data, &msglen, &consumed); - munit_assert_ptr_null(rval); - munit_assert_int(msglen, ==, 0xab); - munit_assert_int(consumed, ==, 0xbc); - - /* Now try a valid one */ - Frame f = FRAME__INIT; - f.length = 0xcd; - size_t framelen = frame__get_packed_size(&f); - - unsigned char buf[framelen * 4]; - for (int i = 0; i < 4; i++) - frame__pack(&f, buf + framelen * i); - - const char *ptr = (char*)buf; - for (int i = 0; i < 4; i++) { - const unsigned char *next_frame = next_message(ptr, &msglen, &consumed); - munit_assert_ptr_equal(next_frame, buf + (i + 1) * framelen); - munit_assert_int(consumed, ==, framelen); - munit_assert_int(msglen, ==, 0xcd); - ptr += consumed; - } - - return MUNIT_OK; -} - -#define TEST(_func) \ - { .name = #_func, .test = _func } - -static MunitTest ei_tests[] = { - TEST(test_proto_next_message), - { NULL }, -}; - -static const MunitSuite libei_suite -__attribute__((used)) -__attribute__((section("test_section"))) = { - "", - ei_tests, - NULL, - 1, - MUNIT_SUITE_OPTION_NONE, -}; -#endif