Only To developers.
wpa_supplicant 0.8.x, wpa_supplicant_drvier nl80211, wifi chip bcm4330.
转载请注明出处:http://blog.csdn.net/zirconsdu/article/details/8571260
最后修改版,能连接使用ADHOC,能显示信号强度;
Patch
- 修改Settings/wifi中的代码以显示[IBSS][WEP] ssid或没有名字的ssid.
当UI显示SSID列表时,会获取从wpa_supplicant最近扫描到的APs;wpa_supplicant的输出扫描结果并没有过滤掉IBSS或隐藏的APs。
In constructAccessPoints()@WifiSettings.java,
final List<ScanResult> results = mWifiManager.getScanResults(); //同步操作
if (results != null) {
for (ScanResult result : results) {
// Ignore hidden and ad-hoc networks.
if (result.SSID == null || result.SSID.length() == 0/* || result.capabilities.contains("[IBSS]")*/ ) {
continue;
}
- 修改wpa_supplicant,设置IBSS spot工作模式配置和连接时避免跳过
当第一次点击连接IBSS/ADHOC AP时,会弹出输入密码对话框,wpa_supplicant会将AP configuration信息保存到wpa_supplicant.conf中;此时保存该IBSS AP的工作模式为mode=1,保存到wpa_supplicant.conf中。
In wpa_supplicant_ctrl_iface_set_network(…)@ctrl_iface.c
static int wpa_supplicant_ctrl_iface_set_network(
struct wpa_supplicant *wpa_s, char *cmd)
{
int id;
struct wpa_ssid *ssid;
char *name, *value;
struct wpa_bss *bss;
/* cmd: "<network id> <variable name> <value>" */
name = os_strchr(cmd, ' ');
if (name == NULL)
return -1;
*name++ = '\0';
value = os_strchr(name, ' ');
if (value == NULL)
return -1;
*value++ = '\0';
id = atoi(cmd);
wpa_printf(MSG_DEBUG, "CTRL_IFACE: SET_NETWORK id=%d name='%s'",
id, name);
wpa_hexdump_ascii_key(MSG_INFO, "CTRL_IFACE: value",
(u8 *) value, os_strlen(value));
ssid = wpa_config_get_network(wpa_s->conf, id);
if (ssid == NULL) {
wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find network "
"id=%d", id);
return -1;
}
if (wpa_config_set(ssid, name, value, 0) < 0) {
wpa_printf(MSG_DEBUG, "CTRL_IFACE: Failed to set network "
"variable '%s'", name);
return -1;
}
if (os_strcmp(name, "ssid") == 0) {
wpa_printf(MSG_DEBUG, "CTRL_IFACE: check if hook %s ssid->mode to 1(IBSS) ", value);
bss = NULL;
dl_list_for_each(bss, &wpa_s->bss_id, struct wpa_bss, list_id) {
if(bss->ssid) {
wpa_printf(MSG_DEBUG, "CTRL_IFACE: bss ssid foreach '%s'", bss->ssid);
if(os_strncmp(bss->ssid, value+1, os_strlen(bss->ssid))==0 && (bss->caps & IEEE80211_CAP_IBSS))
{
wpa_printf(MSG_DEBUG, "CTRL_IFACE: find matched ssid for '%d', try to set IBSS mode", id);
if (wpa_config_set(ssid, "mode", "1", 0) < 0) {
wpa_printf(MSG_DEBUG, "CTRL_IFACE: failed to set IBSS mode on '%d'", id);
return -1;
}
wpa_printf(MSG_DEBUG, "CTRL_IFACE: hook to set IBSS mode on '%d' successfully", id);
}
}
/* loop all bssid for the ssid */
}
}
当长按AP点击连接时,wpa_supplicant会将AP和扫描结果与配置库中的AP比对,如果为IBSS,则被跳过。
在wpa_scan_res_match(…)@events.c中,修改
if (bss->caps & IEEE80211_CAP_IBSS) {
wpa_dbg(wpa_s, MSG_DEBUG, " skip - IBSS (adhoc) "
"network");
continue;
}
为
if ((bss->caps & IEEE80211_CAP_IBSS)&& (ssid->mode!=IEEE80211_MODE_IBSS)) {
wpa_dbg(wpa_s, MSG_DEBUG, " skip - IBSS (adhoc) "
"network");
continue;
}
wpa_supplicant在扫描结果中找不到匹配的AP进行连接时,会用wpa_supplicant_pick_new_network选择IBSS ssid进行关联,增加代码跳过IBSS AP,因为此时该AP肯定不在扫描结果中。否则会导致去连接这个AP,导致后续扫描出错。
_wpa_supplicant_event_scan_results(…) @ events.c
} else {
wpa_scan_results_free(scan_res);
wpa_dbg(wpa_s, MSG_DEBUG, "No suitable network found");
ssid = wpa_supplicant_pick_new_network(wpa_s);
if (ssid) {
if(ssid->mode == IEEE80211_MODE_IBSS) {
wpa_dbg(wpa_s, MSG_DEBUG, "ibss mode ssid selected by pcik_new_ssid is skipped");
return -1;
}
wpa_dbg(wpa_s, MSG_DEBUG, "Setup a new network");
wpa_supplicant_associate(wpa_s, NULL, ssid);
wpa_supplicant_rsn_preauth_scan_results(wpa_s);
} else {
- linux内核nl80211驱动和bcm4330驱动
wpa_driver_nl80211_ibss发送NL80211_CMD_SET_INTERFACE和 NL80211_CMD_JOIN_IBSS经linux nl80211 driver交给bcm4330 common driver处理。
NL80211_CMD_SET_INTERFACE投递给wl_cfg80211_change_virtual_iface时,需要切换bcm4330固件工作模式到IBSS模式;增加网卡工作模式INFRA/ADHOC设置代码如下,
In wl_cfg80211_change_virtual_iface(…) @ wl_cfg80211.c
if (ap) {
wl_set_mode_by_netdev(wl, ndev, mode);
if (wl->p2p_supported && wl->p2p->vif_created) {
……………………………….
}
} else {
wl_set_mode_by_netdev(wl, ndev, mode);
printk("try to set infra in wl_cfg80211_change_virtual_iface: value=%d, mode=%s", infra, (infra==1)?"INFRA":"ADHOC");
err = wldev_ioctl(ndev, WLC_SET_INFRA, &infra, sizeof(infra), true);
if (unlikely(err)) {
WL_ERR(("WLC_SET_INFRA mode failed with error (%d)\n", err));
return err;
}
}
NL80211_CMD_JOIN_IBSS投递给wl_cfg80211_join_ibss时,设置固件auth模式为OPEN_SYSTEM rather than SHARED_KEY, 设置Beacon Interval和starter freq,然后连接AP。修改代码如下,
In wl_cfg80211_join_ibss @ wl_cfg80211.c
static s32
wl_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *dev,
struct cfg80211_ibss_params *params)
{
struct wl_priv *wl = wiphy_priv(wiphy);
struct cfg80211_bss *bss;
struct ieee80211_channel *chan;
struct wl_join_params join_params;
struct cfg80211_ssid ssid;
s32 scan_retry = 0;
s32 err = 0;
//WL_TRACE(("In\n"));
printk("In wl_cfg80211_join_ibss\n");
CHECK_SYS_UP(wl);
if (params->bssid) { // 此处注释掉以下两行;否则需要在wpa_supplicant wpa_driver_nl80211_join_ibss中修改在IBSS模式下传入的param->bssid为NULL.
// WL_ERR(("Invalid bssid\n"));
printk("wl_cfg80211_join_ibss: with bssid, EOPNOTSUPP originally\n");
// return -EOPNOTSUPP;
}
bss = cfg80211_get_ibss(wiphy, NULL, params->ssid, params->ssid_len);
/* scarely bss==null */
if (!bss) {
memcpy(ssid.ssid, params->ssid, params->ssid_len);
ssid.ssid_len = params->ssid_len;
do {
if (unlikely
(__wl_cfg80211_scan(wiphy, dev, NULL, &ssid) ==
-EBUSY)) {
wl_delay(150);
} else {
break;
}
} while (++scan_retry < WL_SCAN_RETRY_MAX);
/* to allow scan_inform to propagate to cfg80211 plane */
if (rtnl_is_locked()) {
rtnl_unlock();
rollback_lock = true;
}
/* wait 4 secons till scan done.... */
schedule_timeout_interruptible(4 * HZ);
if (rollback_lock)
rtnl_lock();
bss = cfg80211_get_ibss(wiphy, NULL,
params->ssid, params->ssid_len);
}
if (bss) {
wl->ibss_starter = false;
//WL_DBG(("Found IBSS\n"));
printk("wl_cfg80211_join_ibss: Found IBSS\n");
} else {
wl->ibss_starter = true;
printk("wl_cfg80211_join_ibss: Still not Found IBSS\n");
}
/* Configure Privacy for starter */
if (params->privacy)
wsec |= WEP_ENABLED;
/* set auth to open */
err = wldev_iovar_setint_bsscfg(dev, "auth", 0, bssidx);
if (err < 0) {
WL_ERR(("auth error %d\n", err));
return BCME_ERROR;
}
/* set wsec */
err = wldev_iovar_setint_bsscfg(dev, "wsec", wsec, bssidx);
if (err < 0) {
WL_ERR(("wsec error %d\n", err));
return BCME_ERROR;
}
/* set upper-layer auth */
err = wldev_iovar_setint_bsscfg(dev, "wpa_auth", 0, bssidx);
if (err < 0) {
WL_ERR(("wpa_auth error %d\n", err));
return BCME_ERROR;
}
/* Configure Beacon Interval for starter */
if (params->beacon_interval)
bcnprd = htod32(params->beacon_interval);
else
bcnprd = htod32(100);
err = wldev_ioctl(dev, WLC_SET_BCNPRD, &bcnprd, sizeof(bcnprd), true);
if (unlikely(err)) {
WL_ERR(("WLC_SET_BCNPRD failed (%d)\n", err));
goto done;
}
/*
* Join with specific BSSID and cached SSID
* If SSID is zero join based on BSSID only
*/
memset(&join_params, 0, sizeof(join_params));
memcpy((void *)join_params.ssid.SSID, (void *)params->ssid,
params->ssid_len);
join_params.ssid.SSID_len = htod32(params->ssid_len);
join_params_size = sizeof(join_params.ssid);
wl_update_prof(wl, dev, NULL, &join_params.ssid, WL_PROF_SSID);
if (params->bssid) {
memcpy(&join_params.params.bssid, params->bssid, ETHER_ADDR_LEN);
join_params_size = sizeof(join_params.ssid) + WL_ASSOC_PARAMS_FIXED_SIZE;
} else {
//memset(&join_params.params.bssid, 0, ETHER_ADDR_LEN);
memcpy(&join_params.params.bssid, ðer_bcast, ETH_ALEN);
}
wl_update_prof(wl, dev, NULL, &join_params.params.bssid, WL_PROF_BSSID);
chan = params->channel;
if (chan) {
u32 target_channel;
wl->channel = ieee80211_frequency_to_channel(chan->center_freq);
if (params->channel_fixed) {
printk("wl_cfg80211_join_ibss: set channel %d in join params[len=%d]\n", wl->channel, join_params_size);
/* adding chanspec */
wl_ch_to_chanspec(wl->channel, &join_params, &join_params_size);
printk("wl_cfg80211_join_ibss: channel %d setted in join params[len=%d]\n", wl->channel, join_params_size);
}
/* set channel for starter */
target_channel = htod32(wl->channel);
err = wldev_ioctl(dev, WLC_SET_CHANNEL, &target_channel, sizeof(target_channel), true);
if (unlikely(err)) {
WL_ERR(("WLC_SET_CHANNEL failed (%d)\n", err));
goto done;
}
} else {
printk("wl_cfg80211_join_ibss: with zero wl->channel\n");
wl->channel = 0;
}
printk("wl_cfg80211_join_ibss: before wldev_ioctl\n");
// err = wldev_ioctl(dev, WLC_SET_SSID, &join_params, sizeof(join_params), false);
err = wldev_ioctl(dev, WLC_SET_SSID, &join_params, join_params_size, true);
if (unlikely(err)) {
WL_ERR(("Error (%d)\n", err));
printk("wl_cfg80211_join_ibss:: Error (%d)\n", err);
return err;
}
wl_set_drv_status(wl, CONNECTING, dev);
done:
return err;
}
修改__wl_cfg80211_scan以设置BCM4330在IBSS模式下也能正常扫描出结果。
In __wl_cfg80211_scan(…) @ wl_cfg80211.c
add escan_req = false initialization.
after
iscan_req = false;
modify Legacy scan中if (!wl->p2p_supported || !p2p_scan(wl))
to
if ((!wl->p2p_supported || !p2p_scan(wl)) && !wl_is_ibssmode(wl, ndev))
modify else if(escan_req)块中if (wl->p2p_supported)
to
if (wl->p2p_supported && !wl_is_ibssmode(wl, ndev))
modify direct scan中sr->ssid.SSID_len =
min_t(u8, sizeof(sr->ssid.SSID), ssids->ssid_len);
to
if(ssids)
sr->ssid.SSID_len =
min_t(u8, sizeof(sr->ssid.SSID), ssids->ssid_len);
else
sr->ssid.SSID_len = 0;
增加函数wl_inform_ibss @ wl_cfg80211.c
static s32
wl_inform_ibss(struct wl_priv *wl, struct net_device *dev, const u8 *bssid)
{
struct wiphy *wiphy = wl_to_wiphy(wl);
struct ieee80211_channel *notify_channel;
struct wl_bss_info *bi = NULL;
struct ieee80211_supported_band *band;
u8 *buf = NULL;
s32 err = 0;
u16 channel;
u32 freq;
u64 notify_timestamp;
u16 notify_capability;
u16 notify_interval;
u8 *notify_ie;
size_t notify_ielen;
s32 notify_signal;
printk("Enter wl_inform_ibss\n");
buf = kzalloc(WL_BSS_INFO_MAX, GFP_KERNEL);
if (buf == NULL) {
WL_ERR(("kzalloc() failed\n"));
err = -ENOMEM;
goto CleanUp;
}
*(u32 *)buf = htod32(WL_BSS_INFO_MAX);
err = wldev_ioctl(dev, WLC_GET_BSS_INFO, buf, WL_BSS_INFO_MAX, false);
if (unlikely(err)) {
WL_ERR(("WLC_GET_BSS_INFO failed: %d\n", err));
goto CleanUp;
}
bi = (wl_bss_info_t *)(buf + 4);
channel = bi->ctl_ch ? bi->ctl_ch :
CHSPEC_CHANNEL(le16_to_cpu(bi->chanspec));
if (channel <= CH_MAX_2G_CHANNEL)
band = wiphy->bands[IEEE80211_BAND_2GHZ];
else
band = wiphy->bands[IEEE80211_BAND_5GHZ];
freq = ieee80211_channel_to_frequency(channel, band->band);
notify_channel = ieee80211_get_channel(wiphy, freq);
notify_timestamp = jiffies_to_msecs(jiffies)*1000; /* uSec */
notify_capability = le16_to_cpu(bi->capability);
notify_interval = le16_to_cpu(bi->beacon_period);
notify_ie = (u8 *)bi + le16_to_cpu(bi->ie_offset);
notify_ielen = le16_to_cpu(bi->ie_length);
notify_signal = (s16)le16_to_cpu(bi->RSSI) * 100;
WL_DBG(("channel: %d(%d)\n", channel, freq));
WL_DBG(("capability: %X\n", notify_capability));
WL_DBG(("beacon interval: %d\n", notify_interval));
WL_DBG(("signal: %d\n", notify_signal));
WL_DBG(("notify_timestamp: %#018llx\n", notify_timestamp));
cfg80211_inform_bss(wiphy, notify_channel, bssid,
notify_timestamp, notify_capability, notify_interval,
notify_ie, notify_ielen, notify_signal, GFP_KERNEL);
CleanUp:
kfree(buf);
printk("Exit wl_inform_ibss\n");
return err;
}
增加两个函数wl_update_ibss_info和wl_ibss_joined_done
static s32 wl_update_ibss_info(struct wl_priv *wl, struct net_device *ndev)
{
struct cfg80211_bss *bss;
struct wl_bss_info *bi;
struct wlc_ssid *ssid;
struct bcm_tlv *tim;
s32 beacon_interval;
s32 dtim_period;
size_t ie_len;
u8 *ie;
u8 *curbssid;
s32 err = 0;
struct wiphy *wiphy;