博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
解决OpenWrt无线搜索错误bug
阅读量:6341 次
发布时间:2019-06-22

本文共 10002 字,大约阅读时间需要 33 分钟。

  hot3.png

    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("%s - %s",				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 "%s" % translate("unknown")		else			return "%s" % 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%>

<%:Join Network: Wireless Scan%>

<% for i, net in ipairs(scanlist(3)) do net.encryption = net.encryption or { } %>
<% end %>
<%=percent_wifi_signal(net)%>%
<%=net.ssid and utl.pcdata(net.ssid) or "%s" % translate("hidden")%>
Channel: <%=net.channel%> | Mode: <%=net.mode%> | BSSID: <%=net.bssid%> | Encryption: <%=format_wifi_encryption(net.encryption)%>
<% if net.encryption.wpa then %>
<% for _, v in ipairs(net.encryption.auth_suites) do %>
<% end; for _, v in ipairs(net.encryption.group_ciphers) do %>
<% end; for _, v in ipairs(net.encryption.pair_ciphers) do %>
<% end; end %>
" />

进一步的测试发现,在调用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 instancefunction 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		})	endend

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

root@OpenWrt:~# iwinfo --helpUsage:	iwinfo  info	iwinfo  scan	iwinfo  txpowerlist	iwinfo  freqlist	iwinfo  assoclist	iwinfo  countrylistroot@OpenWrt:~# iwinfo radio0 scanCell 01 - Address: 00:00:00:00:00:00 ESSID: unknown Mode: Unknown Channel: unknown Signal: -256 dBm Quality: 0/0 Encryption: noneCell 02 - Address: 00:00:00:00:00:00 ESSID: unknown Mode: Unknown Channel: unknown Signal: -256 dBm Quality: 0/0 Encryption: noneCell 03 - Address: 00:00:00:00:00:00 ESSID: unknown Mode: Unknown Channel: unknown Signal: -256 dBm Quality: 0/0 Encryption: noneCell 04 - Address: 00:00:00:00:00:00 ESSID: unknown Mode: Unknown Channel: unknown Signal: -256 dBm Quality: 0/0 Encryption: noneCell 05 - Address: 00:00:00:00:00:00 ESSID: unknown Mode: Unknown Channel: unknown Signal: -256 dBm Quality: 0/0 Encryption: noneCell 06 - Address: 00:00:00:00:00:00 ESSID: unknown Mode: Unknown Channel: unknown Signal: -256 dBm Quality: 0/0 Encryption: noneCell 07 - Address: 00:00:00:00:00:00 ESSID: unknown Mode: Unknown Channel: unknown Signal: -256 dBm Quality: 0/0 Encryption: noneCell 08 - Address: 00:00:00:00:00:00 ESSID: unknown Mode: Unknown Channel: unknown Signal: -256 dBm Quality: 0/0 Encryption: noneCell 09 - Address: 00:00:00:00:00:00 ESSID: unknown Mode: Unknown Channel: unknown Signal: -256 dBm Quality: 0/0 Encryption: noneCell 10 - Address: 00:00:00:00:00:00 ESSID: unknown Mode: Unknown Channel: unknown Signal: -256 dBm Quality: 0/0 Encryption: noneCell 11 - Address: 00:00:00:00:00:00 ESSID: unknown Mode: Unknown Channel: unknown Signal: -256 dBm Quality: 0/0 Encryption: noneCell 12 - Address: 00:00:00:00:00:00 ESSID: unknown Mode: Unknown Channel: unknown Signal: -256 dBm Quality: 0/0 Encryption: noneCell 13 - Address: 00:00:00:00:00:00 ESSID: unknown Mode: Unknown Channel: unknown Signal: -256 dBm Quality: 0/0 Encryption: noneCell 14 - Address: 00:00:00:00:00:00 ESSID: unknown Mode: Unknown Channel: unknown Signal: -256 dBm Quality: 0/0 Encryption: noneCell 15 - Address: 00:00:00:00:00:00 ESSID: unknown Mode: Unknown Channel: unknown Signal: -256 dBm Quality: 0/0 Encryption: noneCell 16 - Address: 00:00:00:00:00:00 ESSID: unknown Mode: Unknown Channel: unknown Signal: -256 dBm Quality: 0/0 Encryption: noneCell 17 - Address: 00:00:00:00:00:00 ESSID: unknown Mode: Unknown Channel: unknown Signal: -256 dBm Quality: 0/0 Encryption: noneCell 18 - Address: 00:00:00:00:00:00 ESSID: unknown Mode: Unknown Channel: unknown Signal: -256 dBm Quality: 0/0 Encryption: noneCell 19 - Address: 00:00:00:00:00:00 ESSID: unknown Mode: Unknown Channel: unknown Signal: -256 dBm Quality: 0/0 Encryption: noneCell 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.oendififneq ($(filter madwifi,$(IWINFO_BACKENDS)),)	IWINFO_CFLAGS  += -DUSE_MADWIFI	IWINFO_LIB_OBJ += iwinfo_madwifi.oendififneq ($(filter nl80211,$(IWINFO_BACKENDS)),)	IWINFO_CFLAGS      += -DUSE_NL80211	IWINFO_CLI_LDFLAGS += -lnl-tiny	IWINFO_LIB_LDFLAGS += -lnl-tiny	IWINFO_LIB_OBJ     += iwinfo_nl80211.oendif
无线搜索有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。

转载于:https://my.oschina.net/osbin/blog/298526

你可能感兴趣的文章
Oracle运算符收录(易忘记,但是又很重要的运算符)
查看>>
POJ 2062 Card Game Cheater
查看>>
'ascii' codec can't decode byte 0xd6 in position 0
查看>>
TPVJ水题
查看>>
OWINS是什么(转载)
查看>>
在一台电脑访问另一台电脑的mysql数据库
查看>>
指针数组与数组指针
查看>>
python之MySQL学习——数据操作
查看>>
Quartz定调度简单案例
查看>>
关于微信小程序 modal弹框组件的介绍
查看>>
给一系列的div中的第一个添加class
查看>>
centos6.8 安装jenkins
查看>>
vue-cli3.0+node.js+axios跨域请求session不一样的问题
查看>>
C#发送DKIM签名的邮件
查看>>
python中获取字典的key列表和value列表
查看>>
Windows8中使用IE8等低版本浏览器
查看>>
[图形图像]一次光线追踪的尝试
查看>>
C# 中out,ref,params参数的使用
查看>>
玩转VIM编辑器-vim附加特性
查看>>
Ubuntu下有关Java和数据库的一些工作记录(二)
查看>>