11 #include "dhcp-protocol.h"
12 #include "dhcp-internal.h"
27 static bool verbose = false;
29 static struct option_desc option_tests[] = {
30 { {}, 0, {}, 0, { 42, 5, 65, 66, 67, 68, 69 }, 7, false, },
31 { {}, 0, {}, 0, { 42, 5, 65, 66, 67, 68, 69, 0, 0,
32 DHCP_OPTION_MESSAGE_TYPE, 1, DHCP_ACK }, 12, true, },
33 { {}, 0, {}, 0, { 8, 255, 70, 71, 72 }, 5, false, },
34 { {}, 0, {}, 0, { 0x35, 0x01, 0x05, 0x36, 0x04, 0x01, 0x00, 0xa8,
35 0xc0, 0x33, 0x04, 0x00, 0x01, 0x51, 0x80, 0x01,
36 0x04, 0xff, 0xff, 0xff, 0x00, 0x03, 0x04, 0xc0,
37 0xa8, 0x00, 0x01, 0x06, 0x04, 0xc0, 0xa8, 0x00,
38 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, },
40 { {}, 0, {}, 0, { DHCP_OPTION_MESSAGE_TYPE, 1, DHCP_OFFER,
41 42, 3, 0, 0, 0 }, 8, true, },
42 { {}, 0, {}, 0, { 42, 2, 1, 2, 44 }, 5, false, },
45 { 222, 3, 1, 2, 3, DHCP_OPTION_MESSAGE_TYPE, 1, DHCP_NAK }, 8,
46 { DHCP_OPTION_OVERLOAD, 1, DHCP_OVERLOAD_FILE }, 3, true, },
48 { { 1, 4, 1, 2, 3, 4, DHCP_OPTION_MESSAGE_TYPE, 1, DHCP_ACK }, 9,
49 { 222, 3, 1, 2, 3 }, 5,
50 { DHCP_OPTION_OVERLOAD, 1,
51 DHCP_OVERLOAD_FILE|DHCP_OVERLOAD_SNAME }, 3, true, },
54 static const char *dhcp_type(int type)
58 return "DHCPDISCOVER";
76 static void test_invalid_buffer_length(void)
80 assert(dhcp_option_parse(&message, 0, NULL, NULL) == -EINVAL);
81 assert(dhcp_option_parse(&message, sizeof(DHCPMessage), NULL, NULL)
85 static void test_cookie(void)
87 _cleanup_free_ DHCPMessage *message;
88 size_t len = sizeof(DHCPMessage) + 4;
91 message = malloc0(len);
93 opt = (uint8_t *)(message + 1);
96 assert(dhcp_option_parse(message, len, NULL, NULL) == -EINVAL);
103 assert(dhcp_option_parse(message, len, NULL, NULL) == -ENOMSG);
106 static DHCPMessage *create_message(uint8_t *options, uint16_t optlen,
107 uint8_t *file, uint8_t filelen,
108 uint8_t *sname, uint8_t snamelen)
110 DHCPMessage *message;
111 size_t len = sizeof(DHCPMessage) + 4 + optlen;
114 message = malloc0(len);
115 opt = (uint8_t *)(message + 1);
122 if (options && optlen)
123 memcpy(&opt[4], options, optlen);
125 if (file && filelen <= 128)
126 memcpy(&message->file, file, filelen);
128 if (sname && snamelen <= 64)
129 memcpy(&message->sname, sname, snamelen);
134 static void test_ignore_opts(uint8_t *descoption, int *descpos, int *desclen)
136 while (*descpos < *desclen) {
137 switch(descoption[*descpos]) {
138 case DHCP_OPTION_PAD:
142 case DHCP_OPTION_MESSAGE_TYPE:
143 case DHCP_OPTION_OVERLOAD:
153 static int test_options_cb(uint8_t code, uint8_t len, const uint8_t *option,
156 struct option_desc *desc = user_data;
157 uint8_t *descoption = NULL;
158 int *desclen = NULL, *descpos = NULL;
163 assert((!desc && !code && !len) || desc);
168 assert(code != DHCP_OPTION_PAD);
169 assert(code != DHCP_OPTION_END);
170 assert(code != DHCP_OPTION_MESSAGE_TYPE);
171 assert(code != DHCP_OPTION_OVERLOAD);
173 while (desc->pos >= 0 || desc->filepos >= 0 || desc->snamepos >= 0) {
175 if (desc->pos >= 0) {
176 descoption = &desc->options[0];
177 desclen = &desc->len;
178 descpos = &desc->pos;
179 } else if (desc->filepos >= 0) {
180 descoption = &desc->file[0];
181 desclen = &desc->filelen;
182 descpos = &desc->filepos;
183 } else if (desc->snamepos >= 0) {
184 descoption = &desc->sname[0];
185 desclen = &desc->snamelen;
186 descpos = &desc->snamepos;
189 assert(descoption && desclen && descpos);
192 test_ignore_opts(descoption, descpos, desclen);
194 if (*descpos < *desclen)
197 if (*descpos == *desclen)
201 assert(*descpos != -1);
203 optcode = descoption[*descpos];
204 optlen = descoption[*descpos + 1];
207 printf("DHCP code %2d(%2d) len %2d(%2d) ", code, optcode,
210 assert(code == optcode);
211 assert(len == optlen);
213 for (i = 0; i < len; i++) {
216 printf("0x%02x(0x%02x) ", option[i],
217 descoption[*descpos + 2 + i]);
219 assert(option[i] == descoption[*descpos + 2 + i]);
225 *descpos += optlen + 2;
227 test_ignore_opts(descoption, descpos, desclen);
229 if (desc->pos != -1 && desc->pos == desc->len)
232 if (desc->filepos != -1 && desc->filepos == desc->filelen)
235 if (desc->snamepos != -1 && desc->snamepos == desc->snamelen)
241 static void test_options(struct option_desc *desc)
243 uint8_t *options = NULL;
244 uint8_t *file = NULL;
245 uint8_t *sname = NULL;
250 _cleanup_free_ DHCPMessage *message;
254 file = &desc->file[0];
255 filelen = desc->filelen;
259 sname = &desc->sname[0];
260 snamelen = desc->snamelen;
264 options = &desc->options[0];
268 message = create_message(options, optlen, file, filelen,
271 buflen = sizeof(DHCPMessage) + 4 + optlen;
274 assert((res = dhcp_option_parse(message, buflen,
277 } else if (desc->success) {
278 assert((res = dhcp_option_parse(message, buflen,
281 assert(desc->pos == -1 && desc->filepos == -1 &&
282 desc->snamepos == -1);
284 assert((res = dhcp_option_parse(message, buflen,
289 printf("DHCP type %s\n", dhcp_type(res));
292 static uint8_t result[64] = {
296 static uint8_t options[64] = {
300 31, 8, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38,
302 55, 3, 0x51, 0x52, 0x53,
303 17, 7, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
307 static void test_option_set(void)
313 assert(dhcp_option_append(NULL, NULL, 0, 0, NULL) == -EINVAL);
317 assert(dhcp_option_append(&opt, NULL, 0, 0, NULL) == -EINVAL);
318 assert(opt == &result[0] && len == 0);
320 assert(dhcp_option_append(&opt, &len, DHCP_OPTION_PAD,
321 0, NULL) == -ENOBUFS);
322 assert(opt == &result[0] && len == 0);
326 assert(dhcp_option_append(&opt, &len, DHCP_OPTION_PAD,
328 assert(opt == &result[5] && len == 0);
332 while (pos < 64 && options[pos] != DHCP_OPTION_END) {
336 assert(dhcp_option_append(&opt, &len, options[pos],
338 &options[pos + 2]) >= 0);
340 if (options[pos] == DHCP_OPTION_PAD) {
341 assert(opt == &result[pos + 1]);
342 assert(len == oldlen - 1);
345 assert(opt == &result[pos + 2 + options[pos + 1]]);
346 assert(len == oldlen - 2 - options[pos + 1]);
347 pos += 2 + options[pos + 1];
351 for (i = 0; i < pos; i++) {
353 printf("%2d: 0x%02x(0x%02x)\n", i, result[i],
355 assert(result[i] == options[i]);
362 int main(int argc, char *argv[])
366 test_invalid_buffer_length();
371 for (i = 0; i < ELEMENTSOF(option_tests); i++)
372 test_options(&option_tests[i]);