summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPatrik Flykt <patrik.flykt@linux.intel.com>2013-12-09 23:43:14 +0200
committerZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>2013-12-12 11:43:33 -0500
commita10c375e02da66efec40e28142bc22fd8955e968 (patch)
tree8351fc1a84e95702a894509bee2fad7d79b3c888
parent78628cd27355a157bf44df1cb91f782150a7ca20 (diff)
dhcp: Add tests for DHCP options, file and sname fields
Add a structure describing the DHCP file, sname and trailing options fields. Create a messge holding these fields and call the internal option parsing function. In the test callback function verify that only regular options are passed and figure out which part of the DHCP message is the one that is being processed. As the test program knows the full contents of the test options in the test structure, skip all non-regular fields and verify that the option provided to the callback indeed is the one expected. Check also if non-regular option fields are to be ignored in the end of the option field as the callback is not called again and the final check when the whole message has been processed needs to be successful. Add a boolean flag for pretty-printing, anticipate there will be a nice option to toggle it in the future.
-rw-r--r--src/libsystemd-dhcp/test-dhcp-option.c260
1 files changed, 257 insertions, 3 deletions
diff --git a/src/libsystemd-dhcp/test-dhcp-option.c b/src/libsystemd-dhcp/test-dhcp-option.c
index cde8c29222..df717af06d 100644
--- a/src/libsystemd-dhcp/test-dhcp-option.c
+++ b/src/libsystemd-dhcp/test-dhcp-option.c
@@ -5,11 +5,74 @@
#include <string.h>
#include <assert.h>
-#include <util.h>
+#include "util.h"
+#include "macro.h"
#include "dhcp-protocol.h"
#include "dhcp-internal.h"
+struct option_desc {
+ uint8_t sname[64];
+ int snamelen;
+ uint8_t file[128];
+ int filelen;
+ uint8_t options[128];
+ int len;
+ bool success;
+ int filepos;
+ int snamepos;
+ int pos;
+};
+
+static bool verbose = false;
+
+static struct option_desc option_tests[] = {
+ { {}, 0, {}, 0, { 42, 5, 65, 66, 67, 68, 69 }, 7, false, },
+ { {}, 0, {}, 0, { 42, 5, 65, 66, 67, 68, 69, 0, 0,
+ DHCP_OPTION_MESSAGE_TYPE, 1, DHCP_ACK }, 12, true, },
+ { {}, 0, {}, 0, { 8, 255, 70, 71, 72 }, 5, false, },
+ { {}, 0, {}, 0, { 0x35, 0x01, 0x05, 0x36, 0x04, 0x01, 0x00, 0xa8,
+ 0xc0, 0x33, 0x04, 0x00, 0x01, 0x51, 0x80, 0x01,
+ 0x04, 0xff, 0xff, 0xff, 0x00, 0x03, 0x04, 0xc0,
+ 0xa8, 0x00, 0x01, 0x06, 0x04, 0xc0, 0xa8, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, },
+ 40, true, },
+ { {}, 0, {}, 0, { DHCP_OPTION_MESSAGE_TYPE, 1, DHCP_OFFER,
+ 42, 3, 0, 0, 0 }, 8, true, },
+ { {}, 0, {}, 0, { 42, 2, 1, 2, 44 }, 5, false, },
+
+ { {}, 0,
+ { 222, 3, 1, 2, 3, DHCP_OPTION_MESSAGE_TYPE, 1, DHCP_NAK }, 8,
+ { DHCP_OPTION_OVERLOAD, 1, DHCP_OVERLOAD_FILE }, 3, true, },
+
+ { { 1, 4, 1, 2, 3, 4, DHCP_OPTION_MESSAGE_TYPE, 1, DHCP_ACK }, 9,
+ { 222, 3, 1, 2, 3 }, 5,
+ { DHCP_OPTION_OVERLOAD, 1,
+ DHCP_OVERLOAD_FILE|DHCP_OVERLOAD_SNAME }, 3, true, },
+};
+
+static const char *dhcp_type(int type)
+{
+ switch(type) {
+ case DHCP_DISCOVER:
+ return "DHCPDISCOVER";
+ case DHCP_OFFER:
+ return "DHCPOFFER";
+ case DHCP_REQUEST:
+ return "DHCPREQUEST";
+ case DHCP_DECLINE:
+ return "DHCPDECLINE";
+ case DHCP_ACK:
+ return "DHCPACK";
+ case DHCP_NAK:
+ return "DHCPNAK";
+ case DHCP_RELEASE:
+ return "DHCPRELEASE";
+ default:
+ return "unknown";
+ }
+}
+
static void test_invalid_buffer_length(void)
{
DHCPMessage message;
@@ -21,7 +84,7 @@ static void test_invalid_buffer_length(void)
static void test_cookie(void)
{
- DHCPMessage *message;
+ _cleanup_free_ DHCPMessage *message;
size_t len = sizeof(DHCPMessage) + 4;
uint8_t *opt;
@@ -38,14 +101,205 @@ static void test_cookie(void)
opt[3] = 99;
assert(dhcp_option_parse(message, len, NULL, NULL) == -ENOMSG);
+}
+
+static DHCPMessage *create_message(uint8_t *options, uint16_t optlen,
+ uint8_t *file, uint8_t filelen,
+ uint8_t *sname, uint8_t snamelen)
+{
+ DHCPMessage *message;
+ size_t len = sizeof(DHCPMessage) + 4 + optlen;
+ uint8_t *opt;
- free(message);
+ message = malloc0(len);
+ opt = (uint8_t *)(message + 1);
+
+ opt[0] = 99;
+ opt[1] = 130;
+ opt[2] = 83;
+ opt[3] = 99;
+
+ if (options && optlen)
+ memcpy(&opt[4], options, optlen);
+
+ if (file && filelen <= 128)
+ memcpy(&message->file, file, filelen);
+
+ if (sname && snamelen <= 64)
+ memcpy(&message->sname, sname, snamelen);
+
+ return message;
+}
+
+static void test_ignore_opts(uint8_t *descoption, int *descpos, int *desclen)
+{
+ while (*descpos < *desclen) {
+ switch(descoption[*descpos]) {
+ case DHCP_OPTION_PAD:
+ *descpos += 1;
+ break;
+
+ case DHCP_OPTION_MESSAGE_TYPE:
+ case DHCP_OPTION_OVERLOAD:
+ *descpos += 3;
+ break;
+
+ default:
+ return;
+ }
+ }
+}
+
+static int test_options_cb(uint8_t code, uint8_t len, const uint8_t *option,
+ void *user_data)
+{
+ struct option_desc *desc = user_data;
+ uint8_t *descoption = NULL;
+ int *desclen = NULL, *descpos = NULL;
+ uint8_t optcode = 0;
+ uint8_t optlen = 0;
+ uint8_t i;
+
+ assert((!desc && !code && !len) || desc);
+
+ if (!desc)
+ return -EINVAL;
+
+ assert(code != DHCP_OPTION_PAD);
+ assert(code != DHCP_OPTION_END);
+ assert(code != DHCP_OPTION_MESSAGE_TYPE);
+ assert(code != DHCP_OPTION_OVERLOAD);
+
+ while (desc->pos >= 0 || desc->filepos >= 0 || desc->snamepos >= 0) {
+
+ if (desc->pos >= 0) {
+ descoption = &desc->options[0];
+ desclen = &desc->len;
+ descpos = &desc->pos;
+ } else if (desc->filepos >= 0) {
+ descoption = &desc->file[0];
+ desclen = &desc->filelen;
+ descpos = &desc->filepos;
+ } else if (desc->snamepos >= 0) {
+ descoption = &desc->sname[0];
+ desclen = &desc->snamelen;
+ descpos = &desc->snamepos;
+ }
+
+ assert(descoption && desclen && descpos);
+
+ if (*desclen)
+ test_ignore_opts(descoption, descpos, desclen);
+
+ if (*descpos < *desclen)
+ break;
+
+ if (*descpos == *desclen)
+ *descpos = -1;
+ }
+
+ assert(*descpos != -1);
+
+ optcode = descoption[*descpos];
+ optlen = descoption[*descpos + 1];
+
+ if (verbose)
+ printf("DHCP code %2d(%2d) len %2d(%2d) ", code, optcode,
+ len, optlen);
+
+ assert(code == optcode);
+ assert(len == optlen);
+
+ for (i = 0; i < len; i++) {
+
+ if (verbose)
+ printf("0x%02x(0x%02x) ", option[i],
+ descoption[*descpos + 2 + i]);
+
+ assert(option[i] == descoption[*descpos + 2 + i]);
+ }
+
+ if (verbose)
+ printf("\n");
+
+ *descpos += optlen + 2;
+
+ test_ignore_opts(descoption, descpos, desclen);
+
+ if (desc->pos != -1 && desc->pos == desc->len)
+ desc->pos = -1;
+
+ if (desc->filepos != -1 && desc->filepos == desc->filelen)
+ desc->filepos = -1;
+
+ if (desc->snamepos != -1 && desc->snamepos == desc->snamelen)
+ desc->snamepos = -1;
+
+ return 0;
+}
+
+static void test_options(struct option_desc *desc)
+{
+ uint8_t *options = NULL;
+ uint8_t *file = NULL;
+ uint8_t *sname = NULL;
+ int optlen = 0;
+ int filelen = 0;
+ int snamelen = 0;
+ int buflen = 0;
+ _cleanup_free_ DHCPMessage *message;
+ int res;
+
+ if (desc) {
+ file = &desc->file[0];
+ filelen = desc->filelen;
+ if (!filelen)
+ desc->filepos = -1;
+
+ sname = &desc->sname[0];
+ snamelen = desc->snamelen;
+ if (!snamelen)
+ desc->snamepos = -1;
+
+ options = &desc->options[0];
+ optlen = desc->len;
+ desc->pos = 0;
+ }
+ message = create_message(options, optlen, file, filelen,
+ sname, snamelen);
+
+ buflen = sizeof(DHCPMessage) + 4 + optlen;
+
+ if (!desc) {
+ assert((res = dhcp_option_parse(message, buflen,
+ test_options_cb,
+ NULL)) == -ENOMSG);
+ } else if (desc->success) {
+ assert((res = dhcp_option_parse(message, buflen,
+ test_options_cb,
+ desc)) >= 0);
+ assert(desc->pos == -1 && desc->filepos == -1 &&
+ desc->snamepos == -1);
+ } else
+ assert((res = dhcp_option_parse(message, buflen,
+ test_options_cb,
+ desc)) < 0);
+
+ if (verbose)
+ printf("DHCP type %s\n", dhcp_type(res));
}
int main(int argc, char *argv[])
{
+ unsigned int i;
+
test_invalid_buffer_length();
test_cookie();
+ test_options(NULL);
+
+ for (i = 0; i < ELEMENTSOF(option_tests); i++)
+ test_options(&option_tests[i]);
+
return 0;
}