i40e: fix crash on DCB query
[dpdk.git] / app / test / test_cmdline_ipaddr.c
1 /*-
2  *   BSD LICENSE
3  *
4  *   Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
5  *   All rights reserved.
6  *
7  *   Redistribution and use in source and binary forms, with or without
8  *   modification, are permitted provided that the following conditions
9  *   are met:
10  *
11  *     * Redistributions of source code must retain the above copyright
12  *       notice, this list of conditions and the following disclaimer.
13  *     * Redistributions in binary form must reproduce the above copyright
14  *       notice, this list of conditions and the following disclaimer in
15  *       the documentation and/or other materials provided with the
16  *       distribution.
17  *     * Neither the name of Intel Corporation nor the names of its
18  *       contributors may be used to endorse or promote products derived
19  *       from this software without specific prior written permission.
20  *
21  *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24  *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25  *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26  *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27  *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28  *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29  *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30  *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31  *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32  */
33
34 #include <stdio.h>
35 #include <string.h>
36 #include <inttypes.h>
37 #include <netinet/in.h>
38
39 #ifndef __linux__
40 #ifndef __FreeBSD__
41 #include <net/socket.h>
42 #else
43 #include <sys/socket.h>
44 #endif
45 #endif
46
47 #include <rte_string_fns.h>
48
49 #include <cmdline_parse.h>
50 #include <cmdline_parse_ipaddr.h>
51
52 #include "test_cmdline.h"
53
54 #define IP4(a,b,c,d) {((uint32_t)(((a) & 0xff)) | \
55                                            (((b) & 0xff) << 8) | \
56                                            (((c) & 0xff) << 16)  | \
57                                            ((d) & 0xff)  << 24)}
58
59 #define U16_SWAP(x) \
60                 (((x & 0xFF) << 8) | ((x & 0xFF00) >> 8))
61
62 /* create IPv6 address, swapping bytes where needed */
63 #ifndef s6_addr16
64 # define s6_addr16      __u6_addr.__u6_addr16
65 #endif
66 #define IP6(a,b,c,d,e,f,g,h) .ipv6 = \
67                 {.s6_addr16 = \
68                 {U16_SWAP(a),U16_SWAP(b),U16_SWAP(c),U16_SWAP(d),\
69                  U16_SWAP(e),U16_SWAP(f),U16_SWAP(g),U16_SWAP(h)}}
70
71 /** these are defined in netinet/in.h but not present in linux headers */
72 #ifndef NIPQUAD
73
74 #define NIPQUAD_FMT "%u.%u.%u.%u"
75 #define NIPQUAD(addr)                           \
76         (unsigned)((unsigned char *)&addr)[0],  \
77         (unsigned)((unsigned char *)&addr)[1],  \
78         (unsigned)((unsigned char *)&addr)[2],  \
79         (unsigned)((unsigned char *)&addr)[3]
80
81 #define NIP6_FMT "%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x"
82 #define NIP6(addr)                                      \
83         (unsigned)((addr).s6_addr[0]),                  \
84         (unsigned)((addr).s6_addr[1]),                  \
85         (unsigned)((addr).s6_addr[2]),                  \
86         (unsigned)((addr).s6_addr[3]),                  \
87         (unsigned)((addr).s6_addr[4]),                  \
88         (unsigned)((addr).s6_addr[5]),                  \
89         (unsigned)((addr).s6_addr[6]),                  \
90         (unsigned)((addr).s6_addr[7]),                  \
91         (unsigned)((addr).s6_addr[8]),                  \
92         (unsigned)((addr).s6_addr[9]),                  \
93         (unsigned)((addr).s6_addr[10]),                 \
94         (unsigned)((addr).s6_addr[11]),                 \
95         (unsigned)((addr).s6_addr[12]),                 \
96         (unsigned)((addr).s6_addr[13]),                 \
97         (unsigned)((addr).s6_addr[14]),                 \
98         (unsigned)((addr).s6_addr[15])
99
100 #endif
101
102
103
104 struct ipaddr_str {
105         const char * str;
106         cmdline_ipaddr_t addr;
107         unsigned flags;
108 };
109
110 const struct ipaddr_str ipaddr_valid_strs[] = {
111                 {"0.0.0.0", {AF_INET, {IP4(0,0,0,0)}, 0},
112                                 CMDLINE_IPADDR_V4},
113                 {"0.0.0.0/0", {AF_INET, {IP4(0,0,0,0)}, 0},
114                                 CMDLINE_IPADDR_V4 | CMDLINE_IPADDR_NETWORK},
115                 {"0.0.0.0/24", {AF_INET, {IP4(0,0,0,0)}, 24},
116                                 CMDLINE_IPADDR_V4 | CMDLINE_IPADDR_NETWORK},
117                 {"192.168.1.0/24", {AF_INET, {IP4(192,168,1,0)}, 24},
118                                 CMDLINE_IPADDR_V4 | CMDLINE_IPADDR_NETWORK},
119                 {"012.34.56.78/24", {AF_INET, {IP4(12,34,56,78)}, 24},
120                                 CMDLINE_IPADDR_V4 | CMDLINE_IPADDR_NETWORK},
121                 {"34.56.78.90/1", {AF_INET, {IP4(34,56,78,90)}, 1},
122                                 CMDLINE_IPADDR_V4 | CMDLINE_IPADDR_NETWORK},
123                 {"::", {AF_INET6, {IP6(0,0,0,0,0,0,0,0)}, 0},
124                                         CMDLINE_IPADDR_V6},
125                 {"::1", {AF_INET6, {IP6(0,0,0,0,0,0,0,1)}, 0},
126                                 CMDLINE_IPADDR_V6},
127                 {"::1/32", {AF_INET6, {IP6(0,0,0,0,0,0,0,1)}, 32},
128                                 CMDLINE_IPADDR_V6 | CMDLINE_IPADDR_NETWORK},
129                 {"::/32", {AF_INET6, {IP6(0,0,0,0,0,0,0,0)}, 32},
130                                         CMDLINE_IPADDR_V6 | CMDLINE_IPADDR_NETWORK},
131                 /* RFC5952 requests that only lowercase should be used */
132                 {"1234:5678:90ab:cdef:4321:8765:BA09:FEDC", {AF_INET6,
133                                 {IP6(0x1234,0x5678,0x90AB,0xCDEF,0x4321,0x8765,0xBA09,0xFEDC)},
134                                 0},
135                                 CMDLINE_IPADDR_V6},
136                 {"1234::1234/64", {AF_INET6,
137                                 {IP6(0x1234,0,0,0,0,0,0,0x1234)},
138                                 64},
139                                 CMDLINE_IPADDR_V6 | CMDLINE_IPADDR_NETWORK},
140                 {"1234::/64", {AF_INET6,
141                                 {IP6(0x1234,0,0,0,0,0,0,0)},
142                                 64},
143                                 CMDLINE_IPADDR_V6 | CMDLINE_IPADDR_NETWORK},
144                 {"1:1::1/32", {AF_INET6,
145                                 {IP6(1,1,0,0,0,0,0,1)},
146                                 32},
147                                 CMDLINE_IPADDR_V6 | CMDLINE_IPADDR_NETWORK},
148                 {"1:2:3:4::/64", {AF_INET6,
149                                 {IP6(1,2,3,4,0,0,0,0)},
150                                 64},
151                         CMDLINE_IPADDR_V6 | CMDLINE_IPADDR_NETWORK},
152                 {"::ffff:192.168.1.0/64", {AF_INET6,
153                                 {IP6(0,0,0,0,0,0xFFFF,0xC0A8,0x100)},
154                                 64},
155                         CMDLINE_IPADDR_V6 | CMDLINE_IPADDR_NETWORK},
156                 /* RFC5952 requests not using :: to skip one block of zeros*/
157                 {"1::2:3:4:5:6:7", {AF_INET6,
158                                 {IP6(1,0,2,3,4,5,6,7)},
159                                 0},
160                         CMDLINE_IPADDR_V6},
161 };
162
163 const char * ipaddr_garbage_addr4_strs[] = {
164                 /* IPv4 */
165                 "192.168.1.0 garbage",
166                 "192.168.1.0\0garbage",
167                 "192.168.1.0#garbage",
168                 "192.168.1.0\tgarbage",
169                 "192.168.1.0\rgarbage",
170                 "192.168.1.0\ngarbage",
171 };
172 #define IPv4_GARBAGE_ADDR IP4(192,168,1,0)
173
174 const char * ipaddr_garbage_addr6_strs[] = {
175                 /* IPv6 */
176                 "1:2:3:4::8 garbage",
177                 "1:2:3:4::8#garbage",
178                 "1:2:3:4::8\0garbage",
179                 "1:2:3:4::8\rgarbage",
180                 "1:2:3:4::8\ngarbage",
181                 "1:2:3:4::8\tgarbage",
182 };
183 #define IPv6_GARBAGE_ADDR {IP6(1,2,3,4,0,0,0,8)}
184
185 const char * ipaddr_garbage_network4_strs[] = {
186                 /* IPv4 */
187                 "192.168.1.0/24 garbage",
188                 "192.168.1.0/24\0garbage",
189                 "192.168.1.0/24#garbage",
190                 "192.168.1.0/24\tgarbage",
191                 "192.168.1.0/24\rgarbage",
192                 "192.168.1.0/24\ngarbage",
193 };
194 #define IPv4_GARBAGE_PREFIX 24
195
196 const char * ipaddr_garbage_network6_strs[] = {
197                 /* IPv6 */
198                 "1:2:3:4::8/64 garbage",
199                 "1:2:3:4::8/64#garbage",
200                 "1:2:3:4::8/64\0garbage",
201                 "1:2:3:4::8/64\rgarbage",
202                 "1:2:3:4::8/64\ngarbage",
203                 "1:2:3:4::8/64\tgarbage",
204 };
205 #define IPv6_GARBAGE_PREFIX 64
206
207
208
209 const char * ipaddr_invalid_strs[] = {
210                 /** IPv4 **/
211
212                 /* invalid numbers */
213                 "0.0.0.-1",
214                 "0.0.-1.0",
215                 "0.-1.0.0",
216                 "-1.0.0.0",
217                 "0.0.0.-1/24",
218                 "256.123.123.123",
219                 "255.256.123.123",
220                 "255.255.256.123",
221                 "255.255.255.256",
222                 "256.123.123.123/24",
223                 "255.256.123.123/24",
224                 "255.255.256.123/24",
225                 "255.255.255.256/24",
226                 /* invalid network mask */
227                 "1.2.3.4/33",
228                 "1.2.3.4/33231313",
229                 "1.2.3.4/-1",
230                 "1.2.3.4/24/33",
231                 "1.2.3.4/24/-1",
232                 "1.2.3.4/24/",
233                 /* wrong format */
234                 "1/24"
235                 "/24"
236                 "123.123.123",
237                 "123.123.123.",
238                 "123.123.123.123.",
239                 "123.123.123..123",
240                 "123.123.123.123.123",
241                 ".123.123.123",
242                 ".123.123.123.123",
243                 "123.123.123/24",
244                 "123.123.123./24",
245                 "123.123.123.123./24",
246                 "123.123.123..123/24",
247                 "123.123.123.123.123/24",
248                 ".123.123.123/24",
249                 ".123.123.123.123/24",
250                 /* invalid characters */
251                 "123.123.123.12F",
252                 "123.123.12F.123",
253                 "123.12F.123.123",
254                 "12F.123.123.123",
255                 "12J.123.123.123",
256                 "123,123,123,123",
257                 "123!123!123!12F",
258                 "123.123.123.123/4F",
259
260                 /** IPv6 **/
261
262                 /* wrong format */
263                 "::fffff",
264                 "ffff:",
265                 "1:2:3:4:5:6:7:192.168.1.1",
266                 "1234:192.168.1.1:ffff::",
267                 "1:2:3:4:5:6:7:890ab",
268                 "1:2:3:4:5:6:7890a:b",
269                 "1:2:3:4:5:67890:a:b",
270                 "1:2:3:4:56789:0:a:b",
271                 "1:2:3:45678:9:0:a:b",
272                 "1:2:34567:8:9:0:a:b",
273                 "1:23456:7:8:9:0:a:b",
274                 "12345:6:7:8:9:0:a:b",
275                 "1:::2",
276                 "1::::2",
277                 "::fffff/64",
278                 "1::2::3",
279                 "1::2::3/64",
280                 ":1:2",
281                 ":1:2/64",
282                 ":1::2",
283                 ":1::2/64",
284                 "1::2:3:4:5:6:7:8/64",
285
286                 /* invalid network mask */
287                 "1:2:3:4:5:6:7:8/129",
288                 "1:2:3:4:5:6:7:8/-1",
289
290                 /* invalid characters */
291                 "a:b:c:d:e:f:g::",
292
293                 /** misc **/
294
295                 /* too long */
296                 "1234:1234:1234:1234:1234:1234:1234:1234:1234:1234:1234"
297                 "random invalid text",
298                 "",
299                 "\0",
300                 " ",
301 };
302
303 #define IPADDR_VALID_STRS_SIZE \
304         (sizeof(ipaddr_valid_strs) / sizeof(ipaddr_valid_strs[0]))
305 #define IPADDR_GARBAGE_ADDR4_STRS_SIZE \
306         (sizeof(ipaddr_garbage_addr4_strs) / sizeof(ipaddr_garbage_addr4_strs[0]))
307 #define IPADDR_GARBAGE_ADDR6_STRS_SIZE \
308         (sizeof(ipaddr_garbage_addr6_strs) / sizeof(ipaddr_garbage_addr6_strs[0]))
309 #define IPADDR_GARBAGE_NETWORK4_STRS_SIZE \
310         (sizeof(ipaddr_garbage_network4_strs) / sizeof(ipaddr_garbage_network4_strs[0]))
311 #define IPADDR_GARBAGE_NETWORK6_STRS_SIZE \
312         (sizeof(ipaddr_garbage_network6_strs) / sizeof(ipaddr_garbage_network6_strs[0]))
313 #define IPADDR_INVALID_STRS_SIZE \
314         (sizeof(ipaddr_invalid_strs) / sizeof(ipaddr_invalid_strs[0]))
315
316 static void
317 dump_addr(cmdline_ipaddr_t addr)
318 {
319         switch (addr.family) {
320         case AF_INET:
321         {
322                 printf(NIPQUAD_FMT " prefixlen=%u\n",
323                                 NIPQUAD(addr.addr.ipv4.s_addr), addr.prefixlen);
324                 break;
325         }
326         case AF_INET6:
327         {
328                 printf(NIP6_FMT " prefixlen=%u\n",
329                                 NIP6(addr.addr.ipv6), addr.prefixlen);
330                 break;
331         }
332         default:
333                 printf("Can't dump: unknown address family.\n");
334                 return;
335         }
336 }
337
338
339 static int
340 is_addr_different(cmdline_ipaddr_t addr1, cmdline_ipaddr_t addr2)
341 {
342         if (addr1.family != addr2.family)
343                 return 1;
344
345         if (addr1.prefixlen != addr2.prefixlen)
346                 return 1;
347
348         switch (addr1.family) {
349         /* IPv4 */
350         case AF_INET:
351                 if (memcmp(&addr1.addr.ipv4, &addr2.addr.ipv4,
352                                 sizeof(struct in_addr)) != 0)
353                         return 1;
354                 break;
355         /* IPv6 */
356         case AF_INET6:
357         {
358                 if (memcmp(&addr1.addr.ipv6, &addr2.addr.ipv6,
359                                 sizeof(struct in6_addr)) != 0)
360                         return 1;
361                 break;
362         }
363         /* thing that should not be */
364         default:
365                 return -1;
366         }
367         return 0;
368 }
369
370 static int
371 can_parse_addr(unsigned addr_flags, unsigned test_flags)
372 {
373         if ((test_flags & addr_flags) == addr_flags) {
374                 /* if we are not trying to parse network addresses */
375                 if (test_flags < CMDLINE_IPADDR_NETWORK)
376                         return 1;
377                 /* if this is a network address */
378                 else if (addr_flags & CMDLINE_IPADDR_NETWORK)
379                         return 1;
380         }
381         return 0;
382 }
383
384 int
385 test_parse_ipaddr_valid(void)
386 {
387         cmdline_parse_token_ipaddr_t token;
388         char buf[CMDLINE_TEST_BUFSIZE];
389         cmdline_ipaddr_t result;
390         unsigned i;
391         uint8_t flags;
392         int ret;
393
394         /* cover all cases in help */
395         for (flags = 0x1; flags < 0x8; flags++) {
396                 token.ipaddr_data.flags = flags;
397
398                 memset(buf, 0, sizeof(buf));
399
400                 if (cmdline_get_help_ipaddr((cmdline_parse_token_hdr_t*)&token,
401                                 buf, sizeof(buf)) == -1) {
402                         printf("Error: help rejected valid parameters!\n");
403                         return -1;
404                 }
405         }
406
407         /* test valid strings */
408         for (i = 0; i < IPADDR_VALID_STRS_SIZE; i++) {
409
410                 /* test each valid string against different flags */
411                 for (flags = 1; flags < 0x8; flags++) {
412
413                         /* skip bad flag */
414                         if (flags == CMDLINE_IPADDR_NETWORK)
415                                 continue;
416
417                         /* clear out everything */
418                         memset(buf, 0, sizeof(buf));
419                         memset(&result, 0, sizeof(result));
420                         memset(&token, 0, sizeof(token));
421
422                         token.ipaddr_data.flags = flags;
423
424                         cmdline_get_help_ipaddr((cmdline_parse_token_hdr_t*)&token,
425                                                         buf, sizeof(buf));
426
427                         ret = cmdline_parse_ipaddr((cmdline_parse_token_hdr_t*)&token,
428                                 ipaddr_valid_strs[i].str, (void*)&result,
429                                 sizeof(result));
430
431                         /* if should have passed, or should have failed */
432                         if ((ret < 0) ==
433                                         (can_parse_addr(ipaddr_valid_strs[i].flags, flags))) {
434                                 printf("Error: unexpected behavior when parsing %s as %s!\n",
435                                                 ipaddr_valid_strs[i].str, buf);
436                                 printf("Parsed result: ");
437                                 dump_addr(result);
438                                 printf("Expected result: ");
439                                 dump_addr(ipaddr_valid_strs[i].addr);
440                                 return -1;
441                         }
442                         if (ret != -1 &&
443                                         is_addr_different(result, ipaddr_valid_strs[i].addr)) {
444                                 printf("Error: result mismatch when parsing %s as %s!\n",
445                                                 ipaddr_valid_strs[i].str, buf);
446                                 printf("Parsed result: ");
447                                 dump_addr(result);
448                                 printf("Expected result: ");
449                                 dump_addr(ipaddr_valid_strs[i].addr);
450                                 return -1;
451                         }
452                 }
453         }
454
455         /* test garbage ipv4 address strings */
456         for (i = 0; i < IPADDR_GARBAGE_ADDR4_STRS_SIZE; i++) {
457
458                 struct in_addr tmp = IPv4_GARBAGE_ADDR;
459
460                 /* test each valid string against different flags */
461                 for (flags = 1; flags < 0x8; flags++) {
462
463                         /* skip bad flag */
464                         if (flags == CMDLINE_IPADDR_NETWORK)
465                                 continue;
466
467                         /* clear out everything */
468                         memset(buf, 0, sizeof(buf));
469                         memset(&result, 0, sizeof(result));
470                         memset(&token, 0, sizeof(token));
471
472                         token.ipaddr_data.flags = flags;
473
474                         cmdline_get_help_ipaddr((cmdline_parse_token_hdr_t*)&token,
475                                                         buf, sizeof(buf));
476
477                         ret = cmdline_parse_ipaddr((cmdline_parse_token_hdr_t*)&token,
478                                 ipaddr_garbage_addr4_strs[i], (void*)&result,
479                                 sizeof(result));
480
481                         /* if should have passed, or should have failed */
482                         if ((ret < 0) ==
483                                         (can_parse_addr(CMDLINE_IPADDR_V4, flags))) {
484                                 printf("Error: unexpected behavior when parsing %s as %s!\n",
485                                                 ipaddr_garbage_addr4_strs[i], buf);
486                                 return -1;
487                         }
488                         if (ret != -1 &&
489                                         memcmp(&result.addr.ipv4, &tmp, sizeof(tmp))) {
490                                 printf("Error: result mismatch when parsing %s as %s!\n",
491                                                 ipaddr_garbage_addr4_strs[i], buf);
492                                 return -1;
493                         }
494                 }
495         }
496
497         /* test garbage ipv6 address strings */
498         for (i = 0; i < IPADDR_GARBAGE_ADDR6_STRS_SIZE; i++) {
499
500                 cmdline_ipaddr_t tmp = {.addr = IPv6_GARBAGE_ADDR};
501
502                 /* test each valid string against different flags */
503                 for (flags = 1; flags < 0x8; flags++) {
504
505                         /* skip bad flag */
506                         if (flags == CMDLINE_IPADDR_NETWORK)
507                                 continue;
508
509                         /* clear out everything */
510                         memset(buf, 0, sizeof(buf));
511                         memset(&result, 0, sizeof(result));
512                         memset(&token, 0, sizeof(token));
513
514                         token.ipaddr_data.flags = flags;
515
516                         cmdline_get_help_ipaddr((cmdline_parse_token_hdr_t*)&token,
517                                                         buf, sizeof(buf));
518
519                         ret = cmdline_parse_ipaddr((cmdline_parse_token_hdr_t*)&token,
520                                 ipaddr_garbage_addr6_strs[i], (void*)&result,
521                                 sizeof(result));
522
523                         /* if should have passed, or should have failed */
524                         if ((ret < 0) ==
525                                         (can_parse_addr(CMDLINE_IPADDR_V6, flags))) {
526                                 printf("Error: unexpected behavior when parsing %s as %s!\n",
527                                                 ipaddr_garbage_addr6_strs[i], buf);
528                                 return -1;
529                         }
530                         if (ret != -1 &&
531                                         memcmp(&result.addr.ipv6, &tmp.addr.ipv6, sizeof(struct in6_addr))) {
532                                 printf("Error: result mismatch when parsing %s as %s!\n",
533                                                 ipaddr_garbage_addr6_strs[i], buf);
534                                 return -1;
535                         }
536                 }
537         }
538
539
540         /* test garbage ipv4 network strings */
541         for (i = 0; i < IPADDR_GARBAGE_NETWORK4_STRS_SIZE; i++) {
542
543                 struct in_addr tmp = IPv4_GARBAGE_ADDR;
544
545                 /* test each valid string against different flags */
546                 for (flags = 1; flags < 0x8; flags++) {
547
548                         /* skip bad flag */
549                         if (flags == CMDLINE_IPADDR_NETWORK)
550                                 continue;
551
552                         /* clear out everything */
553                         memset(buf, 0, sizeof(buf));
554                         memset(&result, 0, sizeof(result));
555                         memset(&token, 0, sizeof(token));
556
557                         token.ipaddr_data.flags = flags;
558
559                         cmdline_get_help_ipaddr((cmdline_parse_token_hdr_t*)&token,
560                                                         buf, sizeof(buf));
561
562                         ret = cmdline_parse_ipaddr((cmdline_parse_token_hdr_t*)&token,
563                                 ipaddr_garbage_network4_strs[i], (void*)&result,
564                                 sizeof(result));
565
566                         /* if should have passed, or should have failed */
567                         if ((ret < 0) ==
568                                         (can_parse_addr(CMDLINE_IPADDR_V4 | CMDLINE_IPADDR_NETWORK, flags))) {
569                                 printf("Error: unexpected behavior when parsing %s as %s!\n",
570                                                 ipaddr_garbage_network4_strs[i], buf);
571                                 return -1;
572                         }
573                         if (ret != -1 &&
574                                         memcmp(&result.addr.ipv4, &tmp, sizeof(tmp))) {
575                                 printf("Error: result mismatch when parsing %s as %s!\n",
576                                                 ipaddr_garbage_network4_strs[i], buf);
577                                 return -1;
578                         }
579                 }
580         }
581
582         /* test garbage ipv6 address strings */
583         for (i = 0; i < IPADDR_GARBAGE_NETWORK6_STRS_SIZE; i++) {
584
585                 cmdline_ipaddr_t tmp = {.addr = IPv6_GARBAGE_ADDR};
586
587                 /* test each valid string against different flags */
588                 for (flags = 1; flags < 0x8; flags++) {
589
590                         /* skip bad flag */
591                         if (flags == CMDLINE_IPADDR_NETWORK)
592                                 continue;
593
594                         /* clear out everything */
595                         memset(buf, 0, sizeof(buf));
596                         memset(&result, 0, sizeof(result));
597                         memset(&token, 0, sizeof(token));
598
599                         token.ipaddr_data.flags = flags;
600
601                         cmdline_get_help_ipaddr((cmdline_parse_token_hdr_t*)&token,
602                                                         buf, sizeof(buf));
603
604                         ret = cmdline_parse_ipaddr((cmdline_parse_token_hdr_t*)&token,
605                                 ipaddr_garbage_network6_strs[i], (void*)&result,
606                                 sizeof(result));
607
608                         /* if should have passed, or should have failed */
609                         if ((ret < 0) ==
610                                         (can_parse_addr(CMDLINE_IPADDR_V6 | CMDLINE_IPADDR_NETWORK, flags))) {
611                                 printf("Error: unexpected behavior when parsing %s as %s!\n",
612                                                 ipaddr_garbage_network6_strs[i], buf);
613                                 return -1;
614                         }
615                         if (ret != -1 &&
616                                         memcmp(&result.addr.ipv6, &tmp.addr.ipv6, sizeof(struct in6_addr))) {
617                                 printf("Error: result mismatch when parsing %s as %s!\n",
618                                                 ipaddr_garbage_network6_strs[i], buf);
619                                 return -1;
620                         }
621                 }
622         }
623
624         return 0;
625 }
626
627 int
628 test_parse_ipaddr_invalid_data(void)
629 {
630         cmdline_parse_token_ipaddr_t token;
631         char buf[CMDLINE_TEST_BUFSIZE];
632         cmdline_ipaddr_t result;
633         unsigned i;
634         uint8_t flags;
635         int ret;
636
637         memset(&result, 0, sizeof(result));
638
639         /* test invalid strings */
640         for (i = 0; i < IPADDR_INVALID_STRS_SIZE; i++) {
641
642                 /* test each valid string against different flags */
643                 for (flags = 1; flags < 0x8; flags++) {
644
645                         /* skip bad flag */
646                         if (flags == CMDLINE_IPADDR_NETWORK)
647                                 continue;
648
649                         /* clear out everything */
650                         memset(buf, 0, sizeof(buf));
651                         memset(&token, 0, sizeof(token));
652
653                         token.ipaddr_data.flags = flags;
654
655                         cmdline_get_help_ipaddr((cmdline_parse_token_hdr_t*)&token,
656                                         buf, sizeof(buf));
657
658                         ret = cmdline_parse_ipaddr((cmdline_parse_token_hdr_t*)&token,
659                                 ipaddr_invalid_strs[i], (void*)&result,
660                                 sizeof(result));
661
662                         if (ret != -1) {
663                                 printf("Error: parsing %s as %s succeeded!\n",
664                                                 ipaddr_invalid_strs[i], buf);
665                                 printf("Parsed result: ");
666                                 dump_addr(result);
667                                 return -1;
668                         }
669                 }
670         }
671
672         return 0;
673 }
674
675 int
676 test_parse_ipaddr_invalid_param(void)
677 {
678         cmdline_parse_token_ipaddr_t token;
679         char buf[CMDLINE_TEST_BUFSIZE];
680         cmdline_ipaddr_t result;
681
682         snprintf(buf, sizeof(buf), "1.2.3.4");
683         token.ipaddr_data.flags = CMDLINE_IPADDR_V4;
684
685         /* null token */
686         if (cmdline_parse_ipaddr(NULL, buf, (void*)&result,
687                         sizeof(result)) != -1) {
688                 printf("Error: parser accepted invalid parameters!\n");
689                 return -1;
690         }
691         /* null buffer */
692         if (cmdline_parse_ipaddr((cmdline_parse_token_hdr_t*)&token,
693                         NULL, (void*)&result, sizeof(result)) != -1) {
694                 printf("Error: parser accepted invalid parameters!\n");
695                 return -1;
696         }
697         /* empty buffer */
698         if (cmdline_parse_ipaddr((cmdline_parse_token_hdr_t*)&token,
699                         "", (void*)&result, sizeof(result)) != -1) {
700                 printf("Error: parser accepted invalid parameters!\n");
701                 return -1;
702         }
703         /* null result */
704         if (cmdline_parse_ipaddr((cmdline_parse_token_hdr_t*)&token,
705                         buf, NULL, 0) == -1) {
706                 printf("Error: parser rejected null result!\n");
707                 return -1;
708         }
709
710         /* null token */
711         if (cmdline_get_help_ipaddr(NULL, buf, 0) != -1) {
712                 printf("Error: help accepted invalid parameters!\n");
713                 return -1;
714         }
715         /* null buffer */
716         if (cmdline_get_help_ipaddr((cmdline_parse_token_hdr_t*)&token,
717                         NULL, 0) != -1) {
718                 printf("Error: help accepted invalid parameters!\n");
719                 return -1;
720         }
721         return 0;
722 }