14418919fSjohnjiang /* SPDX-License-Identifier: BSD-3-Clause
24418919fSjohnjiang  * Copyright(c) 2010-2014 Intel Corporation
34418919fSjohnjiang  */
44418919fSjohnjiang 
54418919fSjohnjiang #include <stdio.h>
64418919fSjohnjiang #include <string.h>
74418919fSjohnjiang #include <inttypes.h>
84418919fSjohnjiang 
94418919fSjohnjiang #include <rte_ether.h>
104418919fSjohnjiang #include <rte_string_fns.h>
114418919fSjohnjiang 
124418919fSjohnjiang #include <cmdline_parse.h>
134418919fSjohnjiang #include <cmdline_parse_etheraddr.h>
144418919fSjohnjiang 
154418919fSjohnjiang #include "test_cmdline.h"
164418919fSjohnjiang 
174418919fSjohnjiang struct ether_addr_str {
184418919fSjohnjiang 	const char * str;
194418919fSjohnjiang 	uint64_t address;
204418919fSjohnjiang };
214418919fSjohnjiang 
224418919fSjohnjiang /* valid strings */
234418919fSjohnjiang const struct ether_addr_str ether_addr_valid_strs[] = {
244418919fSjohnjiang 		{"01:23:45:67:89:AB", 0xAB8967452301ULL},
254418919fSjohnjiang 		{"4567:89AB:CDEF", 0xEFCDAB896745ULL},
264418919fSjohnjiang };
274418919fSjohnjiang 
284418919fSjohnjiang /* valid strings with various garbage at the end.
294418919fSjohnjiang  * these strings are still valid because parser checks for
304418919fSjohnjiang  * end of token, which is either space chars, null char or
314418919fSjohnjiang  * a hash sign.
324418919fSjohnjiang  */
334418919fSjohnjiang const char * ether_addr_garbage_strs[] = {
344418919fSjohnjiang 		"00:11:22:33:44:55\0garbage",
354418919fSjohnjiang 		"00:11:22:33:44:55#garbage",
364418919fSjohnjiang 		"00:11:22:33:44:55 garbage",
374418919fSjohnjiang 		"00:11:22:33:44:55\tgarbage",
384418919fSjohnjiang 		"00:11:22:33:44:55\ngarbage",
394418919fSjohnjiang 		"00:11:22:33:44:55\rgarbage",
404418919fSjohnjiang 		"00:11:22:33:44:55#",
414418919fSjohnjiang 		"00:11:22:33:44:55 ",
424418919fSjohnjiang 		"00:11:22:33:44:55\t",
434418919fSjohnjiang 		"00:11:22:33:44:55\n",
444418919fSjohnjiang 		"00:11:22:33:44:55\r",
454418919fSjohnjiang };
464418919fSjohnjiang #define GARBAGE_ETHERADDR 0x554433221100ULL /* corresponding address */
474418919fSjohnjiang 
484418919fSjohnjiang 
494418919fSjohnjiang const char * ether_addr_invalid_strs[] = {
504418919fSjohnjiang 		/* valid chars, invalid syntax */
514418919fSjohnjiang 		"0123:45:67:89:AB",
524418919fSjohnjiang 		"01:23:4567:89:AB",
534418919fSjohnjiang 		"01:23:45:67:89AB",
544418919fSjohnjiang 		"012:345:678:9AB",
554418919fSjohnjiang 		"01:23:45:67:89:ABC",
564418919fSjohnjiang 		"01:23:45:67:89:A",
574418919fSjohnjiang 		"01:23:45:67:89",
584418919fSjohnjiang 		"01:23:45:67:89:AB:CD",
594418919fSjohnjiang 		/* invalid chars, valid syntax */
604418919fSjohnjiang 		"IN:VA:LI:DC:HA:RS",
614418919fSjohnjiang 		"INVA:LIDC:HARS",
624418919fSjohnjiang 		/* misc */
634418919fSjohnjiang 		"01 23 45 67 89 AB",
644418919fSjohnjiang 		"01.23.45.67.89.AB",
654418919fSjohnjiang 		"01,23,45,67,89,AB",
664418919fSjohnjiang 		"01:23:45\0:67:89:AB",
674418919fSjohnjiang 		"01:23:45#:67:89:AB",
684418919fSjohnjiang 		"random invalid text",
694418919fSjohnjiang 		"random text",
704418919fSjohnjiang 		"",
714418919fSjohnjiang 		"\0",
724418919fSjohnjiang 		" ",
734418919fSjohnjiang };
744418919fSjohnjiang 
754418919fSjohnjiang static int
is_addr_different(const struct rte_ether_addr addr,uint64_t num)764418919fSjohnjiang is_addr_different(const struct rte_ether_addr addr, uint64_t num)
774418919fSjohnjiang {
784418919fSjohnjiang 	int i;
794418919fSjohnjiang 	for (i = 0; i < RTE_ETHER_ADDR_LEN; i++, num >>= 8)
804418919fSjohnjiang 		if (addr.addr_bytes[i] != (num & 0xFF)) {
814418919fSjohnjiang 			return 1;
824418919fSjohnjiang 		}
834418919fSjohnjiang 	return 0;
844418919fSjohnjiang }
854418919fSjohnjiang 
864418919fSjohnjiang /* test invalid parameters */
874418919fSjohnjiang int
test_parse_etheraddr_invalid_param(void)884418919fSjohnjiang test_parse_etheraddr_invalid_param(void)
894418919fSjohnjiang {
904418919fSjohnjiang 	char buf[CMDLINE_TEST_BUFSIZE];
914418919fSjohnjiang 	struct rte_ether_addr result;
924418919fSjohnjiang 	int ret = 0;
934418919fSjohnjiang 
944418919fSjohnjiang 	/* try all null */
954418919fSjohnjiang 	ret = cmdline_parse_etheraddr(NULL, NULL, NULL, 0);
964418919fSjohnjiang 	if (ret != -1) {
974418919fSjohnjiang 		printf("Error: parser accepted null parameters!\n");
984418919fSjohnjiang 		return -1;
994418919fSjohnjiang 	}
1004418919fSjohnjiang 
1014418919fSjohnjiang 	/* try null buf */
1024418919fSjohnjiang 	ret = cmdline_parse_etheraddr(NULL, NULL, (void*)&result,
1034418919fSjohnjiang 		sizeof(result));
1044418919fSjohnjiang 	if (ret != -1) {
1054418919fSjohnjiang 		printf("Error: parser accepted null string!\n");
1064418919fSjohnjiang 		return -1;
1074418919fSjohnjiang 	}
1084418919fSjohnjiang 
1094418919fSjohnjiang 	/* try null result */
1104418919fSjohnjiang 
1114418919fSjohnjiang 	/* copy string to buffer */
1124418919fSjohnjiang 	strlcpy(buf, ether_addr_valid_strs[0].str, sizeof(buf));
1134418919fSjohnjiang 
1144418919fSjohnjiang 	ret = cmdline_parse_etheraddr(NULL, buf, NULL, 0);
1154418919fSjohnjiang 	if (ret == -1) {
1164418919fSjohnjiang 		printf("Error: parser rejected null result!\n");
1174418919fSjohnjiang 		return -1;
1184418919fSjohnjiang 	}
1194418919fSjohnjiang 
1204418919fSjohnjiang 	/* token is not used in ether_parse anyway so there's no point in
1214418919fSjohnjiang 	 * testing it */
1224418919fSjohnjiang 
1234418919fSjohnjiang 	/* test help function */
1244418919fSjohnjiang 	memset(&buf, 0, sizeof(buf));
1254418919fSjohnjiang 
1264418919fSjohnjiang 	/* coverage! */
1274418919fSjohnjiang 	ret = cmdline_get_help_etheraddr(NULL, buf, sizeof(buf));
1284418919fSjohnjiang 	if (ret < 0) {
1294418919fSjohnjiang 		printf("Error: help function failed with valid parameters!\n");
1304418919fSjohnjiang 		return -1;
1314418919fSjohnjiang 	}
1324418919fSjohnjiang 
1334418919fSjohnjiang 	return 0;
1344418919fSjohnjiang }
1354418919fSjohnjiang 
1364418919fSjohnjiang /* test valid parameters but invalid data */
1374418919fSjohnjiang int
test_parse_etheraddr_invalid_data(void)1384418919fSjohnjiang test_parse_etheraddr_invalid_data(void)
1394418919fSjohnjiang {
1404418919fSjohnjiang 	int ret = 0;
1414418919fSjohnjiang 	unsigned i;
1424418919fSjohnjiang 	struct rte_ether_addr result;
1434418919fSjohnjiang 
1444418919fSjohnjiang 	/* test full strings */
145*2d9fd380Sjfb8856606 	for (i = 0; i < RTE_DIM(ether_addr_invalid_strs); i++) {
1464418919fSjohnjiang 
1474418919fSjohnjiang 		memset(&result, 0, sizeof(struct rte_ether_addr));
1484418919fSjohnjiang 
1494418919fSjohnjiang 		ret = cmdline_parse_etheraddr(NULL, ether_addr_invalid_strs[i],
1504418919fSjohnjiang 			(void*)&result, sizeof(result));
1514418919fSjohnjiang 		if (ret != -1) {
1524418919fSjohnjiang 			printf("Error: parsing %s succeeded!\n",
1534418919fSjohnjiang 					ether_addr_invalid_strs[i]);
1544418919fSjohnjiang 			return -1;
1554418919fSjohnjiang 		}
1564418919fSjohnjiang 	}
1574418919fSjohnjiang 
1584418919fSjohnjiang 	return 0;
1594418919fSjohnjiang }
1604418919fSjohnjiang 
1614418919fSjohnjiang /* test valid parameters and data */
1624418919fSjohnjiang int
test_parse_etheraddr_valid(void)1634418919fSjohnjiang test_parse_etheraddr_valid(void)
1644418919fSjohnjiang {
1654418919fSjohnjiang 	int ret = 0;
1664418919fSjohnjiang 	unsigned i;
1674418919fSjohnjiang 	struct rte_ether_addr result;
1684418919fSjohnjiang 
1694418919fSjohnjiang 	/* test full strings */
170*2d9fd380Sjfb8856606 	for (i = 0; i < RTE_DIM(ether_addr_valid_strs); i++) {
1714418919fSjohnjiang 
1724418919fSjohnjiang 		memset(&result, 0, sizeof(struct rte_ether_addr));
1734418919fSjohnjiang 
1744418919fSjohnjiang 		ret = cmdline_parse_etheraddr(NULL, ether_addr_valid_strs[i].str,
1754418919fSjohnjiang 			(void*)&result, sizeof(result));
1764418919fSjohnjiang 		if (ret < 0) {
1774418919fSjohnjiang 			printf("Error: parsing %s failed!\n",
1784418919fSjohnjiang 					ether_addr_valid_strs[i].str);
1794418919fSjohnjiang 			return -1;
1804418919fSjohnjiang 		}
1814418919fSjohnjiang 		if (is_addr_different(result, ether_addr_valid_strs[i].address)) {
1824418919fSjohnjiang 			printf("Error: parsing %s failed: address mismatch!\n",
1834418919fSjohnjiang 					ether_addr_valid_strs[i].str);
1844418919fSjohnjiang 			return -1;
1854418919fSjohnjiang 		}
1864418919fSjohnjiang 	}
1874418919fSjohnjiang 
1884418919fSjohnjiang 	/* test garbage strings */
189*2d9fd380Sjfb8856606 	for (i = 0; i < RTE_DIM(ether_addr_garbage_strs); i++) {
1904418919fSjohnjiang 
1914418919fSjohnjiang 		memset(&result, 0, sizeof(struct rte_ether_addr));
1924418919fSjohnjiang 
1934418919fSjohnjiang 		ret = cmdline_parse_etheraddr(NULL, ether_addr_garbage_strs[i],
1944418919fSjohnjiang 			(void*)&result, sizeof(result));
1954418919fSjohnjiang 		if (ret < 0) {
1964418919fSjohnjiang 			printf("Error: parsing %s failed!\n",
1974418919fSjohnjiang 					ether_addr_garbage_strs[i]);
1984418919fSjohnjiang 			return -1;
1994418919fSjohnjiang 		}
2004418919fSjohnjiang 		if (is_addr_different(result, GARBAGE_ETHERADDR)) {
2014418919fSjohnjiang 			printf("Error: parsing %s failed: address mismatch!\n",
2024418919fSjohnjiang 					ether_addr_garbage_strs[i]);
2034418919fSjohnjiang 			return -1;
2044418919fSjohnjiang 		}
2054418919fSjohnjiang 	}
2064418919fSjohnjiang 
2074418919fSjohnjiang 	return 0;
2084418919fSjohnjiang }
209