882 lines
33 KiB
C
882 lines
33 KiB
C
|
/************************************************************************/
|
||
|
/* */
|
||
|
/* ***** ***** */
|
||
|
/* ***** ***** */
|
||
|
/* ***** ***** */
|
||
|
/* ***** ***** */
|
||
|
/* *************** *************** */
|
||
|
/* ***************** ***************** */
|
||
|
/* *************** *************** */
|
||
|
/* ***** ***** TheNetNode */
|
||
|
/* ***** ***** Portable */
|
||
|
/* ***** ***** Network */
|
||
|
/* ***** ***** Software */
|
||
|
/* */
|
||
|
/* File src/l3vc.c (maintained by: ???) */
|
||
|
/* */
|
||
|
/* This file is part of "TheNetNode" - Software Package */
|
||
|
/* */
|
||
|
/* Copyright (C) 1998 - 2008 NORD><LINK e.V. Braunschweig */
|
||
|
/* */
|
||
|
/* This program is free software; you can redistribute it and/or modify */
|
||
|
/* it under the terms of the NORD><LINK ALAS (Allgemeine Lizenz fuer */
|
||
|
/* Amateurfunk Software) as published by Hans Georg Giese (DF2AU) */
|
||
|
/* on 13/Oct/1992; either version 1, or (at your option) any later */
|
||
|
/* version. */
|
||
|
/* */
|
||
|
/* This program is distributed WITHOUT ANY WARRANTY only for further */
|
||
|
/* development and learning purposes. See the ALAS (Allgemeine Lizenz */
|
||
|
/* fuer Amateurfunk Software). */
|
||
|
/* */
|
||
|
/* You should have received a copy of the NORD><LINK ALAS (Allgemeine */
|
||
|
/* Lizenz fuer Amateurfunk Software) along with this program; if not, */
|
||
|
/* write to NORD><LINK e.V., Hinter dem Berge 5, D-38108 Braunschweig */
|
||
|
/* */
|
||
|
/* Dieses Programm ist PUBLIC DOMAIN, mit den Einschraenkungen durch */
|
||
|
/* die ALAS (Allgemeine Lizenz fuer Amateurfunk Software), entweder */
|
||
|
/* Version 1, veroeffentlicht von Hans Georg Giese (DF2AU), */
|
||
|
/* am 13.Oct.1992, oder (wenn gewuenscht) jede spaetere Version. */
|
||
|
/* */
|
||
|
/* Dieses Programm wird unter Haftungsausschluss vertrieben, aus- */
|
||
|
/* schliesslich fuer Weiterentwicklungs- und Lehrzwecke. Naeheres */
|
||
|
/* koennen Sie der ALAS (Allgemeine Lizenz fuer Amateurfunk Software) */
|
||
|
/* entnehmen. */
|
||
|
/* */
|
||
|
/* Sollte dieser Software keine ALAS (Allgemeine Lizenz fuer Amateur- */
|
||
|
/* funk Software) beigelegen haben, wenden Sie sich bitte an */
|
||
|
/* NORD><LINK e.V., Hinter dem Berge 5, D-38108 Braunschweig */
|
||
|
/* */
|
||
|
/************************************************************************/
|
||
|
|
||
|
#include "tnn.h"
|
||
|
#include "l3local.h"
|
||
|
|
||
|
/* definitionen */
|
||
|
/* FlexNet 0er Frames */
|
||
|
|
||
|
/* BYTE 0 */
|
||
|
#define SOFTKENNUNG 0x23
|
||
|
/* Bit 0..2 Software */
|
||
|
/* 000 Flex Net */
|
||
|
/* 001 BayCom Node */
|
||
|
/* 010 Digi Ware */
|
||
|
/* 011 TheNetNode */
|
||
|
/* 100 SNet */
|
||
|
/* 101 XNet */
|
||
|
/* 110 .. 111 reserve */
|
||
|
#define S_FLEXNET 0
|
||
|
#define S_BAYCOM 1
|
||
|
#define S_DIGIWARE 2
|
||
|
#define S_THENET 3
|
||
|
#define S_SNET 4
|
||
|
#define S_XNET 5
|
||
|
/* Bit 3 Virtuelle Adressierung, 0 = disable, 1 = enable */
|
||
|
#define S_VFLAG 8
|
||
|
/* Bit 4 frei , 0 */
|
||
|
/* Bit 5 frei , 1 */
|
||
|
/* Bit 6 frei , 0 */
|
||
|
/* Bit 7 frei , 0 */
|
||
|
|
||
|
/* BYTE 1 Version */
|
||
|
#define SOFTVERSION 0x11
|
||
|
|
||
|
#define TOKEN_ER 0
|
||
|
#define TOKEN_ER_REQ 1
|
||
|
#define TOKEN_ICH 2
|
||
|
#define TOKEN_ICH_REQ 3
|
||
|
|
||
|
#define LOWER -1
|
||
|
#define HIGHER 1
|
||
|
#define SAME 0
|
||
|
|
||
|
/* SSID fuer FlexNet aufbereiten */
|
||
|
#define FLEXSSID(id) (((id[L2IDLEN-1] & 0x1E) >> 1) + '0')
|
||
|
|
||
|
/* Messzeit in Sekunden, hat beim FlexNet nur einen Sinn,
|
||
|
* wenn noch kein Connect steht, ansonsten gibt diese
|
||
|
* Zeit nur die Pausen zwischen zwei Local-Tests an
|
||
|
*/
|
||
|
|
||
|
static int callcompare(char *, char *);
|
||
|
static void flex_tx_rtt_query(PEER *pp);
|
||
|
static void flex_tx_init(PEER *pp);
|
||
|
static void flex_tx_routes(PEER *pp);
|
||
|
static void flex_route_reply(char *);
|
||
|
static MBHEAD *getfbp(UBYTE, LNKBLK *, const char *format, ...);
|
||
|
static void sendfbp(MBHEAD *);
|
||
|
static void flex_tx_rtt_reply(PEER *);
|
||
|
|
||
|
void
|
||
|
local_flex_srv(void)
|
||
|
{
|
||
|
PEER *pp;
|
||
|
int i;
|
||
|
int max_peers = netp->max_peers;
|
||
|
|
||
|
for (i = 0, pp = netp->peertab; i < max_peers; i++, pp++)
|
||
|
if (pp->used)
|
||
|
{
|
||
|
if (pp->typ == LOCAL_M)
|
||
|
{
|
||
|
if (pp->rttstart) /* Messung unterwegs? */
|
||
|
continue;
|
||
|
if (pp->nbrl2l) /* ... Leichen abwerfen */
|
||
|
{
|
||
|
/* Disconnect einleiten. */
|
||
|
discnbp(pp);
|
||
|
/* Deaktiv markieren. */
|
||
|
pp->nbrl2l = NULL;
|
||
|
}
|
||
|
else
|
||
|
if (pp->rtt_time == 0) /* Messzeit abgelaufen? */
|
||
|
{
|
||
|
if (connbr(pp))
|
||
|
pp->rttstart = tic10; /* Start Zeitmessung */
|
||
|
}
|
||
|
else
|
||
|
pp->rtt_time--;
|
||
|
}
|
||
|
else
|
||
|
if (pp->typ == FLEXNET)
|
||
|
{
|
||
|
if (pp->nbrl2l == NULL) /* gibt es einen Link? */
|
||
|
{
|
||
|
#ifdef PORT_L2_CONNECT_TIME
|
||
|
if (pp->l2link->sabmtime == 0)
|
||
|
{
|
||
|
#endif
|
||
|
#ifdef PORT_L2_CONNECT_RETRY
|
||
|
|
||
|
if (connbr(pp) == FALSE) /* sonst neu connecten */
|
||
|
continue;
|
||
|
|
||
|
pp->nbrl2l->tries = (UBYTE)portpar[pp->nbrl2l->liport].retry - (UBYTE)portpar[pp->nbrl2l->liport].l2_connect_retry;
|
||
|
#else
|
||
|
connbr(pp); /* sonst neu connecten */
|
||
|
#endif
|
||
|
}
|
||
|
#ifdef PORT_L2_CONNECT_TIME
|
||
|
else
|
||
|
pp->l2link->sabmtime--;
|
||
|
continue;
|
||
|
}
|
||
|
#endif
|
||
|
if (pp->nbrl2l->state < L2SIXFER)
|
||
|
continue; /* und ist er aktiv? */
|
||
|
if (pp->rttstart) /* Laufzeitmessung */
|
||
|
{ /* unterwegs? */
|
||
|
#ifndef FLEXTIMEFIX
|
||
|
if (tic10 - pp->rttstart >= 6000L) /* maximal 60 Sekunden */
|
||
|
#else
|
||
|
if (tic10 - pp->rttstart >= 18000L) /* maximal 180 Sekunden */
|
||
|
#endif /* FLEXTIMEFIX */
|
||
|
discnbp(pp); /* sonst abwerfen */
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
if (pp->rtt_time == 0) /* Zeit fuer neue Messung */
|
||
|
flex_tx_rtt_query(pp);
|
||
|
else
|
||
|
pp->rtt_time--; /* sonst weiterwarten */
|
||
|
|
||
|
if (pp->quality)
|
||
|
{
|
||
|
if (pp->brotim == 0) /* Zeit fuer neue Meldung? */
|
||
|
flex_tx_routes(pp); /* Meldungen uebertragen */
|
||
|
else
|
||
|
pp->brotim--;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*----------------------------------------------------------------------*/
|
||
|
/* eine Status-Aenderung fuer die LOCALS (gemessene) behandeln */
|
||
|
/*----------------------------------------------------------------------*/
|
||
|
void local_status(PEER *pp, WORD status)
|
||
|
{
|
||
|
ULONG rtt;
|
||
|
INDEX index;
|
||
|
|
||
|
if (pp->typ == LOCAL_M) {
|
||
|
switch (status) {
|
||
|
case L2MCONNT :
|
||
|
case L2MLRESF :
|
||
|
case L2MLREST :
|
||
|
discnbp(pp);
|
||
|
case L2MBUSYF :
|
||
|
if (pp->rttstart) {
|
||
|
rtt = (tic10 - pp->rttstart) + 1;
|
||
|
update_peer_quality(pp, rtt, DONT_CHANGE_QUAL);
|
||
|
if ((index = add_route(pp, pp->l2link->call,
|
||
|
(unsigned)pp->quality)) != NO_INDEX) {
|
||
|
update_lt(pp, index, 1);
|
||
|
update_alias(index, pp->l2link->alias);
|
||
|
}
|
||
|
rtt_metric(pp, (long)rtt);
|
||
|
}
|
||
|
pp->rttstart = 0;
|
||
|
pp->rtt_time = MESSTIME;
|
||
|
break;
|
||
|
case L2MFAILW :
|
||
|
if (pp->rttstart) {
|
||
|
update_peer_quality(pp, 0L, DONT_CHANGE_QUAL);
|
||
|
add_route(pp, pp->l2link->call, 0);
|
||
|
}
|
||
|
case L2MDISCF :
|
||
|
pp->rttstart = 0;
|
||
|
pp->rtt_time = MESSTIME;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*----------------------------------------------------------------------*/
|
||
|
/* eine Status-Aenderung fuer die FLEXNET behandeln */
|
||
|
/*----------------------------------------------------------------------*/
|
||
|
void
|
||
|
flex_status(PEER *pp, WORD status)
|
||
|
{
|
||
|
#ifdef PORT_L2_CONNECT_TIME
|
||
|
UWORD port = 0;
|
||
|
#endif
|
||
|
if (pp->typ == FLEXNET)
|
||
|
{
|
||
|
switch (status)
|
||
|
{
|
||
|
case L2MCONNT :
|
||
|
case L2MLRESF :
|
||
|
case L2MLREST :
|
||
|
pp->token = (callcompare(pp->l2link->call, myid) == LOWER)?
|
||
|
TOKEN_ER:TOKEN_ICH;
|
||
|
connect_peer(pp);
|
||
|
flex_tx_init(pp); /* Init-Frame schicken */
|
||
|
#ifndef FLEX_TX_RTT_FIX
|
||
|
flex_tx_rtt_query(pp); /* und Laufzeitmessung */
|
||
|
#endif
|
||
|
pp->maxtime = 30000U; /* maximale Laufzeit */
|
||
|
break;
|
||
|
|
||
|
case L2MFAILW :
|
||
|
case L2MDISCF :
|
||
|
#ifdef PORT_L2_CONNECT_TIME
|
||
|
port = pp->l2link->port;
|
||
|
pp->l2link->sabmtime = portpar[port].l2_connect_time;
|
||
|
#endif /* PORT_L2_CONNECT_TIME */
|
||
|
|
||
|
/* Route als ausgefallen melden. */
|
||
|
update_peer_quality(pp, 0L, DONT_CHANGE_QUAL);
|
||
|
/* Alle Nodes von der Route loeschen. */
|
||
|
check_all_destot();
|
||
|
|
||
|
#ifdef AUTOROUTING
|
||
|
/* Link ist eine Auto-Route. */
|
||
|
if (pp->l2link->ppAuto == AUTO_ROUTE)
|
||
|
{
|
||
|
#ifdef AXIPR_HTML
|
||
|
/* Protokoll fuer HTML-Ausgabe setzen. */
|
||
|
SetHTML(pp->l2link->port, pp->l2link->call, NULL, FALSE);
|
||
|
#endif /* AXIPR_HTML */
|
||
|
|
||
|
/* Link austragen. */
|
||
|
unregister_neigb(pp->l2link->call, pp->l2link->digil, pp->l2link->port);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
update_peer_quality(pp, 0, DONT_CHANGE_QUAL);
|
||
|
#endif /* AUTOROUTING */
|
||
|
break;
|
||
|
|
||
|
default :
|
||
|
update_peer_quality(pp, 0, DONT_CHANGE_QUAL);
|
||
|
disconnect_peer(pp);
|
||
|
break;
|
||
|
}
|
||
|
#ifdef __WIN32__
|
||
|
pp->brotim = 0; /* mit Broadcast beginnen */
|
||
|
pp->rttstart = 0; /* Messung zuruecksetzen */
|
||
|
#else
|
||
|
pp->brotim = /* mit Broadcast beginnen */
|
||
|
pp->rttstart = /* Messung zuruecksetzen */
|
||
|
#endif /* WIN32 */
|
||
|
pp->rtt_time = 0;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Ein Frame mit einer bestimmten PID anlegen und Verweis auf den
|
||
|
* zugehoerigen Link speichern.
|
||
|
*/
|
||
|
static MBHEAD *getfbp(UBYTE pid, LNKBLK *lnkpoi, const char *format, ...)
|
||
|
{
|
||
|
va_list arg_ptr;
|
||
|
char str[256];
|
||
|
MBHEAD *fbp;
|
||
|
|
||
|
va_start(arg_ptr, format); /* String formatieren */
|
||
|
vsprintf(str, format, arg_ptr);
|
||
|
va_end(arg_ptr);
|
||
|
|
||
|
(fbp = (MBHEAD *) allocb(ALLOC_MBHEAD))->l2fflg = pid;
|
||
|
fbp->l2link = lnkpoi; /* zugehoerigen Link speichern */
|
||
|
putstr(str, fbp); /* Text in das Frame speichern */
|
||
|
return(fbp);
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Ein Frame an den Level 2 senden (muss mit getfbp erzeugt worden sein)
|
||
|
*/
|
||
|
static void sendfbp(MBHEAD *fbp)
|
||
|
{
|
||
|
rwndmb(fbp); /* Frame zurueckspulen */
|
||
|
i3tolnk(fbp->l2fflg, fbp->l2link, fbp);
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Flexnet Initialisierungs-Frame senden, dort sind die maximale SSID und
|
||
|
* diverse Kennungen enthalten
|
||
|
*/
|
||
|
static void
|
||
|
flex_tx_init(PEER *pp)
|
||
|
{
|
||
|
sendfbp(getfbp(L2CFLEXNET, pp->nbrl2l,
|
||
|
"0" /* Frame-Kennung */
|
||
|
"%c" /* maximale SSID */
|
||
|
"%c%c", /* Software-Name und Version */
|
||
|
(maxSSID() + '0'), /* TEST DG9OBU : max. SSID melden */
|
||
|
SOFTKENNUNG,
|
||
|
SOFTVERSION));
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Flexnet Laufzeitmessungs-Antwort senden, es enthaelt unsere eigene
|
||
|
* Laufzeit*2 (Flexnet uebertraegt Hin-und-Rueck-Laufzeiten).
|
||
|
*/
|
||
|
static void
|
||
|
flex_tx_rtt_reply(PEER *pp)
|
||
|
{
|
||
|
sendfbp(getfbp(L2CFLEXNET, pp->nbrl2l,
|
||
|
"1" /* Frame-Kennung */
|
||
|
"%lu", /* unsere Laufzeit */
|
||
|
pp->my_quality ? pp->my_quality/10L : (ULONG)(pp->nbrl2l->SRTT/10L)));
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Flexnet Laufzeitmessungs-Frame senden
|
||
|
*/
|
||
|
static void
|
||
|
flex_tx_rtt_query(PEER *pp)
|
||
|
{
|
||
|
MBHEAD *fbp;
|
||
|
|
||
|
fbp = getfbp(L2CFLEXNET, pp->nbrl2l, "2");/* Frame-Kennung */
|
||
|
while (fbp->mbpc < 201) /* auf 201 Bytes auffuellen */
|
||
|
putchr(' ', fbp);
|
||
|
sendfbp(fbp);
|
||
|
pp->rttstart = tic10; /* Startzeit der Messung merken */
|
||
|
}
|
||
|
|
||
|
/************************************************************************/
|
||
|
/* */
|
||
|
/* Flexnet Routing-Informations-Frame senden, hier wird die Token- */
|
||
|
/* uebergabe und die Sendung von Routing-Informationen durchgefuehrt. */
|
||
|
/* */
|
||
|
/************************************************************************/
|
||
|
static void
|
||
|
flex_tx_routes(PEER *pp)
|
||
|
{
|
||
|
MBHEAD *fbp = NULL;
|
||
|
INDEX index;
|
||
|
int max_nodes = netp->max_nodes;
|
||
|
NODE *np = netp->nodetab;
|
||
|
ROUTE *rp = pp->routes;
|
||
|
PEER *bestpp;
|
||
|
UWORD quality;
|
||
|
unsigned reported_quality;
|
||
|
unsigned diff;
|
||
|
|
||
|
switch (pp->token) /* je nach Token-Status */
|
||
|
{
|
||
|
case TOKEN_ICH_REQ: /* ich warte auf Token und es kommt */
|
||
|
discnbp(pp); /* nicht */
|
||
|
#if MAX_TRACE_LEVEL > 0
|
||
|
notify(1, "token lost %6.6s", pp->l2link->call);
|
||
|
#endif
|
||
|
return;
|
||
|
|
||
|
case TOKEN_ER:
|
||
|
case TOKEN_ER_REQ:
|
||
|
case TOKEN_ICH:
|
||
|
/* Wir koennen mit der Sendung der Informationen beginnen, da wir das */
|
||
|
/* Token haben. */
|
||
|
for (index = 0; index < max_nodes; index++, np++, rp++)
|
||
|
{
|
||
|
/* Leere Eintraege uebergehen */
|
||
|
if (!np->id[0])
|
||
|
continue;
|
||
|
/* Keine versteckten Ziele melden */
|
||
|
if (np->alias[0] == '#')
|
||
|
continue;
|
||
|
/* Dem Nachbarn nicht sich selbst melden */
|
||
|
if (cmpid(np->id, pp->l2link->call))
|
||
|
continue;
|
||
|
/* Lokale Links nicht melden, die sind schon in unserer SSID- */
|
||
|
/* Range mit beruecksichtigt. Locals, die nicht das Knotencall */
|
||
|
/* haben, muessen aber gemeldet werden, da sie nicht von der */
|
||
|
/* SSID-Range erfasst werden. */
|
||
|
if (cmpcal(myid, np->id) && SSIDinrange(SSID(np->id)))
|
||
|
continue;
|
||
|
|
||
|
#ifdef LINKSMOD_LOCALMOD
|
||
|
if (CheckLocalLink(np->id) == TRUE) /* Ist ein LOCAL-Link. */
|
||
|
continue; /* Zum naechsten Eintrag. */
|
||
|
#endif /* LINKSMOD_LOCALMOD */
|
||
|
|
||
|
quality = (find_best_qual(index, &bestpp, FLEX_MASK) + 9) / 10;
|
||
|
reported_quality = rp->reported_quality / 10; /* gemeldete Zeit */
|
||
|
|
||
|
if (bestpp == pp) /* Partner ist der beste Weg */
|
||
|
{
|
||
|
if (!reported_quality) /* war er schon der Downstream? */
|
||
|
continue; /* dann keine Aenderung */
|
||
|
/* Den Partner informieren, das er jetzt unser Upstream wird, indem wir */
|
||
|
/* 0 melden. */
|
||
|
quality = 0;
|
||
|
}
|
||
|
else /* bester Weg geht wo anders */
|
||
|
{ /* zu meldende Qualitaet berechnen */
|
||
|
if (quality)
|
||
|
quality += (unsigned)(pp->quality / 10L);
|
||
|
if (quality == reported_quality) /* keine Aenderung */
|
||
|
continue;
|
||
|
diff = (reported_quality / 8); /* 12.5% Schwelle */
|
||
|
diff = max(diff, 2); /* minimum 200ms */
|
||
|
if (quality && reported_quality) /* beide gut */
|
||
|
if ( (quality < reported_quality) /* nicht schlechter */
|
||
|
&& (reported_quality-quality <= diff))
|
||
|
continue; /* und unwesentlich besser */
|
||
|
}
|
||
|
|
||
|
if (pp->token == TOKEN_ER) /* erst nach Token fragen */
|
||
|
{
|
||
|
sendfbp(getfbp(L2CFLEXNET, pp->nbrl2l, "3+"));
|
||
|
pp->token = TOKEN_ICH_REQ;
|
||
|
pp->brotim = 120; /* falls er nicht in 120s antwortet */
|
||
|
return; /* ohne Token nichts senden */
|
||
|
}
|
||
|
|
||
|
if (fbp == NULL) /* eventuell neuen Buffer anlegen */
|
||
|
fbp = getfbp(L2CFLEXNET, pp->nbrl2l, "3");
|
||
|
/* wenn ich dem Nachbarn etwas melde, ist er automatisch mein Upstream, */
|
||
|
/* seine Qualitaet verwerfe ich also. Dem Downstream melde ich nie */
|
||
|
/* etwas (quality = 0), deshalb werfe ich seine Qualitaet nicht weg. */
|
||
|
if (quality)
|
||
|
update_route(pp, index, 0);
|
||
|
/* Maxtime des Nachbarn beruecksichtigen */
|
||
|
if (quality > pp->maxtime / 10L)
|
||
|
continue;
|
||
|
putprintf(fbp, "%6.6s%c%c%u ",
|
||
|
np->id, /* Rufzeichen des Ziels */
|
||
|
FLEXSSID(np->id), /* untere SSID */
|
||
|
np->ssid_high+'0',/* obere SSID */
|
||
|
quality); /* Quality (in 100ms, siehe oben) */
|
||
|
rp->reported_quality = quality * 10; /* merken, was gemeldet */
|
||
|
/* wurde */
|
||
|
if (fbp->mbpc >= 256 - (6 /*id*/
|
||
|
+ 2 /*2 ssids*/
|
||
|
+ 5 /*4 quality+space*/))
|
||
|
{
|
||
|
sendfbp(fbp);
|
||
|
fbp = NULL; /* Frame senden wenn Buffer voll */
|
||
|
}
|
||
|
}
|
||
|
if (pp->token == TOKEN_ER_REQ) /* er will das Token */
|
||
|
{
|
||
|
if (!fbp)
|
||
|
fbp = getfbp(L2CFLEXNET, pp->nbrl2l, "3");
|
||
|
putchr('-', fbp); /* ihm das Token geben */
|
||
|
pp->token = TOKEN_ER; /* nun hat er das Token */
|
||
|
}
|
||
|
if (fbp)
|
||
|
sendfbp(fbp); /* eventuell Reste senden */
|
||
|
break;
|
||
|
}
|
||
|
pp->brotim = 10; /* in 10s wieder melden */
|
||
|
}
|
||
|
|
||
|
/* Einen Buffer in einen String umkopieren. CR wird entfernt. */
|
||
|
static void
|
||
|
mbp2str(MBHEAD *mbp, char *str)
|
||
|
{
|
||
|
int ch;
|
||
|
|
||
|
while (mbp->mbgc < mbp->mbpc)
|
||
|
if ((ch = getchr(mbp)) != '\r')
|
||
|
*str++ = ch;
|
||
|
*str = 0;
|
||
|
}
|
||
|
|
||
|
/************************************************************************/
|
||
|
/* */
|
||
|
/* Ein Routentest-Frame empfangen und weiterleiten / oder beantworten */
|
||
|
/* Routentest weiterleiten Format: 6HQQQQQSSSSSS XXXXXX DDDDDD */
|
||
|
/* H TTL-Zaehler. Beginnt bei ! (ASCII $21) und zaehlt hinauf !"#$%&/ */
|
||
|
/* Q QSO-Nummer ist erstes Zeichen davon = ' (96dez | 60hex) oder */
|
||
|
/* entsprechendes Bit gesetzt, wird zusaetzlich ein */
|
||
|
/* 7er Frame erzeugt und zurueckgeschickt. */
|
||
|
/* S Source-Digi */
|
||
|
/* X Digipeater .... */
|
||
|
/* D Ziel-Digi */
|
||
|
/* */
|
||
|
/************************************************************************/
|
||
|
void
|
||
|
flex_route_query(char *buf)
|
||
|
{
|
||
|
char *bp, *p; /* Buffer fuer die Bearbeitung */
|
||
|
char dstid[L2IDLEN]; /* Zielrufzeichen */
|
||
|
char dstcal[15]; /* ASCII: Rufzeichen des Zielnode */
|
||
|
char nbrcal[15]; /* ASCII: Rufzeichen des Nachbarn */
|
||
|
char linkzeit[10];
|
||
|
char *insert; /* Das soll eingefuegt werden. */
|
||
|
PEER *pp;
|
||
|
MBHEAD *fbp;
|
||
|
int len;
|
||
|
int mask_flag = 0;
|
||
|
|
||
|
buf[0] = '7'; /* Default: Frame geht zurueck */
|
||
|
bp = buf + 7;
|
||
|
|
||
|
while ((p = strchr(bp, ' ')) != NULL)
|
||
|
bp = p + 1; /* zum letzten Call gehen */
|
||
|
|
||
|
if (strlen(bp) > 9) /* XXXXXX-99 darf noch drinstehen */
|
||
|
return;
|
||
|
strcpy(dstcal, bp); /* auch als ASCII merken */
|
||
|
str2call(dstid, bp); /* Zielrufzeichen lesen */
|
||
|
|
||
|
insert = ""; /* Default: nichts einfuegen */
|
||
|
linkzeit[0] = NUL;
|
||
|
|
||
|
if (++buf[1] < '!' + 20) /* noch Hops uebrig? */
|
||
|
{
|
||
|
if (iscall(dstid, NULL, &pp, FLEX_MASK))
|
||
|
{
|
||
|
/* Wenn es der Linkpartner selber ist, dann schicken wir das einfach */
|
||
|
/* zurueck, sonst basteln wir sein Call da rein und schicken ihm das */
|
||
|
/* Frame. */
|
||
|
/* (durch iscall(..,VC|VC_FAR) ist sichergestellt, das wir hier nur */
|
||
|
/* Flexnets haben, die ferne Ziele anbieten) */
|
||
|
if (!cmpid(dstid, pp->l2link->call)) /* WEITERLEITEN */
|
||
|
{
|
||
|
call2str(insert = nbrcal, pp->l2link->call);
|
||
|
strcat(nbrcal, " "); /* Leerzeichen als Trennung */
|
||
|
buf[0] = '6'; /* doch weiterleiten */
|
||
|
} /* nichts einfuegen, nur zuerueck */
|
||
|
mask_flag = pp->options; /* merken was es war. VC | VC_FAR | DG */
|
||
|
}
|
||
|
else
|
||
|
if (iscall(dstid, NULL, &pp, DG))
|
||
|
insert = "<tnngate> ";
|
||
|
else
|
||
|
insert = "??? ";
|
||
|
}
|
||
|
else
|
||
|
insert = "... "; /* Hops abgelaufen */
|
||
|
|
||
|
len = (int)(strlen(buf) + strlen(insert)) + 1/*CR*/;
|
||
|
if (len >= 230) /* Frame wird zulang, kuerzen */
|
||
|
{
|
||
|
insert = len < 250 ? ">>> " : "";
|
||
|
buf[0] = '7'; /* zulange an den Absender zurueck */
|
||
|
}
|
||
|
/* hier angekommen haben wir genuegend Platz, um insert einzufuegen, */
|
||
|
/* oder insert ist leer. */
|
||
|
p = bp;
|
||
|
strcpy(bp, insert);
|
||
|
strcat(bp, dstcal);
|
||
|
|
||
|
if (buf[0] == '6') /* 6er leiten wir selber weiter */
|
||
|
{
|
||
|
fbp = getfbp(L2CFLEXNET, pp->nbrl2l, "");
|
||
|
putstr(buf, fbp); /* String ins Frame */
|
||
|
putchr('\r', fbp); /* CR hinterher */
|
||
|
sendfbp(fbp); /* und senden... */
|
||
|
}
|
||
|
if (buf[2] >= 0x60) /* erweiterter Routentest ? */
|
||
|
{
|
||
|
if (mask_flag & VC_FAR) /* und auch ein Flex? */
|
||
|
{
|
||
|
bp = p;
|
||
|
sprintf(linkzeit,"(%lu) ", (unsigned)pp->quality / 10L);
|
||
|
strcpy(bp, linkzeit);
|
||
|
strcat(bp, insert);
|
||
|
strcat(bp, dstcal);
|
||
|
buf[0] = '7';
|
||
|
}
|
||
|
}
|
||
|
if (buf[0] == '7')
|
||
|
flex_route_reply(buf); /* 7er erledigt flex_route_reply */
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
/************************************************************************/
|
||
|
/* */
|
||
|
/* Eine Routentest-Antwort auswerten oder weiterleiten. */
|
||
|
/* Routentest-Antwort Format: 7HQQQQQSSSSSS XXXXXX DDDDDD */
|
||
|
/* 01234567890123 */
|
||
|
/* H TTL-Zaehler. Beginnt bei ! (ASCII $21) und zaehlt hinauf !"#$%&/ */
|
||
|
/* Q QSO-Nummer */
|
||
|
/* S Source-Digi */
|
||
|
/* X Digipeater .... */
|
||
|
/* D Ziel-Digi */
|
||
|
/* */
|
||
|
/* Wir waehlen einen beliebigen Rueckweg, nicht unbedingt den in der */
|
||
|
/* Anfrage festgestellten (eventuell gehts zurueck anders). */
|
||
|
/* */
|
||
|
/************************************************************************/
|
||
|
static void
|
||
|
flex_route_reply(char *buf)
|
||
|
{
|
||
|
char *p; /* Buffer fuer die Bearbeitung */
|
||
|
char srcid[L2IDLEN]; /* Zielrufzeichen */
|
||
|
char srccal[15]; /* ASCII: Rufzeichen des Zielnode */
|
||
|
PEER *pp;
|
||
|
MBHEAD *fbp;
|
||
|
USRBLK *up;
|
||
|
unsigned int uid;
|
||
|
|
||
|
if ((p = strchr(buf+7, ' ')) == NULL)
|
||
|
return;
|
||
|
*p = 0; /* Rufzeichen isolieren */
|
||
|
if (strlen(buf + 7) > 9) /* Absender-Rufzeichen zu lang */
|
||
|
return;
|
||
|
strcpy(srccal, buf + 7); /* und kopieren */
|
||
|
str2call(srcid, srccal); /* in internes Format wandeln */
|
||
|
*p = ' '; /* ... wieder Space daraus machen */
|
||
|
|
||
|
if (cmpid(srcid, myid)) /* etwa fuer mich? */
|
||
|
{
|
||
|
if(buf[2] > 0x60) /* das ' entfernen */
|
||
|
buf[2] = buf[2] & 0xbf;
|
||
|
else
|
||
|
buf[2] = 0x20;
|
||
|
|
||
|
sscanf(buf + 2, "%5u", &uid); /* User-ID lesen */
|
||
|
if (uid > 0 && uid < NUMPAT) /* nur wenn die ID gueltig ist */
|
||
|
if ((up = ptctab[uid].ublk) != NULL)
|
||
|
{
|
||
|
#ifdef SEND_ASYNC_RESFIX
|
||
|
/* Sicher ist sicher. */
|
||
|
buf[256] = 0;
|
||
|
#endif /* SEND_ASYNC_RESFIX */
|
||
|
send_async_response(up, "Route (VC): ", buf + 7);
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
else /* WEITERLEITEN */
|
||
|
if (++buf[1] < '!' + 40) /* noch Hops uebrig? */
|
||
|
if (iscall(srcid, NULL, &pp, FLEX_MASK))
|
||
|
{
|
||
|
if (pp->nbrl2l)
|
||
|
{
|
||
|
fbp = getfbp(L2CFLEXNET, pp->nbrl2l, "");
|
||
|
putstr(buf, fbp); /* String ins Frame */
|
||
|
putchr('\r', fbp); /* CR hinterher */
|
||
|
sendfbp(fbp); /* und senden... */
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/************************************************************************/
|
||
|
/* */
|
||
|
/* Auswertung eines empfangenen Flexnet-Frames */
|
||
|
/* */
|
||
|
/************************************************************************/
|
||
|
void
|
||
|
flex_rx(PEER *pp, MBHEAD * mbp)
|
||
|
{
|
||
|
char call[L2IDLEN];
|
||
|
int ssidoben;
|
||
|
long myrtt;
|
||
|
long hisrtt;
|
||
|
unsigned quality;
|
||
|
UBYTE data;
|
||
|
char buf[280];
|
||
|
INDEX index;
|
||
|
#if MAX_TRACE_LEVEL > 6
|
||
|
char notify_call[10];
|
||
|
#endif
|
||
|
|
||
|
if (pp->nbrl2l == NULL)
|
||
|
return;
|
||
|
|
||
|
if (mbp->l2link) /* Info Frame ? */
|
||
|
{
|
||
|
switch ((buf[0] = getchr(mbp)))
|
||
|
{
|
||
|
case '0':
|
||
|
if (mbp->mbpc - mbp->mbgc < 3)
|
||
|
return; /* Minimum 3 Bytes im Frame */
|
||
|
pp->l2link->ssid_high =
|
||
|
getchr(mbp)-'0'; /* Get max SSID */
|
||
|
data = getchr(mbp); /* Version lesen */
|
||
|
pp->version = data + /* Versionskennung zusammenbauen */
|
||
|
(getchr(mbp)<<8); /* Softwareversion dazuaddieren */
|
||
|
break;
|
||
|
|
||
|
/* Beantwortung unseres 2er Frames */
|
||
|
case '1':
|
||
|
myrtt = (tic10 - pp->rttstart);
|
||
|
myrtt += (myrtt / 8 + 1); /* ca. 12,5% Aufschlag */
|
||
|
myrtt = max(myrtt, 10);
|
||
|
mbp2str(mbp, buf); /* Frame in ein String kopieren */
|
||
|
hisrtt = atoi((char *) buf) * 10;/* Flex gibt in 100ms an */
|
||
|
hisrtt = max(hisrtt, 10); /* er sendetet RTT, wir wollen Delay */
|
||
|
update_peer_quality(pp, (ULONG)myrtt, (ULONG)hisrtt);
|
||
|
if ((index = add_route(pp, pp->l2link->call,
|
||
|
(unsigned)pp->quality)) != NO_INDEX)
|
||
|
{
|
||
|
update_lt(pp, index, 1);
|
||
|
update_alias(index, pp->l2link->alias);
|
||
|
update_ssid(index, pp->l2link->ssid_high);
|
||
|
}
|
||
|
rtt_metric(pp, myrtt);
|
||
|
pp->rttstart = 0;
|
||
|
|
||
|
/* festes Messinterval */
|
||
|
pp->rtt_time = MESSTIME;
|
||
|
break;
|
||
|
|
||
|
/* Partner schickt Testframe, Antwort mit unserer Laufzeit */
|
||
|
case '2':
|
||
|
flex_tx_rtt_reply(pp); /* Antwort schicken */
|
||
|
break;
|
||
|
|
||
|
/* Routinginfo / Tokenuebergabe */
|
||
|
case '3':
|
||
|
while (mbp->mbgc < mbp->mbpc)
|
||
|
{
|
||
|
if (ge6chr(call, mbp)) /* Rufzeichen komplett? */
|
||
|
{
|
||
|
if (mbp->mbpc-mbp->mbgc < 2/*ssid*/+1/*Zeit*/)
|
||
|
return;
|
||
|
call[L2IDLEN-1] = ((getchr(mbp)-'0') << 1) | 0x60;
|
||
|
ssidoben = getchr(mbp) - '0';
|
||
|
quality = 0;
|
||
|
while (isdigit(data = getchr(mbp)) && mbp->mbgc < mbp->mbpc)
|
||
|
quality = 10 * quality + (data - '0');
|
||
|
if (quality >= 6000)
|
||
|
quality = 0;
|
||
|
if (quality)
|
||
|
quality += quality / 5; /* 20% Aufschlag als Hop-Horizont */
|
||
|
if ((index = add_route(pp, call, quality * 10)) != NO_INDEX)
|
||
|
{
|
||
|
update_lt(pp, index, DEFAULT_LT);
|
||
|
update_ssid(index, ssidoben);
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
switch (call[0])
|
||
|
{
|
||
|
case '+' : /* er will das Token haben */
|
||
|
pp->token = TOKEN_ER_REQ;
|
||
|
flex_tx_routes(pp); /* Routen uebertragen, Token halten */
|
||
|
break;
|
||
|
case '-' : /* er gibt uns das Token */
|
||
|
pp->token = TOKEN_ICH;
|
||
|
flex_tx_routes(pp); /* Routen uebertragen, Token halten */
|
||
|
break;
|
||
|
}
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
/* 4xxxx sagt die maximal erlaubte Ziel-Laufzeit fuer Broadcast. */
|
||
|
/* Wenn sie kleiner wird, muessen groessere ausgetragen werden. */
|
||
|
/* 4xxxx! Flex hat irgendwie seine Dest's zermarmelt. Alles neu melden. */
|
||
|
case '4': /* Choke fuer die Laufzeit der Ziele */
|
||
|
mbp2str(mbp, buf);
|
||
|
#ifdef __WIN32__
|
||
|
pp->maxtime = (unsigned short)atoi ((char *) buf) * (unsigned short)10L;
|
||
|
#else
|
||
|
pp->maxtime = atoi ((char *) buf) * 10L;
|
||
|
#endif /* WIN32 */
|
||
|
#if MAX_TRACE_LEVEL > 6
|
||
|
call2str(notify_call, pp->l2link->call);
|
||
|
notify(7, "%s maxtime -> %u0 ms", notify_call, pp->maxtime);
|
||
|
#endif
|
||
|
if (strchr(buf, '!') != 0) /* Nachbar hat Uebersicht verloren,*/
|
||
|
flex_tx_routes(pp); /* will Dest's */
|
||
|
break;
|
||
|
|
||
|
case '5':
|
||
|
break;
|
||
|
|
||
|
/* Routentest hin, weiterleiten */
|
||
|
case '6':
|
||
|
mbp2str(mbp, buf + 1); /* Frame in ein String kopieren */
|
||
|
flex_route_query(buf);
|
||
|
break;
|
||
|
|
||
|
/* Routentest zurueck, weiterleiten */
|
||
|
case '7':
|
||
|
mbp2str(mbp, buf + 1); /* Frame in ein String kopieren */
|
||
|
flex_route_reply(buf);
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
break;
|
||
|
} /* switch */
|
||
|
} /* if infoframe */
|
||
|
}
|
||
|
|
||
|
static int
|
||
|
callcompare(char * call1, char * call2)
|
||
|
{
|
||
|
register int i;
|
||
|
|
||
|
/* Rufzeichen zeichenweise miteinander vergleichen */
|
||
|
for (i = 0; i < L2IDLEN - 1; ++i)
|
||
|
{
|
||
|
if (call1[i] != call2[i])
|
||
|
{
|
||
|
if (call1[i] < call2[i])
|
||
|
return(LOWER);
|
||
|
if (call1[i] > call2[i])
|
||
|
return(HIGHER);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* Rufzeichen waren gleich, dann muss die SSID entscheiden */
|
||
|
if ((call1[L2IDLEN-1] & 0x1e) > (call2[L2IDLEN-1] & 0x1e))
|
||
|
return(HIGHER);
|
||
|
else
|
||
|
return(LOWER);
|
||
|
}
|
||
|
|
||
|
/************************************************************************\
|
||
|
* *
|
||
|
* Informationstransfer von Level2 zum FlexNet-Router *
|
||
|
* Fuer jedes empfangene Packet wird die Flexnet-Behandlungsroutine *
|
||
|
* aus src/l3c.c aufgerufen. *
|
||
|
* *
|
||
|
\************************************************************************/
|
||
|
void
|
||
|
flexnet_rx(PEER *pp)
|
||
|
{
|
||
|
MBHEAD *mbp;
|
||
|
|
||
|
/* Zunaechst empfangene Frames verarbeiten, bis Liste leer... */
|
||
|
while ( (mbp = (MBHEAD *)(pp->rxfl.head))
|
||
|
!= (MBHEAD *)&(pp->rxfl))
|
||
|
{
|
||
|
ulink((LEHEAD *)mbp); /* Packet aus der Liste aushaengen */
|
||
|
flex_rx(pp, mbp); /* Auswertung durchfuehren */
|
||
|
dealmb(mbp); /* fertig, Buffer freigeben */
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* End of src/l3vc.c */
|