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