/* * Copyright (c) 2022 Meta * * SPDX-License-Identifier: Apache-2.0 */ #include #include #include #include #ifdef CONFIG_ARCH_POSIX #include #else #include #endif #include #include #include static const char *const crc_types[] = { [CRC4] = "4", [CRC4_TI] = "4_ti", [CRC7_BE] = "7_be", [CRC8] = "8", [CRC8_CCITT] = "8_ccitt", [CRC16] = "16", [CRC16_ANSI] = "16_ansi", [CRC16_CCITT] = "16_ccitt", [CRC16_ITU_T] = "16_itu_t", [CRC32_C] = "32_c", [CRC32_IEEE] = "32_ieee", }; static int string_to_crc_type(const char *s) { int i; for (i = 0; i < ARRAY_SIZE(crc_types); ++i) { if (strcmp(s, crc_types[i]) == 0) { return i; } } return -1; } static void usage(const struct shell *sh) { size_t i; shell_print(sh, "crc [options..]
"); shell_print(sh, "options:"); shell_print(sh, "-f This is the first packet"); shell_print(sh, "-l This is the last packet"); shell_print(sh, "-p Use polynomial 'poly'"); shell_print(sh, "-r Reflect"); shell_print(sh, "-s Use 'seed' as the initial value"); shell_print(sh, "-t Compute the CRC described by 'type'"); shell_print(sh, "Note: some options are only useful for certain CRCs"); shell_print(sh, "CRC Types:"); for (i = 0; i < ARRAY_SIZE(crc_types); ++i) { shell_print(sh, "%s", crc_types[i]); } } static int cmd_crc(const struct shell *sh, size_t argc, char **argv) { int rv; size_t size = -1; bool last = false; uint32_t poly = 0; bool first = false; uint32_t seed = 0; bool reflect = false; void *addr = (void *)-1; enum crc_type type = CRC32_IEEE; optind = 1; while ((rv = getopt(argc, argv, "fhlp:rs:t:")) != -1) { switch (rv) { case 'f': first = true; break; case 'h': usage(sh); return 0; case 'l': last = true; break; case 'p': poly = (size_t)strtoul(optarg, NULL, 16); if (poly == 0 && errno == EINVAL) { shell_error(sh, "invalid seed '%s'", optarg); return -EINVAL; } break; case 'r': reflect = true; break; case 's': seed = (size_t)strtoul(optarg, NULL, 16); if (seed == 0 && errno == EINVAL) { shell_error(sh, "invalid seed '%s'", optarg); return -EINVAL; } break; case 't': type = string_to_crc_type(optarg); if (type == -1) { shell_error(sh, "invalid type '%s'", optarg); return -EINVAL; } break; case '?': default: usage(sh); return -EINVAL; } } if (optind + 2 > argc) { shell_error(sh, "'address' and 'size' arguments are mandatory"); usage(sh); return -EINVAL; } addr = (void *)strtoul(argv[optind], NULL, 16); if (addr == 0 && errno == EINVAL) { shell_error(sh, "invalid address '%s'", argv[optind]); return -EINVAL; } size = (size_t)strtoul(argv[optind + 1], NULL, 0); if (size == 0 && errno == EINVAL) { shell_error(sh, "invalid size '%s'", argv[optind + 1]); return -EINVAL; } shell_print(sh, "0x%x", crc_by_type(type, addr, size, seed, poly, reflect, first, last)); return 0; } SHELL_CMD_ARG_REGISTER(crc, NULL, NULL, cmd_crc, 0, 12);