Linux Kernel 3.3 not registering missed beacons with connected Access Point - linux

I'm using linux kernel 3.3 (I cannot upgrade my kernel, sorry!) and am trying to use the wpa_cli utility to monitor the status of my WiFi connection. I'm using an Edimax WiFi dongle to connect to a wireless access point.
I expect to see something like this:
# wpa_cli status
Selected interface 'wlan0'
wpa_state=SCANNING
ip_address=XXX.XXX.XXX.XXX
address=XX:XX:XX:XX:XX:XX
Or the same thing but with wpa_state=COMPLETED, depending upon my connection status.
Parsing the this text output allows me to see if my wireless connection is active or scanning. However, I have noticed that after powering off my access point wpa_state=COMPLETED is still being returned. Using the command:
# iwlist wlan0 scanning
Forces a scan and wpa_state will occasionally be correct, but usually (99%) not.
Here is my /etc/wpa_supplicant.conf:
ctrl_interface=/var/run/wpa_supplicant
ap_scan=1
country=US
network={
ssid="myssid"
psk="mypsk"
key_mgmt=WPA-PSK
eap=
}
After some investigation, I believe something weird is happening causing the kernel to return a cached version of the AP list. I am using the RTL8192cu driver. I've already looked at this issue, and it is not the same as mine.
My belief is that the issue may be somewhere in the kernel. In the file net/mac80211/scan.c, at line 214 in function ieee80211_scan_rx, I see a bssid from the BSS of my AP appear (when AP has power) and get put via ieee80211_rx_bss_put (here). At this point, it is returned in scan results and wpa_supplicant causes the MLME layer in the kernel to authenticate and connect with that AP. However, after disconnecting AP power, I never see the MLME layer relinquish it's atomic_t hold on that BSS. This causes the BSS to never to unlinked in the function
cfg80211_bss_expire at the end of a scan (cfg80211_wext_giwscan), in file net/wireless/scan.c, line 205 (here).
Specifically, I would like to know why the atomic used to "hold" a BSS is not decremented on power removal from the AP - causing linux to miss sufficient beacons for a disconnect? Or, is there some configuration with wpa_supplicant I need to add to have the MLME kernel layer decrement it's hold on the BSS, or is this clearly a kernel bug?
I've already tried:
# wpa_cli bss_expire_age 10
# wpa_cli bss_expire_count 2
and have not resolved my issue.

So after a lot of digging, I found that the issue was because of the kernel's rtlwifi driver. To me, it looks like the rtl8192cu driver was suppose to be responsible for handling missed beacons, by calling the function ieee80211_beacon_loss, but that call is nowhere to be found. I removed support for IEEE80211_HW_BEACON_FILTER in the rtlwifi driver and the issue has been fixed.
This patch is essentially the same changes that I made, and the comments in this file are part of what led to me this answer.

Related

Linux: writing to the i2c/SMBus

I have a problem with the i2c/SMBus on a Linux System with an Intel Apollo Lake processor. I am trying to read/write from/to an EEPROM but I face some issues. My EEPROM is located at the address 0x56, and I am able to watch the Bus with my Logic Analyzer.
When I try to read from the device via i2ctools (i2cget) the System behaves as expected. My issue occurs when I try to perform a write command via i2cset for example. i2cset ends with an error (Write failed). Because I am able to watch the Bus electrically I can also say that all lines stay HIGH and the Bus is not touched. I was able to activate the dev_dbg() functions in the i2c driver i2c_i801 and when I perform i2cset I am able to find (dmesg) the debug message:
[ 765.095591] [2753] i2c_i801:i801_check_post:433: i801_smbus 0000:00:1f.1: No response
When running my minimal I²C Python code using the smbus2 lib, I get the following error message and the above mentioned debug message:
from smbus2 import SMBus
bus = SMBus(0)
b = bus.read_byte_data(86,10) #<- This is performed
b = bus.write_byte_data(86,10,12) #<- This is not performed
bus.close()
Error:
File "usr/local/lib/python3.8/dist-packagers/smbus2-0.4.0-py3.8.egg/smbus/smbus2.py", line 455, in write_byte_data
ioctl(self.fd, I2C_SMBUS, msg)
OSERROR: [Errno 6] No such device or adress
A big hint for me is that I am not able to perform a write command in the address space form 0x50 to 0x57. My guess is that some driver locks the address space to prevent write command to that "dangerous" area.
My question is: "Does anyone know this kind of behavior and is there a solution so that I can write to my EEPROM at address 0x56? OR Is there a lock surrounding the i2c adress space from 0x50 to 0x57 and who is my opponent?"
I am kind of a newbie to the whole driver and kernel world so please be kind and it is quite possible that I made a beginner mistake.
I would appreciate hints and tips I can look after surrounding my problem.
It seems that I found the cause of my problem. In this Forum post is described that Intel changed a configuration Bit at the SMBus controller.
OK, I know what's going on.
Starting with the 8-Series/C220 chipsets, Intel introduced a new
configuration bit for the SMBus controller in register HOSTC (PCI
D31:F3 Address Offset 40h):
Bit 4 SPD Write Disable - R/WO.
0 = SPD write enabled.
1 = SPD write disabled. Writes to SMBus addresses 50h - 57h are
disabled.
This badly documented change in the configuration explains the issues.
One Challenge is, that to apply and enable changes to the SPD-write Bit the System needs to be rebooted. Unfortunately while rebooting the BIOS will change the Bit back to the default. The only solution seems to be an adaption in the BIOS.
For me, this issue is resolved. I just wanted to share this information in case someone faces the same issues.

BlueZ remote device presence

Using BlueZ, which
is the official Linux Bluetooth stack
I'd like to know which of the below two methods are better suited for detecting a device's presence in the nearby.
To be more exact, I want to periodically scan for a Bluetooth device (not BLE => no advertisement packets are sent).
I found two ways of detecting it:
1.) Using l2ping
# l2ping BTMAC
2.) Using hcitool
# hcitool name BTMAC
Both approaches working.
I'd like to know, which approach would drain more battery of the scanned device?
Looking at solution #1 (l2ping's source):
It uses a standard socket connect call to connect to the remote device, then uses the send command to send data to it:
send(sk, send_buf, L2CAP_CMD_HDR_SIZE + size, 0)
Now, L2CAP_CMD_HDR_SIZE is 4, and default size is 44, so altogether 48 bytes are sent, and received back with L2CAP_ECHO_REQ.
For hcitool I just have found the entrypoint:
int hci_read_remote_name(int dd, const bdaddr_t *bdaddr, int len, char *name, int to);
My questions:
which of these approaches are better (less power-consuming) for the remote device? If there is any difference at all.
shall I reduce the l2ping's size? What shall be the minimum?
is my assumption correct that hci_read_remote_name also connects to the remote device and sends some kind of request to it for getting back its name?
To answer your questions:-
which of these approaches are better (less power-consuming) for the remote device? If there is any difference at all.
l2ping BTMAC is the more suitable command purely because this is what it is meant to do. While "hcitool name BTMAC" is used to get the remote device's name, "l2ping" is used to detect its presence which is what you want to achieve. The difference in power consumption is really minimal, but if there is any then l2ping should be less power consuming.
shall I reduce the l2ping's size? What shall be the minimum?
If changing the l2ping size requires modifying the source code then I recommend leaving it the same. By leaving it the same you are using the same command that has been used countless times and the same command that was used to qualify the BlueZ stack. This way there's less chance for error and any change would not result in noticeable performance or power improvements.
is my assumption correct that hci_read_remote_name also connects to the remote device and sends some kind of request to it for getting back its name?
Yes your assumption is correct. According the Bluetooth Specification v5.2, Vol 4, Part E, Section 7.1.19 Remote Name Request Command:
If no connection exists between the local device and the device
corresponding to the BD_ADDR, a temporary Link Layer connection will
be established to obtain the LMP features and name of the remote
device.
I hope this helps.

How to deal with linux kernel drivers (for newbies)

I am trying to undestand how to USE linux kernel drivers. One day I wrote linux kernel module for handling interrupts from gpio. Built it with "make" command and loaded it with "insmod" and it worked. But now I am trying to use this ov5642 camera driver.I downloaded the source code. made "make" command in folder with sources and when it built I used "insmod" command to load it. It is now listed in already loaded modules list but I have got no idea how to get grabbed frames.
How can I make it work and access its output ?
In order to capture frames from the module, you need to "probe" your driver with a platform device (i.e. you have to create a platform device in order to call "ov5642_probe" function). If the probe function is being called, and ends successfully reaching to "return 0", you will get a print "Chip ID 0x5642 detected" in dmesg. (You can easily check weather the probe function is being called or not by putting a simple "printk(KERN ERR "### my probe function is being called")" at line number 935 in probe function and check in dmesg. If it is being called, you have to interface the camera properly in order to probe driver successfully.
If probe function fails (i.e. being called but not reaching till "return 0"), then there should be problem with reading the registers of ov5642. Check the i2c connections and power supplies of camera properly (and make sure its power on sequence is performed as mentioned in datasheet) if you get "Chip ID" other than 0x5642 or i2c read fails.
If the probe function is not being called, then you need to create a proper platform_device.
Assuming you are doing this on a custom board where ov5642 module is interfaced.
If you get "Chip ID 0x5642 detected" in dmesg, then you should try with "v4l-utils" package. There are many options available in v4l2-ctl command where you can set format, query capabilities, start stream, grab frame. If you are unable to install v4l-utils on your board, then, you should try https://gist.github.com/maxlapshin/1253534. You can also refer to Documentation/video4linux/ on lxr online or any kernel source offline if you are interested in developing a camera driver.
If you are a newbie, and you want to learn to deal with kernel drivers, refer to http://www.makelinux.net/ldd3/ and specially platform driver documentation under Documentation/driver-model/platform.txt on lxr for creating and probing a platform driver.

i2cdetect doesn't find anything on goodix chip

I have a goodix chip for the touchscreen on my tablet PC and even though I compiled the latest kernel module for it, things are not working.
I am using exactly this kernel version with the patched driver:
https://github.com/NimbleX/kernel
For starters, the picture of the said chip is the following:
The DSDT tables contain information regarding the touchscreen.
From what I understand the touchscreen is connected via an I2C serial interface but lshw shows that *-serial is UNCLAIMED.
Nevertheless I can see that the i2c_i801 module for the SMBus controller is loaded.
With the help of Aleksei I was able to determine that the toucscreen is connected to i2c-1 buss and that the controller must use 0x14 or 0x5d address.
Unfortunatelly, i2cdetect doesn't find anything, as it can be seen here.
I created a lengthy gist with the output of the following:
dmesg
DSDT.dsl
lshw
lspci
lsusb
/proc/bus/input/devices
xinput
I know that some of these are redundant and that others are useless but nevertheless it's better to have where to search than to miss something out.
I measured with a multimeter and the chip is powered both when running Windows and Linux so this rules out that I need to somehow tell Linux to power this thing out.
So, what do do next in order to debug this thing?
Hi can you check where pin 5,6 are connected specifically 6 which is reset ic so if that may be reseting the ic. just a posiblity.

Linux: calling open() on a USB device which may not be present

I have a device attached to a Raspberry Pi. The Pi is running ARCH Linux. The device communicates with the Pi via USB. The device has to be switched on and off via a pulse and I have control, from the Pi, of a relay which causes this pulse. However I can never be sure whether the device is initially on or off.
In my code I toggle the relay and then speculatively call open() on the device (with flags O_RDWR | O_NOCTTY). The problem is that if I am doing this when the device is off the open() call hangs. I have tried waiting for 1 second after the toggle, for things to settle, but that hasn't helped. I have tried calling stat() before the open() call but this always returns zero (so the device is there as far as stat() is concerned). I have tried specifying O_NON_BLOCK in the open() call but that causes it to always fail.
Can anyone suggest either (a) what I'm doing wrong or (b) a reliable way forward?
You can be certain that the device has powered if it has USB enumerated. You can use libudev to find the list of USB enumerated devices and check whether your device is on that list.
The command line "lsusb" does that. So if you need an example of how to use libudev then you can read the lsusb source code (https://github.com/gregkh/lsusb).
If you can be sure that the device will eventually turn up, the blocking open() ("hangs") may actually be what you want! The call to open() will return, hopefully with success, when your device turns up.
The stat() call simply checks if the device special file is there. It can't tell you if there is anything listening.
One possible way forward, would be to open() with O_NONBLOCK in an exponential back-off loop.
Depending on what you mean with "communicates via USB", you may want to use libusb. If it's just a USB serial port, wrapping open() yourself is probably the easiest though.
It's not clear what you have done to get a device file that survives disconnect.
The usual approach is to use hotplug+udev to create (and remove) the device symlinks, then the special file would only be there when the device is plugged in.
Courtesy of all the helpful people below, the quick answer was to include in my .rules file a "remove" action to go with the existing "add" action. So in the file where I have:
ACTION=="add", ATTRS{interface}=="Pololu Orangutan X2 Serial Adapter", MODE="7777", SYMLINK+="OrangutanUSB"
...to give me a /dev/OrangutanUSB device, I have included a new line:
ACTION=="remove", ATTRS{interface}=="Pololu Orangutan X2 Serial Adapter", MODE="7777", SYMLINK-="OrangutanUSB"
...to cause the operating system to remove the /dev/OrangutanUSB device when it has been powered off. This way the open() call fails correctly when the device has gone, rather than hanging.
Ultimately, what I should do is check that the device is enumerated, rather than expecting open() to fail, but that can wait until I have the time. For now my code works as originally intended.

Resources