文档章节

解决OpenWrt无线搜索错误bug

娱乐你我
 娱乐你我
发布于 2014/08/06 14:16
字数 2139
阅读 592
收藏 1

    TP-LINK 841n路由更新openwrt系统到Barrier Breaker r41988,“网络”-->“无线”-->“搜索”这个功能就不能用了,trunk版的也有这个问题。其实今年4、5月份玩HG255D路由就有这个问题,但当时的源码编译给TP-LINK 841n却没有这个问题。对这样的问题,确实比较头大,花了两天时间终于找到bug所在(只解决wr841n的,我的hg255d出问题了)。

    无线搜索bug截图(注意device参数radio0):

一番搜索后发现此页面的源码在系统的/usr/lib/lua/luci/view/admin_network/wifi_join.htm文件里,对应openwrt的源码路径为./feeds/luci/modules/admin-full/luasrc/view/admin_network/wifi_join.htm。终于要代码如下:

<%-

	local sys = require "luci.sys"
	local utl = require "luci.util"

	function guess_wifi_signal(info)
		local scale = (100 / (info.quality_max or 100) * (info.quality or 0))
		local icon

		if not info.bssid or info.bssid == "00:00:00:00:00:00" then
			icon = resource .. "/icons/signal-none.png"
		elseif scale < 15 then
			icon = resource .. "/icons/signal-0.png"
		elseif scale < 35 then
			icon = resource .. "/icons/signal-0-25.png"
		elseif scale < 55 then
			icon = resource .. "/icons/signal-25-50.png"
		elseif scale < 75 then
			icon = resource .. "/icons/signal-50-75.png"
		else
			icon = resource .. "/icons/signal-75-100.png"
		end

		return icon
	end

	function percent_wifi_signal(info)
		local qc = info.quality or 0
		local qm = info.quality_max or 0

		if info.bssid and qc > 0 and qm > 0 then
			return math.floor((100 / qm) * qc)
		else
			return 0
		end
	end

	function format_wifi_encryption(info)
		if info.wep == true then
			return "WEP"
		elseif info.wpa > 0 then
			return translatef("<abbr title='Pairwise: %s / Group: %s'>%s - %s</abbr>",
				table.concat(info.pair_ciphers, ", "),
				table.concat(info.group_ciphers, ", "),
				(info.wpa == 3) and translate("mixed WPA/WPA2")
					or (info.wpa == 2 and "WPA2" or "WPA"),
				table.concat(info.auth_suites, ", ")
			)
		elseif info.enabled then
			return "<em>%s</em>" % translate("unknown")
		else
			return "<em>%s</em>" % translate("open")
		end
	end

	local dev = luci.http.formvalue("device")
	local iw = luci.sys.wifi.getiwinfo(dev)

	if not iw then
		luci.http.redirect(luci.dispatcher.build_url("admin/network/wireless"))
		return
	end


	function scanlist(times)
		local i, k, v
		local l = { }
		local s = { }

		for i = 1, times do
			for k, v in ipairs(iw.scanlist or { }) do
				if not s[v.bssid] then
					l[#l+1] = v
					s[v.bssid] = true
				end
			end
		end

		return l
	end
-%>

<%+header%>

<h2><a id="content" name="content"><%:Join Network: Wireless Scan%></a></h2>

<div class="cbi-map">
	<fieldset class="cbi-section">
		<table class="cbi-section-table" style="empty-cells:hide">
			<!-- scan list -->
			<% for i, net in ipairs(scanlist(3)) do net.encryption = net.encryption or { } %>
			<tr class="cbi-section-table-row cbi-rowstyle-<%=1 + ((i-1) % 2)%>">
				<td class="cbi-value-field" style="width:16px; padding:3px">
					<abbr title="<%:Signal%>: <%=net.signal%> <%:dB%> / <%:Quality%>: <%=net.quality%>/<%=net.quality_max%>">
						<img src="<%=guess_wifi_signal(net)%>" /><br />
						<small><%=percent_wifi_signal(net)%>%</small>
					</abbr>
				</td>
				<td class="cbi-value-field" style="vertical-align:middle; text-align:left; padding:3px">
					<big><strong><%=net.ssid and utl.pcdata(net.ssid) or "<em>%s</em>" % translate("hidden")%></strong></big><br />
					<strong>Channel:</strong> <%=net.channel%> |
					<strong>Mode:</strong> <%=net.mode%> |
					<strong>BSSID:</strong> <%=net.bssid%> |
					<strong>Encryption:</strong> <%=format_wifi_encryption(net.encryption)%>
				</td>
				<td class="cbi-value-field" style="width:40px">
					<form action="<%=REQUEST_URI%>" method="post">
						<input type="hidden" name="device" value="<%=utl.pcdata(dev)%>" />
						<input type="hidden" name="join" value="<%=utl.pcdata(net.ssid)%>" />
						<input type="hidden" name="mode" value="<%=net.mode%>" />
						<input type="hidden" name="bssid" value="<%=net.bssid%>" />
						<input type="hidden" name="channel" value="<%=net.channel%>" />
						<input type="hidden" name="wep" value="<%=net.encryption.wep and 1 or 0%>" />
						<% if net.encryption.wpa then %>
						<input type="hidden" name="wpa_version" value="<%=net.encryption.wpa%>" />
						<% for _, v in ipairs(net.encryption.auth_suites) do %><input type="hidden" name="wpa_suites" value="<%=v%>" />
						<% end; for _, v in ipairs(net.encryption.group_ciphers) do %><input type="hidden" name="wpa_group" value="<%=v%>" />
						<% end; for _, v in ipairs(net.encryption.pair_ciphers) do %><input type="hidden" name="wpa_pairwise" value="<%=v%>" />
						<% end; end %>

						<input type="hidden" name="clbridge" value="<%=iw.type == "wl" and 1 or 0%>" />

						<input class="cbi-button cbi-button-apply" type="submit" value="<%:Join Network%>" />
					</form>
				</td>
			</tr>
			<% end %>
			<!-- /scan list -->
		</table>
	</fieldset>
</div>

进一步的测试发现,在调用function scanlist(times)异常导致生成的网页不完整,浏览器就会看到那段错误信息。而此函数又是在调用iw.scanlist发生异常。由local iw = luci.sys.wifi.getiwinfo(dev)找到sys.lua模块,路径/usr/lib/lua/luci/sys.lua,对应openwrt源码位置./feeds/luci/modules/base/luasrc/sys.lua。主要源码:

--- Get wireless information for given interface.
-- @param ifname        String containing the interface name
-- @return              A wrapped iwinfo object instance
function wifi.getiwinfo(ifname)
	local stat, iwinfo = pcall(require, "iwinfo")

	if ifname then
		local c = 0
		local u = uci.cursor_state()
		local d, n = ifname:match("^(%w+)%.network(%d+)")
		if d and n then
			ifname = d
			n = tonumber(n)
			u:foreach("wireless", "wifi-iface",
				function(s)
					if s.device == d then
						c = c + 1
						if c == n then
							ifname = s.ifname or s.device
							return false
						end
					end
				end)
		elseif u:get("wireless", ifname) == "wifi-device" then
			u:foreach("wireless", "wifi-iface",
				function(s)
					if s.device == ifname and s.ifname then
						ifname = s.ifname
						return false
					end
				end)
		end

		local t = stat and iwinfo.type(ifname)
		local x = t and iwinfo[t] or { }
		return setmetatable({}, {
			__index = function(t, k)
				if k == "ifname" then
					return ifname
				elseif x[k] then
					return x[k](ifname)
				end
			end
		})
	end
end

原来是调用iwinfo命令完成的无线搜索。在openwrt下运行iwinfo命令:

root@OpenWrt:~# iwinfo --help
Usage:
	iwinfo <device> info
	iwinfo <device> scan
	iwinfo <device> txpowerlist
	iwinfo <device> freqlist
	iwinfo <device> assoclist
	iwinfo <device> countrylist
root@OpenWrt:~# iwinfo radio0 scan
Cell 01 - Address: 00:00:00:00:00:00
          ESSID: unknown
          Mode: Unknown  Channel: unknown
          Signal: -256 dBm  Quality: 0/0
          Encryption: none

Cell 02 - Address: 00:00:00:00:00:00
          ESSID: unknown
          Mode: Unknown  Channel: unknown
          Signal: -256 dBm  Quality: 0/0
          Encryption: none

Cell 03 - Address: 00:00:00:00:00:00
          ESSID: unknown
          Mode: Unknown  Channel: unknown
          Signal: -256 dBm  Quality: 0/0
          Encryption: none

Cell 04 - Address: 00:00:00:00:00:00
          ESSID: unknown
          Mode: Unknown  Channel: unknown
          Signal: -256 dBm  Quality: 0/0
          Encryption: none

Cell 05 - Address: 00:00:00:00:00:00
          ESSID: unknown
          Mode: Unknown  Channel: unknown
          Signal: -256 dBm  Quality: 0/0
          Encryption: none

Cell 06 - Address: 00:00:00:00:00:00
          ESSID: unknown
          Mode: Unknown  Channel: unknown
          Signal: -256 dBm  Quality: 0/0
          Encryption: none

Cell 07 - Address: 00:00:00:00:00:00
          ESSID: unknown
          Mode: Unknown  Channel: unknown
          Signal: -256 dBm  Quality: 0/0
          Encryption: none

Cell 08 - Address: 00:00:00:00:00:00
          ESSID: unknown
          Mode: Unknown  Channel: unknown
          Signal: -256 dBm  Quality: 0/0
          Encryption: none

Cell 09 - Address: 00:00:00:00:00:00
          ESSID: unknown
          Mode: Unknown  Channel: unknown
          Signal: -256 dBm  Quality: 0/0
          Encryption: none

Cell 10 - Address: 00:00:00:00:00:00
          ESSID: unknown
          Mode: Unknown  Channel: unknown
          Signal: -256 dBm  Quality: 0/0
          Encryption: none

Cell 11 - Address: 00:00:00:00:00:00
          ESSID: unknown
          Mode: Unknown  Channel: unknown
          Signal: -256 dBm  Quality: 0/0
          Encryption: none

Cell 12 - Address: 00:00:00:00:00:00
          ESSID: unknown
          Mode: Unknown  Channel: unknown
          Signal: -256 dBm  Quality: 0/0
          Encryption: none

Cell 13 - Address: 00:00:00:00:00:00
          ESSID: unknown
          Mode: Unknown  Channel: unknown
          Signal: -256 dBm  Quality: 0/0
          Encryption: none

Cell 14 - Address: 00:00:00:00:00:00
          ESSID: unknown
          Mode: Unknown  Channel: unknown
          Signal: -256 dBm  Quality: 0/0
          Encryption: none

Cell 15 - Address: 00:00:00:00:00:00
          ESSID: unknown
          Mode: Unknown  Channel: unknown
          Signal: -256 dBm  Quality: 0/0
          Encryption: none

Cell 16 - Address: 00:00:00:00:00:00
          ESSID: unknown
          Mode: Unknown  Channel: unknown
          Signal: -256 dBm  Quality: 0/0
          Encryption: none

Cell 17 - Address: 00:00:00:00:00:00
          ESSID: unknown
          Mode: Unknown  Channel: unknown
          Signal: -256 dBm  Quality: 0/0
          Encryption: none

Cell 18 - Address: 00:00:00:00:00:00
          ESSID: unknown
          Mode: Unknown  Channel: unknown
          Signal: -256 dBm  Quality: 0/0
          Encryption: none

Cell 19 - Address: 00:00:00:00:00:00
          ESSID: unknown
          Mode: Unknown  Channel: unknown
          Signal: -256 dBm  Quality: 0/0
          Encryption: none

Cell 20 - Address: 00:00:00:00:00:00
          ESSID: unknown
          Mode: Unknown  Channel: unknown
          Signal: -256 dBm  Quality: 0/0
          Encryption: none
看看Address、ESSID。。 说明iwinfo根本就无法扫描到无线接入点。而在4、5月份编译的版本运行此命令没问题,可以搜索到接入点。iwinfo涉及到两个文件,在openwrt系统下一个是可执行文件/usr/bin/iwinfo,另一个是动态链接库文件/usr/lib/libiwinfo.so。于是拷贝之前系统(可以用搜索功能)的iwinfo、libiwinfo.so文件到有问题的路由的/tmp目录下,shell切换到/tmp目录,执行export LD_LIBRARY_PATH=.

然后再执行./iwinfo radio0 scan,发现搜索无线接入点正常,看来出来就出在iwinfo、libiwinfo.so上。直接删除/tmp目录下的libiwinfo.so后再./iwinfo radio0 scan,问题又出现了。由此推断出问题应该在libiwinfo.so里。iwinfo工具源码在openwrt源码的./package/network/utils/iwinfo下,注意Makefile文件有如下代码:

IWINFO_BACKENDS := \
	$(if $(CONFIG_PACKAGE_kmod-brcm-wl),wl) \
	$(if $(CONFIG_PACKAGE_kmod-brcm-wl-mini),wl) \
	$(if $(CONFIG_PACKAGE_kmod-brcm-wl-mimo),wl) \
	$(if $(CONFIG_PACKAGE_kmod-madwifi),madwifi) \
	$(if $(CONFIG_PACKAGE_kmod-mac80211),nl80211)
在src目录下的Makefile文件有如下代码:
ifneq ($(filter wl,$(IWINFO_BACKENDS)),)
	IWINFO_CFLAGS  += -DUSE_WL
	IWINFO_LIB_OBJ += iwinfo_wl.o
endif

ifneq ($(filter madwifi,$(IWINFO_BACKENDS)),)
	IWINFO_CFLAGS  += -DUSE_MADWIFI
	IWINFO_LIB_OBJ += iwinfo_madwifi.o
endif

ifneq ($(filter nl80211,$(IWINFO_BACKENDS)),)
	IWINFO_CFLAGS      += -DUSE_NL80211
	IWINFO_CLI_LDFLAGS += -lnl-tiny
	IWINFO_LIB_LDFLAGS += -lnl-tiny
	IWINFO_LIB_OBJ     += iwinfo_nl80211.o
endif
无线搜索有3中实现,刚开始我也不知道841n下是用哪种,索性在makefile文件里写些调试输出语句。然后make package/network/utils/iwinfo/compile V=s重新编译iwinfo,发现用的是nl80211,也就是说要改的代码在./src/iwinfo_nl80211.c。经过一系列的调试最终发现bug所在。解决方案如下:
// iwinfo_cli.c文件
static void print_scanlist(const struct iwinfo_ops *iw, const char *ifname)
{
	int i, x, len=0; //这里len必须初始化为0
	char buf[IWINFO_BUFSIZE];
	struct iwinfo_scanlist_entry *e;

	if (iw->scanlist(ifname, buf, &len))
	{
		printf("Scanning not possible\n\n");
		return;
	}
	else if (len <= 0)
	{
		printf("No scan results\n\n");
		return;
	}
// iwinfo_nl80211.c文件nl80211_phy2ifname函数修改如下
static char * nl80211_phy2ifname(const char *ifname)
{
	int fd, ifidx = -1, cifidx = -1, phyidx = -1;
	char buffer[64];
	static char nif[IFNAMSIZ] = { 0 };//注意静态变量

	DIR *d;
	struct dirent *e;
	char *ret = NULL; //添加

	if (!ifname)
		return NULL;
	else if (!strncmp(ifname, "phy", 3))
		phyidx = atoi(&ifname[3]);
	else if (!strncmp(ifname, "radio", 5))
		phyidx = atoi(&ifname[5]);
	//当传进来的ifname=wlan0时,phyidx=-1,后面的memset可能会把ifname清空。
	//memset(nif, 0, sizeof(nif)); //注释掉,因为ifname可能指向nif

	if (phyidx > -1)
	{
		if ((d = opendir("/sys/class/net")) != NULL)
		{
			while ((e = readdir(d)) != NULL)
			{
				snprintf(buffer, sizeof(buffer),
				         "/sys/class/net/%s/phy80211/index", e->d_name);

				if (nl80211_readint(buffer) == phyidx)
				{
					snprintf(buffer, sizeof(buffer),
					         "/sys/class/net/%s/ifindex", e->d_name);

					if ((cifidx = nl80211_readint(buffer)) >= 0 &&
					    ((ifidx < 0) || (cifidx < ifidx)))
					{
						ifidx = cifidx;
						strncpy(nif, e->d_name, sizeof(nif));
						ret = nif ; //添加
						break ; //添加
					}
				}
			}

			closedir(d);
		}
	}

	return ret ; //修改
}

make package/network/utils/iwinfo/compile V=s 重新编译iwinfo,传到路由上测试,iwinfo radio0 scan已经没问题,可以正常搜索无线了。其实我不喜欢nl80211_phy2ifname函数用静态变量方式返回,而更倾向于用函数参数的方式,例如声明成static char * nl80211_phy2ifname(const char *ifname, char *out);

已经向官方提交bug链接

© 著作权归作者所有

娱乐你我
粉丝 39
博文 32
码字总数 23759
作品 0
福州
程序员
私信 提问
开源路由器项目 OpenWrt 发布 18.06 稳定分支的首个版本

OpenWrt 18.06.0 - First Stable Release - July 2018 OpenWrt 项目是一个针对嵌入式设备的 Linux 操作系统。它完全取代了厂商提供的各种无线路由器和非网络设备的固件。已被支持的设备,请参...

Just_4_Fun
2018/08/01
8.9K
12
OpenWrt系列教程汇总 & OpenWrt简体中文Wiki

OpenWrt系列教程汇总 OpenWrt简体中文Wiki 快速导航

AlphaJay
2011/07/26
42.7K
1
OpenWrt 和 LEDE 宣布正式合并,名字沿用 OpenWrt

2017 年 5 月,我们曾报道过 OpenWrt 和 LEDE 项目正在讨论合并,现在,二者已在官网正式宣布合并,合并后的项目仍用 OpenWRT 命名。合并后的 OpenWrt 项目将按照 LEDE 制定的规范进行管理。...

王练
2018/01/05
6K
13
OpenWRT 14.07 RC1 发布,支持原生 IPv6

路由器Linux发行版OpenWRT发布了14.07 RC1,主要新特性是支持原生IPv6和整合Procd初始化系统。Procd是OpenWRT新的预初始化、初始化、热插拔和事件系统。其它变化包括:Linux内核升级到3.10;...

oschina
2014/07/17
4.5K
6
新 FCC 可能禁止在 WiFi 路由器安装 OpenWRT

新的 FCC(美国联邦通讯委员会)规则可能会禁止在 WiFi 路由器安装 OpenWRT。 OpenWrt 类似于 Buildroot 的路由器固件,为嵌入式设备所研发的 Linux 发行版。目前 OpenWrt 已支持多个平台(如...

oschina
2015/07/29
11.3K
38

没有更多内容

加载失败,请刷新页面

加载更多

springboot 403 问题

添加WebAppConfigurer 配置 @Configuration@EnableAutoConfigurationpublic class WebAppConfigurer extends WebMvcConfigurerAdapter { public WebAppConfigurer() { } ......

布袋和尚_爱吃鱼
28分钟前
4
0
Python自动更换壁纸爬虫与tkinter结合

直接上代码 import ctypesimport timeimport requestsimport osfrom threading import Threadfrom tkinter import Tk, Label, Button,Entry,StringVar,messagebox# '放到AppData\Roami......

物种起源-达尔文
29分钟前
3
0
Postgresql Study 笔记

Postgresql 安装 Windows, MAC Install Postgresql 下载地址: https://www.enterprisedb.com/downloads/postgres-postgresql-downloads Linux Install sudo apt-get update sudo apt-get in......

slagga
31分钟前
4
0
layer.open 打开新页面传参问题

如图所示,点击出售,把A页面的数据传到弹框上面,因为弹框比较复杂,所以使用引入一个新页面。 A.html a.js B.html b.js 1、第一种方案 sellInte: function (){ var obj = document.g...

木九天
34分钟前
4
0
沙龙报名 | 区块链数据服务技术应用实践

京东云是国内首家提供区块链数据在线分析服务产品的公司,也是行业内首家对区块链数据服务进行开源的公司。 本次沙龙是京东云BDS开源后,首次在深圳举办线下沙龙,我们将邀请京东云BDS团队核...

京东云技术新知
34分钟前
4
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部