Towards Better Global DMR Ham Radio ID Generation
Digital Mobile Radio (DMR) is an excellent digital mode for ham radio use, especially for HTs. It is routable via IP, so repeaters can be linked via the Internet, and inexpensive commercial radios are readily available.
Turning DMR IDs into IPs
Because it’s digital communications, DMR is IP-based, so each radio on the same network needs a globally unique ID that can fit in a 24-bit integer (0–16,777,215). In hex, this is 0xFFFFFF
. Why only 24 bits? Well, DMR is based on IPv4, and the first 8 bits are used for routing. So 24 bits + 8 bits = 32 bits, which is the length of an IPv4 address.
NOTE: I may use byte and octet interchangeably, and I’m referring to 8 bits.
For example, let’s take a radio with the ID 3108128 (0x2F6D20
).
radio ID | hex |
---|---|
3108128 | 0x2F6D20 |
For reference, these are the individual hex octets of the radio ID translated into integers:
hex | integer |
---|---|
0x2F6D20 | 3108128 (my DMR radio ID) |
0x2F____ | 47 |
0x__6D__ | 109 |
0x____20 | 32 |
In MotoTRBO parlance, the radio protocol routing octet is called the Common Air Interface (CAI), and it’s the first octet of the radio’s IPv4 address. The default CAI is 12, which means that the first byte of the IP address of the DMR radio would be 0x0C
. So if we prepend the CAI 0x0C
to the Radio ID 0x2F6D20
, we get 0x0C2F6D20
. That number in decimal is 204434720, but that doesn’t look anything like a regular IPv4 address. If you break up the 4-byte IPv4 address 0x0C2F6D20
into individual octets and then convert those into integers, you get the real IPv4 address:
hex | integer |
---|---|
0x0C2F6D20 | 204424720 (WTF?) |
0x0C______ | 12 |
0x__2F____ | 47 |
0x____6D__ | 109 |
0x______20 | 32 |
And there we have it. 12.47.109.32 is the IP address of the DMR radio with the ID 3108128 and the default CAI 12.
CAI + 1 is for devices attached via USB, and CAI + 2 is for devices attached via bluetooth:
- 13.47.109.32 is the IP address of the computer attached to the USB programming cable.
- 14.47.109.32 is the IP address of the computer attached to the bluetooth connection.
The Problem
The organizations that allocate global DMR radio IDs for ham use came up with a numbering scheme based on integer numbers and Mobile Country Code (MCC) regions, not 24-bit IP addresses. This is perfectly reasonable if you’re not a network engineer or have any clue how DMR IDs actually work, but it is very limiting in terms of distributing the IDs across the entire available 24-bit address space.
For example, my radio ID is 3108128. I’m in region 3108 (United States, Colorado), radio number 128. That’s easy for me as a human to identify, but what happens when there are more than 999 radios in a region? Some regions have already run out.
These IDs also require centralized coordination, something that certain hams categorically resist. Amateur radio is traditionally rules-based and loosely coordinated, but with the current DMR radio numbering scheme, you have to have a single global authority to ensure that each DMR radio ID is unique. Politics and cliquishness does occasionally rear up in ham radio: should that stop someone from joining a DMR network?
If you don’t have a unique address, another radio that is connected the same network may receive traffic intended for you, or vice-versa. It’s an IP address conflict.
A Potential Solution
I suppose each licensing body (e.g., the FCC) could issue several unique 24-bit numbers to each radio licensee, but every licensing body on Earth would have to coordinate or be given a block of numbers to use (like how IANA issues IP addresses).
One proposed solution I had (back in 2011) was to hash the callsign of the user in order to generate random-looking-but-probably-unique numbers. Hashing is a cryptographic function that reproducibly turns one thing into something else, and it’s a one-way trip. If I were to use the MD5 algorithm to hash K0PRW
, I would get a8b5dbe2fe44e741c0b3f0d9d53ba632
.
Suppose I stripped all the non-numeric digits from that output: I would get 85244741030953632
. Then let’s take the last 8 digits to get 30953632
. Hmm. That’s bigger than the largest 24-bit number (16777215), so let’s lop off the first digit to reduce it to 7 digits in length and we get 0953632
. That’ll work. Now I have a 24-bit number, 953632
, that I could potentially use for a DMR radio ID.
But wait a second – what if I have more than one radio? Well, how many is enough? 10? 100? Suppose we want to give each ham the opportunity to assign 10 radios to his callsign. Let’s hash K0PRW0
instead (my first radio).
- hash
K0PRW0
:a7c5744f5e868950af95cb7b0abe0127
- remove non-numbers:
75744586895095700127
- get last 8:
95700127
- Whoops, too big. Get the last 7 instead:
5700127
Q&A
All right, how does one go the other way, i.e., how do I determine a callsign from a hash?
You can’t.
Hashes are designed to be one-way cryptographic functions, meaning they encode data but can’t decode data. Most websites and services that require you to create a password aren’t really storing your password, they’re storing hashes of your password. That way if someone steals the database, they don’t get people’s passwords, just their hashes.
Well couldn’t we design a mathematical function to turn a callsign into a 24-bit integer and then back into a callsign?
Have at it. I’m no math whiz by any means, but in order to do this, you’d need to programmatically map every possible callsign to a unique number. The longest US callsigns can be in the 2x3 format, with the prefix starting with A, K, N, or W:
[AKNW][A-Z][0-9][AAA-ZZZ]
So that’s 4 * 26 * 10 * (26^3), or 18,279,040. Let’s say this is the number of potential callsigns. This alone is greater than the maximum size of a 24-bit integer (16,777,215), and we haven’t even accounted for shorter callsigns or other countries.
Realistically, though, that’s not a likely scenario.
Now we probably won’t have more than 16,777,215 hams using DMR at the same time. (If we do, then heaven help us!) So we can reexamine the hashing function, which also has an interesting property that it is designed to reduce collisions. A collision would be if two different inputs to the hashing function produced the same output. For example, if I hashed KC0BVU1
and K0PRW1
and both resulted in the same ID. I didn’t come up with a real example, because to do that, I’d have to hash every callsign possible and compare all of the outputs.
Hashing it out
Since we’re thinking in bets, let’s calculate what the odds are of any one of those 18.2 million potential callsigns would generate a collision, or the same DMR ID. Let’s assume that each one of these 18.2 million hams will have 10 DMR radios. That’s 182 million radios (in this scenario, radio manufacturers have taken over the world). I’ve written some Python code to calculate the odds.
|
|
This gives me a list like ["AA0AAA" ... "WZ9ZZZ"]
. In the real world there are special and reserved callsigns and prefixes and the like, but this is a worst-case scenario, so just go with it for now.
Now that we have a list of callsigns, let’s turn them into a list of radios.
|
|
Now I have a list like ["AA0AA0" ... "WZ9ZZZ9"]
. All that’s left to do is to hash all of these into DMR radio IDs and do some simple math to get the stats:
|
|
And you get an output something like this:
|
|
A better hash function
That was some ugly hacking to an old hashing algorithm in order to make a bigger output fit into a smaller number. But what if there was a hashing algorithm that would let you define the output size, and in doing so gave you a better distribution with fewer collisions? Turns out there is a way. The Keccak algorithm used in SHA-3 allows you to define an arbitrary output size (all the way down to 1 bit). So by changing the hash_callsign()
function to this…
|
|
…we get this output:
|
|
More realistic scenarios
In reality not every ham will be on DMR and not every DMR ham will have 10 radios. Let’s look at a more realistic situation. In fact, let’s get the actual list of current DMR amateur operators and assume they each have 2 radios with unique IDs. For that I had to write another function.
|
|
Now when I run this data through the program I get:
|
|
Not bad. There are 343 radios out of 100,722 (0.34%) that may collide if they are online at the same time. Also less than 1% of the potential radio address/ID space is used, so there’s room for growth.
Just for fun, what if every current DMR ham actually had 10 radios?
|
|
The system is scaling up quite nicely. There are now 7,565 collisions out of 503,610 radios (1.50%). The number of radios has increased x5 but the collision rate has only increased x4.4 (1.5/0.34).
Tradeoffs
So now we have to decide if this programmatic way of generating callsigns is worth it.
Advantages
- You can determine a friend’s DMR radio ID by using his callsign + SSID, even if he doesn’t have a DMR radio yet.
- No central authority needed, no politics, no power struggles
- Faster to get online with DMR: no need to wait for someone else to assign an ID
- DMR radio ID generation software could easily be placed on a public website or on a computer with no network access; online or offline availability: you pick
- Does not rely on the dwindling availability of IDs in certain MCC ITU regions
Disadvantages
- Not absolutely guaranteed to have a globally unique ID, only a high probability. Individuals would have to coordinate if collisions occur.
- May result in collisions in the event that both users are online and on the same network at the same time
- Unable to mentally localize received radio IDs based only on the number
- Requires access to a website or software program to generate your radio ID
- User database generation is more difficult (but not impossible)
- Current software systems may be predicated around having a globally unique radio ID
Another Potential Solution
Use a centralized number registry, but rethink it to be centered around how DMR numbering actually works and, therefore, be more flexible. Divide the world up into 3 octets worth of organizational units and sub-units. Each of these octets can contain 256 numbers (0–255).
For example, the country could be the 2nd octet, the region could be the 3rd octet, and the individual radio in that region could be the 4th octet. This method more logically routes traffic according to address, much how a network admin might set up subnets and routing in a large class-A (or /8) network, which is essentially what DMR is.
So if my radio IP is 12.31.81.128, that might mean that I’m in country 31 (USA), region 81 (Colorado region 1, whatever that is, probably divided geographically by population), radio unit #128. We’d figure out the DMR ID like so:
integer | hex |
---|---|
31 | 0x1f____ |
81 | 0x__51__ |
128 | 0x____80 |
2052480 (new-style DMR radio ID) | 0x1f5180 |
Another cool and logical solution. In this manner I could potentially use subnet masks and routing tables to do interesting things with DMR and a computer. It wouldn’t be completely intuitive at first, but nearby radios would still have substantially similar radio ID numbers when viewed in integer format.
Or perhaps we could group radios not by geographic area, but by function. Or by registrar, group, or club (DMR-MARC, Brandmeister, etc.), giving certain organizations certain subnets.
This alternative has many of the same drawbacks as the current method, including the need for central coordination and assigning countries, states, provinces, areas, and what-have-you to numbers. But in the end it may be better to think of DMR radio IDs in IP networking terms, rather than the current space-constrained methodology.