Free DNS provides easy shared DNS hosting & URL forwarding

Thursday, April 17, 2014

Udev tricks - How to toggle built-in wi-fi on/off

My Toshiba Satellite laptop has a RTL8192CE built-in wifi, which is a total joke. It only works if I'm within a few meters range of the router and without any big obstacles between. For example, if I'm in my home office I can't even use the router that is in the next room. All other devices in our house can connect and mark it as strong signal. If by any luck my laptop manages to connect, the connection is unusable, with network speeds of less than 1Mb/s and most of the packages failing their CRC checksum.

I googled and test various solutions. None of them worked. I found many others which have same problem. Different OSes, different laptop models, same card type, same problem. After loosing (in total) more than 3 days on this, I decided it's just not worth it and bought and Atheros external USB wifi dongle (model TL-WN721N). It works perfectly and without any problems.

The problem I had now is that when I plug the USB wifi, Network Manager in Ubuntu clutters its menu and dialog boxes with various options to select which wifi card to use. For example, when I want to connect to a hidden network, it asked me to select which card to use for connection. It also used to keep trying to reconnect to the home network on the faulty card (but that I fixed by deleting Wi-fi network settings). This is annoying and overall makes me waste a lot of time. Therefore, I read udev man pages to find out how can I disable the built-in wifi whenever I plug in the USB one. Eventually I came up with these rules:

SUBSYSTEM=="net", ACTION=="add", ENV{INTERFACE}=="wlan1", RUN+="/sbin/rmmod rtl8192ce"
SUBSYSTEM=="net", ACTION=="remove", ENV{INTERFACE}=="wlan1", RUN+="/sbin/modprobe --quiet rtl8192ce"

The major time waster was ENV{INTERFACE}=="wlan1" because NAME=="wlan1" works on add event, but not on remove. I also lost some valueable time trying to get it work with INTERFACE=="wlan1", before I actually understood that INTERFACE is not a property.

These rules go under: /etc/udev/rules.d/99-disable-builtin-wlan.rules.

Later on, I decided to do something similar for the built-in soundcard (for similar reasons). It took me some time to find out the proper commands to disabled it. First I tried to remove its modules (like i did with the wifi), but that option failed because they were always in use by PulseAudio. So I started to look into PulseAudio options. I found the pactl (and pacmd) which seemed to do what I needed. It took another 30 minutes of testing to find out how to use them for this task and another 15 minutes to find out that they don't work as root, but should be run as the current user. After that, writing the udev rules was a piece of cake:

SUBSYSTEM=="sound", ACTION=="add", ENV{ID_TYPE}=="audio", RUN+="/bin/su abautu -c '/usr/bin/pactl set-card-profile alsa_card.pci-0000_00_1b.0 off'"
SUBSYSTEM=="sound", ACTION=="remove", ENV{ID_TYPE}=="audio", RUN+="/bin/su abautu -c '/usr/bin/pactl set-card-profile alsa_card.pci-0000_00_1b.0 output:analog-stereo+input:analog-stereo'"

Note that you need to replace "su abautu" with your own username or it won't work.