On Wed, Nov 13, 2013 at 11:22:36PM +0200, Patrik Flykt wrote: > 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. > --- > src/dhcp/test-dhcp-option.c | 258 > +++++++++++++++++++++++++++++++++++++++++++ > 1 file changed, 258 insertions(+) > > diff --git a/src/dhcp/test-dhcp-option.c b/src/dhcp/test-dhcp-option.c > index 9302fd6..a2b79ce 100644 > --- a/src/dhcp/test-dhcp-option.c > +++ b/src/dhcp/test-dhcp-option.c > @@ -10,6 +10,68 @@ > #include "protocol.h" > #include "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; > @@ -43,10 +105,206 @@ static void test_cookie(void) > free(message); > } > > +static DHCPMessage *create_message(uint8_t *options, uint16_t optlen, > + uint8_t *file, uint8_t filelen, > + uint8_t *sname, uint8_t snamelen) > +{ > + DHCPMessage *message; > + int len = sizeof(DHCPMessage) + 4 + optlen; > + uint8_t *opt; > + > + 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, 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; > + DHCPMessage *message; _cleanup_free_
> + 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)); > + > + free(message); > +} > + > int main(int argc, char *argv[]) > { > + unsigned int i; > + > test_invalid_buffer_length(); > test_cookie(); > > + test_options(NULL); > + > + for (i = 0; i < sizeof(option_tests)/sizeof(struct option_desc); i++) ELEMENTSOF > + test_options(&option_tests[i]); > + > return 0; > } Zbyszek _______________________________________________ systemd-devel mailing list systemd-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/systemd-devel