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)
202 assert(*descpos != -1);
204 optcode = descoption[*descpos];
205 optlen = descoption[*descpos + 1];
208 printf("DHCP code %2d(%2d) len %2d(%2d) ", code, optcode,
211 assert(code == optcode);
212 assert(len == optlen);
214 for (i = 0; i < len; i++) {
217 printf("0x%02x(0x%02x) ", option[i],
218 descoption[*descpos + 2 + i]);
220 assert(option[i] == descoption[*descpos + 2 + i]);
226 *descpos += optlen + 2;
228 test_ignore_opts(descoption, descpos, desclen);
230 if (desc->pos != -1 && desc->pos == desc->len)
233 if (desc->filepos != -1 && desc->filepos == desc->filelen)
236 if (desc->snamepos != -1 && desc->snamepos == desc->snamelen)
242 static void test_options(struct option_desc *desc)
244 uint8_t *options = NULL;
245 uint8_t *file = NULL;
246 uint8_t *sname = NULL;
251 _cleanup_free_ DHCPMessage *message;
255 file = &desc->file[0];
256 filelen = desc->filelen;
260 sname = &desc->sname[0];
261 snamelen = desc->snamelen;
265 options = &desc->options[0];
269 message = create_message(options, optlen, file, filelen,
272 buflen = sizeof(DHCPMessage) + 4 + optlen;
275 assert((res = dhcp_option_parse(message, buflen,
278 } else if (desc->success) {
279 assert((res = dhcp_option_parse(message, buflen,
282 assert(desc->pos == -1 && desc->filepos == -1 &&
283 desc->snamepos == -1);
285 assert((res = dhcp_option_parse(message, buflen,
290 printf("DHCP type %s\n", dhcp_type(res));
293 static uint8_t result[64] = {
297 static uint8_t options[64] = {
301 31, 8, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38,
303 55, 3, 0x51, 0x52, 0x53,
304 17, 7, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
308 static void test_option_set(void)
314 assert(dhcp_option_append(NULL, NULL, 0, 0, NULL) == -EINVAL);
318 assert(dhcp_option_append(&opt, NULL, 0, 0, NULL) == -EINVAL);
319 assert(opt == &result[0] && len == 0);
321 assert(dhcp_option_append(&opt, &len, DHCP_OPTION_PAD,
322 0, NULL) == -ENOBUFS);
323 assert(opt == &result[0] && len == 0);
327 assert(dhcp_option_append(&opt, &len, DHCP_OPTION_PAD,
329 assert(opt == &result[5] && len == 0);
333 while (pos < 64 && options[pos] != DHCP_OPTION_END) {
337 assert(dhcp_option_append(&opt, &len, options[pos],
339 &options[pos + 2]) >= 0);
341 if (options[pos] == DHCP_OPTION_PAD) {
342 assert(opt == &result[pos + 1]);
343 assert(len == oldlen - 1);
346 assert(opt == &result[pos + 2 + options[pos + 1]]);
347 assert(len == oldlen - 2 - options[pos + 1]);
348 pos += 2 + options[pos + 1];
352 for (i = 0; i < pos; i++) {
354 printf("%2d: 0x%02x(0x%02x)\n", i, result[i],
356 assert(result[i] == options[i]);
363 int main(int argc, char *argv[])
367 test_invalid_buffer_length();
372 for (i = 0; i < ELEMENTSOF(option_tests); i++)
373 test_options(&option_tests[i]);