6 #include "alloc-util.h"
7 #include "dhcp-internal.h"
8 #include "dhcp-protocol.h"
25 static bool verbose
= false;
27 static struct option_desc option_tests
[] = {
28 { {}, 0, {}, 0, { 42, 5, 65, 66, 67, 68, 69 }, 7, false, },
29 { {}, 0, {}, 0, { 42, 5, 65, 66, 67, 68, 69, 0, 0,
30 SD_DHCP_OPTION_MESSAGE_TYPE
, 1, DHCP_ACK
}, 12, true, },
31 { {}, 0, {}, 0, { 8, 255, 70, 71, 72 }, 5, false, },
32 { {}, 0, {}, 0, { 0x35, 0x01, 0x05, 0x36, 0x04, 0x01, 0x00, 0xa8,
33 0xc0, 0x33, 0x04, 0x00, 0x01, 0x51, 0x80, 0x01,
34 0x04, 0xff, 0xff, 0xff, 0x00, 0x03, 0x04, 0xc0,
35 0xa8, 0x00, 0x01, 0x06, 0x04, 0xc0, 0xa8, 0x00,
36 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, },
38 { {}, 0, {}, 0, { SD_DHCP_OPTION_MESSAGE_TYPE
, 1, DHCP_OFFER
,
39 42, 3, 0, 0, 0 }, 8, true, },
40 { {}, 0, {}, 0, { 42, 2, 1, 2, 44 }, 5, false, },
43 { 222, 3, 1, 2, 3, SD_DHCP_OPTION_MESSAGE_TYPE
, 1, DHCP_NAK
}, 8,
44 { SD_DHCP_OPTION_OVERLOAD
, 1, DHCP_OVERLOAD_FILE
}, 3, true, },
46 { { 1, 4, 1, 2, 3, 4, SD_DHCP_OPTION_MESSAGE_TYPE
, 1, DHCP_ACK
}, 9,
47 { 222, 3, 1, 2, 3 }, 5,
48 { SD_DHCP_OPTION_OVERLOAD
, 1,
49 DHCP_OVERLOAD_FILE
|DHCP_OVERLOAD_SNAME
}, 3, true, },
52 static const char *dhcp_type(int type
) {
55 return "DHCPDISCOVER";
73 static void test_invalid_buffer_length(void) {
76 assert_se(dhcp_option_parse(&message
, 0, NULL
, NULL
, NULL
) == -EINVAL
);
77 assert_se(dhcp_option_parse(&message
, sizeof(DHCPMessage
) - 1, NULL
, NULL
, NULL
) == -EINVAL
);
80 static void test_message_init(void) {
81 _cleanup_free_ DHCPMessage
*message
= NULL
;
82 size_t optlen
= 4, optoffset
;
83 size_t len
= sizeof(DHCPMessage
) + optlen
;
86 message
= malloc0(len
);
88 assert_se(dhcp_message_init(message
, BOOTREQUEST
, 0x12345678,
89 DHCP_DISCOVER
, ARPHRD_ETHER
, optlen
, &optoffset
) >= 0);
91 assert_se(message
->xid
== htobe32(0x12345678));
92 assert_se(message
->op
== BOOTREQUEST
);
94 magic
= (uint8_t*)&message
->magic
;
96 assert_se(magic
[0] == 99);
97 assert_se(magic
[1] == 130);
98 assert_se(magic
[2] == 83);
99 assert_se(magic
[3] == 99);
101 assert_se(dhcp_option_parse(message
, len
, NULL
, NULL
, NULL
) >= 0);
104 static DHCPMessage
*create_message(uint8_t *options
, uint16_t optlen
,
105 uint8_t *file
, uint8_t filelen
,
106 uint8_t *sname
, uint8_t snamelen
) {
107 DHCPMessage
*message
;
108 size_t len
= sizeof(DHCPMessage
) + optlen
;
110 message
= malloc0(len
);
113 memcpy_safe(&message
->options
, options
, optlen
);
114 memcpy_safe(&message
->file
, file
, filelen
);
115 memcpy_safe(&message
->sname
, sname
, snamelen
);
120 static void test_ignore_opts(uint8_t *descoption
, int *descpos
, int *desclen
) {
121 assert(*descpos
>= 0);
123 while (*descpos
< *desclen
) {
124 switch(descoption
[*descpos
]) {
125 case SD_DHCP_OPTION_PAD
:
129 case SD_DHCP_OPTION_MESSAGE_TYPE
:
130 case SD_DHCP_OPTION_OVERLOAD
:
140 static int test_options_cb(uint8_t code
, uint8_t len
, const void *option
, void *userdata
) {
141 struct option_desc
*desc
= userdata
;
142 uint8_t *descoption
= NULL
;
143 int *desclen
= NULL
, *descpos
= NULL
;
148 assert_se((!desc
&& !code
&& !len
) || desc
);
153 assert_se(code
!= SD_DHCP_OPTION_PAD
);
154 assert_se(code
!= SD_DHCP_OPTION_END
);
155 assert_se(code
!= SD_DHCP_OPTION_MESSAGE_TYPE
);
156 assert_se(code
!= SD_DHCP_OPTION_OVERLOAD
);
158 while (desc
->pos
>= 0 || desc
->filepos
>= 0 || desc
->snamepos
>= 0) {
160 if (desc
->pos
>= 0) {
161 descoption
= &desc
->options
[0];
162 desclen
= &desc
->len
;
163 descpos
= &desc
->pos
;
164 } else if (desc
->filepos
>= 0) {
165 descoption
= &desc
->file
[0];
166 desclen
= &desc
->filelen
;
167 descpos
= &desc
->filepos
;
168 } else if (desc
->snamepos
>= 0) {
169 descoption
= &desc
->sname
[0];
170 desclen
= &desc
->snamelen
;
171 descpos
= &desc
->snamepos
;
174 assert_se(descoption
&& desclen
&& descpos
);
177 test_ignore_opts(descoption
, descpos
, desclen
);
179 if (*descpos
< *desclen
)
182 if (*descpos
== *desclen
)
187 assert_se(*descpos
!= -1);
189 optcode
= descoption
[*descpos
];
190 optlen
= descoption
[*descpos
+ 1];
193 printf("DHCP code %2d(%2d) len %2d(%2d) ", code
, optcode
,
196 assert_se(code
== optcode
);
197 assert_se(len
== optlen
);
199 for (i
= 0; i
< len
; i
++) {
202 printf("0x%02x(0x%02x) ", ((uint8_t*) option
)[i
],
203 descoption
[*descpos
+ 2 + i
]);
205 assert_se(((uint8_t*) option
)[i
] == descoption
[*descpos
+ 2 + i
]);
211 *descpos
+= optlen
+ 2;
213 test_ignore_opts(descoption
, descpos
, desclen
);
215 if (desc
->pos
!= -1 && desc
->pos
== desc
->len
)
218 if (desc
->filepos
!= -1 && desc
->filepos
== desc
->filelen
)
221 if (desc
->snamepos
!= -1 && desc
->snamepos
== desc
->snamelen
)
227 static void test_options(struct option_desc
*desc
) {
228 uint8_t *options
= NULL
;
229 uint8_t *file
= NULL
;
230 uint8_t *sname
= NULL
;
235 _cleanup_free_ DHCPMessage
*message
= NULL
;
239 file
= &desc
->file
[0];
240 filelen
= desc
->filelen
;
244 sname
= &desc
->sname
[0];
245 snamelen
= desc
->snamelen
;
249 options
= &desc
->options
[0];
253 message
= create_message(options
, optlen
, file
, filelen
,
256 buflen
= sizeof(DHCPMessage
) + optlen
;
259 assert_se((res
= dhcp_option_parse(message
, buflen
, test_options_cb
, NULL
, NULL
)) == -ENOMSG
);
260 } else if (desc
->success
) {
261 assert_se((res
= dhcp_option_parse(message
, buflen
, test_options_cb
, desc
, NULL
)) >= 0);
262 assert_se(desc
->pos
== -1 && desc
->filepos
== -1 && desc
->snamepos
== -1);
264 assert_se((res
= dhcp_option_parse(message
, buflen
, test_options_cb
, desc
, NULL
)) < 0);
267 printf("DHCP type %s\n", dhcp_type(res
));
270 static uint8_t options
[64] = {
274 31, 8, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38,
276 55, 3, 0x51, 0x52, 0x53,
277 17, 7, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
281 static void test_option_set(void) {
282 _cleanup_free_ DHCPMessage
*result
= NULL
;
283 size_t offset
= 0, len
, pos
;
286 result
= malloc0(sizeof(DHCPMessage
) + 11);
289 result
->options
[0] = 'A';
290 result
->options
[1] = 'B';
291 result
->options
[2] = 'C';
292 result
->options
[3] = 'D';
294 assert_se(dhcp_option_append(result
, 0, &offset
, 0, SD_DHCP_OPTION_PAD
,
295 0, NULL
) == -ENOBUFS
);
296 assert_se(offset
== 0);
299 assert_se(dhcp_option_append(result
, 5, &offset
, 0, SD_DHCP_OPTION_PAD
,
300 0, NULL
) == -ENOBUFS
);
301 assert_se(offset
== 4);
302 assert_se(dhcp_option_append(result
, 6, &offset
, 0, SD_DHCP_OPTION_PAD
,
304 assert_se(offset
== 5);
308 while (pos
< len
&& options
[pos
] != SD_DHCP_OPTION_END
) {
309 assert_se(dhcp_option_append(result
, len
, &offset
, DHCP_OVERLOAD_SNAME
,
312 &options
[pos
+ 2]) >= 0);
314 if (options
[pos
] == SD_DHCP_OPTION_PAD
)
317 pos
+= 2 + options
[pos
+ 1];
320 assert_se(offset
== pos
);
323 for (i
= 0; i
< 9; i
++) {
325 printf("%2u: 0x%02x(0x%02x) (options)\n", i
, result
->options
[i
],
327 assert_se(result
->options
[i
] == options
[i
]);
331 printf("%2d: 0x%02x(0x%02x) (options)\n", 9, result
->options
[9],
334 assert_se(result
->options
[9] == SD_DHCP_OPTION_END
);
337 printf("%2d: 0x%02x(0x%02x) (options)\n", 10, result
->options
[10],
340 assert_se(result
->options
[10] == SD_DHCP_OPTION_PAD
);
342 for (i
= 0; i
< pos
- 8; i
++) {
344 printf("%2u: 0x%02x(0x%02x) (sname)\n", i
, result
->sname
[i
],
346 assert_se(result
->sname
[i
] == options
[i
+ 9]);
353 int main(int argc
, char *argv
[]) {
356 test_invalid_buffer_length();
361 for (i
= 0; i
< ELEMENTSOF(option_tests
); i
++)
362 test_options(&option_tests
[i
]);