TheNetNode-CB/src/l7conn.c

1240 lines
36 KiB
C
Raw Normal View History

2019-05-15 00:19:53 +02:00
/************************************************************************/
/* */
/* ***** ***** */
/* ***** ***** */
/* ***** ***** */
/* ***** ***** */
/* *************** *************** */
/* ***************** ***************** */
/* *************** *************** */
/* ***** ***** TheNetNode */
/* ***** ***** Portable */
/* ***** ***** Network */
/* ***** ***** Software */
/* */
/* File src/l7conn.c (maintained by: DF6LN) */
/* */
/* 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"
static char usrvia[2 * L2VLEN + L2IDLEN + 1];
static BOOLEAN is_cq(const char *, DEST *);
static WORD conprm2(DEST *, DEST *);
static WORD conprm(WORD *, char **, DEST *);
static void conerr(int, DEST *);
static void setupmsg(DEST *);
static void setptc(void *, UBYTE);
static void conhst(void);
static void conl4(DEST *);
static void conl2(DEST *);
static void con_cq(DEST *);
static void conusr(int, DEST *);
#define CP_L2CON 2
#define CP_L4CON 4
#define CP_HOSTCON 7
#define CP_CQ 42
#define CP_PARERR 10
#define CP_NODIG 11
#define CP_BADQUAL 12
#define CP_INTERN 13
#define CP_UNKNOWN 14
#define NOPORT (-1)
/************************************************************************/
/* Schaun, ob wir ein Call in der MH-Liste haben und dest fuellen. */
/*----------------------------------------------------------------------*/
BOOLEAN
isheard(char *id, DEST *dest)
{
MHEARD *mhp;
BOOLEAN exact = FALSE;
ULONG heard = 0L;
/* Es wird die L2-MHeardliste von hinten durchsucht */
for (mhp = (MHEARD *)l2heard.heardl.tail;
mhp != (MHEARD *)&l2heard.heardl;
mhp = mhp->prev)
{
if (cmpcal(id, mhp->id)) /* Call in MH-Liste */
{
if (cmpid(id, mhp->id)) /* SSID auch passend ? */
exact = TRUE;
else
{
/* Gefundener Eintrag ist aelter als gespeicherter Eintrag */
#ifndef __WIN32__
if (mhp->heard < heard)
#else
if ((ULONG)mhp->heard < heard)
#endif /* WIN32 */
continue;
else
heard = mhp->heard;
}
dest->port = mhp->port; /* Port aus MH */
#ifdef EAX25
dest->eax = mhp->eax_link;
#endif
dest->typ = 'U';
*dest->via = 0;
if (exact == TRUE) /* wenn SSID auch passt, fertig! */
return (TRUE);
}
}
/* Nichts exaktes gefunden */
return (FALSE);
}
#ifdef EAX25
/* Ermittelt fuer eine Port/Call-Kombination die Verwendung von EAX.25 */
BOOLEAN useEAX(char* call, WORD port)
{
DEST tmpDest;
/* Zuerst die Porteinstellungen ansehen */
if (port != NOPORT)
{
switch (portpar[port].eax_behaviour)
{
case 0: return (FALSE);
break;
case 1:
case 2: if (isheard(call, &tmpDest) == TRUE)
return (tmpDest.eax);
else
return (FALSE);
break;
case 3: return (TRUE);
break;
default: break;
}
}
return (FALSE);
}
#endif
/************************************************************************/
/* */
/* Feststellen, ob das gewuenschte Call ein CQ-Rufer ist. */
/* */
/************************************************************************/
static BOOLEAN
is_cq(const char *id, DEST *dest)
{
CQBUF *cqp;
for (cqp = (CQBUF *)cq_user.head; /* CQ-Liste durchsuchen */
cqp != (CQBUF *)&cq_user;
cqp = cqp->next)
{
if (cmpid(id, cqp->id)) /* Call stimmt? */
{
dest->uid = cqp->uid; /* UID eintragen */
cpyid(dest->call, id); /* Call auch */
dealoc((MBHEAD *)ulink((LEHEAD *)cqp)); /* CQ-Eintrag loeschen */
return (TRUE);
}
}
return (FALSE);
}
/************************************************************************/
/* */
/* Connectwunsch bewerten und analysieren */
/* */
/* user enthaelt die Daten des Connectwunsches: */
/* call enthaelt das Ziel */
/* via enthaelt den Repeaterpfad (optional) */
/* port enthaelt den Sendeport (optional) */
/* */
/* dest nimmt die Ergebnisse der Analysen auf. dest->call muss immer */
/* gesetzt werden, damit dem User eine Fehlermeldung mit Rufzeichen */
/* angezeigt werden kann ! */
/* */
/************************************************************************/
static WORD
conprm2(DEST *user, DEST *dest)
{
int l3route; /* L3-Erreichbarkeit */
char* call;
char* tmp;
/* rudimentaere Pruefung, ohne Ziel gehts nicht */
if (user->call[0] == 0)
return (CP_PARERR); /* Parameter-Fehler */
/* Connect an Hostkonsole ? */
if (cmpid(user->call, hostid))
return (CP_HOSTCON); /* Connect geht an Host */
/* Haben wir Repeater ? */
if (user->via[0] != 0)
{ /* Ja, haben wir */
/* printf("\nmit VIA\n"); */
tmp = (char*)ndigipt(user->via);
/* keiner mehr nach uns */
if (*tmp == 0)
call = user->call;
else
call = tmp;
}
else
{
/* Nein, keine Repeater */
/* printf("\nohne VIA\n"); */
call = user->call;
/* gleich auf CQ-User pruefen */
if (is_cq(call, dest))
return (CP_CQ);
}
#ifdef OS_IPLINK
/* Ist es ein IPConv-Rufzeichen. */
if (IPConvIS(user->call, dest))
return(CP_IPCONV);
#endif /* OS_IPLINK */
/* Eine passende Route suchen */
switch (l3route = l3_find_route(call, dest))
{
/* Ziel unerreichbar */
case NODE_DOWN:
/* Wenn der Node ausgefallen ist, duerfen auch User einen Umweg */
/* probieren wenn sie den Port angeben. */
/* printf("\nNODE_DOWN\n"); */
cpyid(dest->call, user->call);
if (user->via[0] != 0)
cpyidl(dest->via, user->via);
/* Ohne Port gibt es einen Fehler */
if (user->port == NOPORT)
{
/* printf("\nkein port angegeben\n"); */
return (CP_BADQUAL);
}
dest->typ = 'U'; /* User */
dest->port = user->port;
#ifdef EAX25
dest->eax = useEAX(dest->call, dest->port);
#endif
return (CP_L2CON);
break;
/* Ziel erreichbar */
case NODE_AVAILABLE:
/* printf("\nNODE_AVAILABLE\n"); */
cpyid(dest->call, user->call);
#ifdef CONNECTMOD_GOPORT
/* User hat ein Port angegeben, */
/* dann gehen wir ueber L2. */
if (user->port != NOPORT)
{
dest->typ = 'U'; /* User */
dest->port = user->port;
cpyidl(dest->via, user->via);
#ifdef EAX25
dest->eax = useEAX(dest->call, dest->port);
#endif
return (CP_L2CON);
}
#endif /* CONNECTMOD_GOPORT */
/* Geht der Weg ueber NETROM-Transport ? (N- oder I-Link) */
if (dest->typ <= NETROM)
{
if (call == user->via)
{
/* printf("\nVIA im L2 oder explizit L2 !!!\n"); */
if (user->via[0] != 0)
cpyidl(dest->via, user->via);
dest->typ = 'U';
#ifdef EAX25
dest->eax = useEAX(dest->call, dest->port);
#endif
return (CP_L2CON);
}
if (call == user->call)
{
/* printf("\nL4 CONNECT\n"); */
return (CP_L4CON);
}
}
/* Weg geht ueber L2 (F- oder L-Link) weiter */
if (user->via[0] != 0)
cpyidl(dest->via, user->via);
/* printf("\nL2-connect\n"); */
#ifdef EAX25
dest->eax = useEAX(call, dest->port);
#endif
return (CP_L2CON);
break;
/* Ziel unbekannt */
case NODE_UNKNOWN:
/* printf("\nNODE_UNKNOWN\n"); */
break; /* Durchfallen zum MHeard-Check */
default:
break;
}
/* Naechstes Ziel ist kein Nachbar und nicht im Routing */
/* Ist das Call in MHeard ? */
if (isheard(call, dest) == TRUE)
{
/* Ja */
/* printf("\nin MH\n"); */
cpyid(dest->call, user->call);
if (user->via[0] != 0)
cpyidl(dest->via, user->via);
/* Hat der User einen Port angegeben, dann nehmen wir den und */
/* nicht den, den MHeard gespeichert hat. */
if (user->port != NOPORT)
dest->port = user->port;
dest->typ = 'U';
return (CP_L2CON);
}
else
{
/* printf("\nNICHT in MH\n"); */
if (user->port == NOPORT)
{
/* printf("\nkein userport angegeben\n"); */
cpyid(dest->call, user->call);
if (user->via[0] != 0)
cpyidl(dest->via, user->via);
return (CP_UNKNOWN);
}
else /* User hat einen Port angegeben, weiter. */
{
/* printf("\nuserport angegeben\n"); */
}
}
if (user->port != NOPORT)
{
dest->port = user->port;
dest->via[0] = '\0';
dest->typ = 'U';
}
if (user->via[0] != 0)
{
cpyidl(dest->via, user->via);
dest->typ = 'U';
}
cpyid(dest->call, user->call);
#ifdef EAX25
dest->eax = useEAX(user->call, user->port);
#endif
/* Per L2 zum Ziel */
return (CP_L2CON);
}
/************************************************************************/
/* */
/* Parameter fuer den Connect-Befehl auswerten und in dest speichern. */
/* conprm() erhaelt eine Kopie von clipoi/clicnt und arbeitet damit. */
/* */
/************************************************************************/
static WORD
conprm(WORD *n, /* Restlaenge der Parameterzeile */
char **p, /* Parameter des Connectbefehls */
DEST *dest)
{
int index;
char ident[L2CALEN];
DEST user;
user.typ = 'U';
user.call[0] = 0;
user.port = NOPORT; /* Port setzen */
user.via[0] = 0;
if (!*n)
{
/* Keine Parameter - Verbindung zur Konsole gewuenscht */
return (CP_HOSTCON);
}
/* TEST DG9OBU */
/* Ist das Ziel ein Call ? Beim Sysop ist das egal, der darf alles */
if (getcal(n, p, issyso() ? FALSE : TRUE, user.call) != YES)
{
/* printf("\nein alias ?\n"); */
/* Connect-Parameter ist kein Rufzeichen - ist es ein ALIAS? */
if (getide(n, p, ident) != ERRORS)
{
/* printf("pruefe auf alias !\n"); */
/* Gueltiger ALIAS eingegeben - in der Nodes-Liste suchen */
if ((index = find_alias(ident)) != -1)
{
/* printf("gefunden !\n"); */
/* ALIAS in der Nodesliste gefunden, Call kopieren */
cpyid(user.call, netp->nodetab[index].id);
}
}
else
{
/*
else
printf("kein alias\n");
*/
}
}
getdig(n, p, TRUE, user.via); /* Digi-Liste uebernehmen */
getport(n, p, &user.port); /* Port-Angabe geht auch am Ende */
#ifdef PACSAT
if (cmpid(user.call, pacsatid))
{
ccpbox();
return (CP_INTERN);
}
else
#endif
return (conprm2(&user, dest));
}
#define CE_HTFULL 0
#define CE_CTFULL 1
#define CE_LTFULL 2
#define CE_BADQUAL 3
#define CE_SUSPEND 4
#define CE_BUSY 5
#define CE_PORTOFF 6
#define CE_INVCAL 7
#define CE_UNKNOWN 8
#define CE_INVLEN 9
#define CE_NODIG 10
/************************************************************************/
/* */
/* (xxx table full) Fehler ausgeben und Fernconnects ablehnen. */
/* */
/************************************************************************/
static void
conerr(int error, DEST *dest)
{
static const char *fullerr[] = {"Host",
"Circuit",
"Link"};
static const char *failerr[] = {" (not available)",
" (Callsign is restricted)"};
static const char *busyerr[] = {" (already connected)"};
MBHEAD *mbp;
int port;
char dstcal[10];
if (ptctab[userpo->uid].local == PTC_LOCAL)
{
switch (error)
{
case CE_HTFULL:
case CE_BUSY:
if (g_utyp(userpo->uid) == L2_USER)
rejlnk(g_ulink(userpo->uid)); /* durchfallen */
default:
disusr(userpo->uid);
}
}
else
{
switch (error)
{
case CE_HTFULL:
case CE_CTFULL:
case CE_LTFULL:
puttfu(fullerr[error]);
return;
case CE_BADQUAL:
case CE_SUSPEND:
mbp = putals(failmsg);
putid(dest->call, mbp);
putstr(failerr[error - CE_BADQUAL], mbp);
break;
case CE_BUSY:
mbp = putals(dmmsg);
putid(dest->call, mbp);
putstr(busyerr[error - CE_BUSY], mbp);
break;
case CE_PORTOFF:
call2str(dstcal, (dest->via[0] != 0 ? dest->via : dest->call));
mbp = putals("Port not in use\r");
putprintf(mbp, "(Routing shows %s reachable on port %u, but "
"port is disabled)", dstcal, dest->port);
break;
case CE_INVCAL:
mbp = putals(invcalmsg);
break;
case CE_UNKNOWN:
call2str(dstcal, (dest->via[0] != 0 ? dest->via : dest->call));
mbp = putals(failmsg);
#ifdef SPEECH
putprintf(mbp, speech_message(239), dstcal, dstcal);
#else
putprintf(mbp, "%s\rNode / User unknown! If %s is a L2-user, "
"try one of these commands:", dstcal, dstcal);
#endif
for (port = 0; port < L2PNUM; port++)
{
if ( (portenabled(port) && updmheard(port))
#ifdef L1TCPIP
/* Keine TCPIP-Interface auflisten. */
&&(!CheckPortTCP((UWORD)port))
#endif /* L1TCPIP */
)
putprintf(mbp, "\rCONNECT %s %s", dstcal, portpar[port].name);
}
break;
case CE_INVLEN:
mbp = putals("Too many repeaters (max. 8 repeaters)");
case CE_NODIG:
mbp = putals("Can't route");
break;
#ifdef L1TCPIP
case CE_TCPIP:
mbp = putals(failmsg);
putid(dest->call, mbp);
putstr(" (Port is suspended!)", mbp);
break;
#endif /* L1TCPIP */
default:
mbp = putals("Can't connect");
break;
}
putchr(CR, mbp);
prompt(mbp);
seteom(mbp);
}
}
/************************************************************************/
/* */
/* Nachricht ueber den Linkaufbau ausgeben. */
/* */
/************************************************************************/
static void
setupmsg(DEST *dest)
{
MBHEAD *mbp;
if (ptctab[userpo->uid].local == PTC_NORMAL)
{
switch (dest->typ)
{
case NETROM:
case TNN:
case INP:
case THENET:
mbp = putals("Interlink setup (");
putstr(portpar[dest->port].name, mbp);
break;
case FLEXNET:
mbp = putals("Interlink setup (via ");
putid(dest->nbrcal, mbp);
break;
case LOCAL_M:
mbp = putals("Link setup (");
putstr(portpar[dest->port].name, mbp);
break;
case LOCAL:
#ifdef LINKSMOD_LOCALMOD
case LOCAL_N:
case LOCAL_V:
#endif /* LINKSMOD_LOCALMOD */
mbp = putals("Local setup (");
putstr(portpar[dest->port].name, mbp);
break;
default:
mbp = putals("Downlink setup (");
putstr(portpar[dest->port].name, mbp);
putstr(") ...\r", mbp);
/*
* Bei einem Downlink soll keine LOOP-Warnung angezeigt werden.
*/
seteom(mbp);
return;
}
putstr(") ...\r", mbp);
#ifdef _INTERN
if (userport(userpo) == dest->port)
putstr("WARNING: Loop detected (HELP LOOP)\r", mbp);
#endif
seteom(mbp);
}
}
/************************************************************************/
/* */
/* Connect-Partner in der Patchcord-Liste eintragen. */
/* */
/************************************************************************/
static void
setptc(void *link, UBYTE typ)
{
PTCENT *ptcp;
PTCENT *p_ptcp;
UID uid = userpo->uid;
ptcp = ptctab + uid;
ptcp->p_uid = g_uid(link, typ);
p_ptcp = ptctab + ptcp->p_uid;
p_ptcp->p_uid = uid;
}
/************************************************************************/
/* */
/* Connect an die Host-Console herstellen. */
/* */
/************************************************************************/
static void
conhst(void)
{
int i;
for (i = 1, hstusr = hstubl + 1; i < MAXHST; ++i, ++hstusr)
if ((!hstusr->conflg) && (cmpid(hstusr->call, hostid)))
break;
if (i != MAXHST)
{
cpyid(hstusr->call, usrcal);
if (hstreq())
{
setptc(hstusr, HOST_USER);
userpo->status = US_CREQ;
return;
}
}
conerr(CE_HTFULL, NULL);
}
/*
* Level 4 Connect (Circuit) herstellen.
*/
static void
conl4(DEST *dest)
{
CIRBLK *cirp;
LNKBLK *frelnk;
int i;
for (i = 0, cirpoi = cirtab; i < NUMCIR; ++i, ++cirpoi)
if (cirpoi->state == L4SDSCED)
break;
if (i != NUMCIR)
{
cpyid(cirpoi->downca, dest->np->id);
cpyid(cirpoi->upcall, usrcal);
switch (g_utyp(userpo->uid))
{
case L4_USER: /* User ist Circuit */
cirp = (CIRBLK *)g_ulink(userpo->uid);
cpyid(cirpoi->upnod, cirp->upnod); /* Uplinkknoten setzen */
cpyidl(cirpoi->upnodv, cirp->upnodv); /* Digikette auch */
break;
case L2_USER: /* User ist L2-Link */
frelnk = (LNKBLK *)g_ulink(userpo->uid);
cpyid(cirpoi->upnod, myid); /* Uplink hier */
cpyidl(cirpoi->upnodv, frelnk->viaidl); /* und Digikette */
break;
default: /* User vom Host */
cpyid(cirpoi->upnod, myid); /* Uplink hier */
*cirpoi->upnodv = '\0'; /* kein Digi */
break;
}
cpyid(cirpoi->l3node, dest->np->id);
userpo->status = US_CREQ;
setptc(cirpoi, L4_USER);
setupmsg(dest); /* "Interlink setup ..." */
newcir();
}
else /* Circuit aufbauen */
conerr(CE_CTFULL, dest); /* Circuit Table full */
}
/*
* Level 2 Connect herstellen.
*/
static void
conl2(DEST *dest)
{
#ifdef L1TCPIP
/* TCPIP-Frames haben hier nix zu suchen. */
if (CheckPortTCP(dest->port))
{
conerr(CE_TCPIP, dest);
return;
}
#endif /* L1TCPIP */
/* User-Suspendierung pruefen */
if (dest->typ == 'U')
if (is_down_suspended(dest->call, dest->port))
{
conerr(CE_SUSPEND, dest);
return;
}
if (portenabled(dest->port))
{
#ifndef CONNECTMOD_SET_NODE
if ( (dest->typ != FLEXNET) /* bei FLEXNET Pfadweitergabe */
&& (dest->typ != LOCAL) /* bei Locals */
&& (dest->typ != LOCAL_M) /* bei Locals mit Messung */
&& (dest->typ != 'U') /* und auch bei User-Connect */
)
{
/* uns als Absender ins Via-Feld eintragen */
cpyid(usrvia, myid);
usrvia[L2IDLEN - 1] |= L2CH;
usrvia[L2IDLEN] = 0;
}
#else
/* usrvia leeren */
memset(usrvia, 0, sizeof(usrvia));
/* ist kein Einstiegsknoten definiert */
/* setzen wir unser Mycall. */
if (updigi[0] == FALSE)
{
cpyid(usrvia, myid);
usrvia[L2IDLEN - 1] |= L2CH;
usrvia[L2IDLEN] = 0;
}
else
{
cpyid(usrvia, updigi);
usrvia[L2IDLEN - 1] |= L2CH;
usrvia[L2IDLEN] = 0;
cpyid(usrvia + L2IDLEN, myid);
usrvia[L2IDLEN + L2IDLEN - 1] |= L2CH;
usrvia[L2IDLEN + L2IDLEN] = 0;
memset(updigi, 0, sizeof(updigi));
}
#endif /* CONNECTMOD_SET_NODE */
if ((strlen(dest->via) + strlen(usrvia)) > L2VLEN)
{
conerr(CE_INVLEN, dest);
return;
}
else
strcat(usrvia, dest->via);
/* wenn wir diesen Link schon aktiv haben, melden wir BUSY */
#ifdef __WIN32__
lnkpoi = getlnk((unsigned char)dest->port, usrcal, dest->call, usrvia);
#else
lnkpoi = getlnk(dest->port, usrcal, dest->call, usrvia);
#endif /* WIN32 */
if (lnkpoi)
{
if (lnkpoi->state == L2SDSCED)
{
/* Standard: Bitmaske fuer AX.25 */
#ifndef EAX25
lnkpoi->bitmask = 0x07;
#else
/* Behandlung bei EAX.25 */
/* Mode 2: standardmaessig EAX25 versuchen, antwortet die */
/* Gegenstelle nicht, dann erfolgt spaeter ein Fallback */
/* auf AX.25. */
if (portpar[dest->port].eax_behaviour == 2)
lnkpoi->bitmask = 0x7F;
else
/* EAX nach MHeard-Infos */
lnkpoi->bitmask = (dest->eax == TRUE) ? 0x7F : 0x07;
#endif
userpo->status = US_CREQ;
setptc(lnkpoi, L2_USER);
setupmsg(dest); /* "Downlink setup" ... */
newlnk(); /* Neuen Link aufbauen */
}
else
conerr(CE_BUSY, dest); /* Busy (Already connected) */
}
else
#ifndef CONl2FIX
conerr(CE_LTFULL, dest); /* Link table full */
#else
conerr(CE_INVCAL, dest); /* Link table full */
#endif /* CONl2FIX */
}
else
conerr(CE_PORTOFF, dest); /* Port ist abgeschaltet */
}
static void
con_cq(DEST *dest)
{
UID uid = userpo->uid;
PTCENT *ptcp;
PTCENT *p_ptcp;
CQBUF *cqp;
ptcp = ptctab + uid;
ptcp->p_uid = dest->uid;
p_ptcp = ptctab + ptcp->p_uid;
p_ptcp->p_uid = uid;
cqp = (CQBUF *)allocb(ALLOC_CQBUF);
cqp->uid = uid;
cqp->p_uid = dest->uid;
relink((LEHEAD *)cqp, (LEHEAD *)cq_statl.tail);
}
#ifdef OS_IPLINK
/* TCPIP Connect herstellen. */
void conIP(DEST *dest)
{
/* Ein Connect zum TCPIP-Nachbarn aufbauen. */
if (IPConvConnect(dest->call, usrcal, FALSE))
{
/* Connect misslungen. */
/* Server nicht online. */
conerr(CE_BUSY, dest);
return;
}
#ifdef CONl3LOCAL
/* Partner kommt via L4? */
if (g_utyp(userpo->uid) == L4_USER)
/* ja? mit CACK bestaetigen */
ackcir(g_ulink(userpo->uid));
#endif /* CONl3LOCAL */
/* Markiere den l2port vom TCPIP. */
dest->port = tcppoi->port;
/* Markiere Connectversuch. */
userpo->status = US_CREQ;
/* Connect-Partner in der Patchcord-Liste eintragen. */
setptc(tcppoi, TCP_USER);
/* Nachricht ueber den Linkaufbau ausgeben. */
setupmsg(dest);
/* Connect melden. */
tcppoi->state = L2MCONNT;
tcppoi->Intern = TRUE;
/* Ziel Rufzeichen fuer Connectmeldung setzen. */
cpyid(tcppoi->Upcall, dest->call);
/* Ziel Rufzeichen setzen. */
cpyid(tcppoi->Downcall, dest->call);
}
#endif /* OS_IPLINK */
static void
conusr(int type, DEST *dest)
{
switch (type)
{
case CP_CQ: /* CQ-User connecten */
con_cq(dest);
break;
case CP_HOSTCON: /* Connect an die Console */
conhst(); /* nicht an Kanal 0 connecten */
break;
case CP_L4CON: /* Layer4 (NET/ROM) Connect? */
conl4(dest); /* Level 4 Connect */
break;
case CP_L2CON: /* Level2 connect? */
conl2(dest);
break;
#ifdef OS_IPLINK
case CP_IPCONV: /* TCPIP connect? */
conIP(dest);
break;
#endif /* OS_IPLINK */
case CP_BADQUAL:
conerr(CE_BADQUAL, dest);
break;
case CP_INTERN:
break;
case CP_UNKNOWN:
conerr(CE_UNKNOWN, dest);
break;
case CP_NODIG:
conerr(CE_NODIG, dest);
break;
default: /* Fehler aufgetreten? */
conerr(CE_INVCAL, dest);
break;
}
}
/************************************************************************/
/* Einleiten einer Weiterverbindung bei Gateway-Connects. */
/* Hierzu wird aus dem L2-via-Feld gelesen, wohin der Link gehen */
/* soll. Bei L4-Links wird entsprechend das Zielcall gelesen. */
/*----------------------------------------------------------------------*/
void
gateway(void)
{
UID uid = userpo->uid;
PTCENT *ptcp = ptctab + uid;
char *viap;
char *p;
DEST user;
DEST dest;
/* TEST DG9OBU */
BOOLEAN invia = FALSE; /* Merker: war ich in den vias dabei ? */
#ifdef PROXYFUNC
user.via[0] = 0;
#endif
cpyid(usrcal, calofs(UPLINK, userpo->uid)); /* Mycall */
switch (g_utyp(userpo->uid))
{
case L2_USER:
lnkpoi = g_ulink(userpo->uid);
cpyid(user.call, lnkpoi->srcid); /* Ziel-Rufzeichen */
#ifdef CONNECTMOD_SET_NODE
SetMyNode(lnkpoi->viaidl); /* Einstiegsknoten setzen. */
#endif /* CONNECTMOD_SET_NODE */
/* Jetzt stellen wir das Addressfeld des eingehenden Links zusammen. */
/* In usrvia wird der bisherige Weg gespeichert, in user.via der */
/* restliche. */
/* Der Weg wird nur soweit kopiert, bis wir den ersten Digi kennen, der */
/* Rest ist dann unwichtig. */
/* Achtung, die Via-Liste ist hier umgedreht, hinten stehen die, */
/* die schon gedigipeated haben */
/* hinter letztes Via */
for (viap = lnkpoi->viaidl; *viap; viap += L2IDLEN);
/* usrvia leeren */
memset(usrvia, 0, sizeof(usrvia));
/* Via-Liste durchgehen, Arbeitszeiger auf usrvia-Liste */
for (p = usrvia; viap > lnkpoi->viaidl;)
{
viap -= L2IDLEN; /* zum ersten Via */
memcpy(p, viap, L2IDLEN); /* in die schon-gedigipeated-Liste damit */
/* Merken, ob ich in den VIAs mit dabei bin. */
if (cmpid(myid, viap))
invia = TRUE;
p[L2IDLEN - 1] ^= L2CH;
/* H-Bit gesetzt ? */
if (!(p[L2IDLEN - 1] & L2CH))
{
p[L2IDLEN - 1] |= L2CH;
p[L2IDLEN] = 0;
for (p = user.via; viap > lnkpoi->viaidl;)
{
viap -= L2IDLEN; /* den Rest regulaer kopieren */
cpyid(p, viap); /* die muessen alle noch */
p += L2IDLEN;
}
break;
}
p += L2IDLEN;
}
*p = 0;
/* TEST DG9OBU */
/* Waren wir *nicht* in den VIAs dabei, dann war der Link auch */
/* urspruenglich nicht an uns, sondern an einen unserer Locals */
/* und wurde stellvertretend fuer diesen angenommen. */
/* (FlexNet braucht das so wenn wir einen SSID-Bereich melden) */
/* Beim Downlink baut conl2() das VIA-Feld neu zusammen, wir */
/* muessen ihm noch anzeigen, dass es keine weiteren VIAs gibt */
/* die er noch nehmen muss. */
if ((invia == FALSE) && (islocal(user.call)))
user.via[0] = NUL;
break;
case L4_USER:
cirpoi = g_ulink(userpo->uid);
cpyid(user.call, cirpoi->destca); /* Ziel-Rufzeichen */
user.via[0] = 0;
/* hier werden wir spaeter mal aus cirpoi->upnod/upnodv den alten und */
/* mit einer L4-modif den weitern weg rausfinden. */
#ifndef CONNECTMOD_SET_NODE
cpyid(usrvia, myid); /* eigenes Call */
usrvia[L2IDLEN - 1] |= L2CH; /* wir haben gedigipeated */
usrvia[L2IDLEN] = 0; /* und fertig */
#else
cpyid(updigi, cirpoi->upnod); /* Einstiegsknoten setzen. */
updigi[L2IDLEN - 1] |= L2CH; /* Flag setzen. */
#endif /* CONNECTMOD_SET_NODE */
break;
default:
return;
}
user.port = NOPORT; /* Port ist uns egal */
#ifdef EAX25
user.eax = FALSE;
#endif
user.typ = 0;
ptcp->local = PTC_LOCAL;
/* Zur Sicherheit */
dest.call[0] = 0;
dest.via[0] = 0;
dest.eax = FALSE;
dest.port = NOPORT;
dest.typ = 0;
conusr(conprm2(&user, &dest), &dest);
ptcp->recflg = FALSE; /* nie Reconnect */
}
/**************************************************************************/
/* CONNECT */
/*------------------------------------------------------------------------*/
void
ccpcon(char *Direct)
{
DEST dest;
/* Zur Sicherheit */
dest.call[0] = 0;
dest.via[0] = 0;
dest.eax = FALSE;
dest.port = NOPORT;
cpyid(usrvia, myid);
usrvia[L2IDLEN - 1] |= L2CH;
usrvia[L2IDLEN] = 0;
conusr(conprm(&clicnt, &clipoi, &dest), &dest);
ptctab[userpo->uid].recflg = (Direct == NULL);
}
/**************************************************************************/
/* CQ */
/*------------------------------------------------------------------------*/
void
ccpcq(void)
{
MBHEAD *mbp;
WORD prt;
CQBUF *cqp;
PTCENT *ptcp;
UID uid = userpo->uid;
/* CQ-Buffer besorgen, User-ID und User-Pfad speichern und einhaengen */
cqp = (CQBUF *)allocb(ALLOC_CQBUF);
cqp->uid = uid;
cpyid(cqp->id, calofs(UPLINK, uid));
relink((LEHEAD *)cqp, (LEHEAD *)cq_user.tail);
userpo->status = US_CQ;
/* wir rufen CQ */
ptcp = ptctab + uid;
ptcp->p_uid = uid;
ptcp->recflg = TRUE;
skipsp(&clicnt, &clipoi);
/* Text kopieren */
mbp = getmbp();
mbp->l2fflg = L2CPID;
while (clicnt-- > 0)
putchr(*clipoi++, mbp);
putchr(CR, mbp);
/* Frame vorbereiten */
cpyid(usrvia, myid);
usrvia[L2IDLEN - 1] |= L2CH;
usrvia[L2IDLEN] = 0;
/* auf allen aktiven Ports mit aktivem MHeard als UI senden */
for (prt = 0; prt < L2PNUM; prt++)
{
if (!(updmheard(prt) && portenabled(prt)))
continue;
rwndmb(mbp);
#ifdef __WIN32__
sdui(usrvia, cqdest, usrcal, (char)prt, mbp);
#else
sdui(usrvia, cqdest, usrcal, prt, mbp);
#endif /* WIN32 */
}
/* Frame wegschmeissen */
dealmb(mbp);
/* Meldung an User */
mbp = putals("Waiting ...\r");
seteom(mbp);
}
/************************************************************************/
/* */
/* Fuer via-Connects feststellen, ob das gewuenschte Ziel bekannt ist. */
/* Diese Funktion wird vom L2 aufgerufen. Daher gibt es keinen aktuell */
/* zu bearbeitenden User! */
/* */
/************************************************************************/
BOOLEAN
conn_ok(const char *rxhdr)
{
DEST dest1;
DEST dest2;
userpo = NULL;
dest1.typ = 'U';
dest1.port = NOPORT;
cpyid(dest1.call, rxhdr);
cpyidl(dest1.via, rxhdr + 2 * L2IDLEN);
switch (conprm2(&dest1, &dest2))
{
case CP_L2CON:
case CP_L4CON:
case CP_HOSTCON:
#ifdef L1IPCONV
case CP_IPCONV:
#endif /* L1IPCONV */
case CP_CQ:
return(TRUE);
}
return(FALSE);
}
#ifdef CONNECTMOD_SET_NODE
/* Einstiegsknoten setzen. */
void SetMyNode(char *viaidl)
{
char *viap;
updigi[0] = 0;
if (*viaidl == NUL) /* Es gibt keine Digiliste. */
return; /* Keine Aenderung. */
for(viap = viaidl; *viap; viap += L2IDLEN); /* Durchsuche Digiliste. */
viap-=L2IDLEN; /* naechstes Rufzeichen .*/
cpyid(updigi, viap); /* Einstiegsknoten setzen. */
updigi[L2IDLEN - 1] |= L2CH; /* Flag setzen. */
return;
}
#endif /* CONNECTMOD_SET_NODE */
/* End of src/l7conn.c */