2015-07-27 00:35:07 +00:00
|
|
|
//
|
|
|
|
// This file is part of Dire Wolf, an amateur radio packet TNC.
|
|
|
|
//
|
|
|
|
// Copyright (C) 2011, 2013 John Langner, WB2OSZ
|
|
|
|
//
|
|
|
|
// This program is free software: you can redistribute it 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 program 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/>.
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
|
|
/*------------------------------------------------------------------
|
|
|
|
*
|
|
|
|
* Name: dedupe.c
|
|
|
|
*
|
|
|
|
* Purpose: Avoid transmitting duplicate packets which are too
|
|
|
|
* close together.
|
|
|
|
*
|
|
|
|
*
|
|
|
|
* Description: We want to avoid digipeating duplicate packets to
|
|
|
|
* to help reduce radio channel congestion with
|
|
|
|
* redundant information.
|
|
|
|
* Duplicate packets can occur in several ways:
|
|
|
|
*
|
|
|
|
* (1) A digipeated packet can loop between 2 or more
|
|
|
|
* digipeaters. For example:
|
|
|
|
*
|
|
|
|
* W1ABC>APRS,WIDE3-3
|
|
|
|
* W1ABC>APRS,mycall*,WIDE3-2
|
|
|
|
* W1ABC>APRS,mycall,RPT1*,WIDE3-1
|
|
|
|
* W1ABC>APRS,mycall,RPT1,mycall*
|
|
|
|
*
|
|
|
|
* (2) We could hear our own original transmission
|
|
|
|
* repeated by someone else. Example:
|
|
|
|
*
|
|
|
|
* mycall>APRS,WIDE3-3
|
|
|
|
* mycall>APRS,RPT1*,WIDE3-2
|
|
|
|
* mycall>APRS,RPT1*,mycall*,WIDE3-1
|
|
|
|
*
|
|
|
|
* (3) We could hear the same packet from multiple
|
|
|
|
* digipeaters (with or without the original).
|
|
|
|
*
|
|
|
|
* W1ABC>APRS,WIDE3-2
|
|
|
|
* W1ABC>APRS,RPT1*,WIDE3-2
|
|
|
|
* W1ABC>APRS,RPT2*,WIDE3-2
|
|
|
|
* W1ABC>APRS,RPT3*,WIDE3-2
|
|
|
|
*
|
|
|
|
* (4) Someone could be sending the same thing over and
|
|
|
|
* over with very little delay in between.
|
|
|
|
*
|
|
|
|
* W1ABC>APRS,WIDE3-3
|
|
|
|
* W1ABC>APRS,WIDE3-3
|
|
|
|
* W1ABC>APRS,WIDE3-3
|
|
|
|
*
|
|
|
|
* We can catch the first two by looking for 'mycall' in
|
|
|
|
* the source or digipeater fields.
|
|
|
|
*
|
|
|
|
* The other two cases require us to keep a record of what
|
|
|
|
* we transmitted recently and test for duplicates that
|
|
|
|
* should be dropped.
|
|
|
|
*
|
|
|
|
* Once we have the solution to catch cases (3) and (4)
|
|
|
|
* there is no reason for the special case of looking for
|
|
|
|
* mycall. The same technique catches all four situations.
|
|
|
|
*
|
|
|
|
* For detecting duplicates, we need to look
|
|
|
|
* + source station
|
|
|
|
* + destination
|
|
|
|
* + information field
|
|
|
|
* but NOT the changing list of digipeaters.
|
|
|
|
*
|
|
|
|
* Typically, only a checksum is kept to reduce memory
|
|
|
|
* requirements and amount of compution for comparisons.
|
|
|
|
* There is a very very small probability that two unrelated
|
|
|
|
* packets will result in the same checksum, and the
|
|
|
|
* undesired dropping of the packet.
|
|
|
|
*
|
|
|
|
* References: Original APRS specification:
|
|
|
|
*
|
|
|
|
* TBD...
|
|
|
|
*
|
|
|
|
* "The New n-N Paradigm"
|
|
|
|
*
|
|
|
|
* http://www.aprs.org/fix14439.html
|
|
|
|
*
|
|
|
|
*------------------------------------------------------------------*/
|
|
|
|
|
|
|
|
#define DEDUPE_C
|
|
|
|
|
|
|
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <assert.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <time.h>
|
|
|
|
|
|
|
|
|
|
|
|
#include "ax25_pad.h"
|
|
|
|
#include "dedupe.h"
|
|
|
|
#include "fcs_calc.h"
|
|
|
|
#include "textcolor.h"
|
2015-11-18 13:09:45 +00:00
|
|
|
#ifndef DIGITEST
|
|
|
|
#include "igate.h"
|
|
|
|
#endif
|
2015-07-27 00:35:07 +00:00
|
|
|
|
|
|
|
|
|
|
|
/*------------------------------------------------------------------------------
|
|
|
|
*
|
|
|
|
* Name: dedupe_init
|
|
|
|
*
|
|
|
|
* Purpose: Initialize the duplicate detection subsystem.
|
|
|
|
*
|
|
|
|
* Input: ttl - Number of seconds to retain information
|
|
|
|
* about recent transmissions.
|
|
|
|
*
|
|
|
|
*
|
|
|
|
* Returns: None
|
|
|
|
*
|
|
|
|
* Description: This should be called at application startup.
|
|
|
|
*
|
|
|
|
*
|
|
|
|
*------------------------------------------------------------------------------*/
|
|
|
|
|
|
|
|
static int history_time = 30; /* Number of seconds to keep information */
|
|
|
|
/* about recent transmissions. */
|
|
|
|
|
|
|
|
#define HISTORY_MAX 25 /* Maximum number of transmission */
|
|
|
|
/* records to keep. If we run out of */
|
|
|
|
/* room the oldest ones are overwritten */
|
|
|
|
/* before they expire. */
|
|
|
|
|
|
|
|
static int insert_next; /* Index, in array below, where next */
|
|
|
|
/* item should be stored. */
|
|
|
|
|
|
|
|
static struct {
|
|
|
|
|
|
|
|
time_t time_stamp; /* When the packet was transmitted. */
|
|
|
|
|
|
|
|
unsigned short checksum; /* Some sort of checksum for the */
|
|
|
|
/* source, destination, and information. */
|
|
|
|
/* is is not used anywhere else. */
|
|
|
|
|
|
|
|
short xmit_channel; /* Radio channel number. */
|
|
|
|
|
|
|
|
} history[HISTORY_MAX];
|
|
|
|
|
|
|
|
|
|
|
|
void dedupe_init (int ttl)
|
|
|
|
{
|
|
|
|
history_time = ttl;
|
|
|
|
insert_next = 0;
|
|
|
|
memset (history, 0, sizeof(history));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*------------------------------------------------------------------------------
|
|
|
|
*
|
|
|
|
* Name: dedupe_remember
|
|
|
|
*
|
|
|
|
* Purpose: Save information about a packet being transmitted so we
|
|
|
|
* can detect, and avoid, duplicates later.
|
|
|
|
*
|
|
|
|
* Input: pp - Pointer to packet object.
|
|
|
|
*
|
|
|
|
* chan - Radio channel for transmission.
|
|
|
|
*
|
|
|
|
* Returns: None
|
|
|
|
*
|
|
|
|
* Rambling: At one time, my thinking is that we want to keep track of
|
|
|
|
* ALL transmitted packets regardless of origin or type.
|
|
|
|
*
|
|
|
|
* + my beacons
|
|
|
|
* + anything from a connected application
|
|
|
|
* + anything digipeated
|
|
|
|
*
|
|
|
|
* The easiest way to catch all cases is to call dedup_remember()
|
|
|
|
* from inside tq_append().
|
|
|
|
*
|
|
|
|
* But I don't think that is the right approach.
|
|
|
|
* When acting as a KISS TNC, we should just shovel everything
|
|
|
|
* through and not question what the application is doing.
|
|
|
|
* If the connected application has a digipeating function,
|
|
|
|
* it's responsible for those decisions.
|
|
|
|
*
|
|
|
|
* My current thinking is that dedupe_remember() should be
|
|
|
|
* called BEFORE tq_append() in the digipeater case.
|
|
|
|
*
|
|
|
|
* We should also capture our own beacon transmissions.
|
|
|
|
*
|
|
|
|
*------------------------------------------------------------------------------*/
|
|
|
|
|
|
|
|
void dedupe_remember (packet_t pp, int chan)
|
|
|
|
{
|
|
|
|
history[insert_next].time_stamp = time(NULL);
|
|
|
|
history[insert_next].checksum = ax25_dedupe_crc(pp);
|
|
|
|
history[insert_next].xmit_channel = chan;
|
|
|
|
|
|
|
|
insert_next++;
|
|
|
|
if (insert_next >= HISTORY_MAX) {
|
|
|
|
insert_next = 0;
|
|
|
|
}
|
2015-11-18 13:09:45 +00:00
|
|
|
|
|
|
|
/* If we send something by digipeater, we don't */
|
|
|
|
/* want to do it again if it comes from APRS-IS. */
|
|
|
|
/* Not sure about the other way around. */
|
|
|
|
|
|
|
|
#ifndef DIGITEST
|
|
|
|
ig_to_tx_remember (pp, chan, 1);
|
|
|
|
#endif
|
2015-07-27 00:35:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*------------------------------------------------------------------------------
|
|
|
|
*
|
|
|
|
* Name: dedupe_check
|
|
|
|
*
|
|
|
|
* Purpose: Check whether this is a duplicate of another sent recently.
|
|
|
|
*
|
|
|
|
* Input: pp - Pointer to packet object.
|
|
|
|
*
|
|
|
|
* chan - Radio channel for transmission.
|
|
|
|
*
|
|
|
|
* Returns: True if it is a duplicate.
|
|
|
|
*
|
|
|
|
*
|
|
|
|
*------------------------------------------------------------------------------*/
|
|
|
|
|
|
|
|
int dedupe_check (packet_t pp, int chan)
|
|
|
|
{
|
|
|
|
unsigned short crc = ax25_dedupe_crc(pp);
|
|
|
|
time_t now = time(NULL);
|
|
|
|
int j;
|
|
|
|
|
|
|
|
for (j=0; j<HISTORY_MAX; j++) {
|
|
|
|
if (history[j].time_stamp >= now - history_time &&
|
|
|
|
history[j].checksum == crc &&
|
|
|
|
history[j].xmit_channel == chan) {
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* end dedupe.c */
|