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
当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;
}
当第一次点击连接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 {
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;
wiphy = wl_to_wiphy(wl);
if (!wl_is_ibssmode(wl, ndev))
return err;
ssid = (struct wlc_ssid *)wl_read_prof(wl, ndev, WL_PROF_SSID);
curbssid = wl_read_prof(wl, ndev, WL_PROF_BSSID);
bss = cfg80211_get_bss(wiphy, NULL, curbssid,
ssid->SSID, ssid->SSID_len, WLAN_CAPABILITY_IBSS,
WLAN_CAPABILITY_IBSS);
mutex_lock(&wl->usr_sync);
if (!bss) {
WL_DBG(("Could not find the AP\n"));
*(u32 *) wl->extra_buf = htod32(WL_EXTRA_BUF_MAX);
err = wldev_ioctl(ndev, WLC_GET_BSS_INFO,
wl->extra_buf, WL_EXTRA_BUF_MAX, false);
if (unlikely(err)) {
WL_ERR(("Could not get bss info %d\n", err));
goto update_ibss_info_out;
}
bi = (struct wl_bss_info *)(wl->extra_buf + 4);
if (memcmp(bi->BSSID.octet, curbssid, ETHER_ADDR_LEN)) {
WL_ERR(("BSSID and curbssid mismatch\n"));
err = -EIO;
goto update_ibss_info_out;
}
err = wl_inform_single_bss(wl, bi);
if (unlikely(err))
goto update_ibss_info_out;
ie = ((u8 *)bi) + bi->ie_offset;
ie_len = bi->ie_length;
beacon_interval = cpu_to_le16(bi->beacon_period);
} else {
WL_DBG(("Found the AP in the list - BSSID %pM\n", bss->bssid));
ie = bss->information_elements;
ie_len = bss->len_information_elements;
beacon_interval = bss->beacon_interval;
cfg80211_put_bss(bss);
}
tim = bcm_parse_tlvs(ie, ie_len, WLAN_EID_TIM);
if (tim) {
dtim_period = tim->data[1];
} else {
/*
* active scan was done so we could not get dtim
* information out of probe response.
* so we speficially query dtim information.
*/
err = wldev_ioctl(ndev, WLC_GET_DTIMPRD,
&dtim_period, sizeof(dtim_period), false);
if (unlikely(err)) {
WL_ERR(("WLC_GET_DTIMPRD error (%d)\n", err));
goto update_ibss_info_out;
}
}
wl_update_prof(wl, ndev, NULL, &beacon_interval, WL_PROF_BEACONINT);
wl_update_prof(wl, ndev, NULL, &dtim_period, WL_PROF_DTIMPERIOD);
update_ibss_info_out:
mutex_unlock(&wl->usr_sync);
return err;
}
static s32
wl_ibss_joined_done(struct wl_priv *wl, struct net_device *ndev,
const wl_event_msg_t *e, void *data)
{
s32 err = 0;
WL_DBG(("%s enter\n", __FUNCTION__));
if (wl->scan_request) {
printk("Cancel ongoing scan in %s\n", __FUNCTION__);
wl_cfg80211_scan_abort(wl, ndev);
}
wl_get_assoc_ies(wl, ndev);
wl_update_ibss_info(wl, ndev);
wl_update_pmklist(ndev, wl->pmk_list, err);
cfg80211_ibss_joined(ndev, (s8 *)&e->addr, GFP_KERNEL);
return err;
}
当得到WLC_E_LINK成功和WLC_E_SET_SSID成功时,使用如下两种方式之一通知用户态。
第一种:
In wl_notify_connect_status(…)@ wl_cfg80211.c
} else {
WL_DBG(("wl_notify_connect_status : event %d status : %d \n",
ntoh32(e->event_type), ntoh32(e->status)));
if (wl_is_linkup(wl, e, ndev)) {
wl_link_up(wl);
act = true;
wl_update_prof(wl, ndev, e, &act, WL_PROF_ACT);
wl_update_prof(wl, ndev, NULL, (void *)&e->addr, WL_PROF_BSSID);
if (wl_is_ibssmode(wl, ndev)) {
printk("linkup in ibss mode, before to call cfg80211_ibss_joined\n");
wl_inform_ibss(wl, ndev, (s8 *)&e->addr);
cfg80211_ibss_joined(ndev, (s8 *)&e->addr, GFP_KERNEL);// =>EVENT_ASSOC
WL_DBG(("joined in IBSS network\n"));
} else {
…………………………….
}
if (wl_get_drv_status(wl, CONNECTING, ndev)) {
wl_bss_connect_done(wl, ndev, e, data, false);
}
} else {
printk("%s nothing\n", __FUNCTION__);
}
}
或者第二种:
} else {
WL_DBG(("wl_notify_connect_status : event %d status : %d \n",
ntoh32(e->event_type), ntoh32(e->status)));
if (wl_is_linkup(wl, e, ndev)) {
wl_link_up(wl);
act = true;
wl_update_prof(wl, ndev, e, &act, WL_PROF_ACT);
wl_update_prof(wl, ndev, NULL, (void *)&e->addr, WL_PROF_BSSID);
if (wl_is_ibssmode(wl, ndev)) {
char * addr_ptr = (char *)&e->addr;
printk("linkup in ibss mode, before to call cfg80211_ibss_joined\n");
wl_ibss_joined_done(wl, ndev, e, data);
wl_clr_drv_status(wl, CONNECTING, ndev); // IBSS模式下,CONNECTING和CONNECTED两个标志可以酌情不使用
wl_set_drv_status(wl, CONNECTED, ndev);
WL_DBG(("joined in IBSS network\n"));
} else {
…………………………….
}
if (wl_get_drv_status(wl, CONNECTING, ndev)) {
wl_bss_connect_done(wl, ndev, e, data, false);
}
} else {
printk("%s nothing\n", __FUNCTION__);
}
}
在wl_cfg80211_get_station中增加IBSS模式下的得到RSSI Signal的代码,显示信号强度。
CHECK_SYS_UP(wl);
if (wl_get_mode_by_netdev(wl, dev) == WL_MODE_AP) {
……
} else if (wl_get_mode_by_netdev(wl, dev) == WL_MODE_BSS) {
……
} else if (wl_get_mode_by_netdev(wl, dev) == WL_MODE_IBSS) {
u8 *curmacp = wl_read_prof(wl, dev, WL_PROF_BSSID);
printk("%s is called for IBSS mode!!!!!!!\n", __FUNCTION__);
if (!wl_get_drv_status(wl, CONNECTED, dev) || // IBSS模式下不使用CONNECTED标志时,可以不要此条件
(dhd_is_associated(dhd, NULL) == FALSE)) {
WL_ERR(("NOT assoc\n"));
err = -ENODEV;
goto get_station_err_ibss;
}
if (memcmp(mac, curmacp, ETHER_ADDR_LEN)) {
WL_ERR(("Wrong Mac address: "MACSTR" != "MACSTR"\n",
MAC2STR(mac), MAC2STR(curmacp)));
}
/* Report the current tx rate */
err = wldev_ioctl(dev, WLC_GET_RATE, &rate, sizeof(rate), false);
if (err) {
WL_ERR(("Could not get rate (%d)\n", err));
} else {
rate = dtoh32(rate);
sinfo->filled |= STATION_INFO_TX_BITRATE;
sinfo->txrate.legacy = rate * 5;
WL_DBG(("Rate %d Mbps\n", (rate / 2)));
}
memset(&scb_val, 0, sizeof(scb_val));
scb_val.val = 0;
err = wldev_ioctl(dev, WLC_GET_RSSI, &scb_val,
sizeof(scb_val_t), false);
if (err) {
WL_ERR(("Could not get rssi (%d)\n", err));
goto get_station_err_ibss;
}
rssi = dtoh32(scb_val.val);
sinfo->filled |= STATION_INFO_SIGNAL;
sinfo->signal = rssi;
WL_DBG(("RSSI %d dBm\n", rssi));
get_station_err_ibss:
if (err) {
/* Disconnect due to zero BSSID or error to get RSSI */
WL_ERR(("force cfg80211_disconnected\n"));
wl_clr_drv_status(wl, CONNECTED, dev); // IBSS模式下不使用CONNECTED标志时,可以酌情处理
cfg80211_disconnected(dev, 0, NULL, 0, GFP_KERNEL);
wl_link_down(wl);
}
}
return err;
}
Patch END.
Principle and Control Flow
Settings/Wifi UI part structure
WifiSettings是主对话框
167
168 @Override
169 public void onActivityCreated(Bundle savedInstanceState) {
170 // We don't call super.onActivityCreated() here, since it assumes we already set up
171 // Preference (probably in onCreate()), while WifiSettings exceptionally set it up in
172 // this method.
173
174 mWifiManager = (WifiManager) getSystemService(Context.WIFI_SERVICE);
175 mWifiManager.asyncConnect(getActivity(), new WifiServiceHandler());
176 if (savedInstanceState != null
177 && savedInstanceState.containsKey(SAVE_DIALOG_ACCESS_POINT_STATE)) {
178 mDlgEdit = savedInstanceState.getBoolean(SAVE_DIALOG_EDIT_MODE);
179 mAccessPointSavedState = savedInstanceState.getBundle(SAVE_DIALOG_ACCESS_POINT_STATE);
180 }
1101 public void asyncConnect(Context srcContext, Handler srcHandler) {
1102 mAsyncChannel.connect(srcContext, srcHandler, getMessenger());
1103 }
establish a half connect between WifiManager and WifiService.
1117 public void connectNetwork(WifiConfiguration config) {
1118 if (config == null) {
1119 return;
1120 }
1121 mAsyncChannel.sendMessage(CMD_CONNECT_NETWORK, config);
1122 }
ContextMenu是长按的三菜单Menu
@Override
public boolean onContextItemSelected(MenuItem item) {
if (mSelectedAccessPoint == null) {
return super.onContextItemSelected(item);
}
switch (item.getItemId()) {
case MENU_ID_CONNECT: {
if (mSelectedAccessPoint.networkId != INVALID_NETWORK_ID) {
if (!requireKeyStore(mSelectedAccessPoint.getConfig())) {
mWifiManager.connectNetwork(mSelectedAccessPoint.networkId);
}
} else if (mSelectedAccessPoint.security == AccessPoint.SECURITY_NONE) {
/** Bypass dialog for unsecured networks */
mSelectedAccessPoint.generateOpenNetworkConfig();
mWifiManager.connectNetwork(mSelectedAccessPoint.getConfig());
} else {
showConfigUi(mSelectedAccessPoint, true);
}
return true;
}
case MENU_ID_FORGET: {
mWifiManager.forgetNetwork(mSelectedAccessPoint.networkId);
return true;
}
case MENU_ID_MODIFY: {
showConfigUi(mSelectedAccessPoint, true);
return true;
}
}
return super.onContextItemSelected(item);
}
onPreferenceTreeClick是点击使能选项,使能Wifi。
WifiConfigController是MVC中的Controller
WifiDialog是单击的config对话框
In IWifiManager.aidl
32interface IWifiManager {};
In WifiService.java
public class WifiService extends IWifiManager.Stub {};
In WifiManager.java, NOT the intermediate file of IWifiManager.aidl
485 public WifiManager(IWifiManager service, Handler handler) {
486 mService = service;
487 mHandler = handler;
488 }
In ContextImpl.java
449 registerService(WIFI_SERVICE, new ServiceFetcher() {
450 public Object createService(ContextImpl ctx) {
451 IBinder b = ServiceManager.getService(WIFI_SERVICE);
452 IWifiManager service = IWifiManager.Stub.asInterface(b);
453 returnnew WifiManager(service, ctx.mMainThread.getHandler());
454 }});
In 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;
}
if (result.SSID == null || result.SSID.length() == 0 ) {
continue;
}
boolean found = false;
for (AccessPoint accessPoint : apMap.getAll(result.SSID)) {
if (accessPoint.update(result))
found = true;
}
if (!found) {
AccessPoint accessPoint = new AccessPoint(getActivity(), result);
accessPoints.add(accessPoint);
apMap.put(accessPoint.ssid, accessPoint);
}
}
}
private void updateAccessPoints() {
final int wifiState = mWifiManager.getWifiState();
switch (wifiState) {
case WifiManager.WIFI_STATE_ENABLED:
// AccessPoints are automatically sorted with TreeSet.
final Collection<AccessPoint> accessPoints = constructAccessPoints();
getPreferenceScreen().removeAll();
if (mInXlSetupWizard) {
((WifiSettingsForSetupWizardXL)getActivity()).onAccessPointsUpdated(
getPreferenceScreen(), accessPoints);
} else {
for (AccessPoint accessPoint : accessPoints) {
// When WAPI is not customized to be on all
// WAPI APs will be invisible
if (accessPoint.isVisible()) {
getPreferenceScreen().addPreference(accessPoint);
}
}
}
break;
case WifiManager.WIFI_STATE_ENABLING:
getPreferenceScreen().removeAll();
break;
case WifiManager.WIFI_STATE_DISABLING:
addMessagePreference(R.string.wifi_stopping);
break;
case WifiManager.WIFI_STATE_DISABLED:
addMessagePreference(R.string.wifi_empty_list_wifi_off);
break;
}
}
Scanner使用定时器,周期性向WifiService请求扫描,相关代码如下。
private class Scanner extends Handler {
private int mRetry = 0;
void resume() {
if (!hasMessages(0)) {
sendEmptyMessage(0);
}
}
void forceScan() {
removeMessages(0);
sendEmptyMessage(0);
}
void pause() {
mRetry = 0;
removeMessages(0);
}
@Override
public void handleMessage(Message message) {
if (mWifiManager.startScanActive()) {
mRetry = 0;
} else if (++mRetry >= 3) {
mRetry = 0;
Toast.makeText(getActivity(), R.string.wifi_fail_to_scan,
Toast.LENGTH_LONG).show();
return;
}
sendEmptyMessageDelayed(0, WIFI_RESCAN_INTERVAL_MS);
}
}
几个重要操作的控制流:
WifiSettings=>WifiManager::connect(…)
Scanner=>WifiManager:: startScanActive()
WifiEnabler=> WifiManager:: setWifienabled() |||| =>WifiService::setWifiEnabled()=>WifiStateMachine ::setWifiEnabled()
总之,发出SCAN或CONNECT的异步命令,等待事件通知做界面响应。主要就是不停的AP列表、信号强度刷新。其余命令是同步命令。
连接过程中显示的字符串
In /packages/apps/Settings/res/values/arrays.xml
223 <!-- Wi-Fi settings -->
224
225 <!-- Match this with the order of NetworkInfo.DetailedState. --> <skip />
226 <!-- Wi-Fi settings. The status messages when the network is unknown. -->
227 <string-array name="wifi_status">
228 <!-- Status message of Wi-Fi when it is idle. -->
229 <item></item>
230 <!-- Status message of Wi-Fi when it is scanning. -->
231 <item>Scanning\u2026</item>
232 <!-- Status message of Wi-Fi when it is connecting. -->
233 <item>Connecting\u2026</item>
234 <!-- Status message of Wi-Fi when it is authenticating. -->
235 <item>Authenticating\u2026</item>
236 <!-- Status message of Wi-Fi when it is obtaining IP address. -->
237 <item>Obtaining IP address\u2026</item>
238 <!-- Status message of Wi-Fi when it is connected. -->
239 <item>Connected</item>
240 <!-- Status message of Wi-Fi when it is suspended. -->
241 <item>Suspended</item>
242 <!-- Status message of Wi-Fi when it is disconnecting. -->
243 <item>Disconnecting\u2026</item>
244 <!-- Status message of Wi-Fi when it is disconnected. -->
245 <item>Disconnected</item>
246 <!-- Status message of Wi-Fi when it is a failure. -->
247 <item>Unsuccessful</item>
248 </string-array>
In WifiService.java
public class WifiService extends IWifiManager.Stub {};
WifiService线程的启动如下
In SystemServer.java
384 try {
385 Slog.i(TAG, "Wi-Fi P2pService");
386 wifiP2p = new WifiP2pService(context);
387 ServiceManager.addService(Context.WIFI_P2P_SERVICE, wifiP2p);
388 } catch (Throwable e) {
389 reportWtf("starting Wi-Fi P2pService", e);
390 }
391
392 try {
393 Slog.i(TAG, "Wi-Fi Service");
394 wifi = new WifiService(context);
395 ServiceManager.addService(Context.WIFI_SERVICE, wifi);
396 } catch (Throwable e) {
397 reportWtf("starting Wi-Fi Service", e);
398 }
WifiService的构造函数本质是启动了一个带有消息队列的线程做WifiService,两个Handler attach到该消息队列上。
428 HandlerThread wifiThread = new HandlerThread("WifiService");
429 wifiThread.start();
430 mAsyncServiceHandler = new AsyncServiceHandler(wifiThread.getLooper());
431 mWifiStateMachineHandler = new WifiStateMachineHandler(wifiThread.getLooper());
WifiSerivce作为一个service,WifiService.java在frameworks/base/services/java/com/android/server/目录下。但其实现使用的WifiStateMachine在frameworks/base/wifi/java/android/net/wifi/目录下。
WifiStateMachine状态机使用WifiNative wpa_ctrl和wpa_supplicant通讯, WifiMonitor监听WifiNative的异步消息。客户端传来的命令和WifiMonitor监听到的响应汇入WifiStateMachine的消息队列,驱动WifiStateMachine转动起来。
WifiStateMachine的方法中同步的带有’sync’字样,异步的是直接发送消息,通过WifiMonitor异步收集结果,WifiMonitor就是个ReceiverThread加消息协议转换。WifiMonitor在使用unix domain socket ctrl interface时是poll在socket上,有wpa_supplicant发回的数据时,recv。
In WifiStateMachine.java
680 public void setWifiEnabled(boolean enable) {
681 mLastEnableUid.set(Binder.getCallingUid());
682 if (enable) {
683 /* Argument is the state that is entered prior to load */
684 sendMessage(obtainMessage(CMD_LOAD_DRIVER, WIFI_STATE_ENABLING, 0));
685 sendMessage(CMD_START_SUPPLICANT);
686 } else {
687 sendMessage(CMD_STOP_SUPPLICANT);
688 /* Argument is the state that is entered upon success */
689 sendMessage(obtainMessage(CMD_UNLOAD_DRIVER, WIFI_STATE_DISABLED, 0));
690 }
691 }
In WifiStateMachine.java
553 public WifiStateMachine(Context context, String wlanInterface) {
649 if (DBG) setDbg(true);
650
651 //start the state machine
652 start();
653 }
2024 class InitialState extends State {
2025 @Override
2026 //TODO: could move logging into a common class
2027 public void enter() {
2028 if (DBG) log(getName() + "\n");
2029 // [31-8] Reserved for future use
2030 // [7 - 0] HSM state change
2031 // 50021 wifi_state_changed (custom|1|5)
2032 EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
2033
2034 if (WifiNative.isDriverLoaded()) {
2035 transitionTo(mDriverLoadedState);
2036 }
2037 else {
2038 transitionTo(mDriverUnloadedState);
2039 }
2040
2041 //Connect to WifiP2pService
2042 mWifiP2pManager = (WifiP2pManager) mContext.getSystemService(Context.WIFI_P2P_SERVICE);
2043 mWifiP2pChannel.connect(mContext, getHandler(), mWifiP2pManager.getMessenger());
2044
2045 /* IPv6 is disabled at boot time and is controlled by framework
2046 * to be enabled only as long as we are connected to an access point
2047 *
2048 * This fixes issues, a few being:
2049 * - IPv6 addresses and routes stick around after disconnection
2050 * - When connected, the kernel is unaware and can fail to start IPv6 negotiation
2051 * - The kernel sometimes starts autoconfiguration when 802.1x is not complete
2052 */
2053 try {
2054 mNwService.disableIpv6(mInterfaceName);
2055 } catch (RemoteException re) {
2056 loge("Failed to disable IPv6: " + re);
2057 } catch (IllegalStateException e) {
2058 loge("Failed to disable IPv6: " + e);
2059 }
2060 }
2061 }
2276 class DriverUnloadedState extends State {
2277 @Override
2278 public void enter() {
2279 if (DBG) log(getName() + "\n");
2280 EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
2281 }
2282 @Override
2283 public boolean processMessage(Message message) {
2284 if (DBG) log(getName() + message.toString() + "\n");
2285 switch (message.what) {
2286 case CMD_LOAD_DRIVER:
2287 mWifiP2pChannel.sendMessage(WIFI_ENABLE_PENDING);
2288 transitionTo(mWaitForP2pDisableState);
2289 break;
2290 case WifiP2pService.P2P_ENABLE_PENDING:
2291 mReplyChannel.replyToMessage(message, P2P_ENABLE_PROCEED);
2292 break;
2293 default:
2294 return NOT_HANDLED;
2295 }
2296 EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
2297 return HANDLED;
2298 }
2299 }
WifiP2pService.java会P2p的各状态下对WIFI_ENABLE_PENDING进行处理,同时WifiStateMachine进入等待p2p结束的状态。
3542 class WaitForP2pDisableState extends State {
3543 private int mSavedArg;
3544 @Override
3545 public void enter() {
3546 if (DBG) log(getName() + "\n");
3547 EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
3548
3549 //Preserve the argument arg1 that has information used in DriverLoadingState
3550 mSavedArg = getCurrentMessage().arg1;
3551 }
3552 @Override
3553 public boolean processMessage(Message message) {
3554 if (DBG) log(getName() + message.toString() + "\n");
3555 switch(message.what) {
3556 case WifiP2pService.WIFI_ENABLE_PROCEED:
3557 //restore argument from original message (CMD_LOAD_DRIVER)
3558 message.arg1 = mSavedArg;
3559 transitionTo(mDriverLoadingState);
3560 break;
}
}
收到P2pManager传来的WIFI_ENABLE_PROCEED,转到DriverLoadingState,开始加载driver。
2063 class DriverLoadingState extends State {
2064 @Override
2065 public void enter() {
2066 if (DBG) log(getName() + "\n");
2067 EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
2068
2069 final Message message = new Message();
2070 message.copyFrom(getCurrentMessage());
2071 /* TODO: add a timeout to fail when driver load is hung.
2072 * Similarly for driver unload.
2073 */
2074 new Thread(new Runnable() {
2075 public void run() {
2076 mWakeLock.acquire();
2077 //enabling state
2078 switch(message.arg1) {
2079 case WIFI_STATE_ENABLING:
2080 setWifiState(WIFI_STATE_ENABLING);
2081 break;
2082 case WIFI_AP_STATE_ENABLING:
2083 setWifiApState(WIFI_AP_STATE_ENABLING);
2084 break;
2085 }
2086
2087 if(WifiNative.loadDriver()) {
2088 if (DBG) log("Driver load successful");
2089 sendMessage(CMD_LOAD_DRIVER_SUCCESS);
2090 } else {
2091 loge("Failed to load driver!");
2092 switch(message.arg1) {
2093 case WIFI_STATE_ENABLING:
2094 setWifiState(WIFI_STATE_UNKNOWN);
2095 break;
2096 case WIFI_AP_STATE_ENABLING:
2097 setWifiApState(WIFI_AP_STATE_FAILED);
2098 break;
2099 }
2100 sendMessage(CMD_LOAD_DRIVER_FAILURE);
2101 }
2102 mWakeLock.release();
2103 }
2104 }).start();
2105 }
2106
2107 @Override
2108 public boolean processMessage(Message message) {
2109 if (DBG) log(getName() + message.toString() + "\n");
2110 switch (message.what) {
2111 case CMD_LOAD_DRIVER_SUCCESS:
2112 transitionTo(mDriverLoadedState);
2113 break;
2114 case CMD_LOAD_DRIVER_FAILURE:
2115 transitionTo(mDriverFailedState);
2116 break;
2117 case CMD_LOAD_DRIVER:
2118 case CMD_UNLOAD_DRIVER:
2119 case CMD_START_SUPPLICANT:
2120 case CMD_STOP_SUPPLICANT:
2121 case CMD_START_AP:
2122 case CMD_STOP_AP:
2123 case CMD_START_DRIVER:
2124 case CMD_STOP_DRIVER:
2125 case CMD_SET_SCAN_MODE:
2126 case CMD_SET_SCAN_TYPE:
2127 case CMD_SET_HIGH_PERF_MODE:
2128 case CMD_SET_COUNTRY_CODE:
2129 case CMD_SET_FREQUENCY_BAND:
2130 case CMD_START_PACKET_FILTERING:
2131 case CMD_STOP_PACKET_FILTERING:
2132 deferMessage(message);
2133 break;
2134 default:
2135 return NOT_HANDLED;
2136 }
2137 EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
2138 return HANDLED;
2139 }
2140 }
加载驱动成功会进入DriverLoadedState状态,在该状态下继续下一条加载wifi soc固件和启动wpa_supplicant的处理。
2142 class DriverLoadedState extends State {
2143 @Override
2144 public void enter() {
2145 if (DBG) log(getName() + "\n");
2146 EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
2147 }
2148 @Override
2149 public boolean processMessage(Message message) {
2150 if (DBG) log(getName() + message.toString() + "\n");
2151 switch(message.what) {
2152 case CMD_UNLOAD_DRIVER:
2153 transitionTo(mDriverUnloadingState);
2154 break;
2155 case CMD_START_SUPPLICANT:
2156 try {
2157 mNwService.wifiFirmwareReload(mInterfaceName, "STA");
2158 } catch (Exception e) {
2159 loge("Failed to reload STA firmware " + e);
2160 // continue
2161 }
2162 try {
2163 //A runtime crash can leave the interface up and
2164 //this affects connectivity when supplicant starts up.
2165 //Ensure interface is down before a supplicant start.
2166 mNwService.setInterfaceDown(mInterfaceName);
2167 //Set privacy extensions
2168 mNwService.setInterfaceIpv6PrivacyExtensions(mInterfaceName, true);
2169 } catch (RemoteException re) {
2170 loge("Unable to change interface settings: " + re);
2171 } catch (IllegalStateException ie) {
2172 loge("Unable to change interface settings: " + ie);
2173 }
2174
2175 if(WifiNative.startSupplicant()) {
2176 if (DBG) log("Supplicant start successful");
2177 mWifiMonitor.startMonitoring();
2178 transitionTo(mSupplicantStartingState);
2179 } else {
2180 loge("Failed to start supplicant!");
2181 sendMessage(obtainMessage(CMD_UNLOAD_DRIVER, WIFI_STATE_UNKNOWN, 0));
2182 }
2183 break;
2184 case CMD_START_AP:
2185 transitionTo(mSoftApStartingState);
2186 break;
2187 default:
2188 return NOT_HANDLED;
2189 }
2190 EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
2191 return HANDLED;
2192 }
2193 }
2315 class SupplicantStartingState extends State {
2316 @Override
2317 public void enter() {
2318 if (DBG) log(getName() + "\n");
2319 EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
2320 }
2321 @Override
2322 public boolean processMessage(Message message) {
2323 if (DBG) log(getName() + message.toString() + "\n");
2324 switch(message.what) {
2325 case WifiMonitor.SUP_CONNECTION_EVENT:
2326 if (DBG) log("Supplicant connection established");
2327 WifiNative.setP2pDisable(1);
2328 setWifiState(WIFI_STATE_ENABLED);
2329 mSupplicantRestartCount = 0;
2330 /* Reset the supplicant state to indicate the supplicant
2331 * state is not known at this time */
2332 mSupplicantStateTracker.sendMessage(CMD_RESET_SUPPLICANT_STATE);
2333 mWpsStateMachine.sendMessage(CMD_RESET_WPS_STATE);
2334 /* Initialize data structures */
2335 mLastBssid = null;
2336 mLastNetworkId = WifiConfiguration.INVALID_NETWORK_ID;
2337 mLastSignalLevel = -1;
2338
2339 mWifiInfo.setMacAddress(WifiNative.getMacAddressCommand());
2340
2341 WifiConfigStore.initialize(mContext);
2342
2343 sendSupplicantConnectionChangedBroadcast(true);
2344 transitionTo(mDriverStartedState);
2345 break;
2346 case WifiMonitor.SUP_DISCONNECTION_EVENT:
2347 if (++mSupplicantRestartCount <= SUPPLICANT_RESTART_TRIES) {
2348 loge("Failed to setup control channel, restart supplicant");
2349 WifiNative.killSupplicant();
2350 transitionTo(mDriverLoadedState);
2351 sendMessageDelayed(CMD_START_SUPPLICANT, SUPPLICANT_RESTART_INTERVAL_MSECS);
2352 } else {
2353 loge("Failed " + mSupplicantRestartCount +
2354 " times to start supplicant, unload driver");
2355 mSupplicantRestartCount = 0;
2356 transitionTo(mDriverLoadedState);
2357 sendMessage(obtainMessage(CMD_UNLOAD_DRIVER, WIFI_STATE_UNKNOWN, 0));
2358 }
2359 break;
2360 case CMD_LOAD_DRIVER:
2361 case CMD_UNLOAD_DRIVER:
2362 case CMD_START_SUPPLICANT:
2363 case CMD_STOP_SUPPLICANT:
2364 case CMD_START_AP:
2365 case CMD_STOP_AP:
2366 case CMD_START_DRIVER:
2367 case CMD_STOP_DRIVER:
2368 case CMD_SET_SCAN_MODE:
2369 case CMD_SET_SCAN_TYPE:
2370 case CMD_SET_HIGH_PERF_MODE:
2371 case CMD_SET_COUNTRY_CODE:
2372 case CMD_SET_FREQUENCY_BAND:
2373 case CMD_START_PACKET_FILTERING:
2374 case CMD_STOP_PACKET_FILTERING:
2375 deferMessage(message);
2376 break;
2377 default:
2378 return NOT_HANDLED;
2379 }
2380 EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
2381 return HANDLED;
2382 }
2383 }
2384
2385 class SupplicantStartedState extends State {
2386 @Override
2387 public void enter() {
2388 if (DBG) log(getName() + "\n");
2389 EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
2390 /* Initialize for connect mode operation at start */
2391 mIsScanMode = false;
2392 /* Wifi is available as long as we have a connection to supplicant */
2393 mNetworkInfo.setIsAvailable(true);
2394 /* Set scan interval */
2395 long supplicantScanIntervalMs = Settings.Secure.getLong(mContext.getContentResolver(),
2396 Settings.Secure.WIFI_SUPPLICANT_SCAN_INTERVAL_MS,
2397 mDefaultSupplicantScanIntervalMs);
2398 WifiNative.setScanIntervalCommand((int)supplicantScanIntervalMs / 1000);
2399 }
2400 @Override
2401 public boolean processMessage(Message message) {
2402 if (DBG) log(getName() + message.toString() + "\n");
2403 WifiConfiguration config;
2404 boolean eventLoggingEnabled = true;
2405 switch(message.what) {
2406 case CMD_STOP_SUPPLICANT: /* Supplicant stopped by user */
2407 transitionTo(mSupplicantStoppingState);
2408 break;
2409 case WifiMonitor.SUP_DISCONNECTION_EVENT: /* Supplicant connection lost */
2410 loge("Connection lost, restart supplicant");
2411 WifiNative.killSupplicant();
2412 WifiNative.closeSupplicantConnection();
2413 mNetworkInfo.setIsAvailable(false);
2414 handleNetworkDisconnect();
2415 sendSupplicantConnectionChangedBroadcast(false);
2416 mSupplicantStateTracker.sendMessage(CMD_RESET_SUPPLICANT_STATE);
2417 mWpsStateMachine.sendMessage(CMD_RESET_WPS_STATE);
2418 transitionTo(mDriverLoadedState);
2419 sendMessageDelayed(CMD_START_SUPPLICANT, SUPPLICANT_RESTART_INTERVAL_MSECS);
2420 break;
2421 case WifiMonitor.SCAN_RESULTS_EVENT:
2422 eventLoggingEnabled = false;
2423 setScanResults(WifiNative.scanResultsCommand());
2424 sendScanResultsAvailableBroadcast();
2425 mScanResultIsPending = false;
2426 break;
2427 case CMD_PING_SUPPLICANT:
2428 boolean ok = WifiNative.pingCommand();
2429 mReplyChannel.replyToMessage(message, message.what, ok ? SUCCESS : FAILURE);
2430 break;
2431 case CMD_ADD_OR_UPDATE_NETWORK:
2432 config = (WifiConfiguration) message.obj;
2433 mReplyChannel.replyToMessage(message, CMD_ADD_OR_UPDATE_NETWORK,
2434 WifiConfigStore.addOrUpdateNetwork(config));
2435 break;
2436 case CMD_REMOVE_NETWORK:
2437 ok = WifiConfigStore.removeNetwork(message.arg1);
2438 mReplyChannel.replyToMessage(message, message.what, ok ? SUCCESS : FAILURE);
2439 break;
2440 case CMD_ENABLE_NETWORK:
2441 ok = WifiConfigStore.enableNetwork(message.arg1, message.arg2 == 1);
2442 mReplyChannel.replyToMessage(message, message.what, ok ? SUCCESS : FAILURE);
2443 break;
2444 case CMD_ENABLE_ALL_NETWORKS:
2445 long time = android.os.SystemClock.elapsedRealtime();
2446 if (time - mLastEnableAllNetworksTime > MIN_INTERVAL_ENABLE_ALL_NETWORKS_MS) {
2447 WifiConfigStore.enableAllNetworks();
2448 mLastEnableAllNetworksTime = time;
2449 }
2450 break;
2451 case CMD_DISABLE_NETWORK:
2452 ok = WifiConfigStore.disableNetwork(message.arg1, message.arg2);
2453 mReplyChannel.replyToMessage(message, message.what, ok ? SUCCESS : FAILURE);
2454 break;
2455 case CMD_BLACKLIST_NETWORK:
2456 WifiNative.addToBlacklistCommand((String)message.obj);
2457 break;
2458 case CMD_CLEAR_BLACKLIST:
2459 WifiNative.clearBlacklistCommand();
2460 break;
2461 case CMD_SAVE_CONFIG:
2462 ok = WifiConfigStore.saveConfig();
2463 mReplyChannel.replyToMessage(message, CMD_SAVE_CONFIG, ok ? SUCCESS : FAILURE);
2464
2465 // Inform the backup manager about a data change
2466 IBackupManager ibm = IBackupManager.Stub.asInterface(
2467 ServiceManager.getService(Context.BACKUP_SERVICE));
2468 if (ibm != null) {
2469 try {
2470 ibm.dataChanged("com.android.providers.settings");
2471 } catch (Exception e) {
2472 // Try again later
2473 }
2474 }
2475 break;
2476 /* Cannot start soft AP while in client mode */
2477 case CMD_START_AP:
2478 loge("Failed to start soft AP with a running supplicant");
2479 setWifiApState(WIFI_AP_STATE_FAILED);
2480 break;
2481 case CMD_SET_SCAN_MODE:
2482 mIsScanMode = (message.arg1 == SCAN_ONLY_MODE);
2483 break;
2484 case CMD_SAVE_NETWORK:
2485 config = (WifiConfiguration) message.obj;
2486 WifiConfigStore.saveNetwork(config);
2487 break;
2488 case CMD_FORGET_NETWORK:
2489 WifiConfigStore.forgetNetwork(message.arg1);
2490 break;
2491 default:
2492 return NOT_HANDLED;
2493 }
2494 if (eventLoggingEnabled) {
2495 EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
2496 }
2497 return HANDLED;
2498 }
2499
2500 @Override
2501 public void exit() {
2502 mNetworkInfo.setIsAvailable(false);
2503 }
2504 }
233 private class AsyncServiceHandler extends Handler {
234
235 AsyncServiceHandler(android.os.Looper looper) {
236 super(looper);
237 }
238
239 @Override
240 public void handleMessage(Message msg) {
241 switch (msg.what) {
242 case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED: {
243 if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL) {
244 Slog.d(TAG, "New client listening to asynchronous messages");
245 mClients.add((AsyncChannel) msg.obj);
246 } else {
247 Slog.e(TAG, "Client connection failure, error=" + msg.arg1);
248 }
249 break;
250 }
251 case AsyncChannel.CMD_CHANNEL_DISCONNECTED: {
252 if (msg.arg1 == AsyncChannel.STATUS_SEND_UNSUCCESSFUL) {
253 Slog.d(TAG, "Send failed, client connection lost");
254 } else {
255 Slog.d(TAG, "Client connection lost with reason: " + msg.arg1);
256 }
257 mClients.remove((AsyncChannel) msg.obj);
258 break;
259 }
260 case AsyncChannel.CMD_CHANNEL_FULL_CONNECTION: {
261 AsyncChannel ac = new AsyncChannel();
262 ac.connect(mContext, this, msg.replyTo);
263 break;
264 }
265 case WifiManager.CMD_ENABLE_TRAFFIC_STATS_POLL: {
266 mEnableTrafficStatsPoll = (msg.arg1 == 1);
267 mTrafficStatsPollToken++;
268 if (mEnableTrafficStatsPoll) {
269 notifyOnDataActivity();
270 sendMessageDelayed(Message.obtain(this, WifiManager.CMD_TRAFFIC_STATS_POLL,
271 mTrafficStatsPollToken, 0), POLL_TRAFFIC_STATS_INTERVAL_MSECS);
272 }
273 break;
274 }
275 case WifiManager.CMD_TRAFFIC_STATS_POLL: {
276 if (msg.arg1 == mTrafficStatsPollToken) {
277 notifyOnDataActivity();
278 sendMessageDelayed(Message.obtain(this, WifiManager.CMD_TRAFFIC_STATS_POLL,
279 mTrafficStatsPollToken, 0), POLL_TRAFFIC_STATS_INTERVAL_MSECS);
280 }
281 break;
282 }
283 case WifiManager.CMD_CONNECT_NETWORK: {
284 if (msg.obj != null) {
285 mWifiStateMachine.connectNetwork((WifiConfiguration)msg.obj);
286 } else {
287 mWifiStateMachine.connectNetwork(msg.arg1);
288 }
289 break;
290 }
291 case WifiManager.CMD_SAVE_NETWORK: {
292 mWifiStateMachine.saveNetwork((WifiConfiguration)msg.obj);
293 break;
294 }
295 case WifiManager.CMD_FORGET_NETWORK: {
296 mWifiStateMachine.forgetNetwork(msg.arg1);
297 break;
298 }
299 case WifiManager.CMD_START_WPS: {
300 //replyTo has the original source
301 mWifiStateMachine.startWps(msg.replyTo, (WpsInfo)msg.obj);
302 break;
303 }
304 case WifiManager.CMD_DISABLE_NETWORK: {
305 mWifiStateMachine.disableNetwork(msg.replyTo, msg.arg1, msg.arg2);
306 break;
307 }
308 default: {
309 Slog.d(TAG, "WifiServicehandler.handleMessage ignoring msg=" + msg);
310 break;
311 }
312 }
313 }
314 }
调用WifiStateMachine的connectNetwork方法。
935 public void connectNetwork(int netId) {
936 sendMessage(obtainMessage(CMD_CONNECT_NETWORK, netId, 0));
937 }
938
939 public void connectNetwork(WifiConfiguration wifiConfig) {
940 /* arg1 is used to indicate netId, force a netId value of
941 * WifiConfiguration.INVALID_NETWORK_ID when we are passing
942 * a configuration since the default value of 0 is a valid netId
943 */
944 sendMessage(obtainMessage(CMD_CONNECT_NETWORK, WifiConfiguration.INVALID_NETWORK_ID,
945 0, wifiConfig));
946 }
在ConnectedState时,新选择network,连接,并且在收到连接好前转到disconnectState
2969 case CMD_CONNECT_NETWORK:
2970 int netId = message.arg1;
2971 WifiConfiguration config = (WifiConfiguration) message.obj;
2972
2973 /* We connect to a specific network by issuing a select
2974 * to the WifiConfigStore. This enables the network,
2975 * while disabling all other networks in the supplicant.
2976 * Disabling a connected network will cause a disconnection
2977 * from the network. A reconnectCommand() will then initiate
2978 * a connection to the enabled network.
2979 */
2980 if (config != null) {
2981 netId = WifiConfigStore.selectNetwork(config);
2982 } else {
2983 WifiConfigStore.selectNetwork(netId);
2984 }
2985
2986 /* The state tracker handles enabling networks upon completion/failure */
2987 mSupplicantStateTracker.sendMessage(CMD_CONNECT_NETWORK);
2988
2989 WifiNative.reconnectCommand();
2990 mLastExplicitNetworkId = netId;
2991 mLastNetworkChoiceTime = SystemClock.elapsedRealtime();
2992 mNextWifiActionExplicit = true;
2993 if (DBG) log("Setting wifi connect explicit for netid " + netId);
2994 /* Expect a disconnection from the old connection */
2995 transitionTo(mDisconnectingState);
2996 break;
SupplicantStateTracker.java收到CMD_CONNECT_NETWORK消息后追踪状态。主要是在reconnectCommand中做的连接。
152
153 class DefaultState extends State {
154 @Override
155 public void enter() {
156 if (DBG) Log.d(TAG, getName() + "\n");
157 }
158 @Override
159 public boolean processMessage(Message message) {
160 if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
161 switch (message.what) {
162 case WifiMonitor.AUTHENTICATION_FAILURE_EVENT:
163 mAuthenticationFailuresCount++;
164 mAuthFailureInSupplicantBroadcast = true;
165 break;
166 case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT:
167 StateChangeResult stateChangeResult = (StateChangeResult) message.obj;
168 SupplicantState state = stateChangeResult.state;
169 sendSupplicantStateChangedBroadcast(state, mAuthFailureInSupplicantBroadcast);
170 mAuthFailureInSupplicantBroadcast = false;
171 transitionOnSupplicantStateChange(stateChangeResult);
172 break;
173 case WifiStateMachine.CMD_RESET_SUPPLICANT_STATE:
174 transitionTo(mUninitializedState);
175 break;
176 case WifiStateMachine.CMD_CONNECT_NETWORK:
177 mNetworksDisabledDuringConnect = true;
178 break;
179 default:
180 Log.e(TAG, "Ignoring " + message);
181 break;
182 }
183 return HANDLED;
184 }
185 }
WifiNative.java
104 public native static boolean reconnectCommand();
android_net_wifi_Wifi.cpp
603 { "reconnectCommand", "()Z", (void *)android_net_wifi_reconnectCommand },
WifiNative.java中使用reconnectCommand方法时没有检查返回值,所以消息估计是异步传回。
static jboolean doBooleanCommand(const char* expect, const char* fmt, ...)
static int doCommand(const char *cmd, char *replybuf, int replybuflen)
call int wifi_command(const char *command, char *reply, size_t *reply_len) @ wifi_bcm.c
wpa_supplicant的扫描结果中有IBSS WEP,在Java层被过滤掉。
android_net_wifi_Wifi.cpp
120static jboolean android_net_wifi_loadDriver(JNIEnv* env, jobject)
121{
122 return (jboolean)(::wifi_load_driver() == 0);
123}
wifi_bcm.c
wifi_bcm.c有设置KMGT update_ctrl_interface ,就是从config file里面找ctrl_interface=wlan0这项,生成unix domain socket的监听端口文件名。wlan0时,系统会生成/dev/socket/wpa_wlan0;是目录的时候,可能在该目录下生成一个什么名称的文件。
875int wifi_command(const char *command, char *reply, size_t *reply_len)
876{
877 return wifi_send_command(ctrl_conn, command, reply, reply_len);
878}
发送命令到wpa_supplicant的监听socket上,该socket的recv函数是wpa_supplicant_ctrl_iface_receive,在wpa_supplicant的初始化过程中注册
main() => wpa_supplicant_add_iface => wpa_supplicant_init_iface => wpa_supplicant_ctrl_iface_init => eloop_register_read_sock.
wpa_supplicant_ctrl_iface_receive => wpa_supplicant_ctrl_iface_process
3286 } else if (os_strcmp(buf, "RECONNECT") == 0) {
3287 if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED)
3288 reply_len = -1;
3289 else if (wpa_s->disconnected) {
3290 wpa_s->disconnected = 0;
3291 wpa_s->reassociate = 1;
3292 wpa_supplicant_req_scan(wpa_s, 0, 0);
3293 }
3521 } else if (os_strcmp(buf, "SCAN") == 0) {
3522 if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED)
3523 reply_len = -1;
3524 else {
3525 if (!wpa_s->scanning &&
3526 ((wpa_s->wpa_state <= WPA_SCANNING) ||
3527 (wpa_s->wpa_state == WPA_COMPLETED))) {
3528 wpa_s->scan_req = 2;
3529 wpa_supplicant_req_scan(wpa_s, 0, 0);
3530 } else {
3531 wpa_printf(MSG_DEBUG, "Ongoing scan action - "
3532 "reject new request");
3533 reply_len = os_snprintf(reply, reply_size,
3534 "FAIL-BUSY\n");
3535 }
3536 }
3537 } else if (os_strcmp(buf, "SCAN_RESULTS") == 0) {
3538 reply_len = wpa_supplicant_ctrl_iface_scan_results(
3539 wpa_s, reply, reply_size);
3540 } else if (os_strncmp(buf, "SELECT_NETWORK ", 15) == 0) {
3541 if (wpa_supplicant_ctrl_iface_select_network(wpa_s, buf + 15))
3542 reply_len = -1;
3543 } else if (os_strncmp(buf, "ENABLE_NETWORK ", 15) == 0) {
3544 if (wpa_supplicant_ctrl_iface_enable_network(wpa_s, buf + 15))
3545 reply_len = -1;
3546 } else if (os_strncmp(buf, "DISABLE_NETWORK ", 16) == 0) {
3547 if (wpa_supplicant_ctrl_iface_disable_network(wpa_s, buf + 16))
3548 reply_len = -1;
3549 } else if (os_strcmp(buf, "ADD_NETWORK") == 0) {
3550 reply_len = wpa_supplicant_ctrl_iface_add_network(
3551 wpa_s, reply, reply_size);
3552 } else if (os_strncmp(buf, "REMOVE_NETWORK ", 15) == 0) {
3553 if (wpa_supplicant_ctrl_iface_remove_network(wpa_s, buf + 15))
3554 reply_len = -1;
3555 } else if (os_strncmp(buf, "SET_NETWORK ", 12) == 0) {
3556 if (wpa_supplicant_ctrl_iface_set_network(wpa_s, buf + 12))
3557 reply_len = -1;
3558 } else if (os_strncmp(buf, "GET_NETWORK ", 12) == 0) {
3559 reply_len = wpa_supplicant_ctrl_iface_get_network(
3560 wpa_s, buf + 12, reply, reply_size);
3561#ifndef CONFIG_NO_CONFIG_WRITE
3562 } else if (os_strcmp(buf, "SAVE_CONFIG") == 0) {
3563 if (wpa_supplicant_ctrl_iface_save_config(wpa_s))
3564 reply_len = -1;
3565#endif /* CONFIG_NO_CONFIG_WRITE */
3566 } else if (os_strncmp(buf, "GET_CAPABILITY ", 15) == 0) {
3567 reply_len = wpa_supplicant_ctrl_iface_get_capability(
3568 wpa_s, buf + 15, reply, reply_size);
3569 } else if (os_strncmp(buf, "AP_SCAN ", 8) == 0) {
3570 if (wpa_supplicant_ctrl_iface_ap_scan(wpa_s, buf + 8))
3571 reply_len = -1;
3572 } else if (os_strncmp(buf, "SCAN_INTERVAL ", 14) == 0) {
hardware/libhardware_legacy/wifi/Android.mk
3LOCAL_CFLAGS += -DCONFIG_CTRL_IFACE_CLIENT_DIR=\"/data/misc/wifi/sockets\"
4LOCAL_CFLAGS += -DCONFIG_CTRL_IFACE_CLIENT_PREFIX=\"wpa_ctrl_\"
/data/misc/wifi/sockets是使用wpa_cli库接口建立unix domain socket时,本地文件名。这两个宏构成如/data/misc/wifi/sockets/ wpa_ctrl_pid-nn的文件名,就是unix domain socket的文件名。
目标文件名是/dev/socket/wpa_wlan0,是socket的另一端,这个是由wpa_supplicant打开的。参见init.Manufacture.rc。wpa_cli去连接这个服务端口。
使用单独的wpa_cli端时,如下使用
wpa_cli -p /dev/socket/ -i wpa_wlan0
单独的wpa_cli会新建两个unix domain socket的两个local文件名。
wpa_ctrl_11762-1
wpa_ctrl_11762-2
如果wpa_supplicant以logger输出时,wpa_cli会得到消息输出。
9738 log 0:00 /system/bin/logwrapper /system/bin/wpa_supplicant -iwlan0 -puse_p2p_group_interface=1 -Dnl80211 -iwlan0 -c/data/misc/wifi/wpa_supplicant.conf -ddd
9740 wifi 0:23 /system/bin/wpa_supplicant -iwlan0 -puse_p2p_group_interface=1 -Dnl80211 -iwlan0 -c/data/misc/wifi/wpa_supplicant.conf -ddd
wifi驱动可能是
#define WIFI_DRIVER_MODULE_PATH "/system/lib/modules/wlan.ko"
可能是
#WIFI_DRIVER_MODULE_PATH := "/system/etc/bcm4330/dhd.ko"
insmod(DRIVER_MODULE_PATH, DRIVER_MODULE_ARG)
也可能是builtIn的。in wifi_bcm.c
LOGI("Using BuildIn WiFi driver");
property_set(DRIVER_PROP_NAME, "ok");
加载wpa_supplicant
property_get("wifi.interface", iface, WIFI_TEST_INTERFACE);
property_get("persist.wpa_supplicant.debug", supp_debug, "false");
if (strcmp(supp_debug, "true") == 0) {
SLOGI("persist.wpa_supplicant.debug property true");
snprintf(daemon_cmd, PROPERTY_VALUE_MAX, "%s:-i%s -c%s -ddd", SUPPLICANT_NAME, iface, config_file);
} else {
SLOGI("persist.wpa_supplicant.debug property false");
snprintf(daemon_cmd, PROPERTY_VALUE_MAX, "%s:-i%s -c%s", SUPPLICANT_NAME, iface, config_file);
}
property_set("ctl.start", daemon_cmd);
由driver扫描完后发出 wpa_supplicant_event(drv->ctx, EVENT_SCAN_RESULTS, &event);
2155 case EVENT_SCAN_RESULTS:
2156 wpa_supplicant_event_scan_results(wpa_s, data);
2157 break;
wpa_supplicant_event_scan_results
_wpa_supplicant_event_scan_results
wpa_supplicant_pick_network
wpa_supplicant_select_bss
wpa_scan_res_match
现在的是match之后,下一个是什么过程。要找到:从Connect命令后找,启动搜索,搜索结果,configed匹配到?
连接前启动扫描,扫描结果匹配后,自然是连接。就从_wpa_supplicant_event_scan_results在pick netwoerk之后看。
if (selected) {
int skip;
skip = !wpa_supplicant_need_to_roam(wpa_s, selected, ssid, scan_res);
wpa_scan_results_free(scan_res);
if (skip)
return 0;
wpa_supplicant_connect(wpa_s, selected, ssid);
wpa_supplicant_rsn_preauth_scan_results(wpa_s);
}
wpa_supplicant_connect => wpa_supplicant_associate
@ssid: wpa_ssid structure for a configured network or %NULL for any network
wpa_supplicant_ctrl_iface_select_network => wpa_supplicant_select_network =>wpa_supplicant_req_scan(wpa_s, 0, 0);
wpa_supplicant_enable_network - Mark a configured network as enabled
@ssid: wpa_ssid structure for a configured network or %NULL
wpa_supplicant_ctrl_iface_enable_network => wpa_supplicant_enable_network =>wpa_supplicant_req_scan(wpa_s, 0, 0);
当扫描时wpa_supplicant_scan with ap_scan==0 => wpa_supplicant_gen_assoc_event
32static void wpa_supplicant_gen_assoc_event(struct wpa_supplicant *wpa_s)
33{
34 struct wpa_ssid *ssid;
35 union wpa_event_data data;
36
37 ssid = wpa_supplicant_get_ssid(wpa_s);
38 if (ssid == NULL)
39 return;
40
41 if (wpa_s->current_ssid == NULL) {
42 wpa_s->current_ssid = ssid;
43 if (wpa_s->current_ssid != NULL)
44 wpas_notify_network_changed(wpa_s);
45 }
46 wpa_supplicant_initiate_eapol(wpa_s);
47 wpa_dbg(wpa_s, MSG_DEBUG, "Already associated with a configured "
48 "network - generating associated event");
49 os_memset(&data, 0, sizeof(data));
50 wpa_supplicant_event(wpa_s, EVENT_ASSOC, &data);
51}
或者当连接bss后,
wpa_driver_nl80211_event_receive => process_event() => mlme_event_join_ibss() => wpa_supplicant_event(drv->ctx,EVENT_ASSOC, NULL);
在wpa_driver_nl80211_init_nl中,wpa_driver_nl80211_event_receive注册到netlink socket的读处理上。
eloop_register_read_sock(nl_socket_get_fd(drv->nl_handle_event),
wpa_driver_nl80211_event_receive, drv,
drv->nl_handle_event);
或者当INFRA时,
直接wpa_driver_nl80211_connect发送NL80211_CMD_CONNECT,会收到NL80211_CMD_CONNECT响应,用mlme_event_connect=>wpa_supplicant_event(drv->ctx, EVENT_ASSOC, &event);处理
好像是用来做AUTH+ASSOCIATE阶段的。
case EVENT_ASSOC: wpa_supplicant_event_assoc(wpa_s, data);
driver可以找到是kernel/drivers/net/wireless/bcmdhd/wl_cfg80211.c
按照driver的要求打包数据。
wpa_supplicant_associate是连接和验证的入口。
wpa_supplicant_associate
calls => wpa_drv_associate
calls => wpa_driver_nl80211_associate when drvier_nl80211 is used.
calls => wpa_driver_nl80211_ibss for IBSS mode.
wpa_driver_nl80211_ibss首先将驱动和固件设置到IBSS工作模式,然后发送JOIN_IBSS命令。
4709static int wpa_driver_nl80211_ibss(struct wpa_driver_nl80211_data *drv,
4710 struct wpa_driver_associate_params *params)
4711{
4712 struct nl_msg *msg;
4713 int ret = -1;
4714 int count = 0;
4715
4716 wpa_printf(MSG_DEBUG, "nl80211: Join IBSS (ifindex=%d)", drv->ifindex);
4717
4718 if (wpa_driver_nl80211_set_mode(&drv->first_bss, params->mode)) {
4719 wpa_printf(MSG_INFO, "nl80211: Failed to set interface into "
4720 "IBSS mode");
4721 return -1;
4722 }
4723
4724retry:
4725 msg = nlmsg_alloc();
4726 if (!msg)
4727 return -1;
4728
4729 genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0,
4730 NL80211_CMD_JOIN_IBSS, 0);
4731 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
4732
4733 if (params->ssid == NULL || params->ssid_len > sizeof(drv->ssid))
4734 goto nla_put_failure;
4735
4736 wpa_hexdump_ascii(MSG_DEBUG, " * SSID",
4737 params->ssid, params->ssid_len);
4738 NLA_PUT(msg, NL80211_ATTR_SSID, params->ssid_len,
4739 params->ssid);
4740 os_memcpy(drv->ssid, params->ssid, params->ssid_len);
4741 drv->ssid_len = params->ssid_len;
4742
4743 wpa_printf(MSG_DEBUG, " * freq=%d", params->freq);
4744 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, params->freq);
4745
4746 ret = nl80211_set_conn_keys(params, msg);
4747 if (ret)
4748 goto nla_put_failure;
4749
4750 if (params->wpa_ie) {
4751 wpa_hexdump(MSG_DEBUG,
4752 " * Extra IEs for Beacon/Probe Response frames",
4753 params->wpa_ie, params->wpa_ie_len);
4754 NLA_PUT(msg, NL80211_ATTR_IE, params->wpa_ie_len,
4755 params->wpa_ie);
4756 }
4757
4758 ret = send_and_recv_msgs(drv, msg, NULL, NULL);
4759 msg = NULL;
4760 if (ret) {
4761 wpa_printf(MSG_DEBUG, "nl80211: Join IBSS failed: ret=%d (%s)",
4762 ret, strerror(-ret));
4763 count++;
4764 if (ret == -EALREADY && count == 1) {
4765 wpa_printf(MSG_DEBUG, "nl80211: Retry IBSS join after "
4766 "forced leave");
4767 nl80211_leave_ibss(drv);
4768 nlmsg_free(msg);
4769 goto retry;
4770 }
4771
4772 goto nla_put_failure;
4773 }
4774 ret = 0;
4775 wpa_printf(MSG_DEBUG, "nl80211: Join IBSS request sent successfully");
4776
4777nla_put_failure:
4778 nlmsg_free(msg);
4779 return ret;
4780}
首先看设置网卡工作模式 INFRA还是ADHOC
5148static int nl80211_set_mode(struct wpa_driver_nl80211_data *drv,
5149 int ifindex, int mode)
5150{
5151 struct nl_msg *msg;
5152 int ret = -ENOBUFS;
5153
5154 msg = nlmsg_alloc();
5155 if (!msg)
5156 return -ENOMEM;
5157
5158 genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
5159 0,NL80211_CMD_SET_INTERFACE, 0);
5160 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ifindex);
5161 NLA_PUT_U32(msg, NL80211_ATTR_IFTYPE, mode);
5162
5163 ret = send_and_recv_msgs(drv, msg, NULL, NULL);
5164 if (!ret)
5165 return 0;
5166nla_put_failure:
5167 wpa_printf(MSG_DEBUG, "nl80211: Failed to set interface %d to mode %d:"
5168 " %d (%s)", ifindex, mode, ret, strerror(-ret));
5169 return ret;
5170}
NL80211_CMD_SET_INTERFACE command to kernel space driver =>
static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info)
=>
1586 if (change)
1587 err =cfg80211_change_iface(rdev, dev, ntype, flags, ¶ms);
cfg80211_change_iface instead calls =>
=> wl_cfg80211_change_virtual_iface
此处wl_cfg80211在设置到IBSS模式时没有执行,需要patch上WLC_SET_INFRA
err = wldev_ioctl(ndev, WLC_SET_INFRA, &infra, sizeof(infra), true);
另外地,wldev_ioctl(ndev, WLC_SET_INFRA, &infra, sizeof(infra), true)在wl_config_ifmode中也被调用,而wl_config_ifmode在wl_cfg80211_up(void *para)=>__wl_cfg80211_up中被调用。
wl_cfg80211_up只在dhd驱动的open函数dhd_open(struct net_device *net)中使用一次,用于网卡打开进行配置使用,所以iwconfig可以使能网卡IBSS模式,但是wpa_supplicant不能使能网卡IBSS模式的原因大概在此。
static s32 wl_config_ifmode(struct wl_priv *wl, struct net_device *ndev, s32 iftype)
{
s32 infra = 0;
s32 err = 0;
s32 mode = 0;
switch (iftype) {
case NL80211_IFTYPE_MONITOR:
case NL80211_IFTYPE_WDS:
WL_ERR(("type (%d) : currently we do not support this mode\n",
iftype));
err = -EINVAL;
return err;
case NL80211_IFTYPE_ADHOC:
mode = WL_MODE_IBSS;
break;
case NL80211_IFTYPE_STATION:
case NL80211_IFTYPE_P2P_CLIENT:
mode = WL_MODE_BSS;
infra = 1;
break;
case NL80211_IFTYPE_AP:
case NL80211_IFTYPE_P2P_GO:
mode = WL_MODE_AP;
infra = 1;
break;
default:
err = -EINVAL;
WL_ERR(("invalid type (%d)\n", iftype));
return err;
}
infra = htod32(infra);
err = wldev_ioctl(ndev, WLC_SET_INFRA, &infra, sizeof(infra), true);
if (unlikely(err)) {
WL_ERR(("WLC_SET_INFRA error (%d)\n", err));
return err;
}
wl_set_mode_by_netdev(wl, ndev, mode);
return 0;
}
再看第二个步骤发送JOIN_IBSS
join_ibss in driver_nl80211.c
wpa_driver_nl80211_ibss
genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0,
NL80211_CMD_JOIN_IBSS, 0);
NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
kernel/net/wireless/nl80211.c is one driver top file for JOIN_IBSS。
4330static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info)
4331{
4332 struct cfg80211_registered_device *rdev = info->user_ptr[0];
4333 struct net_device *dev = info->user_ptr[1];
4334 struct cfg80211_ibss_params ibss;
4335 struct wiphy *wiphy;
4336 struct cfg80211_cached_keys *connkeys = NULL;
4337 int err;
4338
4339 memset(&ibss, 0, sizeof(ibss));
4340
4341 if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE]))
4342 return -EINVAL;
4343
4344 if (!info->attrs[NL80211_ATTR_WIPHY_FREQ] ||
4345 !info->attrs[NL80211_ATTR_SSID] ||
4346 !nla_len(info->attrs[NL80211_ATTR_SSID]))
4347 return -EINVAL;
4348
4349 ibss.beacon_interval = 100;
4350
4351 if (info->attrs[NL80211_ATTR_BEACON_INTERVAL]) {
4352 ibss.beacon_interval =
4353 nla_get_u32(info->attrs[NL80211_ATTR_BEACON_INTERVAL]);
4354 if (ibss.beacon_interval < 1 || ibss.beacon_interval > 10000)
4355 return -EINVAL;
4356 }
4357
4358 if (!rdev->ops->join_ibss)
4359 return -EOPNOTSUPP;
4360
4361 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_ADHOC)
4362 return -EOPNOTSUPP; //这个东西并不影响IBSS逻辑
4363
4364 wiphy = &rdev->wiphy;
4365
4366 if (info->attrs[NL80211_ATTR_MAC])
4367 ibss.bssid = nla_data(info->attrs[NL80211_ATTR_MAC]);
4368 ibss.ssid = nla_data(info->attrs[NL80211_ATTR_SSID]);
4369 ibss.ssid_len = nla_len(info->attrs[NL80211_ATTR_SSID]);
4370
4371 if (info->attrs[NL80211_ATTR_IE]) {
4372 ibss.ie = nla_data(info->attrs[NL80211_ATTR_IE]);
4373 ibss.ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);
4374 }
4375
4376 ibss.channel = ieee80211_get_channel(wiphy,
4377 nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]));
4378 if (!ibss.channel ||
4379 ibss.channel->flags & IEEE80211_CHAN_NO_IBSS ||
4380 ibss.channel->flags & IEEE80211_CHAN_DISABLED)
4381 return -EINVAL;
4382
4383 ibss.channel_fixed = !!info->attrs[NL80211_ATTR_FREQ_FIXED];
4384 ibss.privacy = !!info->attrs[NL80211_ATTR_PRIVACY];
4385
4386 if (info->attrs[NL80211_ATTR_BSS_BASIC_RATES]) {
4387 u8 *rates =
4388 nla_data(info->attrs[NL80211_ATTR_BSS_BASIC_RATES]);
4389 int n_rates =
4390 nla_len(info->attrs[NL80211_ATTR_BSS_BASIC_RATES]);
4391 struct ieee80211_supported_band *sband =
4392 wiphy->bands[ibss.channel->band];
4393 int err;
4394 err = ieee80211_get_ratemask(sband, rates, n_rates,
4395 &ibss.basic_rates);
4396 if (err)
4397 return err;
4398 }
4399
4400 if (info->attrs[NL80211_ATTR_MCAST_RATE] &&
4401 !nl80211_parse_mcast_rate(rdev, ibss.mcast_rate,
4402 nla_get_u32(info->attrs[NL80211_ATTR_MCAST_RATE])))
4403 return -EINVAL;
4404
4405 if (ibss.privacy && info->attrs[NL80211_ATTR_KEYS]) {
4406 connkeys = nl80211_parse_connkeys(rdev,
4407 info->attrs[NL80211_ATTR_KEYS]);
4408 if (IS_ERR(connkeys))
4409 return PTR_ERR(connkeys);
4410 }
4411
4412 err = cfg80211_join_ibss(rdev, dev, &ibss, connkeys);
4413 if (err)
4414 kfree(connkeys);
4415 return err;
4416}
In wl_cfg80211.c
1758static s32
1759wl_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *dev,
1760 struct cfg80211_ibss_params *params)
1761{
1762 struct wl_priv *wl = wiphy_priv(wiphy);
1763 struct cfg80211_bss *bss;
1764 struct ieee80211_channel *chan;
1765 struct wl_join_params join_params;
1766 struct cfg80211_ssid ssid;
1767 s32 scan_retry = 0;
1768 s32 err = 0;
1769 bool rollback_lock = false;
1770
1771 WL_TRACE(("In\n"));
1772 CHECK_SYS_UP(wl);
1773 if (params->bssid) { // remove the ibss-blocking code
1774 WL_ERR(("Invalid bssid\n"));
1775 return -EOPNOTSUPP;
1776 }
1777 bss = cfg80211_get_ibss(wiphy, NULL, params->ssid, params->ssid_len);
1778 if (!bss) {
1779 memcpy(ssid.ssid, params->ssid, params->ssid_len);
1780 ssid.ssid_len = params->ssid_len;
1781 do {
1782 if (unlikely
1783 (__wl_cfg80211_scan(wiphy, dev, NULL, &ssid) ==
1784 -EBUSY)) {
1785 wl_delay(150);
1786 } else {
1787 break;
1788 }
1789 } while (++scan_retry < WL_SCAN_RETRY_MAX);
1790 /* to allow scan_inform to propagate to cfg80211 plane */
1791 if (rtnl_is_locked()) {
1792 rtnl_unlock();
1793 rollback_lock = true;
1794 }
1795
1796 /* wait 4 secons till scan done.... */
1797 schedule_timeout_interruptible(4 * HZ);
1798 if (rollback_lock)
1799 rtnl_lock();
1800 bss = cfg80211_get_ibss(wiphy, NULL,
1801 params->ssid, params->ssid_len);
1802 }
1803 if (bss) {
1804 wl->ibss_starter = false;
1805 WL_DBG(("Found IBSS\n"));
1806 } else {
1807 wl->ibss_starter = true;
1808 }
1809 chan = params->channel;
1810 if (chan)
1811 wl->channel = ieee80211_frequency_to_channel(chan->center_freq);
1812 /*
1813 * Join with specific BSSID and cached SSID
1814 * If SSID is zero join based on BSSID only
1815 */
1816 memset(&join_params, 0, sizeof(join_params));
1817 memcpy((void *)join_params.ssid.SSID, (void *)params->ssid,
1818 params->ssid_len);
1819 join_params.ssid.SSID_len = htod32(params->ssid_len);
1820 if (params->bssid)
1821 memcpy(&join_params.params.bssid, params->bssid,
1822 ETHER_ADDR_LEN);
1823 else
1824 memset(&join_params.params.bssid, 0, ETHER_ADDR_LEN);
1825
1826 err = wldev_ioctl(dev, WLC_SET_SSID, &join_params,
1827 sizeof(join_params), false);
1828 if (unlikely(err)) {
1829 WL_ERR(("Error (%d)\n", err));
1830 return err;
1831 }
1832 return err;
1833}
发送给dhd固件,err是0,表发送成功;
WLC_SET_SSID的结果以异步形式由固件发送回来。此时收到的WLC_E_SET_SSID的status是WLC_E_STATUS_NO_NETWORKS。
设置WLC_SET_INFRA后,修改join_ibss相关代码,可以收到WLC_E_SET_SSID with status WLC_E_STATUS_SUCCESSFUL,连接上IBSS。
驱动中在IBSS时收到的主要是WLC_E_LINK、WLC_E_JOIN和WLC_E_SET_SSID,会通过event_handler处理或通知wpa_supplicant.
wpa_driver_nl80211_event_rtm_newlink是在wpa_driver_nl80211_init中注册的
cfg->newlink_cb = wpa_driver_nl80211_event_rtm_newlink;
cfg->dellink_cb = wpa_driver_nl80211_event_rtm_dellink;
在driver_nl80211中,event上行路线。
netlink_receive处理link时间,调用wpa_driver_nl80211_event_rtm_newlink/dellink,调用wpa_driver_nl80211_event_link处理link层面事件,调用wpa_supplicant_event通知wpa_s。
mac layer me处理层面,mlme_event调用mlme_event_mgmt处理management帧事件,其余如data、control帧使用mlme_event_xxxx系列函数处理,然后调用wpa_supplicant_event通知wpa_s。
wl_notify_connect_status是在wl_init_event_handler中注册的。
5255static void wl_init_event_handler(struct wl_priv *wl)
5256{
5257 memset(wl->evt_handler, 0, sizeof(wl->evt_handler));
5258
5259 wl->evt_handler[WLC_E_SCAN_COMPLETE] = wl_notify_scan_status;
5260 wl->evt_handler[WLC_E_LINK] = wl_notify_connect_status;
5261 wl->evt_handler[WLC_E_DEAUTH_IND] = wl_notify_connect_status;
5262 wl->evt_handler[WLC_E_DEAUTH] = wl_notify_connect_status;
5263 wl->evt_handler[WLC_E_DISASSOC_IND] = wl_notify_connect_status;
5264 wl->evt_handler[WLC_E_ASSOC_IND] = wl_notify_connect_status;
5265 wl->evt_handler[WLC_E_REASSOC_IND] = wl_notify_connect_status;
5266 wl->evt_handler[WLC_E_ROAM] = wl_notify_roaming_status;
5267 wl->evt_handler[WLC_E_MIC_ERROR] = wl_notify_mic_status;
5268 wl->evt_handler[WLC_E_SET_SSID] = wl_notify_connect_status;
5269 wl->evt_handler[WLC_E_ACTION_FRAME_RX] = wl_notify_rx_mgmt_frame;
5270 wl->evt_handler[WLC_E_PROBREQ_MSG] = wl_notify_rx_mgmt_frame;
5271 wl->evt_handler[WLC_E_P2P_PROBREQ_MSG] = wl_notify_rx_mgmt_frame;
5272 wl->evt_handler[WLC_E_P2P_DISC_LISTEN_COMPLETE] = wl_cfgp2p_listen_complete;
5273 wl->evt_handler[WLC_E_ACTION_FRAME_COMPLETE] = wl_cfgp2p_action_tx_complete;
5274 wl->evt_handler[WLC_E_ACTION_FRAME_OFF_CHAN_COMPLETE] = wl_cfgp2p_action_tx_complete;
5275
5276}
scan results内核数据更新
wl_escan_handler中对扫描到的每个报告帧解析,添加到内核网卡数据结构bss_list中;
wl_escan_handler => wl_inform_bss => wl_inform_single_bss
连接成功AP后,也会更新该数据结构。
wl_bss_connect_done => wl_update_bss_info(not ibss) => wl_inform_single_bss
以后wl_inform_single_bss => cfg80211_inform_bss_frame => cfg80211_bss_update操作rb tree.
还有一条线 cfg80211_inform_bss => cfg80211_bss_update此条线能找到
wl_ibss_join_done => wl_update_ibss_info(ibss) => wl_inform_single_bss
dhd_rx_frame =>
dhd_wl_host_event =>
wl_host_event + wl_iw_event + wl_cfg80211_event
以下BoardConfig.mk中的好像没用到,没有定义WIFI_DRIVER_MODULE_PATH。
device/qcom/msm7627a/BoardConfig.mk
7ifeq ($(QC_PROP),true)
8 BOARD_USES_QCOM_HARDWARE := true
9 DYNAMIC_SHARED_LIBV8SO := true
10 BOARD_USES_ADRENO_200 := true
11 HAVE_ADRENO200_SOURCE := true
12 HAVE_ADRENO200_SC_SOURCE := true
13 HAVE_ADRENO200_FIRMWARE := true
14 BOARD_USES_QCNE := true
15 USE_OPENGL_RENDERER := true
16 BOARD_USE_QCOM_LLVM_CLANG_RS := true
17 ifneq ($(BUILD_TINY_ANDROID), true)
18 BOARD_VENDOR_QCOM_GPS_LOC_API_AMSS_VERSION := 50001
19 BOARD_VENDOR_QCOM_GPS_LOC_API_HARDWARE := default
20 BOARD_CAMERA_LIBRARIES := libcamera
21 BOARD_HAVE_BLUETOOTH := true
22 BOARD_HAVE_BLUETOOTH_BCM := true
23 BOARD_HAVE_QCOM_FM := false
24 #BOARD_USES_GENERIC_AUDIO := true
25 HOSTAPD_VERSION := VER_2_0_DEV_BCM
26 BOARD_HOSTAPD_DRIVER := NL80211
27 #BOARD_HAS_QCOM_WLAN := true
28 BOARD_WPA_SUPPLICANT_DRIVER := NL80211
29 WPA_SUPPLICANT_VERSION := VER_0_8_X_BCM
30
31 #WIFI_DRIVER_MODULE_PATH := "/system/etc/bcm4330/dhd.ko"
32 WIFI_DRIVER_MODULE_NAME := "dhd"
33 WIFI_DRIVER_MODULE_ARG := "firmware_path=/system/etc/bcm4330/sdio-g-pool-pno-pktfilter-keepalive-wapi-wme-p2p-idsup-idauth-sta-aoe.bin nvram_path=/system/etc/bcm4330/bcm94330wlsdgbphone.txt iface_name=wlan"
34 BOARD_HOTSPOT_SAR_BACKUP := true
35
36
37 #WIFI_SDIO_IF_DRIVER_MODULE_PATH := "/system/lib/modules/librasdioif.ko"
38 #WIFI_SDIO_IF_DRIVER_MODULE_NAME := "librasdioif"
39 #WIFI_SDIO_IF_DRIVER_MODULE_ARG := ""
40 WIFI_DRIVER_FW_PATH_PARAM := "/sys/module/bcmdhd/parameters/firmware_path"
41 WIFI_DRIVER_FW_PATH_STA := "/system/etc/bcm4330/sdio_g_pool_pno_pktfilter_keepalive_wapi_wme_idsup_idauth_sta_aoe.bin"
42 WIFI_DRIVER_FW_PATH_AP := "/system/etc/bcm4330/sdio_g_pool_pno_pktfilter_keepalive_wapi_wme_idsup_idauth_apsta_aoe.bin"
43 WIFI_DRIVER_FW_PATH_P2P := "/system/etc/bcm4330/sdio_g_pool_pno_pktfilter_keepalive_wapi_wme_idsup_idauth_p2p_aoe.bin"
44 BOARD_WPA_SUPPLICANT_PRIVATE_LIB := lib_driver_cmd_bcmdhd
45 BOARD_HOSTAPD_PRIVATE_LIB := lib_driver_cmd_bcmdhd
46 BOARD_WLAN_DEVICE := bcmdhd
47 endif # !BUILD_TINY_ANDROID
其余在init.rc中
setprop wifi.interface wlan0
# Connectivity: Enable Wifi EAP SIM
setprop ro.wifi.eap_sim_enabled true
chown wifi wifi /dev/wlandev
chmod 0660 /dev/wlandev
# Create the directories used by the Wireless subsystem
mkdir /data/misc/wifi 0770 wifi wifi
mkdir /data/misc/wifi/sockets 0770 wifi wifi
mkdir /data/misc/wifi/wpa_supplicant 0770 wifi wifi
mkdir /data/misc/dhcp 0770 dhcp dhcp
chown dhcp dhcp /data/misc/dhcp
service wpa_supplicant /system/bin/logwrapper /system/bin/wpa_supplicant -iwlan0 -puse_p2p_group_interface=1 -Dnl80211
class late_start
user root
group wifi inet
socket wpa_wlan0 dgram 660 wifi wifi
disabled
oneshot
service dhcpcd_wlan0 /system/bin/dhcpcd -ABKLG
class late_start
disabled
oneshot
service qcom-sh /system/bin/sh /init.qcom.sh
class late_start
user root
oneshot
service qcom-wifi /system/bin/sh /system/etc/init.qcom.wifi.sh
class late_start
oneshot
desnt works
/system/bin/logwrapper /system/bin/wpa_supplicant -iwlan0 -puse_p2p_group_interface=1 -Dnl80211 -C/data/system/wpa_supplicant -c/data/misc/wifi/wpa_supplicant.conf