Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 1022f327 authored by Romain Hunault's avatar Romain Hunault 🚴🏻
Browse files

Merge branch 'fix-wifi-hotspot' into 'v1-pie'

Fix wifi hotspot issue

Closes e/backlog#1477

See merge request !3
parents 5195b463 06e01418
Loading
Loading
Loading
Loading
+5 −0
Original line number Diff line number Diff line
@@ -195,6 +195,9 @@ enum qca_nl80211_vendor_subcmds {
    /* Get Concurrency Matrix */
    QCA_NL80211_VENDOR_SUBCMD_GET_CONCURRENCY_MATRIX = 42,
    QCA_NL80211_VENDOR_SUBCMD_APFIND = 52,

    QCA_NL80211_VENDOR_SUBCMD_DO_ACS = 54, //IKLOCSEN-3054, MOTO Gambugge

    /* Start Wifi Logger */
    QCA_NL80211_VENDOR_SUBCMD_WIFI_LOGGER_START = 62,

@@ -489,6 +492,8 @@ enum qca_nl80211_vendor_subcmds_index {
    QCA_NL80211_VENDOR_SUBCMD_NUD_STATS_GET_INDEX,
    QCA_NL80211_VENDOR_SUBCMD_HANG_REASON_INDEX,
    QCA_NL80211_VENDOR_SUBCMD_LINK_PROPERTIES_INDEX,

    QCA_NL80211_VENDOR_SUBCMD_DO_ACS_INDEX, //IKLOCSEN-3054, MOTO Gambugge
};

/**
+298 −0
Original line number Diff line number Diff line
@@ -6677,6 +6677,288 @@ static int wlan_hdd_cfg80211_firmware_roaming(struct wiphy *wiphy,
    return ret;
}
//IKLOCSEN-3054, MOTO Gambugge, 10/16/2017 – implement do_acs() in WLAN driver
/**
 * enum qca_wlan_vendor_attr_acs_offload
 *
 * @QCA_WLAN_VENDOR_ATTR_ACS_PRIMARY_CHANNEL: ACS selected primary channel
 * @QCA_WLAN_VENDOR_ATTR_ACS_SECONDARY_CHANNEL: ACS selected secondary channel
 * @QCA_WLAN_VENDOR_ATTR_ACS_HW_MODE: hw_mode for ACS
 * @QCA_WLAN_VENDOR_ATTR_ACS_HT_ENABLED: indicate if HT capability is enabled
 * @QCA_WLAN_VENDOR_ATTR_ACS_HT40_ENABLED: indicate HT capability
 */
enum qca_wlan_vendor_attr_acs_offload {
    QCA_WLAN_VENDOR_ATTR_ACS_CHANNEL_INVALID = 0,
    QCA_WLAN_VENDOR_ATTR_ACS_PRIMARY_CHANNEL,
    QCA_WLAN_VENDOR_ATTR_ACS_SECONDARY_CHANNEL,
    QCA_WLAN_VENDOR_ATTR_ACS_HW_MODE,
    QCA_WLAN_VENDOR_ATTR_ACS_HT_ENABLED,
    QCA_WLAN_VENDOR_ATTR_ACS_HT40_ENABLED,
    QCA_WLAN_VENDOR_ATTR_ACS_VHT_ENABLED,
    QCA_WLAN_VENDOR_ATTR_ACS_CHWIDTH,
    QCA_WLAN_VENDOR_ATTR_ACS_CH_LIST,
    QCA_WLAN_VENDOR_ATTR_ACS_VHT_SEG0_CENTER_CHANNEL,
    QCA_WLAN_VENDOR_ATTR_ACS_VHT_SEG1_CENTER_CHANNEL,
    QCA_WLAN_VENDOR_ATTR_ACS_FREQ_LIST,
    /* keep last */
    QCA_WLAN_VENDOR_ATTR_ACS_AFTER_LAST,
    QCA_WLAN_VENDOR_ATTR_ACS_MAX =
    QCA_WLAN_VENDOR_ATTR_ACS_AFTER_LAST - 1
};
/**
 * enum qca_wlan_vendor_acs_hw_mode
 *
 * @QCA_ACS_MODE_IEEE80211B: 11b mode
 * @QCA_ACS_MODE_IEEE80211G: 11g mode
 * @QCA_ACS_MODE_IEEE80211A: 11a mode
 * @QCA_ACS_MODE_IEEE80211AD: 11ad mode
 */
 enum qca_wlan_vendor_acs_hw_mode {
    QCA_ACS_MODE_IEEE80211B,
    QCA_ACS_MODE_IEEE80211G,
    QCA_ACS_MODE_IEEE80211A,
    QCA_ACS_MODE_IEEE80211AD,
    QCA_ACS_MODE_IEEE80211ANY,
};
static const struct nla_policy
wlan_hdd_cfg80211_do_acs_policy[QCA_WLAN_VENDOR_ATTR_ACS_MAX+1] = {
    [QCA_WLAN_VENDOR_ATTR_ACS_HW_MODE] = { .type = NLA_U8 },
    [QCA_WLAN_VENDOR_ATTR_ACS_HT_ENABLED] = { .type = NLA_FLAG },
    [QCA_WLAN_VENDOR_ATTR_ACS_HT40_ENABLED] = { .type = NLA_FLAG },
    [QCA_WLAN_VENDOR_ATTR_ACS_VHT_ENABLED] = { .type = NLA_FLAG },
    [QCA_WLAN_VENDOR_ATTR_ACS_CHWIDTH] = { .type = NLA_U16 },
    [QCA_WLAN_VENDOR_ATTR_ACS_CH_LIST] = { .type = NLA_UNSPEC },
    [QCA_WLAN_VENDOR_ATTR_ACS_FREQ_LIST] = { .type = NLA_UNSPEC },
};
/**
 * wlan_hdd_cfg80211_acs_ch_select_evt: Callback function for ACS evt
 * @adapter: Pointer to SAP adapter struct
 * @pri_channel: SAP ACS procedure selected Primary channel
 * @sec_channel: SAP ACS procedure selected secondary channel
 *
 * This is a callback function from SAP module on ACS procedure is completed.
 * This function send the ACS selected channel information to hostapd
 *
 * Return: None
 */
void wlan_hdd_cfg80211_acs_ch_select_evt(hdd_adapter_t *adapter, tChannelListInfo channel_list)
{
    hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
    struct sk_buff *vendor_event;
    int ret_val;
    uint16_t ch_width;
    vendor_event = cfg80211_vendor_event_alloc(hdd_ctx->wiphy,
        &(adapter->wdev),
        4 * sizeof(u8) + 1 * sizeof(u16) + 4 + NLMSG_HDRLEN,
        QCA_NL80211_VENDOR_SUBCMD_DO_ACS_INDEX,
        GFP_KERNEL);
    if (!vendor_event) {
        hddLog(VOS_TRACE_LEVEL_ERROR, "cfg80211_vendor_event_alloc failed");
        return;
    }
    ret_val = nla_put_u8(vendor_event,
        QCA_WLAN_VENDOR_ATTR_ACS_PRIMARY_CHANNEL,
        channel_list.channels[0]);
    if (ret_val) {
        hddLog(VOS_TRACE_LEVEL_ERROR, "QCA_WLAN_VENDOR_ATTR_ACS_PRIMARY_CHANNEL put fail");
        kfree_skb(vendor_event);
        return;
    }
    ret_val = nla_put_u8(vendor_event,
        QCA_WLAN_VENDOR_ATTR_ACS_SECONDARY_CHANNEL,
        0); // IKSWO-21203, Moto, gambugge, Fix channel set failure in nl80211 driver
    if (ret_val) {
        hddLog(VOS_TRACE_LEVEL_ERROR, "QCA_WLAN_VENDOR_ATTR_ACS_SECONDARY_CHANNEL put fail");
        kfree_skb(vendor_event);
        return;
    }
    ch_width = 20;
    ret_val = nla_put_u16(vendor_event,
        QCA_WLAN_VENDOR_ATTR_ACS_CHWIDTH,
        ch_width);
    if (ret_val) {
        hddLog(VOS_TRACE_LEVEL_ERROR, "QCA_WLAN_VENDOR_ATTR_ACS_CHWIDTH put fail");
        kfree_skb(vendor_event);
        return;
    }
    if (channel_list.channels[channel_list.num_channels - 1] > 14)
        ret_val = nla_put_u8(vendor_event,
            QCA_WLAN_VENDOR_ATTR_ACS_HW_MODE,
            QCA_ACS_MODE_IEEE80211A);
    else
        ret_val = nla_put_u8(vendor_event,
        QCA_WLAN_VENDOR_ATTR_ACS_HW_MODE,
        QCA_ACS_MODE_IEEE80211G);
    if (ret_val) {
        hddLog(VOS_TRACE_LEVEL_ERROR, "QCA_WLAN_VENDOR_ATTR_ACS_HW_MODE put fail");
        kfree_skb(vendor_event);
        return;
    }
    hddLog(VOS_TRACE_LEVEL_INFO, "ACS result for wlan0: PRI_CH: %d SEC_CH: %d",
        channel_list.channels[0],
        channel_list.channels[channel_list.num_channels - 1]);
    cfg80211_vendor_event(vendor_event, GFP_KERNEL);
    return;
}
/**
 * __wlan_hdd_cfg80211_do_acs(): CFG80211 handler function for DO_ACS Vendor CMD
 * @wiphy:  Linux wiphy struct pointer
 * @wdev:   Linux wireless device struct pointer
 * @data:   ACS information from hostapd
 * @data_len: ACS information length
 *
 * This function handle DO_ACS Vendor command from hostapd, parses ACS config
 * and starts ACS procedure.
 *
 * Return: ACS procedure start status
 */
static int __wlan_hdd_cfg80211_do_acs(struct wiphy *wiphy,
  struct wireless_dev *wdev,
  const void *data, int data_len)
{
    VOS_STATUS status;
    struct net_device *dev = wdev->netdev;
    hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
    tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(pAdapter);
    tChannelListInfo channel_list;
    int currentBand = 0;
    struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_ACS_MAX + 1];
    uint8_t hw_mode;
    int i;
    if (NULL == wdev) {
        hddLog(VOS_TRACE_LEVEL_ERROR, "%s: wdev is Null", __func__);
        return -ENODEV;
    }
    if (NULL == wdev->netdev) {
        hddLog(VOS_TRACE_LEVEL_ERROR, "%s: dev is Null", __func__);
        return -ENODEV;
    }
    status = nla_parse(tb, QCA_WLAN_VENDOR_ATTR_ACS_MAX, data, data_len,
                       wlan_hdd_cfg80211_do_acs_policy);
    if (status) {
        hddLog(VOS_TRACE_LEVEL_ERROR, "DO_ACS NL CMD parsing failed");
        return -EINVAL;
    }
    if (!tb[QCA_WLAN_VENDOR_ATTR_ACS_HW_MODE]) {
        hddLog(VOS_TRACE_LEVEL_ERROR, "Attr hw_mode failed");
        return -EINVAL;
    }
    hw_mode = nla_get_u8(tb[QCA_WLAN_VENDOR_ATTR_ACS_HW_MODE]);
    /* hw_mode = a/b/g: QCA_WLAN_VENDOR_ATTR_ACS_CH_LIST and
    * QCA_WLAN_VENDOR_ATTR_ACS_FREQ_LIST attrs are present, and
    * QCA_WLAN_VENDOR_ATTR_ACS_CH_LIST is used for obtaining the
    * channel list, QCA_WLAN_VENDOR_ATTR_ACS_FREQ_LIST is ignored
    * since it contains the frequency values of the channels in
    * the channel list.
    * hw_mode = any: only QCA_WLAN_VENDOR_ATTR_ACS_FREQ_LIST attr
    * is present
    */
    if (tb[QCA_WLAN_VENDOR_ATTR_ACS_CH_LIST]) {
        char *tmp = nla_data(tb[QCA_WLAN_VENDOR_ATTR_ACS_CH_LIST]);
        channel_list.num_channels = nla_len(
            tb[QCA_WLAN_VENDOR_ATTR_ACS_CH_LIST]);
        if (channel_list.num_channels) {
            memcpy(channel_list.channels, tmp,
                channel_list.num_channels);
        }
    } else if (tb[QCA_WLAN_VENDOR_ATTR_ACS_FREQ_LIST]) {
        uint32_t *freq =
        nla_data(tb[QCA_WLAN_VENDOR_ATTR_ACS_FREQ_LIST]);
        channel_list.num_channels = nla_len(
        tb[QCA_WLAN_VENDOR_ATTR_ACS_FREQ_LIST]) /
        sizeof(uint32_t);
        if (channel_list.num_channels) {
        /* convert frequency to channel */
        for (i = 0; i < channel_list.num_channels; i++)
            channel_list.channels[i] =
                ieee80211_frequency_to_channel(freq[i]);
        }
    }
    if (channel_list.num_channels >=1) {
        if (hw_mode == QCA_ACS_MODE_IEEE80211A) {
            currentBand =
                (channel_list.channels[channel_list.num_channels - 1] >= 149) ? 3 :
                (channel_list.channels[channel_list.num_channels - 1] >= 100) ? 2 :
                (channel_list.channels[channel_list.num_channels - 1] >=  36) ? 1 : 0;
        } else { // Auto 2.4 Ghz
            currentBand = 0;
        }
    }
    hddLog(VOS_TRACE_LEVEL_INFO,
            "ACS Config for wlan0: HW_MODE: %d NUM CHANNELS: %d START_CH: %d"
            "END_CH: %d currentBand: %d",
            hw_mode,
            channel_list.num_channels,
            channel_list.channels[0],
            channel_list.channels[channel_list.num_channels - 1],
            currentBand);
    status = WLANSAP_SetChannelRange(hHal,
            channel_list.channels[0],
            channel_list.channels[channel_list.num_channels - 1],
            currentBand);
    if (!VOS_IS_STATUS_SUCCESS(status)) {
        hddLog(VOS_TRACE_LEVEL_ERROR, "%s SetChannelRange Failed!!!",__func__);
        return -EINVAL;
    }
    (WLAN_HDD_GET_CTX(pAdapter))->is_dynamic_channel_range_set = 1;
    (WLAN_HDD_GET_CTX(pAdapter))->cfg_ini->apAutoChannelSelection = 1;
    wlan_hdd_cfg80211_acs_ch_select_evt(pAdapter, channel_list);
    return status;
}
/**
* wlan_hdd_cfg80211_do_acs : CFG80211 handler function for DO_ACS Vendor CMD
* @wiphy:  Linux wiphy struct pointer
* @wdev:   Linux wireless device struct pointer
* @data:   ACS information from hostapd
* @data_len: ACS information len
*
* This function handle DO_ACS Vendor command from hostapd, parses ACS config
* and starts ACS procedure.
*
* Return: ACS procedure start status
*/
static int wlan_hdd_cfg80211_do_acs(struct wiphy *wiphy,
  struct wireless_dev *wdev,
  const void *data, int data_len)
{
    int ret;
    vos_ssr_protect(__func__);
    ret = __wlan_hdd_cfg80211_do_acs(wiphy, wdev, data, data_len);
    vos_ssr_unprotect(__func__);
    return ret;
}
//END IKLOCSEN-3054
static const struct
nla_policy
qca_wlan_vendor_get_wifi_info_policy[
@@ -8862,6 +9144,16 @@ const struct wiphy_vendor_command hdd_wiphy_vendor_commands[] =
                 WIPHY_VENDOR_CMD_NEED_NETDEV,
        .doit = wlan_hdd_cfg80211_get_logger_supp_feature
   },
    //IKLOCSEN-3054, MOTO Gambugge, 10/16/2017 – implement do_acs() in WLAN driver
    {
        .info.vendor_id = QCA_NL80211_VENDOR_ID,
        .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_DO_ACS,
        .flags = WIPHY_VENDOR_CMD_NEED_WDEV |
            WIPHY_VENDOR_CMD_NEED_NETDEV |
            WIPHY_VENDOR_CMD_NEED_RUNNING,
        .doit = wlan_hdd_cfg80211_do_acs
    },
    //END IKLOCSEN-3054
};
/* vendor specific events */
@@ -8988,6 +9280,12 @@ struct nl80211_vendor_cmd_info wlan_hdd_cfg80211_vendor_events[] =
         .vendor_id = QCA_NL80211_VENDOR_ID,
         .subcmd = QCA_NL80211_VENDOR_SUBCMD_LINK_PROPERTIES,
    },
    //IKLOCSEN-3054, MOTO Gambugge, 10/16/2017 – implement do_acs() in WLAN driver
    [QCA_NL80211_VENDOR_SUBCMD_DO_ACS_INDEX] = {
        .vendor_id = QCA_NL80211_VENDOR_ID,
        .subcmd = QCA_NL80211_VENDOR_SUBCMD_DO_ACS
    },
    //END IKLOCSEN-3054
};
/*
+23 −3
Original line number Diff line number Diff line
@@ -2419,9 +2419,11 @@ static __iw_softap_setparam(struct net_device *dev,
    hdd_adapter_t *pHostapdAdapter = (netdev_priv(dev));
    tHalHandle hHal;
    hdd_context_t *pHddCtx = NULL;
    int *value = (int *)extra;
    int sub_cmd = value[0];
    int set_value = value[1];
    //BEGIN MOT IKSWO-9634, gambugge, Use copy_from_user to get user space data
    uint8_t *mot_value;
    int sub_cmd;
    int set_value;
    //END IKSWO-9634
    eHalStatus status;
    int ret = 0; /* success */
    int enable_pattrn_byte_match, enable_magic_pkt;
@@ -2429,6 +2431,24 @@ static __iw_softap_setparam(struct net_device *dev,

    ENTER();

    //BEGIN MOT IKSWO-9634, gambugge, Use copy_from_user to get user space data
    mot_value = (uint8_t*)kmalloc(wrqu->data.length+1, GFP_KERNEL);

    if (NULL == mot_value)
        return -ENOMEM;

    if(copy_from_user((uint8_t *)mot_value, (uint8_t *)(wrqu->data.pointer), wrqu->data.length)) {
        VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
                    "%s -- copy from user -- data pointer failed! bailing", __func__);
        kfree(mot_value);
        return -EFAULT;
    }

    sub_cmd = (int )(*(mot_value + 0));
    set_value = (int)(*(mot_value + 1));
    kfree(mot_value);
    //END IKSWO-9634

    if (NULL == pHostapdAdapter)
    {
        VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
+30 −0
Original line number Diff line number Diff line
@@ -153,6 +153,18 @@ static char *country_code;
static int   enable_11d = -1;
static int   enable_dfs_chan_scan = -1;
#define BUF_LEN_SAR 10
static char  sar_sta_buffer[BUF_LEN_SAR];
static struct kparam_string sar_sta = {
   .string = sar_sta_buffer,
   .maxlen = BUF_LEN_SAR,
};
static char  sar_mhs_buffer[BUF_LEN_SAR];
static struct kparam_string sar_mhs = {
   .string = sar_mhs_buffer,
   .maxlen = BUF_LEN_SAR,
};
#ifndef MODULE
static int wlan_hdd_inited;
#endif
@@ -18572,6 +18584,12 @@ bool hdd_is_cli_iface_up(hdd_context_t *hdd_ctx)
	return false;
}
static int sar_changed_handler(const char *kmessage,
                                  const struct kernel_param *kp)
{
   return param_set_copystring(kmessage, kp);
}
//Register the module init/exit functions
module_init(hdd_module_init);
module_exit(hdd_module_exit);
@@ -18590,6 +18608,11 @@ static const struct kernel_param_ops fwpath_ops = {
	.get = param_get_string,
};
static const struct kernel_param_ops sar_ops = {
	.set = sar_changed_handler,
	.get = param_get_string,
};
#ifdef MODULE
module_param(con_mode, int, 0);
#else
@@ -18608,3 +18631,10 @@ module_param(enable_11d, int,
module_param(country_code, charp,
             S_IRUSR | S_IRGRP | S_IROTH);
module_param_cb(sar_sta, &sar_ops, &sar_sta,
                    S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
module_param_cb(sar_mhs, &sar_ops, &sar_mhs,
                    S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
+4 −2
Original line number Diff line number Diff line
@@ -1454,7 +1454,9 @@ int __wlan_hdd_mgmt_tx( struct wiphy *wiphy, struct net_device *dev,

    //If GO adapter exists and operating on same frequency
    //then we will not request remain on channel
    if (ieee80211_frequency_to_channel(chan->center_freq) == home_ch)
    if (chan &&
        (ieee80211_frequency_to_channel(chan->center_freq) ==
        home_ch))
    {
        /*  if GO exist and is not off channel
         *  wait time should be zero.
@@ -1465,7 +1467,7 @@ int __wlan_hdd_mgmt_tx( struct wiphy *wiphy, struct net_device *dev,
#endif

#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,38))
    if( offchan && wait)
    if( offchan && wait && chan)
    {
        int status;
        rem_on_channel_request_type_t req_type = OFF_CHANNEL_ACTION_TX;
Loading