一个简单的wifi热点启动流程追踪


最近在调试wifi的热点相关的东西,做下笔记。代码根据log进行调用追踪。
之前说过,我在关闭CONFIG_ACS的开关后,可以实现热点的打开。但我尝试去打开ACS的逻辑开关过后,发现了新的问题,为了方便自己记录流程,所以做了这个笔记。

一、ACS初始化函数

log

2-23 09:29:48.979  2251  2251 I hostapd : ACS: Automatic channel selection started, this may take a bit start !!!!
02-23 09:29:48.979  2251  2251 E hostapd :acs_request_scan funcation start !!! 
02-23 09:29:48.979  2251  2251 E hostapd : ACS: Scanning 1 / 5
02-23 09:29:48.979  2251  2251 E hostapd : hostapd_driver_scan 111
02-23 09:29:50.708  2251  2251 E hostapd : acs_request_scan Failed to request initial scan
02-23 09:29:50.708  2251  2251 I hostapd : wlan0: IEEE 802.11 Configured channel (0) or frequency (0) not found from the channel list of the current mode (1) IEEE 802.11g
02-23 09:29:50.708  2251  2251 W hostapd : wlan0: IEEE 802.11 Configured channel (0) or frequency (0) not found from the channel list of the current mode (1) IEEE 802.11g
02-23 09:29:50.709  2251  2251 I hostapd : wlan0: IEEE 802.11 Hardware does not support configured channel
02-23 09:29:50.709  2251  2251 W hostapd : wlan0: IEEE 802.11 Hardware does not support configured channel
02-23 09:29:50.709  2251  2251 E hostapd : Could not select hw_mode and channel. (-3)
02-23 09:29:50.709  2251  2251 I hostapd : wlan0: interface state UNINITIALIZED->DISABLED
02-23 09:29:50.709  2251  2251 I hostapd : wlan0: AP-DISABLED 
02-23 09:29:50.709  2251  2251 E hostapd : wlan0: Unable to setup interface.
02-23 09:29:50.709  2251  2251 I hostapd : nl80211: deinit ifname=wlan0 disabled_11b_rates=0
external/wpa_supplicant_8/wpa_supplicant/src/ap/acs.c

/*首先进入初始化函数*/
enum hostapd_chan_status acs_init(struct hostapd_iface *iface)
{
    wpa_printf(MSG_INFO, "ACS: Automatic channel selection started, this may take a bit");

    if (iface->drv_flags & WPA_DRIVER_FLAGS_ACS_OFFLOAD) {
        wpa_printf(MSG_INFO, "ACS: Offloading to driver");
        if (hostapd_drv_do_acs(iface->bss[0]))
            return HOSTAPD_CHAN_INVALID;
        return HOSTAPD_CHAN_ACS;
    }

    if (!iface->current_mode &&
        iface->conf->hw_mode != HOSTAPD_MODE_IEEE80211ANY)
        return HOSTAPD_CHAN_INVALID;

    acs_cleanup(iface);//清除之前的数据防止干扰
	/*调用acs_request_scan函数进行扫描*/
    if (acs_request_scan(iface) < 0)
        return HOSTAPD_CHAN_INVALID;
	/*设置接口状态*/
    hostapd_set_state(iface, HAPD_IFACE_ACS);
    wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, ACS_EVENT_STARTED);
	/*让上层函数知道需要等到acs扫描流程*/
    return HOSTAPD_CHAN_ACS;
}

调用acs_request_scan函数进行扫描,也就是正真执行扫描的地方。

static int acs_request_scan(struct hostapd_iface *iface)
{
    struct wpa_driver_scan_params params;
    int i, *freq;
    int num_channels;
    struct hostapd_hw_modes *mode;
    /*创建存储channel信息用的变量*/
    os_memset(&params, 0, sizeof(params));
    
    num_channels = 0;
    for (i = 0; i < iface->num_hw_features; i++) {
        mode = &iface->hw_features[i];
        if (!hostapd_hw_skip_mode(iface, mode))
            num_channels += mode->num_channels;
    }
    
    params.freqs = os_calloc(num_channels + 1, sizeof(params.freqs[0]));
    if (params.freqs == NULL)
        return -1;

    freq = params.freqs;
    
    for (i = 0; i < iface->num_hw_features; i++) {
        mode = &iface->hw_features[i];
        if (!hostapd_hw_skip_mode(iface, mode))
            freq = acs_request_scan_add_freqs(iface, mode, freq);
    }
    
    *freq = 0;
    
    if (params.freqs == freq) {
        wpa_printf(MSG_ERROR, "ACS: No available channels found");
        os_free(params.freqs);
        return -1;
    }
    /*将scan函数赋值成acs_scan_complete,之后执行scan_cb的时候就会调acs_scan_complete*/
    iface->scan_cb = acs_scan_complete;
    /*这里输出当前执行到第几次acs扫描,将MSG_DEBUG,改为MSG_ERROR可看到扫描次数*/
    wpa_printf(MSG_DEBUG, "ACS: Scanning %d / %d",
           iface->acs_num_completed_scans + 1,
           iface->conf->acs_num_scans);
	/*进行单次扫描,调用这个函数,我的log在这里出错*/
    if (hostapd_driver_scan(iface->bss[0], &params) < 0) {
        wpa_printf(MSG_ERROR, "ACS: Failed to request initial scan");
        acs_cleanup(iface);//清除数据
        os_free(params.freqs);//释放什么
        return -1;
    }
    os_free(params.freqs);
    return 0;
}

然后会调用这个函数

external/wpa_supplicant_8/src/ap/ap_drv_ops.c

int hostapd_driver_scan(struct hostapd_data *hapd,
            struct wpa_driver_scan_params *params)
{
	/*如果scan2注册了,则调用该函数,返回对应的函数*/
    if (hapd->driver && hapd->driver->scan2)
        return hapd->driver->scan2(hapd->drv_priv, params);
    return -1;
}

后面又会调用到:至于为啥会跑到这里,不太清楚,但是log显示下一个函数就是这里出错的

static int setup_interface2(struct hostapd_iface *iface)
{
	iface->wait_channel_update = 0;
	if (hostapd_get_hw_features(iface)) {//获取硬件信息
		/* Not all drivers support this yet, so continue without hw
		 * feature data. */
	} else {//我的设备会走这个else分支
		int ret = hostapd_select_hw_mode(iface);//选择硬件模式,我的硬件模式有问题,导致了后面一系列问题。
		if (ret < 0) {//异常情况处理返回 -3 
			wpa_printf(MSG_ERROR, "Could not select hw_mode and "
				   "channel. (%d)", ret);
			goto fail;
		}
		if (ret == 1) {//正常情况之需要进行acs扫描流程
			wpa_printf(MSG_DEBUG, "Interface initialization will be completed in a callback (ACS)");
			return 0;
		}
		ret = hostapd_check_ht_capab(iface);//不需要acs扫描流程,已有选定的信道
		if (ret < 0)
			goto fail;
		if (ret == 1) {//等待acs扫描结束后,也会调到hostapd_setup_interface_complete结束函数
			wpa_printf(MSG_DEBUG, "Interface initialization will "
				   "be completed in a callback");
			return 0;
		}
		if (iface->conf->ieee80211h)
			wpa_printf(MSG_DEBUG, "DFS support is enabled");
	}
	return hostapd_setup_interface_complete(iface, 0);//初始化结束函数
fail:
	hostapd_set_state(iface, HAPD_IFACE_DISABLED);//异常处理
	wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, AP_EVENT_DISABLED);
	if (iface->interfaces && iface->interfaces->terminate_on_error)
		eloop_terminate();
	return -1;
}

下面其实就是这里出现错误

/external/wpa_supplicant_8/hostapd/src/ap/hw_features.c

static void hostapd_notify_bad_chans(struct hostapd_iface *iface)
{
	if (!iface->current_mode) {
		hostapd_logger(iface->bss[0], NULL, HOSTAPD_MODULE_IEEE80211,
			       HOSTAPD_LEVEL_WARNING,
			       "Hardware does not support configured mode");
		return;
	}
	hostapd_logger(iface->bss[0], NULL,
		       HOSTAPD_MODULE_IEEE80211,
		       HOSTAPD_LEVEL_WARNING,
		       "Configured channel (%d) or frequency (%d) not found from the channel list of the current mode (%d) %s",
		       iface->conf->channel,
		       iface->freq,
		       iface->current_mode->mode,
		       hostapd_hw_mode_txt(iface->current_mode->mode));
	hostapd_logger(iface->bss[0], NULL, HOSTAPD_MODULE_IEEE80211,
		       HOSTAPD_LEVEL_WARNING,
		       "Hardware does not support configured channel");//出现这个错误
}

同时在选择硬件模式的时候会调用 hostapd_select_hw_mode这个函数

int hostapd_select_hw_mode(struct hostapd_iface *iface)
{
	int i;
	if (iface->num_hw_features < 1)
		return -1;
	if ((iface->conf->hw_mode == HOSTAPD_MODE_IEEE80211G || iface->conf->ieee80211n || iface->conf->ieee80211ac) && iface->conf->channel == 14) {
		wpa_printf(MSG_INFO, "Disable OFDM/HT/VHT on channel 14");
		iface->conf->hw_mode = HOSTAPD_MODE_IEEE80211B;
		iface->conf->ieee80211n = 0;
		iface->conf->ieee80211ac = 0;
	}//异常处理
	iface->current_mode = NULL;//把值清为NULL
	for (i = 0; i < iface->num_hw_features; i++) {//遍历当前接口的hw_features
       /*其中iface的结构体定义如下,
           struct hostapd_iface {
               ... ...
               struct hostapd_hw_modes *hw_features;//接口支持的hw_modes的数组
               int num_hw_features;//接口支持的hw_modes的个数
               ... ...
           }
       */
		struct hostapd_hw_modes *mode = &iface->hw_features[i];
		if (mode->mode == iface->conf->hw_mode) {
                  //如果hostapd.conf中配的hw_mode与当前接口支持的模式匹配成功了,
                  //就将接口当前模式赋为这个值,跳出循环
			iface->current_mode = mode;
			break;
		}
	}
	if (iface->current_mode == NULL) {//如果没有匹配的上的模式,则报错,返回-2进行异常处理
		if (!(iface->drv_flags & WPA_DRIVER_FLAGS_ACS_OFFLOAD) ||
		    !(iface->drv_flags & WPA_DRIVER_FLAGS_SUPPORT_HW_MODE_ANY))
		{
			wpa_printf(MSG_ERROR,"Hardware does not support configured mode");
			hostapd_logger(iface->bss[0], NULL, HOSTAPD_MODULE_IEEE80211, HOSTAPD_LEVEL_WARNING,
                        "Hardware does not support configured mode (%d) (hw_mode in hostapd.conf)", (int) iface->conf->hw_mode);
			return -2;
		}
	}
	switch (hostapd_check_chans(iface)) {//调用hostapd_check_chans函数
         //会判断是否需要acs扫描选择信道。如果hostapd.conf中channel配置成0(不配置就是0),就需要经过acs扫描算法流程
         //若hostapd.conf中没配置channel,则说明已选定了信道,就判断该信道是否valid
	case HOSTAPD_CHAN_VALID: //没配置channel
		return 0;
	case HOSTAPD_CHAN_ACS: /* ACS will run and later complete */
		return 1;
	case HOSTAPD_CHAN_INVALID: //异常情况条件的处理
	default:
		hostapd_notify_bad_chans(iface);
		return -3;
	}
}

调用 hostapd_check_chans 函数

static enum hostapd_chan_status hostapd_check_chans(struct hostapd_iface *iface)
{
	if (iface->conf->channel) {//如果hostapd.conf配置了非零的channel值,即指定了AP所在的channel
		if (hostapd_is_usable_chans(iface))//调用hostapd_is_usable_chans函数判断下是否为可用信道
			return HOSTAPD_CHAN_VALID;
		else
			return HOSTAPD_CHAN_INVALID;
	}
	/*
	 * The user set channel=0 or channel=acs_survey
	 * which is used to trigger ACS.
	 */
	switch (acs_init(iface)) {//如果配置的channel值是0,则需要进行acs算法流程,故而要初始化acs
	case HOSTAPD_CHAN_ACS: //需要进行acs算法
		return HOSTAPD_CHAN_ACS;
	case HOSTAPD_CHAN_VALID: //若不需要acs,则出了异常情况,返回INVALID
	case HOSTAPD_CHAN_INVALID:
	default:
		return HOSTAPD_CHAN_INVALID;
	}
}

external的相关代码后面就没有再跟了,因为函数已经走向了错误的方向,所以这个此就到这里吧。

二、函数跳转驱动

log:

02-25 01:21:05.690  2164  2164 I hostapd : rfkill: Cannot open RFKILL control device
02-25 01:21:05.692  2164  2164 I hostapd : ACS: Automatic channel selection started, this may take a bit start !!!!
02-25 01:21:05.692  2164  2164 E hostapd : Enter acs_request_scan funcation start !!! 
02-25 01:21:05.692  2164  2164 E hostapd : ACS: Scanning 1 / 5
02-25 01:21:05.692  2164  2164 E hostapd : enter hostapd_driver_scan 111
02-25 01:21:05.693     0     0 E [dhd][wlan0] wl_run_escan: LEGACY_SCAN sync ID: 0, bssidx: 0
02-25 01:21:05.701     0     0 I         : [dhd] CFG80211-ERROR) wl_run_escan :  Escan set error (-4)
02-25 01:21:05.707     0     0 I         : [dhd] CFG80211-ERROR) wl_run_escan : scan error (-4)
02-25 01:21:05.713     0     0 I         : [dhd] CFG80211-ERROR) wl_cfg80211_scan : scan error (-11)
02-25 01:21:05.720     0     0 E [dhd][wlan0] wl_cfg80211_add_del_bss: wl bss 2 bssidx:0
02-25 01:21:05.730     0     0 E [dhd][wlan0] wl_run_escan: LEGACY_SCAN sync ID: 1, bssidx: 0
02-25 01:21:05.737     0     0 I         : [dhd] CFG80211-ERROR) wl_run_escan :  Escan set error (-4)
02-25 01:21:05.744     0     0 I         : [dhd] CFG80211-ERROR) wl_run_escan : scan error (-4)
02-25 01:21:05.750     0     0 I         : [dhd] CFG80211-ERROR) wl_cfg80211_scan : scan error (-11)
02-25 01:21:05.759  2164  2164 E hostapd : ACS: acs_request_scan Failed to request initial scan

从log可以看出,当调用函数到hostapd_driver_scan(单次扫描的时候)

int hostapd_driver_scan(struct hostapd_data *hapd,
			struct wpa_driver_scan_params *params)
{
	if (hapd->driver && hapd->driver->scan2) { 
        	wpa_printf(MSG_ERROR,"enter hostapd_driver_scan 111");
		return hapd->driver->scan2(hapd->drv_priv, params);
    }
    wpa_printf(MSG_ERROR,"enter hostapd_driver_scan 222");
	return -1;
}

添加打印后确定会从scan2这里调用驱动里面的函数

kernel_imx/drivers/net/wireless/bcmdhd/wl_cfgscan.c

static s32
wl_run_escan(struct bcm_cfg80211 *cfg, struct net_device *ndev,
	struct cfg80211_scan_request *request, uint16 action)
{
	s32 err = BCME_OK;
	u32 n_channels;
	u32 n_ssids;
	s32 params_size;
	wl_escan_params_t *eparams = NULL;
	wl_escan_params_v2_t *eparams_v2 = NULL;
	u8 *scan_params = NULL;
	u8 *params = NULL;
	u8 chan_buf[sizeof(u32)*(WL_NUMCHANNELS + 1)];
	u32 num_chans = 0;
	s32 channel;
	u32 n_valid_chan;
	s32 search_state = WL_P2P_DISC_ST_SCAN;
	u32 i, j, n_nodfs = 0;
	u16 *default_chan_list = NULL;
	wl_uint32_list_t *list;
	s32 bssidx = -1;
	struct net_device *dev = NULL;
	........
}

后面就是根据报错继续追函数的调用了。

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

永不秃头的程序员

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值