chiark / gitweb /
Remove src/backlight
[elogind.git] / src / libsystemd-network / test-dhcp-option.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 #include <stdio.h>
4 #include <stdbool.h>
5 #include <errno.h>
6 #include <string.h>
7
8 #include "util.h"
9 #include "macro.h"
10
11 #include "dhcp-protocol.h"
12 #include "dhcp-internal.h"
13
14 struct option_desc {
15         uint8_t sname[64];
16         int snamelen;
17         uint8_t file[128];
18         int filelen;
19         uint8_t options[128];
20         int len;
21         bool success;
22         int filepos;
23         int snamepos;
24         int pos;
25 };
26
27 static bool verbose = false;
28
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, },
39           40, true, },
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, },
43
44         { {}, 0,
45           { 222, 3, 1, 2, 3, DHCP_OPTION_MESSAGE_TYPE, 1, DHCP_NAK }, 8,
46           { DHCP_OPTION_OVERLOAD, 1, DHCP_OVERLOAD_FILE }, 3, true, },
47
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, },
52 };
53
54 static const char *dhcp_type(int type) {
55         switch(type) {
56         case DHCP_DISCOVER:
57                 return "DHCPDISCOVER";
58         case DHCP_OFFER:
59                 return "DHCPOFFER";
60         case DHCP_REQUEST:
61                 return "DHCPREQUEST";
62         case DHCP_DECLINE:
63                 return "DHCPDECLINE";
64         case DHCP_ACK:
65                 return "DHCPACK";
66         case DHCP_NAK:
67                 return "DHCPNAK";
68         case DHCP_RELEASE:
69                 return "DHCPRELEASE";
70         default:
71                 return "unknown";
72         }
73 }
74
75 static void test_invalid_buffer_length(void) {
76         DHCPMessage message;
77
78         assert_se(dhcp_option_parse(&message, 0, NULL, NULL) == -EINVAL);
79         assert_se(dhcp_option_parse(&message, sizeof(DHCPMessage) - 1, NULL, NULL)
80                == -EINVAL);
81 }
82
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;
87         uint8_t *magic;
88
89         message = malloc0(len);
90
91         assert_se(dhcp_message_init(message, BOOTREQUEST, 0x12345678,
92                   DHCP_DISCOVER, ARPHRD_ETHER, optlen, &optoffset) >= 0);
93
94         assert_se(message->xid == htobe32(0x12345678));
95         assert_se(message->op == BOOTREQUEST);
96
97         magic = (uint8_t*)&message->magic;
98
99         assert_se(magic[0] == 99);
100         assert_se(magic[1] == 130);
101         assert_se(magic[2] == 83);
102         assert_se(magic[3] == 99);
103
104         assert_se(dhcp_option_parse(message, len, NULL, NULL) >= 0);
105 }
106
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;
112
113         message = malloc0(len);
114         assert_se(message);
115
116         if (options && optlen)
117                 memcpy(&message->options, options, optlen);
118
119         if (file && filelen <= 128)
120                 memcpy(&message->file, file, filelen);
121
122         if (sname && snamelen <= 64)
123                 memcpy(&message->sname, sname, snamelen);
124
125         return message;
126 }
127
128 static void test_ignore_opts(uint8_t *descoption, int *descpos, int *desclen) {
129         assert(*descpos >= 0);
130
131         while (*descpos < *desclen) {
132                 switch(descoption[*descpos]) {
133                 case DHCP_OPTION_PAD:
134                         *descpos += 1;
135                         break;
136
137                 case DHCP_OPTION_MESSAGE_TYPE:
138                 case DHCP_OPTION_OVERLOAD:
139                         *descpos += 3;
140                         break;
141
142                 default:
143                         return;
144                 }
145         }
146 }
147
148 static int test_options_cb(uint8_t code, uint8_t len, const uint8_t *option, void *user_data) {
149         struct option_desc *desc = user_data;
150         uint8_t *descoption = NULL;
151         int *desclen = NULL, *descpos = NULL;
152         uint8_t optcode = 0;
153         uint8_t optlen = 0;
154         uint8_t i;
155
156         assert_se((!desc && !code && !len) || desc);
157
158         if (!desc)
159                 return -EINVAL;
160
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);
165
166         while (desc->pos >= 0 || desc->filepos >= 0 || desc->snamepos >= 0) {
167
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;
180                 }
181
182                 assert_se(descoption && desclen && descpos);
183
184                 if (*desclen)
185                         test_ignore_opts(descoption, descpos, desclen);
186
187                 if (*descpos < *desclen)
188                         break;
189
190                 if (*descpos == *desclen)
191                         *descpos = -1;
192         }
193
194         assert_se(descpos);
195         assert_se(*descpos != -1);
196
197         optcode = descoption[*descpos];
198         optlen = descoption[*descpos + 1];
199
200         if (verbose)
201                 printf("DHCP code %2d(%2d) len %2d(%2d) ", code, optcode,
202                                 len, optlen);
203
204         assert_se(code == optcode);
205         assert_se(len == optlen);
206
207         for (i = 0; i < len; i++) {
208
209                 if (verbose)
210                         printf("0x%02x(0x%02x) ", option[i],
211                                         descoption[*descpos + 2 + i]);
212
213                 assert_se(option[i] == descoption[*descpos + 2 + i]);
214         }
215
216         if (verbose)
217                 printf("\n");
218
219         *descpos += optlen + 2;
220
221         test_ignore_opts(descoption, descpos, desclen);
222
223         if (desc->pos != -1 && desc->pos == desc->len)
224                 desc->pos = -1;
225
226         if (desc->filepos != -1 && desc->filepos == desc->filelen)
227                 desc->filepos = -1;
228
229         if (desc->snamepos != -1 && desc->snamepos == desc->snamelen)
230                 desc->snamepos = -1;
231
232         return 0;
233 }
234
235 static void test_options(struct option_desc *desc) {
236         uint8_t *options = NULL;
237         uint8_t *file = NULL;
238         uint8_t *sname = NULL;
239         int optlen = 0;
240         int filelen = 0;
241         int snamelen = 0;
242         int buflen = 0;
243         _cleanup_free_ DHCPMessage *message = NULL;
244         int res;
245
246         if (desc) {
247                 file = &desc->file[0];
248                 filelen = desc->filelen;
249                 if (!filelen)
250                         desc->filepos = -1;
251
252                 sname = &desc->sname[0];
253                 snamelen = desc->snamelen;
254                 if (!snamelen)
255                         desc->snamepos = -1;
256
257                 options = &desc->options[0];
258                 optlen = desc->len;
259                 desc->pos = 0;
260         }
261         message = create_message(options, optlen, file, filelen,
262                                  sname, snamelen);
263
264         buflen = sizeof(DHCPMessage) + optlen;
265
266         if (!desc) {
267                 assert_se((res = dhcp_option_parse(message, buflen,
268                                                 test_options_cb,
269                                                 NULL)) == -ENOMSG);
270         } else if (desc->success) {
271                 assert_se((res = dhcp_option_parse(message, buflen,
272                                                 test_options_cb,
273                                                 desc)) >= 0);
274                 assert_se(desc->pos == -1 && desc->filepos == -1 &&
275                                 desc->snamepos == -1);
276         } else
277                 assert_se((res = dhcp_option_parse(message, buflen,
278                                                 test_options_cb,
279                                                 desc)) < 0);
280
281         if (verbose)
282                 printf("DHCP type %s\n", dhcp_type(res));
283 }
284
285 static uint8_t options[64] = {
286         'A', 'B', 'C', 'D',
287         160, 2, 0x11, 0x12,
288         0,
289         31, 8, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38,
290         0,
291         55, 3, 0x51, 0x52, 0x53,
292         17, 7, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
293         255
294 };
295
296 static void test_option_set(void) {
297         _cleanup_free_ DHCPMessage *result = NULL;
298         size_t offset = 0, len, pos;
299         unsigned i;
300
301         result = malloc0(sizeof(DHCPMessage) + 11);
302         assert_se(result);
303
304         result->options[0] = 'A';
305         result->options[1] = 'B';
306         result->options[2] = 'C';
307         result->options[3] = 'D';
308
309         assert_se(dhcp_option_append(result, 0, &offset, 0, DHCP_OPTION_PAD,
310                                      0, NULL) == -ENOBUFS);
311         assert_se(offset == 0);
312
313         offset = 4;
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,
318                                      0, NULL) >= 0);
319         assert_se(offset == 5);
320
321         offset = pos = 4;
322         len = 11;
323         while (pos < len && options[pos] != DHCP_OPTION_END) {
324                 assert_se(dhcp_option_append(result, len, &offset, DHCP_OVERLOAD_SNAME,
325                                              options[pos],
326                                              options[pos + 1],
327                                              &options[pos + 2]) >= 0);
328
329                 if (options[pos] == DHCP_OPTION_PAD)
330                         pos++;
331                 else
332                         pos += 2 + options[pos + 1];
333
334                 if (pos < len)
335                         assert_se(offset == pos);
336         }
337
338         for (i = 0; i < 9; i++) {
339                 if (verbose)
340                         printf("%2u: 0x%02x(0x%02x) (options)\n", i, result->options[i],
341                                options[i]);
342                 assert_se(result->options[i] == options[i]);
343         }
344
345         if (verbose)
346                 printf("%2d: 0x%02x(0x%02x) (options)\n", 9, result->options[9],
347                        DHCP_OPTION_END);
348
349         assert_se(result->options[9] == DHCP_OPTION_END);
350
351         if (verbose)
352                 printf("%2d: 0x%02x(0x%02x) (options)\n", 10, result->options[10],
353                        DHCP_OPTION_PAD);
354
355         assert_se(result->options[10] == DHCP_OPTION_PAD);
356
357         for (i = 0; i < pos - 8; i++) {
358                 if (verbose)
359                         printf("%2u: 0x%02x(0x%02x) (sname)\n", i, result->sname[i],
360                                options[i + 9]);
361                 assert_se(result->sname[i] == options[i + 9]);
362         }
363
364         if (verbose)
365                 printf ("\n");
366 }
367
368 int main(int argc, char *argv[]) {
369         unsigned i;
370
371         test_invalid_buffer_length();
372         test_message_init();
373
374         test_options(NULL);
375
376         for (i = 0; i < ELEMENTSOF(option_tests); i++)
377                 test_options(&option_tests[i]);
378
379         test_option_set();
380
381         return 0;
382 }