| /* |
| * DHD CONFIG INI |
| * |
| * Copyright (C) 2021, Broadcom. |
| * |
| * Unless you and Broadcom execute a separate written software license |
| * agreement governing use of this software, this software is licensed to you |
| * under the terms of the GNU General Public License version 2 (the "GPL"), |
| * available at http://www.broadcom.com/licenses/GPLv2.php, with the |
| * following added to such license: |
| * |
| * As a special exception, the copyright holders of this software give you |
| * permission to link this software with independent modules, and to copy and |
| * distribute the resulting executable under terms of your choice, provided that |
| * you also meet, for each linked independent module, the terms and conditions of |
| * the license of that module. An independent module is a module which is not |
| * derived from this software. The special exception does not apply to any |
| * modifications of the software. |
| * |
| * |
| * <<Broadcom-WL-IPTag/Open:>> |
| * |
| * $Id$ |
| */ |
| |
| #include <linux/fs.h> |
| #include <linux/ctype.h> |
| #include <typedefs.h> |
| #include <dhd_config.h> |
| #include <dhd_dbg.h> |
| #include <dhd_linux_priv.h> |
| #if defined(WL_CFG80211) |
| #include <wl_cfg80211.h> |
| #endif /* WL_CFG80211 */ |
| #include <wldev_common.h> |
| #include <wl_cfgvif.h> |
| |
| #define strtoul(nptr, endptr, base) bcm_strtoul((nptr), (endptr), (base)) |
| #define LEGACY_RATE_COUNT 8 |
| #define MAX_MASK_PATTERN_FILTER_LEN 64 |
| |
| extern int pattern_atoh_len(char *src, char *dst, int len); |
| |
| int |
| dhd_preinit_proc(dhd_pub_t *dhd, int ifidx, char *name, char *value) |
| { |
| wl_country_t cspec = {{0}, -1, {0}}; |
| uint32 var_int; |
| char * revstr; |
| char * endptr = NULL; |
| int ret = 0; |
| |
| //// set MAC address |
| if (!strcasecmp(name, "cur_etheraddr")) { |
| struct ether_addr ea; |
| |
| bcm_ether_atoe(value, &ea); |
| |
| ret = memcmp(&ea.octet, dhd->mac.octet, ETHER_ADDR_LEN); |
| if (ret == 0) { |
| DHD_ERROR(("%s: Same Macaddr\n", __FUNCTION__)); |
| return 0; |
| } |
| |
| DHD_ERROR(("%s: Change Macaddr = %02X:%02X:%02X:%02X:%02X:%02X\n", __FUNCTION__, |
| ea.octet[0], ea.octet[1], ea.octet[2], |
| ea.octet[3], ea.octet[4], ea.octet[5])); |
| |
| ret = dhd_iovar(dhd, 0, "cur_etheraddr", (char*)&ea, ETHER_ADDR_LEN, NULL, 0, TRUE); |
| if (ret < 0) { |
| DHD_ERROR(("%s: can't set MAC address , error=%d\n", __FUNCTION__, ret)); |
| return ret; |
| } else { |
| memcpy(dhd->mac.octet, (void *)&ea, ETHER_ADDR_LEN); |
| return ret; |
| } |
| } |
| //// country code |
| else if (!strcasecmp(name, "country")) { |
| revstr = strchr(value, '/'); |
| #if defined(DHD_BLOB_EXISTENCE_CHECK) |
| if (dhd->is_blob) { |
| cspec.rev = 0; |
| memcpy(cspec.country_abbrev, value, WLC_CNTRY_BUF_SZ); |
| memcpy(cspec.ccode, value, WLC_CNTRY_BUF_SZ); |
| } else |
| #endif /* DHD_BLOB_EXISTENCE_CHECK */ |
| { |
| if (revstr) { |
| cspec.rev = strtoul(revstr + 1, &endptr, 10); |
| memcpy(cspec.country_abbrev, value, WLC_CNTRY_BUF_SZ); |
| cspec.country_abbrev[2] = '\0'; |
| memcpy(cspec.ccode, cspec.country_abbrev, WLC_CNTRY_BUF_SZ); |
| } else { |
| cspec.rev = -1; |
| memcpy(cspec.country_abbrev, value, WLC_CNTRY_BUF_SZ); |
| memcpy(cspec.ccode, value, WLC_CNTRY_BUF_SZ); |
| #if defined(CUSTOM_COUNTRY_CODE) |
| get_customized_country_code(dhd->info->adapter, |
| (char *)&cspec.country_abbrev, &cspec, dhd->dhd_cflags); |
| #else |
| get_customized_country_code(dhd->info->adapter, |
| (char *)&cspec.country_abbrev, &cspec); |
| #endif |
| } |
| |
| } |
| DHD_ERROR(("config country code is country : %s, rev : %d !!\n", |
| cspec.country_abbrev, cspec.rev)); |
| ret = dhd_iovar(dhd, 0, "country", (char*)&cspec, sizeof(cspec), NULL, 0, TRUE); |
| return ret; |
| } else if (!strcasecmp(name, "autocountry")) { |
| var_int = (uint)simple_strtol(value, NULL, 0); |
| ret = dhd_iovar(dhd, 0, "autocountry", (char *)&var_int, |
| sizeof(var_int), NULL, 0, TRUE); |
| return ret; |
| } |
| //// band |
| else if (!strcasecmp(name, "band")) { |
| if (!strcmp(value, "auto")) |
| var_int = WLC_BAND_AUTO; |
| else if (!strcmp(value, "a")) |
| var_int = WLC_BAND_5G; |
| else if (!strcmp(value, "b")) |
| var_int = WLC_BAND_2G; |
| else if (!strcmp(value, "all")) |
| var_int = WLC_BAND_ALL; |
| else { |
| DHD_ERROR(("band should be one of the a or b or all\n")); |
| var_int = WLC_BAND_AUTO; |
| } |
| if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_BAND, &var_int, |
| sizeof(var_int), TRUE, 0)) < 0) |
| DHD_ERROR(("set band err=%d\n", ret)); |
| return ret; |
| } else if (!strcasecmp(name, "autocountry")) { |
| var_int = (uint)simple_strtol(value, NULL, 0); |
| ret = dhd_iovar(dhd, 0, "autocountry", (char *)&var_int, |
| sizeof(var_int), NULL, 0, TRUE); |
| return ret; |
| } |
| //// scan parameters |
| else if (!strcasecmp(name, "scan_assoc_time")) { |
| var_int = (uint)simple_strtol(value, NULL, 0); |
| ret = dhd_iovar(dhd, 0, "scan_assoc_time", (char *)&var_int, |
| sizeof(var_int), NULL, 0, TRUE); |
| return ret; |
| } else if (!strcasecmp(name, "scan_unassoc_time")) { |
| var_int = (uint)simple_strtol(value, NULL, 0); |
| ret = dhd_iovar(dhd, 0, "scan_unassoc_time", (char *)&var_int, |
| sizeof(var_int), NULL, 0, TRUE); |
| return ret; |
| } else if (!strcasecmp(name, "scan_passive_time")) { |
| var_int = (uint)simple_strtol(value, NULL, 0); |
| ret = dhd_iovar(dhd, 0, "scan_passive_time", (char *)&var_int, |
| sizeof(var_int), NULL, 0, TRUE); |
| return ret; |
| } else if (!strcasecmp(name, "scan_home_time")) { |
| var_int = (uint)simple_strtol(value, NULL, 0); |
| ret = dhd_iovar(dhd, 0, "scan_home_time", (char *)&var_int, |
| sizeof(var_int), NULL, 0, TRUE); |
| return ret; |
| } else if (!strcasecmp(name, "scan_home_away_time")) { |
| var_int = (uint)simple_strtol(value, NULL, 0); |
| ret = dhd_iovar(dhd, 0, "scan_home_away_time", (char *)&var_int, |
| sizeof(var_int), NULL, 0, TRUE); |
| return ret; |
| } else if (!strcasecmp(name, "scan_nprobes")) { |
| var_int = (uint)simple_strtol(value, NULL, 0); |
| ret = dhd_iovar(dhd, 0, "scan_nprobes", (char *)&var_int, |
| sizeof(var_int), NULL, 0, TRUE); |
| return ret; |
| } |
| //// roam parameters |
| else if (!strcasecmp(name, "roam_period")) { |
| var_int = (uint)simple_strtol(value, NULL, 0); |
| ret = dhd_iovar(dhd, 0, "roamperiod", (char *)&var_int, |
| sizeof(var_int), NULL, 0, TRUE); |
| return ret; |
| } else if (!strcasecmp(name, "full_roam_period")) { |
| var_int = (uint)simple_strtol(value, NULL, 0); |
| ret = dhd_iovar(dhd, 0, "fullroamperiod", (char *)&var_int, |
| sizeof(var_int), NULL, 0, TRUE); |
| return ret; |
| } |
| // beacon monitor |
| else if (!strcasecmp(name, "bcn_timeout")) { |
| var_int = (uint)simple_strtol(value, NULL, 0); |
| ret = dhd_iovar(dhd, 0, "bcn_timeout", (char *)&var_int, |
| sizeof(var_int), NULL, 0, TRUE); |
| return ret; |
| } else if (!strcasecmp(name, "bcn_li_dtim")) { |
| var_int = (uint)simple_strtol(value, NULL, 0); |
| ret = dhd_iovar(dhd, 0, "bcn_li_dtim", (char *)&var_int, |
| sizeof(var_int), NULL, 0, TRUE); |
| return ret; |
| } else if (!strcasecmp(name, "bcn_li_bcn")) { |
| var_int = (uint)simple_strtol(value, NULL, 0); |
| ret = dhd_iovar(dhd, 0, "bcn_li_bcn", (char *)&var_int, |
| sizeof(var_int), NULL, 0, TRUE); |
| return ret; |
| } |
| // roam by low RSSI factor |
| else if (!strcasecmp(name, "roam_delta")) { |
| struct { |
| int val; |
| int band; |
| } x; |
| x.val = (int)simple_strtol(value, NULL, 0); |
| /* x.band = WLC_BAND_AUTO; */ |
| x.band = WLC_BAND_ALL; |
| ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_ROAM_DELTA, &x, sizeof(x), TRUE, 0); |
| return ret; |
| } else if (!strcasecmp(name, "roam_trigger")) { |
| int roam_trigger[2]; |
| |
| roam_trigger[0] = (int)simple_strtol(value, NULL, 0); |
| roam_trigger[1] = WLC_BAND_ALL; |
| ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_ROAM_TRIGGER, &roam_trigger, |
| sizeof(roam_trigger), TRUE, 0); |
| return ret; |
| } else if (!strcasecmp(name, "roam_trigger_2g")) { |
| int roam_trigger[2]; |
| |
| roam_trigger[0] = (int)simple_strtol(value, NULL, 0); |
| roam_trigger[1] = WLC_BAND_2G; |
| ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_ROAM_TRIGGER, &roam_trigger, |
| sizeof(roam_trigger), TRUE, 0); |
| return ret; |
| } else if (!strcasecmp(name, "roam_trigger_5g")) { |
| int roam_trigger[2]; |
| |
| roam_trigger[0] = (int)simple_strtol(value, NULL, 0); |
| roam_trigger[1] = WLC_BAND_5G; |
| ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_ROAM_TRIGGER, &roam_trigger, |
| sizeof(roam_trigger), TRUE, 0); |
| return ret; |
| } |
| // roam by signal drop step factor |
| else if (!strcasecmp(name, "roam_signal_drop_step")) { |
| var_int = (uint)simple_strtol(value, NULL, 0); |
| ret = dhd_iovar(dhd, 0, "roam_signal_drop_step", (char *)&var_int, |
| sizeof(var_int), NULL, 0, TRUE); |
| return ret; |
| } else if (!strcasecmp(name, "roam_signal_drop_block_time")) { |
| var_int = (uint)simple_strtol(value, NULL, 0); |
| ret = dhd_iovar(dhd, 0, "roam_signal_drop_block_time", (char *)&var_int, |
| sizeof(var_int), NULL, 0, TRUE); |
| return ret; |
| } |
| // roam by QBSS load (CU) factor |
| else if (!strcasecmp(name, "roam_qbss_load_threshold")) { |
| var_int = (uint)simple_strtol(value, NULL, 0); |
| ret = dhd_iovar(dhd, 0, "roam_qbss_load_threshold", (char *)&var_int, |
| sizeof(var_int), NULL, 0, TRUE); |
| return ret; |
| } else if (!strcasecmp(name, "roam_qbss_load_duration")) { |
| var_int = (uint)simple_strtol(value, NULL, 0); |
| ret = dhd_iovar(dhd, 0, "roam_qbss_load_duration", (char *)&var_int, |
| sizeof(var_int), NULL, 0, TRUE); |
| return ret; |
| } |
| // scan score compute algorithm |
| else if (!strcasecmp(name, "roam_score_rssi_bounder_a")) { |
| var_int = (uint)simple_strtol(value, NULL, 0); |
| ret = dhd_iovar(dhd, 0, "roam_score_rssi_bounder_a", (char *)&var_int, |
| sizeof(var_int), NULL, 0, TRUE); |
| return ret; |
| } else if (!strcasecmp(name, "roam_score_rssi_bounder_b")) { |
| var_int = (uint)simple_strtol(value, NULL, 0); |
| ret = dhd_iovar(dhd, 0, "roam_score_rssi_bounder_b", (char *)&var_int, |
| sizeof(var_int), NULL, 0, TRUE); |
| return ret; |
| } else if (!strcasecmp(name, "roam_score_coeff_a")) { |
| var_int = (uint)simple_strtol(value, NULL, 0); |
| ret = dhd_iovar(dhd, 0, "roam_score_coeff_a", (char *)&var_int, |
| sizeof(var_int), NULL, 0, TRUE); |
| return ret; |
| } else if (!strcasecmp(name, "roam_score_coeff_b")) { |
| var_int = (uint)simple_strtol(value, NULL, 0); |
| ret = dhd_iovar(dhd, 0, "roam_score_coeff_b", (char *)&var_int, |
| sizeof(var_int), NULL, 0, TRUE); |
| return ret; |
| } else if (!strcasecmp(name, "roam_score_coeff_c")) { |
| var_int = (uint)simple_strtol(value, NULL, 0); |
| ret = dhd_iovar(dhd, 0, "roam_score_coeff_c", (char *)&var_int, |
| sizeof(var_int), NULL, 0, TRUE); |
| return ret; |
| } |
| //// powersaving related |
| // power management |
| else if (!strcasecmp(name, "PM")) { |
| var_int = (int)simple_strtol(value, NULL, 0); |
| ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_PM, |
| &var_int, sizeof(var_int), TRUE, 0); |
| return ret; |
| } else if (!strcasecmp(name, "lpc")) { |
| var_int = (int)simple_strtol(value, NULL, 0); |
| if (dhd_wl_ioctl_cmd(dhd, WLC_DOWN, NULL, 0, TRUE, 0) < 0) { |
| DHD_ERROR(("%s: wl down failed\n", __FUNCTION__)); |
| } |
| ret = dhd_iovar(dhd, 0, "lpc", (char *)&var_int, sizeof(var_int), NULL, 0, TRUE); |
| if (ret < 0) { |
| DHD_ERROR(("%s Set lpc failed %d\n", __FUNCTION__, ret)); |
| } |
| if (dhd_wl_ioctl_cmd(dhd, WLC_UP, NULL, 0, TRUE, 0) < 0) { |
| DHD_ERROR(("%s: wl up failed\n", __FUNCTION__)); |
| } |
| return ret; |
| } |
| //// 802.11k |
| else if (!strcasecmp(name, "rrm")) { |
| struct rrm_cap_ie { |
| uint8 cap[DOT11_RRM_CAP_LEN]; |
| } rrm_cap; |
| int len; |
| uint high = 0, low = 0; |
| // modify to avoid overlfow warning |
| char hs[4+1] = {0}, ls[8+1] = {0}; |
| len = strlen(value); |
| DHD_INFO(("rrm value len %d\n", len)); |
| if (len <= 12) { |
| if ( (value[0] == '0') |
| && ( (value[1] == 'x') |
| || (value[1] == 'X') |
| ) |
| ) { |
| if (len == 11) { |
| strlcpy(hs, value, 4); |
| strlcpy(ls, value + 3, 9); |
| high = (int)simple_strtol(hs, NULL, 16); |
| low = (int)simple_strtol(ls, NULL, 16); |
| } else if (len == 12) { |
| strlcpy(hs, value, 5); |
| strlcpy(ls, value + 4, 9); |
| high = (int)simple_strtol(hs, NULL, 16); |
| low = (int)simple_strtol(ls, NULL, 16); |
| } else { |
| low = (int)simple_strtol(value, NULL, 16); |
| } |
| } else { |
| high = 0x0; |
| low = (int)simple_strtol(value, NULL, 10); |
| } |
| |
| rrm_cap.cap[0] = low & 0x000000ff; |
| rrm_cap.cap[1] = (low & 0x0000ff00) >> 8; |
| rrm_cap.cap[2] = (low & 0x00ff0000) >> 16; |
| rrm_cap.cap[3] = (low & 0xff000000) >> 24; |
| rrm_cap.cap[4] = high; |
| |
| if (dhd_wl_ioctl_cmd(dhd, WLC_DOWN, NULL, 0, TRUE, 0) < 0) { |
| DHD_ERROR(("%s: wl down failed\n", __FUNCTION__)); |
| } |
| ret = dhd_iovar(dhd, 0, "rrm", (char *)&rrm_cap, sizeof(rrm_cap), NULL, 0, |
| TRUE); |
| if (ret < 0) { |
| DHD_ERROR(("%s Set rrm failed %d\n", __FUNCTION__, ret)); |
| } |
| if (dhd_wl_ioctl_cmd(dhd, WLC_UP, NULL, 0, TRUE, 0) < 0) { |
| DHD_ERROR(("%s: wl up failed\n", __FUNCTION__)); |
| } |
| return ret; |
| } else { |
| DHD_ERROR(("only allow with prefix 0x or decimal incorrect\n")); |
| return BCME_USAGE_ERROR; |
| } |
| } |
| //// BW CAP |
| else if (!strcasecmp(name, "bw_cap_2g")) { |
| struct { |
| u32 band; |
| u32 bw_cap; |
| } param = {0, 0}; |
| |
| var_int = (int)simple_strtol(value, NULL, 0); |
| param.band = WLC_BAND_2G; |
| param.bw_cap = var_int; |
| |
| if (dhd_wl_ioctl_cmd(dhd, WLC_DOWN, NULL, 0, TRUE, 0) < 0) { |
| DHD_ERROR(("%s: wl down failed\n", __FUNCTION__)); |
| } |
| ret = dhd_iovar(dhd, 0, "bw_cap", (char *)¶m, sizeof(param), |
| NULL, 0, TRUE); |
| if (ret < 0) { |
| DHD_ERROR(("%s Set bw_cap failed %d\n", __FUNCTION__, ret)); |
| } |
| if (dhd_wl_ioctl_cmd(dhd, WLC_UP, NULL, 0, TRUE, 0) < 0) { |
| DHD_ERROR(("%s: wl up failed\n", __FUNCTION__)); |
| } |
| } else if (!strcasecmp(name, "bw_cap_5g")) { |
| struct { |
| u32 band; |
| u32 bw_cap; |
| } param = {0, 0}; |
| |
| var_int = (int)simple_strtol(value, NULL, 0); |
| param.band = WLC_BAND_5G; |
| param.bw_cap = var_int; |
| |
| if (dhd_wl_ioctl_cmd(dhd, WLC_DOWN, NULL, 0, TRUE, 0) < 0) { |
| DHD_ERROR(("%s: wl down failed\n", __FUNCTION__)); |
| } |
| ret = dhd_iovar(dhd, 0, "bw_cap", (char *)¶m, sizeof(param), |
| NULL, 0, TRUE); |
| if (ret < 0) { |
| DHD_ERROR(("%s Set bw_cap failed %d\n", __FUNCTION__, ret)); |
| } |
| if (dhd_wl_ioctl_cmd(dhd, WLC_UP, NULL, 0, TRUE, 0) < 0) { |
| DHD_ERROR(("%s: wl up failed\n", __FUNCTION__)); |
| } |
| } |
| //// 802.11 mode |
| // 11ax |
| else if (!strcasecmp(name, "he_enab")) { |
| var_int = (uint)simple_strtol(value, NULL, 0); |
| if (var_int == 0) { |
| dhd->conf->he_disable = 1; |
| } |
| return ret; |
| } |
| // 11ac |
| else if (!strcasecmp(name, "vhtmode")) { |
| var_int = (uint)simple_strtol(value, NULL, 0); |
| if (var_int == 0) { |
| dhd->conf->vhtmode_disable = 1; |
| } |
| return ret; |
| } |
| // 11n |
| else if (!strcasecmp(name, "nmode")) { |
| var_int = (uint)simple_strtol(value, NULL, 0); |
| if (var_int == 0) { |
| dhd->conf->nmode_disable = 1; |
| } |
| return ret; |
| } |
| // 11b/g |
| else if (!strcasecmp(name, "gmode")) { |
| dhd->conf->gmode = (int)simple_strtol(value, NULL, 0); |
| dhd->conf->gmode_set = 1; |
| return ret; |
| } |
| //// 802.11 ax |
| else if (!strcasecmp(name, "he_features")) { |
| struct net_device *ndev; |
| struct bcm_cfg80211 *cfg; |
| s32 bssidx = 0; |
| char *endptr = NULL; |
| if ((value[0] == '0') && ((value[1] == 'x') || (value[1] == 'X'))) { |
| var_int = (int)simple_strtol(value, &endptr, 16); |
| } else { |
| var_int = (int)simple_strtol(value, &endptr, 10); |
| } |
| if (*endptr != '\0') { |
| DHD_ERROR(("Wrong format %s\n", endptr)); |
| return BCME_USAGE_ERROR; |
| } else { |
| ndev = dhd_linux_get_primary_netdev(dhd); |
| if (!ndev) { |
| DHD_ERROR(("%s: Cannot find netdev\n", __FUNCTION__)); |
| return -ENODEV; |
| } |
| cfg = wl_get_cfg(ndev); |
| if (!cfg) { |
| DHD_ERROR(("%s: Cannot find cfg\n", __FUNCTION__)); |
| return -EINVAL; |
| } |
| if ((bssidx = wl_get_bssidx_by_wdev(cfg, ndev->ieee80211_ptr)) < 0) { |
| DHD_ERROR(("find index from wdev failed\n")); |
| ret = -EINVAL; |
| } |
| |
| ret = wl_cfg80211_set_he_features(ndev, cfg, bssidx, WL_IF_TYPE_STA, var_int); |
| if (ret) { |
| DHD_ERROR(("failed to set ax features %d\n", ret)); |
| |
| } |
| return ret; |
| } |
| } |
| //// 802.11 ac |
| else if (!strcasecmp(name, "vht_features")) { |
| var_int = (int)simple_strtol(value, NULL, 0); |
| |
| if (dhd_wl_ioctl_cmd(dhd, WLC_DOWN, NULL, 0, TRUE, 0) < 0) { |
| DHD_ERROR(("%s: wl down failed\n", __FUNCTION__)); |
| } |
| ret = dhd_iovar(dhd, 0, "vht_features", (char *)&var_int, sizeof(var_int), NULL, 0, |
| TRUE); |
| if (ret < 0) { |
| DHD_ERROR(("%s Set vht_features failed %d\n", __FUNCTION__, ret)); |
| } |
| if (dhd_wl_ioctl_cmd(dhd, WLC_UP, NULL, 0, TRUE, 0) < 0) { |
| DHD_ERROR(("%s: wl up failed\n", __FUNCTION__)); |
| } |
| return ret; |
| } else if (!strcasecmp(name, "fbt")) { |
| uint powervar = 0; |
| var_int = (int)simple_strtol(value, NULL, 0); |
| |
| powervar = 0; |
| ret = dhd_iovar(dhd, 0, "mpc", (char *)&powervar, sizeof(powervar), |
| NULL, 0, TRUE); |
| if (ret) { |
| DHD_ERROR(("%s: mpc failed:%d\n", __FUNCTION__, ret)); |
| } |
| ret = dhd_iovar(dhd, 0, "fbt", (char *)&var_int, sizeof(var_int), |
| NULL, 0, TRUE); |
| if (ret < 0) { |
| DHD_ERROR(("%s Set fbt failed %d\n", __FUNCTION__, ret)); |
| } |
| powervar = 1; |
| if (dhd_iovar(dhd, 0, "mpc", (char *)&powervar, sizeof(powervar), |
| NULL, 0, TRUE) < 0) { |
| DHD_ERROR(("%s: mpc failed:%d\n", __FUNCTION__, ret)); |
| } |
| return ret; |
| } |
| //// rate set |
| else if(!strcasecmp(name, "rateset_legacy")) { |
| int v = 0; |
| char *p; |
| typedef wl_rateset_args_v2_t _wl_rateset_args_t; |
| _wl_rateset_args_t defrs; |
| struct net_device *ndev; |
| int i, rscount = 0; |
| |
| bzero(&defrs, sizeof(_wl_rateset_args_t)); |
| ndev = dhd_linux_get_primary_netdev(dhd); |
| if (!ndev) { |
| DHD_ERROR(("%s: Cannot find netdev\n", __FUNCTION__)); |
| return -ENODEV; |
| } |
| ret = wldev_iovar_getbuf(ndev, "cur_rateset", NULL, 0, |
| &defrs, sizeof(_wl_rateset_args_t), NULL); |
| if (ret < 0) { |
| WL_ERR(("get rateset failed = %d\n", ret)); |
| return ret; |
| } |
| bzero(&defrs.rates, sizeof(defrs.rates)); |
| v = (int)(simple_strtol(value, &p, 0) * 2); |
| for (rscount = 0; rscount < LEGACY_RATE_COUNT; rscount++) { |
| if (!strnicmp(p, "b,", 2)) { |
| v |= 0x80; |
| defrs.rates[rscount] = v; |
| p += 2; |
| } else if (*p == ','){ |
| defrs.rates[rscount] = v; |
| p++; |
| } else if (!strnicmp(p, "b\0", 2)) { |
| v |= 0x80; |
| defrs.rates[rscount] = v; |
| break; |
| } else if (*p == '\0') { |
| defrs.rates[rscount] = v; |
| break; |
| } |
| v = (int)(simple_strtol(p, &p, 0) * 2); |
| } |
| /* check no basic rates */ |
| for (i = 0; i < rscount; i++) { |
| if (defrs.rates[i] & 0x80) { |
| break; |
| } |
| } |
| if (i < rscount) { |
| if (dhd_wl_ioctl_cmd(dhd, WLC_DOWN, NULL, 0, TRUE, 0) < 0) { |
| DHD_ERROR(("%s: wl down failed\n", __FUNCTION__)); |
| } |
| ret = dhd_iovar(dhd, 0, "rateset", (char *)&defrs, sizeof(_wl_rateset_args_t), |
| NULL, 0, TRUE); |
| if (ret < 0) { |
| DHD_ERROR(("%s Set rateset_legacy failed %d\n", __FUNCTION__, ret)); |
| } |
| if (dhd_wl_ioctl_cmd(dhd, WLC_UP, NULL, 0, TRUE, 0) < 0) { |
| DHD_ERROR(("%s: wl up failed\n", __FUNCTION__)); |
| } |
| } |
| return ret; |
| } else if(!strcasecmp(name, "rateset_ht")) { |
| typedef wl_rateset_args_v2_t _wl_rateset_args_t; |
| uint low = 0, high = 0; |
| _wl_rateset_args_t defrs; |
| struct net_device *ndev; |
| uint8 *rsmcs = NULL; |
| |
| bzero(&defrs, sizeof(_wl_rateset_args_t)); |
| ndev = dhd_linux_get_primary_netdev(dhd); |
| if (!ndev) { |
| DHD_ERROR(("%s: Cannot find netdev\n", __FUNCTION__)); |
| return -ENODEV; |
| } |
| ret = wldev_iovar_getbuf(ndev, "cur_rateset", NULL, 0, |
| &defrs, sizeof(_wl_rateset_args_t), NULL); |
| if (ret < 0) { |
| WL_ERR(("get rateset failed = %d\n", ret)); |
| return ret; |
| } |
| var_int = (uint)simple_strtol(value, NULL, 16); |
| low = var_int & 0x000000ff; |
| high = (var_int & 0x0000ff00) >> 8; |
| |
| rsmcs = defrs.mcs; |
| rsmcs[0] = low; |
| rsmcs[1] = high; |
| if (dhd_wl_ioctl_cmd(dhd, WLC_DOWN, NULL, 0, TRUE, 0) < 0) { |
| DHD_ERROR(("%s: wl down failed\n", __FUNCTION__)); |
| } |
| ret = dhd_iovar(dhd, 0, "rateset", (char *)&defrs, sizeof(_wl_rateset_args_t), |
| NULL, 0, TRUE); |
| if (ret < 0) { |
| DHD_ERROR(("%s Set rateset_ht failed %d\n", __FUNCTION__, ret)); |
| } |
| if (dhd_wl_ioctl_cmd(dhd, WLC_UP, NULL, 0, TRUE, 0) < 0) { |
| DHD_ERROR(("%s: wl up failed\n", __FUNCTION__)); |
| } |
| return ret; |
| } else if(!strcasecmp(name, "rateset_he")) { |
| typedef wl_rateset_args_v2_t _wl_rateset_args_t; |
| uint32 stream1 = 0, stream2 = 0; |
| _wl_rateset_args_t defrs; |
| struct net_device *ndev; |
| uint16 *rshe_mcs = NULL; |
| char* endp = NULL; |
| |
| bzero(&defrs, sizeof(_wl_rateset_args_t)); |
| ndev = dhd_linux_get_primary_netdev(dhd); |
| if (!ndev) { |
| DHD_ERROR(("%s: Cannot find netdev\n", __FUNCTION__)); |
| return -ENODEV; |
| } |
| ret = wldev_iovar_getbuf(ndev, "cur_rateset", NULL, 0, |
| &defrs, sizeof(_wl_rateset_args_t), NULL); |
| if (ret < 0) { |
| WL_ERR(("get rateset failed = %d\n", ret)); |
| return ret; |
| } |
| |
| stream1 = (uint)simple_strtol(value, &endp, 16); |
| if (endp[0] == ',') { |
| stream2 = (uint)simple_strtol(endp + 1, NULL, 16); |
| } |
| if ((stream1 != 0x0000) && /* vht disabled */ |
| (stream1 != WL_HE_CAP_MCS_0_7_MAP) && /* he mcs0-7 */ |
| (stream1 != WL_HE_CAP_MCS_0_9_MAP) && /* he mcs0-9 */ |
| (stream1 != WL_HE_CAP_MCS_0_11_MAP)) { /* he mcs0-11 */ |
| DHD_ERROR(("HE rate mask must be 0 (disabled)," |
| " 0xff (MCS0-7), 0x3ff (MCS0-9), or 0xfff (MCS0-11).\n")); |
| return BCME_BADARG; |
| } |
| if ((stream2 != 0x0000) && /* vht disabled */ |
| (stream2 != WL_HE_CAP_MCS_0_7_MAP) && /* he mcs0-7 */ |
| (stream2 != WL_HE_CAP_MCS_0_9_MAP) && /* he mcs0-9 */ |
| (stream2 != WL_HE_CAP_MCS_0_11_MAP)) { /* he mcs0-11 */ |
| DHD_ERROR(("HE rate mask must be 0 (disabled), 0xff (MCS0-7)" |
| ", 0x3ff (MCS0-9), or 0xfff (MCS0-11).\n")); |
| return BCME_BADARG; |
| } |
| |
| rshe_mcs = defrs.he_mcs; |
| rshe_mcs[0] = stream1; |
| rshe_mcs[1] = stream2; |
| DHD_INFO(("rateset he %x %x\n",rshe_mcs[0], rshe_mcs[1])); |
| if (dhd_wl_ioctl_cmd(dhd, WLC_DOWN, NULL, 0, TRUE, 0) < 0) { |
| DHD_ERROR(("%s: wl down failed\n", __FUNCTION__)); |
| } |
| ret = dhd_iovar(dhd, 0, "rateset", (char *)&defrs, sizeof(_wl_rateset_args_t), NULL, 0, |
| TRUE); |
| if (ret < 0) { |
| DHD_ERROR(("rateset %s Set rateset_he failed %d\n", __FUNCTION__, ret)); |
| } |
| if (dhd_wl_ioctl_cmd(dhd, WLC_UP, NULL, 0, TRUE, 0) < 0) { |
| DHD_ERROR(("%s: wl up failed\n", __FUNCTION__)); |
| } |
| return ret; |
| } |
| //// assoc preference |
| else if (!strcasecmp(name, "assoc_pref")) { |
| var_int = (int)simple_strtol(value, NULL, 0); |
| ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_ASSOC_PREFER, |
| &var_int, sizeof(var_int), TRUE, 0); |
| return ret; |
| } |
| //// retry times |
| else if (!strcasecmp(name, "srl")) { |
| var_int = (uint)simple_strtol(value, NULL, 0); |
| ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_SRL, &var_int, sizeof(var_int), TRUE, 0); |
| if (ret < 0) { |
| DHD_ERROR(("rateset %s Set srl failed %d\n", __FUNCTION__, ret)); |
| } |
| return ret; |
| } else if (!strcasecmp(name, "lrl")) { |
| var_int = (uint)simple_strtol(value, NULL, 0); |
| ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_LRL, &var_int, sizeof(var_int), TRUE, 0); |
| if (ret < 0) { |
| DHD_ERROR(("rateset %s Set srl failed %d\n", __FUNCTION__, ret)); |
| } |
| return ret; |
| } |
| //// per-frame retry limit |
| else if (!strcasecmp(name, "pfrt_en")) { |
| uint powervar = 0; |
| var_int = (int)simple_strtol(value, NULL, 0); |
| |
| if (dhd_wl_ioctl_cmd(dhd, WLC_UP, NULL, 0, TRUE, 0) < 0) { |
| DHD_ERROR(("%s: wl up failed\n", __FUNCTION__)); |
| } |
| ret = dhd_iovar(dhd, 0, "mpc", (char *)&powervar, sizeof(powervar), NULL, |
| 0, TRUE); |
| if (ret) { |
| DHD_ERROR(("%s: mpc failed:%d\n", __FUNCTION__, ret)); |
| } |
| ret = dhd_iovar(dhd, 0, "pfrt_en", (char *)&var_int, sizeof(var_int), NULL, 0, |
| TRUE); |
| if (ret < 0) { |
| DHD_ERROR(("%s Set pfrt_en failed %d\n", __FUNCTION__, ret)); |
| } |
| powervar = 1; |
| if (dhd_iovar(dhd, 0, "mpc", (char *)&powervar, sizeof(powervar), NULL, |
| 0, TRUE) < 0) { |
| DHD_ERROR(("%s: mpc failed\n", __FUNCTION__)); |
| } |
| return ret; |
| } else if (!strcasecmp(name, "pfrt_auth")) { |
| uint powervar = 0; |
| var_int = (int)simple_strtol(value, NULL, 0); |
| |
| if (dhd_wl_ioctl_cmd(dhd, WLC_UP, NULL, 0, TRUE, 0) < 0) { |
| DHD_ERROR(("%s: wl up failed\n", __FUNCTION__)); |
| } |
| ret = dhd_iovar(dhd, 0, "mpc", (char *)&powervar, sizeof(powervar), NULL, |
| 0, TRUE); |
| if (ret) { |
| DHD_ERROR(("%s: mpc failed:%d\n", __FUNCTION__, ret)); |
| } |
| ret = dhd_iovar(dhd, 0, "pfrt_auth", (char *)&var_int, sizeof(var_int), NULL, 0, |
| TRUE); |
| if (ret < 0) { |
| DHD_ERROR(("%s Set pfrt_auth failed %d\n", __FUNCTION__, ret)); |
| } |
| powervar = 1; |
| if (dhd_iovar(dhd, 0, "mpc", (char *)&powervar, sizeof(powervar), NULL, |
| 0, TRUE) < 0) { |
| DHD_ERROR(("%s: mpc failed\n", __FUNCTION__)); |
| } |
| return ret; |
| } else if (!strcasecmp(name, "pfrt_asrq")) { |
| uint powervar = 0; |
| var_int = (int)simple_strtol(value, NULL, 0); |
| |
| if (dhd_wl_ioctl_cmd(dhd, WLC_UP, NULL, 0, TRUE, 0) < 0) { |
| DHD_ERROR(("%s: wl up failed\n", __FUNCTION__)); |
| } |
| ret = dhd_iovar(dhd, 0, "mpc", (char *)&powervar, sizeof(powervar), NULL, |
| 0, TRUE); |
| if (ret) { |
| DHD_ERROR(("%s: mpc failed:%d\n", __FUNCTION__, ret)); |
| } |
| ret = dhd_iovar(dhd, 0, "pfrt_asrq", (char *)&var_int, sizeof(var_int), NULL, 0, |
| TRUE); |
| if (ret < 0) { |
| DHD_ERROR(("%s Set pfrt_asrq failed %d\n", __FUNCTION__, ret)); |
| } |
| powervar = 1; |
| if (dhd_iovar(dhd, 0, "mpc", (char *)&powervar, sizeof(powervar), NULL, |
| 0, TRUE) < 0) { |
| DHD_ERROR(("%s: mpc failed\n", __FUNCTION__)); |
| } |
| return ret; |
| } else if (!strcasecmp(name, "pfrt_rasrq")) { |
| uint powervar = 0; |
| var_int = (int)simple_strtol(value, NULL, 0); |
| |
| if (dhd_wl_ioctl_cmd(dhd, WLC_UP, NULL, 0, TRUE, 0) < 0) { |
| DHD_ERROR(("%s: wl up failed\n", __FUNCTION__)); |
| } |
| ret = dhd_iovar(dhd, 0, "mpc", (char *)&powervar, sizeof(powervar), NULL, |
| 0, TRUE); |
| if (ret) { |
| DHD_ERROR(("%s: mpc failed:%d\n", __FUNCTION__, ret)); |
| } |
| ret = dhd_iovar(dhd, 0, "pfrt_rasrq", (char *)&var_int, sizeof(var_int), NULL, 0, |
| TRUE); |
| if (ret < 0) { |
| DHD_ERROR(("%s Set pfrt_rasrq failed %d\n", __FUNCTION__, ret)); |
| } |
| powervar = 1; |
| if (dhd_iovar(dhd, 0, "mpc", (char *)&powervar, sizeof(powervar), NULL, |
| 0, TRUE) < 0) { |
| DHD_ERROR(("%s: mpc failed\n", __FUNCTION__)); |
| } |
| return ret; |
| } else if (!strcasecmp(name, "pfrt_gact")) { |
| uint powervar = 0; |
| var_int = (int)simple_strtol(value, NULL, 0); |
| |
| if (dhd_wl_ioctl_cmd(dhd, WLC_UP, NULL, 0, TRUE, 0) < 0) { |
| DHD_ERROR(("%s: wl up failed\n", __FUNCTION__)); |
| } |
| ret = dhd_iovar(dhd, 0, "mpc", (char *)&powervar, sizeof(powervar), NULL, |
| 0, TRUE); |
| if (ret) { |
| DHD_ERROR(("%s: mpc failed:%d\n", __FUNCTION__, ret)); |
| } |
| ret = dhd_iovar(dhd, 0, "pfrt_gact", (char *)&var_int, sizeof(var_int), NULL, 0, |
| TRUE); |
| if (ret < 0) { |
| DHD_ERROR(("%s Set pfrt_gact failed %d\n", __FUNCTION__, ret)); |
| } |
| powervar = 1; |
| if (dhd_iovar(dhd, 0, "mpc", (char *)&powervar, sizeof(powervar), NULL, |
| 0, TRUE) < 0) { |
| DHD_ERROR(("%s: mpc failed\n", __FUNCTION__)); |
| } |
| return ret; |
| } |
| //// AMPDU control per TID |
| else if (!strcasecmp(name, "ampdu_tid")) { |
| int i; |
| struct { |
| uint8 tid; |
| uint8 enable; |
| } ampdu_tid = {0, 0}; |
| |
| var_int = (int)simple_strtol(value, NULL, 16); |
| if (var_int <= 0xFF) { |
| for (i = 0; i < 8; i++) { |
| ampdu_tid.tid = i; |
| ampdu_tid.enable = (var_int >> i) & 1; |
| ret = dhd_iovar(dhd, 0, "ampdu_tid", (char *)&du_tid, sizeof(ampdu_tid), NULL, 0, |
| TRUE); |
| if (ret < 0) { |
| DHD_ERROR(("%s Set ampdu_tid failed %d\n", __FUNCTION__, ret)); |
| } |
| } |
| } else { |
| DHD_ERROR(("Set wrong value to ampdu_tid\n")); |
| } |
| } |
| //// keep alive |
| else if (!strcasecmp(name, "mkeep_alive")) { |
| uint32 msec = 0; |
| wl_mkeep_alive_pkt_t mkeep_alive_pkt = {0, 0, 0, 0, 0, {0}}; |
| |
| msec = (int)simple_strtol(value, NULL, 0); |
| mkeep_alive_pkt.period_msec = msec; |
| mkeep_alive_pkt.version = htod16(WL_MKEEP_ALIVE_VERSION); |
| mkeep_alive_pkt.length = htod16(WL_MKEEP_ALIVE_FIXED_LEN); |
| /* Setup keep alive zero for null packet generation */ |
| mkeep_alive_pkt.keep_alive_id = 0; |
| mkeep_alive_pkt.len_bytes = 0; |
| bzero(mkeep_alive_pkt.data, sizeof(mkeep_alive_pkt.data)); |
| ret = dhd_iovar(dhd, 0, "mkeep_alive", (char *)&mkeep_alive_pkt, sizeof(mkeep_alive_pkt), NULL, 0, |
| TRUE); |
| if (ret < 0) { |
| DHD_ERROR(("%s Set mkeep_alive failed %d\n", __FUNCTION__, ret)); |
| } |
| } |
| //// packet filter |
| else if (!strcasecmp(name, "pkt_filter_add")) { |
| int32 mask_size, pattern_size; |
| char *id, *offset, *bitmask, *pattern; |
| struct wl_pkt_filter pkt_filter; |
| int i; |
| |
| pkt_filter.negate_match = htod32(0); |
| pkt_filter.type = htod32(0); |
| if ((id = bcmstrtok(&value, ",", 0)) == NULL) { |
| DHD_ERROR(("%s(): id not found\n", __FUNCTION__)); |
| return BCME_ERROR; |
| } |
| if ((offset = bcmstrtok(&value, ",", 0)) == NULL) { |
| DHD_ERROR(("%s(): offset not found\n", __FUNCTION__)); |
| return BCME_ERROR; |
| } |
| if ((bitmask = bcmstrtok(&value, ",", 0)) == NULL) { |
| DHD_ERROR(("%s(): bitmask not found\n", __FUNCTION__)); |
| return BCME_ERROR; |
| } |
| if ((pattern = bcmstrtok(&value, ",", 0)) == NULL) { |
| DHD_ERROR(("%s(): pattern not found\n", __FUNCTION__)); |
| return BCME_ERROR; |
| } |
| |
| pkt_filter.id = strtoul(id, NULL, 0); |
| pkt_filter.u.pattern.offset = strtoul(offset, NULL, 0); |
| mask_size = pattern_atoh_len(bitmask, |
| (char *)pkt_filter.u.pattern.mask_and_pattern, |
| MAX_MASK_PATTERN_FILTER_LEN); |
| pattern_size = pattern_atoh_len(pattern, |
| (char *)&pkt_filter.u.pattern.mask_and_pattern[mask_size], |
| MAX_MASK_PATTERN_FILTER_LEN); |
| |
| if (mask_size != pattern_size) { |
| DHD_ERROR(("Mask and pattern not the same size\n")); |
| ret = -EINVAL; |
| return ret; |
| } |
| |
| pkt_filter.u.pattern.size_bytes = mask_size; |
| UNUSED_PARAMETER(i); |
| for(i = 0; i < (mask_size + pattern_size); i++) { |
| DHD_INFO(("pkt_filter_add mask_and_pattern 0x%x\n", pkt_filter.u.pattern.mask_and_pattern[i])); |
| } |
| |
| ret = dhd_iovar(dhd, 0, "pkt_filter_add", (char *)&pkt_filter, sizeof(pkt_filter), NULL, 0, |
| TRUE); |
| if (ret < 0) { |
| DHD_ERROR(("%s() Set pkt_filter_add failed %d\n", __FUNCTION__, ret)); |
| } |
| } else if (!strcasecmp(name, "pkt_filter_enable")) { |
| char* endp = NULL; |
| wl_pkt_filter_enable_t filter_enable; |
| |
| filter_enable.id = (uint)simple_strtol(value, &endp, 0); |
| if (endp[0] == ',') { |
| filter_enable.enable = (uint)simple_strtol(endp + 1, NULL, 0); |
| } |
| |
| ret = dhd_iovar(dhd, 0, "pkt_filter_enable", (char *)&filter_enable, sizeof(filter_enable), NULL, 0, |
| TRUE); |
| if (ret < 0) { |
| DHD_ERROR(("%s Set pkt_filter_enable failed %d\n", __FUNCTION__, ret)); |
| } |
| } |
| // other default |
| else { |
| /* wlu_iovar_setint */ |
| var_int = (int)simple_strtol(value, NULL, 0); |
| |
| /* Setup timeout bcn_timeout from dhd driver 4.217.48 */ |
| if (!strcmp(name, "roam_off")) { |
| /* Setup timeout if Beacons are lost to report link down */ |
| if (var_int) { |
| uint bcn_timeout = 2; |
| ret = dhd_iovar(dhd, 0, "bcn_timeout", (char *)&bcn_timeout, |
| sizeof(bcn_timeout), NULL, 0, TRUE); |
| if (ret < 0) { |
| DHD_ERROR(("%s set bcn_timeout failed %d\n", |
| __FUNCTION__, ret)); |
| } |
| } |
| } |
| /* Setup timeout bcm_timeout from dhd driver 4.217.48 */ |
| |
| DHD_INFO(("%s:[%s]=[%d]\n", __FUNCTION__, name, var_int)); |
| |
| return dhd_iovar(dhd, 0, name, (char *)&var_int, |
| sizeof(var_int), NULL, 0, TRUE); |
| } |
| |
| return 0; |
| } |
| |
| // Added for compatibility |
| // https://github.com/torvalds/linux/commit/736706bee3298208343a76096370e4f6a5c55915 |
| #if (LINUX_VERSION_CODE > KERNEL_VERSION(5, 0, 0)) |
| #define get_ds() KERNEL_DS |
| #endif // (LINUX_VERSION_CODE > KERNEL_VERSION(5, 0, 0)) |
| |
| extern char config_path[]; |
| |
| // ' ' (0x20) space (SPC) |
| // '\t' (0x09) horizontal tab (TAB) |
| // '\v' (0x0b) vertical tab (VT) |
| // '\f' (0x0c) feed (FF) |
| // '\r' (0x0d) carriage return (CR) |
| // '\n' (0x0a) newline (LF) |
| #define IS_LINE_END(ch) (('\r' == (ch)) || ('\n' == (ch)) || ('\0' == (ch))) |
| #define IS_WHITE_SPACE(ch) ((' ' == (ch)) || ('\t' == (ch)) || ('\v' == (ch)) || ('\f' == (ch))) |
| #define IS_SPACE(ch) ((IS_LINE_END(ch)) || (IS_WHITE_SPACE(ch))) |
| #define IS_COMMENT_CHAR(ch) ('#' == (ch)) |
| |
| int |
| dhd_preinit_config(dhd_pub_t *dhd, int ifidx) |
| { |
| mm_segment_t old_fs; |
| struct kstat stat; |
| struct file *fp = NULL; |
| unsigned int len; |
| char *buf = NULL, *p, *name, *value; |
| int ret = 0; |
| |
| if ('\0' == config_path[0]) { |
| printk(KERN_ERR "config_path can't be read. \n"); |
| return 0; |
| } |
| |
| old_fs = get_fs(); |
| set_fs(get_ds()); |
| if ((ret = dhd_vfs_stat(config_path, &stat))) { |
| set_fs(old_fs); |
| printk(KERN_ERR "%s: Failed to get information (%d)\n", |
| config_path, ret); |
| return ret; |
| } |
| set_fs(old_fs); |
| |
| if (!(buf = MALLOC(dhd->osh, stat.size + 1))) { |
| printk(KERN_ERR "Failed to allocate memory %llu bytes\n", stat.size); |
| return -ENOMEM; |
| } |
| memset(buf, 0x0, stat.size + 1); |
| printk("dhd_preinit_config : config path : %s \n", config_path); |
| |
| // modify to avoid warning |
| if ( (!(fp = dhd_os_open_image1(dhd, config_path))) |
| || (0 >= (len = dhd_os_get_image_block(buf, stat.size, fp))) |
| ) { |
| goto err; |
| } |
| |
| if (len != stat.size) { |
| printk("dhd_preinit_config : Error - read length mismatched len = %d\n", len); |
| goto err; |
| } |
| |
| dhd_conf_dependency_dft(dhd); |
| buf[stat.size] = '\0'; |
| for (p = buf; *p; p++) { |
| if (IS_SPACE(*p)) continue; // remove all prefix space |
| |
| DHD_INFO(("%s-%d: searching item '%s'\n", __FUNCTION__, __LINE__, p)); |
| if (IS_COMMENT_CHAR(*p)) { |
| DHD_INFO(("%s-%d: found #, *p='%c' '%s'\n", __FUNCTION__, __LINE__, *p, p)); |
| do { |
| p++; |
| } while (!(IS_LINE_END(*p))); |
| DHD_INFO(("%s-%d: done sarch, *p='%c' '%s'\n", __FUNCTION__, __LINE__, *p, p)); |
| continue; |
| } |
| DHD_INFO(("%s-%d: spliting item '%s'\n", __FUNCTION__, __LINE__, p)); |
| |
| // search name |
| for (name = p; *p; p++) { |
| if (IS_WHITE_SPACE(*p)) { // remove suffix space |
| *p = '\0'; |
| } else if (IS_COMMENT_CHAR(*p)) { |
| p--; // use the comment char for next time searching |
| break; |
| } else if (IS_LINE_END(*p)) { |
| break; |
| } else if ('=' == *p) { |
| *p = '\0'; |
| do { p++; } while ((*p) && (IS_WHITE_SPACE(*p))); // remove prefix space |
| if ('\0' == *p) break; |
| |
| // search value |
| for (value = p; *p; p++) { |
| DHD_INFO(("%s-%d: probe with ch='%c', 0x%p\n", |
| __FUNCTION__, __LINE__, *p, p)); |
| if (IS_WHITE_SPACE(*p) || IS_COMMENT_CHAR(*p)) { |
| *p = '\0'; |
| } else if (IS_LINE_END(*p)) { |
| *p = '\0'; |
| DHD_ERROR(("%s-%d: name='%s', value='%s'\n", |
| __FUNCTION__, __LINE__, name, value)); |
| if ((ret = dhd_preinit_proc(dhd, ifidx, name, value)) < 0) { |
| printk(KERN_ERR "%s: %s=%s\n", |
| bcmerrorstr(ret), name, value); |
| } |
| p--; // skip both inner and outer for-loop |
| break; |
| } |
| } |
| } |
| } |
| } |
| |
| ret = 0; |
| |
| out: |
| if (fp) |
| dhd_os_close_image1(dhd, fp); |
| if (buf) |
| MFREE(dhd->osh, buf, stat.size+1); |
| return ret; |
| |
| err: |
| ret = -1; |
| goto out; |
| } |
| |
| void |
| dhd_conf_11mode_set(dhd_pub_t *dhd) |
| { |
| dhd_config_t *config = dhd->conf; |
| int ret = 0; |
| int enable_mode = 0; |
| |
| if (config->nmode_disable || config->vhtmode_disable || |
| config->he_disable || config->gmode_set) { |
| if (dhd_wl_ioctl_cmd(dhd, WLC_DOWN, NULL, 0, TRUE, 0) < 0) { |
| DHD_ERROR(("%s: wl down failed\n", __FUNCTION__)); |
| } |
| |
| if (config->nmode_disable) { |
| /* nmode 0. fw set ac/ax 0 as well */ |
| ret = dhd_iovar(dhd, 0, "nmode", (char *)&enable_mode, |
| sizeof(enable_mode), NULL, 0, TRUE); |
| if (ret < 0) { |
| DHD_ERROR(("%s Set nmode failed %d\n", __FUNCTION__, ret)); |
| } |
| } |
| |
| if (config->gmode_set) { |
| ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_GMODE, (char *)&config->gmode, |
| sizeof(config->gmode), TRUE, 0); |
| if (ret < 0) { |
| DHD_ERROR(("%s Set gmode failed %d\n", __FUNCTION__, ret)); |
| } |
| } |
| |
| if (config->vhtmode_disable) { |
| ret = dhd_iovar(dhd, 0, "vhtmode", (char *)&enable_mode, |
| sizeof(enable_mode), NULL, 0, TRUE); |
| if (ret < 0) { |
| DHD_ERROR(("%s Set vhtmode failed %d\n", __FUNCTION__, ret)); |
| } |
| } |
| |
| if (config->he_disable) { |
| struct net_device *ndev; |
| struct bcm_cfg80211 *cfg; |
| s32 bssidx = 0; |
| |
| ndev = dhd_linux_get_primary_netdev(dhd); |
| if (!ndev) { |
| DHD_ERROR(("%s: Cannot find netdev\n", __FUNCTION__)); |
| goto end; |
| } |
| cfg = wl_get_cfg(ndev); |
| if (!cfg) { |
| DHD_ERROR(("%s: Cannot find cfg\n", __FUNCTION__)); |
| goto end; |
| } |
| if ((bssidx = wl_get_bssidx_by_wdev(cfg, ndev->ieee80211_ptr)) < 0) { |
| DHD_ERROR(("find index from wdev failed\n")); |
| goto end; |
| } |
| ret = wl_cfg80211_set_he_enab(ndev, cfg, bssidx, WL_IF_TYPE_STA, 0); |
| if (ret) { |
| DHD_ERROR(("failed to disable ax %d\n", ret)); |
| |
| } |
| } |
| |
| end: |
| if (dhd_wl_ioctl_cmd(dhd, WLC_UP, NULL, 0, TRUE, 0) < 0) { |
| DHD_ERROR(("%s: wl up failed\n", __FUNCTION__)); |
| } |
| } |
| } |
| |
| void |
| dhd_conf_dependency_dft(dhd_pub_t *dhd) |
| { |
| dhd_config_t *config = dhd->conf;; |
| |
| config->nmode_disable = 0; |
| config->vhtmode_disable = 0; |
| config->he_disable = 0; |
| |
| config->gmode = 1; |
| config->gmode_set = 0; |
| config->scan_band_prefer = -1; |
| } |
| |
| void |
| dhd_conf_dependency_set(dhd_pub_t *dhd) |
| { |
| dhd_conf_11mode_set(dhd); |
| } |
| |
| int |
| dhd_conf_attach(dhd_pub_t *dhd) |
| { |
| dhd_config_t *config; |
| |
| if (dhd->conf != NULL) { |
| DHD_ERROR(("config is attached before!\n")); |
| return 0; |
| } |
| if (!(config = MALLOC(dhd->osh, sizeof(dhd_config_t)))) { |
| DHD_ERROR(("MALLOC failed\n")); |
| goto fail; |
| } |
| memset(config, 0, sizeof(dhd_config_t)); |
| |
| dhd->conf = config; |
| |
| return 0; |
| |
| fail: |
| if (config != NULL) |
| MFREE(dhd->osh, config, sizeof(dhd_config_t)); |
| return BCME_NOMEM; |
| } |
| |
| void |
| dhd_conf_detach(dhd_pub_t *dhd) |
| { |
| if (dhd->conf) { |
| MFREE(dhd->osh, dhd->conf, sizeof(dhd_config_t)); |
| } |
| dhd->conf = NULL; |
| } |