1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
8 #include "alloc-util.h"
9 #include "dhcp-internal.h"
10 #include "dhcp-protocol.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
) {
57 return "DHCPDISCOVER";
75 static void test_invalid_buffer_length(void) {
78 assert_se(dhcp_option_parse(&message
, 0, NULL
, NULL
) == -EINVAL
);
79 assert_se(dhcp_option_parse(&message
, sizeof(DHCPMessage
) - 1, NULL
, NULL
)
83 static void test_message_init(void) {
84 _cleanup_free_ DHCPMessage
*message
= NULL
;
85 size_t optlen
= 4, optoffset
;
86 size_t len
= sizeof(DHCPMessage
) + optlen
;
89 message
= malloc0(len
);
91 assert_se(dhcp_message_init(message
, BOOTREQUEST
, 0x12345678,
92 DHCP_DISCOVER
, ARPHRD_ETHER
, optlen
, &optoffset
) >= 0);
94 assert_se(message
->xid
== htobe32(0x12345678));
95 assert_se(message
->op
== BOOTREQUEST
);
97 magic
= (uint8_t*)&message
->magic
;
99 assert_se(magic
[0] == 99);
100 assert_se(magic
[1] == 130);
101 assert_se(magic
[2] == 83);
102 assert_se(magic
[3] == 99);
104 assert_se(dhcp_option_parse(message
, len
, NULL
, NULL
) >= 0);
107 static DHCPMessage
*create_message(uint8_t *options
, uint16_t optlen
,
108 uint8_t *file
, uint8_t filelen
,
109 uint8_t *sname
, uint8_t snamelen
) {
110 DHCPMessage
*message
;
111 size_t len
= sizeof(DHCPMessage
) + optlen
;
113 message
= malloc0(len
);
116 if (options
&& optlen
)
117 memcpy(&message
->options
, options
, optlen
);
119 if (file
&& filelen
<= 128)
120 memcpy(&message
->file
, file
, filelen
);
122 if (sname
&& snamelen
<= 64)
123 memcpy(&message
->sname
, sname
, snamelen
);
128 static void test_ignore_opts(uint8_t *descoption
, int *descpos
, int *desclen
) {
129 assert(*descpos
>= 0);
131 while (*descpos
< *desclen
) {
132 switch(descoption
[*descpos
]) {
133 case DHCP_OPTION_PAD
:
137 case DHCP_OPTION_MESSAGE_TYPE
:
138 case DHCP_OPTION_OVERLOAD
:
148 static int test_options_cb(uint8_t code
, uint8_t len
, const void *option
, void *userdata
) {
149 struct option_desc
*desc
= userdata
;
150 uint8_t *descoption
= NULL
;
151 int *desclen
= NULL
, *descpos
= NULL
;
156 assert_se((!desc
&& !code
&& !len
) || desc
);
161 assert_se(code
!= DHCP_OPTION_PAD
);
162 assert_se(code
!= DHCP_OPTION_END
);
163 assert_se(code
!= DHCP_OPTION_MESSAGE_TYPE
);
164 assert_se(code
!= DHCP_OPTION_OVERLOAD
);
166 while (desc
->pos
>= 0 || desc
->filepos
>= 0 || desc
->snamepos
>= 0) {
168 if (desc
->pos
>= 0) {
169 descoption
= &desc
->options
[0];
170 desclen
= &desc
->len
;
171 descpos
= &desc
->pos
;
172 } else if (desc
->filepos
>= 0) {
173 descoption
= &desc
->file
[0];
174 desclen
= &desc
->filelen
;
175 descpos
= &desc
->filepos
;
176 } else if (desc
->snamepos
>= 0) {
177 descoption
= &desc
->sname
[0];
178 desclen
= &desc
->snamelen
;
179 descpos
= &desc
->snamepos
;
182 assert_se(descoption
&& desclen
&& descpos
);
185 test_ignore_opts(descoption
, descpos
, desclen
);
187 if (*descpos
< *desclen
)
190 if (*descpos
== *desclen
)
195 assert_se(*descpos
!= -1);
197 optcode
= descoption
[*descpos
];
198 optlen
= descoption
[*descpos
+ 1];
201 printf("DHCP code %2d(%2d) len %2d(%2d) ", code
, optcode
,
204 assert_se(code
== optcode
);
205 assert_se(len
== optlen
);
207 for (i
= 0; i
< len
; i
++) {
210 printf("0x%02x(0x%02x) ", ((uint8_t*) option
)[i
],
211 descoption
[*descpos
+ 2 + i
]);
213 assert_se(((uint8_t*) option
)[i
] == descoption
[*descpos
+ 2 + i
]);
219 *descpos
+= optlen
+ 2;
221 test_ignore_opts(descoption
, descpos
, desclen
);
223 if (desc
->pos
!= -1 && desc
->pos
== desc
->len
)
226 if (desc
->filepos
!= -1 && desc
->filepos
== desc
->filelen
)
229 if (desc
->snamepos
!= -1 && desc
->snamepos
== desc
->snamelen
)
235 static void test_options(struct option_desc
*desc
) {
236 uint8_t *options
= NULL
;
237 uint8_t *file
= NULL
;
238 uint8_t *sname
= NULL
;
243 _cleanup_free_ DHCPMessage
*message
= NULL
;
247 file
= &desc
->file
[0];
248 filelen
= desc
->filelen
;
252 sname
= &desc
->sname
[0];
253 snamelen
= desc
->snamelen
;
257 options
= &desc
->options
[0];
261 message
= create_message(options
, optlen
, file
, filelen
,
264 buflen
= sizeof(DHCPMessage
) + optlen
;
267 assert_se((res
= dhcp_option_parse(message
, buflen
,
270 } else if (desc
->success
) {
271 assert_se((res
= dhcp_option_parse(message
, buflen
,
274 assert_se(desc
->pos
== -1 && desc
->filepos
== -1 &&
275 desc
->snamepos
== -1);
277 assert_se((res
= dhcp_option_parse(message
, buflen
,
282 printf("DHCP type %s\n", dhcp_type(res
));
285 static uint8_t options
[64] = {
289 31, 8, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38,
291 55, 3, 0x51, 0x52, 0x53,
292 17, 7, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
296 static void test_option_set(void) {
297 _cleanup_free_ DHCPMessage
*result
= NULL
;
298 size_t offset
= 0, len
, pos
;
301 result
= malloc0(sizeof(DHCPMessage
) + 11);
304 result
->options
[0] = 'A';
305 result
->options
[1] = 'B';
306 result
->options
[2] = 'C';
307 result
->options
[3] = 'D';
309 assert_se(dhcp_option_append(result
, 0, &offset
, 0, DHCP_OPTION_PAD
,
310 0, NULL
) == -ENOBUFS
);
311 assert_se(offset
== 0);
314 assert_se(dhcp_option_append(result
, 5, &offset
, 0, DHCP_OPTION_PAD
,
315 0, NULL
) == -ENOBUFS
);
316 assert_se(offset
== 4);
317 assert_se(dhcp_option_append(result
, 6, &offset
, 0, DHCP_OPTION_PAD
,
319 assert_se(offset
== 5);
323 while (pos
< len
&& options
[pos
] != DHCP_OPTION_END
) {
324 assert_se(dhcp_option_append(result
, len
, &offset
, DHCP_OVERLOAD_SNAME
,
327 &options
[pos
+ 2]) >= 0);
329 if (options
[pos
] == DHCP_OPTION_PAD
)
332 pos
+= 2 + options
[pos
+ 1];
335 assert_se(offset
== pos
);
338 for (i
= 0; i
< 9; i
++) {
340 printf("%2u: 0x%02x(0x%02x) (options)\n", i
, result
->options
[i
],
342 assert_se(result
->options
[i
] == options
[i
]);
346 printf("%2d: 0x%02x(0x%02x) (options)\n", 9, result
->options
[9],
349 assert_se(result
->options
[9] == DHCP_OPTION_END
);
352 printf("%2d: 0x%02x(0x%02x) (options)\n", 10, result
->options
[10],
355 assert_se(result
->options
[10] == DHCP_OPTION_PAD
);
357 for (i
= 0; i
< pos
- 8; i
++) {
359 printf("%2u: 0x%02x(0x%02x) (sname)\n", i
, result
->sname
[i
],
361 assert_se(result
->sname
[i
] == options
[i
+ 9]);
368 int main(int argc
, char *argv
[]) {
371 test_invalid_buffer_length();
376 for (i
= 0; i
< ELEMENTSOF(option_tests
); i
++)
377 test_options(&option_tests
[i
]);