Ubus call in Luci network.js failing and returning null object

Luci version: 19.07.1
Platform: x86_64

The wireless page on my Luci interface is displaying incorrect information. The image below shows what I mean

It's putting in Generic data for the hardware name and the strings for channel and Bitrate are null. It also thinks the wireless is not associated. Despite there being a number of stations associated.

By comparison, my 15.05 displays the data correctly, so you can see what should actually be displayed. The radio0 is clearly identified by it's hardware name and the BSSIS and Encryption type is shown instead of the "not associated" messager.

Untitled2

Digging into the javascript code for Luci, specifically /www/luci-static/resources/network.js, the call to ubus('dev', 'iwinfo', 'hardware') in this function is failing in the second line of the function. Clearly, similar calls are failing elsewhere as other information is also not being return correctly: the channel and bitrate for example.

    getI18n: function() {
        var hw = this.ubus('dev', 'iwinfo', 'hardware'),
            type = L.isObject(hw) ? hw.name : null;  // L.isObject(hw) is false and so hwname is set to null

        if (this.ubus('dev', 'iwinfo', 'type') == 'wl')
            type = 'Broadcom';

        var hwmodes = this.getHWModes(),
            modestr = '';

        hwmodes.sort(function(a, b) {
            return (a.length != b.length ? a.length > b.length : a > b);
        });

        modestr = hwmodes.join('');

        return '%s 802.11%s Wireless Controller (%s)'.format(type || 'Generic', modestr, this.getName());
    },

However, doing some sanity checks with the ubus command line utility shows that ubus seems to be working fine, as it returns the required information for this radio device correctly, so that call to ubus in network.js should not be returning a null object.

root@OpenWrt:~# ubus call iwinfo info '{ "device": "radio0" }'
{
	"phy": "phy0",
	"bssid": "00:19:70:A2:89:15",
	"country": "AM",
	"mode": "Master",
	"channel": 44,
	"frequency": 5220,
	"frequency_offset": 0,
	"txpower": 30,
	"txpower_offset": 0,
	"quality_max": 70,
	"noise": 0,
	"htmodes": [
		"HT20",
		"HT40",
		"VHT20",
		"VHT40",
		"VHT80"
	],
	"hwmodes": [
		"ac",
		"n"
	],
	"hardware": {
		"id": [
			5772,
			60,
			0,
			0
		],
		"name": "Qualcomm Atheros QCA9880"
	}
}

If anyone with deeper knowledge of the internals can perhaps point me in the right direction as to other checks I can do to track down this problem, that would be really helpful.

Note: I have done a full clean, update of feeds and a recompile multiple times. I've tested this against both uhttpd and nginx and the behaviour is the same.

The root cause of this error is that in this call

    var hw = this.ubus('dev', 'iwinfo', 'hardware'),
            type = L.isObject(hw) ? hw.name : null;

the check L.isObject(hw) fails and so hw.name is returned as null.

Investigating a little further, if I look at the _ubusdata that the function ubus() accesses and enumerate it, I can see that the two radios are there, each with their own "dev" object.

Iterating through the dev object, there is clearly no "iwinfo" object. All the other info appears to be populated and correct when I iterate through the config and interfaces object, just there is no iwinfo object in the dev object. So of course it thinks the radio is generic and any other info depending on data extracted from iwinfo will of course also be absent

rpcd-mod-iwinfo is selected and installed and the relevant iwinfo.so binaries are correctly located in their respective folders. libiwinfo is installed. One can see it all works correctly because the ubus command line call I showed previously lists the hardware info correctly.

Top level _ubusdata object:

radio: radio0
dev: [object Object]
radio: radio1
dev: [object Object]

Now the "dev" object:

up: true
pending: false
autostart: true
disabled: false
retry_setup_failed: false
config: [object Object]
interfaces: [object Object],[object Object]
up: true

Now the "config" object:

noscan: true
ht_capab: [HT40+][LDPC][SHORT-GI-20][SHORT-GI-40][TX-STBC][RX-STBC1][DSSS_CCK-40]
channel: 44
htmode: VHT80
country: GB
hwmode: 11a
path: pci0000:00/0000:00:03.0/0000:04:00.0/0000:05:05.0/0000:08:00.0
log_level: 3
txpower: 30

And the "interfaces" object

section: wifinet0
ifname: wlan0
config: [object Object]

is this the issue

It’s a bug in OpenWrt master. The ubus call network.wireless status output does not contain an ifname for the second and subsequent virtual interfaces which LuCI needs to map iwinfo information. Bug report here: https://github.com/openwrt/luci/issues/3670

Thanks @jow. Very helpful. While this is very likely similar to or the same problem, and while displaying similar symptoms on Luci, I get different behaviour from

ubus call network.wireless status

and

ubus call luci-rpc getWirelessDevices

None of my radios on Luci display correct information.

To recap my hardware/configuration: I have two radios, one 5Ghz and one 2.4Ghz. Each of them is running two interfaces - one for my normal wireless lan and one for a guest wireless VLAN.

Of note, the similarity with the person who reported the bug you kindly linked, we both have an Atheros QCA9880 card. Whether this is relevant or just coincidence, I don't know.

In my case ubus call network.wireless status actually does return interface names for all of the VAPs

root@OpenWrt:~# ubus call network.wireless status
{
	"radio0": {
		"up": true,
		"pending": false,
		"autostart": true,
		"disabled": false,
		"retry_setup_failed": false,
		"config": {
			"hwmode": "11a",
			"path": "pci0000:00/0000:00:03.0/0000:04:00.0/0000:05:05.0/0000:08:00.0",
			"log_level": 3,
			"txpower": 30,
			"noscan": "1",
			"noscan": true,
			"ht_capab": [
				"[HT40+][LDPC][SHORT-GI-20][SHORT-GI-40][TX-STBC][RX-STBC1][DSSS_CCK-40]"
			],
			"channel": "44",
			"htmode": "VHT80",
			"country": "GB"
		},
		"interfaces": [
			{
				"section": "wifinet0",
				"ifname": "wlan0",
				"config": {
					"mode": "ap",
					"encryption": "psk2+ccmp",
					"key": "XXXX",
					"ssid": "AAAA5Ghz",
					"wps_pushbutton": false,
					"mode": "ap",
					"network": [
						"lan"
					]
				}
			},
			{
				"section": "wifinet3",
				"ifname": "wlan0-1",
				"config": {
					"mode": "ap",
					"ssid": "BBBB5Ghz",
					"encryption": "psk2",
					"key": "XXXX",
					"wps_pushbutton": false,
					"mode": "ap",
					"network": [
						"guest"
					]
				}
			}
		]
	},
	"radio1": {
		"up": true,
		"pending": false,
		"autostart": true,
		"disabled": false,
		"retry_setup_failed": false,
		"config": {
			"path": "pci0000:00/0000:00:03.0/0000:04:00.0/0000:05:07.0/0000:09:00.0",
			"log_level": 3,
			"txpower": 24,
			"country": "00",
			"hwmode": "11g",
			"noscan": "1",
			"noscan": true,
			"htmode": "HT20",
			"channel": "1"
		},
		"interfaces": [
			{
				"section": "wifinet1",
				"ifname": "wlan1",
				"config": {
					"mode": "ap",
					"encryption": "psk2+ccmp",
					"key": "XXXX",
					"ssid": "AAAA",
					"wps_pushbutton": false,
					"mode": "ap",
					"network": [
						"lan"
					]
				}
			},
			{
				"section": "wifinet2",
				"ifname": "wlan1-1",
				"config": {
					"mode": "ap",
					"encryption": "psk2+ccmp",
					"key": "XXXX",
					"ssid": "BBBB",
					"wps_pushbutton": false,
					"mode": "ap",
					"network": [
						"guest"
					]
				}
			}
		]
	}
}

However, ubus call luci-rpc getWirelessDevices gives output that lacks the iwinfo object in the json output from the command, which explains why the network.js script receives a null iwinfo object.

root@OpenWrt:~# ubus call luci-rpc getWirelessDevices
{
	"radio0": {
		"up": true,
		"pending": false,
		"autostart": true,
		"disabled": false,
		"retry_setup_failed": false,
		"config": {
			"hwmode": "11a",
			"path": "pci0000:00/0000:00:03.0/0000:04:00.0/0000:05:05.0/0000:08:00.0",
			"log_level": 3,
			"txpower": 30,
			"noscan": "1",
			"noscan": true,
			"ht_capab": [
				"[HT40+][LDPC][SHORT-GI-20][SHORT-GI-40][TX-STBC][RX-STBC1][DSSS_CCK-40]"
			],
			"channel": "44",
			"htmode": "VHT80",
			"country": "GB"
		},
		"interfaces": [
			{
				"section": "wifinet0",
				"ifname": "wlan0",
				"config": {
					"mode": "ap",
					"encryption": "psk2+ccmp",
					"key": "XXXX",
					"ssid": "AAAA5Ghz",
					"wps_pushbutton": false,
					"mode": "ap",
					"network": [
						"lan"
					]
				}
			},
			{
				"section": "wifinet3",
				"ifname": "wlan0-1",
				"config": {
					"mode": "ap",
					"ssid": "BBBB5Ghz",
					"encryption": "psk2",
					"key": "XXXX",
					"wps_pushbutton": false,
					"mode": "ap",
					"network": [
						"guest"
					]
				}
			}
		]
	},
	"radio1": {
		"up": true,
		"pending": false,
		"autostart": true,
		"disabled": false,
		"retry_setup_failed": false,
		"config": {
			"path": "pci0000:00/0000:00:03.0/0000:04:00.0/0000:05:07.0/0000:09:00.0",
			"log_level": 3,
			"txpower": 24,
			"country": "00",
			"hwmode": "11g",
			"noscan": "1",
			"noscan": true,
			"htmode": "HT20",
			"channel": "1"
		},
		"interfaces": [
			{
				"section": "wifinet1",
				"ifname": "wlan1",
				"config": {
					"mode": "ap",
					"encryption": "psk2+ccmp",
					"key": "XXXX",
					"ssid": "AAAA",
					"wps_pushbutton": false,
					"mode": "ap",
					"network": [
						"lan"
					]
				}
			},
			{
				"section": "wifinet2",
				"ifname": "wlan1-1",
				"config": {
					"mode": "ap",
					"encryption": "psk2+ccmp",
					"key": "BBBB",
					"ssid": "XXXX",
					"wps_pushbutton": false,
					"mode": "ap",
					"network": [
						"guest"
					]
				}
			}
		]
	}
}

So in conclusion, I'm not 100% certain my problem has the same root cause. I'll try put some debug code into rpcd / rpcd-mod-luci to get some more information

Ok, I've found the bug.

I put some debug statements into luci.c in rpcd-mod-luci as per the below

static bool rpc_luci_get_iwinfo(struct blob_buf *buf, const char *devname,
                                bool phy_only)
{
    struct iwinfo_crypto_entry crypto = {};
    struct iwinfo_hardware_id ids = {};
    const struct iwinfo_ops *iw;
    void *iwlib, *o, *o2, *a;
    int nret;

    openlog("rpcd-mod-luci", LOG_CONS|LOG_NDELAY|LOG_NOWAIT|LOG_PID, LOG_DAEMON);
    syslog(LOG_DAEMON|LOG_ALERT, "entering rpc_luci_getiwinfo()");
    closelog();

    if (!iw_backend || !iw_close || !iw_modenames) {
        iwlib = dlopen("libiwinfo.so", RTLD_LOCAL);

        if (!iwlib) {

            char *strdlerr = dlerror();
            openlog("rpcd-mod-luci", LOG_CONS|LOG_NDELAY|LOG_NOWAIT|LOG_PID, LOG_DAEMON);
            syslog(LOG_DAEMON|LOG_ALERT, "cannot open libiwinfo.so: %s", strdlerr);
            closelog();
            return false;
        }


This code fails on the dlopen. The error is as follows

Mar  1 19:38:22 OpenWrt rpcd-mod-luci[15893]: cannot open libiwinfo.so: libiwinfo.so: invalid mode for dlopen(): Invalid argument

The call to dlopen() is indeed being made with invalid arguments. According to the man page for dlopen()

       One of the following two values must be included in flags:

       RTLD_LAZY
              Perform lazy binding.  Resolve symbols only as the code that
              references them is executed.  If the symbol is never
              referenced, then it is never resolved.  (Lazy binding is
              performed only for function references; references to
              variables are always immediately bound when the shared object
              is loaded.)  Since glibc 2.1.1, this flag is overridden by the
              effect of the LD_BIND_NOW environment variable.

       RTLD_NOW
              If this value is specified, or the environment variable
              LD_BIND_NOW is set to a nonempty string, all undefined symbols
              in the shared object are resolved before dlopen() returns.  If
              this cannot be done, an error is returned.

So altering the call thus

iwlib = dlopen("libiwinfo.so", RTLD_LAZY|RTLD_LOCAL);

The problem is fixed. The output of ubus call luci-rpc getWirelessDevices now correctly returns the iwinfo object in the json and the wireless information is now all properly populated in the Luci interface. I'll raise an issue on the github

This topic was automatically closed 10 days after the last reply. New replies are no longer allowed.