1515 lines
32 KiB
C
1515 lines
32 KiB
C
/*
|
|
Copyright 2001-2022 John Wiseman G8BPQ
|
|
|
|
This file is part of LinBPQ/BPQ32.
|
|
|
|
LinBPQ/BPQ32 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 3 of the License, or
|
|
(at your option) any later version.
|
|
|
|
LinBPQ/BPQ32 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 LinBPQ/BPQ32. If not, see http://www.gnu.org/licenses
|
|
*/
|
|
|
|
/*
|
|
Copyright 2001-2022 John Wiseman G8BPQ
|
|
|
|
This file is part of LinBPQ/BPQ32.
|
|
|
|
LinBPQ/BPQ32 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 3 of the License, or
|
|
(at your option) any later version.
|
|
|
|
LinBPQ/BPQ32 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 LinBPQ/BPQ32. If not, see http://www.gnu.org/licenses
|
|
*/
|
|
|
|
//
|
|
// C replacement for L3Code.asm
|
|
//
|
|
#define Kernel
|
|
|
|
#define _CRT_SECURE_NO_DEPRECATE
|
|
|
|
#pragma data_seg("_BPQDATA")
|
|
|
|
#include "time.h"
|
|
#include "stdio.h"
|
|
#include <fcntl.h>
|
|
|
|
#include "CHeaders.h"
|
|
#include "tncinfo.h"
|
|
|
|
VOID UPDATEDESTLIST();
|
|
VOID MOVEALL(dest_list * DEST);
|
|
VOID MOVE3TO2(dest_list * DEST);
|
|
VOID CLEARTHIRD(dest_list * DEST);
|
|
VOID L3TRYNEXTDEST(struct ROUTE * ROUTE);
|
|
VOID SendNETROMRoute(struct PORTCONTROL * PORT, unsigned char * axcall);
|
|
void SendVARANetromNodes(struct TNCINFO * TNC, MESSAGE *Buffer);
|
|
void SendVARANetromMsg(struct TNCINFO * TNC,L3MESSAGEBUFFER * Buffer);
|
|
|
|
extern BOOL NODESINPROGRESS ;;
|
|
PPORTCONTROL L3CURRENTPORT;
|
|
extern dest_list * CURRENTNODE;
|
|
|
|
int L3_10SECS = 10;
|
|
|
|
|
|
VOID L3BG()
|
|
{
|
|
// TRANSFER MESSAGES FROM DEST TO LINK
|
|
|
|
int n = MAXDESTS;
|
|
struct DEST_LIST * DEST = DESTS; // NODE LIST
|
|
struct PORTCONTROL * PORT = PORTTABLE;
|
|
struct ROUTE * ROUTE;
|
|
struct TNCINFO * TNC;
|
|
|
|
struct _LINKTABLE * LINK;
|
|
|
|
while (n--)
|
|
{
|
|
if (DEST->DEST_CALL[0]) // Active entry?
|
|
{
|
|
while(DEST->DEST_Q) // FRAMES TO SEND?
|
|
{
|
|
int ActiveRoute = DEST->DEST_ROUTE;
|
|
|
|
if (ActiveRoute)
|
|
{
|
|
ROUTE = DEST->NRROUTE[ActiveRoute - 1].ROUT_NEIGHBOUR;
|
|
|
|
// if NetROM over VARA pass direct to the driver
|
|
|
|
if (ROUTE)
|
|
{
|
|
TNC = TNCInfo[ROUTE->NEIGHBOUR_PORT];
|
|
|
|
if (TNC && TNC->NetRomMode)
|
|
{
|
|
PL3MESSAGEBUFFER MSG = (PL3MESSAGEBUFFER)Q_REM(&DEST->DEST_Q);
|
|
SendVARANetromMsg(TNC, MSG);
|
|
return;
|
|
}
|
|
}
|
|
if (ROUTE)
|
|
LINK = ROUTE->NEIGHBOUR_LINK;
|
|
else
|
|
LINK= NULL;
|
|
|
|
if (LINK)
|
|
{
|
|
if (LINK->L2STATE == 0)
|
|
{
|
|
// LINK ENTRY IS INVALID - IT PROBABLY HAS BEEN 'ZAPPED', SO CANCEL IT
|
|
|
|
ROUTE->NEIGHBOUR_LINK = NULL;
|
|
}
|
|
else
|
|
{
|
|
if (LINK->L2STATE < 5)
|
|
{
|
|
goto NextDest; // Wait for it to activate
|
|
}
|
|
else
|
|
{
|
|
ROUTE->NBOUR_IFRAMES++;
|
|
C_Q_ADD(&LINK->TX_Q, Q_REM(&DEST->DEST_Q));
|
|
continue; // See if more
|
|
}
|
|
}
|
|
}
|
|
// Drop through to Activate
|
|
}
|
|
|
|
if (ACTIVATE_DEST(DEST) == FALSE)
|
|
{
|
|
// Node has no routes - get rid of it
|
|
|
|
REMOVENODE(DEST);
|
|
return; // Avoid riskof looking at lod entries
|
|
}
|
|
}
|
|
}
|
|
|
|
NextDest:
|
|
DEST++;
|
|
}
|
|
}
|
|
|
|
BOOL ACTIVATE_DEST(struct DEST_LIST * DEST)
|
|
{
|
|
int n = MAXDESTS;
|
|
struct PORTCONTROL * PORT = PORTTABLE;
|
|
struct ROUTE * ROUTE;
|
|
struct _LINKTABLE * LINK;
|
|
struct TNCINFO * TNC;
|
|
|
|
int ActiveRoute;
|
|
|
|
if (DEST->DEST_ROUTE == 0) // ALREADY HAVE A SELECTED ROUTE?
|
|
DEST->DEST_ROUTE = 1; // TRY TO ACTIVATE FIRST
|
|
|
|
ActiveRoute = DEST->DEST_ROUTE - 1;
|
|
|
|
ROUTE = DEST->NRROUTE[ActiveRoute].ROUT_NEIGHBOUR;
|
|
|
|
if (ROUTE == 0)
|
|
{
|
|
// Currnet Route not present
|
|
// If current route is 1, then we must have INP3 routes (or entry is corrupt)
|
|
|
|
if (DEST->DEST_ROUTE != 1)
|
|
goto NOROUTETODEST;
|
|
|
|
// Current Route is 1
|
|
|
|
if (DEST->ROUTE[0].ROUT_NEIGHBOUR == 0)
|
|
return FALSE; // No INP3 so No Routes
|
|
|
|
DEST->DEST_ROUTE = 4; // First INP3
|
|
ROUTE = DEST->ROUTE[0].ROUT_NEIGHBOUR;
|
|
}
|
|
|
|
// if NetROM over VARA conection is made by the driver
|
|
|
|
TNC = TNCInfo[ROUTE->NEIGHBOUR_PORT];
|
|
|
|
if (TNC && TNC->NetRomMode)
|
|
{
|
|
return TRUE;
|
|
}
|
|
|
|
LINK = ROUTE->NEIGHBOUR_LINK;
|
|
|
|
if (LINK == 0)
|
|
{
|
|
// Need to Activate Link
|
|
|
|
// SET UP LINK TABLE ENTRY
|
|
|
|
return L2SETUPCROSSLINK(ROUTE);
|
|
}
|
|
|
|
// We mst be waiting for link to come up
|
|
|
|
return TRUE;
|
|
|
|
NOROUTETODEST:
|
|
|
|
// CURRENT NEIGHBOUR NOT DEFINED - RESET TO USE FIRST
|
|
|
|
if (DEST->DEST_ROUTE == 1)
|
|
return FALSE; // First not defined so give up
|
|
|
|
DEST->DEST_ROUTE = 0;
|
|
return TRUE;
|
|
}
|
|
|
|
char Call1[10];
|
|
char Call2[10];
|
|
char Call3[10];
|
|
|
|
VOID PROCESSNODEMESSAGE(MESSAGE * Msg, struct PORTCONTROL * PORT)
|
|
{
|
|
// PROCESS A NET/ROM 'NODES' MESSAGE
|
|
|
|
// UPDATE _NEIGHBOURS LIST WITH ORIGINATING CALL, AND
|
|
// DESTINATION LIST WITH ANY PRACTICAL ROUTES
|
|
|
|
|
|
struct DEST_LIST * DEST;
|
|
struct ROUTE * ROUTE;
|
|
int Portno = PORT->PORTNUMBER;
|
|
time_t Stamp;
|
|
int HH, MM;
|
|
int Msglen = Msg->LENGTH;
|
|
int n;
|
|
UCHAR * ptr1, * ptr2, * saveptr;
|
|
int Qual;
|
|
APPLCALLS * APPL;
|
|
int App;
|
|
|
|
|
|
if (PORT->PORTQUALITY == 0 || PORT->INP3ONLY)
|
|
return;
|
|
|
|
// SEE IF OUR CALL - DONT WANT TO PUT IT IN LIST!
|
|
|
|
if (CompareCalls(Msg->ORIGIN, NETROMCALL))
|
|
return;
|
|
|
|
if (CheckExcludeList(Msg->ORIGIN) == 0)
|
|
return;
|
|
|
|
for (App = 0; App < NumberofAppls; App++)
|
|
{
|
|
APPL=&APPLCALLTABLE[App];
|
|
|
|
if (APPL->APPLHASALIAS == 0 && CompareCalls(Msg->ORIGIN, APPL->APPLCALL))
|
|
return;
|
|
}
|
|
|
|
Msg->ORIGIN[6] &= 0x1E; // MASK OFF LAST ADDR BIT
|
|
|
|
// Trap Empty Call
|
|
|
|
if (Msg->ORIGIN[0] == 0x40)
|
|
return;
|
|
|
|
/*
|
|
// validate call ptr = &Buffer->ORIGIN[0];
|
|
n = 6;
|
|
|
|
while(n--)
|
|
{
|
|
// Try a bit harder to detect corruption
|
|
|
|
c = *(ptr++);
|
|
|
|
if (c & 1)
|
|
{
|
|
ReleaseBuffer(Buffer);
|
|
return;
|
|
}
|
|
|
|
c = c >> 1;
|
|
|
|
if (!isalnum(c) && !(c == '#') && !(c == ' '))
|
|
{
|
|
ReleaseBuffer(Buffer);
|
|
return;
|
|
}
|
|
}
|
|
|
|
*/
|
|
// SEE IF ORIGINATING CALL IS IN NEIGHBOUR LIST - IF NOT ADD IT
|
|
|
|
if (FindNeighbour(Msg->ORIGIN, Portno, &ROUTE) == 0)
|
|
{
|
|
// Not in list
|
|
|
|
if (ROUTE == NULL)
|
|
return; // Table full
|
|
|
|
// CREATE NEIGHBOUR RECORD
|
|
|
|
memcpy(ROUTE->NEIGHBOUR_CALL, Msg->ORIGIN, 7);
|
|
|
|
ROUTE->NEIGHBOUR_PORT = Portno;
|
|
ROUTE->NEIGHBOUR_QUAL = PORT->PORTQUALITY;
|
|
|
|
ROUTE->NEIGHBOUR_LINK = 0; // CANT HAVE A LINK IF NEW _NODE
|
|
|
|
ROUTE->NoKeepAlive = PORT->PortNoKeepAlive;
|
|
}
|
|
|
|
// if locked route with quality zero ignore
|
|
|
|
if ((ROUTE->NEIGHBOUR_FLAG & 1)) // LOCKED ROUTE
|
|
if (ROUTE->NEIGHBOUR_QUAL == 0)
|
|
return;
|
|
|
|
// If Ignoreunlocked set, ignore it not locked
|
|
|
|
if ((ROUTE->NEIGHBOUR_FLAG & 1) == 0) // LOCKED ROUTE
|
|
if (PORT->IgnoreUnlocked)
|
|
return;
|
|
|
|
SendNETROMRoute(PORT, Msg->ORIGIN);
|
|
|
|
// if not locked, update route quality from port quality (may have changed config and not cleared SAVENODES
|
|
|
|
if ((ROUTE->NEIGHBOUR_FLAG & 1) == 0) // Not LOCKED ROUTE
|
|
ROUTE->NEIGHBOUR_QUAL = PORT->PORTQUALITY;
|
|
|
|
// GET TIME FROM BIOS DATA AREA OR RTC
|
|
|
|
time((time_t *)&Stamp);
|
|
|
|
Stamp = Stamp % 86400; // Secs into day
|
|
HH = (int)(Stamp / 3600);
|
|
|
|
Stamp -= HH * 3600;
|
|
MM = (int)(Stamp / 60);
|
|
|
|
ROUTE->NEIGHBOUR_TIME = 256 * HH + MM;
|
|
|
|
// GET QUALITY
|
|
|
|
Qual = ROUTEQUAL = ROUTE->NEIGHBOUR_QUAL; // FOR INITIAL ROUTE TABLE UPDATE
|
|
|
|
// CHECK LINK IS IN DEST LIST
|
|
|
|
if (FindDestination(Msg->ORIGIN, &DEST) == 0)
|
|
{
|
|
if (DEST == NULL)
|
|
return; // Tsble Full
|
|
|
|
// CREATE DESTINATION RECORD
|
|
|
|
memset(DEST, 0, sizeof(struct DEST_LIST));
|
|
|
|
memcpy(DEST->DEST_CALL, Msg->ORIGIN, 7);
|
|
|
|
NUMBEROFNODES++;
|
|
}
|
|
|
|
// ALWAYS UPDATE ALIAS IN CASE NOT PRESENT IN ORIGINAL TABLE
|
|
|
|
ptr1 = &Msg->L2DATA[1];
|
|
ptr2 = &DEST->DEST_ALIAS[0];
|
|
|
|
if (*ptr1 > ' ') // Only of present
|
|
{
|
|
// Validate Alias, mainly for DISABL KPC3 Problem
|
|
UCHAR c;
|
|
|
|
n = 6;
|
|
while (n--)
|
|
{
|
|
c = *(ptr1++);
|
|
if (c < 0x20 || c > 0x7A)
|
|
c = ' ';
|
|
|
|
*(ptr2++) = c;
|
|
}
|
|
}
|
|
else
|
|
ptr1 += 6;
|
|
|
|
|
|
// UPDATE QUALITY AND OBS COUNT
|
|
|
|
PROCROUTES(DEST, ROUTE, Qual);
|
|
|
|
Msglen -= (MSGHDDRLEN + 23); // LEVEL 2 HEADER FLAG and NODE MNEMONIC
|
|
|
|
// PROCESS DESTINATIONS from message
|
|
|
|
// ptr1 = start
|
|
|
|
saveptr = ptr1 - 21;
|
|
|
|
while (Msglen >= 21) // STILL AT LEAST 1 ENTRY LEFT
|
|
{
|
|
Msglen -= 21;
|
|
saveptr += 21;
|
|
ptr1 = saveptr;
|
|
|
|
// SEE IF OUR CALL - DONT WANT TO PUT IT IN LIST!
|
|
|
|
if (CompareCalls(ptr1, MYCALL))
|
|
{
|
|
// But use it to get route quality setting from other end
|
|
|
|
// As we now get qual ftom highest, only use this after a reload in
|
|
// case other end has changed.
|
|
if (ROUTE->FirstTimeFlag == 0)
|
|
{
|
|
// Check if route is via our node
|
|
|
|
if (memcmp(ptr1, &ptr1[13], 7) == 0)
|
|
{
|
|
if (ROUTE->OtherendLocked == 0) // Dont update locked quality
|
|
ROUTE->OtherendsRouteQual = ptr1[20];
|
|
|
|
ROUTE->FirstTimeFlag = 1; // Only do it first time after load
|
|
}
|
|
}
|
|
continue;
|
|
}
|
|
|
|
if (CheckExcludeList(ptr1) == 0) // Excluded
|
|
continue;
|
|
|
|
for (n = 0; n < 32; n++)
|
|
{
|
|
if (CompareCalls(ptr1, APPLCALLTABLE[n].APPLCALL))
|
|
continue;
|
|
}
|
|
|
|
// MAKE SURE ITS NOT CORRUPTED
|
|
|
|
n = 6;
|
|
|
|
while (n--)
|
|
{
|
|
if (*(ptr1++) < 0x40) // Call
|
|
{
|
|
Call1[ConvFromAX25(Msg->ORIGIN, Call1)] = 0;
|
|
Call2[ConvFromAX25(saveptr, Call2)] = 0;
|
|
memcpy(Call3, saveptr + 7,6);
|
|
Call3[6] = 0;
|
|
Debugprintf("Corrupt Node Entry from %s for %s:%s", Call1, Call2, Call3);
|
|
goto IgnoreNode;
|
|
}
|
|
}
|
|
ptr1++; // skip ssid
|
|
|
|
n = 6;
|
|
|
|
while (n--)
|
|
{
|
|
if (*(ptr1) && ((*(ptr1) < 0x20 || *(ptr1) > 0x7A)) ) // Should we accept zeros or convert to spaces??
|
|
{
|
|
Call1[ConvFromAX25(Msg->ORIGIN, Call1)] = 0;
|
|
Call2[ConvFromAX25(saveptr, Call2)] = 0;
|
|
memcpy(Call3, saveptr + 7,6);
|
|
Call3[6] = 0;
|
|
Debugprintf("Corrupt Node Entry from %s for %s:%s", Call1, Call2, Call3);
|
|
goto IgnoreNode;
|
|
}
|
|
ptr1++;
|
|
}
|
|
|
|
ptr1 -= 13; // Back to start
|
|
|
|
// CALCULATE ROUTE QUALITY
|
|
|
|
// Experimantal Code to adjust received route qualities based on deduced quality
|
|
// settings at other end of link.
|
|
|
|
// Don't mess with Application Qualities. There are almost always 255, and
|
|
// if not there is probably a good reason for the value chosen.
|
|
|
|
if (CompareCalls(Msg->ORIGIN, &ptr1[13]))
|
|
{
|
|
// Application Node - Just do normal update
|
|
|
|
Qual = (((ROUTEQUAL * ptr1[20]) + 128)) / 256;
|
|
}
|
|
else
|
|
{
|
|
// Try using the highest reported indirect route as remote qual
|
|
|
|
if (ROUTE->OtherendLocked == 0) // Not locked
|
|
{
|
|
if (ptr1[20] > ROUTE->OtherendsRouteQual)
|
|
ROUTE->OtherendsRouteQual = ptr1[20];
|
|
}
|
|
|
|
// Treat 255 as 254, so 255 routes doen't get included with minquals
|
|
// designed to only include applcalls
|
|
|
|
if (ptr1[20] == 255)
|
|
ptr1[20] = 254;
|
|
|
|
Qual = (((ROUTEQUAL * ptr1[20]) + 128)) / 256;
|
|
|
|
// I think we should normalize indirect routes twice
|
|
// as node not only sends differnet qual but adjusts incoming qual with it
|
|
|
|
// or should we ............
|
|
|
|
// We don't touch appl callsigns so I think everything here is an indirect route
|
|
|
|
if (ROUTE->OtherendsRouteQual && PORT->NormalizeQuality)
|
|
{
|
|
Qual = (Qual * ROUTEQUAL) / ROUTE->OtherendsRouteQual;
|
|
// not sure about this! Qual = (Qual * ROUTEQUAL) / ROUTE->OtherendsRouteQual; // Twice
|
|
|
|
if (Qual > ROUTEQUAL)
|
|
Qual = ROUTEQUAL;
|
|
}
|
|
}
|
|
|
|
// SEE IF BELOW MIN QUAL FOR AUTO UPDATES
|
|
|
|
if (Qual < MINQUAL)
|
|
continue;
|
|
|
|
// CHECK LINK IS IN DEST LIST
|
|
|
|
if (FindDestination(ptr1, &DEST) == 0)
|
|
{
|
|
if (DEST == NULL)
|
|
continue;
|
|
|
|
// CREATE DESTINATION RECORD
|
|
|
|
memset(DEST, 0, sizeof(struct DEST_LIST));
|
|
memcpy(DEST->DEST_CALL, ptr1, 7);
|
|
NUMBEROFNODES++;
|
|
}
|
|
|
|
ptr1 += 7;
|
|
|
|
// UPDATE ALIAS
|
|
|
|
memcpy(DEST->DEST_ALIAS, ptr1, 6);
|
|
|
|
ptr1 += 6;
|
|
|
|
// NOW POINTING AT BEST NEIGHBOUR - IF THIS IS US, THEN ROUTE IS A LOOP
|
|
|
|
if (CompareCalls(ptr1, NETROMCALL))
|
|
Qual = 0;
|
|
|
|
// DEST IS NOW IN TABLE -
|
|
|
|
// 1. SEE IF THIS ROUTE IS IN TABLE - IF SO UPDATE QUALITY,
|
|
// IF NOT, ADD THIS ONE IF IT HAS HIGHER QUALITY THAN EXISTING ONES
|
|
|
|
|
|
PROCROUTES(DEST, ROUTE, Qual);
|
|
ptr1 += 8;
|
|
IgnoreNode:;
|
|
}
|
|
}
|
|
|
|
VOID PROCROUTES(struct DEST_LIST * DEST, struct ROUTE * ROUTE, int Qual)
|
|
{
|
|
// ADD NEIGHBOUR ADDRESS IN ROUTE TO NODE's ROUTE TABLE IF BETTER QUALITY THAN THOSE PRESENT
|
|
|
|
int Index = 0;
|
|
struct NR_DEST_ROUTE_ENTRY Temp;
|
|
|
|
if (DEST->DEST_STATE & 0x80) // BBS ENTRY
|
|
return;
|
|
|
|
for (Index = 0; Index < 4; Index++)
|
|
{
|
|
if (DEST->NRROUTE[Index].ROUT_NEIGHBOUR == ROUTE)
|
|
{
|
|
if (Index == 0)
|
|
{
|
|
// THIS IS A REFRESH OF BEST - IF THIS ISNT ACTIVE ROUTE, MAKE IT ACTIVE
|
|
|
|
if (DEST->DEST_ROUTE > 1) // LEAVE IT IF NOT SELECTED OR ALREADY USING BEST
|
|
DEST->DEST_ROUTE = 1;
|
|
}
|
|
|
|
goto UpdatateThisEntry;
|
|
}
|
|
}
|
|
|
|
// NOT IN ANY ROUTE
|
|
|
|
Index = 0;
|
|
|
|
if (DEST->NRROUTE[0].ROUT_NEIGHBOUR == 0)
|
|
goto UpdatateThisEntry; // SPARE ENTRY, SO USE IT
|
|
|
|
if (DEST->NRROUTE[0].ROUT_QUALITY < Qual)
|
|
{
|
|
// New route is better than best, so move other two down and add here
|
|
|
|
DEST->NRROUTE[2] = DEST->NRROUTE[1];
|
|
DEST->NRROUTE[1] = DEST->NRROUTE[0];
|
|
|
|
DEST->DEST_ROUTE = 0; // Se we will switch to new one
|
|
|
|
goto UpdatateThisEntry;
|
|
}
|
|
|
|
Index = 1;
|
|
|
|
if (DEST->NRROUTE[1].ROUT_NEIGHBOUR == 0)
|
|
goto UpdatateThisEntry; // SPARE ENTRY, SO USE IT
|
|
|
|
if (DEST->NRROUTE[1].ROUT_QUALITY < Qual)
|
|
{
|
|
// New route is better than second, so move down and add here
|
|
|
|
DEST->NRROUTE[2] = DEST->NRROUTE[1];
|
|
goto UpdatateThisEntry;
|
|
}
|
|
|
|
Index = 2;
|
|
|
|
if (DEST->NRROUTE[2].ROUT_NEIGHBOUR == 0)
|
|
goto UpdatateThisEntry;
|
|
|
|
if (DEST->NRROUTE[2].ROUT_QUALITY < Qual)
|
|
{
|
|
// New route is better than third, so add here
|
|
goto UpdatateThisEntry;
|
|
}
|
|
|
|
// THIS ROUTE IS WORSE THAN ANY OF THE CURRENT 3 - IGNORE IT
|
|
|
|
return;
|
|
|
|
|
|
UpdatateThisEntry:
|
|
|
|
DEST->NRROUTE[Index].ROUT_NEIGHBOUR = ROUTE;
|
|
|
|
// I DONT KNOW WHY I DID THIS, BUT IT CAUSES REFLECTED ROUTES
|
|
// TO BE SET UP WITH OBS = 0. THIS MAY PREVENT A VALID ALTERNATE
|
|
// VIA THE SAME NODE TO FAIL TO BE FOUND. SO I'LL TAKE OUT THE
|
|
// TEST AND SEE IF ANYTHING NASTY HAPPENS
|
|
// IT DID - THIS IS ALSO CALLED BY CHECKL3TABLES. TRY RESETING
|
|
// OBS, BUT NOT QUALITY
|
|
|
|
if ((DEST->NRROUTE[Index].ROUT_OBSCOUNT & 0x80) == 0)
|
|
DEST->NRROUTE[Index].ROUT_OBSCOUNT = OBSINIT; // SET OBSOLESCENCE COUNT
|
|
|
|
if (Qual)
|
|
DEST->NRROUTE[Index].ROUT_QUALITY = Qual; // IF ZERO, SKIP UPDATE
|
|
|
|
// IT IS POSSIBLE ROUTES ARE NOW OUT OF ORDER
|
|
|
|
SORTROUTES:
|
|
|
|
if (DEST->NRROUTE[1].ROUT_QUALITY > DEST->NRROUTE[0].ROUT_QUALITY)
|
|
{
|
|
// SWAP 1 AND 2
|
|
|
|
Temp = DEST->NRROUTE[0];
|
|
|
|
DEST->NRROUTE[0] = DEST->NRROUTE[1];
|
|
DEST->NRROUTE[1] = Temp;
|
|
|
|
DEST->DEST_ROUTE = 0; // FORCE A RE-ASSESSMENT
|
|
}
|
|
|
|
if (DEST->NRROUTE[2].ROUT_QUALITY > DEST->NRROUTE[1].ROUT_QUALITY)
|
|
{
|
|
// SWAP 2 AND 3
|
|
|
|
Temp = DEST->NRROUTE[1];
|
|
|
|
DEST->NRROUTE[1] = DEST->NRROUTE[2];
|
|
DEST->NRROUTE[2] = Temp;
|
|
|
|
goto SORTROUTES; // 1 AND 2 MAY NOW BE WRONG!
|
|
}
|
|
}
|
|
|
|
int COUNTNODES(struct ROUTE * ROUTE)
|
|
{
|
|
// COUNT NODES WITH ROUTE VIA NEIGHBOUR
|
|
|
|
int count = 0;
|
|
int n = MAXDESTS;
|
|
struct DEST_LIST * DEST = DESTS; // NODE LIST
|
|
|
|
while (n--)
|
|
{
|
|
if (DEST->NRROUTE[0].ROUT_NEIGHBOUR == ROUTE)
|
|
count++;
|
|
else if (DEST->NRROUTE[1].ROUT_NEIGHBOUR == ROUTE)
|
|
count++;
|
|
else if (DEST->NRROUTE[2].ROUT_NEIGHBOUR == ROUTE)
|
|
count++;
|
|
else if (DEST->ROUTE[0].ROUT_NEIGHBOUR == ROUTE)
|
|
count++;
|
|
else if (DEST->ROUTE[1].ROUT_NEIGHBOUR == ROUTE)
|
|
count++;
|
|
else if (DEST->ROUTE[2].ROUT_NEIGHBOUR == ROUTE)
|
|
count++;
|
|
|
|
DEST++;
|
|
}
|
|
return count;
|
|
}
|
|
|
|
VOID SENDNODE00();
|
|
VOID L3BG();
|
|
|
|
|
|
|
|
VOID SENDNEXTNODESFRAGMENT();
|
|
|
|
VOID SENDNODESMSG()
|
|
{
|
|
if (NODESINPROGRESS)
|
|
return;
|
|
|
|
L3CURRENTPORT = PORTTABLE;
|
|
SENDNEXTNODESFRAGMENT();
|
|
}
|
|
|
|
int fragmentCount = 0; // Node broadcast packets sent to current port
|
|
|
|
VOID SENDNEXTNODESFRAGMENT()
|
|
{
|
|
// SEND NEXT FRAGMENT OF A NODES BROADCAST
|
|
|
|
// FRAGMENTS ARE SENT AT 10 SECONDS INTERVALS - PARTLY TO REDUCE
|
|
// QRM, PARTLY TO REDUCE LOAD ON BUFFERS (AND TX POWER SUPPLIES!)
|
|
|
|
// SEND TO PORT IN CURRENTPORT, STARTING AT CURRENTNODE
|
|
|
|
struct PORTCONTROL * PORT = L3CURRENTPORT;
|
|
dest_list * DEST = CURRENTNODE;
|
|
MESSAGE * Buffer;
|
|
int Count;
|
|
int Qual;
|
|
int CURRENTPORTNO, TXMINQUAL;
|
|
UCHAR * ptr1, * ptr2;
|
|
|
|
if (DEST == 0)
|
|
{
|
|
// FIRST FRAGMENT TO A PORT
|
|
|
|
fragmentCount = 0;
|
|
|
|
// Don't send NODES to Shared TX or INP3 Port
|
|
|
|
while (PORT->PORTQUALITY == 0 || PORT->TXPORT || PORT->INP3ONLY)
|
|
{
|
|
// No NODES to this port, so go to next
|
|
|
|
PORT = PORT->PORTPOINTER;
|
|
if (PORT == NULL)
|
|
{
|
|
// Finished
|
|
|
|
NODESINPROGRESS = 0;
|
|
return;
|
|
}
|
|
}
|
|
|
|
L3CURRENTPORT = PORT;
|
|
|
|
DEST = CURRENTNODE = DESTS; // START OF LIST
|
|
NODESINPROGRESS = 1;
|
|
}
|
|
|
|
CURRENTPORTNO = PORT->PORTNUMBER;
|
|
|
|
TXMINQUAL = PORT->PORTMINQUAL;
|
|
|
|
if (TXMINQUAL == 0)
|
|
TXMINQUAL = 1; // Dont send zero
|
|
|
|
Buffer = GetBuff();
|
|
|
|
if (Buffer == 0)
|
|
return;
|
|
|
|
Buffer->PORT = CURRENTPORTNO;
|
|
|
|
memcpy(Buffer->ORIGIN, NETROMCALL, 7);
|
|
memcpy(Buffer->DEST, NODECALL, 7);
|
|
|
|
Buffer->ORIGIN[6] |= 0x61; // SET CMD END AND RESERVED BITS
|
|
|
|
Buffer->CTL = UI;
|
|
Buffer->PID = 0xCF; // Netrom
|
|
|
|
ptr1 = &Buffer->L2DATA[0];
|
|
|
|
*(ptr1++) = 0xff; // Nodes Flag
|
|
|
|
memcpy(ptr1, MYALIASTEXT, 6);
|
|
|
|
ptr1+= 6;
|
|
|
|
// ADD DESTINATION INFO (UNLESS BBS ONLY)
|
|
|
|
// If NODE = 0 just send application nodes
|
|
|
|
Count = PORT->NODESPACLEN;
|
|
|
|
if (Count == 0)
|
|
Count = 256;
|
|
|
|
if (Count < 50) // STUPIDLY SMALL?
|
|
Count = 50; // EVEN THIS IS RATHER SILLY
|
|
|
|
Count -= 22; // Fixed Part
|
|
|
|
Count /= 21; // 21 Bytres per entry
|
|
|
|
while (Count)
|
|
{
|
|
if (DEST >= ENDDESTLIST)
|
|
{
|
|
CURRENTNODE = 0; // Finished on this port
|
|
L3CURRENTPORT = PORT->PORTPOINTER;
|
|
if (L3CURRENTPORT == NULL)
|
|
{
|
|
// Finished
|
|
|
|
NODESINPROGRESS = 0;
|
|
}
|
|
goto Sendit;
|
|
}
|
|
|
|
if (DEST->DEST_CALL[0] != 0x40 && DEST->NRROUTE[0].ROUT_QUALITY >= TXMINQUAL &&
|
|
DEST->NRROUTE[0].ROUT_OBSCOUNT >= OBSMIN &&
|
|
(NODE == 1 || DEST->DEST_STATE & 0x80)) // Only send appl nodes if DEST = 0;
|
|
{
|
|
// Send it
|
|
|
|
ptr2 = &DEST->DEST_CALL[0];
|
|
memcpy(ptr1, ptr2, 13); // Dest and Alias
|
|
ptr1 += 13;
|
|
|
|
ptr2 = (UCHAR *)DEST->NRROUTE[0].ROUT_NEIGHBOUR;
|
|
|
|
if (ptr2 == 0)
|
|
|
|
// DUMMY POINTER IN BBS ENTRY - PUT IN OUR CALL
|
|
|
|
ptr2 = MYCALL;
|
|
|
|
memcpy(ptr1, ptr2, 7); // Neighbour Call
|
|
ptr1 += 7;
|
|
|
|
Qual = 100;
|
|
|
|
if (DEST->NRROUTE[0].ROUT_NEIGHBOUR && DEST->NRROUTE[0].ROUT_NEIGHBOUR->NEIGHBOUR_PORT == CURRENTPORTNO)
|
|
{
|
|
// BEST NEIGHBOUR IS ON CURRENT PORT - REDUCE QUALITY BY QUAL_ADJUST
|
|
|
|
Qual -= PORT->QUAL_ADJUST;
|
|
}
|
|
|
|
Qual *= DEST->NRROUTE[0].ROUT_QUALITY;
|
|
Qual /= 100;
|
|
|
|
*(ptr1++) = (UCHAR)Qual;
|
|
|
|
Count--;
|
|
}
|
|
DEST++;
|
|
}
|
|
|
|
CURRENTNODE = DEST;
|
|
|
|
Sendit:
|
|
|
|
Buffer->LENGTH = (int)(ptr1 - (UCHAR *)Buffer);
|
|
|
|
if (Buffer->LENGTH > 35 || fragmentCount == 0) // Always send first even if no other nodes
|
|
{
|
|
if (PORT->TNC && PORT->TNC->Hardware == H_VARA)
|
|
SendVARANetromNodes(PORT->TNC, Buffer);
|
|
else
|
|
PUT_ON_PORT_Q(PORT, Buffer);
|
|
|
|
fragmentCount++;
|
|
}
|
|
else
|
|
ReleaseBuffer(Buffer);
|
|
|
|
}
|
|
|
|
VOID L3LINKCLOSED(struct _LINKTABLE * LINK, int Reason)
|
|
{
|
|
// L2 SESSION HAS SHUT DOWN (PROBABLY DUE TO INACTIVITY)
|
|
|
|
struct ROUTE * ROUTE;
|
|
|
|
// CLEAR NEIGHBOUR
|
|
|
|
ROUTE = LINK->NEIGHBOUR; // TO NEIGHBOUR
|
|
|
|
if (ROUTE)
|
|
{
|
|
LINK->NEIGHBOUR = NULL; // Clear links
|
|
ROUTE->NEIGHBOUR_LINK = NULL;
|
|
|
|
CLEARACTIVEROUTE(ROUTE, Reason); // CLEAR ASSOCIATED DEST ENTRIES
|
|
}
|
|
}
|
|
|
|
VOID CLEARACTIVEROUTE(struct ROUTE * ROUTE, int Reason)
|
|
{
|
|
// FIND ANY DESINATIONS WITH [ESI] AS ACTIVE NEIGHBOUR, AND
|
|
// SET INACTIVE
|
|
|
|
dest_list * DEST;
|
|
int n;
|
|
|
|
if (Reason != NORMALCLOSE || ROUTE->INP3Node)
|
|
TellINP3LinkGone(ROUTE);
|
|
|
|
DEST = DESTS;
|
|
n = MAXDESTS;
|
|
|
|
DEST--; // So we can increment at start of loop
|
|
|
|
while (n--)
|
|
{
|
|
DEST++;
|
|
|
|
if (DEST->DEST_ROUTE == 0)
|
|
continue;
|
|
|
|
if (DEST->ROUTE[DEST->DEST_ROUTE].ROUT_NEIGHBOUR == ROUTE) // Is this the active route
|
|
{
|
|
// Yes, so clear
|
|
|
|
DEST->DEST_ROUTE = 0; // SET NO ACTIVE ROUTE
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
VOID L3TimerProc()
|
|
{
|
|
int i;
|
|
struct PORTCONTROL * PORT = PORTTABLE;
|
|
struct ROUTE * ROUTE;
|
|
|
|
struct _LINKTABLE * LINK;
|
|
|
|
// CHECK FOR EXCESSIVE BUFFERS QUEUED AT LINK LEVEL
|
|
|
|
if (QCOUNT < 100)
|
|
{
|
|
LINK = LINKS;
|
|
i = MAXLINKS;
|
|
|
|
while (i--);
|
|
{
|
|
if (LINK->LINKTYPE == 3) // Only if Internode
|
|
{
|
|
if (COUNT_AT_L2(LINK) > 50)
|
|
{
|
|
Debugprintf("Excessive L3 Queue");
|
|
L3LINKCLOSED(LINK, LINKSTUCK); // REPORT TO LEVEL 3
|
|
CLEAROUTLINK(LINK);
|
|
}
|
|
}
|
|
LINK++;
|
|
}
|
|
}
|
|
|
|
STATSTIME++;
|
|
|
|
if (IDTIMER) // Not if Disabled
|
|
{
|
|
IDTIMER--;
|
|
|
|
if (IDTIMER == 0)
|
|
{
|
|
IDTIMER = IDINTERVAL;
|
|
SENDIDMSG();
|
|
}
|
|
}
|
|
|
|
// CHECK FOR BEACON
|
|
|
|
if (BTTIMER) // Not if Disabled
|
|
{
|
|
BTTIMER--;
|
|
|
|
if (BTTIMER == 0)
|
|
{
|
|
BTTIMER = BTINTERVAL;
|
|
SENDBTMSG();
|
|
}
|
|
}
|
|
|
|
// CHECK FOR NODES BROADCAST
|
|
|
|
if (L3TIMER) // Not if Disabled
|
|
{
|
|
L3TIMER--;
|
|
|
|
if (L3TIMER == 0)
|
|
{
|
|
// UPDATE DEST LIST AND SEND 'NODES' MESSAGE
|
|
|
|
L3TIMER = L3INTERVAL;
|
|
UPDATEDESTLIST();
|
|
SENDNODESMSG();
|
|
}
|
|
}
|
|
|
|
// TIDY ROUTES
|
|
|
|
ROUTE = NEIGHBOURS;
|
|
i = MAXNEIGHBOURS;
|
|
|
|
ROUTE--;
|
|
|
|
while (i--)
|
|
{
|
|
ROUTE++;
|
|
|
|
if (ROUTE->NEIGHBOUR_FLAG & 1) // Locked?
|
|
continue;
|
|
|
|
if (ROUTE->NEIGHBOUR_LINK) // Has an active Session
|
|
continue;
|
|
|
|
if (COUNTNODES(ROUTE) == 0) // NODES USING THIS DESTINATION
|
|
{
|
|
// IF NUMBER USING ROUTE IS ZERO, DELETE IT
|
|
|
|
memset(ROUTE, 0, sizeof (struct ROUTE));
|
|
}
|
|
}
|
|
}
|
|
|
|
VOID L3FastTimer()
|
|
{
|
|
// CALLED ONCE PER SECOND - USED ONLY TO SEND NEXT PART OF A NODES OR
|
|
// ID MESSAGE SEQUENCE
|
|
|
|
MESSAGE * Msg;
|
|
struct PORTCONTROL * PORT = PORTTABLE;
|
|
|
|
INP3TIMER();
|
|
|
|
// Send Node faster if VARA
|
|
|
|
if (NODESINPROGRESS && L3CURRENTPORT->TNC && L3CURRENTPORT->TNC->NetRomMode)
|
|
SENDNEXTNODESFRAGMENT();
|
|
|
|
L3_10SECS--;
|
|
|
|
if (L3_10SECS == 0)
|
|
{
|
|
L3_10SECS = 10;
|
|
|
|
if (IDMSG_Q) // ID/BEACON TO SEND
|
|
{
|
|
Msg = Q_REM(&IDMSG_Q);
|
|
|
|
PORT = GetPortTableEntryFromPortNum(Msg->PORT);
|
|
|
|
if (PORT && PORT->TXPORT == 0) // DONT SEND IF SHARED TX
|
|
PUT_ON_PORT_Q(PORT, Msg);
|
|
else
|
|
ReleaseBuffer(Msg);
|
|
}
|
|
|
|
if (NODESINPROGRESS)
|
|
SENDNEXTNODESFRAGMENT();
|
|
}
|
|
}
|
|
|
|
|
|
VOID UPDATEDESTLIST()
|
|
{
|
|
// DECREMENT OBS COUNTERS ON EACH ROUTE, AND REMOVE 'DEAD' ENTRIES
|
|
|
|
dest_list * DEST;
|
|
int n;
|
|
|
|
DEST = DESTS;
|
|
n = MAXDESTS;
|
|
|
|
DEST--; // So we can increment at start of loop
|
|
|
|
while (n--)
|
|
{
|
|
DEST++;
|
|
|
|
if (DEST->DEST_CALL[0] == 0) // SPARE ENTRY
|
|
continue;
|
|
|
|
if (DEST->DEST_STATE & 0x80) // LOCKED DESTINATION
|
|
continue;
|
|
|
|
UPDEST000:
|
|
|
|
if (DEST->NRROUTE[0].ROUT_NEIGHBOUR == 0) // NO DESTINATIONS - DELETE ENTRY unless inp3 routes
|
|
{
|
|
// Any INP3 Routes?
|
|
|
|
if (DEST->ROUTE[0].ROUT_NEIGHBOUR == 0)
|
|
{
|
|
// NO ROUTES LEFT TO DEST - REMOVE IT
|
|
|
|
REMOVENODE(DEST); // Unchain, Clear queue and zap
|
|
}
|
|
continue;
|
|
}
|
|
|
|
if (DEST->NRROUTE[0].ROUT_OBSCOUNT == 0)
|
|
{
|
|
// FAILED IN USE - DELETE
|
|
|
|
MOVEALL(DEST);
|
|
goto UPDEST000; //LOOP BACK TO PROCESS MOVED ENTRIES
|
|
}
|
|
|
|
if ((DEST->NRROUTE[0].ROUT_OBSCOUNT & 0x80) == 0) // Locked?
|
|
{
|
|
DEST->NRROUTE[0].ROUT_OBSCOUNT--;
|
|
|
|
if (DEST->NRROUTE[0].ROUT_OBSCOUNT == 0) // Timed out
|
|
{
|
|
MOVEALL(DEST);
|
|
goto UPDEST000; //LOOP BACK TO PROCESS MOVED ENTRIES
|
|
}
|
|
}
|
|
|
|
// Process Next Neighbour
|
|
|
|
UPDEST010:
|
|
|
|
if (DEST->NRROUTE[1].ROUT_NEIGHBOUR == 0)
|
|
continue; // NO MORE DESTINATIONS
|
|
|
|
if (DEST->NRROUTE[1].ROUT_OBSCOUNT == 0)
|
|
{
|
|
// FAILED IN USE - DELETE
|
|
|
|
MOVE3TO2(DEST);
|
|
goto UPDEST010; //LOOP BACK TO PROCESS MOVED ENTRIES
|
|
}
|
|
|
|
if ((DEST->NRROUTE[1].ROUT_OBSCOUNT & 0x80) == 0) // Locked?
|
|
{
|
|
DEST->NRROUTE[1].ROUT_OBSCOUNT--;
|
|
|
|
if (DEST->NRROUTE[1].ROUT_OBSCOUNT == 0) // Timed out
|
|
{
|
|
MOVE3TO2(DEST);
|
|
goto UPDEST010; //LOOP BACK TO PROCESS MOVED ENTRIES
|
|
}
|
|
}
|
|
|
|
// Process Next Neighbour
|
|
|
|
if (DEST->NRROUTE[2].ROUT_NEIGHBOUR == 0)
|
|
continue; // NO MORE DESTINATIONS
|
|
|
|
if (DEST->NRROUTE[2].ROUT_OBSCOUNT == 0)
|
|
{
|
|
// FAILED IN USE - DELETE
|
|
|
|
CLEARTHIRD(DEST);
|
|
continue;
|
|
}
|
|
|
|
if ((DEST->NRROUTE[2].ROUT_OBSCOUNT & 0x80) == 0) // Locked?
|
|
{
|
|
DEST->NRROUTE[2].ROUT_OBSCOUNT--;
|
|
|
|
if (DEST->NRROUTE[2].ROUT_OBSCOUNT == 0) // Timed out
|
|
{
|
|
CLEARTHIRD(DEST);
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
VOID MOVEALL(dest_list * DEST)
|
|
{
|
|
DEST->NRROUTE[0] = DEST->NRROUTE[1];
|
|
MOVE3TO2(DEST);
|
|
}
|
|
|
|
VOID MOVE3TO2(dest_list * DEST)
|
|
{
|
|
DEST->NRROUTE[1] = DEST->NRROUTE[2];
|
|
CLEARTHIRD(DEST);
|
|
}
|
|
|
|
VOID CLEARTHIRD(dest_list * DEST)
|
|
{
|
|
memset(&DEST->NRROUTE[2], 0, sizeof (struct NR_DEST_ROUTE_ENTRY));
|
|
DEST->DEST_ROUTE = 0; // CANCEL ACTIVE ROUTE, SO WILL RE-ASSESS BEST
|
|
}
|
|
|
|
// L4 Flags Values
|
|
|
|
#define DISCPENDING 8 // SEND DISC WHEN ALL DATA ACK'ED
|
|
|
|
VOID REMOVENODE(dest_list * DEST)
|
|
{
|
|
TRANSPORTENTRY * L4 = L4TABLE;
|
|
int n = MAXCIRCUITS;
|
|
|
|
// Remove a node, either because routes have gone, or APPL API has invalidated it
|
|
|
|
while (DEST->DEST_Q)
|
|
ReleaseBuffer(Q_REM(&DEST->DEST_Q));
|
|
|
|
// MAY NEED TO CHECK FOR L4 CIRCUITS USING DEST, BUT PROBABLY NOT,
|
|
// AS THEY SHOULD HAVE TIMED OUT LONG AGO
|
|
|
|
// Not necessarily true with INP3, so had better check
|
|
|
|
while (n--)
|
|
{
|
|
if (L4->L4USER[0])
|
|
{
|
|
if (L4->L4TARGET.DEST == DEST)
|
|
{
|
|
// Session to/from this Dest
|
|
|
|
TRANSPORTENTRY * Partner = L4->L4CROSSLINK;
|
|
char Nodename[20];
|
|
|
|
Nodename[DecodeNodeName(DEST->DEST_CALL, Nodename)] = 0; // null terminate
|
|
|
|
Debugprintf("Delete Node for %s Called with active L4 Session - State %d",
|
|
Nodename, L4->L4STATE);
|
|
|
|
if (Partner)
|
|
{
|
|
// if connnecting, send error message and drop back to command level
|
|
|
|
if (L4->L4STATE == 2)
|
|
{
|
|
struct DATAMESSAGE * Msg = GetBuff();
|
|
Partner->L4CROSSLINK = 0; // Back to command lewel
|
|
|
|
if (Msg)
|
|
{
|
|
UCHAR * ptr1;
|
|
|
|
Msg->PID = 0xf0;
|
|
ptr1 = SetupNodeHeader(Msg);
|
|
ptr1 += sprintf(ptr1, "Error - Node %s has disappeared\r", Nodename);
|
|
|
|
Msg->LENGTH = (int)(ptr1 - (UCHAR *)Msg);
|
|
C_Q_ADD(&Partner->L4TX_Q, Msg);
|
|
PostDataAvailable(Partner);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Failed in session - treat as if a L4DREQ received
|
|
|
|
CLOSECURRENTSESSION(Partner);
|
|
}
|
|
}
|
|
CLEARSESSIONENTRY(L4);
|
|
}
|
|
}
|
|
L4++;
|
|
}
|
|
memset(DEST, 0, sizeof(struct DEST_LIST));
|
|
NUMBEROFNODES--;
|
|
}
|
|
|
|
VOID L3CONNECTFAILED(struct _LINKTABLE * LINK)
|
|
{
|
|
// L2 LINK SETUP HAS FAILED - SEE IF ANOTHER NEIGHBOUR CAN BE USED
|
|
|
|
struct PORTCONTROL * PORT = PORTTABLE;
|
|
struct ROUTE * ROUTE;
|
|
|
|
|
|
ROUTE = LINK->NEIGHBOUR; // TO NEIGHBOUR
|
|
|
|
if (ROUTE == NULL)
|
|
return; // NOTHING ???
|
|
|
|
TellINP3LinkSetupFailed(ROUTE);
|
|
|
|
ROUTE->NEIGHBOUR_LINK = 0; // CLEAR IT
|
|
|
|
L3TRYNEXTDEST(ROUTE); // RESET ASSOCIATED DEST ENTRIES
|
|
}
|
|
|
|
|
|
VOID L3TRYNEXTDEST(struct ROUTE * ROUTE)
|
|
{
|
|
// FIND ANY DESINATIONS WITH [ESI] AS ACTIVE NEIGHBOUR, AND
|
|
// SET NEXT BEST NEIGHBOUR (IF ANY) ACTIVE
|
|
|
|
int n = MAXDESTS;
|
|
struct DEST_LIST * DEST = DESTS; // NODE LIST
|
|
int ActiveRoute;
|
|
|
|
while (n--)
|
|
{
|
|
ActiveRoute = DEST->DEST_ROUTE;
|
|
|
|
if (ActiveRoute)
|
|
{
|
|
ActiveRoute --; // Routes numbered 1 - 6, idex from 0
|
|
|
|
if (DEST->NRROUTE[ActiveRoute].ROUT_NEIGHBOUR == ROUTE)
|
|
{
|
|
// We were best
|
|
|
|
// NEIGHBOUR HAS FAILED - DECREMENT OBSCOUNT
|
|
// AND TRY TO ACTIVATE ANOTHER (IF ANY)
|
|
|
|
if (DEST->NRROUTE[ActiveRoute].ROUT_OBSCOUNT)
|
|
{
|
|
// IF ALREADY ZERO - WILL BE DELETED BY NEXT NODES UPDATE
|
|
|
|
if ((DEST->NRROUTE[ActiveRoute].ROUT_OBSCOUNT & 0x80) == 0)
|
|
{
|
|
// not Locked
|
|
|
|
DEST->NRROUTE[ActiveRoute].ROUT_OBSCOUNT--;
|
|
|
|
// if ROUTE HAS EXPIRED - WE SHOULD CLEAR IT, AND MOVE OTHERS (IF ANY) UP
|
|
}
|
|
}
|
|
|
|
// REMOVE FIRST MESSAGE FROM DEST_Q. L4 WILL RETRY - IF IT IS LEFT HERE
|
|
// WE WILL TRY TO ACTIVATE THE DESTINATION FOR EVER
|
|
|
|
if (DEST->DEST_Q)
|
|
ReleaseBuffer(Q_REM(&DEST->DEST_Q));
|
|
|
|
DEST->DEST_ROUTE++; // TO NEXT
|
|
|
|
if (DEST->DEST_ROUTE = 7)
|
|
DEST->DEST_ROUTE = 1; // TRY TO ACTIVATE FIRST
|
|
}
|
|
}
|
|
DEST++;
|
|
}
|
|
}
|
|
|
|
VOID CHECKNEIGHBOUR(struct _LINKTABLE * LINK, L3MESSAGEBUFFER * Msg)
|
|
{
|
|
// MESSAGE RECEIVED ON LINK WITH NO ROUTE - SET ONE UP
|
|
|
|
struct ROUTE * ROUTE;
|
|
struct PORTCONTROL * PORT = LINK->LINKPORT;
|
|
int Portno = PORT->PORTNUMBER;
|
|
|
|
if (FindNeighbour(LINK->LINKCALL, Portno, &ROUTE) == 0)
|
|
{
|
|
if (ROUTE == 0)
|
|
goto L3CONN08; // TABLE FULL??
|
|
|
|
// FIRST MAKE SURE WE ARE ALLOWING NETWORK ACTIVITY ON THIS PORT
|
|
|
|
if (PORT->PORTQUALITY == 0 && PORT->INP3ONLY == 0)
|
|
return;
|
|
|
|
ROUTE->NEIGHBOUR_QUAL = PORT->PORTQUALITY;
|
|
ROUTE->INP3Node = PORT->INP3ONLY;
|
|
|
|
memcpy(ROUTE->NEIGHBOUR_CALL, LINK->LINKCALL, 7);
|
|
|
|
ROUTE->NEIGHBOUR_PORT = Portno;
|
|
ROUTE->NoKeepAlive = PORT->PortNoKeepAlive;
|
|
}
|
|
|
|
// SET THIS AS ACTIVE LINK IF NONE PRESENT
|
|
|
|
if (ROUTE->NEIGHBOUR_LINK == 0)
|
|
{
|
|
ROUTE->NEIGHBOUR_LINK = LINK;
|
|
ROUTE->NEIGHBOUR_PORT = Portno;
|
|
}
|
|
|
|
L3CONN08:
|
|
|
|
LINK->NEIGHBOUR = ROUTE; // SET LINK - NEIGHBOUR
|
|
}
|
|
|
|
struct DEST_LIST * CHECKL3TABLES(struct _LINKTABLE * LINK, L3MESSAGEBUFFER * Msg)
|
|
{
|
|
// CHECK THAT FAR NODE IS IN 'NODES'.
|
|
// RETURNS POINTER TO NEIGHBOUR ENTRY
|
|
|
|
struct ROUTE * ROUTE;
|
|
struct DEST_LIST * DEST;
|
|
int Qual;
|
|
|
|
ROUTE = LINK->NEIGHBOUR;
|
|
|
|
if (FindDestination(Msg->L3SRCE, &DEST))
|
|
return DEST; // Ok
|
|
|
|
if (DEST == NULL)
|
|
return NULL; // Tsble Full
|
|
|
|
// ADD DESTINATION VIA NEIGHBOUR, UNLESS ON BLACK LIST
|
|
|
|
#ifdef EXCLUDEBITS
|
|
|
|
if (CheckExcludeList(Msg->L3SRCE) == 0)
|
|
return 0;
|
|
|
|
#endif
|
|
|
|
memcpy(DEST->DEST_CALL, Msg->L3SRCE, 7);
|
|
|
|
NUMBEROFNODES++;
|
|
|
|
// MAKE SURE NEIGHBOUR IS DEFINED FOR DESTINATION
|
|
|
|
// IF NODE is NEIGHBOUR, THEN CAN USE NEIGHBOUR QUALITY,
|
|
// OTHERWISE WE DONT KNOW ROUTE, SO MUST SET QUAL TO 0
|
|
|
|
|
|
Qual = 0; // DONT KNOW ROUTING, SO SET QUALITY TO ZERO
|
|
|
|
PROCROUTES(DEST, ROUTE, Qual); // ADD NEIGHBOUR IF NOT PRESENT
|
|
|
|
if (DEST->DEST_ROUTE == 0)
|
|
{
|
|
// MAKE CURRENT NEIGHBOUR ACTIVE
|
|
|
|
int n = 0;
|
|
|
|
DEST->DEST_ROUTE = 1;
|
|
|
|
while (n < 3)
|
|
{
|
|
if (DEST->NRROUTE[n].ROUT_NEIGHBOUR == ROUTE)
|
|
break;
|
|
|
|
DEST->DEST_ROUTE++;
|
|
n++;
|
|
}
|
|
|
|
if (DEST->DEST_ROUTE > 3)
|
|
{
|
|
DEST->DEST_ROUTE = 1; // CURRENT NEIGHBOUR ISNT IN DEST LIST - SET TO USE BEST
|
|
return DEST; // Can't update OBS
|
|
}
|
|
}
|
|
|
|
// REFRESH OBS COUNT
|
|
|
|
if (DEST->DEST_ROUTE)
|
|
{
|
|
int Index = DEST->DEST_ROUTE -1;
|
|
|
|
if (DEST->NRROUTE[Index].ROUT_OBSCOUNT & 0x80) // Locked:
|
|
return DEST;
|
|
|
|
DEST->NRROUTE[Index].ROUT_OBSCOUNT = OBSINIT;
|
|
}
|
|
return DEST;
|
|
}
|
|
|
|
VOID REFRESHROUTE(TRANSPORTENTRY * Session)
|
|
{
|
|
// RESET OBS COUNT ON CURRENT ROUTE TO DEST FOR SESSION IN [EBX]
|
|
// CALLED WHEN INFO ACK RECEIVED, INDICATING ROUTE IS STILL OK
|
|
|
|
struct DEST_LIST * DEST;
|
|
int Index;
|
|
|
|
DEST = Session->L4TARGET.DEST;
|
|
|
|
if (DEST == 0)
|
|
return; // No Dest ???
|
|
|
|
Index = DEST->DEST_ROUTE;
|
|
|
|
if (Index == 0)
|
|
return; // NONE ACTIVE???
|
|
|
|
Index--;
|
|
|
|
if (DEST->NRROUTE[Index].ROUT_OBSCOUNT & 0x80)
|
|
return; // Locked
|
|
|
|
DEST->NRROUTE[Index].ROUT_OBSCOUNT = OBSINIT;
|
|
}
|
|
|
|
|