Patch android wifi to enable IBSS/WEP support

本文针对开发者,详细介绍了如何通过补丁修改Android系统,以支持IBSS(Adhoc)和WEP功能。内容包括修改wpa_supplicant、wpa_supplicant_ctrl_iface_set_network、wpa_scan_res_match等函数,以及对linux内核nl80211驱动和bcm4330驱动的相关修改,以实现WiFi芯片bcm4330在IBSS模式下的工作。
摘要由CSDN通过智能技术生成

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

  1. 修改Settings/wifi中的代码以显示[IBSS][WEP] ssid或没有名字的ssid.

UI显示SSID列表时,会获取从wpa_supplicant最近扫描到的APswpa_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;

               }

  1. 修改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 {

  1. linux内核nl80211驱动和bcm4330驱动

wpa_driver_nl80211_ibss发送NL80211_CMD_SET_INTERFACE NL80211_CMD_JOIN_IBSSlinux 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 Intervalstarter 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, &ether_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以设置BCM4330IBSS模式下也能正常扫描出结果。

In __wl_cfg80211_scan(…) @ wl_cfg80211.c

add escan_req = false initialization.

after

                iscan_req = false;

modify  Legacy scanif (!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 scansr->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_infowl_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;

 

   

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值