/* * Command implementations */ #include #include #include #include #include "besphy_rf.h" #define U8_MAX 255 #define U16_MAX 65535 /* rf cmd length cannot exceed 640 bytes */ #define RF_LEN_MAX 640 struct vendor_rf_cmd_t { u32 cmd_type; u32 cmd_argc; u32 cmd_len; u8 cmd[0]; }; /* ID - BES_MSG_TEST */ struct bes_msg_test_t { int dummy; }; /** * ID -BES_MSG_SET_SNAP_FRAME * bes_msg_set_snap_frame - set SNAP frame format * @len: length of SNAP frame, if 0 SNAP frame disabled * @frame: SNAP frame format * * In this structure is difference between user space because * format and length have to be hidden * */ struct bes_msg_set_snap_frame_t { u8 len; u8 frame[0]; }; struct nl_data { size_t d_size; void *d_data; }; /* ID - BES_MSG_TEST */ struct advance_scan_elems { u8 scanMode; u16 duration; }; /** * ID - BES_MSG_SET_TX_QUEUE_PARAMS * bes_msg_set_txqueue_params - store Tx queue params * @user_priority: User priority for which TSPEC negotiated * @medium_time: Allowed medium time * @expiry_time: The expiry time of MSDU * */ struct bes_msg_set_txqueue_params { u8 user_priority; u16 medium_time; u16 expiry_time; }; /** * ID - BES_MSG_START_STOP_TSM * bes_msg_set_start_stop_tsm - To start or stop collecting TSM metrics in * bes2600 driver * @start: To start or stop collecting TSM metrics * @up: up for which metrics to be collected * @packetization_delay: Packetization period for this TID * */ struct bes_msg_start_stop_tsm_t { u8 start; /*1: To start, 0: To stop*/ u8 up; u16 packetization_delay; }; /** * ID - BES_MSG_SET_POWER_SAVE * power_save_elems - To enable/disable legacy power Save */ struct power_save_elems { int powerSave; }; /** * add_ip_offload_t - Parameters related to tcp alive: port, payload length, payload */ struct add_ip_offload_t { uint8_t proto; uint16_t dest_port; uint16_t payload_len; uint8_t payload[0]; }; /** * ip_alive_iac_idx - idx of tcp & udp alive stream */ struct ip_alive_iac_idx { int idx; }; /** * ip_alive_period - tcp & udp alive period */ struct ip_alive_period { int period; }; /** * bes_tsm_stats - To retrieve the Transmit Stream Measurement stats * @actual_msrmt_start_time: The TSF at the time at which the measurement * started * @msrmt_duration: Duration for measurement * @peer_sta_addr: Peer STA address * @tid: TID for which measurements were made * @reporting_reason: Reason for report sent * @txed_msdu_count: The number of MSDUs transmitted for the specified TID * @msdu_discarded_count: The number of discarded MSDUs for the specified TID * @msdu_failed_count: The number of failed MSDUs for the specified TID * @multi_retry_count: The number of MSDUs which were retried * @qos_cfpolls_lost_count: The number of QOS CF polls frames lost * @avg_q_delay: Average queue delay * @avg_transmit_delay: Average transmit delay * @bin0_range: Delay range of the first bin (Bin 0) * @bin0: bin0 transmit delay histogram * @bin1: bin1 transmit delay histogram * @bin2: bin2 transmit delay histogram * @bin3: bin3 transmit delay histogram * @bin4: bin4 transmit delay histogram * @bin5: bin5 transmit delay histogram * */ struct bes_tsm_stats { u64 actual_msrmt_start_time; u16 msrmt_duration; u8 peer_sta_addr[6]; u8 tid; u8 reporting_reason; u32 txed_msdu_count; u32 msdu_discarded_count; u32 msdu_failed_count; u32 multi_retry_count; u32 qos_cfpolls_lost_count; u32 avg_q_delay; u32 avg_transmit_delay; u8 bin0_range; u32 bin0; u32 bin1; u32 bin2; u32 bin3; u32 bin4; u32 bin5; } __packed; struct wsm_tx_power_range { int min_power_level; int max_power_level; u32 stepping; }; struct vendor_rf_cmd_reply { u32 id; u32 len; char msg[0]; }; struct wifi_power_cali_save_t { u16 mode; u16 band; u16 ch; u16 power_cali; u16 status; /* 0: fail, 1: success */ }; struct wifi_freq_cali_save_t { u16 freq_cali; u16 status; /* 0: fail, 1: success */ }; /* code to do everything */ static void print_dump(const char *fmt, unsigned int size, unsigned int count, const void *buffer) { int i = 0; int rowsize = 16; switch(size) { case sizeof(uint32_t): while(i < count) { printf(fmt, *(uint32_t *)((uint32_t *)buffer + i)); if (i % rowsize == rowsize - 1) printf("\n"); i++; } break; case sizeof(uint16_t): while(i < count) { printf(fmt, *(uint16_t *)((uint16_t *)buffer + i)); if (i % rowsize == rowsize - 1) printf("\n"); i++; } break; case sizeof(uint8_t): default: while(i < count) { printf(fmt, *(uint8_t *)((uint8_t *)buffer + i)); if (i % rowsize == rowsize - 1) printf("\n"); i++; } break; } printf("\n"); } static int print_recvmsgs(struct nl_msg *msg, void *arg) { struct nlattr *tb[NL80211_ATTR_MAX + 2]; struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg)); /* Gets the payload of the msg */ struct nlattr *td[BESPHY_TM_ATTR_MAX + 2]; struct bes_tsm_stats tsm_stats; struct wsm_tx_power_range power_range[2]; int cmd_id = *((int *)arg); struct vendor_rf_cmd_reply *rf_cmd_msg; struct wifi_power_cali_save_t *wifi_power_cali; struct wifi_freq_cali_save_t *wifi_freq_cali; /* get reply message for all nlmsg */ nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), genlmsg_attrlen(gnlh, 0), NULL); if (!tb[NL80211_ATTR_TESTDATA] || !tb[NL80211_ATTR_WIPHY]) { printf("no data!\n"); return NL_SKIP; } /* get reply message for rf test cmd */ nla_parse(td, BESPHY_TM_ATTR_MAX, nla_data(tb[NL80211_ATTR_TESTDATA]), nla_len(tb[NL80211_ATTR_TESTDATA]), NULL); if (!td[BESPHY_TM_MSG_DATA]) { printf("no recvmsgs info\n"); return NL_SKIP; } switch (cmd_id) { case BES_MSG_TEST: printf("\nphy#%d, the cmd msg_test recvmsgs is:\ndummy = %d\n\n", nla_get_u32(tb[NL80211_ATTR_WIPHY]), (*((int *)nla_data(td[BESPHY_TM_MSG_DATA])))); break; case BES_MSG_GET_TX_POWER_LEVEL: printf("\nphy#%d, the cmd get_tx_power_level recvmsgs is:\npower = %d\n\n", nla_get_u32(tb[NL80211_ATTR_WIPHY]), (*((int *)nla_data(td[BESPHY_TM_MSG_DATA])))); break; case BES_MSG_GET_TX_POWER_RANGE: memcpy(power_range, (struct wsm_tx_power_range *)nla_data(td[BESPHY_TM_MSG_DATA]), sizeof(power_range)); printf("\nphy#%d, the cmd get_tx_power_range recvmsgs is:\ \ntxPowerRange[0]:\nmin_power_level = %d, max_power_level = %d, stepping = %u\n", nla_get_u32(tb[NL80211_ATTR_WIPHY]), power_range[0].min_power_level, power_range[0].max_power_level, power_range[0].stepping); printf("txPowerRange[1]:\nmin_power_level = %d, max_power_level = %d, stepping = %u\n", power_range[1].min_power_level, power_range[1].max_power_level, power_range[1].stepping); break; case BES_MSG_GET_TSM_PARAMS: memcpy(&tsm_stats, (struct bes_tsm_stats *)nla_data(td[BESPHY_TM_MSG_DATA]), sizeof(tsm_stats)); printf("\nphy#%d, the cmd get_tsm_params recvmsgs is:\n", nla_get_u32(tb[NL80211_ATTR_WIPHY])); #if __WORDSIZE == 64 printf("actual_msrmt_start_time = %lu\n", tsm_stats.actual_msrmt_start_time); #else printf("actual_msrmt_start_time = %llu\n", tsm_stats.actual_msrmt_start_time); #endif printf("msrmt_duration = %d\n" "peer_sta_addr = %02x:%02x:%02x:%02x:%02x:%02x\ntid = %d\n" "reporting_reason = %d\ntxed_msdu_count = %u\n" "msdu_discarded_count = %u\nmsdu_failed_count = %u\n" "multi_retry_count = %u\nqos_cfpolls_lost_count = %u\n" "avg_q_delay = %u\navg_transmit_delay = %u\n" "bin0_range = %d\nbin0 = %u\nbin1 = %u\nbin1 = %u\n" "bin3 = %u\nbin4 = %u\nbin5 = %u\n\n", tsm_stats.msrmt_duration, tsm_stats.peer_sta_addr[0], tsm_stats.peer_sta_addr[1], tsm_stats.peer_sta_addr[2], tsm_stats.peer_sta_addr[3], tsm_stats.peer_sta_addr[4], tsm_stats.peer_sta_addr[5], tsm_stats.tid, tsm_stats.reporting_reason, tsm_stats.txed_msdu_count, tsm_stats.msdu_discarded_count, tsm_stats.msdu_failed_count, tsm_stats.multi_retry_count, tsm_stats.qos_cfpolls_lost_count, tsm_stats.avg_q_delay, tsm_stats.avg_transmit_delay, tsm_stats.bin0_range, tsm_stats.bin0, tsm_stats.bin1, tsm_stats.bin2, tsm_stats.bin3, tsm_stats.bin4, tsm_stats.bin5); break; case BES_MSG_GET_ROAM_DELAY: printf("\nphy#%d, the cmd get_roam_delay recvmsgs is:\nroam_delay = %d\n\n", nla_get_u32(tb[NL80211_ATTR_WIPHY]), (*((int *)nla_data(td[BESPHY_TM_MSG_DATA])))); break; case BES_MSG_ADD_IP_OFFLOAD: printf("\nphy#%d, the keep_alive_cfg recvmsgs is:\nkeep_alive_iac_idx = %d\n\n", nla_get_u32(tb[NL80211_ATTR_WIPHY]), (*((int *)nla_data(td[BESPHY_TM_MSG_DATA])))); break; case BES_MSG_VENDOR_RF_CMD: rf_cmd_msg = (struct vendor_rf_cmd_reply *)nla_data(td[BESPHY_TM_MSG_DATA]); switch (rf_cmd_msg->id) { case VENDOR_RF_SIGNALING_CMD: printf("\nphy#%d, the vendor signaling cmd recvmsgs is:\n%s\n\n", nla_get_u32(tb[NL80211_ATTR_WIPHY]), rf_cmd_msg->msg); break; case VENDOR_RF_NOSIGNALING_CMD: printf("\nphy#%d, the rf cmd recvmsgs is:\n%s\n\n", nla_get_u32(tb[NL80211_ATTR_WIPHY]), rf_cmd_msg->msg); break; case VENDOR_RF_SAVE_CMD: printf("\nphy#%d, save success.\n\n", nla_get_u32(tb[NL80211_ATTR_WIPHY])); break; case VENDOR_RF_GET_SAVE_FREQOFFSET_CMD: printf("\nphy#%d, freq clai: 0x%04x\n\n", nla_get_u32(tb[NL80211_ATTR_WIPHY]), ((uint16_t *)rf_cmd_msg->msg)[0]); break; case VENDOR_RF_GET_SAVE_POWERLEVEL_CMD: printf("\nphy#%d, power cali 2g:\n", nla_get_u32(tb[NL80211_ATTR_WIPHY])); print_dump("0x%04x ", 2, 3, (uint16_t *)rf_cmd_msg->msg); printf("power cali 5g:\n"); print_dump("0x%04x ", 2, 13, (uint16_t *)rf_cmd_msg->msg + 3); break; case VENDOR_RF_SAVE_FREQOFFSET_CMD: wifi_freq_cali = (struct wifi_freq_cali_save_t *)(rf_cmd_msg->msg); printf("\nphy#%d, freqOffset save msg:\n", nla_get_u32(tb[NL80211_ATTR_WIPHY])); if (wifi_freq_cali->status) printf("success to save freq cali.\n"); else printf("fail to save freq cali.\n"); printf("freq cali = 0x%04x\n", wifi_freq_cali->freq_cali); break; case VENDOR_RF_SAVE_POWERLEVEL_CMD: wifi_power_cali = (struct wifi_power_cali_save_t *)(rf_cmd_msg->msg); printf("\nphy#%d, powerlevel save msg:\n", nla_get_u32(tb[NL80211_ATTR_WIPHY])); if (wifi_power_cali->status) printf("success to save power cali.\n"); else printf("fail to save power cali.\n"); printf("mode = %u, band = %u, ch = %u, powerlevel = 0x%04x\n", wifi_power_cali->mode, wifi_power_cali->band, wifi_power_cali->ch, wifi_power_cali->power_cali); break; default: break; } break; default: break; } return NL_SKIP; } /** * rf_itoa() converts rf cmd related numbers to characters. * NUM_BIT represents the number of bits occupied * by cmd_num and cmd_len after they are converted into strings. */ #if 0 #define NUM_BIT 3 static int rf_itoa(char *rf_cmd, int num) { int i, j; int len; char tmp[NUM_BIT + 1]; if (num > pow(10, NUM_BIT) - 1 || num < 1) return -1; sprintf(tmp, "%d", num); len = strlen(tmp); if (len > NUM_BIT || len < 1) return -1; for (i = 0; i < NUM_BIT -len; i++) { rf_cmd[i] = '0'; } for (j = 0; i < NUM_BIT && j < len; i++, j++) { rf_cmd[i] = tmp[j]; } return 0; } #endif /* Merge all parameters into one pointer. */ static void str_join(u8 *cat_cmd, const int argc, char **argv) { char *argv_tmp; int i; for (i = 0; i < argc; argv++, i++) { argv_tmp = *argv; while (*argv_tmp != '\0') { *cat_cmd++ = *argv_tmp++; } if (i + 1 == argc) { *cat_cmd = '\0'; } else { *cat_cmd++ = ' '; } } } /* Gets the length of all parameters. */ static u32 get_cmd_len(const int argc, char **argv) { int i; u32 ret = 0; if (argc <= 1 || !argv) return 0; for (i = 0; i < argc; argv++, i++) { if (*argv != NULL) { ret += strlen(*argv) + 1; } else { return 0; } } return ret; } static int do_vendor_rf_cmd(struct nl_cb *cb, struct nl_msg *msg, const int argc, char **argv) { u32 cmd_len; static int id_type = BES_MSG_VENDOR_RF_CMD; cmd_len = get_cmd_len(argc, argv); if (!cmd_len || cmd_len > RF_LEN_MAX) { goto invalid_para; } struct vendor_rf_cmd_t *vendor_cmd = (struct vendor_rf_cmd_t *) malloc(cmd_len + 3 * sizeof(u32)); if (!vendor_cmd) { return -ENOMEM; } if (!strcmp(argv[1], "save")) vendor_cmd->cmd_type = VENDOR_RF_SAVE_CMD; else if (!strcmp(argv[1], "get_save_freqOffset")) vendor_cmd->cmd_type = VENDOR_RF_GET_SAVE_FREQOFFSET_CMD; else if (!strcmp(argv[1], "get_save_powerlevel")) vendor_cmd->cmd_type = VENDOR_RF_GET_SAVE_POWERLEVEL_CMD; else if (!strcmp(argv[1], "save_powerlevel")) vendor_cmd->cmd_type = VENDOR_RF_SAVE_POWERLEVEL_CMD; else if (!strcmp(argv[1], "save_freqOffset")) vendor_cmd->cmd_type = VENDOR_RF_SAVE_FREQOFFSET_CMD; else /* distinguish between signaling or non-signaling in the driver.*/ vendor_cmd->cmd_type = VENDOR_RF_SIG_NOSIG_MIX; vendor_cmd->cmd_argc = argc; vendor_cmd->cmd_len = cmd_len; str_join(vendor_cmd->cmd, argc, argv); struct nl_data *data_vendor_cmd = (struct nl_data *) malloc(sizeof(struct nl_data)); if (!data_vendor_cmd) { return -ENOMEM; } data_vendor_cmd->d_size = cmd_len + 3 * sizeof(u32); data_vendor_cmd->d_data = vendor_cmd; NLA_PUT_U32(msg, BESPHY_TM_MSG_ID, id_type); NLA_PUT_DATA(msg, BESPHY_TM_MSG_DATA, data_vendor_cmd); nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, print_recvmsgs, &id_type); free(vendor_cmd); vendor_cmd = NULL; free(data_vendor_cmd); data_vendor_cmd = NULL; return 0; invalid_para: return -EINVAL; nla_put_failure: return -ENOBUFS; } /** * Convert integer numeric string to a int number, * otherwise return false. * The number of converted numbers does not exceed the size range of INT. */ #define ATOI_MAX_BIT 10 static bool msg_tsm_atoi(const char *str, int *ret) { if (!str || strlen(str) == 0) return false; int i, j; int len, sum_tmp; bool negative = false; int inx_end = 0; unsigned int sum = 0; unsigned int num_max = pow(2, 31) - 1; len = strlen(str); if (str[0] == '-') { if (len > 1) { negative = true; inx_end = 1; num_max++; } else { return false; } } int multiple[ATOI_MAX_BIT]; multiple[ATOI_MAX_BIT - 1] = 1; for (i = ATOI_MAX_BIT -2; i >= 0; i--) { multiple[i] = 10 * multiple[i + 1]; } for (i = len - 1, j = ATOI_MAX_BIT -1; i >= inx_end && j >= 0; i--, j--) { if (str[i] >= '0' && str[i] <= '9') { sum_tmp = (str[i] - '0') * multiple[j]; if (sum <= sum + sum_tmp && sum + sum_tmp <= num_max) sum += sum_tmp; else return false; } else { return false; } } if (negative) { sum *= -1; } if (i >= inx_end) { return false; } else { *ret = sum; return true; } } static int do_msg_test_cmd(struct nl_cb *cb, struct nl_msg *msg, const int argc, char **argv) { if (argc != 3) { goto invalid_para; } int dummy_tmp; static int id_type = BES_MSG_TEST; struct bes_msg_test_t msg_test; if (!msg_tsm_atoi(argv[2], &dummy_tmp)) goto invalid_para; msg_test.dummy = dummy_tmp; NLA_PUT_U32(msg, BESPHY_TM_MSG_ID, BES_MSG_TEST); NLA_PUT_TYPE(msg, struct bes_msg_test_t, BESPHY_TM_MSG_DATA, msg_test); nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, print_recvmsgs, &id_type); return 0; invalid_para: return -EINVAL; nla_put_failure: return -ENOBUFS; } /** * Converts hexadecimal strings to a single byte. * The input format is, and each parameter contains one * or two hexadecimal characters. * such as 25 ab Ac AF 2 3 36 */ static bool hex_str_to_byte(int argc, char **argv, unsigned char *ret) { if (!ret) return false; int i, len; for (i = 0; i < argc; i++) { if (!argv[i]) return false; len = strlen(argv[i]); if (len > 2 || len < 1) return false; /* convert lowercase to uppercase. */ if(argv[i][len - 1] >= 'a' && argv[i][len - 1] <= 'f') argv[i][len - 1] = argv[i][len - 1] & ~0x20; /* convert hexadecimal characters to numbers. */ if (argv[i][len - 1] >= 'A' && argv[i][len - 1] <= 'F') ret[i] = argv[i][len - 1] - 'A' + 10; else if (argv[i][len - 1] >= '0' && argv[i][len - 1] <= '9') ret[i] = argv[i][len - 1] & ~0x30; else return false; if (len == 2) { if(argv[i][0] >= 'a' && argv[i][0] <= 'f') argv[i][0] = argv[i][0] & ~0x20; if (argv[i][0] >= 'A' && argv[i][0] <= 'F') ret[i] |= (argv[i][0] - 'A' + 10) << 4; else if (argv[i][0] >= '0' && argv[i][0] <= '9') ret[i] |= (argv[i][0] & ~0x30) << 4; else return false; } } return true; } static int do_set_snap_frame_cmd(struct nl_cb *cb, struct nl_msg *msg, int argc, char **argv) { /* argc contains phy and command name */ if (argc > U8_MAX + 2 || argc < 3) { goto invalid_para; } argc -= 2; argv += 2; struct bes_msg_set_snap_frame_t *snap_frame = (struct bes_msg_set_snap_frame_t *) malloc(argc + 1); if (!snap_frame) { return -ENOMEM; } snap_frame->len = (u8)argc; if (!hex_str_to_byte(argc, argv, snap_frame->frame)) goto invalid_para; struct nl_data *data_snap_frame = (struct nl_data *) malloc(sizeof(struct nl_data)); if (!data_snap_frame) { return -ENOMEM; } data_snap_frame->d_size = argc + 1; data_snap_frame->d_data = snap_frame; NLA_PUT_U32(msg, BESPHY_TM_MSG_ID, BES_MSG_SET_SNAP_FRAME); NLA_PUT_DATA(msg, BESPHY_TM_MSG_DATA, data_snap_frame); free(snap_frame); snap_frame = NULL; free(data_snap_frame); data_snap_frame = NULL; return 0; invalid_para: return -EINVAL; nla_put_failure: return -ENOBUFS; } static int do_get_tx_power_level_cmd(struct nl_cb *cb, struct nl_msg *msg, const int argc, char **argv) { if (argc != 2) { goto invalid_para; } static int id_type = BES_MSG_GET_TX_POWER_LEVEL; NLA_PUT_U32(msg, BESPHY_TM_MSG_ID, BES_MSG_GET_TX_POWER_LEVEL); NLA_PUT_U32(msg, BESPHY_TM_MSG_DATA, 0); nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, print_recvmsgs, &id_type); return 0; invalid_para: return -EINVAL; nla_put_failure: return -ENOBUFS; } static int do_get_tx_power_range_cmd(struct nl_cb *cb, struct nl_msg *msg, const int argc, char **argv) { if (argc != 2) { goto invalid_para; } static int id_type = BES_MSG_GET_TX_POWER_RANGE; NLA_PUT_U32(msg, BESPHY_TM_MSG_ID, BES_MSG_GET_TX_POWER_RANGE); NLA_PUT_U32(msg, BESPHY_TM_MSG_DATA, 0); nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, print_recvmsgs, &id_type); return 0; invalid_para: return -EINVAL; nla_put_failure: return -ENOBUFS; } static int do_set_advance_scan_elems_cmd(struct nl_cb *cb, struct nl_msg *msg, const int argc, char **argv) { if (argc != 4) { goto invalid_para; } int duration_tmp, len_tmp; struct advance_scan_elems scan_elems; if (!msg_tsm_atoi(argv[2], &len_tmp) || !msg_tsm_atoi(argv[3], &duration_tmp)) goto invalid_para; if (duration_tmp > U16_MAX || duration_tmp < 0) { goto invalid_para; } if (len_tmp > U8_MAX || len_tmp < 0) { goto invalid_para; } scan_elems.scanMode = (u8)len_tmp; scan_elems.duration = (u16)duration_tmp; NLA_PUT_U32(msg, BESPHY_TM_MSG_ID, BES_MSG_SET_ADVANCE_SCAN_ELEMS); NLA_PUT_TYPE(msg, struct advance_scan_elems, BESPHY_TM_MSG_DATA, scan_elems); return 0; invalid_para: return -EINVAL; nla_put_failure: return -ENOBUFS; } static int do_set_tx_queue_params_cmd(struct nl_cb *cb, struct nl_msg *msg, const int argc, char **argv) { if (argc != 5) { goto invalid_para; } int user_priority_tmp; int medium_time_tmp; int expiry_time_tmp; struct bes_msg_set_txqueue_params txqueue_params; if (!msg_tsm_atoi(argv[2], &user_priority_tmp) || !msg_tsm_atoi(argv[3], &medium_time_tmp) || !msg_tsm_atoi(argv[4], &expiry_time_tmp)) goto invalid_para; if (user_priority_tmp > U8_MAX || user_priority_tmp < 0) goto invalid_para; if (medium_time_tmp > U16_MAX || medium_time_tmp < 0) goto invalid_para; if (expiry_time_tmp > U16_MAX || expiry_time_tmp < 0) goto invalid_para; txqueue_params.user_priority = (u8)user_priority_tmp; txqueue_params.medium_time = (u16)medium_time_tmp; txqueue_params.expiry_time = (u16)expiry_time_tmp; NLA_PUT_U32(msg, BESPHY_TM_MSG_ID, BES_MSG_SET_TX_QUEUE_PARAMS); NLA_PUT_TYPE(msg, struct bes_msg_set_txqueue_params, BESPHY_TM_MSG_DATA, txqueue_params); return 0; invalid_para: return -EINVAL; nla_put_failure: return -ENOBUFS; } static int do_start_stop_tsm_cmd(struct nl_cb *cb, struct nl_msg *msg, const int argc, char **argv) { if (argc != 5) { goto invalid_para; } struct bes_msg_start_stop_tsm_t start_stop_tsm; int start_tmp; int up_tmp; int packetization_delay_tmp; if (!msg_tsm_atoi(argv[2], &start_tmp) || !msg_tsm_atoi(argv[3], &up_tmp) || !msg_tsm_atoi(argv[4], &packetization_delay_tmp)) goto invalid_para; if (start_tmp > U8_MAX || start_tmp < 0) goto invalid_para; if (up_tmp > U8_MAX || up_tmp < 0) goto invalid_para; if (packetization_delay_tmp > U16_MAX || packetization_delay_tmp < 0) goto invalid_para; start_stop_tsm.start = (u8)start_tmp; start_stop_tsm.up = (u8)up_tmp; start_stop_tsm.packetization_delay = (u16)packetization_delay_tmp; NLA_PUT_U32(msg, BESPHY_TM_MSG_ID, BES_MSG_START_STOP_TSM); NLA_PUT_TYPE(msg, struct bes_msg_start_stop_tsm_t, BESPHY_TM_MSG_DATA, start_stop_tsm); return 0; invalid_para: return -EINVAL; nla_put_failure: return -ENOBUFS; } static int do_get_tsm_params_cmd(struct nl_cb *cb, struct nl_msg *msg, const int argc, char **argv) { if (argc != 2) { goto invalid_para; } static int id_type = BES_MSG_GET_TSM_PARAMS; NLA_PUT_U32(msg, BESPHY_TM_MSG_ID, BES_MSG_GET_TSM_PARAMS); NLA_PUT_U32(msg, BESPHY_TM_MSG_DATA, 0); nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, print_recvmsgs, &id_type); return 0; invalid_para: return -EINVAL; nla_put_failure: return -ENOBUFS; } static int do_get_roam_delay_cmd(struct nl_cb *cb, struct nl_msg *msg, const int argc, char **argv) { if (argc != 2) { goto invalid_para; } static int id_type = BES_MSG_GET_ROAM_DELAY; NLA_PUT_U32(msg, BESPHY_TM_MSG_ID, BES_MSG_GET_ROAM_DELAY); NLA_PUT_U32(msg, BESPHY_TM_MSG_DATA, 0); nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, print_recvmsgs, &id_type); return 0; invalid_para: return -EINVAL; nla_put_failure: return -ENOBUFS; } static int do_set_power_save_cmd(struct nl_cb *cb, struct nl_msg *msg, const int argc, char **argv) { if (argc != 3) { goto invalid_para; } int powerSave_tmp; struct power_save_elems power_elems; if (!msg_tsm_atoi(argv[2], &powerSave_tmp)) goto invalid_para; power_elems.powerSave = powerSave_tmp; NLA_PUT_U32(msg, BESPHY_TM_MSG_ID, BES_MSG_SET_POWER_SAVE); NLA_PUT_TYPE(msg, struct power_save_elems, BESPHY_TM_MSG_DATA, power_elems); return 0; invalid_para: return -EINVAL; nla_put_failure: return -ENOBUFS; } static int do_add_ip_offload_cmd(struct nl_cb *cb, struct nl_msg *msg, const int argc, char **argv) { if (argc != 5) { goto invalid_para; } u8 proto_temp; int dest_port_temp; int payload_len_temp; int data_len; static int id_type = BES_MSG_ADD_IP_OFFLOAD; if (!strcmp(argv[2], "udp")) proto_temp = 0; else if (!strcmp(argv[2], "tcp")) proto_temp = 1; else goto invalid_para; if (!msg_tsm_atoi(argv[3], &dest_port_temp)) goto invalid_para; if (dest_port_temp > U16_MAX || dest_port_temp < 0) goto invalid_para; payload_len_temp = strlen(argv[4]); if (payload_len_temp > U16_MAX || payload_len_temp < 0) goto invalid_para; data_len = 3 * sizeof(uint16_t) + payload_len_temp + 1; struct add_ip_offload_t *add_ip_offload = (struct add_ip_offload_t *) malloc(data_len); if (!add_ip_offload) { return -ENOMEM; } add_ip_offload->proto = proto_temp; add_ip_offload->dest_port = (u16)dest_port_temp; add_ip_offload->payload_len = (u16)payload_len_temp; memcpy(add_ip_offload->payload, argv[4], payload_len_temp + 1); struct nl_data *data_add_ip_offload = (struct nl_data *) malloc(sizeof(struct nl_data)); if (!data_add_ip_offload) { return -ENOMEM; } data_add_ip_offload->d_size = data_len; data_add_ip_offload->d_data = add_ip_offload; NLA_PUT_U32(msg, BESPHY_TM_MSG_ID, BES_MSG_ADD_IP_OFFLOAD); NLA_PUT_DATA(msg, BESPHY_TM_MSG_DATA, data_add_ip_offload); nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, print_recvmsgs, &id_type); free(add_ip_offload); add_ip_offload = NULL; free(data_add_ip_offload); data_add_ip_offload = NULL; return 0; invalid_para: return -EINVAL; nla_put_failure: return -ENOBUFS; } static int do_del_ip_offload_cmd(struct nl_cb *cb, struct nl_msg *msg, const int argc, char **argv) { if (argc != 3) { goto invalid_para; } if (strncmp(argv[0],"wlan", 4)) { printf("%s para error, input wlanname\n", argv[0]); goto invalid_para; } int idx_tmp; struct ip_alive_iac_idx iac_idx; if (!msg_tsm_atoi(argv[2], &idx_tmp)) goto invalid_para; iac_idx.idx = idx_tmp; NLA_PUT_U32(msg, BESPHY_TM_MSG_ID, BES_MSG_DEL_IP_OFFLOAD); NLA_PUT_TYPE(msg, struct ip_alive_iac_idx, BESPHY_TM_MSG_DATA, iac_idx); return 0; invalid_para: return -EINVAL; nla_put_failure: return -ENOBUFS; } static int do_set_ip_offload_period_cmd(struct nl_cb *cb, struct nl_msg *msg, const int argc, char **argv) { if (argc != 3) { goto invalid_para; } if (strncmp(argv[0],"wlan", 4)) { printf("%s para error, input wlanname\n", argv[0]); goto invalid_para; } int period_tmp; struct ip_alive_period alive_period; if (!msg_tsm_atoi(argv[2], &period_tmp)) goto invalid_para; alive_period.period = period_tmp; NLA_PUT_U32(msg, BESPHY_TM_MSG_ID, BES_MSG_SET_IP_OFFLOAD_PERIOD); NLA_PUT_TYPE(msg, struct ip_alive_period, BESPHY_TM_MSG_DATA, alive_period); return 0; invalid_para: return -EINVAL; nla_put_failure: return -ENOBUFS; } /* * Print the currently executed test command. * And fill command to genlmsg. */ static int do_besphy_test_cmd(struct nl_cb *cb, struct nl_msg *msg, const int argc, char **argv) { int i, ret; if (argv[1]) { printf("do_%s: argc=%d, argv: %s ",argv[1], argc - 1, argv[1]); } else { goto para_input_error; } for (i = 2; i < argc; i++) { if (argv[i]) { printf("%s ",argv[i]); } else { printf("\n"); goto para_input_error; } } printf("\n"); if (!strcmp(argv[1], "msg_test")) { ret = do_msg_test_cmd(cb, msg, argc, argv); } else if (!strcmp(argv[1], "set_snap_frame")) { ret = do_set_snap_frame_cmd(cb, msg, argc, argv); } else if (!strcmp(argv[1], "get_tx_power_level")) { ret = do_get_tx_power_level_cmd(cb, msg, argc, argv); } else if (!strcmp(argv[1], "get_tx_power_range")) { ret = do_get_tx_power_range_cmd(cb, msg, argc, argv); } else if (!strcmp(argv[1], "set_advance_scan_elems")) { ret = do_set_advance_scan_elems_cmd(cb, msg, argc, argv); } else if (!strcmp(argv[1], "set_tx_queue_params")) { ret = do_set_tx_queue_params_cmd(cb, msg, argc, argv); } else if (!strcmp(argv[1], "start_stop_tsm")) { ret = do_start_stop_tsm_cmd(cb, msg, argc, argv); } else if (!strcmp(argv[1], "get_tsm_params")) { ret = do_get_tsm_params_cmd(cb, msg, argc, argv); } else if (!strcmp(argv[1], "get_roam_delay")) { ret = do_get_roam_delay_cmd(cb, msg, argc, argv); } else if(!strcmp(argv[1], "set_power_save")) { ret = do_set_power_save_cmd(cb, msg, argc, argv); } else if(!strcmp(argv[1], "keep_alive_cfg")) { ret = do_add_ip_offload_cmd(cb, msg, argc, argv); } else if(!strcmp(argv[1], "del_keep_alive")) { ret = do_del_ip_offload_cmd(cb, msg, argc, argv); } else if(!strcmp(argv[1], "keep_alive_peroid")) { ret = do_set_ip_offload_period_cmd(cb, msg, argc, argv); } else { /** * always keep the vendor rf cmd at the end. * including signaling and nosignaling */ ret = do_vendor_rf_cmd(cb, msg, argc, argv); } return ret; para_input_error: printf("The number of input param is not equal to argc.\n"); return -EINVAL; } int do_commands(struct nl_cb *cb, struct nl_msg *msg, const int argc, char **argv) { int ret = 0; if (argc <= 1) { return -EINVAL; } ret = do_besphy_test_cmd(cb, msg, argc, argv); return ret; }