Skip to main content

This is a new website theme. Help me improve it and give your feedback (opens in a new tab).

HamBSD Development Log 2020-05-05

Published:

Tags:

Hambsd Journal Aprs Openbsd Ax25 Planet FSFE
This blog post is more than two years old. It is preserved here in the hope that it is useful to someone, but please be aware that links may be broken and that opinions expressed here may not reflect my current views. If this is a technical article, it may no longer reflect current best practice.

I worked on HamBSD today, still looking at improvements to aprsisd(8). My focus today was on converting AX.25 packets to the TNC2 format used by APRS-IS.

I fixed the path formatting to include the asterisks for used path entries. Before packets would always appear to APRS-IS to have been heard directly, which gave some impressive range statistics for packets that had in fact been through one or two digipeaters.

A little more filtering is now implemented for packets. The control field and PID are verified to ensure the packets are APRS packets.

The entire path for AX.25 packet read from axtap(4) interface to TNC2 formatted string going out the TCP/TLS connection has bounds checks, with almost all string functions replaced with the mem* equivalents.

It wasn’t clear if it’s necessary to escape the non-printable characters in packets before sending to APRS-IS, and it turns out that actually you’re not meant to do that. I’d implemented this with the following (based roughly on how the KISS output escaping working in kiss(4):

icp = AX25_INFO_PTR(pkt_ax25, pi);
iep = pkt_ax25 + ax25_len;
while (icp < iep) {
        ibp = icp;
        while (icp < iep) {
                if (!isprint(*icp++)) {
                        icp--;
                        break;
                }
        }
        if (icp > ibp) {
                if (tp + (icp - ibp) > TNC2_MAXLINE)
                        /* Too big for a TNC2 format line */
                        return 0;
                memcpy(&pkt_tnc2[tp], ibp, icp - ibp);
                tp += icp - ibp;
        }
        if (icp < iep) {
                if (tp + 6 > TNC2_MAXLINE)
                        /* Too big for a TNC2 format line */
                        return 0;
                pkt_tnc2[tp++] = '<';
                pkt_tnc2[tp++] = '0';
                pkt_tnc2[tp++] = 'x';
                pkt_tnc2[tp++] = hex_chars[(*icp >> 4) & 0xf];
                pkt_tnc2[tp++] = hex_chars[*icp & 0xf];
                pkt_tnc2[tp++] = '>';
                icp++;
        }
}

I can now probably replace this with just a single bounds check and memcpy, but then I need to worry about logging. There is a debug log for every packet that I’ll probably just call strvis(3).

This did throw up something interesting though, so maybe this wasn’t a complete waste of time. I noticed that a “<0x0d>” was getting appended to packets coming out of my Yaesu VX-8DE. It turns out that this wasn’t a bug in my code or in aprsc (the APRS-IS server software I was connected to) but it’s actually a real byte that is tagged on the end of every APRS packet generated by the radio’s firmware. I never saw it before because aprsc would interpret this byte (ASCII carriage return) as the end of a packet, it would just be lost.

Next steps:

  • Removing the non-printable character escaping again
  • Filtering generic APRS queries (to avoid packet floods)
  • Filtering 3rd-party packets