Building and running a Packet Radio Winlink solution in a Docker container, on a Raspberry Pi

Running Packet Radio apps in a Docker container, on a Raspberry Pi? Are you mad I hear you ask?Isn’t it hard enough to get ax25 and Packet Radio up and running on the Pi anyway? Having done this a few times already, this was my thinking, and I had the crazy idea that encapsulating most of the config and setup in Dockerfiles to build preconfigured containers might be an idea worth exploring.

Installing and configuring ax25 for the Raspberry Pi and Winlink clients that use ax25 like paclink-unix or PAT can be done and work well, but the steps, as for example documented in this comprehensive guide for building and installing paclink-unix which span several pages of instructions – this can be daunting even for those more familiar with building and installing apps from source on Linux.

Since the steps are well documented, I wondered if they could be captured in a Dockerfile to automate building a self-contained and ready to run Docker container.

tldr; The short story

I did eventually did get this working building ax25 from source and using Pat, but it took me down a rabbit hole for several hours. Skip to the end if you just want to find out how to build and run the completed Docker containers.

The Longer Explanation

I could not get ax25 to work self-contained in it’s own Docker container, as I ran into issues either accessing my serial device connected to my TNC Pi from inside the Container, and/or creating an ax0 interface when running kissattach.

If you expose the serial port on the Raspberry Pi to the Container running paclink-unix:

docker run -it --device=/dev/ttyAMA0 rpi-paclink

… When trying kissattach in the container it gives:

kissattach: Error setting line discipline: TIOCSETD: Operation not permitted

Are you sure you have enabled MKISS support in the kernel

or, if you made it a module, that the module is loaded?

Alternatively, starting with –privileged:

docker run -it --privileged  -v /dev/ttyAMA0:/dev/ttyAMA0  rpi-paclink

gives:

sudo kissattach /dev/ttyAMA0 1

kissattach: SIOCSIFMTU: No such device

I was initially trying to get this working because I wanted to run paclink-unix for Winlink email. Part of this app when you run the make script it will create wl2kserial and wl2ktelnet, but not wl2kax25. I had already run into this before, as it seems it doesn’t compile unless it has a later version of the ax25 stack compiled from source.

I changed gears and looked for how you could share an up and running ax25 stack from the Docker host, and it turns out this is easy to do, you just pass the –network=host param, and then ax0 appears in your network interfaces in your container.

The next issue I ran into is that configuring postfix as your email transport take some effort. bazaudi.com have a very detailed set of instructions, but I couldn’t get it working for outgoing email. It was working for incoming via wl2ktelnet and wl2kax25, but only for receiving emails and not sending. Time to try something else.

Installing and configuring Pat in a Container

I tried to get Pat working once before – I think I had it working on either a Debian or Ubuntu box, but couldn’t get it working on Raspbian on a Pi. I decided to try it again in this setup, and reusing the base image with ax25 already compiled from source, it was actually very easy to get Pat up and running.

This is dependent on having ax25 installed and configure on the host Pi OS, and the shared to the container with –network=host. I know, this seems redundant, but this is the only way I managed to get this working.

My base image for Raspbian including ax25 built form source is here: https://github.com/kevinhooke/DockerRPiAX25FromSource 

To build the image passing in the parameterized value for your callsign (passing your callsign in place of ‘yourcall’):

docker build --build-param MYCALL=yourcall -t rpi-ax25 .

Next build an image containing Pat, based on the image we just built – the source for this Dockerfile is here: https://github.com/kevinhooke/DockerRPiPATWinlink.git

Build this image with:

docker build --build-arg MYCALL=yourcall --build-arg MYCALLSSID=yourcall-1 
    --build-arg MYLOC=AA11aa --build-arg WINLINKPASS=yourwlpass 
    -t rpi-wl-pat .

Now to start it up remember we’re relying on an ax25 connection from the host, and we’re going to share it with the guest container. My TNC-Pi board connected to my Raspberry Pi is available on serial device as /dev/ttyAMA0, so I start up my ax0 port like:

sudo kissattach /dev/ttyAMA0 1 10.1.1.1

Next, run the container as a daemon, share the host networking, and expose port 8080 so we can access the Pat webapp:

docker run -d –network=host -p 8080:8080 rpi-wl-pat

Now let’s fire up the webapp:

Looks good, this is the Pat inbox. Let’s send a test email to myself – this is going to be sent using Packet over 2m VHF via my local Winlink gateway, AG6QO-10. I have this preconfigured in my Pat config file. You can configure this yourself before creating the rpi-wl-pat image:

Remember the Pat webapp that we’re interacting with here is running in a Docker container, on a Raspberry Pi. I just happen to be accessing it remotely from my Mac. For mobile operation or out in the field, you could attach a touchscreen to the Pi and connect a keyboard and mouse too.

To send my email over RF to the Winlink gateway, click Action, then Connect:

In the Pat status window we now see a log of the Packet exchange between my station and AG6QO-10 via BERR37:

A few seconds later the email arrives in my gmail inbox:

If I reply to the email in gmail, it will go back over the Winlink network, and be waiting for me when I connect to the Winlink gateway again over RF. Let’s give that a go in Pat – select Action and Connect, we connect to AG6QO0-10 again over 2m VHF, and now the reply is in my inbox in Pat:

Success!

Appending values to the end of a file from a Unix shell

Some things you do repeatedly from a *nix shell are incredibly useful and time-saving that you do them without thinking about it. Say for example you need to add a file or directory name to a file like .gitignore. On Windows you might open an editor and add the new lines to the end of the file and save it, but in a *nix shell (I imagine there’s a comparable approach maybe using something like Windows Powershell too), you can do:

echo "newfile" >> .gitignore

and you’re done.

Packet Radio with Debian Hamradio Pure Blend

I stumbled across this concept of ‘Debian Pure Blends‘ a couple of days back. These are Debian distros that are configured with software preinstalled for a specific purpose, like graphic design, and astronomy. The Ham Radio distro caught my eye as it’s preconfigured with ax25 and Direwolf for Packet Radio.

The trouble is, while it has these included in the distro so you get them out of the box, it doesn’t seem they’re configured, and worse, the ax25 support doesn’t appear to work with Direwolf.

Here’s a few notes of my experimenting:

Direwolf uses a direwolf.conf file in your home directory which you customize with your callsign and setup to connect with your soundcard input and output. There doesn’t seem to be a copy of this file anywhere on the filesystem. The file is usually created if you’re building/installing from source by running ‘make install-conf’. I searched my fresh Debian install and couldn’t find a copy of direwolf.conf anywhere, so already being familiar with Direwolf, I decided to uninstall the pre-installed version (apt-get remove direwolf) and build/install from source unstead. See my previous notes on how to do this.

Immediately ran into the libasound library missing:

/usr/bin/ld: cannot find -lasound
 collect2: error: ld returned 1 exit status
 Makefile.linux:257: recipe for target 'fsk_fast_filter.h' failed
 make: *** [fsk_fast_filter.h] Error 1

This is fixed by installing libasound:

apt-get install libasound2-dev

 

Edit /etc/ax25/axports and add a line like this:
1 YOURCALL-1 1200 255 2 2m packet

Starting up direwolf for the first time:

 kev@kh-debian:/etc/ax25$ direwolf -t 0 -p
 Dire Wolf version 1.3

Reading config file /home/kev/direwolf.conf
 Audio device for both receive and transmit: default (channel 0)
 Channel 0: 1200 baud, AFSK 1200 & 2200 Hz, E+, 44100 sample rate.
 ERROR can't open device /dev/ttyUSB0 for channel 0 PTT control.
 Permission denied
 Note: PTT not configured for channel 0. (Ignore this if using VOX.)
 Ready to accept KISS client application on port 8001 ...
 Ready to accept AGW client application 0 on port 8000 ...
 Virtual KISS TNC is available on /dev/pts/1
 WARNING - Dire Wolf will hang eventually if nothing is reading from it.
 Created symlink /tmp/kisstnc -> /dev/pts/1

Looks like /dev/ttyUSB0 cannot be opened for my PTT on my Rigblaster Plug n Play.

Following instructions from here, as root, I did:

usermod -a -G dialout kev

and then logged out and logged back in again. That fixed that issue.

The input volume was low, so I bumped up the mic slider in the top right to about half way, and now the input volume is better:

KG6SJT-10 audio level = 43(20/19) [NONE] |||||||__
 [0.3] KG6SJT-10>ID:Network Node (YCARES)
 Unknown message type N, motorcycle

 

Next up, starting Direwolf and then starting up my ax25 stack with kissattach and mkiss (which I’ve covered before here), I was getting a Permission Denied error:

kev@kh-debian:~$ sudo kissattach /dev/ptmx 1 44.56.4.118
AX.25 port 1 bound to device ax0
Awaiting client connects on
/dev/pts/4

Followed by:

kev@kh-debian:~$ sudo mkiss /tmp/kisstnc /dev/pts/4
 mkiss: open: Permission denied

I posted a question about this on the Direwolf group on Yahoo Groups here. Since it looks like mkiss is getting permission denied accessing /tmp/kisstnc from Direwolf, I started Direwolf with a sudo and this avoided this error. Direwolf shouldn’t need to run with sudo permissions so something’s not quite right, but this did allow me to get up and running, and then I could ‘axcall 1 kberr’ to make a connection to nearest packet node.

To get to this point I could have installed a vanilla version of Debian, Direwolf from source, and ax25, and I probably would have got to the same point in about the same about of time, but when I have time I’ll take a look at the other apps that get preinstalled.

RT73 wifi driver on Debian 8 completely filled my hard disk with syslog messages

Just installed Debian Hamradio Pure Blend, and I thought a 20GB partition for / would be plenty, but after a day I was getting disk full errors. So I shrunk my /home partition and extended my / partition up to 50GB. A day later it was at 100% again (I had just deleted some log file files to free up some space):

kev@kh-debian:/var/log$ df -h

Filesystem      Size  Used Avail Use% Mounted on
/dev/sda9        58G   53G  2.5G  96% /
/dev/sda10       20G  279M   19G   2% /home

Guessing something was up, I cd’d into /var/log to see what was showing up in my log files and was surprised to see this:

kev@kh-debian:/var/log$ ls -lS

total 49743852

-rw-r----- 1 root              adm  15123453253 Dec 24 18:37 syslog
-rw-r----- 1 root              adm  13204397200 Dec 24 18:37 kern.log
-rw-r----- 1 root              adm  12416440518 Dec 24 18:37 daemon.log
-rw-r----- 1 root              adm  10053382069 Dec 24 18:37 messages
-rw-r----- 1 root              adm    139506083 Dec 23 07:04 syslog.2.gz
-rw-rw-r-- 1 root              utmp      292292 Dec 24 18:33 lastlog

Ok, ok. That’s where my disk space has gone.

Looking in syslog, I’ve got these messages repeating about 100 times a second:

Dec 24 18:55:01 kh-debian wpa_supplicant[862]: wlan0: Failed to initialize driver interface
Dec 24 18:55:01 kh-debian NetworkManager[696]: <error> [1482634501.576472] [supplicant-manager/nm-supplicant-interface.c:856] interface_add_cb(): (wlan0): error adding interface: wpa_supplicant couldn't grab this interface.
Dec 24 18:55:01 kh-debian NetworkManager[696]: <info> (wlan0): supplicant interface state: starting -> down
Dec 24 18:55:01 kh-debian kernel: [ 2026.757616] ieee80211 phy0: rt2x00lib_request_firmware: Info - Loading firmware file 'rt73.bin'
Dec 24 18:55:01 kh-debian kernel: [ 2026.757646] rt73usb 1-7:1.0: firmware: failed to load rt73.bin (-2)
Dec 24 18:55:01 kh-debian kernel: [ 2026.757652] rt73usb 1-7:1.0: Direct firmware load failed with error -2
Dec 24 18:55:01 kh-debian kernel: [ 2026.757656] rt73usb 1-7:1.0: Falling back to user helper
Dec 24 18:55:01 kh-debian wpa_supplicant[862]: Could not set interface wlan0 flags (UP): Cannot allocate memory
Dec 24 18:55:01 kh-debian wpa_supplicant[862]: nl80211: Could not set interface 'wlan0' UP

 Following the install instructions here: https://wiki.debian.org/WiFi/rt73 – and then rebooted, problem solved. Log messages gone.