int ath6kl_tm_cmd(struct wiphy *wiphy, void *data, int len) { struct ath6kl *ar = wiphy_priv(wiphy); struct nlattr *tb[ATH6KL_TM_ATTR_MAX + 1]; int err, buf_len; void *buf; err = nla_parse(tb, ATH6KL_TM_ATTR_MAX, data, len, ath6kl_tm_policy); if (err) return err; if (!tb[ATH6KL_TM_ATTR_CMD]) return -EINVAL; switch (nla_get_u32(tb[ATH6KL_TM_ATTR_CMD])) { case ATH6KL_TM_CMD_TCMD: if (!tb[ATH6KL_TM_ATTR_DATA]) return -EINVAL; buf = nla_data(tb[ATH6KL_TM_ATTR_DATA]); buf_len = nla_len(tb[ATH6KL_TM_ATTR_DATA]); ath6kl_wmi_test_cmd(ar->wmi, buf, buf_len); return 0; break; #ifdef ATH6KL_SUPPORT_WLAN_HB case ATH6KL_TM_CMD_WLAN_HB: { struct wlan_hb_params *hb_params; struct ath6kl_vif *vif; vif = ath6kl_vif_first(ar); if (!vif) return -EINVAL; if (!tb[ATH6KL_TM_ATTR_DATA]) { printk(KERN_ERR "%s: NO DATA\n", __func__); return -EINVAL; } buf = nla_data(tb[ATH6KL_TM_ATTR_DATA]); buf_len = nla_len(tb[ATH6KL_TM_ATTR_DATA]); hb_params = (struct wlan_hb_params *)buf; if (hb_params->cmd == NL80211_WLAN_HB_ENABLE) { if (hb_params->enable != 0) { if (ath6kl_enable_wow_hb(ar)) { printk(KERN_ERR "%s: enable hb wow fail\n", __func__); return -EINVAL; } if (hb_params->enable & WLAN_HB_TCP_ENABLE) { ar->wlan_hb_enable |= WLAN_HB_TCP_ENABLE; if (ath6kl_wmi_set_heart_beat_params( ar->wmi, vif->fw_vif_idx, WLAN_HB_TCP_ENABLE)) { printk(KERN_ERR "%s: set heart beat enable fail\n", __func__); return -EINVAL; } } else if (hb_params->enable & WLAN_HB_UDP_ENABLE) { ar->wlan_hb_enable |= WLAN_HB_UDP_ENABLE; } } else { ar->wlan_hb_enable = 0; #ifdef CONFIG_ANDROID if (ath6kl_android_enable_wow_default(ar)) { printk(KERN_ERR "%s: enable android defualt wow fail\n", __func__); } #endif if (ath6kl_wmi_set_heart_beat_params(ar->wmi, vif->fw_vif_idx, 0)) { printk(KERN_ERR "%s: set heart beat enable fail\n", __func__); return -EINVAL; } } } else if (hb_params->cmd == NL80211_WLAN_TCP_PARAMS) { if (ath6kl_wmi_heart_beat_set_tcp_params(ar->wmi, vif->fw_vif_idx, hb_params->params.tcp_params.src_port, hb_params->params.tcp_params.dst_port, hb_params->params.tcp_params.timeout)) { printk(KERN_ERR "%s: set heart beat tcp params fail\n", __func__); return -EINVAL; } } else if (hb_params->cmd == NL80211_WLAN_TCP_FILTER) { if (hb_params->params.tcp_filter.length > WMI_MAX_TCP_FILTER_SIZE) { printk(KERN_ERR "%s: size of tcp filter is too large: %d\n", __func__, hb_params->params.tcp_filter.length); return -E2BIG; } if (ath6kl_wmi_heart_beat_set_tcp_filter(ar->wmi, vif->fw_vif_idx, hb_params->params.tcp_filter.filter, hb_params->params.tcp_filter.length)) { printk(KERN_ERR "%s: set heart beat tcp filter fail\n", __func__); return -EINVAL; } } else if (hb_params->cmd == NL80211_WLAN_UDP_PARAMS) { if (ath6kl_wmi_heart_beat_set_udp_params(ar->wmi, vif->fw_vif_idx, hb_params->params.udp_params.src_port, hb_params->params.udp_params.dst_port, hb_params->params.udp_params.interval, hb_params->params.udp_params.timeout)) { printk(KERN_ERR "%s: set heart beat udp params fail\n", __func__); return -EINVAL; } } else if (hb_params->cmd == NL80211_WLAN_UDP_FILTER) { if (hb_params->params.udp_filter.length > WMI_MAX_UDP_FILTER_SIZE) { printk(KERN_ERR "%s: size of udp filter is too large: %d\n", __func__, hb_params->params.udp_filter.length); return -E2BIG; } if (ath6kl_wmi_heart_beat_set_udp_filter(ar->wmi, vif->fw_vif_idx, hb_params->params.udp_filter.filter, hb_params->params.udp_filter.length)) { printk(KERN_ERR "%s: set heart beat udp filter fail\n", __func__); return -EINVAL; } } else if (hb_params->cmd == NL80211_WLAN_NET_INFO) { if (ath6kl_wmi_heart_beat_set_network_info(ar->wmi, vif->fw_vif_idx, hb_params->params.net_info.device_ip, hb_params->params.net_info.server_ip, hb_params->params.net_info.gateway_ip, hb_params->params.net_info.gateway_mac)) { printk(KERN_ERR "%s: set heart beat network information fail\n", __func__); return -EINVAL; } } } return 0; break; #endif #ifdef ATH6KL_SUPPORT_WIFI_DISC case ATH6KL_TM_CMD_WIFI_DISC: { struct wifi_disc_params *disc_params; struct ath6kl_vif *vif; vif = ath6kl_vif_first(ar); if (!vif) return -EINVAL; if (!tb[ATH6KL_TM_ATTR_DATA]) { printk(KERN_ERR "%s: NO DATA\n", __func__); return -EINVAL; } buf = nla_data(tb[ATH6KL_TM_ATTR_DATA]); buf_len = nla_len(tb[ATH6KL_TM_ATTR_DATA]); disc_params = (struct wifi_disc_params *)buf; if (disc_params->cmd == NL80211_WIFI_DISC_IE) { u8 ie_hdr[6] = {0xDD, 0x00, 0x00, 0x03, 0x7f, 0x00}; u8 *ie = NULL; u16 ie_length = disc_params->params.ie_params.length; ie = kmalloc(ie_length+6, GFP_KERNEL); if (ie == NULL) return -ENOMEM; memcpy(ie, ie_hdr, 6); ie[1] = ie_length+4; memcpy(ie+6, disc_params->params.ie_params.ie, ie_length); if (ath6kl_wmi_set_appie_cmd(ar->wmi, vif->fw_vif_idx, WMI_FRAME_PROBE_REQ, ie, ie_length+6)) { kfree(ie); printk(KERN_ERR "%s: wifi discovery set probe request ie fail\n", __func__); return -EINVAL; } if (ath6kl_wmi_set_appie_cmd(ar->wmi, vif->fw_vif_idx, WMI_FRAME_PROBE_RESP, ie, ie_length+6)) { kfree(ie); printk(KERN_ERR "%s: wifi discovery set probe response ie fail\n", __func__); return -EINVAL; } kfree(ie); } else if (disc_params->cmd == NL80211_WIFI_DISC_IE_FILTER) { if (ath6kl_wmi_disc_ie_cmd(ar->wmi, vif->fw_vif_idx, disc_params->params.ie_filter_params.enable, disc_params->params.ie_filter_params.startPos, disc_params->params.ie_filter_params.filter, disc_params->params.ie_filter_params.length)) { printk(KERN_ERR "%s: wifi discovery set ie filter fail\n", __func__); return -EINVAL; } } else if (disc_params->cmd == NL80211_WIFI_DISC_START) { int band, freq, numPeers, random; if (disc_params->params.start_params.channel <= 14) band = IEEE80211_BAND_2GHZ; else band = IEEE80211_BAND_5GHZ; freq = ieee80211_channel_to_frequency( disc_params->params.start_params.channel, band); if (!freq) { printk(KERN_ERR "%s: wifi discovery start channel %d error\n", __func__, disc_params->params.start_params.channel); return -EINVAL; } if (disc_params->params.start_params.numPeers == 0) numPeers = 1; else if (disc_params->params.start_params.numPeers > 4) numPeers = 4; else numPeers = disc_params->params.start_params.numPeers; random = (disc_params->params.start_params.random == 0) ? 100 : disc_params->params.start_params.random; if (disc_params->params.start_params.txPower) ath6kl_wmi_set_tx_pwr_cmd(ar->wmi, vif->fw_vif_idx, disc_params->params.start_params.txPower); /* disable scanning */ ath6kl_wmi_scanparams_cmd(ar->wmi, vif->fw_vif_idx, 0xFFFF, 0, 0, 0, 0, 0, 0, 0, 0, 0); if (ath6kl_wmi_disc_mode_cmd(ar->wmi, vif->fw_vif_idx, 1, freq, disc_params->params.start_params.dwellTime, disc_params->params.start_params.sleepTime, random, numPeers, disc_params->params.start_params.peerTimeout )) { printk(KERN_ERR "%s: wifi discovery start fail\n", __func__); return -EINVAL; } /* change disc state to active */ ar->disc_active = true; } else if (disc_params->cmd == NL80211_WIFI_DISC_STOP) { /* change disc state to inactive */ ar->disc_active = false; if (ath6kl_wmi_disc_mode_cmd(ar->wmi, vif->fw_vif_idx, 0, 0, 0, 0, 0, 0, 0)) { printk(KERN_ERR "%s: wifi discovery stop fail\n", __func__); return -EINVAL; } } } return 0; break; #endif #ifdef ATH6KL_SUPPORT_WIFI_KTK case ATH6KL_TM_CMD_WIFI_KTK: { struct wifi_ktk_params *ktk_params; struct ath6kl_vif *vif; vif = ath6kl_vif_first(ar); if (!vif) return -EINVAL; if (!tb[ATH6KL_TM_ATTR_DATA]) { printk(KERN_ERR "%s: NO DATA\n", __func__); return -EINVAL; } buf = nla_data(tb[ATH6KL_TM_ATTR_DATA]); buf_len = nla_len(tb[ATH6KL_TM_ATTR_DATA]); ktk_params = (struct wifi_ktk_params *)buf; if (ktk_params->cmd == NL80211_WIFI_KTK_IE) { u8 ie_hdr[6] = {0xDD, 0x00, 0x00, 0x03, 0x7f, 0x00}; u8 *ie = NULL; u16 ie_length = ktk_params->params.ie_params.length; ie = kmalloc(ie_length+6, GFP_KERNEL); if (ie == NULL) return -ENOMEM; memcpy(ie, ie_hdr, 6); ie[1] = ie_length+4; memcpy(ie+6, ktk_params->params.ie_params.ie, ie_length); if (ath6kl_wmi_set_appie_cmd(ar->wmi, vif->fw_vif_idx, WMI_FRAME_PROBE_RESP, ie, ie_length+6)) { kfree(ie); printk(KERN_ERR "%s: wifi ktk set probe response ie fail\n", __func__); return -EINVAL; } if (ath6kl_wmi_set_appie_cmd(ar->wmi, vif->fw_vif_idx, WMI_FRAME_BEACON, ie, ie_length+6)) { kfree(ie); printk(KERN_ERR "%s: wifi ktk set beacon ie fail\n", __func__); return -EINVAL; } kfree(ie); } else if (ktk_params->cmd == NL80211_WIFI_KTK_IE_FILTER) { if (ath6kl_wmi_disc_ie_cmd(ar->wmi, vif->fw_vif_idx, ktk_params->params.ie_filter_params.enable, ktk_params->params.ie_filter_params.startPos, ktk_params->params.ie_filter_params.filter, ktk_params->params.ie_filter_params.length)) { printk(KERN_ERR "%s: wifi ktk set ie filter fail\n", __func__); return -EINVAL; } } else if (ktk_params->cmd == NL80211_WIFI_KTK_START) { ar->ktk_active = true; /* Clear the legacy ie pattern and filter */ if (ath6kl_wmi_disc_ie_cmd(ar->wmi, vif->fw_vif_idx, 0, 0, NULL, 0)) { printk(KERN_ERR "%s: wifi ktk clear ie filter fail\n", __func__); return -EINVAL; } memcpy(ar->ktk_passphrase, ktk_params->params.start_params.passphrase, 16); if (ath6kl_wmi_probedssid_cmd(ar->wmi, vif->fw_vif_idx, 1, SPECIFIC_SSID_FLAG, ktk_params->params.start_params.ssid_len, ktk_params->params.start_params.ssid)) { printk(KERN_ERR "%s: wifi ktk set probedssid fail\n", __func__); return -EINVAL; } if (ath6kl_wmi_ibss_pm_caps_cmd(ar->wmi, vif->fw_vif_idx, ADHOC_PS_KTK, 5, 10, 10)) { printk(KERN_ERR "%s: wifi ktk set power save mode on fail\n", __func__); return -EINVAL; } } else if (ktk_params->cmd == NL80211_WIFI_KTK_STOP) { ar->ktk_active = false; if (ath6kl_wmi_ibss_pm_caps_cmd(ar->wmi, vif->fw_vif_idx, ADHOC_PS_DISABLE, 0, 0, 0)) { printk(KERN_ERR "%s: wifi ktk set power save mode off fail\n", __func__); return -EINVAL; } } } return 0; break; #endif default: return -EOPNOTSUPP; } }
int ath6kl_wmi_set_customer_testmode_cmd(struct ath6kl_vif *vif, athcfg_wcmd_testmode_t *val) { struct sk_buff *skb; struct WMI_CUSTOMER_TESTMODE_STRUCT *cmd; int ret = 0; bool send_wmi_flag = false; switch(val->operation) { case ATHCFG_WCMD_TESTMODE_BSSID: { if(memcmp(testmode_private.bssid,val->bssid,sizeof(testmode_private.bssid)) != 0) { memcpy(testmode_private.bssid,val->bssid,sizeof(testmode_private.bssid)); send_wmi_flag = true; } //printk("%s[%d] testmode_private.bssid=\"%pM\"\n",__func__,__LINE__,testmode_private.bssid); } break; case ATHCFG_WCMD_TESTMODE_CHAN: { if(testmode_private.chan != val->chan) { testmode_private.chan = val->chan; send_wmi_flag = true; } //printk("%s[%d] testmode_private.chan=%d\n",__func__,__LINE__,testmode_private.chan); } break; case ATHCFG_WCMD_TESTMODE_RX: { if(testmode_private.rx != val->rx) { testmode_private.rx = val->rx; send_wmi_flag = true; } } break; case ATHCFG_WCMD_TESTMODE_ANT: default: printk("%s[%d]Not support\n",__func__,__LINE__); return -1; } //send WMI to target if(send_wmi_flag) { testmode_private.rx = val->rx; skb = ath6kl_wmi_get_new_buf(sizeof(*cmd)); if (!skb) return -ENOMEM; cmd = (struct WMI_CUSTOMER_TESTMODE_STRUCT *) skb->data; //transfer to little endian memcpy(cmd->bssid, val->bssid, sizeof(cmd->bssid)); cmd->chan = cpu_to_le32(val->chan); cmd->operation = cpu_to_le16(val->operation); cmd->antenna = val->antenna; cmd->rx = val->rx; cmd->rssi_combined = cpu_to_le32(val->rssi_combined); cmd->rssi0 = cpu_to_le32(val->rssi0); cmd->rssi1 = cpu_to_le32(val->rssi1); cmd->rssi2 = cpu_to_le32(val->rssi2); ret = ath6kl_wmi_cmd_send(vif, skb, WMI_SET_CUSTOM_TESTMODE, NO_SYNC_WMIFLAG); } if(val->operation == ATHCFG_WCMD_TESTMODE_RX) { if(val->rx == 1) { s8 n_channels = 1; u16 *channels = NULL; int i; set_bit(SONY_WMI_TESTMODE_RX, &vif->flag); //set scan param ath6kl_wmi_scanparams_cmd( vif, 0, 0xffff, 0, vif->sc_params.minact_chdwell_time, vif->sc_params.maxact_chdwell_time,//0xffff, 1000,//vif->sc_params.pas_chdwell_time, msec vif->sc_params.short_scan_ratio, (vif->sc_params.scan_ctrl_flags & ~ACTIVE_SCAN_CTRL_FLAGS), //vif->sc_params.scan_ctrl_flags, vif->sc_params.max_dfsch_act_time, vif->sc_params.maxact_scan_per_ssid); //assign request channel channels = kzalloc(n_channels * sizeof(u16), GFP_KERNEL); if (channels == NULL) { n_channels = 0; } for (i = 0; i < n_channels; i++) { channels[i] = ieee80211_channel_to_frequency_ath6kl((testmode_private.chan == 0 ? 1:testmode_private.chan),IEEE80211_NUM_BANDS); //printk("%s[%d]channels[%d]=%d,testmode_private.chan=%d\n",__func__,__LINE__,i,channels[i],testmode_private.chan); } ret = ath6kl_wmi_bssfilter_cmd( vif, ALL_BSS_FILTER, 0); if (ret) { printk("%s[%d] Fail\n",__func__,__LINE__); goto rx_fail; } ret = ath6kl_wmi_startscan_cmd(vif, WMI_LONG_SCAN, 1, false, 0, 0, n_channels, channels); if (ret) { printk("%s[%d] Fail\n",__func__,__LINE__); goto rx_fail; } rx_fail: kfree(channels); } else { //cancel test mode scan clear_bit(SONY_WMI_TESTMODE_RX, &vif->flag); ath6kl_wmi_scanparams_cmd(vif, vif->sc_params.fg_start_period, vif->sc_params.fg_end_period, vif->sc_params.bg_period, vif->sc_params.minact_chdwell_time, vif->sc_params.maxact_chdwell_time, vif->sc_params.pas_chdwell_time, vif->sc_params.short_scan_ratio, vif->sc_params.scan_ctrl_flags, vif->sc_params.max_dfsch_act_time, vif->sc_params.maxact_scan_per_ssid); } } return ret; }