Skip to content
This repository has been archived by the owner on Aug 1, 2020. It is now read-only.

Commit

Permalink
icao_filter.[ch] from the experimental branch.
Browse files Browse the repository at this point in the history
  • Loading branch information
mutability committed Jan 20, 2015
1 parent 270a22e commit 0433ed3
Show file tree
Hide file tree
Showing 7 changed files with 197 additions and 65 deletions.
4 changes: 2 additions & 2 deletions Makefile
Expand Up @@ -21,10 +21,10 @@ all: dump1090 view1090
%.o: %.c dump1090.h
$(CC) $(CPPFLAGS) $(CFLAGS) $(EXTRACFLAGS) -c $< -o $@

dump1090: dump1090.o anet.o interactive.o mode_ac.o mode_s.o net_io.o crc.o demod_2000.o demod_2400.o stats.o cpr.o
dump1090: dump1090.o anet.o interactive.o mode_ac.o mode_s.o net_io.o crc.o demod_2000.o demod_2400.o stats.o cpr.o icao_filter.o
$(CC) -g -o $@ $^ $(LIBS) $(LIBS_RTL) $(LDFLAGS)

view1090: view1090.o anet.o interactive.o mode_ac.o mode_s.o net_io.o crc.o stats.o cpr.o
view1090: view1090.o anet.o interactive.o mode_ac.o mode_s.o net_io.o crc.o stats.o cpr.o icao_filter.o
$(CC) -g -o $@ $^ $(LIBS) $(LDFLAGS)

clean:
Expand Down
7 changes: 4 additions & 3 deletions dump1090.c
Expand Up @@ -120,8 +120,7 @@ void modesInit(void) {

// Allocate the various buffers used by Modes
Modes.trailing_samples = (Modes.oversample ? (MODES_OS_PREAMBLE_SAMPLES + MODES_OS_LONG_MSG_SAMPLES) : (MODES_PREAMBLE_SAMPLES + MODES_LONG_MSG_SAMPLES)) + 16;
if ( ((Modes.icao_cache = (uint32_t *) malloc(sizeof(uint32_t) * MODES_ICAO_CACHE_LEN * 2) ) == NULL) ||
((Modes.pFileData = (uint16_t *) malloc(MODES_ASYNC_BUF_SIZE) ) == NULL) ||
if ( ((Modes.pFileData = (uint16_t *) malloc(MODES_ASYNC_BUF_SIZE) ) == NULL) ||
((Modes.magnitude = (uint16_t *) calloc(MODES_ASYNC_BUF_SAMPLES+Modes.trailing_samples, 2) ) == NULL) ||
((Modes.maglut = (uint16_t *) malloc(sizeof(uint16_t) * 256 * 256) ) == NULL) ||
((Modes.log10lut = (uint16_t *) malloc(sizeof(uint16_t) * 256 * 256) ) == NULL) )
Expand All @@ -131,7 +130,6 @@ void modesInit(void) {
}

// Clear the buffers that have just been allocated, just in-case
memset(Modes.icao_cache, 0, sizeof(uint32_t) * MODES_ICAO_CACHE_LEN * 2);
memset(Modes.pFileData,127, MODES_ASYNC_BUF_SIZE);

// Validate the users Lat/Lon home location inputs
Expand Down Expand Up @@ -218,6 +216,7 @@ void modesInit(void) {

// Prepare error correction tables
modesChecksumInit(Modes.nfix_crc);
icaoFilterInit();
}
//
// =============================== RTLSDR handling ==========================
Expand Down Expand Up @@ -607,6 +606,8 @@ void backgroundTasks(void) {

time_t now = time(NULL);

icaoFilterExpire();

if (Modes.net) {
modesNetPeriodicWork();
}
Expand Down
4 changes: 1 addition & 3 deletions dump1090.h
Expand Up @@ -153,8 +153,6 @@
#define MODES_OUT_FLUSH_SIZE (MODES_OUT_BUF_SIZE - 256)
#define MODES_OUT_FLUSH_INTERVAL (60)

#define MODES_ICAO_CACHE_LEN 1024 // Power of two required
#define MODES_ICAO_CACHE_TTL 60 // Time to live of cached addresses
#define MODES_UNIT_FEET 0
#define MODES_UNIT_METERS 1

Expand Down Expand Up @@ -230,6 +228,7 @@
#include "demod_2400.h"
#include "stats.h"
#include "cpr.h"
#include "icao_filter.h"


//======================== structure declarations =========================
Expand Down Expand Up @@ -308,7 +307,6 @@ struct { // Internal state
uint64_t timestampBlk; // Timestamp of the start of the current block
struct timeb stSystemTimeBlk; // System time when RTL passed us currently processing this block
int fd; // --ifile option file descriptor
uint32_t *icao_cache; // Recently seen ICAO addresses cache
uint16_t *maglut; // I/Q -> Magnitude lookup table
uint16_t *log10lut; // Magnitude -> log10 lookup table
int exit; // Exit from the main loop when true
Expand Down
140 changes: 140 additions & 0 deletions icao_filter.c
@@ -0,0 +1,140 @@
// Part of dump1090, a Mode S message decoder for RTLSDR devices.
//
// icao_filter.c: hashtable for ICAO addresses
//
// Copyright (c) 2014,2015 Oliver Jowett <oliver@mutability.co.uk>
//
// This file is free software: you may copy, redistribute and/or modify it
// under the terms of the GNU General Public License as published by the
// Free Software Foundation, either version 2 of the License, or (at your
// option) any later version.
//
// This file is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.

#include "dump1090.h"

// hash table size, must be a power of two:
#define ICAO_FILTER_SIZE 4096

// Seconds between filter expiry flips:
#define MODES_ICAO_FILTER_TTL 60

// Open-addressed hash table with linear probing.
// We store each address twice to handle Address/Parity and Data/Parity
// which need to match on a partial address (top 16 bits only).

// Maintain two tables and switch between them to age out entries.

static uint32_t icao_filter_a[ICAO_FILTER_SIZE];
static uint32_t icao_filter_b[ICAO_FILTER_SIZE];
static uint32_t *icao_filter_active;

static uint32_t icaoHash(uint32_t a)
{
// Jenkins one-at-a-time hash, unrolled for 3 bytes
uint32_t hash = 0;

hash += a & 0xff;
hash += hash << 10;
hash ^= hash >> 6;

hash += (a >> 8) & 0xff;
hash += (hash << 10);
hash ^= (hash >> 6);

hash += (a >> 16) & 0xff;
hash += (hash << 10);
hash ^= (hash >> 6);

hash += (hash << 3);
hash ^= (hash >> 11);
hash += (hash << 15);

return hash & (ICAO_FILTER_SIZE-1);
}

void icaoFilterInit()
{
memset(icao_filter_a, 0, sizeof(icao_filter_a));
memset(icao_filter_b, 0, sizeof(icao_filter_b));
icao_filter_active = icao_filter_a;
}

void icaoFilterAdd(uint32_t addr)
{
uint32_t h = icaoHash(addr);
while (icao_filter_active[h] && icao_filter_active[h] != addr)
h = (h+1) & (ICAO_FILTER_SIZE-1);
if (!icao_filter_active[h])
icao_filter_active[h] = addr;

// also add with a zeroed top byte, for handling DF20/21 with Data Parity
h = icaoHash(addr & 0x00ffff);
while (icao_filter_active[h] && (icao_filter_active[h] & 0x00ffff) != (addr & 0x00ffff))
h = (h+1) & (ICAO_FILTER_SIZE-1);
if (!icao_filter_active[h])
icao_filter_active[h] = addr;
}

int icaoFilterTest(uint32_t addr)
{
uint32_t h, h0;

h0 = h = icaoHash(addr);
while (icao_filter_a[h] && icao_filter_a[h] != addr)
h = (h+1) & (ICAO_FILTER_SIZE-1);
if (icao_filter_a[h])
return 1;

h = h0;
while (icao_filter_b[h] && icao_filter_b[h] != addr)
h = (h+1) & (ICAO_FILTER_SIZE-1);
if (icao_filter_b[h])
return 1;

return 0;
}

uint32_t icaoFilterTestFuzzy(uint32_t partial)
{
uint32_t h, h0;

partial &= 0x00ffff;
h0 = h = icaoHash(partial);
while (icao_filter_a[h] && (icao_filter_a[h] & 0x00ffff) != partial)
h = (h+1) & (ICAO_FILTER_SIZE-1);
if (icao_filter_a[h])
return icao_filter_a[h];

h = h0;
while (icao_filter_b[h] && (icao_filter_b[h] & 0x00ffff) != partial)
h = (h+1) & (ICAO_FILTER_SIZE-1);
if (icao_filter_b[h])
return icao_filter_b[h];

return 0;
}

// call this periodically:
void icaoFilterExpire()
{
static time_t next_flip = 0;
time_t now = time(NULL);

if (now >= next_flip) {
if (icao_filter_active == icao_filter_a) {
memset(icao_filter_b, 0, sizeof(icao_filter_b));
icao_filter_active = icao_filter_b;
} else {
memset(icao_filter_a, 0, sizeof(icao_filter_a));
icao_filter_active = icao_filter_a;
}
next_flip = now + MODES_ICAO_FILTER_TTL;
}
}
41 changes: 41 additions & 0 deletions icao_filter.h
@@ -0,0 +1,41 @@
// Part of dump1090, a Mode S message decoder for RTLSDR devices.
//
// icao_filter.c: prototypes for ICAO address hashtable
//
// Copyright (c) 2014,2015 Oliver Jowett <oliver@mutability.co.uk>
//
// This file is free software: you may copy, redistribute and/or modify it
// under the terms of the GNU General Public License as published by the
// Free Software Foundation, either version 2 of the License, or (at your
// option) any later version.
//
// This file is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.

#ifndef DUMP1090_ICAO_FILTER_H
#define DUMP1090_ICAO_FILTER_H

// Call once:
void icaoFilterInit();

// Add an address to the filter
void icaoFilterAdd(uint32_t addr);

// Test if the given address matches the filter
int icaoFilterTest(uint32_t addr);

// Test if the top 16 bits match any previously added address.
// If they do, returns an arbitrary one of the matched
// addresses. Returns 0 on failure.
uint32_t icaoFilterTestFuzzy(uint32_t partial);

// Call this periodically to allow the filter to expire
// old entries.
void icaoFilterExpire();

#endif
54 changes: 7 additions & 47 deletions mode_s.c
Expand Up @@ -67,46 +67,6 @@ int modesMessageLenByType(int type) {
return (type & 0x10) ? MODES_LONG_MSG_BITS : MODES_SHORT_MSG_BITS ;
}

//=========================================================================
//
// Hash the ICAO address to index our cache of MODES_ICAO_CACHE_LEN
// elements, that is assumed to be a power of two
//
uint32_t ICAOCacheHashAddress(uint32_t a) {
// The following three rounds wil make sure that every bit affects
// every output bit with ~ 50% of probability.
a = ((a >> 16) ^ a) * 0x45d9f3b;
a = ((a >> 16) ^ a) * 0x45d9f3b;
a = ((a >> 16) ^ a);
return a & (MODES_ICAO_CACHE_LEN-1);
}
//
//=========================================================================
//
// Add the specified entry to the cache of recently seen ICAO addresses.
// Note that we also add a timestamp so that we can make sure that the
// entry is only valid for MODES_ICAO_CACHE_TTL seconds.
//
void addRecentlySeenICAOAddr(uint32_t addr) {
uint32_t h = ICAOCacheHashAddress(addr);
Modes.icao_cache[h*2] = addr;
Modes.icao_cache[h*2+1] = (uint32_t) time(NULL);
}
//
//=========================================================================
//
// Returns 1 if the specified ICAO address was seen in a DF format with
// proper checksum (not xored with address) no more than * MODES_ICAO_CACHE_TTL
// seconds ago. Otherwise returns 0.
//
int ICAOAddressWasRecentlySeen(uint32_t addr) {
uint32_t h = ICAOCacheHashAddress(addr);
uint32_t a = Modes.icao_cache[h*2];
uint32_t t = Modes.icao_cache[h*2+1];
uint64_t tn = time(NULL);

return ( (a) && (a == addr) && ( (tn - t) <= MODES_ICAO_CACHE_TTL) );
}
//
//=========================================================================
//
Expand Down Expand Up @@ -342,7 +302,7 @@ void decodeModesMessage(struct modesMessage *mm, unsigned char *msg) {
// If we correct, validate ICAO addr to help filter birthday paradox solutions.
if (mm->correctedbits) {
uint32_t ulAddr = (msg[1] << 16) | (msg[2] << 8) | (msg[3]);
if (!ICAOAddressWasRecentlySeen(ulAddr))
if (!icaoFilterTest(ulAddr))
mm->correctedbits = 0;
}
}
Expand All @@ -357,11 +317,11 @@ void decodeModesMessage(struct modesMessage *mm, unsigned char *msg) {

if ((mm->crcok = (0 == mm->crc))) {
// DF 11 : if crc == 0 try to populate our ICAO addresses whitelist.
addRecentlySeenICAOAddr(mm->addr);
icaoFilterAdd(mm->addr);
} else if (mm->crc < 80) {
mm->crcok = ICAOAddressWasRecentlySeen(mm->addr);
mm->crcok = icaoFilterTest(mm->addr);
if (mm->crcok) {
addRecentlySeenICAOAddr(mm->addr);
icaoFilterAdd(mm->addr);
}
}

Expand All @@ -371,7 +331,7 @@ void decodeModesMessage(struct modesMessage *mm, unsigned char *msg) {

if ((mm->crcok = (0 == mm->crc))) {
// DF 17 : if crc == 0 try to populate our ICAO addresses whitelist.
addRecentlySeenICAOAddr(mm->addr);
icaoFilterAdd(mm->addr);
}

} else if (mm->msgtype == 18) { // DF 18
Expand All @@ -380,13 +340,13 @@ void decodeModesMessage(struct modesMessage *mm, unsigned char *msg) {

if ((mm->crcok = (0 == mm->crc))) {
// DF 18 : if crc == 0 try to populate our ICAO addresses whitelist.
addRecentlySeenICAOAddr(mm->addr);
icaoFilterAdd(mm->addr);
}

} else { // All other DF's
// Compare the checksum with the whitelist of recently seen ICAO
// addresses. If it matches one, then declare the message as valid
mm->crcok = ICAOAddressWasRecentlySeen(mm->addr = mm->crc);
mm->crcok = icaoFilterTest(mm->addr = mm->crc);
}

// If we're checking CRC and the CRC is invalid, then we can't trust any
Expand Down
12 changes: 2 additions & 10 deletions view1090.c
Expand Up @@ -96,16 +96,6 @@ void view1090Init(void) {
}
#endif

// Allocate the various buffers used by Modes
if ( NULL == (Modes.icao_cache = (uint32_t *) malloc(sizeof(uint32_t) * MODES_ICAO_CACHE_LEN * 2)))
{
fprintf(stderr, "Out of memory allocating data buffer.\n");
exit(1);
}

// Clear the buffers that have just been allocated, just in-case
memset(Modes.icao_cache, 0, sizeof(uint32_t) * MODES_ICAO_CACHE_LEN * 2);

// Validate the users Lat/Lon home location inputs
if ( (Modes.fUserLat > 90.0) // Latitude must be -90 to +90
|| (Modes.fUserLat < -90.0) // and
Expand All @@ -127,6 +117,7 @@ void view1090Init(void) {

// Prepare error correction tables
modesChecksumInit(Modes.nfix_crc);
icaoFilterInit();
}

// Set up data connection
Expand Down Expand Up @@ -296,6 +287,7 @@ int main(int argc, char **argv) {

// Keep going till the user does something that stops us
while (!Modes.exit) {
icaoFilterExpire();
interactiveRemoveStaleAircrafts();
interactiveShowData();
if ((fd == ANET_ERR) || (recv(c->fd, pk_buf, sizeof(pk_buf), MSG_PEEK | MSG_DONTWAIT) == 0)) {
Expand Down

0 comments on commit 0433ed3

Please sign in to comment.