| #include <stdbool.h> |
| #include <errno.h> |
| #include <time.h> |
| #include <net/if.h> |
| #include <unistd.h> |
| #include <sys/types.h> |
| #include <sys/stat.h> |
| #include <fcntl.h> |
| #include <sys/mman.h> |
| |
| #include "calibrator.h" |
| #include "plt.h" |
| #include "ini.h" |
| #include "nvs.h" |
| |
| SECTION(get); |
| SECTION(set); |
| |
| static int handle_push_nvs(struct nl80211_state *state, |
| struct nl_cb *cb, |
| struct nl_msg *msg, |
| int argc, char **argv) |
| { |
| void *map = MAP_FAILED; |
| int fd, retval = 0; |
| struct nlattr *key; |
| struct stat filestat; |
| |
| if (argc != 1) { |
| return 1; |
| } |
| |
| fd = open(argv[0], O_RDONLY); |
| if (fd < 0) { |
| perror("Error opening file for reading"); |
| return 1; |
| } |
| |
| if (fstat(fd, &filestat) < 0) { |
| perror("Error stating file"); |
| return 1; |
| } |
| |
| map = mmap(0, filestat.st_size, PROT_READ, MAP_SHARED, fd, 0); |
| if (map == MAP_FAILED) { |
| perror("Error mmapping the file"); |
| goto nla_put_failure; |
| } |
| |
| key = nla_nest_start(msg, NL80211_ATTR_TESTDATA); |
| if (!key) { |
| goto nla_put_failure; |
| } |
| |
| NLA_PUT_U32(msg, WL1271_TM_ATTR_CMD_ID, WL1271_TM_CMD_NVS_PUSH); |
| NLA_PUT(msg, WL1271_TM_ATTR_DATA, filestat.st_size, map); |
| |
| nla_nest_end(msg, key); |
| |
| goto cleanup; |
| |
| nla_put_failure: |
| retval = -ENOBUFS; |
| |
| cleanup: |
| if (map != MAP_FAILED) { |
| munmap(map, filestat.st_size); |
| } |
| |
| close(fd); |
| |
| return retval; |
| } |
| |
| COMMAND(set, push_nvs, "<nvs filename>", |
| NL80211_CMD_TESTMODE, 0, CIB_PHY, handle_push_nvs, |
| "Push NVS file into the system"); |
| |
| #if 0 |
| static int handle_fetch_nvs(struct nl80211_state *state, |
| struct nl_cb *cb, |
| struct nl_msg *msg, |
| int argc, char **argv) |
| { |
| char *end; |
| void *map = MAP_FAILED; |
| int fd, retval = 0; |
| struct nlattr *key; |
| struct stat filestat; |
| |
| if (argc != 0) |
| return 1; |
| |
| key = nla_nest_start(msg, NL80211_ATTR_TESTDATA); |
| if (!key) |
| goto nla_put_failure; |
| |
| NLA_PUT_U32(msg, WL1271_TM_ATTR_CMD_ID, WL1271_TM_CMD_NVS_PUSH); |
| NLA_PUT_U32(msg, WL1271_TM_ATTR_IE_ID, WL1271_TM_CMD_NVS_PUSH); |
| |
| nla_nest_end(msg, key); |
| |
| goto cleanup; |
| |
| nla_put_failure: |
| retval = -ENOBUFS; |
| |
| cleanup: |
| if (map != MAP_FAILED) |
| munmap(map, filestat.st_size); |
| |
| close(fd); |
| |
| return retval; |
| } |
| |
| COMMAND(set, fetch_nvs, NULL, |
| NL80211_CMD_TESTMODE, 0, CIB_NETDEV, handle_fetch_nvs, |
| "Send command to fetch NVS file"); |
| #endif |
| static int get_nvs_mac(struct nl80211_state *state, struct nl_cb *cb, |
| struct nl_msg *msg, int argc, char **argv) |
| { |
| unsigned char mac_buff[12]; |
| int fd; |
| |
| argc -= 2; |
| argv += 2; |
| |
| if (argc != 1) { |
| return 2; |
| } |
| |
| fd = open(argv[0], O_RDONLY); |
| if (fd < 0) { |
| perror("Error opening file for reading"); |
| return 1; |
| } |
| |
| read(fd, mac_buff, 12); |
| |
| printf("MAC addr from NVS: %02x:%02x:%02x:%02x:%02x:%02x\n", |
| mac_buff[11], mac_buff[10], mac_buff[6], |
| mac_buff[5], mac_buff[4], mac_buff[3]); |
| |
| close(fd); |
| |
| return 0; |
| } |
| |
| COMMAND(get, nvs_mac, "<nvs filename>", 0, 0, CIB_NONE, get_nvs_mac, |
| "Get MAC addr from NVS file (offline)"); |
| |
| /* |
| * Sets MAC address in NVS. |
| * The default value for MAC is random where 1 byte zero. |
| */ |
| static int set_nvs_mac(struct nl80211_state *state, struct nl_cb *cb, |
| struct nl_msg *msg, int argc, char **argv) |
| { |
| unsigned char mac_buff[12]; |
| unsigned char in_mac[6]; |
| int fd; |
| |
| argc -= 2; |
| argv += 2; |
| |
| if (argc < 1 || (argc == 2 && (strlen(argv[1]) != 17))) { |
| return 2; |
| } |
| |
| if (argc == 2) { |
| sscanf(argv[1], "%2x:%2x:%2x:%2x:%2x:%2x", |
| (unsigned int *)&in_mac[0], (unsigned int *)&in_mac[1], |
| (unsigned int *)&in_mac[2], (unsigned int *)&in_mac[3], |
| (unsigned int *)&in_mac[4], (unsigned int *)&in_mac[5]); |
| } else { |
| srand((unsigned)time(NULL)); |
| |
| in_mac[0] = 0x0; |
| in_mac[1] = rand()%256; |
| in_mac[2] = rand()%256; |
| in_mac[3] = rand()%256; |
| in_mac[4] = rand()%256; |
| in_mac[5] = rand()%256; |
| } |
| |
| fd = open(argv[0], O_RDWR); |
| if (fd < 0) { |
| perror("Error opening file for reading"); |
| return 1; |
| } |
| |
| read(fd, mac_buff, 12); |
| #if 0 |
| printf("Got MAC addr for NVS: %02x:%02x:%02x:%02x:%02x:%02x\n", |
| in_mac[0], in_mac[1], in_mac[2], |
| in_mac[3], in_mac[4], in_mac[5]); |
| |
| printf("Got MAC addr from NVS: %02x:%02x:%02x:%02x:%02x:%02x\n", |
| mac_buff[11], mac_buff[10], mac_buff[6], |
| mac_buff[5], mac_buff[4], mac_buff[3]); |
| #endif |
| mac_buff[11] = in_mac[0]; |
| mac_buff[10] = in_mac[1]; |
| mac_buff[6] = in_mac[2]; |
| mac_buff[5] = in_mac[3]; |
| mac_buff[4] = in_mac[4]; |
| mac_buff[3] = in_mac[5]; |
| |
| lseek(fd, 0L, 0); |
| |
| write(fd, mac_buff, 12); |
| |
| close(fd); |
| |
| return 0; |
| } |
| |
| COMMAND(set, nvs_mac, "<nvs file> [<mac addr>]", 0, 0, CIB_NONE, set_nvs_mac, |
| "Set MAC addr in NVS file (offline), like XX:XX:XX:XX:XX:XX"); |
| |
| static int set_ref_nvs(struct nl80211_state *state, struct nl_cb *cb, |
| struct nl_msg *msg, int argc, char **argv) |
| { |
| struct wl12xx_common cmn = { |
| .arch = UNKNOWN_ARCH, |
| .parse_ops = NULL, |
| .dual_mode = DUAL_MODE_UNSET, |
| .done_fem = NO_FEM_PARSED |
| }; |
| |
| argc -= 2; |
| argv += 2; |
| |
| if (argc != 1) { |
| return 1; |
| } |
| |
| if (read_ini(*argv, &cmn)) { |
| fprintf(stderr, "Fail to read ini file\n"); |
| return 1; |
| } |
| |
| cfg_nvs_ops(&cmn); |
| |
| if (create_nvs_file(&cmn)) { |
| fprintf(stderr, "Fail to create reference NVS file\n"); |
| return 1; |
| } |
| #if 0 |
| printf("\n\tThe NVS file (%s) is ready\n\tCopy it to %s and " |
| "reboot the system\n\n", |
| NEW_NVS_NAME, CURRENT_NVS_NAME); |
| #endif |
| return 0; |
| } |
| |
| COMMAND(set, ref_nvs, "<ini file>", 0, 0, CIB_NONE, set_ref_nvs, |
| "Create reference NVS file"); |
| |
| static int set_ref_nvs2(struct nl80211_state *state, struct nl_cb *cb, |
| struct nl_msg *msg, int argc, char **argv) |
| { |
| struct wl12xx_common cmn = { |
| .arch = UNKNOWN_ARCH, |
| .parse_ops = NULL, |
| .dual_mode = DUAL_MODE_UNSET, |
| .done_fem = NO_FEM_PARSED |
| }; |
| |
| argc -= 2; |
| argv += 2; |
| |
| if (argc != 2) { |
| return 1; |
| } |
| |
| if (read_ini(*argv, &cmn)) { |
| return 1; |
| } |
| |
| argv++; |
| if (read_ini(*argv, &cmn)) { |
| return 1; |
| } |
| |
| cfg_nvs_ops(&cmn); |
| |
| if (create_nvs_file(&cmn)) { |
| fprintf(stderr, "Fail to create reference NVS file\n"); |
| return 1; |
| } |
| #if 0 |
| printf("\n\tThe NVS file (%s) is ready\n\tCopy it to %s and " |
| "reboot the system\n\n", |
| NEW_NVS_NAME, CURRENT_NVS_NAME); |
| #endif |
| return 0; |
| } |
| |
| COMMAND(set, ref_nvs2, "<ini file> <ini file>", 0, 0, CIB_NONE, set_ref_nvs2, |
| "Create reference NVS file for 2 FEMs"); |
| |
| static int set_upd_nvs(struct nl80211_state *state, struct nl_cb *cb, |
| struct nl_msg *msg, int argc, char **argv) |
| { |
| char *fname = NULL; |
| struct wl12xx_common cmn = { |
| .arch = UNKNOWN_ARCH, |
| .parse_ops = NULL |
| }; |
| |
| argc -= 2; |
| argv += 2; |
| |
| if (argc < 1) { |
| return 1; |
| } |
| |
| if (read_ini(*argv, &cmn)) { |
| fprintf(stderr, "Fail to read ini file\n"); |
| return 1; |
| } |
| |
| cfg_nvs_ops(&cmn); |
| |
| if (argc == 2) { |
| fname = *++argv; |
| } |
| |
| if (update_nvs_file(fname, &cmn)) { |
| fprintf(stderr, "Fail to update NVS file\n"); |
| return 1; |
| } |
| #if 0 |
| printf("\n\tThe updated NVS file (%s) is ready\n\tCopy it to %s and " |
| "reboot the system\n\n", NEW_NVS_NAME, CURRENT_NVS_NAME); |
| #endif |
| return 0; |
| } |
| |
| COMMAND(set, upd_nvs, "<ini file> [<nvs file>]", 0, 0, CIB_NONE, set_upd_nvs, |
| "Update values of a NVS from INI file"); |
| |
| static int get_dump_nvs(struct nl80211_state *state, struct nl_cb *cb, |
| struct nl_msg *msg, int argc, char **argv) |
| { |
| char *fname = NULL; |
| struct wl12xx_common cmn = { |
| .arch = UNKNOWN_ARCH, |
| .parse_ops = NULL |
| }; |
| |
| argc -= 2; |
| argv += 2; |
| |
| if (argc > 0) { |
| fname = *argv; |
| } |
| |
| if (dump_nvs_file(fname, &cmn)) { |
| fprintf(stderr, "Fail to dump NVS file\n"); |
| return 1; |
| } |
| |
| return 0; |
| } |
| |
| COMMAND(get, dump_nvs, "[<nvs file>]", 0, 0, CIB_NONE, get_dump_nvs, |
| "Dump NVS file, specified by option or current"); |
| |
| static int set_autofem(struct nl80211_state *state, struct nl_cb *cb, |
| struct nl_msg *msg, int argc, char **argv) |
| { |
| char *fname = NULL; |
| unsigned char val; |
| struct wl12xx_common cmn = { |
| .arch = UNKNOWN_ARCH, |
| .parse_ops = NULL |
| }; |
| |
| argc -= 2; |
| argv += 2; |
| |
| if (argc < 1) { |
| fprintf(stderr, "Missing argument\n"); |
| return 2; |
| } |
| |
| sscanf(argv[0], "%2x", (unsigned int *)&val); |
| |
| if (argc == 2) { |
| fname = argv[1]; |
| } |
| |
| if (set_nvs_file_autofem(fname, val, &cmn)) { |
| fprintf(stderr, "Fail to set AutoFEM\n"); |
| return 1; |
| } |
| |
| return 0; |
| } |
| |
| COMMAND(set, autofem, "<0-manual|1-auto> [<nvs file>]", 0, 0, CIB_NONE, set_autofem, |
| "Set Auto FEM detection, where 0 - manual, 1 - auto detection"); |
| |
| static int set_fem_manuf(struct nl80211_state *state, struct nl_cb *cb, |
| struct nl_msg *msg, int argc, char **argv) |
| { |
| char *fname = NULL; |
| unsigned char val; |
| struct wl12xx_common cmn = { |
| .arch = UNKNOWN_ARCH, |
| .parse_ops = NULL |
| }; |
| |
| argc -= 2; |
| argv += 2; |
| |
| if (argc < 1) { |
| fprintf(stderr, "Missing argument\n"); |
| return 2; |
| } |
| |
| sscanf(argv[0], "%2x", (unsigned int *)&val); |
| |
| if (argc == 2) { |
| fname = argv[1]; |
| } |
| |
| if (set_nvs_file_fem_manuf(fname, val, &cmn)) { |
| fprintf(stderr, "Fail to set AutoFEM\n"); |
| return 1; |
| } |
| |
| return 0; |
| } |
| |
| COMMAND(set, fem_manuf, "<0|1> [<nvs file>]", 0, 0, CIB_NONE, set_fem_manuf, |
| "Set FEM manufacturer"); |
| |