Category Archives: computers

serialized

router += serialMy ath10k-based router now has serial headers, after I managed to crash it a few times over the weekend while testing out some patches. Thank you, TP-Link, for making the pins so easily accessible, to the extent that it’s easier to whip out the soldering iron than remind oneself how to setup kexec/kdump.

I do need to get one of these nifty usb-serial cables so that the JTAG ribbon cable + FTDI-breakout-on-a-breadboard monstrosity can go back into the
parts bin, but it is working fine otherwise. [The pictured 7-segment display and TTL chips are just misdirection, by the way.]

There was a momentary bit of confusion on my part when the console showed the router stuck in a loop requesting recovery firmware over TFTP instead of the normal boot process…until I realized that the reset button was wedged in the depressed state by the case. Whoops.

Spectrum

The ath9k and later chips support a spectral scan feature for measuring channel occupancy. I played with it for the first time last week over the Thanksgiving holiday. Simon Wunderlich’s FFT_eval is a great tool to look at the captured RF spectrum, but I found myself wanting something more real-time, and the various other things I found on github with that aim didn’t work for me. So, this too-ugly-to-live python hack happened.

It turns out that the samples are rather coarse and infrequent, so the result is not as dynamic as I’d hoped. However, I made the pretty heatmap below with a few hours’ worth of samples, and although I didn’t yet label frequencies, you can see a couple of channels in active use. There’s still plenty of room for improvement in the visualization.

functional bitrate sim

My wmediumd rewrite is a bit further along thanks to getting a few hours to hack on it this weekend. It can now accurately simulate throughput between a pair of radios using legacy rates. For example, if we set the SNR between two devices to 20 dB, then they can communicate at a nominal 54 mbps rate, yielding about 26 Mbps achieved in iperf:

[  3]  0.0-10.0 sec  31.2 MBytes  26.1 Mbits/sec

At 15 dB, we can send between 24 and 36 Mbps nominal rates, which yields:

[  3]  0.0-10.1 sec  21.0 MBytes  17.5 Mbits/sec

Note that achieved throughput is quite a bit lower than nominal, as in real life — if aggregation were implemented then they would be closer.

The basic architecture is pretty simple: frames are queued on a per-sender management or data queue depending on type, and delivery time is computed based on whether or not there is loss and the contention window parameters of the queues. A timerfd is used to schedule reporting of frame delivery back to the kernel at appropriate times. The delivery time does not take into account actual contention, although this could be done in principle by looking at all the queued frames for all stations.

I haven’t really decided what to do about configuration. I stripped out the jamming and probability matrix configurations, as I feel like doing things on a signal level basis are simpler. But at this point there’s no real way to specify signal levels either (other than hardcoding), and some scenarios probably want something dynamic (e.g. mobile stations).

Changes are in my wmediumd master branch. Unfortunately, I won’t have much time to work on this for the next two months, but patches for the many TODOs are welcome.

wmediumd speed test

Thanks to some inquries on linux-wireless, I took a look at wmediumd recently. The code could use a bit of work, and there are some features I’ve been meaning to add since forever, so I started gutting it with an eye towards sprucing up the architecture and feature set (changes can be found here).

One of the questions from the mailing list was whether wmediumd adds a lot of overhead compared to mac80211_hwsim. It is of course doing more work, with additional memory copies, context switches, etc — but is it enough to make wmediumd unworkable?

So I did a quick TCP iperf test on my laptop with an open mesh, and get the following numbers.

hwsim without wmediumd:

    [  3]  0.0-10.0 sec  1.36 GBytes  1.16 Gbits/sec

hwsim with wmediumd:

    [  3]  0.0-10.0 sec  1.27 GBytes  1.09 Gbits/sec

It looks like wmediumd is doing fine. This is with monitors running, the non-monitor case does about twice that. Actually, I think this is a bit lower than it should be, but considering both cases are close, and a good deal faster than your typical wifi connection, it’s probably good enough for some level of bandwidth simulation.

wpas mesh

Continuing where I left off with my OpenWRT mesh nodes, after installing the OS, the next step is to get a mesh-enabled userspace on them.

One can use iw to create an open mesh, and the authsae daemon for secure mesh, and OpenWRT already ships both of those, so just installing those packages is really all that is required.

However, I’m currently working on a patchset to add mesh support to wpa_supplicant, which could be useful for platforms where wpa_s is already present and running yet another daemon just for secure mesh is unpalatable. Here’s the recipe I’m using to keep the latest version on the device and use it for day-to-day activities.

Since OpenWRT can use git as a package source and already does so for hostapd, building a custom wpa_supplicant is mainly a matter of just changing the git repository url and config. I made the following changes in the package/network/services/hostapd directory:

diff --git a/package/network/services/hostapd/Makefile b/package/network/services/host
index 6872742..5985339 100644
--- a/package/network/services/hostapd/Makefile
+++ b/package/network/services/hostapd/Makefile
@@ -10,10 +10,10 @@ include $(TOPDIR)/rules.mk
 PKG_NAME:=hostapd
 PKG_VERSION:=2014-06-03
 PKG_RELEASE:=1
-PKG_REV:=84df167554569af8c87f0a8ac1fb508192417d8e
+PKG_REV:=prepare-submit-v12
 
 PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.bz2
-PKG_SOURCE_URL:=git://w1.fi/srv/git/hostap.git
+PKG_SOURCE_URL:=https://github.com/cozybit/wpa_supplicant.git
 PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION)
 PKG_SOURCE_VERSION:=$(PKG_REV)
 PKG_SOURCE_PROTO:=git
diff --git a/package/network/services/hostapd/files/wpa_supplicant-full.config b/packa
index bbfaa73..4d9e00e 100644
--- a/package/network/services/hostapd/files/wpa_supplicant-full.config
+++ b/package/network/services/hostapd/files/wpa_supplicant-full.config
@@ -407,3 +407,9 @@ CONFIG_NO_RANDOM_POOL=y
 NEED_80211_COMMON=y
 
 CONFIG_IBSS_RSN=y
+
+CONFIG_AP=y
+CONFIG_P2P=y
+CONFIG_TDLS=y
+CONFIG_SAE=y
+CONFIG_MESH=y

(Offhand, I don’t know if P2P and TDLS are really required, but as it matches my existing config, we’ll go with that.)

You’ll also need to enable CONFIG_WPA_SUPPLICANT_OPENSSL=y in the OpenWRT menuconfig in order for SAE to link properly.

Rebuilding from scratch looks like this:

rm dl/hostapd-*.tar.bz2
make package/hostapd/{download,prepare,clean,compile,install} V=s

Once built, I have a simple script which copies over the bin/x86_64/packages/{hostapd*,wpa-s*} files and then runs opkg install on each of the nodes.

To start the mesh, I use the following script:

#!/bin/bash
pubip=`ip route get 8.8.8.8 | awk 'NR==1 {print $NF}'`
last8=`echo $pubip | awk -F . '{print $4}'`
meship=10.10.1.$last8
iface=wlan0

cat<<__EOM > wpa_s.conf
network={
    ssid="your-meshid-here"
    mode=5
    frequency=2412
    key_mgmt=SAE
    psk="your-pw-here"
}
__EOM
ip addr flush $iface
ip link set $iface down
iw dev $iface set type mp
ip link set $iface up
ip addr add $meship/24 dev $iface

killall wpa_supplicant
wpa_supplicant -dd -i $iface -c wpa_s.conf >wpa_s.log 2>&1 &

In response to the previous blog post, Johannes Berg pointed out that running nfsroot and PXE booting these devices would be even easier than futzing with USB sticks and copying binaries back and forth. Unfortunately, the BIOS on these machines doesn’t appear to support netboot, and at least for now, I can’t be bothered to figure out how to do it from within grub. At any rate, I find this setup makes for a fairly painless compile / deploy / test cycle.

Zotac OpenWRT

ZOTAC! The Zotac NM10-ITX is a mini-ITX motherboard, which in my configuration has a 1.66 GHz Atom D510 on board, 8 GB SSD, 2 GB ram, and a pair of 2×2 ath9k devices. I wound up with a few of these boxes as a mesh testbed due to my work with Cozybit. Until recently, they ran distro11s, which is basically Debian with some mesh/wireless utilities and some custom init scripts thrown on top. I was looking to re-image them, and I believe distro11s is not actively maintained. The boxes are beefy enough to run unmodified Debian, but OpenWRT has various niceties when building all things wireless from source, and I might like to run the same setup on more constrained devices, so I went with that.

Building OpenWRT from git is a rather simple affair [1]. In my case, I made a few trips through make kernel_menuconfig to get the right config for a properly booting kernel (namely, CONFIG_ATA_PIIX, CONFIG_INPUT_EVDEV, CONFIG_USB_HID, CONFIG_HID_GENERIC, and CONFIG_R8169 were needed for functional disk, keyboard, and network on boot). I also customized the network setup via files/etc/config/network so that eth0 would come up with DHCP rather than a fixed IP at 192.168.1.1.

Once built, one needs a way to copy the OpenWRT image onto the drive. Enter Bootable USB Stick.

I recently procured a speedy, spacious USB stick in order to run a sizeable VM on my disk-space-poor laptop. As I already had an ext4 partition on the USB stick, making it into a bootable rescue/installer OS was mostly a matter of debootstrap [2]. I gave it a user account, put my ssh keys on it, and also configured it to start up with DHCP on the first interface. Among other things, that means linking /etc/udev/rules.d/70-persistent-net.rules to /dev/null so that, as the rescue OS is booted on multiple machines, the first NIC remains named eth0.

On top of the base install, I copied the OpenWRT combined disk image onto the stick. Imaging a new machine then involves booting off the USB drive, overwriting the main block device with the disk image, and then resizing the root partition to use the full drive:

#!/bin/bash
gzip -dc /home/bob/openwrt-x86_64-combined-ext4.img.gz > /dev/sda
p2start=`sfdisk -d /dev/sda | grep sda2 | awk '{print $4}' | sed -e "s/,//"`
cat<<__EOM__ | fdisk /dev/sda d 2 n p 2 $p2start  w __EOM__ resize2fs /dev/sda2 # may customize root image here for each device by mounting it, etc. 

You can build disk images that match your disk size and skip repartitioning and resize2fs, but in the case that the disk is large (like mine), zero-filling all the unused space is a big waste of time. I'm sure there is a smart way to use sparse images to overcome this, but fdisk/resize2fs is the simplest thing that works for me.

Since I have my local DHCP server set up to assign known addresses and DNS names to these machines based on their MAC address, I can do the installs without a console on each machine: plug in the stick, reboot, ssh into it when it comes up, run my imaging script, shutdown and pull the stick. Easy!

Tablet guts

Tablet gutsIn case you want to know what the inside of a Samsung Galaxy Tab 3.0 looks like, I propose the following experiment: unplug one, and let it sit unused and un-powered for two months. You will then find it in the state where disconnecting and reconnecting the battery is required to get it to charge again. I am not making this up. Oh, and opening it is pretty tricky even with the proper plastic tools to do so. Since I have two of them, that’s how I lost thirty minutes of my life on Saturday.

As for why I have two: this particular model has a Marvell SoC inside, and the wireless SD8787 peripheral can be used with the upstream cfg80211-based mwifiex driver. For cozybit, I helped write an alternative mac80211 driver that can run mesh. It was a little slower and more power hungry than mwifiex, but in addition to being mesh/ibss/AP capable, had some nice-for-development features like SDIO tracing and an nl80211-testmode interface that could run firmware commands from userspace, upon which we built some test scaffolding. You can get the code for that driver today, but development is pretty much at a dead end because we needed to extend the firmware for host-based operation, and there will probably never be a redistributable firmware at this point.

I’d love to have an open firmware for the device, but as I have seen and touched the NDA encumbered firmware, it’s unlikely that I can have any hand in bringing that about.

++router

As a sometime wireless hacker, it’s a bit embarrassing to admit that I’ve had the factory firmware on my wifi router all this time, but when I first tried OpenWrt on it, ath9k was only a few months old and dropped connections all the time. Thus, I made do with the factory install but ran many of the essential services (dns, dhcp, tftp, etc) from my Linux workstation. And life continued apace.

After a recent network upgrade, I found I could no longer make my router understand ipv6, and so it was time to put the original firmware to pasture. In the intervening years, ath9k grew up, so I took another try with OpenWrt. The install took about 20 minutes, most of which was configuring the firewall and copying my existing dnsmasq config into a uci-friendly format. Everything works great and my ipv6 is back. Nice job, all involved!

I suppose I could now eat even more dogfood by running a mesh interface on one of the radios. In the past, I’ve tinkered with mesh as a wireless distribution system, but I don’t have much of a use for that currently with every room in the new place being wired. Perhaps my backyard could use expanded coverage?

vim cheat codes

Or, how I read parts of the fine manual.

Yesterday, after spending way too much time trying to get find(1) to exclude vim swapfiles, I finally had it with them cluttering up my work directories. As is usually the case when vim triggers an itch, I thought, “there must be a setting for that,” and lo, there was.

set directory=~/.vimswap//

Make that directory and all the swap files go there instead. The trailing double slashes mean the swap files get named in such a way as to avoid conflicts.

Here are some other things added to my vimrc over the last year or so.

Show whitespace issues as spelling mistakes:

match SpellBad /s+$| +zet/

I used to always set my windows to 80 columns, but then I started using ‘set number’ and then all of that went out the window, so to speak. So now I do this to show where wrapping needs to happen:

set colorcolumn=80

This hack is kind of neat, it shows +/- change markers on the edge, based on git changes in your working copy:

https://github.com/airblade/vim-gitgutter

(To make it less intrusive, I added highlight clear SignColumn.)

Once upon a time, I had a really complicated macro to search up the directory hierarchy looking for tags files. It turns out vim already does that if you add a semicolon in there (:help file-searching):

set tags=./tags;

Phone bugs

If you want to experience what it is like to be the first person to ever do something, might I suggest turning on all the debug knobs on an Android vendor kernel? Some speculative fixes over here, but there is still at least one other RCU bug on boot, and this use-after-free in the usb controller driver:

[   34.520080] msm_hsic_host msm_hsic_host: remove, state 1
[   34.525329] usb usb1: USB disconnect, device number 1
[   34.529602] usb 1-1: USB disconnect, device number 2
[   34.637023] msm_hsic_host msm_hsic_host: USB bus 1 deregistered
[   34.668945] Unable to handle kernel paging request at virtual address aaaaaae6
[   34.675201] pgd = c0004000
[   34.678497] [aaaaaae6] *pgd=00000000
[   34.681762] Internal error: Oops: 5 [#1] PREEMPT SMP ARM
[   34.686737] Modules linked in: wcn36xx_msm(O) wcn36xx(O) mac80211(O) cfg80211(O) compat(O)
[   34.694976] CPU: 1    Tainted: G        W  O  (3.4.0-g4a73a1d-00005-g311eaee-dirty #2)
[   34.702972] PC is at __gpio_get_value+0x28/0x1cc
[   34.707489] LR is at do_restart+0x24/0xd8
[   34.711486] pc : []    lr : []    psr: 60000013
[   34.711486] sp : ebcd9ed8  ip : c032a858  fp : ebcd9ef4
[   34.722930] r10: 00000000  r9 : c04dd67c  r8 : 00000000
[   34.728210] r7 : c4d81f00  r6 : 6b6b6b6b  r5 : c10099cc  r4 : aaaaaaaa
[   34.734680] r3 : 09090904  r2 : c1672f80  r1 : 00000010  r0 : 6b6b6b6b
                                                                 ^^^^^^^^ whoops
[   34.741241] Flags: nZCv  IRQs on  FIQs on  Mode SVC_32  ISA ARM  Segment kernel
[   34.748504] Control: 10c5787d  Table: acfb006a  DAC: 00000015

I guess I should try to find out where to report bugs for these (predictably) not upstream drivers, but that seems like a total pain.