#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");