commit 6e56114b944c4dbabe7f28bd9a21d20eb192d250 Author: Marcus Hanisch DLM274 Date: Wed May 15 00:19:53 2019 +0200 initial commit diff --git a/LICENSE b/LICENSE new file mode 100755 index 0000000..2a303f4 --- /dev/null +++ b/LICENSE @@ -0,0 +1,86 @@ + + Allgemeine Lizenz für Amateurfunk Software (ALAS) + +Copyright (C) 1994 NORD> c " verbindet mit der ersten Konsole + +Jetzt ggf. noch im laufenden Betrieb Einstellungen vornehmen (IP, Baken, +Links, Convers etc.). + +Optional: + +A.) Mit dem Kommando "sp" an der TNN-Konsole die aktuelle Konfiguration + speichern wenn alle Einstellungen gemacht sind +B.) Die neue Datei "parms.tnb" sichten, ist alles korrekt, so kann diese in + "tnn179.tnb" umbenannt werden. Achtung: "parms.tnb" selber wird beim + Systemstart NICHT ausgewertet !!! + +In der Datei "startup.log" befinden sich die Reaktionen auf die Verarbeitung +der einzelnen Befehle der tnn179.tnb. Hier kann im Fehlerfall ueberprueft +werden, welche Befehle nicht akzeptiert wurden. + + +Update von TNN Version 1.78/1.79pre? : +-------------------------------------- + +1.) Archiv auspacken + +Optional: Optionen in "all.h" ueberpruefen und ggf. anpassen + +2.) "make" oder "make install" ausfuehren. Bei letzterem wird die Verzeichnis- + struktur mit angelegt und NUR das "tnn"-Executeable kopiert. +3.) "tnn"-Executable ins TNN-Verzeichnis kopieren +4.) Optional: externe Programm in die entsprechenden Verzeichnisse kopieren + +Alte Konfigurationsdateien (tnn178.tnb etc.) werden automatisch geupdated. +Auf Schreibberechtigungen des Users achten, der TNN dann startet, kann TNN die +neuen Dateien nicht erzeugen, so wird mit STANDARDEINSTELLUNGEN (!) gestartet. +Zur Sicherheit koennen die alten Dateien auch vor dem ersten Start von Hand +in die neuen Namen kopiert werden (tnn178.tnb -> tnn179.tnb etc.). Als weitere +Alternative bietet sich das "upd"-Utility an, welches nach dem Uebersetzen +ebenfalls im "bin"-Verzeichnis zu finden ist. + + +Update einer TNN-Version 1.77 oder aelter : +------------------------------------------- + +Hier ist leider Handarbeit angesagt. Es sollte das Neuinstallations-Verfahren +durchgefuehrt werden, danach von Hand die Einstellungen (vor allem die PAR- +Sektion) uebertragen und die Bedeutung der Parameter pruefen. Alternativ kann +auch versucht werden, die alten .tnb-Dateien in die neue, laufende TNN mit dem +"run"-Kommando einzulesen ("run tnn177.tnb"), und anschliessend mittels "sp" +eine parms.tnb-Datei zur weiteren Anpassung erzeugt werden. + + +Noch Probleme und Fragen ? Hier kann geholfen werden : +------------------------------------------------------ + +* Im DL-Convers auf Kanal 170. +* Auf www.nordlink.org im "Forum", Rubrik "TNN". diff --git a/README.md b/README.md new file mode 100644 index 0000000..9138047 --- /dev/null +++ b/README.md @@ -0,0 +1,10 @@ +# TheNetNode-CB +TheNetNode from Nordlink><, CB-Version (TNN 1.79cb53) + +Version Info: + +TheNetNode (Linux) (CB), Version 1.79cb53 (May 8 2019) + Copyright by NORD>" eingebaut. + und main von "void" nach "int" umgestellt. + +20.06.99 +- Durch einen Fehler in der Speicherroutine konnte es unter Linux in einer + bestimmten Situation zu einem 'Segmentation fault' kommen. + Wurde abgefangen. + \ No newline at end of file diff --git a/contrib/msgmsy/msg.inf b/contrib/msgmsy/msg.inf new file mode 100755 index 0000000..57452dd --- /dev/null +++ b/contrib/msgmsy/msg.inf @@ -0,0 +1,23 @@ +Hallo Sysop's, +das Paket sollte folgende Dateien beinhalten. + +- msg_lin.c das Programm. MUSS als msg.exe. TNN verlangt .exe!!!! +- msg.usr die Hilfedatei +- msg.mak das Makefile +- msg.his Histo + +Nach dem Kompilieren solltet Ihr eine msg.exe haben. + +Bitte msg.exe in's Verzeichnis "userexe" kopieren. +Die Hilfe-Datei msg.usr bitte ins Verzeichnis "msg". +Das Verzeichnis "msg" sollte unter tnn stehen. Aber das wisst Ihr sicher. + +Es wird kein Environmenteintrag benoetigt. + +Das Programm erkennt wo es ist. Zwingend ist nur vorgeschrieben, +das die Hilfedatei im Verzeichniss "msg" steht!!! +Da werden auch die call.msg geschrieben. + +Fehler bitte unbedingt melden!! + +Bis denne Bernd DG8BR diff --git a/contrib/msgmsy/msg.sys b/contrib/msgmsy/msg.sys new file mode 100755 index 0000000..6c83fb8 --- /dev/null +++ b/contrib/msgmsy/msg.sys @@ -0,0 +1,62 @@ + +Uebersicht zur MSY-Hilfe : 3.02 +------------------------- + +(MSY) C count lifetime -1 +(MSY) D dir +(MSY) E erase +(MSY) G group +(MSY) L list +(MSY) S send +(MSY) V version + + + +Detaillierte Hilfe zu MSY : +--------------------------- + + +(MSY) C + Lifetime aller MSG's wird um 1 verringert. Dieses kann per Hand + geschehen oder sinnvollerweise mit z. B. folgendem TNB-File. + + ######01.TNB + ============ + ; ;Diese File startet taeglich um 1:00 Uhr. + MSY C ;Lifetime der .MSG-File um einen Tag herrabsetzen + ; ;und bei Lifetime = 0 entfernen. + +(MSY) D Listet die Header aller MSG's auf. + +(MSY) D -#x o. +#x + MSG's, deren LT (-) kleiner o. (+) groesser x-Tage ist. + +(MSY) D -*x o. +*x + MSG's, die (-) juenger o. (+) aelter als x-Tage sind. + +(MSY) D FROM + zeigt MSG-Liste sortiert nach Absender-Calls an. + + Die Sortierung kann auch nach : + + BYTE, DATE, TIME, LT, RETURN vorgenommen werden. + +(MSY) E ALL + Loescht alle MSG's von oder an . + +(MSY) E 3 + Loescht die dritte Nachricht an . Varianten sind 1-4, 2- oder -3. + +(MSY) G +/- + Fuegt/loescht ein/aus . Zugelassen sind in einer Gruppe + maximal 50 Call's. + +(MSY) L + Zeigt alle MSG-Files. + +(MSY) S <#x> + Schreibt an mit Lifetime x. Hier ist eine Lifetime von + maximal 99 Tagen moeglich. + +(MSY) V + Ausgabe von der Versionsnummer und dem Datum. diff --git a/contrib/msgmsy/msg.usr b/contrib/msgmsy/msg.usr new file mode 100755 index 0000000..c40213c --- /dev/null +++ b/contrib/msgmsy/msg.usr @@ -0,0 +1,78 @@ +Uebersicht zur MSG-Hilfe : 3.04 +------------------------- +(MS)G S <#lifetime> sendet MSG +(MS)G R liest MSG +(MS)G L listet MSGs +(MS)G E loescht MSGs +(MS)G G listet Gruppen +(MS)G V zeigt Version + + + +Detaillierte Hilfe zu MSG : +--------------------------- + +(MS)G S # + Zum Erstellen einer Digimail (MSG) : + + Der Message-Befehl ermoeglicht es, einem Benutzer des Knotens eine kurze + (!) Nachricht in den CTEXT zu schreiben. Beim naechsten Connect wird + diese Zeile dann bei Ihm im CTEXT erscheinen. Statt des Zielcalls kann + auch eine Zielgruppe angegeben werden. Diese ist eine Art Verteiler- + liste. Jedes Mitglied der Zielgruppe bekommt eine Kopie der Nachricht. + + Die Lifetime kann, muss aber nicht, angegeben werden. Sie kann von #1 = + einem Tag bis #30 = dreissig Tage angegeben werden. Wird keine Lifetime + angegeben, so wird sie auf default = 7 Tage gesetzt. Das taegliche + Herabsetzen der Lifetime geschieht im Digi. Ist die Lifetime abgelaufen + und der Adressat ist nicht der Absender, bekommt der Absender seine MSG + mit einer Default-Lifetime von 7 Tagen zurueck. Nach dieser Zeit wird + die MSG endgueltig geloescht. + + Abhaengig davon, ob das System mit einer Festplatte oder einer RAMDISK + arbeitet, kann die Nachricht bei Absturz oder Reset verloren gehen. + + Beispiel: MSG S DL9GYA #10 Roland, bitte connecte mich, wenn Du zurueck + bist! + + MSG S SYSOP Link nach ..... defekt?! + + Letzteres wuerde die Nachricht an die OM's der Gruppe SYSOP weiter- + leiten. + Die Definition einer neuen Gruppe geschieht nur durch die Sysops. Bitte + danach fragen. + +(MS)G R + Liest die eigenen MSG's aus. + +(MS)G R + Liest die an gerichteten MSG's aus. + +(MS)G R 1 oder 1-3 + Zusaetzlich kann noch eine Numerierung mit angegeben werden. Also + lesen der MSG 1 oder MSG 1-3. + +(MS)G L + Listet die eigenen Header auf. + +(MS)G E + Dieser Befehl loescht alle eigenen Digimail-Nachrichten. + +(MS)G E 1-2 + Dieser Befehl loescht Nr. 1-2 der eigenen Digimail-Nachrichten. Es muss + mindestens eine Zahl angegeben werden. + +(MS)G E 1- + Dieser Befehl loescht alle eigenen Digimail-Nachrichten die an + geschickt wurden. + +(MS)G G + zeigt alle vorhandenen Verteiler-Gruppen mit Call's an. + +(MS)G G + zeigt nur die Call's in der an + + Neue Gruppen koennen nur vom Sysop angelegt werden! + +(MS)G V + Gibt Versionsnummer und -Datum aus. diff --git a/contrib/msgmsy/msg_lin.c b/contrib/msgmsy/msg_lin.c new file mode 100755 index 0000000..3e9afb9 --- /dev/null +++ b/contrib/msgmsy/msg_lin.c @@ -0,0 +1,950 @@ +/************************************************************************/ +/* */ +/* ***** ***** */ +/* ***** ***** */ +/* ***** ***** */ +/* ***** ***** */ +/* *************** *************** */ +/* ***************** ***************** */ +/* *************** *************** */ +/* ***** ***** TheNetNode */ +/* ***** ***** Portable */ +/* ***** ***** Network */ +/* ***** ***** Software */ +/* */ +/* File msg_lin.c (maintained by: DG8BR) */ +/* */ +/* */ +/* Copyright (C) 1998 - 2008 NORD> +#include +#include +#include +#include + +#ifdef __MSDOS__ + #include +#endif + +#ifdef __GO32__ + #include +#endif + +#ifdef __linux__ + #include + #include + #include + #include + #include +#endif + +#ifdef WIN32 +#ifdef _MSC_VER +/* Wird nur im VC benoetig. */ +#include +#endif /* MSC_VER */ +#include +#include "sys/dirent32.h" +#include "sys/fnmatch.h" +#endif /* WIN32 */ + +/* Definitionen */ +#define MaxZeilen 200 +#define MaxLT 30 +#define FALSE 0 +#define TRUE (!FALSE) +#define DefaultLT " 7" +#ifdef __MSDOS__ + #define Seperator '\\' + #define xfindfirst findfirst + #define xfindnext findnext +#endif + +#ifdef WIN32 + #define MAXPATH 255 + #define NAME_MAX 260 + #define findfirst _findfirst + #define findnext _findnext + #define Seperator '\\' +#endif /* WIN32 */ + +#ifdef __linux__ + #define Seperator '/' + #define MAXPATH 128 /* ist unter TC3.1 auf 80 festgelegt */ + #define stricmp strcasecmp +#endif + +/* Globale Variablen */ +int Status; /* True, wenn procedure erfolgreich */ +int Gruppe; /* True, wenn Call==Gruppe */ +char Usercall[10]; /* Aufrufender des MSG-pgms */ +char msgpath[MAXPATH]; +char ZeitZone[5]; +#ifndef WIN32 +struct ffblk ffblk; +#endif /* WIN32 */ + +/* Prototypen */ +void ListMsg (int,int,char**); +void GroupMsg ( int, char** ); +void SendMsg ( int, char** ); +void HelpMsg ( void ); +void VerMsg ( void ); + +int Suche_Datei ( char* ); +void Stop (char* ); +int Calltest ( char* ); +int speichern ( char*, char*, char* ); /* Unterfunktion von SendMsg */ + +/* Alles unter dem nachfolgenden ifdef __linux__ wurde aus dem TNN-Packet */ +/* fuer LinuX von der NORD>ff_name erhal- */ +/* ten bleiben, weil dieser beim Aufruf von "xfindnext" gesucht wird. */ +/* */ +/************************************************************************/ + +int xfindfirst(const char *pathname, struct ffblk *ffblk, int attrib) +{ + char *fnpoi; + DIR *dp; + struct dirent *dirp; + int retval; + + strcpy(ffblk->ff_path, pathname); /* Filename incl. Pfad */ +#ifdef WIN32 + fnpoi = strrchr(ffblk->ff_path, Seperator); /* Pfad angegeben? */ +#else + fnpoi = strrchr(ffblk->ff_path, '/'); /* Pfad angegeben? */ +#endif /* WIN32 */ + if (fnpoi == NULL) /* - nein .. */ + { + strcpy(ffblk->ff_find, ffblk->ff_path); /* Filename kopieren */ + strcpy(ffblk->ff_path, msgpath); /* default: msgpath */ + } + else /* mit Pfad */ + { + if (fnpoi == ffblk->ff_path+strlen(ffblk->ff_path)) /* ohne Name */ + return(-1); /* Unsinn */ + strcpy(ffblk->ff_find, ++fnpoi); /* nur Filename */ + *fnpoi = '\0'; /* Filename im Pfad loeschen */ + } + + if ((dp = opendir(ffblk->ff_path)) == NULL) /* Directory vorhanden? */ + return(-1); + retval = -1; /* default: nix gefunden */ + while ((dirp = readdir(dp)) != NULL) /* Eintrag vorhanden? */ + { + if ((fnmatch(ffblk->ff_find, dirp->d_name, + FNM_PATHNAME|FNM_PERIOD) != 0)) + continue; + strcpy(ffblk->ff_name, dirp->d_name); + setfiletime(ffblk); + retval = 0; + break; + } + closedir(dp); + return(retval); +} + +/****************************************************************************/ +/* */ +/* Erst den zuletzt gefundenen Eintrag suchen (steht in ffblk->ff_name) */ +/* und den darauffolgenden passenden Eintrag zurueckmelden. */ +/* */ +/****************************************************************************/ + +int xfindnext(struct ffblk *ffblk) +{ + DIR *dp; + struct dirent *dirp; + int retval; + + if ((dp = opendir(ffblk->ff_path)) == NULL) + return -1; + retval = -1; /* default: nix gefunden */ + while ((dirp = readdir(dp)) != NULL) + { + if ((fnmatch(ffblk->ff_name, dirp->d_name, + FNM_PATHNAME|FNM_PERIOD) != 0)) + continue; + retval = 1; + break; + } + if (retval == 1) + { + retval = -1; /* default: nix gefunden */ + while ((dirp = readdir(dp)) != NULL) + { + if ((fnmatch(ffblk->ff_find, dirp->d_name, + FNM_PATHNAME|FNM_PERIOD) != 0)) + continue; + strcpy(ffblk->ff_name, dirp->d_name); + setfiletime(ffblk); + retval = 0; + break; + } + } + closedir(dp); + return(retval); +} + +/****************************************************************************/ +/* */ +/* Bei xfindfirst und xfindnext Datum und Uhrzeit im Fileblock setzen */ +/* */ +/****************************************************************************/ + +void setfiletime(struct ffblk *ffblk) +{ + struct stat filestat; + struct tm *filetime; + char fn[MAXPATH]; + + sprintf(fn, "%s%s", ffblk->ff_path, ffblk->ff_name); + stat(fn, &filestat); + filetime = gmtime(&filestat.st_mtime); + ffblk->ff_ftime = ((filetime->tm_sec / 2) & 0x1f) + + ((filetime->tm_min & 0x3f) << 5) + + ((filetime->tm_hour & 0x1f) << 11); + ffblk->ff_fdate = (filetime->tm_mday & 0x1f) + + ((filetime->tm_mon & 0x0f) << 5) + + (((filetime->tm_year - 80) & 0x7f) << 9); +} + +/* Copyright (C) 1995 DJ Delorie, see COPYING.DJ for details */ + +char* strlwr(char *_s) +{ + char *rv = _s; + while (*_s) + { + *_s = tolower(*_s); + _s++; + } + return rv; +} +/* + String in Grossbuchstaben umwandeln - aus DJGPP GNU-Paket fuer DOS + von D.J. Delorie +*/ + +char *strupr(char *s) +{ + char *p = s; + while (*s) + { + if ((*s >= 'a') && (*s <= 'z')) + *s += 'A'-'a'; + s++; + } + return p; +} + +#endif /* Linux-Teil */ + +/*============================================================================ + VerMsg.c +============================================================================*/ +#define MsgVersion "3.04" +#define MsgDatum "14.05.1997 von DF7BZ & DG3AAH" +#define MsgLinux "(20.06.99) nach 'C' portiert von DG8BR" +#ifdef WIN32 +#define MsgWin32 "(17.01.04) Modifiziert fuer Win32 von DAA531 Oliver Kern." +#endif + +void VerMsg ( void ) +{ +#ifdef WIN32 + printf("\nMSG-Programm %s von %s \n%s\n%s\n",MsgVersion, MsgDatum,MsgLinux,MsgWin32); +#else + printf("\nMSG-Programm %s von %s \n%s\n",MsgVersion, MsgDatum,MsgLinux); +#endif + Status = TRUE; +} +/*============================================================================ + SendMsg.c +============================================================================*/ +/* Parameterreihenfolge ist: +Programmname Befehl Empfaenger (Lifetime) Nachricht Absender */ +/* 1 2 3 4 5 6 + 0 1 2 3 4 5 */ +void SendMsg ( int argc, char *argv[] ) +{ + int a; + char LT[3] = DefaultLT; /* LifeTime im Header einer MSG */ + char buffer[80]; /* Nachrichtentext */ + char dname[MAXPATH]; + char name[9]; /* Gruppen oder Empfeangername */ + FILE *fp; /* Empfaenger-Dateizeiger */ + + a = 2; /* Empfangscall */ + + sscanf (argv[a], "%s", &(*name)); /* Empfaenger feststellen */ + if ( Calltest(name) == FALSE) + Stop("Fehler im Empfaengerrufzeichen."); + + + a++; /* Lifetime oder Nachricht */ + + if(argv[a][0] == '#') /* Lifetime vorhanden? */ + { + strcpy (LT,&(argv[a][1])); /* Lifetime */ + if (( atoi(LT) < 1 ) || (atoi(LT) > MaxLT)) + { + printf("ACHTUNG ! Lifetime muss zwischen 1 und %d sein!\n\n",MaxLT); + strcpy(LT,DefaultLT); + } + a++; /* Nur wenn lifetime da war */ + } + + buffer[0] = ' '; /* Nachricht einruecken. Sieht doch besser aus */ + buffer[1] = '\0'; + + for(;a < argc-1; a++) /* die komplette Nachricht einlesen */ + { + sprintf (buffer+(char)strlen(buffer),"%s ", argv[a]); + } + if(buffer[1] == '\0') /* wenn nix dann mecker */ + Stop("Nachricht fehlt !"); + + buffer[strlen(buffer)-1] = '\n'; /* return einfuegen */ + a = 0; /* wird noch benoetigt */ +/*--------------------------------------------------------------------------*/ + if ( Gruppe == TRUE ) /* wird in Calltest geprueft */ + { + sprintf(dname,"%s%s.mbr",msgpath,name); + /* Gruppendatei oeffnen */ + if((fp = fopen(dname,"rt")) == NULL) + { + sprintf(dname,"Fehler #S1 Konnte die Datei %s nicht oeffnen.",name); + Stop(dname); + } + while(!feof(fp)) + { + *name = '\0'; + fscanf(fp,"%s",&(*name)); + if(name[0] != '\0') /* fscanf findet trotz feof was */ + { + strlwr(name); + speichern(LT,name,buffer); + a = TRUE; + } + } + fclose(fp); + } + else + a = speichern(LT,name,buffer); /* Speichern ohne Gruppe */ + + if (a == TRUE) + { + printf("\nInhalt der Nachricht :\n"); /* das bekommen alle */ + printf("----------------------\n"); + printf("%s",buffer); + } + + Status = TRUE; +} +/*--------------------------------------------------------------------------*/ +int speichern (char *LT,char *name,char *buffer) +{ + int a = 0; /* Nachrichtenzaehler */ + int b = 0; /* Umspeicherzaehler */ + int ist = 0; /* Flag fuer eingefuegte Nachricht. */ + char dname[MAXPATH]; + char MsgZeit[40]; + char Nachricht[MaxZeilen][80]; + char Zbuffer[80]; /* Zwischenbuffer beim umspeichern */ + char Datum[9]; + FILE *fp; + time_t t; + struct tm *ts; + char *Tage[] = { "Sun", "Mon", "Thu", "Wed", "Thu", "Fri", "Sat" }; + + time(&t); + ts = localtime(&t); + sprintf(Datum,"%02d.%02d.%02d",ts->tm_mday,ts->tm_mon +1,ts->tm_year%100); + sprintf(MsgZeit,"Time: %s, %s / %02d:%02dZ",Tage[ts->tm_wday], + Datum, + ts->tm_hour, + ts->tm_min); + + sprintf(dname,"%s%s.msg",msgpath,name); + strupr(name); /* nun wird name nur noch GROSS gebraucht */ + + if ((fp = fopen(dname,"rt")) == NULL) /* Datei vorhanden? */ + { + if((fp = fopen(dname,"wt")) == NULL) /* Nein, schreibend oeffnen */ + { + printf("Fehler beim Oeffnen von %s !\n",dname); + return(FALSE); + } + fprintf(fp,"\nMessage from %-6s - %s Lifetime %2s\n%s", + Usercall,MsgZeit,LT,buffer); + + fclose(fp); + } + else /* Datei ist da. Alles einlesen und aktuelle Nachricht einschieben */ + { + fgets(Nachricht[a], 79,fp); + while(!feof(fp)) + { + if(strstr(Nachricht[a],"Message from ")) /* Kopfzeile von MSG */ + { + if( strstr(Nachricht[a],Usercall)) /* hat er schon eine von call? */ + { /* und auch von heute ? */ + if(strstr(Nachricht[a],Datum) && !strstr(Nachricht[a],"RETURN")) + { /* LT aus Datei nehmen */ + if(Gruppe == FALSE) /* Bei Gruppe die LT ueberschreiben */ + strncpy(LT,strstr(Nachricht[a],"Lifetime ")+9,2); + else /* sonst LT uebernehmen */ + { + strncpy (strstr(Nachricht[a],"Lifetime ")+9,LT,2); + } + fgets(Nachricht[++a],79,fp); /* 1 String kommt auf jeden Fall */ + do + { + if(fgets(Zbuffer,79,fp)) /* kommt noch mehr */ + { + if(strstr(Zbuffer,"Message from ")) + break; /* Nee. War nur eine Zeile */ + strcpy(Nachricht[++a],Zbuffer); /* sonst kopieren */ + } + else /* sicherheitshalber leer machen */ + *Zbuffer = '\0'; + } + while(!feof(fp)); + + strcpy(Nachricht[++a],buffer); /* aktuelle Nachricht einfuegen */ + if(Zbuffer[0] != '\x0') /* die geholte Zeile auch einfuegen */ + strcpy(Nachricht[++a],Zbuffer); + ist = TRUE; /* habe eingefuegt */ + } + } + } + a++; + fgets(Nachricht[a], 79,fp); + } + fclose(fp); + + if ( a >= MaxZeilen ) + { + printf("%s hat zuviele Nachrichten ! Nichts gespeichert!\n",name); + return(FALSE); /* Speichertext wird nicht ausgegeben */ + } + + unlink(dname); + + if ((fp = fopen(dname,"wt")) == NULL) + Stop("Fehler #S2 Problem beim Zurueckschreiben der Datei!"); + while (b < a) + { + fprintf(fp,"%s",Nachricht[b++]); + } + if(ist == FALSE) /* habe nicht eingefuegt, also anhaengen */ + fprintf(fp,"Message from %-6s - %s Lifetime %2s\n%s", + Usercall,MsgZeit,LT,buffer); + + fclose(fp); + } + + printf("MSG wurde fuer %-6s mit einer Lifetime von %s Tag(en)" + " gespeichert.\n",name,LT); + return(TRUE); /* war alles richtig */ +} + +/*============================================================================ + ListMsg.c +============================================================================*/ +/* Parameterreihenfolge ist: Programmname Befehl von-bis Rufzeichen Usercall + Argument(argv) 0 1 2 3 4 + Argument(argc) 1 2 3 4 5 + +Argument 2 (von-bis) und 3 (Rufzeichen) sind optional. +Wenn 2 nicht angegeben, dann alles ausgeben. +Wenn 3 angegeben, beim Loeschen pruefen ob Usercall der Absender war ? +Ansonsten ist es egal was fuer ein Call angegeben wurde! +*/ + +void ListMsg (int Befehl,int argc,char *argv[]) +{ + int von = 1; /* Nur Nachricht von * ausgeben. 1 = default */ + int bis = 99; /* Nur Nachricht bis * ausgeben. 99 = default */ + int Nr = 0; /* Nummer der Nachricht. Von 1 bis MaxZeilen */ + int a; + int aus; /* es wurde was ausgegeben, also nicht speichern */ + int seine = 0; /* user's eigene MSG */ + int Ruecknr; /* wieviel Zeilen noch zurueckgeschreiben */ + char trenner = '\0'; /* wird nur fuer sscanf benoetigt */ + char AnzNr[3] = "00"; /* Das wird ausgegeben. */ + char dname[MAXPATH]; /* Pfad und Dateiname */ + char name[7]; /* Dateiname */ + char Nachricht[MaxZeilen][80]; + FILE *fp; + + *name = '\0'; /* erstmal den Namen weg */ +/*---------------------------------------------------------------------------- + von-bis und eventuell das call pruefen. +----------------------------------------------------------------------------*/ + if (argc == 4 || argc == 5) /* Nummer und/oder Call */ + { + for ( a = 2; a < argc-1; a++) + { + if((isdigit(argv[a][0])) != FALSE) + Nr = sscanf(argv[a],"%02d%c%02d",&von, &trenner, &bis); + if (Nr == 1) /* wenn nur eine Zahl eingegeben wurde. */ + bis = von; + if((argv[a][0] == '-') == TRUE) + Nr = sscanf (argv[a],"%c%02d",&trenner, &bis); + if (Nr == 0) /* Argument ein Call */ + sscanf(argv[a],"%s",&(*name)); + Nr = 0; /* name nach von-bis wird nicht gefunden, wenn Nr gesetzt */ + } + if( von > bis ) /* Ev. sollte man das einfach verbessern */ + Stop("Ende liegt vor Anfang!"); + } + if(*name == FALSE) /* wenn kein Call angegeben wurde */ + { + strcpy(name,Usercall); /* Sind seine MSG's */ + } + else + { + if (Calltest(name) == FALSE) /* Gucken ob der User richtig schreiben */ + Stop("Das angegebene Rufzeichen ist ungueltig !"); /* Sonst Mecker */ + } +/*--------------------------------------------------------------------------*/ + strlwr(name); + sprintf(dname,"%s%s.msg",msgpath,name); + strupr(name); + Nr = 0; + + if ((fp = fopen(dname,"rt")) == NULL) + { + printf("Keine MSG fuer %s gefunden.\n",name); + exit(0); + } + + printf("\n%s :\n",name); /* Empfaenger der Nachricht ausgeben */ + + while(!feof(fp)) /* erstmal alles lesen */ + { + if((fgets(Nachricht[Nr],79,fp)) != NULL) + { + if (Nachricht[Nr][0] == 0x0A) /* LF-Return, */ + continue; /* naechste Zeile einlesen. */ + + Nr++; + } + + if ( Nr > MaxZeilen ) /* Sollte nie vorkommen !! */ + { + fclose(fp); + sprintf(dname,"Fehler #L1 %s ist zu gross! ",ffblk.ff_name); + Stop(dname); + } + } + fclose(fp); + +/*---------------------------------------------------------------------------- +Die gewuenschten Nachrichten ausgeben und wenn geloescht werden soll, die +entsprechenden Zeilen markieren. +----------------------------------------------------------------------------*/ + aus = 0; + Ruecknr = Nr; + + for (a = 0; a < Nr; a++) + { + if(strstr(Nachricht[a],"Message from ")) /* Kopfzeile von MSG */ + { + if ( AnzNr[1] == '9' ) /* wenn 9 dann auf 0 setzen und das */ + { /* vorherige Byte auf 1 */ + AnzNr[0]++; + AnzNr[1] = '0'; + } + else + AnzNr[1]++; /* wenn nicht, dann nur erhoehen */ + + aus++; /* zaehlt die nachrichtennummern */ + + if(( aus >= von) && ( aus <= bis) == TRUE) + { + if (Befehl == 'e') /* feststellen ob es seine oder ob von ihm */ + { + if(!stricmp(name,Usercall) || strstr(Nachricht[a],Usercall)) + { + printf("MSG %s: %s",AnzNr,Nachricht[a]); + *Nachricht[a] = '\0'; /* Loeschen markieren */ + Ruecknr--; + seine = TRUE; /* fuer den Nachrichteninhalt */ + } + else + seine = FALSE; + } + if(Befehl == 'r' || Befehl == 'l') + printf("MSG %s: %s",AnzNr,Nachricht[a]); + } + } + else /* ist kein Nachrichtenkopf */ + { + if(( aus >= von) && ( aus <= bis) == TRUE) /* aber gueltige Nummer */ + { + if( Befehl == 'e' && seine == TRUE) + { + printf("%s",Nachricht[a]); + *Nachricht[a] = '\0'; + Ruecknr--; + } + if(Befehl == 'r') + printf("%s",Nachricht[a]); + } + } + } +/*---------------------------------------------------------------------------- + Und nun wird geloescht. +----------------------------------------------------------------------------*/ + + if(Befehl == 'e') + { + if(Ruecknr == 0) /* ist nix mehr zum zurueckschreiben */ + unlink(dname); + else + { + unlink(dname); + if ((fp = fopen(dname,"wt")) == NULL) + { + Stop("Fehler #L2 Fehler beim Zurueckschreiben der Datei!"); + } + for (a = 0; a < Nr; a++) + { + if(*Nachricht[a] != '\0') + fprintf(fp,"%s",Nachricht[a]); + } + fclose(fp); + } + if(Ruecknr < Nr) /* wenn ja, dann wurde was geloescht. */ + printf("\nDiese MSG('s) wurde(n) soeben geloescht!\n"); + else + printf("\nEs wurde nichts geloescht!\n"); + } + Status = TRUE; +} +/*============================================================================ + HelpMsg.c +============================================================================*/ +void HelpMsg ( void ) +{ + char filename[MAXPATH]; + FILE *fp; + + sprintf(filename,"%smsg.usr",msgpath); + if (( fp = fopen(filename,"rt")) == NULL) + { + Stop("Fehler #H1 Konnte Hilfedatei nicht oeffnen."); + } + while (!feof(fp)) + { + if((fgets(filename,79,fp)) != NULL) + printf("%s",filename); + } + fclose (fp); + Status = TRUE; +} +/*============================================================================ + GroupMsg.c +============================================================================*/ +/* Parameterreihenfolge ist: Programmname Befehl Gruppe Usercall + Argument(argv) 0 1 2 3 + Argument(argc) 1 2 3 4 + Wobei Gruppe optional ist. Wenn keine Gruppe angegeben wurde, dann alle + Gruppen auflisten. +*/ + +void GroupMsg ( int argc, char *argv[] ) +{ + int a; + int gefunden; + char dname[MAXPATH]; + FILE *fp; + + if(argc == 3) + sprintf(dname,"%s*.mbr",msgpath); + if(argc == 4) + sprintf(dname,"%s%s.mbr",msgpath,strlwr(argv[2])); + if(argc > 4) + Stop("Zuviele Parameter !"); + + gefunden = xfindfirst( dname, &ffblk, 0); + if (gefunden != FALSE) /* wenn nicht gefunden, dann meckern */ + Stop("Gruppe nicht gefunden..."); + + printf("\n"); + + while (!gefunden) + { + sprintf(dname,"%s%s",msgpath,ffblk.ff_name); + + if (( fp = fopen(dname,"rt")) == NULL) + Stop("Fehler #G1 Konnte Datei nicht oeffnen."); + + strcpy(dname,ffblk.ff_name); + dname[strlen(dname)-4] = '\0'; /* Standard IMMER .EXT */ + printf("%s :\n",strupr(dname)); + + for(a = strlen(dname)+2;a > 0;a--) /* Laenge des Gruppennamens */ + { + printf("-"); /* unterstreichen */ + } + printf("\n"); /* und dann ..... return !!! */ + + do /* Datei ausgeben */ + { + fgets(dname,79,fp); + printf("%s",dname); + *dname = '\0'; + } + while (!feof(fp)); + + printf("\n"); + + fclose (fp); + gefunden = xfindnext(&ffblk); + } + Status= TRUE; +} + +/*============================================================================ + MSG_LIN.C +============================================================================*/ + +/*--------------------------------------------------------------------------*/ +void Stop(char *S) +{ + if (strchr(S, '#')) /* Systemfehler */ + { + printf("\n%s\n", S); + printf("Bitte Beschreibung des Fehlers an Sysop schicken !\n"); + } + else + { + if (strchr(S, '!')) /* Bedienungsfehler */ + { + printf("\n%s\n", S); + printf("Bitte Hilfe anfordern mit 'MSG H'.\n"); + } + else + { + printf("\n%s\n", S); /* nur ne dumme Bemerkung */ + } + } + exit(0); +} +/*--------------------------------------------------------------------------*/ +int Calltest( char *Call ) +{ + int falschesZ, Zahl, i, a; + char dname[MAXPATH]; + Zahl = 0; + falschesZ = 0; /* falsches Zeichen */ + + + if(!Gruppe) + { + if (strchr(Call, '-') > (char *)NULL) + *(char *) (strchr(Call, '-')) = '\0'; + } + a = strlen(Call); + for (i = 0; i < a; i++) /* AeAe pruefen ob Zeichen in Call Ok AeAe */ + { + Call[i] = tolower(Call[i]); /* fuer die Ascii-Ausgabe */ + + /* Ae alle Zeichen die in der ASCII-Tabelle ueber Z, zwischen 9 und A + sowie unter 0 liegen, machen Call ungueltig ! Ae */ + + if (isdigit(Call[i])) + Zahl++; + if (Call[i] > 'z') + falschesZ++; + if (Call[i] < 'a' && Call[i] > '9') + falschesZ++; + if (Call[i] < '0') + falschesZ++; + } + + sprintf(dname,"%s%s.mbr",msgpath,Call); /* auch auf Gruppe testen, erspart*/ + if ((xfindfirst (dname, &ffblk,0)) == 0) /* einwenig Arbeit */ + Gruppe = TRUE; + + if (!Gruppe && (strlen(Call) < 4 || strlen(Call) > 6 || Zahl < 1 + || Zahl > 2 || falschesZ > 0)) + return(TRUE); + return(TRUE); +} +/*--------------------------------------------------------------------------*/ + +int main ( int argc, char *argv[] ) +{ + char hilfstring[MAXPATH]; + char Call[11]; + char Befehl = '\0'; /* Befehl ist argv[1] */ + char *fnpoi; + + Status = FALSE; /* ist immer FALSE, muss von der Funktion gesetzt werden */ + + *msgpath = '\0'; + + if (getcwd(msgpath,MAXPATH)== NULL) /* Wo sind wir denn? */ + { + printf("\nKonnte Pfad nicht ermmitteln!\n"); + exit(0); + } + + if(*(fnpoi = msgpath + strlen(msgpath)) != Seperator) /* / oder \\ dran ? */ + *fnpoi++ = Seperator; + strcat(fnpoi, "msg"); /* Hier sollten immer MSG`s unter TNN sein !!! */ + *(fnpoi+3) = Seperator; /* msgpath ist nun festgelegt */ + + sprintf ( hilfstring,"%smsg.usr",msgpath); /* Hilfedatei da ?? */ + + if (xfindfirst( hilfstring, &ffblk, 0) != FALSE) + Stop ( "\nFehler #M1 Fehler im MSGPATH ! Hilfe-Datei nicht gefunden !" ); + + + if (argc < 3) + Stop("\nEs wurde kein Befehl angegeben !"); + + if ( strlen(argv[1]) > 1 ) + Stop( "\nDer Befehl wird nur mit dem Anfangsbuchstaben angegeben !"); + else + Befehl = tolower( argv[1][0] ); + + strcpy(Call, argv[argc - 1]); /* Absender ermitteln */ + + if(Calltest(Call) == FALSE) /* und pruefen ob es ein call ist */ + Stop("\nFehler in Deinem Rufzeichen !?"); + else + strcpy ( Usercall, Call); + + strupr(Usercall); + + printf("\nDigimail fuer TheNetNode!\n"); + + switch (Befehl) + { + case 'e': + case 'l': + case 'r': ListMsg(Befehl,argc,argv); + break; + case 's': if ( argc < 4 ) + Stop("Zuwenig Parameter!\n"); + else + SendMsg(argc,argv); + break; + + case 'g': GroupMsg(argc,argv); + break; + + case 'h': HelpMsg(); + break; + + case 'v': VerMsg(); + break; + + default: sprintf(hilfstring, "Befehl %c ungueltig !", Befehl); + Stop(hilfstring); + break; + } + if (!Status) + { + sprintf(hilfstring, "#Fehler bei Ausfuehrung des '%c'-Befehls !",Befehl); + Stop(hilfstring); + } + return(0); +} diff --git a/contrib/msgmsy/msy.his b/contrib/msgmsy/msy.his new file mode 100755 index 0000000..8511a39 --- /dev/null +++ b/contrib/msgmsy/msy.his @@ -0,0 +1,41 @@ +Version gleich Datum +==================== + +16.01.99 +- 2 Testversionen an DB0CEL und DB0UHI verteilt. Aber ohne MSY D XXX. +- Kommt der Hinweis"Nicht implementiert." + +25.02.99 +- Fehler in GroupSys entfernt. Hat in der 1.ten Zeile nur 10 statt 11 Calls +- geschrieben. Ist beim Loeschen eines Calls aufgefallen. + +01.03.99 +- Fehler in GroupSys entfernt. Beim Call setzen oder loeschen wurde die +- Gruppe kleingeschrieben ausgegeben. + +04.03.99 +- in 2 Funktionen wurde auf das Fehlen von Dateien falsch reagiert. +- Nun nicht mehr Stop, sondern Meldung und exit + +18.03.99 +- Nun ist das entgueltige Version fertig. + +30.04.99 +- Bei der Linuxversion wurde bei der CHECK-Funktion nur eine! Datei im der + Lifetime verringert. + xfindnext erwartet das die Datei, die in ffblk steht, existiert. + Ich hatte sie gerade geloescht :-(( + Wurde gerichtet. +02.05.99 +- Bei der Linux-Version konnte man mehrmals am Tag die Checkfunktion aufrufen. + Sollte aber nur einmal am Tag ausfuehrbar sein. + Die Dateizeit und Systemzeit passten nicht. Es fehlte 1 Monat bei der Datei- + Zeit.. +- In setfiletime beim Monat eine 1 hinzuaddiert. + +20.06.99 +- Durch einen Fehler in der Speicherroutine konnte es unter Linux in einer + bestimmten Situation zu einem 'Segmentation fault' kommen. + Wurde abgefangen. +- Ein 'toupper' in 'tolower' geaendert. Sollte ein paar Byte sparen. + \ No newline at end of file diff --git a/contrib/msgmsy/msy.inf b/contrib/msgmsy/msy.inf new file mode 100755 index 0000000..2a806a0 --- /dev/null +++ b/contrib/msgmsy/msy.inf @@ -0,0 +1,26 @@ +Hallo Sysop's, +das Paket sollte folgende Dateien beinhalten. + +- msy_lin.c das Programm. MUSS als msy.exe TNN verlangt .exe!!! +- msg.sys die Hilfedatei +- msy.his Histo +- msy.mak Makefile + +Nach dem Kompilieren solltet Ihr eine msy.exe haben. + +Bitte msy.exe in's Verzeichnis "sysexe" kopieren. +Die Hilfe-Datei msg.sys bitte ins Verzeichnis "msg". +Das Verzeichnis "msg" sollte unter tnn stehen. Aber das wisst Ihr sicher. + +Es wird kein Environmenteintrag benoetigt. + +Das Programm erkennt wo es ist. Zwingend ist nur vorgeschrieben, +das die Hilfedatei im Verzeichniss "msg" steht!!! + +Da werden auch die call.msg geschrieben. + +Eventuell solltet Ihr Euch eine TNB schreiben. Ist in msg.sys beschrieben. + +Fehler bitte unbedingt melden!! + +Bis denne Bernd DG8BR diff --git a/contrib/msgmsy/msy_lin.c b/contrib/msgmsy/msy_lin.c new file mode 100755 index 0000000..e2c9d10 --- /dev/null +++ b/contrib/msgmsy/msy_lin.c @@ -0,0 +1,1725 @@ +/************************************************************************/ +/* */ +/* ***** ***** */ +/* ***** ***** */ +/* ***** ***** */ +/* ***** ***** */ +/* *************** *************** */ +/* ***************** ***************** */ +/* *************** *************** */ +/* ***** ***** TheNetNode */ +/* ***** ***** Portable */ +/* ***** ***** Network */ +/* ***** ***** Software */ +/* */ +/* File msy_lin.c (maintained by: DG8BR) */ +/* */ +/* */ +/* Copyright (C) 1998 - 2008 NORD> +#include +#include +#include +#include + +#ifdef __MSDOS__ + #include +#endif + +#ifdef __GO32__ + #include +#endif + +#ifdef __linux__ + #include + #include + #include + #include + #include +#endif + +#ifdef WIN32 +#ifdef _MSC_VER +/* Wird nur im VC benoetig. */ +#include +#endif /* WIN32 */ +#include +#include +#include "sys/dirent32.h" +#include "sys/fnmatch.h" +#endif /* WIN32 */ + +/* Definitionen */ +#define MaxZeilen 200 +#define MaxLT 99 +#define FALSE 0 +#define TRUE (!FALSE) +#define DefaultLT " 7" +#define MAXGROUP 50 +#ifdef __MSDOS__ + #define Seperator '\\' + #define xfindfirst findfirst + #define xfindnext findnext +#endif + +#ifdef WIN32 + #define MAXPATH 255 + #define NAME_MAX 260 + #define findfirst _findfirst + #define findnext _findnext + #define Seperator '\\' +#endif /* WIN32 */ + +#ifdef __linux__ + #define Seperator '/' + #define MAXPATH 128 /* ist unter TC3.1 auf 80 festgelegt */ + #define stricmp strcasecmp +#endif + +/* Globale Variablen */ +int Status; /* True, wenn procedure erfolgreich */ +int Gruppe; /* True, wenn Call=Gruppe */ +char Usercall[10]; /* Aufrufender des MSG-pgms */ +char msgpath[MAXPATH]; +char Nachricht[MaxZeilen][80]; /* wird von mehreren Funktionen genutzt */ +#ifndef WIN32 +struct ffblk ffblk; +#endif /* WIN32 */ +struct ZEILE{ /* fuer DirMsy */ + char From[7]; + char To[7]; + char Date[14]; + char Time[7]; + int LT; + char Return[7]; + int Byte; + }; + +/* Prototypen */ +void CheckMsy (void); +void DirMsy (int, char**); +void ListMsy (int, char**); +void SendMsy ( int, char** ); +void GetMsy (void); +void GroupMsy ( int, char** ); +void GroupList ( char* ); +void GroupSys ( char** ); +void HelpMsy (void); +void VerMsy (void); + +int Kopie (int, char, struct ZEILE *, char, char*, int, char); +int Calltest ( char* ); +int speichern ( char*, char*, char* ); /* Unterfunktion von SendMsg */ +void Stop (char* ); + +/* Alles unter dem nachfolgenden ifdef __linux__ wurde aus dem TNN-Packet */ +/* fuer LinuX von der NORD>ff_name erhal- */ +/* ten bleiben, weil dieser beim Aufruf von "xfindnext" gesucht wird. */ +/* */ +/************************************************************************/ + +int xfindfirst(const char *pathname, struct ffblk *ffblk, int attrib) +{ + char *fnpoi; + DIR *dp; + struct dirent *dirp; + int retval; + + strcpy(ffblk->ff_path, pathname); /* Filename incl. Pfad */ +#ifdef WIN32 + fnpoi = strrchr(ffblk->ff_path, Seperator); /* Pfad angegeben? */ +#else + fnpoi = strrchr(ffblk->ff_path, '/'); /* Pfad angegeben? */ +#endif /* WIN32 */ + if (fnpoi == NULL) /* - nein .. */ + { + strcpy(ffblk->ff_find, ffblk->ff_path); /* Filename kopieren */ + strcpy(ffblk->ff_path, msgpath); /* default: msgpath */ + } + else /* mit Pfad */ + { + if (fnpoi == ffblk->ff_path+strlen(ffblk->ff_path)) /* ohne Name */ + return(-1); /* Unsinn */ + strcpy(ffblk->ff_find, ++fnpoi); /* nur Filename */ + *fnpoi = '\0'; /* Filename im Pfad loeschen */ + } + + if ((dp = opendir(ffblk->ff_path)) == NULL) /* Directory vorhanden? */ + return(-1); + retval = -1; /* default: nix gefunden */ + while ((dirp = readdir(dp)) != NULL) /* Eintrag vorhanden? */ + { + if ((fnmatch(ffblk->ff_find, dirp->d_name, + FNM_PATHNAME|FNM_PERIOD) != 0)) + continue; + strcpy(ffblk->ff_name, dirp->d_name); + setfiletime(ffblk); + retval = 0; + break; + } + closedir(dp); + return(retval); +} + +/****************************************************************************/ +/* */ +/* Erst den zuletzt gefundenen Eintrag suchen (steht in ffblk->ff_name) */ +/* und den darauffolgenden passenden Eintrag zurueckmelden. */ +/* */ +/****************************************************************************/ + +int xfindnext(struct ffblk *ffblk) +{ + DIR *dp; + struct dirent *dirp; + int retval; + + if ((dp = opendir(ffblk->ff_path)) == NULL) + return -1; + retval = -1; /* default: nix gefunden */ + while ((dirp = readdir(dp)) != NULL) + { + if ((fnmatch(ffblk->ff_name, dirp->d_name, + FNM_PATHNAME|FNM_PERIOD) != 0)) + continue; + retval = 1; + break; + } + if (retval == 1) + { + retval = -1; /* default: nix gefunden */ + while ((dirp = readdir(dp)) != NULL) + { + if ((fnmatch(ffblk->ff_find, dirp->d_name, + FNM_PATHNAME|FNM_PERIOD) != 0)) + continue; + strcpy(ffblk->ff_name, dirp->d_name); + setfiletime(ffblk); + retval = 0; + break; + } + } + closedir(dp); + return(retval); +} + +/****************************************************************************/ +/* */ +/* Bei xfindfirst und xfindnext Datum und Uhrzeit im Fileblock setzen */ +/* */ +/****************************************************************************/ + +void setfiletime(struct ffblk *ffblk) +{ + struct stat filestat; + struct tm *filetime; + char fn[MAXPATH]; + + sprintf(fn, "%s%s", ffblk->ff_path, ffblk->ff_name); + stat(fn, &filestat); + filetime = gmtime(&filestat.st_mtime); + ffblk->ff_ftime = ((filetime->tm_sec / 2) & 0x1f) + + ((filetime->tm_min & 0x3f) << 5) + + ((filetime->tm_hour & 0x1f) << 11); + ffblk->ff_fdate = (filetime->tm_mday & 0x1f) + + (((filetime->tm_mon + 1) & 0x0f) << 5) + + (((filetime->tm_year - 80) & 0x7f) << 9); +} + +/* Copyright (C) 1995 DJ Delorie, see COPYING.DJ for details */ + +char* strlwr(char *_s) +{ + char *rv = _s; + while (*_s) + { + *_s = tolower(*_s); + _s++; + } + return rv; +} + +/* + String in Grossbuchstaben umwandeln - aus DJGPP GNU-Paket fuer DOS + von D.J. Delorie +*/ + +char *strupr(char *s) +{ + char *p = s; + while (*s) + { + if ((*s >= 'a') && (*s <= 'z')) + *s += 'A'-'a'; + s++; + } + return p; +} + +/* Copyright (C) 1995 DJ Delorie, see COPYING.DJ for details */ + +char *itoa(int value, char *string, int radix) +{ + char tmp[33]; + char *tp = tmp; + int i; + unsigned v; + int sign; + char *sp; + + if (radix > 36 || radix <= 1) + { + errno = EDOM; + return 0; + } + + sign = (radix == 10 && value < 0); + if (sign) + v = -value; + else + v = (unsigned)value; + while (v || tp == tmp) + { + i = v % radix; + v = v / radix; + if (i < 10) + *tp++ = i+'0'; + else + *tp++ = i + 'a' - 10; + } + + if (string == 0) + string = (char *)malloc((tp-tmp)+sign+1); + sp = string; + + if (sign) + *sp++ = '-'; + while (tp > tmp) + *sp++ = *--tp; + *sp = 0; + return string; +} + +#endif /* Linux-Teil */ + +/*---------------------------------------------------------------------------- + VerMsy.C +----------------------------------------------------------------------------*/ +#define MsyVersion "3.02" +#define MsyDatum "16.10.1996 von DF7BZ & DG3AAH" +#define MsyLinux "(20.06.99) nach 'C' portiert von DG8BR" +#ifdef WIN32 +#define MsyWin32 "(11.01.04) Modifiziert fuer Win32 von DAA531 Oliver Kern." +#endif + +void VerMsy ( void ) +{ + #ifdef WIN32 + printf("\nMSG-Programm %s von %s \n%s\n%s\n",MsyVersion, MsyDatum,MsyLinux,MsyWin32); +#else + printf("\nMSG-Programm %s von %s \n%s\n",MsyVersion, MsyDatum,MsyLinux); +#endif + Status = TRUE; +} + +/*---------------------------------------------------------------------------- + HelpMsy.C +----------------------------------------------------------------------------*/ +void HelpMsy ( void ) +{ + char filename[MAXPATH]; + FILE *fp; + sprintf(filename,"%smsg.sys",msgpath); + if (( fp = fopen(filename,"rt")) == NULL) + Stop("Fehler #H1 Konnte Hilfedatei nicht oeffnen."); + + while (!feof(fp)) + { + if((fgets(filename,79,fp)) != NULL) + printf("%s",filename); + } + fclose (fp); + Status = TRUE; +} + +/*---------------------------------------------------------------------------- + CheckMsy.C +Funktion prueft anhand des Datums ob es aeltere MSG's gibt. Wenn ja, dann +die Lifetime ermitteln und um einen reduzieren. Bei "0", Empfaenger und +Absender vertauschen und ein RETURN in den Header packen und auf DefaultLT +setzen. Wenn Lifetime "0" und RETURN oder Empfaenger und Absender gleich, +dann loeschen. +----------------------------------------------------------------------------*/ +void CheckMsy (void) +{ + int Anzahl = 0; /* Anzahl der eingelesenen Zeilen */ + int Nr; /* Zeilennummer die gerade bearbeitet wird */ + int LTz; /* Lifetimezaehler */ + int loeschen = 0; + int RueckNr = 0; /* Zaehler fuer zurueckzuschreibende Zeilen */ + int gefunden; + unsigned int Datum; + char LT[3]; + char Empfaenger[7]; + char Absender[7]; + char dname[MAXPATH]; + time_t t; + struct tm *ts; + FILE *fp, *aus; + + time(&t); + ts = localtime(&t); /* aktuelles Datum in Form ffblk.ff_fdate bringen */ + Datum = (ts->tm_mday & 0x1f) + + (((ts->tm_mon + 1) & 0x0f) << 5) + + (((ts->tm_year - 80) & 0x7f) << 9); + + sprintf(dname,"%s*.msg",msgpath); + if (( gefunden = xfindfirst(dname,&ffblk,0)) != FALSE) + { + printf("Keine MSG-Dateien gefunden.\n"); + exit(0); + } + + while(!gefunden) + { + if(Datum != ffblk.ff_fdate ) /* nur wenn Unterschied !! */ + { + sprintf(dname,"%s%s",msgpath,ffblk.ff_name); + fp = fopen(dname,"rt"); + Anzahl = 0; + do + { + if((fgets(Nachricht[Anzahl],80,fp)) != NULL) + Anzahl++; + if ( Anzahl > MaxZeilen ) /* Sollte nie vorkommen !! */ + { + fclose(fp); /* nachfolgendes wird nur auf der Konsole ausgegeben */ + printf("\nIn %s sind zuviele Nachrichten !" + " Bitte Sysop verstaendigen !\n",ffblk.ff_name); + } + } + while(!feof(fp)); + fclose(fp); /* Ursprungsdatei schliessen und nun auswerten */ + RueckNr = Anzahl; + /* Die Auswertung folgt hier */ + + for (Nr = 0;Nr < Anzahl;) + { + if(strstr(Nachricht[Nr],"Message from ")) + { + loeschen = 0; + strncpy (LT,strstr(Nachricht[Nr],"Lifetime ")+9,2); + LT[2] = '\0'; + LTz = atoi(LT); + LTz--; + if (LTz == 0) + { + if(strstr(Nachricht[Nr],"RETURN")) /* Return schon da ? */ + { + Nachricht[Nr][0] = '\0'; /* Loeschen */ + RueckNr--; + loeschen = 1; + } + else + { + strncpy (Absender,strstr(Nachricht[Nr],"from ")+5,6); + strncpy (Empfaenger,ffblk.ff_name,6); + if (Empfaenger[5] == '.') /* Punkt entfernen */ + Empfaenger[5] = ' '; + Absender[6] = Empfaenger[6] = '\0'; /* Stringende setzen */ + + if(!stricmp(Empfaenger,Absender)) /* beide gleich ? */ + { + Nachricht[Nr][0] = '\0'; /* dann gibt es kein Return */ + RueckNr--; + loeschen = 1; + } + else /* nun beide Calls tauschen */ + { + strncpy(strstr(Nachricht[Nr],"from ")+5,strupr(Empfaenger),6); + strcpy(strstr(Nachricht[Nr],"Lifetime ")+9,DefaultLT); + strcat(Nachricht[Nr]," RETURN\n"); + if(Absender[5] == ' ') + Absender[5] = '\0'; + sprintf(dname,"%s%s.msg",msgpath,strlwr(Absender)); + aus = fopen(dname,"at"); /* an das andere Call schicken */ + fprintf(aus,"%s",Nachricht[Nr]); + Nachricht[Nr][0] = '\0'; /* und loeschen */ + Nr++; /* einen weiter */ + RueckNr--; + while (Anzahl > Nr) + { + if(!strstr(Nachricht[Nr],"Message from ")) + { + fprintf(aus,"%s",Nachricht[Nr]); + Nachricht[Nr][0] = '\0'; + Nr++; + RueckNr--; + } + else + { + Nr--; + break; + } + } + fclose(aus); + } + } + } + else + { + itoa(LTz,LT,10); /* Wenn nur Lifetime ein weniger. Aendern und */ + if(strlen(LT) == 1 ) + { + LT[1] = LT[0]; + LT[0] = ' '; + } + strncpy(strstr(Nachricht[Nr],"Lifetime ")+9,LT,2); /*zurueck */ + Nr++; + } + } /* Ende Message */ + else + { + if (loeschen == 1) + { + Nachricht[Nr][0] = '\0'; + RueckNr--; + } + } + Nr++; + } /* Ende for */ + sprintf(dname,"%s%s",msgpath,ffblk.ff_name); + + unlink(dname); /* alte Datei loeschen */ + } /* Ende Datum */ + /* und nun die alte(neue) Datei wieder zurueckschreiben */ + + if (RueckNr > 0) + { + fp = fopen(dname,"at"); /* und wieder aufmachen */ + for (Nr = 0; Anzahl > Nr; Nr++) + { + if(Nachricht[Nr][0] != '\0') + { + fprintf(fp,"%s",Nachricht[Nr]); + } + } + fclose(fp); + Anzahl = 0; + RueckNr = 0; + Nr = 0; + } + gefunden = xfindnext(&ffblk); /* naechste Datei */ + } + printf("Checkmsg am %02d.%02d.%02d um %02d:%02d durchgefuehrt.\n", + ts->tm_mday,ts->tm_mon+1,ts->tm_year,ts->tm_hour,ts->tm_min); + Status = TRUE; +} +/*---------------------------------------------------------------------------- + DirMsy.C +----------------------------------------------------------------------------*/ +/* Diese Funktion listet alle vorhandenen Nachrichten in kompremierter Form +auf. Der Nachrichteninhalt wird nur als Laenge dargestellt. +Sondersache: mit # wird nach Lifetime gesucht und mit * nach Datum +*/ + +void DirMsy (int argc, char* argv[]) +{ + int gefunden; + int Anzahl = 0; + int a; + int b; + int c; + int SuchTage; + int Tag; + int Mon; + int Jahr; + char was; /* was wird gewuenscht? LT oder Tage */ + char Vorzeichen; /* '+' oder '-' */ + char Befehl; + char Hilf[60]; + char Suchdatum[10]; + char dname[MAXPATH]; /* kompletter Pfad mit Dateiname */ + char buffer[MaxZeilen][80]; + time_t t; + struct tm *ts; + struct ZEILE Zeile; + FILE *fp; + char Monat[12] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; + + if(argc > 4 ) + Stop("Zuviele Parameter!\n"); + + Befehl = ' '; /* als Vorbesetzung */ + + if(argc == 3) /* MSY D CALL == MSY D TO CALL */ + Befehl = 'T'; + + if (argc == 4) + { + strupr(argv[2]); + { + if(!strcmp(argv[2], "TO")) + { + Befehl = 'T'; + } + if(!strcmp(argv[2],"FROM")) + { + Befehl = 'F'; + } + if(!strcmp(argv[2],"BYTE")) + { + Befehl = 'B'; + } + if(!strcmp(argv[2],"DATE")) + { + Befehl = 'D'; + } + if(!strcmp(argv[2],"TIME")) + { + Befehl = 'H'; + } + if(!strcmp(argv[2],"LT")) + { + Befehl = 'L'; + } + if(!strcmp(argv[2],"RETURN")) + { + Befehl = 'R'; + } + if(*argv[2] == '-'|| *argv[2] == '+') + { + if(sscanf(argv[2],"%c%c%d",&Vorzeichen,&was,&SuchTage) != 3) + Stop("Parameter falsch!\n"); + if(SuchTage < 1 || SuchTage > MaxLT) + Stop("Tage falsch angegeben!\n"); + if(was == '*') + { + time(&t); + ts = localtime(&t); /* aktuelles Datum holen */ + if((Tag = ts->tm_mday - SuchTage) > 0) /* ist in diesem Monat */ + sprintf(Suchdatum,"%02d%02d%02d",ts->tm_year,ts->tm_mon+1,Tag); + else /* doch anderer Monat */ + { + Tag = ts->tm_mday - SuchTage; /* ist nicht in diesem Monat */ + Mon = ts->tm_mon + 1; /* 1 mehr. localtime liefert 1 weniger */ + Jahr = ts->tm_year + 1900; /* Muss wegen Schaltjahr sein */ + while (Tag < 1) + { + Mon--; + if (Mon < 1) /* Jahreswechsel ? */ + Mon = 12; + if (Mon == 2 && (Jahr%4) == (Jahr/4) && Jahr != 0) + Monat[Mon - 1] = 29; /* Schaltjahr */ + Tag += Monat[Mon - 1]; + } + if(Mon > ts->tm_mon) /* War Jahreswechsel ? */ + Jahr -= 1901; + else + Jahr -= 1900; + sprintf(Suchdatum,"%02d%02d%02d",Jahr,Mon,Tag); + } + } + Befehl = 'X'; /* Es wird nach der TO-Sortierung ausgegeben */ + } + } + } + if(Befehl == ' ') + Stop("Falscher Parameter!\n"); +/*----------------------Datei suchen-------------------------------*/ + sprintf(dname,"%s*.msg",msgpath); + + if (( gefunden = xfindfirst(dname,&ffblk,0)) != FALSE) + { + printf("Keine MSG-Dateien gefunden.\n"); + exit(0); + } +/*--------------------Datei einlesen-------------------------------*/ + while(!gefunden) + { + sprintf(dname,"%s%s",msgpath,ffblk.ff_name); + if((fp = fopen(dname,"rt")) == NULL) + { + sprintf(dname,"Fehler #D! beim Oeffnen der Datei %s\n",ffblk.ff_name); + Stop(dname); + } + a = 0; + + while(!feof(fp)) /* Datei wird komplett eingelesen */ + { + if((fgets(buffer[a],79,fp)) != NULL) + a++; + } + fclose(fp); +/*------------------Buffer auswerten--------------------------*/ + for(b = 0,c = 0;b < a; b++) + { + if(strstr(buffer[b],"Message from ")) /* erst den Header verarbeiten */ + { + if(c > 0) /* wenn c > 0, dann gab es schon einen Header */ + Anzahl = Kopie(Anzahl,Befehl,&Zeile,was,Suchdatum,SuchTage, + Vorzeichen); + strncpy(Zeile.To,ffblk.ff_name,6); /* To */ + if(Zeile.To[5] == '.') + Zeile.To[5] = ' '; /* Call ist immer 6stellig */ + Zeile.To[6] = '\0'; + c = sscanf(buffer[b],"%*s %*s %6c %*s %*s %13c %*s %s %*s %i %s", + Zeile.From,Zeile.Date,Zeile.Time,&Zeile.LT, + Zeile.Return); + Zeile.Date[13] = '\0'; /* muss stringabschluss sein */ + Zeile.From[6] = '\0'; + if(c == 4) /* kein Return */ + strcpy(Zeile.Return," \0"); /* fuer Sortierung nach Return */ + + Zeile.Byte = 0; /* auf 0 setzen, der vorherige hat gesetzt */ + } + else + Zeile.Byte += (strlen(buffer[b])-2); /* eingeruecktes Blank und */ + } /* (cr)lf entfernt */ + Anzahl = Kopie(Anzahl,Befehl,&Zeile,was,Suchdatum,SuchTage,Vorzeichen); + + gefunden = xfindnext(&ffblk); /* naechste Datei */ + } +/*----------------------Daten ausgeben--------------------------------*/ + if(Anzahl == 0) + { + printf("\nKeine passende MSG-Datei gefunden !\n"); + Status = TRUE; + return; + } + printf("\n"); + switch(Befehl) + { + case 'T' : + case 'X' : + { + printf(" TO FROM BYTE DATE TIME LT RETURN\n"); + printf("------ ------ ---- ------------- ------ -- ------\n"); + break; + } + case 'F' : + { + printf(" FROM TO BYTE DATE TIME LT RETURN\n"); + printf("------ ------ ---- ------------- ------ -- ------\n"); + break; + } + case 'B' : + { + printf("BYTE TO FROM DATE TIME LT RETURN\n"); + printf("---- ------ ------ ------------- ------ -- ------\n"); + break; + } + case 'D' : + { + printf(" DATE TO FROM BYTE TIME LT RETURN\n"); + printf("------------- ------ ------ ---- ------ -- ------\n"); + break; + } + case 'H' : + { + printf(" TIME TO FROM BYTE DATE LT RETURN\n"); + printf("------ ------ ------ ---- ------------- -- ------\n"); + break; + } + case 'L' : + { + printf("LT TO FROM BYTE DATE TIME RETURN\n"); + printf("-- ------ ------ ---- ------------- ------ ------\n"); + break; + } + case 'R' : + { + printf("RETURN TO FROM BYTE DATE TIME LT\n"); + printf("------ ------ ------ ---- ------------- ------ --\n"); + break; + } + } + for (a = 0; a < Anzahl; a++) + { + for (b = Anzahl - 1; b >= a; b--) + { + if (strcmp(Nachricht[a], Nachricht[b]) > 0) /* sortieren */ + { + strcpy(Hilf, Nachricht[a]); + strcpy(Nachricht[a], Nachricht[b]); + strcpy(Nachricht[b], Hilf); + } + } + } + + for(a = 0; a < Anzahl; a++) /* ausgeben */ + { + printf("%s\n",Nachricht[a]); + } + Status = TRUE; +} +int Kopie (int Anzahl, char Befehl, struct ZEILE *Zeile, char was, + char *Suchdatum,int SuchTage,char Vorzeichen ) +{ + int a; + int erdarf = 0; + int Tag; + int Mon; + int Jahr; + char laenge[5]; + char hilf[3]; + char Hilf[10]; + char Abstand[] = " \0"; + + if(Befehl == 'X') + { + if(was == '*') + { + sscanf(Zeile->Date,"%*s%d.%d.%d",&Tag,&Mon,&Jahr); /* Datum von MSG */ + sprintf(Hilf,"%02d%02d%02d",Jahr,Mon,Tag); + a = strcmp(Suchdatum,Hilf); /* aelter == +, juenger == - */ + } + else /* dann ist es `#` */ + { + if(Zeile->LT < SuchTage) /* kleiner == -, groesser == + */ + a = 1; + else + a = -1; + } + erdarf = 0; + if(Vorzeichen == '-' && a > 0) + erdarf = 1; + if(Vorzeichen == '+' && a < 0) + erdarf = 1; + if(erdarf == 0) + return(Anzahl); + } + itoa(Zeile->Byte,hilf,10); /* aus Zahl eine string machen */ + sprintf(laenge,"%4s",hilf); + itoa(Zeile->LT,hilf,10); /* bei einstelliger LT, muss 2stellig werden */ + sprintf(Hilf,"%2s",hilf); + switch(Befehl) /* String nach gewuenschter Reihenfolge zusammenstellen */ + { + case 'T' : + case 'X' : + { + strcpy(Nachricht[Anzahl],strupr(Zeile->To)); + *Zeile->To ='\0'; + break; + } + case 'F' : + { + strcpy(Nachricht[Anzahl],Zeile->From); + *Zeile->From ='\0'; + break; + } + case 'B' : + { + strcpy(Nachricht[Anzahl],laenge); + *laenge ='\0'; + break; + } + case 'D' : + { + strcpy(Nachricht[Anzahl],Zeile->Date); + *Zeile->Date ='\0'; + break; + } + case 'H' : + { + strcpy(Nachricht[Anzahl],Zeile->Time); + *Zeile->Time ='\0'; + break; + } + case 'L' : + { + strcpy(Nachricht[Anzahl],Hilf); + *Hilf ='\0'; + break; + } + case 'R' : + { + strcpy(Nachricht[Anzahl],Zeile->Return); + *Zeile->Return ='\0'; + break; + } + } + strcat(Nachricht[Anzahl],Abstand); /* Der Abstand nach der Sortierung */ + + if(*Zeile->To) /* und nun den Rest. nix kann nicht kopiert werden */ + { + strcat(Nachricht[Anzahl],strupr(Zeile->To)); + strcat(Nachricht[Anzahl],Abstand); + } + if(*Zeile->From) + { + strcat(Nachricht[Anzahl],Zeile->From); + strcat(Nachricht[Anzahl],Abstand); + } + if(*laenge) + { + strcat(Nachricht[Anzahl],laenge); + strcat(Nachricht[Anzahl],Abstand); + } + if(*Zeile->Date) + { + strcat(Nachricht[Anzahl],Zeile->Date); + strcat(Nachricht[Anzahl],Abstand); + } + if(*Zeile->Time) + { + strcat(Nachricht[Anzahl],Zeile->Time); + strcat(Nachricht[Anzahl],Abstand); + } + if(*Hilf) + { + strcat(Nachricht[Anzahl],Hilf); + strcat(Nachricht[Anzahl],Abstand); + } + if(*Zeile->Return) + strcat(Nachricht[Anzahl],Zeile->Return); + Anzahl++; + return(Anzahl); +} +/*---------------------------------------------------------------------------- + ListMsy.C +----------------------------------------------------------------------------*/ +/* ListMsy ist eigentlich falsch!! Es wird zwar was gelistet, aber auch +meistens geloescht. Ich habe aber den Funktionsnamen aus dem Pascalsource +uebernommen. +Diese Teil prueft die Msg-Nummern bzw das Call, listet sie auf und loescht +das Ganze. Der Rest wird wieder gespeichert. + +Parameterreihenfolge ist: Programmname Befehl Argument Argument Sysopcall + Argument(argv) 0 1 2 3 4 + Argument(argc) 1 2 3 4 5 + NSY E DG8BR DG8BR +Diese Variante ist nicht drin. MSY E 01.01.98/15:02 DG8BR + MSY E DG8BR 3 DG8BR + MSY E ALL DG8BR DG8BR + +Als Sysop darf er alles loeschen. Darum wird argc 5 nicht ueberprueft. +*/ + +void ListMsy (int argc,char *argv[]) +{ + int von = 1; /* Nur Nachricht von * ausgeben. 1 = default */ + int bis = 99; /* Nur Nachricht bis * ausgeben. 99 = default */ + int Nr = 0; /* Nummer der Nachricht. Von 1 bis MaxZeilen */ + int a; + int aus; /* es wurde was ausgegeben, also nicht speichern */ + int Ruecknr = 0; /* wieviel Zeilen noch zurueckgeschreiben */ + int alle = 0; /* Flag fuer alle MSG's von/an Call loeschen */ + int gefunden; /* Datei gefunden */ + int loeschen = 0; /* loeschenflag */ + char trenner = '\0'; /* wird nur fuer sscanf benoetigt */ + char AnzNr[3] = "00"; /* Das wird ausgegeben. */ + char dname[MAXPATH]; /* Pfad und Dateiname */ + char name[7]; /* gesuchter Dateiname */ + char ptr[7]; /* Absendercall in MSG */ + char Ucall[10]; /* gekuerzter Dateiname */ + FILE *fp; + + *name = '\0'; /* erstmal den Namen weg */ +/*---------------------------------------------------------------------------- + von-bis und eventuell das call pruefen. +----------------------------------------------------------------------------*/ + if (argc == 4 || argc == 5) /* Nummer und/oder Call */ + { + for ( a = 2; a < argc-1; a++) /* eigenes Call wird mit uebergeben */ + { + if((isdigit(argv[a][0])) != FALSE) + Nr = sscanf(argv[a],"%02d%c%02d",&von, &trenner, &bis); + if (Nr == 1) /* wenn nur eine Zahl eingegeben wurde. */ + bis = von; + if((argv[a][0] == '-') == TRUE) /* nur -X angegeben */ + Nr = sscanf (argv[a],"%c%02d",&trenner, &bis); + if (Nr == 0) /* Argument ein Call */ + { + sscanf(argv[a],"%s",&(*name)); + if (stricmp(name,"ALL") == FALSE) /* all angegeben ? */ + { + alle = TRUE; + *name = '\0'; /* name fuer die callpruefung frei machen */ + } + } + Nr = 0; /* name nach von-bis wird nicht gefunden, wenn Nr gesetzt */ + } + if( von > bis ) /* Ev. sollte man das einfach verbessern */ + Stop("Ende liegt vor Anfang."); + } + if(*name == FALSE) /* wenn kein Call angegeben wurde */ + { + Stop("Kein Rufzeichen angegeben!"); /* Es MUSS immer ein Call da sein */ + } + else + { + if (Calltest(name) == FALSE) /* Gucken ob der User richtig schreiben */ + Stop("Das angegebene Rufzeichen ist ungueltig."); /* Sonst Mecker */ + } + trenner = FALSE; /* wird nun fuer Call schon ausgegeben benutzt. */ +/*--------------------------------------------------------------------------*/ + + if( alle == TRUE) /* wenn all, dann alle Dateien durchsuchen */ + { + sprintf(dname,"%s*.msg",msgpath); + loeschen = 1; /* loeschen sperren */ + } + else /* Einzelcall angegeben */ + sprintf(dname,"%s%s.msg",msgpath,name); + + if (( gefunden = xfindfirst(dname,&ffblk,0)) != FALSE) + Stop("Keine MSG-Dateien gefunden !"); + + while(!gefunden) /* Solange es noch Msg-Dateien gibt */ + { + sprintf(dname,"%s%s",msgpath,ffblk.ff_name); + if ((fp = fopen(dname,"rt")) == NULL) + { + printf("Keine MSG fuer %s gefunden.\n",name); + exit(0); + } + strcpy(Ucall,ffblk.ff_name); /* Usernamen selektieren */ + Ucall[strlen(Ucall)-4] = '\0'; /* .MSG weg */ + strupr(Ucall); + Nr = 0; + AnzNr[0] = AnzNr[1] = '0'; + + while(!feof(fp)) /* erstmal alles lesen */ + { + if((fgets(Nachricht[Nr],79,fp)) != NULL) + Nr++; + if ( Nr > MaxZeilen ) /* Sollte nie vorkommen !! */ + { + fclose(fp); + sprintf(dname,"%s ist zu gross! ",ffblk.ff_name); + Stop(dname); + } + } + fclose(fp); + /* das nachfolgende xfindnext MUSS hier stehen, weil xfindnext mit */ + /* geloeschte Dateien nicht funktioniert */ + gefunden = xfindnext(&ffblk); /* naechste Datei */ + + +/*---------------------------------------------------------------------------- +Die gewuenschten Nachrichten ausgeben und wenn geloescht werden soll, die +entsprechenden Zeilen markieren. +----------------------------------------------------------------------------*/ + aus = 0; + Ruecknr = Nr; + + for (a = 0; a < Nr; a++) + { + if(strstr(Nachricht[a],"Message from ")) /* Kopfzeile von MSG */ + { + loeschen = 1; /* loeschen sperren */ + if ( AnzNr[1] == '9' ) /* wenn 9 dann auf 0 setzen und das */ + { /* vorherige Byte auf 1 */ + AnzNr[0]++; + AnzNr[1] = '0'; + } + else + AnzNr[1]++; /* wenn nicht, dann nur erhoehen */ + + aus++; /* zaehlt die nachrichtennummern */ + if (alle == 1) + { + if(stricmp(Ucall,name) == 0) /* Dateiname gleich Suchcall?? */ + loeschen = 0; + else + { + sscanf(Nachricht[a],"%*s %*s %s",ptr); /* MSG von Suchcall?? */ + if(!stricmp(ptr,name)) + loeschen = 0; + } + } + else + loeschen = 0; /* kein all, loeschen freigeben */ + if(( aus >= von) && ( aus <= bis) && (loeschen == 0) == TRUE) + { + if(trenner == FALSE) + { + printf("\n%s :\n",Ucall); /* Empfaenger der Nachricht ausgeben */ + + for (Nr = strlen(Ucall)+2; Nr > 0; Nr--) + printf("-"); + printf("\n"); + trenner = TRUE; + Nr = Ruecknr; /* Nr wieder zuruechschreiben. Wurde missbraucht. */ + } + printf("MSG %s: %s",AnzNr,Nachricht[a]); + *Nachricht[a] = '\0'; /* Loeschen markieren */ + Ruecknr--; + } + } + else /* ist kein Nachrichtenkopf */ + { + if(( aus >= von) && ( aus <= bis) && (loeschen == 0)== TRUE) + { /* aber gueltige Nummer */ + printf("%s",Nachricht[a]); + *Nachricht[a] = '\0'; + Ruecknr--; + } + } + } +/*---------------------------------------------------------------------------- + Und nun wird geloescht. +----------------------------------------------------------------------------*/ + + if(Ruecknr < Nr) /* Wenn es denn was zuloeschen gibt.. */ + { + if(Ruecknr == 0) /* ist nix mehr zum zurueckschreiben */ + unlink(dname); + else + { + unlink(dname); + if ((fp = fopen(dname,"wt")) == NULL) + { + Stop("Fehler #L1 Fehler beim Zurueckschreiben der Datei!"); + } + for (a = 0; a < Nr; a++) + { + if(*Nachricht[a] != '\0') + fprintf(fp,"%s",Nachricht[a]); + } + fclose(fp); + } + } + trenner = FALSE; + } + if(Ruecknr < Nr) /* wenn ja, dann wurde was geloescht. */ + printf("\nDiese MSG('s) wurde(n) soeben geloescht!\n"); + else + printf("\nEs wurde nichts geloescht!\n"); + + Status = TRUE; +} +/*============================================================================ + SendMsy.c +============================================================================*/ +/* Parameterreihenfolge ist: +Programmname Befehl Empfaenger (Lifetime) Nachricht Absender */ + +void SendMsy ( int argc, char *argv[] ) +{ + int a; + char LT[3] = DefaultLT; /* LifeTime im Header einer MSG */ + char buffer[80]; /* Nachrichtentext */ + char dname[MAXPATH]; + char name[9]; /* Gruppen oder Empfeangername */ + FILE *fp; /* Empfaenger-Dateizeiger */ + + a = 2; /* Empfangscall */ + + sscanf (argv[a], "%s", &(*name)); /* Empfaenger feststellen */ + if ( Calltest(name) == FALSE) + Stop("Fehler im Empfaengerrufzeichen."); + + a++; /* Lifetime oder Nachricht */ + + if(argv[a][0] == '#') /* Lifetime vorhanden? */ + { + strcpy (LT,&(argv[a][1])); /* Lifetime */ + if (( atoi(LT) < 1 ) || (atoi(LT) > MaxLT)) + { + printf("ACHTUNG ! Lifetime muss zwischen 1 und %d sein!\n\n",MaxLT); + strcpy(LT,DefaultLT); + } + a++; /* Nur wenn lifetime da war */ + } + + buffer[0] = ' '; /* Nachricht einruecken. Sieht doch besser aus */ + buffer[1] = '\0'; + + for(;a < argc-1; a++) /* die komplette Nachricht einlesen */ + { + sprintf (buffer+(char)strlen(buffer),"%s ", argv[a]); + } + if(buffer[1] == '\0') /* wenn nix dann mecker */ + Stop("Nachricht fehlt !"); + + buffer[strlen(buffer)-1] = '\n'; /* return einfuegen */ + a = 0; /* wird noch benoetigt */ +/*--------------------------------------------------------------------------*/ + if ( Gruppe == TRUE ) /* wird in Calltest geprueft */ + { + sprintf(dname,"%s%s.mbr",msgpath,name); /* Gruppendatei oeffnen */ + if((fp = fopen(dname,"rt")) == NULL) + { + sprintf(dname,"Fehler #S1 Konnte die Datei %s nicht oeffnen.",name); + Stop(dname); + } + while(!feof(fp)) + { + *name = '\0'; + fscanf(fp,"%7s",name); /* Call aus der MBR holen */ + if(name[0] != '\0') /* fscanf findet trotz feof was */ + { + strlwr(name); + speichern(LT,name,buffer); + a = TRUE; + } + } + fclose(fp); + } + else + a = speichern(LT,name,buffer); /* Speichern ohne Gruppe */ + + if (a == TRUE) + { + printf("\nInhalt der Nachricht :\n"); /* das bekommen alle */ + printf("----------------------\n"); + printf("%s",buffer); + } + + Status = TRUE; +} +/*--------------------------------------------------------------------------*/ +int speichern (char *LT,char *name,char *buffer) +{ + int a = 0; /* Nachrichtenzaehler */ + int b = 0; /* Umspeicherzaehler */ + int ist = 0; /* Flag fuer eingefuegte Nachricht. */ + char dname[MAXPATH]; + char MsgZeit[40]; + char Zbuffer[80]; /* Zwischenbuffer beim umspeichern */ + char Datum[9]; + FILE *fp; + time_t t; + struct tm *ts; + char *Tage[] = { "Sun", "Mon", "Thu", "Wed", "Thu", "Fri", "Sat" }; + + time(&t); + ts = localtime(&t); + sprintf(Datum,"%02d.%02d.%02d",ts->tm_mday,ts->tm_mon +1,ts->tm_year%100); + sprintf(MsgZeit,"Time: %s, %s / %02d:%02dZ",Tage[ts->tm_wday], + Datum, + ts->tm_hour, + ts->tm_min); + + sprintf(dname,"%s%s.msg",msgpath,name); + strupr(name); /* nun wird name nur noch GROSS gebraucht */ + + if ((fp = fopen(dname,"rt")) == NULL) /* Datei vorhanden? */ + { + if((fp = fopen(dname,"wt")) == NULL) /* Nein, schreibend oeffnen */ + { + printf("Fehler beim Oeffnen von %s !\n",dname); + return(FALSE); + } + fprintf(fp,"Message from %-6s - %s Lifetime %2s\n%s", + Usercall,MsgZeit,LT,buffer); + + fclose(fp); + } + else /* Datei ist da. Alles einlesen und aktuelle Nachricht einschieben */ + { + fgets(Nachricht[a], 79,fp); + while(!feof(fp)) + { + if(strstr(Nachricht[a],"Message from ")) /* Kopfzeile von MSG */ + { + if( strstr(Nachricht[a],Usercall)) /* hat er schon eine von call? */ + { /* und auch von heute ? */ + if(strstr(Nachricht[a],Datum) && !strstr(Nachricht[a],"RETURN")) + { /* LT aus Datei nehmen */ + if(Gruppe == FALSE) /* Bei Gruppe die LT ueberschreiben */ + strncpy(LT,strstr(Nachricht[a],"Lifetime ")+9,2); + else /* sonst LT uebernehmen */ + { + strncpy (strstr(Nachricht[a],"Lifetime ")+9,LT,2); + } + fgets(Nachricht[++a],79,fp); /* 1 String kommt auf jeden Fall */ + do + { + if(fgets(Zbuffer,79,fp)) /* kommt noch mehr */ + { + if(strstr(Zbuffer,"Message from ")) + break; /* Nee. War nur eine Zeile */ + strcpy(Nachricht[++a],Zbuffer); /* sonst kopieren */ + } + else /* sicherheitshalber leer machen */ + *Zbuffer = '\0'; + } + while(!feof(fp)); + + strcpy(Nachricht[++a],buffer); /* aktuelle Nachricht einfuegen */ + if(Zbuffer[0] != '\x0') /* die geholte Zeile auch einfuegen */ + strcpy(Nachricht[++a],Zbuffer); + ist = TRUE; /* habe eingefuegt */ + } + } + } + a++; + fgets(Nachricht[a], 79,fp); + } + fclose(fp); + + if ( a >= MaxZeilen ) + { + printf("%s hat zuviele Nachrichten ! Nichts gespeichert!\n",name); + return(FALSE); /* Speichertext wird nicht ausgegeben */ + } + + unlink(dname); + + if ((fp = fopen(dname,"wt")) == NULL) + Stop("Fehler #S2 Problem beim Zurueckschreiben der Datei!"); + while (b < a) + { + fprintf(fp,"%s",Nachricht[b++]); + } + if(ist == FALSE) /* habe nicht eingefuegt, also anhaengen */ + fprintf(fp,"Message from %-6s - %s Lifetime %2s\n%s", + Usercall,MsgZeit,LT,buffer); + + fclose(fp); + } + + printf("MSG wurde fuer %-6s mit einer Lifetime von %s Tag(en)" + " gespeichert.\n",name,LT); + return(TRUE); /* war alles richtig */ +} + + +/*---------------------------------------------------------------------------- + GetMsy.C + +Dieser Teil listet einfach alle Msg-Dateien auf. Header und Inhalt. +----------------------------------------------------------------------------*/ +void GetMsy (void) +{ + int a; + int gefunden; + char dname[MAXPATH]; + char Datei[10]; + char buffer[80]; + FILE *fp; + + sprintf(dname,"%s*.msg",msgpath); + + if (( gefunden = xfindfirst(dname,&ffblk,0)) != FALSE) + Stop("Keine MSG-Dateien gefunden."); + + while(!gefunden) + { + strcpy(Datei,ffblk.ff_name); + printf("\n%s\n",strupr(Datei)); + for (a = strlen(Datei); a > 0; a--) + printf("-"); + printf("\n"); + sprintf(dname,"%s%s",msgpath,ffblk.ff_name); + fp = fopen(dname,"rt"); + while(!feof(fp)) + { + if((fgets(buffer,79,fp)) != NULL) + printf("%s",buffer); + } + fclose(fp); + gefunden = xfindnext(&ffblk); + } + Status = TRUE; +} +/*---------------------------------------------------------------------------- + GroupMsy.C +----------------------------------------------------------------------------*/ +/* Parameterreihenfolge ist: Programmname Befehl [Gruppe -/+ Call] Usercall + Argument(argv) 0 1 2 3 4 5 + Argument(argc) 1 2 3 4 5 6 + Wobei Gruppe, -/+ und call optional sind. Wenn keine Gruppe angegeben + wurde, dann alle Gruppen auflisten. Das letze Argument wird nicht aus- + gewertet. +*/ + +void GroupMsy ( int argc, char *argv[] ) +{ + char dname[MAXPATH]; + + if(argc == 3) /* Keine Gruppe angegeben */ + { + sprintf(dname,"%s*.mbr",msgpath); + GroupList(dname); + } + if(argc == 4) /* Gruppe angegeben */ + { + sprintf(dname,"%s%s.mbr",msgpath,strlwr(argv[2])); + GroupList(dname); + } + if(argc == 5) + Stop("Zuviele oder zuwenige Parameter !"); + if(argc == 6) + GroupSys(argv); +} +void GroupList(char *dname) +{ + int a; + int gefunden; + FILE *fp; + + gefunden = xfindfirst( dname, &ffblk, 0); + if (gefunden != FALSE) /* wenn nicht gefunden, dann meckern */ + Stop("Gruppe nicht gefunden..."); + + printf("\n"); + + while (!gefunden) + { + sprintf(dname,"%s%s",msgpath,ffblk.ff_name); + + if (( fp = fopen(dname,"rt")) == NULL) + Stop("Fehler #G1 Konnte Datei nicht oeffnen!"); + + strcpy(dname,ffblk.ff_name); + dname[strlen(dname)-4] = '\0'; /* Standard IMMER .EXT */ + printf("%s :\n",dname); + + for(a = strlen(dname)+2;a > 0;a--) /* Laenge des Gruppennamens */ + { + printf("-"); /* unterstreichen */ + } + printf("\n"); /* und dann ..... return !!! */ + + do /* Datei ausgeben */ + { + if(( fgets(dname,79,fp)) != NULL) + printf("%s",dname); + } + while (!feof(fp)); + + printf("\n"); + + fclose (fp); + gefunden = xfindnext(&ffblk); + } + Status= TRUE; +} +/*---------------------------------------------------------------------------- + GroupSys.C +----------------------------------------------------------------------------*/ +void GroupSys ( char *argv[]) +{ + int a; + int Anzahl; + int Nr = 0; + int was; /* Flag fuer - oder + call */ + int gefunden = FALSE; + char dname[MAXPATH]; + char call[MAXGROUP][8]; + FILE *fp; + + sprintf(dname,"%s%s.mbr",msgpath,strlwr(argv[2])); + was = *argv[3]; /* Was wird den gewuenscht ?? */ + + if (was > '.' ) /* simpelpruefung ob es + - ist */ + Stop("Falsche Parameterreihenfolge!"); + + if((fp = fopen(dname,"rt")) == NULL) /* Nun kommt es drauf an. */ + { + if(was == '-') /* Loeschen? Und ist da auch was ? */ + Stop("Gruppe ist nicht vorhanden!"); /* Noeh. Ist nix */ + else + printf("\n%s.mbr erzeugt.\n",argv[2]); /* Was Neues. */ + } + else /* Dann + */ + { + while(!feof(fp)) /* Erstmal einlesen */ + { + *call[Nr] = '\0'; + fscanf(fp,"%7s",&(*call[Nr])); /* fscanf findet zuviel */ + if(call[Nr][0] != '\0') + Nr++; + if(Nr > MAXGROUP) + Stop("Zuviele Calls in der Gruppe!"); + } + fclose(fp); + } + strupr(argv[4]); + strupr(argv[2]); + Anzahl = Nr; + + for( a = 0; a < Nr; a++ ) /* Gruppe durchsuchen */ + { + if((strcmp(call[a],argv[4])) == 0) + { + gefunden = TRUE; + if(was == '+') /* Call schon da ? */ + Stop("Das Call gibt es schon in der Gruppe!"); + else /* Loeschen !! */ + { + printf("\n%s wurde aus %s entfernt.\n",call[a],argv[2]); + (call[a][0] = '\0'); + Anzahl--; + } + } + } + if(gefunden == FALSE) /* Nichts gefunden */ + { + if(was == '-') /* und sollte loeschen.. */ + { + sprintf(dname,"%s ist nicht in der Gruppe %s !",argv[4],argv[2]); + Stop(dname); + } + else /* also eintragen */ + { + strcpy(call[Nr],argv[4]); + Nr++; + Anzahl++; + if(Nr > MAXGROUP) + Stop("Zuviele Calls in der Gruppe!"); + printf("\n%s wird der Gruppe %s hinzugefuegt.\n",call[a],argv[2]); + } + } + unlink(dname); /* die eingelesene Datei loeschen */ + + if (Anzahl == 0) + { + printf("Das Call war der letzte Eintrag. Gruppe geloescht.\n"); + exit(0); + } + + if((fp = fopen(dname,"wt")) == NULL) + Stop("Fehler #G2 Probleme beim Oeffnen der Datei !"); + + for ( a = 0,Anzahl = 0; a < Nr; a++) + { + if(*call[a] != '\0') + { + fprintf(fp,"%-6s ",call[a]); + Anzahl++; /* Anzahl nur erhoehen wenn auch geschrieben wird */ + } + if(Anzahl > 10) /* ist eigentlich 11 */ + { + fprintf(fp,"\n"); + Anzahl = 0; + } + } + fprintf(fp,"\n"); /* Return nach dem letztem Call */ + fclose(fp); + Status = TRUE; +} + +/*---------------------------------------------------------------------------- + MSY_LIN.C +----------------------------------------------------------------------------*/ +void Stop(char *S) +{ + if (strchr(S, '#')) /* Systemfehler */ + { + printf("\n%s\n", S); + printf("Bitte Beschreibung des Fehlers an Sysop schicken !\n"); + } + else + { + if (strchr(S, '!')) /* Bedienungsfehler */ + { + printf("\n%s\n", S); + printf("Bitte Hilfe anfordern mit 'MSY H'.\n"); + } + else + { + printf("\n%s\n", S); /* nur ne dumme Bemerkung */ + } + } + exit(0); +} +/*--------------------------------------------------------------------------*/ +int Calltest( char *Call ) +{ + int falschesZ, Zahl, i, a; + char dname[MAXPATH]; + Zahl = 0; + falschesZ = 0; /* falsches Zeichen */ + + if(!Gruppe) + { + if (strchr(Call, '-') > (char *)NULL) + *(char *) (strchr(Call, '-')) = '\0'; + } + a = strlen(Call); + for (i = 0; i < a; i++) /* pruefen ob Zeichen in Call Ok */ + { + Call[i] = tolower(Call[i]); /* fuer die Ascii-Ausgabe */ + + /* alle Zeichen die in der ASCII-Tabelle ueber Z, zwischen 9 und A + sowie unter 0 liegen, machen Call ungueltig ! */ + + if (isdigit(Call[i])) + Zahl++; + if (Call[i] > 'z') + falschesZ++; + if (Call[i] < 'a' && Call[i] > '9') + falschesZ++; + if (Call[i] < '0') + falschesZ++; + } + + sprintf(dname,"%s%s.mbr",msgpath,Call); /* auch auf Gruppe testen, erspart*/ + if ((xfindfirst(dname, &ffblk,0)) == 0) /* einwenig Arbeit */ + Gruppe = TRUE; + + if (!Gruppe && (strlen(Call) < 4 || strlen(Call) > 6 || Zahl < 1 || Zahl > 2 + || falschesZ > 0)) + return(TRUE); + return(TRUE); +} +/*--------------------------------------------------------------------------*/ + +int main ( int argc, char *argv[] ) +{ + char hilfstring[MAXPATH]; + char Call[11]; + char Befehl = '\0'; /* Befehl ist argv[1] */ + char *fnpoi; + + Status = FALSE; /* ist immer FALSE, muss von der Funktion gesetzt werden */ + + *msgpath = '\0'; + + if (getcwd(msgpath,MAXPATH)== NULL) /* Wo sind wir denn? */ + { + printf("\nKonnte Pfad nicht ermmitteln!\n"); + exit(0); + } + + if(*(fnpoi = msgpath + strlen(msgpath)) != Seperator) /* / oder \\ dran ? */ + *fnpoi++ = Seperator; + strcat(fnpoi, "msg"); /* Hier sollten immer MSG`s unter TNN sein !!! */ + *(fnpoi+3) = Seperator; /* msgpath ist nun festgelegt */ + + sprintf ( hilfstring,"%smsg.sys",msgpath); /* Hilfedatei da ??*/ + + if (xfindfirst( hilfstring, &ffblk, 0) != FALSE) + Stop ( "\nFehler #M1 Fehler im MSGPATH ! Hilfe-Datei nicht gefunden !" ); + + + if (argc < 3) + Stop("\nEs wurde kein Befehl angegeben !"); + + if ( strlen(argv[1]) > 1 ) + Stop( "\nDer Befehl wird nur mit dem Anfangsbuchstaben angegeben !"); + else + Befehl = tolower( argv[1][0] ); + + strcpy(Call, argv[argc - 1]); /* Absender ermitteln */ + if(Calltest(Call) == FALSE) /* und pruefen ob es ein call ist */ + Stop("\nFehler in Deinem Rufzeichen !?"); + else + { + strcpy ( Usercall, Call); + strupr(Usercall); + } + + printf("\nDigimail fuer SysOp's\n"); + + switch (Befehl) + { + case 'c': CheckMsy(); + break; + + case 'd': DirMsy(argc, argv); + break; + + case 'e': ListMsy(argc, argv); + break; + + case 's': if (argc < 4) + Stop("Zuwenig Parameter!\n"); + else + SendMsy(argc,argv); + break; + + case 'l': GetMsy(); + break; + + case 'g': GroupMsy(argc,argv); + break; + + case 'h': HelpMsy(); + break; + + case 'v': VerMsy(); + break; + + default: sprintf(hilfstring, "Befehl %c ungueltig !", Befehl); + Stop(hilfstring); + break; + } + if (!Status) + { + sprintf(hilfstring, "#Fehler bei Ausfuehrung des '%c'-Befehls !",Befehl); + Stop(hilfstring); + } + return(0); +} diff --git a/contrib/onlhelp/makefile b/contrib/onlhelp/makefile new file mode 100755 index 0000000..2e2eb3b --- /dev/null +++ b/contrib/onlhelp/makefile @@ -0,0 +1,87 @@ +######################################################################## +# # +# ***** ***** # +# ***** ***** # +# ***** ***** # +# ***** ***** # +# *************** *************** # +# ***************** ***************** # +# *************** *************** # +# ***** ***** TheNetNode # +# ***** ***** Portable # +# ***** ***** Network # +# ***** ***** Software # +# # +# File contrib/onlhelp/makefile (maintained by: DF6LN) # +# # +# Copyright (C) 1998 - 2004 NORD> +#include +#include +#include + +#ifdef WIN32 +#define MODI "(01.08.04) Modifiziert fuer Win32 von DAA531 Oliver Kern." +#endif + +#define VERSION "1.1" +#define VDATUM "Mar 01 2000" + +char *helpfn; +char *idxfn; +char progname[128]; + +#if defined(WIN32) && defined(_MSC_VER) +int strcasecmp(const char *Sstr, const char *Dstr) +{ + char _Sstr[255]; + char _Dstr[255]; + + if ( (Sstr == NULL) + ||(Dstr == NULL)) + return(1); + + strcpy(_Sstr, Sstr); + strcpy(_Dstr, Dstr); + strupr(_Sstr); + strupr(_Dstr); + + if (strcmp(_Sstr, _Dstr) == 0) + return(0); + else + return(1); +} + +int strncasecmp(const char *Sstr, const char *Dstr, int len) +{ + char _Sstr[255]; + char _Dstr[255]; + + if ( (Sstr == NULL) + ||(Dstr == NULL)) + return(1); + + strcpy(_Sstr, Sstr); + strcpy(_Dstr, Dstr); + strupr(_Sstr); + strupr(_Dstr); + + if (strncmp(_Sstr, _Dstr, len) == 0) + return(0); + else + return(1); +} + +#endif /* WIN32 */ + + +int gettopic(char *in, char *topic) /* prueft auf Zeile mit Befehl*/ +{ + if (*in == '(' && strchr(in, ')')) { + sscanf(in, "%s", topic); + if (strstr(in, "externer Befehl")) + return 2; + return 1; + } + return 0; +} + +void getcmd(char *cmd) /* liest den Befehl ohne Klammern */ +{ + char *cp = cmd; + + if (*cmd == '(') + cmd++; + + while (*cmd && *cmd != ')') + *cp++ = *cmd++; + + if (*cmd == ')') + cmd++; + + while (*cmd) + *cp++ = *cmd++; + + *cp = '\0'; +} + +int genindex(void) /* legt Index-File an */ +{ + FILE *fpt, *fpi; + char in[128], c_cmd[32], tmp[32]; +#ifdef WIN32 + int state, + i, + lines = 0; +#else + int state, i, lines; +#endif /* WIN32 */ + + long pos; + + if ((fpt = fopen(helpfn, "r")) == NULL) { + puts("Konnte Hilfedatei nicht oeffnen."); + return 0; + } + if ((fpi = fopen(idxfn, "w")) == NULL) { + puts("Konnte Index nicht anlegen."); + fclose(fpt); + return 0; + } + + state = 1; + pos = 0; + while (fgets(in, 120, fpt) != NULL) { + if (state == 1) { /* fetch version */ + if (!strncmp(in, "TNN-Doku-Version", 16)) { + fprintf(fpi, "%s", in); + state++; + } + } + else if (state == 2) { /* fetch first topic */ + if ((i = gettopic(in, tmp)) != 0) { + fprintf(fpi, "%s %d %ld ", tmp, i - 1, pos); + strcpy(c_cmd, tmp); + lines = 1; + state++; + } + } + else if (state == 3) { /* fetch next topics */ + if ( (i = gettopic(in, tmp)) != 0 + && strcasecmp(c_cmd, tmp)) { + fprintf(fpi, "%d\n%s %d %ld ", lines, tmp, i - 1, pos); + strcpy(c_cmd, tmp); + lines = 1; + } + else + lines++; + } + pos = ftell(fpt); + } + + fprintf(fpi, "%d\n", lines); + + fclose(fpt); + fclose(fpi); + + return 1; +} + +int checkindex(void) /* prueft, ob Indexfile neu angelegt werden muss */ +{ + struct stat statbuf1, statbuf2; + + if (stat(helpfn, &statbuf1)) { + puts("Hilfe-Datei fehlt. Bitte Sysop verstaendigen !"); + return 0; + } + if (stat(idxfn, &statbuf2)) + statbuf2.st_ctime = 0; + + if (statbuf1.st_ctime > statbuf2.st_ctime) { + puts("Generiere Index."); + return genindex(); + } + + return 1; +} + +void overview(void) /* Alle Befehle in der Uebersicht */ +{ + FILE *fpi; + char in[128], cmd[32]; + int left, ext, lines; + long pos; + + if ((fpi = fopen(idxfn, "r")) != NULL) { + puts("Programm-"VERSION" vom "VDATUM" by DL1XAO"); + fgets(in, 100, fpi); + printf("%s", in); +#ifdef WIN32 + puts(""MODI"\n"); +#endif + puts("\nFolgende Befehle sind laut Dokumentation verfuegbar :"); + puts("\nBefehl Hilfe-Seiten Befehl Hilfe-Seiten"); + + left = 1; + while (fgets(in, 120, fpi) != NULL) { + sscanf(in, "%s %d %ld %d\n", cmd, &ext, &pos, &lines); + lines = (lines + 18) / 20; + + printf("%-15s%s", cmd, ext ? "(extern) " : " "); + + if (left) + printf("%2d ", lines); + else + printf("%2d\n", lines); + left = 1 - left; /* Seitenwechsel */ + + } + puts("\nExterne Befehle sind nicht bei jedem Digi vorhanden !"); + fclose(fpi); + } +} + +/* Topic im Index suchen */ +int findtopic(char *topic, char *fcmd, long *pos, int *lines) +{ + FILE *fpi; + char in[128], cmd[32]; + int ext; + + if ((fpi = fopen(idxfn, "r")) != NULL) { + fgets(in, 100, fpi); + + while (fgets(in, 120, fpi) != NULL) { + sscanf(in, "%s %d %ld %d\n", cmd, &ext, pos, lines); + strcpy(fcmd, cmd); + getcmd(cmd); + if (!strncasecmp(topic, cmd, strlen(topic))) { + fclose(fpi); + return 1; + } + } + fclose(fpi); + } + return 0; +} + +void showhelp(char *topic, int startpage) /* Hilfe zu topic anzeigen */ +{ + FILE *fpt; + char in[128], cmd[32] ,*cp; + int lines, pages, n; + long pos; + + if (!findtopic(topic, cmd, &pos, &lines)) { + printf("Keine Hilfe zu %s gefunden.\n", topic); + return; + } + + pages = (lines + 18) / 20; + + if (startpage > pages) { + printf("Keine Seite %d zu %s vorhanden.\n", startpage, topic); + return; + } + + if ((fpt = fopen(helpfn, "r")) != NULL) { + fseek(fpt, pos, SEEK_SET); + + if (startpage == -1) { /* display all */ + while (lines && fgets(in, 120, fpt) != NULL) { + printf("%s", in); + lines--; + } + } + else { /* show one page */ + fgets(in, 120, fpt); + lines--; + if ((cp = strchr(in, '\n')) != NULL) + *cp = '\0'; + printf("%-70.70s Seite %d\n", in, startpage); + + n = (startpage - 1) * 20; /* skip n lines */ + while (n-- && fgets(in, 120, fpt) != NULL) + lines--; + + n = (lines > 20) ? 20 : lines; + while (n-- && fgets(in, 120, fpt) != NULL) { /* show page */ + printf("%s", in); + lines--; + } + + if (lines) + printf("Weiter mit \'%s %s %d\'\n", progname, topic, startpage + 1); + else + printf("Ende Hilfe zu %s!\n", cmd); + } + + fclose(fpt); + } +} + +void sysopcheck(char *pname) /* sind wir SYSHELP ? */ +{ + + char *cp; + + cp = strrchr(pname, '/'); + if (!cp) + cp = strrchr(pname, '\\'); + if (!cp) + cp = pname - 1; + + strcpy(progname, cp + 1); + + if ((cp = strchr(progname, '.')) != NULL) + *cp = '\0'; + + if (!strncasecmp(progname, "SYSH", 4)) { + + helpfn = "ohs.txt"; + idxfn = "ohs.idx"; + } + else { + helpfn = "ohu.txt"; + idxfn = "ohu.idx"; + } +} + +int main(int argc, char **argv) +{ + char topic[32]; + int start; + + puts("\nHilfe fuer TNN"); + + sysopcheck(argv[0]); + + if (checkindex()) { + + if (argc < 2) { + puts("Zuwenig Parameter angegeben !"); + } + else if (argc == 2) { /* oh dl1xao */ + overview(); + } + else if (argc == 3 || argc == 4) { /* oh st [2|*] dl1xao */ + strncpy(topic, argv[1], 30); + topic[30] ='\0'; + getcmd(topic); + start = 1; + if (argc == 4) { + if (*argv[2] == '*') + start = -1; + else { + start = atoi(argv[2]); + if (start < 1 || start > 20) { + puts("Nummer der Folgeseite muss zwischen 1 und 20 liegen !"); + return 1; + } + } + } + showhelp(argv[1], start); + } + else { + puts("Zuviele Parameter angegeben !"); + } + } + return 0; +} diff --git a/contrib/onlhelp/ohs.txt b/contrib/onlhelp/ohs.txt new file mode 100755 index 0000000..a0b4ae7 --- /dev/null +++ b/contrib/onlhelp/ohs.txt @@ -0,0 +1,1683 @@ +TNN-Doku-Version 1.79mh03 vom 17. Jul 2005 by CB-PR Team Dessau +(AL)IAS [] + ALIAS Befehle dienen dazu um einen Connect zum nächstgelegenen + DX-Cluster oder zur nächsten Mailbox/Externen_Convers einzutragen + + Zu Beachten ist lediglich, das die zeichenkette nicht laenger, + als 16 zeichen sein darf !! + + Beispiel: + ~~~~~~~~~ + AL BCM C DBX531 1 DNO531 + + Zum Loeschen: + ~~~~~~~~~~~~~ + Nur "AL BCM" eingeben. + +(AX)IPR +/- UDP + Zeigt die interne AX25IP-Routing-Tabelle an. + + Dieses Modul wurde Automatisiert. Das heißt eingehende neu Routen, + werden automatisch in die Interne Routing Tabelle aufgenommen. Diese + werden auch als (AUTO-ROUTE) bezeichnet. Ändert sich eine IP-Adresse + oder UDP-Port, wird das in der Internen Routing Tabelle aktualisiert. + + Neu: + ~~~~ + Dann wurde eine Protokoll-Erkennung eingebaut. Damit ist es jetzt möglich + das sich Routen automatisch an das Node anbinden koennen (AX25IP-Port) + Flexnet-bzw. Netrom-Protokolle werden automatisch in die LINKS Tabelle + eingetragen. Außerdem koennen User aus dem Internet sich in das Node + einloggen. Wird eine Route nach einer "gewissen Zeit" + (wird auch als "PINGTIME" bezeichnet) nicht mehr gelesen, wird diese + Route aus der internen-Routing Tabelle geloescht. Das gilt aber nur fuer + (AUTO-ROUTEN) mit oder ohne Linkanbindung. + + ACHTUNG: + ~~~~~~~~ + AX25IP.CFG wird nicht mehr unterstützt!!! Alle Eintraege in der AX25IP.CFG + muessen einmal auf der Console ausgeführt werden. Mit "SP" kann man die + eingegebenen Daten speichern. + + Folgende Befehle stehen zur Verfügung: + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + Den UDP-Port ändern, wo unser TNN-Knoten lauscht: + ------------------------------------------------- + AX U 93 + + Loglevel ändern: + ~~~~~~~~~~~~~~~~ + AX L 4 + + loglevel 0 - no output + loglevel 1 - config info only + loglevel 2 - major events and errors + loglevel 3 - major events, errors and AX25 frame trace + loglevel 4 - all events + + Die Log-Informationen werden in der Datei ax25ip.log abgespeichert. + + Eine AX25IP-Route eintragen: + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + UDP-Modus: + ---------- + AX R + DIG531 DIG531.DYNDNS.ORG UDP 93 + + IP-Modus: + --------- + AX R + DIG531 DIG531.DYNDNS.ORG + + Eine AX25IP-Route austragen: + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + AX R - DIG531 + + Unsere interne Routing-Tabelle: + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + JO61QH:DIG531> AXIP-Routes:(72/90) + Alias-:Call---IP-------------Mode-Port--PMode---PTime---RX----TX---Online- + Riesa: DNO531 213.146.112.94 UDP 93 INP 298 1296KB 1190KB 19H,0m + + AXIP-Rotes:(70/90) + | | + | max. Anzahl AXIPR-Routen + aktuelle Anzahl der AXIPR-Routen + + Alias = Aliasname vom Linkpartner + Call = Rufzeichen vom Linkpartner + IP = Aktuelle IP_Adresse vom Linkpartner/User + Mode = Protokoll, UDP oder IP. + Port = TX-Port vom Linkpartner/User + PMode = Protokollanforderung unseres Linkpartners. + PTime = Pingtime, brauchen wir für die Aktualisierung der DNS-Adresse. + RX = empangene UDP-Packete. + TX = gesendete UDP-Packete. + Online = Connect Zeit. + + Mit dem Parameter "PINGTIME" kann man die Aktualisierung der AXIPR-Routen + steuern. (Weitere Informationen siehe PArameter "PINGTIME") + + Es bersteht die Möglichkeit die interne-Rozing-Tabelle als HTML + darzustellen. Möchte man dies gerne tun, muss man in der TNN179.TNB das + richtige Verzeichnis setzen und im TNN den PArameter HTML-STAT einschalten. + Die AKtualisierung der HTML-Datei "rstat.html" erfolgt aller 1.Minute. + Außerdem kann man das Aussehen der HTML-Statistik nach seinen wünschen + anpassen. Anderungen sind in der Datei "rstat.css" vorzunehmen. + +(ARP) +/- DG/VC [ ] + Nimmt mit als DC/VC als in die Linkliste + auf. Die Digipeater und k”nnen mit angegeben werden. + + ARP-Eintr„ge macht TNN automatisch. Sie mssen nur fr Wege ber via- + Digipeater und NET/ROM-Verbindungen angeben werden, da hier ARP nicht + m”glich ist. + + ARP-Eintr„ge werden fr Gateways gemacht, bzw. fr direkt erreichbare + Stationen. + + DestIP Ist die IP-Nummer des (IP-) Nachbars auf diesem Port + + +/- Zum Ein- oder Austragen + + Publ. Publish soll dieser Port/Nachbar allen anderen auch bekannt + gegeben werden? Ein P steht fr "ARP beantworten", wird es + weggelassen, werden ARP-Anfragen an dieses Ziel ignoriert. + + Port Portname des Knotens ber den die IP-Adresse erreichbar + ist. Es kann hier auch wieder NETROM angegeben werden. + + DG/VC Datagram/Virtual Circuit. Also soll das ganze + Verbindungslos aufgebaut werden (Datagram) oder soll eine + Verbindung da sein (Virtual Circuit). Von Digi zu Digi + sollte DATAGRAM eingestellt sein, dann gibt es weniger + overhead. Dann findet allerdings auch keine Fehlerkorrektur + auf dem Link statt, dies wird aber (zwar etwas langsamer) + von den Endstationen (TCP/IP) gemacht. Auf DAMA-Einstieg + ist UNBEDINGT VC einzustellen. Bei NETROMs hat dieser + Parameter keine Bedeutung. + + Call AX-25-Call, unter dem der Rechner mit der IP-Nummer + erreichbar ist. + + Beispiel: ARP 44.130.82.41 + P Sysop_9k6 VC DB7KG DB7KG-5 + + Was geht, und was nicht geht: + - Der IP-Router von TNN kann Frames beliebiger L„nge durch + Fragmentierung bertragen. Die Reassemblierung wird der Endstation + berlassen. + - TNN empf„ngt aus Kompatibilit„tsgrnden zu FlexNet nur Packete bis + 256 Bytes Info. + - ARP/REV ARP-Anfragen werden sofern erlaubt, beantwortet. + +(BE)ACON = + Setzt bzw. „ndert die Bakentexte fr die einzelnen Ports. + +(BE)ACON = + Entfernt den Bakentext. + +(BE)ACON + Schaltet die Bake ein. + + Port 0..16 Portnummer. + + mins 0..n 0 = Bake aus. + n = Intervall in Minuten. + Default ist 10 Minuten. + + metric 0, 1, 2, 3 0 =Keine Metric. + 1 =Metric. + 2 =Zus„tzlich STAT. + 3 =Status Bake (Neu) + + call oder alias QST = UI-Frame von Knoten an Call 'QST'. + + Es gibt Terminalprogramme, welche die METRIC- und/oder STAT- Bake direkt + auswerten und anzeigen k”nnen. Besonders sind an dieser Stelle zu + erw„hnen: THP (Turbo Host Packet) und TOP (The Other Packet). + + Am Knotenterminal kann diese Bake auch mitgeschrieben oder auch in einen + File gespeichert werden. Eingabe: MU + METRIC STAT oder MCU + + METRIC STAT. Beim Neustart wird der Monitor ausgeschaltet. + + Die Bake mit metric=1 hat diese Informationen: + + 980208 210306 Up= 101148 Mem=1773568 Buf=5956 Rps= 524 + Lnk=154 Cir= 45 Sum=2602324027 Thr= 51464 + 980208 210406 Up= 101159 Mem=1773568 Buf=6645 Rps= 522 + Lnk=154 Cir= 43 Sum=2602669277 Thr= 48512 + + 980208 210306 Aktuelles Datum und Uhrzeit. + Up=101158 Betriebszeit in Tagen, Stunden und Minuten. + 10 Tage, 11 Stunden und 58 Minuten. + Mem=1773568 Freier DOS RAM (Coreleft, Bytes) + Buf=5956 Freier TNN-Buffer (Bl”cke). + Rps=524 Hauptschleifendurchl„ufe/Sekunde. + R=0 Anzahl der Token-Recoveries. + Lnk=154 Anzahl der aktiven L2-Links. + Cir=45 Anzahl der aktiven Circuits (L4-Links). + Sum=229961 Z„hlerstand des Statistik-Gesamtz„hlers. + Thr=51464 Derzeitiger Datendurchsatz in Baud. + + + Bei metric=2 wird zus„tzlich bei jedem empfangenen L3-RTT Meáframe ein + UI-Paket des Knotens an METRIC abgestrahlt: + + 10.12.97 16:26:52 DB0LBG-7(09) + L3RTT=15490ms L3SRTT=7350ms (7350ms/6760ms) L2SRTT=820ms SUM=4302022 + 10.12.97 16:26:54 DB0NHM(10) + L3RTT=840ms L3SRTT=790ms (1090ms/500ms) L2SRTT=640ms SUM=1750605 + 10.12.97 16:27:02 DB0BID(09) + L3RTT=2210ms L3SRTT=1340ms (1780ms/900ms) L2SRTT=680ms SUM=1510236 + + Aktuelles Datum und Uhrzeit + DB0LBG-7 Rufzeichen des Nachbarknotens. + (09) Empfangsport des Meáframe. + L3rtt=000185ms Soeben gemessener Level-3 RTT. + L3SRTT= 1. Zeit ( 2. Zeit / 3. Zeit ). + 1. Zeit Ermittelter SRTT aus der Messung. + Bei FlexNet mittel aus 2. Zeit und 3. Zeit. + 2. Zeit Von diesem Knoten ermittelter SRTT in ms. + 3. Zeit Von anderen Knoten ermittelter SRTT in ms. + L2srtt=00074ms Level-2 SRTT Laufzeit in ms. + SUM=4302022 Z„hlerstand des Linkz„hlers damit man beim + Auswerten die Linklast hat. + Neu: + ~~~~ + Statusbake mit intressanten Informationen für die User oder Sysop + Die Aussendung der Bake kann man mit dem PArameter Statusbake steuern. + Der Standartwert ist 300 (5 Minuten), das heißt aller 5 Minuten wird + die Bake gesendet. + + Statusbake einstellen: + ~~~~~~~~~~~~~~~~~~~~~~ + (Beispiel für Port 0,Intervall 60, und Statusbake 3) + + BEACON 0 60 3 IDENT + + Ausgabe auf dem Monitor + ~~~~~~~~~~~~~~~~~~~~~~~ + T0:DNO531 to STATUS UI^ pid F0-21.03.04 21:26:13 + Links: 32, Convers: 23, Dest/Nodes: 272, Buffers: 19872, Runtime: 44m,55s + DIG531:3 DNO531:28 KR1GAT:3 DIX213:2 + + Die Status-Bake hat folgende Informationen + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + Links = aktuelle Anzahl der L2-Links im Knoten + Convers = aktuelle Anzahl der Convers-User im Knoten + Dest/User = Anzahl erreichbare Dest/Nodes + Buffer = Freie Buffer + Runtime = Laufzeit des Programmes + Rufzeichen = alle Linkpartner mit Laufzeitangabe + (außer links ohne Laufzeitmessung) + + Die Status-Bake ist er ab V1.79mh02 verfügbar!!! + +(BE)ACON 0 0 ID + Schaltet die Bake wieder aus. + +(CL)EAR + L”scht alle Statistikeintr„ge. + +(CONV)ers (C)stat + ...oder im Conversmode mit: /Link + Zeigt die Liste und den Status der Nachbar-Convers-Host an sowie die + Laufzeiten zu allen Convers-Host und deren Versionsnummer. NUR im + Sysopmodus wird zus„tzlich der eingetragene Weg (ob l4 oder l2 mit Port + und Via-Eintr„gen) angezeigt. + +(CONV)ers (C)stat + ...oder im Conversmode mit: /Link + Nimmt einen Nachbarknoten fr Convers-Betrieb auf. Unter ist das + Rufzeichen des Nachbarknoten einzusetzen. Der Nachbarknoten muá dann in + der Nodesliste stehen. + +(CONV)ers (C)stat + ...oder im Conversmode mit: /Link + Nimmt einen Nachbarknoten fr Convers-Betrieb ber eine Level2 Verbindung + auf. Unter ist das Rufzeichen des Nachbarknoten einzusetzen. Unter + ist die Portnummer anzugeben und bei Bedarf ein oder mehrere via- + call. + +(CONV)ers (C)stat 254 + ...oder im Conversmode mit: /Link 254 + Gibt einen Nachbarknoten fr Convers-Betrieb frei. Unter ist das + Rufzeichen des Nachbarknoten einzusetzen. Es wird zu dem KEIN Link + aufgebaut sondern TNN erwartet, daá dieses den Link aufbaut. + Dieses ist z.B. fr Wampe Rechner die zwar selbst einen Link aufbauen + k”nnen aber nicht mit einem ankommenden Connect zurecht kommen. Der + Eintrag wird gekennzeichnet mit: (trusted host). + + ES MšSSEN UNBEDINGT LOOPS VERHINDERT WERDEN. DESHALB: BITTE ABSPRECHEN ! + +(CONV)ers (C)stat - + ...oder im Conversmode mit: /Link - + L”scht den Eintrag. + +(CONV)ers - intern - + + PingPong Convers aus Sysopsicht: + + Links: + Links werden mit dem "/links" Befehl eingetragen, der auch auáerhalb des + Convers mittels "conv c" verfgbar ist. So eingetragene Links sind + permanent und werden in bestimmten Intervallen (9s,150s,300s,600s,...,3h) + connected. Es gibt auch nichtpermanente Links, diese Option ist aber + durch Konfiguration einstellbar. Diese Links werden bei einem Linkabriá + automatisch ausgetragen, der Knoten connected den neuen Partnern nicht + hinterher. (Das Eintragen geschieht durch Eingeben des "/..host" + Befehls.) + + Syntax ist: /l [-][call [port [via]]] + bzw. auáerhalb von Convers: conv c [-][call [port [via]]] + + - Dient zum L”schen eines Eintrags ( reicht aus). + Ist das Rufzeichen des Nachbarknotens. + Downlinkport (wird nur bei L2 Verbindungen gebraucht). + Via-call (optional fr L2 Verbindungen). + + Fr L4-Verbindungen gengt die Angabe des Calls des gewnschten Knotens, + es wird NICHT versucht, eine L2-Verbindung bei fehlendem Nodeeintrag + aufzubauen. Dem Sysop wird bei diesem Befehl unter jedem Linkeintrag der + Connectweg in Klammern angezeigt, z.B.: + + im Falle L4 (DB0AGM), + im Falle L2 (DB0XYZ on port 2 via DB0ZXY). + + Hilfe: + Ist in einer Datei namens CONVERSD.XHF. Diese enth„lt alle Texte, + getrennt durch Markierungen. Es ist erlaubt, die Texte zu „ndern, + Reihenfolge spielt bis auf den obersten Abschnitt keine Rolle. Die + Markierungen sind durch Convers vorgegeben, Einfgen von neuen + Markierungen ist daher sinnlos. Die Datei enth„lt Umlaute nach ISO, bitte + beim šberarbeiten daran denken. Wird die Hilfe angefordert, konvertiert + der Convers die Umlaute selber in die vom User gewnschte Form. + + Sonstige Dateien: + CONVERS.PRS enth„lt die pers”nlichen Daten aller, die diese am eigenen + Knoten eingegeben haben. Diese Datei ist ebenfalls im Textverzeichnis, + wird aber beim Beenden von TNN im Configverzeichnis gesichert bzw. beim + periodischem Sichern der Konfiguration. Darunter fallen der Personaltext, + die Zeichensatzwahl und die Zeilenbreite. + + NICKNAME.TXT enthaelt Daten von Usern die ihren Nicknamen, Passowrt !! + im Convers gesetzt haben. Die liegt im Hauptverzeichnis von TNN und wird + beim Beenden von TNN gespeichert. + + Loop detected: + Loop werden nun berwacht und der entsprechende Link fr eine Stunde "aus + dem Verkehr gezogen". Das Auftreten und die H„ufigkeit wird in der CONV- + C-Tabelle angezeigt. + +(CPERS) (externer Befehl) + Ist nun nur noch zur Pflege der "Visitenkarten" der Datei CONVERS.PRS. + Zum einen gibt es mitunter mal Eintr„ge, die "zuf„llig" entstanden sind, + und die der Sysop gerne entfernen m”chte. Oder sie auch nur durch einen + anderen ersetzen. Der einfache Aufruf des Programmes entfernt + "Leereintr„ge" ohne Text sowie "unsinnige" Texte, die zum Beispiel nur + aus einem Zeichen bestehen. Bei jedem Aufruf des Programmes wird eine + Datei CONVERS.ALT angelegt, um zumindest die letzte Žnderung der Datei + noch einmal rckg„ngig machen zu k”nnen. Da es durch den Aufruf dieses + Programmes zu Speicherplatzproblemen (CONVERS.PRS zu groá) kommen kann, + berprft das Programm zuerst, ob die Datei noch in den verbleibenden + Speicher geladen werden kann. + +(CPERS) /sort + Sortiert die Eintr„ge alphabetisch nach dem Call. + +(CPERS) + + Ersetzt bzw. fgt das Call mit dem an die Datei CONVERS.PRS an. Es + wird hierbei KEIN Callcheck durchgefhrt ! + +(CPERS) - + Entfernt das Call und den Eintrag aus der Datei CONVERS.PRS. Auch hier + KEIN Callcheck, damit auch die unsinnigsten Eintr„ge bearbeitet werden + k”nnen. + +(CWER) (externer Befehl) + Ist ein kleines Programm, welches die Visitenkarten der User, die sie + sich selbst mit /P im Conversmode erzeugt haben, anzeigt. + +(CWER) a + Erzeugt eine Liste mit allen Eintr„gen. + +(CWER) l + Zeigt die l=letzten von Eintr„gen an (die neuen werden immer + hinten angeh„ngt). + +(CWER) + Kann auch in Verbindung den Platzhaltern "*" und "?" aufgerufen werden. + Dabei steht "*" fr beliebig viele Zeichen und "?" fr genau 1 Zeichen. + +(DCD) + Das DCD- Kommando zeigt den in der Software erkannten DCD Zustand an. + + P00 P01 P02 P03 P04 P05 P06 P07 P08 P09 P10 P11 P12 P13 P14 P15 + t rt rt rT T OFF OFF OFF OFF OFF OFF OFF OFF + + OFF = Port nicht in Betrieb, + r = DCD an, + R = DCD an und noch Frames im Empf„nger in der Vanessa, + t = PTT an, + T = PTT an, noch Frames zu senden in der Vanessa. + +(DOS) + Zugriff auf COMMAND.COM. Hiermit lassen sich viele Operationen + durchfhren. Natrlich muá hierzu COMMAND.COM auch den Zugriff auf die + entsprechenden Erweiterungsprogramme haben. Doch Vorsicht ist unbedingt + angesagt! Bei einem Fehler habe ich zumindest 50 km Autofahrt und evtl. + einen kr„ftigen Fuámarsch gewonnen. Also interaktive Eingaben vermeiden! + + Beispiel: DOS DIR listet das aktuelle Verzeichnis. + DOS DIR A: listet LW A. + + Bei LINUX heiát das Kommando SHELL, und beim TNC3 heiát das Kommando TOS. + +(DX)CLUSTER - + l”scht das gesetzte Call. + +(DX)CUSTER + setzt das Call des lokalen Cluster. Das Cluster muá nun nicht mehr + Bestandteil des eigenen Knotens sein, sondern es kann auch ein beliebiges + Cluster eingetragen werden. + +(E)DIT + Legt den hinter edit angegebenen File-Name im Workpath an. Mit (E)dit + kann jedoch kein bestehenden File zum Žndern aufgerufen werden. + Bestehende File werden ersetzt!. + +(E)DIT + Auch die Angabe eines Pfades ist m”glich. + + Ist der Editiermodi bereits durch einen anderen Sysop aufgerufen, so + bekommt man die MSG : + + Edit-Mode in use by other Sysop + +(HTTP)D Server + + Neu: + ~~~~ + Der HTTP-Server funktioniert nur unter LINUX und WIN32-Systeme. + (Das Grundgerüst besteht aus dem Quellcode von der BayCom-Mailbox V1.44) + Die Funktion des HTTPD_Server ist sehr aenlich mit der BCM zu vergleichen. + Beim erten Login wird nach Benutzername und Passwort gefragt, + Passowrt ist optional,also nicht zwingend! + Kommt eine http Anfrage vom User, wird dieser automatisch ins TNN + angemeldet Befehle ausgeführt und wieder abgemeldet. + + Konfiguration: + ~~~~~~~~~~~~~~ + (HTTPD-Port definieren in der TNN.INI) + + device http + kisstype 23 + port 0 + + TNN-Console + ~~~~~~~~~~~ + (Httpd-Port öffnen) + + PO 0 ON + + TCP-Port ändern: + ~~~~~~~~~~~~~~~~ + + HT P 80 + + Mein LOGlevel ändern: + ~~~~~~~~~~~~~~~~~~~~~ + + HT L 0 + Damit ist die Konfiguration abgeschlossen. + Port 0 ist nur ein Beispiel der HTTPD_Server kann auch auf andere Ports + definiert werden. Wenn es Probleme beim HTTPD-Server geben sollte, ist es + hilfreich LOGlevel einzuschalten. + HT L 1 + Es werden nur Fehlermeldungen in die Datei "httpd.log" geschrieben. + HT L 2 + Es werden alle Informationen in die Datei "httpd.log" geschrieben. + + Weitere Infos: + ~~~~~~~~~~~~~~ + Es wird draud geachtet, ob ein User in der SUSPEND-Liste + (Rufzeichen sperren) steht. Interne und Externe HTML-Ausgabe. + Interne HTML-Ausgabe:ist eine Standart HTML-Seite die im Programm + festgelegt ist. + Externe HTML-Ausgabe:jeder Sysop hat die Möglichkeit seine HTML-Datei + selbst zu erstellen. Weiter Infos siehe (TNN179_CB.PDF) + +(IPA)dress 0.0.0.0/32 + Setzt die IP-Adresse und die Subnetzbits des Knotens. + Werden keine Subnetzbits angegeben, so wird 32 eingestellt. + +(IPR)oute / +/- + + Nimmt / auf in die IP- + Routenliste auf. + + DestIP Ist die IP-Nummer des (IP-) Nachbars auf diesem Port + + Maskbits Hier wird entweder eine Zahl (Anzahl Bits) oder eine Art + Pseudo IP-Nummer eingetragen. Anzahl der Bits heiát: Eine + IP-Nummer hat 4 Bytes mit 8 Bit = 32 Bit. Trage ich hier 16 + ein, so werden nur die ersten 2 Byte ausgewertet + (entspricht fr AFU: 44.130; 44=AFu 130=DL). Trage ich 24 + ein, wird schon die Region beachtet, also 3 Bytes (44=AFU + 130=DL 27=KS) bei einer (Beispiel) Nummer 44.130.27.80. So + kann man hierarchisch Routen aussortieren. Bei der anderen + M”glichkeit wird fr das Byte, was frei bleibt eine 0 + eingetragen. + + Bsp.: 44.130.27.0 = Kassel. + + Kann auch mit Broadcast zusammen so aussehen: + + 255.255.255.0 oder 44.130.27.255..kommt ganz darauf an + + +/- Zum Ein- oder Austragen + + Interface Hier wird die Schnittstelle benannt, wo die Pakete fuer + herauskommen sollen. Dies kann der NAME eines + Ports sein (also User_1k2, User_9k6). Es kann auch "NETROM" + angegeben werden. In diesem Fall wird das Packet an ein + NETROM-Ziel (das muá natuerlich auch ein Gateway [TNN] oder + ein TCP/IP-Host [KA9Q] sein) bertragen. + Fuer die Verwendung des direkten Kernel-Interfaces unter + Linux ist hier der Name "KERNEL" anzugeben. + + GateIP Wird ein Gateway benannt, so wird hier die IP-Nummer des + Gateways eingetragen. ueber ihn werden dann alle + (IP-)Packets vermittelt. + + Metric Diese Angabe wird in einer sp„teren Version Bedeutung + haben, z.Z. bitte ignorieren. + + Beispiel: IPROUTE 44.130.27.0/24 + User_9k6 + + Hinweis: TNN lernt aus dem Netz per INP empfangene IP-Routen zu anderen + Nodes. Diese Routen werden automatisch wieder entfernt, sobald + der Node abgemeldet wird. Von Hand gemacht Eintraege werden von + der Automatik nicht ausgetragen (gilt auch fuer Eintraege aus + .TNB-Dateien). Naehere Infos siehe bei (PA)RMS. + +(K)ill + Unterbricht alle Level-2 Verbindungen auf dem nach Sendung der + . + +(K)ill + Unterbricht alle Level-2 Verbindungen zu dem nach Sendung der + . + +(K)ill * + Trennt alle Level 2 QSO auf dem Digipeater nach Sendung der . + +(L)INKS +/- TYP [P] [Port] ALIAS:CALL[-*] [ []] [INFOTEXT=Inhalt] + Nimmt [Proxy] mit ber in die Linkliste auf. + Fuer die Anbindung von Digipeatern ohne TheNetNode-Protokoll. + Die Digipeater und koennen mit angegeben werden. + Es werden nur Nodes angenommen die, unter Links eingetragen sind. + Hierbei wird auch der eingetragene Port beachtet. + + +/- + Eintragen und - Austragen des Links. + + Typen: + + L = Local + Call und Alias wird mit einer Laufzeit von 4000 ms in die NODES- + Liste bernommen, es wird aber keine Laufzeitberprfung + durchgefhrt. In der Routesliste wird er ohne Eintrag in Status + gefhrt. + + L+ = Local + Wie oben, jedoch wird die Erreichbarkeit geprft und die Laufzeit + gemessen. Kann die Laufzeit ermittelt werden, so wird dieses Ziel + zur besseren šbersicht als conn. im Status gefhrt. + + F = FlexNet + Port arbeitet mit FlexNet Protokoll. + + N = NetRom + Aktueller TheNet-Nachbar. šbernahme in Nodesliste mit der + ermittelten Laufzeit. Es erfolgt KEINE automatische Umschaltung + mehr zum InterNode Protokoll. Um INP zu verwenden MUSS nun + explizit der Modus "I" angegeben werden !!! + + N- = Altes NetRom (mit UI-Baken zur Nodesuebermittlung) + + I = InterNode Protokoll + Aktuelles Protokoll, unterstuetzt die Verbreitung von IP-Infor- + mationen. Bei Angabe von I wird nur noch I aufgebaut, es erfolgt + KEIN Rueckfall mehr auf N oder N+ !!! + + [P] Neu: Proxy-Funktion! Text wird noch Aktualisiert. + + #ALIAS ALIAS - Eintr„ge die mit einem "#" davor gekennzeichnet sind, + werden zwar in die ”rtliche Nodesliste aufgenommen aber nicht als + NODE weiter verteilt. + +(L3)MHEARD - + Setzt die Z„hlerst„nde der Level 3-Statistik auf 0, aber l”scht nicht die + L3MH-Liste. + Dies sollte einmal monatlich durch automatisch ausgefuehrte + TNB-Dateien mit geschehen. + +(L3)MHEARD = + Setzt die L3MH-Liste auf die Rufzeichen. Man bedenke aber, daá + sie auch gespeichert werden mssen. L”schen der MH-Liste geschieht immer + dann, wenn ihre Gr”áe verringert wird. Damit sind dann aber auch die L3- + Daten verloren. + +(LOA)D oder (LOA)D \ + L„dt auf die Diskette oder HD beim Knoten. Der + darf maximal 8 Zeichen + 3 ext. lang sein (gilt + nicht unter Linux) und muá folgendes Format haben: + + LOAD TNN179.EXE + + Vorsicht bei der Auswahl des Filenamen, damit nicht das bisherige TNN- + Programm versehentlich berschrieben wird. Gegebenenfalls einen noch + nicht verwendeten Filenamen verwenden und nach dem Umkopieren in das + gewnschte Verzeichnis mit DOS REN ... umbenennen. + + Nach der Eingabe von "LOAD " wartet der Rechner auf die + Zeichenfolge #BIN#L„nge (z.B. #BIN#82345). Die Zahl hinter #BIN# steht + fr die Programml„nge in Bytes (dezimal). Auf diese Zeichenfolge wird mit + einem #OK# reagiert. Nachdem der SYSOP dieses #OK# empfangen hat, kann + mit der šbertragung begonnen werden. + + Die oben beschriebene Prozedur entspricht derjenigen, die von THP, SP + oder GIPSY als AUTOBIN-THP bekannt ist. Zum Einladen eignen sich diese + Programme also ganz besonders. + + Nach erfolgreichem Einladen gibt der Knoten eine Checksumme (CRC) aus. + Diese Checksumme MUSS derjenigen entsprechen, die auch von den o.a. + Programmen ermittelt wird. TNN wurde daran angepaát. + + Siehe hierzu auch noch die M”glichkeiten die STARTCNT.EXE erm”glicht. + +(M)AILBOX + setzt das Call der lokalen Mailbox. Die Mailbox muá nun nicht mehr + Bestandteil des eigenen Knotens sein, sondern es kann auch eine beliebige + Mailbox eingetragen werden. + +(M)AILBOX - + l”scht das gesetzte Call. + + Eine Mailbake (!) ist kein Befehl in TNN, sondern eine Funktion der + jeweiligen Mailbox-Software. UI-Frames k”nnen auf einem bestimmten Port + gesendet werden. Dazu wird der Knoten - Alias mit SSID verwendet. Der + SSID gibt hierbei den Port an, wo die Bake gesendet werden soll. + + DB0GSO-10 to MAILS via GSO-4 + < 15:36:57 > DPBOX v5.07.00 + Mail for : DB6KF DC8KN DG1KMN DG3KMB DK3BR DL0GSO + + sende die Mailbake der DP-BOX auf Port 4 (GSO der Alias, -4 der SSID = + Port). šber diesen Weg k”nnte z.B. auch eine DP-BOX einen PACSAT + Broadcast auf einem bestimmten Port abstrahlen. + +(MH)EARD - + Setzt die Z„hlerst„nde der USER-Statistik auf 0, aber l”scht nicht die + MH-Liste, die bei mehreren Userports ben”tigt wird. + Dies sollte einmal monatlich durch eine automatische TNB-Datei geschehen. + +(MH)EARD = + Setzt die MH-Liste auf die Rufzeichen. Man bedenke aber, daá sie + auch gespeichert werden mssen. Die L„ngen„nderung fhrt nur zum Verlust + der am Ende der Liste stehenden Call. Die Anzahl ist auf 5000 begrenzt. + +(MO)NITOR OPTIONEN PORT + Weitere Hilfe Siehe unter (TR)RACE. + +(MSY) (externer Befehl) + MSY.EXE in SYSEXE ist ein Hilfsprogramm fr den Sysop, das zu MSG.EXE in + USEREXE geh”rt. + +(MSY) C + Lifetime aller Nachrichten wird um 1 verringert. Dieses kann per Hand + geschehen oder mit einem solchen TNB-File. + (Beispiel fuer taegliche Ausfuehrung) + + ######01.TNB + ============ + ; ;Diese File startet t„glich um 1:00 Uhr. + MSY C ;Lifetime der .MSG-File um einen Tag herabsetzen + ; ;und bei Lifetime = 0 entfernen. + +(MSY) D + Listet die Header aller vorhandenen Nachrichten auf. + +(MSY) D -#x o. +#x + Nachrichten, deren Lifetime (-) kleiner o. (+) gr”áer x-Tage ist. + +(MSY) D -*x o. +*x + Nachrichten, die (-) jnger o. (+) „lter als x-Tage sind. + +(MSY) D FROM + Zeigt die Nachrichtenliste sortiert nach Absender Calls an. + + Die Sortierung kann auch nach : + + BYTE, DATE, TIME, LT, RETURN vorgenommen werden. + +(MSY) E ALL + L”scht alle Nachrichten von oder an . + +(MSY) E 01.01.95/00:00:01 + L”scht alle Nachrichten dieses Datums/dieser Uhrzeit. + +(MSY) G +/- + Fgt/l”scht aus . Zugelassen in einer Gruppe sind maximal + 50 Call. + +(MSY) L + Zeigt alle Nachrichtenfiles. + +(MSY) S #x + Schreibt an mit Lifetime #. Hier ist eine Lifetime von + maximal 99 Tagen m”glich. + +(MSY) V + Ausgabe von der Versionsnummer und dem Datum. + +(O)utput (externer Befehl) + OUTPUT.EXE ist nun ein eigenst„ndiges Programm geworden, das der Sysop im + Bedarfsfall aufrufen kann. Der Aufruf erfolgt wie bei einem internen + Befehl. OUTPUT.EXE ist, wenn es sich im PATH SYSEXE befindet, NUR vom + SYSOP nach der Privilegierung aufrufbar. Bei Eingabe von Output ohne + Argument wird der momentane Zustand der Portbits angezeigt. + + KS:DB0EAM> IO-Port-Status + 0 1 2 3 4 5 6 7 + 1 1 1 1 1 1 1 1 + + Der Befehl Output ist fr Fernsteuerungen vorgesehen. Die 8 + Datenleitungen des Druckerports (LPT1) des PC k”nnen bitweise ein- und + ausgeschaltet werden. + + Der Ausgangszustand nach einem Programmstart ist "alles eingeschaltet". + Die Basisadresse des Ports wird ber das Rechner-BIOS abgefragt. Soll + also ein anderer Port als LPT1 verwendet werden, so muá nur bei 40:08 die + passende Adresse stehen. + + Dieser Befehl steht ebenfalls fuer Linux als externes Programm zur + Verfuegung. + +(O)utput + : zu schaltendes Datenbit (0..7). + : neuer Pegel (0 oder 1). + +(PA)RMS + Zeigt den eingestellten Wert dieses Parameters sowie den einstellbaren + Bereich an. + +(PA)RMS + + Beispiel: P 1 20 + + Setzt Parameter 1 (NoAckBuf) auf 20. Die Žnderung wird quittiert mit: + + 1: NoAckBuf = 20 (7...127) + + Autoparameter: + Einige Parameter fr die Ports werden nun automatisch von TNN + eingestellt, so daá nun nur noch MaxFrame und TXDelay brig bleiben. + Diese werden nun nicht mehr ber die PARAMETER eingestellt sondern + mit dem PORT-Kommando. + + T2 = 2888 / (Baudrate / 100) + bei DAMA wird T2*2 genommen (Idee DG3AAH) + + IRTT = (T2 + TXDelay) * 2. + Der IRTT wird beim Connect mit der Anzahl der noch zu digipeatenden + Stationen multipliziert. + + Retry = 10 bei DAMA, sonst 20. + + Persistance ist bei Duplex und DAMA 255, ansonsten 255/User. Bei 0 Usern + auch 255. + Es werden nur die zum Knoten connecteten User bercksichtigt. Der + Knoten nimmt also nicht auf Schwarzfahrer auf der gleichen QRG + Rcksicht. + Interlinks werden mit einem separaten Wert behandelt. + + Slottime = TXDelay + (wird von den Porteinstellungen uebernommen) + +(PAC)SAT + zeigt im SYSOP-Mode die eingestellten Parameter an. + + BROADCAST-Parms: + 01:Timer 200 02:Frames 15 03:Diskfree 1000 + +(PAC)SAT + + Beispiel: pac p 1 300 + + Setzt Parameter 1 (PacSatTimer) auf 300. Die Žnderung wird quittiert mit: + + 1: Timer = 300 (0...10000) + + Die Parameter in einzelnen: + + 01: PacSatTimer : 200 + 02: PacSatFrms : 15 + 03: PacMaxMail : 1000 + + Mit PAC P 01 wird eingestellt, in welchen Intervallen der Knoten die + PacSat-Frames sendet, dieser Parameter muá so eingestellt werden, daá der + TNC nicht berl„uft. Mit PAC P 02 wird die Anzahl der Pakete die, + gleichzeitig gesendet werden, eingestellt. Das sollte bei 9k6 20 oder so + sein, (pi * Daumen 5 Frames pro Sekunde), sonst lohnt sich das nicht. Mit + P 03 kann die max. Anzahl der Mail im PACSAT-Server eingestellt werden. + Sind beim S&F mehr als mit PAC P 03 angegebenen Mail im Server, so werden + die „ltesten Mail gel”scht. + + šber die Timersteuerung kann eine optimale Kanalauslastung erreicht + werden, die von vereinzelten Aussendungen auf einem User-Einstieg bis zur + Dauertastung alles erm”glicht, dabei werden zwei Taktiken untersttzt: + + - nur PacSat-Ausg„nge: + Dauertastung, fr den ISM-Bereich. TNN macht dann 24-Stunden am Tag 365 + Tage im Jahr Krach mit Dauertr„ger. Dazu ist auf dem Port, auf dem PacSat + betrieben wird, ein DAMA-Eprom zu verwenden, DAMA fr den PORT aber + ABZUSCHALTEN. Die DAMA-Best„tigung wird benutzt, um die Dauertastung zu + gew„hrleisten. P 02 bestimmt, wieviele Frames auf einmal zum TNC + geschickt werden, der muá immer einen ausreichenden Vorrat haben, damit + er die PTT nicht losl„át, das darf aber auch nicht zu viel sein, sonst + l„uft er ber. Je nach Ringbelastung muá dieser Wert so sein, daá der TNC + auch ohne, daá er Daten kriegt, eine Weile durchh„lt. Bei 19k2 Tokenring + habe ich den Param p 02 auf 14, bei 38k4 kann das weniger sein, bei sehr + stark belastetemTokenring mehr. P 01 gibt an, wie lange gewartet wird, + wenn KEINE DAMA-Best„tigung kommt, dieser Parameter sollte auf 1000 + stehen, ist aber eigentlich unerheblich (solange die Best„tigungen + kommen). + + - Gemischte Ein/Ausg„nge: + Hier muá man entweder DAMA fr den Port einschalten und ein DAMA-Eprom + verwenden oder KEIN DAMA-Eprom verwenden und kein DAMA machen, DAMA-Eprom + und kein DAMA geht NICHT (dann macht der Knoten Dauertastung) + + Dauertastungs-Ausg„nge sind unbedingt vorzuziehen, sie setzen 82MB Daten + mit 9k6 am Tag um, das ist das 10-fache eines normalen 9k6-Einstiegs. + Auáerdem hat jeder User was davon, nicht nur Dauersauger XYZ. Ein + Broadcast-Ausgang mit 1k2 ist Unsinn und sollte nicht betrieben werden. + Es muá aber unbedingt darauf geachtet werden, daá der Sender auch fr + Dauertastung geeignet ist. Der Tnet-Mini ist z.B. im Original nicht + geeignet! + +(PAC)SAT c + Setzt das Rufzeichen des BROADCAST-Server. + +(PO)RT ..... + + Als Port-Befehle sind gltig: + + OFF Port abschalten + ON Port einschalten (nur Linux), + SCC Port auf USCC-Karte einstellen (DOS/GNU) bzw. + keine TNC-Parameter setzen (nur Linux) + Tokenring Port auf Tokenring schalten + Vanessa Port auf Vanessa schalten + EXTern Port auf den extern geladenen Treiber schalten + KISS1..4 Port auf Kiss ohne CRC + RKiss1..4 Port auf Kiss mit RMNC-CRC + SMACK1..4 Port auf Kiss mit SMACK-CRC + MODEM1..3 Port auf Modem (TNC3) + HSBUS Port auf HSBUS (TNC3) + LOOP Port auf Loopback (NICHT bei Linux) + Name Port-Namen vergeben, z.B. Name=User1k2 + MODE Port-Mode setzen, Format: 9600d Baudrate: + 300...4915200 + Flags: + d : Duplex + c : DCD bei 1k2-Modem + r : ext. Takt (rx) + t : ext. Takt (tx) + e : ext. Takt beide (Vanessa) + m : Multibaud-Kopplung (Vanessa, SCC) + z : NRZ statt NRZI + MAXFRAME setzen, adaptives Maxframe mit zusaetzlichem "a" + TXDELAY setzen + DAMA 0, 1-4 Port auf DAMA Master x setzen (max. 4 DAMA-Master) + DAMA S Port auf DAMA-Slave setzen + CTEXT on/off CText senden + SYSOP on/off nach Connect nur SYS m”glich, gilt nur + fr Verbindungen zum CCP, NETROM und + TCPIP gehen weiterhin + MH on/off MH-Liste fhren + + (OF)F : Port ausgeschaltet. + + (ON): Nur bei Linux: Port eingeschaltet. Da im File tnn.ini eine + feste Zuordnung zwischen den Ports und der Hardware sowie + des KISS-Modus eingestellt wird, ist es nicht erforderlich, + die Hardware einzustellen. Der Parameter ON ist daher der + sicherste, aber KISS ist auch immer gltig zum einschalten. + + (TO)kenring : Frames an diesen Port werden auf die Tokenring- + Schnittstelle gelegt. Die Tokenring-Schnittstelle liegt + default auf COM 1, wenn sie nicht in der START.BAT anders + definiert wird. Bei Linux wird die Bezeichnung TOKENRING + nur akzeptiert, wenn auch in tnn.ini der Port als + Tokenring-Port deklariert ist. + + ...(MO)de: Keine Auswirkung auf den Tokenring, aber auf die L2-Timer ! + + (VA)nessa : TNN ist sowohl fr den Tokenring als auch fr den + gleichzeitigen Einsatz von Vanessakarten geeignet. Fr + Frames an diesen Port wird, ber den in der TNN-Soft + implementierten Vanessatreiber, die entsprechende + Vanessakarte ber den Rechnerbus angesprochen und unter + (PO)rts wird der entsprechende Port mit "Vanessa" + gekennzeichnet (Jedoch NUR, wenn auch eine VANESSA + eingebaut ist). Bei Linux wird die Bezeichnung VANESSA nur + akzeptiert, wenn auch in tnn.ini der Port als Vanessa-Port + deklariert ist. + + ...(MO)de: d : + Vollduplex. Bei der Vanessakarte bleibt der TX nach der + letzten Sendung noch fr ca. 1 Minute getastet. Weitere + Frames werden ohne TXDelay gesendet. Beim TNC im Tokenring + ist diese Zeit im Eprom festlegbar. + + ...(MO)de: e : + Externer Takt. + + ...(MO)de: m : + Dual - Speed - Port (Nur mit und auf den beiden Ports der + entsprechenden Vanessakarte m”glich). + + (SCC) : Die BayCom USCC-Karte wird bei der DOS- bzw. GNU-Version + nun intern untersttzt! Bei Linux bedeutet der Parameter + SCC, daá fr diesen Port keine Initialisierung der L1- + Parameter erfolgt (TXD, Persistence, Slottime, etc.). Dies + ist Aufgabe eines Initialisierungsprogramms, das vor TNN + aufgerufen werden muá - alternativ gelten die TNC-Default- + Werte. Der Parameter SCC ist bei Linux nur wirksam, wenn + der Port in tnn.ini entsprechend eingetragen ist. Die Mode- + Werte werden bei Linux ignoriert. + + ...(MO)de: c : + Software DCD fr AFSK-Modems. + + ...(MO)de: e : + Externer Takt. (Fr DF9IC-Modem). + + ...(MO)de: z : + NRZ statt NRZI. (Fr DF9IC-Modem). + + Hinweis: Soll DF9IC-Modem an eine Vanessa angeschlossen werden, so + ben”tigt es NRZ-GAL ! Mit den NRZI-GAL funktioniert der + externe Clock nicht !!! + + (KISS1)..(KISS4) :Die Frames an diesen Port werden ber den in der TNN- + Soft implementierten KISS-Treiber, an die in der START.BAT + definierte COM-Schnittstelle, ber den Rechnerbus geleitet. + Unter (PO)rts wird der entsprechende Port mit "Kiss1 .. + Kiss4" gekennzeichnet und mit (MO)de der Speed sowie das + CRC-Verfahren festgelegt. Bei Linux kann mit dem Parameter + KISS jede Port-Art eingeschaltet werden. Die Zahl fr den + KISS-Port wird bei Linux ignoriert. + + (SMACK1)..(SMACK4) : + KISSLINK mit SMACK CRC. Bei Linux wird die Bezeichnung + SMACK nur akzeptiert, wenn auch in tnn.ini der Port als + SMACK-Port deklariert ist. Die Zahl fr den SMACK-Port wird + bei Linux ignoriert. + + (RKISS1)..(RKISS4) : + KISSLINK mit RMNC-CRC. Bei Linux wird die Bezeichnung + RKISS. nur akzeptiert, wenn auch in tnn.ini der Port als + RKISS-Port deklariert ist. Die Zahl fr den Kiss-Port wird + bei Linux ignoriert. + + Anmerkung: Bei EXTERNEN-Treibern wird der TYP der Hardware direkt + vorgenommen und ist nach dem Starten der Software bereits + unter dem jeweiligen Port sichtbar. + + DAMA 0, 1-4 + + Port auf DAMA-Master x setzen. Bei der Linux-Version + funktioniert DAMA NUR mit Tokenring oder Vanessa ! Dies ist + durch fehlende DCD-Information von anderen Schnittstellen- + typen bedingt. + + (ACHTUNG DAMA-BIT im EPROM der Tokenring-Software brennen!) + + DAMA S + + Port auf DAMA-Slave setzen. + + CTEXT on / off + Ist CTEXT on wird generell der CTEXT.TXT gesendet. Ist noch + zus„tzlich ein CTEXT.n (n=Portnr.) vorhanden, so wird auch + dieser auf den entsprechenden Port gesendet. Ist CTEXT=0, + so werden auch evtl. vorhandene .MSG Files nicht + gesendet. + + SYSOP on / off + Setzt den angegebenen Port auf SYSOP-Mode. Diese Funktion + soll dem Sysop helfen, seine Wartungsarbeiten durchfhren + zu k”nnen. Der Knoten nimmt ohne eine SYSOP-Priviligierung + auf diesem Port keine Kommandos mehr an. Die Umstellung + kann auch w„hrend des Betriebes erfolgen, ohne daá die User + disconnected werden. NetRom und TCPIP gehen weiterhin. + + Semiduplex Links k”nnen auch auf SYSOP gesetzt werden. + Dadurch wird ein unerlaubtes "Einsteigen" auf den Links + verhindert. Der Level 3-4 Link zum Nachbarn bleibt + unberhrt. + + MH on / off Das Fhren der MH-Liste auf den Interlinks kostet + Rechnerzeit und die MH-Liste wird unbersichtlich. Sie wird + gefhrt, um bei mehreren Userzug„ngen mehr Transparenz ber + die Zug„nge zu erhalten UND damit der KNOTEN weiá, auf + welchem Port er einen bestimmen User connecten muá. + + (NA)me : Gibt diesem Port eine spezielle Bezeichnung. Sie darf + maximal 10 Zeichen lang sein und dient der Unterscheidung + der Ports. Wenn z.B. mehrere Userzug„nge oder Baudraten + benutzt werden, ist in der MH-Liste ersichtlich, welches + Call auf welchem Zugang QRV ist. Weiterhin wird der + Portname benutzt, um auf einem bestimmten Port einen + Connect auszusenden, unabh„ngig vom Eintrag in der MH- + Liste. DB0EAM hat einen "70cm_1200" und einen "70cm_9600" + Zugang sowie nun auf 23cm einen "23cm_9600". Die Port-Namen + sind auch so eingestellt. Mit "c DB0XYZ 70cm_9600" kann ein + Connect auf dem 9600_Bit/s Port ausgesendet werden. Wird + kein Port-Name beim Connect eingesetzt, so wird Port 0 + benutzt, ist das Call in der MH-Liste vorhanden mit einem + Eintrag auf einen anderen Port als Port 0, so wird dieser + Port benutzt. + +(PR)OMPT + Ohne Text zeigt die derzeitige Einstellung an: + + Prompt: %c de %d (%t) > + +(PR)OMPT = + šbernimmt den String als Prompt. Enth„lt der eingegebene String die + Zeichen %c, %d, %t, %0, so werden diese im sp„teren Prompt wie folgt + umgewandelt: + + %a In den Alias des Knotens, + %c In das Call des User, + %C In das Call des User mit SSID, + %d In das IDENT des Knotens, + %D In das IDENT des Knotens mit SSID, + %r In ein Return, + %t In die momentane Uhrzeit in HH:MM, + %s In das aktuelle Datum, + %0 Verhindert die Aussendung des Promptes. + + PR =%c de %d (%t) > ergibt: + + DG9FU de DB0EAM (18:30) > + + Es hat sich eingebrgert, im gesamten PR-Netz UTC zu verwenden. Dies + erspart einem auch das l„stige Neusetzen der Sommer-/Winterzeit. + +(RE)AD + Dient zum Lesen eines Files. Der Name muá mit Erweiterung angegeben + werden. z.B.: + + READ CTEXT.TXT oder READ AKTUELL.TXT. + Hier sind auch Pfadangaben erlaubt. Diese sind notwendig, wenn ein Text + vom Laufwerk A: gelesen werden soll und der DOS-Pfad auf ein virtuelles + Laufwerk zeigt. z.B.: + + READ A:\TNN\AKTUELL.TXT. + +(READB)IN + Erlaubt das bin„re Downladen von Files. Das Verfahren ist das gleiche wie + unter LOAD, nur in der Richtung vom Knoten zum Sysop. + +(RES)ET SYSTEM + L„át den Knotenrechner einen Kaltstart ausfhren. Bei Linux geht das nur, + wenn TNN als user root laeuft - sonst wird das Programm einfach beendet. + +(RES)ET + Fhrt einen Reset des Port-TNC bzw. der entsprechenden Vanessakarte aus. + +(RU)NBATCH + Fhrt das angegebene TNB-File aus und gibt die Best„tigung " OK " + zurck. + +(RUNBATCH) + Hiermit lassen sich aus einer TNB weitere TNB aufrufen. Damit ist es + m”glich die TNN176.TNB z. B. in eine PARAM.TNB und eine IPNUMMER.TNB zu + unterteilen. + + EXTERNE PROGRAMME/BEFEHLE fr den + SYSOP: + +(S)TAT + + Nimmt in die Statistik auf. + +(S)TAT - + L”scht aus der Statistik. + +(SETCALL) (externer Befehl) + Die Felder k”nnen mit (SETCALL) ausgefllt oder ge„ndert werden. SETCALL + soll dem SYSOP erm”glichen auf die Datens„tze zugreifen zu k”nnen. + + Zu den Programmen SHOWCALL.EXE, SAVECALL.EXE und SETCALL.EXE ist in dem + Dir SAVECALL jeweils eine Datei mit der Endung .SXK. Werden diese + Sprachdateien in .SPK umbenannt, so werden sie statt der internen Texte + benutzt, was jedoch einen zus„tzlichen HD-Zugriff bedeutet. Sollte jemand + diese Dateien bersetzen, so wrde ich mich ber einen Rcklauf freuen. + +(SETCALL) + + -> SaveCall Version [010696] de DG3AAH <- + SETCALL CALL /N ........................... 30 Zeichen fr den Name + SETCALL CALL /Q ........................... 30 Zeichen des Wohnortes + SETCALL CALL /L ...... 6 Zeichen des World-Locators + SETCALL CALL /D ....... 7 Zeichen fr Eingabe des DOK + SETCALL CALL /V ......... 9 Zeichen QRV auf ... Digi + SETCALL CALL /M ................. 20 Zeichen Mybbs der Mailbox + SETCALL CALL /T ..... . . . . . . . ..... 40 Zeichen fr freien Text + ( ein * als Text l”scht diesen Eintrag ) + + SETCALL CALL /* : l”scht den Inhalt aller Eintrags fr Call. + SETCALL CALL /B : blockiert CALL fr ShowCall. + SETCALL CALL /F : gibt Call fr ShowCall frei. + SETCALL CALL : gibt Infos ber Call aus, auch wenn blockiert. + ( ein B als Call gibt alle blockierten Calls aus ) + + Auf der Diskette ist jeweils ein Grundbestand von Calls vorhanden (der + von DB0EAM). Updates davon gibt es nur gegen Zusendung des eigenen + Datensatzes und wenn sich jemand findet der eine SORTIERROUTINE sowie die + Erzeugung der entsprechenden CALL.IDX dafr schreibt. + +(SH)owSYS (externer Befehl) + SHOW_SYS zeigt die Eintr„ge in der Datei SYSOP.PRO in einer + bersichtlichen Form an. + +(SH)owSYS /l + SHOW_SYS zeigt die Eintr„ge in der Datei SYSOP.PRO in einer + bersichtlichen Form an und l”scht dabei alle Privilegierungs-Eintr„ge. + +(SP)arm oder besser Save Parameter + Save Parameter erstellt ein File PARAMS.TNB, das alle derzeit + eingestellten Parameter beinhaltet. PARMS.TNB kann, umkopiert nach + TNN179.TNB, zum Einstellen der Parameter von TNN beim Neustart verwendet + werden. Als Best„tigung kommt "PARMS.TNB saved ..." + +(STAR)T + Startet das angegebene Programm. Der Programmname muá vollst„ndig + angegeben werden, z.B.: Start TNNDOS.EXE. Befindet sich das Programm + nicht im aktuellen Pfad, so muá dieser selbstverst„ndlich mit angegeben + werden. Der Ablauf des Startvorganges wird nun nicht mehr auf dem + Bildschirm angezeigt, sondern in eine Datei STARTUP.LOG geschrieben. + +(STAR)T funktioniert NICHT bei den DPMI-Versionen ! + +(STARTCNT) (externer Befehl) + eine sehr hilfreiches Programm. + + Wer h„ufiger neue Testversionen an seinem Digi einsetzt oder mit den + TNN176.TNB Konfigurationsdateien spielt, der sollte unbedingt die Utility + "STARTCNT.EXE" verwenden! Dieses Programmm wird zusammen mit den TNN-Tools + verteilt und stammt von Andreas, DB7KG. STARTCNT ist ein kleines EXE- + Programm, welches einen Z„hler bei jedem Aufruf herunterz„hlt. Solange der + Z„hler nicht null ist, wird immer ein ERRORLEVEL von 1 zurckgegeben. Ist + der Z„hler abgelaufen, dann ist der ERRORLEVEL 0. Damit lassen sich dann + mittels einer Batch-Datei sehr bequem zwei verschiedene Versionen starten. + Damit STARTCNT auch bei Stromausfall funktioniert, wird der Z„hler + natrlich in einer Datei gespeichert. + + Wenn man sich als Sysop in den Knoten eingelogged hat, dann kann man z.B. + mit "DOS STARTCNT 5" diesen Z„hler auf 5 setzen. Nun darf der Knoten 5mal + abstrzen / resetten oder was auch immer, bis wieder die alte (stabile) + Software gestartet wird. + + STARTCNT + stellt die jeweilige Anzahl an Starts ein (Durchl„ufe der START.BAT). Die + Anzahl wird um 1 verringert, wenn die STARTCNT.EXE ohne + aufgerufen wird. + + Die folgenden Zeilen mssen dann jedoch in die START.BAT aufgenommen werden. + + STARTCNT + IF ERRORLEVEL==1 GOTO OKGNU32 + ECHO Starte die TNN_ALT.EXE + + REM !!!!!!!!!!!!!!! ALTE SOFT HIER STARTEN (TNN_ALT.EXE) !!!!!!!!!!!!!!!!!! + COPY TNN179.DOS TNN179.TNB + TNN_ALT.exe + REM !!!!!!!!!!!!!!! ALTE SOFT HIER STARTEN (TNN_ALT.EXE) !!!!!!!!!!!!!!!!!! + + GOTO ENDE + :OKGNU32 + + ECHO Starte die TNN_NEU.EXE + + REM !!!!!!!!!!!!!!! HIER WIRD DIE NEUE SOFTWARE GESTARTET !!!!!!!!!!!!!!!! + COPY TNN179.DPI TNN179.TNB + TNN_NEU.exe + REM !!!!!!!!!!!!!!! HIER WIRD DIE NEUE SOFTWARE GESTARTET !!!!!!!!!!!!!!!! + + HILFSPROGRAMME fr den SYSOP zu + Hause: + +(SUS)PEND + + Beschr„nkt das Rufzeichen auf Port auf eine Anzahl von + . + + Beispiele: + + DB2OS soll auf dem Knoten generell nur 2 Verbindungen , egal auf welchem + Port, aufbauen k”nnen. Dann wird unter einfach der fiktive Port + 255 angegeben. + + SUS + 255 DB2OS 2 + + Soll er nun vom USER-PORT 0 ganz ausgeschlossen werden, so ist + einzugeben: + + SUS + 0 DB2OS + + Ein Level-2 Ausschluá erfolgt mit: + + SUS + 254 DB2OS + + Der Connect des Knotens ist erstmal m”glich. Jedoch nach dem ersten I- + Frame des User bekommt er das File SUSPEND.TXT zugesandt und danach einen + Disconnect. + + Hinweis: + Soll eine Connect-Beschraenkung fuer ALLE User eingerichtet werden, so + ist das Kommando "PORT x MAXCON=x" zu verwenden. + +(SUS)PEND - + Gibt dem Rufzeichen auf Port wieder das Benutzen des + Knotens frei. + + Ein PR-User hat sich beim BAPT darber beklagt, daá ihm der Betreiber + eines Digipeater nur noch jeweils einen Connect mit dem Digi zur selben + Zeit zur Verfgung stellt. Da dieses Problem schon h„ufiger fr + Diskussionen in PR gesorgt hat, gebe ich hiermit das Schreiben des BAPT + an den Digi-Betreiber im vollen Wortlaut wieder: + + Aktenzeichen 123-8 B 3581-29 vom 28.01.1997 + + Begrenzung auf maximal einen gleichzeitigen Connect bei dem Digipeater DB0xxx + + Sehr geehrter Herr xxx, + + wie mit Ihnen am 27.01.1997 telefonisch besprochen, teilen wir Ihnen hiermit + unsere grunds„tzlichen Aussagen mit, die von uns bezglich einer gegen Sie + vorgebrachten Beschwerde wegen der o. g. Beschr„nkung bei Ihrem Digipeater + gegenber dem Beschwerdefhrer gemacht wurden. + Wir betrachten die o. g. Begrenzung nicht als Ausschluss im Sinne der Anlage + 1, Punkt 2.4.2.7 der DV-AFuG. Ein Ausschluss auf Grund eines entsprechenden + Missbrauches einer Relaisfunkstelle liegt nicht vor, vielmehr handelt es sich + hier um Begrenzungen aus betrieblichen Grnden. Wir halten diese Begrenzung + fr eine, zum Beispiel aus Kapazit„tsgrnden, sinnvolle Massnahme, um + m”glichst vielen Funkamateuren die Gelegenheit zu geben, mit diesem + Digipeater zu arbeiten. Es muá Sache des Betreibers eines Digipeaters + bleiben, nach seiner Einsch„tzung die von ihm zur Verfgung gestellte + technische Einrichtung hinsichtlich Quantit„t den Nutzern anzubieten. + Ausserdem sehen wir keine rechtliche Grundlage, auf die sich im + Amateurfunkdienst ein Anspruch auf mehrere gleichzeitige Verbindungen ber + eine Relaisfunkstelle begrnden l„sst. Fr weitere Fragen stehen wir Ihnen + gerne zur Verfgung. + + Mit freundlichen Grssen + + Im Auftrag + + gez. Jeromin (fr Link) + +(SY)SOP + Gibt eine 5er Zahlengruppe aus fr das Einloggen des Sysop. + + PASSWORT-Eingaben: + Die Paáworteingabe fr den User wurde erweitert, so daá auch Paáworte wie + bei BAYCOM-BOX erlaubt sind. Die alten 5-stelligen Antworten gehen auch. + Der Trick besteht darin, das eigentliche Paáwort in einem langen String + Datenmll zu verstecken! + + BAYCOM-PASSWORT: + Das wichtigste zuerst, die Methode ist kompatibel zur alten, man kann + ohne weiteres einfach die 5 Antwortbuchstaben senden. Zus„tzlich ist es + aber m”glich, die Antwort in einer Zufallszeichenkette zu verstecken. Ist + die L”sung z.B. 12345, werden folgende Antworten auch als korrektes + Password akzeptiert: + + 54321532412345221134254235244242415526 + ----- + + 12345 + ----- + + 12131415234132145132412345 + ----- + + Da dem Lauscher nicht bekannt ist, wo die L”sung ist, kann er sich das + Password nicht zusammenbasteln. Es empfehlen sich also Paáw”rter mit + m”glichst vielen verschiedenen Zeichen, um die Verschleierung zu erh”hen. + +(SYSH)elp (externer Befehl) + Ist ein externer Befehl fr eine neue Hilfefunktion. Funktion wie bei + (H)elp nur wird auf die OHS.TXT Online-Hilfe-Sysop zugegriffen. + +(SYST)ext Text (externer Befehl) + Systext bietet nun die M”glichkeit, in die Datei SYSOP.PRO eine Zeile + Text einzufgen. Damit k”nnen zum Beispiel Parameter„nderungen fr die + "anderen" Sysop dokumentiert werden. Damit ist nun auch eine gewisse + Historie m”glich. Die Datei SYSOP.PRO wird bersichtlicher, wenn die + Eintr„ge anders ausgegeben werden. Auch Neustarts (z.Z. mit b-log.exe + dokumentiert) sollen noch in der SYSOP.PRO aufgenommen werden. + +(TE)ST + Gibt einen 0/1 Wechsel auf dem angegebenen Port von 4 KByte L„nge aus, + fr Abgleicharbeiten z.B. am Modem. Die Testfunktion kann nur noch der + Sysop ausl”sen. Ruft der User die Testfunktion auf, so bekommt er ein + "Port disabled" zurck. + +(TI)ME + Zeigt Datum und Uhrzeit des Knotens an. + + Einstellen von Uhrzeit und Datum ist nur ber die DOS-Befehle m”glich! + + Zeit mit: DOS TIME HH:MM + Datum mit: DOS DATE TT.MM.JJ + oder mit: DOS DATE TT.MM.JJJJ + + Doch Vorsicht! Nur "DOS TIME" zeigt die aktuelle Uhrzeit auf dem Monitor + des Knotens an und erwartet die neue Uhrzeit per Tastatur. Der Knoten + steht dann bis zum RESET. Dieser erfolgt automatisch nach ca. 2 Minuten + durch den Software-Watchdog von TNN. + + Ein wenig Mitdenken geh”rt auch dazu. + +(TOP) (externer Befehl) + Ist ein externer Befehl, der die MHEARD.TAB in besser lesbarer Form + anzeigt. In der CONFIG.TOP mssen allerdings die Port - Namen + eingestellt werden. Da nun auch die Level 3 Verbindungen gefhrt werden, + sollte man alle Port - Namen dort eintragen. + + # Configfile fr TOP.EXE. + # Alle Angaben die nicht gelesen werden sollen mssen eine # am Zeilenanfang + haben. + # + # Einstieg + P0 = 70cm_1200 + # Einstieg + P1 = 70cm_9600 + # Einstieg + P2 = 23cm_9600 + # Link DB0GOE + P3 = Goettingen + # ... bis + p16 = ??? + # Ende des Files + +(TR)ace + Dieser Befehl dient zum erkennen und finden von Fehlern. Es stehen + folgende Module zur Verfgung. Dazu ist der Level mit einem Wert zwischen + 0 (Aus) und 9 (Alles) einstellbar. Der Trace wird, wenn mehr im Monitor + zu senden sind als nach Parameter NoAckBuf eingestellt ist, nicht + abgebrochen sondern nur unterbrochen. D.h. es k”nnen, wenn man zu viel + monitoren will, Lcken entstehen. + + Beispiel: (TR)ace 9 (ALLE anzeigen, wirklich alles) + + Die Level (Anhaltswerte) + 9 = reine Information + 7 = wichtige Information + 5 = wichtiges Ereignis + 3 = nicht kritischer Fehler + 1 = kritischer (fataler) Fehler + 0 = aus + + Der Monitor erlaubt auch ONLINE ein Call oder Port zu monitoren, ohne es + zu erst in ein File im Knoten zu schreiben. Die Syntax ist die gleiche + wie bei MUSIC. Da es sich hier bereits um einen Monitoraufruf + handelt, ist das "m" fr Monitor natrlich fehl am Platz. + + Beispiel: (TR)ace USICH 9 +DG0XX + +(TEL)NET Server + + Neu: + ~~~~ + Der Telnet-Server funktioniert nur unter LINUX und WIN32-Systeme. + Zu beachten wäre, das der TCP-Port (Standart 23) im jeweiligen System + freigeschaltet (Firewall) sein muss! + + Konfiguration: + ~~~~~~~~~~~~~~ + (Telnet-Port definieren in der TNN.INI) + + device telnet + kisstype 22 + port 0 + + TNN-Console: + ~~~~~~~~~~~~ + (Telnet-Port öffnen) + + PO 0 ON + + TCP-Port ändern: + ~~~~~~~~~~~~~~~~ + + TEL P 23 + + Mein-LOGlevel ändern: + ~~~~~~~~~~~~~~~~~~~~~ + + TEL L 0 + + Damit ist die Konfiguration abgeschlossen. + Port 0 ist nur ein Beispiel! Der Telnet-Server kann auch auf andere Ports + definiert werden! Wenn es Probleme beim Telnet-Server geben sollte, ist es + hilfreich LOGlevel einzuschlaten. + TEL L 1 + Es werden Informationen in die Datei "telnet.log" geschrieben + (Für mich sehr hilfreich) + Um den Telnet-Server zu testen, einfach im jeweiligen System: + telnet localhost 23 + ausfuhren. Bekommt man kein Zugriff auf den Telnet-Server, prüfen ob alle + Konfigurationen korrekt eingetragen sind, auch an die Firewall denken! + + Weiter Infos: + ~~~~~~~~~~~~~ + Den Login-Text kann man erweitern, in dem man eine Datei "login.txt" + erstellt, mit dem jeweiligem Inhalt, Dieser Inhalt wird dann bei jedem + Connect mit ausgegeben. Ein Telnet User kann Maximal 9 Connects aufbauen! + Die SSID wird automatisch wergeben. Es wird auch drauf geachtet, ob ein + User in der SUSPEND-Liste (Rufzeichen spreren) Steht! + +(ALT) X + Bricht das Programm ab und geht auf die DOS-Ebene zurck. + Bei Linux geht das nur mit QUIT. + +(ESC) C + Connect von der Tastatur als HOST in den Knoten + +(ESC) D + Disconnect + +(ESC) @E1 + ™ffnet ein neues File. Wenn das File bereits existiert, wird + es nicht gel”scht, sondern die Ausgaben werden ans Ende + angeh„ngt. Monitorausgaben werden auf ein File (YYMMDDHH.PRO) + umgeleitet. + +(ESC) @E0 + Schaltet die Ausgabe ab und schlieát das File. + +(ESC) I [P] + Einstellung des globalen HOST Call. Dieses kann auch mit dem + Befehl "C" connected werden. + +(ESC) K + Gibt Datum und Uhrzeit aus. + +(ESC) K0 + Monitor wird ohne Datum und Uhrzeit dargestellt. + +(ESC) K2 + Monitor wird mit Datum und Uhrzeit dargestellt. + +(ESC) Logout + Verlassen der Konsole und verschlieáen. + +(ESC) L + Zeigt den Status der Kan„le an. + +(ESC) M + Zeigt die derzeitige Einstellung an. (Bedeutung der Parameter + siehe unten) + + ACHTUNG! Bei den Monitorbefehlen ist, bei stark belasteten + Knotenrechnern, Vorsicht geboten. Da der Rechner dann um + einiges langsamer wird, bekommt man das Monitoren nur schwer + wieder ausgeschaltet, da die Tastatur kaum noch abgefragt + wird. + +(ESC) MN + Monitor aus. (Je mehr der Monitor anzuzeigen hat, desto + langsamer wird der Knoten. Also nach Gebrauch immer den + Monitor wieder auf "AUS" schalten ! + +(ESC) MUSIC H/F +/- + Monitoren von: + U = Unprotokollierten Paketen, + I = Info Paketen, + S = Kontroll Paketen, + C = Monitor an auch bei bestehendem Connect, + H = HEADER, bei I-Frames nur den Header anzeigen, der + Infoteil der Frames wird unterdrckt, + F = FULL, I-Frames mit Infoinhalt anzeigen, es werden die + kompletten Frames gemonitort, + = Nur der angegebene Port wird gemonitort, + + = Nur diese Call (bis zu 8) monitoren, + - = Diese Call im Monitor unterdrcken. + + kann mit SSID angegeben werden. + Unter sind auch Eingaben wie QST und LSTAT m”glich. + +(ESC) P + Zeigt das aktuelle Paáwort an. Das funktioniert natrlich nur + an der Console ! + +(ESC) P1234567890 usw. bis zu 80 Zeichen. + Setzt das Paáwort auf "1234567890 usw. bis zu 80 Zeichen". + +(ESC) R0 + Es erfolgt kein Hinweis auf Token-Recovery. + +(ESC) R1 + Bei jedem Token-Recovery wird auf dem Bildschirm der Text + *** Token-Recovery (1) Wed Jan 19 13:45:10 1994 *** + angezeigt. Die Ziffer gibt an, wieviele Recovery nacheinander + aufgetreten sind, sowie Datum und Uhrzeit. Dieses ist die + default Einstellung. + +(ESC) S + Zeigt den Aktuellen Kanal an. + +(ESC) Sn + Schaltet zum Kanal n um. (Gltige Kan„le sind 1 - 30) + +(ESC) T + Zeigt die momentan auf dem Tokenring eingestellte Baudrate. + Dieser Befehl gilt nicht fr die Linux-Version. + +(ESC) T 9600 / 19200 / 38400 + Stellt die entsprechende Baudrate auf dem Tokenring ein. + +(ESC) T 57600 / 115200 + Stellt die entsprechende Baudrate auf dem Tokenring ein, + fr diese Baudraten ist jedoch ein FIFO-Baustein (16550) + erforderlich. + +(ESC) T ? + Gibt eine Hilfe aus. + +(ESC) Y0 + Kein Connect zum HOST m”glich (default). + +(ESC) Yn + Verbindungen zum HOST sind auf n Hostkan„len freigegeben (n = + 1 bis 30). Der Connect zum HOST ist mit C m”glich OHNE den + Zusatz eines , sowie mit C , wobei fr das + globale Host-Call gilt. + + (########.TNB) FILES + ....ein Leckerbissen + + Ein ganz allt„gliches Problem: immer nachts um 03:00 passiert angeblich + Frchterliches am Knoten, wenn der OM AA0BB erscheint. Man máte mal am + Knoten mitmonitoren. Oder man m”chte jede Nacht um 23:00 die Statistik + auf Disk schreiben. Oder von 16:00 bis 24:00 sollen andere Parameter auf + dem Einstieg genommen werden. Alles Beispiele fr den Einsatz von TNN- + Batch Files. + + Die Sache ist ganz einfach. Es gibt zwei Sorten von Batchfiles, die sich + durch den Namen unterscheiden: YYMMDDHH.TNB und YYMMWXHH.TNB. Dabei ist + YY das Jahr, MM der Monat, DD der Tag, HH die Stunde und X der Wochentag, + an dem das File gestartet werden soll. Und damit nicht fr jede Aktion + ein extra File gemacht werden muá, darf "#" als Platzhalter fr eine + Ziffer genommen werden. + + Verzeichnis: + Die .TNB Dateien geh”ren in das Verzeichnis, welches in der TNN176.CFG + unter Workpath angegeben wurde. + + Beispiele: + + TNN179.TNB Wird NUR beim Neustart des Programmes ausgefhrt. + ########.TNB Wird beim Neustart sowie zur vollen Stunde ausgefhrt. + ######23.TNB Startet jeden Tag um 23:00 Uhr. + ####0100.TNB Startet immer am 1. jedes Monats um 00:00 Uhr. + 94040100.TNB Startet am 01-APR-94 um 00:00 Uhr. + ####W116.TNB Startet immer Montags um 16:00 Uhr (Sonntag ist Tag 0). + 94##W011.TNB Startet an jedem Sonntag im Jahre 1994 um 11:00 Uhr. + + Der Aufbau der Files ist simpel: es steht alles so drin, wie man es auch + an der Console eintippen wrde. Mit einer einzigen Ausnahme: wenn ein + Batch abl„uft, ist automatisch ein Login passiert, und nach Ablauf des + Files ist der alte Login Status wieder vorhanden. + + Damit nun nicht nur der Bildschirm am Knoten gefllt wird, sondern auch + was fr die Nachwelt bleibt, ist eine neuer Befehl fr die Console + dazugekommen: + + Damit nun das leichter in eine .TNB Datei geschrieben werden kann, + ist hier ersatzweise auch ein # an der ersten Stelle zul„ssig. + + Um eine monatliche Statistik zu erzeugen, ist folgendes File n”tig: + + ####0100.TNB + ============ + ; Dieses File startet am 1. des Monats um 0:00 Uhr. + esc @e1 ; Umlenken der Ausgabe in ein File. + Stat ; Auslesen der Statistik. + MH 500 + ; Auslesen der MH Liste. + Esc @e0 ; Umlenken ausschalten. + Clear ; Statistik l”schen. + MH - ; USER-Statistik auf "0" Stellen. + L3MH - ; L3-Statistik loeschen + + Ab dem ";" sind Kommentare erlaubt. + + Genauso sind auch DOS Kommandos m”glich. Bei der Linux-Version sind SHELL + Kommandos zwar zul„ssig, aber sie werden meist nicht ausgefhrt. Der + Grund hierfr: SHELL Kommandos werden im Hintergrund ausgefhrt als + eigener Prozeá (der normale Knotenbetrieb l„uft also weiter). Wird + w„hrend eines laufenden SHELL Kommandos ein neuer Befehl eingegeben (das + ist der n„chste Befehl im TNB-File), wird das laufende Kommando + abgebrochen und der neue Befehl wird ignoriert. + +(SPE)ECH + Zeigt welche Sprachen im System vorhanden sind. + + TNN-Console + ~~~~~~~~~~~ + (Sprache einstellen) + + SPE DEU + für Sprache Deutsch (Neu) + + SPE ENG + für Sprache Englisch (Standart) + +(IPC)ONV + IP-CONVERS ist ein weiteres TCPIP-Feature nach TELNET und HTTPD. + Es gibt 2 moeglichkeiten eine IP-Anbindung z.B an ein SAUPP-Convers + an zu binden. + + TNN.INI + ~~~~~~~ + device ipconv + kisstype 24 + port 5 (port kann angepasst werden!) + + Converslink eintragen: + (im Conversmodus) + + Syntax: /l + Name IP-Adresse TCP-Port + (Beispiel: /l + Wuppertal 217.172.188.168 3600) + + !!NEU!! ACHTUNG *** ACHTUNG *** ACHTUNG *** ACHTUNG !!NEU!! + + Neuer Syntax: + ~~~~~~~~~~~~~ + /l + HOSTNAME AX25-CALL L2PORT VIACALL + + Beispiele: + ~~~~~~~~~~ + (L2) /l + Siegen dno572-6 0 DNO572 + (L4) /l + Siegen dno572-6 + (TCPIP) /l + Wuppertal 217.172.188.168 3600 + /l + Wuppertal Wupper 5 + (AX25-CALL "Wupper" muss unter IPC definiert sein) + + Direckte Anbindung per IP: + ~~~~~~~~~~~~~~~~~~~~~~~~~~ + Eine Anbindung z.B zum Saupp per AX25-kernel ist nun Vergangenheit. + Eine Direkt IP-Anbindung zum Saupp macht es moeglich. Die Einrichtung + ist Kinderleicht. Im Saupp selbst muss man nix extra Konfigurieren, + lediglich muss IP aktiv sein. Auf der TNN-Console muss eine IPCONV-Route + erstellt werden. Damit ist die Kopplung fertig!!! + + Nun stellt sich jeder die frage wie komme ich nun in den Saupp-Convers? + Ganz einfach in dem man angegebenen Namen mit dem Befehl Connect benutzt. + Ich nehme dazu mal als Beispiel "Wuppertal" Im Knoten einfach "C Wupper" + und schon gelangt man in den Saupp-Convers. + + IPCONV-Route eintragen: + ~~~~~~~~~~~~~~~~~~~~~~~ + Syntax: IPC R + Name IP_Adresse TCP-Port + (Beispiel: IPC R + Wupper 217.172.188.168 3600) + + Der Name darf nur 6 Zeichen enthalten !!! + Auch HOSTNAMEN (dig531.dyndns.org) werden unterstuetzt !!! + diff --git a/contrib/onlhelp/ohu.txt b/contrib/onlhelp/ohu.txt new file mode 100755 index 0000000..7356ab7 --- /dev/null +++ b/contrib/onlhelp/ohu.txt @@ -0,0 +1,2300 @@ +TNN-Doku-Version 1.79mh03 vom 17. Jul 2005 by CB-PR Team Dessau +(AX)IPR + Zeigt die Interne AX25IP-Routing-Tabelle an. + +(A)KTUELL (externer Befehl) + Gibt aktuelle Informationen aus. + +(BE)ACON + Zeigt die eingestellten Bakenparameter und Bakentexte an. + +(C)ONNECT + Connect zum HOST-Interface wenn dieses mit Y 1 freigegeben ist. Ist + Y auf 0 gesetzt, so wird am Terminal ein CONNECT REQUEST fm angezeigt. + +(C)ONNECT + Mit dem Connect-Befehl wird eine Verbindung zu einem anderen Knoten oder + einem anderen Benutzer aufgebaut. Die Eingabe + + CONNECT DB0FD + + oder auch abgekrzt und klein geschrieben + + c db0fd + + bewirkt, daá erst in der NODES-Liste (Nodes und Flexnet-Destinations) + nach dem Call DB0FD abgesucht wird. Handelt es sich um ein Call, das in + der NODES-Liste eingetragen ist, so wird die Meldung: + + Interlink setup (via call) ... + + ausgegeben und in Klammern wird angezeigt zu welchem direkten Nachbarn + der Connect gesendet wird. + + Wird dieses Call local gefhrt, so wird ein: + + Link setup (Portname)... + + Ist kein Eintrag vorhanden, so wird die MH-Liste durchsucht. Ist dort ein + Eintrag vorhanden, so wird der Connect auf dem entsprechenden Port + ausgesendet. Ist auch dort kein Eintrag vorhanden, so bleibt nur noch + eine Aussendung des Connect auf dem vorgegebenen Downport (siehe + Parameter) brig. Es wird dann immer die Meldung: + + Downlink setup (Portname) + + ausgegeben. An den Meldungen ist bereits erkennbar, und somit auch durch + Router auswertbar, ob eine Verbindung zu einem TheNet - bzw. TheNetNode- + Knoten berhaupt aufgebaut werden kann. + + Steht Downport auf einem nicht benutzten Port, um so unerreichbare Ziele + nicht zig mal auf dem Port 0 aussenden zu mssen, so wird angezeigt: + +(CONV)ers + Schaltet um in den Convers-Modus. + + Der Convers-Modus bei TheNetNode + + Seit Conversd v2.14 besteht die M”glichkeit, Convers-Knoten untereinander + zuvernetzen, d.h. ein Convers-User muá sich nicht ber einen langen + Digipeaterweg bis zu dem Convers-Knoten connecten, auf dem sich seine + gewnschten Gespr„chspartner befinden, sondern es gengt, wenn ein + Connect zum n„chsten Convers-Knoten aufgebaut wird, der das Conversd- + Protokoll untersttzt. Leider neigte diese Version zu Schleifen beim + Verbindungsaufbau. + + Seit TheNetNode V1.50 (PC) ist ein wesentlich verbesserter Convers-Modus + implementiert worden. Es handelt sich dabei um Conversd PingPong-Release + 3.12, das von DK5SG entwickelt, von DC6IQ weiter gefhrt und von DL1XAO + in TheNetNode eingebaut wurde. + + Mit der v3.12 (pp-conversd) funktioniert die Vernetzung nun ohne + Probleme. Auáerdem wird eine Menge zus„tzlicher Komfort geboten, wie z.B. + Personaltexte, Kanalthemen, Kanaloptionen und Umlautwandler. + + Mit der v3.13a (pp-conversd) (Deutsch) kommen noch Passwortschutz und + Nickname funktion dazu. + + Auch „ltere Conversd k”nnen angebunden werden, nur verstehen diese nicht + alle Kommandos bzw. nicht vollst„ndig, sie wirken praktisch als Filter + fr die neuen Funktionen. + + Zwischen den Convers-Hosts werden alle Texte, welche die verschiedenen + User schreiben, nicht mehr getrennt fr jeden Benutzer einzeln, sondern + nur noch einmal bertragen. Dies entlastet die Linkstrecken sprbar, da + z.B. 10 Benutzern ein und dasselbe Packet ber die Interlinks nicht 10mal + bertragen werden muá, sondern nur noch 1mal! + + Weiterhin ist der Convers-Einzugsbereich natrlich wesentlich gr”áer + geworden, und man kann davon ausgehen, daá man nun h„ufiger einen + Gespr„chspartner im Convers findet. + + Die Convers-Befehle stehen unter -(CONV)ERS - intern - . + +(CONV)ers + Schaltet um in den Convers-Modus auf Kanal . + +(CONV)ers C(stat) + Zeigt die bestehenden Verbindungen, Laufzeiten, Datenmengen usw. an. + + Host State Quality Revision Since NextTry Tries Queue RX TX + db0goe Connected 1s/1s pp-3.06t 17:55 0 136K 267K + (DB0GOE on port 6) + db0ii Connected 10s/7s pp-3.06t 7:07 0 1K 48K + (DB0II on port 9 via DB0BID) + db0kh Connected 1s/1s pp-3.06t 6:13 0 17K 65K + (DB0KH on port 11) + db0gso Disc./locked --- 9:22 10:22 0 + (DB0GSO on port 9 via DB0BID) + 1 loops detected. + dg9fu Disconnected --- 18:47 + (trusted host) + DB0KV (dw-0.84k) 2m DB0NOE (dw-0.82b) 5m db0acc (pp-3.12f) 25s + db0ais (pp-3.12f) 3m db0ber (pp-3.06t) 3m db0bhv (pp-2.93t) 1m + db0bid (pp-3.06t) 9s db0bro (pp-3.06t) 12s db0cl (pp-2.93t) 2m + + Wird nun ein Convers-LOOP bemerkt, so wird der ermittelte Link fr eine + Stunde aus dem Verkehr gezogen. Trotzdem sollten LOOP vermieden werden. + Die Anzeige der Eintr„ge wie (DB0GOE on port 6) sind erst nach der SYSOP- + Priviligierung sichtbar. + +(CONV)ers O(nline) [q ; l ; a] + Zeigt die Benutzer das Convers an. Zus„tzliche Optionen wie [q ; l ; a], + sind m”glich. + +(CONV)ers - intern - + + Im Convers-Modus stehen folgende Kommandos zur Verfgung (die Kommandos + k”nnen durch die Verwendung der Groábuchstaben abgekrzt werden): + + /Away [Text] Markiert Dich als abwesend. + /ALl [Text] Text an alle User Deines Kanals. + /Beep Beep-Modus an/aus. + /Channel [n] Verbindet dich zus„tzlich mit dem Kanal n. + /CHARacter Setzt verschiedene Zeichenwandlungen. + /Destinations Listet erreichbare ping-pong Hosts. + /Help [Kommando] Gibt Hilfe-Informationen. + /EXClusiv User Text Sendet Text an alle auf Deinem Kanal auáer User. + /Filter [Calls] Setzt Calls, deren Texte gefiltert werden sollen. + /Invite User L„dt User auf Deinen Kanal ein. + /Links [args] Listet oder setzt (Sysop) conversd-Partner. + /LISt Listet alle Kan„le und ihre Themen. + /LEave [Kanal] Verl„át Kanal oder derzeitigen Kanal. + /Msg User Text Sendet Text an User oder. + /Msg #Kanal Text Sendet Text an den angegebenen Kanal. + /ME [Text] Sendet einen Aktionstext. + /MOde [Kanal] Optionen Setzt Kanaloptionen. + /NOtify [Calls] Setzt Calls, deren Erscheinen gemeldet werden soll. + /PERSonal [Text] Setzt pers”nliche Beschreibung. + /PASSwort Setzt persoenliches Passwort + /NIckname [Name] Setzt Nickname + /SYSop Macht dich zum convers Sysop + /PRompt abcd Prompt setzen (a=Query; b=Normal; c=Ctrl-g; d=Ctrl-h). + /Quit Convers verlassen. + /QUEry [User] Startet/beendet private Konversation. + /Topic [#Kanal] [Text] Setzt Thema des Kanals. Thema=@ entfernt Thema. + /UPtime Wie lange l„uft dieses conversd berhaupt schon ? + /Verbose Laber-Modus ein/aus. + + /VERSion Zeigt Info zu dieser Version. + /SYSInfo Conversd host information + /Who [*; A; L; Q] Zeigt User und Ihre Kan„le + (*=eigner; A=abwesend; L=lang; Q=kurz). + /WIdth [Wert] Setzt/zeigt Zeilenbreite. + + Die Erkl„rungen im einzelnen: + + /ALL + Wenn Du im /query Modus bist, wird Text mit vorangestelltem /all + behandelt, als wrdest Du ohne /query arbeiten. + + /AWAY + /away setzt den Abwesendheitstext, den die anderen lesen k”nnen. Beim + Aufruf ohne Argument wird der Text gel”scht und man gilt wieder als + anwesend. + + /BEEP + Hiermit wird das Klingelzeichen (CTRL-G), welches vor jeder Mitteilung + gesendet werden kann, ein- oder ausgeschaltet. Dieses Kommando ist + eigentlich eine Untermenge des /prompt Befehls, siehe dort. + + /CHAN + Verbindet Dich zus„tzlich mit dem gewnschten Kanal. Im Gegensatz zu + „lteren Conversd-Implementationen verbleibt man auch noch im vorherigen + Kanal, denn es wird eine Mehrfach-Kanal-Verbindung untersttzt. Um einen + Kanal zu verlassen, muát Du "/leave" verwenden. Ohne Angabe eines Kanals + wird die Info ausgegeben, auf welchen Kan„len Du Dich befindest. + + /CHAR + Mit diesem Befehl kannst Du dem Convers mitteilen, welche + Zeichensatzwandlung Du haben m”chtest. Die Syntax ist: /char [In-Typ + [Out-Typ]] wenn Du z.B. mit einem Atari ST arbeitest, k”nntest Du "/char + pc atari" eingeben. Wenn Du einen PC benutzt und Umlaute im TeX-Stil + schreiben m”chtest, gebe "/char tex pc" ein. "/char ?" listet die + m”glichen Einstellungen. + + Die Einstellung wird mit "/pers" gespeichert (siehe dort). + + Der Dank fr diese nette Funktion geht an Tommy, + (Internet mail) (AmPR-Net mail). Vorschl„ge + sollten an ihn weitergeleitet werden. + + M”gliche Einstellungen mit /char: + iso-8859-1, ansi, 8bit + dumb, ascii, none, us + tex + ibm7bit, 7bit, commodore, c64, digicom + roman8 + ibmpc, pc, at, xt + atari, + binary, image + + /DEST + Alle Pingpong-Hosts, die miteinander verbunden sind, werden aufgelistet. + Die Zahlen zeigen die Antwortzeiten in Sekunden. + + /DEST + Fragt den Weg zum ab und zeigt dabei die šbertragungszeiten ab. + + /EXCL + Dieses Kommando ist das Gegenteil des /MSG-Befehls. Hiermit sendest Du + Text an alle User dieses Kanals auáer dem einen als ersten Parameter + angegebenen. Da der Text intern als privater Text an die anderen + verschickt wird, werden die Links etwas mehr belastet + + /FILT + Wenn Du die Texte bestimmter User nicht lesen m”chtest, so kannst Du sie + hiermit in eine Liste einfgen. Alle Texte werden dann ausgefiltert, bei + pers”nlichen Texten ("/msg") wird eine Rckmeldung an den Absender + geschickt. Das Setzen/L”schen geschieht wie bei "/notify", also z.B. + "/filter + dc1ik - db4ut" setzt dc1ik und l”scht db4ut aus der Liste. + + /HELP + Das Hilfekommando kann von zus„tzlichen Parametern gefolgt sein. Der + Schr„gstrich darf hier nicht vor dem fraglichen Kommando stehen, z.B.: + /Help Invi. ALLE Hilfstexte k”nnen auch auáerhalb des Conversmode mit + "Help conversd" als komplette šbersicht gelesen werden. + + /INVI + Es wird eine Einladung zum genannten User geschickt. Diese Einladung wird + durch das gesamte Netz geleitet. Wenn derjenige auf einem anderen Kanal + ist und Dein Kanal als privat eingerichtet ist, so kann er auf Deinen + Privatkanal wechseln. Wenn er im Befehlsinterpreter eines Knotens ist, so + empf„ngt er die Einladung, er kann dann aber nicht direkt auf Deinen + Privatkanal kommen, weshalb er nochmals einzuladen ist. + + /JOIN + Verbindet Dich zus„tzlich mit dem gewnschten Kanal. Im Gegensatz zu + „lteren Conversd-Implementationen, verbleibt man auch noch im vorherigen + Kanal, denn es wird eine Mehrfach-Kanal-Verbindung untersttzt. Um einen + Kanal zu verlassen, muát Du "/leave" verwenden. Ohne Angabe eines Kanals + werden Infos zu den von Dir benutzten Kan„len ausgegeben. + + /LEAV + Mit diesem Befehl kannst Du entweder den derzeitigen oder den angegebenen + Kanal verlassen. Wenn dieser der letzte ist, so wird conversd verlassen. + + /LINK + Der momentane Linkstatus wird angezeigt. Dies sind normalerweise + Hostname, Linkstatus, Laufzeiten, Versionskodes und Statuszeit, gefolgt + von der Zeit des n„chsten Connectversuches und Anzahl der Versuche (auf + Disconnecteten oder im Aufbau befindlichen Links), bei bestehender + Verbindung werden die Queue-L„ngen und Bytestatistiken angezeigt. + + Wenn Du Sysop bist, kannst Du Verbindungen setzen oder l”schen. Es wird + dann auch noch zus„tzlich in Klammern der Verbindungsweg angezeigt. + Syntax: /l [[-] Host [Port [via]]] + + /LIST + Alle Kan„le, ihre Themen, Optionen und User werden angezeigt. Die + Klammerwerte bedeuten: + (@) = Channel Oparator, + (G) = Mit AWAY abwesend gemeldet, + (!) = User ist im Sysopmodus. + + /ME + Dieser Befehl dient dazu, den Usern auf Deinem Kanal eine T„tigkeit + anzuzeigen. Wenn du z.B. "/me g„hnt" eingibst, bekommen alle User dieses + Kanals folgendes angezeigt: + + *** dc6iq g„hnt + + /MODE + Das Modekommando ist eines der kompliziertesten. Es wird wie folgt + benutzt: + + "/mo [] <+ ; -> >". + Die Optionen bedeuten folgendes: + t = Das Thema des Kanals l„át sich NUR von Kanal-Sysops „ndern. + i = Der Kanal wird Usern anderer Kan„le verheimlicht. + s = Der Kanal ist geheim, die Kanalnummer wird nicht mehr angezeigt. + m = Der Kanal ist moderiert, nur Kanal-Sysops drfen schreiben. + p = Der Kanal ist privat, man ben”tigt eine Einladung zum Einloggen. + l = Der Kanal ist lokal, Texte werden nicht weiter verteilt. + o = Macht zum Kanal-Sysop (kein - m”glich). + + Das Plus setzt eine Option, der Strich l”scht sie. Es sind Kombinationen + erlaubt, so wrde z.B. "/mode 69 -s+todc6iq" folgendes bewirken: Kanal 69 + ist nicht mehr geheim, aber die Themen drfen nur vom Kanal-Sysop gesetzt + werden. Zus„tzlich wird dc6iq ein Kanal-Sysop. + + /MSG + Sendet einen Text an einen speziellen User oder an einen verbundenem + Kanal. Wenn der Text an einen Kanal gehen soll, so muá man folgendes + eingeben: + + "/msg # ". + + Wenn das Ziel ein User ist, so kann er den Text an den zus„tzlichen + Sternchen erkennen. Z.B. wenn dc6iq eine Nachricht an dc1ik mit "/m dc1ik + Das ist ein Test" schickt, so erh„lt dc1ik folgendes: "<*dc6iq*>: Das ist + ein Test". + + /NOTI + Du wirst informiert, wenn eine bestimmte Person in der Personenliste im + Convers erscheint. Z.B. fgt "/notify + dc1ik" dc1ik in die Liste ein, + "/notify - db4ut" entfernt db4ut aus der Liste. Das Einfgen/L”schen + mehrerer Calls in einem Kommando ist m”glich, z.B. bewirkt "/notify + + dc1ik db4ut - dc6iq dh2paf +dg3kcr", daá dc1ik, db4ut und dg3kcr + eingefgt werden sowie dc6iq und dh2paf entfernt werden. Das Entfernen + von Calls, die nicht in der Liste stehen, wird ignoriert. + + /PERS + Es kann eine kurze Beschreibung zu Deiner Person gesetzt werden, den die + anderen User mit "/who" sehen k”nnen. Z.B: "/pers Fred, Buechig, JN49fb". + + Ohne Text wird die Beschreibung gel”scht. Diese Implementation merkt sich + bis zu 118 Zeichen der Beschreibung und setzt diese dann automatisch beim + Einloggen (die "/char" und "/width" Einstellungen werden dann auch + gespeichert und beim Einloggen gesetzt). + + /PASS + Es besteht auch die moeglichkeit im TNN-Convers ein Passwort zu setzten. + "/pass zeige" zeigt das derzeitige Passwort an. "/pass neu passworttext" + wird ein Neues Passwort gesetzt. Mit "/pass loeschen" wird das Passwort + geloescht. + + /NICK + Setzt den Nickname auf "nick", so das fortan vor Deiner Massages + statt gesendet wird. + Der Nickname wird auf dem Server Gespeichert und bei jedem Connect, + Automatisch gesetzt. Ein Nickname kann bis zu 10 Zeichen besitzen. + + /SYS + Nach Aufruf dieses Befehls wird eine Zufallsnummer zwichen 0 und 99999 + angezeigt. Nimm jede Zahl, multipliziere mit der verbunden Geheimnummer + in der Knofiguration in der (TNN179.TNB) summiere sie auf, und antworte + mit "99999" + + /PROM + Das Prompt-Kommando nimmt vier Argumente in einer zusammenh„ngenden + Zeichenkette. "/prompt abcd" setzt + + a = Als "/query"-Prompt. + b = Fr den normalen Prompt. + d = ist ein Zeichen, um den Prompt zu l”schen (normalerweise Backspace + c = Ist ein Zeichen, welches vor jedem Text, den Du empf„ngst, gesendet + wird (normalerweise also CTRL-G). + + /QUER + Der angegebene User ist in Zukunft der einzige Empf„nger fr alle Texte, + die Du eingibst. Diese werden dann als private Texte an den User + geschickt, wie bei "/m". Zum Ausschalten ohne Argument aufrufen, danach + geht alles wieder wie gewohnt an den Kanal. Sozusagen ein Privatmodus. + + /QUIT + Wenn Du das eingibst, verl„át Du diesen wunderbaren Ping-Pong-Convers. + Ich hoffe, es gefiel Dir. + + /TOPI + Hiermit kann fr den Kanal ein Thema gesetzt werden. Die anderen User + k”nnen dieses sehen, wenn sie "/who quick" oder "/list" eingeben. Wenn + keine Kanalnummer angegeben wird, so wird das Thema des aktiven Kanals + gesetzt. Wird eine Nummer angegeben, so muá Du auch auf diesem Kanal + eingeloggt sein. Um das Thema zu l”schen, ist als Thema ein "@" + einzusetzen. + + /UPTI + Dieser Befehl zeigt an, wie lange conversd schon aktiv ist. + + /VERB + Schaltet die Laber-Option ein/aus. Du bekommst dann viele Informationen + ber Aktionen der User (Einloggen/Ausloggen/Texte setzen/...), auch wenn + diese nicht auf Deinem Kanal sind. + + /VERS + Zeigt etwas Text zu dieser Version (in Deutsch). + + /SYSI + Zeigt etwas Text zum "Conversd Host" in dieser Version. Dieser Text kann, + in der "conversd.xhf" geändert werden, (Siehe tnn179_cb.pdf) + + /WHO + Dieser Befehl hat 4 Optionen. + a = Zeigt alle User und ihre Abwesendheitstexte, wenn gesetzt. + l = Generiert eine LANGE Liste mit Personenbeschreibung, + Abwesendheitstexte und Queue-Informationen. + q = Gibt eine kurze Auflistung aus + * = Zeigt alle User Deines Kanals. + + Wenn Du Informationen ber bestimmte User brauchst, kannst Du die "/who u + Userliste" Variante benutzen. + + /WIDT + Macht conversd Deine Bildschirmbreite (Zeichen/Zeile) bekannt. Die + Meldungen der anderen wird dann auf diese Breite gebracht. Voreingestellt + ist 80. Die Einstellung bei "/pers" gespeichert (siehe dort). + + (!) : + Mit einen vorangestelltem ! ist es m”glich, die TheNetNode-Befehle auch + vom Convers aus aufzurufen. + +(CQ) + + Durch Eingabe von CQ kann ber jeden TheNet-Knoten ein CQ-Ruf gestartet + werden. CQ Text... (Text bis zu 75 Zeichen), jedoch keine zus„tzlichen + Digipeater m”glich. TheNetNode kann mehrere CQ-Rufe gleichzeitig + verwalten, jedoch nur einen je Uplink bzw. Circuit. + + Wie starte ich einem CQ-Anruf ? + + Angenommen, DB2OS in Hannover m”chte beim Knoten in Braunschweig einen + allgemeinen CQ-Ruf absetzen. Zun„chst connected er BS:DB0FC und gibt dann + dort den CQ-Befehl ein. + + cq cq de DB2OS HANNOVER JO42VG/EM60G VIA BS -- PSE CONNECT DB2OS-15 + + WICHTIG: Durch einen nachfolgenden Befehl oder ein RETURN wird der CQ + Zustand abgebrochen! + + VARIANTE A: + + OM Karl, DK7AL, ist zur gleichen Zeit mit dem Knoten BS:DB0FC connected + und sieht nun bei der Eingabe des USER-Befehls folgende Liste: + + BS:DB0FC> TheNetNode 1.70 (731) + Uplink (DF3AV) <--> Circuit (BS77:DB0FC-8 DF3AV) + Uplink (DF2AU) <..> Downlink (DF2AU-15 DK4EG-1) + Circuit (H:DB0FD DB2OS) <..> CQ (DB2OS-15) + Uplink (DK7AL) + + "<..> CQ(DB2OS-15)" zeigt nun an, daá DB2OS (vom Knoten H:DB0FD kommend) + eine Verbindung in den Raum BS sucht und den CQ-Befehl eingegeben hat. + DK7AL muá an dieser Stelle nur "C DB2OS-15" eingeben und ist SOFORT mit + DB2OS verbunden!!! Das mhsame Zurckverfolgen des Verbindungsweges + entf„llt komplett bzw. ist nicht erforderlich. + + VARIANTE B: + + OM Wolfgang, DB3AN, monitort die Frequenz und sieht pl”tzlich folgendes + Paket auf dem Bildschirm (NORD> Connected to DB3AN". + + Wie man sieht, kann man also auf der Benutzerebene des Knotens, oder + direkt, den Verbindungsaufbau nach dem "Sichten" des CQ-Ruf einleiten. + +(D)EST + Zeigt die Eintr„ge der NODES-Liste in der bei den RMNC blichen Weise an. + + Destinations (5): + DB0BID 0-0 DB0EAM 3-3 DB0EAM 4-4 DB0NHM 0-0 DB0NHM 4-4 + 1) 2) + + 1.) Erreichbare Ziele (Destinations), + 2.) SSID-Bereich des Calls. + +(D)EST <*> + Liste wie oben jedoch zus„tzlich mit Laufzeiten. + +(D)EST + Hierbei muá das Call nicht vollst„ndig sein. Die Eingabe von (D)est HB9* + zur Anzeige aller HB9.. Destinationen. Sie werden mit Call, SSID-Bereich, + Laufzeit und Port, auf dem sie erreichbar sind, angezeigt. + +(D)EST + Zeigt die Liste wie bei (N)odes an .... eben nur fr die FlexNet + Liebhaber. + +(D)EST < + Zeigt die Nodes / Destinationen an, die von diesem Nachbar mit der besten + Laufzeit meldet. + +(DX)CLUSTER + Wurde ein locales Cluster eingetragen, so reicht die Eingabe von zum + Connect dieses Cluster. Sinn dieses Befehles ist es, nicht immer auf + einem Knoten nach dem n„chstgelegenen Cluster suchen zu mssen. + +(G)RAPH + Graphische Ausgabe einiger statistischen Werte. Gefhrt werden die Werte: + (B)aud + (C)ircuits + (F)ree buffers + (L)2-Links + (N)odes + (R)ounds + (*) Fr die Ausgabe aller Statistiken. + + Beispiel: (G)RAPH (B)AUD zeigt die Entwicklung der letzen Stunde mit dem + Bezugspunkt 0 auf der y-Achse an: + + Throughput (Baud): Maximum: 31232 Average: 18222 Minimum: 10904 + + 31245| + 29162| ## + 27079| # ## + 24996| # ##### + 22913| ### ## ##### + 20830| ##### ### # ###### + 18747| # ######### # ## ####### + 16664|#################### # ## ######## ## # + 14581|##################### # ######## # # ################# + 12498|################################### ###################### + 10415|############################################################ + 8332|############################################################ + 6249|############################################################ + 4166|############################################################ + 2083|############################################################ + +------------------------------------------------------------ Elap. + Time + -3600 -3240 -2880 -2520 -2160 -1800 -1440 -1080 -720 -360 0 Seconds + + Um die Žnderungen besser sehen zu k”nnen, kann der Bezugspunkt durch ein + nachfolgendes "+" auf den MINUMUM-Wert verschoben werden. + Beispiel: (G)RAPH (B)AUD + . + + Throughput (Baud): Maximum: 31232 Average: 18222 Minimum: 10904 + 31244| + 29888| # + 28532| ## + 27176| # ## + 25820| # ### + 24464| # ##### + 23108| ### ## ##### + 21752| ### # ### # ##### + 20396| ##### ### # # ###### + 19040| ######### # # ###### + 17684| ############# ## ## ####### # + 16328|#################### # ### # ######### ##### + 14972|##################### ######## # # ################# + 13616|################################## ### ################# + 12260|################################### ###################### + 10904|############################################################ + +------------------------------------------------------------ Elap. + Time + -3600 -3240 -2880 -2520 -2160 -1800 -1440 -1080 -720 -360 0 Seconds + + Wird nun noch ein (D)AY eingefgt, so erh„lt man die Ausgabe der + vergangenen 23 1/2 Stunden. + Beispiel: (G)RAPH (D)AY (B)AUD + + +(H)ELP (externer Befehl) + Zu den Befehlen in TheNetNode gibt es jeweils auch eine Erkl„rung bzw. + Hilfe. Mit der Eingabe (H)ELP wird eine šbersicht ber die m”glichen + Hilfen ausgegeben sowie auch die Anzahl der Bildschirmseiten. Mit (H)ELP + (N)ODES werden die ersten 22 Zeilen ausgegeben. Die Zeilen 23-44 kommen + nach der Eingabe (H)ELP (N)ODES 2 . Wer zurckbl„ttern kann, kann auch + alle Seiten auf einmal bermittelt bekommen durch das anh„ngen eines "*". + Beispiel: (H)ELP (N)ODES * + + Programm 1.2 vom Oct 07 2004 by DAD213 + TNN-Doku-Version 1.79mh03 vom 6. Jul 2005 by CB-PR Team Dessau + + Folgende Befehle sind laut Dokumentation verfgbar : + Befehl Hilfe-Seiten Befehl Hilfe-Seiten + + (A)KTUELL (extern) 1 (BE)ACON 1 + (C)ONNECT 3 (CONV)ers 17 + (CQ) 4 (D)EST 2 + (DX)CLUSTER 1 (H)ELP 1 + (HA)RDWARE (extern) 1 (I)NFO (extern) 1 + (L)INKS 1 (L3)MHEARD 3 + (M)AILBOX 1 (MAP) (extern) 1 + (MH)EARD 5 (MSG) (extern) 3 + (N)ODES 7 (PA)RAMETER 6 + (PAC)SAT 1 (PI)NG 1 + (PO)RT 8 (Q)UIT 1 + (QTH) (extern) 2 (R)OUTES 5 + (S)TAT 19 (SAT) (extern) 1 + (SAV)ecall (extern) 1 (SH)owcall (extern) 2 + (SO)FTWARE (extern) 1 (TA)LK 1 + (TI)ME 1 (TOP) (extern) 5 + (U)SER 14 (V)ERSION 1 + (HTTP)D 1 (TEL)NET 1 + (IPC)ONV 1 + + Externe Befehle sind nicht bei jedem Digi vorhanden ! + +(H)elp + Zeigt die erste Seite (20 Zeilen) der Hilfe zum an. + +(H)elp 2 + Zeigt die zweite Seite der Hilfe zum an. + +(H)elp * + Zeigt alle Seiten der Hilfe zum an. + +(HA)RDWARE (externer Befehl) + Gibt eine Hardwarebeschreibung des Knotens aus. + +(HTTP)D Server + + Neu: + ~~~~ + Die Funktion des HTTPD-Server ist sehr änlich mit der BCM zu vergleichen. + Beim erten Login wird nach Benutzername und Passwort gefragt, + Passowrt ist optional,also nicht zwingend! + +(I)NFO (externer Befehl) + Ausgabe des Info-Textes. + +(L)INKS + Zeigt die eingetragenen Rufzeichen, die den Links zugeordnet sind. + + Links von DEFUNK:CB0DE (4/32) + Type-Port--ALIAS:CALL------Route----------Infotext--------- + L P 4 debcm:DBQ213 Archiv-Mailbox + I 1 DENET1:KR2GAT InetNode Dessau + I 1 JO61QH:DIG531 InetNode Glaubitz/Riesa + F 0 JO61DU:DNQ230 FunkNode Dessau/Waldersee + + Typ: + L = Localer Eintrag + L+ = Localer Eintrag wird gemessen + F = FlexNet-Nachbar + N = NetRom-Nachbar + I = INP-Nachbar + + P = Proxy Funktion + +(L3)MHEARD + Gibt eine aktuelle Rufzeichenliste der letzten 10 geh”rten L3-Calls mit + Datum, Uhrzeit, Port-Name, RX-Byte, TX-Byte, L3 Frame von Call und L3 + Frame an Nachbar geroutet. Die L3MH-Liste wird seit der Version + TNN175ag10 wie die Statistik im aktuellen Laufwerk gesichert. Sie dient + dazu, die L3-Verbindungen die ber den Knoten laufen, beurteilen zu + k”nnen. Die SSID wird hierbei beachtet. + + KS:DB0EAM> MHEARD (97/500) + 30.01.98 17:29 P 1 [ 6095559, 12686304] KR2GAT + 30.01.98 17:29 P 0 [ 67218, 153548] DNQ230 + 30.01.98 17:29 P 5 [ 421886, 15142753] DAD213-1 + 30.01.98 17:29 P 6 [ 5535466, 17842422] DE0SAU + 30.01.98 17:29 P 4 [ 24644, 1217402] DBQ213 + 30.01.98 17:29 P 2 [ 62988, 519602] DE1CS + + MHEARD (/) + Die beiden Ziffern in der ersten Zeile geben an: + 1. = L„nge der gefhrten MH-Liste, + 2. = Eingestellte L„nge. + +(L3)MHEARD + Gibt eine aktuelle Rufzeichenliste der letzten geh”rten Calls + mit Datum, Uhrzeit, RX-Byte, TX-Byte, L3 Frame von Call und L3 Frame an + Nachbar geroutet aus. + +(L3)MHEARD + Listet wann und unter welcher SSID der Knoten mit dem zuletzt ein + L3-Frame ber diesen Digi gesendet hat. Weiterhin werden die RX-Byte und + TX-Byte (aus der Sicht des Knotens) mit angezeigt, die seit dem letzen + L”schen der L3MHEARD-Liste oder Ver„ndern der Anzahl der Listeneintr„ge + aufgelaufen sind. + + Im k”nnen auch Wildcards verwendet werden. Dabei steht "*" fr + beliebig viele (oder keine) Zeichen und "?" steht fr genau 1 Zeichen. + + (L3)MHEARD df6ln = Eintr„ge mit dem Rufzeichen DF6LN + (L3)MHEARD df* = Eintr„ge von DF-Stationen + (L3)MHEARD *b? = Stationen mit "B" als vorletztem Buchstaben + (L3)MHEARD *b* = Stationen mit "B" im Rufzeichen + +(M)AILBOX + Wurde eine locale Mailbox eingetragen, so reicht die Eingabe eines + zum Connect dieser Mailbox. Sinn dieses Befehles ist es, nicht immer auf + einem Knoten nach der n„chstgelegenen Mailbox suchen zu mssen. + +(MAP) (externer Befehl) + Zeigt eine kleine Karte der direkten Umgebung des Knotens. + +(MH)EARD + Gibt eine aktuelle Rufzeichenliste der letzten 10 geh”rten Calls mit + Datum, Uhrzeit, Port-Name, RX-Byte und TX-Byte aus. Die MH-Liste wird + seit der Version TNN149l9 wie die Statistik im aktuellen Laufwerk + gesichert. Sie dient nun auch dazu, einen User auf dem Port zu connecten, + auf dem er zuletzt geh”rt wurde. Die SSID wird hierbei beachtet. Es ist + also m”glich, mit dem Call DB0XY-1 auf dem Port 0 und mit dem Call DB0XY- + 2 auf einem anderen Port QRV zu sein. Wer selten QRV ist, f„llt nun, je + nach L„nge der Liste, irgendwann aus ihr raus. + + + Als Erweiterung kann ein "+" eingegeben werden. Es wird dann eine + erweiterte User-Statistik ausgegeben. Sie besteht aus den vom User + empfangenen Rej = (r) an den User gesendete Rej = (t) sowie die Anzahl + der DAMA-Verst”áe = (d). + + DEFUNK:CB0DE> MHEARD (26/30) + Date Time Port RX TX Call RX-Rej TX-Rej DAMA + 19.03.98 13:34 P 0 [ 927365KB, 1932892B ] DNQ230 26r 19t 0d + 19.03.98 13:33 P 2 [ 59149KB, 407445B ] DE1CS 4r 2t 0d + 19.03.98 13:33 P 0 [ 24821KB, 856196B ] DE1BA 4r 3t 0d + 19.03.98 13:33 P 5 [ 40804KB, 231705B ] DAD213-1 9r 4t 0d + 19.03.98 13:33 P 0 [ 880KB, 43047B ] DAA772 4r 0t 0d + + => + + MHEARD (/) + Die beiden Ziffern in der ersten Zeile geben an: + 1. = Anzahl der gefhrten Calls in der MH-Liste, + 2. = L„nge der MH-Liste. + +(MH)EARD + Gibt eine aktuelle Rufzeichenliste der letzten geh”rten Calls + mit Datum, Uhrzeit, RX-Byte und TX-Byte aus. + +(MH)EARD + Listet wann und unter welcher SSID der User mit dem den Knoten + zuletzt benutzt hat. Weiterhin werden die RX-Byte und TX-Byte (aus der + Sicht des Knotens) mit angezeigt, die seit dem letzen L”schen der MHEARD- + Liste oder Ver„ndern der Anzahl der Listeneintr„ge aufgelaufen sind. + + Im k”nnen auch Wildcards verwendet werden. Dabei steht "*" fr + beliebig viele (oder keine) Zeichen und "?" steht fr genau 1 Zeichen. + + (MH)EARD df6ln = Eintr„ge mit dem Rufzeichen DF6LN + (MH)EARD df* = Eintr„ge von DF-Stationen + (MH)EARD *b? = Stationen mit "B" als vorletztem Buchstaben + (MH)EARD *b* = Stationen mit "B" im Rufzeichen + + (N)ODES + Zeigt alle momentan bekannten Knoten an, die das NET/ROM- bzw. TheNet-L3- + Protokoll verwenden. Die ausgegebene Liste wird regelm„áig ber + sogenannte Rundspruchsendungen (Broadcast) der TheNet-Nachbarknoten auf + dem neuesten Stand gehalten. Die Liste „ndert sich also, wenn Links + ausfallen oder neue Links hinzukommen. Auáerdem „ndern sich die + Laufzeiten der einzelnen Eintr„ge in Abh„ngigkeit von der Linkbelastung + und bei schlechten Ausbreitungsbedingungen. Beispiel: + + 1 2 3 4 + / / / / + KS:DB0EAM > Nodes (139/1009): + + SH9600:DB0AZ HUSUM:DB0HES HHWEST:DB0HHW HL:DB0MAR + KIELMB:DB0OQ SL:DB0SUE SYF7:OZ3DIJ-7 + / / + 5 6 + + 1.) Alias dieses Netzknoten. + 2.) Rufzeichen dieses Netzknoten. + 3.) Anzahl der bekannten Knoteneintr„ge. + 4.) Maximal m”gliche Anzahl an Eintr„gen + 5.) Alias des Endknoten. + 6.) Rufzeichen des Endknoten. + + ALIAS ist dabei eine maximal 6-stellige Abkrzung zur besseren + geographischen Einordnung des Knotenstandortes. In unserem Raum werden + normalerweise die blichen Autokennzeichen als ALIAS verwendet oder aber + kurze Ortsnamen auch ausgeschrieben (wie z.B. bei KS:DB0EAM oder + KIEL:DB0IL). Zu den in der Liste aufgefhrten Endknoten kann in der Regel + mit dem Connect-Befehl eine Verbindung hergestellt werden. Endknoten, + deren ALIAS mit "BOX" oder "MB" endet, sind damit als Mailbox erkennbar; + DX-Cluster sind mit "DX" oder "DXC" am Ende des ALIAS erkennbar. + + Die Anzahl der bekannten Netzknoten wird hinter "Nodes" in Klammern + angezeigt. + + Der Nodes-Befehl kann bis auf den ersten Buchstaben abgekrzt werden und + auch beliebig groá und / oder klein geschrieben werden. Der Nodes-Befehl + kann auáerdem mit Parametern aufgerufen werden, um Informationen zu + einzelnen Endknoten oder Gruppen von Endknoten zu bekommen. + + Mit dem Befehl: + +(MO)NITOR OPTIONEN PORT + Optionen: + U = Unprotokollierten Paketen, + I = Info Paketen, + S = Kontroll Paketen, + C = Monitor an auch bei bestehendem Connect, + H = HEADER, bei I-Frames nur den Header anzeigen, der + Infoteil der Frames wird unterdrckt, + F = FULL, I-Frames mit Infoinhalt anzeigen, es werden die + kompletten Frames gemonitort, + = Nur der angegebene Port wird gemonitort, + + = Nur diese Call (bis zu 8) monitoren, + - = Diese Call im Monitor unterdrcken. + + Beispiel: MO usci 2 + +(MSG) (externer Befehl) + +(MSG) S # + Zum Erstellen einer Digimail: + + Der Message-Befehl erm”glicht es, einem Benutzer des Knotens eine kurze + (!) Nachricht in den CTEXT zu schreiben. Beim n„chsten Connect wird diese + Zeile dann bei ihm im CTEXT erscheinen. Statt des Zielcalls kann auch + eine Zielgruppe angegeben werden. Diese ist eine Art Verteilerliste. + Jedes Mitglied der Zielgruppe bekommt eine Kopie der Nachricht. + + Die Lifetime kann, muá aber nicht, angegeben werden. Sie kann von #1 = + einem Tag bis #99 = neunundneunzig Tagen angegeben werden. Wird keine + Lifetime angegeben, so wird sie auf default = 14 Tage gesetzt. Das + Herabsetzen der Lifetime geschieht mittels MSY C. Siehe "Externe + Programme fr den SYSOP". + + Abh„ngig davon, ob das System mit einer Festplatte oder einer RAMDISK + arbeitet, kann die Nachricht bei Absturz oder Reset verloren gehen. + + Beispiel: MSG S DL9GYA #10 Roland, bitte connecte mich, wenn Du zurck + bist! + + MSG S SYSOP Link nach ..... defekt?! + + Letzteres wrde die Nachricht an DL1KWS und DL9GYA weiterleiten. Die + Definition einer neuen Gruppe geschieht nur durch den Sysop. Bitte danach + fragen. + +(MSG) R + Liest die eigenen Nachrichten aus. + +(MSG) R + Liest die an gerichteten Nachrichten aus. + +(MSG) R 1 oder 1-3 + Zus„tzlich kann noch eine Numerierung mit angegeben werden. Also Lesen + der Nachrichten 1 oder 1-3. + +(MSG) L + Listet die eigenen Header auf. + +(MSG) E + Der MSG E Befehl l”scht alle eigenen Digimail-Nachrichten im eigenen + CTEXT. + +(MSG) G + Zeigt alle vorhandenen Verteilergruppen mit Call an. + +(MSG) G + Zeigt nur die Call in dieser an. + + Neue Gruppen k”nnen nur vom Sysop angelegt werden! + +(MSG) V + Gibt die Versionsnummer und - Datum aus. + +(N)ODES oder (N)ODES + bekommt man eine Auflistung der bekannten Wege zu dem mit bzw. + angegebenen Endknoten. So erh„lt man z.B. mit "(N)odes DB0FC". + Ein zus„tzliches "*" hinter zeigt alle Wege an. Weiterhin wird + hiermit der NetRom - Route - Rekord (NRR) ausgel”st. + + 1 2 + / / + Routes to BRO:DB0BRO + ---T[ms]----RxT----TxT--LT-Mode-Obc-----RTT-Po-Route------------------------ + > 4330 3910 0 2 DG 0 420 6 DB0GOE + 16440 7000 4870 10 DG 19 9440 9 HB9AK via DB0BID + 30970 17560 4870 5 DG 0 13410 9 DB0LBG-7 via DB0BID + 600000 599990 4870 4 DG 0 1550 9 DB0KH via DB0BID + > 4800 4800 0 10 VC 0 910 10 DB0NHM + 5970 10 0 1 DG 0 5960 10 DB0BRO via DB0NHM + 25200 3480 0 2 DG 0 21720 10 DB0GOE via DB0NHM + 600000 599990 4870 4 DG 0 520 11 DB0KH + ^ / / / / / / / / / + 3 4 5 6 7 8 9 10 11 12 + + 1.) ALIAS-Kennzeichen des gefragten Endknoten. + 2.) Rufzeichen des gefragten Endknoten. + 3.) > = Der Weg wird derzeit verwendet fr eine Verbindung zu dem + Endknoten. + + = Zeigt eine alternative Route an, ber die auch Datenbertragung + stattfindet. + - = Diese Route ist abgemeldet und wird nicht mehr benutzt. + * = Es wird kein Obs mehr gefhrt, da der Nachbar bereits + differenziellen Broadcast untersttzt. + 4.) Gemessene Laufzeit in ms des jeweiligen Weges. + 5.) RxT Laufzeit die vom dem Nachbar ber das Ziel DB0BRO gemeldet + wurde. + Bzw. 10 wenn es ein direkter Nachbar ist. + 6.) Laufzeit mit der das Ziel weitergemeldet wird. (Errechnet sich aus + RxT und gemessener Laufzeit zum Nachbarknoten). + 7.) Lifetime des Knotens. Wenn LT=0 wird der Knoten nicht mehr weiter + verbreitet. + 8.) šbertragungsmode auf diesem Link DG = Data Gramm (H”here + Protokollebene die das Umrouten erm”glicht) ; VC = Virtual Circuit + (Unterste Protokollebene). + 9.) Obc Obsolentcounter (Veraltensz„hler) fr Ziele mit altem + Protokoll. + 10.) Round - Trip - Timer oder Laufzeit zum Nachbarknoten. + 11.) Port ber den die Verbindung geroutet wird. + 12.) Rufzeichen des Nachbarknotens fr den jeweiligen Weg. + + Bei einer Laufzeit 600000 ms wurde der Weg ber Fastlearn aufgenommen. + + Das NRR - Frame wird zum Node gesendet und der Weg hin und zurck + aufgezeichnet. Der abgefragte Node muá jedoch den NRR untersttzen sonst + kommt keine Antwort zurck. Digipeater wie DB0FC untersttzen NRR zwar + nicht leiten aber das Frame weiter und erscheinen in der Liste dann mit + einem "?" . Das angesprochene Node wird mit einem "*" gekennzeichnet. + + KS:DB0EAM> Route (DG): DB0EAM DB0GOE DB0BRO* DB0EAM + + Folgende Konstellation bei DB0SHG: + + Routes to BS:DB0FC + ---T[ms]----RxT----TxT--LT-Mode-Obc-----RTT-Po-Route---------- + - 33800 33800 33900 10 VC 0 12880 4 DB0HSK + > 17700 17700 0 10 VC 0 77830 6 DB0HW + 43360 10 0 1 DG 21 43350 6 DB0FC via DB0HW + + bedeutet nichts anders, also das ein User der DB0FC connecten m”chte, den + FlexNet-Weg ber DB0HW vorgeschlagen bekommt, weil sonst keine wesentlich + schnellere Alternative zur Verfgung steht. Eine solche Verbindung kann + natrlich NICHT umgeroutet werden, selbst wenn zwischendurch ein besserer + NETROM-Weg zur Verfgung steht ! + + Umgedreht wird nie eine NETROM-QSO auf FlexNet-Weg umgeroutet. + + Wie war es frher (1.70)..... + Da gab es zwei Listen, eine NETROM und eine FlexNet. Es wurde immer + zuerst der NETROM-Weg genommen, egal wie schlecht er war ! Im schlimmsten + Fall bedeutete dies, NETROM 10 Minuten Laufzeit, FlexNet-Weg 10 Sekunden. + Dieses war jedoch wenig sinnvoll. Heute gibt es nur noch eine Liste, + dafr werden FlexNet-Ziele mit einigen % unterbewertet. Sind mehrere + NETROM-Wege vorhanden so wird natrlich weiterhin umgeroutet. + + Hin- und Rckweg k”nnen bekanntlich unterschiedlich Wege nehmen. + + Um erweiterte Informationen ber eine Gruppe von Endknoten zu bekommen, + gibt man den Befehl ein: + +(N)ODES + + Fr wird dabei der Wert fr die minimale Laufzeit der + Endknoten angegeben. Soll nicht eine minimale, sondern eine maximale + Laufzeit angegeben werden, wird nach der Laufzeit ein Minus geschrieben. + Fr kann ein Rufzeichen oder ein ALIAS eingesetzt werden, bei dem + "*" und "?" als Platzhalter verwendet werden k”nnen. Dabei steht "*" fr + beliebig viele (oder keine) Zeichen und "?" steht fr genau 1 Zeichen. + Auáerdem kann man die Abfrage auf den ALIAS-Teil oder auf den Rufzeichen- + Teil des Knoteneintrages beschr„nken, indem man ein ":" vor oder hinter + setzt. Mit ":" begrenzt man die Abfrage auf den ALIAS-Teil, + und mit ":" begrenzt man die Abfrage auf den Rufzeichen-Teil der + Knoteneintr„ge. Wird nur eine angegeben, so werden alle Knoten + mit passender Laufzeit angezeigt. Wird nur ein angegeben, so wird + die Laufzeit bei der Auswahl nicht bercksichtigt. Die ausgegebene Liste + an Endknoten sieht dann z.B. so aus: + + KS:DB0EAM > Nodes: (7) + + HHS:DB0HBS 176/11 HHSBOX:DB0HBS-1 69/11 + / / / / + 1 2 3 4 + + 1.) ALIAS des Endknoten. + 2.) Rufzeichen des Endknoten. + 3.) Laufzeit in mal 10 ms fr den besten bekannten Weg. + 4.) Port fr Nachbarknoten. + + Beispiele: + + Befehl ! Antwort + ==============!========================================================== + NODES 2000 ! Alle Eintr„ge mit Laufzeiten min. 2000. + NODES -60 ! Alle Eintr„ge mit Laufzeiten max. 60. + NODES 100 d* ! Rufzeichen oder ALIAS beginnt mit "D", Laufzeit min. 100. + NODES -100 *d ! Rufzeichen oder ALIAS endet mit "D", Laufzeit max. 100. + NODES *d* ! Rufzeichen oder ALIAS enth„lt ein "D", Laufzeit egal. + NODES ????? ! Rufzeichen oder ALIAS ist genau 5 Zeichen lang. + NODES :d* ! Rufzeichen beginnt mit "D". + NODES :?b* ! Rufzeichen mit "B" als 2. Buchstaben (DB- u. HB9-Stationen). + NODES :hb9* ! HB9-Rufzeichen. + NODES :*l ! Rufzeichen endet mit "L". + NODES k*: ! ALIAS beginnt mit "K". + NODES *box*: ! ALIAS enth„lt "BOX". + NODES *dx: ! ALIAS endet mit "DX". + NODES *u?: ! ALIAS mit "U" als vorletztem Buchstabe. + NODES * ! Zeigt die gesamte Liste an. + +(N)ODES < + Zeigt die Nodes / Destinationen an, die von diesem Nachbar mit der besten + Laufzeit meldet. + +(PA)RAMETER + Ausgabe der Parameter-Liste. + + DEFUNK:CB0DE> Parms: + 01:NoAckBuf 20 02:L3-MaxTime 200 03:SaveConfig 6 + 04:DAMA-Speedf 0 05:DAMA-MaxPri 15 06:DAMA-MaxPol 0 + 07:DAMA-Tout 100 08:CommandLog 2 09:SysopLog 1 + 10:TestSSID 15 11:ConvSSID 6 12:AutoIPR 3 + 13:Timeout 18000 14:HostTime 0 15:MH-Default 1 + 16:MH-Len 30 17:Statusbake 300 18:L3-MaxLT 5 + => + + 01: NoAckBuf + šberfllungsgrenzwert in Anzahl Frames. Anzahl der Pakete, die auf + der Transport-Layer-Ebene zwischengespeichert werden, bis eine + Choke-Nachricht zum vermittelten Knoten geschickt wird. Gleichzeitig + die Anzahl Frames, die im Link-Layer zwischengespeichert werden, + bevor das Link-Layer in den Busy-Zustand geht. Dieser Grenzwert** + verhindert den šberlauf eines TheNet-Knoten, falls ber das + Transport-Layer zu viele Pakete einlaufen, oder falls eine Station + in einem Link zu viele Pakete auf einmal senden will. + + 02: L3-MaxTime + Maximale Laufzeit von Knoten, die ueber Interlinkverbindungen + an andere Knoten gemeldet werden. Uebersteigt die Laufzeit eine + Knotens den eingestellten Wert, so wird er nicht weitergemeldet. + + 03: SaveConfig + Zeitraum in 10 min-Schritten, in dem TNN176.STA und MHEARD.TAB mit + den aktuellen Statistikdaten auf Disk oder HD gespeichert wird. + + 04: Dama-Speedf + Bei TNN-Digis mit Multibaud (z.B. 1200 und 9600 Baud) bestand + ebenfalls ein weiter Wunsch, einen Anreiz fr 9k6-Betrieb zu + schaffen. Im Normalfall werden 1200- und 9k6-User gleichbehandelt, + und man kann lediglich ber MAXFRAME den 9k6-Betrieb etwas + bevorzugen. šblicherweise sollte man MAXFRAME 7 auf 9k6 benutzen und + nicht mehr als MAXFRAME 2 auf 1200 Baud. Aber einigen Sysop war dies + noch nicht genug. Was der neue DAMA-Speedfaktor bewirkt, soll nun am + folgenden Beispiel erl„utert werden. Angenommen, wir haben einen + 1200-Baud- und einen 9600-Baud-Einstieg, und wir wollen die 9600er + User deutlich bevorzugen. Steht DAMA-Speedf jetzt auf 9600, dann + werden User auf einem 1200-Baud erst in jeder 8. Runde bedient. Auf + den ersten Blick scheint dies viel zu langsam, aber bei 9k6 sind die + Frames ja so kurz, so daá es also NICHT gleich um Faktor 8 langsamer + geht. Sind berhaupt keine 9k6-User da, dann ist alles wie bisher. + Wichtig: Die korrekte Baudrate muá im Speed-Parameter fr den + jeweiligen Port richtig eingetragen sein. + + Die "Verlangsamung" berechnet sich so: + + DAMA-Speedf 9600 + Verlangsamung = ------------ = ----- = 8 + Speed[Port] 1200 === + + Bei dem 9k6-Port ergibt sich entsprechend ein Faktor von 1. Hat man + gleichzeitig noch einen 2k4-Einstieg, dann ist die Verlangsamung + dort 9600/2400 = 4. M”chte man den 1200er Einstieg nicht gleich um + Faktor 8 beeinflussen, kann man natrlich einen beliebigen Wert + zwischen 1200-9600 (oder mehr!) bei diesem Parameter eintragen. Ein + Wert kleiner als die niedrigste Baudrate bzw. ein Wert von 0 + schaltet diese Funktion ab. + + 05: DAMA-MaxPri + Maximaler Z„hlerstand, der erreicht werden kann bei geringer + Aktivit„t eines User. Dieser User wird dann seltener zu Gunsten der + anderen User abgefragt, ob er Daten zu senden hat. + + 06: DAMA-MaxPol + 0 = ausgeschaltet. + x = Nach x Verst”áen erfolgt ein Abwurf vom DAMA-Master. + + Die TNN-Software bietet fr den SYSOP eine abschaltbare DAMA- + Kontrolle. Alle User, die sich nicht an das DAMA-Protokoll halten, + bekommen bei jedem DAMA-Verstoá eine entsprechende WARNUNG + mitgeteilt. Ist eine, vom Sysop einstellbare, Anzahl berschritten, + dann erfolgt ein Abwurf des User vom Digi! Die "Meckermeldungen" + werden nicht mehr nutzlos als UI-Frame (Bake) ausgesendet werden, + sondern sie werden jetzt mitten in das betreffende QSO eingeh„ngt. + Die Warnung gibt die Anzahl der aktuellen Verst”áe an sowie die + Anzahl der Verst”áe, bis ein Disconnect seitens des DAMA-Master + erfolgt (mit entsprechender Meldung). + + 07: DAMA-Tout + Zeit in 10 ms, die gewartet wird, wenn auf ein Paket an einen User + keine Best„tigung kommt, bis zum Senden an den n„chsten User in der + Reihenfolge. + + 08: CommandLog + Schafft nun die M”glichkeit, eine Logdatei COMMAND.LOG im + Verzeichnis TNN zu fhren. Es werden alle Eingaben im Knoten mit + CALL, DATUM, UHRZEIT und COMMAND in der Datei abgespeichert. Es sind + folgende Einstellungen m”glich: + + 0 = Keine Protokollierung. + 1 = Nur Sysop-Eingaben werden protokolliert. + 2 = Alle Eingaben werden protokolliert (Vorsicht, die Logdatei + w„chst schnell!). + + 09: SysopLog + Speichert wer sich als SYSOP beim Knoten privilegiert. + + 10: Downport + Legt den Port fest, auf dem die Connect ausgesendet werden die der + Knoten nicht zuordnen kann. Z.B.: Wenn ein Knoten connected werden + der nicht in der NODES-Liste steht oder ein User connected werden + soll der nicht in der MH-Liste steht. Sollen die nicht zuzuordnenden + Connect nicht auf einem User-Einstieg ausgesendet werden, so kann + auch ein ausgeschalteter Port zugewiesen werden. Die connectende + Station bekommt dann ein "Port not in use" zurck. + + 10: TestSSID + Legt die SSID fest, mit der dieser Knoten die Laufzeitmessung + durchfhrt bei einem mit L+ eingetragenes Call. + + 11: ConvSSID + Einstellung der SSID die der Convers benutzen soll. + + 12: AutoIPR + Automatisches Lernen von IP-Adressen anderer Nodes (nur fuer INP). + Es werden verschiedene Stufen der Filterung unterstuetzt, Stufe 3 + ist standardmaessig eingestellt. + + 0 : ausgeschaltet, KEINE automatischen IPR- und ARP-Ein/Austragungen + (damit kann man die Tabellen einfrieren wenn sie gefuellt sind !) + 1 : automatische Ein/Austragung OHNE jegliche Pruefung der + IP-Adressen + 2 : automatische Ein/Austragung, unmoegliche IP-Adressen werden + ignoriert (x.x.x.0 x.x.x.255) + 3 : automatische Ein/Austragung, es werden nur IP-Adressen + beruecksichtigt, die im gleichen Netz (44.x.x.x) und gueltig sind. + + 13: Timeout + Einstellung User Timeout. + + 14: HostTime + Einstellung Sysop Timeout. + + 15: MH-Default + Einstellung der MH anzeige (Default ist 1) + + 16: MH-Len + Hier wird eingestellt wie lang die MH-liste sein soll. + + 17: Statusbake + + + 18: L3-MaxLT + +(PAC)SAT + Zeigt Call und Message-Pool des BROADCAST-Server an. + + Server call: XX0XX-2 + Message pool: 1-9 (9 Messages) + +(PI)NG + Fhrt eine Laufzeitabfrage zu der IP-Nummer durch. + +(PO)RT + Gibt eine Liste mit den aktuellen Porteinstellungen aus: (Diese + Darstellung ist ein MISCHMASCH aus DOS/GNU- und LINUX- Version und dient + hier nur zur Verdeutlichung.) + + DEFUNK:CB0DE> Link-Interface Ports: + -#-Name--------Speed/Mode-Max-TXD-PACL-PERS-SLOT-FRACK--T2----T3-RET-DA-C-S-M + 0 CB-Kanal76 1200 4 30 128 255 32 200 127 18000 10 C M + 1 Internet 1200 7 0 256 255 0 200 0 18000 15 C M + 2 Telnet 19200 7 0 256 255 0 200 0 150 15 C M + 3 HTTP 19200 7 0 256 255 0 200 0 18000 15 C M + 4 Mailbox 19200d 7 0 256 255 0 200 0 18000 15 M + 5 Sysop 19200 7 0 256 255 0 200 0 18000 15 M + 6 CVS-Server 19200 7 0 256 255 0 200 0 150 15 C M + + #: Gibt den Port des Knotens an. + + Name: Zur leichteren šbersicht. + + Speed/Mode: + Speed zeigt die eingestellte Baudrate sowie zus„tzlich gesetzte + Flags an. + + d : Duplex. + c : CRC bzw. DCD bei 1k2-Modem. + r : ext. Takt (rx). + t : ext. Takt (tx). + e : ext. Takt beide (Vanessa). + m : Multibaud-Kopplung (Vanessa, SCC). + z : NRZ statt NRZI. + + Max: + eingestelltes MaxFrame. + + TXD: + eingestelltes TXDelay. + + PACL: + eingestellte PACLen. + + PERS: + eingestellte PERSistanz. + + SLOT: + eingestellte SLOTime. + + FRACK: + eingestellter FRACK. + + T2: + eingestellte T2 time. + + T3: + eingestellte T3 time. + + RET: + eingestellte RETries. + + DA: + Nummer des DAMA-Masters dieses Ports. Es sind vier unabhaengige + DAMA-Master verfuegbar. + + C: + Auf diesem Port werden die Texte ausgesendet. + + S: + Auf diesem Port ist der SYSOP-Mode aktiviert. Ein L2-Connect ist nur + mit Paáwort m”glich. + + M: + Auf diesem Port wird die MH-Liste gefhrt. + +(PO)RT * + Gibt eine Liste mit den aktuellen Port Parametern aus: + + DEFUNK:CB0DE>Port Parameters: + Max EAX- EAX- IPOLL IPOLL INTERLINK- L4- + -#-Port-------Con-MaxF-Mode-Paclen-Retry-Time-Retry-Auto-Hardware + 0:CB-Kanal76 3 16 1 128 3 120 3 0 KISS /tnn/TNC/kanal76 + 1:Internet 0 16 1 128 3 120 3 1 AX25IP + 2:Telnet 0 16 1 128 3 120 3 0 TELNET 23 + 3:HTTP 0 16 1 128 3 120 3 0 HHTPD 8080 + 4:Mailbox 0 16 1 128 3 120 3 0 KISS /dev/ttya0 + 5:Sysop 0 16 1 128 3 120 3 0 KISS /dev/ttya1 + 6:CVS-Server 0 16 1 128 3 120 3 0 IPCONV 3604 + + Nur TXDelay und MaxFrame werden noch vom Sysop eingestellt. Die anderen + Parameter stellt TNN selbst ein. + + TXDelay: + Sendervorlaufzeit nach dem Hochtasten des Senders bis zur Aussendung + des ersten Datenpaketes in Millisekunden * 10. + + Pers: + Persistence Wert (0-255). + + Slot: + Zeitschlitz-Intervall (Slot time intervall) in 10ms. Dieser + Parameter gibt die Dauer des Zeitschlitzes fr die Persistance- + Steuerung an. Jedesmal, wenn der TNC ein Paket ausstrahlen wollte + und die unter Slot-Time beschriebenen Zufallszahl auáerhalb des + Persistance-Bereich lag, wird dann fr die Dauer des Zeitschlitzes + gewartet und anschlieáend die Persistance-Prozedur erneut + durchlaufen. + + IRTT: + Bedeutet Initial-Round-Trip-Time und ist der Anfangswert fr die + RTT-Berechnung, also der Wert, der fr die erste Berechnung anstelle + von SRTT benutzt wird, wenn noch keine Messung erfolgen konnte. + + Der Timer 1 (wann soll der TNN Nachfragen, wenn er Deine Antwort + nicht geh”rt hat) berechnet sich wie folgt: + + Fr RETRIES kleiner gleich 3: T1 = SRTT * 3 + fr RETRIES gr”áer 3: T1 = SRTT * (RETRIES + 4) + + Beim Connecten wird SRTT aus dem IRTT berechnet (siehe Parms): + + SRTT = (DIGI*2 + 1) * IRTT + + Bei einem direkten Connect entspricht SRTT dann dem IRTT, mit Anzahl + DIGI wird es dann entsprechend gr”áer. Wenn nun auf einem Ports ein + IRTT = 500 = 5 Sekunden eingestellt wurde bedeutet das: + + Retry 1..3 -> T1 = 5 * 3 = 15 Sekunden bis zur Nachfrage ! + + z.B. bei Retry 6 -> T1 = 5s * ( 6 + 4 ) = 50s Sekunden !!! + + Bei laufendem Betrieb bewegt sich der SRTT dann dynamisch. + + MaxFrame: + Anwender-Link MaxFrame in Anzahl der Frames. Anzahl der Infopakete + auf Layer2-Ebene, die ohne Erhalt einer Best„tigung hintereinander + ausgesendet werden drfen. + + L2Retry: + Bestimmt die Anzahl der Versuche, um auf Layer2-Ebene Kontakt zu + einer anderen Station zu bekommen (Antwort auf Kommandos und Poll). + Nach dieser Anzahl von Versuchen wird der Link als defekt gemeldet, + falls keine Antwort erfolgt. + + Timer2: + Anwender-Link T2 in Millisekunden * 10. Dieser Timer bestimmt die + Wartezeit, nachdem ein eingehendes Informationspaket best„tigt wird + mit einem RR/REJ/RNR-Paket. Einerseits ist diese Verz”gerung zur + Durchsatzsteigerung da, weil man in diesem Intervall anderen eine + Chance zum Senden gibt, andererseits wird dem Sende-Layer die Chance + gegeben, eine Best„tigung in ein zu sendendes Infopaket zu packen + und somit ein Link-Layer-Paket einzusparen. (Das Ergebnis ist in der + Statistik abzulesen.) + +(Q)UIT + Verbindung wird vom Knoten aufgel”st (DISCONNECT). Dadurch ergibt sich + die M”glichkeit, zum vorher connecteten Knoten reconnected + (zurckverbunden) zu werden. Der Text QUIT.TXT wird vor dem Aufl”sen der + Verbindung gesendet. + +(QTH) (externer Befehl) + +(QTH) oder (QTH) + QTH berechnet Entfernung und Richtung zwischen zwei QTH-Kennern. Wird nur + ein QTH-Kenner angegeben, so wird die Entfernung zum Knoten berechnet ! + Auáerdem ermittelt QTH alle gltigen Angaben fr die Standorte, z.B. zur + Ermittlung des neuen weltweiten QTH-Kenner aus der geografischen + Koordinate. QTH akzeptiert sowohl den neuen weltweiten als auch den alten + QTH-Kenner. Auáerdem k”nnen L„ngen- und Breitengrade in Dezimalform oder + auch in Grad:Minuten:Sekunden angegeben werden. + +(QTH) + Berechnung der Entfernung und Richtung zwischen dem Standort des Knotens + und . + +(QTH) + Berechnung der Entfernung und Richtung zwischen und . + + Gltige Eingabeformate: + Alter QTH-Kenner : FM04C oder FM04C/2 (Ohne Angabe gilt Feldraster /2) + Neuer QTH-Kenner : JO52JW + + Geogr. Koordinate: GGG:MM:SS/GG:MM:SS z.B. 10:47:30/52:56:15 + (”stl.L„nge/n”rdl.Breite in Grad:Min:Sek) + + Geogr. Koordinate: GGG.GGG/GG.GGG z.B. 10.792/52.937 + (”stl.L„nge/n”rdl.Breite in Dezimalform) + + Es ist zu beachten, daá innerhalb einer geografischen Koordinate nur in + Grad:Minuten:Sekunden oder mit Gleitkommazahlen (Realzahlen) gearbeitet + werden kann. Ein Mischen beider Formate ist unzul„ssig. + +(R)OUTES + Zeigt die bestehenden Routen zu den Nachbarknoten an. + + Routes of DEFUNK:CB0DE (4/32) + Node----Typ-Po--Dst/Rou---L3SRTT[ms]---Maxtime[ms]State--Route---Contime + DBQ213 L 4 1/1 + KR2GAT I 1 348/264 0/0 6000 conn. 10d, 8h + DIG531 I 1 86/3 2/2 2000 conn. 10d, 8h + DNQ230 F 0 60/2 430/710 0 conn. 2h,45m + + Routes of DEFUNK:DE0DIG (5/32) + Die Routesliste ist auf das wesentliche gekrzt ! Die (5/32) + besagt, daá in der Linkliste 5 von 32 m”glichen Eintr„gen benutzt + sind. Die L„nge der Linkliste kann ggf. mit SET TNNCFG=xxxx,xx + angepaát werden. (siehe: START.BAT) "Nur bei TNN/Win32" + + NODE : + Anzeige des Rufzeichens des benachbarten Knotens. + + Type : + Gibt an, um welchen Typ es sich bei diesem Eintrag handelt. M”glich + sind: + + Type I : + Nachbar arbeitet mit dem neuen InterNode - Protokoll, in dem + TheNetNode nur Laufzeiten austauscht. + + Type L : + Local Call und Alias wird mit Laufzeit 4000 ms eingetragen. Es wird + keine Laufzeitberprfung durchgefhrt. + + Wird ein L+ eingesetzt, so wird das Ziel alle 5 Minuten connected. + Ist das Ziel QRV, so wird dieses mit der Laufzeit in die Routesliste + eingetragen und weiter gemeldet. + + Type F : + FlexNet Port arbeitet mit FlexNet Protokoll. + + Type N : + NetRom-Nachbar kann das Level-3 Protokoll alter Art, sendet jedoch + die Meáframes noch unprotokolliert zurck. + + Type N+ : + NetRom-Nachbar verwendet das neue Protokoll, wo unerreichbare Ziele + sofort abgemeldet werden. Die šbermittlung und Messung geschieht im + Level-3 nun protokolliert. + + Type N- : + NetRom-Nachbar verwendet das alte Protokoll. Nicht erreichbare Ziele + fallen auf Grund der Timer aus der Nodesliste. Die šbermittlung und + Messung geschieht im Level-2 als UI-Frames und damit NICHT + gesichert! + + Po : + Port, ber den die Verbindung l„uft. + + Dst : + Anzahl der Ziele die von dem Nachbarn gemeldet werden. + + L3SRTT[ms] : + Zeigt die von diesem Node ermittelte Laufzeit in Millisekunden an, + sowie die der Gegenseite. + + State setup : + Es wird versucht eine Verbindung zum Nachbarn aufzubauen. + + State conn. : + Die Verbindung zum Nachbarn ist erfolgreich aufgebaut worden und + bleibt von nun an bestehen. NUR wenn diese Level2 Verbindung + besteht, werden auch die NODES / DESTINATIONEN von diesem Nachbarn + in die bernommen. Damit werden nun Zielknoten aus dem Netz + entfernt, die nicht sicher zu erreichen sind oder zu denen der Link + nur in einer Richtung besteht. + + Route : + Digipeater, die nicht das TheNet-Protokoll benutzen bis zum + eingetragenen TheNet-Knoten. + +(R)OUTES (V)ersion : + Zeigt zus„tzlich den Softwarestand der Nachbarknoten mit an und was fr + ein Broadcast dahin gemacht wird. + info-broadcast = Alter TheNet Broadcast, + UI-broadcast = Broadcast wird gesichert im Level 3 bertragen, + differential-broaccast = Es werden nur die Žderungen bertragen. + +(S)TAT : + Gibt die Statistik, die im Knoten gefhrt wird, aus. Mit (S)TAT werden + jedoch nur noch die Kopfdaten ausgegeben. + + Weitere Statistiken: + (S)tat (*) Ausgabe aller Statistiken; + (S)tat (E)rrorKopf und Error-Statistik; + (S)tat (H)ardware Kopf und Hardware-Statistik; + (S)tat (I)p Kopf und TCPIP-Statistik; + (S)tat (K)ernel-Interface (nur Linux) + (S)tat (L)ink Kopf und Link-Statistik; + (S)tat (P)ortsKopf und Port-Statistik. + + Die Kopfdaten .... + + System Statistics: 01.06.05 00:00:13 - 21.04.05 16:29:58 + Startup: 21.04.05 16:29:58 + Runtime: 50d,32m + + (min) (now) (max) + Rounds/sec: 337 737 1487 + Free Buffers: 9247 9769 10000 + Overall Throughput: 32400 158208 Baud + Active L2-Links: 109 179 + Active Circuits: 25 53 + Active Nodes: 399 411 + + TNN Load: 2% + Sysload: 5.60% + Loadavg: 0.05 0.06 0.00 + CPU time used: user 2374ms, system 3710ms + Buffer usage: 4% + Network Heap: 1817800 Bytes + + System Statistics: + Datum und Uhrzeit des letzten L”schens der Statistik sowie das + Auslesedatum und - Uhrzeit. Wichtig bei automatischen Abrufen der + Statistik fr Diagramme. + + Startup: 21.04.05 16:29:58 + Letzter Neustart der Software. + + RunTime: 50d,32m + Laufzeit des Programmes in Tagen/Stunden,Minuten. + + Die folgenden Angaben sind jeweils der: minimaler Wert aktueller Wert + maximaler Wert + + Rounds/sec: + Gibt die Hauptschleifendurchl„ufe des Programmes an. + + Free Buffers : + Zeigt die freien Buffer des Knotens an. + + Ein Buffer sind 64 Info-Byte und 8 Listenzeiger-Byte, insgesamt also + 72 Byte. Jede zwischengespeicherte Informationen belegt Buffer, die + Liste anderer bekannter Knoten belegt Buffer. Der Sinn, diese Anzahl + freier Buffer dem Anwender mitzuteilen, ist, daá es keinen Zweck + hat, bei einer sehr geringen Anzahl freier Buffer (< ca. 300) + Connects zu probieren. Denn wenn TheNetNode keinen freien Buffer + mehr zur Verfgung hat, wird ein Reset ausgel”st, der alle + bestehenden Verbindungen mit totalem Informationsverlust l”scht. Im + Normalbetrieb ist dieser Fall aber nahezu ausgeschlossen, da bei + normal gesetzten TheNetNode-Parametern eigentlich nie zu wenig + Buffer vorhanden sein k”nnen (man kann nicht beliebig viele Pakete + hintereinander im Knoten "abladen"). + + Overall Throughput : + Zeigt den Datendurchsatz des Knotens an. Hierbei handelt es sich um + reine Infodaten ohne Protokoll- und Overheadbytes ! + + Aktive L2-Links : + Anzeige der Anzahl der aktiven und maximal gleichzeitig + vorgekommenen Level-2-Verbindungen. + + Active Nodes: + Hier wird die Anzahl der derzeit bekannten Nodes angezeigt. Die + zweite Anzahl gibt die maximal eingestellte Anzahl der verwaltbaren + Nodes an. (Dieses ist die n„chste Primzahl nach der unter TNNCFG = + eingestellten Gr”áe.) + + Aktive Circuits : + Anzeige der Anzahl der aktiven und maximal gleichzeitig + vorgekommenen Circuit-Verbindungen. Hier werden natrlich nur die + Verbindungen angezeigt, die auf diesem Knoten beginnen oder enden. + Alle anderen Verbindungen werden ja virtuell durch das Netz geleitet + und brauchen nicht auf jedem Knoten verwaltet zu werden. + + CPU load : 39% + Zeigt die Auslastung der CPU an. + + Buffer usage : 14% + Verh„ltnis zwischen belegten und zur Verfgung stehenden Buffern in + %. + + Network Heap: + Sind die durch Routing - Infos belegten Bytes. + + Free RAM (Fmem) : + Freier Hauptspeicher fr DOS. Bei der DPMI-Version der freie + Gesamtspeicher (bis 16 MB). + + Die Hardware - Statistik.... + + Tokenring-Statistics: + + Tokens/sec: 92 161 180 + TOKENRING load: 11% + + Token ring speed: 38400 Bit/s. + Token-Recoveries: 1 + Bad-Frames: 0 + TNC#1 RxAdr: 0 RxErr: 0 + TNC#3 RxAdr: 0 RxErr: 0 + + Tokens/sec: + Zeigt die Aktivit„ten des Tokenringes an. + + TOKENRING load : 36% + Zeigt die Auslastung des Tokenring an. + + Tokenring speed: 38400 Bit/s. + Anzeige der eingestellten Baudrate des Tokenringes. + + Token-Recoveries: + Sind Abfragen an die TNC, die nicht wieder zum Rechner zurckkommen. + Sie werden mit Anzahl, Datum und Uhrzeit angezeigt. + + BAD Frames: + Defektes oder falsches Token. Diese Fehler werden auf Port 0 + gez„hlt, da nicht festgestellt werden kann, auf welchem port der + Fehler entstanden ist. + + TNC#1 RxAdr: 0 RxErr: 0: + Sowie Fehler der einzelnen TNC. + + RxAdr Fehler: + ? + + RxErr Fehler: + ? + + KISS-Statistics: + KISS1 RxCRC: 0 RxErr: 0 + + KISS1 RxCRC: 0 RxErr: 0 + Fehler dieser Kiss - Schnittstelle. + + RxCRC Fehler: + Ein Frame mit falscher CRC wurde auf einem SMACK- oder RMNC-Kisslink + empfangen. Diese Fehler werden erkannt und sind unkritisch, weisen + aber auf eine schlechte šbertragung hin. + + RxErr Fehler: + ? + + External-Statistics: + TNN-ETH TxErr: 0 RxOvr: 0 OFlow: 0 IOErr: 0 + + Fehler die durch externe Treiber entstehen. + + TxErr Fehler: + ? + + RxOvr Fehler: + ? + + Oflow Fehler: + ? + + IOErr Fehler: + ? + + Die Error - Statistik.... + + Error-Statistics: + + RxID RxLen RxCtl Resets + 0:70cm_1200 26 0 0 0 + 1:70cm_9600 347 0 0 2 + 2:23cm_9600 383 3 0 0 + 3:Lohfelden 170 3 0 2 + 4:Cluster 0 0 0 0 + 5:Mailbox 0 0 0 2 + 6:Goettingen 0 0 0 0 + + RxID Fehler: + ? + + RxLen Fehler: + ? + + RxCtl Fehler: + ? + + Resets: + Anzahl der Resets der entsprechenden Port Hardware (Vanessakarten + oder TNC im Tokenring). + + Die IP - Statistik .... + + IP-Gateway-Statistics: + + ipForwarding: 1 ipDefaultTTL: 10 ipInReceives: 0 + ipInHdrErrors: 2 ipInAddrErrors: 0 ipForwDatagrams: 2 + ipInUnknownProtos: 0 ipInDiscards: 0 ipInDelivers: 0 + ipOutRequests: 1 ipOutDiscards: 0 ipOutNoRoutes: 2 + ipReasmTimeout: 30 ipReasmReqds: 0 ipReasmOKs: 0 + ipReasmFails: 0 ipFragOKs: 0 ipFragFails: 0 + ipFragCreates: 0 + + ipForwarding: + 0 = IP-Router ausgeschaltet + 1 = IP-Router eingeschaltet + + ipDefaultTTL: + Time-to-live fuer von TNN erzeugte IP-Pakete + + ipInReceives: + Anzahl empfangene IP-Pakete + + ipInHdrErrors: + Anzahl fehlerhafter IP-Header + + ipInAddrErrors: + Anzahl fehlerhafter IP-Adressen + + ipForwDatagrams: + Anzahl weitergeleiteter IP-Datagramme + + ipInUnknownProtos: + Anzahl IP-Rahmen mit unbekannten Protokollen + + ipInDiscards: + Anzahl geloeschter IP-Rahmen + + ipInDelivers: + ???????? + + ipOutRequests: + ???????? + + ipOutDiscards: + Anzahl geloeschter Pakete + + ipOutNoRoutes: + Anzahl IP-Pakete, fuer die keine Route vorhanden war + + ipReasmTimeout: + Anzahl der wegen Zeitueberschreitung nicht zusammengesetzter + fragmentierter IP-Pakete + + ipReasmReqds: + Anzahl notwendiger IP-Framezusammensetzungen + + ipReasmOKs: + Anzahl erfolgreich zusammengesetzter IP-Fragmente + + ipReasmFails: + Anzahl gescheiterter IP-Fragmentzusammensetzungen + + ipFragOKs: + Anzahl IP-Fragmente + + ipFragFails: + Anzahl fehlgeschlagener IP-Fragmenterzeugungen + + ipFragCreates: + Anzahl erzeugter IP-Fragmente + + Die Link - Statistik .... + + Bytes total I RR REJ RNR %RR %REJ %RNR + Link to DB0GOE 06.03.94 06:38:27 - 06.03.94 21:03:18 + RX: 4373648 44196 23645 2154 188 30 2 0 + TX: 14631652 78768 27066 238 220 61 0 0 + Link to DB0AX 06.03.94 06:38:27 - 06.03.94 21:03:17 + RX: 1295328 16120 14472 636 0 42 1 0 + TX: 6824718 33662 11907 6 0 73 0 0 + Link to DB0NHM 06.03.94 06:38:27 - 06.03.94 21:03:15 + RX: 931191 5796 9626 663 1124 61 4 7 + TX: 2915931 15564 6895 407 3 118 7 0 + + Bytes total I RR REJ RNR %RR %REJ %RNR + Beschriftungszeile der Linkstatistikzahlen RX bzw. TX: + + RX bzw. TX: + Bytes total Byte insgesamt, + I Infoframe, + RR Best„tigungs-Frame, + REJ Reject-Frame, + %RR RR Frames/gesendete I Frames in %, + %REJ REJ Frames/gesendete I Frames in %, + %RNR RNR Frames/gesendete I Frames in %. + + %RR: + Ziel ist es, nicht jedes einzelne I Frame zu best„tigen sondern nach + M”glichkeit mehrere I-Frames mit einem RR-Frame zu best„tigen. + Hierfr ist der T2-Timer zust„ndig. Andererseits darf aber auch die + Gegenstelle nicht zu schnell pollen. Dieses Poll-Frame wird wiederum + mit einem RR-Frame best„tigt. + + %REJ: + Gibt Auskunft ber die Qualit„t eines Interlinks. + + %RNR: + Gibt Auskunft ber die Verarbeitungsgeschwindigkeit der Gegenstelle. + RNR gibt es aber auch, wenn die Gegenstelle zu wenig Speicher hat. + + %: Derzeit werden noch ALLE auf dem Interlink laufenden Frames + ausgewertet. Ist der Level-2-Verkehr freigegeben, so werden + natrlich auch REJ, RNR usw. von den Level-2-Verbindungen mit + aufgenommen. Diesen Unterschied kann man aus der Statistik von + DB0EAM besonders gut ablesen. Auf dem Interlink nach DB0AX ist im + Gegensatz zu dem Interlink nach DB0GOE der Level-2-Verkehr nicht + zugelassen. Nach DB0AX greifen die Steuerfunktionen des Level-3/4 + Protokolles. Es kommt nur sehr selten zu einem RNR- Frame. + Andererseits kann man hier auch den konsequenten HF-Technischen + Aufbau (keinerlei gegenseitige Beeinflussung der Interlinks) von + DB0EAM ablesen. Wurden von DB0AX in der Regel 2,4% der Pakete + rejected, so sind es in der Gegenrichtung fast 0%. Auf dem Interlink + nach DB0KH k”nnte das nur nach Sperrung des Level-2 festgestellt + werden. Vergleicht man nun die Statistik von DB0NHM und DB0AX (sind + zwar nur 23 Stunden, aber in der Tendenz gleichbleibend), so sieht + man deutlich den gravierenden Nachteil eines Level2-Systems wie + FlexNet. Die groáe Anzahl von RNR wird ber ALLE Teilstrecken, ber + die der Level-2 aufgebaut wurde, bertragen. Auf dem Interlink nach + DB0AX ist Level-2-Digipeating gesperrt, und damit steuert der Level- + 3/4 den Datenfluá. Genauso nachteilig verh„lt sich das + Best„tigungsverhalten von FlexNet-Nachbar. + + Link to - . + Diese Rufzeichen-Statistik zeigt an, wann die Statistik zuletzt + gel”scht worden ist, und wann das letzte Byte empfangen worden ist. + + Die Port - Statistik .... + + Links RxB TxB RxBaud TxBaud RxOver TxOver + 0:70cm_1200 6/5 5387k 52340k 64 208 83% 8% + 1:70cm_9600 4/3 27434k 576083k 56 104 42% 1% + 2:23cm_9600 4/1 10524k 60302k 392 248 6% 12% + 3:Lohfelden 5/2 20441k 119742k 48 48 46% 9% + 4:Cluster 23/1 68199k 31129k 128 48 10% 59% + 5:Mailbox 21/1 2011M 588261k 4720 1616 2% 17% + 6:Goettingen 1/1 176951k 424651k 496 1216 8% 2% + + Total = 922.987.789 Bytes + + In der Statistik werden nur die Info-Byte erfaát! + + 0: + Port Nummer und Portname. + + Links x/y + x = Anzahl der l2 Verbindungen + y = Anzahl unterschiedlicher Call. + Links wird fr die Einstellung der automatischen Parameter + gebraucht. + + RxB ... TxB + Empfangene ... gesendete Datenmenge in Byte; k = Kilobyte; M = + Megabyte; G = Gigabyte. + + RxBaud ... TxBaud + Momentane Empfangsseitige ... Sendeseitige Linkbelastung. + + RxOver ... TxOver + Prozentuales Verh„ltnis von Nutzdatenbertragung zu + Protokolldatenbertragung. + + Total = Bytes. + Summe aller empfangenen und gesendeten Byte. + + (TA)LK + Schaltet eine TALK-Verbindung zu dem User mit dem . Als Quittung + der Eingebende wenn der User mit dem Kommandointerpreter verbunden ist: + You are now talking with DL0EAM. Laeve this mode with /q. Alle weiteren + Eigaben bekommt der User als: Msg from dl0eam: text............ Dieses + ist jedoch nur eine einseitige Verbindung. + +(SAT) (externer Befehl) + Zeigt die derzeit 40 m”glichen Satelliten sowie eine kurze Hilfe an. + +(SAT) + Berechnet die Satellitenposition zum Zeitpunkt der Abfrage, bezogen auf + den Standort des Knotens. Ausgegeben werden nicht nur die Positionsdaten, + sondern auch die n”tigen Antennen-Einstellungen. + +(SAT) oder (SAT) + Wie zuvor, jedoch wird nicht der Locator des Knotens, sondern der + angegebene verwendet. + + Gltiges Eingabeformat: + Geogr. Koordinate: GGG.GGG GG.GGG z.B. 10.792 52.937 + (”stl.L„nge/n”rdl.Breite in Dezimalform) + +(SAV)ecall (externer Befehl) + +(SAV)ecall + Die Felder k”nnen mit (SAV)ecall ausgefllt oder ge„ndert werden. + + SAVECALL /N .... . . . . . ..... 30 Zeichen fr den Namen + SAVECALL /Q .... . . . . . ..... 30 Zeichen des Wohnortes + SAVECALL /L ...... 6 Zeichen des World-Locators + SAVECALL /D ....... 7 Zeichen fr Eingabe des DOK + SAVECALL /V ......... 9 Zeichen QRV auf ... Digi + SAVECALL /M .................... 25 Zeichen Mybbs der Mailbox + SAVECALL /T .... . . . . . ..... 40 Zeichen fr freien Text + ( ein * als Text l”scht diesen Eintrag ) + SAVECALL /* ==> Vorsicht !! l”scht den ganzen Eintrag ! + + DOK Bitte so eintragen: F73 oder F73/Z25 + .....sonst klappt es mit dem Suchen nachher nicht. + +(SH)owcall (externer Befehl) + +(SH)owcall + Ist ein kleines Programm, welches die Visitenkarten der User, die sie + sich selbst SAVECALL erzeugt haben, ausliest und anzeigt. Muster: + + == ShowCall ====================================== 01.09.95 === + = Call : ...... Name : .............................. = + = Loc : ...... QTH : .............................. = + = QRV on : ......... MyBBS : .................... = + = Dok : ....... Update : JJMMTTHH CALL = + = = + = Free MSG : ........................................ = + ================================================== de DG3AAH == + + Die Liste lebt von der Beteiligung der User. Deshalb darf nur der darin + lesen und suchen der selbst zumindest die Felder Name, Locator und QTH + eingetragen hat. Das kann auch in Verbindung den Platzhaltern "*" + und "?" aufgerufen werden. Dabei steht "*" fr beliebig viele Zeichen und + "?" steht fr genau 1 Zeichen. Es wird eine Liste der Calls aus, + bestehend aus : + - Call, Name, Wohnort und Locator. + Die ersten 3 Zeichen mssen jedoch angegeben werden, damit nicht + unendliche Listen ausgelesen werden. + +(SH)owcall W + Zeigt die Anzahl der Eintr„ge an. + +(SO)FTWARE (externer Befehl) + Gibt eine Softwarebeschreibung aus. + +(SPE)ECH + Zeigt welche Sprechen im System vorhanden sind. + +(TA)LK + Mit TALK kann man einem User eine Textzeile zusenden, wenn dieser + mit dem Kommandointerpreter des Knotens verbunden ist. Besteht zu dem + User keine Verbindung vom Kommandointerpreter, so wird die Textzeile bis + zu einem Reconnect aufgehoben. Wird die Verbindung durch einen Disconnect + vom User aufgel”st, wird die Textzeile .....fachgerecht und gebhrenfrei + entsorgt. + +(TI)ME + Gibt das Systemdatum und die Uhrzeit aus. + +(TOP) (externer Befehl) + Dieser Aufruf wertet die MHEARD.TAB aus und erzeugt eine "Hitliste". Die + Auswertung ist nicht immer auf dem neuesten Stand. Die Datei MHEARD.TAB + wird in Abh„ngigkeit des Parameters 11 aktualisiert. Der aktuelle Stand + kann an der Uhrzeit im Kopf der Tabelle abgelesen werden. + +(TOP) + Gibt eine Liste mit der L„nge bis maximal aus. + +(TOP) - + Gibt eine Liste von 10 Calls, die auf dem bekannt sind, aus. + +(TOP) - + Gibt eine Liste mit der L„nge bis maximal , die auf diesem + bekannt sind, aus. + +(TOP) + Gibt nur dieses Rufzeichen, aber mit den verschiedenen registrierten SSID + aus. + +(TOP) + Z.B.: TOP DG8B* . Gibt alle Rufzeichen aus, die mit DG8B anfangen. + +(TOP) -L3 + Wertet statt der MHEARD.TAB die L3HEARD.TAB aus. In der werden die Links + gespeichert. Der Parameter -l3 kann mit -port und anzahl verknpft + werden. + +(TOP) -h + Gibt eine kurze Hilfe aus. + +(TOP) -v + Zeigt den Versionsstand an. + + MHEARD-Auswertung vom 01.11.97 08:33 UTC bis 07.11.97 22:07 UTC + + Nr. Call Port Rx Tx Summe % RxRej TxRej Dama + 1 DB0CXH CUX 5700751 40803866 46504617 47 571 6931 0 * + 2 DB0WHV WHV 14771265 8463332 23234597 23 865 881 0 + 3 DL3BCO 70cm 6702818 157864 6860682 6 32 0 4 + 4 DB0DIM CUX 1479456 3923212 5402668 5 62 2919 0 #* + 5 DG3BAF 70cm 2757348 175502 2932850 2 12 0 0 + 6 DG8BR 70cm 1969490 269554 2239044 2 64 0 0 # + 7 DG9BJY 70cm 2014585 48985 2063570 2 1 0 0 + + . Hat Call empfangen ---! ! ! ! ! ! ! ! + . Hat Call gesendet ---------------! ! ! ! ! ! ! + . Hat Call ber den Digi bertragen ----------! ! ! ! ! ! + . Hat Call Anteil an Digiauslastung --------------! ! ! ! ! + . Hat Call gesendet, weil schlecht geh”rt --------------! ! ! ! + . Hat Call empfangen, weil Digi schlecht geh”rt --------------! ! ! + . Hat Call gegen DAMA verstoáen -----------------------------------! ! + . Call hat * = VIA gearbeitet ----------------------------------! + . Call ist # = mit unterschiedlichen SSID auf Ports QRV --------! + + 103 DL6BI 70cm 1333 15 1348 0 0 0 0 + 104 DG6BAF 70cm 975 135 1110 0 0 0 0 + 105 DK5BO 70cm 773 190 963 0 0 0 0 + 106 DB0MHD CUX 87 355 442 0 0 0 0 + + Ausgewertet wurden alle Ports. + Die aufgelisteten Benutzer haben 98.405.235 Bytes = 100 % šbertragen. + Insgesamt wurden 98.405.235 Bytes von 106 User bewegt. + + Falls sich jemand ber die Differenz zwischen Pl„tze und User wundert: + Sie entsteht wenn ein Benutzer auf mehreren Ports aktiv ist. Z.B.: 70cm + und 23cm. Oder so... Tatsache ist, es wird das Rufzeichen nur einmal + gez„hlt. + + Beispiel fr eine Einzelausgabe: + + Datum Port Rx Tx RxRej TxRej D Call Via + 31.03.95 22:53 70cm 7528028 1917008 120 0 0 DG3BAF + 31.03.95 22:32 70cm 314818 3684301 13 0 0 DG3BAF-2 + 30.03.95 10:08 70cm 0 5 0 0 0 DG3BAF-15 DL1BKL + 25.03.95 09:49 70cm 23946 65179 1 0 0 DG3BAF-1 + 03.03.95 10:07 70cm 1175 438 0 0 0 DG3BAF-4 + + Die Liste erkl„rt sich wohl von selbst. + + Unter D stehen die DAMA-Verst”áe, und unter Via steht der, der sich als + Digipeater zur Verfgung gestellt hat. + +(TEL)NET Server + Ein simpler Telnet-Server. + +(TR)ACE OPTIONEN PORT + Dieser Befehl dient zum erkennen und finden von Fehlern. Es stehen folgende + Optionen zur Verfgung. + + Optionen: + U = Unprotokollierten Paketen, + I = Info Paketen, + S = Kontroll Paketen, + C = Monitor an auch bei bestehendem Connect, + H = HEADER, bei I-Frames nur den Header anzeigen, der + Infoteil der Frames wird unterdrckt, + F = FULL, I-Frames mit Infoinhalt anzeigen, es werden die + kompletten Frames gemonitort, + = Nur der angegebene Port wird gemonitort, + + = Nur diese Call (bis zu 8) monitoren, + - = Diese Call im Monitor unterdrcken. + + Beispiel: TR fusci 2 + +(U)SER + Nach der Eingabe von U (fr USER) erscheint z.B.: + + DENET1:KR2GAT> TheNetNode (Linux) (CB) V1.79mh03_rev40 (19459) + Uplink(DQA230) N:KR1GAT <--> (DQA230 <> DNX213-5) P5 CVS-Server + Uplink(DAD213-2) N:KR1GAT + Uplink @ Dessau:KR1GAT + Uplink(DIG396-1) N:DIG396 <--> (DIG396-1 <> KR2GAT-6) P5 CVS-Server + Uplink(DIX393-1) N:DIX393 <--> (DIX393-1 <> KR2GAT-6) P5 CVS-Server + Uplink(DNO920-1) N:DNO920 <--> (DNO920-1 <> KR2GAT-6) P5 CVS-Server + + DENET1 Ist der "ALIAS" des Knotens, eine Art Pseudonym. Zum einen soll + dieser ALIAS eine geographische Information bieten, die einfacheres + Zuordnen unbekannter Calls zu einem Gebiet erm”glicht. Zum anderen + erm”glicht, im Gegensatz zum IDENT (Rufzeichen), der ALIAS ein + mehrfaches Connecten eines Knotens, denn man kann z.B.: + + DENET1, DENET2, DENET3, + + etc. gleichzeitig connecten, aber nur einmal KR2GAT. + + Die andere M”glichkeit, Multiconnect an einem TheNet-Knoten + durchzufhren, ist die Benutzung des eigenen Rufzeichens mit + verschiedenen SSID gleichzeitig. Das kann derzeit aber nicht jede + Software. Als ALIAS wird in DL h„ufig des Autokennzeichens des + Haupteinzugsbereiches verwendet, kurze Ortsnamen k”nnen auch + vorteilhaft ausgeschrieben werden, wodurch der Erkennungswert weiter + zunimmt. Andere Alternativen wie z.B. Postleitzahlen oder WW- + Locatoren sind nicht sehr einpr„gsam. + + Die Verwendung des ALIAS, statt des Rufzeichens, ist K E I N + Rufzeichenmiábrauch, da der ALIAS ja gar keinen den internationalen + Normen fr Amateurfunkrufzeichen entsprechenden Aufbau hat (haben + sollte...). Genausowenig wie ja auch ein Ruf an CQ oder Test kein + Rufzeichenmiábrauch ist oder das 4-Zeichen Call bei Amtor. Die + geforderte Rufzeichen-Nennung alle 10 Minuten wird vom Netzknoten + mit einer Bakenaussendung an ID ausgefhrt, in der auch der + verwendete ALIAS mitgeteilt wird. Auáerdem bleibt die Verwendung des + ALIAS im AX25-Adreáfeld auf Endanwender begrenzt, zwischen den + Knoten selbst werden die offiziellen IDENT (Rufzeichen) benutzt. + Auch l„át sich jeder TheNet-Knoten anhand des INFO-, USER- und + NODES-Befehles identifizieren. Eine einheitliche Verwendung von + Autokennzeichen in Knotenlisten erh”ht die Transparenz der Netze + wesentlich. + + KR2GAT + Ist das offizielle IDENT (Rufzeichen) des TheNet-Knotens. + + Uplink + Zeigt an, daá der Benutzer mit dem Rufzeichen hier am Knoten + in das Netz eingestiegen ist. Etwa vorhandene Digipeater werden in + der n„chsten Zeile angezeigt. + + Downlink + Zeigt an, daá der Benutzer hier mit dem Rufzeichen das Netz + verl„át. Etwa vorhandene Digipeater werden in der n„chsten Zeile + angezeigt. + + Host + Bedeutet eine Verbindung zum Bedienerterminal des Knotens. + + CQ + Kann nur auf der rechten Seite erscheinen und zeigt, daá der + Benutzer "CQ" ruft. Um eine Verbindung zu ihm aufzubauen, muá das + mit der SSID im Connect-Befehl abgegeben werden. + + <--> + Zeigt eine bestehende Verbindung an. + + <..> + Zeigt eine im Aufbau befindliche Verbindung an. + + Ein Eintrag ohne "rechte Seite" bedeutet, daá die Verbindung hier + zur Zeit endet und der Benutzer mit dem Befehlsinterpreter des + Knotens verbunden ist. + + Uplink @ Dessau:KR1GAT + Zeigt den Einstiegsknoten des User an, sofern dieser nicht aus der + Circuit-Zeile bereits hervorgeht. Dieses ist immer dann der Fall, + wenn mehrere Level4-Verbindungen (Circuits) nacheinander aufgebaut + werden. + + Downlink Port_5 via DB0XYZ oder Uplink Port_5 via DB0XYZ + Zeigt den Downlink-Weg an, den der User genommen hat. >Port_5< steht + in diesem Fall fr Port-Namen des entsprechenden Port (siehe (PO)rt + Befehl) und ist ein Level2-Interlink. + +(U)ser h + Wie (U)ser, zeigt zus„tzlich die Convershost-Verbindungen an. + +(U)ser + + Zeigt in Tabellenform die Level2-Verbindungen an...... + + DENET1:KR2GAT> TheNetNode (Linux) (CB), 1.79mh03_rev40 (19474) + L2 - User: + PO SrcCall DstCall LS Rx Tx Tr SRTT RxB TxB Baud ConTime Pr Da + -------------------------------------------------------------------------- + 1 KR2GAT DNO275 IXF 0 0 0 50 109928k 685912k 1413 5d,21h - + 1 KR2GAT D12KFG IXF 0 0 0 50 4583 9 253 1d,0h - + 1 KR2GAT DNX995 IXF 0 0 0 50 259713 188 200 3d,10h - + 1 KR2GAT FIN6CN IXF 0 0 0 50 50776 6325 15 2h,0m - + 1 KR2GAT BO2NOD IXF 0 0 0 50 273953k 169538k 1330 5d,20h - + 1 KR2GAT FC6NOD IXF 0 0 0 50 451216 189109 377 2h,1m - + 1 KR2GAT DLGNOD IXF 0 0 0 229 104530 2955 33 2d,8h - + 1 KR2GAT DNQ504 IXF 0 0 0 50 508806 794267 128 2d,6h - + 1 KR2GAT CB0RG IXF 0 0 0 50 2293k 2220k 128 3d,0h - + 1 KR2GAT KR4GAT IXF 0 0 0 208 9860 23822 96 39m,12s - + 1 KR2GAT DIX393 IXF 0 0 0 246 2239k 3437k 136 3d,2h - + 1 KR2GAT DNX354 IXF 0 0 0 50 2053k 2223k 120 3d,2h - + 1 KR2GAT I45HES IXF 0 0 0 50 6020k 2651k 96 7d,3h - + 1 KR2GAT D11KFG IXF 0 0 0 50 71066 66668 96 3h,36m - + 1 KR2GAT DNX233 IXF 0 0 0 50 6446 20086 96 37m,47s - + 1 KR2AGT CB0SFT-1 IXF 0 0 0 104 78228 591668 112 3h,35m - + 1 KR2GAT NB1BKM-1 IXF 0 0 0 50 94387 93401 96 3h,36m - + 1 KR2GAT DIG233 IXF 0 0 0 50 21540 24779 120 38m,10s - + 1 KR2GAT PRKT10 IXF 0 0 0 50 4653 27953 128 12m,21s - + 1 KR2GAT KR1GAT IXF 0 0 0 50 5630k 4861k 120 6d,18h - + 1 KR2GAT DIX956 IXF 0 0 0 50 11820 8823 552 6m,23s - + 1 KR2GAT KB0BLD IXF 0 0 0 66 30971 24786 96 50m,13s - + 1 KR2GAT GF1DIG IXF 0 0 0 50 4544k 4575k 160 6d,21h - + 1 KR2GAT CB0GBZ IXF 0 0 0 50 1606k 2576k 144 7d,2h - + 1 KR2GAT DOK346 IXF 0 0 0 50 1037k 1109k 344 1d,16h - + 1 KR2GAT KR3GAT IXF 0 0 0 50 107858 189871 152 3h,17m - + 1 KR2GAT DNO404 IXF 0 0 0 50 184898 216233 112 7h,21m - + 1 KR2GAT CB0DLN-8 IXF 0 0 0 50 5999k 5332k 520 9d,14h - + 1 KR2GAT DIG396 IXF 0 0 0 50 60936 74319 168 1h,32m - + 1 KR2GAT AS1NOD REJ 0 0 0 50 108014 91700 192 3h,36m - + 1 KR2GAT CB0NET IXF 0 0 0 207 27023 50862 104 1h,29m - + 1 KR2GAT CB1NET IXF 0 0 0 224 1112k 739736 120 1d,4h - + 1 KR2GAT DNX580 IXF 0 0 0 177 795 795 0 2s - + 1 KR2GAT LNK989 IXF 0 0 0 50 76149 14340 232 15m,50s - + 1 KR2GAT DNX2DB IXF 0 0 0 116 193373 184141 840 8h,1m - + 1 KR2GAT DNO459 IXF 0 0 0 50 22473 122805 144 1h,36m - + 1 KR2AGT KR1BOX-8 IXF 0 0 0 144 18 152 24 3m,42s - + / / / / / / / / / / / / / + 1) 2) 3) 4) 5) 6) 7) 8) 9) 10) 11) 12) 13) + + 1) Benutzter Port zur einfacheren šbersicht. + 2) Quellrufzeichen des L2-QSOs. + 3) Zielrufzeichen des L2-QSOs. + 4) L2-Link-Status: + SET = Link-Setup, + FMR = Frame Reject, + DRQ = Disconnect Request, + HTH = Wartet auf Connect eines Digipeating-Zieles, + IXF = Info Transfer, + REJ = REJ Send, + WAK = Waiting Acknowledge, + DBS = Device Busy, + RBS = Remote Busy, + BBS = Both Busy, + WDB = Waiting Ack and Device Busy, + WRB = Waiting Ack and Remote Busy, + WBB = Waiting Ack and Both Busy, + RDB = REJ Send and Device Busy, + RRB = REJ Send and Remote Busy, + RBB = REJ Send and Both Busy. + 5) Anzahl der empfangenen Frames in der Warteschlange fr diesen Link. + 6) Anzahl der noch zu sendenden Frames in der Warteschlange fr diesen + Link + Wenn ein Link zu einem Nachbarn zusammenbricht, wird dieser bei mehr + als 100 ausstehenden Paketen im L2 einfach abgebrochen. + 7) Anzahl Retries. + 8) Stand des 'Smoothed Round Trip Timers'(in mal 10 ms). + 9) Anzahl empfangender Bytes seit Bestehen des Links. + 10) Anzahl gesendeter Bytes seit Bestehen des Links. + 11) Aktuelle effektive Baudrate fr diesen Link. + 12) Connectzeit in HH:MM:SS und bei ber 23:59:59 Stunden dann nur noch + als TTT/HH:MM. + 13) Bei DAMA-Netzeinstiegen: + Aktuelle Priorit„t des User (0: = h”chste Priorit„t). + + .......und auch die Level4-Verbindungen. + + L4 - User: + Call Node S Rx Tx Tr Win SRTT RxB TxB Baud ConTime + ----------------------------------------------------------------------------- + DQA230 KR1GAT I 0 0 0 10 7425 696 16898 80 3h,40m + DAD213-2 KR1GAT I 0 0 0 10 1075 6 793 48 12m,43s + DIG396-1 DIG396 I 0 0 0 10 2620 61024 1419k 48 5d,3h + DIX393-1 DIX393 I 0 0 0 10 2042 70971 1532k 96 5d,14h + DNO920-1 DNO920 I 0 0 0 10 2670 54939 1389k 48 4d,21h + KR1BOX-8 DNO920 I 0 0 0 10 1000 72 9 8 3m,39s + / / / / / / / / / / / / + 1) 2) 3) 4) 5) 6) 7) 8) 9) 10) 11) 12) + + 1) Rufzeichen des User. + 2) Call des Knotens mit dem der User verbunden ist. + 3) L4-Circuit-Status. + S = Circuit-Setup, + .I = Eigener Knoten steht im Choke (Datenbertragung angehalten), + I. = Der Zielknoten steht im Choke, + I = Normaler Info-Transfer, + D = Disconnect-Request. + 4) Anzahl der empfangenen Frames in der Warteschlange fr diesen + Circuit. + 5) Anzahl der noch zu sendenden Frames in der Warteschlange fr diesen + Circuit. + 6) Anzahl Transport-Retries. + 7) Transport Fenstergr”áe. + 8) L4 SRTT. + 9) Anzahl empfangender Bytes seit Bestehen des Circuits. + 10) Anzahl gesendeter Bytes seit Bestehen des Circuits. + 11) Aktuelle effektive Baudrate fr diesen Circuit. + 12) Connectzeit in HH:MM:SS und bei ber 23:59:59 Stunden dann nur noch + als TTT/HH:MM. + + Zur Messung des L4SRTT: + Durch den Aufbau des NET/ROM Layer 4 kann man Grunds„tzlich nur in + Senderichtung den SRTT messen, d.h. immer wenn wir Info senden, + messen wir die Laufzeit. Von dem L4SRTT wird haupts„chlich das + Acknowledge - Timeout und das Requery - Timeout abgeleitet. + + Acknowledge - Timeout: + Der L4 kann Daten Senden, bis ein sogenanntes Sendefenster voll ist. + Dieses umfaát in der Regel 10 Frames. Das Sendefenster wird beim + Verbindungsaufbau zwischen den Partnern vereinbart und ist auf + beiden Seiten gleich. Danach wird auch das Acknowledge(Best„tigung) + - Verhalten ausgerichtet. Sobald das Empfangsfenster halb voll ist, + wird sofort eine Best„tigung gesendet, sp„testens aber nach der + einfachen L4SRTT-Zeit. Damit wird einerseits ein st„ndiger Fluá + sichergestellt, andererseits werden unn”tige ACK verhindert. + + Requery - Timeout: + "Requery" ist hier eigentlich nicht richtig, denn NET/ROM hat keine + Kommandos in Empfangsrichtung. Dies bedeutet, das nach einer + bestimmten Zeit das Frame vom Sender wiederholt werden muá, der + Empf„nger kann nicht mitteilen, das er das Frame nicht bekommen hat. + Man spricht von Requery-by-Timeout, man k”nnte auch sagen + Retransmission-Timeout. Dieser Timeout wird wieder vom L4SRTT + abgeleitet, mit Faktor 3. + + Was sagt uns das? + Ein sehr hoher SRTT-Wert (sagen wir 100s) bedeutet nicht, das diese + Verbindung wirklich so lahm ist, sondern einfach das dort wenig los + ist, und beide seiten sehr selten ein ACK schicken. Da wir sowieso + beim halben Fenster ein ACK schicken, kann die Verbindung jederzeit + schnellen Datentransfer aufnehmen. Andererseits ist es richtig, das + solche Links mit sehr langen Requery - Timeout belegt werden, + schlieálich k”nnte es sein, das der Partner sich einfach lange Zeit + l„át fr die Best„tigung (hoher L4SRTT). Die hier vorgestellten + Abl„ufe sind TCP/IP entliehen und den besonderen Anforderungen von + NET/ROM angepaát. Da TCP/IP mit Antwortzeiten im Millisekunden - + Bereich arbeitet, wir aber bei einigen Sekunden, wird sich erst + zeigen, ob das alles so richtig hinhaut. Durch Begrenzungen nach + unten und oben ist in der Soft sichergestellt, das nicht + allzuschiefe "automatische" Timerwerte generiert werden k”nnen. + + TCPIP-User: + Iface SrcCall DesCall NT T3 RxB TxB Baud ConTime + ------------------------------------------------------------------------ + IPConv: DIX393-1 KR2GAT-6 17983 17983 1532k 70971 96 5d,14h + IPConv: DQA230 DNX213-5 17760 17760 16898 696 80 3h,40m + IPConv: DIG396-1 KR2GAT-6 17983 17983 1419k 61024 48 5d,3h + IPConv: DNO920-1 KR2GAT-6 17983 17983 1389 54939 48 4d,21h + +(U)ser (L)inks + Zeigt in Tabellenform NUR die Level2-Verbindungen an. + +(U)ser (C)ircuit + Zeigt in Tabellenform NUR die Level4- (Circuit -) Verbindungen an. + +(U)ser + Zeigt in Tabellenform NUR die Level2-Verbindungen des angegebenen Ports + an. + +(U)ser + Zeigt nur den bestimmten User an. Dabei sind die folgenden Abfragen + m”glich : + u db7*; + u db7kg* zeigt aber auch db7kga, db7kgb, db7kgc usw. aber auch alle SSID + von DB7KG; + u db7kg zeigt db7kg-0 an; + u db7kg-15 zeigt db7kg-15an; + u db7kg-* geht NICHT + + L2 - User: + + Po SrcCall DstCall LS Rx Tx Tr SRTT RxB TxB Baud ConTime Pri + -------------------------------------------------------------------------- + 2 KS-5 DG9FU-5 IXF 0 0 0 95 2624 96563 96 2:13:33 - + 2 KS-6 DG9FU IXF 0 0 0 85 176 5367 72 1:07:41 - + + Uplink(DG9FU-5) <--> Convers(DG9FU-5) Ch 170 + Uplink 23cm_9600 + Uplink(DG9FU) + Uplink 23cm_9600 + + DG9FU de DB0EAM (16:52) > + +(V)ERSION + Gibt die aktuelle Versionsnummer der Software aus. + +(V)ERSION + + Zeigt die Version und die Compiler Switches an. + +(IPC)ONV + IP-CONVERS ist ein weiteres TCPIP-Feature nach TELNET und HTTPD. + + Somit ist eine Kopplung TNN<>Saupp per IP kinder leicht. + Weitere Funktionen des IP-Convers-Server: Tel/Web-Zugang + + (IRC-Modus ist in Arbeit, geht aber nicht so schnell) :-) + diff --git a/contrib/output/makefile b/contrib/output/makefile new file mode 100755 index 0000000..4d5f8f8 --- /dev/null +++ b/contrib/output/makefile @@ -0,0 +1,115 @@ +######################################################################## +# # +# ***** ***** # +# ***** ***** # +# ***** ***** # +# ***** ***** # +# *************** *************** # +# ***************** ***************** # +# *************** *************** # +# ***** ***** TheNetNode # +# ***** ***** Portable # +# ***** ***** Network # +# ***** ***** Software # +# # +# File contrib/output/makefile (maintained by: DF6LN) # +# # +# Copyright (C) 1998 - 2004 NORD> +#define inportb(adr) inb(adr) +#define outportb(adr, data) outb(data, adr) +#define port_adresse 0x378 /* LPT 1 */ +#else /* GO32 */ +#include +#define port_adresse _farpeekw(_dos_ds,0x00408) +#endif + +char version[] = __NAME__ ", Version " __VER__ __AUTHOR__ + " ("__DATE__ ", " __TIME__ ")\r"; + +/*----------------------------------------------------------------------*/ +/* Fehler im Aufruf melden */ +/*----------------------------------------------------------------------*/ +void usage_error(void) +{ + puts(version); + printf("Syntax: OUTPUT [ <0|1>]\n"); + printf(" (using io-port 0x%x)\n", port_adresse); + exit(1); +} + +/*----------------------------------------------------------------------*/ +/* Port Bit setzen */ +/*----------------------------------------------------------------------*/ +void set_port(int io_port) +{ + if (io_port < 8) + { + outportb(port_adresse, (inportb(port_adresse) | (0x01 << io_port))); + /* setzt STROBE-Bit auf LOW-Position (invertiert) */ + outportb(port_adresse + 2, (inportb(port_adresse + 2) | (0x01 << 0))); + /* 400ms warten */ + usleep(400000); + /* setzt STROBE-Bit auf HIGH-Position (invertiert) */ + outportb(port_adresse + 2, (inportb(port_adresse + 2) & ~(0x01 << 0))); + } + else + usage_error(); +} + +/*----------------------------------------------------------------------*/ +/* Port Bit loeschen */ +/*----------------------------------------------------------------------*/ +void reset_port(int io_port) +{ + if (io_port < 8) + { + outportb(port_adresse, (inportb(port_adresse) & ~(0x01 << io_port))); + /* setzt STROBE-Bit auf LOW-Position (invertiert) */ + outportb(port_adresse + 2, (inportb(port_adresse + 2) | (0x01 << 0))); + /* 400ms warten */ + usleep(400000); + /* setzt STROBE-Bit auf HIGH-Position (invertiert) */ + outportb(port_adresse + 2, (inportb(port_adresse + 2) & ~(0x01 << 0))); + } + else + usage_error(); +} + +/*----------------------------------------------------------------------*/ +/* Port Bit lesen */ +/*----------------------------------------------------------------------*/ +int read_port(int io_port) +{ + if (io_port < 8) + return((inportb(port_adresse) >> io_port) & 1); + else + { + usage_error(); + return(0); + } +} + +/*----------------------------------------------------------------------*/ +/* Port Status anzeigen */ +/*----------------------------------------------------------------------*/ + +void show_port(void) +{ + int ioport; + + printf("\nOutput-Status:\n 7 6 5 4 3 2 1 0\n"); + for (ioport = 7; ioport >= 0; ioport--) + printf(" %1.1d", read_port(ioport)); + + printf("\n"); +} + +/*----------------------------------------------------------------------*/ + +int main(int argc, char *argv[]) +{ + int bit = -1; + +#ifdef __LINUX__ + /* direkten Portzugriff beim Kernel anfordern */ + if (ioperm(port_adresse, 3, 1)) + { + perror("Can't get permissions for port-access. (Are you \'root\' ?)"); + exit(1); + } +#endif + + if (argc == 2) /* Nur Status ausgeben */ + { + show_port(); + return(0); + } + + if (argc == 4) /* Port setzen/loeschen, 4 da TNN Rufzeichen anfuegt */ + { + switch (*argv[2]) + { + case '0': bit = atoi(argv[1]); + + if (bit < 0 || bit > 7 ) + { + usage_error(); + exit(1); + } + + reset_port(bit); + show_port(); + break; + + case '1': bit = atoi(argv[1]); + + if (bit < 0 || bit > 7 ) + { + usage_error(); + exit(1); + } + + set_port(bit); + show_port(); + break; + + default: usage_error(); + exit(1); + } + return(0); + } + usage_error(); + +#ifdef __LINUX__ + /* Port wieder freigeben */ + if (ioperm(port_adresse, 3, 0)) + { + perror("Can't release io-permissions !"); + exit(1); + } +#endif + + return(1); +} + +/*----------------------------------------------------------------------*/ +/*--- Ende von output.c ---*/ diff --git a/contrib/pfhadd/makefile b/contrib/pfhadd/makefile new file mode 100755 index 0000000..a6f7afb --- /dev/null +++ b/contrib/pfhadd/makefile @@ -0,0 +1,110 @@ +######################################################################## +# # +# ***** ***** # +# ***** ***** # +# ***** ***** # +# ***** ***** # +# *************** *************** # +# ***************** ***************** # +# *************** *************** # +# ***** ***** TheNetNode # +# ***** ***** Portable # +# ***** ***** Network # +# ***** ***** Software # +# # +# File contrib/pfhadd/makefile (maintained by: DF6LN) # +# # +# Copyright (C) 1998 - 2004 NORD> +#define inportb(adr) inb(adr) +#define outportb(adr, data) outb(data, adr) +#define port_adresse 0x378 /* LPT 1 */ +#else /* GO32 */ +#include +#define port_adresse _farpeekw(_dos_ds,0x00408) +#endif + +char version[] = __NAME__ ", Version " __VER__ __AUTHOR__ + " ("__DATE__ ", " __TIME__ ")\r"; + +/*----------------------------------------------------------------------*/ +/* Fehler im Aufruf melden */ +/*----------------------------------------------------------------------*/ +void usage_error(void) +{ + puts(version); + printf("Syntax: OUTPUT [ <0|1>]\n"); + printf(" (using io-port 0x%x)\n", port_adresse); + exit(1); +} + +/*----------------------------------------------------------------------*/ +/* Port Bit setzen */ +/*----------------------------------------------------------------------*/ +void set_port(int io_port) +{ + if (io_port < 8) + { + outportb(port_adresse, (inportb(port_adresse) | (0x01 << io_port))); + /* setzt STROBE-Bit auf LOW-Position (invertiert) */ + outportb(port_adresse + 2, (inportb(port_adresse + 2) | (0x01 << 0))); + /* 400ms warten */ + usleep(400000); + /* setzt STROBE-Bit auf HIGH-Position (invertiert) */ + outportb(port_adresse + 2, (inportb(port_adresse + 2) & ~(0x01 << 0))); + } + else + usage_error(); +} + +/*----------------------------------------------------------------------*/ +/* Port Bit loeschen */ +/*----------------------------------------------------------------------*/ +void reset_port(int io_port) +{ + if (io_port < 8) + { + outportb(port_adresse, (inportb(port_adresse) & ~(0x01 << io_port))); + /* setzt STROBE-Bit auf LOW-Position (invertiert) */ + outportb(port_adresse + 2, (inportb(port_adresse + 2) | (0x01 << 0))); + /* 400ms warten */ + usleep(400000); + /* setzt STROBE-Bit auf HIGH-Position (invertiert) */ + outportb(port_adresse + 2, (inportb(port_adresse + 2) & ~(0x01 << 0))); + } + else + usage_error(); +} + +/*----------------------------------------------------------------------*/ +/* Port Bit lesen */ +/*----------------------------------------------------------------------*/ +int read_port(int io_port) +{ + if (io_port < 8) + return((inportb(port_adresse) >> io_port) & 1); + else + { + usage_error(); + return(0); + } +} + +/*----------------------------------------------------------------------*/ +/* Port Status anzeigen */ +/*----------------------------------------------------------------------*/ + +void show_port(void) +{ + int ioport; + + printf("\nOutput-Status:\n 7 6 5 4 3 2 1 0\n"); + for (ioport = 7; ioport >= 0; ioport--) + printf(" %1.1d", read_port(ioport)); + + printf("\n"); +} + +/*----------------------------------------------------------------------*/ + +int main(int argc, char *argv[]) +{ + int bit = -1; + +#ifdef __LINUX__ + /* direkten Portzugriff beim Kernel anfordern */ + if (ioperm(port_adresse, 3, 1)) + { + perror("Can't get permissions for port-access. (Are you \'root\' ?)"); + exit(1); + } +#endif + + if (argc == 2) /* Nur Status ausgeben */ + { + show_port(); + return(0); + } + + if (argc == 4) /* Port setzen/loeschen, 4 da TNN Rufzeichen anfuegt */ + { + switch (*argv[2]) + { + case '0': bit = atoi(argv[1]); + + if (bit < 0 || bit > 7 ) + { + usage_error(); + exit(1); + } + + reset_port(bit); + show_port(); + break; + + case '1': bit = atoi(argv[1]); + + if (bit < 0 || bit > 7 ) + { + usage_error(); + exit(1); + } + + set_port(bit); + show_port(); + break; + + default: usage_error(); + exit(1); + } + return(0); + } + usage_error(); + +#ifdef __LINUX__ + /* Port wieder freigeben */ + if (ioperm(port_adresse, 3, 0)) + { + perror("Can't release io-permissions !"); + exit(1); + } +#endif + + return(1); +} + +/*----------------------------------------------------------------------*/ +/*--- Ende von output.c ---*/ diff --git a/contrib/top/config.top b/contrib/top/config.top new file mode 100755 index 0000000..0450845 --- /dev/null +++ b/contrib/top/config.top @@ -0,0 +1,21 @@ +# Configdatei fuer TOP +# Alle Angaben die nicht gelesen werden sollen muessen eine # am Zeilen- +# anfang haben. +# +P0 = Port0 +P1 = Port1 +P2 = Port2 +P3 = Port3 +P4 = Port4 +P5 = Port5 +P6 = Port6 +P7 = Port7 +P8 = Port8 +P9 = Port9 +P10 = Port10 +P11 = Port11 +P12 = Port12 +P13 = Port13 +P14 = Port14 +P15 = Port15 +# Ende der Datei diff --git a/contrib/top/makefile b/contrib/top/makefile new file mode 100755 index 0000000..c8b15c8 --- /dev/null +++ b/contrib/top/makefile @@ -0,0 +1,106 @@ +######################################################################## +# # +# ***** ***** # +# ***** ***** # +# ***** ***** # +# ***** ***** # +# *************** *************** # +# ***************** ***************** # +# *************** *************** # +# ***** ***** TheNetNode # +# ***** ***** Portable # +# ***** ***** Network # +# ***** ***** Software # +# # +# File contrib/pfhadd/makefile (maintained by: DG8BR) # +# # +# Copyright (C) 1998 - 2004 NORD> +#include +#include +#include +#include +#ifdef __MSDOS__ + #include + #include +#endif +#if defined(__linux__) || defined(__GO32__) + #include + #include + #include +#endif + +#ifdef WIN32 +#include +#include + +#define Seperator '\\' +#endif /* WIN32 */ + +/* prototypen */ + +int get_ftime (int); /* Dateizeit der MHEARD.TAB holen */ +void config_lesen (void); /* config-file einlesen */ +char grossbuchstabe (char); /* meine toupper-Version */ +void prozent (unsigned long, unsigned long, char*); /* Prozentberechnung */ +void ssid_weg ( char* ); /* die SSiD von Call entfernen */ +void benutzung (void); /* Kurzhilfe ausgeben */ +void einles (int, int); /* Hauptleseroutine */ +void addier (void); /* Bytes der einzelnen Call's addieren */ +void sortier (int, int); /* nach Menge sortieren, Plaetze vergeben, Ausgabe */ +char* punkte (char*, unsigned long); /* Zahl mit 100ter Punkte */ +void callraus (char*); /* Einzelausgabe von Call */ +int callcmp (char*, char*, int); /* Call mit Call vergleichen */ + +/* globale Variablen */ + +char VERSION[] = "TOP v1.06g ("DATUM") (c) DG8BR"; + +struct line { /* Struktur fuer die Daten. Speicherbedarf 52 Bytes */ + struct line *naechster; /* naechster Eintrag */ + unsigned int platz; + unsigned long gesamt; + time_t heard; /* Uhrzeit */ + unsigned long tx; /* gesendete Bytes */ + unsigned long rx; /* empfangene Bytes */ + unsigned int d; /* Damaverstoesse */ + unsigned int t; /* gesendete Rejects */ + unsigned int r; /* empfangene Rejects */ + unsigned int mhport; /* Digiport */ + unsigned int flag; /* Call aktiv */ + char call[10]; + char via[10]; + int dummi; /* fuer die verschiedene Via's */ + } *liste; +struct line *listenanfang; /* Eintrag der ersten Station der Liste */ +time_t Dateianfang; /* Wann die MHEARD.TAB gegonnen wurde. */ +time_t filetime; /* entspricht dem Listenende */ +char zeitzone[3] = "UTC"; /* Zeitzonenbezeichnung */ +unsigned long max; /* Gesamtbytes ueber alles */ +int max_user; /* alle gezaehlten Benutzer */ +int max_nenner; +char filename[12]; +struct kanal { /* hier wird die config.top abgelegt */ + char name[11]; + unsigned long gesamt; + } port[16]; /* Port0 -Port15 */ + +/*---------------------------------------------------------------------------- +* Zeit der MHEARD.TAB holen. Wird als bis-Zeit genommen. Damit sollte egal +* in welcher Reihenfolge die Daten stehen, bzw. wie durcheinander sie sind. +*/ +int get_ftime(int handle) +{ +#ifdef WIN32 +#else + struct stat filestat; + + if (fstat(handle, &filestat) == -1) + return(-1); + filetime = filestat.st_mtime; /* filetime ist 32bit-Zahl */ +#endif + return(0); +} + +/*---------------------------------------------------------------------------- +** Config-File einlesen +** Wird von main aufgerufen. Rueckgabewert: Keiner +** +** Diese Datei sollte in dem TNN-Pfad stehen. +** +** Config sollte folgendermassen aussehen: +** #Beispiel fuer den Einstieg. Alle Zeilen ohne # werden eingelesen +** P0 = 70cm +*/ + +void config_lesen (void) +{ + FILE *ein; + char buffer[81]; + char standard[] = "P 0"; + int a; + + if ((ein = fopen("config.top","rt")) != NULL) + { + while(!feof(ein)) + { + fgets(buffer,80,ein); + if((buffer[0] != '#') && (strlen(buffer) > 1)) /* nur lesen wenn # */ + { /* und Zeile > 1 */ + a = atoi(&buffer[1]); /* Portnummer holen */ + strtok(buffer," ="); + if ( buffer[0] == 'P' ) + strcpy(port[a].name ,strtok(NULL," =\n\r")); /* Portnamen */ + } + } + } + for ( a = 0; a < 16; a++) /* PORT wird nun von 0-15 eingerichtet */ + { + if (port[a].name[0] == EOS) /* wenn der Port nicht von der Config */ + strcpy(port[a].name,standard); /* versorgt wurde */ + + if ( standard[2] == '9' ) /* wenn 9 dann auf 0 setzen und das */ + { /* vorherige Byte auf 1 */ + standard[1] = '1'; + standard[2] = '0'; + } + else + standard[2]++; /* wenn nicht, dann nur erhoehen */ + } + #ifdef DEBUG + printf("config erfolgreich.\n"); + #endif +} +/*---------------------------------------------------------------------------- +** Diese Routine wurde aus dem TNN-Packet entnommen. +** Erdacht hat sie DG9AML. Von mir an TOP angepasst. +*/ +void prozent (unsigned long zaehler, unsigned long nenner, char *resultstr) +{ + int i, zaehlernull; + char tmp[32]; + tmp[0] = EOS; + *resultstr = EOS; + zaehlernull = 0; + if (nenner == 0) /* dividiert durch 0 ergibt eine Fehlermeldung */ + { + zaehler = 0L; + nenner = 1L; + } + + if (zaehler / nenner != 0) /* 100er Stelle */ + { + sprintf(tmp, "%s%lu", resultstr, zaehler / nenner); + strcpy(resultstr,tmp); + } + else + zaehlernull = 1; +/* Solange der zaehler kleiner nenner ist wird der zaehler um eine 10-potenz +** hoeher. Da bei 4,3G grossen Zahlen ein Ueberlauf stattfinden wuerde, +** werden beide Zahlen um eine 10er-potenz gekuerzt. +*/ + if ( zaehler > 430000000L) + { + zaehler = zaehler / 10; + nenner = nenner / 10; + } + zaehler = (zaehler % nenner) * 10; + if (zaehlernull != 1 || zaehler / nenner != 0) /* 10er Stelle */ + { + sprintf(tmp, "%s%lu",resultstr, zaehler / nenner); + strcpy(resultstr,tmp); + } + if ( zaehler > 430000000L) + { + zaehler = zaehler / 10; + nenner = nenner / 10; + } + zaehler = (zaehler % nenner) * 10; + sprintf(tmp, "%s%lu", resultstr, zaehler / nenner); /* 1er Stelle */ + strcpy(resultstr,tmp); + if ( zaehler > 430000000L) + { + zaehler = zaehler / 10; + nenner = nenner / 10; + } + zaehler = (zaehler % nenner) * 10; + strcat(resultstr, "."); + + for (i = 0 ; i < 2; i++) /* 2 Kommastellen */ + { + sprintf(tmp, "%s%lu", resultstr, zaehler / nenner); + if ( zaehler > 430000000L) + { + zaehler = zaehler / 10; + nenner = nenner / 10; + } + zaehler = (zaehler % nenner) * 10; + strcpy(resultstr,tmp); + } + return; +} + + +/*---------------------------------------------------------------------------- +** meine Version von 'toupper' +*/ + +char grossbuchstabe ( char buchstabe ) +{ + if ( buchstabe > 'Z' ) + buchstabe -= ' '; + return ( buchstabe ); +} +/*---------------------------------------------------------------------------- +** Die SSID vom call entfernen. +** Return ist ein String ohne SSID +** Es gibt kein eigentliches Return. Es wird direkt der Eintrag via Zeiger +** geaendert. +*/ +void ssid_weg (char *callmit) +{ + char *callohne; + + for (callohne = callmit; *callohne; callohne++) + if ( *callohne == '-' ) + *callohne = EOS; +} +/*----------------------------------------------------------------------------- +** Kurzanleitung ausgeben +*/ + +void benutzung (void) +{ + printf("\n"); + printf(" Befehlssyntax Bedeutung Beispiel\n\n"); + printf(" TOP alle Port, 10 Plaetze TOP\n"); + printf(" TOP Anzahl <*> soviel Plaetze, alle Ports TOP 45\n"); + printf(" TOP -Port einen Port, 10 Plaetze TOP -0 \n"); + printf(" TOP Anzahl -Port soviel Plaetze, ein Port TOP 30 -0\n"); + printf(" TOP -Port Anzahl ein Port, soviel Plaetze TOP -0 30 \n"); + printf(" TOP Call nur ein Rufzeichen TOP dg8br\n"); + printf(" TOP Ca* Alle Call's mit DL TOP dl*\n"); + printf(" TOP -L3 Die L3HEARD auswerten\n"); + printf(" TOP -v Version\n"); + printf(" TOP -h dieses hier\n\n"); + printf("Weitere Hilfe gibt es mit 'Help Top'\n"); /* Hinweis auf Help */ +} + + +/*---------------------------------------------------------------------------- +** Vergleicht 2 Calls miteinander. +** Beide calls werden ohne SSId geliefert. +** Returnwert : bei Gleichheit 0, sonst 1 +** call1 == das Call das gesucht wird. +** call2 == mit dem wird verglichen +** wird von addier und callraus aufgerufen +*/ + +int callcmp ( char *call1 , char *call2, int len ) +{ + while ( len-- ) /* Call wird zeichenweise verglichen */ + if (*call1++ != *call2++ ) /* bei Gleichheit return mit 0 */ + return (1); + return (0); +} + +/*---------------------------------------------------------------------------- +** Die Gesamt-Zahl der Endsummen werden zwecks besserer Lesbarkeit +** mit 100ter Punkte versehen. +** Wird von sortier aufgerufen. +** Rueckgabe : gepunkteter String +*/ + +char* punkte (char *string, unsigned long all) +{ + char temp[20]; /* Hilfsstring */ + char *tp = temp; /* Zeiger auf temp */ + int a = 0; /* Zaehler fuer Punkte */ + int b = 0; /* Zaehler Returnstring */ + + while ( all ) /* Solange das Ende von all nicht erreicht */ + { +#ifdef WIN32 + *tp++ = (char)((all % 10) + '0'); /* Zahl/10 und den Rest verasscien */ +#else + *tp++ = (all % 10) + '0'; /* Zahl/10 und den Rest verasscien */ +#endif /* WIN32 */ + all = all / 10; /* Quelle muss auch geteilt werden */ + + a++; + if ( a == 3 && all != EOS) /* Punkt einfuegen */ + { + *tp++ = '.'; + a = 0; + } + } + *tp = EOS; + + a = strlen(temp); + + while ( a ) /* und nun kopieren, aber von hinten nach vorne */ + string[b++] = temp[--a]; + + string[b] = EOS; + return(string); +} + +/*---------------------------------------------------------------------------- +** Generelle Einleseroutine. Wird von main aufgerufen. +** Es wird immer fuer einen Eintrag dynamisch Speicher allociert. +** Und auch nur ein Eintrag zur Zeit gelesen. +** Der erste Speicherplatz hat auch schon gueltige Daten. Der letze Eintrag +** hat im "naechster" ein NULL stehen!! Es geht bis zum NULL-Eintrag!! +** User die im TX oder RX nichts haben, werden eingelesen aber wenn keine +** Einzelausgabe gewuenscht sofort wieder geloescht. +** Wird von main aufgerufen. +** +** Der CONFPATH wird nun vom Programm ermittelt. Es wird also bei der Linux- +** Version kein globaler CONFPATH-Eintrag mehr benoetigt. Bei der DOS(GNU32) +** wird es aber gesetzt, aber nicht genutzt. Bei der Linux-Version wird der +** Eintrag auch gesetzt, gilt aber nur fuer den TNN-Task. +** +** neues Format der MHEARD.TAB jetzt reiner ASCII +** Erster Eintrag ist der neuste Eintrag. +** Aufbau : Zeit im PC-Format , RX-Bytes , TX-Bytes , Port +** rx-rej , tx-rej , dama-verstoesse , Call +** +** Bespiel: 855398713 1083577 170775 2 1 8 2 DG9FU-15 +*/ + +void einles (int alles, int Gesamt) +{ + FILE *ein; + int a = 0; + char buffer[81]; + char file[81]; + char *fp; + struct line *indexalt = NULL; /* Hilfszeiger um alten Eintrag zufinden */ + int kontrolle = 0; /* Zaehler der eingelesenen Datensaetze */ + *file = EOS; + + if(getcwd(file,80) == NULL) /* Pfad feststellen */ + { + printf("\nKonnte den Pfad nicht ermitteln !\n"); + exit(0); + } + if(*(fp = file + strlen(file)) != Seperator) + { + *fp++ = Seperator; /* Seperator anhaengen */ + *fp = EOS; /* und schulz */ + } + strcat(file,filename); + + if (( ein = fopen (file , "rb")) == NULL) + { + printf ("\n%s nicht gefunden!\n", file); + exit (0); + } + + if (get_ftime(fileno(ein)) != 0) + printf("\nEndezeit kann nicht ermittelt werden !\n"); + + while (!feof(ein)) + { + if ((liste = malloc(sizeof(struct line))) == NULL) + { + printf("Kein Speicher!!! %d Datensaetze eingelesen.\n",kontrolle); + kontrolle = sizeof(struct line); + printf("Eine Datenzeile benoetigt %d Bytes.\n",kontrolle); + printf("Bitte diese Zeilen mit Digicall mir, DG8BR, zuschicken!!"); + exit(0); + } + kontrolle++; + if (( fgets (buffer, 80, ein )) != NULL) + { + if ( buffer[0] == ':' ) /* dann wurde die MHEARD begonnen */ + { /* ist ab der 1.74xx drin */ + sscanf ( buffer+1, "%lu", (unsigned long *)&Dateianfang ); + continue; + } + liste->via[0] = EOS; + liste->call[0] = EOS; + + sscanf (buffer ,"%lu %lu %lu %u %u %u %u %u %s %s", + (unsigned long *)&liste->heard ,&liste->rx ,&liste->tx ,&liste->mhport, + &liste->d, &liste->r ,&liste->t ,&liste->flag,liste->call, + liste->via); + if(Gesamt == 0) + { + if(alles == 1 && ((liste ->tx == 0L) || (liste->rx == 0L))) + { + free(liste); + continue; /* Bei Summenausgabe, nur Leute mit gueltigen Daten */ + } + } + if ( alles == 1 ) /* Bei Summenausgabe, die SSId weg */ + ssid_weg (liste->call); + + liste->dummi = ' '; + liste->gesamt = 0L; + + if ( a == 0 ) + { + listenanfang = liste; /* Damit wird der 1.te Eintrag gefunden */ + indexalt = liste; /* beim 1.ten Mal muss hier gespeichert werden */ + a++; + } + indexalt->naechster = liste; /* im vorherigen Eintrag den Naechsten */ + indexalt = liste; /* eintragen. Und dann den Alten auf neu setzen */ + } + } + indexalt->naechster = NULL; /* Sonst wird das Ende der Liste nicht bemerkt*/ + fclose(ein); + #ifdef DEBUG + printf("%d Datensaetze eingelesen.\n",kontrolle); + printf("einles erfolgreich.\n"); + #endif +} + +/*---------------------------------------------------------------------------- +** Alle Bytes eines Call's zusammenzaehlen. Es werden bis auf einen Listen- +** eintrag alle ungueltig gemacht. +** Ermittelt fuer die globalen Variablen max und port.gesamt die Werte. +** Wird von main aufgerufen. +** +*/ + +void addier (void) +{ + struct line *index = NULL; /* Zieleintrag */ + struct line *indexalt = NULL; /* vorheriger Eintrag beim Durchsuchen */ + + liste = listenanfang; /* Und nu geht es los */ + while ( liste != NULL ) + { + index = liste; /* call uebernehmen */ + indexalt = liste; /* aktuell merken */ + liste = liste->naechster; /* und weiterschalten */ + + while ( liste != NULL) + { + if (!callcmp (index->call, liste->call, 6 )) /* call gleich ?? */ + { + if (index->mhport == liste->mhport) /* und Port gleich ?? */ + { + index->tx += liste->tx; /* a weng rechnen */ + index->rx += liste->rx; + index->t += liste->t; + index->r += liste->r; + index->d += liste->d; + indexalt->naechster = liste->naechster; /* Listenplatz aendern */ + free ( liste ); /* und den Alten wech */ + liste = indexalt->naechster; /* zurueck auf aktuellen Stand */ + } + else /* Call gleich, aber anderer port */ + { + if (index->dummi != '#') /* wenn noch nicht gekennzeichnet */ + { + index->dummi = liste->dummi = '#'; + max_user--; /* Jedes Call wird nur einmal gezaehlt */ + } + indexalt = liste; + liste = liste->naechster; /* und weiterschalten */ + } + } + else /* call nicht gleich */ + { + indexalt = liste; /* aktuell merken */ + liste = liste->naechster; /* und weiterschalten */ + } + } + index->gesamt = index->tx + index->rx; /* Ergebnisse speichern */ + index->platz = 0; + + max_user++; + max += index->gesamt; /* Gesamtdurchsatz des Digi's */ + port[index->mhport].gesamt += index->gesamt; /* Portdurchsatz */ + liste = index->naechster; /* zurueck */ + } + #ifdef DEBUG + printf("addier erfolgreich.\n"); + #endif +} + +/*---------------------------------------------------------------------------- +** Suche nach der groessten Zahl und zwar nehme 1.te Zahl und vergleiche mit +** der naechsten. Ist sie groesser, nehmen, sonst naechsten Platz. Wenn Zahl +** gefunden, wird ein Platz vergeben und es beginnt von vorne. Die Liste +** wird nur nach gueltigen Listenplaetzen durchsucht. D.h. nur wenn Platz = 0 +** ist. +** Hier ist nun auch die Ausgabe. Ausgegeben wird bis Anzahl erreicht. Die +** Liste wird trotzdem bis zum Ende durchsucht um die Anzahl der Benutzer +** zubekommen. +** Wird von main aufgerufen. +** +*/ + +void sortier (int anzahl, int ports) +{ + int a; + int c = 0; /* Ausgabeplatz */ + char f[32]; + unsigned long aktu; + unsigned long alleszusammen = 0L; + char tmp[15]; /* Rueckgabevariable fuer gepunkteten String */ + struct line *indexplatz = NULL; /* hat zur Zeit das meiste */ + /* und wird ausgegeben */ + struct tm *ts; + + liste = listenanfang; /* von Vorne suchen */ + + while ( liste != NULL ) + { + a = 0; + aktu = 0L; /* und wieder auf 0, damit wieder richtig gefunden wird */ + + while ( liste != NULL ) /* Es wird immer die ganze Tabelle durchsucht */ + { +#ifdef WIN32 + if((liste->platz == 0) && (liste->mhport == (unsigned int)ports || ports == 'a')) +#else + if((liste->platz == 0) && (liste->mhport == ports || ports == 'a')) +#endif /* WIN32 */ + { /* platz gueltig, dann mit aktu vergleichen */ + if ((liste->gesamt) >= aktu) /* wenn aktu > gesamt */ + { /* dann neuen aktu uebernehmen */ + aktu = liste->gesamt; /* um die Plaetze zuerhalten */ + indexplatz = liste; /* der hat die meisten, uebernehmen */ + a = 1; /* Flag setzen fuer fuendig geworden */ + } + } + liste = liste->naechster; + } + if (a == 1) /* Es wurde was gefunden */ + { + indexplatz->platz = 5000; /* Pseudo-Platznummer vergeben */ + if ( c == 0 ) /* nur beim 1ten mal */ + { + ts = localtime(&Dateianfang); /* Zeit von Anfang holen */ + if (!strcmp(filename, "mheard.tab")) + printf("\n\n MHEARD-Auswertung"); + else + printf("\n\n L3MHEARD-Auswertung"); + + printf(" vom %02d.%02d.%02d %02d:%02d %.3s", + ts->tm_mday, + ts->tm_mon+1, + ts->tm_year%100, + ts->tm_hour, + ts->tm_min, + zeitzone); + + ts = localtime(&filetime); /* Zeit von Listenende */ + + printf(" bis %02d.%02d.%02d %02d:%02d %.3s\n",ts->tm_mday, + ts->tm_mon+1, + ts->tm_year%100, + ts->tm_hour, + ts->tm_min, + zeitzone); + printf("\nNr. Call Port Rx Tx " + "Summe %%"); + + if (!strcmp( filename,"mheard.tab")) + printf(" RxRej TxRej Dama\n"); + + c++; /* nun Platzzaehler */ + } + if ( ports == 'a' ) /* Alle Ports ausgeben ? */ + prozent(indexplatz->gesamt,max, f); + else + prozent(indexplatz->gesamt ,port[ports].gesamt,f); + /* Prozentsatz des Users berechnen */ + printf("\n%3u %-6s %-10s %10lu %10lu %10lu %5s", + c,indexplatz->call,port[indexplatz->mhport].name,indexplatz->tx, + indexplatz->rx,indexplatz->gesamt,f); + + if (!strcmp( filename , "mheard.tab")) + { + printf(" %5u %5u %4u %c",indexplatz->t,indexplatz->r, + indexplatz->d,indexplatz->dummi); + if ( indexplatz->via[0] != EOS ) /* via gibt es nicht mehr */ + printf("*"); + } + else /* L3MHEARD */ + printf(" %2c",indexplatz->dummi); + + alleszusammen += indexplatz->gesamt; + c++; /* Anzahl erhoehen */ + liste = listenanfang; /* und wieder an Anfang gehen */ + } + if ( c > anzahl ) + break; + } + if (c == 0 ) /* was gefunden ? */ + { + if ( ports != 'a' ) + printf("\nFuer diesen Port sind keine Daten in der MHEARD-Tabelle!\n"); + else + printf("\nKeine Daten in der MHEARD-Tabelle!\n"); + } + else + { + if ( ports == 'a' ) + { + prozent(alleszusammen,max,f); + printf("\n\nDiese User haben auf allen Ports %s Bytes = %s %%" + " uebertragen.\n",punkte( tmp,alleszusammen ), f); + } + else + { + prozent(alleszusammen,port[ports].gesamt,f); + printf("\n\nDiese User haben auf Port %d (%s) %s Bytes = %s%%" + " uebertragen.\n",ports,port[ports].name,punkte( tmp, + alleszusammen ),f ); + } + printf("Insgesamt wurden %s Bytes von %d Benutzer bewegt.\n",punkte + (tmp,max), (max_user)); + } + #ifdef DEBUG + printf("sortiert erfolgreich.\n"); + #endif +} + +/*---------------------------------------------------------------------------- +** Einzelaugabe eines Calls +** Seit der 1.75 gibt es im L2 keine Via-Eintraege mehr in der MHEARD.TAB. +*/ + +void callraus(char *suchcall) +{ + int a; + int calllen = 0; + char vergleichcall[10] = "0x00"; + struct line *liste; + struct tm *ts; + + calllen = strlen (suchcall); + + for ( a = 0; a < calllen; a++ ) /* call in Grossbuchstaben wandeln */ + { + suchcall[a] = grossbuchstabe ( suchcall[a] ); + } + + if ( suchcall[calllen -1] =='*' ) /* Wenn * vorhanden, calllen 1 weniger */ + calllen-- ; /* sonst wird das * mitgesucht. */ + else + calllen = 6; + + a = 0; + + liste = listenanfang; + while (liste != NULL) + { + strcpy(vergleichcall, liste->call); + ssid_weg ( vergleichcall ); + if (!callcmp(suchcall,vergleichcall,calllen)) /* und guggen ob da */ + { + if ( a == 0 ) /* nur beim erstenmal */ + { + printf("\nDatum Port Rx Tx RxRej " + "TxRej D Call\n"); + } + ts = localtime ( &liste->heard ) ; + printf("\n%02d.%02d.%02d %02d:%02d ", ts->tm_mday, + ts->tm_mon+1, + ts->tm_year%100, + ts->tm_hour, + ts->tm_min); + + printf("%-10s %9lu %9lu %5u %5u %3u %-9s", + port[liste->mhport].name,liste->tx,liste->rx,liste->t,liste->r, + liste->d,liste->call); + a = 1; + } + liste = liste->naechster; + } + if ( a == 0 ) + printf("\n%s nicht gehoert!",suchcall); + + ts = localtime ( &filetime ); /* wann das letze Mal gesaved */ + printf("\n\nStand: %02d.%02d.%02d %02d:%02d %.3s\n", ts->tm_mday, + ts->tm_mon+1, + ts->tm_year%100, + ts->tm_hour, + ts->tm_min, + zeitzone); + #ifdef DEBUG + printf("callraus erfolgreich\n"); + #endif +} + +/*---------------------------------------------------------------------------- +** Aufruf ohne Parameter ergibt eine Ausgabe von 10 Eintraege von allen Ports. +** Es koennen ein bestimmter Port oder eine bestimmte Anzahl uebergeben +** werden. Oder beides gemeinsam. Reihenfolge, egal. +** Dann kann man noch ein Rufzeichen eingeben. Aber dann nur das!! +*/ + +int main (int argc, char *argv[]) +{ + int uni; /* Uebergabevariable fuer max_user */ + int Ausgabe = 10; + int Gesamt = 0; + char Port = 'a'; /* Dummi fuer Ausgabe alle Ports */ + char call[10] = "\x0"; + char *port_z; /* Zeiger fuer Port */ + + #ifdef DEBUG + clock_t ende; + #endif + + strcpy (filename, "mheard.tab"); + + for ( argc--, uni = 1; uni < argc; uni++ ) + { + if (argv[uni][0] == '-') /* erstmal die -Parameter bearbeiten */ + { + switch (argv[uni][1] ) + { + case 'V' : + case 'v' : printf("\n%s\n",VERSION); + exit(0); + break; + case 'H' : + case 'h' : + case '?' : benutzung (); + exit(0); + case 'L' : + case 'l' : strcpy(filename, "l3heard.tab"); + break; + default : if (isdigit( argv[uni][1])) + { + port_z = argv[uni]; /* auf zeiger umkopieren */ + port_z++; /* einen weiterdrehen, damit - verschwindet */ + Port = atoi(port_z); /* aus Asci "echte" Hexwerte */ + break; /*machen. Kann dann nur Port sein */ + } + else + { + benutzung(); /* Kurzhilfe ausgeben */ + exit(0); + } + } + } + if ( isdigit (argv[uni][0] )) /* Zahl ?? */ + Ausgabe = atoi (argv[uni]); /* Anzahl der Ausgabe */ + + if ( isalpha (argv [uni][0])) /* Buchstabe ?? */ + { + strncpy ( call, argv[uni],9 ); + uni = argc; /* Bei Call wird ALLES ignoriert!! */ + if ( strlen ( call ) < 3 ) /* Es sollte mehr als 1 Buchstabe sein */ + { + printf("\nMindestens 2 Buchstaben und eine Zahl oder * eingeben!\n"); + exit (0); + } + } + if(*argv[uni] == '*') + Gesamt = 1; /* Alles einlesen, aber SSId weg */ + } + + config_lesen(); + + if ((port_z = getenv("TZ")) != NULL) + strcpy(zeitzone,port_z); + + if( call[0] ) /* wenn call angegeben, alles ignorieren */ + { + einles(0,Gesamt); /* MHEARD.TAB einlesen mit Nullbyteleute */ + callraus(call); /* Einzelcall ausgeben */ + } + else + { + einles(1,Gesamt); /* MHEARD.TAB einlesen OHNE Nullbyteleute */ + addier(); + sortier(Ausgabe, Port); /* sortiert und gibt aus */ + } + #ifdef DEBUG + ende = clock(); + printf("Laufzeit = %ld \n",(ende*100) / 182); + #endif + exit(EXIT_SUCCESS); +} diff --git a/doc/conversd.g b/doc/conversd.g new file mode 100755 index 0000000..b7dbe07 --- /dev/null +++ b/doc/conversd.g @@ -0,0 +1,207 @@ +Commands may be abbreviated. Commands are: +/Away [text] Mark user as being away +/ALl text Send text to all users +/Beep Toggle Beep-Mode +/Channel n Switch to channel n +/CHARset [in [out]] Change terminal emulation (default ansi) +/Destinations List reachable ping-pong hosts +/Filter [calls] Set calls you want to filter +/Help [command] Print help information +/Invite user Invite user to join your channel +/IMsg user text Send Text to all on channel except user +/Links [args] List or setup links +/LISt List all channels and topics +/LEave [channel] Leaves specified or default channel +/Msg user|#channel text Send message to a user or joined channel +/ME text Write action to channel +/MOde [channel] options Set channel options +/NIck nickname Set your (nick)name +/NONick Delete your (nick)name +/NOTify [calls] Send notice if one of calls signs on +/Personal [text] Set personal description +/PRompt abcd Prompts a=query b=std c=ctrl-g d=ctrl-h +/Quit Terminate the convers session +/QUEry [user] Start/End a private conversation +/Topic [#chan] [text] Set channel topic. Text=@ removes topic +/UPtime How long is this conversd up ? +/Verbose Toggles verbose Flag +/VERSion Show version information +/Who [N|*|A|L|U|@] List users and their channel numbers +/WIdth [value] Set/show terminal width +@@ALL +If you are in /query mode, a text written with /all at the front will +be displayed as a normal convers text written to all users on this channel. +@@AWAY +/away sets an away-text for the other users. called with no additional +arguments, you are marked as being back again. +@@BEEP +(/beep /bell) +The beep command toggles a warning bell (^G) being sent before every message +coming from another user. This command really is a subset of the /prompt +command, see there. +@@CHAR +With this command, you can tell the convers deamon which type of umlauts you +prefer to use. The Syntax is /char [intype [outtype]]. For example, if you +work on an Atari st you could say: "/char atari atari". If you use a pc and +like to write your own umlauts in TeX style, "/char tex pc" may work. Use +"/char ?" to see a list. Play a bit around with this feature ! +Special Thanks to Thommy, (Internet mail) + (AmPR-Net mail) who wrote this nice feature. +Suggestions to this feature should be redirected to him :-) +Your char-setting will be stored when using "/pers", see there. +Please notice; use the correct charset for your program, not for your type +of computer. +@@DEST +(/destinations /hosts) +All Pingpong hosts in the network being connected to each other are listed. +The numbers shown in the list are response times in seconds. Use "/d #" to +see another form of this list. +@@EXCL +(/exclude /imsg /iwrite) +The exclude command is the opposite of the /msg command. You can send +messages to all users on the channel except the one given as the first +parameter. Internally these messages are sent as private messages to the +users, so links are flooded a bit more :-) +@@FAID +Welcome to the convers, select the right conversion for umlauts (/char), +set your personal description (/pers) +and change (/join) to another channel of your interest, if you want. +Whith /who you get an overview of the channels, more help with /help. +Have fun. +@@FILT +If you don't want to read texts from certain users, you can set a list +of calls. Messages from this calls are discarded for you. The syntax is +similar to "/notify". E.g. "/filter + dc1ik - db4ut" adds the user dc1ik +to the filter and removes db4ut from the list. +@@HELP +(/? /help) +The help command may be invoked with an additional parameter. I believe you +hacked in "help help" to see this, right ? :-). better try out help options +that are followed by an additional command. +@@INVI +An invitation tho the named user is sent. The invite is passed through all +convers nodes in the net. If the user is on another channel, he will be able +to join your private channel. If he is in the commandinterpreter on a node, +he will receive the invitation message. In the latter case he will be unable +to join a private channel directly. +@@JOIN +(/channel /join) +Join another channel. Unlike other other conversd implementations Ping-Pong- +conversd supports multiple channel joins the same time. Thus the old channel +is not left. You may do this by invoking "/leave". +@@LEAV +Invoking this command you will leave the actual channel or the specified +channel. If the given channel is your last existence in the convers channel, +you'll quit the whole program. +@@LINK +The current link state is displayed. In the standard version, host name, +link state, link round trip times, neighbour revision codes and state time +followed by time of next try and count of connect tries (on disconnected or +connecting links) are shown, connected lines print out their queue length +and total transmit statistics. +If you are sysop, you may also set up or remove links at runtime. +Connection-info will be shown in brackets additionally. +Syntax: /l [@ host]|[[+]|[-] host [port [via]]] +With "/l @host" you are able to get info from host (not all versions support +this function). +@@LIST +All channels, their topics (if set), flags (if some) and users are displayed. +@@ME +If you want to display an action you take, you might use this command. E.g. +entering the line "/me yawns" all connected users in this channel will see +a message like: "*** dc6iq yawns" +@@MODE +The mode command is one of the most complicated ones. It is invoked with +/mode <+|->>. + Flags may be a set of the following: + t - channel topic may be set by channel operators only + i - channel is invisible for users not on it + s - channel is secrect, only its number not displayed + m - channel is moderated, only channel-operators may talk + p - channel is private, invitation needed to join here + l - channel is local, no text forwarding to other nodes (NYI) + o - make a channel operator + +The plus indicates an option to be set, a dash resets the option. +A combination of + and - is allowed so the following command will work: +"/mode 69 -s+todc6iq". Channel 69 is no longer secret, but topics may be +set only by channel operators. In addition the user dc6iq becomes a channel +operator. +Without parameters, the current settings will be listed. +On channel 0 it is impossible to set modes! +@@MSG +(/msg /send /write) +Send a text to one special user or a joined channel. If the message should +be redirected to a channel, The command must be invoked in this syntax: +"/msg # ". The adressee (if user) can indicate the private +character of the message due to additional asterisks in his received lines. +a mesage written by dc6iq to dc1ik looks like this: "/m dc1ik This is a Test" +will be received by dc1ik like this: "<*dc6iq*>: This is a test". +@@NICK +You can set your nickname to be displayed in front of your callsign. The +nickname is forwarded to other convers hosts. Use "/nick @" or "/nonick" +to delete your nickname. +@@NONICK +If a nickname is set, it is deleted. (same as "/nick @") +@@NOTI +You are notified if one person out of the notification list appears on any +channel in this convers. E.g. "/notify + dc1ik" adds the user dc1ik to the +notification list, "/notify - db4ut" removes him from the list. The list is +initially treated as if a plus "+"-sign was given, multiple lists may be +specified. The following command would be legal and would result in adding +dc1ik, db4ut and dg3kcr to the list, while removing dc6iq and dh2paf: +"/notify dh2paf + dc1ik db4ut - dc6iq dh2paf +dg3kcr" +Removing non-members to the list is ignored. +@@PERS +(/note /personal) +A brief description can be set up, accessible to all users via the "/who"- +command. A typical Message looks like this: "/pers Fred, Buechig, JN49fb". +The description can be deleted with "/pers @". +The digi stores up to 118 chars of this description and set it automatically +when you enter convers (the settings of "/char" and "/width" will be stored +and set on login, too). Storing is also possible with simply "/pers". +@@PROM +The prompt command takes up to four arguments in one concatenated string. +Thus "/prompt abcd" will set up "a" for the query prompt, "b" for the +standard prompt. "d" is the character to remove the prompt, and "c" is +displayed whenever a text is sent to you. Normally you make "c" a control-G +(beep char) and "d" a backspace or delete character (control-h or 0x7f). +@@QUER +The username given as argument will be the only recipient for all further +texts. They are send as private messages (just like /m). With no optional +argument, the further texts go into the whole channel again. +@@QUIT +(/bye /exit /quit) +Passing this command to conversd, you will retire from the famous Ping-Pong +conversation. I hope you enjoyed this stuff :-) +@@TOPI +A brief description of the channel topic can be set. Other users can look +it up with the "/who quick" or "/list" commands. If the channel number is +omitted, the topic will be set to the current channel, else to the desired +one. If no #channel is given, the topic will appear on the current channel, +if specified, the topic on that channel will be set (only if youre logged +on to that channel). To clear a topic, just try to set a topic like "@" :-) +An empty topic command diplays the current's channel topic. +@@UPTI +The uptime command tells us how long this conversd is up and running. +@@VERB +The verbose flag is toggled. You will be flooded with information if you +enable this feature. +@@VERS +Print out version information to this software. +@@WHO +(/users /who) +This command shows the users and has multiple options: + n [channel] tabular form (limitable to one channel) + a [channel] away-text listing (limitable to one channel) + l [channel] long listing (limitable to one channel) + u users detailed infos to specified users + * [channel] listing of idle-times (own or specified channel) + @ host to specified host limited tabular form +without option you get a brief listing ("/list"). +@@WIDT +Tell conversd about your screen width. Then formatted messages will use the +entire screen. It is set to 80 by default. +Your width-setting will be stored when using "/pers", see there. +@@---- +rev3.12c/20001003 \ No newline at end of file diff --git a/doc/conversd.xhf b/doc/conversd.xhf new file mode 100755 index 0000000..0eb489b --- /dev/null +++ b/doc/conversd.xhf @@ -0,0 +1,259 @@ +*********************************************************************** +* Hilfe zum PingPong-Release 3.13a (TNN) - Stand: 4.09.2004 by DAD213 * +*********************************************************************** +Kommandos koennen abgekuerzt werden. +/Away [Text] markiert Dich als abwesend +/ALl Text Text an alle User Deines Kanals +/Beep Beep-Modus an/aus +/Channel n wechselt auf Kanal n +/CHARset [rein [raus]] setzt Zeichenwandler (ANSI ist Voreinstellung) +/Destinations listet erreichbare ping-pong Hosts +/EXClude User Text sendet Text an alle auf Deinem Kanal ausser User +/Filter [Calls] setzt Calls, deren Texte gefiltert werden sollen +/Help [Kommando] gibt Hilfe-Informationen +/Invite User laedt User auf Deinen Kanal ein +/Links [args] listet oder setzt (Sysops) conversd-Partner +/LISt listet alle Kanaele und ihre Themen +/LEave [Kanal] verlaesst Kanal oder derzeitigen Kanal +/Msg User|#Kanal Text sendet Text an User oder verbundenen Kanal +/ME [Text] sendet einen Aktionstext +/MOde [Kanal] Optionen setzt Kanaloptionen +/NIckname text setzt den eigenen Namen +/NONickname loescht einen gesetzten Namen +/NOTify [Calls] setzt Calls, deren Erscheinen gemeldet werden soll +/PERSonal [Text] setzt persoenliche Beschreibung +/PASSwort setzt persoenliches Passwort +/NIckname [Name] setzt Nickname +/SYSop macht dich zum Convers Sysop +/PRompt abcd Prompt setzen a=Query b=Normal c=Ctrl-g d=Ctrl-h +/Quit convers verlassen +/QUEry [User] startet/beendet private Konversation +/Topic [#Kanal] [Text] setzt Thema des Kanals. Thema=@ entfernt Thema +/UPtime wie lange laeuft dieser conversd ueberhaupt schon ? +/Verbose Laber-Modus an/aus +/VERSion zeigt Info zu dieser Version +/SYSInfo convers host information +/Who [N|*|A|L|U|@] zeigt User und Ihre Kanaele +/WIdth [Wert] setzt/zeigt Zeilenbreite +@@ALL +Wenn Du im /query Modus bist, wird Text mit vorangestelltem /all behandelt, +als wuerdest Du ohne /query arbeiten. +@@AWAY +/away setzt den Abwesendheitstext, den die anderen lesen koennen. Beim +Aufruf ohne Argument wird der Text geloescht und man gilt wieder als anwesend. +@@BEEP +(/beep /bell) +Hiermit wird das Klingelzeichen (^G), welches vor jeder Mitteilung gesendet +werden kann, ein- oder ausgeschaltet. Diese Kommando ist eigentlich eine +Untermenge des /prompt Befehls, siehe dort. +@@CHAR +Mit diesem Befehl kannst Du dem Convers mitteilen, welche Zeichensatzwandlung +Du haben moechtest. Die Syntax ist +/char [In-Typ [Out-Typ]] +Wenn Du z.B. mit einem Atari ST arbeitest, koenntest Du "/char atari" eingeben. +Wenn Du einen PC benutzt und Umlaute im TeX-Stil schreiben moechtest, gebe +"/char tex pc" ein, "/char ?" listet die Moeglichkeiten auf. Spiel ein +bisschen mit dieser Funktion. +Der Dank dafuer geht an Thommy, (Internet mail) + (AmPR-Net mail). Vorschlaege sollten an ihm +weitergeleitet werden. +Diese Einstellung wird bei "/pers" gespeichert (siehe dort). +Wichtig ist hier weniger der Rechnertyp, sondern der Zeichensatz, den das +verwendete Programm benutzt. +@@DEST +(/destinations /hosts) +Alle Pingpong-Hosts, die miteinander verbunden sind, werden aufgelistet. Die +Zahlen zeigen die Antwortszeiten in Sekunden. Mit "/d #" kann eine andere +Darstellung gewaehlt werden. +@@EXCL +(/exclude /imsg /iwrite) +Dieses Kommando ist das Gegenteil des /msg Befehls. Hiermit sendest Du Text +an alle User dieses Kanals ausser dem einen als ersten Parameter angegebenen. +Da der Text intern als privater Text an die Anderen verschickt wird, werden +die Links etwas mehr belastet :-) +@@FAID +*** User Liste mit (/W *) +*** Nickname setzen mit (/NI name) +*** Passwort setzen mit (/PASS neu passwort) +*** Personal text setzen mit (/Pers Name * QTH * LOC) +@@FILT +Wenn Du die Texte bestimmter User nicht lesen moechtest, so kannst Du sie +hiermit in eine Liste einfuegen. Alle Texte werden dann ausgefiltert, bei +persoenlichen Texten ("/msg") wird eine Rueckmeldung an den Absender geschickt. +Das Setzen/Loeschen geschieht wie bei "/notify", also z.B. +"/filter + dg7ncq - db4ut" setzt dg7ncq und loescht db4ut aus der Liste. +@@HELP +(/? /help) +Das Hilfekommando kann von zusaetzlichen Parametern gefolgt sein. Du hattest +bestimmt "/help help" eingetippt um dies hier zu sehen, gelle ? :-) +Der Schraegstrich darf hier nicht vor den fraglichen Kommandos stehen. +@@INVI +Es wird eine Einladung zum genannten User geschickt. Diese Einladung wird +durch das gesamte Netz geleitet. Wenn derjenige auf einem anderen Kanal +ist und Dein Kanal als privat eingerichtet ist, so kann er auf Deinen +Privatkanal wechseln. Wenn er im Befehlsinterpreter eines Knotens ist, so +empfaengt er die Einladung, er kann dann aber nicht direkt auf Deinen +Privatkanal kommen, weshalb er nochmals einzuladen ist. +@@JOIN +(/channel /join) +Verbindet Dich zusaetzlich mit dem gewuenschten Kanal. Im Gegensatz zu aelteren +conversd-Implementationen, verbleibt man auch noch im vorherigen Kanal, denn +es wird eine Mehrfach-Kanal-Verbindung unterstuetzt. Um einen Kanal zu +verlassen, musst Du "/leave" verwenden. Ohne Angabe eines Kanals, werden Infos +zu den von Dir benutzten Kanaelen ausgegeben. +@@LEAV +Mit diesem Befehl kannst Du entweder den derzeitigen oder den angegebenen +Kanal verlassen. Wenn dieser der letzte ist, so wird conversd verlassen. +@@LINK +Der momentane Linkstatus wird angezeigt. Dies sind normalerweise Hostname, +Linkstatus, Laufzeiten, Versionskodes und Statuszeit, gefolgt von der Zeit +des naechsten Connectversuches und Anzahl der Versuche (auf Disconnecteten +oder im Aufbau befindlichen Links), bei bestehender Verbindung werden die +Queue-Laengen und Byte-Statistiken angezeigt. +Wenn Du Sysop bist, kannst Du Verbindungen Setzen oder Loeschen. Es wird +dann auch noch zusaetzlich in Klammern der Verbindungsweg angezeigt. +Syntax: /l [@ Host]|[[+]|[-] Host [Port [via]]] +Mit "/l @ Host" koennen andere Hosts fernabgefragt werden (wird nicht von +allen Versionen unterstuetzt). +@@LIST +Alle Kanaele, ihre Themen, Optionen und User werden angezeigt. +@@ME +(/me /action) +Dieser Befehl dient dazu, den Usern auf Deinem Kanal eine Taetigkeit +anzuzeigen. Wenn du z.B. "/me gaehnt" eingibst, bekommen alle User dieses +Kanals folgendes angezeigt: +*** dad213@Dessau gaehnt +@@MODE +Das mode-Kommando ist eines der kompliziertesten. Es wird wie folgt benutzt: +/mode [] <+|->>. + Die Optionen bedeuten folgendes: + t - Das Thema des Kanals laesst sich NUR von Kanal-Sysops aendern + i - Der Kanal wird Usern anderer Kanaele verheimlicht + s - Der Kanal ist geheim, die Kanalnummer wird nicht mehr angezeigt + m - Der Kanal ist moderiert, nur Kanal-Sysops duerfen schreiben + p - Der Kanal ist privat, man benoetigt eine Einladung zum Einloggen + l - Der Kanal ist lokal, Texte werden nicht weiterverteilt + o - macht zum Kanal-Sysop (kein - moeglich) + +Das Plus setzt eine Option, der Strich loescht sie. Es sind Kombinationen +erlaubt, so wuerde "/mode 69 -s+todc6iq" folgendes bewirken: Kanal 69 ist +nicht mehr geheim, aber die Themen duerfen nur vom Kanal-Sysop gesetzt +werden. Zusaetzlich wird dc6iq ein Kanal-Sysop. +Ohne Angabe von Parametern werden die derzeitigen Optionen angezeigt. +Auf Kanal 0 sind keine Modes setzbar! +@@MSG +(/msg /send /write) +Sendet einen Text an einen speziellen User oder an einen verbundenem Kanal. +Wenn der Text an einen Kanal gehen soll, so muss man folgendes eingeben: +"/msg # ". Wenn das Ziel ein User ist, so kann er den Text +an den zusaetzlichen Sternchen erkennen. Z.B. wenn dc6iq eine Nachricht an +dc1ik mit "/m dc1ik Das ist ein Test" sendet, so erhaelt dc1ik folgendes: +"<*dc6iq*>: Das ist ein test". +@@NICKNAME +Setzt den eigenen Namen, der zusaetzlich vor dem Rufzeichen ausgegeben +wird. Der Name wird auch andere Convers-Hosts weitergeleitet. Ein gesetzter +Name kann mit den Kommandos "/nick @" oder "/nonickname" geloescht werden. +@@NONICKNAME +Loescht einen gesetzten Namen (siehe auch "/nick @"). +@@NOTI +Du wirst informiert, wenn eine bestimmte Person in der Personenliste im +convers erscheint. Z.B. fuegt "/notify + dc1ik" dc1ik in die Liste ein, +"/notify - db4ut" entfernt db4ut aus der Liste. Das Einfuegen/Loeschen +mehrerer Calls in einem Kommando ist moeglich, z.b. bewirkt +"/notify + dc1ik db4ut - dc6iq dh2paf +dg3kcr", dass dc1ik, db4ut und dg3kcr +eingefuegt und dc6iq und dh2paf entfernt werden. Das Entfernen von Calls, +die nicht in der Liste stehen wird ignoriert. +@@PERS +(/note /personal) +Es kann eine kurze Beschreibung zu Deiner Person gesetzt werden, den die +anderen User mit "/who" sehen koennen. Z.B: "/pers Fred, Buechig, JN49fb". +Mit einem @ als Text wird sie geloescht. Diese Implementation merkt sich +bis zu 118 Zeichen der Beschreibung und setzt diese dann automatisch beim +Einloggen (die "/char" und "/width" Einstellungen werden dann auch +gespeichert und beim Einloggen gesetzt). Speichern ist auch ohne Setzen +moeglich, einfach ohne Text aufrufen. +@@PROM +Das prompt-Kommando nimmt vier Argumente in einer zusammenhaengenden Zeichen- +kette. "/prompt abcd" setzt "a" als "/query"-Prompt, "b" fuer den normalen +Prompt. "d" ist ein Zeichen um den Prompt zu loeschen (also normalerweise +Backspace (^H) oder Delete). "c" ist ein Zeichen, welches vor jedem Text, +den Du empfaengst, gesendet wird (normalerweise also ^G). +@@QUER +Der angegebene User ist in Zukunft der einzige Empfaenger fuer alle Texte, +die Du eingibst. Diese werden dann als private Texte an den User geschickt, +wie bei "/m". Zum Ausschalten, ohne Argument aufrufen, danach geht alles +wieder wie gewohnt an den Kanal. Sozusagen ein Privatmodus. +@@QUIT +(/bye /exit /quit) +Wenn Du das eingibst, verlaesst Du diesen wunderbaren Ping-Pong-Convers. +Das willst Du doch nicht wirklich? :-) +@@TOPI +Hiermit kann fuer den Kanal ein Thema gesetzt werden. Die anderen User +koennen dieses sehen, wenn sie "/who" oder "/list" eingeben. Wenn keine +Kanalnummer angegeben wird, so wird das Thema des aktiven Kanals gesetzt. +Wird eine Nummer angegeben, so musst Du auch auf diesem Kanal eingeloggt sein. +Um das Thema zu loeschen, ist als Thema ein "@" einzusetzen. +@@UPTI +Dieser Befehl zeigt an, wielange conversd schon aktiv ist. +@@VERB +Schaltet die Laber-Option ein/aus. Du bekommst dann viele Informationen +ueber Aktionen der User (Einloggen/Ausloggen/Texte-setzen/...), auch wenn +diese nicht auf Deinem Kanal sind. +@@VERS +Zeigt etwas Text zu dieser Version (in englisch). +@@WHO +(/users /who) +Dieser Befehl zeigt die eingeloggten User und hat mehrere Optionen: + n [Kanal] tabellarische Darstellung (auf einen Kanal begrenzbar) + a [Kanal] Abwesendheitsliste (auf einen Kanal begrenzbar) + l [Kanal] ausfuehrliche Liste (auf einen Kanal begrenzbar) + u Userliste ausfuehrliche Infos zu den Usern in der Userliste + * [Kanal] Liste der Idlezeiten (eigener oder angegebener Kanal) + @ Host auf Host begrenzte tabellarische Darstellung +ohne Option wird die kurze Darstellung, wie bei "/list", ausgegeben. +@@WIDT +Macht conversd Deine Bildschirmbreite (Zeichen/Zeile) bekannt. Die Meldungen +der anderen wird dann auf diese Breite gebracht. Voreingestellt ist 80. +Diese Einstellung wird bei "/pers" gespeichert (siehe dort). +@@NICK +/NIckname [nick] setzt den "nickname" + +Setzt den Nickname auf "nick", so das fortan vor Deiner Messages + statt gesendet wird. +Der Nickname wird auf dem Server Gespeichert und bei jedem Connect +automatisch gesetzt. + +Der Nickname darf max. 10 Zeichen lang sein !! + +Nur fuer Sysop's +~~~~~~~~~~~~~~~~ +/NIchname list Zeigt alle eintraege in der nickname.txt +/NIckname save Speichert die nickname.txt +/NIckname del Call Loescht ein Rufzeichen aus der nickname.txt +@@PASS +/PASS neu [passwort] setzt das Passwort fuer den Convers. + +Wenn Password-Authentication gewuenscht ist, nutze den "/pass" Befehl. +pass zeige zeigt das derzeitige Passwort. + neu [Passwort] setzt ein neues Passwort. + loeschen loescht das Passwort. + +Ein Passwort kann bis zu 80 Zeichen lang sein. +@@SYSI +*** System Information [pp-3.13a] - Email: dad213@datel-dessau.de +*** PingPong-Release version PP-3.13a (18.08.2004/daa531/dad213) +@@SYS +/SYSop [nummer] Convers-Sysop werden + +Nach Aufruf dieses Befehls wird eine Zufallsnummer zwischen 0 und 99999 +angezeigt. Nimm jede Zahl, multipliziere mit der verbunden Geheimnummer +in der Konfiguration (TNN179.PAS) summiere sie auf, und antworte z.B mit "99999" +@@CTEXT +*** Looking up DL-Convers +* +* (Hilfe in Deutsch) +* +* ACHTUNG!! Neue Convers-Befehle siehe (/HELP) +* +@@---- +rev3.13a/04.09.2004 by DAD213 diff --git a/doc/deutsch.txt b/doc/deutsch.txt new file mode 100755 index 0000000..a9b1fab --- /dev/null +++ b/doc/deutsch.txt @@ -0,0 +1,351 @@ +"Convers Sitzung wurde beendet.\rEnter command. Befehl HELP fuer Hilfe.\r" +"*** Du bist bereits im convers-mode.\r" +"Der Convers-Hostname ist zu lang (max.9 Zeichen)!\r" +"Convers-Hostname erfolgreich geaendert in %s.\r" +"Gesperrt!\r +"%s%s@%s ist Abwesend:\r %s\r" +"%s%s@%s ist wieder zurueck.\r" +"%s%s macht Dich zum Kanal-Sysop fuer Kanal %d\r" +"%s%s@%s ist jetzt Sysop fuer Kanal %d\r" +"Kanal %d" +"%s%s@%s auf %s setzt persoenlichen Text:\r %s\r" +"%s%s@%s auf %s entfernt persoenlichen Text.\r" +"%s%s@%s auf %s setzt Kanal-Topic:\r %s\r" +"%s%s@%s auf %s entfernt Kanal-Topic.\r", +"geheimen Kanal" +"unsichbaren Kanal" +"%s%s:%s@%s auf %s setzt persoenlichen Text:\r %s\r" +"%s%s:%s@%s verlaesst %s.\r" +"%s%s@%s verlaesst %s.\r" +"%s%s@%s verlaesst %s (%s).\r" +"%s%s:%s@%s betritt %s\r" +"%s%s@%s betritt %s\r" +"%s%s ist abwesend: %s" +"%sIhre Nachrichten werden dadurch Ignoriert %s" +"\r\a\a%sMessage von %s...\rBitte verbinden mit %s auf Kanal %d.\r\a\a\r" +"%s%s Einladung gesandt zu %s @ %s." +"%sUser %s ist bereits auf diesen Kanal." +"*** Unbekannter Befehl '/" +"'. Benutze /HELP fuer Hilfe.\r" +"*** Du bist abwesend oder etwa nicht ? :-)\r" +"*** Dies ist ein moderierter Kanal. Nur Kanal-Sysop koennen schreiben.\r" +"*** Gefragter User verliess Kanal.\r" +"%sDu bist jetzt Abwesend.\r" +"%sDu bist wieder da.\r" +"%sWarst du weg ? :-)\r" +"*** Beep modus %sgeschalten\r" +"%sDu bist jetzt auf Kanal %d. Hier sind %d User Online.\r" +"*** Topic wurde gesetzt von %s (%s):\r " +"*** Also zugefuegt:" +"kanal %d (privat)" +"kanal %d (%d benutzer)" +"%sKanalnummer muss im bereich 0..%d sein.\r" +"%sKanal %d ist bereits Standard.\r" +"%sDu brauchst eine Einladung, um den Kanal zu betreten %d.\r" +"%s%s@%s Versucht privaten Kanal zu betreten." +"%sKann Kanal nicht betreten %d kein freier Platz.\r" +"%sDu bist jetzt auf Kanal %d. " +"Du bist alleine.\r" +"Hier sind %d User Online.\r" +"*** Zeichensatz in/out ist %s/%s.\r" +"Unbekannter Zeichensatz: '%s'. Benutze ein von diesen:\r%s***\r +"*** Zeichensatz in/out gesetzt auf %s/%s.\r" +"Hilfe für diesen befehl nicht eingebaut...\rWrite it - or try anthor one :-)\r" +"Befehl nicht gefunden...\r" +"*** Kein weg gefunden zu %s\r" +"%sNeuer Standard-Kanal: %d.\r" +"%sDu verlaesst Kanal %d.\r" +"%sDu bist nicht im Kanal %d.\r" +"*** Request gesendet zu %s.\r" +"Du musst Sysop sein um ein neuen link setzen zu koennen\r" +"Link-Tabelle voll!\r" +"Argument Fehler!\r" +"%sDu hast den Kanal nicht betreten %d.\r" +"%sBenutzer nicht gefunden: %s.\r" +"%s%s ist Abwesend: %s\r" +"*** nicht existierenter Kanal !\r" +"*** Keine Optionen auf Kanal 0 !\r" +"*** Du bist kein Kanal-Sysop !\r" +"%s @ %s PingPong-Release %5.5s (TNN) - Benutze /HELP fuer Hilfe.\r" +"%sDu brauchst eine Einladung fuer Kanal %d.\r" +"%s%s@%s Versucht Privaten Kanal zu betreten." +"*** Du eroeffnest einen neuen Kanal %d.\r" +"*** Pers-text gesetzt auf.\rHallo, %s\r" +"*** Bitte dein personal text eintragen. ( /H PERS )\r" +"%sDu wirst benachrichtigt, wenn einer der folgenden\rUser sich ein-/ausloggt:\r" +"%s wird gefiltert:\r" +"*** %s ist Online.\r" +"gespeichert.\r" +"*** Kein Pers-Text gespeichert.\r" +"geloescht.\r" +"gespeichert.\r" +"*** Prompting mode %sgeschalten\r" +"ein" +"aus" +"Du musst Sysop sein um neu zu starten!\r" +"Link zu %s delocked.\r" +"%sBenutzer nicht gefunden: %.20s.\r" +"%sStarte private unterhaltung mit %s.\r" +"%sBeende private unterhaltung mit %s.\r" +"%sKanal-Topic auf Kanal %d enternt von %s (%s).\r" +"%sKanal-Topic gesetzt auf Kanal %d von %s /%s).\r" +"%sAktueller Kanal-Topic auf Kanal %d von %s (%s)\r " +"%sKein aktuller Kanal-Topic auf Kanal %d\r" +"%sKanal %d existiert nicht.\r" +"*** %s@%s rennt seit %s\r" +"*** Verbose mode %sgeschalten\r" +" Diese Convers Implantation ist urspruenglich von Dieter Deyke (DK5SG)\r geschrieben, und von Fred Baumgaten (DC6IG) modifiziert.\r Neu Implementierung und erweiterung von Odo Roscher \r " +" Diese Version (3.13a) beinhaltet Passwort-Schutz und Nickname-funktion\r und wurde von Olli (DAA531) erweitert/modifiziert.\r\r Diese Version (3.13a) wurde von Chris (DAD213)\r ins Deutsche uebersetzt.\r" +" Zeit Pers-Text\r" +"Login Status\r" +"Login Pers-Text\r" +"(anwesend)" +"\r Abwesend: " +" (seit " +" (WEG)" +"\r Letzte Aktivitaet: " +"*** Akltuelle Bildschirmbreite ist %d\r" +"*** erlaubt sind 32 bis 255\r" +"*** Bildschirmbreite gesetzt auf %d\r" +"*** Urgent message from operator (%s):\r " +"*** Links at %s" +"free" +"*** Nickname gesetzt auf: %s\r" +"Kein Login moeglich!\rRufzeichen %s ist am Host %s eingeloggt!\r" +"*** Dein Passwort wurde geloescht!\r" +"*** Kein Passwort gesetzt!\r" +"*** Dein Passwort lautet:\r%s\r" +"*** Es ist kein Passwort definiert!\r" +"*** Passwort wurde gesetzt!\r" +"*** Passwort muss mindestens 5 bzw. maximal 80 Zeichen enthalten!\r" +"*** Passwort fehlt!\r" +"*** Syntax: pass [Neues Passwort]\r" +"*** Passwort ist korrekt!\r" +"*** Passwort ist falsch!\r" +"*** Topic wurde gesetzt von %s (%s):\r %s\r" +"\r*** %d User auf Kanal%s ***\r" +" Durchschnitt: %lu" +"\r%7s00 02 04 06 08 10 12 14 16 18 20 22\r%9s01 03 05 07 09 11 13 15 17 19 21 23 Stunde\r\r" +"\r%7s0 0 1 1 0 0 1 1 0 0 1 1 0 0 1 1 0 0 1 1 0 0 1 1 0 0 1 1\r"%7s0 6 2 8 0 6 2 8 0 6 2 8 0 6 2 8 0 6 2 8 0 6 2 8 0 6 2 8 h\r%7sMontag Dienstag Mittwoch Donnerstag Freitag Samstag Sonntag\r\r" +" Elap. Zeit\r%6s-3600 -3240 -2880 -2520 -2160 -1800 -1440 -1080 -720 -360 0 Sekunden\r\r" +"> DISCONNECT: Zu viele nicht-DAMA Polls (%u) !!\r" +"WARNUNG: nicht-DAMA Poll #%u, Trennung nach %u !!\r" +"Grafik geloescht!\r" +"SYSTEM-Grafik:\r" +"(G)raph (H)Stunde (B)aud\r (D)Tag (C)ircuits\r (W)oche (F)rei buffers\r (L)2-Links\r (N)odes\r (R)ounds\r (*) Alles\r" +"PORTGRAPH:\r(G)raph (H)our (I)nfo frames\r (D)ay (R)eject frames\r (W)eek (F)rmr frames\r (S)abm frames\r dis(C) frames\r" +" d(M) frames\r (*) All\r" +"\r*** vom DAMA-Master " +"%s<>%s gerissen" +"Sie sind gesperrt.\r" +"\r- Abgebrochen -\r\r" +"Sri, kein Text vorhanden!\r" +"CLI erfolglos!\r" +"Wartend auf AUTOBIN-Transfer...\r +"\rL2 - User:\rPo SrcCall DstCall LS Rx Tx Tr SRTT RxB TxB Baud ConTime Pr Da\r" +"\rL4 - User:\rCall Node S Rx Tx Tr Win SRTT RxB TxB Baud ConTime\r" +"frei" +"frei" +"\rHost-User:\rCH Call F NT RX TX ST RxB TxB Baud ConTime\r-------------------------------------------------------------------------\r" }, +"\rTCPIP-User:\rIface SrcCall DstCall NT T3 RxB TxB Baud ConTime\r-------------------------------------------------------------------------\r" +"\r System Statistics: " +"\r Startup: " +"\r\r Port-Statistics:\r\r Links RxB TxB RxBaud TxBaud RxOver TxOver\r" +"\rTotal = " +" Bytes\r" +"\r Error-Statistics:\r\r" RxID RxLen RxCtl Resets\r" +"\rLink-Statistics:\r" +"\rLink to " +" via " +"\rFrames: I UI RR REJ RNR SABM/UA DISC/DM FRMR\r" +"Bytes: Total Info Header Overhead %I %RR %REJ %RNR\r" +" TQual:" +"\rIP-Gateway-Statistics:\r\r" +"free" +"free" +"Warnung - Port nicht activ.\r" +"Unzulaessiges Rufzeichen.\r" +"Unzulaessige Kennzeichnung.\r" +"free" +"free" +"Type-Port--Alias:Call------Route--------------Infotext------------\r" +"Benutzer nicht gefunden!\r" +"Das Sysop Passwort wurde geaendert!\r" +"Fehler: Das Passwort muss 80 Zeichen enthalten!\r" +"editing>%s\rEnter text. Ende mit '.' in einer neuen Zeile.\r" +"free" +"\r (min) (now) (max)\r Rounds/sec: %8lu %8lu %8lu\r" +" Free Buffers: %8u %8u %8u\rOverall Throughput:%18lu %8lu Baud\r Aktive L2-Links:%18u %8u\r Aktive Circuits:%18u %8u\r Aktive Nodes:%18u %8u\r" +"\r Aktive Sockets:%18u %8u\r" +"\r Buffer usage: %lu%%" +"\r Network Heap: %lu Bytes" +"\r CPU load: %lu%%" +"TX: Once:%11lu Repeated:%10lu IQual:" +" Copyright by NORD> um zurueck zu schreiben):\r %s\r" +"Consolen MyCall:%s\r" +"Unzulaessiger dateiname!\r" +"EDIT/LOAD durch anderen Sysop in gebrauch\r" +"Open error!\r" +"Datei error!\r" +"Statistik-Tabelle geloescht!\r" +"\rUnzulaessiger Port\r" +"\rPort abgeschalten\r" +"Kein Text\r" +"Unzulaessiger Call\r" +"Nachricht gesendet\r" +"Kein User\r" +"Keine Argumente\r" +"Keine mailbox!\r" +"Keine DX-cluster!\r" +"Alias zu lang, max. %u Zeichen.\r" +"Befehl zu lang, max. %u Zeichen.\r" +"can't create %s !\r" +"kann nicht oeffnen %s !\r" +"%lu Bytes frei\r" +"\r*** Nachricht vom Sysop: %s ***\r" +"%3u link(s) disconnected.\r" +"%s.TNB gespeichert...\r" +"Fehler: Tracen auf Port %u ist nicht erlaubt!!!\r" +"Fehler: Port %u ist nicht aktiv!!!\r" +"Warning: max. trace level von dieser TNN version ist %d\r" +"\rAllBuffer : %lu (%lu) a %lu Bytes\r" +"Wrong Owner: Buffer:%lu Wert:%d\r" +"FreeBuffer: %lu (%lu)\r" +"Errors : %lu\r" +"z.Z definierte aliasses:\r" +"Kein alias gespeichert\r" +"Alias gespeichert.\r" +"Kann nicht speichern, kein speicher.\r" +"Alias geloescht.\r" +"Kein solche definierte Namensabkuerzung, kann nicht loeschen.\r" +" nicht geloescht!\r" +" geloescht.\r" +" ist eingeschraenkt " +"zugaenglich machen verweigert\r" +"zum Zugang level-2\r" +"zu Maximum " +" simultanous Anschluesse\r" +"from using Port " +"Datei hat keine laenge!\r" +"Datei nicht gefunden!\r" +"Keine L2-link gefunden.\r" +"Fehler: Keine Portangabe oder ungueltiger Port! (Beispiel: MO S 1).\r Weitere Hilfe mit HELP MO .\r" +"Fehler: Sie haben keine optionen angegeben! (Beispiel:MO S 1).\r Weitere Hilfe mit HELP MO .\r" +" ist aus" +"Unzulaessiges program!\r" +"Unzulaessiger Hostcommand\r" +"%s\rNode / User unbekannt! Bitte Port angeben, wenn %s ein User ist:" +" (Telnetport ist gesperrt!)" +" (Httpdport ist gesperrt!)" +"Willkommen bei %s" +"* CHANNEL NOT CONNECTED *\a\n" +"CONNECTED to " +"DISCONNECTED fm " +"CONNECT REQUEST fm " +"INVALID COMMAND\r" +"Laenge = %d; Call = %s\n" +"\r receive %u" +" send %u unacked 0" +"INVALID VALUE: %u" +"nicht vorhanden" +"CHANNEL NOT CONNECTED" +"[FRAME EMPTY?!?]" +"[FRAME TOO LONG]" +"INVALID COMMAND: " +"INVALID EXTENDED COMMAND: " +"\rERROR : Port oder Call unzulaessig !\r" +"ARP-Tabelle von " +"\rDestination P Interface Callsign Digi Mode Timer\r" +"Meine IP address: " +" IP address : " +"kein weg zu " +"IP-Routes von " +"\rDestination------Len--Flags-Interface--Gateway----------Metric----\r" +"Unzulaessige IP addresse!\r" +"\rERROR : Unzulaessige IP-Adresse !\r" +"\rINP: frame error, len = %u, left = %u\r" +"\r[AX25 Fragment; %u Frame(s) to follow - original PID %X]\r" +"\r[AX25 Fragment; %u Frame(s) to follow]\r" +" (UNGUELTIGE ALIAS!)\r" +" (UNGUELTIGE IP ADDRESS!)\r" +"\rAlle Nodes die ueber %s geroutet werden zeigen:\r" +"Fehler: Connect-Status von 0 bis 1!\r" +"Fehler: Ungueltiger L4-Parameter!\r" +"Rufzeichen steht nicht in der Links-Liste!\r" +"Ungueltiger Befehl. Befehl HELP fuer Hilfe.\r" +"Commandline zu lang.." +" tabelle voll\r" +"TheNetNode wird beendet!\n" +"Date Time Port" +" Rx Tx Call\n" +" RX TX Call RX-Rej TX-Rej DAMA\n" +"Sri, kann tempfile nicht oeffnen...\r" +"%24.24s %6.6s: zurueckgewiesen (mailbox)\n" +"%lX-%lX (%lu Messages)\r" +"BROADCAST eingeschalten auf port %u (%s).\r" +"Server call: " +"\rMessage pool: " +"Empty\r" +"PACSAT BOX-Call ist jetzt " +"Filesystem neu geladen\r" +"CRC Fehler\n" +"Sprache %s kann nicht geladen werden.\r" +"Sprache ist auf %s eingestellt.\r" +"Fehler in Sprachdatei %s Zeile %d !!!\n%s\n" +"Folgende Sprachen wurden gefunden:\n" +"Es wurden keine Sprachdateien gefunden\n" +"Mein LogLevel ist %d\r" +"Fehler: Loglevel werte von 0 bis 4!\r" +"(%d/%d)\rAlias-:Call------IP--------------Mode-Port--PMode---Time----RX-----TX---Online-\r" +"Lausche auf UDP-port %u\r" +"AX25IP : kann nicht erstellen ip raw-socket: %s\n" +"AX25IP : kann nicht setzen non-blocking I/O auf ip raw-socket\n" +"AX25IP : kann nicht setzen SO_KEEPALIVE fuer ip : %s\n" +"AX25IP : kann nicht setzen IPTOS_THROUGHPUT fuer ip : %s\n" +"Fehler: startWinsock, fehler code: %d\n" +"AX25IP : kann nicht erstellen socket: %s\n" +"AX25IP : kann nicht setzen non-blocking I/O auf udp socket\n" +"AX25IP : kann nicht setzen SO_KEEPALIVE fuer udp : %s\n" +"AX25IP : kann nicht setzen IPTOS_THROUGHPUT fuer udp : %s\n" +"AX25IP : kann nicht erstellen udp socket: %s\n" +"Routing tabelle ist voll; eintragung ignoriert.\n" +"Ungueltige IP-Adresse!\r"; +"Unzulaessige Option\r" +"Unzulaessiger Parameter\r" +"AX25IP-Port nicht eingeschaltet!!!\n" +"UDP-Port unzulaessig, nicht geaendert !!!\r" +"Fehler: Eingestellter UDP-Port misslungen, UDP-Port wurde nicht geaendert !!!\n" +"UDP-Port erfolgreich geaendert\r" +"Fehler in Sprachdatei %s.txt,\nmaximale Zeilenlaenge von %d ueberschritten (letzte Meldung %d)!!!\n" +"Ungueltige Sprache (%s)!!!\n" +"Fehler in Sprachdatei %s.txt,\nmaximale Zeilenlaenge von %d unterschritten (letzte Meldung %d)!!!\n" +"Fehler in Sprachdatei %s Zeile %d ist zu lang !!!\n" +"Fehler: Loglevel wert von 0 bis 3!\r" +"Mein TCP-Port: %u\r" +"TCP-Port nicht eingeschaltet !!!\n" +"TCP-Port nicht guelig, keine Aenderung !!!\r" +"Fehler: Einstellter TCP-Port misslungen, TCP-Port wurde nicht geaendert !!!\r" +"TCP-Port erfolgreich geaendert.\r" +"Kann nicht socket fuer IPX erstellen : %s\n" +"Kann nicht Bind IPX addresse: %s\n" +"Fehler: Error: can't set non-blocking I/O on IPX socket" +"Fehler: Winsock kann nicht initialisiert werden!\n" +"Fehler %s: Socket kann nicht erstellt werden!\n" +"Fehler %s: ioctlsocket kann nicht initialisiert werden!\n" +"Fehler %s: Bind kann nicht initialisiert werden!\n" +"Fehler %s: Listen kann nicht initialisiert werden!\n" +"form_referer string zu lang" +"Route ist bereits eingetragen, bei neueintrag erst loeschen!!!\n" +"Sie sind schon als Sysop angemeldet!.\n +"*** Conversd rennt seit: %s\r" +"Ungueltige Qualitaet!\r" +"*** Hostname ist %s.\r" +"Kein Senden moeglich, Port ist ausgeschaltet!\r" +"Timeout fuer Dynamische Lern-Routen ist %u sekunden.\r" +"HTML-Statistik ist %d.\r" +"Error: HTML-Statistic wert ungueltig (0 - 1)" +"Error: timeout wert ungueltig (0 - 86400) !\r" +" (Port ist gesperrt!)\r" +"\r*** Insgesamt %d User auf allen Kanaelen ***\r" \ No newline at end of file diff --git a/doc/diverse_doc/Beipieldateien/conversd.g b/doc/diverse_doc/Beipieldateien/conversd.g new file mode 100644 index 0000000..b5516cf --- /dev/null +++ b/doc/diverse_doc/Beipieldateien/conversd.g @@ -0,0 +1,199 @@ +Commands may be abbreviated. Commands are: +/Away [text] Mark user as being away +/ALl text Send text to all users +/Beep Toggle Beep-Mode +/Channel n Switch to channel n +/CHARset [in [out]] Change terminal emulation (default ansi) +/Destinations List reachable ping-pong hosts +/Filter [calls] Set calls you want to filter +/Help [command] Print help information +/Invite user Invite user to join your channel +/IMsg user text Send Text to all on channel except user +/Links [args] List or setup links +/LISt List all channels and topics +/LEave [channel] Leaves specified or default channel +/Msg user|#channel text Send message to a user or joined channel +/ME text Write action to channel +/MOde [channel] options Set channel options +/NOtify [calls] Send notice if one of calls signs on +/Personal [text] Set personal description +/PRompt abcd Prompts a=query b=std c=ctrl-g d=ctrl-h +/Quit Terminate the convers session +/QUEry [user] Start/End a private conversation +/Topic [#chan] [text] Set channel topic. Text=@ removes topic +/UPtime How long is this conversd up ? +/Verbose Toggles verbose Flag +/VERSion Show version information +/Who [N|*|A|L|U|@] List users and their channel numbers +/WIdth [value] Set/show terminal width +@@ALL +If you are in /query mode, a text written with /all at the front will +be displayed as a normal convers text written to all users on this channel. +@@AWAY +/away sets an away-text for the other users. called with no additional +arguments, you are marked as being back again. +@@BEEP +(/beep /bell) +The beep command toggles a warning bell (^G) being sent before every message +coming from another user. This command really is a subset of the /prompt +command, see there. +@@CHAR +With this command, you can tell the convers deamon which type of umlauts you +prefer to use. The Syntax is /char [intype [outtype]]. For example, if you +work on an Atari st you could say: "/char atari atari". If you use a pc and +like to write your own umlauts in TeX style, "/char tex pc" may work. Use +"/char ?" to see a list. Play a bit around with this feature ! +Special Thanks to Thommy, (Internet mail) + (AmPR-Net mail) who wrote this nice feature. +Suggestions to this feature should be redirected to him :-) +Your char-setting will be stored when using "/pers", see there. +Please notice; use the correct charset for your program, not for your type +of computer. +@@DEST +(/destinations /hosts) +All Pingpong hosts in the network being connected to each other are listed. +The numbers shown in the list are response times in seconds. Use "/d #" to +see another form of this list. +@@EXCL +(/exclude /imsg /iwrite) +The exclude command is the opposite of the /msg command. You can send +messages to all users on the channel except the one given as the first +parameter. Internally these messages are sent as private messages to the +users, so links are flooded a bit more :-) +@@FAID +Welcome to the convers, select the right conversion for umlauts (/char), +set your personal description (/pers) +and change (/join) to another channel of your interest, if you want. +Whith /who you get an overview of the channels, more help with /help. +Have fun. +@@FILT +If you don't want to read texts from certain users, you can set a list +of calls. Messages from this calls are discarded for you. The syntax is +similar to "/notify". E.g. "/filter + dc1ik - db4ut" adds the user dc1ik +to the filter and removes db4ut from the list. +@@HELP +(/? /help) +The help command may be invoked with an additional parameter. I believe you +hacked in "help help" to see this, right ? :-). better try out help options +that are followed by an additional command. +@@INVI +An invitation tho the named user is sent. The invite is passed through all +convers nodes in the net. If the user is on another channel, he will be able +to join your private channel. If he is in the commandinterpreter on a node, +he will receive the invitation message. In the latter case he will be unable +to join a private channel directly. +@@JOIN +(/channel /join) +Join another channel. Unlike other other conversd implementations Ping-Pong- +conversd supports multiple channel joins the same time. Thus the old channel +is not left. You may do this by invoking "/leave". +@@LEAV +Invoking this command you will leave the actual channel or the specified +channel. If the given channel is your last existence in the convers channel, +you'll quit the whole program. +@@LINK +The current link state is displayed. In the standard version, host name, +link state, link round trip times, neighbour revision codes and state time +followed by time of next try and count of connect tries (on disconnected or +connecting links) are shown, connected lines print out their queue length +and total transmit statistics. +If you are sysop, you may also set up or remove links at runtime. +Connection-info will be shown in brackets additionally. +Syntax: /l [@ host]|[[+]|[-] host [port [via]]] +With "/l @host" you are able to get info from host (not all versions support +this function). +@@LIST +All channels, their topics (if set), flags (if some) and users are displayed. +@@ME +If you want to display an action you take, you might use this command. E.g. +entering the line "/me yawns" all connected users in this channel will see +a message like: "*** dc6iq yawns" +@@MODE +The mode command is one of the most complicated ones. It is invoked with +/mode <+|->>. + Flags may be a set of the following: + t - channel topic may be set by channel operators only + i - channel is invisible for users not on it + s - channel is secrect, only its number not displayed + m - channel is moderated, only channel-operators may talk + p - channel is private, invitation needed to join here + l - channel is local, no text forwarding to other nodes (NYI) + o - make a channel operator + +The plus indicates an option to be set, a dash resets the option. +A combination of + and - is allowed so the following command will work: +"/mode 69 -s+todc6iq". Channel 69 is no longer secret, but topics may be +set only by channel operators. In addition the user dc6iq becomes a channel +operator. +Without parameters, the current settings will be listed. +On channel 0 it is impossible to set modes! +@@MSG +(/msg /send /write) +Send a text to one special user or a joined channel. If the message should +be redirected to a channel, The command must be invoked in this syntax: +"/msg # ". The adressee (if user) can indicate the private +character of the message due to additional asterisks in his received lines. +a mesage written by dc6iq to dc1ik looks like this: "/m dc1ik This is a Test" +will be received by dc1ik like this: "<*dc6iq*>: This is a test". +@@NOTI +You are notified if one person out of the notification list appears on any +channel in this convers. E.g. "/notify + dc1ik" adds the user dc1ik to the +notification list, "/notify - db4ut" removes him from the list. The list is +initially treated as if a plus "+"-sign was given, multiple lists may be +specified. The following command would be legal and would result in adding +dc1ik, db4ut and dg3kcr to the list, while removing dc6iq and dh2paf: +"/notify dh2paf + dc1ik db4ut - dc6iq dh2paf +dg3kcr" +Removing non-members to the list is ignored. +@@PERS +(/note /personal) +A brief description can be set up, accessible to all users via the "/who"- +command. A typical Message looks like this: "/pers Fred, Buechig, JN49fb". +The description can be deleted with "/pers @". +The digi stores up to 118 chars of this description and set it automatically +when you enter convers (the settings of "/char" and "/width" will be stored +and set on login, too). Storing is also possible with simply "/pers". +@@PROM +The prompt command takes up to four arguments in one concatenated string. +Thus "/prompt abcd" will set up "a" for the query prompt, "b" for the +standard prompt. "d" is the character to remove the prompt, and "c" is +displayed whenever a text is sent to you. Normally you make "c" a control-G +(beep char) and "d" a backspace or delete character (control-h or 0x7f). +@@QUER +The username given as argument will be the only recipient for all further +texts. They are send as private messages (just like /m). With no optional +argument, the further texts go into the whole channel again. +@@QUIT +(/bye /exit /quit) +Passing this command to conversd, you will retire from the famous Ping-Pong +conversation. I hope you enjoyed this stuff :-) +@@TOPI +A brief description of the channel topic can be set. Other users can look +it up with the "/who quick" or "/list" commands. If the channel number is +omitted, the topic will be set to the current channel, else to the desired +one. If no #channel is given, the topic will appear on the current channel, +if specified, the topic on that channel will be set (only if youre logged +on to that channel). To clear a topic, just try to set a topic like "@" :-) +An empty topic command diplays the current's channel topic. +@@UPTI +The uptime command tells us how long this conversd is up and running. +@@VERB +The verbose flag is toggled. You will be flooded with information if you +enable this feature. +@@VERS +Print out version information to this software. +@@WHO +(/users /who) +This command shows the users and has multiple options: + n [channel] tabular form (limitable to one channel) + a [channel] away-text listing (limitable to one channel) + l [channel] long listing (limitable to one channel) + u users detailed infos to specified users + * [channel] listing of idle-times (own or specified channel) + @ host to specified host limited tabular form +without option you get a brief listing ("/list"). +@@WIDT +Tell conversd about your screen width. Then formatted messages will use the +entire screen. It is set to 80 by default. +Your width-setting will be stored when using "/pers", see there. +@@---- +rev3.12c/20001003 \ No newline at end of file diff --git a/doc/diverse_doc/Beipieldateien/conversd.xhf b/doc/diverse_doc/Beipieldateien/conversd.xhf new file mode 100644 index 0000000..21e92e4 --- /dev/null +++ b/doc/diverse_doc/Beipieldateien/conversd.xhf @@ -0,0 +1,205 @@ +Kommandos koennen abgekuerzt werden. Kommandos: +/Away [Text] markiert Dich als abwesend +/ALl Text Text an alle User Deines Kanals +/Beep Beep-Modus an/aus +/Channel n wechselt auf Kanal n +/CHARset [rein [raus]] setzt Zeichenwandler (ANSI ist Voreinstellung) +/Destinations listet erreichbare ping-pong Hosts +/EXClude User Text sendet Text an alle auf Deinem Kanal ausser User +/Filter [Calls] setzt Calls, deren Texte gefiltert werden sollen +/Help [Kommando] gibt Hilfe-Informationen +/Invite User laedt User auf Deinen Kanal ein +/Links [args] listet oder setzt (Sysops) conversd-Partner +/LISt listet alle Kanaele und ihre Themen +/LEave [Kanal] verlaesst Kanal oder derzeitigen Kanal +/Msg User|#Kanal Text sendet Text an User oder verbundenen Kanal +/ME Text sendet einen Aktionstext +/MOde [Kanal] Optionen setzt Kanaloptionen +/NOtify [Calls] setzt Calls, deren Erscheinen gemeldet werden soll +/Personal [Text] setzt persoenliche Beschreibung +/PRompt abcd Prompt setzen a=Query b=Normal c=Ctrl-g d=Ctrl-h +/Quit convers verlassen +/QUEry [User] startet/beendet private Konversation +/Topic [#Kanal] [Text] setzt Thema des Kanals. Thema=@ entfernt Thema +/UPtime wie lange laeuft dieser conversd ueberhaupt schon ? +/Verbose Laber-Modus an/aus +/VERSion zeigt Info zu dieser Version +/Who [N|*|A|L|U|@] zeigt User und Ihre Kanaele +/WIdth [Wert] setzt/zeigt Zeilenbreite +@@ALL +Wenn Du im /query Modus bist, wird Text mit vorangestelltem /all behandelt, +als wuerdest Du ohne /query arbeiten. +@@AWAY +/away setzt den Abwesendheitstext, den die anderen lesen koennen. Beim +Aufruf ohne Argument wird der Text geloescht und man gilt wieder als anwesend. +@@BEEP +(/beep /bell) +Hiermit wird das Klingelzeichen (^G), welches vor jeder Mitteilung gesendet +werden kann, ein- oder ausgeschaltet. Diese Kommando ist eigentlich eine +Untermenge des /prompt Befehls, siehe dort. +@@CHAR +Mit diesem Befehl kannst Du dem Convers mitteilen, welche Zeichensatzwandlung +Du haben moechtest. Die Syntax ist +/char [In-Typ [Out-Typ]] +Wenn Du z.B. mit einem Atari ST arbeitest, koenntest Du "/char atari" eingeben. +Wenn Du einen PC benutzt und Umlaute im TeX-Stil schreiben moechtest, gebe +"/char tex pc" ein, "/char ?" listet die Moeglichkeiten auf. Spiel ein +bisschen mit dieser Funktion. +Der Dank dafuer geht an Thommy, (Internet mail) + (AmPR-Net mail). Vorschlaege sollten an ihm +weitergeleitet werden. +Diese Einstellung wird bei "/pers" gespeichert (siehe dort). +Wichtig ist hier weniger der Rechnertyp, sondern der Zeichensatz, den das +verwendete Programm benutzt. +@@DEST +(/destinations /hosts) +Alle Pingpong-Hosts, die miteinander verbunden sind, werden aufgelistet. Die +Zahlen zeigen die Antwortszeiten in Sekunden. Mit "/d #" kann eine andere +Darstellung gewaehlt werden. +@@EXCL +(/exclude /imsg /iwrite) +Dieses Kommando ist das Gegenteil des /msg Befehls. Hiermit sendest Du Text +an alle User dieses Kanals ausser dem einen als ersten Parameter angegebenen. +Da der Text intern als privater Text an die Anderen verschickt wird, werden +die Links etwas mehr belastet :-) +@@FAID +Willkommen im Convers, passe die Wandlung der Umlaute an (/char), +setze Deine persoenliche Beschreibung (/pers) +und wechsele (/join) wenn Du moechtest auf einen anderen Kanal Deiner Wahl. +Eine Uebersicht der Kanaele erhaeltst Du mit /who , weitere Hilfe mit /help. +Viel Spass. +@@FILT +Wenn Du die Texte bestimmter User nicht lesen moechtest, so kannst Du sie +hiermit in eine Liste einfuegen. Alle Texte werden dann ausgefiltert, bei +persoenlichen Texten ("/msg") wird eine Rueckmeldung an den Absender geschickt. +Das Setzen/Loeschen geschieht wie bei "/notify", also z.B. +"/filter + dg7ncq - db4ut" setzt dg7ncq und loescht db4ut aus der Liste. +@@HELP +(/? /help) +Das Hilfekommando kann von zusaetzlichen Parametern gefolgt sein. Du hattest +bestimmt "/help help" eingetippt um dies hier zu sehen, gelle ? :-) +Der Schraegstrich darf hier nicht vor den fraglichen Kommandos stehen. +@@INVI +Es wird eine Einladung zum genannten User geschickt. Diese Einladung wird +durch das gesamte Netz geleitet. Wenn derjenige auf einem anderen Kanal +ist und Dein Kanal als privat eingerichtet ist, so kann er auf Deinen +Privatkanal wechseln. Wenn er im Befehlsinterpreter eines Knotens ist, so +empfaengt er die Einladung, er kann dann aber nicht direkt auf Deinen +Privatkanal kommen, weshalb er nochmals einzuladen ist. +@@JOIN +(/channel /join) +Verbindet Dich zusaetzlich mit dem gewuenschten Kanal. Im Gegensatz zu aelteren +conversd-Implementationen, verbleibt man auch noch im vorherigen Kanal, denn +es wird eine Mehrfach-Kanal-Verbindung unterstuetzt. Um einen Kanal zu +verlassen, musst Du "/leave" verwenden. Ohne Angabe eines Kanals, werden Infos +zu den von Dir benutzten Kanaelen ausgegeben. +@@LEAV +Mit diesem Befehl kannst Du entweder den derzeitigen oder den angegebenen +Kanal verlassen. Wenn dieser der letzte ist, so wird conversd verlassen. +@@LINK +Der momentane Linkstatus wird angezeigt. Dies sind normalerweise Hostname, +Linkstatus, Laufzeiten, Versionskodes und Statuszeit, gefolgt von der Zeit +des naechsten Connectversuches und Anzahl der Versuche (auf Disconnecteten +oder im Aufbau befindlichen Links), bei bestehender Verbindung werden die +Queue-Laengen und Byte-Statistiken angezeigt. +Wenn Du Sysop bist, kannst Du Verbindungen Setzen oder Loeschen. Es wird +dann auch noch zusaetzlich in Klammern der Verbindungsweg angezeigt. +Syntax: /l [@ Host]|[[+]|[-] Host [Port [via]]] +Mit "/l @ Host" koennen andere Hosts fernabgefragt werden (wird nicht von +allen Versionen unterstuetzt). +@@LIST +Alle Kanaele, ihre Themen, Optionen und User werden angezeigt. +@@ME +(/me /action) +Dieser Befehl dient dazu, den Usern auf Deinem Kanal eine Taetigkeit +anzuzeigen. Wenn du z.B. "/me gaehnt" eingibst, bekommen alle User dieses +Kanals folgendes angezeigt: +*** dc6iq gaehnt +@@MODE +Das mode-Kommando ist eines der kompliziertesten. Es wird wie folgt benutzt: +/mode [] <+|->>. + Die Optionen bedeuten folgendes: + t - Das Thema des Kanals laesst sich NUR von Kanal-Sysops aendern + i - Der Kanal wird Usern anderer Kanaele verheimlicht + s - Der Kanal ist geheim, die Kanalnummer wird nicht mehr angezeigt + m - Der Kanal ist moderiert, nur Kanal-Sysops duerfen schreiben + p - Der Kanal ist privat, man benoetigt eine Einladung zum Einloggen + l - Der Kanal ist lokal, Texte werden nicht weiterverteilt + o - macht zum Kanal-Sysop (kein - moeglich) + +Das Plus setzt eine Option, der Strich loescht sie. Es sind Kombinationen +erlaubt, so wuerde "/mode 69 -s+todc6iq" folgendes bewirken: Kanal 69 ist +nicht mehr geheim, aber die Themen duerfen nur vom Kanal-Sysop gesetzt +werden. Zusaetzlich wird dc6iq ein Kanal-Sysop. +Ohne Angabe von Parametern werden die derzeitigen Optionen angezeigt. +Auf Kanal 0 sind keine Modes setzbar! +@@MSG +(/msg /send /write) +Sendet einen Text an einen speziellen User oder an einen verbundenem Kanal. +Wenn der Text an einen Kanal gehen soll, so muss man folgendes eingeben: +"/msg # ". Wenn das Ziel ein User ist, so kann er den Text +an den zusaetzlichen Sternchen erkennen. Z.B. wenn dc6iq eine Nachricht an +dc1ik mit "/m dc1ik Das ist ein Test" sendet, so erhaelt dc1ik folgendes: +"<*dc6iq*>: Das ist ein test". +@@NOTI +Du wirst informiert, wenn eine bestimmte Person in der Personenliste im +convers erscheint. Z.B. fuegt "/notify + dc1ik" dc1ik in die Liste ein, +"/notify - db4ut" entfernt db4ut aus der Liste. Das Einfuegen/Loeschen +mehrerer Calls in einem Kommando ist moeglich, z.b. bewirkt +"/notify + dc1ik db4ut - dc6iq dh2paf +dg3kcr", dass dc1ik, db4ut und dg3kcr +eingefuegt und dc6iq und dh2paf entfernt werden. Das Entfernen von Calls, +die nicht in der Liste stehen wird ignoriert. +@@PERS +(/note /personal) +Es kann eine kurze Beschreibung zu Deiner Person gesetzt werden, den die +anderen User mit "/who" sehen koennen. Z.B: "/pers Fred, Buechig, JN49fb". +Mit einem @ als Text wird sie geloescht. Diese Implementation merkt sich +bis zu 118 Zeichen der Beschreibung und setzt diese dann automatisch beim +Einloggen (die "/char" und "/width" Einstellungen werden dann auch +gespeichert und beim Einloggen gesetzt). Speichern ist auch ohne Setzen +moeglich, einfach ohne Text aufrufen. +@@PROM +Das prompt-Kommando nimmt vier Argumente in einer zusammenhaengenden Zeichen- +kette. "/prompt abcd" setzt "a" als "/query"-Prompt, "b" fuer den normalen +Prompt. "d" ist ein Zeichen um den Prompt zu loeschen (also normalerweise +Backspace (^H) oder Delete). "c" ist ein Zeichen, welches vor jedem Text, +den Du empfaengst, gesendet wird (normalerweise also ^G). +@@QUER +Der angegebene User ist in Zukunft der einzige Empfaenger fuer alle Texte, +die Du eingibst. Diese werden dann als private Texte an den User geschickt, +wie bei "/m". Zum Ausschalten, ohne Argument aufrufen, danach geht alles +wieder wie gewohnt an den Kanal. Sozusagen ein Privatmodus. +@@QUIT +(/bye /exit /quit) +Wenn Du das eingibst, verlaesst Du diesen wunderbaren Ping-Pong-Convers. +Das willst Du doch nicht wirklich? :-) +@@TOPI +Hiermit kann fuer den Kanal ein Thema gesetzt werden. Die anderen User +koennen dieses sehen, wenn sie "/who" oder "/list" eingeben. Wenn keine +Kanalnummer angegeben wird, so wird das Thema des aktiven Kanals gesetzt. +Wird eine Nummer angegeben, so musst Du auch auf diesem Kanal eingeloggt sein. +Um das Thema zu loeschen, ist als Thema ein "@" einzusetzen. +@@UPTI +Dieser Befehl zeigt an, wielange conversd schon aktiv ist. +@@VERB +Schaltet die Laber-Option ein/aus. Du bekommst dann viele Informationen +ueber Aktionen der User (Einloggen/Ausloggen/Texte-setzen/...), auch wenn +diese nicht auf Deinem Kanal sind. +@@VERS +Zeigt etwas Text zu dieser Version (in englisch). +@@WHO +(/users /who) +Dieser Befehl zeigt die eingeloggten User und hat mehrere Optionen: + n [Kanal] tabellarische Darstellung (auf einen Kanal begrenzbar) + a [Kanal] Abwesendheitsliste (auf einen Kanal begrenzbar) + l [Kanal] ausfuehrliche Liste (auf einen Kanal begrenzbar) + u Userliste ausfuehrliche Infos zu den Usern in der Userliste + * [Kanal] Liste der Idlezeiten (eigener oder angegebener Kanal) + @ Host auf Host begrenzte tabellarische Darstellung +ohne Option wird die kurze Darstellung, wie bei "/list", ausgegeben. +@@WIDT +Macht conversd Deine Bildschirmbreite (Zeichen/Zeile) bekannt. Die Meldungen +der anderen wird dann auf diese Breite gebracht. Voreingestellt ist 80. +Diese Einstellung wird bei "/pers" gespeichert (siehe dort). +@@---- +rev3.12c/20001003 diff --git a/doc/diverse_doc/Beipieldateien/tnnini.all.txt b/doc/diverse_doc/Beipieldateien/tnnini.all.txt new file mode 100644 index 0000000..f7ac69a --- /dev/null +++ b/doc/diverse_doc/Beipieldateien/tnnini.all.txt @@ -0,0 +1,168 @@ +# This is a sample of the file tnn.ini with all options and devices shown. +#----------------------------------------------------------------------------- +# Average rounds/sec (default is missing is 100) - the real value depends +# on processor power and system load. Increase this on heavy loaded systems +# and if you have high speed ports (76800 baud and up) +#rounds 200 +# File permissions for files created by TNN - octal value as used by umask(2) +# default value = 000 (world readable/writable) +# use 077 to limit access to the owner of TNN +#perms 077 +# Working directory for TNN +tnn_dir /usr/local/tnn/ +# Unix-Socket for TNT hostmode interface (optional) +#tnn_socket /usr/local/tnn/tnn-socket +# Program to start before using any hardware ports (optional) - don't use +# any parameters! +#tnn_start kill_other_processes +# Number of buffers (optional; default = 10000) +buffers 10000 +# file containing process id (mandatory) +tnn_procfile tnn.pid +#----------------------------------------------------------------------------- +# device 1 = Tokenring on /dev/ttyS0; 38400 Bd; Ports 0 and 1 +device /dev/ttyS0 +# lockfile for device 1 +tnn_lockfile /var/lock/LCK..ttyS0 +# speed on device 1 +speed 38400 +# type of KISS on device 1: +# 0 = KISS, 1 = SMACK, 2 = RMNC-KISS, 3 = Tokenring (1st device only), +# 4 = Vanessa, 5 = SCC, 6 = TF (experimental!), 7 = IPX (1 IPX port only), +# 8 = AX25IP (1 AX25IP port only), 9 = Loop, 10 = Kernel-AX.25 Interface +# 11 = Kernel-AX.25 Interface for DG1KJD-Kernel +kisstype 3 +# L2-Port associated with device 1 - use several port lines, if kisstype = 3 +port 0 +port 1 +#----------------------------------------------------------------------------- +# device 2 = standard KISS on /dev/ttyS1; 9600Bd; Port 2 +device /dev/ttyS1 +# lockfile for device 2 +tnn_lockfile /var/lock/LCK..ttyS1 +# speed on device 2 +speed 9600 +# type of KISS on device 2: +# 0 = KISS, 1 = SMACK, 2 = RMNC-KISS, +# 4 = Vanessa, 5 = SCC, 6 = TF (experimental!), 7 = IPX (1 IPX port only), +# 8 = AX25IP (1 AX25IP port only), 9 = Loop, 10 = Kernel-AX.25 Interface +# 11 = Kernel-AX.25 Interface for DG1KJD-Kernel +kisstype 0 +# L2-Port associated with device 2 +port 2 +#----------------------------------------------------------------------------- +# device 3 = SMACK on /dev/ttyS2; 115200 Bd; Port 3 +device /dev/ttyS2 +# lockfile for device 3 +tnn_lockfile /var/lock/LCK..ttyS2 +# speed on device 3 +speed 115200 +# type of KISS on device 3: +# 0 = KISS, 1 = SMACK, 2 = RMNC-KISS, +# 4 = Vanessa, 5 = SCC, 6 = TF (experimental!), 7 = IPX (1 IPX port only), +# 8 = AX25IP (1 AX25IP port only), 9 = Loop, 10 = Kernel-AX.25 Interface +# 11 = Kernel-AX.25 Interface for DG1KJD-Kernel +kisstype 1 +# L2-Port associated with device 3 +port 3 +#----------------------------------------------------------------------------- +# device 4 = RMNC-Kiss on /dev/ttyS3; 19200 Bd; Port 4 +device /dev/ttyS3 +# lockfile for device 4 +tnn_lockfile /var/lock/LCK..ttyS3 +# speed on device 4 +speed 19200 +# type of KISS on device 4: +# 0 = KISS, 1 = SMACK, 2 = RMNC-KISS, +# 4 = Vanessa, 5 = SCC, 6 = TF (experimental!), 7 = IPX (1 IPX port only), +# 8 = AX25IP (1 AX25IP port only), 9 = Loop, 10 = Kernel-AX.25 Interface +# 11 = Kernel-AX.25 Interface for DG1KJD-Kernel +kisstype 2 +# L2-Port associated with device 4 +port 4 +#----------------------------------------------------------------------------- +# device 5 = Vanessa; Port 5 +device Vanessa +# type of KISS on device 5: +# 0 = KISS, 1 = SMACK, 2 = RMNC-KISS, +# 4 = Vanessa, 5 = SCC, 6 = TF (experimental!), 7 = IPX (1 IPX port only), +# 8 = AX25IP (1 AX25IP port only), 9 = Loop, 10 = Kernel-AX.25 Interface +# 11 = Kernel-AX.25 Interface for DG1KJD-Kernel +kisstype 4 +# L2-Port associated with device 5 +port 5 +#----------------------------------------------------------------------------- +# device 6 = SCC on /dev/scc0; Port 6 +device /dev/scc0 +# lockfile for device 6 +tnn_lockfile /var/lock/LCK..scc0 +# type of KISS on device 6: +# 0 = KISS, 1 = SMACK, 2 = RMNC-KISS, +# 4 = Vanessa, 5 = SCC, 6 = TF (experimental!), 7 = IPX (1 IPX port only), +# 8 = AX25IP (1 AX25IP port only), 9 = Loop, 10 = Kernel-AX.25 Interface +# 11 = Kernel-AX.25 Interface for DG1KJD-Kernel +kisstype 5 +# L2-Port associated with device 6 +port 6 +#----------------------------------------------------------------------------- +# device 7 = TNC with TF 2.7b on /dev/ttyS4; 19200 Bd; Port 7 +# WARNING! This configuration is NOT recommended for a standalone digipeater! +device /dev/ttyS4 +# lockfile for device 7 +tnn_lockfile /var/lock/LCK..ttyS4 +# speed on device 7 +speed 19200 +# type of KISS on device 7: +# 0 = KISS, 1 = SMACK, 2 = RMNC-KISS, +# 4 = Vanessa, 5 = SCC, 6 = TF (experimental!), 7 = IPX (1 IPX port only), +# 8 = AX25IP (1 AX25IP port only), 9 = Loop, 10 = Kernel-AX.25 Interface +# 11 = Kernel-AX.25 Interface for DG1KJD-Kernel +kisstype 6 +# L2-Port associated with device 7 +port 7 +#----------------------------------------------------------------------------- +# device 8 = IPX; Port 8 +device ipx +# type of KISS on device 8: +# 0 = KISS, 1 = SMACK, 2 = RMNC-KISS, +# 4 = Vanessa, 5 = SCC, 6 = TF (experimental!), 7 = IPX (1 IPX port only), +# 8 = AX25IP (1 AX25IP port only), 9 = Loop, 10 = Kernel-AX.25 Interface +# 11 = Kernel-AX.25 Interface for DG1KJD-Kernel +kisstype 7 +# L2-Port associated with device 8 +port 8 +#----------------------------------------------------------------------------- +# device 9 = AX25IP; Port 9 +device ax25ip +# type of KISS on device 9: +# 0 = KISS, 1 = SMACK, 2 = RMNC-KISS, +# 4 = Vanessa, 5 = SCC, 6 = TF (experimental!), 7 = IPX (1 IPX port only), +# 8 = AX25IP (1 AX25IP port only), 9 = Loop, 10 = Kernel-AX.25 Interface +# 11 = Kernel-AX.25 Interface for DG1KJD-Kernel +kisstype 8 +# L2-Port associated with device 9 +port 9 +#----------------------------------------------------------------------------- +# device 10 = Kernel-AX.25; Port 10 (example with Interface ax0) +device ax0 +# type of KISS on device 10: +# 0 = KISS, 1 = SMACK, 2 = RMNC-KISS, +# 4 = Vanessa, 5 = SCC, 6 = TF (experimental!), 7 = IPX (1 IPX port only), +# 8 = AX25IP (1 AX25IP port only), 9 = Loop, 10 = Kernel-AX.25 Interface +# 11 = Kernel-AX.25 Interface for DG1KJD-Kernel +kisstype 10 +# L2-Port associated with device 10 +port 10 +#----------------------------------------------------------------------------- +# device 11 = DG1KJD-Kernel-AX.25; Port 11 (example with Interface ax0) +device ax0 +# type of KISS on device 11: +# 0 = KISS, 1 = SMACK, 2 = RMNC-KISS, +# 4 = Vanessa, 5 = SCC, 6 = TF (experimental!), 7 = IPX (1 IPX port only), +# 8 = AX25IP (1 AX25IP port only), 9 = Loop, 10 = Kernel-AX.25 Interface +# 11 = Kernel-AX.25 Interface for DG1KJD-Kernel +kisstype 11 +# L2-Port associated with device 11 +port 11 +# +# END \ No newline at end of file diff --git a/doc/diverse_doc/TNN Kurzanleitung User.pdf b/doc/diverse_doc/TNN Kurzanleitung User.pdf new file mode 100644 index 0000000..72eb738 Binary files /dev/null and b/doc/diverse_doc/TNN Kurzanleitung User.pdf differ diff --git a/doc/diverse_doc/TNN179mh05.pdf b/doc/diverse_doc/TNN179mh05.pdf new file mode 100644 index 0000000..2e480c7 Binary files /dev/null and b/doc/diverse_doc/TNN179mh05.pdf differ diff --git a/doc/diverse_doc/tnn179_cb.doc b/doc/diverse_doc/tnn179_cb.doc new file mode 100644 index 0000000..69027e5 Binary files /dev/null and b/doc/diverse_doc/tnn179_cb.doc differ diff --git a/doc/diverse_doc/tnn179_cb.pdf b/doc/diverse_doc/tnn179_cb.pdf new file mode 100644 index 0000000..8019305 Binary files /dev/null and b/doc/diverse_doc/tnn179_cb.pdf differ diff --git a/doc/diverse_doc/tnn179_cb2004.pdf b/doc/diverse_doc/tnn179_cb2004.pdf new file mode 100644 index 0000000..c6247a0 Binary files /dev/null and b/doc/diverse_doc/tnn179_cb2004.pdf differ diff --git a/doc/diverse_doc/tnn179_cb2006.pdf b/doc/diverse_doc/tnn179_cb2006.pdf new file mode 100644 index 0000000..1bd1842 Binary files /dev/null and b/doc/diverse_doc/tnn179_cb2006.pdf differ diff --git a/doc/diverse_doc/tnn179_cb_2.pdf b/doc/diverse_doc/tnn179_cb_2.pdf new file mode 100644 index 0000000..7835cef Binary files /dev/null and b/doc/diverse_doc/tnn179_cb_2.pdf differ diff --git a/doc/englisch.txt b/doc/englisch.txt new file mode 100755 index 0000000..8158173 --- /dev/null +++ b/doc/englisch.txt @@ -0,0 +1,351 @@ +"Convers session terminated.\rEnter command. Type HELP for help.\r" +"*** You are already in convers-mode.\r" +"The Convers-Hostname is to long (max.9 indications)!\r" +"Convers-Hostname successful changed in %s.\r" +"Locked!\r +"%s%s@%s has gone away:\r %s\r" +"%s%s@%s is back again.\r" +"%s%s made you a channel operator for channel %d\r" +"%s%s@%s is now a channel operator for channel %d\r" +"channel %d" +"%s%s@%s on %s set personal text:\r %s\r" +"%s%s@%s on %s removed personal text.\r" +"%s%s@%s on %s set channel topic:\r %s\r" +"%s%s@%s on %s removed channel topic.\r", +"secret channel" +"this invisible channel" +"%s%s:%s@%s on %s set personal text:\r %s\r" +"%s%s:%s@%s left %s.\r" +"%s%s@%s left %s.\r" +"%s%s@%s left %s (%s).\r" +"%s%s:%s@%s joined %s\r" +"%s%s@%s joined %s\r" +"%s%s is away: %s" +"%sYour messages are ignored by %s" +"\r\a\a%sMessage from %s...\rPlease join %s channel %d.\r\a\a\r" +"%s%s Invitation sent to %s @ %s." +"%sUser %s is already on this channel." +"*** Unknown command '/" +"'. Type /HELP for Help.\r" +"*** You are away, aren't you ? :-)\r" +"*** This is a moderated channel. Only channel operators may write.\r" +"*** Queried user left channel.\r" +"%sYou are marked as being away.\r" +"%sYou are no longer marked as being away.\r" +"%sActually you were marked as being here :-)\r" +"*** Beep mode %sabled\r" +"%sYou are talking to channel %d. There are %d users.\r" +"*** current Topic by: %s (%s):\r " +"*** Also attached:" +"channel %d (alone)" +"channel %d (%d users)" +"%sChannel number must be in the range 0..%d.\r" +"%sChannel %d is already default.\r" +"%sYou need an invitation to join the privat channel %d.\r" +"%s%s@%s try to join your privat channel." +"%scannot join channel %d, no more space.\r" +"%sYou are now talking to channel %d" +"You're alone.\r" +"There are %d users.\r" +"*** Charset in/out is %s/%s.\r" +"Unknown charset: '%s'. You may use one of them:\r%s***\r" +"*** Charset in/out set to %s/%s.\r" +"Help on this command not yet implemented ...\rWrite it - or try another one :-)\r" +"No such command...\r" +"*** no route to %s\r" +"%sDefault channel is now %d.\r" +"%sLeft channel %d.\r" +"%sYou were not on channel %d.\r" +"*** Reguest sent to %s.\r" +"You must be an operator to set a new links\r" +"Link table full !\r" +"Argument error !\r" +"%sYou have not joined channel %d.\r" +"%sNo such user: %s.\r" +"%s%s is away: %s\r" +"*** non existing channel !\r" +"*** no modes on channel 0 !\r" +"*** You are not on operator !\r" +"%s @ %s PingPong-Release %5.5s (TNN) - Type /HELP for help.\r" +"%sYou need an invitation to join channel %d.\r" +"%s%s@%s try to join your privat channel." +"*** You created a new channel %d.\r" +"*** Personal text and date set.\rHello, %s\r" +"*** Please set your personal text. ( /H PERS )\r" +"%sYou are notified if one of the following users sign on/off:\r" +"%sYou filter the messages of the following users:\r" +"*** %s is online.\r" +"and data saved.\r" +"*** No personal text save.\r" +"deleted.\r" +"and data set.\r" +"*** Prompting mode %sabled\r" +"en" +"dis" +"You must be an operator to restart!\r" +"Link to %s delocked.\r" +"%sNo such user: %.20s.\r" +"%sStarting privat conversation with %s.\r" +"%sEnding privat conversation with %s.\r" +"%sChannel topic on channel %d removed from %s (%s).\r" +"%sChannel topic set on channel %d from %s (%s).\r" +"%sCurrent channel topic on channel %d from %s (%s) is\r " +"%sNo current channel topic on channel %d.\r" +"%sChannel channel %d non existent.\r" +"*** %s@%s is up for %s\r" +"*** Verbose mode %sabled\r" +" This conversd implementation was originally written by Dieter Deyke\r . It was modified and maintained up to version\r 3.11 by Fred Baumgarten, dc6iq. This implementation is partly rewritten,\r enhanced and maintained by " +"Odo Roscher \r for TheNetNode and Xnet.\r" +" Idle Personal\r" +"Login State\r" +"Login Personal\r" +"(here)" +"\r Away: " +" (since " +" (AWAY)" +"\r Last Activity: " +"*** Current screen width is %d\r" +"*** Range 32 to 255\r" +"*** Screen width set to %d\r" +"*** Urgent message from operator (%s):\r " +"*** Links at %s" +"free" +"*** Nickname set to: %s.\r" +"none login possible!\rcall signal %s is logged in at the host %s!\r" +"*** your password was deleted!\r" +"*** no password set!\r" +"*** reads. your password:\r%s\r" +"*** it is not defined a password!\r" +"*** password was set!\r" +"*** password must contain at least 5 and/or maximally 80 indications!\r" +"*** is missing. to password!\r" +"*** Syntax: pass [new password]\r" +"*** password is correct!\r" +"*** password is wrong!\r" +"*** current Topic by: %s (%s):\r %s\r" +"\r*** %d user on channel%s ***\r" +" Average: %lu" +"\r%7s00 02 04 06 08 10 12 14 16 18 20 22\r%9s01 03 05 07 09 11 13 15 17 19 21 23 Hour\r\r" +"\r%7s0 0 1 1 0 0 1 1 0 0 1 1 0 0 1 1 0 0 1 1 0 0 1 1 0 0 1 1\r"%7s0 6 2 8 0 6 2 8 0 6 2 8 0 6 2 8 0 6 2 8 0 6 2 8 0 6 2 8 h\r%7sMonday Tuesday Wednes. Thursd. Friday Saturd. Sunday\r\r" +" Elap. time\r%6s-3600 -3240 -2880 -2520 -2160 -1800 -1440 -1080 -720 -360 0 Seconds\r\r" +"> DISCONNECT: Too many non-DAMA Polls (%u) !!\r" +"WARNING: non-DAMA Poll #%u, Disconnect after %u !!\r" +"Graph cleared!\r" +"SYSTEMGRAPH:\r" +"(G)raph (H)our (B)aud\r (D)ay (C)ircuits\r (W)eek (F)ree buffers\r (L)2-Links\r (N)odes\r (R)ounds\r (*) All\r" +"PORTGRAPH:\r(G)raph (H)our (I)nfo frames\r (D)ay (R)eject frames\r (W)eek (F)rmr frames\r (S)abm frames\r dis(C) frames\r" +" d(M) frames\r (*) All\r" +"\r*** from DAMA-Master " +"%s<>%s broken" +"You are suspended.\r" +"\r- Aborted -\r\r" +"Sri, no text available!\r" +"CLI failed!\r" +"Waiting for AUTOBIN-Transfer...\r +"\rL2 - User:\r"Po SrcCall DstCall LS Rx Tx Tr SRTT RxB TxB Baud ConTime Pr Da\r" +"\rL4 - User:\rCall Node S Rx Tx Tr Win SRTT RxB TxB Baud ConTime\r" +"free" +"free" +"\rHost-User:\rCH Call F NT RX TX ST RxB TxB Baud ConTime\r-------------------------------------------------------------------------\r" +"\rTCPIP-User:\rIface SrcCall DstCall NT T3 RxB TxB Baud ConTime\r-------------------------------------------------------------------------\r" +"\r System Statistics: " +"\r Startup: " +"\r\r Port-Statistics:\r\r Links RxB TxB RxBaud TxBaud RxOver TxOver\r" +"\rTotal = " +" Bytes\r" +"\r Error-Statistics:\r\r" RxID RxLen RxCtl Resets\r" +"\rLink-Statistics:\r" +"\rLink to " +" via " +"\rFrames: I UI RR REJ RNR SABM/UA DISC/DM FRMR\r" +"Bytes: Total Info Header Overhead %I %RR %REJ %RNR\r" +" TQual:" +"\rIP-Gateway-Statistics:\r\r" +"free" +"free" +"Warning - Port not active.\r" +"Invalid callsign.\r" +"Invalid ident.\r" +"free" +"free" +"Type-Port--Alias:Call------Route--------------Infotext------------\r" +"No such User!\r" +"the Sysop password changed !\r" +"errors: The password must 80 indications contained !\r" +"editing>%s\rEnter text. End with '.' in a new line.\r" +"free" +"\r (min) (now) (max)\r Rounds/sec: %8lu %8lu %8lu\r" +" Free Buffers: %8u %8u %8u\rOverall Throughput:%18lu %8lu Baud\r Active L2-Links:%18u %8u\r Active Circuits:%18u %8u\r Active Nodes:%18u %8u\r" +"\r Active Sockets:%18u %8u\r" +"\r Buffer usage: %lu%%" +"\r Network Heap: %lu Bytes" +"\r CPU load: %lu%%" +"TX: Once:%11lu Repeated:%10lu IQual:" +" Copyright by NORD>. + += KERN DOWN: Deaktiviert das Interface zum Kernel. Das eingetragene Interface + und die automatisch im Kernel und tnn eingetragenen IP-Routen + werden geloescht, sonstige Routen im tnn-Router die auf das + Interface zeigen, bleiben eingetragen, sie funktionieren + aber natuerlich nicht mehr. Daten, die bei deDOWNtem Interface + durch noch bestehende Routeneintraege auf ein solches geroutet + werden, werden in den Biteimer befoerdert. + += allgemeines: etliche Kommandos sind nur nach vorheriger, erfolgreicher + Ausfuehrung anderer Kommandos moeglich oder haengen vom + derzeitigen Zustand des Interfaces ab. Wenn man etwas machen + will was derzeit nicht geht, erhaelt man (mehr oder weniger) + ausfuehrliche Meckermeldungen. Die Konfiguration eines Inter- + faces kann nur geaendert werden wenn es DOWN ist. Ausnahme: + IPA-Aenderungen, aber die werden bei aktivem Interface (noch) + nicht an den Kernel durchgereicht. Das Resultat ist denkbar + einfach: das Interface geht dann nicht mehr. + += Ablaufbeispiel: + - IPA 44.130.13.100 + - KERN INIT + - KERN SETKIP 44.130.13.102 bzw. KERN SETKIP db0uhi.ampr.org + - (KERN STATUS zum gucken) + - KERN UP + - ... + - (eventuell zusaetzliche Routeneintraege mit IPR) + - ... + - KERN DOWN + += STAT zeigt auch die Statistik des Kernelinterfaces mit an, diese kann auch + direkt mit "STAT K" abgefragt werden wenn eincompiliert. += Versionsbefehl zeigt Feature und Kernel als Interface an wenn eincompiliert diff --git a/history/178mh03.his b/history/178mh03.his new file mode 100755 index 0000000..8f7fae7 --- /dev/null +++ b/history/178mh03.his @@ -0,0 +1,9 @@ += IPA-Befehl modifiziert, Angabe der Subnetz-Bits jetzt moeglich. + Es findet KEINE UEBERPRUEFUNG statt ob das Subnetz zur IP passt, + also selber ausrechnen ! (soll spaeter mal anders werden) + Bsp: IPA 44.130.13.100/32 + += Meldung der eigenen IP und Subnetz-Bits per INP an andere Nodes += bei "SP" (SaveParam) Speicherung der eigene IP jetzt auch mit den + Subnetz-Bits + diff --git a/history/178mh04.his b/history/178mh04.his new file mode 100755 index 0000000..78ea6c5 --- /dev/null +++ b/history/178mh04.his @@ -0,0 +1,36 @@ += Aenderung bei den Subnetz-Bits bei IPA: sind keine angegeben so melden + wir uns mit 32 weiter, das sorgt dafuer, dass wir nur die eigene IP an + uns ziehen und nicht alles. + += per INP empfangene IP-Adressen und Subnetz-Bits anderer Digis werden in + entsprechende IPR- und ARP-Eintraege umgesetzt. + (Info: anlegen/aendern ueber src/l3inp.c::update_options(..) + loeschen ueber src/l3tab.c::add_route(..., qual=0) ->del_route(...) ) + += haben wir keine eigene IP (IPA 0.0.0.0) melden wir auch keine Subnetz-Bits + += ARP- und IPR-Eintraege werden nur gemacht wenn wir eine eigene IP + gesetzt haben und Parameter 12 gesetzt (!= 0) ist (siehe unten) + += neuer Par 12 ("AutoIPR") + 0 : ausgeschaltet, KEINE automatischen IPR- und ARP-Ein/Austragungen + (damit kann man die Tabellen einfrieren wenn sie gefuellt sind !) + 1 : automatische Ein/Austragung OHNE jegliche Pruefung der IP-Adressen + 2 : automatische Ein/Austragung, unmoegliche IP-Adressen werden ignoriert + (x.x.x.0 x.x.x.255) + 3 : automatische Ein/Austragung, es werden nur IP-Adressen beruecksichtigt, + die im GLEICHEN Netz wie man selbst und gueltig sind. (default) + (Bsp: hat man die IP 44.1.2.3 werden nur andere 44.x.x.x-IPs eingetragen) + + Die Pruefung mit Stufe 3 ist *dringend* zu empfehlen, wer sich mal genau + anguckt was da z.T. fuer schrottige Adressen von einigen Knoten verbreitet + werden, weiss warum. Moechte man alles offen haben ist Stufe 1 zu waehlen, + man sollte sich dann aber nicht wundern, wenn z.B. das lokale Ethernet + ploetzlich in die Botanik geroutet wird ! + + Auf die Befehle IPR und ARP haben diese Einstellungen keine Wirkung, von + Hand sind jederzeit weitere (auch unsinnige) Eintragungen moeglich. + += IPA: IP-Adressen die auf .0 oder .255 enden werden nicht akzeptiert. + (.0: Netzwerkbasisadresse, .255: Broadcastadresse, beide sind lt. IP-Spec + nicht als Hostadressen zugelassen) diff --git a/history/178mh05.his b/history/178mh05.his new file mode 100755 index 0000000..f9ffd22 --- /dev/null +++ b/history/178mh05.his @@ -0,0 +1,80 @@ += maximale Anzahl der moeglichen Connects von Usern zum Digi auf *einem Port* + jeweils fuer jeden Port seperat einstellbar + + Aktivierung : in include/all.h das "#define USERMAXCON" entkommentieren + + Anzahl der maximalen Connects einstellbar mit dem PORT-Befehl: + "PORT MAXCON ", + die Anzeige des eingestellten Wertes erfolgt mit dem Kommando + "PORT *" !!! + + Eine Anzahl von 0 deaktiviert die Funktion. (Voreinstellung) + + Diese Einstellung gilt fuer *alle* User auf dem angegebenen Port, einzelne + User muessen weiterhin mit SUSPEND beschraenkt werden. Es werden nur neue + Connects abgelehnt wenn die maximale Anzahl erreicht ist, wird die Anzahl + auf einen Wert niedriger als die aktuelle Anzahl an Connects eines Users + eingestellt, so bleiben diese Verbindungen bestehen. Neue Verbindungen die + ueber die Maximalzahl hinausgehen werden von Knoten mit BUSY abgelehnt. + + !!! ACHTUNG, WICHTIG !!! !!! ACHTUNG, WICHTIG !!! !!! ACHTUNG, WICHTIG !!! + + "SP" schreibt auch MAXCON in parms.tnb wenn die Funktion eincompiliert ist, + eine TNN-Version OHNE diese Funktionalitaet kann dann die generierten PORT- + Zeilen NICHT (!!!) verstehen und IGNORIERT SIE KOMPLETT !!! (d.h. alle + Porteinstellungen fuer diesen Port bleiben WIRKUNGSLOS und der Port + deshalb ggf. auch falsch konfiguriert und funktioniert nicht !!!. + + Abhilfe: jede Porteinstellung (oder nur die absolut wichtigen) in seperate + Zeilen schreiben. (oder mal den PORT-Befehl ueberarbeiten...) + + Nachtrag: PORT wurde irgendwann veraendert, beschriebenes Verhalten tritt + bei unbekannten Befehlen nicht mehr auf. + += AutoIPR setzte zwar die Subnetze, aber nicht die Gateways. Korrigiert. + += das Kernelinterface funktionierte wegen Aenderungen am Kernel mit Kernel + 2.4.6 nicht mehr. Jetzt geht es wieder, bei Problemen mit Kernel 2.2.x und + 2.4.x-Kerneln VOR 2.4.6 die Kommentare in os/linux/kernelif.h beachten !!! + += bei "SP" wurden beim Dump der IPR- und ARP-Eintraege Eintraege, die auf den + Kernel-Port zeigten, nicht korrekt geschrieben. Jetzt ok. + += bei "SP" wird auch die Konfiguration des Kernel-Interfaces geschrieben + WENN das Interface konfiguriert UND zum diesem Zeitpunkt aktiv ist. + Damit soll sichergestellt werden, dass nur gueltige und funktionierende + Konfigurationen geschrieben werden. + += bei "SP" wird auch die Konfiguration der AX25IP-Routen geschrieben + += neuer Sysop-Befehl "ALIAS" zum Einrichten von Kommando-Aliassen. + + Aktivierung: in include/all.h das "#define ALIASCMD" entkommentieren, + die maximale Laenge von Aliassen und den zugeordneten Kommandostrings + kann in include/typedef.h (ganz am Ende) geaendert werden, in der + Standardeinstellung koennen Aliasse acht Zeichen und die Kommandos 16 + Zeichen lang sein. + + !!! Das Alias und das Kommando werden in Grossbuchstaben konvertiert !!! + + Liste der definierten Aliasse abrufen: "alias". + + Alias hinzufuegen: "alias funkruf c db0xyz-12" legt das Kommandoalias + "FUNKRUF" an und verknuepft es mit dem Kommando + "C DB0XYZ-12". + + Alias loeschen: "alias funkruf" loescht das zuvor definierte Alias "FUNKRUF", + falls solch ein Alias nicht existiert gibts ne Meckermeldung. + += INP: halbstuendlich einmal die ganze Nodesliste an den Nachbarn melden + (l3misc.c::brosrv10(...)) + += INP: versteckte Nodes werden ignoriert wenn sie empfangen werden + (dafuer dass die erst gar nicht gemeldet werden ist eigentlich der + Ursprungsnode verantwortlich, aber einige andere Nodesofts kriegen + das anscheinend nicht gebacken) + += LINK-Befehl ueberarbeitet, durch Zufall eine nicht erkannte Abbruchbedingung + bei der Parameterauswertung gefunden (er suchte wild in der Gegend rum wenn + die Zeile nicht ganz gefuellt war, sprich nicht alle erwarteten Parameter + vorhanden waren) diff --git a/history/178mh06.his b/history/178mh06.his new file mode 100755 index 0000000..16cc72a --- /dev/null +++ b/history/178mh06.his @@ -0,0 +1,47 @@ += Linux: serielle Ports (KISS, RKISS, TOKENRING usw.) bis 460300 Baud + += Linux: Interfaces des Kernel-AX.25 koennen als Ports verwendet werden + + Aktivierung: #define KERNELIF (wie fuer das IP-Interface) muss aktiviert sein + + Einstellen: in tnn.ini: als "device" den Interfacenamen (ax0, ax1 usw.) + angeben, "kisstype" auf den Wert 10 stellen + + Bsp: + device ax0 + kisstype 10 + port 1 + + Das Interface muss natuerlich laufen wenn man sich daran binden will, also + das Kernel-AX.25 vor TNN starten, die Portparameter von TNN werden an das + Interface durchgereicht und falls von Kernel-Seite (z.b. durch kissparms) + Portparameter veraendert werden, so werden diese von TNN erkannt, durch + AutoParameter *alle* Parameter des Ports neu berechnet und an das Interface + zurueckuebertragen. Hierdurch kann es natuerlich vorkommen, dass die + vorher gesetzten Parameter wieder veraendert werden. + + Treten waehrend des Betriebs Probleme mit einem Kernelinterface auf, so + wird der betreffende Port ausgetragen ("PORT x OFF"). Ein Wiedereinschalten + (mit den alten Einstellungen) ist ggf. mit "PORT x ON" moeglich. + + DAMA-Master ist ungetestet, er sollte *NICHT* richtig funktionieren weil + wir nicht wissen wann das Interface das Frame wirklich fertig gesendet + hat !!! Aktivieren laesst er sich aber trotzdem, was dabei rauskommt + ist Glueckssache, der Kernel *kann* nicht melden wenn er fertig mit der + Aussendung ist. (ist nicht vorgesehen im Kernel-AX.25) + + DAMA-Slave laesst sich wie gewohnt mit "DAMA S" ueber den Port-Befehl + aktivieren und sollte funktionieren. + += Linux: Watchdog beendet sich auch bei Fehlern auf der Pipe, der + Hauptprozess wird schneller gekillt. + += MHeard korrigiert, Fehler wenn User auf mehr als einem Port gehoert wurde + (DG8BR) + += in der LINK-Struktur Variable "brotim" (Broadcast-Timer) von BOOLEAN (???) + auf UWORD geaendert + += kosmetische Korrekturen beim VER-Befehl. Inzwischen waren dort so viele + anzeigbare Optionen moeglich dass die Ausgabe ziemlich chaotisch aussah. + Hinweis auf nordlink.org hinzugefuegt. diff --git a/history/178mh07.his b/history/178mh07.his new file mode 100755 index 0000000..cd3e4c9 --- /dev/null +++ b/history/178mh07.his @@ -0,0 +1,43 @@ += INP: voller Nodes-Broadcast nur noch einmal pro Stunde, Aenderungen wegen + Broadcast an l3netrom.c::inform_peer() wieder rueckgaengig gemacht, + bessere Methode fuer INP nun direkt in l3misc.c::brosrv10() + implementiert. + + Es werden jetzt *alle* Nodes *unabhaengig* vom Horizont und den Filtern + bei der normalen Meldung gesendet !!! Dies soll sicherstellen, dass + auch Nodes, die bisher immer durch den Filter gefallen sind, + geupdated werden. + += INP: nach erster RTT-Messung sofort per zweiter Bake dem Nachbarn die RTT + mitteilen. Dies macht den Link sofort benutzbar und nicht wie bisher + erst nach der zweiten Bake. (nur bei Nachbarn die L3RTT unterstuetzen, + nicht bei Nachbarn die per BROAD arbeiten, funktioniert also auch bei + N/N+ Links) + += INP: wenn wir einen N/N+ Link aufbauen wollen senden wir die INP-Kennung + nicht mehr, empfangen wir INP-Faehigkeit des Nachbarn und wollen aber + N/N+, so ignorieren wir sie. Wollen wir I, der Nachbar kann(/will) das + aber nicht, so bauen wir N+ auf. + + ACHTUNG: INP-Links muessen jetzt also mit I auf *beiden* Seiten + eingestellt werden sonst gibts nur N+ !!!!!!!!!!!!!! + += INP: Filter geaendert, Knoten die mit "#temp" als Alias gemeldet werden, + werden uebernommen und der Alias geloescht. (XNet-Fehler) + Andere geheime Aliasse werden weiterhin ignoriert. + += 7conn.c::isheard() durchsucht die die MHeard-Liste nun umgekehrt. (DG8BR) + += Aenderungen am Flexnet-Modul und am GO32-Watchdog von DG8BR + (siehe flex178mh06.his) + += Linux: pty-Schnittstellen bei einer Baudrate von 0 auf nichtblockierenden + IO-Modus stellen (NICHT auf echte ser. Schnitstellen anwenden !) + += bei wenigen freien Buffern (100) kontrollierter Ausstieg, so wenig Buffer + kommen nicht vor, nur bei "Bufferfressern". Damit der Digi dann nicht + stehen bleibt sondern wiederkommt wird hier kontrolliert abgebrochen + (Exitcode -2). Ggf. werden die Parameter (save_parms()) nicht mehr + gesichert wenn zu dem Zeitpunkt nicht wieder genug Buffer zur Verfuegung + stehen. + diff --git a/history/178mh08.his b/history/178mh08.his new file mode 100755 index 0000000..f8ca58e --- /dev/null +++ b/history/178mh08.his @@ -0,0 +1,41 @@ += INP: Soll ein INP-Link aufgebaut werden, so wird die NODES-Bake nicht mehr + zusammen mit dem SABM waehrend des Verbindungsaufbaus gesendet. + += INP: Check der empfangenen Subnetzbits eines Nodes, ist deren Anzahl + kleiner oder gleich null oder groesser als 32, so werden die IP- + Daten des Nodes geloescht, der Node aber trotzdem uebernommen. + += INP: wird eine Abmeldung fuer einen Node empfangen, dann wird die Lifetime + dieses Knotens auf 0 gesetzt. Dies hilft anscheinend gegen Nodes die + mit einer Laufzeit von 0 in der Liste stehen und nicht ausgetragen werden + += Linux: Kernelinterfaceupdate wegen Fehlern in den Kerneln nach 2.4.6. + + Es werden bei Fehlern jetzt ausfuehrlichere Meldungen + geschrieben, fuer den Kernelfehler gibt es ein Workaround: + + Bei fehlerhaften 2.4.x-Kerneln heisst das Interface jetzt nicht + mehr 'tnn' sondern auch 'tunX'. (siehe Beschreibung fuer 2.2.x-Style). + + Es erfolgt eine Info ueber den Namenswechsel beim UPpen des + Kernelinterfaces. + += pacsat.c und pacserv.c ueberarbeitet, bessere Beschreibung und Beseitigung + des Fehlers der Pacsat unter Linux gelegentlich abstuerzen liess (DH6BB) + += Fehler behoben, dass Pacsat eine nicht vorhandene Datei loeschen wollte + (DH6BB) + += Connect im FlexNet-Stil (c -3 etc.) moeglich + += in der Statistik werden die auf Links gesendeten UI-Frames erfasst, da bisher + hierzu die Monitorfunktion benutzt wurde, konnte nicht festgestellt werden + an welchen Nachbarn das Frame eigentlich gesendet worden war da das Ziel + NODES ist. + += Linux: externe Texte deren Filenamen exakt acht Zeichen lang waren konnten + nicht verwendet werden (DH6BB) + += bei AutoIPR wurden in Mode 2 und 3 keine Eintraege durch del_node() + geloescht. Korrigiert. + diff --git a/history/178mh09.his b/history/178mh09.his new file mode 100755 index 0000000..c983a7b --- /dev/null +++ b/history/178mh09.his @@ -0,0 +1,35 @@ += INP: die stuendliche Nodes-Meldung an den Nachbarn konnte Nodes aus der + Tabelle entfernen die noch abgemeldet werden sollten. Jetzt werden + nur noch Nodes angefasst die eine Laufzeit haben. + += ALIAS-Kommando komplett neu implementiert, die alte Variante schien + Memory-Leaks zu produzieren, neue Variante arbeitet jetzt mit der + Listenverwaltung aehnlich wie MHeard. + += Kommando-Aliasse werden bei SP in die Parameterdatei geschrieben + += NETROM: Filter ergaenzt der verhindert, dass Nodes mit geheimen + Alias beim RX des alten NETROM Nodes-Broadcasts eingetragen werden + (nur altes NETROM, UI-Broadcasts) (DG8BR) + += FlexNet: Maxtime-Meldung wieder ausgebaut, laesst manchmal den Link stehen + bleiben (DG8BR) + += L2: pollt der Digi einen User und erreicht die maximale Anzahl an Polls + (N2-Zaehler) weil keine Antwort erhalten wurde, dann bekommt der User + ein DISC. Bisher erfolgte keine Reaktion ausser dem stillen "vergessen" + der Verbindung. + += Callcheck beim Connect-Befehl nicht machen wenn der User Sysop ist + += Linux: Kernel-AX.25 Interfaces konnten nicht immer geoeffnet werden wegen + einem Fehler in der Fehlerbehandlung. Es werden jetzt detaillierte + Fehlermeldungen geschrieben wenn Operationen fehlschlagen. + += Linux: Funktion xtempnam() neu implementiert wegen Meldung des Compilers + dass die bisher verwendete Systemfunktion tempnam() nicht sicher sei. + Jetzt wird mkstemp() verwendet. + += Problem mit nicht ausgetragenen Nodes war wieder aufgetreten, Erkennung + ob ein Peer-Eintrag benutzt ist oder nicht in drop_unreachable_nodes() + geaendert (pp->used anstelle von pp->routes) \ No newline at end of file diff --git a/history/178mh10.his b/history/178mh10.his new file mode 100755 index 0000000..7a937ee --- /dev/null +++ b/history/178mh10.his @@ -0,0 +1,91 @@ += Linux: AX25IP und AXIPX aufgeraeumt und von eigenen select()-Funktionen + befreit bei {ax25ip,axipx}_recv(). Die Pruefung auf lesbaren + Descriptor geschieht nun mit in linux.c::update_timer(), dort wird + nun fuer alle Interfacetypen die einen Filedescriptor benutzen + (AX25IP, AXIPX, Kernel-AX.25, Kernel-IP) auf die jeweiligen RX- + Funktionen verzweigt. Diese Massnahme sollte bei Verwendung der + beiden Modi eine geringere Auslastung bei hoeherer Reaktions- + schnelligkeit erbringen. ACHTUNG: AXIPX nicht getestet !!! + += viele Aenderungen und Fixes von Odo, DL1XAO (siehe 178or*.his) + += Soll ein INP-Link aufgebaut werden UND die RTT-Messung UND der + Faehigkeitsabgleich laeuft noch, dann senden wir keine Node-Infos + im NETROM-Format an den Nachbarn falls die RTT-Bake nicht innerhalb + von ein paar Sekunden wieder zurueckgekommen ist (l3misc.c::brosrv10()) + += L2: Aenderungen an der Statemachine wieder teilweise rueckgaengig gemacht + da mit DAMA nicht 100%ig vertraeglich, bei nicht-DAMA funktionsfaehig. + += Linux: Kernel-AX.25 mit dem Kernel-Stack von DG1KJD kompatibel gemacht. + Es erfolgt eine automatische Erkennung, welcher Stack vorliegt, + allerdings erfolgt eine Umschaltung in den KJD-Mode erst mit dem + ERSTEN EMPFANGENEN Frame !!! Frames, die auf einem KJD-Stack VORHER + gesendet werden, werden vom Stack als fehlerhaft erkannt und + NICHT GESENDET !!! Ein Setzen der L2-Parameter wie TX-Delay etc. + ist mit dem KJD-Stack zwar moeglich, wird aber noch nicht + unterstuetzt (mangels Testmoeglichkeit). Parameteraenderungen + (TX-Delay, TX-Tail etc.) muessen mit den fuer das jeweilige Interface + zur Verfuegung stehenden Tools erledigt werden !!! + += L4: Erweiterung des L4, es koennen Pakete jeglicher PID uebertragen + werden. Schaltbar per #define NEW_L4 in all.h. Funktioniert nur, wenn + Quell- und Zielknoten diese Modifikation unterstuetzen, d.h. nur + zwischen zwei TNN's !!! Defaultmaessig NICHT mit eincompiliert, + sollte nur zu Testzwecken eingeschaltet werden !!! + += ARP- und IPR-Eintraege werden (intern) markiert, ob sie von einer Automatik + (INP-Routenlerner) oder von Hand gemacht wurden. Ueber Automatik gelernte + Routen koennen von der Automatik UND von Hand (ARP/IPR-Befehl) ausgetragen + werden, von Hand gemachte Eintraege NUR von Hand. Dies verhindert, dass die + Automatik Eintraege austraegt, die schon vorher existent waren und + unabhaengig von den INP-Infos immer vorhanden sein sollen. So sind statische + Routen moeglich die nicht verloren gehen, auch wenn die INP-Infos zu diesem + Ziel entfernt werden. + + !!! aus .tnb-Files geladene Eintraege gelten als VON HAND gemacht !!! + += l3ip.c: Cache fuer IP-Routinginformationen implementiert, war zwar in den + Kommentaren zum Code erwaehnt, aber nirgends implementiert. Steht + nun in rt_find(). Zu aktivieren in all.h, #define IPRTCACHE. + += L2 nun mit Extended-AX.25. Eincompilieren mit #define EAX25 in all.h. + + Ob eine Gegenstation EAX.25 kann wird in MHeard vermerkt, aber nicht + gespeichert ! Ueber die zusaetzlichen Parameter EAXMAXF und EAXMODE beim + Port-Befehl laesst sich das Maxframe und das EAX.25-Verhalten auf dem Port + steuern. Hierbei gilt fuer EAXMODE folgendes: + + 0 nur AX.25 zugelassen, EAX.25-Verbindungen werden abgelehnt. + 1 Mode nach Faehigkeiten der Gegenstation bzw. nach MHeard. (AX.25 und EAX.25) + 2 nur EAX.25 zugelassen, AX.25-Verbindungen werden abgelehnt. + + Bei Mode 1 erfolgt ein Fallback auf AX.25 wenn ein EAX.25-Connect zur + Gegenstation mit DM beantwortet wurde. Mode 1 ist standardmaessig + eingestellt. + + EAXMAXF kann max. 127 sein, sollte jedoch 32 nicht ueberschreiten, + default ist 16. Bisher ist ein Maxframe groesser 7 noch nicht mit + allen Hardwareinterfaces getestet !!! Hier muss experimentiert werden. + (auf VANESSA funktionierts einwandfrei) + + Die zusaetzlichen Parameter bei Port sind mit "P *" abrufbar. + Parameter 1 (NoAckBuf) sollte bei Verwendung von EAX.25 entsprechend + vergroessert werden, hier sollte mindestens 1,5 * groesstes verwendetes + EAX.25-Maxframe eingestellt werden, damit immer genug Daten da sind. + + Die Maxframe-Automatik funktioniert analog wie bei AX.25 aber nur dann, + wenn sie bei AX.25 aktiviert worden ist ! Also dort beim Maxframe + ggf. das "a" machen (PO x MAXF=?a). Aenderung in Zukunft moeglich. + += Tokenring: mit neueren Rechnern, die mehrere tausend Runden pro Sekunde + schaffen, konnte der Tokenring auf ein fruehzeitiges "Timeout" laufen und + einen Tokenverlust annehmen weil zu viele Runden vergangen, das Token aber + noch nicht wieder da war, da ein von den Runden abhaengiger Zaehler benutzt + wurde. Jetzt wird ein echter Timer und ein Token-Timeout von zwei Sekunden + verwendet, Timeout einstellbar ueber TOKENTIMEOUT in all.h. + + Dieser Fehler betraf die DOS und die Linux-Version !!! + += Auf Ports, die als Interlinks arbeiten, Persistence anders einstellen + (l2misc.c::autopar() und l3misc::islinkport()) diff --git a/history/178nk01.his b/history/178nk01.his new file mode 100755 index 0000000..806ded1 --- /dev/null +++ b/history/178nk01.his @@ -0,0 +1,23 @@ += L3 neu sortiert - es entfallen l3a.c, l3b.c l3c.c; iproute.c heisst nun + l3ip.c. Neu: l3inp.c, l3misc.c, l3nbr.c, l3netrom.c, l3rtt.c, l3tab.c, + l3var.c, l3vc.c, l7showl3.c. l3.h entfaellt, statt dessen gibt es nun + l3local.h (nur fuer L3) und l3global.h (fuer alle Layer). + Verbesserungsvorschlaege zur Aufteilung bzw. zu Filenamen sind willkommen! + += L3: Bei der automatischen Nachbarerkennung werden beim umschalten von NETROM + auf INP alle bisher als UI gesendeten Ziele erneut gemeldet. + += Node-Call in Kleinschrift anzeigen, wenn INP-Options vorhanden. + += GO32-Include-Files include/{hardware.h,kiss.h,pc.h,vanessa.h,api.h,api32.h} + nach os/go32 verschoben. + += Linux-Version: bei STAT wird "Free RAM (Fmem)" nicht mehr angezeigt. + += DG9OBU: + - neues Kernel-Interface fuer Linux-Version (s. history/178mh01.his + und history/kernelif.his). + - neuer Befehl AXIPR (s. history/axipr.his) für Einstellungen, die bisher + nur ueber ax25ip.cfg (incl. Neustart) vorgenommen werden konnten. + += Auto-Update der Konfigurationsdateien TNNxxx.PAS und TNNxxx.TNB. diff --git a/history/178nk02.his b/history/178nk02.his new file mode 100755 index 0000000..651b116 --- /dev/null +++ b/history/178nk02.his @@ -0,0 +1,13 @@ += DG9OBU: Kernel-Interface nun fuer 2.2er und 2.4er Kernel + += DG9OBU: IPR-Automatik + += Bei DAMA zusaetzliche Sendepause alle ca. 30s + += L4: + - Zielknoten des Circuits wird als Call gespeichert, nicht mehr als + Eintrag der Nodesliste + - itol3 nun ohne Prioritaet (wurde sowieso nicht tatsaechlich verwendet) + += Hostmode: Anzeige bei "ESC Y" korrigiert - der eigentliche Fehler, dass + numhsts manchmal <0 wird, ist damit nicht beseitigt! diff --git a/history/178or01.his b/history/178or01.his new file mode 100755 index 0000000..c8eaec1 --- /dev/null +++ b/history/178or01.his @@ -0,0 +1,32 @@ +Änderungen in or01: +- fdfl und co sind weg, ersetzt durch etwas flexibleres, kein fdefblk + mehr, sondern fname, was man auch noch ausbauen könnte, um die + Begrenzung bei edit oder uploads auf ein File zu umgehen. + +- Der Convers ist ausschaltbar, er wird zwar nur durch Leeroutinen + ersetzt, aber zum Platz sparen reicht das. + +- NOPORTINMON baut die Monitorausgabe etwas um, damit bestimmte + Hostmodeprg etwas glücklicher sind, leider beeinflußt dies auch + die Ausgabe beim Monitortrace. + +- SETTAILTIME schaltet das Setzen der Tailtime ein, ist für TNC3 + recht nützlich. Langfristig würde ich es begrüßen, wenn in der + Expert-version alle Pars des L1 setzbar sind, sie können ja gerne + automatisch vorberechnet werden, aber wenn man was dran drehen will, + kann man es dann wenigstens. + +- Einige Funktionen, die ich in Assembler progr. hab, sind ausgedef't + + + + +---snip--- + +Notiz für Nils: +AutoIPR Prüfung... die Netzeeinteilung in Klassen gibs nimmer, folglich +ist die Prüfung auf *.255 *.0 nicht korrekt, dies muß abhängig von der +Maske passieren. HHB hat zB .64 und .127 als verbotene Adr. (/26). +in dem Sinne kann es auch keine /31er Maske geben, weil die beiden +entstehenden Adr. ebensolche Netz und BC Adr wären. + diff --git a/history/178or02.his b/history/178or02.his new file mode 100755 index 0000000..777aa55 --- /dev/null +++ b/history/178or02.his @@ -0,0 +1,39 @@ +Änderungen in or02, ausgehend von mh09: + +-Beenden der TNN bei < 100 Buffer in buffers.c nicht übernommen. + +-Variablen in l2rx.c für MaxCon lokalisiert und abgemagert. + +-Erweiterungen beim BC in eigne Funktion ausgelagert. + +-In l3nbr.c eine Variable eingespart. + +-ALIASCMD überarbeitet, Ersatz findet zentraler in ccpcmd() statt, wird mit + Listen realisiert und erlaubt es Parameter hinter den Aliassen zu übernehmen, + nur der Alias selbst wird in Großschreibung konvertiert. + +-bezugnehmend auf mh05 History, ccpport überarbeitet, sodaß auch nichtaktivierte + Sachen "gesetzt" werden können, sie werden halt einfach überlesen. + +-Da mir die po + Zeile zu breit wurde, hab ich die Überschrift 2-zeilig gemacht + +-In l7ip.c ist mal wieder unser Problem mit der Bitmaske zu sehen, wir sollten + wirklich mal über eine sinnvolle Prüfung diskutieren. (siehe vorherige + History, unten) und + wer bits == 1 liefert kann doch auch nicht die Wahrheit sagen, hier könnte + man durchaus ein minimum von 2..4 bits fordern, max 32 (keine 31!) und alles + was außerhalb ist wird ignoriert und nicht umgeändert (gilt als Fehler) + (bzw. 8 minimum, da ampr.net 44.x.x.x/8 ist) + +-In l7showl3.c; dump-raw-node-info hab ich nicht übernommen (war als Test + deklariert). + +-dump_port etwas angepaßt fr meinen Kram. + +-In search_file soll laut mh08-History ein Fehler sein, den muß mir aber erst + einer beweisen, da ich ihn bei Nachprüfung nicht finden kann, bzw. der Fehler + muß wenn, an anderer Stelle sein. + +-In mh_port_lookup war ein if zuviel. + + diff --git a/history/178or03.his b/history/178or03.his new file mode 100755 index 0000000..0dbdfd6 --- /dev/null +++ b/history/178or03.his @@ -0,0 +1,15 @@ +Änderungen in or03: + +-Im Convers die Callprüfung korrigiert und die Benutzung von clilin + in cvs_cmds.c ausgebaut. + +-valcal() Rückgabewert korrigiert. + +-Bei ccp_call() das if vorsorglich geändert. + + + +Änderungen in or03, ausgehend von mh10: + +-nur Übernahme in l3misc.c + diff --git a/history/179.his b/history/179.his new file mode 100755 index 0000000..8f4f1af --- /dev/null +++ b/history/179.his @@ -0,0 +1,6 @@ += neuen L4 vorerst wieder abgeschaltet um volle Kompatibilitaet zu anderen + Systemen zu wahren + += sonst keine Aenderungen seit pre8, nur Debugmodus ausgeschaltet und Hinweise + auf geaenderte Stellen aus dem Source entfernt, Adressen in der ALAS + aktualisiert, ReadMe auf Release angepasst diff --git a/history/179mh01.his b/history/179mh01.his new file mode 100755 index 0000000..7f0e67c --- /dev/null +++ b/history/179mh01.his @@ -0,0 +1,78 @@ ++ An FlexNet-Nachbarn melden wir statt wie bisher nun jeden unserer Locals + nicht mehr einzeln, sondern nur noch wie bei FlexNet ueblich einen SSID- + Bereich. + + Der gemeldete Bereich errechnet sich aus dem Knotencall sowie der minimalen + und maximalen SSID aller per Lokaleintrag (L/L+) angeschlossenen Ziele, die + das gleiche Call wie der Digi haben. Versteckte Locals (Alias mit '#' am + Anfang) werden ignoriert. + + Die Berechnung des Bereiches erfolgt bei der Sendung des 0er-Frames beim + Linkaufbau zu einem FlexNet-Nachbarn. Es kann nun aber vorkommen, dass + nicht hinter allen SSID des gemeldeten Bereiches auch ein Local ist. Des + weiteren ist fuer andere Knoten nicht ersichtlich, dass DB0XYZ-4 gar nicht + direkt am Netz haengt, sondern sich eigentlich hinter DB0XYZ befindet. Aus + diesen Gruenden muessen nun auch folgende Linkwuensche akzeptiert werden: + + * Linkwuensche, die an einen Local gerichtet sind. Diese Linkwuensche + werden mit der normalen Gateway-Funktion umgesetzt, der VIA-Schwanz + des eingehenden Links wird entfernt ! + * Linkwuensche, die an eine SSID unseres gemeldeten Bereiches gerichtet + sind, hinter denen aber kein Local steckt. Diese Links landen nun ganz + normal im Knoten. + + aber: + + * Linkwuensche an Locals die es zwar gibt, die aber grad nicht erreichbar + sind (L+), bleiben unbeantwortet. In diesem Fall landet man auch nicht + im Digi ! + + Aendert sich der verfuegbare SSID-Bereich waehrend der Interlink zum FlexNet- + Nachbarn schon besteht, so wird kein Update des Bereichs an den Nachbarn + durchgefuehrt, da hierzu der Link gekappt werden muesste. (FlexNet sieht + hier nur die Moeglichkeit vor, nach einer Aenderung des SSID-Bereichs diesen + per Link-Reset neu zu melden) + + Es ist nun auch moeglich, direkt auf den Einstiegen die Locals + unter deren Calls zu connecten. Dies wird spaeter vielleicht noch so + eingeschraenkt, dass dies nur auf Ports mit einem FlexNet-Interlink + moeglich ist, und auf allen anderen Ports wieder normal mit via connected + werden muss. + += Linux: Beim Aendern des UDP-Ports beim AXIPR-Befehl blieb TNN komplett + stehen. Es wurde keine Meldung ueber die positive Aenderung angezeigt. + (Problem gemeldet von Oliver Kern) + += Linux: Nicht existierende Kernel-AX.25-Interfaces wurden nicht korrekt als + nicht funktionierend gekennzeichnet, dadurch war beim Start ein + Haenger moeglich. Korrigiert. + += Linux: Die PCISCC4-Einsteckkarte ist nun mit Hilfe des 2.4.x-Treibers + von F6FBB mit normalem Kernel-AX.25 nutzbar. TNN verwaltet die + wichtigsten Portparameter selbst (TXD, TXT, PERS, Duplex) und + uebertraegt sie bei Aenderungen an die Karte. Fuer die korrekte + Konfiguration des angeschlossenen Modemtyps MUSS das zusaetzliche + Programm "setpciscc" verwendet werden !!! Mit diesem Programm + gemachte Aenderungen werden allerdings von TNN (noch) nicht wieder + uebernommen, da keine Benachrichtigung erfolgt. + + Zu aktivieren in include/all.h -> #define PCISCC4_KAX25 einschalten, + aber NUR wenn ein 2.4-Kernel mit dem Treiber vorhanden ist !!! Mit einem + normalen 2.4-Kernel kann dann NICHT compiliert werden !!! + += L4: "PID-Race" beim neuen L4 behoben. PID-Uebermittlung sollte nun + fehlerfrei funktionieren. + += Der IP-Router baut nun auch ausgehend Extended-AX.25 auf, wenn die zu + connectende Station im MHeard mit EAX.25 gekennzeichnet ist. + += EAX25: Werte von EAXMODE beim PORT-Befehl geaendert: + Mode 0 : nur AX.25 (unveraendert) + Mode 1 : AX.25 und EAX.25, Connects nach MHeard (unveraendert, default) + Mode 2 : AX.25 und EAX.25, ausgehende Connects zuerst immer in EAX.25, + erfolgt nach zwei SABME keine Antwort, dann Rueckfall auf AX.25 + Mode 3 : nur EAX.25 erlaubt (wie der alte Mode 2) + += Verbesserungsvorschlaege von DL1XAO eingepflegt + += In allen Files im Copyright die Jahreszahl angepasst diff --git a/history/179mh02.his b/history/179mh02.his new file mode 100755 index 0000000..252e677 --- /dev/null +++ b/history/179mh02.his @@ -0,0 +1,125 @@ += Linux: "Test"-Befehl konnte AX25IP und AX25IPX zum Absturz bringen. + Korrigiert. + ++ Linux: AX25IP hat nun einen automatischen Routenlerner, der bei eingehenden + Connects den Absender in die AX25IP-Routentabelle mit aufnimmt und + mit einem inaktivitaets-Timeout versieht. Laeuft dieser ab (1 Stunde), + so wird der gelernte Knoten wieder ausgetragen. Gelernte Knoten + werden bei "SP" nicht mit ausgegeben ! Das neue Feld "Timeout" der + AX25IP-Routenausgabe (Befehl "axipr") gibt die restliche Lebenszeit + des Knotens bis zur Austragung an. + + Einzuschalten in all.h, #define AX25IP_DYNLEARN. + + Wird mit AXIPR (nur neue Syntax !!!) ein Timeout von 0 eingestellt, + so werden gelernte Knoten NICHT vergessen und verbleiben in der Liste ! + Ihre IP wird aber weiterhin ueberprueft und geupdated wenn das Call + ploetzlich mit einer anderen IP gehoert wird (dyndns). Knoten mit einem + Timeout von 0 werden bei "SP" mit in die parms.tnb ausgegeben ! + += Linux: LOOPBACK-Interface schaltbar gemacht, defaultmaessig ist es nun + deaktiviert. (hat wohl sowieso keiner benutzt, oder ???) + + Wer es doch braucht, Einzuschalten in all.h, #define LOOPBACK + ++ Linux: Code an vielen Stellen aufgeraeumt, mit zusaetzlichen Kommentaren + versehen und genauere Fehlermeldungen im L1 eingebaut. + += Linux: Neuer Kommandoparser und Syntax fuer AXIPR, der Befehl orientiert + sich nun grob am Linux "route"-Kommando. + + ACHTUNG, es wird immer entweder NUR die neue ODER die alte Syntax + verstanden !!! => tnb's in der alten Syntax versteht der neue + Parser nicht und die AXIPRs fehlen dann ! + + Soll die alte Syntax (= der alte Parser) wieder verwendet werden, + dann #define AXIPROLDSYNTAX in all.h setzen ! Bei "SP" wird ebenfalls + in der neuen Syntax geschrieben falls nicht auf alte Syntax + zurueckdefine'd wurde. + + Nochmal: neue TNNs verstehen die AXIPR-Kommandos in der tnn179.tnb + von alten Versionen nicht mehr (und umgekehrt) !!! Einen + Konverter gibt es (noch) nicht. + + Nur Eintraege in der ax25ip.cfg werden von beiden Versionen + verstanden ! + + Die neue Syntax lautet wie folgt: + + axipr {add, +} {call, "default"} [ []] + axipr {delete, del, -} {call, "default"} + + axipr myudp [UDP-Port] + axipr {loglevel, log} [Loglevel] (NEU !!!, siehe ax25ip.cfg) + axipr timeout [seconds] (NEU !!!, siehe dyn. Routenlerner) + + Ein paar Beispiele: + + IP-Route hinzufuegen : axipr add dg9obu-1 1.2.3.4 + UDP-Route hinzufuegen : axipr add dg9obu-1 1.2.3.4 udp 12345 + Defaultroute (IP) : axipr + default 1.2.3.4 + Route loeschen : axipr - dg9obu-1 + Defaultroute loeschen : axipr del default + Loglevel aendern : axipr loglevel 3 + UDP-Port aendern : axipr myudp 12345 + Timeout aendern : axipr timeout 7200 + + Bei erfolgreicher Abarbeitung erfolgt bei den Kommandos keine erneute + Ausgabe der Liste und man erhaelt gleich wieder das Prompt. Nur im + Fehlerfall erfolgen Fehlerhinweise. Bei Verwendung der neuen Syntax + kann (eigentlich) auf die ax25ip.cfg verzichtet werden, alle + Einstellungen koennen nun dynamisch veraendert werden und sind ueber + die tnn179.tnb einlesbar. + + Weiterhin wurde bei der alten und neuen Syntax ein kleiner Fehler + bei der MyUDP-Port-Aenderung behoben. Der UDP-Port konnte nicht + geaendert werden, falls es nicht mindestens eine aktive UDP-Route gab. + ++ Anpassungen an GCC 3.4.0 + ++ Linux: Die CPU-Auslastung kann nicht aus /proc/loadavg ermittelt werden, da + dort etwas ganz anderes ausgesagt wird, naemlich die IO-Last. Die + echte CPU-Last wird nun intern selbst aus dem Verhaeltnis von + Uptime zu Idletime der letzten zehn Sekunden berechnet. Die Werte aus + /proc/loadavg werden zur Information weiterhin ausgegeben. + ++ Neues L1-Interface: 6PACK (vorerst nur unter Linux) + + 6PACK ist ein zum KISS-Tokenring aehnliches, jedoch von Kanalzugriff weiter + ausgereiftes Protkoll. Die gesamte Steuerung des TNC erfolgt durch die + Software, der TNC ist nur ein dummer Befehlsempfaenger. Genau wie beim + Tokenring koennen mehrere TNC in Reihe geschaltet werden. Im TNC ist ein + spezielles EPROM mit einer 6PACK-Firmware notwendig ! + + Konfiguration: in der tnn.ini: + + Als kisstype ist bei dem entsprechenden Device "12" anzugeben, danach fuer + jeden vorhandenen TNC eine "port"-Zeile (wie beim Tokenring). In der + tnn179.tnb muss bei diesen Ports nur "ON" eingetragen werden. Es sollten + immer genau so viele Ports wie TNC vorhanden sind zugeordnet werden ! + + Eine ausfuehrliche Beschreibung findet sich in der tnnini.all in os/linux/ini. + + Mit dem neuen Befehl "6pack" kann eine Statistik und die aktuelle Zuordnung + von TNC zu den Ports abgerufen werden, eine Veraenderung von Parametern ist + nicht moeglich. Die Behandlung von moeglichen Fehlern des Rings wird + komplett ohne Eingriffsmoeglichkeit durchgefuehrt. Falls ein TNC fehlerhaft + sein sollte, so ist dies an den Checksum- und Reset-Zaehlern zu erkennen. + + Achtung, dieser L1-Treiber befindet sich noch in der Erprobung, er sollte + nur nach ausgiebigen Tests produktiv eingesetzt werden ! Bitte etwaige + Fehler melden ! Ausserdem sind das Copyright und die Bestimmungen der aus + dem FlexNet-Paket stammenden 6PACK-Firmware fuer TNC2 zu bachten, + insbesondere was den Einsatz im CB-Funk betrifft ! + += Linux: Die Ausfuehrung von Shellkommandos mit "sh" aus der tnn179.tnb und + anderen von dort gestarteten tnb-Files war nicht moeglich. Korrigiert. + += AX25IP: Probleme beim Empfang behoben, TCP hat nun Vorrang vor UDP wenn beides + aktiv ist. Bei eingeschaltetem Logging wird das Log nicht mehr + mit jedem empfangenen Paket unnoetig vollgeschrieben. + += L3VC: Bei der Meldung an FlexNet-Nachbarn wurden Locals, deren Call nicht + gleich dem des Knotens ist, nicht gemeldet. (DAC922 Stefan) + +- Zielsystem "DOS16" entfernt und kleinere kosmetische Aenderungen (DG8BR Bernd) diff --git a/history/179mh03.his b/history/179mh03.his new file mode 100755 index 0000000..e0c625f --- /dev/null +++ b/history/179mh03.his @@ -0,0 +1,114 @@ +* "Mailbox" und "DX"-Kommando konnten fehlerhaft arbeiten, wenn keine Mailbox + oder kein DX-Cluster eingetragen wurde. Initialisierungen verschoben, wurden + offensichtlich ignoriert. (Compilerfehler ?) + +* Diverse uninitialisierte Variablen gefixt und zusaetzliche Sicherheits- + initialisierungen eingebaut. Aufraeumen des Speichers bei Programmende. + += Der L2-RX ignorierte die "QST" ARP-UI-Frames, korrigiert. + += Linux: 6PACK hatte RX-Probleme auf TNC2 mit original 6PACK-Firmware, auf dem + TNC3 tritt das Problem nicht auf (fehlerhafte/unvollstaendige 6PACK- + Implementation im TNC3). + + Weiterhin gibt es fuer den Sysop nun ein Kommando "6pack loglevel x", + wobei 0 <= x <= 4 gilt. Je groesser x, desto mehr Debugausgabe erfolgt + in eine Datei namens "6pack.log". Achtung, x = 4 ist sehr ausfuehrlich + und sollte nur benutzt werden, wenn ein Anlass besteht und auch genug + Plattenplatz vorhanden ist ! Es erfolgt keine Ausgabe der Meldungen auf + der Console bzw. im verbundenen Kanal, es wird nur in besagte Datei gelogt. + += Linux: AX25IP vereinheitlicht, so dass Aufgaben des L1-Treibers nicht wie bisher + an Stellen ausserhalb des Treibers erledigt werden. + += Linux: AX25IP: Korrektur eines Fehlers, der den Empfang bei IP-Links verhinderte. + += Linux: AX25IP: Mehr Frametypen fuehren beim dyn. Routenlerner nun zu einem + Eintrag. + += Linux: "ax25ip.cfg"-Konfigurationsdatei wurde bis zum Programmende offen + gehalten. Wird jetzt nach dem Einlesen wieder geschlossen. + += Linux: Vanessa nur deinitialisieren wenn auch eine Karte gefunden wurde, + Speicher nur unmappen wenn er auch gemapt war. + += Linux: Compilieren war ohne gesetzten "#define KERNELIF" nicht mehr moeglich. + += Linux: Lock-Files ordentlich abraeumen bei Fehlern waehrend des L1-Setups. + +* Folgende schaltbare Funktionen wurden aus all.h entfernt und befinden sich + nun fest im Code: + + + IPRTCACHE IP-Routencache + + REALROUTECOUNT Zaehlung der Routen zum Nachbar + +* INP-Modul aufgeraeumt, hier war sehr viel versionsspezifischer Code bzgl. + erster INP-Implementationen. Dieser Code wird nun NICHT mehr mit compiliert, + er ist nur noch auf Knoten notwendig die mit TNN-Nachbarn mit Versionen + kleiner als 1.76 linken ! Wer diese Codeteile benoetigt, muss das + "#define OLD_INP" in all.h aktivieren, sonst werden so alte Nachbarn nicht + mehr verstanden ! Besagter Code wird asap dauerhaft entfernt, dies ist nur + eine Uebergangsloesung !!! + ++ Linux: "sm02"-Patch integriert, fuer alle HDLC-Devices ("bc*"-Interfaces) + und SoundModem ("sm*") wird nun DCD und PTT vom Kernel abgefragt. + Einzuschalten mit "#define HDLC_DCDPTTSTAT" in all.h. + + Fuer den SCC-Treiber kann nun ebenfalls die PTT-Information vom + Kernel erhalten werden, einzuschalten mit "#define SCC_DCDPTTSTAT". + + Weiterhin kann nach einem kleinen Patch am Kernel auch der DCD- + Zustand der SCC-Devices abgefragt werden, hierzu ist zusaetzlich + der "#define OBU_SCC_DCD" zu aktivieren. Achtung, dies funktioniert + NUR mit veraendertem Kerneltreiber, mit "vanilla"-Kerneln bzw. deren + SCC-Treiber ist ein compilieren nicht mehr moeglich ! Naehere Infos + finden sich in "sccpatch.txt". + +* Kommandozeile fuer externe Programme konnte ueberlaufen. Behoben. (sm04) + +* Linux: Der Routenlerner muss die direkt gehoerte Station, also ggf. das + letzte Via, lernen und nicht unbedingt den eigentlichen Absender. + (sm04) + +* Linux: AXIPR wertete in der alten Syntax bei "R +" die angegeben IP-Adresse + nicht korrekt aus. + +* Linux: Interaktive Shell. Wird bei "sh" kein direkt auszufuehrender Befehl + angegeben, so erhaelt man eine interaktive Shell. Befehle wie z.B. + "sh ls -l" werden wie bisher direkt ausgefuehrt. Der Timeout fuer + nicht-interaktive Befehle betraegt weiterhin eine Minute, die + interaktive Shell hat hier fuenf Minuten mit Timeout-Warnung. + (Nur als Sysop, nicht fuer Benutzer verfuegbar) + ++ Bei UI-Frames wird der via-Pfad ausgewertet und der Weg zum naechsten Hop + bestimmt. Es gelten die folgenden Einschraenkungen: + + Falls das eigene Knotencall ... + + ... das naechste Via ist: Falls es noch weitere Via nach uns gibt UND der + naechste Hop per L2 erreichbar (also ein Local oder Flexnet-Nachbar) ist, + wird das Frame auf dem entsprechenden Port ausgegeben. Sind wir das letzte + Via in der Liste, dann wird geprueft, ob das Ziel ein Local oder ein lokaler + User ist und falls dem so ist, das Frame auf dem entsprechenden Port ausgegeben. + + ... nicht das naechste Via ist: Es wird geprueft, ob das gewuenschte Via + bekannt UND per L2 (Flexnet oder Local) erreichbar ist, und das Frame dann + auf dem entprechenden Port ausgegeben. Calls auf Userports werden hier nicht + als moegliche naechste Via-Ziele beruecksichtigt. Ebenfalls werden auf Ports + empfangene Frames, die nicht an uns gerichtet sind und wenn der Port keine + Interlinks hat, ignoriert. + + Grundsaetzlich findet keine Ausgabe von UI-Frames statt, wenn das naechste + notwendige Ziel, also das naechste Via oder der Zielknoten, nur per NETROM + erreichbar ist. Der via-Pfad wird bis auf das Aendern des H-Bit beim eigenen + Call nicht veraendert ! + + Eventuell soll spaeter mal ein Flexnet-aehnliches UI-Forwarding implementiert + werden, da ich aber komplett im NETROM-Land sitze und keine Moeglichkeit habe + Flexnet zu beobachten, bin ich auf Traces unter genauer Angabe der Situation + angewiesen. Wer so etwas oder sogar Dokumentation beisteuen kann, bitte zuschicken. + (dg9obu@nordlink.org oder dg9obu@db0uhi.#nds.deu.eu) + + Die schon im Code vorhandene Mailbaken-Funktion, die mit Hilfe des Knoten-Aliasses + eine gezielte Aussendung von UI-Frames auf bestimmten Ports ermoeglichte, ist + weiterhin unveraendert vorhanden. diff --git a/history/179mh04.his b/history/179mh04.his new file mode 100755 index 0000000..e295b93 --- /dev/null +++ b/history/179mh04.his @@ -0,0 +1,109 @@ +Aenderungen 179mh03 -> 179mh04: +------------------------------- + += INP meldet bei Aenderung der Knoten-IP oder Subnetzmaske dies allen + INP-faehigen Nachbarn. + += INP-Parser aufgeraeumt, die Auswertung von einem fehlerhaft empfangenen + Node fuehrt nun nicht mehr zum Abbruch der Auswertung des ganzen INP-Frames. + += Die mit #define OLD_INP bereits stillgelegten Codeteile wurden entfernt. + += Output-Programm modifiziert: Patch von DK2CRN eingebaut (zusaetzl. + Wartezeit fuer STROBE-Leitung) und zusaetzl. Pruefungen (DG9OBU). + += Ausgabe des SSID-Bereiches der Linkpartner beim "routes"-Befehl. + += AX.25 ARP-"QST"-Frames die noch erreichbare Ziele im VIA-Pfad haben, + reichen wir nun weiter, ist das naechste Ziel nicht erreichbar, + schmeissen wir sie weg. + + Frames die uns als letztes VIA haben nehmen wir an, weil der Vorgaenger + es auf Grund des Pfades zu uns geschickt hat und wir kein weiteres Ziel + dafuer haben. + +* Linux: make: Unterstuetzung von externen Linkerflags, make-Aufruf + beruecksichtigt nun die Variable "LDFLAGS_LIN" beim Linken. + + Um z.B. mit dem gcc statische, gestrippte Binaries zu erhalten nimmt man z.B.: + "make LDFLAGS_LIN=-static LDFLAGS_LIN+=-s" + + Die Variable wird auch an die makefiles in "contrib" durchgereicht. + +* Linux: Erkennung fuer MIPS-Systeme beim Compilieren (WRT54G, MeshCube): + + (aut. Erkennung oder "make MIPS=YES [...]" bei Crosscompilierung) + + "contrib/output" wird fuer MIPS-Systeme NICHT mehr uebersetzt. + Dies ist fuer den WRT54G oder MeshCube gedacht, diese beiden haben + keinen parallelen Printerport wie die i386-kompatiblen Systeme. + "make" gibt hier einen kurzen Hinweis aus dass nichts gebaut wurde. + + "Vanessa" wird ebenfalls fuer MIPS-Systeme NICHT mehr genutzt, aber + noch ein restl. Rumpf mit eincompiliert. Diese Hardware gibt es fuer + MIPS einfach nicht. + + Diese Variable wird ebenfalls an makefiles in "contrib" durchgereicht. + +* Linux: kleine Anpassung im Convers damit keine Meckermeldungen mehr + beim Compilieren mit dem GCC unter Linux ausgegeben werden + +* Linux: mit dem Befehl "setshell" kann eine abweichende Shell gesetzt werden. Beim + Start wird die Umgebungsvariable SHELL gelesen und eine dort eingestellte + Shell uebernommen. Ist diese Variable leer so erfolgt eine Warnung und der Shell- + Mechanismus ist nicht nutzbar. + + Wichtig fuer "busybox": die Shell sollte ein symbolischer Link sein damit + busybox weiss, was zu tun ist. Also nicht "setshell /bin/busybox" sondern + "setshell /bin/bash", wobei "/bin/bash" ein symbolischer Link auf "/bin/busybox" + sein muss. + + Beispiel: + "setshell" liefert eine kurze Hilfe + "setshell ?" fragt die aktuelle Einstellung ab + "setshell /bin/sh" setzt /bin/sh als zu verwendende Shell + + Das uebergebene Programm wird rudimentaer auf seine Eignung als ausfuehrbare + Datei untersucht (kein Socket, Verzeichnis etc., ausfuehrbar) + += L2-Connects mit Via-Pfad beruecksichtigen bei der Suche des naechsten Ziels + nun auch die MHeard-Liste wenn kein Ziel im L3 gefunden wurde. Der Via-Pfad + wird durchgereicht. + += Bei der verzoegerten Bestaetigung von Hop-to-Hop-Verbindungen konnte das UA-Frame + in seltenen Faellen mit falschen Flags gesendet werden. Die Flags des in diesem + Fall gesendeten UA-Frames sind nun fest verdrahtet (Response und Final -> "UA-"). + += Linux: Schalter AXIPROLDSYNTAX ausgebaut, die AXIPR-Parser koennen nun umgeschaltet + werden, nach dem Start ist der *ALTE* Parser aktiv, damit alte Konfigurationen + problemlos gelesen werden koennen. Das Umschalten erfolgt wie folgt: + + Alt -> Neu : "AXIPR P" + Neu -> Alt : "AXIPR OLD" oder "AXIPR O" + + Ist der neue Parser zum Zeitpunkt von "sp" aktiv, so schreibt er den Umschaltebefehl + fuer Alt -> Neu mit in die tnb-Datei. + + >>> Wer seine .tnb schon in neuer Syntax hat, der muss den Umschaltebefehl haendisch <<< + >>> nachtragen !!! <<< + + (... oder man aendere den Source auf die bevorzugte Variante: os/linux/ax25ip.h, Zeile 93) + += Linux: Der Shell-Befehl nutzt nun eine Bibliotheksfunktion, um eine Shell abzuforken. + Hierdurch sollten die "ERROR while reading ..."-Fehler nun beseitigt sein. + Ursache dafuer waren offenbar nicht eindeutige Prozessgruppenzugehoerigkeiten und + Probleme mit dem gemeinsam verwendeten Descriptor. + + >>> Die Benutzung der interaktiven Shell ist in tnb-Dateien nun blockiert !!! <<< + + Damit steht TNN hoechtens eine Minute (Standard-Timeout) an einem Shell-Befehl. + + In den Batchdateien sind nur noch Shellaufrufe in der Art "sh ls -l" moeglich, ein + "sh" hat keine Wirkung bzw. wird eine entsprechende Fehlermeldung in eine ggf. + offene Logdatei geschrieben. + + Zum Linken von TNN ist nun zusaetzlich die "libutil"-Bibliothek erforderlich ! + += Linux: 6PACK ruft nun auch bei offenem Ring weiter nach seinen TNC, dies wurde bisher + nur gemacht falls ueberhaupt irgendetwas empfangen wurde. Kleine Korrekturen + beim Schliessen des ser. Ports. diff --git a/history/179mh05.his b/history/179mh05.his new file mode 100755 index 0000000..0a88e14 --- /dev/null +++ b/history/179mh05.his @@ -0,0 +1,108 @@ +Aenderungen 179mh04 -> 179mh05: +------------------------------- + +Diese Version besteht hauptsaechlich aus Bugfixes, sowie einigen Funktionen, +die aus der CB-Variante uebernommen wurden. Im Einzelnen sind geaendert: + +* Fix fuer Absturz bei Connect mit Via-Angabe. + +* Alle Makros, die in CTEXT.TXT funktionieren, koennen nun auch in + QUIT.TXT verwendet werden. + += Linux: bei der nicht-interaktiven Shell konnte bei Kommandos, die keine + Rueckgabe erzeugten, die "ERROR while read()ing"-Meldung noch + erscheinen, obwohl kein Fehler vorlag. Korrigiert. + + Weiterhin konnte die Ausgabe grosser Datenmengen + (sh cat /var/log/messages) dazu fuehren, dass eine Sicherheitsfunktion + ansprach und den ueberfuellten Link abwarf. Jetzt wird die Verbindung + nur noch mit maximal 100 ausstehenden Frames mit Daten aus der Shell + gefuellt. + += MHeard/L3MHeard zeigt nun bei Aenderung der Listengroesse nicht mehr die + Liste an, sondern gibt nur noch eine Meldung ueber die neue Groesse aus. + +* Nickname-Unterstuetzung fuer den Convers. Es ist nun die Angabe eines Namens + moeglich, der zusaetzlich vor dem Rufzeichen angezeigt wird. Die Eingabe wird + an andere Convers-Hosts weitergeleitet, sofern sie die Nickname-Faehigkeit in + ihren Feature-Flags angezeigt haben. Die Umsetzung erfolgte in Anlehnung an + die Implementierung im tpp-convers 1.14, jedoch erfolgt die Anzeige des Nicknames + nicht so haeufig wie im Original. + + Hinzugekommen sind die beiden Kommandos: + + /NICKname oder "@" setzt den Namen, der @ loescht ihn + /NONickname loescht den Namen (wie "/nick @") + + Angepasste Hilfedateien finden sich im Verzeichnis "doc" ! + + Einzuschalten mit dem #define CONVNICK in all.h. Ist es aktiviert, werden + andere Feature-Flags gesendet und die Version "3.14c" bzw. "pp-3.14t" gemeldet. + +* Onlinehilfe angepasst und geupdated + += 6PACK: Ein weiterer Wachhund sorgt nun dafuer, dass der intern gespeicherte + PTT-Status des TNC rueckgesetzt wird, falls Infopakete des TNC verloren gehen. + += Datum im Copyright angepasst + +* Linux: Das Interface zum Kernel heisst nun "tnn" statt "tun0" und wurde fuer + die 2.6er-Kernelreihe angepasst. Weiterhin ist nun die Angabe der + Subnetzbits fuer die Kernel-Seite des Interfaces moeglich. + (IP-Adresse/Subnetz-Bits). + + Achtung, bei einigen Kerneln klappt die Aktivierung des Interfaces + nicht, obwohl kein Fehler gemeldet wird. In diesem Fall muss in der + Datei "kif_up.tnb" der Befehl "sh ifconfig up" ein- + getragen werden. Der Interfacename ist "tnn". + ++ Empfangene und gesendete FRMR-Pakete werden im Trace dekodiert. + +* Connectbewertung komplett ueberarbeitet, dem User sind nun mehr Uebersteuerungs- + moeglichkeiten vorhanden. Die Angabe eines abweichenden Ports ist nun nur noch + als letzter Parameter moeglich ! (c db0abc ... {Portnummer, Portname}) + +* Linux: bei AX25IP ist der dynamische Routenlerner nun fest eingebaut, der Schalter + AX25IP_DYNLEARN in all.h ist somit entfallen. + +* Linux: AX25IP arbeitet nun primaer mit Hostnamen statt mit IP-Adressen. Wird ein Host + angegeben der momentan nicht aufgeloest werden kann, so wird er mit der IP- + Adresse 0.0.0.0 in die Routentabelle aufgenommen und bei jedem gesendeten Frame + zu diesem Host ein Adressaufloesungsversuch unternommen. Somit koennen ueber + dynamisches IP erreichbare Hosts ohne Kenntnis der aktuellen IP eingetragen werden. + + Wird statt eines Hostnamens eine IP-Adresse eingetragen, so wird diese direkt + uebernommen, der Hostname wird auf die IP-Adresse gesetzt. + + Dynamische Routen werden nun bei "sp" ebenfalls in die parms.tnb geschrieben, + jedoch werden sie auskommentiert und sind somit nicht aktiv. Durch einen manuellen + Eingriff koennen diese Eintrage auf einfache Weise permanent gemacht werden. + + Die Routentabelle wird in einem konfigurierbaren Intervall durchsucht + und alle Hostnamen in ihre aktuellen IP-Adressen aufgeloest. Sofern geaenderte IP- + Adressen nicht schon durch den Routenlerner aktualisiert werden, passiert dies nun. + Hinzugekommen ist der Befehl "LOOKUP " beim AXIPR-Kommando (nur neue + Syntax !!!), eine Einstellung von 0 deaktiviert die Ausfuehrung, voreingestellt + sind 180 Sekunden. Achtung, steht kein erreichbarer Nameserver zur Verfuegung, + kann der Knoten eventuell kurz einfrieren, da die Systemfunktionen hier + blockieren. + +* Linux: das uebermittelte Datum beim AutoBIN-Transfer war um einen Monat daneben. + +* Linux: bei gleichzeitiger Benutzung von AX25IP IP- und UDP-Verbindungen, konnte + eine Sendung mit einer falschen Portnummer erfolgen (DH6BB) + +* Die automatische Berechnung der Port-Parameter (Persistenz, L2-Retry, L2-Timer, ...) + kann uebersteuert werden. Werte, die weiterhin automatisch berechnet werden, werden + bei "po *" mit einem kleinen "a"-Suffix versehen, von Hand uebersteuerte Werte erscheinen + ohne Suffix. Soll ein nicht mehr automatisch berechneter Port-Parameter wieder in die + automatische Berechnung aufgenommen werden, so ist als Wert "a" anzugeben ("po 1 pers=a"). + Standardmaessig werden alle Port-Parameter automatisch berechnet. + + Die EXPERTPARAMETER muesen in all.h aktiviert sein ! (ist nun Standard) + +* Neues Makro %f zum Einlesen einer Textdatei. Der Dateiname muss direkt hinter dem %f stehen, + nach dem Dateinamen ist ein Leerzeichen einzufuegen, welches spaeter nicht mit ausgegeben + wird. (DH6BB) + + Bsp im Ctext: "Aktuelle Temperatur %f/usr/local/wx/wx.txt Grad Celsius" diff --git a/history/179mh06.his b/history/179mh06.his new file mode 100755 index 0000000..9cd94ce --- /dev/null +++ b/history/179mh06.his @@ -0,0 +1,20 @@ +Aenderungen 179mh05 -> 179mh06: +------------------------------- + +* Linux: der Routenlerner das ax25ip hatte ein Problem mit der Default-Route, was das + Lernen von neuen Verbindungen blockieren konnte. + +* Linux: Konsolen- und Socketbehandlung modifiziert: + Wenn TNN im Hintergrund gestartet wird, fuehrt eine geschlossene Konsole oder + ein geschlossener Socket beim Schliessen des TTY nun nicht mehr dazu, dass + 100% CPU gezogen werden. + + Einmal als geschlossen bzw. fehlerhaft erkannte TTY werden nicht neu verbunden, + abgebrochene Sockets werden fuer eine neue Verbindung wiederhergestellt. + +* Linux: neuer Kommandozeilenschalter "-v" fuer ausfuehrlichere Startmeldungen. + (nur bei Problemen interessant, nicht fuer den Regelbetrieb) + +* Linux: kleinere Aufraeumarbeiten und Sicherheitspruefungen von Systemaufrufen hinzugefuegt. + +* Linux/MIPS: PACSAT und einige x86-spezifische Sachen werden nicht mehr mit compiliert diff --git a/history/179pre1.his b/history/179pre1.his new file mode 100755 index 0000000..44d143b --- /dev/null +++ b/history/179pre1.his @@ -0,0 +1,9 @@ += MH zeigt bei gehoerten Stationen die EAX.25 verwenden dies hinter dem + Rufzeichen an + += kleine Aenderungen von Bernd DG8BR an l3vc.c. + += AX25IP-Routen konnten doppelt eingetragen werden, jetzt werden Routen + fuer ein Call das schon in der Liste steht nicht mehr angenommen, + der Eintrag muss zuerst geloescht werden. Es erfolgt eine Meckermeldung. + \ No newline at end of file diff --git a/history/179pre2.his b/history/179pre2.his new file mode 100755 index 0000000..a7efb6e --- /dev/null +++ b/history/179pre2.his @@ -0,0 +1,11 @@ += EAX.25: Keine Auswertung des EAX-Flags im Frame bei eingehenden Connects + mehr, die Umschaltung erfolgt nun nur noch bei Empfang von SABME. + += EAX.25: Neues Monitorformat bei I-Frames + += Fixes von DL1XAO an MHeard, Port und L7 eingearbeitet + += Externe Programme dem Paket hinzugefuegt, Copyrights aktualisiert + += Aenderungen am externen Programm pfhadd wegen Compilermeldung ueber + unklare Schleife diff --git a/history/179pre3.his b/history/179pre3.his new file mode 100755 index 0000000..f263e7f --- /dev/null +++ b/history/179pre3.his @@ -0,0 +1,17 @@ += EAX.25: Interne Aenderungen, Einsparung vieler lokaler Variablen. TNN verhaelt + sich an einigen Stellen nun geringfuegig anders als das EAX25 des + Linuxkernels, eine Zusammenarbeit ist trotzdem problemlos moeglich. + Die jetzige Implementation haelt sich strikt an die Spezifikation. + + Das maximal moegliche Maxframe wurde auf 32 begrenzt, standardmaessig + wird nun mit einem Maxframe von 16 gearbeitet. + += Linux: Behandlung von DG1KJD's AX.25-Kernelvariante geaendert, soll dieser + Kernel verwendet werden, dann ist dies mit "kisstype 11" in der + tnn.ini bei dem entsprechenden Port anzugeben. Die automatische + Erkennung ENTFAELLT hiermit ersatzlos da sie eine nicht behebbare + Schwaeche bei der Erkennung des Kerneltyps hatte, sie war darauf + angewiesen dass zuerst ein Frame empfangen werden musste bevor auf + dem KJD-Stack korrekt gesendet werden konnte. Die Portparameter fuer + KJD-Ports muessen weiterhin mit den entsprechenden Zusatztools + gesetzt werden, TNN kann dies mangels Testmoeglichkeit noch nicht. diff --git a/history/179pre4.his b/history/179pre4.his new file mode 100755 index 0000000..6cab3c3 --- /dev/null +++ b/history/179pre4.his @@ -0,0 +1,19 @@ += Statistik des IP-Kernelinterfaces wurde beim CLEAR-Kommando nicht mit + geloescht. Korrigiert. + += Weitere Anpassungen wegen KJD-Kernel + += Im Linuxteil testweise alle Zaehlvariablen in Schleifen von i++ auf ++i + umgestellt da Praefixoperation keine temporaere Variable benoetigen. + Weiterhin alle Zaehlvariablen ohne weitere Bedeutung auf "register" + umgestellt. + ++ Aenderungen von Bernd DG8BR am FlexNet-Modul: + l3vc.c + - Digisystem (X)NET hinzugefgt. + l7showl3.c + - Erkennung von XNET in Funktion "putrou" erweitert. + - Unbekannte Digiprogramme wurden nicht erkannt. Wurde nicht richtig + - beendet. + + \ No newline at end of file diff --git a/history/179pre5.his b/history/179pre5.his new file mode 100755 index 0000000..7e5b8d4 --- /dev/null +++ b/history/179pre5.his @@ -0,0 +1,36 @@ +* Zusaetzliche Makros fuer Prompt: + '%l' Anzahl aktiver L2-Links + '%p' Portnummer + '%P' Pseudo-Name des Ports + '%u' Anzahl der User auf dem aktuellen Port + '%%' % + + Zur Erinnerung: diese und die anderen Prompt-Makros funktionieren auch + in CTEXT.TXT und CTEXT. !!! + +* Linux: AX25IP umgekrempelt, es ist nun ein paralleler Betrieb von UDP und IP + moeglich. Ebenfalls kann die UDP-Portnummer, auf der TNN hoert, nun waehrend + des laufenden Betriebs geaendert werden. + + ACHTUNG !!! Die entsprechenden Ports sind netzwerkseitig nur offen, wenn + es auch AXIPR-Routen gibt !!! So lange keine Route oder eine Defaultroute + eingetragen wurde, empfaengt TNN deshalb auch nix !!! Dies gilt fuer IP und + UDP jeweils getrennt, ohne IP-Routen kein IP-Empfang, ohne UDP-Routen kein + UDP-Empfang !!! Die Ports oeffnen und schliessen automatisch je nach + Vorhandensein von Routen. Ohne eingetragene Routen sind sie sowieso wertlos, + da TNN Sendeframes wegschmeisst, wenn es keine IP-Adresse ermitteln kann. + Fuer Empfangsversuche ist also z.B. eine Defaultroute zu 127.0.0.1 im + zu beobachtenden Mode notwendig. + + Die standardmaessig geschlossenen Ports sollten auch gegen Angriffe aus + dem Internet schuetzen (Flooding etc.). + +* Linux: Fehler im Kernel-AX.25 behoben, es war kein RX/TX mehr moeglich, + weitere Anpassungen wegen KJD-Kernel + +* Der "Routes"-Befehl zeigt nun an, wie viele Routen wirklich auf einen + jeweiligen Nachbarn zeigen. + + Die Zahl unter "Dst" gibt wie bisher an, wie viele Ziele von diesem + Nachbarn bekannt sind, unter "Rou" steht nun zusaetzlich, fuer wieviele + Ziele dieser Nachbar derzeit der beste Weg ist. diff --git a/history/179pre6.his b/history/179pre6.his new file mode 100755 index 0000000..f5b9b13 --- /dev/null +++ b/history/179pre6.his @@ -0,0 +1,9 @@ +* Diese Version wurde nie veroeffentlicht, sie enthielt nur Veraenderungen, + um unter AX25IP mehrere Ports zu ermoeglichen. Dies wird benoetigt, um + auf Knoten mit Internetlinks mehrere Verbindungen in Mode N oder N- zu + ermoeglichen. Um der Verlinkung via Internet keinen weiteren Vorschub + zu leisten, wurde die Ergebnisse nicht in den Code uebernommen. + + Funktionieren tut das oben beschriebene dennoch in der nicht veroeffent- + lichten pre6. Teilweise Anpassungen sind noch notwendig, werden aber + nicht weiter verfolgt. diff --git a/history/179pre7.his b/history/179pre7.his new file mode 100755 index 0000000..16544b4 --- /dev/null +++ b/history/179pre7.his @@ -0,0 +1,8 @@ += einige History-Files nachtraeglich geupdated + += Linux: Race-Condition bei Verwendung des Hostmode-Sockets behoben. Es + konnte vorkommen, dass TNN sich nicht starten liess, wenn der + Socket verwendet werden sollte. Starts mit Konsole gingen in diesem + Fall jedoch problemlos. + += Linux: kernelif.c: einige Newlines in Ausgaben in Returns geaendert diff --git a/history/179pre8.his b/history/179pre8.his new file mode 100755 index 0000000..365b0c4 --- /dev/null +++ b/history/179pre8.his @@ -0,0 +1,17 @@ += Probleme bei den neuen Makros behoben + += In l3tab.c::l3_find_route() wurde beim Aufbau des VIA-Feldes bei L2-Connects + eine nicht initialisierte Variable zum Vergleich herangezogen. Dies konnte + dazu fuehren, dass das VIA-Feld nicht korrekt aufgebaut wurde, weil + eventuell ein falscher Linkpartnertyp festgestellt wurde. + += Funktion l7utils.c::getdig() bereinigt, Rueckgabetyp war nicht mit erwartetem + Typ an anderen Stellen im Code identisch und konnte zu falschen Ergebnissen + fuehren. + += Linux: Problem mit dem Kernelinterface fuer KJD-Kernel behoben, es konnten + keine Interfaces geoeffnet werden. + += In all.h die schaltbaren Optionen neu gruppiert, selten benutzte Optionen + weiter unten eingetragen, ausserdem sind die L4-Erweiterungen nun standard- + maessig eingeschaltet. \ No newline at end of file diff --git a/history/axipr.his b/history/axipr.his new file mode 100755 index 0000000..305099f --- /dev/null +++ b/history/axipr.his @@ -0,0 +1,67 @@ + + +!!!! ACHTUNG +!!!! Dies ist die ALTE Syntax des AXIPR-Kommandos ! +!!!! ( siehe 179mh02.his fuer neue Syntax !!! ) + +----------------------------------------------------------------------------- + +Die Datei ax25ip.cfg wird (erstmal) noch benoetigt fuer die Socket- +Initialisierung und Einstellung des Loglevel. + +Syntax: +======= + +AXIPR + +Zeigt die derzeit gueltigen AXIP-Routen. Diese werden auch angezeigt, wenn +erfolgreich ein Eintrag zugefuegt oder geloescht wurde. + +AXIPR R + [mode [udp-Port]] + +Es wird eine Route eingetragen zum Rufzeichen ueber den Host . +Fuer muss ein gueltiges Rufzeichen verwendet werden. Fuer kann +sowohl eine IP-Adresse als auch ein Hostname (max. 32 Zeichen) angegeben +werden. Optional kann der fuer mode "IP" oder "UDP" gewaehlt werden. Fuer +mode UDP kann zusaetzlich der udp-Port des Zieles angegeben werden. + +AXIPR R - + +Die Route zu wird aus der Liste entfernt. + +AXIPR D + [mode [udp-Port]] + +Es wird eine Default-Route eingetragen zum Host . Fuer kann +sowohl eine IP-Adresse als auch ein Hostname (max. 32 Zeichen) angegeben +werden. Optional kann der fuer mode "IP" oder "UDP" gewaehlt werden. Fuer +mode UDP kann zusaetzlich der udp-Port des Zieles angegeben werden. + +AXIPR D - + +Die Default-Route wird geloescht. + + +Wichtig! Man kann (vorerst) nur entweder IP-Routen verwenden, wenn man selbst +einen IP-Socket verwendet, oder es muessen UDP-Routen verwendet werden, wenn +man selbst einen UDP-Socket verwendet. + + +Beispiele: +========== + +AXIPR R + DB0ABC db0abc.ampr.org + Traegt ein IP-Route zu DB0ABC mit der IP-Adresse von db0abc.ampr.org ein + +AXIPR D + 44.55.66.77 UDP + Setzt die Defaultroute auf die IP 44.55.66.77 mit UDP-Protokoll auf dem + UDP-Defaultport (10093) + +AXIPR R + DB0ABC-10 db0abc-u.ampr.org UDP 34567 + Traegt eine UDP-Route auf Port 34567 bei DB0ABC-10 mit der IP-Adresse + von db0abc-u.ampr.org ein + +AXIPR R - DB0ABC + Loescht den Routeneintrag fuer DB0ABC + +AXIPR D - + Loescht die Default-Route diff --git a/history/eax25.his b/history/eax25.his new file mode 100755 index 0000000..f3eb59c --- /dev/null +++ b/history/eax25.his @@ -0,0 +1,33 @@ +Hinweise zum Extended-AX.25: +============================ + +- Die Verwendung/Akzeptanz von EAX.25 laesst sich ueber den Wert von EAXMODE + beim PORT-Befehl steuern: + + Mode 0 : nur AX.25 erlaubt, EAX.25 wird abgelehnt + Mode 1 : AX.25 und EAX.25, Connects nach MHeard (default) + Mode 2 : AX.25 und EAX.25, ausgehende Connects zuerst immer in EAX.25, + erfolgt nach zwei SABME keine Antwort, dann Rueckfall auf AX.25 + Mode 3 : nur EAX.25 erlaubt, AX.25 wird abgelehnt + +- BEIDE Seiten muessen EAX.25 unterstuetzen, Unterstuetzung ist derzeit + nur im Linux-Kernel, WAMPES, NETCHL und TNN vorhanden. Gegenstellen, die + nur AX.25 koennen, ignorieren die EAX.25-Frames entweder komplett oder + senden auf das SABME ein DM. Sollte eine AX.25-Station faelschlicherweise + einen EAX.25-Connect annehmen, dann kommt es frueher oder spaeter zum FRMR. + +- Auf TNCs mit Hostmode AX.25-Firmware (TF 2.7b, TNC3 Turbofirmware etc.) + oder PC/Flexnet sehen EAX.25-Verbindungen im Monitor entweder komisch aus + (PID laeuft durch), oder werden gar nicht angezeigt ! + +- TNN's EAX.25 verhaelt sich passiv, Verbindungen werden nur mit EAX.25 + aufgebaut, wenn die Zielstation damit in der MH-Liste vermerkt ist, + oder der EAXMODE-Parameter fuer den Port auf 2 oder 3 steht. + +- Interlink-Ports (egal welcher Linkmode) verhalten sich wie normale Userports. + Man kann auch zu Flexnet-Linkpartnern EAX.25 einstellen, jedoch verstehen + diese es nicht und senden gleich ein DM. Hier also NIE EAXMODE 3 benutzen ! + +- Nach Aenderung des EAXMODEs eines Port muss ein bestehender Link geKILLt + werden, damit die neue Einstellung beruecksichtigt wird. Aenderungen am + EAXMAXFrame werden sofort wirksam. diff --git a/history/flex178mh06.his b/history/flex178mh06.his new file mode 100755 index 0000000..58eeeaa --- /dev/null +++ b/history/flex178mh06.his @@ -0,0 +1,27 @@ +Aenderungen in der Flexroutine. +- l3vc.c +Es konnte passieren, das eine Tokenanforderung einfach an die Destinations +angehaengt wurde. Dort wurde es dann nicht gelesen. +Die Tokenabgabe wird nun in einem eigenen Frame geschickt. +- mh08 +Die Änderung wieder rückgängig gemacht. Nach Studium des DigiWare-Code +kann man es so machen. +Eigentlich sollten wir es auch erkennen. + +Diverse Kleinigkeiten geändert + +Wir schicken nun auch eine Maxtime zum Nachbarn. Aber nur innerhalb der +Grenzen 1-3000. Wird in Parameter 02 eine 0 oder grosser 300000 einge- +tragen, dann senden wir maxtime = 3000. + +Einige Notifymeldungen wegen Tokenbehandlung eingebaut. +Diese Notifymeldungen können, durch setzen der entsprechenden Zahl +in include/all.h (MAX_TRACE_LEVEL 9), unterdrückt werden. + + +-os/go32/go32.c +Beim Watchdog wird nun der letze Befehl und die Zeit in die debug.txt +geschrieben. +Hilft eventuell bei der Fehlersuche. + + diff --git a/history/kernelif.his b/history/kernelif.his new file mode 100755 index 0000000..527ee80 --- /dev/null +++ b/history/kernelif.his @@ -0,0 +1,274 @@ +Das IP-Kernelinterface von TNN +============================== + +Das Kernelinterface ermoeglicht die direkte Kopplung des TNN-internen +IP-Routers an den IP-Router des Linuxkernels. Hierdurch koennen (bei reiner +IP-Kopplung an den Kernel) zusaetzliche Programme wie die AX.25-Utilities +eingespart werden. Ein Shell-Login in Linux ist ueber diese Funktion nicht +moeglich, hierfuer werden weiterhin die AX.25-Utilities benoetigt. Wird das +Interface aktiviert, so werden im Kernel-IP-Router und bei TNN automatisch +entsprechende Routeneintraege erzeugt, TNN erscheint dann wie eine +Netzwerkkarte im Kernel. + + +Voraussetzungen +=============== + +Das Kernelinterface wurde erfolgreich mit dem 2.2.x- und 2.4.x-Kerneltree +getestet, Kernel der 2.0.x-Serie sind bisher nicht getestet worden, +hier funktioniert unter Umstaenden auch das Tool fuer die 2.2.x-Kernel. + +In jedem Fall muss die Netzwerkunterstuetzung fuer TCP/IP im Kernel vorhanden +sein. Dies ist aber eigentlich immer der Fall. Neuere Kernel bringen den +Treiber meist schon mit oder er liegt als Modul bei. Vor dem Start von +TNN sollte er ggf. mit "modprobe tun" geladen werden. + +Da auf grundlegende Netzwerkfunktionen zugegriffen wird, sollte TNN mit +Root-Berechtigung laufen !!! Ansonsten funktionieren eventuell einige +Zugriffe nicht. + +Das fuer Kernel 2.2.x benoetigte Paket "tun-1.1.tar.gz" ist bei DB0UHI-4 +im Fileserver unter "/filesurf/linux/tun" oder im Internet unter +"http://vtun.sourceforge.net/tun/tun-1.1.tar.gz" zu finden. + + +Allgemeine Installation: +======================== + +Die Interfacefunktionalitaet ist per Voreinstellung deaktiviert. Um sie zu +aktivieren entfernt man die Kommentarzeichen um den Eintrag "#define KERNELIF" +in der Includedatei "all.h" im "include"-Unterverzeichnis. Danach ist TNN +mit "make" neu zu compilieren. + +Installation unter Kernel 2.4.x und 2.6.x : +=========================================== + +Viele aktuelle Distributionen bringen TUN schon mit ! Meistens reicht +ein "modprobe tun". + +Die Installation ist hier sehr einfach. Bei der Kernelkonfiguration mit +"make menuconfig", "make config" oder aehnlichen Tools muss bei dem Punkt +"Network device support" der Unterpunkt "Universal TUN/TAP device driver" +aktiviert werden. Dieser Treiber kann entweder fest in den Kernel oder als +Modul gebaut werden, wie man es macht ist Geschmackssache. Nachdem der Kernel +gebaut und installiert ist, muss noch mit den Befehlen "mkdir /dev/net" und +"mknod /dev/net/tun c 10 200" ein Device angelegt werden. Dies erfordert Root- +Berechtigung. Damit sind wir fertig. + +!!! Wichtig: bitte das Kernel-interne TUN benutzen, nicht das tun-Paket ! +!!! Trotzdem aber hiervon das Infofile mit den Installationsinfos +!!! lesen (schadet nicht). + + +Installation unter Kernel 2.2.x: +================================ + +Zuerst muss das Paket "tun-1.1.tar.gz" gemaess der Anleitung in dem Paket +installiert werden und die Moduleintraege gemacht werden. Es muessen danach +unter dem Verzeichnis "/dev" Eintraege mit den Namen "tun0" bis "tun9" +vorhanden sein. + +Vor dem Start von TNN muss das tun-Modul entweder per "modprobe tun " oder +durch den Autoloader geladen werden (kontrollieren !!!). Falls Warnmeldungen +nach dem Hinzufuegen der char-major-Eintraege in /etc/modules.conf kommen +("modules.conf ist more recent...."), dann nochmal "depmod -a" ausfuehren. + +Hiermit ist die Installation bereits abgeschlossen, der einzige Unterschied zu +der Kernel-2.4.x-Installation besteht nur darin, dass das erzeugte Interface +nicht "tnn" sonder "tun*" heisst, wobei * eine (beliebige) Zahl ist. + + +Steuerung des Interfaces: +========================= + +Um das Interface zu steuern wurde der neue SYSOP(!)-Befehl "KERNELIF" oder kurz +"KERN" eingefuehrt. Die komplette Steuerung erfolgt ueber diesen Befehl und +seine Unterfunktionen. Ausserdem wurde der IPR-Befehl fuer die Routeneintraege +im TNN-Router erweitert um Routen auf das Kernelinterface legen zu koennen. + +Das Interface initialisiert sich beim Start nicht automatisch ! Dies ist +beabsichtigt um durch eine eventuell fehlerhafte Erkennung des Interface- +Stils des Kernels keine Probleme zu verursachen. + + +Die Interfacefunktionen: +======================== + +Hier sollen zuerst die Funktionen im Einzelnen vorgestellt werden, ein +Ablaufbeispiel findet sich im Anhang. + +Das Interface unterstuetzt die Unterfunktionen "INIT", "SETKIP", "DOWN", "UP", +"CLEAR" und "STATUS", alle sind nur fuer den Sysop verfuegbar. + +KERN INIT: Initialisiert das Interface, es wird geprueft ob der Kernel die + benoetigten Funktionen bereitstellt. Das Interface initialisiert + sich NICHT von selbst, dies muss explizit mit INIT erfolgen !!! + Es ist sonst nicht nutzbar. An dieser Stelle erfolgt ein Warnhinweis + falls zu diesem Zeitpunkt mit "IPA" noch keine Node-IP festgelegt + wurde. Die Interfacestatistik wird geloescht. Ist das Initerface + bereits initialisiert laesst dich dieser Befehl nur auf ein im + DOWN-Zustand befindliches Interface anwenden. + + +KERN STATUS: Zeigt den momentanen Status und die Statistik des Interfaces an. + + +KERN CLEAR: Loescht die Statistik der empfangenen und gesendeten Bytes. + Dies passiert auch beim "CLEAR" fuer die Gesamtstatistik. + + +KERN SETKIP: Setzt die IP des Linuxkernels. Hier kann entweder eine IP- + Adresse oder ein Hostname angegeben werden, letzterer wird + entsprechend aufgeloest *wenn* ein Nameserver verfuegbar ist. + Die Angabe einer IP-Nummer ist deshalb zu bevorzugen ! + + Dieser Parameter *muss* unbedingt passieren, bevor das Interface + mit "KERN UP" aktiviert wird, ist dies nicht geschehen kann das + Interface nicht benutzt werden ! Die Node-IP von TNN wird wie + ueblich mit dem "IPA"-Kommando gesetzt, dies muss ebenfalls vorher + passiert sein. + + Bsp: "KERN SETKIP 44.130.13.110" oder + "KERN SETKIP db0uhi.ampr.org" + + Bei "KERN STATUS" wird grundsaetzlich nur die IP-Nummer angzeigt, + nicht aber ein eventuell angegebener Hostname. + + +KERN UP: Aktiviert ein *vollstaendig* konfiguriertes Interface, ist die + Konfiguration noch unvollstaendig wird entsprechend auf die + fehlenden Einstellungen hingewiesen. + + Im Kernel wird ein Interface mit dem Namen "tnn" erzeugt + und eine Route mit der Node-IP fuer TNN im Kernel-IP-Router + eingetragen. Dies passiert alles automatisch auf der Basis der + gesetzten IP-Adressen. Im TNN IP-Router wird ebenfalls ein passender + Routeneintrag erzeugt. + + !!! Bei Kernel-2.2.x-Style heisst das Interface "tun*" !!! + + Das Interface laesst sich nur in den UP-Zustand schalten wenn + folgende Einstellungen erfolgt sind: + IPA , KERN INIT, KERN SETKIP . + + +KERN DOWN: Deaktiviert ein aktives Interface zum Kernel. Das eingetragene + Interface und die automatisch im Kernel und TNN eingetragenen + IP-Routen werden geloescht, sonstige Routen im TNN-Router die + auf das Interface zeigen bleiben eingetragen, sie funktionieren + aber natuerlich nicht mehr! Zusaetzliche Routen im Linux IP-Router + die auf das "tnn"-Interface zeigen werden geloescht !!! + + !!! Bei Kernel-2.2.x-Style heisst das Interface "tun*" !!! + + Daten, die auf ein im DOWN-Zustand befindliches Interface durch + noch bestehende Routeneintraege geroutet werden, werden ohne + weitere Nachricht geloescht !!! + + +allgemeines: Einige Kommandos sind nur nach vorheriger, erfolgreicher + Ausfuehrung anderer Kommandos moeglich oder haengen vom + derzeitigen Zustand des Interfaces ab. Wenn eine Aktion + ausgefuehrt werden soll die derzeit aufgrund des Zustandes + des Interfaces nicht moeglich ist, so erhaelt man eine + entsprechende Fehlermeldung. + + Die Konfiguration eines Interfaces kann nur geaendert werden + wenn es im DOWN-Zustand ist. Ausnahme: IPA-Aenderungen, aber + diese werden bei aktivem Interface (noch) nicht an den Kernel + durchgereicht. Das Resultat ist denkbar einfach: das Interface + geht dann nicht mehr. Man muss das Interface einmal DOWN und + dann wieder UP schalten. Aber Vorsicht: zusaetzliche IP-Routen + im Linux-Kernel gehen verloren und muessen neu gesetzt werden. + + +Ablaufbeispiel: +=============== + +Nachfolgend ein Beispiel um den TNN-Knoten DB0UHI (44.130.13.100) mit dem +Linux-Kernel auf der Maschine zu verbinden. Dem Kernel wird dabei die +IP-Adresse 44.130.13.102 (db0uhi-u.ampr.org) zugewiesen. TNN-Befehle sind +gross geschrieben, Linux-Shellbefehle klein. Bei den SH-Kommandos ist die +Schreibweise zu beachten, die Linux-Shellbefehle muessen klein geschrieben +werden, die TNN-Befehle koennen wahlweise gross oder klein geschrieben werden. + + + - Zuerst die Node-IP des Knotens setzen: "IPA 44.130.13.100" + - Danach kann das Interface initialisiert werden: "KERN INIT" + - Jetzt muss die IP-Adresse festgelegt werden, die der Kernel + bekommen soll. Dies geschieht mit: "KERN SETKIP 44.130.13.102" + bzw. "KERN SETKIP db0uhi-u.ampr.org" + - Jetzt sollte die Konfiguration ueberprueft werden: "KERN STATUS". + Dies kann selbstverstaendlich auch schon vorher einmal gemacht + werden. + - Wenn alles ok ist kann das Interface aktiviert werden: "KERN UP" + + Jetzt kann man noch diverse Checks durchfuehren: + + - Auf TNN-Seite sollte nun ein Routeneintrag in die IP-Routingtabelle + erfolgt sein und auf den Port "KERNEL" zeigen. Pruefbar mit: "IPR" + + - Auf Kernel-Seite sollte ein Interface mit dem Namen "tnn" existieren, + dies kann unter TNN mit dem Befehl "SH ifconfig" ueberprueft werden. + Die IP-Routen kann man sich mit "SH route" anzeigen lassen, hier sollte + eine Route erscheinen, die auf das tnn-Device zeigt. + + - Jetzt kann man einen einfachen Test machen: "PING 44.130.13.102". + Hiermit PING't TNN den Kernel an. Wenn dies funktioniert ist das + Interface betriebsbereit, was es transportiert haengt jetzt nur noch + von den Routingeintraegen in TNN und im Kernel ab. Um Routen hinzuzufuegen + oder zu loeschen sind die Befehle "IPR" (TNN) und "route" (Kernel) zu + benutzen. + +Das Interface sollte generell nur einmal am Anfang, z.B. aus der Startdatei +"tnn178.tnb" heraus, aktiviert werden. Aenderungen an einem aktiven Interface +sind nicht moeglich, es muss immer mit "KERN DOWN" deaktiviert werden bevor +z.B. neue IP-Adressen gesetzt werden. Die meisten Funktionen des Interface +verweigern dann die Befehlsausfuehrung mit entsprechenden Meldungen. + + +Aenderungen am IPR-Befehl: +========================== + +Der IPR-Befehl zum Ein- und Austragen von Routen im TNN IP-Router wurde bei +dem Port-Abschnitt um den virtuellen Port "KERNEL" erweitert. Routen, die diesen +Port erhalten, zeigen auf das Kernel-Interface. + +GANZ WICHTIG : sollte ein weiterer Port im System existieren dessen Name +"Kernel" (Gross-/Kleinschreibung egal) lautet, kann es nicht funktionieren ! +Der Portname des realen Ports ist dann zu aendern !!! + +Alles weitere zu IPR ist gleich geblieben findet sich in der zugehoerigen Hilfe. + + +Sonstiges: +========== + +- Die Interfacestatistik kann auch mit "STAT K" abgerufen werden. +- Zu den moeglichen Portnamen fuer echte Ports siehe Hinweis bei den Aenderungen + am "IPR"-Befehl. +- Ist das Kernel-Interface-Feature eincompiliert erscheint auch ein Hinweis + beim "VER +"-Versions-Befehl. + +****************************************************************************** + +Anbindung an Linux Kernel-AX.25: +================================ + +Einstellung ueber tnn.ini: + +- bei "device" den Interfacenamen (siehe ifconfig) angeben +- "lockfile" bleibt frei +- "kisstype" auf den Wert "10" stellen, bei KJD-Kernel "11" verwenden +- bei "port" den gewuenschten Port angeben + +Bsp: +device ax0 +kisstype 10 +port 1 + +Danach den Port ueber den PORT-Befehl mit ON aktivieren. Mit OFF laesst sich +ein Kernelport wieder abschalten, sollte waehrend des Betriebs eines Kernel- +ports ein Fehler auftreten so wird dieser Port eventuell deaktiviert, er +laesst sich ggf. wieder mit ON einschalten. + diff --git a/history/sccpatch.txt b/history/sccpatch.txt new file mode 100755 index 0000000..1cf0694 --- /dev/null +++ b/history/sccpatch.txt @@ -0,0 +1,38 @@ +Anleitung zum Patchen des SCC-Treibers V 3.0 von DL1BKE +------------------------------------------------------- + +Der folgende Patch sollte mit fast allen Kerneln funktionieren, die +den SCC-Treiber in der Version "3.0.dl1bke" enthalten. Beiliegender DIFF +wurde auf einem 2.4.28-Kernel erzeugt, er sollte auch auf 2.2.x- und 2.6.x- +Kerneln mit etwas Handarbeit einzupflegen sein. + +Das neue scc.h muss anschliessend noch in das Verzeichnis "/usr/include/linux" +kopiert werden, sonst motzt TNN beim compilieren weil er noch die alte +Version sieht ! + +--- snip --- + +--- linux/drivers/net/hamradio/scc.c.orig 2002-11-29 00:53:13.000000000 +0100 ++++ linux/drivers/net/hamradio/scc.c 2004-12-26 18:47:02.000000000 +0100 +@@ -1400,6 +1400,7 @@ + case PARAM_WAIT: return CAST(scc->kiss.waittime); + case PARAM_MAXDEFER: return CAST(scc->kiss.maxdefer); + case PARAM_TX: return CAST(scc->kiss.tx_inhibit); ++ case PARAM_DCD: return CAST(scc->dcd); + default: return NO_SUCH_PARAM; + } + +--- linux/include/linux/scc.h.orig 2004-12-23 21:40:18.000000000 +0100 ++++ linux/include/linux/scc.h 2004-12-26 18:44:48.000000000 +0100 +@@ -50,6 +50,7 @@ + PARAM_WAIT, + PARAM_MAXDEFER, + PARAM_TX, ++ PARAM_DCD, + PARAM_HWEVENT = 31, + PARAM_RETURN = 255 /* reset kiss mode */ + }; + +--- snap --- + +25.12.2004 DG9OBU diff --git a/history/tnn178.his b/history/tnn178.his new file mode 100755 index 0000000..5df28a6 --- /dev/null +++ b/history/tnn178.his @@ -0,0 +1,2 @@ += Speicher-Leck bei Pacsat behoben += einige ungenutzte Funktionen entsorgt diff --git a/history/tnn178a.his b/history/tnn178a.his new file mode 100755 index 0000000..1020ce9 --- /dev/null +++ b/history/tnn178a.his @@ -0,0 +1,4 @@ += KISS / RKISS Fehler bei GO32-Version beseitigt += kleine Aenderung im makefile, damit nicht mit jedem "make" alles neu + uebersetzt wird += ipDefaultTTL -> 32 diff --git a/include/all.h b/include/all.h new file mode 100644 index 0000000..60d333d --- /dev/null +++ b/include/all.h @@ -0,0 +1,473 @@ +/************************************************************************/ +/* */ +/* ***** ***** */ +/* ***** ***** */ +/* ***** ***** */ +/* ***** ***** */ +/* *************** *************** */ +/* ***************** ***************** */ +/* *************** *************** */ +/* ***** ***** TheNetNode */ +/* ***** ***** Portable */ +/* ***** ***** Network */ +/* ***** ***** Software */ +/* */ +/* File include/all.h (maintained by: you) */ +/* */ +/* This file is part of "TheNetNode" - Software Package */ +/* */ +/* Copyright (C) 1998 - 2008 NORD> 16 +#error "L2PNUM >16 is not tested!" +#endif + +#define DAMA_CH L2PNUM /* Anzahl der Dama-Kanaele */ + +#ifdef MC68302 +# define MAXCOMS 3 /* Anzahl der seriellen Ports */ +#else +# define MAXCOMS 4 +#endif +#define MAXKISS MAXCOMS /* Anzahl der KISSLINKS */ + +#define MAXSUSPEND 50 /* Maximalanzahl Sperrungen */ +#define MAXCVSHOST 10 /* Maximaleintraege ConversHosts */ +#define MAXSTAT 16 /* Anzahl der Statistik-Eintraege */ +#define MAXNMBSTN 16 /* Quantisierung Stationen/Port */ + +#define MINBUFF 256 + +#define NUL ((char) 0x00) /* ASCII-Zeichen */ +#define BELL 0x07 +#define BS 0x08 +#define TAB 0x09 +#define LF 0x0A +#define CR 0x0D +#define XON 0x11 +#define XOFF 0x13 +#define ESC 0x1B +#define DEL 0x7F + +#define MONI 0x01 /* Monitor: I-Frames */ +#define MONU 0x02 /* UI-Frames */ +#define MONS 0x04 /* S-Frames */ +#define MONC 0x08 /* Anzeige, auch wenn connected */ +#define MONF 0x10 /* Anzeige des Info-Feldes */ +#define MONT 0x20 /* Sende-/Empfangszeit */ +#define MONL 0x40 /* Info-Laengen-Anzeige */ + +#define SECONDS_PER_DAY 86400L /* the number of seconds in one day */ +#define SECONDS_PER_HOUR 3600L /* " " " " " " hour */ +#define SECONDS_PER_MIN 60L /* " " " " " " min. */ + +#ifdef CRASHDEBUG +#define TRACE(x) wowarich2 = "x" +#else +#define TRACE(x) +#endif + +/************************************************************************/ +/* Einiges fuer TNC3 */ +/************************************************************************/ +#ifdef MC68302 +#define __BOOLEAN +#include + +#undef stdout /* stdout Simulation */ +extern FILE *stdout; + +#define MAXPATH 20 + +#define xchdir(a); + +#endif + +/************************************************************************/ +/* hier noch einige Sachen fuer PP-conversd */ +/************************************************************************/ + +#define MAXCHANNEL 32767 /* hoechster conversd Kanal */ + +#if defined(__TURBOC__) || defined(__STDC__) || defined(__WIN32__) +#define __ARGS(x) x +#ifndef __DOTS +#define __DOTS ,... +#endif +#else +#define __ARGS(x) () +#define const +#ifndef __DOTS +#define __DOTS +#endif +#endif + +#if !defined (min) +#define min(a,b) ((a) >= (b) ? (b) : (a)) +#define max(a,b) ((a) >= (b) ? (a) : (b)) +#endif + +/*#define uchar(x) ((x) & 0xff) wers braucht, solls anmachen, DL1XAO*/ +#define uchar(x) (x) + +#ifdef CONVNICK +#define REV "$Revision: 3.14c $" +#else + #define REV "$Revision: 3.12c $" +#endif + +#define INIT 0 /* Befehle fuer personalmanager und convers_config */ +#define SAVE 1 +#define SET 2 +#define GET 3 + +/************************************************************************/ +/* Dateitrennungszeichen usw fuer das Filesystem festlegen */ +/************************************************************************/ +#define SEPARATORS "\\/" /* die DOS- und die Unix-Konvention */ + + /* File-Flags */ +#define FF_LWR 1 /* Dateinamen sind immer klein */ +#define FF_TXT 2 /* Unterscheidung TEXT/BIN bei open */ + +#ifdef __LINUX__ +#define FILE_SEP '/' /* Linux und falcOS haben / */ +#define FILE_FLAGS FF_LWR +#define NO_DISKDRIVE /* keine Laufwerksbuchstaben */ +/* die folgenden Pfade koennen auch ueber einen Compilerswitch im */ +/* makefile definiert werden */ +#ifndef TEXTPATH +#define TEXTPATH "/usr/local/tnn/" +#endif +#ifndef TEXTCMDPATH +#define TEXTCMDPATH TEXTPATH "textcmd/" +#endif +#ifndef USEREXEPATH +#define USEREXEPATH TEXTPATH "userexe/" +#endif +#ifndef SYSEXEPATH +#define SYSEXEPATH TEXTPATH "sysexe/" +#endif +#ifndef MSGPATH +#define MSGPATH TEXTPATH "msg/" +#endif +#ifdef SPEECH +#ifndef SPEECHPATH +#define SPEECHPATH TEXTPATH "speech/" +#endif +#endif +#ifdef PACSAT +#ifndef PACSATPATH +#define PACSATPATH TEXTPATH "pacsat/" +#endif +#endif +#ifdef AXIPR_HTML +#ifndef HTMLPATH +#define HTMLPATH "/usr/local/httpd/htdocs/" +#endif +#endif +#define STRIPCHR CR +#define ENDCHR LF +#define PORTABLE +#else /* nicht __LINUX__ */ +#define FILE_SEP '\\' /* DOS und ST haben das alte \ */ +#define STRIPCHR LF +#define ENDCHR CR +#ifndef MC68302 +#define FILE_FLAGS FF_TXT +#ifndef TEXTPATH +#define TEXTPATH "TNN\\" +#endif +#ifndef TEXTCMDPATH +#define TEXTCMDPATH TEXTPATH "TEXTCMD\\" +#endif +#ifndef USEREXEPATH +#define USEREXEPATH TEXTPATH "USEREXE\\" +#endif +#ifndef SYSEXEPATH +#define SYSEXEPATH TEXTPATH "SYSEXE\\" +#endif +#ifdef PACSAT +#ifndef PACSATPATH +#define PACSATPATH TEXTPATH "PACSAT\\" +#endif +#endif +#ifdef AXIPR_HTML +#ifndef HTMLPATH +#define HTMLPATH TEXTPATH +#endif +#endif +#ifndef MSGPATH +#define MSGPATH TEXTPATH "MSG\\" +#endif +#ifdef SPEECH +#ifndef SPEECHPATH +#define SPEECHPATH TEXTPATH "SPEECH\\" +#endif +#endif +#else /* MC68302 */ +#define FILE_FLAGS FF_LWR +#define TEXTPATH "r:\\" +#define TEXTCMDPATH TEXTPATH +#define USEREXEPATH TEXTPATH +#define SYSEXEPATH TEXTPATH +#define MSGPATH TEXTPATH +#endif +#endif + +#define GRAPH_LINES 15 +#define GRAPH_INTERVAL 10 /* Alle 10 s einen neuen Wert speichern */ +#define GRAPH_STD_ELEMENTS 60 /* 60 Elemente je Stunde */ +#define GRAPH_DAY_ELEMENTS 48 /* 24 * 2 halbe Stunden je Tag */ +#define GRAPH_WEK_ELEMENTS 56 /* 8 * 7 Tagesabschnitte je Woche */ + +#ifdef BUFFER_DEBUG +#define ALLOC_LEHEAD 1 +#define ALLOC_MBHEAD 2 +#define ALLOC_USRBLK1 3 +#define ALLOC_USRBLK2 4 +#define ALLOC_L2LINK 5 +#define ALLOC_MB 6 +#define ALLOC_MONBUF 7 +#define ALLOC_CQBUF 8 +#define ALLOC_IP_ROUTE 9 +#define ALLOC_ARP_TAB 10 +#define ALLOC_MHEARD 11 +#define ALLOC_PACSATBLK 12 +#ifdef USERPROFIL +#define ALLOC_USEPROF 13 +#endif /* USEPROFIL. */ +#ifdef TCP_STACK +#define ALLOC_TCPSTACK 14 +#endif /* TCP_STACK. */ +#ifdef L1TCPIP +#define ALLOC_L1TCPIP 15 +#endif /* L1TCPIP */ +#ifdef L1HTTPD +#define ALLOC_L1HTTPD_RX 16 +#define ALLOC_L1HTTPD_TX 17 +#endif /* L1HTTPD */ +#ifdef L1IPCONV +#define ALLOC_L1IPCONV 18 +#endif /* L1IPCONV */ +#ifdef L1IRC +#define ALLOC_L1IRC 19 +#endif /* L1IRC */ +#define ALLOC_INPOPT 20 +#define ALLOC_NO_OWNER 21 +#define ALLOC_MAXELEMENTE 22 +#else +#define ALLOC_LEHEAD +#define ALLOC_MBHEAD +#define ALLOC_USRBLK1 +#define ALLOC_USRBLK2 +#define ALLOC_L2LINK +#define ALLOC_MB +#define ALLOC_MONBUF +#define ALLOC_CQBUF +#define ALLOC_IP_ROUTE +#define ALLOC_ARP_TAB +#define ALLOC_MHEARD +#define ALLOC_PACSATBLK +#ifdef USERPROFIL +#define ALLOC_USEPROF +#endif /* USERPROFIL. */ +#ifdef TCP_STACK +#define ALLOC_TCPSTACK +#endif /* TCP_STACK. */ +#ifdef L1TCPIP +#define ALLOC_L1TCPIP +#endif /* L1TCPIP */ +#ifdef L1HTTPD +#define ALLOC_L1HTTPD_RX +#define ALLOC_L1HTTPD_TX +#endif /* L1HTTPD */ +#ifdef L1IPCONV +#define ALLOC_L1IPCONV +#endif /* L1IPCONV */ +#ifdef L1IRC +#define ALLOC_L1IRC +#endif /* L1IRC */ +#define ALLOC_INPOPT +#define ALLOC_NO_OWNER +#define ALLOC_MAXELEMENTE +#endif + +/* End of include/all.h */ + diff --git a/include/allmodif.h b/include/allmodif.h new file mode 100755 index 0000000..3e6b998 --- /dev/null +++ b/include/allmodif.h @@ -0,0 +1,728 @@ +/************************************************************************/ +/* */ +/* Modifizierungen von DAA531 Oliver Kern */ +/* DAC922 Stefan */ +/* */ +/************************************************************************/ + + +/************************************************************************/ +/* */ +/* AFU-Callcheck deaktiviert */ +/* */ +/************************************************************************/ +#define CALLCHECK + + +#if defined(__WIN32__) || defined(__LINUX__) +/************************************************************************/ +/* */ +/* Port oeffnen / schliessen. */ +/* */ +/************************************************************************/ +#define ATTACH + + +/************************************************************************/ +/* */ +/* AX25IP-Modul. */ +/* */ +/* Dynamische DNS Verwalten. */ +/* Parameter Loglevel per Console einstellbar. */ +/* Keine Frame verarbeiten beim einlesen der tnn179.tnb. */ +/* Zusaetzliche Meldungen bei ein - und austragen von AXIPR-Routen. */ +/* */ +/************************************************************************/ +#define AXIPR_UDP +#ifdef AXIPR_UDP + +/************************************************************************/ +/* */ +/* AXIPR-Liste in HTML-Format schreiben. */ +/* Datei: rstat.html, rstat.css. */ +/* Verzeichnis wird in der TNN179.PAS angepasst. */ +/* */ +/************************************************************************/ +#define AXIPR_HTML + +#endif /* AXIPR_UDP */ +#endif /* WIN32/LINUX */ + + +/************************************************************************/ +/* */ +/* Allgemeiner Direktiv fuer alle Modifizierungen und Fixe. */ +/* */ +/************************************************************************/ +#define MODIFIGLOBAL +#ifdef MODIFIGLOBAL + +#define FUNCFIX /* Fix in einzelnen funktionen. */ +#ifdef FUNCFIX + +#define CONVTOPIC_FIX /* Fix in funktion send_topic. */ + +#define CONVNICK_FIX /* Fix in funktion nickname_command. */ + +#define MHEAX_LINKFIX /* Variable eax_link wurde nicht immer */ + /* gesetzt, behoben. */ + +#define MHRXTXBYTESFIX /* Nur "Info-Bytes" werden gezaehlt, der */ + /* AX25-Header wird abgezogen. */ + +#define L4NOBAKE /* Steht der Routing-TYP noch nicht fest, */ + /* senden wir zum Nachbarn noch keine Bake */ + /* irgendeiner Art. */ + +#define SEND_ASYNC_RESFIX /* Null-Zeichen setzen - sicher ist sicher. */ + +#define FLEX_TX_RTT_FIX /* Kein Doppelte Laufzeitmessung senden. */ + +#define LOCAL_ROUTEFIX /* hiermit setzen wir die LOCAL-Time runter */ + /* von 400ms auf 10ms. Leider ist es vorge- */ + /* kommen, das eine LOCAL-ROUTE im Netz bes-*/ + /* ser geroutet wurde, als die von unseren */ + /* Node. */ + +#define FLEXTIMEFIX /* Mess-Timeout erhoeht. */ + +#define FLEX_ROUTINGFIX /* Flex-GATE deaktivieren. */ + +#define AUTOBINAERFIX /* Fehler in "Load" behoben. (WPP) */ + /* Paxcon funktioniert nun auch ab mh02. */ + +#define SAVEPARAMFIX /* Parameter in die TNN179.TNB speichern. */ + +#define CONFPATHFIX /* Der angegebene TEXTPATH in TNN179.PAS */ + /* auch CONFPATH zuweisen !!! Wichtig, wenn */ + /* Verzeichnisse wie MSG und interne */ + /* Prozesse auf CONFPATH zugreifen. */ + +#define MSGPATHFIX /* Der MSG Path wird in der funktion main.c */ + /* definiert von confpath. Nun ist es aber */ + /* moeglich, das der confpath, wo TNN.EXE */ + /* gestartet wurde, nicht stimmt, weil der */ + /* TEXTPATH in der TNN179.PAS ganz anders */ + /* definiert wurde. Als muessen wir das */ + /* korrigieren. */ + +#define PARMS_PORTMOD /* den PORT Befehl mit dem PARMS Befehl */ + /* tauschen. Mit dem Befehl P werden die */ + /* Portparamter angezeigt. */ + /* (Mehrfach gewuenscht!) */ + +/*************************************************************************/ +/* */ +/* UI-Frames von einem Port auf einen anderen Port durchreichen. */ +/* */ +/* Aenderungen: 1. Digipeater-Call -> TNN-Call */ +/* 2. Auch auf RX-Port wo die Bake gehoert wurde senden. */ +/* */ +/*************************************************************************/ +#define UIDIGIMOD + +/*************************************************************************/ +/* */ +/* Gibt es keinen Weg zum Ziel (n call), Fehlermeldung ausgeben. */ +/* */ +/*************************************************************************/ +#define NONODESFIX + + +/*************************************************************************/ +/* */ +/* Flexnet-Ziele -> nur noch in der Destinations-Liste angezeigen. */ +/* Nodes-Ziele -> nur noch in der Nodes-Liste angezeigen. */ +/* */ +/*************************************************************************/ +#define SHOW_DESTNODES + + +/*************************************************************************/ +/* */ +/* Nach erneuten SABM, Zeitmessung starten. */ +/* */ +/*************************************************************************/ +#define RTTSTART_MOD + + +/*************************************************************************/ +/* */ +/* Standard-Baken Text deaktiviert. */ +/* TheNetNode (Win32) (CB), 1.79cb52 (TEST:CB1GRH) */ +/* */ +/* Kann mit //BAKEFIX wieder aktiviert werden. */ +/* */ +/*************************************************************************/ +#define BAKEFIX + + +/*************************************************************************/ +/* */ +/* UI-Frame mit POLL-Flag. . */ +/* */ +/*************************************************************************/ +#define UIPOLLFIX + +#endif /* FUNCFIX */ + + +/*************************************************************************/ +/* */ +/* Aktiviert das Auto-Routing. */ +/* */ +/*************************************************************************/ +#define AUTOROUTING +#ifdef AUTOROUTING +#define AUTO_ROUTE 0 /* AutoRoute, keine Speicherung in TNN179.TNB */ +#define FIXED_ROUTE 1 /* FesteRoute, wird gespeichert in TNN179.TNB */ +#endif /* AUTOROUTING */ + + +/*************************************************************************/ +/* */ +/* Alias in kleinbuchstaben umwandeln. Wird ein Alias in GROSSBUCHSTABEN */ +/* gespeichert, wird dieser Linkeintrag beim naechsten start NICHT */ +/* eingelesen !!!. */ +/* */ +/*************************************************************************/ +#define ALIASSAVEMOD + + +/*************************************************************************/ +/* */ +/* BEACON/BAKE . */ +/* */ +/* Beacon-Bake (Metric) erweitert auf 0..3. */ +/* */ +/* Ausgabe (BE 0 60 3 IDNET): */ +/* DNO531 to STATUS UI^ pid F0 - 19.09.03 23:44:37 */ +/* Links: 31, Convers: 25, Dest/Nodes: 267, Runtime: 31d,15h */ +/* DNO530:39 CB0DLN:44 */ +/* */ +/* Beschreibung der Bake im einzelnen: */ +/* Links: 32 -> aktuelle L2-Links im Knoten. */ +/* Convers: 25 -> aktuelle anzahl user im Convers. */ +/* Dest/Nodes: 267 -> aktuelle anzahl der Destination und Nodes. */ +/* Runtime: 31d.15 -> Laufzeit der Knotensoftware. */ +/* */ +/*************************************************************************/ +#define BEACON_STATUS + + +/*************************************************************************/ +/* */ +/* Modifizierung am Modul Convers */ +/* */ +/*************************************************************************/ +#define CONVMOD +#ifdef CONVMOD + +#define CONV_CHECK_USER /* Pruefung auf Doppel-Login. */ + +#define CONV_TOPIC /* Topic-Call sichern. */ + +#define CONVERS_HOSTNAME /* Convers-Hostname aendern. Es stehen 15 */ + /* Zeichen zur Verfuegung. */ + +#define CONVERS_CTEXT /* In der Datei conversd.xhf unter @@CTEXT */ + /* kann man einen zusaetzlichen CTEXT zu- */ + /* zusammen basteln. */ + +#define CONVERS_LINKS /* Aenderungen an den Convers-Links. */ + +#define CONVERS_SYSINFO /* System-Ausgabe (wunsch DAD213) */ + +#define CONVERS_NO_NAME_OK /* Deaktivierung funktion name_ok. */ + +#define CONVERS_USERANZAHL /* Gesamtanzahl der Convers-User im Kanal. */ + + +#endif /* CONVMOD */ + +/*************************************************************************/ +/* */ +/* Modifizierung am Modul CONNECT */ +/* */ +/*************************************************************************/ +#define CONNECTMOD +#ifdef CONNECTMOD +/*************************************************************************/ +/* */ +/* User hat Port angegeben, dann gehen wir ueber L2. */ +/* */ +/*************************************************************************/ +#define CONNECTMOD_GOPORT + +/*************************************************************************/ +/* */ +/* Status-Meldungen "*** connected to" bzw. "*** reconnected to" */ +/* eingebaut. */ +/* */ +/*************************************************************************/ +#define CONNECTMOD_MSG + +/*************************************************************************/ +/* */ +/* Auch wenn der Nachbar nicht erreichbar, wird ein L2-Link aufgebaut. */ +/* */ +/*************************************************************************/ +#define CONNECTMOD_NODE_AVAI + +/*************************************************************************/ +/* */ +/* Einstiegsknoten setzen. */ +/* Das Rufzeichen was weitergeleitet wird, ist der Node, wo sich der */ +/* User eingeloggt hat. Ist eine weitere Anpassung an Flexnet und */ +/* Baycom-Systemen. */ +/* */ +/*************************************************************************/ +#define CONNECTMOD_SET_NODE + +#endif /* CONNECTMOD */ + + +/*************************************************************************/ +/* */ +/* Connect-Zeit in Flexnet-Stil ausgeben. */ +/* 1 CB0RIE CB1GLA IXF 0 0 0 13 136 138 96 13h,21m - */ +/* ======= */ +/*************************************************************************/ +#define CONNECTTIME + + +/*************************************************************************/ +/* */ +/* System sauber runterfahren. */ +/* Erweiterte Fehlersuche . */ +/* (Hat mir schon einige Arbeit erspart.) */ +/* */ +/*************************************************************************/ +#define DEBUG_MODUS + + +/*************************************************************************/ +/* */ +/* Editor erweitert. (ist noch nicht eingebaut) */ +/* */ +/*************************************************************************/ +#define EDITOR + + +/*************************************************************************/ +/* */ +/* Damit setzt man einmalig das Consolen-Mycall. */ +/* Speicherung erfolgt in der TNN179.TNB. Bei jeden neustart wird das */ +/* neue Consolen-Mycall gesetzt. */ +/* */ +/*************************************************************************/ +#define HOSTMYCALL + + +/*************************************************************************/ +/* */ +/* Modifizierung am Modul IPROUTE */ +/* */ +/* IP-Adresse 0.0.0.0 unter ARP sperren. */ +/* Default IP-Adresse 0.0.0.0 unter IPR setzen. */ +/* Ist eine default-route gesetzt, werden alle NICHT definierten */ +/* IP-Adressen an diese default-route geschicht. */ +/* */ +/* default-route unter IPR eintragen: */ +/* 0.0.0.0 + NETROM 192.168.100.10 */ +/* Wichtig ist die Gateway Adresse !!! */ +/* */ +/*************************************************************************/ +#define IPROUTEMOD + + +/*************************************************************************/ +/* */ +/* Ist der L4-Timeout abgelaufen, wird die Verbindung getrennt. */ +/* Vor der Trennung schicken wir den User eine Meldung. */ +/* */ +/*************************************************************************/ +#define L4TIMEOUTAUSGABE + + +/*************************************************************************/ +/* */ +/* L4-User killen (ccpkill kann nur L2). */ +/* */ +/*************************************************************************/ +#define L4KILL + + +/*************************************************************************/ +/* */ +/* Modifizierung am Modul (L)INKS */ +/* */ +/*************************************************************************/ +#define LINKSMOD +#ifdef LINKSMOD +/*************************************************************************/ +/* */ +/* Syntax Link ein/austragen fuer Sysop ausgeben. */ +/* */ +/*************************************************************************/ +#define LINKSMODSYNTAXFIX + +/*************************************************************************/ +/* */ +/* Stations-Beschreibung.unter Links-Liste. */ +/* */ +/*************************************************************************/ +#define LINKSMODINFO + +/*************************************************************************/ +/* */ +/* Zusaetzliche Meldungen bei ein/austragen von Links. */ +/* */ +/*************************************************************************/ +#define LINKSMOD_MSG + +/*************************************************************************/ +/* */ +/* Wenn kein Routing-TYP angegeben, dann gibt es eine Fehlermeldung. */ +/* Der Routing-TYP muss korrekt gesetzt werden !!! */ +/* */ +/*************************************************************************/ +#define LINKSMODROUTINGTYP + +/*************************************************************************/ +/* */ +/* Routing-TYP LOCAL ohne Messung, ohne Weiterleitung */ +/* und ohne Raute '#' im Alias. */ +/* */ +/* Routing-Typ "L-" */ +/* */ +/* Routing-TYP LOCAL ohne Messung, ohne Weiterleitung und versteckt. */ +/* Die Route ist nur fuer den Sysop sichtbar. */ +/* */ +/* Routing-Typ "L#" */ +/* */ +/*************************************************************************/ +/*#define LINKSMOD_LOCALMOD */ + +#endif /* LINKSMOD */ + + +/*************************************************************************/ +/* */ +/* Jeder Link-Nachbar mit Routing-Protokoll bekommt keinen CTEXT von uns.*/ +/* */ +/*************************************************************************/ +/*#define NOCTEXT */ + + +/*************************************************************************/ +/* */ +/* Modifizierung am Modul MAKROS */ +/* */ +/*************************************************************************/ +#define MAKROS +#ifdef MAKROS +/*************************************************************************/ +/* */ +/* Echte Useranzahl ausgeben. */ +/* Dafuer Modifiziere ich das Makro "%u", da ich das eh fuer unnutze */ +/* halte. Wer es im orignal zustand haben will, deaktiviert einfach */ +/* //#define MAKRO_USER */ +/* */ +/*************************************************************************/ +#define MAKRO_USER + +/*************************************************************************/ +/* */ +/* Makros in TXT-Datei (info.txt/map.txt) im Verzeichnis TEXTCMD */ +/* einsetzbar. */ +/* */ +/*************************************************************************/ +#define MAKRO_FILE + +/*************************************************************************/ +/* */ +/* Makro %v, Loginstring (TNN V1.79 (Win32). */ +/* Code von DAC922 Stefan. */ +/* */ +/*************************************************************************/ +#define MAKRO_NOLOGINSTR + +#endif /* MAKROS */ + + +/*************************************************************************/ +/* */ +/* Modifizierung am Modul (MH)EARD */ +/* */ +/* Modifizierung der MH-Liste (Flexnet-Stil) */ +/* Einzelne Port Listen. */ +/* MH-Listenlaenge einstellbar. */ +/* Verschiedene MH-Listen Formate. */ +/* */ +/*************************************************************************/ +#define MH_LISTE + + +/*************************************************************************/ +/* */ +/* Modifizierung am Modul (R)ORTPARAMETER */ +/* */ +/*************************************************************************/ +#define PORTPARAMETER +#ifdef PORTPARAMETER +/*************************************************************************/ +/* */ +/* Manuelle Portparameter. */ +/* */ +/* Paketlaenge, Persistance, Slottime, IRTT(Frack), T2, T3, Retry. */ +/* */ +/*************************************************************************/ +#define PORT_MANUELL + +/*************************************************************************/ +/* */ +/* IPOLL-Frame (von TheFirmware uebernommen) */ +/* */ +/* Manuelle Portparamter: */ +/* Paketlaenge: PO 0 I=128 */ +/* (Ab welcher groesser soll IPOLL-Frame zuschlagen.) */ +/* */ +/* Retry PO 0 IR=3 */ +/* (Wieviel mal das Frame Wiederholt werden soll). */ +/* */ +/*************************************************************************/ +#define IPOLL_FRAME + +/*************************************************************************/ +/* */ +/* Ist die L2_CONNECT_TIME abgelaufen, duerfen wir den Linkpartner Rufen.*/ +/* Nach abgelaufener L2_CONNECT_RETRY wird die L2_CONNECT_TIME wieder */ +/* hochgesetzt. Damit erreichen wir immer eine gewisse Pause beim */ +/* LINKAUFBAU, wenn unsere Nachbar-Station grade mal nicht online ist. */ +/* */ +/*************************************************************************/ +#define PORT_L2_CONNECT_TIME + +/*************************************************************************/ +/* */ +/* Wie viel mal soll nach dem Linkpartner gerufen werden bis zur */ +/* naechsten Pause. */ +/* */ +/*************************************************************************/ +#define PORT_L2_CONNECT_RETRY + +/*************************************************************************/ +/* */ +/* einzelne Ports sperren. Mode Parameter "l" (kleines "L") */ +/* Beispiel: PO 0 mode=1200l */ +/* Es duerfen nur LINK-Partner in der LINKS-LISTE Connecten, andere */ +/* bekommen Stationen bekommen eine kleine Meldung "INTERLINK" bzw. */ +/* man kann die Meldung selber in einer Datei festlegen (LOCK.TXT). */ +/* */ +/*************************************************************************/ +#define PORT_SUSPEND + +#endif /* PORTPARAMETER */ + + +/*************************************************************************/ +/* */ +/* Verhindert das gleichzeitige senden auf mehreren Port's. */ +/* Mode-Parameter "s". (po 0 mode=1200s) */ +/* */ +/* Noch nicht vollstaendig. */ +/* */ +/*************************************************************************/ +#define PORT_SYNRONATION + + +/*************************************************************************/ +/* */ +/* Proxyfunktion (noch zu optimieren). */ +/* */ +/*************************************************************************/ +#define PROXYFUNC + + +/*************************************************************************/ +/* */ +/* Modifizierung am Modul (R)OUTES */ +/* */ +/*************************************************************************/ +#define ROUTESMOD +#ifdef ROUTESMOD +/*************************************************************************/ +/* */ +/* L3RTT-Anzeige / 10 */ +/* */ +/*************************************************************************/ +#define ROUTESMOD_L3RTTSHOW + +/*************************************************************************/ +/* */ +/* Alle Nodes die ueber den Linkpartner geroutet werden anzeigen. */ +/* (Beispiel: R CB0GLA) */ +/* */ +/*************************************************************************/ +#define ROUTESMODVIANODES + +#endif /* ROUTESMOD */ + + +/*************************************************************************/ +/* */ +/* System-Verzeichnisse anlegen. */ +/* */ +/*************************************************************************/ +#define SETPATH + + +/*************************************************************************/ +/* */ +/* Sprachauswahl deutsch / englich fuer System und Convers-Meldungen. */ +/* */ +/* Ist erweiterbar fuer weitere Sprachen. */ +/* */ +/*************************************************************************/ +#define SPEECH + + +/*************************************************************************/ +/* */ +/* Sysop-Passwort im laufenden Betrieb aendern. */ +/* Das neue Passwort wird in der TNN179.TNB gespeichert und beim */ +/* naechsten neustart eingelesen. */ +/* */ +/* SYNTAX: PASS dasistmeinpasswort */ +/* (Passwortstring muss genau 80 Zeichen haben) */ +/* */ +/*************************************************************************/ +#define SYSOPPASSWD + + +/*************************************************************************/ +/* */ +/* TCPIP-Service */ +/* */ +/* Interner TCP-Stack. */ +/* TCPIP L1-Layer. */ +/* OS-Stack (Win32 / Linux) */ +/* TELNET-Server */ +/* HTTPD-Server */ +/* IPCONVER-Server */ +/* TNN SAUPP. */ +/* IRC-Server (noch nicht vollstaendig!) */ +/* */ +/*************************************************************************/ +#define TCP_STACK +#define L1TCPIP +#define OS_STACK +#define L1TELNET +#define L1HTTPD +#define L1IPCONV +/* #define L1IRC */ +#define OS_IPLINK + + + +/*************************************************************************/ +/* */ +/* Modifizierung am Routing-TYP THENET.im zusammenhang mit X1J4-Knoten. */ +/* */ +/* L4TIMEOUT L4-Link no activity Timer (THENET-TYP). */ +/* Ist der Timer abgelaufen, wird der Link */ +/* getrennt, aber die Connects die ueber */ +/* diesen Link laufen werden nicht getrennt. */ +/* Bei Aktivitaet wird der Link wieder */ +/* automatisch aufgebaut. */ +/* */ +/* L4QUALI Qualitaet einer Route setzen (THENET). */ +/* (Beispiel: R CB0GLA QUAL=128) */ +/* */ +/* NOROUTE Route "#" im Alias zulassen. Ist ueber */ +/* den L4PAR 7 0..1 einstellbar. */ +/* */ +/* */ +/*************************************************************************/ +#define THENETMOD + + +/*************************************************************************/ +/* */ +/* Modifizierung am Modul "TIMER". */ +/* */ +/*************************************************************************/ +#define TIMERMOD +#ifdef TIMERMOD +/*************************************************************************/ +/* */ +/* Max. SRTT-Wert auf 250 festlegen. */ +/* */ +/*************************************************************************/ +#define SRTTMAXMOD 250 + +/*************************************************************************/ +/* */ +/* SRTT-Wert updaten bei schnellen Links. */ +/* */ +/*************************************************************************/ +#define T1TIMERMOD + +/*************************************************************************/ +/* */ +/* Anfangswert fuer Smoothed Round Trip Timer setzen. */ +/* */ +/*************************************************************************/ +#define SETISRTTMOD + +#endif /* TIMERMOD */ + + +/*************************************************************************/ +/* */ +/* Alle TCPIP-Interface bei der Auflistung nicht mit angezeigt, da ein */ +/* connect auf den Port nicht moeglich ist. */ +/* (Node / User unknown! Please specify port, if DD0DSD is a User:) */ +/* */ +/*************************************************************************/ +#define TCPIP_NO_SHOW + + +/*************************************************************************/ +/* */ +/* L2-Timeout Manuell setzen. */ +/* */ +/* PA Timeout 60..54000. */ +/* */ +/*************************************************************************/ +#define TIMEOUT_MANUELL + + +/*************************************************************************/ +/* */ +/* USER-PROFIL . */ +/* */ +/* Persoenliche Einstellungen, z.B. Passwort, Nickname verwalten. */ +/* */ +/*************************************************************************/ +#define USERPROFIL + + +/*************************************************************************/ +/* */ +/* USER duerfen Monitoring. */ +/* */ +/*************************************************************************/ +#define USER_MONITOR + + +/*************************************************************************/ +/* */ +/* Modifizierung der Userausgabe. */ +/* */ +/*************************************************************************/ +#define USER_AUSGABE + + +#endif /* MODIFIGLOBAL */ diff --git a/include/conversd.h b/include/conversd.h new file mode 100755 index 0000000..03dbb32 --- /dev/null +++ b/include/conversd.h @@ -0,0 +1,132 @@ +/************************************************************************/ +/* */ +/* ***** ***** */ +/* ***** ***** */ +/* ***** ***** */ +/* ***** ***** */ +/* *************** *************** */ +/* ***************** ***************** */ +/* *************** *************** */ +/* ***** ***** TheNetNode */ +/* ***** ***** Portable */ +/* ***** ***** Network */ +/* ***** ***** Software */ +/* */ +/* File include/conversd.h (maintained by: DL1XAO) */ +/* */ +/* This file is part of "TheNetNode" - Software Package */ +/* */ +/* Copyright (C) 1998 - 2008 NORD> + * + * Modifications by Fred Baumgarten + * $Revision: 3.12 $$Date: 1996/03/03 10:09:47 $ + * + * Modifications by Oliver Kern + * $Revision: 3.13 $$Date: 17.08.2004 22:22 $ + */ + +/* zusammengefuehrtes USER.H und HOST.H, damit alle Kommandos samt + Kommandotabelle mit statischen Funktionen auskommen */ + +#include "tnn.h" +#ifdef PPCONVERS +#include "conversd.h" +#define ISO 0 + +extern char cnvinbuf[]; + +static CHANNEL *ins_channel __ARGS((WORD chan)); +static BOOLEAN has_ChOp __ARGS((WORD chan)); +static void disp_links __ARGS((CONNECTION *cp, char *user)); +static void ed_list __ARGS((CONNECTION *cp, WORD which)); +static WORD is_looped __ARGS((PERMLINK *l, char *host)); +#ifdef CONVERS_NO_NAME_OK +#else +static BOOLEAN name_ok __ARGS((char *call)); +#endif +static BOOLEAN host_ok __ARGS((char *call)); + +static void all_command __ARGS((CONNECTION *cp)); +static void away_command __ARGS((CONNECTION *cp)); +static void beep_command __ARGS((CONNECTION *cp)); +static void channel_command __ARGS((CONNECTION *cp)); +static void charset_command __ARGS((CONNECTION *cp)); +static void cstat_command __ARGS((CONNECTION *cp)); +static void filter_command __ARGS((CONNECTION *cp)); +#ifndef L1IRC +static void help_command __ARGS((CONNECTION *cp)); +#endif /* L1IRC */ +#ifdef CONVERS_HOSTNAME +static void hostname_command __ARGS((CONNECTION *cp)); +#endif +static void hosts_command __ARGS((CONNECTION *cp)); +static void invite_command __ARGS((CONNECTION *cp)); +static void imsg_command __ARGS((CONNECTION *cp)); +#ifndef L1IRC +static void leave_command __ARGS((CONNECTION *cp)); +static void links_command __ARGS((CONNECTION *cp)); +#endif /* L1IRC */ +static void list_command __ARGS((CONNECTION *cp)); +#ifndef L1IRC +static void msg_command __ARGS((CONNECTION *cp)); +#endif /* L1IRC */ +static void me_command __ARGS((CONNECTION *cp)); +static void mode_command __ARGS((CONNECTION *cp)); +static void name_command __ARGS((CONNECTION *cp)); +#ifdef CONVNICK +static void nickname_command __ARGS((CONNECTION *cp)); +static void nonickname_command __ARGS((CONNECTION *cp)); +#endif +static void notify_command __ARGS((CONNECTION *cp)); +static void personal_command __ARGS((CONNECTION *cp)); +static void prompt_command __ARGS((CONNECTION *cp)); +static void query_command __ARGS((CONNECTION *cp)); +static void restart_command __ARGS((CONNECTION *cp)); +#ifdef CONVERS_SYSINFO +static void sysinfo_command __ARGS((CONNECTION *cp)); +#endif +static void topic_command __ARGS((CONNECTION *cp)); +static void uptime_command __ARGS((CONNECTION *cp)); +static void verbose_command __ARGS((CONNECTION *cp)); +static void version_command __ARGS((CONNECTION *cp)); +static void width_command __ARGS((CONNECTION *cp)); +static void who_command __ARGS((CONNECTION *cp)); +static void wall_command __ARGS((CONNECTION *cp)); +#ifdef CVS_ZAPPING +static void zap_command __ARGS((CONNECTION *cp)); +#endif + +static void h_away_command __ARGS((CONNECTION *cp)); +static void h_cmsg_command __ARGS((CONNECTION *cp)); +static void h_dest_command __ARGS((CONNECTION *cp)); +static void h_host_command __ARGS((CONNECTION *cp)); +static void h_invi_command __ARGS((CONNECTION *cp)); +static void h_link_command __ARGS((CONNECTION *cp)); +static void h_oper_command __ARGS((CONNECTION *cp)); +static void h_ping_command __ARGS((CONNECTION *cp)); +static void h_pong_command __ARGS((CONNECTION *cp)); +static void h_rout_command __ARGS((CONNECTION *cp)); +static void h_topi_command __ARGS((CONNECTION *cp)); +#ifdef CONVNICK +static void h_uadd_command __ARGS((CONNECTION *cp)); +#endif +static void h_udat_command __ARGS((CONNECTION *cp)); +static void h_unknown_command __ARGS((CONNECTION *cp)); +static void h_umsg_command __ARGS((CONNECTION *cp)); +static void h_user_command __ARGS((CONNECTION *cp)); + +typedef struct cmdtable { + char *name; + void (*fnc)(CONNECTION *); + char *help; + WORD states; +} CMDTABLE; + +static CMDTABLE cmdtable[] = { + + {"?", help_command, "HELP", CM_USER}, + {"away", away_command, "AWAY", CM_USER}, + {"action", me_command, "ME", CM_USER}, + {"all", all_command, "ALL", CM_USER}, + {"beep", beep_command, "BEEP", CM_USER}, + {"bell", beep_command, "BEEP", CM_USER}, + {"bye", bye_command, "QUIT", CM_USER}, + {"channel", channel_command, "JOIN", CM_USER}, + {"charset", charset_command, "CHAR", CM_USER}, + {"cstat", cstat_command, NULL, CM_UNKNOWN}, + {"destinations", hosts_command, "DEST", CM_USER}, + {"exit", bye_command, "QUIT", CM_USER}, + {"exclude", imsg_command, "EXCL", CM_USER}, + {"filter", filter_command, "FILT", CM_USER}, + {"help", help_command, "HELP", CM_USER}, +#ifdef CONVERS_HOSTNAME + {"hostname", hostname_command, "HOST", CM_UNKNOWN}, +#endif + {"hosts", hosts_command, "DEST", CM_USER}, + {"invite", invite_command, "INVI", CM_USER}, + {"imsg", imsg_command, "EXCL", CM_USER}, + {"iwrite", imsg_command, "EXCL", CM_USER}, + {"join", channel_command, "JOIN", CM_USER}, + {"links", links_command, "LINK", CM_USER}, + {"leave", leave_command, "LEAV", CM_USER}, + {"list", list_command, "LIST", CM_USER}, + {"msg", msg_command, "MSG", CM_USER}, + {"me", me_command, "ME", CM_USER}, + {"mode", mode_command, "MODE", CM_USER}, + {"name", name_command, NULL, CM_UNKNOWN}, +#ifdef CONVNICK + {"nickname", nickname_command, "NICK", CM_USER}, + {"nonickname", nonickname_command, "NONICK", CM_USER}, +#endif + {"notify", notify_command, "NOTI", CM_USER}, + {"note", personal_command, "PERS", CM_USER}, + {"online", who_command, NULL, CM_UNKNOWN}, + {"personal", personal_command, "PERS", CM_USER}, + {"prompt", prompt_command, "PROM", CM_USER}, + {"quit", bye_command, "QUIT", CM_USER}, + {"query", query_command, "QUER", CM_USER}, + {"restart", restart_command, NULL, CM_USER}, + {"send", msg_command, "MSG", CM_USER}, +#ifdef CONVERS_SYSINFO + {"sysinfo", sysinfo_command, "SYSI", CM_USER}, +#endif + {"topic", topic_command, "TOPI", CM_USER}, + {"users", who_command, "WHO", CM_USER}, + {"uptime", uptime_command, "UPTI", CM_USER}, + {"verbose", verbose_command, "VERB", CM_USER}, + {"version", version_command, "VERS", CM_USER}, + {"who", who_command, "WHO", CM_USER}, + {"width", width_command, "WIDT", CM_USER}, + {"wall", wall_command, NULL, CM_USER}, + {"write", msg_command, "MSG", CM_USER}, +#ifdef CVS_ZAPPING + {"zap", zap_command, NULL, CM_USER}, +#endif + + {"\377\200away", h_away_command, NULL, CM_HOST}, + {"\377\200cmsg", h_cmsg_command, NULL, CM_HOST}, + {"\377\200dest", h_dest_command, NULL, CM_HOST}, + {"\377\200host", h_host_command, NULL, CM_UNKNOWN}, + {"\377\200invi", h_invi_command, NULL, CM_HOST}, + {"\377\200link", h_link_command, NULL, CM_HOST}, + {"\377\200mode", mode_command, NULL, CM_HOST}, + {"\377\200oper", h_oper_command, NULL, CM_HOST}, + {"\377\200ping", h_ping_command, NULL, CM_HOST}, + {"\377\200pong", h_pong_command, NULL, CM_HOST}, + {"\377\200rout", h_rout_command, NULL, CM_HOST}, + {"\377\200topi", h_topi_command, NULL, CM_HOST}, +#ifdef CONVNICK + {"\377\200uadd", h_uadd_command, NULL, CM_HOST}, +#endif + {"\377\200udat", h_udat_command, NULL, CM_HOST}, + {"\377\200umsg", h_umsg_command, NULL, CM_HOST}, + {"\377\200user", h_user_command, NULL, CM_HOST}, + + {NULL, 0, NULL, 0} +}; + +#endif +/* End of $RCSfile$ */ diff --git a/include/function.h b/include/function.h new file mode 100644 index 0000000..4a68a31 --- /dev/null +++ b/include/function.h @@ -0,0 +1,743 @@ +/************************************************************************/ +/* */ +/* ***** ***** */ +/* ***** ***** */ +/* ***** ***** */ +/* ***** ***** */ +/* *************** *************** */ +/* ***************** ***************** */ +/* *************** *************** */ +/* ***** ***** TheNetNode */ +/* ***** ***** Portable */ +/* ***** ***** Network */ +/* ***** ***** Software */ +/* */ +/* File include/function.h (maintained by: ???) */ +/* */ +/* This file is part of "TheNetNode" - Software Package */ +/* */ +/* Copyright (C) 1998 - 2008 NORD> L2 Traffic */ + +/* Definitionen for PP-Convers */ +extern WORD cvs_pc; +extern time_t currtime; +extern time_t boottime; +extern const char *convtype; +extern const char *myfeatures; +extern char *myhostname; +extern char myrev[]; +extern char timestamp[]; +extern PERMLINK *permarray[MAXCVSHOST]; +extern CONNECTION *connections; +extern DESTINATION *destinations; +extern CHANNEL *channels; + +extern LONG rounds_pro_sec; /* Anzahl Rounds/Sekunde */ +extern LONG rounds_max_sec; /* Maximale Anzahl */ +extern LONG rounds_min_sec; /* Minimale Anzahl */ +extern LONG rounds_count; /* Zaehler fuer Rounds */ + +extern BEACON beacon[L2PNUM]; + +extern time_t t; + +#if defined(CRASHDEBUG) || defined(__LINUX__) +extern char *wowarich; +extern char *wowarich2; +#endif + +#ifdef PACSAT +extern WORD pacsat_enabled[]; +extern UWORD pacsat_timer; +extern UWORD pacsat_frames; +extern UWORD pacsat_free; +extern LONG first_fid; +extern LONG last_fid; +extern char pacsatid[]; +#endif + +extern unsigned int_level; /* Interrupt-Vertiefungs-Level */ + +extern ULONG MEMORY_NEEDED; /* fuer Message Buffer */ +extern UWORD proto; +extern char loginstr[]; +extern char infostr[]; + +extern char author[]; + +extern BOOLEAN tnnb_aktiv; + +extern time_t sys_time; +extern struct tm *sys_localtime; + +#ifdef GRAPH +extern TGRAPH graph; +#endif + +#ifdef AXIPR_HTML +extern char htmlpath[]; +#endif + +#ifdef MH_LISTE +extern UWORD MHdefault; +extern UWORD MHlen; +#endif + +#ifdef TIMEOUT_MANUELL +extern UWORD ininat; +#endif /* TIMEOUT_MANUELL */ + +#ifdef HOSTMYCALL +extern char hostuserid[]; +#endif + +#ifdef BEACON_STATUS +extern UWORD statustim; +#endif + + +#ifdef AXIPR_UDP +extern BOOLEAN LookAX25IP; /* Wir durfen keine Frame lesen. */ +#endif /* AXIPR_UDP */ + +#ifdef DEBUG_MODUS +extern char lastbuf[]; +extern char *lastfunc; +#endif /* DEBUG_MODUS */ + +extern BOOLEAN bVerbose; + +/* End of global.h */ diff --git a/include/host.h b/include/host.h new file mode 100755 index 0000000..29c670e --- /dev/null +++ b/include/host.h @@ -0,0 +1,100 @@ +/************************************************************************/ +/* */ +/* ***** ***** */ +/* ***** ***** */ +/* ***** ***** */ +/* ***** ***** */ +/* *************** *************** */ +/* ***************** ***************** */ +/* *************** *************** */ +/* ***** ***** TheNetNode */ +/* ***** ***** Portable */ +/* ***** ***** Network */ +/* ***** ***** Software */ +/* */ +/* File include/host.h (maintained by: DF6LN) */ +/* */ +/* This file is part of "TheNetNode" - Software Package */ +/* */ +/* Copyright (C) 1998 - 2008 NORD>>5 & 7) +#define DELAY 0x10 +#define THRUPUT 0x8 +#define RELIABLITY 0x4 + +/* structure for an ip address (long) */ +typedef unsigned long ipaddr; + +/* Format of a MIB entry for statistics gathering */ +typedef struct mib_entry { + const char *name; + struct { + unsigned int integer; + } value; +} MIB_ENTRY; + +#define TLB 30 /* Default reassembly timeout, sec */ +#define IPVERSION 4 /* IP-Version 4.0 */ +#define IP_MAXOPT 40 /* Largest option field, bytes */ + +/* SNMP MIB variables, used for statistics and control. See RFC 1066 */ +#define ipForwarding Ip_mib[1].value.integer +#define ipDefaultTTL Ip_mib[2].value.integer +#define ipInReceives Ip_mib[3].value.integer +#define ipInHdrErrors Ip_mib[4].value.integer +#define ipInAddrErrors Ip_mib[5].value.integer +#define ipForwDatagrams Ip_mib[6].value.integer +#define ipInUnknownProtos Ip_mib[7].value.integer +#define ipInDiscards Ip_mib[8].value.integer +#define ipInDelivers Ip_mib[9].value.integer +#define ipOutRequests Ip_mib[10].value.integer +#define ipOutDiscards Ip_mib[11].value.integer +#define ipOutNoRoutes Ip_mib[12].value.integer +#define ipReasmTimeout Ip_mib[13].value.integer +#define ipReasmReqds Ip_mib[14].value.integer +#define ipReasmOKs Ip_mib[15].value.integer +#define ipReasmFails Ip_mib[16].value.integer +#define ipFragOKs Ip_mib[17].value.integer +#define ipFragFails Ip_mib[18].value.integer +#define ipFragCreates Ip_mib[19].value.integer + +#define NUMIPMIB 19 + +/* IP header, INTERNAL representation */ +typedef struct ip_struct { + unsigned char version; /* IP version number */ + unsigned char ihl; /* Internet Header Length */ + unsigned char tos; /* Type of service */ + unsigned length; /* Total length */ + unsigned id; /* Identification */ + unsigned offset; /* Fragment offset in bytes */ + struct { + unsigned char df; /* Don't fragment flag */ + unsigned char mf; /* More Fragments flag */ + } flags; + + unsigned char ttl; /* Time to live */ + + unsigned char protocol; /* Protocol */ + unsigned checksum; /* Header checksum */ + ipaddr source; /* Source address */ + ipaddr dest; /* Destination address */ + unsigned char options[IP_MAXOPT];/* Options field */ + unsigned optlen; /* Length of options field, bytes */ +} IP; + +#define TCP_MAXOPT 4 /* max Anzahl als Option-Bytes */ +typedef unsigned long SEQ; +typedef unsigned long ACK; +/* TCP header */ +typedef struct tcp_struct { + unsigned srcPort; /* Source-Port */ + unsigned dstPort; /* Destination-POrt */ + SEQ seqnum; /* Sequence Number */ + ACK acknum; /* Acknowledgement Number */ + unsigned char data_offset; /* Data Offset 4 Bits */ + unsigned char res; /* reserviert */ + unsigned flags; /* Flags */ + unsigned window; /* Window */ + unsigned checksum; /* Checksum */ + unsigned urgentPointer; /* Urgent Pointer */ + unsigned char options[TCP_MAXOPT]; /* Options and Padding */ +} TCP; + +/* UDP header */ +typedef struct udp_struct { + unsigned srcPort; + unsigned dstPort; + unsigned length; + unsigned checksum; +} UDP; + +#define NULLIP (IP *)NULL +#define IPLEN 20 /* Length of standard IP header */ + +/* Fields in option type byte */ +#define OPT_COPIED 0x80 /* Copied-on-fragmentation flag */ +#define OPT_CLASS 0x60 /* Option class */ +#define OPT_NUMBER 0x1f /* Option number */ + +/* IP option numbers */ +#define IP_EOL 0 /* End of options list */ +#define IP_NOOP 1 /* No Operation */ +#define IP_SECURITY 2 /* Security parameters */ +#define IP_LSROUTE 3 /* Loose Source Routing */ +#define IP_TIMESTAMP 4 /* Internet Timestamp */ +#define IP_RROUTE 7 /* Record Route */ +#define IP_STREAMID 8 /* Stream ID */ +#define IP_SSROUTE 9 /* Strict Source Routing */ + +/* Timestamp option flags */ +#define TS_ONLY 0 /* Time stamps only */ +#define TS_ADDRESS 1 /* Addresses + Time stamps */ +#define TS_PRESPEC 3 /* Prespecified addresses only */ + +/* structure for routing tables */ + +typedef struct iproute +{ + struct iproute *nextip; + struct iproute *previp; +#ifdef BUFFER_DEBUG + UBYTE owner; /* Muss an 9. Bytestelle stehen */ +#endif + ipaddr dest; + ipaddr gateway; + unsigned metric; + unsigned timer; + unsigned char bits; +#ifdef __WIN32__ + unsigned char Interface; +#else + unsigned char interface; +#endif + unsigned char flags; +#define RTDYNAMIC 0x01 /* dynamic ip-address */ + unsigned char spare_byte; + UBYTE port; + BOOLEAN automatic_flag; +} IP_ROUTE; + +#define NULLROUTE (IP_ROUTE *)NULL + +/* Cache for the last-used routing entry, speeds up the common case where + * we handle a burst of packets to the same destination + */ +/*typedef struct rt_cache { + ipaddr target; + IP_ROUTE *route; +} RT_CACHE; +*/ +typedef struct arp_tab +{ + struct arp_tab *nextar; + struct arp_tab *prevar; +#ifdef BUFFER_DEBUG + UBYTE owner; /* Muss an 9. Bytestelle stehen */ +#endif + ipaddr dest; + unsigned timer; + char dgmode; + UBYTE hwtype; + char publish_flag; + char state; + char callsign[7]; + char digi[15]; + WORD port; + BOOLEAN automatic_flag; +} ARP_TAB; + +#define NULLARP (ARP_TAB *)NULL + +#define ARP_NETROM 0 +#define ARP_AX25 3 + +#define MAXHWALEN 10 +#define IPTYPE 42 + +#define ARP_REQUEST 1 +#define ARP_REPLY 2 +#define REVARP_REQUEST 3 +#define REVARP_REPLY 4 + +typedef struct arp +{ + unsigned hardware; + unsigned protocol; + unsigned char hwalen; + unsigned char pralen; + unsigned opcode; + unsigned char shwaddr[MAXHWALEN]; + ipaddr sprotaddr; + unsigned char thwaddr[MAXHWALEN]; + ipaddr tprotaddr; +} ARP; + +#define NULLBUF ( void * )NULL + +/* Pseudo-header for TCP and UDP checksumming */ +typedef struct pseudo_header { + ipaddr source; /* IP source */ + ipaddr dest; /* IP destination */ + unsigned char protocol; /* Protocol */ + unsigned length; /* Data field length */ +} PSEUDO_HEADER; +#define NULLHEADER (struct pseudo_header *)NULL + +#ifdef IPROUTE +/* src/l7ip.c */ +void ccpipr(void); +void showroute(IP_ROUTE *,MBHEAD *); +void show_ip_addr(ipaddr,MBHEAD *); +BOOLEAN get_ip_addr(ipaddr *,WORD *,char **); +void ccparp(void); +void showarp(ARP_TAB *,MBHEAD *); +void ccpipa(void); +void ccpipb(void); +void ccpips(void); +BOOLEAN rt_add(ipaddr,unsigned int ,ipaddr,int ,unsigned int ,unsigned int ,int, BOOLEAN); +BOOLEAN route_find(IP_ROUTE **,ipaddr *,ipaddr,unsigned int ); +BOOLEAN rt_drop(ipaddr,unsigned int, BOOLEAN); +BOOLEAN arp_add(ipaddr, WORD, char *, const char *, unsigned int, + unsigned int, BOOLEAN, BOOLEAN); +BOOLEAN find_arp(ARP_TAB * *,ipaddr, WORD ); +BOOLEAN arp_drop(ipaddr, WORD, BOOLEAN); +void arpsrv(void); +void ccpping(void); +BOOLEAN l2toip(WORD); + +/* src/iproute.c */ +void ipinit(void ); +void ipserv(void ); +void ip_route(MBHEAD * ); +void arp_service(MBHEAD *); +IP_ROUTE *rt_find(ipaddr); +void nr_iface(MBHEAD *,ipaddr ); +void l2_iface(MBHEAD *,unsigned int ,ipaddr,unsigned int ); +ARP_TAB *res_arp(ipaddr, unsigned int ); +MBHEAD *htonip(IP *,MBHEAD *, BOOLEAN ); +int ip_send(ipaddr,ipaddr,unsigned ,unsigned ,unsigned ,MBHEAD *,unsigned short ,unsigned short ,unsigned ); +unsigned short eac(long ); +unsigned short cksum(PSEUDO_HEADER *,MBHEAD *,unsigned short ); +void arp_request(ipaddr,unsigned,unsigned); +void arp_send( unsigned, char *); +void ccp_ip_help(ipaddr *, const char *); +BOOLEAN pingem(ipaddr target,int seq,int id, int len, char *opt); + +#define NR4_OP_PID 0 +#define NR_PROTO_IP 0x0c + +typedef struct ipportpar { + WORD ipMode; /* Mode-Flags fuer diesen Port */ +#define ARP_OK 0x0001 /* ARP erlaubt */ +#define IP_FORWARDING 0x0002 /* das Weiterleiten von IP-Frames */ + WORD mtu; /* Maximale Blockgroesse */ +} IPPORTPAR; + +extern LHEAD arprxfl; /* Empfangene ARP-Frames */ + +extern IPPORTPAR IPpar[]; /* fuer jeden L2-Port + NETROM */ +#define NETROM_PORT L2PNUM + +#ifdef KERNELIF +#define KERNEL_PORT L2PNUM + 1 +#endif + +#define is_my_ip_addr( address ) ( address == my_ip_addr ) +#define is_broadcast_address( address ) ( bcast_ip_addr != 0 && bcast_ip_addr == address ) + +#else +#define l2toip(x) FALSE + +#endif /* IPROUTE */ +/* End of $RCSfile$ */ diff --git a/include/ipv.h b/include/ipv.h new file mode 100755 index 0000000..6627b9c --- /dev/null +++ b/include/ipv.h @@ -0,0 +1,72 @@ +/************************************************************************/ +/* */ +/* ***** ***** */ +/* ***** ***** */ +/* ***** ***** */ +/* ***** ***** */ +/* *************** *************** */ +/* ***************** ***************** */ +/* *************** *************** */ +/* ***** ***** TheNetNode */ +/* ***** ***** Portable */ +/* ***** ***** Network */ +/* ***** ***** Software */ +/* */ +/* File include/ipv.h (maintained by: DG1KWA) */ +/* */ +/* This file is part of "TheNetNode" - Software Package */ +/* */ +/* Copyright (C) 1998 - 2008 NORD> HTML. */ + FILE *fp; /* Datei laden. */ +#endif /* L1HTTPD */ +#ifdef L1IPCONV + BOOLEAN CVSlink; /* Linkpartner. */ + BOOLEAN Intern; /* Connect Intern. */ +#ifdef L1IRC + BOOLEAN IrcMode; /* irc-client. */ +#endif /* L1IRC */ +#endif /* L1IPCONV */ + BOOLEAN LoginPrompt; /* Prompt senden. */ + BOOLEAN cr; /* Return durchlaufen. */ + WORD state; /* Connected, Disconnected setzen. */ + LHEAD inbuf; /* Listenkopf Eingabebuffer */ + LHEAD outbuf; /* Listenkopf Ausgabebuffer */ + char txstatus; /* Sender frei/busy. */ +} TCPIP; + +extern TCPIP *tcptbl; /* Zeiger auf die TBL. */ +extern TCPIP *tcppoi; /* Zeiger auf den aktuellen TCPIP-User. */ +extern LHEAD tcpfrel; /* Liste der freien Linkbloecke. */ +extern LHEAD tcpactl; /* Liste der aktiven Linkbloecke. */ +extern LHEAD rxflRX; /* Empfangsliste */ +extern LHEAD rxflTX; /* Sendeliste */ + +extern int tcp_tbl_top; /* Anzahl der aktuellen TCP-User. */ + +extern void TcpipSRV(void); /* TCPIP-Service. */ +extern void InitTCP(void); /* TCPIP Initialisieren. */ +extern void InitIFC(void); /* Interface Initialisieren. */ +extern void L1ExitTCP(WORD); /* TCPIP-Interface schliessen. */ +extern void L1ctlTCP(int, int); /* Level 1 Kontrolle */ +extern BOOLEAN TcpDCD(int); /* DCD-Status liefern. */ +extern BOOLEAN L1InitTCP(UWORD, int, int); /* TCPIP-Port Initialisieren. */ +extern void HwstrTCP(UWORD, int, MBHEAD *);/* Portinfo-String (PORT-Befehl)*/ +extern int CheckPortTCP(int); /* Pruefe, auf TCP-Port's. */ +extern void DumpTCP(MBHEAD *); /* TCPIP-Einstellungen sichern. */ +extern BOOLEAN itoTCP(BOOLEAN, MBHEAD *); /* Info vom L7 an TCP-Interf. senden*/ +extern void SetDiscTCP(void); /* User hat ein Disconnect eingeleitet. */ +extern void TimerTCP(void); /* Noactivity-Timer fuer alle TCPIP Connect's. */ +extern int KillTCP(UWORD, char *,WORD); /* TCPIP-User/Link(s) KILLEN. */ +extern int ReadSockTCP(void); /* Zeichen vom Socket holen. */ +extern BOOLEAN CheckContens(char); /* Pruefe Loginzeichen. */ +extern void TcpipRelink(MBHEAD *); /* Eingehende Daten weiterleiten. */ +extern MBHEAD *SetBuffer(void); /* Buffer besorgen. */ +extern int SetupTCP(char *, unsigned short); /* Sock Initialisieren.*/ +T_INTERFACE *SearchIf(UWORD); /* Das gesuchte Interface ermitteln */ + /* und den Interfacezeiger setzen. */ +extern void MhUpdateTCP(MBHEAD *, /* Buffer */ + BOOLEAN); /* Flag fuer RX/TX-Bytes. */ +extern BOOLEAN LoginTCP(MBHEAD *); +extern void RelinkTCP(MBHEAD *); /* Packet umhaengen. */ + + + +extern void DiscTCP(void); /* Alle Parameter auf default zuruecksetzen */ + /* und den User aus der Liste nehmen. */ + +extern int AddUserTCP(T_INTERFACE *, /* Neue User hinzufuegen, */ + unsigned, /* vorrausgesetzt es sind noch */ + char *); /* freie Sockets vorhanden. */ + +extern void SetDefaultWorthTCP(unsigned, /* Defaultwerte setzen. */ + char *, + int , + UWORD , + BOOLEAN); + +extern void WriteLogTCP(BOOLEAN, /* System- und Errormeldungen */ + const char *, /* in einer Logdatei schreiben. */ + ...); + +#define T_LOGL1 if(ifpp->log > 0)(void)WriteLogTCP /* System-Meldungen in */ + /* einer Logdatei schreiben. */ +#define T_LOGL2 if(ifpp->log > 1)(void)WriteLogTCP /* System- und Error- */ + /* meldungen in einer Logdatei schreiben. */ +#define T_LOGL3 if(ifpp->log > 2)(void)WriteLogTCP /* ALLE Log-Meldungen */ + /* schreiben. */ + +extern T_INTERFACE *SetInterface(UWORD); + +#define KISS_TCPIP 22 /* 1. TCPIP-Interface */ + /* 22 Telnet */ + /* 23 Httpd */ + /* 24 IPConv */ + /* 25 IRC */ + +#define KISS_MAX 25 /* letztes Interface */ + +#endif /* L1TCPIP */ + +/* End of include/l1tcpip.h */ diff --git a/include/l1telnet.h b/include/l1telnet.h new file mode 100755 index 0000000..6468bba --- /dev/null +++ b/include/l1telnet.h @@ -0,0 +1,19 @@ +#ifdef L1TCPIP + +#define L1TELNET /* TELNET-Interface. */ + +#define KISS_TELNET 22 /* Telnet KISS-Types */ +#define TEL_ID 0 /* Interface-ID TELNET. */ + +#define DEFAULT_TELNET_PORT 10023 /* Default Port 10023. */ +#define TELNET_TXT "telnet.txt" /* Fuer Login-Prompt. */ +#define TELNETLOG "telnet.log" /* Logdatei zum mit schreiben von */ + /* System- und Errormeldungen. */ + + +extern TRILLIAN GetContensTEL(char); /* Aktuelle Zeichen auswerten. */ +extern void ccptelnet(void); /* TELNET-Server Einstellung aendern/setzen. */ + +#endif /* L1TCPIP */ + +/* End of include/l1telnet.h */ diff --git a/include/l2.h b/include/l2.h new file mode 100755 index 0000000..d983b00 --- /dev/null +++ b/include/l2.h @@ -0,0 +1,172 @@ +/************************************************************************/ +/* */ +/* ***** ***** */ +/* ***** ***** */ +/* ***** ***** */ +/* ***** ***** */ +/* *************** *************** */ +/* ***************** ***************** */ +/* *************** *************** */ +/* ***** ***** TheNetNode */ +/* ***** ***** Portable */ +/* ***** ***** Network */ +/* ***** ***** Software */ +/* */ +/* File include/l2.h (maintained by: DF6LN) */ +/* */ +/* This file is part of "TheNetNode" - Software Package */ +/* */ +/* Copyright (C) 1998 - 2008 NORD>fd_count; __i++) { \ + if (((Fd_set *)(set))->fd_array[__i] == (fd)) { \ + break; \ + } \ + } \ + if (__i == ((Fd_set *)(set))->fd_count) { \ + if (((Fd_set *)(set))->fd_count < FD_SETSIZE) { \ + ((Fd_set *)(set))->fd_array[__i] = (fd); \ + ((Fd_set *)(set))->fd_count++; \ + } \ + } \ +} while(0) + +#define FD_ZERO_T(set) (((Fd_set *)(set))->fd_count=0) + +extern BOOLEAN GetSocket(Socklen_t, Fd_set *); +#define FD_ISSET_T(fd, set) GetSocket((Socklen_t)(fd), (Fd_set *)(set)) + +struct In_addr { + union { + struct { UBYTE s_b1,s_b2,s_b3,s_b4; } S_un_b; + struct { UWORD s_w1,s_w2; } S_un_w; + ULONG _S_addr; + } _S_un; +#define _S_addr _S_un._S_addr + /* can be used for most tcp & ip code */ +}; + +struct Sockaddr_in +{ + short sin_family; + UWORD sin_port; + struct In_addr sin_addr; + char sin_zero[8]; +}; + +struct Sockaddr +{ + UWORD sa_family; /* address family */ + char sa_data[14]; /* up to 14 bytes of direct address */ +}; + +struct Timeval +{ + long tv_sec; /* seconds */ + long tv_usec; /* and microseconds */ +}; + +typedef struct tsocket /* Struktur Socketliste */ +{ + struct tsocket *next; + struct tsocket *prev; +#ifdef BUFFER_DEBUG + UBYTE owner; /* Muss an 9. Bytestelle stehen */ +#endif + ACK RecvNext; /* Naechstes Frame Empfangen. */ + SEQ SendNext; /* Naechstes Frame Senden. */ + ACK SendUnacked; /* Noch nicht gesende Frames. */ + unsigned long IpDest; /* IP-Adresse vom Nachbarn. */ + int Socket; /* Socket. */ + int Domain; /* Domain. */ + int Type; /* Protokoll-Typ (TCP oder UDP). */ + int PacNum; /* Frame-Zaehler. */ + /* TCP-Header. */ + unsigned DestPort; /* Destination-Port */ + unsigned LocalPort; /* Local-Port setzen. */ + unsigned short MaxListen; /* Groesse der Warteschlange. */ + unsigned short Listen; /* Momentan in der Warteschlange. */ + unsigned char UrgPointer; /* Urgent Pointer */ + UBYTE State; /* Socket-Status. */ + UBYTE TState; /* Socket-Status. */ + UBYTE tos; /* Type of service */ + BOOLEAN RecvEvent; /* Select markieren, Empfang. */ + BOOLEAN SendEvent; /* Select markieren, Senden. */ +} TSOCKET; + +extern TSOCKET sockets[NUM_SOCKETS]; + +extern int Socket(int, /* Ein socket anlegen. */ + int, + int); + +extern int Bind (int, /* Socket binden. */ + struct Sockaddr *, + Socklen_t); + +extern int Listen(int, /* Lausche auf Socket. */ + int); + +extern int Select(int, /* Den Socket auf Aktivitaet pruefen. */ + Fd_set *, + Fd_set *, + Fd_set *, + struct Timeval *); + +extern int Accept(int , /* Verbindungsbau annehmen/ablehnen. */ + struct Sockaddr *, + Socklen_t *); + +extern int Recv (int , /* Daten Empfangen. */ + char *, + int , + int); + +extern int Send (int , /* Daten Senden. */ + char *, + int, + int); + +extern void Close (int); /* Socket schliessen. */ + + +extern int SearchSock(int); /* Den Socket aus der Socketliste suchen. */ +extern void DelSocket(int); /* Socket als unbenutzt markieren. */ + +/* konvertiert die Kurzganzzahl hostshort Rechner- nach Netzwerk-Byteordnung. */ +extern unsigned short Htons(unsigned short); +/* konvertiert die Kurzganzzahl netshort von Netzwerk-nach Rechner-Byteordnung*/ +extern unsigned short Ntohs(unsigned short); +/* konvertiert die Langganzzahl hostlong von Rechner-nach Netzwerk-Byteordnung*/ +extern unsigned long Htonl(unsigned long); +/* konvertiert die Langganzzahl netlong von Netzwerk- nach Rechner-Byteordnung*/ +extern unsigned long Ntohl(unsigned long); + +#endif /* TCP_STACK. */ + +/* End of include/l3sock.h. */ diff --git a/include/l3tcp.h b/include/l3tcp.h new file mode 100755 index 0000000..c4991d7 --- /dev/null +++ b/include/l3tcp.h @@ -0,0 +1,91 @@ + +extern LHEAD rxSegment; /* RX TCP-Segmente */ +extern LHEAD txSegment; /* TX TCP-Segment. */ +extern LHEAD rxDaten; /* RX-Buffer. */ + +#define TCP_HEADER 20 /* TCP-Headerlaenge. */ +#define TCP_OPTION 8 /* TCP-Optionslaenge. */ + +/* TCP-Option-Flags */ +#define TFIN 0x01 /* Socket schliessen. */ +#define TSYN 0x02 /* Verbindungsaufbau starten. */ +#define TRST 0x04 /* Verbindung zurueck setzen. */ +#define TPSH 0x08 /* Daten senden. */ +#define TACK 0x10 /* Bestaetigungen. */ +#define TURGE 0x20 /* Flag ignored */ + +#define WINSIZE 512 /* Fenstergroesse festlegen. */ + +/* TCP-Options */ +#define OPTEND 516 /* End of Option List. */ +#define OPTNOO 257 /* No-Operation. */ +#define OPTMSS 512 /* Maximum Segment Size. */ +#define OPTPA3 1026 + +#define TCP_TIMEOUT 30 /* Timer-Wert fuer Segment Wiederholungen. */ +#define TCP_MAX_RETRY 7 /* Maximal Wiederholen. */ + +typedef struct datenrx /* Struktur fuer RX-Bufferung. */ +{ + struct datenrx *next; + struct datenrx *prev; +#ifdef BUFFER_DEBUG + UBYTE owner; /* Muss an 9. Bytestelle stehen */ +#endif + MBHEAD *Data; /* RX-Buffer eines Segment. */ + int Sock; /* Socket vom Segment. */ +} DATENRX; + +typedef struct stackrx /* Struktur RX-Segment Empfang. */ +{ + struct stackrx *next; + struct stackrx *prev; +#ifdef BUFFER_DEBUG + UBYTE owner; /* Muss an 9. Bytestelle stehen */ +#endif + MBHEAD *Data; /* Buffer eines Segment . */ + IP *IpHdr; /* IP-Header. */ +} STACKRX; + +typedef struct stacktx /* Struktur TX-Segment senden. */ +{ + struct stacktx *next; + struct stacktx *prev; +#ifdef BUFFER_DEBUG + UBYTE owner; /* Muss an 9. Bytestelle stehen */ +#endif + MBHEAD *Data; /* Buffer. */ + int Sock; /* Socket. */ + unsigned short Flags; /* TCP-Flags. */ + unsigned char TState; /* TCP-Statusaenderung. */ + int Timer; /* Timer. */ + time_t TimeLast; /* */ + int Retry; /* Retry-Zaehler. */ +} STACKTX; + + +extern void StackInitTCP(void); /* TCP Initialisieren */ +extern void StackSRV(void) ; /* TCP-Service */ +extern void StackTimer(void); /* Timer fuer Frame-Wiederholungen. */ + +extern void SendTcpFlag(register int,/* Frame fuer IP-Router vorbereiten. */ + + MBHEAD *, + unsigned int, + unsigned short, + unsigned short, + unsigned short); + +extern void TCPIPProcess(register IP *,/* Eingehende TCP-Daten weiter-*/ + register MBHEAD *);/* leiten in die RX-Seg.-liste*/ + +extern void PutTXStack(register int, /* Neues TX-Segment in die Sende-*/ + MBHEAD *, /* liste anlegen/anhaengen. */ + int, + unsigned short, + unsigned char); + +extern void DelSock(int); /* Entsorge alle Buffer vom Socket. */ +extern DATENRX *GetBuffer(TSOCKET *); /* Einen Eintrag aus der RX-Liste holen.*/ + +/* End of include/l3tcp.h. */ diff --git a/include/l3thenet.h b/include/l3thenet.h new file mode 100755 index 0000000..bb4bb3d --- /dev/null +++ b/include/l3thenet.h @@ -0,0 +1,45 @@ + +extern PARAM L4partab[]; +extern int L4partablen; + +extern UWORD obcini; /* Anfangswert fuer Knoten Lebensdauer */ +extern UWORD obcbro; /* min. Restlebensdauer fuer Rundspruch */ + +/* L4TIMEOUT */ +extern UWORD L4Timeout; /* L4-Link no activity Timer. */ + +/* NOROUTE */ +extern UWORD NoRoute; /* 0 = Link-Nachbar mit # im Alias NICHT zulassen. */ + /* 1 = Link-Nachbar mit # im Alias zulassen. */ + /* Parameter 0 ist standard. */ + +extern UWORD l4_beta3; /* BUSY/REQ-TIMEOUT (T3) = SRTT * BETA3 */ + +typedef struct L4param /* L4-Parameter */ +{ + UWORD *paradr; /* Adresse des Parameters */ + UWORD minimal; /* Minimalwert */ + UWORD maximal; /* Maximalwert */ + const char *parstr; /* Name des Parameters */ +} L4PARAM; + +extern void ccpL4par(void); /* L4-Parameter setzen/aendern. */ +extern void dump_l4parms(MBHEAD *); /* Param auf Festplatte sichern.*/ + /* L4-Parameter unter */ +extern BOOLEAN RoutesL4Para(MBHEAD *, PEER *); /* ROUTES aendern.*/ +extern void BroadcastBakeClear(PEER *); /* Broadcast-Timer zurueck- */ + /* setzen. */ +extern BOOLEAN OBSinitTimer(PEER *pp); /* Alterungs-Zaehler minimieren.*/ +extern void BroadCastBake(void); /* Broadcast-Nodes Bake senden. */ +extern void bcast(MBHEAD **, char *, UWORD); + +/* L4TIMEOUT */ +extern PEER *SearchTHENET(void); /* Suche THENET-Typ. */ +extern unsigned short SetL4Timeout(void); /* Wenn THENET L4-Timeout setzen, */ + /* ansonsten normal L2-Timeout setzen. */ + +/* L4QUALI */ +extern void dump_routes(MBHEAD *); /* Qualitaet einer Route (nur */ + /* vom Typ THENET) speichern. */ + +/* End of include/l3thenet.h. */ diff --git a/include/l4.h b/include/l4.h new file mode 100755 index 0000000..3967078 --- /dev/null +++ b/include/l4.h @@ -0,0 +1,96 @@ +/************************************************************************/ +/* */ +/* ***** ***** */ +/* ***** ***** */ +/* ***** ***** */ +/* ***** ***** */ +/* *************** *************** */ +/* ***************** ***************** */ +/* *************** *************** */ +/* ***** ***** TheNetNode */ +/* ***** ***** Portable */ +/* ***** ***** Network */ +/* ***** ***** Software */ +/* */ +/* File include/l4.h (maintained by: ???) */ +/* */ +/* This file is part of "TheNetNode" - Software Package */ +/* */ +/* Copyright (C) 1998 - 2008 NORD> Interner Stack / 0 -> OS-Stack */ + + +extern int SetupOS(T_INTERFACE *, /* Aktive Socket's setzen. */ + unsigned short); + +extern int RecvOS(UWORD, fd_set); /* Eingehende TCPIP-Packet bearbeiten. */ + +extern BOOLEAN L1InitOS(UWORD, int, unsigned short); + +extern void L1ExitOS(UWORD); + +extern int PutflushSockOS(void); /* Frame aus der Sendeliste senden. */ + +extern BOOLEAN CloseSockOS(BOOLEAN, /* Schliesse aktuellen Socket. */ + WORD); + +extern BOOLEAN CheckSocketOS(void); /* Pruefe, ob der Socket aktiv ist. */ + +extern void ListenTCP_OS(void); + +extern int AddUserOS(T_INTERFACE *, /* TCP-Interface. */ + unsigned, /* Neuer Socket. */ + char *); /* IP-Adresse. */ + +#endif /* OS_STACK */ + +/* End of include/ostcpip.h */ diff --git a/include/profil.h b/include/profil.h new file mode 100755 index 0000000..d8b363a --- /dev/null +++ b/include/profil.h @@ -0,0 +1,64 @@ + +#define PWSETLEN 17 /* Gesamtlaenge fuer PW-Optionen. */ + +typedef struct ProfTab +{ + const char *name; + LHEAD heardl; + UWORD max; + UWORD act; +} PROFTAB; + +extern PROFTAB proftab; + + +typedef struct prfheard +{ + struct prfheard *next; /* doppelt verkettete Liste */ + struct prfheard *prev; +#ifdef BUFFER_DEBUG + UBYTE owner; /* Muss an 9. Bytestelle stehen */ +#endif + char name[L2IDLEN + 1]; /* Rufzeichen. */ + char nick[NAMESIZE + 1]; /* Nickname. */ + char setpw[PWSETLEN + 1]; /* Aktiviere Passwortabfrage auf den */ + /* gewuenschten Port. */ + char passwd[80 + 1]; /* Passwort. */ +} PRFHEARD; + +typedef struct profcmd /* Profil-Struktur */ +{ + const char *str; /* Befehlsname */ + const char par; /* Zeiger auf Parameter */ +} PROFCMD; + +extern void InitProfilTAB(void); /* TBL Initialisieren. */ +extern void SaveProfil(void); /* TBL-Liste auf Festplatte sichern. */ +extern void ProfilService(CONNECTION *); /* Aktualisiere Profil-Daten. */ + +extern void LoadTableProfil(PROFTAB *); +extern void LoadTableProfil(PROFTAB *); + + +extern void ProfilLoad(CONNECTION *); +extern PRFHEARD *LookupProfil(PROFTAB *, const char *); +extern PRFHEARD *AddProfil(PROFTAB *, const char *); +extern void ccpprofil(void); + +extern PRFHEARD *SearchProfil(const char *); +extern BOOLEAN SearchPasswdProfil(void); +extern void SendPasswdStringProfil(void); + +#define DEFAULT_PASS "12345678901234567890123456789012345678901234567890123456789012345678901234567890" +extern BOOLEAN CheckPasswd(void); +extern TRILLIAN GetPasswd(WORD *, char **, int, char *); +extern void PasswdKodierung(const char *, char *); +extern void PasswdDekodierung(const char *, char *); + + +#ifdef CONVNICK +extern void UpdateNickProfil(PROFTAB *, PRFHEARD *, const char *, const char *); +extern BOOLEAN GetNickname(CONNECTION *); +#endif /* CONVNICK */ + +/* End of include/profil.h. */ diff --git a/include/profiler.h b/include/profiler.h new file mode 100755 index 0000000..43bc226 --- /dev/null +++ b/include/profiler.h @@ -0,0 +1,81 @@ +/************************************************************************/ +/* */ +/* ***** ***** */ +/* ***** ***** */ +/* ***** ***** */ +/* ***** ***** */ +/* *************** *************** */ +/* ***************** ***************** */ +/* *************** *************** */ +/* ***** ***** TheNetNode */ +/* ***** ***** Portable */ +/* ***** ***** Network */ +/* ***** ***** Software */ +/* */ +/* File include/profiler.h (maintained by: DL1XAO) */ +/* */ +/* This file is part of "TheNetNode" - Software Package */ +/* */ +/* Copyright (C) 1998 - 2008 NORD>x?y:x) +#define st_min(x,y) x=(x==0)?(y):(y +#include +#include +#include +#include +#include + +/*---------- Header-Files abhaengig vom Compiler / Betriebssystem ------*/ + +#ifdef __LINUX__ +#include "linclude.h" +#endif + +#ifdef __WIN32__ +#include "winclude.h" +#endif /* WIN32 */ + +#ifdef PC +#include +#if defined(__DOS16__) || defined(__FALCON__) +#include +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#endif + +#ifdef ST +#include +#include +#endif + +/*------------------ Header-Files fuer TNN -----------------------------*/ + +#include "allmodif.h" +#include "all.h" +#include "l2.h" +#include "typedef.h" +#include "l2s.h" +#ifdef __LINUX__ +#include "linux.h" +#endif +#ifdef __WIN32__ +#include "win32.h" +#endif /* WIN32 */ +#include "function.h" +#include "global.h" +#include "l3global.h" +#include "l4.h" +#include "l7.h" +#include "ip.h" +#ifdef IPROUTE +#include "icmp.h" +#include "ipv.h" +#endif +#include "host.h" +#include "stat.h" +#include "profiler.h" +#ifdef SPEECH +#include "speech.h" +#endif +#ifdef USERPROFIL +#include "profil.h" +#endif /* USERPROFIL */ +#ifdef THENETMOD +#include "l3thenet.h" +#endif /* THENETMOD */ +#ifdef ATTACH +#include "l1attach.h" +#endif /* ATTACH */ +#ifdef TCP_STACK +#include "l3sock.h" +#include "l3tcp.h" +#endif /* TCP_STACK. */ +#ifdef L1TCPIP +#include "l1tcpip.h" +#endif /* L1TCPIP. */ +#ifdef OS_STACK +#include "ostcpip.h" +#endif /* OS_STACK. */ + +/* End of include/tnn.h */ diff --git a/include/typedef.h b/include/typedef.h new file mode 100755 index 0000000..eeb722c --- /dev/null +++ b/include/typedef.h @@ -0,0 +1,1127 @@ +/************************************************************************/ +/* */ +/* ***** ***** */ +/* ***** ***** */ +/* ***** ***** */ +/* ***** ***** */ +/* *************** *************** */ +/* ***************** ***************** */ +/* *************** *************** */ +/* ***** ***** TheNetNode */ +/* ***** ***** Portable */ +/* ***** ***** Network */ +/* ***** ***** Software */ +/* */ +/* File include/typedef.h (maintained by: ???) */ +/* */ +/* This file is part of "TheNetNode" - Software Package */ +/* */ +/* Copyright (C) 1998 - 2008 NORD>fp geupdate? */ +#endif + CONNECTION *convers; /* Pointer auf Convers-Struktur */ +#ifdef PACSAT + PACSATBLK *pacsat; /* Zeiger auf den PACSAT-Block */ +#endif + MONBUF *monitor; /* Zeiger auf den Monitor-Filter-Buffer */ + int auditlevel; + char talkcall[11]; + UBYTE status; /* USER-Status */ +#define US_NULL 0 /* leer/dummy */ +#define US_CCP 1 /* CCP-User */ +#define US_CREQ 2 /* Connect-Request */ +#define US_WPWD 3 /* Warte auf Sysop-Passwort */ +#define US_RTXT 4 /* Empfange Textdatei */ +#define US_WBIN 5 /* Warte auf #BIN# */ +#define US_SBIN 6 /* Sende Binaerdaten */ +#define US_RBIN 7 /* Empfange Binaerdaten */ +#define US_CHST 8 /* ConversHost */ +#define US_TALK 9 /* TALK-Mode */ +#define US_DIG 10 /* User muss weitergereicht werden */ +#define US_EXTP 12 /* externes Programm laeuft (Linux) */ +#define US_CQ 13 /* User ruft CQ */ +#define US_WUPW 14 /* warte auf User-Password */ +#ifdef USER_MONITOR +#define US_TRAC 15 /* Ein User Trace auf einen Port. */ +#endif /* USER_MONITOR */ +#ifdef USERPROFIL +#define US_UPWD 16 /* Warte auf User-Passwort */ +#endif /* USERPROFIL */ + +#if defined(__LINUX__) || defined(__WIN32__) + pid_t child_pid; /* PID des Child-Prozesses */ + UWORD child_timeout; /* Timeout */ + int child_fd; /* Filedescriptor des tty-Interfaces */ + BOOLEAN child_iactive; /* interaktive Shell oder nur Single-Command */ +#endif /* LINUX / WIN32 */ + UBYTE sysflg; /* SYSOP Flag */ + UBYTE errcnt; /* CCP Fehlerzaehler */ + UBYTE convflag; /* wenn != 0 soll nicht in den ccp zurueck */ + /* 1 = CVSHOST von aussen 2= CVSHOST von uns */ + UBYTE paswrd[5]; /* gegebene Passwort Stellen */ +#ifdef USER_PASSWORD + UBYTE pwdtyp; /* User-Password Typ */ +#define PW_NOPW 0 /* noch kein Password eingegeben */ +#define PW_USER 1 /* User hat Password eingegeben */ +#endif +#ifdef L1IRC + UWORD IrcMode; /* IRC-Mode markieren. */ +#endif /* L1IRC */ +} USRBLK; + +typedef struct /* Zum Host connectete User */ +{ + char call[L2IDLEN]; /* Call des Users */ + char conflg; /* User ist connected Flag */ + char disflg; /* Flag: Verbindung trennen, wenn Info weg */ + char direction; /* 0 = Conn. von aussen; 1 = Conn. zum Knoten */ + UWORD noacti; /* Timer fuer keine Aktivitaet */ + UWORD inlin; /* eingelaufene Zeilen */ + UWORD outlin; /* auszugebende Zeilen */ + UWORD outsta; /* auszugebende Meldung */ + LHEAD inbuf; /* Listenkopf Eingabebuffer */ + LHEAD outbuf; /* Listenkopf Ausgabebuffer */ +} HOSTUS; + +typedef struct l2_link +{ +#ifdef BUFFER_DEBUG + void *next; + void *prev; + UBYTE owner; /* Muss an 9. Bytestelle stehen */ +#endif + char call[L2IDLEN]; /* Rufzeichen */ + char alias[L2CALEN]; /* Alias */ + char digil[L2VLEN+1]; /* Digiliste */ +/* char digil[2*L2IDLEN+1];*/ /* Digiliste - NUR 2 DIGIS! */ + UWORD port; /* L2-Port */ + UWORD ssid_high; /* SSID oben fuer Flexnet */ +#ifdef LINKSMODINFO +#define INFOSIZE 28 + char info[INFOSIZE + 1]; /* Stationsbeschreibung. */ + +#endif /* LINKSMODINFO */ +#ifdef AUTOROUTING + UWORD ppAuto; /* Fixed/Auto-Route. */ +#endif /* AUTOROUTING */ + +#ifdef PORT_L2_CONNECT_TIME + UWORD sabmtime; /* Intervall fuer SABM */ +#endif +} L2LINK; + +#define NOMODE -1 /* Linkmode ist noch nicht gesetzt/egal */ +#define INP 0 /* Knoten nach INP-Protokoll */ +#define TNN 1 /* neuer TNN-Typ */ +#define THENET 2 /* Nachbar, der nicht auf Messung reagiert */ +#define NETROM 3 /* unser guter alter Netrom */ + /* alles <= NETROM wird als NETROM behandelt! */ +#define FLEXNET 4 /* FlexNet */ +#define LOCAL 5 /* Local */ +#define LOCAL_M 6 /* Local mit Messung */ +#ifdef LINKSMOD_LOCALMOD +#define LOCAL_N 7 /* Local ohne Messung und ohne Weiterleitung an */ + /* den Nachbarn. */ + +#define LOCAL_V 8 /* Local ohne Messung, ohne Weiterleitung und */ + /* versteckt, nur fuer den Sysop sichtbar. */ +#endif /* LINKSMOD_LOCALMOD */ + +#define SSID(x) ((x[L2CALEN]>>1)&0x0F) +#define MAX_SSIDs 16 + +typedef struct /* Weginformation */ +{ + unsigned reported_quality; /* letzte gemeldete Qualitaet */ + unsigned quality; /* letzte empfangene Qualitaet */ + int timeout; /* Timeout (> 0 wenn aktiv) */ + char lt; /* Hops seit dem Ziel */ + char ssid_high; /* oberer SSID-Bereich */ +} ROUTE; + +typedef struct peer /* ein Segment ("Nachbar") */ +{ + ROUTE *routes; /* Liste mit Weginformationen */ + + /* alle Qualitaeten in ms Schritten */ + ULONG quality; /* geglaettete Qualitaet zum Segment */ + ULONG my_quality; /* meine Messung */ + ULONG his_quality; /* seine Messung */ + + BOOLEAN used; /* frei? */ + + BOOLEAN locked; /* feste Route, nicht loeschen */ + int options; + + int num_routes; /* Anzahl der Routen */ + + struct peer *primary; /* Flag: == 0 primaerer Weg */ + /* != 0 der beste Weg dorthin */ + + L2LINK *l2link; /* vorgegebener Link-Weg */ + WORD rtt_time; /* Messintervalle fuer L3RTT */ + ULONG rttstart; /* Laufzeitmessung, Startzeit */ + + LHEAD rxfl; /* Neigbour Frame List */ + + WORD tosend; /* Frames fuer den Nachbarn */ + + LNKBLK *nbrl2l; /* Querverweis zur Level2 Tabelle */ + UBYTE tries; /* Anzahl der Connectversuche */ + char soll_typ; /* Nachbar Typ (soll) */ + char typ; /* Nachbar Typ (ist) */ +#ifdef PROXYFUNC +#define PROXYMASK 64 + BOOLEAN proxy; /* Proxyfunktion fuer diesen Link */ +#endif + BOOLEAN secured; + WORD version; /* TNN-Version */ + UBYTE token; /* Flexnet, wer hat das Token? */ + UWORD brotim; /* Broadcast Timer */ + UWORD maxtime; /* max. gewuenschte Laufzeit */ +#ifdef CONNECTTIME + ULONG contime; /* Connectzeit in Flexnet-Stil. */ +#endif /* CONNECTTIME */ +#ifdef THENETMOD + UWORD obscnt; /* Restlebensdauer fuer Rundspruch. */ + BOOLEAN constatus; /* Connect-Status. */ +#endif /* THENETMOD */ +} PEER; + +typedef struct node /* Nodes-Liste */ +{ + struct node *next; /* doppelt verkettete Liste */ + struct node *prev; + char id[L2IDLEN]; /* Rufzeichen des Nodes */ + char alias[L2CALEN]; /* Alias dieses Zieles */ + ULONG ipa; /* IP-Adresse */ + UBYTE bits; /* Bits fuer Subnet-Maske */ + MBHEAD *options; /* unbekannte INP-Options in Buffer */ + char ssid_high; /* oberer SSID-Bereich */ +} NODE; + +typedef struct network /* ein Netzwerk */ +{ + PEER *peertab; /* Segment-Tabelle */ + NODE *nodetab; /* Nodes-Tabelle */ + LHEAD nodelis; /* sortierte Nodes-Liste */ + int max_peers; /* max. Anzahl der Segmente */ + int num_peers; /* Anzahl der aktiven Segmente */ + int max_nodes; /* max. Anzahl der Nodes */ + int num_nodes; /* Anzahl der aktiven Nodes */ +} NETWORK; + +typedef struct { /* ein Netrom Route Record Eintrag */ +#ifdef __WIN32__ + UBYTE id[L2IDLEN]; + UBYTE lt; +#else + char id[L2IDLEN]; + char lt; +#endif +} NRRLIST; + +typedef struct ptcent /* Patchcord Liste */ +{ + ULONG inforx; /* Empfangene Info-Bytes */ + ULONG infotx; /* Gesendete Info-Bytes */ + ULONG lastrx; /* letzter Stand der Info-Bytes */ + ULONG lasttx; /* letzter Stand der Info-Bytes */ + ULONG contime; /* Connect-Zeit */ + ULONG rxbps; /* Empfangsbaudrate */ + ULONG txbps; /* Sendebaudrate */ + BOOLEAN recflg; /* Nach einem DISCONNECT reconnect in CCP? */ + UID p_uid; /* Partner User-ID */ + USRBLK *ublk; /* Zugehoeriger User-Block (p_uid==CCP_USER) */ + LINKTYP state; /* Ist das der Uplink? */ + UBYTE local; +#define PTC_NORMAL 0 +#define PTC_LOCAL 1 +} PTCENT; /* es gehoeren immer 2 Eintraege zusammen */ + +typedef struct cirblk /* Level 3 Kontrollblock */ +{ + struct cirblk *head; /* doppelt verkettete Liste */ + struct cirblk *tail; + char state; /* Status: 0=leer, 1=ConReq, 2=Con, 3=DisReq */ +#ifdef __WIN32__ + unsigned char idxpar; /* Partner Index */ + unsigned char ideige; /* eigener ID */ + unsigned char idpart; /* Partner ID */ +#else + char idxpar; /* Partner Index */ + char ideige; /* eigener ID */ + char idpart; /* Partner ID */ +#endif /* WIN32 */ + char destca[L2IDLEN]; /* Zielrufzeichen (wenn != myid -> LOCAL) */ + char downca[L2IDLEN]; /* Downlink Call */ + char upcall[L2IDLEN]; /* Uplink Call */ + char window; /* Fenstergroesse */ + char l4rxvs; /* letzte bestaetigte Framenummer */ + char l4vs; /* letzte gesendete Framenummer */ + char l4vr; /* letzte erhaltene Framenummer */ + char l4rs; /* notwendige Antwort: 0=ACK, 1=NAK, 2=NAKweg*/ + UBYTE l4try; /* Transport Versuche */ + char l4flag; /* DISC-req, selbst choked, Partner choked */ + UWORD RTT; /* Round-Trip-Timer (10 ms) */ + UWORD SRTT; /* Smoothed Round Trip Timer */ + /* SRTT = (Alpha x SRTT + RTT)/(Alpha + 1) */ + char RTTvs; /* RTT gestartet bei dieser Framenummer */ + UWORD traout; /* Transport Timeout */ + UWORD acktim; /* Acknowledge Timer */ + UWORD tranoa; /* no-activity-Timeout */ + UWORD numrx; /* empfangene Frames */ + UWORD numtx; /* zu sendende Frames */ + MBHEAD *fragme; /* Fragment eines kommenden Frames */ + char l3node[L2IDLEN]; /* Node-Call fuer diesen Circuit */ + LHEAD mbhdrx; /* Listenkopf empfangene Frames */ + LHEAD mbhdtx; /* Listenkopf zu sendende Frames */ + LHEAD mbhdos; /* Listenkopf: Frames ausserhalb der Folge */ + UWORD ll4txNR; /* last level 4 tx NR (on5zs) */ + char upnod[L2IDLEN]; /* Uplinkknoten */ + char upnodv[L2VLEN+1];/* Digipeaterkette beim Uplink */ +#ifdef NEW_L4 + UBYTE pid; /* aktuelle PID des Links */ +#endif +} CIRBLK; + +typedef struct param /* Parameter */ +{ + UWORD *paradr; /* Adresse des Parameters */ + UWORD minimal; /* Minimalwert */ + UWORD maximal; /* Maximalwert */ + const char *parstr; /* Name des Parameters */ +} PARAM; + +typedef struct command /* Befehls-Struktur */ +{ + const char *cmdstr; /* Befehlsname */ + void (*cmdfun)(const char *); /* auszufuehrende Funktion */ + const char *cmdpar; /* Zeiger auf Parameter */ +} COMAND; +/* WICHTIG!: bei ST gibts eine Struktur COMMAND schon (os-headers) */ + +typedef struct hostcomand /* Funktionen nur fuer Console */ +{ + const char *cmdstr; /* Funktionsname */ + void (*cmdfun)(void); /* auszufuehrende Funktion */ +} HOSTCMD; + +typedef struct statistik /* Fuer Statistik */ +{ + char call[L2IDLEN]; /* Rufzeichen */ + char viacall[L2IDLEN]; /* falls Call nur via gefuehrt wird */ + time_t hfirst; /* zuerst gehoert */ + time_t hlast; /* zuletzt gehoert */ + /* rx = 0, tx = 1 */ + ULONG Bytetotal[2]; /* Anzahl Info+Protokoll Bytes */ + ULONG Byteheader[2]; /* Anzahl Protokoll Bytes */ + ULONG Ino[2]; /* Anzahl I-Frames */ + ULONG RRno[2]; /* Anzahl RR-Frames */ + ULONG REJno[2]; /* Anzahl REJ-Frames */ + ULONG RNRno[2]; /* Anzahl RNR-Frames */ + ULONG SABMno[2]; + ULONG DISCno[2]; + ULONG UAno[2]; + ULONG DMno[2]; + ULONG FRMRno[2]; + ULONG UIno[2]; + ULONG txByterepeated; /* Anzahl wiederholte Infobytes */ +} STAT; + +typedef struct mhtab { /* MHEARD-Tabelle */ + const char *name; + time_t mhstart; + LHEAD heardl; + UWORD max; + UWORD act; +} MHTAB; + +typedef struct mheard /* Direkt am Digi-Standort gehoerte */ +{ /* L2-Frames */ + struct mheard *next; /* doppelt verkettete Liste */ + struct mheard *prev; +#ifdef BUFFER_DEBUG + UBYTE owner; /* Muss an 9. Bytestelle stehen */ +#endif + time_t heard; /* Zeitpunkt des Empfangs */ + ULONG tx_bytes; /* Gesendete Info-Bytes zum User */ + ULONG rx_bytes; /* Empfangene Info-Bytes vom User */ + ULONG tx_rej; /* wieviele rej gesendet ? */ + ULONG rx_rej; /* wieviele empfangen */ + UWORD port; /* TNC, an dem das Frames gehoert wurde */ + char id[L2IDLEN]; /* Rufzeichen */ + char via[L2IDLEN]; /* via einer Station? */ + UWORD damawarn; /* Meckermeldungen/DISC's vom Knoten */ +#ifdef EAX25 + BOOLEAN eax_link; /* Merker: Link unterstuetzt EAX.25 */ +#endif +#ifdef MH_LISTE + WORD flag; /* zuletzt gehoertes Rufzeichen/Port */ +#endif /* anzeigen. */ +} MHEARD; + +typedef struct cqbuf /* Eintrag fuer User im CQ-Modus */ +{ + struct cqbuf *next; /* doppelt verkettete Liste */ + struct cqbuf *prev; +#ifdef BUFFER_DEBUG + UBYTE owner; /* Muss an 9. Bytestelle stehen */ +#endif + char id[7]; /* Rufzeichen */ + UID uid; /* User ID */ + UID p_uid; +} CQBUF; + +typedef struct portinfo /* Alle L1 Parameter fuer einen Port */ +{ + char name[11]; /* Pseudoname des Ports */ + UWORD speed; /* Port Speed (z.Z. nur fuer Vanessa */ + + WORD reset_port; /* Diesen Port resetten ? */ + UWORD nmblks; /* Anzahl Links auf dem Port */ + UWORD nmbstn; /* Anzahl Stationen auf dem Port */ + + UWORD txdelay; /* Txdelay auf diesem Port */ + UWORD mtu; /* Maximum Transmition Units (I-Feld) */ + + UWORD persistance; /* AUTOPAR: Persistance */ + UWORD slottime; /* AUTOPAR: Slottime */ + + UWORD IRTT; /* AUTOPAR: IRTT (T1) */ + UWORD T2; /* AUTOPAR: T2 */ + UWORD retry; /* AUTOPAR: retry */ + + UWORD maxframe; /* MANUELL: maxframe */ + +#ifdef PORT_MANUELL + UWORD paclen; /* MANUELL: Packetlaenge */ + UWORD T3; /* MANUELL: T3_timer */ +#endif /* PORT_MANUELL */ + +#ifdef IPOLL_FRAME + UWORD ipoll_paclen; /* MANUELL: IPOLL-Paecketlaenge */ + UWORD ipoll_retry; /* MANUELL: IPOLL-Retry */ +#endif /* IPOLL_FRAME */ + +#ifdef PORT_L2_CONNECT_TIME + UWORD l2_connect_time; /* Intervall fuer SABM */ +#endif + +#ifdef PORT_L2_CONNECT_RETRY + UWORD l2_connect_retry; /* MANUELL: RETRY fuer LINKAUFBAU */ +#endif + +#ifdef AUTOROUTING +#define L_NOROUTE 0 /* Auto-Routing ausgeschaltet. */ +#define L_THENET 1 /* THENET. */ +#define L_INP 2 /* INP. */ +#define L_FLEXNET 3 /* FLEXNET. */ +#define L_INPFLEX 4 /* INP/THENET/FLEXNET (Vollmodus). */ + + UWORD poAuto; /* MANUELL: Fixed/Auto-Routing. */ +#endif /* AUTOROUTING */ + +#ifdef THENETMOD + UWORD broadcast; /* MANUELL: fuer Broadcast-Nodes Bake. */ +#endif /* THENETMOD */ + +#ifdef EAX25 + UWORD maxframe_eax; /* MANUELL: maxframe bei Extended-AX.25 */ + UWORD eax_behaviour; /* MANUELL: Verhalten des EAX.25 */ +#endif + +#ifdef SETTAILTIME + UWORD tailtime; /* MANUELL: tailtime */ +#endif + + UWORD l1mode; /* Mode-Flags */ +/* Masken fuer den L1-Mode-Parameter */ +#ifdef PORT_SYNRONATION +#define MODE_ss 0x0008 /* Port Synronation */ +#endif +#ifdef PORT_SUSPEND +#define MODE_l 0x0004 /* Port sperren */ +#endif +#define MODE_m 0x0200 /* Multibaud Flag (Kanalkopplung) */ +#define MODE_e 0x0100 /* externer Takt Vanessa */ +#define MODE_d 0x0080 /* Vollduplex */ +#define MODE_r 0x0040 /* externer RX-Takt */ +#define MODE_t 0x0020 /* externer TX-Takt */ +#define MODE_z 0x0010 /* NRZ statt NRZI bei SCC */ +#define MODE_c 0x0002 /* CRC bei KISS, DCD bei SER12 */ +#define MODE_off 0x0001 /* Special: Wenn 1, Kanal abgeschaltet */ +#define CLR_L1MODE(port) portpar[port].l1mode = 0 +#define SET_L1MODE(port,mode) portpar[port].l1mode |= mode + + UWORD l2mode; /* Mode-Flags */ +/* Masken fuer den L2-Mode-Parameter */ +#define MODE_am 0x8000 /* Maxframe-Automatik */ +#define MODE_ds 0x4000 /* DAMA-Slave */ +#define MODE_h 0x2000 /* MH Flag (an=HEARD fuehren/aus) */ +#define MODE_s 0x1000 /* SYSOP Flag (an=nur mit PRIV/aus) */ +#define MODE_a 0x0800 /* DAMA Flag (an/aus) */ +#define MODE_x 0x0400 /* CTEXT Flag (an/aus) */ + +#ifdef EXPERTPARAMETER + UWORD l2autoparam; /* mode flags */ + /* Masken fuer Autoparameter */ +#define MODE_apers 0x8000 /* Persistence-Automatik */ +#define MODE_aslot 0x4000 /* Slottime-Automatik */ +#define MODE_aIRTT 0x2000 /* IRTT-Automatik */ +#define MODE_aT2 0x1000 /* T2-Automatik */ +#define MODE_aretry 0x0800 /* Retry-Automatik */ +#endif + + UWORD l1_tx_timer; /* Verzoegerung fuer Sendertastung */ + int dch; /* Dama-Kanal */ + + int major; + #define NO_MAJOR 0 + int minor; + #define NO_MINOR (-1) + +#ifdef DAMASLAVE + UWORD damaok; /* != 0 ->Port ist DAMA-Slave */ + UWORD sendok; +#endif + +#ifdef USERMAXCON /* != 0 ->max. Anzahl simultaner Connects */ + int maxcon; /* eines Users (fuer alle User gleich) */ +#endif +} PORTINFO; + +#define portenabled(port) (portpar[port].major != NO_MAJOR) + +#define dama(port) (portpar[port].l2mode & MODE_a) +#ifdef DAMASLAVE +#define damaslave(port) (portpar[port].l2mode & MODE_ds) +#define damaslaveon(port) (damaslave(port) && (portpar[port].damaok != 0)) +#endif +#define updmheard(port) (portpar[port].l2mode & MODE_h) +#define sysoponly(port) (portpar[port].l2mode & MODE_s) +#define ctextenabled(port) (portpar[port].l2mode & MODE_x) +#define automaxframe(port) (portpar[port].l2mode & MODE_am) + +#define fullduplex(port) (portpar[port].l1mode & MODE_d) +#define extclock(port) (portpar[port].l1mode & MODE_e) +#define multibaud(port) (portpar[port].l1mode & MODE_m) +#ifdef PORT_SUSPEND +#define port_suspend_enabled(port) (portpar[port].l1mode & MODE_l) +#endif +#ifdef PORT_SYNRONATION +#define port_synronation_enabled(port) (portpar[port].l1mode & MODE_ss) +#endif + + +typedef struct l1modetab { + char ch; + int mode; +} L1MODETAB; + +#define DCDFLAG 0x1 /* Kanal-Zustaende fuer iscd() */ +#define PTTFLAG 0x2 +#define RXBFLAG 0x4 +#define TXBFLAG 0x8 + +#define L1CRES 1 /* Requests fuer l1_ctl() */ +#define L1CCMD 2 +#define L1CTST 3 + +typedef struct portcmd /* Port-Befehls-Struktur */ +{ + const char *cmdstr; /* Befehlsname */ + const char cmdpar; /* Zeiger auf Parameter DB7KG */ +} PORTCMD; + +typedef struct portstat +{ + UWORD reset_count; /* Anzahl der Resets ? */ + + ULONG rx_bytes; /* Anzahl bisher empfangener Bytes */ + ULONG tx_bytes; /* Anzahl bisher gesendeter Bytes */ + + ULONG last_rx; /* letzter Zaehlerstand empfangene Bytes */ + ULONG last_tx; /* letzter Zaehlerstand gesendeter Bytes */ + + ULONG rx_baud; /* Empfangsbaudrate (MAC) */ + ULONG tx_baud; /* Sendebaudrate (MAC) */ + + ULONG rx_overhead; /* empfangener Protokolloverhead */ + ULONG tx_overhead; /* gesendeter Protokolloverhead */ + + UWORD invalid[4]; /* Invalid Frames + 1 in Reserve */ +} PORTSTAT; + +#define INV_FRAME(port, type) portstat[port].invalid[type]++ +#define INVF_ADR 0 /* Addressfehler (L2) */ +#define INVF_ALN 1 /* Addressfeldlaenge (L2) */ +#define INVF_CTL 2 /* Controlfeldfehler (L2) */ + +typedef struct major { /* Layer 1 Geraetestruktur */ + char *name; + int (*istome)(int, char *); + void (*init)(void); + void (*exit)(void); + void (*handle)(void); + void (*ctl)(int, int); + WORD (*dcd)(PORTINFO *); + int (*attach)(int, int, BOOLEAN); + int (*detach)(int); + void (*info)(int, int, MBHEAD *); + void (*timer)(UWORD); +#define HW_INF_IDENT 1 +#define HW_INF_INFO 2 +#define HW_INF_STAT 3 +#define HW_INF_CLEAR 4 +} MAJOR; + +typedef struct devtable { /* Layer 1 Geraeteliste */ + char *name; + int major; /* Major des Treiber nach der reg. */ + int (*reg_func)(void); +} DEVTABLE; +#define REGISTER_DEVICE(a,b) {a,0,b} + +typedef struct suspend /* Liste gesperrter Rufzeichen */ +{ + char call[L2CALEN]; /* gesperrtes Rufzeichen */ + UWORD port; /* Port auf dem gesperrt ist */ + UBYTE okcount; /* Anzahl zulaessiger Links */ +} SUSPEND; + +typedef struct bake +{ + char beades[L2IDLEN]; /* Zielrufzeichen fuer Bake */ + char beadil[L2VLEN+1]; /* Digiliste fuer Bake */ + WORD interval; /* Zeitinterval in Minuten */ + WORD beatim; /* Minuten-Zaehler */ + WORD telemetrie; /* Telemetrie mitsenden */ + char text[80]; /* Bakentext */ +} BEACON; + +typedef struct +{ + char call[L2IDLEN]; /* Rufzeichen incl. SSID */ + char via[L2VLEN+1]; /* VIA-Pfad */ + WORD port; /* Port */ +#ifdef EAX25 + BOOLEAN eax; /* Flag: EAX-Verbindung */ +#endif + char typ; + char nbrcal[L2IDLEN]; + NODE *np; + UID uid; +} DEST; + +typedef union max_buffer /* sizeof() -> groesster Buffer */ +{ + MB mb; + MBHEAD mbhead; + MHEARD mheard; + USRBLK usrblk; + L2LINK l2link; +} MAX_BUFFER; + +#ifdef BUFFER_DEBUG +#define sizeof_MBDATA (sizeof(MAX_BUFFER)-sizeof(UBYTE)-sizeof(void*)*2) +#else +#define sizeof_MBDATA (sizeof(MAX_BUFFER)-sizeof(void*)*2) +#endif + +#ifdef GRAPH +typedef struct tgraphpeak +{ + ULONG max; + ULONG ave; + ULONG min; +} TGRAPHPEAK; + +typedef struct tgraphelement +{ + TGRAPHPEAK hour[GRAPH_STD_ELEMENTS]; + TGRAPHPEAK day [GRAPH_DAY_ELEMENTS]; + TGRAPHPEAK week[GRAPH_WEK_ELEMENTS]; +} TGRAPHELEMENT; + +#ifdef PORTGRAPH +typedef struct tportgraphpeak +{ + ULONG rx; + ULONG tx; +} TPORTGRAPHPEAK; + +typedef struct tportgraphelement +{ + TPORTGRAPHPEAK hour[GRAPH_STD_ELEMENTS]; + TPORTGRAPHPEAK day [GRAPH_DAY_ELEMENTS]; + TPORTGRAPHPEAK week[GRAPH_WEK_ELEMENTS]; +} TPORTGRAPHELEMENT; +#endif + +typedef struct tgraph +{ + BOOLEAN enabled; + int hour_pos; /* Position des aktuellen Elementes */ + int day_pos; + int week_pos; + int hour_slot; /* Anzahl der gespeicherten Werte im akt. Element */ + int day_slot; + int week_slot; + TGRAPHELEMENT circuit; + TGRAPHELEMENT freebuffer; + TGRAPHELEMENT l2link; + TGRAPHELEMENT node; + TGRAPHELEMENT roundpsec; + TGRAPHELEMENT throughput; +#ifdef PORTGRAPH + TPORTGRAPHELEMENT sabm[L2PNUM]; + TPORTGRAPHELEMENT disc[L2PNUM]; + TPORTGRAPHELEMENT dm[L2PNUM]; + TPORTGRAPHELEMENT info[L2PNUM]; + TPORTGRAPHELEMENT reject[L2PNUM]; + TPORTGRAPHELEMENT frmr[L2PNUM]; +#endif +} TGRAPH; +#endif /* ifdef graph */ + +#ifdef MC68302 +struct ftime +{ + unsigned ft_tsec: 5; + unsigned ft_min: 6; + unsigned ft_hour: 5; + unsigned ft_year: 7; + unsigned ft_month: 4; + unsigned ft_day: 5; +}; +#endif + +#ifdef ALIASCMD +#define MAXALIASLEN 8 +#define MAXALIASCMDLEN 16 + +typedef struct cmdalias { + char alias[MAXALIASLEN + 1]; /* Alias */ + char cmd[MAXALIASCMDLEN + 1]; /* auszufuehrendes Kommando */ + struct cmdalias *next; /* pointer to next entry */ +} CMDALIAS; +#endif + +#endif +/* End of include/typedef.h */ diff --git a/makefile b/makefile new file mode 100755 index 0000000..97f2fb8 --- /dev/null +++ b/makefile @@ -0,0 +1,610 @@ +######################################################################## +# # +# ***** ***** # +# ***** ***** # +# ***** ***** # +# ***** ***** # +# *************** *************** # +# ***************** ***************** # +# *************** *************** # +# ***** ***** TheNetNode # +# ***** ***** Portable # +# ***** ***** Network # +# ***** ***** Software # +# # +# File makefile (maintained by: DF6LN) # +# # +# This file is part of "TheNetNode" - Software Package # +# # +# Copyright (C) 1998 - 2006 NORD> MS-DOS GCC Cross-Compiler von J.J. van der Heijden - verfuegbar +# unter sunsite.unc.edu:/pub/Linux/devel/msdos +# +ifeq ($(SYSTEM), LINUX) +# +# Der native gcc dieser Architektur, er wird fuer die Uebersetzung des +# Cleaners benoetigt, da dieser beim Crosscompilieren nicht fuer das Zielsystem, +# sondern fuer den Host compiliert werden muss ! +# +HOSTCC := gcc +# +# Der zum Uebersetzen genutzte Compiler kann beim make-Aufruf uebersteuert werden +# (make CC=gcc-foobar). Ist CC nicht definiert, dann nehmen wir den gcc des Host. +# +# +ifeq ($(CC), "") +CC := gcc +endif +CC_GO32 := gcc-go32 +else +CC_GO32 := gcc +endif +# +# Compiler-Flags +# +# VORSICHT! TNN ist nicht getestet mit eingeschalteten Optimierungen, ausser +# an den notwendigen Stellen (VANESSA). Option -O2 (oder aehnlich) also +# keinesfalls anfuegen. +# +CFLAGS := -funsigned-char $(WARNINGS) +# Wegkommentieren, wenn fuer Pentium uebersetzt werden soll +# CFLAGS += -mcpu=pentium +# Die folgende Zeile wegkommentieren, wenn fuer 386 uebersetzt werden soll +# CFLAGS += -m386 +# Fuer ganz mutige : Compiler-Optimierungen einschalten (siehe oben !!!) +# CFLAGS += -O2 +# Die folgende Zeile kommentieren, wenn keine Debugsymbole gewuenscht sind. +# Noch mehr Debug gibt es mit -g3, weniger mit -g1, -g entspricht -g2. (Linux) +CFLAGS += -g +ifeq ($(SYSTEM), LINUX) +CFLAGS += -pipe -Dstricmp=strcasecmp -Dstrnicmp=strncasecmp +#CFLAGS += -pedantic +#CFLAGS += -O +endif + +CFLAGS += -I$(HDR) -I$(SRC) + +# +# Nun haben wir die gemeinsamen Compiler-Flags fuer GO32 und fuer Linux. +# Eventuell trotz obiger Warnung eingeschaltete Optimierungen werden entfernt. +# Dazu kommen jetzt noch die Systemspezifischen Include-Verzeichnisse und fuer +# die Linux-TNN die von TNN zu verwendenden Verzeichnisse. +# +CFLAGS := $(subst -O ,,$(subst -O2 ,,$(subst -O3 ,,$(CFLAGS)))) +CFLAGS_GO32 := $(CFLAGS) -I$(GO32) +CFLAGS_LIN := $(CFLAGS) -I$(LIN) +CFLAGS_LIN += -DINIPATH=\"$(patsubst %//,%/,$(INSTCFG)/)\" +CFLAGS_LIN += -DTEXTPATH=\"$(TNNDIR)\" +CFLAGS_LIN += -DTEXTCMDPATH=\"$(TNNTEXTCMD)\" +CFLAGS_LIN += -DUSEREXEPATH=\"$(TNNUSEREXE)\" +CFLAGS_LIN += -DSYSEXEPATH=\"$(TNNSYSEXE)\" +CFLAGS_LIN += -DPACSATPATH=\"$(TNNPACSAT)\" +CFLAGS_LIN += -DMSGPATH=\"$(TNNMSG)\" + +# MIPS-Systeme bekommen noch ein besonderes Kennzeichen +ifeq ($(MIPS), YES) +CFLAGS_LIN += -DMIPS=$(MIPS) +endif + +# +# Source-, Header- und Object-Files +# +L3SRC := l3inp.c l3misc.c l3nbr.c l3netrom.c l3thenet.c +L3SRC += l3rtt.c l3tab.c l3var.c l3vc.c +L3TCP += l3sock.c l3tcp.c l1tcpip.c l1telnet.c l1httpd.c l1ipconv.c l1irc.c +COMMONSRC := buffer.c callstr.c cvs_cmds.c cvs_cvsd.c cvs_serv.c +COMMONSRC += cvs_cvrt.c file.c global.c graph.c +COMMONSRC += l2dama.c l2misc.c l2rx.c l2stma.c l2timer.c l2tx.c +COMMONSRC += l3ip.c $(L3SRC) $(L3TCP) l4.c l7.c l7ccp.c l7cmds.c +COMMONSRC += l7conn.c l7host.c l7hstcmd.c l7ip.c l7moni.c +COMMONSRC += l7showl3.c l7time.c l7utils.c main.c mh.c +COMMONSRC += pacsat.c pacserv.c profil.c profiler.c speech.c +VERSRC := $(SRC)/version.c + +LINUXSRCS := $(patsubst %,$(SRC)/%,$(COMMONSRC)) +LINUXSRCS += $(LIN)/init.c $(LIN)/linux.c $(LIN)/l1linux.c +LINUXSRCS += $(LIN)/axipx.c $(LIN)/ax25ip.c $(LIN)/kernelip.c +LINUXSRCS += $(LIN)/kernelax.c $(LIN)/6pack.c +LINUXSRCS += $(LIN)/l1attach.c $(LIN)/ostcpip.c $(LIN)/osipconv.c +LINUXOBJS := $(LINUXSRCS:.c=.o) +VANSRC := $(LIN)/vanlinux.c +VANOBJ := $(LIN)/vanlinux.o +VEROBJL := $(SRC)/version.o +L3SRCS := $(patsubst %,$(SRC)/%,$(L3SRC)) +L3OBJL := $(L3SRCS:.c=.o) + +GO32_SRCS := $(GO32)/api.c $(GO32)/go32.c $(GO32)/16550.c +GO32_SRCS += $(GO32)/l1.c $(patsubst %,$(SRC)/%,$(COMMONSRC)) +GO32_OBJS := $(GO32_SRCS:.c=.obj) +GO32L1 := $(GO32)/extdev.c $(GO32)/kiss.c $(GO32)/loop.c +GO32L1 += $(GO32)/par.c $(GO32)/scc.c $(GO32)/tokenrng.c +GO32L1 += $(GO32)/vanessa.c $(GO32)/kiss.h $(GO32)/vanessa.h +VEROBJG := $(SRC)/version.obj +L3OBJG := $(L3SRCS:.c=.obj) + +HDRNAMS := all.h allmodif.h conversd.h cvs_cmds.h +HDRNAMS += function.h global.h host.h icmp.h ip.h ipv.h l2.h l2s.h +HDRNAMS += l3sock.h l3tcp.h l1httpd.h l1tcpip.h l1telnet.h +HDRNAMS += l3global.h l3thenet.h l4.h l7.h profil.h profiler.h stat.h +HDRNAMS += system.h speech.h tnn.h typedef.h + +LINUXHDRS := $(patsubst %,$(HDR)/%,$(HDRNAMS)) +LINUXHDRS += $(LIN)/linux.h $(LIN)/vanlinux.h $(LIN)/linclude.h +LINUXHDRS += $(LIN)/kernelip.h $(LIN)/kernelax.h $(LIN)/ax25ip.h +GO32HDRS := $(patsubst %,$(HDR)/%,$(HDRNAMS)) $(GO32)/api.h +GO32HDRS += $(GO32)/api32.h $(GO32)/hardware.h $(GO32)/pc.h +L3HDR := $(HDR)/l3local.h + +MAKEFILE := makefile +OTHER1 := alas.txt $(SRC)/config.c $(INI)/ax25ip.cfg +OTHER1 += $(INI)/{tnn179.tnb,tnnini.all} $(L3HDR) +OTHER1 += $(SRC)/cleaner.c $(SRC)/update.c history/*.his +OTHER2 := $(DOC)/{conversd.{xhf,g},tnn179.pdf} +OTHER2 += $(CONTRIB)/makefile + +.SUFFIXES: +.SILENT: +.EXPORT_ALL_VARIABLES: + +.PHONY: all tnn upd tnngo32 updgo32 clean cleaner +.PHONY: mindist dist bigdist install baseinstall + +%.o: %.c $(MAKEFILE) $(CLEANER) + echo -n 'Compiling $@ ' + $(CLEANER) $< + $(CC) -c $(CFLAGS_LIN) -o $@ $< + echo done. + +%.obj: %.c $(MAKEFILE) $(CLEANER) + echo -n 'Compiling $@ ' + $(CLEANER) $< + $(CC_GO32) -c $(CFLAGS_GO32) -o $@ $< + +all: tnn upd + +$(LINUXOBJS): $(LINUXHDRS) $(MAKEFILE) +$(VEROBJL): $(VERSRC) $(LINUXOBJS) $(VANOBJ) +$(VEROBJG): $(VERSRC) $(GO32_OBJS) +$(GO32_OBJS): $(GO32HDRS) $(MAKEFILE) +$(SRC)/global.o: $(SRC)/config.c +$(SRC)/global.obj: $(SRC)/config.c +$(GO32)/l1.obj: $(GO32L1) +$(L3OBJL) $(L3OBJG): $(L3HDR) + +cleaner: $(CLEANER) +tnngo32: $(BIN)/tnngo32 + +ifeq ($(SYSTEM), LINUX) +# +# erstmal kommt Linux +# + +# externe Libs +LIB := -lutil + +.PHONY: go32 _dist _mindist _install + +tnn: $(BIN)/tnn +go32: tnngo32 updgo32 +upd: $(BIN)/upd +updgo32: $(BIN)/updgo32 + +# bin-Verzeichnis erstellen +$(BIN): +ifneq ($(wildcard $(BIN)), $(BIN)) + echo Creating directory $(BIN) + - mkdir $(BIN) +endif + +# Linux VANESSA Treiber +$(VANOBJ): $(MAKEFILE) $(CLEANER) +$(VANOBJ): $(VANSRC) $(LIN)/vanlinux.h $(LINUXHDRS) + echo -n 'Compiling $@ ' + $(CLEANER) $(VANSRC) $(LIN)/vanlinux.h + $(CC) -c -O2 $(CFLAGS_LIN) -o $@ $(VANSRC) + echo done. + +# TNN-Executable linken +$(BIN)/tnn: $(LINUXOBJS) $(VANOBJ) $(VEROBJL) $(CLEANER) + echo -n 'Linking $@ ' + $(CLEANER) $(LINUXHDRS) + $(CC) $(LINUXOBJS) $(VANOBJ) $(VEROBJL) $(LDFLAGS_LIN) $(LIB) -o $@ + echo done. + +# Sourcecode-Cleaner +$(CLEANER): $(SRC)/cleaner.c $(LINUXHDRS) $(MAKEFILE) +ifneq ($(wildcard $(BIN)), $(BIN)) + echo Creating directory $(BIN) + - mkdir $(BIN) +endif + echo -n 'Building $@ ' + $(HOSTCC) $(CFLAGS_LIN) $(SRC)/cleaner.c $(LDFLAGS_LIN) -o $@ + echo done. + +# TNN GO32 +$(BIN)/tnngo32: $(GO32_OBJS) $(VEROBJG) $(CLEANER) + $(CLEANER) $(GO32HDRS) + $(CC_GO32) $(GO32_OBJS) $(VEROBJG) -o $@ + chmod 644 $@ + echo $@ done. + +# Updater +$(BIN)/upd: $(BIN) $(SRC)/update.c $(LINUXHDRS) $(MAKEFILE) + $(CC) $(CFLAGS_LIN) $(SRC)/update.c $(LDFLAGS_LIN) -o $@ + echo $@ done. + +# Updater fuer GO32 +$(BIN)/updgo32: $(BIN) $(SRC)/update.c $(GO32HDRS) $(MAKEFILE) + $(CC_GO32) $(CFLAGS_GO32) $(SRC)/update.c -o $@ + chmod 644 $@ + echo $@ done. + +# Aufraeumen +clean: + rm -f $(LINUXOBJS) $(VANOBJ) $(GO32_OBJS) $(VEROBJL) $(VEROBJG) + rm -f $(NAME).tar.bz2 .macros + rm -f {.,$(SRC),$(LIN),$(INI),$(GO32),$(HDR),$(DOC)}/*~ + rm -f {$(GO32),history}/*~ + rm -f $(BIN)/{cleaner,{upd,tnn}{,go32{,.exe}}} + rm -rf bin +ifeq ("$(findstring 179,$(shell pwd))","179") + rm -rf usr +endif + +TNNINI := $(INI)/tnn.ini +TNNPAS := $(INI)/tnn179.pas +# +# Mit "make mindist" wird der Source verpackt, soweit zum uebersetzen noetig, +# mit "make dist" wird zusaetzlich die Doku verpackt und mit "make bigdist" +# sind auch die Teile im Verzeichnis contrib/ dabei. Hier ist allerdings kein +# Unterschied zu sehen zwischen "dist" und "bigdist", sondern nur in +# contrib/*/makefile. +# +dist bigdist: _mindist +ifeq ("$(findstring 179,$(shell pwd))","179") + cp --parents $(OTHER2) $(DISTDIR) + echo $(NAME).tar.bz2 + tar -cf $(NAME).tar $(DISTDIR) + bzip2 $(NAME).tar + rm -rf usr +else + echo Invalid Directory Name. +endif + +mindist: _mindist +ifeq ("$(findstring 179,$(shell pwd))","179") + echo $(NAME).tar.bz2 + tar -cf $(NAME).tar $(DISTDIR) + bzip2 $(NAME).tar + rm -rf usr +else + echo Invalid Directory Name. +endif + +_mindist: _dist $(TNNINI) $(TNNPAS) + cp --parents $(LINUXSRCS) $(LINUXHDRS) $(VANSRC) $(DISTDIR) + cp --parents $(GO32_SRCS) $(GO32HDRS) $(GO32L1) $(DISTDIR) + cp --parents $(VERSRC) $(MAKEFILE) $(DISTDIR) + cp --parents $(OTHER1) $(DISTDIR) + +_dist: +ifeq ("$(findstring 179,$(shell pwd))","179") + rm -rf usr $(NAME).tar.bz2 + mkdir --parents $(DISTDIR) +else + echo Invalid Directory Name. +endif +# +# install nur fuer Linux-Version - GO32-Version muss von Hand kopiert werden +# +install: all _install + install -m 0700 $(BIN)/tnn $(INSTBIN)/tnn + +_install: + install -m 0700 -d $(TNNDIR) + install -m 0700 -d $(TNNSYSEXE) + install -m 0700 -d $(TNNTEXTCMD) + install -m 0700 -d $(TNNUSEREXE) + install -m 0700 -d $(TNNPACSAT) + install -m 0700 -d $(TNNMSG) + +baseinstall: install $(TNNINI) $(TNNPAS) + install -m 0700 -d $(INSTCFG) + install -m 0600 $(TNNINI) $(INSTCFG)/tnn.ini + install -m 0600 $(INI)/tnnini.all $(TNNDIR)/tnnini.all + install -m 0600 $(INI)/ax25ip.cfg $(TNNDIR)/ax25ip.cfg + install -m 0600 $(TNNPAS) $(TNNDIR)/tnn179.pas + install -m 0600 $(INI)/tnn179.tnb $(TNNDIR)/tnn179.tnb + install -m 0600 $(DOC)/conversd.xhf $(TNNDIR)/conversd.xhf + +$(TNNINI): $(MAKEFILE) + echo $@ + echo "# This is an example for a tnn.ini-file" >$(TNNINI) + echo "# For a more comprehensive example see tnnini.all" >$(TNNINI) + echo "# -----------------------------------------------" >$(TNNINI) + echo "# File permissions for files created by TNN" >$(TNNINI) + echo "# octal value as used by umask(2)" >>$(TNNINI) + echo "# default value = 000 (world readable/writable)" >>$(TNNINI) + echo "# use 077 to limit access to the owner of TNN" >>$(TNNINI) + echo "#perms 077" >>$(TNNINI) + echo "# Working directory for TNN" >$(TNNINI) + echo "#tnn_dir $(TNNDIR)" >>$(TNNINI) + echo "# Unix-Socket for TNT hostmode interface (optional)" >>$(TNNINI) + echo "#tnn_socket $(TNNDIR)tnn-socket" >>$(TNNINI) + echo "# Program to start before using any hardware ports" >>$(TNNINI) + echo "# (optional) - don't use any parameters!" >>$(TNNINI) + echo "#tnn_start kill_other_processes" >>$(TNNINI) + echo "# Number of buffers (optional; default = 10000)" >>$(TNNINI) + echo "buffers 10000" >>$(TNNINI) + echo "# file containing process id (mandatory)" >>$(TNNINI) + echo "tnn_procfile tnn.pid" >>$(TNNINI) + echo "# rounds per second (if missing, default 100)" >>$(TNNINI) + echo "#rounds 200" >>$(TNNINI) + echo "#-------------------------------------------------" >>$(TNNINI) + echo "# device 1" >>$(TNNINI) + echo "device /dev/ttyS0" >>$(TNNINI) + echo "# lockfile for device 1" >>$(TNNINI) + echo "tnn_lockfile /var/lock/LCK..ttyS0" >>$(TNNINI) + echo "# speed on device 1" >>$(TNNINI) + echo "speed 38400" >>$(TNNINI) + echo "# type of KISS on device 1:" >>$(TNNINI) + echo "# 0 = KISS, 1 = SMACK, 2 = RMNC-KISS," >>$(TNNINI) + echo "# 3 = Tokenring (1st device only)," >>$(TNNINI) + echo "# 4 = Vanessa, 5 = SCC, 6 = TF (experimental!)," >>$(TNNINI) + echo "# 7 = IPX (1 IPX port only)," >>$(TNNINI) + echo "# 8 = AX25IP (1 AX25IP port only)" >>$(TNNINI) + echo "# 10 = Kernel-AX.25, 11 = DG1KJD Kernel-AX.25" >>$(TNNINI) + echo "# 12 = 6PACK" >>$(TNNINI) + echo "kisstype 3" >>$(TNNINI) + echo "# L2-Port associated with device 1" >>$(TNNINI) + echo "# use several port lines, if kisstype = 3" >>$(TNNINI) + echo "port 0" >>$(TNNINI) + echo "port 1" >>$(TNNINI) + echo "port 2" >>$(TNNINI) + echo "port 3" >>$(TNNINI) + echo "port 4" >>$(TNNINI) + echo "port 5" >>$(TNNINI) + echo "port 6" >>$(TNNINI) + echo "port 7" >>$(TNNINI) + echo "port 8" >>$(TNNINI) + echo "port 9" >>$(TNNINI) + echo "port 10" >>$(TNNINI) + echo "port 11" >>$(TNNINI) + echo "port 12" >>$(TNNINI) + echo "port 13" >>$(TNNINI) + echo "port 14" >>$(TNNINI) + echo "port 15" >>$(TNNINI) + echo "#-------------------------------------------------" >>$(TNNINI) + echo "# device 2" >>$(TNNINI) + echo "#device /dev/ttyS1" >>$(TNNINI) + echo "# lockfile for device 2" >>$(TNNINI) + echo "#tnn_lockfile /var/lock/LCK..ttyS1" >>$(TNNINI) + echo "# speed on device 2" >>$(TNNINI) + echo "#speed 38400" >>$(TNNINI) + echo "# type of KISS on device 2:" >>$(TNNINI) + echo "# 0 = KISS, 1 = SMACK, 2 = RMNC-KISS," >>$(TNNINI) + echo "# 4 = Vanessa, 5 = SCC, 6 = TF (experimental!)," >>$(TNNINI) + echo "# 7 = IPX (1 IPX port only)," >>$(TNNINI) + echo "# 8 = AX25IP (1 AX25IP port only)" >>$(TNNINI) + echo "# 10 = Kernel-AX.25, 11 = DG1KJD Kernel-AX.25" >>$(TNNINI) + echo "# 12 = 6PACK" >>$(TNNINI) + echo "#kisstype 1" >>$(TNNINI) + echo "# L2-Port associated with device 2" >>$(TNNINI) + echo "#port 1" >>$(TNNINI) + +$(TNNPAS): $(MAKEFILE) + echo $@ + echo "; TheNetNode Configuration File" >$(TNNPAS) + echo ";" >>$(TNNPAS) + echo "; DO NOT CHANGE THE ORDER OF THE CONFIGURATION LINES !" >>$(TNNPAS) + echo "; DO NOT CLEAR ANY LINES !" >>$(TNNPAS) + echo ";" >>$(TNNPAS) + echo "; NET/ROM-Sysop-Password, 80 Characters (01234567890123...)" >>$(TNNPAS) + echo -n "1234567890123456789012345678901234567890" >>$(TNNPAS) + echo "1234567890123456789012345678901234567890" >>$(TNNPAS) + echo ";" >>$(TNNPAS) + echo "; Console Password" >>$(TNNPAS) + echo "Geheim" >>$(TNNPAS) + echo ";" >>$(TNNPAS) + echo "; Node Ident (Test)" >>$(TNNPAS) + echo "Test " >>$(TNNPAS) + echo ";" >>$(TNNPAS) + echo "; Node MyCall (XX0XX)" >>$(TNNPAS) + echo "XX0XX" >>$(TNNPAS) + echo ";" >>$(TNNPAS) + echo "; Workpath, Path to the Help-Files ($(TNNDIR))" >>$(TNNPAS) + echo "; TNN should be started from this path." >>$(TNNPAS) + echo "$(TNNDIR)" >>$(TNNPAS) + echo ";" >>$(TNNPAS) + echo "; Path to the executable Text-Files ($(TNNTEXTCMD))" >>$(TNNPAS) + echo "$(TNNTEXTCMD)" >>$(TNNPAS) + echo ";" >>$(TNNPAS) + echo "; Path to the extern Programs for User ($(TNNUSEREXE))" >>$(TNNPAS) + echo "$(TNNUSEREXE)" >>$(TNNPAS) + echo ";" >>$(TNNPAS) + echo "; Path to the extern Programs only for Sysop ($(TNNSYSEXE))" >>$(TNNPAS) + echo "$(TNNSYSEXE)" >>$(TNNPAS) + echo ";" >>$(TNNPAS) + echo "; Path to the PACSAT-Files ($(TNNPACSAT))" >>$(TNNPAS) + echo "$(TNNPACSAT)" >>$(TNNPAS) + +mac: + $(CC) $(CFLAGS_LIN) -E -dM $(HDR)/tnn.h > .macros + +else +# +# nun kommt Dose +# +tnn: tnngo32 +upd: $(BIN)/updgo32 + +$(BIN): +ifneq ($(wildcard $(BIN)), $(BIN)) + echo $(BIN) + - mkdir $(subst /,\\,$(BIN)) +endif + +clean: + erase $(subst /,\\,$(BIN))\* + erase $(subst /,\\,$(BIN))\*.exe + erase $(subst /,\\,$(SRC))\*.o* + erase $(subst /,\\,$(SRC))\*.bak + erase $(subst /,\\,$(GO32))\*.o* + erase $(subst /,\\,$(GO32))\*.bak + erase $(subst /,\\,$(DOC))\*.bak + erase $(subst /,\\,$(INCLUDE))\*.bak + erase $(subst /,\\,$(HISTORY))\*.bak + +$(BIN)/tnngo32: $(GO32_OBJS) $(VEROBJG) $(CLEANER) + $(CLEANER) $(GO32HDRS) + $(CC_GO32) $(GO32_OBJS) $(VEROBJG) -o $@ + echo $@ done. + +$(CLEANER): $(SRC)/cleaner.c $(GO32HDRS) $(MAKEFILE) +ifneq ($(wildcard $(BIN)), $(BIN)) + echo $(BIN) + - mkdir $(BIN) +endif + $(CC) $(CFLAGS_GO32) $(SRC)/cleaner.c -o $@ + echo $@ done. + +$(BIN)/updgo32: $(BIN) $(SRC)/update.c $(GO32HDRS) $(MAKEFILE) + $(CC) $(CFLAGS_GO32) $(SRC)/update.c -o $@ + echo $@ done. + +mindist dist bigdist install baseinstall: + echo Please update your Operating System. + echo The target $@ is only valid for Linux. + +endif +# +# Die Makefiles in contrib/* sollen auch noch verarbeitet +# werden (wenn vorhanden) +# +MF := $(wildcard contrib/*/makefile) +ifneq ($(strip $(MF)),) +include $(MF) +endif diff --git a/os/go32/16550.c b/os/go32/16550.c new file mode 100755 index 0000000..c1e7d39 --- /dev/null +++ b/os/go32/16550.c @@ -0,0 +1,610 @@ +/************************************************************************/ +/* */ +/* ***** ***** */ +/* ***** ***** */ +/* ***** ***** */ +/* ***** ***** */ +/* *************** *************** */ +/* ***************** ***************** */ +/* *************** *************** */ +/* ***** ***** TheNetNode */ +/* ***** ***** Portable */ +/* ***** ***** Network */ +/* ***** ***** Software */ +/* */ +/* File os/go32/16550.c (maintained by: ???) */ +/* */ +/* This file is part of "TheNetNode" - Software Package */ +/* */ +/* Copyright (C) 1998 - 2008 NORD>base; + + if (!ap->is_16550) { + /********************************************************************* + * <<<<<<<<<<< interrupt function for 8250 and 16450 >>>>>>>>>>>>>>> * + *********************************************************************/ + while ((iir = inportb(IIR)) != 1) { /* while interrup pending */ + switch (iir) { + case 0x04: + /************************************************************* + * interrupt type is - Receiver data available * + * interrupt reset with : read rx buffer register * + ************************************************************/ + /* read data + clear interrupt */ + ap->in_buffer[ap->in_buffer_in++] = inportb(TRX); + if (ap->in_buffer_in == ap->in_buffersize) + ap->in_buffer_in = 0; + break; + + case 0x02: + /************************************************************* + * interrupt type is - Transmitter Holding Registre Empty * + * source int. is - Transmitter Holding Registre Empty * + * interrupt reset with : reading iir if source * + * or write in tx holding register * + ************************************************************/ + if (ap->out_buffer_in != ap->out_buffer_out) { + outportb(TRX, ap->out_buffer[ap->out_buffer_out++]); + if (ap->out_buffer_out == ap->out_buffersize) + ap->out_buffer_out = 0; + } + else + ap->out_aktiv = FALSE; + break; + + case 0x06: + /************************************************************* + * interrupt type is - receiver line status * + * source int is - Overun error or - Parity erorr * + * - framming error or - Break interrupt * + * interrupt reset with : reading the Line Status Register * + ************************************************************/ + ap->in_buffer[ap->in_buffer_in++] = 0xdb; + if (ap->in_buffer_in == ap->in_buffersize) + ap->in_buffer_in = 0; + ap->in_buffer[ap->in_buffer_in++] = 0x00; /* erzeugt Bad Frame*/ + if (ap->in_buffer_in == ap->in_buffersize) + ap->in_buffer_in = 0; + inportb(LSR); /* reset this interupt */ + break; + + case 0x00: + /************************************************************* + * interrupt type is - Modem status (normal never activ) * + * source int is - CTS or DSR or Ring or DCD * + * interrupt reset with : reading Modem Status Register * + ************************************************************/ + inportb(MSR); /* reset interrupt */ + break; + } /* end switch */ + } /* end while */ + } /* end if */ + + else { + /********************************************************************* + * <<<<<<<<<<<<<<<<< interrupt function for 16550 >>>>>>>>>>>>>>>>>> * + ********************************************************************/ + while ((iir = inportb(IIR)&0x8f) != 0x81){ /* while interrup pending */ + switch (iir) { + case 0x84: + case 0x8C: + /************************************************************* + * interrupt type is - Receiver data available (0x84) or * + * - Caractere timeout (0x8C) * + * interrupt reset with : read rx buffer register Drops * + * below the trigger Level (0x84) * + * : read all the caracter in rx buffer * + ************************************************************/ + /* while data ready ? */ + while((inportb(LSR) & 0x01) == 0x01) { + ap->in_buffer[ap->in_buffer_in++] = inportb(TRX); + if (ap->in_buffer_in == ap->in_buffersize) + ap->in_buffer_in = 0; + } + break; + + case 0x82: + /************************************************************* + * interrupt type is - Transmitter Holding Register Empty * + * source int. is - Transmitter Holding Register Empty * + * interrupt reset with : reading iir if source * + * or write in tx holding register * + ************************************************************/ + if (ap->out_buffer_in == ap->out_buffer_out ) + ap->out_aktiv = FALSE; + else { + do { + outportb(TRX, ap->out_buffer[ap->out_buffer_out++]); + if (ap->out_buffer_out == ap->out_buffersize) + ap->out_buffer_out = 0; + } + while((ap->out_buffer_in != ap->out_buffer_out) && (--i > 0)); + } + break; + + case 0x86: + /************************************************************* + * interrupt type is - receiver line status * + * source int is - Overun error or - Parity erorr * + * - framming error or - Break interrupt * + * interrupt reset with : reading the Line Status Register * + ************************************************************/ + ap->in_buffer[ap->in_buffer_in++] = 0xdb; + if (ap->in_buffer_in == ap->in_buffersize) + ap->in_buffer_in = 0; + ap->in_buffer[ap->in_buffer_in++] = 0x00; /* erzeugt Bad Frame */ + if (ap->in_buffer_in == ap->in_buffersize) + ap->in_buffer_in = 0; + inportb(LSR); /* reset this interupt */ + break; + + case 0x80: + /************************************************************* + * interrupt type is - Modem status (normal never activ) * + * source int is - CTS or DSR or Ring or DCD * + * interrupt reset with : reading Modem Status Register * + ************************************************************/ + inportb(MSR); /* reset interrupt */ + break; + + } /* end switch */ + } /* end while int */ + } /* end else 8250 16450 / 16550 */ +} /* end function */ + +void clear_sio(int dev) { + int oldier; + int c = 1; + __com_struct *ap = &asydev[dev]; + register int base; + + base = ap->base; + + /* Empfangs-Overrun loeschen */ + while (inportb(LSR) != 0x60 && (c++ <= 1600)) inportb(TRX); + + /* Interruptfehlerquellen loeschen */ + oldier = inportb(IER); /* alle Interrupts sperren */ + outportb(IER, 0); + + c = 1; + while (inportb(IIR) == 0 && c <= 10) { + if ((inportb(IIR) & 6) == 6) { + inportb(LSR); + eoi(); + } + if ((inportb(IIR) & 4) == 4) { + inportb(TRX); + eoi(); + } + if (inportb(IIR) == 0) { + inportb(MSR); + eoi(); + } + c++; + } + + outportb(IER, oldier); +} + +void clear_rs232(int dev) { + + __com_struct *ap = &asydev[dev]; + register int base; + + if (!ap->active) return; + + base = ap->base; + + clear_sio(dev); + + disable(); /* Int vorsichtshalber abschalten */ + if (ap->is_16550) { + outportb(FCR, 0x87); /* FIFO ON , reset rx and tx FIFO */ + outportb(FCR, 0x81); /* trigger level = 14 bytes */ + } + + do + { + inportb(TRX); /* Datenregister leeren */ + } + while((inportb(LSR) & 0x01) == 0x01); + + ap->in_buffer_in = ap->in_buffer_out = ap->out_buffer_in = + ap->out_buffer_out = 0; + ap->out_aktiv = FALSE; + + enable(); /* int wieder an */ +} + +/*----------------------------------------------------------------------*/ +/* Initialisieren der Schnittstelle, OHNE Baudrate setzen! */ +/* Buffer initialisieren, Interrupt Vektoren setzen */ +/* */ +/* 16550A-FIFO-Bits (Portadresse [Basis+2]) */ +/* ================ */ +/* */ +/* Bit Read: IIR Write: FIFO Control */ +/* --------------------------------------------------- */ +/* 0 Interrupt Pending FIFO enable */ +/* 1 ID-Bit 1 FIFO Reset Receive */ +/* 2 ID-Bit 2 FIFO Reset Transmit */ +/* 3 ID-Bit 3 (Timeout) 0 (im PC/AT) */ +/* 4 0 0 */ +/* 5 0 0 */ +/* 6 FIFO ON (nur 16550A) Trigger Level TL0 */ +/* 7 FIFO ON Trigger Level TL1 */ +/* */ +/* TL1 TL0 Trigger-Level */ +/* 0 0 1 Byte */ +/* 0 1 4 Bytes */ +/* 1 0 8 Bytes */ +/* 1 1 14 Bytes */ +/*----------------------------------------------------------------------*/ +int open_rs232(int dev, int base, int irq, int insize, int outsize) +{ + __com_struct *ap = &asydev[dev]; + + if (ap->active) { + printf("*** WARNING: COM%u is already in use!\n",dev+1); + return(-1); + } + + ap->active = TRUE; + + ap->base = base; + ap->irq = irq; + + clear_sio(dev); + + outportb(FCR, 0x01); /* enable FIFO mode (16550) */ + + printf("--- /dev/COM%u (0x%03X,IRQ%u), UART is ", dev+1, base, irq); + + if ((inportb(FCR) & 0x80) == 0x80) { /* test if FIFO enabled */ + ap->is_16550 = TRUE; + printf("16550A"); + outportb(FCR,0x87); /* FIFO ON, clear rx and tx FIFO */ + } + else { + ap->is_16550 = FALSE; + printf("8250/16450"); + } + + do { + inportb(TRX); /* Datenregister leeren */ + } while((inportb(LSR) & 0x01) == 0x01); + + outportb(LCR, 0x07); /* 8bit + 2 stop, DLAB auf 0 */ + outportb(IER, 0x07); /* Interrupt: Rx, TX, RLS */ + outportb(MCR, 0x08); /* Interrupt frei (out2) */ + + ap->in_buffer_in = ap->in_buffer_out = ap->out_buffer_in = + ap->out_buffer_out = 0; + ap->out_aktiv = FALSE; + + disable(); + allocirq(irq, 0, rs232_int, dev); /* Vektor setzen */ + ap->oldmask = getmask(irq); + maskon(irq); + ap->out_buffer = malloc(ap->in_buffersize = insize); + ap->in_buffer = malloc(ap->out_buffersize = outsize); + enable(); /* Interrupt frei */ + + return(dev); +} + +/*----------------------------------------------------------------------*/ +/* Schnittstelle sperren */ +/*----------------------------------------------------------------------*/ +void close_rs232(int dev) { + __com_struct *ap = &asydev[dev]; + register int base; + + if (!ap->active) return; + + base = ap->base; + clear_sio(dev); + + disable(); + if (!ap->oldmask) maskoff(ap->irq); + outportb(IER, 0x00); /* keine Interrupt Freigabe */ + outportb(MCR, 0x08); /* Out2 sperrt Interrupt */ + if (ap->is_16550) + outportb(FCR,0x00); /* FIFO OFF */ + freeirq(ap->irq); + enable(); +} + +/*----------------------------------------------------------------------*/ +/* Neuer Syntax nach DL1XAO, Implementierung DB7KG: */ +/* Setzt die naechstbeste Baudrate und liefert die gesetzte zurueck. */ +/*----------------------------------------------------------------------*/ +int setbaud(int dev, int argu) { + + __com_struct *ap = &asydev[dev]; + register int base; + int baudtab[] = {12,24,48,96,192,384,576,1152,0}, *i, lsb; + + if (!ap->active) return(0); + + base = ap->base; + + clear_sio(dev); + + for (i = baudtab; *i; i++) + if (argu <= *i) break; + + if (*i) argu = *i; /* wenn mehr als Maximalwert gewuenscht,*/ + else argu = 1152; /* dann begrenzen */ + + lsb = 1152 / argu; /* Teiler berechnen */ + + outportb(LCR, 0x87); /* auf Baudraten Register 2 stop bit */ + outportb(TRX, lsb ); /* LSB Teilerfaktor */ + outportb(IER, 0x00); /* MSB */ + outportb(LCR, 0x07); /* 8 Bit, keine Paritaet, 2 Stop */ + + return(argu); +} + +/*----------------------------------------------------------------------*/ +/* Anzahl der Stopbits setzen */ +/*----------------------------------------------------------------------*/ +void setstopbits(int dev, int stops) +{ + __com_struct *ap = &asydev[dev]; + register int base; + + base = ap->base; + + if (!ap->active) return; + + clear_sio(dev); + if (stops == 2) outportb(LCR, 0x07); /* 8 Bit, keine Paritaet, 2 Stop */ + else outportb(LCR, 0x03); /* 8 Bit, k. Paritaet, 1 Stop */ + clear_sio(dev); +} + +/*----------------------------------------------------------------------*/ +/* Zeichen aus Buffer an Programm liefern */ +/*----------------------------------------------------------------------*/ +int rs232_in(int dev) { + char c; + register __com_struct *ap = &asydev[dev]; + + if (!ap->active) return(-1); + + if (ap->in_buffer_in != ap->in_buffer_out) { + c = ap->in_buffer[ap->in_buffer_out++]; + if (ap->in_buffer_out == ap->in_buffersize) + ap->in_buffer_out = 0; + return(c); + } + return(-1); +} + +/*----------------------------------------------------------------------*/ +/* Zeichen an Schnittstelle geben, ggfs im Buffer speichern */ +/*----------------------------------------------------------------------*/ +void rs232_out(int dev, int c) { + register __com_struct *ap = &asydev[dev]; + + if (!ap->active) return; + + disable(); + if (ap->out_aktiv) { + ap->out_buffer[ap->out_buffer_in++] = c; + if (ap->out_buffer_in == ap->out_buffersize) + ap->out_buffer_in = 0; + } + else { + ap->out_aktiv = TRUE; + outportb(ap->base,c); + } + enable(); +} + +/*----------------------------------------------------------------------*/ +/* Blockweise von der Schnittstelle lesen */ +/*----------------------------------------------------------------------*/ +int rs232_read(int dev, UBYTE *buf, int max) { + register __com_struct *ap = &asydev[dev]; + int n; + + if (!ap->active) return(-1); + + disable(); + for (n = 0; n < max; n++) { + if (ap->in_buffer_in != ap->in_buffer_out) { + *buf++ = ap->in_buffer[ap->in_buffer_out++]; + if (ap->in_buffer_out == ap->in_buffersize) + ap->in_buffer_out = 0; + } else { + enable(); + return(n); + } + } + enable(); + return(n); +} + +/*----------------------------------------------------------------------*/ +/* Speicherblock an Schnittstelle geben, ggfs im Buffer speichern */ +/*----------------------------------------------------------------------*/ +void rs232_write(int dev, UBYTE *start, UBYTE *end) { + register __com_struct *ap = &asydev[dev]; + + if (!ap->active) return; + + disable(); + if (!ap->out_aktiv) { + ap->out_aktiv = TRUE; + outportb(ap->base, *start++); + } + while((end - start) > 0L) { + ap->out_buffer[ap->out_buffer_in++] = *start++; + if (ap->out_buffer_in == ap->out_buffersize) + ap->out_buffer_in = 0; + } + enable(); +} + +/*----------------------------------------------------------------------*/ +/* Status Eingabe */ +/*----------------------------------------------------------------------*/ +int rs232_in_status(int dev) +{ + __com_struct *ap = &asydev[dev]; + + if (!ap->active) return(0); + + return(!(ap->in_buffer_in == ap->in_buffer_out)); +} + +/*----------------------------------------------------------------------*/ +/* Status Eingabe */ +/*----------------------------------------------------------------------*/ +int rs232_out_status(int dev) +{ + __com_struct *ap = &asydev[dev]; + + if (!ap->active) return(0); + +/*#ifndef no_db7kg_fast_and_dirty_hack_for_db0fd + if (ap->out_buffer_in == ap->out_buffer_out) + ap->out_aktiv = FALSE; +#endif*/ + return(ap->out_aktiv); +} + +void init_rs232(void) +{ + int i; + + for (i = 0; i < MAXCOMS; i++) + asydev[i].active = FALSE; +} + +void exit_rs232(void) +{ + int i; + + for (i = 0; i < MAXCOMS; i++) + if (asydev[i].active) + close_rs232(i); +} + +/*----------------------------------------------------------------------*/ + +/* End of os/go32/16550.c */ diff --git a/os/go32/api.c b/os/go32/api.c new file mode 100755 index 0000000..6da9cd8 --- /dev/null +++ b/os/go32/api.c @@ -0,0 +1,223 @@ +/************************************************************************/ +/* */ +/* ***** ***** */ +/* ***** ***** */ +/* ***** ***** */ +/* ***** ***** */ +/* *************** *************** */ +/* ***************** ***************** */ +/* *************** *************** */ +/* ***** ***** TheNetNode */ +/* ***** ***** Portable */ +/* ***** ***** Network */ +/* ***** ***** Software */ +/* */ +/* File os/go32/api.c (maintained by: ???) */ +/* */ +/* This file is part of "TheNetNode" - Software Package */ +/* */ +/* Copyright (C) 1998 - 2008 NORD> +#include +#include "api.h" +#include "api32.h" + +char manifest[20]; +unsigned dev_irq = 0; +__dpmi_raddr tx_rframe; +L1FRAME tx_pframe; + +/* Anzahl der Kanaele holen */ +int l1_enum_ports(void) +{ + __dpmi_regs r; + + if (dev_irq == 0) return(0); + r.x.ax = API32_ENUM_PORTS; + __dpmi_int(dev_irq+1, &r); + return(r.x.ax); +} + +/* einen Kanal initialisieren */ +int l1_init_port(unsigned port, unsigned baud, unsigned mode) +{ + __dpmi_regs r; + + if (dev_irq == 0) return(0); + r.x.ax = API32_INIT_PORT; + r.x.bx = port & 0xFFFF; + r.x.cx = baud & 0xFFFF; + r.x.dx = mode & 0xFFFF; + __dpmi_int(dev_irq+1, &r); + return(r.x.ax); +} + +/* das naechste Frame empfangen */ +void *l1_rx_frame(void) +{ + static L1FRAME frame_buf; + __dpmi_regs r; + + if (dev_irq == 0) return(NULL); + r.x.ax = API32_RX_FRAME; + __dpmi_int(dev_irq+1, &r); + if (r.x.ax) { + dosmemget((((int)r.x.es)<<4)+r.x.bx,sizeof(L1FRAME),&frame_buf); + return(&frame_buf); + } + return(NULL); +} + +/* einen Sende-Buffer holen */ +L1FRAME far *l1_get_txbuf(unsigned port) +{ + __dpmi_regs r; + + if (dev_irq == 0) return(NULL); + r.x.ax = API32_GET_TXBUF; + r.x.bx = port & 0xFFFF; + __dpmi_int(dev_irq+1, &r); + if (r.x.ax) { /* Buffer bekommen */ + tx_rframe.segment = r.x.es; + tx_rframe.offset16 = r.x.bx; + return(&tx_pframe); + } + return(NULL); +} + +/* den Sender anstossen */ +void l1_kick(void) +{ + __dpmi_regs r; + + if (dev_irq == 0) return; + dosmemput(&tx_pframe,sizeof(L1FRAME), + ((int)tx_rframe.segment<<4)+tx_rframe.offset16); + r.x.ax = API32_KICK; + __dpmi_int(dev_irq+1, &r); +} + +/* Calibrierung durchfuehren */ +void l1_calibrate(unsigned port, unsigned minutes) +{ + __dpmi_regs r; + + if (dev_irq == 0) return; + r.x.ax = API32_CALIBRATE; + r.x.bx = port & 0xFFFF; + r.x.cx = minutes & 0xFFFF; + __dpmi_int(dev_irq+1, &r); +} + +/* den Kanal-Status abfragen */ +unsigned l1_state(unsigned port) +{ + __dpmi_regs r; + + if (dev_irq == 0) return(0); + r.x.ax = API32_STATE; + r.x.bx = port & 0xFFFF; + __dpmi_int(dev_irq+1, &r); + return(r.x.ax); +} + +/* den Hardwarenamen eines Kanals holen */ +char far *l1_ident(unsigned port) +{ + static char ident[20]; + __dpmi_regs r; + + if (dev_irq == 0) return(NULL); + r.x.ax = API32_IDENT; + r.x.bx = port & 0xFFFF; + __dpmi_int(dev_irq+1, &r); + dosmemget((((int)r.x.es)<<4)+r.x.bx, 20, ident); + return(ident); +} + +/* ist dieser Kanal aktiv? */ +int l1_active(unsigned port) +{ + __dpmi_regs r; + + if (dev_irq == 0) return(0); + r.x.ax = API32_ACTIVE; + r.x.bx = port & 0xFFFF; + __dpmi_int(dev_irq+1, &r); + return(r.x.ax); +} + +/* die L1-Statistik lesen bzw loeschen */ +L1STATISTICS far *l1_stat(unsigned port, int del) +{ + static L1STATISTICS pstat; + __dpmi_regs r; + + if (dev_irq == 0) return(NULL); + r.x.ax = API32_STAT; + r.x.bx = port & 0xFFFF; + r.x.cx = del & 0xFFFF; + __dpmi_int(dev_irq+1, &r); + dosmemget(((int)r.x.es<<4)+r.x.bx, sizeof(L1STATISTICS), &pstat); + return(&pstat); +} + +int find_devirq(void) +{ + unsigned irq; + __dpmi_raddr p; + + for (irq = 0x60; irq <= 0xF0; irq++) { /* freien IRQ suchen */ + __dpmi_get_real_mode_interrupt_vector(irq, &p); + if (p.segment) { + dosmemget((((int)p.segment)<<4)+p.offset16, 20, manifest); + if (strncmp(manifest,"FlexNet",7)==0) + { /* schon installiert */ + dev_irq = irq; + return(1); + } + } + } + return(0); +} + +#endif + +/* End of os/go32/api.c */ diff --git a/os/go32/api.h b/os/go32/api.h new file mode 100755 index 0000000..59d1fa6 --- /dev/null +++ b/os/go32/api.h @@ -0,0 +1,145 @@ +/************************************************************************/ +/* */ +/* ***** ***** */ +/* ***** ***** */ +/* ***** ***** */ +/* ***** ***** */ +/* *************** *************** */ +/* ***************** ***************** */ +/* *************** *************** */ +/* ***** ***** TheNetNode */ +/* ***** ***** Portable */ +/* ***** ***** Network */ +/* ***** ***** Software */ +/* */ +/* File include/api.h (maintained by: ???) */ +/* */ +/* This file is part of "TheNetNode" - Software Package */ +/* */ +/* Copyright (C) 1998 - 2008 NORD>data, fp->len))->l2port = fp->port; + relink((LEHEAD *)rxfhd, (LEHEAD *)rxfl.tail); + } + + for (port = 0; port < L2PNUM; port++, l2flp++) {/* Ports durchsehen */ + p = &portpar[port]; /* ob etwas zu senden ist */ + if (p->major != ext_major) continue; + if(kick[port]) { + state = ext_state(port); /* Port-Zustand holen */ + if (fullduplex(port)) state |= CH_FDX; + if (((state & CH_FDX) == 0) && + ((state & CH_PTT) == 0)) { /* Sender noch nicht an */ + if (p->l1_tx_timer > ticks) { + p->l1_tx_timer -= ticks; + } else { + if ((state & CH_DCD) || + (state & CH_RXB) || + (rand()%256>p->persistance)) + p->l1_tx_timer = p->slottime; + else + p->l1_tx_timer = 0; + } + } else p->l1_tx_timer = 0; + + if (p->l1_tx_timer == 0) { + if ((fp = l1_get_txbuf(port)) != NULL) { + fp->len = 0; + fp->port = port; + fp->txdelay = portpar[port].txdelay; + ulink((LEHEAD *)(txfhdl = (MBHEAD *) l2flp->head));/*Zeiger holen*/ + if (txfhdl->mbpc < 400) + fp->len = cpymbflat(fp->data, txfhdl); + relink((LEHEAD *)txfhdl, /* als gesendet betrachten und in */ + (LEHEAD *)stfl.tail); /* die gesendet Liste umhaengen */ + kick[port] = ((LHEAD *)l2flp->head != l2flp); + l1_kick(); + } + } + } + } +} + +static WORD ext_dcd(PORTINFO *port) +{ + int state = 0; + int hw_state; + + hw_state = l1_state(port->minor); + if (hw_state & CH_DCD) /* DCD an, kein Duplex, nicht */ + state |= DCDFLAG; /* senden */ + if (hw_state & CH_RXB) /* Daten im empfaenger, nicht */ + state |= RXBFLAG; /* senden (auch bei Duplex) */ + /* der externe Treiber sagt uns, wann die PTT wirklich an ist + und nicht wann das letzte Zeichen raus ist, das ist fuer + Duplex nicht zu gebrauchen, dafuer ist hier aber auch die + Verzoegerung zwischen uebergabe an stfl und Sendung nicht + so gross */ + if (hw_state & CH_PTT) /* PTT an, kein Duplex, warten*/ + state |= PTTFLAG; /* bis PTT aus */ + return(state); +} + +/* Durch die feste Bindung minor=port ist die Pruefung auf Doppelbelegung */ +/* nicht notwendig. Man koennte das aendern, aber das verwirrt dann ganz */ +/* schoen, wenn die Ports nicht in Ladereihenfolge genommen werden. */ +static int ext_attach(int port, int unused_devnr, BOOLEAN check_only) +{ + if (dev_irq > 0) + if (port < l1_enum_ports()) { + if (!check_only) + portpar[port].minor = port; + return(1); + } + return(0); +} + +static void ext_info(int what, int port, MBHEAD *mbp) +{ + char str[11]; + L1STATISTICS *stat; + int cnt; + + switch (what) { + case HW_INF_IDENT : + putstr("EXTDEV", mbp); + break; + case HW_INF_INFO : + strncpy(str, l1_ident(port), 10); + str[10] = 0; /* maximal 10 Zeichen */ + putstr(str, mbp); + break; + case HW_INF_STAT : + for (port = cnt = 0; port < l1_enum_ports(); port++) + if (portpar[port].major == ext_major) { + if (cnt++ == 0) + putstr("\rExternal-Statistics:\r\r", mbp); + stat = l1_stat(port, 0); + putprintf(mbp, " %-10.10s TxErr: %5lu RxOvr: %5lu OFlow: %5lu IOErr: %5lu\r", + l1_ident(port), + stat->tx_error, stat->rx_overrun, stat->rx_bufferoverflow, + stat->io_error); + } + break; + case HW_INF_CLEAR : + l1_stat(port, 1); + /* durchfallen */ + default : + default_l1info(what, port, mbp); + } +} + +static void ext_ctl(int req, int port) +{ + switch (req) { + case L1CCMD : + case L1CRES : + l1_init_port(port, portpar[port].speed, portpar[port].l1mode); + break; + } + default_l1ctl(req, port); /* Flags loeschen */ +}; + +static int register_extdev(void) +{ + MAJOR *m; + + if (find_devirq()) { /* Externes Interface suchen */ + m = register_major(); + m->name = "EXTDEV"; + m->dcd = ext_dcd; + m->attach = ext_attach; + m->info = ext_info; + m->timer = ext_timer; + m->ctl = ext_ctl; + return(ext_major = num_major); + } + return(0); +} + +/* End of os/go32/extdev.c */ diff --git a/os/go32/go32.c b/os/go32/go32.c new file mode 100755 index 0000000..5cbb128 --- /dev/null +++ b/os/go32/go32.c @@ -0,0 +1,764 @@ +/************************************************************************/ +/* */ +/* ***** ***** */ +/* ***** ***** */ +/* ***** ***** */ +/* ***** ***** */ +/* *************** *************** */ +/* ***************** ***************** */ +/* *************** *************** */ +/* ***** ***** TheNetNode */ +/* ***** ***** Portable */ +/* ***** ***** Network */ +/* ***** ***** Software */ +/* */ +/* File os/go32/go32.c (maintained by: ???) */ +/* */ +/* This file is part of "TheNetNode" - Software Package */ +/* */ +/* Copyright (C) 1998 - 2008 NORD> +#include +#include +#include + +#define WATCH_TIME 6000 /* ca.5 Minuten Timeout */ +#define PIC 0x20 /* Interrupt-Controller */ +#define PIT 0x40 /* Timer Port 0 */ + +int _crt0_startup_flags = _CRT0_FLAG_LOCK_MEMORY; +unsigned int_level = 0; +int GNU32BUFFERS = 5000; +char *dbg_module = ""; +int tim_factor; +int conscom = -1; /* Schnittstellen-Handle fuer Console */ +int portadress = 0; +static int oldtimer = 0; +FILE *aus; /* Fuer den Wachhund */ +char debugfile[MAXPATH]; +WORD watchdog; /* wurde schon mal extern deklariert */ +static BOOLEAN flag = TRUE; +struct tm *zeit; + +/**************************************************************************/ +/* vsnprintf fuer DOSe DG8BR */ +/*------------------------------------------------------------------------*/ +int vsnprintf(char *str, int NOTIFYVSNPFBUFF, const char *format, va_list arg_ptr) +{ + char str2[4096]; + int n = 0; + + if (vsprintf(str2, format, arg_ptr) == EOF) + return(EOF); + + if ((n = strlen(str2)) > NOTIFYVSNPFBUFF) + return(n); + + strncpy(str, str2, NOTIFYVSNPFBUFF); + return(n); +} + +/**************************************************************************/ +/* */ +/*------------------------------------------------------------------------*/ +void randomize(void) +{ +} + +/**************************************************************************/ +/* */ +/*------------------------------------------------------------------------*/ +unsigned long coreleft(void) +{ + return(_go32_dpmi_remaining_physical_memory()); +} + +/**************************************************************************/ +/* */ +/*------------------------------------------------------------------------*/ +BOOLEAN ishput(void) +{ + return(conscom == -1 ? FALSE : rs232_out_status(conscom)); +} + +/**************************************************************************/ +/* */ +/*------------------------------------------------------------------------*/ +BOOLEAN ishget() +{ + if (kbhit()) + { + if (ishmod) + hgetc(); /* im Hostmode Console ignorieren */ + else + return(TRUE); /* im Terminalmode melden, dass was da ist */ + } + if (conscom != -1) + return(rs232_in_status(conscom)); + return(FALSE); /* keine Umleitung, also auch nix da */ +} + +/**************************************************************************/ +/* */ +/*------------------------------------------------------------------------*/ +char hgetc(void) +{ + #define Prefix 0 + #define ALT_X '-' + char retval; + + if (kbhit()) { + if ((retval = getch()) == Prefix) + if (getch() == ALT_X) + quit_program(0); + return(retval); + } + if (conscom != -1) + if (rs232_in_status(conscom)) + return(rs232_in(conscom)); + return(0); +} + +/**************************************************************************/ +/* */ +/* Zeichen an die Console ausgeben. Wenn eine Umleitung besteht, das */ +/* Zeichen zusaetzlich noch dort ausgeben. Auf die PC-Console wird im */ +/* Hostmode nichts geschrieben. */ +/* */ +/*------------------------------------------------------------------------*/ +void hputc(char c) +{ + if (!ishmod) { /* keine Ausgaben im Hostmode */ + if (c == CR) /* nur fuer PC/Console notwenig! */ + putchar('\n'); + else + putchar(c); + } + if (conscom != -1) + rs232_out(conscom, c); +} + +/**************************************************************************/ +/* */ +/*------------------------------------------------------------------------*/ +BOOLEAN init_hardware(int argc, char *argv[]) +{ + char *tz_string; + int baseadress[3]; + int lpt = 0; + + #define MEMORY_NEEDED (GNU32BUFFERS*sizeof(MAX_BUFFER)) + + randomize(); + + if (getenv("TNN32BUFFERS") != NULL) + sscanf(getenv("TNN32BUFFERS"), "%u", &GNU32BUFFERS); + + if (getenv("TOGGLEPORT") != NULL) + { + sscanf(getenv("TOGGLEPORT"), "%u", &lpt); + + baseadress[0] = _farpeekw(_dos_ds,0x0040*16 + 0x08); /* LPT 1 */ + baseadress[1] = _farpeekw(_dos_ds,0x0040*16 + 0x0a); /* LPT 2 */ + baseadress[2] = _farpeekw(_dos_ds,0x0040*16 + 0x0c); /* LPT 3 */ + portadress = baseadress[lpt -1]; + printf("\nfound LPT at $%x.\n",portadress); + portadress = portadress + 2; /* getoggelt wird 2 hoeher */ + toggle_lpt(); /* schon mal schalten, sonst werden es 2 Minuten */ + } + if ((RAMBOT = (char *) calloc(1,MEMORY_NEEDED)) == NULL) + { + printf("\n\007\n*** WARNING: Not enough memory !\n\n"); + exit(-1); + } + + RAMTOP = RAMBOT + MEMORY_NEEDED; + + /**********************************************************************/ + /* Komandozeile auswerten */ + /**********************************************************************/ + if (argc > 1) hputs("*** WARNING: Parameters ignored"); + + /**********************************************************************/ + /* Systemzeit und Zeitberechung initialisieren */ + /**********************************************************************/ + tz_string = getenv("TZ"); /* Feststellen, ob TimeZone */ + if (tz_string == NULL) { /* gesetzt ist, sonst */ + putenv("TZ=UTC0"); /* mit UTC0 vorbelegen */ + puts("*** WARNING: Timezone set to UTC"); + } + tzset(); /* Zeitzone auswerten */ + + consfile = stdout; + + return(FALSE); +} + +/**************************************************************************/ +/* */ +/*------------------------------------------------------------------------*/ +void init_console(void) +{ + int dev,adr,irq,bd; + + read_envcom("CONSOLE", &dev, &adr, &irq); + if (dev != -1) { + conscom = open_rs232(dev,adr,irq,512,512); + bd = setbaud(conscom, 192); + xprintf(" setting to %u00 8N1.\n", bd); + xprintf("--- CONSOLE attached to /dev/COM%u\n", dev+1); + } +} + +/**************************************************************************/ +/* */ +/*------------------------------------------------------------------------*/ +void exit_console(void) +{ + if (conscom != -1) + close_rs232(conscom); +} + +/**************************************************************************/ +/* Uebergabe von Daten an die Shell (nur Linux) */ +/*------------------------------------------------------------------------*/ +BOOLEAN l7tosh(MBHEAD *mbp) +{ + return(FALSE); +} + +/**************************************************************************/ +/* Shell-Server (nur Linux) */ +/*------------------------------------------------------------------------*/ +void shellsrv(void) +{ +} + +/**************************************************************************/ +/* Ausfuehren einer neuen Software */ +/*------------------------------------------------------------------------*/ +void tnnexec(char *file) +{ + char filename[MAXPATH+1]; + + strncpy(filename, file, MAXPATH); + filename[MAXPATH] = 0; + if (xaccess(filename,0)==0) { + l1exit(); + /* bei DOS16 -> done_umb() */ + exit_timer(); + exit_hardware(); + execl(filename, filename, NULL); + perror("EXEC"); + HALT("tnnexec"); + } +} + +/**************************************************************************/ +/* Ausfuehren eines Befehls */ +/*------------------------------------------------------------------------*/ +BOOLEAN tnnshell(char *cmdline) +{ + char cmd[MAXPATH+MAXPATH+2], *name; + + strncpy(cmd, cmdline, MAXPATH); + cmd[MAXPATH] = 0; + name = tempnam(textpath, "sh"); + if (name) { + strcat(cmd, " > "); + strcat(cmd, name); + system(cmd); + strcpy(cmdline, normfname(name)); + free(name); + } else cmdline[0] = 0; + + return(FALSE); +} + +/**************************************************************************/ +/* Hardware deinitialisieren */ +/*------------------------------------------------------------------------*/ +void exit_hardware() +{ + free((void *) RAMBOT); +} + +/**************************************************************************/ +/* System neu starten (GNU32 -> Beenden und Rechner neu starten) */ +/*------------------------------------------------------------------------*/ +void reboot_system() +{ + __dpmi_regs r; + l1exit(); + + r.x.ax = 47; /* Pointer setzen */ + r.x.cs = 0xffff; /* Segment im DOS */ + r.x.ip = 0x0000; /* Offset im DOS */ + r.x.ss = r.x.sp = 0; /* Sollen laut DPMI auf 0 stehen */ + __dpmi_simulate_real_mode_procedure_retf(&r); /* Kaltstartroutine */ +} + +/**************************************************************************/ +/* An LPT1 den Pin 16(RESET) toggeln. Hardware-Watchdog */ +/**************************************************************************/ +void +toggle_lpt (void) +{ + if (portadress != 0) + { + if (flag) + { + writebit(portadress, 0x04, 1); /* Pin 16 einschalten */ + flag = FALSE; + } + else + { + writebit(portadress, 0x04, 0); /* Pin 16 ausschalten */ + flag = TRUE; + } + } +} + +/**************************************************************************/ +/* Wenn moeglich Interrupts wieder freigeben */ +/*------------------------------------------------------------------------*/ +void decEI(void) +{ + if (--int_level == 0) + enable(); +} + +/**************************************************************************/ +/* Interrupts sperren in kritischen Bereichen. */ +/*------------------------------------------------------------------------*/ +void DIinc(void) +{ + int_level++; + disable(); +} + +/* Disable hardware interrupt */ +int +maskoff(unsigned irq) +{ + if (irq < 8) + { + setbit(0x21, (char)(1 << irq)); + } + else + if (irq < 16) + { + irq -= 8; + setbit(0xa1, (char)(1 << irq)); + } + else + { + return(-1); + } + return(0); +} + +/* Enable hardware interrupt */ +int +maskon(unsigned irq) +{ + if (irq < 8) + { + clrbit(0x21, 1 << irq); + } + else + if (irq < 16) + { + irq -= 8; + clrbit(0xa1, 1 << irq); + } + else + { + return(-1); + } + return(0); +} + +/* Return 1 if specified interrupt is enabled, 0 if not, -1 if invalid */ +int +getmask(unsigned irq) +{ + if (irq < 8) + return((inportb(0x21) & (1 << irq)) ? 0 : 1); + else + if (irq < 16) + { + irq -= 8; + return((inportb(0xa1) & (1 << irq)) ? 0 : 1); + } + else + return(-1); +} + +/* Set bit(s) in I/O port */ +void +setbit(unsigned port, unsigned char bits) +{ + outportb(port, inportb(port) | bits); +} + +/* Clear bit(s) in I/O port */ +void +clrbit(unsigned port, unsigned char bits) +{ + outportb(port, inportb(port) & ~bits); +} + +/* Set or clear selected bits(s) in I/O port */ +void +writebit(unsigned port, unsigned char mask, int val) +{ + unsigned char x; + + x = inportb(port); + if (val) + x |= mask; + else + x &= ~mask; + outportb(port, x); +} + +struct int_tab +{ + __dpmi_paddr old; /* Previous handler at this vector */ + _go32_dpmi_seginfo new; /* Current handler, with wrapper info */ + void (*func)(int); /* Function to call on interrupt */ + int arg; /* Arg to pass to interrupt function */ + int chain; /* Is interrupt chained to old handler? */ +} Int_tab[16]; + +/* What a crock. All this inelegance should be replaced with something + * that figures out what interrupt is being serviced by reading the 8259. + */ +static void +irq0(void) +{ + eoi(); + (*Int_tab[0].func)(Int_tab[0].arg); +} + +static void +irq1(void) +{ + eoi(); + (*Int_tab[1].func)(Int_tab[1].arg); +} + +static void +irq2(void) +{ + eoi(); + (*Int_tab[2].func)(Int_tab[2].arg); +} + +static void +irq3(void) +{ + eoi(); + (*Int_tab[3].func)(Int_tab[3].arg); +} + +static void +irq4(void) +{ + eoi(); + (*Int_tab[4].func)(Int_tab[4].arg); +} + +static void +irq5(void) +{ + eoi(); + (*Int_tab[5].func)(Int_tab[5].arg); +} + +static void +irq6(void) +{ + eoi(); + (*Int_tab[6].func)(Int_tab[6].arg); +} + +static void +irq7(void) +{ + eoi(); + (*Int_tab[7].func)(Int_tab[7].arg); +} + +static void +irq8(void) +{ + eoi(); + (*Int_tab[8].func)(Int_tab[8].arg); +} + +static void +irq9(void) +{ + eoi(); + (*Int_tab[9].func)(Int_tab[9].arg); +} + +static void +irq10(void) +{ + eoi(); + (*Int_tab[10].func)(Int_tab[10].arg); +} + +static void +irq11(void) +{ + eoi(); + (*Int_tab[11].func)(Int_tab[11].arg); +} + +static void +irq12(void) +{ + eoi(); + (*Int_tab[12].func)(Int_tab[12].arg); +} + +static void +irq13(void) +{ + eoi(); + (*Int_tab[13].func)(Int_tab[13].arg); +} + +static void +irq14(void) +{ + eoi(); + (*Int_tab[14].func)(Int_tab[14].arg); +} + +static void +irq15(void) +{ + eoi(); + (*Int_tab[15].func)(Int_tab[15].arg); +} + +static void (*Vectab[16])(void) = +{ + irq0, irq1, irq2, irq3, irq4, irq5, irq6, irq7, + irq8, irq9, irq10, irq11, irq12, irq13, irq14, irq15 +}; + +int +allocirq(unsigned irq, int chain, void (*func)(int), int arg) +{ + struct int_tab *ip; + unsigned char intno; + int i; + + if (irq > 15) + return(-1); /* IRQ out of legal range */ + + ip = &Int_tab[irq]; + if (ip->func != NULL) + return(-1); /* Already in use */ +/* Convert irq to actual CPU interrupt vector */ + intno = (irq < 8) ? irq + 8 : 0x70 + irq - 8; + + __dpmi_get_protected_mode_interrupt_vector(intno, &ip->old); + ip->func = func; + ip->arg = arg; + ip->new.pm_offset = (int)Vectab[irq]; + ip->new.pm_selector = _go32_my_cs(); + ip->chain = chain; + + if (chain) + return(_go32_dpmi_chain_protected_mode_interrupt_vector(intno, &ip->new)); + + if ((i = _go32_dpmi_allocate_iret_wrapper(&ip->new)) != 0) + return(i); + return(_go32_dpmi_set_protected_mode_interrupt_vector(intno, &ip->new)); +} + +int +freeirq(unsigned irq) +{ + struct int_tab *ip; + int i; + + if (irq > 15) + return(-1); /* IRQ out of legal range */ + + ip = &Int_tab[irq]; + ip->func = NULL; +/* Convert irq to actual CPU interrupt vector */ + irq = (irq < 8) ? irq + 8 : 0x70 + irq - 8; + if (ip->chain) + return(_go32_dpmi_unchain_protected_mode_interrupt_vector(irq, &ip->new)); + if((i = __dpmi_set_protected_mode_interrupt_vector(irq, &ip->old)) != 0) + return(i); + return(_go32_dpmi_free_iret_wrapper(&ip->new)); +} + +void +init_timer(void) +{ + unsigned long t1, t2, tx; + + tx = time(NULL); /* Korrekturfaktor fuer kaputte Boards */ + while (tx == time(NULL)); + t1 = uclock(); + while (tx + 1 == time(NULL)); + t2 = uclock(); + if (t2 - t1 > 2000000) + { + xprintf("*** WARNING: Timer XTAL is 2.38Mhz\n"); + tim_factor = 2; + } + else + tim_factor = 1; + watchdog = 0; /* erstmal auf 0 stellen */ + disable(); /* einen Soft-Wachhund installieren */ + allocirq(0, 1, watch_dog_reset, 0); /* wir haengen uns in IRQ 0 */ + oldtimer = getmask(0); /* alten IRQ-Vektor merken */ + maskon(0); + enable(); +} + +void +exit_timer(void) +{ + disable(); + if (!oldtimer) + maskoff(0); /* alten IRQ-Vektor wieder herstellen */ + freeirq(0); /* einmal mit neuer Maske freigeben ?! */ + enable(); +} + +void +update_timer(void) +{ + static uclock_t last_uclock = 0L; + static uclock_t uclock_sum = 0L; + uclock_t now, diff; + + watchdog = 0; /* watchdog zuruecksetzen */ + now = uclock(); /* aktuelle Uhrzeit merken */ + diff = (now - last_uclock) /* Zeit seit letzer Runde */ + * tim_factor; /* Korrekturfaktor */ + + last_uclock = now; /* den neuen Wert merken */ + + uclock_sum += diff; /* aktueller Zaehlerstand */ +/* jetzt die vergangenen Tenticks aufaddieren und vom Zaehlerstand */ +/* wegstreichen, Ungenauigkeit etwa 1.2ms in 10 Sekunden. Da es */ +/* sich hier nur um einen Timer fuer LAPB (AX.25) handelt, ist das */ +/* zu verkraften. */ + tic10 += (unsigned) (uclock_sum / (UCLOCKS_PER_SEC / 100)); + uclock_sum %= (UCLOCKS_PER_SEC / 100); + + fflush(stdout); +} + +void +watch_dog_reset(int nix) +{ + nix = 1; /* Dummy-Variable. Ist beim IRQ-Aufruf so definiert!! */ + if (++watchdog > WATCH_TIME) + { + sprintf(debugfile, "%s\\debug.txt", textcmdpath); + aus = fopen(debugfile, "at"); + fprintf(aus, "Der Wachhund hat zugebissen!!\n"); + fprintf(aus, "Letzter Befehl war : %s\n", clilin); + zeit = localtime(&sys_time); + fprintf(aus, "%02d.%02d.%02d %02d:%02d\n\n", zeit->tm_mday, + zeit->tm_mon+1, + zeit->tm_year%100, + zeit->tm_hour, + zeit->tm_min); + fclose(aus); + reboot_system(); /* und Schulz is */ + } +} + +/* Written to extend gopint.c in djgpp library */ +int _go32_dpmi_unchain_protected_mode_interrupt_vector(unsigned irq,_go32_dpmi_seginfo *info) +{ + __dpmi_paddr v; + char *stack; + char *wrapper; + + __dpmi_get_protected_mode_interrupt_vector(irq,&v); + /* Sanity check: does the vector point into our program? A bug in gdb + * keeps us from hooking the keyboard interrupt when we run under its + * control. This test catches it. + */ + if (v.selector != _go32_my_cs()) + return(-1); + wrapper = (char *)v.offset32; + /* Extract previous vector from the wrapper chainback area */ + v.offset32 = *(long *)(wrapper + 0x5b); + v.selector = *(short *)(wrapper + 0x5f); + /* Extract stack base from address of _call_count variable in wrapper */ + stack = (char *)(*(long *)(wrapper+0x0F) - 8); +#define STACK_WAS_MALLOCED (1 << 0) + + if (*(long *) stack & STACK_WAS_MALLOCED) + free(stack); + free(wrapper); + __dpmi_set_protected_mode_interrupt_vector(irq, &v); + return(0); +} + +/* Re-arm 8259 interrupt controller(s) + * Should be called just after taking an interrupt, instead of just + * before returning. This is because the 8259 inputs are edge triggered, and + * new interrupts arriving during an interrupt service routine might be missed. + */ +void eoi(void) +{ +/* read in-service register from secondary 8259 */ + outportb(0xa0, 0x0b); + if(inportb(0xa0)) + outportb(0xa0, 0x20); /* Send EOI to secondary 8259 */ + outportb(0x20, 0x20); /* Send EOI to primary 8259 */ +} + +/* End of os/go32/go32.c */ diff --git a/os/go32/hardware.h b/os/go32/hardware.h new file mode 100755 index 0000000..3fa0099 --- /dev/null +++ b/os/go32/hardware.h @@ -0,0 +1,89 @@ +/************************************************************************/ +/* */ +/* ***** ***** */ +/* ***** ***** */ +/* ***** ***** */ +/* ***** ***** */ +/* *************** *************** */ +/* ***************** ***************** */ +/* *************** *************** */ +/* ***** ***** TheNetNode */ +/* ***** ***** Portable */ +/* ***** ***** Network */ +/* ***** ***** Software */ +/* */ +/* File include/hardware.h (maintained by: ???) */ +/* */ +/* This file is part of "TheNetNode" - Software Package */ +/* */ +/* Copyright (C) 1998 - 2008 NORD>dev = open_rs232(dev,adr,irq,KI_BUFFERSIZE,KI_BUFFERSIZE); + kp->active = (kp->dev != -1); + } else kp->active = FALSE; +#endif /* PC */ +#ifdef ST + read_envdev(str, device, ""); + kp->active = ((*device && (kp->dev = open_rs232(device)) > 0)); +#endif /* ST */ + if (kp->active) { + bd = setbaud(kp->dev, 96); + setstopbits(kp->dev, 1); + printf(" setting to %u00 8N1.\n", bd); + } + kp->kisslinkport = -1; + kp->rx_state = 0; + kp->rxfhd = NULL; + if (kp->active) + numactive++; + } + return(numactive); +} + +/************************************************************************/ +/* Level1 Exit */ +/************************************************************************/ +static void kiss_exit(void) +{ + int kiss; + + for (kiss = 0; kiss < MAXKISS; kiss++) + if (kissdev[kiss].active) close_rs232(kissdev[kiss].dev); +} + +/* Berechnung eines Teil-CRC 16 nach SMACK Methode */ +/**************************************************************************/ +static UBYTE smack_crc(UWORD *crc, UBYTE c) +{ + static const UWORD crc_table[] = { + 0x0000, 0xc0c1, 0xc181, 0x0140, 0xc301, 0x03c0, 0x0280, 0xc241, + 0xc601, 0x06c0, 0x0780, 0xc741, 0x0500, 0xc5c1, 0xc481, 0x0440, + 0xcc01, 0x0cc0, 0x0d80, 0xcd41, 0x0f00, 0xcfc1, 0xce81, 0x0e40, + 0x0a00, 0xcac1, 0xcb81, 0x0b40, 0xc901, 0x09c0, 0x0880, 0xc841, + 0xd801, 0x18c0, 0x1980, 0xd941, 0x1b00, 0xdbc1, 0xda81, 0x1a40, + 0x1e00, 0xdec1, 0xdf81, 0x1f40, 0xdd01, 0x1dc0, 0x1c80, 0xdc41, + 0x1400, 0xd4c1, 0xd581, 0x1540, 0xd701, 0x17c0, 0x1680, 0xd641, + 0xd201, 0x12c0, 0x1380, 0xd341, 0x1100, 0xd1c1, 0xd081, 0x1040, + 0xf001, 0x30c0, 0x3180, 0xf141, 0x3300, 0xf3c1, 0xf281, 0x3240, + 0x3600, 0xf6c1, 0xf781, 0x3740, 0xf501, 0x35c0, 0x3480, 0xf441, + 0x3c00, 0xfcc1, 0xfd81, 0x3d40, 0xff01, 0x3fc0, 0x3e80, 0xfe41, + 0xfa01, 0x3ac0, 0x3b80, 0xfb41, 0x3900, 0xf9c1, 0xf881, 0x3840, + 0x2800, 0xe8c1, 0xe981, 0x2940, 0xeb01, 0x2bc0, 0x2a80, 0xea41, + 0xee01, 0x2ec0, 0x2f80, 0xef41, 0x2d00, 0xedc1, 0xec81, 0x2c40, + 0xe401, 0x24c0, 0x2580, 0xe541, 0x2700, 0xe7c1, 0xe681, 0x2640, + 0x2200, 0xe2c1, 0xe381, 0x2340, 0xe101, 0x21c0, 0x2080, 0xe041, + 0xa001, 0x60c0, 0x6180, 0xa141, 0x6300, 0xa3c1, 0xa281, 0x6240, + 0x6600, 0xa6c1, 0xa781, 0x6740, 0xa501, 0x65c0, 0x6480, 0xa441, + 0x6c00, 0xacc1, 0xad81, 0x6d40, 0xaf01, 0x6fc0, 0x6e80, 0xae41, + 0xaa01, 0x6ac0, 0x6b80, 0xab41, 0x6900, 0xa9c1, 0xa881, 0x6840, + 0x7800, 0xb8c1, 0xb981, 0x7940, 0xbb01, 0x7bc0, 0x7a80, 0xba41, + 0xbe01, 0x7ec0, 0x7f80, 0xbf41, 0x7d00, 0xbdc1, 0xbc81, 0x7c40, + 0xb401, 0x74c0, 0x7580, 0xb541, 0x7700, 0xb7c1, 0xb681, 0x7640, + 0x7200, 0xb2c1, 0xb381, 0x7340, 0xb101, 0x71c0, 0x7080, 0xb041, + 0x5000, 0x90c1, 0x9181, 0x5140, 0x9301, 0x53c0, 0x5280, 0x9241, + 0x9601, 0x56c0, 0x5780, 0x9741, 0x5500, 0x95c1, 0x9481, 0x5440, + 0x9c01, 0x5cc0, 0x5d80, 0x9d41, 0x5f00, 0x9fc1, 0x9e81, 0x5e40, + 0x5a00, 0x9ac1, 0x9b81, 0x5b40, 0x9901, 0x59c0, 0x5880, 0x9841, + 0x8801, 0x48c0, 0x4980, 0x8941, 0x4b00, 0x8bc1, 0x8a81, 0x4a40, + 0x4e00, 0x8ec1, 0x8f81, 0x4f40, 0x8d01, 0x4dc0, 0x4c80, 0x8c41, + 0x4400, 0x84c1, 0x8581, 0x4540, 0x8701, 0x47c0, 0x4680, 0x8641, + 0x8201, 0x42c0, 0x4380, 0x8341, 0x4100, 0x81c1, 0x8081, 0x4040 + }; + + *crc = (*crc >> 8) ^ crc_table[(*crc ^ c) & 0xFF]; + return(c); +} + +/* Berechnung eines Teil-CRC 16 nach RMNC Methode */ +/**************************************************************************/ +static UBYTE rmnc_crc(UWORD *crc, UBYTE c) +{ + static const UWORD Crc_rmnc_table[] = { + 0x0f87, 0x1e0e, 0x2c95, 0x3d1c, 0x49a3, 0x582a, 0x6ab1, 0x7b38, + 0x83cf, 0x9246, 0xa0dd, 0xb154, 0xc5eb, 0xd462, 0xe6f9, 0xf770, + 0x1f06, 0x0e8f, 0x3c14, 0x2d9d, 0x5922, 0x48ab, 0x7a30, 0x6bb9, + 0x934e, 0x82c7, 0xb05c, 0xa1d5, 0xd56a, 0xc4e3, 0xf678, 0xe7f1, + 0x2e85, 0x3f0c, 0x0d97, 0x1c1e, 0x68a1, 0x7928, 0x4bb3, 0x5a3a, + 0xa2cd, 0xb344, 0x81df, 0x9056, 0xe4e9, 0xf560, 0xc7fb, 0xd672, + 0x3e04, 0x2f8d, 0x1d16, 0x0c9f, 0x7820, 0x69a9, 0x5b32, 0x4abb, + 0xb24c, 0xa3c5, 0x915e, 0x80d7, 0xf468, 0xe5e1, 0xd77a, 0xc6f3, + 0x4d83, 0x5c0a, 0x6e91, 0x7f18, 0x0ba7, 0x1a2e, 0x28b5, 0x393c, + 0xc1cb, 0xd042, 0xe2d9, 0xf350, 0x87ef, 0x9666, 0xa4fd, 0xb574, + 0x5d02, 0x4c8b, 0x7e10, 0x6f99, 0x1b26, 0x0aaf, 0x3834, 0x29bd, + 0xd14a, 0xc0c3, 0xf258, 0xe3d1, 0x976e, 0x86e7, 0xb47c, 0xa5f5, + 0x6c81, 0x7d08, 0x4f93, 0x5e1a, 0x2aa5, 0x3b2c, 0x09b7, 0x183e, + 0xe0c9, 0xf140, 0xc3db, 0xd252, 0xa6ed, 0xb764, 0x85ff, 0x9476, + 0x7c00, 0x6d89, 0x5f12, 0x4e9b, 0x3a24, 0x2bad, 0x1936, 0x08bf, + 0xf048, 0xe1c1, 0xd35a, 0xc2d3, 0xb66c, 0xa7e5, 0x957e, 0x84f7, + 0x8b8f, 0x9a06, 0xa89d, 0xb914, 0xcdab, 0xdc22, 0xeeb9, 0xff30, + 0x07c7, 0x164e, 0x24d5, 0x355c, 0x41e3, 0x506a, 0x62f1, 0x7378, + 0x9b0e, 0x8a87, 0xb81c, 0xa995, 0xdd2a, 0xcca3, 0xfe38, 0xefb1, + 0x1746, 0x06cf, 0x3454, 0x25dd, 0x5162, 0x40eb, 0x7270, 0x63f9, + 0xaa8d, 0xbb04, 0x899f, 0x9816, 0xeca9, 0xfd20, 0xcfbb, 0xde32, + 0x26c5, 0x374c, 0x05d7, 0x145e, 0x60e1, 0x7168, 0x43f3, 0x527a, + 0xba0c, 0xab85, 0x991e, 0x8897, 0xfc28, 0xeda1, 0xdf3a, 0xceb3, + 0x3644, 0x27cd, 0x1556, 0x04df, 0x7060, 0x61e9, 0x5372, 0x42fb, + 0xc98b, 0xd802, 0xea99, 0xfb10, 0x8faf, 0x9e26, 0xacbd, 0xbd34, + 0x45c3, 0x544a, 0x66d1, 0x7758, 0x03e7, 0x126e, 0x20f5, 0x317c, + 0xd90a, 0xc883, 0xfa18, 0xeb91, 0x9f2e, 0x8ea7, 0xbc3c, 0xadb5, + 0x5542, 0x44cb, 0x7650, 0x67d9, 0x1366, 0x02ef, 0x3074, 0x21fd, + 0xe889, 0xf900, 0xcb9b, 0xda12, 0xaead, 0xbf24, 0x8dbf, 0x9c36, + 0x64c1, 0x7548, 0x47d3, 0x565a, 0x22e5, 0x336c, 0x01f7, 0x107e, + 0xf808, 0xe981, 0xdb1a, 0xca93, 0xbe2c, 0xafa5, 0x9d3e, 0x8cb7, + 0x7440, 0x65c9, 0x5752, 0x46db, 0x3264, 0x23ed, 0x1176, 0x00ff + }; + + *crc = (*crc << 8) ^ Crc_rmnc_table[((*crc >> 8) ^ c) & 0xff]; + return(c); +} + +/* dies ist eine Inline-Code-Sequence, die benutzt wird, um ein Zeichen */ +/* Slip-kodiert auszugeben. Da es ein Macro ist, darf ch nur einmal */ +/* abgefragt werden. tmp ist eine Registervariable und speichert ch */ +/* fuer eine 2. Abfrage zwischen. */ +/* Dies wuerde sauberer mit einem inline tag gehen, aber Borland kennt */ +/* soetwas nicht. */ +#define slip_encode(ch) switch ((tmp=ch)&0xFF) { \ + case FEND: TX_CHAR(FESC); \ + TX_CHAR(TFEND); \ + break; \ + case FESC: TX_CHAR(FESC); \ + TX_CHAR(TFESC); \ + break; \ + default: TX_CHAR(tmp); } + +/************************************************************************/ +/* kisslink_put_frame() - Frame(s) im Ringpuffer ablegen */ +/*----------------------------------------------------------------------*/ +static void kisslink_put_frame(__kiss_struct *kp) +{ + UWORD crc; + LHEAD *l2flp; + MBHEAD *txfhdl; + UBYTE *out; + UBYTE register tmp; + + l2flp = &txl2fl[kp->kisslinkport]; + + /* Nur senden wenn letztes Frame raus ist */ + + if (!rs232_out_status(kp->dev)) + { + portpar[kp->kisslinkport].reset_port = + commandflag[kp->kisslinkport] = + testflag[kp->kisslinkport] = FALSE; + + if (kick[kp->kisslinkport]) { + ulink((LEHEAD *)(txfhdl = (MBHEAD *) l2flp->head));/*Zeiger holen*/ + TX_BEG(); /* Sender bereit */ + TX_CHAR(FEND); /* neues Frame */ + /* das Frame nach der SMACK-Methode einpacken und senden */ + if (kp->use_crc == SMACK) { + crc = 0; + TX_CHAR(smack_crc(&crc, 0x80)); + while (txfhdl->mbgc < txfhdl->mbpc) /* solange Daten vorhanden sind */ + slip_encode(smack_crc(&crc, getchr(txfhdl))); + slip_encode(crc); + slip_encode(crc >> 8); + } else + /* das Frame nach der RMNC-Methode einpacken und senden */ + if (kp->use_crc == RMNC) { + crc = 0xFFFF; + TX_CHAR(rmnc_crc(&crc, 0x20)); + while (txfhdl->mbgc < txfhdl->mbpc) /* solange Daten vorhanden sind */ + slip_encode(rmnc_crc(&crc, getchr(txfhdl))); + slip_encode(crc >> 8); + slip_encode(crc); + } else { + /* das Frame ohne CRC einpacken und senden */ + TX_CHAR(0x00); + while (txfhdl->mbgc < txfhdl->mbpc) /* solange Daten vorhanden sind */ + slip_encode(getchr(txfhdl)); + } + TX_CHAR(FEND); /* Frame bendet */ + rs232_write(kp->dev, blkbuf, out); /* und an die RS232 damit */ + + relink((LEHEAD *)txfhdl, /* als gesendet betrachten und in */ + (LEHEAD *)stfl.tail); /* die gesendet Liste umhaengen */ + + kick[kp->kisslinkport] = ((LHEAD *)l2flp->head != l2flp); + } + } +} + +/************************************************************************/ +/* kisslink_get_frame() - Frame(s) aus Ringbuffer holen */ +/*----------------------------------------------------------------------*/ +static void kisslink_get_frame(__kiss_struct *kp) +{ + UBYTE ch, *in = blkbuf; + int state; + int n; + int use_crc; + UWORD rx_crc; + MBHEAD *rxfhd; + + /* mit if() abzubrechen ist quatsch, while (n) ist auch nurn if() */ + /* ich hab mir angeschaut was mein compiler macht, keine Vorteile */ + + if ((n = rs232_read(kp->dev, blkbuf, BLOCKSIZE))==0) return; + + /* das war allerdings bevor ich state,rxfhd,rx_crc und use_crc rein- */ + /* genommen habe ... sri odo */ + + state = kp->rx_state; + rxfhd = kp->rxfhd; + rx_crc = kp->crc; + use_crc = kp->use_crc; + + while (n) /* Zeichen auswerten */ + { + ch = *in++; /* Zeichen holen */ + n--; + switch (state) /* ueber Status verzweigen */ + { + case WFEND: /* Frame Anfang erwartet */ + if (ch == FEND) + state = GTYPE; /* Frameanfang entdeckt */ + continue; + + case GTYPE: + if (ch != FEND) /* zuletzt FEND bekommen */ + { + if ((ch & 0x0F) > 0) { + state = WFEND; /* Kommandos */ + continue; + } + state = GFRAM; /* Daten */ + if (rxfhd) /* wenn Frame aktiv, auf den Muell */ + relink((LEHEAD *)rxfhd, (LEHEAD *)trfl.tail); + (rxfhd = (MBHEAD *)allocb(ALLOC_MBHEAD))->l2port = kp->kisslinkport; + + switch (use_crc = kp->use_crc) { + case SMACK : + rx_crc = 0; + smack_crc(&rx_crc, 0x80); + break; + case RMNC : + rx_crc = 0xFFFF; + rmnc_crc(&rx_crc, 0x20); + break; + } + } + continue; + + case GFRAM: /* vom TNC holen */ + switch (ch) + { + case FEND: + state = WFEND; /* Frame-Ende = Anfang fuer nextes */ + if (rxfhd) { /* nur wenn ein Frame aktiv */ + switch (use_crc) { + case SMACK : + if (rxfhd->mbpc > 2) + rxfhd->mbpc -= 2; + if (rx_crc) { + kp->crcerrors++; + continue; /* wirklich Fehler */ + } + relink((LEHEAD *)rxfhd, (LEHEAD *)rxfl.tail); + rxfhd = NULL; /* kein RX-Frame aktiv */ + break; + case RMNC : + if (rxfhd->mbpc > 2) + rxfhd->mbpc -= 2; + if ((rx_crc & 0xffff) != 0x7070) { + kp->crcerrors++; + continue; /* wirklich Fehler */ + } + default: + relink((LEHEAD *)rxfhd, (LEHEAD *)rxfl.tail); + rxfhd = NULL; /* kein RX-Frame aktiv */ + } + } + continue; /* Das war's.. fertig! */ + + case FESC: + state++; /* FESC wird zu FESC-TFESC */ + continue; /* Rueckwandlung.. */ + } + break; + + case GFRMT: + switch (ch) /* TFEND/TFESC-Rueckwandlung */ + { + case TFEND: + ch = FEND; + break; + + case TFESC: + ch = FESC; + break; + + default: + kp->sliperrors++; + state = WFEND; + continue; + } + state--; + break; + + } /* switch(state) */ + + switch (use_crc) { + case SMACK : smack_crc(&rx_crc, ch); + break; + case RMNC : rmnc_crc(&rx_crc, ch); + break; + } + putchr(ch, rxfhd); /* Zeichen in Frame */ + if (rxfhd->mbpc > L2MFLEN) /* Framelaengencheck */ + state = WFEND; + } /* solange Zeichen in der RS232 */ + + kp->rx_state = state; + kp->rxfhd = rxfhd; + kp->crc = rx_crc; +} + +/************************************************************************/ +/* Level1 RX/TX fuer KISSLINK */ +/* wird staendig in der main() Hauptschleife aufgerufen. */ +/************************************************************************/ +static void kisslink(void) +{ + int kiss; + __kiss_struct *kp; + + for (kiss = 0, kp = kissdev; kiss < MAXKISS; kiss++, kp++) + { + if ((kp->kisslinkport != -1) && kp->active) + { + kisslink_get_frame(kp); + kisslink_put_frame(kp); + } + } +} + +static WORD kiss_dcd(PORTINFO *port) +{ + __kiss_struct *kp; + int state = 0; + + kp = &kissdev[port->minor]; + + if (rs232_out_status(kp->dev)) + state |= PTTFLAG; + if (kp->rx_state > 1) + state |= DCDFLAG; + return(state); +} + +static void kiss_ctl(int req, int port) +{ + __kiss_struct *kp; + int minor; + + minor = portpar[port].minor; + + kp = &kissdev[minor]; + + switch (req) { + case L1CCMD : + case L1CRES : + portpar[kp->kisslinkport].speed = + setbaud(kp->dev, portpar[kp->kisslinkport].speed); + /* macht setbaud automatisch */ +#ifndef MC68K + setstopbits(kp->dev,1); +#else /* statttdessen crc-mode vorbereiten */ + setkissmode(port); +#endif + break; + } + default_l1ctl(req, port); /* Flags loeschen */ +}; + +#define MINOR_SMACK_FLAG (SMACK << 8) +#define MINOR_RMNC_FLAG (RMNC << 8) +#define MINOR_MASK (0xFF) + +static int kiss_istome(int major, char *devname) +{ + char name[21], *cp; + int minor = 0; + + strncpy(name, devname, 20); /* Minor bestimmen und abschneiden */ + name[20] = 0; + for (cp = name; isalpha(*cp); cp++); /* Zahl suchen */ + if (isdigit(*cp)) minor = atoi(cp); + *cp = 0; /* kann nicht schaden */ + + if (minor < 1 || minor > MAXKISS) + return(NO_MINOR); /* falscher Geraetekanal (minor) */ + + minor--; + + if (strnicmp(name, "KISS", strlen(name))==0) + return(minor); + else if (strnicmp(name, "SMACK", strlen(name))==0) + return(minor|MINOR_SMACK_FLAG); + else if (strnicmp(name, "RKISS", strlen(name))==0) + return(minor|MINOR_RMNC_FLAG); + + return(NO_MINOR); +} + +static int kiss_attach(int port, int minor, BOOLEAN check_only) +{ + __kiss_struct *kp; + int use_crc; + + use_crc = (minor >> 8); + minor &= MINOR_MASK; + + kp = &kissdev[minor]; + + if (kp->active) { /* Geraetekanal bereit? */ + if (kp->kisslinkport == -1) { + if (!check_only) { + kp->kisslinkport = port; + kp->use_crc = use_crc; + portpar[port].minor = minor; + clear_rs232(minor); + } + return(1); + } + if (kp->kisslinkport == port) + return(1); + } + return(0); /* versuchte Doppeleintragung */ +} + +static int kiss_detach(int port) +{ + int kiss = portpar[port].minor; + + kissdev[kiss].kisslinkport = -1; + return(1); +} + +static void kiss_info(int what, int port, MBHEAD *mbp) +{ + char *name[] = {"KISS", "SMACK", "RKISS"}; /* SMACK=1, RMNC=2 */ + int minor, cnt; + __kiss_struct *kp; + + minor = portpar[port].minor; + + switch (what) { + case HW_INF_IDENT : + case HW_INF_INFO : + putprintf(mbp, "%s%u", name[kissdev[minor].use_crc], minor+1); + break; + case HW_INF_STAT : + for (minor = cnt = 0, kp = kissdev; minor < MAXKISS; minor++, kp++) + if (kp->kisslinkport != -1) { + if (cnt++ == 0) + putstr("\rKISS-Statistics:\r\r", mbp); + putprintf(mbp, " KISS%u RxCRC: %5u RxErr: %5u\r", + minor+1, kp->crcerrors, kp->sliperrors); + } + break; + case HW_INF_CLEAR : + + /* durchfallen */ + default: + default_l1info(what, port, mbp); + } +} + +static int register_kiss(void) +{ + MAJOR *m; + + if (kiss_init()) { + m = register_major(); + m->name = "KISS/SMACK/RKISS"; + m->istome = kiss_istome; + m->exit = kiss_exit; + m->handle = kisslink; + m->ctl = kiss_ctl; + m->dcd = kiss_dcd; + m->attach = kiss_attach; + m->detach = kiss_detach; + m->info = kiss_info; + return(kiss_major = num_major); + } + return(0); +} + +/*----------------------------------------------------------------------*/ + +/* End of os/go32/kiss.c */ diff --git a/os/go32/kiss.h b/os/go32/kiss.h new file mode 100755 index 0000000..a93d9d8 --- /dev/null +++ b/os/go32/kiss.h @@ -0,0 +1,65 @@ +/************************************************************************/ +/* */ +/* ***** ***** */ +/* ***** ***** */ +/* ***** ***** */ +/* ***** ***** */ +/* *************** *************** */ +/* ***************** ***************** */ +/* *************** *************** */ +/* ***** ***** TheNetNode */ +/* ***** ***** Portable */ +/* ***** ***** Network */ +/* ***** ***** Software */ +/* */ +/* File include/kiss.h (maintained by: ???) */ +/* */ +/* This file is part of "TheNetNode" - Software Package */ +/* */ +/* Copyright (C) 1998 - 2008 NORD>Minor statt. */ + +static MAJOR majortab[MAX_MAJOR+1]; /* Tabelle der MAC-Treiber */ +static int num_major = 0; + +/* Default-Handler. Diese koennen die MAC-Treiber-Handler ersetzen oder */ +/* ergaenzen, indem der Aufruf durchgereicht wird. */ + +/* Geraet-Initialisierung. */ +/* Das Geraet und alle Minors werden vorinitialisiert. Diese Funktion */ +/* wird beim Systemstart nach erfolgreicher registrierung aufgerufen. */ +static void default_l1init(void) +{ +} + +/* Geraet-Deinitialisierung. */ +/* Beim Runterfahren des Systems wird diese Routine aufgerufen. */ +#define default_l1exit default_l1init + +/* Geraet-Behandlung */ +/* Hier koennen staendige Aufgaben erledigt werden, z.B. die Interrupt- */ +/* Buffer leeren und Frames an den L2 schicken. Nur hier darf auf L1- */ +/* Strukturen zugegriffen werden, nie aus dem Interrupt. */ +#define default_l1handle default_l1init + +/* Geraet-Konfiguration */ +/* Hier werden Konfigurations/Test/Reset-Anfragen bearbeit. */ +static void +default_l1ctl(int req, int port) +{ + PORTINFO *p = &portpar[port]; + + if (p->reset_port) + portstat[port].reset_count++; + p->reset_port = + commandflag[port] = + testflag[port] = FALSE; +} + +/* Geraet-DCD */ +/* Wenn moeglich sollte das Geraet hier seinen tatsaechlichen DCD-Status */ +/* liefern. Es duerfen keine Interpretationen (z.B. Vollduplex) geschehen,*/ +/* das macht der L2 selbst. */ +static WORD default_l1dcd(PORTINFO *port) +{ + return(0); +} + +/* Feststellen, ob wir mit dem L1-MAC-Namen gemeint sind. Es wird */ +/* immer minor 0 geliefert (nicht geeignet fuer KISS usw). */ +static int default_l1istome(int major, char *devname) +{ + if (strnicmp(majortab[major].name, devname, strlen(devname))==0) + return(0); + return(NO_MINOR); +} + +/* Geraet-Timerbehandlung. */ +static void default_l1timer(UWORD ticks) +{ +} + +/* Geraet anschliessen */ +/* Ein Geraet und Minor an einen Port anschliessen. Dies muss */ +/* nicht immer Erfolg haben. Der Minor wurde mittels dem jeweiligen */ +/* l1istome ermittelt. */ +/* Ist checkonly TRUE, dann soll nur geprueft werden, ob ein Eintrag */ +/* moeglich WAERE, aber NICHTS ausgefuehrt werden. */ +static int default_l1attach(int port, int unused_minor, BOOLEAN unused_checkonly) +{ + return(1); +} + +/* Geraet-Abschalten */ +/* Einen Port abschalten, wenn das Geraet eine Trennung zulaesst. */ +static int default_l1detach(int unused_port) +{ + return(1); +} + +/* Geraet-Informationen */ +/* what=HW_INF_IDENT sollte der Geraetename geliefert werden. Wenn das */ +/* Geraet mehrere hat (z.B. KISS/SMACK/RKISS), soll es */ +/* den aktuellen liefern (benutzt von SPARAM). */ +/* what=HW_INF_INFO sollte max. 10 Zeichen Geraetekonfiguration liefern, */ +/* im Normalfalle auch der Name, eventuell mit etwas */ +/* mehr Info. */ +/* what=... sollte spaeter mal hsbus_stat() u.ae. ersetzen */ +static void +default_l1info(int what, int port, MBHEAD *mbp) +{ + switch (what) + { + case HW_INF_IDENT : + case HW_INF_INFO : + putstr(majortab[portpar[port].major].name, mbp); + } +} + +/* MAC-Treiber registrieren. Es werden die default-Handler eingetragen, */ +/* nur die benoetigten Routinen muessen vom Treiber ersetzt werden. Jeder */ +/* Treiber sollte vor der Registrierung pruefen, ob ueberhaupt ein Geraet */ +/* im System vorhanden ist und sich ggfs garnicht installieren. Dies */ +/* beschleunigt den allgemeinen Ablauf im L1. */ +static MAJOR *register_major(void) +{ + MAJOR *m; + + if (num_major > MAX_MAJOR) + return(NULL); + m = &majortab[++num_major]; + + m->istome = default_l1istome; + m->init = default_l1init; + m->exit = default_l1exit; + m->handle = default_l1handle; + m->ctl = default_l1ctl; + m->dcd = default_l1dcd; + m->attach = default_l1attach; + m->detach = default_l1detach; + m->info = default_l1info; + m->timer = default_l1timer; + + return(m); +} + +/* Einen Port mit einem MAC-Treiber verbinden. Falls der Port bereits */ +/* belegt ist, wird vorher l1detach() aufgerufen. Dieser darf aber auch */ +/* fehlschlagen (wenn der Port nicht umkonfigurierbar ist, z.B. Host- */ +/* terminal). Der Geraetetreiber setzt nur seinen minor, den major */ +/* setzt l1attach selbst (der Geraetetreiber kennt eigentlich seinen */ +/* major nicht). */ +int l1attach(int port, char *devname) +{ + int major; + int minor; + PORTINFO *p = &portpar[port]; + + /* als erstes suchen wir einen passenden major */ + for (major = 1; major <= num_major; major++) + if ((minor = majortab[major].istome(major, devname)) != NO_MINOR) + break; + + if (major > num_major) + return(0); /* Geraet unbekannt */ + + if (!majortab[major].attach(port, minor, TRUE/*check only*/)) + return(0); /* erstmal nur antesten */ + + /* hier angekommen ist das neue Geraet bereit, ein eventuell altes */ + /* schalten wir aus. */ + + if (p->major != NO_MAJOR) + l1detach(port); + + if (p->major == NO_MAJOR) { /* nur wenn Abschaltung erfolgreich war */ + if (majortab[major].attach(port, minor, FALSE/*attach*/)) { + p->major = major; + return(1); + } + } + + return(0); /* Port belegt / nicht belegbar */ +} + +/* Einen Port von einem MAC-Treiber trennen. Dies darf fehlschlagen, */ +/* wenn z.B. der L1 anderweitig konfiguriert wurde (Linux). */ +void l1detach(int port) +{ + int major; + MBHEAD *mbp; + LHEAD *mlp; + + major = portpar[port].major; + if (major != NO_MAJOR) + if (majortab[major].detach(port)) + portpar[port].major = NO_MAJOR; + if (portpar[port].major == NO_MAJOR) { + mlp = &txl2fl[port]; + while ((LHEAD *)mlp->head != mlp) { + mbp = (MBHEAD *)ulink((LEHEAD *)mlp->head); + relink((LEHEAD *)mbp, (LEHEAD *)stfl.tail); + } + kick[port] = FALSE; + } +} + +/************************************************************************/ +/* Initialisierung der Variablen und der Hardware */ +/************************************************************************/ + +void l1init(void) +{ + MAJOR *m; + int i; + PORTINFO *p; + + for (i=0, p = portpar; ireset_port = FALSE; /* Tnx an Odo */ + p->speed = 12; + p->major = NO_MAJOR; + p->minor = -1; + cd_timer[i] = 0; + kick[i] = FALSE; /* kein TNC sendet */ + testflag[i] = FALSE; + commandflag[i] = FALSE; + } + + blkbuf = malloc(BLOCKSIZE); + if (blkbuf == NULL) memerr(); + + show_recovery = TRUE; + + register_majors(); + + for (m = &majortab[1]; m <= &majortab[num_major]; m++) + m->init(); + + l1sclr("*"); +} + +/************************************************************************/ +/* Layer 1 deinitialisieren */ +/*----------------------------------------------------------------------*/ +void l1exit (void) +{ + MAJOR *m; + + for (m = &majortab[1]; m <= &majortab[num_major]; m++) + m->exit(); +} + +/************************************************************************/ +/* Timer-Behandlung fuer den L1 */ +/* wird aus timsrv() herraus aufgerufen */ +/*----------------------------------------------------------------------*/ +void l1timr(UWORD ticks) +{ + MAJOR *m; + + for (m = &majortab[1]; m <= &majortab[num_major]; m++) + m->timer(ticks); +} + +/************************************************************************/ +/* Level1 RX/TX */ +/* wird staendig in der main() Hauptschleife aufgerufen. */ +/*----------------------------------------------------------------------*/ +void l1rxtx(void) +{ + MAJOR *m; + int major; + + rounds_count++; /* Anzahl der Hauptschleifendurchlaeufe */ + for (m = &majortab[major = 1]; major <= num_major; major++, m++) + m->handle(); +} + +/************************************************************************/ +/* Markieren, dass fuer TNC #port Frames zum Senden vorliegen */ +/*----------------------------------------------------------------------*/ +void kicktx(int port) +{ + kick[port] = TRUE; +} + +/************************************************************************/ +/* */ +/* iscd(): Carrier Detect */ +/* */ +/* Ueberpruefung des Kanalstatus fuer einen Port. Wenn auf einem */ +/* Kanal der Sender getastet ist, wird 2 geliefert. Wenn auf dem */ +/* Kanal Daten empfangen werden, wird 1 geliefert. 0 wird geliefert, */ +/* wenn der Kanal frei ist, oder auf Vollduplex geschaltet ist. */ +/* */ +/* Hinweis: Einige Geraete unterstuetzen diese Funktion nur ungenau */ +/* (z.B. Tokenring) */ +/* */ +/*----------------------------------------------------------------------*/ +WORD iscd(int port) +{ + int state = 0; + int major; + PORTINFO *p; + + p = portpar+port; + major = p->major; + if (major != NO_MAJOR) { + if ((LHEAD *)txl2fl[port].head != &txl2fl[port]) + state |= TXBFLAG; + return(state | majortab[major].dcd(p)); + } + return(state); +} + +/************************************************************************/ +/* Level1 Control */ +/* eine Aktion fuer einen Hardware-Port nachfragen */ +/*----------------------------------------------------------------------*/ +void l1ctl(int req, int port) +{ + int major; + + switch(req) { + case L1CRES: portpar[port].reset_port = TRUE; + break; + case L1CCMD: commandflag[port] = TRUE; + break; + case L1CTST: testflag[port] = TRUE; + } + + major = portpar[port].major; + if (major != NO_MAJOR) + majortab[major].ctl(req, port); +} + +/* Infostring fuer den Port-Befehl zusammenbauen. */ +void l1hwstr(int port, MBHEAD *mbp) +{ + if (portpar[port].major == NO_MAJOR) + putstr("OFF", mbp); + else + majortab[portpar[port].major].info(HW_INF_INFO, port, mbp); +} + +/* Infostring fuer SAVEPARM zusammenbauen. */ +void l1hwcfg(int port, MBHEAD *mbp) +{ + if (portpar[port].major == NO_MAJOR) + putstr("OFF", mbp); + else + majortab[portpar[port].major].info(HW_INF_IDENT, port, mbp); +} + +/* + * Blocktransferroutinen fuer den Level 1 + * Message-Buffer koennen Blockweise in einen linearen Buffer umgewandelt + * werden und wieder zurueck. Dies darf aber so ohne weiteres nur im + * Level 1 erfolgen, da der Buffer zurueckgespult wird. + */ + +static int cpymbflat(char *buf, MBHEAD *fbp) { + MB *bp; + LHEAD *llp = &fbp->mbl; /* Zeiger auf den Listenkopf */ + int i = fbp->mbpc; /* Anzahl der Bytes im Frame */ + + for (bp = (MB *)llp->head; bp != (MB *)llp; + bp = bp->nextmb, i -= sizeof_MBDATA, buf += sizeof_MBDATA) + memcpy(buf, bp->data, sizeof_MBDATA); + return(fbp->mbpc); +} + +static MBHEAD *cpyflatmb(char *buf, int size) { + MBHEAD *mbhd; + MB *bp; + LHEAD *llp; + + mbhd = (MBHEAD *)allocb(ALLOC_MBHEAD); /* einen Buffer fuer den Kopf */ + mbhd->mbpc = size; /* soviel wird mal drinstehen */ + llp = &mbhd->mbl; /* Zeiger auf den Listenkopf */ + for ( ; size > 0; size -= sizeof_MBDATA, buf += sizeof_MBDATA) { + memcpy((bp = (MB *)allocb(ALLOC_MB))->data, buf, sizeof_MBDATA); + relink((LEHEAD *)bp, (LEHEAD *)llp->tail); + } + rwndmb(mbhd); /* mbbp richtig setzen */ + return(mbhd); +} + +#ifdef VANESSA + #include "vanessa.c" +#endif + +#ifdef EXTDEV + #include "extdev.c" +#endif + +#ifdef TOKENRING + #include "tokenrng.c" +#endif + +#ifdef COMKISS + #include "kiss.c" +#endif + +#ifdef SCC + #include "scc.c" +#endif + +#ifdef PAR96 + #include "par.c" +#endif + +#include "loop.c" + +#ifdef TCP_STACK + #include "tcp.c" +#endif /* TCP_STACK */ + +/* Geraetetabelle. */ +/* In dieser Tabelle werden alle Geraete registriert. Bezuege aus L1.C */ +/* auf Variablen der Treiber sind verboten. */ +/* Die Reihenfolge hier bestimmt auch die Reihenfolge bei der STAT- */ +/* Ausgabe. */ +DEVTABLE devtable[] = +{ + REGISTER_DEVICE("LOOPBACK", register_loopback), +#ifdef TOKENRING + REGISTER_DEVICE("TOKENRING", register_tokenring), +#endif +#ifdef COMKISS + REGISTER_DEVICE("KISS", register_kiss), +#endif +#ifdef VANESSA + REGISTER_DEVICE("VANESSA", register_vanessa), +#endif +#ifdef EXTDEV + REGISTER_DEVICE("EXTDEV", register_extdev), +#endif +#ifdef SCC + REGISTER_DEVICE("SCC", register_scc), +#endif +#ifdef PAR96 + REGISTER_DEVICE("PAR96", register_par), +#endif +#ifdef TCP_STACK + REGISTER_DEVICE("TCPIP", RegisterTCP), +#endif /* TCP_STACK */ + REGISTER_DEVICE(NULL, NULL) +}; + +/* Hier werden alle majors nacheinander gebeten, sich zu registrieren. */ +/* Sie muessen es aber nicht, falls z.B. keine Schnittstellen frei oder */ +/* vorhanden sind. */ +void register_majors(void) +{ + DEVTABLE *t; + + for (t = devtable; t->reg_func; t++) + t->major = t->reg_func(); +} + +/* Aufzaehlen der vorhandenen Layer 1 Geraete. Dies sind nicht die */ +/* tatsaechlich installierten, sondern die compilierten. */ +void l1enum(MBHEAD *mbp) +{ + DEVTABLE *t; + + for (t = devtable; t->reg_func; t++) { + putstr(t->major ? " *" : " ", mbp); + putstr(t->name, mbp); + } +} + +/* Information zu einem Geraet abrufen (Statistik). */ +void l1stat(const char *devname, MBHEAD *mbp) +{ + DEVTABLE *t; + + for (t = devtable; t->reg_func; t++) + if (strcmp(t->name, devname) == 0 || *devname == '*') /* Name stimmt? */ + if (t->major) + majortab[t->major].info(HW_INF_STAT, 0, mbp); +} + +/* Portstatistik loeschen */ +void l1sclr(const char *devname) +{ + DEVTABLE *t; + + for (t = devtable; t->reg_func; t++) + if (strcmp(t->name, devname) == 0 || *devname == '*') /* Name stimmt? */ + if (t->major) + majortab[t->major].info(HW_INF_CLEAR, 0, NULL); +} + +/* End of os/go32/l1.c */ diff --git a/os/go32/loop.c b/os/go32/loop.c new file mode 100755 index 0000000..35ac761 --- /dev/null +++ b/os/go32/loop.c @@ -0,0 +1,95 @@ +/************************************************************************/ +/* */ +/* ***** ***** */ +/* ***** ***** */ +/* ***** ***** */ +/* ***** ***** */ +/* *************** *************** */ +/* ***************** ***************** */ +/* *************** *************** */ +/* ***** ***** TheNetNode */ +/* ***** ***** Portable */ +/* ***** ***** Network */ +/* ***** ***** Software */ +/* */ +/* File os/go32/loop.c (maintained by: ???) */ +/* */ +/* This file is part of "TheNetNode" - Software Package */ +/* */ +/* Copyright (C) 1998 - 2008 NORD>head));/*Zeiger holen*/ + rxport = port^1; + if (portpar[rxport].major != loop_major) + rxport = port; + /*if (rand() % 15) {*/ + len = cpymbflat(blkbuf, txfhd); + rxfhd = cpyflatmb(blkbuf, len); + rxfhd->l2port = rxport; + relink((LEHEAD *)rxfhd, (LEHEAD *)rxfl.tail); + /*}*/ + relink((LEHEAD *)txfhd, /* als gesendet betrachten und in */ + (LEHEAD *)stfl.tail); /* die gesendet Liste umhaengen */ + kick[port] = ((LHEAD *)l2flp->head != l2flp); + } + } + } +} + +static int register_loopback(void) +{ + MAJOR *m; + + m = register_major(); + m->name = "LOOPBACK"; + m->handle = loopback; + return(loop_major = num_major); +} + + +/* End of os/go32/loop.c */ diff --git a/os/go32/par.c b/os/go32/par.c new file mode 100755 index 0000000..5c3af7e --- /dev/null +++ b/os/go32/par.c @@ -0,0 +1,794 @@ +/************************************************************************/ +/* */ +/* ***** ***** */ +/* ***** ***** */ +/* ***** ***** */ +/* ***** ***** */ +/* *************** *************** */ +/* ***************** ***************** */ +/* *************** *************** */ +/* ***** ***** TheNetNode */ +/* ***** ***** Portable */ +/* ***** ***** Network */ +/* ***** ***** Software */ +/* */ +/* File os/go32/par.c (maintained by: ???) */ +/* */ +/* This file is part of "TheNetNode" - Software Package */ +/* */ +/* Copyright (C) 1998 - 2008 NORD>> 8) + + #if 0 +#ifndef outp +#define outp(p,b) outportb(p,b) +#endif +#ifndef inp +#define inp(p) inportb(p) +#endif + #endif + +#define not0(par) (par ? par : 1) + +#define TX_IDLE 0 +#define TX_DWAIT 1 +#define TX_DELAY 2 +#define TX_ACTIVE 3 +#define TX_FLUSH 4 +#define TX_TAIL 5 + +/* PAR */ +#define TXD 0x01 +#define PTT 0x02 +#define BURST 0x04 +#define DCDBIT 0x10 +#define RXD 0x20 + +#define IRQEN 0x10 + +#define DCDCOUNT 5 +#define DCDABORT 5 +#define DCDLIMIT 15 + +/* L1 */ +#define MIN_LEN 15 + +#define STUFF 5 +#define FLAG 6 +#define ABRT 7 +#define FREE 30 + +/* CRC */ +#define CRC_RESET 0xFFFF +#define CRC_MASK 0x8408 +#define CRC_CHECK 0xF0B8 + +typedef struct __par_struct +{ + int l2port; + + int parbase; + int parirq; + int paroldmask; + + int port; + int irq; + + int bit_cnt; + int idle; + int shift; + int lastbit; + int frm_len; + unsigned short crc; + unsigned short fcs; + int dcd_cnt; + int dcd; + int sync; + + int tx_state; + char *tx_buf; + char *tx_ptr; + int tx_len; + int tx_bitcnt; + int tx_idle; + int tx_bit; + int tx_timer; + unsigned short tx_fcs; + unsigned tx_shift; + + unsigned long scr; + + int slottime; + int persistance; + int tailtime; + int txdelay; + int flags; + + unsigned burstbuf; + + unsigned overruns; + unsigned underruns; + unsigned crcerrors; + unsigned lenerrors; + + MBHEAD *rxfhd; +} __par_struct; + +static __par_struct par96tab[PARCHANS]; +static int par_major = 0; + +static UWORD *parbuf, *parin, *parout; + +static void par_int(int); + +/* Wenn der Sender keine Daten mehr ausstehen hat, wird ein weiteres + * Frame in den Sendebuffer kopiert. */ +static void par_put_frame(__par_struct *par) +{ + MBHEAD *fbp; + int port; + LHEAD *l2flp; + + if (par->tx_len == 0) { /* erst senden wenn alles raus ist */ + if ((port = par->l2port) == -1) return; + if (kick[port]) { + /* ein weiteres Frame aus der Sendeliste holen */ + l2flp = &txl2fl[port]; + ulink((LEHEAD *)(fbp = (MBHEAD *) l2flp->head)); + kick[port] = ((LHEAD *)l2flp->head != l2flp); + + par->tx_len = cpymbflat(par->tx_ptr = par->tx_buf, fbp); + + relink((LEHEAD *)fbp, /* als gesendet betrachten und in */ + (LEHEAD *)stfl.tail); /* die gesendet Liste umhaengen */ + + disable(); + + if (par->tx_state == TX_IDLE) + { + par->tx_timer = not0 (par->slottime); + par->tx_state = TX_DWAIT; + } + + enable(); + } + } +} + +/* Der PAR-Empfangs-Ringbuffer wird geleert. Dort werden von allen Kanaelen + * Empfangsdaten gesammelt. Das Format entspricht dem alten l1put(). + */ +static void par_get_frame(void) +{ + int minor; + MBHEAD **rxfbpp; + unsigned action; + __par_struct *par = par96tab; + +#ifndef __GO32__ + UWORD *_parin; + + disable(); + _parin = parin; + enable(); +#else +#define _parin parin +#endif + + while (parout != _parin) { + action = *parout++; /* Zeichen aus dem Ringbuffer lesen */ + if (parout >= parbuf+PAR_RXSIZE) + parout = parbuf; + + minor = (action>>8) & 0x7F; + + par = par96tab + minor; + rxfbpp = &par->rxfhd; /* Adresse RX-Framezeiger */ + if (!(action & 0x8000)) /* Zeichen oder Befehl ? */ + { /* Zeichen : */ + if (!*rxfbpp) /* RX-Frame aktiv ? */ + { + *rxfbpp = (MBHEAD *)allocb(); /* nein - neues anlegen */ + (*rxfbpp)->l2port = par->l2port; /* fuer port */ + } + putchr(action & 0xFF,*rxfbpp); /* Zeichen in Frame */ + } + else /* Befehl : */ + if (*rxfbpp) /* nur wenn Frame aktiv */ + { /* Befehl ausfuehren */ + if (action & 0x0001) /* Frame in Muelleimer */ + relink((LEHEAD *)*rxfbpp, (LEHEAD *)trfl.tail); + else { /* Frame in RX-Liste */ + if ((*rxfbpp)->mbpc > 2) /* FCS eleminieren */ + (*rxfbpp)->mbpc -= 2; /* das erste Byte kommt */ + /* noch vor HUNT */ + relink((LEHEAD *)*rxfbpp, (LEHEAD *)rxfl.tail); + } + *rxfbpp = NULL; /* kein RX-Frame aktiv */ + } + } +} + +static void par(void) +{ + __par_struct *par; + + par_get_frame(); + for (par = par96tab; par < par96tab+PARCHANS; par++) + if (par->parbase) + par_put_frame(par); +} + +static WORD par_dcd(PORTINFO *port) +{ + __par_struct *par; + int state = 0; + + par = &par96tab[port->minor]; + + if (par->tx_state) + state |= PTTFLAG; + if (par->dcd) + state |= DCDFLAG; + return(state); +} + +static void par_ctl(int req, int port) +{ + __par_struct *par; + int minor; + PORTINFO *p; + + p = portpar+port; + minor = p->minor; + par = &par96tab[minor]; + + switch (req) { + case L1CCMD : + case L1CRES : + if (p->speed != 192) + p->speed = 96; + par->slottime = p->slottime; + par->persistance = p->persistance; + par->txdelay = p->txdelay; + par->tailtime = TAILTIME; + par->flags = p->l1mode; + par->tx_state = + par->tx_timer = 0; + par->tx_len = 0; + par->dcd = 0; + outp (par->parbase, PTT | BURST); + outp (par->parbase + 2, inp (par->parbase + 2) | IRQEN); + break; + } + default_l1ctl(minor, req); /* Flags loeschen */ +}; + +static int par_attach(int port, int minor, BOOLEAN check_only) +{ + __par_struct *par; + + par = &par96tab[minor]; + + if (par_major) { + if (par->l2port == -1) { + if (!check_only) { + par->l2port = port; + portpar[port].minor = minor; + par_ctl(L1CRES, port); + } + return(1); + } + if (par->l2port == port) + return(1); + } + return(0); /* versuchte Doppeleintragung */ +} + +static int par_detach(int port) +{ + __par_struct *par = &par96tab[portpar[port].minor]; + + par->l2port = -1; + + outp (par->parbase + 2, inp (par->parbase + 2) & ~IRQEN); + outp (par->parbase, PTT | BURST); + + return(1); +} + +static void par_info(int what, int port, MBHEAD *mbp) +{ + int minor, cnt; + __par_struct *par; + + minor = portpar[port].minor; + + switch (what) { + case HW_INF_IDENT : + case HW_INF_INFO : + putprintf(mbp, "PAR%u", minor); + break; + case HW_INF_STAT : + for (minor = cnt = 0, par = par96tab; minor < PARCHANS; minor++, par++) + if (par->l2port != -1) { + if (cnt++ == 0) + putstr("\rPAR-Statistics:\r\r", mbp); + putprintf(mbp, " PAR%u RxOvr: %5u TxUnd: %5u RxCRC: %5u RxLen: %5u\r", + minor, par->overruns, par->underruns, par->crcerrors, par->lenerrors); + } + break; + case HW_INF_CLEAR : + par = &par96tab[minor]; + par->overruns = + par->underruns = + par->crcerrors = + par->lenerrors = 0; + /* durchfallen */ + default : + default_l1info(what, port, mbp); + } +} + +/* SCC-Modes: + t -> Sendetakt extern (DF9IC) + e -> Sendetakt BRG (32-fach) + -> Sendetakt DPLL (32-fach) + r -> Empfangstakt extern (DF9IC) + -> Empfangstakt DPLL +*/ + +static void parput(UWORD action) +{ + *parin++ = action; + if (parin >= parbuf+PAR_RXSIZE) + parin = parbuf; +} + +#define rxput(port, val) parput (((port) << 8) | (val)) +#define rxeof(port) parput (((port) << 8) | 0x8000) +#define rxdiscard(port) parput (((port) << 8) | 0x8001) + +/*** HDLC ******************************************************************/ + +void hdlc_put_word(int minor, struct __par_struct *par, unsigned burstbuf) +{ + int bit; + int dcd; + int cnt; + + dcd = par->flags & MODE_c; + + for (cnt = 16; cnt--; ) + { + bit = burstbuf & 1; + burstbuf >>= 1; + + par->scr = (par->scr << 1) | (bit != par->lastbit); + par->lastbit = bit; + + bit = !((UWORD) par->scr & 1) + ^ !((UWORD) par->scr & 0x1000) + ^ !( par->scr & 0x20000L); + + if (!bit) + { + if (par->idle < STUFF) + { + par->idle = 0; + goto shift_bit; + } + + if (par->idle == FLAG) + { + if ( dcd + && par->dcd_cnt < DCDLIMIT + && ++par->dcd_cnt == DCDCOUNT) + { + par->dcd = TRUE; + } + + if (par->frm_len) + { + if ( par->sync + && par->frm_len >= MIN_LEN+2 + && par->bit_cnt == 1 + && par->fcs == CRC_CHECK) + { + rxeof(minor); + } + else + rxdiscard(minor); + + par->frm_len = 0; + } + + par->bit_cnt = 8; + par->sync = TRUE; + par->crc = CRC_RESET; + } + + par->idle = 0; + } + else + { + if (par->idle < FREE) + { + if (++par->idle < ABRT) + { +shift_bit: if (par->sync) + { + if (par->shift >>= 1, bit) + par->shift |= 0x80; + + par->crc = (par->crc >> 1) ^ ((bit ^ + par->crc) & 1 ? CRC_MASK : 0); + + if (--par->bit_cnt == 0) + { + /* par->sync = ! */ + rxput (minor, par->shift); + par->fcs = par->crc; + par->bit_cnt = 8; + par->frm_len++; + } + } + } + else + { + if (dcd) + { + if (par->dcd_cnt > DCDABORT) + par->dcd_cnt -= DCDABORT; + else + par->dcd_cnt = 0; + + if (par->dcd_cnt < DCDCOUNT) + { + par->dcd = FALSE; + } + } + + par->sync = FALSE; + } + } + } + } +} + +unsigned hdlc_get_word(int minor, __par_struct *par) +{ + int bit; + int cnt; + int shift; + + for (cnt = 16; cnt--; ) { + /* wenn wir Daten senden, muessen wir das Stuffing beruecksichtigen */ + if ( par->tx_idle == STUFF + && ( par->tx_state == TX_ACTIVE + || par->tx_state == TX_FLUSH)) + { + par->tx_bit ^= 1; + par->tx_idle = 0; + } else + { + if (!par->tx_bitcnt) + { + switch (par->tx_state) + { + case TX_DELAY: + if (par->tx_timer) + { + par->tx_shift = SDLC_FLAG; + par->tx_bitcnt = 8; + break; + } + par->tx_fcs = CRC_RESET; + par->tx_idle = 0; + par->tx_state = TX_ACTIVE; + + case TX_ACTIVE: + if (par->tx_ptr >= par->tx_buf + par->tx_len) { + par->tx_state = TX_FLUSH; + par->tx_shift = ~par->tx_fcs; + par->tx_bitcnt = 16; + par->tx_len = 0; + } else { + par->tx_shift = *par->tx_ptr++; + par->tx_bitcnt = 8; + } + break; + + case TX_FLUSH: + par->tx_timer = TAILTIME; + par->tx_state = TX_TAIL; + + case TX_TAIL: + par->tx_shift = SDLC_FLAG; + par->tx_bitcnt = 8; + break; + } + } + + if (par->tx_shift & 1) + par->tx_idle++; + else { + par->tx_bit ^= 1; + par->tx_idle = 0; + } + + par->tx_fcs = (par->tx_fcs >> 1) ^ ((par->tx_shift ^ + par->tx_fcs) & 1 ? CRC_MASK : 0); + + par->tx_shift >>= 1; + par->tx_bitcnt--; + } + + par->scr = (par->scr << 1) + | (bit = par->tx_bit + ^ !((UWORD) par->scr & 0x800) + ^ !( par->scr & 0x10000L)); + + shift >>= 1; + if (bit) + shift |= 0x8000; + } + + return(shift); +} + +/*** PAR RX *****************************************************************/ + +void par_rx(int minor) +{ + unsigned burstbuf; + int port_inp; + int port_out; + int cnt; + __par_struct *par = par96tab+minor; + + port_out = par->parbase; + port_inp = par->parbase+1; + /* Die Daten als Burst lesen, damit wieder Platz in der FIFO ist */ + for (cnt = 16; cnt--; ) + { + burstbuf >>= 1; + if (inp(port_inp) & RXD) + burstbuf |= 0x8000; + outp (port_out, PTT); + outp (port_out, PTT | BURST); + } + /* DCD fuer PicPar/PicPar97 */ + if (!(par->flags & MODE_c)) + par->dcd = inp (port_inp) & DCDBIT; + +#if 0 + hdlc_put_word(minor, par, burstbuf); +#endif +} + +/*** PAR TX *****************************************************************/ + +void par_tx(int minor) +{ + int bit; + int cnt; + int port_out; + unsigned shift; + __par_struct *par = par96tab+minor; + + port_out = par->parbase; + /* zuerst werden die vorbereiteten Daten gesendet */ + shift = par->burstbuf; + for (cnt = 16; cnt--; ) { + bit = shift & 1; + shift >>= 1; + outp(port_out, bit); + outp(port_out, bit | BURST); + } + +#if 0 + par->burstbuf = hdlc_get_word(minor, par); +#endif +} + +static void par_timer (UWORD ticks) +{ + __par_struct *par; + int minor; + + if (par_major == 0) + return; + + for (minor = 0, par = par96tab; minor < PARCHANS; minor++, par++) + if (par->l2port != -1) { + +#if 1 + hdlc_put_word(minor, par, hdlc_get_word(minor, par)); +#endif + + disable (); + + if (par->tx_timer) + if (par->tx_timer <= ticks) + { + par->tx_timer = 0; + + switch (par->tx_state) + { + case TX_DWAIT: + if ( (par->flags & MODE_d) + || ( (!par->dcd) + && ((rand()&0xff) <= par->persistance) + ) + ) { + par->tx_timer = not0(par->txdelay); + par->tx_state = TX_DELAY; + } else + par->tx_timer = not0(par->slottime); + break; + + case TX_TAIL: + outp(par->parbase, PTT | BURST); + par->tx_state = TX_IDLE; + } + } else + par->tx_timer -= ticks; + + enable (); + } +} + + +/*** PAR Interrupt **********************************************************/ + +void par_int(int minor) +{ + if (par96tab[minor].tx_state > TX_DWAIT) + par_tx(minor); + else + par_rx(minor); +} + +/* Defaultparameter setzen */ +static int par_init(void) +{ + char tmp[10]; + char *str; + __par_struct *par; + int minor; + unsigned parbase; + unsigned parirq; + int used; + + used = 0; + for (par = par96tab, minor = 0; minor < PARCHANS; minor++, par++) { + par->parbase = 0; + par->l2port = -1; + sprintf(tmp, "PAR%u", minor); + if ((str = getenv(tmp)) != NULL) { + parbase = parirq = 0; + sscanf(str, "%x,%u", &parbase, &parirq); + if (parbase && parirq) { + if ((parbuf = malloc(PAR_RXSIZE*sizeof(UWORD))) == NULL) + return(0); + parin = parout = parbuf; + if ((par->tx_buf = malloc(PAR_TXSIZE)) == NULL) + return(0); + par->tx_len = 0; + par->rxfhd = NULL; + + par->parirq = parirq; + par->parbase = parbase; + + disable(); /* Interrupt aus */ + allocirq(parirq, 0, par_int, 0); /* neuen Vektor setzen */ + par->paroldmask = getmask(parirq); + maskon(parirq); + enable(); + + printf("--- /dev/PAR%u (0x%03X,IRQ%u) detected.\n", minor, parbase, parirq); + + used++; + } + } + } + return(used); /* eine Karte gefunden/konfiguriert ? */ +} + +static void par_exit(void) +{ + __par_struct *par; + int minor; + + if (par_major) { + for (minor = 0, par = par96tab; minor < PARCHANS; minor++, par++) + if (par->parbase) { + if (par->l2port) par_detach(par->l2port); + if (par->paroldmask) maskoff(par->parirq); + freeirq(par->parirq); + } + } +} + +static int register_par(void) +{ + MAJOR *m; + + if (par_init()) { + m = register_major(); + m->name = "PAR96"; + m->exit = par_exit; + m->handle = par; + m->ctl = par_ctl; + m->dcd = par_dcd; + m->attach = par_attach; + m->detach = par_detach; + m->info = par_info; + m->timer = par_timer; + return(par_major = num_major); + } + return(0); +} + +#undef rxput +#undef rxeof +#undef rxdiscard + +/* End of os/go32/par.c */ diff --git a/os/go32/pc.h b/os/go32/pc.h new file mode 100755 index 0000000..d7ed119 --- /dev/null +++ b/os/go32/pc.h @@ -0,0 +1,83 @@ +/************************************************************************/ +/* */ +/* ***** ***** */ +/* ***** ***** */ +/* ***** ***** */ +/* ***** ***** */ +/* *************** *************** */ +/* ***************** ***************** */ +/* *************** *************** */ +/* ***** ***** TheNetNode */ +/* ***** ***** Portable */ +/* ***** ***** Network */ +/* ***** ***** Software */ +/* */ +/* File include/pc.h (maintained by: ???) */ +/* */ +/* This file is part of "TheNetNode" - Software Package */ +/* */ +/* Copyright (C) 1998 - 2008 NORD> +#include +#include + +unsigned char inportb (unsigned short _port); +void outportb (unsigned short _port, unsigned char _data); + +/* go32.c */ +void watch_dog_reset(int nix); +int _go32_dpmi_unchain_protected_mode_interrupt_vector(unsigned irq, + _go32_dpmi_seginfo *info); +void toggle_lpt (void); +void randomize (void); + +/* 16550.c */ +void rs232_int (int); +void clear_sio (int); +void exit_rs232 (void); + +#endif + +int maskoff(unsigned irq); +int maskon(unsigned irq); +int getmask(unsigned irq); +void setbit(unsigned port,unsigned char bits); +void clrbit(unsigned port,unsigned char bits); +void writebit(unsigned port,unsigned char mask,int val); +int allocirq(unsigned irq, int chain, void (*func)(int),int arg); +int freeirq(unsigned irq); +void eoi(void); + +/* End of include/pc.h */ diff --git a/os/go32/scc.c b/os/go32/scc.c new file mode 100755 index 0000000..6316c3d --- /dev/null +++ b/os/go32/scc.c @@ -0,0 +1,891 @@ +/************************************************************************/ +/* */ +/* ***** ***** */ +/* ***** ***** */ +/* ***** ***** */ +/* ***** ***** */ +/* *************** *************** */ +/* ***************** ***************** */ +/* *************** *************** */ +/* ***** ***** TheNetNode */ +/* ***** ***** Portable */ +/* ***** ***** Network */ +/* ***** ***** Software */ +/* */ +/* File os/go32/scc.c (maintained by: ???) */ +/* */ +/* This file is part of "TheNetNode" - Software Package */ +/* */ +/* Copyright (C) 1998 - 2008 NORD>> 8) + +#define set(var, bit) var |= (1 << bit) +#define res(var, bit) var &= ~(1 << bit) + +#define SCCDELAY inp (0xE4) /* non-existing port (2us) */ + +#ifndef outp +#define outp(p,b) outportb(p,b) +#endif +#ifndef inp +#define inp(p) inportb(p) +#endif + +#define WR0(val) outp ((SCCDELAY, scc->ctrl), val) +#define WR8(val) WR (8, val) +#define WR(reg, val) outp ((SCCDELAY, outp (scc->ctrl, reg), \ + SCCDELAY, scc->ctrl), val) + +#define RR0 inp ((SCCDELAY, scc->ctrl)) +#define RR8 inp ((SCCDELAY, scc->data)) +#define RR(reg) inp ((SCCDELAY, outp (scc->ctrl, reg), \ + SCCDELAY, scc->ctrl)) + +#define not0(par) (par ? par : 1) + +enum {TX_IDLE, TX_DWAIT, TX_DELAY, TX_ACTIVE, TX_FLUSH, TX_TAIL}; + +typedef struct __scc_struct +{ + int l2port; + + unsigned chan; + unsigned data, ctrl; + + unsigned baud; + + int flags; + + int dcd; + int rx_err; + unsigned rx_len; + + int tx_state; + unsigned tx_timer; + char *tx_buf; + char *tx_ptr; + int tx_len; + + MBHEAD *rxfhd; + + UBYTE rr0; + + unsigned errors; + + unsigned tailtime; + unsigned slottime; + unsigned persistance; + unsigned txdelay; + + unsigned overruns; + unsigned underruns; + unsigned crcerrors; + unsigned lenerrors; + unsigned buferrors; +} __scc_struct; + +typedef struct __scc_board { + char *name; + int chans; + unsigned base; + unsigned irq; + int data[SCCCHANS]; + int ctrl; +} __scc_board; + +static __scc_struct sccchans[SCCCHANS]; +static int scc_major = 0; + +static unsigned sccbase; +static unsigned sccirq; +static unsigned sccboard; +static int sccoldmask; +static unsigned sccminors; + +static UWORD *sccbuf, *sccin, *sccout; + +static __scc_board sccboardtab[] = +{ + {"DSCC", 8, 0x300, 7, {1, 0, 3, 2, 5, 4, 7, 6}, 16}, /* DSCC */ + {"OSCC", 4, 0x150, 3, {3, 1, 7, 5, 0, 0, 0, 0}, -1}, /* OSCC */ + {"USCC", 4, 0x300, 7, {0, 1, 2, 3, 0, 0, 0, 0}, 4}, /* USCC */ + {NULL , 0, 0, 0, {0, 0, 0, 0, 0, 0, 0, 0}, 0} +}; + +static void scc_int(int); +static void int_tx(__scc_struct *); +static void int_rx(__scc_struct *); +static void int_ex(__scc_struct *); +static void int_sp(__scc_struct *); +static void scc_clk (__scc_struct *, int); +static int scc_init(void); +static void scc_exit(void); +static void scc_timer(UWORD); + +/* Wenn der Sender keine Daten mehr ausstehen hat, wird ein weiteres + * Frame in den Sendebuffer kopiert. */ +static void scc_put_frame(__scc_struct *scc) +{ + MBHEAD *fbp; + int port; + LHEAD *l2flp; + + if (scc->tx_len == 0) { /* erst senden wenn alles raus ist */ + if ((port = scc->l2port) == -1) return; + if (kick[port]) { + /* ein weiteres Frame aus der Sendeliste holen */ + l2flp = &txl2fl[port]; + ulink((LEHEAD *)(fbp = (MBHEAD *) l2flp->head)); + kick[port] = ((LHEAD *)l2flp->head != l2flp); + + /* Frame aus dem Buffer in den SCC-Buffer kopieren. Hier wird + der Interrupt nicht gesperrt, da tx_len zuletzt und atomic + gesetzt wird. */ + scc->tx_len = cpymbflat(scc->tx_ptr = scc->tx_buf, fbp); + + relink((LEHEAD *)fbp, /* als gesendet betrachten und in */ + (LEHEAD *)stfl.tail); /* die gesendet Liste umhaengen */ + + /* Wenn der sender noch nicht an ist, starten wir die Kanal- + Arbitrierung, ansonsten stoppen wir ein eventuelles TXTAIL + und gehen wieder zum senden ueber. */ + + disable(); + switch (scc->tx_state) { + case TX_IDLE: + scc->tx_timer = scc->flags & MODE_d ? 1 : not0 (scc->slottime); + scc->tx_state = TX_DWAIT; + break; + + case TX_TAIL: + scc->tx_timer = 1; + scc->tx_state = TX_DELAY; + } + enable(); + } + } +} + +/* Der SCC-Empfangs-Ringbuffer wird geleert. Dort werden von allen Kanaelen + * Empfangsdaten gesammelt. Das Format entspricht dem alten l1put(). + */ +static void scc_get_frame(void) +{ + int port, len; + MBHEAD **rxfbpp; + unsigned action; + __scc_struct *scc; + + LOOP { + disable(); + if (sccout == sccin) { + enable(); + break; + } + action = *sccout++; /* Zeichen aus dem Ringbuffer lesen */ + if (sccout >= sccbuf+SCC_RXSIZE) + sccout = sccbuf; + enable(); + + scc = sccchans + ((action>>8) & 0x7F); + + if ((port = scc->l2port) == -1) + continue; + + rxfbpp = &scc->rxfhd; /* Adresse RX-Framezeiger */ + if (!(action & 0x8000)) /* Zeichen oder Befehl ? */ + { /* Zeichen : */ + if (!*rxfbpp) /* RX-Frame aktiv ? */ + { + *rxfbpp = (MBHEAD *)allocb(ALLOC_MBHEAD); /* nein - neues anlegen */ + (*rxfbpp)->l2port = port; /* fuer port */ + } + putchr(action & 0xFF,*rxfbpp); /* Zeichen in Frame */ + } + else /* Befehl : */ + if (*rxfbpp) /* nur wenn Frame aktiv */ + { /* Befehl ausfuehren */ + if (action & 0x0001) /* Frame in Muelleimer */ + relink((LEHEAD *)*rxfbpp, (LEHEAD *)trfl.tail); + else { /* Frame in RX-Liste */ + len = (action>>1)&3; + if ((*rxfbpp)->mbpc > len) /* FCS eleminieren */ + (*rxfbpp)->mbpc -= len; /* das erste Byte kommt */ + /* noch vor HUNT */ + relink((LEHEAD *)*rxfbpp, (LEHEAD *)rxfl.tail); + } + *rxfbpp = NULL; /* kein RX-Frame aktiv */ + } + } +} + +static void scc(void) +{ + __scc_struct *scc; + + if (scc_major == 0) + return; + + scc_get_frame(); + for (scc = sccchans; scc < sccchans+sccminors; scc++) { + scc_put_frame(scc); + } +} + +static WORD scc_dcd(PORTINFO *port) +{ + __scc_struct *scc; + int state = 0; + + scc = &sccchans[port->minor]; + + if (scc->tx_state) + state |= PTTFLAG; + if (scc->dcd) + state |= DCDFLAG; + return(state); +} + +static void scc_ctl(int req, int port) +{ + __scc_struct *scc; + int minor; + PORTINFO *p; + + p = portpar+port; + minor = p->minor; + scc = &sccchans[minor]; + + switch (req) { + case L1CCMD : + case L1CRES : + if (p->speed > 384) + p->speed = 384; + if (p->speed < 3) + p->speed = 3; + scc->baud = (unsigned) (p->speed * 100); + scc->slottime = p->slottime; + scc->persistance = p->persistance; + scc->txdelay = p->txdelay; + scc->tailtime = p->speed == 3 ? 4 : TAILTIME; + scc->flags = p->l1mode; + + WR (4, SDLC); + WR (10, scc->flags & MODE_z ? NRZ | ABUNDER : NRZI | ABUNDER); + WR (7, SDLC_FLAG); + WR (3, RX_DIS); + WR (5, TX_DIS); + + scc_clk (scc, scc->tx_state != TX_IDLE); + + WR (3, RX_EN); + WR (5, scc->flags & MODE_t ? TX_EN : TX_DIS); + + WR (15, SYNC_IE | DCD_IE); + WR0 (RES_EX_INT); + WR0 (RES_EX_INT); + WR (1, EX_IE | TX_IE | RX_IE); + + scc->rr0 = RR0; + + /* nochmal zur Sicherheit den CHIP-interrupt-master-enable an */ + WR (2, (scc->chan>>1) << 4); + WR (9, MINT_EN); + break; + } + default_l1ctl(req, port); /* Flags loeschen */ +}; + +static int scc_istome(int major, char *devname) +{ + char name[21], *cp; + int minor = 0; + + strncpy(name, devname, 20); /* Minor bestimmen und abschneiden */ + name[20] = 0; + for (cp = name; isalpha(*cp); cp++); /* Zahl suchen */ + if (isdigit(*cp)) minor = atoi(cp); + *cp = 0; /* kann nicht schaden */ + + if (minor < 0 || minor >= sccminors) + return(NO_MINOR); /* falscher Geraetekanal (minor) */ + + return(minor); +} + +static int scc_attach(int port, int minor, BOOLEAN check_only) +{ + __scc_struct *scc; + + scc = &sccchans[minor]; + + if (scc_major) { + if (scc->l2port == -1) { + if (!check_only) { + scc->l2port = port; + portpar[port].minor = minor; + scc_ctl(L1CRES, port); + } + return(1); + } + if (scc->l2port == port) + return(1); + } + return(0); /* versuchte Doppeleintragung */ +} + +static int scc_detach(int port) +{ + __scc_struct *scc = &sccchans[portpar[port].minor]; + + WR (1, 0); + + if (scc->rxfhd) { + dealmb(scc->rxfhd); + scc->rxfhd = NULL; + } + scc->l2port = -1; + return(1); +} + +static void scc_info(int what, int port, MBHEAD *mbp) +{ + int minor, cnt; + __scc_struct *scc; + + minor = portpar[port].minor; + + switch (what) { + case HW_INF_IDENT : + case HW_INF_INFO : + putprintf(mbp, "%s%u", sccboardtab[sccboard].name, minor); + break; + case HW_INF_STAT : + for (minor = cnt = 0, scc = sccchans; minor < sccminors; minor++, scc++) + if (scc->l2port != -1) { + if (cnt++ == 0) + putstr("\rSCC-Statistics:\r\r", mbp); + putprintf(mbp, " SCC%u RxOvr: %5u TxUnd: %5u RxCRC: %5u RxBuf: %5u\r", + minor, scc->overruns, scc->underruns, scc->crcerrors, scc->buferrors); + } + break; + case HW_INF_CLEAR : + scc = &sccchans[minor]; + scc->overruns = + scc->underruns = + scc->crcerrors = + scc->lenerrors = + scc->buferrors = 0; + /* durchfallen */ + default : + default_l1info(what, port, mbp); + } +} + +/* SCC-Modes: + t -> Sendetakt extern (DF9IC) + e -> Sendetakt BRG (32-fach) + -> Sendetakt DPLL (32-fach) + r -> Empfangstakt extern (DF9IC) + -> Empfangstakt DPLL +*/ + +static void sccput(UWORD action) +{ + *sccin++ = action; + if (sccin >= sccbuf+SCC_RXSIZE) + sccin = sccbuf; +} + +#define rxput(port, val) sccput (((port) << 8) | (val)) +#define rxeof(port, fcs) sccput (((port) << 8) | 0x8000 | (fcs<<1)) +#define rxdiscard(port) sccput (((port) << 8) | 0x8001) + +/*** SCC Clock **************************************************************/ + +static void scc_clk (__scc_struct *scc, int tx_on) +{ + UWORD tconst; + + if (scc->flags & MODE_t) /* externer Takt */ + { + WR (11, TRxC_RTxC); + WR (14, DPLL_DIS); + } + else + { + tconst = PCLK / 64L / scc->baud; + if (tx_on) + tconst *= 32; + tconst -= 2; + + WR (12, LOBYTE (tconst)); + WR (13, HIBYTE (tconst)); + + WR (11, tx_on ? DPLL_BRG | TRxOUT_BRG + : (scc->flags & MODE_e ? DPLL_RTxC | TRxOUT_BRG + : DPLL_RTxC | TRxOUT_DPLL)); + + WR (14, DPLL_SRCBRG); + if ((scc->flags & MODE_z) == 0) WR (14, DPLL_NRZI); + WR (14, DPLL_EN); + } +} + +/*** SCC TX *****************************************************************/ + +static void scc_tx (__scc_struct *scc, int tx_on) +{ + /* wenn MODE_t nicht gesetzt ist, muessen wir bei TX umschalten */ + if ((scc->flags & MODE_t) == 0) + { + WR (3, RX_DIS); + WR (5, TX_DIS); + + scc_clk (scc, tx_on); + + if (tx_on) + WR (5, TX_EN | RTS); + else + WR (3, RX_EN); + } + else + WR (5, tx_on ? TX_EN | RTS : TX_EN); +} + +/*** Timer ******************************************************************/ + +static void scc_timer (UWORD ticks) +{ + __scc_struct *scc; + + if (scc_major == 0) + return; + + for (scc = sccchans; scc < sccchans+sccminors; scc++) + if (scc->l2port != -1) + { + disable (); + + if (scc->tx_timer) + { + if (scc->tx_timer <= ticks) + { + scc->tx_timer = 0; + + switch (scc->tx_state) + { + case TX_DWAIT: + if ( (scc->flags & MODE_d) + || ( (!scc->dcd) + && ((rand()&0xff) <= scc->persistance) + ) + ) + { + scc_tx(scc, TRUE); + scc->tx_timer = not0(scc->txdelay); + scc->tx_state = TX_DELAY; + } + else + scc->tx_timer = not0(scc->slottime); + break; + + case TX_DELAY: + WR0 (RES_TX_CRC); + WR8 (*scc->tx_ptr++); + WR0 (RES_EOM); + scc->tx_state = TX_ACTIVE; + break; + + case TX_TAIL: + scc_tx(scc, FALSE); + scc->tx_state = TX_IDLE; + } + } + else + scc->tx_timer -= ticks; + } + enable (); + } +} + +/*** SCC Interrupt **********************************************************/ + +static void (*handler[]) (__scc_struct *) = {int_tx, int_ex, int_rx, int_sp}; + +//#define DEBUG(x) _farpokeb(_dos_ds,0xB8000, x); + +static void scc_int(int foo) +{ + __scc_struct *scc; + UBYTE rr2; + + //DEBUG(ch++); + + for (scc = sccchans; scc < sccchans+sccminors; ) + if (RR (3)) + { + scc++; + rr2 = RR (2); + handler[(rr2 >> 1) & 3] (&sccchans[(rr2 >> 3) ^ 1]); + scc = sccchans; + } + else + scc += 2; +} + +/*** TX Handler *************************************************************/ + +static void int_tx(__scc_struct *scc) +{ + switch (scc->tx_state) + { + case TX_ACTIVE: + if (RR0 & TX_EOM) + { + scc->underruns++; + scc->errors++; + scc->tx_ptr = scc->tx_buf; /* txrewind */ + scc->tx_state = TX_FLUSH; + } + else + if (scc->tx_ptr >= scc->tx_buf + scc->tx_len) /* Frameende? */ + { + WR (10, scc->flags & MODE_z ? NRZ : NRZI); + WR0 (RES_TX_IP); + scc->tx_state = TX_FLUSH; + scc->tx_len = 0; /* Frame gesendet */ + } else + WR8 (*scc->tx_ptr++); + break; + + case TX_FLUSH: + WR (10, scc->flags & MODE_z ? NRZ | ABUNDER : NRZI | ABUNDER); + + if (scc->tx_ptr < scc->tx_buf + scc->tx_len) /* noch Daten? */ + { + WR0 (RES_TX_CRC); + WR8 (*scc->tx_ptr++); + WR0 (RES_EOM); + scc->tx_state = TX_ACTIVE; + } + else + { + WR0 (RES_TX_IP); + scc->tx_timer = scc->tailtime; /* + clkstep */ + scc->tx_state = TX_TAIL; + } + } +} + +/*** Extern Status Change ***************************************************/ + +static void int_ex (__scc_struct *scc) +{ + static UBYTE rr0, delta; + + delta = (rr0 = RR0) ^ scc->rr0; + + if (scc->l2port != -1) + { + if (scc->rx_len && rr0 & (ABORT | HUNT)) + { + rxdiscard (scc->chan); + scc->rx_len = 0; + scc->rx_err = FALSE; + } + + if (delta & (scc->flags & MODE_c ? HUNT : DCD)) + { + scc->dcd = (scc->flags & MODE_c) + ? (!(rr0 & HUNT)) + : (rr0 & DCD); + } + } + + scc->rr0 = rr0; + WR0 (RES_EX_INT); +} + +/*** RX Handler *************************************************************/ + +static void int_rx (__scc_struct *scc) +{ + UBYTE rr8; + + rr8 = RR8; + + if (!scc->rx_err) + { + /* scc->rx_err = */ rxput (scc->chan, rr8); + scc->rx_len++; + } +} + +/*** Special RX Condition ***************************************************/ + +static void int_sp (__scc_struct *scc) +{ + UBYTE rr1; + + rr1 = RR (1); + RR8; + + if (rr1 & RX_OVR) + { + scc->overruns++; + scc->errors++; + scc->rx_err = TRUE; + } + + if (rr1 & SDLC_EOF) + { + if ( !scc->rx_err + && scc->rx_len >= MIN_LEN+1 + && (rr1 & (CRC_ERR | RESIDUE)) == RES8) + { + rxeof (scc->chan, 1); + } + else + if (scc->rx_len) { + rxdiscard (scc->chan); + /*if (scc->rx_len > 2) { + if (scc->rx_len < MIN_LEN+1) scc->lenerrors++; + if ((rr1 & (CRC_ERR | RESIDUE)) != RES8) scc->crcerrors++; + }*/ + } + scc->rx_len = 0; + scc->rx_err = FALSE; + } + + WR0 (RES_ERR); +} + +/*** SCC Hardware Reset *****************************************************/ + +static void scc_hw_reset (void) +{ + __scc_struct *scc; + UWORD delay; + + for (scc = sccchans; scc < &sccchans[sccminors]; scc += 2) + { + RR0; + WR (9, HW_RES); + for (delay = 100; delay--;) SCCDELAY; + } +} + +/*** SCC Detect *************************************************************/ +static int scc_detect(int max) +{ + __scc_struct *scc; + + for (scc = sccchans; scc < sccchans+max; scc++) + { + RR0; + WR (13, 0x55); if (RR (13) != 0x55) break; + WR (13, 0xAA); if (RR (13) != 0xAA) break; + } + return((int) (scc - sccchans)); +} + +/* Boardtyp auswaehlen, Defaultparameter setzen */ +static int scc_init(void) +{ + char *str; + __scc_board *board; + __scc_struct *scc; + int chan; + + for (sccboard = 0, board = sccboardtab; board->name; board++, sccboard++) { + if ((str = getenv(board->name)) != NULL) { + sccbase = board->base; + sccirq = board->irq; + sscanf(str, "%x,%u", &sccbase, &sccirq); + if (sccbase && sccirq) { + + if ((sccbuf = malloc(SCC_RXSIZE*sizeof(UWORD))) == NULL) + return(0); + + sccin = sccout = sccbuf; + + for (chan = 0, scc = sccchans; chan < SCCCHANS; chan++, scc++) { + scc->l2port = -1; + scc->rxfhd = NULL; + scc->chan = chan; + scc->data = sccbase + board->data[chan]; + scc->ctrl = scc->data + board->ctrl; + if ((scc->tx_buf = malloc(SCC_TXSIZE)) == NULL) { + while (--scc >= sccchans) + free(scc->tx_buf); + free(sccbuf); + return(0); + } + scc->tx_len = 0; + } + + scc_hw_reset(); + + disable(); /* Interrupt aus */ + allocirq(sccirq, 0, scc_int, 0); /* neuen Vektor setzen */ + sccoldmask = getmask(sccirq); + maskon(sccirq); + enable(); + + xprintf("--- /dev/SCC (0x%03X,IRQ%u), ", sccbase, sccirq); + sccminors = scc_detect(board->chans); + if ((sccminors & 1) == 0) { + if (sccminors) { + printf("card is %s, %u channels\n", board->name, sccminors); + return(1); + } else xprintf("%s not detected\n", board->name); + } else xprintf("channel number is odd\n"); + } + } + } + return(0); /* keine Karte gefunden/konfiguriert */ +} + +static void scc_exit(void) +{ + if (scc_major) { + if (sccoldmask) maskoff(sccirq); + freeirq(sccirq); + scc_hw_reset(); + } +} + +static int register_scc(void) +{ + MAJOR *m; + + if (scc_init()) { + m = register_major(); + m->name = "USCC/DSCC/OSCC"; + m->istome = scc_istome; + m->exit = scc_exit; + m->handle = scc; + m->ctl = scc_ctl; + m->dcd = scc_dcd; + m->attach = scc_attach; + m->detach = scc_detach; + m->info = scc_info; + m->timer = scc_timer; + return(scc_major = num_major); + } + return(0); +} + +/* End of os/go32/scc.c */ diff --git a/os/go32/tcp.c b/os/go32/tcp.c new file mode 100755 index 0000000..db678fa --- /dev/null +++ b/os/go32/tcp.c @@ -0,0 +1,329 @@ +/************************************************************************/ +/* */ +/* ***** ***** */ +/* ***** ***** */ +/* ***** ***** */ +/* ***** ***** */ +/* *************** *************** */ +/* ***************** ***************** */ +/* *************** *************** */ +/* ***** ***** TheNetNode */ +/* ***** ***** Portable */ +/* ***** ***** Network */ +/* ***** ***** Software */ +/* */ +/* File os/go32/tcp.c (maintained by: DAA531) */ +/* */ +/* This file is part of "TheNetNode" - Software Package */ +/* */ +/* Copyright (C) 1998 - 2008 NORD>actively == FALSE) + { + /* Interface, L2Port setzen. */ + printf("--- TCPIP Initialisieren KissType %d\n", Interface); + tpoi->actively = FALSE; + tpoi->l2port = EOF; + + /* Um ein erhoehen. */ + numactive++; + } /* Interface ist schon belegt. */ + } /* Ungueltiges Interface. */ + } /* for */ + + return(numactive); +} + +/************************************************************************/ +/* Level1 Exit */ +/************************************************************************/ +static void ExitL1TCP(void) +{ + T_INTERFACE *tpoi; + register int i; + + for (i = 0; i < MAXINTERFACE; i++) + { + tpoi = &ifp[i]; + + L1ExitTCP(tpoi->Interface); + } +} + +/* DCD-Status liefern. */ +static WORD DcdL1TCP(PORTINFO *port) +{ + /* Sender ist immer frei. */ + return(FALSE); +} + +static void CtlL1TCP(int req, int port) +{ + switch (req) + { + case L1CCMD : + case L1CRES : + break; + } + + default_l1ctl(req, port); /* Flags loeschen */ +}; + + +static int IstomeL1TCP(int major, char *devname) +{ + char name[20 + 1]; + + strncpy(name, devname, 20); /* Minor bestimmen und abschneiden */ + name[20] = 0; + +#ifdef L1TELNET + if (strnicmp(name, "TELNET", strlen(name))==0) + return(TEL_ID); +#endif /* L1TELNET */ + +#ifdef L1HTTPD + if (strnicmp(name, "HTTPD", strlen(name))==0) + return(HTP_ID); +#endif /* L1HTTPD */ + +#ifdef L1IPCONV + if (strnicmp(name, "IPCONV", strlen(name))==0) + return(CVS_ID); +#endif /* L1IPCONV */ + +#ifdef L1IRC + if (strnicmp(name, "IRC", strlen(name))==0) + return(IRC_ID); +#endif /* L1IPCONV */ + + return(NO_MINOR); +} + +static int AttachL1TCP(int port, int minor, BOOLEAN check_only) +{ + /* Zeiger auf das aktuelle Interface. */ + T_INTERFACE *tpoi = &ifp[minor]; + + if (tpoi->actively == FALSE) + { + if (tpoi->l2port == EOF) + { + if (!check_only) + { + if (!L1InitTCP(tpoi->Interface, port, tpoi->tcpport)) + return(FALSE); + + portpar[port].minor = minor; + } + + return(1); + } + + if (tpoi->l2port == port) + return(1); + } + + return(0); /* versuchte Doppeleintragung */ +} + +static int DetachL1TCP(int port) +{ + /* Zeiger auf das aktuelle Interface. */ + T_INTERFACE *tpoi = &ifp[portpar[port].minor]; + + /* Port deaktivieren. */ + tpoi->l2port = EOF; + /* Schliesse Interface. */ + L1ExitTCP(tpoi->Interface); + return(TRUE); +} + +static void InfoL1TCP(int what, int port, MBHEAD *mbp) +{ + /* Zeiger auf das aktuelle Interface. */ + T_INTERFACE *tpoi = &ifp[portpar[port].minor]; + + switch (what) + { + case HW_INF_IDENT : + case HW_INF_INFO : + putprintf(mbp, "%s %u", tpoi->name, Htons(tpoi->tcpport)); + break; + + case HW_INF_STAT : + case HW_INF_CLEAR : + break; + /* durchfallen */ + + default: + default_l1info(what, port, mbp); + } +} + +/* Pruefe auf TCP-Port. */ +int CheckPortTCP(int port) +{ + /* Inetrface ermitteln. */ + T_INTERFACE *tpoi = &ifp[portpar[port].minor]; + + /* Nur wenn aktiv. */ + if (tpoi->actively == TRUE) + { + switch (tpoi->Interface) + { +#ifdef L1TELNET + case KISS_TELNET : + if (tpoi->l2port == port) + return(TRUE); +#endif /* L1TELNET */ + +#ifdef L1HTTPD + case KISS_HTTPD : + if (tpoi->l2port == port) + return(TRUE); +#endif /* L1HTTPD */ + +#ifdef L1IPCONV + case KISS_IPCONV : + if (tpoi->l2port == port) + return(TRUE); +#endif /* L1IPCONV */ + +#ifdef L1IRC + case KISS_IRC : + if (tpoi->l2port == port) + return(TRUE); +#endif /* L1IRC */ + + /* Ungueltiges Interface. */ + default : + return(FALSE); + } /* switch. */ + } + else + return(FALSE); +} + + +static int RegisterTCP(void) +{ + MAJOR *m; + + if (InitL1TCP()) { + m = register_major(); + m->name = "TCPIP"; + m->istome = IstomeL1TCP; + m->exit = ExitL1TCP; + m->ctl = CtlL1TCP; + m->dcd = DcdL1TCP; + m->attach = AttachL1TCP; + m->detach = DetachL1TCP; + m->info = InfoL1TCP; + return(num_major); + } + return(0); +} + +#endif /* TCP_STACK */ +/*----------------------------------------------------------------------*/ + +/* End of os/go32/tcp.c */ diff --git a/os/go32/tokenrng.c b/os/go32/tokenrng.c new file mode 100755 index 0000000..7ce5bed --- /dev/null +++ b/os/go32/tokenrng.c @@ -0,0 +1,643 @@ +/************************************************************************/ +/* */ +/* ***** ***** */ +/* ***** ***** */ +/* ***** ***** */ +/* ***** ***** */ +/* *************** *************** */ +/* ***************** ***************** */ +/* *************** *************** */ +/* ***** ***** TheNetNode */ +/* ***** ***** Portable */ +/* ***** ***** Network */ +/* ***** ***** Software */ +/* */ +/* File os/go32/tokenrng.c (maintained by: ???) */ +/* */ +/* This file is part of "TheNetNode" - Software Package */ +/* */ +/* Copyright (C) 1998 - 2008 NORD> (token_sent + TOKENTIMEOUT)) /* Tokenring im Timeout */ + { + clear_rs232(tkcom); /* RS232 Buffer loeschen */ + clear_rs232(tkcom); /* RS232 Buffer loeschen */ + clear_rs232(tkcom); /* RS232 Buffer loeschen */ + rx_state = 0; /* RX-State auf FEND */ + + if (lost_token++ >= 400) + HALT("tokenring"); /* Rechner neu starten */ + + if ((lost_token % 100) == 0) /* neue Baudrate probieren */ + { + switch (tkbaud) + { + case 96: tkbaud = 192; break; /* no luck, try 19200 Baud */ + case 192: tkbaud = 384; break; /* no luck, try 38400 Baud */ + case 384: tkbaud = 96; break; /* go back to 9600 Baud */ + } + setbaud(tkcom, tkbaud); + xprintf ("*** Autobaud - Token ring: %u00 bit/s. \n",tkbaud); + } + + send_token(); /* Neues Token auf den Ring legen */ + token_sent = tic10; /* Zeit merken wann Token gesendet */ + recovery_count++; /* Dieser Wert wird auch bei STAT angezeigt! */ + + for (port = 0; port < L2PNUM; port++) + if (portpar[port].major == tok_major) + commandflag[port] = TRUE; /* neue Parameter an TNC, RESET.. */ + tr_cmd = 2; /* Flag setzen "es ist was zu tun" */ + + if (!incnt && show_recovery == TRUE) + { + xprintf("*** Token-Recovery (%ld) : %s", lost_token, ctime(&sys_time)); + notify(1, "*** Token-Recovery (%lu)", lost_token); + } + } + } + else + lost_token = 0; +} + +/************************************************************************/ +/* tokenring_put_frame() - Frame(s) im Ringpuffer ablegen */ +/* Beschleunigte Variante nach DL1XAO */ +/*----------------------------------------------------------------------*/ +static void tokenring_put_frame(void) +{ + int port; + UBYTE ch, *out; + WORD *kp = kick; + PORTINFO *pp = portpar; + LHEAD *l2flp = txl2fl; + MBHEAD *txfhdl; + + for (port = 0; port < L2PNUM; port++, pp++, kp++, l2flp++) { + if ( pp->major != tok_major + || *kp == FALSE ) /* Port hat nichts zum Senden */ + continue; + + cd_timer[port] = tic10; /* Wir senden, Belegt-Timer starten */ + + ulink((LEHEAD *)(txfhdl = (MBHEAD *) l2flp->head));/*Zeiger holen*/ + TX_BEG(); /* Sender bereit */ + TX_CHAR(FEND); /* Frame beginnt */ + TX_CHAR(port); /* Port */ + TX_CHAR(0x00); /* Datenframe */ + while (txfhdl->mbgc < txfhdl->mbpc) /* solange Daten vorhanden sind */ + switch(ch = getchr(txfhdl)) { + case FEND: TX_CHAR(FESC); + TX_CHAR(TFEND); + break; + case FESC: TX_CHAR(FESC); + TX_CHAR(TFESC); + break; + + default: TX_CHAR(ch); + } + + TX_CHAR(FEND); /* Frame bendet */ + rs232_write(tkcom, blkbuf, out); /* und senden... */ + + relink((LEHEAD *)txfhdl, /* als gesendet betrachten und in */ + (LEHEAD *)stfl.tail); /* die gesendet Liste umhaengen */ + + *kp = (l2flp->head != l2flp); + } /* for */ +} + +/************************************************************************/ +/* tokenring_get_frame() - Frame(s) aus Ringbuffer holen */ +/*----------------------------------------------------------------------*/ +static void tokenring_get_frame(void) +{ + static WORD k; + static int port; + static MBHEAD *rxfhd = NULL; + UBYTE ch, *in = blkbuf; + int n; + + n = rs232_read(tkcom, blkbuf, BLOCKSIZE); + while (n) { /* Zeichen auswerten */ + ch = *in++; /* Zeichen holen */ + n--; + switch (rx_state) /* ueber Status verzweigen */ + { + case WFEND: /* Frame Anfang erwartet */ + if (ch == FEND) + rx_state = GPORT; /* Frameanfang entdeckt */ + continue; + + case GPORT: + switch (ch) /* zuletzt FEND bekommen */ + { + case FEND: continue; /* noch ein FEND: uebergehen */ + + case 0xFF: rx_state = TOKEN; /* Token Anfang */ + continue; + + default: port = ch & 0x7F; /* Port von TNC */ + +/* Ueberpruefen ob der Port ueberhaupt gueltig ist */ + if ( ( port >= L2PNUM + || portpar[port].major != tok_major) + && portpar[port].major != NO_MAJOR) + { + rx_state = WFEND; /* wieder auf Frame warten */ + bad_frames++; + continue; /* gleich abbrechen.. */ + } + rx_state = GTYPE; /* next state: */ + } + continue; + + case GTYPE: /* Port bekannt: */ + switch (ch) /* nun auswerten... */ + { + case 0x00: rx_state = GFRAM; /* es folgen [].. */ + if (rxfhd) /* wenn Frame aktiv, auf den Muell */ + relink((LEHEAD *)rxfhd, (LEHEAD *)trfl.tail); + (rxfhd = (MBHEAD *)allocb(ALLOC_MBHEAD))->l2port = port; + continue; + + case 0x0C: k = 0; /* Port hat RESET gemacht */ + rx_state = RESET; + continue; + + case 0x0E: rx_state = DAMAP; /* DAMA Frame sent, PTT */ + continue; + + default: rx_state = WFEND; /* Kommando unbekannt. */ + } + continue; + + case GFRAM: /* vom TNC holen */ + switch (ch) + { + case FEND: /* nur wenn Frame aktiv, */ + if (rxfhd) { /* Befehl ausfuehren */ + relink((LEHEAD *)rxfhd, (LEHEAD *)rxfl.tail); + rxfhd = NULL; /* kein RX-Frame aktiv */ + } + rx_state = WFEND; /* Das war's.. fertig! */ + continue; + + case FESC: rx_state++; /* FESC wird zu FESC-TFESC */ + continue; /* Rueckwandlung.. */ + + } /* noch mehr... */ + break; + + case GFRMT: + switch (ch) /* TFEND/TFESC-Rueckwandlung */ + { + case TFEND: ch = FEND; + break; + + case TFESC: ch = FESC; + break; + + default: rx_state = WFEND; + continue; + } + rx_state--; + break; + + case TOKEN: /* Token-Anfang gefunden */ + switch (ch) /* wird immer an Port 0xff gesendet */ + { + case 6: rx_state = TOKN2; /* Token OK */ + continue; + default: rx_state = WFEND; /* ungueltig, kein Token! */ + } + continue; + + case TOKN2: + if (ch == FEND) /* gueltiges Token empfangen */ + { + token_count++; + + if (tr_res) /* Ist TNC zu resetten? */ + tokenring_reset_tnc(); + + if (tr_cmd) + if (--tr_cmd == 0) /* Ist TNC zu konfigurieren? */ + tokenring_config_tnc(); + + if (tr_tst) /* Test-Folge zu senden? */ + tokenring_send_test(); + + tokenflag = TRUE; + tokenring_put_frame(); + send_token(); + token_sent = tic10; /* Zeit merken */ + } + rx_state = WFEND; + continue; + + case RESET: /* Port hat RESET gemacht */ + switch (ch) + { + case FEND: tr_cmd = commandflag[port] = TRUE; + portstat[port].reset_count++; + rx_state = WFEND; + continue; + + default: if (++k > 6) + rx_state = WFEND; + } + continue; + + case DAMAP: /* DAMA Frame gesendet, PTT */ + if (ch == FEND) + cd_timer[port] = 0; /* Kanal frei: Timer stoppen */ + rx_state = WFEND; + continue; + + } /* switch(rxstate) */ + + putchr(ch, rxfhd); /* Zeichen in Frame */ + + if (rxfhd->mbpc > L2MFLEN) /* Framelaengencheck */ + rx_state = WFEND; + } +} + +/************************************************************************/ +/* Token auf Ring legen */ +/*----------------------------------------------------------------------*/ +void send_token(void) +{ + static UBYTE token[6] = { FEND, 0xFF, 0x06, FEND, 0, 0 }; + rs232_write(tkcom, token, &token[4]); +} + +/************************************************************************/ +/* Jeden TNC mit Parametern versorgen */ +/*----------------------------------------------------------------------*/ +void tokenring_config_tnc(void) +{ + UBYTE port, *out; + WORD *cf = commandflag; + PORTINFO *pp = portpar; + + for (port = 0; port < L2PNUM; port++, pp++, cf++) { + if ( pp->major != tok_major + || *cf != TRUE /* der nicht... */ + ) + continue; /* ..ueberspringen */ + + TX_BEG(); /* Sendung starten */ + TX_CHAR(FEND); /* TX-Delay einstellen */ + TX_CHAR(port); + TX_CHAR(1); + TX_CHAR(pp->txdelay); + TX_CHAR(FEND); + TX_CHAR(FEND); /* Persistance einstellen */ + TX_CHAR(port); + TX_CHAR(2); + TX_CHAR(pp->persistance); + TX_CHAR(FEND); + TX_CHAR(FEND); /* Slottime einstellen */ + TX_CHAR(port); + TX_CHAR(3); + TX_CHAR(pp->slottime); + TX_CHAR(FEND); + TX_CHAR(FEND); /* Tailtime einstellen */ + TX_CHAR(port); + TX_CHAR(4); + TX_CHAR(TAILTIME); + TX_CHAR(FEND); + TX_CHAR(FEND); /* Fullduplex an/aus */ + TX_CHAR(port); + TX_CHAR(5); + TX_CHAR((pp->l1mode & MODE_d) != 0 ? 1 : 0); + TX_CHAR(FEND); + TX_CHAR(FEND); /* DAMA an/aus */ + TX_CHAR(port); + TX_CHAR(6); + TX_CHAR(dama(port) ? 1 : 0); + TX_CHAR(FEND); + rs232_write(tkcom, blkbuf, out); /* und senden... */ + *cf = FALSE; + } + tr_cmd = 0; +} + + +/************************************************************************/ +/* Reset Befehl an alle TNCs geben */ +/*----------------------------------------------------------------------*/ +static void tokenring_reset_tnc(void) +{ + int port; + UBYTE *out; + PORTINFO *pp = portpar; + + for (port = 0; port < L2PNUM; port++, pp++) /* Alle TNCs durchgehen */ + { + if ( pp->major != tok_major + || pp->reset_port != TRUE /* soll dieser Reset bekommen? */ + ) + continue; + + TX_BEG(); + TX_CHAR(FEND); + TX_CHAR(port); + TX_CHAR(0x0D); + TX_CHAR(FEND); + rs232_write(tkcom, blkbuf, out); /* und senden... */ + pp->reset_port = FALSE; + } + tr_res = FALSE; /* RESET erledigt... */ +} + +/************************************************************************/ +/* TEST-Befehl ausfuehren, dazu 4 KByte L/H-Folgen senden (Keine Flags!)*/ +/*----------------------------------------------------------------------*/ +void tokenring_send_test(void) +{ + UBYTE port, *out; + WORD *tf = testflag; + UWORD count; + PORTINFO *pp = portpar; + + for (port = 0; port < L2PNUM; port++, pp++, tf++) { + if ( pp->major != tok_major /* Nicht fuer uns... */ + || *tf != TRUE /* der nicht... */ + ) + continue; /* ..ueberspringen */ + + TX_BEG(); + TX_CHAR(FEND); + TX_CHAR(port); /* der TEST Port */ + TX_CHAR(0x00); + rs232_write(tkcom, blkbuf, out); /* und senden... */ + + count = pp->speed / 8 * 10; /* 10 sec lang */ + if (count < 1024) + count = 1024; + + memset(blkbuf, 0x00, (size_t)(BLOCKSIZE - 2)); + + while (count) { /* und senden... */ + if (count > BLOCKSIZE - 2) { + rs232_write(tkcom, blkbuf, &blkbuf[BLOCKSIZE - 1]); + count -= (BLOCKSIZE - 2); + } + else { + out = &blkbuf[count]; + TX_CHAR(FEND); + count = 0; + } + } + + TX_CHAR(FEND); + rs232_write(tkcom, blkbuf, out); + + *tf = FALSE; /* TEST erledigt.. */ + } + tr_tst = FALSE; +} + +static WORD tokenring_dcd(PORTINFO *port) +{ + int minor = port->minor; + ULONG *cdt; + + cdt = &cd_timer[minor]; + + if ( dama(minor) + && *cdt) { /* belegt.. */ + if ((tic10 - *cdt) > CD_TIMEOUT) /* Timeout abgelaufen? */ + *cdt = 0; /* Timer stoppen */ + if (*cdt) /* Timer laeuft: Port ist belegt..*/ + return(PTTFLAG); /* Einen belegten Port gefunden! */ + } + return(FALSE); /* keine Kanalkontrolle */ +} + +static int tokenring_attach(int port, int unused_minor, BOOLEAN check_only) +{ + if (tkcom > -1) { /* Geraetekanal bereit? */ + if (!check_only) + /* Minor wird auf Untergeraet (TNC) gesetzt, es wird aber nur ein Ring + unterstuezt. Eigentlich waeren die Ringe die Minors ... */ + portpar[port].minor = port; + return(1); + } + return(0); /* versuchte Doppeleintragung */ +} + +static void tokenring_info(int what, int port, MBHEAD *mbp) +{ + switch (what) { + case HW_INF_STAT : + if (tkcom >= -1) { + putstr("\rTokenring-Statistics:\r\r", mbp); + putprintf(mbp, " Tokens/sec: %8lu %8lu %8lu\r", + token_min_sec, token_pro_sec, token_max_sec); + if (token_max_sec) + putprintf(mbp, " TOKENRING load: %lu%%\r", + 100 - (((ULONG)token_pro_sec)*100L) / ((ULONG)token_max_sec)); + putprintf(mbp, "\r Token ring speed: %u00 Bit/s.\r" + " Token-Recoveries: %u\r" + " Bad-Frames: %u\r", + tkbaud, recovery_count, bad_frames); + } + break; + case HW_INF_CLEAR : + token_max_sec = + token_min_sec = 0; + recovery_count = + bad_frames = 0; + /* durchfallen! */ + default : + default_l1info(what, port, mbp); + break; + } +} + +static void tokenring_timer(UWORD ticks) +{ + static UWORD delay = 0; + + delay += ticks; + if (delay > 6000) { /* eine Minute vergangen */ + token_pro_sec = (token_count / 60L); + if (token_max_sec && token_min_sec) { + token_max_sec = token_pro_sec > token_max_sec + ? token_pro_sec + : token_max_sec; + token_min_sec = token_pro_sec > token_min_sec + ? token_min_sec + : token_pro_sec; + } else + token_min_sec = + token_max_sec = + token_pro_sec; + token_count = 0; + delay %= 6000; + } +} + +static int register_tokenring(void) +{ + MAJOR *m; + + if (tokenring_l1init()) { + m = register_major(); + m->name = "TOKENRING"; + m->exit = tokenring_exit; + m->handle = tokenring; + m->ctl = tokenring_ctl; + m->dcd = tokenring_dcd; + m->info = tokenring_info; + m->timer = tokenring_timer; + m->attach = tokenring_attach; + return(tok_major = num_major); + } + return(0); +} + +/* End of os/go32/tokenrng.c */ diff --git a/os/go32/vanessa.c b/os/go32/vanessa.c new file mode 100755 index 0000000..9052849 --- /dev/null +++ b/os/go32/vanessa.c @@ -0,0 +1,379 @@ +/************************************************************************/ +/* */ +/* ***** ***** */ +/* ***** ***** */ +/* ***** ***** */ +/* ***** ***** */ +/* *************** *************** */ +/* ***************** ***************** */ +/* *************** *************** */ +/* ***** ***** TheNetNode */ +/* ***** ***** Portable */ +/* ***** ***** Network */ +/* ***** ***** Software */ +/* */ +/* File os/go32/vanessa.c (maintained by: ???) */ +/* */ +/* This file is part of "TheNetNode" - Software Package */ +/* */ +/* Copyright (C) 1998 - 2008 NORD> +#include +#include +#endif + +#ifdef __GO32__ +#define ReadVanW(port,what) _farpeekw(_dos_ds,0xD0000+((port)<<12)+(what)) +#define WriteVanW(port,what,data) _farpokew(_dos_ds,0xD0000+((port)<<12)+(what),data) +#define ReadVanB(port,what) _farpeekb(_dos_ds,0xD0000+((port)<<12)+(what)) +#define WriteVanB(port,what,data) _farpokeb(_dos_ds,0xD0000+((port)<<12)+(what),data) +#define ReadVanX(port,what,data,size) dosmemget(0xD0000+((port<<12)+(what)), size, data) +#define WriteVanX(port,what,data,size) dosmemput(data, size, 0xD0000+((port<<12)+(what))) +#else +#define ReadVanW(port,what) (*((unsigned *)MK_FP(0xD000,((port)<<12)+(what)))) +#define WriteVanW(port,what,data) *((unsigned *)MK_FP(0xD000,((port)<<12)+(what)))=data +#define ReadVanB(port,what) (*((unsigned char *)MK_FP(0xD000,((port)<<12)+(what)))) +#define WriteVanB(port,what,data) *((unsigned char *)MK_FP(0xD000,((port)<<12)+(what)))=data +#define ReadVanX(port,what,data,size) memcpy(data, MK_FP(0xD000,((port<<12)+(what))),size) +#define WriteVanX(port,what,data,size) memcpy(MK_FP(0xD000,((port<<12)+(what))),data,size) +#endif + +/* lokale Funktionen */ +static void vanessa_send_test(int); +static void vanessa_get_frame(void); +static void vanessa_put_frame(void); +static void vanessa_config(WORD); +static void vanessa_reset_tnc(void); +void vanessa(void); +BOOLEAN van_test(int); +WORD vanessa_dcd(PORTINFO *); +void vanessa_l1init(void); + +static BOOLEAN van_tst, van_res, van_cmd; + + +static char van_version[L2PNUM]; /* Versions-Kennung */ +static char van_revision[L2PNUM]; /* der VANESSA */ +static char van_patch[L2PNUM]; + +static int van_major = 0; + +/************************************************************************/ +/* Level1 RX/TX fuer VANESSA */ +/* wird staendig in der main() Hauptschleife aufgerufen. */ +/************************************************************************/ +void vanessa(void) +{ + WORD port; + + vanessa_get_frame(); /* read VANESSA CRAM */ + vanessa_put_frame(); /* write frame into VANESSA CRAM */ + + for (port=1; port < L2PNUM; port += 2) /* hb9pae 930521 */ + { + if (portpar[port].major == van_major) + { + if (ReadVanW(port, dp_cCMD)==0) /* pruefen of vanessa restart */ + { + commandflag[port] = TRUE; /* wenn TRUE, parameter uebergeben */ + commandflag[port-1] = TRUE; + portstat[port].reset_count++; /* und restart zaehlen */ + WriteVanW(port, dp_cCMD, 1); + } + } + } + + if (van_res) /* auxiliary cmd to Vanessa */ + vanessa_reset_tnc(); /* VANESSA resetten */ + + if (van_cmd || van_tst) + for (port=0; port < L2PNUM; port++) /* hb9pae 930521 */ + { + if (portpar[port].major == van_major) + { + if (commandflag[port]) + { + vanessa_config(port); /* VANESSA Port neue Parameter */ + commandflag[port] = FALSE; + } + + if (testflag[port]) + { + vanessa_send_test(port); /* VANESSA Test-Folge senden */ + testflag[port] = FALSE; + } + } /* gueltiger VANESSA-Port */ + } /* alle Ports */ + + van_tst = van_res = van_cmd = FALSE; +} + +/************************************************************************/ +/* Vanessa INIT */ +/************************************************************************/ +void vanessa_l1init(void) +{ + WORD port; + + for (port=0; porthead)); /*Zeiger holen*/ + len = cpymbflat(blkbuf, txfhdl); + WriteVanX(port, dp_oBuffer, blkbuf, len); + relink((LEHEAD *)txfhdl, /* als gesendet betrachten und in */ + (LEHEAD *)stfl.tail); /* die gesendet Liste umhaengen */ + kick[port] = ((LHEAD *)l2flp->head != l2flp); + WriteVanW(port,dp_iBufEmpty,1); /* Frame wird gesendet */ + WriteVanW(port,dp_oLFrm,len); /* set size and ... */ + WriteVanW(port,dp_oFProd,CRAM_VALID); /* Terminate */ + } /* if CRAM_VALID... */ +} /* end */ + +/************************************************************************/ +/* vanessa_get_frame() - Frame(s) aus dem VANESSA CRAM holen */ +/*----------------------------------------------------------------------*/ +void vanessa_get_frame(void) +{ + int port; + WORD l; + MBHEAD *rxfhd; + + for (port=0; port < L2PNUM; port++) + if (portpar[port].major == van_major) + while (ReadVanW(port,dp_iFProd)==CRAM_VALID) /* frame available */ + { + outportb(ledio_adr[port],LED_ON); + l = ReadVanW(port,dp_iLFrm); /* get size */ + if (l >= BLOCKSIZE) l = 0; + if (l > 0) { + ReadVanX(port, dp_iBuffer, blkbuf, l); + (rxfhd = cpyflatmb(blkbuf, l))->l2port = port; + relink((LEHEAD *)rxfhd, (LEHEAD *)rxfl.tail); + } + WriteVanW(port,dp_iFProd,!CRAM_VALID); /* CRAM free */ + outportb(ledio_adr[port],LED_OFF); + } /* Frame empfangen */ +} + +/************************************************************************/ +/* VANESSA mit Parametern versorgen */ +/*----------------------------------------------------------------------*/ +void vanessa_config(WORD port) +{ + WORD portspeed; + PORTINFO *p; + + if (portpar[port].major == van_major) + { + p = portpar+port; + WriteVanW(port,dp_Slottime, p->slottime & 0xff); + WriteVanW(port,dp_TxDelay, p->txdelay & 0xff); + WriteVanW(port,dp_Persistance, p->persistance & 0xff); + WriteVanW(port,dp_FullDuplex, fullduplex(port)?1:0); + + if (extclock(port)) portspeed = 0xff07; /* External Clock!! */ + else + switch (p->speed) + { + case 12: portspeed = 0xff00; break; + case 24: portspeed = 0xff01; break; + case 48: portspeed = 0xff02; break; + case 96: portspeed = 0xff03; break; + case 192: portspeed = 0xff04; break; + case 384: portspeed = 0xff05; break; + default: portspeed = 0xff00; p->speed = 12; + } + WriteVanW(port,dp_vanspeed,portspeed); + /* mhm, das sieht mir komisch aus ##BUMP## DB7KG */ + WriteVanB((port&0xfe), ((dp_cData)+0x74F), multibaud(port) ? 1 : 0); + WriteVanB(port, ((dp_cData)+0x74F), multibaud(port) ? 1 : 0); + WriteVanW(port, dp_oMagic, 0); + WriteVanW(port, dp_reReadParams, CRAM_VALID); + outportb(ledio_adr[port], LED_OFF); /* LED Vanessa off */ + WriteVanW(port,dp_iFProd,!CRAM_VALID); /* CRAM Vanessa loeschen */ + } +} + +/************************************************************************/ +/* Reset Befehl an alle VANESSA's geben */ +/*----------------------------------------------------------------------*/ +void vanessa_reset_tnc(void) +{ + int port; + + for (port = 0; port < L2PNUM; port++) /* Alle FP's durchgehen */ + { + if ( portpar[port].reset_port /* soll dieser Reset bekommen? */ + && portpar[port].major == van_major + ) + { + portpar[port].reset_port = FALSE; /* rueckstellen */ + outportb(reset_adr[port>>1],0xFF);/* set RESET and... */ + delay(50); /* .. wait some time */ + outportb(reset_adr[port>>1],0x0); /* remove RESET again */ + } + } +} + + +/************************************************************************/ +/* TEST-Befehl ausfuehren, funktioniert nur ab VANESSA Firmware 4.0 !! */ +/*----------------------------------------------------------------------*/ +void vanessa_send_test(int port) +{ + if (portpar[port].major == van_major) + { + if (ReadVanW(port,dp_oFProd) != CRAM_VALID) /* CRAM Buffer free */ + { + WriteVanW(port,dp_oLFrm,-1); /* Frame Size = -1 */ + WriteVanW(port,dp_oFProd,CRAM_VALID); /* CRAM buffer valid */ + } + testflag[port] = FALSE; /* TEST fertig */ + } +} + +/*******************************************************************/ +/* Testen ob ueberhaupt ne VAN da ist */ +/* Patch dazu gekommen, 22/02/97 DG1KWA */ +/* PS: in der alten Routine war auch noch ein Fehler :-) */ +/*******************************************************************/ + +BOOLEAN van_test(int port) +{ + van_version[port] = 4; /* aktuelle Version steht nicht im DP */ + van_revision[port] = ReadVanB((port&0xFE),dp_cData+0x751) / 16; + van_patch[port] = ReadVanB((port&0xFE),dp_cData+0x74E); /* new */ + return(ReadVanW((port&0xFE)+1,dp_cData+0x750)==0x3412); +} + +WORD vanessa_dcd(PORTINFO *port) +{ + int state = 0; + int minor = port->minor; + + if (ReadVanW(minor,dp_oFProd) == CRAM_VALID) /* Sendedaten in der VAN */ + state |= TXBFLAG; + if (ReadVanW(minor,dp_iFProd) == CRAM_VALID) /* Empfangsdaten */ + state |= RXBFLAG; + if (ReadVanB(minor,dp_iPTT)) + state |= PTTFLAG; + if (!ReadVanB(minor,dp_iDCD)) + state |= DCDFLAG; + return(state); /* Kanal ist frei */ +} + +static void vanessa_ctl(int req, int port) +{ + switch(req) { + case L1CRES: van_res = TRUE; + break; + case L1CCMD: van_cmd = TRUE; + break; + case L1CTST: van_tst = TRUE; + } +} + +static int vanessa_attach(int port, int unused_minor, BOOLEAN check_only) +{ + if (van_test(port)) { + if (!check_only) /* nur pruefen? */ + portpar[port].minor = port; + return(1); + } + return(0); +} + +static void vanessa_info(int what, int port, MBHEAD *mbp) +{ + switch (what) { + case HW_INF_IDENT : + default_l1info(what, port, mbp); + break; + case HW_INF_INFO : + putprintf(mbp, "VAN v%x.%02x%c", + van_version[port], + van_revision[port], + van_patch[port]); + break; + default : + default_l1info(what, port, mbp); + } +} + +static int register_vanessa(void) +{ + MAJOR *m; + int i; + + for (i = 0; i < L2PNUM; i++) + if (van_test(i)) { /* das koennte Probleme machen! */ + m = register_major(); + m->name = "VANESSA"; + m->handle = vanessa; + m->ctl = vanessa_ctl; + m->dcd = vanessa_dcd; + m->attach = vanessa_attach; + m->info = vanessa_info; + return(van_major = num_major); + } + return(0); +} + +/* End of os/go32/vanessa.c */ diff --git a/os/go32/vanessa.h b/os/go32/vanessa.h new file mode 100755 index 0000000..124a2dd --- /dev/null +++ b/os/go32/vanessa.h @@ -0,0 +1,98 @@ +/************************************************************************/ +/* */ +/* ***** ***** */ +/* ***** ***** */ +/* ***** ***** */ +/* ***** ***** */ +/* *************** *************** */ +/* ***************** ***************** */ +/* *************** *************** */ +/* ***** ***** TheNetNode */ +/* ***** ***** Portable */ +/* ***** ***** Network */ +/* ***** ***** Software */ +/* */ +/* File include/vanessa.h (maintained by: ???) */ +/* */ +/* This file is part of "TheNetNode" - Software Package */ +/* */ +/* Copyright (C) 1998 - 2008 NORD> TNC_TIMEOUT) + { + RING[uTNC].uReset++; + uRingStatus = RING_IDLE; + LOGL3("TNC %u: TNC seit %ld ms still, reinitialisiere Ring !", uTNC, (tic10 - RING[uTNC].tLastHeard) * 10); + LOGL3("tic10 ist %ld, LastHeard = %ld", tic10, RING[uTNC].tLastHeard); + break; + } + + /* normaler Watchdog fuer TNC-Anwesenheit */ + if ((tic10 - RING[uTNC].tWatchdog) > TNC_WATCHDOG) + { + cCmd[0] = cmdLED(uTNC); + toRing(cCmd, 1); + RING[uTNC].tWatchdog = tic10; + + /* RXC darf nicht ohne DCD gesetzt sein, ggf. korrigieren */ + if ((RING[uTNC].bDCD == FALSE) && (RING[uTNC].cRXC)) + { + RING[uTNC].cRXC = 0; + LOGL3("TNC %u: RXC-Korrektur !", uTNC); + } + } + + /* Festhaengende PTT loesen */ + if ((RING[uTNC].tPTTWatchdog != 0) && (tic10 > RING[uTNC].tPTTWatchdog)) + { + /* sendet dieses TNC momentan ? */ + if (RING[uTNC].cTXC > 0) + { + RING[uTNC].cTXC--; + LOGL3("TNC %u: TXC-Korrektur !", uTNC); + + /* noch Sendeframes im TNC, dann wieder scharf machen */ + if (RING[uTNC].cTXC > 0) + { + /* wir nehmen die Aussendung eines Frames maximaler Laenge, */ + /* TX-Delay, TX-Tail und etwas Sicherheit an */ + RING[uTNC].tPTTWatchdog = ( tic10 + + (2 * portpar[uMap_TNCtoPort[uTNC]].txdelay) + + (21120 / portpar[uMap_TNCtoPort[uTNC]].speed) + ); + } + else + { + RING[uTNC].tPTTWatchdog = 0; /* Wachhund aus */ + } + } + else + { + /* TNC sendet nicht, aber Wachhund auch angekettet ? */ + if (RING[uTNC].tPTTWatchdog != 0) + { + RING[uTNC].tPTTWatchdog = 0; + LOGL3("TNC %u: PTT-Watchdog entlaufen, wieder eingefangen !", uTNC); + } + } + } + } + } + + /* Ring nicht initialisiert */ + if (uRingStatus == RING_IDLE) + { + /* TNC-Strukturen initialisieren */ + for (uTNC = 0; uTNC < MAX_TNC; ++uTNC) + initTNC(uTNC); + + /* Zaehlung starten */ + startCount(); + + /* Zurueck zu anderen Aufgaben */ + return; + } + + /* Daten vom Ring holen (Daten, Meldungen etc.) */ + Sixpack_RX(); + + /* So lange wir auf das Zaehlpaket warten, keine Sendedaten auf */ + /* den Ring legen, aber ggf. noch ein Zaehlpaket senden. */ + if (uRingStatus == RING_INIT) + { + /* Falls nach zehn Sekunden kein Zaehlpaket kam, wieder eines senden */ + if ((tic10 - tLastInit) >= PROBE_TIMEOUT) + { + uRingStatus = RING_IDLE; + LOGL2("-RING-: Ring laeuft nicht, reinitialisiere ..."); + } + + return; + } + + /* Sendedaten zu den TNC bringen */ + Sixpack_TX(); +} + +/************************************************************************/ +/* Liefert den DCD-Status eines TNC */ +/* ACHTUNG, die "+" beim Zusammenbau des Status sollen da sein ! */ +/* (normalerweise waeren es "|=", aber die funktionieren hier nicht) */ +/************************************************************************/ +WORD Sixpack_DCD(UWORD uPort) +{ + WORD uDCD = 0; + register UBYTE uTNC; /* Nummer des zustaendigen TNC ermitteln */ + + if (uPort <= L2PNUM) + uTNC = uMap_PorttoTNC[uPort]; + else + return (0); + + /* Kein TNC fuer diesen Port */ + if (uTNC == 0xFF) + return (0); + + /* DCD vom TNC gemeldet ? */ + if (RING[uTNC].bDCD == TRUE) + uDCD |= (WORD)(DCDFLAG); + + /* Sendet der TNC gerade oder Calibrate ? */ + if ( (RING[uTNC].cTXC > 0) + || (RING[uTNC].cTestCount > 0) + ) + uDCD |= (WORD)(PTTFLAG); + + /* Empfaengt der TNC momentan ein Frame ? */ +/* + if (RING[uTNC].cRXC > 0) + uDCD += (WORD)(RXBFLAG); +*/ + /* DCD-Zustand melden */ + return (uDCD); +} + +/************************************************************************/ +/* Verarbietung von normalen 6PACK-Meldungen */ +/************************************************************************/ +void processSixpackCmd(UBYTE cByte) +{ + UBYTE uTNC = (cByte & MASK_TNCNUM); + UBYTE cCmdBuf[1]; + + /* Puffer holen und Empfangsport eintragen */ + MBHEAD *rxfhd = NULL; + + /* LED-Kommandos, die keinen TNC fanden ignorieren wir */ + if ((cByte & CMD_LED) == CMD_LED) + return; + + /* Start of Frame, TX-Underrun, RX-Overrun, RX-Buffer Overflow */ + if ((cByte & MASK_NORMCMD) == MASK_NORMCMD) + { + /* nur die oberen Bits interessieren uns hier */ + if ((cByte & MASK_CMD) == CMD_SOF) + { + /* Start of Frame */ + LOGL4("TNC %u: 'Start of Frame' (%sleitend)", uTNC, ((cReceiveFrom != 0xFF) ? "aus" : "ein")); + + switch (uRXStatus) + { + /* Einleitendes SOF */ + case RX_WAIT_SOF: + /* RX beginnt, erstes SOF am Frameanfang */ + if (cReceiveFrom == 0xFF) + { + LOGL2("TNC %u: RX beginnt, RXC ist jetzt %u)", uTNC, RING[uTNC].cRXC); + + if (RING[uTNC].cRXC == 0) + LOGL3("TNC %u: 'Start of Frame' waehrend RXC noch null !!!", uTNC); + + if (uRXRawBufferSize != 0) + LOGL3("TNC %u: RX-Rohdatenpuffer schon vorgefuellt !!!", uTNC); + + /* merken, von welchem TNC wir empfangen */ + cReceiveFrom = uTNC; + + /* Puffer ruecksetzen */ +/* + memset(cRXRawBuffer, 0, sizeof(cRXRawBuffer)); + uRXRawBufferSize = 0; + memset(cRXBuffer, 0, sizeof(cRXBuffer)); + uRXBufferSize = 0; +*/ + /* CON-LED des betreffenden TNC einschalten */ + setLED(uTNC, LED_CON); + cCmdBuf[0] = cmdLED(uTNC); + toRing(cCmdBuf, 1); + } + else + LOGL3("TNC %u: RX-TNC bei erstem SOF schon gesetzt !", uTNC); + + /* Empfangszustand merken */ + uRXStatus = RX_WAIT_END; + break; + + /* Wir empfangen und haben beendendes SOF erhalten */ + case RX_WAIT_END: + if (cReceiveFrom != uTNC) + LOGL3("TNC %u: RX-TNC bei Frameende ungleich TNC (%u) bei Frameanfang !", uTNC, cReceiveFrom); + + /* Pruefen, ob Empfangsdaten da sind, wenn nein, dann sind */ + /* wir sehr wahrscheinlich out of sync und empfangen einfach */ + /* mal weiter, da wir jetzt erst wahrscheinlich am Frame- */ + /* anfang sind. */ + if (uRXRawBufferSize == 0) + { + /* wie bei normalem RX-Beginn ... */ + /* merken, von welchem TNC wir empfangen */ + cReceiveFrom = uTNC; + + /* Puffer ruecksetzen */ +/* + memset(cRXRawBuffer, 0, sizeof(cRXRawBuffer)); + uRXRawBufferSize = 0; + memset(cRXBuffer, 0, sizeof(cRXBuffer)); + uRXBufferSize = 0; +*/ + /* CON-LED des betreffenden TNC einschalten */ + setLED(uTNC, LED_CON); + cCmdBuf[0] = cmdLED(uTNC); + toRing(cCmdBuf, 1); + + LOGL2("TNC %u: Resync !!!", uTNC); + + return; + } + + /* Empfangene Daten dekodieren */ + if (DecodeRawBuffer(cReceiveFrom)) + { + /* Checksumme ist korrekt, Daten an L2 geben */ + /* Hier koennen auch Daten von TNC ankommen, */ + /* die keinem Port zugeordnet sind. Deren Daten */ + /* werfen wir weg. */ + if (portenabled(uMap_TNCtoPort[cReceiveFrom])) + { + /* Port ist eingeschaltet, dann Daten in den Empfangspuffer */ + register UWORD uByteCounter; + + /* Puffergroesse korrigieren (TX-Delay und Checksumme) */ + uRXBufferSize -= 2; + + /* Puffer holen */ + (rxfhd = (MBHEAD *)allocb(ALLOC_MBHEAD))->l2port = uMap_TNCtoPort[cReceiveFrom]; + + /* Frame in Buffer umkopieren */ + for (uByteCounter = 1; uByteCounter <= uRXBufferSize; ++uByteCounter) + putchr(cRXBuffer[uByteCounter], rxfhd); + + /* Frame zum L2 geben */ + relink((LEHEAD *)rxfhd, (LEHEAD *)rxfl.tail); + } + } + else + { + /* Checksumme fehlerhaft */ + LOGL3("TNC %u: Checksumme fehlerhaft !!!", uTNC); + RING[cReceiveFrom].uChecksumErr++; + } + + /* CON-LED ausschalten */ + resetLED(cReceiveFrom, LED_CON); + cCmdBuf[0] = cmdLED(cReceiveFrom); + toRing(cCmdBuf, 1); + + /* Frameempfang vermerken */ + if (RING[cReceiveFrom].cRXC > 0) + RING[cReceiveFrom].cRXC--; + + /* Empfangsvariablen neu initialisieren und Puffer ruecksetzen */ + cReceiveFrom = 0xFF; + uRXStatus = RX_WAIT_SOF; + + memset(cRXRawBuffer, 0, sizeof(cRXRawBuffer)); + uRXRawBufferSize = 0; + memset(cRXBuffer, 0, sizeof(cRXBuffer)); + uRXBufferSize = 0; + + LOGL3("TNC %u: RX beendet, RXC ist jetzt %u", uTNC, RING[uTNC].cRXC); + break; + + default: break; + } + } /* if (SOF) */ + + switch (cByte & MASK_CMD) + { + /* TX-Underrun */ + case MSG_TXU : /* TX-Underrun waehrend des Sendens des Testsignals ? */ + if (RING[uTNC].cTestCount > 0) + { + RING[uTNC].cTestCount = 0; + resetLED(uTNC, LED_STA | LED_CON); + cCmdBuf[0] = cmdLED(uTNC); + toRing(cCmdBuf, 1); + } + + RING[uTNC].uTXU++; + RING[uTNC].cTXC = 0; + LOGL3("TNC %u: TX-Underrun (neuer Zaehlerstand: %u)", uTNC, RING[uTNC].uTXU); + break; + + /* RX-Overrun */ + case MSG_RXO : RING[uTNC].uRXO++; + LOGL3("TNC %u: RX-Overrun (neuer Zaehlerstand: %u)", uTNC, RING[uTNC].uRXO); + break; + + /* RX Buffer Overflow */ + case MSG_RXB : RING[uTNC].uRXB++; + LOGL3("TNC %u: RX Buffer-Overflow (neuer Zaehlerstand: %u)", uTNC, RING[uTNC].uRXB); + break; + + default : break; + } /* switch */ + } /* if (... NORMCMD) */ +} + +/************************************************************************/ +/* Verarbeitung von 6PACK-Prioritaetskommandos */ +/************************************************************************/ +void processSixpackPrioCmd(UBYTE cByte) +{ + UBYTE uTNC = (cByte & MASK_TNCNUM); + + /* Prioritaetsmeldungen */ + if ((cByte & MASK_CALCNT) != 0) + { + LOGL4("TNC %u: Prioritaetskommando \"Zaehlung/Calibrate\" empfangen", uTNC); + + /* Calibrate, Kanalzuweisung */ + if ((cByte & MASK_CHAN) != 0) + { + /* Kanalzuweisung / Zaehlung */ + LOGL1("TNC %u: Kanalzuweisung empfangen", uTNC); + } + else + { + UBYTE cCmdBuf[2]; + + /* Calibrate */ + LOGL2("TNC %u: Calibrate-Paket empfangen, Calibrate-Zaehler des TNC ist %u", uTNC, RING[uTNC].cTestCount); + + /* TNC meldet beendetes Calibrate, wenn noch Calibrates uebrig, dann */ + /* wieder ein Kommando schicken und STA-Led einschalten */ + if (RING[uTNC].cTestCount > 1) + { + RING[uTNC].cTestCount--; + setLED(uTNC, LED_STA); + cCmdBuf[0] = cmdLED(uTNC); + cCmdBuf[1] = cmdCAL(uTNC); + toRing(cCmdBuf, 2); + LOGL2("TNC %u: Calibrate-Paket gesendet, Calibrate-Zaehler des TNC ist jetzt %u", uTNC, RING[uTNC].cTestCount); + } + else + { + /* letztes Calibrate beendet, dann STA-Led ausschalten */ + RING[uTNC].cTestCount = 0; + resetLED(uTNC, LED_STA); + cCmdBuf[0] = cmdLED(uTNC); + toRing(cCmdBuf, 1); + LOGL2("TNC %u: Calibrate beendet", uTNC); + } + } + } + else + { + /* DCD, RX-Zaehler, TX-Zaehler */ + /* DCD immer uebernehmen */ + RING[uTNC].bDCD = ((cByte & MASK_DCD) == MASK_DCD ? TRUE : FALSE); + + /* RX-Zaehler + 1 */ + /* Das Kommando ist nur erlaubt, wenn auch DCD gesetzt ist */ + if ((cByte & MASK_RXC) == MASK_RXC) + { + if (RING[uTNC].bDCD == TRUE) + { + RING[uTNC].cRXC++; + LOGL2("TNC %u: 'RX-Zaehler + 1', RXC ist jetzt %u", uTNC, RING[uTNC].cRXC); + } + else + LOGL2("TNC %u: 'RX-Zaehler + 1' ohne DCD, ignoriere.", uTNC); + } + + /* TX-Zaehler + 1 */ + if ((cByte & MASK_TXC) == MASK_TXC) + { + if (RING[uTNC].cTXC > 0) + { + RING[uTNC].cTXC--; + + /* noch Frames in der Sendung, dann Wachhund scharf machen */ + if (RING[uTNC].cTXC > 0) + { + /* wir nehmen die Aussendung eines Frames maximaler Laenge, */ + /* TX-Delay, TX-Tail und etwas Sicherheit an */ + RING[uTNC].tPTTWatchdog = ( tic10 + + (2 * portpar[uMap_TNCtoPort[uTNC]].txdelay) + + (21120 / portpar[uMap_TNCtoPort[uTNC]].speed) + ); + } + else /* Aussendung beendet, Wachhund wieder anketten */ + { + RING[uTNC].tPTTWatchdog = 0; + } + } + else /* keine Sendung, ist der Hund auch angekettet ? */ + { + if (RING[uTNC].tPTTWatchdog != 0) + RING[uTNC].tPTTWatchdog = 0; + } + + LOGL2("TNC %u: 'TX-Zaehler + 1', TXC ist jetzt %u", uTNC, RING[uTNC].cTXC); + } + + /* TNC lebt noch */ + RING[uTNC].tLastHeard = tic10; + } +} + +/************************************************************************/ +/* 6PACK-Empfang */ +/************************************************************************/ +void Sixpack_RX(void) +{ + UBYTE cBuf[520]; + ssize_t iRet; + register int iCounter; + register int iSelRet; + UBYTE cRXByte; + UBYTE uNumTNC; + + /* ganz wichtig, Linux modifiziert in select() diese Werte !!! */ + tv.tv_sec = 0; + tv.tv_usec = 0; + + FD_ZERO(&rset); + FD_SET(iDescriptor, &rset); + + iSelRet = select(iDescriptor + 1, &rset, NULL, NULL, &tv); + + /* Fehler bei select() ? */ + if (iSelRet < 0) + { + LOGL4("-RING-: Fehler %n bei select() : %s", errno, strerror(errno)); + Sixpack_l1exit(); + Sixpack_l1init(); + return; + } + + /* select() hat keinen lesbaren Descriptor gefunden, */ + /* oder es ist nicht unserer */ + if ((iSelRet == 0) || (!FD_ISSET(iDescriptor, &rset))) + return; + + memset(cBuf, 0, sizeof(cBuf)); + + /* Daten holen */ + iRet = read(iDescriptor, cBuf, 512); + + /* Ist was gekommen ? */ + if (iRet > 0) + { + /* zeichenweise Verarbeitung */ + for (iCounter = 0; iCounter < iRet; ++iCounter) + { + /* Zeichen aus dem Puffer holen */ + cRXByte = cBuf[iCounter]; + + /* Wir warten noch auf das Zaehlpaket, so lange kein anderer Empfang */ + if (uRingStatus == RING_INIT) + { + /* Zaehlkommando zurueckgekommen ? */ + if ((cRXByte & CMD_INIT) == CMD_INIT) + { + /* Kanalzuweisung / Zaehlung */ + uNumTNC = (cRXByte - CMD_INIT); + + LOGL1("-RING-: TNC-Zaehlung beendet, %u TNC gefunden", uNumTNC); + + /* Ring "kurzgeschlossen", noch einmal initialisieren */ + if (uNumTNC == 0) + { + uRingStatus = RING_IDLE; + LOGL3("-RING-: kein TNC im Ring, Ring ist kurzgeschlossen !"); + return; + } + + /* Ports mit TNC verbinden */ + if (assignPorts(uNumTNC) != uNumTNC) + LOGL1("-RING-: TNC-Zaehlung weicht von konfigurierter Portanzahl ab !!!"); + } + + /* Falls nach zehn Sekunden kein Zaehlpaket kam, wieder eines senden */ + if ((tic10 - tLastInit) >= PROBE_TIMEOUT) + { + uRingStatus = RING_IDLE; + LOGL2("-RING-: Ring laeuft nicht, reinitialisiere ..."); + return; + } + + continue; + } + + /* Meldungen und Daten verarbeiten */ + /* Prioritaetsmeldungen */ + if ((cRXByte & MASK_PRIOCMD) == MASK_PRIOCMD) + { + processSixpackPrioCmd(cRXByte); + continue; + } + + /* normale Meldungen */ + if ((cRXByte & MASK_NORMCMD) == MASK_NORMCMD) + { + processSixpackCmd(cRXByte); + continue; + } + + /* Daten */ + if ((cRXByte & MASK_DATA) == 0) + { + /* Daten zum falschen Zeitpunkt ? */ + if ((uRXStatus != RX_WAIT_END) || (cReceiveFrom == 0xFF)) + { + LOGL3("-RING-: Daten ohne SOF (%x) !!! rxsize=%u", cRXByte, uRXRawBufferSize); +/* continue; */ + } + + /* In den rohen Puffer damit */ + cRXRawBuffer[uRXRawBufferSize++] = cRXByte; + + continue; + } + + LOGL1("-RING-: Daten ohne Ziel !!! (hex 0x%x, dez %u)", cRXByte, cRXByte); + } /* for (...) */ + } /* if (iRet > 0) */ + else + { + /* wenn nach zehn Sekunden kein Zaehlpaket kam, dann noch eines senden */ + if ( (iRet == 0) + && (uRingStatus == RING_INIT) + && ((tic10 - tLastInit) >= PROBE_TIMEOUT) + ) + uRingStatus = RING_IDLE; + + /* Schnittstellenfehler ! Das sollte NIE passieren ... */ + if ((iRet < 0) && (errno != EAGAIN) && (errno != EWOULDBLOCK)) + { + /* Oh oh ... alles versuchen neu zu starten ... */ + LOGL2("-RING-: Fehler auf der Schnittstelle, start Ring neu !!!"); + Sixpack_l1exit(); + Sixpack_l1init(); + } + } +} + +/************************************************************************/ +/* Dekodiert den gefuellten 6PACK-Rohdatenpuffer in den Nutzdatenpuffer */ +/************************************************************************/ +BOOLEAN DecodeRawBuffer(UBYTE uTNC) +{ + register UWORD uBufferPos; + + UBYTE cChecksum = uTNC; + UBYTE cTmpByte = 0; + UBYTE cBufCorrection = 0; + + /* Puffer auffuellen */ + while ((uRXRawBufferSize % 4) != 0) + { + ++uRXRawBufferSize; + ++cBufCorrection; /* Merken fuer Korrektur des dekodierten Puffers */ + } + + /* rohen Empfangspuffer decodieren */ + for (uBufferPos = 0; uBufferPos <= uRXRawBufferSize; ++uBufferPos) + { + register UBYTE cByte = cRXRawBuffer[uBufferPos]; + + switch (uBufferPos % 4) + { + /* 1. 6PACK */ + case 0: cTmpByte = cByte; + break; + + /* 2. 6PACK */ + case 1: cRXBuffer[uRXBufferSize++] = (cTmpByte | ((cByte << 2) & 0xC0)); + cTmpByte = (cByte & 0x0F); + break; + + /* 3. 6PACK */ + case 2: cRXBuffer[uRXBufferSize++] = (cTmpByte | ((cByte << 2) & 0xF0)); + cTmpByte = (cByte & 0x03); + break; + + /* 4. 6PACK */ + case 3: cRXBuffer[uRXBufferSize++] = (cTmpByte | (cByte << 2)); + break; + + default: break; + } + } + + /* Checksumme ueber den dekodierten Puffer berechnen */ + for (uBufferPos = 0; uBufferPos < uRXBufferSize; ++uBufferPos) + cChecksum += cRXBuffer[uBufferPos]; + + /* dekodierten Puffer in der Groesse korrigieren */ + uRXBufferSize -= cBufCorrection; + + /* Checksumme pruefen und entsprechend melden */ + if (cChecksum == 0xFF) + return (TRUE); + else + { + LOGL3("TNC %u: Checksummenfehler : %u Bytes roh, %u Byte dekodiert, Checksumme %u", + uTNC, uRXRawBufferSize, uRXBufferSize, cChecksum); + return (FALSE); + } +} + +/************************************************************************/ +/* Sendet alle fuer einen Port anstehenden Frames zum TNC */ +/************************************************************************/ +void sendSixpack(UBYTE uTNC) +{ + UBYTE cCheckSum; + UBYTE cRawBuffer[512]; + UBYTE cSendBuffer[512]; + UWORD uRawBufferSize; + UWORD uSendBufferSize; + register UWORD uCounter; + + MBHEAD *txfhdl; + LHEAD *l2flp; + + /* Portnummer fuer den TNC holen */ + UWORD uPort = uMap_TNCtoPort[uTNC]; + + /* Sicher ist sicher ... */ + if (kissmode(uPort) != KISS_6PACK) + return; + + /* Sendeliste des Ports holen */ + l2flp = (LHEAD *)&txl2fl[uPort]; + + /* Bei ausgeschalteten Ports die Sendeliste ohne Sendung kopieren */ + if (!portenabled(uPort)) + { + while (l2flp->head != l2flp) + relink(ulink((LEHEAD *) l2flp->head), (LEHEAD *)stfl.tail); + return; + } + + /* So lange Sendepakete da sind, diese auf den Ring geben */ + /* TNC aber nicht ueberfuellen */ + while (kick[uPort]) + { + /* Sendelistenzeiger pruefen */ + if (l2flp->head == l2flp) + { + /* Zeiger steht auf Anfang, also doch nix zu senden */ + kick[uPort] = FALSE; + return; + } + + /* Puffer loeschen fuer neues Frame */ + memset(cSendBuffer, 0, sizeof(cSendBuffer)); + uSendBufferSize = 0; + memset(cRawBuffer, 0, sizeof(cRawBuffer)); + uRawBufferSize = 0; + + /* STA-LED waehrend der Datenuebertragung zum TNC einschalten */ + setLED(uTNC, LED_STA); + cSendBuffer[uSendBufferSize++] = cmdLED(uTNC); + /* "TX-Zaehler + 1" und "Start of Frame" senden */ + cSendBuffer[uSendBufferSize++] = cmdTXC(uTNC); + cSendBuffer[uSendBufferSize++] = cmdSOF(uTNC); + + /* TX-Delay in den rohen Puffer */ + cRawBuffer[uRawBufferSize++] = (UBYTE)(portpar[uPort].txdelay & 0xFF); + + /* Checksumme mit der TNC-Nummer initialisieren und TX-Delay hinzufuegen */ + cCheckSum = uTNC; + cCheckSum += (UBYTE)(portpar[uPort].txdelay & 0xFF); + + /* Zeiger auf Sendeliste holen */ + ulink((LEHEAD *)(txfhdl = (MBHEAD *)l2flp->head)); + + /* Rohdaten kopieren und Checksumme bilden */ + while (txfhdl->mbgc < txfhdl->mbpc) + { + register UBYTE cByte = getchr(txfhdl); + cRawBuffer[uRawBufferSize++] = cByte; + cCheckSum += cByte; + } + + /* Checksumme dem Puffer hinzufuegen */ + cRawBuffer[uRawBufferSize] = (UBYTE)(0xFF - cCheckSum); + + /* Puffer codieren */ + for (uCounter = 0; uCounter <= uRawBufferSize; ++uCounter) + { + switch (uCounter % 3) + { + /* 1. Byte -> 1. & 2. 6PACK */ + case 0: cSendBuffer[uSendBufferSize++] = (cRawBuffer[uCounter] & 0x3F); + cSendBuffer[uSendBufferSize] = ((cRawBuffer[uCounter] >> 2) & 0x30); + break; + + /* 2. Byte -> 2. & 3. 6PACK */ + case 1: cSendBuffer[uSendBufferSize++] |= (cRawBuffer[uCounter] & 0x0F); + cSendBuffer[uSendBufferSize] = ((cRawBuffer[uCounter] >> 2) & 0x3C); + break; + + /* 3. Byte -> 3. & 4. 6PACK */ + case 2: cSendBuffer[uSendBufferSize++] |= (cRawBuffer[uCounter] & 0x03); + cSendBuffer[uSendBufferSize++] = (cRawBuffer[uCounter] >> 2); + + default: break; /* das sollte _nie_ passieren ... */ + } + } + + /* Sendepuffer "auffuellen" (terminiert das in Bearbeitung befindliche 6PACK) */ + if ((uRawBufferSize % 3) != 2) + ++uSendBufferSize; + + /* abschliessendes SOF */ + cSendBuffer[uSendBufferSize++] = cmdSOF(uTNC); + + /* STA-LED wieder ausschalten */ + resetLED(uTNC, LED_STA); + cSendBuffer[uSendBufferSize++] = cmdLED(uTNC); + + /* Auf den Ring damit */ + toRing(cSendBuffer, uSendBufferSize); + + /* Merken, dass ein Sendeframe unterwegs ist und Wachhunde scharf machen */ + RING[uTNC].cTXC++; + RING[uTNC].tTXWatchdog = tic10; + RING[uTNC].tPTTWatchdog = ( tic10 + + (2 * portpar[uMap_TNCtoPort[uTNC]].txdelay) + + (21120 / portpar[uMap_TNCtoPort[uTNC]].speed) + ); + + /* Frame in die gesendet-Liste umhaengen */ + relink((LEHEAD *)txfhdl, (LEHEAD *)stfl.tail); + + /* ein Frame gesendet, Sendewarteschlange aktualisieren */ + kick[uPort] = ((LHEAD *)l2flp->head != l2flp); + + LOGL3("TNC %u: Frame an TNC gesendet, TXC ist jetzt %u", uTNC, RING[uTNC].cTXC); + } /* while (...) */ +} + +/************************************************************************/ +/* Sendet ausstehende Frames zu den TNC, Kanalarbitrierung */ +/************************************************************************/ +void Sixpack_TX(void) +{ + register UBYTE uTNC; + register UWORD uPort; + UBYTE cCmdBuf[1]; + + /* Merker, ob wir senden duerfen */ + BOOLEAN bSendOK = FALSE; + + for (uTNC = 0; uTNC < MAX_TNC; ++uTNC) + { + /* Nur fuer angeschlossene TNC. Da die TNC-Nummern nur ununterbrochen */ + /* aufsteigend sein koennen, beim ersten nicht vorhandenen TNC raus, */ + /* es kann keiner mehr danach kommen. */ + if (RING[uTNC].bPresent == FALSE) + break; + + /* Wenn wir senden und die TX-Watchdogzeit abgelaufen ist, */ + /* dann den aktuellen LED-Zustand zum TNC senden (TX-Watchdog) */ + if ( ( (RING[uTNC].cTestCount > 0) /* Testsignal */ + || (RING[uTNC].cTXC > 0) /* unbestaetigte Frames */ + ) + && ((RING[uTNC].tTXWatchdog + TXWDTIME) < tic10)) + { + /* aktuellen LED-Zustand als Watchdogpaket senden */ + cCmdBuf[0] = cmdLED(uTNC); + toRing(cCmdBuf, 1); + + /* letzten Watchdogzeitpunkt merken */ + RING[uTNC].tTXWatchdog = tic10; + } + + /* Port holen, der diesem TNC zugeordnet ist */ + uPort = uMap_TNCtoPort[uTNC]; + + /* Arbiter fuer Kanalzugriff */ + /* Port hat was zu senden, TNC nicht ueberfuellen */ + if (kick[uPort] /* && RING[uTNC].cTXC < 5 */ ) + { + LHEAD *l2flp; + + LOGL4("TNC %u: Port %u ist fuer Sendung markiert und hat Platz", uTNC, uPort); + + /* Sendeliste des Ports holen */ + l2flp = (LHEAD *)&txl2fl[uPort]; + + /* Sendelistenzeiger pruefen */ + if (l2flp->head == l2flp) + { + /* Zeiger steht auf Anfang, doch nix zu senden */ + LOGL4("TNC %u: keine Sendedaten, eventuell Calibrate, keine Arbitrierung", uTNC); + kick[uPort] = FALSE; + return; + } + + /* Arbitrierung notwendig ? */ + if ((fullduplex(uPort)) || (RING[uTNC].cTXC > 0)) + { + LOGL4("TNC %u: Port ist Vollduplex oder sendet bereits, sende sofort", uTNC); + bSendOK = TRUE; + } + else + { + /* DCD beruecksichtigen */ + if (!(Sixpack_DCD(uPort) & (WORD)(DCDFLAG))) + { + LOGL4("TNC %u: Kanal ist frei, Slottime ist %u ms", uTNC, portpar[uPort].slottime * 10); + + /* Hatten wir schon mal versucht zu senden ? (Slottime) */ + if ( (RING[uTNC].tNextArbit != 0L) + && (RING[uTNC].tNextArbit > tic10) + ) + { + LOGL4("TNC %u: nicht genug Zeit seit letztem Arbit vergangen", uTNC); + } + else + { + LOGL4("TNC %u: genug Zeit seit letztem Arbit vergangen", uTNC); + + /* Kanalzugriff auswuerfeln (Persistenz) */ + if ((rand() % 255) <= (dama(uPort) ? 0xFF : (portpar[uPort].persistance & 0xFF))) + { + LOGL4("TNC %u: Zufallszahl kleiner, Sendung moeglich", uTNC); + bSendOK = TRUE; + } + else + { + LOGL4("TNC %u: Zufallszahl zu gross, keine Sendung", uTNC); + /* Merken, wann wir es zuletzt versucht hatten zu senden, */ + /* naechster Versuch erst nach Ablauf der Slottime. */ + RING[uTNC].tNextArbit = (tic10 + portpar[uPort].slottime); + } + } + } + else + { + LOGL4("TNC %u: DCD erkannt, kann nicht mehr senden", uTNC); + /* Waren wir selbst grad in der Arbitrierung und wurden */ + /* durch die RX-DCD unterbrochen, dann Sendeversuch abbrechen. */ + if (RING[uTNC].tNextArbit != 0L) + { + RING[uTNC].tNextArbit = 0L; + LOGL4("TNC %u: laufende Arbitrierung abgebrochen", uTNC); + } + } + } + + if (bSendOK == TRUE) + { + /* Kanal frei und Sendung ok */ + LOGL4("TNC %u: Arbitrierung, sende !", uTNC); + sendSixpack(uTNC); + /* wir konnten Senden */ + RING[uTNC].tNextArbit = 0L; + } + else + { + /* Kanal blockiert, nicht senden */ + LOGL4("TNC %u: Arbitrierung nicht erfolgreich", uTNC); + } + } /* if ( kick[uPort] ... ) */ + } /* for ( ... ) */ +} + +/************************************************************************/ +/* TNCs im Ring zaehlen / Zaehlpaket senden */ +/************************************************************************/ +void startCount(void) +{ + UBYTE cCmdBuf[1]; + + /* Sicherheitscheck, ob wir die Zuordnungen jetzt aendern duerfen */ + if (uRingStatus != RING_IDLE) + return; + + /* Zaehlkommando zusammenbauen und senden */ + cCmdBuf[0] = cmdINIT(0); + toRing(cCmdBuf, 1); + + /* Zeitpunkt und Sendung merken */ + tLastInit = tic10; + ++uNumProbes; + + /* Merken, dass wir auf das Zaehlpaket warten */ + uRingStatus = RING_INIT; + LOGL4("-RING-: Zaehlpaket gesendet"); +} + +/************************************************************************/ +/* Datenpuffer auf den Ring senden */ +/* (basierend auf writen() aus einem Stevens-Buch) */ +/************************************************************************/ +void toRing(UBYTE *pBuffer, UWORD uSize) +{ + UWORD uErrorCounter = 0; + + size_t tLeft = uSize; + ssize_t tWritten; + const UBYTE *pBufPtr; + + pBufPtr = pBuffer; + + /* nur wenn der Ring offen ist duerfen wir hier rein */ + if (uRingStatus == RING_HALT) + return; + + /* solange noch Daten zu senden sind */ + while (tLeft > 0) + { + if ((tWritten = write(iDescriptor, pBufPtr, tLeft)) <= 0) + { + if (errno == EINTR) + tWritten = 0; + else + { + if (++uErrorCounter >= 0xFF) + { + LOGL3("-RING-: Schnittstellenfehler %u (%s)", errno, strerror(errno)); + Sixpack_l1exit(); + Sixpack_l1init(); + return; + } + } + } + + tLeft -= tWritten; + pBufPtr += tWritten; + } +} + +/************************************************************************/ +/* Ordnet jedem 6PACK-Port einen freien TNC-Port */ +/************************************************************************/ +UBYTE assignPorts(UBYTE uAvailTNC) +{ + register UBYTE i; + register UBYTE j = 0; + + UBYTE cCmdBuf[2]; + + /* Sicherheitscheck, ob wir die Zuordnungen jetzt aendern duerfen */ + if (uRingStatus != RING_INIT) + return (0); + + /* zuerst alle TNC als nicht vorhanden markieren */ + for (i = 0; i < MAX_TNC; ++i) + { + RING[i].bPresent = FALSE; + uMap_TNCtoPort[i] = 0; + } + + /* und das Gleiche mit den Ports machen */ + for (i = 0; i < L2PNUM; ++i) + uMap_PorttoTNC[i] = 0xFF; /* kein TNC */ + + /* Alle L2-Ports durchgehen */ + for (i = 0; (i < L2PNUM && j < uAvailTNC); ++i) + { + /* andere Ports nicht beachten */ + if (kissmode(i) != KISS_6PACK) + continue; + + LOGL2("-RING-: Assoziiere TNC %u mit Port %u", j, i); + + /* TNC mit Port verbinden */ + RING[j].bPresent = TRUE; + RING[j].tWatchdog = tic10; + RING[j].tLastHeard = tic10; + RING[j].tPTTWatchdog = 0; + uMap_PorttoTNC[i] = j; + uMap_TNCtoPort[j] = i; + + /* bei gefundenen TNC die CON-LED einschalten */ + resetLED(j, LED_STA); + setLED(j, LED_CON); + cCmdBuf[0] = cmdLED(j); + resetLED(j, LED_CON); + toRing(cCmdBuf, 1); + ++j; + } + + /* Empfang und initialisieren */ + cReceiveFrom = 0xFF; + uRXStatus = RX_WAIT_SOF; + + /* Ring freigeben fuer Datenverkehr */ + uRingStatus = RING_RUN; + + /* melden, wie viele Zuordnungen gemacht worden sind */ + return (j); +} + +/************************************************************************/ +/* L1-Kontrolle (Reset, Portparameter etc.) */ +/************************************************************************/ +void Sixpack_l1ctl(int iReq, UWORD uPort) +{ + UBYTE cCmdBuf[2]; + register UBYTE uTNC = uMap_PorttoTNC[uPort]; + + /* nur 6PACK-Ports und davon auch nur die existierenden duerfen hier rein */ + if ( (kissmode(uPort) != KISS_6PACK) + || (RING[uTNC].bPresent == FALSE) + ) + return; + + /* Anfragen unterscheiden */ + switch (iReq) + { + /* Reset eines TNC. Das geht bei 6PACK nicht direkt, also muss der ganze */ + /* Ring dran glauben ... */ + case L1CRES : RING[uTNC].uReset++; + /* den Ring neu initialiseren */ + uRingStatus = RING_IDLE; + LOGL2("TNC %u: TNC-Reset (neuer Zaehlerstand: %u)", uTNC, RING[uTNC].uReset); + break; + + /* Testsignal initiieren (4 x 15 Sekunden) */ + case L1CTST : RING[uTNC].cTestCount = 4; + setLED(uTNC, LED_STA); + cCmdBuf[0] = cmdCAL(uTNC); + cCmdBuf[1] = cmdLED(uTNC); + toRing(cCmdBuf, 2); + LOGL2("TNC %u: Testsignal initiiert", uTNC); + break; + + /* Portparameter zum TNC bringen, das braucht 6PACK nicht, */ + /* alles ausser TX-Delay machen wir selbst. */ + case L1CCMD : + default : break; + } +} + +/************************************************************************/ +/* Device einrichten */ +/************************************************************************/ +void Sixpack_l1init(void) +{ + register UWORD i; + UWORD uFehler = 0; + DEVICE *l1pp; + struct serial_struct ser_io; + BOOLEAN bPortFound = FALSE; + + /* Zufallsgenerator initialisieren */ + srand(0); + + /* Erstes 6PACK-Device suchen fuer Lockfile */ + /* Alle L1-Ports durchgehen */ + for (i = 0; i < L1PNUM; ++i) + { + l1pp = &l1port[i]; + + if (l1pp->kisstype == KISS_6PACK) + { + bPortFound = TRUE; + break; + } + } + + /* haben wir einen Port gefunden ? */ + if (bPortFound == FALSE) + return; + + /* Lock-File schreiben */ + l1pp->lock = -1; + if (*(l1pp->tnn_lockfile) != '\0') + { + if (access(l1pp->tnn_lockfile, F_OK) == 0) + { + pid_t alienPID; + FILE* lockFile; + + printf("6PACK-L1: Warning: Device %s seems to be locked by another by another process.\n", l1pp->device); + LOGL1("Warning: Device %s seems to be locked by another by another process.", l1pp->device); + + if ((lockFile = fopen(l1pp->tnn_lockfile, "r")) != NULL) + { + fscanf(lockFile, "%i", &alienPID); + fclose(lockFile); + printf("6PACK-L1: Checking if process with PID %u is still alive ... ", alienPID); + LOGL1("Checking if process with PID %u is still alive ...", alienPID); + + if ((kill(alienPID, 0) == -1) && (errno == ESRCH)) + { + printf("No. Deleting stale lockfile.\n"); + LOGL1("No. Deleting stale lockfile."); + unlink(l1pp->tnn_lockfile); + } + else + { + printf("Ohoh, active process found.\n6PACK-L1: I won't touch the port !!! Restart with \"-u\" to override.\n"); + LOGL1("Ohoh, active process found. I won't touch the port !!! Restart with \"-u\" to override."); + uFehler = 1; + } + + } + else + { + printf("6PACK-L1: Sorry, can't open lockfile for reading locking pocess' PID.\n"); + LOGL1("Sorry, can't open lockfile for reading locking pocess' PID."); + } + + } + + if ((uFehler == 0) && ((l1pp->lock = open(l1pp->tnn_lockfile, O_CREAT|O_EXCL, 0666)) == -1)) + { + uFehler = 1; + printf("Error: Device %s is locked by other user;\n" + " unable to create lockfile %s\n", l1pp->device, l1pp->tnn_lockfile); + printf(" (%s)\n", strerror(errno)); + LOGL1("Error: Device %s is locked by other user;" + " unable to create lockfile %s", l1pp->device, l1pp->tnn_lockfile); + LOGL1(" (%s)", strerror(errno)); + } + else + { + char uBuf[16]; + memset(uBuf, 0, sizeof(uBuf)); + sprintf(uBuf, "%10d\n", getpid()); + write(l1pp->lock, uBuf, strlen(uBuf)); + close(l1pp->lock); + } + } + + /* Seriellen Port fuer Ein- und Ausgabe oeffnen */ + if (uFehler == 0) /* nur wenn Lock-File geschrieben */ + { /* wurde oder nicht gefordert war */ + if ((iDescriptor = open(l1pp->device, O_RDWR)) == -1) + { + uFehler = 2; + printf("Error: can't open device %s\n", l1pp->device); + printf(" (%s)\n", strerror(errno)); + LOGL1("Error: can't open device %s", l1pp->device); + LOGL1(" (%s)", strerror(errno)); + } + } + + /* Einstellungen der seriellen Schnittstelle merken */ + if (uFehler == 0) /* nur wenn Port geoeffnet worden ist */ + { + tcgetattr(iDescriptor, &(l1pp->org_termios)); + if (l1pp->speed == B38400) /* >= 38400 Bd */ + { + if (ioctl(iDescriptor, TIOCGSERIAL, &ser_io) < 0) + { + uFehler = 3; + printf("Error: can't get actual settings for device %s\n", l1pp->device); + printf(" (%s)\n", strerror(errno)); + LOGL1("Error: can't get actual settings for device %s", l1pp->device); + LOGL1(" (%s)", strerror(errno)); + } + } + } + + /* Neue Einstellungen der seriellen Schnittstelle setzen */ + if (uFehler == 0) + { + l1pp->wrk_termios = l1pp->org_termios; + l1pp->wrk_termios.c_cc[VTIME] = 0; /* empfangene Daten */ + l1pp->wrk_termios.c_cc[VMIN] = 0; /* sofort abliefern */ + l1pp->wrk_termios.c_iflag = IGNBRK; /* BREAK ignorieren */ + l1pp->wrk_termios.c_oflag = 0; /* keine Delays oder */ + l1pp->wrk_termios.c_lflag = 0; /* Sonderbehandlungen */ + l1pp->wrk_termios.c_cflag |= (CS8 /* 8 Bit */ + |CREAD /* RX ein */ + |CLOCAL); /* kein Handshake */ + l1pp->wrk_termios.c_cflag &= ~(CSTOPB /* 1 Stop-Bit */ + |PARENB /* ohne Paritaet */ + |HUPCL); /* kein Handshake */ + + /* pty verwenden ? */ + if (l1pp->speed != B0) /* B0 -> pty soll ver- */ + { /* wendet werden */ + /* Empfangsparameter setzen */ + if (cfsetispeed(&(l1pp->wrk_termios), l1pp->speed) == -1) + { + uFehler = 4; + printf("Error: can't set input baudrate settings on device %s\n", l1pp->device); + printf(" (%s)\n", strerror(errno)); + LOGL1("Error: can't set input baudrate settings on device %s", l1pp->device); + LOGL1(" (%s)", strerror(errno)); + } + + /* Empfangsparameter setzen */ + if (cfsetospeed(&(l1pp->wrk_termios), l1pp->speed) == -1) + { + uFehler = 4; + printf("Error: can't set output baudrate settings on device %s\n", l1pp->device); + printf(" (%s)\n", strerror(errno)); + LOGL1("Error: can't set output baudrate settings on device %s", l1pp->device); + LOGL1(" (%s)", strerror(errno)); + } + + if (l1pp->speed == B38400) /* wenn >= 38400 Bd */ + { + ser_io.flags &= ~ASYNC_SPD_MASK; /* Speed-Flag -> 0 */ + ser_io.flags |= l1pp->speedflag; /* Speed-Flag setzen */ + + if (ioctl(iDescriptor, TIOCSSERIAL, &ser_io) < 0) + { + uFehler = 4; + printf("Error: can't set device settings on device %s\n", l1pp->device); + printf(" (%s)\n", strerror(errno)); + LOGL1("Error: can't set device settings on device %s", l1pp->device); + LOGL1(" (%s)", strerror(errno)); + } + } + } + } + + /* Serielle Schnittstelle auf neue Parameter einstellen */ + if (uFehler == 0) + { + tcsetattr(iDescriptor, TCSADRAIN, &(l1pp->wrk_termios)); + l1pp->port_active = TRUE; + + /* Ring ist nun offen, aber noch nicht initialisiert */ + uRingStatus = RING_IDLE; + + LOGL1("-RING-: Port erfolgreich geoeffnet"); + + return; + } + + /* Fehlerbehandlung */ + /* Port war schon offen, alte Einstellungen wiederherstellen */ + if (uFehler > 3) + tcsetattr(iDescriptor, TCSADRAIN, &(l1pp->org_termios)); + + /* Port war schon offen, aber noch nicht veraendert, nur schliessen */ + if (uFehler > 2) + { + close(iDescriptor); + iDescriptor = -1; + } + + /* Port war nicht offen, aber es existiert ein Lockfile, schliessen */ + if (uFehler > 1) + { + if (l1pp->lock != -1) + { + close(l1pp->lock); + l1pp->lock = -1; + } + } + + /* Lockfile loeschen */ + if ((*(l1pp->tnn_lockfile) != '\0') && (l1pp->lock != -1)) + unlink(l1port[i].tnn_lockfile); + + LOGL1("-RING-: Port %s konnte nicht geoeffnet werden !", l1pp->device); +} + +/************************************************************************/ +/* Device schliessen */ +/************************************************************************/ +void Sixpack_l1exit(void) +{ + register UWORD i; + + /* Erstes 6PACK-Device suchen */ + /* Alle L1-Ports durchgehen */ + for (i = 0; i < L1PNUM; ++i) + { + if (l1port[i].kisstype == KISS_6PACK) + break; + } + + /* Keinen 6PACK-Port gefunden ? */ + if (i == L1PNUM) + return; + + /* Ring wird angehalten */ + uRingStatus = RING_HALT; + + /* Serieller Port offen ? Dann schliessen */ + if (iDescriptor != -1) + { + /* Alte Porteinstellungen wiederherstellen */ + tcsetattr(iDescriptor, TCSADRAIN, &(l1port[i].org_termios)); + /* Port schliessen */ + close(iDescriptor); + iDescriptor = -1; + } + else + return; + + /* Lockfile gesetzt ? */ + if (*(l1port[i].tnn_lockfile) != '\0') + { + /* Lockfile offen ? Dann schliessen und loeschen */ + if (l1port[i].lock != -1) + { + close(l1port[i].lock); + l1port[i].lock = -1; + unlink(l1port[i].tnn_lockfile); + } + } + + /* Port nicht mehr aktiv */ + l1port[i].port_active = FALSE; + + LOGL1("-RING-: Port geschlossen"); +} + +/************************************************************************/ +/* Anzeige der TNC-Statistiken */ +/************************************************************************/ +void ccp6pack(void) +{ + MBHEAD *mbp; + register UBYTE uTNC; + register UBYTE i; + register UBYTE uNumPorts = 0; + + ULONG uUpDays = (tic10 - tLastInit) / 100; /* eigentlich sinds hier noch Sekunden ... */ + ULONG uUpHours, uUpMinutes, uUpSeconds; + +#define BUFLEN 32 + char cBuf[BUFLEN + 1]; + + /* Alle L2-Ports durchgehen */ + for (i = 0; i < L2PNUM; ++i) + if (kissmode(i) == KISS_6PACK) + ++uNumPorts; + + /* ueberhaupt ein Port da ? */ + if (uNumPorts == 0) + { + mbp = putals("No 6PACK-Ports configured."); + /* und ab die Post ... */ + putprintf(mbp, "\r"); + prompt(mbp); + seteom(mbp); + return; + } + + /* Sysop will aendern und noch was in der Zeile da ? */ + if (issyso() && skipsp(&clicnt, &clipoi)) + { + /* Frischer Buffer */ + memset(cBuf, 0, sizeof(cBuf)); + + /* Operation lesen (add, delete) */ + for (i = 0; i < BUFLEN; ++i) + { + if ((!clicnt) || (*clipoi == ' ')) + break; + clicnt--; + cBuf[i] = toupper(*clipoi++); + } + + /* Hinzufuegen (add oder +) */ + if ( (strcmp(&cBuf[0], "LOGLEVEL") == 0) + || (strcmp(&cBuf[0], "LOG") == 0) + ) + { + WORD uNewLevel; + + /* Noch was da in der Kommandozeile ? */ + if (!skipsp(&clicnt, &clipoi)) + { + mbp = getmbp(); + putprintf(mbp, "6PACK's actual loglevel is %u\r", uLogLevel); + /* und ab die Post ... */ + prompt(mbp); + seteom(mbp); + return; + } + + /* neues Loglevel lesen */ + uNewLevel = nxtnum(&clicnt, &clipoi); + + if ((uNewLevel < 0) || (uNewLevel > 4)) + { + putmsg("error: loglevel out of range (0-4) !!!\r"); + return; + } + + /* Wert uebernehmen */ + SixpackLog("-RING-: Loglevel %u -> %u", uLogLevel, uNewLevel); + uLogLevel = (UWORD)uNewLevel; + + /* und ab die Post ... */ + mbp = getmbp(); + prompt(mbp); + seteom(mbp); + return; + } + } + + mbp = putals("6PACK Error-Statistics:\r"); + + putprintf(mbp, " TX- RX- RX-Buffer-\r"); + putprintf(mbp, "-TNC#-Port#-Underrun-Overrun--Overflow--Checksum-Resets-Cal-RXC-TXC-LHeard[ms]\r"); + + /* alle TNC durchgehen */ + for (uTNC = 0; uTNC < MAX_TNC; ++uTNC) + { + /* nicht vorhandene TNC */ + if (RING[uTNC].bPresent == FALSE) + { + putprintf(mbp, " %u N/A - - - - - - - - -\r", uTNC); + continue; + } + + /* vorhandene TNC */ + putprintf(mbp, " %u %2u %5u %5u %5u %5u %5u %1u %2u %2u %5u\r", + uTNC, /* TNC */ + uMap_TNCtoPort[uTNC], /* Port */ + RING[uTNC].uTXU, /* TX-Underrun */ + RING[uTNC].uRXO, /* RX-Overrun */ + RING[uTNC].uRXB, /* RX-Buffer Overflow */ + RING[uTNC].uChecksumErr, /* Anz. Checksummenfehler */ + RING[uTNC].uReset, /* Anz. Resets */ + RING[uTNC].cTestCount, /* Anz. Calibrates */ + RING[uTNC].cRXC, /* RX-Zaehler */ + RING[uTNC].cTXC, /* TX-Zaehler */ + ((tic10 - RING[uTNC].tLastHeard) * 10)); /* LastHeard */ + } /* for (...) */ + + putprintf(mbp, "\rRing is "); + + switch (uRingStatus) + { + case RING_HALT : putprintf(mbp, "halted due to unrecoverable errors ! Please restart.\r"); + break; + + case RING_IDLE : putprintf(mbp, "waiting for TNC-initialization.\r"); + break; + + case RING_INIT : putprintf(mbp, "awaiting the return of the probe packet.\r"); + putprintf(mbp, "(%u probes sent so far, last probe sent %u ms ago)\r", uNumProbes, ((tic10 - tLastInit) * 10) ); + break; + + case RING_RUN : putprintf(mbp, "up and running for"); + + uUpSeconds = uUpDays % 60L; + uUpDays /= 60L; + uUpMinutes = uUpDays % 60L; + uUpDays /= 60L; + uUpHours = uUpDays % 24L; + uUpDays /= 24L; + + if (uUpDays < 1L) + putprintf(mbp, " %2lu:%02lu:%02lu\r", uUpHours, uUpMinutes, uUpSeconds); /* hh:mm:ss */ + else + { + if (uUpDays < 99L) + putprintf(mbp, " %2lu/%02lu:%02lu\r", uUpDays, uUpHours, uUpMinutes); /* dd/hh:mm */ + else + putprintf(mbp, " %5lu/%02lu\r", uUpDays, uUpHours); /* ddddd/hh */ + } + break; + + default: putprintf(mbp, "an undefined state !!! You really shouldn't see this ... Please restart.\r"); break; + } + + /* und ab die Post ... */ + putprintf(mbp, "\r"); + prompt(mbp); + seteom(mbp); +} + +/************************************************************************/ +/* Log-Funktion zum Debugging */ +/************************************************************************/ +void SixpackLog(const char *format, ...) +{ + FILE *fp; + va_list arg_ptr; + struct timeval tv; + static char str[30]; + char *ptr; + + fp = fopen("6pack.log", "a"); + + if (fp != NULL) + { + gettimeofday(&tv, NULL); + ptr = ctime(&tv.tv_sec); + strcpy(str, &ptr[11]); + snprintf(str + 8, sizeof(str) - 8, ".%06ld", tv.tv_usec); + fprintf(fp, "%s:", str); + + va_start(arg_ptr, format); + vfprintf(fp, format, arg_ptr); + va_end(arg_ptr); + + fprintf(fp, "\n"); + fclose(fp); + } + else + { + /* Fehler beim Schreiben in die Logdatei, dann das Logging beenden */ + uLogLevel = 0; + } +} + +/**************************************************************************/ + +#endif diff --git a/os/linux/6pack.h b/os/linux/6pack.h new file mode 100755 index 0000000..c4ea7fd --- /dev/null +++ b/os/linux/6pack.h @@ -0,0 +1,222 @@ +/************************************************************************/ +/* */ +/* ***** ***** */ +/* ***** ***** */ +/* ***** ***** */ +/* ***** ***** */ +/* *************** *************** */ +/* ***************** ***************** */ +/* *************** *************** */ +/* ***** ***** TheNetNode */ +/* ***** ***** Portable */ +/* ***** ***** Network */ +/* ***** ***** Software */ +/* */ +/* File os/linux/6pack.h (maintained by: DG9OBU) */ +/* */ +/* This file is part of "TheNetNode" - Software Package */ +/* */ +/* Copyright (C) 1998 - 2008 NORD> TNC) */ +#define CMD_LED 0x60 /* Grundmaske fuer LED-Kommando */ +#define CMD_CON 0x08 /* LED CON (PC -> TNC) */ +#define CMD_STA 0x10 /* LED STA (PC -> TNC) */ +#define CMD_CAL 0xE0 /* Calibrate (PC <> TNC) */ +#define CMD_INIT 0xE8 /* Kanalzuweisung (PC <> TNC) */ +#define CMD_PRIO 0x80 /* Prioritaetsmeldung (PC <> TNC) */ + +/* Meldungen */ +#define MSG_TXU 0x48 /* TX-Underrun (TNC -> PC) */ +#define MSG_RXO 0x50 /* RX-Overrun (TNC -> PC) */ +#define MSG_RXB 0x58 /* RX Buffer overflow (TNC -> PC) */ + +/* Bitmasken fuer Aufbau und Auswertung der Prioritaetsmeldung */ +#define MASK_TXC 0x20 /* "TX-Zaehler + 1" */ +#define MASK_RXC 0x10 /* "RX-Zaehler + 1" */ +#define MASK_DCD 0x08 /* "DCD" */ + +/* Hilfsmasken */ +#define MASK_DATA 0xC0 +#define MASK_CMD 0xF8 +#define MASK_TNCNUM 0x07 +#define MASK_PRIOCMD 0x80 +#define MASK_NORMCMD 0x40 +#define MASK_CALCNT 0x40 +#define MASK_CHAN 0x08 + +#define LED_CON 0x08 +#define LED_STA 0x10 + +#define TXWDTIME 45 /* 450ms Watchdog beim Senden */ +#define PROBE_TIMEOUT 1000 /* 10 Sekunden (= 1000 x 10ms) warten auf Zaehlpaket */ +#define TNC_TIMEOUT 500 /* 5 Sekunden Timeout fuer TNC */ +#define TNC_WATCHDOG 250 /* 2,5 Sekunden Watchdog bei Empfang */ + +/* Variablen und Strukturen */ +typedef struct tnc { + /* Kanalsteuerung */ + BOOLEAN bPresent; /* Gibt es diesen TNC im Ring ? */ + ULONG tLastHeard; /* Zeitpunkt des letzten Lebenszeichen */ + ULONG tNextArbit; /* Zeitpunkt der naechsten Kanalarbitrierung */ + ULONG tWatchdog; /* normaler Watchdog */ + ULONG tTXWatchdog; /* Watchdog waehrend TX und Calibrate */ + ULONG tPTTWatchdog; /* Watchdog fuer PTT-Kontrolle */ + UBYTE cLED; /* LEDs am TNC */ + BOOLEAN bDCD; /* DCD-Status */ + UBYTE cTXC; /* TX-Zaehler */ + UBYTE cRXC; /* RX-Zaehler */ + UBYTE cTestCount; /* Anzahl der zu sendenden Calibrates a 15 Sekunden */ + /* Statistik */ + UWORD uTXU; /* Fehlerzaehler TX-Underrun */ + UWORD uRXO; /* Fehlerzaehler RX-Overrun */ + UWORD uRXB; /* Fehlerzaehler RX Buffer Overflow */ + UWORD uReset; /* Anzahl der TNC-Resets */ + UWORD uChecksumErr; /* Anzahl Checksummenfehler */ +} TNC; + +/* Puffer fuer empfangene, rohe 6PACK-Daten */ +static UBYTE cRXRawBuffer[1024]; +static UWORD uRXRawBufferSize = 0; + +/* Puffer fuer dekodierte 6PACK-Frames */ +static UBYTE cRXBuffer[1024]; +static UWORD uRXBufferSize = 0; + +static TNC RING[(UBYTE)MAX_TNC]; + +#ifndef ATTACH +int iDescriptor = -1; +#endif /* ATTACH */ + +fd_set rset; +static struct timeval tv; + +static UWORD uLogLevel = 0; + +static UWORD uMap_TNCtoPort[MAX_TNC]; /* TNC -> Port */ +static UBYTE uMap_PorttoTNC[L2PNUM]; /* Port -> TNC */ + +static ULONG tLastInit = 0; +static UWORD uNumProbes = 0; + +UBYTE uRingStatus = RING_HALT; +UBYTE uRXStatus = RX_WAIT_SOF; +UBYTE cReceiveFrom = 0xFF; + +/* oeffentliche Funktionen */ +void Sixpack_Housekeeping(void); +void Sixpack_l1init(void); +void Sixpack_l1exit(void); +WORD Sixpack_DCD(UWORD); +void ccp6pack(void); + +/* interne Funktionen */ +void Sixpack_RX(void); +void Sixpack_TX(void); + +void startCount(void); +void toRing(UBYTE *, UWORD); + +void initTNC(UBYTE); + +/* Einfache inline-Funktionen fuer die wir (hoffentlich) */ +/* keine Debugsymbole brauchen ... */ + +/************************************************************************/ +/* Erzeugt das 6PACK LED-Kommando */ +/************************************************************************/ +UBYTE cmdLED(UBYTE uTNC) { return (CMD_LED | RING[uTNC].cLED | (uTNC & MASK_TNCNUM)); } + +/************************************************************************/ +/* Erzeugt das 6PACK Calibrate-Kommando */ +/************************************************************************/ +UBYTE cmdCAL(UBYTE uTNC) { return (CMD_CAL | (uTNC & MASK_TNCNUM)); } + +/************************************************************************/ +/* Erzeugt das 6PACK Kanalzuweisungs-Kommando */ +/************************************************************************/ +UBYTE cmdINIT(UBYTE uTNC) { return (CMD_INIT | (uTNC & MASK_TNCNUM)); } + +/************************************************************************/ +/* Erzeugt das 6PACK "TX-Zaehler + 1"-Kommando */ +/************************************************************************/ +UBYTE cmdTXC(UBYTE uTNC) { return (CMD_PRIO | MASK_TXC | (uTNC & MASK_TNCNUM)); } + +/************************************************************************/ +/* Erzeugt das 6PACK "Start of frame"-Kommando */ +/************************************************************************/ +UBYTE cmdSOF(UBYTE uTNC) { return (CMD_SOF | (uTNC & MASK_TNCNUM)); } + +/************************************************************************/ +/* Setzt die angegebene LED in der TNC-Struktur */ +/************************************************************************/ +void setLED(UBYTE uTNC, UBYTE cLED) { if (uTNC < MAX_TNC) RING[uTNC].cLED |= cLED; } + +/************************************************************************/ +/* Loescht die angegebene LED in der TNC-Struktur */ +/************************************************************************/ +void resetLED(UBYTE uTNC, UBYTE cLED) { if (uTNC < MAX_TNC) RING[uTNC].cLED &= !cLED; } + +UBYTE assignPorts(UBYTE); + +BOOLEAN DataToBuffer(UBYTE); +BOOLEAN DecodeRawBuffer(UBYTE); + +void SixpackLog(const char *, ...); + +#define LOGL1 if(uLogLevel>0)(void)SixpackLog +#define LOGL2 if(uLogLevel>1)(void)SixpackLog +#define LOGL3 if(uLogLevel>2)(void)SixpackLog +#define LOGL4 if(uLogLevel>3)(void)SixpackLog + +#endif /* __SIXPACK_H__ */ + +/* End of os/linux/6pack.h */ diff --git a/os/linux/ax25ip.c b/os/linux/ax25ip.c new file mode 100644 index 0000000..a6eba9c --- /dev/null +++ b/os/linux/ax25ip.c @@ -0,0 +1,3376 @@ +/************************************************************************/ +/* */ +/* ***** ***** */ +/* ***** ***** */ +/* ***** ***** */ +/* ***** ***** */ +/* *************** *************** */ +/* ***************** ***************** */ +/* *************** *************** */ +/* ***** ***** TheNetNode */ +/* ***** ***** Portable */ +/* ***** ***** Network */ +/* ***** ***** Software */ +/* */ +/* File os/linux/ax25ip.c (maintained by: DG9OBU) */ +/* */ +/* This file is part of "TheNetNode" - Software Package */ +/* */ +/* Copyright (C) 1998 - 2008 NORD>l4time = bufpoi->mbpc; + + /* Check auf Eintrag fuer die default-Route */ + if (rp.callsign[0] != 1) + putprintf(bufpoi, "%s", call_to_a(&rp.callsign[0])); + else + putstr("default", bufpoi); + + putspa(11, bufpoi); + + /* IP-Adresse ausgeben */ + show_ip_addr(ntohl(rp.ip_addr), bufpoi); + + putspa(29, bufpoi); + + /* UDP-Port ausgeben wenn UDP-Port gesetzt */ + if (rp.udp_port != 0) + { + /* Eine UDP-Route */ + putstr("UDP", bufpoi); + putspa(35, bufpoi); + putnum(ntohs(rp.udp_port), bufpoi); + } + else + /* Eine IP-Route */ + putstr("IP", bufpoi); + + /* Routen-Timeout anzeigen */ + if (rp.timeout != 0) + { + ULONG d = rp.timeout; + ULONG h, m, s; /* Stunden, Minuten, Sekunden */ + + s = d % 60L; + d /= 60L; + m = d % 60L; + d /= 60L; + h = d % 24L; + + putspa(40, bufpoi); + putprintf(bufpoi, " %02lu:%02lu:%02lu", h, m, s); /* hh:mm:ss */ + } + + if (rp.hostname[0] != 0) + { + putspa(50, bufpoi); + putprintf(bufpoi, "%s", rp.hostname); + } + + putstr("\r", bufpoi); +} + +/* Anzahl von IP- oder UDP-Routen in der Routingtabelle feststellen */ +/* (IP-Routen haben keinen UDP-Port gesetzt) */ +/* UDP = FALSE -> IP-Routen zaehlen, UDP = TRUE -> UDP-Routen zaehlen */ +/* Default-Route wird beachtet */ +unsigned int count_routes(BOOLEAN udp) +{ + register unsigned int i; + register unsigned int j = 0; + + /* Gesamte Routingtabelle durchgehen */ + for (i = 0; i < route_tbl_top; ++i) + { + if ( ((udp == TRUE) && (route_tbl[i].udp_port != 0)) /* UDP-Route */ + || ((udp == FALSE) && (route_tbl[i].udp_port == 0))) /* IP-Route */ + ++j; + } + + /* Default-Route */ + if (default_route.callsign[0] != 0) + { + if ( ((udp == TRUE) && (default_route.udp_port != 0)) /* UDP-Route */ + || ((udp == FALSE) && (default_route.udp_port == 0))) /* IP-Route */ + ++j; + } + + /* Anzahl Routen melden */ + return (j); +} + +/* Timeout fuer gelernte Routen */ +void route_age(void) +{ + register unsigned int i = 0; + +#ifdef AXIPR_HTML + /* htmlstatistik-timer. */ + h_timer(); +#endif + + /* Gesamte Routingtabelle durchgehen */ + for (; i < route_tbl_top; ++i) + { + /* Route mit laufendem Timer */ + if (route_tbl[i].timeout != 0) + { + /* Timer laeuft jetzt ab */ + if (--route_tbl[i].timeout == 0) + /* Route loeschen */ + route_del(route_tbl[i].callsign); + } + } +} + +/* Hostname -> IP-Adressen aufloesen */ +void route_update(struct route_table_entry *rtentry) +{ + struct hostent *hstent; + + /* Kein Hostname, dann auch keine Umwandlung moeglich */ + if (rtentry->hostname[0] == 0) + return; + + /* Hostname im IP-Adresse konvertieren */ + if ((hstent = gethostbyname((char*)&rtentry->hostname[0])) != NULL) + { + /* Bei Aenderung uebernehmen */ + if (memcmp(&rtentry->ip_addr, &hstent->h_addr_list[0][0], 4) != 0) + { + /* IP-Adresse hat sich geaendert */ + memcpy(&rtentry->ip_addr, &hstent->h_addr_list[0][0], 4); + LOGL1("IP-adress for %s changed !", rtentry->hostname); + } + } + +#ifdef AXIPR_UDP + /* Original UDP-Port setzen. */ + rtentry->udp_port = rtentry->org_udp_port; +#endif /* AXIPR_UDP */ +} + +/* Partielle Frame-Analyse fuer dyn. Eintraege */ +BOOLEAN route_canlearn(MBHEAD *fbp) +{ + char *p; /* Zeiger im Header */ + register int n; + UBYTE ctl; + + rwndmb(fbp); /* Frame von vorne */ + + for (p = rxfhdr, n = 1; n <= L2INUM + L2VNUM; ++n) + { + if (!getfid(p, fbp)) /* naechstes Call lesen */ + return (FALSE); + + p += L2IDLEN; + if (*(p - 1) & L2CEOA) + break; /* Ende des Addressfeldes */ + } + *(p - 1) &= ~L2CEOA; + *p = NUL; + ctl = getchr(fbp); /* Control-Byte extrahieren */ + ctl &= ~L2CPF; /* Poll-Flag loeschen */ + /* Nur UI, UA und SABM/SABME erzeugen einen dynamischen Eintrag */ + if ( ctl == L2CUI /* UI */ + || ctl == L2CUA /* UA */ + || ctl == L2CSABM /* SABM */ +#ifdef EAX25 + || ctl == L2CSABME /* SABME (EAX.25) */ + ) +#endif + return (TRUE); + +#ifndef AXIPR_UDP + /* Alle anderen Kontrollcodes landen hier und bewirken keinen Eintrag */ + return (FALSE); +#else + return (TRUE); +#endif +} + +/*************************************************************************/ +/* Kommandointerface fuer Operationen auf die AX25IP-Routentabelle */ +/*************************************************************************/ + +/* Eine Route anhand eines Calls loeschen, liefert TRUE wenn erfolgreich */ +BOOLEAN route_del(unsigned char *call) +{ + register int i; + register int j; + + /* Soll die Default-Route geloescht werden ? */ + if ((call == NULL) || (call[0] == NUL)) + { + /* Als unbenutzt markieren */ + default_route.callsign[0] = NUL; + + /* Pruefen, ob Sockets noch notwendig */ + ax25ip_check_down(); + return (TRUE); + } + + /* Uebergebenes Call in der Tabelle suchen */ + for (i = 0; i < route_tbl_top; ++i) + { + if (addrmatch(call, route_tbl[i].callsign)) + { + /* BINGO ! */ + /* Problem: die Tabelle hat keinen Merker, ob ein Eintrag gueltig ist, */ + /* die Eintraege haengen einfach hintereinander. Deshalb alle */ + /* Eintraege oberhalb des gefundenen Eintrages einen nach */ + /* unten kopieren und den "table-top" einen herabsetzen. */ + for (j = i; j < route_tbl_top; ++j) + route_tbl[j] = route_tbl[j + 1]; + + /* Ein Tabelleneintrag weniger */ + route_tbl_top--; + + /* Pruefen, ob Sockets noch notwendig */ + ax25ip_check_down(); + return(TRUE); + } + } + + return(FALSE); +} + +static const char inv_mode[] = "Invalid Mode\r"; +static const char inv_call[] = "Invalid Callsign\r"; +static const char inv_ip[] = "Invalid IP adress\r"; +static const char inv_par[] = "Invalid Parameter\r"; + +void +ccpaxipr(void) +{ + MBHEAD *mbp; + int port = 0; + register int i; + int tmp_fd = -1; + int new_udp = 0; + unsigned char call[L2IDLEN]; + char hostname[HNLEN + 1]; + struct hostent *host; + int uNewTimeout; +#ifdef AXIPR_UDP + int NewLogLevel = FALSE; +#endif +#ifdef AXIPR_HTML + char *timeset = set_time(); + int NewHtmlStat = FALSE; +#endif + char cBuf[BUFLEN + 1]; + unsigned int uCmd = OP_NONE; + unsigned int uMode = NO_MODE; + +#ifdef AXIPR_HTML +#define OP_HTMLSTAT 10 +#endif + + memset(hostname, 0, sizeof(hostname)); + + /* AX25IP ueberhaupt aktiv ? */ + if (ax25ip_active == FALSE) + { + putmsg("No AX25IP-interface present, nothing to configure or show !\r"); + return; + } + + /* neuen Parser verwenden ? */ + if (new_parser == TRUE) + { + + /* Sysop will aendern und noch was in der Zeile da ? */ + if (issyso() && skipsp(&clicnt, &clipoi)) + { + /* Frischer Buffer */ + memset(cBuf, 0, sizeof(cBuf)); + + /* Operation lesen (add, delete) */ + for (i = 0; i < BUFLEN; ++i) + { + if ((!clicnt) || (*clipoi == ' ')) + break; + clicnt--; + cBuf[i] = toupper(*clipoi++); + } + + /* Zum alten Parser zurueckschalten */ + if ( (strcmp(cBuf, "OLD") == 0) + || (cBuf[0] == 'O') + ) + { + new_parser = FALSE; + putmsg("Switched to old axipr-parser !!!\r"); + return; + } + + /* Hinzufuegen (add oder +) */ + if ( (strcmp(cBuf, "ADD") == 0) + || (cBuf[0] == '+') + ) + uCmd = OP_ADD; + + /* Loeschen (delete, del oder -) */ + if ( (strcmp(cBuf, "DELETE") == 0) + || (strcmp(cBuf, "DEL") == 0) + || (cBuf[0] == '-') + ) + uCmd = OP_DEL; + + /* eigenen UDP-Port aendern */ + if (strcmp(cBuf, "MYUDP") == 0) + uCmd = OP_MYUDP; + + /* Namensaufloesungsintervall einstellen */ + if (strcmp(cBuf, "LOOKUP") == 0) + uCmd = OP_HNUPD; + + /* Loglevel */ + if ( (strcmp(cBuf, "LOGLEVEL") == 0) + || (strcmp(cBuf, "LOG") == 0) + ) + uCmd = OP_LOG; + + /* Timeout fuer dynamische Routen */ + if (strcmp(cBuf, "TIMEOUT") == 0) + uCmd = OP_TIMEOUT; + +#ifdef AXIPR_HTML + /* htmlstatistik */ + if ( (strcmp(cBuf, "HTMLSTAT") == 0) + || (strcmp(cBuf, "H") == 0)) + + uCmd = OP_HTMLSTAT; +#endif + + /* Fehler bei der Auswertung ? */ + if (uCmd == OP_NONE) + { + putmsg(inv_mode); + return; + } + + /* Hier rein, wenn der Timeout fuer dynamische Routen geaendert werden soll */ + if (uCmd == OP_TIMEOUT) + { + int uNewTimeout; + + /* Noch was da in der Kommandozeile ? */ + if (!skipsp(&clicnt, &clipoi)) + { + mbp = getmbp(); + putprintf(mbp, "the actual timeout for dynamic routes is : %u\r", uDynTimeout); + /* und ab die Post ... */ + prompt(mbp); + seteom(mbp); + return; + } + + /* Timeout lesen */ + uNewTimeout = nxtlong(&clicnt, &clipoi); + + if ( (uNewTimeout < 0) + ||(uNewTimeout > (86400))) /* max. 1 Tag */ + { + putmsg("error: timeout out of range (0 - 86400) !\r"); + return; + } + + /* Wert uebernehmen */ + uDynTimeout = uNewTimeout; + + /* und ab die Post ... */ + mbp = getmbp(); + prompt(mbp); + seteom(mbp); + return; + } + + /* Hier rein, wenn das Intervall der Namensaufloesung geaendert werden soll */ + if (uCmd == OP_HNUPD) + { + UWORD uNewInterval; + + /* Noch was da in der Kommandozeile ? */ + if (!skipsp(&clicnt, &clipoi)) + { + mbp = getmbp(); + + putprintf(mbp, "Hostname-update "); + + if (uNamesUpdate != 0) + putprintf(mbp, "occurs every %u seconds.\r", uNamesUpdate / 100); + else + putprintf(mbp, "is disabled at the moment.\r"); + + /* und ab die Post ... */ + prompt(mbp); + seteom(mbp); + return; + } + + /* Timeout lesen */ + uNewInterval = nxtnum(&clicnt, &clipoi); + + if (uNewInterval > 3600) /* max. eine Stunde */ + { + putmsg("error: value out of range (0 - 3600 seconds) !\r"); + return; + } + + /* Wert uebernehmen */ + uNamesUpdate = uNewInterval * 100; + + /* und ab die Post ... */ + mbp = getmbp(); + prompt(mbp); + seteom(mbp); + return; + } + + /* Hier rein, wenn der Loglevel geaendert werden soll */ + if (uCmd == OP_LOG) + { + int new_loglevel; + + /* Noch was da in der Kommandozeile ? */ + if (!skipsp(&clicnt, &clipoi)) + { + mbp = getmbp(); + putprintf(mbp, "my actual loglevel is : %u\r", loglevel); + /* und ab die Post ... */ + prompt(mbp); + seteom(mbp); + return; + } + + /* neues Loglevel lesen */ + new_loglevel = nxtnum(&clicnt, &clipoi); + + if ( (new_loglevel < 0) + ||(new_loglevel > 4)) + { + putmsg("error: loglevel out of range (0 - 4) !!!\r"); + return; + } + + /* Wert uebernehmen */ + loglevel = new_loglevel; + + /* und ab die Post ... */ + mbp = getmbp(); + prompt(mbp); + seteom(mbp); + return; + } + +#ifdef AXIPR_HTML + if (uCmd == OP_HTMLSTAT) + { + /* Noch was da in der Kommandozeile ? */ + if (!skipsp(&clicnt, &clipoi)) + { + mbp = getmbp(); +#ifdef SPEECH + putprintf(mbp, speech_message(347),HtmlStat); +#else + putprintf(mbp, "HTML-Statistic is %d\r", HtmlStat); +#endif + /* und ab die Post ... */ + prompt(mbp); + seteom(mbp); + return; + } + + /* Timeout lesen */ + NewHtmlStat = nxtnum(&clicnt, &clipoi); + + if ( (NewHtmlStat < 0) + ||(NewHtmlStat > 1)) + { +#ifdef SPEECH + putmsg(speech_message(300)); +#else + putmsg("errors: Log level worth from 0 to 1!\r"); +#endif + return; + } + + /* Wert uebernehmen */ + HtmlStat = NewHtmlStat; + + /* und ab die Post ... */ + mbp = getmbp(); + prompt(mbp); + seteom(mbp); + return; + } +#endif + + /* Hier nur rein, wenn wir als naechstes eine UDP-Portnummer erwarten */ + if (uCmd == OP_MYUDP) + { + /* Noch was da in der Kommandozeile ? */ + if (!skipsp(&clicnt, &clipoi)) + { + mbp = getmbp(); + putprintf(mbp, "my actual UDP-port is : %u\r", ntohs(my_udp)); + /* und ab die Post ... */ + prompt(mbp); + seteom(mbp); + return; + } + + /* neue UDP-Portnummer lesen */ + new_udp = nxtlong(&clicnt, &clipoi); + + if ( (new_udp <= 0) + ||(new_udp > 65535)) + { + putmsg("error: UDP-port number not valid (0 - 65535) !!!\r"); + return; + } + +#ifdef AXIPR_UDP + /* Neuer UDP-Port gleich MY-UDP? */ + /* Keine Aenderungen durchfuehren. */ + if (my_udp == htons((unsigned short)new_udp)) + { + /* und ab die Post ... */ + mbp = getmbp(); + prompt(mbp); + seteom(mbp); + return; + } +#endif /* AXIPR_UDP */ + +#ifndef AXIPR_UDP + /* Laufendes UDP aendern */ + if (fd_udp != -1) + { +#endif + /* Versuchen, neuen UDP-Port anzulegen */ + if ((tmp_fd = setup_udp(htons((unsigned short)new_udp))) != -1) + { +#ifndef AXIPR_UDP + /* Neuen Descriptor eintragen und alten schliessen */ + close(fd_udp); +#else + /* Nur wenn alter Socket noch lebt, */ + if (fd_udp != EOF) + /* dann schliessen wir den Socket. */ + close(fd_udp); +#endif /* AXIPR_UDP */ + + fd_udp = tmp_fd; + /* Gibt es einen Eintrag. */ + if (l1pp) + /* Check, ob neuer Filedescriptor groesser ist */ + l1pp->kisslink = max(fd_ip, fd_udp); + + /* Neuen UDP-Port merken */ + my_udp = htons((unsigned short)new_udp); + } + else + { + putmsg("error: changing the UDP-port failed !!!\r"); + return; + } +#ifndef AXIPR_UDP + } + else + { + /* neuen UDP-Port merken */ + my_udp = htons((unsigned short)new_udp); + } +#endif + /* und ab die Post ... */ + mbp = getmbp(); + prompt(mbp); + seteom(mbp); + return; + } + + /* Noch was da in der Kommandozeile ? */ + if (!skipsp(&clicnt, &clipoi)) + { + putmsg("syntax error: callsign missing\r"); + return; + } + + /* Frischer Buffer */ + memset(cBuf, 0, sizeof(cBuf)); + + /* Call lesen */ + for (i = 0; i < BUFLEN; ++i) + { + if ((!clicnt) || (*clipoi == ' ')) + break; + + clicnt--; + cBuf[i] = toupper(*clipoi++); + } + + /* Operation auf Default-Route ? */ + if (strcmp(cBuf, "DEFAULT") == 0) + call[0] = NUL; /* Leere Callstring als Indikator fuer Defaultroute */ + else + { + /* Call konvertieren und pruefen */ + if (a_to_call(cBuf, call) != 0) + { + putmsg(inv_call); + return; + } + } + + /* Wenn wir loeschen wollen, brauchen wir nichts mehr */ + if (uCmd != OP_DEL) + { + /* Noch was da in der Kommandozeile ? */ + if (!skipsp(&clicnt, &clipoi)) + { + putmsg("syntax error: IP-adress missing\r"); + return; + } + + /* Frische Buffer */ + memset(hostname, 0, sizeof(hostname)); + + /* Hostnamen / IP-Adresse lesen */ + for (i = 0; i < HNLEN; ++i) + { + if (!clicnt || *clipoi == ' ') + break; + + clicnt--; + hostname[i] = *clipoi++; + } + + /* eventuellen Hostnamen aufloesen */ + if ((host = gethostbyname(hostname)) == NULL) + { + mbp = getmbp(); + putprintf(mbp, "Warning: can't resolve IP for host %s ! I keep trying ...\r", hostname); + prompt(mbp); + seteom(mbp); + } + else + { + strncpy(hostname, host->h_name, sizeof(hostname)); + } + } /* if (uCmd != OP_DEL) */ + + /* Optionale UDP-Parameter lesen */ + skipsp(&clicnt, &clipoi); + + /* Frischer Buffer */ + memset(cBuf, 0, sizeof(cBuf)); + + /* Mode lesen (IP, UDP) */ + for (i = 0; i < BUFLEN; ++i) + { + if ((!clicnt) || (*clipoi == ' ')) + break; + + clicnt--; + cBuf[i] = toupper(*clipoi++); + } + + /* Mode bestimmen (UDP) */ + /* Bei der Initialisierung wurde bereits IP eingestellt */ + if ( (strcmp(cBuf, "UDP") == 0) + || (cBuf[0] == 'U') + ) + uMode = UDP_MODE; + + /* Noch was da in der Kommandozeile ? */ + if (!skipsp(&clicnt, &clipoi)) + port = DEFAULT_UDP_PORT; + else + { + /* neue UDP-Portnummer lesen */ + port = nxtlong(&clicnt, &clipoi); + + if ( (port <= 0) + ||(port > 65535)) + { + putmsg("error: UDP-port number not valid\r"); + return; + } + } + + /* Operation ausfuehren */ + switch (uCmd) + { + /* Route hinzufuegen */ + case OP_ADD : +#ifndef AXIPR_UDP + route_add((unsigned char*)&hostname, host, call, (uMode == UDP_MODE ? port : 0), (call[0] == 0 ? TRUE : FALSE), 0); + break; +#else + if (route_add((unsigned char*)&hostname + , host + , call + , (uMode == UDP_MODE ? (int)port : 0) + , (call[0] == 0 ? TRUE : FALSE) + , 0 + , hostname +#ifdef AXIPR_HTML + , timeset + , P_USER +#endif /* AXIPR_HTML */ + )) + putmsg("Call is registerd.\r"); + + return; +#endif /* AXIPR_UDP */ + + /* Route loeschen */ + case OP_DEL : +#ifndef AXIPR_UDP + route_del(call); + break; +#else + + if (route_del(call)) + putmsg("Call is deleted!\r"); + else + putmsg("Call no deleted!\r"); + + return; +#endif /* AXIPR_UDP. */ + + + default : break; + } + + mbp = getmbp(); + /* und ab die Post ... */ + prompt(mbp); + seteom(mbp); + return; + } + + } + else + { + /* ALTE SYNTAX */ + + /* Sysop will aendern und noch was in der Zeile da ? */ + if (issyso() && skipsp(&clicnt, &clipoi)) + { + clicnt--; + + switch (toupper(*clipoi++)) + { + case 'P': /* Parser aendern */ + /* wir koennen nur in den neuen Parser umschalten */ + new_parser = TRUE; + putmsg("Switched to new axipr-parser !!!\r"); + return; + break; + + case 'R': /* Routen-Eintrag */ + /* Kommandozeile pruefen */ + if (!skipsp(&clicnt, &clipoi)) + { + putmsg(inv_par); + return; + } + + clicnt--; + + switch (*clipoi++) + { + case '-': /* Route loeschen */ + /* Call lesen */ + if (getcal(&clicnt, &clipoi, TRUE, (char *)call) != YES) + { + invcal(); + return; + } + + /* Call konvertieren */ + for (i = 0; i < L2CALEN; ++i) + call[i] = call[i] << 1; + +#ifdef AXIPR_UDP + /* und ab die Post ... */ + mbp = getmbp(); + + if (route_del(call)) + putstr("Call is delete!\r", mbp); + else + putstr("Call no delete!\r", mbp); + + prompt(mbp); + seteom(mbp); + return; +#else + /* Route loeschen */ + route_del(call); + break; +#endif /* AXIPR_UDP. */ + + case '+': /* Route hinzufuegen */ + /* Call lesen */ + if (getcal(&clicnt, &clipoi, TRUE, (char *)call) != YES) + { + invcal(); + return; + } + + /* Call linksschieben */ + for (i = 0; i < L2CALEN; ++i) + call[i] = call[i] << 1; + + /* Noch was da in der Kommandozeile ? */ + if (!skipsp(&clicnt, &clipoi)) + { + putmsg("IP-Adress/Hostname missing\r"); + return; + } + + /* Frische Buffer */ + memset(hostname, 0, sizeof(hostname)); + + /* Hostnamen / IP-Adresse lesen */ + for (i = 0; i < HNLEN; ++i) + { + if (!clicnt || *clipoi == ' ') + break; + + clicnt--; + hostname[i] = *clipoi++; + } + + /* Hostname / IP-Adresse aufloesen */ + if ((host = gethostbyname(hostname)) == NULL) + { + putmsg(inv_ip); + return; + } + + /* Mode-Parameter vorhanden ? */ + if (skipsp(&clicnt, &clipoi)) + { + --clicnt; + switch (toupper(*clipoi++)) + { + case 'I': /* IP: Port steht fest */ + break; + case 'U': /* UDP: abweichenden Port lesen wenn vorhanden */ + nextspace(&clicnt, &clipoi); + if (!skipsp(&clicnt, &clipoi)) + port = DEFAULT_UDP_PORT; + else + { + port = nxtlong(&clicnt, &clipoi); + + if ( (port <= 0) + ||(port > 65535)) + { + putmsg("error: UDP-port number not valid\r"); + return; + } + } + break; + + default: /* unbekannter Modus */ + putmsg(inv_mode); + return; + } + } + /* Route hinzufuegen */ +#ifndef AXIPR_UDP + route_add((unsigned char*)&hostname, host, call, (int) port, FALSE, 0); + break; +#else + if (route_add((unsigned char *)&hostname + , host + , call + , (int) port + , FALSE + , 0 + , hostname +#ifdef AXIPR_HTML + , timeset + , P_USER +#endif /* AXIPR_HTML */ + )) + putmsg("Call is registerd.\r"); + + return; +#endif /* AXIPR_UDP */ + + } + break; + + case 'D': /* Default Route aendern */ + + nextspace(&clicnt, &clipoi); + + /* Noch Eingaben da ? */ + if (!skipsp(&clicnt, &clipoi)) + { + putmsg(inv_mode); + return; + } + + clicnt--; + + /* Operation bestimmen */ + switch (*clipoi++) + { + case '-': /* Default Route loeschen */ +#ifdef AXIPR_UDP + /* und ab die Post ... */ + mbp = getmbp(); + + if (route_del((unsigned char *)"")) + putstr("Call is delete!\r", mbp); + else + putstr("Call no delete!\r", mbp); + + prompt(mbp); + seteom(mbp); + return; +#else + route_del((unsigned char *)""); + break; +#endif /* AXIPR_UDP. */ + + case '+': /* Default Route eingeben */ + + /* IP-Adresse / Hostname lesen */ + if (!skipsp(&clicnt, &clipoi)) + { + putmsg(inv_ip); + return; + } + + /* Frische Buffer */ + memset(hostname, 0, sizeof(hostname)); + + /* IP-Adresse / Hostname kopieren */ + for (i = 0; i < HNLEN; ++i) + { + if (!clicnt || *clipoi == ' ') + break; + clicnt--; + hostname[i] = *clipoi++; + } + + /* aufloesen */ + if ((host = gethostbyname(hostname)) == NULL) + { + putmsg(inv_ip); + return; + } + + /* Modus-Kennzeichner lesen falls vorhanden */ + if (skipsp(&clicnt, &clipoi)) + { + --clicnt; + switch (toupper(*clipoi++)) + { + case 'I': /* IP: Port steht fest */ + break; + case 'U': /* UDP: eventuell abweichenden Port lesen */ + nextspace(&clicnt, &clipoi); + + if (!skipsp(&clicnt, &clipoi)) + port = DEFAULT_UDP_PORT; + else + { + port = nxtlong(&clicnt, &clipoi); + + if ( (port <= 0) + ||(port > 65535)) + { + putmsg("error: UDP-port number not valid\r"); + return; + } + } + break; + default: /* unbekannter Modus */ + putmsg(inv_mode); + return; + } + } + /* Route eintragen */ +#ifndef AXIPR_UDP + route_add((unsigned char*)&hostname, host, NULL, (int) port, TRUE, 0); + break; +#else + if (route_add((unsigned char*)&hostname + , host + , NULL + , (int) port + , TRUE + , 0 + , hostname +#ifdef AXIPR_HTML + , timeset + , P_USER +#endif /* AXIPR_HTML */ + )) + putmsg("Call is registerd.\r"); + + return; +#endif /* AXIPR_UDP */ + + default: + putmsg(inv_mode); + return; + } + break; + + /* Eigenen UDP-Port aendern */ + case 'U': + /* neuer Port muss vorhanden sein */ + if (!skipsp(&clicnt, &clipoi)) + { + putmsg(inv_par); + return; + } + + /* UDP-Port ermitteln */ + new_udp = nxtlong(&clicnt, &clipoi); + + if ( (new_udp <= 0) + ||(new_udp > 65535)) + { + putmsg("UDP-Port not valid, not changed !!!\r"); + return; + } + +#ifdef AXIPR_UDP + /* Neuer UDP-Port gleich MY-UDP? */ + /* Keine Aenderungen durchfuehren. */ + if (my_udp == htons((unsigned short)new_udp)) + { + /* und ab die Post ... */ + mbp = getmbp(); + prompt(mbp); + seteom(mbp); + return; + } +#endif /* AXIPR_UDP */ + +#ifndef AXIPR_UDP + /* Laufendes UDP aendern */ + if (fd_udp != -1) + { +#endif + /* Versuchen, neuen UDP-Port anzulegen */ + if ((tmp_fd = setup_udp(htons((unsigned short)new_udp))) != -1) + { +#ifndef AXIPR_UDP + /* Neuen Descriptor eintragen und alten schliessen */ + close(fd_udp); +#else + /* Nur wenn alter Socket noch lebt, */ + if (fd_udp != EOF) + /* dann schliessen wir den Socket. */ + close(fd_udp); +#endif /* AXIPR_UDP */ + + fd_udp = tmp_fd; + /* Gibt es einen Eintrag. */ + if (l1pp) + /* Check, ob neuer Filedescriptor groesser ist */ + l1pp->kisslink = max(fd_ip, fd_udp); + + /* Neuen UDP-Port merken */ + my_udp = htons((unsigned short)new_udp); + } + else + { + putmsg("ERROR: Changing UDP-Port failed, Port not changed !!!\r"); + return; + } +#ifndef AXIPR_UDP + } + else + { + /* neuen UDP-Port merken */ + my_udp = htons((unsigned short)new_udp); + } +#endif + + putmsg("UDP-Port successfully changed\r"); +#ifdef AXIPR_UDP + return; +#else + break; +#endif /* AXIPR_UDP. */ + + /* Timeout fuer dynamische Routen aendern. */ + case 'T': + + /* Noch was da in der Kommandozeile ? */ + if (!skipsp(&clicnt, &clipoi)) + { + mbp = getmbp(); + putprintf(mbp, "the actual timeout for dynamic routes is : %u\r", uDynTimeout); + /* und ab die Post ... */ + prompt(mbp); + seteom(mbp); + return; + } + + /* Timeout lesen */ + uNewTimeout = nxtlong(&clicnt, &clipoi); + + if ( (uNewTimeout < 0) + ||(uNewTimeout > (86400))) /* max. 1 Tag */ + { + putmsg("error: timeout out of range (0 - 86400) !\r"); + return; + } + + /* Wert uebernehmen */ + uDynTimeout = uNewTimeout; + + /* und ab die Post ... */ + mbp = getmbp(); + prompt(mbp); + seteom(mbp); + return; + +#ifdef AXIPR_UDP + /* Loglevel aendern. */ + case 'L': + + /* Noch was da in der Kommandozeile ? */ + if (!skipsp(&clicnt, &clipoi)) + { + mbp = getmbp(); +#ifdef SPEECH + putprintf(mbp, speech_message(299),loglevel); +#else + putprintf(mbp, "My LogLevel: %d\r",loglevel); +#endif + /* und ab die Post ... */ + prompt(mbp); + seteom(mbp); + return; + } + + /* Loglevel lesen */ + NewLogLevel = nxtnum(&clicnt, &clipoi); + + if ( (NewLogLevel < 0) + ||(NewLogLevel > 4)) + { +#ifdef SPEECH + putmsg(speech_message(300)); +#else + putmsg("errors: Log level worth from 0 to 4!\r"); +#endif + return; + } + + /* Wert uebernehmen */ + loglevel = NewLogLevel; + + /* und ab die Post ... */ + mbp = getmbp(); + prompt(mbp); + seteom(mbp); + return; +#endif /* AXIPR_UDP */ + +#ifdef AXIPR_HTML + /* htmlstatistik aendern. */ + case 'H': + + /* Noch was da in der Kommandozeile ? */ + if (!skipsp(&clicnt, &clipoi)) + { + mbp = getmbp(); +#ifdef SPEECH + putprintf(mbp, speech_message(347),HtmlStat); +#else + putprintf(mbp, "HTML-Statistic is %d\r", HtmlStat); +#endif + /* und ab die Post ... */ + prompt(mbp); + seteom(mbp); + return; + } + + /* Loglevel lesen */ + NewHtmlStat = nxtnum(&clicnt, &clipoi); + + if ( (NewHtmlStat < 0) + ||(NewHtmlStat > 1)) + { +#ifdef SPEECH + putmsg(speech_message(348)); +#else + putmsg("Error: HTML-Statistic worth from 0 to 1!\r\r"); +#endif + return; + } + + /* Wert uebernehmen */ + HtmlStat = NewHtmlStat; + + /* und ab die Post ... */ + mbp = getmbp(); + prompt(mbp); + seteom(mbp); + return; +#endif + + /* Unbekannte Kommandos */ + default: + putmsg(inv_par); + return; + } + } + } + + mbp = putals("AXIP-Routes:\rCall-------IP----------------Mode--Port--Timeout--IP/Hostname----\r"); + + /* Alle Routingtabelleneintraege durchgehen und ausgeben */ + for (i = 0; i < route_tbl_top; ++i) + show_rt_entry(route_tbl[i], mbp); + + /* Default-Route ausgeben wenn vorhanden */ + if (default_route.callsign[0] == 1) + show_rt_entry(default_route, mbp); + + putprintf(mbp, "-----------------------------------------------------------------\r"); + + /* Eigenen UDP-Port ausgeben */ + putprintf(mbp, "UDP-port (%u): ", ntohs(my_udp)); + putprintf(mbp, "%s", (fd_udp != -1 ? "active" : "not active")); + + /* IP-Status ausgeben */ + putprintf(mbp, ", IP-protocol (family %u): ", IPPROTO_AX25); + putprintf(mbp, "%s", (fd_ip != -1 ? "active" : "not active")); + + /* Timeout des dynamischen Routenlerners ausgeben */ + putprintf(mbp, "\rTimeout for dynamically learned routes is %u seconds.\r", uDynTimeout); + + /* Hostname -> IP-Adresse Aktualisierungsintervall ausgeben */ + putprintf(mbp, "Hostname-to-IP-adress conversion "); + + if (uNamesUpdate != 0) + putprintf(mbp, "occurs every %u seconds.\r", uNamesUpdate / 100); + else + putprintf(mbp, "is disabled.\r"); + +#ifdef AXIPR_UDP +#ifdef SPEECH + putprintf(mbp, speech_message(299), loglevel); +#else + putprintf(mbp, "My LOGLevel is %u.\r", loglevel); +#endif /* SPEECH */ +#endif /* AXIPR_UDP */ + +#ifdef AXIPR_HTML +#ifdef SPEECH + putprintf(mbp, speech_message(347), HtmlStat); +#else + putprintf(mbp, "My HTML-Statistic is %d.\r", HtmlStat); +#endif /* SPEECH */ +#endif /* AXIPR_HTML */ + + /* und ab die Post ... */ + prompt(mbp); + seteom(mbp); +} + +/* Routeneintraege fuer parms.tnb ausgeben */ +void dump_ax25ip(MBHEAD* mbp) +{ + register int i; + + putstr(";\r; AX25IP Routes\r;\r", mbp); + + if (new_parser == TRUE) + { + putstr("; WARNING: this section is written using the new syntax of the AXIPR-command,\r", mbp); + putstr("; DO NOT USE with older TNNs compiled only for old style syntax !!!\r;\r", mbp); + + /* Falls wir noch im alten Parser sind, dann umschalten */ + putprintf(mbp, "AXIPR P\r"); + /* eigenen UDP-Port ausgeben */ + putprintf(mbp, "AXIPR MYUDP %u\r", ntohs(my_udp)); + /* Timeout fuer dynamische Routen ausgeben */ + putprintf(mbp, "AXIPR TIMEOUT %u\r", uDynTimeout); + /* Intervall fuer Hostnamen-Update ausgeben */ + putprintf(mbp, "AXIPR LOOKUP %u\r", uNamesUpdate); + } + +#ifdef AXIPR_UDP + /* eigenen UDP-Port ausgeben */ + putprintf(mbp, "AXIPR U %u\r", ntohs(my_udp)); + /* Timeout fuer dynamische Routen ausgeben */ + putprintf(mbp, "AXIPR T %u\r", uDynTimeout); + + putprintf(mbp, "AXIPR L %d\r",loglevel); + +#ifdef AXIPR_HTML + putprintf(mbp, "AXIPR H %d\r",HtmlStat); +#endif /* AXIPR_HTML */ +#endif /* AXIPR_UDP */ + + /* alle Routingtabelleneintraege durchgehen und ausgeben */ + for (i = 0; i < route_tbl_top; ++i) + { + /* Dynamisch gelernte Routen werden nicht geschrieben ! */ + if (route_tbl[i].timeout != 0) + continue; + +/* putprintf(mbp, "; ");*/ + + /* Eintrag einer Route erzeugen */ + putprintf(mbp, (new_parser == FALSE ? "AXIPR R + %s " : "AXIPR ADD %s ") + , call_to_a(&route_tbl[i].callsign[0])); + + /* Den Hostnamen ausgeben */ + putprintf(mbp, "%s", route_tbl[i].hostname); + + /* Mode und ggf. Port ausgeben wenn UDP */ + if (route_tbl[i].udp_port != 0) + { + putstr((new_parser == FALSE ? " U " : " UDP "), mbp); + putnum(ntohs(route_tbl[i].udp_port), mbp); + } + + putstr("\r", mbp); + } + + /* Die Defaultroute ausgeben wenn gesetzt */ + if (default_route.callsign[0] == 1) + { + /* Kommandokopf schreiben */ + putstr((new_parser == FALSE ? "AXIPR D + " : "AXIPR ADD DEFAULT "), mbp); + + /* Den Hostnamen ausgeben */ + putprintf(mbp, "%s", default_route.hostname); + + /* Mode und ggf. Port ausgeben wenn UDP */ + if (default_route.udp_port != 0) + { + putstr((new_parser == FALSE ? " U " : " UDP "), mbp); + putnum(ntohs(default_route.udp_port), mbp); + } + putstr("\r", mbp); + } +} + +/************************************************************************/ +/* AX25IP Initialisierung */ +/************************************************************************/ +BOOLEAN ax25ip_l1init(int l2port) +{ + if (ax25ip_active == TRUE) + return(TRUE); + + /* Socketstrukturen initialisieren */ + memset((char*)&to, 0, sizeof(to)); + memset((char*)&from, 0, sizeof(from)); + + ax25ip_port = l2port; + l1pp = &l1port[l1ptab[l2port]]; + l2flp = (LHEAD *) &txl2fl[l2port]; + + /* Routingtabelle initialisieren */ + route_init(); + + /* Konfiguration einlesen */ + if (config_read() == FALSE) + return(FALSE); + + /* Notwendige Sockets anlegen */ +#ifndef AXIPR_UDP + ax25ip_check_up(); +#endif + + /* Wir sind fertig */ + ax25ip_active = TRUE; + return(TRUE); +} + +/* Einen Filedescriptor fuer IP anlegen */ +int setup_ip(void) +{ + /* Temporaerer Filedescriptor */ + int tmp_fd = -1; + + /* Adressstruktur loeschen */ + memset((char*)&ipbind, 0, sizeof(ipbind)); + + /* Rohen IP-Socket anlegen */ + if ((tmp_fd = socket(AF_INET, SOCK_RAW, IPPROTO_AX25)) < 0) + { + xprintf("AX25IP : cannot create ip raw-socket: %s\n", strerror(errno)); + LOGL2("AX25IP : cannot create ip raw-socket: %s\n", strerror(errno)); + return(-1); + } + + /* Nonblocking-IO */ + if (fcntl(tmp_fd, F_SETFL, FNDELAY) < 0) + { + xprintf("AX25IP : cannot set non-blocking I/O on ip raw-socket\n"); + LOGL2("AX25IP : cannot set non-blocking I/O on ip raw-socket\n"); + close(tmp_fd); + return(-1); + } + + /* Socket-Optionen fuer RAW-IP einstellen */ + /* SO_KEEPALIVE einschalten */ + if (sockopt_keepalive == TRUE) + { + int iFlag = 1; + + if (setsockopt(tmp_fd, SOL_SOCKET, SO_KEEPALIVE, &iFlag, sizeof(int)) < 0) + { + xprintf("AX25IP : cannot set SO_KEEPALIVE for ip : %s\n", strerror(errno)); + LOGL2("AX25IP : cannot set SO_KEEPALIVE for ip : %s\n", strerror(errno)); + } + } + + /* Socket auf max. Durchsatz */ + if (sockopt_throughput == TRUE) + { + int iFlag = IPTOS_THROUGHPUT; + + if (setsockopt(tmp_fd, IPPROTO_IP, IP_TOS, &iFlag, sizeof(IPTOS_THROUGHPUT)) < 0) + { + xprintf("AX25IP : cannot set IPTOS_THROUGHPUT for ip : %s\n", strerror(errno)); + LOGL2("AX25IP : cannot set IPTOS_THROUGHPUT for ip : %s\n", strerror(errno)); + } + } + + /* Adressstruktur mit notwendigen Werten fuellen */ + ipbind.sin_family = AF_INET; + ipbind.sin_addr.s_addr = htonl(INADDR_ANY); + + return (tmp_fd); +} + +/* Einen Filedescriptor fuer UDP anlegen */ +/* Es muss der UDP-Port angegeben werden, auf dem wir hoeren wollen */ +/* (Achtung: UDP-Port in Network-Byteorder) */ +int setup_udp(unsigned short udp_port) +{ + /* Temporaerer Filedescriptor */ + int tmp_fd = -1; + + /* Port-Check */ + if (udp_port == 0) + return(-1); + + /* Adressstruktur loeschen */ + memset((char*)&udpbind, 0, sizeof(udpbind)); + + /* UDP-Socket anlegen */ + if ((tmp_fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) + { + xprintf("AX25IP : cannot create socket: %s\n", strerror(errno)); + LOGL2("AX25IP : cannot create socket: %s\n", strerror(errno)); + return(-1); + } + + /* Nonblocking-IO */ + if (fcntl(tmp_fd, F_SETFL, FNDELAY) < 0) + { + xprintf("AX25IP : cannot set non-blocking I/O on udp socket\n"); + LOGL2("AX25IP : cannot set non-blocking I/O on udp socket\n"); + close(tmp_fd); + return(-1); + } + + /* Adressstruktur fuellen */ + udpbind.sin_addr.s_addr = htonl(INADDR_ANY); + udpbind.sin_port = udp_port; + udpbind.sin_family = AF_INET; + + /* Adresse und Port binden */ + if (bind(tmp_fd, (struct sockaddr *)&udpbind, sizeof(udpbind)) < 0) + { + xprintf("AX25IP : cannot bind udp socket: %s\n", strerror(errno)); + LOGL2("AX25IP : cannot bind udp socket: %s\n", strerror(errno)); + close(tmp_fd); + return(-1); + } + + return(tmp_fd); +} + +/* Pruefen, ob schon Sockets angelegt sind, wenn nicht, dann notwendige */ +/* Sockets oeffnen */ +void ax25ip_check_up(void) +{ + /* IP notwendig ? */ + if ((count_routes(FALSE) != 0) && (fd_ip == -1)) + fd_ip = setup_ip(); /* IP starten */ + + /* UDP notwendig ? */ + if ((count_routes(TRUE) != 0) && (fd_udp == -1)) + fd_udp = setup_udp(my_udp); /* UDP starten */ + +#ifdef AXIPR_UDP + if (l1pp != NULL) +#endif + /* Markieren, ob IP oder UDP laufen */ + l1pp->kisslink = max(fd_ip, fd_udp); +} + +/* Pruefen, ob Sockets angelegt sind und diese noch benoetigt werden. */ +/* Falls nicht, Sockets schliessen */ +void ax25ip_check_down(void) +{ + /* IP notwendig ? */ + if ((count_routes(FALSE) == 0) && (fd_ip != -1)) + { + close(fd_ip); + fd_ip = -1; + } + + /* UDP notwendig ? */ + if ((count_routes(TRUE) == 0) && (fd_udp != -1)) + { + close(fd_udp); + fd_udp = -1; + } + + /* Gibt es einen Eintrag. */ + if (l1pp) + /* Markieren, ob IP oder UDP laufen */ + l1pp->kisslink = max(fd_ip, fd_udp); +} + +/*************************************************************************/ +/* AX25IP Pakete empfangen */ +/*************************************************************************/ +void ax25ip_recv(void) +{ + struct ip *ipptr; + struct timeval tv; + int l = 0; + int iDescriptorsReady = 0; + register int i = 0; + register int max_fd = -1; + socklen_t fromlen = sizeof(from); + int hdr_len = 0; + UBYTE buf[MAX_FRAME+1]; + UBYTE *bufptr; + MBHEAD *rxfhd; + BOOLEAN UDP_Frame = FALSE; + fd_set rmask; + +#ifdef AXIPR_UDP + if (LookAX25IP) + return; +#endif /* AX25IP_UDP */ + + FD_ZERO(&rmask); + + /* IP-Filedescriptor eintragen */ + if (fd_ip != -1) + { + FD_SET(fd_ip, &rmask); + if (fd_ip > max_fd - 1) + max_fd = fd_ip + 1; + } + + /* UDP-Filedescriptor eintragen */ + if (fd_udp != -1) + { + FD_SET(fd_udp, &rmask); + if (fd_udp > max_fd - 1) + max_fd = fd_udp + 1; + } + + /* ist was aktiv ? */ + if (max_fd == -1) + return; + + tv.tv_usec = 0; + tv.tv_sec = 0; + + iDescriptorsReady = select(max_fd, &rmask, NULL, NULL, &tv); + + /* nix da */ + if (iDescriptorsReady == 0) + return; + + /* Fehler */ + if (iDescriptorsReady == -1) + { + LOGL2("select()-Error %i: %s", errno, strerror(errno)); + return; + } + + /* RX fuer IP */ + if ((fd_ip != -1) && (FD_ISSET(fd_ip, &rmask))) + { + l = recvfrom(fd_ip, (UBYTE *)(bufptr = buf), MAX_FRAME, 0, (struct sockaddr *) &from, &fromlen); + + if (l > 0) + { + if (l > sizeof(struct ip)) + { + ipptr = (struct ip*)buf; + hdr_len = 4 * ipptr->ip_hl; + + if (!ok_crc(buf + hdr_len, l - hdr_len)) + { /* stimmt die CRC ? */ + LOGL2("IP-RX: CRC-Error, frame dropped"); + return; /* Fehler */ + } + } + else + { + LOGL2("IP-RX: frame too short, frame dropped"); + return; /* Fehler */ + } + } + i = hdr_len; + } + + /* RX fuer UDP, aber nur, wenn nicht schon TCP was empfangen hat */ + if ((fd_udp != -1) && (FD_ISSET(fd_udp, &rmask) && (l == 0))) + { + l = recvfrom(fd_udp, (UBYTE *)(bufptr = buf), MAX_FRAME, 0, (struct sockaddr *) &from, &fromlen); + + if (l > 0) + { + if (!ok_crc(buf, l)) + { /* stimmt die CRC ? */ + LOGL2("UDP-RX: CRC-Error, frame dropped"); + return; /* Fehler */ + } + } + UDP_Frame = TRUE; + } + + /* Ab hier gemeinsame Behandlung */ + /* Erst mal gucken, ob was gekommen ist */ + if (l == 0) + return; /* nix da */ + + l -= 2; /* CRC abschneiden */ + + if (l < 15) + { + LOGL2("AX25IP: RX frame dropped, length wrong, frame is too short !"); + return; + } + + /* Hier angekommen haben wir (hoffentlich) ein gueltiges Frame. Die */ + /* weitere Behandlung ist fuer IP und UDP nahezu identisch. */ + + /* Frame in Buffer umkopieren und Empfangsport eintragen */ + rxfhd = cpyflatmb((char*)&buf[i], l - i); + rxfhd->l2port = ax25ip_port; + + /* Frame in die L2-RX-Kette einhaengen */ + relink((LEHEAD *)rxfhd, (LEHEAD *)rxfl.tail); + + /* Jetzt noch das Frame an den Routenlerner zur Analyse */ + if (route_canlearn(rxfhd)) + { + /* Frame kann zum Lernen benutzt werden */ + /* Absenderrufzeichen ermitteln und konvertieren */ + /* Wir brauchen hier nicht den eigentlichen Absender, */ + /* sondern den, der als letztes gedigipeated hat. */ + struct in_addr ipaddr; +#ifndef AXIPR_UDP + struct route_table_entry* rtptr; +#endif /* AXIPR_UDP */ + unsigned char srccall[L2IDLEN + 1]; + + cpyid((char *)srccall, dheardcall(rxfhdr)); + + /* Call linksschieben */ + for (i = 0; i < L2CALEN; ++i) + srccall[i] = srccall[i] << 1; + + /* Gibt es schon eine IP fuer dieses Call, dann kann sich die IP */ + /* geaendert haben. Falls ja und es sich um einen dynamischen Eintrag */ + /* handelt, dann loeschen und neuen Eintrag anlegen. */ +#ifndef AXIPR_UDP + if ((rtptr = call_to_ip(srccall)) != NULL) + { + if (( (rtptr->ip_addr != from.sin_addr.s_addr) + || (rtptr->udp_port != (UDP_Frame == TRUE ? ntohs(from.sin_port) : 0))) + && (rtptr->timeout != 0)) + route_del(srccall); /* Route loeschen */ + else + { + if (rtptr != &default_route) + return; /* Adresse unveraendert */ + } + } +#endif /* AXIPR_UDP */ + + ipaddr.s_addr = from.sin_addr.s_addr; + +#ifndef AXIPR_UDP + /* Route eintragen */ + route_add((unsigned char*)inet_ntoa(ipaddr), NULL, srccall, + (UDP_Frame == TRUE ? ntohs(from.sin_port) : 0), FALSE, uDynTimeout); +#else + route_analyse(ipaddr, srccall, + (UDP_Frame == TRUE ? ntohs(from.sin_port) : 0)); + } +#endif /* AXIPR_UDP */ +} + +void ax25ip_send(void) +{ + unsigned char buf[MAX_FRAME]; + int len = 0; + int fd = -1; + MBHEAD *txfhdl; + + struct route_table_entry *rt; + struct hostent *hstent; + + unsigned char *call; + + if (kick[ax25ip_port]) /* haben wir was zu senden ? */ + { + /* Sicherheitsabfrage, da kick[] auch manipuliert werden kann */ + if (l2flp->head == l2flp) + { + kick[ax25ip_port] = FALSE; + return; + } + + ulink((LEHEAD *)(txfhdl = (MBHEAD *) l2flp->head));/*Zeiger holen*/ + + /* Daten aus den internen Puffern in einen linearen Puffer uebertragen */ + len = cpymbflat((char*)&buf[0], txfhdl); + + relink((LEHEAD *)txfhdl, /* als gesendet betrachten und in */ + (LEHEAD *)stfl.tail); /* die gesendet Liste umhaengen */ + + kick[ax25ip_port] = ((LHEAD *)l2flp->head != l2flp); + + /* Naechstes Call der Digipeaterkette holen */ + call = next_addr(buf); + + /* IP-Adresse des naechsten Digipeaters ermitteln */ + rt = call_to_ip(call); + + if (rt == NULL) /* wir kennen das Ziel nicht */ + { +#ifdef AXIPR_UDP + if ((rt = search_route(call)) == NULL) + { +#endif + LOGL2("no route for %s, can't send", call_to_a(call)); + return; + } +#ifdef AXIPR_UDP + } +#endif + + /* Ein Host, zu dem bisher keine IP-Adresse aufgeloest werden konnte */ + if (rt->ip_addr == 0L) + { + /* Versuchen, jetzt eine IP-Adresse zu bestimmen */ + if ((hstent = gethostbyname((char*)rt->hostname)) != NULL) + memcpy((unsigned char*)&rt->hostname, (unsigned char *)&hstent->h_addr_list[0][0], 4); + } + + /* Checksumme anhaengen */ + add_ax25crc(buf, len); + /* CRC-Bytes sind dazugekommen */ + len += 2; + /* Ziel-IP-Adresse in Sendestruktur eintragen */ + memcpy((char *) &to.sin_addr, (char *)&rt->ip_addr, 4); + /* Ziel-Port nur bei UDP eintragen */ + if (rt->udp_port != 0) + memcpy((char *) &to.sin_port, (char *)&rt->udp_port, 2); + else + to.sin_port = 0; /* bei IP kein Port */ + + to.sin_family = AF_INET; + + /* Unterscheidung IP oder UDP */ + if (to.sin_port == 0) + fd = fd_ip; + else + fd = fd_udp; + + if (fd == -1) + { + LOGL2("error: no descriptor, can't send !!!"); + return; + } + + if (sendto(fd, (char *)buf, len, 0, (struct sockaddr *)&to, sizeof(to)) < 0) + LOGL2("error: sendto failed, fd=%u error=%s", fd, strerror(errno)); + } +} + +/*************************************************************************/ +/* AX25IP Deinitialisierung, Port und Sockets schliessen */ +/*************************************************************************/ +void ax25ip_l1exit(void) +{ + /* Nur wenn aktiv */ + if (ax25ip_active == FALSE) + return; + + /* IP-Socket schliessen wenn offen */ + if (fd_ip != -1) + { + close(fd_ip); + fd_ip = -1; + } + + /* UDP-Socket schliessen wenn offen */ + if (fd_udp != -1) + { + close(fd_udp); + fd_udp = -1; + } + + /* AX25IP nicht mehr aktiv */ + ax25ip_active = FALSE; + + /* Gibt es einen Eintrag. */ + if (l1pp) + l1pp->kisslink = -1; +} + +void ax25ip_l1ctl(int req, int port) +{ + /* nur eigene Ports bearbeiten */ + if ((ax25ip_active == FALSE) || (kissmode(port) != KISS_AXIP)) + return; + + switch (req) + { + /* Testpattern auf dem Port senden (wird unterdrueckt) */ + case L1CTST : testflag[port] = FALSE; + kick[port] = FALSE; + break; + + default : break; + } +} + +void ax25ip_hwstr(int port, MBHEAD *mbp) +{ +#ifdef AXIPR_UDP + putstr(" ", mbp); + /* My UDP-Port ausgeben. */ + putprintf(mbp,"%u", ntohs(my_udp)); +#endif +} + +BOOLEAN ax25ip_dcd(int port) +{ + return (FALSE); +} + + +/* routing.c Routing table manipulation routines + * + * Copyright 1991, Michael Westerhof, Sun Microsystems, Inc. + * This software may be freely used, distributed, or modified, providing + * this header is not removed. + * + + * Modified for use in TNN by DG1KWA & DG9OBU + + */ + + + +/* Initialize the routing table */ +void route_init(void) +{ + /* Defaultroute initialisieren */ + memset(&default_route, 0 , sizeof(struct route_table_entry)); + + /* Routen initialisieren */ + memset(&route_tbl, 0, (TABLE_SIZE * sizeof(struct route_table_entry))); +} + +/* Add a new route entry */ +#ifndef AXIPR_UDP +static void route_add(unsigned char* hostname, struct hostent *hstent, unsigned char *call, int udpport, + int default_rt, int timeout) +#else +static BOOLEAN route_add(unsigned char *host, struct hostent *hstent, unsigned char *call, int udpport, + int default_rt, int timeout, char *hostname +#ifdef AXIPR_HTML + , char *timeset, UWORD protokoll +#endif /* AXIPR_HTML */ + ) +#endif /* AXIPR_UDP */ +{ + register unsigned int i = 0; + struct route_table_entry *rtptr; + struct hostent *hst; + + /* Eintrag soll Defaultroute sein */ + if (default_rt) + { + for (i = 1; i < 7 ;++i) + default_route.callsign[i] = 0; + + if (hstent != NULL) + memcpy(&default_route.ip_addr, (unsigned char *)&hstent->h_addr_list[0][0], 4); + else + memset(&default_route.ip_addr, 0, 4); + + default_route.udp_port = htons((unsigned short)udpport); + default_route.timeout = 0; /* Defaultroute ohne Timeout */ + + if (hostname != NULL) + strncpy((char*)&default_route.hostname, (char*)hostname, HNLEN); + + default_route.callsign[0] = 1; /* mark valid */ + + /* Socket ggf. installieren */ + ax25ip_check_up(); + +#ifndef AXIPR_UDP + return; +#else + return(TRUE); +#endif /* AXIPR_UDP */ + } + + /* Normale Routen nur wenn Call vorhanden */ + if (call == NULL) +#ifndef AXIPR_UDP + return; +#else + return(FALSE); +#endif /* AXIPR_UDP */ + + /* Check auf doppelte Eintraege, Eintrag wird nur angenommen wenn */ + /* es noch noch keinen Eintrag unter diesem Call gibt. */ + if (((rtptr = call_to_ip(call)) != NULL) && (rtptr->ip_addr != default_route.ip_addr)) + { +#ifndef AXIPR_UDP + putmsg("A route to this callsign is already set up, delete it first.\r"); + return; +#else +#ifndef AXIPR_HTML + UpdateRoute(call, udpport, timeout, hostname); +#else + UpdateRoute(call, udpport, timeout, hostname, timeset, protokoll); +#endif /* AXIPR_HTML */ + return(FALSE); +#endif /* AXIPR_UDP */ + } + + /* Passt noch ein Eintrag in die Tabelle ? */ + if (route_tbl_top >= TABLE_SIZE) + { + xprintf("Routing table is full; entry ignored.\n"); + LOGL2("Routing table is full; entry ignored"); + putmsg("Routing table is full, entry ignored\r"); +#ifndef AXIPR_UDP + return; +#else + return(FALSE); +#endif /* AXIPR_UDP */ + } + + /* Call eintragen */ + for (i = 0; i < 6; ++i) + route_tbl[route_tbl_top].callsign[i] = call[i] & 0xfe; + + /* SSID eintragen */ + route_tbl[route_tbl_top].callsign[6] = (call[6] & 0x1e) | 0x60; + + if (hstent != NULL && hstent->h_length != 0) + { + memcpy((unsigned char*)&route_tbl[route_tbl_top].ip_addr, (unsigned char *)&hstent->h_addr_list[0][0], 4); + } + else + memset(&route_tbl[route_tbl_top].ip_addr, 0, sizeof(route_tbl[route_tbl_top].ip_addr)); + + route_tbl[route_tbl_top].udp_port = htons((unsigned short)udpport); + route_tbl[route_tbl_top].timeout = timeout; + + if (hostname != NULL) + { + memcpy(&route_tbl[route_tbl_top].hostname, hostname, strlen((char*)hostname)); + /* Keine Adressaufloesung bisher, dann probieren wir es noch einmal */ + if (hstent == NULL) + { + if ((hst = gethostbyname((char*)hostname)) != NULL) + memcpy((unsigned char*)&route_tbl[route_tbl_top].ip_addr, &hst->h_addr_list[0][0], 4); + } + } + +#ifdef AXIPR_UDP + /* Original UDP-Port eintragen. */ + route_tbl[route_tbl_top].org_udp_port = htons((UWORD)udpport); +#endif + +#ifdef AXIPR_HTML + /* Hostname eintragen. */ + (void)memcpy(route_tbl[route_tbl_top].timeset, timeset, 17); + /* Protokoll eintragen. */ + route_tbl[route_tbl_top].protokoll = P_USER; + /* Route als offline markieren. */ + route_tbl[route_tbl_top].online = FALSE; +#endif + + /* Ein Routeneintrag mehr */ + route_tbl_top++; + + /* Socket ggf. installieren */ + ax25ip_check_up(); + +#ifndef AXIPR_UDP + return; +#else + return(TRUE); +#endif /* AXIPR_UDP */ +} + +/* + * Return an IP address and port number given a callsign. + * We return a pointer to the address; the port number can be found + * immediately following the IP address. (UGLY coding; to be fixed later!) + */ + +struct route_table_entry* call_to_ip(unsigned char *call) +{ + register int i; + unsigned char mycall[7]; + + /* Leere Calls koennen nicht verarbeitet werden */ + if (call == NULL) + return (NULL); + + /* Call-Bytes kopieren, letztes Bit abschneiden (entspricht >> 1 & 7F) */ + for (i = 0; i < 6; ++i) + mycall[i] = call[i] & 0xfe; + + /* SSID kopieren */ + mycall[6] = (call[6] & 0x1e) | 0x60; + + /* Routingtabelle durchsuchen */ + for (i = 0; i < route_tbl_top; ++i) + { + if (addrmatch(mycall , route_tbl[i].callsign)) + { + /* Aktivitaet auf diesem Eintrag, dann Timeout erneuern */ + if (route_tbl[i].timeout) + route_tbl[i].timeout = uDynTimeout; + + return (&route_tbl[i]); /* Eintrag gefunden */ + } + } + + /* Kein Routingeintrag vorhanden, Default-Route melden wenn vorhanden */ + if (default_route.callsign[0]) + return (&default_route); + + /* Kein Routingeintrag gefunden, keine Defaultroute */ + return (NULL); +} + +/* + * tack on the CRC for the frame. Note we assume the buffer is long + * enough to have the two bytes tacked on. + */ +void add_ax25crc(unsigned char *buf, int l) +{ + unsigned short int u = compute_crc(buf, l); + + buf[l] = u & 0xff; /* lsb first */ + buf[l + 1] = (u >> 8) & 0xff; /* msb next */ +} + + +/* + ********************************************************************** + * The following code was taken from Appendix B of RFC 1171 + * (Point-to-Point Protocol) + * + * The RFC credits the following sources for this implementation: + * + * Perez, "Byte-wise CRC Calculations", IEEE Micro, June, 1983. + * + * Morse, G., "Calculating CRC's by Bits and Bytes", Byte, + * September 1986. + * + * LeVan, J., "A Fast CRC", Byte, November 1987. + * + * + * The HDLC polynomial: x**0 + x**5 + x**12 + x**16 + */ + +/* + * u16 represents an unsigned 16-bit number. Adjust the typedef for + * your hardware. + */ +/*typedef unsigned short u16;*/ + + +/* + * FCS lookup table as calculated by the table generator in section 2. + */ +static UWORD fcstab[256] = { + 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf, + 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7, + 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e, + 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876, + 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd, + 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5, + 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c, + 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974, + 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb, + 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3, + 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a, + 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72, + 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9, + 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1, + 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738, + 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70, + 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7, + 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff, + 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036, + 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e, + 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5, + 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd, + 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134, + 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c, + 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3, + 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb, + 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232, + 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a, + 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1, + 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9, + 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330, + 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78 +}; + +#define PPPINITFCS 0xffff /* Initial FCS value */ +#define PPPGOODFCS 0xf0b8 /* Good final FCS value */ + +/* + * Calculate a new fcs given the current fcs and the new data. + */ +UWORD pppfcs(register UWORD fcs, register unsigned char *cp, register int len) +{ + while (len--) + fcs = (fcs >> 8) ^ fcstab[(fcs ^ *cp++) & 0xff]; + + return(fcs); +} + +/* + * End code from Appendix B of RFC 1171 + ********************************************************************** + */ + +/* + * The following routines are simply convenience routines... + * I'll merge them into the mainline code when suitably debugged + */ + +/* Return the computed CRC */ +UWORD compute_crc(unsigned char *buf, int l) +{ + UWORD fcs = (pppfcs(PPPINITFCS, buf, l) ^ 0xFFFF); + + return (fcs); +} + +/* Return true if the CRC is correct */ +BOOLEAN ok_crc(unsigned char *buf, int l) +{ + UWORD fcs = pppfcs(PPPINITFCS, buf, l); + + return (fcs == PPPGOODFCS); +} + +/* return true if the addresses supplied match */ +int addrmatch(unsigned char *a, unsigned char *b) +{ + if ((*a == '\0') || (*b == '\0')) return(0); + + if ((*a++ ^ *b++) & 0xfe) return(0); /* "K" */ + if ((*a++ ^ *b++) & 0xfe) return(0); /* "A" */ + if ((*a++ ^ *b++) & 0xfe) return(0); /* "9" */ + if ((*a++ ^ *b++) & 0xfe) return(0); /* "W" */ + if ((*a++ ^ *b++) & 0xfe) return(0); /* "S" */ + if ((*a++ ^ *b++) & 0xfe) return(0); /* "B" */ + if ((*a++ ^ *b++) & 0x1e) return(0); /* ssid */ + return(1); +} + +/* return pointer to the next station to get this packet */ +unsigned char *next_addr(unsigned char *f) +{ + unsigned char *a; + + /* If no digis, return the destination address */ + if (NO_DIGIS(f)) return(f); + + /* check each digi field. The first one that hasn't seen it is the one */ + a = f + 7; + do { + a += 7; + if (NOTREPEATED(a)) return(a); + } while (NOT_LAST(a)); + +/* all the digis have seen it. return the destination address */ + return(f); +} + +/* Open and read the config file */ +int config_read(void) +{ + FILE *cf; + char buf[256], cbuf[256]; + int errflag = 0; + int e = 0; + int lineno = 0; + char cfgfile[256]; + + strcpy(cfgfile, confpath); + strcat(cfgfile, CONFIG_FILE); + + if ((cf = fopen(cfgfile, "r")) == NULL) + { +#ifdef INIPATH + strcpy(cfgfile, INIPATH); + strcat(cfgfile, CONFIG_FILE); + + if ((cf = fopen(cfgfile, "r")) == NULL) + { +#endif +#ifdef AXIPR_UDP + /* AX25IP.CFG ist nicht mehr noetig, */ + /* kann aber weiterhin benutzt werden. */ + return(TRUE); +#endif + xprintf("AX25IP: Config file %s not found or could not be opened\n", CONFIG_FILE); + return(FALSE); +#ifdef INIPATH + } +#endif + } + + while (fgets(buf, 255, cf) != NULL) + { + (void)strcpy(cbuf, buf); + ++lineno; + + if ((e = parse_line(buf)) < 0) + { + xprintf("Config error at line %d: ", lineno); + + switch (e) + { + case -1 : xprintf("Missing argument\n"); break; + case -2 : xprintf("Bad callsign format\n"); break; + case -3 : xprintf("Bad option - on/off\n"); break; + case -4 : xprintf("Bad option - tnc/digi\n"); break; + case -5 : xprintf("Host not known\n"); break; + case -6 : xprintf("Unknown command\n"); break; + case -7 : xprintf("Text string too long\n"); break; + case -8 : xprintf("Bad option - every/after\n"); break; + case -9 : xprintf("Bad option - ip/udp\n"); break; + + default: xprintf("Unknown error\n"); break; + } + xprintf("%s", cbuf); + ++errflag; + } + } + + if (errflag) + exit(1); + + if (mode == NO_MODE) + { + xprintf("Must specify ip and/or udp sockets\n"); + return(FALSE); + } + + fclose(cf); + + return(TRUE); +} + +/* Process each line from the config file. The return value is encoded. */ +int parse_line(char *buf) +{ + char *p; + char *q; + char hostname[HNLEN]; + unsigned char tcall[7]; + struct hostent hstent; + struct hostent *he; + int i = 0; + int uport = 0; + int dfalt = 0; +#ifdef AXIPR_HTML + char *timeset = set_time(); +#endif + + p = strtok(buf, " \t\n\r"); + + /* Leere Zeilen */ + if (p == NULL) + return(0); + + /* Kommentarzeilen nicht auswerten */ + if (*p == '#') + return(0); + + if (strcmp(p, "socket") == 0) + { + q = strtok(NULL, " \t\n\r"); + + if (q == NULL) + return(-1); + + if (strcmp(q, "ip") == 0) + mode = IP_MODE; + else if (strcmp(q, "udp") == 0) + { + mode = UDP_MODE; + my_udp = htons(DEFAULT_UDP_PORT); + + /* Bei UDP optionale Portnummer lesen */ + q = strtok(NULL, " \t\n\r"); + + /* Nummer war vorhanden, auswerten */ + if (q != NULL) + { + i = atoi(q); + /* Nummer ist gueltig, uebernehmen */ + if (i > 0) + my_udp = htons(i); + } + } + else + return(-9); + + return(0); + } + else if (strcmp(p, "socketoption") == 0) + { + q = strtok(NULL, " \t\n\r"); + + /* Pruefung auf leere Zeile */ + if (q == NULL) + return(-1); + + if (strcmp(q, "SO_KEEPALIVE") == 0) + { + sockopt_keepalive = TRUE; + } + else if (strcmp(q, "IPTOS_THROUGHPUT") == 0) + { + sockopt_throughput = TRUE; + } + else return(-9); + + return(0); + + } else if (strcmp(p, "loglevel") == 0) { + q = strtok(NULL, " \t\n\r"); + if (q == NULL) return(-1); + loglevel = atoi(q); + return(0); + + } else if (strcmp(p, "route") == 0) { + uport = 0; + dfalt = 0; + + q = strtok(NULL, " \t\n\r"); + + /* Pruefung auf leere Zeile */ + if (q == NULL) + return(-1); + + /* Pruefung auf default-Route */ + if (strcmp(q, "default") == 0) + dfalt = 1; + else + { + /* Ziel der Route pruefen */ + if (a_to_call(q, tcall) != 0) + return(-2); + } + + /* Hostnamen holen, dies kann auch eine IP-Adresse sein */ + q = strtok(NULL, " \t\n\r"); + if (q == NULL) + return(-1); + + he = gethostbyname(q); + + /* Keine gueltige IP-Adresse ? */ + if (he == NULL) + { + /* Da route_add() eine hostent-Struktur braucht, bauen wir ihm eine. */ + /* Den Hostname sichern und den Zeiger auf den Puffer im hostent eintragen. */ + strncpy(hostname, q, HNLEN); + + he = &hstent; + he->h_name = hostname; + } + + q = strtok(NULL, " \t\n\r"); + + if (q != NULL) + { + if (strcmp(q, "udp") == 0) + { + uport = DEFAULT_UDP_PORT; + + q = strtok(NULL, " \t\n\r"); + if (q != NULL) + { + i = atoi(q); + if (i > 0) + uport = i; + } + } + } +#ifndef AXIPR_UDP + route_add((unsigned char*)he->h_name, he, tcall, uport, dfalt, 0); +#else + route_add((unsigned char*)he->h_name, he, tcall, uport, dfalt, 0, (char *)he->h_name +#ifdef AXIPR_HTML + , timeset, P_USER +#endif /* AXIPR_HTML */ + ); +#endif /* AXIPR_UDP */ + return(0); + } + return(-999); +} + + +/* Convert ascii callsign to internal format */ +int a_to_call(char *text, unsigned char *tcall) +{ + register size_t i = 0; + int ssid = 0; + unsigned char c; + + if (strlen(text) == 0) + return(-1); + + for (i = 0; i < 6; ++i) + tcall[i] = (' ' << 1); + + tcall[6] = '\0'; + + for (i = 0; i < strlen(text); ++i) + { + c = text[i]; + if (c == '-') + { + ssid = atoi(&text[i + 1]); + if (ssid > 15) + return(-1); + tcall[6] = (ssid << 1); + return(0); + } + + if (islower(c)) + c = toupper(c); + + if (i > 5) + return(-1); + + tcall[i] = (c << 1); + } + return(0); +} + +/* Convert internal callsign to printable format */ +char *call_to_a(unsigned char *tcall) +{ + int i = 0; + int ssid = 0; + char *tptr; + static char t[10]; + + for (i = 0, tptr = t; i < 6; ++i) + { + if (tcall[i] == (' ' << 1)) + break; + *tptr = tcall[i] >> 1; + tptr++; + } + + ssid = (tcall[6] >> 1) & 0x0f; + if (ssid > 0) + { + *tptr = '-'; + tptr++; + + if (ssid > 9) + { + *tptr = '1'; + tptr++; + ssid -= 10; + } + *tptr = '0' + ssid; + tptr++; + } + + *tptr = '\0'; + return(&t[0]); +} + +void write_log(const char *format, ...) +{ + FILE *fp; + va_list arg_ptr; + struct tm *lt; + + fp = fopen("ax25ip.log", "a+"); + + if (fp != NULL) + { + lt = localtime(&sys_time); + fprintf(fp, "%16.16s:", ctime(&sys_time)); + va_start(arg_ptr, format); + vfprintf(fp, format, arg_ptr); + va_end(arg_ptr); + fprintf(fp, "\n"); + fclose(fp); + } +} + +#ifdef AXIPR_UDP +/* AX25IP-Frame untersuchen, wenn Aenderungen */ +/* z.B. UDP-Port, IP-Adresse in TBL Aktualisieren.*/ +void route_analyse(struct in_addr ip, unsigned char *call, int uport) +{ + register int i; + char mycall[7]; + +#ifdef AXIPR_HTML + char *timeset = set_time(); +#endif /* AXIPR_HTML */ + + /* Leere Calls koennen nicht verarbeitet werden */ + if (call[0] == FALSE) + return; + + /* Call-Bytes kopieren, letztes Bit abschneiden (entspricht >> 1 & 7F) */ + for (i = 0; i < 6; ++i) + mycall[i] = call[i] & 0xfe; + + /* SSID kopieren */ + mycall[6] = (call[6] & 0x1e) | 0x60; + + /* Routingtabelle durchsuchen */ + for (i = 0; i < route_tbl_top; ++i) + { + if (addrmatch((unsigned char *)mycall , route_tbl[i].callsign)) + { + /* Bei Aenderung uebernehmen */ + if (memcmp(&ip, &route_tbl[i].ip_addr, 4) != 0) + /* IP-Adresse hat sich geaendert */ + memcpy(&route_tbl[i].ip_addr, &ip, 4); + + /* UDP-Port unterschiedlich? */ + if (route_tbl[i].udp_port != htons((UWORD)uport)) + /* UDP-Port updaten. */ + route_tbl[i].udp_port = htons((UWORD)uport); + +#ifdef AXIPR_HTML + /* Route ggf. auf online setzen. */ + if (!route_tbl[i].online) + route_tbl[i].online = TRUE; +#endif + /* Aktivitaet auf diesem Eintrag, dann Timeout erneuern */ + if (route_tbl[i].timeout) + route_tbl[i].timeout = uDynTimeout; + + /* Aktualisierung beendet. */ + return; + } + } + +#ifndef AXIPR_HTML + /* Auto-Route eintragen */ + route_add((unsigned char*)inet_ntoa(ip), NULL, call,uport, FALSE, uDynTimeout, (char*)inet_ntoa(ip)); +#else + /* Auto-Route eintragen */ + route_add((unsigned char*)inet_ntoa(ip), NULL, call,uport, FALSE, uDynTimeout, (char*)inet_ntoa(ip), timeset, P_USER); +#endif /* AXIPR_HTML */ +} + +/* Per Rufzeichen, ohne die SSID zubeachten, einen */ +/* Routeneintrag suchen. Gibt es keinen Eintrag, */ +/* wird sofort abgebrochen, ansonsten werden die */ +/* routeneintraege IP-Adresse und UDP-Port ueber- */ +/* nommen und das neue Rufzeichen wird eingetragen.*/ +struct route_table_entry *search_route(unsigned char *call) +{ + register int i; + char srccall[10]; +#ifdef AXIPR_HTML + char *timeset = set_time(); +#endif /* AXIPR_HTML */ + + /* Konvertiere Rufzeichen. */ + callss2str((char *)srccall, call_to_a(call)); + + /* TB durchgehen. */ + for (i = 0; i < route_tbl_top; ++i) + { + /* Suche Rufzeichen. */ + if (cmpcal(srccall, call_to_a(&route_tbl[i].callsign[0]))) + { +#ifndef AXIPR_HTML + /* Auto-Route eintragen */ + route_add((unsigned char *)&route_tbl[i].ip_addr, NULL, (unsigned char *)call, htons(route_tbl[i].org_udp_port), FALSE, uDynTimeout, (char *)route_tbl[i].hostname); +#else + /* Auto-Route eintragen */ + route_add((unsigned char *)&route_tbl[i].ip_addr, NULL, (unsigned char *)call, htons(route_tbl[i].org_udp_port), FALSE, uDynTimeout, (char *)route_tbl[i].hostname, timeset, P_USER); +#endif /* AXIPR_HTML */ + /* Aktuellen Eintrag weiterreichen. */ + return (&route_tbl[i]); /* Eintrag gefunden */ + } + } + /* Kein Rufzeichen gefunden. */ + return (NULL); +} + +/* Eine AX-Route Updaten. */ +void UpdateRoute(unsigned char *srccall, + int udpport, + int timeout, + char *hostname +#ifdef AXIPR_HTML + , char *timeset + , UWORD protokoll +#endif /* AXIPR_HTML */ +) +{ + MBHEAD *mbp; + register int i; + + /* TB durchgehen. */ + for (i = 0; i < route_tbl_top; ++i) + { + /* Suche Rufzeichen. */ + if (addrmatch((unsigned char *)srccall , route_tbl[i].callsign)) + { + route_tbl[i].org_udp_port = route_tbl[i].udp_port = htons((unsigned short)udpport); + /* Hostname eintragen. */ + (void)memcpy(route_tbl[i].hostname, hostname, HNLEN); + /* ggf. Timeout setzen. */ + route_tbl[i].timeout = timeout; + +#ifdef AXIPR_HTML + /* Hostname eintragen. */ + (void)memcpy(route_tbl[i].timeset, timeset, 17); + /* Protokoll eintragen. */ + route_tbl[i].protokoll = P_USER; +#endif /* AXIPR_HTML */ + + mbp = getmbp(); + + /* und ab die Post ... */ + prompt(mbp); + seteom(mbp); + return; + } + } +} + +#ifdef AXIPR_HTML + +/* Protokoll fuer HTML-Ausgabe setzen. */ +void SetHTML(int port, char *call, PEER *pp, BOOLEAN flag) +{ + register int i; + char srccall[10 + 1]; + + call2str(srccall, call); + + /* Routingtabelle durchsuchen */ + for (i = 0; i < route_tbl_top; ++i) + { + if (!strcmp(srccall , call_to_a(&route_tbl[i].callsign[0]))) + { + /* Protokoll setzen. */ + set_status(i, port, pp); + + /* Route auf online/offline stellen. */ + route_tbl[i].online = flag; + + break; + } + } +} + +/* Aktualisiere Loginzeit fuer TB */ +char *set_time(void) +{ + time_t go; + struct tm *zeit; + static char c[17]; + char *timeset = c; + + /* aktuelle Kalenderzeit */ + time(&go); + /* konvertiert Datum und Uhrzeit. */ + zeit = localtime(&go); + /* Formatiere eine Zeit-/Datumsangabe */ + strftime(c,17,"%d-%b-%H:%M:%S",zeit); + +/* Aktuelle Login Date/Time */ +return(timeset); +} + +/* Protokoll setzen. */ +void set_status(register int a, int port, PEER *pp) +{ + if (pp == NULL) /* Route wird ausgetragen. */ + { + route_tbl[a].protokoll = P_OFFLINE; /* Route auf OFFLINE setzen. */ + route_tbl[a].online = FALSE; + return; + } + + switch(pp->typ) /* Protokol-TYP. */ + { + case INP : /* INP-TYP. */ + route_tbl[a].protokoll = P_INP; /* INP-TYP setzen. */ + break; + + case TNN : /* TNN-TYP */ + case THENET : /* THENET-TYP. */ + route_tbl[a].protokoll = P_THENET; /* TNN/THENET-TYP setzen. */ + break; + + case FLEXNET: /* FLEXNET-TYP. */ + route_tbl[a].protokoll = P_FLEXNET; /* FLEXNET-TYP setzen. */ + break; + + default: + route_tbl[a].protokoll = P_OFFLINE; /* Route auf OFFLINE setzen. */ + route_tbl[a].online = FALSE; + return; + } + + route_tbl[a].online = TRUE; +} + +/* Timer fuer htmlstatistik. */ +void h_timer(void) +{ + static LONG h_Timer = 0L; + + /* Timer abgelaufen. */ + if (h_Timer <= 0L) + { + /* Timer neu setzen. */ + /* fest auf 60 sec. */ + h_Timer = 60L; + /* html auf Platte schreiben. */ + w_statistik(); + } + /* Timer runter zaehlen. */ + h_Timer--; +} + +/* Hiermit checken wir ob die rstat.css existiert. */ +/* FALSE = keine rstat.css gefunden */ +/* TRUE = es existiert eine rstat.css */ +static int check_css_file(void) +{ + char cssfile[255]; + + /* Path kopieren. */ + strcpy(cssfile, htmlpath); + /* CSS-Dateiname anhaengen. */ + strcat(cssfile, CSS_RFILE); + + /* Pruefe ob Datei existiert.*/ + if (!access(cssfile,FALSE)) + /* Datei existiert. */ + return(TRUE); + else + /* Nix gefunden! */ + return(FALSE); +} + +/* Eine default RSTAT.CSS schreiben */ +static void rstat_css_default_file(void) +{ + FILE *fp; + char cfgfile[255]; + + if (HtmlStat == FALSE) + return; + + strcpy(cfgfile, htmlpath); + strcat(cfgfile, CSS_RFILE); + if ((fp = fopen(cfgfile, "w+t")) == NULL) + return; + + fprintf(fp,"BODY {\n" + " BACKGROUND-IMAGE: url('bg.jpg');\n" + " BACKGROUND-COLOR: #000080;\n" + " COLOR: #FFFFFF;\n" + " FONT-FAMILY: Verdana, Arial;\n" + " FONT-SIZE: 12;\n" + "}\n"); + + fprintf(fp,"H1 {\n" + " FONT-SIZE: 18; COLOR: #FFCC00;\n" + "}\n"); + + fprintf(fp,"H2 {\n" + " FONT-SIZE: 12; COLOR: #FFFFFF;\n" + "}\n"); + + fprintf(fp,"a:link, a:visited {\n" + " COLOR: #FFFFFF;\n" + " text-weight: bold;\n" + " text-decoration: none;\n" + "}\n"); + + fprintf(fp,"a:hover {\n" + " COLOR: #FF6600;\n" + " text-weight: bold;\n" + " text-decoration: none;\n" + "}\n" + ".info {\n" + " FONT-SIZE: 12; COLOR: #99CCFF;\n" + "}\n"); + + fprintf(fp,"table.box {\n" + " background-color: #ffbb00;\n" + " backcolor: #220000;\n" + " backcolorlight: #00ff00;\n" + " backcolordark: #000000;\n" + " border-width: 0px;\n" + " width: 95%%;\n" + " border-style: outset;\n" + " border-spacing: 2px;\n" + " border-padding: 8px;\n" + "}\n"); + +fprintf(fp,".status {\n" + " FONT-SIZE: 10; BACKGROUND: #000000; COLOR: #FFCC00; TEXT-ALIGN: center;\n" + "}\n"); + + fprintf(fp,".off {\n" + " FONT-SIZE: 10; BACKGROUND: #000000; COLOR: #ffffff;\n" + "}"); + + fprintf(fp,".offline {\n" + " FONT-SIZE: 10; BACKGROUND: #9f00FF; COLOR: #ffffff;\n" + "}"); + + fprintf(fp,".user {\n" + " FONT-SIZE: 10; BACKGROUND: #E06060; COLOR: #ffffff;\n" + "}\n"); + + fprintf(fp,".thenet {\n" + " FONT-SIZE: 10; BACKGROUND: #E00060; COLOR: #ffffff;\n" + "}\n"); + + fprintf(fp,".inp {\n" + " FONT-SIZE: 10; BACKGROUND: #0070C0; COLOR: #ffffff;\n" + "}\n"); + + fprintf(fp,".Flexnet {\n" + " FONT-SIZE: 10; BACKGROUND: #006060; COLOR: #ffffff;\n" + "}\n"); + + fprintf(fp,".about {\n" + " FONT-SIZE: 13; COLOR: #ffffff;\n" + "}\n"); + + fclose(fp); +} + +/* Wie viel Ports sind nich frei ? */ +static int free_ports(void) +{ + int free = FALSE; + + return(free = TABLE_SIZE - route_tbl_top); +} + +/* Wie viel L2-Links (USER) - sind aktiv ? */ +static int activ_user(void) +{ + register int a; + int user = FALSE; + + /* TB durchgehen */ + for (a = 0; a < route_tbl_top; a++) + /* nur die als User markiert sind */ + if ( route_tbl[a].protokoll == P_USER + /* und online sind !!! */ + && route_tbl[a].online > 0) + /* Alle USER zaehlen */ + user++; + + return(user); +} + +/* Wie viel L2/L4_links sind aktiv ? */ +static int activ_links(void) +{ + register int a; + int links = FALSE; + + /* TB durchgehen */ + for (a = 0; a < route_tbl_top; a++) + /* L2/L4-Link online ? */ + if ( route_tbl[a].online > 0 + /* wir zaehlen alle Protokolle, ausser USER */ + && route_tbl[a].protokoll != 1) + links++; + + return(links); +} + +/* Die Aktuelle Uhrzeit fuer HTML ausgeben */ +static char *puttim_stat(void) +{ + struct tm *p; + static char tim[20]; + time_t timet; + char *atime = tim; + + time(&timet); + + p = localtime(&timet); + sprintf(tim,"%02i.%02i.%02i %02i:%02i:%02i", + p->tm_mday, p->tm_mon+1, p->tm_year % 100, + p->tm_hour, p->tm_min, p->tm_sec); + + return(atime); +} + +static char *set_class(UWORD flag, register int a) +{ + static char o[8]; + char *protokoll = o; + + switch(flag) + { + case P_OFFLINE : + if (!route_tbl[a].online) + strcpy(o, "offline"); + + break; + + case P_USER : + if (route_tbl[a].online) + strcpy(o, "user"); + else + strcpy(o, "offline"); + break; + + case P_THENET : + if (route_tbl[a].online) + strcpy(o, "thenet"); + else + strcpy(o, "offline"); + break; + + case P_INP : + if (route_tbl[a].online) + strcpy(o, "inp"); + else + strcpy(o, "offline"); + + break; + + case P_FLEXNET : + if (route_tbl[a].online) + strcpy(o, "flexnet"); + else + strcpy(o, "offline"); + + break; + + default: + strcpy(o, "unknown"); + break; + } + + return(protokoll); +} + +static char *set_pname(register int a) +{ + static char p[8]; + char *protokoll = p; + + switch(route_tbl[a].protokoll) + { + case P_USER : + strcpy(p, "L2"); + break; + + case P_THENET : + strcpy(p, "THENET"); + break; + + case P_INP : + strcpy(p, "INP"); + break; + + case P_FLEXNET : + strcpy(p, "FLEXNET"); + break; + + default: + strcpy(p, "UNKNOWN"); + break; + } + +return(protokoll); +} + +static void all_route(FILE *fp, UWORD flag, register int a) +{ + char *pclass = set_class(flag, a); + char *protokoll = set_pname(a); + + /* Nummer einer Route. */ + fprintf(fp,"
%d\n" + , pclass, a); + + /* Rufzeichen. */ + fprintf(fp," %s\n" + , pclass + , call_to_a(&route_tbl[a].callsign[0])); + + /* IP-Adresse. */ + fprintf(fp," " + " %s\n" + , pclass + , route_tbl[a].hostname + , route_tbl[a].hostname); + + /* Hostname/IP-Adresse. */ + fprintf(fp,"
%s\n" + , pclass + , route_tbl[a].hostname); + + /* UDP-Port */ + fprintf(fp,"
%d\n" + , pclass + , htons(route_tbl[a].udp_port)); + + /* Loginzeit */ + fprintf(fp,"
%s\n" + , pclass + , route_tbl[a].timeset); + + if (route_tbl[a].timeout) + /* Timeout */ + fprintf(fp,"
%d\n" + , pclass + , route_tbl[a].timeout); + else + /* Statische Route */ + fprintf(fp,"
Statisch\n" + , pclass); + + /* Protokoll */ + fprintf(fp,"
%s\n" + , pclass + , protokoll); +} + +static void show_route(FILE *fp, UWORD flag, register int a) +{ + switch(flag) + { + case P_OFFLINE : + if (!route_tbl[a].online) + fprintf(fp," \n"); + + break; + + case P_USER : + if ( route_tbl[a].protokoll == flag + && route_tbl[a].online) + fprintf(fp," \n"); + else + fprintf(fp," \n"); + + break; + + case P_THENET : + if ( route_tbl[a].protokoll == flag + && route_tbl[a].online) + fprintf(fp," \n"); + else + fprintf(fp," \n"); + + break; + + + case P_INP : + if ( route_tbl[a].protokoll == flag + && route_tbl[a].online) + fprintf(fp," \n"); + else + fprintf(fp," \n"); + + break; + + case P_FLEXNET : + if ( route_tbl[a].protokoll == flag + && route_tbl[a].online) + fprintf(fp," \n"); + else + fprintf(fp," \n"); + + break; + + + default: + if ( route_tbl[a].protokoll == flag + && route_tbl[a].online) + fprintf(fp," \n"); + else + fprintf(fp," \n"); + + break; + } + all_route(fp, flag, a); +} + +/* Schreibe htmlstatistik auf Platte. */ +void w_statistik(void) +{ + FILE *fp; + char cfgfile[255],mycall[10]; + char *atime = puttim_stat(); + register int a; + char runtime[8 + 1]; +#ifndef CONNECTTIME + unsigned long upt, + upd, + uph; +#endif /* CONNECTTIME */ + + /* Pruefe, ob htmlstatistik eingeschaltet ist. */ + if (HtmlStat == FALSE) + /* Ist nicht eingeschaltet, abbruch. */ + return; + else + { + /* Pruefe ob CSS-Datei exisiert. */ + if (!check_css_file()) + /* Nein, dann neuschreiben. */ + rstat_css_default_file(); + + } + + strcpy(cfgfile,htmlpath ); + strcat(cfgfile, HTML_RFILE); + if ((fp = fopen(cfgfile,"w+t")) == NULL) + return; + + call2str(mycall,myid); + +#ifndef CONNECTTIME + upt = sys_time - start_time; /* Uptime in seconds */ + upd = upt / SECONDS_PER_DAY; /* Uptime days */ + upt %= SECONDS_PER_DAY; + uph = upt / SECONDS_PER_HOUR; /* Uptime hours */ + upt %= SECONDS_PER_HOUR; + + if (upd > 0) + sprintf(runtime, "%2lud,%2luh", upd, uph); + else + if (uph > 0) + sprintf(runtime, "%2luh,%2lus", uph, upt); + else + if (upt > 0) + sprintf(runtime, " %2lus", upt); + else + sprintf(runtime, " "); +#else + sprintf(runtime, "%s", ConnectTime(tic10 / 100)); +#endif /* CONNECTTIME */ + + fprintf(fp,"" + "\n" + "\n" + "AXIPR-Statistik\n" + "\n" + "\n\n",HTML_INV); + + fprintf(fp,"
\n" + "

%s%s)

\n",signon,mycall); + + fprintf(fp,"

Date/Time: %s Runtime: %s, %d Frei

\n\n",atime, runtime, free_ports()); + fprintf(fp," %d L2/L4-LINKS\n",activ_links()); + fprintf(fp,"\n"); + fprintf(fp," \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n"); + + /* TB durchgehen. */ + for (a = 0; a < route_tbl_top; a++) + { + /* Nur aktive Routen zeigen. */ + if (route_tbl[a].online == FALSE) + /* zum naechsten Eintrag. */ + continue; + + /* Nur INP- oder FLEXNET-Routen bearbeiten */ + if (route_tbl[a].protokoll > P_USER) + /* und anzeigen. */ + show_route(fp, route_tbl[a].protokoll, a); + } + + fprintf(fp,"
Nr.RufzeichenIP-AdresseDYNDNSUDPLoginTimeoutProtokoll


\n"); + + fprintf(fp,"%d USER\n",activ_user()); + fprintf(fp,"\n"); + fprintf(fp," \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n"); + + /* TB durchgehen */ + for (a = 0; a < route_tbl_top; a++) + { + /* Nur aktive Routen zeigen. */ + if (route_tbl[a].online == FALSE) + /* zum naechsten Eintrag. */ + continue; + + /* Nur USER-Routen bearbeiten */ + if (route_tbl[a].protokoll == P_USER) + /* und anzeigen. */ + show_route(fp, route_tbl[a].protokoll, a); + } + + fprintf(fp,"
Nr.RufzeichenIP-AdresseDYNDNSUDPLoginTimeoutProtokoll
\n\n"); + fprintf(fp,"
My UDP-Port: %u\n",htons(my_udp)); + fprintf(fp,"\n"); + fclose(fp); +} + +#endif /* AXIPR_HTML */ +#endif /* AXIPR_UDP */ + +#endif + +/* End of os/linux/ax25ip.c */ diff --git a/os/linux/ax25ip.h b/os/linux/ax25ip.h new file mode 100755 index 0000000..ecca914 --- /dev/null +++ b/os/linux/ax25ip.h @@ -0,0 +1,198 @@ +/************************************************************************/ +/* */ +/* ***** ***** */ +/* ***** ***** */ +/* ***** ***** */ +/* ***** ***** */ +/* *************** *************** */ +/* ***************** ***************** */ +/* *************** *************** */ +/* ***** ***** TheNetNode */ +/* ***** ***** Portable */ +/* ***** ***** Network */ +/* ***** ***** Software */ +/* */ +/* File os/linux/ax25ip.h (maintained by: DG9OBU) */ +/* */ +/* This file is part of "TheNetNode" - Software Package */ +/* */ +/* Copyright (C) 1998 - 2008 NORD>0)(void)write_log +#define LOGL2 if(loglevel>1)(void)write_log +#define LOGL3 if(loglevel>2)(void)write_log +#define LOGL4 if(loglevel>3)(void)write_log + +#define HNLEN 64 + +#define OP_NONE 0 +#define OP_ADD 1 +#define OP_DEL 2 +#define OP_MYUDP 3 +#define OP_LOG 4 +#define OP_TIMEOUT 5 +#define OP_HNUPD 6 + +#define BUFLEN 32 + +static unsigned int uDynTimeout = 3600; /* eine Stunde */ + +/* Variablen */ +static LHEAD *l2flp; +static DEVICE *l1pp; +static int ax25ip_port; +static BOOLEAN ax25ip_active = FALSE; +static BOOLEAN sockopt_keepalive = FALSE; +static BOOLEAN sockopt_throughput = FALSE; +static WORD mode; +/* Nameservice-Updateintervall (in Zehntelsekunden !) */ +static UWORD uNamesUpdate = 18000; +static struct sockaddr_in udpbind; +static struct sockaddr_in ipbind; +static struct sockaddr_in to; +static struct sockaddr_in from; +#ifndef ATTACH +unsigned short my_udp = 0; +#endif /* ATTACH */ +int route_tbl_top = 0; +int loglevel = 0; + +int fd_udp = -1; /* Filedescriptor fuer UDP */ +int fd_ip = -1; /* Filedescriptor fuer IP */ + +/* TEST DG9OBU */ +static BOOLEAN new_parser = FALSE; /* Standardmaessig alte Syntax */ + +struct route_table_entry { + unsigned char callsign[L2IDLEN]; /* the callsign and ssid */ + unsigned long ip_addr; /* the IP address */ + unsigned short udp_port; /* the port number if udp */ + unsigned int timeout; /* Timeout der Route */ + unsigned char hostname[HNLEN]; +#ifdef AXIPR_UDP + unsigned short org_udp_port; /* Original UDP-Port. */ +#endif +#ifdef AXIPR_HTML + unsigned char timeset[17 + 1]; /* Login-Zeit/Date. */ + unsigned short protokoll; /* Protokoll (INP,Flexnet..) */ + unsigned short online; /* Route online/offline. */ +#endif +}; + +struct route_table_entry route_tbl[TABLE_SIZE]; +struct route_table_entry default_route; + +/* Funktionsprototypen */ +int setup_ip(void); +int setup_udp(unsigned short); +void show_rt_entry(struct route_table_entry, MBHEAD*); +void ccpaxipr(void); +void ax25ip_send(void); +void ax25ip_recv(void); +void ax25ip_check_up(void); +void ax25ip_check_down(void); +#ifndef AXIPR_UDP +static void route_add(unsigned char*, struct hostent*, unsigned char*, int, int, int); +#else +static BOOLEAN route_add(unsigned char*, struct hostent*, unsigned char*, int, int, int + , char * +#ifdef AXIPR_HTML + , char *, UWORD +#endif /* AXIPR_HTML */ + ); +#endif /* AXIPR_UDP */ + +BOOLEAN route_del(unsigned char*); +unsigned int count_routes(BOOLEAN); +void route_init(void); +void route_age(void); +void route_update(struct route_table_entry*); +BOOLEAN route_canlearn(MBHEAD*); +void add_crc(unsigned char*, int); +int addrmatch(unsigned char*, unsigned char*); +void add_ax25crc(unsigned char*, int); +UWORD compute_crc(unsigned char*, int); +BOOLEAN ok_crc(unsigned char*, int); +int config_read(void); +int parse_line(char*); +int a_to_call(char*, unsigned char*); +char *call_to_a(unsigned char*); + +struct route_table_entry *call_to_ip(unsigned char*); + +unsigned char *next_addr(unsigned char*); +void write_log(const char*, ...); + +#ifdef AXIPR_UDP +void route_analyse(struct in_addr, unsigned char *, int); +void route_check(register int); +struct route_table_entry *search_route(unsigned char *); +void UpdateRoute(unsigned char *, int, int, char * +#ifdef AXIPR_HTML + , char *, UWORD +#endif /* AXIPR_HTML */ + ); +#endif /* AXIPR_UDP */ + +#ifdef AXIPR_HTML +#define P_OFFLINE 0 +#define P_USER 1 +#define P_THENET 2 +#define P_INP 3 +#define P_FLEXNET 4 + +#define CSS_RFILE "rstat.css" +#define HTML_RFILE "rstat.html" +#define HTML_INV 60 + +static unsigned int HtmlStat = FALSE; /* HtmlStatistik ausgeshaltet. */ + +void h_timer(void); +void w_statistik(void); +char *set_time(void); +void set_status(register int, int, PEER *); +#endif + +/* End */ diff --git a/os/linux/axipx.c b/os/linux/axipx.c new file mode 100755 index 0000000..728fb42 --- /dev/null +++ b/os/linux/axipx.c @@ -0,0 +1,264 @@ +/************************************************************************/ +/* */ +/* ***** ***** */ +/* ***** ***** */ +/* ***** ***** */ +/* ***** ***** */ +/* *************** *************** */ +/* ***************** ***************** */ +/* *************** *************** */ +/* ***** ***** TheNetNode */ +/* ***** ***** Portable */ +/* ***** ***** Network */ +/* ***** ***** Software */ +/* */ +/* File os/linux/axipx.c (maintained by: DG1KWA) */ +/* */ +/* This file is part of "TheNetNode" - Software Package */ +/* */ +/* Copyright (C) 1998 - 2008 NORD>kisslink = socket(AF_IPX, SOCK_DGRAM, PF_IPX); + l2flp = (LHEAD *) &txl2fl[l2port]; + + if (l1pp->kisslink < 0) + { +#ifdef SPEECH + printf(speech_message(331), strerror(errno)); +#else + printf("cannot create socket for IPX : %s\n", strerror(errno)); +#endif + return(FALSE); + } + + memset(&myaddr, 0, sizeof(myaddr)); + myaddr.sipx_family = AF_IPX; + myaddr.sipx_network = 0x00L; + myaddr.sipx_port = htons(0xCE73); + + if (bind(l1pp->kisslink, (struct sockaddr *) &myaddr, sizeof(myaddr))) + { +#ifdef SPEECH + printf(speech_message(332), strerror(errno)); +#else + printf("cannot bind IPX address: %s\n", strerror(errno)); +#endif + close(l1pp->kisslink); + l1pp->kisslink = -1; + return(FALSE); + } + + addrlen = sizeof(myaddr); + if (getsockname(l1pp->kisslink, (struct sockaddr *) &myaddr, &addrlen) < 0) + { + perror("getsockname(ipx)"); + } + + if (fcntl(l1pp->kisslink, F_SETFL, FNDELAY) < 0) + { +#ifdef SPEECH + printf(speech_message(333)); +#else + printf("Error: can't set non-blocking I/O on IPX socket"); +#endif + close(l1pp->kisslink); + l1pp->kisslink = -1; + return(FALSE); + } + + axipx_active = TRUE; + return(TRUE); +} + +void axipx_l1exit(void) +{ + if (axipx_active == FALSE) + return; + + close(l1pp->kisslink); + axipx_active = FALSE; + l1pp->kisslink = -1; +} + + +void axipx_l1ctl(int req, int port) +{ + /* nur eigene Ports bearbeiten */ + if (kissmode(port) != KISS_IPX) + return; + + switch(req) + { + /* Testpattern auf dem Port senden (wird unterdrueckt) */ + case L1CTST : testflag[port] = FALSE; + kick[port] = FALSE; + break; + + default : break; + } +} + +void axipx_hwstr(int port, MBHEAD *mbp) +{ +} + +BOOLEAN axipx_dcd(int port) +{ + return (FALSE); +} + +/* IPX-Sende-Routine */ +void axipx_send(void) +{ + char buf[MAX_FRAME]; + WORD len = 0; + MBHEAD *txfhdl; + + if (kick[axipx_port]) + { /* haben wir was zu senden ? */ + /* Sicherheitsabfrage, da kisck[] auch manipuliert werden kann */ + if (l2flp->head == l2flp) + { + kick[axipx_port] = FALSE; + return; + } + + ulink((LEHEAD *)(txfhdl = (MBHEAD *) l2flp->head));/*Zeiger holen*/ + + while ( (txfhdl->mbgc < txfhdl->mbpc) /* solange Daten vorhanden sind */ + && (len < MAX_FRAME)) + buf[len++] = getchr(txfhdl); + + relink((LEHEAD *)txfhdl, /* als gesendet betrachten und in */ + (LEHEAD *)stfl.tail); /* die gesendet Liste umhaengen */ + + kick[axipx_port] = ((LHEAD *)l2flp->head != l2flp); + + if (sendto(l1pp->kisslink, (char *)buf, len, 0, + (struct sockaddr *)&bcaddr, sizeof(bcaddr)) < 0) + { + perror("sendto(l1pp->kisslink) in axipx_send()"); + } + } +} + +/* IPX Empfangs-Routine */ +void axipx_recv(void) +{ + struct sockaddr_ipx addr; + socklen_t addrlen = sizeof(addr); + int l = 0; + int i = 0; + UBYTE buf[MAX_FRAME]; + UBYTE *bufptr; + MBHEAD *rxfhd; + + if (!axipx_active) + return; + + l = recvfrom(l1pp->kisslink, (char *) (bufptr = buf), sizeof(buf), 0, + (struct sockaddr *) &addr, &addrlen); + + if (l > 0) + { + /* unseren eigenen Frames wollen wir nicht empfangen */ + if (!memcmp(addr.sipx_node, myaddr.sipx_node, IPX_NODE_LEN)) + return; + + (rxfhd = (MBHEAD *)allocb(ALLOC_MBHEAD))->l2port = axipx_port; + + for (i = 0; i < l; i++) + putchr(buf[i], rxfhd); /* Buffer umkopieren */ + + relink((LEHEAD *)rxfhd, (LEHEAD *)rxfl.tail); + } +} + +#endif + +/* End of os/linux/axipx.c */ diff --git a/os/linux/ini/ax25ip.cfg b/os/linux/ini/ax25ip.cfg new file mode 100755 index 0000000..a62df90 --- /dev/null +++ b/os/linux/ini/ax25ip.cfg @@ -0,0 +1,41 @@ +# Sample thenetnode/ax25ip configuration file +# +# First select active socket types. Both can be active at the same time. +# syntax: socket [udp-port] +# +socket ip +#socket udp 10093 +# +# +# loglevel 0 - no output +# loglevel 1 - config info only +# loglevel 2 - major events and errors +# loglevel 3 - major events, errors, and AX25 frame trace +# loglevel 4 - all events +# +loglevel 2 +# +# Define some routes. One example routes all traffic for callsign db0zzz +# to a host named nexthost.bla.blub. You can define as many as +# required. +# syntax: route [udp] [udp-port] +# +#route db0zzz nexthost.bla.blub +#route db0gso otherhost.bla.blub udp +route db0wst 192.100.100.50 +route dg2kwa 44.130.19.50 +# +# A catch-all is provided: this line sends all calls not specifically +# noted in the routing tables to otherhost.bla.blub. Use this feature +# with great care -- the host on the other end may not appreciate all the +# traffic! +# syntax: route default [udp] [udp-port] +# +#route default 192.100.100.50 +# +# Now set some socket options +# available options are : IPTOS_THROUGHPUT SO_KEEPALIVE +# important ! use multiple socketoption-lines, one for each option +# +socketoption IPTOS_THROUGHPUT +socketoption SO_KEEPALIVE diff --git a/os/linux/ini/tnn.ini b/os/linux/ini/tnn.ini new file mode 100755 index 0000000..01d7a76 --- /dev/null +++ b/os/linux/ini/tnn.ini @@ -0,0 +1,74 @@ +# +# Sample tnn.ini, see tnnini.all for a more comprehensive example with all +# possibilities shown. +# +# ------------------------------------------------------------------------ +# +# Working directory for TNN +#tnn_dir /usr/local/tnn/ +# Unix-Socket for TNT hostmode interface (optional) +#tnn_socket /usr/local/tnn/tnn-socket +# Program to start before using any hardware ports +# (optional) - don't use any parameters! +#tnn_start kill_other_processes +# Number of buffers (optional; default is 10000) +buffers 10000 +# file containing process id (mandatory) +tnn_procfile tnn.pid +# rounds per second (optinal, defaults is 100) +#rounds 200 +# permissions for files created by tnn +perms 077 +#------------------------------------------------- +# device 1 +device /dev/ttyS0 +# lockfile for device 1 +tnn_lockfile /var/lock/LCK..ttyS0 +# speed on device 1 +speed 38400 +# type of KISS on device 1: +# 0 = KISS, 1 = SMACK, 2 = RMNC-KISS, +# 3 = Tokenring (1st device only), +# 4 = Vanessa, 5 = SCC, 6 = TF (experimental!), +# 7 = IPX (1 IPX port only), +# 8 = AX25IP (1 AX25IP port only) +# 10 = Kernel-AX.25, 11 = DG1KJD Kernel-AX.25 +# +# 22 = Telnet, 23 = Httpd, 24 = IPConvers +kisstype 3 +# L2-Port associated with device 1 +# use several port lines, if kisstype = 3 +port 0 +port 1 +port 2 +port 3 +port 4 +port 5 +port 6 +port 7 +port 8 +port 9 +port 10 +port 11 +port 12 +port 13 +port 14 +port 15 +#------------------------------------------------- +# device 2 +#device /dev/ttyS1 +# lockfile for device 2 +#tnn_lockfile /var/lock/LCK..ttyS1 +# speed on device 2 +#speed 38400 +# type of KISS on device 2: +# 0 = KISS, 1 = SMACK, 2 = RMNC-KISS, +# 4 = Vanessa, 5 = SCC, 6 = TF (experimental!), +# 7 = IPX (1 IPX port only), +# 8 = AX25IP (1 AX25IP port only) +# 10 = Kernel-AX.25, 11 = DG1KJD Kernel-AX.25 +# +# 22 = Telnet, 23 = Httpd, 24 = IPConvers +#kisstype 1 +# L2-Port associated with device 2 +#port 1 diff --git a/os/linux/ini/tnn179.pas b/os/linux/ini/tnn179.pas new file mode 100755 index 0000000..312c0f8 --- /dev/null +++ b/os/linux/ini/tnn179.pas @@ -0,0 +1,32 @@ +; TheNetNode Configuration File +; +; DO NOT CHANGE THE ORDER OF THE CONFIGURATION LINES ! +; DO NOT CLEAR ANY LINES ! +; +; NET/ROM-Sysop-Password, 80 Characters (01234567890123...) +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +; +; Console Password +Geheim +; +; Node Ident (Test) +Test +; +; Node MyCall (XX0XX) +XX0XX +; +; Workpath, Path to the Help-Files (/usr/local/tnn/) +; TNN should be started from this path. +/usr/local/tnn/ +; +; Path to the executable Text-Files (/usr/local/tnn/textcmd/) +/usr/local/tnn/textcmd/ +; +; Path to the extern Programs for User (/usr/local/tnn/userexe/) +/usr/local/tnn/userexe/ +; +; Path to the extern Programs only for Sysop (/usr/local/tnn/sysexe/) +/usr/local/tnn/sysexe/ +; +; Path to the PACSAT-Files (/usr/local/tnn/pacsat/) +/usr/local/tnn/pacsat/ diff --git a/os/linux/ini/tnn179.tnb b/os/linux/ini/tnn179.tnb new file mode 100755 index 0000000..4b672a8 --- /dev/null +++ b/os/linux/ini/tnn179.tnb @@ -0,0 +1,16 @@ +port 0 NAME=Port0 on CTEXT=1 DAMA=0 MH=1 Mode=1200 +port 1 NAME=Port1 on CTEXT=1 DAMA=0 MH=0 Mode=1200 +port 2 NAME=Port2 on CTEXT=1 DAMA=0 MH=0 Mode=1200 +port 3 NAME=Port3 on CTEXT=1 DAMA=0 MH=0 Mode=1200 +port 4 NAME=Port4 on CTEXT=1 DAMA=0 MH=0 Mode=1200 +port 5 NAME=Port5 on CTEXT=1 DAMA=0 MH=0 Mode=1200 +port 6 NAME=Port6 on CTEXT=1 DAMA=0 MH=0 Mode=1200 +port 7 NAME=Port7 on CTEXT=1 DAMA=0 MH=0 Mode=1200 +port 8 NAME=Port8 on CTEXT=1 DAMA=0 MH=0 Mode=1200 +port 9 NAME=Port9 on CTEXT=1 DAMA=0 MH=0 Mode=1200 +port 10 NAME=Prt10 on CTEXT=1 DAMA=0 MH=0 Mode=1200 +port 11 NAME=Prt11 on CTEXT=1 DAMA=0 MH=0 Mode=1200 +port 12 NAME=Prt12 on CTEXT=1 DAMA=0 MH=0 Mode=1200 +port 13 NAME=Prt13 on CTEXT=1 DAMA=0 MH=0 Mode=1200 +port 14 NAME=Prt14 on CTEXT=1 DAMA=0 MH=0 Mode=1200 +port 15 NAME=Prt15 on CTEXT=1 DAMA=0 MH=0 Mode=1200 diff --git a/os/linux/ini/tnnini.all b/os/linux/ini/tnnini.all new file mode 100755 index 0000000..7df328e --- /dev/null +++ b/os/linux/ini/tnnini.all @@ -0,0 +1,255 @@ +# +# This is a sample of the file tnn.ini with all options and devices shown. +# +#----------------------------------------------------------------------------- +# +# Average rounds/sec (default if missing is 100) - the real value depends +# on processor power and system load. Increase this on heavy loaded systems +# and if you have high speed ports (76800 baud and up). Normally, it doesn't +# need to be changed, if more power is required, tnn increases rounds by +# itself. This value can be interpreted as some kind of idle gas ;) +# +#rounds 200 +# +# File permissions for files created by TNN - octal value as used by umask(2) +# default value is 000 (world readable/writable & EXECUTEABLE !!!). +# use 077 to limit access to the owner of TNN only (suggested) +# +#perms 077 +# +# Working directory for TNN +# +tnn_dir /usr/local/tnn/ +# +# Unix-Socket for TNNs hostmode interface (optional) +# +#tnn_socket /usr/local/tnn/tnn-socket +# +# Program to start before using any hardware ports (optional) - don't use +# any parameters! +# +#tnn_start kill_other_processes +# +# Number of buffers (optional; default = 10000) +# +buffers 10000 +# +# File containing process id (mandatory) +# +tnn_procfile tnn.pid +# +#----------------------------------------------------------------------------- +# Example Device Configurations +#----------------------------------------------------------------------------- +# device 1 = Tokenring on /dev/ttyS0; 38400 Bd; Ports 0 and 1 +device /dev/ttyS0 +# lockfile for device 1 +tnn_lockfile /var/lock/LCK..ttyS0 +# speed on device 1 +speed 38400 +# type of KISS on device 1: +# 0 = KISS, 1 = SMACK, 2 = RMNC-KISS, 3 = Tokenring (1st device only), +# 4 = Vanessa, 5 = SCC, 6 = TF (experimental!), 7 = IPX (1 IPX port only), +# 8 = AX25IP (1 AX25IP port only), 9 = Loop, 10 = Kernel-AX.25 Interface +# 11 = Kernel-AX.25 Interface for DG1KJD-Kernel, 12 = 6PACK +# +# 22 = Telnet, 23 = Httpd, 24 = IPConvers +kisstype 3 +# L2-Port(s) associated with device 1 - use several port lines, one for every +# TNC in your tokenring. The ports assigned here MUST match the TNC-number +# burned into the ROM of the tokenring-TNC !!! +port 0 +port 1 +#----------------------------------------------------------------------------- +# device 2 = standard KISS on /dev/ttyS1; 9600Bd; Port 2 +device /dev/ttyS1 +# lockfile for device 2 +tnn_lockfile /var/lock/LCK..ttyS1 +# speed on device 2 +speed 9600 +# type of KISS on device 2: +# 0 = KISS, 1 = SMACK, 2 = RMNC-KISS, +# 4 = Vanessa, 5 = SCC, 6 = TF (experimental!), 7 = IPX (1 IPX port only), +# 8 = AX25IP (1 AX25IP port only), 9 = Loop, 10 = Kernel-AX.25 Interface +# 11 = Kernel-AX.25 Interface for DG1KJD-Kernel, 12 = 6PACK +# +# 22 = Telnet, 23 = Httpd, 24 = IPConvers +kisstype 0 +# L2-Port associated with device 2 +port 2 +#----------------------------------------------------------------------------- +# device 3 = SMACK on /dev/ttyS2; 115200 Bd; Port 3 +device /dev/ttyS2 +# lockfile for device 3 +tnn_lockfile /var/lock/LCK..ttyS2 +# speed on device 3 +speed 115200 +# type of KISS on device 3: +# 0 = KISS, 1 = SMACK, 2 = RMNC-KISS, +# 4 = Vanessa, 5 = SCC, 6 = TF (experimental!), 7 = IPX (1 IPX port only), +# 8 = AX25IP (1 AX25IP port only), 9 = Loop, 10 = Kernel-AX.25 Interface +# 11 = Kernel-AX.25 Interface for DG1KJD-Kernel, 12 = 6PACK +# +# 22 = Telnet, 23 = Httpd, 24 = IPConvers +kisstype 1 +# L2-Port associated with device 3 +port 3 +#----------------------------------------------------------------------------- +# device 4 = RMNC-Kiss on /dev/ttyS3; 19200 Bd; Port 4 +device /dev/ttyS3 +# lockfile for device 4 +tnn_lockfile /var/lock/LCK..ttyS3 +# speed on device 4 +speed 19200 +# type of KISS on device 4: +# 0 = KISS, 1 = SMACK, 2 = RMNC-KISS, +# 4 = Vanessa, 5 = SCC, 6 = TF (experimental!), 7 = IPX (1 IPX port only), +# 8 = AX25IP (1 AX25IP port only), 9 = Loop, 10 = Kernel-AX.25 Interface +# 11 = Kernel-AX.25 Interface for DG1KJD-Kernel, 12 = 6PACK +# +# 22 = Telnet, 23 = Httpd, 24 = IPConvers +kisstype 2 +# L2-Port associated with device 4 +port 4 +#----------------------------------------------------------------------------- +# device 5 = VANESSA-Board ; Port 5 +device Vanessa +# +# no "tnn_lockfile"- or "speed"-lines required here! +# +# type of KISS on device 5: +# 0 = KISS, 1 = SMACK, 2 = RMNC-KISS, +# 4 = Vanessa, 5 = SCC, 6 = TF (experimental!), 7 = IPX (1 IPX port only), +# 8 = AX25IP (1 AX25IP port only), 9 = Loop, 10 = Kernel-AX.25 Interface +# 11 = Kernel-AX.25 Interface for DG1KJD-Kernel, 12 = 6PACK +# +# 22 = Telnet, 23 = Httpd, 24 = IPConvers +kisstype 4 +# L2-Port associated with device 5 +port 5 +#----------------------------------------------------------------------------- +# device 6 = SCC on /dev/scc0; Port 6 +device /dev/scc0 +# lockfile for device 6 +tnn_lockfile /var/lock/LCK..scc0 +# type of KISS on device 6: +# 0 = KISS, 1 = SMACK, 2 = RMNC-KISS, +# 4 = Vanessa, 5 = SCC, 6 = TF (experimental!), 7 = IPX (1 IPX port only), +# 8 = AX25IP (1 AX25IP port only), 9 = Loop, 10 = Kernel-AX.25 Interface +# 11 = Kernel-AX.25 Interface for DG1KJD-Kernel, 12 = 6PACK +# +# 22 = Telnet, 23 = Httpd, 24 = IPConvers +kisstype 5 +# L2-Port associated with device 6 +port 6 +#----------------------------------------------------------------------------- +# device 7 = TNC with TF 2.7b/KISS on /dev/ttyS4; 19200 Bd; Port 7 +# WARNING! This configuration is NOT recommended for a standalone digipeater! +device /dev/ttyS4 +# lockfile for device 7 +tnn_lockfile /var/lock/LCK..ttyS4 +# speed on device 7 +speed 19200 +# type of KISS on device 7: +# 0 = KISS, 1 = SMACK, 2 = RMNC-KISS, +# 4 = Vanessa, 5 = SCC, 6 = TF (experimental!), 7 = IPX (1 IPX port only), +# 8 = AX25IP (1 AX25IP port only), 9 = Loop, 10 = Kernel-AX.25 Interface +# 11 = Kernel-AX.25 Interface for DG1KJD-Kernel, 12 = 6PACK +# +# 22 = Telnet, 23 = Httpd, 24 = IPConvers +kisstype 6 +# L2-Port associated with device 7 +port 7 +#----------------------------------------------------------------------------- +# device 8 = AX25IPX ; Port 8 +device ipx +# type of KISS on device 8: +# 0 = KISS, 1 = SMACK, 2 = RMNC-KISS, +# 4 = Vanessa, 5 = SCC, 6 = TF (experimental!), 7 = IPX (1 IPX port only), +# 8 = AX25IP (1 AX25IP port only), 9 = Loop, 10 = Kernel-AX.25 Interface +# 11 = Kernel-AX.25 Interface for DG1KJD-Kernel, 12 = 6PACK +# +# 22 = Telnet, 23 = Httpd, 24 = IPConvers +kisstype 7 +# L2-Port associated with device 8 +port 8 +#----------------------------------------------------------------------------- +# device 9 = AX25IP ; Port 9 +device ax25ip +# type of KISS on device 9: +# 0 = KISS, 1 = SMACK, 2 = RMNC-KISS, +# 4 = Vanessa, 5 = SCC, 6 = TF (experimental!), 7 = IPX (1 IPX port only), +# 8 = AX25IP (1 AX25IP port only), 9 = Loop, 10 = Kernel-AX.25 Interface +# 11 = Kernel-AX.25 Interface for DG1KJD-Kernel, 12 = 6PACK +# +# 22 = Telnet, 23 = Httpd, 24 = IPConvers +kisstype 8 +# L2-Port associated with device 9 +port 9 +#----------------------------------------------------------------------------- +# device 10 = Kernel-AX.25; Port 10 (example with Interface ax0) +device ax0 +# type of KISS on device 10: +# 0 = KISS, 1 = SMACK, 2 = RMNC-KISS, +# 4 = Vanessa, 5 = SCC, 6 = TF (experimental!), 7 = IPX (1 IPX port only), +# 8 = AX25IP (1 AX25IP port only), 9 = Loop, 10 = Kernel-AX.25 Interface +# 11 = Kernel-AX.25 Interface for DG1KJD-Kernel, 12 = 6PACK +# +# 22 = Telnet, 23 = Httpd, 24 = IPConvers +kisstype 10 +# L2-Port associated with device 10 +port 10 +#----------------------------------------------------------------------------- +# device 11 = DG1KJD-Kernel-AX.25; Port 11 (example with Interface ax0) +device ax0 +# type of KISS on device 11: +# 0 = KISS, 1 = SMACK, 2 = RMNC-KISS, +# 4 = Vanessa, 5 = SCC, 6 = TF (experimental!), 7 = IPX (1 IPX port only), +# 8 = AX25IP (1 AX25IP port only), 9 = Loop, 10 = Kernel-AX.25 Interface +# 11 = Kernel-AX.25 Interface for DG1KJD-Kernel, 12 = 6PACK +# +# 22 = Telnet, 23 = Httpd, 24 = IPConvers +kisstype 11 +# L2-Port associated with device 11 +port 11 +#----------------------------------------------------------------------------- +# device 12 = 6PACK TNC(s) on /dev/ttyS5; 57600 Bd; Ports 12 and 13 +device /dev/ttyS5 +# lockfile for device 1 +tnn_lockfile /var/lock/LCK..ttyS5 +# speed on device 1 +speed 57600 +# type of KISS on device 1: +# 0 = KISS, 1 = SMACK, 2 = RMNC-KISS, 3 = Tokenring (1st device only), +# 4 = Vanessa, 5 = SCC, 6 = TF (experimental!), 7 = IPX (1 IPX port only), +# 8 = AX25IP (1 AX25IP port only), 9 = Loop, 10 = Kernel-AX.25 Interface +# 11 = Kernel-AX.25 Interface for DG1KJD-Kernel, 12 = 6PACK +# +# 22 = Telnet, 23 = Httpd, 24 = IPConvers +kisstype 12 +# L2-Port(s) associated with device 12 - use several port lines, one for every +# TNC in the 6PACK-ring. The ring is auto-configured at startup, the first +# port found here is assigned to the first TNC in the ring, the second port to +# the second TNC and so on. The maximum of TNCs in a 6PACK-ring is 8 ! +# +# If you wish to attach more than one 6PACK-TNC, you *MUST* build a ring ! +# It is not possible to have more than one device configured as 6PACK at +# the moment ! This is a new device, if you find errors, please report them !!! +# +port 12 +port 13 +#----------------------------------------------------------------------------- +# device 22 = TELNET on TCP-Port 23 +device 23 +# type of KISS on device 1: +# 0 = KISS, 1 = SMACK, 2 = RMNC-KISS, 3 = Tokenring (1st device only), +# 4 = Vanessa, 5 = SCC, 6 = TF (experimental!), 7 = IPX (1 IPX port only), +# 8 = AX25IP (1 AX25IP port only), 9 = Loop, 10 = Kernel-AX.25 Interface +# 11 = Kernel-AX.25 Interface for DG1KJD-Kernel, 12 = 6PACK +# +# 22 = Telnet, 23 = Httpd, 24 = IPConvers +kisstype 22 +# L2-Port associated with device 15 +port 15 +# +# END \ No newline at end of file diff --git a/os/linux/init.c b/os/linux/init.c new file mode 100644 index 0000000..e6a50fa --- /dev/null +++ b/os/linux/init.c @@ -0,0 +1,813 @@ +/************************************************************************/ +/* */ +/* ***** ***** */ +/* ***** ***** */ +/* ***** ***** */ +/* ***** ***** */ +/* *************** *************** */ +/* ***************** ***************** */ +/* *************** *************** */ +/* ***** ***** TheNetNode */ +/* ***** ***** Portable */ +/* ***** ***** Network */ +/* ***** ***** Software */ +/* */ +/* File os/linux/init.c (maintained by: DF6LN) */ +/* */ +/* This file is part of "TheNetNode" - Software Package */ +/* */ +/* Copyright (C) 1998 - 2008 NORD>typ < NIX; ip++) + { + if (stricmp(str1, ip->name) == 0) + break; /* gefunden */ + } + + /* Parameter auswerten */ + switch (ip->typ) + { + /* Parameter "tnn_dir" */ + case DIRECTORY: + /* Verzeichnisname kopieren und Laenge merken */ + strcpy(tnn_dir, str2); + tmp = strlen(tnn_dir); + /* abschliessendes "/" an den Pfad anhaengen */ + if (tnn_dir[strlen(tnn_dir) - 1] != '/') + strcat(tnn_dir, "/"); + + chdir(tnn_dir); + /* in das Verzeichnis wechseln */ + if (chdir(tnn_dir) == -1) + printf("WARNING: error while changing directory : %s", strerror(errno)); + + return (FALSE); + + /* Parameter "tnn_errfile" */ + case ERRORFILE: + /* Dateinamen kopieren */ + strcpy(tnn_errfile, str2); + return (FALSE); + + /* Parameter "tnn_procfile" */ + case PROCFILE: + /* Dateiname kopieren */ + strcpy(tnn_procfile, str2); + return (FALSE); + + /* Parameter "tnn_socket" */ + case SOCKET: + /* nur wenn Socket noch nicht gesetzt */ + if (console_type != CONS_SOCKET_DO_SETUP) + { + /* Socketnamen jetzt benutzt */ + strcpy(tnn_socket, str2); + console_type = CONS_SOCKET_DO_SETUP; + return (FALSE); + } + return (TRUE); + + /* Parameter "tnn_start" */ + case START: + /* Programmnamen kopieren */ + strcpy(start_name, str2); + return (FALSE); + + /* Parameter "tnn_stop" */ + case STOP: + /* Programmnamen kopieren */ + strcpy(stop_name, str2); + return (FALSE); + + /* Parameter "buffers" */ + case BUFFERS: + /* Anzahl Buffer lesen */ + if (sscanf(str2, "%lu", &tnn_buffers) != 1) + return (TRUE); + + return (FALSE); + + /* Parameter "rounds" */ + case ROUNDS: + /* Anzahl Runden lesen */ + if (sscanf(str2, "%u", &u) != 1) + return (TRUE); + + /* gegen Ueberlauf durch negative Werte durch Spielkinder, der sscanf */ + /* liefert bei signed-Werten einen sehr hohen unsigned-Wert */ + if (u > 65500) + u = 65500; + + /* gewuenschten Wert runterteilen um das nicht spaeter im Vergleicher */ + /* tun zu muessen, auf Nachkommastellen keinen Wert legen */ + maxrounds = (u / 100); + + /* zu wenig Drehzahl ist ungesund */ + if (maxrounds < 1) + maxrounds = 1; + + return (FALSE); + + /* Parameter "perms" */ + case PERMS: + /* Wert fuer umask lesen */ + if (sscanf(str2, "%o", &u) != 1) + return (TRUE); + + /* neue umask setzen */ + umask(u); + return (FALSE); + + /* Parameter "device" */ + case DEV: + /* schon alle Ports vergeben ? */ + if (max_device >= L1PNUM - 1) + return (TRUE); + + /* Device merken */ + strcpy(l1port[++max_device].device, str2); + return (FALSE); + + /* Parameter "tnn_lockfile" */ + case LOCKFILE: + if ( (max_device < 0) /* kein Device */ + || (l1port[max_device].tnn_lockfile[0])) /* Name doppelt */ + return (TRUE); + + /* Lockfile merken */ + strcpy(l1port[max_device].tnn_lockfile, str2); + return (FALSE); + + /* Parameter Speed */ + case SPEED: + if ( (max_device < 0) /* kein Device */ + || (sscanf(str2, "%d", &tmp) != 1)) /* Wert ermitteln */ + return (TRUE); + + l1port[max_device].speedflag = 0; + + /* Geschwindigkeits-Code suchen */ + switch (tmp) + { + case 0: + l1port[max_device].speed = 0; + return (FALSE); + + case 9600: + l1port[max_device].speed = B9600; + return (FALSE); + + case 19200: + l1port[max_device].speed = B19200; + return (FALSE); + + case 38400: + l1port[max_device].speed = B38400; + return (FALSE); + + case 57600: +#ifdef B57600 + l1port[max_device].speed = B57600; +#else + l1port[max_device].speed = B38400; + l1port[max_device].speedflag = ASYNC_SPD_HI; +#endif + return (FALSE); + + case 115200: +#ifdef B115200 + l1port[max_device].speed = B115200; +#else + l1port[max_device].speed = B38400; + l1port[max_device].speedflag = ASYNC_SPD_VHI; +#endif + return (FALSE); + + case 230400: +#ifdef B230400 + l1port[max_device].speed = B230400; +#else + l1port[max_device].speed = B38400; + l1port[max_device].speedflag = ASYNC_SPD_SHI; +#endif + return (FALSE); + + case 460800: +#ifdef B460800 + l1port[max_device].speed = B460800; +#else + l1port[max_device].speed = B38400; +#endif + l1port[max_device].speedflag = ASYNC_SPD_WARP; + return (FALSE); + + /* unbekannte Geschwindigkeiten */ + default: + return (TRUE); + } + return (FALSE); + + /* Parameter "kisstype" */ + case KISSTYPE: + if ( (max_device < 0) /* kein Device */ + || (sscanf(str2, "%d", &tmp) != 1) /* Wet ermitteln */ +#ifndef AX_IPX + || (tmp == KISS_IPX) +#endif +#ifndef AX25IP + || (tmp == KISS_AXIP) +#endif +#ifndef VANESSA + || (tmp == KISS_VAN) +#endif +#ifndef KERNELIF + || (tmp == KISS_KAX25) + || (tmp == KISS_KAX25KJD) +#endif +#ifndef SIXPACK + || (tmp == KISS_6PACK) + || ((tmp == KISS_6PACK) && (max_device != 0)) +#endif + || (tmp < KISS_NORMAL) + || (tmp > KISS_MAX) + || ((tmp == KISS_TOK) && (max_device != 0))) + return (TRUE); + + /* Typ merken */ + l1port[max_device].kisstype = tmp; + + /* Geschwindigkeit fuer Tokenring-Port */ + if (tmp == KISS_TOK) + { + tkcom = 1; + switch (l1port[0].speed) + { + case B9600: + tkbaud = 96; + break; + + case B19200: + tkbaud = 192; + break; + + case B38400: + tkbaud = 384; +#ifndef B57600 + if (l1port[0].speedflag == ASYNC_SPD_HI) + tkbaud = 576; +#endif +#ifndef B115200 + if (l1port[0].speedflag == ASYNC_SPD_VHI) + tkbaud = 1152; +#endif +#ifndef B230400 + if (l1port[0].speedflag == ASYNC_SPD_SHI) + tkbaud = 2304; +#endif +#ifndef B460800 + if (l1port[0].speedflag == ASYNC_SPD_WARP) + tkbaud = 4608; +#endif + + break; + +#ifdef B57600 + case B57600: + tkbaud = 576; + break; +#endif +#ifdef B115200 + case B115200: + tkbaud = 1152; + break; +#endif +#ifdef B230400 + case B230400: + tkbaud = 2304; + break; +#endif +#ifdef B460800 + case B460800: + tkbaud = 4608; + break; +#endif + } + } + return (FALSE); + + /* Parameter "port" */ + case PORT: + if ( (max_device < 0) + || (sscanf(str2, "%d", &tmp) != 1) + || (tmp < 0) + || (tmp > L2PNUM) + || (l1port[max_device].kisstype < 0)) + return (TRUE); + + /* Sonderbehandlung fuer Tokenring-Ports */ + if (l1port[max_device].kisstype == KISS_TOK) + { + /* noch Ports verfuegbar ? */ + if (++tokenring_ports >= L2PNUM) + return (TRUE); + + l1ptab[tmp] = 0; + l2ptab[max_device] = -1; + ++used_l1ports; + return (FALSE); + } + +#ifdef SIXPACK + /* Sonderbehandlung fuer 6PACK-Ports */ + if (l1port[max_device].kisstype == KISS_6PACK) + { + /* noch Ports verfuegbar ? */ + if (++sixpack_ports >= L2PNUM) + return (TRUE); + + l1ptab[tmp] = max_device; + l2ptab[max_device] = -1; + ++used_l1ports; + return (FALSE); + } +#endif + /* alle andere Devices */ + /* noch Ports verfuegbar ? */ + if (++used_l1ports >= L2PNUM) + return (TRUE); + + if ( l1ptab[tmp] == -1 /* Port noch nicht */ + && l2ptab[max_device] == -1) /* verwendet? */ + { + l1ptab[tmp] = max_device; + l2ptab[max_device] = tmp; + } + + /* Evtl. sollte noch geprueft werden, ob die Zuordnung der Vanessa- */ + /* ports konsistent ist. */ + return (FALSE); + + default: + return (TRUE); + } + return (FALSE); +} + +/************************************************************************/ +/* Fuegt das TNN-Verzeichnis vorne hinzu */ +/************************************************************************/ +void +add_tnndir(char *str) +{ + char temp[80]; + + /* leere Strings verarbeiten wir nicht */ + if (str[0] == NUL) + return; + + /* nur bearbeiten, wenn erstes Zeichen nicht / ist */ + if (str[0] != '/') + { + strcpy(temp, tnn_dir); + strcat(temp, str); + strcpy(str, temp); + } +} + +/************************************************************************/ +/* Lesen des TNN-INI-Files und des Kommandozeilenparameter */ +/************************************************************************/ +BOOLEAN +read_init_file(int argc, char *argv[]) +{ + FILE *init_file_fp; + BOOLEAN wrong_usage = FALSE; + BOOLEAN file_end = FALSE; + BOOLEAN file_corrupt = FALSE; + BOOLEAN warning = FALSE; + char line[82]; + char str1[82]; + char str2[82]; + char tmp_str[80]; + int rslt; + char *str_ptr; + int scanned; + int i; + DEVICE *l1pp; +#ifdef AX_IPX + int axipx_ports = 0; +#endif +#ifdef AX25IP + int ax25ip_ports = 0; +#endif +#ifdef L1TELNET + int telnet_ports = 0; +#endif /* L1TELNET */ +#ifdef L1HTTPD + int httpd_ports = 0; +#endif /* L1HTTPD */ +#ifdef L1IPCONV + int ipconv_ports = 0; +#endif /* L1IPCONV */ +#ifdef L1IRC + int irc_ports = 0; +#endif /* L1IRC */ + + /* erst mal alles initialisieren */ + tnn_buffers = TNN_BUFFERS; + max_device = -1; +#ifdef ATTACH + tokenring_ports = 0; + sixpack_ports = 0; +#else + tokenring_ports = -1; +#endif /* ATTACH */ + used_l1ports = -1; + kiss_active = FALSE; + tnn_socket[0] = + start_name[0] = + stop_name[0] = NUL; + console_type = CONS_TERM_DO_SETUP; /* wir erwarten erst einmal eine Konsole */ + + /* alle L1-Ports durchgehen und initialisieren */ + for (i = 0; i < L1PNUM; ++i) + { + l1pp = &l1port[i]; + l1pp->device[0] = NUL; + l1pp->tnn_lockfile[0] = NUL; + l1pp->speed = 0; + l1pp->speedflag = 0; + l1pp->kisstype = KISS_NIX; + l1pp->kisslink = -1; + l1pp->port_active = FALSE; + l2ptab[i] = -1; + } + + /* alle L2-Ports durchgehen und initialisieren */ + for (i = 0; i < L2PNUM; ++i) + { + l1ptab[i] = -1; + CLR_L1MODE(i); + SET_L1MODE(i, MODE_off); + } + + strcpy(tnn_initfile, "tnn.ini"); + scanned = 1; + unlock = 0; + + /* Kommandozeilenparameter auswerten */ + while ((scanned < argc) && (!wrong_usage)) + { + /* Parameter "-i" (alternatives INI-File) */ + if (strcmp(argv[scanned], "-i") == 0) + { + scanned++; + if (scanned < argc) + { + strcpy(tnn_initfile, argv[scanned]); + } + else + wrong_usage = TRUE; + } + else if (strcmp(argv[scanned], "-s") == 0) + /* Parameter "-s" (alternativ Socket) */ + { + scanned++; + if (scanned < argc) + { + strcpy(tnn_socket, argv[scanned]); + console_type = CONS_SOCKET_DO_SETUP; + } + else + wrong_usage = TRUE; + } + else if (strcmp(argv[scanned], "-u") == 0) + /* Parameter "-u" (Lock-Files loeschen) */ + { + unlock = 1; + } + else if (strcmp(argv[scanned], "-v") != 0) + { + wrong_usage = TRUE; + } + scanned++; + } + + /* falsche / unbekannte Kommandozeilenparameter */ + if (wrong_usage) + { + printf("Usage : tnn [-i ] [-s ] [-u] [-v]\n"); + return (TRUE); + } + + /* INI-File oeffnen */ + if (!(init_file_fp = fopen(tnn_initfile, "r"))) + { + warning = TRUE; + str_ptr = getenv("HOME"); + if (str_ptr != NULL) + { + sprintf(tmp_str, "%s/%s", str_ptr, tnn_initfile); + if ((init_file_fp = fopen(tmp_str, "r")) != NULL) + warning = FALSE; + } +#ifdef INIPATH + if (!init_file_fp) + { + sprintf(tmp_str, "%s/%s", INIPATH, tnn_initfile); + if ((init_file_fp = fopen(tmp_str, "r")) != NULL) + warning = FALSE; + } +#endif + } + + /* Datei nicht gefunden */ + if (warning) + { +#ifdef ATTACH + /* tnn_procfile muss definiert sein! */ + strcpy(tnn_procfile, "tnn.pid"); + return(FALSE); +#else + printf("ERROR: %s not found\n\n", tnn_initfile); + return (TRUE); +#endif /* ATTACH */ + } + + /* solange noch was im INI_File ist */ + while (!file_end) + { + /* eine Zeile einlesen */ + if (fgets(line, 82, init_file_fp) == NULL) + { + file_end = TRUE; + } + else + { + /* Zeile konnte nicht eingelesen werden */ + if (strlen(line) == 82) + { + file_end = TRUE; + file_corrupt = TRUE; + } + else + { + if (line[0] != '#') + { /* ignore comment-lines */ + rslt = sscanf(line, "%s %s", str1, str2); + switch (rslt) + { + case EOF: /* ignore blank lines */ + break; + case 2: + if (analyse_value(str1, str2)) /* Zeile analysieren */ + { + file_end = TRUE; + file_corrupt = TRUE; + } + break; + default: + file_end = TRUE; + file_corrupt = TRUE; + break; + } + } + } + } + } + fclose(init_file_fp); + + if (file_corrupt) + { + printf("ERROR: %s is in wrong format, wrong line:\n%s\n\n", tnn_initfile, line); + return (TRUE); + } + else + { + for (i = 0; i < L1PNUM; i++) + { +#ifdef AX_IPX + if (l1port[i].kisstype == KISS_IPX) + { + if (axipx_ports == 0) + ++axipx_ports; + else + l1port[i].kisstype = KISS_NIX; + } +#endif +#ifdef AX25IP + if (l1port[i].kisstype == KISS_AXIP) + { + if (ax25ip_ports == 0) + ++ax25ip_ports; + else + l1port[i].kisstype = KISS_NIX; + } +#endif +#ifdef L1TELNET + if (l1port[i].kisstype == KISS_TELNET) + { + if (telnet_ports == 0) + ++telnet_ports; + else + l1port[i].kisstype = KISS_NIX; + } +#endif /* L1TELNET */ +#ifdef L1HTTPD + if (l1port[i].kisstype == KISS_HTTPD) + { + if (httpd_ports == 0) + ++httpd_ports; + else + l1port[i].kisstype = KISS_NIX; + } +#endif /* L1HTTPD */ +#ifdef L1IPCONV + if (l1port[i].kisstype == KISS_IPCONV) + { + if (ipconv_ports == 0) + ++ipconv_ports; + else + l1port[i].kisstype = KISS_NIX; + } +#endif /* L1IPCONV */ +#ifdef L1IRC + if (l1port[i].kisstype == KISS_IRC) + { + if (irc_ports == 0) + ++irc_ports; + else + l1port[i].kisstype = KISS_NIX; + } +#endif /* L1IPCONV */ + + if (*(l1port[i].tnn_lockfile) != NUL) + add_tnndir(l1port[i].tnn_lockfile); + } + add_tnndir(tnn_errfile); + add_tnndir(tnn_procfile); + add_tnndir(tnn_socket); + + if (used_l1ports >= 0) + kiss_active = TRUE; + + /* externes Programm starten wenn gesetzt */ + if (start_name[0]) + system(start_name); + + return (FALSE); + } +} + +/************************************************************************/ +/* Proc-File schreiben */ +/************************************************************************/ +BOOLEAN +init_proc(void) +{ + FILE *fp = NULL; + pid_t pid = 0; + int killresult = 0; + + VMSG("--- Checking pid-file ...\n"); + + fp = fopen(tnn_procfile, "r"); + + if (fp != NULL) /* altes tnn.pid vorhanden? */ + { + if (fscanf(fp, "%d", &pid) == 1) /* alte PID lesen */ + { + killresult = kill(pid, 0); + + if (killresult != -1) /* lebt das alte Programm noch? */ + { + fclose(fp); + return (FALSE); /* lebt noch, also ENDE! */ + } + } + fclose(fp); + } + + VMSG("--- Creating new pid-file ...\n"); + + /* neues File anleegn */ + fp = fopen(tnn_procfile, "w+"); + + if (fp == NULL) + { + printf("ERROR: Can't create process file\n"); + return (FALSE); + } + + /* aktuelle PID hineinschreiben */ + pid = getpid(); + fprintf(fp, "%d", pid); + fclose(fp); + + return (TRUE); +} + +/************************************************************************/ +/* Proc-File loeschen */ +/************************************************************************/ +void +exit_proc(void) +{ + unlink(tnn_procfile); +} + +/* End of os/linux/init.c */ diff --git a/os/linux/kernelax.c b/os/linux/kernelax.c new file mode 100755 index 0000000..55a0bce --- /dev/null +++ b/os/linux/kernelax.c @@ -0,0 +1,644 @@ +/************************************************************************/ +/* */ +/* ***** ***** */ +/* ***** ***** */ +/* ***** ***** */ +/* ***** ***** */ +/* *************** *************** */ +/* ***************** ***************** */ +/* *************** *************** */ +/* ***** ***** TheNetNode */ +/* ***** ***** Portable */ +/* ***** ***** Network */ +/* ***** ***** Software */ +/* */ +/* File os/linux/kernelax.c (maintained by: DG9OBU) */ +/* */ +/* This file is part of "TheNetNode" - Software Package */ +/* */ +/* Copyright (C) 1998 - 2008 NORD>port_active != TRUE) + || ((l1pp->kisstype != KISS_KAX25) && (l1pp->kisstype != KISS_KAX25KJD)) + || (l1pp->kisslink > -1)) + return (FALSE); + + /* Socket anlegen */ + if ((l1pp->kisslink = socket(AF_PACKET, SOCK_PACKET, htons(ETH_P_ALL))) < 0) + { + mbp = putals("Can't create socket !\r"); + show_error(mbp); + seteom(mbp); + + /* da in der Regel auf "-1" geprueft wird ... */ + l1pp->kisslink = -1; + return (FALSE); + } + + /* Interfacestruktur bereinigen und Interface auswaehlen */ + memset(&ifr, 0, sizeof(ifr)); + strcpy(ifr.ifr_name, l1pp->device); + + /* vom Kernel die aktuellen Interfaceeinstellungen holen */ + if (ioctl(l1pp->kisslink, SIOCGIFFLAGS, &ifr) < 0) + { + /* dieses Interface gab es aber nicht */ + mbp = putals("Can't get current interface flags from kernel !\r"); + show_error(mbp); + seteom(mbp); + + /* Interface schliessen und als nicht nutzbar markieren */ + close(l1pp->kisslink); + l1pp->kisslink = -1; + return (FALSE); + } + + /* Flags des Interfaces sichern */ + l1pp->oldifparms = ifr.ifr_flags; + + /* Sicherheitshalber Interface aktivieren */ + ifr.ifr_flags |= IFF_UP; + +/* brauchen wir das wirklich ??? */ +/* ifr.ifr_flags |= IFF_PROMISC; */ + + /* Aenderungen zum Interface bringen */ + if (ioctl(l1pp->kisslink, SIOCSIFFLAGS, &ifr) < 0) + { + mbp = putals("Can't set new interface flags !\r"); + show_error(mbp); + seteom(mbp); + + /* Schliessen und alte Einstellungen wiederherstellen */ + ifax_close(l1pp); + return (FALSE); + } + + /* Socketstruktur loeschen und danach fuellen */ + memset(&sa, 0, sizeof(sa)); + strcpy(sa.sa_data, l1pp->device); + sa.sa_family = AF_INET; + + /* Interface binden */ + if (bind(l1pp->kisslink, &sa, sizeof(struct sockaddr)) < 0) + { + mbp = putals("Can't bind interface !\r"); + show_error(mbp); + seteom(mbp); + + /* Schliessen und alte Einstellungen wiederherstellen */ + ifax_close(l1pp); + return (FALSE); + } + + return (TRUE); +} + +/**************************************************************************/ +/* Interface schliessen */ +/**************************************************************************/ +void ifax_close(DEVICE *l1pp) +{ + struct ifreq ifr; + + /* nur bei Interfaces mit gueltigem Descriptor */ + if (l1pp->kisslink != -1) + { + /* Alten Interface-Zustand wiederherstellen */ + ifr.ifr_flags = l1pp->oldifparms; + ioctl(l1pp->kisslink, SIOCSIFFLAGS, &ifr); + + /* Schliessen und als unbenutzt markieren */ + close(l1pp->kisslink); + l1pp->kisslink = -1; + } +} + +/**************************************************************************/ +/* Portinfo-String fuer den PORT-Befehl */ +/**************************************************************************/ +void ifax_hwstr(int port, MBHEAD *mbp) +{ + putprintf(mbp, " Interface %s", &(l1port[l1ptab[port]].device[0])); +} + +/**************************************************************************/ +/* Daten vom Interface abholen, vorher muss mit select geprueft werden */ +/* ob auch Daten da sind (Stichwort select() ) */ +/**************************************************************************/ +void ifax_rx(int fd) +{ + int i = 0; + int j = 0; + int port = 0; + char buf[2048]; + + MBHEAD *mbhd; + + for (port = 0; port < L2PNUM; port++) + { + /* nur aktive Kernelports und davon den richtigen mit dem aktiven fd */ + if ( (l1port[l1ptab[port]].port_active != TRUE) + || (l1port[l1ptab[port]].kisstype < KISS_KAX25) + || (l1port[l1ptab[port]].kisstype > KISS_KAX25KJD) + || (l1port[l1ptab[port]].kisslink != fd)) + continue; + + memset(buf, 0, sizeof(buf)); + errno = 0; + + i = recvfrom(l1port[l1ptab[port]].kisslink, &buf[0], 2048, 0, NULL, 0); + + /* Fehler abfangen */ + if (i <= 0) + { + if (i < 0) + { + /* es konnte nicht richtig gesendet werden, Port schliessen */ + l1detach(port); + } + return; + } + + /* bei normalem Kernelstack das KISS-Kommandobyte auswerten */ + if (l1port[l1ptab[port]].kisstype == KISS_KAX25) + { + j = 1; + /* Sortieren was da gekommen ist, Parameteraenderungen uebernehmen */ + switch (buf[0] & 0x0F) + { + case 0 : break; /* normale Frames */ + case PARAM_TXDELAY: + portpar[port].txdelay = (int)buf[1]; + autopar(port); + return; + case PARAM_SLOTTIME: + portpar[port].slottime = (int)buf[1]; + autopar(port); + return; + case PARAM_PERSIST: + portpar[port].persistance = (int)buf[1]; + autopar(port); + return; + case PARAM_FULLDUP: + if (buf[1]) + portpar[port].l1mode = portpar[port].l1mode & MODE_d; + else + portpar[port].l1mode = portpar[port].l1mode & ~MODE_d; + autopar(port); + return; + default : return; /* alles unbekannte wird nicht weitergereicht */ + } + } + + /* Puffer besorgen und Port eintragen */ + (mbhd = (MBHEAD *)allocb(ALLOC_MBHEAD))->l2port = port; + + /* Puffer kopieren */ + for (; j < i; j++) + putchr(buf[j], mbhd); + + /* in Empfangsliste einhaengen */ + relink((LEHEAD *)mbhd, (LEHEAD *)rxfl.tail); + } +} + +/**************************************************************************/ +/* Sendedaten an das Interface schicken, keine Parameter */ +/**************************************************************************/ +void ifax_tx(void) +{ + struct sockaddr to; + char buf[2048]; + int count = 1; + int port; + + MBHEAD *txfhdl; + LHEAD *l2flp; + + l2flp = txl2fl; + + for (port = 0; port < L2PNUM; l2flp++, port++) + { + /* Feststellen, ob der Port hier behandelt werden kann */ + if ( (l1port[l1ptab[port]].port_active != TRUE) + || (l1port[l1ptab[port]].kisstype < KISS_KAX25) + || (l1port[l1ptab[port]].kisstype > KISS_KAX25KJD) + || (l1port[l1ptab[port]].kisslink < 0) + ) + continue; + + if (portenabled(port)) + { + if (kick[port]) /* was zum senden... */ + { + if (l2flp->head == l2flp) + { + /* nichts mehr zu senden da */ + kick[port] = FALSE; + continue; + } + + memset(&buf[0], 0, sizeof(buf)); + + /* KJD-Stack */ + if (l1port[l1ptab[port]].kisstype == KISS_KAX25KJD) + count = 0; + + ulink((LEHEAD *)(txfhdl = (MBHEAD *) l2flp->head)); /* Zeiger holen */ + + while (txfhdl->mbgc < txfhdl->mbpc) /* solange Daten vorhanden sind */ + buf[count++] = getchr(txfhdl); + + relink((LEHEAD *)txfhdl, /* als gesendet betrachten und in */ + (LEHEAD *)stfl.tail); /* die gesendet Liste umhaengen */ + + kick[port] = ((LHEAD *)l2flp->head != l2flp); + + memset(&to, 0, sizeof(to)); + errno = 0; + + /* Interface setzen auf dem dieses Paket gesendet werden soll */ + strcpy(to.sa_data, l1port[l1ptab[port]].device); + + /* Puffer senden und Fehler feststellen */ + if (sendto(l1port[l1ptab[port]].kisslink, &buf[0], count, 0, &to, sizeof(to)) < 0) + l1detach(port); + } + } + else /* Port kann nicht senden, Frames einfach kopieren */ + while (l2flp->head != l2flp) + relink(ulink((LEHEAD *) l2flp->head), (LEHEAD *)stfl.tail); + } +} + +/**************************************************************************/ +/* Setzt die Parameter (Slottime, TX-Delay usw.) */ +/**************************************************************************/ +void ifax_param(int port) +{ + struct sockaddr to; + unsigned char buf[2]; + static int count = 2; /* alle KISS-Befehle sind zwei Bytes lang */ + + /* Feststellen, ob der Port hier behandelt werden kann */ + if ( (l1port[l1ptab[port]].port_active != TRUE) + || (l1port[l1ptab[port]].kisstype != KISS_KAX25) + || (l1port[l1ptab[port]].kisslink < 0) + ) + return; + +#ifdef PCISCC4_KAX25 + /* PCISCC4-Devices unter normalem Kernel-AX.25 mit dem Treiber von F6FBB */ + /* oder unter einem 2.2.x-KJD-Kernel. Hier funktioniert leider die normale */ + /* KISS-Mimik nicht, also muessen die Einstellungen per ioctl() zum Treiber. */ + if (strncmp("dscc", l1port[l1ptab[port]].device, 4) == 0) + { + struct ifreq ifr; + struct devcfg_t cfg; + + memset(&ifr, 0, sizeof(ifr)); + strcpy(ifr.ifr_name, l1port[l1ptab[port]].device); +/* + if (ioctl(l1port[l1ptab[port]].kisslink, SIOCGIFFLAGS, &ifr) < 0) + { + notify(1, "*** PCISCC4: Can't select interface %s", l1port[l1ptab[port]].device); + return; + } +*/ + ifr.ifr_data = (caddr_t)&cfg; + + /* aktuelle Einstellungen holen */ + if (ioctl(l1port[l1ptab[port]].kisslink, SIOCPCISCCGDCFG, &ifr) < 0) + { + notify(1, "*** PCISCC4: Can't read current setting from interface %s", l1port[l1ptab[port]].device); + return; + } + + /* Einstellungen modifizieren */ + /* Semi/Vollduplex einstellen */ + cfg.duplex = (fullduplex(port) ? CFG_DUPLEX_FULLPTT : CFG_DUPLEX_HALF); + + /* TX-Delay (Achtung: Anzahl Bits, nicht Millisekunden) */ + cfg.txdelval = (int)((portpar[port].speed * 100) * (portpar[port].txdelay * 10) / 1000); + + /* TX-Tail */ +#ifdef SETTAILTIME + cfg.txtailval = (int)((portpar[port].speed * 100) * (portpar[port].tailtime * 10) / 1000); +#endif + /* Slottime */ + cfg.slottime = (int)((portpar[port].speed * 100) * (portpar[port].slottime * 10) / 1000);; + + /* Persistance */ + cfg.persist = (dama(port)) ? 255 : portpar[port].persistance; + + /* Neue Einstellungen zum Interface bringen */ + ifr.ifr_data = (caddr_t)&cfg; + + /* und ab damit zum Treiber */ + if (ioctl(l1port[l1ptab[port]].kisslink, SIOCPCISCCSDCFG, &ifr) < 0) + notify(1, "*** PCISCC4: Can't set new settings on interface %s", l1port[l1ptab[port]].device); + + return; + } +#endif + + /* Hier ist Schluss fuer KJD-Kernel, der kennt die KISS-Methoden nicht. */ + if (l1port[l1ptab[port]].kisstype == KISS_KAX25KJD) + return; + + /* Alle anderen Interfaces landen hier, normale KISS-Methode zum */ + /* Einstellen der Portparameter. Sicherheitshalber alle Einstellungen */ + /* separat vornehmen. */ + /* Interface waehlen */ + memset(&to, 0, sizeof(to)); + strcpy(to.sa_data, l1port[l1ptab[port]].device); + + /* TX-Delay senden */ + buf[0] = PARAM_TXDELAY; + buf[1] = portpar[port].txdelay; + + if (sendto(l1port[l1ptab[port]].kisslink, &buf[0], count, 0, &to, sizeof(to)) < 0) + { + notify(1, "*** KERNELAX: Can't set TX-Delay on interface %s", l1port[l1ptab[port]].device); + return; + } + + /* Slottime senden */ + buf[0] = PARAM_SLOTTIME; + buf[1] = portpar[port].slottime; + + if (sendto(l1port[l1ptab[port]].kisslink, &buf[0], count, 0, &to, sizeof(to)) < 0) + { + notify(1, "*** KERNELAX: Can't set Slottime on interface %s", l1port[l1ptab[port]].device); + return; + } + + /* Persistance senden */ + buf[0] = PARAM_PERSIST; + buf[1] = (dama(port) ? 255 : portpar[port].persistance); + + if (sendto(l1port[l1ptab[port]].kisslink, &buf[0], count, 0, &to, sizeof(to)) < 0) + { + notify(1, "*** KERNELAX: Can't set Persistance on interface %s", l1port[l1ptab[port]].device); + return; + } + + /* Vollduplex setzen */ + buf[0] = PARAM_FULLDUP; + buf[1] = (fullduplex(port) ? 1 : 0); + + if (sendto(l1port[l1ptab[port]].kisslink, &buf[0], count, 0, &to, sizeof(to)) < 0) + { + notify(1, "*** KERNELAX: Can't set Half/Fullduplex on interface %s", l1port[l1ptab[port]].device); + return; + } + + return; +} + +/**************************************************************************/ +/* Level 1 Kontroll- und Kommandointerface */ +/**************************************************************************/ +void ifax_l1ctl(int req) +{ + switch (req) + { + case L1CCMD : update_parms = TRUE; break; /* Portparameter setzen */ + default : break; /* den Rest koennen wir nicht */ + } +} + +/**************************************************************************/ +/* Generelle Funktion, sendet ausstehende Frames und bringt ggf. */ +/* Parameteraenderungen zum Interface usw. */ +/**************************************************************************/ +void ifax_housekeeping(void) +{ + register int port; + + ifax_tx(); + + if (update_parms) + { + for (port = 0; port < L2PNUM; ++port) + { + if (l1port[l1ptab[port]].kisstype != KISS_KAX25) + continue; + + if (commandflag[port]) + { + ifax_param(port); + commandflag[port] = FALSE; + } + } + update_parms = FALSE; + } +} + +/**************************************************************************/ +/* DCD/PTT-Status fuer Kernelinterfaces abfragen */ +/**************************************************************************/ +int ifax_dcd(int port) +{ + int state = 0; + + if ( (l1port[l1ptab[port]].port_active != TRUE) + || ( (l1port[l1ptab[port]].kisstype != KISS_KAX25) + && (l1port[l1ptab[port]].kisstype != KISS_KAX25KJD) + ) + || (l1port[l1ptab[port]].kisslink < 0) + ) + return 0; /* Device gehoert hier nicht hin */ + +#ifdef PCISCC4_KAX25 + /* PCISCC4-Devices mit dem Treiber von F6FBB fuer 2.4.x-Kernel */ + /* oder 2.2.x-KJD-Kernel */ + /* (dscc0, dscc1, ...) */ + if (strncmp("dscc", l1port[l1ptab[port]].device, 4) == 0) + { + struct ifreq ifr; + unsigned long devstat; + + memset(&ifr, 0, sizeof(ifr)); + strcpy(ifr.ifr_name, l1port[l1ptab[port]].device); + + if (ioctl(l1port[l1ptab[port]].kisslink, SIOCPCISCCGDSTAT, &ifr) < 0) + { + notify(1, "*** PCISCC4: Can't read DCD/PTT state from interface %s", l1port[l1ptab[port]].device); + return 0; + } + + devstat = (unsigned long)ifr.ifr_data; + + /* DCD */ + if (devstat & STATUS_CD) + state |= (WORD)(DCDFLAG); + + /* PTT */ + if (devstat & STATUS_RTS) + state |= (WORD)(PTTFLAG); + + /* noch mehr PTT-Zustaende (mit Daten in der PCISCC4) */ + switch (devstat & 15) + { + case TX_DELAY : + case TX_XMIT : state |= (WORD)(TXBFLAG); break; + + default : break; + } + + return state; + } +#endif + +#ifdef HDLC_DCDPTTSTAT + /* hdlcdrv wird benutzt von bcsf, bcsh, bce, bcp, sm (2.4.x) */ + if ( (strncmp("bc", l1port[l1ptab[port]].device, 2) == 0) + || (strncmp("sm", l1port[l1ptab[port]].device, 2) == 0) + ) + { + struct ifreq ifr; + struct hdlcdrv_ioctl ifrpar; + + ifr.ifr_data = (caddr_t)&ifrpar; + ifrpar.cmd = HDLCDRVCTL_GETSTAT; + + strcpy(ifr.ifr_name, l1port[l1ptab[port]].device); + + if (ioctl(l1port[l1ptab[port]].kisslink, SIOCDEVPRIVATE, &ifr) < 0) + { + notify(1, "*** HDLCDRV: Can't read DCD/PTT state from interface %s", l1port[l1ptab[port]].device); + return 0; + } + + /* DCD */ + if (ifrpar.data.cs.dcd) + state |= (WORD)(DCDFLAG); + + /* PTT */ + if (ifrpar.data.cs.ptt) + state |= (WORD)(PTTFLAG); + + return state; + } +#endif + +#ifdef SCC_DCDPTTSTAT + /* SCC-Devices (scc0, scc1, ... ) */ + if (strncmp("scc", l1port[l1ptab[port]].device, 3) == 0) + { + struct ifreq ifr; + struct scc_kiss_cmd kiss_cmd; + + ifr.ifr_data = (caddr_t)&kiss_cmd; + kiss_cmd.command = PARAM_RTS; + + strcpy(ifr.ifr_name, l1port[l1ptab[port]].device); + + /* PTT-Zustand holen */ + if (ioctl(l1port[l1ptab[port]].kisslink, SIOCSCCGKISS, &ifr) < 0) + { + notify(1, "*** SCC: Can't read PTT state from interface %s", l1port[l1ptab[port]].device); + return 0; + } + + /* PTT */ + if (kiss_cmd.param) + state |= (WORD)(PTTFLAG); + +#ifdef OBU_SCC_DCD + /* Funktioniert NUR mit gepatchten Kerneln !!! (siehe history/sccpatch.txt) */ + ifr.ifr_data = (caddr_t)&kiss_cmd; + kiss_cmd.command = PARAM_DCD; + + strcpy(ifr.ifr_name, l1port[l1ptab[port]].device); + + /* DCD-Zustand holen */ + if (ioctl(l1port[l1ptab[port]].kisslink, SIOCSCCGKISS, &ifr) < 0) + { + notify(1, "*** SCC: Can't read DCD state from interface %s", l1port[l1ptab[port]].device); + return state; /* PTT kann gesetzt sein, also Status melden ! */ + } + + /* DCD */ + if (kiss_cmd.param) + state |= (WORD)(DCDFLAG); +#endif + + return state; + } +#endif + + return 0; +} + +#endif + +/* End of os/linux/kernelax.c */ diff --git a/os/linux/kernelax.h b/os/linux/kernelax.h new file mode 100755 index 0000000..42d2dd0 --- /dev/null +++ b/os/linux/kernelax.h @@ -0,0 +1,76 @@ +/************************************************************************/ +/* */ +/* ***** ***** */ +/* ***** ***** */ +/* ***** ***** */ +/* ***** ***** */ +/* *************** *************** */ +/* ***************** ***************** */ +/* *************** *************** */ +/* ***** ***** TheNetNode */ +/* ***** ***** Portable */ +/* ***** ***** Network */ +/* ***** ***** Software */ +/* */ +/* File os/linux/kernelax.h (maintained by: DG9OBU) */ +/* */ +/* This file is part of "TheNetNode" - Software Package */ +/* */ +/* Copyright (C) 1998 - 2008 NORD> +#include + +/* PCISCC4 mit dem Treiber von F6FBB */ +#ifdef PCISCC4_KAX25 +#include +#endif + +/* DCD und PTT beim HDLC-Treiber abfragen */ +#ifdef HDLC_DCDPTTSTAT +#include +#endif + +/* DCD und PTT beim SCC-Treiber abfragen */ +#ifdef SCC_DCDPTTSTAT +#include +#endif + +/* Kommando-Bytecodes fuer den KISS-Socket */ +#define PARAM_TXDELAY 1 +#define PARAM_PERSIST 2 +#define PARAM_SLOTTIME 3 +#define PARAM_TXTAIL 4 +#define PARAM_FULLDUP 5 + +/* End of os/linux/kernelif.h */ diff --git a/os/linux/kernelip.c b/os/linux/kernelip.c new file mode 100755 index 0000000..df3dfc4 --- /dev/null +++ b/os/linux/kernelip.c @@ -0,0 +1,689 @@ +/************************************************************************/ +/* */ +/* ***** ***** */ +/* ***** ***** */ +/* ***** ***** */ +/* ***** ***** */ +/* *************** *************** */ +/* ***************** ***************** */ +/* *************** *************** */ +/* ***** ***** TheNetNode */ +/* ***** ***** Portable */ +/* ***** ***** Network */ +/* ***** ***** Software */ +/* */ +/* File os/linux/kernelip.c (maintained by: DG9OBU) */ +/* */ +/* This file is part of "TheNetNode" - Software Package */ +/* */ +/* Copyright (C) 1998 - 2008 NORD>\r"); + prompt(mbp); + seteom(mbp); + return; + } + + mbp = putals("Kernel-IP "); + + if (get_ip_addr(&t_ip_addr, &clicnt, &clipoi) == TRUE) /* IP lesen */ + { + /* Unmoegliche IP-Adressen abfangen (nur niederwertigstes Byte) */ + /* eigentlich muesste man die anderen auch noch pruefen... */ + if (((t_ip_addr & 0xFF) == 0L) || ((t_ip_addr & 0xFF) == 0xFF)) + { + putstr("is invalid !\r", mbp); + prompt(mbp); + seteom(mbp); + return; + } + + if (skipsp(&clicnt, &clipoi)) /* sind noch weitere Zeichen da? */ + { + if (*clipoi++ == '/') /* Subnetz-Trenner vorhanden? */ + { + clicnt--; + /* Subnetz-Bits lesen und Idiotencheck machen */ + t_ip_bits = nxtnum(&clicnt, &clipoi); + if (t_ip_bits > 32 || t_ip_bits < 1) + t_ip_bits = 32; + } + } + + kip_info.kernel_ip = t_ip_addr; + + if (t_ip_addr == 0L) + kip_info.maskbits = 0; + else + kip_info.maskbits = t_ip_bits; /* Subnetz-Bits uebernehmen */ + + putstr("set to ", mbp); + show_ip_addr(kip_info.kernel_ip, mbp); + putchr('/', mbp); + putnum(kip_info.maskbits, mbp); + putchr('\r', mbp); + } + else + putstr("could not be read ! Don't use hostnames, numbers only !\r", mbp); + + prompt(mbp); + seteom(mbp); + return; + + } + + mbp = putals("Usage: KERNELIF [INIT, CLEAR, SETKIP, UP, DOWN, STATUS]\r"); + prompt(mbp); + seteom(mbp); + return; + } + else + invmsg(); +} + +/* Den Infoblock initialisieren */ +static void ifip_init(struct kip *if_info) +{ + if_info->if_available = FALSE; + if_info->if_style = 0; + if_info->if_active = FALSE; + if_info->kernel_ip = 0L; + if_info->maskbits = 32; + if_info->if_fd = -1; + if_info->bytes_rx = 0L; + if_info->bytes_tx = 0L; +} + +/* Pruefen, ob notwendige Funktionen verfuegbar sind */ +static BOOLEAN ifip_usable(struct kip *if_info) +{ + int fd = 0; + int i = 0; + + char ifdev[14]; + + if ((fd = open(IFIP, O_RDWR)) > 0) + { + if_info->if_available = TRUE; + if_info->if_style = 256; + close(fd); + return TRUE; + } + + for (i = 0; i < 255; i++) + { + sprintf(ifdev, "/dev/tun%d", i); + if ((fd = open(ifdev, O_RDWR)) > 0) + { + if_info->if_available = TRUE; + if_info->if_style = i; + close(fd); + return TRUE; + } + } + + if_info->if_available = FALSE; + if_info->if_style = 0; + return FALSE; +} + +/* Den Link zum Kernel schliessen und im Infoblock als inaktiv vermerken */ +static void ifip_close(struct kip *if_info) +{ + if ((if_info->if_active == TRUE) && (if_info->if_fd >= 0)) + { + close(if_info->if_fd); + if_info->if_fd = -1; + if_info->if_active = FALSE; + } +} + +/* Das Interface kreieren */ +BOOLEAN ifip_setup(struct kip *if_info) +{ + int fd = 0; + int sd = 0; + int err = 0; + int i = 0; + + char dev[IFNAMSIZ]; + char ifdev[14]; + + unsigned long netmask; + + MBHEAD *mbp; + + struct ifreq ifr; + + memset(&ifr, 0, sizeof(ifr)); + memset(dev, 0, sizeof(dev)); + + /* Neue Variante (>2.4.6 und 2.6.x) */ + if (if_info->if_style == 256) + { + sprintf(dev, "tnn"); + + if ((fd = open(IFIP, O_RDWR)) <= 0) + { + close(fd); + mbp = putals("Can't open device !!!\r"); + show_error(mbp); + seteom(mbp); + return FALSE; + } + + ifr.ifr_flags = (IFF_TUN | IFF_NO_PI); + strncpy(ifr.ifr_name, dev, IFNAMSIZ); + + if ((err = ioctl(fd, TUNSETIFF, (void *) &ifr)) < 0 ) + { + close(fd); + mbp = putals("Can't set miscelleanous device flags, trying fallback ...\r"); + seteom(mbp); + + if ((fd = open(IFIP, O_RDWR)) <= 0) + { + close(fd); + mbp = putals("Sorry, can't open device anymore !!!\r"); + show_error(mbp); + seteom(mbp); + return FALSE; + } + + memset(&ifr, 0, sizeof(ifr)); + ifr.ifr_flags = (IFF_TUN | IFF_NO_PI); + + if (((err = ioctl(fd, TUNSETIFF, (void *) &ifr)) < 0 ) || (fd <= 0)) + { + close(fd); + mbp = putals("Can't set device flags, giving up !!!\r"); + show_error(mbp); + seteom(mbp); + return FALSE; + } + + mbp = putals(""); + putprintf(mbp, "Info: interface's name changed from '%s' to '%s' !!!\r", dev, ifr.ifr_name); + seteom(mbp); + + strcpy(dev, ifr.ifr_name); + } + strncpy(dev, ifr.ifr_name, IFNAMSIZ); + } + else + { /* Alte Variante (2.2.x) */ + sprintf(ifdev, "/dev/tun%d", if_info->if_style); + + fd = open(ifdev, O_RDWR); + + if (fd <= 0) + { + close(fd); + mbp = putals("Can't open device !!!\r"); + show_error(mbp); + seteom(mbp); + return FALSE; + } + + sprintf(dev, "tun%d", if_info->if_style); + } + + memset(&ifr, 0, sizeof(ifr)); + + sd = socket(AF_INET, SOCK_DGRAM, 0); + + if (sd <= 0) + { + close(sd); + mbp = putals("Can't set up interface !!!\r"); + show_error(mbp); + seteom(mbp); + return FALSE; + } + + strcpy(ifr.ifr_name, dev); + + ifr.ifr_addr.sa_family = AF_INET; + + ifr.ifr_addr.sa_data[0] = 0; + ifr.ifr_addr.sa_data[1] = 0; + ifr.ifr_addr.sa_data[6] = 0; + + for (i = 0; i < 4; i++) + ifr.ifr_addr.sa_data[5-i] = (if_info->kernel_ip >> 8 * i) & 0xff; + + if (ioctl(sd, SIOCSIFADDR, &ifr) < 0) + { + close(sd); + mbp = putals("Can't set kernel-side ip-adress !!!\r"); + show_error(mbp); + seteom(mbp); + return FALSE; + } + + for (i = 0; i < 4; i++) + ifr.ifr_addr.sa_data[5-i] = (my_ip_addr >> 8 * i) & 0xff; + + if (ioctl(sd, SIOCSIFDSTADDR, &ifr) < 0) + { + close(sd); + mbp = putals("Can't set tnn-side ip-adress !!!\r"); + show_error(mbp); + seteom(mbp); + return FALSE; + } + + netmask = (~0L) << (32 - if_info->maskbits); + + for (i = 0; i < 4; i++) + ifr.ifr_addr.sa_data[5-i] = (netmask >> 8 * i) & 0xFF; + + if (ioctl(sd, SIOCSIFNETMASK, &ifr) < 0) + { + close(sd); + mbp = putals("Can't set kernel-side netmask !!!\r"); + show_error(mbp); + seteom(mbp); + return FALSE; + } + + memset(&ifr, 0, sizeof(ifr)); + strncpy(ifr.ifr_name, dev, IFNAMSIZ); + + if ((err = ioctl(sd, SIOCGIFFLAGS, &ifr)) < 0) + { + close(sd); + mbp = putals("Can't read current interface flags !!!\r"); + show_error(mbp); + seteom(mbp); + return FALSE; + } + +/* ifr.ifr_flags &= IFF_NOARP; */ + ifr.ifr_flags |= IFF_UP; +/* ifr.ifr_flags |= IFF_RUNNING; */ + + if ((err = ioctl(sd, SIOCSIFFLAGS, &ifr)) < 0) + { + close(sd); + mbp = putals("Can't set new interface flags !!!\r"); + show_error(mbp); + seteom(mbp); + return FALSE; + } + + close(sd); + + strcpy(dev, ifr.ifr_name); + + if_info->if_active = TRUE; + if_info->if_fd = fd; + + return TRUE; +} + +/* Die Statistik des Infoblocks loeschen */ +void ifip_clearstat(void) +{ + kip_info.bytes_rx = 0L; + kip_info.bytes_tx = 0L; +} + +/* Statistik ausgeben */ +void ifip_dispstat(MBHEAD *mbp) +{ + putstr("\rKernel-Interface statistics:", mbp); + + putstr("\rBytes received : ", mbp); + putnum(kip_info.bytes_rx, mbp); + + putstr("\rBytes sent : ", mbp); + putnum(kip_info.bytes_tx, mbp); + + putstr("\r", mbp); +} + +/* Interface aktiv ? Wenn ja wird der verwendete Descriptor gemeldet, wenn */ +/* nicht wird -1 zurueckgemeldet */ +int ifip_active(void) +{ + if (kip_info.if_active == TRUE) + return (kip_info.if_fd); + else return (-1); +} + +/* Ein IP-Frame vom Kernel holen und in den internen Router einschleusen. */ +/* Sollte nur aufgerufen werden, wenn der Descriptor lesbar ist. */ +void ifip_frame_to_router(void) +{ + char buf[4096]; + int i = -1; + int j = 0; + + MBHEAD *mbhd; + + if ((i = read(kip_info.if_fd, &buf[0], 4096)) <= 0) + { + /* irgendwas lief schief, wir machen dicht */ + close(kip_info.if_fd); + kip_info.if_fd = -1; + kip_info.if_active = FALSE; + + return; + } + + kip_info.bytes_rx += (ULONG)i; + + (mbhd = (MBHEAD *)allocb(ALLOC_MBHEAD))->l2port = KERNEL_PORT; + + for (j = 0; j < i; j++) + putchr(buf[j], mbhd); + + rwndmb(mbhd); + + relink((LEHEAD *)mbhd, (LEHEAD *)iprxfl.tail); +} + +void ifip_frame_to_kernel(MBHEAD *mhbp) +{ + char buf[2048]; + int i = -1; + int j = 0; + + /* falls das Interface nicht aktiv ist und noch Routing-Leichen da sind */ + /* die noch was auf dem Port abladen, einfach wegschmeissen */ + if (kip_info.if_active == FALSE) + { + dealmb(mhbp); + return; + } + + rwndmb(mhbp); + + while (mhbp->mbgc < mhbp->mbpc) /* solange Daten vorhanden sind */ + buf[j++] = getchr(mhbp); + + dealmb(mhbp); + + kip_info.bytes_tx += (ULONG)j; + + if ((i = write(kip_info.if_fd, &buf[0], j)) <= 0) + { + /* irgendwas lief schief, wir machen dicht */ + close(kip_info.if_fd); + kip_info.if_fd = -1; + kip_info.if_active = FALSE; + } +} + +/* Die Konfiguration des Kernelinterfaces fuer parms.tnb dumpen */ +void dump_kernel(MBHEAD *mbp) +{ + putstr(";\r; Kernel Interface Configuration\r;\r", mbp); + + /* nur bei AKTIVIERTEM und LAUFENDEN Interface und wenn dem Kernel */ + /* eine IP-Adresse zugewiesen worden ist */ + if ((kip_info.if_active == FALSE) || (kip_info.kernel_ip == 0)) + { + putstr("; (no information dumped because interface was not running\r", mbp); + putstr("; or not properly configured)\r", mbp); + return; + } + + putstr("KERN INIT\r", mbp); + + /* die IP-Adresse des Kernels dumpen */ + putstr("KERN SETKIP ", mbp); + show_ip_addr(kip_info.kernel_ip, mbp); + putstr("\r", mbp); + + putstr("KERN UP\r", mbp); +} + +#endif + +/* End of os/linux/kernelip.c */ diff --git a/os/linux/kernelip.h b/os/linux/kernelip.h new file mode 100755 index 0000000..bf8a3cc --- /dev/null +++ b/os/linux/kernelip.h @@ -0,0 +1,108 @@ +/************************************************************************/ +/* */ +/* ***** ***** */ +/* ***** ***** */ +/* ***** ***** */ +/* ***** ***** */ +/* *************** *************** */ +/* ***************** ***************** */ +/* *************** *************** */ +/* ***** ***** TheNetNode */ +/* ***** ***** Portable */ +/* ***** ***** Network */ +/* ***** ***** Software */ +/* */ +/* File os/linux/kernelip.h (maintained by: DG9OBU) */ +/* */ +/* This file is part of "TheNetNode" - Software Package */ +/* */ +/* Copyright (C) 1998 - 2008 NORD> + +#include /* Die Version des Linux-Kernels */ + +/* Das tun-Interface und dessen Header gibt es erst seit 2.4.x im Kernel */ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) +#include +#else +#warning Kernel-Version is < 2.4.0, using internally defined values for tun-Interface ! +#endif + +#include + +/* + Notwendiges aus if_tun.h, da es aber bei 2.2.x-Style noch kein if_tun.h + im Kerneltree gibt, sind die Sachen hier zusaetzlich mit drin. Wird das + if_tun.h trotz des Kernel-Versionschecks nicht gefunden, dann das Include + fuer if_tun.h einfach auskommentieren. + + Alles was eigentlich der Kernel schon definieren sollte pruefen wir, falls + das #include fuer if_tun.h fehlt, dann definieren wir die Werte selbst. + Eventuell ist fuer alte Kernel auch das TUN-Device anzupassen ! +*/ + +#ifndef IFF_TUN +#define IFF_TUN 0x0001 +#endif + +#ifndef IFF_TAP +#define IFF_TAP 0x0002 +#endif + +#ifndef IFF_NO_PI +#define IFF_NO_PI 0x1000 +#endif + +#ifndef TUNSETIFF +#define TUNSETIFF (('T'<< 8) | 202) +#endif + +/* unser bevorzugtes TUN-Device */ +#define IFIP "/dev/net/tun" + +/* Data type definitions --------------------------------------- */ + +struct kip +{ + BOOLEAN if_available; + BOOLEAN if_active; + int if_style; + int if_fd; + ipaddr kernel_ip; + UBYTE maskbits; + ULONG bytes_tx; + ULONG bytes_rx; +}; + +/* End of os/linux/kernelip.h */ diff --git a/os/linux/l1attach.c b/os/linux/l1attach.c new file mode 100755 index 0000000..1065ca9 --- /dev/null +++ b/os/linux/l1attach.c @@ -0,0 +1,1086 @@ +#include "tnn.h" + +static ULONG token_sent = 0L; + +/* Pruefen, ob KissType in der TBL gesetzt ist. */ +static BOOLEAN SearchKissType(UWORD Interface) +{ + register int i; + + /* Alle Ports durchgehen. */ + for (i = 0; i < L1PNUM; ++i) + /* KissType gleich. */ + if (l1port[i].kisstype == Interface) + /* Ja. */ + return(TRUE); + + /* Nein, */ + return(FALSE); +} + +#define ATT_PORT 1 +#define ATT_KISSTYPE 2 +#define ATT_SPEED 3 +#define ATT_DEVICE 4 + +ATTPRT attprt[] = { + {"PORT", ATT_PORT }, + {"KTYP", ATT_KISSTYPE }, + {"SPEED", ATT_SPEED }, + {"DEVICE", ATT_DEVICE }, + {NULL, 0 } +}; + +ATTTYP attyp[] = { + {"KISS", KISS_NORMAL }, + {"SMACK", KISS_SMACK }, + {"RMNC", KISS_RMNC }, + {"TOKENRING", KISS_TOK }, + {"VANESSA", KISS_VAN }, + {"SCC", KISS_SCC }, + {"TF", KISS_TF }, + {"IPX", KISS_IPX }, + {"AX25IP", KISS_AXIP }, + {"LOOP", KISS_LOOP }, + {"KAX25", KISS_KAX25 }, + {"KAX25KJD", KISS_KAX25KJD }, + {"6PACK", KISS_6PACK }, +#ifdef L1TELNET + {"TELNET", KISS_TELNET }, +#endif /* L1TELNET */ +#ifdef L1HTTPD + {"HTTPD", KISS_HTTPD }, +#endif /* L1HTTPD */ +#ifdef L1IPCONV + {"IPCONV", KISS_IPCONV }, +#endif /* L1IPCONV */ +#ifdef L1IRC + {"IRC", KISS_IRC }, +#endif /* L1IRC */ + {NULL, 0 } +}; + +#define ATT_NO_OPTION 0 +#define ATT_POR_BUSY 1 +#define ATT_INV_PORT 2 +#define ATT_INV_TYP 3 +#define ATT_KIS_BUSY 4 +#define ATT_SPE_BUSY 5 +#define ATT_INV_OPTION 6 +#define ATT_INV_UDP 7 +#define ATT_INV_TCP 8 + +static const char *errormsg[] = +{ + "No Option." + ,"Port is busy." + ,"Invalid Port." + ,"Invalid KissType." + ,"Kisstype is busy." + ,"Invalid Speed." + ,"Invalid Option." + ,"Invalid UDP-Port." + ,"Invalid TCP-Port." +}; + +/* KissType setzen. */ +int SetKissType(WORD Interface, int port) +{ + switch (Interface) + { + case KISS_NORMAL: + case KISS_SMACK: + case KISS_RMNC: + case KISS_TOK: + return(Interface); + + break; +#ifdef VANESSA + case KISS_VAN: + /* Testen ob es ueberhaupt eine Vanessa gibt. */ + if (!van_test(port)) + return(KISS_NIX); + + break; +#endif + case KISS_SCC: + case KISS_TF: + case KISS_KAX25: + case KISS_KAX25KJD: + case KISS_6PACK: + return(Interface); + + break; + + /* Pruefe auf doppel-Eintraege! */ + case KISS_IPX: + case KISS_AXIP: + case KISS_LOOP: +#ifdef L1TELNET + case KISS_TELNET: +#endif /* L1TELNET */ +#ifdef L1HTTPD + case KISS_HTTPD: +#endif /* L1HTTPD */ +#ifdef L1IPCONV + case KISS_IPCONV: +#endif /* L1IPCONV */ +#ifdef L1IRC + case KISS_IRC: +#endif /* L1IRC */ + /* KissType schon gesetzt? */ + if (!SearchKissType(Interface)) + /* Nein, dann jetzt setzen. */ + return(Interface); + /* KissType existiert schon. */ + else + /* nicht setzen. */ + return(KISS_NIX); + + break; + + /* Unbekanntes KissType. */ + default: + /* nicht setzen. */ + return(KISS_NIX); + + break; + } + + return(KISS_NIX); +} + +/* Baudrate setzen. */ +int SetSpeed(char *speed, UWORD KissType) +{ + int Speed = EOF; + + /* Baudrate holen. */ + if ((sscanf(speed, "%d", &Speed) != 1)) + /* Fehler, abbruch. */ + return(EOF); + + /* Geschwindigkeit fuer Tokenring-Port */ + if (KissType == KISS_TOK) + /* Tokenring setzen. */ + tkcom = 1; + + switch(Speed) + { + case 0: + return(FALSE); + + case 9600: + if (KissType == KISS_TOK) + tkbaud = 96; + + return(B9600); + + case 19200: + if (KissType == KISS_TOK) + tkbaud = 192; + + return(B19200); + + case 38400: + if (KissType == KISS_TOK) + tkbaud = 384; + + return(B38400); + + case 57600: + if (KissType == KISS_TOK) + tkbaud = 576; + +#ifdef B57600 + return(B57600); +#else + return(B38400); +#endif + + case 115200: + if (KissType == KISS_TOK) + tkbaud = 1152; + +#ifdef B115200 + return(B115200); +#else + return(B38400); +#endif + + case 230400: + if (KissType == KISS_TOK) + tkbaud = 2304; + +#ifdef B230400 + return(B230400); +#else + return(B38400); +#endif + + case 460800: + if (KissType == KISS_TOK) + tkbaud = 4608; + +#ifdef B460800 + return(B460800); +#else + return(B38400); +#endif + + /* unbekannte Geschwindigkeiten */ + default: + return(EOF); + } + + return(EOF); +} + +/* Baudrateflags setzen. */ +int SetSpeedflag(char *speed) +{ + int Speed = EOF; + + /* Baudrate holen. */ + if ((sscanf(speed, "%d", &Speed) != 1)) + /* Fehler, abbruch. */ + return(EOF); + + switch(Speed) + { + + case 57600: + return(ASYNC_SPD_HI); + + case 115200: + return(ASYNC_SPD_VHI); + + case 230400: + return(ASYNC_SPD_SHI); + + case 460800: + return(ASYNC_SPD_WARP); + + /* unbekannte Geschwindigkeiten */ + default: + return(FALSE); + } + + return(FALSE); +} + +/* Buffer "clipoi" einlesen. */ +char *ReadBuf(char *cBuf, BOOLEAN flag) +{ + register int i; + skipsp(&clicnt, &clipoi); + + /* Frischer Buffer */ + memset(cBuf, 0, sizeof(cBuf)); + + for (i = 0; i < MAXPATH; ++i) + { + if ((!clicnt) || (*clipoi == ' ')) + break; + + if (*clipoi == '=') + { + clicnt--; + clipoi++; + break; + } + clicnt--; + /* TRUE, In Grossbuchstaben umwandeln. */ + if (flag) + cBuf[i] = toupper(*clipoi++); + /* FALSE. */ + else + /* keine Aenderungen durchfuehren. */ + cBuf[i] = (*clipoi++); + } + + cBuf[i] = 0; + + return(cBuf); +} + +/* Eine Modifizierte Funktion Init_kisslink(); */ +BOOLEAN InitKissLink(UWORD port) +{ + DEVICE *l1att = &l1port[l1ptab[port]]; + int Error = 0; + + switch(l1att->kisstype) + { + case KISS_TOK: + /* Nur die 1. Schnittstelle Initialisieren. */ + if (tokenring_ports > 1) + return(FALSE); + + /* Alle Device haben hier nix zu suchen. */ +#ifdef VANESSA + case KISS_VAN: +#endif + case KISS_SCC: + case KISS_IPX: + case KISS_AXIP: + case KISS_LOOP: + case KISS_KAX25: + case KISS_KAX25KJD: +#ifdef L1TELNET + case KISS_TELNET: +#endif /* L1TELNET */ +#ifdef L1HTTPD + case KISS_HTTPD: +#endif /* L1HTTPD */ +#ifdef L1IPCONV + case KISS_IPCONV: +#endif /* L1IPCONV */ +#ifdef L1IRC + case KISS_IRC: +#endif /* L1IRC */ + /* und weg hier. */ + return(FALSE); + +#ifdef SIXPACK + case KISS_6PACK: + /* 6PACK-Ring ist schon Initialisiert. */ + if (iDescriptor) + /* Schliesse schnittstelle. */ + close(iDescriptor); + + /* Neue Konfiguration Initialisieren. */ + Sixpack_l1init(); + + return(FALSE); +#endif /* SIXPACK */ + } + +/************************************************************************/ +/* */ +/* Port oeffnen. */ +/* */ +/************************************************************************/ + l1att->kisslink = open(l1att->device, l1att->speed); + + if (l1att->kisslink == KISS_NIX) + { + Error = 1; + printf("Error: can't open device %s\n", l1att->device); + printf(" (%s)\n", strerror(errno)); + } + +/************************************************************************/ +/* */ +/* Serielle Schnittstelle auf neue Parameter einstellen, KISS-Empfang */ +/* initialisieren */ +/* */ +/************************************************************************/ + if (!Error) + { + l1att->rx_state = ST_BEGIN; + l1att->rx_port = 0; + l1att->tx_port = 0; + + if (l1att->kisstype == KISS_TF) + tf_set_kiss(l1att); + } + +/************************************************************************/ +/* */ +/* Wenn kein Fehler aufgetreten ist, dann fuer gewisse Interfaces die */ +/* ersten Aktionen ausfuehren. */ +/* */ +/* Tokenring : Token senden */ +/* 6PACK : TNC-Zaehlung anstossen */ +/* */ +/************************************************************************/ + + if (!Error) + { + /* Tokenring */ + if (l1att->kisstype == KISS_TOK) + { + send_kisscmd(0xff, CMD_TOKEN, 0); /* Token senden */ + token_sent = tic10; /* Zeitpunkt der Sendung */ + tokenflag = FALSE; /* Token unterwegs */ + } + return(FALSE); + } + + if (Error) + { + /* Handle schliessen. */ + close(l1att->kisslink); + return(TRUE); + } + + /* Initialisierung war erfolgreich. */ + return(FALSE); +} + +/* Port setzen. */ +void ccpattach(void) +{ + MBHEAD *mbp; + ATTPRT *attcmd; + ATTTYP *attype; + char Buf[MAXPATH + 1]; + char *cBuf = Buf; + int port = EOF; + int error = ATT_NO_OPTION; + WORD found; + WORD att_kisstype = EOF; + WORD att_speed = EOF; + WORD att_speedflag= EOF; + char att_device[MAXPATH + 1]; + + /* Sysop will aendern und noch was in der Zeile da ? */ + if (issyso() && skipsp(&clicnt, &clipoi)) + { + memset(att_device, 0, sizeof(att_device)); + do + { + /* Gibt es einen Fehler? */ + if (error != ATT_NO_OPTION) + /* Abbruch. */ + break; + + /* Option einlesen. */ + cBuf = ReadBuf(cBuf, TRUE); + + /* Option in TBL suchen. */ + for (attcmd = attprt, found = 0; !found && attcmd->attstr != NULL; ++attcmd) + { + if (!strncmp(attcmd->attstr, cBuf, strlen(cBuf))) + /* Option gefunden. */ + found = attcmd->attnum; + } + + switch (found) + { + /* PORT. */ + case ATT_PORT: + skipsp(&clicnt, &clipoi); + + /* Port einlesen/pruefen. */ + if ((port = (nxtnum(&clicnt, &clipoi) & 0x7F)) < L2PNUM) + { + /* uninitialisierter Port */ + if (l1ptab[port] != -1) + /* Port ist belegt. */ + error = ATT_POR_BUSY; + } + /* Portangabe liegt ausserhalb vom Grenzbereichs. */ + else + /* Markiere Fehlermeldung. */ + error = ATT_INV_PORT; + + break; + + /* KISSTYPE setzen. */ + case ATT_KISSTYPE: + /* KissType einlesen. */ + cBuf = ReadBuf(cBuf, TRUE); + + /* KissType in TBL suchen. */ + for (attype = attyp, found = EOF; found == EOF && attype->attstr != NULL; ++attype) + { + if (!strncmp(attype->attstr, cBuf, strlen(cBuf))) + /* KissType gefunden. */ + found = attype->attnum; + } + + /* Unbekannte KissType. */ + if (found == EOF ) + { + /* Markiere Fehlermeldung. */ + error = ATT_INV_TYP; + break; + } + + /* Kisstype setzen. */ + if ((att_kisstype = SetKissType(found, port)) == EOF) + /* EOF, Markiere Fehlermeldung. */ + error = ATT_KIS_BUSY; + + break; + + /* Baudrate setzen. */ + case ATT_SPEED: + /* Baudrate einlesen. */ + cBuf = ReadBuf(cBuf, TRUE); + + /* Baudrate setzen. */ + if ((att_speed = SetSpeed(cBuf, att_kisstype)) == EOF) + /* EOF, Markiere Fehlermeldung. */ + error = ATT_SPE_BUSY; + + /* Baudrateflag setzen. */ + att_speedflag = SetSpeedflag(cBuf); + + break; + + /* Device setzen. */ + case ATT_DEVICE: + /* Device einlesen. */ + cBuf = ReadBuf(cBuf, FALSE); + + switch(att_kisstype) + { + case KISS_NORMAL: + case KISS_SMACK: + case KISS_RMNC: + case KISS_TOK: +#ifdef VANESSA + case KISS_VAN: +#endif + case KISS_SCC: + case KISS_TF: + case KISS_KAX25: + case KISS_KAX25KJD: + case KISS_6PACK: + strncpy(att_device, cBuf, MAXPATH); + break; + + /* UDP-Port pruefen. */ + case KISS_AXIP: + if (atoi(cBuf) < 65536) + { + strncpy(att_device, cBuf, MAXPATH); + /* Neuen UDP-Port markieren. */ + my_udp = htons((unsigned short)atoi(cBuf)); + } + /* UDP-Port liegt ausserhalb vom Grenzbereich. */ + else + /* Markiere Fehlermeldung. */ + error = ATT_INV_UDP; + + break; + +#ifdef L1TELNET + /* TCP-Port pruefen. */ + case KISS_TELNET: + if (atoi(cBuf) < 65536) + strncpy(att_device, cBuf, MAXPATH); + /* UDP-Port liegt ausserhalb vom Grenzbereich. */ + else + /* Markiere Fehlermeldung. */ + error = ATT_INV_TCP; + + break; +#endif /* L1TELNET */ +#ifdef L1HTTPD + /* TCP-Port pruefen. */ + case KISS_HTTPD: + if (atoi(cBuf) < 65536) + strncpy(att_device, cBuf, MAXPATH); + /* UDP-Port liegt ausserhalb vom Grenzbereich. */ + else + /* Markiere Fehlermeldung. */ + error = ATT_INV_TCP; + + break; +#endif /* L1HTTPD */ +#ifdef L1IPCONV + /* TCP-Port pruefen. */ + case KISS_IPCONV: + if (atoi(cBuf) < 65536) + strncpy(att_device, cBuf, MAXPATH); + /* UDP-Port liegt ausserhalb vom Grenzbereich. */ + else + /* Markiere Fehlermeldung. */ + error = ATT_INV_TCP; + + break; +#endif /* L1IPCONV */ +#ifdef L1IRC + /* TCP-Port pruefen. */ + case KISS_IRC: + if (atoi(cBuf) < 65536) + strncpy(att_device, cBuf, MAXPATH); + /* UDP-Port liegt ausserhalb vom Grenzbereich. */ + else + /* Markiere Fehlermeldung. */ + error = ATT_INV_TCP; + + break; +#endif /* L1IRC */ + } + + case KISS_LOOP : + break; + + default: + /* Unbekannte Option. */ + error = ATT_INV_OPTION; + break; + } + } + /* Gibt es noch Zeichen. */ + while (clicnt > 0); + } + /* Kein Sysop. */ + else + { + if (!issyso()) + invmsg(); + else + { + DEVICE *l1att; + + mbp = putals("ATTACH-TABLES:\rPort--KISSTYPE---DEVICE\r"); + + /* alle Ports durchgehen */ + for (port = 0; port < L2PNUM; ++port) + { + /* uninitialisierter Port */ + if (l1ptab[port] == -1) + { + putprintf(mbp, "%2d Port deaktiv.\r", port); + continue; + } + + l1att = &l1port[l1ptab[port]]; + + for (attype = attyp; attype->attstr != NULL; ++attype) + if (l1att->kisstype == attype->attnum) + break; + + putprintf(mbp, "%2d %-10s " + , port + , attype->attstr); + + switch(l1att->kisstype) + { + case KISS_AXIP: + putprintf(mbp, "%u" ,ntohs(my_udp)); + break; + +#ifdef L1TELNET + case KISS_TELNET: + putprintf(mbp, "%d" , atoi(l1att->device)); + break; +#endif /* L1TELNET */ +#ifdef L1HTTPD + case KISS_HTTPD: + putprintf(mbp, "%d" , atoi(l1att->device)); + break; +#endif /* L1HTTPD */ +#ifdef L1IPCONV + case KISS_IPCONV: + putprintf(mbp, "%d" , atoi(l1att->device)); + break; +#endif /* L1IPCONV */ +#ifdef L1IRC + case KISS_IRC: + putprintf(mbp, "%d" , atoi(l1att->device)); + break; +#endif /* L1IRC */ + + default: + putprintf(mbp, "%-5s" ,l1att->device); + break; + } + putstr("\r", mbp); + + + } + /* und ab geht die Post. */ + prompt(mbp); + seteom(mbp); + } + return; + } + + /* Kisstype Tokenring. */ + if ( (att_kisstype == KISS_TOK) + /* Ja, dann zaehlen wir. */ + &&(++tokenring_ports)) + { + /* Sonderbehandlung fuer Tokenring-Ports */ + if (att_kisstype == KISS_TOK) + { + l1ptab[port] = 0; + l2ptab[max_device] = -1; + } + } + /* Kein Tokenring. */ +#ifdef SIXPACK + /* Sonderbehandlung fuer 6PACK-Ports */ + if ( (att_kisstype == KISS_6PACK) + &&(++sixpack_ports)) + { + /* Sonderbehandlung fuer Tokenring-Ports */ + if (att_kisstype == KISS_6PACK) + { + l1ptab[port] = max_device; + l2ptab[max_device] = -1; + } + } +#endif + + /* Sind alle Einstellungen korrekt? */ + if ( (port == EOF) + /* Pruefen ob Kisstype */ + ||(att_kisstype == EOF) + /* und Device korrekt gesetzt sind. */ + ||((att_device[0] == FALSE) + &&(att_kisstype != KISS_AXIP) + &&(att_kisstype != KISS_LOOP))) + { + mbp = getmbp(); + + /* Fehlermeldung ausgeben mit Syntax. */ + putprintf(mbp, "%s\r", errormsg[error]); + putstr("Syntax: ATT PORT=X KTYP=KISSTYPE SPEED=19200 DEVICE=SCHNITTSTELLE\r", mbp); + prompt(mbp); + seteom(mbp); + return; + } + /* Kisstype/Device sind OK. */ + else + { + /* Port auf aktiv stellen. */ + l1port[++max_device].port_active = TRUE; + /* Kisstype setzen. */ + l1port[max_device].kisstype = att_kisstype; + /* Baudrateflag setzen. */ + l1port[max_device].speedflag = att_speedflag; + /* Baudrate setzen. */ + l1port[max_device].speed = att_speed; + /* Device setzen. */ + strcpy(l1port[max_device].device, att_device); + + /* Port markieren. */ + l1ptab[port] = max_device; + l2ptab[max_device] = port; + + /* Zaehler L1Ports. */ + ++used_l1ports; + /* Kiss aktivieren. */ + kiss_active = TRUE; + + /* Serielle Schnittstellen initialisieren */ + if (InitKissLink((UWORD)port)) + { + /* Es gab ein Fehler bei der Initialisierung. */ + /* Alle Werte zuruecksetzen. */ + l1port[max_device].port_active = FALSE; + l1port[max_device].kisstype = KISS_NIX; + l1port[max_device].speedflag = 0; + l1port[max_device].speed = 0; + l1port[max_device].device[0] = 0; + + l1ptab[port] = EOF; + l2ptab[port] = EOF; + --max_device; + --used_l1ports; + + mbp = getmbp(); + + putstr("Error with initializing the interface\r", mbp); + prompt(mbp); + seteom(mbp); + return; + } + } + + mbp = getmbp(); + + putprintf(mbp, "Port %d Attached.\r", port); + prompt(mbp); + seteom(mbp); +} + +/* Port entladen. */ +void ccpdetach(void) +{ + MBHEAD *mbp; + DEVICE *l1att; + int port; + + /* Sysop will aendern und noch was in der Zeile da ? */ + if (issyso() && skipsp(&clicnt, &clipoi)) + { + /* Port einlesen/pruefen. */ + if ((port = (nxtnum(&clicnt, &clipoi) & 0x7F)) < L2PNUM) + { + /* uninitialisierter Port */ + if (l1ptab[port] == EOF) + { + mbp = getmbp(); + putprintf(mbp, "Port %d is no activ.\r", port); + prompt(mbp); + seteom(mbp); + return; + } + /* Port eingeschaltet. */ + if (portenabled(port)) + /* Port runterfahren. */ + l1detach(port); + + l1att = &l1port[l1ptab[port]]; + /* Schliesse Schnittstelle. */ + switch(l1att->kisstype) + { + case KISS_TOK: + /* Schliesse Schnittstelle. */ + close(l1att->kisslink); + + /* Port's zuruecksetzen. */ + tokenring_ports = 0; + break; + + + case KISS_NORMAL: + case KISS_SMACK: + case KISS_RMNC: + + + case KISS_TF: + close(l1att->kisslink); + break; + +#ifdef SIXPACK + case KISS_6PACK: + /* Schnittstelle schliessen. */ + Sixpack_l1exit(); + + /* Port's zuruecksetzen. */ + sixpack_ports = 0; +#endif /* SIXPACK */ + + case KISS_AXIP: + case KISS_KAX25: + case KISS_KAX25KJD: +#ifdef L1TELNET + case KISS_TELNET: +#endif /* L1TELNET */ +#ifdef L1HTTPD + case KISS_HTTPD: +#endif /* L1HTTPD */ +#ifdef L1IPCONV + case KISS_IPCONV: +#endif /* L1IPCONV */ +#ifdef L1IRC + case KISS_IRC: +#endif /* L1IRC */ + close(l1att->kisslink); + break; + + default: + break; + + } + + /* Defaultwerte setzen. */ + l1att->port_active = FALSE; + l1att->kisstype = KISS_NIX; + l1att->speed = 0; + l1att->device[0] = 0; + + l1ptab[port] = EOF; + l2ptab[port] = EOF; + + mbp = getmbp(); + putprintf(mbp, "Port %d Detach.\r", port); + prompt(mbp); + seteom(mbp); + return; + } + /* Ungueltiger Port. */ + else + { + mbp = getmbp(); + putstr("Invalid Port.\r", mbp); + prompt(mbp); + seteom(mbp); + return; + } + } + else + { /* Sysop ? */ + if (!issyso()) + invmsg(); + /* Portangabe fehlt.*/ + else + { + mbp = getmbp(); + + putstr("Port failed.\r", mbp); + prompt(mbp); + seteom(mbp); + } + } +} +/* Speed einlesen fuer tnb. */ +int ReadSpeed(unsigned int Speed) +{ + switch(Speed) + { + case 0: + return(FALSE); + + case B9600: + return(9600); + + case B19200: + return(19200); + + case B38400: + return(38400); + + case B57600: +#ifdef B57600 + return(57600); +#else + return(38400); +#endif + +#ifdef B115200 + case B115200: + return(115200); +#else + return(38400); +#endif + case 230400: +#ifdef B230400 + return(230400); +#else + return(38400); +#endif + + case 460800: +#ifdef B460800 + return(460800); +#else + return(38400); +#endif + + /* unbekannte Geschwindigkeiten */ + default: + return(FALSE); + } + return(FALSE); +} + +/* Attach-Eintraege in tnb sichern. */ +void dump_attach(MBHEAD *mbp) +{ + DEVICE *l1pp; + int port; + + putstr(";\r; Attach (l1-Level)\r;\r", mbp); + + /* alle Ports durchgehen */ + for (port = 0; port < L2PNUM; ++port) + { + /* uninitialisierter Port */ + if (l1ptab[port] == -1) + continue; + + l1pp = &l1port[l1ptab[port]]; + + putprintf(mbp, "ATTACH PORT=%d ", port); + + switch(l1pp->kisstype) + { + case KISS_NORMAL: + putprintf(mbp, "KTYP=KISS SPEED=%d DEVICE=%s" + , ReadSpeed(l1pp->speed) + , l1pp->device); + break; + + case KISS_SMACK: + putprintf(mbp, "KTYP=SMACK SPEED=%d DEVICE=%s" + , ReadSpeed(l1pp->speed) + , l1pp->device); + break; + + case KISS_RMNC: + putprintf(mbp, "KTYP=RMNC SPEED=%d DEVICE=%s" + , ReadSpeed(l1pp->speed) + , l1pp->device); + break; + + case KISS_TOK: + putprintf(mbp, "KTYP=TOKENRING SPEED=%d DEVICE=%s" + , ReadSpeed(l1pp->speed) + , l1pp->device); + break; + + case KISS_SCC: + putprintf(mbp, "KTYP=SCC DEVIVE=%s" + , l1pp->device); + break; + + case KISS_TF: + putprintf(mbp, "KTYP=TF SPEED=%d DEVICE=%s" + , ReadSpeed(l1pp->speed) + , l1pp->device); + break; + + case KISS_IPX: + putprintf(mbp, "KTYP=IPX"); + break; + + case KISS_AXIP: + putstr("KTYP=AX25IP ", mbp); + if (l1pp->device) + putprintf(mbp, "DEVICE=%d" + , ntohs(my_udp)); + else + putstr("DEVICE=", mbp); + break; + + case KISS_LOOP: + putprintf(mbp, "KTYP=LOOP"); + break; + + case KISS_KAX25: + putprintf(mbp, "KTYP=KAX25 DEVICE=%s" + , l1pp->device); + break; + + case KISS_KAX25KJD: + putprintf(mbp, "KTYP=KAX25DJK DEVICE=%s" + , l1pp->device); + break; + + case KISS_6PACK: + putprintf(mbp, "KTYP=6PACK SPEED=%d DEVICE=%s" + , ReadSpeed(l1pp->speed) + , l1pp->device); + break; + +#ifdef L1TELNET + case KISS_TELNET: + putprintf(mbp, "KTYP=TELNET DEVICE=%d" + , atoi(l1pp->device)); + break; +#endif /* L1TELNET */ +#ifdef L1HTTPD + case KISS_HTTPD: + putprintf(mbp, "KTYP=HTTPD DEVICE=%d" + , atoi(l1pp->device)); + break; +#endif /* L1HTTPD */ +#ifdef L1IPCONV + case KISS_IPCONV: + putprintf(mbp, "KTYP=IPCONV DEVICE=%d" + , atoi(l1pp->device)); + break; +#endif /* L1IPCONV */ +#ifdef L1IRC + case KISS_IRC: + putprintf(mbp, "KTYP=IRC DEVICE=%d" + , atoi(l1pp->device)); + break; +#endif /* L1IRC */ + } + putstr("\n", mbp); + } +} + +/* End of os/win32/l1attach.c */ diff --git a/os/linux/l1linux.c b/os/linux/l1linux.c new file mode 100755 index 0000000..334568d --- /dev/null +++ b/os/linux/l1linux.c @@ -0,0 +1,2533 @@ +/************************************************************************/ +/* */ +/* ***** ***** */ +/* ***** ***** */ +/* ***** ***** */ +/* ***** ***** */ +/* *************** *************** */ +/* ***************** ***************** */ +/* *************** *************** */ +/* ***** ***** TheNetNode */ +/* ***** ***** Portable */ +/* ***** ***** Network */ +/* ***** ***** Software */ +/* */ +/* File os/linux/l1linux.c (maintained by: DF6LN) */ +/* */ +/* This file is part of "TheNetNode" - Software Package */ +/* */ +/* Copyright (C) 1998 - 2008 NORD>tnn_lockfile) != '\0') + unlink(l1pp->tnn_lockfile); + if (i == max_device) + break; + } + +/************************************************************************/ +/* */ +/* Lockfiles schreiben und Kiss-Ports initialisieren. */ +/* */ +/************************************************************************/ + + /* alle L1-ports durch gehen */ + for (i = 0; i < L1PNUM; ++i) + { + l1pp = &l1port[i]; + +/************************************************************************/ +/* */ +/* Wenn Vanessa, naechsten Port. */ +/* */ +/************************************************************************/ + +#ifdef VANESSA + if (stricmp("VANESSA", l1pp->device) == 0) + { + check_van = TRUE; + l1pp->kisstype = KISS_VAN; /* falls Kisstype nicht angegeben */ + if (i == max_device) + break; + else + continue; + } +#endif + +/************************************************************************/ +/* */ +/* Wenn IPX, auch naechsten Port. */ +/* */ +/************************************************************************/ + +#ifdef AX_IPX + if (stricmp("IPX", l1pp->device) == 0) + { + l1pp->kisstype = KISS_IPX; /* falls Kisstype nicht angegeben */ + l1pp->port_active = TRUE; + if (i == max_device) + break; + else + continue; + } +#endif + +/************************************************************************/ +/* */ +/* Wenn AX25IP, auch naechsten Port. */ +/* */ +/************************************************************************/ + +#ifdef AX25IP + if (stricmp("AX25IP", l1pp->device) == 0) + { + l1pp->kisstype = KISS_AXIP; /* falls Kisstype nicht angegeben */ + l1pp->port_active = TRUE; + if (i == max_device) + break; + else + continue; + } +#endif + +/************************************************************************/ +/* */ +/* Kernel-AX25 hat hier auch nix zu suchen */ +/* */ +/************************************************************************/ +#ifdef KERNELIF + if ( (l1pp->kisstype == KISS_KAX25) + || (l1pp->kisstype == KISS_KAX25KJD)) + { + l1pp->port_active = TRUE; + if (i == max_device) + break; + else + continue; + } +#endif + +/************************************************************************/ +/* */ +/* 6PACK hat hier auch nix zu suchen */ +/* */ +/************************************************************************/ +#ifdef SIXPACK + if (l1pp->kisstype == KISS_6PACK) + { + l1pp->port_active = TRUE; + if (i == max_device) + break; + else + continue; + } +#endif + +#ifdef L1TELNET +/************************************************************************/ +/* */ +/* Wenn TELNET, auch naechsten Port. */ +/* */ +/************************************************************************/ + + if (l1pp->kisstype == KISS_TELNET) + { + int TCPPort = atoi(l1pp->device); + + if ( (TCPPort < 1) + ||(TCPPort > 65536)) + { + printf("Warnung: Alte Syntax device %s ungueltig!!!\n" + " Neue Syntax device 1..65535.\n" + "TCP-Port wird auf default 10023 gesetzt.\n" + "Aenderung in der TNN.INI vornehmen!\n", l1pp->device); + strncpy(l1pp->device, "10023", MAXPATH); + } + else + { + l1pp->port_active = TRUE; + } + + if (i == max_device) + break; + else + continue; + } +#endif /* L1TELNET */ + +#ifdef L1HTTPD +/************************************************************************/ +/* */ +/* Wenn HTTPD, auch naechsten Port. */ +/* */ +/************************************************************************/ + + if (l1pp->kisstype == KISS_HTTPD) + { + int TCPPort = atoi(l1pp->device); + + if ( (TCPPort < 1) + ||(TCPPort > 65536)) + { + printf("Warnung: Alte Syntax device %s ungueltig!!!\n" + " Neue Syntax device 1..65535.\n" + "TCP-Port wird auf default 18080 gesetzt.\n" + "Aenderung in der TNN.INI vornehmen!\n", l1pp->device); + strncpy(l1pp->device, "18080", MAXPATH); + } + else + l1pp->port_active = TRUE; + + if (i == max_device) + break; + else + continue; + } +#endif /* L1HTTPD */ + +#ifdef L1IPCONV +/************************************************************************/ +/* */ +/* Wenn IPCONV, auch naechsten Port. */ +/* */ +/************************************************************************/ + + if (l1pp->kisstype == KISS_IPCONV) + { + int TCPPort = atoi(l1pp->device); + + if ( (TCPPort < 1) + ||(TCPPort > 65536)) + { + printf("Warnung: Alte Syntax device %s ungueltig!!!\n" + " Neue Syntax device 1..65535.\n" + "TCP-Port wird auf default 13600 gesetzt.\n" + "Aenderung in der TNN.INI vornehmen!\n", l1pp->device); + strncpy(l1pp->device, "13600", MAXPATH); + } + else + l1pp->port_active = TRUE; + + if (i == max_device) + break; + else + continue; + } +#endif /* L1IPCONV */ + +#ifdef L1IRC +/************************************************************************/ +/* */ +/* Wenn IRC, auch naechsten Port. */ +/* */ +/************************************************************************/ + + if (l1pp->kisstype == KISS_IRC) + { + int TCPPort = atoi(l1pp->device); + + if ( (TCPPort < 1) + ||(TCPPort > 65536)) + { + printf("Warnung: Alte Syntax device %s ungueltig!!!\n" + " Neue Syntax device 1..65535.\n" + "TCP-Port wird auf default 13600 gesetzt.\n" + "Aenderung in der TNN.INI vornehmen!\n", l1pp->device); + strncpy(l1pp->device, "13600", MAXPATH); + } + else + l1pp->port_active = TRUE; + + if (i == max_device) + break; + else + continue; + } +#endif /* L1IRC */ + +/************************************************************************/ +/* */ +/* Zuerst Lock-File schreiben. */ +/* */ +/************************************************************************/ + l1pp->lock = -1; + if (*(l1pp->tnn_lockfile) != '\0') + { + l1pp->lock = open(l1pp->tnn_lockfile, O_CREAT|O_EXCL, 0666); + if (l1pp->lock == -1) + { + fehler = 1; + printf("Error: device %s is locked by other user;\n" + " or unable to create lockfile %s\n", + l1pp->device, l1pp->tnn_lockfile); + printf("(%s)\n", strerror(errno)); + } + else + { + close(l1pp->lock); + tmp_lockfile = fopen(l1pp->tnn_lockfile, "w"); + fprintf(tmp_lockfile, "%10d\n", mypid); + fclose(tmp_lockfile); + } + } + +/************************************************************************/ +/* */ +/* Port oeffnen. */ +/* */ +/************************************************************************/ + + if (fehler == 0) /* nur wenn Lock-File geschrieben */ + { /* wurde oder nicht gefordert war */ + l1pp->kisslink = open(l1pp->device, O_RDWR); + if (l1pp->kisslink == -1) + { + fehler = 2; + printf("Error: can't open device %s\n", l1pp->device); + printf(" (%s)\n", strerror(errno)); + } + } + +/************************************************************************/ +/* */ +/* Alte Einstellungen der seriellen Schnittstelle merken */ +/* */ +/************************************************************************/ + if (fehler == 0) /* nur wenn Port geoeffnet! */ + { + tcgetattr(l1pp->kisslink, &(l1pp->org_termios)); + if (l1pp->speed == B38400) /* >= 38400 Bd */ + { + if (ioctl(l1pp->kisslink, TIOCGSERIAL, &ser_io) < 0) + { + fehler = 3; + printf("Error: can't get actual settings for device %s\n", l1pp->device); + printf(" (%s)\n", strerror(errno)); + } + } + } + +/************************************************************************/ +/* */ +/* Neue Einstellungen der seriellen Schnittstelle setzen */ +/* */ +/************************************************************************/ + + if (fehler == 0) + { + l1pp->wrk_termios = l1pp->org_termios; + l1pp->wrk_termios.c_cc[VTIME] = 0; /* empfangene Daten */ + l1pp->wrk_termios.c_cc[VMIN] = 0; /* sofort abliefern */ + l1pp->wrk_termios.c_iflag = IGNBRK; /* BREAK ignorieren */ + l1pp->wrk_termios.c_oflag = 0; /* keine Delays oder */ + l1pp->wrk_termios.c_lflag = 0; /* Sonderbehandlungen */ + + l1pp->wrk_termios.c_cflag |= (CS8 /* 8 Bit */ + |CREAD /* RX ein */ + |CLOCAL); /* kein Handshake */ + l1pp->wrk_termios.c_cflag &= ~(CSTOPB /* 1 Stop-Bit */ + |PARENB /* ohne Paritaet */ + |HUPCL); /* kein Handshake */ + + /* TEST DG9OBU */ + /* pty's stellen wir auf non-blocking io */ + if (l1pp->speed == B0) + { + if ((flags = fcntl(l1pp->kisslink, F_GETFL, 0)) < 0) + printf("Error: can't read pty's current flags !!!\n"); + + if (fcntl(l1pp->kisslink, F_SETFL, (flags | O_NONBLOCK)) < 0) + printf("Error: can't set pty's nonblocking-flag !!!\n"); + } + + if (l1pp->speed != B0) /* B0 -> pty soll ver- */ + { /* wendet werden */ + cfsetispeed(&(l1pp->wrk_termios), /* Empfangsparameter */ + l1pp->speed); /* setzen */ + cfsetospeed(&(l1pp->wrk_termios), /* Sendeparameter */ + l1pp->speed); /* setzen */ + + if (l1pp->speed == B38400) /* wenn >= 38400 Bd */ + { + ser_io.flags &= ~ASYNC_SPD_MASK; /* Speed-Flag -> 0 */ + ser_io.flags |= l1pp->speedflag; /* Speed-Flag setzen */ + + if (ioctl(l1pp->kisslink, TIOCSSERIAL, &ser_io) < 0) + { + fehler = 4; + printf("Error: can't set device settings on device %s\n", l1pp->device); + printf(" (%s)\n", strerror(errno)); + } + } + } + } + +/************************************************************************/ +/* */ +/* Serielle Schnittstelle auf neue Parameter einstellen, KISS-Empfang */ +/* initialisieren */ +/* */ +/************************************************************************/ + + if (fehler == 0) + { + tcsetattr(l1pp->kisslink, TCSADRAIN, &(l1pp->wrk_termios)); + l1pp->rx_state = ST_BEGIN; + l1pp->rx_port = 0; + l1pp->tx_port = 0; + l1pp->port_active = TRUE; + + if (l1pp->kisstype == KISS_TF) + tf_set_kiss(l1pp); + } + else + break; + if (i == max_device) + break; + } + +/************************************************************************/ +/* */ +/* Wenn kein Fehler aufgetreten ist, dann fuer gewisse Interfaces die */ +/* ersten Aktionen ausfuehren. */ +/* */ +/* Tokenring : Token senden */ +/* 6PACK : TNC-Zaehlung anstossen */ +/* */ +/************************************************************************/ + + if (fehler == 0) + { + /* Tokenring */ + if (l1port[0].kisstype == KISS_TOK) + { + send_kisscmd(0xff, CMD_TOKEN, 0); /* Token senden */ + token_sent = tic10; /* Zeitpunkt der Sendung */ + tokenflag = FALSE; /* Token unterwegs */ + } + return(FALSE); + } + +/************************************************************************/ +/* */ +/* Wenn bei einem Teil der Initialisierung ein Fehler aufgetreten ist, */ +/* muessen alle bisher vorgenommenen Parameteraenderungen der seriellen */ +/* Schnittstellen rueckgaengig gemacht werden. Ausserdem muessen alle */ +/* geoeffneten Files wieder geschlossen werden. */ +/* */ +/************************************************************************/ + + do + { + /* Port war schon offen, alte Einstellungen wiederherstellen */ + if ((fehler > 3) && (l1port[i].kisslink != -1)) + tcsetattr(l1port[i].kisslink, TCSADRAIN, &(l1port[i].org_termios)); + + /* Port war schon offen, aber noch nicht veraendert, nur schliessen */ + if ((fehler > 2) && (l1port[i].kisslink != -1)) + { + close(l1port[i].kisslink); + l1port[i].kisslink = -1; + } + + /* Port war nicht offen, aber es existiert ein Lockfile, schliessen */ + if ((fehler > 1) && (l1port[i].lock != -1)) + { + close(l1port[i].lock); + l1port[i].lock = -1; + } + + /* Lockfile loeschen */ + if (l1port[i].tnn_lockfile[0] != '\0') + { + unlink(l1port[i].tnn_lockfile); + l1port[i].tnn_lockfile[0] = '\0'; + } + + fehler = 4; /* beim naechsten Durchgang alles restaurieren */ + } while (--i >= 0); + + return(TRUE); +} + +/************************************************************************/ +/* */ +/* Serielle Schnittstellen wieder freigeben (fuer Programmende) */ +/* */ +/************************************************************************/ + +void exit_kisslink(void) +{ + register WORD i; + char buffer[] = { FEND, 0xFF }; + + for (i = 0; i < L1PNUM; ++i) + { + /* abgeschaltete Ports */ + if (!l1port[i].port_active) + continue; +#ifdef AX_IPX + /* AX_IPX */ + if (l1port[i].kisstype > KISS_IPX) + continue; +#endif +#ifdef KERNELIF + /* Kernel-AX.25 */ + if ( (l1port[i].kisstype == KISS_KAX25) + || (l1port[i].kisstype == KISS_KAX25KJD)) + continue; +#endif +#ifdef AX25IP + /* AX25IP */ + if (l1port[i].kisstype == KISS_AXIP) + continue; +#endif +#ifdef VANESSA + if (l1port[i].kisstype == KISS_VAN) + continue; +#endif +#ifdef SIXPACK + /* 6PACK */ + if (l1port[i].kisstype == KISS_6PACK) + continue; +#endif +#ifdef L1TELNET + /* TELNET-Server */ + if (l1port[i].kisstype == KISS_TELNET) + continue; +#endif /* L1TELNET */ +#ifdef L1HTTPD + /* HTTPD-Server */ + if (l1port[i].kisstype == KISS_HTTPD) + continue; +#endif /* L1HTTPD */ +#ifdef L1IPCONV + /* IPCONV-Server */ + if (l1port[i].kisstype == KISS_IPCONV) + continue; +#endif /* L1IPCONV */ +#ifdef L1IRC + /* IRC-Server */ + if (l1port[i].kisstype == KISS_IRC) + continue; +#endif /* L1IRC */ + + /* TNC mit TheFirmware */ + if (l1port[i].kisstype == KISS_TF) + { + /* KISS-Kommando senden (TNC-Reset) */ + write(l1port[i].kisslink, buffer, 2); + sleep(1); + } + + /* Alte Porteinstellungen wiederherstellen */ + tcsetattr(l1port[i].kisslink, TCSADRAIN, &(l1port[i].org_termios)); + /* Port schliessen */ + close(l1port[i].kisslink); + + /* Lockfile loeschen */ + if (*(l1port[i].tnn_lockfile) != '\0') + unlink(l1port[i].tnn_lockfile); + /* alle Devices bearbeitet ? */ + if (i == max_device) + break; + } + kiss_active = FALSE; +} + +/************************************************************************/ +/* */ +/* Level1 Ende, Ports schliessen und aufraeumen */ +/* */ +/************************************************************************/ + +void l1exit(void) +{ +#ifdef KERNELIF + /* Kernel-AX.25 */ + register unsigned int i; + + for (i = 0;i < L1PNUM; ++i) + if ( (l1port[i].kisstype == KISS_KAX25) + || (l1port[i].kisstype == KISS_KAX25KJD)) + ifax_close(&(l1port[i])); +#endif + /* KISS-Schnittstellen */ + if (kiss_active) + exit_kisslink(); +#ifdef VANESSA + /* Vanessa */ + vanessa_l1exit(); +#endif +#ifdef AX_IPX + /* AX25IPX */ + axipx_l1exit(); +#endif +#ifdef AX25IP + /* AX25IP */ + ax25ip_l1exit(); +#endif +#ifdef SIXPACK + /* 6PACK */ + Sixpack_l1exit(); +#endif +#ifdef L1TELNET + /* TCPIP-Interface schliessen. */ + L1ExitTCP(KISS_TELNET); +#endif /* L1TELNET */ +#ifdef L1HTTPD + /* TCPIP-Interface schliessen. */ + L1ExitTCP(KISS_HTTPD); +#endif /* L1HTTPD */ +#ifdef L1IPCONV + /* TCPIP-Interface schliessen. */ + L1ExitTCP(KISS_IPCONV); +#endif /* L1IPCONV */ +#ifdef L1IRC + /* TCPIP-Interface schliessen. */ + L1ExitTCP(KISS_IRC); +#endif /* L1IRC */ +} + + +/************************************************************************/ +/* */ +/* Level1 Timer */ +/* Watchdog-Timer fuer die einzelnen L2-Ports */ +/* */ +/************************************************************************/ + +void l1timr(UWORD ticks) +{ + register unsigned int i; + + if ((tic1m += ticks) > 6000) /* alle Minute */ + { + tic1m -= 6000; + /* Statistik fuer den Tokenring */ + token_pro_sec = (token_count / 60L); + + if ( (token_max_sec != 0) + && (token_min_sec != 0)) + { + token_max_sec = max(token_pro_sec, token_max_sec); + token_min_sec = min(token_pro_sec, token_min_sec); + } + else + token_min_sec = token_max_sec = token_pro_sec; + + token_count = 0L; + } + + /* DCD (TX) fuer die Tokenring-Ports checken */ + for (i = 0; i < L2PNUM; ++i) + if (wd_timer[i] < ticks) + { + wd_timer[i] = WATCHDOG_TIMEOUT; + portpar[i].reset_port = TRUE; + } +} + +/************************************************************************/ +/* */ +/* Level1 RX/TX */ +/* wird staendig in der main() Hauptschleife aufgerufen. */ +/* */ +/************************************************************************/ + +void l1rxtx(void) +{ + register UBYTE i; + DEVICE *l1pp; + +#ifdef VANESSA + if (found_vanessa != 0) + vanessa(); +#endif +#ifdef AX_IPX + axipx(); +#endif +#ifdef AX25IP + ax25ip(); +#endif +#ifdef KERNELIF + ifax_housekeeping(); +#endif +#ifdef SIXPACK + Sixpack_Housekeeping(); +#endif + + ++rounds_count; /* Anzahl der Hauptschleifendurchlaeufe */ +#ifdef LOOPBACK + /* Loopback-Funktionalitaet */ + loopback(); +#endif + + /* alle Ports durchgehen */ + for (i = 0; i < L2PNUM; ++i) + { + /* uninitialisierter Port */ + if (l1ptab[i] == -1) + continue; + /* deaktivierter Port */ + if (!portenabled(i)) + continue; + l1pp = &l1port[l1ptab[i]]; + /* Tokenring darf nur senden, wenn wir das Token haben */ + if ( (l1pp->kisstype == KISS_TOK) /* Wenn Token noch unterwegs, */ + && (tokenflag == FALSE)) /* nicht senden! */ + continue; + +#ifdef AX_IPX + if (l1pp->kisstype == KISS_IPX) + continue; +#endif +#ifdef AX25IP + if (l1pp->kisstype == KISS_AXIP) + continue; +#endif +#ifdef VANESSA + if (l1pp->kisstype == KISS_VAN) + continue; +#endif +#ifdef KERNELIF + if ( (l1pp->kisstype == KISS_KAX25) + || (l1pp->kisstype == KISS_KAX25KJD)) + continue; +#endif +#ifdef SIXPACK + if (l1pp->kisstype == KISS_6PACK) + continue; +#endif +#ifdef L1TELNET + if (l1pp->kisstype == KISS_TELNET) + continue; +#endif /* L1TELNET */ +#ifdef L1HTTPD + if (l1pp->kisstype == KISS_HTTPD) + continue; +#endif /* L1HTTPD */ +#ifdef L1IPCONV + if (l1pp->kisstype == KISS_IPCONV) + continue; +#endif /* L1IPCONV */ +#ifdef L1IRC + if (l1pp->kisstype == KISS_IRC) + continue; +#endif /* L1IRC */ + +/************************************************************************/ +/* */ +/* Nicht-Tokenring-TNCs konfigurieren, falls notwendig */ +/* */ +/************************************************************************/ + + if (commandflag[i]) /* TNC konfigurieren */ + config_tnc(i); + +/************************************************************************/ +/* */ +/* Tokenring ist frei - oder SMACK-/KISS-Link */ +/* */ +/************************************************************************/ + if (kick[i]) /* Es soll auf diesem Port gesendet werden */ + { + kissframe_to_tnc(i, FALSE); /* Alles fuer diesen Port senden */ + cd_timer[i] = tic10; /* Wir senden, Belegt-Timer starten */ + } + } + if (l1port[0].kisstype != KISS_TOK) /* kein Tokenring da? */ + return; + +/************************************************************************/ +/* */ +/* Tokenring ueberwachen - wenn Token empfangen, ggf. neue Daten senden */ +/* oder TNC(s) resetten bzw. konfigurieren. Wenn zu lange kein Token */ +/* angekommen, Verlust des Token annehmen und neues Token generieren. */ +/* */ +/************************************************************************/ + + if (tokenflag == FALSE) /* nichts gekommen? */ + { + if (tic10 > (token_sent + TOKENTIMEOUT)) /* noch einmal warten.. */ + { + if (++lost_token >= 150) /* zu viele Token-Recoveries */ + HALT("Tokenring"); + + l1port[0].rx_state = ST_BEGIN; /* auf FEND warten */ + send_kisscmd(0xff, CMD_TOKEN, 0); /* Token senden */ + token_sent = tic10; /* nix gekommen... */ + ++recovery_count; /* fuer die Statistik */ + + for (i = 0; i < L2PNUM; ++i) /* ggf neue Parameter an TNC */ + { + if ( portenabled(i) + && (kissmode(i) == KISS_TOK)) + { + commandflag[i] = TRUE; /* Portparameter neu einstellen */ + kissframe_to_tnc(i, TRUE); /* zur Sicherheit bei Recovery */ + } /* Restframes loeschen */ + } + + if (show_recovery == TRUE) + { + notify(1, "*** Token-Recovery (%lu)", lost_token); + if (!blicnt) + xprintf("*** Token-Recovery (%lu)\n", lost_token); + } + } + } + else /* Token ist angekommen */ + { + for (i = 0; i < L2PNUM; ++i) + { + if (l1ptab[i] == -1) /* Port uninitialisiert */ + continue; + if (!portenabled(i)) /* Port ist aus */ + continue; + l1pp = &l1port[l1ptab[i]]; + if (l1pp->kisstype != KISS_TOK) /* nicht Tokenring */ + continue; + if (portpar[i].reset_port == TRUE) /* diesen Port resetten?*/ + { + send_kisscmd(i, CMD_TNCRES, 0); + portpar[i].reset_port = FALSE; + commandflag[i] = TRUE; /* nach Reset TNC konfigurieren */ + break; /* nur 1 RESET/Token, mehr */ + } /* kommt evtl. nicht durch, da */ + } /* TNC taub ist nach RESET */ + + send_kisscmd(0xff, CMD_TOKEN, 0); /* Token senden */ + token_sent = tic10; + tokenflag = FALSE; + lost_token = 0; + } +} + +/************************************************************************/ +/* */ +/* Loopback-Ports bearbeiten */ +/* */ +/************************************************************************/ +#ifdef LOOPBACK +static void loopback(void) +{ + LHEAD *l2flp; + MBHEAD *txfhd; + MBHEAD *rxfhd; + register int port; + int rxport; + + l2flp = txl2fl; + + for (port = 0; port < L2PNUM; l2flp++, port++)/* jeden Port durchlaufen */ + { + if (kissmode(port) == KISS_LOOP) + { +/* wenn zwei L2-Ports mit aufeinanderfolgender Nummer (um genau zu sein */ +/* ein Port mit gerader Nummer und der mit der naechsthoeheren Nummer) */ +/* auf LOOP gesetzt sind, auf den Nachbarport senden; andernfalls auf */ +/* Sendeport */ + rxport = port ^ 1; + if ( !portenabled(rxport) + || (kissmode(rxport) != KISS_LOOP)) + rxport = port; + + while (kick[port]) /* was zum senden... */ + { + ulink((LEHEAD *)(txfhd = (MBHEAD *) l2flp->head)); + rxfhd = (MBHEAD *) allocb(ALLOC_MBHEAD); + + rxfhd->l2port = rxport; + while (txfhd->mbpc > txfhd->mbgc) + putchr(getchr(txfhd), rxfhd); + relink((LEHEAD *)rxfhd, (LEHEAD *)rxfl.tail); /* in Rx-Liste */ + relink((LEHEAD *)txfhd, (LEHEAD *)stfl.tail); /* Frame gesendet */ + kick[port] = ((LHEAD *)l2flp->head != l2flp); + } + } + } +} +#endif + +/************************************************************************/ +/* */ +/* TNC gemaess Port-Parametern konfigurieren */ +/* */ +/************************************************************************/ + +static void config_tnc(int l2port) +{ + PORTINFO *ppp; + DEVICE *l1pp; + + l1pp = &l1port[l1ptab[l2port]]; + ppp = &portpar[l2port]; + + if ( (l1pp->kisstype != KISS_TOK) /* DAMA geht nur mit Tokenring */ + && (l1pp->kisstype != KISS_VAN)) /* oder Vanessa */ + ppp->l2mode &= ~MODE_a; + + if ( (l1pp->kisstype == KISS_TOK) /* Tokenring aber Token noch */ + && (tokenflag == FALSE)) /* unterwegs? -> beim naechsten */ + return; /* Durchgang nochmal probieren */ + + send_kisscmd(l2port, CMD_TXDELAY, ppp->txdelay); + + /* Persistance je nach DAMA einstellen */ + if (dama(l2port)) + send_kisscmd(l2port, CMD_PERSIST, 255); + else + send_kisscmd(l2port, CMD_PERSIST, ppp->persistance); + + send_kisscmd(l2port, CMD_SLOTTIME, ppp->slottime); + send_kisscmd(l2port, CMD_TXTAIL, TAILTIME); + send_kisscmd(l2port, CMD_FULLDUP, fullduplex(l2port) ? 1 : 0); + send_kisscmd(l2port, CMD_DAMA, (dama(l2port)) ? 1 : 0); + commandflag[l2port] = FALSE; +} + +/************************************************************************/ +/* */ +/* Level1 Control */ +/* eine Aktion fuer einen Hardware-Port anfordern */ +/* */ +/************************************************************************/ + +void l1ctl(int req, int port) +{ + /* je nach Request die notwendigen Aktionen bestimmen */ + switch (req) + { + /* Port resetten */ + case L1CRES: portpar[port].reset_port = TRUE; + break; + /* Parameter zum Port bringen */ + case L1CCMD: commandflag[port] = TRUE; + break; + /* Testsignal senden */ + case L1CTST: testflag[port] = TRUE; + kick[port] = TRUE; + break; + /* sonstiges */ + default: break; + } +#ifdef VANESSA + if (found_vanessa != 0) + vanessa_l1ctl(req); +#endif +#ifdef AX_IPX + axipx_l1ctl(req, port); +#endif +#ifdef AX25IP + ax25ip_l1ctl(req, port); +#endif +#ifdef KERNELIF + ifax_l1ctl(req); +#endif +#ifdef SIXPACK + Sixpack_l1ctl(req, port); +#endif +#ifdef L1TCPIP + L1ctlTCP(req, port); +#endif /* L1TCPIP */ +} + +/************************************************************************/ +/* */ +/* Kommando fuer TNC-Parameter an KISS-Link senden */ +/* */ +/************************************************************************/ + +void send_kisscmd(int l2prt, int cmd, int value) +{ + char tx_buffer[10]; /* Buffer fuer KISS-Frame - 10 Zeichen reicht! */ + char *tx_bufptr; + unsigned len; + char val2; + DEVICE *l1pp; + + /* ohne KISS geht es hier nicht weiter */ + if (!kiss_active) + return; + + if (l2prt != 0xff) /* wenn nicht Token */ + l1pp = &l1port[l1ptab[l2prt]]; + else + l1pp = l1port; /* Token = Tokenring = 1. Device */ + + switch (l1pp->kisstype) /* pruefen, ob Kommando zum */ + { /* Kiss-Modus passt */ + case KISS_RMNC: + case KISS_SCC: + return; + break; + case KISS_TOK: + if (cmd < CMD_TXDELAY) return; + if ((cmd > CMD_TOKEN) && (cmd != CMD_TNCRES)) return; + break; + default: + if ((cmd < CMD_TXDELAY) || (cmd > CMD_FULLDUP)) return; + break; + } + + tx_bufptr = tx_buffer; /* KISS-Frame in Puffer schreiben */ + *tx_bufptr++ = FEND; + len = 1; + + if (l1pp->kisstype == KISS_TOK) /* Port-Nummer nur bei Token- */ + { /* ring */ + *tx_bufptr++ = l2prt; + len++; + } + + *tx_bufptr++ = (char)cmd; + ++len; + + if ((l2prt != 0xff) && (cmd != CMD_TNCRES)) /* Parameter folgt */ + { + val2 = (char)(value & 0xFF); /* Parameter nur 0 - 255 */ + switch (val2) /* ggf. Sonderbehandlung */ + { + case FEND: /* FEND -> FESC - TFEND */ + *tx_bufptr++ = FESC; + *tx_bufptr++ = TFEND; + len += 2; + break; + case FESC: /* FESC -> FESC - TFESC */ + *tx_bufptr++ = FESC; + *tx_bufptr++ = TFESC; + len += 2; + break; + default: /* keine Sonderbehandlung */ + *tx_bufptr++ = val2; + len++; + break; + } + } + *tx_bufptr++ = FEND; /* Ende Kommando-Frame */ + ++len; + + write(l1pp->kisslink, tx_buffer, len);/* Kommando-Frame absenden */ +} + +/************************************************************************/ +/* */ +/* send all frames in txbuffer over kisslink */ +/* */ +/************************************************************************/ + +static void kissframe_to_tnc(int l2prt, BOOLEAN recovery) +{ + char tx_buffer[2*MAXKISSLEN]; + char *tx_bufptr; + unsigned len; + unsigned short ch1; + int i; + char tmp_buffer[MAXKISSLEN]; + char *tmp_bufptr; + int tmp_buflen; + DEVICE *l1pp; + MBHEAD *txfhdl; + LHEAD *l2flp; + ULONG count = 0L; + + /* Testsignal senden ? */ + if (testflag[l2prt] == TRUE) + { + count = (portpar[l2prt].speed * 1000) / 8; /* 10 sec lang */ + if (count < 1024) /* min. 1kB */ + count = 1024; + } + + l1pp = &l1port[l1ptab[l2prt]]; + kick[l2prt] = FALSE; /* alles senden */ + l2flp = (LHEAD *) &txl2fl[l2prt]; + + while ( (l2flp->head != l2flp) /* solange Frames vorhanden */ + || (testflag[l2prt] == TRUE)) /* oder TEST gefordert */ + { + if (l2flp->head != l2flp) /* erst Info, danach erst TEST */ + { + txfhdl = (MBHEAD *) l2flp->head; + ulink((LEHEAD *) txfhdl); + tmp_bufptr = tmp_buffer; /* Zwischenpuffer auf Anfang */ + *tmp_bufptr++ = (char)0x00; /* fuer KISS-Befehl "Daten */ + tmp_buflen = 1; /* folgen" */ + + while (txfhdl->mbgc < txfhdl->mbpc) /* noch Zeichen im Frame */ + { + ch1 = getchr(txfhdl); /* 1 Zeichen aus Frame holen */ + *tmp_bufptr++ = (char)(ch1 & 0xFF);/* Zeichen in Zwischenpuffer */ + ++tmp_buflen; + } + + relink((LEHEAD *) txfhdl, (LEHEAD *) stfl.tail); + } + else /* TEST */ + { + tmp_bufptr = tmp_buffer; /* Zwischenpuffer auf Anfang */ + *tmp_bufptr++ = 0x00; /* fuer KISS-Befehl "Daten */ + tmp_buflen = 1; /* folgen" */ + while (count > 0) /* noch Zeichen fuer Test */ + { + if (tmp_buflen == MAXKISSLEN-3) /* Buffer voll? */ + break; + *tmp_bufptr++ = 0; /* Zeichen in Zwischenpuffer */ + ++tmp_buflen; + if (--count == 0) /* fertig? */ + testflag[l2prt] = FALSE; + } + } + if (!portenabled(l2prt)) /* Port aus -> Frame ist abgeholt, auf */ + continue; /* zum naechsten .. */ + if (recovery) /* bei Token-Recovery */ + continue; /* zum naechsten .. */ + tx_bufptr = tx_buffer; /* Sendepuffer auf Anfang */ + *tx_bufptr++ = FEND; /* KISS-Frame beginnt mit FEND */ + + len = 1; + switch (l1pp->kisstype) /* KISS-Befehl "Daten folgen" abhaengig */ + { /* vom KISS-Modus */ + case KISS_NORMAL: /* KISS einfach */ + case KISS_SCC: + *tmp_buffer = 0x00; + break; + + case KISS_SMACK: /* SMACK */ + case KISS_TF: /* TheFirmware */ + *tmp_buffer = 0x80; + append_crc_16(tmp_buffer, &tmp_buflen); /* CRC ueber gesamtes */ + break; /* Frame anhaengen */ + + case KISS_RMNC: /* RMNC-KISS */ + *tmp_buffer = 0x20; + append_crc_rmnc(tmp_buffer, &tmp_buflen);/* CRC ueber gesamtes */ + break; /* Frame anhaengen */ + + case KISS_TOK: /* Tokenring-KISS */ + *tmp_buffer = 0x00; + *tx_bufptr++ = l2prt; /* L2-Port vorweg */ + ++len; + break; + } + tmp_bufptr = tmp_buffer; /* Zwischenpuffer auf Anfang */ + + for (i = 0; i < tmp_buflen; ++i) /* Zwischenpuffer -> Sendepuffer */ + { /* kopieren */ + switch (*tmp_bufptr) + { + case FEND: /* FEND -> FESC / TFEND */ + *tx_bufptr++ = FESC; + *tx_bufptr++ = TFEND; + len += 2; + break; + + case FESC: /* FESC -> FESC / TFESC */ + *tx_bufptr++ = FESC; + *tx_bufptr++ = TFESC; + len += 2; + break; + + default: /* keine Sonderbehandlung */ + *tx_bufptr++ = *tmp_bufptr; + ++len; + break; + } + ++tmp_bufptr; + } + *tx_bufptr++ = FEND; /* Frameende = FEND */ + ++len; + + write(l1pp->kisslink, tx_buffer, len); /* Frame -> TNC */ + } +} + +/************************************************************************/ +/* */ +/* Empfangsframe in TNN-Puffer schreiben - CRC ist ggf. schon geprueft */ +/* */ +/************************************************************************/ + +static void frame_to_l1(WORD port, char *buffer, int len) +{ + static MBHEAD *rxfrhd; + register int i; + + rxfrhd = (MBHEAD *) allocb(ALLOC_MBHEAD); + rxfrhd->l2port = port; + + for (i = 0; i < len; ++i) + putchr(buffer[i], rxfrhd); + + relink((LEHEAD *) rxfrhd, (LEHEAD *)rxfl.tail); +} + +/************************************************************************/ +/* */ +/* Frame auf Gueltigkeit pruefen (Laenge, CRC) und gueltige Frames */ +/* weiterreichen */ +/* */ +/************************************************************************/ + +static void frame_valid(WORD port, char *buffer, int len, int type) +{ + switch (type) + { + case KISS_NORMAL: /* KISS einfach, Tokenring oder SCC: */ + case KISS_TOK: /* nur Framelaenge kann geprueft werden */ + case KISS_SCC: + if (len <= MAXFRAMELEN) + frame_to_l1(port, buffer+1, len-1); + break; + case KISS_SMACK: /* SMACK: CRC und Framelaenge */ + case KISS_TF: /* TF auch mit SMACK */ + if (!check_crc_16(buffer, &len)) /* pruefen */ + if (len <= MAXFRAMELEN) + frame_to_l1(port, buffer+1, len-1); + break; + case KISS_RMNC: /* RMNC-KISS: CRC und Frame- */ + if (!check_crc_rmnc(buffer, &len))/* laenge pruefen */ + if (len <= MAXFRAMELEN) + frame_to_l1(port, buffer+1, len-1); + break; + } +} + + +/************************************************************************/ +/* */ +/* put data received over kisslink in rxbuffer */ +/* */ +/************************************************************************/ + +void framedata_to_queue(int dev, char *buffer, int len) +{ + char *bufptr; + register int i; + UBYTE ch; + DEVICE *l1pp; + static WORD k; + + l1pp = &l1port[dev]; + + if (l1pp->kisstype == KISS_TOK) /* Waehrend Empfang kein Token- */ + token_sent = tic10; /* recovery */ + + for (bufptr = buffer, i = 0; i < len; ++i, bufptr++) + { + ch = *bufptr; /* 1 Zeichen aus Puffer holen */ + switch (l1pp->rx_state) + { + case ST_BEGIN: /* Frameanfang suchen */ + if (ch == FEND) /* alles ausser FEND ignorieren */ + l1pp->rx_state = ST_PORT; + break; + case ST_PORT: /* Portnummer folgt */ + if (ch != FEND) /* zusaetzliche FEND ignorieren */ + { + switch (l1pp->kisstype) + { + case KISS_NORMAL: + case KISS_SCC: + +/************************************************************************/ +/* */ +/* KISS einfach: Die Portnummer ist als Bit 4-7 kodiert. Daher sind */ +/* eigentlich 16 Ports moeglich. Dies wird von dieser Software aber */ +/* (noch?) nicht unterstuetzt. Gibt es ueberhaupt TNC-Software, die */ +/* normalen KISS-Modus mit mehreren Ports unterstuetzt? Wer kann das */ +/* einbauen und testen? */ +/* */ +/************************************************************************/ + + if ((ch & 0x8F) == 0x00) + l1pp->rx_port = (ch & 0x70) >> 4; + else + { + l1pp->rx_state = ST_BEGIN; + l1pp->bad_frames++; + } + break; + case KISS_SMACK: + case KISS_TF: + +/************************************************************************/ +/* */ +/* SMACK: Die Portnummer ist als Bit 4-6 kodiert. Daher sind eigentlich */ +/* 8 Ports moeglich. Dies wird von dieser Software aber (noch?) nicht */ +/* unterstuetzt. Gibt es ueberhaupt TNC-Software, die den SMACK-Modus */ +/* mit mehreren Ports unterstuetzt? Wer kann das einbauen und testen? */ +/* */ +/************************************************************************/ + + if ((ch & 0x8F) == 0x80) + l1pp->rx_port = (ch & 0x70) >> 4; + else + { + l1pp->rx_state = ST_BEGIN; + l1pp->bad_frames++; + } + break; + case KISS_RMNC: + if ((ch & 0xFF) == 0x20) + l1pp->rx_port = 0; + else + { + l1pp->rx_state = ST_BEGIN; + l1pp->bad_frames++; + } + break; + case KISS_TOK: + +/************************************************************************/ +/* */ +/* Tokenring: Die Portnummer ist als einzelnes Byte definiert. Daher */ +/* sind eigentlich 255 Ports moeglich. TNN unterstuetzt aber nur die */ +/* Ports 0 - 15. Ausserdem wird Port 255 fuer das Token verwendet. */ +/* */ +/************************************************************************/ + + l1pp->rx_port = ch; + if ( (ch != 0xff) /* nicht Token-Port? */ + && ((ch >= L2PNUM) /* gueltige Portnummer? */ + || (l1ptab[(WORD) ch] != 0))) /* Port definiert? */ + { + l1pp->rx_state = ST_BEGIN; + l1pp->bad_frames++; + } + else + l1pp->rx_state = ST_TOKCMD; + break; + } + +/************************************************************************/ +/* */ +/* Die Portnummer wird jetzt ueberprueft. Ausser beim Tokenring MUSS es */ +/* 0 sein. */ +/* */ +/************************************************************************/ + + if (l1pp->kisstype != KISS_TOK) + { + if (l1pp->rx_state != ST_BEGIN) + { + if (l1pp->rx_port != 0x00) + { + l1pp->rx_state = ST_BEGIN; + l1pp->bad_frames++; + } + else + { + l1pp->rx_state = ST_DATA; + l1pp->rx_bufptr = l1pp->rx_buffer; + *l1pp->rx_bufptr++ = ch; + l1pp->rx_buflen = 1; + } + } + } + } + break; + case ST_DATA: /* Daten kommen */ + switch (ch) + { + case FEND: /* Frameende? */ + if (l1pp->kisstype != KISS_TOK) /* ggf. Portnummer aus */ + l1pp->rx_port = l2ptab[dev]; /* Tabelle holen */ + frame_valid(l1pp->rx_port, /* Frame pruefen und */ + l1pp->rx_buffer, /* an L2 weitergeben */ + l1pp->rx_buflen, + l1pp->kisstype); + l1pp->rx_state = ST_PORT; /* naechstes Frame kann */ + break; /* kommen */ + case FESC: /* FESC -> Sonderfall */ + l1pp->rx_state = ST_ESC; + break; + default: /* normales Zeichen */ + *l1pp->rx_bufptr = ch; + l1pp->rx_bufptr++; + l1pp->rx_buflen++; + if (l1pp->rx_buflen > MAXKISSLEN) /* Frame zu lang? */ + { + l1pp->rx_state = ST_BEGIN; + l1pp->bad_frames++; + } + break; + } + break; + case ST_ESC: /* zuletzt FESC empfangen */ + switch (ch) + { + case TFEND: /* FESC / TFEND -> FEND */ + *l1pp->rx_bufptr = FEND; + l1pp->rx_bufptr++; + l1pp->rx_buflen++; + if (l1pp->rx_buflen > MAXKISSLEN) /* Frame zu lang? */ + { + l1pp->rx_state = ST_BEGIN; + l1pp->bad_frames++; + } + else + l1pp->rx_state = ST_DATA; + break; + case TFESC: /* FESC / TFESC -> FESC */ + *l1pp->rx_bufptr = FESC; + l1pp->rx_bufptr++; + l1pp->rx_buflen++; + if (l1pp->rx_buflen > MAXKISSLEN) /* Frame zu lang? */ + { + l1pp->rx_state = ST_BEGIN; + l1pp->bad_frames++; + } + else + l1pp->rx_state = ST_DATA; + break; + default: + l1pp->rx_state = ST_BEGIN; + l1pp->bad_frames++; + break; + } + break; + case ST_TOKCMD: /* Tokenring nach Port */ + switch (ch & 0xff) /* kommt Kommando */ + { + case 0: /* Kommando: "Daten */ + l1pp->rx_state = ST_DATA; /* folgen" */ + l1pp->rx_bufptr = l1pp->rx_buffer; + *l1pp->rx_bufptr++ = ch; + l1pp->rx_buflen = 1; + break; + case CMD_TOKEN: /* Kommando: "Token" */ + if (l1pp->rx_port == 0xff) + l1pp->rx_state = ST_TOKEN; + else + l1pp->rx_state = ST_BEGIN; + break; + case MSG_TNCRES: /* Kommando: "TNC- */ + if (l1pp->rx_port != 0xff) /* Meldung - Reset" */ + { + k = 0; + l1pp->rx_state = ST_TNCRES; + } + else + { + l1pp->rx_state = ST_BEGIN; + l1pp->bad_frames++; + } + break; + case MSG_SENTDAMA: /* Kommando: "TNC- */ + if (l1pp->rx_port != 0xff) /* Meldung: DAMA-Frames */ + l1pp->rx_state = ST_DAMA; /* gesendet" */ + else + { + l1pp->rx_state = ST_BEGIN; + l1pp->bad_frames++; + } + break; + default: /* unbekanntes Kommando */ + l1pp->rx_state = ST_BEGIN; + l1pp->bad_frames++; + break; + } + break; + case ST_TOKEN: /* nach Token kommt FEND */ + if (ch == FEND) + { + tokenflag = TRUE; + l1pp->rx_state = ST_PORT; + ++token_count; + } + else + { + l1pp->rx_state = ST_BEGIN; + l1pp->bad_frames++; + } + break; + case ST_TNCRES: /* nach TNC-Meldung kommt FEND */ + if (ch == FEND) + { + commandflag[l1pp->rx_port] = TRUE; + portstat[l1pp->rx_port].reset_count++; + l1pp->rx_state = ST_PORT; + printf("TNC-Reset - Port %d\r\n", l1pp->rx_port); + } + else + { + if (++k > 6) + { + l1pp->rx_state = ST_BEGIN; + l1pp->bad_frames++; + } + } + break; + case ST_DAMA: /* nach TNC-Meldung kommt FEND */ + if (ch == FEND) + { + cd_timer[l1pp->rx_port] = 0; /* Kanal frei: Timer stoppen */ + l1pp->rx_state = ST_PORT; + } + else + { + l1pp->rx_state = ST_BEGIN; + l1pp->bad_frames++; + } + break; + default: + l1pp->rx_state = ST_BEGIN; + l1pp->bad_frames++; + break; + } + } +} + +/************************************************************************/ +/* */ +/* Markieren, dass fuer TNC #port Frames zum Senden vorliegen */ +/* */ +/************************************************************************/ + +void kicktx(int port) +{ + kick[port] = TRUE; +} + +/************************************************************************/ +/* */ +/* iscd(): Carrier Detect Wichtig fuer DAMA !!! */ +/* */ +/* Return: abhaengig von der Hardware des Ports - nur KISS wird */ +/* direkt behandelt. PTTFLAG = auf DAMA-Port noch nicht */ +/* alles gesendet, 0 sonst. */ +/* */ +/************************************************************************/ + +WORD iscd(int l2port) +{ + switch (kissmode(l2port)) + { +#ifdef VANESSA + case KISS_VAN : return (vanessa_dcd(l2port)); break; +#endif +#ifdef AX_IPX + case KISS_IPX : return (axipx_dcd(l2port)); break; +#endif +#ifdef AX25IP + case KISS_AXIP : return (ax25ip_dcd(l2port)); break; +#endif +#if defined(KERNELIF) && (defined(PCISCC4_KAX25) || defined(HDLC_DCDPTTSTAT) || defined(SCC_DCDPTTSTAT)) + case KISS_KAX25 : return (ifax_dcd(l2port)); break; +#endif +#ifdef SIXPACK + case KISS_6PACK : return (Sixpack_DCD(l2port)); break; +#endif +#ifdef L1TELNET + case KISS_TELNET: return (TcpDCD(l2port)); break; +#endif /* L1TELNET */ +#ifdef L1HTTPD + case KISS_HTTPD: return (TcpDCD(l2port)); break; +#endif /* L1HTTPD */ +#ifdef L1IPCONV + case KISS_IPCONV: return (TcpDCD(l2port)); break; +#endif /* L1IPCONV */ +#ifdef L1IRC + case KISS_IRC: return (TcpDCD(l2port)); break; +#endif /* L1IRC */ + + default : break; + } + + /* DCD fuer Tokenring */ + if ( dama(l2port) /* Nur DAMA-Ports und belegt.. */ + && cd_timer[l2port]) + { + if ((tic10 - cd_timer[l2port]) > CD_TIMEOUT) /* Timeout abgelaufen? */ + cd_timer[l2port] = 0; /* Timer stoppen */ + + if (cd_timer[l2port]) /* Timer laeuft: Port ist belegt */ + return(PTTFLAG); /* Einen belegten Port gefunden! */ + }/*Nur DAMA*/ + + return(FALSE); +} + +/************************************************************************/ +/* */ +/* Aufzaehlen der vorhandenen Layer 1 Geraete. Dies sind nicht die */ +/* tatsaechlich installierten sondern die compilierten. */ +/* */ +/************************************************************************/ + +void l1enum(MBHEAD *mbp) +{ +#ifdef LOOPBACK + putstr(" * KISS-Protocols: TOKENRING KISS SMACK RKISS TF LOOP\r", mbp); +#else + putstr(" * KISS-Protocols: TOKENRING KISS SMACK RKISS TF\r", mbp); +#endif +#ifdef SIXPACK + putstr(" * 6PACK\r", mbp); +#endif +#ifdef VANESSA + putstr(" * VANESSA\r", mbp); +#endif +#ifdef AX_IPX + putstr(" * IPX\r", mbp); +#endif +#ifdef AX25IP + putstr(" * AX25IP\r", mbp); +#endif +#ifdef KERNELIF + putstr(" * Kernel-AX.25\r", mbp); + putstr(" * IP-Tunnel\r", mbp); +#endif +#ifdef L1TELNET + putstr(" * TELNET-Server\r", mbp); +#endif /* L1TELNET */ +#ifdef L1HTTPD + putstr(" * HTTPD-Server\r", mbp); +#endif /* L1HTTPD */ +#ifdef L1IPCONV + putstr(" * IPCONVERS-Server\r", mbp); +#endif /* L1IPCONV */ +#ifdef L1IRC + putstr(" * IRC-Server\r", mbp); +#endif /* L1IRC */ +} + +/************************************************************************/ +/* */ +/* L1-Statistik loeschen (alle Ports) */ +/* */ +/************************************************************************/ + +void l1sclr(const char *str) +{ + register unsigned int i; + + token_pro_sec = 0; + token_max_sec = 0; + token_min_sec = 0; + token_count = 0; + recovery_count = 0L; + + for (i = 0; i < L1PNUM; ++i) + l1port[i].bad_frames = 0L; + +#ifdef KERNELIF + ifip_clearstat(); +#endif +} + +/************************************************************************/ +/* */ +/* L1-Statistik (Tokenring) anzeigen */ +/* */ +/************************************************************************/ + +void l1stat(const char *name, MBHEAD *mbp) +{ + int i; + BOOLEAN flag = FALSE; + + if (tkcom >= 0) + { + putprintf(mbp, "\rTokens/sec - min.: %u; last: %u; max.: %u\r", token_min_sec, token_pro_sec, token_max_sec); + + if (token_max_sec != 0) /* nicht vor 1. Messung */ + putprintf(mbp, "TOKENRING load: %u%%\r", 100-(((ULONG)token_pro_sec)*100L) / ((ULONG)token_max_sec)); + + if (recovery_count != 0) + putprintf(mbp, "\rToken-Recoveries: %lu\r", recovery_count); + } + + for (i = 0; i < L1PNUM; ++i) + { + if (l1port[i].bad_frames != 0) + { + if (!flag) + { + flag = TRUE; + putstr("\rBad frames:\r", mbp); + } + putprintf(mbp, "Device %s = %lu\r", l1port[i].device, l1port[i].bad_frames); + } + } +} + +/************************************************************************/ +/* */ +/* L1 beenden */ +/* */ +/************************************************************************/ + +void l1detach(int l2prt) +{ + portpar[l2prt].major = NO_MAJOR; +#ifdef AX_IPX + if (kissmode(l2prt) == KISS_IPX) + axipx_l1exit(); +#endif +#ifdef AX25IP + if (kissmode(l2prt) == KISS_AXIP) + ax25ip_l1exit(); +#endif +#ifdef KERNELIF + if ( (kissmode(l2prt) == KISS_KAX25) + || (kissmode(l2prt) == KISS_KAX25KJD)) + ifax_close(&(l1port[l1ptab[l2prt]])); +#endif +#ifdef L1TELNET + if (kissmode(l2prt) == KISS_TELNET) + L1ExitTCP(kissmode(l2prt)); +#endif /* L1TELNET */ +#ifdef L1HTTPD + if (kissmode(l2prt) == KISS_HTTPD) + L1ExitTCP(kissmode(l2prt)); +#endif /* L1HTTPD */ +#ifdef L1IPCONV + if (kissmode(l2prt) == KISS_IPCONV) + L1ExitTCP(kissmode(l2prt)); +#endif /* L1IPCONV */ +#ifdef L1IRC + if (kissmode(l2prt) == KISS_IRC) + L1ExitTCP(kissmode(l2prt)); +#endif /* L1IRC */ +} + +/************************************************************************/ +/* */ +/* L1 starten */ +/* */ +/************************************************************************/ + +int l1attach(int l2prt, char *buf) +{ + if (l1port[l1ptab[l2prt]].port_active == FALSE) +/* Port undefiniert in tnn.ini - der Port kann auf LOOP gesetzt werden */ + { + if (strnicmp("LOOP", buf, min(4, strlen(buf))) == 0) + { + kissmode(l2prt) = KISS_LOOP; + portpar[l2prt].major = 1; + return(1); + } + return(0); + } + if (strnicmp("TOKENRING", buf, min(9, strlen(buf))) == 0) + { + if (kissmode(l2prt) == KISS_TOK) + { + portpar[l2prt].major = 1; + return(1); + } + } + +#ifdef SIXPACK + if (strnicmp("6PACK", buf, min(5, strlen(buf))) == 0) + { + if (kissmode(l2prt) == KISS_6PACK) + { + portpar[l2prt].major = 1; + return(1); + } + } +#endif + + if (strnicmp("KISS", buf, min(4, strlen(buf))) == 0) + { + if ((kissmode(l2prt) != KISS_NIX) && (kissmode(l2prt) != KISS_VAN)) + { + portpar[l2prt].major = 1; + return(1); + } + } + if (strnicmp("SMACK", buf, min(5, strlen(buf))) == 0) + { + if (kissmode(l2prt) == KISS_SMACK) + { + portpar[l2prt].major = 1; + return(1); + } + } + if (strnicmp("TF", buf, 2) == 0) + { + if (kissmode(l2prt) == KISS_TF) + { + portpar[l2prt].major = 1; + return(1); + } + } + if (strnicmp("RKISS", buf, min(5, strlen(buf))) == 0) + { + if (kissmode(l2prt) == KISS_RMNC) + { + portpar[l2prt].major = 1; + return(1); + } + } +#ifdef VANESSA + if (strnicmp("VANESSA", buf, min(7, strlen(buf))) == 0) + { + if (kissmode(l2prt) == KISS_VAN) + { + portpar[l2prt].major = 1; + return(1); + } + } +#endif +#ifdef AX_IPX + if (strnicmp("IPX", buf, min(3, strlen(buf))) == 0) + { + if (kissmode(l2prt) == KISS_IPX) + { + if (!axipx_l1init(l2prt)) + return(0); + portpar[l2prt].major = 1; + return(1); + } + } +#endif +#ifdef AX25IP + if (strnicmp("AX25IP", buf, min(6, strlen(buf))) == 0) + { + if (kissmode(l2prt) == KISS_AXIP) + { + if (!ax25ip_l1init(l2prt)) + return(0); + portpar[l2prt].major = 1; + return(1); + } + } +#endif +#ifdef KERNELIF + if (strnicmp("KERNEL", buf, min(6, strlen(buf))) == 0) + { + if ( (kissmode(l2prt) == KISS_KAX25) + || (kissmode(l2prt) == KISS_KAX25KJD)) + { + if (!ifax_setup(&(l1port[l1ptab[l2prt]]))) + return(0); + portpar[l2prt].major = 1; + return(1); + } + } +#endif +#ifdef L1TELNET + if (strnicmp("TELNET", buf, min(6, strlen(buf))) == FALSE) + { + if (kissmode(l2prt) == KISS_TELNET) + { + if (!L1InitTCP(kissmode(l2prt), l2prt, htons((unsigned short)atoi(l1port[l1ptab[l2prt]].device)))) + return(FALSE); + + portpar[l2prt].major = TRUE; + return(TRUE); + } + } +#endif /* L1TELNET */ +#ifdef L1HTTPD + if (strnicmp("HTTPD", buf, min(6, strlen(buf))) == FALSE) + { + if (kissmode(l2prt) == KISS_HTTPD) + { + if (!L1InitTCP(kissmode(l2prt), l2prt, htons((unsigned short)atoi(l1port[l1ptab[l2prt]].device)))) + return(FALSE); + + portpar[l2prt].major = TRUE; + return(TRUE); + } + } +#endif /* L1HTTPD */ +#ifdef L1IPCONV + if (strnicmp("IPCONV", buf, min(6, strlen(buf))) == FALSE) + { + if (kissmode(l2prt) == KISS_IPCONV) + { + if (!L1InitTCP(kissmode(l2prt), l2prt, htons((unsigned short)atoi(l1port[l1ptab[l2prt]].device)))) + return(FALSE); + + portpar[l2prt].major = TRUE; + return(TRUE); + } + } +#endif /* L1IPCONV */ +#ifdef L1IRC + if (strnicmp("IRC", buf, min(3, strlen(buf))) == FALSE) + { + if (kissmode(l2prt) == KISS_IRC) + { + if (!L1InitTCP(kissmode(l2prt), l2prt, htons((unsigned short)atoi(l1port[l1ptab[l2prt]].device)))) + return(FALSE); + + portpar[l2prt].major = TRUE; + return(TRUE); + } + } +#endif /* L1IRC */ + if (strnicmp("SSC", buf, min(3, strlen(buf))) == 0) + { + if (kissmode(l2prt) == KISS_SCC) + { + portpar[l2prt].major = 1; + return(1); + } + } + + if (stricmp("ON", buf) == 0) + { + if (kissmode(l2prt) != KISS_NIX) + { +#ifdef AX_IPX + if (kissmode(l2prt) == KISS_IPX) + { + if (!axipx_l1init(l2prt)) + return(0); + } +#endif +#ifdef AX25IP + if (kissmode(l2prt) == KISS_AXIP) + { + if (!ax25ip_l1init(l2prt)) + return(0); + } +#endif +#ifdef KERNELIF + if ( (kissmode(l2prt) == KISS_KAX25) + || (kissmode(l2prt) == KISS_KAX25KJD)) + { + if (!ifax_setup(&(l1port[l1ptab[l2prt]]))) + return(0); + } +#endif +#ifdef L1TELNET + if (kissmode(l2prt) == KISS_TELNET) + { + if (!L1InitTCP(kissmode(l2prt), l2prt, htons((unsigned short)atoi(l1port[l1ptab[l2prt]].device)))) + return(FALSE); + } +#endif /* L1TELNET */ +#ifdef L1HTTPD + if (kissmode(l2prt) == KISS_HTTPD) + { + if (!L1InitTCP(kissmode(l2prt), l2prt, htons((unsigned short)atoi(l1port[l1ptab[l2prt]].device)))) + return(FALSE); + } +#endif /* L1HTTPD */ +#ifdef L1IPCONV + if (kissmode(l2prt) == KISS_IPCONV) + { + if (!L1InitTCP(kissmode(l2prt), l2prt, htons((unsigned short)atoi(l1port[l1ptab[l2prt]].device)))) + return(FALSE); + } +#endif /* L1IPCONV */ +#ifdef L1IRC + if (kissmode(l2prt) == KISS_IRC) + { + if (!L1InitTCP(kissmode(l2prt), l2prt, htons((unsigned short)atoi(l1port[l1ptab[l2prt]].device)))) + return(FALSE); + } +#endif /* L1IRC */ + + portpar[l2prt].major = 1; + return(1); + } + } + return(0); +} + +/************************************************************************/ +/* */ +/* Infostring fuer den Port-Befehl zusammenbauen. */ +/* */ +/************************************************************************/ + +void l1hwstr(int l2prt, MBHEAD *mbp) +{ + l1hwcfg(l2prt, mbp); + if ((kissmode(l2prt) != KISS_VAN) && (kissmode(l2prt) < KISS_IPX)) + { + putchr(' ', mbp); + putstr(l1port[l1ptab[l2prt]].device, mbp); + } + else + { +#ifdef VANESSA + if (kissmode(l2prt) == KISS_VAN) + van_hwstr(l2prt, mbp); +#endif +#ifdef AX_IPX + if (kissmode(l2prt) == KISS_IPX) + axipx_hwstr(l2prt, mbp); +#endif +#ifdef AX25IP + if (kissmode(l2prt) == KISS_AXIP) + ax25ip_hwstr(l2prt, mbp); +#endif +#ifdef KERNELIF + if ( (kissmode(l2prt) == KISS_KAX25) + || (kissmode(l2prt) == KISS_KAX25KJD)) + ifax_hwstr(l2prt, mbp); +#endif +#ifdef L1TELNET + if (kissmode(l2prt) == KISS_TELNET) + HwstrTCP(KISS_TELNET, l2prt, mbp); +#endif /* L1TELNET */ +#ifdef L1HTTPD + if (kissmode(l2prt) == KISS_HTTPD) + HwstrTCP(KISS_HTTPD, l2prt, mbp); +#endif /* L1HTTPD */ +#ifdef L1IPCONV + if (kissmode(l2prt) == KISS_IPCONV) + HwstrTCP(KISS_IPCONV, l2prt, mbp); +#endif /* L1IPCONV */ +#ifdef L1IRC + if (kissmode(l2prt) == KISS_IRC) + HwstrTCP(KISS_IRC, l2prt, mbp); +#endif /* L1IRC */ + } +} + +/************************************************************************/ +/* */ +/* Infostring fuer SAVEPARM zusammenbauen. */ +/* */ +/************************************************************************/ + +void l1hwcfg(int l2prt, MBHEAD *mbp) +{ + if (!portenabled(l2prt)) + putstr("OFF", mbp); + else + { + switch (kissmode(l2prt)) + { + case KISS_SMACK: putstr("SMACK", mbp); + break; + case KISS_TF: putstr("TF", mbp); + break; + case KISS_TOK: putstr("TOKENRING", mbp); + break; +#ifdef LOOPBACK + case KISS_LOOP: putstr("LOOP", mbp); + break; +#endif + case KISS_RMNC: putstr("RKISS", mbp); + break; +#ifdef VANESSA + case KISS_VAN: putstr("VANESSA", mbp); + break; +#endif +#ifdef AX_IPX + case KISS_IPX: putstr("IPX", mbp); + break; +#endif +#ifdef AX25IP + case KISS_AXIP: putstr("AX25IP", mbp); + break; +#endif +#ifdef KERNELIF + case KISS_KAX25: + case KISS_KAX25KJD: putstr("KERNEL", mbp); + break; +#endif +#ifdef SIXPACK + case KISS_6PACK: putstr("6PACK", mbp); + break; +#endif +#ifdef L1TELNET + case KISS_TELNET: putstr("TELNET", mbp); + break; +#endif /* L1TELNET */ +#ifdef L1HTTPD + case KISS_HTTPD: putstr("HTTPD ", mbp); + break; +#endif /* L1HTTPD */ +#ifdef L1IPCONV + case KISS_IPCONV: putstr("IPCONV", mbp); + break; +#endif /* L1IPCONV */ +#ifdef L1IRC + case KISS_IRC: putstr("IRC ", mbp); + break; +#endif /* L1IRC */ + + default: putstr("KISS", mbp); + break; + } + } +} + +/* + * Blocktransferroutinen fuer den Level 1 + * Message-Buffer koennen Blockweise in einen linearen Buffer umgewandelt + * werden und wieder zurueck. Dies darf aber so ohne weiteres nur im + * Level 1 erfolgen, da der Buffer zurueckgespult wird. + */ + +/* Message-Buffer -> linearen Buffer */ +int cpymbflat(char *buf, MBHEAD *fbp) +{ + MB *bp; + LHEAD *llp = &fbp->mbl; /* Zeiger auf den Listenkopf */ + int i = fbp->mbpc; /* Anzahl der Bytes im Frame */ + + for (bp = (MB *)llp->head; bp != (MB *)llp; + bp = bp->nextmb, i -= sizeof_MBDATA, buf += sizeof_MBDATA) + memcpy(buf, bp->data, sizeof_MBDATA); + return(fbp->mbpc); +} + +/* linearer Buffer -> Message-Buffer */ +MBHEAD *cpyflatmb(char *buf, int size) +{ + MBHEAD *mbhd; + MB *bp; + LHEAD *llp; + + mbhd = (MBHEAD *)allocb(ALLOC_MBHEAD); /* einen Buffer fuer den Kopf */ + mbhd->mbpc = size; /* soviel wird mal drinstehen */ + llp = &mbhd->mbl; /* Zeiger auf den Listenkopf */ + for ( ; size > 0; size -= sizeof_MBDATA, buf += sizeof_MBDATA) { + memcpy((bp = (MB *)allocb(ALLOC_MB))->data, buf, sizeof_MBDATA); + relink((LEHEAD *)bp, (LEHEAD *)llp->tail); + } + rwndmb(mbhd); /* mbbp richtig setzen */ + return(mbhd); +} + +/************************************************************************/ +/* */ +/* TNC mit TheFirmware in KISS-Modus schalten */ +/* */ +/************************************************************************/ + +#ifndef ATTACH +static void tf_set_kiss(DEVICE *l1pp) +#else +void tf_set_kiss(DEVICE *l1pp) +#endif /* ATTACH */ +{ + char buffer1[] = {0x18, 0x12, 0x18, ESC, '@', 'K', CR}; + char buffer2[] = {FESC, FEND, FEND, 0x80, 0, 0, FEND}; + + write(l1pp->kisslink, buffer1, 7); + sleep(5); + write(l1pp->kisslink, buffer2, 7); +} + +/* tfkiss: TNC-emulation for Linux + Copyright (C) 1995-96 by Mark Wahl + CRC calculation (crc.c) + created: Mark Wahl DL4YBG 95/10/08 + updated: Mark Wahl DL4YBG 96/01/31 +*/ + +/* CRC-table for SMACK */ +static const int +Crc_16_table[] = { + 0x0000, 0xc0c1, 0xc181, 0x0140, 0xc301, 0x03c0, 0x0280, 0xc241, + 0xc601, 0x06c0, 0x0780, 0xc741, 0x0500, 0xc5c1, 0xc481, 0x0440, + 0xcc01, 0x0cc0, 0x0d80, 0xcd41, 0x0f00, 0xcfc1, 0xce81, 0x0e40, + 0x0a00, 0xcac1, 0xcb81, 0x0b40, 0xc901, 0x09c0, 0x0880, 0xc841, + 0xd801, 0x18c0, 0x1980, 0xd941, 0x1b00, 0xdbc1, 0xda81, 0x1a40, + 0x1e00, 0xdec1, 0xdf81, 0x1f40, 0xdd01, 0x1dc0, 0x1c80, 0xdc41, + 0x1400, 0xd4c1, 0xd581, 0x1540, 0xd701, 0x17c0, 0x1680, 0xd641, + 0xd201, 0x12c0, 0x1380, 0xd341, 0x1100, 0xd1c1, 0xd081, 0x1040, + 0xf001, 0x30c0, 0x3180, 0xf141, 0x3300, 0xf3c1, 0xf281, 0x3240, + 0x3600, 0xf6c1, 0xf781, 0x3740, 0xf501, 0x35c0, 0x3480, 0xf441, + 0x3c00, 0xfcc1, 0xfd81, 0x3d40, 0xff01, 0x3fc0, 0x3e80, 0xfe41, + 0xfa01, 0x3ac0, 0x3b80, 0xfb41, 0x3900, 0xf9c1, 0xf881, 0x3840, + 0x2800, 0xe8c1, 0xe981, 0x2940, 0xeb01, 0x2bc0, 0x2a80, 0xea41, + 0xee01, 0x2ec0, 0x2f80, 0xef41, 0x2d00, 0xedc1, 0xec81, 0x2c40, + 0xe401, 0x24c0, 0x2580, 0xe541, 0x2700, 0xe7c1, 0xe681, 0x2640, + 0x2200, 0xe2c1, 0xe381, 0x2340, 0xe101, 0x21c0, 0x2080, 0xe041, + 0xa001, 0x60c0, 0x6180, 0xa141, 0x6300, 0xa3c1, 0xa281, 0x6240, + 0x6600, 0xa6c1, 0xa781, 0x6740, 0xa501, 0x65c0, 0x6480, 0xa441, + 0x6c00, 0xacc1, 0xad81, 0x6d40, 0xaf01, 0x6fc0, 0x6e80, 0xae41, + 0xaa01, 0x6ac0, 0x6b80, 0xab41, 0x6900, 0xa9c1, 0xa881, 0x6840, + 0x7800, 0xb8c1, 0xb981, 0x7940, 0xbb01, 0x7bc0, 0x7a80, 0xba41, + 0xbe01, 0x7ec0, 0x7f80, 0xbf41, 0x7d00, 0xbdc1, 0xbc81, 0x7c40, + 0xb401, 0x74c0, 0x7580, 0xb541, 0x7700, 0xb7c1, 0xb681, 0x7640, + 0x7200, 0xb2c1, 0xb381, 0x7340, 0xb101, 0x71c0, 0x7080, 0xb041, + 0x5000, 0x90c1, 0x9181, 0x5140, 0x9301, 0x53c0, 0x5280, 0x9241, + 0x9601, 0x56c0, 0x5780, 0x9741, 0x5500, 0x95c1, 0x9481, 0x5440, + 0x9c01, 0x5cc0, 0x5d80, 0x9d41, 0x5f00, 0x9fc1, 0x9e81, 0x5e40, + 0x5a00, 0x9ac1, 0x9b81, 0x5b40, 0x9901, 0x59c0, 0x5880, 0x9841, + 0x8801, 0x48c0, 0x4980, 0x8941, 0x4b00, 0x8bc1, 0x8a81, 0x4a40, + 0x4e00, 0x8ec1, 0x8f81, 0x4f40, 0x8d01, 0x4dc0, 0x4c80, 0x8c41, + 0x4400, 0x84c1, 0x8581, 0x4540, 0x8701, 0x47c0, 0x4680, 0x8641, + 0x8201, 0x42c0, 0x4380, 0x8341, 0x4100, 0x81c1, 0x8081, 0x4040 +}; + +/* CRC-table for RMNC-KISS */ +static const int +Crc_rmnc_table[] = { + 0x0f87, 0x1e0e, 0x2c95, 0x3d1c, 0x49a3, 0x582a, 0x6ab1, 0x7b38, + 0x83cf, 0x9246, 0xa0dd, 0xb154, 0xc5eb, 0xd462, 0xe6f9, 0xf770, + 0x1f06, 0x0e8f, 0x3c14, 0x2d9d, 0x5922, 0x48ab, 0x7a30, 0x6bb9, + 0x934e, 0x82c7, 0xb05c, 0xa1d5, 0xd56a, 0xc4e3, 0xf678, 0xe7f1, + 0x2e85, 0x3f0c, 0x0d97, 0x1c1e, 0x68a1, 0x7928, 0x4bb3, 0x5a3a, + 0xa2cd, 0xb344, 0x81df, 0x9056, 0xe4e9, 0xf560, 0xc7fb, 0xd672, + 0x3e04, 0x2f8d, 0x1d16, 0x0c9f, 0x7820, 0x69a9, 0x5b32, 0x4abb, + 0xb24c, 0xa3c5, 0x915e, 0x80d7, 0xf468, 0xe5e1, 0xd77a, 0xc6f3, + 0x4d83, 0x5c0a, 0x6e91, 0x7f18, 0x0ba7, 0x1a2e, 0x28b5, 0x393c, + 0xc1cb, 0xd042, 0xe2d9, 0xf350, 0x87ef, 0x9666, 0xa4fd, 0xb574, + 0x5d02, 0x4c8b, 0x7e10, 0x6f99, 0x1b26, 0x0aaf, 0x3834, 0x29bd, + 0xd14a, 0xc0c3, 0xf258, 0xe3d1, 0x976e, 0x86e7, 0xb47c, 0xa5f5, + 0x6c81, 0x7d08, 0x4f93, 0x5e1a, 0x2aa5, 0x3b2c, 0x09b7, 0x183e, + 0xe0c9, 0xf140, 0xc3db, 0xd252, 0xa6ed, 0xb764, 0x85ff, 0x9476, + 0x7c00, 0x6d89, 0x5f12, 0x4e9b, 0x3a24, 0x2bad, 0x1936, 0x08bf, + 0xf048, 0xe1c1, 0xd35a, 0xc2d3, 0xb66c, 0xa7e5, 0x957e, 0x84f7, + 0x8b8f, 0x9a06, 0xa89d, 0xb914, 0xcdab, 0xdc22, 0xeeb9, 0xff30, + 0x07c7, 0x164e, 0x24d5, 0x355c, 0x41e3, 0x506a, 0x62f1, 0x7378, + 0x9b0e, 0x8a87, 0xb81c, 0xa995, 0xdd2a, 0xcca3, 0xfe38, 0xefb1, + 0x1746, 0x06cf, 0x3454, 0x25dd, 0x5162, 0x40eb, 0x7270, 0x63f9, + 0xaa8d, 0xbb04, 0x899f, 0x9816, 0xeca9, 0xfd20, 0xcfbb, 0xde32, + 0x26c5, 0x374c, 0x05d7, 0x145e, 0x60e1, 0x7168, 0x43f3, 0x527a, + 0xba0c, 0xab85, 0x991e, 0x8897, 0xfc28, 0xeda1, 0xdf3a, 0xceb3, + 0x3644, 0x27cd, 0x1556, 0x04df, 0x7060, 0x61e9, 0x5372, 0x42fb, + 0xc98b, 0xd802, 0xea99, 0xfb10, 0x8faf, 0x9e26, 0xacbd, 0xbd34, + 0x45c3, 0x544a, 0x66d1, 0x7758, 0x03e7, 0x126e, 0x20f5, 0x317c, + 0xd90a, 0xc883, 0xfa18, 0xeb91, 0x9f2e, 0x8ea7, 0xbc3c, 0xadb5, + 0x5542, 0x44cb, 0x7650, 0x67d9, 0x1366, 0x02ef, 0x3074, 0x21fd, + 0xe889, 0xf900, 0xcb9b, 0xda12, 0xaead, 0xbf24, 0x8dbf, 0x9c36, + 0x64c1, 0x7548, 0x47d3, 0x565a, 0x22e5, 0x336c, 0x01f7, 0x107e, + 0xf808, 0xe981, 0xdb1a, 0xca93, 0xbe2c, 0xafa5, 0x9d3e, 0x8cb7, + 0x7440, 0x65c9, 0x5752, 0x46db, 0x3264, 0x23ed, 0x1176, 0x00ff +}; + +static void append_crc_16(char *buffer, int *len) +{ + register int i; + int crc_16 = 0; + char *bufptr = buffer; + + for (i = 0; i < *len; ++i) + crc_16 = (crc_16 >> 8) ^ Crc_16_table[(crc_16 ^ *bufptr++) & 0xff]; + + *bufptr++ = crc_16; + *bufptr++ = (crc_16 >> 8); + *len += 2; +} + +static int check_crc_16(char *buffer, int *len) +{ + register int i; + int crc_16 = 0; + char *bufptr = buffer; + + if (*len < 3) + return(1); + + for (i = 0; i < *len; ++i) + crc_16 = (crc_16 >> 8) ^ Crc_16_table[(crc_16 ^ *bufptr++) & 0xff]; + + if (crc_16) + return(1); + + *len -= 2; + return(0); +} + +static void append_crc_rmnc(char *buffer, int *len) +{ + register int i; + int crc_rmnc = 0xFFFF; + char *bufptr = buffer; + + for (i = 0; i < *len; ++i) + crc_rmnc = (crc_rmnc << 8) ^ Crc_rmnc_table[((crc_rmnc >> 8) ^ *bufptr++) & 0xff]; + + *bufptr++ = (crc_rmnc >> 8); + *bufptr++ = crc_rmnc; + *len += 2; +} + +static int check_crc_rmnc(char *buffer, int *len) +{ + register int i; + int crc_rmnc = 0xFFFF; + char *bufptr = buffer; + + if (*len < 3) + return(1); + + for (i = 0; i < *len; ++i) + crc_rmnc = (crc_rmnc << 8) ^ Crc_rmnc_table[((crc_rmnc >> 8) ^ *bufptr++) & 0xff]; + + if ((crc_rmnc & 0xFFFF) != 0x7070) + return(1); + + *len -= 2; + return(0); +} + +/* End of os/linux/l1linux.c */ diff --git a/os/linux/linclude.h b/os/linux/linclude.h new file mode 100755 index 0000000..daac019 --- /dev/null +++ b/os/linux/linclude.h @@ -0,0 +1,86 @@ +/************************************************************************/ +/* */ +/* ***** ***** */ +/* ***** ***** */ +/* ***** ***** */ +/* ***** ***** */ +/* *************** *************** */ +/* ***************** ***************** */ +/* *************** *************** */ +/* ***** ***** TheNetNode */ +/* ***** ***** Portable */ +/* ***** ***** Network */ +/* ***** ***** Software */ +/* */ +/* File os/linux/linclude.h (maintained by: DF6LN) */ +/* */ +/* This file is part of "TheNetNode" - Software Package */ +/* */ +/* Copyright (C) 1998 - 2008 NORD> +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifndef __GLIBC__ +#include +#include +#else +#ifdef __i386__ +#include +#endif +#include +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* End of os/linux/linclude.h */ diff --git a/os/linux/linux.c b/os/linux/linux.c new file mode 100644 index 0000000..76cea4c --- /dev/null +++ b/os/linux/linux.c @@ -0,0 +1,2265 @@ +/************************************************************************/ +/* */ +/* ***** ***** */ +/* ***** ***** */ +/* ***** ***** */ +/* ***** ***** */ +/* *************** *************** */ +/* ***************** ***************** */ +/* *************** *************** */ +/* ***** ***** TheNetNode */ +/* ***** ***** Portable */ +/* ***** ***** Network */ +/* ***** ***** Software */ +/* */ +/* File os/linux/linux.c (maintained by: DF6LN) */ +/* */ +/* This file is part of "TheNetNode" - Software Package */ +/* */ +/* Copyright (C) 1998 - 2008 NORD>= 'A') && (*s <= 'Z')) + *s += 'a'-'A'; + s++; + } + return(p); +} + + +/* + String in Grossbuchstaben umwandeln - aus DJGPP GNU-Paket fuer MS-DOS + von D.J. Delorie +*/ + +char * +strupr(char *s) +{ + char *p = s; + while (*s) + { + if ((*s >= 'a') && (*s <= 'z')) + *s += 'A'-'a'; + s++; + } + return(p); +} + +/************************************************************************/ +/* */ +/* Als Ersatz fuer die Funktionen "findfirst" und "findnext" (bei DOS) */ +/* werden die Funktionen "xfindfirst" und "xfindnext" verwendet. Hier */ +/* wird nur der fuer TNN benoetigte Teil in die Struktur ffblk einge- */ +/* tragen. Der zuletzt gefundene Filename muss in ffblk->ff_name erhal- */ +/* ten bleiben, weil dieser beim Aufruf von "xfindnext" gesucht wird. */ +/* */ +/************************************************************************/ + +int +xfindfirst(const char *pathname, struct ffblk *ffblk, int attrib) +{ + char *fnpoi; + DIR *dp; + struct dirent *dirp; + int retval; + + strcpy(ffblk->ff_path, pathname); /* Filename incl. Pfad */ + normfname(ffblk->ff_path); /* '\\' -> '/' */ + fnpoi = strrchr(ffblk->ff_path, '/'); /* Pfad angegeben? */ + if (fnpoi == NULL) /* - nein .. */ + { + strcpy(ffblk->ff_find, ffblk->ff_path); /* Filename kopieren */ + strcpy(ffblk->ff_path, textpath); /* default: textpath */ + } + else /* mit Pfad */ + { + if (fnpoi == ffblk->ff_path+strlen(ffblk->ff_path)) /* ohne Name */ + return(-1); /* Unsinn */ + strcpy(ffblk->ff_find, ++fnpoi); /* nur Filename */ + *fnpoi = NUL; /* Filename im Pfad loeschen */ + } + + if ((dp = opendir(ffblk->ff_path)) == NULL) /* Directory vorhanden? */ + return(-1); + retval = -1; /* default: nix gefunden */ + while ((dirp = readdir(dp)) != NULL) /* Eintrag vorhanden? */ + { + if ((fnmatch(ffblk->ff_find, dirp->d_name, + FNM_PATHNAME|FNM_PERIOD) != 0)) + continue; + strcpy(ffblk->ff_name, dirp->d_name); + setfiletime(ffblk); + retval = 0; + break; + } + closedir(dp); + return(retval); +} + +/************************************************************************/ +/* */ +/* Erst den zuletzt gefundenen Eintrag suchen (steht in ffblk->ff_name) */ +/* und den darauffolgenden passenden Eintrag zurueckmelden. */ +/* */ +/************************************************************************/ + +int +xfindnext(struct ffblk *ffblk) +{ + DIR *dp; + struct dirent *dirp; + int retval; + + if ((dp = opendir(ffblk->ff_path)) == NULL) return(-1); + retval = -1; /* default: nix gefunden */ + while ((dirp = readdir(dp)) != NULL) + { + if ((fnmatch(ffblk->ff_name, dirp->d_name, + FNM_PATHNAME|FNM_PERIOD) != 0)) + continue; + retval = 1; + break; + } + if (retval == 1) + { + retval = -1; /* default: nix gefunden */ + while ((dirp = readdir(dp)) != NULL) + { + if ((fnmatch(ffblk->ff_find, dirp->d_name, + FNM_PATHNAME|FNM_PERIOD) != 0)) + continue; + strcpy(ffblk->ff_name, dirp->d_name); + setfiletime(ffblk); + retval = 0; + break; + } + } + closedir(dp); + return(retval); +} + +/************************************************************************/ +/* */ +/* Bei xfindfirst und xfindnext Datum und Uhrzeit im Fileblock setzen */ +/* */ +/************************************************************************/ + +static void +setfiletime(struct ffblk *ffblk) +{ + struct stat filestat; + struct tm *filetime; + char fn[MAXPATH]; + + sprintf(fn, "%s%s", ffblk->ff_path, ffblk->ff_name); + stat(fn, &filestat); + filetime = gmtime(&filestat.st_mtime); + ffblk->ff_ftime = ((filetime->tm_sec / 2) & 0x1f) + + ((filetime->tm_min & 0x3f) << 5) + + ((filetime->tm_hour & 0x1f) << 11); + ffblk->ff_fdate = (filetime->tm_mday & 0x1f) + + (((filetime->tm_mon & 0x0f) + 1) << 5) + + (((filetime->tm_year - 80) & 0x7f) << 9); +} + +/************************************************************************/ +/* */ +/* Temporaeren Filenamen generieren und pruefen auf Verwendbarkeit, */ +/* d.h. Grossbuchstaben sind nicht erlaubt, damit die Datei bei ccpread */ +/* gefunden wird. */ +/* */ +/* 31.3.02 DG9OBU auf Verwendung von mkstemp() umgestellt */ +/************************************************************************/ + +char * +xtempnam(const char *directory, const char *prefix) +{ + char *fn = NULL; + size_t i; + register int x; + + const char* sixx = "XXXXXX\000"; + + char namebuf[PATH_MAX]; + char xe[128]; + + /* den Dateinamen erstellen, prefix und sechs X fuer mkstemp() */ + memset(xe, 0, sizeof(xe)); + strcpy(xe, prefix); + strcat(xe, sixx); + + /* solange bis brauchbarer Filename gefunden */ + while (fn == NULL) + { + /* Namen zusammenbauen */ + memset(namebuf, 0, sizeof(namebuf)); + strcpy(namebuf, directory); + strcat(namebuf, xe); + + /* File generieren */ + if ((x = mkstemp(&namebuf[0])) > 0) + { + /* und gleich wieder schliessen und loeschen */ + close(x); + unlink(&namebuf[0]); + + /* Namen pruefen */ + for (i = 0; i < strlen(&namebuf[0]); ++i) /* Filenamen untersuchen */ + if (namebuf[i] != tolower(namebuf[i])) /* Grossbuchstabe geht nicht */ + break; + + /* wenn Namenspruefung erfolgreich war, dann Namen melden */ + if (i == strlen(namebuf)) + { + fn = malloc(PATH_MAX); + strcpy(fn, &namebuf[0]); + return(fn); + } + } + else break; + } + + /* nicht erfolgreich */ + return(NULL); +} + +/************************************************************************/ +/* */ +/* Ermitteln des freien Festplattenplatzes in Bytes. */ +/* */ +/* Damit es fuer grosse Festplatten keinen Ueberlauf gibt (Rueckgabe */ +/* ist vom Typ LONG), wird ab 1GB freiem Speicher immer 1GB zurueck- */ +/* gemeldet - sieht da jemand Probleme? */ +/* */ +/************************************************************************/ + +LONG +getdiskfree(char *path) +{ + FILE *fp; + char str[100]; + ULONG frei = 0L; + + sprintf(str, "df %s", path); + + if ((fp = popen(str, "r")) != NULL) + { + fgets(str, 100, fp); + fgets(str, 100, fp); + pclose(fp); + sscanf(str, "%*s %*s %*s %lu", &frei); + + if (frei >= 1024 * 1024 * 1024) + frei = (1024 * 1024 * 1024); + else + frei = (frei * 1024); + } + + return (frei); +} + +/************************************************************************/ +/* */ +/* Fuer das erweiterte AUTOBIN-Protokoll wird die File-Zeit in einem */ +/* Bitfeld gespeichert (s. Doku zu DPBOX), wie es BC++ bei dem Befehl */ +/* getftime verwendet. Hier wird die Linux-Zeit der letzten Aenderung */ +/* verwendet. */ +/* */ +/************************************************************************/ + +int getftime(int handle, struct ftime *ftimep) +{ + struct stat filestat; + struct tm *filetime; + + if (fstat(handle, &filestat) == -1) + return(-1); + + filetime = gmtime(&filestat.st_mtime); + + ftimep->ft_tsec = filetime->tm_sec / 2; + ftimep->ft_min = filetime->tm_min; + ftimep->ft_hour = filetime->tm_hour; + ftimep->ft_day = filetime->tm_mday; + ftimep->ft_month = filetime->tm_mon + 1; + ftimep->ft_year = filetime->tm_year - 80; + + return(0); +} + +/************************************************************************/ +/* */ +/* Fuer DOS-Kompatibilitaet - Programm starten und Exit-Code des */ +/* Programms zurueckgeben */ +/* */ +/************************************************************************/ + +int +spawnl(int mode, const char *path, const char *arg0, const char *arg1, + const char *arg2, const char *arg3, const char *arg4, const char *arg5) +{ + pid_t pid; + int status; + + if (mode != P_WAIT) + { + errno = EINVAL; + return (-1); + } + + if ((pid = fork()) < 0) + { + errno = ENOMEM; + return (-1); + } + else + { + if (pid == 0) + { + if (execl(path, arg0, arg1, arg2, arg3, arg4, arg5, NULL) == -1) + { + exit(-1); + } + } + } + + waitpid(pid, &status, 0); + return(status); +} + +/************************************************************************/ +/* */ +/* Groesse des freien RAM feststellen (wenig aussagekraeftig durch */ +/* SWAP-Partition). Schlaegt der Aufruf fehl, wird 0 gemeldet. */ +/* */ +/************************************************************************/ + +ULONG +coreleft(void) +{ + FILE *fp; + char str[100]; + ULONG frei = 0L; + + if ((fp = popen("free -b", "r")) != NULL) + { + fgets(str, 100, fp); + fgets(str, 100, fp); + pclose(fp); + sscanf(str, "%*s %*s %*s %lu", &frei); + } + return(frei); +} + +/************************************************************************/ +/* */ +/* Befehlszeile auf Zeichen pruefen, die von der Shell ausgewertet */ +/* werden. Diese werden entwertet durch ein vorangesetztes '\\'. */ +/* */ +/************************************************************************/ + +void +security_check(char *cmd) +{ + char *cmdpoi = cmd; + char tmpcmd[MAXPATH]; + register int i = 0; + char ch; + + for (; i < MAXPATH - 2; ++i) + { + ch = *cmdpoi++; + if (ch == NUL) + break; + if (strchr("*?\\|&;()<>$'`{}[]^#\"", ch) != NULL) + tmpcmd[i++] = '\\'; + tmpcmd[i] = ch; + + } + + tmpcmd[i] = NUL; + strcpy(cmd, tmpcmd); +} + +/************************************************************************/ +/* */ +/* 10ms-Ticker updaten */ +/* */ +/************************************************************************/ +void +update_timer(void) +{ + fd_set rmask; + struct timeval timevalue; + int max_fd = 0; + int count; + register int i; + int len; + char buffer[1024]; + socklen_t clilen; + struct sockaddr_un cli_addr; + static UWORD roundcounter = 1; +#ifndef NO_WATCHDOG + int lasttic10 = tic10; +#endif +#ifdef KERNELIF + int kif_fd = -1; +#endif + + gettimeofday(&tv, &tz); + + tic10 = (tv.tv_sec - tv_old.tv_sec) * 100 + + (tv.tv_usec - tv_old.tv_usec) / 10000; + +#ifndef NO_WATCHDOG + if (tic10 - lasttic10) + if (write(watch_dog[1], "\0", 1) != 1) + { + exit(1); + } +#endif + + FD_ZERO(&rmask); + + /* Behandlung der Konsole bzw. Socket-Verbindung */ + switch (console_type) + { + /* Ein/Ausgabe ueber normales Terminal */ + case CONS_TERM_RUNNING: + FD_SET(0, &rmask); /* Eingabe Console */ + max_fd = 1; + break; + + /* Ein/Ausgabe ueber Socket, aber noch nicht verbunden */ + case CONS_SOCKET_WAITING: + FD_SET(sockfd, &rmask); + if (sockfd > max_fd - 1) + max_fd = sockfd + 1; + break; + + /* Ein/Ausgabe ueber verbundenen Socket */ + case CONS_SOCKET_CONNECTED: + FD_SET(consockfd, &rmask); + if (consockfd > max_fd - 1) + max_fd = consockfd + 1; + break; + + /* Alles andere ... */ + default: + break; + } + +/* + + if (!use_socket) + { + + FD_SET(0, &rmask); + max_fd = 1; + } + else + { + if (!soc_con) + { + FD_SET(sockfd, &rmask); + if (sockfd > max_fd - 1) + max_fd = sockfd + 1; + } + else + { + + FD_SET(consockfd, &rmask); + if (consockfd > max_fd - 1) + max_fd = consockfd + 1; + } + } +*/ + + if (kiss_active) + { + for (i = 0; i < L1PNUM; ++i) + { + if (l1port[i].kisslink < 0) + continue; + +#ifdef VANESSA + if (l1port[i].kisstype == KISS_VAN) + continue; +#endif +#ifdef AX_IPX + if (l1port[i].kisstype == KISS_IPX) + continue; +#endif +#ifdef AX25IP + if (l1port[i].kisstype == KISS_AXIP) + continue; +#endif +#ifdef KERNELIF + if ( (l1port[i].kisstype == KISS_KAX25) + || (l1port[i].kisstype == KISS_KAX25KJD)) + continue; +#endif +#ifdef SIXPACK + if (l1port[i].kisstype == KISS_6PACK) + continue; +#endif + + if (l1port[i].port_active) + { + FD_SET(l1port[i].kisslink, &rmask); + if (l1port[i].kisslink > max_fd -1) + max_fd = l1port[i].kisslink + 1; + } + } + } + +#ifdef KERNELIF + /* IP-Interface Filedescriptor ermitteln */ + if ((kif_fd = ifip_active()) != -1) /* ein aktives Kernelinterface */ + { + FD_SET(kif_fd, &rmask); + if (kif_fd > max_fd - 1) + max_fd = kif_fd + 1; + } +#endif + + /* fuer alle Interfaces die benutzten Filedescriptoren fuer select() */ + /* ermitteln und eintragen */ + for (i = 0; i < L1PNUM; ++i) + { + /* nur aktive Ports bearbeiten */ + if ( (l1port[i].kisslink < 0) || (l1port[i].port_active != TRUE) +#ifdef SIXPACK + || (l1port[i].kisstype == KISS_6PACK) /* der hat hier nichts zu suchen */ +#endif + ) + continue; + + + /* Interfacetypen durchgehen */ + if ( +#ifdef KERNELIF + (l1port[i].kisstype == KISS_KAX25) + || (l1port[i].kisstype == KISS_KAX25KJD) +#endif +#if defined(KERNELIF) && defined(AX_IPX) + || +#endif +#ifdef AX_IPX + (l1port[i].kisstype == KISS_IPX) +#endif + ) + { + FD_SET(l1port[i].kisslink, &rmask); + if (l1port[i].kisslink > max_fd -1) + max_fd = l1port[i].kisslink + 1; + } + } /* for(...) */ + + timevalue.tv_usec = 10000; + timevalue.tv_sec = 0; + + if (++roundcounter < maxrounds) /* schon genug Runden vergangen? */ + timevalue.tv_usec = 0; + else + roundcounter = 0; /* Durchlaufzaehler ruecksetzen */ + + count = select(max_fd, &rmask, NULL, NULL, &timevalue); + + if (count == -1) + return; + + /* Konsolen/Socketverbindung bearbeiten */ + switch (console_type) + { + /* Konsole ist ein Terminal */ + case CONS_TERM_RUNNING: + /* Zeichen auf der Standardeingabe ? */ + if (FD_ISSET(0, &rmask)) + { + if ((len = read(0, buffer, 1024)) != -1) + host_to_queue(buffer, len); + else + { + /* Oh, oh, Fehler beim Lesen von der Konsole */ + /* Es werden nun weitere Konsolenoperationen */ + /* unterdrueckt. */ + console_type = CONS_NO_CONSOLE; + } + } + break; + + /* Socket wartet auf Verbindung */ + case CONS_SOCKET_WAITING: + /* Wartende Verbindung annehmen */ + if (FD_ISSET(sockfd, &rmask)) + { + clilen = sizeof(cli_addr); + consockfd = accept(sockfd, (struct sockaddr *) &cli_addr, &clilen); + if (consockfd >= 0) + console_type = CONS_SOCKET_CONNECTED; + } + break; + + /* Daten von verbundenem Socket */ + case CONS_SOCKET_CONNECTED: + if (FD_ISSET(consockfd, &rmask)) + { + len = read(consockfd, buffer, 1024); + if ((len == -1) || (len == 0)) + { + close(consockfd); + consockfd = -1; + console_type = CONS_SOCKET_WAITING; + } + else + host_to_queue(buffer, len); + } + break; + + default: + break; + } + +/* + + if (!use_socket) + { + if (FD_ISSET(0, &rmask)) + if ((len = read(0, buffer, 1024)) != 0) + host_to_queue(buffer, len); + } + else + { + if (!soc_con) + { + if (FD_ISSET(sockfd, &rmask)) + { + clilen = sizeof(cli_addr); + consockfd = accept(sockfd, (struct sockaddr *) &cli_addr, &clilen); + if (consockfd >= 0) + soc_con = TRUE; + } + } + else + if (FD_ISSET(consockfd, &rmask)) + { + len = read(consockfd, buffer, 1024); + if ((len == -1) || (len == 0)) + { + close(consockfd); + soc_con = FALSE; + } + else + host_to_queue(buffer, len); + } + } +*/ + +#ifdef KERNELIF + /* IP-Interface RX */ + if ((kif_fd != -1) && (FD_ISSET(kif_fd, &rmask))) + ifip_frame_to_router(); +#endif + + /* alle Ports durchgehen */ + for (i = 0; i < L1PNUM; ++i) + { + /* unbenutzte Ports nicht bearbeiten */ + if ( (l1port[i].kisslink < 0) || (l1port[i].port_active != TRUE) +#ifdef SIXPACK + || (l1port[i].kisstype == KISS_6PACK) /* der hat hier nichts zu suchen */ +#endif + ) + continue; + + + /* pruefen ob dieser Port einen lesbaren Filedescriptor hat */ + if (FD_ISSET(l1port[i].kisslink, &rmask)) + { + /* je nach Interfacetyp den richtigen RX aufrufen */ + switch (l1port[i].kisstype) + { +#ifdef KERNELIF + /* Kernel-AX25-Port RX */ + case KISS_KAX25 : + case KISS_KAX25KJD : ifax_rx(l1port[i].kisslink); + break; +#endif +#ifdef AX_IPX + /* AXIPX-RX */ + case KISS_IPX : axipx_recv(); + break; +#endif + default : continue; + } + } + } + + if (kiss_active) + { + for (i = 0; i < L1PNUM; ++i) + { + if (l1port[i].kisslink == -1) + continue; +#ifdef VANESSA + if (l1port[i].kisstype == KISS_VAN) + continue; +#endif +#ifdef AX_IPX + if (l1port[i].kisstype == KISS_IPX) + continue; +#endif +#ifdef AX25IP + if (l1port[i].kisstype == KISS_AXIP) + continue; +#endif +#ifdef KERNELIF + if ( (l1port[i].kisstype == KISS_KAX25) + || (l1port[i].kisstype == KISS_KAX25KJD)) + continue; +#endif +#ifdef SIXPACK + if (l1port[i].kisstype == KISS_6PACK) + continue; +#endif + if (l1port[i].port_active) + if (FD_ISSET(l1port[i].kisslink, &rmask)) + if ((len = read(l1port[i].kisslink, buffer, 1024)) != 0) + framedata_to_queue(i, buffer, len); + } + } +} + +/************************************************************************/ +/* */ +/* Rechner neu starten */ +/* */ +/************************************************************************/ + +void +reboot_system(void) +{ + exit_all(); + sync(); + /* CRASH(); */ + /*system("/sbin/shutdown -r now");*/ +/* Hierher wird man wohl nur kommen, wenn tnn nicht als root gestartet */ +/* wurde. Nun gibt es 2 Moeglichkeiten: entweder wir starten von vorne, */ +/* weil die Resourcen ja breits freigegeben wurden, oder aber wir */ +/* beenden das Programm, weil das ja mehr oder weniger gefordert wurde. */ +/* Sinnvoller ist es wohl, wenn wir das Programm verlassen, in der */ +/* Hoffnung, dass es danach regulaer von einem Batch erneut gestartet */ +/* wird. Das ist jedenfalls besser, als nix zu tun. */ + exit(1); +} + +/************************************************************************/ +/* */ +/* Shell-Befehl - Linux-spezifischer Teil: */ +/* Das gewuenschte Programm wird als Hintergrundprozess gestartet. */ +/* */ +/************************************************************************/ + +BOOLEAN +tnnshell(char *cmdline) +{ + char sysline[MAXPATH + 1]; + + char cFirstArg[MAXPATH + 1]; + + char *pFirstArg = NULL; + + + MBHEAD* mbp; + + struct termios term; + + /* In TNB-Files darf die interaktive Shell nicht verwendet werden */ + if ((tnnb_aktiv == TRUE) && (strlen(cmdline) == 0)) + { + putmsg("Interactive shell is not allowed in tnb-files !\r"); + return (FALSE); + } + + /* Haben wir eine Shell ? */ + if (cShell[0] == 0) + { + putmsg("No shell set, use 'setshell' to set one !\r"); + return (FALSE); + } + + /* Initialisieren */ + memset(sysline, 0, MAXPATH); + memset(cFirstArg, 0, MAXPATH); + memset(&term, 0, sizeof(struct termios)); + + term.c_iflag = ICRNL | IXOFF; + term.c_oflag = OPOST | ONOCR; /* ONLCR */ + term.c_cflag = CS8 | CREAD | CLOCAL; + term.c_lflag = ISIG | ICANON; + +/* + term.c_iflag = IGNCR | IXOFF; + term.c_oflag = OPOST | ONLCR | ONLRET | OCRNL; + term.c_cflag = CS8 | CREAD | CLOCAL; + term.c_lflag = ISIG | ICANON; +*/ + + term.c_cc[VINTR] = 3; /* ^C */ + term.c_cc[VSUSP] = 26; /* ^Z */ + term.c_cc[VQUIT] = 28; + term.c_cc[VERASE] = 8; /* ^H */ + term.c_cc[VKILL] = 24; /* ^X */ + term.c_cc[VEOF] = 4; /* ^D */ + + strncpy(sysline, cmdline, MAXPATH); + sysline[MAXPATH] = NUL; /* Sicher ist sicher ... */ + + /* Das erste Argument fuer exec bestimmen */ + if ((pFirstArg = strrchr(cShell, '/')) == NULL) + { + pFirstArg = cShell; + } + else + { + ++pFirstArg; /* wir wollen das erste Zeichen hinter dem "/" */ + } + + if (strlen(cmdline) == 0) + cFirstArg[0] = '-'; + + strcat(cFirstArg, pFirstArg); + + /* neue Shell abforken */ + if ((userpo->child_pid = forkpty(&userpo->child_fd, NULL, &term, NULL)) == -1) + { + /* forkpty() nicht moeglich */ + userpo->child_pid = 0; + putmsg("Can't fork child process !\r"); + return(FALSE); + } + else + { + if (userpo->child_pid == 0) /* Kind-Prozess (die Shell) */ + { + if (strlen(cmdline) == 0) + { + execl(cShell, cFirstArg, NULL); + } + else + { + execl(cShell, cFirstArg, "-c", cmdline, NULL); + } + + /* Wenn wir hier ankommen, dann ist wirklich was nicht ok ... */ + exit(-1); + } + else /* Hauptprogramm */ + { + /* Timeout und Interaktivitaet setzen je nach Shell-Typ */ + /* Achtung, Timeout in 100ms-Schritten ! */ + if (strlen(cmdline) == 0) + { + mbp = getmbp(); + putprintf(mbp, "Invoking shell, type 'exit' to end your session.\r"); + seteom(mbp); + userpo->child_timeout = 30000; /* 5 Min. Timeout */ + userpo->child_iactive = TRUE; /* interaktive Shell */ + } + else + { + userpo->child_timeout = 6000; /* 1 Min. Timeout */ + userpo->child_iactive = FALSE; /* keine interaktive Shell */ + } + + userpo->status = US_EXTP; /* externes Programm laeuft */ + return(TRUE); + } + } + return(TRUE); +} + +/************************************************************************/ +/* */ +/* Pruefen, ob Kind-Prozesse beendet sind (vom Sysop gestartete externe */ +/* Programme). Bei Zeitueberschreitung wird das Programm mit einer */ +/* entsprechenden Fehlermeldung abgebrochen. */ +/* */ +/************************************************************************/ + +void +shellsrv(void) +{ + pid_t c_pid; + + MBHEAD* mbp; + + for (userpo = (USRBLK *) usccpl.head; + userpo != (USRBLK *) &usccpl; + userpo = (USRBLK *) userpo->unext) + { + if (userpo->status != US_EXTP) /* externer Prozess aktiv? */ + continue; /* nein .. */ + + if (userpo->child_pid == 0) /* externer Prozess aktiv? */ + continue; /* nein .. */ + + c_pid = waitpid(userpo->child_pid, /* dieser Prozess beendet? */ + NULL, WNOHANG); + + /* Prozess noch nicht beendet */ + if (c_pid == 0) /* noch nicht fertig? */ + { + /* Timeout-Warnung fuer interaktive Shell */ + if ((userpo->child_iactive == TRUE) && (userpo->child_timeout <= 6000)) + { + MBHEAD* mbp; + + switch (userpo->child_timeout) + { + case 1000 : + case 2000 : + case 3000 : + case 6000 : mbp = putals("WARNING: Your shell times out in "); + putprintf(mbp, "%u seconds !!!\r", (userpo->child_timeout / 100)); + seteom(mbp); + break; + + default : break; + } + } + + /* Shell-Timeout */ + if (--userpo->child_timeout == 0) /* zu lange inaktiv? */ + { + kill(-(userpo->child_pid), SIGKILL); /* Abbruch (Watchdog) */ + c_pid = waitpid(userpo->child_pid, /* Prozess-Status holen */ + NULL, 0); /* sonst gips 'n Zombie */ + userpo->child_pid = 0; + putmsg("SHELL SESSION ABORTED (TIMEOUT)\r"); + break; + } + else + { + shell_to_user(); + continue; + } + } + + /* Shell ist geschlossen */ + if (userpo->child_fd != -1) + { + if (c_pid > 0) + shell_to_user(); /* Letzte Daten abholen */ + + /* Shell nun schon geschlossen ? */ + if (userpo->child_fd != -1) + { + close(userpo->child_fd); + userpo->child_fd = -1; + } + } + + userpo->child_pid = 0; /* Prozess ist fertig */ + userpo->child_timeout = 0; + userpo->child_iactive = FALSE; + userpo->status = US_CCP; + + /* und ab die Post ... */ + mbp = getmbp(); + prompt(mbp); + seteom(mbp); + } +} + +/************************************************************************/ +/* */ +/* Daten von der Shell abholen und zum User bringen */ +/* */ +/************************************************************************/ + +void +shell_to_user(void) +{ + fd_set rset; + + struct timeval tvalue; + + int i; + + UBYTE usrtype; + + /* nur gueltige Descriptoren */ + if (userpo->child_fd == -1) + return; + + /* Pruefen, ob die Verbindung noch Daten aufnehmen kann, ist eine L2/L4- */ + /* Verbindung zu voll, dann keine neuen Pakete generieren. An die Hostkonsole wird */ + /* ungebremst ausgegeben. */ + usrtype = g_utyp(userpo->uid); + + if ( ((usrtype == L2_USER) || (usrtype == L4_USER)) + && (((LNKBLK *)g_ulink(userpo->uid))->tosend > 100) + ) + return; + + FD_ZERO(&rset); + FD_SET(userpo->child_fd, &rset); + + tvalue.tv_usec = 0; + tvalue.tv_sec = 0; + + /* Daten holen */ + if ((i = select((userpo->child_fd + 1), &rset, NULL, NULL, &tvalue)) < 0) + { + putmsg("ERROR while select()-ing descriptor !!!\r"); + close(userpo->child_fd); + userpo->child_fd = -1; + userpo->child_timeout = 1; /* Aufraeumen macht shellsrv() */ + } + else + { + /* Daten Shell -> User */ + if ((i > 0) && (FD_ISSET(userpo->child_fd, &rset))) + { + unsigned char data[8192]; + + unsigned int uZaehler; + + ssize_t rd; + + + MBHEAD* mbp; + + if ((rd = read(userpo->child_fd, data, 8192)) == -1) + { + /* Ist der abgearbeitete Befehl ohne jegliche Rueckgabe, dann wird der Fehler 5 */ + /* erzeugt. Im nicht-interaktiven Modus unterdruecken wir die Fehlermeldung, im */ + /* interaktiven Modus wird er normal angezeigt. */ + if ((errno == EIO) && (userpo->child_iactive == TRUE)) + { + mbp = putals(""); + putprintf(mbp, "ERROR %u while read()-ing descriptor !!! Shell terminated !\r", errno); + seteom(mbp); + } + close(userpo->child_fd); + userpo->child_fd = -1; + userpo->child_timeout = 1; /* Aufraeumen macht shellsrv() */ + } + + if (rd > 0) + { + mbp = getmbp(); + + for (uZaehler = 0; uZaehler < rd; ++uZaehler) + { + if (data[uZaehler] == 0x0D) + continue; + + if (data[uZaehler] == 0x0A) + { + putchr(0x0D, mbp); + continue; + } + + putchr(data[uZaehler], mbp); + } + + seteom(mbp); + + /* Timeout ruecksetzen */ + if (userpo->child_iactive == TRUE) + userpo->child_timeout = 30000; + } + } + } +} + +/************************************************************************/ +/* */ +/* User-Eingabe in mhdp verarbeiten */ +/* */ +/************************************************************************/ + +BOOLEAN +l7tosh(MBHEAD *mhdp) +{ + if (userpo->status == US_EXTP) /* externer Prozess aktiv? */ + { + if (userpo->child_iactive == FALSE) + { + dealmb(mhdp); /* Abbruchzeile ignorieren */ + userpo->mbhd = NULL; + kill(-(userpo->child_pid), SIGKILL); /* Abbruch (Watchdog) */ + waitpid(userpo->child_pid, /* Prozess-Status holen */ + NULL, 0); /* sonst gips 'n Zombie */ + putmsg("SHELL ABORTED by User\r"); + userpo->child_pid = 0; /* Prozess ist fertig */ + userpo->child_fd = -1; + userpo->child_iactive = FALSE; + userpo->child_timeout = 0; + userpo->status = US_CCP; + return(TRUE); + } + else + { + struct timeval tvalue; + int i; + + fd_set wset; + + FD_ZERO(&wset); + FD_SET(userpo->child_fd, &wset); + + tvalue.tv_usec = 0; + tvalue.tv_sec = 0; + + if ((i = select((userpo->child_fd + 1), NULL, &wset, NULL, &tvalue)) < 0) + { + putmsg("ERROR while select()-ing descriptor !!!)\r"); + userpo->child_fd = -1; + userpo->child_timeout = 1; /* Aufraeumen macht shellsrv() */ + } + else + { + /* Daten User -> Shell */ + if ((i > 0) && (FD_ISSET(userpo->child_fd, &wset) && (mhdp->mbgc < mhdp->mbpc))) + { + unsigned char data[1024]; + unsigned int uBufSize = 0; + + while (mhdp->mbgc < mhdp->mbpc) + data[uBufSize++] = getchr(mhdp); + + /* Daten zum Shell-Child schicken */ + if (write(userpo->child_fd, data, uBufSize) < 0) + { + /* Oh oh, das hat nicht geklappt */ + userpo->child_fd = -1; + userpo->child_timeout = 1; /* Aufraeumen macht shellsrv() */ + } + else + { + /* Timeout ruecksetzen */ + if (userpo->child_iactive == TRUE) + userpo->child_timeout = 30000; + } + + dealmb(mhdp); + userpo->mbhd = NULL; + } + } + } + return (TRUE); + } + return (FALSE); +} + +/************************************************************************/ +/* */ +/* Filenamen pruefen */ +/* */ +/************************************************************************/ + +BOOLEAN +good_file_name(const char *file) +{ + if ( (strncmp("/bin/", file, 5) == 0) + || (strncmp("/dev/", file, 5) == 0) + || (strncmp("/proc/", file, 6) == 0) + || (strncmp("/sbin/", file, 6) == 0) + || (strncmp("/usr/bin/", file, 9) == 0) + || (strncmp("/usr/sbin/", file, 10) == 0) + || (strncmp("/usr/local/bin/", file, 16) == 0) + || (strncmp("/usr/local/sbin/", file, 17) == 0)) + return(FALSE); + + return(TRUE); +} + +/************************************************************************/ +/* */ +/* */ +/************************************************************************/ + +void +tnnexec(char *file_name) +{ + if (access(file_name, X_OK) == 0) /* nur ausfuehrbares Programm */ + { + exit_all(); /* Resourcen freigeben */ + execl(file_name, NULL, NULL); /* Programm starten */ +/* Hierher darf man eigentlich nicht kommen! Daher verlassen wir das */ +/* Programm in der Hoffnung, dass es danach regulaer von einem Batch */ +/* erneut gestartet wird. */ + exit(1); + } +} + +/************************************************************************/ +/* */ +/* */ +/************************************************************************/ + +void +init_console(void) +{ +#ifdef L1TCPIP + /* Interface Initialisieren. */ + InitIFC(); +#endif /* L1TCPIP */ + + if (console_type == CONS_TERM_DO_SETUP) + { + setvbuf(stdout, NULL, _IONBF, 0); /* Ausgabe ungepuffert */ + tcgetattr(fileno(stdin), &oconin_termios); + tcgetattr(fileno(stdout), &oconout_termios); + nconin_termios = oconin_termios; + nconin_termios.c_cc[VTIME] = 0; + nconin_termios.c_cc[VMIN] = 1; + nconin_termios.c_cc[VSTART] = -1; + nconin_termios.c_cc[VSTOP] = -1; + nconin_termios.c_iflag = IGNBRK; + nconin_termios.c_oflag = OPOST|ONLCR; + nconin_termios.c_lflag = 0; + nconin_termios.c_cflag = (CS8|CREAD|CLOCAL); + tcsetattr(fileno(stdin), TCSADRAIN, &nconin_termios); + nconout_termios = oconout_termios; + nconout_termios.c_cc[VTIME] = 0; + nconout_termios.c_cc[VMIN] = 1; + nconout_termios.c_cc[VSTART] = -1; + nconout_termios.c_cc[VSTOP] = -1; + nconout_termios.c_iflag = IGNBRK|ICRNL; + nconout_termios.c_oflag = OPOST|ONLCR|ONLRET|OCRNL; + nconout_termios.c_lflag = 0; + nconout_termios.c_cflag = (CS8|CREAD|CLOCAL); + tcsetattr(fileno(stdout), TCSAFLUSH, &nconout_termios); + + consfile = stdout; + console_type = CONS_TERM_RUNNING; + } + else + consfile = NULL; + + hostq_root = NULL; + hostq_last = NULL; + hostq_len = 0; +} + +/************************************************************************/ +/* */ +/* */ +/************************************************************************/ + +void +exit_console(void) +{ + struct hostqueue *hostq_ptr; + + while (hostq_root != NULL) + { + hostq_ptr = hostq_root; + hostq_root = hostq_ptr->next; + free(hostq_ptr); + } + + hostq_last = NULL; + hostq_len = 0; + exit_proc(); + + if (console_type != CONS_TERM_RUNNING) + return; + + tcsetattr(1, TCSADRAIN, &oconout_termios); + tcsetattr(0, TCSADRAIN, &oconin_termios); + + console_type = CONS_NO_CONSOLE; +} + +/************************************************************************/ +/* */ +/* */ +/************************************************************************/ + +static void +alloc_hostqbuf(void) +{ + struct hostqueue *hostq_ptr; + + hostq_ptr = (struct hostqueue *) malloc(sizeof(struct hostqueue)); + if (hostq_ptr == NULL) + { + exit_all(); + exit(1); + } + + hostq_ptr->first = 0; + hostq_ptr->last = 0; + hostq_ptr->next = NULL; + if (hostq_root == NULL) + { + hostq_root = hostq_ptr; + } + else + { + hostq_last->next = hostq_ptr; + hostq_last = hostq_ptr; + } + + hostq_last = hostq_ptr; +} + +/* put one character in host-queue */ + +static void +puthostq(char ch) +{ + struct hostqueue *hostq_ptr; + + if (hostq_root == NULL) + alloc_hostqbuf(); + + hostq_ptr = hostq_last; + + if (hostq_ptr->last >= HOSTQ_BUFLEN) + { + alloc_hostqbuf(); + hostq_ptr = hostq_last; + } + + hostq_ptr->buffer[hostq_ptr->last] = ch; + hostq_ptr->last++; + hostq_len++; +} + +/* get one character out of host-queue */ + +static char +gethostq(void) +{ + struct hostqueue *hostq_ptr; + char ch; + + if ((hostq_len == 0) || (hostq_root == NULL)) /* sanity check */ + return(0); + + hostq_ptr = hostq_root; + ch = hostq_ptr->buffer[hostq_ptr->first]; + hostq_ptr->first++; + hostq_len--; + + if ( (hostq_ptr->first == hostq_ptr->last) + || (hostq_ptr->first == HOSTQ_BUFLEN)) + { + if (hostq_ptr->next == NULL) + { + hostq_root = NULL; + hostq_last = NULL; + } + else + hostq_root = hostq_ptr->next; + + free(hostq_ptr); + } + return(ch); +} + +/************************************************************************/ +/* */ +/* */ +/************************************************************************/ + +void +hputc(char c) +{ + int res; + + if (tnb_ch) + { + if (consfile != NULL) + fputc(c, consfile); + + return; + } + + switch (console_type) + { + case CONS_SOCKET_CONNECTED: + + res = write(consockfd, &c, 1); + + if (res == -1) + { + close(consockfd); + consockfd = -1; + console_type = CONS_SOCKET_WAITING; + } + + break; + + case CONS_TERM_RUNNING: + + if ((c == '\n') || (c == '\r')) + putchar(LF); + else + putchar(c); + break; + + default: + break; + + } +} + +/* return if character available */ + +BOOLEAN +ishget(void) +{ + return(hostq_len != 0); +} + +/* return if output to console is stopped */ + +BOOLEAN +ishput(void) +{ + return(FALSE); +} + +/* get one character from console */ + +char +hgetc(void) +{ + char ch = gethostq(); + + if (console_type == CONS_TERM_RUNNING) + if (ch == LF) + ch = CR; + + return (ch); +} + +/* put received characters in hostbuffer */ + +static void +host_to_queue(char *buffer, int len) +{ + char *bufptr; + register int i = 0; + + bufptr = buffer; + + while (i < len) + { + puthostq(*bufptr); + ++i; + bufptr++; + } +} + +/************************************************************************/ +/* */ +/* */ +/************************************************************************/ + +BOOLEAN +init_hardware(int argc, char *argv[]) +{ + char *pEnvShell = NULL; + int scanned = 1; + + + umask(0); + time(&sys_time); + + /* Kommandozeilenparameter auswerten */ + /* Den Verbose-Modus schon hier feststellen */ + while (scanned < argc) + { + /* Parameter "-v" (ausfuehrlichere Meldungen) */ + if (strcmp(argv[scanned], "-v") == 0) + { + bVerbose = TRUE; + } + ++scanned; + } + + VMSG("--- Verbose logging started !\n"); + + /* Shell loeschen */ + memset(cShell, 0, sizeof(cShell)); + + VMSG("--- Determining shell-program ...\n"); + + /* Shell aus dem Environment holen */ + if ((pEnvShell = getenv("SHELL")) == NULL) + fprintf(stderr, "Warning: SHELL not set, can't use external programs !!!\n"); + else + { + /* Shell kopieren */ + strncpy(cShell, pEnvShell, sizeof(cShell)); + + /* und sicherheitshalber abschliessen */ + cShell[sizeof(cShell)] = 0; + VMSG("--- Shell is '%s'\n", cShell); + } + + VMSG("--- Reading ini-file ...\n"); + if (read_init_file(argc, argv)) + return(TRUE); + + VMSG("--- Entering pid-file checks ...\n"); + if (!init_proc()) + exit(1); +/* + if (tnn_errfile[0] != NUL) + { + } +*/ + VMSG("--- Allocating mem for %ld buffers ...\n", tnn_buffers); + + RAMBOT = (char *)malloc(tnn_buffers * sizeof(MAX_BUFFER)); + RAMTOP = RAMBOT + tnn_buffers * sizeof(MAX_BUFFER); + + if (RAMBOT == NULL) + { + VMSG("!!! Allocation mem for %ld buffers failed, trying to allocate for %u buffers now ...\n", tnn_buffers, TNN_BUFFERS); + RAMBOT = (char *)malloc(TNN_BUFFERS * sizeof(MAX_BUFFER)); + RAMTOP = RAMBOT + TNN_BUFFERS * sizeof(MAX_BUFFER); + if (RAMBOT == NULL) + { + fprintf(stderr, "malloc for buffers failed\n"); + exit(1); + } + else + tnn_buffers = TNN_BUFFERS; + } + + if (kiss_active) + { + VMSG("--- Initializing KISS-interfaces ...\n"); + if (init_kisslink()) + { + free(RAMBOT); + exit(1); + } + } + + if (console_type == CONS_SOCKET_DO_SETUP) + { + VMSG("--- Initializing UNIX-socket interface ...\n"); + if ((sockfd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) + { + fprintf(stderr, "Can't open socket !\n"); + fprintf(stderr, "Error %u : %s\n", errno, strerror(errno)); + fprintf(stderr, "Exiting.\n"); + close(sockfd); + free(RAMBOT); + + if (kiss_active) + exit_kisslink(); + exit(1); + } + + memset((char *) &serv_addr, 0, sizeof(serv_addr)); + serv_addr.sun_family = AF_UNIX; + strcpy(serv_addr.sun_path, tnn_socket); + servlen = strlen(serv_addr.sun_path) + sizeof(serv_addr.sun_family); + unlink(serv_addr.sun_path); + + if (bind(sockfd, (struct sockaddr *) &serv_addr, servlen) < 0) + { + fprintf(stderr, "Can't bind socket !\n"); + fprintf(stderr, "Error %u : %s\n", errno, strerror(errno)); + fprintf(stderr, "Exiting.\n"); + close(sockfd); + free(RAMBOT); + + if (kiss_active) + exit_kisslink(); + exit(1); + } + + if (listen(sockfd, 5) < 0) + { + fprintf(stderr, "Can't listen to socket !\n"); + fprintf(stderr, "Error %u : %s\n", errno, strerror(errno)); + fprintf(stderr, "Exiting.\n"); + free(RAMBOT); + if (kiss_active) + exit_kisslink(); + exit(1); + } + + console_type = CONS_SOCKET_WAITING; + + if (getppid() != 1) + { + if (fork() != 0) + { + /* Parent */ + exit_proc(); /* eigenes PID-File loeschen */ + exit(0); + } + else + { + sleep(1); /* warten, dass Parent sein PID-File loescht */ + /* Child */ + if (!init_proc()) + exit(1); + } + } + } +#ifndef NO_WATCHDOG + VMSG("--- Initializing watchdog ...\n"); + watchdog_init(); +#endif + + VMSG("--- Installing signal-handlers ...\n"); +#ifdef DEBUG_MODUS + signal(SIGSEGV, sigsegv); + signal(SIGTERM, sigterm); +#endif + + signal(SIGHUP, SIG_IGN); + signal(SIGTSTP, SIG_IGN); + signal(SIGTTIN, SIG_IGN); + signal(SIGTTOU, SIG_IGN); + signal(SIGPIPE, SIG_IGN); + + gettimeofday(&tv, &tz); + tv_old = tv; + + return(FALSE); +} + +#ifndef NO_WATCHDOG +/************************************************************************/ +/* */ +/* Watchdog - ein vom TNN-Hauptprogramm unabhaengiger Prozess muss */ +/* regelmaessig vom Hauptprogramm Daten erhalten. Bleiben diese Daten */ +/* laenger als 60s aus, wird TNN beendet. */ +/* */ +/************************************************************************/ +static void +watchdog_init(void) +{ + pid_t pid; + time_t wdzeit; + time_t zeit; + int num; + int status; + char buf[1000]; + + VMSG("--- Initializing watchdog ...\n"); + + if (pipe(watch_dog) < 0) + { + fprintf(stderr, "Error %u while creating watchdog's pipe: %s\n", errno, strerror(errno)); + fprintf(stderr, "Exiting.\n"); + exit(1); + } + + /* Descriptoren auf non-blocking einstellen */ + num = fcntl(watch_dog[0], F_GETFL, 0); + num |= O_NONBLOCK; + fcntl(watch_dog[0], F_SETFL, num); + + num = fcntl(watch_dog[1], F_GETFL, 0); + num |= O_NONBLOCK; + fcntl(watch_dog[1], F_SETFL, num); + + /* Forken */ + if ((pid = fork()) < 0) + { + fprintf(stderr, "Error %u while fork()-ing in watchdog: %s\n", errno, strerror(errno)); + fprintf(stderr, "Exiting.\n"); + exit(1); + } + else + { + /* Na wer sind wir denn ... */ + if (pid == 0) + { + /* wir sind Child (das Hauptprogramm) */ + wdpid[0] = getpid(); + close(watch_dog[0]); + + sleep(1); + + return; + } + else + { + /* und wir sind Parent (der Watchdog) */ + wdpid[0] = pid; /* Child */ + wdpid[1] = getpid(); /* Parent */ + + close(watch_dog[1]); + + VMSG(" +-> main loop has pid %u\n", wdpid[0]); + VMSG(" +-> watchdog has pid %u\n", wdpid[1]); + + signal(SIGHUP, SIG_IGN); + signal(SIGTSTP, SIG_IGN); + signal(SIGTTIN, SIG_IGN); + signal(SIGTTOU, SIG_IGN); + signal(SIGSEGV, sigsegv); + + time(&zeit); + time(&wdzeit); + + LOOP + { + /* Hat sich das Child beendet ? */ + if (waitpid(wdpid[0], &status, WNOHANG)) + { + /* Child hat sich beendet */ + /* Es gibt nichts mehr zu killen, pid wegwerfen */ + wdpid[0] = 0; + + VMSG("!!! watchdog: child has exited !\n"); + + if (bVerbose == TRUE) + { + if (WIFEXITED(status)) + VMSG(" +-> child exited with code %u\n", WEXITSTATUS(status)); + + if (WIFSIGNALED(status)) + { + VMSG(" +-> child exited because of signal %u\n", WTERMSIG(status)); + + if (WCOREDUMP(status)) + VMSG(" +-> child wrote a core dump !\n"); + } + } + + break; + } + + /* Child sollte laufen, dann schauen, ob es was geschickt hat */ + num = read(watch_dog[0], &buf, sizeof(buf)); + + if ( (num == 0) /* schreibendes Ende der Pipe geschlossen */ + || ((num < 0) && (errno != EWOULDBLOCK))) /* sonstige Fehler */ + break; + + if (num > 0) + { + time(&wdzeit); + continue; + } + + time(&zeit); + + if ((zeit - wdzeit) > 60) + break; + + sleep(1); + } + + time(&wdzeit); + close(watch_dog[0]); + + if (wdpid[0] != 0) + { + VMSG("!!! watchdog: child has exited abnormally !\n"); + + kill(-wdpid[0], SIGSEGV); + /* Falls aus irgendeinem Grund SIGSEGV nicht zum Programmende fuehrt, */ + /* kommt ein SIGKILL hinterher. Damit wird sichergestellt, dass der */ + /* Childprozess beendet wird. */ + sleep(1); + kill(-wdpid[0], SIGKILL); + } + + /* Hauptprogramm beenden */ + exit(0); + } + } +} +#endif + +/************************************************************************/ +/* */ +/* */ +/************************************************************************/ + +void +exit_hardware(void) +{ + free(RAMBOT); + + if (kiss_active) + exit_kisslink(); +} + +#ifdef DEBUG_MODUS +/************************************************************************/ +/* Signalbehandlungsfunktion fuer das Signal SIGTERM */ +/************************************************************************/ +static void +sigterm(int signo) +{ + signal(SIGTERM, SIG_IGN); + printf("sigterm\n"); + quit_program(-1); +} + +void +sigsegv(int signo) +{ + signal(SIGSEGV, SIG_IGN); +#ifdef DEBUG_MODUS + printf("\nTheNetNode verursachte einen unbekannten Systemfehler!!!\n"); + printf("Letzte Funktion war: %s\n", lastfunc); +#endif + quit_program(-1); +} +#endif + +/************************************************************************/ +/* */ +/* */ +/************************************************************************/ + +int +exit_all(void) +{ + exit_mh(); /* MH-Liste sichern */ + save_stat(); + save_configuration(); + personalmanager(SAVE, NULL, NULL); /* Pers. Daten fuer Convers */ + + /* noch laufende Shells killen */ + for (userpo = (USRBLK *) usccpl.head; + userpo != (USRBLK *) &usccpl; + userpo = (USRBLK *) userpo->unext) + { + if (userpo->status != US_EXTP) /* externer Prozess aktiv? */ + continue; + + kill(-(userpo->child_pid), SIGKILL); /* Abbruch */ + waitpid(userpo->child_pid, NULL, 0); /* Prozess-Status holen */ + } + + /* Buffer freigeben */ + free(RAMBOT); + + /* Ab hier stehen keine Buffer mehr zur Verfuegung, alles was mit Buffern */ + /* zu tun hat, gibt nun nen Segfault ! */ + + if (console_type == CONS_SOCKET_CONNECTED) + { + close(consockfd); + consockfd = -1; + console_type = CONS_SOCKET_WAITING; + } + + if (console_type == CONS_SOCKET_WAITING) + { + close(sockfd); + sockfd = -1; + } + else + exit_console(); + + if (kiss_active) + exit_kisslink(); + + exit_proc(); + printf("\r\n"); + return(0); +} + +/************************************************************************/ +/* */ +/* Systembelastung durch TNN berechnen */ +/* diese Routine muss alle 10 Sekunden aufgerufen werden */ +/* */ +/************************************************************************/ +void +calculate_load(void) +{ + static long clktck = 0; + static int oldtime; + static float oldjiffies[2]; + static pid_t tnnpid; + FILE *fp; + int utime; + int stime; + register int gtime; + char proc_name[80]; + + /* im ersten Durchlauf alles aufraeumen */ + if (clktck == 0) + { + clktck = sysconf(_SC_CLK_TCK); + tnnpid = getpid(); + oldjiffies[0] = 0; + oldjiffies[1] = 0; + oldtime = 0; + load[0] = 0; + load[1] = 0; + load[2] = 0; + } + + sprintf(proc_name , "/proc/%d/stat", tnnpid); + + /* stat-Datei von TNN oeffnen */ + if ((fp = fopen(proc_name, "r"))) + { + fscanf(fp, "%*d %*s %*c %*d %*d %*d %*d " + "%*d %*u %*u %*u %*u %*u %d %d", + &utime, &stime); + fclose(fp); + + /* User- & System-Time addieren und in Sekunden umrechnen */ + gtime = (utime + stime) - oldtime; + + /* die letzten Zeiten fuer neue Berechnung merken */ + oldtime = utime + stime; + + /* Prozente ausrechnen */ + tnn_load = ((gtime * 100) / (10 * clktck)); + } + else + tnn_load = -1; /* Fehler ! */ + + /* Systemload aus /proc/loadavg lesen */ + if ((fp = fopen("/proc/loadavg", "r"))) + { + fscanf(fp, "%f %f %f %*s %*s", &load[0], &load[1], &load[2]); + fclose(fp); + } + else + load[0] = -1; + + /* gesamte Systembelastung im letzten Messintervall errechnen */ + if ((fp = fopen("/proc/uptime", "r"))) + { + float actjiffies[2]; + + fscanf(fp, "%f %f", &actjiffies[0], &actjiffies[1]); + fclose(fp); + + if (oldjiffies[0] != 0 && oldjiffies[1] != 0) + sys_load = 100 * (1 - ((actjiffies[1] - oldjiffies[1]) / (actjiffies[0] - oldjiffies[0]))); + + oldjiffies[0] = actjiffies[0]; + oldjiffies[1] = actjiffies[1]; + } + else + sys_load = -1; +} + +/************************************************************************/ +/* */ +/* Load-Werte ausgeben */ +/* */ +/************************************************************************/ +void +print_load(MBHEAD *mbp) +{ + ULONG user = 0; + ULONG sys = 0; + struct rusage sysusage; + + if (tnn_load >= 0) + putprintf(mbp, "\r TNN-Load: %i%%", tnn_load); + else + putprintf(mbp, "\r TNN-Load: can't read from /proc !"); + + if (sys_load >= 0) + putprintf(mbp, "\r Sysload: %.2f%%", sys_load); + else + putprintf(mbp, "\r Sysload: can't read from /proc !"); + + /* IO-Last ausgeben (siehe auch man proc) */ + if (load[0] >= 0) + putprintf(mbp, "\r Loadavg: %.2f %.2f %.2f", + load[0], load[1], load[2]); + else /* mhh...Kernel ohne /proc-System compiliert ? */ + putprintf(mbp, "\r Loadavg: can't read from /proc/loadavg !"); + + /* verbrauchte Systemzeit ausgeben, wenn moeglich */ + if (getrusage(RUSAGE_SELF, &sysusage) == 0) + { + user = (ULONG)sysusage.ru_utime.tv_sec * 1000L + + sysusage.ru_utime.tv_usec / 1000L; + sys = (ULONG)sysusage.ru_stime.tv_sec * 1000L + + sysusage.ru_stime.tv_usec / 1000L; + + if (getrusage(RUSAGE_CHILDREN, &sysusage) == 0) + { + user += (ULONG) sysusage.ru_utime.tv_sec * 1000L + + sysusage.ru_utime.tv_usec / 1000L; + sys += (ULONG) sysusage.ru_stime.tv_sec * 1000L + + sysusage.ru_stime.tv_usec / 1000L; + } + + if (user > 1000000L || sys > 1000000L) + putprintf(mbp, "\r CPU time used: user %lus, system %lus", + user / 1000L, sys / 1000L); + else + putprintf(mbp, "\r CPU time used: user %lums, system %lums", + user, sys); + } +} + +/* ermoeglicht das Setzen einer anderen Shell */ +void ccpsetshell(void) +{ + MBHEAD *mbp; + char cBuf[512]; + + const size_t tBufSize = sizeof(cBuf); + + register size_t tCmdlen = 0; + + struct stat tFileStat; + + /* Sysop will aendern und noch was in der Zeile da ? */ + if (issyso()) + { + /* Sind noch Usereingaben da ? */ + if (skipsp(&clicnt, &clipoi)) + { + /* Frischer Buffer */ + memset(cBuf, 0, tBufSize); + + /* Zeile lesen */ + for (; tCmdlen < tBufSize; ++tCmdlen) + { + if ((!clicnt) || (*clipoi == ' ')) + break; + clicnt--; + cBuf[tCmdlen] = (*clipoi++); + } + } + else /* Syntax anzeigen */ + { + mbp = putals("usage:\r'setshell /path/to/shell' to set a new shell\r"); + putprintf(mbp, "'setshell ?' to get the current setting\r"); + prompt(mbp); + seteom(mbp); + return; + } + } + else /* kein Sysop */ + { + invmsg(); + return; + } + + /* Aktuelle Einstellung anzeigen */ + if ((tCmdlen == 1) && (cBuf[0] == '?')) + { + mbp = putals(""); + putprintf(mbp, "current shell is : %s\r", cShell); + prompt(mbp); + seteom(mbp); + return; + } + + /* Neue Shell grob ueberpruefen */ + if (access(cBuf, F_OK) == -1) /* gibt es das File ? */ + { + mbp = putals(""); + putprintf(mbp, "error accessing file '%s': %s\r", cBuf, strerror(errno)); + prompt(mbp); + seteom(mbp); + return; + } + + /* Nur regulaere Dateien und Links erlaubt */ + if (stat(cBuf, &tFileStat) == -1) + { + mbp = putals(""); + putprintf(mbp, "can't get stats for '%s': %s\r", cBuf, strerror(errno)); + prompt(mbp); + seteom(mbp); + return; + } + else + { + /* Pruefung */ + if ( ((tFileStat.st_mode & S_IFDIR) == S_IFDIR) /* directory */ + || ((tFileStat.st_mode & S_IFSOCK) == S_IFSOCK) /* socket */ + || ((tFileStat.st_mode & S_IFBLK) == S_IFBLK) /* block device */ + || ((tFileStat.st_mode & S_IFCHR) == S_IFCHR) /* character device */ + || ((tFileStat.st_mode & S_IFIFO) == S_IFIFO) /* fifo */ + ) + { + mbp = putals(""); + putprintf(mbp, "'%s' is not a file, can't use !\r", cBuf); + prompt(mbp); + seteom(mbp); + return; + } + } + + /* Ausfuehrbar muss es auch noch sein */ + if (access(cBuf, X_OK) == -1) /* nur ausfuehrbares Programm */ + { + mbp = putals(""); + putprintf(mbp, "file '%s' is NOT marked executable, not accepted !!!\r", cBuf); + prompt(mbp); + seteom(mbp); + return; + } + + /* Uebernehmen */ + strncpy(cShell, cBuf, min(sizeof(cShell), tBufSize)); + mbp = putals(""); + putprintf(mbp, "shell changed to : %s\r", cShell); + prompt(mbp); + seteom(mbp); + return; +} + +#ifdef L1TCPIP +/* Pruefe auf TCPIP-Port's */ +int CheckPortTCP(int port) +{ + switch(kissmode(port)) + { +#ifdef L1TELNET + case KISS_TELNET : + return(TRUE); +#endif /* L1TELNET */ + +#ifdef L1HTTPD + case KISS_HTTPD : + return(TRUE); +#endif /* L1HTTPD */ + +#ifdef L1IPCONV + case KISS_IPCONV : + return(TRUE); +#endif /* L1IPCONV */ + +#ifdef L1IRC + case KISS_IRC : + return(TRUE); +#endif /* L1IRC */ + + default : + return(FALSE); + } + + return(FALSE); +} +#endif /* L1TCPIP */ + +/* + Dummy-Funktionen +*/ + +void +init_timer(void) {} +void +DIinc(void) {} +void +decEI(void) {} +void +exit_timer(void) {} +void +init_rs232(void) {} + +/* End of os/linux/linux.c */ diff --git a/os/linux/linux.h b/os/linux/linux.h new file mode 100644 index 0000000..277e27e --- /dev/null +++ b/os/linux/linux.h @@ -0,0 +1,329 @@ +/************************************************************************/ +/* */ +/* ***** ***** */ +/* ***** ***** */ +/* ***** ***** */ +/* ***** ***** */ +/* *************** *************** */ +/* ***************** ***************** */ +/* *************** *************** */ +/* ***** ***** TheNetNode */ +/* ***** ***** Portable */ +/* ***** ***** Network */ +/* ***** ***** Software */ +/* */ +/* File os/linux/linux.h (maintained by: DF6LN) */ +/* */ +/* This file is part of "TheNetNode" - Software Package */ +/* */ +/* Copyright (C) 1998 - 2008 NORD> 38400 */ + WORD kisstype; /* 0 = Kiss, 1 = SMACK, 2 = RMNC-KISS, */ + /* 3 = Tokenring, 4 = Vanessa, 5 = SCC, */ + /* 6 = TheFirmware, 7 = IPX, 8 = AX25IP */ + WORD rx_state; + WORD rx_port; + WORD tx_port; + char rx_buffer[MAXKISSLEN]; + char *rx_bufptr; + int rx_buflen; + ULONG bad_frames; /* Zaehler fuer Bad-Frames auf dem Port */ +#ifdef KERNELIF + unsigned short oldifparms; +#endif +} DEVICE; + +struct hostqueue { + int first; + int last; + char buffer[HOSTQ_BUFLEN]; + struct hostqueue *next; +}; + +struct ffblk +{ + char ff_path[MAXPATH]; + char ff_find[NAME_MAX]; + char ff_name[NAME_MAX]; + unsigned ff_fdate; + unsigned ff_ftime; +}; + +struct ftime +{ + unsigned ft_tsec : 5; + unsigned ft_min : 6; + unsigned ft_hour : 5; + unsigned ft_day : 5; + unsigned ft_month : 4; + unsigned ft_year : 7; +}; + +/* ------------------ Globale Variablen der Linux-Version --------------*/ + + extern ULONG tnn_buffers; + extern char tnn_initfile[MAXPATH]; + extern char tnn_dir[MAXPATH]; + extern char tnn_errfile[MAXPATH]; + extern char tnn_procfile[MAXPATH]; + extern WORD max_device; + extern DEVICE l1port[L1PNUM]; + extern BOOLEAN kiss_active; +#ifdef ATTACH + extern WORD tokenring_ports; + extern WORD sixpack_ports; +#endif /* ATTACH */ + extern WORD used_l1ports; + extern WORD l1ptab[L2PNUM]; + extern WORD l2ptab[L1PNUM]; + extern DEVICE *l1dp; + extern BOOLEAN unlock; + extern UWORD maxrounds; + + extern LONG bad_frames; + extern time_t last_recovery; + +/* extern BOOLEAN use_socket; */ + extern char tnn_socket[MAXPATH]; + extern char start_name[MAXPATH]; + extern char stop_name[MAXPATH]; + + char cShell[512]; /* Pfad zu Shell */ + + extern UBYTE console_type; /* Typ der Konsole: keine, Terminal, Socket */ + +/* ------------------- Funktionen bei Linux-Version --------------------*/ + +char *strlwr(char *); +char *strupr(char *); +int getftime(int, struct ftime *); +int spawnl(int, const char *, const char *, const char *, + const char *, const char *, const char *, const char *); +BOOLEAN init_kisslink(void); +void exit_kisslink(void); +void send_kisscmd(int, int, int); +void framedata_to_queue(int, char *, int); +void put_error(char *); +void hputud(unsigned); +void reset_hardware(void); +int exit_all(void); +BOOLEAN read_init_file(int, char *[]); +BOOLEAN init_proc(void); +void exit_proc(void); +void add_tnndir(char *); +void security_check(char *); +BOOLEAN good_file_name(const char *); +char *xtempnam(const char *, const char *); +void calculate_load(void); +void print_load(MBHEAD *); +void shell_to_user(void); +void ccpsetshell(void); + +#ifndef _TNN_LINUX_C +#define tempnam(x, y) xtempnam(x, y) +#endif + +/* Blocktransfer-Funktionen */ +int cpymbflat(char *, MBHEAD *); +MBHEAD *cpyflatmb(char *, int); + +#ifdef VANESSA +void vanessa_l1ctl(int); +void vanessa_l1init(void); +void vanessa(void); +WORD vanessa_dcd(int); +void vanessa_l1exit(void); +void van_hwstr(int, MBHEAD *); +#endif + +#ifdef AX_IPX +void axipx(void); +BOOLEAN axipx_l1init(int); +void axipx_l1exit(void); +void axipx_l1ctl(int, int); +void axipx_hwstr(int, MBHEAD *); +BOOLEAN axipx_dcd(int); +void axipx_recv(void); +void axipx_send(void); +#endif + +#ifdef AX25IP +void ax25ip(void); +BOOLEAN ax25ip_l1init(int); +void ax25ip_l1exit(void); +void ax25ip_l1ctl(int, int); +void ax25ip_hwstr(int, MBHEAD *); +BOOLEAN ax25ip_dcd(int); +void ccpaxipr(void); +#if defined(_MSC_VER) +void ax25ip_recv(void); +#endif +#endif + +#define kissmode(x) l1port[l1ptab[x]].kisstype +#define CRASH() *((int *) NULL) = 0 + +#ifdef KERNELIF +/* IP-Tunnel */ +void ifip_frame_to_kernel(MBHEAD *); +void ifip_clearstat(void); +void ifip_dispstat(MBHEAD *); +int ifip_active(void); +void ifip_frame_to_router(void); + +/* Kernel-AX.25 */ +BOOLEAN ifax_setup(DEVICE *); +void ifax_close(DEVICE *); +void ifax_hwstr(int, MBHEAD *); +void ifax_rx(int); +void ifax_tx(void); +void ifax_parms(int); +void ifax_l1ctl(int); +void ifax_housekeeping(void); +int ifax_dcd(int); +#endif + +/* 6PACK */ +#ifdef SIXPACK +void Sixpack_Housekeeping(void); +WORD Sixpack_DCD(UWORD); +void Sixpack_l1init(void); +void Sixpack_l1exit(void); +void Sixpack_l1ctl(int, UWORD); +void ccp6pack(void); +#endif + + +#ifdef DEBUG_MODUS +void sigsegv(int); +#endif + +/* End of os/linux/linux.h */ diff --git a/os/linux/osipconv.c b/os/linux/osipconv.c new file mode 100755 index 0000000..d848e7d --- /dev/null +++ b/os/linux/osipconv.c @@ -0,0 +1,200 @@ + +#include "tnn.h" +#ifdef OS_IPLINK + +/* Zeiger auf das Aktuelle Interface. */ +static T_INTERFACE *ifpp; + + +/* Struktur (sockaddr_in) fuer Server definieren. */ +struct sockaddr_in myaddr_in; +/* Struktur (sockaddr_in) fuer client definieren. */ +struct sockaddr_in peeraddr_in; + + +/* Ein Connect zum TCPIP-Nachbarn aufbauen. */ +int IPConvConnectOS(char *call, char *upcall, BOOLEAN flag) +{ + SENDTX *STx = NULL; + int fd = EOF; + int ch = FALSE; + register int i = EOF; + struct hostent *h; + long addr; + char tmp[10]; +#ifdef DEBUG_MODUS + lastfunc = "osipconv(IPConvConnectOS)"; +#endif /* DEBUG_MODUS */ + + ifpp = &ifp[CVS_ID]; /* Zeiger auf das IPCONV-Interface. */ + + /* IPConvers aktiv? */ + if (ifpp->actively == FALSE) + { + /* ggf. Logbuch fuehren. */ + T_LOGL1(TRUE, "(IPConvConnectOS):\nIPConvConnectOS: Kein IPConvers-Port geoeffnet!\n"); + /* Nein, abbrechen. */ + return(TRUE); + } + + /* Suche Rufzeichen in der IPC-TBL. */ + if ((i = IPConvSearch(call)) == EOF) + { + /* ggf. Logbuch fuehren. */ + T_LOGL1(TRUE, "(IPConvConnectOS):\nRufzeichen (%s) wurde nicht gefunden!\n" + , call); + /* Nix gefunden, abbrechen. */ + return(TRUE); + } + + /* Konvertiere Rufzeichen OHNE SSID!. */ + callss2str(tmp, upcall); + + /* Konvertiere IP-Adresse. */ + if ( (addr = inet_addr((const char *)ip_tbl[i].hostname)) == EOF) + { + /* Hostname aufloesen. */ + if ((h = gethostbyname((char *)ip_tbl[i].hostname)) == FALSE) + { + /* ggf. Logbuch fuehren. */ + T_LOGL1(TRUE, "(IPConvConnectOS):\nIP-Adresse/Hostname (%s) konnte nicht aufgeloest werden!\n" + , ip_tbl[i].hostname); + /* Hostname/IP-Adresse ungueltig, abbrechen. */ + return(TRUE); + } + + /* IP-Adresse zuweisen. */ + addr = ((struct in_addr*)h->h_addr)->s_addr; + } + + /* Adressstruktur loeschen */ + memset(&myaddr_in, 0, sizeof(myaddr_in)); + + /* Adressstruktur fuellen */ + myaddr_in.sin_family = AF_INET; + /* Auf tcp_port lauschen. */ + myaddr_in.sin_port = htons(ip_tbl[i].port); + /* Jedes netzwerk-taugliche Geraet abfragen. */ + myaddr_in.sin_addr.s_addr = addr; + + /* Socket erstellen. */ + if ((fd = socket (AF_INET, SOCK_STREAM, 0)) == EOF) + { + /* ggf. Logbuch fuehren. */ + T_LOGL1(TRUE, "(IPConvConnectOS):%s\nNeuen Socket konnte nicht erstellt werden!\n" + , ip_tbl[i].hostname); + +#ifdef SPEECH + printf(speech_message(335)); +#else + printf("Error: Socket cannot be constructed!\r"); +#endif + return(TRUE); + } + + /* Connnect Initialisieren. */ + if (connect (fd, (struct sockaddr *) &myaddr_in, sizeof (struct sockaddr_in)) == EOF) + { + /* ggf. Logbuch fuehren. */ + T_LOGL1(TRUE, "(IPConvConnectOS):\nConnect nicht moeglich (IP-Addr: %s)!\n" + , ip_tbl[i].hostname); + + /* Schliesse Socket. */ + close(fd); + return(TRUE); + } + + /* Neues TCPIP-Segment anlegen. */ + if (AddUserOS(ifpp, fd, (char *)ip_tbl[i].hostname)) + { + /* Schliesse Socket. */ + close(fd); + return(TRUE); + } + + /* Markiere Route als Linkpartner. */ + tcppoi->CVSlink = TRUE; + /* Markiere das wir eingeloggt sind. */ + tcppoi->login = TRUE; + /* Markiere, kein prompt senden. */ + tcppoi->LoginPrompt = TRUE; + + /* Maximalwert fuer die Statistik */ + if (++nmbtcp > nmbtcp_max) + nmbtcp_max = nmbtcp; + + /* Mit channel angabe? */ + if (clicnt) + /* Hole channel. */ + ch = atoi(clipoi); + + /* Wenn Nachbar STATUS "User" hat, gleich durch connecten. */ + if ( (!flag) + &&(ip_tbl[i].linkflag == TRUE)) + { + /* ggf. Logbuch fuehren. */ + T_LOGL2(TRUE, "(IPConvConnectOS):\nVerbindung zur IP-Adresse %s hergestellt.\n" + , ip_tbl[i].hostname); + + return(FALSE); + } + + if ((STx = (SENDTX *)allocb(ALLOC_L1IPCONV)) == NULL)/* TX-Segment besorgen. */ + { + /* ggf. Logbuch fuehren. */ + T_LOGL1(TRUE, "(IPConvConnectOS):%s\nSpeicher (%d) ist voll!\n" + , ip_tbl[i].hostname + , nmbfre); + + /* Schliesse Socket. */ + close(fd); + + tcppoi->disflg |= 0x80; /* Segment auf Disconnect setzen. */ + return(TRUE); /* Kein Segment frei, abbruch. */ + } + + if ((STx->Data = SetBuffer()) == NULL) /* Buffer besorgen. */ + { + dealoc((MBHEAD *)ulink((LEHEAD *)STx)); /* TX-Segment entsorgen.*/ + + /* ggf. Logbuch fuehren. */ + T_LOGL1(TRUE, "(IPConvConnectOS):%s\nSpeicher (%d) ist voll!\n" + , ip_tbl[i].hostname + , nmbfre); + + /* Schliesse Socket. */ + close(fd); + + tcppoi->disflg |= 0x80; /* Segment auf Disconnect setzen. */ + return(TRUE); /* Buffer ist voll, abbruch. */ + } + + STx->Sock = tcppoi->sock; /* Socket setzen. */ + STx->Interface = tcppoi->Interface; /* Interface setzen. */ + STx->Mode = tcppoi->mode; /* Stack-Mode setzen. */ + + /* Je nach Status von flag */ + /* demenstsprechend reagieren. */ + if (flag) + putprintf(STx->Data, "ppconvers/\377\200HOST %s %s %s\r", myhostname, myrev, myfeatures); + else + { + /* Wenn Nachbar STATUS "User" hat, gleich durch connecten. */ + if (ip_tbl[i].linkflag == FALSE) + /* Loginstring vorbereiten. */ + putprintf(STx->Data, "/na %s %d\r", tmp, ch); + } + + rwndmb(STx->Data); + /* Umhaengen in die sendesliste. */ + relink((LEHEAD *) STx, (LEHEAD *)rxflTX.tail);/* Umhaengen in die Sendeliste. */ + + /* ggf. Logbuch fuehren. */ + T_LOGL2(TRUE, "(IPConvConnectOS):\nVerbindung zur IP-Adresse %s hergestellt.\n" + , ip_tbl[i].hostname); + return(FALSE); +} + +#endif /* OS_IPLINK */ + +/* End of os/linux/osipconv.c */ diff --git a/os/linux/ostcpip.c b/os/linux/ostcpip.c new file mode 100755 index 0000000..7b4c9ee --- /dev/null +++ b/os/linux/ostcpip.c @@ -0,0 +1,697 @@ + +#include "tnn.h" +#ifdef OS_STACK + +static T_INTERFACE *ifpp; /* Zeiger auf das aktuelle Interface */ + +struct sockaddr_in myaddr_in; +struct sockaddr_in peeraddr_in; + + +/* Schliesse aktuellen Socket. */ +BOOLEAN CloseSockOS(BOOLEAN ALL, WORD INTERFACE) +{ + int i, + j = 0; +#ifdef DEBUG_MODUS + lastfunc = "ostcpip(CloseSockOS)"; +#endif /* DEBUG_MODUS */ + + /* ALLE Socket-Verbindungen schliessen. */ + if (ALL == TRUE) + { + /* TCPIP-TBL durchgehen. */ + for (i = 0, tcppoi = tcptbl; i < MAXTCPIP; ++i, ++tcppoi) + { + /* Ist Socket noch offen? */ + if ( INTERFACE == tcppoi->Interface + && tcppoi->sock > TRUE) + { + if (tcppoi->mode != OS_MODE) /* Segment kein OS-STACK, */ + continue; /* zum naechsten Segment. */ + + /* Socket schliessen. */ + close(tcppoi->sock); + + /* TCPIP-User/link aus der Liste raushaengen */ + /* bzw. Parameter wieder auf 0 setzen. */ + DiscTCP(); + } + + /* Sind alle aktiven Sockets durchlaufen, */ + if (((tcppoi->activ) && (j++ >= tcp_tbl_top)) || (j == tcp_tbl_top)) + /* brechen wir ab. */ + return(FALSE); + } + } + + /* Socket schliessen. */ + close(tcppoi->sock); + + /* TCPIP-User/Link aus der Liste raushaengen */ + /* bzw. Parameter wieder auf 0 setzen. */ + DiscTCP(); + return(FALSE); +} + +/* TCPIP-Port Initialisierung. */ +BOOLEAN L1InitOS(UWORD Interface, int l2port, unsigned short TCPPort) +{ +#ifdef DEBUG_MODUS + lastfunc = "ostcpip(L1InitOS)"; +#endif /* DEBUG_MODUS */ + + if (l2port == EOF) /* Keine Portangabe!!!. */ + { + printf("(L1InitOS): Fehler, keine L2-Portangabe!!!\n"); + return(FALSE); + } + /* Zeiger auf das aktuelle Interface. */ + if ((ifpp = SearchIf(Interface)) == NULL) + { + printf("(L1InitOS): Fehler, Interface existiert nicht!!!\n"); + return(FALSE); /* Abbrechen. */ + } + + /* Einen neuen Filedescriptor anlegen. */ + if ((ifpp->OsSock = SetupOS(ifpp, htons(TCPPort))) == EOF) + return(FALSE); /* Abbrechen. */ + + ifpp->l2port = l2port; /* L2-Port setzen. */ + ifpp->tcpport = TCPPort; /* akt. TCP-Port setzen. */ + + return(TRUE); /* Erfolgreich Socket erstellt. */ +} + +/* TCPIP-Interface schliessen. */ +void L1ExitOS(UWORD Interface) +{ + T_INTERFACE *ifpoi; +#ifdef DEBUG_MODUS + lastfunc = "ostcpip(L1ExitOS)"; +#endif /* DEBUG_MODUS */ + + /* Zeiger auf das aktuelle Interface. */ + if ((ifpoi = SearchIf(Interface)) == NULL) + /* Aktuelles Interface ist deaktiv, */ + /* dann zum naechsten Interface. */ + return; + + /* Alle TCPIP-Verbindungen auf den Interface schliessen. */ + CloseSockOS(TRUE, ifpoi->Interface); + + /* Interface ist nicht aktiv, */ + if (ifpoi->actively == FALSE) + /* damit ist hier schon schluss. */ + return; + + /* TCPIP-Socket schliessen. */ + close(ifpoi->OsSock); + + /* Markiere TCPIP-Interface als deaktiv. */ + ifpoi->actively = FALSE; +} + + /* Einen Filedescriptor anlegen. */ +int SetupOS(T_INTERFACE *ifpp, /* Zeiger auf das aktuelle Interface. */ + unsigned short tcp_port) /* Neuer TCP-Port. */ +{ + int tmp_fd = EOF; /* Temporaerer Filedescriptor */ +#ifdef DEBUG_MODUS + lastfunc = "ostcpip(SetupOS)"; +#endif /* DEBUG_MODUS */ + + if (tcp_port == FALSE) /* Kein Port angegeben. */ + { + T_LOGL1(TRUE, "(SetupOS):\nKein TCP-Port angegeben.\n"); + return(EOF); /* Abbruch. */ + } + + memset(&myaddr_in, 0, sizeof(myaddr_in)); /* Adressstruktur loeschen */ + memset(&peeraddr_in, 0, sizeof(peeraddr_in)); + myaddr_in.sin_family = AF_INET; /* Adressstruktur fuellen */ + myaddr_in.sin_port = htons(tcp_port); /* TCP-Port setzen. */ + myaddr_in.sin_addr.s_addr = INADDR_ANY; /* Jedes Netzwerk Geraet abfragen. */ + + /* Socket erstellen. */ + if ((tmp_fd = socket(AF_INET, SOCK_STREAM, 0)) == EOF) + { + printf("Error %s: Socket cannot be constructed!\r", ifpp->name); + + T_LOGL1(TRUE, "(SetupOS):\nNeuer Socket kann nicht geoeffnet werden.\n"); + return(EOF); /* Keine freien Socket's. */ + } + + /* Bind Initialisieren. */ + if (bind (tmp_fd, (struct sockaddr *) &myaddr_in, sizeof (struct sockaddr_in)) == EOF) + { + printf("Error %s: Bind cannot be initialized!\n", ifpp->name); + close(tmp_fd); /* Schliesse Socket. */ + + T_LOGL1(TRUE, "(SetupOS):\nBind Initialisierung fehlgeschlagen.\n"); + return(EOF); /* Fehler beim Bind . */ + } + + if (listen (tmp_fd, 3) == EOF) /* Listen Initialisieren. */ + { + printf("Error %s: listen cannot be initialized!\n", ifpp->name); + close(tmp_fd); /* Schliesse Socket. */ + + T_LOGL1(TRUE, "(SetupOS):\nListen Initialisierung fehlgeschlagen.\n"); + return(EOF); /* Fehler beim Listen. */ + } + + T_LOGL1(TRUE, "(SetupOS):\nTCP-Port (%d) erfolgreich gesetzt.\n" + , ntohs(tcp_port)); + return(tmp_fd); /* Aktuelle Filedescriptor. */ +} + + +/* Anhand des Sockets den User aus der Liste holen. */ +TCPIP *FdReadOS(fd_set *fds) +{ + int i, + j = 0; + LHEAD *h_llp; + + h_llp = &tcpactl; +#ifdef DEBUG_MODUS + lastfunc = "ostcpip(FdReadOS)"; +#endif /* DEBUG_MODUS */ + + /* TCPIP-TBL durchgehen. */ + for (i = 0, tcppoi = tcptbl; i < MAXTCPIP; ++i, ++tcppoi) + { + if (tcppoi->mode != OS_MODE) + continue; + + /* Nur wenn aktiv! */ + if (tcppoi->activ) + { + /* Vergleiche die Sockets */ + if (FD_ISSET(tcppoi->sock, fds)) + { + /* wir haben einen Link gefunden */ + ulink((LEHEAD *)tcppoi); + relink((LEHEAD *)tcppoi, (LEHEAD *)h_llp->tail); + return(tcppoi); + } + } + /* Sind alle aktiven Sockets durchlaufen, */ + if (((tcppoi->activ) && (j++ >= tcp_tbl_top)) || (j == tcp_tbl_top)) + /* brechen wir ab. */ + break; + } + + /* Keinen Eintrag gefunden. */ + return(NULL); +} + +int ReadSockOS(void) /* Empfangene TCPIP Packete. */ +{ + fd_set fdsI; + struct timeval timevalue; + int ret = EOF; +#ifdef DEBUG_MODUS + lastfunc = "ostcpip(ReadSockOS)"; +#endif /* DEBUG_MODUS */ + + if (tcppoi->rxc >= tcppoi->RecvLen) /* Sind alle Zeichen verarbeitet. */ + { + if (!tcppoi->mode) /* OS-Stack. */ + { + FD_ZERO(&fdsI); /* Inhalt loeschen. */ + FD_SET((unsigned)tcppoi->sock, &fdsI); /* Socket setzen. */ + + timevalue.tv_usec = 0; + timevalue.tv_sec = 0; + /* Pruefe auf aktivitaet. */ + ret = select(tcppoi->sock + 1, &fdsI, NULL , NULL ,&timevalue); + + if (ret <= 0) + return((int)NULL); /* Keine aktivitaet auf den Socket. */ + else + /* Zeichen vom Socket empfangen. */ + tcppoi->RecvLen = recv (tcppoi->sock, tcppoi->rxbuf, RXLEN,0); + } + + if (tcppoi->RecvLen < 1) /* Fehler beim Empfang. */ + { + if (tcppoi->RecvLen == EOF) /* Socket wurde mittlerweile geloes. */ + { + ifpp = SetInterface(tcppoi->Interface); /* akt. Interface setzen. */ + /* ggf. Logbuch fuehren. */ + T_LOGL1(TRUE, "(ReadSockOS):%s\n (Recv) Fehler beim empfang, Segment wird auf DISC gesetzt!\n" + , tcppoi->ip); + + + tcppoi->disflg |= 0x80; /* Segment auf DISC stellen. */ + return((int)NULL); + } + + if ( (ret) + &&(tcppoi->RecvLen == 0)) + { + ifpp = SetInterface(tcppoi->Interface); /* akt. Interface setzen. */ + /* ggf. Logbuch fuehren. */ + T_LOGL1(TRUE, "(ReadSockOS):%s\n(Recv) Keine Zeichen, Segment wird auf DISC gesetzt!\n" + , tcppoi->ip); + + tcppoi->disflg |= 0x80; /* Segment auf DISC stellen. */ + return((int)NULL); + } + } + + tcppoi->rxc = 0; /* RX-Zaehler auf 0 setzen. */ + tcppoi->rxbuf[tcppoi->RecvLen] = 0; /* Nullzeichen setzen. */ + /* ggf. Logbuch fuehren. */ + + ifpp = SetInterface(tcppoi->Interface); + T_LOGL3(TRUE, "(ReadSockOS):%s\nInput:\r%s\r" + , tcppoi->ip + , tcppoi->rxbuf); + } + + ret = tcppoi->rxbuf[tcppoi->rxc++]; /* Zeichen vom rxbuf holen. */ + + return(ret); /* Aktuelle Zeichen weiterreichen. */ +} + +static int OsStackReadIndicationsSock(void) /* Zeichen vom Socket einlesen. */ +{ + TRILLIAN ok = ERRORS; + char s; +#ifdef DEBUG_MODUS + lastfunc = "ostcpip(OsStackReadIndicationsSock)"; +#endif /* DEBUG_MODUS */ + + while(1) /* Alle Zeichen von Socket einlesen. */ + { + s = ReadSockOS(); /* Zeichen vom Socket. */ + + if (tcppoi->cmdlen >= RXLEN) /* Maximale Buffergroesse erreicht, */ + { + ifpp = SetInterface(tcppoi->Interface); + T_LOGL1(TRUE, "(OsStackReadIndicationsSock):%s\nMaximale Buffergroesse erreicht!\n" + , tcppoi->ip); + return(TRUE); + } + + switch(tcppoi->Interface) /* Interface. */ + { +#ifdef L1TELNET + case KISS_TELNET : /* TELNET-Server. */ + if ((ok = GetContensTEL(s)) == ERRORS) /* Aktuelle Zeichen auswerten.*/ + break; /* Zeichen verarbeitet, kein Return. */ + else + if (ok == YES) /* Zeichen verarbeitet und Return. */ + { + tcppoi->cmd[tcppoi->cmdlen] = 0; /* Nullzeichen setzen. */ + return(TRUE); /* Frame ist komplett. */ + } + else + continue; /* Sind noch Zeichen im RXBUF, */ + /* zum naechsten Zeichen. */ + break; +#endif /* L1TELNET. */ + +#ifdef L1HTTPD + case KISS_HTTPD : /* HTTPD-Server. */ + if ((ok = GetContensHTP(s)) == ERRORS) /* Aktuelle Zeichen auswerten.*/ + break; /* Zeichen verarbeitet, kein Return. */ + else + if (ok == YES) /* Zeichen verarbeitet und Return. */ + { + tcppoi->cmd[tcppoi->cmdlen] = 0; /* Nullzeichen setzen. */ + return(TRUE); /* Frame ist komplett. */ + } + else + continue; /* Sind noch Zeichen im RXBUF, */ + /* zum naechsten Zeichen. */ + break; +#endif /* L1HTTPD. */ + +#ifdef L1IPCONV + /* IPCONV */ + case KISS_IPCONV : + /* Aktuelle Zeichen auswerten. */ + if ((ok = GetContensCVS(s)) == ERRORS) + /* Alle Zeichen verarbeitet, aber kein Return. */ + break; + else + /* Alle Zeichen verarbeitet und Return? */ + if (ok == YES) + { + /* User/Link noch kein Login. */ + if (!tcppoi->login) + { + /* Pruefe auf Login. */ + if (!strncmp(tcppoi->cmd, "/na", 3)) + /* Kein Prompt senden. */ + tcppoi->LoginPrompt = TRUE; + } + tcppoi->cmd[tcppoi->cmdlen] = 0; + /* Frame komplett. */ + return(TRUE); + } + else + /* Sind noch Zeichen im RXBUF,*/ + /* zum naechsten Zeichen. */ + continue; + + break; +#endif /* L1IPCONV */ + +#ifdef L1IRC + /* IPCONV */ + case KISS_IRC : + /* Aktuelle Zeichen auswerten. */ + if ((ok = GetContensCVS(s)) == ERRORS) + /* Alle Zeichen verarbeitet, aber kein Return. */ + break; + else + /* Alle Zeichen verarbeitet und Return? */ + if (ok == YES) + { + tcppoi->cmd[tcppoi->cmdlen] = 0; + /* Frame komplett. */ + return(TRUE); + } + else + /* Sind noch Zeichen im RXBUF,*/ + /* zum naechsten Zeichen. */ + continue; + + break; +#endif /* L1IRC */ + + default : /* Ungueltiges Interface. */ + break; /* Hier werden wir nie kommen. */ + } + + return(FALSE); /* Frame noch nicht komplett. */ + } + + return(FALSE); /* Frame noch nicht komplett. */ +} + +void ServOS(void) /* Empfangene Zeichen in Frames packen. */ +{ + READRX *SRx; + register int i; +#ifdef DEBUG_MODUS + lastfunc = "ostcpip(ServOS)"; +#endif /* DEBUG_MODUS */ + + if (OsStackReadIndicationsSock()) /* Empfangene Zeichen analysieren. */ + { + if(tcppoi->cmdlen > 0) /* Es sind Zeichen im Buffer.*/ + { + if ((SRx = (READRX *)allocb(ALLOC_L1TCPIP)) == NULL)/* RX-Seg. besorgen */ + { + ifpp = SetInterface(tcppoi->Interface); + T_LOGL1(TRUE, "(ServOS):%s\nSpeicher (%d) ist voll!\n" + , tcppoi->ip + , nmbfre); + tcppoi->disflg |= 0x80; /* Segment auf Disconnect setzen. */ + return; /* Kein Segment frei, abbruch. */ + } + + if ((SRx->Data = SetBuffer()) == NULL) /* Buffer besorgen. */ + { + dealoc((MBHEAD *)ulink((LEHEAD *)SRx)); /* RX-Segment entsorgen. */ + + ifpp = SetInterface(tcppoi->Interface); + T_LOGL1(TRUE, "(ServOS):%s\nSpeicher (%d) ist voll!\n" + , tcppoi->ip + , nmbfre); + tcppoi->disflg |= 0x80; /* Segment auf Disconnect setzen. */ + return; /* Buffer ist voll, abbruch. */ + } + + SRx->Sock = tcppoi->sock; /* Socket setzen. */ + SRx->Interface = tcppoi->Interface; /* Inetrface setzen. */ + SRx->Mode = tcppoi->mode; /* Stack-Mode setzen. */ + + for (i = 0; i < tcppoi->cmdlen; ++i) + putchr(tcppoi->cmd[i], SRx->Data); /* Buffer fuellen. */ + + tcppoi->cmdlen = 0; /* Buffer-Zaehler zuruecksetzen. */ + tcppoi->cmd[0] = 0; /* Nullzeichen setzen. */ + + if (tcppoi->activ) /* Nur wenn Socket aktiv. */ + relink((LEHEAD *) SRx, (LEHEAD *)rxflRX.tail);/* Ab in die Empf.-liste*/ + else + { + ifpp = SetInterface(tcppoi->Interface); /* akt. Interface setzen. */ + T_LOGL1(TRUE, "(ServOS):%s\nSegment ist nicht mehr aktiv!\n" + , tcppoi->ip); + + if (SRx->Data != NULL) + dealmb(SRx->Data); /* Buffer entsorgen. */ + + dealoc((MBHEAD *)ulink((LEHEAD *)SRx)); /* RX-Segment entsorgen.*/ + } /* Socket ist nicht mehr aktiv. */ + } /* kein Zeichen im buffer. */ + } /* Frame ist noch nicht komplett. */ +} + +/* Neue User hinzufuegen, vorrausgesetzt es sind noch freie Sockets vorhanden.*/ +int AddUserOS(T_INTERFACE *ifpoi, /* TCP-Interface. */ + unsigned NewSocket, /* Neuer Socket. */ + char *ip) /* IP-Adresse. */ +{ +#ifdef DEBUG_MODUS + lastfunc = "ostcpip(AddUserOS)"; +#endif /* DEBUG_MODUS */ + + while ((LHEAD *)tcpfrel.head != &tcpfrel) + { + tcppoi = (TCPIP *)ulink((LEHEAD *)tcpfrel.head); + SetDefaultWorthTCP(NewSocket, /* Defaultwerte setzen, neuer Socket. */ + ip, /* IP-Adresse. */ + ifpoi->l2port, /* L2-Port. */ + ifpoi->Interface, /* TCPIP-Interface. */ + OS_MODE); /* OS-STack. */ + + ServOS(); /* Empfangene Zeichen in Frames packen. */ + return(FALSE); + } + + ifpp = SetInterface(ifpoi->Interface); /* akt. Interface setzen. */ + /* ggf. Logbuch fuehren. */ + T_LOGL1(TRUE, "(AddUserOS):%s\nKann kein neues TCPIP-Segment anlegen !\n" + , ip); + return(TRUE); +} + +void ListenTCP_OS(void) +{ + fd_set rmask; + struct timeval timevalue; + UWORD Interface = KISS_TCPIP; + int max_fd; + register int i; + int count, + j = 0; +#ifdef DEBUG_MODUS + lastfunc = "ostcpip(ListenTCP_OS)"; +#endif /* DEBUG_MODUS */ + + max_fd = 0; + FD_ZERO(&rmask); + + /* Interface-Socket's setzen. */ + for (i = 0; i < MAXINTERFACE; i++, Interface++) + { + /* Zeiger auf das aktuelle Interface. */ + if ((ifpp = SearchIf(Interface)) == NULL) + continue; + + if (ifpp->actively == FALSE) + continue; + + /* Interface-Socket setzen. */ + FD_SET((unsigned)ifpp->OsSock, &rmask); + + if (ifpp->OsSock > max_fd - 1) + max_fd = ifpp->OsSock + 1; + } + + /* User-Socket's setzen. */ + for (i = 0, tcppoi = tcptbl; i < MAXTCPIP; ++i, ++tcppoi) + { + if (tcppoi->activ) /* Nur wenn Interface Socket aktiv! */ + { + if (tcppoi->mode != OS_MODE) /* Kein OS-STACK, */ + continue; /* zum naechsten Segment. */ + + if (tcppoi->sock < 1) /* Kein Socket gesetzt, */ + continue; /* zum naechsten Segment. */ + + FD_SET((unsigned)tcppoi->sock, &rmask); /* Socket setzen */ + + if (tcppoi->sock > max_fd - 1) + max_fd = tcppoi->sock + 1; + } + + if ( ((tcppoi->activ) /* Sind alle aktiven Sockets durchlaufen, */ + && (j++ >= tcp_tbl_top)) + || (j == tcp_tbl_top)) + break; /* brechen wir ab. */ + } + + timevalue.tv_usec = 0; + timevalue.tv_sec = 0; + + count = select(max_fd, &rmask, NULL, NULL, &timevalue); + + if (count < 1) + return; + + Interface = KISS_TCPIP; + + for (i = 0; i < MAXINTERFACE; i++, Interface++) + { + if ((ifpp = SearchIf(Interface)) == NULL) /* Ungueltiges Interface, */ + continue; /* zum naechsten Interface. */ + + if (ifpp->actively == FALSE) /* Interface nicht aktiv, */ + continue; /* zum naechsten Interface. */ + + + if (FD_ISSET(ifpp->OsSock, &rmask)) /* Interface-Socketvergleich. */ + { + char ip[IPADDR]; + int NewSock; + socklen_t addrlen; + ULONG peerip = 0; + char *p = (char *)&peerip; + + addrlen = sizeof peeraddr_in; + + if ((NewSock = accept(ifpp->OsSock, (struct sockaddr *) &peeraddr_in, &addrlen)) != EOF) + { + peerip = peeraddr_in.sin_addr.s_addr; + sprintf (ip, "%d.%d.%d.%d",(p[0] & 255) + ,(p[1] & 255) + ,(p[2] & 255) + ,(p[3] & 255)); + /* Einen Neuen TCPIP-User/Link hinzufuegen. Bekannt */ + /* ist das Interface, der Socket und die IP-Adresse. */ + if (AddUserOS(ifpp, NewSock, ip)) + { + close(NewSock); + return; + } + + /* ggf. Logbuch fuehren. */ + ifpp = SetInterface(tcppoi->Interface); + T_LOGL2(TRUE, "(ListenTCP_OS):\nVerbindung zur IP-Adresse %s angenommen.\n" + , ip); + return; + } + } + } + + /* Anhand des Sockets den User aus der Liste Holen */ + if ((tcppoi = FdReadOS(&rmask)) != NULL) + { + /* ggf. Logbuch fuehren. */ + ifpp = SetInterface(tcppoi->Interface); + T_LOGL3(TRUE, "(ListenTCP_OS):%s\nAktuellen Socket (%d) in der Liste gefunden.\n" + , tcppoi->ip + , tcppoi->sock); + + /* TCPIP Packete empfangen/bearbeiten/senden*/ + ServOS(); + return; + } +} + + +/* Frame aus der Sendeliste senden. */ +int PutflushSockOS(void) +{ + int ok = FALSE; + int ret = FALSE; +#ifdef DEBUG_MODUS + lastfunc = "ostcpip(PutflushSockOS)"; +#endif /* DEBUG_MODUS */ + + if (tcppoi->txc) /* Gibt es was zu senden. */ + { + while (1) /* Gibt es was zu senden. */ + { + fd_set wfdsI; + struct timeval Tv; + + FD_ZERO(&wfdsI); /* Loesche inhalt. */ + FD_SET((unsigned)tcppoi->sock, &wfdsI); /* Socket setzen. */ + + if (select(tcppoi->sock + 1, NULL, &wfdsI , NULL ,&Tv))/* Sender frei.*/ + { + if (tcppoi->txstatus == TCP_TX_BUSY) /* Sender ist auf Busy. */ + tcppoi->txstatus = TCP_TX_FREE; /* Sender auf frei stellen. */ + + /* Frame senden */ + if ((ok = send(tcppoi->sock, tcppoi->txbuf + tcppoi->sum, tcppoi->txc - tcppoi->sum,0)) < 0) + { + ifpp = SetInterface(tcppoi->Interface); + T_LOGL1(TRUE, "(PutflushSockTCP):%s\nFrame senden fehlgeschlagen!\n" + , tcppoi->ip); + + tcppoi->disflg |= 0x80; /* Segment auf Disconnect setzen. */ + return(TRUE); /* Abbruch. */ + } + + ifpp = SetInterface(tcppoi->Interface); /* ggf. Logbuch fuehren. */ + T_LOGL3(TRUE, "(PutflushSockOS):%s\nOutput:\r%s\r" + , tcppoi->ip + , tcppoi->txbuf); + + tcppoi->sum += ok; /* Markiere, gesendete Zeichen. */ + + if (tcppoi->sum == tcppoi->txc) /* Alle Zeichen gesendet. */ + break; /* Schleife verlassen. */ + + } + + if (ret == FALSE) /* Sender ist nicht frei. */ + { + tcppoi->txstatus = TCP_TX_BUSY; /* Sender auf Busy stellen. */ + return(FALSE); + } + } + + tcppoi->sum = 0; /* Zuruecksetzen. */ + tcppoi->txc = 0; + tcppoi->txbuf[0] = 0; + } + + return(FALSE); +} + +BOOLEAN CheckSocketOS(void) +{ + int ok = EOF; +#ifdef DEBUG_MODUS + lastfunc = "ostcpip(CheckSocketOS)"; +#endif /* DEBUG_MODUS */ + + if ((ok = send(tcppoi->sock, "", 0, 0)) < 0) /* Socket noch aktiv. */ + { + ifpp = SetInterface(tcppoi->Interface); + T_LOGL1(TRUE, "(CheckSocket):%s\nSocket ist nicht mehr aktiv!\n" + , tcppoi->ip); + + tcppoi->disflg |= 0x80; /* Segment auf DISC setzen. */ + return(TRUE); /* Socket ist nicht mehr aktiv */ + } + else + return(FALSE); /* Socket ist aktiv. */ +} + +#endif /* OS_STACK */ + +/* End of os/linux/ostcpip.h */ diff --git a/os/linux/vanlinux.c b/os/linux/vanlinux.c new file mode 100755 index 0000000..1780396 --- /dev/null +++ b/os/linux/vanlinux.c @@ -0,0 +1,481 @@ +/************************************************************************/ +/* */ +/* ***** ***** */ +/* ***** ***** */ +/* ***** ***** */ +/* ***** ***** */ +/* *************** *************** */ +/* ***************** ***************** */ +/* *************** *************** */ +/* ***** ***** TheNetNode */ +/* ***** ***** Portable */ +/* ***** ***** Network */ +/* ***** ***** Software */ +/* */ +/* File os/linux/vanlinux.c (maintained by: DG1KWA) */ +/* */ +/* This file is part of "TheNetNode" - Software Package */ +/* */ +/* Copyright (C) 1998 - 2008 NORD>head == l2flp) + { + kick[port] = FALSE; + continue; + } + if (ReadVanW(port, dp_oFProd) != CRAM_VALID) /* CRAM Buffer free */ + { + len = 0; + ulink((LEHEAD *)(txfhdl = (MBHEAD *) l2flp->head));/*Zeiger holen*/ + while (txfhdl->mbgc < txfhdl->mbpc) /* solange Daten vorhanden sind */ + WriteVanB(port, dp_oBuffer + (len++), getchr(txfhdl)); + + relink((LEHEAD *)txfhdl, /* als gesendet betrachten und in */ + (LEHEAD *)stfl.tail); /* die gesendet Liste umhaengen */ + + kick[port] = ((LHEAD *)l2flp->head != l2flp); + WriteVanW(port, dp_iBufEmpty, 1); /* Frame wird gesendet... */ + WriteVanW(port, dp_oLFrm, len); /* set size and .. */ + WriteVanW(port, dp_oFProd, CRAM_VALID); /* terminate */ + usleep(50); + } /* if CRAM_VALID... */ + } /* if kick[port]... */ + } /* Port enabled */ + else + while (l2flp->head != l2flp) + relink(ulink((LEHEAD *) l2flp->head), (LEHEAD *)stfl.tail); + } /* for (port .... */ + } /* for (live .... */ +} /* end */ + + +/************************************************************************/ +/* vanessa_get_frame() - Frame(s) aus dem VANESSA CRAM holen */ +/*----------------------------------------------------------------------*/ +void vanessa_get_frame(void) +{ + register unsigned int port; + WORD i, l; + MBHEAD *rxfhd; + + for (port = 0; port < L2PNUM; ++port) + { + if (van_enabled(port)) + { + while (ReadVanW(port, dp_iFProd) == CRAM_VALID) + { + outportb(ledio_adr[port], LED_ON); + + l = ReadVanW(port, dp_iLFrm); + + if (l > 0) + { + (rxfhd = (MBHEAD *)allocb(ALLOC_MBHEAD))->l2port = port; + + for (i = 0; i < l; ++i) + putchr(ReadVanB(port, dp_iBuffer+i), rxfhd); + + relink((LEHEAD *)rxfhd, (LEHEAD *)rxfl.tail); + } + WriteVanW(port, dp_iFProd, !CRAM_VALID); + outportb(ledio_adr[port], LED_OFF); + usleep(50); + } + } + } +} + +/************************************************************************/ +/* VANESSA mit Parametern versorgen */ +/*----------------------------------------------------------------------*/ +void vanessa_config(WORD port) +{ + UWORD portspeed; + + if (van_enabled(port)) + { + WriteVanW(port, dp_Slottime, portpar[port].slottime & 0xff); + WriteVanW(port, dp_TxDelay, portpar[port].txdelay & 0xff); + WriteVanW(port, dp_Persistance, (dama(port) + ? 0Xff : portpar[port].persistance & 0xff)); + WriteVanW(port, dp_FullDuplex, fullduplex(port)?1:0); + + if (extclock(port)) + portspeed = 0xff07; + else + { + switch (portpar[port].speed) + { + case 12: portspeed = 0xff00; break; + case 24: portspeed = 0xff01; break; + case 48: portspeed = 0xff02; break; + case 96: portspeed = 0xff03; break; + case 192: portspeed = 0xff04; break; + case 384: portspeed = 0xff05; break; + default: portspeed = 0xff00; portpar[port].speed = 12; + } + } + + WriteVanW(port, dp_vanspeed, portspeed); + + WriteVanB((port&0xfe), ((dp_cData)+0x74F), multibaud(port) ? 1 : 0); + WriteVanB(port, ((dp_cData)+0x74F), (multibaud(port) ? 1 : 0)); + WriteVanW(port, dp_oMagic, 0); + WriteVanW(port, dp_reReadParams, CRAM_VALID); + outportb(ledio_adr[port], LED_OFF); + WriteVanW(port, dp_iFProd, !CRAM_VALID); + } +} + +/************************************************************************/ +/* Reset Befehl an alle VANESSA's geben */ +/*----------------------------------------------------------------------*/ +void vanessa_reset_tnc(void) +{ + register unsigned int port; + + for (port = 0; port < L2PNUM; ++port) /* Alle FP's durchgehen */ + { + if ( portpar[port].reset_port /* soll dieser Reset bekommen? */ + && van_enabled(port) + ) + { + portpar[port].reset_port = FALSE; /* rueckstellen */ + outportb(reset_adr[port >> 1], 0xFF); /* set RESET and... */ + delay(50); /* .. wait some time */ + outportb(reset_adr[port >> 1], 0x0); /* remove RESET again */ + } + } +} + + +/************************************************************************/ +/* TEST-Befehl ausfuehren, funktioniert nur ab VANESSA Firmware 4.0 !! */ +/*----------------------------------------------------------------------*/ +void vanessa_send_test(int port) +{ + if (van_enabled(port)) + { + if (ReadVanW(port, dp_oFProd) != CRAM_VALID) /* CRAM Buffer free */ + { + WriteVanW(port, dp_oLFrm, -1); /* Frame Size = -1 */ + WriteVanW(port, dp_oFProd, CRAM_VALID); /* CRAM buffer valid */ + } + testflag[port] = FALSE; /* TEST fertig */ + } +} + +/*******************************************************************/ +/* Testen ob ueberhaupt ne VAN da ist */ +/* Patch dazu gekommen, 22/02/97 DG1KWA */ +/* PS: in der alten Routine war auch noch ein Fehler :-) */ +/*******************************************************************/ + +BOOLEAN van_test(int port) +{ + van_version[port] = 4; /* aktuelle Version steht nicht im DP */ + van_revision[port] = ReadVanB((port&0xFE), dp_cData+0x751) / 16; + van_patch[port] = ReadVanB((port&0xFE), dp_cData+0x74E); /* new */ + return(ReadVanW(((port&0xFE)+1), dp_cData+0x750) == 0x3412); +} + +WORD vanessa_dcd(int port) +{ + WORD state = 0; + + if (!van_enabled(port)) + return 0; + + if (ReadVanW(port,dp_oFProd) == CRAM_VALID) /* Sendedaten in der VAN */ + state |= (WORD) TXBFLAG; + if (ReadVanW(port,dp_iFProd) == CRAM_VALID) /* Empfangsdaten in der VAN */ + state |= (WORD) RXBFLAG; + if (ReadVanB(port,dp_iPTT)) /* wir senden ! */ + state |= (WORD) PTTFLAG; + if (!ReadVanB(port,dp_iDCD)) /* wir empfangen etwas */ + state |= (WORD) DCDFLAG; + + return(state); +} + +static void vanessa_ctl(int req) +{ + switch (req) + { + case L1CRES : van_res = TRUE; break; + case L1CCMD : van_cmd = TRUE; break; + case L1CTST : van_tst = TRUE; break; + + default : break; + } +} + +/************************************************************************/ +/* Vanessa EXIT (nur fuer LINUX) */ +/************************************************************************/ +void vanessa_l1exit(void) +{ + register unsigned int port; + + /* Mem wieder freigeben... */ + munmap(base, 0x10000); + + /* und die IO-Ports */ + for (port = 0; port < L2PNUM; ++port) + { + ioperm(ledio_adr[port], 3, 0); + ioperm(reset_adr[port / 2], 3, 0); + } +} + +void vanessa_l1ctl(int req) +{ + vanessa_ctl(req); +} + +static BOOLEAN van_enabled(int port) +{ + return(portenabled(port) && (kissmode(port) == KISS_VAN)); +} + +void van_hwstr(int port, MBHEAD *mbp) +{ + putprintf(mbp, " v4.%02x%c", van_revision[port], van_patch[port]); +} + +#endif diff --git a/os/linux/vanlinux.h b/os/linux/vanlinux.h new file mode 100755 index 0000000..6a7c7b5 --- /dev/null +++ b/os/linux/vanlinux.h @@ -0,0 +1,92 @@ +/************************************************************************/ +/* */ +/* ***** ***** */ +/* ***** ***** */ +/* ***** ***** */ +/* ***** ***** */ +/* *************** *************** */ +/* ***************** ***************** */ +/* *************** *************** */ +/* ***** ***** TheNetNode */ +/* ***** ***** Portable */ +/* ***** ***** Network */ +/* ***** ***** Software */ +/* */ +/* File os/linux/vanlinux.h (maintained by: DG1KWA) */ +/* */ +/* This file is part of "TheNetNode" - Software Package */ +/* */ +/* Copyright (C) 1998 - 2008 NORD> TNC_TIMEOUT) + { + RING[uTNC].uReset++; + uRingStatus = RING_IDLE; + LOGL3("TNC %u: TNC seit %ld ms still, reinitialisiere Ring !", uTNC, (tic10 - RING[uTNC].tLastHeard) * 10); + LOGL3("tic10 ist %ld, LastHeard = %ld", tic10, RING[uTNC].tLastHeard); + break; + } + + /* normaler Watchdog fuer TNC-Anwesenheit */ + if ((tic10 - RING[uTNC].tWatchdog) > TNC_WATCHDOG) + { + cCmd[0] = cmdLED(uTNC); + toRing(cCmd, 1); + RING[uTNC].tWatchdog = tic10; + + /* RXC darf nicht ohne DCD gesetzt sein, ggf. korrigieren */ + if ((RING[uTNC].bDCD == FALSE) && (RING[uTNC].cRXC)) + { + RING[uTNC].cRXC = 0; + LOGL3("TNC %u: RXC-Korrektur !", uTNC); + } + } + + /* Festhaengende PTT loesen */ + if ((RING[uTNC].tPTTWatchdog != 0) && (tic10 > RING[uTNC].tPTTWatchdog)) + { + /* sendet dieses TNC momentan ? */ + if (RING[uTNC].cTXC > 0) + { + RING[uTNC].cTXC--; + LOGL3("TNC %u: TXC-Korrektur !", uTNC); + + /* noch Sendeframes im TNC, dann wieder scharf machen */ + if (RING[uTNC].cTXC > 0) + { + /* wir nehmen die Aussendung eines Frames maximaler Laenge, */ + /* TX-Delay, TX-Tail und etwas Sicherheit an */ + RING[uTNC].tPTTWatchdog = ( tic10 + + (2 * portpar[uMap_TNCtoPort[uTNC]].txdelay) + + (21120 / portpar[uMap_TNCtoPort[uTNC]].speed) + ); + } + else + { + RING[uTNC].tPTTWatchdog = 0; /* Wachhund aus */ + } + } + else + { + /* TNC sendet nicht, aber Wachhund auch angekettet ? */ + if (RING[uTNC].tPTTWatchdog != 0) + { + RING[uTNC].tPTTWatchdog = 0; + LOGL3("TNC %u: PTT-Watchdog entlaufen, wieder eingefangen !", uTNC); + } + } + } + } + } + + /* Ring nicht initialisiert */ + if (uRingStatus == RING_IDLE) + { + /* TNC-Strukturen initialisieren */ + for (uTNC = 0; uTNC < MAX_TNC; ++uTNC) + initTNC(uTNC); + + /* Zaehlung starten */ + startCount(); + + /* Zurueck zu anderen Aufgaben */ + return; + } + + /* Daten vom Ring holen (Daten, Meldungen etc.) */ + Sixpack_RX(); + + /* So lange wir auf das Zaehlpaket warten, keine Sendedaten auf */ + /* den Ring legen, aber ggf. noch ein Zaehlpaket senden. */ + if (uRingStatus == RING_INIT) + { + /* Falls nach zehn Sekunden kein Zaehlpaket kam, wieder eines senden */ + if ((tic10 - tLastInit) >= PROBE_TIMEOUT) + { + uRingStatus = RING_IDLE; + LOGL2("-RING-: Ring laeuft nicht, reinitialisiere ..."); + } + + return; + } + + /* Sendedaten zu den TNC bringen */ + Sixpack_TX(); +} + +/************************************************************************/ +/* Liefert den DCD-Status eines TNC */ +/* ACHTUNG, die "+" beim Zusammenbau des Status sollen da sein ! */ +/* (normalerweise waeren es "|=", aber die funktionieren hier nicht) */ +/************************************************************************/ +WORD Sixpack_DCD(UWORD uPort) +{ + WORD uDCD = 0; + register UBYTE uTNC; /* Nummer des zustaendigen TNC ermitteln */ + + if (uPort <= L2PNUM) + uTNC = uMap_PorttoTNC[uPort]; + else + return (0); + + /* Kein TNC fuer diesen Port */ + if (uTNC == 0xFF) + return (0); + + /* DCD vom TNC gemeldet ? */ + if (RING[uTNC].bDCD == TRUE) + uDCD |= (WORD)(DCDFLAG); + + /* Sendet der TNC gerade oder Calibrate ? */ + if ( (RING[uTNC].cTXC > 0) + || (RING[uTNC].cTestCount > 0) + ) + uDCD |= (WORD)(PTTFLAG); + + /* Empfaengt der TNC momentan ein Frame ? */ +/* + if (RING[uTNC].cRXC > 0) + uDCD += (WORD)(RXBFLAG); +*/ + /* DCD-Zustand melden */ + return (uDCD); +} + +/************************************************************************/ +/* Verarbietung von normalen 6PACK-Meldungen */ +/************************************************************************/ +void processSixpackCmd(UBYTE cByte) +{ + UBYTE uTNC = (cByte & MASK_TNCNUM); + UBYTE cCmdBuf[1]; + + /* Puffer holen und Empfangsport eintragen */ + MBHEAD *rxfhd = NULL; + + /* LED-Kommandos, die keinen TNC fanden ignorieren wir */ + if ((cByte & CMD_LED) == CMD_LED) + return; + + /* Start of Frame, TX-Underrun, RX-Overrun, RX-Buffer Overflow */ + if ((cByte & MASK_NORMCMD) == MASK_NORMCMD) + { + /* nur die oberen Bits interessieren uns hier */ + if ((cByte & MASK_CMD) == CMD_SOF) + { + /* Start of Frame */ + LOGL4("TNC %u: 'Start of Frame' (%sleitend)", uTNC, ((cReceiveFrom != 0xFF) ? "aus" : "ein")); + + switch (uRXStatus) + { + /* Einleitendes SOF */ + case RX_WAIT_SOF: + /* RX beginnt, erstes SOF am Frameanfang */ + if (cReceiveFrom == 0xFF) + { + LOGL2("TNC %u: RX beginnt, RXC ist jetzt %u)", uTNC, RING[uTNC].cRXC); + + if (RING[uTNC].cRXC == 0) + LOGL3("TNC %u: 'Start of Frame' waehrend RXC noch null !!!", uTNC); + + if (uRXRawBufferSize != 0) + LOGL3("TNC %u: RX-Rohdatenpuffer schon vorgefuellt !!!", uTNC); + + /* merken, von welchem TNC wir empfangen */ + cReceiveFrom = uTNC; + + /* Puffer ruecksetzen */ +/* + memset(cRXRawBuffer, 0, sizeof(cRXRawBuffer)); + uRXRawBufferSize = 0; + memset(cRXBuffer, 0, sizeof(cRXBuffer)); + uRXBufferSize = 0; +*/ + /* CON-LED des betreffenden TNC einschalten */ + setLED(uTNC, LED_CON); + cCmdBuf[0] = cmdLED(uTNC); + toRing(cCmdBuf, 1); + } + else + LOGL3("TNC %u: RX-TNC bei erstem SOF schon gesetzt !", uTNC); + + /* Empfangszustand merken */ + uRXStatus = RX_WAIT_END; + break; + + /* Wir empfangen und haben beendendes SOF erhalten */ + case RX_WAIT_END: + if (cReceiveFrom != uTNC) + LOGL3("TNC %u: RX-TNC bei Frameende ungleich TNC (%u) bei Frameanfang !", uTNC, cReceiveFrom); + + /* Pruefen, ob Empfangsdaten da sind, wenn nein, dann sind */ + /* wir sehr wahrscheinlich out of sync und empfangen einfach */ + /* mal weiter, da wir jetzt erst wahrscheinlich am Frame- */ + /* anfang sind. */ + if (uRXRawBufferSize == 0) + { + /* wie bei normalem RX-Beginn ... */ + /* merken, von welchem TNC wir empfangen */ + cReceiveFrom = uTNC; + + /* Puffer ruecksetzen */ +/* + memset(cRXRawBuffer, 0, sizeof(cRXRawBuffer)); + uRXRawBufferSize = 0; + memset(cRXBuffer, 0, sizeof(cRXBuffer)); + uRXBufferSize = 0; +*/ + /* CON-LED des betreffenden TNC einschalten */ + setLED(uTNC, LED_CON); + cCmdBuf[0] = cmdLED(uTNC); + toRing(cCmdBuf, 1); + + LOGL2("TNC %u: Resync !!!", uTNC); + + return; + } + + /* Empfangene Daten dekodieren */ + if (DecodeRawBuffer(cReceiveFrom)) + { + /* Checksumme ist korrekt, Daten an L2 geben */ + /* Hier koennen auch Daten von TNC ankommen, */ + /* die keinem Port zugeordnet sind. Deren Daten */ + /* werfen wir weg. */ + if (portenabled(uMap_TNCtoPort[cReceiveFrom])) + { + /* Port ist eingeschaltet, dann Daten in den Empfangspuffer */ + register UWORD uByteCounter; + + /* Puffergroesse korrigieren (TX-Delay und Checksumme) */ + uRXBufferSize -= 2; + + /* Puffer holen */ + (rxfhd = (MBHEAD *)allocb(ALLOC_MBHEAD))->l2port = uMap_TNCtoPort[cReceiveFrom]; + + /* Frame in Buffer umkopieren */ + for (uByteCounter = 1; uByteCounter <= uRXBufferSize; ++uByteCounter) + putchr(cRXBuffer[uByteCounter], rxfhd); + + /* Frame zum L2 geben */ + relink((LEHEAD *)rxfhd, (LEHEAD *)rxfl.tail); + } + } + else + { + /* Checksumme fehlerhaft */ + LOGL3("TNC %u: Checksumme fehlerhaft !!!", uTNC); + RING[cReceiveFrom].uChecksumErr++; + } + + /* CON-LED ausschalten */ + resetLED(cReceiveFrom, LED_CON); + cCmdBuf[0] = cmdLED(cReceiveFrom); + toRing(cCmdBuf, 1); + + /* Frameempfang vermerken */ + if (RING[cReceiveFrom].cRXC > 0) + RING[cReceiveFrom].cRXC--; + + /* Empfangsvariablen neu initialisieren und Puffer ruecksetzen */ + cReceiveFrom = 0xFF; + uRXStatus = RX_WAIT_SOF; + + memset(cRXRawBuffer, 0, sizeof(cRXRawBuffer)); + uRXRawBufferSize = 0; + memset(cRXBuffer, 0, sizeof(cRXBuffer)); + uRXBufferSize = 0; + + LOGL3("TNC %u: RX beendet, RXC ist jetzt %u", uTNC, RING[uTNC].cRXC); + break; + + default: break; + } + } /* if (SOF) */ + + switch (cByte & MASK_CMD) + { + /* TX-Underrun */ + case MSG_TXU : /* TX-Underrun waehrend des Sendens des Testsignals ? */ + if (RING[uTNC].cTestCount > 0) + { + RING[uTNC].cTestCount = 0; + resetLED(uTNC, LED_STA | LED_CON); + cCmdBuf[0] = cmdLED(uTNC); + toRing(cCmdBuf, 1); + } + + RING[uTNC].uTXU++; + RING[uTNC].cTXC = 0; + LOGL3("TNC %u: TX-Underrun (neuer Zaehlerstand: %u)", uTNC, RING[uTNC].uTXU); + break; + + /* RX-Overrun */ + case MSG_RXO : RING[uTNC].uRXO++; + LOGL3("TNC %u: RX-Overrun (neuer Zaehlerstand: %u)", uTNC, RING[uTNC].uRXO); + break; + + /* RX Buffer Overflow */ + case MSG_RXB : RING[uTNC].uRXB++; + LOGL3("TNC %u: RX Buffer-Overflow (neuer Zaehlerstand: %u)", uTNC, RING[uTNC].uRXB); + break; + + default : break; + } /* switch */ + } /* if (... NORMCMD) */ +} + +/************************************************************************/ +/* Verarbeitung von 6PACK-Prioritaetskommandos */ +/************************************************************************/ +void processSixpackPrioCmd(UBYTE cByte) +{ + UBYTE uTNC = (cByte & MASK_TNCNUM); + + /* Prioritaetsmeldungen */ + if ((cByte & MASK_CALCNT) != 0) + { + LOGL4("TNC %u: Prioritaetskommando \"Zaehlung/Calibrate\" empfangen", uTNC); + + /* Calibrate, Kanalzuweisung */ + if ((cByte & MASK_CHAN) != 0) + { + /* Kanalzuweisung / Zaehlung */ + LOGL1("TNC %u: Kanalzuweisung empfangen", uTNC); + } + else + { + UBYTE cCmdBuf[2]; + + /* Calibrate */ + LOGL2("TNC %u: Calibrate-Paket empfangen, Calibrate-Zaehler des TNC ist %u", uTNC, RING[uTNC].cTestCount); + + /* TNC meldet beendetes Calibrate, wenn noch Calibrates uebrig, dann */ + /* wieder ein Kommando schicken und STA-Led einschalten */ + if (RING[uTNC].cTestCount > 1) + { + RING[uTNC].cTestCount--; + setLED(uTNC, LED_STA); + cCmdBuf[0] = cmdLED(uTNC); + cCmdBuf[1] = cmdCAL(uTNC); + toRing(cCmdBuf, 2); + LOGL2("TNC %u: Calibrate-Paket gesendet, Calibrate-Zaehler des TNC ist jetzt %u", uTNC, RING[uTNC].cTestCount); + } + else + { + /* letztes Calibrate beendet, dann STA-Led ausschalten */ + RING[uTNC].cTestCount = 0; + resetLED(uTNC, LED_STA); + cCmdBuf[0] = cmdLED(uTNC); + toRing(cCmdBuf, 1); + LOGL2("TNC %u: Calibrate beendet", uTNC); + } + } + } + else + { + /* DCD, RX-Zaehler, TX-Zaehler */ + /* DCD immer uebernehmen */ + RING[uTNC].bDCD = ((cByte & MASK_DCD) == MASK_DCD ? TRUE : FALSE); + + /* RX-Zaehler + 1 */ + /* Das Kommando ist nur erlaubt, wenn auch DCD gesetzt ist */ + if ((cByte & MASK_RXC) == MASK_RXC) + { + if (RING[uTNC].bDCD == TRUE) + { + RING[uTNC].cRXC++; + LOGL2("TNC %u: 'RX-Zaehler + 1', RXC ist jetzt %u", uTNC, RING[uTNC].cRXC); + } + else + LOGL2("TNC %u: 'RX-Zaehler + 1' ohne DCD, ignoriere.", uTNC); + } + + /* TX-Zaehler + 1 */ + if ((cByte & MASK_TXC) == MASK_TXC) + { + if (RING[uTNC].cTXC > 0) + { + RING[uTNC].cTXC--; + + /* noch Frames in der Sendung, dann Wachhund scharf machen */ + if (RING[uTNC].cTXC > 0) + { + /* wir nehmen die Aussendung eines Frames maximaler Laenge, */ + /* TX-Delay, TX-Tail und etwas Sicherheit an */ + RING[uTNC].tPTTWatchdog = ( tic10 + + (2 * portpar[uMap_TNCtoPort[uTNC]].txdelay) + + (21120 / portpar[uMap_TNCtoPort[uTNC]].speed) + ); + } + else /* Aussendung beendet, Wachhund wieder anketten */ + { + RING[uTNC].tPTTWatchdog = 0; + } + } + else /* keine Sendung, ist der Hund auch angekettet ? */ + { + if (RING[uTNC].tPTTWatchdog != 0) + RING[uTNC].tPTTWatchdog = 0; + } + + LOGL2("TNC %u: 'TX-Zaehler + 1', TXC ist jetzt %u", uTNC, RING[uTNC].cTXC); + } + + /* TNC lebt noch */ + RING[uTNC].tLastHeard = tic10; + } +} + +/************************************************************************/ +/* 6PACK-Empfang */ +/************************************************************************/ +void Sixpack_RX(void) +{ + UBYTE cBuf[520]; + LONG iRet; + register int iCounter; + register int iSelRet; + UBYTE cRXByte; + UBYTE uNumTNC; + + /* ganz wichtig, Linux modifiziert in select() diese Werte !!! */ + tv.tv_sec = 0; + tv.tv_usec = 0; + + FD_ZERO(&rset); + FD_SET((unsigned int)iDescriptor, &rset); + + iSelRet = select(iDescriptor + 1, &rset, NULL, NULL, &tv); + + /* Immer pruefen ob daten anliegen. */ + iSelRet = TRUE; + + /* Fehler bei select() ? */ + if (iSelRet < 0) + { + LOGL4("-RING-: Fehler %n bei select() : %s", errno, strerror(errno)); + Sixpack_l1exit(); + Sixpack_l1init(); + return; + } + + /* select() hat keinen lesbaren Descriptor gefunden, */ + /* oder es ist nicht unserer */ + if ((iSelRet == 0) || (!FD_ISSET(iDescriptor, &rset))) + return; + + memset(cBuf, 0, sizeof(cBuf)); + + /* Daten holen */ + iRet = read(iDescriptor, cBuf, 512); + + /* Ist was gekommen ? */ + if (iRet > 0) + { + /* zeichenweise Verarbeitung */ + for (iCounter = 0; iCounter < iRet; ++iCounter) + { + /* Zeichen aus dem Puffer holen */ + cRXByte = cBuf[iCounter]; + + /* Wir warten noch auf das Zaehlpaket, so lange kein anderer Empfang */ + if (uRingStatus == RING_INIT) + { + /* Zaehlkommando zurueckgekommen ? */ + if ((cRXByte & CMD_INIT) == CMD_INIT) + { + /* Kanalzuweisung / Zaehlung */ + uNumTNC = (cRXByte - CMD_INIT); + + LOGL1("-RING-: TNC-Zaehlung beendet, %u TNC gefunden", uNumTNC); + + /* Ring "kurzgeschlossen", noch einmal initialisieren */ + if (uNumTNC == 0) + { + uRingStatus = RING_IDLE; + LOGL3("-RING-: kein TNC im Ring, Ring ist kurzgeschlossen !"); + return; + } + + /* Ports mit TNC verbinden */ + if (assignPorts(uNumTNC) != uNumTNC) + LOGL1("-RING-: TNC-Zaehlung weicht von konfigurierter Portanzahl ab !!!"); + } + + /* Falls nach zehn Sekunden kein Zaehlpaket kam, wieder eines senden */ + if ((tic10 - tLastInit) >= PROBE_TIMEOUT) + { + uRingStatus = RING_IDLE; + LOGL2("-RING-: Ring laeuft nicht, reinitialisiere ..."); + return; + } + + continue; + } + + /* Meldungen und Daten verarbeiten */ + /* Prioritaetsmeldungen */ + if ((cRXByte & MASK_PRIOCMD) == MASK_PRIOCMD) + { + processSixpackPrioCmd(cRXByte); + continue; + } + + /* normale Meldungen */ + if ((cRXByte & MASK_NORMCMD) == MASK_NORMCMD) + { + processSixpackCmd(cRXByte); + continue; + } + + /* Daten */ + if ((cRXByte & MASK_DATA) == 0) + { + /* Daten zum falschen Zeitpunkt ? */ + if ((uRXStatus != RX_WAIT_END) || (cReceiveFrom == 0xFF)) + { + LOGL3("-RING-: Daten ohne SOF (%x) !!! rxsize=%u", cRXByte, uRXRawBufferSize); +/* continue; */ + } + + /* In den rohen Puffer damit */ + cRXRawBuffer[uRXRawBufferSize++] = cRXByte; + + continue; + } + + LOGL1("-RING-: Daten ohne Ziel !!! (hex 0x%x, dez %u)", cRXByte, cRXByte); + } /* for (...) */ + } /* if (iRet > 0) */ + else + { + /* wenn nach zehn Sekunden kein Zaehlpaket kam, dann noch eines senden */ + if ( (iRet == 0) + && (uRingStatus == RING_INIT) + && ((tic10 - tLastInit) >= PROBE_TIMEOUT) + ) + uRingStatus = RING_IDLE; + + /* Schnittstellenfehler ! Das sollte NIE passieren ... */ + if ((iRet < 0) && (errno != EAGAIN) && (errno != EWOULDBLOCK)) + { + /* Oh oh ... alles versuchen neu zu starten ... */ + LOGL2("-RING-: Fehler auf der Schnittstelle, start Ring neu !!!"); + Sixpack_l1exit(); + Sixpack_l1init(); + } + } +} + +/************************************************************************/ +/* Dekodiert den gefuellten 6PACK-Rohdatenpuffer in den Nutzdatenpuffer */ +/************************************************************************/ +BOOLEAN DecodeRawBuffer(UBYTE uTNC) +{ + register UWORD uBufferPos; + + UBYTE cChecksum = uTNC; + UBYTE cTmpByte = 0; + UBYTE cBufCorrection = 0; + + /* Puffer auffuellen */ + while ((uRXRawBufferSize % 4) != 0) + { + ++uRXRawBufferSize; + ++cBufCorrection; /* Merken fuer Korrektur des dekodierten Puffers */ + } + + /* rohen Empfangspuffer decodieren */ + for (uBufferPos = 0; uBufferPos <= uRXRawBufferSize; ++uBufferPos) + { + register UBYTE cByte = cRXRawBuffer[uBufferPos]; + + switch (uBufferPos % 4) + { + /* 1. 6PACK */ + case 0: cTmpByte = cByte; + break; + + /* 2. 6PACK */ + case 1: cRXBuffer[uRXBufferSize++] = (cTmpByte | ((cByte << 2) & 0xC0)); + cTmpByte = (cByte & 0x0F); + break; + + /* 3. 6PACK */ + case 2: cRXBuffer[uRXBufferSize++] = (cTmpByte | ((cByte << 2) & 0xF0)); + cTmpByte = (cByte & 0x03); + break; + + /* 4. 6PACK */ + case 3: cRXBuffer[uRXBufferSize++] = (cTmpByte | (cByte << 2)); + break; + + default: break; + } + } + + /* Checksumme ueber den dekodierten Puffer berechnen */ + for (uBufferPos = 0; uBufferPos < uRXBufferSize; ++uBufferPos) + cChecksum += cRXBuffer[uBufferPos]; + + /* dekodierten Puffer in der Groesse korrigieren */ + uRXBufferSize -= cBufCorrection; + + /* Checksumme pruefen und entsprechend melden */ + if (cChecksum == 0xFF) + return (TRUE); + else + { + LOGL3("TNC %u: Checksummenfehler : %u Bytes roh, %u Byte dekodiert, Checksumme %u", + uTNC, uRXRawBufferSize, uRXBufferSize, cChecksum); + return (FALSE); + } +} + +/************************************************************************/ +/* Sendet alle fuer einen Port anstehenden Frames zum TNC */ +/************************************************************************/ +void sendSixpack(UBYTE uTNC) +{ + UBYTE cCheckSum; + UBYTE cRawBuffer[512]; + UBYTE cSendBuffer[512]; + UWORD uRawBufferSize; + UWORD uSendBufferSize; + register UWORD uCounter; + + MBHEAD *txfhdl; + LHEAD *l2flp; + + /* Portnummer fuer den TNC holen */ + UWORD uPort = uMap_TNCtoPort[uTNC]; + + /* Sicher ist sicher ... */ + if (kissmode(uPort) != KISS_6PACK) + return; + + /* Sendeliste des Ports holen */ + l2flp = (LHEAD *)&txl2fl[uPort]; + + /* Bei ausgeschalteten Ports die Sendeliste ohne Sendung kopieren */ + if (!portenabled(uPort)) + { + while (l2flp->head != l2flp) + relink(ulink((LEHEAD *) l2flp->head), (LEHEAD *)stfl.tail); + return; + } + + /* So lange Sendepakete da sind, diese auf den Ring geben */ + /* TNC aber nicht ueberfuellen */ + while (kick[uPort]) + { + /* Sendelistenzeiger pruefen */ + if (l2flp->head == l2flp) + { + /* Zeiger steht auf Anfang, also doch nix zu senden */ + kick[uPort] = FALSE; + return; + } + + /* Puffer loeschen fuer neues Frame */ + memset(cSendBuffer, 0, sizeof(cSendBuffer)); + uSendBufferSize = 0; + memset(cRawBuffer, 0, sizeof(cRawBuffer)); + uRawBufferSize = 0; + + /* STA-LED waehrend der Datenuebertragung zum TNC einschalten */ + setLED(uTNC, LED_STA); + cSendBuffer[uSendBufferSize++] = cmdLED(uTNC); + /* "TX-Zaehler + 1" und "Start of Frame" senden */ + cSendBuffer[uSendBufferSize++] = cmdTXC(uTNC); + cSendBuffer[uSendBufferSize++] = cmdSOF(uTNC); + + /* TX-Delay in den rohen Puffer */ + cRawBuffer[uRawBufferSize++] = (UBYTE)(portpar[uPort].txdelay & 0xFF); + + /* Checksumme mit der TNC-Nummer initialisieren und TX-Delay hinzufuegen */ + cCheckSum = uTNC; + cCheckSum += (UBYTE)(portpar[uPort].txdelay & 0xFF); + + /* Zeiger auf Sendeliste holen */ + ulink((LEHEAD *)(txfhdl = (MBHEAD *)l2flp->head)); + + /* Rohdaten kopieren und Checksumme bilden */ + while (txfhdl->mbgc < txfhdl->mbpc) + { + register UBYTE cByte = getchr(txfhdl); + cRawBuffer[uRawBufferSize++] = cByte; + cCheckSum += cByte; + } + + /* Checksumme dem Puffer hinzufuegen */ + cRawBuffer[uRawBufferSize] = (UBYTE)(0xFF - cCheckSum); + + /* Puffer codieren */ + for (uCounter = 0; uCounter <= uRawBufferSize; ++uCounter) + { + switch (uCounter % 3) + { + /* 1. Byte -> 1. & 2. 6PACK */ + case 0: cSendBuffer[uSendBufferSize++] = (cRawBuffer[uCounter] & 0x3F); + cSendBuffer[uSendBufferSize] = ((cRawBuffer[uCounter] >> 2) & 0x30); + break; + + /* 2. Byte -> 2. & 3. 6PACK */ + case 1: cSendBuffer[uSendBufferSize++] |= (cRawBuffer[uCounter] & 0x0F); + cSendBuffer[uSendBufferSize] = ((cRawBuffer[uCounter] >> 2) & 0x3C); + break; + + /* 3. Byte -> 3. & 4. 6PACK */ + case 2: cSendBuffer[uSendBufferSize++] |= (cRawBuffer[uCounter] & 0x03); + cSendBuffer[uSendBufferSize++] = (cRawBuffer[uCounter] >> 2); + + default: break; /* das sollte _nie_ passieren ... */ + } + } + + /* Sendepuffer "auffuellen" (terminiert das in Bearbeitung befindliche 6PACK) */ + if ((uRawBufferSize % 3) != 2) + ++uSendBufferSize; + + /* abschliessendes SOF */ + cSendBuffer[uSendBufferSize++] = cmdSOF(uTNC); + + /* STA-LED wieder ausschalten */ + resetLED(uTNC, LED_STA); + cSendBuffer[uSendBufferSize++] = cmdLED(uTNC); + + /* Auf den Ring damit */ + toRing(cSendBuffer, uSendBufferSize); + + /* Merken, dass ein Sendeframe unterwegs ist und Wachhunde scharf machen */ + RING[uTNC].cTXC++; + RING[uTNC].tTXWatchdog = tic10; + RING[uTNC].tPTTWatchdog = ( tic10 + + (2 * portpar[uMap_TNCtoPort[uTNC]].txdelay) + + (21120 / portpar[uMap_TNCtoPort[uTNC]].speed) + ); + + /* Frame in die gesendet-Liste umhaengen */ + relink((LEHEAD *)txfhdl, (LEHEAD *)stfl.tail); + + /* ein Frame gesendet, Sendewarteschlange aktualisieren */ + kick[uPort] = ((LHEAD *)l2flp->head != l2flp); + + LOGL3("TNC %u: Frame an TNC gesendet, TXC ist jetzt %u", uTNC, RING[uTNC].cTXC); + } /* while (...) */ +} + +/************************************************************************/ +/* Sendet ausstehende Frames zu den TNC, Kanalarbitrierung */ +/************************************************************************/ +void Sixpack_TX(void) +{ + register UBYTE uTNC; + register UWORD uPort; + UBYTE cCmdBuf[1]; + + /* Merker, ob wir senden duerfen */ + BOOLEAN bSendOK = FALSE; + + for (uTNC = 0; uTNC < MAX_TNC; ++uTNC) + { + /* Nur fuer angeschlossene TNC. Da die TNC-Nummern nur ununterbrochen */ + /* aufsteigend sein koennen, beim ersten nicht vorhandenen TNC raus, */ + /* es kann keiner mehr danach kommen. */ + if (RING[uTNC].bPresent == FALSE) + break; + + /* Wenn wir senden und die TX-Watchdogzeit abgelaufen ist, */ + /* dann den aktuellen LED-Zustand zum TNC senden (TX-Watchdog) */ + if ( ( (RING[uTNC].cTestCount > 0) /* Testsignal */ + || (RING[uTNC].cTXC > 0) /* unbestaetigte Frames */ + ) + && ((RING[uTNC].tTXWatchdog + TXWDTIME) < tic10)) + { + /* aktuellen LED-Zustand als Watchdogpaket senden */ + cCmdBuf[0] = cmdLED(uTNC); + toRing(cCmdBuf, 1); + + /* letzten Watchdogzeitpunkt merken */ + RING[uTNC].tTXWatchdog = tic10; + } + + /* Port holen, der diesem TNC zugeordnet ist */ + uPort = uMap_TNCtoPort[uTNC]; + + /* Arbiter fuer Kanalzugriff */ + /* Port hat was zu senden, TNC nicht ueberfuellen */ + if (kick[uPort] /* && RING[uTNC].cTXC < 5 */ ) + { + LHEAD *l2flp; + + LOGL4("TNC %u: Port %u ist fuer Sendung markiert und hat Platz", uTNC, uPort); + + /* Sendeliste des Ports holen */ + l2flp = (LHEAD *)&txl2fl[uPort]; + + /* Sendelistenzeiger pruefen */ + if (l2flp->head == l2flp) + { + /* Zeiger steht auf Anfang, doch nix zu senden */ + LOGL4("TNC %u: keine Sendedaten, eventuell Calibrate, keine Arbitrierung", uTNC); + kick[uPort] = FALSE; + return; + } + + /* Arbitrierung notwendig ? */ + if ((fullduplex(uPort)) || (RING[uTNC].cTXC > 0)) + { + LOGL4("TNC %u: Port ist Vollduplex oder sendet bereits, sende sofort", uTNC); + bSendOK = TRUE; + } + else + { + /* DCD beruecksichtigen */ + if (!(Sixpack_DCD(uPort) & (WORD)(DCDFLAG))) + { + LOGL4("TNC %u: Kanal ist frei, Slottime ist %u ms", uTNC, portpar[uPort].slottime * 10); + + /* Hatten wir schon mal versucht zu senden ? (Slottime) */ + if ( (RING[uTNC].tNextArbit != 0L) + && (RING[uTNC].tNextArbit > tic10) + ) + { + LOGL4("TNC %u: nicht genug Zeit seit letztem Arbit vergangen", uTNC); + } + else + { + LOGL4("TNC %u: genug Zeit seit letztem Arbit vergangen", uTNC); + + /* Kanalzugriff auswuerfeln (Persistenz) */ + if ((rand() % 255) <= (dama(uPort) ? 0xFF : (portpar[uPort].persistance & 0xFF))) + { + LOGL4("TNC %u: Zufallszahl kleiner, Sendung moeglich", uTNC); + bSendOK = TRUE; + } + else + { + LOGL4("TNC %u: Zufallszahl zu gross, keine Sendung", uTNC); + /* Merken, wann wir es zuletzt versucht hatten zu senden, */ + /* naechster Versuch erst nach Ablauf der Slottime. */ + RING[uTNC].tNextArbit = (tic10 + portpar[uPort].slottime); + } + } + } + else + { + LOGL4("TNC %u: DCD erkannt, kann nicht mehr senden", uTNC); + /* Waren wir selbst grad in der Arbitrierung und wurden */ + /* durch die RX-DCD unterbrochen, dann Sendeversuch abbrechen. */ + if (RING[uTNC].tNextArbit != 0L) + { + RING[uTNC].tNextArbit = 0L; + LOGL4("TNC %u: laufende Arbitrierung abgebrochen", uTNC); + } + } + } + + if (bSendOK == TRUE) + { + /* Kanal frei und Sendung ok */ + LOGL4("TNC %u: Arbitrierung, sende !", uTNC); + sendSixpack(uTNC); + /* wir konnten Senden */ + RING[uTNC].tNextArbit = 0L; + } + else + { + /* Kanal blockiert, nicht senden */ + LOGL4("TNC %u: Arbitrierung nicht erfolgreich", uTNC); + } + } /* if ( kick[uPort] ... ) */ + } /* for ( ... ) */ +} + +/************************************************************************/ +/* TNCs im Ring zaehlen / Zaehlpaket senden */ +/************************************************************************/ +void startCount(void) +{ + UBYTE cCmdBuf[1]; + + /* Sicherheitscheck, ob wir die Zuordnungen jetzt aendern duerfen */ + if (uRingStatus != RING_IDLE) + return; + + /* Zaehlkommando zusammenbauen und senden */ + cCmdBuf[0] = cmdINIT(0); + toRing(cCmdBuf, 1); + + /* Zeitpunkt und Sendung merken */ + tLastInit = tic10; + ++uNumProbes; + + /* Merken, dass wir auf das Zaehlpaket warten */ + uRingStatus = RING_INIT; + LOGL4("-RING-: Zaehlpaket gesendet"); +} + +/************************************************************************/ +/* Datenpuffer auf den Ring senden */ +/* (basierend auf writen() aus einem Stevens-Buch) */ +/************************************************************************/ +void toRing(UBYTE *pBuffer, UWORD uSize) +{ + UWORD uErrorCounter = 0; + + size_t tLeft = uSize; + LONG tWritten; + const UBYTE *pBufPtr; + + pBufPtr = pBuffer; + + /* nur wenn der Ring offen ist duerfen wir hier rein */ + if (uRingStatus == RING_HALT) + return; + + /* solange noch Daten zu senden sind */ + while (tLeft > 0) + { + if ((tWritten = write(iDescriptor, (void *)pBufPtr, tLeft)) <= 0) + { + if (errno == EINTR) + tWritten = 0; + else + { + if (++uErrorCounter >= 0xFF) + { + LOGL3("-RING-: Schnittstellenfehler %u (%s)", errno, strerror(errno)); + Sixpack_l1exit(); + Sixpack_l1init(); + return; + } + } + } + + tLeft -= tWritten; + pBufPtr += tWritten; + } +} + +/************************************************************************/ +/* Ordnet jedem 6PACK-Port einen freien TNC-Port */ +/************************************************************************/ +UBYTE assignPorts(UBYTE uAvailTNC) +{ + register UBYTE i; + register UBYTE j = 0; + + UBYTE cCmdBuf[2]; + + /* Sicherheitscheck, ob wir die Zuordnungen jetzt aendern duerfen */ + if (uRingStatus != RING_INIT) + return (0); + + /* zuerst alle TNC als nicht vorhanden markieren */ + for (i = 0; i < MAX_TNC; ++i) + { + RING[i].bPresent = FALSE; + uMap_TNCtoPort[i] = 0; + } + + /* und das Gleiche mit den Ports machen */ + for (i = 0; i < L2PNUM; ++i) + uMap_PorttoTNC[i] = 0xFF; /* kein TNC */ + + /* Alle L2-Ports durchgehen */ + for (i = 0; (i < L2PNUM && j < uAvailTNC); ++i) + { + /* andere Ports nicht beachten */ + if (kissmode(i) != KISS_6PACK) + continue; + + LOGL2("-RING-: Assoziiere TNC %u mit Port %u", j, i); + + /* TNC mit Port verbinden */ + RING[j].bPresent = TRUE; + RING[j].tWatchdog = tic10; + RING[j].tLastHeard = tic10; + RING[j].tPTTWatchdog = 0; + uMap_PorttoTNC[i] = j; + uMap_TNCtoPort[j] = i; + + /* bei gefundenen TNC die CON-LED einschalten */ + resetLED(j, LED_STA); + setLED(j, LED_CON); + cCmdBuf[0] = cmdLED(j); + resetLED(j, LED_CON); + toRing(cCmdBuf, 1); + ++j; + } + + /* Empfang und initialisieren */ + cReceiveFrom = 0xFF; + uRXStatus = RX_WAIT_SOF; + + /* Ring freigeben fuer Datenverkehr */ + uRingStatus = RING_RUN; + + /* melden, wie viele Zuordnungen gemacht worden sind */ + return (j); +} + +/************************************************************************/ +/* L1-Kontrolle (Reset, Portparameter etc.) */ +/************************************************************************/ +void Sixpack_l1ctl(int iReq, UWORD uPort) +{ + UBYTE cCmdBuf[2]; + register UBYTE uTNC = uMap_PorttoTNC[uPort]; + + /* nur 6PACK-Ports und davon auch nur die existierenden duerfen hier rein */ + if ( (kissmode(uPort) != KISS_6PACK) + || (RING[uTNC].bPresent == FALSE) + ) + return; + + /* Anfragen unterscheiden */ + switch (iReq) + { + /* Reset eines TNC. Das geht bei 6PACK nicht direkt, also muss der ganze */ + /* Ring dran glauben ... */ + case L1CRES : RING[uTNC].uReset++; + /* den Ring neu initialiseren */ + uRingStatus = RING_IDLE; + LOGL2("TNC %u: TNC-Reset (neuer Zaehlerstand: %u)", uTNC, RING[uTNC].uReset); + break; + + /* Testsignal initiieren (4 x 15 Sekunden) */ + case L1CTST : RING[uTNC].cTestCount = 4; + setLED(uTNC, LED_STA); + cCmdBuf[0] = cmdCAL(uTNC); + cCmdBuf[1] = cmdLED(uTNC); + toRing(cCmdBuf, 2); + LOGL2("TNC %u: Testsignal initiiert", uTNC); + break; + + /* Portparameter zum TNC bringen, das braucht 6PACK nicht, */ + /* alles ausser TX-Delay machen wir selbst. */ + case L1CCMD : + default : break; + } +} + +/************************************************************************/ +/* Device einrichten */ +/************************************************************************/ +void Sixpack_l1init(void) +{ + register UWORD i; + UWORD uFehler = 0; + DEVICE *l1pp; + BOOLEAN bPortFound = FALSE; + + /* Zufallsgenerator initialisieren */ + srand(0); + + /* Erstes 6PACK-Device suchen fuer Lockfile */ + /* Alle L1-Ports durchgehen */ + for (i = 0; i < L1PNUM; ++i) + { + l1pp = &l1port[i]; + + if (l1pp->kisstype == KISS_6PACK) + { + bPortFound = TRUE; + break; + } + } + + /* haben wir einen Port gefunden ? */ + if (bPortFound == FALSE) + return; + + /* Lock-File schreiben */ + l1pp->lock = -1; + + /* Seriellen Port fuer Ein- und Ausgabe oeffnen */ + if (uFehler == 0) /* nur wenn Lock-File geschrieben */ + { /* wurde oder nicht gefordert war */ + if ((iDescriptor = open_win(l1pp->device, l1pp->speed)) == -1) + { + uFehler = 2; + printf("Error: can't open device %s\n", l1pp->device); + printf(" (%s)\n", strerror(errno)); + LOGL1("Error: can't open device %s", l1pp->device); + LOGL1(" (%s)", strerror(errno)); + } + } + + /* Serielle Schnittstelle auf neue Parameter einstellen */ + if (uFehler == 0) + { + l1pp->port_active = TRUE; + + /* Ring ist nun offen, aber noch nicht initialisiert */ + uRingStatus = RING_IDLE; + + LOGL1("-RING-: Port erfolgreich geoeffnet"); + + return; + } + + /* Port war schon offen, aber noch nicht veraendert, nur schliessen */ + if (uFehler > 2) + { + CloseHandle((void *)iDescriptor); + iDescriptor = -1; + } + + /* Port war nicht offen, aber es existiert ein Lockfile, schliessen */ + if (uFehler > 1) + { + if (l1pp->lock != -1) + { + close(l1pp->lock); + l1pp->lock = -1; + } + } + + /* Lockfile loeschen */ + if ((*(l1pp->tnn_lockfile) != '\0') && (l1pp->lock != -1)) + unlink(l1port[i].tnn_lockfile); + + LOGL1("-RING-: Port %s konnte nicht geoeffnet werden !", l1pp->device); +} + +/************************************************************************/ +/* Device schliessen */ +/************************************************************************/ +void Sixpack_l1exit(void) +{ + register UWORD i; + + /* Erstes 6PACK-Device suchen */ + /* Alle L1-Ports durchgehen */ + for (i = 0; i < L1PNUM; ++i) + { + if (l1port[i].kisstype == KISS_6PACK) + break; + } + + /* Keinen 6PACK-Port gefunden ? */ + if (i == L1PNUM) + return; + + /* Ring wird angehalten */ + uRingStatus = RING_HALT; + + /* Serieller Port offen ? Dann schliessen */ + if (iDescriptor != -1) + { + /* Port schliessen */ + CloseHandle((void *)iDescriptor); + iDescriptor = -1; + } + else + return; + + /* Lockfile gesetzt ? */ + if (*(l1port[i].tnn_lockfile) != '\0') + { + /* Lockfile offen ? Dann schliessen und loeschen */ + if (l1port[i].lock != -1) + { + close(l1port[i].lock); + l1port[i].lock = -1; + unlink(l1port[i].tnn_lockfile); + } + } + + /* Port nicht mehr aktiv */ + l1port[i].port_active = FALSE; + + LOGL1("-RING-: Port geschlossen"); +} + +/************************************************************************/ +/* Anzeige der TNC-Statistiken */ +/************************************************************************/ +void ccp6pack(void) +{ + MBHEAD *mbp; + register UBYTE uTNC; + register UBYTE i; + register UBYTE uNumPorts = 0; + + ULONG uUpDays = (tic10 - tLastInit) / 100; /* eigentlich sinds hier noch Sekunden ... */ + ULONG uUpHours, uUpMinutes, uUpSeconds; + +#define BUFLEN 32 + char cBuf[BUFLEN + 1]; + + /* Alle L2-Ports durchgehen */ + for (i = 0; i < L2PNUM; ++i) + if (kissmode(i) == KISS_6PACK) + ++uNumPorts; + + /* ueberhaupt ein Port da ? */ + if (uNumPorts == 0) + { + mbp = putals("No 6PACK-Ports configured."); + /* und ab die Post ... */ + putprintf(mbp, "\r"); + prompt(mbp); + seteom(mbp); + return; + } + + /* Sysop will aendern und noch was in der Zeile da ? */ + if (issyso() && skipsp(&clicnt, &clipoi)) + { + /* Frischer Buffer */ + memset(cBuf, 0, sizeof(cBuf)); + + /* Operation lesen (add, delete) */ + for (i = 0; i < BUFLEN; ++i) + { + if ((!clicnt) || (*clipoi == ' ')) + break; + clicnt--; + cBuf[i] = toupper(*clipoi++); + } + + /* Hinzufuegen (add oder +) */ + if ( (strcmp(&cBuf[0], "LOGLEVEL") == 0) + || (strcmp(&cBuf[0], "LOG") == 0) + ) + { + WORD uNewLevel; + + /* Noch was da in der Kommandozeile ? */ + if (!skipsp(&clicnt, &clipoi)) + { + mbp = getmbp(); + putprintf(mbp, "6PACK's actual loglevel is %u\r", uLogLevel); + /* und ab die Post ... */ + prompt(mbp); + seteom(mbp); + return; + } + + /* neues Loglevel lesen */ + uNewLevel = nxtnum(&clicnt, &clipoi); + + if (((int)uNewLevel < 0) || (uNewLevel > 4)) + { + putmsg("error: loglevel out of range (0-4) !!!\r"); + return; + } + + /* Wert uebernehmen */ + SixpackLog("-RING-: Loglevel %u -> %u", uLogLevel, uNewLevel); + uLogLevel = (UWORD)uNewLevel; + + /* und ab die Post ... */ + mbp = getmbp(); + prompt(mbp); + seteom(mbp); + return; + } + } + + mbp = putals("6PACK Error-Statistics:\r"); + + putprintf(mbp, " TX- RX- RX-Buffer-\r"); + putprintf(mbp, "-TNC#-Port#-Underrun-Overrun--Overflow--Checksum-Resets-Cal-RXC-TXC-LHeard[ms]\r"); + + /* alle TNC durchgehen */ + for (uTNC = 0; uTNC < MAX_TNC; ++uTNC) + { + /* nicht vorhandene TNC */ + if (RING[uTNC].bPresent == FALSE) + { + putprintf(mbp, " %u N/A - - - - - - - - -\r", uTNC); + continue; + } + + /* vorhandene TNC */ + putprintf(mbp, " %u %2u %5u %5u %5u %5u %5u %1u %2u %2u %5u\r", + uTNC, /* TNC */ + uMap_TNCtoPort[uTNC], /* Port */ + RING[uTNC].uTXU, /* TX-Underrun */ + RING[uTNC].uRXO, /* RX-Overrun */ + RING[uTNC].uRXB, /* RX-Buffer Overflow */ + RING[uTNC].uChecksumErr, /* Anz. Checksummenfehler */ + RING[uTNC].uReset, /* Anz. Resets */ + RING[uTNC].cTestCount, /* Anz. Calibrates */ + RING[uTNC].cRXC, /* RX-Zaehler */ + RING[uTNC].cTXC, /* TX-Zaehler */ + ((tic10 - RING[uTNC].tLastHeard) * 10)); /* LastHeard */ + } /* for (...) */ + + putprintf(mbp, "\rRing is "); + + switch (uRingStatus) + { + case RING_HALT : putprintf(mbp, "halted due to unrecoverable errors ! Please restart.\r"); + break; + + case RING_IDLE : putprintf(mbp, "waiting for TNC-initialization.\r"); + break; + + case RING_INIT : putprintf(mbp, "awaiting the return of the probe packet.\r"); + putprintf(mbp, "(%u probes sent so far, last probe sent %u ms ago)\r", uNumProbes, ((tic10 - tLastInit) * 10) ); + break; + + case RING_RUN : putprintf(mbp, "up and running for"); + + uUpSeconds = uUpDays % 60L; + uUpDays /= 60L; + uUpMinutes = uUpDays % 60L; + uUpDays /= 60L; + uUpHours = uUpDays % 24L; + uUpDays /= 24L; + + if (uUpDays < 1L) + putprintf(mbp, " %2lu:%02lu:%02lu\r", uUpHours, uUpMinutes, uUpSeconds); /* hh:mm:ss */ + else + { + if (uUpDays < 99L) + putprintf(mbp, " %2lu/%02lu:%02lu\r", uUpDays, uUpHours, uUpMinutes); /* dd/hh:mm */ + else + putprintf(mbp, " %5lu/%02lu\r", uUpDays, uUpHours); /* ddddd/hh */ + } + break; + + default: putprintf(mbp, "an undefined state !!! You really shouldn't see this ... Please restart.\r"); break; + } + + /* und ab die Post ... */ + putprintf(mbp, "\r"); + prompt(mbp); + seteom(mbp); +} + +/************************************************************************/ +/* Log-Funktion zum Debugging */ +/************************************************************************/ +void SixpackLog(const char *format, ...) +{ + FILE *fp; + va_list arg_ptr; + struct timeval tv; + static char str[30]; + char *ptr; + + fp = fopen("6pack.log", "a"); + + if (fp != NULL) + { + gettimeofday(&tv, NULL); + ptr = ctime(&tv.tv_sec); + strcpy(str, &ptr[11]); + fprintf(fp, "%s:", str); + + va_start(arg_ptr, format); + vfprintf(fp, format, arg_ptr); + va_end(arg_ptr); + + fprintf(fp, "\n"); + fclose(fp); + } + else + { + /* Fehler beim Schreiben in die Logdatei, dann das Logging beenden */ + uLogLevel = 0; + } +} + +/**************************************************************************/ + +#endif +/* End of os/win32/6pack.c */ diff --git a/os/win32/6pack.h b/os/win32/6pack.h new file mode 100755 index 0000000..8f48b7a --- /dev/null +++ b/os/win32/6pack.h @@ -0,0 +1,222 @@ +/************************************************************************/ +/* */ +/* ***** ***** */ +/* ***** ***** */ +/* ***** ***** */ +/* ***** ***** */ +/* *************** *************** */ +/* ***************** ***************** */ +/* *************** *************** */ +/* ***** ***** TheNetNode */ +/* ***** ***** Portable */ +/* ***** ***** Network */ +/* ***** ***** Software */ +/* */ +/* File os/linux/6pack.h (maintained by: DG9OBU) */ +/* */ +/* This file is part of "TheNetNode" - Software Package */ +/* */ +/* Copyright (C) 1998 - 2008 NORD> TNC) */ +#define CMD_LED 0x60 /* Grundmaske fuer LED-Kommando */ +#define CMD_CON 0x08 /* LED CON (PC -> TNC) */ +#define CMD_STA 0x10 /* LED STA (PC -> TNC) */ +#define CMD_CAL 0xE0 /* Calibrate (PC <> TNC) */ +#define CMD_INIT 0xE8 /* Kanalzuweisung (PC <> TNC) */ +#define CMD_PRIO 0x80 /* Prioritaetsmeldung (PC <> TNC) */ + +/* Meldungen */ +#define MSG_TXU 0x48 /* TX-Underrun (TNC -> PC) */ +#define MSG_RXO 0x50 /* RX-Overrun (TNC -> PC) */ +#define MSG_RXB 0x58 /* RX Buffer overflow (TNC -> PC) */ + +/* Bitmasken fuer Aufbau und Auswertung der Prioritaetsmeldung */ +#define MASK_TXC 0x20 /* "TX-Zaehler + 1" */ +#define MASK_RXC 0x10 /* "RX-Zaehler + 1" */ +#define MASK_DCD 0x08 /* "DCD" */ + +/* Hilfsmasken */ +#define MASK_DATA 0xC0 +#define MASK_CMD 0xF8 +#define MASK_TNCNUM 0x07 +#define MASK_PRIOCMD 0x80 +#define MASK_NORMCMD 0x40 +#define MASK_CALCNT 0x40 +#define MASK_CHAN 0x08 + +#define LED_CON 0x08 +#define LED_STA 0x10 + +#define TXWDTIME 45 /* 450ms Watchdog beim Senden */ +#define PROBE_TIMEOUT 1000 /* 10 Sekunden (= 1000 x 10ms) warten auf Zaehlpaket */ +#define TNC_TIMEOUT 500 /* 5 Sekunden Timeout fuer TNC */ +#define TNC_WATCHDOG 250 /* 2,5 Sekunden Watchdog bei Empfang */ + +/* Variablen und Strukturen */ +typedef struct tnc { + /* Kanalsteuerung */ + BOOLEAN bPresent; /* Gibt es diesen TNC im Ring ? */ + ULONG tLastHeard; /* Zeitpunkt des letzten Lebenszeichen */ + ULONG tNextArbit; /* Zeitpunkt der naechsten Kanalarbitrierung */ + ULONG tWatchdog; /* normaler Watchdog */ + ULONG tTXWatchdog; /* Watchdog waehrend TX und Calibrate */ + ULONG tPTTWatchdog; /* Watchdog fuer PTT-Kontrolle */ + UBYTE cLED; /* LEDs am TNC */ + BOOLEAN bDCD; /* DCD-Status */ + UBYTE cTXC; /* TX-Zaehler */ + UBYTE cRXC; /* RX-Zaehler */ + UBYTE cTestCount; /* Anzahl der zu sendenden Calibrates a 15 Sekunden */ + /* Statistik */ + UWORD uTXU; /* Fehlerzaehler TX-Underrun */ + UWORD uRXO; /* Fehlerzaehler RX-Overrun */ + UWORD uRXB; /* Fehlerzaehler RX Buffer Overflow */ + UWORD uReset; /* Anzahl der TNC-Resets */ + UWORD uChecksumErr; /* Anzahl Checksummenfehler */ +} TNC; + +/* Puffer fuer empfangene, rohe 6PACK-Daten */ +static UBYTE cRXRawBuffer[1024]; +static UWORD uRXRawBufferSize = 0; + +/* Puffer fuer dekodierte 6PACK-Frames */ +static UBYTE cRXBuffer[1024]; +static UWORD uRXBufferSize = 0; + +static TNC RING[(UBYTE)MAX_TNC]; + +#ifndef ATTACH +int iDescriptor = -1; +#endif /* ATTACH */ + +fd_set rset; +static struct timeval tv; + +static UWORD uLogLevel = 0; + +static UWORD uMap_TNCtoPort[MAX_TNC]; /* TNC -> Port */ +static UBYTE uMap_PorttoTNC[L2PNUM]; /* Port -> TNC */ + +static ULONG tLastInit = 0; +static UWORD uNumProbes = 0; + +UBYTE uRingStatus = RING_HALT; +UBYTE uRXStatus = RX_WAIT_SOF; +UBYTE cReceiveFrom = 0xFF; + +/* oeffentliche Funktionen */ +void Sixpack_Housekeeping(void); +void Sixpack_l1init(void); +void Sixpack_l1exit(void); +WORD Sixpack_DCD(UWORD); +void ccp6pack(void); + +/* interne Funktionen */ +void Sixpack_RX(void); +void Sixpack_TX(void); + +void startCount(void); +void toRing(UBYTE *, UWORD); + +void initTNC(UBYTE); + +/* Einfache inline-Funktionen fuer die wir (hoffentlich) */ +/* keine Debugsymbole brauchen ... */ + +/************************************************************************/ +/* Erzeugt das 6PACK LED-Kommando */ +/************************************************************************/ +UBYTE cmdLED(UBYTE uTNC) { return (CMD_LED | RING[uTNC].cLED | (uTNC & MASK_TNCNUM)); } + +/************************************************************************/ +/* Erzeugt das 6PACK Calibrate-Kommando */ +/************************************************************************/ +UBYTE cmdCAL(UBYTE uTNC) { return (CMD_CAL | (uTNC & MASK_TNCNUM)); } + +/************************************************************************/ +/* Erzeugt das 6PACK Kanalzuweisungs-Kommando */ +/************************************************************************/ +UBYTE cmdINIT(UBYTE uTNC) { return (CMD_INIT | (uTNC & MASK_TNCNUM)); } + +/************************************************************************/ +/* Erzeugt das 6PACK "TX-Zaehler + 1"-Kommando */ +/************************************************************************/ +UBYTE cmdTXC(UBYTE uTNC) { return (CMD_PRIO | MASK_TXC | (uTNC & MASK_TNCNUM)); } + +/************************************************************************/ +/* Erzeugt das 6PACK "Start of frame"-Kommando */ +/************************************************************************/ +UBYTE cmdSOF(UBYTE uTNC) { return (CMD_SOF | (uTNC & MASK_TNCNUM)); } + +/************************************************************************/ +/* Setzt die angegebene LED in der TNC-Struktur */ +/************************************************************************/ +void setLED(UBYTE uTNC, UBYTE cLED) { if (uTNC < MAX_TNC) RING[uTNC].cLED |= cLED; } + +/************************************************************************/ +/* Loescht die angegebene LED in der TNC-Struktur */ +/************************************************************************/ +void resetLED(UBYTE uTNC, UBYTE cLED) { if (uTNC < MAX_TNC) RING[uTNC].cLED &= !cLED; } + +UBYTE assignPorts(UBYTE); + +BOOLEAN DataToBuffer(UBYTE); +BOOLEAN DecodeRawBuffer(UBYTE); + +void SixpackLog(const char *, ...); + +#define LOGL1 if(uLogLevel>0)(void)SixpackLog +#define LOGL2 if(uLogLevel>1)(void)SixpackLog +#define LOGL3 if(uLogLevel>2)(void)SixpackLog +#define LOGL4 if(uLogLevel>3)(void)SixpackLog + +#endif /* __SIXPACK_H__ */ + +/* End of os/win32/6pack.h */ diff --git a/os/win32/ax25ip.c b/os/win32/ax25ip.c new file mode 100755 index 0000000..c05283f --- /dev/null +++ b/os/win32/ax25ip.c @@ -0,0 +1,3387 @@ +/************************************************************************/ +/* */ +/* ***** ***** */ +/* ***** ***** */ +/* ***** ***** */ +/* ***** ***** */ +/* *************** *************** */ +/* ***************** ***************** */ +/* *************** *************** */ +/* ***** ***** TheNetNode */ +/* ***** ***** Portable */ +/* ***** ***** Network */ +/* ***** ***** Software */ +/* */ +/* File os/linux/ax25ip.c (maintained by: DG9OBU) */ +/* */ +/* This file is part of "TheNetNode" - Software Package */ +/* */ +/* Copyright (C) 1998 - 2008 NORD>l4time = bufpoi->mbpc; + + /* Check auf Eintrag fuer die default-Route */ + if (rp.callsign[0] != 1) + putprintf(bufpoi, "%s", call_to_a(&rp.callsign[0])); + else + putstr("default", bufpoi); + + putspa(11, bufpoi); + + /* IP-Adresse ausgeben */ + show_ip_addr(ntohl(rp.ip_addr), bufpoi); + + putspa(29, bufpoi); + + /* UDP-Port ausgeben wenn UDP-Port gesetzt */ + if (rp.udp_port != 0) + { + /* Eine UDP-Route */ + putstr("UDP", bufpoi); + putspa(35, bufpoi); + putnum(ntohs(rp.udp_port), bufpoi); + } + else + /* Eine IP-Route */ + putstr("IP", bufpoi); + + /* Routen-Timeout anzeigen */ + if (rp.timeout != 0) + { + ULONG d = rp.timeout; + ULONG h, m, s; /* Stunden, Minuten, Sekunden */ + + s = d % 60L; + d /= 60L; + m = d % 60L; + d /= 60L; + h = d % 24L; + + putspa(40, bufpoi); + putprintf(bufpoi, " %02lu:%02lu:%02lu", h, m, s); /* hh:mm:ss */ + } + + if (rp.hostname[0] != 0) + { + putspa(50, bufpoi); + putprintf(bufpoi, "%s", rp.hostname); + } + + putstr("\r", bufpoi); +} + +/* Anzahl von IP- oder UDP-Routen in der Routingtabelle feststellen */ +/* (IP-Routen haben keinen UDP-Port gesetzt) */ +/* UDP = FALSE -> IP-Routen zaehlen, UDP = TRUE -> UDP-Routen zaehlen */ +/* Default-Route wird beachtet */ +unsigned int count_routes(BOOLEAN udp) +{ + register unsigned int i; + register unsigned int j = 0; + + /* Gesamte Routingtabelle durchgehen */ + for (i = 0; i < (unsigned int)route_tbl_top; ++i) + { + if ( ((udp == TRUE) && (route_tbl[i].udp_port != 0)) /* UDP-Route */ + || ((udp == FALSE) && (route_tbl[i].udp_port == 0))) /* IP-Route */ + ++j; + } + + /* Default-Route */ + if (default_route.callsign[0] != 0) + { + if ( ((udp == TRUE) && (default_route.udp_port != 0)) /* UDP-Route */ + || ((udp == FALSE) && (default_route.udp_port == 0))) /* IP-Route */ + ++j; + } + + /* Anzahl Routen melden */ + return (j); +} + +/* Timeout fuer gelernte Routen */ +void route_age(void) +{ + register unsigned int i = 0; + +#ifdef AXIPR_HTML + /* htmlstatistik-timer. */ + h_timer(); +#endif + + /* Gesamte Routingtabelle durchgehen */ + for (; i < (unsigned int)route_tbl_top; ++i) + { + /* Route mit laufendem Timer */ + if (route_tbl[i].timeout != 0) + { + /* Timer laeuft jetzt ab */ + if (--route_tbl[i].timeout == 0) + /* Route loeschen */ + route_del(route_tbl[i].callsign); + } + } +} + +/* Hostname -> IP-Adressen aufloesen */ +void route_update(struct route_table_entry *rtentry) +{ + struct hostent *hstent; + + /* Kein Hostname, dann auch keine Umwandlung moeglich */ + if (rtentry->hostname[0] == 0) + return; + + /* Hostname im IP-Adresse konvertieren */ + if ((hstent = gethostbyname((char*)&rtentry->hostname[0])) != NULL) + { + /* Bei Aenderung uebernehmen */ + if (memcmp(&rtentry->ip_addr, &hstent->h_addr_list[0][0], 4) != 0) + { + /* IP-Adresse hat sich geaendert */ + memcpy(&rtentry->ip_addr, &hstent->h_addr_list[0][0], 4); + LOGL1("IP-adress for %s changed !", rtentry->hostname); + } + } + +#ifdef AXIPR_UDP + /* Original UDP-Port setzen. */ + rtentry->udp_port = rtentry->org_udp_port; +#endif /* AXIPR_UDP */ +} + +/* Partielle Frame-Analyse fuer dyn. Eintraege */ +BOOLEAN route_canlearn(MBHEAD *fbp) +{ + char *p; /* Zeiger im Header */ + register int n; + UBYTE ctl; + + rwndmb(fbp); /* Frame von vorne */ + + for (p = rxfhdr, n = 1; n <= L2INUM + L2VNUM; ++n) + { + if (!getfid(p, fbp)) /* naechstes Call lesen */ + return (FALSE); + + p += L2IDLEN; + if (*(p - 1) & L2CEOA) + break; /* Ende des Addressfeldes */ + } + *(p - 1) &= ~L2CEOA; + *p = NUL; + ctl = getchr(fbp); /* Control-Byte extrahieren */ + ctl &= ~L2CPF; /* Poll-Flag loeschen */ + /* Nur UI, UA und SABM/SABME erzeugen einen dynamischen Eintrag */ + if ( ctl == L2CUI /* UI */ + || ctl == L2CUA /* UA */ + || ctl == L2CSABM /* SABM */ +#ifdef EAX25 + || ctl == L2CSABME /* SABME (EAX.25) */ + ) +#endif + return (TRUE); + +#ifndef AXIPR_UDP + /* Alle anderen Kontrollcodes landen hier und bewirken keinen Eintrag */ + return (FALSE); +#else + return (TRUE); +#endif +} + +/*************************************************************************/ +/* Kommandointerface fuer Operationen auf die AX25IP-Routentabelle */ +/*************************************************************************/ + +/* Eine Route anhand eines Calls loeschen, liefert TRUE wenn erfolgreich */ +BOOLEAN route_del(unsigned char *call) +{ + register int i; + register int j; + + /* Soll die Default-Route geloescht werden ? */ + if ((call == NULL) || (call[0] == NUL)) + { + /* Als unbenutzt markieren */ + default_route.callsign[0] = NUL; + + /* Pruefen, ob Sockets noch notwendig */ + ax25ip_check_down(); + return (TRUE); + } + + /* Uebergebenes Call in der Tabelle suchen */ + for (i = 0; i < route_tbl_top; ++i) + { + if (addrmatch(call, route_tbl[i].callsign)) + { + /* BINGO ! */ + /* Problem: die Tabelle hat keinen Merker, ob ein Eintrag gueltig ist, */ + /* die Eintraege haengen einfach hintereinander. Deshalb alle */ + /* Eintraege oberhalb des gefundenen Eintrages einen nach */ + /* unten kopieren und den "table-top" einen herabsetzen. */ + for (j = i; j < route_tbl_top; ++j) + route_tbl[j] = route_tbl[j + 1]; + + /* Ein Tabelleneintrag weniger */ + route_tbl_top--; + + /* Pruefen, ob Sockets noch notwendig */ + ax25ip_check_down(); + return(TRUE); + } + } + + return(FALSE); +} + +static const char inv_mode[] = "Invalid Mode\r"; +static const char inv_call[] = "Invalid Callsign\r"; +static const char inv_ip[] = "Invalid IP adress\r"; +static const char inv_par[] = "Invalid Parameter\r"; + +void +ccpaxipr(void) +{ + MBHEAD *mbp; + int port = 0; + register int i; + int tmp_fd = -1; + int new_udp = 0; + unsigned char call[L2IDLEN]; + char hostname[HNLEN + 1]; + struct hostent *host = NULL; + int uNewTimeout; +#ifdef AXIPR_UDP + char *Hostname = hostname; + int NewLogLevel = FALSE; +#endif +#ifdef AXIPR_HTML + char *timeset = set_time(); + int NewHtmlStat = FALSE; +#endif + char cBuf[BUFLEN + 1]; + unsigned int uCmd = OP_NONE; + unsigned int uMode = NO_MODE; + +#ifdef AXIPR_HTML +#define OP_HTMLSTAT 10 +#endif + + memset(hostname, 0, sizeof(hostname)); + + /* AX25IP ueberhaupt aktiv ? */ + if (ax25ip_active == FALSE) + { + putmsg("No AX25IP-interface present, nothing to configure or show !\r"); + return; + } + + /* neuen Parser verwenden ? */ + if (new_parser == TRUE) + { + + /* Sysop will aendern und noch was in der Zeile da ? */ + if (issyso() && skipsp(&clicnt, &clipoi)) + { + /* Frischer Buffer */ + memset(cBuf, 0, sizeof(cBuf)); + + /* Operation lesen (add, delete) */ + for (i = 0; i < BUFLEN; ++i) + { + if ((!clicnt) || (*clipoi == ' ')) + break; + clicnt--; + cBuf[i] = toupper(*clipoi++); + } + + /* Zum alten Parser zurueckschalten */ + if ( (strcmp(cBuf, "OLD") == 0) + || (cBuf[0] == 'O') + ) + { + new_parser = FALSE; + putmsg("Switched to old axipr-parser !!!\r"); + return; + } + + /* Hinzufuegen (add oder +) */ + if ( (strcmp(cBuf, "ADD") == 0) + || (cBuf[0] == '+') + ) + uCmd = OP_ADD; + + /* Loeschen (delete, del oder -) */ + if ( (strcmp(cBuf, "DELETE") == 0) + || (strcmp(cBuf, "DEL") == 0) + || (cBuf[0] == '-') + ) + uCmd = OP_DEL; + + /* eigenen UDP-Port aendern */ + if (strcmp(cBuf, "MYUDP") == 0) + uCmd = OP_MYUDP; + + /* Namensaufloesungsintervall einstellen */ + if (strcmp(cBuf, "LOOKUP") == 0) + uCmd = OP_HNUPD; + + /* Loglevel */ + if ( (strcmp(cBuf, "LOGLEVEL") == 0) + || (strcmp(cBuf, "LOG") == 0) + ) + uCmd = OP_LOG; + + /* Timeout fuer dynamische Routen */ + if (strcmp(cBuf, "TIMEOUT") == 0) + uCmd = OP_TIMEOUT; + +#ifdef AXIPR_HTML + /* htmlstatistik */ + if ( (strcmp(cBuf, "HTMLSTAT") == 0) + || (strcmp(cBuf, "H") == 0)) + + uCmd = OP_HTMLSTAT; +#endif + + /* Fehler bei der Auswertung ? */ + if (uCmd == OP_NONE) + { + putmsg(inv_mode); + return; + } + + /* Hier rein, wenn der Timeout fuer dynamische Routen geaendert werden soll */ + if (uCmd == OP_TIMEOUT) + { + int uNewTimeout; + + /* Noch was da in der Kommandozeile ? */ + if (!skipsp(&clicnt, &clipoi)) + { + mbp = getmbp(); + putprintf(mbp, "the actual timeout for dynamic routes is : %u\r", uDynTimeout); + /* und ab die Post ... */ + prompt(mbp); + seteom(mbp); + return; + } + + /* Timeout lesen */ + uNewTimeout = nxtlong(&clicnt, &clipoi); + + if ( (uNewTimeout < 0) + ||(uNewTimeout > (86400))) /* max. 1 Tag */ + { + putmsg("error: timeout out of range (0 - 86400) !\r"); + return; + } + + /* Wert uebernehmen */ + uDynTimeout = uNewTimeout; + + /* und ab die Post ... */ + mbp = getmbp(); + prompt(mbp); + seteom(mbp); + return; + } + + /* Hier rein, wenn das Intervall der Namensaufloesung geaendert werden soll */ + if (uCmd == OP_HNUPD) + { + UWORD uNewInterval; + + /* Noch was da in der Kommandozeile ? */ + if (!skipsp(&clicnt, &clipoi)) + { + mbp = getmbp(); + + putprintf(mbp, "Hostname-update "); + + if (uNamesUpdate != 0) + putprintf(mbp, "occurs every %u seconds.\r", uNamesUpdate / 100); + else + putprintf(mbp, "is disabled at the moment.\r"); + + /* und ab die Post ... */ + prompt(mbp); + seteom(mbp); + return; + } + + /* Timeout lesen */ + uNewInterval = nxtnum(&clicnt, &clipoi); + + if (uNewInterval > 3600) /* max. eine Stunde */ + { + putmsg("error: value out of range (0 - 3600 seconds) !\r"); + return; + } + + /* Wert uebernehmen */ + uNamesUpdate = uNewInterval * 100; + + /* und ab die Post ... */ + mbp = getmbp(); + prompt(mbp); + seteom(mbp); + return; + } + + /* Hier rein, wenn der Loglevel geaendert werden soll */ + if (uCmd == OP_LOG) + { + int new_loglevel; + + /* Noch was da in der Kommandozeile ? */ + if (!skipsp(&clicnt, &clipoi)) + { + mbp = getmbp(); + putprintf(mbp, "my actual loglevel is : %u\r", loglevel); + /* und ab die Post ... */ + prompt(mbp); + seteom(mbp); + return; + } + + /* neues Loglevel lesen */ + new_loglevel = nxtnum(&clicnt, &clipoi); + + if ( (new_loglevel < 0) + ||(new_loglevel > 4)) + { + putmsg("error: loglevel out of range (0 - 4) !!!\r"); + return; + } + + /* Wert uebernehmen */ + loglevel = new_loglevel; + + /* und ab die Post ... */ + mbp = getmbp(); + prompt(mbp); + seteom(mbp); + return; + } + +#ifdef AXIPR_HTML + if (uCmd == OP_HTMLSTAT) + { + /* Noch was da in der Kommandozeile ? */ + if (!skipsp(&clicnt, &clipoi)) + { + mbp = getmbp(); +#ifdef SPEECH + putprintf(mbp, speech_message(347),HtmlStat); +#else + putprintf(mbp, "HTML-Statistic is %d\r", HtmlStat); +#endif + /* und ab die Post ... */ + prompt(mbp); + seteom(mbp); + return; + } + + /* Timeout lesen */ + NewHtmlStat = nxtnum(&clicnt, &clipoi); + + if ( (NewHtmlStat < 0) + ||(NewHtmlStat > 1)) + { +#ifdef SPEECH + putmsg(speech_message(300)); +#else + putmsg("errors: Log level worth from 0 to 1!\r"); +#endif + return; + } + + /* Wert uebernehmen */ + HtmlStat = NewHtmlStat; + + /* und ab die Post ... */ + mbp = getmbp(); + prompt(mbp); + seteom(mbp); + return; + } +#endif /* AXIPR_HTML */ + + /* Hier nur rein, wenn wir als naechstes eine UDP-Portnummer erwarten */ + if (uCmd == OP_MYUDP) + { + /* Noch was da in der Kommandozeile ? */ + if (!skipsp(&clicnt, &clipoi)) + { + mbp = getmbp(); + putprintf(mbp, "my actual UDP-port is : %u\r", ntohs(my_udp)); + /* und ab die Post ... */ + prompt(mbp); + seteom(mbp); + return; + } + + /* neue UDP-Portnummer lesen */ + new_udp = nxtlong(&clicnt, &clipoi); + + if ( (new_udp <= 0) + ||(new_udp > 65535)) + { + putmsg("error: UDP-port number not valid (0 - 65535) !!!\r"); + return; + } + +#ifdef AXIPR_UDP + /* Neuer UDP-Port gleich MY-UDP? */ + /* Keine Aenderungen durchfuehren. */ + if (my_udp == htons((unsigned short)new_udp)) + { + /* und ab die Post ... */ + mbp = getmbp(); + prompt(mbp); + seteom(mbp); + return; + } +#endif /* AXIPR_UDP */ + +#ifndef AXIPR_UDP + /* Laufendes UDP aendern */ + if (fd_udp != -1) + { +#endif + /* Versuchen, neuen UDP-Port anzulegen */ + if ((tmp_fd = setup_udp(htons((unsigned short)new_udp))) != -1) + { +#ifndef AXIPR_UDP + /* Neuen Descriptor eintragen und alten schliessen */ + close(fd_udp); +#else + /* Nur wenn alter Socket noch lebt, */ + if (fd_udp != EOF) + /* dann schliessen wir den Socket. */ + close(fd_udp); +#endif /* AXIPR_UDP */ + + fd_udp = tmp_fd; + /* Gibt es einen Eintrag. */ + if (l1pp) + /* Check, ob neuer Filedescriptor groesser ist */ + l1pp->kisslink = max(fd_ip, fd_udp); + + /* Neuen UDP-Port merken */ + my_udp = htons((unsigned short)new_udp); + } + else + { + putmsg("error: changing the UDP-port failed !!!\r"); + return; + } +#ifndef AXIPR_UDP + } + else + { + /* neuen UDP-Port merken */ + my_udp = htons(new_udp); + } +#endif + /* und ab die Post ... */ + mbp = getmbp(); + prompt(mbp); + seteom(mbp); + return; + } + + /* Noch was da in der Kommandozeile ? */ + if (!skipsp(&clicnt, &clipoi)) + { + putmsg("syntax error: callsign missing\r"); + return; + } + + /* Frischer Buffer */ + memset(cBuf, 0, sizeof(cBuf)); + + /* Call lesen */ + for (i = 0; i < BUFLEN; ++i) + { + if ((!clicnt) || (*clipoi == ' ')) + break; + + clicnt--; + cBuf[i] = toupper(*clipoi++); + } + + /* Operation auf Default-Route ? */ + if (strcmp(cBuf, "DEFAULT") == 0) + call[0] = NUL; /* Leere Callstring als Indikator fuer Defaultroute */ + else + { + /* Call konvertieren und pruefen */ + if (a_to_call(cBuf, call) != 0) + { + putmsg(inv_call); + return; + } + } + + /* Wenn wir loeschen wollen, brauchen wir nichts mehr */ + if (uCmd != OP_DEL) + { + /* Noch was da in der Kommandozeile ? */ + if (!skipsp(&clicnt, &clipoi)) + { + putmsg("syntax error: IP-adress missing\r"); + return; + } + + /* Frische Buffer */ + memset(hostname, 0, sizeof(hostname)); + + /* Hostnamen / IP-Adresse lesen */ + for (i = 0; i < HNLEN; ++i) + { + if (!clicnt || *clipoi == ' ') + break; + + clicnt--; + hostname[i] = *clipoi++; + } + + /* eventuellen Hostnamen aufloesen */ + if ((host = gethostbyname(hostname)) == NULL) + { + mbp = getmbp(); + putprintf(mbp, "Warning: can't resolve IP for host %s ! I keep trying ...\r", hostname); + prompt(mbp); + seteom(mbp); + } + else + { + strncpy(hostname, host->h_name, sizeof(hostname)); + } + } /* if (uCmd != OP_DEL) */ + + /* Optionale UDP-Parameter lesen */ + skipsp(&clicnt, &clipoi); + + /* Frischer Buffer */ + memset(cBuf, 0, sizeof(cBuf)); + + /* Mode lesen (IP, UDP) */ + for (i = 0; i < BUFLEN; ++i) + { + if ((!clicnt) || (*clipoi == ' ')) + break; + + clicnt--; + cBuf[i] = toupper(*clipoi++); + } + + /* Mode bestimmen (UDP) */ + /* Bei der Initialisierung wurde bereits IP eingestellt */ + if ( (strcmp(cBuf, "UDP") == 0) + || (cBuf[0] == 'U') + ) + uMode = UDP_MODE; + + /* Noch was da in der Kommandozeile ? */ + if (!skipsp(&clicnt, &clipoi)) + port = DEFAULT_UDP_PORT; + else + { + /* neue UDP-Portnummer lesen */ + port = nxtlong(&clicnt, &clipoi); + + if ( (port <= 0) + ||(port > 65535)) + { + putmsg("error: UDP-port number not valid\r"); + return; + } + } + + /* Operation ausfuehren */ + switch (uCmd) + { + /* Route hinzufuegen */ + case OP_ADD : +#ifndef AXIPR_UDP + route_add((unsigned char*)&hostname, host, call, (uMode == UDP_MODE ? port : 0), (call[0] == 0 ? TRUE : FALSE) + break; +#else + if (route_add((unsigned char*)&hostname + , host + , call + , (uMode == UDP_MODE ? (int)port : 0) + , (call[0] == 0 ? TRUE : FALSE) + , 0 + , hostname +#ifdef AXIPR_HTML + , timeset + , P_USER +#endif /* AXIPR_HTML */ + )) + putmsg("Call is registerd.\r"); + + return; +#endif /* AXIPR_UDP */ + + /* Route loeschen */ + case OP_DEL : +#ifndef AXIPR_UDP + route_del(call); + break; +#else + + if (route_del(call)) + putmsg("Call is deleted!\r"); + else + putmsg("Call no deleted!\r"); + + return; +#endif /* AXIPR_UDP. */ + + + default : break; + } + + mbp = getmbp(); + /* und ab die Post ... */ + prompt(mbp); + seteom(mbp); + return; + } + + } + else + { + /* ALTE SYNTAX */ + + /* Sysop will aendern und noch was in der Zeile da ? */ + if (issyso() && skipsp(&clicnt, &clipoi)) + { + clicnt--; + + switch (toupper(*clipoi++)) + { + case 'P': /* Parser aendern */ + /* wir koennen nur in den neuen Parser umschalten */ + new_parser = TRUE; + putmsg("Switched to new axipr-parser !!!\r"); + return; + break; + + case 'R': /* Routen-Eintrag */ + /* Kommandozeile pruefen */ + if (!skipsp(&clicnt, &clipoi)) + { + putmsg(inv_par); + return; + } + + clicnt--; + + switch (*clipoi++) + { + case '-': /* Route loeschen */ + /* Call lesen */ + if (getcal(&clicnt, &clipoi, TRUE, (char *)call) != YES) + { + invcal(); + return; + } + + /* Call konvertieren */ + for (i = 0; i < L2CALEN; ++i) + call[i] = call[i] << 1; + +#ifdef AXIPR_UDP + /* und ab die Post ... */ + mbp = getmbp(); + + if (route_del(call)) + putstr("Call is delete!\r", mbp); + else + putstr("Call no delete!\r", mbp); + + prompt(mbp); + seteom(mbp); + return; +#else + /* Route loeschen */ + route_del(call); + break; +#endif /* AXIPR_UDP. */ + + case '+': /* Route hinzufuegen */ + /* Call lesen */ + if (getcal(&clicnt, &clipoi, TRUE, (char *)call) != YES) + { + invcal(); + return; + } + + /* Call linksschieben */ + for (i = 0; i < L2CALEN; ++i) + call[i] = call[i] << 1; + + /* Noch was da in der Kommandozeile ? */ + if (!skipsp(&clicnt, &clipoi)) + { + putmsg("IP-Adress/Hostname missing\r"); + return; + } + + /* Frische Buffer */ + memset(hostname, 0, sizeof(hostname)); + + /* Hostnamen / IP-Adresse lesen */ + for (i = 0; i < HNLEN; ++i) + { + if (!clicnt || *clipoi == ' ') + break; + + clicnt--; + hostname[i] = *clipoi++; + } + + /* Hostname / IP-Adresse aufloesen */ + if ((host = gethostbyname(hostname)) == NULL) + { + putmsg(inv_ip); + return; + } + + /* Mode-Parameter vorhanden ? */ + if (skipsp(&clicnt, &clipoi)) + { + --clicnt; + switch (toupper(*clipoi++)) + { + case 'I': /* IP: Port steht fest */ + break; + case 'U': /* UDP: abweichenden Port lesen wenn vorhanden */ + nextspace(&clicnt, &clipoi); + if (!skipsp(&clicnt, &clipoi)) + port = DEFAULT_UDP_PORT; + else + { + port = nxtlong(&clicnt, &clipoi); + + if ( (port <= 0) + ||(port > 65535)) + { + putmsg("error: UDP-port number not valid\r"); + return; + } + } + break; + + default: /* unbekannter Modus */ + putmsg(inv_mode); + return; + } + } + /* Route hinzufuegen */ +#ifndef AXIPR_UDP + route_add((unsigned char*)&hostname, host, call, (int) port, FALSE, 0); + break; +#else + if (route_add((unsigned char*)&hostname + , host + , call + , (int) port + , FALSE + , 0 + , hostname +#ifdef AXIPR_HTML + , timeset + , P_USER +#endif /* AXIPR_HTML */ + )) + putmsg("Call is registerd.\r"); + + return; +#endif /* AXIPR_UDP */ + + } + break; + + case 'D': /* Default Route aendern */ + + nextspace(&clicnt, &clipoi); + + /* Noch Eingaben da ? */ + if (!skipsp(&clicnt, &clipoi)) + { + putmsg(inv_mode); + return; + } + + clicnt--; + + /* Operation bestimmen */ + switch (*clipoi++) + { + case '-': /* Default Route loeschen */ +#ifdef AXIPR_UDP + /* und ab die Post ... */ + mbp = getmbp(); + + if (route_del((unsigned char *)"")) + putstr("Call is delete!\r", mbp); + else + putstr("Call no delete!\r", mbp); + + prompt(mbp); + seteom(mbp); + return; +#else + route_del((unsigned char *)""); + break; +#endif /* AXIPR_UDP. */ + + case '+': /* Default Route eingeben */ + + /* IP-Adresse / Hostname lesen */ + if (!skipsp(&clicnt, &clipoi)) + { + putmsg(inv_ip); + return; + } + + /* Frische Buffer */ + memset(hostname, 0, sizeof(hostname)); + + /* IP-Adresse / Hostname kopieren */ + for (i = 0; i < HNLEN; ++i) + { + if (!clicnt || *clipoi == ' ') + break; + clicnt--; + hostname[i] = *clipoi++; + } + + /* aufloesen */ + if ((host = gethostbyname(hostname)) == NULL) + { + putmsg(inv_ip); + return; + } + + /* Modus-Kennzeichner lesen falls vorhanden */ + if (skipsp(&clicnt, &clipoi)) + { + --clicnt; + switch (toupper(*clipoi++)) + { + case 'I': /* IP: Port steht fest */ + break; + case 'U': /* UDP: eventuell abweichenden Port lesen */ + nextspace(&clicnt, &clipoi); + + if (!skipsp(&clicnt, &clipoi)) + port = DEFAULT_UDP_PORT; + else + { + port = nxtlong(&clicnt, &clipoi); + + if ( (port <= 0) + ||(port > 65535)) + { + putmsg("error: UDP-port number not valid\r"); + return; + } + } + break; + default: /* unbekannter Modus */ + putmsg(inv_mode); + return; + } + } + /* Route eintragen */ +#ifndef AXIPR_UDP + route_add((unsigned char*)&hostname, host, NULL, (int) port, TRUE, 0); + break; +#else + if (route_add((unsigned char*)&hostname + , host + , NULL + , (int) port + , TRUE + , 0 + , hostname +#ifdef AXIPR_HTML + , timeset + , P_USER +#endif /* AXIPR_HTML */ + )) + putmsg("Call is registerd.\r"); + + return; +#endif /* AXIPR_UDP */ + + default: + putmsg(inv_mode); + return; + } + break; + + /* Eigenen UDP-Port aendern */ + case 'U': + /* neuer Port muss vorhanden sein */ + if (!skipsp(&clicnt, &clipoi)) + { + putmsg(inv_par); + return; + } + + /* Port ermitteln. */ + new_udp = nxtlong(&clicnt, &clipoi); + + if ( (new_udp <= 0) + ||(new_udp >= 65535)) + { + putmsg("UDP-Port not valid, not changed !!!\r"); + return; + } + +#ifdef AXIPR_UDP + /* Neuer UDP-Port gleich MY-UDP? */ + /* Keine Aenderungen durchfuehren. */ + if (my_udp == htons((unsigned short)new_udp)) + { + /* und ab die Post ... */ + mbp = getmbp(); + prompt(mbp); + seteom(mbp); + return; + } +#endif /* AXIPR_UDP */ + +#ifndef AXIPR_UDP + /* Laufendes UDP aendern */ + if (fd_udp != -1) + { +#endif + /* Versuchen, neuen UDP-Port anzulegen */ + if ((tmp_fd = setup_udp(htons((unsigned short)new_udp))) != -1) + { +#ifndef AXIPR_UDP + /* Neuen Descriptor eintragen und alten schliessen */ + close(fd_udp); +#else + /* Nur wenn alter Socket noch lebt, */ + if (fd_udp != EOF) + /* dann schliessen wir den Socket. */ + close(fd_udp); +#endif /* AXIPR_UDP */ + + fd_udp = tmp_fd; + /* Gibt es einen Eintrag. */ + if (l1pp) + /* Check, ob neuer Filedescriptor groesser ist */ + l1pp->kisslink = max(fd_ip, fd_udp); + + /* Neuen UDP-Port merken */ + my_udp = htons((unsigned short)new_udp); + } + else + { + putmsg("ERROR: Changing UDP-Port failed, Port not changed !!!\r"); + return; + } +#ifndef AXIPR_UDP + } + else + { + /* neuen UDP-Port merken */ + my_udp = htons(new_udp); + } +#endif + + putmsg("UDP-Port successfully changed\r"); +#ifdef AXIPR_UDP + return; +#else + break; +#endif /* AXIPR_UDP. */ + + /* Timeout fuer dynamische Routen aendern. */ + case 'T': + + /* Noch was da in der Kommandozeile ? */ + if (!skipsp(&clicnt, &clipoi)) + { + mbp = getmbp(); + putprintf(mbp, "the actual timeout for dynamic routes is : %u\r", uDynTimeout); + /* und ab die Post ... */ + prompt(mbp); + seteom(mbp); + return; + } + + /* Timeout lesen */ + uNewTimeout = nxtlong(&clicnt, &clipoi); + + if ( (uNewTimeout < 0) + ||(uNewTimeout > (86400))) /* max. 1 Tag */ + { + putmsg("error: timeout out of range (0 - 86400) !\r"); + return; + } + + /* Wert uebernehmen */ + uDynTimeout = uNewTimeout; + + /* und ab die Post ... */ + mbp = getmbp(); + prompt(mbp); + seteom(mbp); + return; + +#ifdef AXIPR_UDP + /* Loglevel aendern. */ + case 'L': + + /* Noch was da in der Kommandozeile ? */ + if (!skipsp(&clicnt, &clipoi)) + { + mbp = getmbp(); +#ifdef SPEECH + putprintf(mbp, speech_message(299),loglevel); +#else + putprintf(mbp, "My LogLevel: %d\r",loglevel); +#endif + /* und ab die Post ... */ + prompt(mbp); + seteom(mbp); + return; + } + + /* Loglevel lesen */ + NewLogLevel = nxtnum(&clicnt, &clipoi); + + if ( (NewLogLevel < 0) + ||(NewLogLevel > 4)) + { +#ifdef SPEECH + putmsg(speech_message(300)); +#else + putmsg("errors: Log level worth from 0 to 4!\r"); +#endif + return; + } + + /* Wert uebernehmen */ + loglevel = NewLogLevel; + + /* und ab die Post ... */ + mbp = getmbp(); + prompt(mbp); + seteom(mbp); + return; +#endif /* AXIPR_UDP */ + +#ifdef AXIPR_HTML + /* htmlstatistik aendern. */ + case 'H': + + /* Noch was da in der Kommandozeile ? */ + if (!skipsp(&clicnt, &clipoi)) + { + mbp = getmbp(); +#ifdef SPEECH + putprintf(mbp, speech_message(347),HtmlStat); +#else + putprintf(mbp, "HTML-Statistic is %d\r", HtmlStat); +#endif + /* und ab die Post ... */ + prompt(mbp); + seteom(mbp); + return; + } + + /* Loglevel lesen */ + NewHtmlStat = nxtnum(&clicnt, &clipoi); + + if ( (NewHtmlStat < 0) + ||(NewHtmlStat > 1)) + { +#ifdef SPEECH + putmsg(speech_message(348)); +#else + putmsg("Error: HTML-Statistic worth from 0 to 1!\r\r"); +#endif + return; + } + + /* Wert uebernehmen */ + HtmlStat = NewHtmlStat; + + /* und ab die Post ... */ + mbp = getmbp(); + prompt(mbp); + seteom(mbp); + return; +#endif + + /* Unbekannte Kommandos */ + default: + putmsg(inv_par); + return; + } + } + } + + mbp = putals("AXIP-Routes:\rCall-------IP----------------Mode--Port--Timeout--IP/Hostname----\r"); + + /* Alle Routingtabelleneintraege durchgehen und ausgeben */ + for (i = 0; i < route_tbl_top; ++i) + show_rt_entry(route_tbl[i], mbp); + + /* Default-Route ausgeben wenn vorhanden */ + if (default_route.callsign[0] == 1) + show_rt_entry(default_route, mbp); + + putprintf(mbp, "-----------------------------------------------------------------\r"); + + /* Eigenen UDP-Port ausgeben */ + putprintf(mbp, "UDP-port (%u): ", ntohs(my_udp)); + putprintf(mbp, "%s", (fd_udp != -1 ? "active" : "not active")); + + /* IP-Status ausgeben */ + putprintf(mbp, ", IP-protocol (family %u): ", IPPROTO_AX25); + putprintf(mbp, "%s", (fd_ip != -1 ? "active" : "not active")); + + /* Timeout des dynamischen Routenlerners ausgeben */ + putprintf(mbp, "\rTimeout for dynamically learned routes is %u seconds.\r", uDynTimeout); + + /* Hostname -> IP-Adresse Aktualisierungsintervall ausgeben */ + putprintf(mbp, "Hostname-to-IP-adress conversion "); + + if (uNamesUpdate != 0) + putprintf(mbp, "occurs every %u seconds.\r", uNamesUpdate / 100); + else + putprintf(mbp, "is disabled.\r"); + +#ifdef AXIPR_UDP +#ifdef SPEECH + putprintf(mbp, speech_message(299), loglevel); +#else + putprintf(mbp, "My LOGLevel is %u.\r", loglevel); +#endif /* SPEECH */ +#endif /* AXIPR_UDP */ + +#ifdef AXIPR_HTML +#ifdef SPEECH + putprintf(mbp, speech_message(347), HtmlStat); +#else + putprintf(mbp, "My HTML-Statistic is %d.\r", HtmlStat); +#endif /* SPEECH */ +#endif /* AXIPR_HTML */ + + /* und ab die Post ... */ + prompt(mbp); + seteom(mbp); +} + +/* Routeneintraege fuer parms.tnb ausgeben */ +void dump_ax25ip(MBHEAD* mbp) +{ + register int i; + + putstr(";\r; AX25IP Routes\r;\r", mbp); + + if (ax25ip_active == FALSE) + return; + + if (new_parser == TRUE) + { + putstr("; WARNING: this section is written using the new syntax of the AXIPR-command,\r", mbp); + putstr("; DO NOT USE with older TNNs compiled only for old style syntax !!!\r;\r", mbp); + + /* Falls wir noch im alten Parser sind, dann umschalten */ + putprintf(mbp, "AXIPR P\r"); + /* eigenen UDP-Port ausgeben */ + putprintf(mbp, "AXIPR MYUDP %u\r", ntohs(my_udp)); + /* Timeout fuer dynamische Routen ausgeben */ + putprintf(mbp, "AXIPR TIMEOUT %u\r", uDynTimeout); + /* Intervall fuer Hostnamen-Update ausgeben */ + putprintf(mbp, "AXIPR LOOKUP %u\r", uNamesUpdate); + } + +#ifdef AXIPR_UDP + /* eigenen UDP-Port ausgeben */ + putprintf(mbp, "AXIPR U %u\r", ntohs(my_udp)); + /* Timeout fuer dynamische Routen ausgeben */ + putprintf(mbp, "AXIPR T %u\r", uDynTimeout); + + putprintf(mbp, "AXIPR L %d\r",loglevel); + +#ifdef AXIPR_HTML + putprintf(mbp, "AXIPR H %d\r",HtmlStat); +#endif /* AXIPR_HTML */ +#endif /* AXIPR_UDP */ + + /* alle Routingtabelleneintraege durchgehen und ausgeben */ + for (i = 0; i < route_tbl_top; ++i) + { + /* Dynamisch gelernte Routen werden inaktiv zur Information geschrieben ! */ + if (route_tbl[i].timeout != 0) + continue; + +/* putprintf(mbp, "; ");*/ + + /* Eintrag einer Route erzeugen */ + putprintf(mbp, (new_parser == FALSE ? "AXIPR R + %s " : "AXIPR ADD %s ") + , call_to_a(&route_tbl[i].callsign[0])); + + /* Den Hostnamen ausgeben */ + putprintf(mbp, "%s", route_tbl[i].hostname); + + /* Mode und ggf. Port ausgeben wenn UDP */ + if (route_tbl[i].udp_port != 0) + { + putstr((new_parser == FALSE ? " U " : " UDP "), mbp); + putnum(ntohs(route_tbl[i].udp_port), mbp); + } + + putstr("\r", mbp); + } + + /* Die Defaultroute ausgeben wenn gesetzt */ + if (default_route.callsign[0] == 1) + { + /* Kommandokopf schreiben */ + putstr((new_parser == FALSE ? "AXIPR D + " : "AXIPR ADD DEFAULT "), mbp); + + /* Den Hostnamen ausgeben */ + putprintf(mbp, "%s", default_route.hostname); + + /* Mode und ggf. Port ausgeben wenn UDP */ + if (default_route.udp_port != 0) + { + putstr((new_parser == FALSE ? " U " : " UDP "), mbp); + putnum(ntohs(default_route.udp_port), mbp); + } + putstr("\r", mbp); + } +} + +/************************************************************************/ +/* AX25IP Initialisierung */ +/************************************************************************/ +BOOLEAN ax25ip_l1init(int l2port) +{ + if (ax25ip_active == TRUE) + return(TRUE); + + /* Socketstrukturen initialisieren */ + memset((char*)&to, 0, sizeof(to)); + memset((char*)&from, 0, sizeof(from)); + + ax25ip_port = l2port; + l1pp = &l1port[l1ptab[l2port]]; + l2flp = (LHEAD *) &txl2fl[l2port]; + + /* Routingtabelle initialisieren */ + route_init(); + + /* Konfiguration einlesen */ + if (config_read() == FALSE) + return(FALSE); + + /* Notwendige Sockets anlegen */ +#ifndef AXIPR_UDP + ax25ip_check_up(); +#endif + + /* Wir sind fertig */ + ax25ip_active = TRUE; + return(TRUE); +} + +/* Einen Filedescriptor fuer IP anlegen */ +int setup_ip(void) +{ + /* Temporaerer Filedescriptor */ + int tmp_fd = -1; + + /* Adressstruktur loeschen */ + memset((char*)&ipbind, 0, sizeof(ipbind)); + + /* Rohen IP-Socket anlegen */ + if ((tmp_fd = socket(AF_INET, SOCK_RAW, IPPROTO_AX25)) < 0) + { + xprintf("AX25IP : cannot create ip raw-socket: %s\n", strerror(errno)); + LOGL2("AX25IP : cannot create ip raw-socket: %s\n", strerror(errno)); + return(-1); + } + + /* Nonblocking-IO */ + if (fcntl(tmp_fd, F_SETFL, FNDELAY) < 0) + { + xprintf("AX25IP : cannot set non-blocking I/O on ip raw-socket\n"); + LOGL2("AX25IP : cannot set non-blocking I/O on ip raw-socket\n"); + close(tmp_fd); + return(-1); + } + + /* Adressstruktur mit notwendigen Werten fuellen */ + ipbind.sin_family = AF_INET; + ipbind.sin_addr.s_addr = htonl(INADDR_ANY); + + return (tmp_fd); +} + +/* Einen Filedescriptor fuer UDP anlegen */ +/* Es muss der UDP-Port angegeben werden, auf dem wir hoeren wollen */ +/* (Achtung: UDP-Port in Network-Byteorder) */ +int setup_udp(unsigned short udp_port) +{ + /* Temporaerer Filedescriptor */ + int tmp_fd = -1; + + /* Port-Check */ + if (udp_port == 0) + return(-1); + + /* Adressstruktur loeschen */ + memset((char*)&udpbind, 0, sizeof(udpbind)); + + /* UDP-Socket anlegen */ + if ((tmp_fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) + { + xprintf("AX25IP : cannot create socket: %s\n", strerror(errno)); + LOGL2("AX25IP : cannot create socket: %s\n", strerror(errno)); + return(-1); + } + + /* Nonblocking-IO */ + if (fcntl(tmp_fd, F_SETFL, FNDELAY) < 0) + { + xprintf("AX25IP : cannot set non-blocking I/O on udp socket\n"); + LOGL2("AX25IP : cannot set non-blocking I/O on udp socket\n"); + close(tmp_fd); + return(-1); + } + + /* Socket-Optionen fuer UDP einstellen */ + /* SO_KEEPALIVE einschalten */ + if (sockopt_keepalive == TRUE) + { + int iFlag = 1; + + if (setsockopt(tmp_fd, SOL_SOCKET, SO_KEEPALIVE, (const char *)&iFlag, sizeof(int)) < 0) + { + xprintf("AX25IP : cannot set SO_KEEPALIVE for udp : %s\n", strerror(errno)); + LOGL2("AX25IP : cannot set SO_KEEPALIVE for udp : %s\n", strerror(errno)); + } + } + + /* Socket auf max. Durchsatz */ + if (sockopt_throughput == TRUE) + { + int iFlag = IPTOS_THROUGHPUT; + + if (setsockopt(tmp_fd, IPPROTO_IP, IP_TOS, (const char *)&iFlag, sizeof(IPTOS_THROUGHPUT)) < 0) + { + xprintf("AX25IP : cannot set IPTOS_THROUGHPUT for udp : %s\n", strerror(errno)); + LOGL2("AX25IP : cannot set IPTOS_THROUGHPUT for udp : %s\n", strerror(errno)); + } + } + + /* Adressstruktur fuellen */ + udpbind.sin_addr.s_addr = htonl(INADDR_ANY); + udpbind.sin_port = udp_port; + udpbind.sin_family = AF_INET; + + /* Adresse und Port binden */ + if (bind(tmp_fd, (struct sockaddr *)&udpbind, sizeof(udpbind)) < 0) + { + xprintf("AX25IP : cannot bind udp socket: %s\n", strerror(errno)); + LOGL2("AX25IP : cannot bind udp socket: %s\n", strerror(errno)); + close(tmp_fd); + return(-1); + } + + return(tmp_fd); +} + +/* Pruefen, ob schon Sockets angelegt sind, wenn nicht, dann notwendige */ +/* Sockets oeffnen */ +void ax25ip_check_up(void) +{ + /* IP notwendig ? */ + if ((count_routes(FALSE) != 0) && (fd_ip == -1)) + fd_ip = setup_ip(); /* IP starten */ + + /* UDP notwendig ? */ + if ((count_routes(TRUE) != 0) && (fd_udp == -1)) + fd_udp = setup_udp(my_udp); /* UDP starten */ + +#ifdef AXIPR_UDP + if (l1pp != NULL) +#endif + /* Markieren, ob IP oder UDP laufen */ + l1pp->kisslink = max(fd_ip, fd_udp); +} + +/* Pruefen, ob Sockets angelegt sind und diese noch benoetigt werden. */ +/* Falls nicht, Sockets schliessen */ +void ax25ip_check_down(void) +{ + /* IP notwendig ? */ + if ((count_routes(FALSE) == 0) && (fd_ip != -1)) + { + close(fd_ip); + fd_ip = -1; + } + + /* UDP notwendig ? */ + if ((count_routes(TRUE) == 0) && (fd_udp != -1)) + { + close(fd_udp); + fd_udp = -1; + } + + /* Gibt es einen Eintrag. */ + if (l1pp) + /* Markieren, ob IP oder UDP laufen */ + l1pp->kisslink = max(fd_ip, fd_udp); +} + +/*************************************************************************/ +/* AX25IP Pakete empfangen */ +/*************************************************************************/ +void ax25ip_recv(void) +{ + struct iphdr *ipptr; + struct timeval tv; + int l = 0; + int iDescriptorsReady = 0; + register int i = 0; + register int max_fd = -1; + socklen_t fromlen = sizeof(from); + int hdr_len = 0; + UBYTE buf[MAX_FRAME+1]; + UBYTE *bufptr; + MBHEAD *rxfhd; + BOOLEAN UDP_Frame = FALSE; + fd_set rmask; + +#ifdef AXIPR_UDP + if (LookAX25IP) + return; +#endif /* AX25IP_UDP */ + + FD_ZERO(&rmask); + + /* IP-Filedescriptor eintragen */ + if (fd_ip != -1) + { + FD_SET((unsigned int)fd_ip, &rmask); + if (fd_ip > max_fd - 1) + max_fd = fd_ip + 1; + } + + /* UDP-Filedescriptor eintragen */ + if (fd_udp != -1) + { + FD_SET((unsigned int)fd_udp, &rmask); + if (fd_udp > max_fd - 1) + max_fd = fd_udp + 1; + } + + /* ist was aktiv ? */ + if (max_fd == -1) + return; + + tv.tv_usec = 0; + tv.tv_sec = 0; + + iDescriptorsReady = select(max_fd, &rmask, NULL, NULL, &tv); + + /* nix da */ + if (iDescriptorsReady == 0) + return; + + /* Fehler */ + if (iDescriptorsReady == -1) + { + LOGL2("select()-Error %i: %s", errno, strerror(errno)); + return; + } + + /* RX fuer IP */ + if ((fd_ip != -1) && (FD_ISSET(fd_ip, &rmask))) + { + l = recvfrom(fd_ip, (UBYTE *)(bufptr = buf), MAX_FRAME, 0, (struct sockaddr *) &from, &fromlen); + + if (l > 0) + { + if (l > (signed)sizeof(struct iphdr*)) + { + ipptr = (struct iphdr*)buf; + hdr_len = 20; + + if (!ok_crc(buf + hdr_len, l - hdr_len)) + { /* stimmt die CRC ? */ + LOGL2("IP-RX: CRC-Error, frame dropped"); + return; /* Fehler */ + } + } + else + { + LOGL2("IP-RX: frame too short, frame dropped"); + return; /* Fehler */ + } + } + i = hdr_len; + } + + /* RX fuer UDP, aber nur, wenn nicht schon TCP was empfangen hat */ + if ((fd_udp != -1) && (FD_ISSET(fd_udp, &rmask) && (l == 0))) + { + l = recvfrom(fd_udp, (UBYTE *)(bufptr = buf), MAX_FRAME, 0, (struct sockaddr *) &from, &fromlen); + + if (l > 0) + { + if (!ok_crc(buf, l)) + { /* stimmt die CRC ? */ + LOGL2("UDP-RX: CRC-Error, frame dropped"); + return; /* Fehler */ + } + } + UDP_Frame = TRUE; + } + + /* Ab hier gemeinsame Behandlung */ + /* Erst mal gucken, ob was gekommen ist */ + if (l == 0) + return; /* nix da */ + + l -= 2; /* CRC abschneiden */ + + if (l < 15) + { + LOGL2("AX25IP: RX frame dropped, length wrong, frame is too short !"); + return; + } + + /* Hier angekommen haben wir (hoffentlich) ein gueltiges Frame. Die */ + /* weitere Behandlung ist fuer IP und UDP nahezu identisch. */ + + /* Frame in Buffer umkopieren und Empfangsport eintragen */ + rxfhd = cpyflatmb((char*)&buf[i], l - i); + rxfhd->l2port = ax25ip_port; + + /* Frame in die L2-RX-Kette einhaengen */ + relink((LEHEAD *)rxfhd, (LEHEAD *)rxfl.tail); + + /* Jetzt noch das Frame an den Routenlerner zur Analyse */ + if (route_canlearn(rxfhd)) + { + /* Frame kann zum Lernen benutzt werden */ + /* Absenderrufzeichen ermitteln und konvertieren */ + /* Wir brauchen hier nicht den eigentlichen Absender, */ + /* sondern den, der als letztes gedigipeated hat. */ + struct in_addr ipaddr; +#ifndef AXIPR_UDP + struct route_table_entry* rtptr; +#endif /* AXIPR_UDP */ + unsigned char srccall[L2IDLEN + 1]; + + cpyid((char *)srccall, dheardcall(rxfhdr)); + + /* Call linksschieben */ + for (i = 0; i < L2CALEN; ++i) + srccall[i] = srccall[i] << 1; + + /* Gibt es schon eine IP fuer dieses Call, dann kann sich die IP */ + /* geaendert haben. Falls ja und es sich um einen dynamischen Eintrag */ + /* handelt, dann loeschen und neuen Eintrag anlegen. */ +#ifndef AXIPR_UDP + if ((rtptr = call_to_ip(srccall)) != NULL) + { + if (( (rtptr->ip_addr != from.sin_addr.s_addr) + || (rtptr->udp_port != (UDP_Frame == TRUE ? ntohs(from.sin_port) : 0))) + && (rtptr->timeout != 0)) + route_del(srccall); /* Route loeschen */ + else + { + if (rtptr != &default_route) + return; /* Adresse unveraendert */ + } + } +#endif /* AXIPR_UDP */ + + ipaddr.s_addr = from.sin_addr.s_addr; + +#ifndef AXIPR_UDP + /* Route eintragen */ + route_add((unsigned char*)inet_ntoa(ipaddr), NULL, srccall, + (UDP_Frame == TRUE ? ntohs(from.sin_port) : 0), FALSE, uDynTimeout); +#else + route_analyse(ipaddr, srccall, + (UDP_Frame == TRUE ? ntohs(from.sin_port) : 0)); + } +#endif /* AXIPR_UDP */ +} + +/*************************************************************************/ +/* AX25IP Pakete senden */ +/*************************************************************************/ +void ax25ip_send(void) +{ + unsigned char buf[MAX_FRAME]; + int len = 0; + int fd = -1; + MBHEAD *txfhdl; + + struct route_table_entry *rt; + struct hostent *hstent; + + unsigned char *call; + + if (kick[ax25ip_port]) /* haben wir was zu senden ? */ + { + /* Sicherheitsabfrage, da kick[] auch manipuliert werden kann */ + if (l2flp->head == l2flp) + { + kick[ax25ip_port] = FALSE; + return; + } + + ulink((LEHEAD *)(txfhdl = (MBHEAD *) l2flp->head));/*Zeiger holen*/ + + /* Daten aus den internen Puffern in einen linearen Puffer uebertragen */ + len = cpymbflat((char*)&buf[0], txfhdl); + + relink((LEHEAD *)txfhdl, /* als gesendet betrachten und in */ + (LEHEAD *)stfl.tail); /* die gesendet Liste umhaengen */ + + kick[ax25ip_port] = ((LHEAD *)l2flp->head != l2flp); + + /* Naechstes Call der Digipeaterkette holen */ + call = next_addr(buf); + + /* IP-Adresse des naechsten Digipeaters ermitteln */ + rt = call_to_ip(call); + + if (rt == NULL) /* wir kennen das Ziel nicht */ + { +#ifdef AXIPR_UDP + if ((rt = search_route(call)) == NULL) + { +#endif + LOGL2("no route for %s, can't send", call_to_a(call)); + return; + } +#ifdef AXIPR_UDP + } +#endif + + /* Ein Host, zu dem bisher keine IP-Adresse aufgeloest werden konnte */ + if (rt->ip_addr == 0L) + { + /* Versuchen, jetzt eine IP-Adresse zu bestimmen */ + if ((hstent = gethostbyname((char*)rt->hostname)) != NULL) + memcpy((unsigned char*)&rt->hostname, (unsigned char *)&hstent->h_addr_list[0][0], 4); + } + + /* Checksumme anhaengen */ + add_ax25crc(buf, len); + /* CRC-Bytes sind dazugekommen */ + len += 2; + /* Ziel-IP-Adresse in Sendestruktur eintragen */ + memcpy((char *) &to.sin_addr, (char *)&rt->ip_addr, 4); + /* Ziel-Port nur bei UDP eintragen */ + if (rt->udp_port != 0) + memcpy((char *) &to.sin_port, (char *)&rt->udp_port, 2); + else + to.sin_port = 0; /* bei IP kein Port */ + + to.sin_family = AF_INET; + + /* Unterscheidung IP oder UDP */ + if (to.sin_port == 0) + fd = fd_ip; + else + fd = fd_udp; + + if (fd == -1) + { + LOGL2("error: no descriptor, can't send !!!"); + return; + } + + if (sendto(fd, (char *)buf, len, 0, (struct sockaddr *)&to, sizeof(to)) < 0) + LOGL2("error: sendto failed, fd=%u error=%s", fd, strerror(errno)); + } +} + +/*************************************************************************/ +/* AX25IP Deinitialisierung, Port und Sockets schliessen */ +/*************************************************************************/ +void ax25ip_l1exit(void) +{ + /* Nur wenn aktiv */ + if (ax25ip_active == FALSE) + return; + + /* IP-Socket schliessen wenn offen */ + if (fd_ip != -1) + { + close(fd_ip); + fd_ip = -1; + } + + /* UDP-Socket schliessen wenn offen */ + if (fd_udp != -1) + { + close(fd_udp); + fd_udp = -1; + } + + /* AX25IP nicht mehr aktiv */ + ax25ip_active = FALSE; + + /* Gibt es einen Eintrag. */ + if (l1pp) + l1pp->kisslink = -1; +} + +void ax25ip_l1ctl(int req, int port) +{ + /* nur eigene Ports bearbeiten */ + if ((ax25ip_active == FALSE) || (kissmode(port) != KISS_AXIP)) + return; + + switch (req) + { + /* Testpattern auf dem Port senden (wird unterdrueckt) */ + case L1CTST : testflag[port] = FALSE; + kick[port] = FALSE; + break; + + default : break; + } +} + +void ax25ip_hwstr(int port, MBHEAD *mbp) +{ +#ifdef AXIPR_UDP + putstr(" ", mbp); + /* My UDP-Port ausgeben. */ + putprintf(mbp,"%u", ntohs(my_udp)); +#endif +} + +BOOLEAN ax25ip_dcd(int port) +{ + return (FALSE); +} + + +/* routing.c Routing table manipulation routines + * + * Copyright 1991, Michael Westerhof, Sun Microsystems, Inc. + * This software may be freely used, distributed, or modified, providing + * this header is not removed. + * + + * Modified for use in TNN by DG1KWA & DG9OBU + + */ + + + +/* Initialize the routing table */ +void route_init(void) +{ + /* Defaultroute initialisieren */ + memset(&default_route, 0 , sizeof(struct route_table_entry)); + + /* Routen initialisieren */ + memset(&route_tbl, 0, (TABLE_SIZE * sizeof(struct route_table_entry))); +} + +/* Add a new route entry */ +#ifndef AXIPR_UDP +static void route_add(unsigned char* hostname, struct hostent *hstent, unsigned char *call, int udpport, + int default_rt, int timeout) +#else +static BOOLEAN route_add(unsigned char *host, struct hostent *hstent, unsigned char *call, int udpport, + int default_rt, int timeout, char *hostname +#ifdef AXIPR_HTML + , char *timeset, UWORD protokoll +#endif /* AXIPR_HTML */ + ) +#endif /* AXIPR_UDP */ +{ + register unsigned int i = 0; + struct route_table_entry *rtptr; + struct hostent *hst; + + /* Eintrag soll Defaultroute sein */ + if (default_rt) + { + for (i = 1; i < 7 ;++i) + default_route.callsign[i] = 0; + + if (hstent != NULL) + memcpy(&default_route.ip_addr, (unsigned char *)&hstent->h_addr_list[0][0], 4); + else + memset(&default_route.ip_addr, 0, 4); + + default_route.udp_port = htons((unsigned short)udpport); + default_route.timeout = 0; /* Defaultroute ohne Timeout */ + + if (hostname != NULL) + strncpy((char*)&default_route.hostname, (char*)hostname, HNLEN); + + default_route.callsign[0] = 1; /* mark valid */ + + /* Socket ggf. installieren */ + ax25ip_check_up(); + +#ifndef AXIPR_UDP + return; +#else + return(TRUE); +#endif /* AXIPR_UDP */ + } + + /* Normale Routen nur wenn Call vorhanden */ + if (call == NULL) +#ifndef AXIPR_UDP + return; +#else + return(FALSE); +#endif /* AXIPR_UDP */ + + /* Check auf doppelte Eintraege, Eintrag wird nur angenommen wenn */ + /* es noch noch keinen Eintrag unter diesem Call gibt. */ + if (((rtptr = call_to_ip(call)) != NULL) && (rtptr->ip_addr != default_route.ip_addr)) + { +#ifndef AXIPR_UDP + putmsg("A route to this callsign is already set up, delete it first.\r"); + return; +#else +#ifndef AXIPR_HTML + UpdateRoute(call, udpport, timeout, hostname); +#else + UpdateRoute(call, udpport, timeout, hostname, timeset, protokoll); +#endif /* AXIPR_HTML */ + return(FALSE); +#endif /* AXIPR_UDP */ + } + + /* Passt noch ein Eintrag in die Tabelle ? */ + if (route_tbl_top >= TABLE_SIZE) + { + xprintf("Routing table is full; entry ignored.\n"); + LOGL2("Routing table is full; entry ignored"); + putmsg("Routing table is full, entry ignored\r"); +#ifndef AXIPR_UDP + return; +#else + return(FALSE); +#endif /* AXIPR_UDP */ + } + + /* Call eintragen */ + for (i = 0; i < 6; ++i) + route_tbl[route_tbl_top].callsign[i] = call[i] & 0xfe; + + /* SSID eintragen */ + route_tbl[route_tbl_top].callsign[6] = (call[6] & 0x1e) | 0x60; + + if (hstent != NULL && hstent->h_length != 0) + { + memcpy((unsigned char*)&route_tbl[route_tbl_top].ip_addr, (unsigned char *)&hstent->h_addr_list[0][0], 4); + } + else + memset(&route_tbl[route_tbl_top].ip_addr, 0, sizeof(route_tbl[route_tbl_top].ip_addr)); + + route_tbl[route_tbl_top].udp_port = htons((unsigned short)udpport); + route_tbl[route_tbl_top].timeout = timeout; + + if (hostname != NULL) + { + memcpy(&route_tbl[route_tbl_top].hostname, hostname, strlen((char*)hostname)); + /* Keine Adressaufloesung bisher, dann probieren wir es noch einmal */ + if (hstent == NULL) + { + if ((hst = gethostbyname((char*)hostname)) != NULL) + memcpy((unsigned char*)&route_tbl[route_tbl_top].ip_addr, &hst->h_addr_list[0][0], 4); + } + } + +#ifdef AXIPR_UDP + /* Original UDP-Port eintragen. */ + route_tbl[route_tbl_top].org_udp_port = htons((UWORD)udpport); +#endif + +#ifdef AXIPR_HTML + /* Hostname eintragen. */ + (void)memcpy(route_tbl[route_tbl_top].timeset, timeset, 17); + /* Protokoll eintragen. */ + route_tbl[route_tbl_top].protokoll = P_USER; + /* Route als offline markieren. */ + route_tbl[route_tbl_top].online = FALSE; +#endif + + /* Ein Routeneintrag mehr */ + route_tbl_top++; + + /* Socket ggf. installieren */ + ax25ip_check_up(); + +#ifndef AXIPR_UDP + return; +#else + return(TRUE); +#endif /* AXIPR_UDP */ +} + +/* + * Return an IP address and port number given a callsign. + * We return a pointer to the route structure for this callsign + * or a NULL-pointer if no route was found. + */ + +struct route_table_entry* call_to_ip(unsigned char *call) +{ + register int i; + unsigned char mycall[7]; + + /* Leere Calls koennen nicht verarbeitet werden */ + if (call == NULL) + return (NULL); + + /* Call-Bytes kopieren, letztes Bit abschneiden (entspricht >> 1 & 7F) */ + for (i = 0; i < 6; ++i) + mycall[i] = call[i] & 0xfe; + + /* SSID kopieren */ + mycall[6] = (call[6] & 0x1e) | 0x60; + + /* Routingtabelle durchsuchen */ + for (i = 0; i < route_tbl_top; ++i) + { + if (addrmatch(mycall , route_tbl[i].callsign)) + { + /* Aktivitaet auf diesem Eintrag, dann Timeout erneuern */ + if (route_tbl[i].timeout) + route_tbl[i].timeout = uDynTimeout; + + return (&route_tbl[i]); /* Eintrag gefunden */ + } + } + + /* Kein Routingeintrag vorhanden, Default-Route melden wenn vorhanden */ + if (default_route.callsign[0]) + return (&default_route); + + /* Kein Routingeintrag gefunden, keine Defaultroute */ + return (NULL); +} + +/* + * tack on the CRC for the frame. Note we assume the buffer is long + * enough to have the two bytes tacked on. + */ +void add_ax25crc(unsigned char *buf, int l) +{ + unsigned short int u = compute_crc(buf, l); + + buf[l] = u & 0xff; /* lsb first */ + buf[l + 1] = (u >> 8) & 0xff; /* msb next */ +} + + +/* + ********************************************************************** + * The following code was taken from Appendix B of RFC 1171 + * (Point-to-Point Protocol) + * + * The RFC credits the following sources for this implementation: + * + * Perez, "Byte-wise CRC Calculations", IEEE Micro, June, 1983. + * + * Morse, G., "Calculating CRC's by Bits and Bytes", Byte, + * September 1986. + * + * LeVan, J., "A Fast CRC", Byte, November 1987. + * + * + * The HDLC polynomial: x**0 + x**5 + x**12 + x**16 + */ + +/* + * u16 represents an unsigned 16-bit number. Adjust the typedef for + * your hardware. + */ +/*typedef unsigned short u16;*/ + + +/* + * FCS lookup table as calculated by the table generator in section 2. + */ +static UWORD fcstab[256] = { + 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf, + 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7, + 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e, + 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876, + 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd, + 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5, + 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c, + 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974, + 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb, + 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3, + 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a, + 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72, + 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9, + 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1, + 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738, + 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70, + 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7, + 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff, + 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036, + 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e, + 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5, + 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd, + 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134, + 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c, + 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3, + 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb, + 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232, + 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a, + 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1, + 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9, + 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330, + 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78 +}; + +#define PPPINITFCS 0xffff /* Initial FCS value */ +#define PPPGOODFCS 0xf0b8 /* Good final FCS value */ + +/* + * Calculate a new fcs given the current fcs and the new data. + */ +UWORD pppfcs(register UWORD fcs, register unsigned char *cp, register int len) +{ + while (len--) + fcs = (fcs >> 8) ^ fcstab[(fcs ^ *cp++) & 0xff]; + + return(fcs); +} + +/* + * End code from Appendix B of RFC 1171 + ********************************************************************** + */ + +/* + * The following routines are simply convenience routines... + * I'll merge them into the mainline code when suitably debugged + */ + +/* Return the computed CRC */ +UWORD compute_crc(unsigned char *buf, int l) +{ + UWORD fcs = (pppfcs(PPPINITFCS, buf, l) ^ 0xFFFF); + + return (fcs); +} + +/* Return true if the CRC is correct */ +BOOLEAN ok_crc(unsigned char *buf, int l) +{ + UWORD fcs = pppfcs(PPPINITFCS, buf, l); + + return (fcs == PPPGOODFCS); +} + +/* return true if the addresses supplied match */ +int addrmatch(unsigned char *a, unsigned char *b) +{ + if ((*a == '\0') || (*b == '\0')) return(0); + + if ((*a++ ^ *b++) & 0xfe) return(0); /* "K" */ + if ((*a++ ^ *b++) & 0xfe) return(0); /* "A" */ + if ((*a++ ^ *b++) & 0xfe) return(0); /* "9" */ + if ((*a++ ^ *b++) & 0xfe) return(0); /* "W" */ + if ((*a++ ^ *b++) & 0xfe) return(0); /* "S" */ + if ((*a++ ^ *b++) & 0xfe) return(0); /* "B" */ + if ((*a++ ^ *b++) & 0x1e) return(0); /* ssid */ + return(1); +} + +/* return pointer to the next station to get this packet */ +unsigned char *next_addr(unsigned char *f) +{ + unsigned char *a; + + /* If no digis, return the destination address */ + if (NO_DIGIS(f)) return(f); + + /* check each digi field. The first one that hasn't seen it is the one */ + a = f + 7; + do { + a += 7; + if (NOTREPEATED(a)) return(a); + } while (NOT_LAST(a)); + +/* all the digis have seen it. return the destination address */ + return(f); +} + +/* Open and read the config file */ +int config_read(void) +{ + FILE *cf; + char buf[256], cbuf[256]; + int errflag = 0; + int e = 0; + int lineno = 0; + char cfgfile[256]; + + strcpy(cfgfile, confpath); + strcat(cfgfile, CONFIG_FILE); + + if ((cf = fopen(cfgfile, "r")) == NULL) + { +#ifdef INIPATH + strcpy(cfgfile, INIPATH); + strcat(cfgfile, CONFIG_FILE); + + if ((cf = fopen(cfgfile, "r")) == NULL) + { +#endif +#ifdef AXIPR_UDP + /* AX25IP.CFG ist nicht mehr noetig, */ + /* kann aber weiterhin benutzt werden. */ + return(TRUE); +#endif + xprintf("AX25IP: Config file %s not found or could not be opened\n", CONFIG_FILE); + return(FALSE); +#ifdef INIPATH + } +#endif + } + + while (fgets(buf, 255, cf) != NULL) + { + (void)strcpy(cbuf, buf); + ++lineno; + + if ((e = parse_line(buf)) < 0) + { + xprintf("Config error at line %d: ", lineno); + + switch (e) + { + case -1 : xprintf("Missing argument\n"); break; + case -2 : xprintf("Bad callsign format\n"); break; + case -3 : xprintf("Bad option - on/off\n"); break; + case -4 : xprintf("Bad option - tnc/digi\n"); break; + case -5 : xprintf("Host not known\n"); break; + case -6 : xprintf("Unknown command\n"); break; + case -7 : xprintf("Text string too long\n"); break; + case -8 : xprintf("Bad option - every/after\n"); break; + case -9 : xprintf("Bad option - ip/udp\n"); break; + + default: xprintf("Unknown error\n"); break; + } + xprintf("%s", cbuf); + ++errflag; + } + } + + if (errflag) + exit(1); + + if (mode == NO_MODE) + { + xprintf("Must specify ip and/or udp sockets\n"); + return(FALSE); + } + + fclose(cf); + + return(TRUE); +} + +/* Process each line from the config file. The return value is encoded. */ +int parse_line(char *buf) +{ + char *p; + char *q; + char hostname[HNLEN]; + unsigned char tcall[7]; + struct hostent hstent; + struct hostent *he; + int i = 0; + int uport = 0; + int dfalt = 0; +#ifdef AXIPR_HTML + char *timeset = set_time(); +#endif + + p = strtok(buf, " \t\n\r"); + + memset(&hstent, 0, sizeof(hstent)); + + /* Leere Zeilen */ + if (p == NULL) + return(0); + + /* Kommentarzeilen nicht auswerten */ + if (*p == '#') + return(0); + + if (strcmp(p, "socket") == 0) + { + q = strtok(NULL, " \t\n\r"); + + if (q == NULL) + return(-1); + + if (strcmp(q, "ip") == 0) + mode = IP_MODE; + else if (strcmp(q, "udp") == 0) + { + mode = UDP_MODE; + my_udp = htons(DEFAULT_UDP_PORT); + + /* Bei UDP optionale Portnummer lesen */ + q = strtok(NULL, " \t\n\r"); + + /* Nummer war vorhanden, auswerten */ + if (q != NULL) + { + i = atoi(q); + /* Nummer ist gueltig, uebernehmen */ + if (i > 0) + my_udp = htons((unsigned short)i); + } + } + else + return(-9); + + return(0); + } + else if (strcmp(p, "socketoption") == 0) + { + q = strtok(NULL, " \t\n\r"); + + /* Pruefung auf leere Zeile */ + if (q == NULL) + return(-1); + + if (strcmp(q, "SO_KEEPALIVE") == 0) + { + sockopt_keepalive = TRUE; + } + else if (strcmp(q, "IPTOS_THROUGHPUT") == 0) + { + sockopt_throughput = TRUE; + } + else return(-9); + + return(0); + + } else if (strcmp(p, "loglevel") == 0) { + q = strtok(NULL, " \t\n\r"); + if (q == NULL) return(-1); + loglevel = atoi(q); + return(0); + + } else if (strcmp(p, "route") == 0) { + uport = 0; + dfalt = 0; + + q = strtok(NULL, " \t\n\r"); + + /* Pruefung auf leere Zeile */ + if (q == NULL) + return(-1); + + /* Pruefung auf default-Route */ + if (strcmp(q, "default") == 0) + dfalt = 1; + else + { + /* Ziel der Route pruefen */ + if (a_to_call(q, tcall) != 0) + return(-2); + } + + /* Hostnamen holen, dies kann auch eine IP-Adresse sein */ + q = strtok(NULL, " \t\n\r"); + if (q == NULL) + return(-1); + + he = gethostbyname(q); + + /* Keine gueltige IP-Adresse ? */ + if (he == NULL) + { + /* Da route_add() eine hostent-Struktur braucht, bauen wir ihm eine. */ + /* Den Hostname sichern und den Zeiger auf den Puffer im hostent eintragen. */ + strncpy(hostname, q, HNLEN); + + he = &hstent; + he->h_name = hostname; + } + + q = strtok(NULL, " \t\n\r"); + + if (q != NULL) + { + if (strcmp(q, "udp") == 0) + { + uport = DEFAULT_UDP_PORT; + + q = strtok(NULL, " \t\n\r"); + if (q != NULL) + { + i = atoi(q); + if (i > 0) + uport = i; + } + } + } +#ifndef AXIPR_UDP + route_add((unsigned char*)he->h_name, he, tcall, uport, dfalt, 0); +#else + route_add((unsigned char*)he->h_name, he, tcall, uport, dfalt, 0, (char*)he->h_name +#ifdef AXIPR_HTML + , timeset, P_USER +#endif /* AXIPR_HTML */ + ); +#endif /* AXIPR_UDP */ + return(0); + } + return(-999); +} + + +/* Convert ascii callsign to internal format */ +int a_to_call(char *text, unsigned char *tcall) +{ + register size_t i = 0; + int ssid = 0; + unsigned char c; + + if (strlen(text) == 0) + return(-1); + + for (i = 0; i < 6; ++i) + tcall[i] = (' ' << 1); + + tcall[6] = '\0'; + + for (i = 0; i < strlen(text); ++i) + { + c = text[i]; + if (c == '-') + { + ssid = atoi(&text[i + 1]); + if (ssid > 15) + return(-1); + tcall[6] = (ssid << 1); + return(0); + } + + if (islower(c)) + c = toupper(c); + + if (i > 5) + return(-1); + + tcall[i] = (c << 1); + } + return(0); +} + +/* Convert internal callsign to printable format */ +char *call_to_a(unsigned char *tcall) +{ + int i = 0; + int ssid = 0; + char *tptr; + static char t[10]; + + for (i = 0, tptr = t; i < 6; ++i) + { + if (tcall[i] == (' ' << 1)) + break; + *tptr = tcall[i] >> 1; + tptr++; + } + + ssid = (tcall[6] >> 1) & 0x0f; + if (ssid > 0) + { + *tptr = '-'; + tptr++; + + if (ssid > 9) + { + *tptr = '1'; + tptr++; + ssid -= 10; + } + *tptr = '0' + ssid; + tptr++; + } + + *tptr = '\0'; + return(&t[0]); +} + +void write_log(const char *format, ...) +{ + FILE *fp; + va_list arg_ptr; + struct tm *lt; + + fp = fopen("ax25ip.log", "a+"); + + if (fp != NULL) + { + lt = localtime(&sys_time); + fprintf(fp, "%16.16s:", ctime(&sys_time)); + va_start(arg_ptr, format); + vfprintf(fp, format, arg_ptr); + va_end(arg_ptr); + fprintf(fp, "\n"); + fclose(fp); + } + else + loglevel = 0; /* Logging aus da Fehler mit der Logdatei */ +} + +#ifdef AXIPR_UDP +/* AX25IP-Frame untersuchen, wenn Aenderungen */ +/* z.B. UDP-Port, IP-Adresse in TBL Aktualisieren.*/ +void route_analyse(struct in_addr ip, unsigned char *call, int uport) +{ + register int i; + char mycall[7]; + +#ifdef AXIPR_HTML + char *timeset = set_time(); +#endif /* AXIPR_HTML */ + + /* Leere Calls koennen nicht verarbeitet werden */ + if (call[0] == FALSE) + return; + + /* Call-Bytes kopieren, letztes Bit abschneiden (entspricht >> 1 & 7F) */ + for (i = 0; i < 6; ++i) + mycall[i] = call[i] & 0xfe; + + /* SSID kopieren */ + mycall[6] = (call[6] & 0x1e) | 0x60; + + /* Routingtabelle durchsuchen */ + for (i = 0; i < route_tbl_top; ++i) + { + if (addrmatch((unsigned char *)mycall , route_tbl[i].callsign)) + { + /* Bei Aenderung uebernehmen */ + if (memcmp(&ip, &route_tbl[i].ip_addr, 4) != 0) + /* IP-Adresse hat sich geaendert */ + memcpy(&route_tbl[i].ip_addr, &ip, 4); + + /* UDP-Port unterschiedlich? */ + if (route_tbl[i].udp_port != htons((UWORD)uport)) + /* UDP-Port updaten. */ + route_tbl[i].udp_port = htons((UWORD)uport); + +#ifdef AXIPR_HTML + /* Route ggf. auf online setzen. */ + if (!route_tbl[i].online) + route_tbl[i].online = TRUE; +#endif + /* Aktivitaet auf diesem Eintrag, dann Timeout erneuern */ + if (route_tbl[i].timeout) + route_tbl[i].timeout = uDynTimeout; + + /* Aktualisierung beendet. */ + return; + } + } + +#ifndef AXIPR_HTML + /* Auto-Route eintragen */ + route_add((unsigned char*)inet_ntoa(ip), NULL, call,uport, FALSE, uDynTimeout, (char*)inet_ntoa(ip)); +#else + /* Auto-Route eintragen */ + route_add((unsigned char*)inet_ntoa(ip), NULL, call,uport, FALSE, uDynTimeout, (char*)inet_ntoa(ip), timeset, P_USER); +#endif /* AXIPR_HTML */ +} + +/* Per Rufzeichen, ohne die SSID zubeachten, einen */ +/* Routeneintrag suchen. Gibt es keinen Eintrag, */ +/* wird sofort abgebrochen, ansonsten werden die */ +/* routeneintraege IP-Adresse und UDP-Port ueber- */ +/* nommen und das neue Rufzeichen wird eingetragen.*/ +struct route_table_entry *search_route(unsigned char *call) +{ + register int i; + char srccall[10]; +#ifdef AXIPR_HTML + char *timeset = set_time(); +#endif /* AXIPR_HTML */ + + /* Konvertiere Rufzeichen. */ + callss2str((char *)srccall, call_to_a(call)); + + /* TB durchgehen. */ + for (i = 0; i < route_tbl_top; ++i) + { + /* Suche Rufzeichen. */ + if (cmpcal(srccall, call_to_a(&route_tbl[i].callsign[0]))) + { +#ifndef AXIPR_HTML + /* Auto-Route eintragen */ + route_add((unsigned char *)&route_tbl[i].ip_addr, NULL, (unsigned char *)call, htons(route_tbl[i].org_udp_port), FALSE, uDynTimeout, (char *)route_tbl[i].hostname); +#else + /* Auto-Route eintragen */ + route_add((unsigned char *)&route_tbl[i].ip_addr, NULL, (unsigned char *)call, htons(route_tbl[i].org_udp_port), FALSE, uDynTimeout, (char *)route_tbl[i].hostname, timeset, P_USER); +#endif /* AXIPR_HTML */ + /* Aktuellen Eintrag weiterreichen. */ + return (&route_tbl[i]); /* Eintrag gefunden */ + } + } + /* Kein Rufzeichen gefunden. */ + return (NULL); +} + +/* Eine AX-Route Updaten. */ +void UpdateRoute(unsigned char *srccall, + int udpport, + int timeout, + char *hostname +#ifdef AXIPR_HTML + , char *timeset + , UWORD protokoll +#endif /* AXIPR_HTML */ +) +{ + MBHEAD *mbp; + register int i; + + /* TB durchgehen. */ + for (i = 0; i < route_tbl_top; ++i) + { + /* Suche Rufzeichen. */ + if (addrmatch((unsigned char *)srccall , route_tbl[i].callsign)) + { + route_tbl[i].org_udp_port = route_tbl[i].udp_port = htons((unsigned short)udpport); + /* Hostname eintragen. */ + (void)memcpy(route_tbl[i].hostname, hostname, HNLEN); + /* ggf. Timeout setzen. */ + route_tbl[i].timeout = timeout; + +#ifdef AXIPR_HTML + /* Hostname eintragen. */ + (void)memcpy(route_tbl[i].timeset, timeset, 17); + /* Protokoll eintragen. */ + route_tbl[i].protokoll = P_USER; +#endif /* AXIPR_HTML */ + + mbp = getmbp(); + + /* und ab die Post ... */ + prompt(mbp); + seteom(mbp); + return; + } + } +} + +#ifdef AXIPR_HTML + +/* Protokoll fuer HTML-Ausgabe setzen. */ +void SetHTML(int port, char *call, PEER *pp, BOOLEAN flag) +{ + register int i; + char srccall[10 + 1]; + + call2str(srccall, call); + + /* Routingtabelle durchsuchen */ + for (i = 0; i < route_tbl_top; ++i) + { + if (!strcmp(srccall , call_to_a(&route_tbl[i].callsign[0]))) + { + /* Protokoll setzen. */ + set_status(i, port, pp); + + /* Route auf online/offline stellen. */ + route_tbl[i].online = flag; + + break; + } + } +} + +/* Aktualisiere Loginzeit fuer TB */ +char *set_time(void) +{ + time_t go; + struct tm *zeit; + static char c[17]; + char *timeset = c; + + /* aktuelle Kalenderzeit */ + time(&go); + /* konvertiert Datum und Uhrzeit. */ + zeit = localtime(&go); + /* Formatiere eine Zeit-/Datumsangabe */ + strftime(c,17,"%d-%b-%H:%M:%S",zeit); + +/* Aktuelle Login Date/Time */ +return(timeset); +} + +/* Protokoll setzen. */ +void set_status(register int a, int port, PEER *pp) +{ + if (pp == NULL) /* Route wird ausgetragen. */ + { + route_tbl[a].protokoll = P_OFFLINE; /* Route auf OFFLINE setzen. */ + route_tbl[a].online = FALSE; + return; + } + + switch(pp->typ) /* Protokol-TYP. */ + { + case INP : /* INP-TYP. */ + route_tbl[a].protokoll = P_INP; /* INP-TYP setzen. */ + break; + + case TNN : /* TNN-TYP */ + case THENET : /* THENET-TYP. */ + route_tbl[a].protokoll = P_THENET; /* TNN/THENET-TYP setzen. */ + break; + + case FLEXNET: /* FLEXNET-TYP. */ + route_tbl[a].protokoll = P_FLEXNET; /* FLEXNET-TYP setzen. */ + break; + + default: + route_tbl[a].protokoll = P_OFFLINE; /* Route auf OFFLINE setzen. */ + route_tbl[a].online = FALSE; + return; + } + + route_tbl[a].online = TRUE; +} + +/* Timer fuer htmlstatistik. */ +void h_timer(void) +{ + static LONG h_Timer = 0L; + + /* Timer abgelaufen. */ + if (h_Timer <= 0L) + { + /* Timer neu setzen. */ + /* fest auf 60 sec. */ + h_Timer = 60L; + /* html auf Platte schreiben. */ + w_statistik(); + } + /* Timer runter zaehlen. */ + h_Timer--; +} + +/* Hiermit checken wir ob die rstat.css existiert. */ +/* FALSE = keine rstat.css gefunden */ +/* TRUE = es existiert eine rstat.css */ +static int check_css_file(void) +{ + char cssfile[255]; + + /* Path kopieren. */ + strcpy(cssfile, htmlpath); + /* CSS-Dateiname anhaengen. */ + strcat(cssfile, CSS_RFILE); + + /* Pruefe ob Datei existiert.*/ + if (!access(cssfile,FALSE)) + /* Datei existiert. */ + return(TRUE); + else + /* Nix gefunden! */ + return(FALSE); +} + +/* Eine default RSTAT.CSS schreiben */ +static void rstat_css_default_file(void) +{ + FILE *fp; + char cfgfile[255]; + + if (HtmlStat == FALSE) + return; + + strcpy(cfgfile, htmlpath); + strcat(cfgfile, CSS_RFILE); + if ((fp = fopen(cfgfile, "w+t")) == NULL) + return; + + fprintf(fp,"BODY {\n" + " BACKGROUND-IMAGE: url('bg.jpg');\n" + " BACKGROUND-COLOR: #000080;\n" + " COLOR: #FFFFFF;\n" + " FONT-FAMILY: Verdana, Arial;\n" + " FONT-SIZE: 12;\n" + "}\n"); + + fprintf(fp,"H1 {\n" + " FONT-SIZE: 18; COLOR: #FFCC00;\n" + "}\n"); + + fprintf(fp,"H2 {\n" + " FONT-SIZE: 12; COLOR: #FFFFFF;\n" + "}\n"); + + fprintf(fp,"a:link, a:visited {\n" + " COLOR: #FFFFFF;\n" + " text-weight: bold;\n" + " text-decoration: none;\n" + "}\n"); + + fprintf(fp,"a:hover {\n" + " COLOR: #FF6600;\n" + " text-weight: bold;\n" + " text-decoration: none;\n" + "}\n" + ".info {\n" + " FONT-SIZE: 12; COLOR: #99CCFF;\n" + "}\n"); + + fprintf(fp,"table.box {\n" + " background-color: #ffbb00;\n" + " backcolor: #220000;\n" + " backcolorlight: #00ff00;\n" + " backcolordark: #000000;\n" + " border-width: 0px;\n" + " width: 95%%;\n" + " border-style: outset;\n" + " border-spacing: 2px;\n" + " border-padding: 8px;\n" + "}\n"); + +fprintf(fp,".status {\n" + " FONT-SIZE: 10; BACKGROUND: #000000; COLOR: #FFCC00; TEXT-ALIGN: center;\n" + "}\n"); + + fprintf(fp,".off {\n" + " FONT-SIZE: 10; BACKGROUND: #000000; COLOR: #ffffff;\n" + "}"); + + fprintf(fp,".offline {\n" + " FONT-SIZE: 10; BACKGROUND: #9f00FF; COLOR: #ffffff;\n" + "}"); + + fprintf(fp,".user {\n" + " FONT-SIZE: 10; BACKGROUND: #E06060; COLOR: #ffffff;\n" + "}\n"); + + fprintf(fp,".thenet {\n" + " FONT-SIZE: 10; BACKGROUND: #E00060; COLOR: #ffffff;\n" + "}\n"); + + fprintf(fp,".inp {\n" + " FONT-SIZE: 10; BACKGROUND: #0070C0; COLOR: #ffffff;\n" + "}\n"); + + fprintf(fp,".Flexnet {\n" + " FONT-SIZE: 10; BACKGROUND: #006060; COLOR: #ffffff;\n" + "}\n"); + + fprintf(fp,".about {\n" + " FONT-SIZE: 13; COLOR: #ffffff;\n" + "}\n"); + + fclose(fp); +} + +/* Wie viel Ports sind nich frei ? */ +static int free_ports(void) +{ + int free = FALSE; + + return(free = TABLE_SIZE - route_tbl_top); +} + +/* Wie viel L2-Links (USER) - sind aktiv ? */ +static int activ_user(void) +{ + register int a; + int user = FALSE; + + /* TB durchgehen */ + for (a = 0; a < route_tbl_top; a++) + /* nur die als User markiert sind */ + if ( route_tbl[a].protokoll == P_USER + /* und online sind !!! */ + && route_tbl[a].online > 0) + /* Alle USER zaehlen */ + user++; + + return(user); +} + +/* Wie viel L2/L4_links sind aktiv ? */ +static int activ_links(void) +{ + register int a; + int links = FALSE; + + /* TB durchgehen */ + for (a = 0; a < route_tbl_top; a++) + /* L2/L4-Link online ? */ + if ( route_tbl[a].online > 0 + /* wir zaehlen alle Protokolle, ausser USER */ + && route_tbl[a].protokoll != 1) + links++; + + return(links); +} + +/* Die Aktuelle Uhrzeit fuer HTML ausgeben */ +static char *puttim_stat(void) +{ + struct tm *p; + static char tim[20]; + time_t timet; + char *atime = tim; + + time(&timet); + + p = localtime(&timet); + sprintf(tim,"%02i.%02i.%02i %02i:%02i:%02i", + p->tm_mday, p->tm_mon+1, p->tm_year % 100, + p->tm_hour, p->tm_min, p->tm_sec); + + return(atime); +} + +static char *set_class(UWORD flag, register int a) +{ + static char o[8]; + char *protokoll = o; + + switch(flag) + { + case P_OFFLINE : + if (!route_tbl[a].online) + strcpy(o, "offline"); + + break; + + case P_USER : + if (route_tbl[a].online) + strcpy(o, "user"); + else + strcpy(o, "offline"); + break; + + case P_THENET : + if (route_tbl[a].online) + strcpy(o, "thenet"); + else + strcpy(o, "offline"); + break; + + case P_INP : + if (route_tbl[a].online) + strcpy(o, "inp"); + else + strcpy(o, "offline"); + + break; + + case P_FLEXNET : + if (route_tbl[a].online) + strcpy(o, "flexnet"); + else + strcpy(o, "offline"); + + break; + + default: + strcpy(o, "unknown"); + break; + } + + return(protokoll); +} + +static char *set_pname(register int a) +{ + static char p[8]; + char *protokoll = p; + + switch(route_tbl[a].protokoll) + { + case P_USER : + strcpy(p, "L2"); + break; + + case P_THENET : + strcpy(p, "THENET"); + break; + + case P_INP : + strcpy(p, "INP"); + break; + + case P_FLEXNET : + strcpy(p, "FLEXNET"); + break; + + default: + strcpy(p, "UNKNOWN"); + break; + } + +return(protokoll); +} + +static void all_route(FILE *fp, UWORD flag, register int a) +{ + char *pclass = set_class(flag, a); + char *protokoll = set_pname(a); + + /* Nummer einer Route. */ + fprintf(fp,"
%d\n" + , pclass, a); + + /* Rufzeichen. */ + fprintf(fp," %s\n" + , pclass + , call_to_a(&route_tbl[a].callsign[0])); + + /* IP-Adresse. */ + fprintf(fp," " + " %s\n" + , pclass + , route_tbl[a].hostname + , route_tbl[a].hostname); + + /* Hostname/IP-Adresse. */ + fprintf(fp,"
%s\n" + , pclass + , route_tbl[a].hostname); + + /* UDP-Port */ + fprintf(fp,"
%d\n" + , pclass + , htons(route_tbl[a].udp_port)); + + /* Loginzeit */ + fprintf(fp,"
%s\n" + , pclass + , route_tbl[a].timeset); + + if (route_tbl[a].timeout) + /* Timeout */ + fprintf(fp,"
%d\n" + , pclass + , route_tbl[a].timeout); + else + /* Statische Route */ + fprintf(fp,"
Statisch\n" + , pclass); + + /* Protokoll */ + fprintf(fp,"
%s\n" + , pclass + , protokoll); +} + +static void show_route(FILE *fp, UWORD flag, register int a) +{ + switch(flag) + { + case P_OFFLINE : + if (!route_tbl[a].online) + fprintf(fp," \n"); + + break; + + case P_USER : + if ( route_tbl[a].protokoll == flag + && route_tbl[a].online) + fprintf(fp," \n"); + else + fprintf(fp," \n"); + + break; + + case P_THENET : + if ( route_tbl[a].protokoll == flag + && route_tbl[a].online) + fprintf(fp," \n"); + else + fprintf(fp," \n"); + + break; + + + case P_INP : + if ( route_tbl[a].protokoll == flag + && route_tbl[a].online) + fprintf(fp," \n"); + else + fprintf(fp," \n"); + + break; + + case P_FLEXNET : + if ( route_tbl[a].protokoll == flag + && route_tbl[a].online) + fprintf(fp," \n"); + else + fprintf(fp," \n"); + + break; + + + default: + if ( route_tbl[a].protokoll == flag + && route_tbl[a].online) + fprintf(fp," \n"); + else + fprintf(fp," \n"); + + break; + } + all_route(fp, flag, a); +} + +/* Schreibe htmlstatistik auf Platte. */ +void w_statistik(void) +{ + FILE *fp; + char cfgfile[255],mycall[10]; + char *atime = puttim_stat(); + register int a; + char runtime[8 + 1]; +#ifndef CONNECTTIME + unsigned long upt, + upd, + uph; +#endif /* CONNECTTIME */ + + /* Pruefe, ob htmlstatistik eingeschaltet ist. */ + if (HtmlStat == FALSE) + /* Ist nicht eingeschaltet, abbruch. */ + return; + else + { + /* Pruefe ob CSS-Datei exisiert. */ + if (!check_css_file()) + /* Nein, dann neuschreiben. */ + rstat_css_default_file(); + + } + + strcpy(cfgfile,htmlpath ); + strcat(cfgfile, HTML_RFILE); + if ((fp = fopen(cfgfile,"w+t")) == NULL) + return; + + call2str(mycall,myid); + +#ifndef CONNECTTIME + upt = sys_time - start_time; /* Uptime in seconds */ + upd = upt / SECONDS_PER_DAY; /* Uptime days */ + upt %= SECONDS_PER_DAY; + uph = upt / SECONDS_PER_HOUR; /* Uptime hours */ + upt %= SECONDS_PER_HOUR; + + if (upd > 0) + sprintf(runtime, "%2lud,%2luh", upd, uph); + else + if (uph > 0) + sprintf(runtime, "%2luh,%2lus", uph, upt); + else + if (upt > 0) + sprintf(runtime, " %2lus", upt); + else + sprintf(runtime, " "); +#else + sprintf(runtime, "%s", ConnectTime(tic10 / 100)); +#endif /* CONNECTTIME */ + + fprintf(fp,"" + "\n" + "\n" + "AXIPR-Statistik\n" + "\n" + "\n\n",HTML_INV); + + fprintf(fp,"
\n" + "

%s%s)

\n",signon,mycall); + + fprintf(fp,"

Date/Time: %s Runtime: %s, %d Frei

\n\n",atime, runtime, free_ports()); + fprintf(fp," %d L2/L4-LINKS\n",activ_links()); + fprintf(fp,"\n"); + fprintf(fp," \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n"); + + /* TB durchgehen. */ + for (a = 0; a < route_tbl_top; a++) + { + /* Nur aktive Routen zeigen. */ + if (route_tbl[a].online == FALSE) + /* zum naechsten Eintrag. */ + continue; + + /* Nur INP- oder FLEXNET-Routen bearbeiten */ + if (route_tbl[a].protokoll > P_USER) + /* und anzeigen. */ + show_route(fp, route_tbl[a].protokoll, a); + } + + fprintf(fp,"
Nr.RufzeichenIP-AdresseDYNDNSUDPLoginTimeoutProtokoll


\n"); + + fprintf(fp,"%d USER\n",activ_user()); + fprintf(fp,"\n"); + fprintf(fp," \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n"); + + /* TB durchgehen */ + for (a = 0; a < route_tbl_top; a++) + { + /* Nur aktive Routen zeigen. */ + if (route_tbl[a].online == FALSE) + /* zum naechsten Eintrag. */ + continue; + + /* Nur USER-Routen bearbeiten */ + if (route_tbl[a].protokoll == P_USER) + /* und anzeigen. */ + show_route(fp, route_tbl[a].protokoll, a); + } + + fprintf(fp,"
Nr.RufzeichenIP-AdresseDYNDNSUDPLoginTimeoutProtokoll
\n\n"); + fprintf(fp,"
My UDP-Port: %u\n",htons(my_udp)); + fprintf(fp,"\n"); + fclose(fp); +} + +#endif /* AXIPR_HTML */ +#endif /* AXIPR_UDP */ + +#endif + +/* End of os/win32/ax25ip.c */ diff --git a/os/win32/ax25ip.h b/os/win32/ax25ip.h new file mode 100755 index 0000000..0e2efcc --- /dev/null +++ b/os/win32/ax25ip.h @@ -0,0 +1,199 @@ +/************************************************************************/ +/* */ +/* ***** ***** */ +/* ***** ***** */ +/* ***** ***** */ +/* ***** ***** */ +/* *************** *************** */ +/* ***************** ***************** */ +/* *************** *************** */ +/* ***** ***** TheNetNode */ +/* ***** ***** Portable */ +/* ***** ***** Network */ +/* ***** ***** Software */ +/* */ +/* File os/linux/ax25ip.h (maintained by: DG9OBU) */ +/* */ +/* This file is part of "TheNetNode" - Software Package */ +/* */ +/* Copyright (C) 1998 - 2008 NORD>0)(void)write_log +#define LOGL2 if(loglevel>1)(void)write_log +#define LOGL3 if(loglevel>2)(void)write_log +#define LOGL4 if(loglevel>3)(void)write_log + +#define HNLEN 64 + +#define OP_NONE 0 +#define OP_ADD 1 +#define OP_DEL 2 +#define OP_MYUDP 3 +#define OP_LOG 4 +#define OP_TIMEOUT 5 +#define OP_HNUPD 6 + +#define BUFLEN 32 + + static unsigned int uDynTimeout = 3600; /* eine Stunde */ + +/* Variablen */ +static LHEAD *l2flp; +static DEVICE *l1pp; +static int ax25ip_port; +static BOOLEAN ax25ip_active = FALSE; +static BOOLEAN sockopt_keepalive = FALSE; +static BOOLEAN sockopt_throughput = FALSE; +static WORD mode; +/* Nameservice-Updateintervall (in Zehntelsekunden !) */ +static UWORD uNamesUpdate = 18000; +static struct sockaddr_in udpbind; +static struct sockaddr_in ipbind; +static struct sockaddr_in to; +static struct sockaddr_in from; +#ifndef ATTACH +unsigned short my_udp = 0; +#endif +int route_tbl_top = 0; +int loglevel = 0; + +int fd_udp = -1; /* Filedescriptor fuer UDP */ +int fd_ip = -1; /* Filedescriptor fuer IP */ + +/* TEST DG9OBU */ +static BOOLEAN new_parser = FALSE; /* Standardmaessig alte Syntax */ + +struct route_table_entry { + unsigned char callsign[L2IDLEN]; /* the callsign and ssid */ + unsigned long ip_addr; /* the IP address */ + unsigned short udp_port; /* the port number if udp */ + unsigned int timeout; /* Timeout der Route */ + unsigned char hostname[HNLEN]; +#ifdef AXIPR_UDP + unsigned short org_udp_port; /* Original UDP-Port. */ +#endif +#ifdef AXIPR_HTML + unsigned char timeset[17 + 1]; /* Login-Zeit/Date. */ + unsigned short protokoll; /* Protokoll (INP,Flexnet..) */ + unsigned short online; /* Route online/offline. */ +#endif +}; + +struct route_table_entry route_tbl[TABLE_SIZE]; +struct route_table_entry default_route; + +/* Funktionsprototypen */ +int setup_ip(void); +int setup_udp(unsigned short); +void show_rt_entry(struct route_table_entry, MBHEAD*); +void ccpaxipr(void); +void ax25ip_send(void); +void ax25ip_recv(void); +void ax25ip_check_up(void); +void ax25ip_check_down(void); +#ifndef AXIPR_UDP +static void route_add(unsigned char*, struct hostent*, unsigned char*, int, int, int); +#else +static BOOLEAN route_add(unsigned char*, struct hostent*, unsigned char*, int, int, int + , char * +#ifdef AXIPR_HTML + , char *, UWORD +#endif /* AXIPR_HTML */ + ); +#endif /* AXIPR_UDP */ + +BOOLEAN route_del(unsigned char*); +unsigned int count_routes(BOOLEAN); +void route_init(void); +void route_age(void); +void route_update(struct route_table_entry*); +BOOLEAN route_canlearn(MBHEAD*); +void add_crc(unsigned char*, int); +int addrmatch(unsigned char*, unsigned char*); +void add_ax25crc(unsigned char*, int); +UWORD compute_crc(unsigned char*, int); +BOOLEAN ok_crc(unsigned char*, int); +int config_read(void); +int parse_line(char*); +int a_to_call(char*, unsigned char*); +char *call_to_a(unsigned char*); + +struct route_table_entry *call_to_ip(unsigned char*); + +unsigned char *next_addr(unsigned char*); +void write_log(const char*, ...); + + +#ifdef AXIPR_UDP +void route_analyse(struct in_addr, unsigned char *, int); +void route_check(register int); +struct route_table_entry *search_route(unsigned char *); +void UpdateRoute(unsigned char *, int, int, char * +#ifdef AXIPR_HTML + , char *, UWORD +#endif /* AXIPR_HTML */ + ); +#endif /* AXIPR_UDP */ + +#ifdef AXIPR_HTML +#define P_OFFLINE 0 +#define P_USER 1 +#define P_THENET 2 +#define P_INP 3 +#define P_FLEXNET 4 + +#define CSS_RFILE "rstat.css" +#define HTML_RFILE "rstat.html" +#define HTML_INV 60 + +static unsigned int HtmlStat = FALSE; /* HtmlStatistik ausgeshaltet. */ + +void h_timer(void); +void w_statistik(void); +char *set_time(void); +void set_status(register int, int, PEER *); +#endif + +/* End */ diff --git a/os/win32/init.c b/os/win32/init.c new file mode 100755 index 0000000..98a5a5e --- /dev/null +++ b/os/win32/init.c @@ -0,0 +1,714 @@ +/************************************************************************/ +/* */ +/* ***** ***** */ +/* ***** ***** */ +/* ***** ***** */ +/* ***** ***** */ +/* *************** *************** */ +/* ***************** ***************** */ +/* *************** *************** */ +/* ***** ***** TheNetNode */ +/* ***** ***** Portable */ +/* ***** ***** Network */ +/* ***** ***** Software */ +/* */ +/* File os/win32/init.c (maintained by: DF6LN) */ +/* */ +/* This file is part of "TheNetNode" - Software Package */ +/* */ +/* Copyright (C) 1998 - 2008 NORD>typ < NIX; ip++) + { + if (stricmp(str1, ip->name) == 0) + break; /* gefunden */ + } + + /* Parameter auswerten */ + switch (ip->typ) + { + /* Parameter "tnn_dir" */ + case DIRECTORY: + /* Verzeichnisname kopieren und Laenge merken */ + strcpy(tnn_dir, str2); + tmp = strlen(tnn_dir); + /* abschliessendes "/" an den Pfad anhaengen */ + if (tnn_dir[strlen(tnn_dir) - 1] != '/') + strcat(tnn_dir, "/"); + + chdir(tnn_dir); + /* in das Verzeichnis wechseln */ + if (chdir(tnn_dir) == -1) + printf("WARNING: error while changing directory : %s", strerror(errno)); + + return (FALSE); + + /* Parameter "tnn_errfile" */ + case ERRORFILE: + /* Dateinamen kopieren */ + strcpy(tnn_errfile, str2); + return (FALSE); + + /* Parameter "tnn_start" */ + case START: + /* Programmnamen kopieren */ + strcpy(start_name, str2); + return (FALSE); + + /* Parameter "tnn_stop" */ + case STOP: + /* Programmnamen kopieren */ + strcpy(stop_name, str2); + return (FALSE); + + /* Parameter "buffers" */ + case BUFFERS: + /* Anzahl Buffer lesen */ + if (sscanf(str2, "%lu", &tnn_buffers) != 1) + return (TRUE); + + return (FALSE); + + /* Parameter "rounds" */ + case ROUNDS: + /* Anzahl Runden lesen */ + if (sscanf(str2, "%u", &u) != 1) + return (TRUE); + + /* gegen Ueberlauf durch negative Werte durch Spielkinder, der sscanf */ + /* liefert bei signed-Werten einen sehr hohen unsigned-Wert */ + if (u > 65500) + u = 65500; + + /* gewuenschten Wert runterteilen um das nicht spaeter im Vergleicher */ + /* tun zu muessen, auf Nachkommastellen keinen Wert legen */ + maxrounds = (u / 100); + + /* zu wenig Drehzahl ist ungesund */ + if (maxrounds < 1) + maxrounds = 1; + + return (FALSE); + + /* Parameter "perms" */ + case PERMS: + /* Wert fuer umask lesen */ + if (sscanf(str2, "%o", &u) != 1) + return (TRUE); + + /* neue umask setzen */ + umask(u); + return (FALSE); + + /* Parameter "device" */ + case DEV: + /* schon alle Ports vergeben ? */ + if (max_device >= L1PNUM - 1) + return (TRUE); + + /* Device merken */ + strcpy(l1port[++max_device].device, str2); + return (FALSE); + + /* Parameter "tnn_lockfile" */ + case LOCKFILE: + if ( (max_device < 0) /* kein Device */ + || (l1port[max_device].tnn_lockfile[0])) /* Name doppelt */ + return (TRUE); + + /* Lockfile merken */ + strcpy(l1port[max_device].tnn_lockfile, str2); + return (FALSE); + + /* Parameter Speed */ + case SPEED: + if ( (max_device < 0) /* kein Device */ + || (sscanf(str2, "%d", &tmp) != 1)) /* Wert ermitteln */ + return (TRUE); + + l1port[max_device].speedflag = 0; + + /* Geschwindigkeits-Code suchen */ + switch (tmp) + { + case 0: + l1port[max_device].speed = 0; + return (FALSE); + + case 9600: + l1port[max_device].speed = B9600; + return (FALSE); + + case 19200: + l1port[max_device].speed = B19200; + return (FALSE); + + case 38400: + l1port[max_device].speed = B38400; + return (FALSE); + + case 57600: +#ifdef B57600 + l1port[max_device].speed = B57600; +#else + l1port[max_device].speed = B38400; + l1port[max_device].speedflag = ASYNC_SPD_HI; +#endif + return (FALSE); + + case 115200: +#ifdef B115200 + l1port[max_device].speed = B115200; +#else + l1port[max_device].speed = B38400; + l1port[max_device].speedflag = ASYNC_SPD_VHI; +#endif + return (FALSE); + + case 230400: +#ifdef B230400 + l1port[max_device].speed = B230400; +#else + l1port[max_device].speed = B38400; + l1port[max_device].speedflag = ASYNC_SPD_SHI; +#endif + return (FALSE); + + case 460800: +#ifdef B460800 + l1port[max_device].speed = B460800; +#else + l1port[max_device].speed = B38400; +#endif + l1port[max_device].speedflag = ASYNC_SPD_WARP; + return (FALSE); + + /* unbekannte Geschwindigkeiten */ + default: + return (TRUE); + } + return (FALSE); + + /* Parameter "kisstype" */ + case KISSTYPE: + if ( (max_device < 0) /* kein Device */ + || (sscanf(str2, "%d", &tmp) != 1) /* Wet ermitteln */ +#ifndef AX_IPX + || (tmp == KISS_IPX) +#endif +#ifndef AX25IP + || (tmp == KISS_AXIP) +#endif +#ifndef VANESSA + || (tmp == KISS_VAN) +#endif +#ifndef KERNELIF + || (tmp == KISS_KAX25) + || (tmp == KISS_KAX25KJD) +#endif +#ifndef SIXPACK + || (tmp == KISS_6PACK) + || ((tmp == KISS_6PACK) && (max_device != 0)) +#endif + || (tmp < KISS_NORMAL) + || (tmp > KISS_MAX) + || ((tmp == KISS_TOK) && (max_device != 0))) + return (TRUE); + + /* Typ merken */ + l1port[max_device].kisstype = tmp; + + /* Geschwindigkeit fuer Tokenring-Port */ + if (tmp == KISS_TOK) + { + tkcom = 1; + switch (l1port[0].speed) + { + case B9600: + tkbaud = 96; + break; + + case B19200: + tkbaud = 192; + break; + + case B38400: + tkbaud = 384; +#ifndef B57600 + if (l1port[0].speedflag == ASYNC_SPD_HI) + tkbaud = 576; +#endif +#ifndef B115200 + if (l1port[0].speedflag == ASYNC_SPD_VHI) + tkbaud = 1152; +#endif +#ifndef B230400 + if (l1port[0].speedflag == ASYNC_SPD_SHI) + tkbaud = 2304; +#endif +#ifndef B460800 + if (l1port[0].speedflag == ASYNC_SPD_WARP) + tkbaud = 4608; +#endif + + break; + +#ifdef B57600 + case B57600: + tkbaud = 576; + break; +#endif +#ifdef B115200 + case B115200: + tkbaud = 1152; + break; +#endif +#ifdef B230400 + case B230400: + tkbaud = 2304; + break; +#endif +#ifdef B460800 + case B460800: + tkbaud = 4608; + break; +#endif + } + } + return (FALSE); + + /* Parameter "port" */ + case PORT: + if ( (max_device < 0) + || (sscanf(str2, "%d", &tmp) != 1) + || (tmp < 0) + || (tmp > L2PNUM) + || (l1port[max_device].kisstype < 0)) + return (TRUE); + + /* Sonderbehandlung fuer Tokenring-Ports */ + if (l1port[max_device].kisstype == KISS_TOK) + { + /* noch Ports verfuegbar ? */ + if (++tokenring_ports >= L2PNUM) + return (TRUE); + + l1ptab[tmp] = 0; + l2ptab[max_device] = -1; + ++used_l1ports; + return (FALSE); + } + +#ifdef SIXPACK + /* Sonderbehandlung fuer 6PACK-Ports */ + if (l1port[max_device].kisstype == KISS_6PACK) + { + /* noch Ports verfuegbar ? */ + if (++sixpack_ports >= L2PNUM) + return (TRUE); + + l1ptab[tmp] = max_device; + l2ptab[max_device] = -1; + ++used_l1ports; + return (FALSE); + } +#endif + /* alle andere Devices */ + /* noch Ports verfuegbar ? */ + if (++used_l1ports >= L2PNUM) + return (TRUE); + + if ( l1ptab[tmp] == -1 /* Port noch nicht */ + && l2ptab[max_device] == -1) /* verwendet? */ + { + l1ptab[tmp] = max_device; + l2ptab[max_device] = tmp; + } + + /* Evtl. sollte noch geprueft werden, ob die Zuordnung der Vanessa- */ + /* ports konsistent ist. */ + return (FALSE); + + default: + return (TRUE); + } + return (FALSE); +} + +/************************************************************************/ +/* Fuegt das TNN-Verzeichnis vorne hinzu */ +/************************************************************************/ +void +add_tnndir(char *str) +{ + char temp[80]; + + /* leere Strings verarbeiten wir nicht */ + if (str[0] == NUL) + return; + + /* nur bearbeiten, wenn erstes Zeichen nicht / ist */ + if (str[0] != '/') + { + strcpy(temp, tnn_dir); + strcat(temp, str); + strcpy(str, temp); + } +} + +/************************************************************************/ +/* Lesen des TNN-INI-Files und des Kommandozeilenparameter */ +/************************************************************************/ +BOOLEAN +read_init_file(int argc, char *argv[]) +{ + FILE *init_file_fp; + BOOLEAN wrong_usage = FALSE; + BOOLEAN file_end = FALSE; + BOOLEAN file_corrupt = FALSE; + BOOLEAN warning = FALSE; + char line[82]; + char str1[82]; + char str2[82]; + char tmp_str[80]; + int rslt; + char *str_ptr; + int scanned; + int i; + DEVICE *l1pp; +#ifdef AX_IPX + int axipx_ports = 0; +#endif +#ifdef AX25IP + int ax25ip_ports = 0; +#endif +#ifdef L1TELNET + int telnet_ports = 0; +#endif /* L1TELNET */ +#ifdef L1HTTPD + int httpd_ports = 0; +#endif /* L1HTTPD */ +#ifdef L1IPCONV + int ipconv_ports = 0; +#endif /* L1IPCONV */ +#ifdef L1IRC + int irc_ports = 0; +#endif /* L1IRC */ + + /* erst mal alles initialisieren */ + tnn_buffers = TNN_BUFFERS; + max_device = -1; +#ifdef ATTACH + tokenring_ports = 0; + sixpack_ports = 0; +#else + tokenring_ports = -1; +#endif /* ATTACH */ + used_l1ports = -1; + kiss_active = FALSE; + start_name[0] = + stop_name[0] = NUL; + + /* alle L1-Ports durchgehen und initialisieren */ + for (i = 0; i < L1PNUM; ++i) + { + l1pp = &l1port[i]; + l1pp->device[0] = NUL; + l1pp->tnn_lockfile[0] = NUL; + l1pp->speed = 0; + l1pp->speedflag = 0; + l1pp->kisstype = KISS_NIX; + l1pp->kisslink = -1; + l1pp->port_active = FALSE; + l2ptab[i] = -1; + } + + /* alle L2-Ports durchgehen und initialisieren */ + for (i = 0; i < L2PNUM; ++i) + { + l1ptab[i] = -1; + CLR_L1MODE(i); + SET_L1MODE(i, MODE_off); + } + + strcpy(tnn_initfile, "tnn.ini"); + scanned = 1; + + /* Kommandozeilenparameter auswerten */ + while ((scanned < argc) && (!wrong_usage)) + { + /* Parameter "-i" (alternatives INI-File) */ + if (strcmp(argv[scanned], "-i") == 0) + { + scanned++; + if (scanned < argc) + { + strcpy(tnn_initfile, argv[scanned]); + } + else + wrong_usage = TRUE; + } + else if (strcmp(argv[scanned], "-v") != 0) + { + wrong_usage = TRUE; + } + scanned++; + } + + /* falsche / unbekannte Kommandozeilenparameter */ + if (wrong_usage) + { + printf("Usage : tnn [-i ] [-v]\n"); + return (TRUE); + } + + /* INI-File oeffnen */ + if (!(init_file_fp = fopen(tnn_initfile, "r"))) + { + warning = TRUE; + str_ptr = getenv("HOME"); + if (str_ptr != NULL) + { + sprintf(tmp_str, "%s/%s", str_ptr, tnn_initfile); + if ((init_file_fp = fopen(tmp_str, "r")) != NULL) + warning = FALSE; + } +#ifdef INIPATH + if (!init_file_fp) + { + sprintf(tmp_str, "%s/%s", INIPATH, tnn_initfile); + if ((init_file_fp = fopen(tmp_str, "r")) != NULL) + warning = FALSE; + } +#endif + } + + /* Datei nicht gefunden */ + if (warning) + { +#ifdef ATTACH + return(FALSE); +#else + printf("ERROR: %s not found\n\n", tnn_initfile); + Break(); + return (TRUE); +#endif /* ATTACH */ + } + + /* solange noch was im INI_File ist */ + while (!file_end) + { + /* eine Zeile einlesen */ + if (fgets(line, 82, init_file_fp) == NULL) + { + file_end = TRUE; + } + else + { + /* Zeile konnte nicht eingelesen werden */ + if (strlen(line) == 82) + { + file_end = TRUE; + file_corrupt = TRUE; + } + else + { + if (line[0] != '#') + { /* ignore comment-lines */ + rslt = sscanf(line, "%s %s", str1, str2); + switch (rslt) + { + case EOF: /* ignore blank lines */ + break; + case 2: + if (analyse_value(str1, str2)) /* Zeile analysieren */ + { + file_end = TRUE; + file_corrupt = TRUE; + } + break; + default: + file_end = TRUE; + file_corrupt = TRUE; + break; + } + } + } + } + } + fclose(init_file_fp); + + if (file_corrupt) + { + printf("ERROR: %s is in wrong format, wrong line:\n%s\n\n", tnn_initfile, line); + Break(); + return (TRUE); + } + else + { + for (i = 0; i < L1PNUM; i++) + { +#ifdef AX_IPX + if (l1port[i].kisstype == KISS_IPX) + { + if (axipx_ports == 0) + ++axipx_ports; + else + l1port[i].kisstype = KISS_NIX; + } +#endif +#ifdef AX25IP + if (l1port[i].kisstype == KISS_AXIP) + { + if (ax25ip_ports == 0) + ++ax25ip_ports; + else + l1port[i].kisstype = KISS_NIX; + } +#endif +#ifdef L1TELNET + if (l1port[i].kisstype == KISS_TELNET) + { + if (telnet_ports == 0) + ++telnet_ports; + else + l1port[i].kisstype = KISS_NIX; + } +#endif /* L1TELNET */ +#ifdef L1HTTPD + if (l1port[i].kisstype == KISS_HTTPD) + { + if (httpd_ports == 0) + ++httpd_ports; + else + l1port[i].kisstype = KISS_NIX; + } +#endif /* L1HTTPD */ +#ifdef L1IPCONV + if (l1port[i].kisstype == KISS_IPCONV) + { + if (ipconv_ports == 0) + ++ipconv_ports; + else + l1port[i].kisstype = KISS_NIX; + } +#endif /* L1IPCONV */ +#ifdef L1IRC + if (l1port[i].kisstype == KISS_IRC) + { + if (irc_ports == 0) + ++irc_ports; + else + l1port[i].kisstype = KISS_NIX; + } +#endif /* L1IRC */ + + if (*(l1port[i].tnn_lockfile) != NUL) + add_tnndir(l1port[i].tnn_lockfile); + } + add_tnndir(tnn_errfile); + + if (used_l1ports >= 0) + kiss_active = TRUE; + + /* externes Programm starten wenn gesetzt */ + if (start_name[0]) + system(start_name); + + return (FALSE); + } +} + +/* End of os/win32/init.c */ diff --git a/os/win32/l1attach.c b/os/win32/l1attach.c new file mode 100755 index 0000000..c1e7d0b --- /dev/null +++ b/os/win32/l1attach.c @@ -0,0 +1,1091 @@ +#include "tnn.h" + +static ULONG token_sent = 0L; + +/* Pruefen, ob KissType in der TBL gesetzt ist. */ +static BOOLEAN SearchKissType(UWORD Interface) +{ + register int i; + + /* Alle Ports durchgehen. */ + for (i = 0; i < L1PNUM; ++i) + /* KissType gleich. */ + if (l1port[i].kisstype == Interface) + /* Ja. */ + return(TRUE); + + /* Nein, */ + return(FALSE); +} + +#define ATT_PORT 1 +#define ATT_KISSTYPE 2 +#define ATT_SPEED 3 +#define ATT_DEVICE 4 + +ATTPRT attprt[] = { + {"PORT", ATT_PORT }, + {"KTYP", ATT_KISSTYPE }, + {"SPEED", ATT_SPEED }, + {"DEVICE", ATT_DEVICE }, + {NULL, 0 } +}; + +ATTTYP attyp[] = { + {"KISS", KISS_NORMAL }, + {"SMACK", KISS_SMACK }, + {"RMNC", KISS_RMNC }, + {"TOKENRING", KISS_TOK }, + {"VANESSA", KISS_VAN }, + {"SCC", KISS_SCC }, + {"TF", KISS_TF }, + {"IPX", KISS_IPX }, + {"AX25IP", KISS_AXIP }, + {"LOOP", KISS_LOOP }, + {"KAX25", KISS_KAX25 }, + {"KAX25KJD", KISS_KAX25KJD }, + {"6PACK", KISS_6PACK }, +#ifdef L1TELNET + {"TELNET", KISS_TELNET }, +#endif /* L1TELNET */ +#ifdef L1HTTPD + {"HTTPD", KISS_HTTPD }, +#endif /* L1HTTPD */ +#ifdef L1IPCONV + {"IPCONV", KISS_IPCONV }, +#endif /* L1IPCONV */ +#ifdef L1IRC + {"IRC", KISS_IRC }, +#endif /* L1IRC */ + {NULL, 0 } +}; + +#define ATT_NO_OPTION 0 +#define ATT_POR_BUSY 1 +#define ATT_INV_PORT 2 +#define ATT_INV_TYP 3 +#define ATT_KIS_BUSY 4 +#define ATT_SPE_BUSY 5 +#define ATT_INV_OPTION 6 +#define ATT_INV_UDP 7 +#define ATT_INV_TCP 8 + +static const char *errormsg[] = +{ + "No Option." + ,"Port is busy." + ,"Invalid Port." + ,"Invalid KissType." + ,"Kisstype is busy." + ,"Invalid Speed." + ,"Invalid Option." + ,"Invalid UDP-Port." + ,"Invalid TCP-Port." +}; + +/* KissType setzen. */ +int SetKissType(WORD Interface, int port) +{ + switch (Interface) + { + case KISS_NORMAL: + case KISS_SMACK: + case KISS_RMNC: + case KISS_TOK: + return(Interface); + + break; +#ifdef VANESSA + case KISS_VAN: + /* Testen ob es ueberhaupt eine Vanessa gibt. */ + if (!van_test(port)) + return(KISS_NIX); + + break; +#endif + case KISS_SCC: + case KISS_TF: + case KISS_KAX25: + case KISS_KAX25KJD: + case KISS_6PACK: + return(Interface); + + break; + + /* Pruefe auf Doppel-Eintraege! */ + case KISS_IPX: + case KISS_AXIP: + case KISS_LOOP: +#ifdef L1TELNET + case KISS_TELNET: +#endif /* L1TELNET */ +#ifdef L1HTTPD + case KISS_HTTPD: +#endif /* L1HTTPD */ +#ifdef L1IPCONV + case KISS_IPCONV: +#endif /* L1IPCONV */ +#ifdef L1IRC + case KISS_IRC: +#endif /* L1IRC */ + /* KissType schon gesetzt? */ + if (!SearchKissType(Interface)) + /* Nein, dann jetzt setzen. */ + return(Interface); + /* KissType existiert schon. */ + else + /* nicht setzen. */ + return(KISS_NIX); + + break; + + /* Unbekanntes KissType. */ + default: + /* nicht setzen. */ + return(KISS_NIX); + + break; + } + + return(KISS_NIX); +} + +/* Baudrate setzen. */ +int SetSpeed(char *speed, UWORD KissType) +{ + int Speed = EOF; + + /* Baudrate holen. */ + if ((sscanf(speed, "%d", &Speed) != 1)) + /* Fehler, abbruch. */ + return(EOF); + + /* Geschwindigkeit fuer Tokenring-Port */ + if (KissType == KISS_TOK) + /* Tokenring setzen. */ + tkcom = 1; + + switch(Speed) + { + case 0: + return(FALSE); + + case 9600: + if (KissType == KISS_TOK) + tkbaud = 96; + + return(B9600); + + case 19200: + if (KissType == KISS_TOK) + tkbaud = 192; + + return(B19200); + + case 38400: + if (KissType == KISS_TOK) + tkbaud = 384; + + return(B38400); + + case 57600: + if (KissType == KISS_TOK) + tkbaud = 576; + +#ifdef B57600 + return(B57600); +#else + return(B38400); +#endif + + case 115200: + if (KissType == KISS_TOK) + tkbaud = 1152; + +#ifdef B115200 + return(B115200); +#else + return(B38400); +#endif + + case 230400: + if (KissType == KISS_TOK) + tkbaud = 2304; + +#ifdef B230400 + return(B230400); +#else + return(B38400); +#endif + + case 460800: + if (KissType == KISS_TOK) + tkbaud = 4608; + +#ifdef B460800 + return(B460800); +#else + return(B38400); +#endif + + /* unbekannte Geschwindigkeiten */ + default: + return(EOF); + } + + return(EOF); +} + +/* Baudrateflags setzen. */ +int SetSpeedflag(char *speed) +{ + int Speed = EOF; + + /* Baudrate holen. */ + if ((sscanf(speed, "%d", &Speed) != 1)) + /* Fehler, abbruch. */ + return(EOF); + + switch(Speed) + { + + case 57600: + return(ASYNC_SPD_HI); + + case 115200: + return(ASYNC_SPD_VHI); + + case 230400: + return(ASYNC_SPD_SHI); + + case 460800: + return(ASYNC_SPD_WARP); + + /* unbekannte Geschwindigkeiten */ + default: + return(FALSE); + } + + return(FALSE); +} + +/* Buffer "clipoi" einlesen. */ +char *ReadBuf(char *cBuf, BOOLEAN flag) +{ + register int i; + skipsp(&clicnt, &clipoi); + + /* Frischer Buffer */ + memset(cBuf, 0, sizeof(cBuf)); + + for (i = 0; i < MAXPATH; ++i) + { + if ((!clicnt) || (*clipoi == ' ')) + break; + + if (*clipoi == '=') + { + clicnt--; + clipoi++; + break; + } + clicnt--; + /* TRUE, In Grossbuchstaben umwandeln. */ + if (flag) + cBuf[i] = toupper(*clipoi++); + /* FALSE. */ + else + /* keine Aenderungen durchfuehren. */ + cBuf[i] = (*clipoi++); + } + + cBuf[i] = 0; + + return(cBuf); +} + +/* Eine Modifizierte Funktion Init_kisslink(); */ +BOOLEAN InitKissLink(UWORD port) +{ + DEVICE *l1att = &l1port[l1ptab[port]]; + int Error = 0; + + switch(l1att->kisstype) + { + case KISS_TOK: + if (tokenring_ports > 1) + return(FALSE); + + /* Alle Device haben hier nix zu suchen. */ +#ifdef VANESSA + case KISS_VAN: +#endif + case KISS_SCC: + case KISS_IPX: + case KISS_AXIP: + case KISS_LOOP: + case KISS_KAX25: + case KISS_KAX25KJD: +#ifdef L1TELNET + case KISS_TELNET: +#endif /* L1TELNET */ +#ifdef L1HTTPD + case KISS_HTTPD: +#endif /* L1HTTPD */ +#ifdef L1IPCONV + case KISS_IPCONV: +#endif /* L1IPCONV */ +#ifdef L1IRC + case KISS_IRC: +#endif /* L1IRC */ + /* und weg hier. */ + return(FALSE); + +#ifdef SIXPACK + case KISS_6PACK: + /* 6PACK-Ring ist schon Initialisiert. */ + if (iDescriptor) + /* Schliesse schnittstelle. */ + CloseHandle((void *)iDescriptor); + + /* Neue Konfiguration Initialisieren. */ + Sixpack_l1init(); + + return(FALSE); +#endif /* SIXPACK */ + } + +/************************************************************************/ +/* */ +/* Port oeffnen. */ +/* */ +/************************************************************************/ + l1att->kisslink = open_win(l1att->device, l1att->speed); + + if (l1att->kisslink == KISS_NIX) + { + Error = 1; + printf("Error: can't open device %s\n", l1att->device); + printf(" (%s)\n", strerror(errno)); + } + +/************************************************************************/ +/* */ +/* Serielle Schnittstelle auf neue Parameter einstellen, KISS-Empfang */ +/* initialisieren */ +/* */ +/************************************************************************/ + if (!Error) + { + l1att->rx_state = ST_BEGIN; + l1att->rx_port = 0; + l1att->tx_port = 0; + + if (l1att->kisstype == KISS_TF) + tf_set_kiss(l1att); + } + +/************************************************************************/ +/* */ +/* Wenn kein Fehler aufgetreten ist, dann fuer gewisse Interfaces die */ +/* ersten Aktionen ausfuehren. */ +/* */ +/* Tokenring : Token senden */ +/* 6PACK : TNC-Zaehlung anstossen */ +/* */ +/************************************************************************/ + + if (!Error) + { + /* Tokenring */ + if (l1att->kisstype == KISS_TOK) + { + send_kisscmd(0xff, CMD_TOKEN, 0); /* Token senden */ + token_sent = tic10; /* Zeitpunkt der Sendung */ + tokenflag = FALSE; /* Token unterwegs */ + } + return(FALSE); + } + + if (Error) + { + /* Handle schliessen. */ + CloseHandle((void *)l1att->kisslink); + return(TRUE); + } + + /* Initialisierung war erfolgreich. */ + return(FALSE); +} + +/* Port setzen. */ +void ccpattach(void) +{ + MBHEAD *mbp; + ATTPRT *attcmd; + ATTTYP *attype; + char Buf[MAXPATH + 1]; + char *cBuf = Buf; + int port = EOF; + int error = ATT_NO_OPTION; + WORD found; + WORD att_kisstype = EOF; + WORD att_speed = EOF; + WORD att_speedflag= EOF; + char att_device[MAXPATH + 1]; + + /* Sysop will aendern und noch was in der Zeile da ? */ + if (issyso() && skipsp(&clicnt, &clipoi)) + { + memset(att_device, 0, sizeof(att_device)); + do + { + /* Gibt es einen Fehler? */ + if (error != ATT_NO_OPTION) + /* Abbruch. */ + break; + + /* Option einlesen. */ + cBuf = ReadBuf(cBuf, TRUE); + + /* Option in TBL suchen. */ + for (attcmd = attprt, found = 0; !found && attcmd->attstr != NULL; ++attcmd) + { + if (!strncmp(attcmd->attstr, cBuf, strlen(cBuf))) + /* Option gefunden. */ + found = attcmd->attnum; + } + + switch (found) + { + /* PORT. */ + case ATT_PORT: + skipsp(&clicnt, &clipoi); + + /* Port einlesen/pruefen. */ + if ((port = (nxtnum(&clicnt, &clipoi) & 0x7F)) < L2PNUM) + { + /* uninitialisierter Port */ + if (l1ptab[port] != -1) + /* Port ist belegt. */ + error = ATT_POR_BUSY; + } + /* Portangabe liegt ausserhalb vom Grenzbereichs. */ + else + /* Markiere Fehlermeldung. */ + error = ATT_INV_PORT; + + break; + + /* KISSTYPE setzen. */ + case ATT_KISSTYPE: + /* KissType einlesen. */ + cBuf = ReadBuf(cBuf, TRUE); + + /* KissType in TBL suchen. */ + for (attype = attyp, found = EOF; found == EOF && attype->attstr != NULL; ++attype) + { + if (!strncmp(attype->attstr, cBuf, strlen(cBuf))) + /* KissType gefunden. */ + found = attype->attnum; + } + + /* Unbekannte KissType. */ + if (found == EOF ) + { + /* Markiere Fehlermeldung. */ + error = ATT_INV_TYP; + break; + } + + /* Kisstype setzen. */ + if ((att_kisstype = SetKissType(found, port)) == EOF) + /* EOF, Markiere Fehlermeldung. */ + error = ATT_KIS_BUSY; + + break; + + /* Baudrate setzen. */ + case ATT_SPEED: + /* Baudrate einlesen. */ + cBuf = ReadBuf(cBuf, TRUE); + + /* Baudrate setzen. */ + if ((att_speed = SetSpeed(cBuf, att_kisstype)) == EOF) + /* EOF, Markiere Fehlermeldung. */ + error = ATT_SPE_BUSY; + + /* Baudrateflag setzen. */ + att_speedflag = SetSpeedflag(cBuf); + + break; + + /* Device setzen. */ + case ATT_DEVICE: + /* Device einlesen. */ + cBuf = ReadBuf(cBuf, FALSE); + + switch(att_kisstype) + { + case KISS_NORMAL: + case KISS_SMACK: + case KISS_RMNC: + case KISS_TOK: +#ifdef VANESSA + case KISS_VAN: +#endif + case KISS_SCC: + case KISS_TF: + case KISS_KAX25: + case KISS_KAX25KJD: + case KISS_6PACK: + strncpy(att_device, cBuf, MAXPATH); + break; + + + /* UDP-Port pruefen. */ + case KISS_AXIP: + if (atoi(cBuf) < 65536) + { + strncpy(att_device, cBuf, MAXPATH); + /* Neuen UDP-Port markieren. */ + my_udp = htons((unsigned short)atoi(cBuf)); + } + /* UDP-Port liegt ausserhalb vom Grenzbereich. */ + else + /* Markiere Fehlermeldung. */ + error = ATT_INV_UDP; + + break; + +#ifdef L1TELNET + /* TCP-Port pruefen. */ + case KISS_TELNET: + if (atoi(cBuf) < 65536) + strncpy(att_device, cBuf, MAXPATH); + /* TCP-Port liegt ausserhalb vom Grenzbereich. */ + else + /* Markiere Fehlermeldung. */ + error = ATT_INV_TCP; + + break; +#endif /* L1TELNET */ +#ifdef L1HTTPD + /* TCP-Port pruefen. */ + case KISS_HTTPD: + if (atoi(cBuf) < 65536) + strncpy(att_device, cBuf, MAXPATH); + /* TCP-Port liegt ausserhalb vom Grenzbereich. */ + else + /* Markiere Fehlermeldung. */ + error = ATT_INV_TCP; + + break; +#endif /* L1HTTPD */ +#ifdef L1IPCONV + /* TCP-Port pruefen. */ + case KISS_IPCONV: + if (atoi(cBuf) < 65536) + strncpy(att_device, cBuf, MAXPATH); + /* TCP-Port liegt ausserhalb vom Grenzbereich. */ + else + /* Markiere Fehlermeldung. */ + error = ATT_INV_TCP; + + break; +#endif /* L1IPCONV */ +#ifdef L1IRC + /* TCP-Port pruefen. */ + case KISS_IRC: + if (atoi(cBuf) < 65536) + strncpy(att_device, cBuf, MAXPATH); + /* TCP-Port liegt ausserhalb vom Grenzbereich. */ + else + /* Markiere Fehlermeldung. */ + error = ATT_INV_TCP; + + break; +#endif /* L1IRC */ + } + + case KISS_LOOP: + break; + + default: + /* Unbekannte Option. */ + error = ATT_INV_OPTION; + break; + } + } + /* Gibt es noch Zeichen. */ + while (clicnt > 0); + } + /* Kein Sysop. */ + else + { + if (!issyso()) + invmsg(); + else + { + DEVICE *l1att; + + mbp = putals("ATTACH-TABLES:\rPort--KISSTYPE---DEVICE\r"); + + /* alle Ports durchgehen */ + for (port = 0; port < L2PNUM; ++port) + { + /* uninitialisierter Port */ + if (l1ptab[port] == -1) + { + putprintf(mbp, "%2d Port deaktiv.\r", port); + continue; + } + + l1att = &l1port[l1ptab[port]]; + + for (attype = attyp; attype->attstr != NULL; ++attype) + if (l1att->kisstype == attype->attnum) + break; + + putprintf(mbp, "%2d %-10s " + , port + , attype->attstr); + + switch(l1att->kisstype) + { + case KISS_AXIP: + putprintf(mbp, "%u" ,ntohs(my_udp)); + break; + +#ifdef L1TELNET + case KISS_TELNET: + putprintf(mbp, "%d" , atoi(l1att->device)); + break; +#endif /* L1TELNET */ +#ifdef L1HTTPD + case KISS_HTTPD: + putprintf(mbp, "%d" , atoi(l1att->device)); + break; +#endif /* L1HTTPD */ +#ifdef L1IPCONV + case KISS_IPCONV: + putprintf(mbp, "%d" , atoi(l1att->device)); + break; +#endif /* L1IPCONV */ +#ifdef L1IRC + case KISS_IRC: + putprintf(mbp, "%d" , atoi(l1att->device)); + break; +#endif /* L1IRC */ + + default: + putprintf(mbp, "%-5s" ,l1att->device); + break; + } + putstr("\r", mbp); + + + } + /* und ab geht die Post. */ + prompt(mbp); + seteom(mbp); + } + return; + } + + /* Kisstype Tokenring. */ + if ( (att_kisstype == KISS_TOK) + /* Ja, dann zaehlen wir. */ + &&(++tokenring_ports)) + { + /* Sonderbehandlung fuer Tokenring-Ports */ + if (att_kisstype == KISS_TOK) + { + l1ptab[port] = 0; + l2ptab[max_device] = -1; + } + } + /* Kein Tokenring. */ +#ifdef SIXPACK + /* Sonderbehandlung fuer 6PACK-Ports */ + if ( (att_kisstype == KISS_6PACK) + &&(++sixpack_ports)) + { + /* Sonderbehandlung fuer Tokenring-Ports */ + if (att_kisstype == KISS_6PACK) + { + l1ptab[port] = max_device; + l2ptab[max_device] = -1; + } + } +#endif + + /* Sind alle Einstellungen korrekt? */ + if ( (port == EOF) + /* Pruefen ob Kisstype */ + ||(att_kisstype == EOF) + /* und Device korrekt gesetzt sind. */ + ||((att_device[0] == FALSE) + &&(att_kisstype != KISS_AXIP) + &&(att_kisstype != KISS_LOOP))) + { + mbp = getmbp(); + + /* Fehlermeldung ausgeben mit Syntax. */ + putprintf(mbp, "%s\r", errormsg[error]); + putstr("Syntax: ATT PORT=X KTYP=KISSTYPE SPEED=19200 DEVICE=SCHNITTSTELLE\r", mbp); + prompt(mbp); + seteom(mbp); + return; + } + /* Kisstype/Device sind OK. */ + else + { + /* Port auf aktiv stellen. */ + l1port[++max_device].port_active = TRUE; + /* Kisstype setzen. */ + l1port[max_device].kisstype = att_kisstype; + /* Baudrateflag setzen. */ + l1port[max_device].speedflag = att_speedflag; + /* Baudrate setzen. */ + l1port[max_device].speed = att_speed; + /* Device setzen. */ + strcpy(l1port[max_device].device, att_device); + + /* Port markieren. */ + l1ptab[port] = max_device; + l2ptab[max_device] = port; + + /* Zaehler L1Ports. */ + ++used_l1ports; + /* Kiss aktivieren. */ + kiss_active = TRUE; + + /* Serielle Schnittstellen initialisieren */ + if (InitKissLink((UWORD)port)) + { + /* Es gab ein Fehler bei der Initialisierung. */ + /* Alle Werte zuruecksetzen. */ + l1port[max_device].port_active = FALSE; + l1port[max_device].kisstype = KISS_NIX; + l1port[max_device].speedflag = 0; + l1port[max_device].speed = 0; + l1port[max_device].device[0] = 0; + + l1ptab[port] = EOF; + l2ptab[port] = EOF; + --max_device; + --used_l1ports; + + mbp = getmbp(); + + putstr("Error with initializing the interface\r", mbp); + prompt(mbp); + seteom(mbp); + return; + } + } + + mbp = getmbp(); + + putprintf(mbp, "Port %d Attached.\r", port); + prompt(mbp); + seteom(mbp); +} + +/* Port entladen. */ +void ccpdetach(void) +{ + MBHEAD *mbp; + DEVICE *l1att; + int port; + + /* Sysop will aendern und noch was in der Zeile da ? */ + if (issyso() && skipsp(&clicnt, &clipoi)) + { + /* Port einlesen/pruefen. */ + if ((port = (nxtnum(&clicnt, &clipoi) & 0x7F)) < L2PNUM) + { + /* uninitialisierter Port */ + if (l1ptab[port] == EOF) + { + mbp = getmbp(); + putprintf(mbp, "Port %d is no activ.\r", port); + prompt(mbp); + seteom(mbp); + return; + } + /* Port eingeschaltet. */ + if (portenabled(port)) + /* Port runterfahren. */ + l1detach(port); + + l1att = &l1port[l1ptab[port]]; + /* Schliesse Schnittstelle. */ + switch(l1att->kisstype) + { + case KISS_TOK: + /* Schnittstelle schliessen. */ + CloseHandle((void *)l1att->kisslink); + + /* Port's zuruecksetzen. */ + tokenring_ports = 0; + break; + + case KISS_NORMAL: + case KISS_SMACK: + case KISS_RMNC: + case KISS_TF: + CloseHandle((void *)l1att->kisslink); + + break; + + +#ifdef SIXPACK + case KISS_6PACK: + /* 6PACK-Schnittstelle schliessen. */ + Sixpack_l1exit(); + + /* Port's zuruecksetzen. */ + sixpack_ports = 0; + break; +#endif /* SIXPACK */ + + + case KISS_AXIP: + case KISS_KAX25: + case KISS_KAX25KJD: +#ifdef L1TELNET + case KISS_TELNET: +#endif /* L1TELNET */ +#ifdef L1HTTPD + case KISS_HTTPD: +#endif /* L1HTTPD */ +#ifdef L1IPCONV + case KISS_IPCONV: +#endif /* L1IPCONV */ +#ifdef L1IRC + case KISS_IRC: +#endif /* L1IRC */ + close(l1att->kisslink); + break; + + + default: + break; + + } + + /* Defaultwerte setzen. */ + l1att->port_active = FALSE; + l1att->kisstype = KISS_NIX; + l1att->speed = 0; + l1att->device[0] = 0; + + l1ptab[port] = EOF; + l2ptab[port] = EOF; + + mbp = getmbp(); + putprintf(mbp, "Port %d Detach.\r", port); + prompt(mbp); + seteom(mbp); + return; + } + /* Ungueltiger Port. */ + else + { + mbp = getmbp(); + putstr("Invalid Port.\r", mbp); + prompt(mbp); + seteom(mbp); + return; + } + } + else + { /* Sysop ? */ + if (!issyso()) + invmsg(); + /* Portangabe fehlt.*/ + else + { + mbp = getmbp(); + + putstr("Port failed.\r", mbp); + prompt(mbp); + seteom(mbp); + } + } +} +/* Speed einlesen fuer tnb. */ +int ReadSpeed(unsigned int Speed) +{ + switch(Speed) + { + case 0: + return(FALSE); + + case B9600: + return(9600); + + case B19200: + return(19200); + + case B38400: + return(38400); + + case B57600: +#ifdef B57600 + return(57600); +#else + return(38400); +#endif + +#ifdef B115200 + case B115200: + return(115200); +#else + return(38400); +#endif + case 230400: +#ifdef B230400 + return(230400); +#else + return(38400); +#endif + + case 460800: +#ifdef B460800 + return(460800); +#else + return(38400); +#endif + + /* unbekannte Geschwindigkeiten */ + default: + return(FALSE); + } + return(FALSE); +} + +/* Attach-Eintraege in tnb sichern. */ +void dump_attach(MBHEAD *mbp) +{ + DEVICE *l1pp; + int port; +#define TELNET 0 +#define HTTPD 1 +#define IPCONV 2 + + putstr(";\r; Attach (l1-Level)\r;\r", mbp); + + /* alle Ports durchgehen */ + for (port = 0; port < L2PNUM; ++port) + { + /* uninitialisierter Port */ + if (l1ptab[port] == -1) + continue; + + l1pp = &l1port[l1ptab[port]]; + + putprintf(mbp, "ATTACH PORT=%d ", port); + + switch(l1pp->kisstype) + { + case KISS_NORMAL: + putprintf(mbp, "KTYP=KISS SPEED=%d DEVICE=%s" + , ReadSpeed(l1pp->speed) + , l1pp->device); + break; + + case KISS_SMACK: + putprintf(mbp, "KTYP=SMACK SPEED=%d DEVICE=%s" + , ReadSpeed(l1pp->speed) + , l1pp->device); + break; + + case KISS_RMNC: + putprintf(mbp, "KTYP=RMNC SPEED=%d DEVICE=%s" + , ReadSpeed(l1pp->speed) + , l1pp->device); + break; + + case KISS_TOK: + putprintf(mbp, "KTYP=TOKENRING SPEED=%d DEVICE=%s" + , ReadSpeed(l1pp->speed) + , l1pp->device); + break; + + case KISS_SCC: + putprintf(mbp, "KTYP=SCC DEVIVE=%s" + , l1pp->device); + break; + + case KISS_TF: + putprintf(mbp, "KTYP=TF SPEED=%d DEVICE=%s" + , ReadSpeed(l1pp->speed) + , l1pp->device); + break; + + case KISS_IPX: + putprintf(mbp, "KTYP=IPX"); + break; + + case KISS_AXIP: + putstr("KTYP=AX25IP ", mbp); + if (l1pp->device) + putprintf(mbp, "DEVICE=%d" + , ntohs(my_udp)); + else + putstr("DEVICE=", mbp); + break; + + case KISS_LOOP: + putprintf(mbp, "KTYP=LOOP"); + break; + + case KISS_KAX25: + putprintf(mbp, "KTYP=KAX25 DEVICE=%s" + , l1pp->device); + break; + + case KISS_KAX25KJD: + putprintf(mbp, "KTYP=KAX25DJK DEVICE=%s" + , l1pp->device); + break; + + case KISS_6PACK: + putprintf(mbp, "KTYP=6PACK SPEED=%d DEVICE=%s" + , ReadSpeed(l1pp->speed) + , l1pp->device); + break; + +#ifdef L1TELNET + case KISS_TELNET: + putprintf(mbp, "KTYP=TELNET DEVICE=%d" + , atoi(l1pp->device)); + break; +#endif /* L1TELNET */ +#ifdef L1HTTPD + case KISS_HTTPD: + putprintf(mbp, "KTYP=HTTPD DEVICE=%d" + , atoi(l1pp->device)); + break; +#endif /* L1HTTPD */ +#ifdef L1IPCONV + case KISS_IPCONV: + putprintf(mbp, "KTYP=IPCONV DEVICE=%d" + , atoi(l1pp->device)); + break; +#endif /* L1IPCONV */ +#ifdef L1IRC + case KISS_IRC: + putprintf(mbp, "KTYP=IRC DEVICE=%d" + , atoi(l1pp->device)); + break; +#endif /* L1IRC */ + } + putstr("\n", mbp); + } +} + +/* End of os/win32/l1attach.c */ diff --git a/os/win32/l1win32.c b/os/win32/l1win32.c new file mode 100755 index 0000000..2529f06 --- /dev/null +++ b/os/win32/l1win32.c @@ -0,0 +1,2389 @@ +/************************************************************************/ +/* */ +/* ***** ***** */ +/* ***** ***** */ +/* ***** ***** */ +/* ***** ***** */ +/* *************** *************** */ +/* ***************** ***************** */ +/* *************** *************** */ +/* ***** ***** TheNetNode */ +/* ***** ***** Portable */ +/* ***** ***** Network */ +/* ***** ***** Software */ +/* */ +/* File os/win32/l1win32.c (maintained by: DF6LN) */ +/* */ +/* This file is part of "TheNetNode" - Software Package */ +/* */ +/* Copyright (C) 1998 - 2008 NORD>device) == 0) + { + check_van = TRUE; + l1pp->kisstype = KISS_VAN; /* falls Kisstype nicht angegeben */ + if (i == max_device) + break; + else + continue; + } +#endif + +/************************************************************************/ +/* */ +/* Wenn IPX, auch naechsten Port. */ +/* */ +/************************************************************************/ + +#ifdef AX_IPX + if (stricmp("IPX", l1pp->device) == 0) + { + l1pp->kisstype = KISS_IPX; /* falls Kisstype nicht angegeben */ + l1pp->port_active = TRUE; + if (i == max_device) + break; + else + continue; + } +#endif + +/************************************************************************/ +/* */ +/* Wenn AX25IP, auch naechsten Port. */ +/* */ +/************************************************************************/ + +#ifdef AX25IP + if (stricmp("AX25IP", l1pp->device) == 0) + { + l1pp->kisstype = KISS_AXIP; /* falls Kisstype nicht angegeben */ + l1pp->port_active = TRUE; + if (i == max_device) + break; + else + continue; + } +#endif + +/************************************************************************/ +/* */ +/* Kernel-AX25 hat hier auch nix zu suchen */ +/* */ +/************************************************************************/ +#ifdef KERNELIF + if ( (l1pp->kisstype == KISS_KAX25) + || (l1pp->kisstype == KISS_KAX25KJD)) + { + l1pp->port_active = TRUE; + if (i == max_device) + break; + else + continue; + } +#endif + +/************************************************************************/ +/* */ +/* 6PACK hat hier auch nix zu suchen */ +/* */ +/************************************************************************/ +#ifdef SIXPACK + if (l1pp->kisstype == KISS_6PACK) + { + l1pp->port_active = TRUE; + if (i == max_device) + break; + else + continue; + } +#endif + +#ifdef L1TELNET +/************************************************************************/ +/* */ +/* Wenn TELNET, auch naechsten Port. */ +/* */ +/************************************************************************/ + + if (l1pp->kisstype == KISS_TELNET) + { + int TCPPort = atoi(l1pp->device); + + if ( (TCPPort < 1) + ||(TCPPort > 65536)) + { + printf("Warnung: Alte Syntax device %s ungueltig!!!\n" + " Neue Syntax device 1..65535.\n" + "TCP-Port wird auf default 10023 gesetzt.\n" + "Aenderung in der TNN.INI vornehmen!\n", l1pp->device); + strncpy(l1pp->device, "10023", MAXPATH); + Break(); + } + else + { + l1pp->port_active = TRUE; + } + + if (i == max_device) + break; + else + continue; + } +#endif /* L1TELNET */ + +#ifdef L1HTTPD +/************************************************************************/ +/* */ +/* Wenn HTTPD, auch naechsten Port. */ +/* */ +/************************************************************************/ + + if (l1pp->kisstype == KISS_HTTPD) + { + int TCPPort = atoi(l1pp->device); + + if ( (TCPPort < 1) + ||(TCPPort > 65536)) + { + printf("Warnung: Alte Syntax device %s ungueltig!!!\n" + " Neue Syntax device 1..65535.\n" + "TCP-Port wird auf default 18080 gesetzt.\n" + "Aenderung in der TNN.INI vornehmen!\n", l1pp->device); + strncpy(l1pp->device, "18080", MAXPATH); + Break(); + } + else + l1pp->port_active = TRUE; + + if (i == max_device) + break; + else + continue; + } +#endif /* L1HTTPD */ + +#ifdef L1IPCONV +/************************************************************************/ +/* */ +/* Wenn IPCONV, auch naechsten Port. */ +/* */ +/************************************************************************/ + + if (l1pp->kisstype == KISS_IPCONV) + { + int TCPPort = atoi(l1pp->device); + + if ( (TCPPort < 1) + ||(TCPPort > 65536)) + { + printf("Warnung: Alte Syntax device %s ungueltig!!!\n" + " Neue Syntax device 1..65535.\n" + "TCP-Port wird auf default 13600 gesetzt.\n" + "Aenderung in der TNN.INI vornehmen!\n", l1pp->device); + strncpy(l1pp->device, "13600", MAXPATH); + Break(); + } + else + l1pp->port_active = TRUE; + + if (i == max_device) + break; + else + continue; + } +#endif /* L1IPCONV */ + +#ifdef L1IRC +/************************************************************************/ +/* */ +/* Wenn IRC, auch naechsten Port. */ +/* */ +/************************************************************************/ + + if (l1pp->kisstype == KISS_IRC) + { + int TCPPort = atoi(l1pp->device); + + if ( (TCPPort < 1) + ||(TCPPort > 65536)) + { + printf("Warnung: Alte Syntax device %s ungueltig!!!\n" + " Neue Syntax device 1..65535.\n" + "TCP-Port wird auf default 13601 gesetzt.\n" + "Aenderung in der TNN.INI vornehmen!\n", l1pp->device); + strncpy(l1pp->device, "13601", MAXPATH); + Break(); + } + else + l1pp->port_active = TRUE; + + if (i == max_device) + break; + else + continue; + } +#endif /* L1IRC */ + +/************************************************************************/ +/* */ +/* Port oeffnen. */ +/* */ +/************************************************************************/ + + if (fehler == 0) /* nur wenn Lock-File geschrieben */ + { /* wurde oder nicht gefordert war */ + l1pp->kisslink = open_win(l1pp->device, l1pp->speed); + + if (l1pp->kisslink == -1) + { + fehler = 2; + printf("Error: can't open device %s\n", l1pp->device); + printf(" (%s)\n", strerror(errno)); + } + } + +/************************************************************************/ +/* */ +/* Serielle Schnittstelle auf neue Parameter einstellen, KISS-Empfang */ +/* initialisieren */ +/* */ +/************************************************************************/ + + if (fehler == 0) + { + l1pp->rx_state = ST_BEGIN; + l1pp->rx_port = 0; + l1pp->tx_port = 0; + l1pp->port_active = TRUE; + + if (l1pp->kisstype == KISS_TF) + tf_set_kiss(l1pp); + } + else + break; + if (i == max_device) + break; + } + +/************************************************************************/ +/* */ +/* Wenn kein Fehler aufgetreten ist, dann fuer gewisse Interfaces die */ +/* ersten Aktionen ausfuehren. */ +/* */ +/* Tokenring : Token senden */ +/* 6PACK : TNC-Zaehlung anstossen */ +/* */ +/************************************************************************/ + + if (fehler == 0) + { + /* Tokenring */ + if (l1port[0].kisstype == KISS_TOK) + { + send_kisscmd(0xff, CMD_TOKEN, 0); /* Token senden */ + token_sent = tic10; /* Zeitpunkt der Sendung */ + tokenflag = FALSE; /* Token unterwegs */ + } + return(FALSE); + } + +/************************************************************************/ +/* */ +/* Wenn bei einem Teil der Initialisierung ein Fehler aufgetreten ist, */ +/* muessen alle bisher vorgenommenen Parameteraenderungen der seriellen */ +/* Schnittstellen rueckgaengig gemacht werden. Ausserdem muessen alle */ +/* geoeffneten Files wieder geschlossen werden. */ +/* */ +/************************************************************************/ + + do + { + /* Port war schon offen, aber noch nicht veraendert, nur schliessen */ + if ((fehler > 2) && (l1port[i].kisslink != -1)) + { + CloseHandle((void *)l1port[i].kisslink); + l1port[i].kisslink = -1; + } + + fehler = 4; /* beim naechsten Durchgang alles restaurieren */ + } while (--i >= 0); + + return(TRUE); +} + +/************************************************************************/ +/* */ +/* Serielle Schnittstellen wieder freigeben (fuer Programmende) */ +/* */ +/************************************************************************/ + +void exit_kisslink(void) +{ + register WORD i; + char buffer[] = { (char)FEND, (char)0xFF }; + + for (i = 0; i < L1PNUM; ++i) + { + /* abgeschaltete Ports */ + if (!l1port[i].port_active) + continue; +#ifdef AX_IPX + /* AX_IPX */ + if (l1port[i].kisstype > KISS_IPX) + continue; +#endif +#ifdef KERNELIF + /* Kernel-AX.25 */ + if ( (l1port[i].kisstype == KISS_KAX25) + || (l1port[i].kisstype == KISS_KAX25KJD)) + continue; +#endif +#ifdef AX25IP + /* AX25IP */ + if (l1port[i].kisstype == KISS_AXIP) + continue; +#endif +#ifdef VANESSA + if (l1port[i].kisstype == KISS_VAN) + continue; +#endif +#ifdef SIXPACK + /* 6PACK */ + if (l1port[i].kisstype == KISS_6PACK) + continue; +#endif +#ifdef L1TELNET + /* TELNET-Server */ + if (l1port[i].kisstype == KISS_TELNET) + continue; +#endif /* L1TELNET */ +#ifdef L1HTTPD + /* HTTPD-Server */ + if (l1port[i].kisstype == KISS_HTTPD) + continue; +#endif /* L1HTTPD */ +#ifdef L1IPCONV + /* IPCONV-Server */ + if (l1port[i].kisstype == KISS_IPCONV) + continue; +#endif /* L1IPCONV */ +#ifdef L1IRC + /* IRC-Server */ + if (l1port[i].kisstype == KISS_IRC) + continue; +#endif /* L1IRC */ + + /* TNC mit TheFirmware */ + if (l1port[i].kisstype == KISS_TF) + { + /* KISS-Kommando senden (TNC-Reset) */ + write(l1port[i].kisslink, buffer, 2); + sleep(1); + } + + CloseHandle((void *)l1port[i].kisslink); + /* Lockfile loeschen */ + if (*(l1port[i].tnn_lockfile) != '\0') + unlink(l1port[i].tnn_lockfile); + /* alle Devices bearbeitet ? */ + if (i == max_device) + break; + } + kiss_active = FALSE; +} + +/************************************************************************/ +/* */ +/* Level1 Ende, Ports schliessen und aufraeumen */ +/* */ +/************************************************************************/ + +void l1exit(void) +{ +#ifdef KERNELIF + /* Kernel-AX.25 */ + register unsigned int i; + + for (i = 0;i < L1PNUM; ++i) + if ( (l1port[i].kisstype == KISS_KAX25) + || (l1port[i].kisstype == KISS_KAX25KJD)) + ifax_close(&(l1port[i])); +#endif + /* KISS-Schnittstellen */ + if (kiss_active) + exit_kisslink(); +#ifdef VANESSA + /* Vanessa */ + vanessa_l1exit(); +#endif +#ifdef AX_IPX + /* AX25IPX */ + axipx_l1exit(); +#endif +#ifdef AX25IP + /* AX25IP */ + ax25ip_l1exit(); +#endif +#ifdef SIXPACK + /* 6PACK */ + Sixpack_l1exit(); +#endif +#ifdef L1TELNET + /* TCPIP-Interface schliessen. */ + L1ExitTCP(KISS_TELNET); +#endif /* L1TELNET */ +#ifdef L1HTTPD + /* TCPIP-Interface schliessen. */ + L1ExitTCP(KISS_HTTPD); +#endif /* L1HTTPD */ +#ifdef L1IPCONV + /* TCPIP-Interface schliessen. */ + L1ExitTCP(KISS_IPCONV); +#endif /* L1IPCONV */ +#ifdef L1IRC + /* TCPIP-Interface schliessen. */ + L1ExitTCP(KISS_IRC); +#endif /* L1IRC */ +} + + +/************************************************************************/ +/* */ +/* Level1 Timer */ +/* Watchdog-Timer fuer die einzelnen L2-Ports */ +/* */ +/************************************************************************/ + +void l1timr(UWORD ticks) +{ + register unsigned int i; + + if ((tic1m += ticks) > 6000) /* alle Minute */ + { + tic1m -= 6000; + /* Statistik fuer den Tokenring */ + token_pro_sec = (token_count / 60L); + + if ( (token_max_sec != 0) + && (token_min_sec != 0)) + { + token_max_sec = max(token_pro_sec, token_max_sec); + token_min_sec = min(token_pro_sec, token_min_sec); + } + else + token_min_sec = token_max_sec = token_pro_sec; + + token_count = 0L; + } + + /* DCD (TX) fuer die Tokenring-Ports checken */ + for (i = 0; i < L2PNUM; ++i) + if (wd_timer[i] < ticks) + { + wd_timer[i] = WATCHDOG_TIMEOUT; + portpar[i].reset_port = TRUE; + } +} + +/************************************************************************/ +/* */ +/* Level1 RX/TX */ +/* wird staendig in der main() Hauptschleife aufgerufen. */ +/* */ +/************************************************************************/ + +void l1rxtx(void) +{ + register UBYTE i; + DEVICE *l1pp; + +#ifdef VANESSA + if (found_vanessa != 0) + vanessa(); +#endif +#ifdef AX_IPX + axipx(); +#endif +#ifdef AX25IP + ax25ip(); +#endif +#ifdef KERNELIF + ifax_housekeeping(); +#endif +#ifdef SIXPACK + Sixpack_Housekeeping(); +#endif + + ++rounds_count; /* Anzahl der Hauptschleifendurchlaeufe */ +#ifdef LOOPBACK + /* Loopback-Funktionalitaet */ + loopback(); +#endif + + /* alle Ports durchgehen */ + for (i = 0; i < L2PNUM; ++i) + { + /* uninitialisierter Port */ + if (l1ptab[i] == -1) + continue; + /* deaktivierter Port */ + if (!portenabled(i)) + continue; + l1pp = &l1port[l1ptab[i]]; + /* Tokenring darf nur senden, wenn wir das Token haben */ + if ( (l1pp->kisstype == KISS_TOK) /* Wenn Token noch unterwegs, */ + && (tokenflag == FALSE)) /* nicht senden! */ + continue; + +#ifdef AX_IPX + if (l1pp->kisstype == KISS_IPX) + continue; +#endif +#ifdef AX25IP + if (l1pp->kisstype == KISS_AXIP) + continue; +#endif +#ifdef VANESSA + if (l1pp->kisstype == KISS_VAN) + continue; +#endif +#ifdef KERNELIF + if ( (l1pp->kisstype == KISS_KAX25) + || (l1pp->kisstype == KISS_KAX25KJD)) + continue; +#endif +#ifdef SIXPACK + if (l1pp->kisstype == KISS_6PACK) + continue; +#endif +#ifdef L1TELNET + if (l1pp->kisstype == KISS_TELNET) + continue; +#endif /* L1TELNET */ +#ifdef L1HTTPD + if (l1pp->kisstype == KISS_HTTPD) + continue; +#endif /* L1HTTPD */ +#ifdef L1IPCONV + if (l1pp->kisstype == KISS_IPCONV) + continue; +#endif /* L1IPCONV */ +#ifdef L1IRC + if (l1pp->kisstype == KISS_IRC) + continue; +#endif /* L1IRC */ + +/************************************************************************/ +/* */ +/* Nicht-Tokenring-TNCs konfigurieren, falls notwendig */ +/* */ +/************************************************************************/ + + if (commandflag[i]) /* TNC konfigurieren */ + config_tnc(i); + +/************************************************************************/ +/* */ +/* Tokenring ist frei - oder SMACK-/KISS-Link */ +/* */ +/************************************************************************/ + if (kick[i]) /* Es soll auf diesem Port gesendet werden */ + { + kissframe_to_tnc(i, FALSE); /* Alles fuer diesen Port senden */ + cd_timer[i] = tic10; /* Wir senden, Belegt-Timer starten */ + } + } + if (l1port[0].kisstype != KISS_TOK) /* kein Tokenring da? */ + return; + +/************************************************************************/ +/* */ +/* Tokenring ueberwachen - wenn Token empfangen, ggf. neue Daten senden */ +/* oder TNC(s) resetten bzw. konfigurieren. Wenn zu lange kein Token */ +/* angekommen, Verlust des Token annehmen und neues Token generieren. */ +/* */ +/************************************************************************/ + + if (tokenflag == FALSE) /* nichts gekommen? */ + { + if (tic10 > (token_sent + TOKENTIMEOUT)) /* noch einmal warten.. */ + { + if (++lost_token >= 150) /* zu viele Token-Recoveries */ + HALT("Tokenring"); + + l1port[0].rx_state = ST_BEGIN; /* auf FEND warten */ + send_kisscmd(0xff, CMD_TOKEN, 0); /* Token senden */ + token_sent = tic10; /* nix gekommen... */ + ++recovery_count; /* fuer die Statistik */ + + for (i = 0; i < L2PNUM; ++i) /* ggf neue Parameter an TNC */ + { + if ( portenabled(i) + && (kissmode(i) == KISS_TOK)) + { + commandflag[i] = TRUE; /* Portparameter neu einstellen */ + kissframe_to_tnc(i, TRUE); /* zur Sicherheit bei Recovery */ + } /* Restframes loeschen */ + } + + if (show_recovery == TRUE) + { + notify(1, "*** Token-Recovery (%lu)", lost_token); + if (!blicnt) + xprintf("*** Token-Recovery (%lu)\n", lost_token); + } + } + } + else /* Token ist angekommen */ + { + for (i = 0; i < L2PNUM; ++i) + { + if (l1ptab[i] == -1) /* Port uninitialisiert */ + continue; + if (!portenabled(i)) /* Port ist aus */ + continue; + l1pp = &l1port[l1ptab[i]]; + if (l1pp->kisstype != KISS_TOK) /* nicht Tokenring */ + continue; + if (portpar[i].reset_port == TRUE) /* diesen Port resetten?*/ + { + send_kisscmd(i, CMD_TNCRES, 0); + portpar[i].reset_port = FALSE; + commandflag[i] = TRUE; /* nach Reset TNC konfigurieren */ + break; /* nur 1 RESET/Token, mehr */ + } /* kommt evtl. nicht durch, da */ + } /* TNC taub ist nach RESET */ + + send_kisscmd(0xff, CMD_TOKEN, 0); /* Token senden */ + token_sent = tic10; + tokenflag = FALSE; + lost_token = 0; + } +} + +/************************************************************************/ +/* */ +/* Loopback-Ports bearbeiten */ +/* */ +/************************************************************************/ +#ifdef LOOPBACK +static void loopback(void) +{ + LHEAD *l2flp; + MBHEAD *txfhd; + MBHEAD *rxfhd; + register int port; + int rxport; + + l2flp = txl2fl; + + for (port = 0; port < L2PNUM; l2flp++, port++)/* jeden Port durchlaufen */ + { + if (kissmode(port) == KISS_LOOP) + { +/* wenn zwei L2-Ports mit aufeinanderfolgender Nummer (um genau zu sein */ +/* ein Port mit gerader Nummer und der mit der naechsthoeheren Nummer) */ +/* auf LOOP gesetzt sind, auf den Nachbarport senden; andernfalls auf */ +/* Sendeport */ + rxport = port ^ 1; + if ( !portenabled(rxport) + || (kissmode(rxport) != KISS_LOOP)) + rxport = port; + + while (kick[port]) /* was zum senden... */ + { + ulink((LEHEAD *)(txfhd = (MBHEAD *) l2flp->head)); + rxfhd = (MBHEAD *) allocb(ALLOC_MBHEAD); + + rxfhd->l2port = rxport; + while (txfhd->mbpc > txfhd->mbgc) + putchr(getchr(txfhd), rxfhd); + relink((LEHEAD *)rxfhd, (LEHEAD *)rxfl.tail); /* in Rx-Liste */ + relink((LEHEAD *)txfhd, (LEHEAD *)stfl.tail); /* Frame gesendet */ + kick[port] = ((LHEAD *)l2flp->head != l2flp); + } + } + } +} +#endif + +/************************************************************************/ +/* */ +/* TNC gemaess Port-Parametern konfigurieren */ +/* */ +/************************************************************************/ + +static void config_tnc(int l2port) +{ + PORTINFO *ppp; + DEVICE *l1pp; + + l1pp = &l1port[l1ptab[l2port]]; + ppp = &portpar[l2port]; + + if ( (l1pp->kisstype != KISS_TOK) /* DAMA geht nur mit Tokenring */ + && (l1pp->kisstype != KISS_VAN)) /* oder Vanessa */ + ppp->l2mode &= ~MODE_a; + + if ( (l1pp->kisstype == KISS_TOK) /* Tokenring aber Token noch */ + && (tokenflag == FALSE)) /* unterwegs? -> beim naechsten */ + return; /* Durchgang nochmal probieren */ + + send_kisscmd(l2port, CMD_TXDELAY, ppp->txdelay); + + /* Persistance je nach DAMA einstellen */ + if (dama(l2port)) + send_kisscmd(l2port, CMD_PERSIST, 255); + else + send_kisscmd(l2port, CMD_PERSIST, ppp->persistance); + + send_kisscmd(l2port, CMD_SLOTTIME, ppp->slottime); + send_kisscmd(l2port, CMD_TXTAIL, TAILTIME); + send_kisscmd(l2port, CMD_FULLDUP, fullduplex(l2port) ? 1 : 0); + send_kisscmd(l2port, CMD_DAMA, (dama(l2port)) ? 1 : 0); + commandflag[l2port] = FALSE; +} + +/************************************************************************/ +/* */ +/* Level1 Control */ +/* eine Aktion fuer einen Hardware-Port anfordern */ +/* */ +/************************************************************************/ + +void l1ctl(int req, int port) +{ + /* je nach Request die notwendigen Aktionen bestimmen */ + switch (req) + { + /* Port resetten */ + case L1CRES: portpar[port].reset_port = TRUE; + break; + /* Parameter zum Port bringen */ + case L1CCMD: commandflag[port] = TRUE; + break; + /* Testsignal senden */ + case L1CTST: testflag[port] = TRUE; + kick[port] = TRUE; + break; + /* sonstiges */ + default: break; + } +#ifdef VANESSA + if (found_vanessa != 0) + vanessa_l1ctl(req); +#endif +#ifdef AX_IPX + axipx_l1ctl(req, port); +#endif +#ifdef AX25IP + ax25ip_l1ctl(req, port); +#endif +#ifdef KERNELIF + ifax_l1ctl(req); +#endif +#ifdef SIXPACK + Sixpack_l1ctl(req, (UWORD)port); +#endif +#ifdef L1TCPIP + L1ctlTCP(req, port); +#endif /* L1TCPIP */ +} + +/************************************************************************/ +/* */ +/* Kommando fuer TNC-Parameter an KISS-Link senden */ +/* */ +/************************************************************************/ + +void send_kisscmd(int l2prt, int cmd, int value) +{ + UBYTE tx_buffer[10]; /* Buffer fuer KISS-Frame - 10 Zeichen reicht! */ + UBYTE *tx_bufptr; + unsigned len; + UBYTE val2; + DEVICE *l1pp; + + /* ohne KISS geht es hier nicht weiter */ + if (!kiss_active) + return; + + if (l2prt != 0xff) /* wenn nicht Token */ + l1pp = &l1port[l1ptab[l2prt]]; + else + l1pp = l1port; /* Token = Tokenring = 1. Device */ + + switch (l1pp->kisstype) /* pruefen, ob Kommando zum */ + { /* Kiss-Modus passt */ + case KISS_RMNC: + case KISS_SCC: + return; + break; + case KISS_TOK: + if (cmd < CMD_TXDELAY) return; + if ((cmd > CMD_TOKEN) && (cmd != CMD_TNCRES)) return; + break; + default: + if ((cmd < CMD_TXDELAY) || (cmd > CMD_FULLDUP)) return; + break; + } + + tx_bufptr = tx_buffer; /* KISS-Frame in Puffer schreiben */ + *tx_bufptr++ = (char)FEND; + len = 1; + + if (l1pp->kisstype == KISS_TOK) /* Port-Nummer nur bei Token- */ + { /* ring */ + *tx_bufptr++ = l2prt; + len++; + } + + *tx_bufptr++ = (char)cmd; + ++len; + + if ((l2prt != 0xff) && (cmd != CMD_TNCRES)) /* Parameter folgt */ + { + val2 = (char)(value & 0xFF); /* Parameter nur 0 - 255 */ + switch (val2) /* ggf. Sonderbehandlung */ + { + case FEND: /* FEND -> FESC - TFEND */ + *tx_bufptr++ = (char)FESC; + *tx_bufptr++ = (char)TFEND; + len += 2; + break; + case FESC: /* FESC -> FESC - TFESC */ + *tx_bufptr++ = (char)FESC; + *tx_bufptr++ = (char)TFESC; + len += 2; + break; + default: /* keine Sonderbehandlung */ + *tx_bufptr++ = val2; + len++; + break; + } + } + *tx_bufptr++ = (char)FEND; /* Ende Kommando-Frame */ + ++len; + + write(l1pp->kisslink, tx_buffer, len);/* Kommando-Frame absenden */ +} + +/************************************************************************/ +/* */ +/* send all frames in txbuffer over kisslink */ +/* */ +/************************************************************************/ + +static void kissframe_to_tnc(int l2prt, BOOLEAN recovery) +{ + UBYTE tx_buffer[2*MAXKISSLEN]; + UBYTE *tx_bufptr; + unsigned len; + unsigned short ch1; + int i; + UBYTE tmp_buffer[MAXKISSLEN]; + UBYTE *tmp_bufptr; + int tmp_buflen; + DEVICE *l1pp; + MBHEAD *txfhdl; + LHEAD *l2flp; + ULONG count = 0L; + + /* Testsignal senden ? */ + if (testflag[l2prt] == TRUE) + { + count = (portpar[l2prt].speed * 1000) / 8; /* 10 sec lang */ + if (count < 1024) /* min. 1kB */ + count = 1024; + } + + l1pp = &l1port[l1ptab[l2prt]]; + kick[l2prt] = FALSE; /* alles senden */ + l2flp = (LHEAD *) &txl2fl[l2prt]; + + while ( (l2flp->head != l2flp) /* solange Frames vorhanden */ + || (testflag[l2prt] == TRUE)) /* oder TEST gefordert */ + { + if (l2flp->head != l2flp) /* erst Info, danach erst TEST */ + { + txfhdl = (MBHEAD *) l2flp->head; + ulink((LEHEAD *) txfhdl); + tmp_bufptr = tmp_buffer; /* Zwischenpuffer auf Anfang */ + *tmp_bufptr++ = (char)0x00; /* fuer KISS-Befehl "Daten */ + tmp_buflen = 1; /* folgen" */ + + while (txfhdl->mbgc < txfhdl->mbpc) /* noch Zeichen im Frame */ + { + ch1 = getchr(txfhdl); /* 1 Zeichen aus Frame holen */ + *tmp_bufptr++ = (char)(ch1 & 0xFF);/* Zeichen in Zwischenpuffer */ + ++tmp_buflen; + } + + relink((LEHEAD *) txfhdl, (LEHEAD *) stfl.tail); + } + else /* TEST */ + { + tmp_bufptr = tmp_buffer; /* Zwischenpuffer auf Anfang */ + *tmp_bufptr++ = 0x00; /* fuer KISS-Befehl "Daten */ + tmp_buflen = 1; /* folgen" */ + while (count > 0) /* noch Zeichen fuer Test */ + { + if (tmp_buflen == MAXKISSLEN-3) /* Buffer voll? */ + break; + *tmp_bufptr++ = 0; /* Zeichen in Zwischenpuffer */ + ++tmp_buflen; + if (--count == 0) /* fertig? */ + testflag[l2prt] = FALSE; + } + } + if (!portenabled(l2prt)) /* Port aus -> Frame ist abgeholt, auf */ + continue; /* zum naechsten .. */ + if (recovery) /* bei Token-Recovery */ + continue; /* zum naechsten .. */ + tx_bufptr = tx_buffer; /* Sendepuffer auf Anfang */ + *tx_bufptr++ = (char)FEND; /* KISS-Frame beginnt mit FEND */ + len = 1; + switch (l1pp->kisstype) /* KISS-Befehl "Daten folgen" abhaengig */ + { /* vom KISS-Modus */ + case KISS_NORMAL: /* KISS einfach */ + case KISS_SCC: + *tmp_buffer = 0x00; + break; + + case KISS_SMACK: /* SMACK */ + case KISS_TF: /* TheFirmware */ + *tmp_buffer = 0x80; + append_crc_16(tmp_buffer, &tmp_buflen); /* CRC ueber gesamtes */ + break; /* Frame anhaengen */ + + case KISS_RMNC: /* RMNC-KISS */ + *tmp_buffer = 0x20; + append_crc_rmnc(tmp_buffer, &tmp_buflen);/* CRC ueber gesamtes */ + break; /* Frame anhaengen */ + + case KISS_TOK: /* Tokenring-KISS */ + *tmp_buffer = 0x00; + *tx_bufptr++ = l2prt; /* L2-Port vorweg */ + ++len; + break; + } + tmp_bufptr = tmp_buffer; /* Zwischenpuffer auf Anfang */ + + for (i = 0; i < tmp_buflen; ++i) /* Zwischenpuffer -> Sendepuffer */ + { /* kopieren */ + switch (*tmp_bufptr) + { + case FEND: /* FEND -> FESC / TFEND */ + *tx_bufptr++ = (char)FESC; + *tx_bufptr++ = (char)TFEND; + len += 2; + break; + + case FESC: /* FESC -> FESC / TFESC */ + *tx_bufptr++ = (char)FESC; + *tx_bufptr++ = (char)TFESC; + len += 2; + break; + + default: /* keine Sonderbehandlung */ + *tx_bufptr++ = *tmp_bufptr; + ++len; + break; + } + ++tmp_bufptr; + } + *tx_bufptr++ = (char)FEND; /* Frameende = FEND */ + ++len; + + write(l1pp->kisslink, tx_buffer, len); /* Frame -> TNC */ + } +} + +/************************************************************************/ +/* */ +/* Empfangsframe in TNN-Puffer schreiben - CRC ist ggf. schon geprueft */ +/* */ +/************************************************************************/ + +static void frame_to_l1(WORD port, char *buffer, int len) +{ + static MBHEAD *rxfrhd; + register int i; + + rxfrhd = (MBHEAD *) allocb(ALLOC_MBHEAD); + rxfrhd->l2port = port; + + for (i = 0; i < len; ++i) + putchr(buffer[i], rxfrhd); + + relink((LEHEAD *) rxfrhd, (LEHEAD *)rxfl.tail); +} + +/************************************************************************/ +/* */ +/* Frame auf Gueltigkeit pruefen (Laenge, CRC) und gueltige Frames */ +/* weiterreichen */ +/* */ +/************************************************************************/ + +static void frame_valid(WORD port, char *buffer, int len, int type) +{ + switch (type) + { + case KISS_NORMAL: /* KISS einfach, Tokenring oder SCC: */ + case KISS_TOK: /* nur Framelaenge kann geprueft werden */ + case KISS_SCC: + if (len <= MAXFRAMELEN) + frame_to_l1(port, buffer+1, len-1); + break; + case KISS_SMACK: /* SMACK: CRC und Framelaenge */ + case KISS_TF: /* TF auch mit SMACK */ + if (!check_crc_16(buffer, &len)) /* pruefen */ + if (len <= MAXFRAMELEN) + frame_to_l1(port, buffer+1, len-1); + break; + case KISS_RMNC: /* RMNC-KISS: CRC und Frame- */ + if (!check_crc_rmnc(buffer, &len))/* laenge pruefen */ + if (len <= MAXFRAMELEN) + frame_to_l1(port, buffer+1, len-1); + break; + } +} + + +/************************************************************************/ +/* */ +/* put data received over kisslink in rxbuffer */ +/* */ +/************************************************************************/ + +void framedata_to_queue(int dev, char *buffer, int len) +{ + UBYTE *bufptr; + register int i; + UBYTE ch; + DEVICE *l1pp; + static WORD k; + + l1pp = &l1port[dev]; + + if (l1pp->kisstype == KISS_TOK) /* Waehrend Empfang kein Token- */ + token_sent = tic10; /* recovery */ + + for (bufptr = buffer, i = 0; i < len; ++i, bufptr++) + { + ch = *bufptr; /* 1 Zeichen aus Puffer holen */ + switch (l1pp->rx_state) + { + case ST_BEGIN: /* Frameanfang suchen */ + if (ch == FEND) /* alles ausser FEND ignorieren */ + l1pp->rx_state = ST_PORT; + break; + case ST_PORT: /* Portnummer folgt */ + if (ch != FEND) /* zusaetzliche FEND ignorieren */ + { + switch (l1pp->kisstype) + { + case KISS_NORMAL: + case KISS_SCC: + +/************************************************************************/ +/* */ +/* KISS einfach: Die Portnummer ist als Bit 4-7 kodiert. Daher sind */ +/* eigentlich 16 Ports moeglich. Dies wird von dieser Software aber */ +/* (noch?) nicht unterstuetzt. Gibt es ueberhaupt TNC-Software, die */ +/* normalen KISS-Modus mit mehreren Ports unterstuetzt? Wer kann das */ +/* einbauen und testen? */ +/* */ +/************************************************************************/ + + if ((ch & 0x8F) == 0x00) + l1pp->rx_port = (ch & 0x70) >> 4; + else + { + l1pp->rx_state = ST_BEGIN; + l1pp->bad_frames++; + } + break; + case KISS_SMACK: + case KISS_TF: + +/************************************************************************/ +/* */ +/* SMACK: Die Portnummer ist als Bit 4-6 kodiert. Daher sind eigentlich */ +/* 8 Ports moeglich. Dies wird von dieser Software aber (noch?) nicht */ +/* unterstuetzt. Gibt es ueberhaupt TNC-Software, die den SMACK-Modus */ +/* mit mehreren Ports unterstuetzt? Wer kann das einbauen und testen? */ +/* */ +/************************************************************************/ + + if ((ch & 0x8F) == 0x80) + l1pp->rx_port = (ch & 0x70) >> 4; + else + { + l1pp->rx_state = ST_BEGIN; + l1pp->bad_frames++; + } + break; + case KISS_RMNC: + if ((ch & 0xFF) == 0x20) + l1pp->rx_port = 0; + else + { + l1pp->rx_state = ST_BEGIN; + l1pp->bad_frames++; + } + break; + case KISS_TOK: + +/************************************************************************/ +/* */ +/* Tokenring: Die Portnummer ist als einzelnes Byte definiert. Daher */ +/* sind eigentlich 255 Ports moeglich. TNN unterstuetzt aber nur die */ +/* Ports 0 - 15. Ausserdem wird Port 255 fuer das Token verwendet. */ +/* */ +/************************************************************************/ + + l1pp->rx_port = ch; + if ( (ch != 0xff) /* nicht Token-Port? */ + && ((ch >= L2PNUM) /* gueltige Portnummer? */ + || (l1ptab[(WORD) ch] != 0))) /* Port definiert? */ + { + l1pp->rx_state = ST_BEGIN; + l1pp->bad_frames++; + } + else + l1pp->rx_state = ST_TOKCMD; + break; + } + +/************************************************************************/ +/* */ +/* Die Portnummer wird jetzt ueberprueft. Ausser beim Tokenring MUSS es */ +/* 0 sein. */ +/* */ +/************************************************************************/ + + if (l1pp->kisstype != KISS_TOK) + { + if (l1pp->rx_state != ST_BEGIN) + { + if (l1pp->rx_port != 0x00) + { + l1pp->rx_state = ST_BEGIN; + l1pp->bad_frames++; + } + else + { + l1pp->rx_state = ST_DATA; + l1pp->rx_bufptr = l1pp->rx_buffer; + *l1pp->rx_bufptr++ = ch; + l1pp->rx_buflen = 1; + } + } + } + } + break; + case ST_DATA: /* Daten kommen */ + switch (ch) + { + case FEND: /* Frameende? */ + if (l1pp->kisstype != KISS_TOK) /* ggf. Portnummer aus */ + l1pp->rx_port = l2ptab[dev]; /* Tabelle holen */ + frame_valid(l1pp->rx_port, /* Frame pruefen und */ + l1pp->rx_buffer, /* an L2 weitergeben */ + l1pp->rx_buflen, + l1pp->kisstype); + l1pp->rx_state = ST_PORT; /* naechstes Frame kann */ + break; /* kommen */ + case FESC: /* FESC -> Sonderfall */ + l1pp->rx_state = ST_ESC; + break; + default: /* normales Zeichen */ + *l1pp->rx_bufptr = ch; + l1pp->rx_bufptr++; + l1pp->rx_buflen++; + if (l1pp->rx_buflen > MAXKISSLEN) /* Frame zu lang? */ + { + l1pp->rx_state = ST_BEGIN; + l1pp->bad_frames++; + } + break; + } + break; + case ST_ESC: /* zuletzt FESC empfangen */ + switch (ch) + { + case TFEND: /* FESC / TFEND -> FEND */ + *l1pp->rx_bufptr = (char)FEND; + l1pp->rx_bufptr++; + l1pp->rx_buflen++; + if (l1pp->rx_buflen > MAXKISSLEN) /* Frame zu lang? */ + { + l1pp->rx_state = ST_BEGIN; + l1pp->bad_frames++; + } + else + l1pp->rx_state = ST_DATA; + break; + case TFESC: /* FESC / TFESC -> FESC */ + *l1pp->rx_bufptr = (char)FESC; + l1pp->rx_bufptr++; + l1pp->rx_buflen++; + if (l1pp->rx_buflen > MAXKISSLEN) /* Frame zu lang? */ + { + l1pp->rx_state = ST_BEGIN; + l1pp->bad_frames++; + } + else + l1pp->rx_state = ST_DATA; + break; + default: + l1pp->rx_state = ST_BEGIN; + l1pp->bad_frames++; + break; + } + break; + case ST_TOKCMD: /* Tokenring nach Port */ + switch (ch & 0xff) /* kommt Kommando */ + { + case 0: /* Kommando: "Daten */ + l1pp->rx_state = ST_DATA; /* folgen" */ + l1pp->rx_bufptr = l1pp->rx_buffer; + *l1pp->rx_bufptr++ = ch; + l1pp->rx_buflen = 1; + break; + case CMD_TOKEN: /* Kommando: "Token" */ + if (l1pp->rx_port == 0xff) + l1pp->rx_state = ST_TOKEN; + else + l1pp->rx_state = ST_BEGIN; + break; + case MSG_TNCRES: /* Kommando: "TNC- */ + if (l1pp->rx_port != 0xff) /* Meldung - Reset" */ + { + k = 0; + l1pp->rx_state = ST_TNCRES; + } + else + { + l1pp->rx_state = ST_BEGIN; + l1pp->bad_frames++; + } + break; + case MSG_SENTDAMA: /* Kommando: "TNC- */ + if (l1pp->rx_port != 0xff) /* Meldung: DAMA-Frames */ + l1pp->rx_state = ST_DAMA; /* gesendet" */ + else + { + l1pp->rx_state = ST_BEGIN; + l1pp->bad_frames++; + } + break; + default: /* unbekanntes Kommando */ + l1pp->rx_state = ST_BEGIN; + l1pp->bad_frames++; + break; + } + break; + case ST_TOKEN: /* nach Token kommt FEND */ + if (ch == FEND) + { + tokenflag = TRUE; + l1pp->rx_state = ST_PORT; + ++token_count; + } + else + { + l1pp->rx_state = ST_BEGIN; + l1pp->bad_frames++; + } + break; + case ST_TNCRES: /* nach TNC-Meldung kommt FEND */ + if (ch == FEND) + { + commandflag[l1pp->rx_port] = TRUE; + portstat[l1pp->rx_port].reset_count++; + l1pp->rx_state = ST_PORT; + printf("TNC-Reset - Port %d\r\n", l1pp->rx_port); + } + else + { + if (++k > 6) + { + l1pp->rx_state = ST_BEGIN; + l1pp->bad_frames++; + } + } + break; + case ST_DAMA: /* nach TNC-Meldung kommt FEND */ + if (ch == FEND) + { + cd_timer[l1pp->rx_port] = 0; /* Kanal frei: Timer stoppen */ + l1pp->rx_state = ST_PORT; + } + else + { + l1pp->rx_state = ST_BEGIN; + l1pp->bad_frames++; + } + break; + default: + l1pp->rx_state = ST_BEGIN; + l1pp->bad_frames++; + break; + } + } +} + +/************************************************************************/ +/* */ +/* Markieren, dass fuer TNC #port Frames zum Senden vorliegen */ +/* */ +/************************************************************************/ + +void kicktx(int port) +{ + kick[port] = TRUE; +} + +/************************************************************************/ +/* */ +/* iscd(): Carrier Detect Wichtig fuer DAMA !!! */ +/* */ +/* Return: abhaengig von der Hardware des Ports - nur KISS wird */ +/* direkt behandelt. PTTFLAG = auf DAMA-Port noch nicht */ +/* alles gesendet, 0 sonst. */ +/* */ +/************************************************************************/ + +WORD iscd(int l2port) +{ + switch (kissmode(l2port)) + { +#ifdef VANESSA + case KISS_VAN : return (vanessa_dcd(l2port)); break; +#endif +#ifdef AX_IPX + case KISS_IPX : return (axipx_dcd(l2port)); break; +#endif +#ifdef AX25IP + case KISS_AXIP : return (ax25ip_dcd(l2port)); break; +#endif +#if defined(KERNELIF) && (defined(PCISCC4_KAX25) || defined(HDLC_DCDPTTSTAT) || defined(SCC_DCDPTTSTAT)) + case KISS_KAX25 : return (ifax_dcd(l2port)); break; +#endif +#ifdef SIXPACK + case KISS_6PACK : return (Sixpack_DCD((UWORD)l2port)); break; +#endif +#ifdef L1TELNET + case KISS_TELNET: return (TcpDCD(l2port)); break; +#endif /* L1TELNET */ +#ifdef L1HTTPD + case KISS_HTTPD: return (TcpDCD(l2port)); break; +#endif /* L1HTTPD */ +#ifdef L1IPCONV + case KISS_IPCONV: return (TcpDCD(l2port)); break; +#endif /* L1IPCONV */ +#ifdef L1IRC + case KISS_IRC: return (TcpDCD(l2port)); break; +#endif /* L1IRC */ + + default : break; + } + + /* DCD fuer Tokenring */ + if ( dama(l2port) /* Nur DAMA-Ports und belegt.. */ + && cd_timer[l2port]) + { + if ((tic10 - cd_timer[l2port]) > CD_TIMEOUT) /* Timeout abgelaufen? */ + cd_timer[l2port] = 0; /* Timer stoppen */ + + if (cd_timer[l2port]) /* Timer laeuft: Port ist belegt */ + return(PTTFLAG); /* Einen belegten Port gefunden! */ + }/*Nur DAMA*/ + + return(FALSE); +} + +/************************************************************************/ +/* */ +/* Aufzaehlen der vorhandenen Layer 1 Geraete. Dies sind nicht die */ +/* tatsaechlich installierten sondern die compilierten. */ +/* */ +/************************************************************************/ + +void l1enum(MBHEAD *mbp) +{ +#ifdef LOOPBACK + putstr(" * KISS-Protocols: TOKENRING KISS SMACK RKISS TF LOOP\r", mbp); +#else + putstr(" * KISS-Protocols: TOKENRING KISS SMACK RKISS TF\r", mbp); +#endif +#ifdef SIXPACK + putstr(" * 6PACK\r", mbp); +#endif +#ifdef VANESSA + putstr(" * VANESSA\r", mbp); +#endif +#ifdef AX_IPX + putstr(" * IPX\r", mbp); +#endif +#ifdef AX25IP + putstr(" * AX25IP\r", mbp); +#endif +#ifdef KERNELIF + putstr(" * Kernel-AX.25\r", mbp); + putstr(" * IP-Tunnel\r", mbp); +#endif +#ifdef L1TELNET + putstr(" * TELNET-Server\r", mbp); +#endif /* L1TELNET */ +#ifdef L1HTTPD + putstr(" * HTTPD-Server\r", mbp); +#endif /* L1HTTPD */ +#ifdef L1IPCONV + putstr(" * IPCONVERS-Server\r", mbp); +#endif /* L1IPCONV */ +#ifdef L1IRC + putstr(" * IRC-Server\r", mbp); +#endif /* L1IRC */ +} + +/************************************************************************/ +/* */ +/* L1-Statistik loeschen (alle Ports) */ +/* */ +/************************************************************************/ + +void l1sclr(const char *str) +{ + register unsigned int i; + + token_pro_sec = 0; + token_max_sec = 0; + token_min_sec = 0; + token_count = 0; + recovery_count = 0L; + + for (i = 0; i < L1PNUM; ++i) + l1port[i].bad_frames = 0L; + +#ifdef KERNELIF + ifip_clearstat(); +#endif +} + +/************************************************************************/ +/* */ +/* L1-Statistik (Tokenring) anzeigen */ +/* */ +/************************************************************************/ + +void l1stat(const char *name, MBHEAD *mbp) +{ + int i; + BOOLEAN flag = FALSE; + + if (tkcom >= 0) + { + putprintf(mbp, "\rTokens/sec - min.: %u; last: %u; max.: %u\r", token_min_sec, token_pro_sec, token_max_sec); + + if (token_max_sec != 0) /* nicht vor 1. Messung */ + putprintf(mbp, "TOKENRING load: %u%%\r", 100-(((ULONG)token_pro_sec)*100L) / ((ULONG)token_max_sec)); + + if (recovery_count != 0) + putprintf(mbp, "\rToken-Recoveries: %lu\r", recovery_count); + } + + for (i = 0; i < L1PNUM; ++i) + { + if (l1port[i].bad_frames != 0) + { + if (!flag) + { + flag = TRUE; + putstr("\rBad frames:\r", mbp); + } + putprintf(mbp, "Device %s = %lu\r", l1port[i].device, l1port[i].bad_frames); + } + } +} + +/************************************************************************/ +/* */ +/* L1 beenden */ +/* */ +/************************************************************************/ + +void l1detach(int l2prt) +{ + portpar[l2prt].major = NO_MAJOR; +#ifdef AX_IPX + if (kissmode(l2prt) == KISS_IPX) + axipx_l1exit(); +#endif +#ifdef AX25IP + if (kissmode(l2prt) == KISS_AXIP) + ax25ip_l1exit(); +#endif +#ifdef KERNELIF + if ( (kissmode(l2prt) == KISS_KAX25) + || (kissmode(l2prt) == KISS_KAX25KJD)) + ifax_close(&(l1port[l1ptab[l2prt]])); +#endif +#ifdef L1TELNET + if (kissmode(l2prt) == KISS_TELNET) + L1ExitTCP(kissmode(l2prt)); +#endif /* L1TELNET */ +#ifdef L1HTTPD + if (kissmode(l2prt) == KISS_HTTPD) + L1ExitTCP(kissmode(l2prt)); +#endif /* L1HTTPD */ +#ifdef L1IPCONV + if (kissmode(l2prt) == KISS_IPCONV) + L1ExitTCP(kissmode(l2prt)); +#endif /* L1IPCONV */ +#ifdef L1IRC + if (kissmode(l2prt) == KISS_IRC) + L1ExitTCP(kissmode(l2prt)); +#endif /* L1IRC */ +} + +/************************************************************************/ +/* */ +/* L1 starten */ +/* */ +/************************************************************************/ + +int l1attach(int l2prt, char *buf) +{ + if (l1port[l1ptab[l2prt]].port_active == FALSE) +/* Port undefiniert in tnn.ini - der Port kann auf LOOP gesetzt werden */ + { + if (strnicmp("LOOP", buf, min(4, strlen(buf))) == 0) + { + kissmode(l2prt) = KISS_LOOP; + portpar[l2prt].major = 1; + return(1); + } + return(0); + } + if (strnicmp("TOKENRING", buf, min(9, strlen(buf))) == 0) + { + if (kissmode(l2prt) == KISS_TOK) + { + portpar[l2prt].major = 1; + return(1); + } + } + +#ifdef SIXPACK + if (strnicmp("6PACK", buf, min(5, strlen(buf))) == 0) + { + if (kissmode(l2prt) == KISS_6PACK) + { + portpar[l2prt].major = 1; + return(1); + } + } +#endif + + if (strnicmp("KISS", buf, min(4, strlen(buf))) == 0) + { + if ((kissmode(l2prt) != KISS_NIX) && (kissmode(l2prt) != KISS_VAN)) + { + portpar[l2prt].major = 1; + return(1); + } + } + if (strnicmp("SMACK", buf, min(5, strlen(buf))) == 0) + { + if (kissmode(l2prt) == KISS_SMACK) + { + portpar[l2prt].major = 1; + return(1); + } + } + if (strnicmp("TF", buf, 2) == 0) + { + if (kissmode(l2prt) == KISS_TF) + { + portpar[l2prt].major = 1; + return(1); + } + } + if (strnicmp("RKISS", buf, min(5, strlen(buf))) == 0) + { + if (kissmode(l2prt) == KISS_RMNC) + { + portpar[l2prt].major = 1; + return(1); + } + } +#ifdef VANESSA + if (strnicmp("VANESSA", buf, min(7, strlen(buf))) == 0) + { + if (kissmode(l2prt) == KISS_VAN) + { + portpar[l2prt].major = 1; + return(1); + } + } +#endif +#ifdef AX_IPX + if (strnicmp("IPX", buf, min(3, strlen(buf))) == 0) + { + if (kissmode(l2prt) == KISS_IPX) + { + if (!axipx_l1init(l2prt)) + return(0); + portpar[l2prt].major = 1; + return(1); + } + } +#endif +#ifdef AX25IP + if (strnicmp("AX25IP", buf, min(6, strlen(buf))) == 0) + { + if (kissmode(l2prt) == KISS_AXIP) + { + if (!ax25ip_l1init(l2prt)) + return(0); + portpar[l2prt].major = 1; + return(1); + } + } +#endif +#ifdef KERNELIF + if (strnicmp("KERNEL", buf, min(6, strlen(buf))) == 0) + { + if ( (kissmode(l2prt) == KISS_KAX25) + || (kissmode(l2prt) == KISS_KAX25KJD)) + { + if (!ifax_setup(&(l1port[l1ptab[l2prt]]))) + return(0); + portpar[l2prt].major = 1; + return(1); + } + } +#endif +#ifdef L1TELNET + if (strnicmp("TELNET", buf, min(6, strlen(buf))) == FALSE) + { + if (kissmode(l2prt) == KISS_TELNET) + { + if (!L1InitTCP(kissmode(l2prt), l2prt, htons((unsigned short)atoi(l1port[l1ptab[l2prt]].device)))) + return(FALSE); + + portpar[l2prt].major = TRUE; + return(TRUE); + } + } +#endif /* L1TELNET */ +#ifdef L1HTTPD + if (strnicmp("HTTPD", buf, min(6, strlen(buf))) == FALSE) + { + if (kissmode(l2prt) == KISS_HTTPD) + { + if (!L1InitTCP(kissmode(l2prt), l2prt, htons((unsigned short)atoi(l1port[l1ptab[l2prt]].device)))) + return(FALSE); + + portpar[l2prt].major = TRUE; + return(TRUE); + } + } +#endif /* L1HTTPD */ +#ifdef L1IPCONV + if (strnicmp("IPCONV", buf, min(6, strlen(buf))) == FALSE) + { + if (kissmode(l2prt) == KISS_IPCONV) + { + if (!L1InitTCP(kissmode(l2prt), l2prt, htons((unsigned short)atoi(l1port[l1ptab[l2prt]].device)))) + return(FALSE); + + portpar[l2prt].major = TRUE; + return(TRUE); + } + } +#endif /* L1IPCONV */ +#ifdef L1IRC + if (strnicmp("IRC", buf, min(3, strlen(buf))) == FALSE) + { + if (kissmode(l2prt) == KISS_IRC) + { + if (!L1InitTCP(kissmode(l2prt), l2prt, htons((unsigned short)atoi(l1port[l1ptab[l2prt]].device)))) + return(FALSE); + + portpar[l2prt].major = TRUE; + return(TRUE); + } + } +#endif /* L1IRC */ + if (strnicmp("SSC", buf, min(3, strlen(buf))) == 0) + { + if (kissmode(l2prt) == KISS_SCC) + { + portpar[l2prt].major = 1; + return(1); + } + } + + if (stricmp("ON", buf) == 0) + { + if (kissmode(l2prt) != KISS_NIX) + { +#ifdef AX_IPX + if (kissmode(l2prt) == KISS_IPX) + { + if (!axipx_l1init(l2prt)) + return(0); + } +#endif +#ifdef AX25IP + if (kissmode(l2prt) == KISS_AXIP) + { + if (!ax25ip_l1init(l2prt)) + return(0); + } +#endif +#ifdef KERNELIF + if ( (kissmode(l2prt) == KISS_KAX25) + || (kissmode(l2prt) == KISS_KAX25KJD)) + { + if (!ifax_setup(&(l1port[l1ptab[l2prt]]))) + return(0); + } +#endif +#ifdef L1TELNET + if (kissmode(l2prt) == KISS_TELNET) + { + if (!L1InitTCP(kissmode(l2prt), l2prt, htons((unsigned short)atoi(l1port[l1ptab[l2prt]].device)))) + return(FALSE); + } +#endif /* L1TELNET */ +#ifdef L1HTTPD + if (kissmode(l2prt) == KISS_HTTPD) + { + if (!L1InitTCP(kissmode(l2prt), l2prt, htons((unsigned short)atoi(l1port[l1ptab[l2prt]].device)))) + return(FALSE); + } +#endif /* L1HTTPD */ +#ifdef L1IPCONV + if (kissmode(l2prt) == KISS_IPCONV) + { + if (!L1InitTCP(kissmode(l2prt), l2prt, htons((unsigned short)atoi(l1port[l1ptab[l2prt]].device)))) + return(FALSE); + } +#endif /* L1IPCONV */ +#ifdef L1IRC + if (kissmode(l2prt) == KISS_IRC) + { + if (!L1InitTCP(kissmode(l2prt), l2prt, htons((unsigned short)atoi(l1port[l1ptab[l2prt]].device)))) + return(FALSE); + } +#endif /* L1IRC */ + + portpar[l2prt].major = 1; + return(1); + } + } + return(0); +} + +/************************************************************************/ +/* */ +/* Infostring fuer den Port-Befehl zusammenbauen. */ +/* */ +/************************************************************************/ + +void l1hwstr(int l2prt, MBHEAD *mbp) +{ + l1hwcfg(l2prt, mbp); + if ((kissmode(l2prt) != KISS_VAN) && (kissmode(l2prt) < KISS_IPX)) + { + putchr(' ', mbp); + putstr(l1port[l1ptab[l2prt]].device, mbp); + } + else + { +#ifdef VANESSA + if (kissmode(l2prt) == KISS_VAN) + van_hwstr(l2prt, mbp); +#endif +#ifdef AX_IPX + if (kissmode(l2prt) == KISS_IPX) + axipx_hwstr(l2prt, mbp); +#endif +#ifdef AX25IP + if (kissmode(l2prt) == KISS_AXIP) + ax25ip_hwstr(l2prt, mbp); +#endif +#ifdef KERNELIF + if ( (kissmode(l2prt) == KISS_KAX25) + || (kissmode(l2prt) == KISS_KAX25KJD)) + ifax_hwstr(l2prt, mbp); +#endif +#ifdef L1TELNET + if (kissmode(l2prt) == KISS_TELNET) + HwstrTCP(KISS_TELNET, l2prt, mbp); +#endif /* L1TELNET */ +#ifdef L1HTTPD + if (kissmode(l2prt) == KISS_HTTPD) + HwstrTCP(KISS_HTTPD, l2prt, mbp); +#endif /* L1HTTPD */ +#ifdef L1IPCONV + if (kissmode(l2prt) == KISS_IPCONV) + HwstrTCP(KISS_IPCONV, l2prt, mbp); +#endif /* L1IPCONV */ +#ifdef L1IRC + if (kissmode(l2prt) == KISS_IRC) + HwstrTCP(KISS_IRC, l2prt, mbp); +#endif /* L1IRC */ + } +} + +/************************************************************************/ +/* */ +/* Infostring fuer SAVEPARM zusammenbauen. */ +/* */ +/************************************************************************/ + +void l1hwcfg(int l2prt, MBHEAD *mbp) +{ + if (!portenabled(l2prt)) + putstr("OFF", mbp); + else + { + switch (kissmode(l2prt)) + { + case KISS_SMACK: putstr("SMACK", mbp); + break; + case KISS_TF: putstr("TF", mbp); + break; + case KISS_TOK: putstr("TOKENRING", mbp); + break; +#ifdef LOOPBACK + case KISS_LOOP: putstr("LOOP", mbp); + break; +#endif + case KISS_RMNC: putstr("RKISS", mbp); + break; +#ifdef VANESSA + case KISS_VAN: putstr("VANESSA", mbp); + break; +#endif +#ifdef AX_IPX + case KISS_IPX: putstr("IPX", mbp); + break; +#endif +#ifdef AX25IP + case KISS_AXIP: putstr("AX25IP", mbp); + break; +#endif +#ifdef KERNELIF + case KISS_KAX25: + case KISS_KAX25KJD: putstr("KERNEL", mbp); + break; +#endif +#ifdef SIXPACK + case KISS_6PACK: putstr("6PACK", mbp); + break; +#endif +#ifdef L1TELNET + case KISS_TELNET: putstr("TELNET", mbp); + break; +#endif /* L1TELNET */ +#ifdef L1HTTPD + case KISS_HTTPD: putstr("HTTPD ", mbp); + break; +#endif /* L1HTTPD */ +#ifdef L1IPCONV + case KISS_IPCONV: putstr("IPCONV", mbp); + break; +#endif /* L1IPCONV */ +#ifdef L1IRC + case KISS_IRC: putstr("IRC ", mbp); + break; +#endif /* L1IRC */ + + default: putstr("KISS", mbp); + break; + } + } +} + +/* + * Blocktransferroutinen fuer den Level 1 + * Message-Buffer koennen Blockweise in einen linearen Buffer umgewandelt + * werden und wieder zurueck. Dies darf aber so ohne weiteres nur im + * Level 1 erfolgen, da der Buffer zurueckgespult wird. + */ + +/* Message-Buffer -> linearen Buffer */ +int cpymbflat(char *buf, MBHEAD *fbp) { + MB *bp; + LHEAD *llp = &fbp->mbl; /* Zeiger auf den Listenkopf */ + int i = fbp->mbpc; /* Anzahl der Bytes im Frame */ + + for (bp = (MB *)llp->head; bp != (MB *)llp; + bp = bp->nextmb, i -= sizeof_MBDATA, buf += sizeof_MBDATA) + memcpy(buf, bp->data, sizeof_MBDATA); + return(fbp->mbpc); +} + +/* linearer Buffer -> Message-Buffer */ +MBHEAD *cpyflatmb(char *buf, int size) { + MBHEAD *mbhd; + MB *bp; + LHEAD *llp; + + mbhd = (MBHEAD *)allocb(ALLOC_MBHEAD); /* einen Buffer fuer den Kopf */ + mbhd->mbpc = size; /* soviel wird mal drinstehen */ + llp = &mbhd->mbl; /* Zeiger auf den Listenkopf */ + for ( ; size > 0; size -= sizeof_MBDATA, buf += sizeof_MBDATA) { + memcpy((bp = (MB *)allocb(ALLOC_MB))->data, buf, sizeof_MBDATA); + relink((LEHEAD *)bp, (LEHEAD *)llp->tail); + } + rwndmb(mbhd); /* mbbp richtig setzen */ + return(mbhd); +} + +/************************************************************************/ +/* */ +/* TNC mit TheFirmware in KISS-Modus schalten */ +/* */ +/************************************************************************/ + +#ifndef ATTACH +static void tf_set_kiss(DEVICE *l1pp) +#else +void tf_set_kiss(DEVICE *l1pp) +#endif /* ATTACH */ +{ + char buffer1[] = {0x18, 0x12, 0x18, ESC, '@', 'K', CR}; + char buffer2[] = {(char)FESC, (char)FEND, (char)FEND, (char)0x80, 0, 0, (char)FEND}; + + write(l1pp->kisslink, buffer1, 7); + sleep(5); + write(l1pp->kisslink, buffer2, 7); +} + +/* tfkiss: TNC-emulation for Win32 + Copyright (C) 1995-96 by Mark Wahl + CRC calculation (crc.c) + created: Mark Wahl DL4YBG 95/10/08 + updated: Mark Wahl DL4YBG 96/01/31 +*/ + +/* CRC-table for SMACK */ +static const int +Crc_16_table[] = { + 0x0000, 0xc0c1, 0xc181, 0x0140, 0xc301, 0x03c0, 0x0280, 0xc241, + 0xc601, 0x06c0, 0x0780, 0xc741, 0x0500, 0xc5c1, 0xc481, 0x0440, + 0xcc01, 0x0cc0, 0x0d80, 0xcd41, 0x0f00, 0xcfc1, 0xce81, 0x0e40, + 0x0a00, 0xcac1, 0xcb81, 0x0b40, 0xc901, 0x09c0, 0x0880, 0xc841, + 0xd801, 0x18c0, 0x1980, 0xd941, 0x1b00, 0xdbc1, 0xda81, 0x1a40, + 0x1e00, 0xdec1, 0xdf81, 0x1f40, 0xdd01, 0x1dc0, 0x1c80, 0xdc41, + 0x1400, 0xd4c1, 0xd581, 0x1540, 0xd701, 0x17c0, 0x1680, 0xd641, + 0xd201, 0x12c0, 0x1380, 0xd341, 0x1100, 0xd1c1, 0xd081, 0x1040, + 0xf001, 0x30c0, 0x3180, 0xf141, 0x3300, 0xf3c1, 0xf281, 0x3240, + 0x3600, 0xf6c1, 0xf781, 0x3740, 0xf501, 0x35c0, 0x3480, 0xf441, + 0x3c00, 0xfcc1, 0xfd81, 0x3d40, 0xff01, 0x3fc0, 0x3e80, 0xfe41, + 0xfa01, 0x3ac0, 0x3b80, 0xfb41, 0x3900, 0xf9c1, 0xf881, 0x3840, + 0x2800, 0xe8c1, 0xe981, 0x2940, 0xeb01, 0x2bc0, 0x2a80, 0xea41, + 0xee01, 0x2ec0, 0x2f80, 0xef41, 0x2d00, 0xedc1, 0xec81, 0x2c40, + 0xe401, 0x24c0, 0x2580, 0xe541, 0x2700, 0xe7c1, 0xe681, 0x2640, + 0x2200, 0xe2c1, 0xe381, 0x2340, 0xe101, 0x21c0, 0x2080, 0xe041, + 0xa001, 0x60c0, 0x6180, 0xa141, 0x6300, 0xa3c1, 0xa281, 0x6240, + 0x6600, 0xa6c1, 0xa781, 0x6740, 0xa501, 0x65c0, 0x6480, 0xa441, + 0x6c00, 0xacc1, 0xad81, 0x6d40, 0xaf01, 0x6fc0, 0x6e80, 0xae41, + 0xaa01, 0x6ac0, 0x6b80, 0xab41, 0x6900, 0xa9c1, 0xa881, 0x6840, + 0x7800, 0xb8c1, 0xb981, 0x7940, 0xbb01, 0x7bc0, 0x7a80, 0xba41, + 0xbe01, 0x7ec0, 0x7f80, 0xbf41, 0x7d00, 0xbdc1, 0xbc81, 0x7c40, + 0xb401, 0x74c0, 0x7580, 0xb541, 0x7700, 0xb7c1, 0xb681, 0x7640, + 0x7200, 0xb2c1, 0xb381, 0x7340, 0xb101, 0x71c0, 0x7080, 0xb041, + 0x5000, 0x90c1, 0x9181, 0x5140, 0x9301, 0x53c0, 0x5280, 0x9241, + 0x9601, 0x56c0, 0x5780, 0x9741, 0x5500, 0x95c1, 0x9481, 0x5440, + 0x9c01, 0x5cc0, 0x5d80, 0x9d41, 0x5f00, 0x9fc1, 0x9e81, 0x5e40, + 0x5a00, 0x9ac1, 0x9b81, 0x5b40, 0x9901, 0x59c0, 0x5880, 0x9841, + 0x8801, 0x48c0, 0x4980, 0x8941, 0x4b00, 0x8bc1, 0x8a81, 0x4a40, + 0x4e00, 0x8ec1, 0x8f81, 0x4f40, 0x8d01, 0x4dc0, 0x4c80, 0x8c41, + 0x4400, 0x84c1, 0x8581, 0x4540, 0x8701, 0x47c0, 0x4680, 0x8641, + 0x8201, 0x42c0, 0x4380, 0x8341, 0x4100, 0x81c1, 0x8081, 0x4040 +}; + +/* CRC-table for RMNC-KISS */ +static const int +Crc_rmnc_table[] = { + 0x0f87, 0x1e0e, 0x2c95, 0x3d1c, 0x49a3, 0x582a, 0x6ab1, 0x7b38, + 0x83cf, 0x9246, 0xa0dd, 0xb154, 0xc5eb, 0xd462, 0xe6f9, 0xf770, + 0x1f06, 0x0e8f, 0x3c14, 0x2d9d, 0x5922, 0x48ab, 0x7a30, 0x6bb9, + 0x934e, 0x82c7, 0xb05c, 0xa1d5, 0xd56a, 0xc4e3, 0xf678, 0xe7f1, + 0x2e85, 0x3f0c, 0x0d97, 0x1c1e, 0x68a1, 0x7928, 0x4bb3, 0x5a3a, + 0xa2cd, 0xb344, 0x81df, 0x9056, 0xe4e9, 0xf560, 0xc7fb, 0xd672, + 0x3e04, 0x2f8d, 0x1d16, 0x0c9f, 0x7820, 0x69a9, 0x5b32, 0x4abb, + 0xb24c, 0xa3c5, 0x915e, 0x80d7, 0xf468, 0xe5e1, 0xd77a, 0xc6f3, + 0x4d83, 0x5c0a, 0x6e91, 0x7f18, 0x0ba7, 0x1a2e, 0x28b5, 0x393c, + 0xc1cb, 0xd042, 0xe2d9, 0xf350, 0x87ef, 0x9666, 0xa4fd, 0xb574, + 0x5d02, 0x4c8b, 0x7e10, 0x6f99, 0x1b26, 0x0aaf, 0x3834, 0x29bd, + 0xd14a, 0xc0c3, 0xf258, 0xe3d1, 0x976e, 0x86e7, 0xb47c, 0xa5f5, + 0x6c81, 0x7d08, 0x4f93, 0x5e1a, 0x2aa5, 0x3b2c, 0x09b7, 0x183e, + 0xe0c9, 0xf140, 0xc3db, 0xd252, 0xa6ed, 0xb764, 0x85ff, 0x9476, + 0x7c00, 0x6d89, 0x5f12, 0x4e9b, 0x3a24, 0x2bad, 0x1936, 0x08bf, + 0xf048, 0xe1c1, 0xd35a, 0xc2d3, 0xb66c, 0xa7e5, 0x957e, 0x84f7, + 0x8b8f, 0x9a06, 0xa89d, 0xb914, 0xcdab, 0xdc22, 0xeeb9, 0xff30, + 0x07c7, 0x164e, 0x24d5, 0x355c, 0x41e3, 0x506a, 0x62f1, 0x7378, + 0x9b0e, 0x8a87, 0xb81c, 0xa995, 0xdd2a, 0xcca3, 0xfe38, 0xefb1, + 0x1746, 0x06cf, 0x3454, 0x25dd, 0x5162, 0x40eb, 0x7270, 0x63f9, + 0xaa8d, 0xbb04, 0x899f, 0x9816, 0xeca9, 0xfd20, 0xcfbb, 0xde32, + 0x26c5, 0x374c, 0x05d7, 0x145e, 0x60e1, 0x7168, 0x43f3, 0x527a, + 0xba0c, 0xab85, 0x991e, 0x8897, 0xfc28, 0xeda1, 0xdf3a, 0xceb3, + 0x3644, 0x27cd, 0x1556, 0x04df, 0x7060, 0x61e9, 0x5372, 0x42fb, + 0xc98b, 0xd802, 0xea99, 0xfb10, 0x8faf, 0x9e26, 0xacbd, 0xbd34, + 0x45c3, 0x544a, 0x66d1, 0x7758, 0x03e7, 0x126e, 0x20f5, 0x317c, + 0xd90a, 0xc883, 0xfa18, 0xeb91, 0x9f2e, 0x8ea7, 0xbc3c, 0xadb5, + 0x5542, 0x44cb, 0x7650, 0x67d9, 0x1366, 0x02ef, 0x3074, 0x21fd, + 0xe889, 0xf900, 0xcb9b, 0xda12, 0xaead, 0xbf24, 0x8dbf, 0x9c36, + 0x64c1, 0x7548, 0x47d3, 0x565a, 0x22e5, 0x336c, 0x01f7, 0x107e, + 0xf808, 0xe981, 0xdb1a, 0xca93, 0xbe2c, 0xafa5, 0x9d3e, 0x8cb7, + 0x7440, 0x65c9, 0x5752, 0x46db, 0x3264, 0x23ed, 0x1176, 0x00ff +}; + +static void append_crc_16(char *buffer, int *len) +{ + register int i; + int crc_16 = 0; + UBYTE *bufptr = buffer; + + for (i = 0; i < *len; ++i) + crc_16 = (crc_16 >> 8) ^ Crc_16_table[(crc_16 ^ *bufptr++) & 0xff]; + + *bufptr++ = crc_16; + *bufptr++ = (crc_16 >> 8); + *len += 2; +} + +static int check_crc_16(char *buffer, int *len) +{ + register int i; + int crc_16 = 0; + UBYTE *bufptr = buffer; + + if (*len < 3) + return(1); + + for (i = 0; i < *len; ++i) + crc_16 = (crc_16 >> 8) ^ Crc_16_table[(crc_16 ^ *bufptr++) & 0xff]; + + if (crc_16) + return(1); + + *len -= 2; + return(0); +} + +static void append_crc_rmnc(char *buffer, int *len) +{ + register int i; + int crc_rmnc = 0xFFFF; + UBYTE *bufptr = buffer; + + for (i = 0; i < *len; ++i) + crc_rmnc = (crc_rmnc << 8) ^ Crc_rmnc_table[((crc_rmnc >> 8) ^ *bufptr++) & 0xff]; + + *bufptr++ = (crc_rmnc >> 8); + *bufptr++ = crc_rmnc; + *len += 2; +} + +static int check_crc_rmnc(char *buffer, int *len) +{ + register int i; + int crc_rmnc = 0xFFFF; + UBYTE *bufptr = buffer; + + if (*len < 3) + return(1); + + for (i = 0; i < *len; ++i) + crc_rmnc = (crc_rmnc << 8) ^ Crc_rmnc_table[((crc_rmnc >> 8) ^ *bufptr++) & 0xff]; + + if ((crc_rmnc & 0xFFFF) != 0x7070) + return(1); + + *len -= 2; + return(0); +} + +/* End of os/win32/l1win32.c */ diff --git a/os/win32/osipconv.c b/os/win32/osipconv.c new file mode 100755 index 0000000..b9a424c --- /dev/null +++ b/os/win32/osipconv.c @@ -0,0 +1,198 @@ + +#include "tnn.h" +#ifdef OS_IPLINK + +/* Zeiger auf das Aktuelle Interface. */ +static T_INTERFACE *ifpp; + + +/* Struktur (sockaddr_in) fuer Server definieren. */ +struct sockaddr_in myaddr_in; +/* Struktur (sockaddr_in) fuer client definieren. */ +struct sockaddr_in peeraddr_in; + + +/* Ein Connect zum TCPIP-Nachbarn aufbauen. */ +int IPConvConnectOS(char *call, char *upcall, BOOLEAN flag) +{ + SENDTX *STx = NULL; + int fd = EOF; + int ch = FALSE; + register int i = EOF; + struct hostent *h; + long addr; + char tmp[10]; +#ifdef DEBUG_MODUS + lastfunc = "osipconv(IPConvConnectOS)"; +#endif /* DEBUG_MODUS */ + + ifpp = &ifp[CVS_ID]; /* Zeiger auf das IPCONV-Interface. */ + + /* IPConvers aktiv? */ + if (ifpp->actively == FALSE) + { + /* ggf. Logbuch fuehren. */ + T_LOGL1(TRUE, "(IPConvConnectOS):\nKein IPConvers-Port geoeffnet!\n"); + /* Nein, abbrechen. */ + return(TRUE); + } + + /* Suche Rufzeichen in der IPC-TBL. */ + if ((i = IPConvSearch(call)) == EOF) + { + /* ggf. Logbuch fuehren. */ + T_LOGL1(TRUE, "(IPConvConnectOS):\nRufzeichen (%s) wurde nicht gefunden!\n" + , call); + /* Nix gefunden, abbrechen. */ + return(TRUE); + } + + /* Konvertiere Rufzeichen OHNE SSID!. */ + callss2str(tmp, upcall); + + /* Konvertiere IP-Adresse. */ + if ( (addr = inet_addr((const char *)ip_tbl[i].hostname)) == EOF) + { + /* Hostname aufloesen. */ + if ((h = gethostbyname((char *)ip_tbl[i].hostname)) == FALSE) + { + /* ggf. Logbuch fuehren. */ + T_LOGL1(TRUE, "(IPConvConnectOS):\nIP-Adresse/Hostname (%s) konnte nicht aufgeloest werden!\n" + , ip_tbl[i].hostname); + /* Hostname/IP-Adresse ungueltig, abbrechen. */ + return(TRUE); + } + + /* IP-Adresse zuweisen. */ + addr = ((struct in_addr*)h->h_addr)->s_addr; + } + + /* Adressstruktur loeschen */ + memset(&myaddr_in, 0, sizeof(myaddr_in)); + + /* Adressstruktur fuellen */ + myaddr_in.sin_family = AF_INET; + /* Auf tcp_port lauschen. */ + myaddr_in.sin_port = htons(ip_tbl[i].port); + /* Jedes netzwerk-taugliche Geraet abfragen. */ + myaddr_in.sin_addr.s_addr = addr; + + /* Socket erstellen. */ + if ((fd = socket (AF_INET, SOCK_STREAM, 0)) == EOF) + { + /* ggf. Logbuch fuehren. */ + T_LOGL1(TRUE, "(IPConvConnectOS):%s\nNeuer Socket konnte nicht erstellt werden!\n" + , ip_tbl[i].hostname); +#ifdef SPEECH + printf(speech_message(335)); +#else + printf("Error: Socket cannot be constructed!\r"); +#endif + return(TRUE); + } + + /* Connnect Initialisieren. */ + if (connect (fd, (struct sockaddr *) &myaddr_in, sizeof (struct sockaddr_in)) == EOF) + { + /* ggf. Logbuch fuehren. */ + T_LOGL1(TRUE, "(IPConvConnectOS):\nConnect nicht möglich (IP-Addr: %s)!\n" + , ip_tbl[i].hostname); + + /* Schliesse Socket. */ + close(fd); + return(TRUE); + } + + T_LOGL2(TRUE, "(IPConvConnectOS):\nMit IP-Adr./Hostname %s verbunden.\n" + , ip_tbl[i].hostname); + + /* Neues TCPIP-Segment anlegen. */ + if (AddUserOS(ifpp, fd, (char *)ip_tbl[i].hostname)) + { + /* Schliesse Socket. */ + close(fd); + return(TRUE); + } + + /* Markiere Route als Linkpartner. */ + tcppoi->CVSlink = TRUE; + /* Markiere das wir eingeloggt sind. */ + tcppoi->login = TRUE; + /* Markiere, kein prompt senden. */ + tcppoi->LoginPrompt = TRUE; + + /* Maximalwert fuer die Statistik */ + if (++nmbtcp > nmbtcp_max) + nmbtcp_max = nmbtcp; + + /* Mit channel angabe? */ + if (clicnt) + /* Hole channel. */ + ch = atoi(clipoi); + + /* Wenn Nachbar STATUS "User" hat, gleich durch connecten. */ + if ( (!flag) + &&(ip_tbl[i].linkflag == TRUE)) + { + /* ggf. Logbuch fuehren. */ + T_LOGL2(TRUE, "(IPConvConnectOS):\nVerbindung zur IP-Adresse %s hergestellt.\n" + , ip_tbl[i].hostname); + + return(FALSE); + } + + if ((STx = (SENDTX *)allocb(ALLOC_L1IPCONV)) == NULL)/* TX-Segment besorgen. */ + { + /* ggf. Logbuch fuehren. */ + T_LOGL1(TRUE, "(IPConvConnectOS):%s\nSpeicher (%d) ist voll!\n" + , ip_tbl[i].hostname + , nmbfre); + + /* Schliesse Socket. */ + close(fd); + + tcppoi->disflg |= 0x80; /* Segment auf Disconnect setzen. */ + return(TRUE); /* Kein Segment frei, abbruch. */ + } + + if ((STx->Data = SetBuffer()) == NULL) /* Buffer besorgen. */ + { + /* ggf. Logbuch fuehren. */ + T_LOGL1(TRUE, "(IPConvConnectOS):%s\nSpeicher (%d) ist voll!\n" + , ip_tbl[i].hostname + , nmbfre); + + /* Schliesse Socket. */ + close(fd); + + dealoc((MBHEAD *)ulink((LEHEAD *)STx)); /* TX-Segment entsorgen.*/ + + tcppoi->disflg |= 0x80; /* Segment auf Disconnect setzen. */ + return(TRUE); /* Buffer ist voll, abbruch. */ + } + + STx->Sock = tcppoi->sock; /* Socket setzen. */ + STx->Interface = tcppoi->Interface; /* Interface setzen. */ + STx->Mode = tcppoi->mode; /* Stack-Mode setzen. */ + + /* Je nach Status von flag */ + /* demenstsprechend reagieren. */ + if (flag) + putprintf(STx->Data, "ppconvers/\377\200HOST %s %s %s\r", myhostname, myrev, myfeatures); + else + { + /* Wenn Nachbar STATUS "User" hat, gleich durch connecten. */ + if (ip_tbl[i].linkflag == FALSE) + /* Loginstring vorbereiten. */ + putprintf(STx->Data, "/na %s %d\r", tmp, ch); + } + + rwndmb(STx->Data); + /* Umhaengen in die sendesliste. */ + relink((LEHEAD *) STx, (LEHEAD *)rxflTX.tail);/* Umhaengen in die Sendeliste. */ + return(FALSE); +} + +#endif /* OS_IPLINK */ + +/* End of os/win32/osipconv.c */ diff --git a/os/win32/ostcpip.c b/os/win32/ostcpip.c new file mode 100755 index 0000000..e4dd012 --- /dev/null +++ b/os/win32/ostcpip.c @@ -0,0 +1,707 @@ + +#include "tnn.h" +#ifdef OS_STACK + +static T_INTERFACE *ifpp; /* Zeiger auf das aktuelle Interface */ + +struct sockaddr_in myaddr_in; +struct sockaddr_in peeraddr_in; + + +/* Schliesse aktuellen Socket. */ +BOOLEAN CloseSockOS(BOOLEAN ALL, WORD INTERFACE) +{ + int i, + j = 0; +#ifdef DEBUG_MODUS + lastfunc = "ostcpip(CloseSockOS)"; +#endif /* DEBUG_MODUS */ + + /* ALLE Socket-Verbindungen schliessen. */ + if (ALL == TRUE) + { + /* TCPIP-TBL durchgehen. */ + for (i = 0, tcppoi = tcptbl; i < MAXTCPIP; ++i, ++tcppoi) + { + /* Ist Socket noch offen? */ + if ( INTERFACE == tcppoi->Interface + && tcppoi->sock > TRUE) + { + if (tcppoi->mode != OS_MODE) /* Segment kein OS-STACK, */ + continue; /* zum naechsten Segment. */ + + /* Socket schliessen. */ + close(tcppoi->sock); + + /* TCPIP-User/link aus der Liste raushaengen */ + /* bzw. Parameter wieder auf 0 setzen. */ + DiscTCP(); + } + + /* Sind alle aktiven Sockets durchlaufen, */ + if (((tcppoi->activ) && (j++ >= tcp_tbl_top)) || (j == tcp_tbl_top)) + /* brechen wir ab. */ + return(FALSE); + } + } + + /* Socket schliessen. */ + close(tcppoi->sock); + + /* TCPIP-User/Link aus der Liste raushaengen */ + /* bzw. Parameter wieder auf 0 setzen. */ + DiscTCP(); + return(FALSE); +} + +/* TCPIP-Port Initialisierung. */ +BOOLEAN L1InitOS(UWORD Interface, int l2port, unsigned short TCPPort) +{ +#ifdef DEBUG_MODUS + lastfunc = "ostcpip(L1InitOS)"; +#endif /* DEBUG_MODUS */ + + if (l2port == EOF) /* Keine Portangabe!!!. */ + { + printf("(L1InitOS): Fehler, keine L2-Portangabe!!!\n"); + return(FALSE); + } + /* Zeiger auf das aktuelle Interface. */ + if ((ifpp = SearchIf(Interface)) == NULL) + { + printf("(L1InitOS): Fehler, Interface existiert nicht!!!\n"); + return(FALSE); /* Abbrechen. */ + } + /* Einen neuen Filedescriptor anlegen. */ + if ((ifpp->OsSock = SetupOS(ifpp, htons(TCPPort))) == EOF) + return(FALSE); /* Abbrechen. */ + + ifpp->l2port = l2port; /* L2-Port setzen. */ + ifpp->tcpport = TCPPort; /* akt. TCP-Port setzen. */ + + return(TRUE); /* Erfolgreich Socket erstellt. */ +} + +/* TCPIP-Interface schliessen. */ +void L1ExitOS(UWORD Interface) +{ + T_INTERFACE *ifpoi; +#ifdef DEBUG_MODUS + lastfunc = "ostcpip(L1ExitOS)"; +#endif /* DEBUG_MODUS */ + + /* Zeiger auf das aktuelle Interface. */ + if ((ifpoi = SearchIf(Interface)) == NULL) + /* Aktuelles Interface ist deaktiv, */ + /* dann zum naechsten Interface. */ + return; + + /* Alle TCPIP-Verbindungen auf den Interface schliessen. */ + CloseSockOS(TRUE, ifpoi->Interface); + + /* Interface ist nicht aktiv, */ + if (ifpoi->actively == FALSE) + /* damit ist hier schon schluss. */ + return; + + /* TCPIP-Socket schliessen. */ + close(ifpoi->OsSock); + + /* Markiere TCPIP-Interface als deaktiv. */ + ifpoi->actively = FALSE; +} + + /* Einen Filedescriptor anlegen. */ +int SetupOS(T_INTERFACE *ifpp, /* Zeiger auf das aktuelle Interface. */ + unsigned short tcp_port) /* Neuer TCP-Port. */ +{ + int tmp_fd = EOF; /* Temporaerer Filedescriptor */ +#ifdef DEBUG_MODUS + lastfunc = "ostcpip(SetupOS)"; +#endif /* DEBUG_MODUS */ + + if (tcp_port == FALSE) /* Kein Port angegeben. */ + { + T_LOGL1(TRUE, "(SetupOS):\nKein TCP-Port angegeben.\n"); + return(EOF); /* Abbruch. */ + } + + memset(&myaddr_in, 0, sizeof(myaddr_in)); /* Adressstruktur loeschen */ + memset(&peeraddr_in, 0, sizeof(peeraddr_in)); + myaddr_in.sin_family = AF_INET; /* Adressstruktur fuellen */ + myaddr_in.sin_port = htons(tcp_port); /* TCP-Port setzen. */ + myaddr_in.sin_addr.s_addr = INADDR_ANY; /* Jedes Netzwerk Geraet abfragen. */ + + /* Socket erstellen. */ + if ((tmp_fd = socket(AF_INET, SOCK_STREAM, 0)) == EOF) + { + printf("Error %s: Socket cannot be constructed!\r", ifpp->name); + + T_LOGL1(TRUE, "(SetupOS):\nNeuer Socket kann nicht geoeffnet werden.\n"); + return(EOF); /* Keine freien Socket's. */ + } + + /* Bind Initialisieren. */ + if (bind (tmp_fd, (struct sockaddr *) &myaddr_in, sizeof (struct sockaddr_in)) == EOF) + { + printf("Error %s: Bind cannot be initialized!\n", ifpp->name); + close(tmp_fd); /* Schliesse Socket. */ + + T_LOGL1(TRUE, "(SetupOS):\nBind Initialisierung fehlgeschlagen.\n"); + return(EOF); /* Fehler beim Bind . */ + } + + if (listen (tmp_fd, 3) == EOF) /* Listen Initialisieren. */ + { + printf("Error %s: listen cannot be initialized!\n", ifpp->name); + close(tmp_fd); /* Schliesse Socket. */ + + T_LOGL1(TRUE, "(SetupOS):\nListen Initialisierung fehlgeschlagen.\n"); + return(EOF); /* Fehler beim Listen. */ + } + + T_LOGL1(TRUE, "(SetupOS):\nTCP-Port (%d) erfolgreich gesetzt.\n" + , ntohs(tcp_port)); + return(tmp_fd); /* Aktuelle Filedescriptor. */ +} + + +/* Anhand des Sockets den User aus der Liste holen. */ +TCPIP *FdReadOS(fd_set *fds) +{ + int i, + j = 0; + LHEAD *h_llp; + + h_llp = &tcpactl; +#ifdef DEBUG_MODUS + lastfunc = "ostcpip(FdReadOS)"; +#endif /* DEBUG_MODUS */ + + /* TCPIP-TBL durchgehen. */ + for (i = 0, tcppoi = tcptbl; i < MAXTCPIP; ++i, ++tcppoi) + { + if (tcppoi->mode != OS_MODE) + continue; + + /* Nur wenn aktiv! */ + if (tcppoi->activ) + { + /* Vergleiche die Sockets */ + if (FD_ISSET(tcppoi->sock, fds)) + { + /* wir haben einen Link gefunden */ + ulink((LEHEAD *)tcppoi); + relink((LEHEAD *)tcppoi, (LEHEAD *)h_llp->tail); + return(tcppoi); + } + } + /* Sind alle aktiven Sockets durchlaufen, */ + if (((tcppoi->activ) && (j++ >= tcp_tbl_top)) || (j == tcp_tbl_top)) + /* brechen wir ab. */ + break; + } + + /* Keinen Eintrag gefunden. */ + return(NULL); +} + +int ReadSockOS(void) /* Empfangene TCPIP Packete. */ +{ + fd_set fdsI; + struct timeval timevalue; + int ret = EOF; +#ifdef DEBUG_MODUS + lastfunc = "ostcpip(ReadSockOS)"; +#endif /* DEBUG_MODUS */ + + if (tcppoi->rxc >= tcppoi->RecvLen) /* Sind alle Zeichen verarbeitet. */ + { + if (!tcppoi->mode) /* OS-Stack. */ + { + FD_ZERO(&fdsI); /* Inhalt loeschen. */ + FD_SET((unsigned)tcppoi->sock, &fdsI); /* Socket setzen. */ + + timevalue.tv_usec = 0; + timevalue.tv_sec = 0; + /* Pruefe auf aktivitaet. */ + ret = select(tcppoi->sock + 1, &fdsI, NULL , NULL ,&timevalue); + + if (ret <= 0) + return((int)NULL); /* Keine aktivitaet auf den Socket. */ + else + /* Zeichen vom Socket empfangen. */ + tcppoi->RecvLen = recv (tcppoi->sock, tcppoi->rxbuf, RXLEN,0); + } + + if (tcppoi->RecvLen < 1) /* Fehler beim Empfang. */ + { + if (tcppoi->RecvLen == EOF) /* Socket wurde mittlerweile geloes. */ + { + ifpp = SetInterface(tcppoi->Interface); /* akt. Interface setzen. */ + /* ggf. Logbuch fuehren. */ + T_LOGL1(TRUE, "(ReadSockOS):%s\n (Recv) Fehler beim empfang, Segment wird auf DISC gesetzt!\n" + , tcppoi->ip); + + tcppoi->disflg |= 0x80; /* Segment auf DISC stellen. */ + return((int)NULL); + } + + if ( (ret) + &&(tcppoi->RecvLen == 0)) + { + ifpp = SetInterface(tcppoi->Interface); /* akt. Interface setzen. */ + /* ggf. Logbuch fuehren. */ + T_LOGL1(TRUE, "(ReadSockOS):%s\n(Recv) Keine Zeichen, Segment wird auf DISC gesetzt!\n" + , tcppoi->ip); + + tcppoi->disflg |= 0x80; /* Segment auf DISC stellen. */ + return((int)NULL); + } + } + + tcppoi->rxc = 0; /* RX-Zaehler auf 0 setzen. */ + tcppoi->rxbuf[tcppoi->RecvLen] = 0; /* Nullzeichen setzen. */ + /* ggf. Logbuch fuehren. */ + + ifpp = SetInterface(tcppoi->Interface); + T_LOGL3(TRUE, "(ReadSockOS):%s\nInput:\r%s\r" + , tcppoi->ip + , tcppoi->rxbuf); + } + + ret = tcppoi->rxbuf[tcppoi->rxc++]; /* Zeichen vom rxbuf holen. */ + + return(ret); /* Aktuelle Zeichen weiterreichen. */ +} + +static int OsStackReadIndicationsSock(void) /* Zeichen vom Socket einlesen. */ +{ + TRILLIAN ok = ERRORS; + char s; +#ifdef DEBUG_MODUS + lastfunc = "ostcpip(OsStackReadIndicationsSock)"; +#endif /* DEBUG_MODUS */ + + while(1) /* Alle Zeichen von Socket einlesen. */ + { + s = ReadSockOS(); /* Zeichen vom Socket. */ + + if (tcppoi->cmdlen >= RXLEN) /* Maximale Buffergroesse erreicht, */ + { + ifpp = SetInterface(tcppoi->Interface); + T_LOGL1(TRUE, "(OsStackReadIndicationsSock):%s\nMaximale Buffergroesse erreicht!\n" + , tcppoi->ip); + return(TRUE); + } + + switch(tcppoi->Interface) /* Interface. */ + { +#ifdef L1TELNET + case KISS_TELNET : /* TELNET-Server. */ + if ((ok = GetContensTEL(s)) == ERRORS) /* Aktuelle Zeichen auswerten.*/ + break; /* Zeichen verarbeitet, kein Return. */ + else + if (ok == YES) /* Zeichen verarbeitet und Return. */ + { + tcppoi->cmd[tcppoi->cmdlen] = 0; /* Nullzeichen setzen. */ + return(TRUE); /* Frame ist komplett. */ + } + else + continue; /* Sind noch Zeichen im RXBUF, */ + /* zum naechsten Zeichen. */ + break; +#endif /* L1TELNET. */ + +#ifdef L1HTTPD + case KISS_HTTPD : /* HTTPD-Server. */ + if ((ok = GetContensHTP(s)) == ERRORS) /* Aktuelle Zeichen auswerten.*/ + break; /* Zeichen verarbeitet, kein Return. */ + else + if (ok == YES) /* Zeichen verarbeitet und Return. */ + { + tcppoi->cmd[tcppoi->cmdlen] = 0; /* Nullzeichen setzen. */ + return(TRUE); /* Frame ist komplett. */ + } + else + continue; /* Sind noch Zeichen im RXBUF, */ + /* zum naechsten Zeichen. */ + break; +#endif /* L1HTTPD. */ + +#ifdef L1IPCONV + /* IPCONV */ + case KISS_IPCONV : + /* Aktuelle Zeichen auswerten. */ + if ((ok = GetContensCVS(s)) == ERRORS) + /* Alle Zeichen verarbeitet, aber kein Return. */ + break; + else + /* Alle Zeichen verarbeitet und Return? */ + if (ok == YES) + { + /* User/Link noch kein Login. */ + if (!tcppoi->login) + { + /* Pruefe auf Login. */ + if (!strncmp(tcppoi->cmd, "/na", 3)) + /* Kein Prompt senden. */ + tcppoi->LoginPrompt = TRUE; + } + tcppoi->cmd[tcppoi->cmdlen] = 0; + /* Frame komplett. */ + return(TRUE); + } + else + /* Sind noch Zeichen im RXBUF,*/ + /* zum naechsten Zeichen. */ + continue; + + break; +#endif /* L1IPCONV */ + +#ifdef L1IRC + /* IPCONV */ + case KISS_IRC : + /* Aktuelle Zeichen auswerten. */ + if ((ok = GetContensCVS(s)) == ERRORS) + /* Alle Zeichen verarbeitet, aber kein Return. */ + break; + else + /* Alle Zeichen verarbeitet und Return? */ + if (ok == YES) + { + /* User/Link noch kein Login. */ + if (!tcppoi->login) + { + /* Pruefe auf Login. */ + if (!strncmp(tcppoi->cmd, "/na", 3)) + /* Kein Prompt senden. */ + tcppoi->LoginPrompt = TRUE; + } + tcppoi->cmd[tcppoi->cmdlen] = 0; + /* Frame komplett. */ + return(TRUE); + } + else + /* Sind noch Zeichen im RXBUF,*/ + /* zum naechsten Zeichen. */ + continue; + + break; +#endif /* L1IPCONV */ + + default : /* Ungueltiges Interface. */ + break; /* Hier werden wir nie kommen. */ + } + + return(FALSE); /* Frame noch nicht komplett. */ + } + + return(FALSE); /* Frame noch nicht komplett. */ +} + +void ServOS(void) /* Empfangene Zeichen in Frames packen. */ +{ + READRX *SRx; + register int i; +#ifdef DEBUG_MODUS + lastfunc = "ostcpip(ServOS)"; +#endif /* DEBUG_MODUS */ + + if (OsStackReadIndicationsSock()) /* Empfangene Zeichen analysieren. */ + { + if(tcppoi->cmdlen > 0) /* Es sind Zeichen im Buffer.*/ + { + if ((SRx = (READRX *)allocb(ALLOC_L1TCPIP)) == NULL)/* RX-Seg. besorgen */ + { + ifpp = SetInterface(tcppoi->Interface); + T_LOGL1(TRUE, "(ServOS):%s\nSpeicher (%d) ist voll!\n" + , tcppoi->ip + , nmbfre); + tcppoi->disflg |= 0x80; /* Segment auf Disconnect setzen. */ + return; /* Kein Segment frei, abbruch. */ + } + + if ((SRx->Data = SetBuffer()) == NULL) /* Buffer besorgen. */ + { + dealoc((MBHEAD *)ulink((LEHEAD *)SRx)); /* RX-Segment entsorgen. */ + + ifpp = SetInterface(tcppoi->Interface); + T_LOGL1(TRUE, "(ServOS):%s\nSpeicher (%d) ist voll!\n" + , tcppoi->ip + , nmbfre); + tcppoi->disflg |= 0x80; /* Segment auf Disconnect setzen. */ + return; /* Buffer ist voll, abbruch. */ + } + + SRx->Sock = tcppoi->sock; /* Socket setzen. */ + SRx->Interface = tcppoi->Interface; /* Inetrface setzen. */ + SRx->Mode = tcppoi->mode; /* Stack-Mode setzen. */ + + for (i = 0; i < tcppoi->cmdlen; ++i) + putchr(tcppoi->cmd[i], SRx->Data); /* Buffer fuellen. */ + + tcppoi->cmdlen = 0; /* Buffer-Zaehler zuruecksetzen. */ + tcppoi->cmd[0] = 0; /* Nullzeichen setzen. */ + + if (tcppoi->activ) /* Nur wenn Socket aktiv. */ + relink((LEHEAD *) SRx, (LEHEAD *)rxflRX.tail);/* Ab in die Empf.-liste*/ + else + { + ifpp = SetInterface(tcppoi->Interface); /* akt. Interface setzen. */ + T_LOGL1(TRUE, "(ServOS):%s\nSegment ist nicht mehr aktiv!\n" + , tcppoi->ip); + + if (SRx->Data != NULL) + dealmb(SRx->Data); /* Buffer entsorgen. */ + + dealoc((MBHEAD *)ulink((LEHEAD *)SRx)); /* RX-Segment entsorgen.*/ + } /* Socket ist nicht mehr aktiv. */ + } /* kein Zeichen im buffer. */ + } /* Frame ist noch nicht komplett. */ +} + +/* Neue User hinzufuegen, vorrausgesetzt es sind noch freie Sockets vorhanden.*/ +int AddUserOS(T_INTERFACE *ifpoi, /* TCP-Interface. */ + unsigned NewSocket, /* Neuer Socket. */ + char *ip) /* IP-Adresse. */ +{ +#ifdef DEBUG_MODUS + lastfunc = "ostcpip(AddUserOS)"; +#endif /* DEBUG_MODUS */ + + while ((LHEAD *)tcpfrel.head != &tcpfrel) + { + tcppoi = (TCPIP *)ulink((LEHEAD *)tcpfrel.head); + SetDefaultWorthTCP(NewSocket, /* Defaultwerte setzen, neuer Socket. */ + ip, /* IP-Adresse. */ + ifpoi->l2port, /* L2-Port. */ + ifpoi->Interface, /* TCPIP-Interface. */ + OS_MODE); /* OS-STack. */ + + ServOS(); /* Empfangene Zeichen in Frames packen. */ + return(FALSE); + } + + ifpp = SetInterface(ifpoi->Interface); /* akt. Interface setzen. */ + /* ggf. Logbuch fuehren. */ + T_LOGL1(TRUE, "(AddUserOS):%s\nKann kein neues TCPIP-Segment anlegen !\n" + , ip); + return(TRUE); +} + +void ListenTCP_OS(void) +{ + fd_set rmask; + struct timeval timevalue; + UWORD Interface = KISS_TCPIP; + int max_fd; + register int i; + int count, + j = 0; +#ifdef DEBUG_MODUS + lastfunc = "ostcpip(ListenTCP_OS)"; +#endif /* DEBUG_MODUS */ + + max_fd = 0; + FD_ZERO(&rmask); + + /* Interface-Socket's setzen. */ + for (i = 0; i < MAXINTERFACE; i++, Interface++) + { + /* Zeiger auf das aktuelle Interface. */ + if ((ifpp = SearchIf(Interface)) == NULL) + continue; + + if (ifpp->actively == FALSE) + continue; + + /* Interface-Socket setzen. */ + FD_SET((unsigned)ifpp->OsSock, &rmask); + + if (ifpp->OsSock > max_fd - 1) + max_fd = ifpp->OsSock + 1; + } + + /* User-Socket's setzen. */ + for (i = 0, tcppoi = tcptbl; i < MAXTCPIP; ++i, ++tcppoi) + { + if (tcppoi->activ) /* Nur wenn Interface Socket aktiv! */ + { + if (tcppoi->mode != OS_MODE) /* Kein OS-STACK, */ + continue; /* zum naechsten Segment. */ + + if (tcppoi->sock < 1) /* Kein Socket gesetzt, */ + continue; /* zum naechsten Segment. */ + + FD_SET((unsigned)tcppoi->sock, &rmask); /* Socket setzen */ + + if (tcppoi->sock > max_fd - 1) + max_fd = tcppoi->sock + 1; + } + + if ( ((tcppoi->activ) /* Sind alle aktiven Sockets durchlaufen, */ + && (j++ >= tcp_tbl_top)) + || (j == tcp_tbl_top)) + break; /* brechen wir ab. */ + } + + timevalue.tv_usec = 0; + timevalue.tv_sec = 0; + + count = select(max_fd, &rmask, NULL, NULL, &timevalue); + + if (count < 1) + return; + + Interface = KISS_TCPIP; + + for (i = 0; i < MAXINTERFACE; i++, Interface++) + { + if ((ifpp = SearchIf(Interface)) == NULL) /* Ungueltiges Interface, */ + continue; /* zum naechsten Interface. */ + + if (ifpp->actively == FALSE) /* Interface nicht aktiv, */ + continue; /* zum naechsten Interface. */ + + + if (FD_ISSET(ifpp->OsSock, &rmask)) /* Interface-Socketvergleich. */ + { + char ip[IPADDR + 1]; + int NewSock; + socklen_t addrlen; + ULONG peerip = 0; + char *p = (char *)&peerip; + + addrlen = sizeof peeraddr_in; + + if ((NewSock = accept(ifpp->OsSock, (struct sockaddr *) &peeraddr_in, &addrlen)) != EOF) + { + peerip = peeraddr_in.sin_addr.s_addr; + sprintf (ip, "%d.%d.%d.%d",(p[0] & 255) + ,(p[1] & 255) + ,(p[2] & 255) + ,(p[3] & 255)); + /* Einen Neuen TCPIP-User/Link hinzufuegen. Bekannt */ + /* ist das Interface, der Socket und die IP-Adresse. */ + if (AddUserOS(ifpp, NewSock, ip)) + { + close(NewSock); + return; + } + + /* ggf. Logbuch fuehren. */ + ifpp = SetInterface(tcppoi->Interface); + T_LOGL2(TRUE, "(ListenTCP_OS):\n" + "Verbindung zur IP-Adresse %s angenommen.\n" + "Neu erzeugter Socket ist (%d).\n" + , ip + , NewSock); + return; + } + } + } + + /* Anhand des Sockets den User aus der Liste Holen */ + if ((tcppoi = FdReadOS(&rmask)) != NULL) + { + /* ggf. Logbuch fuehren. */ + ifpp = SetInterface(tcppoi->Interface); + + T_LOGL3(TRUE, "(ListenTCP_OS):%s\nAktuellen Socket (%d) in der Liste gefunden.\n" + , tcppoi->ip + , tcppoi->sock); + + /* TCPIP Packete empfangen/bearbeiten/senden */ + ServOS(); + return; + } +} + + +/* Frame aus der Sendeliste senden. */ +int PutflushSockOS(void) +{ + int ok = FALSE; + int ret = FALSE; +#ifdef DEBUG_MODUS + lastfunc = "ostcpip(PutflushSockOS)"; +#endif /* DEBUG_MODUS */ + + if (tcppoi->txc) /* Gibt es was zu senden. */ + { + while (1) /* Gibt es was zu senden. */ + { + fd_set wfdsI; + struct timeval Tv; + + FD_ZERO(&wfdsI); /* Loesche inhalt. */ + FD_SET((unsigned)tcppoi->sock, &wfdsI); /* Socket setzen. */ + + if (select(tcppoi->sock + 1, NULL, &wfdsI , NULL ,&Tv))/* Sender frei.*/ + { + if (tcppoi->txstatus == TCP_TX_BUSY) /* Sender ist auf Busy. */ + tcppoi->txstatus = TCP_TX_FREE; /* Sender auf frei stellen. */ + + /* Frame senden */ + if ((ok = send(tcppoi->sock, tcppoi->txbuf + tcppoi->sum, tcppoi->txc - tcppoi->sum,0)) < 0) + { + ifpp = SetInterface(tcppoi->Interface); + T_LOGL1(TRUE, "(PutflushSockTCP):%s\nFrame senden fehlgeschlagen!\n" + , tcppoi->ip); + + tcppoi->disflg |= 0x80; /* Segment auf Disconnect setzen. */ + return(TRUE); /* Abbruch. */ + } + + ifpp = SetInterface(tcppoi->Interface); /* ggf. Logbuch fuehren. */ + T_LOGL3(TRUE, "(PutflushSockOS):%s\nOutput:\r%s\r" + , tcppoi->ip + , tcppoi->txbuf); + + tcppoi->sum += ok; /* Markiere, gesendete Zeichen. */ + + if (tcppoi->sum == tcppoi->txc) /* Alle Zeichen gesendet. */ + break; /* Schleife verlassen. */ + + } + + if (ret == FALSE) /* Sender ist nicht frei. */ + { + tcppoi->txstatus = TCP_TX_BUSY; /* Sender auf Busy stellen. */ + return(FALSE); + } + } + + tcppoi->sum = 0; /* Zuruecksetzen. */ + tcppoi->txc = 0; + tcppoi->txbuf[0] = 0; + } + + return(FALSE); +} + +BOOLEAN CheckSocketOS(void) +{ + int ok = EOF; +#ifdef DEBUG_MODUS + lastfunc = "ostcpip(CheckSocketOS)"; +#endif /* DEBUG_MODUS */ + + if ((ok = send(tcppoi->sock, "", 0, 0)) < 0) /* Socket noch aktiv. */ + { + ifpp = SetInterface(tcppoi->Interface); + T_LOGL1(TRUE, "(CheckSocket):%s\nSocket ist nicht mehr aktiv!\n" + , tcppoi->ip); + + tcppoi->disflg |= 0x80; /* Segment auf DISC setzen. */ + return(TRUE); /* Socket ist nicht mehr aktiv */ + } + else + return(FALSE); /* Socket ist aktiv. */ +} + +#endif /* OS_STACK */ + +/* End of os/linux/ostcpip.h */ diff --git a/os/win32/sys/dirent32.c b/os/win32/sys/dirent32.c new file mode 100755 index 0000000..dd19d83 --- /dev/null +++ b/os/win32/sys/dirent32.c @@ -0,0 +1,88 @@ +#include "dirent32.h" + +/* Verzeichniss offnen. */ +DIR *opendir(const char *dir) +{ + DIR *dp; + char *filespec; + long handle; + int index; + + filespec = malloc(strlen(dir) + 2 + 1); + strcpy(filespec, dir); + index = strlen(filespec) - 1; + if (index >= 0 && (filespec[index] == '/' || filespec[index] == '\\')) + filespec[index] = '\0'; + + strcat(filespec, "/*"); + + dp = (DIR *)malloc(sizeof(DIR)); + dp->offset = 0; + dp->finished = 0; + dp->dir = strdup(dir); + + if ((handle = _findfirst(filespec, &(dp->fileinfo))) < 0) + { + if (handle == -1) + { + closedir(dp); + return NULL; + } + + if (errno == ENOENT) + dp->finished = 1; + else + { + closedir(dp); + return NULL; + } + } + + dp->handle = handle; + free(filespec); + + return dp; +} + +/* Dateien aus Verzeichnis lesen. */ +struct dirent *readdir(DIR *dp) +{ + if (!dp || dp->finished) + return NULL; + + if (dp->offset != 0) + { + if (_findnext(dp->handle, &(dp->fileinfo)) < 0) + { + dp->finished = 1; + return NULL; + } + } + dp->offset++; + + strncpy(dp->dent.d_name, dp->fileinfo.name, _MAX_FNAME); + dp->dent.d_ino = 1; + dp->dent.d_reclen = strlen(dp->dent.d_name); + dp->dent.d_off = dp->offset; + + return&(dp->dent); +} + +/* Verzeichnis schliessen. */ +int closedir(DIR *dp) +{ + if (!dp) + return 0; + + _findclose(dp->handle); + + if (dp->dir) + free(dp->dir); + + if (dp) + free(dp); + + return 0; +} + +/* End of os/win32/dirent.c */ diff --git a/os/win32/sys/dirent32.h b/os/win32/sys/dirent32.h new file mode 100755 index 0000000..a8c8948 --- /dev/null +++ b/os/win32/sys/dirent32.h @@ -0,0 +1,31 @@ +#include +#include +#include +#include "fnmatch.h" +#include +#include + +struct dirent +{ + long d_ino; /* inode (always 1 in WIN32) */ + off_t d_off; /* offset to this dirent */ + unsigned short d_reclen; /* length of d_name */ + char d_name[_MAX_FNAME+1]; /* filename (null terminated) */ +}; + +typedef struct +{ + long handle; /* _findfirst/_findnext handle */ + short offset; /* offset into directory */ + short finished; /* 1 if there are not more files */ + struct _finddata_t fileinfo; /* from _findfirst/_findnext */ + char *dir; /* the dir we are reading */ + struct dirent dent; /* the dirent to return */ +} DIR; + +DIR *opendir(const char *); +int closedir(DIR *); +struct dirent *readdir(DIR *); +void rewinddir(DIR *); + +/* End of os/win32/dirent.h */ diff --git a/os/win32/sys/fnmatch.c b/os/win32/sys/fnmatch.c new file mode 100755 index 0000000..452088e --- /dev/null +++ b/os/win32/sys/fnmatch.c @@ -0,0 +1,183 @@ +#include +#include "fnmatch.h" + +int +fnmatch (const char *pattern, const char *string, int flags) +{ + register const char *p = pattern, *n = string; + register char c; + + if ((flags & ~__FNM_FLAGS) != 0) + { + errno = EINVAL; + return -1; + } + + while ((c = *p++) != '\0') + { + switch (c) + { + case '?': + if (*n == '\0') + return FNM_NOMATCH; + else if ((flags & FNM_PATHNAME) && *n == '/') + return FNM_NOMATCH; + else if ((flags & FNM_PERIOD) && *n == '.' && + (n == string || ((flags & FNM_PATHNAME) && n[-1] == '/'))) + return FNM_NOMATCH; + break; + + case '\\': + if (!(flags & FNM_NOESCAPE)) + c = *p++; + if (*n != c) + return FNM_NOMATCH; + break; + + case '*': + if ((flags & FNM_PERIOD) && *n == '.' && + (n == string || ((flags & FNM_PATHNAME) && n[-1] == '/'))) + return FNM_NOMATCH; + + for (c = *p++; c == '?' || c == '*'; c = *p++, ++n) + if (((flags & FNM_PATHNAME) && *n == '/') || + (c == '?' && *n == '\0')) + return FNM_NOMATCH; + + if (c == '\0') + return 0; + + { + char c1 = (!(flags & FNM_NOESCAPE) && c == '\\') ? *p : c; + for (--p; *n != '\0'; ++n) + if ((c == '[' || *n == c1) && + fnmatch(p, n, flags & ~FNM_PERIOD) == 0) + return 0; + return FNM_NOMATCH; + } + + case '[': + { + /* Nonzero if the sense of the character class is inverted. */ + register int not; + + if (*n == '\0') + return FNM_NOMATCH; + + if ((flags & FNM_PERIOD) && *n == '.' && + (n == string || ((flags & FNM_PATHNAME) && n[-1] == '/'))) + return FNM_NOMATCH; + + not = (*p == '!' || *p == '^'); + if (not) + ++p; + + c = *p++; + for (;;) + { + register char cstart = c, cend = c; + + if (!(flags & FNM_NOESCAPE) && c == '\\') + cstart = cend = *p++; + + if (c == '\0') + /* [ (unterminated) loses. */ + return FNM_NOMATCH; + + c = *p++; + + if ((flags & FNM_PATHNAME) && c == '/') + /* [/] can never match. */ + return FNM_NOMATCH; + + if (c == '-' && *p != ']') + { + cend = *p++; + if (!(flags & FNM_NOESCAPE) && cend == '\\') + cend = *p++; + if (cend == '\0') + return FNM_NOMATCH; + c = *p++; + } + + if (*n >= cstart && *n <= cend) + goto matched; + + if (c == ']') + break; + } + if (!not) + return FNM_NOMATCH; + break; + + matched:; + /* Skip the rest of the [...] that already matched. */ + while (c != ']') + { + if (c == '\0') + /* [... (unterminated) loses. */ + return FNM_NOMATCH; + + c = *p++; + if (!(flags & FNM_NOESCAPE) && c == '\\') + /* 1003.2d11 is unclear if this is right. %%% */ + ++p; + } + if (not) + return FNM_NOMATCH; + } + break; + + default: + if (FOLD_FN_CHAR (c) != FOLD_FN_CHAR (*n)) + return FNM_NOMATCH; + } + + ++n; + } + + if (*n == '\0') + return 0; + + return FNM_NOMATCH; +} + +unsigned char +WNT_filename_classes[] = +{ + 0x00,0x01,0x02,0x03, 0x04,0x05,0x06,0x07, + 0x08,0x09,0x0a,0x0b, 0x0c,0x0d,0x0e,0x0f, + 0x10,0x11,0x12,0x13, 0x14,0x15,0x16,0x17, + 0x18,0x19,0x1a,0x1b, 0x1c,0x1d,0x1e,0x1f, + 0x20,0x21,0x22,0x23, 0x24,0x25,0x26,0x27, + 0x28,0x29,0x2a,0x2b, 0x2c,0x2d,0x2e,0x2f, + 0x30,0x31,0x32,0x33, 0x34,0x35,0x36,0x37, + 0x38,0x39,0x3a,0x3b, 0x3c,0x3d,0x3e,0x3f, + 0x40,0x61,0x62,0x63, 0x64,0x65,0x66,0x67, + 0x68,0x69,0x6a,0x6b, 0x6c,0x6d,0x6e,0x6f, + 0x70,0x71,0x72,0x73, 0x74,0x75,0x76,0x77, + 0x78,0x79,0x7a,0x5b, 0x2f,0x5d,0x5e,0x5f, + 0x60,0x61,0x62,0x63, 0x64,0x65,0x66,0x67, + 0x68,0x69,0x6a,0x6b, 0x6c,0x6d,0x6e,0x6f, + 0x70,0x71,0x72,0x73, 0x74,0x75,0x76,0x77, + 0x78,0x79,0x7a,0x7b, 0x7c,0x7d,0x7e,0x7f, + 0x80,0x81,0x82,0x83, 0x84,0x85,0x86,0x87, + 0x88,0x89,0x8a,0x8b, 0x8c,0x8d,0x8e,0x8f, + 0x90,0x91,0x92,0x93, 0x94,0x95,0x96,0x97, + 0x98,0x99,0x9a,0x9b, 0x9c,0x9d,0x9e,0x9f, + 0xa0,0xa1,0xa2,0xa3, 0xa4,0xa5,0xa6,0xa7, + 0xa8,0xa9,0xaa,0xab, 0xac,0xad,0xae,0xaf, + 0xb0,0xb1,0xb2,0xb3, 0xb4,0xb5,0xb6,0xb7, + 0xb8,0xb9,0xba,0xbb, 0xbc,0xbd,0xbe,0xbf, + 0xc0,0xc1,0xc2,0xc3, 0xc4,0xc5,0xc6,0xc7, + 0xc8,0xc9,0xca,0xcb, 0xcc,0xcd,0xce,0xcf, + 0xd0,0xd1,0xd2,0xd3, 0xd4,0xd5,0xd6,0xd7, + 0xd8,0xd9,0xda,0xdb, 0xdc,0xdd,0xde,0xdf, + 0xe0,0xe1,0xe2,0xe3, 0xe4,0xe5,0xe6,0xe7, + 0xe8,0xe9,0xea,0xeb, 0xec,0xed,0xee,0xef, + 0xf0,0xf1,0xf2,0xf3, 0xf4,0xf5,0xf6,0xf7, + 0xf8,0xf9,0xfa,0xfb, 0xfc,0xfd,0xfe,0xff, +}; + +/* End of os/win32/fnmatch.c */ + diff --git a/os/win32/sys/fnmatch.h b/os/win32/sys/fnmatch.h new file mode 100755 index 0000000..914558b --- /dev/null +++ b/os/win32/sys/fnmatch.h @@ -0,0 +1,41 @@ +/* Copyright (C) 1992 Free Software Foundation, Inc. +This file is part of the GNU C Library. + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +The GNU C Library 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 +Library General Public License for more details. */ + +#ifndef _FNMATCH_H + +#define _FNMATCH_H 1 + +/* Bits set in the FLAGS argument to `fnmatch'. */ +#undef FNM_PATHNAME +#define FNM_PATHNAME (1 << 0)/* No wildcard can ever match `/'. */ +#undef FNM_NOESCAPE +#define FNM_NOESCAPE (1 << 1)/* Backslashes don't quote special chars. */ +#undef FNM_PERIOD +#define FNM_PERIOD (1 << 2)/* Leading `.' is matched only explicitly. */ +#undef __FNM_FLAGS +#define __FNM_FLAGS (FNM_PATHNAME|FNM_NOESCAPE|FNM_PERIOD) + +/* Value returned by `fnmatch' if STRING does not match PATTERN. */ +#undef FNM_NOMATCH +#define FNM_NOMATCH 1 + +/* Match STRING against the filename pattern PATTERN, + returning zero if it matches, FNM_NOMATCH if not. */ +extern int fnmatch (const char *pattern, const char *string, int flags); + +# define FOLD_FN_CHAR(c) (WNT_filename_classes[(unsigned char) (c)]) +extern unsigned char WNT_filename_classes[]; + +#endif /* fnmatch.h */ + +/* End of os/win32/fnmatch.h */ diff --git a/os/win32/sys/strings.c b/os/win32/sys/strings.c new file mode 100755 index 0000000..ba0d81b --- /dev/null +++ b/os/win32/sys/strings.c @@ -0,0 +1,59 @@ +#include + +int strcasecmp(const char *Dest, const char *Source) +{ + char tDest[1024 + 1]; + char tSource[1024 + 1]; + + /* Leere Strings koennen wir nicht bearbeiten. */ + if ( (Source[0] == 0) + ||(Dest[0] == 0)) + return(1); + + /* Sicherung */ + strncpy(tSource, Source, 1024); + strncpy(tDest, Dest, 1024); + + /* Umwandeln in Grossbuchstaben. */ + strupr(tSource); + strupr(tDest); + + /* Sting vergleichen. */ + if (strcmp(tSource, tDest) == 0) + /* Strings passt. */ + return(0); + else + /* String stimmt nicht ueberein. */ + return(1); +} + +#ifdef _MSC_VER /* Nur fuer VC */ +int strncasecmp(const char *Dest, const char *Source, int len) +{ + char tSource[1024 + 1]; + char tDest[1024 + 1]; + + /* Leere Strings koennen wir nicht bearbeiten. */ + if ( (Source[0] == 0) + ||(Dest[0] == 0)) + return(1); + + /* Sicherung */ + strncpy(tSource, Source, 1024); + strncpy(tDest, Dest, 1024); + + /* Umwandeln in Grossbuchstaben. */ + strupr(tSource); + strupr(tDest); + + /* Sting vergleichen. */ + if (strncmp(tSource, tDest, len) == 0) + /* Strings passt. */ + return(0); + else + /* String stimmt nicht ueberein. */ + return(1); +} +#endif + +/* End of os/win32/strings.h */ diff --git a/os/win32/sys/strings.h b/os/win32/sys/strings.h new file mode 100755 index 0000000..4e6b02f --- /dev/null +++ b/os/win32/sys/strings.h @@ -0,0 +1,11 @@ +#define _STINGS_C + +#ifndef strcasecmp +int strcasecmp(const char *, const char *); +#endif + +#ifdef _MSC_VER /* Nur fuer VC */ +int strncasecmp(const char *, const char *, int); +#endif + +/* End of os/win32/sys/stings.h */ diff --git a/os/win32/tnn32/TNN179.PAS b/os/win32/tnn32/TNN179.PAS new file mode 100755 index 0000000..42ec6c1 --- /dev/null +++ b/os/win32/tnn32/TNN179.PAS @@ -0,0 +1,35 @@ +; TheNetNode Configuration File +; +; DO NOT CHANGE THE ORDER OF THE CONFIGURATION LINES ! +; DO NOT CLEAR ANY LINES ! +; +; NET/ROM-Sysop-Password, 80 Characters (01234567890123...) +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +; +; Console Password +m +; +; Node Ident (Test) +TEST +; +; Node MyCall (XX0XX) +CB1GRH +; +; Workpath, Path to the Help-Files (TNN\) +; TNN should be started from this path. +F:\BACKUP\TNN\ +; +; Path to the executable Text-Files (TNN\TEXTCMD\) +F:\BACKUP\TNN\TEXTCMD\ +; +; Path to the extern Programs for User (TNN\USEREXE\) +F:\BACKUP\TNN\USEREXE\ +; +; Path to the extern Programs only for Sysop (TNN\SYSEXE\) +F:\BACKUP\TNN\SYSEXE\ +; +; Path fuer HTML (/usr/local/httpd/htdocs/) +F:\BACKUP\TNN\PACSAT\ +; +; Path fuer HTML (/usr/local/httpd/htdocs/) +F:\BACKUP\TNN\HTTP\ diff --git a/os/win32/tnn32/icon1.ico b/os/win32/tnn32/icon1.ico new file mode 100755 index 0000000..406d27d Binary files /dev/null and b/os/win32/tnn32/icon1.ico differ diff --git a/os/win32/tnn32/resource.h b/os/win32/tnn32/resource.h new file mode 100755 index 0000000..518f634 --- /dev/null +++ b/os/win32/tnn32/resource.h @@ -0,0 +1,16 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Developer Studio generated include file. +// Used by tnn32.rc +// +#define IDI_ICON1 101 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 102 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1000 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/os/win32/tnn32/tnn32.dsp b/os/win32/tnn32/tnn32.dsp new file mode 100755 index 0000000..9e994a5 --- /dev/null +++ b/os/win32/tnn32/tnn32.dsp @@ -0,0 +1,529 @@ +# Microsoft Developer Studio Project File - Name="tnn32" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** NICHT BEARBEITEN ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=tnn32 - Win32 Debug +!MESSAGE Dies ist kein gültiges Makefile. Zum Erstellen dieses Projekts mit NMAKE +!MESSAGE verwenden Sie den Befehl "Makefile exportieren" und führen Sie den Befehl +!MESSAGE +!MESSAGE NMAKE /f "tnn32.mak". +!MESSAGE +!MESSAGE Sie können beim Ausführen von NMAKE eine Konfiguration angeben +!MESSAGE durch Definieren des Makros CFG in der Befehlszeile. Zum Beispiel: +!MESSAGE +!MESSAGE NMAKE /f "tnn32.mak" CFG="tnn32 - Win32 Debug" +!MESSAGE +!MESSAGE Für die Konfiguration stehen zur Auswahl: +!MESSAGE +!MESSAGE "tnn32 - Win32 Release" (basierend auf "Win32 (x86) Console Application") +!MESSAGE "tnn32 - Win32 Debug" (basierend auf "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "tnn32 - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD BASE RSC /l 0x407 /d "NDEBUG" +# ADD RSC /l 0x407 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 + +!ELSEIF "$(CFG)" == "tnn32 - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD CPP /nologo /MT /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /FR /YX /FD /GZ /c +# ADD BASE RSC /l 0x407 /d "_DEBUG" +# ADD RSC /l 0x407 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept + +!ENDIF + +# Begin Target + +# Name "tnn32 - Win32 Release" +# Name "tnn32 - Win32 Debug" +# Begin Group "include" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\..\include\all.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\include\allmodif.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\include\conversd.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\include\cvs_cmds.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\include\function.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\include\global.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\include\host.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\include\icmp.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\include\ip.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\include\ipv.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\include\l1attach.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\include\l1httpd.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\include\l1ipconv.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\include\l1irc.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\include\l1tcpip.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\include\l1telnet.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\include\l2.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\include\l2s.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\include\l3global.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\include\l3local.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\include\l3sock.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\include\l3tcp.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\include\l3thenet.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\include\l4.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\include\l7.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\include\ostcpip.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\include\profil.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\include\profiler.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\include\speech.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\include\stat.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\include\system.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\include\tnn.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\include\typedef.h +# End Source File +# End Group +# Begin Group "os" + +# PROP Default_Filter "" +# Begin Group "win32" + +# PROP Default_Filter "" +# Begin Group "sys" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\sys\dirent32.c +# End Source File +# Begin Source File + +SOURCE=..\sys\dirent32.h +# End Source File +# Begin Source File + +SOURCE=..\sys\fnmatch.c +# End Source File +# Begin Source File + +SOURCE=..\sys\fnmatch.h +# End Source File +# Begin Source File + +SOURCE=..\sys\strings.c +# End Source File +# Begin Source File + +SOURCE=..\sys\strings.h +# End Source File +# End Group +# Begin Source File + +SOURCE=..\6pack.c +# End Source File +# Begin Source File + +SOURCE=..\6pack.h +# End Source File +# Begin Source File + +SOURCE=..\ax25ip.c +# End Source File +# Begin Source File + +SOURCE=..\ax25ip.h +# End Source File +# Begin Source File + +SOURCE=..\init.c +# End Source File +# Begin Source File + +SOURCE=..\l1attach.c +# End Source File +# Begin Source File + +SOURCE=..\l1win32.c +# End Source File +# Begin Source File + +SOURCE=..\osipconv.c +# End Source File +# Begin Source File + +SOURCE=..\ostcpip.c +# End Source File +# Begin Source File + +SOURCE=..\win32.c +# End Source File +# Begin Source File + +SOURCE=..\win32.h +# End Source File +# Begin Source File + +SOURCE=..\winclude.h +# End Source File +# End Group +# End Group +# Begin Group "src" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\..\src\buffer.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\src\callstr.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\src\cvs_cmds.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\src\cvs_cvrt.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\src\cvs_cvsd.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\src\cvs_serv.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\src\file.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\src\global.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\src\graph.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\src\l1httpd.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\src\l1ipconv.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\src\l1irc.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\src\l1tcpip.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\src\l1telnet.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\src\l2dama.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\src\l2misc.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\src\l2rx.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\src\l2stma.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\src\l2timer.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\src\l2tx.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\src\l3inp.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\src\l3ip.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\src\l3misc.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\src\l3nbr.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\src\l3netrom.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\src\l3rtt.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\src\l3sock.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\src\l3tab.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\src\l3tcp.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\src\l3thenet.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\src\l3var.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\src\l3vc.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\src\l4.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\src\l7.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\src\l7ccp.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\src\l7cmds.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\src\l7conn.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\src\l7host.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\src\l7hstcmd.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\src\l7ip.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\src\l7moni.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\src\l7showl3.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\src\l7time.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\src\l7utils.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\src\main.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\src\mh.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\src\pacsat.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\src\pacserv.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\src\profil.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\src\profiler.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\src\speech.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\src\version.c +# End Source File +# End Group +# Begin Group "Ressourcen" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=.\icon1.ico +# End Source File +# Begin Source File + +SOURCE=.\tnn32.rc +# End Source File +# End Group +# End Target +# End Project diff --git a/os/win32/tnn32/tnn32.dsw b/os/win32/tnn32/tnn32.dsw new file mode 100755 index 0000000..915907d --- /dev/null +++ b/os/win32/tnn32/tnn32.dsw @@ -0,0 +1,89 @@ +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNUNG: DIESE ARBEITSBEREICHSDATEI DARF NICHT BEARBEITET ODER GELÖSCHT WERDEN! + +############################################################################### + +Project: "help"=..\TOOLS\help\help.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "msg"=..\TOOLS\msg\msg.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "msy"=..\TOOLS\msy\msy.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "pfhadd"=..\TOOLS\pfhadd\pfhadd.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "tnn32"=.\tnn32.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "top"=..\TOOLS\top\top.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/os/win32/tnn32/tnn32.opt b/os/win32/tnn32/tnn32.opt new file mode 100755 index 0000000..515357c Binary files /dev/null and b/os/win32/tnn32/tnn32.opt differ diff --git a/os/win32/tnn32/tnn32.plg b/os/win32/tnn32/tnn32.plg new file mode 100755 index 0000000..ce12098 --- /dev/null +++ b/os/win32/tnn32/tnn32.plg @@ -0,0 +1,221 @@ + + +
+

Erstellungsprotokoll

+

+--------------------Konfiguration: tnn32 - Win32 Debug-------------------- +

+

Befehlszeilen

+Creating command line "rc.exe /l 0x407 /fo"Debug/tnn32.res" /d "_DEBUG" "F:\BACKUP\THENETNODE\Juli\179cb53_aug\os\win32\tnn32\tnn32.rc"" +Erstellen der temporären Datei "C:\DOKUME~1\OlliK\LOKALE~1\Temp\RSPAD.tmp" mit Inhalten +[ +/nologo /MT /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /FR"Debug/" /Fp"Debug/tnn32.pch" /YX /Fo"Debug/" /Fd"Debug/" /FD /GZ /c +"F:\BACKUP\THENETNODE\Juli\179cb53_aug\os\win32\sys\dirent32.c" +"F:\BACKUP\THENETNODE\Juli\179cb53_aug\os\win32\sys\fnmatch.c" +"F:\BACKUP\THENETNODE\Juli\179cb53_aug\os\win32\sys\strings.c" +"F:\BACKUP\THENETNODE\Juli\179cb53_aug\os\win32\6pack.c" +"F:\BACKUP\THENETNODE\Juli\179cb53_aug\os\win32\ax25ip.c" +"F:\BACKUP\THENETNODE\Juli\179cb53_aug\os\win32\init.c" +"F:\BACKUP\THENETNODE\Juli\179cb53_aug\os\win32\l1attach.c" +"F:\BACKUP\THENETNODE\Juli\179cb53_aug\os\win32\l1win32.c" +"F:\BACKUP\THENETNODE\Juli\179cb53_aug\os\win32\osipconv.c" +"F:\BACKUP\THENETNODE\Juli\179cb53_aug\os\win32\ostcpip.c" +"F:\BACKUP\THENETNODE\Juli\179cb53_aug\os\win32\win32.c" +"F:\BACKUP\THENETNODE\Juli\179cb53_aug\src\buffer.c" +"F:\BACKUP\THENETNODE\Juli\179cb53_aug\src\callstr.c" +"F:\BACKUP\THENETNODE\Juli\179cb53_aug\src\cvs_cmds.c" +"F:\BACKUP\THENETNODE\Juli\179cb53_aug\src\cvs_cvrt.c" +"F:\BACKUP\THENETNODE\Juli\179cb53_aug\src\cvs_cvsd.c" +"F:\BACKUP\THENETNODE\Juli\179cb53_aug\src\cvs_serv.c" +"F:\BACKUP\THENETNODE\Juli\179cb53_aug\src\file.c" +"F:\BACKUP\THENETNODE\Juli\179cb53_aug\src\global.c" +"F:\BACKUP\THENETNODE\Juli\179cb53_aug\src\graph.c" +"F:\BACKUP\THENETNODE\Juli\179cb53_aug\src\l1httpd.c" +"F:\BACKUP\THENETNODE\Juli\179cb53_aug\src\l1ipconv.c" +"F:\BACKUP\THENETNODE\Juli\179cb53_aug\src\l1irc.c" +"F:\BACKUP\THENETNODE\Juli\179cb53_aug\src\l1tcpip.c" +"F:\BACKUP\THENETNODE\Juli\179cb53_aug\src\l1telnet.c" +"F:\BACKUP\THENETNODE\Juli\179cb53_aug\src\l2dama.c" +"F:\BACKUP\THENETNODE\Juli\179cb53_aug\src\l2misc.c" +"F:\BACKUP\THENETNODE\Juli\179cb53_aug\src\l2rx.c" +"F:\BACKUP\THENETNODE\Juli\179cb53_aug\src\l2stma.c" +"F:\BACKUP\THENETNODE\Juli\179cb53_aug\src\l2timer.c" +"F:\BACKUP\THENETNODE\Juli\179cb53_aug\src\l2tx.c" +"F:\BACKUP\THENETNODE\Juli\179cb53_aug\src\l3inp.c" +"F:\BACKUP\THENETNODE\Juli\179cb53_aug\src\l3ip.c" +"F:\BACKUP\THENETNODE\Juli\179cb53_aug\src\l3misc.c" +"F:\BACKUP\THENETNODE\Juli\179cb53_aug\src\l3nbr.c" +"F:\BACKUP\THENETNODE\Juli\179cb53_aug\src\l3netrom.c" +"F:\BACKUP\THENETNODE\Juli\179cb53_aug\src\l3rtt.c" +"F:\BACKUP\THENETNODE\Juli\179cb53_aug\src\l3sock.c" +"F:\BACKUP\THENETNODE\Juli\179cb53_aug\src\l3tab.c" +"F:\BACKUP\THENETNODE\Juli\179cb53_aug\src\l3tcp.c" +"F:\BACKUP\THENETNODE\Juli\179cb53_aug\src\l3thenet.c" +"F:\BACKUP\THENETNODE\Juli\179cb53_aug\src\l3var.c" +"F:\BACKUP\THENETNODE\Juli\179cb53_aug\src\l3vc.c" +"F:\BACKUP\THENETNODE\Juli\179cb53_aug\src\l4.c" +"F:\BACKUP\THENETNODE\Juli\179cb53_aug\src\l7.c" +"F:\BACKUP\THENETNODE\Juli\179cb53_aug\src\l7ccp.c" +"F:\BACKUP\THENETNODE\Juli\179cb53_aug\src\l7cmds.c" +"F:\BACKUP\THENETNODE\Juli\179cb53_aug\src\l7conn.c" +"F:\BACKUP\THENETNODE\Juli\179cb53_aug\src\l7host.c" +"F:\BACKUP\THENETNODE\Juli\179cb53_aug\src\l7hstcmd.c" +"F:\BACKUP\THENETNODE\Juli\179cb53_aug\src\l7ip.c" +"F:\BACKUP\THENETNODE\Juli\179cb53_aug\src\l7moni.c" +"F:\BACKUP\THENETNODE\Juli\179cb53_aug\src\l7showl3.c" +"F:\BACKUP\THENETNODE\Juli\179cb53_aug\src\l7time.c" +"F:\BACKUP\THENETNODE\Juli\179cb53_aug\src\l7utils.c" +"F:\BACKUP\THENETNODE\Juli\179cb53_aug\src\main.c" +"F:\BACKUP\THENETNODE\Juli\179cb53_aug\src\mh.c" +"F:\BACKUP\THENETNODE\Juli\179cb53_aug\src\pacsat.c" +"F:\BACKUP\THENETNODE\Juli\179cb53_aug\src\pacserv.c" +"F:\BACKUP\THENETNODE\Juli\179cb53_aug\src\profil.c" +"F:\BACKUP\THENETNODE\Juli\179cb53_aug\src\profiler.c" +"F:\BACKUP\THENETNODE\Juli\179cb53_aug\src\speech.c" +"F:\BACKUP\THENETNODE\Juli\179cb53_aug\src\version.c" +] +Creating command line "cl.exe @C:\DOKUME~1\OlliK\LOKALE~1\Temp\RSPAD.tmp" +Erstellen der temporären Datei "C:\DOKUME~1\OlliK\LOKALE~1\Temp\RSPAE.tmp" mit Inhalten +[ +kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /incremental:yes /pdb:"Debug/tnn32.pdb" /debug /machine:I386 /out:"Debug/tnn32.exe" /pdbtype:sept +.\Debug\dirent32.obj +.\Debug\fnmatch.obj +.\Debug\strings.obj +.\Debug\6pack.obj +.\Debug\ax25ip.obj +.\Debug\init.obj +.\Debug\l1attach.obj +.\Debug\l1win32.obj +.\Debug\osipconv.obj +.\Debug\ostcpip.obj +.\Debug\win32.obj +.\Debug\buffer.obj +.\Debug\callstr.obj +.\Debug\cvs_cmds.obj +.\Debug\cvs_cvrt.obj +.\Debug\cvs_cvsd.obj +.\Debug\cvs_serv.obj +.\Debug\file.obj +.\Debug\global.obj +.\Debug\graph.obj +.\Debug\l1httpd.obj +.\Debug\l1ipconv.obj +.\Debug\l1irc.obj +.\Debug\l1tcpip.obj +.\Debug\l1telnet.obj +.\Debug\l2dama.obj +.\Debug\l2misc.obj +.\Debug\l2rx.obj +.\Debug\l2stma.obj +.\Debug\l2timer.obj +.\Debug\l2tx.obj +.\Debug\l3inp.obj +.\Debug\l3ip.obj +.\Debug\l3misc.obj +.\Debug\l3nbr.obj +.\Debug\l3netrom.obj +.\Debug\l3rtt.obj +.\Debug\l3sock.obj +.\Debug\l3tab.obj +.\Debug\l3tcp.obj +.\Debug\l3thenet.obj +.\Debug\l3var.obj +.\Debug\l3vc.obj +.\Debug\l4.obj +.\Debug\l7.obj +.\Debug\l7ccp.obj +.\Debug\l7cmds.obj +.\Debug\l7conn.obj +.\Debug\l7host.obj +.\Debug\l7hstcmd.obj +.\Debug\l7ip.obj +.\Debug\l7moni.obj +.\Debug\l7showl3.obj +.\Debug\l7time.obj +.\Debug\l7utils.obj +.\Debug\main.obj +.\Debug\mh.obj +.\Debug\pacsat.obj +.\Debug\pacserv.obj +.\Debug\profil.obj +.\Debug\profiler.obj +.\Debug\speech.obj +.\Debug\version.obj +.\Debug\tnn32.res +] +Erstellen der Befehlzeile "link.exe @C:\DOKUME~1\OlliK\LOKALE~1\Temp\RSPAE.tmp" +

Ausgabefenster

+Ressourcen werden kompiliert... +Kompilierung läuft... +dirent32.c +fnmatch.c +strings.c +6pack.c +ax25ip.c +init.c +l1attach.c +l1win32.c +osipconv.c +ostcpip.c +win32.c +buffer.c +callstr.c +cvs_cmds.c +cvs_cvrt.c +cvs_cvsd.c +cvs_serv.c +file.c +global.c +graph.c +l1httpd.c +l1ipconv.c +l1irc.c +l1tcpip.c +l1telnet.c +l2dama.c +l2misc.c +l2rx.c +l2stma.c +l2timer.c +l2tx.c +l3inp.c +l3ip.c +l3misc.c +l3nbr.c +l3netrom.c +l3rtt.c +l3sock.c +l3tab.c +l3tcp.c +l3thenet.c +l3var.c +l3vc.c +l4.c +l7.c +l7ccp.c +l7cmds.c +l7conn.c +l7host.c +l7hstcmd.c +l7ip.c +l7moni.c +l7showl3.c +l7time.c +l7utils.c +main.c +mh.c +pacsat.c +pacserv.c +profil.c +profiler.c +speech.c +version.c +Linker-Vorgang läuft... + + + +

Ergebnisse

+tnn32.exe - 0 Fehler, 0 Warnung(en) +
+ + diff --git a/os/win32/tnn32/tnn32.rc b/os/win32/tnn32/tnn32.rc new file mode 100755 index 0000000..7df6ac5 --- /dev/null +++ b/os/win32/tnn32/tnn32.rc @@ -0,0 +1,61 @@ +//Microsoft Developer Studio generated resource script. +// +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// Deutsch (Deutschland) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_DEU) + +///////////////////////////////////////////////////////////////////////////// +// +// Icon +// + +// Icon with lowest ID value placed first to ensure application icon +// remains consistent on all systems. +IDI_ICON1 ICON DISCARDABLE "icon1.ico" + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE DISCARDABLE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE DISCARDABLE +BEGIN + "#include ""afxres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE DISCARDABLE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + +#endif // Deutsch (Deutschland) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/os/win32/win32.c b/os/win32/win32.c new file mode 100755 index 0000000..4a25d77 --- /dev/null +++ b/os/win32/win32.c @@ -0,0 +1,1107 @@ +/************************************************************************/ +/* */ +/* ***** ***** */ +/* ***** ***** */ +/* ***** ***** */ +/* ***** ***** */ +/* *************** *************** */ +/* ***************** ***************** */ +/* *************** *************** */ +/* ***** ***** TheNetNode */ +/* ***** ***** Portable */ +/* ***** ***** Network */ +/* ***** ***** Software */ +/* */ +/* File os/win32/win32.c (maintained by: DF6LN) */ +/* */ +/* This file is part of "TheNetNode" - Software Package */ +/* */ +/* Copyright (C) 1998 - 2008 NORD>= 'A') && (*s <= 'Z')) + *s += 'a'-'A'; + s++; + } + return(p); +} + + +/* + String in Grossbuchstaben umwandeln - aus DJGPP GNU-Paket fuer MS-DOS + von D.J. Delorie +*/ + +char * +strupr(char *s) +{ + char *p = s; + while (*s) + { + if ((*s >= 'a') && (*s <= 'z')) + *s += 'A'-'a'; + s++; + } + return(p); +} + +/************************************************************************/ +/* */ +/* Als Ersatz fuer die Funktionen "findfirst" und "findnext" (bei DOS) */ +/* werden die Funktionen "xfindfirst" und "xfindnext" verwendet. Hier */ +/* wird nur der fuer TNN benoetigte Teil in die Struktur ffblk einge- */ +/* tragen. Der zuletzt gefundene Filename muss in ffblk->ff_name erhal- */ +/* ten bleiben, weil dieser beim Aufruf von "xfindnext" gesucht wird. */ +/* */ +/************************************************************************/ + +int +xfindfirst(const char *pathname, struct ffblk *ffblk, int attrib) +{ + char *fnpoi; + DIR *dp; + struct dirent *dirp; + int retval; + + strcpy(ffblk->ff_path, pathname); /* Filename incl. Pfad */ + normfname(ffblk->ff_path); /* '\\' -> '/' */ + fnpoi = strrchr(ffblk->ff_path, FILE_SEP); /* Pfad angegeben? */ + if (fnpoi == NULL) /* - nein .. */ + { + strcpy(ffblk->ff_find, ffblk->ff_path); /* Filename kopieren */ + strcpy(ffblk->ff_path, textpath); /* default: textpath */ + } + else /* mit Pfad */ + { + if (fnpoi == ffblk->ff_path+strlen(ffblk->ff_path)) /* ohne Name */ + return(-1); /* Unsinn */ + strcpy(ffblk->ff_find, ++fnpoi); /* nur Filename */ + *fnpoi = NUL; /* Filename im Pfad loeschen */ + } + + if ((dp = opendir(ffblk->ff_path)) == NULL) /* Directory vorhanden? */ + return(-1); + retval = -1; /* default: nix gefunden */ + while ((dirp = readdir(dp)) != NULL) /* Eintrag vorhanden? */ + { + if ((fnmatch(ffblk->ff_find, dirp->d_name, + FNM_PATHNAME|FNM_PERIOD) != 0)) + continue; + strcpy(ffblk->ff_name, dirp->d_name); + setfiletime(ffblk); + retval = 0; + break; + } + closedir(dp); + return(retval); +} + +/************************************************************************/ +/* */ +/* Erst den zuletzt gefundenen Eintrag suchen (steht in ffblk->ff_name) */ +/* und den darauffolgenden passenden Eintrag zurueckmelden. */ +/* */ +/************************************************************************/ + +int +xfindnext(struct ffblk *ffblk) +{ + DIR *dp; + struct dirent *dirp; + int retval; + + if ((dp = opendir(ffblk->ff_path)) == NULL) return(-1); + retval = -1; /* default: nix gefunden */ + while ((dirp = readdir(dp)) != NULL) + { + if ((fnmatch(ffblk->ff_name, dirp->d_name, + FNM_PATHNAME|FNM_PERIOD) != 0)) + continue; + retval = 1; + break; + } + if (retval == 1) + { + retval = -1; /* default: nix gefunden */ + while ((dirp = readdir(dp)) != NULL) + { + if ((fnmatch(ffblk->ff_find, dirp->d_name, + FNM_PATHNAME|FNM_PERIOD) != 0)) + continue; + strcpy(ffblk->ff_name, dirp->d_name); + setfiletime(ffblk); + retval = 0; + break; + } + } + closedir(dp); + return(retval); +} + +/************************************************************************/ +/* */ +/* Bei xfindfirst und xfindnext Datum und Uhrzeit im Fileblock setzen */ +/* */ +/************************************************************************/ + +static void +setfiletime(struct ffblk *ffblk) +{ + struct stat filestat; + struct tm *filetime; + struct stat FSize; + char fn[MAXPATH]; + + sprintf(fn, "%s%s", ffblk->ff_path, ffblk->ff_name); + stat(fn, &filestat); + filetime = gmtime(&filestat.st_mtime); + ffblk->ff_ftime = ((filetime->tm_sec / 2) & 0x1f) + + ((filetime->tm_min & 0x3f) << 5) + + ((filetime->tm_hour & 0x1f) << 11); + ffblk->ff_fdate = (filetime->tm_mday & 0x1f) + + (((filetime->tm_mon & 0x0f) + 1) << 5) + + (((filetime->tm_year - 80) & 0x7f) << 9); + + if (!stat(ffblk->ff_name, &FSize)) + ffblk->ff_fsize = FSize.st_size; +} + +/************************************************************************/ +/* */ +/* Ermitteln des freien Festplattenplatzes in Bytes. */ +/* */ +/* Damit es fuer grosse Festplatten keinen Ueberlauf gibt (Rueckgabe */ +/* ist vom Typ LONG), wird ab 1GB freiem Speicher immer 1GB zurueck- */ +/* gemeldet - sieht da jemand Probleme? */ +/* */ +/************************************************************************/ + +LONG +getdiskfree(char *path) +{ + DWORD free = 0; + + GetDiskFreeSpace("C:\\", NULL, NULL, NULL, &free); + return(free); +} + +/************************************************************************/ +/* */ +/* Fuer das erweiterte AUTOBIN-Protokoll wird die File-Zeit in einem */ +/* Bitfeld gespeichert (s. Doku zu DPBOX), wie es BC++ bei dem Befehl */ +/* getftime verwendet. Hier wird die Win32-Zeit der letzten Aenderung */ +/* verwendet. */ +/* */ +/************************************************************************/ + +int getftime(int handle, struct ftime *ftimep) +{ + struct stat filestat; + struct tm *filetime; + + if (fstat(handle, &filestat) == -1) + return(-1); + + filetime = gmtime(&filestat.st_mtime); + + ftimep->ft_tsec = filetime->tm_sec / 2; + ftimep->ft_min = filetime->tm_min; + ftimep->ft_hour = filetime->tm_hour; + ftimep->ft_day = filetime->tm_mday; + ftimep->ft_month = filetime->tm_mon + 1; + ftimep->ft_year = filetime->tm_year - 80; + + return(0); +} + +/************************************************************************/ +/* */ +/* 10ms-Ticker updaten */ +/* */ +/************************************************************************/ +void +update_timer(void) +{ + fd_set rmask; + fd_set wmask; + struct timeval timevalue; + int max_fd = 0; + int count; + register int i; + int len; + char buffer[1024]; + static UWORD roundcounter = 1; +#ifndef NO_WATCHDOG + int lasttic10 = tic10; +#endif + + gettimeofday(&tv, &tz); + + tic10 = (tv.tv_sec - tv_old.tv_sec) * 100 + + (tv.tv_usec - tv_old.tv_usec) / 10000; + +#ifndef NO_WATCHDOG + if (tic10 - lasttic10) + if (write(watch_dog[1], "\0", 1) != 1) + exit(1); +#endif + + FD_ZERO(&rmask); + FD_ZERO(&wmask); + + FD_SET((unsigned)consolefd, &rmask); /* Eingabe Console */ + max_fd = 1; + + if (kiss_active) + { + for (i = 0; i < L1PNUM; ++i) + { + if (l1port[i].kisslink < 0) + continue; + +#ifdef VANESSA + if (l1port[i].kisstype == KISS_VAN) + continue; +#endif +#ifdef AX_IPX + if (l1port[i].kisstype == KISS_IPX) + continue; +#endif +#ifdef AX25IP + if (l1port[i].kisstype == KISS_AXIP) + continue; +#endif +#ifdef KERNELIF + if ( (l1port[i].kisstype == KISS_KAX25) + || (l1port[i].kisstype == KISS_KAX25KJD)) + continue; +#endif +#ifdef SIXPACK + if (l1port[i].kisstype == KISS_6PACK) + continue; +#endif + + if (l1port[i].port_active) + { + FD_SET((unsigned)l1port[i].kisslink, &wmask); + if (l1port[i].kisslink > max_fd -1) + max_fd = l1port[i].kisslink + 1; + } + } + } + + /* fuer alle Interfaces die benutzten Filedescriptoren fuer select() */ + /* ermitteln und eintragen */ + for (i = 0; i < L1PNUM; ++i) + { + /* nur aktive Ports bearbeiten */ + if ( (l1port[i].kisslink < 0) || (l1port[i].port_active != TRUE) +#ifdef SIXPACK + || (l1port[i].kisstype == KISS_6PACK) /* der hat hier nichts zu suchen */ +#endif + ) + continue; + + + /* Interfacetypen durchgehen */ + } /* for(...) */ + + timevalue.tv_usec = 10000; + timevalue.tv_sec = 0; + + if (++roundcounter < maxrounds) /* schon genug Runden vergangen? */ + timevalue.tv_usec = 0; + else + roundcounter = 0; /* Durchlaufzaehler ruecksetzen */ + + count = select(max_fd, &rmask, NULL, NULL, &timevalue); + + if (count == -1) + return; + + /* alle Ports durchgehen */ + for (i = 0; i < L1PNUM; ++i) + { + /* unbenutzte Ports nicht bearbeiten */ + if ( (l1port[i].kisslink < 0) || (l1port[i].port_active != TRUE) +#ifdef SIXPACK + || (l1port[i].kisstype == KISS_6PACK) /* der hat hier nichts zu suchen */ +#endif + ) + continue; + } + + if (kiss_active) + { + for (i = 0; i < L1PNUM; ++i) + { + if (l1port[i].kisslink == -1) + continue; +#ifdef AX25IP + if (l1port[i].kisstype == KISS_AXIP) + continue; +#endif +#ifdef SIXPACK + if (l1port[i].kisstype == KISS_6PACK) + continue; +#endif + if (l1port[i].port_active) + if (FD_ISSET(l1port[i].kisslink, &wmask)) + if ((len = read(l1port[i].kisslink, buffer, 1024)) != 0) + framedata_to_queue(i, buffer, len); + } + } +} + +/************************************************************************/ +/* */ +/* Rechner neu starten */ +/* */ +/************************************************************************/ + +void +reboot_system(void) +{ + exit_all(); +/* Hierher wird man wohl nur kommen, wenn tnn nicht als root gestartet */ +/* wurde. Nun gibt es 2 Moeglichkeiten: entweder wir starten von vorne, */ +/* weil die Resourcen ja breits freigegeben wurden, oder aber wir */ +/* beenden das Programm, weil das ja mehr oder weniger gefordert wurde. */ +/* Sinnvoller ist es wohl, wenn wir das Programm verlassen, in der */ +/* Hoffnung, dass es danach regulaer von einem Batch erneut gestartet */ +/* wird. Das ist jedenfalls besser, als nix zu tun. */ + Break(); + exit(1); +} + +/************************************************************************/ +/* */ +/* Shell-Befehl - Win32-spezifischer Teil: */ +/* Das gewuenschte Programm wird als Hintergrundprozess gestartet. */ +/* */ +/************************************************************************/ + +BOOLEAN +tnnshell(char *cmdline) +{ + return(TRUE); +} + +/************************************************************************/ +/* */ +/* Pruefen, ob Kind-Prozesse beendet sind (vom Sysop gestartete externe */ +/* Programme). Bei Zeitueberschreitung wird das Programm mit einer */ +/* entsprechenden Fehlermeldung abgebrochen. */ +/* */ +/************************************************************************/ + +void +shellsrv(void) +{ +} + +/************************************************************************/ +/* */ +/* Daten von der Shell abholen und zum User bringen */ +/* */ +/************************************************************************/ + +void +shell_to_user(void) +{ +} + +/************************************************************************/ +/* */ +/* User-Eingabe in mhdp verarbeiten */ +/* */ +/************************************************************************/ + +BOOLEAN +l7tosh(MBHEAD *mhdp) +{ + if (userpo->status == US_EXTP) /* externer Prozess aktiv? */ + { + if (userpo->child_iactive == FALSE) + { + dealmb(mhdp); /* Abbruchzeile ignorieren */ + userpo->mbhd = NULL; + kill((pid_t *)(userpo->child_pid), SIGKILL); /* Abbruch (Watchdog) */ + putmsg("SHELL ABORTED by User\r"); + userpo->child_pid = 0; /* Prozess ist fertig */ + userpo->child_fd = -1; + userpo->child_iactive = FALSE; + userpo->child_timeout = 0; + userpo->status = US_CCP; + return(TRUE); + } + return (TRUE); + } + return (FALSE); +} + +/************************************************************************/ +/* */ +/* Filenamen pruefen */ +/* */ +/************************************************************************/ + +BOOLEAN +good_file_name(const char *file) +{ + return(TRUE); +} + +/************************************************************************/ +/* */ +/* */ +/************************************************************************/ + +void +tnnexec(char *file) +{ + char filename[MAXPATH+1]; + + strncpy(filename, file, MAXPATH); + filename[MAXPATH] = 0; + + if (xaccess(filename,0)==0) + { + l1exit(); + /* bei DOS16 -> done_umb() */ + exit_timer(); + exit_hardware(); + execl(filename, filename, NULL); + perror("EXEC"); + HALT("tnnexec"); + } +} + +/************************************************************************/ +/* */ +/* */ +/************************************************************************/ + +/* Winsocket Initialisieren. */ +static int startWinsock(void) +{ + WSADATA wsa; + return WSAStartup(MAKEWORD(2,0),&wsa); +} + +void +init_console(void) +{ + console_titel(); + +#ifdef L1TCPIP + /* Interface Initialisieren. */ + InitIFC(); +#endif /* L1TCPIP */ + + setvbuf(stdout, NULL, _IONBF, 0); /* Ausgabe ungepuffert */ + + /* Winsocket Initialisieren. */ + if (startWinsock()) + { +#ifdef SPEECH + printf(speech_message(334)); +#else + printf("Error: Winsock cannot be initialized!\r"); +#endif + return; + } + + if ((consolefd = socket(AF_INET, SOCK_STREAM, 0)) < 0) + return; + + consfile = stdout; +} + +/************************************************************************/ +/* */ +/* */ +/************************************************************************/ + +void +exit_console(void) +{ +} + +/************************************************************************/ +/* */ +/* */ +/************************************************************************/ + +void hputc(char c) +{ + if (!ishmod) + { /* keine Ausgaben im Hostmode */ + if (c == CR) /* nur fuer PC/Console notwenig! */ + putchar('\n'); + else + putchar(c); + } +} + +/* return if character available */ + +BOOLEAN ishget() +{ + if (kbhit()) + { + if (ishmod) + hgetc(); /* im Hostmode Console ignorieren */ + else + return(TRUE); /* im Terminalmode melden, dass was da ist */ + } + + return(FALSE); /* keine Umleitung, also auch nix da */ +} + +/* return if output to console is stopped */ + +BOOLEAN ishput(void) +{ + return(FALSE); +} + +/* get one character from console */ + +char hgetc(void) +{ + #define Prefix 0 + #define ALT_X '-' + char retval = 0; + + if (kbhit()) + { + if ((retval = getch()) == Prefix) + { + if (getch() == ALT_X) + quit_program(0); + } + } + + return(retval); +} + +/************************************************************************/ +/* */ +/* */ +/************************************************************************/ + +BOOLEAN +init_hardware(int argc, char *argv[]) +{ + int scanned = 1; + + umask(0); + time(&sys_time); + + /* Kommandozeilenparameter auswerten */ + /* Den Verbose-Modus schon hier feststellen */ + while (scanned < argc) + { + /* Parameter "-v" (ausfuehrlichere Meldungen) */ + if (strcmp(argv[scanned], "-v") == 0) + { + bVerbose = TRUE; + } + ++scanned; + } + + VMSG("--- Verbose logging started !\n"); + + VMSG("--- Reading ini-file ...\n"); + if (read_init_file(argc, argv)) + return(TRUE); + +/* + if (tnn_errfile[0] != NUL) + { + } +*/ + VMSG("--- Allocating mem for %u buffers ...\n", tnn_buffers); + + RAMBOT = (char *)malloc(tnn_buffers * sizeof(MAX_BUFFER)); + RAMTOP = RAMBOT + tnn_buffers * sizeof(MAX_BUFFER); + + if (RAMBOT == NULL) + { + VMSG("!!! Allocation mem for %ld buffers failed, trying to allocate for %u buffers now ...\n", tnn_buffers, TNN_BUFFERS); + RAMBOT = (char *)malloc(TNN_BUFFERS * sizeof(MAX_BUFFER)); + RAMTOP = RAMBOT + TNN_BUFFERS * sizeof(MAX_BUFFER); + if (RAMBOT == NULL) + { + fprintf(stderr, "malloc for buffers failed\n"); + exit(1); + } + else + tnn_buffers = TNN_BUFFERS; + } + + if (kiss_active) + { + VMSG("--- Initializing KISS-interfaces ...\n"); + if (init_kisslink()) + { + free(RAMBOT); + Break(); + exit(1); + } + } + +#ifndef NO_WATCHDOG + VMSG("--- Initializing watchdog ...\n"); + watchdog_init(); +#endif + + VMSG("--- Installing signal-handlers ...\n"); +#ifdef DEBUG_MODUS + signal(SIGSEGV, sigsegv); + signal(SIGTERM, sigterm); + signal(SIGPIPE, SigPipe); +#endif + + signal(SIGHUP, SIG_IGN); + signal(SIGTSTP, SIG_IGN); + signal(SIGTTIN, SIG_IGN); + signal(SIGTTOU, SIG_IGN); + + gettimeofday(&tv, &tz); + tv_old = tv; + + return(FALSE); +} + +#ifndef NO_WATCHDOG +/************************************************************************/ +/* */ +/* Watchdog - ein vom TNN-Hauptprogramm unabhaengiger Prozess muss */ +/* regelmaessig vom Hauptprogramm Daten erhalten. Bleiben diese Daten */ +/* laenger als 60s aus, wird TNN beendet. */ +/* */ +/************************************************************************/ +static void +watchdog_init(void) +{ +} +#endif + +/************************************************************************/ +/* */ +/* */ +/************************************************************************/ + +void +exit_hardware(void) +{ + free(RAMBOT); + + if (kiss_active) + exit_kisslink(); +} + +#ifdef DEBUG_MODUS +/************************************************************************/ +/* Signalbehandlungsfunktion fuer das Signal SIGTERM */ +/************************************************************************/ +static void +sigterm(int signo) +{ + signal(SIGTERM, SIG_IGN); + printf("sigterm\n"); + quit_program(-1); +} + +void +sigsegv(int signo) +{ + signal(SIGSEGV, SIG_IGN); + printf("\nTheNetNode verursachte einen unbekannten Systemfehler!!!\n"); + printf("Letzte Funktion war: %s\n", lastfunc); + Break(); + + quit_program(-1); +} + +/************************************************************************/ +/* */ +/* Signalbehandlungsfunktion fuer das Signal SIGPIPE */ +/* */ +/* Ursache, in bereits geschlossene Socket-Verbindung schreiben/lesen. */ +/* */ +/************************************************************************/ +void SigPipe(int signo) +{ + signal(SIGPIPE, SIG_IGN); + Break(); +} + +#endif + +/************************************************************************/ +/* */ +/* */ +/************************************************************************/ + +int +exit_all(void) +{ + exit_mh(); /* MH-Liste sichern */ + save_stat(); + save_configuration(); + personalmanager(SAVE, NULL, NULL); /* Pers. Daten fuer Convers */ + + /* noch laufende Shells killen */ + for (userpo = (USRBLK *) usccpl.head; + userpo != (USRBLK *) &usccpl; + userpo = (USRBLK *) userpo->unext) + { + if (userpo->status != US_EXTP) /* externer Prozess aktiv? */ + continue; + + kill((pid_t *)(userpo->child_pid), SIGKILL); /* Abbruch */ + } + + /* Buffer freigeben */ + free(RAMBOT); + + /* Ab hier stehen keine Buffer mehr zur Verfuegung, alles was mit Buffern */ + /* zu tun hat, gibt nun nen Segfault ! */ + + if (kiss_active) + exit_kisslink(); + + printf("\r\n"); + return(0); +} + +static void message_handler(void) +{ + printf("\a\a\n\n*** ACHTUNG ***\n" + "TheNetNode beenden mit ESC QUIT Enter im Konsolen-Fenster !!!.\n"); +} + +BOOL CtrlHandler( DWORD fdwCtrlType ) +{ + switch( fdwCtrlType ) + { + + case CTRL_C_EVENT: + message_handler(); + return( TRUE ); + + // CTRL-CLOSE: confirm that the user wants to exit. + case CTRL_CLOSE_EVENT: + message_handler(); + return( TRUE ); + + // Pass other signals to the next handler. + case CTRL_BREAK_EVENT: + message_handler(); + return FALSE; + + case CTRL_LOGOFF_EVENT: + message_handler(); + return FALSE; + + case CTRL_SHUTDOWN_EVENT: + message_handler(); + return FALSE; + +#ifdef DEBUG_MDOUS + case SIGSEGV: + sigsegv(fdwCtrlType); + return FALSE; +#endif + + default: + return FALSE; + } +} + +void console_titel(void) +{ + TCHAR szOldTitle[MAX_PATH]; + TCHAR szNewTitle[MAX_PATH]; + char call[10]; + + call2str(call,myid); + + if( GetConsoleTitle(szOldTitle, MAX_PATH) ) + { + wsprintf(szNewTitle, TEXT("%s%s)"), signon,call); + + if( !SetConsoleTitle(szNewTitle) ) + printf("SetConsoleTitle failed (%d)\n", GetLastError()); + } +} + +/* Code vom Stefan DAC922. */ +void gettimeofdaywindows(struct timeval *tv, struct timezone *tz) +{ + SYSTEMTIME systm; + FILETIME ftm; + LONGLONG ll; + + GetSystemTime(&systm); + if (!SystemTimeToFileTime(&systm,&ftm)) + exit(1); + + ll = (LONGLONG) ftm.dwHighDateTime; + ll <<= 32; + ll |= (LONGLONG) ftm.dwLowDateTime; + ll -= 116444736000000000; + ll /= 10000000; + tv->tv_sec = (long) ll; + tv->tv_usec = (long) systm.wMilliseconds * 1000; +} + +void kill(HANDLE Handle, WORD flag) +{ + TerminateProcess(Handle, flag); + _endthread(); +} + +/* Ersatz fuer "system("pause"), bei Fernsteuerung */ +/* eines Knotens kann man schlecht eine Taste druecken. */ +void Break(void) +{ + time_t lasttime; + time_t now; + + now = time(NULL); + lasttime = time(NULL); + + while (lasttime + 10 > now) + { + now = time(NULL); + } +} + +#ifdef L1TCPIP +/* Pruefe auf TCPIP-Port's */ +int CheckPortTCP(int port) +{ + switch(kissmode(port)) + { +#ifdef L1TELNET + case KISS_TELNET : + return(TRUE); +#endif /* L1TELNET */ + +#ifdef L1HTTPD + case KISS_HTTPD : + return(TRUE); +#endif /* L1HTTPD */ + +#ifdef L1IPCONV + case KISS_IPCONV : + return(TRUE); +#endif /* L1IPCONV */ + +#ifdef L1IRC + case KISS_IRC : + return(TRUE); +#endif /* L1IRC */ + + default : + return(FALSE); + } + + return(FALSE); +} +#endif /* L1TCPIP */ + +/* + Dummy-Funktionen +*/ + +ULONG +coreleft(void) { return(FALSE); } +void +init_timer(void) {} +void +DIinc(void) {} +void +decEI(void) {} +void +exit_timer(void) {} +void +init_rs232(void) {} + +/* End of os/win32/win32.c */ diff --git a/os/win32/win32.h b/os/win32/win32.h new file mode 100755 index 0000000..8d7580b --- /dev/null +++ b/os/win32/win32.h @@ -0,0 +1,334 @@ +/************************************************************************/ +/* */ +/* ***** ***** */ +/* ***** ***** */ +/* ***** ***** */ +/* ***** ***** */ +/* *************** *************** */ +/* ***************** ***************** */ +/* *************** *************** */ +/* ***** ***** TheNetNode */ +/* ***** ***** Portable */ +/* ***** ***** Network */ +/* ***** ***** Software */ +/* */ +/* File os/win32/win32.h (maintained by: DF6LN) */ +/* */ +/* This file is part of "TheNetNode" - Software Package */ +/* */ +/* Copyright (C) 1998 - 2008 NORD> + +/*------------------ Definitionen der anderen Versionen aufheben -------*/ + +#undef TOKENRING +#undef COMKISS +#undef EXTDEV + +#if defined(i386) && !defined(MIPS) +#define VANESSA +#endif + +#define AX25IP + +/*------------------ Definitionen fuer Win32-Version -------------------*/ + +#define L1PNUM L2PNUM /* max. 16 Schnittstellen im PC */ +#define HOSTQ_BUFLEN 1024 /* Groesse Tastatur-/Bildschirmspeicher */ +#define TNN_BUFFERS 10000 /* Vorgabe Bufferzahl */ + +/* definitions for kiss-commands */ +#define CMD_TXDELAY 1 +#define CMD_PERSIST 2 +#define CMD_SLOTTIME 3 +#define CMD_TXTAIL 4 +#define CMD_FULLDUP 5 +#define CMD_DAMA 6 +#define CMD_TOKEN 6 +#define CMD_TNCRES 0x0d +#define MSG_TOKEN CMD_TOKEN +#define MSG_TNCRES 0x0c +#define MSG_SENTDAMA 0x0e + +/* definitions for different KISS-types */ +#define KISS_NIX -1 +#define KISS_NORMAL 0 +#define KISS_SMACK 1 +#define KISS_RMNC 2 +#define KISS_TOK 3 +#define KISS_VAN 4 +#define KISS_SCC 5 +#define KISS_TF 6 +#define KISS_IPX 7 +#define KISS_AXIP 8 +#define KISS_LOOP 9 +#define KISS_KAX25 10 +#define KISS_KAX25KJD 11 +#define KISS_6PACK 12 + +/* set this to the highest available mode (used for error-checking) */ +#ifndef L1TCPIP +#define KISS_MAX 12 +#endif /* L1TCPIP */ + +/* maximum length of a received frame, TNN does not accept more! */ +#define MAXFRAMELEN L2MFLEN +#define CRCLEN 2 +#define MAXKISSLEN MAXFRAMELEN+CRCLEN + +/* defines for rx_state */ +#define ST_BEGIN 0 +#define ST_PORT 1 +#define ST_DATA 2 +#define ST_ESC 3 +#define ST_TOKCMD 4 +#define ST_TOKEN 5 +#define ST_TNCRES 6 +#define ST_DAMA 7 + +/* special codes used for KISS-protocol */ +#define FEND 0xC0 +#define FESC 0xDB +#define TFEND 0xDC +#define TFESC 0xDD + +#define MAXPATH 255 + +#define ASYNC_SPD_HI 0x0010 /* Use 56000 instead of 38400 bps */ +#define ASYNC_SPD_VHI 0x0020 /* Use 115200 instead of 38400 bps */ +#define ASYNC_SPD_SHI 0x1000 /* Use 230400 instead of 38400 bps */ +#define ASYNC_SPD_WARP 0x1010 /* Use 460800 instead of 38400 bps */ + +#define B9600 9600 +#define B19200 19200 +#define B38400 38400 +#define B57600 57600 + +#define MAXDRIVE 26 +#define MAXDIR 255 +#define MAXFILE 255 +#define MAXEXT 255 + +#define IPTOS_THROUGHPUT 0x08 +#define ENOTCONN WSAENOTCONN +#define EWOULDBLOCK WSAEWOULDBLOCK + +#define SIGHUP 1 +#define SIGKILL 9 +#define SIGPIPE 13 +#define SIGCHLD 17 +#define SIGTSTP 20 +#define SIGTTIN SIGBREAK /* Ctrl-Break sequence */ +#define SIGTTOU SIGABRT /* abnormal termination triggered by abort call */ + +#define findfirst _findfirst +#define findnext _findnext + +#define gettimeofday gettimeofdaywindows +#define vsnprintf _vsnprintf +#define sleep(x) Sleep(x*1000) +#define close closesocket +#define read w_read +#define write w_write + +#define fcntl ioctlsocket +#define F_SETFL FIONBIO +#define FNDELAY &noblockingmode + +#define xtempnam(x, y) tempnam(x, y) + +#define IP_TOS 3 /* IP type of service and preced */ + + +typedef struct +{ + BOOLEAN port_active; /* Hardwareport ist aktiv */ + char device[MAXPATH]; /* Device fuer diesen Port */ + char tnn_lockfile[MAXPATH];/* Lockfile fuer Device dieses Ports */ + int lock; /* Filenummer fuer Lock-File */ + int kisslink; /* Filenummer fuer Device */ + UWORD speed; /* Baudrate des Device */ + WORD speedflag; /* Flag fuer Baudraten > 38400 */ + WORD kisstype; /* 0 = Kiss, 1 = SMACK, 2 = RMNC-KISS, */ + /* 3 = Tokenring, 4 = Vanessa, 5 = SCC, */ + /* 6 = TheFirmware, 7 = IPX, 8 = AX25IP */ + WORD rx_state; + WORD rx_port; + WORD tx_port; + char rx_buffer[MAXKISSLEN]; + char *rx_bufptr; + int rx_buflen; + ULONG bad_frames; /* Zaehler fuer Bad-Frames auf dem Port */ +} DEVICE; + +struct hostqueue { + int first; + int last; + char buffer[HOSTQ_BUFLEN]; + struct hostqueue *next; +}; + +struct ffblk +{ + char ff_path[MAXPATH]; + char ff_find[NAME_MAX]; + char ff_name[NAME_MAX]; + unsigned ff_fdate; + unsigned ff_ftime; + unsigned long ff_fsize; /* Fuer Dateigrosse. */ +}; + +struct ftime +{ + unsigned ft_tsec : 5; + unsigned ft_min : 6; + unsigned ft_hour : 5; + unsigned ft_day : 5; + unsigned ft_month : 4; + unsigned ft_year : 7; +}; + +struct timezone +{ + int tz_minuteswest; /* Minutes west of GMZ */ + int tz_dsttime; /* Nonzero if DST is ever in effect. */ +}; + +typedef unsigned int socklen_t; + +/* ------------------ Globale Variablen der Win32-Version --------------*/ + + extern ULONG tnn_buffers; + extern char tnn_initfile[MAXPATH]; + extern char tnn_dir[MAXPATH]; + extern char tnn_errfile[MAXPATH]; + extern WORD max_device; + extern DEVICE l1port[L1PNUM]; + extern BOOLEAN kiss_active; +#ifdef ATTACH + extern WORD tokenring_ports; + extern WORD sixpack_ports; +#endif /* ATTACH */ + extern WORD used_l1ports; + extern WORD l1ptab[L2PNUM]; + extern WORD l2ptab[L1PNUM]; + extern DEVICE *l1dp; + extern UWORD maxrounds; + + extern LONG bad_frames; + extern time_t last_recovery; + + extern char start_name[MAXPATH]; + extern char stop_name[MAXPATH]; + + char cShell[512]; /* Pfad zu Shell */ + + static u_long noblockingmode = FIONBIO; + /* Variable fuer Winsock Initialisieren. */ + extern int consolefd; + +/* ------------------- Funktionen bei Win32-Version --------------------*/ + +char *strlwr(char *); +char *strupr(char *); +int getftime(int, struct ftime *); +BOOLEAN init_kisslink(void); +void exit_kisslink(void); +void send_kisscmd(int, int, int); +void framedata_to_queue(int, char *, int); +void put_error(char *); +void hputud(unsigned); +void reset_hardware(void); +int exit_all(void); +BOOLEAN read_init_file(int, char *[]); +BOOLEAN init_proc(void); +void exit_proc(void); +void add_tnndir(char *); +void security_check(char *); +BOOLEAN good_file_name(const char *); +char *xtempnam(const char *, const char *); +void calculate_load(void); +void print_load(MBHEAD *); +void shell_to_user(void); +void ccpsetshell(void); + +BOOLEAN good_file_name(const char *); +int getftime(int, struct ftime *); +int exit_all(void); +int open_win (char *, int); +int w_read (int, void *, int); +int w_write (int, void *, int); +int strcasecmp(const char *, const char *); +void console_titel(void); +void gettimeofdaywindows(struct timeval *, struct timezone *); +BOOL CtrlHandler(DWORD); +#ifdef _MSC_VER +int strncasecmp(const char *, const char *, int); +#endif +void kill(HANDLE Handle, WORD flag); +void Break(void); +void SetFileSize(struct ffblk *); + +/* Blocktransfer-Funktionen */ +int cpymbflat(char *, MBHEAD *); +MBHEAD *cpyflatmb(char *, int); + +#ifdef AX25IP +void ax25ip(void); +BOOLEAN ax25ip_l1init(int); +void ax25ip_l1exit(void); +void ax25ip_l1ctl(int, int); +void ax25ip_hwstr(int, MBHEAD *); +BOOLEAN ax25ip_dcd(int); +void ccpaxipr(void); +#endif + +#define kissmode(x) l1port[l1ptab[x]].kisstype +#define CRASH() *((int *) NULL) = 0 + +/* 6PACK */ +#ifdef SIXPACK +void Sixpack_Housekeeping(void); +WORD Sixpack_DCD(UWORD); +void Sixpack_l1init(void); +void Sixpack_l1exit(void); +void Sixpack_l1ctl(int, UWORD); +void ccp6pack(void); +#endif + +#ifdef DEBUG_MODUS +void sigsegv(int); +#endif + +/* End of os/win32/win32.h */ diff --git a/os/win32/winclude.h b/os/win32/winclude.h new file mode 100755 index 0000000..a4814cb --- /dev/null +++ b/os/win32/winclude.h @@ -0,0 +1,31 @@ + +#include +#include +#ifdef _MSC_VER +/* Wird nur im VC benoetig. */ +#include +#endif /* MSC_VER */ +#include +#include +#include +#include +#include +#include +#include +#include "sys/dirent32.h" +#include "sys/fnmatch.h" +#include "sys/strings.h" + +#pragma comment(lib, "ws2_32.lib" ) + +typedef void *pthread_t; +#ifdef _MSC_VER +/* Wird nur im VC benoetig. */ +typedef void *pid_t; +#endif /* MSC_VER */ + +#define NAME_MAX 260 + +/* End of os/win32/winclude.h */ + + diff --git a/src/buffer.c b/src/buffer.c new file mode 100755 index 0000000..2445d6f --- /dev/null +++ b/src/buffer.c @@ -0,0 +1,836 @@ +/************************************************************************/ +/* */ +/* ***** ***** */ +/* ***** ***** */ +/* ***** ***** */ +/* ***** ***** */ +/* *************** *************** */ +/* ***************** ***************** */ +/* *************** *************** */ +/* ***** ***** TheNetNode */ +/* ***** ***** Portable */ +/* ***** ***** Network */ +/* ***** ***** Software */ +/* */ +/* File src/buffer.c (maintained by: DF6LN) */ +/* */ +/* This file is part of "TheNetNode" - Software Package */ +/* */ +/* Copyright (C) 1998 - 2008 NORD>| | -> hd ------->| |-----+ | * +* +--------+ +--------+ | * +* | | | |-------+ * +* +--------+ +--------+ * +* | | | | * +* * +\************************************************************************/ +void +inithd(LHEAD *hd) +{ + hd->head = hd->tail = hd; +} + +/************************************************************************/ +/* Anfang des freien Speichers */ +/*----------------------------------------------------------------------*/ +static char huge * +minmem(void) +{ + return (RAMBOT); +} + +/************************************************************************/ +/* Ende des freien Speichers */ +/*----------------------------------------------------------------------*/ +static char huge * +maxmem(void) +{ + return (RAMTOP); +} + +/************************************************************************/ +/* Buffer-Verwaltung initialisieren. */ +/*----------------------------------------------------------------------*/ +void +init_buffers(void) +{ + MAX_BUFFER huge *actbp; + ULONG n; + + nmblks = nmbfre = nmblks_max = 0; + + actbp = (MAX_BUFFER *)minmem(); + n = (ULONG)((maxmem() - minmem()) / sizeof(MAX_BUFFER)); + +#ifdef __WIN32__ + nmbfre_max = (unsigned short)n; +#else + nmbfre_max = n; +#endif /* WIN32 */ + + while (n--) + { +#ifdef BUFFER_DEBUG + ((MBHEAD *)actbp)->owner = ALLOC_LEHEAD; +#endif + dealoc((MBHEAD *)actbp++); + } + + nmbfre_min = nmbfre; +} + +/************************************************************************\ +* * +* action : Element aus Liste aushaengen. * +* * +* * +* le ---+ * +* vor | raus hinter * +* +--------+ +-->+--------+ +--------+ * +* ----->| |--------->| prevle |--------->| |-----> * +* +--------+ +--------+ +--------+ * +* <-----| |<---------| nextle |<---------| |<----- * +* +--------+ +--------+ +--------+ * +* | | | | | | * +* * +* * +* \/ * +* * +* * +* raus vor hinter * +* +--------+ +--------+ +--------+ * +* le --->| nextle | ----->| |----->| |-----> * +* +--------+ +--------+ +--------+ * +* | prevle | <-----| |<-----| |<----- * +* +--------+ +--------+ +--------+ * +* | | | | | | * +* * +* * + ************************************************************************ +* * +* parameter : le - Zeiger auf auszuhaengendes Listenelement * +* * +* returns : le * +* * +\************************************************************************/ +LEHEAD * +ulink(LEHEAD *le) +{ + le->prevle->nextle = le->nextle; /* Hinliste ohne le */ + le->nextle->prevle = le->prevle; /* Rueckliste ohne le */ + return (le); /* Zeiger auf das Element zurueck */ +} + +/************************************************************************\ +* * +* action : Element in Liste einhaengen. * +* * +* * +* neu vor hinter * +* +--------+ +--------+ +--------+ * +* new --->| nextle | pred --->| |----->| |-----> * +* +--------+ +--------+ +--------+ * +* | prevle | <-----| |<-----| |<----- * +* +--------+ +--------+ +--------+ * +* | | | | | | * +* * +* * +* \/ * +* * +* * +* new ---+ * +* vor | neu hinter * +* +--------+ +-->+--------+ +--------+ * +* pred --->| |--------->| prevle |--------->| |-----> * +* +--------+ +--------+ +--------+ * +* <-----| |<---------| nextle |<---------| |<----- * +* +--------+ +--------+ +--------+ * +* | | | | | | * +* * +* * + ************************************************************************ +* * +* parameter : new - Zeiger auf einzuhaengendes Listenelement * +* pred - Zeiger auf Listenelement, hinter dem new * +* eingehaengt werden soll * +* * +* returns : new * +* * +\************************************************************************/ +LEHEAD * +relink(LEHEAD *new, LEHEAD *pred) +{ + new->nextle = pred->nextle; /* Vorzeiger im neuen Element */ + new->prevle = pred; /* Rueckzeiger im neuen Element */ + new->nextle->prevle = new; /* Rueckzeiger dahinter */ + pred->nextle = new; /* Vorzeiger davor */ + return (new); /* Zeiger auf neues Element */ +} + +/************************************************************************\ +* * +* action : "allocate buffer" * +* * +* Leeren Buffer aus der Freiliste holen, Programmneustart * +* wenn keine Buffer mehr in Freiliste. * +* * + ************************************************************************ +* * +* r/w globals : nmbfre - Anzahl der Buffer in Freiliste freel * +* freel - verkettete Liste der freien Buffer * +* * +* locals : s.u. * +* * +* returns : Zeiger auf freien Buffer, fall vorhanden * +* * +\************************************************************************/ +LEHEAD * +#ifdef BUFFER_DEBUG +allocb(int owner) +#else +allocb(void) +#endif +{ + LEHEAD *ret; /* Buffer Rueckgabewert */ + + nmbfre--; /* 1 Buffer weniger */ + if (nmbfre < nmbfre_min) + nmbfre_min = nmbfre; + if (!nmbfre) /* wenn nicht genug frei */ + { +#ifdef BUFFER_DEBUG + bufstat(); /* Buffernutzung protokollieren */ +#endif + HALT("allocb: no free buffers !"); /* dann Rechner neu starten.. */ + } + ret = ulink((LEHEAD *)freel.head); /* Buffer aus Liste aushaengen */ +#ifdef BUFFER_DEBUG + if (ret->owner != ALLOC_NO_OWNER) + { + bufstat(); /* Buffernutzung protokollieren */ + HALT("allocb: buffer with owner in free-list !"); + } + + ret->owner = (UBYTE)owner; +#endif + return (ret); /* Zeiger auf Freibuffer zurueck */ +} + +/************************************************************************\ +* * +* "deallocate" * +* * +* Buffer, auf den bp zeigt, initialisieren als neuen Messagebufferhead * +* (rwndmb()) und deallokieren, d.h. in die Freiliste freel einhaengen * +* und den Freibufferzaehler nmbfre inkrementieren. * +* * +* * +* +--------+ * +* bp --->| | deallokieren * +* +--------+ * +* | | * +* +--------+ * +* | | * +* * +\************************************************************************/ +void +dealoc(MBHEAD *bp) +{ +#ifdef INSANE_BUFFER_DEBUG + MBPTRCHECK(bp); +#endif + + bp->mbl.head = /* als Messagehead initialisieren */ + bp->mbl.tail = /* Bufferlistenkopf */ + &bp->mbl; /* initialisieren */ + bp->mbpc = 0; /* Message leer */ + bp->mbgc = 0; /* Rest initialisieren */ + bp->mbbp = NULL; +#ifdef BUFFER_DEBUG + if (bp->owner != ALLOC_NO_OWNER) + bp->owner = ALLOC_NO_OWNER; + else + HALT("dealoc: buffer with no owner !"); /* Rechner neu starten.. */ +#endif + rwndmb(bp); /* Buffer an Freiliste anhaengen */ + relink((LEHEAD *)bp, (LEHEAD *)freel.tail); + ++nmbfre; /* 1 Freibuffer mehr */ + if (nmbfre > nmbfre_max) /* > nmbfre_max darf nicht sein! */ + HALT("dealoc: more buffers free than allocated !"); /* neu starten */ +} + +/************************************************************************\ +* * +* "deallocate message buffer" * +* * +* Einen kompletten Messagespeicher, auf dessen Kopf mbhd zeigt, * +* deallokieren, d.h. sowohl den Messagebufferhead als auch alle an * +* dessen Messagebufferliste haengende Datenbuffer deallokieren. * +* * +* * +* +--------+ deallokieren * +* mbhd -->| | * +* +--------+ * +* | | * +* +--------+ +--------+ +--------+ * +* a --->| |----->| |---> --->| |---> a * +* + mbl + +--------+ ... +--------+ * +* b <---| |<-----| |<--- <---| |<--- b * +* +--------+ +--------+ +--------+ * +* | | | | | | * +* * +\************************************************************************/ +void +dealmb(MBHEAD *mbhd) +{ + MB *bp; /* Datenbufferzeiger */ + +#ifdef INSANE_BUFFER_DEBUG + MBPTRCHECK(mbhd); +#endif + +/* alle Datenbuffer */ + while ((bp = (MB *)mbhd->mbl.head) != (MB *)&mbhd->mbl) + dealoc((MBHEAD *)ulink((LEHEAD *)bp)); + dealoc(mbhd); /* Am Ende den Kopf */ +} + +/************************************************************************\ +* * +* "deallocate message list" * +* * +* Komplette Messageliste, auf deren Listenkopf mlp zeigt, deallokieren. * +* D.h. alle Messagespeicher (jeweils Kopf und daran haengende * +* Datenbuffer) deallokieren. * +* * +* * +* +--------+ +--------+ +--------+ * +* mlp --->| head |--->| |---> --->| |---> mlp * +* +--------+ +--------+ ... +--------+ * +* b <---| tail |<---| |<--- <---| |<--- b * +* +--------+ +--------+ +--------+ * +* | |---> \ | |---> \ * +* + + | + + | * +* | |<--- /| | |<--- /| * +* +--------+ | +--------+ | * +* | | | | | | * +* | | * +* deallokieren |------------------------| * +* siehe unten dealmb() * +* * +\************************************************************************/ +/*#include "coredump.c" */ +void +dealml(LEHEAD *mlp) +{ + MBHEAD *bp; /* Zeiger auf Messagebufferhead */ + +#if 0 + int i; + + for (bp = (MBHEAD *)mlp->nextle, i = 0; + bp != (MBHEAD *)mlp; + bp = (MBHEAD *)bp->nextmh) + if (++i > 10000) + { /* Fehler !!! */ + coredump(); + i = *((char *)NULL); /* Zugriff auf NULL-Pointer */ + exit(-1); /* notfalls normaler exit */ + } +#endif + + LOOP /* fuer alle Messagebufferheads */ + { /* in Messagespeicherliste : */ + bp = (MBHEAD *)mlp->nextle; /* Zeiger auf naechsten Msgbhead */ + if (mlp == (LEHEAD *)bp) /* Schwanz beisst Kopf -> fertig */ + break; /* sonst Messagespeicher deallok. */ + dealmb((MBHEAD *)ulink((LEHEAD *)bp)); + } +} + +/************************************************************************\ +* * +* action : "rewind message buffer" * +* * +* Message-Buffer (Kopf und Datenbufferliste) zuruecksetzen. * +* Get-Counter auf 0 setzen, Buffer-Pointer so setzen, dass * +* beim naechsten getchr() auf das das erste Datenbyte des * +* ersten Datenbuffers zugegriffen wird. * +* (Dies muss wie folgt geschehen, da der Get-Counter in * +* jedem Fall auf 0 stehen muss und in getchr() auf % 32 * +* fuer das Positionieren auf den naechsten Datenbuffer * +* abgetestet wird.) * +* * + ************************************************************************ +* * +* parameter : mbhd - Zeiger auf Kopf des Message-Buffers * +* * +\************************************************************************/ +void +rwndmb(MBHEAD *mbhd) +{ +#ifdef INSANE_BUFFER_DEBUG + MBPTRCHECK(mbhd); +#endif + +/* Kopf wie Datenbufferende */ + mbhd->mbbp = (char *)(((MAX_BUFFER huge *)&(mbhd->mbl)) + 1); + mbhd->mbgc = 0; /* Bufferanfang */ +} + +/************************************************************************\ +* * +* action : "put character" * +* * +* Zeichen in Messagebuffer schreiben, Put-Counter erhoehen * +* und Buffer-Pointer setzen. Ist der aktuelle Datenbuffer * +* im Messagebuffer voll, dann neuen Datenbuffer allokieren * +* und ans Datenbufferlistenende des Messagebuffers * +* anhaengen. * +* * + ************************************************************************ +* * +* parameter : ch - in den Buffer zu schreibendes Zeichen * +* mbhd - Zeiger auf den Messagebuffer-Kopf, in den ch * +* zu schreiben ist * +* * +* r/o globals: - * +* * +* r/w globals: - * +* * +* locals : - * +* * +* returns : - * +* * +\************************************************************************/ +void +putchr(char ch, MBHEAD *mbhd) +{ +#ifdef INSANE_BUFFER_DEBUG + MBPTRCHECK(mbhd); +#endif + + if (mbhd->mbpc++ % sizeof_MBDATA == 0) + mbhd->mbbp = ((MB *)(relink((LEHEAD *)allocb(ALLOC_LEHEAD), + (LEHEAD *)mbhd->mbl.tail)))->data; + + *mbhd->mbbp++ = ch; +} + +/************************************************************************\ +* * +* action : "get character" * +* * +* Zeichen aus einem Messagebuffer holen. Datenbuffer-Poiner * +* setzen und Get-Count erhoehen. Uebergang in der * +* Datenbufferliste vom Ende eines Datenbuffers zum * +* naechsten ausfuehren. * +* * + ************************************************************************ +* * +* parameter : mbhd - Zeiger auf Kopf des Messagebuffers, aus dem * +* das Zeichen gelesen werden soll * +* * +* r/o globals: - * +* * +* r/w globals: - * +* * +* locals : - * +* * +* returns : aus dem Buffer gelesenes Zeichen * +* * +\************************************************************************/ +#ifdef __WIN32__ +unsigned char +#else +char +#endif /* WIN32 */ +getchr(MBHEAD *mbhd) +{ +#ifdef INSANE_BUFFER_DEBUG + MBPTRCHECK(mbhd); +#endif + + if (mbhd->mbgc++ % sizeof_MBDATA == 0) + mbhd->mbbp = ((MB *)((MAX_BUFFER huge *)(mbhd->mbbp) - 1))->nextmb->data; + return (*mbhd->mbbp++); +} + +#ifndef MC68K +/************************************************************************ + * Function : 16 Bits aus einem Buffer lesen + * + * Inputs : Zeiger auf den Buffer + * + * Returns : unsigned integer + * + * Operation : Liest 2 Bytes und vertauscht sie + *----------------------------------------------------------------------*/ +UWORD +get16(MBHEAD *mbhd) +{ + UWORD retval; + +#ifdef INSANE_BUFFER_DEBUG + MBPTRCHECK(mbhd); +#endif + + retval = ((UWORD)(getchr(mbhd)) << 8); + retval |= (UWORD)getchr(mbhd); + return (retval); +} + +/************************************************************************ + * Function : Schreibt ein Word in den Buffer + * + * Inputs : Der Wert (Word), Zeiger auf den Buffer + * + * Returns : nothing + * + * Operation : + *----------------------------------------------------------------------*/ +void +put16(UWORD value, MBHEAD *mbhd) +{ +#ifdef INSANE_BUFFER_DEBUG + MBPTRCHECK(mbhd); +#endif + + putchr((BYTE)((value >> 8) & 0xff), mbhd); + putchr((BYTE)(value & 0xff), mbhd); +} + +/************************************************************************ + * Function : 32 Bits aus einem Buffer lesen + * + * Inputs : Zeiger auf den Buffer + * + * Returns : unsigned long integer + * + * Operation : Liest 2 Words und vertauscht sie + *----------------------------------------------------------------------*/ +ULONG +get32(MBHEAD *mbhd) +{ + ULONG retval; + +#ifdef INSANE_BUFFER_DEBUG + MBPTRCHECK(mbhd); +#endif + + retval = ((ULONG)(getchr(mbhd)) << 24); + retval |= ((ULONG)(getchr(mbhd)) << 16); + retval |= ((ULONG)(getchr(mbhd)) << 8); + retval |= (ULONG)getchr(mbhd); + return (retval); +} + +/************************************************************************ + * Function : Schreibt ein Long in den Buffer + * + * Inputs : Der Wert (Long), Zeiger auf den Buffer + * + * Returns : nothing + * + * Operation : + *----------------------------------------------------------------------*/ +void +put32(ULONG value, MBHEAD *mbhd) +{ +#ifdef INSANE_BUFFER_DEBUG + MBPTRCHECK(mbhd); +#endif + + putchr((BYTE)((value >> 24) & 0xff), mbhd); + putchr((BYTE)((value >> 16) & 0xff), mbhd); + putchr((BYTE)((value >> 8) & 0xff), mbhd); + putchr((BYTE)(value & 0xff), mbhd); +} +#else +UWORD +get16(MBHEAD *mbhd) +{ + UWORD retval; + char *r = (UBYTE *)&retval; +#if defined(BUFFER_DEBUG) && defined(__LINUX__) || defined(__WIN32__) + MBPTRCHECK(mbhd); +#endif + + *r++ = getchr(mbhd); + *r = getchr(mbhd); + return (retval); +} + +void +put16(UWORD value, MBHEAD *mbhd) +{ + char *r = (UBYTE *)&value; +#if defined(BUFFER_DEBUG) && defined(__LINUX__) || defined(__WIN32__) + MBPTRCHECK(mbhd); +#endif + + putchr(*r++, mbhd); + putchr(*r, mbhd); +} + +ULONG +get32(MBHEAD *mbhd) +{ + ULONG retval; + char *r = (UBYTE *)&retval; +#if defined(BUFFER_DEBUG) && defined(__LINUX__) || defined(__WIN32__) + MBPTRCHECK(mbhd); +#endif + + *r++ = getchr(mbhd); + *r++ = getchr(mbhd); + *r++ = getchr(mbhd); + *r = getchr(mbhd); + return (retval); +} + +void +put32(ULONG value, MBHEAD *mbhd) +{ + char *r = (UBYTE *)&value; +#if defined(BUFFER_DEBUG) && defined(__LINUX__) || defined(__WIN32__) + MBPTRCHECK(mbhd); +#endif + + putchr(*r++, mbhd); + putchr(*r++, mbhd); + putchr(*r++, mbhd); + putchr(*r, mbhd); +} +#endif + +/************************************************************************\ +* * +* "split copy" * +* * +* Die Bytes aus dem Messagebuffer, auf dessen Kopf mbhd zeigt, in den * +* Framebuffer, auf dessen Kopf fbp zeigt, kopieren. Es werden hoechstens * +* max Bytes kopiert, hat die Message mehr Bytes, so wird ein neuer * +* Messagebuffer angelegt, die restlichen Messagebytes werden in diesen * +* Buffer kopiert, der neue Buffer wird hinter den alten Messagebuffer * +* gehaengt, der Putcount des alten Buffers wird auf max gestellt, das * +* "more follows"-Flag morflg des neuen Buffers wird geloescht, l2fflg * +* wird uebertragen. * +* * +* Return : TRUE - der Messagebuffer wurde aufgesplittet * +* FALSE - sonst * +* * +\************************************************************************/ + +BOOLEAN +splcpy(WORD max, MBHEAD *fbp, MBHEAD *mbhd) +{ + char huge *mbbpsa; /* Sicherung mbbp */ + BOOLEAN split; /* TRUE: Split erfolgt */ + WORD mbgcsa; /* Sicherung mbgc */ + WORD mbgc2; /* mbgc alt -> mbpc alt */ + WORD n; /* Zaehler */ + MBHEAD *mbhd2; /* Kopfzeiger neuer Messagebuffer */ + + split = FALSE; /* zunaechst nichts gesplittet */ + mbbpsa = mbhd->mbbp; /* Bufferpointer sichern */ + mbgcsa = mbhd->mbgc; /* Getcounter sichern */ + for (n = 0; mbhd->mbgc < mbhd->mbpc && n < max; ++n) + putchr(getchr(mbhd), fbp); /* maximal max Bytes kopieren */ + if (mbhd->mbgc < mbhd->mbpc) /* noch Bytes ueber -> Split ! */ + { + mbgc2 = mbhd->mbgc; /* Getcount fuer spaeter merken */ + mbhd2 = (MBHEAD *)allocb(ALLOC_MBHEAD); /* neuen Buffer erzeugen */ + while (mbhd->mbgc < mbhd->mbpc) /* die restlichen Bytes in diesen */ + putchr(getchr(mbhd), mbhd2); /* Buffer kopieren */ + rwndmb(mbhd2); /* neuen Buffer rewinden */ + mbhd2->morflg = FALSE; /* noch dem neuen folgt keiner */ + mbhd2->l2fflg = mbhd->l2fflg; /* Frameflag uebertragen */ + mbhd2->repeated = 0; /* noch nicht erneut gesendet */ + relink((LEHEAD *)mbhd2, + (LEHEAD *)mbhd); /* neu. Buf. hinter alten haengen */ + mbhd->mbpc = mbgc2; /* alter Buffer nur max Zeichen ! */ + split = TRUE; /* wir mussten splitten */ + } + mbhd->mbbp = mbbpsa; /* Bufferpointer restaurieren */ + mbhd->mbgc = mbgcsa; /* Getcount restaurieren */ + return (split); /* Split oder nicht */ +} + +#ifdef BUFFER_DEBUG +/* Schreibt die aktuelle Buffer-Benutzung in eine Datei */ +/* Wichtig: hier nichts benutzen, was irgendwie wieder */ +/* neue Buffer belegen oder freigeben wuerde ! */ +static +void bufstat(void) +{ + MAX_BUFFER huge *actbp; + ULONG i, n; + ULONG used[ALLOC_MAXELEMENTE + 1]; + FILE *fp; + + if ((fp = fopen("buffer.log", "a+")) != NULL) + { + for (i = 0; i < ALLOC_MAXELEMENTE + 1; i++) + used[i] = 0; + + actbp = (MAX_BUFFER *)RAMBOT; + n = (ULONG)((RAMTOP - RAMBOT) / sizeof(MAX_BUFFER)); + + fprintf(fp, "\rTotal Buffers : %ld (%u free) at %u Bytes each\r", n, nmbfre_max, (unsigned int)sizeof(MAX_BUFFER)); + + while (n--) + { + if ((UBYTE) ((USRBLK *)actbp)->owner >= ALLOC_MAXELEMENTE) + { + used[ALLOC_MAXELEMENTE]++; + fprintf(fp,"Wrong Owner: Buffer:%lu Owner:%d\r", n, (UBYTE) ((USRBLK *)actbp)->owner); + } + else + used[(UBYTE) ((USRBLK *)actbp)->owner]++; + actbp++; + } + + fprintf(fp, "Free : by owner %lu, by counter %u\r", used[ALLOC_NO_OWNER], nmbfre); + fprintf(fp, "LEHEAD : %lu\r", used[ALLOC_LEHEAD]); + fprintf(fp, "MBHEAD : %lu\r", used[ALLOC_MBHEAD]); + fprintf(fp, "USRBLK1: %lu\r", used[ALLOC_USRBLK1]); + fprintf(fp, "USRBLK2: %lu\r", used[ALLOC_USRBLK2]); + fprintf(fp, "L2LINK : %lu\r", used[ALLOC_L2LINK]); + fprintf(fp, "MB : %lu\r", used[ALLOC_MB]); + fprintf(fp, "MONBUF : %lu\r", used[ALLOC_MONBUF]); + fprintf(fp, "CQBUF : %lu\r", used[ALLOC_CQBUF]); + fprintf(fp, "IPROUTE: %lu\r", used[ALLOC_IP_ROUTE]); + fprintf(fp, "ARPTAB : %lu\r", used[ALLOC_ARP_TAB]); + fprintf(fp, "MHEARD : %lu\r", used[ALLOC_MHEARD]); + fprintf(fp, "PACSAT : %lu\r", used[ALLOC_PACSATBLK]); +#ifdef TCP_STACK + fprintf(fp, "TCPSTA : %lu\r", used[ALLOC_TCPSTACK]); +#endif /* TCP_STACK */ +#ifdef L1TCPIP + fprintf(fp, "TCPIP : %lu\r", used[ALLOC_L1TCPIP]); +#endif /* L1TCPIP */ +#ifdef L1HTTPD + fprintf(fp, "HTTPDRX: %lu\r", used[ALLOC_L1HTTPD_RX]); + fprintf(fp, "HTTPDTX: %lu\r", used[ALLOC_L1HTTPD_TX]); +#endif /* L1HTTPD */ + fprintf(fp, "INPOPT : %lu\r", used[ALLOC_INPOPT]); + + if (used[0] != 0L) + fprintf(fp, "??? : %lu\r", used[0]); + + fprintf(fp, "Errors : %lu\r", used[ALLOC_MAXELEMENTE]); + + fclose(fp); + } +} + +#ifdef INSANE_BUFFER_DEBUG +/************************************************************************/ +/* Log-Funktion zum Debugging */ +/************************************************************************/ +static void +TOLOG(const char *format, ...) +{ + FILE *fp; + va_list arg_ptr; + struct timeval tv; + static char str[30]; + char *ptr; + + if ((fp = fopen("buffer.log", "a+")) != NULL) + { + gettimeofday(&tv, NULL); + ptr = ctime(&tv.tv_sec); + strcpy(str, &ptr[11]); + fprintf(fp, "%s:", str); + + va_start(arg_ptr, format); + vfprintf(fp, format, arg_ptr); + va_end(arg_ptr); + + fprintf(fp, "\n"); + fclose(fp); + } +} + +/************************************************************************\ +* Prueft, ob der uebergebene Pointer im Bufferbereich liegt * +\************************************************************************/ +static void +MBPTRCHECK(MBHEAD* checkme) +{ + /* Ist der uebergebene Zeiger im gueltigen Bereich ? */ + if (((char*)checkme < RAMBOT) || ((char*)checkme > RAMTOP)) + { + TOLOG("An error occured while accessing one of my buffers, the\r"); + TOLOG("desired buffer at adress %p is outside of my allocted\r", checkme); + TOLOG("memory range from %p to %p (%ld bytes) !\r", RAMBOT, RAMTOP, (RAMTOP - RAMBOT)); + TOLOG("Here is the actual usage of the buffer system:\r"); + + bufstat(); + + TOLOG("I will crash now for conservation of the stack ...\r"); + HALT("MBPTRCHECK: crash !\r"); + } +} +#endif /* INSANE_BUFFER_DEBUG */ + +#endif /* BUFFER_DEBUG */ + +/* End of src/buffer.c */ diff --git a/src/callstr.c b/src/callstr.c new file mode 100755 index 0000000..cbca127 --- /dev/null +++ b/src/callstr.c @@ -0,0 +1,468 @@ +/************************************************************************/ +/* */ +/* ***** ***** */ +/* ***** ***** */ +/* ***** ***** */ +/* ***** ***** */ +/* *************** *************** */ +/* ***************** ***************** */ +/* *************** *************** */ +/* ***** ***** TheNetNode */ +/* ***** ***** Portable */ +/* ***** ***** Network */ +/* ***** ***** Software */ +/* */ +/* File src/callstr.c (maintained by: ???) */ +/* */ +/* This file is part of "TheNetNode" - Software Package */ +/* */ +/* Copyright (C) 1998 - 2008 NORD>mbpc - mbhd->mbgc < L2IDLEN) + return (FALSE); + for (i = 0; i < L2CALEN; ++i) + { + if (((c = getchr(mbhd)) & L2CEOA) != 0) + return (FALSE); + *dest++ = (c >> 1) & 0x7F; + } + *dest = '\0'; + if (is_down_suspended((dest - L2CALEN), 253)) + { + return (FALSE); + } + *dest = getchr(mbhd); + return (TRUE); +} + +/* TEST DG9OBU */ + +/************************************************************************/ +/* */ +/* "get frame id complete" */ +/* */ +/* Ein Rufzeichen in AX.25-Notation aus einem Buffer lesen. Es wird */ +/* immer ein komplettes Call gelesen um im Eingangsbuffer eine */ +/* definierte Position zu erreichen, erst danach wird das Call */ +/* ueberprueft. */ +/************************************************************************/ +BOOLEAN +getfidc(char *dest, MBHEAD *mbhd) +{ + BOOLEAN bRetVal = TRUE; + + char c; + + WORD i; + + /* Noch ein Call im Buffer ? */ + if (mbhd->mbpc - mbhd->mbgc < L2IDLEN) + return (FALSE); + + /* Call lesen */ + for (i = 0; i < L2CALEN; ++i) + { + /* EOA-Bit darf nicht vorzeitig kommen ! */ + if (((c = getchr(mbhd)) & L2CEOA) != 0) + bRetVal = FALSE; + + *dest++ = (c >> 1) & 0x7F; + } + + /* SSID ausblenden */ + *dest = '\0'; + + /* Check */ + if (is_down_suspended((dest - L2CALEN), 253)) + bRetVal = FALSE; + + /* SSID hinzufuegen */ + *dest = getchr(mbhd); + + return (bRetVal); +} + +#ifndef MC68K +/************************************************************************/ +/* */ +/* "compare call" */ +/* */ +/* Rufzeichen vergleichen. EOA und H-Bit werden ignoriert. */ +/* */ +/************************************************************************/ +BOOLEAN +cmpcal(const char *id1, const char *id2) +{ + return (strncmp(id1, id2, L2CALEN) == 0); +} + +/************************************************************************/ +/* */ +/* "compare id" */ +/* */ +/* Rufzeichen und SSID vergleichen. EOA und H-Bit werden ignoriert. */ +/* */ +/************************************************************************/ +BOOLEAN +cmpid(const char *id1, const char *id2) +{ + return ( cmpcal(id1, id2) + && (id2[L2CALEN] & 0x1E) == (id1[L2CALEN] & 0x1E)); +} + +/************************************************************************/ +/* */ +/* "compare id list" */ +/* */ +/* Zwei Rufzeichenlisten werden verglichen. Die H-Bits muessen in allen */ +/* Rufzeichen uebereinstimmen. */ +/* */ +/************************************************************************/ +BOOLEAN +cmpidl(const char *idl1, const char *idl2) +{ + while (*idl2 != '\0') + { + if (memcmp(idl1, idl2, L2IDLEN)) + return (FALSE); + idl2 += L2IDLEN; + idl1 += L2IDLEN; + } + + return ((*idl1 == '\0') ? TRUE : FALSE); +} + +/************************************************************************/ +/* */ +/* "copy id" */ +/* */ +/* Rufzeichen kopieren. End-of-Address und Has-been-digipeated Bit */ +/* werden geloescht. */ +/* */ +/************************************************************************/ +void +cpyid(char *dest, const char *source) +{ + memcpy(dest, source, L2CALEN); + dest[L2IDLEN - 1] = source[L2IDLEN - 1] & ~(L2CEOA | L2CCR); +} + +/************************************************************************/ +/* */ +/* "copy id list" */ +/* */ +/* Rufzeichenliste kopieren. EOA und H Bit bleiben erhalten. */ +/* */ +/************************************************************************/ +void +cpyidl(char *dest, const char *source) +{ + while (*source != '\0') + { + memcpy(dest, source, L2IDLEN); + source += L2IDLEN; + dest += L2IDLEN; + } + *dest = '\0'; +} +#endif +/************************************************************************/ +/* */ +/* "add id" */ +/* */ +/* An eine Rufzeichenliste ein Call anhaengen. */ +/* */ +/************************************************************************/ +void +addid(char *dest, const char *source) +{ + char *cp; + + cp = (char *)strchr((char *)dest, 0); + if (&cp[0] < &dest[L2VLEN]) + { + memcpy(cp, source, L2IDLEN); + cp[L2IDLEN] = 0; + } +} + +/************************************************************************/ +/* */ +/* "first not digipeated" */ +/* */ +/* Das erste Call aus einer Rufzeichenliste lesen, das noch nicht */ +/* gedigipeated hat. Es darf weder unser Call sein noch ein gesetztes */ +/* H-Bit haben. */ +/* */ +/************************************************************************/ +const char * +ndigipt(const char *digis) +{ + const char *viap; + + for (viap = digis; *viap; viap += L2IDLEN) + if ((viap[L2IDLEN - 1] & L2CH) == 0) + break; + if (*viap) + if (istome(viap)) + viap += L2IDLEN; + return (viap); +} + +#ifdef MH_LISTE + +const char * +ydigipt(const char *viap) +{ + + for (viap = rxfhdr + L2ILEN; *viap; viap += L2IDLEN) + if ((viap[L2IDLEN - 1] & L2CH) != 0) + if (!viap[L2IDLEN] || !(viap[L2ILEN - 1] & L2CH)) + break; + if (*viap) + if (istome(viap)) + viap += L2IDLEN; + return (viap); +} +#endif + +/************************************************************************/ +/* */ +/* "put via" */ +/* */ +/* Eine Rufzeichenliste in AX.25 in einen Frame schreiben. Das letzte */ +/* Rufzeichen erhaelt das EOA-Bit. */ +/* */ +/************************************************************************/ +void +putvia(const char *idl, MBHEAD *mbhd) +{ + while (*idl != '\0') + { + putfid(idl, mbhd); + idl += L2IDLEN; + } + *(mbhd->mbbp - 1) |= L2CEOA; +} + +/************************************************************************/ +/* */ +/* "put frame id" */ +/* */ +/* Ein Rufzeichen in AX.25-Notation in einen Buffer schreiben. */ +/* */ +/************************************************************************/ +void +putfid(const char *id, MBHEAD *mbhd) +{ + WORD i; + + for (i = 0; i < L2CALEN; ++i) + putchr((char)(*id++ << 1), mbhd); + putchr(*id, mbhd); +} + +/************************************************************************/ +/* Convert Type CALL to string */ +/*----------------------------------------------------------------------*/ +void +call2str(char *d, char *call) +{ + char c; + int i; + + for (i = 0; i < L2IDLEN - 1; i++) + { + c = *call++; + if (c > ' ') + *d++ = c; + else if (c < ' ') + *d++ = ' '; + } + + c = (*call >> 1) & 0x0f; + if (c != 0) + { + *d++ = '-'; + if (c >= 10) + { + *d++ = '1'; + c -= 10; + } + *d++ = '0' + c; + } + + *d = '\0'; +} + +/************************************************************************/ +/* Convert Type CALL to string and strip SSID */ +/*----------------------------------------------------------------------*/ +void +callss2str(char *d, char *call) +{ + WORD i; + + for (i = 0; i < L2IDLEN - 1 && *call != ' '; i++) + *d++ = *call++; + + *d = '\0'; +} + +/************************************************************************/ +/* Convert string to CALL */ +/*----------------------------------------------------------------------*/ +void +str2call(char *d, char *call) +{ + WORD l = strlen(call); + + getcal(&l, (char **)&call, TRUE, d); +} + + +/*-----------------------------------------------------------------------*/ +/* diese funktion hab ich 'gefunden' und etwas abgemagert */ + /* wer ist ich??? ^^^ */ +/* Author: James R. Van Zandt */ +/* 27 Spencer Dr. */ +/* Nashua NH 03062 */ +/* */ +/* */ +/*-----------------------------------------------------------------------*/ +static BOOLEAN +pnmtch(const char *pat, char *nam) +{ + const char **a, + **n, + *s; + const char *alive[MAXMASK + 2]; + const char *next[MAXMASK + 2]; + + next[0] = pat; + next[1] = 0; + while (next[0]) + { + a = alive; + n = next; + + while (a <= alive + MAXMASK && ((*a++ = *n) != 0)) + { + if (**n == '*') + { + for (s = *n; *++s == '*';); + if (s != n[1] && a <= alive + MAXMASK) + *a++ = s; + } + n++; + } + if (*nam == 0) + return ((*a[-2] == 0) ? TRUE : FALSE); + a = alive; + n = next; + while (*a) + { + switch (**a) + { + case '?': + *n++ = *a + 1; + break; + case '*': + if (strlen(*n) >= 1) + *n++ = *a; + + break; + + default: + if (**a == *nam) + *n++ = *a + 1; + } + a++; + } + *n = 0; + nam++; + } + return (FALSE); +} + +/* c6mtch() - 6 zeichen matschen... */ +/* TRUE wenn string 's' auf muster 'pat' passt */ +/* nicht dass es umstaendlich waere... der string wird umkopiert und */ +/* NULterminiert, um eine vorgefundene Funktion zu benutzen */ +BOOLEAN +c6mtch(const char *s, const char *pat) +{ + char c6[6 + 1]; + WORD i; + + for (i = 0; i < 6; i++) + { + if (s[i] == ' ') + break; + c6[i] = isascii(s[i]) ? toupper(s[i]) : s[i]; + } + c6[i] = '\0'; + return ((i > 0) ? pnmtch(pat, c6) : FALSE); +} + +/************************************************************************/ +/* "direct heard callsign" */ +/* Das Call aus einer Rufzeichenliste lesen, das direkt gehoert wurde. */ +/************************************************************************/ +const char * +dheardcall(const char *viap) +{ + for (viap += 2 * L2IDLEN; *viap; viap += L2IDLEN) + if ((viap[L2IDLEN - 1] & L2CH) == 0) + break; + return (viap-L2IDLEN); +} + +/* End of src/callstr.c */ diff --git a/src/cleaner.c b/src/cleaner.c new file mode 100755 index 0000000..ed1a42f --- /dev/null +++ b/src/cleaner.c @@ -0,0 +1,304 @@ +/************************************************************************/ +/* Sourcen-Reiniger von DL1XAO */ +/* */ +/* expandiert in den gewuenschten Files die Tabulatoren, loescht */ +/* ueberfluessige Spaces und wandelt Umlaute */ +/* */ +/* Aenderungen fuer Kommandozeilenparameter von DF6LN */ +/* */ +/************************************************************************/ + +#include "tnn.h" + +int clean(char *); +void usage(void); + +int tabs = 8; + +int +main(int argc, char *argv[]) +{ + char file[MAXPATH]; + int i = 1; + char *sp; + + if (argc < 2) + { + usage(); + return (-1); + } + + if (argc > 2) + { + if (!strcmp(argv[1], "-t")) + { + if (sscanf(argv[2], "%d", &tabs) != 1) + { + usage(); + return (-1); + } + if (tabs < 2 || tabs > 8) + { + fprintf(stderr, "TAB size out of range (2 .. 8).\n"); + return (-1); + } + i += 2; + if (i == argc) + { + usage(); + return (-1); + } + } + } + + for (; i < argc; i++) + { + strcpy(file, argv[i]); + strlwr(file); + sp = strstr(file, ".c"); + if (sp != file + strlen(file) - 2) + { + sp = strstr(file, ".h"); + if (sp != file + strlen(file) - 2) + { + fprintf(stderr, "%s has bad file extension.\n", argv[i]); + return (-1); + } + } + if (!clean(file)) + return (-1); + } + return (0); +} + +void +usage(void) +{ + fprintf(stderr, "Usage: cleaner [-t ] filename [filename [...]]\n"); +} + +int +clean(char *fn) +{ + char tempf[10]; + char out[2048]; + char *co; + int changed = 0; + int n, c, lc; + FILE *fpi; + FILE *fpo; + + if ((fpi = xfopen(fn, "rb")) == NULL) + { + fprintf(stderr, "File not found: %s\n", fn); + return (0); + } + strcpy(tempf, "temp"); + if ((fpo = xfopen(tempf, "w")) == NULL) + { + fprintf(stderr, "Can't open temp file.\n"); + fclose(fpi); + return (0); + } + setvbuf(fpi, NULL, _IOFBF, 8192L); + setvbuf(fpo, NULL, _IOFBF, 8192L); + + for (lc = 0, co = out; (c = fgetc(fpi)) != EOF; ) + { +#ifndef __LINUX__ + if (c == '\n' && lc != '\r') + changed = 1; +#else + if (c == '\r') + changed = 1; +#endif + + switch (c) + { + case 9: changed = 1; + c = ' '; + for (n = tabs -1 - ((co - out) % tabs); n; n--) + *co++ = c; + break; + case 0x8e: + case 0xc4: changed = 1; + *co++ = 'A'; + c = 'e'; + break; + case 0x99: + case 0xd6: changed = 1; + *co++ = 'O'; + c = 'e'; + break; + case 0x9a: + case 0xdc: changed = 1; + *co++ = 'U'; + c = 'e'; + break; + case 0x84: + case 0xe4: changed = 1; + *co++ = 'a'; + c = 'e'; + break; + case 0x94: + case 0xf6: changed = 1; + *co++ = 'o'; + c = 'e'; + break; + case 0x81: + case 0xfc: changed = 1; + *co++ = 'u'; + c = 'e'; + break; + case 0x9e: + case 0xdf: + case 0xe1: changed = 1; + c = 's'; + *co++ = c; + break; + } + + lc = c; + if (c != '\r' && c != '\n') + *co++ = c; + + if (c == '\n') + { + while (co > out && *(co - 1) == ' ') + { + co--; + changed = 1; + } + *co++ = '\n'; + *co = '\0'; + fputs(out, fpo); + co = out; + } + } + + fclose(fpi); + fclose(fpo); + if (changed) + { + unlink(fn); + rename(tempf, fn); + fprintf(stderr, "Changed version of %s saved.\n", fn); + } + else + unlink(tempf); + return (-1); +} + +/* + String in Kleinbuchstaben umwandeln - aus DJGPP GNU-Paket fuer MS-DOS + von D.J. Delorie +*/ + +char * +strlwr(char *s) +{ + char *p = s; + while (*s) + { + if ((*s >= 'A') && (*s <= 'Z')) + *s += 'a'-'A'; + s++; + } + return(p); +} + + +/*----------------------------------------------------------------------*/ +/* */ +/* Einen Dateinamen normieren, d.h. er wird den Gegenheiten des */ +/* verwendeten Dateisystems angepasst. Die Informationen hierfuer */ +/* werden in ALL.H festgelegt. */ +/* */ +/*----------------------------------------------------------------------*/ +char * +normfname(char *filename) +{ + char *s; /* Zeiger innerhalb des Namens */ + + for (s = filename; *s; s++) /* alle Zeichen im String durchgehen */ + if (strchr(SEPARATORS, *s)) /* ein Dateitrennungszeichen ? */ + *s = FILE_SEP; /* dann durch das richtige ersetzen */ +#if (FILE_FLAGS & FF_LWR) + strlwr(filename); /* eventuell in Kleinschreibung... */ +#endif + return (filename); +} + +/*----------------------------------------------------------------------*/ +/* */ +/* Eine Datei oeffnen, es wird darauf geachtet, das einige Betriebs- */ +/* systeme zwischen Textdateien und Binaerdateien unterscheiden. */ +/* normfname() wird zur Normierung des Dateinamens benutzt. */ +/* */ +/*----------------------------------------------------------------------*/ +FILE * +xfopen(const char *filename, const char *mode) +{ + char fmode[4], *fm; /* der angepasste Datei-Mode */ + char fname[MAXPATH+1]; + + strcpy(fname, filename); /* umkopieren, den Originalnamen */ + normfname(fname); /* nicht anfassen */ + + fm = fmode; + if (strchr(mode, 'w')) /* zum Schreiben */ + *fm++ = 'w'; + else + if (strchr(mode, 'a')) /* zum Anhaengen */ + *fm++ = 'a'; + else + *fm++ = 'r'; /* sonst zum Lesen oeffnen */ +#if (FILE_FLAGS & FF_TXT) /* b/t-Flag uebernehmen? */ + if (strchr(mode, 'b')) /* eine Binaer-Datei? */ + *fm++ = 'b'; /* ... Flag uebernehmen */ +#ifndef MC68K + if (strchr(mode, 't')) /* eine Text-Datei? */ + *fm++ = 't'; /* ... Flag uebernehmen */ +#endif +#endif + if (strchr(mode, '+')) /* Ueberschreiben? */ + *fm++ = '+'; + + *fm = 0; /* String terminieren */ + return (fopen(fname, fmode)); /* Datei oeffnen */ +} + +/*----------------------------------------------------------------------*/ +/* */ +/* Eine Datei loeschen, es werden ALLE Dateien geloescht (auch RDONLY) */ +/* normfname() wird zur Normierung des Dateinamen benutzt. */ +/* */ +/*----------------------------------------------------------------------*/ +int +xremove(const char *filename) +{ + char fname[MAXPATH+1]; + + strcpy(fname, filename); /* umkopieren, den Originalnamen */ + normfname(fname); /* nicht anfassen */ + return (remove(fname)); +} + +/*----------------------------------------------------------------------*/ +/* */ +/* Eine Datei umbenennen. */ +/* normfname() wird zur Normierung des Dateinamens benutzt. */ +/* */ +/*----------------------------------------------------------------------*/ +int +xrename(const char *oldname, const char *newname) +{ + char fname[MAXPATH+1]; + char fname2[MAXPATH+1]; + + strcpy(fname, oldname); /* umkopieren, den Originalnamen */ + normfname(fname); /* nicht anfassen */ + strcpy(fname2, newname); /* umkopieren, den neuen Namen */ + normfname(fname2); /* nicht anfassen */ + return (rename(fname,fname2)); +} diff --git a/src/config.c b/src/config.c new file mode 100755 index 0000000..9ba3e91 --- /dev/null +++ b/src/config.c @@ -0,0 +1,207 @@ +/************************************************************************/ +/* */ +/* ***** ***** */ +/* ***** ***** */ +/* ***** ***** */ +/* ***** ***** */ +/* *************** *************** */ +/* ***************** ***************** */ +/* *************** *************** */ +/* ***** ***** TheNetNode */ +/* ***** ***** Portable */ +/* ***** ***** Network */ +/* ***** ***** Software */ +/* */ +/* File src/config.c (maintained by: ???) */ +/* */ +/* This file is part of "TheNetNode" - Software Package */ +/* */ +/* Copyright (C) 1998 - 2008 NORD> + * + * Modifications by Fred Baumgarten + * $Revision: 3.12 $$Date: 1996/03/03 10:09:47 $ + * + * Modifications by Oliver Kern + * $Revision: 3.13 $$Date: 17.08.2004 22:22 $ + */ + +/* zusammengefuehrtes USER.C und HOST.C, damit alle Kommandos samt + Kommandotabelle mit statischen Funktionen auskommen */ + +#include "cvs_cmds.h" +#ifdef PPCONVERS + +/*---------------------------------------------------------------------------*/ + +#ifdef CONVNICK +/* Den Nickname und/oder nur das Call ausgeben */ +void makeName(CONNECTION* pCon, char* pBuffer) +{ + memset(pBuffer, 0, sizeof(pBuffer)); + + if (pCon->nickname[0] != '\0') + sprintf(pBuffer, "%s:%s", pCon->name, pCon->nickname); + else + sprintf(pBuffer, "%s", pCon->name); +} +#endif + +void process_input(CONNECTION *cp) +{ + char *arg; + WORD arglen; + CMDTABLE *cmdp; + CHANNEL *ch; + CONNECTION *c; +#ifdef CONVNICK + char buf[2 * NAMESIZE + 2]; /* Name + ":" + Nickname + 1 */ +#endif + + clear_locks(); + cp->locked = 1; + ts2(); + + if (cp->type == CT_USER) { + arg = convertin(cp->charset_in, cnvinbuf); + if (arg != cnvinbuf) + strcpy(cnvinbuf, arg); + } + +#ifdef USERPROFIL + if (userpo->status == US_UPWD) /* User ist im Passwort-Modus. */ + { + cp->type = US_UPWD; /* Passwort-Modus setzen. */ + + if (!strncmp(cnvinbuf, "/NAME", 5))/* Beim 1.Login Kanal ermitteln/setzen */ + { + char *Channel; + + Channel = strrchr(cnvinbuf, ' '); /* Kanal ermitteln. */ + cp->channel = atoi(Channel); /* Kanal setzen. */ + return; + } + + strncpy(clipoi, cnvinbuf, 6); /* Passwortstring vom User sichern. */ + clicnt = 5; /* laenge setzen. */ + + if (CheckPasswd()) /* Pruefe Passwortstring vom User. */ + { + SendPasswdStringProfil(); /* String war nicht korrekt, */ + return; /* neuen Passwortstring an User senden. */ + } + /* Passwortstring vom User ist korrekt. */ + userpo->status = US_CCP; /* Markiere, kein Passwort-Modus. */ + cp->type = CT_UNKNOWN; /* Typ ist noch ungekannt. */ + + sprintf(cnvinbuf, "/NAME %s %d", cp->name, cp->channel); + } +#endif /* USERPROFIL */ + + cnvinbuf[2000] = '\0'; /* Zulange Antworten vermeiden */ + +#ifdef L1IRC + if (cp->IrcMode == TRUE) + { + ProcessIrcInput(cnvinbuf, cp); + return; + } +#endif /* L1IRC */ + + if (*cnvinbuf == '/') { + if (!strncmp(cnvinbuf, "/\377\200", 3) && tolower(*(cnvinbuf+3)) != 'c') + send_proto("cmds", "RX fm %s %s", cp->name, cnvinbuf+3); + arglen = (WORD)strlen(arg = getarg(cnvinbuf + 1, GET_NXTLC)); + for (cmdp = cmdtable; cmdp->name; cmdp++) + if (!strncmp(cmdp->name, arg, arglen)) { + if (cmdp->states & (1 << cp->type)) { + (*cmdp->fnc)(cp); + return; + } + } + if (cp->type == CT_USER) { + if (!strncmp(arg, "\377\200", 2)) /* unangemeldete Hosts */ + return; /* werden ignoriert */ +#ifdef SPEECH + appenddirect(cp, speech_message(28)); +#else + appenddirect(cp, "*** Unknown command '/"); +#endif + appendstring(cp, arg); +#ifdef SPEECH + appenddirect(cp, speech_message(29)); +#else + appenddirect(cp, "'. Type /HELP for help.\r"); +#endif + appendprompt(cp, 0); + } + else if (cp->type == CT_HOST && !strncmp(arg, "\377\200", 2)) { + if (strncmp("\377\200host", arg, 6)) { + *strchr(cnvinbuf, 0) = ' '; /* durch getarg verursachte \0 loeschen */ + h_unknown_command(cp); + } + } + return; + } + + if (cp->type == CT_USER) { + if (cp->away) +#ifdef SPEECH + appenddirect(cp, speech_message(30)); +#else + appenddirect(cp, "*** You are away, aren't you ? :-)\r"); +#endif + if (cp->query[0] == '\0') { + for (ch = channels; ch; ch = ch->next) { + if (ch->chan == cp->channel) break; + } + if (cp->operator || cp->channelop || !(ch->flags & M_CHAN_M)) + { +#ifdef CONVNICK + makeName(cp, buf); + send_msg_to_channel(buf, cp->channel, cnvinbuf); +#else + send_msg_to_channel(cp->name, cp->channel, cnvinbuf); +#endif + } else { +#ifdef SPEECH + appenddirect(cp, speech_message(31)); +#else + appenddirect(cp, "*** This is a moderated channel. Only channel operators may write.\r"); +#endif + } + } else { + for (c = connections; c; c = c->next) +#ifdef CONVNICK + /* Typ User. */ + if ( c->type == CT_USER + /* Callvergleich */ + && (!strcasecmp(c->name, cp->query) + /* Nicknamevergleich */ + || !strcasecmp(c->nickname, cp->query))) +#else + if (c->type == CT_USER && !strcmp(c->name, cp->query)) +#endif + break; + if (!c) { +#ifdef SPEECH + appenddirect(cp, speech_message(32)); +#else + appenddirect(cp, "*** Queried user left convers.\r"); +#endif + } else { +#ifdef CONV_NICK + makeName(cp, buf); + send_msg_to_user(buf, cp->query, cnvinbuf); +#else + send_msg_to_user(cp->name, cp->query, cnvinbuf); +#endif + } + } + } + appendprompt(cp, 0); +} + +/*---------------------------------------------------------------------------*/ +/* User-Kommandos */ +/*---------------------------------------------------------------------------*/ + +static void all_command(CONNECTION *cp) +{ + CHANNEL *ch; + char *s; +#ifdef CONVNICK + char buf[2 * NAMESIZE + 2]; /* Name + ":" + Nickname + 1 */ +#endif + + s = getarg(NULL, GET_ALL); + + for (ch = channels; ch; ch = ch->next) { + if (ch->chan == cp->channel) break; + } + if (cp->operator || cp->channelop || !(ch->flags & M_CHAN_M)) { + if (*s) { +#ifdef CONVNICK + makeName(cp, buf); + send_msg_to_channel(buf, cp->channel, s); +#else + send_msg_to_channel(cp->name, cp->channel, s); +#endif + } + } else { +#ifdef SPEECH + appenddirect(cp, speech_message(31)); +#else + appenddirect(cp, "*** This is a moderated channel. Only channel operators may write.\r"); +#endif + } + appendprompt(cp, 0); +} + +/*---------------------------------------------------------------------------*/ + +static void away_command(CONNECTION *cp) +{ + char *s; + char buffer[128]; + CONNECTION *p; + + s = getarg(NULL, GET_ALL); + if (*s || cp->away) { + if (*s) +#ifdef SPEECH + sprintf(buffer, speech_message(33), timestamp); +#else + sprintf(buffer, "%sYou are marked as being away.\r", timestamp); +#endif + else +#ifdef SPEECH + sprintf(buffer, speech_message(34), timestamp); +#else + sprintf(buffer, "%sYou are no longer marked as being away.\r", timestamp); +#endif + for (p = connections; p; p = p->next) { + if (p->type == CT_USER && !p->via && !Strcmp(p->name, cp->name)) { + setstring(&(p->away), s, 256); + p->atime = currtime; + p->locked = 1; + } + } +#ifndef CONVNICK + send_awaymsg(cp->name, myhostname, currtime, s); +#else + send_awaymsg(cp->name, cp->nickname, myhostname, currtime, s); +#endif /* CONVNICK */ + } else +#ifdef SPEECH + sprintf(buffer, speech_message(35), timestamp); +#else + sprintf(buffer, "%sActually you were marked as being here :-)\r", timestamp); +#endif + + appenddirect(cp, buffer); + appendprompt(cp, 0); +} + +/*---------------------------------------------------------------------------*/ + +static void beep_command(CONNECTION *cp) +{ + char buffer[32], *c; + + if (cp->prompt[3] == '\0') { + cp->prompt[3] = '\007'; +#ifdef SPEECH + c = speech_message(83); +#else + c = "en"; +#endif + } + else { + cp->prompt[3] = '\0'; +#ifdef SPEECH + c = speech_message(84); +#else + c = "dis"; +#endif + } +#ifdef SPEECH + sprintf(buffer, speech_message(36), c); +#else + sprintf(buffer, "*** Beep mode %sabled\r", c); +#endif + appenddirect(cp, buffer); + appendprompt(cp, 0); +} + +/*---------------------------------------------------------------------------*/ + +void bye_command2(CONNECTION *cp, char *reason) +{ + CONNECTION *p; + WORD users_left; + CLIST *cl = NULLCLIST; + WORD channel; + + switch (cp->type) { + case CT_UNKNOWN: + cp->type = CT_CLOSED; + break; + +#ifdef USERPROFIL + case US_UPWD: /* User ist im Passwort-Modus. */ +#endif /* USERPROFIL */ + case CT_USER: + cp->type = CT_CLOSED; + cl = cp->chan_list; + while (cl) { + users_left = count_user(cl->channel); + if (!users_left) destroy_channel(cl->channel); + clear_locks(); +#ifndef CONVNICK + send_user_change_msg(cp->name, cp->host, cl->channel, -1, reason, currtime); +#else + send_user_change_msg(cp->name, cp->nickname, cp->host, cl->channel, -1, reason, currtime); +#endif /* CONVNICK */ + cp->chan_list = cl->next; + free (cl); + cl = cp->chan_list; + } + break; + case CT_HOST: + cp->type = CT_CLOSED; + update_permlinks(cp->name, NULLCONNECTION, 0); + for (p = connections; p; p = p->next) + if (p->via == cp) { + p->type = CT_CLOSED; + clear_locks(); + channel = p->channel; +#ifndef CONVNICK + send_user_change_msg(p->name, p->host, p->channel, -1, reason, currtime); +#else + send_user_change_msg(p->name, p->nickname, p->host, p->channel, -1, reason, currtime); +#endif /* CONVNICK */ + users_left = count_user(channel); + if (!users_left) destroy_channel(channel); + } + break; + case CT_CLOSED: + break; + } +} + +/*---------------------------------------------------------------------------*/ + +void bye_command(CONNECTION *cp) +{ + char *s; + char buffer[256]; + + s = getarg(NULL, GET_ALL); + if (!s || !*s) { + bye_command2(cp, "/quit"); + } else { + sprintf(buffer, "\"%.252s\"", s); + bye_command2(cp, buffer); + } +} + +/*---------------------------------------------------------------------------*/ + +static CHANNEL *ins_channel(WORD chan) +{ + CHANNEL *ch, *ch1; + + ch = (CHANNEL *) calloc(1, sizeof(CHANNEL)); + + if (ch) { + ch->chan = chan; + + if (!channels || channels->chan > chan) { + ch->next = channels; + channels = ch; + } else { + ch1 = channels; + while (ch1->next) { + if (ch1->next->chan > chan) { + ch->next = ch1->next; + ch1->next = ch; + return(ch); + } + ch1 = ch1->next; + } + if (!ch1->next) { + ch->next = ch1->next; + ch1->next = ch; + } + } + } + return(ch); +} + +/*---------------------------------------------------------------------------*/ + +static BOOLEAN has_ChOp(WORD chan) +{ + CONNECTION *p; + CLIST *cl; + + for (p = connections; p; p = p->next) { + if (p->type == CT_USER) { + if (p->channel == chan && p->channelop) + return(1); + + for (cl = p->chan_list; cl; cl = cl->next) + if (cl->channel == chan && cl->channelop) + return(1); + } + } + return(0); +} + +/*---------------------------------------------------------------------------*/ + +static void channel_command(CONNECTION *cp) +{ + char *s; + char buffer[256]; + WORD newchannel; + LONG nc; + CHANNEL *ch; + CONNECTION *p; + WORD printit, first; + CLIST *cl; + + s = getarg(NULL, GET_NXTLC); + + if (!*s) { +#ifdef SPEECH + sprintf(buffer, speech_message(37), + timestamp, cp->channel, count_user(cp->channel)); +#else + sprintf(buffer, "%sYou are talking to channel %d. There are %d users.\r", + timestamp, cp->channel, count_user(cp->channel)); +#endif + appenddirect(cp, buffer); + for (ch = channels; ch; ch = ch->next) { + if (ch->chan == cp->channel) break; + } + + if (ch->topic) + { +#ifdef CONV_TOPIC +#ifdef SPEECH + sprintf(buffer, speech_message(38), ch->name, ts(ch->time)); +#else + sprintf(buffer, "*** current Topic by: %s (%s):\r " + , ch->name + , ts(ch->time)); +#endif /* SPEECH */ +#else + appenddirect(cp, "*** current Topic is:\r "); +#endif /* CONV_TOPIC */ + appendstring(cp, ch->topic); + appenddirect(cp, "\r"); + } + printit = 0; + first = 1; + for (cl = cp->chan_list; cl; cl = cl->next) { + if (cl->channel != cp->channel) { + if (first) { + first = 0; +#ifdef SPEECH + appenddirect(cp, speech_message(39)); +#else + appenddirect(cp, "*** Also attached:"); +#endif + } else { + appenddirect(cp, ","); + } + printit = count_user(cl->channel); + if (printit == 1) { +#ifdef SPEECH + sprintf(buffer, speech_message(40), cl->channel); +#else + sprintf(buffer, " channel %d (alone)", cl->channel); +#endif + } else { +#ifdef SPEECH + sprintf(buffer, speech_message(41), cl->channel, printit); +#else + sprintf(buffer, " channel %d (%d users)", cl->channel, printit); +#endif + } + appenddirect(cp, buffer); + } + } + if (printit) appenddirect(cp, ".\r"); + appendprompt(cp, 0); + return; + } + nc = atol(s); newchannel = (WORD)nc; + if (nc < 0L || nc > MAXCHANNEL) { +#ifdef SPEECH + sprintf(buffer, speech_message(42), timestamp, MAXCHANNEL); +#else + sprintf(buffer, "%sChannel numbers must be in the range 0..%d.\r", timestamp, MAXCHANNEL); +#endif + appenddirect(cp, buffer); + appendprompt(cp, 0); + return; + } + if (newchannel == cp->channel) { +#ifdef SPEECH + sprintf(buffer, speech_message(43), timestamp, cp->channel); +#else + sprintf(buffer, "%sChannel %d is already default.\r", timestamp, cp->channel); +#endif + appenddirect(cp, buffer); + appendprompt(cp, 0); + return; + } + + for (ch = channels; ch; ch = ch->next) { + if (ch->chan == newchannel) break; + } + for (cl = cp->chan_list; cl; cl = cl->next) { + if (cl->channel == newchannel) break; + } + if (!((cp->invitation_channel == newchannel) || !(ch) || !(ch->flags & M_CHAN_P)) && !cl && !cp->operator) { +#ifdef SPEECH + sprintf(buffer, speech_message(44), timestamp, newchannel); +#else + sprintf(buffer, "%sYou need an invitation to join the private channel %d.\r", timestamp, newchannel); +#endif + appenddirect(cp, buffer); + appendprompt(cp, 0); +#ifdef SPEECH + sprintf(buffer, speech_message(45), timestamp, cp->name, cp->host); +#else + sprintf(buffer, "%s%s@%s try to join your privat channel.", timestamp, cp->name, cp->host); +#endif + send_msg_to_channel("conversd", newchannel, buffer); + return; + } + if (!cl) { + cl = (CLIST *)calloc(1, sizeof(CLIST)); + if (!cl || (!ch && NULL == ins_channel(newchannel)) ) { +#ifdef SPEECH + sprintf(buffer, speech_message(46), timestamp, newchannel); +#else + sprintf(buffer, "%scannot join channel %d, no more space.\r", timestamp, newchannel); +#endif + appenddirect(cp, buffer); + appendprompt(cp, 0); + if (cl) + free(cl); + return; + } + cp->locked = 1; +#ifndef CONVNICK + send_user_change_msg(cp->name,cp->host, -1, newchannel, cp->pers, cp->time); +#else + send_user_change_msg(cp->name,cp->nickname, cp->host, -1, newchannel, cp->pers, cp->time); +#endif /* CONVNICK */ + cl->time = currtime; + cp->mtime = currtime; + if (!ch || !has_ChOp(newchannel)) + cl->channelop = 2; + cl->channel = newchannel; + cl->next = cp->chan_list; + cp->chan_list = cl; + cp->locked = 0; + } + cp->channel = newchannel; +#ifdef SPEECH + sprintf(buffer, speech_message(47), timestamp, cp->channel); +#else + sprintf(buffer, "%sYou are now talking to channel %d. ", timestamp, cp->channel); +#endif + appenddirect(cp, buffer); + if (ch) { + if ((first = count_user(cp->channel)) == 1) { +#ifdef SPEECH + sprintf(buffer, speech_message(48)); +#else + sprintf(buffer, "You're alone.\r"); +#endif + } else { +#ifdef SPEECH + sprintf(buffer, speech_message(49), first); +#else + sprintf(buffer, "There are %d users.\r", first); +#endif + } + appenddirect(cp, buffer); + if (ch->topic) + { +#ifdef CONV_TOPIC +#ifdef SPEECH + sprintf(buffer, speech_message(38), ch->name, ts(ch->time)); + appenddirect(cp, buffer); +#else + sprintf(buffer, "*** current Topic by: %s (%s):\r " + , ch->name + , ts(ch->time)); + appenddirect(cp, buffer); +#endif /* SPEECH */ +#else + appenddirect(cp, "*** current Topic is:\r "); +#endif /* CONV_TOPIC */ + appendstring(cp, ch->topic); + appenddirect(cp, "\r"); + } + } else { +#ifdef SPEECH + appenddirect(cp, speech_message(48)); +#else + appenddirect(cp, "You're alone.\r"); +#endif + } + if (cl->channelop == 2) { + for (p = connections; p; p = p->next) { + if (p->type == CT_HOST) { + sprintf(buffer, "/\377\200OPER conversd %d %s\r", cp->channel, cp->name); + appenddirect(p, buffer); + send_proto("cmds", "TX to %s %s", p->name, buffer+3); + } + } + } + cp->channelop = cl->channelop; + appendprompt(cp, 0); +} + +/*---------------------------------------------------------------------------*/ + +static void charset_command(CONNECTION *cp) +{ + char *s1, *s2; + char buffer[300]; + WORD charset_in, charset_out; + + s1 = getarg(NULL, GET_NXTLC); + + if (!*s1) { +#ifdef SPEECH + sprintf(buffer, speech_message(50), + get_charset_by_ind(cp->charset_in), + get_charset_by_ind(cp->charset_out)); +#else + sprintf(buffer, "*** Charset in/out is %s/%s.\r", + get_charset_by_ind(cp->charset_in), + get_charset_by_ind(cp->charset_out)); +#endif + appenddirect(cp, buffer); + appendprompt(cp, 0); + return; + } + + charset_in = get_charset_by_name(s1); + + s2 = getarg(NULL, GET_NXTLC); + if (*s2) charset_out = get_charset_by_name(s2); + else charset_out = charset_in; + + if (charset_in < 0 || charset_out < 0) { + cp->charset_out = ISO; +#ifdef SPEECH + sprintf(buffer, speech_message(51), + (charset_in < 0) ? s1 : s2, list_charsets()); +#else + sprintf(buffer, "Unknown charset: '%s'. You may use one of them:\r%s***\r", + (charset_in < 0) ? s1 : s2, list_charsets()); +#endif + appenddirect(cp, buffer); + appendprompt(cp, 0); + return; + } + + cp->charset_in = charset_in; + cp->charset_out = charset_out; + +#ifdef SPEECH + sprintf(buffer, speech_message(52), + get_charset_by_ind(cp->charset_in), + get_charset_by_ind(cp->charset_out)); +#else + sprintf(buffer, "*** Charset in/out set to %s/%s.\r", + get_charset_by_ind(cp->charset_in), + get_charset_by_ind(cp->charset_out)); +#endif + appenddirect(cp, buffer); + appendprompt(cp, 0); +} + +/*---------------------------------------------------------------------------*/ + +static void cstat_command(CONNECTION *cp) +{ + cp->verbose = 1; /* Flag wird beim Aendern der Links geloescht */ + if (*getarg(NULL, GET_ALL) != '#') { + links_command(cp); + getarg("", GET_NXTLC); /* damit hosts_command keine Argumente kriegt */ + } + if (cp->verbose) + hosts_command(cp); +} + +/*---------------------------------------------------------------------------*/ + +static void filter_command(CONNECTION *cp) +{ + ed_list(cp, 1); +} + +/*---------------------------------------------------------------------------*/ +/* Damit convers der sprachlichen Umgebung angepasst werden kann ist + * die Hilfe extern organisiert. Die Hilfedatei besteht aus den + * jeweiligen Hifstexten, die am Anfang ein Stichwort zum Suchen + * haben und zwar @@Stichwort. Der allgemeine Hilfetext sind die + * ersten Zeilen in der Datei, bis zum @@ des ersten Stichworts. + */ +static WORD read_xhelp(char *topic, CONNECTION *cp) +{ + FILE *fp; + char tmp[128], ts[16]; + char *c; +#ifdef L1IRC + char buffer[2048]; +#endif /* L1IRC */ + + if (!topic) + return(0); + + sprintf(tmp, "%sconversd.xhf", textpath); + if ((fp = xfopen(tmp, "rt")) == NULL) + return(0); + + if (*topic) { /* topic gesetzt, suchen... */ + sprintf(ts, "@@%s", topic); + do { + if (fgets(tmp, 120, fp) == NULL) { + fclose(fp); + return(0); + } + if ((c = strpbrk(tmp, "\r\n")) != NULL) + *c = NUL; + } + while (strcmp(ts,tmp)); + } + if (fgets(tmp, 120, fp) == NULL) { + fclose(fp); + return(0); + } + do { +#ifdef L1IRC + if (cp->IrcMode == TRUE) + sprintf(buffer, ":%s 372 %s :" + , myhostname + , cp->nickname); +#endif /* L1IRC */ + if ((c = strpbrk(tmp, "\r\n")) != NULL) + { + *c++ = '\r'; + *c = NUL; + } +#ifdef L1IRC + if (cp->IrcMode == TRUE) + appendstring(cp, buffer); +#endif /* L1IRC */ + appendstring(cp, tmp); + topic = fgets(tmp, 120, fp); + } + while (topic && (*tmp != '@' || *(tmp+1) != '@')); + fclose(fp); +#ifdef L1IRC + if (cp->IrcMode == TRUE) + { + sprintf(buffer, "\n:%s 376 %s :\n" + , myhostname + , cp->nickname); + appendstring(cp, buffer); + } +#endif /* L1IRC */ + return(1); +} + +#ifndef L1IRC +static void help_command(CONNECTION *cp) +#else +void help_command(CONNECTION *cp) +#endif /* L1IRC */ +{ + char *s1; + CMDTABLE *cmdp; + + s1 = getarg(NULL, GET_NXTLC); + if (*s1 == '/') + s1++; + + if (*s1 == '\0') + read_xhelp("", cp); + else { + for (cmdp = cmdtable; cmdp->name; cmdp++) + if ((cmdp->states & (1 << cp->type)) && !strnicmp(cmdp->name, s1, strlen(s1))) + break; + if (cmdp->name) + { + if (!read_xhelp(cmdp->help, cp)) +#ifdef SPEECH + appenddirect(cp, speech_message(53)); +#else + appenddirect(cp, "Help on this command not yet implemented...\rWrite it - or try another one :-)\r"); +#endif + } + else +#ifndef L1IRC +#ifdef SPEECH + appenddirect(cp, speech_message(54)); +#else + appenddirect(cp, "No such command...\r"); +#endif /* SPEECH */ +#else + { + char buffer[128]; + +#ifdef SPEECH + sprintf(buffer, speech_message(54)); +#else + sprintf(buffer, "No such command...\r"); +#endif /* SPEECH */ + if (cp->IrcMode == TRUE) + sprintf(buffer, ":%s 421 %s No such command...\n" + , myhostname + , (*cp->nickname ? cp->nickname : cp->name)); + + appenddirect(cp, buffer); + } +#endif /* L1RC */ + } + appendprompt(cp, 1); +} + +/*---------------------------------------------------------------------------*/ + +static void hosts_command(CONNECTION *cp) +{ + char buffer[256], tmp[64]; + DESTINATION *d; + WORD i = 1; + char *dest; + + dest = getarg(NULL, GET_NXTCS); + + if (*dest == '\0') { + for (d = destinations; d; d = d->next) { + if (d->rtt) { + sprintf(buffer, "%-9.9s (%-8.8s) %3s", d->name, d->rev, ts3(d->rtt,tmp)); + appenddirect(cp, buffer); + if ((i == 3) || !(d->next)) { + appenddirect(cp, "\r"); + i = 0; + } else { + appenddirect(cp, " "); + } + i++; + } + } + if ((i != 1)) { + appenddirect(cp, "\r"); + } + if (cp->type == CT_USER) { + appendprompt(cp, 1); + } + } else if (*dest == '#') { + for (d = destinations; d; d = d->next) { + if (d->rtt) + sprintf(buffer, "%-12.12s (%-8.8s) %5ld ->%-6s", d->name, d->rev, (long)d->rtt, d->link->cname); + else + sprintf(buffer, "%-12.12s 0 ", d->name); + appenddirect(cp, buffer); + if ((i == 2) || !(d->next)) { + appenddirect(cp, "\r"); + i = 0; + } else { + appenddirect(cp, " "); + } + i++; + } + if ((i != 1)) { + appenddirect(cp, "\r"); + } + if (cp->type == CT_USER) { + appendprompt(cp, 1); + } + } else { + for (d = destinations; d; d = d->next) { + if (d->rtt && d->link && !strcmp(d->name, dest)) { + clear_locks(); + sprintf(buffer, "*** Host : %s (%-8.8s) T=%lds\r", dest, d->rev, (long)d->rtt); + appenddirect(cp, buffer); + sprintf(buffer, "*** route: %s (%ld) %s -> %s\r", myhostname, + (long)((d->link->rxtime + d->link->txtime) / 2L), + d->link->cname, dest); + appenddirect(cp, buffer); + if (strcmp(dest, d->link->name)) { + sprintf(buffer, "/\377\200ROUT %s %s 99\r", dest, cp->name); + appenddirect(d->link->connection, buffer); + send_proto("cmds", "TX to %s %s", d->link->connection->name, buffer+3); + } + break; + } + } + if (d == NULLDESTINATION) { +#ifdef SPEECH + sprintf(buffer, speech_message(55), dest); +#else + sprintf(buffer, "*** no route to %s\r", dest); +#endif + appenddirect(cp, buffer); + } + appendprompt(cp, 0); + } +} + +/*---------------------------------------------------------------------------*/ + +static void imsg_command(CONNECTION *cp) +{ + char *toname, *text; + CONNECTION *p, *q; +#ifdef CONVNICK + char buf[2 * NAMESIZE + 2]; /* Name + ":" + Nickname + 1 */ +#endif + + toname = getarg(NULL, GET_NXTLC); + text = getarg(NULL, GET_ALL); + if (!*text) { + appendprompt(cp, 0); + return; + } + for (p = connections; p; p = p->next) + { +#ifdef CONVNICK + makeName(cp, buf); + + /* Typ User. */ + if ( p->type == CT_USER + /* Channelvergleich */ + && p->channel == cp->channel + /* Callvergleich */ + && (strcasecmp(p->name, toname) + /* Nicknamevergleich */ + || strcasecmp(p->nickname, toname)) != 0) + { + send_msg_to_user(buf, p->name, text); +#else + if (p->type == CT_USER && p->channel == cp->channel && strcmp(p->name, toname) != 0) { + send_msg_to_user(cp->name, p->name, text); +#endif + q = p->next; + while (q) { + if (!strcmp(p->name, q->name)) + q->locked = 1; + q = q->next; + } + } + if (p->via) + p->via->locked = 0; + } + appendprompt(cp, 0); +} + +/*---------------------------------------------------------------------------*/ + +static void invite_command(CONNECTION *cp) +{ + char *toname; + + toname = getarg(NULL, GET_NXTLC); + if (*toname) send_invite_msg(cp->name, toname, cp->channel); + appendprompt(cp, 0); +} + +/*---------------------------------------------------------------------------*/ + +#ifndef L1IRC +static void leave_command(CONNECTION *cp) +#else +void leave_command(CONNECTION *cp) +#endif /* L1IRC */ +{ + WORD chan; + WORD users_left; + CLIST *cl, *cl2; + char *arg; + char buffer[128]; + + arg = getarg(NULL, GET_NXTLC); +#ifdef L1IRC + if (arg && *arg == '#') + arg++; +#endif /* L1IRC */ + if (*arg) { + chan = atoi(arg); + } else { + chan = cp->channel; + } + if ((chan == cp->channel) && (cp->chan_list->next == NULLCLIST)) { +#ifndef L1IRC + bye_command(cp); + return; +#else + if (cp->IrcMode == FALSE) + { + bye_command(cp); + return; + } +#endif /* L1IRC */ + } + cl2 = cp->chan_list; +#ifdef L1IRC + if (cl2 == NULL) + { + if (cp->IrcMode == TRUE) + return; + } +#endif /* L1IRC */ + if (cl2->channel == chan) { + cp->chan_list = cl2->next; + free(cl2); + users_left = count_user(chan); + if (!users_left) destroy_channel(chan); + cp->locked = 1; +#ifndef CONVNICK + send_user_change_msg(cp->name, cp->host, chan, -1, "/leave", cp->time); +#else + send_user_change_msg(cp->name, cp->nickname, cp->host, chan, -1, "/leave", cp->time); +#endif /* CONVNICK */ + cp->locked = 0; + if (chan == cp->channel) { +#ifndef L1IRC + cp->channel = cp->chan_list->channel; + cp->channelop = cp->chan_list->channelop; +#else + cp->channel = (cp->chan_list) ? cp->chan_list->channel : -1; + cp->channelop = (cp->chan_list) ? cp->chan_list->channelop : 0; + + if (cp->IrcMode == TRUE) + { + sprintf(buffer,":%s!%s@%s PART #%d\n" + ,(*cp->nickname ? cp->nickname : cp->name) + ,cp->name + ,cp->host + ,chan); + appenddirect(cp, buffer); + appendprompt(cp, 0); + return; + } +#endif /* L1IRC */ +#ifdef SPEECH + sprintf(buffer, speech_message(56), timestamp, cp->channel); +#else + sprintf(buffer, "%sDefault channel is now %d.\r", timestamp, cp->channel); +#endif + appenddirect(cp, buffer); + appendprompt(cp, 0); + } else { +#ifdef SPEECH + sprintf(buffer, speech_message(57), timestamp, chan); +#else + sprintf(buffer, "%sLeft channel %d.\r", timestamp, chan); +#endif +#ifdef L1IRC + if (cp->IrcMode == TRUE) + sprintf(buffer,":%s!%s@%s PART #%d\n" + ,(*cp->nickname ? cp->nickname : cp->name) + ,cp->name + ,cp->host + ,chan); +#endif /* L1IRC */ + appenddirect(cp, buffer); + appendprompt(cp, 0); + } + return; + } + cl = cp->chan_list; + while (cl) { + if (cl->channel == chan) { + cl2->next = cl->next; + free (cl); + cl = cl2; + users_left = count_user(chan); + if (!users_left) destroy_channel(chan); + cp->locked = 1; +#ifndef CONVNICK + send_user_change_msg(cp->name, cp->host, chan, -1, "/leave", cp->time); +#else + send_user_change_msg(cp->name, cp->nickname, cp->host, chan, -1, "/leave", cp->time); +#endif /* CONVNICK */ + cp->locked = 0; + if (chan == cp->channel) { +#ifndef L1IRC + cp->channel = cp->chan_list->channel; + cp->channelop = cp->chan_list->channelop; +#else + cp->channel = (cp->chan_list) ? cp->chan_list->channel : -1; + cp->channelop = (cp->chan_list) ? cp->chan_list->channelop : 0; +#endif /* L1IRC */ +#ifdef SPEECH + sprintf(buffer, speech_message(56), timestamp, cp->channel); +#else + sprintf(buffer, "%sDefault channel is now %d.\r", timestamp, cp->channel); +#endif +#ifdef L1IRC + if (cp->IrcMode == TRUE) + sprintf(buffer,":%s!%s@%s PART #%d\n" + ,(*cp->nickname ? cp->nickname : cp->name) + ,cp->name + ,cp->host + ,chan); +#endif /* L1IRC */ + appenddirect(cp, buffer); + appendprompt(cp, 0); + return; + } else { +#ifdef SPEECH + sprintf(buffer, speech_message(57), timestamp, chan); +#else + sprintf(buffer, "%sLeft channel %d.\r", timestamp, chan); +#endif + appenddirect(cp, buffer); + appendprompt(cp, 0); + return; + } + } else { + cl2 = cl; + } + cl = cl->next; + } +#ifdef SPEECH + sprintf(buffer, speech_message(58), timestamp, chan); +#else + sprintf(buffer, "%sYou were not on channel %d.\r", timestamp, chan); +#endif +#ifdef L1IRC + if (cp->IrcMode == TRUE) + sprintf(buffer, ":%s 442 %s #%d :You were not on channel\n" + , myhostname + , (*cp->nickname ? cp->nickname : cp->name) + , chan); +#endif /* L1IRC */ + appenddirect(cp, buffer); + appendprompt(cp, 0); +} + +/*---------------------------------------------------------------------------*/ +static BOOLEAN scan_linksarg(char *arg, char *hostname, WORD *act, +#ifndef OS_IPLINK + char *call, char *via, WORD *prt) +#else + char *call, char *via, WORD *prt, unsigned char *ip) +#endif /* OS_IPLINK */ +{ + WORD port, bcnt; + char buffer[256], *bp; + + if (*arg == '-' || *arg == '+') { + if (*arg == '-') + *act = 1; + do { + arg++; + } while (*arg == ' '); + } + + bcnt = (WORD) min(strlen(arg), 255); + if (!bcnt) + return(FALSE); + + arg[bcnt] = NUL; + bp = buffer; + strcpy(buffer, arg); + +#ifndef OS_IPLINK + if (getcal(&bcnt, &bp, TRUE, call) != YES) /* Call ok ? */ + return(FALSE); + + callss2str(hostname, call); /* hostname: Call ohne SSID */ +#else + /* Pruefe ob Servername korrekt ist. */ + if (IPConvGetName(&bcnt, &bp, FALSE, hostname) != TRUE) + /* Nicht korrekt, abbruch. */ + return(FALSE); + + /* Pruefe das AX25-CALL. */ + if (getcal(&bcnt, &bp, TRUE, call) == YES) /* Call ok ? */ + *ip = '\0'; + else + { + int TcpPort = 0; + + /* IP-Adresse pruefen. */ + if (IPConvGetIP(&bcnt, &bp, ip) == YES) /* Call ok ? */ + { + struct hostent *he; + + /* Hostname oder IP-Adresse pruefen. */ + he = gethostbyname((char *)ip); + + if (he == NULL) + return(FALSE); + + strncpy(call, hostname, L2CALEN); + call[6] = NUL; + strlwr(hostname); + *prt = 255; + *via = '\0'; + + /* keine weiteren Angaben */ + if (skipsp(&bcnt, &bp) == FALSE) + return(FALSE); + + TcpPort = nxtlong(&bcnt, &bp); + *prt = TcpPort; + + /* Falscher Port */ + if ( (TcpPort <= 0) + ||(TcpPort > 65535)) + return(FALSE); + else + IPConvAddTBL(call, ip, he, (unsigned short)TcpPort, TRUE); + + return(TRUE); + } + else + { + /* Es ist kein IP-Link. */ + *ip = '\0'; + /* Es wuerde kein AX25-CALL gesetzt! */ + cpyid(call, hostname); + /* hostname: Call ohne SSID */ + callss2str(hostname, call); + + if (*act) + { + strlwr(hostname); + IPConvDelTBL(hostname); + return(TRUE); + } + } + } +#endif /* OS_IPLINK */ + + strlwr(hostname); + if (*act) /* Beim Loeschen reicht das soweit */ + return(TRUE); + + *prt = 255; + *via = '\0'; + + if (skipsp(&bcnt, &bp) == FALSE) /* keine weiteren Angaben */ + return(TRUE); + + if (bcnt && !isdigit(*bp)) /* Keine Portangabe */ + return(FALSE); + + port = nxtnum(&bcnt, &bp); + if (port >= L2PNUM && port != 254) /* Falscher Port */ + return(FALSE); + + *prt = port; + if (port != 254) + getdig(&bcnt, &bp, 0, via); + + return(TRUE); +} + + +/* /links - host loeschen (egal, ob L2 oder circuit) + * /links [+] host circuit eintragen + * /links [+] host port [vialist] L2 Verbindung eintragen + * /links @ host Fernabfrage versenden + */ + +#ifndef L1IRC +static void links_command(CONNECTION *cp) +#else +void links_command(CONNECTION *cp) +#endif /* L1IRC */ +{ + char buffer[128]; +#ifndef CONVERS_HOSTNAME + char hn[L2CALEN+1], hc[L2IDLEN], hv[L2VLEN+1]; +#else + char hn[NAMESIZE + 1], /* Server-Name */ + hc[L2IDLEN], /* AX25-Call */ + hv[L2VLEN+1]; /* Digipeater */ +#endif /* CONVERS_HOSTNAME */ + char *arg; + WORD pl, remove = 0, hp; + PERMLINK *p; + CONNECTION *c; +#ifdef CONVERS_LINKS + char name[NAMESIZE + 1]; +#endif +#ifdef OS_IPLINK + unsigned char Hostname[HNLEN + 1]; + + Hostname[0] = 0; +#endif /* OS_IPLINK */ + + arg = getarg(NULL, GET_ALL); + if (*arg == '@' && cp->type == CT_USER) { /* Fernabfrage, aehnlich tpp */ + arg = getarg(NULL, GET_NXTCS); + if (*arg == '@') arg++; + if (!*arg) arg = getarg(NULL, GET_NXTCS); + if (!Strcmp(myhostname, arg)) { + disp_links(cp, NULL); + appendprompt(cp, 1); + } else { + sprintf(buffer, "/\377\200LINK %s %s\r", cp->name, arg); + for (c = connections; c; c = c->next) + if (c->type == CT_HOST) { + appenddirect(c, buffer); + send_proto("cmds", "TX to %s %s", c->name, buffer+3); + } +#ifdef SPEECH + sprintf(buffer, speech_message(59), arg); +#else + sprintf(buffer, "*** Request sent to %s.\r", arg); +#endif + appenddirect(cp, buffer); + appendprompt(cp, 0); + } + return; + } + if (*arg) { + if (cp->operator != 2) { +#ifdef SPEECH + appenddirect(cp, speech_message(60)); +#else + appenddirect(cp, "You must be an operator to set up new links\r"); +#endif + } else { +#ifndef OS_IPLINK + if (scan_linksarg(arg, hn, &remove, hc, hv, &hp) == TRUE) { +#else + if (scan_linksarg(arg, hn, &remove, hc, hv, &hp, Hostname) == TRUE) { +#endif /* OS_IPLINK */ + for (pl = 0; pl < MAXCVSHOST; pl++) { + p = permarray[pl]; +#ifdef CONVERS_LINKS + /* es sind kein eintrage vorhanden. */ + if (p == NUL) + /* zum Schleifenkopf. */ + continue; + /* kopie vom AX25 Rufzeichen. */ + strcpy(name,hn); + /* In Grossbuchstaben umwandeln. */ + strupr(name); + /* Vergleiche Conversname und AX25 Rufzeichen. */ + if ((!strcasecmp(p->cname, hn)) || (cmpcal(p->call, name))) { +#else + if (p && (!strcmp(p->cname, hn) || !cmpcal(p->call, hn))) { +#endif + if (p->connection) + bye_command2(p->connection, "link killed"); + if (permarray[pl] != NULLPERMLINK) { + permarray[pl] = NULLPERMLINK; + free(p); + } + break; + } + } + for (c = connections; c; c = c->next) + if (!strcmp(c->name, hn)) + bye_command2(c, "link killed"); + if (!remove) { + p = update_permlinks(hn, NULLCONNECTION, 1); + if (p) { + strncpy(p->cname, hn, NAMESIZE); + p->port = hp; /* port */ + cpyid(p->call, hc); /* call */ + cpyidl(p->via, hv); /* digis */ +#ifdef OS_IPLINK + if (Hostname[0] != FALSE) + { + strncpy((char *)p->HostName, (char *)Hostname, HNLEN); + p->TcpLink = TRUE; + } + else + p->TcpLink = FALSE; +#endif /* OS_IPLINK */ + } else { +#ifdef SPEECH + appenddirect(cp, speech_message(61)); +#else + appenddirect(cp, "Link table full !\r"); +#endif + } + } + cp->verbose = 0; /* bei cstat keine Destinations mehr anzeigen */ + userpo->sysflg = 2; + } else { +#ifdef SPEECH + appenddirect(cp, speech_message(62)); +#else + appenddirect(cp, "Argument error !\r"); +#endif + } + } + } + disp_links(cp, NULL); + if (cp->type == CT_USER) { + appendprompt(cp, 1); + } +} + +static void disp_links(CONNECTION *cp, char *user) +{ + char buffer[128], *bp, tmp[10]; + WORD pl; + PERMLINK *p; + + strcpy(buffer, "Host State Quality Revision Since NextTry Tries Queue RX TX"); + if (user) { + clear_locks(); + send_msg_to_user ("conversd", user, buffer); + } else { + strcat(buffer, "\r"); + appenddirect(cp, buffer); + } + for (pl = 0; pl < MAXCVSHOST; pl++) { + p = permarray[pl]; + if (p) { + bp = buffer; + bp += sprintf(bp, "%-9.9s ", p->cname); + if (!p->connection) { + bp += sprintf(bp, "%s --- %s", + (p->locked)?"Disc./locked":"Disconnected", ts(p->statetime)); + if (p->port != 254) + bp += sprintf(bp, " %s %5d", ts(p->retrytime), p->tries); + } else { + if (p->connection->type == CT_HOST) { + bp += sprintf(bp, "Connected "); + if (p->txtime || p->rxtime) { + if (p->rxtime == -1) { + bp += sprintf(bp, " %3s ", ts3(p->txtime, tmp)); + } else { + bp += sprintf(bp, "%3s/", ts3(p->txtime, tmp)); + bp += sprintf(bp, "%-3s", ts3(p->rxtime, tmp)); + } + } else { + bp += sprintf(bp, " --- "); + } + bp += sprintf(bp, " %-8.8s %s %5ld %4ldK %4ldK", + p->connection->rev, ts(p->connection->time), + queuelength(p->connection), p->connection->received/1024L, + p->connection->xmitted/1024L); + } else { + bp += sprintf(bp, "Connecting --- %s", ts(p->statetime)); + bp += sprintf(bp, " %s %5d", ts(p->retrytime), p->tries); + } + } + if (user) { + clear_locks(); + send_msg_to_user ("conversd", user, buffer); + } else { + strcpy(bp, "\r"); + appenddirect(cp, buffer); + + if (cp->operator) { + call2str(tmp, p->call); + bp = buffer; + if (p->port == 254) { + bp += sprintf(bp, "(trusted host"); + } else { +#ifdef OS_IPLINK + if (p->TcpLink) + bp += sprintf(bp, "(%s", p->HostName); + else +#endif /* OS_IPLINK */ + bp += sprintf(bp, "(%s", tmp); + if (p->port != 255) { + bp += sprintf(bp, " on port %d", p->port); + if (*p->via) { + char *liste = p->via; + bp += sprintf(bp, " via"); + while (*liste) { + call2str(tmp, liste); + bp += sprintf(bp, " %s", tmp); + liste += L2IDLEN; + } + } + } + } + strcpy(bp, ")\r"); + appenddirect(cp, buffer); + } + } + if (p->nlcks) { + sprintf(buffer, " %d loops detected.", p->nlcks); + if (user) { + clear_locks(); + send_msg_to_user ("conversd", user, buffer); + } else { + strcat(buffer, "\r"); + appenddirect(cp, buffer); + } + } + } + } + if (user) { + clear_locks(); + send_msg_to_user ("conversd", user, "***"); + } +} + +/*---------------------------------------------------------------------------*/ + +static void list_command(CONNECTION *cp) +{ + char buffer[2048]; + char *flags, *bp; + register CHANNEL *ch; + WORD hide, showit, isonchan, n; + CONNECTION *p; + CLIST *cl; +#ifdef CONVNICK + char buf[(NAMESIZE * 2) + 2]; +#endif + + appenddirect(cp, "Channel Flags Topic\r Users\r"); + for (ch = channels; ch; ch = ch->next) { + isonchan = 0; + hide = 0; + if (ch->chan == cp->channel) + isonchan++; + for (cl = cp->chan_list; cl && !isonchan; cl = cl->next) { + if (cl->channel == ch->chan) { + isonchan++; + } + } + flags = getflags(ch->flags); + if (ch->flags & M_CHAN_S) + hide |= 1; + if (ch->flags & M_CHAN_I) + hide |= 2; + showit = 0; + bp = buffer; + if (!hide || isonchan || cp->operator) { + if (!ch->flags && (!ch->topic)) { + bp += sprintf(bp, "%7d", ch->chan); + } else { + bp += sprintf(bp, "%7d %-6.6s %s\r ", ch->chan, flags, ch->topic?ch->topic:""); + } + showit++; + } else { + if (hide == 1) { + bp += sprintf(bp, "------- %-6.6s %s\r ", flags, ch->topic?ch->topic:""); + showit++; + } + } + n = 9; + if (showit) { + for (p = connections; p; p = p->next) { + if (p->type == CT_USER) { + if (p->via) { + if (p->channel == ch->chan) { + if (n > cp->width - 12) { + n = 9; + bp += sprintf(bp, "\r "); + } +#ifdef CONVNICK + /* Name:Nickname zusammen basteln. */ + makeName(p, buf); + bp += sprintf(bp, " %s(", buf); + n += 2 + (WORD)strlen(buf); +#else + bp += sprintf(bp, " %s(", p->name); + n += 2 + (WORD)strlen(p->name); +#endif /* CONVNICK */ + if (p->operator) { + *bp++ = '!'; + n++; + } + else if (p->channelop) { + *bp++ = '@'; + n++; + } + if (p->away) { + *bp++ = 'G'; + n++; + } + if (*(bp-1) == '(') { + bp--; + n--; + } else { + *bp++ = ')'; + n++; + } + } + } else { + for (cl = p->chan_list; cl; cl = cl->next) { + if (cl->channel == ch->chan) { + if (n > cp->width - 12) { + n = 9; + bp += sprintf(bp, "\r "); + } +#ifdef CONVNICK + /* Name:Nickname zusammen basteln. */ + makeName(p, buf); + bp += sprintf(bp, " %s(", buf); + n += 2 + (WORD)strlen(buf); +#else + bp += sprintf(bp, " %s(", p->name); + n += 2 + (WORD)strlen(p->name); +#endif /* CONVNICK */ + if (p->operator) { + *bp++ = '!'; + n++; + } + else if (cl->channelop) { + *bp++ = '@'; + n++; + } + if (p->away) { + *bp++ = 'G'; + n++; + } + if (*(bp-1) == '(') { + bp--; + n--; + } else { + *bp++ = ')'; + n++; + } + } + } + } + } + } + *bp++ = '\r'; + *bp = '\0'; + appendstring(cp, buffer); + } + } + if (cp->type == CT_USER) { + appendprompt(cp, 1); + } +} + +/*---------------------------------------------------------------------------*/ + +static void me_command(CONNECTION *cp) +{ + char *text; + char buffer[2048]; + CHANNEL *ch; + + text = getarg(NULL, GET_ALL); + + if (*text) { + for (ch = channels; ch; ch = ch->next) { + if (ch->chan == cp->channel) break; + } + if (cp->operator || cp->channelop || !(ch->flags & M_CHAN_M)) { + cp->locked = 1; +#ifdef CONVNICK + if (cp->nickname[0] != '\0') + sprintf(buffer, "*** %s:%s@%s %s", cp->name, cp->nickname, cp->host, text); + else + sprintf(buffer, "*** %s@%s %s", cp->name, cp->host, text); +#else + sprintf(buffer, "*** %s@%s %s", cp->name, cp->host, text); +#endif + send_msg_to_channel("conversd", cp->channel, buffer); + } else { +#ifdef SPEECH + appenddirect(cp, speech_message(31)); +#else + appenddirect(cp, "*** This is a moderated channel. Only channel operators may write.\r"); +#endif + } + } + appendprompt(cp, 0); +} + +/*---------------------------------------------------------------------------*/ + +#ifndef L1IRC +static void msg_command(CONNECTION *cp) +#else +void msg_command(CONNECTION *cp) +#endif /* L1IRC */ +{ + char *toname, *text; + char buffer[600]; + CONNECTION *p; + WORD chan; + CHANNEL *ch; + CLIST *cl; + + toname = getarg(NULL, GET_NXTLC); + text = getarg(NULL, GET_ALL); + if (!*text) { + appendprompt(cp, 0); + return; + } + if (toname[0] == '#') { + chan = atoi(toname+1); + for (cl = cp->chan_list; cl; cl = cl->next) { + if (cl->channel == chan) break; + } + if (!cl) { +#ifdef SPEECH + sprintf(buffer, speech_message(63), timestamp, chan); +#else + sprintf(buffer, "%sYou have not joined channel %d.\r", timestamp, chan); +#endif +#ifdef L1IRC + if (cp->IrcMode == TRUE) + sprintf(buffer, ":%s 405 %s #%d :Du hast den Kanal nicht betreten!\n" + , myhostname + , cp->nickname + , chan); +#endif /* L1IRC */ + appenddirect(cp, buffer); + } else { + for (ch = channels; ch; ch = ch->next) { + if (ch->chan == chan) break; + } + if (cl->channelop || !(ch->flags & M_CHAN_M)) { +#ifdef CONVNICK + makeName(cp, buffer); + send_msg_to_channel(buffer, chan, text); +#else + send_msg_to_channel(cp->name, chan, text); +#endif + } else { +#ifdef L1IRC + if (cp->IrcMode == TRUE) + { + sprintf(buffer, ":%s 481 %s :Permission Denied- You're not an IRC operator\n" + , myhostname + , cp->name); + appendstring(cp, buffer); + } + else +#endif /* L1IRC */ +#ifdef SPEECH + appenddirect(cp, speech_message(31)); +#else + appenddirect(cp, "*** This is a moderated channel. Only channel operators may write.\r"); +#endif + } + } + } else { + for (p = connections; p; p = p->next) +#ifdef CONVNICK + /* Typ User. */ + if ( p->type == CT_USER + /* Callvergleich */ + && (!strcasecmp(p->name, toname) + /* Nickamevergleich */ + || !strcasecmp(p->nickname, toname))) + break; +#else + if (p->type == CT_USER && !strcmp(p->name, toname)) break; +#endif + if (!p) { +#ifdef SPEECH + sprintf(buffer, speech_message(64), timestamp, toname); +#else + sprintf(buffer, "%sNo such user: %s.\r", timestamp, toname); +#endif +#ifdef L1IRC + if (cp->IrcMode == TRUE) + sprintf(buffer, ":%s 401 %s %s :No such nick\n" + , cp->host + , cp->nickname + , toname); +#endif /* L1IRC */ + appendstring(cp, buffer); + } else { + if (p->away) { +#ifdef SPEECH + sprintf(buffer, speech_message(65), timestamp, toname, p->away); +#else + sprintf(buffer, "%s%s is away: %s\r", timestamp, toname, p->away); +#endif +#ifdef L1IRC + if (cp->IrcMode == TRUE) + sprintf(buffer, ":%s 306 %s :User ist Abwesend!\n" + ,cp->host + ,cp->nickname); +#endif /* L1IRC */ + appendstring(cp, buffer); + } +#ifdef CONVNICK + makeName(cp, buffer); + send_msg_to_user(buffer, toname, text); +#else + send_msg_to_user(cp->name, toname, text); +#endif + } + } + appendprompt(cp, 0); +} + +/*---------------------------------------------------------------------------*/ + +static void mode_command(CONNECTION *cp) +{ + char *arg, *c; + WORD remove = 0; + WORD channel; + CONNECTION *p; + register CHANNEL *ch; + WORD oldflags = 0; + CLIST *cl; + WORD op = 0; + + if (cp->type == CT_USER) { + arg = getarg(NULL, GET_ALL); + if (isdigit(*arg)) + channel = atoi(getarg(NULL, GET_NXTLC)); + else + channel = cp->channel; + arg = getarg(NULL, GET_ALL); + for (cl = cp->chan_list; cl; cl = cl->next) { + if ((cl->channel == channel) && (cl->channelop)) { + op++; + break; + } + } + } + else { + channel = atoi(getarg(NULL, GET_NXTLC)); + arg = getarg(NULL, GET_ALL); + } + + for (ch = channels; ch; ch = ch->next) + if (channel == ch->chan) + break; + + if (!ch && cp->type == CT_USER) { +#ifdef SPEECH + appenddirect(cp, speech_message(66)); +#else + appenddirect(cp, "*** non existing channel !\r"); +#endif + appendprompt(cp, 0); + return; + } + + /* Kanal 0 soll keine setzbaren Flags haben. + Flags von Hosts werden durchgereicht. + Sysop loescht fern, bei Aufruf von /mo */ + if (channel == 0) { + if (cp->type == CT_USER) { /* bei uns eingegeben */ + if (!cp->operator) { /* User duerfen nix */ +#ifdef SPEECH + appenddirect(cp, speech_message(67)); +#else + appenddirect(cp, "*** no modes on channel 0 !\r"); +#endif + appendprompt(cp, 0); + return; + } + else { /* Sysop setzt andere Hosts */ + arg = "-sptiml"; /* zurueck (arg ist egal) */ + ch->flags = (WORD)0xFFFFU;/* alle Flags an, zum Loeschen */ + } + } + } /* Flags werden unten nochmals (nach Aussendung) geloescht */ + + if (*arg) { + if (op || cp->operator || (cp->type == CT_HOST)) { + if (ch) + oldflags = ch->flags; + while (*arg) { + switch (toupper(*arg)) { + case '+': + remove = 0; + arg++; + break; + + case '-': + remove = 1; + arg++; + break; + + case 'I': + if (ch) { + if (remove) ch->flags &= ~(M_CHAN_I); + else ch->flags |= M_CHAN_I; + } + arg++; + break; + + case 'L': + if (ch) { + if (remove) ch->flags &= ~(M_CHAN_L); + else ch->flags |= M_CHAN_L; + } + arg++; + break; + + case 'M': + if (ch) { + if (remove) ch->flags &= ~(M_CHAN_M); + else ch->flags |= M_CHAN_M; + } + arg++; + break; + + case 'O': + arg++; + while (*arg) { + while (*arg == ' ') arg++; + c = arg; + while (*c != '\0' && *c != ' ') { + *c = tolower(*c); + c++; /* damit gcc zufrieden ist :( */ + } + if (*c != '\0') + *c++ = '\0'; + for (p = connections; p; p = p->next) { + if (p->type == CT_USER && !Strcmp(p->name, arg)) { + if ((channel == -1) && (cp->type == CT_HOST)) { + p->operator = 1; +#ifndef L1IRC + send_opermsg(arg, p->host, cp->name, -1); +#else + send_opermsg(arg, p->host, cp->name, -1, 0); +#endif /* L1IRC */ + } else { + if (p->channel == channel) { + p->channelop = 1; + } + for (cl = p->chan_list; cl; cl = cl->next) { + if (cl->channel == channel) cl->channelop = 1; + } +#ifndef L1IRC + send_opermsg(arg, p->host, cp->name, -1); +#else + send_opermsg(arg, p->host, cp->name, -1, 0); +#endif /* L1IRC */ + } + } + } + arg = c; + } + break; + + case 'P': + if (ch) { + if (remove) ch->flags &= ~(M_CHAN_P); + else ch->flags |= M_CHAN_P; + } + arg++; + break; + + case 'S': + if (ch) { + if (remove) ch->flags &= ~(M_CHAN_S); + else ch->flags |= M_CHAN_S; + } + arg++; + break; + + case 'T': + if (ch) { + if (remove) ch->flags &= ~(M_CHAN_T); + else ch->flags |= M_CHAN_T; + } + arg++; + break; + + default: + arg++; + break; + } + } + if (ch && ch->flags != oldflags) { + if (cp->type == CT_HOST) + cp->locked = 1; +#ifndef L1IRC + send_mode(ch); +#else + send_mode(ch, cp, oldflags); +#endif /* L1IRC */ + if (channel == 0) /* KEINE Flags auf Kanal 0 ! */ + ch->flags = 0; + } + } else { +#ifdef SPEECH + appenddirect(cp, speech_message(68)); +#else + appenddirect(cp, "*** You are not an operator !\r"); +#endif + } + } + if (cp->type == CT_USER) { + appenddirect(cp, "*** Flags: "); + appenddirect(cp, getflags(ch->flags)); + appenddirect(cp, "\r"); + appendprompt(cp, 0); + } +} + + +/*---------------------------------------------------------------------------*/ + +static void name_command(CONNECTION *cp) +{ + char buffer[2048], *pers; + WORD newchannel; + LONG nc; + CHANNEL *ch; + CLIST *cl; + WORD cnt; + + getarg(NULL, GET_NXTLC); /* name */ + cp->type = CT_USER; + +#ifdef CONVERS_CTEXT + read_xhelp("CTEXT", cp); +#endif +#ifdef SPEECH + sprintf(buffer, speech_message(69), convtype, myhostname, strchr(REV, ':')+2); +#else + sprintf(buffer, "%s @ %s PingPong-Release %5.5s (TNN) - Type /HELP for help.\r", convtype, myhostname, strchr(REV, ':')+2); +#endif + appenddirect(cp, buffer); + + nc = atol(getarg(NULL, GET_NXTLC)); newchannel = (WORD)nc; + + if (nc < 0L || nc > MAXCHANNEL) { +#ifdef SPEECH + sprintf(buffer, speech_message(42), timestamp, MAXCHANNEL); +#else + sprintf(buffer, "%sChannel numbers must be in the range 0..%d.\r", timestamp, MAXCHANNEL); +#endif + appenddirect(cp, buffer); + newchannel = 0; + } + cp->channel = newchannel; + for (ch = channels; ch; ch = ch->next) { + if (ch->chan == cp->channel) break; + } + if (ch && (ch->flags & M_CHAN_P) && !cp->operator) { +#ifdef SPEECH + sprintf(buffer, speech_message(44), timestamp, newchannel); +#else + sprintf(buffer, "%sYou need an invitation to join channel %d.\r", timestamp, newchannel); +#endif + appenddirect(cp, buffer); +#ifdef CONCNICK + if (cp->nickname[0] != '\0') + sprintf(buffer, "%s%s:%s@%s try to join your privat channel.", timestamp, cp->name, cp->nickname, cp->host); + else + sprintf(buffer, "%s%s@%s try to join your privat channel.", timestamp, cp->name, cp->host); +#else + sprintf(buffer, "%s%s@%s try to join your privat channel.", timestamp, cp->name, cp->host); +#endif + send_msg_to_channel("conversd", cp->channel, buffer); + clear_locks(); + cp->locked = 1; + cp->channel = 0; + newchannel = 0; + for (ch = channels; ch; ch = ch->next) { + if (ch->chan == cp->channel) break; + } + } + pers = personalmanager(GET, cp, NULL); + + cl = (CLIST *) calloc(1, sizeof(CLIST)); + if (!cl || (!ch && NULL == ins_channel(newchannel)) ) { +#ifdef SPEECH + sprintf(buffer, speech_message(46), timestamp, newchannel); +#else + sprintf(buffer, "%scannot join channel %d, no more space.\r", timestamp, newchannel); +#endif + appenddirect(cp, buffer); + appendprompt(cp, 0); + if (cl) + free(cl); + cp->type = CT_CLOSED; + return; + } + if (ch) { + cnt = count_user(newchannel); +#ifdef SPEECH + sprintf(buffer, speech_message(47), timestamp, newchannel); +#else + sprintf(buffer, "%sYou are now talking to channel %d. ", timestamp, newchannel); +#endif + appenddirect(cp, buffer); + if (!cnt) { +#ifdef SPEECH + sprintf(buffer, speech_message(48)); +#else + sprintf(buffer, "You're alone.\r"); +#endif + } else { +#ifdef SPEECH + sprintf(buffer, speech_message(49), cnt+1); +#else + sprintf(buffer, "There are %d users.\r", cnt+1); +#endif + } + appenddirect(cp, buffer); + if (ch->topic) { +#ifdef CONV_TOPIC +#ifdef SPEECH + sprintf(buffer, speech_message(125), ch->name, ts(ch->time), ch->topic); +#else + sprintf(buffer, "*** current Topic by: %s (%s):\r %s\r" + , ch->name + , ts(ch->time) + , ch->topic); +#endif /* SPEECH */ +#else + sprintf(buffer, "*** current Topic is:\r %s\r", ch->topic); +#endif /* CONV_TOPIC */ + appendstring(cp, buffer); + } + cp->channelop = (has_ChOp(newchannel)) ? 0 : 1; + } else { +#ifdef SPEECH + sprintf(buffer, speech_message(72), cp->channel); +#else + sprintf(buffer, "*** You created a new channel %d.\r", cp->channel); +#endif + appenddirect(cp, buffer); + cp->channelop = 1; + } + cl->next = NULLCLIST; + cl->channelop = cp->channelop; + cl->channel = cp->channel; + cl->time = currtime; + cp->mtime = currtime; + cp->chan_list = cl; +#ifndef CONVNICK + send_user_change_msg(cp->name, cp->host, -1, cp->channel, pers, currtime); +#else + send_user_change_msg(cp->name, cp->nickname, cp->host, -1, cp->channel, pers, currtime); +#endif /* CONVNICK */ + if (cp->channelop) { + clear_locks(); +#ifndef L1IRC + send_opermsg(cp->name, cp->host, "conversd", cp->channel); +#else + send_opermsg(cp->name, cp->host, "conversd", cp->channel, 1); +#endif /* L1IRC */ + } + if (cp->operator) { /* TNN Sysop-Status wird durchgereicht */ + clear_locks(); +#ifndef L1IRC + send_opermsg(cp->name, cp->host, "conversd", cp->channel); +#else + send_opermsg(cp->name, cp->host, "conversd", cp->channel, 1); +#endif /* L1IRC */ + } + +#ifdef CONVNICK + /* ggf. Nickname setzen. */ + if (GetNickname(cp)) + { + /* Ausgabe vorbereiten. */ +#ifdef SPEECH + sprintf (buffer,speech_message(113),cp->nickname); +#else + sprintf(buffer, "*** Nickname set up: %s\r", cp->nickname); +#endif /* SPEECH. */ + send_uaddmsg(cp); /* Nickname an andere HOST's weiterleiten. */ + appendstring(cp, buffer); + } +#endif /* CONVNICK */ +#ifdef L1IRC + SendIrcNick(cp); +#endif /* L1IRC */ + + if (pers == NULL) + { /* freshmeat, jummy XAO*/ + read_xhelp("FAID", cp); + } + else + if (*pers) + { +#ifdef SPEECH + sprintf(buffer, speech_message(73), pers); +#else + sprintf(buffer, "*** Personal text and data set.\rHello, %s\r", pers); +#endif + appendstring(cp, buffer); +#ifdef CONVNICK + appendprompt(cp, 0); +#else + appendprompt(cp, 1); +#endif + setstring(&(cp->pers), pers, 256); + } else +#ifdef SPEECH + appenddirect(cp, speech_message(74)); +#else + appenddirect(cp, "*** Please set your personal text. ( /H PERS )\r"); +#endif +} + +/*---------------------------------------------------------------------------*/ + +#ifdef CONVNICK +static void nickname_command(CONNECTION *cp) +{ + char *s; + char buffer[128], *bp; + + s = getarg(NULL, GET_ALL); + + bp = buffer + sprintf(buffer, "%sYour nickname is ", timestamp); + + if (!*s) { + if (cp->nickname[0] != '\0') { + sprintf(bp, "\"%s\".\r", cp->nickname); + } + else { + appenddirect(cp, "*** No nickname set.\r"); + appendprompt(cp, 0); + return; + } + } + else { + if (!strcmp(s, "@")) { + s = "\0"; + strcpy(bp, "deleted.\r"); + } + else { +#ifndef CONVNICK_FIX + strcpy(cp->nickname, s, min(strlen(s)); +#else + /* Alten Nickname sichern. */ + strcpy(cp->OldNickname, cp->nickname); + /* Neuen Nickname sichern. */ + strcpy(cp->nickname, s); +#endif /* CONVNICKFIX */ + sprintf(bp, "\"%s\".\r", cp->nickname); + } + } + + /* Aenderungen merken */ + if (s != cp->nickname) + { + /* Alten Nickname sichern. */ + strncpy(cp->OldNickname, cp->nickname, NAMESIZE); + /* Neuen Nickname sichern. */ + strncpy(cp->nickname, s, NAMESIZE); + + /* Melden, wenn was gesetzt ist, abmelden ist anscheinend nicht moeglich */ + if (cp->nickname[0] != '\0') + send_uaddmsg(cp); + + appenddirect(cp, buffer); + appendprompt(cp, 0); + +#ifdef L1IRC + SendIrcNick(cp); +#endif /* L1IRC */ +#ifdef USERPROFIL + /* Aktualisiere Profil-Daten. */ + ProfilService(cp); +#endif /* USERPROFIL */ + return; + } + + appenddirect(cp, buffer); + appendprompt(cp, 0); +} + +/*---------------------------------------------------------------------------*/ + +static void nonickname_command(CONNECTION *cp) +{ + if (cp->nickname[0] != '\0') { + memset(cp->nickname, 0, NAMESIZE); + /* Nickname abmelden (nicht moeglich, nicht vorgesehen !) */ + /* send_uaddmsg(cp); */ + appenddirect(cp, "*** Nickname locally deleted.\r"); + } + else + appenddirect(cp, "*** No nickname set.\r"); + + appendprompt(cp, 0); +} + +#endif + +/*---------------------------------------------------------------------------*/ + +static void notify_command(CONNECTION *cp) +{ + ed_list(cp, 0); +} + +/*---------------------------------------------------------------------------*/ + +/* + * Bearbeiten von Userlisten + * which = 0 modifiziert die /notify-, sonst /filter-Liste + */ +static void ed_list(CONNECTION *cp, WORD which) +{ + char *p, *q, *toname; + CONNECTION *pc; + char buffer[256], tmp[512], wbuf[512]; + WORD action; + + toname = getarg(NULL, GET_NXTLC); + strcpy(tmp, toname); + toname = tmp; + + p = (which == 0) ? cp->notify : cp->filter; + if (p) + strcpy(wbuf, p); + else + *wbuf = '\0'; + + if (*toname == '\0') { + sprintf(buffer, +#ifdef SPEECH + (which == 0) ? speech_message(75) + : speech_message(76), +#else + (which == 0) ? "%sYou are notified if one of the following users sign on/off:\r" + : "%sYou filter the messages of the following users:\r", +#endif + + timestamp); + appenddirect(cp, buffer); + appendstring(cp, wbuf); + appenddirect(cp, "\r"); + } + + action = 0; + while (*toname) { + while ((*toname == '+') || (*toname == '-')) { + while (*toname == '+') { + action = 0; + toname++; + if (*toname == '\0') { + toname = getarg(NULL, GET_NXTLC); + strcpy(tmp, toname); + toname = tmp; + if (*toname == '\0') { + break; + } + } + } + while (*toname == '-') { + action = 1; + toname++; + if (*toname == '\0') { + toname = getarg(NULL, GET_NXTLC); + strcpy(tmp, toname); + toname = tmp; + if (*toname == '\0') { + break; + } + } + } + } + strcat(toname, " "); + p = wbuf; + p = strstr(p, toname); + while (p) { + p--; + if (*p != ' ') { + p++; + p++; + } else { + q = ++p; + while (*q != ' ') q++; + while (*q == ' ') q++; + while (*q != '\0') *p++ = *q++; + *p = *q; + p = wbuf; + } + p = strstr(p, toname); + } + if (action == 0 && strcmp(toname, "conversd ")) { + if (wbuf[0] == '\0') { + strcpy(wbuf, " "); + } + strcat(wbuf, toname); + if (which == 0) { + for (pc = connections; pc; pc = pc->next) { + sprintf(buffer, "%s ", pc->name); + if ((pc->type == CT_USER) && !strncmp(tmp, buffer, strlen(buffer))) { +#ifdef SPEECH + sprintf(buffer, speech_message(76), pc->name); +#else + sprintf(buffer, "*** %s is online.\r", pc->name); +#endif +#ifdef L1IRC + if (cp->IrcMode == TRUE) + sprintf(buffer, ":%s 303 %s :\n", myhostname, cp->nickname); +#endif /* L1IRC */ + appendstring(cp, buffer); + break; + } + } + } + } + toname = getarg(NULL, GET_NXTLC); + strcpy(tmp, toname); + toname = tmp; + } + appendprompt(cp, 0); + setstring((which == 0) ? &cp->notify : &cp->filter, wbuf, 256); +} + +/*---------------------------------------------------------------------------*/ + +static void personal_command(CONNECTION *cp) +{ + char *s; + char buffer[128], *bp; + + s = getarg(NULL, GET_ALL); + + bp = buffer + sprintf(buffer, "%sPersonal text ", timestamp); + + if (!*s) { + if (cp->pers) { + s = cp->pers; +#ifdef SPEECH + strcpy(bp, speech_message(78)); +#else + strcpy(bp, "and data saved.\r"); +#endif + } else { +#ifdef SPEECH + appenddirect(cp, speech_message(79)); +#else + appenddirect(cp, "*** No personal text to save.\r"); +#endif + appendprompt(cp, 0); + return; + } + } else if (!strcmp(s, "@")) { + s = ""; +#ifdef SPEECH + strcpy(bp, speech_message(80)); +#else + strcpy(bp, "deleted.\r"); +#endif + } else { +#ifdef SPEECH + strcpy(bp, speech_message(81)); +#else + strcpy(bp, "and data set.\r"); +#endif + } + personalmanager(SET, cp, s); + if (s != cp->pers) { + setstring(&(cp->pers), s, 256); + cp->mtime = currtime; +#ifndef CONVNICK + send_persmsg(cp->name, myhostname, cp->channel, s, cp->time); +#else + send_persmsg(cp->name, cp->nickname, myhostname, cp->channel, s, cp->time); +#endif /* CONVNICK */ + } + appenddirect(cp, buffer); + appendprompt(cp, 0); +} + +/*---------------------------------------------------------------------------*/ + +static void prompt_command(CONNECTION *cp) +{ + char buffer[42]; + char *args, *p; + +#ifdef L1IRC + if (cp->IrcMode == TRUE) + { + char buffer[2048]; + + sprintf(buffer, ":%s 421 %s PROMPT :Unknown command\n", myhostname, cp->nickname); + appendstring(cp, buffer); + return; + } +#endif /* L1IRC */ + + args = getarg(NULL, GET_ALL); + p = cp->prompt; + p[2] = '\0'; + p[3] = '\0'; + p[0] = '\0'; + + if ((p[1] = args[0]) != '\0') + if ((p[2] = args[1]) != '\0') + if ((p[3] = args[2]) != '\0') + p[0] = args[3]; + if (p[3] == '\b' && p[0] == '\0') { + p[0] = '\b'; + p[3] = '\0'; + } + +#ifdef SPEECH + sprintf(buffer, speech_message(82), (*args) ? speech_message(83) : speech_message(84)); +#else + sprintf(buffer, "*** Prompting mode %sabled\r", (*args) ? "en" : "dis"); +#endif + appenddirect(cp, buffer); + appendprompt(cp, 0); +} + +/*---------------------------------------------------------------------------*/ +/* die loop-lock Loesung soll anders geschehen */ +/* restart loest die loop-locks, + mit dem Komando ist noch mehr geplant +*/ +static void restart_command(CONNECTION *cp) +{ + char buffer[128]; + WORD pl; + PERMLINK *p; + + if (cp->operator != 2) { +#ifndef L1IRC +#ifdef SPEECH + appenddirect(cp, speech_message(85)); +#else + appenddirect(cp, "You must be an operator to restart!\r"); +#endif +#else /* L1IRC */ + if (cp->IrcMode == FALSE) +#ifdef SPEECH + appenddirect(cp, speech_message(85)); +#else /* SPEECH */ + appenddirect(cp, "You must be an operator to restart!\r"); +#endif /* SPEECH */ + else + { + sprintf(buffer, ":%s 481 %s :Permission Denied - You're not an IRC operator\n", myhostname, cp->name); + appendstring(cp, buffer); + } +#endif /* L1IRC */ + } + else { + for (pl = 0; pl < MAXCVSHOST; pl++) { + p = permarray[pl]; + if (p) { + if (p->locked) { + p->locked = 0; + p->statetime = currtime; /* Aufbauzeit auf 1min spaeter setzen */ + p->tries = 0; + p->waittime = 60; + p->rxtime = 0; + p->txtime = 0; + p->testwaittime = currtime; + p->testnexttime = currtime + 60; + p->retrytime = currtime + p->waittime; +#ifdef SPEECH + sprintf(buffer, speech_message(86), p->cname); +#else + sprintf(buffer, "Link to %s delocked.\r", p->cname); +#endif + appenddirect(cp, buffer); + } + } + } + } + appendprompt(cp, 0); +} + +/*---------------------------------------------------------------------------*/ + +static void query_command(CONNECTION *cp) +{ + char *toname; + char buffer[128]; + CONNECTION *p; + +#ifdef L1IRC + if (cp->IrcMode == TRUE) + { + sprintf(buffer, ":%s 421 %s QUERY :Unknown command\n", myhostname, cp->nickname); + appendstring(cp, buffer); + return; + } +#endif /* L1IRC */ + + toname = getarg(NULL, GET_NXTLC); + + if (*toname) { + for (p = connections; p; p = p->next) +#ifdef CONVNICK + /* Typ User. */ + if ( p->type == CT_USER + /* Callvergleich. */ + && (!strcasecmp(p->name, toname) + /* Nicknamevergleich. */ + || !strcasecmp(p->nickname, toname))) + break; +#else + if (p->type == CT_USER && !strcmp(p->name, toname)) break; +#endif + if (!p) { +#ifdef SPEECH + sprintf(buffer, speech_message(87), timestamp, toname); +#else + sprintf(buffer, "%sNo such user: %.20s.\r", timestamp, toname); +#endif + appendstring(cp, buffer); + } + else { + strcpy(cp->query, toname); +#ifdef SPEECH + sprintf(buffer, speech_message(88), timestamp, cp->query); +#else + sprintf(buffer, "%sStarting private conversation with %s.\r", timestamp, cp->query); +#endif + appendstring(cp, buffer); + } + } + else if (cp->query[0] != '\0') { +#ifdef SPEECH + sprintf(buffer, speech_message(89), timestamp, cp->query); +#else + sprintf(buffer, "%sEnding private conversation with %s.\r", timestamp, cp->query); +#endif + appendstring(cp, buffer); + cp->query[0] = '\0'; + } + appendprompt(cp, 0); +} + +/*---------------------------------------------------------------------------*/ + +static void topic_command(CONNECTION *cp) +{ + CHANNEL *ch; + CONNECTION *p; + register char *topic; + char buffer[2048]; + time_t time; + WORD channel; + + channel = cp->channel; + topic = getarg(NULL, GET_ALL); + if (*topic == '#') { + topic++; + while (*topic == ' ') topic++; + channel = atoi(topic); + while (*topic && *topic != ' ') topic++; + while (*topic == ' ') topic++; + } +#ifdef L1IRC + if (cp->IrcMode == TRUE) + { + if (channel < 0) + { + sprintf(buffer, ":%s 442 %s * :No channel joined. Try /join #\n", myhostname, cp->nickname); + appendstring(cp, buffer); + return; + } + + if (*topic == ':') + { + if (!*(topic+1)) + *topic = '@'; // mark deleted + else + topic++; + } + } +#endif /* L1IRC */ + for (p = connections; p; p = p->next) + if (p->type == CT_USER && !strcmp(p->name, cp->name) && (p->channel == channel)) break; + time = currtime; + for (ch = channels; ch; ch = ch->next) { + if (ch->chan == channel) break; + } + if (ch) { + if (ch->time > time) time = ch->time+1L; + if (*topic) { + if (p && (((ch->flags & M_CHAN_T) == 0) || cp->operator || p->channelop)) { + if (*topic == '@') { + *topic = '\0'; +#ifdef CONV_TOPIC +#ifdef SPEECH + sprintf(buffer, speech_message(90), timestamp, channel, ch->name, ts(ch->time)); +#else + sprintf(buffer, "%sChannel topic on channel %d removed from %s (%s).\r" + , timestamp + , channel + , ch->name + , ts(ch->time)); +#endif /* SPEECH */ +#else + sprintf(buffer, "%sChannel topic on channel %d removed.\r", timestamp, channel); +#endif /* CONV_TOPIC */ + } else { +#ifdef CONV_TOPIC + /* Topic sichern. */ + setstring(&(ch->topic), topic, 512); + /* Call sichern. */ + strncpy(ch->name, cp->name, NAMESIZE + 1); + /* Nullzeichen setzen. */ + ch->name[sizeof(ch->name)-1] = 0; + /* Zeit sichern. */ + ch->time = time; +#ifdef SPEECH + sprintf(buffer, speech_message(91), timestamp, channel, ch->name, ts(ch->time)); +#else + sprintf(buffer, "%sChannel topic set on channel %d from %s (%s).\r" + , timestamp + , channel + , ch->name + , ts(ch->time)); +#endif /* SPEECH */ +#else + sprintf(buffer, "%sChannel topic set on channel %d.\r", timestamp, channel); +#endif /* CONV_TOPIC */ +#ifdef L1IRC + if (cp->IrcMode == TRUE) + sprintf(buffer, ":%s TOPIC #%d :%s\n", cp->nickname, channel, topic); +#endif /* L1IRC */ + } +#ifndef CONVNICK + send_topic(cp->name, cp->host, time, channel, topic); +#else + send_topic(cp->name, cp->nickname, cp->host, time, channel, topic); +#endif /* CONVNICK */ + } else { +#ifdef SPEECH + sprintf(buffer, speech_message(68), timestamp); +#else + sprintf(buffer, "%sYou are not an operator.\r", timestamp); +#endif +#ifdef L1IRC + if (cp->IrcMode == TRUE) + sprintf(buffer, ":%s 482 %s #%d :%s\n", myhostname, cp->name, channel, speech_message(68)); +#endif /* L1IRC */ + } + } else { + if (ch->topic) + { +#ifdef CONV_TOPIC +#ifdef SPEECH + sprintf(buffer, speech_message(92), timestamp, channel, ch->name, ts(ch->time)); +#else + sprintf(buffer, "%sCurrent channel topic on channel %d from %s (%s) is\r " + , timestamp + , channel + , ch->name + , ts(ch->time)); +#endif /* SPEECH */ +#else + sprintf(buffer, "%sCurrent channel topic on channel %d is\r " + , timestamp + , channel); +#endif /* CONV_TOPIC */ +#ifndef L1IRC + appenddirect(cp, buffer); + appendstring(cp, ch->topic); + strcpy(buffer, "\r"); +#else + if (cp->IrcMode == TRUE) + { + sprintf(buffer, ":%s 332 %s #%d :%s",cp->host,*cp->nickname ? cp->nickname : cp->name, cp->channel, ch->topic); + buffer[2048] = 0; + appendstring(cp, buffer); + appendstring(cp, "\n"); + sprintf(buffer, ":%s 333 %s #%d %ld\n",cp->host,*cp->nickname ? cp->nickname : cp->name, channel, ch->time); + } + else + { + appenddirect(cp, buffer); + appendstring(cp, ch->topic); + strcpy(buffer, "\r"); + } +#endif /* L1IRC */ + } else { +#ifdef SPEECH + sprintf(buffer, speech_message(93), timestamp, channel); +#else + sprintf(buffer, "%sNo current channel topic on channel %d.\r", timestamp, channel); +#endif +#ifdef L1IRC + if (cp->IrcMode == TRUE) + sprintf(buffer, ":%s 331 %s #%d :There isn't a topic.\n", myhostname, cp->nickname, channel); +#endif /* L1IRC */ + } + } + } else { +#ifdef SPEECH + sprintf(buffer, speech_message(94), timestamp, channel); +#else + sprintf(buffer, "%sChannel channel %d non existent.\r", timestamp, channel); +#endif +#ifdef L1IRC + if (cp->IrcMode == TRUE) + sprintf(buffer, ":%s 442 %s #%d :%s\n", myhostname, cp->nickname, channel, speech_message(94)); +#endif /* L1IRC */ + } + appenddirect(cp, buffer); + appendprompt(cp, 0); +} + +/*---------------------------------------------------------------------------*/ + +static void uptime_command(CONNECTION *cp) +{ + char buffer[128]; + +#ifdef SPEECH + sprintf(buffer, speech_message(95), convtype, myhostname, ts4(currtime - boottime)); +#else + sprintf(buffer, "*** %s@%s is up for %s\r", convtype, myhostname, ts4(currtime - boottime)); +#endif +#ifdef L1IRC + if (cp->IrcMode == TRUE) + { + sprintf(buffer, ":%s 242 %s :Server Up %s\n", myhostname, cp->name, ts4(currtime - boottime)); + appendstring(cp, buffer); + appendprompt(cp, 0); + return; + } +#endif /* L1IRC */ + appenddirect(cp, buffer); + appendprompt(cp, 0); +} + +/*---------------------------------------------------------------------------*/ + +static void verbose_command(CONNECTION *cp) +{ + char buffer[32]; + + cp->verbose = 1 - cp->verbose; +#ifdef SPEECH + sprintf(buffer, speech_message(96), (cp->verbose) ? speech_message(83) : speech_message(84)); +#else + sprintf(buffer, "*** Verbose mode %sabled\r", (cp->verbose) ? "en" : "dis"); +#endif +#ifdef L1IRC + if (cp->IrcMode == TRUE) + { + sprintf(buffer, ":%s MODE %s %cws\n", myhostname, cp->name, cp->verbose ? '+' : '-'); + appendstring(cp, buffer); + appendprompt(cp, 0); + return; + } +#endif /* L1IRC */ + appenddirect(cp, buffer); + appendprompt(cp, 0); +} + +/*---------------------------------------------------------------------------*/ + +static void version_command(CONNECTION *cp) +{ + char buffer[128]; + + sprintf(buffer, "*** conversd PingPong-Release %5.5s (TNN)\r", strchr(REV, ':')+2); + appenddirect(cp, buffer); +#ifdef SPEECH + appenddirect(cp, speech_message(97)); + appenddirect(cp, speech_message(98)); +#else + appenddirect(cp, " This conversd implementation was originally written by Dieter Deyke\r" + " . It was modified and maintained up to version\r" + " 3.11 by Fred Baumgarten, dc6iq. This implementation is partly rewritten,\r" + " enhanced and maintained by Odo Roscher \r" + " for TheNetNode and Xnet.\r"); +#endif + appendprompt(cp, 1); +} + +/*---------------------------------------------------------------------------*/ + +static void who_command(CONNECTION *cp) +{ + char buffer[2048]; + char tmp[20]; + WORD flags; + WORD thischan = -1; + WORD full = 0; + WORD aways = 0; + WORD user = 0; + char channelstr[16]; + char *options; + char *athost = NULL; + CONNECTION *p; + CHANNEL *ch; + CLIST *cl; + WORD showit; + WORD opstat; + WORD isop; + WORD width, w; +#ifdef CONVERS_USERANZAHL + WORD usercount = FALSE; +#endif + + options = getarg(NULL, GET_NXTLC); + if ( *options == '\0' + || strchr("*aln@u", *options) == NULL) { + list_command(cp); + return; + } +#ifdef CONVNICK + appenddirect(cp, "User Nickname Host Via Chan. "); +#else + appenddirect(cp, "User Host Via Chan. "); +#endif + width = cp->width; + if (width < 66) + width = 80; + switch (*options) { + case '*': +#ifdef SPEECH + appenddirect(cp, speech_message(99)); +#else + appenddirect(cp, " Idle Personal\r"); +#endif + thischan = cp->channel; + break; + case 'a': +#ifdef SPEECH + appenddirect(cp, speech_message(100)); +#else + appenddirect(cp, "Login State\r"); +#endif + aways = 1; + break; + case 'u': + user = 1; + options++; + if (!*options) + options = getarg(NULL, GET_ALL); + case 'l': + appenddirect(cp, "Login Queue RX TX\r"); + full = 1; + break; + case '@': + athost = ++options; + if (!*athost) + athost = getarg(NULL, GET_NXTCS); + case 'n': +#ifdef SPEECH + appenddirect(cp, speech_message(101)); +#else + appenddirect(cp, "Login Personal\r"); +#endif + } + if (!user && athost == NULL) { /* optional bei *,a,l,n */ + options = getarg(NULL, GET_NXTLC); /* Kanalfilter setzen */ + if (*options) + thischan = atoi(options); + } + + for (ch = channels; ch; ch = ch->next) { + flags = ch->flags; + for (p = connections; p; p = p->next) { + if (p->type != CT_USER) + continue; + showit = 0; + opstat = 0; + isop = 0; + if (p->channel == ch->chan) { + opstat = p->channelop; + showit = 1; + } + isop = cp->operator; + for (cl = cp->chan_list; cl; cl = cl->next) { + if (ch->chan == cl->channel) { + isop |= cl->channelop; + break; + } + } + for (cl = p->chan_list; cl; cl = cl->next) { + if (ch->chan == cl->channel) { + opstat = cl->channelop; + showit = 1; + break; + } + } + if ( ((flags & M_CHAN_I) && !(isop || ch->chan == cp->channel)) + || (thischan != -1 && thischan != ch->chan) + || (athost && strncmp(athost, p->host, strlen(athost))) + || (user && strstr(options, p->name) == NULL)) + showit = 0; + + if (showit) { + if (!(flags & M_CHAN_S) || (isop) || (ch->chan == cp->channel)) { + sprintf(channelstr, "%5d", ch->chan); + } else { + strcpy(channelstr, "-----"); + } + sprintf(buffer, full ? +#ifdef CONVNICK + "%-6.6s%c %-8.8s %-12.12s %-6.6s %5s %6s %5ld %7ld %7ld" : + "%-6.6s%c %-8.8s %-12.12s %-6.6s %5s %6s", + p->name, p->operator ? '!' : opstat ? '@' : ' ', + (p->nickname[0] != '\0' ? p->nickname : ""), p->host, +#else + "%-6.6s%c %-6.6s %-6.6s %5s %6s %5ld %7ld %7ld" : + "%-6.6s%c %-6.6s %-6.6s %5s %6s", + p->name, p->operator ? '!' : opstat ? '@' : ' ', p->host, +#endif + p->via ? p->via->name : "", channelstr, + (thischan != -1) ? ts3(currtime - p->mtime, tmp) : ts(p->time), + queuelength(p), p->received, p->xmitted); + w = width; + if (p->pers || aways) { + if (full) { + strcat(buffer, "\r Personal: "); + strcat(buffer, p->pers?p->pers:""); + } else { + strcat(buffer, " "); + if (aways) { + if (p->away) { + strncat(buffer, p->away, w - 51); +#ifdef SPEECH + strcat(buffer, speech_message(104)); +#else + strcat(buffer, " (since "); +#endif + strcat(buffer, ts(p->atime)); + strcat(buffer, ")"); + } else { +#ifdef SPEECH + strcat(buffer, speech_message(102)); +#else + strcat(buffer, "(here)"); +#endif + } + } else { + if (p->away) + w -= 7; + if (p->pers) +#ifdef CONVNICK + strncat(buffer, p->pers,22); +#else + strncat(buffer, p->pers, w - 36); +#endif + } + } + } + if (!aways) { + if (p->away) { + if (full) { +#ifdef SPEECH + strcat(buffer, speech_message(103)); +#else + strcat(buffer, "\r Away: "); +#endif + strcat(buffer, p->away); +#ifdef SPEECH + strcat(buffer, speech_message(104)); +#else + strcat(buffer, " (since "); +#endif + strcat(buffer, ts(p->atime)); + strcat(buffer, ")"); + } else { +#ifdef SPEECH + strcat(buffer, speech_message(105)); +#else + strcat(buffer, " (AWAY)"); +#endif + } + } else { + if (full) { + if (p->mtime) { +#ifdef SPEECH + strcat(buffer, speech_message(106)); +#else + strcat(buffer, "\r Last Activity: "); +#endif + strcat(buffer, ts(p->mtime)); + } + } + } + } + strcat(buffer, "\r"); +#ifdef CONVERS_USERANZAHL + usercount++; +#endif + appendstring(cp, buffer); + } + } + } + if (cp->type == CT_USER) { +#ifdef CONVERS_USERANZAHL +if (usercount != FALSE) + { + if (thischan == EOF) +#ifdef SPEECH + sprintf(buffer, speech_message(351),usercount); +#else + sprintf(buffer,"\r*** Insgesamt %d User auf allen Kanaelen ***\r",usercount); +#endif +else +#ifdef SPEECH + sprintf(buffer, speech_message(126),usercount, channelstr); +#else + sprintf(buffer,"\r*** %d User auf Kanal%s ***\r",usercount,channelstr); +#endif + appendstring(cp, buffer); + } else + { +#ifdef SPEECH + sprintf(buffer, speech_message(172)); +#else + sprintf(buffer,"No such User!\r"); +#endif + appendstring(cp, buffer); + } +#else + appendprompt(cp, 1); +#endif + } +} + +/*---------------------------------------------------------------------------*/ + +static void width_command(CONNECTION *cp) +{ + WORD neww; + char buffer[128]; + +#ifdef L1IRC + if (cp->IrcMode == TRUE) + { + sprintf(buffer, ":%s 421 %s WIDTH :Unknown command\n", myhostname, cp->nickname); + appendstring(cp, buffer); + return; + } +#endif /* L1IRC */ + + neww = atoi(getarg(NULL, GET_NXTLC)); + + if (neww == 0) +#ifdef SPEECH + sprintf(buffer, speech_message(107), cp->width); +#else + sprintf(buffer, "*** Current screen width is %d\r", cp->width); +#endif + else if (neww < 32 || neww > 255) +#ifdef SPEECH + sprintf(buffer, speech_message(108)); +#else + sprintf(buffer, "*** Range 32 to 255\r"); +#endif + else { + cp->width = neww; +#ifdef SPEECH + sprintf(buffer, speech_message(109), cp->width); +#else + sprintf(buffer, "*** Screen width set to %d\r", cp->width); +#endif + } + appenddirect(cp, buffer); + appendprompt(cp, 0); +} + +/*---------------------------------------------------------------------------*/ + +static void wall_command(CONNECTION *cp) +{ + char buffer[128]; + CONNECTION *p; + char *text; + + if (cp->operator != 2) { +#ifdef SPEECH + appenddirect(cp, speech_message(68)); +#else + appenddirect(cp, "*** You are not an operator !\r"); +#endif + appendprompt(cp, 0); + return; + } + + text = getarg(NULL, GET_ALL); + if (!*text) + return; + + for (p = connections; p; p = p->next) + if ( p->type == CT_USER + && !p->via + && p != cp) { +#ifdef SPEECH + sprintf(buffer, speech_message(110), cp->name); +#else + sprintf(buffer, "*** Urgent message from operator (%s):\r ", cp->name); +#endif + appenddirect(p, buffer); + appendstring(p, text); + appenddirect(p, "\r"); + appendprompt(p, 0); + } +} + +/*---------------------------------------------------------------------------*/ + +#ifdef CVS_ZAPPING +static void zap_command(CONNECTION *cp) +{ + char buffer[256], *arg; + + arg = getarg(NULL, GET_ALL); + if (cp->operator != 2 || !*arg) + return; + + sprintf(buffer, "/\377\200%.245s\r", arg); + for (cp = connections; cp; cp = cp->next) + if (cp->type == CT_HOST) { + appenddirect(cp, buffer); + send_proto("cmds", "TX to %s %s", cp->name, buffer+3); + } +} +#endif + +/*---------------------------------------------------------------------------*/ +/* Host-Kommandos */ +/*---------------------------------------------------------------------------*/ + +static void h_away_command(CONNECTION *cp) +{ + char *fromname, *hostname, *text; + time_t time; + CONNECTION *p; + int changed = 1; + + fromname = getarg(NULL, GET_NXTLC); + hostname = getarg(NULL, GET_NXTCS); + time = atol(getarg(NULL, GET_NXTLC)); + if (time <= MAXCHANNEL) /* altes AWAY erkennen */ + return; + + text = getarg(NULL, GET_ALL); + cp->locked = 1; + for (p = connections; p; p = p->next) { + if ( p->type == CT_USER + && !Strcmp(p->name, fromname) + && !Strcmp(p->host, hostname)) { + if (p->away && !strcmp(p->away, text)) { + changed = 0; + continue; + } + setstring(&(p->away), text, 256); + p->atime = time; + break; + } + } + if (changed) +#ifndef CONVNICK + send_awaymsg(fromname, hostname, time, text); +#else + send_awaymsg(fromname, p->nickname, hostname, time, text); +#endif /* CONVNICK */ +} + +/*---------------------------------------------------------------------------*/ + +#if !defined(__WIN32__) && !defined(__LINUX__) +#pragma warn -par +#endif +static void h_cmsg_command(CONNECTION *cp) +{ + char *text; + char *name; + WORD channel; +#ifdef CONVNICK + CONNECTION *p; + char name2[2 * NAMESIZE + 2]; /* Rufzeichen:Nickname */ + char Nickname[NAMESIZE + 1], + *c; +#endif + + name = getarg(NULL, GET_NXTLC); +#ifdef CONVNICK + memset(Nickname, 0, sizeof(Nickname)); + memset(name2, 0, sizeof(name2)); + + strncpy(name2, name, 2 * NAMESIZE + 1); /* String fuer Nickname Auswertung. */ + name2[sizeof(name2)-1] = 0; /* Sicher ist sicher. */ + + if ((c = strchr(name2, ':')) != NULL) /* Pruefe nach Nickname. */ + { + c++; /* Loesche zeichen ':'. */ + + strncpy(Nickname, c, NAMESIZE); /* Nickname sichern. */ + Nickname[sizeof(Nickname)-1] = 0; /* Sicher ist sicher. */ + *c = NUL; + } + + if (Nickname[0] != FALSE) /* Nickname gefunden. */ + { + for (p = connections; p; p = p->next) + { + if (!strncasecmp(p->name, name2, L2CALEN)) /* Callvergleich. */ + { + if (!strncasecmp(p->OldNickname /*Ist alter und neuer Nickname gleich,*/ + , p->nickname + , NAMESIZE)) + break; /* Keine Aenderung durchfuehren. */ + + strncpy(p->OldNickname, p->nickname, NAMESIZE); /* Alten Nick sichern. */ + strncpy(p->nickname, Nickname, NAMESIZE); /* Neuen Nick sichern. */ + p->nickname[sizeof(p->nickname)-1] = 0; /* Nullzeichen setzen. */ +#ifdef L1IRC + SendIrcNick(p); /* Nickname an alle IRC-Client's weiterleiten. */ +#endif /* L1IRC */ +#ifdef USERPROFIL + ProfilService(p); /* Aktualisiere Profil-Daten. */ + break; +#endif /* USERPROFIL */ + } + } + } +#endif /* CONVNICK */ + + if (strlen(name) > 64) /* 1. Schutz vor Nicknames */ + name[64] = NUL; + channel = atoi(getarg(NULL, GET_NXTLC)); + text = getarg(NULL, GET_ALL); + if (*text) + send_msg_to_channel(name, channel, text); +} +#if !defined(__WIN32__) && !defined(__LINUX__) +#pragma warn .par +#endif +/*---------------------------------------------------------------------------*/ + +static WORD is_looped(PERMLINK *l, char *host) +{ + DESTINATION *d; + + /* Schleifenerkennung 1: + Nachbar will uns was ueber uns erzaehlen */ + if (!Strcmp(myhostname, host)) + return(1); + + /* Schleifenerkennung 2: + host schon aus anderer Richtung bekannt */ + if (l) { + for (d = destinations; d; d = d->next) + if (!Strcmp(d->name, host)) + break; + if (d && d->link != l && d->rtt) + return(1); + } + + return(0); +} + +/*---------------------------------------------------------------------------*/ + +static void h_dest_command(CONNECTION *cp) +{ + char *name, *rev; + LONG rtt; + PERMLINK *l; + + name = getarg(NULL, GET_NXTCS); + if (!*name) + return; + + rtt = atol(getarg(NULL, GET_NXTLC)); + rev = getarg(NULL, GET_NXTLC); + + l = permlink_of(cp); + + if (is_looped(l, name)) { + if (l) + l->locked = 1; /* verriegeln */ + bye_command2(cp, "loop detect"); /* und abwerfen */ + return; + } + + if (l && rtt >= 0L) + update_destinations(l, name, rtt, rev); +} + +/*---------------------------------------------------------------------------*/ + +static void h_host_command(CONNECTION *cp) +{ + char *name; + char *rev; +#ifdef CONVNICK + char *features; +#endif + char buffer[1024]; + WORD pl; + char *flags; + CONNECTION *c; + PERMLINK *p; + DESTINATION *d; + CHANNEL *ch; + CLIST *cl; + + if (*cp->name == NUL) + return; + + name = getarg(NULL, GET_NXTCS); + if (!*name) + return; + + rev = getarg(NULL, GET_NXTLC); + if (!*rev) + rev = "?"; + +#ifdef CONVNICK + features = getarg(NULL, GET_NXTCS); + + cp->features = 0; + if (strchr(features, 'n') != NULL) + cp->features |= FEATURE_NICK; +#endif + + for (pl = 0; pl < MAXCVSHOST; pl++) { + p = permarray[pl]; + if (p && !Strcmp(p->cname, cp->name)) { + if (p->connection && (p->connection != cp)) + bye_command2(p->connection, "link reorg"); + } + } + for (c = connections; c; c = c->next) /* sicher ist sicher */ + if (!Strcmp(c->name, cp->name) && c != cp && !c->via) + bye_command2(c, "link reorg"); + + cp->type = CT_HOST; + strcpy(cp->host, "-"); + Strcpy(cp->rev, rev); + p = update_permlinks(cp->name, cp, 0); +#ifdef CONVERS_HOSTNAME + Strcpy(p->cname, name); +#else + Strcpy(p->name, name); +#endif + if (cp->up->convflag == 1) { /* nur senden, wenn connect von aussen */ + sprintf(buffer, "/\377\200HOST %s %s %s\r", myhostname, myrev, myfeatures); + appenddirect(cp, buffer); + send_proto("cmds", "TX to %s %s", cp->name, buffer+3); + } + send_proto("cmds", "sending user, modes... to %s", cp->name); + /* DEST's zuerst aussenden (fuer loop-detect) */ + for (d = destinations; d; d = d->next) { + if (d->rtt) { + sprintf(buffer, "/\377\200DEST %s %ld %s\r", d->name, (long)d->rtt + 99L, d->rev); + appenddirect(cp, buffer); + } + } + /* Aussenden eines DEST zum Bekanntmachen (fuer loop-detect) */ + update_destinations(p, name, 1, rev); + for (c = connections; c; c = c->next) { + if (c->type == CT_USER) { + if (!c->via) { + for (cl = c->chan_list; cl; cl = cl->next) { + sprintf(buffer, "/\377\200USER %s %s %ld -1 %d %s\r", c->name, c->host, (long)cl->time, cl->channel, c->pers?c->pers:""); + appenddirect(cp, buffer); + if (cl->channelop) { + sprintf(buffer, "/\377\200OPER conversd %d %s\r", cl->channel, c->name); + appenddirect(cp, buffer); + } + } + +#ifdef CONVNICK + /* Nickname des Users senden wenn er einen hat */ + if ((cp->features & FEATURE_NICK) && (c->nickname[0] != '\0')) { + sprintf(buffer, "/\377\200UADD %s %s %s %d %s\r", c->name, c->host, c->nickname, -1, c->pers ? c->pers : "~~"); + appenddirect(cp, buffer); + } +#endif + if (c->away) { + sprintf(buffer, "/\377\200AWAY %s %s %ld %s\r", c->name, c->host, (long)c->atime, c->away); + appenddirect(cp, buffer); + } + if (c->operator) { + sprintf(buffer, "/\377\200OPER conversd -1 %s\r", c->name); + appenddirect(cp, buffer); + } + } else { + sprintf(buffer, "/\377\200USER %s %s %ld -1 %d %s\r", c->name, c->host, (long)c->time, c->channel, c->pers?c->pers:""); + appenddirect(cp, buffer); + if (c->away) { + sprintf(buffer, "/\377\200AWAY %s %s %ld %s\r", c->name, c->host, (long)c->atime, c->away); + appenddirect(cp, buffer); + } + if (c->channelop) { + sprintf(buffer, "/\377\200OPER conversd %d %s\r", c->channel, c->name); + appenddirect(cp, buffer); + } + if (c->operator) { + sprintf(buffer, "/\377\200OPER conversd -1 %s\r", c->name); + appenddirect(cp, buffer); + } + } + } + } + for (ch = channels; ch; ch = ch->next) { + if (ch->topic) + { +#ifdef CONV_TOPIC + sprintf(buffer, "/\377\200TOPI %s %s %ld %d %s\n" + /* Wenn kein Call gesetzt, conversd setzen. */ + , (*ch->name ? ch->name : "conversd") + /* User Hostname. */ + , myhostname + /* Zeit. */ + , (long)ch->time + /* Kanal. */ + , ch->chan + /* Topic. */ + , ch->topic); +#else + sprintf(buffer, "/\377\200TOPI conversd %s %ld %d %s\r", myhostname, (long)ch->time, ch->chan, ch->topic); +#endif /* CONV_TOPIC */ + appenddirect(cp, buffer); + } + /* Dies wuerde zu 2 unterschiedlichen Modes zwischen den Teilnetzen + der sich verbindenden Hosts fuehren + sprintf(buffer, "/\377\200MODE %d -sptiml+%s\r", ch->chan, flags); + folglich senden wir nur die gesetzten Flags, wenn welche gesetzt sind + */ + flags = strlwr(getflags(ch->flags)); + if (*flags) { + sprintf(buffer, "/\377\200MODE %d +%s\r", ch->chan, flags); + appenddirect(cp, buffer); + } + } +} + +/*---------------------------------------------------------------------------*/ + +#if !defined(__WIN32__) && !defined(__LINUX__) +#pragma warn -par +#endif +static void h_invi_command(CONNECTION *cp) +{ + + char *fromname, *toname; + WORD channel; + + fromname = getarg(NULL, GET_NXTLC); + toname = getarg(NULL, GET_NXTLC); + channel = atoi(getarg(NULL, GET_NXTLC)); + send_invite_msg(fromname, toname, channel); +} + +#if !defined(__WIN32__) && !defined(__LINUX__) +#pragma warn .par +#endif +/*---------------------------------------------------------------------------*/ + +static void h_link_command(CONNECTION *cp) +{ + char buffer[256]; + char *user, *host; + + user = getarg(NULL, GET_NXTLC); + host = getarg(NULL, GET_NXTCS); + if (!Strcmp (myhostname, host)) { + if (!*user) + return; + + clear_locks(); +#ifdef SPEECH + sprintf(buffer, speech_message(111), myhostname); +#else + sprintf(buffer, "*** Links at %s", myhostname); +#endif + send_msg_to_user("conversd", user, buffer); + disp_links(NULLCONNECTION, user); + } else { /* dies macht tpp nicht */ + sprintf(buffer, "/\377\200LINK %s %s", user, host); + strcpy(cnvinbuf, buffer); + h_unknown_command(cp); + } +} + +/*---------------------------------------------------------------------------*/ + +static void h_oper_command(CONNECTION *cp) +{ + char *toname, *fromname; + WORD channel; + CONNECTION *p; + CLIST *cl; + + fromname = getarg(NULL, GET_NXTLC); + channel = atoi(getarg(NULL, GET_NXTLC)); + toname = getarg(NULL, GET_NXTLC); + cp->locked = 1; + + for (p = connections; p; p = p->next) { + if (Strcmp(p->name, toname)) + continue; + + if (channel == -1) { + if (p->type == CT_USER) { + p->operator = 1; +#ifndef L1IRC + send_opermsg(toname, p->host, fromname, channel); +#else + send_opermsg(toname, p->host, fromname, channel, 0); +#endif /* L1IRC */ + } + } else { + if (p->channel == channel) { + p->channelop = 1; + } + for (cl = p->chan_list; cl; cl = cl->next) { + if (cl->channel == channel) cl->channelop = 1; + } +#ifndef L1IRC + send_opermsg(toname, p->host, cp->name, channel); +#else + send_opermsg(toname, p->host, cp->name, channel, 0); +#endif /* L1IRC */ + } + } +} + +/*---------------------------------------------------------------------------*/ + +static void h_ping_command(CONNECTION *cp) +{ + PERMLINK *l; + char buffer[128]; + + l = permlink_of(cp); + if (l) { + sprintf(buffer, "/\377\200PONG %ld\r", (long)l->txtime); + appenddirect(cp, buffer); + send_proto("cmds", "TX to %s %s", cp->name, buffer+3); + } +} + +/*---------------------------------------------------------------------------*/ + +static void h_pong_command(CONNECTION *cp) +{ + PERMLINK *l; + + l = permlink_of(cp); + if (l) { + l->rxtime = atol(getarg(NULL, GET_NXTLC)); + l->txtime = max(currtime - l->testwaittime, 1L); + if (l->rxtime == 0L) l->rxtime = l->txtime; + if ((labs(l->rxtime) > 20001L) || (labs(l->txtime) > 20001L)) { + l->rxtime = 0; + l->txtime = 0; + } + l->testnexttime = l->testwaittime + max(min(60L * (l->txtime), 7200L), 120L); + /* I hacked this because of it's nasty behave - rewrite of the whole stuff is in progress */ + update_destinations(l, l->name, + (l->rxtime == -1L) ? l->txtime : (l->rxtime + l->txtime) / 2L, + cp->rev); + } +} + +/*---------------------------------------------------------------------------*/ + +#if !defined(__WIN32__) && !defined(__LINUX__) +#pragma warn -par +#endif +static void h_rout_command(CONNECTION *cp) +{ + char *dest, *user; + DESTINATION *d; + char buffer[128]; + WORD ttl; + + dest = getarg(NULL, GET_NXTCS); + user = getarg(NULL, GET_NXTLC); + ttl = atoi(getarg(NULL, GET_NXTLC)); + clear_locks(); + for (d = destinations; d; d = d->next) { + if (d->rtt && d->link && !Strcmp(d->name, dest)) { + sprintf(buffer, "*** route: %s (%ld) %s -> %s", myhostname, + (long)((d->link->rxtime + d->link->txtime) / 2L), + d->link->cname, dest); + send_msg_to_user("conversd", user, buffer); + if (ttl && Strcmp(d->link->name, dest)) { + ttl--; + sprintf(buffer, "/\377\200ROUT %s %s %d\r", dest, user, ttl); + appenddirect(d->link->connection, buffer); + send_proto("cmds", "TX to %s %s", d->link->connection->name, buffer+3); + } + } + } +} +#if !defined(__WIN32__) && !defined(__LINUX__) +#pragma warn .par +#endif +/*---------------------------------------------------------------------------*/ + +static void h_topi_command(CONNECTION *cp) +{ + char *fromname, *hostname, *text; + WORD channel; + time_t time; + + fromname = getarg(NULL, GET_NXTLC); + hostname = getarg(NULL, GET_NXTCS); + time = atol(getarg(NULL, GET_NXTLC)); + channel = atoi(getarg(NULL, GET_NXTLC)); + text = getarg(NULL, GET_ALL); + cp->locked = 1; +#ifndef CONVNICK + send_topic(fromname, hostname, time, channel, text); +#else + send_topic(fromname, fromname, hostname, time, channel, text); +#endif /* CONVNICK */ +} + +/*---------------------------------------------------------------------------*/ + +#ifdef CONVNICK +static void h_uadd_command(CONNECTION *cp) +{ + char *name, *host, *data, *nickname, *channel; + CONNECTION *p; + + name = getarg(NULL, GET_NXTLC); + host = getarg(NULL, GET_NXTLC); + nickname = getarg(NULL, GET_NXTCS); + channel = getarg(NULL, GET_NXTLC); + data = getarg(NULL, GET_ALL); + + if (*data == '~' && data[1] == '~') + *data = 0; + + for (p = connections; p ; p = p->next) + { + if ( (!strncasecmp(p->name, name, NAMESIZE)) + &&(!strncasecmp(p->host, host, NAMESIZE))) + { + if (!strncasecmp(p->OldNickname /* Ist alter und neuer Nickname gleich. */ + , nickname + , NAMESIZE)) + break; /* Keine Aenderung durchfuehren. */ + + /* Alten Nickname sichern. */ + strncpy(p->OldNickname, p->nickname, NAMESIZE); + strncpy(p->nickname, nickname, NAMESIZE); + setstring(&(p->pers), data, 256); +#ifdef L1IRC + SendIrcNick(p); +#endif /* L1IRC */ + break; + } + } +} +#endif + +/*---------------------------------------------------------------------------*/ + +static void h_udat_command(CONNECTION *cp) +{ + char *fromname, *hostname, *text; + CONNECTION *p; + + fromname = getarg(NULL, GET_NXTLC); + hostname = getarg(NULL, GET_NXTCS); + text = getarg(NULL, GET_ALL); + if (!strcmp(text, "@")) /* wir verwenden keinen @ mehr */ + text = ""; + cp->locked = 1; + for (p = connections; p; p = p->next) { + if (p->type == CT_USER && !Strcmp(p->name, fromname) && + !Strcmp(p->host, hostname) && strcmp(p->pers?p->pers:"", text)) { + setstring(&(p->pers), text, 256); +#ifndef CONVNICK + send_persmsg(fromname, hostname, p->channel, text, currtime); +#else + send_persmsg(fromname, (*p->nickname ? p->nickname : fromname), hostname, p->channel, text, currtime); +#endif /* CONVNICK */ + } + } +} + +/*---------------------------------------------------------------------------*/ + +#if !defined(__WIN32__) && !defined(__LINUX__) +#pragma warn -par +#endif +static void h_umsg_command(CONNECTION *cp) +{ + char *fromname, *toname, *text; + + fromname = getarg(NULL, GET_NXTLC); + if (strlen(fromname) > 64) /* 1. Schutz vor Nicknames */ + fromname[64] = NUL; + toname = getarg(NULL, GET_NXTLC); + text = getarg(NULL, GET_ALL); + if (*text) send_msg_to_user(fromname, toname, text); +} +#if !defined(__WIN32__) && !defined(__LINUX__) +#pragma warn .par +#endif + +/*---------------------------------------------------------------------------*/ + +/* this command simply passes on any host requests that we don't understand, + since our neighbors MIGHT understand them (von tpp uebernommen) */ + +static void h_unknown_command(CONNECTION *cp) +{ + CONNECTION *p; + + for (p = connections; p; p = p->next) + if (p->type == CT_HOST && p != cp) { + appenddirect(p, cnvinbuf); + appenddirect(p, "\r"); + send_proto("cmds", "TX to %s %s", p->name, cnvinbuf+3); + } +} + +/*---------------------------------------------------------------------------*/ +#ifdef CONVERS_NO_NAME_OK +#else +static BOOLEAN name_ok(char *call) +{ + char tmp[L2IDLEN], buffer[12], *bp; + WORD n, bcnt; + + n = (WORD) strlen(call); + if (n < 4 || n > 9) + return(FALSE); + + strcpy(buffer, call); + if ((bp = strchr(buffer, '-')) != NULL) /* auch Buchstaben-SSID kuerzen(-u) */ + *bp = '\0'; + bp = buffer; + bcnt = (WORD) strlen(bp); + return(getcal(&bcnt, &bp, TRUE, tmp) == YES); +} +#endif + +static BOOLEAN host_ok(char *call) +{ + char *c; + + if ((WORD)strlen(call) < 4) + return(FALSE); + + c = call; + while (*c) { /* nur 0...9 A...Z a...z . - */ + if (!(isalnum(*c) || *c == '.' || *c == '-')) + return(FALSE); + + c++; + } + + c = call; + while (*c) /* mindestens ein Buchstabe */ + if (isalpha(*c++)) + return(TRUE); + + return(FALSE); +} + +/*---------------------------------------------------------------------------*/ + +static void h_user_command(CONNECTION *cp) +{ + char *host; + char *name; + char *pers; + WORD newchannel; + WORD oldchannel; + CONNECTION *p; + CHANNEL *ch; + PERMLINK *l; + WORD users_left; + time_t time; +#ifdef CONVNICK + char nick[NAMESIZE + 1]; +#endif + + name = getarg(NULL, GET_NXTLC); + host = getarg(NULL, GET_NXTCS); + +#ifdef CONVERS_NO_NAME_OK + if (host_ok(host) != TRUE) +#else + if ( name_ok(name) != TRUE + || host_ok(host) != TRUE) +#endif + return; + + if ( (l = permlink_of(cp)) != NULL /* Looperkennung */ + && is_looped(l, host)) { + l->locked = 1; /* verriegeln */ + bye_command2(cp, "loop detect"); /* und abwerfen */ + return; + } + + time = atol(getarg(NULL, GET_NXTLC)); + if (time == 0) time = currtime; + oldchannel = atoi(getarg(NULL, GET_NXTLC)); + newchannel = atoi(getarg(NULL, GET_NXTLC)); + if ( oldchannel < -1 + || newchannel < -1 + || (oldchannel == -1 && newchannel == -1)) /* einige WAMPEn tun dies */ + return; + + pers = getarg(NULL, GET_ALL); + +#ifdef CONVNICK + memset(nick, 0, sizeof(nick)); +#endif /* CONVNICK */ + + for (p = connections; p; p = p->next) + { + if (p->type == CT_USER) + { + if ((p->via == cp) && + !Strcmp(p->name, name) && + !Strcmp(p->host, host)) + { + strncpy(nick, p->nickname, NAMESIZE); + nick[NAMESIZE] = 0; + + if (p->channel == oldchannel) + break; + } + } + } + if (!p) { + p = (CONNECTION *) calloc(1, sizeof(CONNECTION)); + if (p) { + p->type = CT_USER; + Strcpy(p->name, name); +#ifdef CONVNICK + if (nick[0] == FALSE) + { + memset(p->nickname, 0, NAMESIZE); + memset(p->OldNickname, 0, NAMESIZE); + } +#endif + Strcpy(p->host, host); + p->via = cp; + p->next = connections; + connections = p; + } + } + if (p) { + p->time = time; + p->mtime = currtime; + if (*pers && strcmp(pers, "@")) + setstring(&(p->pers), pers, 256); + if ((p->channel = newchannel) < 0) { + p->type = CT_CLOSED; + } + } + +#ifdef CONVNICK + if (*p->nickname) + { + strncpy(nick, p->nickname, NAMESIZE); + nick[NAMESIZE] = 0; + } + else + { + /* ggf Nickname aus Profil laden. */ + if (GetNickname(p)) + { + /* Nickname sichern. */ + strncpy(nick, p->nickname, NAMESIZE); + nick[NAMESIZE] = 0; + } + } +#endif /* CONVNICK */ + + users_left = count_user(oldchannel); + if (!users_left) destroy_channel(oldchannel); + for (ch = channels; ch; ch = ch->next) { + if (ch->chan == newchannel) break; + } + if (p && !ch && (newchannel != -1)) { + ch = ins_channel(newchannel); + } +#ifndef CONVNICK + send_user_change_msg(name, host, oldchannel, newchannel, pers, time); +#else + send_user_change_msg(name, nick, host, oldchannel, newchannel, pers, time); +#endif /* CONVNICK */ +} + +/*---------------------------------------------------------------------------*/ + +#else +#ifndef __LINUX__ +#pragma warn -par +#endif +void bye_command2(CONNECTION *cp, char *reason) +{ +} + +#ifndef __LINUX__ +#pragma warn .par +#endif +#endif + + +#ifdef CONVERS_SYSINFO +/* Sich als Sysop anmelden */ +static void sysinfo_command(CONNECTION *cp) +{ + char buffer[255]; + + sprintf(buffer, "*** conversd PingPong-Release %5.5s (TNN)\r" + , strchr(REV, ':')+2); + appenddirect(cp, buffer); + read_xhelp("SYSI", cp); +#ifdef CONNECTTIME +#ifdef SPEECH + sprintf(buffer, speech_message(342), ConnectTime(tic10 / 100)); +#else + sprintf(buffer, "Convers rennt seit: %s\r", ConnectTime(tic10 / 100)); +#endif /* SPEECH */ +#endif /* CONNECTTIME */ + appenddirect(cp, buffer); +} +#endif + +#ifdef CONVERS_HOSTNAME +static void hostname_command(CONNECTION *cp) +{ + char buffer[255]; + char *arg; + static char HostName[10 + 1]; + + arg = getarg(NULL, GET_ALL); + + /* Hostname aendern darf nur der Sysop! */ + if (cp->operator != 2) + { + /* User bekommt eine Meckermeldung. */ +#ifdef SPEECH + appenddirect(cp, speech_message(68)); +#else + appenddirect(cp, "*** You must be an operator!\r"); +#endif + } + + if (arg[0] == FALSE) + { +#ifdef SPEECH + sprintf(buffer, speech_message(344),myhostname); +#else + sprintf(buffer,"*** Hostname is %s.\r",myhostname); +#endif + appenddirect(cp, buffer); + return; + } + else + { + if (strlen(arg) > 9) + { +#ifdef SPEECH + sprintf(buffer, speech_message(3)); +#else + sprintf(buffer,"*** is too long. the Convers hostname (max.9 indications)!\r"); +#endif + appenddirect(cp, buffer); + return; + } + strncpy(HostName, arg, 10); + myhostname = HostName; +#ifdef SPEECH + sprintf(buffer, speech_message(4), myhostname); +#else + sprintf(buffer,"*** Convers hostname successfully changed in %s.\r",myhostname); +#endif + appenddirect(cp, buffer); + return; + } +} + +#endif + +/* End of $RCSfile$ */ diff --git a/src/cvs_cvrt.c b/src/cvs_cvrt.c new file mode 100755 index 0000000..3acd5a0 --- /dev/null +++ b/src/cvs_cvrt.c @@ -0,0 +1,426 @@ +/************************************************************************/ +/* */ +/* ***** ***** */ +/* ***** ***** */ +/* ***** ***** */ +/* ***** ***** */ +/* *************** *************** */ +/* ***************** ***************** */ +/* *************** *************** */ +/* ***** ***** TheNetNode */ +/* ***** ***** Portable */ +/* ***** ***** Network */ +/* ***** ***** Software */ +/* */ +/* File src/cvs_cvrt.c (maintained by: DL1XAO) */ +/* */ +/* This file is part of "TheNetNode" - Software Package */ +/* */ +/* Copyright (C) 1998 - 2008 NORD>name; p_charset++) + if (!strncmp(p_charset->name, buf, len)) + return(p_charset->ind); + + return(-1); +} + +/*---------------------------------------------------------------------------*/ + +char *get_charset_by_ind(WORD ind) +{ + struct charsets *p_charset; + + for (p_charset = charsets; p_charset->name; p_charset++) + if (p_charset->ind == ind) + return(p_charset->name); + + return((char *) NULL); +} + +/*---------------------------------------------------------------------------*/ + +char *list_charsets(void) +{ + char buf[256]; + char tmp[64]; + WORD i; + struct charsets *p_charset; + + static char *p = (char *) NULL; + + if (p) return(p); + + *buf = '\0'; + for (i = 0; i < CHARSETS; i++) { + *tmp = '\0'; + for (p_charset = charsets; p_charset->name; p_charset++) { + if (i != p_charset->ind) continue; + if (*tmp) strcat(tmp, ", "); + strcat(tmp, p_charset->name); + } + strcat(tmp, " : "); + strcat(tmp, cnvrtinf[i].samples); + strcat(tmp, "\r"); + strcat(buf, tmp); + } + + /* No good solution - but BIN is not part of CHARSERTS */ + *tmp = '\0'; + for (p_charset = charsets; p_charset->name; p_charset++) { + if (p_charset->ind != BIN) continue; + if (*tmp) strcat(tmp, ", "); + strcat(tmp, p_charset->name); + } + strcat(tmp, "\r"); + strcat(buf, tmp); + + return(p = strdup(buf)); +} + +/*---------------------------------------------------------------------------*/ + +char *convertin(WORD in, char *string) +{ + CONVERT *cnvrt; + + if (in <= CHARSETS-1) { + cnvrt = &cnvrtinf[in]; + if (cnvrt->ifunc != NULL) { + stibm2[63] = (in == ATARI) ? 0x9E : 0xE1; + cnvrt->ifunc(cnvrt->par, string); + return(outbuf); + } + } + return(string); +} + +char *convertout(WORD out, char *string) +{ + CONVERT *cnvrt; + + if (out <= CHARSETS-1) { + cnvrt = &cnvrtinf[out]; + if (cnvrt->ofunc != NULL) { + stibm2[63] = (out == ATARI) ? 0x9E : 0xE1; + cnvrt->ofunc(cnvrt->par, string); + return(outbuf); + } + } + return(string); +} + +/*---------------------------------------------------------------------------*/ + +static void cvitexfn(char *d, char *string) +{ + char *s; + int c; + + for (s = string, d = outbuf; *s; s++ ) { + c = *s; + if (c == '\\' && *(s+1) == '\"') { + s++; + *d++ = *s++; + } + else { + if (c == '\"') { + s++; + c = *s; + switch (c) { + case 'A': c = 160+36; break; + case 'O': c = 160+54; break; + case 'U': c = 160+60; break; + case 'a': c = 160+68; break; + case 'o': c = 160+86; break; + case 's': c = 160+63; break; + case 'u': c = 160+92; break; + default: *d++ = '\"'; + } + } + *d++ = c; + } + } + *d = '\0'; +} + +static void cvitabfn(char *tab, char *string) +{ + char *s, *d, *tp; + int c, i; + + for (s = string, d = outbuf; *s; s++ ) { + c = *s; + for (i = 160, tp = tab; i < 256; i++, tp++) { + if (*tp == c) { + c = i; + break; + } + } + *d++ = c; + } + *d = '\0'; +} + +/*---------------------------------------------------------------------------*/ + +static int iso2asc(int c) /* wegkucken! */ +{ + if (c == 160+36) return('A'); + if (c == 160+54) return('O'); + if (c == 160+60) return('U'); + if (c == 160+63) return('s'); + if (c == 160+68) return('a'); + if (c == 160+86) return('o'); + if (c == 160+92) return('u'); + return(c); +} + +static void cvodmbfn(char *d, char *string) +{ + char *s, *ep; + int c; + + for (s = string, d = outbuf, ep = &outbuf[MAXBUF-2]; + *s && (d < ep); + s++ ) { + + c = *s; + if (c >= 160) { + c = iso2asc(c); + if (c < 160) { + *d = c; + + if (c != 's') + c = 'e'; + + if ( isupperalpha(s[1]) + || ( ( d == outbuf + || ( d > outbuf + && isupperalpha(*d) + && isupperalpha(*(d-1)))) + && !isalnum(s[1]))) + c = toupper(c); + + if (c == 'S') + *d = c; + + d++; + } + } + *d++ = c; + } + *d = '\0'; +} + +static void cvotexfn(char *d, char *string) +{ + char *s, *ep; + int c; + + for (s = string, d = outbuf, ep = &outbuf[MAXBUF-2]; + *s && (d < ep); + s++ ) { + + c = *s; + if (c >= 160) { + c = iso2asc(c); + if (c < 160) + *d++ = '\"'; + } + *d++ = c; + } + *d = '\0'; +} + +static void cvotabfn(char *tab, char *string) +{ + register char *s, *d; + int c, x; + + for (s = string, d = outbuf; *s; s++ ) { + c = *s; + if (c >= 160) + if ((x = tab[c - 160]) != 0) + c = x; + *d++ = c; + } + *d = '\0'; +} + +/*---------------------------------------------------------------------------*/ +/* End of $RCSfile$ */ +#endif diff --git a/src/cvs_cvsd.c b/src/cvs_cvsd.c new file mode 100755 index 0000000..3c983fe --- /dev/null +++ b/src/cvs_cvsd.c @@ -0,0 +1,2161 @@ +/************************************************************************/ +/* */ +/* ***** ***** */ +/* ***** ***** */ +/* ***** ***** */ +/* ***** ***** */ +/* *************** *************** */ +/* ***************** ***************** */ +/* *************** *************** */ +/* ***** ***** TheNetNode */ +/* ***** ***** Portable */ +/* ***** ***** Network */ +/* ***** ***** Software */ +/* */ +/* File src/cvs_cvsd.c (maintained by: DL1XAO) */ +/* */ +/* This file is part of "TheNetNode" - Software Package */ +/* */ +/* Copyright (C) 1998 - 2008 NORD> + * + * Modifications by Fred Baumgarten + * $Revision: 3.12 $$Date: 1996/03/03 10:09:47 $ + * + * Modifications by Oliver Kern + * $Revision: 3.13 $$Date: 17.08.2004 22:22 $ + */ +/* modified for use with TheNetNode by DL1XAO */ +/* hierdrin befinden sich alle Senderoutinen und sonstiges, + welches sich nicht mit Datenstrukturen von TNN befasst */ +#include "tnn.h" + +#ifdef PPCONVERS + +#include "conversd.h" + +static char *persfile; +static WORD isonchannel __ARGS((CONNECTION *cp, char *user, char *host)); + +/*---------------------------------------------------------------------------*/ + +void appenddirect(CONNECTION *cp, const char *string) +{ + if (cp->up) + putcvsstr(cp, (char *)string); +} + +void appendformline(CONNECTION *cp, char *prefix, char *text) +{ + char buf[258], *d, *s1, *s2; + WORD prefixlen, l, linelen; + + if (cp->up) { + text = convertout(cp->charset_out, (char *)text); + linelen = cp->width - 1; + l = prefixlen = (WORD)strlen(prefix); + strcpy(buf, prefix); + d = buf + prefixlen; + *d++ = ' '; + + while (*text) { + + while (isspace(uchar(*text))) + text++; + + if (*text) { + while (*text && !isspace(uchar(*text)) && l < linelen) { + *d++ = *text++; + l++; + } + while (isspace(uchar(*text)) && l < linelen) { + s1 = text; + while (isspace(uchar(*s1))) + s1++; + s2 = s1; + while (*s2 && !isspace(uchar(*s2))) + s2++; + if (l + (WORD)(s2 - text) < linelen) { + while (text < s2) { + *d++ = *text++; + l++; + } + } + else if ((WORD)(s2 - s1) > (linelen - prefixlen)) { + while (l < linelen) { + *d++ = *text++; + l++; + } + } + else + text = s1; + } + if (*(d-1) != '\r') + *d++ = '\r'; + *d = '\0'; + putcvsstr(cp, buf); + for (l = 0, d = buf; l < prefixlen; l++) + *d++ = ' '; + } + } + } +} + +void appendstring(CONNECTION *cp, const char *string) +{ + char *p_string; + + if (cp->up && *string) { + + if (cp->type == CT_USER) + p_string = convertout(cp->charset_out, (char *)string); + else + p_string = (char *)string; + + putcvsstr(cp, (char *)p_string); + } +} + +/*---------------------------------------------------------------------------*/ + +/* zusammengefasste Variante von appendprompt/appendc */ + +void appendprompt(CONNECTION *cp, const WORD ast) +{ + char x[3], *p; + +#ifdef L1IRC + if (cp->IrcMode) + return; +#endif /* L1IRC */ + + if (ast == 2) { + p = x; + if (cp->prompt[0]) + *p++ = cp->prompt[0]; + if (cp->prompt[3]) + *p++ = cp->prompt[3]; + *p = '\0'; + if (p != x) + appenddirect(cp, x); + } + else if ((*x = cp->prompt[(*cp->query) ? 1 : 2]) != 0) { + x[1] = '\0'; + appenddirect(cp, x); + } + else if (ast) + appenddirect(cp, "***\r"); +} + +/*---------------------------------------------------------------------------*/ + +void destroy_channel(WORD number) +{ + CHANNEL *ch, *ch1; + + ch1 = NULLCHANNEL; + for (ch = channels; ch; ch = ch->next) { + if (ch->chan == number) { + if (ch1) { + ch1->next = ch->next; + } else { + channels = ch->next; + } + if (ch->topic) + free(ch->topic); + +#ifdef CONV_TOPIC + /* Call loeschen. */ + ch->name[0] = 0; +#endif + free(ch); + break; + } + ch1 = ch; + } +} + +/*---------------------------------------------------------------------------*/ + +PERMLINK *permlink_of(CONNECTION *cp) +{ + WORD pl; + PERMLINK *l; + + for (pl = 0; pl < MAXCVSHOST; pl++) { + l = permarray[pl]; + if (l && l->connection == cp) + return(l); + } + return(NULL); +} + +/*---------------------------------------------------------------------------*/ + +void free_closed_connections() +{ + CONNECTION *cp, *p; + PERMLINK *l; + WORD to; + + for (p = NULLCONNECTION, cp = connections; cp; ) { + l = cp->via ? NULL : permlink_of(cp); + to = 0; + if (l && cp->type == CT_UNKNOWN && cp->time + l->waittime - 5 < currtime) { + send_proto("cvsd", "timeout for %s", cp->name); + to = 1; + } + + if ( cp->type == CT_CLOSED + || to + ||(!l && cp->type == CT_UNKNOWN)) + { + if (p) + { + p->next = cp->next; + free_connection(cp); + cp = p->next; + } + else + { + connections = cp->next; + free_connection(cp); + cp = connections; + } + } + else + { + p = cp; + cp = cp->next; + } + } +} + +/*---------------------------------------------------------------------------*/ + +char *getarg(char *line, WORD mode) +{ + char *arg; + WORD c; + static char *p; + +#ifdef CONVNICK + int mke = FALSE; +#endif + + if (line) p = line; + while (isspace(uchar(*p))) p++; + if (mode == GET_ALL) return(p); + arg = p; + if (mode == GET_NXTCS) + while (*p && !isspace(uchar(*p))) + p++; + else + while (*p && !isspace(uchar(*p))) + { +#ifdef CONVNICK + if (mke == TRUE || (*p == ':')) + { + c = (uchar(*p)); + mke = TRUE; + } + else +#endif + c = tolower(uchar(*p)); +#ifdef __WIN32__ + *p++ = (char)c; +#else + *p++ = c; +#endif /* WIN32 */ + } + + if (*p) + *p++ = '\0'; + + return(arg); +} + +/*---------------------------------------------------------------------------*/ + +char *ts(time_t gmt) +{ + static char buffer[80]; + static char monthnames[] = "JanFebMarAprMayJunJulAugSepOctNovDec"; + struct tm *tm; + + tm = localtime(&gmt); + if (gmt + 24L * 60L * 60L > currtime) + sprintf(buffer, " %2d:%02d", tm->tm_hour, tm->tm_min); + else + sprintf(buffer, "%-3.3s %2d", monthnames + 3 * tm->tm_mon, tm->tm_mday); + return(buffer); +} + +/*---------------------------------------------------------------------------*/ + +void ts2(void) +{ + struct tm *tm; + + tm = localtime(&currtime); + sprintf(timestamp, "*** (%2d:%02d) ", tm->tm_hour, tm->tm_min); +} + +/*---------------------------------------------------------------------------*/ + +char *ts3(time_t seconds, char *buffer) +{ + if (seconds < 100L) { + sprintf(buffer, "%ds", (WORD)seconds); + } else if (seconds <6000L) { + sprintf(buffer, "%dm", (WORD)(seconds/60L)); + } else if (seconds <360000L) { + sprintf(buffer, "%dh", (WORD)(seconds/3600L)); + } else { + sprintf(buffer, "%dd", (WORD)(seconds/86400L)); + } + return(buffer); +} + +/*---------------------------------------------------------------------------*/ + +char *ts4(time_t seconds) +{ + time_t days, hours, minutes; + static char buffer[64]; + char *bp; + + days = seconds / 86400L; + seconds -= days * 86400L; + hours = seconds / 3600L; + seconds -= hours * 3600L; + minutes = seconds / 60L; + seconds -= minutes * 60L; + + bp = buffer; + if (days) + bp += sprintf(bp, "%d days, ", (WORD)days); + if (days+hours) + bp += sprintf(bp, "%d hours, ", (WORD)hours); + if (days+hours+minutes) + bp += sprintf(bp, "%d minutes, ", (WORD)minutes); + sprintf(bp, "%d seconds.", (WORD)seconds); + + return(buffer); +} + +/*---------------------------------------------------------------------------*/ + +WORD count_user(WORD channel) +{ + CONNECTION *p; + CLIST *cl; + WORD n = 0; + + for (p = connections; p; p = p->next) { + if (p->type == CT_USER) { + if (p->via && (p->channel == channel)) { + n++; + } else { + for (cl = p->chan_list; cl; cl = cl->next) { + if (cl->channel == channel) { + n++; + break; + } + } + } + } + } + return(n); +} + +/*---------------------------------------------------------------------------*/ + +void clear_locks() +{ + CONNECTION *p; + + for (p = connections; p; p = p->next) p->locked = 0; +} + +/*---------------------------------------------------------------------------*/ + +static WORD isonchannel(CONNECTION *cp, char *user, char *host) +{ + CONNECTION *p; + CLIST *cl, *cl1; + + for (p = connections; p; p = p->next) + if (p->type == CT_USER && p != cp) + if (!Strcmp(p->name, user) && !Strcmp(p->host, host)) + for (cl = cp->chan_list; cl; cl = cl->next) { + if (p->channel == cl->channel) + return(1); + for (cl1 = p->chan_list; cl1; cl1 = cl1->next) + if (cl1->channel == cl->channel) + return(1); + } + return(0); +} + +/*---------------------------------------------------------------------------*/ + +#ifndef CONVNICK +void send_awaymsg(char *fromname,.char *hostname, +#else +void send_awaymsg(char *fromname, char *fromnickname, char *hostname, +#endif /* CONVNICK */ + time_t time, char *text) +{ + char buffer[2048]; + char namefilt[68], *c; + register CONNECTION *p; + + sprintf(namefilt, " %s ", fromname); + if ((c = strchr(namefilt, ':')) != NULL) { + *c++ = ' '; + *c = NUL; + } + for (p = connections; p; p = p->next) { +#ifdef L1IRC + if (p->IrcMode) + { + if (!p->locked && (p->type == CT_HOST || (p->type == CT_USER && !p->via && p->verbose && isonchannel(p, fromname, hostname)))) + { + sprintf(buffer, ":%s!%s@%s MODE %s %ca%s%s\n", fromname, fromname, hostname, fromname, *text ? '+' : '-', (*text ? " :" : ""), (*text ? text : "")); + appendstring(p, buffer); + p->locked = 1; + continue; + } + } +#endif /* L1IRC */ + if (p->type == CT_HOST) { + if (!p->locked) { + sprintf(buffer, "/\377\200AWAY %s %s %ld %s\r", fromname, hostname, (long)time, text); + appenddirect(p, buffer); + p->locked = 1; + send_proto("cvsd", "TX to %s %s", p->name, buffer+3); + } + } else { + if (!p->via && !p->locked) { + if (isonchannel(p, fromname, hostname)) { + if (!(p->filter && strstr(p->filter, namefilt))) { + appendprompt(p, 2); + if (*text != '\0') +#ifdef SPEECH + sprintf(buffer, speech_message(6), timestamp, fromname, hostname, text); +#else + sprintf(buffer, "%s%s@%s has gone away:\r %s\r", timestamp, fromname, hostname, text); +#endif + else +#ifdef SPEECH + sprintf(buffer, speech_message(7), timestamp, fromname, hostname); +#else + sprintf(buffer, "%s%s@%s is back again.\r", timestamp, fromname, hostname); +#endif +#ifdef L1IRC + if (p->IrcMode == TRUE) /* IRC-Client. */ + { + if (*text != '\0') /* Abmelden. */ + sprintf(buffer, ":%s 301 %s %s : %s\n" /* IRC-Meldung */ + , myhostname /* vorbereiten. */ + , fromname + , (*fromnickname ? fromnickname : fromname) + , text); + else /* Anmelden. */ + sprintf(buffer, ":%s 320 %s %s : is back\n" /* IRC-Meldung */ + , myhostname /* vorbereiten. */ + , fromname + , (*fromnickname ? fromnickname : fromname)); + } +#endif /* L1IRC */ + appendstring(p, buffer); + appendprompt(p, 0); + } + } + p->locked = 1; + } + } + } +} + +/*---------------------------------------------------------------------------*/ + +#ifndef L1IRC +void send_mode(CHANNEL *ch) +#else +void send_mode(CHANNEL *ch, CONNECTION *cp, WORD oldflags) +#endif /* L1IRC */ +{ + register CONNECTION *p; + char buffer[2048]; + char *flags; +#ifdef L1IRC + char flags_irc[16]; + char oldflags_irc[16]; + + flags_irc[0] = '\0'; + oldflags_irc[0] = '\0'; + + if (ch->flags & M_CHAN_S) + { + if (!(oldflags & M_CHAN_S)) + strcat(flags_irc, "p"); + } + + if (ch->flags & M_CHAN_P) + { + if (!(oldflags & M_CHAN_P)) + strcat(flags_irc, "i"); + } + + if (ch->flags & M_CHAN_T) + { + if (!(oldflags & M_CHAN_T)) + strcat(flags_irc, "t"); + } + + if (ch->flags & M_CHAN_I) + { + if (!(oldflags & M_CHAN_I)) + strcat(flags_irc, "s"); + } + + if (ch->flags & M_CHAN_M) + { + if (!(oldflags & M_CHAN_M)) + strcat(flags_irc, "m"); + } + + if ((oldflags & M_CHAN_S) && !(ch->flags & M_CHAN_S)) + strcat(oldflags_irc, "p"); + + if ((oldflags & M_CHAN_P) && !(ch->flags & M_CHAN_P)) + strcat(oldflags_irc, "i"); + + if ((oldflags & M_CHAN_T) && !(ch->flags & M_CHAN_T)) + strcat(oldflags_irc, "t"); + + if ((oldflags & M_CHAN_I) && !(ch->flags & M_CHAN_I)) + strcat(oldflags_irc, "s"); + + if ((oldflags & M_CHAN_M) && !(ch->flags & M_CHAN_M)) + strcat(oldflags_irc, "m"); +#endif /* L1IRC */ + + flags = getflags(ch->flags); + for (p = connections; p; p = p->next) { +#ifdef L1IRC + if (p->IrcMode == FALSE) + { +#endif /* L1IRC */ + if ((p->type == CT_HOST) && !p->locked) { + sprintf(buffer, "/\377\200MODE %d -sptiml+%s\r", ch->chan, flags); + appenddirect(p, buffer); + send_proto("cvsd", "TX to %s %s", p->name, buffer+3); + } +#ifdef L1IRC + } + else + { + struct clist *cl2; + char *fromname; + + if ((p->type == CT_HOST || p->type == CT_USER)) + { + if (p->type == CT_USER && !(p->operator == 2 && p->verbose)) + { + if (p->channel != ch->chan) + { + for (cl2 = p->chan_list; cl2; cl2 = cl2->next) + { + if (cl2->channel == ch->chan) + break; + } + + if (!cl2) + continue; + } + } + + fromname = ((cp) ? ((cp->type == CT_HOST) ? cp->name : cp->nickname) : myhostname); + sprintf(buffer, ":%s MODE #%d %s%s%s%s\n", fromname, ch->chan, (*oldflags_irc) ? "-" : "", oldflags_irc, (*flags_irc) ? "+" : "", flags_irc); + appendstring(p, buffer); + } + } + + p->locked = 1; +#endif /* L1IRC */ + } +} + +/*---------------------------------------------------------------------------*/ + +#ifndef L1IRC +void send_opermsg(char *toname, char *hostname, char *fromname, WORD channel) +#else +void send_opermsg(char *toname, char *hostname, char *fromname, WORD channel, int status_really_changed) +#endif /* L1IRC */ +{ + char buffer[2048]; + register CONNECTION *p; + CLIST *cl; + + for (p = connections; p; p = p->next) { + if (!p->locked) { +#ifdef L1IRC + int ison = 0; + + if (channel >= 0) + { + ison = 0; + + if (p->channel == channel) + ison = 1; + else + { + for (cl = p->chan_list; cl; cl = cl->next) + { + if (cl->channel == channel) + { + ison = 1; + break; + } + } + } + } + + if (p->IrcMode == TRUE) + { + if (channel == EOF) + { + if (p->type == CT_HOST || (p->type == CT_USER && (p->verbose || !strcasecmp(toname, p->name)) && status_really_changed)) + { + sprintf(buffer, ":%s MODE %s +o\n", fromname, toname); + appendstring(p, buffer); + } + } + else + { + if (p->type != CT_USER && p->type != CT_HOST) + continue; + + if (p->type == CT_USER) + { + if (p->via || !status_really_changed) + continue; + + if (!ison) + { + if (!p->verbose) + continue; + } + } + + sprintf(buffer, ":%s MODE #%d +o %s\n", fromname, channel, toname); + appendstring(p, buffer); + } + } +#endif /* L1IRC */ + if (p->type == CT_HOST) { + sprintf(buffer, "/\377\200OPER %s %d %s\r", fromname, channel, toname); + appenddirect(p, buffer); + p->locked = 1; + send_proto("cvsd", "TX to %s %s", p->name, buffer+3); + } else { + if (p->type == CT_USER) { + if (!p->via && (channel != -1)) { + if (!Strcmp(p->name,toname)) { + for (cl = p->chan_list; cl; cl = cl->next) { + if (cl->channel == channel) { + appendprompt(p, 2); +#ifdef SPEECH + sprintf(buffer, speech_message(8), + timestamp, fromname, channel); +#else + sprintf(buffer, "%s%s made you a channel operator for channel %d\r", + timestamp, fromname, channel); +#endif + appenddirect(p, buffer); + appendprompt(p, 0); + break; + } + } + p->locked = 1; + } else { + if (p->verbose) { + appendprompt(p, 2); +#ifdef SPEECH + sprintf(buffer, speech_message(9), + timestamp, toname, hostname, channel); +#else + sprintf(buffer, "%s%s@%s is now a channel operator for channel %d\r", + timestamp, toname, hostname, channel); +#endif + appenddirect(p, buffer); + appendprompt(p, 0); + p->locked = 1; + } + } + } + } + } + } + } +} + +/*---------------------------------------------------------------------------*/ + +#ifndef CONVNICK +void send_persmsg(char *fromname, char *hostname, WORD channel, +#else +void send_persmsg(char *fromname, char *fromnickname, char *hostname, WORD channel, +#endif /* CONVNICK */ + char *text, time_t time) +{ + char buffer[2048]; + char namefilt[68], *c; + register CONNECTION *p; + CHANNEL *ch; + char chan[128]; + WORD mychannel; + CLIST *cl; + + if (!text) /* DL1XAO NULL Pointer abfangen */ + text = ""; + for (ch = channels; ch; ch = ch->next) { + if (ch->chan == channel) break; + } +#ifdef SPEECH + sprintf(chan, speech_message(10), channel); +#else + sprintf(chan, "channel %d", channel); +#endif + if (ch) { + if (ch->flags & M_CHAN_S) strcpy(chan, "secret channel"); + if (ch->flags & M_CHAN_I) strcpy(chan, "this invisible channel"); + } + sprintf(namefilt, " %s ", fromname); + if ((c = strchr(namefilt, ':')) != NULL) { + *c++ = ' '; + *c = NUL; + } + for (p = connections; p; p = p->next) { + if (p->type == CT_HOST) { + if (!p->locked) { +#ifndef L1IRC + sprintf(buffer, "/\377\200USER %s %s %ld %d %d %s\r", fromname, hostname, (long)time, channel, channel, text); +#else + if (p->IrcMode == FALSE) + sprintf(buffer, "/\377\200USER %s %s %ld %d %d %s\r", fromname, hostname, (long)time, channel, channel, text); + else + { + sprintf(buffer, "NICK %s %d %s %s 0 + :%s", fromname, (strcasecmp(hostname, myhostname) ? 1 : 0), fromname, hostname, text); + buffer[2048] = 0; + } +#endif /* L1IRC */ + appenddirect(p, buffer); + p->locked = 1; + send_proto("cvsd", "TX to %s %s", p->name, buffer+3); + } + } else { + mychannel = -1; + for (cl = p->chan_list; cl; cl = cl->next) { + if (cl->channel == channel) { + mychannel = channel; + break; + } + } + if ((p->type == CT_USER) && !p->locked && !p->via && + (p->verbose || (mychannel == channel))) { + if (!(p->filter && strstr(p->filter, namefilt))) { + appendprompt(p, 2); + if (*text != '\0') { +#ifdef SPEECH + sprintf(buffer, speech_message(11), timestamp, fromname, hostname, chan, text); +#else + sprintf(buffer, "%s%s@%s on %s set personal text:\r %s\r", timestamp, fromname, hostname, chan, text); +#endif + } else { +#ifdef SPEECH + sprintf(buffer, speech_message(12), timestamp, fromname, hostname, chan); +#else + sprintf(buffer, "%s%s@%s on %s removed personal text.\r", timestamp, fromname, hostname, chan); +#endif + } +#ifdef L1IRC + if (p->IrcMode == TRUE) + { + sprintf(buffer, ":%s 311 %s %s %s %s * :%s\n" + , myhostname + , p->nickname + , fromname + , (*fromnickname ? fromnickname : fromname) + , hostname + , (*text && *text != '@') ? text : ""); + buffer[2048] = 0; + } +#endif /* L1IRC */ + appendstring(p, buffer); + appendprompt(p, 0); + } + } + p->locked = 1; + } + } +} + +/*---------------------------------------------------------------------------*/ + +#ifndef CONVNICK +void send_topic(char *fromname, char *hostname, time_t time, +#else +void send_topic(char *fromname, char *fromnickname, char *hostname, time_t time, +#endif /* CONVNICK */ + WORD channel, char *text) +{ + char buffer[2048]; + char namefilt[68], *c; + register CONNECTION *p; + register CHANNEL *ch; + char chan[128]; + WORD mychannel, flags = 0; + CLIST *cl; + + for (ch = channels; ch; ch = ch->next) + if (ch->chan == channel) break; + if (ch) { + sprintf(namefilt, " %s ", fromname); + if ((c = strchr(namefilt, ':')) != NULL) { + *c++ = ' '; + *c = NUL; + } +#ifdef SPEECH + sprintf(chan, speech_message(10), channel); +#else + sprintf(chan, "channel %d", channel); +#endif + flags = ch->flags; + if (flags & M_CHAN_S) strcpy(chan, "secret channel"); + if (flags & M_CHAN_I) strcpy(chan, "this invisible channel"); +#ifndef CONVTOPIC_FIX + if (ch->time < time) { +#else + if (ch->time <= time) { +#endif /* CONVTOPIC_FIX */ + setstring(&(ch->topic), text, 512); + ch->time = time; +#ifdef CONV_TOPIC + /* Call sichern. */ + strncpy(ch->name, fromname, NAMESIZE + 1); + /* Nullzeichen setzen. */ + ch->name[sizeof(ch->name)-1] = 0; +#endif + + for (p = connections; p; p = p->next) { + if (p->type == CT_HOST) { + if (!p->locked) { +#ifndef L1IRC + sprintf(buffer, "/\377\200TOPI %s %s %ld %d %s\r", fromname, hostname, (long)time, channel, text); +#else + if (p->IrcMode == FALSE) + sprintf(buffer, ":%s!%s@%s TOPIC #%d :%s\n", fromname, fromname, hostname, channel, text); + else + sprintf(buffer, "/\377\200TOPI %s %s %ld %d %s\r", fromname, hostname, (long)time, channel, text); +#endif /* L1IRC */ + appenddirect(p, buffer); + p->locked = 1; + send_proto("cvsd", "TX to %s %s", p->name, buffer+3); + } + } else { + mychannel = -1; + for (cl = p->chan_list; cl; cl = cl->next) { + if (cl->channel == channel) { + mychannel = channel; + break; + } + } + if ((p->type == CT_USER) && !p->locked && !p->via && + ((!(ch->flags & M_CHAN_I) && p->verbose) || (mychannel == channel) )) { + if (!(p->filter && strstr(p->filter, namefilt))) { + appendprompt(p, 2); + if (*text != '\0') +#ifdef SPEECH + sprintf(buffer, speech_message(13), + timestamp, fromname, hostname, chan, text); +#else + sprintf(buffer, "%s%s@%s on %s set channel topic:\r %s\r", + timestamp, fromname, hostname, chan, text); +#endif + else +#ifdef SPEECH + sprintf(buffer, speech_message(14), + timestamp, fromname, hostname, chan); +#else + sprintf(buffer, "%s%s@%s on %s removed channel topic.\r", + timestamp, fromname, hostname, chan); +#endif +#ifdef L1IRC + if (p->IrcMode == TRUE) + { + char IrcChannel[128]; + + sprintf(IrcChannel, "#%d", channel); + sprintf(buffer, ":%s!%s@%s TOPIC %s :%s\n", fromname, fromname, hostname, IrcChannel, text); + } +#endif /* L1IRC */ + appendstring(p, buffer); + appendprompt(p, 0); + } + } + p->locked = 1; + } + } + } + } +} + +#ifdef CONVNICK +/* Allen Convershosts den geaenderten Nickname mitteilen */ +void send_uaddmsg(CONNECTION *cp) +{ + CONNECTION *p; + char buffer[1024]; + + /* Nur, wenn wir auch einen Nickname haben */ + if (cp->nickname[0] == '\0') + return; + + for (p = connections; p; p = p->next) { + /* Ist es ein Host ? */ + if (p->type == CT_HOST) { + /* Wenn keine Sperre, dann senden wir den Nickname an den Host. */ + if (!p->locked) { + /* Nickname nur senden wenn der Host das Flag gesendet hat. */ + if (p->features & FEATURE_NICK) { + sprintf(buffer, "/\377\200UADD %s %s %s %d %s\r", cp->name, cp->host, cp->nickname, -1, cp->pers ? cp->pers : "~~"); + appenddirect(p, buffer); + send_proto("cvsd", "TX to %s %s", p->name, buffer + 3); + } + } + } + } +} +#endif + +/*---------------------------------------------------------------------------*/ +#ifndef CONVNICK +void send_user_change_msg(char *name, char *host, + WORD oldchannel, WORD newchannel, + char *pers, time_t time) +#else +void send_user_change_msg(char *name, char *nick, char *host, + WORD oldchannel, WORD newchannel, + char *pers, time_t time) +#endif /* CONVNICK */ +{ + char buffer[2048]; + CONNECTION *p; + char oldchan[24], newchan[24], name2[64 + 1], *c; + CHANNEL *ch; + WORD oldflags = 0, newflags = 0; + WORD mychannel; + CLIST *cl; + + if (!pers) /* DL1XAO: NULL Pointer abfangen */ + pers = ""; +#ifdef SPEECH + sprintf(newchan, speech_message(10), newchannel); + sprintf(oldchan, speech_message(10), oldchannel); +#else + sprintf(newchan, "channel %d", newchannel); + sprintf(oldchan, "channel %d", oldchannel); +#endif + sprintf(name2, " %s ", name); + if ((c = strchr(name2, ':')) != NULL) { + *c++ = ' '; + *c = NUL; + } + for (ch = channels; ch; ch = ch->next) + if (ch->chan == newchannel) break; + if (ch) { + newflags = ch->flags; + if (newflags & M_CHAN_S) { +#ifdef SPEECH + strcpy(newchan, speech_message(15)); +#else + strcpy(newchan, "secret channel"); +#endif + } + if (newflags & M_CHAN_I) { +#ifdef SPEECH + strcpy(newchan, speech_message(16)); +#else + strcpy(newchan, "this invisible channel"); +#endif + } + } + for (ch = channels; ch; ch = ch->next) + if (ch->chan == oldchannel) break; + if (ch) { + oldflags = ch->flags; + if (oldflags & M_CHAN_S) { +#ifdef SPEECH + strcpy(oldchan, speech_message(15)); +#else + strcpy(oldchan, "secret channel"); +#endif + } + if (oldflags & M_CHAN_I) { +#ifdef SPEECH + strcpy(oldchan, speech_message(16)); +#else + strcpy(oldchan, "this invisible channel"); +#endif + } + } + for (p = connections; p; p = p->next) { + if (p->type == CT_USER && !p->via && !p->locked) { + mychannel = -1; + for (cl = p->chan_list; cl; cl = cl->next) { + if (cl->channel == oldchannel) { + mychannel = oldchannel; + break; + } + } + if ((newchannel == oldchannel) && (newchannel != -1)) { + if ((p->verbose && !(newflags & M_CHAN_I)) || (mychannel == newchannel)) { + if (!(p->filter && strstr(p->filter, name2))) { + appendprompt(p, 2); +#ifdef L1IRC + if (p->IrcMode == FALSE) + { +#endif /* L1IRC */ + if (*pers && strcmp(pers, "@")) +#ifdef CONVNICK + { + if (*nick != NUL) +#ifdef SPEECH + sprintf(buffer, speech_message(17), timestamp, name, nick, host, newchan, pers); +#else + sprintf(buffer, "%s%s:%s@%s on %s set personal text:\r %s\r", timestamp, name, nick, host, newchan, pers); +#endif +#ifdef SPEECH + sprintf(buffer, speech_message(11), timestamp, name, host, newchan, pers); +#else + sprintf(buffer, "%s%s@%s on %s set personal text:\r %s\r", timestamp, name, host, newchan, pers); +#endif + } +#else + sprintf(buffer, "%s%s@%s on %s set personal text:\r %s\r", timestamp, name, host, newchan, pers); +#endif + else +#ifdef SPEECH + sprintf(buffer, speech_message(12), timestamp, name, host, newchan); +#else + sprintf(buffer, "%s%s@%s on %s removed personal text.\r", timestamp, name, host, newchan); +#endif +#ifdef L1IRC + } + else + sprintf(buffer, ":%s 311 %s %s %s %s * :%s\n" + , myhostname + , name + , (*nick ? nick : name) + , name + , host + , (*pers && *pers != '@') ? pers : ""); +#endif /* L1IRC */ + appendstring(p, buffer); + appendprompt(p, 0); + } + p->locked = 1; + } + } else { + if (oldchannel >= 0) { + if ((!(oldflags & M_CHAN_I) && p->verbose) || (mychannel == oldchannel)) { + appendprompt(p, 2); + if (strlen(pers) < 2) { +#ifdef CONVNICK + if (*nick != NUL) +#ifdef SPEECH + sprintf(buffer, speech_message(18), timestamp, name, nick, host, oldchan); +#else + sprintf(buffer, "%s%s:%s@%s left %s.\r", timestamp, name, nick, host, oldchan); +#endif + else +#endif +#ifdef SPEECH + sprintf(buffer, speech_message(19), timestamp, name, host, oldchan); +#else + sprintf(buffer, "%s%s@%s left %s.\r", timestamp, name, host, oldchan); +#endif + } else { +#ifdef SPEECH + sprintf(buffer, speech_message(20), timestamp, name, host, oldchan, pers); +#else + sprintf(buffer, "%s%s@%s left %s (%s).\r", timestamp, name, host, oldchan, pers); +#endif + } +#ifdef L1IRC + if (p->IrcMode == TRUE) + { + char IrcChannel[128]; + + sprintf(IrcChannel, "#%d", oldchannel); + sprintf(buffer, ":%s!%s@%s PART %s :%s\n" + , (*nick ? nick : name) + , name + , host + , IrcChannel + , "/leave"); + } +#endif /* L1IRC */ + appendstring(p, buffer); + appendprompt(p, 0); + p->locked = 1; + } + } + for (cl = p->chan_list; cl; cl = cl->next) { + if (cl->channel == newchannel) { + break; + } + } + if (newchannel >= 0) { + if ((cl) || (!(newflags & M_CHAN_I) && (p->verbose || (p->notify && strstr(p->notify, name2))))) { + appendprompt(p, 2); +#ifdef CONVNICK + if (*nick != NUL) +#ifdef SPEECH + sprintf(buffer, speech_message(21), timestamp, name, nick,host, newchan); +#else + sprintf(buffer, "%s%s:%s@%s joined %s\r", timestamp, name, nick,host, newchan); +#endif + else +#ifdef SPEECH + sprintf(buffer, speech_message(22), timestamp, name, host, newchan); +#else + sprintf(buffer, "%s%s@%s joined %s\r", timestamp, name, host, newchan); +#endif +#else +#ifdef SPEECH + sprintf(buffer, speech_message(22), timestamp, name, host, newchan); +#else + sprintf(buffer, "%s%s@%s joined %s\r", timestamp, name, host, newchan); +#endif +#endif +#ifdef L1IRC + if (p->IrcMode == TRUE) + { + char IrcChannel[128]; + + sprintf(IrcChannel, "#%d", newchannel); + sprintf(buffer, ":%s!%s@%s JOIN :%s\n", (*nick ? nick : name), name, host, IrcChannel); + appendstring(p, buffer); + + sprintf(buffer, ":%s 303 %s :\n", myhostname, p->nickname); + + appendstring(p, buffer); + sprintf(buffer, ":%s MODE #%d +t\n" + , host + , newchannel); + } +#endif /* L1IRC */ + appendstring(p, buffer); + if (!(p->filter && strstr(p->filter, name2))) { + if (*pers && strcmp(pers, "@")) { +#ifndef L1IRC + sprintf(buffer, " (%s)\r", pers); + appendstring(p, buffer); +#else + sprintf(buffer, " (%s)\r", pers); + + if (p->IrcMode == TRUE) + sprintf(buffer, ":%s 311 %s %s %s %s * :%s\n" + , myhostname + , name + , (*nick ? nick : name) + , name + , host + , (*pers && *pers != '@') ? pers : ""); + + appendstring(p, buffer); +#endif /* L1IRC */ + } + } + appendprompt(p, 0); + p->locked = 1; + } + } + } + } + if (p->type == CT_HOST && !p->locked) { + if (time == currtime) { + time++; + } + sprintf(buffer, "/\377\200USER %s %s %ld %d %d %s\r", name, host, (long)time, oldchannel, newchannel, pers); + appenddirect(p, buffer); + p->locked = 1; + send_proto("cvsd", "TX to %s %s", p->name, buffer+3); + } + } +} + +/*---------------------------------------------------------------------------*/ + +void send_msg_to_local_user(char *fromname, char *toname, char *text) +{ + + char buffer[2048]; + CONNECTION *p; +#ifdef CONVNICK + char buf[(NAMESIZE * 2) + 2]; +#endif + + for (p = connections; p; p = p->next) + if (p->type == CT_USER && (!strcasecmp(p->name, toname) +#ifdef CONVERS_NICKNAME + || !strcasecmp(p->nickname, toname) +#endif + ) && !p->locked) + if (!p->via) { + if (!p->locked) { + appendprompt(p, 2); + if (strcmp(fromname, "conversd")) { +#ifndef L1IRC + sprintf(buffer, "<*%s*>:", fromname); + appendformline(p, buffer, text); +#else + if (p->IrcMode == TRUE) + { + sprintf(buffer,":%s PRIVMSG %s : %s\n", fromname, p->nickname, text); + appendstring(p, buffer); + } + else + { + sprintf(buffer, "<*%s*>:", fromname); + appendformline(p, buffer, text); + } +#endif /* L1IRC */ + if (p->away && text[0] != '*') { +#ifdef CONVNICK + makeName(p, buf); +#ifdef SPEECH + sprintf(buffer,speech_message(23), timestamp, buf, p->away); +#else + sprintf(buffer,"%s%s is away: %s", timestamp, buf, p->away); +#endif /* SPEECH */ +#else +#ifdef SPEECH + sprintf(buffer,speech_message(23), timestamp, p->name, p->away); +#else + sprintf(buffer,"%s%s is away: %s", timestamp, p->name, p->away); +#endif /* SPEECH */ +#endif /* CONVNICK */ +#ifdef L1IRC + if (p->IrcMode == TRUE) + sprintf(buffer, ":%s 301 %s %s :#%s" + , myhostname + , fromname + , toname + , p->away); +#endif /* L1IRC */ + send_msg_to_local_user("conversd",fromname,buffer); + } + } else { +#ifndef L1IRC + appendstring(p, text); + appenddirect(p, "\r"); +#else + if (p->IrcMode == TRUE) + { + appendstring(p, text); + appendstring(p, "\n"); + } + else + { + appendstring(p, text); + appenddirect(p, "\r"); + } +#endif /* L1IRC */ + } + appendprompt(p, 0); + p->locked = 1; + } + } +} + +/*---------------------------------------------------------------------------*/ + +void send_msg_to_user(char *fromname, char *toname, char *text) +{ + + char buffer[2048]; + char namefilt[68], *c; + WORD filtered = 0; + CONNECTION *p; +#ifdef CONVNICK + char buf[(NAMESIZE * 2) + 2]; +#endif + + sprintf(namefilt, " %s ", fromname); + if ((c = strchr(namefilt, ':')) != NULL) { + *c++ = ' '; + *c = NUL; + } + for (p = connections; p; p = p->next) + if (p->type == CT_USER && (!strcasecmp(p->name, toname) +#ifdef CONVERS_NICKNAME + || !strcasecmp(p->nickname, toname) +#endif + ) && !p->locked) { + if (p->via) { + if (!p->via->locked) { + sprintf(buffer, "/\377\200UMSG %s %s %s\r", fromname, toname, text); + appenddirect(p->via, buffer); + p->via->locked = 1; + p->locked = 1; + send_proto("cvsd", "TX to %s %s", p->via->name, buffer+3); + } + } else { + if (!p->locked) { + if (p->filter && strstr(p->filter, namefilt)) { + filtered = 1; + continue; + } + appendprompt(p, 2); + if (strcmp(fromname, "conversd")) { +#ifndef L1IRC + sprintf(buffer, "<*%s*>:", fromname); + appendformline(p, buffer, text); +#else + if (p->IrcMode == TRUE) + { + if ((c = strchr(fromname, ':')) != NULL) + c++; + + sprintf(buffer,":%s PRIVMSG %s : %s\n" + , (c[0] == FALSE ? fromname : c) + , p->nickname, text); + appendstring(p, buffer); + } + else + { + sprintf(buffer, "<*%s*>:", fromname); + appendformline(p, buffer, text); + } +#endif /* L1IRC */ + if (p->away && text[0] != '*') { +#ifdef CONVNICK + makeName(p, buf); +#ifdef SPEECH + sprintf(buffer,speech_message(23), timestamp, buf, p->away); +#else + sprintf(buffer,"%s%s is away: %s", timestamp, buf, p->away); +#endif /* SPEECH */ +#else +#ifdef SPEECH + sprintf(buffer,speech_message(23), timestamp, p->name, p->away); +#else + sprintf(buffer,"%s%s is away: %s", timestamp, p->name, p->away); +#endif /* SPEECH */ +#endif /* CONVNICK */ +#ifdef L1IRC + if (p->IrcMode == TRUE) + sprintf(buffer, ":%s 301 %s %s :#%s\n" + ,p->host + ,p->nickname + ,p->name + ,p->away); +#endif /* L1IRC */ + send_msg_to_local_user("conversd",fromname,buffer); + } + } else { +#ifndef L1IRC + appendstring(p, text); + appenddirect(p, "\r"); +#else + if (p->IrcMode == TRUE) + { + appendstring(p, text); + appendstring(p, "\n"); + } + else + { + appendstring(p, text); + appenddirect(p, "\r"); + } +#endif /* L1IRC */ + } + appendprompt(p, 0); + p->locked = 1; + } + } + } + + if (filtered) { + clear_locks(); +#ifdef SPEECH + sprintf(buffer,speech_message(24), timestamp, toname); +#else + sprintf(buffer,"%sYour messages are ignored by %s", timestamp, toname); +#endif +#ifdef L1IRC + if (p->IrcMode == TRUE) + sprintf(buffer,":%s 465 %s :Nachricht wird gefiltert!\n" + , p->host + , (p->nickname ? p->nickname : p->name)); +#endif /* L1IRC */ + send_msg_to_user("conversd",fromname,buffer); + } +} + +/*---------------------------------------------------------------------------*/ + +void send_msg_to_channel(char *fromname, WORD channel, char *text) +{ + char buffer[2048]; + char namefilt[68], *c; + CONNECTION *p; + CHANNEL *ch; + char addchan[16]; + CLIST *cl; + WORD printit; + WORD cvd; +#ifdef CONVNICK + char Nickname[NAMESIZE + 1]; +#endif /* CONVNICK */ + + cvd = strcmp(fromname, "conversd"); + if (!cvd && !strncmp(text, "*** ", 4)) { /* /me abfangen */ + sscanf(text + 4, "%s", buffer); /* Absender ermitteln */ + buffer[64] = '\0'; + if ((c = strchr(buffer, '@')) != NULL) + *c = '\0'; + sprintf(namefilt, " %s ", buffer); +#ifdef CONVNICK + memset(Nickname, 0, sizeof(Nickname)); /* String Initialisieren. */ + + if ((c = strchr(buffer, ':')) != NULL) /* ggf. Nickname ermitteln. */ + { + c++; /* ':' zeichen loeschen. */ + strncpy(Nickname, c, NAMESIZE); /* Nickname sichern. */ + } +#endif /* CONVNICK */ + } else { + sprintf(namefilt, " %s ", fromname); + if ((c = strchr(namefilt, ':')) != NULL) { + *c++ = ' '; + *c = NUL; + } + } + for (ch = channels; ch; ch = ch->next) { + if (ch->chan == channel) break; + } + for (p = connections; p; p = p->next) { +#ifdef CONVNICK + /* Wir pruefen auf Rufzeichen *und* Nickname */ + if (p->type == CT_USER && (!strcasecmp(p->name, fromname) || !strcasecmp(p->nickname, fromname))) { +#else + if (p->type == CT_USER && !Strcmp(p->name, fromname)) { +#endif + p->mtime = currtime; + } + } + for (p = connections; p; p = p->next) { + if (p->type == CT_USER) { + printit = 0; + if (p->channel == channel) { + printit = 1; + addchan[0] = '\0'; + } else { + for (cl = p->chan_list; cl ; cl = cl->next) { + if (cl->channel == channel) { + printit = 1; + sprintf(addchan, "%d:", channel); + } + } + } + if (printit) { + if (p->via) { + if (!p->via->locked && !(ch->flags & M_CHAN_L)) { + sprintf(buffer, "/\377\200CMSG %s %d %s\r", fromname, channel, text); + appenddirect(p->via, buffer); + p->via->locked = 1; + } + } else { + if (!p->locked) { + if (p->filter && strstr(p->filter, namefilt)) + continue; + appendprompt(p, 2); + if (cvd) { +#ifndef L1IRC + sprintf(buffer, "<%s%s>:", addchan, fromname); + appendformline(p, buffer, text); +#else + if (p->IrcMode == TRUE) + { + sprintf(buffer, ":%s PRIVMSG #%d :%s\n",fromname, channel, text); + appendstring(p, buffer); + } + else + { + sprintf(buffer, "<%s%s>", addchan, fromname); + appendformline(p, buffer, text); + } +#endif /* L1IRC */ + } else { +#ifndef L1IRC + appendstring(p, text); + appenddirect(p, "\r"); +#else + if (p->IrcMode == TRUE) /* IRC-Client. */ + { + char buffer2[2048]; + /* IRC-Meldung vorbereiten. */ + sprintf(buffer2, ":%s PRIVMSG #%d :%s\n" + , (Nickname[0] != FALSE ? Nickname : buffer) + , channel + , text); + appendstring(p, buffer2); /* IRC-Meldung senden. */ + } + else + { + appendstring(p, text); + appenddirect(p, "\r"); + } +#endif /* L1IRC */ + } + appendprompt(p, 0); + p->locked = 1; + } + } + } + } + } +} + +/*---------------------------------------------------------------------------*/ +/* DL1XAO Protokollausgabe, lokal auf Kanal 32767, egal welchen Status + * er sonst noch hat + */ +void send_proto(const char *modul, const char *format, ...) +{ + char buffer[16]; + CONNECTION *p; + CHANNEL *ch; + CLIST *cl; + WORD printit; + va_list arg_ptr; + char str[1024]; + + va_start(arg_ptr, format); + vsprintf(str, format, arg_ptr); + va_end(arg_ptr); + + if (!cvs_pc) + return; + for (ch = channels; ch; ch = ch->next) + if (ch->chan == 32767) + break; + if (!ch) /* nobody online */ + return; + + for (p = connections; p; p = p->next) { + if (p->type == CT_USER && !p->via) { + printit = 0; + if (p->channel == 32767) + printit = 1; + else { + for (cl = p->chan_list; cl ; cl = cl->next) + if (cl->channel == 32767) + printit = 1; + } + if (printit) { + appendprompt(p, 2); + sprintf(buffer, "[%s]:", modul); + appendformline(p, buffer, str); + appendprompt(p, 0); + } + } + } +} + +/*---------------------------------------------------------------------------*/ + +void send_invite_msg(char *fromname, char *toname, WORD channel) +{ + CONNECTION *p; + char buffer[2048]; +#ifdef SPEECH + static char invitetext[128]; + static char responsetext[128]; + + strcpy(invitetext,speech_message(25)); + strcpy(responsetext,speech_message(26)); +#else + static char invitetext[] = "\r\007\007%sMessage from %s...\rPlease join %s channel %d.\r\007\007\r"; + static char responsetext[] = "%s%s Invitation sent to %s @ %s."; +#endif + + + for (p = connections; p; p = p->next) + if (p->type == CT_USER && !Strcmp(p->name, toname)) { + if (p->channel == channel) { + clear_locks(); +#ifdef SPEECH + sprintf(buffer, speech_message(27), timestamp, toname); +#else + sprintf(buffer, "%sUser %s is already on this channel.", timestamp, toname); +#endif + send_msg_to_user("conversd", fromname, buffer); + return; + } + if (!p->via && !p->locked) { + sprintf(buffer, invitetext, timestamp, fromname, convtype, channel); + p->invitation_channel = channel; + appendstring(p, buffer); + clear_locks(); + sprintf(buffer, responsetext, timestamp, convtype, toname, myhostname); + send_msg_to_user("conversd", fromname, buffer); + return; + } + if (p->via && !p->via->locked) { + sprintf(buffer, "/\377\200INVI %s %s %d\r", fromname, toname, channel); + appenddirect(p->via, buffer); + send_proto("cvsd", "TX to %s %s", p->via->name, buffer+3); + return; + } + } + + sprintf(buffer, invitetext, timestamp, fromname, convtype, channel); + if (invite_ccp(toname, buffer)) { + clear_locks(); + sprintf(buffer, responsetext, timestamp, convtype, toname, myhostname); + send_msg_to_user("conversd", fromname, buffer); + return; + } + + for (p = connections; p; p = p->next) + if (p->type == CT_HOST && !p->locked) { + sprintf(buffer, "/\377\200INVI %s %s %d\r", fromname, toname, channel); + appenddirect(p, buffer); + send_proto("cvsd", "TX to %s %s", p->name, buffer+3); + } + +} + +/*---------------------------------------------------------------------------*/ + +void update_destinations(PERMLINK *p, char *name, time_t rtt, char *rev) +{ + PERMLINK *l; + DESTINATION *d, *d1; + WORD pl; + char buffer[256]; + + for (d = destinations; d; d = d->next) + if (!Strcmp(d->name, name)) break; + + if (!d) { + d = (DESTINATION *)calloc(1, sizeof(DESTINATION)); + if (d) { + d->link = p; + Strcpy(d->name, name); + Strcpy(d->rev, rev); + if (!destinations || (! destinations->name) || (Strcmp(destinations->name, name) > 0)) { + d->next = destinations; + destinations = d; + } else { + d1 = destinations; + while (d1->next) { + if (Strcmp(d1->next->name, name) > 0) { + d->next = d1->next; + d1->next = d; + break; + } + d1 = d1->next; + } + if (!d1->next) { + d->next = d1->next; + d1->next = d; + } + } + } + } else { + Strcpy(d->rev, rev); + d->link = p; + } + + if (!d) + return; + + d->rtt = rtt; + if (labs(rtt - d->last_sent_rtt) > (d->last_sent_rtt / 8L)) { + for (pl = 0; pl < MAXCVSHOST; pl++) { + l = permarray[pl]; + if ( l != NULL + && l != d->link + && l->connection + && l->connection->type == CT_HOST + ) { + if (rtt) + sprintf(buffer, "/\377\200DEST %s %ld %s\r", name, rtt+(l->txtime+l->rxtime)/2L, rev); + else + sprintf(buffer, "/\377\200DEST %s 0\r", name); + + d->last_sent_rtt = rtt; + appenddirect(l->connection, buffer); + send_proto("cvsd", "TX to %s %s", l->connection->name, buffer+3); + } + } + } +} + +/*---------------------------------------------------------------------------*/ + +#if !defined(__WIN32__) && !defined(__LINUX__) +#pragma warn -par +#endif +PERMLINK *update_permlinks(char *name, CONNECTION *cp, WORD isperm) +{ + DESTINATION *d; + PERMLINK *p; + WORD pl; +#ifdef CONVERS_LINKS + char NAME[NAMESIZE + 1]; +#endif + + if (*name == NUL) + return(NULLPERMLINK); + +#ifdef CONVERS_LINKS + strncpy(NAME, name, NAMESIZE); + strupr(NAME); +#endif + + for (pl = 0; pl < MAXCVSHOST; pl++) { + p = permarray[pl]; + if (p == NUL) + continue; +#ifdef CONVERS_LINKS + if ((cmpcal(p->call,NAME)) || (!strcasecmp(p->cname, name))) +#else + if (!strcmp(p->cname, name)) +#endif + { /* Eintrag gefunden,aendern */ + for (d = destinations; d; d = d->next) { + if (d->rtt && (d->link == p)) { + update_destinations(p, d->name, 0, ""); + } + } + if (cp) { /* eintragen */ + p->connection = cp; + p->statetime = currtime; + p->tries = 0; + p->waittime = 9; + p->rxtime = 0; + p->txtime = 0; + p->testwaittime = currtime; + p->testnexttime = currtime + 60; + p->retrytime = currtime + p->waittime; + } else { /* austragen */ + p->statetime = currtime; + p->tries = 0; + if (p->locked) { + p->waittime = 3600; + p->nlcks++; + } + else + p->waittime = 9; + p->rxtime = 0; + p->txtime = 0; + p->testwaittime = currtime; + p->testnexttime = currtime + 60; + p->retrytime = currtime + p->waittime; + } + return(p); + } + } + for (pl = 0; pl < MAXCVSHOST; pl++) { /* neuer Eintrag */ + if (!permarray[pl]) break; + } + if (pl < MAXCVSHOST) { + p = (PERMLINK *) calloc(1, sizeof(PERMLINK)); + if (p) { + strncpy(p->cname, name, NAMESIZE); + strcpy(p->call, name); + p->connection = cp; + p->statetime = currtime; + p->waittime = 9; + p->testnexttime = currtime + 60; + p->testwaittime = currtime; + p->retrytime = currtime + p->waittime; + } + permarray[pl] = p; + } else { + return(NULLPERMLINK); + } + return(p); +} +#if !defined(__WIN32__) && !defined(__LINUX__) +#pragma warn .par +#endif + +/*---------------------------------------------------------------------------*/ + +void connect_permlinks() +{ + +#define MAX_WAITTIME (60L*60L*3L) + + WORD pl; + PERMLINK *p; + DESTINATION *d; + + for (pl = 0; pl < MAXCVSHOST; pl++) { + p = permarray[pl]; + if (p && p->connection && p->connection->type == CT_HOST) { + if (p->testnexttime < currtime) { + if ((p->testwaittime + 7300L) < currtime) { + p->rxtime = 0; + p->txtime = 0; + for (d = destinations; d; d = d->next) { + if (d->link == p) { + update_destinations(p, d->name, 0, ""); + } + } + } + appenddirect(p->connection, "/\377\200PING\r"); + send_proto("cvsd", "TX to %s PING", p->cname); + p->testwaittime = currtime; + p->testnexttime = currtime + 7300L; + } + } + } + for (pl = 0; pl < MAXCVSHOST; pl++) { + p = permarray[pl]; + if (p && !p->connection) { + if (p->retrytime < currtime) { + p->tries++; + if (p->locked) { /* Sperrzeit abgelaufen */ + p->waittime = 75; + p->locked = 0; + } + if (p->waittime == 9) p->waittime = 75; /* *2 = 2.5 minutes */ + p->waittime <<= 1; /* 2.5,5,10,20,40,80,160,180,180,... min */ + if (p->waittime > MAX_WAITTIME) p->waittime = MAX_WAITTIME; + p->retrytime = currtime + p->waittime; + if (p->port != 254) + connect_cvshost(p); + } + } + } +} + +/*------------------------------------------------------------------------*/ + +/* lokal eingegebene Personalbeschreibungen werden in einer Datenbank + * gespeichert. Deim Einloggen von bekannten Personen wird der Text + * automatisch gesetzt. Die Datenbank laeuft im textpath (ramdisk), die + * Daten koennen im confpath gesichert werden. Die Textlaenge wird auf + * 118 Zeichen begrenzt, das sollte ausreichen. + * Zusaetzlich werden die Zeilenbreite, sowie Zeichensaetze gespeichert + * und ein Timestamp, der zum Loeschen von VOM's dient. + */ +char *personalmanager(WORD func, CONNECTION *cp, char *pers) +{ + char buffer[1024]; + static char tmp[128]; + ULONG n; + FILE *fp1; +#ifndef MC68302 + FILE *fp2; +#endif + + if (cp && *cp->name) { + sprintf(tmp, "%-6.6s", cp->name); + strupr(tmp); + } + else + cp = NULL; + switch (func) { + case INIT: + persfile = strdup(pers); +#ifndef MC68302 + strcpy(tmp, confpath); + strcat(tmp, "convers.prs"); + if (!stricmp(persfile, tmp)) /* Pfade sind gleich */ + break; + if ((fp1 = xfopen(tmp, "rb")) == NULL) /* noch keine Datei */ + break; + if ((fp2 = xfopen(persfile, "wb")) == NULL) { /*Schreibfehler*/ + fclose(fp1); + break; + } /* Daten umkopieren */ + while ((n = fread(buffer, 1, 1024, fp1)) > 0) + fwrite(buffer, 1, (size_t)n, fp2); + fclose(fp1); + fclose(fp2); +#endif + break; + + case SAVE: +#ifndef MC68302 + strcpy(tmp, confpath); + strcat(tmp, "convers.prs"); + if (!stricmp(persfile, tmp)) /* Pfade sind gleich */ + break; + if ((fp1 = xfopen(persfile, "rb")) == NULL)/*noch keine Datei*/ + break; + if ((fp2 = xfopen(tmp, "wb")) == NULL) { /* Schreibfehler */ + fclose(fp1); + break; + } /* Daten umkopieren */ + while ((n = fread(buffer, 1, 1024, fp1)) > 0) + fwrite(buffer, 1, (size_t)n, fp2); + fclose(fp1); + fclose(fp2); +#endif + break; + + case SET: + if (!cp || !pers) + break; + strncpy(tmp+6, pers, 118); + tmp[124] = (char)(currtime >> 24); /* Timestamp, ca 194 Tage */ + tmp[125] = (char)cp->width; + tmp[126] = (char)cp->charset_in; + tmp[127] = (char)cp->charset_out; + if ((fp1 = xfopen(persfile, "rb+")) == NULL) {/*Datei oeffnen*/ + if ((fp1 = xfopen(persfile, "wb")) != NULL) { /* dann neu */ + fwrite(tmp, 1, 128, fp1); /* der erste Eintrag */ + fclose(fp1); + } + break; + } + func = 0; + n = 0; + while (!func && fread(buffer, 1, 128, fp1)) {/* suchen */ + if (!strncmp(buffer, tmp, 6)) { + func = 1; + break; + } + n += 128; + } + if (func) /* zum editieren zu- */ + fseek(fp1, n, SEEK_SET); /* rueckpositionieren */ + fwrite(tmp, 1, 128, fp1); /* Daten schreiben */ + fclose(fp1); + break; + + case GET: + if (!cp) + break; + if ((fp1 = xfopen(persfile, "rb+")) == NULL) + break; + n = 0; + while (fread(buffer, 1, 128, fp1)) { + if (!strncmp(buffer, tmp, 6)) { /* suchen */ + if (buffer[124] != (char)(currtime >> 24)) { /* neuen */ + buffer[124] = (char)(currtime >> 24); /* Timestamp */ + fseek(fp1, n, SEEK_SET); /*rueckpositionieren*/ + fwrite(buffer, 1, 128, fp1); /* Daten schreiben */ + } + fclose(fp1); + if ((cp->width = buffer[125]) == 0) + cp->width = 80; + cp->charset_in = buffer[126]; + cp->charset_out = buffer[127]; + buffer[124] = '\0'; + strcpy(tmp, buffer+6); + return(tmp); /* zurueckgeben */ + } + n += 128; + } + fclose(fp1); + } + return(NULL); +} + +/*---------------------------------------------------------------------------*/ + +char *getflags(WORD flag) +{ + static char f[8]; + char *p; + + p = f; + if (flag & M_CHAN_S) + *p++ = 'S'; + if (flag & M_CHAN_P) + *p++ = 'P'; + if (flag & M_CHAN_T) + *p++ = 'T'; + if (flag & M_CHAN_I) + *p++ = 'I'; + if (flag & M_CHAN_M) + *p++ = 'M'; + if (flag & M_CHAN_L) + *p++ = 'L'; + *p = '\0'; + return(f); +} + +/*---------------------------------------------------------------------------*/ + +/* aehnlich strncpy, speziell zum Eintragen in die Namensfelder */ +void Strcpy(char *dst, char *src) +{ + WORD max; + + for (max = NAMESIZE-1; max-- && *src; ) + *dst++ = *src++; + *dst = '\0'; +} + +/* aehnlich strncmp, prueft mit auf Namensfeldbreite gekuerztem b */ +WORD Strcmp(char *a, char *b) +{ + char tmp[NAMESIZE]; + + Strcpy(tmp, b); + return(strcmp(a, tmp)); +} + +/*---------------------------------------------------------------------------*/ + +/* Da einige Felder zuviel Platz belegen und es einfach Verschwendung + ist, dafuer soviel Platz zu belegen, obwohl man diese nicht immer + nutzt, verwalten wir das ganze mit Pointern und dynamisch. + Einige andere Funktionen mussten diesem Verhalten angepasst werden. + + Eingabe: + adr : Zeiger auf den Zeiger auf den String + str : neuer String, leer zum Loeschen + max : maximale ehemalige Feldbreite + Resultat: + Ueber adr wird der Zeiger in der Struktur modifiziert */ + +void setstring(char **adr, char *str, WORD max) +{ + if (!*str) { /* Kein String,also loeschen */ + if (*adr) /* schon ein String gesetzt, */ + free(*adr); /* also Speicher freigeben */ + *adr = NULL; /* markieren */ + } + else { +#ifdef __WIN32__ + if (strlen(str) >= (unsigned short)max) /* String zulang, */ +#else + if (strlen(str) >= max) /* String zulang, */ +#endif /* WIN32 */ + *(str + max-1) = '\0'; /* also kuerzen */ + if (*adr) { /* schon ein String gesetzt, */ + if (!strcmp(*adr, str)) /* String ist derselbe */ + return; /* also nichts zutun */ + free(*adr); /* Speicher freigeben */ + } + *adr = strdup(str); /* neuen String einfuegen */ + } +} + +/*---------------------------------------------------------------------------*/ + +#ifdef CONV_CHECK_USER +/************************************************************************/ +/* Pruefung auf Doppel-Login */ +/*----------------------------------------------------------------------*/ +CONNECTION *CheckUserCVS(char *user) +{ + CONNECTION *p; + + for (p = connections; p; p = p->next) + { + if ( ((!strcasecmp(p->name, user)) /* Rufzeichenvergleich. */ +#ifdef CONVNICK + ||(!strcasecmp(p->nickname, user)) /* Nicknamevergleich. */ +#endif /* CONVNICK */ + ) + &&(p->type == CT_USER)) /* Als User markiert. */ + return (p); + } + + return(NULL); +} +#endif /* CONV_CHECK_USER. */ + +#else +#if !defined(__WIN32__) && !defined(__LINUX__) +#pragma warn -par +#endif + +void send_proto(const char *modul, const char *format, ...) +{ +} + +char *personalmanager(WORD func, CONNECTION *cp, char *pers) +{ + return NULL; +} + +#if !defined(__WIN32__) && !defined(__LINUX__) +#pragma warn .par +#endif +#endif + +#ifdef BEACON_STATUS +char *convers_user(char *cuser) +{ + WORD newchannel; + WORD printit; + + newchannel = 0; +#ifdef PPCONVERS + printit = count_user(newchannel); + sprintf(cuser,"%u",printit); +#else + printit = FALSE; +#endif + return(cuser); +} +#endif + +/* End of $RCSfile$ */ diff --git a/src/cvs_serv.c b/src/cvs_serv.c new file mode 100755 index 0000000..f2ae5f4 --- /dev/null +++ b/src/cvs_serv.c @@ -0,0 +1,688 @@ +/************************************************************************/ +/* */ +/* ***** ***** */ +/* ***** ***** */ +/* ***** ***** */ +/* ***** ***** */ +/* *************** *************** */ +/* ***************** ***************** */ +/* *************** *************** */ +/* ***** ***** TheNetNode */ +/* ***** ***** Portable */ +/* ***** ***** Network */ +/* ***** ***** Software */ +/* */ +/* File src/cvs_serv.c (maintained by: DL1XAO) */ +/* */ +/* This file is part of "TheNetNode" - Software Package */ +/* */ +/* Copyright (C) 1998 - 2008 NORD> + * + * Modifications by Fred Baumgarten + * $Revision: 3.12 $$Date: 1996/03/03 10:09:47 $ + * + * Modifications by Oliver Kern + * $Revision: 3.13 $$Date: 17.08.2004 22:22 $ + */ +/* modified for use with TheNetNode by DL1XAO */ +/* Hierdrin befinden sich die mit TNN kommunizierenden Routinen */ + +#include "tnn.h" + +#ifdef PPCONVERS + +#include "conversd.h" + +char cnvinbuf[2048]; +WORD s_CVOUT = FALSE; + + +/*---------------------------------------------------------------------------*/ + +CONNECTION *alloc_connection(USRBLK *up) +{ + CONNECTION *cp; + + cp = (CONNECTION *) calloc(1, sizeof(CONNECTION)); + if (cp != NULLCONNECTION) { + cp->time = currtime; + cp->atime = currtime; + cp->width = 80; + cp->up = up; +#ifdef L1IRC + cp->IrcMode = FALSE; +#endif /* L1IRC */ + cp->next = connections; + connections = cp; + } + return(cp); +} + +/*---------------------------------------------------------------------------*/ + +void free_connection(CONNECTION *cp) +{ + USRBLK *save_userpo; + MBHEAD *mbp; + PERMLINK *p; + + p = permlink_of(cp); + if (p) + p->connection = NULLCONNECTION; + + if (cp->up != NULL) { + save_userpo = userpo; + userpo = cp->up; + if (userpo->convflag != 0) { /* kein recon in ccp */ + disusr(userpo->uid); + userpo->convers = NULLCONNECTION; + /* kilusr(); das macht l2tol7 */ + } else { + mbp = getmbp(); + putstr(timestamp, mbp); +#ifdef SPEECH + putstr(speech_message(1), mbp); +#else + putstr("Convers session terminated.\r", mbp); + putstr("Enter command. Type HELP for help.\r", mbp); +#endif + userpo->convers = NULLCONNECTION; + prompt(mbp); + seteom(mbp); + } + userpo = save_userpo; + } + + if (cp->mbout) + dealmb(cp->mbout); + if (cp->pers) + free(cp->pers); + if (cp->away) + free(cp->away); + if (cp->notify) + free(cp->notify); + if (cp->filter) + free(cp->filter); + free(cp); +} + +/*---------------------------------------------------------------------------*/ + +BOOLEAN invite_ccp(char *toname, char *message) +{ + char tmp[8]; + USRBLK *save_userpo; + MBHEAD *mbp; + + save_userpo = userpo; + for (userpo = (USRBLK *) usccpl.head; + userpo != (USRBLK *) &usccpl; + userpo = (USRBLK *) userpo->unext) + { + if (userpo->convers == NULLCONNECTION && userpo->status == US_CCP) { + callss2str(tmp, calofs(UPLINK, userpo->uid)); + strlwr(tmp); + + if (!Strcmp(tmp, toname)) { + mbp = getmbp(); + putstr(message, mbp); + seteom(mbp); + userpo = save_userpo; + return(TRUE); + } + } + } + userpo = save_userpo; + return(FALSE); +} + +/*---------------------------------------------------------------------------*/ + +BOOLEAN connect_cvshost(PERMLINK *p) +{ + CONNECTION *cp; + USRBLK *save_userpo; + CIRBLK *save_cirpoi; + NODE *node; + PTCENT *ptcp; + char convcall[L2IDLEN]; + + if ((cp = alloc_connection(NULL)) != NULL) { + save_userpo = userpo; + save_cirpoi = cirpoi; + userpo = (USRBLK *) allocb(ALLOC_USRBLK1); + userpo->uid = 0; + userpo->status = US_CHST; + userpo->sysflg = 0; + userpo->errcnt = 0; + userpo->mbhd = NULL; + userpo->talkcall[0]= '\0'; + userpo->monitor = NULL; + userpo->auditlevel = 0; + userpo->fp = NULL; + userpo->fname = NULL; + userpo->convers = cp; + userpo->convflag = 2; /* kam von uns, kein recon in ccp */ +#ifdef PACSAT + userpo->pacsat = NULL; +#endif + + send_proto("serv", "Try Hostconnect to %s (%p)", p->cname, cp); + + strcpy(cp->name, p->cname); + cp->type = CT_UNKNOWN; + cp->up = userpo; + p->connection = cp; + +#ifdef OS_IPLINK + if (p->TcpLink) + { + if (IPConvConnect(p->call, myid, TRUE)) + { + dealoc((MBHEAD *)userpo); /* das war alles nix */ + connections = cp->next; /* tun wir so, als haetten*/ + free(cp); /* wir nichts bemerkt */ + p->connection = NULLCONNECTION; + return(FALSE); + } + + relink((LEHEAD *)userpo,(LEHEAD *) usccpl.tail); + userpo->uid = g_uid(tcppoi, TCP_USER); + + cpyid(tcppoi->Downcall, p->call); + memcpy(tcppoi->Upcall, myid, L2CALEN); + tcppoi->Upcall[L2IDLEN-1] = (convid<<1)|0x60; + + userpo->status = US_CCP; + clrptc(userpo->uid); + ptcp = ptctab + userpo->uid; + ptcp->ublk = userpo; + ptcp->state = UPLINK; /* Convers ist eigentlich Downlink */ + userpo = save_userpo; + cirpoi = save_cirpoi; + return(TRUE); + } +#endif /* OS_IPLINK */ + + if (p->port == 255) { + if (iscall(p->call,&node,NULL,DG)) { + for (cirpoi = cirtab; cirpoi < &cirtab[NUMCIR]; ++cirpoi) + if (cirpoi->state == 0) /* Level 3 Kontrollblock = leer */ + break; /* freien Block gefunden.. */ + + if (cirpoi != &cirtab[NUMCIR]) { /* neues Ciruit erzeugen */ + relink((LEHEAD *)userpo,(LEHEAD *) usccpl.tail); + userpo->uid = g_uid(cirpoi, L4_USER); + cpyid(cirpoi->downca, node->id); + memcpy(cirpoi->upcall, myid, L2CALEN); + cirpoi->upcall[L2IDLEN-1] = (convid<<1)|0x60; + cpyid(cirpoi->upnod, myid); /* Uplink hier */ + *cirpoi->upnodv = '\0'; /* kein Digi */ + cpyid(cirpoi->l3node, node->id); + newcir(); /* L3-Verbindung aufbauen */ + clrptc(userpo->uid); + ptcp = ptctab + userpo->uid; + ptcp->ublk = userpo; + ptcp->state = UPLINK; /* Convers ist eigentlich Downlink */ + userpo = save_userpo; + cirpoi = save_cirpoi; + return(TRUE); + } + } + send_proto("serv", "...no circuit/not a node"); + } + else { + if (portenabled(p->port)) { + memcpy(convcall, myid, L2CALEN); + convcall[L2IDLEN-1] = (convid<<1)|0x60; +#ifdef OS_IPLINK + if (IPConvConnect(p->call, myid, TRUE) == FALSE) + { + relink((LEHEAD *)userpo,(LEHEAD *) usccpl.tail); + userpo->uid = g_uid(tcppoi, TCP_USER); + + cpyid(tcppoi->Downcall, p->call); + memcpy(tcppoi->Upcall, myid, L2CALEN); + tcppoi->Upcall[L2IDLEN-1] = (convid<<1)|0x60; + + userpo->status = US_CCP; + clrptc(userpo->uid); + ptcp = ptctab + userpo->uid; + ptcp->ublk = userpo; + ptcp->state = UPLINK; /* Convers ist eigentlich Downlink */ + userpo = save_userpo; + cirpoi = save_cirpoi; + return(TRUE); + } +#endif /* OS_IPLINK */ + + if ((lnkpoi = getlnk((UBYTE)p->port, convcall, p->call, p->via)) != NULL) { + relink((LEHEAD *)userpo,(LEHEAD *) usccpl.tail); + userpo->uid = g_uid(lnkpoi, L2_USER); + newlnk(); /* L2-Verbindung aufbauen! */ + clrptc(userpo->uid); + ptcp = ptctab + userpo->uid; + ptcp->ublk = userpo; + ptcp->state = UPLINK; /* Convers ist eigentlich Downlink */ + userpo = save_userpo; + cirpoi = save_cirpoi; + return(TRUE); + } else + send_proto("serv", "...no free link"); + } else + send_proto("serv", "...port off"); + } + dealoc((MBHEAD *)userpo); /* das war alles nix */ + connections = cp->next; /* tun wir so, als haetten*/ + free(cp); /* wir nichts bemerkt */ + p->connection = NULLCONNECTION; + userpo = save_userpo; + cirpoi = save_cirpoi; + } + return(FALSE); +} + +/*---------------------------------------------------------------------------*/ + +void putcvsstr(CONNECTION *cp, char *str) +{ + if (cp->mbout == NULL) { + cp->mbout = (MBHEAD *) allocb(ALLOC_MBHEAD); + cp->mbout->l2link = g_ulink(cp->up->uid); + cp->mbout->type = g_utyp(cp->up->uid); + } + putstr(str, cp->mbout); + s_CVOUT = TRUE; +} + +static UWORD cvs2tnn(CONNECTION *cp) +{ + UWORD ret = 0; + + if (cp->mbout != NULL) { + ret = cp->mbout->mbpc - cp->mbout->mbgc; + seteom(cp->mbout); + cp->mbout = NULL; + } + return(ret); +} + +LONG queuelength(CONNECTION *cp) +{ + return((cp->mbout != NULL) ? (cp->mbout->mbpc - cp->mbout->mbgc) : 0L); +} + +/*---------------------------------------------------------------------------*/ + +/*****************************************************************************/ +/* Initialisieren der conversd-Umgebung */ +/*---------------------------------------------------------------------------*/ +void convers_init(void) +{ + char tmp[82]; + int pl; + char *cp; + + time(&boottime); + currtime = boottime; + sprintf(myrev, "PP-%4.4st", strchr(REV, ':')+2); + + callss2str(tmp, myid); /* SSID ja egal ... */ + strlwr(tmp); + myhostname = strdup(tmp); + + sprintf(tmp, "%sconvers.prs", textpath); + personalmanager(INIT, NULL, tmp); + +#ifdef USERPROFIL + InitProfilTAB(); +#endif /* USERPROFIL */ + + for (pl = 0; pl < MAXCVSHOST; pl++) + permarray[pl] = NULLPERMLINK; + + cvs_pc = 1; /* Debug-Kanal 32767 per Default eingeschaltet!! */ + + if ((cp = getenv("CONVERSD")) != NULL) { + while (*cp && *(cp+1) == ':') { + switch (*cp) { + case 'P': cvs_pc = atoi(cp+2); + break; + /*case 'x': cvs_xx = atoi(cp+2);*/ + } + while (*cp && *cp != ' ') + cp++; + while (*cp == ' ') + cp++; + } + } +} + +/*****************************************************************************/ +/* Freigeben der geschlossenen Verbindungen und Aufbau der Hostverbindungen */ +/*---------------------------------------------------------------------------*/ +void conversd() +{ + time(&currtime); + free_closed_connections(); + connect_permlinks(); + convers_output(); +} + +/************************************************************************/ +/* Convers-Daten-Uebergabe */ +/*----------------------------------------------------------------------*/ +BOOLEAN convers_input(MBHEAD *mhdp) +{ + char c; + char *ibuf; + WORD icnt; + + if (mhdp->mbgc >= mhdp->mbpc) + return(TRUE); + + do { +#ifndef L1IRC + if ((c = getchr(mhdp)) == '!') /* process !tnn commands */ + return(FALSE); +#else + if ((c = getchr(mhdp)) == '!') /* process !tnn commands */ + { + if (userpo->IrcMode == FALSE) + return(FALSE); + } +#endif /* L1IRC */ + + if (c == CR || c == LF) + continue; + + ibuf = cnvinbuf; + *ibuf++ = c; + icnt = 1; + while ( mhdp->mbgc < mhdp->mbpc + && (c = getchr(mhdp)) != CR + && c != LF +#ifdef __WIN32__ + && icnt < (short)sizeof(cnvinbuf) - 5) +#else + && icnt < sizeof(cnvinbuf) - 5) +#endif /* WIN32 */ + { + if (c == BS) { + if (icnt > 0) { + --ibuf; + --icnt; + } + } else if (c != ESC) { /* ESC ausfiltern */ + *ibuf++ = c; + ++icnt; + } + } + *ibuf = '\0'; + userpo->convers->received += icnt; + process_input(userpo->convers); + } + while (mhdp->mbgc < mhdp->mbpc && getlin(mhdp)); + + return(TRUE); +} +/************************************************************************/ +/* Convers-Daten-Ausgabe */ +/*----------------------------------------------------------------------*/ +void convers_output() +{ + CONNECTION *cp; + + if (!s_CVOUT) + return; + + s_CVOUT = FALSE; + + for (cp = connections; cp; cp = cp->next) + if (cp->mbout != NULL && cp->up != NULL) + cp->xmitted += cvs2tnn(cp); +} + +/**************************************************************************/ +/* Starten von convers oder Abfragen Userliste, sowie Editieren der Hosts */ +/*------------------------------------------------------------------------*/ +void ccpcvs() +{ + char name[8]; + char buffer[256]; + WORD i; + LONG channel = 0L; + CONNECTION *cp; + PERMLINK *p; + MBHEAD *mbp; +#ifdef CONVERS_LINKS + char call[10]; +#endif + + if (!ismemr()) /* kein Speicher mehr */ + return; + + if (userpo->convers != NULLCONNECTION) { /* !conv abfangen */ +#ifdef SPEECH + appenddirect(userpo->convers, speech_message(2)); +#else + appenddirect(userpo->convers, "*** You are already in convers-mode.\r"); +#endif + return; + } + + if ((cp = alloc_connection(userpo)) == NULLCONNECTION) { + puttfu("Convers"); + + return; + } + + skipsp(&clicnt, &clipoi); /* Abfangen der Nichtteilnehmerbefehle */ + *buffer = '\0'; + if (clicnt) { + switch (*clipoi) { + case 'o': /* Online */ + case 'O': + case 'c': /* CStat */ + case 'C': *buffer = '/'; + *(clipoi+clicnt) = '\0'; + strcpy(buffer+1, (char *) clipoi); + break; +#ifdef CONVERS_HOSTNAME + case 'm': + case 'M': + case 'h': + case 'H': *buffer = '/'; + *(clipoi+clicnt) = '\0'; + strcpy(buffer+1, (char *) clipoi); + break; +#endif + default: channel = nxtlong(&clicnt, &clipoi); + } + } + +#ifdef L1IRC + cp->IrcMode = userpo->IrcMode; +#endif /* L1IRC */ + userpo->convers = cp; + callss2str(name, usrcal); + strlwr(name); +#ifdef CONVERS_LINKS + strcpy(call,name); + strupr(call); +#endif + cp->type = CT_UNKNOWN; + cp->operator = userpo->sysflg ? 2 : 0; /* Sysop-Status durchreichen */ + +#ifdef CONV_CHECK_USER + { + CONNECTION *pP; + + if ((pP = CheckUserCVS(name)) != NULL) /* Pruefung auf Doppel-Login. */ + { /* Kein Login moeglich. */ +#ifdef L1IRC + if (cp->IrcMode == FALSE) +#endif /* L1IRC */ + { + mbp = getmbp(); +#ifdef SPEECH + putprintf(mbp, speech_message(114) + , pP->name + , pP->host); +#else + putprintf(mbp, "none login possible!\n" + "call %s is logged in at the host %s!\n" + , pP->name + , pP->host); +#endif /* SPEECH */ + prompt(mbp); + seteom(mbp); + return; + } + } + } +#endif /* CONV_CHECK_USER */ + + strcpy(cp->name, name); + strcpy(cp->host, myhostname); + +#ifdef CONVNICK + memset(cp->OldNickname, 0, sizeof(cp->OldNickname)); +#endif /* CONVNICK */ + + if (*buffer) { + putcvsstr(cp, "\r"); + strcpy(cnvinbuf, buffer); + } + else { + for (i = 0; i < MAXCVSHOST; i++) { /* besucht uns ein Host? */ + p = permarray[i]; +#ifdef CONVERS_LINKS + if (p == NUL) + break; + if ((!strcmp(p->cname, name)) || (cmpcal(p->call, strupr(call)))) +#else + if (p && !strcmp(p->cname, name)) +#endif + { + if (p->locked) { /* Wird sofort abgewehrt */ + userpo->convers = NULLCONNECTION; + connections = cp->next; + free(cp); + mbp = getmbp(); +#ifdef SPEECH + putstr(speech_message(5), mbp); +#else + putstr("Locked!\r", mbp); +#endif + prompt(mbp); + seteom(mbp); + return; + } + if (p->connection) /* die fliegen hier gleich raus */ + bye_command2(p->connection, "link reorg"); + p = update_permlinks(name, cp, 0); + if (p) { + p->waittime = 60; /* 60s Zeit zur /..host Eingabe */ + if (p->tries > 3) + p->waittime = 120; + p->retrytime = currtime + p->waittime; + } + userpo->convflag = 1; /* kam von aussen, kein recon in ccp */ + return; + } + } +#ifndef L1IRC + sprintf(cnvinbuf, "/NAME %s %ld\r", name, channel); +#else + if (cp->IrcMode == TRUE) + sprintf(cnvinbuf, "USER %s\r", name); + else + sprintf(cnvinbuf, "/NAME %s %ld\r", name, channel); +#endif /* L1IRC */ + } + + process_input(cp); + + if (*buffer) { /* Kommandoausgaben ausgeben cp abmelden */ + cvs2tnn(cp); + userpo->convers = NULLCONNECTION; + connections = cp->next; + free(cp); + mbp = getmbp(); + putchr(CR, mbp); + prompt(mbp); + seteom(mbp); + } +} + +/*------------------------------------------------------------------------*/ + +#else +#if !defined(__WIN32__) && !defined(__LINUX__) +#pragma warn -par +#endif + +BOOLEAN convers_input(MBHEAD *mhdp) +{ + if (mhdp->mbgc >= mhdp->mbpc) + return(TRUE); + + return(FALSE); +} + +void convers_init(void) +{ +} + +void conversd() +{ +} + +void convers_output() +{ +} + +void ccpcvs() +{ + inv_cmd(); +} +#if !defined(__WIN32__) && !defined(__LINUX__) +#pragma warn .par +#endif +#endif +/* End of $RCSfile$ */ diff --git a/src/file.c b/src/file.c new file mode 100755 index 0000000..579fb3d --- /dev/null +++ b/src/file.c @@ -0,0 +1,597 @@ +/************************************************************************/ +/* */ +/* ***** ***** */ +/* ***** ***** */ +/* ***** ***** */ +/* ***** ***** */ +/* *************** *************** */ +/* ***************** ***************** */ +/* *************** *************** */ +/* ***** ***** TheNetNode */ +/* ***** ***** Portable */ +/* ***** ***** Network */ +/* ***** ***** Software */ +/* */ +/* File src/file.c (maintained by: ???) */ +/* */ +/* This file is part of "TheNetNode" - Software Package */ +/* */ +/* Copyright (C) 1998 - 2008 NORD>ptr; st++) + if (fwrite(st->ptr, st->size, 1, fp) != 1) { + ret = FALSE; + break; + } + + if (ret == FALSE) + xprintf("*** %s.STA write error ***\n",cfgfile); + fclose(fp); /* File schliessen */ + return(ret); + } + xprintf("*** %s.STA open error ***\n",cfgfile); + return(FALSE); +} + +void fgetstr(char *str, int n, FILE *fp) +{ + char line[200+1], *c; + int i = min(n, 200); + + do if (fgets(line, 200, fp) == NULL) break; + while (*line == ';'); + + if ((c = strchr(line, '\n')) == NULL) + c = &line[i]; + *c = 0; + strcpy(str, line); +} + +static void fgetpath(char *path, FILE *fp) +{ + char line[MAXPATH+1]; + + fgetstr(line, MAXPATH, fp); + sscanf(line, "%s", path); + addslash(path); +} + +static void fgetcall(char *id, FILE *fp) +{ + char str[15]; + char *callp; + WORD cnt; + + fgetstr(str, 12, fp); + cnt = (WORD)strlen(str); + callp = (char *)&str; + getcal(&cnt, &callp, TRUE, id); +} + +/*----------------------------------------------------------------------*/ +/* Aktuelle Konfiguration laden. */ +/* */ +/* Rueckgabe: TRUE bei erfolgreichem Einladen */ +/* FALSE bei Fehler */ +/*----------------------------------------------------------------------*/ +BOOLEAN +load_configuration(void) +{ + FILE *fp; + char line[200]; +#ifdef AUTO_UPDATE + FILE *ofp; + int c; + BOOLEAN save_new = FALSE; +#endif + + sprintf(line, "%s%s.PAS", confpath, cfgfile); + fp = xfopen(line,"rt"); /* erstmal neue PAS versuchen */ +#ifdef AUTO_UPDATE + if (fp == NULL) /* existiert nicht?, also alte Version */ + { /* lesen und neue Version schreiben */ + save_new = TRUE; + sprintf(line, "%s%s.PAS", confpath, oldcfgfile); + fp = xfopen(line,"rt"); + } +#endif + if (fp != NULL) /* PAS File gefunden */ + { + fgetstr(line, 120, fp); /* Main Password */ + paswle = (UWORD)strlen(line); + + if (paswle > 5) { + paswle = min(paswle, 80); + xprintf("--- Length of Password: %d\n", paswle); + strncpy(paswrd, line, paswle); + } else + xprintf("*** WARNING: Password rejected (too short)\n"); + + fgetstr(pass, 80, fp); /* login password */ + + fgetstr(alias, L2CALEN, fp); /* ALIAS Node-ID */ + strncat(alias, " ", L2CALEN-strlen(alias)); + + fgetcall(myid, fp); /* Node callsign */ + cpyid(hostid, myid); + + fgetpath(textpath, fp); /* Text Path */ + +#ifdef CONFPATHFIX + strcpy(confpath,textpath); /* textpath -> confpath zuweisen. */ +#endif /* CONFPATHFIX */ + + fgetpath(textcmdpath, fp); /* TextCommandPath */ + fgetpath(userexepath, fp); /* UserEXE-Path */ + fgetpath(sysopexepath, fp); /* SysopEXE-Path */ +#ifdef PACSAT /* PACSAT-Path */ + fgetpath(pacsatpath, fp); +#endif +#ifdef AXIPR_HTML /* HTML-Path */ + fgetpath(htmlpath, fp); +#endif + +#ifdef MSGPATHFIX + strcpy(msgpath,textpath); + strcat(msgpath,"msg"); + addslash(msgpath); +#endif /* MSGPATHFIX */ + + fclose(fp); /* Datei schliessen */ +#ifdef AUTO_UPDATE + if (save_new) + save_configuration(); /* neue PAS schreiben, alte Konfiguration */ + + sprintf(line, "%s%s.TNB", textpath, cfgfile); /* neue TNB suchen */ + ofp = xfopen(line,"rt"); + if (ofp != NULL) /* neue TNB existiert schon - so lassen */ + fclose(ofp); + else /* neue TNB existiert noch nicht */ + { + ofp = xfopen(line,"wt"); /* neue TNB wird geschrieben */ + if (ofp != NULL) /* File offen */ + { + sprintf(line, "%s%s.TNB", textpath, oldcfgfile); /* alte TNB */ + fp = xfopen(line,"rt"); + if (fp == NULL) /* keine alte TNB gefunden! */ + fclose(ofp); + else + { + LOOP /* ok, TNB kopieren */ + { + c = fgetc(fp); + if (c == EOF) + break; + fputc(c, ofp); + } + fclose(fp); + fclose(ofp); + } + } + } +#endif + return(TRUE); + } + save_configuration(); /* PAS ganz neu erzeugen */ + + return(FALSE); +} + +/*----------------------------------------------------------------------*/ +/* Aktuelle Statistik-Daten laden. */ +/* */ +/* Rueckgabe: TRUE bei erfolgreichem Einladen */ +/* FALSE bei Fehler */ +/*----------------------------------------------------------------------*/ +BOOLEAN load_stat(void) +{ + FILE *fp; /* File-Pointer */ + LONG filelength; /* Laenge von CONFIG.NET */ + BOOLEAN ret = TRUE; /* Returnwert */ + char file[MAXPATH+1]; /* Puffer fuer Filenamen */ + STATAB *st; + long l = 0; + + STAT *statp; + + sprintf(file, "%s%s.STA", confpath, cfgfile); + + if ((fp = xfopen(file,"rb")) != NULL) /* File oeffnen */ + { + for (st = statab; st->ptr; st++) + l += st->size; + + fseek(fp, 0L, SEEK_END); /* Dateilaenge ermitteln */ + filelength = ftell(fp); + rewind(fp); + + if (filelength != (LONG) l) { /* Stimmt Dateilaenge? */ + ret = FALSE; + xprintf("*** %s.STA has wrong size ***\n", cfgfile); + } + else { /* Laenge stimmt */ + for (st = statab; st->ptr; st++) + if (fread(st->ptr, st->size, 1, fp) != 1) { + ret = FALSE; + break; + } + } + for (statp = mh; statp < mh + MAXSTAT; statp++) + if (statp->call[0] == ' ') + statp->call[0] = '\0'; + fclose(fp); /* Datei schliessen */ + return(ret); + } + /* TNN???.STA konnte nicht geoeffnet werden */ + xprintf("*** %s.STA - open error ***\n", cfgfile); + return(FALSE); +} + +/*----------------------------------------------------------------------*/ +/* */ +/* An einen Verzeichnisnamen das letzte Slash anfuegen. Es wird das */ +/* fuer das jeweilige Dateisystem passende Symbol genommen. Der Name */ +/* wird gleichzeitig normiert. */ +/* */ +/*----------------------------------------------------------------------*/ +void addslash(char *path) +{ + char *p = path; + + normfname(path); /* den Namen normieren */ + + /* jetzt koennen wir einfach FILE_SEP verwenden, da normfname() */ + /* einen abweichenden Syntax bereits korrigiert hat. */ + if (!*path || *((p = path + strlen(path)) - 1) != FILE_SEP) { + *p++ = FILE_SEP; + *p = '\0'; + } +} + +/**************************************************************************/ +/* Sonst kriegt DOS die Panik ... */ +/*------------------------------------------------------------------------*/ +#ifdef PC +BOOLEAN good_file_name(const char *file) + { + if ( (strnicmp(file, "CON", 3) == 0) + || (strnicmp(file, "COM1", 4) == 0) + || (strnicmp(file, "COM2", 4) == 0) + || (strnicmp(file, "COM3", 4) == 0) + || (strnicmp(file, "COM4", 4) == 0) + || (strnicmp(file, "LPT1", 4) == 0) + || (strnicmp(file, "LPT2", 4) == 0) + || (strnicmp(file, "LPT3", 4) == 0) + || (strnicmp(file, "LPT4", 4) == 0) + || (strnicmp(file, "AUX", 3) == 0) + || (strnicmp(file, "PRN", 3) == 0) + || (strnicmp(file, "NUL", 3) == 0) + || (strnicmp(file, "CLOCK$", 6) == 0) + ) + return(FALSE); + else return(TRUE); + } +#endif + +/*----------------------------------------------------------------------*/ +/* */ +/* Einen Dateinamen normieren, d.h. er wird den Gegenheiten des */ +/* verwendeten Dateisystems angepasst. Die Informationen hierfuer */ +/* werden in ALL.H festgelegt. */ +/* */ +/*----------------------------------------------------------------------*/ +char *normfname(char *filename) +{ + char *s; /* Zeiger innerhalb des Namens */ + + for (s = filename; *s; s++) /* alle Zeichen im String durchgehen */ + if (strchr(SEPARATORS, *s)) /* ein Dateitrennungszeichen ? */ + *s = FILE_SEP; /* dann durch das richtige ersetzen */ +#if (FILE_FLAGS & FF_LWR) + strlwr(filename); /* eventuell in Kleinschreibung... */ +#endif + return(filename); +} + +/*----------------------------------------------------------------------*/ +/* */ +/* Wechelt das aktuelle Arbeitsverzeichniss. Der Name wird normiert. */ +/* */ +/*----------------------------------------------------------------------*/ +#ifndef MC68302 +int xchdir(const char *path) +{ + char tmppath[MAXPATH+1]; + static char oldp[MAXPATH+1]; +#ifndef NO_DISKDRIVE + static WORD odrv; +#endif + + if (path) { + strcpy(tmppath, path); + normfname(tmppath); + if (tmppath[strlen(tmppath)-1] == FILE_SEP) + tmppath[strlen(tmppath)-1] = '\0'; +#ifndef NO_DISKDRIVE + odrv = getdisk(); + if (*(tmppath+1) == ':') + setdisk((*tmppath & 0xDF) - 'A'); + getcwd(oldp, MAXPATH); +#endif + chdir(tmppath); + } + else { + chdir(oldp); +#ifndef NO_DISKDRIVE + setdisk(odrv); +#endif + } + return(0); +} +#endif + +#ifndef MC68K /* der ATARI kocht da anders */ +/*----------------------------------------------------------------------*/ +/* */ +/* Feststellen, ob eine Datei existiert. */ +/* */ +/*----------------------------------------------------------------------*/ +int xaccess(const char *filename, int amode) +{ + char fname[MAXPATH+1]; + + strcpy(fname, filename); /* umkopieren, den Originalnamen */ + normfname(fname); /* nicht anfassen */ + return(access(fname, amode)); +} +#else +int xaccess(const char *filename, int amode) +{ + struct ffblk ffblk; + char fname[MAXPATH+1]; + + strcpy(fname, filename); /* umkopieren, den Originalnamen */ + normfname(fname); /* nicht anfassen */ + return(findfirst(fname, &ffblk, 0)); +} +#endif + +/* wird in os/linux/linux.c erledigt */ +#if !defined(__LINUX__) && !defined(__WIN32__) +/*----------------------------------------------------------------------*/ +/* */ +/* Die Suche nach einer bestimmten Datei beginnen. Fortsetzen mit */ +/* xfindnext(). */ +/* */ +/*----------------------------------------------------------------------*/ +int xfindfirst(const char *pathname, struct ffblk *ffblk, int attrib) +{ + char fname[MAXPATH+1]; + + strcpy(fname, pathname); /* umkopieren, den Originalnamen */ + normfname(fname); /* nicht anfassen */ + return(findfirst(pathname, ffblk, attrib)); +} + +/*----------------------------------------------------------------------*/ +/* */ +/* Die Suche nach einer bestimmten Datei fortsetzen. */ +/* */ +/*----------------------------------------------------------------------*/ +int xfindnext(struct ffblk *ffblk) +{ + return(findnext(ffblk)); +} + +#endif /* WIN32 */ + +/*----------------------------------------------------------------------*/ +/* */ +/* Eine Datei oeffnen, es wird darauf geachtet, dass einige Betriebs- */ +/* systeme zwischen Textdateien und Binaerdateien unterscheiden. */ +/* normfname() wird zur Normierung des Dateinamens benutzt. */ +/* */ +/*----------------------------------------------------------------------*/ +FILE *xfopen(const char *filename, const char *mode) +{ + char fmode[4], *fm; /* der angepasste Datei-Mode */ + char fname[MAXPATH+1]; + +#ifndef MC68K + if (!good_file_name(filename)) + return(NULL); +#endif + + strcpy(fname, filename); /* umkopieren, den Originalnamen */ + normfname(fname); /* nicht anfassen */ + + fm = fmode; + if (strchr(mode, 'w')) /* zum Schreiben */ + *fm++ = 'w'; + else if (strchr(mode, 'a')) /* zum Anhaengen */ + *fm++ = 'a'; + else + *fm++ = 'r'; /* sonst zum Lesen oeffnen */ +#if (FILE_FLAGS & FF_TXT) /* b/t-Flag uebernehmen? */ + if (strchr(mode, 'b')) /* eine Binaer-Datei? */ + *fm++ = 'b'; /* ... Flag uebernehmen */ +#ifndef MC68K + if (strchr(mode, 't')) /* eine Text-Datei? */ + *fm++ = 't'; /* ... Flag uebernehmen */ +#endif +#endif + if (strchr(mode, '+')) /* Ueberschreiben? */ + *fm++ = '+'; + + *fm = NUL; /* String terminieren */ + return(fopen(fname, fmode)); /* Datei oeffnen */ +} + +/*----------------------------------------------------------------------*/ +/* */ +/* Eine Datei loeschen, es werden ALLE Dateien geloescht (auch RDONLY) */ +/* normfname() wird zur Normierung des Dateinamen benutzt. */ +/* */ +/*----------------------------------------------------------------------*/ +int xremove(const char *filename) +{ + char fname[MAXPATH+1]; + + strcpy(fname, filename); /* umkopieren, den Originalnamen */ + normfname(fname); /* nicht anfassen */ + return(remove(fname)); +} + +/*----------------------------------------------------------------------*/ +/* */ +/* Eine Datei umbenennen. */ +/* normfname() wird zur Normierung des Dateinamens benutzt. */ +/* */ +/*----------------------------------------------------------------------*/ +int xrename(const char *oldname, const char *newname) +{ + char fname[MAXPATH+1]; + char fname2[MAXPATH+1]; + + strcpy(fname, oldname); /* umkopieren, den Originalnamen */ + normfname(fname); /* nicht anfassen */ + strcpy(fname2, newname); /* umkopieren, den neuen Namen */ + normfname(fname2); /* nicht anfassen */ + return(rename(fname,fname2)); +} + +/* End of src/file.c */ diff --git a/src/global.c b/src/global.c new file mode 100755 index 0000000..7e79c48 --- /dev/null +++ b/src/global.c @@ -0,0 +1,534 @@ +/************************************************************************/ +/* */ +/* ***** ***** */ +/* ***** ***** */ +/* ***** ***** */ +/* ***** ***** */ +/* *************** *************** */ +/* ***************** ***************** */ +/* *************** *************** */ +/* ***** ***** TheNetNode */ +/* ***** ***** Portable */ +/* ***** ***** Network */ +/* ***** ***** Software */ +/* */ +/* File src/global.c (maintained by: ???) */ +/* */ +/* This file is part of "TheNetNode" - Software Package */ +/* */ +/* Copyright (C) 1998 - 2008 NORD> Ziel */ + {&save_timer, 0, 0x7FFF, "SaveConfig"}, /* Config-File sichern *10min */ + {&DamaSpeedFactor,0, 9600, "DAMA-Speedf"}, + {&dama_max, 0, 30, "DAMA-MaxPri"}, + {&MaxPollCnt, 0, 255, "DAMA-MaxPol"}, /* Maximale Userpolls.. */ + {&dama_init, 0, 1000, "DAMA-Tout"}, + {&proto, 0, 2, "CommandLog"}, + {&syspro_flag, 0, 1, "SysopLog"}, + {&testid, 0, 15, "TestSSID"}, + {&convid, 0, 15, "ConvSSID"}, + {&autoipr, 0, 3, "AutoIPR"} /* automatische INP IP-Routen */ + +#ifdef TIMEOUT_MANUELL + ,{&ininat, 60, 54000, "Timeout"} /* MANUELL: TIMEOUT */ +#endif /* TIMEOUT_MANUELL */ + +#ifdef MH_LISTE + ,{&MHdefault, 0, 1,"MH-Default"} /* Auswahl zwischen TNN und Flexnet-Stil */ + ,{&MHlen, 5, 100,"MH-len"} /* Laenge der MH-Liste */ +#endif + +#ifdef BEACON_STATUS + ,{&statustim,300L, 3600L,"Statusbake"} /* hiermit kann man die Aussendung */ + /* der Statusbake steuern. */ +#endif /* (Standard: aller 5min. Aussend.)*/ +#ifdef EXPERT + ,{&worqua, 0, 255, "Min-Quality"}, /* min Qualiatet Autoupdate */ + {&max_lt, 5, 50, "L3-MaxLT"}, + {&broint_i, 6, 960, "Infocast"}, /* Rundspruchintervall in 10s */ + {&broint_ui, 1, 240, "Broadcast"}, /* Rundspruchintervall in 10s */ + {&timliv, 4, 127, "Lifetime"}, /* Anfangswert Pktlebensdauer */ + {&trawir, 4, 127, "T-Window"}, /* Fenstergroesse in Level4 */ +#ifndef PORT_MANUELL + {&paclen, 36, 256, "Paclen"}, /* Paketlaenge */ +#endif /* PORT_MANUELL */ + {&l4_beta3, 1, 1000, "L4-Bsytim"}, + {&l4_beta1, 1, 1000, "L4-Retrans"}, + {&l4_beta2, 1, 1000, "L4-Acktim"} +#endif +#ifdef L2PROFILER + ,{&dmagic, 0, 0xFFFF, "unused"} /* */ +#endif +}; + +int partablen = (int)(sizeof(partab)/sizeof(PARAM)); + +/*-------------------------------------------------------- Befehlstabelle */ +COMAND cmdtab[] = { + {"?", (void (*)) ccphelp, "?" }, + {"A", (void (*)) NULL, NULL}, +#ifdef ALIASCMD + {"ALIAS", (void (*)) ccpalias, NULL}, +#endif +#ifdef IPROUTE + {"ARP", (void (*)) ccparp, NULL}, +#endif +#if defined(__LINUX__) || defined(__WIN32__) && defined(AX25IP) + {"AXIPR", (void (*)) ccpaxipr, NULL}, +#endif +#if (defined(__LINUX__) || defined(__WIN32__)) && defined(ATTACH) + {"ATTACH", (void (*)) ccpattach,NULL}, +#endif + {"//ECHO", (void (*)) ccpecho, NULL}, + {"BYE", (void (*)) ccpquit, NULL}, +#ifdef PACSAT + {"BOX", (void (*)) ccpbox, NULL}, +#endif + {"BEACON", (void (*)) ccpbea, NULL}, +#ifdef BUFFER_DEBUG + {"BUFFER", (void (*)) ccpbuf, NULL}, +#endif + {"CONNECT", (void (*)) ccpcon, NULL}, + {"C!", (void (*)) ccpcon, "NO"}, + {"CLEAR", (void (*)) ccpclr, NULL}, + {"CONVERS", (void (*)) ccpcvs, NULL}, + {"CQ", (void (*)) ccpcq, NULL}, +#if defined(MC68302) || defined(__WIN32__) + {"COPY", (void (*)) ccpcopy, NULL}, +#endif /* WIN32 */ + {"DEST", (void (*)) ccpdest, NULL}, + {"DATE", (void (*)) ccptim, NULL}, +#if (defined(__LINUX__) || defined(__WIN32__)) && defined(ATTACH) + {"DETACH", (void (*)) ccpdetach,NULL}, +#endif +#if defined(MC68302) || defined(__WIN32__) + {"DELETE", (void (*)) ccpdelete,NULL}, + {"DIR", (void (*)) ccpdir, NULL}, +#endif /* WIN32 */ +#ifndef MC68302 + {"DOS", (void (*)) ccpshell, NULL}, +#endif + {"DCD", (void (*)) ccpdcd, NULL}, + {"DXCLUSTER",(void (*)) ccpdxc, NULL}, + {"EDIT", (void (*)) ccpedi, NULL}, + {"ESC", (void (*)) ccpesc, NULL}, +#ifdef GRAPH + {"GRAPH", (void (*)) ccpgraph, NULL}, +#endif + {"HELP", (void (*)) ccphelp, NULL}, + {"HARDWARE", (void (*)) NULL, NULL}, +#ifdef L1HTTPD + {"HTTPD", (void (*)) ccphttpd, NULL}, +#endif /* L1HTTPD */ + {"INFO", (void (*)) NULL, NULL}, +#ifdef IPROUTE + {"IPADDR", (void (*)) ccpipa, NULL}, +#if 0 + {"IPBCST", (void (*)) ccpipb, NULL}, /* IPB ist gesperrt! */ +#endif +#ifdef L1IPCONV + {"IPCONVERS",(void (*)) ccpipconv,NULL}, +#endif /* L1IPCONV */ + {"IPROUT", (void (*)) ccpipr, NULL}, +#endif +#ifdef L1IRC + {"IRC", (void (*)) ccpirc, NULL}, +#endif /* L1IRC */ +#ifdef KERNELIF + {"KERNELIF", (void (*)) ccpkif, NULL}, +#endif + {"KILL", (void (*)) ccpkill, NULL}, + {"LINKS", (void (*)) ccplnk, NULL}, + {"L3MHEARD", (void (*)) ccpl3mh, NULL}, + {"LOAD", (void (*)) ccpload, NULL}, +#ifdef THENETMOD + {"L4PARMS", (void (*)) ccpL4par, NULL}, +#endif /* THENETMOD */ + {"MAILBOX", (void (*)) ccpmail, NULL}, + {"MHEARD", (void (*)) ccpl2mh, NULL}, +#ifdef USER_MONITOR + {"MONITOR", (void (*)) ccptrace, NULL}, +#endif /* USER_MONITOR */ +#ifdef HOSTMYCALL + {"MYHOST", (void (*)) ccpmyhost,NULL}, +#endif /* HOSTMYCALL */ + {"NODES", (void (*)) ccpnod, NULL}, + {"NEWS", (void (*)) NULL, NULL}, +#ifdef PARMS_PORTMOD + {"PORT", (void (*)) ccpport, NULL}, +#else + {"PARMS", (void (*)) ccppar, NULL}, +#endif +#ifdef PARMS_PORTMOD + {"PARMS", (void (*)) ccppar, NULL}, +#else + {"PORT", (void (*)) ccpport, NULL}, +#endif +#ifdef PACSAT + {"PACSAT", (void (*)) ccppacsat,NULL}, +#endif +#ifdef PADDLE + {"PADDLE", (void (*)) ccppaddle,NULL}, +#endif +#ifdef IPROUTE + {"PING", (void (*)) ccpping, NULL}, +#endif + {"PROMPT", (void (*)) ccpprompt,NULL}, +#ifdef USERPROFIL + {"PROFIL", (void (*)) ccpprofil,NULL}, +#endif /* USERPROFIL */ +#ifdef PROFILING + {"PROFILE", (void (*)) ccp_profile,NULL}, +#endif + {"QUIT", (void (*)) ccpquit, NULL}, + {"ROUTES", (void (*)) ccprou, NULL}, + {"READ", (void (*)) ccpread, NULL}, + {"READBIN", (void (*)) ccpreadb, NULL}, + {"RESET", (void (*)) ccpres, NULL}, + {"RUNBATCH", (void (*)) ccprun, NULL}, + {"STAT", (void (*)) ccpsta, NULL}, +#ifndef MC68302 + {"SHELL", (void (*)) ccpshell, NULL}, +#endif +#ifdef __LINUX__ + {"SETSHELL", (void (*)) ccpsetshell, NULL}, +#endif + {"SPARAM", (void (*)) ccpsave, NULL}, +#ifdef SPEECH + {"SPEECH", (void (*)) ccpspeech,NULL}, +#endif + {"SYSOP", (void (*)) ccpsys, NULL}, +#ifdef SYSOPPASSWD + {"SYSPASS", (void (*)) ccppasswd ,NULL}, +#endif /* SYSOPPASSWD */ + {"START", (void (*)) ccpstart, NULL}, + {"SUSPEND", (void (*)) ccpsusp, NULL}, + {"TALK", (void (*)) ccptalk, NULL}, + {"TEST", (void (*)) ccptst, NULL}, +#ifdef L1TELNET + {"TELNET", (void (*)) ccptelnet,NULL}, +#endif /* L1TELNET */ + {"TIME", (void (*)) ccptim, NULL}, + {"TRACE", (void (*)) ccptrace, NULL}, + {"USER", (void (*)) ccpuse, NULL}, + {"VERSION", (void (*)) ccpver, NULL}, +#if defined(__LINUX__) && defined(SIXPACK) + {"6PACK", (void (*)) ccp6pack, NULL}, +#endif + {NULL, NULL, NULL} +}; + +/*-------------------------------------- Befehlstabelle fuer Sysop-Kanal*/ +COMAND syscmdtab[] = { + {"SYSOP", (void (*)) ccpsys, NULL}, + {NULL, NULL, NULL} +}; + +/*-------------------------------------------------------- L1 Portmodes */ +L1MODETAB l1modetab[] = +{ +#ifdef PORT_SYNRONATION + {'s' , MODE_ss}, +#endif +#ifdef PORT_SUSPEND + {'l' , MODE_l}, +#endif + {'d' , MODE_d}, + {'c' , MODE_c}, + {'r' , MODE_r}, + {'t' , MODE_t}, + {'e' , MODE_e}, + {'m' , MODE_m}, + {'z' , MODE_z}, + {'\0', 0 } +}; + +/*----------------------------------------------------------- PP-CONVERSD */ + +/* Variable fuer conversd */ +const char *convtype = "conversd"; +#ifdef CONVNICK +const char *myfeatures = "Admpun"; +#else + const char *myfeatures = "Admpu"; +#endif +WORD cvs_pc; /* Protokoll auf Kanal 32767 */ +time_t boottime; +time_t currtime; +char *myhostname; +char myrev[10]; +char timestamp[16]; +CONNECTION *connections; +PERMLINK *permarray[MAXCVSHOST]; +DESTINATION *destinations; +CHANNEL *channels; + +/*----------------------------------- Befehlstabelle (BEFEHLSINTERPRETER) */ +HOSTCMD hostcmdtab[] = { + {"@", extcmd}, + {"B", Bcmd}, + {"C", Ccmd}, + {"D", Dcmd}, + {"E", Ecmd}, + {"G", Gcmd}, + {"I", Icmd}, + {"J", Jcmd}, + {"K", Kcmd}, + {"L", Lcmd}, + {"M", Mcmd}, + {"Q", Qcmd}, + {"R", Rcmd}, + {"S", Scmd}, + {"T", Tcmd}, + {"Y", Ycmd}, + {"V", Vcmd}, + {0, NULL} +}; + +time_t start_time; +time_t clear_time; + +FILE *consfile; + +ULONG bytecnt; +UWORD crctab[256]; /* crc-Tabelle fuer program_load() */ +UWORD crc; /* crc fuer program_load() */ +ULONG checksum; /* checksumme fuer program_load() */ + +/* Variable fuer L7.C */ +ULONG lastic; + +/* Variable fuer L7MONI.C */ +WORD stamp; + +/* Variable fuer TIMER.C */ +volatile ULONG tic10; + +/* Variable fuer Crash_Debugging */ +#if defined(CRASHDEBUG) || defined(__LINUX__) +char *wowarich; +char *wowarich2; +#endif + +BOOLEAN startup; +BOOLEAN tnnb_aktiv; +ULONG MEMORY_NEEDED = 0x2ff00L / sizeof(MAX_BUFFER); +time_t sys_time; +struct tm *sys_localtime; + +#ifdef BEACON_STATUS +UWORD statustim = 300L; +#endif + +#ifdef AXIPR_UDP +BOOLEAN LookAX25IP = FALSE; /* Wir durfen keine Frame lesen. */ +#endif /* AXIPR_UDP */ + +#ifdef DEBUG_MODUS +char lastbuf[80]; +char *lastfunc = lastbuf; +#endif /* DEBUG_MODUS */ + +/* End of src/global.c */ diff --git a/src/graph.c b/src/graph.c new file mode 100755 index 0000000..c83ca38 --- /dev/null +++ b/src/graph.c @@ -0,0 +1,1226 @@ +/************************************************************************/ +/* */ +/* ***** ***** */ +/* ***** ***** */ +/* ***** ***** */ +/* ***** ***** */ +/* *************** *************** */ +/* ***************** ***************** */ +/* *************** *************** */ +/* ***** ***** TheNetNode */ +/* ***** ***** Portable */ +/* ***** ***** Network */ +/* ***** ***** Software */ +/* */ +/* File src/graph.c (maintained by: DG9AML) */ +/* */ +/* This file is part of "TheNetNode" - Software Package */ +/* */ +/* Copyright (C) 1998 - 2008 NORD>hour[graph.hour_pos] = dummy; + break; + case GRAPH_DAY: + selected->day[graph.day_pos] = dummy; + break; + case GRAPH_WEEK: + selected->week[graph.week_pos] = dummy; + } /* switch */ +} + +#ifdef PORTGRAPH +void +graph_clear_trxpeak(TPORTGRAPHELEMENT *selected, int timesel) +{ + TPORTGRAPHPEAK dummy; + + dummy.rx = + dummy.tx = MAXULONG; + + switch (timesel) + { + case GRAPH_HOUR: + selected->hour[graph.hour_pos] = dummy; + break; + case GRAPH_DAY: + selected->day[graph.day_pos] = dummy; + break; + case GRAPH_WEEK: + selected->week[graph.week_pos] = dummy; + } /* switch */ +} +#endif + +void +graph_clear_element(int timesel, int clearmode) +{ +#ifdef PORTGRAPH + int i; +#endif + + graph_clear_peak(&graph.freebuffer, timesel,clearmode); + graph_clear_peak(&graph.circuit, timesel,clearmode); + graph_clear_peak(&graph.l2link, timesel,clearmode); + graph_clear_peak(&graph.node, timesel,clearmode); + graph_clear_peak(&graph.roundpsec, timesel,clearmode); + graph_clear_peak(&graph.throughput, timesel,clearmode); +#ifdef PORTGRAPH + for (i = 0; i < L2PNUM; i++) + { + graph_clear_trxpeak(&graph.info[i], timesel); + graph_clear_trxpeak(&graph.reject[i], timesel); + graph_clear_trxpeak(&graph.frmr[i], timesel); + graph_clear_trxpeak(&graph.sabm[i], timesel); + graph_clear_trxpeak(&graph.disc[i], timesel); + graph_clear_trxpeak(&graph.dm[i], timesel); + } +#endif +} + +void +graph_actual_longint(TGRAPHPEAK *selected, ULONG newvalue) +{ + if (selected->max < newvalue) + selected->max = newvalue; + if (selected->min > newvalue) + selected->min = newvalue; + selected->ave += newvalue; +} + +void +graph_actual_peak(TGRAPHELEMENT *selected, ULONG newvalue) +{ + graph_actual_longint(&selected->hour[graph.hour_pos], newvalue); + graph_actual_longint(&selected->day[graph.day_pos], newvalue); + graph_actual_longint(&selected->week[graph.week_pos], newvalue); +} + +#ifdef PORTGRAPH +void +graph_actual_trxpeak(TPORTGRAPHELEMENT *selected, BOOLEAN tx) +{ + if (graph.enabled == TRUE) + { + if (tx) + { + if (selected->hour[graph.hour_pos].tx == MAXULONG) + selected->hour[graph.hour_pos].tx = 0; + if (selected->day[graph.day_pos].tx == MAXULONG) + selected->day[graph.day_pos].tx = 0; + if (selected->week[graph.week_pos].tx == MAXULONG) + selected->week[graph.week_pos].tx = 0; + selected->hour[graph.hour_pos].tx++; + selected->day[graph.day_pos].tx++; + selected->week[graph.week_pos].tx++; + } + else + { + if (selected->hour[graph.hour_pos].rx == MAXULONG) + selected->hour[graph.hour_pos].rx = 0; + if (selected->day[graph.day_pos].rx == MAXULONG) + selected->day[graph.day_pos].rx = 0; + if (selected->week[graph.week_pos].rx == MAXULONG) + selected->week[graph.week_pos].rx = 0; + selected->hour[graph.hour_pos].rx++; + selected->day[graph.day_pos].rx++; + selected->week[graph.week_pos].rx++; + } + } +} +#endif + +void +graph_actual_element(void) +{ + graph_actual_peak(&graph.freebuffer, nmbfre); + graph_actual_peak(&graph.circuit, nmbcir); + graph_actual_peak(&graph.l2link, nmblks); + graph_actual_peak(&graph.node, (ULONG)netp->num_nodes); + graph_actual_peak(&graph.roundpsec, (ULONG)rounds_pro_sec); + graph_actual_peak(&graph.throughput, thbps * 8L); +} + +void +graph_average_peak(TGRAPHELEMENT *selected, int timesel) +{ + switch (timesel) + { + case GRAPH_HOUR: + if (graph.hour_slot > 0) + { + selected->hour[graph.hour_pos].ave /= graph.hour_slot; + } + break; + case GRAPH_DAY: + if (graph.day_slot > 0) + { + selected->day[graph.day_pos].ave /= graph.day_slot; + } + break; + case GRAPH_WEEK: + if (graph.week_slot > 0) + { + selected->week[graph.week_pos].ave /= graph.week_slot; + } + } /* switch */ +} + +void +graph_average(int timesel) +{ + graph_average_peak(&graph.freebuffer, timesel); + graph_average_peak(&graph.circuit, timesel); + graph_average_peak(&graph.l2link, timesel); + graph_average_peak(&graph.node, timesel); + graph_average_peak(&graph.roundpsec, timesel); + graph_average_peak(&graph.throughput, timesel); +} + + +/************************************************************************/ +/* Funktion graphclear(void) */ +/* */ +/* loescht die Graphdaten */ +/************************************************************************/ +void +graphclear(void) +{ + for (graph.hour_pos = 0; + graph.hour_pos < GRAPH_STD_ELEMENTS; + graph.hour_pos++) + graph_clear_element(GRAPH_HOUR,1); + for (graph.day_pos = 0; + graph.day_pos < GRAPH_DAY_ELEMENTS; + graph.day_pos++) + graph_clear_element(GRAPH_DAY,1); + for (graph.week_pos = 0; + graph.week_pos < GRAPH_WEK_ELEMENTS; + graph.week_pos++) + graph_clear_element(GRAPH_WEEK,1); + + graph.hour_pos = 0; + graph.day_pos = 0; + graph.week_pos = 0; + graph.hour_slot = 0; + graph.day_slot = 0; + graph.week_slot = 0; + + graph.enabled = FALSE; /* wird nach einer Minute auf TRUE gesetzt */ +} + +/************************************************************************/ +/* GRAPH */ +/* */ +/* Funktion: zeigt einen Textgraphen an. */ +/************************************************************************/ +void +ccpgraph(void) +{ + MBHEAD *mbp; + int timesel = 0, + expand = 0; + char selchr = 0; + char timestr[6], + selstr[6], + prestr[6], + expandstr[6]; +#ifdef PORTGRAPH + int port = 0, + portfound = 0; + char portstr[6]; +#endif + char prechar[3] = "#*+"; /* Presentationchar des Graphen */ + + mbp = getmbp(); + putchr('\r', mbp); + + /* nur der Sysop darf Daten loeschen */ + if (issyso() && strnicmp((char *)clipoi, "CLEAR", 5) == 0) + { + graphclear(); +#ifdef SPEECH + putstr(speech_message(133), mbp); +#else + putstr("Graph cleared!\r", mbp); +#endif + prompt(mbp); + seteom(mbp); + return; + } + clipoi[clicnt] = NUL; +#ifdef PORTGRAPH + portstr[0] = NUL; +#endif + timestr[0] = NUL; + selstr[0] = NUL; + prestr[0] = NUL; + expandstr[0] = NUL; +#ifdef PORTGRAPH + sscanf((char *) clipoi, "%5s %5s %5s %5s %5s", + portstr, + timestr, + selstr, + prestr, + expandstr); + /* ueberpruefen, ob portgraph oder graph gewaehlt wurde */ + if (sscanf(portstr, "%d", &port) == 1) + { /* Portangabe gefunden */ + portfound = 1; + strcpy(prechar, """TR"""); + } + else + { + strcpy(expandstr, prestr); + strcpy(prestr, selstr); + strcpy(selstr, timestr); + strcpy(timestr, portstr); + } +#else + sscanf((char *) clipoi, "%5s %5s %5s %5s", + timestr, + selstr, + prestr, + expandstr); +#endif + + /* Zeiteingabe ermitteln */ + switch (toupper(timestr[0])) + { + case 'H': + timesel = GRAPH_HOUR; + break; + case 'D': + timesel = GRAPH_DAY; + break; + case 'W': + timesel = GRAPH_WEEK; + break; + default: + timesel = 0; + } + + /* Falls Zeiteingabe weggelassen wurde, ist GRAPH_HOUR aktuell */ + if (!timesel) + { + timesel = GRAPH_HOUR; + strcpy(expandstr, prestr); + strcpy(prestr, selstr); + strcpy(selstr, timestr); + } + + selchr = toupper(selstr[0]); + + /* Darstellungszeichen ermitteln */ +#ifdef PORTGRAPH + if (portfound) + { + if (strlen(prestr) == 4 && prestr[0] == '"' && prestr[3] == '"') + { + prechar[0] = prestr[1]; + prechar[1] = prestr[2]; + } + else + strcpy(expandstr, prestr); + } + else + { +#endif + if (strlen(prestr) == 5 && prestr[0] == '"' && prestr[4] == '"') + { + prechar[0] = prestr[1]; + prechar[1] = prestr[2]; + prechar[2] = prestr[3]; + } + else + strcpy(expandstr, prestr); +#ifdef PORTGRAPH + } +#endif + /* Expandmode feststellen */ + if (strcmp(expandstr, "+") == 0) + expand = 1; + else + { + if (strlen(expandstr) != 0) + selchr = 0; + } +#ifdef PORTGRAPH + /* Die Portangabe pruefen */ + if (port < 0 || port >= L2PNUM) + { + selchr = 0; + } + + if (portfound) + { + switch (selchr) + { + case '*': + case 'I': + showportgraph(timesel, &graph.info[port], "Info frames", + port, prechar, mbp); + if (selchr != '*') + break; + case 'R': + showportgraph(timesel, &graph.reject[port], "Reject frames", + port, prechar, mbp); + if (selchr != '*') + break; + case 'F': + showportgraph(timesel, &graph.frmr[port], "FRMR frames", + port, prechar, mbp); + if (selchr != '*') + break; + case 'S': + showportgraph(timesel, &graph.sabm[port], "SABM frames", + port, prechar, mbp); + if (selchr != '*') + break; + case 'C': + showportgraph(timesel, &graph.disc[port], "DISC frames", + port, prechar, mbp); + if (selchr != '*') + break; + case 'M': + showportgraph(timesel, &graph.dm[port], "DM frames", + port, prechar, mbp); + break; + default: + selchr = 0; + } + } + else + { +#endif + switch (selchr) + { + case '*': + case 'B': + showgraph(timesel, &graph.throughput, "Throughput (Baud):", + prechar, expand, mbp); + if (selchr != '*') + break; + case 'F': + showgraph(timesel, &graph.freebuffer, "Free buffers:", + prechar, expand, mbp); + if (selchr != '*') + break; + case 'R': + showgraph(timesel, &graph.roundpsec, "Rounds per seconds:", + prechar, expand, mbp); + if (selchr != '*') + break; + case 'N': + showgraph(timesel, &graph.node, "Nodes:", prechar, expand, mbp); + if (selchr != '*') + break; + case 'C': + showgraph(timesel, &graph.circuit, "Circuits:", prechar, expand, mbp); + if (selchr != '*') + break; + case 'L': + showgraph(timesel, &graph.l2link, "L2-Links:", prechar, expand, mbp); + break; + default: + selchr = 0; + } +#ifdef PORTGRAPH + } +#endif + if (selchr == 0) + { +#ifdef PORTGRAPH +#ifdef SPEECH + putstr(speech_message(134),mbp); +#else + putstr("SYSTEMGRAPH:\r",mbp); +#endif +#endif +#ifdef SPEECH + putstr(speech_message(135), mbp); +#else + putstr("(G)raph (H)our (B)aud\r" + " (D)ay (C)ircuits\r" + " (W)eek (F)ree buffers\r" + " (L)2-Links\r" + " (N)odes\r" + " (R)ounds\r" + " (*) All\r", mbp); +#endif +#ifdef PORTGRAPH +#ifdef SPEECH + putstr(speech_message(136), mbp); + putstr(speech_message(137), mbp); +#else + putstr("PORTGRAPH:\r" + "(G)raph (H)our (I)nfo frames\r" + " (D)ay (R)eject frames\r" + " (W)eek (F)rmr frames\r" + " (S)abm frames\r" + " dis(C) frames\r" + " d(M) frames\r" + " (*) All\r", mbp); +#endif +#endif + } + prompt(mbp); + seteom(mbp); +} + +/************************************************************************/ +/* showportgraph() */ +/* */ +/* Funktion: Generiert einen Portgraph */ +/* */ +/* int timesel: GRAPH_HOUR: Ueberblick 1 Stunde */ +/* GRAPH_DAY: Ueberblick 24 Stunden */ +/* GRAPH_WEEK: Ueberblick 7 Tage */ +/* */ +/* TPORTGRAPHELEMENT select: Welcher Datenbestand ausgegeben werden soll*/ +/* */ +/* char *titel Ueberschrift des Diagrammes */ +/* */ +/* int port Portangabe (fuer Titel) */ +/* */ +/* char *presentation: Darstellung */ +/* */ +/* MBHEAD *mhp: Stringuebergabe */ +/************************************************************************/ +#ifdef PORTGRAPH +void +showportgraph(int timesel, TPORTGRAPHELEMENT *selected, const char *titel, + int port, char *prechar, MBHEAD *mbp) +{ + TPORTGRAPHPEAK peak[60]; /* 60 entspricht dem groessten Peak */ + /* Array aus TGRAPH */ + ULONG raster = 0L; /* noetig fuer Y-Achse (Werteachse) */ + ULONG werttrx, + werttx, + wertrx; + ULONG maximum, + minimum, + average; /* Maximalwerte von wertmax, wertmin,.. */ + WORD elements, + pos; + WORD averagenum; /* gibt belegte peak[] Anzahl an */ + int lines = GRAPH_LINES; + int i, + j; + int start_min, /* Fuer Anzeigeberechnung des Neustartes*/ + start_hour, + start_day; + time_t start_diff; + char zeile[128]; /* Leerzeilenballast entfernen */ + + switch (timesel) + { + case GRAPH_DAY: + elements = GRAPH_DAY_ELEMENTS; + for (i = 0; i < elements; i++) + peak[i] = selected->day[i]; + pos = graph.day_pos; + break; + case GRAPH_WEEK: + elements = GRAPH_WEK_ELEMENTS; + for (i = 0; i < elements; i++) + peak[i] = selected->week[i]; + pos = graph.week_pos; + break; + default: + elements = GRAPH_STD_ELEMENTS; + for (i = 0; i < elements; i++) + peak[i] = selected->hour[i]; + pos = graph.hour_pos; + } + + /* Titel uebergeben */ + putprintf(mbp, "%s (Port %u):", titel,port); + + /* Maximum,Mittel und Minimum Wert bestimmen */ + maximum = average = 0L; + minimum = MAXULONG; + averagenum = 0; + + for (i = 0; i < elements; i++) + { + werttrx = ((peak[i].rx == MAXULONG) ? 0 : peak[i].rx) + + ((peak[i].tx == MAXULONG) ? 0 : peak[i].tx); + if ( maximum < werttrx + && (peak[i].rx != MAXULONG || peak[i].tx != MAXULONG)) + maximum = werttrx; + if (minimum > werttrx) + minimum = werttrx; + if (peak[i].rx != MAXULONG || peak[i].tx != MAXULONG) + { + average += werttrx; + averagenum++; + } + } /* for elements */ + + if (minimum == MAXULONG) + minimum = 0; + if (maximum == MAXULONG) + maximum = 0; + if (maximum > 0) + putprintf(mbp, " Maximum: %lu", (ULONG)maximum); + if (averagenum > 0 && average > 0) +#ifdef SPEECH + putprintf(mbp, speech_message(127), (ULONG)average / averagenum); +#else + putprintf(mbp, " Average: %lu", (ULONG)average / averagenum); +#endif + putprintf(mbp, " Minimum: %lu\r\r", (ULONG)minimum); + + /* Zeilenraster ermitteln */ + raster = maximum / GRAPH_LINES; + if (raster == 0 || maximum % GRAPH_LINES > 0) + raster++; + + /* genaue Zeilenanzahl ermitteln */ + lines = maximum / raster; /* schwankt zwischen 5 und GRAPH_LINES */ + if (maximum % raster > 0) + lines++; + if (lines < 5) + lines = 5; /* min. sollen es 5 Zeilen sein */ + + lines++; + /* Die einzelnen Zeilen generieren */ + do + { + lines--; + zeile[0] = NUL; + putprintf(mbp, "%6lu|", (ULONG)raster * lines); + for (i = 0; i < elements; i++) + { + if (timesel == GRAPH_HOUR) + j = (i + pos + 1 >= GRAPH_STD_ELEMENTS) + ? pos + i + 1 - GRAPH_STD_ELEMENTS + : i + pos + 1; + else + j = i; + + wertrx = (peak[j].rx == MAXULONG) ? 0 : peak[j].rx; + werttx = (peak[j].tx == MAXULONG) ? 0 : peak[j].tx; + + if ((wertrx + werttx) >= raster * lines) + { + putstr(zeile, mbp); + if (werttx >= raster * lines) + /* Kontrollzeichen abfangen */ +#ifdef __WIN32__ + putchr((char)((prechar[0] < 32) ? 'T' : prechar[0]), mbp); +#else + putchr((prechar[0] < 32) ? 'T' : prechar[0], mbp); +#endif /* WIN32 */ + else +#ifdef __WIN32__ + putchr((char)((prechar[1] < 32) ? 'R' : prechar[1]), mbp); +#else + putchr((prechar[1] < 32) ? 'R' : prechar[1], mbp); +#endif /* WIN32 */ + zeile[0] = NUL; + } + else + strcat(zeile, " "); + } /* for itm_min; + start_hour = localtime(&start_time)->tm_hour; + start_day = (localtime(&start_time)->tm_wday != 0) + ? localtime(&start_time)->tm_wday - 1 + : 6; + start_diff = sys_time - start_time; + + for (i = 0; i < elements; i++) + { + j = (i + pos + 1 >= GRAPH_STD_ELEMENTS) + ? pos + i + 1 - GRAPH_STD_ELEMENTS + : i + pos + 1; + + if ( ( (timesel == GRAPH_DAY && i == graph.day_pos) + || (timesel == GRAPH_WEEK && i == graph.week_pos)) + && graph.enabled == TRUE) + putchr('A', mbp); + else + if ( ( timesel == GRAPH_HOUR + && graph.enabled == TRUE + && j == start_min + && start_diff < 3600 - 60) + || ( timesel == GRAPH_DAY + && i == 2 * start_hour + start_min / 30 + && start_diff < 86400 - 1800) + || ( timesel == GRAPH_WEEK + && i == 8 * start_day + start_hour / 3 + && start_diff < 604800 - 10800)) + putchr('N', mbp); + else + putchr('-', mbp); + } + switch (timesel) + { + case GRAPH_DAY: +#ifdef SPEECH + putprintf(mbp, speech_message(128), + " ", " "); +#else + putprintf(mbp, "\r%7s00 02 04 06 08 10 12 14 16 18 20 22\r" + "%9s01 03 05 07 09 11 13 15 17 19 21 23 Hour\r\r", + " ", " "); +#endif + break; + case GRAPH_WEEK: +#ifdef SPEECH + putprintf(mbp, speech_message(129), " ", " ", " "); +#else + putprintf(mbp, "\r%7s0 0 1 1 0 0 1 1 0 0 1 1 0 0" + " 1 1 0 0 1 1 0 0 1 1 0 0 1 1\r" + "%7s0 6 2 8 0 6 2 8 0 6 2 8 0 6 2" + " 8 0 6 2 8 0 6 2 8 0 6 2 8 h\r" + "%7sMonday Tuesday Wednes. Thursd." + " Friday Saturd. Sunday\r\r", " ", " ", " "); +#endif + break; + default: +#ifdef SPEECH + putprintf(mbp, speech_message(130), " "); +#else + putprintf(mbp, " Elap. time\r%6s-3600 -3240 -2880 -2520 -2160 " + "-1800 -1440 -1080 -720 -360 0 Seconds\r\r", " "); +#endif + } /* switch */ +} +#endif + +/************************************************************************/ +/* showgraph() */ +/* */ +/* Funktion: Generiert einen Graph */ +/* */ +/* int timesel: GRAPH_HOUR: Ueberblick 1 Stunde */ +/* GRAPH_DAY: Ueberblick 24 Stunden */ +/* GRAPH_WEEK: Ueberblick 7 Tage */ +/* */ +/* TGRAPHELEMENT select: Welcher Datenbestand ausgegeben werden soll */ +/* */ +/* char *titel Ueberschrift des Diagrammes */ +/* */ +/* char *presentation: 1. Char: Minimum Darstellung */ +/* 2. Char: Average Darstellung */ +/* 3. Char: Maximum Darstellung */ +/* */ +/* int expand: 0: Diagramm nicht strecken */ +/* 1: Diagramm zwischen Max und Min strecken */ +/* */ +/* MBHEAD *mhp: Stringuebergabe */ +/************************************************************************/ +void +showgraph(int timesel, TGRAPHELEMENT *selected, const char *titel, + char *prechar, int expand, MBHEAD *mbp) +{ + TGRAPHPEAK peak[60]; /* 60 entspricht dem groessten Peak */ + /* Array aus TGRAPH */ + ULONG raster = 0L; /* noetig fuer Y-Achse (Werteachse) */ + ULONG wertmax, + wertave, + wertmin; /* Werte aus peak[] */ + ULONG maximum, + minimum, + average; /* Maximalwerte von wertmax, wertmin,.. */ + ULONG expandwert; /* enthaelt minimum oder 0 */ + WORD lastline = 1; /* bei expand=1, 0. Zeile mit ausgeben */ + WORD elements, + slot, + pos; + WORD averagenum; /* gibt belegte peak[] Anzahl an */ + int lines = GRAPH_LINES; + int i, + j; + int start_min, /* Fuer Anzeigeberechnung des Neustartes */ + start_hour, + start_day; + time_t start_diff; + char zeile[128]; /* Leerzeilenballast entfernen */ + + switch (timesel) + { + case GRAPH_DAY: + elements = GRAPH_DAY_ELEMENTS; + for (i = 0; i < elements; i++) + peak[i] = selected->day[i]; + slot = graph.day_slot; + pos = graph.day_pos; + break; + case GRAPH_WEEK: + elements = GRAPH_WEK_ELEMENTS; + for (i = 0; i < elements; i++) + peak[i] = selected->week[i]; + slot = graph.week_slot; + pos = graph.week_pos; + break; + default: + elements = GRAPH_STD_ELEMENTS; + for (i = 0; i < elements; i++) + peak[i] = selected->hour[i]; + slot = graph.hour_slot; + pos = graph.hour_pos; + } + + /* Titel uebergeben */ + putprintf(mbp, "%s", titel); + + /* Maximum,Mittel und Minimum Wert bestimmen */ + maximum = average = 0L; + minimum = MAXULONG; + averagenum = 0; + + for (i = 0; i < elements; i++) + { + wertmax = peak[i].max; + wertave = (i != pos) ? peak[i].ave : (slot > 0) ? peak[i].ave / slot : 0; + wertmin = peak[i].min; + + if (maximum < wertmax && wertmax != MAXULONG) + maximum = wertmax; + if (minimum > wertmin) + minimum = wertmin; + if (wertave != MAXULONG) + { + average += wertave; + averagenum++; + } + } /* for elements */ + + if (minimum == MAXULONG) + minimum = 0; + if (maximum == MAXULONG) + maximum = 0; + if (maximum > 0) + putprintf(mbp, " Maximum: %lu", (ULONG)maximum); + if (averagenum > 0 && average > 0) +#ifdef SPEECH + putprintf(mbp, speech_message(127), (ULONG)average / averagenum); +#else + putprintf(mbp, " Average: %lu", (ULONG)average / averagenum); +#endif + putprintf(mbp, " Minimum: %lu\r\r", (ULONG)minimum); + + /* expand=1: Alle Zeilen unter Minimum weggelassen. Es stehen somit */ + /* 5 bis GRAPH_LINES Zeilen fuer die Werte zwischen Min und Max */ + /* zur Verfuegung. */ + if (expand == 1) + maximum -= minimum; + + /* Zeilenraster ermitteln */ + raster = maximum / GRAPH_LINES; + if (raster == 0 || maximum % GRAPH_LINES > 0) + raster++; + + /* genaue Zeilenanzahl ermitteln */ + lines = maximum / raster; /* schwankt zwischen 5 und GRAPH_LINES */ + if (maximum % raster > 0) + lines++; + if (lines < 5) + lines = 5; /* min. sollen es 5 Zeilen sein */ + + /* Damit Minimalzeile im Expandmode mitangezeigt wird */ + if (expand == 1 && minimum > 0) + lastline = 0; + else + lastline = 1; + lines++; + if (expand == 1) + expandwert = minimum; + else + expandwert = 0; + /* Die einzelnen Zeilen generieren */ + do + { + lines--; + zeile[0] = NUL; + putprintf(mbp, "%6lu|", (ULONG)raster * lines + expandwert); + for (i = 0; i < elements; i++) + { + if (timesel == GRAPH_HOUR) + j = (i + pos + 1 >= GRAPH_STD_ELEMENTS) + ? pos + i + 1 - GRAPH_STD_ELEMENTS + : i + pos + 1; + else + j = i; + + wertmax = peak[j].max; + wertave = (j != pos) + ? peak[j].ave + : (slot > 0) + ? peak[j].ave / slot + : 0; + wertmin = peak[j].min; + + if (wertmax >= raster * lines + expandwert && wertmax != MAXULONG) + { + putstr(zeile, mbp); + if (wertave >= raster * lines + expandwert && wertave != MAXULONG) + { + if (wertmin >= raster * lines + expandwert && wertmin != MAXULONG) + /* Kontrollzeichen abfangen */ +#ifdef __WIN32__ + putchr((char)((prechar[0] < 32) ? '#' : prechar[0]), mbp); +#else + putchr((prechar[0] < 32) ? '#' : prechar[0], mbp); +#endif /* WIN32 */ + else +#ifdef __WIN32__ + putchr((char)((prechar[1] < 32) ? '*' : prechar[1]), mbp); +#else + putchr((prechar[1] < 32) ? '*' : prechar[1], mbp); +#endif /* WIN32 */ + } + else +#ifdef __WIN32__ + putchr((char)((prechar[2] < 32) ? '+' : prechar[2]), mbp); +#else + putchr((prechar[2] < 32) ? '+' : prechar[2], mbp); +#endif /* WIN32 */ + zeile[0] = NUL; + } + else + strcat(zeile, " "); + + } /* for itm_min; + start_hour = localtime(&start_time)->tm_hour; + start_day = (localtime(&start_time)->tm_wday != 0) + ? localtime(&start_time)->tm_wday - 1 + : 6; + start_diff = sys_time - start_time; + + for (i = 0; i < elements; i++) + { + j = (i + pos + 1 >= GRAPH_STD_ELEMENTS) + ? pos + i + 1 - GRAPH_STD_ELEMENTS + : i + pos + 1; + + if ( ( (timesel == GRAPH_DAY && i == graph.day_pos) + || (timesel == GRAPH_WEEK && i == graph.week_pos)) + && graph.enabled == TRUE) + putchr('A', mbp); + else + if ( ( timesel == GRAPH_HOUR + && graph.enabled == TRUE + && j == start_min + && start_diff < 3600 - 60) + || ( timesel == GRAPH_DAY + && i == 2 * start_hour + start_min / 30 + && start_diff < 86400 - 1800) + || ( timesel == GRAPH_WEEK + && i == 8 * start_day + start_hour / 3 + && start_diff < 604800 - 10800)) + putchr('N', mbp); + else + putchr('-', mbp); + } + switch (timesel) + { + case GRAPH_DAY: +#ifdef SPEECH + putprintf(mbp, speech_message(128), " ", " "); +#else + putprintf(mbp, "\r%7s00 02 04 06 08 10 12 14 16 18 20 22\r" + "%9s01 03 05 07 09 11 13 15 17 19 21 23" + " Hour\r\r", " ", " "); +#endif + break; + case GRAPH_WEEK: +#ifdef SPEECH + putprintf(mbp, speech_message(129), " ", " ", " "); +#else + putprintf(mbp, "\r%7s0 0 1 1 0 0 1 1 0 0 1 1 0 0" + " 1 1 0 0 1 1 0 0 1 1 0 0 1 1\r" + "%7s0 6 2 8 0 6 2 8 0 6 2 8 0 6 2" + " 8 0 6 2 8 0 6 2 8 0 6 2 8 h\r" + "%7sMonday Tuesday Wednes. Thursd." + " Friday Saturd. Sunday\r\r", " ", " ", " "); +#endif + break; + default: +#ifdef SPEECH + putprintf(mbp, speech_message(130), " "); +#else + putprintf(mbp, " Elap. time\r%6s-3600 -3240 -2880 -2520 -2160 " + "-1800 -1440 -1080 -720 -360 0 Seconds\r\r", " "); +#endif + } /* switch */ +} + +/************************************************************************/ +/* Funktion graphtimer(void) */ +/* */ +/************************************************************************/ +void +graph_timer(void) +{ + static int graph_time = 0; + int min, + hour, + day; + + graph_time--; + + /* Alle GRAPH_INTERVAL Sekunden werden die Daten verarbeitet */ + if (graph_time <= 0L && graph.enabled == TRUE) + { + graph_time = GRAPH_INTERVAL; /* Wartezeit neu setzen */ + + min = sys_localtime->tm_min; + hour = sys_localtime->tm_hour; + day = (sys_localtime->tm_wday != 0) ? sys_localtime->tm_wday - 1 : 6; + + /* Jede Minute ein neues Datenfeld vorbereiten */ + /* Feldposition aktualisieren dg9aml */ + + if (graph.hour_pos != min) + { +/* alte Spalte ist abgeschlossen, kann gemittelt werden */ + graph_average(GRAPH_HOUR); +/* neue Spalte vorbereiten, Werte zuruecksetzen */ + graph.hour_slot = 0; +/* Falls mehr als eine Min. vergangen ist, mehrere Elemente loeschen */ + while ( min != graph.hour_pos) + { + graph.hour_pos++; + if (graph.hour_pos == GRAPH_STD_ELEMENTS) + graph.hour_pos = 0; + graph_clear_element(GRAPH_HOUR, 1); /* Komplett loeschen */ + } + graph.hour_pos = min; + graph_clear_element(GRAPH_HOUR, 0); + } + /* Jede halbe Stunde ein neues Datenfeld vorbeiten dg9aml */ + if (graph.day_pos != 2 * hour + min / 30) + { + graph_average(GRAPH_DAY); + graph.day_slot = 0; + graph.day_pos = 2 * hour + min / 30; + graph_clear_element(GRAPH_DAY, 0); /* loeschen der neuen Spalte */ + } + + /* Alle 3 Stunden ein neues Datenfeld vorbeiten */ + if (graph.week_pos != 8 * day + hour / 3) + { + graph_average(GRAPH_WEEK); + graph.week_slot = 0; + graph.week_pos = 8 * day + hour / 3; + graph_clear_element(GRAPH_WEEK, 0); /* loeschen der neuen Spalte */ + } + graph_actual_element(); /* aktualisiert Element in hour,day,week */ + graph.hour_slot++; + graph.day_slot++; + graph.week_slot++; + } /* if graph.enabled */ +} + +/************************************************************************/ +/* Aktuelle Graph-Daten speichern. */ +/* */ +/* Rueckgabe: TRUE: Abspeichern erfolgreich */ +/* FALSE: Fehler beim Abspeichern */ +/************************************************************************/ +BOOLEAN +save_graph(void) +{ + FILE *fp; /* File-Pointer */ + BOOLEAN ret = TRUE; /* Return-Wert */ + char file[128]; /* Puffer fuer Filenamen */ + + sprintf(file, "%sGRAPH.STA", confpath); + + if ((fp = xfopen(file,"wb")) != NULL) /* File oeffnen */ + { + if (fwrite(&graph, sizeof(graph), 1, fp) != 1) + { + ret = FALSE; + xprintf("*** GRAPH.STA write error ***\n"); + } + fclose(fp); /* File schliessen */ + return(ret); + } + xprintf("*** GRAPH.STA open error ***\n"); + return(FALSE); +} + +/************************************************************************/ +/* Aktuelle Statistik-Daten laden. */ +/* */ +/* Rueckgabe: TRUE bei erfolgreichem Einladen */ +/* FALSE bei Fehler */ +/************************************************************************/ +BOOLEAN +load_graph(void) +{ + FILE *fp; /* File-Pointer */ + LONG filelength; /* Laenge von GRAPH.STA */ + BOOLEAN ret = TRUE; /* Returnwert */ + char file[MAXPATH+1]; /* Puffer fuer Filenamen */ + + sprintf(file, "%sGRAPH.STA", confpath); + + if ((fp = xfopen(file,"rb")) != NULL) /* File oeffnen */ + { + fseek(fp, 0L, SEEK_END); /* Dateilaenge ermitteln */ + filelength = ftell(fp); + rewind(fp); + + if (filelength != (LONG) sizeof(graph)) + { /* Stimmt Dateilaenge? */ + ret = FALSE; + xprintf("*** GRAPH.STA has wrong size ***\n"); + } + else + { /* Laenge stimmt */ + if (fread(&graph, sizeof(graph), 1, fp) != 1) + { + ret = FALSE; + } + } + fclose(fp); /* Datei schliessen */ + return(ret); + } + /* GRAPH.STA konnte nicht geoeffnet werden */ + xprintf("*** GRAPH.STA - open error ***\n"); + return(FALSE); +} +#endif /* ifdef GRAPH */ + +/* End of src/graph.c */ diff --git a/src/l1httpd.c b/src/l1httpd.c new file mode 100644 index 0000000..b63c54b --- /dev/null +++ b/src/l1httpd.c @@ -0,0 +1,1920 @@ +#include "tnn.h" + +#ifdef L1HTTPD + +/* Interfacezeiger auf HTTPD. */ +static T_INTERFACE *ifhtt = &ifp[HTP_ID]; +/* Zeiger auf das Aktuelle Interface. */ +static T_INTERFACE *ifpp; + +enum { H_GET, H_HEAD, H_POST } method; +enum { NONE, BIN, TXT, GIF, JPG, WAV, MP3} h_mimetype; + +static char h_inbuf[400]; +static char h_cookie_login[30]; +static char h_cookie_pw[16+1]; +static long h_contentlength; +static char *h_content; +static int h_status; +static char h_file[80]; +static char h_uri[200]; +static char h_login[30]; +static char h_pw[17]; +static int h_nocookie; +static char h_header[HEADLEN]; +static char h_userpass[50]; +static char h_referer[100]; +static char h_host[100]; +static int h_version; + + +/* Buffer besorgen und Socket eintragen. */ +MBHEAD *SetBufSock(void) +{ + MBHEAD *tbp = NULL; +#ifdef DEBUG_MODUS + lastfunc = "l1http(SetBufSock)"; +#endif /* DEBUG_MODUS */ + + /* kein Speicher. */ + if (nmbfre < 300) + { + ifpp = SetInterface(tcppoi->Interface); + T_LOGL1(TRUE, "(SetBufSock):%s\nSpeicher (%d) ist voll!\n" + , tcppoi->ip + , nmbfre); + /* Kein Buffer zur Verfuegung. */ + tcppoi->disflg |= 0x80; /* Segment auf Disconnect setzen. */ + return(NULL); + } + + /* Buffer besorgen. */ + if ((tbp = (MBHEAD *) allocb(ALLOC_L1HTTPD_RX)) == NULL) + { + ifpp = SetInterface(tcppoi->Interface); + T_LOGL1(TRUE, "(SetBufSock):%s\nSpeicher (%d) ist voll!\n" + , tcppoi->ip + , nmbfre); + /* Kein Buffer zur Verfuegung. */ + tcppoi->disflg |= 0x80; /* Segment auf Disconnect setzen. */ + return(NULL); + } + + return(tbp); +} + +/* HTTPD-Server Einstellung aendern/setzen. */ +void ccphttpd(void) +{ + MBHEAD *mbp; + char ch; + int tmp_fd = EOF; + int newloglevel = 0; + int new_tcp_port = 0; +#ifdef DEBUG_MODUS + lastfunc = "l1http(ccphttpd)"; +#endif /* DEBUG_MODUS */ + + /* Zeiger auf das aktuelle Interface? */ + if (ifhtt == NULL) + /* Dann Zeiger auf das HTTPD-Interface. */ + ifpp = &ifp[HTP_ID]; + else + ifpp = ifhtt; + + /* Sysop will aendern? */ + if (issyso() && skipsp(&clicnt, &clipoi)) + { + clicnt--; + ch = toupper(*clipoi++); + switch (ch) + { + /* Sysop will httpd-Port aendern */ + case 'P': + if (!skipsp(&clicnt, &clipoi)) + { + putmsg("Invalid Parameter\r"); + return; + } + + /* Neuen TCP-Port einlesen. */ + new_tcp_port = nxtlong(&clicnt, &clipoi); + + if ( (new_tcp_port < 1) + ||(new_tcp_port > 65535)) + { +#ifdef SPEECH + putmsg(speech_message(328)); +#else + putmsg("HTTPD-Port not valid, not changed !!!\r"); +#endif + return; + } + + /* Wenn NEUER TCP-Port und ALTER TCP-Port */ + /* GLEICH sind, brauchen wir nix aendern. */ + if (ifpp->tcpport == Htons((unsigned short)new_tcp_port)) + { +#ifdef SPEECH + putmsg(speech_message(330)); +#else + putmsg("TCP-Port successfully changed\r"); +#endif + return; + } + + /* Ist HTTPD-Server aktiv ? */ + if (ifpp->actively == FALSE) + { +#ifdef SPEECH + putmsg(speech_message(327)); +#else + putmsg("TCP-Port haven not switched on!\r"); +#endif + return; + } + + if ((tmp_fd = SetupTCP(ifpp->name, (unsigned short)new_tcp_port)) != EOF) + { +#ifdef OS_STACK + int tmp_fd_OS; + + if ((tmp_fd_OS = SetupOS(ifpp, (unsigned short)new_tcp_port)) != EOF) + { + /* alten Socket schliessen */ + close(ifpp->OsSock); + /* Neuen Socket merken */ + ifpp->OsSock = tmp_fd_OS; + } + else + { + Close(tmp_fd); + putmsg("ERROR: Changing UDP-Port failed, Port not changed !!!\r"); + return; + } +#endif /* OS_STACK */ + + Close(ifpp->ISock); /* Alten Socket schliessen. */ + ifpp->ISock = tmp_fd ; /* Neuen Socket merken */ + } + else + { /* Neuen TCP-Port liess sich nicht Initialisieren. */ + putmsg("ERROR: Changing UDP-Port failed, Port not changed !!!\r"); + return; + } + + + /* TCP-Port OK, dann markieren wir neuen TCP-Port. */ + ifpp->tcpport = Htons((unsigned short)new_tcp_port); + +#ifdef SPEECH + putmsg(speech_message(330)); +#else + putmsg("TCP-Port successfully changed\r"); +#endif + return; + + + /* Sysop will LOGLevel aendern */ + case 'L': + if (!skipsp(&clicnt, &clipoi)) + { + /* Keine Parameter angegeben, */ + /* status Loglevel anzeigen. */ + mbp = putals("HTTPD-Server:\r"); +#ifdef SPEECH + putprintf(mbp, speech_message(299),ifpp->log); +#else + putprintf(mbp, "My LogLevel: %d\r",ifpp->log); +#endif + prompt(mbp); + seteom(mbp); + return; + } + + /* Markiere neuen Loglevel */ + newloglevel = nxtnum(&clicnt, &clipoi); + + if ( (newloglevel < 0) + ||(newloglevel > 3)) + { + mbp = putals("HTTPD-Server:\r"); +#ifdef SPEECH + putprintf(mbp, speech_message(325)); +#else + putprintf(mbp, "Fehler: Loglevel werte von 0 bis 3!\r"); +#endif + prompt(mbp); + seteom(mbp); + return; + } + + + /* Neuen Loglevel Sysop zeigen */ + ifpp->log = newloglevel; + mbp = putals("HTTPD-Server:\r"); +#ifdef SPEECH + putprintf(mbp, speech_message(299), ifpp->log); +#else + putprintf(mbp, "My Loglevel: %d\r", ifpp->log); +#endif + prompt(mbp); + seteom(mbp); + return; + + break; + + + default: + putmsg("Invalid Paramter\r"); + return; + } + } + + mbp = putals("HTTPD-Server:\r"); +#ifdef SPEECH + putprintf(mbp, speech_message(299), ifpp->log); + putprintf(mbp, speech_message(326), Ntohs(ifpp->tcpport)); +#else + putprintf(mbp, "My Loglevel: %u\r", ifpp->log); + putprintf(mbp, "My TCP-Port: %u\r", Ntohs(ifpp->tcpport)); +#endif + prompt(mbp); + seteom(mbp); +} + +/* Schreibe Konverierung in Buffer. */ +static void putf(MBHEAD *tbp, char *format, ...) +{ + va_list argpoint; + char cbuf[260]; + char *s=cbuf; + int i = 0; +#ifdef DEBUG_MODUS + lastfunc = "l1http(putf)"; +#endif /* DEBUG_MODUS */ + + va_start(argpoint,format); + vsprintf(cbuf,format,argpoint); + va_end(argpoint); + + while(*s && ++i != HEADLEN) + putv(tbp, *(s++)); +} + +/* Konvertierung IBM/HTML. */ +void putv( MBHEAD *tbp, int c) +{ +#ifdef DEBUG_MODUS + lastfunc = "l1http(putv)"; +#endif /* DEBUG_MODUS */ + + if(tcppoi && tcppoi->http == TCP_CMD) + { + switch(c) + { /* Conversion IBM -> HTML */ + case '>': + putf(tbp, ">"); + return; + + case '<': + putf(tbp, "<"); + return; + + case 0x84: + putf(tbp, "ä"); + return; + + case 0x94: + putf(tbp, "ö"); + return; + + case 0x81: + putf(tbp, "ü"); + return; + + case 0x8e: + putf(tbp, "Ä"); + return; + + case 0x99: + putf(tbp, "Ö"); + return; + + case 0x9a: + putf(tbp, "Ü"); + return; + + case 0xe1: + putf(tbp, "ß"); + return; + } + } + + if(c == '\n') + putchr(CR, tbp); + + putchr((char)c, tbp); +} + +static void base64bin(char *in, char *out, int maxlen) +{ + int i,a,end = FALSE; + long outword = FALSE; +#ifdef DEBUG_MODUS + lastfunc = "l1http(base64bin)"; +#endif /* DEBUG_MODUS */ + + while (in[0] && end==0 && maxlen > 3) + { + for (i = 0; i < 4; i++) + { + if (in[i] == 0) + end = 1; + + outword <<= 6; + a = in[i]; + + if (isalpha(a) && isupper(a)) + a -= ('A'); + else + if (isalpha(a) && islower(a)) + a-= ('a' - 26); + else + if (isdigit(a)) + a += 4; + else + if (a == '+') + a = 62; + else + if (a == '/') + a = 63; + else + a = 0; + + outword |= a; + } + + out[0] = (outword >> 16) & 255; + out[1] = (outword >> 8) & 255; + out[2] = (outword) & 255; + in += 4; + out += 3; + maxlen -= 3; + } + out[0] = 0; +} + +static void get_authorization(char *buf ,BOOLEAN cookie, MBHEAD *tbp) +{ + char *search; + char *basic; + char loginpw[50]; + char *locpw; +#ifdef DEBUG_MODUS + lastfunc = "l1http(get_authorization)"; +#endif /* DEBUG_MODUS */ + + if(cookie) + search="TheNetNode"; + else + search="Basic"; + + basic = strstr(buf, search); + + if(basic) + { + basic += (strlen(search) + 1); + if(strlen(basic) > 50) + basic[50] = 0; + + strncpy(h_userpass, basic, 50); + base64bin(basic, loginpw, 49); + locpw = strchr(loginpw, ':'); + + if(locpw) + { + locpw[16 + 1] = 0; + if(cookie) + strncpy(h_cookie_pw, locpw + 1, 17); + else + strncpy(h_pw, locpw + 1, 17); + + locpw[0] = ' '; + } + + locpw = strchr(loginpw, ' '); + if(locpw) + locpw[0] = 0; + + loginpw[16] = 0; + if(cookie) + strncpy(h_cookie_login, loginpw, 30); + else + { + strncpy(h_login, loginpw, 30); + putprintf(tbp, "%s", h_login); + } + } +} + +static int blkill(char *bf) +{ + int i = 0; +#ifdef DEBUG_MODUS + lastfunc = "l1http(blkill)"; +#endif /* DEBUG_MODUS */ + + while (bf[i] == 13 || bf[i] == ' ' || bf[i] == ',') + i++; + + return i; +} + +static char *blankweg(char *s) +{ +#ifdef DEBUG_MODUS + lastfunc = "l1http(blankweg)"; +#endif /* DEBUG_MODUS */ + + if (s == NULL) + return NULL; + + s = strchr(s,' '); + if (s) + { + s[0] = 0; + s += 1; + s += blkill(s); + return s; + } + + return s; +} + +static char *stristr(char *s1, char *s2) +{ + int i; + int l = strlen(s2); +#ifdef DEBUG_MODUS + lastfunc = "l1http(stristr)"; +#endif /* DEBUG_MODUS */ + + while (s1[0]) + { + i = 0; + while ((((s1[i] ^ s2[i]) &0x5f) == 0) && s2[i]) + i++; + + if(i == l) + return s1; + + s1++; + } + + return NULL; +} + +static char *ht_time(time_t t) +{ + static char zeitdatum[40]; +#ifdef DEBUG_MODUS + lastfunc = "l1http(ht_time)"; +#endif /* DEBUG_MODUS */ + + strftime(zeitdatum,sizeof(zeitdatum), "%a, %d-%b-%Y %H:%M:%S GMT",localtime(&t)); + return(zeitdatum); +} + +static long filesize(char *name) +{ + struct stat st; +#ifdef DEBUG_MODUS + lastfunc = "l1http(filesize)"; +#endif /* DEBUG_MODUS */ + + if (stat(name, &st) == 0) + return st.st_size; + else + return 0L; +} + +static time_t filetime(char *name) +{ + struct stat st; +#ifdef DEBUG_MODUS + lastfunc = "l1http(filetime)"; +#endif /* DEBUG_MODUS */ + + if (stat(name, &st) == 0) + return st.st_mtime; + else + return 0L; +} + +static void form_referer(void) +{ + char tmp[80]; + char *hostpos=stristr(h_referer,h_host); +#ifdef DEBUG_MODUS + lastfunc = "l1http(form_referer)"; +#endif /* DEBUG_MODUS */ + + if(h_referer[0] && h_host[0] && hostpos) + { + if ((strlen(hostpos+strlen(h_host))>79)) +#ifdef SPEECH + printf(speech_message(339)); +#else + printf("form_referer str too long"); +#endif + strncpy(tmp, hostpos+strlen(h_host), 80); + strncpy(h_referer, tmp, 80); + } + if(h_referer[0]==0) + strcpy(h_referer, "/"); +} + +static void get_field(char *buf,char *dest,int maxlen) +{ + char *dop=strchr(buf,':'); +#ifdef DEBUG_MODUS + lastfunc = "l1http(get_field)"; +#endif /* DEBUG_MODUS */ + + if(dop) + { + dop++; + + while(dop[0] == ' ') + dop++; + + if(strlen(dop)>=(unsigned)maxlen) + dop[maxlen-1] = FALSE; + + strncpy(dest,dop, 100); + } + else + dest[0] = FALSE; +} + +static void get_contentlength(char *buf) +{ + char *dop=strchr(buf,':'); +#ifdef DEBUG_MODUS + lastfunc = "l1http(get_contentlength)"; +#endif /* DEBUG_MODUS */ + + if(dop) + h_contentlength=atol(dop+1); +} + +static void get_postarea(char *tag,char *result,int max,int wrap) +{ + int i; + char *firstresult; + char *found; +#ifdef DEBUG_MODUS + lastfunc = "l1http(get_postarea)"; +#endif /* DEBUG_MODUS */ + + result[0] = FALSE; + firstresult=result; + + if(h_content==NULL) + return; + + found=stristr(h_content,tag); + if(found) + { + found+=strlen(tag); + while(found[0] && found[0]!='&' && max) + { + if(found[0]=='+') + result[0]=' '; + else if(found[0]=='%') + { char hex[3]; + unsigned val; + hex[0]=found[1]; + hex[1]=found[2]; + hex[2]=0; + sscanf(hex,"%2X",&val); + found+=2; + if(val==13) + { + found++; + continue; + } + result[0]=val; + } + else + result[0]=found[0]; + result++; + found++; + max--; + result[0]=0; + } + } + /* do word wrapping since the browser seems not to be able to do it */ + if(wrap) + { + result=firstresult; + while(result[0]) + { + if(result[0]=='\n') + { + result++; + continue; + } + for(i=0;imbpc != data->mbgc && i != 300) + { + /* Hole Zeichen aus den Buffer. */ + c = getchr(data); + /* Zeichen ein CR-Return? */ + if (c == CR) + /* Eingelesene Zeichen zur weiteren Auswertung. */ + break; + + buffer[i++] = c; + } + /* Nullzeichen setzen. */ + buffer[i++] = '\0'; + +} + +/* Status, Login auswerten. */ +static void GetRequest(MBHEAD *data) +{ + MBHEAD *rxcall; + char locinbuf[301]; + char *locmethod; + char *locuri; + char *locprotocol; + char *slash; + char *ext; +#ifdef DEBUG_MODUS + lastfunc = "l1http(GetRequest)"; +#endif /* DEBUG_MODUS */ + + /* Buffer besorgen. */ + if ((rxcall = SetBufSock()) == NULL) + /* Buffer voll. */ + return; + + /* Status, Login-Daten zurueckspulen. */ + rwndmb(data); + /* Status, Login-Daten einlesen. */ + read_data(data, locinbuf); + + /* ggf. Logbuch fuehren. */ + ifpp = SetInterface(tcppoi->Interface); + T_LOGL3(TRUE, "(GetRequest):%s\nInput: %s" + , tcppoi->ip + , locinbuf); + + strncpy(h_inbuf, locinbuf, 400); + locmethod = locinbuf; + locuri = blankweg(locmethod); + locprotocol = blankweg(locuri); + blankweg(locprotocol); + + h_contentlength=0L; + h_content=NULL; + h_status=200; + h_version=9; /* default if no protocol is given */ + h_file[0]=0; + h_login[0]=0; + h_pw[0]=0; + h_cookie_login[0]=0; + h_cookie_pw[0]=0; + h_nocookie=0; + h_referer[0]=0; /*deti 16-jul-97*/ + h_mimetype=NONE; /*deti 15-jul-97*/ + + if(locprotocol) + { + slash = strchr(locprotocol, '/'); + if (slash && isdigit(slash[1])) + h_version = (slash[1]-'0') * 10; + + if (slash && isdigit(slash[3])) /* DH3MB: Added "slash &&"*/ + h_version += (slash[3] - '0'); + } + + h_uri[0] = 0; + if (locuri) + strncpy(h_uri, locuri, 200); + + if (h_uri[0] != '/') + h_status = 400; + + if (stricmp(locmethod, "GET") == 0) + method = H_GET; + else + if (stricmp(locmethod, "HEAD") == 0) + method = H_HEAD; + else + if (stricmp(locmethod, "POST") == 0) + method = H_POST; + else + h_status = 501; + + if ((ext = strchr(h_uri,'.')) == 0) + { + if(h_file[strlen(h_file)-1]=='/') + h_file[strlen(h_file)-1]=0; + } + + if (ext != NULL) + { + if ( (strstr(h_uri, "htm") + ||(strstr(h_uri, "php"))) == 0) + { + if (strncmp(locuri, "/./", 3) == FALSE) + h_status = 401; + + strcat(h_file, locuri); + + if(h_file[strlen(h_file)-1] == '/') + h_file[strlen(h_file)-1] = FALSE; + } + } + + /* Abmelden */ + if(stricmp(h_uri, "/logout") == FALSE) + { + /* Neuen Status setzen (Logout). */ + h_status = 901; + /* Name loeschen. */ + h_login[0] = 0; + + /* Buffer fuer Rufzeichen gefuellt? */ + if (rxcall != NULL) + /* Buffer freigeben. */ + dealmb(rxcall); + + return; + } + + if(locprotocol && stristr(locprotocol, "HTTP/") == locprotocol) + { + do + { + /* Status, Login-daten einlesen. */ + read_data(data, locinbuf); + + /* ggf. Logbuch fuehren. */ + ifpp = SetInterface(tcppoi->Interface); + T_LOGL3(FALSE, "%s",locinbuf); + + if(locinbuf[0]) + { + if(stristr(locinbuf, "Authorization") == locinbuf) + get_authorization(locinbuf, FALSE, rxcall); + + if(stristr(locinbuf, "Cookie") == locinbuf) + get_authorization(locinbuf, TRUE, rxcall); + + if(stristr(locinbuf, "Referer") == locinbuf) + get_field(locinbuf, h_referer, sizeof(h_referer)); + + if(stristr(locinbuf, "Host") == locinbuf) + get_field(locinbuf, h_host, sizeof(h_host)); + + if(stristr(locinbuf, "Content-length") == locinbuf) + get_contentlength(locinbuf); + + } + } + + while(locinbuf[0]); + + if(h_contentlength) + { + long i; + + if (h_contentlength > 10000000L) + printf("httpd::start_http content too long"); + + h_content = (char *)malloc(h_contentlength * 2); + + for (i = 0; i < h_contentlength; i++) + h_content[i] = ReadSockTCP(); + + h_content[i] = 0; + } + } + + if(h_status != 200) + h_uri[0] = FALSE; + + locuri = strchr(h_uri, '?'); + if (locuri) + { + if(h_content == NULL) + { + locuri[0] = FALSE; + h_content = locuri + 1; + } + } + form_referer(); + + if (ext != NULL) + { + if (strncasecmp(ext, ".htm", 4)) + { + h_status = 200; + + if (rxcall != NULL) + dealmb(rxcall); + + return; + } + } + + /* Anmelden */ + if(stricmp(h_uri, "/login") == FALSE) + { + /* noch keine Anmeldung. */ + if (h_login[0] == FALSE) + { + /* Neuen Status setzen. */ + h_status = 401; + + /* Buffer fuer Rufzeichen gefuellt? */ + if (rxcall != NULL) + /* Buffer entsorgen. */ + dealmb(rxcall); + + return; + } + } + + if (h_login[0] != FALSE) + { + /* User/Link anmelden. */ + if (LoginTCP(rxcall)) + { + /* Buffer fuer Rufzeichen gefuellt? */ + if (rxcall->owner != ALLOC_NO_OWNER) + /* Buffer entsorgen. */ + dealmb(rxcall); + + /* Login war erfolglos, status setzen. */ + h_status = 401; + } + } + + /* Will User einen Befehl ausfuehren? */ + if (stricmp(h_uri, "/cmd") == 0) + { + if (h_login[0] == FALSE) + { + /* Buffer fuer Rufzeichen gefuellt? */ + if (rxcall->owner != ALLOC_NO_OWNER) + /* Buffer entsorgen. */ + dealmb(rxcall); + + /* Neuen Status setzen. */ + h_status = 401; + } + } + + h_nocookie = 1; + + /* Buffer fuer Rufzeichen gefuellt? */ + if (rxcall->owner != ALLOC_NO_OWNER) + /* Buffer entsorgen. */ + dealmb(rxcall); +} + +/* aktuelle Zeit setzen. */ +static time_t ad_time(void) +{ + time_t newvalue; + return(newvalue=time(NULL)); +} + +/* Aktuellen Header in Buffer schreiben. */ +static void PutHeader(MBHEAD *tbp, char *head, BOOLEAN frame) +{ + char *s = h_header; + WORD j = 0, i = strlen(s); + char call[10]; +#ifdef DEBUG_MODUS + lastfunc = "l1http(PutHeader)"; +#endif /* DEBUG_MODUS */ + + while (j != i && j != HEADLEN) + /* Zeichen in Buffer schreiben. */ + putchr(s[j++], tbp); + + /* Zusaetzlichen HTML-Code? */ + if (!frame) + /* Nein, dann abbruch. */ + return; + + call2str(call, myid); + putprintf(tbp, "%s - %s\n",call,head); + putprintf(tbp, "\n"); + putprintf(tbp, "\n"); +} + +/* HTML-Header erstellen. */ +static int PrepareHeader(MBHEAD *tbp) +{ + struct + { + int status; + char *phrase; + } st_tab[] = { + { 200,"OK" }, + { 201,"Created" }, + { 202,"Accepted" }, + { 204,"No Content" }, + { 301,"Moved Permanently" }, + { 302,"Moved Temporarily" }, + { 304,"Not Modified" }, + { 400,"Bad Request" }, + { 401,"Unauthorized" }, + { 403,"Forbidden" }, + { 404,"Not Found" }, + { 500,"Internal Server Errror" }, + { 501,"Not Implemented" }, + { 502,"Bad Gateway" }, + { 503,"Service Unavailable" }, + { 901,"Logout" }, + { 0,"Unknown" } + }; + + int st; + char *mimestr; + char *h=h_header; + char call[10]; +#ifdef DEBUG_MODUS + lastfunc = "l1http(PrepareHeader)"; +#endif /* DEBUG_MODUS */ + + /* Konvertiere MYCALL. */ + call2str(call, myid); + + for(st = 0; st_tab[st].status; st++) + { + if(st_tab[st].status == h_status) + break; + } + + if (h_status == 901) + h_status = 401; + + if(h_version > 9) + { + h += sprintf(h,"HTTP/1.0 %d %s\n",h_status,st_tab[st].phrase); + h += sprintf(h,"Date: %s\n",ht_time(ad_time())); + h += sprintf(h,"Server: TheNetNode V1.79\n"); + + /* Login war erfolglos. */ + if (h_status == 401) + { + h += sprintf(h,"WWW-Authenticate: Basic realm=\"%s\"\n",call); + h += sprintf(h,"Set-Cookie: %s=; path=/; expires=%s\n",call,ht_time(0)); + } + else + if(strcmp(h_uri, "/") == 0 && h_status == 200 && h_pw[0] && h_nocookie == 0) + h += sprintf(h,"Set-Cookie: %s=%s; path=/; expires=%s\n", + call,h_userpass,ht_time(ad_time()+3600*24*30)); + + /* Kein Mime-Type gesetzt. */ + if(h_mimetype == NONE) + { + if(stristr(h_uri, ".jpg")) + h_mimetype = JPG; + + if(stristr(h_uri, ".gif")) + h_mimetype = GIF; + + if(stristr(h_uri, ".wav")) + h_mimetype = WAV; + + if(stristr(h_uri, ".mp3")) + h_mimetype = MP3; + + if(stristr(h_uri, ".tar")) + h_mimetype = BIN; + + if(stristr(h_uri, ".zip")) + h_mimetype = BIN; + } + + /* Content-type stzen. */ + switch(h_mimetype) + { + case JPG: mimestr = MIME_JPG; break; + case GIF: mimestr = MIME_GIF; break; + case BIN: mimestr = MIME_BIN; break; + case WAV: mimestr = MIME_WAV; break; + case MP3: mimestr = MIME_MP3; break; + default: mimestr = MIME_TXT; + } + h += sprintf(h,"Content-type: %s\n",mimestr); + + if(h_file[0] && !access(h_file, 0)) + { + h += sprintf(h,"Content-length: %ld\n",filesize(h_file)); + h += sprintf(h,"Last-modified: %s\n",ht_time(filetime(h_file))); + } + else + { + char cmd[30]; + int expsec=180; + + get_postarea("cmd=",cmd,29,0); + + if(cmd[0] && cmd[0] != 'd' && cmd[0] != 'c' && cmd[0] != 'h') + expsec = (-10000); + + if(stristr(h_uri, "/send") == h_uri) + expsec=8000; /*OE3DZW was 7200 */ + + h += sprintf(h,"Expires: %s\n",ht_time(ad_time()+expsec)); + } + h += sprintf(h, "\n"); + } + + /* Abmelden /logout */ + if(stricmp(h_uri, "/logout") == FALSE) + { + h += sprintf(h,"Logout\n"); + h += sprintf(h,"\n"); + h += sprintf(h,"

%s

\n",st_tab[st].phrase); + h += sprintf(h,"
");
+
+    h += sprintf(h,"Sie haben sich erfolgreich abgemeldet.\n");
+    h += sprintf(h,"Rejected request: '%s'\n",h_inbuf);
+    h += sprintf(h,"

" + "
HTTPD-Server TheNetNode V1.79 - Server at ´%s Port %d
", call, Htons(ifp[HTP_ID].tcpport)); + h += sprintf(h,"\n"); + + /* Aktuellen Header in Buffer schreiben. */ + PutHeader(tbp, st_tab[st].phrase,0); + return(FALSE); + } + + if(h_status != 200) + { + h += sprintf(h,"Unauthorized\n"); + h += sprintf(h,"\n"); + h += sprintf(h,"

%s (%d)

\n",st_tab[st].phrase,h_status); + h += sprintf(h,"
"
+                   "Benutzername ist ungueltig !!!\n"
+                   "Benutzen Sie ein Rufzeichen aus DAA000 bis DZZ999 oder als GAST-Nutzer GAST.\n"
+                   "\n");
+    h += sprintf(h,"An error ocurred while processing your query.\n");
+    h += sprintf(h,"Rejected request: '%s'\n",h_inbuf);
+    h += sprintf(h,"

" + "
HTTPD-Server TheNetNode V1.79 - Server at ´%s Port %d
", call, Htons(ifp[HTP_ID].tcpport)); + h += sprintf(h,"\n"); + + /* Aktuellen Header in Buffer schreiben. */ + PutHeader(tbp, st_tab[st].phrase,0); + return(FALSE); + } + + if(method == H_GET || method == H_POST) + return(TRUE); + + /* Aktuellen Header in Buffer schreiben. */ + PutHeader(tbp, "",1); + return(FALSE); +} + +/* Befehl weiterleiten. */ +static void PutComand(void) +{ + MBHEAD *tbp; + int i = 0; +#ifdef DEBUG_MODUS + lastfunc = "l1http(PutComand)"; +#endif /* DEBUG_MODUS */ + + /* Steht nix in der Befehlszeile, */ + if (!tcppoi->cmdlen) + /* brechen wir hier ab,. */ + return; + + /* zum Schluss das Return setzen. */ + tcppoi->cmd[tcppoi->cmdlen++] = CR; + + /* Buffer besorgen. */ + tbp = (MBHEAD *) allocb(ALLOC_MBHEAD); + + /* Befehlszeile in Buffer schreiben. */ + while (tcppoi->cmdlen-- && i != RXLEN) + /* Zeichen in Buffer schreiben. */ + putchr(tcppoi->cmd[i++], tbp); + + /* Befehl weiterleiten. */ + RelinkTCP(tbp); +} + +/* Path setzen/offnen. */ +BOOLEAN SetFileOpen(char *urifile, MBHEAD *tbp) +{ + char cfgfile[255]; +#ifdef DEBUG_MODUS + lastfunc = "l1http(SetFileOpen)"; +#endif /* DEBUG_MODUS */ + + /* Path setzen. */ + strcpy(cfgfile, textpath); + strcat(cfgfile, "http"); + strcat(cfgfile, urifile); + + /* File-Pointer belegt? */ + if (tcppoi->fp == NULL) + { + /* Datei oeffnen. */ + if ((tcppoi->fp = fopen(cfgfile, "rb")) == NULL) + { + ifpp = SetInterface(tcppoi->Interface); + T_LOGL1(TRUE, "(SetFileOpen):%s\nDatei (%s) kann nicht geoeffnet werden!\n" + , tcppoi->ip + , cfgfile); + + /* Datei laest sich nicht offnen, abbruch. */ + return(TRUE); + } + + ifpp = SetInterface(tcppoi->Interface); + T_LOGL2(TRUE, "(SetFileOpen):%s\nDatei (%s) zum lesen geoeffnet.\n" + , tcppoi->ip + , cfgfile); + } + + PutHeader(tbp, "TheNetNode V1.79", FALSE); + return(FALSE); +} + +/* HTML-Datei konnte nicht geoeffnet */ +/* werden und nun wird gemeckert! */ +static void PutHtmlError(MBHEAD *tbp, char *url) +{ + char call[10]; +#ifdef DEBUG_MODUS + lastfunc = "l1http(PutHtmlError)"; +#endif /* DEBUG_MODUS */ + + /* Markiere, html/text. */ + h_mimetype = TXT; + /* Neuen HTML-Haeder erzeugen. */ + PrepareHeader(tbp); + + /* Path setzen/offnen. */ + if (SetFileOpen("/unknown.html", tbp) == TRUE) + { + /* Aktuellen Header einlesen/schreiben. */ + PutHeader(tbp, "TheNetNode V1.79", FALSE); + + call2str(call, myid); + /* Fehlermeldung zusammenbasteln. */ + putprintf(tbp, "404 Nicht gefunden\n"); + putprintf(tbp, "
\nDie Seite wurde nicht gefunden!\n"); + putprintf(tbp, "
(Angegebene URL: %s)


",url); + putprintf(tbp, "
\n"); + putprintf(tbp, "
HTTPD-Server TheNetNode V1.79 - Server at %s Port %d
", call, Htons(ifp[HTP_ID].tcpport)); + putprintf(tbp, "\n\n"); + } + else + /* Externe Datei laden. */ + tcppoi->status = TCP_URI; +} + +/* Pruefe Index-Verzeichnis. */ +DIR *CheckPath(MBHEAD *tbp, char *Path) +{ + DIR *dp; + char TmpPath1[256]; +#ifdef DEBUG_MODUS + lastfunc = "l1http(CheckPath)"; +#endif /* DEBUG_MODUS */ + + if (strncmp(Path, "//", 2) == FALSE) + return(NULL); + + Path += 1; + + strcpy(TmpPath1, htmlpath); + strcat(TmpPath1, Path); + + /* Verzeichnis oeffnen. */ + dp = opendir(TmpPath1); + + /* Fehler, Verzeichnis letzt sich nicht oeffnen. */ + if (dp == NULL) + /* Abbrechen. */ + return(NULL); + + return(dp); +} + +/* Index-Verzeichnis setzen. */ +void SetIndexPath(char *Path, char *IndexPath) +{ + char Buffer[256]; + char *BPath = Buffer; +#ifdef DEBUG_MODUS + lastfunc = "l1http(SetIndexPath)"; +#endif /* DEBUG_MODUS */ + + strcpy(BPath, Path); + + BPath += 1; + addslash(BPath); + + sprintf(IndexPath, "%s", BPath); +} + +/* Parent-Verzeichnis setzen. */ +void SetParentPath(char *Path, char *ParentPath) +{ + char Buffer[256]; + char TmpPath2[256]; + char *BPath = Buffer; + char *loc; + int pos; +#ifdef DEBUG_MODUS + lastfunc = "l1http(SetParentPath)"; +#endif /* DEBUG_MODUS */ + + SetIndexPath(Path, BPath); + + strcpy(TmpPath2, htmlpath); + strcat(TmpPath2, BPath); + + /* Letztes zeichen (Back/Slash) loeschen. */ + TmpPath2[(strlen(TmpPath2) -1)] = 0; + + /* Suche das letzte Back/Slash. */ + if ((loc = strrchr(TmpPath2, FILE_SEP)) != NULL) + { + /* Position setzen. */ + pos = (int)(loc - TmpPath2); + /* aktuelles Verzeichnis setzen. */ + TmpPath2[pos] = 0; + /* Back/Slash neu setzen. */ + addslash(TmpPath2); + } + + /* Vergleiche Haupt "HTTPD" Verzeichnis mit aktuellen Verzeichnis. */ + if (strcasecmp(htmlpath, TmpPath2)) + { + /* komplettes Verzeichnis setzen. */ + loc = TmpPath2; + /* zum aktuellen Verzeichnis vorruecken. */ + loc += (strlen(htmlpath)); + /* aktuelles Verzeichnis setzen. */ + sprintf(ParentPath, "/%s", loc); + return; + } + + /* Local Hostname setzen. */ + sprintf(ParentPath,"%c", FILE_SEP); +} + +/* Dateien / Verzeichnisse listen. */ +void DirList(MBHEAD *tbp, DIR *dir, char *Path) +{ + struct dirent *dirp; +#ifdef DEBUG_MODUS + lastfunc = "l1http(DirList)"; +#endif /* DEBUG_MODUS */ + + /* Dateien sowie Verzeichnisse auflisten. */ + while ((dirp = readdir(dir)) != NULL) + { + char Size[256]; + char FileName[256]; + long int fSize = 0; + struct stat FSize; + + /* nicht anzeigen. */ + if (dirp->d_name[0] == '.') + continue; + + /* Kompletten Dateiname zusammenfassen. */ + sprintf(FileName, "%s%s%s", htmlpath, Path, dirp->d_name); + + /* Stat-Werte (Zeit, Datum, Dateigroesse) ermitteln. */ + if (!stat(FileName, &FSize)) + /* Bytes uebertragen. */ + fSize = FSize.st_size; + + /* Wert umrechnen in MB. */ + if(fSize >= 999999) + sprintf(Size,"%8ldMB",fSize/(1024*1024)); + else + { + /* Wert umrechnen in KB. */ + if(fSize >= 9999) + sprintf(Size,"%8ldKB",fSize/1024); + else + /* Wert umrechnen in Bytes. */ + sprintf(Size,"%8ldB ",fSize); + } + + putprintf(tbp, " \n
  • %s
  • %10s\n \n",Path ,dirp->d_name, dirp->d_name, (fSize ? Size : "")); + } +} + +/* Httpd-Service. */ +void TcpipHttpd(MBHEAD *data) +{ + MBHEAD *tbp = NULL; + char cmd[200]; + char *head; +#ifdef DEBUG_MODUS + lastfunc = "l1http(TcpipHttpd)"; +#endif /* DEBUG_MODUS */ + + /* Buffer besorgen. */ + if ((tbp = SetBufSock()) == NULL) + /* Kein Speicher.*/ + return; + + /* Status, Login auswerten. */ + GetRequest(data); + + MhUpdateTCP(data, TRUE); /* MH-Liste updaten */ + + /* HTML-Header erstellen. */ + if(PrepareHeader(tbp)) + { + /* Binaertransfer? */ + if(h_file[0]) + { + /* Path setzen/offnen. */ + if (SetFileOpen(h_file, tbp) == TRUE) + /* Externe HTML-Datei kann nicht geoffnet werden. */ + PutHtmlError(tbp, h_file); + else + { + /* Externe Datei laden. */ + tcppoi->status = TCP_URI; + /* Binaertransfer. */ + tcppoi->http = TCP_BIN; + } + } + /* HTML-Code. */ + else + { + get_postarea("cmd=", cmd, 59, 0); + + /* Befehl? */ + if(cmd[0]) + /* Markiere Befehl. */ + head = cmd; + /* Kein Befehl. */ + else + /* String-Header setzen. */ + head = "TheNetNode V1.79"; + + /* Index laden? */ + if( (strcmp(h_uri, "/") == 0) + ||(strcmp(h_uri, "/login") == 0)) + { + /* Path setzen/offnen. */ + if (SetFileOpen(("/index.html"), tbp) == TRUE) + /* Externe HTML-Datei kann nicht geoffnet werden. */ + PutHtmlError(tbp, "http/index.html"); + else + /* Externe Datei laden. */ + tcppoi->status = TCP_URI; + } + /* evl. Kommando ausfuehren. */ + else + /* Will User einen Befehl ausfuehren? */ + if (stricmp(h_uri, "/cmd") == 0) + { + /* Befehl fuer spaeter sichern. */ + strncpy(tcppoi->cmd, head, RXLEN); + /* Laenge setzen. */ + tcppoi->cmdlen = strlen(tcppoi->cmd); + + /* Path setzen/offnen. */ + if (SetFileOpen(("/cmd.html"), tbp) == TRUE) + /* Externe HTML-Datei kann nicht geoffnet werden. */ + PutHtmlError(tbp, "/cmd.html"); + else + { + /* Externe Datei laden. */ + tcppoi->status = TCP_URI; + /* Befehl ausfuehren. */ + tcppoi->http = TCP_CMD; + } + } + /* evl. Verzeichnis/Datei listen. */ + else + { + DIR *Tree; + char call[10]; + char Buffer1[256]; + char Buffer2[256]; + char *IndexPath = Buffer1; + char *ParentPath =Buffer2; + + /* Pruefe Index-Verzeichnis. */ + if ((Tree = CheckPath(tbp, h_uri)) != NULL) + { + /* Index-Verzeichnis setzen. */ + SetIndexPath(h_uri, IndexPath); + + /* Markiere, html/text. */ + h_mimetype = TXT; + /* Neuen HTML-Haeder erzeugen. */ + PrepareHeader(tbp); + + /* Aktuellen Header einlesen/schreiben. */ + PutHeader(tbp, "TheNetNode V1.79", FALSE); + + /* HTML Elemente setzen. */ + putprintf(tbp, "\n \n Index of %s\n \n \n", IndexPath); + putprintf(tbp, "

    Index of %s

    \n", IndexPath); + putprintf(tbp, "
    \n\n \n  \n  \n \n");
    +            putprintf(tbp, " \n  \n  \n \n");
    +
    +            /* Parent-Verzeichnis setzen. */
    +            SetParentPath(h_uri, ParentPath);
    +
    +            putprintf(tbp, " \n 
      \n \n \n", ParentPath); + + /* Verzeichnisse/Dateien Listen. */ + DirList(tbp, Tree, IndexPath); + + call2str(call, myid); + putprintf(tbp, "\n
      NameSize
      "); + putprintf(tbp, "
    • Parent Directory
    •  
      \n
      \n"); + putprintf(tbp, "
      HTTPD-Server TheNetNode V1.79 - Server at %s Port %d
      ", call, Htons(ifp[HTP_ID].tcpport)); + + /* Buffer entsorgen. */ + closedir(Tree); + } + /* Auch kein Befehl. */ + /* Dann kann es nur eine externe HTML-Datei sein. */ + else + /* Path setzen/offnen. */ + if (SetFileOpen(h_uri, tbp) == TRUE) + /* Externe HTML-Datei kann nicht geoffnet werden. */ + PutHtmlError(tbp, h_uri); + else + /* Externe Datei laden. */ + tcppoi->status = TCP_URI; + } + } + } + /* Ist der Buffer gefuellt und gibt es eine anfrage. */ + if ((tbp->mbpc) && (h_uri[0])) + { + /* Buffer zurueck spulen. */ + rwndmb(tbp); + /* Buffer umhaengen in die Sendeliste. */ + relink((LEHEAD *) tbp, (LEHEAD *)tcppoi->outbuf.tail); + /* Markiere, Frame in Sendeliste. */ + ++tcppoi->outlin; + } + /* Es gibt keine Anfrage, damit auch kein Buffer. */ + else + { + /* Buffer entsorgen. */ + dealmb(tbp); + tcppoi->disflg |= 0x80; + } +} + +/* Aktuelle Zeichen auswerten. */ +TRILLIAN GetContensHTP(char contens) +{ + int i = 0; + char s[RXLEN]; +#ifdef DEBUG_MODUS + lastfunc = "l1http(GetContensHTP)"; +#endif /* DEBUG_MODUS */ + + /* Alles auf 0 setzen. */ + tcppoi->cmdlen = 0; + tcppoi->rxc = 0; + + /* Es gibt Zeichen? */ + if (!tcppoi->RecvLen) + /* Nein, brechen wir ab. */ + return(ERRORS); + + /* Alle Zeichen vom Socket holen. */ + while (tcppoi->rxc < tcppoi->RecvLen) + { + /* Aktuelle Zeichen. */ + s[i] = tcppoi->rxbuf[tcppoi->rxc++]; + /* Zeichen ein LF-Return. */ + if (s[i] == LF) + /* zum naechsten Zeichen. */ + continue; + + /* Zeichen ein Return? */ + if (s[i] == CR) + { + /* Return setzen. */ + tcppoi->cmd[tcppoi->cmdlen++] = CR; + /* zum naechsten Zeichen. */ + continue; + } + + /* Aktuelles Zeichen setzen. */ + tcppoi->cmd[tcppoi->cmdlen++] = s[i++]; + } + + /* Nullzeichen setzen. */ + tcppoi->cmd[tcppoi->cmdlen] = '\0'; + /* Frame ist komplett. */ + return(YES); +} + +/* String in Buffer schreiben. */ +static void PutWcard(MBHEAD *tbp, char *buf) +{ + WORD i = strlen(buf); + int j = 0; +#ifdef DEBUG_MODUS + lastfunc = "l1http(PutWcard)"; +#endif /* DEBUG_MODUS */ + + while (j != i && j != 256) + /* Zeichen in Buffer schreiben. */ + putchr(buf[j++], tbp); +} + +/* Suche nach Platzhalter. Findet man einen */ +/* senden wir den jeweiligen String */ +static void search_wildcard(MBHEAD *tbp, char buffer) +{ + char strbuf[256 + 1]; + char call[10]; + static char wildcard = 0; +#ifdef DEBUG_MODUS + lastfunc = "l1http(search_wildcard)"; +#endif /* DEBUG_MODUS */ + + /* Ist Zeichen ein Platzhalter? */ + if ((wildcard == '~') || (buffer == '~')) + { + /* Aktuelles Zeichen sichern. */ + wildcard = buffer; + + switch (buffer) + { + /* Autorstring */ + case 'a': + strncpy(strbuf, author, 256); + /* String in Buffer schreiebn.*/ + PutWcard(tbp, strbuf); + return; + + /* Befehl ausfuehren. */ + case 'b': + /* Befehl weiterleiten. */ + PutComand(); + /* Conversion IBM -> HTML einschalten. */ + tcppoi->http = TCP_CMD; + /* Markiere, Befehl ausfuehren. */ + tcppoi->status = TCP_CMD; + return; + + /* IP-Adresse. */ + case 'i': + strncpy(strbuf, tcppoi->ip, 256); + /* String in Buffer schreiben. */ + PutWcard(tbp, strbuf); + return; + + /* Loginstring. */ + case 'l': + strncpy(strbuf, loginstr, 256); + /* String in Buffer schreiben. */ + PutWcard(tbp, strbuf); + return; + + /* Mycall. */ + case 'm': + call2str(call,myid); + strncpy(strbuf, call, 256); + /* String in Buffer schreiben. */ + PutWcard(tbp, strbuf); + return; + + /* Login-Rufzeichen. */ + case 'r': + /*Login als GAST */ + if (tcppoi->Upcall[0] == FALSE) + { + strncpy(strbuf, "GUEST", 5); + strbuf[5] = 0; + /* String in Buffer schreiben. */ + PutWcard(tbp, strbuf); + return; + } + + /* Login als USER */ + call2str(call, tcppoi->Upcall); + strncpy(strbuf, call, 256); + /* String in Buffer schreiben. */ + PutWcard(tbp, strbuf); + return; + + /* Dateiname sichern. */ + case 'u': + /* index.html? */ + if(strcmp(h_uri, "/") == 0) + strncpy(strbuf, "/http/index.html", 256); + /* Keine index.html. */ + else + strncpy(strbuf, h_uri, 256); + + /* String in Buffer schreiben. */ + PutWcard(tbp, strbuf); + return; + + /* TCP-Port. */ + case 'p': + sprintf(strbuf,"%d", Htons(ifp[HTP_ID].tcpport)); + PutWcard(tbp, strbuf); + return; + + /* Platzhalter. */ + case '~': + /* Bei Binaertransfer keine */ + /* Beachtung auf Platzhalter */ + if (tcppoi->http != TCP_BIN) + /* Binaertransfer, abbruch. */ + return; + } + } + /* Zeichen in Buffer schreiben. */ + putchr((wildcard = (char)buffer), tbp); +} + +/* Externe HTML-Datei laden. */ +BOOLEAN load_uri(void) +{ + SENDTX *STx = NULL; + register int i = 0; + WORD c; + BOOLEAN end = TRUE; + /* Kein Frame in der Warteschlange. */ + int mem = (nmbfre_max / 2); + +#ifdef DEBUG_MODUS + lastfunc = "l1http(load_uri)"; +#endif /* DEBUG_MODUS */ + + /* Frame in der Warteschlange. */ + if (tcppoi->outlin) + { + /* TX-Segment besorgen. */ + if ((STx = (SENDTX *)allocb(ALLOC_L1HTTPD_TX)) == NULL) + { + /* Seqment auf Disc setzen. */ + tcppoi->disflg |= 0x80; + /* Kein Speicher frei. */ + return(FALSE); + } + + /* Hole Frame aus der Warteschlange. */ + STx->Data = (MBHEAD *)ulink((LEHEAD *)tcppoi->outbuf.head); + /* Entferne Markierung aus der Warteschlange. */ + --tcppoi->outlin; + + /* Socket setzen. */ + STx->Sock = tcppoi->sock; + /* Interface setzen, */ + STx->Interface = tcppoi->Interface; + /* Stack-Mode setzen. */ + STx->Mode = tcppoi->mode; + + /* Buffer zurueckspulen.*/ + rwndmb(STx->Data); + /* Buffer in die Sendeliste haengen. */ + relink((LEHEAD *) STx, (LEHEAD *)rxflTX.tail); + /* Frame senden. */ + return(TRUE); + } + + /* Pruefen, ob genug Speicher vorhanden ist. */ + if ( (nmbfre < 300) + ||(mem < (nmbfre_max - nmbfre))) + { + /* ggf. Logbuch fuehren. */ + ifpp = SetInterface(tcppoi->Interface); + T_LOGL2(TRUE, "(load_url):%s\nSpeicher (%d) ist voll!\n" + , tcppoi->ip + , nmbfre); + /* Segment auf Disc setzen. */ + tcppoi->disflg |= 0x80; + /* Kein Speicher frei. */ + return(FALSE); + } + +/* TX-Segment besorgen. */ + if ((STx = (SENDTX *)allocb(ALLOC_L1HTTPD_TX)) == NULL) + { + /* ggf. Logbuch fuehren. */ + ifpp = SetInterface(tcppoi->Interface); + T_LOGL2(TRUE, "(load_url):%s\nSpeicher (%d) ist voll!\n" + , tcppoi->ip + , nmbfre); + /* Segment auf Disc setzen. */ + tcppoi->disflg |= 0x80; + /* Kein Segment frei, abbruch. */ + return(FALSE); + } + + /* Buffer besorgen.*/ + if ((STx->Data = SetBuffer()) == NULL) + { + /* TX-Segment entsorgen.*/ + dealoc((MBHEAD *)ulink((LEHEAD *)STx)); + + /* ggf. Logbuch fuehren. */ + ifpp = SetInterface(tcppoi->Interface); + T_LOGL2(TRUE, "(load_url):%s\nSpeicher (%d) ist voll!\n" + , tcppoi->ip + , nmbfre); + + /* Seqment auf Disc setzen. */ + tcppoi->disflg |= 0x80; + /* Buffer ist voll, abbruch. */ + return(FALSE); + } + + /* Socket setzen. */ + STx->Sock = tcppoi->sock; + /* Interface setzen. */ + STx->Interface = tcppoi->Interface; + /* Stack-Mode setzen. */ + STx->Mode = tcppoi->mode; + + /* Fehler beim Offnen der externen HTML-Datei. */ + if (tcppoi->fp == NULL) + { + /* Buffer entsorgen. */ + dealmb(STx->Data); + /* Seqment auf Disc setzen. */ + tcppoi->disflg |= 0x80; + /* ggf. Logbuch fuehren. */ + ifpp = SetInterface(tcppoi->Interface); + T_LOGL2(TRUE, "(load_url):%s\nDatei ist nicht geoeffnet!\n" + , tcppoi->ip); + return(FALSE); + } + + /* max. 1024 Zeichen einlesen/schreiben. */ + for (; STx->Data->mbpc < 1024; ++i) + { + /* Es wird ein Befehl ausfuehren. */ + if (tcppoi->status == TCP_CMD) + /* Ja, dann spaeter den restlichen html-code laden. */ + break; + + + /* aktuelle Zeichen holen. */ + if ((c = fgetc(tcppoi->fp)) == EOF) + { + /* Dateiende erreicht. */ + end = FALSE; + /* Schleife abbrechen. */ + break; + } + + /* Bei Binaertranfer keine durchsuchung von Wildcards. */ + if (tcppoi->http == TCP_BIN) + /* Schreibe Zeichen in Buffer. */ + putchr((char)(c), STx->Data); + /* Text-Transfer. */ + else + /* Nach Wildcard suchen, ggf auswerten */ + /* und in Buffer schreiben. */ + search_wildcard(STx->Data, (char)(c)); + } + + /* Dateiende erreicht. */ + if (end == FALSE) + { + /* Externe HTML-Datei schliessen. */ + fclose(tcppoi->fp); + + /* ggf. Logbuch fuehren. */ + ifpp = SetInterface(tcppoi->Interface); + T_LOGL2(TRUE, "(load_url):%s\nDatei wird geschlossen.\n" + , tcppoi->ip); + + /* File-Pointer zuruecksetzen. */ + tcppoi->fp = NULL; + /* Markiere, Download abgeschlossen. */ + tcppoi->status = TCP_NULL; + /* Seqment auf Disc setzen. */ + tcppoi->disflg |= 0x80; + } + + /* Buffer zurueckspulen.*/ + rwndmb(STx->Data); + /* Buffer in die Sendeliste haengen. */ + relink((LEHEAD *) STx, (LEHEAD *)rxflTX.tail); + return(TRUE); +} + +void PutHtmlEnd(void) +{ + SENDTX *STx; +#ifdef DEBUG_MODUS + lastfunc = "l1http(PutHtmlEnd)"; +#endif /* DEBUG_MODUS */ + + if ((STx = (SENDTX *)allocb(ALLOC_L1HTTPD_TX)) == NULL)/* TX-Segment besorgen. */ + { + /* ggf. Logbuch fuehren. */ + ifpp = SetInterface(tcppoi->Interface); + T_LOGL2(TRUE, "(PutHtmlEnd):%s\nSpeicher (%d) ist voll!\n" + , tcppoi->ip + , nmbfre); + tcppoi->disflg |= 0x80; + return; /* Kein Segment frei, abbruch. */ + } + + if ((STx->Data = SetBuffer()) == NULL) /* Buffer besorgen. */ + { + dealoc((MBHEAD *)ulink((LEHEAD *)STx)); /* TX-Segment entsorgen.*/ + + /* ggf. Logbuch fuehren. */ + ifpp = SetInterface(tcppoi->Interface); + T_LOGL2(TRUE, "(PutHtmlEnd):%s\nSpeicher (%d) ist voll!\n" + , tcppoi->ip + , nmbfre); + tcppoi->disflg |= 0x80; + return; /* Buffer ist voll, abbruch. */ + } + + STx->Sock = tcppoi->sock; + STx->Interface = tcppoi->Interface; + STx->Mode = tcppoi->mode; /* Stack-Mode setzen. */ + + putprintf(STx->Data, "\n
      "); + + rwndmb(STx->Data); /* Buffer zurueckspulen.*/ + /* Buffer in die Sendeliste haengen. */ + relink((LEHEAD *) STx, (LEHEAD *)rxflTX.tail); +} +#endif +/* End of os/win32/httpd.c */ diff --git a/src/l1ipconv.c b/src/l1ipconv.c new file mode 100755 index 0000000..315176b --- /dev/null +++ b/src/l1ipconv.c @@ -0,0 +1,746 @@ +#include "tnn.h" + +#ifdef L1IPCONV + +/* Zeiger auf das Aktuelle Interface. */ +static T_INTERFACE *ifpp; + +/* Anzahl der aktuellen IP-CONVERS-Routen auf 0 setzen. */ +int ip_tbl_top = 0; + + +#ifdef OS_IPLINK +/******************************************************************************/ +/* */ +/* IPC-Routen ausgeben. */ +/* */ +/******************************************************************************/ +static void ShowIpcEntry(struct iptbl iPC, MBHEAD *buf) +{ + char TmpCall[10]; +#ifdef DEBUG_MODUS + lastfunc = "l1ipconv(ShowIpcEntry)"; +#endif /* DEBUG_MODUS */ + + buf->l4time = buf->mbpc; /* erst mal merken, wo wir sind */ + + call2str(TmpCall, iPC.name); /* Konvertiere Rufzeichen. */ + putprintf(buf, "%s", TmpCall); + + putspa(10, buf); + show_ip_addr(Ntohl(iPC.ipaddr), buf); /* IP-Adresse ausgeben. */ + + putspa(27, buf); + putnum(iPC.port, buf); /* TCP-Port ausgeben. */ + + putspa(33, buf); + putprintf(buf, "%s\r", (iPC.linkflag ? "LINK" : "USER")); /* Status ausgeben*/ +} +#endif /* OS_IPLINK */ + +/* IP-CONVERS-Server Einstellung aendern/setzen. */ +void ccpipconv(void) +{ + MBHEAD *mbp; +#ifdef OS_IPLINK + struct hostent *he; + UBYTE tip[4]; + unsigned char tmpip[IPADDR + 1]; + unsigned char tmphost[HNLEN]; + unsigned int tmptport; + register int i; + char tmpcall[L2IDLEN]; + BOOLEAN tmplink = FALSE; +#endif /* OS_IPLINK */ + char ch; + int tmp_fd = EOF; + int newloglevel = 0; + unsigned int new_tcp_port = 0; +#ifdef DEBUG_MODUS + lastfunc = "l1ipconv(ccpipconv)"; +#endif /* DEBUG_MODUS */ + + ifpp = &ifp[CVS_ID]; /* Zeiger auf das IPCONV-Interface. */ + + /* Sysop will aendern? */ + if (issyso() && skipsp(&clicnt, &clipoi)) + { + clicnt--; + ch = toupper(*clipoi++); + switch (ch) + { + /* Sysop will IPCONV-Port aendern */ + case 'P': + if (!skipsp(&clicnt, &clipoi)) + { + putmsg("Invalid Parameter\r"); + return; + } + + /* Neuen TCP Port einlesen. */ + new_tcp_port = nxtlong(&clicnt, &clipoi); + + if ( (new_tcp_port <= 0) + ||(new_tcp_port > 65535)) + { +#ifdef SPEECH + putmsg(speech_message(328)); +#else + putmsg("IPCONV-Port not valid, not changed !!!\r"); +#endif + return; + } + + /* Wenn NEUER TCP-Port und ALTER TCP-Port */ + /* GLEICH sind, brauchen wir nix aendern. */ + if (ifpp->tcpport == Htons((unsigned short)new_tcp_port)) + { + putmsg("TCP-Port successfully changed\r"); + return; + } + + /* Ist IPCONV-Server aktiv ? */ + if (ifpp->actively == FALSE) + { +#ifdef SPEECH + putmsg(speech_message(327)); +#else + putmsg("TCP-Port haven not switched on!\r"); +#endif + return; + } + + if ((tmp_fd = SetupTCP(ifpp->name, (unsigned short)new_tcp_port)) != EOF) + { +#ifdef OS_STACK + int tmp_fd_OS; + + if ((tmp_fd_OS = SetupOS(ifpp, (unsigned short)new_tcp_port)) != EOF) + { + /* alten Socket schliessen */ + close(ifpp->OsSock); + /* Neuen Socket merken */ + ifpp->OsSock = tmp_fd_OS; + } + else + { + Close(tmp_fd); + putmsg("ERROR: Changing UDP-Port failed, Port not changed !!!\r"); + return; + } +#endif /* OS_STACK */ + + Close(ifpp->ISock); /* Alten Socket schliessen. */ + ifpp->ISock = tmp_fd ; /* Neuen Socket merken */ + } + else + { /* Neuen TCP-Port liess sich nicht Initialisieren. */ + putmsg("ERROR: Changing UDP-Port failed, Port not changed !!!\r"); + return; + } + + /* TCP-Port OK, dann markieren wir neuen TCP-Port. */ + ifpp->tcpport = Htons((unsigned short)new_tcp_port); + +#ifdef SPEECH + putmsg(speech_message(330)); +#else + putmsg("TCP-Port successfully changed\r"); +#endif + return; + + /* Sysop will LOGLevel aendern */ + case 'L': + if (!skipsp(&clicnt, &clipoi)) + { + /* Keine Parameter angegeben, */ + /* status Loglevel anzeigen. */ + mbp = putals("IPCONVER-Server:\r"); +#ifdef SPEECH + putprintf(mbp, speech_message(299),ifpp->log); +#else + putprintf(mbp, "My LogLevel: %d\r",ifpp->log); +#endif + prompt(mbp); + seteom(mbp); + return; + } + + /* Markiere neuen Loglevel */ + newloglevel = nxtnum(&clicnt, &clipoi); + + if ( (newloglevel < 0) + ||(newloglevel > 3)) + { + mbp = putals("IPCONVERS-Server:\r"); +#ifdef SPEECH + putprintf(mbp, speech_message(325)); +#else + putprintf(mbp, "Fehler: Loglevel werte von 0 bis 3!\r"); +#endif + prompt(mbp); + seteom(mbp); + return; + } + + /* Neuen Loglevel Sysop setzen. */ + ifpp->log = newloglevel; + + mbp = putals("IPCONVERS-Server:\r"); +#ifdef SPEECH + putprintf(mbp, speech_message(299), ifpp->log); +#else + putprintf(mbp, "My Loglevel: %d\r", ifpp->log); +#endif + prompt(mbp); + seteom(mbp); + return; + break; + +#ifdef OS_IPLINK + /* Route eintragen/loeschen. */ + case 'R': + /* Steht noch was im Buffer? */ + if (!skipsp(&clicnt, &clipoi)) + { + putmsg("Invalid Parameter\r"); + return; + } + + /* Leerzeile loeschen. */ + clicnt--; + switch (*clipoi++) + { + /* Route loeschen? */ + case '-': + /* Steht noch was im Buffer? */ + if (!skipsp(&clicnt, &clipoi)) + { + putmsg("Invalid Parameter\r"); + return; + } + + /* IPConver-Route loeschen. */ + IPConvDelTBL(clipoi); + break; + + /* Neue Route eintragen. */ + case '+': + /* Steht noch was im Buffer? */ + if (!skipsp(&clicnt, &clipoi)) + { + putmsg("Invalid Parameter\r"); + return; + } + + /* Call lesen */ + if (getcal(&clicnt, &clipoi, TRUE, (char *)tmpcall) != YES) + { + invcal(); + return; + } + + /* Steht noch was im Buffer? */ + if (!skipsp(&clicnt, &clipoi)) + { + putmsg("Invalid Parameter\r"); + return; + } + + /* Hostname/IP-Adresse einlesen. */ + for (i = 0; i < HNLEN; ++i) + { + /* Keine Zeichen oder leerzeichen? */ + if (!clicnt || *clipoi == ' ') + /* Schleife abbrechen. */ + break; + + clicnt--; + /* Aktuelles zeichen in TBL schreiben. */ + tmphost[i] = *clipoi++; + } + tmphost[i] = NUL; + /* Hostname oder IP-Adresse pruefen. */ + he = gethostbyname((char *)tmphost); + + /* IP-Adresse OK? */ + if (he == NULL) + { + /* Hostname nicht bekannt oder */ + /* IP-Adresse ungueltig. */ + putmsg("Invalid Parameter\r"); + return; + } + + (void)memcpy(tip, he->h_addr_list[0], 4); + /* Kopiere IP-Adresse in TBL. */ + sprintf((char *)tmpip, "%d.%d.%d.%d" + ,tip[0] + ,tip[1] + ,tip[2] + ,tip[3]); + + /* Steht noch was im Buffer? */ + if (!skipsp(&clicnt, &clipoi)) + { + putmsg("Invalid Parameter\r"); + return; + } + + /* TCP-Port einlesen. */ + tmptport = nxtlong(&clicnt, &clipoi); + + /* Pruefen ob der TCP-Port gueltig ist. */ + if ( tmptport <= 0 + ||tmptport > 65535) + { + putmsg("Invalid Parameter\r"); + return; + } + + /* Steht noch was im Buffer? */ + if (!skipsp(&clicnt, &clipoi)) + tmplink = FALSE; + else + if (!strncasecmp(clipoi, "LINK", clicnt)) + tmplink = TRUE; + else + tmplink = FALSE; + /* Neue IPC-Route hinzufuegen. */ + IPConvAddTBL(tmpcall, /* Rufzeichen. */ + tmphost, /* Hostname/IP-Adresse. */ + he, /* IP-Adresse. */ + (unsigned short)tmptport, /* TCP-Port. */ + tmplink); /* Status: USER/LINK-Modus. */ + } + break; +#endif /* OS_IPLINK */ + + default: + putmsg("Invalid Parameter\r"); + return; + } + } + mbp = putals("IPCONVERS-Server"); + putprintf(mbp,":(%d/%d):\r", ip_tbl_top, MAX_ROUTEN); + +#ifdef OS_IPLINK + putstr("Name------IP---------------Port--Status-\r", mbp); + + for (i = 0; i < ip_tbl_top; ++i) + ShowIpcEntry(ip_tbl[i], mbp); + + putstr("\r", mbp); +#endif /* OS_IPLINK */ +#ifdef SPEECH + putprintf(mbp, speech_message(299), ifpp->log); + putprintf(mbp, speech_message(326), Ntohs(ifpp->tcpport)); +#else + putprintf(mbp, "My Loglevel: %u\r", ifpp->log); + putprintf(mbp, "My TCP-Port: %u\r", Ntohs(ifpp->tcpport)); +#endif + prompt(mbp); + seteom(mbp); +} + +/******************************************************************************/ +/* */ +/* Im Convers anmelden. */ +/* */ +/******************************************************************************/ +void IPConvLogin(void) +{ + PTCENT *ptcp; +#ifdef DEBUG_MODUS + lastfunc = "l1ipconv(IPConvLogin)"; +#endif /* DEBUG_MODUS */ + + cpyid(usrcal, tcppoi->Upcall); /* Usercall setzen fuer CVS. */ + + clipoi = tcppoi->cmd; /* ggf. Channel setzen. */ + clicnt = tcppoi->cmdlen; /* laenge setzen. */ + + ptcp = ptctab + g_uid(tcppoi, TCP_USER);/* User aus der patchcord ermitteln.*/ + ptcp->state = C_IPLINK; /* Option fuer USER-Ausgabe setzen. */ + + userpo = ptcp->ublk; /* Userblock-Zeiger lesen. */ + userpo->convflag = 1; /* Connect von aussen!. */ +#ifdef L1IRC + userpo->IrcMode = tcppoi->IrcMode; +#endif /* L1IRC */ + + ccpcvs(); /* Login in den Convers. */ + + ifpp = SetInterface(tcppoi->Interface); /* akt. Interface setzen. */ + /* ggf. Logbuch fuehren. */ + T_LOGL2(TRUE, "(IPConvogin):%s\n.Login in den Convermodus.\n" + , tcppoi-> ip); + return; +} + +/* Aktuelle Zeichen auswerten. */ +TRILLIAN GetContensCVS(char contens) +{ + int i = 0; + char s[RXLEN]; +#ifdef DEBUG_MODUS + lastfunc = "l1ipconv(GetContensCVS)"; +#endif /* DEBUG_MODUS */ + + /* Linkpartner? */ + if (tcppoi->CVSlink) + { + /* Alles auf 0 setzen. */ + tcppoi->cmdlen = 0; + tcppoi->rxc = 0; + + /* Alle Zeichen vom Socket holen. */ + while (tcppoi->rxc < tcppoi->RecvLen) + { + /* Aktuelle Zeichen. */ + s[i] = tcppoi->rxbuf[tcppoi->rxc++]; + + /* Zeichen ein Return? */ + if (s[i] == CR) + /* zum naechsten Zeichen. */ + continue; + + /* Zeichen ein Return? */ + if (s[i] == LF) + { + tcppoi->cmd[tcppoi->cmdlen++] = CR; + /* zum naechsten Zeichen. */ + continue; + } + + /* Aktuelles Zeichen setzen. */ + tcppoi->cmd[tcppoi->cmdlen++] = s[i++]; + } + /* Nullzeichen setzen. */ + tcppoi->cmd[tcppoi->cmdlen] = 0; + /* Frame ist komplett. */ + return(YES); + } + else + /* User */ + { + /* Zeichen ein Return? */ + if (contens == CR) + /* Markiere es das es ein Return gibt. */ + tcppoi->cr = TRUE; + + /* Zeichen ein LF-Return? */ + if (contens == LF) + /* LF moegen wir nicht. */ + /* zum naechsten Zeichen. */ + return(NO); + + /* Alle Zeichen durch. */ + if (contens == (int)NULL) + { + /* War ein Return dabei? */ + if (tcppoi->cr) + { + tcppoi->cr = FALSE; + /* Frame ist komplett. */ + return(YES); + } + else + /* Return fehlt, */ + return(ERRORS); + } + + /* User noch nicht eingeloggt? */ + if (!tcppoi->login) + { + /* Zeichen auf Gueltigkeit pruefen. */ + if (CheckContens(contens)) + { + /* Ist es ein Linkpartner? */ + if (!strncmp(tcppoi->cmd, "ppconvers", 9)) + tcppoi->CVSlink = TRUE; + else + /* Ungueltiges Zeichen. */ + /* zum naechsten Zeichen. */ + return(NO); + } + } + + /* Aktuelle Zeichen setzen. */ + tcppoi->cmd[tcppoi->cmdlen++] = contens; + /* Zum naechsten Zeichen. */ + return(NO); + } + + return(ERRORS); +} + +#ifdef OS_IPLINK +/* Speichern der IPCONV-Routen. */ +void IPConvDump(MBHEAD *mbp) +{ + int i; + char tmp[10]; + char *linkstatus[] = {"User","Link"}; +#ifdef DEBUG_MODUS + lastfunc = "l1ipconv(IPConvDump)"; +#endif /* DEBUG_MODUS */ + + putstr("; IPConv Routen\r;\r",mbp); + + for (i = 0; i < ip_tbl_top; i++) + { + call2str(tmp, (char *)ip_tbl[i].name); + putprintf(mbp,"IPC R + %s %s %u %s\r" + ,tmp + ,ip_tbl[i].hostname + ,ip_tbl[i].port + ,ip_tbl[i].linkflag ? linkstatus[ip_tbl[i].linkflag] : linkstatus[ip_tbl[i].linkflag]); + } + putstr(";\r", mbp); +} + +/******************************************************************************/ +/* */ +/* IPC-Route in TBL suchen. */ +/* */ +/******************************************************************************/ +int IPConvIS(char *name, DEST *dest) +{ + register int i; +#ifdef DEBUG_MODUS + lastfunc = "l1ipconv(IPConvIS)"; +#endif /* DEBUG_MODUS */ + + for (i = 0; i < ip_tbl_top; i++) /* Alle Eintraege durch gehen. */ + { + if (cmpid(name, (char *)ip_tbl[i].name)) /* Rufzeichenvergleich. */ + { + cpyid(dest->call, (char *)ip_tbl[i].name); /* Rufzeichen setzen. */ + dest->port = ip_tbl[i].l2port; /* L2-Port setzen. */ + + dest->via[0] = 0; /* defaultwerte setzen. */ + dest->typ = 'U'; + dest->eax = 0; + + return(TRUE); /* Eintrag gefunden. */ + } + } + + return(FALSE); /* Kein eintrag gefunden. */ +} + +/* Rufzeichen in der IPC-TBL suchen. */ +int IPConvSearch(char *call) +{ + register int i = 0; +#ifdef DEBUG_MODUS + lastfunc = "l1ipconv(IPConvSearch)"; +#endif /* DEBUG_MODUS */ + + /* Alle Eintraege durch gehen. */ + for (i = 0; i < ip_tbl_top; ++i) + { + /* Vergleiche Call/SSID. */ + if (cmpid(call, (char *)ip_tbl[i].name)) + /* i = TBL-Nummer vom CALL. */ + return(i); + } + /* Es gibt keinen Eintrag mit dem */ + /* gesuchten Rufzeichen. */ + return(EOF); +} + +/*****************************************************************************/ +/* */ +/* Neue IPC-Route hinzufuegen */ +/* */ +/*****************************************************************************/ +void IPConvAddTBL(char *call, + unsigned char *host, + struct hostent *hstent, + unsigned short tport, + BOOLEAN link) +{ + register int i; +#ifdef DEBUG_MODUS + lastfunc = "l1ipconv(IPConvAddTBL)"; +#endif /* DEBUG_MODUS */ + /* Suche Rufzeichen in der TBL. */ + if ((i = IPConvSearch(call)) != EOF) + { /* IPC-Route Aktualisieren. */ + (void)memcpy(ip_tbl[i].hostname, host, HNLEN); /* Hostname setzen. */ + + ip_tbl[i].l2port = ifp[CVS_ID].l2port; /* L2-Port setzen. */ + ip_tbl[i].port = tport; /* TCP-Port setzen. */ + ip_tbl[i].linkflag = link; /* Status: User/Link setzen. */ + } + else /* IPC-Route hinzufuegen. */ + { + cpyid(ip_tbl[ip_tbl_top].name, call); /* Rufzeichen setzen*/ + + (void)memcpy(ip_tbl[ip_tbl_top].hostname, host, HNLEN);/* Hostname setzen.*/ + (void)memcpy((unsigned char*)&ip_tbl[ip_tbl_top].ipaddr, (unsigned char *)&hstent->h_addr_list[0][0], 4); + + ip_tbl[ip_tbl_top].l2port = ifp[CVS_ID].l2port; /* L2-Port eintragen. */ + ip_tbl[ip_tbl_top].port = tport; /* TCP-Port eintragen. */ + ip_tbl[ip_tbl_top].linkflag = link; /* Status: User/Link setzen. */ + + ip_tbl_top++; /* Ein Tabelleneintrag mehr */ + } +} + +/* IPCONV-Route loeschen. */ +BOOLEAN IPConvDelTBL(char *name) +{ + register int i; + register int j; + char tmp[10]; + char *tmppoi = name; + WORD tmpcnt = strlen(name); +#ifdef DEBUG_MODUS + lastfunc = "l1ipconv(IPConvDelTBL)"; +#endif /* DEBUG_MODUS */ + + getcal(&tmpcnt, &tmppoi, TRUE, tmp); + + for (i = 0; i < ip_tbl_top; ++i) + { + if (cmpid(tmp, (char *)ip_tbl[i].name)) + { + for (j = i; j < ip_tbl_top; ++j) + ip_tbl[j] = ip_tbl[j+1]; + + /* Ein Tabelleneintrag weniger */ + ip_tbl_top--; + return(TRUE); + } + } + return(FALSE); +} + +/* IPConvers-Hostname lesen. */ +BOOLEAN IPConvGetName(WORD *len, char **inbuf, BOOLEAN flag, char *outbuf) +{ + char name[NAMESIZE + 1]; + char *nampoi; + char zeichen; + char *p = *inbuf, *save_inbuf = *inbuf; + WORD n = *len, save_len = *len; + int plen = FALSE; +#ifdef DEBUG_MODUS + lastfunc = "l1ipconv(IPConvGetName)"; +#endif /* DEBUG_MODUS */ + + skipsp(&n, &p); + nampoi = name; + + if (n) + { + while (n > 0) + { + zeichen = (char) toupper(*p); + if (zeichen == ' ') + break; + + if ( ((zeichen >= '0') && (zeichen <= '9')) + || ((zeichen >= 'A') && (zeichen <= 'Z'))) + { + *nampoi++ = zeichen; + p++; + n--; + plen++; + + if (plen > NAMESIZE) + return(FALSE); + + continue; + } + n--; + p++; + } + + name[plen] = 0; + strncpy(outbuf, name, NAMESIZE); + + if (flag) + { + *len = save_len; + *inbuf = save_inbuf; + } + else + { + *len = n; + *inbuf = p; + } + return(TRUE); + } + return(FALSE); +} + +/* IPConvers IP-Adresse lesen,. */ +BOOLEAN IPConvGetIP(WORD *laenge, char **inbuf, unsigned char *outbuf) +{ + char ipadresse[16 + 1]; + char *ipaddrpoi; + char zeichen; + char *p = *inbuf; + WORD n = *laenge; + int len = FALSE; +#ifdef DEBUG_MODUS + lastfunc = "l1ipconv(IPConvGetIP)"; +#endif /* DEBUG_MODUS */ + + skipsp(&n, &p); + ipaddrpoi = ipadresse; + + if (n) + { + while (n > 0) + { + zeichen = (char) toupper(*p); + if (zeichen == ' ') + break; + + if ( (zeichen == '.') + || ((zeichen >= '0') && (zeichen <= '9'))) + { + *ipaddrpoi++ = zeichen; + p++; + n--; + len++; + + if (len > 16) + return(FALSE); + + continue; + } + p++; + n--; + } + + ipadresse[len] = 0; + strncpy((char *)outbuf, (char *)ipadresse, 16); + + *laenge = n; + *inbuf = p; + return(TRUE); + } + return(FALSE); +} + +int IPConvConnect(char *call, char *upcall, BOOLEAN flag) +{ +#ifdef DEBUG_MODUS + lastfunc = "l1ipconv(IPConvConnect)"; +#endif /* DEBUG_MODUS */ + + if (IPConvConnectOS(call, upcall, flag)) + return(TRUE); + + return(FALSE); +} +#endif /* OS_IPLINK */ +#endif /* L1IPCONV */ + +/* End of os/win32/ipconv.c */ diff --git a/src/l1irc.c b/src/l1irc.c new file mode 100755 index 0000000..4b286ef --- /dev/null +++ b/src/l1irc.c @@ -0,0 +1,2232 @@ +#include "tnn.h" +#ifdef L1IRC +#include "conversd.h" + +static T_INTERFACE *ifpp; /* Zeiger auf das Aktuelle Interface.*/ + +void IrcAwayCommand(CONNECTION *cp); /* Username aufloesen. */ +void IrcChannelCommand(CONNECTION *cp); /* CHANNEL-Kommando. */ +void IrcHelpCommand(CONNECTION *cp); /* Help Kommand. */ +void IrcLinksCommand(CONNECTION *cp); /* Links-Kommando. */ +void IrcListCommand(CONNECTION *cp); /* List-Kommando. */ +void IrcNickCommand(CONNECTION *cp); /* Nickname aufloesen. */ +void IrcModeCommand(CONNECTION *cp); /* Mode-Kommando. */ +void IrcNamesCommand(CONNECTION *cp); /* Names-Kommando. */ +void IrcPartCommand(CONNECTION *cp); /* Channel schliessen. */ +void IrcPersonalCommand(CONNECTION *cp); /* Personal-Text setzen/loeschen. */ +void IrcPingCommand(CONNECTION *cp); +void IrcPongCommand(CONNECTION *cp); +void IrcPrivmsgCommand(CONNECTION *cp); /* MSG-Kommando. */ +void IrcQuitCommand(CONNECTION *cp); /* Quit-Kommando. */ +void IrcUserHostCommand(CONNECTION *cp); /* */ +void IrcSquitCommand(CONNECTION *cp); +void IrcUserCommand(CONNECTION *cp); +void IrcWhoCommand(CONNECTION *cp); /* Who-Kommando. */ +void IrcWhoisCommand(CONNECTION *cp); /* Userdaten ausgeben. */ + + +typedef struct cmdtable_irc +{ + char *name; + void (*fnc)(CONNECTION *); + char *help; +} CMDTABLE_IRC; + +CMDTABLE_IRC cmdtable_irc[] = +{ + {"away", IrcAwayCommand, "AWAY"}, + {"channel", IrcChannelCommand, "CHAN"}, + {"help", IrcHelpCommand, "HELP"}, + {"nick", IrcNickCommand, "NICK"}, + {"join", IrcChannelCommand, "JOIN"}, + {"links", IrcLinksCommand, "LINKS"}, + {"list", IrcListCommand, "LIST"}, + {"mode", IrcModeCommand, "MODE"}, + {"names", IrcNamesCommand, "NAMES"}, + {"part", IrcPartCommand, "PART"}, + {"personal", IrcPersonalCommand, "PERS"}, + {"ping", IrcPingCommand, "PING"}, + {"pong", IrcPongCommand, "PONG"}, + {"privmsg", IrcPrivmsgCommand, "PRIVMSG"}, + {"quit", IrcQuitCommand, "QUIT"}, + {"user", IrcUserCommand, "USER"}, + {"userhost", IrcUserHostCommand, "USERHOST"}, + {"squit", IrcSquitCommand, "SQUIT"}, + {"who", IrcWhoCommand, "WOH"}, + {"whois", IrcWhoisCommand, "WHOIS"}, + {NULL, 0, NULL} +}; + +/* IRC-Server Einstellung aendern/setzen. */ +void ccpirc(void) +{ + MBHEAD *mbp; + char ch; + int tmp_fd = EOF; + int newloglevel = 0; + int new_tcp_port = 0; +#ifdef DEBUG_MODUS + lastfunc = "l1irc(ccpirc)"; +#endif /* DEBUG_MODUS */ + + ifpp = &ifp[IRC_ID]; /* Dann Zeiger auf das IRC-Interface. */ + + if (issyso() && skipsp(&clicnt, &clipoi)) /* Sysop will aendern. */ + { + clicnt--; + ch = toupper(*clipoi++); + + switch (ch) + { + case 'P': /* Sysop will IRC-Port aéndern */ + if (!skipsp(&clicnt, &clipoi)) + { + putmsg("Invalid Parameter\r"); + return; + } + + new_tcp_port = nxtlong(&clicnt, &clipoi); /* Neuen Port ermitteln */ + + if ( (new_tcp_port < 1) + ||(new_tcp_port > 65535)) + { + putmsg("TCP-Port not valid, not changed !!!\r"); + return; + } + + if (ifpp->actively == FALSE) /* IRC ist deaktiv.*/ + { + putmsg("TCP-Port haven not switched on!\r"); + return; + } + /* Wenn NEUER Port und ALTER Port gleich sind, nicht neu Initialisieren.*/ + if (ifpp->tcpport == Htons((unsigned short)new_tcp_port)) + { + putmsg("TCP-Port successfully changed\r"); + return; + } + + /* Neuen TCP-Port Initialisieren. */ + if ((tmp_fd = SetupTCP(ifpp->name, (unsigned short)new_tcp_port)) != EOF) + { +#ifdef OS_STACK + int tmp_fd_OS; + + if ((tmp_fd_OS = SetupOS(ifpp, (unsigned short)new_tcp_port)) != EOF) + { + /* alten Socket schliessen */ + close(ifpp->OsSock); + /* Neuen Socket merken */ + ifpp->OsSock = tmp_fd_OS; + } + else + { + Close(tmp_fd); + putmsg("ERROR: Changing UDP-Port failed, Port not changed !!!\r"); + return; + } +#endif /* OS_STACK */ + + Close(ifpp->ISock); /* Alten Socket schliessen. */ + ifpp->ISock = tmp_fd ; /* Neuen Socket merken */ + } + else + { /* Neuen TCP-Port liess sich nicht Initialisieren. */ + putmsg("ERROR: Changing UDP-Port failed, Port not changed !!!\r"); + return; + } + + + ifpp->tcpport = Htons((unsigned short)new_tcp_port); + + putmsg("TCP-Port successfully changed\r"); + return; + + case 'L': /* Sysop will LOGLevel aendern */ + if (!skipsp(&clicnt, &clipoi)) + { + mbp = putals("IRC-Server:\r"); + putprintf(mbp, "My LogLevel: %d\r",ifpp->log); /* Loglevel anzeigen. */ + + prompt(mbp); + seteom(mbp); + return; + } + + newloglevel = nxtnum(&clicnt, &clipoi); /* neuen Loglevel ermitteln. */ + + if ( (newloglevel < 0) + ||(newloglevel > 3)) /* Pruefe neuen Loglevel. */ + { + mbp = putals("IRC-Server:\r"); + putprintf(mbp, "Error: Log level worth from 0 to 3!\r"); + prompt(mbp); + seteom(mbp); + return; + } + + ifpp->log = newloglevel; /* Neuen Loglevel setzen und zeigen */ + mbp = putals("IRC-Server:\r"); + putprintf(mbp, "My Loglevel: %d\r", ifpp->log); + + prompt(mbp); + seteom(mbp); + return; + break; + + + default: /* Ungueltiger Parameter. */ + putmsg("Invalid Parameter\r"); + return; + } + } + + mbp = putals("IRC-Server:\r"); /* Aktuelle Einstellungen zeigen. */ + + putprintf(mbp, "My TCP-Port: %u\r", Ntohs(ifpp->tcpport)); + prompt(mbp); + seteom(mbp); +} + +char *get_mode_flags2irc(int flags) +{ + static char mode[16]; + char *p = mode; +#ifdef DEBUG_MODUS + lastfunc = "l1irc(get_mode_flags2irc)"; +#endif /* DEBUG_MODUS */ + + p = mode; + if (flags & M_CHAN_I) + *p++ = 's'; + + if (flags & M_CHAN_M) + *p++ = 'm'; + + if (flags & M_CHAN_T) + *p++ = 't'; + + if (flags & M_CHAN_P) + *p++ = 'i'; + + if (flags & M_CHAN_S) + *p++ = 'p'; + + // always +n + *p++ = 'n'; + //if (flags & M_CHAN_L) + //*p++ = 'l'; + //*p++ = ' '; + + *p = 0; + + return mode; +} + +/******************************************************************************/ +/* */ +/* Eingehende Befehle bearbeiten. */ +/* */ +/******************************************************************************/ +void ProcessIrcInput(char *cnvinbuf, CONNECTION *cp) +{ + CMDTABLE_IRC *IrcCmdp; + char *cmd; + char buffer[2048]; + int cmdlen; +#ifdef DEBUG_MODUS + lastfunc = "l1irc(ProcessIrcInput)"; +#endif /* DEBUG_MODUS */ + + cnvinbuf[2048] = 0; + + cmd = getarg(cnvinbuf, 0); /* Befehl einlesen. */ + + if (cmd[0] == FALSE) /* kein befehl, */ + return; /* brechen wir ab. */ + + cmdlen = strlen(cmd); /* Befehlslange ermitteln. */ + /* durchsuche Befehls-Liste. */ + for (IrcCmdp = cmdtable_irc; IrcCmdp->name; IrcCmdp++) + { + if (!strncmp(IrcCmdp->name, cmd, cmdlen)) /* Befehl vergleichen. */ + { + (*IrcCmdp->fnc) (cp); /* Befehl ausfuehren. */ + return; + } + } + /* Ungueltiger Befehl. */ + sprintf(buffer, ":%s 421 %s *** Unknown command '/%s'. Type /HELP for help.\n" + , myhostname + , (*cp->nickname ? cp->nickname : cp->name) + , cmd); + appenddirect(cp, buffer); +} + +/******************************************************************************/ +/* */ +/* Away (Ab/Anwesend) setzen. */ +/* */ +/******************************************************************************/ +void IrcAwayCommand(CONNECTION *cp) +{ + char *AwayText; + char buffer[2048]; +#ifdef DEBUG_MODUS + lastfunc = "l1irc(IrcAwayCommand)"; +#endif /* DEBUG_MODUS */ + + AwayText = getarg(NULL, GET_ALL); /* akt. Away-Text ermitteln. */ + + if (*AwayText == ':') /* ':' im String. */ + AwayText++; /* ':' loeschen. */ + + if (AwayText == NULL) /* Kein Text. */ + return; /* Keine Aenderung. */ + + cp->away = AwayText; /* Aktualisiere den aktuellen Away-Text. */ + + if (*AwayText != '\0') /* Abmelden. */ + sprintf(buffer, ":%s 301 %s %s : %s\n" /* IRC-Meldung vorbereiten, */ + , myhostname + , cp->name + , (*cp->nickname ? cp->nickname : cp->name) + , AwayText); + else /* Anmelden. */ + sprintf(buffer, ":%s 320 %s %s : is back\n" /* IRC-Meldung vorbereiten. */ + , myhostname + , cp->name + , (*cp->nickname ? cp->nickname : cp->name)); + + appendstring(cp, buffer); + +#ifndef CONVNICK + send_awaymsg(cp->name, /* Neuen Away-Text an andere Host's weiterleiten. */ + cp->hosthostname, + currtime, + AwayText); +#else + send_awaymsg(cp->name, /* Neuen Away-Text an andere Host's weiterleiten. */ + cp->nickname, + cp->host, + currtime, + AwayText); +#endif /* CONVNICK */ +} + +/******************************************************************************/ +/* */ +/* Persoenlichen Text setzen. */ +/* */ +/******************************************************************************/ +void IrcPersonalCommand(CONNECTION *cp) +{ + char *pers; + char buffer[2048]; +#ifdef DEBUG_MODUS + lastfunc = "l1irc(IrcPersonalCommand)"; +#endif /* DEBUG_MODUS */ + + pers = getarg(NULL, GET_ALL); /* akt. Pers-Text ermitteln. */ + + if (*pers) + { + if (!strcmp(pers, "@")) /* Pers-Text soll geloescht werden. */ + pers = ""; /* Pers-Text loeschen. */ + + personalmanager(SET, cp, pers); /* Datenbank aktualisieren. */ + + if (pers != cp->pers) + { + setstring(&(cp->pers), pers, 256); /* Neuen Pers-Text setzen. */ + cp->mtime = currtime; /* Aktuelle Zeit merken. */ + + sprintf(buffer, ":%s 311 %s %s %s %s * :%s\n" + , myhostname + , cp->nickname + , cp->name + , (*cp->nickname ? cp->nickname : cp->name) + , cp->host + , (*pers && *pers != '@') ? pers : ""); + appendstring(cp, buffer); + +#ifndef CONVNICK + send_persmsg(cp->name, /* Neuen Pers-Text an andere HOST's weiterleiten.*/ + myhostname, + cp->channel, + pers, + cp->time); +#else + send_persmsg(cp->name, /* Neuen Pers-Text an andere HOST's weiterleiten.*/ + cp->nickname, + myhostname, + cp->channel, + pers, + cp->time); +#endif /* CONVNICK */ + } + } +} + +void IrcNoticeCommand(CONNECTION *cp) +{ + char buffer[2048]; + int channel; + char *toname, *text; + CHANNEL *ch; + CLIST *cl; + char *q; +#ifdef DEBUG_MODUS + lastfunc = "l1irc(IrcNoticeCommand)"; +#endif /* DEBUG_MODUS */ + + *buffer = 0; + + toname = getarg(0, 0); + if (*toname && (*toname == '#' || *toname == '~')) + toname++; + + // notice commands should not be answered + if (!*toname) + return; + + text = getarg(NULL, GET_ALL); + + cp->locked = 1; + + if (*text == ':') + text++; + // dcc mess + + if ((q = strchr(text, '\001'))) + { + text = q+1; + if ((q = strchr(text, '\001'))) + *q = 0; + + if (!strncasecmp(text, "AWAY ", 5)) + { + text = text+5; + + while (*text && isspace(*text & 0xff)) + text++; + + if (strcmp(cp->away, text)) + send_awaymsg(cp->name, cp->nickname, myhostname, currtime, text); + + return; + } + + if (!strncasecmp(text, "ACTION ", 7)) + { + text = text+7; + + while (*text && isspace(*text & 0xff)) + text++; + + if (strlen(text) > 384) + text[384] = 0; + } + else + { + while (*text && isspace(*text & 0xff)) + text++; + + if (strlen(text) > 384) + text[384] = 0; + + sprintf(buffer, "*** %s@%s ack :%s:", cp->name, cp->host, text); + } + } + + if (!*buffer) + sprintf(buffer, "*** %s@%s notice: %s", cp->name, cp->host, text); + + if (isdigit(*toname & 0xff) && ((channel = atoi(toname)) > 0 || (channel == 0 && !strcmp(toname, "0")))) + { + // to channel. special care must be taken + for (ch = channels; ch; ch = ch->next) + { + if (ch->chan == channel) + break; + } + + if (!ch) + return; + + // only channels we are on (and have permission to talk) + if (cp->operator == 2) + { + ; + } + else + if (cp->channel == ch->chan) + { + if ((ch->flags & M_CHAN_M) && !cp->channelop) + return; + } + else + { + for (cl = cp->chan_list; cl; cl = cl->next) + if (cl->channel == ch->chan) + break; + + if (!cl) + return; + + if ((ch->flags & M_CHAN_M) && !cl->channelop) + return; + } + + send_msg_to_channel("conversd", (short)channel, buffer); + } + else + { + send_msg_to_user("conversd", toname, buffer); + } +} + +void IrcChannelCommand(CONNECTION *cp) +{ + char *chan; + char buffer[2048]; + WORD newchannel; + struct channel *ch; + struct clist *cl, + *cl2; +#ifdef DEBUG_MODUS + lastfunc = "l1irc(IrcChannelCommand)"; +#endif /* DEBUG_MODUS */ + + /* Channel holen. */ + chan = getarg(NULL, GET_NXTLC); + + if (*chan == '#') + chan++; + + newchannel = atoi(chan); + + for (ch = channels; ch; ch = ch->next) + { + if (ch->chan == newchannel) + break; + } + + for (cl = cp->chan_list; cl; cl = cl->next) + { + if (cl->channel == newchannel) + break; + } + + /* Gibt es einen Eintrag? */ + if (cl) + /* Ja, */ + return; + +#ifdef CONVNICK + send_user_change_msg(cp->name,cp->nickname, cp->host, -1, newchannel, cp->pers, cp->time); +#else + send_user_change_msg(cp->name,cp->host, -1, newchannel, cp->pers, cp->time); +#endif /* CONV_NICKNAME */ + + if (!ch) + cp->locked = 0; + + cl = (CLIST *)calloc(1, sizeof(CLIST)); + cl->time = currtime; + cp->mtime = currtime; + + if (!ch) + cl->channelop = 1; + else + cl->channelop = 0; + + cl->channel = newchannel; + + if (!cp->chan_list || cp->chan_list->channel > cl->channel) + { + cl->next = cp->chan_list; + cp->chan_list = cl; + } + else + for (cl2 = cp->chan_list; cl2; cl2 = cl2->next) + { + if (cl2->next) + { + if (cl2->next->channel > atoi(chan)) + { + cl->next = cl2->next; + cl2->next = cl; + break; + } + } + else + { + cl2->next = cl; + cl->next = NULLCLIST; + break; + } + } + + cp->channel = atoi(chan); + + sprintf(buffer,":%s!%s@%s JOIN :#%d\n" + , (*cp->nickname ? cp->nickname : cp->name) + , cp->name + , cp->host + , cp->channel); + appendstring(cp, buffer); + + sprintf(buffer, ":%s MODE #%d +%s\n" + ,myhostname + ,cp->channel + ,get_mode_flags2irc((ch ? ch->flags : 0))); + appendstring(cp, buffer); + + IrcNamesCommand(cp); + + if (ch) + { + if (ch->topic) + { + sprintf(buffer, ":%s 332 %s #%d :%s\n" + ,cp->host + ,(*cp->nickname ? cp->nickname : cp->name) + ,cp->channel + ,ch->topic); + appendstring(cp, buffer); + + sprintf(buffer, ":%s 333 %s #%d %s %ld\n" + , cp->host + , (*cp->nickname ? cp->nickname : cp->name) + , cp->channel + , ch->name + , ch->time); + appendstring(cp,buffer); + } + cp->channelop = cl->channelop; + } +} + +/* Mode einstellen. */ +void IrcModeCommand(CONNECTION *cp) +{ + CONNECTION *p; + CHANNEL *ch; + CLIST *cl; + char buffer[2048]; + char *arg, + *c; + int remove = 0; + int channel = 0; + int oldflags = 0; + int op = 0; +#ifdef DEBUG_MODUS + lastfunc = "l1irc(IrcModeCommand)"; +#endif /* DEBUG_MODUS */ + + arg = getarg(0, 0); + + if (*arg == ':') + arg++; + + if (*arg == '#') + arg++; + else + { + if (cp->IrcMode) + { + if (!strcmp(arg, "*")) + return; + + if (cp->type == CT_USER) + { + char *arg2 = getarg(0, 0); + + if (!*arg) + { + sprintf(buffer, ":%s 461 %s MODE :Not enough parameters\n" + , cp->host + , (cp->nickname ? cp->nickname : cp->name)); + appendstring(cp, buffer); + return; + } + + if (strcasecmp(arg, cp->nickname)) + { + sprintf(buffer, ":%s 403 %s %s :No such channel\n" + , cp->host + , (cp->nickname ? cp->nickname : cp->name) + , arg); + appendstring(cp, buffer); + return; + } + + *buffer = 0; + + if (!*arg2) + { + sprintf(buffer, ":%s 211 %s %s\n" + , myhostname + , cp->nickname + , (cp->verbose) ? "+sw" : ""); + } + else + { + if (strstr(arg2, "+s") || strstr(arg2, "+w")) + cp->verbose = 1; + else + if (strstr(arg2, "-s") || strstr(arg2, "-w")) + cp->verbose = 0; + else + { + sprintf(buffer, ":%s 501 %s :Unknown MODE flag: %s\n" + , cp->host + , (cp->nickname ? cp->nickname : cp->name) + , arg2); + } + + if (!*buffer) + sprintf(buffer, ":%s MODE %s %csw\n" + , myhostname + , cp->nickname + , (cp->verbose ? '+' : '-')); + + appendstring(cp, buffer); + } + return; + } + } + } + + channel = atoi(arg); + + if (*arg && !strcmp(arg, "*")) + { + channel = cp->channel; + } + else + { + if (!*arg || !(isdigit(*arg & 0xff) && (channel > 0 || (!channel && !strcmp(arg, "0"))))) + { + if (cp->type != CT_HOST) + { + if (*arg) + { + sprintf(buffer, ":%s 403 %s #%s :No such channel\n" + , cp->host + , (cp->nickname ? cp->nickname : cp->name) + , arg); + } + else + { + sprintf(buffer, ":%s 461 %s MODE :Not enough parameters\n" + , cp->host + , (cp->nickname ? cp->nickname : cp->name)); + } + + appendstring(cp, buffer); + appendprompt(cp, 0); + } + + return; + } + + arg = getarg(0, 1); + + if (!*arg && cp->type == CT_USER) + { + for (ch = channels; ch; ch = ch->next) + { + if (ch->chan == channel) + break; +/* + { + sprintf(buffer, ":%s 324 %s %s #%d +%s\n" + , cp->host + , cp->name + , (*cp->nickname ? cp->nickname : cp->name) + , channel + , get_mode_flags2irc(ch->flags)); + appendstring(cp, buffer); + + sprintf(buffer, ":%s 329 %s %s #%d %d\n" + , cp->host + , cp->name + , (*cp->nickname ? cp->nickname : cp->name) + , channel + , 0); + appendstring(cp, buffer); + appendprompt(cp, 0); + break; + }*/ + } + + if (!ch) + { + sprintf(buffer, ":%s 403 %s #%d :No such channel\n" + , cp->host + , (cp->nickname ? cp->nickname : cp->name) + , channel); + appendstring(cp, buffer); + appendprompt(cp, 0); + } + + return; + } + + for (cl = cp->chan_list; cl; cl = cl->next) + { + if (cl->channel == channel) + { + if (cl->channelop) + op++; + break; + } + } + + for (ch = channels; ch; ch = ch->next) + { + if (channel == ch->chan) + break; + } + + if (op || cp->operator == 2 || (cp->type == CT_HOST)) + { + if (!ch || (cp->type != CT_HOST && channel == 0 && cp->operator != 2)) + { + if (cp->type == CT_USER) + { + if (channel == 0) + { + sprintf(buffer, ":%s 477 %s #%d :Channel doesn't support modes\n" + , cp->host + , (cp->nickname ? cp->nickname : cp->name) + , channel); + appendstring(cp, buffer); + } + else + { + sprintf(buffer, ":%s 403 %s #%d :No such channel\n" + , cp->host + , (cp->nickname ? cp->nickname : cp->name) + , channel); + appendstring(cp, buffer); + } + } + } + + return; + } + else + { + if (cp->type == CT_USER) + return; + + oldflags = ch->flags; + + while (*arg) + { + switch (*arg) + { + case '+': + { + remove = 0; + arg++; + break; + } + + case '-': + { + remove = 1; + arg++; + break; + } + + case 'S': + case 's': + { + if (remove && ch) + { + if (!cp->IrcMode) + { + ch->flags -= (ch->flags & M_CHAN_S); + } + else + { + ch->flags -= (ch->flags & M_CHAN_I); + } + } + else + { + if (!cp->IrcMode) + { + ch->flags |= M_CHAN_S; + } + else + { + ch->flags |= M_CHAN_I; + } + } + + arg++; + break; + } + + case 'P': + case 'p': + { + if (remove && ch) + { + if (!cp->IrcMode) + { + ch->flags -= (ch->flags & M_CHAN_P); + } + else + { + ch->flags -= (ch->flags & M_CHAN_S); + } + } + else + { + if (!cp->IrcMode) + { + ch->flags |= M_CHAN_P; + } + else + { + ch->flags |= M_CHAN_S; + } + } + + arg++; + break; + } + + case 'T': + case 't': + { + if (remove && ch) + { + ch->flags -= (ch->flags & M_CHAN_T); + } + else + { + ch->flags |= M_CHAN_T; + } + + arg++; + break; + } + + case 'I': + case 'i': + { + if (remove && ch) + { + if (!cp->IrcMode) + { + ch->flags -= (ch->flags & M_CHAN_I); + } + else + { + ch->flags -= (ch->flags & M_CHAN_P); + } + } + else + { + if (!cp->IrcMode) + { + ch->flags |= M_CHAN_I; + } + else + { + ch->flags |= M_CHAN_P; + } + } + + arg++; + break; + } + + case 'L': + case 'l': + { + if (!cp->IrcMode) + { + if (remove && ch) + { + ch->flags -= (ch->flags & M_CHAN_L); + } + else + { + ch->flags |= M_CHAN_L; + } + } + else + { + sprintf(buffer, ":%s 472 %s %c :is unknown mode char to me\n" + , cp->host + , (cp->nickname ? cp->nickname : cp->name) + , *arg); + appendstring(cp, buffer); + } + + arg++; + break; + } + + case 'M': + case 'm': + { + if (remove && ch) + { + ch->flags -= (ch->flags & M_CHAN_M); + } + else + { + ch->flags |= M_CHAN_M; + } + + arg++; + break; + } + + case 'O': + case 'o': + { + arg++; + while (*arg) + { + CONNECTION *p_found = 0; + int status_really_changed = 0; + char *fromname = cp->name; + char *fromnickname = (cp->type == CT_HOST ? cp->name : cp->nickname); + int user_found = 0; + + while (*arg == ' ') + arg++; + + if (*arg == ':') + arg++; + + c = arg; + + while (*c != ' ') + { + if (*c != '\0') + { + c++; + } + else + break; + } + + if (*c != '\0') + { + *c++ = '\0'; + } + + if (cp->type != CT_HOST && channel < 0 ) + continue; + + clear_locks(); + + if (cp->type == CT_HOST) + cp->locked = 1; + + for (p = connections; p; p = p->next) + { + if (p->type != CT_USER) + continue; + + if (!(!strcasecmp(p->name, arg) || (cp->type == CT_USER && !strcasecmp(p->nickname, arg)))) + continue; + + user_found = 1; + + if (channel == -1) + { + if (!p_found || !p->operator) + p_found = p; + + if (!status_really_changed) + { + status_really_changed = (p->operator == 0); + } + } + else + { + if (p->channel == channel) + { + if (!p_found || !p->channelop) + p_found = p; + + if (!status_really_changed) + status_really_changed = (p->channelop == 0); + + p->channelop = 1; + } + + for (cl = p->chan_list; cl; cl = cl->next) + { + if (cl->channel == p->channel) + { + if (!p_found || !p->channelop) + p_found = p; + + if (!status_really_changed) + status_really_changed = (cl->channelop == 0); + + cl->channelop = 1; + } + } + } + } + + if (p_found) + { + send_opermsg(fromnickname, p_found->host, fromname, (WORD)channel, 0); + } + else + { + if (cp->type == CT_USER) + { + if (cp->IrcMode) + { + if (user_found) + sprintf(buffer, ":%s 441 %s %s #%d :They aren't on that channel\n" + , cp->host + , cp->nickname + , arg + , channel); + else + sprintf(buffer, ":%s 401 %s %s :No such nick\n" + , cp->host + , cp->nickname + , arg); + + appendstring(cp, buffer); + } + else + { + if (user_found) + sprintf(buffer, "*** User not in channel: %s.\n" + , arg); + else + sprintf(buffer, "*** No such user: %s.\n" + , arg); + + appendstring(cp, buffer); + } + } + } + + cp->locked = 1; + arg = c; + } + break; + + } + + case 'N': + case 'B': + case 'b': + case 'V': + case 'v': + case 'K': + case 'k': + case 'W': + case 'w': + { + if (cp->IrcMode) + { + sprintf(buffer, ":%s 472 %s :Unknown MODE flag (%c).\n" + , cp->host + , (cp->nickname ? cp->nickname : cp->name) + , *arg); + appendstring(cp, buffer); + } + + arg++; + break; + } + + case 'n': + default: + { + arg++; + break; + } + } + } + + if (ch && (ch->flags != oldflags)) + { + clear_locks(); // send_opermsg may have locked it.. + cp->locked = 1; + + if (cp->type == CT_USER && !cp->IrcMode) + { + appendstring(cp, "*** Flags: "); + // appendstring(cp, get_mode_flags(ch->flags)); + appendstring(cp, "\n"); + } + + //send_mode(cp, ch, oldflags); + } + } + } +//else + { + if (!ch || ((ch->flags & M_CHAN_S || ch->flags & M_CHAN_I) && !(cp->operator == 2 || cl))) + { + sprintf(buffer, ":%s 403 %s #%d :No such channel\n" + , cp->host + , (cp->nickname ? cp->nickname : cp->name) + , channel); + appendstring(cp, buffer); + } + else + { + sprintf(buffer, ":%s 482 %s #%d :You're not channel operator\n" + , cp->host + , (cp->nickname ? cp->nickname : cp->name) + , channel); + appendstring(cp, buffer); + } + } + + if (cp->type == CT_USER) + { + appendprompt(cp, 0); + } +} + +/* Private MSG verschicken. */ +void IrcPrivmsgCommand(CONNECTION *cp) +{ +#ifdef DEBUG_MODUS + lastfunc = "l1irc(IrcPrivmsgCommand)"; +#endif /* DEBUG_MODUS */ + + msg_command(cp); +} + +/* Channel schliessen. */ +void IrcPartCommand(CONNECTION *cp) +{ +#ifdef DEBUG_MODUS + lastfunc = "l1irc(IrcPartCommand)"; +#endif /* DEBUG_MODUS */ + + leave_command(cp); +} + +/* Help Kommando */ +void IrcHelpCommand(CONNECTION *cp) +{ +#ifdef DEBUG_MODUS + lastfunc = "l1irc(IrcHelpCommand)"; +#endif /* DEBUG_MODUS */ + + help_command(cp); +} + +/* Quit Kommando */ +void IrcQuitCommand(CONNECTION *cp) +{ +#ifdef DEBUG_MODUS + lastfunc = "l1irc(IrcQuitCommand)"; +#endif /* DEBUG_MODUS */ + + bye_command(cp); +} + +void IrcPingCommand(CONNECTION *cp) +{ + char *arg; + char buffer[2048]; +#ifdef DEBUG_MODUS + lastfunc = "l1irc(IrcPingCommand)"; +#endif /* DEBUG_MODUS */ + + arg = getarg(0, 0); + + arg[cp->width] = 0; + + sprintf(buffer, ":%s PONG %s :%s\n", myhostname, myhostname, arg); + appendstring(cp, buffer); +} + +void IrcPongCommand(CONNECTION *cp) +{ + char buffer[1024]; + char *line; + time_t response_time = 0L; +#ifdef DEBUG_MODUS + lastfunc = "l1irc(IrcPongCommand)"; +#endif /* DEBUG_MODUS */ + + line = getarg(0, 0); + + if (*line == ':') + line++; + + if (isalpha(*line)) + { + sprintf(buffer, "PING :%ld\n", currtime); + appendstring(cp, buffer); + return; + } + + sscanf(line, "%ld", &response_time); + + if (response_time < 1L) + { + sprintf(buffer, ":%s 375 %s bad answer, sorry\n" + , myhostname + , (*cp->nickname ? cp->nickname : cp->name)); + appendstring(cp, buffer); + } + else + { + ts2(); + sprintf(buffer, ":%s 375 %s *** rtt %s <-> %s is %s\n" + , myhostname + , (*cp->nickname ? cp->nickname : cp->name) + , myhostname + , (*cp->name ? cp->name : "you") + , ts4(currtime - response_time)); + appendstring(cp, buffer); + } + appendprompt(cp, 0); +} + +/* Alle User auf den aktuellen Channel bereitstellen. */ +void IrcNamesCommand(CONNECTION *cp) +{ + CONNECTION *p; + CHANNEL *ch; + CLIST *cl2; + char buffer[BUFSIZ]; +#ifdef DEBUG_MODUS + lastfunc = "l1irc(IrcNamesCommand)"; +#endif /* DEBUG_MODUS */ + + /* IRC-Meldung vorbereiten. */ + sprintf(buffer,":%s 353 %s = #%d :" + ,myhostname + ,cp->nickname + ,cp->channel); + /* Und abschicken. */ + appendstring(cp,buffer); + + for (ch = channels; ch; ch = ch->next) + { + /* Aktueller Channel? */ + if (ch->chan != cp->channel) + /* Nein, zum naechsten. */ + continue; + + for (p = connections; p; p = p->next) + { + /* Nur angemeldete User. */ + if (p->type == CT_USER) + { + /* if (ch->chan != cp->channel) + break;*/ + /* User im gesuchten Channel. */ + if (p->channel != ch->chan) + { + /* Nein, dann suchen wir in der Channel-List. */ + for (cl2 = p->chan_list; cl2; cl2 = cl2->next) + { + /* User im gesuchten Channel. */ + if (cl2->channel == ch->chan) + /* Eintrag gefunden. */ + break; + } + + /* Kein Eintrag gefunden? */ + if (!cl2) + /* Dann zum naechsten. */ + continue; + } + + /* Username - IRC-Meldung vorbereiten. */ + sprintf(buffer, "%s%s " + ,(p->channelop ? "@" : "") + , (*p->nickname ? p->nickname : p->name)); + /* Und abschicken. */ + appendstring(cp,buffer); + } + } + } + /* LISTENDE - IRC-Meldung vorbereiten. */ + sprintf(buffer, "\n:%s 366 %s #%d\n" + ,myhostname + ,cp->nickname + ,cp->channel); + /* Und abschicken. */ + appendstring(cp, buffer); +} + +/* Auflistung aller User im angegebenen Kanal. */ +void IrcWhoCommand(CONNECTION *cp) +{ + CONNECTION *p; + CHANNEL *ch; + CLIST *cl2; + char buffer[BUFSIZ]; + char *chan; + WORD Channel; +#ifdef DEBUG_MODUS + lastfunc = "l1irc(IrcWhoCommand)"; +#endif /* DEBUG_MODUS */ + + /* Gesuchten Channel holen. */ + chan = getarg(NULL, GET_NXTLC); + + /* 1. Zeichen eine "#"? */ + if (*chan == '#') + /* "#" entfernen. */ + chan++; + + Channel = atoi(chan); + + for (ch = channels; ch; ch = ch->next) + { + for (p = connections; p; p = p->next) + { + /* Nur angemeldete User. */ + if (p->type == CT_USER) + { + /* Unser Channel? */ + if (ch->chan != Channel) + /* Zum naechsten. */ + break; + + /* Hat unser User den gesuchten Channel? */ + if (p->channel != ch->chan) + { + /* Nein, dann schauen wir noch in die Channel-Liste. */ + for (cl2 = p->chan_list; cl2; cl2 = cl2->next) + { + /* Hat unser User den gesuchten Channel? */ + if (cl2->channel == ch->chan) + /* Channel gefunden. */ + break; + } + /* Eintrag gefunden. */ + if (!cl2) + /* Nein, weitersuchen. */ + continue; + } + + /* IRC-Meldung vorbereiten. */ + sprintf(buffer,":%s 352 %s %d %s%s %s %s %s %s%s%s :%d %s\n" + ,myhostname + ,cp->nickname + ,p->channel + ,"" + ,p->name + ,p->host + ,p->host + ,p->nickname + ,(p->away ? "G" : "H") + ,"" + ,(p->operator ? "@" : "") + ,0 + ,(p->pers ? p->pers : "")); + /* Und abschicken. */ + appendstring(cp, buffer); + } + } + } + + /* LISTENDE - IRC-Meldung vorbereiten. */ + sprintf(buffer, ":%s 315 %s #%s\n" + ,myhostname + ,cp->nickname + ,chan); + /* Und abschicken. */ + appendstring(cp,buffer); +} + +void IrcLinksCommand(CONNECTION *cp) +{ + DESTINATION *d; + char buffer[2048]; + char *dest = 0; +#ifdef DEBUG_MODUS + lastfunc = "l1irc(IrcLinksCommand)"; +#endif /* DEBUG_MODUS */ + + if (cp->type == CT_USER) + dest = getarg(0, 0); + else + dest = ""; + + if (*dest == '\0') + { + for (d = destinations; d; d = d->next) + { + if (d->rtt) + { + if (d->name[0] == FALSE) + continue; + + sprintf(buffer, ":%s 364 %s %s %s :%ld %s\n" + , cp->host + , (cp->nickname ? cp->nickname : cp->name) + , d->name + , (d->link->name ? d->link->name : myhostname) + , d->rtt + , d->rev); + appendstring(cp, buffer); + } + } + } + + sprintf(buffer, ":%s 364 %s %s %s :0 %s\n" + , cp->host + , (cp->nickname ? cp->nickname : cp->name) + , cp->host + , cp->host + , "pp-3.14c"); + appendstring(cp, buffer); + + sprintf(buffer, ":%s 365 %s * :End of /LINKS list.\n" + , cp->host + , (cp->nickname ? cp->nickname : cp->name)); + appendstring(cp, buffer); + appendprompt(cp, 0); +} + +/* Auflisten aller aktuellen Channels, Kanal, Useranzahl und Topic. */ +void IrcListCommand(CONNECTION *cp) +{ + CHANNEL *ch; + CONNECTION *p; + CLIST *cl; + char buffer[BUFSIZ]; + int n; +#ifdef DEBUG_MODUS + lastfunc = "l1irc(IrcListCommand)"; +#endif /* DEBUG_MODUS */ + + for (ch = channels; ch; ch = ch->next) + { + /* Userzaehler auf 0 setzen. */ + n = 0; + for (p = connections; p; p = p->next) + { + /* Nur angemeldete User. */ + if (p->type == CT_USER) + { + if (p->channel == ch->chan) + /* Userzaehler um eins hoeher. */ + n++; + else + { + for (cl = p->chan_list; cl; cl = cl->next) + /* Hat unser User den gesuchten Channel? */ + if (cl->channel == ch->chan) + /* Channel gefunden. */ + break; + + /* Eintrag gefunden? */ + if (cl) + /* Userzaehler um eins hoeher. */ + n++; + } + } + } + + /* IRC-Meldung vorbereiten. */ + sprintf(buffer, ":%s 322 %s #%d %d :%s\n" + ,cp->host + ,(*cp->nickname ? cp->nickname : cp->name) + ,ch->chan + ,n + ,(ch->topic ? ch->topic : "")); + + /* Und abschicken. */ + appendstring(cp, buffer); + } + + /* LISTENDE - IRC-Meldung vorbereiten. */ + sprintf(buffer, ":%s 323 %s\n" + ,cp->host + ,(*cp->nickname ? cp->nickname : cp->name)); + + /* Und abschicken. */ + appendstring(cp,buffer); +} + +/* Informationen eines Users. */ +void IrcWhoisCommand(CONNECTION *cp) +{ + char buffer[BUFSIZ]; + char *username; + char *revision; + CONNECTION *p, *c; + CHANNEL *ch; + DESTINATION *d; +#ifdef DEBUG_MODUS + lastfunc = "l1irc(IrcWhoisCommand)"; +#endif /* DEBUG_MODUS */ + + /* Username holen. */ + username = getarg(0, 1); + + for (p = connections; p; p = p->next) + { + /* User angemeldet. */ + if (p->type == CT_USER) + { + /* Gesuchter Username? */ + if ( (strcmp(p->name, username) == FALSE) + ||(strcmp(p->nickname, username) == FALSE)) + { + /* IRC-Meldung vorbereiten. */ + sprintf(buffer, ":%s 311 %s %s %s%s %s * :%s%s\n" + ,myhostname + ,cp->nickname + ,p->nickname + ,"" + ,p->name + ,p->host + ,(p->pers ? p->pers : "") + ,(p->pers == "~" ? " [NonAuth]" : "")); + /* Und abschicken. */ + appendstring(cp,buffer); + + /* User als Sysop angemeldet. */ + if (p->operator) + { + /* IRC-Meldung vorbereiten. */ + sprintf(buffer, ":%s 313 %s %s :is an IRC operator\n" + ,myhostname + ,cp->nickname + ,p->nickname); + /* Und abschicken. */ + appendstring(cp,buffer); + } + + for (c = connections; c; c = c->next) + { + /* Nur angemeldete User. */ + if (c->type != CT_USER) + /* Ein unangemeldeter oder HOST, zum naechsten. */ + continue; + + /* Vergleiche Username. */ + if (strcmp(p->name, c->name)) + /* Nicht unser gesuchter Username, zum naechten. */ + continue; + + /* Aktuellen Channel suchen. */ + for (ch = channels; ch; ch = ch->next) + if (ch->chan == c->channel) + /* gefunden. */ + break; + + /* IRC-Meldung vorbereiten. */ + sprintf(buffer, ":%s 319 %s %s :%s %d \n" + ,myhostname + ,cp->nickname + ,p->nickname + ,(c->channelop ? "@" : "") + ,c->channel); + /* Und abschicken. */ + appendstring(cp, buffer); + } + + /* User eigner Knoten. */ + if (!strcasecmp(p->host, myhostname)) + /* Markieren wir die Revision, */ + revision = strchr(REV, ':')+2; + + /* Pruefe alle Destinationen. */ + for (d = destinations; d; d = d->next) + /* Vergleiche Hostname. */ + if (!strcasecmp(d->name, p->host)) + /* gefunden. */ + break; + + /* Revision, IRC-Meldung vorbereiten. */ + sprintf(buffer, ":%s 312 %s %s %s :%s\n" + ,myhostname + ,cp->nickname + ,p->nickname + ,p->host + ,(d ? d->rev : revision)); + /* Und abschicken. */ + appendstring(cp,buffer); + + /* Online, IRC-Meldung vorbereiten. */ + sprintf(buffer, ":%s 317 %s %s %ld %ld :seconds idle, signon time\n" + ,myhostname + ,cp->nickname + ,p->nickname + ,(currtime - p->mtime), p->time); + /* Und abschicken. */ + appendstring(cp,buffer); + } + } + } + + /* LISTENDE - IRC-Meldung vorbereiten. */ + sprintf(buffer, ":%s 318 %s %s\n" + ,myhostname + ,cp->nickname + ,username); + /* Und abschicken. */ + appendstring(cp,buffer); +} + +/* Username aufloesen. */ +void IrcUserCommand(CONNECTION *cp) +{ + char *user, *pers; +#ifdef DEBUG_MODUS + lastfunc = "l1irc(IrcUserCommand)"; +#endif /* DEBUG_MODUS */ + + /* User erstmal sperren .*/ + cp->locked = 1; + /* Kanal wird spaeter gesetzt. */ + cp->channel = EOF; + + /* Ist es ein Host, ist der hier verkehrt. */ + if (cp->type == CT_HOST) + /* Und weg damit. */ + return; + + /* Username holfen. */ + user = getarg(0, 0); + + /* Personal Text einlesen & speichern. */ + personalmanager(SET, cp, (pers = getarg(NULL, GET_ALL))); + /* Personal Text setzen, max. zeichen 256!. */ + setstring(&(cp->pers), pers, 256); + + /* Username sichern. */ + strncpy(cp->name, user, NAMESIZE + 1); + + /* Verbose, defaultwert setzen. */ + cp->verbose = 0; +} + +/******************************************************************************/ +/* */ +/* Gibt Informationen ueber die Anzahl von Verbindungen, Global und Lokal. */ +/* */ +/******************************************************************************/ +static void IrcLusersCommand(CONNECTION *cp) +{ + char buffer[2048]; + DESTINATION *d; + CHANNEL *ch; + CONNECTION *p; + int n_users = 0; /* Useranzahl. */ + int n_dest, /* Destination/Routen. */ + n_channels, /* Kanalanzahl. */ + n_clients, /* IRC-Client. */ + n_servers, /* IRC-Server. */ + n_operators, /* Operatoranzahl. */ + n_typeunknown; /* Unbekannt. */ +#ifdef DEBUG_MODUS + lastfunc = "l1irc(IrcLusersCommand)"; +#endif /* DEBUG_MODUS */ + + for (n_dest = 0, d = destinations; d; d = d->next) /* Dest/Routen zaehlen. */ + { + if (d->rtt && d->link) /* Dest/Route gefunden. */ + n_dest++; /* um eins erhoehen. */ + } + + for (n_channels = 0, ch = channels; ch; ch = ch->next) /* Kanaele zaehlen. */ + { + if (!(ch->flags & M_CHAN_I)) /* keine unsichtbaren kanaele zaehlen. */ + n_channels++; /* um eins erhoehen. */ + } + + for (n_clients = n_servers = n_typeunknown = n_operators = 0, p = connections; p; p = p->next) + { + switch (p->type) + { + case CT_HOST: + n_servers++; + break; + + case CT_USER: + n_users++; + + if (!p->via) + n_clients++; + + if (p->operator) + n_operators++; + + break; + + case CT_UNKNOWN: + default: + n_typeunknown++; + } + } + + sprintf(buffer, ":%s 251 %s :Hier sind %d User auf %d Server\n", myhostname, cp->nickname, n_users, (n_dest) ? n_dest+1 : 1) ; + appendstring(cp, buffer); + + if (n_operators) + { + sprintf(buffer, ":%s 252 %s %d Sysop%s online\n", myhostname, cp->nickname, n_operators, (n_operators != 1) ? "s" : ""); + appendstring(cp, buffer); + } + + if (n_typeunknown) + { + sprintf(buffer, ":%s 253 %s %d :Ungueltige Verbindung%s\n", myhostname, cp->nickname, n_typeunknown, (n_typeunknown != 1) ? "en" : ""); + appendstring(cp, buffer); + } + + sprintf(buffer, ":%s 254 %s %d :Kanael%s\n", myhostname, cp->nickname, n_channels, (n_channels != 1 ? "e" : "")); + appendstring(cp, buffer); + + sprintf(buffer, ":%s 255 %s :Ich habe %d client%s auf %d Server\n", myhostname, cp->nickname, n_clients, (n_clients != 1) ? "s" : "", n_servers); + appendstring(cp, buffer); +} + +/******************************************************************************/ +/* */ +/* Zusaetzlich Text an IRC-Client senden. */ +/* */ +/******************************************************************************/ +static void IrcMotdCommand(CONNECTION *cp) +{ + FILE *fp; + char motdfile[MAXPATH + 1]; + char buffer[80 + 1]; + char buffer2[128]; +#ifdef DEBUG_MODUS + lastfunc = "l1irc(IrcMotdCommand)"; +#endif /* DEBUG_MODUS */ + + strcpy(motdfile, confpath); + strcat(motdfile, IRC_TXT); + + if ((fp = xfopen(motdfile, "r")) == NULL) /* Fehler beim oeffnen. */ + return; /* Abbrechen. */ + + sprintf(buffer2, ":%s 372 %s :" + , myhostname + , cp->nickname); + + while (fgets(buffer, 80, fp)) /* Maximal 80 Zeichen einlesen. */ + { + appendstring(cp, buffer2); /* Code-String. */ + appendstring(cp, buffer); /* Datei einlesen. */ + } + + sprintf(buffer, "\n:%s 376 %s :\n" + , myhostname + , cp->nickname); + appendstring(cp, buffer); + + fclose(fp); /* Datei schliessen. */ +} + +/******************************************************************************/ +/* */ +/* IRC-Client anmelden. */ +/* */ +/******************************************************************************/ +static void IrcLogin(CONNECTION *cp) +{ + char buffer[2048]; +#ifdef DEBUG_MODUS + lastfunc = "l1irc(IrcLogin)"; +#endif /* DEBUG_MODUS */ + + cp->charset_in = cp->charset_out = ISO_STRIPED; + + sprintf(buffer, ":%s 001 %s :%s @ %s PingPong-Release %5.5s (TNN) - Type /HELP for help.\n" + , myhostname + , cp->nickname + , convtype + , myhostname + , strchr(REV, ':')+2); + appendstring(cp, buffer); + + sprintf(buffer, ":%s 004 %s %s :\n" + , myhostname + , cp->nickname + , myhostname); + + appendstring(cp, buffer); + + IrcLusersCommand(cp); /* Anzahl User, Server, Kanaele etc. ausgeben. */ + IrcMotdCommand(cp); /* Zusaetzlichen Text ausgeben (irc.txt). */ + + cp->width = 80; /* Zeilengrenze setzen .*/ +} + +/******************************************************************************/ +/* */ +/* Nickname aufloesen. */ +/* */ +/******************************************************************************/ +void IrcNickCommand(CONNECTION *cp) +{ + char *arg; + char buffer[2048]; +#ifdef DEBUG_MODUS + lastfunc = "l1irc(IrcNickCommand)"; +#endif /* DEBUG_MODUS */ + + arg = getarg(0, 0); /* Nickname einlesen. */ + + if (cp->type == CT_HOST) /* Host ? */ + return; /* Und weg damit. */ + + if (cp->away != NULL) /* Wenn ein Away-Text gesetzt ist, */ + { + cp->away = NULL; /* zuruecksetzen. */ + +#ifndef CONVNICK + send_awaymsg(cp->name, /* Neuen Away-Text an andere Host's weiterleiten. */ + cp->hosthostname, + currtime, + cp->away); +#else + send_awaymsg(cp->name, /* Neuen Away-Text an andere Host's weiterleiten. */ + cp->nickname, + cp->host, + currtime, + cp->away); +#endif /* CONVNICK */ + return; + } + + if (*arg == ':') /* Gibt es ":" im string? */ + arg++; /* ":" loeschen. */ + + if (!*arg) /* String leer? */ + { + sprintf(buffer, ":%s 431 * :Kein Nickname angegeben!\n" + , myhostname); + appendstring(cp, buffer); + return; + } + +#ifdef CONV_CHECK_USER + { + CONNECTION *pP; + + if ((pP = CheckUserCVS(arg)) != NULL) /* Pruefung auf Doppel-Login. */ + { /* Kein Login moeglich. */ + sprintf(buffer, ":%s 433 %s %s :Nickname already in use\n" + , myhostname + , (*cp->nickname ? cp->nickname : "*") + , arg); + appendstring(cp, buffer); + return; + } + } +#endif /* CONV_CHECK_USER */ + + if (*cp->nickname) /* Schon eingeloggt. */ + { + sprintf(buffer, ":%s!%s@%s NICK :%s\n" /* Meldung abschicken. */ + , cp->nickname + , cp->name + , myhostname + , arg); + appendstring(cp, buffer); /* Meldung abschicken. */ + + strncpy(cp->OldNickname, cp->nickname, NAMESIZE);/* Alten Nick eintragen. */ + cp->nickname[NAMESIZE] = 0; + + strncpy(cp->nickname, arg, NAMESIZE); /* Neuen Nick eintragen. */ + cp->nickname[NAMESIZE] = 0; + return; + } + + strncpy(cp->nickname, arg, NAMESIZE); /* Nick eintragen. */ + cp->nickname[NAMESIZE] = 0; + + if (!*cp->name) /* Noch kein Username bekannt? */ + { + strncpy(cp->name, arg, NAMESIZE + 1);/* Nehmen wir den Nickn als Username.*/ + cp->name[NAMESIZE + 1] = 0; + } + + sprintf(buffer, ":%s!%s@%s NICK :%s\r" /* IRC-Meldung vorbereiten. */ + , cp->nickname + , cp->name + , myhostname + , arg); + appendstring(cp, buffer); /* Und abschicken. */ + + strncpy(cp->host, myhostname, NAMESIZE); /* Hostname eintragen. */ + cp->host[sizeof(cp->host)-1] = 0; + + cp->type = CT_USER; /* Als User markieren. */ + + IrcLogin(cp); /* IRC-Logintext. */ +} + +/******************************************************************************/ +/* */ +/* Nickname an andere IRC-Client's weiterleiten. */ +/* */ +/******************************************************************************/ +void SendIrcNick(CONNECTION *p) +{ + CONNECTION *p2; + CLIST *cl, + *cl2; + char buffer[2048]; +#ifdef DEBUG_MODUS + lastfunc = "l1irc(SendIrcNick)"; +#endif /* DEBUG_MODUS */ + + for (p2 = connections; p2; p2 = p2->next) + { + if (p2->locked) /* Sperre eingeschaltet. */ + continue; /* zum naechsten Eintrag. */ + + if (p2->type == CT_USER) /* Type User. */ + { + if (p2 == p) /* mich selber nicht weitersagen. */ + continue; /* zum naechsten eintrag. */ + + if (p2->channel != p->channel) /* Kanal unterschiedlich. */ + { + for (cl2 = p2->chan_list; cl2; cl2 = cl2->next) + { + if (cl2->channel == p->channel) + break; + else + { + for (cl = p->chan_list; cl; cl = cl->next) + { + if (cl->channel == cl2->channel) + break; + } + } + } + } + + if (p2->IrcMode == FALSE) /* Kein IRC-Client */ + continue; /* zum naechsten Eintrag. */ + /* Keine Aenderung, */ + if ( (!strncasecmp(p->OldNickname, p->nickname, NAMESIZE)) + ||(!strncasecmp(p->name, p->nickname, NAMESIZE))) + continue; /* zum naechsten Eintrag. */ + + /* Aktuellen Nick weitersagen. */ + sprintf(buffer, ":%s!%s@%s NICK %s\n" + , (p->OldNickname[0] == FALSE ? p->name : p->OldNickname) + , p->name + , p->host + , p->nickname); + appenddirect(p2, buffer); + break; + } + } +} + +/******************************************************************************/ +/* */ +/* Informationen vom User ausgeben. . */ +/* */ +/******************************************************************************/ +void IrcUserHostCommand(CONNECTION *cp) +{ + CONNECTION *p; + char buffer[2048]; + char buffer2[2048]; + int found = 0; + char *user; +#ifdef DEBUG_MODUS + lastfunc = "l1irc(IrcUserHostCommand)"; +#endif /* DEBUG_MODUS */ + + user = getarg(0, 0); /* User einlesen. */ + + if (!*user) /* Kein User angegeben. */ + { /* IRC-Meldung vorbereiten */ + sprintf(buffer, ":%s 461 %s USERHOST :Not enough parameters\n" + , myhostname + , cp->nickname); + appendstring(cp, buffer); /* und abschicken. */ + return; + } + + sprintf(buffer2, ":%s 302 %s :" /* IRC-Meldung vorbereiten */ + , myhostname + , cp->nickname); + + while (*user) + { + p = 0; + if ( (!strcasecmp(cp->nickname, user)) /* Uservergleich mit Nick/Name. */ + ||(!strcasecmp(cp->name, user))) + p = cp; /* Eintrag gefunden. */ + else /* Kein Eintrag gefunden. */ + { + for (p = connections; p; p = p->next) /* durchsuche convers-TBL. */ + { + if ( (!strcasecmp(p->nickname, user))/* Uservergleich mit Nick/Name. */ + ||(!strcasecmp(p->name, user))) + break; /* Eintrag gefunden. */ + } + } + + if (!p) /* Kein User gefunden. */ + { + sprintf(buffer, ":%s 401 %s %s :No such nick\n" + , myhostname + , (*cp->nickname ? cp->nickname : cp->name) + , user); + appendstring(cp,buffer); + } + else /* User gefunden. */ + { + sprintf(buffer, "%s%s%s=%c%s%s@%s" + , (found) ? " " : "" + , (*p->nickname ? p->nickname : p->name) + , (p->operator ? "*" : "") + , (p->away ? '-' : '+') + , "" + , p->name + , p->host); + + if (strlen(buffer) + strlen(buffer2) > 510) /* Buf-laenge ueberschritten*/ + break; /* Abbrechen. */ + + strcat(buffer2, buffer); /* Informationen anhaengen. */ + + if (!found) /* Gibt noch keinen Eintrag. */ + found++; /* min. 1 Eintrag. */ + } + + user = getarg(0, 0); /* Naechsten User einlesen. */ + } + + if (found) /* Eintrag gefunden. */ + { + appendstring(cp, buffer2); + appendstring(cp, "\n"); + } +} + +/******************************************************************************/ +/* */ +/* Beendet die Verbindung eines Server's vom Netzwerk. */ +/* */ +/******************************************************************************/ +void IrcSquitCommand(CONNECTION *cp) +{ + char buffer[2048]; + char *arg; +#ifdef DEBUG_MODUS + lastfunc = "l1irc(IrcSquitCommand)"; +#endif /* DEBUG_MODUS */ + + arg = getarg(0, 1); /* Server einlesen. */ + + if (!*arg) /* kein Server angegeben. */ + { + sprintf(buffer, ":%s 461 %s SQUIT :Not enough parameters\n" + , myhostname + , cp->nickname); + appendstring(cp, buffer); + return; + } + + if (cp->operator != 2) /* Kein Sysop, keine Aenderung. */ + { + sprintf(buffer, ":%s 481 %s :Permission Denied- You're not an IRC operator\n" + , myhostname + , cp->name); + appendstring(cp, buffer); + return; + } + + sprintf(buffer, "/link reset %s", arg); /* Reset-Befehl vorbereiten. */ + getarg(buffer, 0); + + links_command(cp); /* Server killen. */ +} + +/******************************************************************************/ +/* */ +/* Username an IRC-Server weiterleiten. */ +/* */ +/******************************************************************************/ +void IrcLinkUser(char *user) +{ + char *scall; +#ifdef DEBUG_MODUS + lastfunc = "l1irc(IrcLinkUser)"; +#endif /* DEBUG_MODUS */ + + if (tcppoi->Interface != KISS_IRC) /* Kein IRC-Interface. */ + { + user[0] = 0; /* Rufzeichen loeschen. */ + tcppoi->disflg |= 0x80; /* Verbindung schliessen. */ + return; + } + + if ((scall = strchr(user, ' ')) != FALSE) /* Zum Rufzeichen springen. */ + { + scall++; /* Leerzeichen entfernen. */ + strncpy(user, scall, L2CALEN); /* Rufzeichen sichern. */ + user[6] = 0; /* Sicher ist sicher. */ + } +} + +/******************************************************************************/ +/* */ +/* Nickname an IRC-Server weiterleiten. */ +/* */ +/******************************************************************************/ +void IrcLinkNick(char *header) +{ + READRX *SRx; + register int i; +#ifdef DEBUG_MODUS + lastfunc = "l1irc(IrcLinkNick)"; +#endif /* DEBUG_MODUS */ + + if (header[0] == FALSE) /* Kein Nick angegeben. */ + return; /* Abbrechen. */ + + if ((SRx = (READRX *)allocb(ALLOC_L1TCPIP)) == NULL) /* RX-Seg. besorgen */ + return; /* Kein Segment frei, abbruch. */ + + if ((SRx->Data = SetBuffer()) == NULL) /* Buffer besorgen. */ + { + dealoc((MBHEAD *)ulink((LEHEAD *)SRx)); /* RX-Segment entsorgen. */ + return; /* Buffer ist voll, abbruch. */ + } + + SRx->Sock = tcppoi->sock; /* Socket setzen. */ + SRx->Interface = tcppoi->Interface; /* Interface setzen. */ + SRx->Mode = tcppoi->mode; /* Stack-Mode setzen. */ + + for (i = 0; i < (signed)strlen(header); ++i) /* Nickname eintragen. */ + putchr(header[i], SRx->Data); + + relink((LEHEAD *) SRx, (LEHEAD *)rxflRX.tail); /* RX-Liste umhaengen. */ +} + +#endif /* L1IRC */ + +/* End of src/l1irc.c */ diff --git a/src/l1tcpip.c b/src/l1tcpip.c new file mode 100755 index 0000000..d698c0a --- /dev/null +++ b/src/l1tcpip.c @@ -0,0 +1,2300 @@ +#include "tnn.h" +#ifdef L1TCPIP + +T_INTERFACE ifp[MAXINTERFACE]; /* Interface-Liste. */ + +LHEAD tcpfrel; /* Liste der freien Linkbloecke */ +LHEAD tcpactl; /* Liste der aktiven Linkbloecke. */ +LHEAD tcptatl; + +LHEAD rxflRX; /* Empfangsliste */ +LHEAD rxflTX; /* Sendeliste */ + +TCPIP *tcppoi; /* "link pointer", globaler Zeiger auf */ + /* den gerade aktuellen Linkblock */ +TCPIP *tcptbl; /* "link table", fuer jeden moeglichen */ + /* TCPIP Eintrag */ + +struct Sockaddr_in Myaddr_in; +struct Sockaddr_in Peeraddr_in; + +static T_INTERFACE *ifpp; /* Zeiger auf das aktuelle Interface */ + +UWORD nmbtcp; /* Anzahl aktiver TCPIP-Links */ +UWORD nmbtcp_max; /* Maximale anzahl der TCPIP-Links */ + +int tcp_tbl_top = 0; /* Zaehler fuer aktive TCP-User. */ + +static BOOLEAN CheckSocket(void); /* Pruefe, ob Socket aktiv ist. */ + +void InitTCP(void) /* TCPIP initialisieren. */ +{ + int i; +#ifdef DEBUG_MODUS + lastfunc = "l1tcpip(InitTCP)"; +#endif /* DEBUG_MODUS */ + + inithd(&tcptatl); + inithd(&tcpactl); + inithd(&tcpfrel); + inithd(&rxflRX); + inithd(&rxflTX); + + for (i = 0, tcppoi = tcptbl; i < MAXTCPIP; ++i, ++tcppoi) + { + tcppoi->ip[0] = 0; + tcppoi->rxbuf[0] = 0; + tcppoi->txbuf[0] = 0; + tcppoi->cmd[0] = 0; + tcppoi->sock = 0; + tcppoi->Upcall[0] = 0; + tcppoi->Downcall[0] = 0; + tcppoi->disflg = 0; + tcppoi->port = 0; + tcppoi->noacti = 0; + tcppoi->T3 = 0; + tcppoi->inlin = 0; + tcppoi->outlin = 0; + tcppoi->activ = 0; + tcppoi->login = 0; + tcppoi->cmdlen = 0; + tcppoi->RecvLen = 0; + tcppoi->rxc = 0; + tcppoi->txc = 0; + tcppoi->sum = 0; + tcppoi->LoginPrompt = 0; + tcppoi->state = L2MNIX; + tcppoi->cr = 0; + tcppoi->txstatus = 0; + tcppoi->Interface = 0; +#ifdef L1HTTPD + tcppoi->status = 0; + tcppoi->http = 0; + tcppoi->fp = NULL; +#endif /* L1HTTPD */ +#ifdef L1IPCONV + tcppoi->CVSlink = FALSE; + tcppoi->Intern = FALSE; +#ifdef L1IRC + tcppoi->IrcMode = FALSE; +#endif /* IRC */ +#endif /* L1IRC */ + + inithd(&tcppoi->inbuf); + inithd(&tcppoi->outbuf); + + resptc(g_uid(tcppoi, TCP_USER)); + relink((LEHEAD *)tcppoi, (LEHEAD *)tcpfrel.tail); + } + + nmbtcp = nmbtcp_max = FALSE; /* TCPIP User/link zaehler. */ +} + +void InitIFC(void) /* Interface Initialisierung */ +{ + register int Interface; +#ifdef DEBUG_MODUS + lastfunc = "l1tcpip(InitIFC)"; +#endif /* DEBUG_MODUS */ + /* alle Interface durchgehen und */ + for (Interface = 0; Interface < MAXINTERFACE; Interface++) + { /* Initialisieren. */ + ifpp = &ifp[Interface]; /* Zeiger auf auf das akt. Interface. */ + ifpp->actively = FALSE; /* Interface deaktiv */ + ifpp->l2port = EOF; /* L2-Port. */ + ifpp->OsSock = 0; /* OS-Socket . */ + ifpp->ISock = 0; /* Interne Socket. */ + ifpp->log = 0; /* Loglevel. */ + +#ifdef L1TELNET + if (Interface == TEL_ID) + { + ifpp->Interface = KISS_TELNET; + ifpp->tcpport = Htons(DEFAULT_TELNET_PORT); /* Default TCP-Port setzen. */ + strncpy(ifpp->name, "TELNET", 10);/* Interface Name setzen. */ + } +#endif /* L1TELNET */ +#ifdef L1HTTPD + if (Interface == HTP_ID) + { + ifpp->Interface = KISS_HTTPD; /* HTTPD-Interface. */ + ifpp->tcpport = Htons(DEFAULT_HTTPD_PORT);/* Default TCP-Port setzen. */ + strncpy(ifpp->name, "HTTPD", 10); /* Interface Name setzen. */ + } +#endif /* L1HTTPD */ +#ifdef L1IPCONV + if (Interface == CVS_ID) + { + ifpp->Interface = KISS_IPCONV; + ifpp->tcpport = Htons(DEFAULT_IPCONV_PORT); /* Default TCP-Port setzen. */ + strncpy(ifpp->name, "IPCONV", 10);/* Interface Name setzen. */ + } +#endif /* L1IPCONV */ +#ifdef L1IRC + if (Interface == IRC_ID) + { + ifpp->Interface = KISS_IRC; + ifpp->tcpport = Htons(DEFAULT_IRC_PORT); /* Default TCP-Port setzen. */ + strncpy(ifpp->name, "IRC", 10); /* Interface Name setzen. */ + } +#endif /* L1IRC */ + } +} + +T_INTERFACE *SearchIf(UWORD Interface) /* Das gesuchte Interface ermitteln */ +{ /* und den Interfacezeiger setzen. */ +#ifdef DEBUG_MODUS + lastfunc = "l1tcpip(SearchIf)"; +#endif /* DEBUG_MODUS */ + + switch(Interface) + { +#ifdef L1TELNET + case KISS_TELNET: /* TELNET Interface. */ + ifpp = &ifp[TEL_ID]; /* Interfacezeiger setzen. */ + break; +#endif /* L1TELNET */ + +#ifdef L1HTTPD + case KISS_HTTPD: /* HTTPD Interface. */ + ifpp = &ifp[HTP_ID]; /* Interfacezeiger setzen. */ + break; +#endif /* L1HTTPD */ + +#ifdef L1IPCONV + case KISS_IPCONV: /* TELNET Interface. */ + ifpp = &ifp[CVS_ID]; /* Interfacezeiger setzen. */ + break; +#endif /* L1IPCONV */ + +#ifdef L1IRC + case KISS_IRC: /* IRC Interface. */ + ifpp = &ifp[IRC_ID]; /* Interfacezeiger setzen. */ + break; +#endif /* L1IPCONV */ + + default: /* kein Interface gefunden. */ + return(NULL); + } + + return(ifpp); /* Aktuelles Interface liefern. */ +} + +/* Schliesse aktuellen Socket. */ +static BOOLEAN CloseSockTCP(BOOLEAN ALL, WORD Interface) +{ + int i, + j = FALSE; +#ifdef DEBUG_MODUS + lastfunc = "l1tcpip(CloseSockTCP)"; +#endif /* DEBUG_MODUS */ + +#ifdef OS_STACK + if (tcppoi->mode == OS_MODE) + return(CloseSockOS(ALL, Interface)); +#endif /* OS_STACK */ + + if (ALL == TRUE) /* ALLE Socket-Verbindungen schliessen. */ + { + for (i = 0, tcppoi = tcptbl; i < MAXTCPIP; ++i, ++tcppoi)/* TBL durchgehen*/ + { + if ( Interface == tcppoi->Interface /* Interfacevergleich */ + && tcppoi->sock > TRUE) /* Socket ist aktiv. */ + { + Close(tcppoi->sock); /* Socket schliessen. */ + DiscTCP(); /* TCPIP-User/link aus der Liste raushaengen */ + } /* bzw. Parameter wieder auf 0 setzen. */ + + if ( ((tcppoi->activ) /* Sind alle aktiven Sockets durchlaufen, */ + && (j++ >= tcp_tbl_top)) + || (j == tcp_tbl_top)) + return(FALSE); /* brechen wir ab. */ + } + } + + Close(tcppoi->sock); /* Socket schliessen. */ + + DiscTCP(); /* TCPIP-User/Link aus der Liste raushaengen */ + return(FALSE); /* bzw. Parameter wieder auf 0 setzen. */ +} + +void L1ExitTCP(WORD Interface) /* TCPIP-Interface schliessen. */ +{ + T_INTERFACE *ifpoi; +#ifdef DEBUG_MODUS + lastfunc = "l1tcpip(L1ExitTCP)"; +#endif /* DEBUG_MODUS */ + +#ifdef OS_STACK + L1ExitOS(Interface); +#endif /* OS_STACK */ + + if ((ifpoi = SearchIf(Interface)) == NULL) /* Zeiger auf das akt. Interface.*/ + return; /* Aktuelles Interface ist deaktiv, */ + /* dann zum naechsten Interface. */ + + if (ifpoi->actively == TRUE) /* Nur wenn Interface aktiv. */ + CloseSockTCP(TRUE, ifpoi->Interface); /* Alle TCPIP-Verbind. schliessen.*/ + + if ((signed)ifpoi->ISock > FALSE) /* TCPIP-Socket schliessen wenn offen */ + Close(ifpoi->ISock); /* Schliesse Socket. */ + + ifpoi->ISock = EOF; + + ifpoi->actively = FALSE; /* Markiere TCPIP-Interface als deaktiv*/ + + T_LOGL1(TRUE, "(L1ExitTCP):\nInterface ist deaktiviert!\n"); +} + + /* Aktive Socket's setzen. */ +static void PutSocketTCP(Fd_set *Rmask, /* Socket-liste. */ + int *maxI) /* Socket-Wert. */ +{ + register int i; + int j = 0; +#ifdef DEBUG_MODUS + lastfunc = "l1tcpip(PutSocketTCP)"; +#endif /* DEBUG_MODUS */ + + /* TCPIP-User/Links durchgehen. */ + for (i = 0, tcppoi = tcptbl; i < MAXTCPIP; ++i, ++tcppoi) + { + if (tcppoi->sock) /* Nur wenn Socket aktiv! */ + { + if (CheckSocket()) /* Pruefe, ob Socket aktiv ist. */ + { + CloseSockTCP(FALSE, tcppoi->Interface); /* Schliesse Socket. */ + continue; /* Zum naechsten Socket. */ + } + + if (tcppoi->mode) /* Interner Stack. */ + { + FD_SET_T((unsigned)tcppoi->sock, Rmask); /* Socket setzen. */ + if (tcppoi->sock > *maxI - 1) + *maxI = tcppoi->sock + 1; + } + } + + if ( ((tcppoi->activ) /* Sind alle aktiven Sockets durchlaufen, */ + && (j++ >= tcp_tbl_top)) + || (j == tcp_tbl_top)) + break; /* brechen wir ab. */ + } +} + + /* Portinfo-String fuer den PORT-Befehl.*/ +void HwstrTCP(UWORD Interface, /* Aktuelle Interface. */ + int port, /* L2Port */ + MBHEAD *mbp) /* Buffer */ +{ + T_INTERFACE *ifpoi; +#ifdef DEBUG_MODUS + lastfunc = "l1tcpip(HwstrTCP)"; +#endif /* DEBUG_MODUS */ + + if ((ifpoi = SearchIf(Interface)) == NULL) /* Zeiger auf das akt. Interface.*/ + return; /* Ungueltiges Interface. */ + + putstr(" ", mbp); + putprintf(mbp,"%u", Ntohs(ifpoi->tcpport)); +} + + /* TCPIP-Port Initialisieren. */ +BOOLEAN L1InitTCP(UWORD Interface, /* Aktuelle Interface. */ + int port, /* L2Port */ + int TCPPort) /* TCP-Port. */ +{ + T_INTERFACE *ifpoi; +#ifdef DEBUG_MODUS + lastfunc = "l1tcpip(L1InitTCP)"; +#endif /* DEBUG_MODUS */ + + if ((ifpoi = SearchIf(Interface)) == NULL) /* Zeiger auf das akt.Interface.*/ + return(FALSE); /* Interface ist belegt. */ + + if (ifpoi->actively == TRUE) /* Interface ist altiv */ + return(FALSE); /* Kann Filedescriptor nicht anlegen. */ + + if ( (TCPPort < 1) + ||(TCPPort > 65535)) + return(FALSE); + /* Einen neuen Filedescriptor anlegen. */ + if ((ifpoi->ISock = SetupTCP(ifpoi->name, Htons((unsigned short)TCPPort))) == EOF) + return(FALSE); /* Kann Filedescriptor nicht anlegen. */ + +#ifdef OS_STACK + if (L1InitOS(Interface, port, (unsigned short)TCPPort) == FALSE) + return(FALSE); +#endif /* OS_STACK */ + + ifpoi->l2port = port; /* L2-Port setzen. */ + ifpoi->actively = TRUE; /* Markiere Interface als aktiv. */ + ifpoi->tcpport = TCPPort; /* Markiere TCP-Port. */ + + return(TRUE); /* Socket wurde erfolgreich erstellt. */ +} + + /* Einen Filedescriptor anlegen. */ +int SetupTCP(char *name, /* Interface-Name. */ + unsigned short tcp_port) /* Neuer TCP-Port. */ +{ + int tmp_fd = EOF; /* Temporaerer Filedescriptor */ +#ifdef DEBUG_MODUS + lastfunc = "l1tcpip(SetupTCP)"; +#endif /* DEBUG_MODUS */ + + if (tcp_port == FALSE) /* Kein Port angegeben. */ + { + T_LOGL1(TRUE, "(SetupTCP):\nKein TCP-Port angegeben.\n"); + return(EOF); /* Abbruch. */ + } + + memset(&Myaddr_in, 0, sizeof(Myaddr_in)); /* Adressstruktur loeschen */ + memset(&Peeraddr_in, 0, sizeof(Peeraddr_in)); + Myaddr_in.sin_family = AF_INET; /* Adressstruktur fuellen */ + Myaddr_in.sin_port = Htons(tcp_port); /* TCP-Port setzen. */ + Myaddr_in.sin_addr._S_addr = INADDR_ANY; /* Jedes Netzwerk Geraet abfragen. */ + + /* Socket erstellen. */ + if ((tmp_fd = Socket(AF_INET, SOCK_STREAM, 0)) == EOF) + { + printf("Error %s: Socket cannot be constructed!\r", ifpp->name); + + T_LOGL1(TRUE, "(SetupTCP):\nNeuer Socket kann nicht geoeffnet werden.\n"); + return(EOF); /* Keine freien Socket's. */ + } + + /* Bind Initialisieren. */ + if (Bind (tmp_fd, (struct Sockaddr *) &Myaddr_in, sizeof (struct Sockaddr_in)) == EOF) + { + printf("Error %s: Bind cannot be initialized!\n", ifpp->name); + Close(tmp_fd); /* Schliesse Socket. */ + + T_LOGL1(TRUE, "(SetupTCP):\nBind Initialisierung fehlgeschlagen.\n"); + return(EOF); /* Fehler beim Bind . */ + } + + if (Listen (tmp_fd, 3) == EOF) /* Listen Initialisieren. */ + { + printf("Error %s: listen cannot be initialized!\n", ifpp->name); + Close(tmp_fd); /* Schliesse Socket. */ + + T_LOGL1(TRUE, "(SetupTCP):\nListen Initialisierung fehlgeschlagen.\n"); + return(EOF); /* Fehler beim Listen. */ + } + + T_LOGL1(TRUE, "(SetupTCP):\nTCP-Port (%d) erfolgreich gesetzt.\n" + , Ntohs(tcp_port)); + + return(tmp_fd); /* Aktuelle Filedescriptor. */ +} + +void L1ctlTCP(int req, int port) /* Level 1 Kontrolle */ +{ + testflag[port] = 0; /* Kein TEST-Frame zulassen. */ + kick[port] = 0; +} + +BOOLEAN TcpDCD(int l2port) /* DCD-Status bei TCPIP ist immer FALSE. */ +{ + return(FALSE); +} + +/* Defaultwerte setzen. */ +void SetDefaultWorthTCP(unsigned sock, /* Neuer Socket. */ + char *ip, /* IP-Adresse. */ + int l2port, /* L2-Port. */ + UWORD Interface, /* TCP-Interface. */ + BOOLEAN Mode) /* Interner TCP-Stack */ +{ +#ifdef DEBUG_MODUS + lastfunc = "l1tcpip(SetDefaultWorthTCP)"; +#endif /* DEBUG_MODUS */ + + strncpy(tcppoi->ip, ip, IPADDR); /* IP-Adresse eintragen. */ + tcppoi->port = l2port; /* L2-Port setzen. */ + tcppoi->activ = TRUE; /* Markiere aktiv. */ + tcppoi->sock = sock; /* Aktuellen Socket setzen. */ + tcppoi->mode = Mode; /* Mode setzen. (Int/Ext.) */ + tcppoi->cmdlen = 0; /* Zaehler fuer cmd-Buffer. */ + tcppoi->inlin = 0; /* eingelaufene Zeilen auf 0 setzen. */ + tcppoi->outlin = 0; /* auszugebende Zeilen auf 0 setzen. */ + tcppoi->RecvLen = 0; /* Rueckgabewert fuer recv. */ + tcppoi->rxc = 0; /* Zaehler fuer RX-BUFFER. */ + tcppoi->LoginPrompt = FALSE; /* Markiere Prompt senden. */ + tcppoi->T3 = T3PARA; /* T3-Timer setzen. */ + tcppoi->noacti = ininat; /* Timeout setzen */ + tcppoi->Interface = Interface; /* Interface ID setzen. */ + tcppoi->state = L2MNIX; /* State setzen. */ + tcppoi->cr = 0; /* Kein RETRUN empfangen. */ + tcppoi->txstatus = TCP_TX_FREE; /* Sender ist frei. */ + tcppoi->Upcall[0] = 0; + tcppoi->Downcall[0] = 0; +#ifdef L1HTTPD + tcppoi->status = TCP_NULL; + tcppoi->http = TCP_NULL; + tcppoi->fp = NULL; +#endif /* L1HTTPD */ +#ifdef L1IPCONV + tcppoi->CVSlink = FALSE; + tcppoi->Intern = FALSE; +#ifdef L1IRC + if (Interface == KISS_IRC) + tcppoi->IrcMode = TRUE; + else + tcppoi->IrcMode = FALSE; +#endif /* L1IRC */ +#endif /* L1IPCONV */ + + tcp_tbl_top++; /* TBL-Zaehler um 1 erhoehen. */ + + relink(ulink((LEHEAD *)tcppoi), /* Link aus der frei-Liste nehmen */ + (LEHEAD *)tcpactl.tail); +} + +int ReadSockTCP(void) /* Empfangene TCPIP Packete. */ +{ + Fd_set fdsI; + int ret = EOF; +#ifdef DEBUG_MODUS + lastfunc = "l1tcpip(ReadSockTCP)"; +#endif /* DEBUG_MODUS */ + + if (tcppoi->rxc >= tcppoi->RecvLen) /* Sind alle Zeichen verarbeitet. */ + { + if (tcppoi->mode == INT_STACK) /* Interner Socket. */ + { + FD_ZERO_T(&fdsI); /* Inhalt loeschen. */ + FD_SET_T((unsigned)tcppoi->sock, &fdsI); /* Socket setzen. */ + + /* Pruefe auf aktivitaet. */ + ret = Select(tcppoi->sock + 1, &fdsI, NULL , NULL ,NULL); + + if (ret) + /* Zeichen vom Socket empfangen. */ + tcppoi->RecvLen = Recv (tcppoi->sock, tcppoi->rxbuf, RXLEN,0); + else + return((int)NULL); /* Keine aktivitaet auf den Socket. */ + } + + if (tcppoi->RecvLen < 1) /* Fehler beim Empfang. */ + { + if (tcppoi->RecvLen == EOF) /* Socket wurde mittlerweile geloes. */ + { + ifpp = SetInterface(tcppoi->Interface); /* akt. Interface setzen. */ + /* ggf. Logbuch fuehren. */ + T_LOGL1(TRUE, "(ReadSockTCP):%s\n (Recv) Fehler beim empfang, Segment wird auf DISC gesetzt!\n" + , tcppoi->ip); + + tcppoi->disflg |= 0x80; /* Segment auf DISC stellen. */ + return((int)NULL); + } + + if ( (ret) + &&(tcppoi->RecvLen == 0)) + { + ifpp = SetInterface(tcppoi->Interface); /* akt. Interface setzen. */ + /* ggf. Logbuch fuehren. */ + T_LOGL1(TRUE, "(ReadSockTCP):%s\n(Recv) Keine Zeichen, Segment wird auf DISC gesetzt!\n" + , tcppoi->ip); + + tcppoi->disflg |= 0x80; /* Segment auf DISC stellen. */ + return((int)NULL); + } + } + + tcppoi->rxc = 0; /* RX-Zaehler auf 0 setzen. */ + tcppoi->rxbuf[tcppoi->RecvLen] = 0; /* Nullzeichen setzen. */ + /* ggf. Logbuch fuehren. */ + ifpp = SetInterface(tcppoi->Interface); + T_LOGL3(TRUE, "(ReadSockTCP):%s\nInput:\r%s\r" + , tcppoi->ip + , tcppoi->rxbuf); + } + + ret = tcppoi->rxbuf[tcppoi->rxc++]; /* Zeichen vom rxbuf holen. */ + + return(ret); /* Aktuelle Zeichen weiterreichen. */ +} + +static int ReadIndicationsSockTCP(void) /* Zeichen vom Socket einlesen. */ +{ + TRILLIAN ok = ERRORS; + char s; +#ifdef DEBUG_MODUS + lastfunc = "l1tcpip(ReadIndicationsSockTCP)"; +#endif /* DEBUG_MODUS */ + + while(1) /* Alle Zeichen von Socket einlesen. */ + { + s = ReadSockTCP(); /* Zeichen vom Socket. */ + + if (tcppoi->cmdlen >= RXLEN) /* Maximale Buffergroesse erreicht, */ + { + ifpp = SetInterface(tcppoi->Interface); + T_LOGL1(TRUE, "(ReadIndicationsSockTCP):%s\nMaximale Buffergroesse erreicht!\n" + , tcppoi->ip); + return(TRUE); + } + + switch(tcppoi->Interface) /* Interface. */ + { +#ifdef L1TELNET + case KISS_TELNET : /* Telnet. */ + if ((ok = GetContensTEL(s)) == ERRORS) /* Aktuelle Zeichen auswerten.*/ + break; /* Zeichen verarbeitet, kein Return. */ + else + if (ok == YES) /* Zeichen verarbeitet und Return. */ + { + tcppoi->cmd[tcppoi->cmdlen] = 0; /* Nullzeichen setzen. */ + return(TRUE); /* Frame ist komplett. */ + } + else + continue; /* Sind noch Zeichen im RXBUF, */ + /* zum naechsten Zeichen. */ + break; +#endif /* L1TELNET. */ + +#ifdef L1HTTPD + case KISS_HTTPD : /* HTTPD-Server. */ + if ((ok = GetContensHTP(s)) == ERRORS) /* Aktuelle Zeichen auswerten.*/ + break; /* Zeichen verarbeitet, kein Return. */ + else + if (ok == YES) /* Zeichen verarbeitet und Return. */ + { + tcppoi->cmd[tcppoi->cmdlen] = 0; /* Nullzeichen setzen. */ + return(TRUE); /* Frame ist komplett. */ + } + else + continue; /* Sind noch Zeichen im RXBUF, */ + /* zum naechsten Zeichen. */ + break; +#endif /* L1HTTPD. */ + +#ifdef L1IPCONV + /* IPCONV */ + case KISS_IPCONV : + /* Aktuelle Zeichen auswerten. */ + if ((ok = GetContensCVS(s)) == ERRORS) + /* Alle Zeichen verarbeitet, aber kein Return. */ + break; + else + /* Alle Zeichen verarbeitet und Return? */ + if (ok == YES) + { + /* User/Link noch kein Login. */ + if (!tcppoi->login) + { + /* Pruefe auf Login. */ + if (!strncmp(tcppoi->cmd, "/na", 3)) + /* Kein Prompt senden. */ + tcppoi->LoginPrompt = TRUE; + } + tcppoi->cmd[tcppoi->cmdlen] = 0; + /* Frame komplett. */ + return(TRUE); + } + else + /* Sind noch Zeichen im RXBUF,*/ + /* zum naechsten Zeichen. */ + continue; + + break; +#endif /* L1IPCONV */ + +#ifdef L1IRC + /* IPCONV */ + case KISS_IRC : + /* Aktuelle Zeichen auswerten. */ + if ((ok = GetContensCVS(s)) == ERRORS) + /* Alle Zeichen verarbeitet, aber kein Return. */ + break; + else + /* Alle Zeichen verarbeitet und Return? */ + if (ok == YES) + { + tcppoi->cmd[tcppoi->cmdlen] = 0; + /* Frame komplett. */ + return(TRUE); + } + else + /* Sind noch Zeichen im RXBUF,*/ + /* zum naechsten Zeichen. */ + continue; + + break; +#endif /* L1IPCONV */ + + default : /* Ungueltiges Interface. */ + break; /* Hier werden wir nie kommen. */ + } + + return(FALSE); /* Frame noch nicht komplett. */ + } + + return(FALSE); /* Frame noch nicht komplett. */ +} + + /* Zusaetzlichen CTEXT einlesen. */ +void LoginTextTCP(char *filename, /* CTEXT-Datei. */ + MBHEAD *tmpmbp) /* Buffer. */ +{ + FILE *fp; + char buffer[80 + 1]; + char convfile[MAXPATH]; +#ifdef DEBUG_MODUS + lastfunc = "l1tcpip(LoginTextTCP)"; +#endif /* DEBUG_MODUS */ + + strcpy(convfile, confpath); /* Basis-Verzeichnis setzen. */ + strcat(convfile, filename); /* CTEXT-Datei setzen. */ + + ifpp = SetInterface(tcppoi->Interface); /* aktuelles Interface */ + /* setzen fuer Logging. */ + if ((fp = fopen(convfile, "r")) == NULL) /* CTEXT-Datei oeffnen. */ + { /* ggf. Logbuch fuehren. */ + T_LOGL1(TRUE, "(LoginTextTCP):%s\nDatei (%s) kann nicht geoeffnet werden!\n" + , tcppoi->ip + , convfile); + return; /* Laest sich nicht oeffnen. */ + } + /* ggf. Logbuch fuehren. */ + T_LOGL2(TRUE, "(LoginTextTCP):%s\nDatei (%s) ist geoeffnet!\n" + , tcppoi->ip + , convfile); + + while (fgets(buffer, 80, fp) != NULL) /* String mit 80 Zeichen einlesen. */ + putprintf(tmpmbp, "%s\r", buffer); + + fclose(fp); /* Datei schliessen. */ + /* ggf. Logbuch fuehren. */ + T_LOGL2(TRUE, "(LoginTextTCP):%s\nDatei (%s) ist geschlossen!\n" + , tcppoi->ip + , convfile); +} + +static void PromptTCP(UWORD Interface) /* Login-Prompt senden. */ +{ + SENDTX *STx = NULL; + char call[10]; + char file[128]; +#ifdef DEBUG_MODUS + lastfunc = "l1tcpip(PromptTCP)"; +#endif /* DEBUG_MODUS */ + + switch(Interface) /* Interface. */ + { +#ifdef L1TELNET + /* TELNET-Server */ + case KISS_TELNET : /* Telnet. */ + strcpy(file, TELNET_TXT); /* Markiere Datei (telnet.txt)*/ + break; +#endif /* L1TELNET */ + +#ifdef L1IPCONV + /* IPCONVERS-Server */ + case KISS_IPCONV : /* IPConvers */ + strcpy(file, IPCONV_TXT); /* Markiere Datei (ipconv.txt)*/ + break; +#endif /* L1IPCONV */ + + default : + tcppoi->LoginPrompt = TRUE; /* Markiere Prompt als gesend.*/ + return; + } + + if ((STx = (SENDTX *)allocb(ALLOC_L1TCPIP)) == NULL)/* TX-Segment besorgen. */ + { + ifpp = SetInterface(tcppoi->Interface); + T_LOGL1(TRUE, "(PromptTCP):%s\nSpeicher (%d) ist voll!\n" + , tcppoi->ip + , nmbfre); + + tcppoi->disflg |= 0x80; /* Segment auf Disconnect setzen. */ + return; /* Kein Segment frei, abbruch. */ + } + + if ((STx->Data = SetBuffer()) == NULL) /* Buffer besorgen. */ + { + dealoc((MBHEAD *)ulink((LEHEAD *)STx)); /* TX-Segment entsorgen.*/ + + ifpp = SetInterface(tcppoi->Interface); + T_LOGL1(TRUE, "(PromptTCP):%s\nSpeicher (%d) ist voll!\n" + , tcppoi->ip + , nmbfre); + + tcppoi->disflg |= 0x80; /* Segment auf Disconnect setzen. */ + return; /* Buffer ist voll, abbruch. */ + } + + call2str(call,myid); /* Konvertiere das MYCALL. */ + putprintf(STx->Data, "%s - %s\n", call, version); /* Standardtext einfuegen.*/ + LoginTextTCP(file, STx->Data); /* evl. erweiterten CTEXT einfuegen. */ + + putprintf(STx->Data, "\nLogin:"); /* Und zum schluss den */ + /* Login Prompt einfuegen. */ + + rwndmb(STx->Data); /* Buffer zurueckspulen.*/ + STx->Sock = tcppoi->sock; /* Socket setzen. */ + STx->Interface = tcppoi->Interface; /* Interface setzen. */ + STx->Mode = tcppoi->mode; /* Stack-Mode setzen. */ + + relink((LEHEAD *) STx, (LEHEAD *)rxflTX.tail);/* Umhaengen in die Sendeliste*/ + tcppoi->LoginPrompt = TRUE; /* Markiere, Login-Prompt als gesendet. */ +} + +void ServTCP(void) /* Empfangene Zeichen in Frames packen. */ +{ + READRX *SRx; + register int i; +#ifdef DEBUG_MODUS + lastfunc = "l1tcpip(ServTCP)"; +#endif /* DEBUG_MODUS */ + + if (ReadIndicationsSockTCP()) /* Empfangene Zeichen analysieren. */ + { + if(tcppoi->cmdlen > 0) /* Es sind Zeichen im Buffer.*/ + { + if ((SRx = (READRX *)allocb(ALLOC_L1TCPIP)) == NULL)/* RX-Seg. besorgen */ + { + ifpp = SetInterface(tcppoi->Interface); + T_LOGL1(TRUE, "(ServTCP):%s\nSpeicher (%d) ist voll!\n" + , tcppoi->ip + , nmbfre); + return; /* Kein Segment frei, abbruch. */ + } + + if ((SRx->Data = SetBuffer()) == NULL) /* Buffer besorgen. */ + { + ifpp = SetInterface(tcppoi->Interface); + T_LOGL1(TRUE, "(ServTCP):%s\nSpeicher (%d) ist voll!\n" + , tcppoi->ip + , nmbfre); + + dealoc((MBHEAD *)ulink((LEHEAD *)SRx)); /* RX-Segment entsorgen. */ + return; /* Buffer ist voll, abbruch. */ + } + + SRx->Sock = tcppoi->sock; /* Socket setzen. */ + SRx->Interface = tcppoi->Interface; /* Inetrface setzen. */ + SRx->Mode = tcppoi->mode; /* Stack-Mode setzen. */ + + for (i = 0; i < tcppoi->cmdlen; ++i) + putchr(tcppoi->cmd[i], SRx->Data); /* Buffer fuellen. */ + + tcppoi->cmdlen = 0; /* Buffer-Zaehler zuruecksetzen. */ + tcppoi->cmd[0] = 0; /* Nullzeichen setzen. */ + + if (tcppoi->activ) /* Nur wenn Socket aktiv. */ + relink((LEHEAD *) SRx, (LEHEAD *)rxflRX.tail);/* Ab in die Empf.-liste*/ + else + { + ifpp = SetInterface(tcppoi->Interface); + T_LOGL1(TRUE, "(ServTCP):%s\nTCP-Segment nicht mehr aktiv!\n" + , tcppoi->ip); + + if (SRx->Data != NULL) + dealmb(SRx->Data); /* Buffer entsorgen. */ + + dealoc((MBHEAD *)ulink((LEHEAD *)SRx)); /* RX-Segment entsorgen.*/ + } /* Socket ist nicht mehr aktiv. */ + } /* kein Zeichen im buffer. */ + } /* Frame ist noch nicht komplett. */ +} + +/* Neue User hinzufuegen, vorrausgesetzt es sind noch freie Sockets vorhanden.*/ +int AddUserTCP(T_INTERFACE *ifpoi, /* TCP-Interface. */ + unsigned NewSocket, /* Neuer Socket. */ + char *ip) /* IP-Adresse. */ +{ +#ifdef DEBUG_MODUS + lastfunc = "l1tcpip(AddUserTCP)"; +#endif /* DEBUG_MODUS */ + + if ((tcppoi = (TCPIP *)tcpfrel.head) == NULL) /* freien Eintrag besorgen. */ + { + ifpp = SetInterface(ifpoi->Interface); + T_LOGL1(TRUE, "(AddUserTCP):%s\nKann kein neues TCPIP-Segment anlegen !\n" + , ip + , tcp_tbl_top); + + return(TRUE); /* es gibt keinen freien Eintrag mehr! */ + } + + + SetDefaultWorthTCP(NewSocket, /* Defaultwerte setzen, neuer Socket. */ + ip, /* IP-Adresse. */ + ifpoi->l2port, /* L2-Port. */ + ifpoi->Interface, /* TCPIP-Interface. */ + INT_STACK); /* Interner TCP-STack. */ + + ServTCP(); /* Empfangene Zeichen in Frames packen. */ + + return(FALSE); +} + + +/* Alle Parameter auf default zuruecksetzen und den User aus der Liste nehmen.*/ +void DiscTCP(void) +{ +#ifdef DEBUG_MODUS + lastfunc = "l1tcpip(DiscTCP)"; +#endif /* DEBUG_MODUS */ + + if (tcppoi->activ == FALSE) /* User ist deaktiv. */ + { + ifpp = SetInterface(tcppoi->Interface); + T_LOGL1(TRUE, "(DiscTCP):%s\nTCP-Segment wurde schon zurueckgesetzt!\n" + , tcppoi->ip); + return; /* Abbruch. */ + } + else /* User ist aktiv. */ + tcppoi->activ = FALSE; /* Markiere, User als deaktiv. */ + + if (tcppoi->login) /* User war eingeloggt. */ + nmbtcp--; /* Ein TCPIP User weniger. */ + + dealml((LEHEAD *)&tcppoi->inbuf); /* Buffer leeren. */ + dealml((LEHEAD *)&tcppoi->outbuf); + + +#ifdef L1HTTPD + if (tcppoi->fp != NULL) + { + fclose(tcppoi->fp); + + /* ggf. Logbuch fuehren. */ + ifpp = SetInterface(tcppoi->Interface); + T_LOGL2(TRUE, "(DiscTCP):%s\nDatei wird geschlossen.\n" + , tcppoi->ip); + } +#endif /* L1HTTPD */ + + /* ggf. Logbuch fuehren. */ + ifpp = SetInterface(tcppoi->Interface); + T_LOGL2(TRUE, "(DiscTCP):\nVerbindung zur IP-Adresse %s wurde geschlossen.\n" + , tcppoi->ip); + + tcppoi->port = 0; /* Parameter auf defaultwerte setzen. */ + tcppoi->sock = 0; + tcppoi->mode = 0; + tcppoi->cmdlen = 0; + tcppoi->rxc = 0; + tcppoi->RecvLen = 0; + tcppoi->login = 0; + tcppoi->noacti = 0; + tcppoi->T3 = 0; + tcppoi->inlin = 0; + tcppoi->outlin = 0; + tcppoi->disflg = 0; + tcppoi->LoginPrompt = 0; + tcppoi->state = L2MNIX; + tcppoi->cr = 0; + tcppoi->txstatus = TCP_TX_FREE; + tcppoi->Upcall[0] = 0; + tcppoi->Downcall[0] = 0; + tcppoi->cmd[0] = 0; + tcppoi->rxbuf[0] = 0; + tcppoi->txbuf[0] = 0; + tcppoi->ip[0] = 0; +#ifdef l1HTTPD + tcppoi->status = 0; + tcppoi->http = 0; + tcppoi->fp = NULL; +#endif /* L1HTTPD */ +#ifdef L1IPCONV + tcppoi->CVSlink = FALSE; + tcppoi->Intern = FALSE; +#ifdef L1IRC + tcppoi->IrcMode = FALSE; +#endif /* L1IRC */ +#endif /* L1IPCONV */ + + tcp_tbl_top--; /* TBL-Zaehler um 1 runter. */ + + l2tol7(2, tcppoi, TCP_USER); /* Statusmeldung an L7 Weiterleiten. */ + resptc(g_uid(tcppoi, TCP_USER)); /* patchcord-Liste zuruecksetzen */ + relink(ulink((LEHEAD *)tcppoi), /* aus der aktiv-Liste nehmen */ + (LEHEAD *)tcpfrel.tail); /* in die Freiliste haengen */ +} + + /* Rufzeichen in der MH-Liste Aktualisieren. */ +void MhUpdateTCP(MBHEAD *tbp, /* Buffer */ + BOOLEAN rxtx) /* Flag fuer RX/TX-Bytes. */ +{ + MHEARD *mhp; + char Upcall[10 + 1]; +#ifdef DEBUG_MODUS + lastfunc = "l1tcpip(MhUpdateTCP)"; +#endif /* DEBUG_MODUS */ + + if (tcppoi->Upcall[0] == FALSE) + return; + + if (updmheard((int)tcppoi->port)) /* Pruefen ob die MH-Liste */ + { /* auf den L2-Port aktiv ist. */ + if (valcal(tcppoi->Upcall) == ERRORS) /* Rufzeichen auf Gueltigkeit pruef.*/ + { + ifpp = SetInterface(tcppoi->Interface); + call2str(Upcall, tcppoi->Upcall); + T_LOGL1(TRUE, "(MhUpdateTCP):%s\nRufzeichen (%s) ist ungueltig!\n" + , tcppoi->ip + , Upcall); + return; /* Ungueltiges Rufzeichen. */ + } + + /* Rufzeichen in der MHListe aktual.*/ + if ((mhp = mh_lookup_port(&l2heard, tcppoi->Upcall, tcppoi->port, FALSE)) == NULL) + mhp = mh_add(&l2heard); /* Neuen MH-Eintrag taetigen. */ + + if (mhp) /* Eintrag gefunden. . */ + /* User/Link Aktualisieren. */ + mh_update(&l2heard, mhp, tcppoi->Upcall, tcppoi->port); + + if (tbp == NULL) /* Kein Eintrag fuer RX/TX-Bytes. */ + return; /* Kein Aktualisierung moeglich. */ + + if (rxtx) /* RX/TX-Bytes Aktualisieren. */ + mhp->rx_bytes += (tbp->mbpc); /* RX-Bytes Aktualiseren. */ + else + mhp->tx_bytes += (tbp->mbpc); /* TX-Bytes Aktualisieren. */ + } +} + +void SendTCP(void) /* Frame vorbereiten fuer Sendeliste. */ +{ + MBHEAD *Data = NULL; + SENDTX *NewSTx = NULL; + char c; +#ifdef DEBUG_MODUS + lastfunc = "l1tcpip(SendTCP)"; +#endif /* DEBUG_MODUS */ + + /* Zeiger auf den Inhalt des Frames. */ + Data = (MBHEAD *)ulink((LEHEAD *)tcppoi->outbuf.head); + --tcppoi->outlin; /* Ein Frame weniger. */ + + if ((NewSTx = (SENDTX *)allocb(ALLOC_L1TCPIP)) == NULL) /* Neues Seg.anlegen*/ + { + ifpp = SetInterface(tcppoi->Interface); + T_LOGL1(TRUE, "(SendTCP):%s\nSpeicher (%d) ist voll!\n" + , tcppoi->ip + , nmbfre); + + tcppoi->disflg |= 0x80; /* Segment auf Disconnect setzen. */ + return; /* Kein TX-Segment frei.*/ + } + + if ((NewSTx->Data = SetBuffer()) == NULL) /* Buffer besorgen. */ + { + dealoc((MBHEAD *)ulink((LEHEAD *)NewSTx)); /* TX-Segment entsorgen.*/ + + ifpp = SetInterface(tcppoi->Interface); + T_LOGL1(TRUE, "(SendTCP):%s\nSpeicher (%d) ist voll!\n" + , tcppoi->ip + , nmbfre); + + tcppoi->disflg |= 0x80; /* Segment auf Disconnect setzen. */ + return; /* Buffer voll, abbruch.*/ + } + + NewSTx->Sock = tcppoi->sock; /* Socket setzen. */ + NewSTx->Interface = tcppoi->Interface; /* Interface setzen. */ + NewSTx->Mode = tcppoi->mode; /* Stack-Mode setzen. */ + + while (Data->mbgc != Data->mbpc) /* Alle Zeichen im Buffer lesen und */ + { /* vorbereiten zum Senden. */ + c = getchr(Data); /* Zeichen aus den Buffer lesen. */ + + switch (tcppoi->Interface) /* Interface. */ + { +#ifdef L1TELNET + case KISS_TELNET : /* TELNET-Interface. */ + if ( (c == CR) /* CR-Return */ + ||(c == LF)) /* oder LF-Return. */ + putchr(LF, NewSTx->Data); /* Setze nur LF-Return. */ + break; +#endif /* L1TELNET */ +#ifdef L1HTTPD + case KISS_HTTPD : /* HTTPD-Interface. */ + if (tcppoi->http == TCP_CMD) /* Befehl via HTTPD. */ + { + /* Schreibe Zeichen in Buffer. */ + putv(NewSTx->Data, c); + /* zum naechsten Zeichen. */ + continue; + } + break; +#endif /* L1HTTPD */ + +#ifdef L1IPCONV + case KISS_IPCONV : /* IPCONV-Interface. */ + if ( (c == CR) /* CR-Return */ + ||(c == LF)) /* oder LF-Return. */ + putchr(LF, NewSTx->Data); /* Setze nur LF-Return. */ + break; +#endif /* L1IPCONV */ + +#ifdef L1IRC + case KISS_IRC : /* IRC-Interface. */ + if ( (c == CR) /* CR-Return */ + ||(c == LF)) /* oder LF-Return. */ + putchr(LF, NewSTx->Data); /* Setze nur LF-Return. */ + break; +#endif /* L1IRC */ + + default : /* Unbekanntes Interface. */ + break; + } + + putchr(c, NewSTx->Data); /* Zeichen in Buffer setzen. */ + } + + rwndmb(NewSTx->Data); /* Buffer zurueckspulen. */ + relink((LEHEAD *) NewSTx, (LEHEAD *)rxflTX.tail); /* In Sendeliste umhaengen*/ + + dealmb(Data); /* Alten Buffer leeren/entsorgen. */ + + tcppoi->cmdlen = 0; /* Komandozeile leeren. */ + tcppoi->cmd[0] = 0; /* Nullzeichen setzen. */ +} + +void SenTCP(void) /* Informationstransfer von TCPIP nach Layer X */ +{ + MBHEAD *mbp; +#ifdef DEBUG_MODUS + lastfunc = "l1tcpip(SenTCP)"; +#endif /* DEBUG_MODUS */ + + while (tcppoi->inlin != 0) /* Frame fuer Layer X? */ + { + mbp = (MBHEAD *)tcppoi->inbuf.head; /* Hole Frame. */ + mbp->l2link = (LNKBLK *)tcppoi; + mbp->type = TCP_USER; + mbp->l2fflg = L2CPID; + + if (!fmlink(FALSE, mbp)) /* Frame fuer Layer X weiterreichen. */ + break; /* Link ist verstopft, abbruch. */ + + --tcppoi->inlin; /* Ein Frame weniger. */ + } +} + +/* Frame aus der Sendeliste senden. */ +static BOOLEAN PutflushSockTCP(void) +{ + int ok = FALSE; + int ret = FALSE; +#ifdef DEBUG_MODUS + lastfunc = "l1tcpip(PutflushSockTCP)"; +#endif /* DEBUG_MODUS */ + +#ifdef OS_STACK + if (tcppoi->mode == OS_MODE) + return(PutflushSockOS()); +#endif /* OS_STACK */ + + if (tcppoi->txc) /* Gibt es was zu senden. */ + { + while (1) /* Gibt es was zu senden. */ + { + Fd_set wfdsI; + + if (tcppoi->mode) /* Interner TCP-Stack. */ + { + FD_ZERO_T(&wfdsI); /* Loesche inhalt. */ + FD_SET_T((unsigned)tcppoi->sock, &wfdsI); /* Socket setzen. */ + + if (Select(tcppoi->sock + 1, NULL, &wfdsI, NULL ,NULL))/* Sender frei.*/ + { + if (tcppoi->txstatus == TCP_TX_BUSY) /* Sender ist auf Busy. */ + tcppoi->txstatus = TCP_TX_FREE; /* Sender auf frei stellen. */ + + /* Frame senden */ + if ((ok = Send(tcppoi->sock, tcppoi->txbuf + tcppoi->sum, tcppoi->txc - tcppoi->sum,0)) < 0) + { + ifpp = SetInterface(tcppoi->Interface); + T_LOGL1(TRUE, "(PutflushSockTCP):%s\nFrame senden fehlgeschlagen!\n" + , tcppoi->ip); + + tcppoi->disflg |= 0x80; /* Segment auf Disconnect setzen. */ + return(TRUE); /* Abbruch. */ + } + + /* ggf. Logbuch fuehren. */ + ifpp = SetInterface(tcppoi->Interface); + T_LOGL3(TRUE, "(PutflushSockTCP):%s\nOutput:\r%s\r" + , tcppoi->ip + , tcppoi->txbuf); + + tcppoi->sum += ok; /* Markiere, gesendete Zeichen. */ + + if (tcppoi->sum == tcppoi->txc) /* Alle Zeichen gesendet. */ + break; /* Schleife verlassen. */ + } + + if (ret == FALSE) /* Sender ist nicht frei. */ + { + tcppoi->txstatus = TCP_TX_BUSY; /* Sender auf Busy stellen. */ + return(FALSE); + } + } + } + + tcppoi->sum = 0; /* Zuruecksetzen. */ + tcppoi->txc = 0; + tcppoi->txbuf[0] = 0; + } + + return(FALSE); +} + +/* Pruefen ob noch Frame in der Warteschlage haengen. */ +static int NotContensTCP(void) +{ + BOOLEAN result = TRUE; /* Keine weiteren Aufgaben. */ +#ifdef DEBUG_MODUS + lastfunc = "l1tcpip(NotContensTCP)"; +#endif /* DEBUG_MODUS */ + + switch(tcppoi->Interface) + { +#ifdef L1TELNET + case KISS_TELNET : + if (!tcppoi->LoginPrompt) /* Noch kein Prompt gesendet */ + PromptTCP(tcppoi->Interface); /* Login-Text senden. */ + + break; +#endif /* L1TELNET */ + +#ifdef L1IPCONV + case KISS_IPCONV : + if (!tcppoi->LoginPrompt) /* Noch kein Prompt gesendet */ + PromptTCP(tcppoi->Interface); /* Login-Text senden. */ + + break; +#endif /* L1IPCONV */ + + default : + break; + } + +#ifdef L1HTTPD + /* HTTPD, Uri laden? Nur wenn Sender frei. */ + if ( (tcppoi->Interface == KISS_HTTPD) + &&(tcppoi->status == TCP_URI) + &&(tcppoi->txstatus != TCP_BUSY)) + { + /* uri laden. */ + if (load_uri()) + { + tcppoi->T3 = T3PARA; + tcppoi->noacti = ininat; + /* Aufgabe bearbeitet. */ + result = FALSE; + } + } +#endif /* L1HTTPD */ + + while (tcppoi->outlin != 0) /* Es sind noch Frames in der Warteschlange */ + { + SendTCP(); /* Frame vorbereiten zum senden */ + result = FALSE; /* Aufgabe bearbeitet. */ +#ifdef L1HTTPD + if (tcppoi->Interface == KISS_HTTPD) + { + if (tcppoi->outlin == 0) + { + tcppoi->disflg |= 0x80; + PutHtmlEnd(); + } + } + #endif /* L1HTTPD */ + } + + if (tcppoi->inlin != 0) /* Frame fuer Layer X. */ + { + SenTCP(); /* Frame fuer Layer X weiterreichen. */ + result = FALSE; /* Aufgabe bearbeitet. */ + } + + if (tcppoi->txstatus == TCP_TX_BUSY) /* Sender ist Busy. */ + { + PutflushSockTCP(); /* Frame erneuert senden. */ + result = FALSE; /* Aufgabe bearbeitet. */ + } + + if ( (tcppoi->disflg) /* Steht Segment auf Disc */ + &&(result)) /* und liegen keine weiteren Aufgaben an, */ + return(TRUE); /* Socket Schliessen. */ + + return(FALSE); +} + +/* Pruefe Logindaten. */ +static WORD CheckData(MBHEAD *tbp, /* Buffer mit Logindaten. */ + char *scall, /* Zeiger fuer Rufzeichen. */ + char *contens) /* Zeiger fuer weiterte Login-Daten. */ +{ + char ch; + UWORD len = 0; + register int j = 0; +#ifdef DEBUG_MODUS + lastfunc = "l1tcpip(CheckData)"; +#endif /* DEBUG_MODUS */ + + rwndmb(tbp); /* Bufferdaten zurueckspulen. */ + + if ((tbp->mbpc - tbp->mbgc) > 256) /* Maximale Logindaten 256 Zeichen. */ + { + ifpp = SetInterface(tcppoi->Interface); + T_LOGL1(TRUE, "(CheckData):%s\nMaximale Logindaten (%d) ueberschritten!\n" + , tcppoi->ip + , tbp->mbgc - tbp->mbpc); + return(FALSE); /* Spielmatz, abbruch. */ + } + + while (tbp->mbgc != tbp->mbpc) /* Alle Zeichen aus den Buffer lesen. */ + { + ch = getchr(tbp); /* Zeichen holen. */ + + if ( (ch == CR) /* Zeichen ein CR-Return, */ + ||(ch == LF) /* oder LF-Return, */ + ||(ch == '#')) /* oder Route. */ + break; /* Brechen wir ab. */ + + scall[len++] = ch; /* Zeichen eintragen. */ + } + + scall[len] = '\0'; /* Nullzeichen setzen. */ + + while (tbp->mbgc != tbp->mbpc) /* Restliche Zeichen aus den Buffer lesen. */ + contens[j++] = getchr(tbp); /* Zeichen holen. */ + + contens[j] = '\0'; /* Nullzeichen setzen. */ + +#ifdef L1IRC + if (tcppoi->IrcMode) + { + IrcLinkUser(scall); + IrcLinkNick(contens); + len = L2CALEN; + } +#endif /* L1IRC */ + + return(len); /* Rufzeichenlaenge. */ +} + +/***********************************************/ +/* Rufzeichen suchen. */ +/* ERRORS - Es wurde kein Rufzeichen gefunden. */ +/* NO - Rufzeichen ohne SSID-Vergleich */ +/* gefunden. */ +/* YES - Rufzeichen mit SSID-Vergleich */ +/* gefunden. */ +/***********************************************/ +static TRILLIAN SearchCall(char *call, BOOLEAN ssid) +{ + TCPIP *tpoi; + int i = FALSE; + int j = FALSE; + TRILLIAN found = ERRORS; +#ifdef DEBUG_MODUS + lastfunc = "l1tcpip(SearchCall)"; +#endif /* DEBUG_MODUS */ + + for (i = 0, tpoi = tcptbl; i < MAXTCPIP; ++i, ++tpoi) /* TBL durchgehen. */ + { + if (tpoi->activ == TRUE) /* Nur wenn aktiv! */ + { + if ( (cmpcal(tpoi->Upcall, call) /* Callvergleich. */ + &&(tpoi->port == tcppoi->port))) /* Portvergleich. */ + { + if (ssid == TRUE) /* SSID-Bereich pruefen. */ + { + if (cmpid(tpoi->Upcall, call)) /* Callvergleich mit SSID. */ + { + found = YES; /* Markiere, */ + break; /* Eintrag gefunden. */ + } + + found = NO; /* Rufzeichen ohne SSID gefunden. */ + } + else + found = NO; /* Rufzeichen ohne SSID gefunden. */ + } + + if ( ((tcppoi->activ) /* Sind alle aktiven Sockets durchlaufen, */ + && (j++ >= tcp_tbl_top)) + || (j == tcp_tbl_top)) + break; /* brechen wir ab. */ + } + } + + return(found); +} + +/* Pruefen der SSID. */ +static int CheckSSID(char *scall) +{ + char ssid = 0; +#ifdef DEBUG_MODUS + lastfunc = "l1tcpip(CheckSSID)"; +#endif /* DEBUG_MODUS */ + + while (SearchCall(scall, TRUE) == TRUE)/* Suche Rufzeichen mit SSID-Bereich */ + { + ssid++; /* Es gibt SCHON ein Rufzeichen mit der SSID, um 1 erhoehen. */ + + if (ssid > 15) /* SSID ist groesser als 15. */ + return(EOF); /* Abbruch! */ + + scall[L2IDLEN-1] = (ssid << 1) | 0x60; /* SSID setzen. */ + } + + return((int)ssid); /* SSID ist noch nicht vergeben. */ +} + +/***********************************************/ +/* Ist das Rufzeichen schon mindestens einmal */ +/* eingeloggt, vergeben wir anhand des letzten */ +/* Call ,mit der hoehsten SSID, die SSID. */ +/***********************************************/ +char *CheckCallSSID(char *scall) +{ +#ifdef DEBUG_MODUS + lastfunc = "l1tcpip(CheckCallSSID)"; +#endif /* DEBUG_MODUS */ + + if (SearchCall(scall,FALSE) == NO) /* Suche Rufzeichen ohne Beachtung */ + { /* der SSID. */ + if (CheckSSID(scall) != EOF) /* Pruefe Rufzeichen auf SSID, */ + /* gegebenfalls neue SSID vergeben. */ + return(scall); /* Rufzeichen mit aktueller SSID. */ + else + { + ifpp = SetInterface(tcppoi->Interface); + T_LOGL1(TRUE, "(CheckCallSSID):%s\nAlle SSID-Nummern vergeben!\n" + , tcppoi->ip); + return(NULL); /* Alle SSID-Nummern sind belegt. */ + } + } + else /* Rufzeichen ohne SSID gefunden. */ + return(scall); /* Rufzeichen setzen. */ +} + +/* Pruefe Loginrufzeichen. */ +static BOOLEAN CheckCall(MBHEAD *tbp, /* Buffer mit Logindaten. */ + char *contens) /* Zeiger fuer erweitere Logibdaten. */ +{ + char scall[256]; + char *call = scall; + char logincall[L2IDLEN]; + char *pcall = logincall; + WORD len = FALSE; +#ifdef DEBUG_MODUS + lastfunc = "l1tcpip(CheckCall)"; +#endif /* DEBUG_MODUS */ + + if ((len = CheckData(tbp, scall, contens)) == FALSE) /* Rufzeichen holen. */ + return(TRUE); /* Ungueltiges Rufzeichen. */ + + if (getcal(&len,&call,FALSE,logincall) == YES) /* Rufzeichen pruefen */ + { + if (valcal(logincall) == ERRORS) /* Pruefe Rufzeichen auf Gueltigkeit. */ + { + ifpp = SetInterface(tcppoi->Interface); + T_LOGL1(TRUE, "(CheckCall):%s\n%s : Ungueltiges Rufzeichen\n" + , tcppoi->ip + , pcall); + return(TRUE); /* Rufzeichen ungueltig. */ + } + + /* Pruefen ob das Rufzeichen als suspend markiert ist. */ + if (is_down_suspended(logincall, tcppoi->port) == TRUE) + { + ifpp = SetInterface(tcppoi->Interface); + T_LOGL1(TRUE, "(CheckCall):%s\n%s : Rufzeichen ist gesperrt!\n" + , tcppoi->ip + , pcall); + return(TRUE); /* Rufzeichen ist gesperrt. */ + } + + if (cmpcal(logincall, myid)) /* Pruefen ob Rufzeichen unser Node ist. */ + { + ifpp = SetInterface(tcppoi->Interface); + T_LOGL1(TRUE, "(CheckCall):%s\n%s : Rufzeichen ist user NODE!\n" + , tcppoi->ip + , pcall); + return(TRUE); /* Rufzeichen wird Missbrauch. */ + } + + /***********************************************/ + /* Ist das Rufzeichen schon mindestens einmal */ + /* eingeloggt, vergeben wir anhand des letzten */ + /* Call, mit der hoehsten SSID, die SSID oder */ + /* die angegebene SSID im Rufzeichen. */ + /***********************************************/ + if ((pcall = CheckCallSSID(logincall)) != NULL) + { + cpyid(tcppoi->Upcall, pcall); /* Quellrufzeichen. */ + cpyid(usrcal, pcall); /* Aktuelle Rufzeichen setzen. */ + cpyid(tcppoi->Downcall, myid); /* Zielrufzeichen. */ + return(FALSE); /* Gueltiges Rufzeichen gefunden. */ + } + else + { + ifpp = SetInterface(tcppoi->Interface); + T_LOGL1(TRUE, "(CheckCall):%s\nSSID ausserhalb des Gueltigkeitsbereiches.\n" + , tcppoi->ip); + + return(TRUE); /* SSID ausserhalb des Gueltigkeitsbereich. */ + } + } + + ifpp = SetInterface(tcppoi->Interface); + T_LOGL1(TRUE, "(CheckCall):%s\n%s : Ungueltiges Rufzeichen\n" + , tcppoi->ip + , call); + return(TRUE); /* Ungueltiges Rufzeichen. */ +} + +/* Rufzeichen anmelden. */ +BOOLEAN LoginTCP(MBHEAD *tbp) +{ + char buffer[256 + 1]; /* Buffer fuer erweiterte Logindaten. */ + char Upcall[10 + 1]; +#ifdef DEBUG_MODUS + lastfunc = "l1tcpip(LoginTCP)"; +#endif /* DEBUG_MODUS */ + + buffer[0] = 0; + + if (CheckCall(tbp, buffer)) /* Pruefe Loginrufzeichen. */ + { + dealmb(tbp); /* Loginrufzeichen ist ungueltig, */ + return(TRUE); /* Buffer entsorgen. */ + } + + /* ggf. Logbuch fuehren. */ + ifpp = SetInterface(tcppoi->Interface); + call2str(Upcall, tcppoi->Upcall); + T_LOGL2(TRUE, "(LoginTCP):%s\nEingeloggt als %s.\n" + , tcppoi->ip + , Upcall); + + tcppoi->login = TRUE; /* Markiere, User als eingeloggt. */ + + if (++nmbtcp > nmbtcp_max) /* Maximalwert fuer die Statistik */ + nmbtcp_max = nmbtcp; + + tcppoi->state = L2MCONNT; /* Statusmeldung an den L7 Melden. */ + +#ifdef L1IPCONV + /* Ist Interface IPConvers? */ + if (tcppoi->Interface == KISS_IPCONV) + { + int i = 0, + j = 0; + + if (buffer[0] != FALSE) + { + buffer[256] = 0; /* Maximale Buffergrenze. */ + + tcppoi->cmdlen = strlen(buffer); /* Laenge setzen. */ + + if (tcppoi->cmdlen > 0) /* Kanalangabe. */ + { + while(tcppoi->cmdlen--) + tcppoi->cmd[i++] = buffer[j++]; /* Channel setzen. */ + + tcppoi->cmd[i++] = 0; /* Nullzeichen setzen. */ + + ifpp = SetInterface(tcppoi->Interface); /* akt. Interface setzen. */ + T_LOGL2(TRUE, "(LoginTCP):%s\nMit Channelangabe (%s).\n" + , tcppoi->ip + , tcppoi->cmd); + } + } + } +#endif /* L1IPCONV */ + + dealmb(tbp); /* Buffer entsorgen. */ + return(FALSE); +} + +/* Packet umhaengen. */ +void RelinkTCP(MBHEAD *tbp) +{ +#ifdef DEBUG_MODUS + lastfunc = "l1tcpip(RelinkTCP)"; +#endif /* DEBUG_MODUS */ + + if (tbp->mbpc) /* Es gíbt daten. */ + { + rwndmb(tbp); /* Buffer zurueckspulen. */ + /* Packet umhaengen. */ + relink((LEHEAD *)tbp, (LEHEAD *)tcppoi->inbuf.tail); + ++tcppoi->inlin; /* Eingabebuffer hat Daten */ + + if (tcppoi->login == TRUE) + MhUpdateTCP(tbp, TRUE); /* MH-Liste Aktualisieren. */ + + tcppoi->noacti = ininat; /* Timeout neu aufziehen. */ + tcppoi->T3 = T3PARA; /* T3-Timer neu aufziehen. */ + tcppoi->cmdlen = 0; /* Zaehler zuruecksetzen. */ + } +} + +/* Anhand des Sockets den User aus der Liste holen. */ +TCPIP *FdReadTCP(Fd_set Rmask) +{ + int i, j = FALSE; + LHEAD *h_llp; + h_llp = &tcpactl; +#ifdef DEBUG_MODUS + lastfunc = "l1tcpip(FdReadTCP)"; +#endif /* DEBUG_MODUS */ + + for (i = 0, tcppoi = tcptbl; i < MAXTCPIP; ++i, ++tcppoi) /* TBL durchgehen.*/ + { + if (tcppoi->mode != INT_STACK) + continue; + + if (tcppoi->activ) /* Nur wenn aktiv. */ + { + if (CheckSocket()) /* Pruefe, ob Socket aktiv ist. */ + { + CloseSockTCP(FALSE, tcppoi->Interface); /* Schliesse Socket. */ + return(NULL); /* Socket deaktiv, Segment auf DISC stellen. */ + } + + if (FD_ISSET_T(tcppoi->sock, &Rmask)) /* Socketvergleich. */ + { + ulink((LEHEAD *)tcppoi); /* wir haben einen Link gefunden. */ + relink((LEHEAD *)tcppoi, (LEHEAD *)h_llp->tail); + return(tcppoi); + } + } + + if ( ((tcppoi->activ) /* Socket ist aktiv, */ + && (j++ >= tcp_tbl_top)) /* merken und pruefen, */ + || (j == tcp_tbl_top)) /* alle aktiven Socket's bearbeitet*/ + break; /* koennen wir abbrechen. */ + } + + return(NULL); /* Keinen Eintrag gefunden. */ +} + +/* Anhand des Sockets den User aus der Liste holen. */ +TCPIP *FdReadSockTCP(int Sock, UWORD Interface, UWORD Mode) +{ + int i, j = FALSE; + LHEAD *h_llp; + h_llp = &tcpactl; +#ifdef DEBUG_MODUS + lastfunc = "l1tcpip(FdReadSockTCP)"; +#endif /* DEBUG_MODUS */ + + for (i = 0, tcppoi = tcptbl; i < MAXTCPIP; ++i, ++tcppoi) /*TBL durchgehen. */ + { + if (tcppoi->activ) /* Nur wenn aktiv. */ + { + if ( (tcppoi->sock == Sock) /* Socketvergleich. */ + &&(tcppoi->Interface == Interface) + &&(tcppoi->mode == Mode)) + { + if (CheckSocket()) /* Pruefe, ob Socket aktiv ist. */ + { + CloseSockTCP(FALSE, tcppoi->Interface); /* Schliesse Socket. */ + return(NULL); /* Socket deaktiv, Segment auf DISC stellen. */ + } + + ulink((LEHEAD *)tcppoi); /* wir haben einen Link gefunden. */ + relink((LEHEAD *)tcppoi, (LEHEAD *)h_llp->tail); + return(tcppoi); + } + } + + if ( ((tcppoi->activ) /* Socket ist aktiv, */ + && (j++ >= tcp_tbl_top)) /* merken und pruefen, */ + || (j == tcp_tbl_top)) /* alle aktiven Socket's bearbeitet*/ + break; /* koennen wir abbrechen. */ + } + + return(NULL); /* Keinen Eintrag gefunden. */ +} + +/* Sender bis max. TXLEN fuellen. */ +static BOOLEAN PutvSockTCP(int c) +{ +#ifdef DEBUG_MODUS + lastfunc = "l1tcpip(PutvSockTCP)"; +#endif /* DEBUG_MODUS */ + + if (tcppoi->txc >= TXLEN) /* Maximale TXLEN erreicht. */ + { + tcppoi->txbuf[tcppoi->txc] = 0; + + if (PutflushSockTCP()) /* Frame senden. */ + return(TRUE); + } + + tcppoi->txbuf[tcppoi->txc++] = c; /* Fuelle txbuffer. */ + return(FALSE); +} + +/* Eingehende Frames bearbeiten. */ +void TcpipRX(void) +{ + READRX *SRx; + READRX *SRxPrev; +#ifdef DEBUG_MODUS + lastfunc = "l1tcpip(TcpipRX)"; +#endif /* DEBUG_MODUS */ + + for (SRx = (READRX *)rxflRX.head; /* Alle RX-Segmente durchgehen. */ + SRx != (READRX *)&rxflRX; + SRx = SRxPrev) + { + SRxPrev = SRx->next; + + /* Aktuellen User aus der Liste holen. */ + if ((tcppoi = FdReadSockTCP(SRx->Sock, SRx->Interface, SRx->Mode)) == NULL) + { + /* ggf. Logbuch fuehren. */ + ifpp = SetInterface(SRx->Interface); + T_LOGL1(TRUE, "(TcpipRX):\nKein User gefunden (Sock:%d, Interface:%d, Mode:%d\n" + "RX-Segment entsorgen.\n" + , SRx->Sock + , SRx->Interface + , SRx->Mode); + + if (SRx->Data != NULL) /* Wenn es daten gibt, */ + dealmb(SRx->Data); /* entsorgen. */ + + dealoc((MBHEAD *)ulink((LEHEAD *)SRx)); /* RX-Segment entsorgen. */ + continue; + } + + switch(tcppoi->Interface) + { +#ifdef L1HTTPD + case KISS_HTTPD : + /* HTTPD-Service. */ + TcpipHttpd(SRx->Data); + + /* Buffer entsorgen. */ + if (SRx->Data != NULL) + dealmb(SRx->Data); + + dealoc((MBHEAD *)ulink((LEHEAD *)SRx)); /* TX-Segment entsorgen. */ + /* naechstes Frame aus der Liste holen. */ + break; +#endif /* L1HTTPD */ + + default : + if (!tcppoi->login) /* Nicht angemeldet. */ + { + if (LoginTCP(SRx->Data)) /* User/Link anmelden. */ + tcppoi->disflg |= 0x80; /* Anmeldung war nicht erfolgreich. */ + } + else /* User-Link ist angemeldet.*/ + RelinkTCP(SRx->Data); /* Frame weiterleiten. */ + + dealoc((MBHEAD *)ulink((LEHEAD *)SRx)); /* RX-Segment entsorgen. */ + break; + } + } +} + +/* Ausgehende Frames senden. */ +void TcpipTX(void) +{ + SENDTX *STx; + SENDTX *STxPrev; + char buf; + int len = 0; +#ifdef DEBUG_MODUS + lastfunc = "l1tcpip(TcpipTX)"; +#endif /* DEBUG_MODUS */ + + for (STx = (SENDTX *)rxflTX.head; /* Alle TX-Segmente durchgehen. */ + STx != (SENDTX *)&rxflTX; + STx = STxPrev) + { + STxPrev = STx->next; + + /* Aktuellen User aus der Liste holen. */ + if ((tcppoi = FdReadSockTCP(STx->Sock, STx->Interface, STx->Mode)) == NULL) + { + /* ggf. Logbuch fuehren. */ + ifpp = SetInterface(STx->Interface); + T_LOGL1(TRUE, "(TcpipRX):\nKein User gefunden (Sock:%d, Interface:%d, Mode:%d\n" + "TX-Segment entsorgen.\n" + , STx->Sock + , STx->Interface + , STx->Mode); + + if (STx->Data != NULL) /* Wenn es daten gibt, */ + dealmb(STx->Data); /* entsorgen. */ + + dealoc((MBHEAD *)ulink((LEHEAD *)STx)); /* TX-Segment entsorgen. */ + continue; /* zum naechsten Segment. */ + } + + if (tcppoi->txstatus == TCP_TX_BUSY) /* Sender steht auf Busy. */ + continue; /* zum naechsten eintrag. */ + + if (tcppoi->login == TRUE) + MhUpdateTCP(STx->Data, FALSE); /* MH-Liste updaten */ + + /* solange Daten vorhanden sind */ + while (STx->Data->mbgc != STx->Data->mbpc) + { + if (PutvSockTCP(buf = getchr(STx->Data))) /* Zeichen in sendebuffer. */ + { + if (STx->Data != NULL) /* Wenn es daten gibt, */ + dealmb(STx->Data); /* entsorgen. */ + + dealoc((MBHEAD *)ulink((LEHEAD *)STx)); /* TX-Segment entsorgen. */ + continue; /* zum naechsten eintrag. */ + } + } + + tcppoi->txbuf[tcppoi->txc] = 0; + PutflushSockTCP(); /* Frame senden. */ + + if (STx->Data != NULL) /* Wenn es daten gibt, */ + dealmb(STx->Data); /* entsorgen. */ + + dealoc((MBHEAD *)ulink((LEHEAD *)STx)); /* TX-Segment entsorgen. */ + + len = 0; /* Zuruecksetzen. */ + } +} + +T_INTERFACE *SetInterface(UWORD Interface) +{ +#ifdef DEBUG_MODUS + lastfunc = "l1tcpip(SetInterface)"; +#endif /* DEBUG_MODUS */ + + switch(Interface) + { + case KISS_TELNET : + ifpp = &ifp[TEL_ID]; + break; + + case KISS_HTTPD : + ifpp = &ifp[HTP_ID]; + break; + + case KISS_IPCONV : + ifpp = &ifp[CVS_ID]; + break; + + default : + break; + } + + return(ifpp); +} + +/*********************************/ +/* Statusaenderungen, */ +/* Frame vorbereiten zum Senden. */ +/* evl. Socket schliessen. */ +/*********************************/ +void TcpipSV(void) +{ + int i, j = FALSE; +#ifdef DEBUG_MODUS + lastfunc = "l1tcpip(TcpipSV)"; +#endif /* DEBUG_MODUS */ + + for (i = 0, tcppoi = tcptbl; i < MAXTCPIP; ++i, ++tcppoi) /*TBL durchgehen. */ + { + if (tcppoi->activ) /* Socket ist aktiv. */ + { + if (tcppoi->state != L2MNIX) /* Statusaenderung. */ + { + l2tol7(tcppoi->state, tcppoi, TCP_USER); /* Statusmeldungen an L7. */ + tcppoi->state = L2MNIX; /* Status auf 0 setzen. */ + cpyid(tcppoi->Upcall, usrcal); /* Quellrufzeichen setzen. */ + +#ifdef L1IPCONV + if ( (tcppoi->Interface == KISS_IPCONV) + &&(tcppoi->Intern == FALSE)) + IPConvLogin(); +#endif /* L1IPCONV */ +#ifdef L1IRC + if ( (tcppoi->Interface == KISS_IRC) + &&(tcppoi->Intern == FALSE)) + IPConvLogin(); +#endif /* L1IRC */ + } + + if (NotContensTCP()) /* Frame vorbereiten zum Senden. */ + CloseSockTCP(FALSE, tcppoi->Interface); /* Socket schliessen. */ + } + + if ( ((tcppoi->activ) /* Socket ist aktiv, */ + && (j++ >= tcp_tbl_top)) /* merken und pruefen, */ + || (j == tcp_tbl_top)) /* alle aktiven Socket's bearbeitet.*/ + break; /* koennen wir abbrechen. */ + } +} + + +/* Lausche auf TCP-Stack. */ +void ListenTCP(void) +{ + UWORD Interface = KISS_TCPIP; + int count, + max_fdI = 0, + i; + Fd_set Rmask; +#ifdef DEBUG_MODUS + lastfunc = "l1tcpip(ListenTCP)"; +#endif /* DEBUG_MODUS */ + + FD_ZERO_T(&Rmask); + + /* fuer alle Interfaces die benutzten Filedescriptoren fuer select() */ + /* ermitteln und eintragen */ + for (i = 0; i < MAXINTERFACE; i++, Interface++) + { /* Zeiger auf das aktuelle Interface. */ + if ((ifpp = SearchIf(Interface)) == NULL) + continue; /* Zum naechsten Interface. */ + + if (ifpp->actively == FALSE) /* Interface ist nicht aktiv.*/ + continue; /* Zum naechsten Interface. */ + + FD_SET_T((unsigned)ifpp->ISock, &Rmask); /* Socket setzen. */ + + if (ifpp->ISock > max_fdI - 1) + max_fdI = ifpp->ISock + 1; + } + + PutSocketTCP(&Rmask, &max_fdI); /* Socket setzen. */ + + /* Pruefe auf Aktivitaet, Int.Stack. */ + count = Select(max_fdI, &Rmask, NULL, NULL, NULL); + + if (!count) /* Keine Aktivitaet. */ + return; /* Zur Hauptschleife. */ + + Interface = KISS_TCPIP; /* 1. TCPIP-Interface setzen. */ + + for (i = 0; i < MAXINTERFACE; i++, Interface++) + { /* Zeiger auf das aktuelle Interface. */ + if ((ifpp = SearchIf(Interface)) == NULL) + continue; /* Zum naechsten Interface. */ + + if (ifpp->actively == FALSE) /* Interface ist nicht aktiv. */ + continue; /* Zum naechsten Interface. */ + + if (FD_ISSET_T(ifpp->ISock, &Rmask)) + { + char ip[IPADDR + 1]; + int NewSock = EOF; + Socklen_t addrlen = EOF; + ULONG peerip = 0; + char *p = (char *) &peerip; + + addrlen = sizeof Peeraddr_in; /* Neuen Socket anlegen. */ + if ((NewSock = Accept(ifpp->ISock, (struct Sockaddr *) &Peeraddr_in, &addrlen)) != EOF) + { + peerip = Peeraddr_in.sin_addr._S_addr; /* IP-Adresse ermitteln. */ + sprintf (ip, "%d.%d.%d.%d",(p[3] & 255) + ,(p[2] & 255) + ,(p[1] & 255) + ,(p[0] & 255)); + } + + if (AddUserTCP(ifpp, NewSock, ip)) /* Neuen User hinzufuegen */ + { + Close(NewSock); + continue; /* zum naechsten Interface. */ + } + + T_LOGL2(TRUE, "(RecvTCP):\n" + "Verbindung zur IP-Adresse %s angenommen.\n" + "Neu erzeugter Socket ist (%d).\n" + , ip + , NewSock); + continue; /* zum naechsten Interface. */ + } /* Interface-Schnittstelle. */ + + if ((tcppoi = FdReadTCP(Rmask)) != NULL) /* Den User aus der Liste Holen */ + { + T_LOGL3(TRUE, "(ListenTCP):%s\nAktuellen Socket (%d) in der Liste gefunden.\n" + , tcppoi->ip + , tcppoi->sock); + + ServTCP(); /* Eingehende TCPIP Packete verarbeiten. */ + continue; /* zum naechsten Interface. */ + } /* Socket suchen. */ + } /* for-schleife. */ +} + +/* TCPIP-Service. */ +void TcpipSRV(void) +{ +#ifdef DEBUG_MODUS + lastfunc = "l1tcpip(TcpipSRV)"; +#endif /* DEBUG_MODUS */ + +#ifdef OS_STACK + ListenTCP_OS(); +#endif /* OS_STACK */ + ListenTCP(); /* Lausche auf TCP-Stack. */ + TcpipTX(); /* ausstehende Frames senden wenn vorhanden */ + TcpipRX(); /* eingehende Frame analysieren. */ + /* Frames in der Warteschlange umhaengen. */ + TcpipSV(); /* Pruefe auf Status, Informationstransfer und ggf */ +} + +/* Aktuelle TCPIP-Daten sichern. */ +void DumpTCP(MBHEAD* mbp) +{ + T_INTERFACE *ifpoi; + UWORD Interface = KISS_TCPIP; + int i; +#ifdef DEBUG_MODUS + lastfunc = "l1tcpip(DumpTCP)"; +#endif /* DEBUG_MODUS */ + + for (i = 0; i < MAXINTERFACE; i++, ifpoi++) /* INTERFACE-TBL durchgehen. */ + { + if ((ifpoi = SearchIf(Interface++)) == NULL) /* Zeiger auf das akt. Inter.*/ + continue; /* Zum naechsten Interface. */ + + if (ifpoi->actively == TRUE) /* Nur wenn Interface aktiv. */ + { + putprintf(mbp,";\r; %s-Server\r;\r", ifpoi->name); + putprintf(mbp,"%s P ", ifpoi->name); + putnum(Ntohs(ifpoi->tcpport), mbp); + putprintf(mbp,"\r%s L %u",ifpoi->name, ifpoi->log); + + putstr("\r;\r",mbp); + } + } + +#ifdef L1IPCONV + IPConvDump(mbp); +#endif /* L1IPCONV */ +} + +/* Pruefe Loginzeichen. */ +BOOLEAN CheckContens(char contents) +{ +#ifdef DEBUG_MODUS + lastfunc = "l1tcpip(CheckContens)"; +#endif /* DEBUG_MODUS */ + + if ( !(contents >= 'A' && contents <= 'Z') + && !(contents >= 'a' && contents <= 'z') + && !(contents >= '0' && contents <= '9') + && !(contents == '-') + && !(contents == '/') +#ifdef L1TELNET + && !((contents == '#') && (tcppoi->Interface != KISS_TELNET)) +#endif /* L1TELNET. */ +#ifdef L1IPCONV + && !((contents == ' ') && (tcppoi->Interface == KISS_IPCONV)) +#endif /* L1IPCONV */ +#ifdef L1IRC + && !((contents == ' ') && (tcppoi->Interface == KISS_IRC)) +#endif /* L1IRC */ + && !(contents == CR ) + && !(contents == LF )) + return(TRUE); + else + return(FALSE); +} + +/* Info vom L7 an TCPIP-Interface senden */ +BOOLEAN itoTCP(BOOLEAN conflg, MBHEAD *ublk) +{ + TCPIP *tcppoi = (TCPIP *)ublk->l2link; + int mem = (nmbfre_max / 2); +#ifdef DEBUG_MODUS + lastfunc = "l1tcpip(itoTCP)"; +#endif /* DEBUG_MODUS */ + + if ( (conflg == TRUE) + ||(tcppoi->outlin < conctl)) + { + if ((ublk->mbpc - ublk->mbgc) == 0) /* Frames ohne Info ignorieren */ + { + T_LOGL1(TRUE, "(itoTCP):%s\nFrames ohne Info ignorieren.\n" + , tcppoi->ip); + + dealmb((MBHEAD *)ulink((LEHEAD *)ublk)); /* Frame entsorgen.*/ + return (TRUE); /* Frame verarbeitet. */ + } + + if ( (nmbfre < 300) + ||(mem < (nmbfre_max - nmbfre))) + { + dealmb((MBHEAD *)ulink((LEHEAD *)ublk)); /* Frame entsorgen.*/ + + /* ggf. Logbuch fuehren. */ + ifpp = SetInterface(tcppoi->Interface); + T_LOGL1(TRUE, "(itoTCP):%s\nSpeicher (%d) ist voll!\n" + , tcppoi->ip + , nmbfre); + + tcppoi->disflg |= 0x80; /* Segment auf Disconnect setzen. */ + return (TRUE); /* Frame verarbeitet. */ + } + /* Markiere das es was zu senden gibt */ + relink(ulink((LEHEAD *)ublk), (LEHEAD *)tcppoi->outbuf.tail); + ublk->type = L2MNIX; /* Info-Frame (keine Meldung) */ + ublk->l4type = HMRINFO; + ++tcppoi->outlin; /* Frame in die Warteschlange haengen. */ + return (TRUE); /* Frame verarbeitet. */ + } + + /* ggf. Logbuch fuehren. */ + ifpp = SetInterface(tcppoi->Interface); + T_LOGL1(TRUE, "(itoTCP):%s\nLink ist verstopft!\n" + , tcppoi->ip); + + return (FALSE); /* Link ist verstopft. */ +} + +/* User hat ein Disconnect eingeleitet. */ +void SetDiscTCP(void) +{ +#ifdef DEBUG_MODUS + lastfunc = "l1tcpip(SetDiscTCP)"; +#endif /* DEBUG_MODUS */ + + /* ggf. Logbuch fuehren. */ + ifpp = SetInterface(tcppoi->Interface); + T_LOGL2(TRUE, "(SetDiscTCP):%s\nTCP-Segment auf Disconnect setzen!\n" + , tcppoi->ip); + + tcppoi->disflg |= 0x80; /* Segment auf Disconnect setzen. */ +} + +/* TCPIP-Timer */ +void TimerTCP(void) +{ + int i, + j = 0; +#ifdef DEBUG_MODUS + lastfunc = "l1tcpip(TimerTCP)"; +#endif /* DEBUG_MODUS */ + + for (i = 0, tcppoi = tcptbl; i < MAXTCPIP; ++i, ++tcppoi)/* TBL durchgehen. */ + { + if (tcppoi->activ) /* Nur wenn aktiv. */ + { + if ( (tcppoi->noacti != FALSE) /* Noactivity-Timer reduzieren */ + &&(--tcppoi->noacti == FALSE)) /* und ggf. User disconnecten. */ + { + ifpp = SetInterface(tcppoi->Interface); + /* ggf. Logbuch fuehren. */ + T_LOGL1(TRUE, "(TimerTCP):%s\nNoactivity-Timer abgelaufen, Segment auf DISC stellen!\n" + , tcppoi->ip); + + tcppoi->disflg |= 0x80; /* Segment auf Disconnect setzen. */ + continue; + } + + if (tcppoi->T3 == 0) /* T3-Timer abgelaufen. */ + { + MhUpdateTCP(NULL, TRUE); /* MH-Liste updaten. */ + tcppoi->T3 = T3PARA; /* T3-Timer neusetzen */ + } + else + tcppoi->T3--; /* T3-Timer ist noch nicht abgelaufen, */ + /* weiter runterzaehlen. */ + } + + if ( ((tcppoi->activ) /* Sind alle aktiven Sockets durchlaufen, */ + && (j++ >= tcp_tbl_top)) + || (j == tcp_tbl_top)) + break; /* brechen wir ab. */ + } +} + +/* System- und Errormeldungen in einer Logdatei schreiben. */ +void WriteLogTCP(BOOLEAN flag, const char *format, ...) +{ + FILE *fp = NUL; + va_list arg_ptr; + struct tm *lt; +#ifdef DEBUG_MODUS + lastfunc = "l1tcpip(WriteLogTCP)"; +#endif /* DEBUG_MODUS */ + + if (ifpp == NULL) /* Kein Interface angegeben!!!. */ + { + printf("(WriteLogTCP): ACHTUNG, kein Interface angegeben!!!\n"); + return; /* keine Meldung schreiben. */ + } + + switch(ifpp->Interface) + { +#ifdef L1TELNET + case KISS_TELNET: + { + if (!ifpp->log) /* Loglevel ist nicht eingeschaltet. */ + return; /* Keine Logmeldungen schreiben. */ + + fp = fopen(TELNETLOG, "a+"); /* Datei oeffnen. */ + break; + } +#endif /* L1TELNET */ + +#ifdef L1HTTPD + case KISS_HTTPD: + { + if (!ifpp->log) /* Loglevel ist nicht eingeschaltet. */ + return; /* Keine Logmeldungen schreiben. */ + + fp = fopen(HTTPDLOG, "a+"); /* Datei oeffnen. */ + break; + } +#endif /* L1HTTPD */ + +#ifdef L1IPCONV + case KISS_IPCONV: + { + if (!ifpp->log) /* Loglevel ist nicht eingeschaltet. */ + return; /* Keine Logmeldungen schreiben. */ + + fp = fopen(IPCONVLOG, "a+"); /* Datei oeffnen. */ + break; + } +#endif /* L1IPCONV */ + +#ifdef L1IRC + case KISS_IRC: + { + if (!ifpp->log) /* Loglevel ist nicht eingeschaltet. */ + return; /* Keine Logmeldungen schreiben. */ + + fp = fopen(IRCLOG, "a+"); /* Datei oeffnen. */ + break; + } +#endif /* L1IPCONV */ + + default : + break; + } + + if (fp == NULL) /* Fehler beim oeffnen der Datei. */ + { + printf("(WriteLogTCP):\nLOG-Datei kann nicht geoeffnet werden!\n"); + return; /* Abbruch. */ + } + + lt = localtime(&sys_time); + + if (flag) /* Datum/Zeit schreiben. */ + fprintf(fp, "%16.16s ", ctime(&sys_time)); + + va_start(arg_ptr, format); + vfprintf(fp, format, arg_ptr); + va_end(arg_ptr); + fprintf(fp, "\n"); + fclose(fp); /* Datei schliessen. */ +} + +/* TCPIP-Sockets killen. */ +int KillTCP(UWORD port, char *call, WORD what) +{ + int i = FALSE; + UWORD kill_zaehler = FALSE; +#ifdef DEBUG_MODUS + lastfunc = "l1tcpip(KillTCP)"; +#endif /* DEBUG_MODUS */ + + /* Alle Aktive Sockets durchlaufen. */ + for (i = 0, tcppoi = tcptbl; i < MAXTCPIP; ++i, ++tcppoi) /* TBL durchgehen */ + { + if ( (tcppoi->activ) /* Nur wenn aktiv. */ + &&((tcppoi->port == port) /* Port gleich. */ + || (port == 255))) /* oder alle Port's. */ + { + switch(what) + { + case 1 : /* Rufzeichen disconnecten. */ + if (!cmpid (call, tcppoi->Upcall)) /* Callvergleich. */ + continue; /* zum naechsten eintrag. */ + break; + + case 3 : /* Alle TCPIP-Links disconnecten. */ + break; + + default: /* Ungueltige option. */ + continue; /* Zum naechsten eintrag. */ + } + + ifpp = SetInterface(tcppoi->Interface); /* akt. Interface setzen. */ + /* ggf. Logbuch fuehren. */ + T_LOGL1(TRUE, "(KillTCP):%s\nSegment wird auf DISC gesetzt!\n" + , tcppoi->ip); + + tcppoi->disflg |= 0x80; /* Segment auf DISC stellen. */ + kill_zaehler++; /* Killzaehler um eins hoeher. */ + } + } + + return(kill_zaehler); +} + +/* Buffer besorgen. */ +MBHEAD *SetBuffer(void) +{ + MBHEAD *tbp = NULL; +#ifdef DEBUG_MODUS + lastfunc = "l1tcpip(SetBuffer)"; +#endif /* DEBUG_MODUS */ + + if (nmbfre < 300) /* Buffer liegt unterhalb des Grenzbereich. */ + return(NULL); /* Kein Buffer zur Verfuegung. */ + + if ((tbp = (MBHEAD *) allocb(ALLOC_L1TCPIP)) == NULL) /* Buffer besorgen. */ + return(NULL); /* Es steht kein buffer zur Verfuegung. */ + + return(tbp); +} + +/* Pruefe, ob Socket aktiv ist. */ +static BOOLEAN CheckSocket(void) +{ +#ifdef DEBUG_MODUS + lastfunc = "l1tcpip(CheckSocket)"; +#endif /* DEBUG_MODUS */ + +#ifdef OS_STACK + if (tcppoi->mode == OS_MODE) + return(CheckSocketOS()); +#endif /* OS_STACK */ + + if (Send(tcppoi->sock, "", 0, 0) < 0) + { + ifpp = SetInterface(tcppoi->Interface); + T_LOGL1(TRUE, "(CheckSocket):%s\nSocket ist nicht mehr aktiv!\n" + , tcppoi->ip); + + /* Segment auf DISC setzen. */ + tcppoi->disflg |= 0x80; + return(TRUE); + } + else + return(FALSE); + + return(TRUE); +} + +#endif /* L1TCPIP */ + +/* End of src/l1tcpip.c */ diff --git a/src/l1telnet.c b/src/l1telnet.c new file mode 100755 index 0000000..1c536e9 --- /dev/null +++ b/src/l1telnet.c @@ -0,0 +1,173 @@ +#include "tnn.h" +#ifdef L1TELNET + +static T_INTERFACE *ifpp; /* Zeiger auf das Aktuelle Interface.*/ + +/* TELNET-Server Einstellung aendern/setzen. */ +void ccptelnet(void) +{ + MBHEAD *mbp; + char ch; + int tmp_fd = EOF; + int newloglevel = 0; + int new_tcp_port = 0; +#ifdef DEBUG_MODUS + lastfunc = "l1telnet(ccptelnet)"; +#endif /* DEBUG_MODUS */ + + ifpp = &ifp[TEL_ID]; /* Dann Zeiger auf das TELNET-Interface. */ + + if (issyso() && skipsp(&clicnt, &clipoi)) /* Sysop will aendern. */ + { + clicnt--; + ch = toupper(*clipoi++); + + switch (ch) + { + case 'P': /* Sysop will Telnet-Port aéndern */ + if (!skipsp(&clicnt, &clipoi)) + { + putmsg("Invalid Parameter\r"); + return; + } + + new_tcp_port = nxtlong(&clicnt, &clipoi); /* Neuen Port ermitteln */ + + if ( (new_tcp_port < 1) + ||(new_tcp_port > 65535)) + { + putmsg("TCP-Port not valid, not changed !!!\r"); + return; + } + + if (ifpp->actively == FALSE) /* Telnet ist deaktiv.*/ + { + putmsg("TCP-Port haven not switched on!\r"); + return; + } + /* Wenn NEUER Port und ALTER Port gleich sind, nicht neu Initialisieren.*/ + if (ifpp->tcpport == Htons((unsigned short)new_tcp_port)) + { + putmsg("TCP-Port successfully changed\r"); + return; + } + + /* Neuen TCP-Port Initialisieren. */ + if ((tmp_fd = SetupTCP(ifpp->name, (unsigned short)new_tcp_port)) != EOF) + { +#ifdef OS_STACK + int tmp_fd_OS; + + if ((tmp_fd_OS = SetupOS(ifpp, (unsigned short)new_tcp_port)) != EOF) + { + /* alten Socket schliessen */ + close(ifpp->OsSock); + /* Neuen Socket merken */ + ifpp->OsSock = tmp_fd_OS; + } + else + { + Close(tmp_fd); + putmsg("ERROR: Changing UDP-Port failed, Port not changed !!!\r"); + return; + } +#endif /* OS_STACK */ + + Close(ifpp->ISock); /* Alten Socket schliessen. */ + ifpp->ISock = tmp_fd ; /* Neuen Socket merken */ + } + else + { /* Neuen TCP-Port liess sich nicht Initialisieren. */ + putmsg("ERROR: Changing UDP-Port failed, Port not changed !!!\r"); + return; + } + + + ifpp->tcpport = Htons((unsigned short)new_tcp_port); + + putmsg("TCP-Port successfully changed\r"); + return; + + case 'L': /* Sysop will LOGLevel aendern */ + if (!skipsp(&clicnt, &clipoi)) + { + mbp = putals("Telnet-Server:\r"); + putprintf(mbp, "My LogLevel: %d\r",ifpp->log); /* Loglevel anzeigen. */ + + prompt(mbp); + seteom(mbp); + return; + } + + newloglevel = nxtnum(&clicnt, &clipoi); /* neuen Loglevel ermitteln. */ + + if ( (newloglevel < 0) + ||(newloglevel > 3)) /* Pruefe neuen Loglevel. */ + { + mbp = putals("Telnet-Server:\r"); + putprintf(mbp, "Error: Log level worth from 0 to 3!\r"); + prompt(mbp); + seteom(mbp); + return; + } + + ifpp->log = newloglevel; /* Neuen Loglevel setzen und zeigen */ + mbp = putals("Telnet-Server:\r"); + putprintf(mbp, "My Loglevel: %d\r", ifpp->log); + + prompt(mbp); + seteom(mbp); + return; + break; + + + default: /* Ungueltiger Parameter. */ + putmsg("Invalid Parameter\r"); + return; + } + } + + mbp = putals("Telnet-Server:\r"); /* Aktuelle Einstellungen zeigen. */ + + putprintf(mbp, "My TCP-Port: %u\r", Ntohs(ifpp->tcpport)); + prompt(mbp); + seteom(mbp); +} + + /* Aktuelle Zeichen auswerten. */ +TRILLIAN GetContensTEL(char contens) +{ +#ifdef DEBUG_MODUS + lastfunc = "l1telnet(GetContensTEL)"; +#endif /* DEBUG_MODUS */ + + if (contens == CR) /* Zeichen ein Return. */ + tcppoi->cr = TRUE; /* Markiere, das es ein Return gibt. */ + + if (contens == LF) /* Zeichen ein LF-Return. LF-Return nicht setzen.*/ + return(NO); /* zum naechsten Zeichen. */ + + if (contens == (int)NULL) /* Alle Zeichen verarbeitet. */ + { + if (tcppoi->cr) /* Return war dabei. */ + { + tcppoi->cr = FALSE; /* Return zuruecksetzen. */ + return(YES); /* Frame ist komplett. */ + } + else + return(ERRORS); /* Return fehlt. */ + } + + if (!tcppoi->login) /* User ist noch nicht eingeloggt. */ + { + if (CheckContens(contens)) /* Login-Zeichen auf Gueltigkeit pruefen. */ + return(NO); /* Ungueltige Zeichen werden ignoriert. */ + } + + tcppoi->cmd[tcppoi->cmdlen++] = contens; /* Aktuelle Zeichen setzen. */ + return(NO); /* Zum naechsten Zeichen. */ +} + +#endif /* L1TELNET */ + +/* End of src/l1telnet.c */ diff --git a/src/l2dama.c b/src/l2dama.c new file mode 100755 index 0000000..87a2c30 --- /dev/null +++ b/src/l2dama.c @@ -0,0 +1,677 @@ +/************************************************************************/ +/* */ +/* ***** ***** */ +/* ***** ***** */ +/* ***** ***** */ +/* ***** ***** */ +/* *************** *************** */ +/* ***************** ***************** */ +/* *************** *************** */ +/* ***** ***** TheNetNode */ +/* ***** ***** Portable */ +/* ***** ***** Network */ +/* ***** ***** Software */ +/* */ +/* File src/l2dama.c (maintained by: DF6LN) */ +/* */ +/* This file is part of "TheNetNode" - Software Package */ +/* */ +/* Copyright (C) 1998 - 2008 NORD>damail); + lnkpoi->pollcnt = 0; /* Anzahl verbotener Polls des DAMA-Users */ + lnkpoi->priold = -1; /* Link-Prioritaets-Merker/Flag */ + lnkpoi->indx = 1; /* Index des Multiconnect */ + lnkpoi->zael = 1; /* Aktiver Multiconnect */ + lnkpoi->anzl = 0; /* Anzahl der Verbindungen bisher */ + clrDAMA(); + } +} + +/*----------------------------------------------------------------------*/ +/* Feststellen, ob auf einem der Ports des Dama-Kanals der Sender */ +/* getastet ist, oder ein User noch etwas antwortet. */ +/*----------------------------------------------------------------------*/ +#define NO_DAMA 2 +#define DAMA_DCD 1 +#define DAMA_NO_DCD 0 +static int +dama_dcd(int kanal) +{ + int port; + int state = NO_DAMA; + PORTINFO *pp; + + for (port = 0, pp = portpar; /* Alle DAMA-Ports pruefen.. */ + port < L2PNUM; + port++, pp++) + { + if (pp->dch != kanal) /* Port gehoert zum Dama-Kanal? */ + continue; + if (iscd(port)) /* nicht busy(), iscd() ! */ + return (DAMA_DCD); + state = DAMA_NO_DCD; + } + return (state); +} + +/*----------------------------------------------------------------------*/ +/* Wenn Info zu senden, gemaess Fenster passende Zahl an I-Frames in */ +/* die Dama-Sendeliste des aktiven Links (lnkpoi) haengen - das */ +/* passiert tatsaechlich in sdi / sdl2fr */ +/*----------------------------------------------------------------------*/ +static BOOLEAN +damatx(void) +{ + int n; + char VS; + + if (lnkpoi->tosend) /* was zu senden? */ + { + if (lnkpoi->flag & L2FREPEAT) /* soll wiederholt werden? */ + { + lnkpoi->flag &= ~L2FREPEAT; + if ((n = outsdI()) != 0) /* wieviel darf ich? */ + { + VS = lnkpoi->VS; /* V(S) merken */ + lnkpoi->VS = lnkpoi->lrxdNR; /* V(S) resetten */ + sdi(0, n); /* nur ausstehende I's senden */ + lnkpoi->VS = VS; /* V(S) zurueck */ + return (TRUE); + } + } + if ((n = itxwnd()) > 0) /* Fenster noch offen? */ + { + sdi(outsdI(), n); /* Frames generieren */ + lnkpoi->priold = lnkpoi->damapm; /* akt. Priori. merken */ + clrDAMA(); /* DAMA-Parameter clear */ + return (TRUE); + } + } + return (FALSE); /* wir haben nix gesendet */ +} + +/*----------------------------------------------------------------------*/ +/* Daten aus der Dama-Sendeliste des aktiven Links (lnkpoi) */ +/* tatsaechlich aussenden - diese Funktion wird nur aufgerufen, wenn */ +/* der Link auch senden darf */ +/*----------------------------------------------------------------------*/ +static void +xmit_damail(BOOLEAN *txflag, int k) +{ + MBHEAD *fbp; + + while ( (fbp = (MBHEAD *)lnkpoi->damail.head) + != (MBHEAD *)&lnkpoi->damail) + { /* sind noch Frames da ? */ + ulink((LEHEAD *)fbp); /* ja: */ + relink((LEHEAD *)fbp, + (LEHEAD *)txl2fl[lnkpoi->liport].tail); + kicktx(lnkpoi->liport); /* Frame markieren */ +#ifdef DAMASLAVE + if (txflag == NULL) + continue; +#endif + lnkpoi->flag |= L2FDAMA1 | L2FDAMA2 /* DAMA Flag Bit 1 & 2 setzen */ + | L2FDACK; /* Bestaetigungs-Flag setzen */ + *txflag = TRUE; /* was da, TX-Flag setzen ! */ + dama_timer[k] = dama_init; /* DAMA-Timer wieder setzen */ + } +} + +/*----------------------------------------------------------------------*/ +/* Daten aus der Dama-Random-Liste des angegebenen Ports tatsaechlich */ +/* aussenden. */ +/*----------------------------------------------------------------------*/ +static void +xmit_damarl(int port, BOOLEAN *txflag) +{ + MBHEAD *fbp; + + while ( (fbp = (MBHEAD *)damarl[port].head) + != (MBHEAD *)&damarl[port]) + { /* sind noch Frames da ? */ + ulink((LEHEAD *)fbp); /* ja: */ + relink((LEHEAD *)fbp, + (LEHEAD *)txl2fl[port].tail); + kicktx(port); /* Frame markieren */ +#ifdef DAMASLAVE + if (txflag != NULL) +#endif + *txflag = TRUE; /* was da, TX-Flag setzen ! */ + } +} + +/*-------------------------------------------------------------------------- + * + * DAMA-Timer abhaengige Funktionen ausfueheren + * + * Aufruf erfolgt von l2timr(). + * + * Funktion: + * dama_timer um ticks vermindern; wenn DAMA-Betrieb freigegeben und + * dama_timer abgelaufen, dann L2-Link-Tabelle nach DAMA-Uplink durch- + * suchen und, falls Info vorliegt I-Frames, sonst Poll senden. + * Anschliessend diesen Uplink als bearbeitet markieren. + * Dabei jeden User nur einmal pro Runde an die Reihe nehmen ! + * + *-------------------------------------------------------------------------*/ +void +timDAMA(UWORD ticks) +{ + WORD i; + BOOLEAN txflag; + WORD dsf; + LHEAD *llp; + WORD port; + int dcd, + k; + +#ifdef DAMASLAVE + for (llp = &l2actl[port = 0]; /* alle Ports durchgehen */ + port < L2PNUM; + port++, llp++) + { + if (damaslaveon(port)) /* DAMA-Slave aktiv? */ + { + if (--portpar[port].damaok == 0) /* Slave-Timeout abgelaufen? */ + portpar[port].sendok = 1; /* ja - Reste senden */ + if (portpar[port].sendok == 1) + { + xmit_damarl(port, NULL); + for (lnkpoi = (LNKBLK *)llp->head; + lnkpoi != (LNKBLK *)llp; + lnkpoi = lnkpoi->next) + { + damatx(); /* Info-Frames generieren */ + xmit_damail(NULL, -1); /* und gleich senden */ + } + portpar[port].sendok = 0; + } + } + } +#endif + + for (k = 0; k < DAMA_CH; k++) /* jeden Dama-Kanal einzeln */ + { /* bearbeiten */ + if ((dcd = dama_dcd(k)) == NO_DAMA) /* kein DAMA Port auf dem Kanal */ + continue; + + dcd &= 1; /* DCD extrahieren */ + + if (!dcd && (dama_timer[k] > 0)) /* Frequenz (DCD) frei und */ + { + if (dama_timer[k] <= ticks) /* DAMA-Timer abgelaufen? */ + dama_timer[k] = 0; + else /* DAMA-Zaehler runterzaehlen */ + dama_timer[k] -= ticks; + } + + if (dama_timer[k] == 0) /* DAMA-Timer abgelaufen? */ + { + if (!dcd) /* DAMA nur weiter, wenn */ + { /* letztes Frame gesendet wurde */ + txflag = FALSE; + for (port = 0; port < L2PNUM; port++) + { + if (portpar[port].dch == k) + xmit_damarl(port, &txflag); + if (txflag) + break; + } + } + + if (!dcd && !txflag) + { /* (Carrier detect) */ + for (i = 0, lnkpoi = lnktbl; + i < LINKNMBR; + ++i, ++lnkpoi) + { /* alle Links nacheinander */ + if (lnkpoi->state == L2SDSCED) + continue; + if (portpar[lnkpoi->liport].dch != k) + continue; + lnkpoi->flag &= ~L2FDAMA2; /* DAMA-Flag 2 loeschen */ + if ((lnkpoi->flag & L2FDAMA1) == 0)/* DAMA-Flag 1 geloescht? */ + { /* ja: war noch nicht dran */ + lnkpoi->flag |= L2FDAMA1; /* DAMA-Flag 1 setzen */ + /* als "dran" kennzeichnen */ + if (lnkpoi->zael == lnkpoi->indx)/* darf Link senden? */ + { + if (damatx() == FALSE) /* Neue I-Frames generieren */ + if ( lnkpoi->damapm == 0 /* Nur bei hoechster Priori. */ + && lnkpoi->damapc == 0)/* pG: 23.8.95 */ + if ((MBHEAD *)lnkpoi->damail.head + == (MBHEAD *)&lnkpoi->damail) + /* Warten auf Bestaetigung */ + { /* oder nix in der Liste ? */ + l2stma(stbl23); /* ja: dann gleich pollen */ + incDAMA(); /* und Prioritaet runter */ + if (lnkpoi->state != L2SHTH) + txflag = TRUE; /* Poll wird gesendet */ + } + xmit_damail(&txflag, k); + break; /* DAMA User gefunden, abbrechen */ + } /* Sende-Erlaubnis? */ + } /* DAMA-Flag 1 geloescht? */ + } /* alle Links */ + + if (i < LINKNMBR && !txflag) + { +/* + * Keine Info zum senden gefunden, also Poll senden ! + * ====> leere Polls ??? + */ +/* Zeit abgelaufen und Link an der Reihe? */ + if ( lnkpoi->damapc == 0 + && lnkpoi->zael == lnkpoi->indx) + { /* auch nur EIN Poll pro Runde */ + ++lnkpoi->tries; /* Tries erhoehen */ + +/* bei Wiederholungen wird Maxframe um 1 reduziert - wer nix empfaengt */ +/* landet irgendwann bei Maxframe 1 */ + if (lnkpoi->tries > 1) + change_maxframe(lnkpoi, -1); + + incDAMA(); /* Prioritaet runtersetzen */ + if (lnkpoi->tries < portpar[lnkpoi->liport].retry) + { + l2stma(stbl23); /* T1 expires (fuer Poll) */ + if (lnkpoi->state != L2SHTH) + txflag = TRUE; + } + else + { + lnkpoi->tries = 0; /* Tries abgelaufen! */ + l2stma(stbl25); /* N2 IS EXCEEDED */ + } + xmit_damail(&txflag, k); + } /* DAMA && Sende-Genehmigung */ + } /* lnkpoi != && !txflag */ + + if (i == LINKNMBR) + { +/* + * Keinen zu bearbeitenden DAMA-Link gefunden, oder schon + * alle DAMA-Links bearbeitet . Also ist die Runde zuende! + * DAMA-Flags loeschen und Prioritaetszaehler runterzaehlen. + * Leere Polls auf MC-Links durch IXFER ersetzen. + */ + +/* DAMA-Flags loeschen */ + for (llp = &l2actl[port = 0]; + port < L2PNUM; + port++, llp++) + { + if (portpar[port].dch != k) + continue; + if (dama(port)) + { + for (lnkpoi = (LNKBLK *)llp->head; + lnkpoi != (LNKBLK *)llp; + lnkpoi = lnkpoi->next) + { +/* DAMA-Flag Bit 1 & 2 loeschen */ + lnkpoi->flag &= ~(L2FDAMA1 + L2FDAMA2); +/* + * Naechsten MC-Link freigeben (zael erhoehen) DAMA-Speed-Faktor beachten. + */ + if ((dsf = (DamaSpeedFactor / 100) + / portpar[lnkpoi->liport].speed) + < 1) + dsf = 1; +/* Zaehler aktualisieren */ + if (lnkpoi->zael < lnkpoi->anzl * dsf) + lnkpoi->zael++; + else + lnkpoi->zael = 1; + } + } + } + +/* Nach jeder DAMA-Runde pruefen, ob eine zusaetzliche Pause eingefuegt */ +/* werden soll. Diese Zusatzpause gibt die Frequenz fuer neue Stationen */ +/* frei, auch wenn die DCD-Pausen sonst zu kurz sind. Nach solch einer */ +/* Zusatzpause wird allerdings (MIN_DELAY * 10ms) keine weitere Pause */ +/* eingefuegt. Die Pausenlaenge ist ueber Parameter "DAMA-Tout" */ +/* einstellbar. */ + if (pause_delay[k] == 0) + { + pause_delay[k] = MIN_DELAY + dama_init; + dama_timer[k] = dama_init; + } + + } + } /* Frequenz frei? */ + } /* DAMA-Timer abgelaufen? */ + +/* + * Bei jedem Aufruf von timDAMA() die DAMA-Prioritaet um ticks + * herunterzaehlen + */ + + for (llp = &l2actl[port = 0]; /* alle Ports durchgehen */ + port < L2PNUM; + port++, llp++) + { + if (portpar[port].dch != k) + continue; + if (dama(port)) /* nur wenns ein DAMA-Port ist */ + { + for (lnkpoi = (LNKBLK *)llp->head; + lnkpoi != (LNKBLK *)llp; + lnkpoi = lnkpoi->next) + { + if (lnkpoi->damapc >= ticks) + lnkpoi->damapc -= ticks; + else + lnkpoi->damapc = 0; + } + } + } + + if (pause_delay[k] > 0) /* Pausen-Verzoegerung aktiv? */ + { + if (pause_delay[k] <= ticks) /* Verzoegerung abgelaufen? */ + pause_delay[k] = 0; + else /* Verzoegerung runterzaehlen */ + pause_delay[k] -= ticks; + } + } +} + + +/*----------------------------------------------------------------------*/ +/* + * DAMA Aktivitaetszaehler und -merker auf 0 setzen + * (wenn User I-Frames gesendet hat) + */ +void +clrDAMA(void) +{ + lnkpoi->damapm = 0; + lnkpoi->damapc = 0; +} + +/*----------------------------------------------------------------------*/ +/* DAMA Aktivitaetsmerker inkrementieren */ +/* Reduzierung der Poll-Rate auf 1min. nach 10min. Inaktivitaet. */ +/*----------------------------------------------------------------------*/ +void +incDAMA(void) +{ + if (lnkpoi->damapm < dama_max) + ++lnkpoi->damapm; + + if ( lnkpoi->noatou > (ininat - 600) /* Keine Aktivitaet?? */ + || lnkpoi->tries > 1) /* Bei Retries schneller.. */ + lnkpoi->damapc = lnkpoi->damapm * 100; /* Prioritaet normal.. */ + else + lnkpoi->damapc = 6000; /* Prioritaet auf 1 Minute */ +} + +/*----------------------------------------------------------------------*/ +/* + * DAMA Timer loeschen + */ + +void +clearDT(UWORD time_val) +{ + int k; + + if ( dama(lnkpoi->liport) + && (lnkpoi->flag & (L2FDAMA1 + L2FDAMA2)) == (L2FDAMA1 + L2FDAMA2)) + { + lnkpoi->flag &= ~L2FDAMA2; + lnkpoi->tries = 0; + k = portpar[lnkpoi->liport].dch; + dama_timer[k] = time_val; + } +} + +/*----------------------------------------------------------------------*/ +/* POLL-Frames von Usern sind bei DAMA verboten und werden angemeckert. */ +/* Zunaechst wird eine Warnung verschickt, dann ein Disconnect. */ +/*----------------------------------------------------------------------*/ +void +polDAMA(void) +{ + MBHEAD *mbp; + MHEARD *mhp; + + if (lnkpoi->state != L2SDSCED) /* Wenn es ein aktiver Link ist.. */ + { + lnkpoi->pollcnt++; /* Neuen Verstoss mitzaehlen.. */ + if ((mhp = mh_lookup(&l2heard, lnkpoi->dstid)) != NULL) + mhp->damawarn++; + + if (MaxPollCnt) /* DAMA-Kontrolle eingeschaltet? */ + { +/*......................................................................*/ +/* Anzahl der maximal zugelassenen Verstoesse ueberschritten, es folgt */ +/* Fehlermeldung und Zwangsdisconnect!!! */ +/*......................................................................*/ + mbp = (MBHEAD *)allocb(ALLOC_MBHEAD); /* Buffer besorgen.. */ + mbp->l2link = lnkpoi; /* Linkpointer und */ + mbp->type = 2; +#ifdef SPEECH + putstr(speech_message(138), mbp); +#else + putstr("\r*** from DAMA-Master ", mbp); +#endif + putcal(myid, mbp); /* Digi-Call ausgeben */ + if (lnkpoi->pollcnt >= MaxPollCnt) + { + /* dealml((LEHEAD *)&lnkpoi->sendil); */ /* Sende-Liste loeschen */ + /* lnkpoi->tosend = 0; */ /* kein Frame zu senden */ + + /* Das loeschen der Sende-Liste ist nicht ganz ungefaehrlich, je */ + /* nach dem, in welchem State wir gerade sind, lieber den Schrott */ + /* senden und dann abwerfen, DB7KG */ + +#ifdef SPEECH + putprintf(mbp, speech_message(131), + lnkpoi->pollcnt); /* Verstoesse ausgeben */ +#else + putprintf(mbp, "> DISCONNECT: Too many non-DAMA Polls (%u) !!\r", + lnkpoi->pollcnt); /* Verstoesse ausgeben */ +#endif + seteom(mbp); + dsclnk(); /* Disconnect einleiten */ + } + else + { /* Vorwarnung! */ +#ifdef SPEECH + putprintf(mbp, speech_message(132), + lnkpoi->pollcnt, MaxPollCnt); +#else + putprintf(mbp, "> WARNING: non-DAMA Poll #%u," + " Disconnect after %u !!\r", + lnkpoi->pollcnt, MaxPollCnt); +#endif + seteom(mbp); + } + } + } +} + +/************************************************************************* + * + * "get Multi Connect Tabels" + * + * "getMCs" wird jedesmal aufgerufen, wenn ein neuer L2-Link dazukommt + * oder abgemeldet wird. (Connect/Disconnect) + * + * "getMCs" stellt DAMA Multi-Connects (MC's) fest und baut die Multi- + * Connect-Tabellen lnkpoi->indz und lnkpoi->anzl auf und korrigiert + * lnkpoi->zael bei Link-Aenderungen auf plausible Werte. + * + * lnkpoi->indz repraesentiert die Indizes einer MC-Station. + * lnkpoi->anzl repraesentiert die Anzahl der MC's einer Station. + * + * lnkpoi->zael wird dann nach jeder Runde erhoeht bzw. zurueckgesetzt. + * Bei Gleichheit von indz und zael erhaelt dieser Link spaeter die + * "Sende-Erlaubnis" ! + * + * getMCs wird nur aufgerufen, wenn wirklich noetig + * (in src/l2stma.c in l2newstate). getMCs arbeitet LINEAR. + * + ************************************************************************/ +void +getMCs(void) +{ + WORD multi, + indx, + port, + k; + LHEAD *llp; + LNKBLK *lp; + char *id; + + lnkpoi->zael = 1; /* Zaehler immer zurueck */ + + id = lnkpoi->dstid; /* geht etwas schneller */ + k = portpar[lnkpoi->liport].dch; + + multi = 0; + for (llp = &l2actl[port = 0]; /* alle Ports durchgehen */ + port < L2PNUM; + port++, llp++) + { + if (portpar[port].dch != k) /* nur fuer diesen Dama-Kanal! */ + continue; + if (dama(port)) /* nur wenns ein DAMA-Port ist */ + for (lp = (LNKBLK *)llp->head; + lp != (LNKBLK *)llp; + lp = lp->next) + if (cmpcal(lp->dstid, id)) + multi++; + } + + if ( (!dama(lnkpoi->liport)) /* kein DAMA-Link? */ + || (!multi)) /* oder letzter MultiConnect */ + { + lnkpoi->indx = 1; /* Index zuruecksetzen! */ + lnkpoi->anzl = 0; /* Anzahl der Verbindungen! */ + return; + } + +/* + * Hinweis zum Ablauf: + * Die Linkliste wird durchlaufen und fuer jeden Multiconnect-Link + * die Anzahl der aktiven Multiconnects (->anzl) und ein Index gesetzt. + * Der aktuelle Link (lnkpoi) wird hier auch gefunden und behandelt, + * sofern dies noetig ist (L2MCONN). + */ + + indx = 0; + for (llp = &l2actl[port = 0]; /* alle Ports durchgehen */ + port < L2PNUM; + port++, llp++) + { + if (portpar[port].dch != k) /* nur fuer diesen Dama-Kanal! */ + continue; + if (dama(port)) /* nur wenns ein DAMA-Port ist */ + for (lp = (LNKBLK *)llp->head; + lp != (LNKBLK *)llp; + lp = lp->next) + if (cmpcal(lp->dstid, id)) /* gleiches Call ? */ + { + lp->indx = ++indx; /* Index setzen */ + lp->anzl = multi; /* Anzahl der Connects */ + } + } +} + +/************************************************************************\ +* * +* "already connected" * +* * +* Hat dieses Rufzeichen auf diesem Port schon einmal connected? * +* * +\************************************************************************/ +BOOLEAN +multiconn(int port, char *id) +{ + LHEAD *llp; + LNKBLK *lp; + + llp = &l2actl[port]; + for (lp = (LNKBLK *)llp->head; + lp != (LNKBLK *)llp; /* alle Links des Ports pruefen */ + lp = lp->next) + if (cmpcal(lp->realid, id)) + return (TRUE); + return (FALSE); +} + +/* End of src/l2dama.c */ diff --git a/src/l2misc.c b/src/l2misc.c new file mode 100755 index 0000000..03de01f --- /dev/null +++ b/src/l2misc.c @@ -0,0 +1,950 @@ +/************************************************************************/ +/* */ +/* ***** ***** */ +/* ***** ***** */ +/* ***** ***** */ +/* ***** ***** */ +/* *************** *************** */ +/* ***************** ***************** */ +/* *************** *************** */ +/* ***** ***** TheNetNode */ +/* ***** ***** Portable */ +/* ***** ***** Network */ +/* ***** ***** Software */ +/* */ +/* File src/l2misc.c (maintained by: DF6LN) */ +/* */ +/* This file is part of "TheNetNode" - Software Package */ +/* */ +/* Copyright (C) 1998 - 2008 NORD>) -> l2tol3(), l2tol7(,lnkpoi,2) */ +/* */ +/* mitgeteilt. */ +/* */ +/* Ein Connectwunsch wird dem Level 2 ueber das Besetzen eines leeren */ +/* Linkblocks mit Quell- und Ziel- sowie Digicalls und Aufrufen von */ +/* newlnk() mitgeteilt (lnkpoi zeigt auf Linkblock !). */ +/* Ein newlnk() auf einen bestehenden Link erzeugt einen Link Reset. */ +/* */ +/* Ein Disconnectwunsch (oder bei mehrmaligem Aufruf der sofortige */ +/* Disconnect) wird ueber das Setzen von lnkpoi auf den jeweiligen */ +/* Linkblock und Aufruf von dsclnk() erreicht. */ +/* */ +/* Der Informationstransfer zum Level 2 geschieht von aussen durch */ +/* Aufruf von itolnk(...), vom Level 2 durch itolx(..), welches dann */ +/* fmlink() aus dem hoeheren Level aufruft. */ +/* */ +/* Ueber sdui(..) koennen unproto-Pakete (UI-Frames) gesendet werden. */ +/* */ +/* Level-3-Pakete (Level-3-UI-Pakete oder Infopakete in Sequenz eines */ +/* Level-2-3-Links) werden ausgefiltert und in die Level-3-Frameliste */ +/* eingehaengt. */ +/* */ +/*----------------------------------------------------------------------*/ + +/* Die Reihenfolge der Bearbeitung ist hier entscheidend. Zuerst werden */ +/* die empfangenen Frames verarbeitet, dann werden I-Frames erzeugt und */ +/* erst dann wird ueber T1/T2 entschieden. */ + +void +l2(void) +{ + clrstfl(); + l2rx(); + l2tx(); + l2timr(); + l2rest(); +} + +/*----------------------------------------------------------------------*/ +void +l2init(void) +{ + WORD i; + + inithd(&rxfl); + inithd(&stfl); + inithd(&trfl); + inithd(&freel); + inithd(&l2frel); + + init_buffers(); + + for (i = 0; i < L2PNUM; ++i) + { + inithd(&txl2fl[i]); + inithd(&l2actl[i]); + } + + for (i = 0, lnkpoi = lnktbl; i < LINKNMBR; ++i, ++lnkpoi) + { + lnkpoi->state = L2SDSCED; + lnkpoi->rcvd = lnkpoi->tosend = 0; + lnkpoi->tmbp = NULL; + lnkpoi->zael = 1; /* MultiConnect */ + inithd(&lnkpoi->rcvdil); + inithd(&lnkpoi->sendil); + inilbl(); + reslnk(); + relink((LEHEAD *)lnkpoi, (LEHEAD *)l2frel.tail); + } + + iniDAMA(); + for (i = 0; i < L2CALEN; i++) + l2als[i] = toupper(alias[i]); +} + +void +autopar(int port) +{ + PORTINFO *p = portpar + port; + UWORD baud; /* Baudrate/100 auf dem Port */ + UWORD P; /* Persistance */ + UWORD W; /* Slottime */ + UWORD IRTT; /* Initial RTT */ + UWORD T2; /* Timer2 */ + UWORD N2; /* Retry */ + BOOLEAN l1update; + +/* T2 wird berechnet als die Laenge der Aussendung eines Frames bei */ +/* der eingestellten Baudrate + 10%. */ + baud = p->speed; + + T2 = 1; /* sehr schneller Link */ + if ((baud != 0) && (baud < 2888)) + T2 = 2888 / baud; /* sonst adaptiv nach Baudrate */ + + if (dama(port)) + T2 <<= 1; /* *2 bei DAMA nach DG3AAH */ + +/* Der IRTT wird auf T2*2 festgelegt, dies sollte immer + * ausreichen, damit eine Antwort kommt. Es wird noch der TXDELAY + * dazugerechnet, in der Annahme die Gegenstation habe etwa einen + * gleich schnellen Transceiver. + */ + IRTT = (T2 + p->txdelay) * 2; + IRTT = max(10, IRTT); + +/* Der Retry ist DEF_N2 bei DUPLEX/CSMA und DEF_N2/2 bei DAMA. */ + N2 = DEF_N2; + if (dama(port)) + N2 /= 2; + +/* P-PERSISTENCE + * Bei DAMA und VOLLDUPLEX wird P immer auf 255 gesetzt. + * Bei einem normalen Einstieg ohne DAMA oder Halb-Duplex + * verwenden wir defaultmaessig P=160 + */ + P = 255; + +/* Persistence und Slottime bei Linkports anders setzen */ + if (!fullduplex(port)) + { + if (islinkport(port)) + P = 200; + else if (!dama(port)) + P = 160; /* Idee DB2OS und DG9FU */ + } + +/* Als Slottime wird der aktuelle TX-Delay Wert genommen. */ + W = p->txdelay; + if (W == 0) + W++; + + l1update = (P != p->persistance) + || (W != p->slottime); + +#ifdef EXPERTPARAMETER + /* Neue Werte nur bei Autoparameter setzen */ + if (p->l2autoparam & MODE_apers) p->persistance = P; + if (p->l2autoparam & MODE_aslot) p->slottime = W; + if (p->l2autoparam & MODE_aIRTT) p->IRTT = IRTT; + if (p->l2autoparam & MODE_aT2) p->T2 = T2; + if (p->l2autoparam & MODE_aretry) p->retry = N2; +#else + p->persistance = P; /* Parameter neu setzen */ + p->slottime = W; + p->IRTT = IRTT; + p->T2 = T2; + p->retry = N2; +#endif + + if (l1update) /* neue L1-Parameter setzen */ + l1ctl(L1CCMD, port); +} + +void +autopers(int port) +{ +#ifdef DAMASLAVE + PORTINFO *p = portpar + port; + + if (damaslaveon(port)) /* wenn DAMA erkannt, dann */ + { + p->persistance = 255; /* sofort antworten */ + p->slottime = 0; /* keine Wartezeit */ + l1ctl(L1CCMD, port); /* Aenderungen zum TNC bringen */ + } +#endif + +#if 0 /* DB2OS will es so ... */ + PORTINFO *p = portpar + port; + UWORD P; /* Persistance */ + BOOLEAN l1update; + +/* Persistance wird berechnet als 255-(Anzahl der User)*10. Bei */ +/* Vollduplex und DAMA wird die Persistance immer auf 255 gesetzt. */ + P = 255; + if ((p->nmbstn > 0) && !fullduplex(port) && !dama(port)) + if (p->nmbstn <= 15) + P = 255 - (p->nmbstn * 10); + else + P = 100; + + l1update = (P != p->persistance); + + p->persistance = P; /* Parameter neu setzen */ + + if (l1update) /* neue L1-Parameter setzen */ + l1ctl(L1CCMD, port); +#endif +} + +#ifdef PORT_SYNRONATION +static int check_syn_port(int port) +{ + int i = 0; + int found = 0; + + /* alle Ports pruefen. */ + for(i = 0; i < L2PNUM; i++) + { + /* Ist Port aktiv? */ + if (!portenabled(i)) + /* Port ist ausgeschaltet, */ + /* zum naechsten Port. */ + continue; + + /* Den eignen Port nicht pruefen*/ + if (port == i) + continue; + + if (port_synronation_enabled(i)) + { + /* Port mit Synronation gefunden. */ + /* Pruefe den Port auf DCD/PTT. */ + found = iscd(i); + continue; + } + } + return(found); +} +#endif + +/* Ist ein Port gerade aktiv ? (Blockierung des Senders und der Timer */ +BOOLEAN +busy(int port) +{ + if (fullduplex(port)) + return ((iscd(port) & (RXBFLAG | TXBFLAG)) != 0); + else +#ifndef PORT_SYNRONATION + return ((iscd(port) & (DCDFLAG | PTTFLAG | RXBFLAG | TXBFLAG)) != 0); +#else + if (port_synronation_enabled(port)) + { + if (check_syn_port(port) || (iscd(port) & (DCDFLAG | PTTFLAG | RXBFLAG | TXBFLAG))) + return(TRUE); + else + return(FALSE); + } + return ((iscd(port) & (DCDFLAG | PTTFLAG | RXBFLAG | TXBFLAG)) != 0); +#endif +} + +/************************************************************************\ +* * +* "level 2 rest" * +* * +* Muellbufferliste frei machen (aus Interruptroutinen entstandener * +* Muell, der besser ausserhalb der Interrupts deallokiert wird aus * +* Zeitgruenden). * +* * +\************************************************************************/ +static void +l2rest(void) +{ + dealml((LEHEAD *)&trfl); /* Muellbufferliste frei machen */ +} + +#ifdef L2PROFILER +void +l2profiler(void) +{ + MBHEAD *mbp; + + if (dmagic == MAGIC_L2PROFILE) + { /* im Level 2 ordentlich Krach */ + while ( lnkpoi->tosend < 10 /* machen */ + && !(lnkpoi->flag & (L2FDSLE | L2FDIMM))) + { + mbp = (MBHEAD *)allocb(ALLOC_MBHEAD); + while (mbp->mbpc < 256) + putchr(' ', mbp); + rwndmb(mbp); + i3tolnk(0x12, lnkpoi, mbp); + } + } +} +#endif + +#ifndef MC68K +/************************************************************************/ +/* */ +/* "is to me" */ +/* */ +/* Ist das uebergebene Rufzeichen unser myid oder alias? Der Alias kann */ +/* mit beliebiger SSID connected werden. */ +/* */ +/************************************************************************/ +BOOLEAN +istome(const char *id) +{ + return ( cmpid(myid, id) /* Stimmt Rufzeichen? */ + || cmpcal(l2als, id)); /* oder ALIAS? */ +} +#endif + +/************************************************************************/ +/* */ +/* "is to me or via me?" */ +/* */ +/* Pruefen, ob wir als naechster an der Reihe sind mit Digipeaten. Dazu */ +/* schauen wir uns das erste Call an, das kein gesetztes Hbit hat, dass */ +/* muessen wir selber sein oder wir schmeissen das Frame weg, */ +/* andernfalls duerfen wir das Frame auswerten. */ +/* */ +/* Rueckgabewerte : 0 = nicht via uns und auch nicht fuer uns */ +/* 1 = gedigipeated/kein via, und Verbindung an uns */ +/* 2 = Verbindung via, aber NICHT an uns */ +/* TEST DG9OBU 3 = Verbindung an unseren SSID-Bereich/Local */ +/* 4 = AX.25-ARP an uns */ +/************************************************************************/ +int +istomev(void) +{ + char *viap = rxfhdr + L2ILEN; /* Zeiger auf erstes Via */ + char *savedviap = viap; /* Zur Sicherheit irgendwo hin zeigen lassen */ + + int iViaNum = -1; + int iViaNumMax = 0; + + while (*viap) + { + ++iViaNumMax; + if (!(viap[L2IDLEN - 1] & L2CH)) + { + if (iViaNum == -1) + { + savedviap = viap; + iViaNum = iViaNumMax; + } + } + viap += L2IDLEN; + } + + if ((iViaNumMax > 0) && (iViaNum > -1)) + { + if (iViaNum < iViaNumMax) + { + /* Wir sind nicht das letzte Via in der Liste */ + return (istome(savedviap) ? 2 : 0); /* Verbindung via uns? */ + } + else + { + /* Wir sind das letzte Via in der Liste */ + if (istome(savedviap)) + { + return((cmpid(rxfhdr, "QST \140")) ? 5 : 2); + } + else + { + return(0); + } + } + } + +/* Hier angekommen haben entweder alle schon gedigipeated oder es gibt */ +/* keine VIAs, auf jeden Fall duerfen wir den Link nehmen, wenn er */ +/* direkt an uns (MyCall ODER Node-Alias) gerichtet ist. */ + if (istome(rxfhdr)) + return 1; + +/* TEST DG9OBU */ +/* Verbindung nicht direkt an mich, sondern in meinen SSID-Bereich */ + if ( (cmpcal(rxfhdr, myid)) /* hat mein Call, SSID egal */ + && (SSIDinrange(SSID(rxfhdr))) /* liegt in meinem SSID-Bereich */ + ) + return 3; + +#ifdef PROXYFUNC + if (isproxy(rxfhdr)) + return 2; +#endif + +#ifdef IPROUTE + /* AX.25-ARP fuer mich ? */ + /* (bzw. an QST und alle in der VIA-Liste haben schon gedigipeated */ + /* oder keine VIA-Liste vorhanden) */ + if (cmpid(rxfhdr, "QST \140")) + return 4; +#endif + + /* Verbindung ist nicht fuer uns */ + return 0; +} + +/************************************************************************\ +* * +* "new link" * +* * +* Link (lnkpoi) neu aufbauen. * +* * +\************************************************************************/ +void +newlnk(void) +{ + reslnk(); /* Sequenzvars/Timer ruecksetzen */ + setiSRTT(); /* RTT-Timer neu starten */ + l2stma(stbl19); /* LOCAL START COMMAND */ +} + +/************************************************************************\ +* * +* "disconnect link" * +* * +* Disconnect-Wunsch an aktuellen Link (lnkpoi) : * +* * +* Linkstatus "Disconnected" * +* -> Ax.25-Parameter "frisch" * +* * +* Linkstatus "Link Setup" oder "Disconnect Request" * +* -> Link NICHT aufloesen, nur Flag vormerken fuer l2rest * +* * +* sonst * +* -> Empfangsinfoframeliste loeschen, Linkstatus bleibt, Flag "nach * +* Loswerden aller zu sendenden Infoframes disconnecten" setzen * +* * +\************************************************************************/ +void +dsclnk(void) +{ + WORD lstate; + + if ((lstate = lnkpoi->state) == L2SDSCED) /* Disced, nur */ + inilbl(); /* AX-Pars neu */ + else + { + dealml((LEHEAD *)&lnkpoi->rcvdil); /* RX-Infoframe- */ + lnkpoi->rcvd = 0; /* loeschen und */ + + if ( lstate == L2SLKSUP /* Linksetup oder */ + || lstate == L2SDSCRQ /* Discreq, */ + || lstate == L2SHTH /* oder wartet */ + || (lnkpoi->flag & L2FDSLE)) + lnkpoi->flag |= L2FDIMM; /* sofort weg */ + else + lnkpoi->flag |= L2FDSLE; /* wenn alles raus */ + } +} + +/************************************************************************\ +* * +* "initialize link" * +* * +* Aktuellen Linkblock (lnkpoi) initialisieren. Sequenzvariablen und * +* Timer initialisieren, Quellcall/Zielcall/via-Liste/ Port setzen aus * +* der txf...-Liste. * +* * +\************************************************************************/ +void +inilnk(void) +{ + reslnk(); /* Sequenzvars/Timer init. */ + cpyid(lnkpoi->srcid, txfhdr + L2IDLEN); /* Quellcall */ + cpyid(lnkpoi->dstid, txfhdr); /* Zielcall */ + cpyidl(lnkpoi->viaidl, txfhdr + L2ILEN); /* via-Liste */ + lnkpoi->liport = txfprt; /* Port */ + setiSRTT(); /* RTT */ + lnkpoi->pollcnt = 0; /* Anzahl verbotener Polls */ + /* des DAMA-Users */ + lnkpoi->noatou = ininat; /* Timeout initialisieren */ +#ifdef EAX25 + if (lnkpoi->bitmask == 0x7F) +#ifdef __WIN32__ + lnkpoi->maxframe = (unsigned char)portpar[lnkpoi->liport].maxframe_eax; +#else + lnkpoi->maxframe = portpar[lnkpoi->liport].maxframe_eax; +#endif /* WIN32 */ + else +#endif +#ifdef __WIN32__ + lnkpoi->maxframe = (unsigned char)portpar[lnkpoi->liport].maxframe; +#else + lnkpoi->maxframe = portpar[lnkpoi->liport].maxframe; +#endif /* WIN32 */ +} + +/************************************************************************\ +* * +* "clear link" * +* * +* Aktuellen Link (lnkpoi) aufloesen. Alle Sequenzvariablen und Timer * +* zuruecksetzen, Sende- und Empfangsinfoframelise loeschen, Linkblock * +* neu mit AX.25-Parametern besetzen. * +* * +\************************************************************************/ +void +clrlnk(void) +{ + reslnk(); /* Sequenzvars/Timer ruecksetzen */ + dealml((LEHEAD *)&lnkpoi->rcvdil); /* Empfangsinfoliste loeschen */ + dealml((LEHEAD *)&lnkpoi->sendil); /* Sendeinfoliste loeschen */ + dealml((LEHEAD *)&lnkpoi->damail); /* DAMA-Puffer loeschen */ + lnkpoi->rcvd = lnkpoi->tosend = 0; /* entsprechende Zaehler loeschen */ + if (lnkpoi->tmbp != NULL) /* RX-Fragmente auch */ + { + dealmb(lnkpoi->tmbp); + lnkpoi->tmbp = NULL; + } + inilbl(); /* Linkblock "frisch" */ +} + +/************************************************************************\ +* * +* "reset link" * +* * +* Aktuellen Link (lnkpoi) zuruecksetzen. Alle Sequenzvariablen und Timer * +* initialisieren. * +* * +\************************************************************************/ +void +reslnk(void) +{ +#ifdef __WIN32__ + lnkpoi->VS = 0; + lnkpoi->VR = 0; + lnkpoi->ltxdNR = 0; + lnkpoi->lrxdNR = 0; + lnkpoi->RTT = 0; +#else + lnkpoi->VS = + lnkpoi->VR = + lnkpoi->ltxdNR = + lnkpoi->lrxdNR = + lnkpoi->RTT = +#endif /* WIN32 */ + lnkpoi->flag = 0; + lnkpoi->noatou = ininat; + resptc(g_uid(lnkpoi, L2_USER)); + clrDAMA(); + lnkpoi->SRTT = portpar[lnkpoi->liport].IRTT; + clrT1(); + clrT2(); +} + +/************************************************************************\ +* * +* "initialize link block" * +* * +* Aktuellen Linkblock (lnkpoi) initialisieren. * +* * +\************************************************************************/ +static void +inilbl(void) +{ + lnkpoi->liport = 0; + lnkpoi->bitmask = 0x07; + clrDAMA(); +} + +/************************************************************************\ +* * +* "acknowledge link" * +* * +* Diese Funktion wird vom L7 aufgerufen, um eine eingehende HTH- * +* Verbindung zu bestaetigen. Es wird lediglich ein Flag gesetzt, in * +* l2rest wird dann die eigentliche Reaktion ausgeloest. * +* * +\************************************************************************/ +void +acklnk(LNKBLK *lp) +{ + if (lp->state == L2SHTH) + lp->flag |= L2FACKHTH; +} + +/************************************************************************\ +* * +* "reject link" * +* * +* Diese Funktion wird vom L7 aufgerufen, um eine eingehende HTH- * +* Verbindung abzulehnen (Partner ist Busy). * +* * +\************************************************************************/ +void +rejlnk(LNKBLK *lp) +{ + if (lp->state == L2SHTH) + lp->flag |= L2FREJHTH; +} + +/************************************************************************\ +* * +* "get link" * +* * +* Einen Link anhand port, srcid, dstid und vial suchen und liefern. Wenn * +* wir noch keinen Link haben, dann einen neuen (leeren) liefern. * +* * +\************************************************************************/ +LNKBLK * +getlnk(UBYTE liport, char *srcid, char *dstid, char *viaidl) +{ + LHEAD *llp; + LNKBLK *lp; + char *p; + + if (!portenabled(liport)) + return(NULL); + + llp = &l2actl[liport]; /* auf dem entsprechenden Port */ + + for (lp = (LNKBLK *)llp->tail; + lp != (LNKBLK *)llp; /* alle Links des Ports pruefen */ + lp = lp->prev) + { + if (cmpid(lp->srcid, srcid)) + if (cmpid(lp->dstid, dstid) + && cmpidl(lp->viaidl, viaidl)) + { + ulink((LEHEAD *)lp); + relink((LEHEAD *)lp, (LEHEAD *)llp->tail); + return (lp); /* wir haben einen Link gefunden */ + } + } + + if ((LHEAD *)l2frel.head == &l2frel) + return (NULL); /* wir haben keinen freien Link */ + + if ( (fvalca(dstid) != YES) + || (nmbfre < 78)) /* falsches Call oder kein Speicher? */ + return (NULL); + + lp = (LNKBLK *)l2frel.head; + cpyid(lp->srcid, srcid); /* Werte setzen */ + cpyid(lp->dstid, dstid); + cpyidl(lp->viaidl, viaidl); + + lp->liport = liport; +/* In den Linkblock wird ein Zeiger auf das Rufzeichen abgelegt, das in */ +/* Wirklichkeit der Ansprechpartner dieses Linkes ist. Es ist das Erste */ +/* Rufzeichen im via-Feld ohne H-Bit oder das Ziel-Rufzeichen selbst. */ + for (p = lp->viaidl; *p; p += L2IDLEN) + if ((p[L2IDLEN - 1] & L2CH) == 0) + break; + lp->realid = *p ? p : lp->dstid; + return (lp); /* leeren Block liefern */ +} + +/************************************************************************/ +/* */ +/* Maxframe-Automatik: Fuer den angegebenen Link wird Maxframe um den */ +/* Wert dif geaendert. Dabei wird der Bereich 1 .. Port-Maxframe */ +/* eingehalten. Zum Vergroessern des Link-Maxframe muss zweimal in */ +/* Folge alles bestaetigt sein. */ +/* */ +/************************************************************************/ +void +change_maxframe(LNKBLK *link, int dif) +{ +#if MAX_TRACE_LEVEL > 4 + char notify_call1[10]; + char notify_call2[10]; +#endif + int old = link->maxframe; + int new_max; + int port_max; + +#ifdef EAX25 + /* Fuer EAX.25-Links ein anderes Maxframe verwenden */ + if (link->bitmask == 0x7F) + port_max = portpar[link->liport].maxframe_eax; + else +#endif + port_max = portpar[link->liport].maxframe; + + if (!automaxframe(link->liport)) + { + link->maxframe = port_max; + return; + } + + if (dif > 0) /* soll vergroessert werden? */ + { + if (old == port_max) /* schon Maximalwert, den Rest */ + return; /* kann man sich sparen */ + + if (link->flag & L2FCMDEL) /* 2. Durchgang in Folge? */ + link->flag &= ~L2FCMDEL; + else + { + link->flag |= L2FCMDEL; /* 1. Durchgang - nix aendern */ + dif = 0; + } + } + else + link->flag &= ~L2FCMDEL; + + new_max = old + dif; + if (new_max < 1) + new_max = 1; + if (new_max > port_max) + new_max = port_max; + + if ((new_max != old) | (link->flag & L2FCMDEL)) + { + link->maxframe = new_max; +#if MAX_TRACE_LEVEL > 4 + call2str(notify_call1, link->srcid); + call2str(notify_call2, link->dstid); + notify(5, "Max %s - %s %d->%d", + notify_call1, notify_call2, old, new_max); +#endif + } +} + +/************************************************************************/ +/* */ +/* UI-Frames von einem Port auf einen anderen Port durchreichen. Diese */ +/* Funktion ist vorgesehen, um z.B. Mail-Beacons von Mailboxes zu */ +/* ermoeglichen. Als Digipeater-Call ist der TNN-Alias zu verwenden mit */ +/* der Nummer des gewuenschten Sende-Ports als SSID. Fuer die Ueber- */ +/* tragung muessen folgende Voraussetzungen erfuellt sein: */ +/* */ +/* - nur PID 0xF0 wird akzeptiert */ +/* - der Sende-Port darf nicht der Empfangsport sein */ +/* */ +/* Um fuer F6FBB-Mailboxes eine Antwort-Funktion zu ermoeglichen, wird */ +/* der SSID des Digipeater-Calls bei der Aussendung auf den Empfangs- */ +/* port gesetzt. */ +/* */ +/************************************************************************/ + +void +gateway_ui(char *fmid, char *toid, char *rxvia, MBHEAD *info) +{ + int port; + char *vp; + char to[L2IDLEN]; + + DEST dst; + + BOOLEAN bCanDigipeat = FALSE; + BOOLEAN bSuppressHBit = FALSE; + + /* Gesamte via-Liste durchgehen */ + for (vp = rxvia; *vp != '\0'; vp += L2IDLEN) + { + /* Hat dieser via-Digi schon gedigipeated ? Ja, dann zum naechsten */ + if (vp[L2IDLEN-1] & L2CH) + continue; + + /* Mailbake fuer Mailbox-Systeme, ermoeglicht die Aussendung des */ + /* UI-Frames gezielt auf einem anderen Port */ + /* Unser *Alias* und PID F0 ? */ +#ifndef UIDIGIMOD + if ((cmpcal(vp, l2als)) && (info->l2fflg == L2CPID)) +#else + if (cmpcal(vp, myid)) +#endif /* UIDIGIMOD */ + { + /* Port holen, auf dem ausgesendet werden soll */ + port = SSID(vp); + /* Pruefen, ob Einschraenkungen erfuellt */ +#ifndef UIDIGIMOD + if ((port < L2PNUM) && portenabled(port) && (port != rxfprt)) +#else + if ((port < L2PNUM) && portenabled(port)) +#endif /* UIDIGIMOD */ + { + /* Via umbauen (Empfangsport und digipeated-Flag eintragen) */ + vp[L2IDLEN-1] = (vp[L2IDLEN-1] & ~0x1E) | (rxfprt << 1) | L2CH; +#ifdef __WIN32__ + sdui(rxvia, toid, fmid, (char)port, info); /* UI-Frame senden */ +#else + sdui(rxvia, toid, fmid, port, info); /* UI-Frame senden */ +#endif /* WIN32 */ + /* Frame loeschen */ + dealmb(info); + return; + } + } + + /* UI-Digipeating fuer andere L2-Frames jeglicher PID. Das gewuenschte */ + /* Ziel muss uns bekannt UND per L2 erreichbar sein, NETROM-Ziele koennen */ + /* per UI (noch) nicht erreicht werden, da schicken wir das UI-Frame im */ + /* L2 weiter. */ + + /* Sind wir der naechste Digi in der Via-Liste ? */ + if (cmpid(vp, myid)) + { + char *tp = vp + L2IDLEN; /* naechster Hop in der Liste (oder NUL) */ + + /* Noch ein Digi nach uns in der via Liste ? */ + if (*tp != '\0') + { + /* Ja, dann feststellen, ob wir den kennen und wo wir lang muessen. */ + /* Es darf sich nur um ein Flexnet- oder lokales L2-Ziel handeln, */ + /* via-Pfade mit Calls auf Userports werden ignoriert. */ + + /* Flexnet- oder lokales, erreichbares L2-Ziel ? */ + if (l3_find_route(tp, &dst) == NODE_AVAILABLE) + { + /* FlexNet, LOCAL und LOCAL_M */ +/* ++ if ( (dst.typ == FLEXNET) ++ || (islocal(tp) == YES) + ) ++*/ + bCanDigipeat = TRUE; + } + } + else + { + /* Keiner mehr nach uns in der Liste, dann schauen, ob wir das Ziel in der */ + /* MHeard-Liste kennen oder es ein lokaler Link von uns ist */ + cpyid(to, toid); /* wir brauchen nur das erste Call */ + + /* Lokaler User (MHeard) ? */ + if (isheard(to, &dst) == TRUE) + bCanDigipeat = TRUE; + else + { + /* Lokal angeschlossener Knoten ? */ + /* Ein erreichbarer Local oder Local ohne Messung */ + if (islocal(to) == YES) + { + /* Es ist ein erreichbarer Local, jetzt noch den Port holen */ + if (l3_find_route(to, &dst) == NODE_AVAILABLE) + bCanDigipeat = TRUE; + } + } + } + } + else /* Wir sind eigentlich nicht dran, kennen aber einen Weg zum naechsten */ + { /* Digi in der Liste ? Das machen wir aber nur fuer RX auf Linkports ! */ + if ( (l3_find_route(vp, &dst) == NODE_AVAILABLE) + && (islinkport(rxfprt)) + ) + { + /* FlexNet, LOCAL und LOCAL_M */ +/* + if ( (dst.typ == FLEXNET) + || (islocal(vp) == YES) + ) + { +*/ + bCanDigipeat = TRUE; + bSuppressHBit = TRUE; /* H-Bit nicht veraendern */ +/* + } +*/ + } + } + + /* Frame digipeaten ? Zielport ok ? */ + if ( (bCanDigipeat == TRUE) + && (portenabled(dst.port)) + && (dst.port >= 0) + && (dst.port < L2PNUM) + ) + { + /* Wenn wir nicht mit in den Vias waren, dann HBit nicht anfassen */ + if (bSuppressHBit == FALSE) + /* Wir haben gedigipeated */ + vp[L2IDLEN - 1] |= L2CH; + +#ifdef __WIN32__ + sdui(rxvia, toid, fmid, (char)dst.port, info); /* UI-Frame senden */ +#else + sdui(rxvia, toid, fmid, dst.port, info); /* UI-Frame senden */ +#endif /* WIN32 */ + /* Frame loeschen */ + dealmb(info); + return; + } + + /* Via-Bearbeitung beendet */ + break; + } + + /* Frame loeschen */ + dealmb(info); + return; +} + +/* End of src/l2misc.c */ diff --git a/src/l2rx.c b/src/l2rx.c new file mode 100755 index 0000000..c6ce49a --- /dev/null +++ b/src/l2rx.c @@ -0,0 +1,1050 @@ +/************************************************************************/ +/* */ +/* ***** ***** */ +/* ***** ***** */ +/* ***** ***** */ +/* ***** ***** */ +/* *************** *************** */ +/* ***************** ***************** */ +/* *************** *************** */ +/* ***** ***** TheNetNode */ +/* ***** ***** Portable */ +/* ***** ***** Network */ +/* ***** ***** Software */ +/* */ +/* File src/l2rx.c (maintained by: DF6LN) */ +/* */ +/* This file is part of "TheNetNode" - Software Package */ +/* */ +/* Copyright (C) 1998 - 2008 NORD>flag & L2FBUSY) && (lnkpoi->busyrx >= (lnkpoi->bitmask == 0x7F) ? 16 : 7)) +#else +#define LINKBUSY ((lnkpoi->flag & L2FBUSY) && (lnkpoi->busyrx >= 7)) +#endif + +/*----------------------------------------------------------------------*/ +/* */ +/* "level 2 receiver" */ +/* */ +/* Alle Frames aus der RX-Frameliste holen und analysieren. Kopie an */ +/* Monitorliste, digipeaten oder in Level-3-Liste, falls erforderlich. */ +/* Auf UI-Frames antworten, falls erforderlich. */ +/* */ +/* Reaktion entsprechend Protokoll, siehe unten. */ +/* */ +/*----------------------------------------------------------------------*/ +void +l2rx(void) +{ + UBYTE *source; /* Zeiger auf Quellrufzeichen/SSID */ + WORD l2state; /* aktueller Level 2 Linkstatus */ + MBHEAD *fbp; /* Framebufferpointer lokal */ + int i; + int frmr_bytes = 3; /* Anzahl Bytes bei FRMR */ + +#ifdef USERMAXCON + LNKBLK *lnk; + WORD user_links; +#endif + + + /* solange empfangene Frames vorhanden */ + while ((fbp = (MBHEAD *)rxfl.head) != (MBHEAD *)&rxfl) + { + ulink((LEHEAD *)fbp); /* eins aus Liste holen */ + + if (!takfhd(fbp)) /* Kopf analysieren */ + { + dealmb(fbp); /* nicht ok, dann wegwerfen */ + continue; /* naechstes Frame */ + } + + fbp->type = 2; /* wir sind im Level 2 */ + fbp->tx = 0; /* es ist ein empfangenes Frame */ + + monitor(fbp); /* an den Monitor */ + + if (rxfctl == L2CUI) /* UI-Frame */ + { +/* if (istome(rxfhdr) == TRUE) * wenn an mich .. */ +/* if (rxfPF != FALSE * .. und Antwort gewuenscht .. */ +/* && rxfCR != FALSE) */ +/* xdm(); * beantworten mit DM */ +/* */ +/* Dies ist ein Protokollverstoss! Nach AX.25-Protokoll soll auf ein */ +/* UI-Frame mit Poll nur dann mit DM geantwortet werden, wenn kein Link */ +/* besteht. Wenn dagegen ein Link besteht, soll entsprechend Linkzu- */ +/* stand geantwortet werden. Dadurch kann ein bestehender, gut funktio- */ +/* nierender Link vorzeitig beendet werden. Jetzt wird der Fehler so */ +/* geaendert, dass auf eine Reaktion hier vollkommen verzichtet wird. */ +/* Manche Spielkinder hatten ausserdem bemerkt, dass man einen Knoten */ +/* abschiessen kann, wenn man ihm in einer Aussendung beliebig viele */ +/* UI-Frames mit Poll schickt. Dadurch werden naemlich fuer die Ant- */ +/* wort-Frames beliebig viele Buffer belegt, bis der Knoten einen Reset */ +/* ausloest. Auch deshalb ist es guenstiger, hier auf eine Reaktion zu */ +/* verzichten. Wenn es jemanden stoeren sollte, darf er natuerlich die */ +/* vom AX.25-Protokoll geforderte Reaktion einbauen. */ + + lnkpoi = NULL; /* kein Linkpointer */ + + /* PID des UI-Frames holen wenn noch Bytes da, sonst 0 eintragen */ + fbp->l2fflg = (fbp->mbgc < fbp->mbpc) ? getchr(fbp) : 0; + + /* Fuer uns interessantes UI-Frame ? */ + if ( (cmpid(rxfhdr, myid)) /* an mich direkt */ + || (cmpid(rxfhdr, "NODES \140")) /* NETROM-Nodes */ +#ifdef IPROUTE + || (istomev() == 4) /* AX25-ARP an "QST" */ + || (istomev() == 5) /* AX25-ARP an "QST" */ +#endif + ) + { + /* UI-Frame bearbeiten */ + if (!tol3sw(fbp)) + dealmb(fbp); + } + else /* UI-Frames, die gedigipeated werden koennen/muessen */ + gateway_ui(rxfhdr + L2IDLEN, rxfhdr, rxfhdr + L2ILEN, fbp); + + continue; + } + +/* Haben wir einen zum Frame passenden Linkblock ? */ +/* */ +/* Die Linkliste dieses Ports durchgehen und nach einem passenden Link- */ +/* block ausschau halten. Wurde er gefunden, wird er an das Ende der */ +/* Liste gehaengt, weil die Liste im naechsten Durchlauf wieder von */ +/* hinten durchsucht wird. */ +/* */ +/* Wenn wir keinen passenden Link haben, aber das Framezielcall an mich */ +/* (Call + SSID oder Ident mit beliebiger SSID) ist, oder das Block- */ +/* quellcall mit dem Framezielcall uebereinstimmt, dann einen neuen */ +/* Link aus der Freiliste holen. */ +/* Wichtig: Es wird der Header, den wir senden wuerden, mit der Link- */ +/* liste verglichen (txf...) */ +/* printf("\nistomev() = %u\n", istomev()); */ +#ifdef __WIN32__ + lnkpoi = getlnk((unsigned char)rxfprt, txfhdr + L2IDLEN, txfhdr, txfhdr + L2ILEN); +#else + lnkpoi = getlnk(rxfprt, txfhdr + L2IDLEN, txfhdr, txfhdr + L2ILEN); +#endif /* WIN32 */ + +/* Jetzt haben wir einen Pointer auf den Link, der entweder schon vorher*/ +/* bestand, oder der jetzt neu angelegt wurde. Ist der Pointer gleich */ +/* NULL, dann ist was schiefgegangen und wir koennen nicht annehmen. */ + + if (lnkpoi == NULL) /* keinen passenden Linkblock gefunden und es */ + /* kann kein Link mehr angenommen werden. */ + { + if (istome(rxfhdr)) /* Verbindung fuer mich ? */ + { + if ( rxfctl == L2CSABM /* SABM */ +#ifdef EAX25 + || rxfctl == L2CSABME /* SABME (EAX.25) */ +#endif + ) + { + l2tolx(L2MBUSYT); /* hoeheren Leveln melden */ + xdm(); /* mit DM beantworten */ + } + else /* sonst nur antworten, wenn */ + if ( rxfPF != 0 /* Command mit Poll, dann */ + && rxfCR != 0) /* mit DM antworten */ + xdm(); + else /* oder wenn kein Command */ + if (rxfctl == L2CDISC) /* Poll, aber ein DISC, mit */ + xua(); /* UA antworten */ + } + dealmb(fbp); /* empfangenes Frame wegwerfen */ + continue; /* und zum naechsten */ + } + + if (lnkpoi->state == L2SDSCED) /* wir haben den Link noch nicht */ + { + if (istomev() == 0) /* nicht fuer mich und auch nicht via */ + { + dealmb(fbp); /* Frame wegwerfen */ + continue; /* und zum naechsten */ + } + } + +/* Falls Timer 3 aktiv, diesen neu setzen, es ist wieder Aktivitaet auf */ +/* dem Link. */ + if (lnkpoi->T3 != 0) + setT3(); + + l2state = lnkpoi->state; /* Linkstatus zur Abfrage */ + +#ifdef DAMASLAVE + if (rxfDA) /* DAMA? */ + { + if (damaslave(rxfprt)) /* DAMA-Slave auf Port erlaubt? */ + { + portpar[rxfprt].damaok = 12000; /* 2 Minuten Timeout */ + if (rxfPF && rxfCR) /* wenn gepollt */ + { + l2stma(stbl10a); /* DAMA-Poll receive */ + portpar[rxfprt].sendok = 1; + if (l2state) /* aktiver Link ? */ + if ( (rxfctl & L2CNONRM) != L2CNONRM /* Frame mit N(R) */ + && srxdNR() == TRUE /* Zaehlerstand ok */ + && lnkpoi->VS != lnkpoi->lrxdNR /* noch was offen? */ + ) + { + ++lnkpoi->tries; /* Retryzaehler erhoehen */ + +#ifdef T1TIMERMOD + /* Nach 3 erfolglosen Versuche, */ + /* wird der SRTT-Wert vergroessert. */ + if ( (lnkpoi->tries > 2) + /* SRTT-Wert kleiner als 50. */ + &&(lnkpoi->SRTT < 50)) + { + lnkpoi->RTT = 10; + clrRTT(); + } +#endif /* T1TIMERMOD */ + + lnkpoi->flag |= L2FREPEAT; +/* da nicht alles bestaetigt, wird Maxframe um 1 reduziert */ + change_maxframe(lnkpoi, -1); + } + } + } + } +#endif + + if (!(rxfctl & L2CNOIM)) /* I-Frame ? */ + { +/*----------------------------------------------------------------------*/ +/* I-Frame : */ +/* */ +/* Nur annehmen, wenn empfangene N(R) des Frames ok, srxdNR(), und das */ +/* I-Frame das naechste erwartete in der Sequenz ist, isntxi(). Wenn */ +/* alles ok, Laenge pruefen und ggf. auf falsche Laenge mit Frame- */ +/* Reject reagieren, sonst Antwort entsprechend Statetable und I-Frame */ +/* verarbeiten. */ +/*----------------------------------------------------------------------*/ + if ( srxdNR() /* N(R) ok? */ + && isnxti()) /* erwartet? */ + { + if (fbp->mbpc - fbp->mbgc <= L2MILEN + 1) /* Info-Laenge ok? */ + { + lnkpoi->tries = 0; +/*----------------------------------------------------------------------*/ +/* Bei DAMA-Betrieb auf dem Port eventuell erstes neues I-Poll */ +/* anmeckern. DAMA-Ack-Poll verzoegern, bis alle Infos verarbeitet.. */ +/* Aktivitaetszaehler und -merker loeschen */ +/*----------------------------------------------------------------------*/ + if (dama(rxfprt)) /* I-Frame auf DAMA-Port ? */ + { + if (rxfPF & L2CPF) /* Wenn I-Poll.. */ + { + polDAMA(); /* anmeckern.. */ + l2stma(stbl00dama); + } + else /* kein Poll */ + { + clrDAMA(); /* DAMA clear ! */ + setT2(0); /* T2 setzen */ + lnkpoi->damapc = lnkpoi->T2; /* und fuer DAMA nehmen */ + l2stma(stbl01dama); /* DAMA braucht auch T2.. */ + } + } + else + if (rxfPF & L2CPF) /* Poll */ + l2stma(stbl00); + else /* kein Poll */ + l2stma(stbl01); + +/* Wenn kein I-Frame mehr kommen kann, T2 loeschen */ + if (((lnkpoi->VR - lnkpoi->ltxdNR) & lnkpoi->bitmask) == lnkpoi->bitmask) + { + lnkpoi->T2 = 0; /* T2 loeschen */ + if (dama(rxfprt)) + lnkpoi->damapc = 0; + } + +/* Linkzustand I-Transfer moeglich und nicht busy ? */ + + if ( (l2state >= L2SIXFER) + && (l2state != L2SHTH) + && !LINKBUSY) + { + if (lnkpoi->flag & L2FBUSY) + lnkpoi->busyrx++; + fbp->l2fflg = fbp->mbgc < fbp->mbpc ? getchr(fbp) : 0; +#ifdef IPROUTE + if (istome (rxfhdr)) + if ((fbp = pid8frag(fbp)) == NULL) + continue; +#endif +/*----------------------------------------------------------------------*/ +/* wenn Level-3-I-Paket, dann in Level-3-RX-Liste einhaengen und Link */ +/* als Level-3-Link markieren, No-Activity-Timeout neu starten */ +/*----------------------------------------------------------------------*/ + if (tol3sw(fbp)) +#ifndef THENETMOD + lnkpoi->noatou = ininat; +#else /* L4TIMEOUT */ + lnkpoi->noatou = SetL4Timeout(); /* L2/L4-Timeout setzen. */ +#endif /* THENETMOD */ + else + { +/*----------------------------------------------------------------------*/ +/* wenn normales Level-2-I-Paket, wenn nicht Busy oder Level-3-Link, I */ +/* annehmen und in Linkempfangsliste einhaengen */ +/*----------------------------------------------------------------------*/ + if (!(lnkpoi->flag & (L2FDSLE | L2FDIMM))) + { + relink((LEHEAD *)fbp, (LEHEAD *)lnkpoi->rcvdil.tail); + ++lnkpoi->rcvd; + } + else /* sonst */ + dealmb(fbp); /* Paket verwerfen */ + } + continue; /* naechstes Paket */ + } + } + else /* Frame zu lang */ + sdfrmr(0x03); /* U/S-Frame invalid! */ + } + } /* durchfallen und Frame wegschmeissen */ + else /* kein I-Frame : */ + { + if (!(rxfctl & L2CNOSM)) /* "no S mask", kein S-Frame */ + { +/*----------------------------------------------------------------------*/ +/* S-Frame : */ +/* */ +/* Nur annehmen, wenn empfangene N(R) des Frames ok, srxdNR(), und wenn */ +/* das Frame kein Infofeld enthaelt. */ +/* */ +/* Auf RR, RNR, REJ entsprechend Statetable antworten, auf andere mit */ +/* Frame-Reject antworten. */ +/*----------------------------------------------------------------------*/ + + if (srxdNR()) /* N(R) ok? */ + { + if (fbp->mbgc == fbp->mbpc) /* kein I-Feld? */ + { + lnkpoi->tries = 0; + if (dama(rxfprt)) /* Auf DAMA-Links: */ + incDAMA(); /* Prioritaet runter */ + switch (rxfctl & 0x0c) + { + case L2CRR & 0x0c: /* RR Frame */ + l2stma(!rxfCR + ? (!rxfPF ? stbl11 : stbl10) + : (!rxfPF ? stbl03 : stbl02)); + if (dama(rxfprt)) /* wenn DAMA-Port */ + if (rxfCR && rxfPF) /* und gepollt wird */ + polDAMA(); /* DAMA-Warnung */ + break; + + case L2CRNR & 0x0c: /* RNR Frame */ + l2stma(!rxfCR + ? (!rxfPF ? stbl15 : stbl14) + : (!rxfPF ? stbl07 : stbl06)); + lnkpoi->flag |= L2FREPEAT; + break; + + case L2CREJ & 0x0c: /* REJ Frame */ + l2stma(!rxfCR + ? (!rxfPF ? stbl13 : stbl12) + : (!rxfPF ? stbl05 : stbl04)); + if ((l2state >= L2SIXFER) && (l2state != L2SHTH)) + { +/* bei REJ wird Maxframe um 1 reduziert - wer mies empfaengt, landet */ +/* irgendwann bei Maxframe 1 */ + change_maxframe(lnkpoi, -1); + lnkpoi->flag |= L2FREPEAT; +#ifndef DAMASLAVE + if (!dama(rxfprt)) +#else + if ( !dama(rxfprt) + && !damaslaveon(rxfprt)) +#endif + sdoi(); /* ausstehende I-Frames senden */ + } + break; + + default: /* Kontrollfeld falsch oder nicht */ + sdfrmr(0x01); /* implementiert! */ + break; + } /* switch */ + } + else /* U/S-Frame mit */ + sdfrmr(0x03); /* unerlaubtem I-Feld */ + } + } /* END S-Frame */ + else /* Kein S-Frame, dann Frame der U-Gruppe */ + { + if ((rxfctl & 0xFF) != L2CFRMR) + { +/*----------------------------------------------------------------------*/ +/* Kein FRMR-Frame, Frame nur annehmen, wenn kein Infofeld vorhanden. */ +/* */ +/* Frame auswerten, reagieren, nach Statetable antworten. */ +/*----------------------------------------------------------------------*/ + clrT3(); /* Timer 3 loeschen */ + if (fbp->mbgc == fbp->mbpc) + { + switch (rxfctl) + { + case L2CSABM: /* neuer Link/-reset */ +#ifdef EAX25 + case L2CSABME: /* neuer EAX.25-Link */ +#endif +#ifdef USERMAXCON + /* Zaehlung auf Port aktiv und Call OK und SABM-Frame fuer/ueber mich ? */ + if ( (portpar[rxfprt].maxcon != 0) + && (fvalca(rxfhdr + L2IDLEN) == YES) + && (istomev() != 0)) + { + /* Anzahl der Connects dieses Users auf *diesem* Port ermitteln */ + for (lnk = lnktbl, i = 0, user_links = 0; i < LINKNMBR; i++, lnk++) + if ( (cmpcal(lnk->dstid, (rxfhdr + L2IDLEN))) + && (lnk->state != L2SDSCED) + && (lnk->liport == rxfprt)) + user_links++; + + /* noch Connects frei ? */ + if (user_links >= portpar[rxfprt].maxcon) + { + /* nein, also den Verbindungswunsch ablehnen */ + xdm(); /* mit DM antworten */ + dealmb(fbp); /* Frame wegschmeissen */ + continue; + } + } +#endif + if (fvalca(rxfhdr + L2IDLEN) != YES) + { + l2tolx(L2MBUSYT); /* nein, melden */ + xdm(); /* mit DM antworten */ + dealmb(fbp); /* Frame vergessen */ + continue; /* naechstes Paket */ + } + +#ifdef EAX25 + /* Ist kein EAX.25 auf diesem Port erlaubt, dann */ + /* Verbindung abwerfen. Das Gleiche noch mal fuer den */ + /* Fall dass nur EAX.25 erzwungen ist, Frame aber AX.25 ist */ + if ( ((rxfctl == L2CSABME) && (portpar[rxfprt].eax_behaviour == 0)) + || ((rxfctl == L2CSABM) && (portpar[rxfprt].eax_behaviour == 3))) + { + xdm(); /* mit DM antworten */ + dealmb(fbp); /* Frame vergessen */ + continue; /* naechstes Paket */ + } + + /* Nur auf EAX.25 umschalten wenn SABME, EAX-Flag ignorieren */ + if (rxfctl == L2CSABME) + { + /* EAX-Verbindung kennzeichnen und Maxframe aendern */ + lnkpoi->bitmask = 0x7F; +#ifdef __WIN32__ + lnkpoi->maxframe = (unsigned char)portpar[rxfprt].maxframe_eax; +#else + lnkpoi->maxframe = portpar[rxfprt].maxframe_eax; +#endif /* WIN32 */ + + } + else + lnkpoi->bitmask = 0x07; /* normale AX.25-Verbindung */ +#endif + /* TEST DG9OBU */ + /* Linkwunsch via uns, kennen wir einen Weg ? */ + /* ebenfalls: Linkwuensche an unsere Locals ? */ + /* (Wird gebraucht bei FlexNet SSID-Bereichsmeldung) */ + + + if ( (lnkpoi->state == L2SDSCED) /* nicht verbunden */ + && ( (istomev() == 2) /* an mich mit via */ + /* nicht an mich, aber einen Local oder in SSID-Range */ + || ((istomev() == 3) && (islocal(rxfhdr) != NO)) +#ifdef PROXYFUNC + || isproxy(rxfhdr) +#endif + ) + ) + { + if (conn_ok(rxfhdr)) /* Ziel bekannt? */ + { + l2stma(stbl08a); /* ja, nicht reagieren */ + /* bis Link steht */ + } + else /* nein - kein neuer */ + { /* Link moeglich */ + dealmb(fbp); /* Frame vergessen */ + continue; /* naechstes Paket */ + } + } + else + l2stma(stbl08); + break; + + case L2CDISC: + if (!l2state) /* Link aktiv ? */ + { + if ( rxfPF != 0 /* nein, wenn Command */ + && rxfCR != 0) /* mit Poll, dann mit */ + xdm(); /* DM antworten */ + else + xua(); /* sonst mit UA */ + dealmb(fbp); /* Frame wegwerfen */ + continue; /* naechstes Paket */ + } + l2stma(stbl09); /* DISC EITHER COMMAND */ + break; + + case L2CUA: + l2stma(stbl16); /* UA EITHER RESPONSE */ + break; + + case L2CDM: +#ifdef EAX25 + /* Wird unser SAMBE mit DM beantwortet, dann Rueckfall */ + /* auf AX.25 */ + if ((l2state == L2SLKSUP) && (lnkpoi->bitmask == 0x7F)) + { + /* Rueckfall nur wenn Port nicht nur EAX.25 zulaesst */ + if (portpar[rxfprt].eax_behaviour != 3) + lnkpoi->bitmask = 0x07; + dealmb(fbp); /* Frame wegwerfen */ + continue; + } +#endif + l2stma(stbl17); /* DM EITHER RESPONSE */ + break; + + default: /* unbekanntes Kontrollfeld : */ + sdfrmr(0x01); /* "Kontrollfeld falsch oder */ + break; /* nicht implementiert" */ + } /* end switch (rxfctl) */ + } /* if */ + else + sdfrmr(0x03); /* Frametyp unbekannt "U/S-Frame mit un- */ + /* erlaubtem Infofeld" */ + } + else + { +/* FRMR-Frame : */ +/* */ +/* Wird nur im Frame-Reject-Zustand oder bei moeglichem Informations- */ +/* transfer angenommen. Es werden die FRMR-Infobytes gelesen, FRMR an */ +/* die hoeheren Level gemeldet, nach Statetable geantwortet. */ + if ( (l2state >= L2SIXFER && l2state != L2SHTH) + || l2state == L2SFRREJ) + { +#ifdef EAX25 + /* FRMR ist bei EAX.25 laenger, neue Laenge setzen */ + if (lnkpoi->bitmask == 0x7F) + frmr_bytes = 5; +#endif + for (source = lnkpoi->frmr, i = 0; i < frmr_bytes; ++i) + { + *source++ = (fbp->mbgc < fbp->mbpc) ? getchr(fbp) : 0; + } + } + l2stma(stbl18); /* FRMR EITHER RESPONSE */ + } + } + } + dealmb(fbp); /* aktuelles Frame verarbeitet, wegwerfen */ + } /* end while ((fbp = rxfl.head) != &rxfl) */ +} + +/************************************************************************/ +/* */ +/* "take frame head" */ +/* */ +/* Adresskopf und Kontrollbyte des Frames aus dem Framebuffer, auf */ +/* dessen Kopf fbp zeigt, analysieren. Diese Funktion ist die erste, */ +/* die auf ein empfangenes Frame angewandt wird. */ +/* */ +/* */ +/* Folgende Parameter werden bei der Analyse gesetzt: */ +/* */ +/* rxfhdr, rxfPF, rxfCR, rxfctl, rxfprt, rxfDA */ +/* (rxfEAX, rxfctlE wenn Extended-AX.25 aktiviert) */ +/* */ +/* Folgende Parameter werden nach der Analyse gesetzt fuer ein */ +/* moegliches Antwortframe : */ +/* */ +/* txfhdr = Quell- und Zielcall aus rxfhdr, aber vertauscht, plus */ +/* reverse via-Liste aus rxfhdr */ +/* txfPF = rxfPF */ +/* txfCR = 0, Response ! */ +/* txfprt = rxfprt */ +/* */ +/* */ +/* Return : TRUE - das Frame hat einen gueltigen AX.25-Framekopf */ +/* FALSE - sonst */ +/* */ +/************************************************************************/ +BOOLEAN +takfhd(MBHEAD *fbp) +{ + char *p; /* Zeiger im Header */ + char *source; /* Quellzeiger Kopien */ + char *dest; /* Zielzeiger Kopien */ + int n; + + rxfprt = fbp->l2port; /* Port uebernehmen */ + + if (!portenabled(rxfprt)) /* Port gesperrt */ + return (FALSE); + + rwndmb(fbp); /* Frame von vorne */ + for (p = rxfhdr, n = 1; n <= L2INUM + L2VNUM; n++) + { + if (!getfid(p, fbp)) /* naechstes Call lesen */ + { + INV_FRAME(rxfprt, INVF_ADR); + return (FALSE); + } + p += L2IDLEN; + if (*(p - 1) & L2CEOA) + break; /* Ende des Addressfeldes */ + } + *(p - 1) &= ~L2CEOA; + + if (n < L2INUM) /* Absender und/oder Ziel fehlt */ + { + INV_FRAME(rxfprt, INVF_ALN); + return (FALSE); + } + + if (n > L2VNUM + L2INUM) /* Addressfeld zu lang */ + { + INV_FRAME(rxfprt, INVF_ALN); + return (FALSE); + } + *p = NUL; /* Addressfeld terminieren */ + + if (fbp->mbgc == fbp->mbpc) /* Control-Feld fehlt? */ + { + INV_FRAME(rxfprt, INVF_CTL); + return (FALSE); + } + + rxfctl = getchr(fbp); /* Control-Byte extrahieren */ + +/* Framelaengencheck UI-Frames: jetzt duerfen noch max. 257 ungelesene */ +/* Bytes im Buffer sein! (PID + 256 Bytes Info) */ + if ((rxfctl == L2CUI) && (fbp->mbpc - fbp->mbgc > L2MILEN + 1)) + return (FALSE); + + rxfDA = !(rxfhdr[L2ILEN-1] & L2CDAMA); /* ist es ein DAMA-Frame? */ + + rxfhdr[L2ILEN-1] |= L2CDAMA; /* DAMA-Flag zuruecksetzen */ + +#ifdef EAX25 + /* EAX-Bit maskieren und invertieren, da im Frame geloescht gleich */ + /* aktiviert bedeutet, hier aber "normale" Logik verwendet wird. */ + rxfEAX = !(rxfhdr[L2ILEN-1] & L2CEAX); /* ist es ein Extended-Frame? */ + + rxfhdr[L2ILEN-1] |= L2CEAX; /* EAX.25-Flag zuruecksetzen */ + + /* bei EAX-Frames zweites Control-Byte lesen wenn nicht U-Frame */ + if (rxfEAX && !((rxfctl & 0x03) == 3)) /* kein U-Frame, dann zweites */ + rxfctlE = getchr(fbp); /* zweites Controlbyte lesen */ + else + rxfctlE = 0; /* zweites Controlbyte leer */ +#endif + + /* Unterscheidung AX.25 V1- oder V2-Frame, wir koennen nur V2 */ + if (((rxfhdr[L2IDLEN - 1] ^ rxfhdr[L2ILEN - 1]) & L2CCR) != 0) + { + /* Auswertung normale AX.25-Frames und EAX U-Frames */ + rxfCR = rxfhdr[L2IDLEN - 1]; + rxfCR &= L2CCR; + +#ifdef EAX25 + /* Pollflag befindet sich an unterschiedlichen Positionen */ + if ( !rxfEAX + || (rxfEAX && ((rxfctl & 0x03) == 3))) +#endif + rxfPF = rxfctl & L2CPF; /* Auswertung Pollflag bei AX.25 */ +#ifdef EAX25 + else + rxfPF = (rxfctlE << 4) & L2CPF; /* Auswertung Pollflag bei EAX25 */ +#endif + } + else + return (rxfctl == L2CUI); /* V1-Frame, nur UI nehmen */ + +#ifdef EAX25 + /* PF-Bit ruecksetzen */ + if ( !rxfEAX + || (rxfEAX && ((rxfctl & 0x03) == 3))) +#endif + rxfctl &= ~L2CPF; /* AX.25 */ +#ifdef EAX25 + else + rxfctlE &= 0xFE; /* EAX.25 */ +#endif + + txfCR = 0; /* Command-Flag fuer TX-Frame */ + txfPF = rxfPF; /* Poll-Flag bei TX wie bei RX */ + txfprt = rxfprt; /* TX-Port gleich RX-Port */ + cpyid(txfhdr, rxfhdr + L2IDLEN); /* Calls von Absender und Ziel */ + cpyid(txfhdr + L2IDLEN, rxfhdr); /* vertauschen */ + +/* Jetzt wird das via-Feld so umgebaut, wie es bei der Sendung aussehen */ +/* wird. */ + for (source = rxfhdr + L2ILEN; *source; source += L2IDLEN) + ; + for (dest = txfhdr + L2ILEN; source != rxfhdr + L2ILEN; dest += L2IDLEN) + { + source -= L2IDLEN; + memcpy(dest, source, L2IDLEN); /* Rufzeichen kopieren */ + dest[L2IDLEN - 1] ^= L2CH; + } + *dest = NUL; + + return (TRUE); +} + +/************************************************************************/ +/* */ +/* "level 2 to level x" */ +/* */ +/* Meldung msg (L2M...) an Layer 3 und hoehere Layer weitergeben. */ +/* */ +/************************************************************************/ +void +l2tolx(WORD msg) +{ + if (!l2tol3(msg)) /* Layer 2 -> Layer 3 */ + l2tol7(msg, lnkpoi, L2_USER); /* Layer 2 -> Layer 7 */ +} + +/************************************************************************\ +* * +* Informationstransfer von Layer 2 nach Layer X * +* --------------------------------------------- * +* * +* Infopakete aus dem aktuellen Link (lnkpoi) an hoehere Level * +* weiterreichen. conctl gibt an, ob der hoehere Level die * +* Erstickungskontrolle" (hier = Beruecksichtigung der maximal * +* noch anzunehmenden I-Pakete) machen soll (FALSE) oder in jedem * +* Fall alle uebermittelten I-Pakete annehmen muss (TRUE). Falls * +* die I-Pakete vom hoeheren Level angenommen wurden, Empfangs- * +* zaehler rcvd und Aktivitaetstimer noatou entsprechend updaten. * +* Es wird l2link in den Framekoepfen der weitergereichten Pakete * +* auf lnkpoi gesetzt und type auf 2 fuer "Level 2". * +* * +* Solange noch empfangene Pakete vorhanden sind, werden diese * +* an andere Layer durch Aufruf von fmlink() uebertragen. Bei ge- * +* setztem Ueberfuellungskontroll-Flag (conctl == TRUE) wird die * +* Uebertragung abgebrochen, wenn der andere Layer keine weiteren * +* Daten mehr aufnehmen kann. * +* * +* Nach erfolgter Uebertragung wird die Anzahl der uebertragenen * +* Zeichen fuer die Statistik gezaehlt und der No-Activity-Timer * +* neu gesetzt. * +* * +\************************************************************************/ +void +i2tolx(BOOLEAN conctrl) +{ + MBHEAD *mbp; /* Zeiger auf Framekopf weiterzureichendes I */ + + if ( (lnkpoi->state == L2SDSCRQ) + || (lnkpoi->flag & (L2FDSLE | L2FDIMM))) + { + dealml((LEHEAD *)&lnkpoi->rcvdil); + lnkpoi->rcvd = 0; + return; + } + + while (lnkpoi->rcvd != 0) /* solange I's aus Link vorhanden */ + { + mbp = (MBHEAD *)lnkpoi->rcvdil.head; + mbp->l2link = lnkpoi; /* Linkzeiger */ + mbp->type = 2; /* Level 2 ! */ + if (!fmlink(conctrl, mbp)) /* I an hoeheren Level geben */ + return; /* Abbruch, wenn nicht angenommen */ + +#ifndef THENETMOD + lnkpoi->noatou = ininat; +#else /* L4TIMEOUT */ + lnkpoi->noatou = SetL4Timeout(); /* L2/L4-Timeout setzen, */ +#endif /* THENETMOD */ + + --lnkpoi->rcvd; /* Empfangspaketezaehler updaten */ + } +} + + +/************************************************************************\ +* * +* "serve received N(R)" * +* * +* Aktuell empfangenes N(R) (rxfctl) des aktuellen Links (lnkpoi) * +* auswerten und entsprechend verfahren (s.u.). * +* * +* Return: TRUE - aktuell empfangenes N(R) ist okay oder * +* Linkzustand laesst N(R)-Empfang nicht zu * +* FALSE - aktuell empfangenes N(R) ist falsch * +* * +\************************************************************************/ +static BOOLEAN +srxdNR(void) +{ +#ifdef __WIN32__ + char rxdNR; /* emfangenes N(R) */ +#else + WORD rxdNR; /* emfangenes N(R) */ +#endif + WORD newok; /* Anzahl neu bestaetigte I's */ + WORD outstd; /* Anzahl ausstehende (unbestaetigte) I's */ + WORD l2state; /* Link-Status */ + + l2state = lnkpoi->state; + if (l2state >= L2SIXFER && l2state != L2SHTH) /* darf N(R) kommen? */ + { +#ifdef EAX25 + /* EAX I- und S-Frames gesondert behandeln, U-Frames wie bei AX25 */ + if ( (lnkpoi->bitmask == 0x7F) && ((rxfctl & 0x03) <= 2)) + rxdNR = ((rxfctlE >> 1) & 0x7F); + else +#endif + rxdNR = ((rxfctl >> 5) & 0x07); /* Sequenznummer lesen */ + + if ( (outstd = outsdI()) != 0 /* Wenn I's ausstehen und */ + && (newok = ((rxdNR - lnkpoi->lrxdNR) & lnkpoi->bitmask)) != 0) + { /* neue bestaetigt wurden: */ + if (newok <= outstd) /* und nicht zuviel bestaet. */ + { + if ( (lnkpoi->lrxdNR) + &&((lnkpoi->RTTvs - lnkpoi->lrxdNR) & lnkpoi->bitmask) >= newok) + clrRTT(); /* RTT-Messung ok, stoppen */ + +#ifdef __WIN32__ + lnkpoi->lrxdNR = (char)rxdNR; /* dann N(R) annehmen, */ +#else + lnkpoi->lrxdNR = rxdNR; /* dann N(R) annehmen, */ +#endif /* WIN32 */ + clrT1(); /* T1 stoppen, */ + /* Sind alle ausstehenden I's */ + if (newok == outstd) /* bestaetigt worden ? */ + { /* ja: */ + +/* Da alles bestaetigt, kann Maxframe erhoeht werden */ + change_maxframe(lnkpoi, +1); + + if ((signed char)lnkpoi->priold != -1) /* bei Downlink-Aktivitaet: */ +#ifdef __WIN32__ + lnkpoi->damapm = (unsigned char)lnkpoi->priold; /* Prioritaet reseten */ +#else + lnkpoi->damapm = lnkpoi->priold; /* Prioritaet reseten */ +#endif /* WIN32 */ + lnkpoi->priold = -1; /* Priori-Flag loeschen */ + clearDT(0); /* DAMA-Timer loeschen <<<< */ + } + else + setT1(); /* T1 neu starten */ + + while (newok-- != 0) /* Alle bestaetigten Frames */ + { /* aus der Liste entfernen */ + dealmb((MBHEAD *)ulink((LEHEAD *)lnkpoi->sendil.head)); + --lnkpoi->tosend; + } + } + else /* Mehr I's bestaetigt als */ + { + sdfrmr((char)0x08); /* ausstehen. Das geht nicht. */ + return (FALSE); /* FRMR erzeugen, N(R) falsch */ + } + } + if ( l2state == L2SWA /* Falls warten auf Bestaetigung */ + || l2state == L2SWADBS + || l2state == L2SWARBS + || l2state == L2SWABBS) + { + if (!rxfCR && rxfPF != 0) /* Wenn RR mit Final war, dann */ + { + clrT1(); /* T1 stoppen */ + clrRTT(); /* RTT stoppen, Messung gueltig */ + if (lnkpoi->VS != lnkpoi->lrxdNR) + lnkpoi->flag |= L2FREPEAT; + clearDT(0); /* DAMA-Timer loeschen */ + } + else if (!lnkpoi->T1) /* T1 neu starten */ + setT1(); + } + } + + return (TRUE); +} + +/************************************************************************\ +* * +* "is next I" * +* * +* Testen, ob das aktuell empfangene I-Frame (rxf...) das naechste fuer * +* den aktuellen Linkblock (lnkpoi) erwartete I-Frame ist, wenn der * +* Linkzustand Informationstransfer zulaesst. Bei nicht erwarteter * +* Sequenznummer entsprechende Statetable abarbeiten. * +* * +* Return : TRUE - I-Frame ist das naechste erwartete oder Linkzustand * +* laesst keinen Informationstransfer zu * +* FALSE - sonst * +* * +\************************************************************************/ +static BOOLEAN +isnxti(void) +{ + WORD iseqno; /* I Sequence Number */ + + if ( lnkpoi->state >= L2SIXFER + && lnkpoi->state != L2SHTH) /* I-Transfer? */ + { + /* N(S) des Kontrollfeldes maskieren, diese Framenummer erwartet ? */ + if ((iseqno = (rxfctl >> 1) & lnkpoi->bitmask) == lnkpoi->VR) /* I erwartet ? */ + { + /* Maximale Erhoehung des Sequenzzaehlers */ + if (((lnkpoi->ltxdNR + lnkpoi->bitmask) & lnkpoi->bitmask) != iseqno) /* kein Ueberlauf ? */ + { + if (!LINKBUSY) /* wenn nicht busy, neue */ + lnkpoi->VR = (iseqno + 1) & lnkpoi->bitmask; /* V(R) setzen */ + } + else + { + sdfrmr((char)0x01); + return (FALSE); + } + } + else + { /* unerwartetes Info: */ + l2stma(!rxfPF ? stbl26 : stb26b); /* INVALID N(S) RECEIVED */ + if (dama(lnkpoi->liport) && rxfPF) /* I-Poll ? <=== */ + polDAMA(); /* ja: muss meckern! <=== */ + return (FALSE); + } + } + return (TRUE); /* I richtig oder Linkzustand ohne I-Transfer */ +} + +/************************************************************************\ +* * +* "info to layer x and clear link" * +* * +* Empfangsdaten ohne Flowcontrol in den Layer hochmelden und dann * +* Link zuruecksetzen. * +* * +\************************************************************************/ +void +i2xclr(void) +{ + i2tolx(TRUE); + clrlnk(); +} + +#ifdef IPROUTE +/************************************************************************\ +* * +* "pid 8 fragmentierung" * +* * +* Ein PID 8 Frame empfangen und ggfs mit vorhergehenden Frames zusammen- * +* basteln. * +* * +\************************************************************************/ +static MBHEAD * +pid8frag(MBHEAD *fbp) +{ + BYTE anz_frag; + MBHEAD *ret; + int len; + + if (fbp->l2fflg != L2CFRAG) /* PID 08 ? */ + return (fbp); /* nein, dann Frame zurueck */ + + if ((len = fbp->mbgc - fbp->mbpc) == 0) /* leeres Frame? */ + { + if (lnkpoi->tmbp != NULL) + dealmb(lnkpoi->tmbp); + dealmb(fbp); + return(NULL); + } + anz_frag = getchr(fbp); /* erstes Byte lesen */ + if (anz_frag & 0x80) /* erstes PID08-Frame */ + { + if (lnkpoi->tmbp != NULL) /* Fehler! Letztes Paket war */ + dealmb(lnkpoi->tmbp); /* noch nicht komplett */ + if (len == 1) /* keine PID im 1. Frame? */ + { + dealmb(fbp); + return(NULL); + } + anz_frag &= 0x7F; /* Anzahl der Folgefragmente */ + lnkpoi->tmbp = (MBHEAD *)allocb(ALLOC_MBHEAD); /* Buffer besorgen */ + lnkpoi->tmbp->l2fflg = getchr(fbp); /* PID des Originals lesen */ + } + else + if (lnkpoi->tmbp == NULL) /* Fehler! Folgefragment ohne */ + { /* vorheriges 1. Fragment */ + dealmb(fbp); /* hier muesste eigentlich ein */ + return (NULL); /* FRMR fuer PID08 folgen, gips */ + } /* aber wohl nicht? */ + while (fbp->mbgc < fbp->mbpc) + putchr(getchr(fbp), lnkpoi->tmbp); + dealmb(fbp); + + if (anz_frag == 0) /* letztes Frame! */ + { + rwndmb(lnkpoi->tmbp); /* zurueckspulen */ + ret = lnkpoi->tmbp; + lnkpoi->tmbp = NULL; + return (ret); /* und an L2 uebergeben */ + } + else + return (NULL); /* es folgen weitere Teile */ +} +#endif + +/* End of src/l2rx.c */ diff --git a/src/l2stma.c b/src/l2stma.c new file mode 100755 index 0000000..181b219 --- /dev/null +++ b/src/l2stma.c @@ -0,0 +1,870 @@ +/************************************************************************/ +/* */ +/* ***** ***** */ +/* ***** ***** */ +/* ***** ***** */ +/* ***** ***** */ +/* *************** *************** */ +/* ***************** ***************** */ +/* *************** *************** */ +/* ***** ***** TheNetNode */ +/* ***** ***** Portable */ +/* ***** ***** Network */ +/* ***** ***** Software */ +/* */ +/* File src/l2stma.c (maintained by: DF6LN) */ +/* */ +/* This file is part of "TheNetNode" - Software Package */ +/* */ +/* Copyright (C) 1998 - 2008 NORD>state]; /* Zeiger auf den Zustandseintrag */ + msg = st->msg; /* Meldung zum Layer */ + + st->func(); /* Zustandsuebergangsfunktion */ + l2newstate(st->newstate); /* neuen State setzen */ + if (msg != L2MNIX) + { + mftb[msg].func(); /* Meldungsfunktion */ +#ifdef __WIN32__ + l2tolx((short)msg); /* Ereignis melden */ +#else + l2tolx(msg); /* Ereignis melden */ +#endif /* WIN32 */ + } +} + +/************************************************************************\ +* * +* "level 2 new state" * +* * +* In einen neuen Zustand uebergehen. Da hier die aktiven Links gezaehlt * +* werden, duerfen Status-Wechel nur hier durchgefuehrt werden. * +* * +\************************************************************************/ +void +l2newstate(WORD newstate) +{ + WORD oldstate; + PORTINFO *p; + int port; + + oldstate = lnkpoi->state; /* alten Status merken */ +/****************************************************/ +/* Konvertierung von 'short ' in 'unsigned char ',*/ +/* moeglicher Datenverlust */ +/* Modifiziert durch Oliver Kern */ +/* Str. d. Zukunft 29 */ +/* 01612 Glaubitz */ +#ifdef __WIN32__ + lnkpoi->state = (UBYTE)newstate; +#else + lnkpoi->state = newstate; +#endif +/****************************************************/ + if (oldstate && !newstate) /* ein Link wird abgebaut */ + { + relink(ulink((LEHEAD *)lnkpoi), /* aus der aktiv-Liste nehmen */ + (LEHEAD *)l2frel.tail); /* in die Freiliste haengen */ + nmblks--; /* nun haben wir einen weniger */ + (p = &portpar[port = lnkpoi->liport])->nmblks--; + if (!multiconn(port, lnkpoi->realid)) /* letzter Connect? */ + { + p->nmbstn--; + autopers(port); /* Port-Parameter anpassen */ + } + getMCs(); /* Veraenderung DAMA melden */ + } + if (!oldstate && newstate) /* ein Link wird aufgebaut */ + { + if (++nmblks > nmblks_max) /* Maximalwert fuer die Statistik */ + nmblks_max = nmblks; + (p = &portpar[port = lnkpoi->liport])->nmblks++; + if (!multiconn(port, lnkpoi->realid)) /* erster Connect? */ + { + p->nmbstn++; + autopers(port); /* Port-Parameter anpassen */ + } + relink(ulink((LEHEAD *)lnkpoi), /* Link aus der frei-Liste nehmen */ + (LEHEAD *)l2actl[lnkpoi->liport].tail); + getMCs(); /* Veraenderung DAMA melden */ + } +} + +/* End of src/l2stma.c */ diff --git a/src/l2timer.c b/src/l2timer.c new file mode 100755 index 0000000..16ca32f --- /dev/null +++ b/src/l2timer.c @@ -0,0 +1,592 @@ +/************************************************************************/ +/* */ +/* ***** ***** */ +/* ***** ***** */ +/* ***** ***** */ +/* ***** ***** */ +/* *************** *************** */ +/* ***************** ***************** */ +/* *************** *************** */ +/* ***** ***** TheNetNode */ +/* ***** ***** Portable */ +/* ***** ***** Network */ +/* ***** ***** Software */ +/* */ +/* File src/l2timer.c (maintained by: DF6LN) */ +/* */ +/* This file is part of "TheNetNode" - Software Package */ +/* */ +/* Copyright (C) 1998 - 2008 NORD> 2 + char notify_call1[10]; + char notify_call2[10]; +#endif + + if ((ticks = (UWORD)(tic10 - last_tic)) != 0) + { + last_tic = tic10; + + for (llp = &l2actl[port = 0]; /* alle Ports durchgehen */ + port < L2PNUM; + port++, llp++) + for (lnkpoi = (LNKBLK *)llp->head; + lnkpoi != (LNKBLK *)llp; /* alle Links des Ports pruefen */ + lnkpoi = nextlp) + { + nextlp = lnkpoi->next; /* Nachfolger schonmal merken */ + + if (lnkpoi->flag & L2FACKHTH) /* Bestaetigung von HTH */ + { + if (lnkpoi->state == L2SHTH) + { + stxfad(); /* Sendepfad setzen */ + txfCR = 0; /* Response */ + txfPF = L2CPF; /* Final */ + xua(); /* UA- als Bestaetigung */ + l2newstate(L2SIXFER); /* neuer State: Connected */ + } + lnkpoi->flag &= ~L2FACKHTH; /* Flag loeschen */ + } + if (lnkpoi->flag & L2FREJHTH) /* Ablehnung von HTH */ + { + if (lnkpoi->state == L2SHTH) + { + stxfad(); /* Sendepfad setzen */ + txfCR = 0; /* Response */ + txfPF = L2CPF; /* Final */ + xdm(); /* DM- als Bestaetigung */ + } + lnkpoi->flag &= ~L2FREJHTH; /* Flag loeschen */ + } +/* Wenn RTT-Messung freigegeben ist, dann RTT um ticks erhoehen */ + if (lnkpoi->RTT != 0) + lnkpoi->RTT += ticks; + + if (lnkpoi->T3 != 0) /* wenn Timer 3 aktiv ... */ + { + if (lnkpoi->T3 <= ticks) /* wenn Timer 3 abgelaufen ... */ + { + clrT3(); /* ... Timer 3 stoppen und */ + l2stma(stbl24); /* Statetable T3 EXPIRES */ + } /* ausfuehren */ + else + lnkpoi->T3 -= ticks; /* sonst herunterzaehlen */ + } +#ifdef L2PROFILER + l2profiler(); /* Spielzeug DB7KG */ +#endif + + if ( (lnkpoi->tosend > 150) /* Der Link laeuft ueber.. */ + && (lnkpoi->state >= L2SIXFER) + && (lnkpoi->state != L2SHTH)) + { +#if MAX_TRACE_LEVEL > 2 + call2str(notify_call1, lnkpoi->srcid); + call2str(notify_call2, lnkpoi->dstid); + notify(3, "%s->%s: too many frames in queue", + notify_call1, notify_call2); +#endif + lnkpoi->flag |= L2FDIMM; /* dann abwerfen */ + } + + if (lnkpoi->flag & L2FDIMM) /* Link sofort kappen */ + { + l2stma(stbl20); /* LOCAL STOP COMMAND */ + lnkpoi->flag &= ~L2FDIMM; + continue; + } + + if ( (lnkpoi->flag & L2FDSLE) /* Disconnect wenn alles raus? */ + && (!lnkpoi->tosend)) /* und nix mehr anstehend? */ + { + reslnk(); /* Sequenzvars/Timer zurueck */ + l2stma(stbl20); /* LOCAL STOP COMMAND */ + continue; + } + +/*----------------------------------------------------------------------*/ +/* sonst empfangene I-Pakete an hoeheren Level uebertragen und */ +/* Busy-Condition pruefen / setzen / aufheben */ +/* */ +/* "Busy werden" - weniger als 30 Freibuffer oder so viele I-Pakete */ +/* empfangen und nicht abgeholt, wie "Erstickungs- */ +/* zaehler" conctl angibt */ +/* */ +/* "Busy aufloesen" - wieder mehr als 62 Freibuffer und weniger als */ +/* halb so viele empfangen und nicht abgeholt wie */ +/* conctl angibt */ +/*----------------------------------------------------------------------*/ + i2tolx(FALSE); + if (!(lnkpoi->flag & L2FBUSY)) /* nicht busy */ + { + if (nmbfre < 30 || lnkpoi->rcvd >= conctl) + { + lnkpoi->flag |= L2FBUSY; /* busy werden */ + lnkpoi->busyrx = 0; + l2stma(stbl21); /* STATION BECOMES BUSY */ + } + } + else + if (nmbfre > 62 && lnkpoi->rcvd < conctl / 2) + { + lnkpoi->flag &= ~L2FBUSY; /* "busy" aufloesen */ + l2stma(stbl22); /* BUSY CONDITION CLEARS */ + } + + if ( busy(port) /* T1 und T2 nur wenn DCD aus ist */ + || dama(port)) + continue; + + if (lnkpoi->T1 != 0) /* wenn Timer 1 aktiv ... */ + { + if (lnkpoi->T1 <= ticks) /* wenn Timer 1 abgelaufen ... */ + { + lnkpoi->T1 = 0; /* ... Timer 1 stoppen */ + lnkpoi->RTT = 0; /* RTT-Messung stoppen */ + setT3(); + + ++lnkpoi->tries; + +#ifdef T1TIMERMOD + /* Nach 3 erfolglosen versuchen, */ + /* wird der SRTT-Wert vergroessert. */ + if ( (lnkpoi->tries > 5) + /* SRTT-Wert kleiner als 50. */ + &&(lnkpoi->SRTT < 50)) + { + lnkpoi->RTT = lnkpoi->SRTT; + lnkpoi->RTT += 100; + /* SRTT-Wert neu berechnen. */ + clrRTT(); + } +#endif /* T1TIMERMOD */ + +/* bei Wiederholungen wird Maxframe um 1 reduziert - wer nix empfaengt */ +/* landet irgendwann bei Maxframe 1 */ + if (lnkpoi->tries > 1) + change_maxframe(lnkpoi, -1); + + if (lnkpoi->tries < /* zu viele Retries ? */ + portpar[port].retry) + l2stma(stbl23); /* Statet. T1 EXPIRES */ + else /* zu viele Retries : */ + { + lnkpoi->tries = 0; /* Retryzaehler leer */ + l2stma(stbl25); /* N2 IS EXCEEDED */ + } + } + else + lnkpoi->T1 -= ticks; /* sonst herunterzaehlen */ + } + + if (lnkpoi->T2 != 0) /* wenn Timer 2 aktiv ... */ + { + if (lnkpoi->T2 <= ticks) /* wenn Timer 2 abgelaufen ... */ + lnkpoi->T2 = 0; /* ... Timer 2 stoppen */ + else + lnkpoi->T2 -= ticks; /* sonst herunterzaehlen */ + } + + if (lnkpoi->T2 == 0) /* Timer 2 abgelaufen oder */ + { /* nicht aktiv? */ +#ifdef DAMASLAVE + if (damaslaveon(port)) + continue; +#endif + if (lnkpoi->RStype != 0) /* T2 abgelaufen */ + { + stxfad(); /* ... dann Responseframe bauen */ + txfCR = txfPF = 0; +#ifdef __WIN32__ + txfctl = setNR((UBYTE)(!(lnkpoi->flag & L2FBUSY) ? lnkpoi->RStype : L2CRNR)); +#else + txfctl = setNR(!(lnkpoi->flag & L2FBUSY) ? lnkpoi->RStype : L2CRNR); +#endif /* WIN32 */ +#ifdef EAX25 + txfEAX = FALSE; + /* Kontrollbytes fuer EAX.25 aufbauen bzw. umbauen */ + if (lnkpoi->bitmask == 0x7F) + { + txfctl &= 0x0F; /* erstes Kontrollbyte aendern */ + txfctlE = (lnkpoi->VR << 1) | (txfPF >> 4); /* V(R) und Pollflag */ + txfEAX = TRUE; + } +#endif + sdl2fr(makfhd(L2FUS), TRUE); /* und senden */ + clrT2(); /* Responsemodus loeschen */ + } + } + } /* fuer alle nicht disconnecteten Links */ + timDAMA(ticks); + } +} + +/************************************************************************/ +/* */ +/* "set T2 and xmit RR response" */ +/* */ +/* Timer 2 setzen und nach Ablauf RR als Response senden. */ +/* */ +/************************************************************************/ +void +t2rrr(void) +{ + setT2(L2CRR); +} + +/************************************************************************/ +/* */ +/* "set T2 and xmit RNR response" */ +/* */ +/* Timer 2 setzen und nach Ablauf RNR als Response senden. */ +/* */ +/************************************************************************/ +void +t2rnrr(void) +{ + setT2(L2CRNR); +} + +/************************************************************************/ +/* */ +/* "set T2 and xmit REJ response" */ +/* */ +/* Timer 2 setzen und nach Ablauf REJ als Response senden. */ +/* */ +/************************************************************************/ +void +t2rejr(void) +{ + setT2(L2CREJ); +} + +/************************************************************************/ +/* */ +/* "set T1" */ +/* */ +/* Den Timer 1 anhand des SRTT setzen. Wenn wir bereits erfolglose */ +/* Versuche hatten (tries != 0), wird der Timer 1 vergroessert. Die */ +/* Laufzeitmessung (RTT) wird neu gestartet. */ +/* */ +/************************************************************************/ +void +setT1(void) +{ + lnkpoi->T1 = lnkpoi->SRTT * L2_BETA; + if (lnkpoi->T1 < 20) /* T1 -> min. 200ms */ + lnkpoi->T1 = 20; + if (lnkpoi->tries) /* im Wiederholungsfalle */ + { +#ifdef EAX25 + /* Wenn EAXMODE == 2 und schon mehrere SABME verschickt, dann */ + /* Rueckfall auf AX.25 nach zwei SABME. */ + if ( (lnkpoi->state == L2SLKSUP) /* Wenn der Link nicht steht */ + && (portpar[lnkpoi->liport].eax_behaviour == 2) /* Mode stimmt */ + && (lnkpoi->bitmask == 0x7F)) /* Ein EAX-Link */ + lnkpoi->bitmask = 0x07; /* AX.25 umschalten */ +#endif + if ( (lnkpoi->state >= L2SIXFER) /* Wenn der Link steht */ + && (lnkpoi->state != L2SHTH)) + lnkpoi->T1 *= 2; /* T1 verdoppeln */ + } + if (lnkpoi->T1 > 6000) /* T1 auf 1 Minute begrenzen */ + lnkpoi->T1 = 6000; + setRTT(); +} + +/************************************************************************/ +/* */ +/* "clear T1" */ +/* */ +/* Timer 1 loeschen, es ist eine Reaktion eingetreten. Die Anzahl der */ +/* Fehlversuche (tries) wird geloescht, ebenso der Timer 3 neu gesetzt. */ +/* */ +/************************************************************************/ +void +clrT1(void) +{ + lnkpoi->T1 = 0; + lnkpoi->tries = 0; + setT3(); +} + +/************************************************************************/ +/* */ +/* "set T2" */ +/* */ +/* Timer 2 starten und festlegen, welches Frame nach Ablauf zu senden */ +/* ist. */ +/* */ +/************************************************************************/ +void +setT2(UBYTE Stype) +{ + lnkpoi->RStype = Stype; + lnkpoi->T2 = portpar[lnkpoi->liport].T2; +} + +/************************************************************************/ +/* */ +/* "clear T2" */ +/* */ +/* Timer 2 loeschen. */ +/* */ +/************************************************************************/ +void +clrT2(void) +{ + lnkpoi->T2 = 0; + lnkpoi->RStype = 0; +} + +/************************************************************************/ +/* */ +/* "set T3" */ +/* */ +/* Timer 3 mit Defaultwert initialisieren. */ +/* */ +/************************************************************************/ +void +setT3(void) +{ +#ifdef PORT_MANUELL + lnkpoi->T3 = portpar[lnkpoi->liport].T3; +#else + lnkpoi->T3 = T3par; +#endif /* PORT_MANUELL */ +} + +/************************************************************************/ +/* */ +/* "clear T3" */ +/* */ +/* Timer 1 loeschen. */ +/* Fehlversuche (tries) wird geloescht, ebenso der Timer 3 neu gesetzt. */ +/* Aus der vergangenen Zeit seit dem setzen des T1 wird der RTT und */ +/* damit der SRTT neu berechnet. */ +/* */ +/************************************************************************/ +void +clrT3(void) +{ + lnkpoi->T3 = 0; +} + +/************************************************************************/ +/* */ +/* "set RTT" */ +/* */ +/* RTT starten und VS merken. */ +/* */ +/************************************************************************/ +void +setRTT(void) +{ + lnkpoi->RTT = 1; + lnkpoi->RTTvs = lnkpoi->VS; +} + +/************************************************************************/ +/* */ +/* "clear RTT" */ +/* */ +/* Aus der vergangenen Zeit seit dem setzen des T1 wird der RTT und */ +/* damit der SRTT neu berechnet. */ +/* */ +/************************************************************************/ +void +clrRTT(void) +{ + /* + * Nach RTT-Berechnung aus KA9Q's TCP/IP-Paket: + * + * SRTT' = (Alpha * SRTT + RTT) / (Alpha + 1) + * + * Alpha getrennt parametrisierbar fuer fallendes/steigendes RTT: + * Alpha1 = steigendes RTT (kleines Alpha -> schnell reagieren) + * Alpha2 = fallendes RTT (grosses Alpha -> langsam reagieren) + * + */ + LNKBLK *lp = lnkpoi; + UWORD rtt = lp->RTT, + srtt = lp->SRTT, + irtt = portpar[lp->liport].IRTT; + + if (rtt > srtt) + srtt = (L2_ALPHA1 * srtt + rtt) / (L2_ALPHA1 + 1); + else + srtt = (L2_ALPHA2 * srtt + rtt) / (L2_ALPHA2 + 1); + + if (srtt < irtt / 10) + srtt = irtt / 10; + if (srtt > irtt * 10) + srtt = irtt * 10; + +#ifdef SRTTMAXMOD + if (srtt > SRTTMAXMOD) /* SRTT-Wert ist groesser als SRTTMAX. */ + srtt = SRTTMAXMOD; /* auf SRTTMAX setzen. */ +#endif /* SRTTMAXMOD */ + + lp->RTT = 0; + lp->SRTT = srtt; +} + +/************************************************************************\ +* * +* "check no activity" * +* * +* Alle aktiven Links (lnktbl, Linkstatus "Information Transfer") auf * +* "keine Aktivitaet" abtesten. Ist der Keine-Aktivitaet-Timer aktiv * +* (!= 0) und nach Dekrementieren abgelaufen, Disconnect einleiten. * +* * +* ACHTUNG: Diese Funktion muss sekuendlich aufgerufen werden, * +* wird aber nur fuer TheNetNode benoetigt. * +* * +\************************************************************************/ +void +chknoa(void) +{ + MBHEAD *mbp; + int port; + LHEAD *llp; + + for (port = 0, llp = &l2actl[0]; /* alle Ports durchgehen */ + port < L2PNUM; + port++, llp++) + for (lnkpoi = (LNKBLK *)llp->head; + lnkpoi != (LNKBLK *)llp; /* alle Links des Ports pruefen */ + lnkpoi = lnkpoi->next) + { + if (!(--lnkpoi->noatou)) + { + mbp = (MBHEAD *)allocb(ALLOC_MBHEAD); + mbp->l2link = lnkpoi; /* Linkpointer und */ + mbp->type = 2; /* Typ (2=L2) setzen */ + putchr('\r', mbp); + putalt(alias, mbp); + putid(myid, mbp); + +#ifndef THENETMOD + putstr("> Timeout (", mbp); + putnum(ininat, mbp); /* Timeout in s ausgeben */ + putstr("s)\r", mbp); + seteom(mbp); /* Text an User senden... */ +#else + /* L4TIMEOUT */ + if (SearchTHENET() == NULL) /* Kein THENET-Typ, */ + { + putstr("> Timeout (", mbp); + putnum(ininat, mbp); /* Timeout in s ausgeben */ + putstr("s) run off.\r", mbp); + seteom(mbp); /* Text an User senden... */ + } + else /* THENET-TYP, keine Info senden. */ + dealmb(mbp); /* Buffer entsorgen. */ +#endif /* THENETMOD */ + + if ( (lnkpoi->state == L2SRBS) /* remote busy? */ + || (lnkpoi->state == L2SWARBS) + || (lnkpoi->state == L2SRSRBS) + || (lnkpoi->state == L2SBBS) /* oder beide busy? */ + || (lnkpoi->state == L2SWABBS) + || (lnkpoi->state == L2SRSBBS) + || (lnkpoi->state == L2SHTH)) /* oder Hop-To-Hop */ + lnkpoi->flag |= L2FDIMM; /* sofort abwerfen */ + else + lnkpoi->flag |= L2FDSLE; /* sonst wenn alles raus */ + } + } +} + +/************************************************************************\ +* * +* "set initial SRTT" * +* * +* Anfangswert fuer Smoothed Round Trip Timer setzen * +* * +\************************************************************************/ +void +setiSRTT(void) +{ + char *viap; /* Zeiger in via-Liste */ + UWORD n; /* Digizaehler */ + + viap = lnkpoi->viaidl; /* Anfang via-Liste */ + n = 0; /* noch kein Digi gezaehlt */ + while (*viap != '\0') /* Digianzahl ermitteln */ + { + if (!(viap[L2IDLEN - 1] & L2CH)) + ++n; + viap += L2IDLEN; + } + n *= 2; + ++n; /* Digianzahl * 2 + 1 */ +#ifndef SETISRTTMOD + lnkpoi->SRTT = portpar[lnkpoi->liport].IRTT * n; +#else + lnkpoi->SRTT = portpar[lnkpoi->liport].IRTT * 1; +#endif /* SETISRTTMOD */ +} + +/* End of src/l2timer.c */ diff --git a/src/l2tx.c b/src/l2tx.c new file mode 100755 index 0000000..3b1bba3 --- /dev/null +++ b/src/l2tx.c @@ -0,0 +1,967 @@ +/************************************************************************/ +/* */ +/* ***** ***** */ +/* ***** ***** */ +/* ***** ***** */ +/* ***** ***** */ +/* *************** *************** */ +/* ***************** ***************** */ +/* *************** *************** */ +/* ***** ***** TheNetNode */ +/* ***** ***** Portable */ +/* ***** ***** Network */ +/* ***** ***** Software */ +/* */ +/* File src/l2tx.c (maintained by: DF6LN) */ +/* */ +/* This file is part of "TheNetNode" - Software Package */ +/* */ +/* Copyright (C) 1998 - 2008 NORD>VR gleich bestaetigt werden koennen. */ +/* (Dies waere nicht moeglich, wenn die Frames bereits im L1 Sender */ +/* sitzen und auf Sendung warten). */ +/* Wenn l2tx() einen Port als frei erkennt, werden fuer alle Links */ +/* Informationen gesendet. Der Sender ist dann wieder gesperrt, bis */ +/* alles auf dem Port gesendet wurde. */ +/* Die Linkliste (pro Port) haelt die letzten Links (also die Ver- */ +/* bindungen, die zuletzt bedient und bestaetigt wurden) am Ende, */ +/* deshalb wird sie hier von vorn nach hinten gelesen. Damit wird */ +/* eine gleichmaessige Verteilung erreicht, es gibt kein "Festsaugen" */ +/* an einem Link. */ +/* */ +/* Frames aus Gesendet-Liste holen und in die Monitorframeliste um- */ +/* haengen. Entsprechend dem Frameinhalt ggf. Timer 1 starten. */ +/* */ +/*----------------------------------------------------------------------*/ +void +l2tx(void) +{ + WORD port; /* Laufindex */ + LHEAD *llp; + int n; + + for (llp = &l2actl[port = 0]; /* alle Ports durchgehen */ + port < L2PNUM; + port++, llp++) + { + if (busy(port)) + continue; /* Port ist noch blockiert */ + if (dama(port)) + continue; /* nicht senden auf DAMA-Ports */ +#ifdef DAMASLAVE + if (damaslaveon(port)) + continue; /* nicht senden auf DAMA-Slave-Ports */ +#endif + + for (lnkpoi = (LNKBLK *)llp->head; + lnkpoi != (LNKBLK *)llp; /* alle Links des Ports pruefen */ + lnkpoi = lnkpoi->next) + { + if (lnkpoi->RStype != L2CREJ) /* REJ nicht durch I ersetzen */ + { + if (lnkpoi->flag & L2FREPEAT) + sdoi(); + else + if ((n = itxwnd()) > 0) /* darf ich ueberhaupt noch was? */ + sdi(outsdI(), n); /* Frames generieren (mit clrT2) */ + } + } + } +} + +/************************************************************************/ +/* */ +/* Gesendetliste aufraeumen */ +/* */ +/************************************************************************/ +void +clrstfl(void) +{ + MBHEAD *sfbp; /* Sendeframebufferpointer */ + + while ((sfbp = (MBHEAD *)stfl.head) != (MBHEAD *)&stfl) + { + ulink((LEHEAD *)sfbp); /* Frame holen */ + if ((sfbp->l2fflg & L2FT1ST) != FALSE) /* ist T1 zu starten ? */ + { + lnkpoi = sfbp->l2link; /* Zeiger auf Linkblock */ + setT1(); /* T1 starten */ + } + sfbp->tx = 1; + if (takfhd(sfbp)) + monitor(sfbp); + dealmb(sfbp); + } +} + +/************************************************************************/ +/* */ +/* Frame-Reject Frame aufbauen und senden */ +/* */ +/************************************************************************/ +void +sdfrmr(char ZYXW) +{ + UBYTE *frmrip; + + if (lnkpoi->state >= L2SIXFER && lnkpoi->state != L2SHTH) + { + frmrip = lnkpoi->frmr; +#ifdef EAX25 + /* EAX.25-FRMR aufbauen */ + if (lnkpoi->bitmask == 0x7F) + { + *frmrip++ = rxfctl; + if ((rxfctl & 0x03) == 3) + *frmrip++ = 0; + else + *frmrip++ = rxfctlE; + + *frmrip++ = (lnkpoi->VS << 1) & 0xFE; + *frmrip++ = (lnkpoi->VR << 1) | (!rxfCR ? 0x1 : 0x0); + *frmrip = ZYXW; + } + else + { +#endif + /* AX.25-FRMR aufbauen */ + *frmrip++ = rxfctl | rxfPF; + *frmrip++ = (lnkpoi->VR << 5) + | (!rxfCR ? 0x10 : 0) + | (lnkpoi->VS << 1); + *frmrip = ZYXW; +#ifdef EAX25 + } +#endif +#if MAX_TRACE_LEVEL > 0 +/***DEBUG***/ + notify(1, "Frame rejected %6.6s->%6.6s VS=%u ltxdNR=%u VR=%u" + " lrxdNR=%u error=%u state=%u", + lnkpoi->srcid, lnkpoi->dstid, + lnkpoi->VS, lnkpoi->ltxdNR, + lnkpoi->VR, lnkpoi->lrxdNR, + ZYXW, lnkpoi->state); +/***DEBUG***/ +#endif + clrT1(); /* Timer stoppen */ + clrT2(); + lnkpoi->RTT = 0; + l2stma(stbl27); /* INVALID N(R) RECEIVED */ + } +} + +/************************************************************************/ +/* */ +/* "xmit null" */ +/* */ +/* Nichts tun. Leerfunktion fuer die Statetable. */ +/* */ +/************************************************************************/ +void +xnull(void) +{ +} + +/************************************************************************/ +/* */ +/* "xmit RR command" */ +/* */ +/* RR als Command senden. */ +/* */ +/************************************************************************/ +void +xrrc(void) +{ + stxcfr(); + sendS(L2CRR); +} + +/************************************************************************/ +/* */ +/* "xmit RR response" */ +/* */ +/* RR als Response senden. */ +/* */ +/************************************************************************/ +void +xrrr(void) +{ + sendS(L2CRR); +} + +/************************************************************************/ +/* */ +/* "xmit RNR command" */ +/* */ +/* REJ als Command senden. */ +/* */ +/************************************************************************/ +void +xrnrc(void) +{ + stxcfr(); + xrnrr(); +} + +/************************************************************************/ +/* */ +/* "xmit RNR response" */ +/* */ +/* RNR als Response senden. */ +/* */ +/************************************************************************/ +void +xrnrr(void) +{ + sendS(L2CRNR); +} + +/************************************************************************/ +/* */ +/* "xmit REJ response" */ +/* */ +/* REJ als Response senden. */ +/* */ +/************************************************************************/ +void +xrejr(void) +{ + sendS(L2CREJ); +} + +/************************************************************************/ +/* */ +/* "send supervisory frame" */ +/* */ +/* Ein Supervisory-Frame aufbauen, Timer 2 loeschen und das Frame */ +/* an den aktuellen Link senden. */ +/* */ +/************************************************************************/ +void +sendS(UBYTE control) +{ + clrT2(); + +#ifdef __WIN32__ + txfctl = (unsigned char)setNR(control); +#else + txfctl = setNR(control); +#endif /* WIN32 */ +#ifdef EAX25 + /* Kontrollbytes fuer EAX.25 aufbauen bzw. umbauen */ + if (lnkpoi->bitmask == 0x7F) + { + txfctl &= 0x0F; /* erstes Kontrollbyte aendern */ + txfctlE = (lnkpoi->VR << 1) | (txfPF >> 4); /* V(R) und Pollflag */ + txfEAX = TRUE; + } +#endif + + sdl2fr(makfhd((!txfCR ? L2FUS : L2FUS | L2FT1ST)), FALSE); +} + +/************************************************************************/ +/* */ +/* "xmit DM" */ +/* */ +/* Ein DM-Frame generieren und an die aktuelle Adresse (txf...) */ +/* senden. */ +/* */ +/************************************************************************/ +void +xdm(void) +{ + txfctl = L2CDM; + sdl2fr(makfhd(L2FUS), TRUE); +} + +/************************************************************************/ +/* */ +/* "xmit UA" */ +/* */ +/* Ein UA-Frame generieren und an die aktuelle Adresse (txf...) */ +/* senden. */ +/* */ +/************************************************************************/ +void +xua(void) +{ + txfctl = L2CUA; + sdl2fr(makfhd(L2FUS), TRUE); +} + +/************************************************************************/ +/* */ +/* "xmit SABM" */ +/* */ +/* Ein SABM-Frame generieren und an die Adresse des aktuellen Linkblock */ +/* senden. */ +/* */ +/************************************************************************/ +void +xsabm(void) +{ + stxcfr(); +#ifdef EAX25 + /* bei gewuenschter EAX.25-Verbindung je nach Porteinstellung einen */ + /* anderen Kopf aufbauen */ + + /* Modus bestimmen je nach Einstellung des Ports */ + switch (portpar[lnkpoi->liport].eax_behaviour) + { + /* EAX.25 auf diesem Port nicht erlaubt */ + case 0: lnkpoi->bitmask = 0x07; + break; + + /* EAX.25 auf diesem Port ist zwingend !!! */ + case 3: lnkpoi->bitmask = 0x7F; + break; + + /* EAX.25 auf diesem Port nach MHeard-Tabelle */ + default: break; + } + + if (lnkpoi->bitmask == 0x7F) + txfctl = L2CSABME; + else +#endif + txfctl = L2CSABM; + +#ifdef RTTSTART_MOD + { + PEER *pSeg; + PEER *peertab = netp->peertab; /* Segment-Tabelle */ + + /* Segment-Tabelle durchgehen. */ + for (pSeg = peertab; pSeg < &peertab[netp->max_peers]; pSeg++) + { + if (!pSeg->used) /* Unbenutzte Eintraege, */ + continue; /* zum naechsten. */ + + if (cmpid(pSeg->l2link->call, lnkpoi->dstid)) /* Callvergleich. */ + pSeg->rttstart = tic10; /* Zeitmessung starten. */ + } + } +#endif /* RTTSTART_MOD */ + + sdl2fr(makfhd((L2FUS | L2FT1ST)), FALSE); +} + +/************************************************************************/ +/* */ +/* "xmit DISC" */ +/* */ +/* Ein DISC-Frame generieren und an die Adresse des aktuellen Linkblock */ +/* senden. */ +/* */ +/************************************************************************/ +void +xdisc(void) +{ + stxcfr(); + txfctl = L2CDISC; + sdl2fr(makfhd((L2FUS | L2FT1ST)), FALSE); +} + +/************************************************************************/ +/* */ +/* "xmit FRMR" */ +/* */ +/* FRMR-Frame generieren und mit der RIP-Information aus dem Linkblock */ +/* fuellen. */ +/* */ +/************************************************************************/ +void +xfrmr(void) +{ + UBYTE *frmrip; + MBHEAD *fbp; + + stxfad(); + txfctl = L2CFRMR; + fbp = makfhd((L2FUS | L2FT1ST)); + frmrip = lnkpoi->frmr; +#ifdef EAX25 + /* EAX.25 FRMR ist zwei Bytes laenger */ + if (lnkpoi->bitmask == 0x7F) + { + putchr(*frmrip++, fbp); + putchr(*frmrip++, fbp); + } +#endif + putchr(*frmrip++, fbp); + putchr(*frmrip++, fbp); + putchr(*frmrip, fbp); + sdl2fr(fbp, TRUE); +} + +/************************************************************************/ +/* */ +/* "set tx command frame" */ +/* */ +/* TX-Frame-Adressierung setzen (siehe stxfad()) und Frame zum */ +/* Kommandoframe machen mit gesetztem Pollbit (txfCR, txfPF). */ +/* */ +/************************************************************************/ +void +stxcfr(void) +{ + stxfad(); /* Adressierung */ + txfCR = L2CCR; /* Command! */ +#ifdef DAMASLAVE + if (damaslaveon(txfprt)) /* Slave darf nicht pollen */ + txfPF = 0; + else +#endif + txfPF = L2CPF; /* Pollbit! */ +} + +/************************************************************************/ +/* */ +/* "set tx frame address" */ +/* */ +/* Adressierung des aktuellen Sendeframes (txfhdr, txfprt) setzen aus */ +/* den im aktuellen Linkblock (lnkpoi) gegebenen Parametern (srcid, */ +/* destid, viaidl, liport). */ +/* */ +/************************************************************************/ +void +stxfad(void) +{ + cpyid(txfhdr + L2IDLEN, lnkpoi->srcid); /* von ... */ + + /* + * DAMA-Bit loeschen, wenn DAMA-Betrieb (geloeschtes Bit = DAMA !) + */ + if (dama(lnkpoi->liport)) + txfhdr[L2ILEN - 1] &= ~L2CDAMA; + +#ifdef EAX25 + if (lnkpoi->bitmask == 0x7F) + txfhdr[L2ILEN - 1] &= ~L2CEAX; +#endif + + cpyid(txfhdr, lnkpoi->dstid); /* nach ... */ + cpyidl(txfhdr + L2ILEN, lnkpoi->viaidl); /* ueber ... */ + + txfprt = lnkpoi->liport; /* auf Port ... */ +} + +/************************************************************************/ +/* */ +/* "set NR" */ +/* */ +/* Im aktuellen Linkblock (lnkpoi) die zuletzt gesendete N(R) (ltxdNR) */ +/* auf V(R) (VR) setzen und Framecontrolbyte control fuer Frameaus- */ +/* sendung mit der N(R) versehen und zurueckgeben. */ +/* */ +/* Return : control mit N(R) versehen */ +/* */ +/************************************************************************/ + +UBYTE +setNR(UBYTE control) +{ + lnkpoi->ltxdNR = lnkpoi->VR; /* neue N(R) */ + return (((lnkpoi->VR << 5) | control)); /* N(R) ins Kontrollfeld */ +} + +/************************************************************************/ +/* */ +/* "send level 2 frame" */ +/* */ +/* Framebuffer, auf dessen Kopf fbp zeigt, rewinden und in die dem Port */ +/* (l2port) entsprechende Level-2-Sendeframeliste einhaengen, wenn noch */ +/* genug Buffer im System frei sind. Andernfalls nicht senden, sondern */ +/* sofort in die Gesendet-Liste (stfl) einhaengen. */ +/* */ +/************************************************************************/ +void +sdl2fr(MBHEAD *fbp, BOOLEAN send_immediately) +{ + UBYTE port; /* Portnummer */ + +#ifndef __WIN32__ + port = fbp->l2port; /* Portnummer holen */ +#else + port = (unsigned char)fbp->l2port; /* Portnummer holen */ +#endif /* WIN32 */ + + if (nmbfre > 14 && portenabled(port)) /* noch genug Buffer und Port */ + { /* eingeschaltet? */ + rwndmb(fbp); /* ja - Framebuffer rewinden */ + /* Frame in Sendeliste */ +#ifdef L1TCPIP + /* TCPIP-Frames haben hier nix zu suchen. */ + if (CheckPortTCP((UWORD)port)) + { + /* Frame entsorgen. */ + dealmb(fbp); + return; + } +#endif /* L1TCPIP */ + + if ( dama(port) /* DAMA-Frames werden in timDAMA gesendet */ +#ifdef DAMASLAVE + || damaslaveon(port) /* DAMA-Slave-Frames auch */ +#endif + ) + { + if (send_immediately == FALSE) + relink((LEHEAD *)fbp, (LEHEAD *)(lnkpoi->damail.tail)); + else + relink((LEHEAD *)fbp, (LEHEAD *)&damarl[port]); + return; + } + relink((LEHEAD *)fbp, (LEHEAD *)txl2fl[port].tail); + kicktx(port); /* es ist was zu senden ! */ + } + else /* kein Platz oder Port aus - Frame als gesendet betrachten */ + { + relink((LEHEAD *)fbp, (LEHEAD *)stfl.tail); + } +} + +/************************************************************************/ +/* */ +/* "make frame header" */ +/* */ +/* Die Header-Daten aus "txf.." werden in einen Buffer geschrieben. */ +/* Sie wurden entweder von getfhd() aus dem Empfangsframe durch */ +/* Spiegelung generiert oder aus dem Linkblock gesetzt. */ +/* */ +/************************************************************************/ +MBHEAD * +makfhd(int fflag) +{ + MBHEAD *fbp; + + txfhdr[L2IDLEN - 1] |= txfCR; + txfhdr[L2ILEN - 1] |= txfCR ^ L2CCR; + + putfid(txfhdr, fbp = (MBHEAD *)allocb(ALLOC_MBHEAD)); + + if (dama(txfprt)) + txfhdr[L2ILEN - 1] &= ~L2CDAMA; + +#ifdef EAX25 + if ((txfEAX == TRUE) && ((txfctl & 0x03) != 0x03)) + txfhdr[L2ILEN - 1] &= ~L2CEAX; + else + txfhdr[L2ILEN - 1] |= L2CEAX; +#endif + + putfid(txfhdr + L2IDLEN, fbp); + putvia(txfhdr + L2ILEN, fbp); + +#ifdef EAX25 + if ((txfEAX == TRUE) && ((txfctl & 0x03) != 0x03)) + { + putchr((UBYTE)(txfctl), fbp); + putchr((UBYTE)(txfctlE | (txfPF >> 4)), fbp); + txfEAX = FALSE; + } + else +#endif + putchr((UBYTE)(txfctl | txfPF), fbp); + + fbp->l2link = lnkpoi; + fbp->type = 2; + fbp->l2fflg = fflag; + fbp->l2port = txfprt; + fbp->repeated = 0; + return (fbp); +} + +/************************************************************************\ +* * +* "information to link" * +* * +* Infobuffer, auf den imbp zeigt, an in diesem Buffer festgelegten Link * +* (l2link) zwecks Aussendung als Paket weitergeben. Wenn nocgnc == TRUE * +* keine "Erstickungskontrolle", sonst conctl beachten (s.u.). * +* Der Infobuffer wird bei Weitergabe an den Link mit der normalen * +* Level 2 PID versehen, der Keine-Aktivitaets-Timer wird neu gestartet. * +* * +* Return: TRUE - imbp wurde angenommen und an den Link weitergegeben * +* FALSE - imbp wurde nicht angenommen wegen Congestion Control * +* = Grenze der pro Link maximal zu speichernden Pakete * +* (conctl) wuerde ueberschritten werden * +* * +\************************************************************************/ +BOOLEAN +itolnk(int pid, BOOLEAN nocgnc, MBHEAD *imbp) +{ + LNKBLK *linkp; +#if 0 + extern void coredump(void); +#endif + + linkp = imbp->l2link; + +/* DEBUG */ + if (linkp->state == L2SDSCED) + { + LNKBLK *l_bak; + + l_bak = lnkpoi; /* damit wir das im Dump sehen */ + lnkpoi = linkp; +#if MAX_TRACE_LEVEL > 2 + notify(1, "send to disc'ed link %6.6s > %6.6s via %s", + linkp->srcid, linkp->dstid, linkp->viaidl); +#endif +#if 0 + coredump(); +#endif + dealmb((MBHEAD *)ulink((LEHEAD *)imbp)); + lnkpoi = l_bak; + return (TRUE); + } + + if (linkp->state == L2SDSCRQ) + { + dealmb((MBHEAD *)ulink((LEHEAD *)imbp)); + return (TRUE); + } + + if (linkp->tosend < conctl || nocgnc == TRUE) + { + imbp->l2fflg = pid; /* PID uebernehmen */ + imbp->repeated = 0; + relink(ulink((LEHEAD *)imbp), /* -> ab in den Link */ + (LEHEAD *)linkp->sendil.tail); + ++linkp->tosend; /* ein Sendepaket mehr */ + +#ifndef THENETMOD + linkp->noatou = ininat; +#else /* L4TIMEOUT */ + linkp->noatou = SetL4Timeout(); /* L2/L4-Timeout setzen.*/ +#endif /* THENETMOD */ + return (TRUE); /* ... imbp angenommen */ + } + return (FALSE); /* ... imbp abgelehnt */ +} + +/************************************************************************\ +* * +* "number of outstanding I's" * +* * +* Anzahl der ausstehenden Info-Frames des aktuellen Linkblock (lnkpoi) * +* berechnen. * +* * +\************************************************************************/ +char +outsdI(void) +{ + return ((lnkpoi->VS - lnkpoi->lrxdNR) & lnkpoi->bitmask); +} + +/************************************************************************\ +* * +* "is tx window open" * +* * +* Kann der Sender des aktuellen Linkblocks noch Informationen aufnehmen? * +* Geliefert wird die Anzahl der Frames, die noch in das aktuelle Fenster * +* passen. * +* * +\************************************************************************/ +char +itxwnd(void) +{ + int outstd, + n, + k; + + if (lnkpoi->tosend) /* ueberhaupt was zu senden? */ + { + switch (lnkpoi->state) /* duerfen wir was senden? */ + { + case L2SIXFER: + case L2SRS: + case L2SDBS: + case L2SRSDBS: + outstd = outsdI(); /* soviel stehen noch aus */ + n = lnkpoi->tosend; /* und soviel ist noch uebrig */ + k = lnkpoi->maxframe; + if ( (outstd < k) /* Fenster noch nicht voll */ + && (n > outstd)) /* und Sendebuffer nicht leer */ + return (fullduplex(lnkpoi->liport) ? 1 : k); + } + } + return (0); /* senden momentan nicht erlaubt */ +} + +/************************************************************************\ +* * +* "send outstanding I's" * +* * +* Aus dem aktuellen Linkblock (lnkpoi) soviele I-Frames senden, wie im * +* Moment unbestaetigt ausstehen. * +* Es wird der komplette Durchgang wiederholt (ab dem 1. unbestaetigtem) * +* Frame. * +* WICHTIG: Nicht senden, wenn wir auf die Antwort der Gegenstation * +* warten (wir haben Poll gesendet). Dann kommt sowieso der * +* Final demnaechst und wir koennen weitersenden. * +* * +\************************************************************************/ +void +sdoi(void) +{ + UWORD n; /* Anzahl I's zu senden */ + int VS; + + switch (lnkpoi->state) /* nur wenn der State stimmt */ + { + case L2SIXFER: + case L2SRS: + case L2SDBS: + case L2SRSDBS: + if ((n = outsdI()) != 0) /* wieviel darf ich? */ + { + VS = lnkpoi->VS; + lnkpoi->VS = lnkpoi->lrxdNR; /* V(S) resetten */ + sdi(0, n); /* I's senden */ + lnkpoi->VS = VS; + } + lnkpoi->flag &= ~L2FREPEAT; + break; + } +} + +/************************************************************************\ +* * +* "send I" * +* * +* Aus dem aktuellen Linkblock (lnkpoi) maximal max I-Frames aus der * +* Infomessageliste aufbauen und senden. Die Frames werden als Command- * +* frames ohne Poll/Final-Bit gesendet. V(S) wird fuer jedes gesendete * +* Frame erhoeht modulo 7. Timer 2 wird abgeschaltet. * +* * +\************************************************************************/ +void +sdi(int outstd, int max) +{ + WORD n, + m, + k; /* Zaehler zu sendende Infos */ + MBHEAD *sendip; /* Kopfzeiger Infobuffer */ + MBHEAD *fbp; /* Kopfzeiger Framebuffer */ + + sendip = (MBHEAD *)lnkpoi->sendil.head; /* erstes Frame */ + for (n = 0; n < outstd; n++) + sendip = (MBHEAD *)sendip->nextmh; /* soviele uebergehen */ + + if (max > lnkpoi->tosend - outstd) /* maximal soviel wie da ist */ + max = lnkpoi->tosend - outstd; + + k = lnkpoi->maxframe; + + if (max + outstd > k) /* und nicht uebers Fenster */ + max = outstd < k + ? k - outstd /* Rest bis zum Fensterende */ + : 0; /* Fenster wurde verkleinert */ + + for (n = 1; + n <= max; /* aus der Linkblock- */ + ++n, sendip = (MBHEAD *)sendip->nextmh) /* infoliste senden */ + { /* wenn vorhanden */ + stxfad(); /* Frameadresse aufbauen */ + txfCR = L2CCR; /* Command! */ + +#ifdef EAX25 + /* EAX.25-Kontrollbytes setzen */ + if (lnkpoi->bitmask == 0x7F) + { + txfctl = (lnkpoi->VS << 1) & 0xFE; /* Controlbyte 1 setzen */ + txfctlE = (lnkpoi->VR << 1) & 0xFE; /* Controlbyte 2 setzen */ + lnkpoi->ltxdNR = lnkpoi->VR; /* neue N(R) */ + txfEAX = TRUE; + } + else + { +#endif + /* AX.25-Kontrollbyte setzen */ +#ifdef __WIN32__ + txfctl = (unsigned char)setNR((char)(lnkpoi->VS << 1)); /* Controlbyte I setzen */ +#else + txfctl = setNR((char)(lnkpoi->VS << 1)); /* Controlbyte I setzen */ +#endif /* WIN32 */ +#ifdef EAX25 + } +#endif + ++lnkpoi->VS; /* V(S) erhoehen */ + lnkpoi->VS &= lnkpoi->bitmask; /* modulo */ + + txfPF = 0; /* normalerweise ohne POLL */ + if ( (((lnkpoi->lrxdNR + k) & lnkpoi->bitmask) == lnkpoi->VS) + || (lnkpoi->tosend == outsdI())) + { + if (dama(lnkpoi->liport)) + txfPF = L2CPF; /* letztes Frame mit POLL! */ + fbp = makfhd(L2FT1ST); /* Ja, T1 und RTT Zeitmessung */ + } + else + fbp = makfhd(0x00); /* Nein, T1/RTT nicht starten */ + + fbp->repeated = sendip->repeated; + putchr(sendip->l2fflg, fbp); /* Frame aufbauen, PID */ + + /* + * Frame aufspalten, wenn zu lang. Gesplittet werden aber nur + * Frames mit Standard-AX.25-PID (ohne L3-Protokoll). Die maximale + * Laenge ist 256 Bytes bzw. wenn niedriger der MTU-Wert fuer den + * jeweiligen Port. + */ + if (sendip->l2fflg == L2CPID) +#ifdef PORT_MANUELL + m = portpar[lnkpoi->liport].paclen; +#else + m = L2MILEN; /* Fest auf 256 Bytes begrenzen */ +#endif /* PORT_MANUELL */ + else + m = min(L2MILEN, portpar[lnkpoi->liport].mtu); + + if (splcpy(m, fbp, sendip) == TRUE) /* Ein Frame mehr zu senden */ + ++lnkpoi->tosend; + +#ifdef MAXFRAMEDEBUG + fbp->lnkflag = lnkpoi->flag; + fbp->lmf = lnkpoi->maxframe; +#ifdef EAX25 + if (lnkpoi->bitmask == 0x7F) +#ifdef __WIN32__ + fbp->pmf = (unsigned char)portpar[lnkpoi->liport].maxframe_eax; +#else + fbp->pmf = portpar[lnkpoi->liport].maxframe_eax; +#endif /* WIN32 */ + else +#endif +#ifdef __WIN32__ + fbp->pmf = (unsigned char)portpar[lnkpoi->liport].maxframe; +#else + fbp->pmf = portpar[lnkpoi->liport].maxframe; +#endif /* WIN32 */ + fbp->tosend = lnkpoi->tosend; +#endif + + sdl2fr(fbp, FALSE); /* Frame senden */ + ++sendip->repeated; /* Frame wird ggf. wiederholt gesendet */ + clrT2(); /* Timer 2 abschalten */ + } +} + +/************************************************************************\ +* * +* "send UI" * +* * +* UI-Frame aufbauen und senden. Das UI-Frame wird an ID dest geschickt * +* ueber den Port port und die via-Liste (nullterminiert) vial, als * +* Quelle wird source genommen, die Infobytes des Frames stehen im * +* Messagebuffer, auf dessen Kopf mbhd zeigt, die PID wird aus l2fflg * +* dieses Buffers genommen. * +* * +\************************************************************************/ +void +sdui(const char *vial, const char *dest, const char *source, char port, + MBHEAD *mbhd) +{ + MBHEAD *fbp; + +#ifdef L1TCPIP + /* TCPIP-Frames haben hier nix zu suchen. */ + if (CheckPortTCP((UWORD)port)) + return; +#endif /* L1TCPIP */ + + cpyid(txfhdr + L2IDLEN, source); + cpyid(txfhdr, dest); + cpyidl(txfhdr + L2ILEN, vial); + txfprt = port; + txfCR = L2CCR; +#ifndef UIPOLLFIX + txfPF = 0; +#else + txfPF = L2CPF; +#endif /* UIPOLLFIX */ + txfctl = L2CUI; + putchr(mbhd->l2fflg, fbp = makfhd(0)); + + while (mbhd->mbgc < mbhd->mbpc) + putchr(getchr(mbhd), fbp); + + sdl2fr(fbp, TRUE); +} + +#ifdef IPOLL_FRAME +void sdipoll() + { + static MBHEAD *sendip; /* Kopfzeiger Infobuffer */ + static MBHEAD *fbp; /* Kopfzeiger Framebuffer */ + + sendip = (MBHEAD *)lnkpoi->sendil.head; + stxfad(); /* Frameadresse aufbauen */ + if ( sendip->mbpc < portpar[lnkpoi->liport].ipoll_paclen /* FEF wird's ein IPoll ? */ + && lnkpoi->tries < portpar[lnkpoi->liport].ipoll_retry + && lnkpoi->tosend) + { + txfCR = L2CCR; /* Command ! */ + txfPF = L2CPF; /* Poll/Final ! */ +#ifdef __WIN32__ + txfctl = setNR((UBYTE)(lnkpoi->lrxdNR << 1)); /* Controlbyte I wie zuvor */ +#else + txfctl = setNR(lnkpoi->lrxdNR << 1); /* Controlbyte I wie zuvor */ +#endif /* WIN32 */ + putchr(sendip->l2fflg, /* Frame aufbauen, PID */ + fbp = makfhd(L2FT1ST)); + splcpy(256,fbp,sendip); /* Message umkopieren */ + sdl2fr(fbp, FALSE); /* Frame senden */ + clrT2(); /* Timer 2 abschalten */ + clrT3(); /* Timer 3 abschalten */ + } + else /* FEF Nein, kein Ipoll... */ + xrrc(); /* FEF ... RR+ senden */ + } +#endif /* IPOLL_FRAME */ + +/* End of src/l2tx.c */ diff --git a/src/l3inp.c b/src/l3inp.c new file mode 100755 index 0000000..d532e7e --- /dev/null +++ b/src/l3inp.c @@ -0,0 +1,701 @@ +/************************************************************************/ +/* */ +/* ***** ***** */ +/* ***** ***** */ +/* ***** ***** */ +/* ***** ***** */ +/* *************** *************** */ +/* ***************** ***************** */ +/* *************** *************** */ +/* ***** ***** TheNetNode */ +/* ***** ***** Portable */ +/* ***** ***** Network */ +/* ***** ***** Software */ +/* */ +/* File src/l3inp.c (maintained by: ???) */ +/* */ +/* This file is part of "TheNetNode" - Software Package */ +/* */ +/* Copyright (C) 1998 - 2008 NORD>max_peers; + unsigned int i = 0; + + for (pp = netp->peertab; i < max_peers; i++, pp++) + { + if (!pp->used) /* nur benutzte Eintraege */ + continue; + if (pp->typ != INP) /* nur INP-Links */ + continue; + rp = pp->routes + index; /* Zeiger auf Route */ + + if (rp->reported_quality) /* nur wenn wir gemeldet hatten */ + rp->reported_quality = DIRTY; + } +} + +/************************************************************************/ +/* */ +/* Auswertung von empfangenen INP-Routinginformationen */ +/* */ +/************************************************************************/ +BOOLEAN +rx_inp_broadcast(PEER *rxpp, MBHEAD *mbp) +{ + char desnod[L2IDLEN]; /* Callsign */ + char beaide[L2CALEN], /* Alias */ + *bp; + + UBYTE uHopCounter; /* Hops */ + UWORD uTransportTime; /* Laufzeit */ + UBYTE uOptionCode; /* Optionscode */ + UBYTE uOptionLength; /* Optionslaenge */ + UBYTE uOptionData[256]; /* Daten der INP-Option */ + MBHEAD *pOptions; /* Optionszeiger */ + + ULONG uIP_Adr; /* IP-Adresse */ + UBYTE uBits; /* Subnetz-Bits */ + + int i; + UBYTE ch; + PEER *pp; + INDEX index; + + BOOLEAN bValid; /* Eintrag verwendbar ? */ + +#if MAX_TRACE_LEVEL > 0 + char notify_call1[10]; +#if MAX_TRACE_LEVEL > 2 + char notify_call2[10]; +#endif +#endif + + if (*mbp->mbbp != INP_RIF) /* Kennung INP-Routing-Paket? */ + return (FALSE); /* Nein, dann Puffer ungelesen zurueckgeben */ + + getchr(mbp); /* RIF-Kenner uebergehen */ + + /* Ist noch mind. ein RIP (ohne Optionen) im RIF ? */ + /* (Call + Hop + Time + EOP = 7 + 1 + 2 + 1 = 11) */ + while ((mbp->mbpc - mbp->mbgc) > 10) + { + /* Nodeseintrag lesen ggf. incl. Alias, IP-Nr./Subnet und anderen */ + /* INP-Options. Fehler werden zunaechst ignoriert. */ + bValid = TRUE; /* Eintrag gueltig */ + cpyals(beaide, DONT_CHANGE_ALIAS); /* Default: kein Alias */ + uIP_Adr = 0L; /* und keine IP-Adresse */ + uBits = 0; /* keine IP-Subnetzbits */ + pOptions = NULL; /* sowie keine Options */ + uHopCounter = 0; /* Hop Counter */ + uTransportTime = 0; /* Laufzeit */ + memset(desnod, 0, sizeof(desnod)); /* Noch kein Zielknoten */ + + if (!getfidc(desnod, mbp)) /* Call holen */ + bValid = FALSE; /* Eintrag ungueltig */ + + if (valcal(desnod) == ERRORS) /* Call gueltig ? */ + bValid = FALSE; /* Eintrag ungueltig */ + + uHopCounter = getchr(mbp); /* Hop-Counter lesen */ + uTransportTime = get16(mbp); /* Laufzeit lesen */ + + if (uHopCounter == 0) /* HopCount 0 darf nie gesendet werden, */ + uHopCounter = DEFAULT_LT; /* korrigieren */ + else + ++uHopCounter; /* Hop-Counter erhoehen */ + + /* Endekriterium fuer den Nodeseintrag ist das EOP-Byte (0x00) */ + /* des RIP-Blocks. Danach koennen weitere Nodeseintraege folgen. */ + while (mbp->mbpc > mbp->mbgc) + { + /* Einzelnen Options-Eintrag lesen und auswerten */ + /* Laenge der Option holen */ + uOptionLength = getchr(mbp); + + if (uOptionLength == INP_EOP) /* EOP ? */ + break; /* alle Optionen gelesen */ + + --uOptionLength; /* Laengenbyte von der Optionslaenge abziehen */ + + /* Sind noch genug Zeichen da ? */ + if ((mbp->mbpc - mbp->mbgc) < uOptionLength) /* INP-Fehler! */ + { + /* Der Fehler wird gemeldet, die fehlerhaften Options werden */ + /* komplett verworfen, damit wir keinen Muell weitermelden. */ +#if MAX_TRACE_LEVEL > 0 + call2str(notify_call1, rxpp->l2link->call); + notify(1, "INP: frame error received from %s, " + "len = %u, left = %u", notify_call1, uOptionLength, + (UWORD)(mbp->mbpc - mbp->mbgc)); +#endif + /* Unbekannte Optionen ? Dann diese loeschen */ + if (pOptions != NULL) + { + dealmb(pOptions); + pOptions = NULL; + } + + /* nicht zu gebrauchen */ + bValid = FALSE; + + break; + } + + uOptionCode = getchr(mbp); /* Optionstyp holen */ + --uOptionLength; /* Typenfeld von der Optionslaenge abziehen */ + + /* Daten der Option holen */ + memset(uOptionData, 0, sizeof(uOptionData)); + for (i = 0; i < uOptionLength; ++i) + uOptionData[i] = getchr(mbp); + + /* Option bestimmen */ + switch (uOptionCode) + { + /* Alias */ + case INP_ALIAS: + + /* Laengencheck */ + if (uOptionLength > L2CALEN) + { +#if MAX_TRACE_LEVEL > 2 + call2str(notify_call1, rxpp->l2link->call); + notify(3, "alias from %s too long (cut)", notify_call1); +#endif + } + + /* Alias kopieren und checken */ + for (i = 0, bp = beaide; (i < uOptionLength) && (i <= L2CALEN); ++i) + { + ch = uOptionData[i]; + + /* Pruefung auf ungueltige Zeichen */ + if ((ch < ' ') || (ch > 127)) + { +#if MAX_TRACE_LEVEL > 2 + call2str(notify_call1, rxpp->l2link->call); + notify(3, "invalid alias from %s (flushed)", notify_call1); +#endif + /* Unbekannte Optionen loeschen wenn vorhanden */ + if (pOptions != NULL) + { + dealmb(pOptions); + pOptions = NULL; + } + + /* nicht zu gebrauchen */ + bValid = FALSE; + } + + /* Zeichen gueltig, uebernehmen */ + *bp++ = ch; + } + + /* Der Nachbar posaunt seine Secrets durch die Gegend ... */ + if (beaide[0] == '#') + { +#if MAX_TRACE_LEVEL > 2 + call2str(notify_call1, rxpp->l2link->call); + call2str(notify_call2, desnod); + notify(3, "%s sent secret node %s", notify_call1, notify_call2); +#endif + /* XNet hat (derzeit ?) einen Fehler, der Nodes mit Geheim-Aliassen */ + /* sendet. Da diese Nodes nicht wirklich geheim sind nehmen wir sie */ + /* trotzdem, loeschen aber ihre Aliasse. */ + if ( (strncasecmp(&beaide[1], "temp", 4) == 0) + || (strncasecmp(&beaide[1], "tmp", 3) == 0) + ) + { + /* fehlerhaften Alias loeschen */ + cpyals(beaide, DONT_CHANGE_ALIAS); /* Alias loeschen */ + i = L2CALEN; /* brauchen wir nicht mehr auffuellen */ +#if MAX_TRACE_LEVEL > 2 + notify(3, "not real secret node, corrected"); +#endif + } + else + { + /* Ein echter Secret Node, normal behandeln (loeschen) */ + if (pOptions != NULL) + { + dealmb(pOptions); + pOptions = NULL; + } +#if MAX_TRACE_LEVEL > 2 + notify(3, "secret node flushed"); +#endif + /* Eintrag ist nicht zu gebrauchen */ + bValid = FALSE; + } + } + + for (; i < L2CALEN; ++i) /* auffuellen mit ' ' */ + *bp++ = ' '; + + break; + + /* IP-Adresse */ + case INP_IPA: + + /* Option lang genug ? */ + if (uOptionLength == 5) + { + /* IP-Adresse lesen */ + uIP_Adr = uOptionData[0] << 24; + uIP_Adr |= uOptionData[1] << 16; + uIP_Adr |= uOptionData[2] << 8; + uIP_Adr |= uOptionData[3]; + + /* Hostbits lesen */ + uBits = uOptionData[4]; + } + else + { +#if MAX_TRACE_LEVEL > 2 + call2str(notify_call1, rxpp->l2link->call); + notify(3, "invalid ipa-length %u from %s (flushed)", uOptionLength, notify_call1); +#endif + if (pOptions != NULL) + { + dealmb(pOptions); + pOptions = NULL; + } + + bValid = FALSE; + } + + /* Rudimentaerer Check der Subnetz-Bits, sind diese falsch */ + /* wird die IP fuer diesen Node nicht uebernommen, die IP */ + /* wird an anderer Stelle je nach Einstellung ueberprueft */ + if ((uBits == 0) || (uBits > 32)) + { + uIP_Adr = 0L; + uBits = 0; +#if MAX_TRACE_LEVEL > 2 + call2str(notify_call1, desnod); + notify(3, "invalid subnet-bits for %s, ip not stored", notify_call1); +#endif + } + break; + + /* unbekannte Option - in Buffer speichern */ + default: + /* Buffer besorgen wenn nicht schon geschehen */ + if (pOptions == NULL) + pOptions = (MBHEAD *)allocb(ALLOC_INPOPT); + + /* Option speichern */ +#ifdef __WIN32__ + putchr((char)(uOptionLength + 2), pOptions); /* Laenge */ +#else + putchr(uOptionLength + 2, pOptions); /* Laenge */ +#endif /* WIN32 */ + putchr(uOptionCode, pOptions); /* Typ */ + + for (i = 0; i < uOptionLength; ++i) /* Daten */ + putchr(uOptionData[i], pOptions); + } /* switch (uOptionCode) */ + } /* while (mbp->mbpc > mbp->mbgc) */ + + /* Hat der Nachbar mich selbst gemeldet ? */ + if (cmpid(myid, desnod) || iscall(desnod, NULL, NULL, VC)) + { +#if MAX_TRACE_LEVEL > 2 + call2str(notify_call1, myid); + call2str(notify_call2, rxpp->l2link->call); + notify(3, "destination %s received from %s (ignored)", + notify_call1, notify_call2); +#endif + if (pOptions != NULL) + { + dealmb(pOptions); + pOptions = NULL; + } + continue; + } + +#if MAX_TRACE_LEVEL > 8 + call2str(notify_call1, rxpp->l2link->call); + call2str(notify_call2, desnod); + notify(9, "%-9.9s>%-6.6s:%-9.9s Time:%u Hops:%u Valid:%u", + notify_call1, beaide, notify_call2, uTransportTime, uHopCounter, + (bValid == TRUE ? 1 : 0)); + + /* IP-Adresse */ + if (uIP_Adr != 0L) + notify(9, "IP:%u.%u.%u.%u/%u", + (uIP_Adr >> 24) & 0xFF, + (uIP_Adr >> 16) & 0xFF, + (uIP_Adr >> 8) & 0xFF, + uIP_Adr & 0xFF, + uBits); + + if (pOptions) + notify(9, "unknown options: %u bytes", pOptions->mbpc); +#endif + + /* Erhaltenen Eintrag pruefen */ + if (uHopCounter > max_lt) /* Nach Lifetime runterzwingen */ + { + uTransportTime = 0; /* Knoten nicht annehmen */ + bValid = FALSE; + } + + if (cmpid(rxpp->l2link->call, desnod)) /* der Nachbar selbst */ + { + uTransportTime = 1; /* 10ms auf die Linklaufzeit */ + uHopCounter = 1; /* immer ein Hop entfernt */ + } + + /* Den Node in der Nodetabelle suchen, ist er schon vorhanden dann */ + /* wird der Eintrag geupdated, ansonsten neu angelegt. */ + if ((index = add_route(rxpp, desnod, uTransportTime)) != NO_INDEX) + { + /* Ziele mit diesen Laufzeiten sollen abgemeldet werden */ + if ((uTransportTime == 60000) || (uTransportTime == 0)) + update_lt(rxpp, index, 0); + else + /* alle anderen Laufzeiten normaler HopCounter */ + update_lt(rxpp, index, uHopCounter); + + /* Optionen nehmen wir nur vom primaeren Partner an, */ + /* haben wir noch keine, dann nehmen wir von jedem. */ + /* Haben wir schon optionale Infos ueber den Node ? */ + /* (Alias, IP-Adresse/Subnetzbits, sonstiges) */ + if ( (!cmpcal(netp->nodetab[index].alias, nulide)) + || (netp->nodetab[index].ipa != 0L) + ) + { + if (find_best_qual(index, &pp, DG) > 0) /* beste Qualitaet */ + { + if (pp != rxpp) /* bester Nachbar ist dieser ? */ + { + /* Nein, nicht bester Nachbar */ + if (pOptions != NULL) /* eventuelle Optionen loeschen */ + { + dealmb(pOptions); + pOptions = NULL; + } + bValid = FALSE; + } + } + } + + /* Der primaere Weg hat sich geaendert, wir uebernehmen Node-Info */ + /* sofern vorhanden (Alias, IP-Nr., Options). Wird keine Zusatzinfo */ + /* gemeldet, bleibt die bisher bekannte Info erhalten. */ + if ( (bValid == TRUE) + && (update_options(index, beaide, uIP_Adr, uBits, pOptions)) + ) + { + propagate_node_update(index); + pOptions = NULL; + } + } /* if (index = add_route(...) ... )*/ + } /* while (...) bis Frameende */ + + /* Wir waren erfolgreich */ + return (TRUE); +} + +/************************************************************************/ +/* */ +/* Uebernehmen neuer Zusatzinfos zu einem Node (Alias, IP-Nr./Subnet, */ +/* weitere unbekannte Options). Wird nichts gemeldet, bleiben bekannte */ +/* Daten gespeichert. Wird etwas neu gemeldet, muessen ALLE Daten neu */ +/* gemeldet werden. Alles was nicht mehr gemeldet wird, wird geloescht. */ +/* */ +/************************************************************************/ +static BOOLEAN +update_options(INDEX index, const char *alias, + ULONG ip_adr, UBYTE bits, MBHEAD *options) +{ + NODE *np; + BOOLEAN res = FALSE; + BOOLEAN ip_valid = TRUE; + int len; + char temp[1]; + ipaddr host; + + temp[0] = 0; /* damit arp_add() zufrieden ist */ + + if ( !cmpcal(alias, nulide) /* nur wenn ueberhaupt INP- */ + || ip_adr != 0L /* Options uebertragen wurden */ + || options != NULL) /* kann sich etwas aendern */ + { +/* Es wurden Options uebertragen - also muessen alle Options auf den */ +/* neuen Wert gesetzt werden, oder geloescht, falls nicht mehr gemeldet */ + np = netp->nodetab + index; + res = !cmpcal(np->alias, alias); + cpyals(np->alias, alias); + + if ( ip_adr != np->ipa + || bits != np->bits) + res = TRUE; + +/* ARP- und IPR-Eintrag erneuern */ +/* nur austragen wenn schon was eingetragen gewesen ist und die */ +/* automatische Modifikation erlaubt */ + if (np->ipa != 0L && autoipr != 0) + { + arp_drop(np->ipa, NETROM_PORT, TRUE); + rt_drop(np->ipa, np->bits, TRUE); + } + +/* neue Eintraege nur machen wenn nicht leer gemeldet und wir selber */ +/* eine IP-Adresse haben und wir das ueberhaupt duerfen (Param. 12) */ + if (ip_adr != 0L && my_ip_addr != 0L && autoipr != 0) + { +/* bevor wir die IP uebernehmen erst mal pruefen wenn wir das sollen */ + if (autoipr >= 2) + { +/* elementare Pruefung immer machen */ + if (((ip_adr & 0xFF) == 0L) || ((ip_adr & 0xFF) == 0xFF)) + ip_valid = FALSE; + +/* nur IPs uebernehmen, die im gleichen Netz sind */ + if ( (autoipr >= 3) + && ((ip_adr & 0xFF000000L) != (my_ip_addr & 0xFF000000L))) + ip_valid = FALSE; + } + + if (ip_valid) + { + arp_add(ip_adr, NETROM_PORT, np->id, temp, 0, 0, FALSE, TRUE); + host = ip_adr; + host >>= (32 - bits); + host <<= (32 - bits); + rt_add(host, bits, ip_adr, NETROM_PORT, 0, 0, 0, TRUE); + } + } + + np->ipa = ip_adr; + np->bits = bits; + + if (options == NULL) /* keine unbekannten Options? */ + { + if (np->options != NULL) /* war aber was bekannt? */ + { + dealmb(np->options); + np->options = NULL; + res = TRUE; + } + return (res); + } + + if (np->options == NULL) /* bisher nix bekannt */ + { + np->options = options; + return (TRUE); + } + + if ((len = options->mbpc) == np->options->mbpc) + { +/* alte und neue Options sind gleich lang - also vergleichen, ob sich */ +/* etwas geaendert hat (wir gehen mal davon aus, dass die Reihenfolge */ +/* unveraendert bleibt) */ + rwndmb(options); + rwndmb(np->options); + while (--len >= 0) + { + if (getchr(options) != getchr(np->options)) + break; + } + + if (len < 0) + { + dealmb(options); /* keine neuen Options */ + return (res); + } + } + dealmb(np->options); /* alte Options vergessen */ + np->options = options; /* neue merken */ + return (TRUE); /* Aenderung */ + } + + return (res); +} + +/************************************************************************/ +/* */ +/* "add internode protocol route information" */ +/* */ +/* Einen Weg zu dem Routing-Info-Frame fuer einen Nachbarn hinzufuegen. */ +/* Das Frame wird gesendet, sobald es voll ist oder in brosrv() wenn */ +/* der Timeout abgelaufen ist. */ +/* */ +/*----------------------------------------------------------------------*/ +void +add_inp_info(MBHEAD **mbpp, NODE *node, PEER *topp, unsigned qualit, + unsigned last_qualit, int lt) +{ + char buf[256], + *bp, + *bp2; + int len; + + bp = buf; + + /* Laufzeit 0 entspricht einer Abmeldung */ + if (qualit == 0) + qualit = HORIZONT; + + *bp++ = lt; /* Hops eintragen */ + *bp++ = qualit >> 8; /* Laufzeit eintragen */ + *bp++ = qualit & 0xFF; + + /* Wurde dieser Node schon mal gemeldet ? Falls ja, dann */ + /* die Optionen nicht noch einmal melden. Ausnahme ist nur, */ + /* wenn sich Daten geaendert haben. */ + if ( (qualit && last_qualit == 0) + || last_qualit == DIRTY) + { + /* Laenge des Alias feststellen */ + for (len = 0; len < L2CALEN; ++len) + if (node->alias[len] == ' ') + break; + + /* Alias uebernehmen */ + if (len != 0) + { + *bp++ = len + 2; /* Laenge */ + *bp++ = INP_ALIAS; /* Typ */ + + memcpy(bp, node->alias, (size_t)len); /* Daten */ + bp += len; + } + + /* IP-Adresse und Subnetzbits uebernehmen */ + if (node->ipa != 0L) + { + *bp++ = 7; /* Laenge */ + *bp++ = INP_IPA; /* Typ */ + + /* IP-Adresse und Subnetzbits eintragen */ +#ifdef __WIN32__ + *bp++ = (unsigned char)(node->ipa >> 24); + *bp++ = (unsigned char)((node->ipa >> 16) & 0xff); + *bp++ = (unsigned char)((node->ipa >> 8) & 0xff); + *bp++ = (unsigned char)(node->ipa & 0xff); +#else + *bp++ = node->ipa >> 24; + *bp++ = (node->ipa >> 16) & 0xff; + *bp++ = (node->ipa >> 8) & 0xff; + *bp++ = node->ipa & 0xff; +#endif /* WIN32 */ + *bp++ = node->bits; + } + + /* uns unbekannte Optionen anhaengen */ + if (node->options != NULL) + { + rwndmb(node->options); + while (node->options->mbpc > node->options->mbgc) + *bp++ = getchr(node->options); + } + } + + *bp++ = 0; /* Ende der Meldung (EOP) */ + len = (int)(bp - buf) + L2IDLEN; /* Laenge berechnen */ + + if (*mbpp) /* noch ein Buffer in Arbeit ? */ + if ((*mbpp)->mbpc + len > 256) /* passt nicht mehr ? */ + brosnd(mbpp, topp); /* dann senden */ + + /* war der Buffer voll so wurde er gesendet und entsorgt, */ + /* *mbpp ist jetzt NULL, das hat brosnd() erledigt */ + + if (*mbpp == NULL) /* noch kein Buffer besorgt */ + { /* neues I-Frame holen */ + (*mbpp = (MBHEAD *)allocb(ALLOC_MBHEAD))->l3_typ = L2CI; +#ifdef __WIN32__ + putchr((char)0xFF, *mbpp); /* Kennung (RIF) */ +#else + putchr(0xFF, *mbpp); /* Kennung (RIF) */ +#endif /* WIN32 */ + } + + putfid(node->id, *mbpp); + for (bp2 = buf; bp2 < bp; bp2++) + putchr(*bp2, *mbpp); +} + +/************************************************************************/ +/* */ +/* "send own node's inp beacon" */ +/* */ +/* Den direkten Nachbarn unsere Daten per INP mitteilen, z.B. nach */ +/* einem Linkaufbau, oder wenn sich unsere Daten (IP-Adresse oder */ +/* Subnetzbits) aendern. */ +/* */ +/*----------------------------------------------------------------------*/ +void send_inp_nodebeacon(PEER* pPeer) +{ + NODE node; + MBHEAD* inpmbp = NULL; + + /* nur INP-Nachbarn duerfen hier rein */ + if (pPeer->typ != INP) + return; + + /* uns selber melden */ + cpyid(node.id, myid); /* unsere ID */ + cpyals(node.alias, alias); /* unser Alias */ + + node.ipa = my_ip_addr; /* usere IP */ + node.bits = my_ip_bits; /* unsere Subnetzbits */ + node.options = NULL; /* keine Options */ + + add_inp_info(&inpmbp, &node, pPeer, 1, 0, 1); /* INP-Frame erstellen */ + brosnd(&inpmbp, pPeer); /* und senden */ +} + +/* End of src/l3inp.c */ diff --git a/src/l3ip.c b/src/l3ip.c new file mode 100755 index 0000000..43107db --- /dev/null +++ b/src/l3ip.c @@ -0,0 +1,1536 @@ +/************************************************************************/ +/* */ +/* ***** ***** */ +/* ***** ***** */ +/* ***** ***** */ +/* ***** ***** */ +/* *************** *************** */ +/* ***************** ***************** */ +/* *************** *************** */ +/* ***** ***** TheNetNode */ +/* ***** ***** Portable */ +/* ***** ***** Network */ +/* ***** ***** Software */ +/* */ +/* File src/l3ip.c (maintained by: DG1KWA) */ +/* */ +/* This file is part of "TheNetNode" - Software Package */ +/* */ +/* Copyright (C) 1998 - 2008 NORD>l2port != KERNEL_PORT) + { +#endif + if ( (mbhd->l2fflg != L2CIP) + || (!IPpar[mbhd->l2port].ipMode & IP_FORWARDING)) + return; +#ifdef KERNELIF + } +#endif + rxnxt = mbhd->mbbp; /* Anfang des Headers merken */ + ip_len = getchr(mbhd); /* Laenge und Version lesen */ + ip.version = (ip_len >> 4) & 0x0f; /* Versionsnummer */ + ip_len = (ip_len & 0x0f) << 2; /* und Laenge in Bytes */ + mbhd->mbbp = rxnxt; /* zurueck an den Anfang */ + if ( (mbhd->mbpc - (--mbhd->mbgc)) < IPLEN + || (ip_len < IPLEN) + || (ip.version != IPVERSION) +#ifdef __WIN32__ + || cksum(NULLHEADER, mbhd, (unsigned short)ip_len) != 0) +#else + || cksum(NULLHEADER, mbhd, ip_len) != 0) +#endif /* WIN32 */ + { + ipInHdrErrors++; + return; + } + + /* jetzt wird der IP-Header ausgewertet */ + getchr(mbhd); /* skip length/version */ + ip.tos = getchr(mbhd); + ip.length = get16(mbhd); + ip.id = get16(mbhd); + ip.offset = get16(mbhd); + ip.flags.mf = (ip.offset & 0x2000) ? 1 : 0; + ip.flags.df = (ip.offset & 0x4000) ? 1 : 0; + ip.offset = (ip.offset & 0x1fff) << 3; + ip.ttl = getchr(mbhd); + ip.protocol = getchr(mbhd); + ip.checksum = get16(mbhd); + ip.source = get32(mbhd); + ip.dest = get32(mbhd); + + /* ist das Ziel eine Broadcast-Addresse ? */ + rxbroadcast = is_broadcast_address(ip.dest); + + /* Optionsfeld auswerten */ + if ((ip.optlen = ip_len - IPLEN) != 0) + for (i = 0; i < ip.optlen; i++) + ip.options[i] = getchr(mbhd); + length = ip.length - ip_len; + + /* wenn das Frame direkt an uns gerichtet ist und wir keinen Speicher */ + /* mehr haben, muessen wir bescheid sagen */ + if (!rxbroadcast && nmbfre < 256) + icmp_output(&ip, mbhd, ICMP_QUENCH, 0, NULLICMP); + + /* Optionsfelder auswerten */ + strict = 0; + for (opt = ip.options; opt < &ip.options[ip.optlen]; opt += opt_len) + { + opt_len = opt[1]; + if ((opt[0] & OPT_NUMBER) == IP_EOL) + break; + + switch (opt[0] & OPT_NUMBER) + { + case IP_NOOP: + opt_len = 1; + break; + + case IP_SSROUTE: + strict = 1; + + case IP_LSROUTE: + if (!is_my_ip_addr(ip.dest)) + break; + if (opt[2] >= opt_len) + break; + ptr = opt + opt[2] - 1; + + memcpy(&ip.dest, ptr, 4); + memcpy(ptr, &my_ip_addr, 4); + + opt[2] += 4; + break; + case IP_RROUTE: + if (opt[2] >= opt_len) + { + if (!rxbroadcast) + { + union icmp_args icmp_args; + + icmp_args.pointer = IPLEN + opt - ip.options; + icmp_output(&ip, mbhd, ICMP_PARAM_PROB, 0, &icmp_args); + } + return; + } + ptr = opt + opt[2] - 1; + memcpy(ptr, &my_ip_addr, 4); + opt += 4; + break; + } + } + +#ifdef TCP_STACK + /* Protokoll TCP, */ + if ( (ip.protocol == TCP_PTCL) + /* und an mich. */ + &&(is_my_ip_addr(ip.dest))) + { + /* An TCP-Stack weiterleiten. */ + TCPIPProcess(&ip, mbhd); + return; + } +#endif /* TCP_STACK */ + + if ((is_my_ip_addr(ip.dest)) || rxbroadcast) + { + if ( !rxbroadcast && !ip.flags.mf && ip.offset == 0 + && ip.protocol == ICMP_PTCL) + { + icmp_input(&ip, mbhd); + ipInReceives++; + return; + } + else + { + if (!rxbroadcast) + icmp_output(&ip, mbhd, ICMP_DEST_UNREACH, + ICMP_PROT_UNREACH, NULLICMP); + ipInUnknownProtos++; + return; + } + } + + ipForwDatagrams++; + + /* Wenn die Lifetime des Frames abgelaufen ist, Frame vernichten und */ + /* Sender benachrichtigen */ + if (--ip.ttl == 0) + { + icmp_output(&ip, mbhd, ICMP_TIME_EXCEED, 0, NULLICMP); + ipInHdrErrors++; + return; + } + + /* Einen passenden Eintrag in der routing-Tabelle finden, wenn nichts */ + /* passt, einen NetSearch durchfuehren (zZ noch nicht implementiert), */ + /* wenn wir dort auch nichts finden, * wird das Frame vernichtet. */ +#ifndef IPROUTEMOD + if ((rp = rt_find(ip.dest)) == NULLROUTE) + { + icmp_output(&ip, mbhd, ICMP_DEST_UNREACH, + ICMP_HOST_UNREACH, NULLICMP); + ipOutNoRoutes++; + return; + } +#else /* IPROUTEMOD */ + if ((rp = rt_find(ip.dest)) == NULLROUTE) + { /* Auf default-route pruefen. */ + if ((rp = rt_find(my_default_ip_addr)) == NULLROUTE) + { + icmp_output(&ip, mbhd, ICMP_DEST_UNREACH, + ICMP_HOST_UNREACH, NULLICMP); + ipOutNoRoutes++; + return; + } + } +#endif /* IPROUTEMOD */ + + /* Den naechsten IP-Router berechnen, an den wir das Frame schicken */ + /* (z.B. das Gateway). Wenn der Eintrag kein Gateway aufweist, dann */ + /* die Zieladdresse nehmen. Wenn das Gateway nicht das Ziel ist, aber */ + /* strictes Routen gefordert wurde, denn Fehler melden ! */ + gateway = rp->gateway == 0L ? ip.dest : rp->gateway; + if (strict && gateway != ip.dest) + { + icmp_output(&ip, mbhd, ICMP_DEST_UNREACH, + ICMP_ROUTE_FAIL, NULLICMP); + ipOutNoRoutes++; + return; + } + + /* Maximale Blockgroese lesen, auf Segmentation pruefen Bei NET/ROM */ + /* wird immer eine MTU von 236 angenommen, da NET/ROM selber einen */ + /* Segmenter enthaelt, wird dieser notfalls zuschlagen. */ +#ifndef KERNELIF + mtu = (rp->port == NETROM_PORT) ? 236 : portpar[rp->port].mtu; +#else + switch(rp->port) + { + case NETROM_PORT: mtu = 236; + break; + /* Fuer den Kernel eine Extrawurst */ + case KERNEL_PORT: mtu = 1500; + break; + + default: mtu = portpar[rp->port].mtu; + } +#endif + + /* Frame ist klein genug, dass es ohne Fragmentierung geroutet werden kann */ + /* Alle Frames vom Kernel sollten hier lang gehen */ + if (ip.length <= mtu) + { + if ((tbp = htonip(&ip, mbhd, 0)) == NULL) + return; + + send_ip_mb(tbp, rp->port, gateway, ip.tos); + return; + } + + /* Das Frame ist zu gross, duerfen wir es zerlegen ? */ + if (ip.flags.df && rp->port == NETROM) /* nein, Fehler melden */ + { + union icmp_args icmp_args; + + icmp_args.mtu = mtu; + icmp_output(&ip, mbhd, ICMP_DEST_UNREACH, + ICMP_FRAG_NEEDED, &icmp_args); + ipFragFails++; + return; + } + + /* Das Frame bei NETROM aufspalten */ + if (rp->port == NETROM) + { + offset = ip.offset; + mf_flag = ip.flags.mf; + while (length != 0) + { + unsigned fragsize; + + ip.offset = offset; + if (length + ip_len <= mtu) + { + fragsize = length; + ip.flags.mf = mf_flag; + } + else + { + fragsize = (mtu - ip_len) & 0xfff8; + ip.flags.mf = 1; + } + ip.length = fragsize + ip_len; + if ((tbp = htonip(&ip, NULLBUF, 0)) == NULL) + return; + + for (i = fragsize; i != 0; i--) + putchr(getchr(mbhd), tbp); + send_ip_mb(tbp, rp->port, gateway, ip.tos); + ipFragCreates++; + offset += fragsize; + length -= fragsize; + } + } + +/* Frame ist zu gross, aber wir nehmen eine AX25- Fragmentierung vor */ + else + { + if ((tbp = htonip(&ip, mbhd, 0)) == NULL) + return; + + send_ip_mb(tbp, rp->port, gateway, ip.tos); + } + ipFragOKs++; + return; +} + +/************************************************************************ + * Function : In der Routing-Tabelle den Weg zu einem Ziel suchen + * + * Inputs : IP addresse + * + * Returns : Entweder zeiger auf den Tabelleneintrag oder NULL + * + * Operation: Erst schauen ob der Cache-Eintrag passt, ansonsten wird die + * Tabelle in absteigender Reihenfolge der Addressbits, wenn + * einer passt, gehts los + *----------------------------------------------------------------------*/ +IP_ROUTE * +rt_find(register ipaddr target) +{ + register IP_ROUTE *iprp; + ipaddr temp = target; + register unsigned bits = 32; + + /* Routentabelle durchgehen, passenden Eintrag suchen */ + for (iprp = (IP_ROUTE *)IP_Routes.head; + iprp != (IP_ROUTE *)&IP_Routes; + iprp = (IP_ROUTE *)iprp->nextip) + { + if (bits > iprp->bits) + temp &= ~0L << (32 - (bits = iprp->bits)); + + /* Route gefunden */ + if (iprp->dest == temp) + return (iprp); + } + + return (NULLROUTE); +} + +/************************************************************************ + * Function : den IP-Header aufbauen und in ein Buffer speichern + * + * Inputs : Zeiger auf den Header, den Buffer, Daten & Ckecksum Flag + * + * Returns : Zeiger auf den neuen Buffer im Netzwerk-format + * + * Operation: einen neuen Buffer erstellen, den Header abspeichern, + * und wenn data nicht NULL ist, die Daten reinspeichern + *----------------------------------------------------------------------*/ +MBHEAD * +htonip(register IP * iphdr, MBHEAD *data, BOOLEAN cflag) +{ + unsigned hdr_len; + register unsigned i; + register MBHEAD *bufpoi; + unsigned fl_offs; + unsigned checksum; + char huge *ptr, + huge * cksum_ptr; + + hdr_len = IPLEN + iphdr->optlen; + if ((bufpoi = ((MBHEAD *)allocb(ALLOC_MBHEAD))) == NULL) + return(NULL); + +#ifdef __WIN32__ + putchr((char)((IPVERSION << 4) | (hdr_len >> 2)), bufpoi); +#else + putchr((IPVERSION << 4) | (hdr_len >> 2), bufpoi); +#endif /* WIN32 */ + putchr(iphdr->tos, bufpoi); +#ifdef __WIN32__ + put16((unsigned short)iphdr->length, bufpoi); + put16((unsigned short)iphdr->id, bufpoi); +#else + put16(iphdr->length, bufpoi); + put16(iphdr->id, bufpoi); +#endif /* WIN32 */ + fl_offs = iphdr->offset >> 3; + if (iphdr->flags.df) + fl_offs |= 0x4000; + if (iphdr->flags.mf) + fl_offs |= 0x2000; +#ifdef __WIN32__ + put16((unsigned short)fl_offs, bufpoi); +#else + put16(fl_offs, bufpoi); +#endif /* WIN32 */ + putchr(iphdr->ttl, bufpoi); + putchr(iphdr->protocol, bufpoi); + cksum_ptr = bufpoi->mbbp; + put16(0, bufpoi); + put32(iphdr->source, bufpoi); + put32(iphdr->dest, bufpoi); + for (i = 0; i < iphdr->optlen; i++) + putchr(iphdr->options[i], bufpoi); + ptr = bufpoi->mbbp; + i = bufpoi->mbpc; + rwndmb(bufpoi); +#ifdef __WIN32__ + checksum = cflag ? iphdr->checksum : cksum(NULLHEADER, bufpoi, (unsigned short)hdr_len); +#else + checksum = cflag ? iphdr->checksum : cksum(NULLHEADER, bufpoi, hdr_len); +#endif /* WIN32 */ + bufpoi->mbbp = cksum_ptr; + bufpoi->mbpc = 10; +#ifdef __WIN32__ + put16((unsigned short)checksum, bufpoi); +#else + put16(checksum, bufpoi); +#endif /* WIN32 */ + bufpoi->mbbp = ptr; + bufpoi->mbpc = i; + if (data != NULL) + { + i = data->mbpc - data->mbgc; + while (i--) + putchr(getchr(data), bufpoi); + } + return (bufpoi); +} + +/* *********************************************************************** + * Function : Ein IP datagramm senden + * Modelled after the example interface on p 32 of RFC 791 + * + * Inputs : + * + * Returns : + * + * Operation: Netzwerk-Header erzeugen, Daten anfuegen und so tun, als ob + * wir das Frame empfangen haetten + * ---------------------------------------------------------------------*/ +int +ip_send(ipaddr source, /* source address */ + ipaddr dest, /* Destination address */ + unsigned protocol, /* Protocol */ + unsigned tos, /* Type of service */ + unsigned ttl, /* Time-to-live */ + MBHEAD *bp, /* Data portion of datagram */ + unsigned short length, /* Optional length of data portion */ + unsigned short id, /* Optional identification */ + unsigned df) /* Don't-fragment flag */ +{ + register MBHEAD *tbp; + IP ip; /* Pointer to IP header */ + register IP *ipptr = &ip; + static unsigned short id_cntr; /* Datagram serial number */ + + ipOutRequests++; + + if (length == 0 && bp != NULL) + length = bp->mbpc - bp->mbgc; + + /* Fill in IP header */ + ipptr->tos = tos; + ipptr->length = IPLEN + length; + ipptr->id = (id == 0) ? id_cntr++ : id; + ipptr->offset = 0; + ipptr->flags.mf = 0; + ipptr->flags.df = df; + ipptr->ttl = (ttl == 0) ? ipDefaultTTL : ttl; + ipptr->protocol = protocol; + ipptr->source = source; + ipptr->dest = dest; + ipptr->optlen = 0; + if ((tbp = htonip(&ip, bp, 0)) == NULL) + { + dealmb(bp); + return(1); + } + dealmb(bp); + tbp->l2fflg = L2CIP; + rwndmb(tbp); + tbp->l2port = NETROM_PORT; /* der Port ist immer eingeschaltet */ + relink((LEHEAD *)tbp, (LEHEAD *)iprxfl.tail); + return (0); +} + +/************************************************************************ + * Function : Ip Router Interface zu NET/ROM + * + * Inputs : Frame zum senden, die Gateway-Addresse, tos-flag + * + * Returns : nix + * + * Operation: Das Frame wird nach der arp-Tabelle addressiert und in die + * L3-Sendeliste gehaengt + *----------------------------------------------------------------------*/ +void +nr_iface(MBHEAD *mhbp, ipaddr gateway) +{ + register unsigned i; + register MBHEAD *mb; + register ARP_TAB *arp; + NODE *np; + + /* den passenden ARP-Eintrag suchen und pruefen, ob der Node bekannt */ + /* und erreichbar ist */ + if ( (arp = res_arp(gateway, ARP_NETROM)) != NULLARP + && (iscall(arp->callsign, &np, NULL, DG))) + { + l4pidx = l4pcid = NR_PROTO_IP; /* NETROM IP Family */ + l4ahd2 = l4ahd3 = 0; /* unbenutzt ... */ + l4aopc = NR4_OP_PID; /* NET/ROM Opcode fuer IP */ + mb = gennhd(); /* L3/L4 Header erzeugen */ + rwndmb(mhbp); /* Zurueckspulen zum senden */ + i = mhbp->mbpc - mhbp->mbgc; /* Daten kopieren */ + while (i--) + putchr(getchr(mhbp), mb); + mb->l2link = (LNKBLK *)np; /* Zielnode setzen */ + mb->l4type = L4TNORMAL; /* Prioritaet setzen */ + relink((LEHEAD *)mb, (LEHEAD *)l3txl.tail); /* nur umhaengen */ + } + dealmb(mhbp); +} + +/************************************************************************ + * Function : AX.25 Handler fuer den ip router + * + * Inputs : wie oben fuer NET/ROM + * + * Returns : nothing + * + * Operation: Feststellen, ob dg oder vc, dann Frame senden + *----------------------------------------------------------------------*/ +void +l2_iface(MBHEAD *mhbp, unsigned port, ipaddr gateway, unsigned tos) +{ + register ARP_TAB *arp; + PTCENT *ptcp; +#ifdef EAX25 + MHEARD *mhp = NULL; +#endif + + + /* IP-Pid setzen */ + rwndmb(mhbp); + mhbp->l2fflg = L2CIP; + + /* find the arp entry. Die if none ! */ + if ((arp = res_arp(gateway, ARP_AX25)) == NULLARP) + { + arp_request(gateway, ARP_AX25, port); + dealmb(mhbp); + } + + /* Now check to see if we are going to DG or VC it */ + else + if ( (arp->dgmode & 1) + || ( (arp->dgmode == 0) + && ( tos & DELAY + || ( !(tos & RELIABILITY) + /* && (ipPar[port].ipMode & DG_OK) */ + )))) + { +#ifdef __WIN32__ + sdui(arp->digi, arp->callsign, myid, (char)port, mhbp); +#else + sdui(arp->digi, arp->callsign, myid, port, mhbp); +#endif /* WIN32 */ + dealmb(mhbp); + } + else + /* Virtual Circuit */ + { +#ifdef __WIN32__ + lnkpoi = getlnk((unsigned char)port, myid, arp->callsign, arp->digi); +#else + lnkpoi = getlnk(port, myid, arp->callsign, arp->digi); +#endif /* WIN32 */ + if (lnkpoi) + { + if (lnkpoi->state == L2SDSCED) + { + ptcp = ptctab + g_uid(lnkpoi, L2_USER); + ptcp->state = D_IPLINK; + ptcp->ublk = NULL; + ptcp->p_uid = NO_UID; +#ifdef EAX25 + /* TEST DG9OBU */ + /* Call in L2-MHeard suchen */ + if ((mhp = mh_lookup(&l2heard, arp->callsign)) != NULL) + { + if ( (mhp->eax_link == TRUE) /* mit EAX.25 gehoert */ + && (portpar[mhp->port].eax_behaviour >= 1) /* und auf Port erlaubt */ + ) + { + lnkpoi->bitmask = 0x7F; +#ifdef __WIN32__ + lnkpoi->maxframe = (unsigned char)portpar[lnkpoi->liport].maxframe_eax; +#else + lnkpoi->maxframe = portpar[lnkpoi->liport].maxframe_eax; +#endif /* WIN32 */ + } + } +#endif + + newlnk(); /* eventuell erst aufbauen */ + } + rwndmb(mhbp); + i3tolnk(mhbp->l2fflg, lnkpoi, mhbp); /* -> ab in den Link */ + } + else + dealmb(mhbp); + } +} + + +/************************************************************************ + * Function : Reverse ARP fuer eine Addresse/Hardwaretyp durchfuehren + * + * Inputs : Pointer to internet address and a hardware ( arp ) type + * + * Returns : Pointer to entry in arp table or a null pointer + * + * Operation: Die Tabelle linear durchsuchen ob ein Eintrag passt + *----------------------------------------------------------------------*/ +ARP_TAB * +res_arp(register ipaddr target, register unsigned hwtype) +{ + register ARP_TAB *arprp; + + for (arprp = (ARP_TAB *) Arp_tab.head; + arprp != (ARP_TAB *) & Arp_tab; + arprp = (ARP_TAB *) arprp->nextar) +#ifdef __WIN32__ + if ( (char)hwtype == arprp->hwtype +#else + if ( hwtype == arprp->hwtype +#endif /* WIN32 */ + && arprp->dest == target) + return (arprp); + return (NULLARP); +} + +/************************************************************************ + * Function : Eine ICMP-Antwort an den Absender des Frames zurueck + * schicken, der Aufrufer gibt das Frame frei! + * + * Inputs : + * + * Returns : nix + * + * Operation: Did you ever hear the one about the vampire rabbit ? + * Note lots of standard icmp bits are commented out. + *----------------------------------------------------------------------*/ +void +icmp_output(IP *ip, /* Header of offending datagram */ + register MBHEAD *data, /* Data portion of datagram */ + unsigned type, /* Codes to send */ + unsigned code, + union icmp_args *args) +{ + MBHEAD *bp, + *bp2; + ICMP icmp; /* ICMP protocol header */ + unsigned short length; /* Total length of reply */ + register unsigned short i; + char huge *rxnxt; + + if ((unsigned char)ip->protocol == ICMP_PTCL) + { + /* Den Header durchsuchen, ob es sicher ist, eine ICMP Nachricht */ + /* zurueckzuschicken */ + rxnxt = data->mbbp; + i = getchr(data) & 0xff; + data->mbbp = rxnxt; + data->mbgc--; + switch (i) + { + case ICMP_ECHO_REPLY: + case ICMP_ECHO: + case ICMP_TIMESTAMP: + case ICMP_TIME_REPLY: + case ICMP_INFO_RQST: + case ICMP_INFO_REPLY: + break; /* These are all safe */ + default: + /* Auf eine Fehlermeldung keine Fehlermeldung senden (gibt */ + /* sonst einen netten Ping-Pong) */ + return; + } + } + + /* Berechnen, wieviel wir vom Frame zurueckschicken wollen, das sind */ + /* maximal der fremde Header und 8 Bytes */ + i = data->mbpc - data->mbgc; + if (i > 8) + i = 8; + length = i + ICMPLEN + IPLEN + ip->optlen; + + /* Den Header neu aufbauen */ + if ((bp = htonip(ip, NULLBUF, 1)) == NULL) + return; + + /* Die Antwort-Daten hineinkopieren */ + while (i--) + putchr(getchr(data), bp); + icmp.type = type; + icmp.code = code; + icmp.args.unused = 0; + + switch (type) + { +/* case ICMP_ECHO: + icmpOutEchos++; + break; + + case ICMP_ECHO_REPLY: + icmpOutEchoReps++; + break; + + case ICMP_INFO_RQST: + break; + + case ICMP_INFO_REPLY: + break; + + case ICMP_TIMESTAMP: + icmpOutTimestamps++; + break; + + case ICMP_ADDR_MASK: + icmpOutAddrMasks++; + break; + + case ICMP_ADDR_MASK_REPLY: + icmpOutAddrMaskReps++; + break; + + case ICMP_TIME_EXCEED: + icmpOutTimeExcds++; + break; + + case ICMP_QUENCH: + icmpOutSrcQuenchs++; + break; +*/ + case ICMP_PARAM_PROB: +/* icmpOutParmProbs++; +*/ icmp.args.pointer = args->pointer; + break; + + case ICMP_REDIRECT: +/* icmpOutRedirects++; +*/ icmp.args.address = args->address; + break; + + case ICMP_TIME_REPLY: +/* icmpOutTimestampReps++; +*/ icmp.args.echo.id = args->echo.id; + icmp.args.echo.seq = args->echo.seq; + break; + + case ICMP_DEST_UNREACH: + if (icmp.code == ICMP_FRAG_NEEDED) + icmp.args.mtu = args->mtu; +/* icmpOutDestUnreachs++; +*/ break; + } + + /* Jetzt generieren wir das eigentliche ICMP-Frame */ + if ((bp2 = htonicmp(&icmp, bp)) == NULL) + { + dealmb(bp); + return; + } + dealmb(bp); + + ip_send(my_ip_addr, ip->source, ICMP_PTCL, ip->tos, + 0, bp2, length, 0, 0); +} + +/************************************************************************ + * Function : Einen ICMP Echo Request erzeugen und absenden + * + * Inputs : Zieladdresse, Sequenznummer und id, ein optionales + * Laengenfeld (maximal 4 Bytes) zur freien Verwendung + * + * Returns : int - TRUE wenn das Frame erzeugt wurde + * + * Operation: Ein Frame anlegen und an die Zieladdresse schicken + *----------------------------------------------------------------------*/ +BOOLEAN +pingem(ipaddr target, int seq, int id, int len, char *opt) +{ + MBHEAD *bp, + *data; + ICMP icmp; /* ICMP protocol header */ + + /* Pruefen, ob Ziel irgendwie erreichbar ist */ + if (rt_find(target) == NULLROUTE) + return (FALSE); + + if ((data = ((MBHEAD *)allocb(ALLOC_MBHEAD))) == NULL) + return(FALSE); + + put32(tic10, data); /* aktuelle Uhrzeit hineinschreiben */ + put32((ULONG)userpo, data); /* und den User */ + while (len--) + putchr(*opt++, data); /* Optionsfeld schreiben */ + + /* icmpOutEchos++; icmpOutMsgs++; */ + + icmp.type = ICMP_ECHO; + icmp.code = 0; + icmp.args.echo.seq = seq; + icmp.args.echo.id = id; + + if ((bp = (htonicmp(&icmp, data))) == NULL) + { + dealmb(data); + return(FALSE); + } + + dealmb(data); + if (ip_send(my_ip_addr, target, ICMP_PTCL, LOW_DELAY, 0, bp, 0, 0, 0) == TRUE) + return(FALSE); + + return (TRUE); +} + +/************************************************************************ + * Function : Einen ICMP-Header erzeugen, Daten hineinkopieren + * + * Inputs : Zeiger auf den ICMP-Header und Daten + * + * Returns : Zeiger auf das fertige Frame + * + * Operation: Well, there was this traveller in Transylvania, + *----------------------------------------------------------------------*/ +MBHEAD * +htonicmp(register ICMP * icmp, MBHEAD *data) +{ + register MBHEAD *bp; + unsigned short checksum; + register unsigned putcnt; + /* char huge *nxtchr; */ + char huge *cksum_ptr; + + if ((bp = ((MBHEAD *)allocb(ALLOC_MBHEAD))) == NULL) + return(NULL); + + putchr(icmp->type, bp); + putchr(icmp->code, bp); + cksum_ptr = bp->mbbp; + put16(0, bp); /* Clear checksum */ + + switch (icmp->type) + { + case ICMP_DEST_UNREACH: + put16(0, bp); + if (icmp->code == ICMP_FRAG_NEEDED) /* Deering/Mogul max MTU + indication */ +#ifdef __WIN32__ + put16((unsigned short)icmp->args.mtu, bp); +#else + put16(icmp->args.mtu, bp); +#endif /* WIN32 */ + else + put16(0, bp); + break; + + case ICMP_PARAM_PROB: + putchr(icmp->args.pointer, bp); + putchr(0, bp); + put16(0, bp); + break; + + case ICMP_REDIRECT: + put32(icmp->args.address, bp); + break; + + case ICMP_ECHO: + case ICMP_ECHO_REPLY: + case ICMP_TIMESTAMP: + case ICMP_TIME_REPLY: + case ICMP_INFO_RQST: + case ICMP_INFO_REPLY: +#ifdef __WIN32__ + put16((unsigned short)icmp->args.echo.id, bp); + put16((unsigned short)icmp->args.echo.seq, bp); +#else + put16(icmp->args.echo.id, bp); + put16(icmp->args.echo.seq, bp); +#endif /* WIN32 */ + break; + + default: + put16(0, bp); + put16(0, bp); + break; + } + rwndmb(data); + putcnt = data->mbpc; + while (putcnt--) + putchr(getchr(data), bp); + + /* Compute checksum, and stash result */ + putcnt = bp->mbpc; + rwndmb(bp); + checksum = cksum(NULLHEADER, bp, bp->mbpc); + bp->mbbp = cksum_ptr; + bp->mbpc = 2; + put16(checksum, bp); + bp->mbpc = putcnt; + rwndmb(bp); + return (bp); +} + +/* *********************************************************************** + * Function : Behandlung von eingehenden ICMP-Frames + * + * Inputs : Dekodierter IP-Header und Framedaten + * + * Returns : nix + * + * Operation: Nur eine sehr einfache ICMP-Behandlung durchfuehren, um + * PING-Anfragen zu beantworten. + * ---------------------------------------------------------------------*/ +void +icmp_input(register IP * ip, register MBHEAD *bp) +{ + MBHEAD *tbp; + register MBHEAD *bp2; + ICMP icmp; + unsigned length, + i; + ULONG ping_tic; + USRBLK *ping_user; + char buf[50]; + UWORD adr[4]; + + length = ip->length - IPLEN - ip->optlen; +#ifdef __WIN32__ + if (cksum(NULLHEADER, bp, (unsigned short)length) != 0) +#else + if (cksum(NULLHEADER, bp, length) != 0) +#endif /* WIN32 */ + return; + if (bp->mbpc - bp->mbgc < 8) + return; + icmp.type = getchr(bp); + icmp.code = getchr(bp); + + /* fremde Pings beantworten */ + if (icmp.type == ICMP_ECHO) + { + get16(bp); + icmp.args.echo.id = get16(bp); + icmp.args.echo.seq = get16(bp); + icmp.type = ICMP_ECHO_REPLY; + bp2 = (MBHEAD *)allocb(ALLOC_MBHEAD); + if (length > 8) + { + i = length - 8; + while (i--) + putchr(getchr(bp), bp2); + } + if ((tbp = htonicmp(&icmp, bp2)) == NULL) + { + dealmb(bp2); + return; + } + dealmb(bp2); + ip_send(ip->dest, ip->source, ICMP_PTCL, +#ifdef __WIN32__ + ip->tos, 0, tbp, (unsigned char)length, 0, 0); +#else + ip->tos, 0, tbp, length, 0, 0); +#endif /* WIN32 */ + return; + } + + /* eigene Pings dem User ausgeben */ + if (icmp.type == ICMP_ECHO_REPLY) + { + get16(bp); + get16(bp); /* id */ + get16(bp); /* seq */ + ping_tic = get32(bp); + ping_user = (void *)get32(bp); + + ping_tic = (tic10 - ping_tic) * 10; + if (ping_tic <= 10) + ping_tic = 10; + + for (i = 0; i < 4; i++) +#ifdef __WIN32__ + adr[i] = (unsigned short)(ip->source >> 8 * i) & 0xff; +#else + adr[i] = (ip->source >> 8 * i) & 0xff; +#endif /* WIN32 */ + sprintf(buf, "%d.%d.%d.%d rtt = %lums, ttl = %u", + adr[3], adr[2], adr[1], adr[0], ping_tic, ip->ttl); +#ifdef SEND_ASYNC_RESFIX + /* Sicher ist sicher. */ + buf[256] = 0; +#endif /* SEND_ASYNC_RESFIX */ + send_async_response(ping_user, "Ping response from ", buf); + } +} + +/************************************************************************ + * Function : Ein "end-around-carry adjustment" durchfuehren + * + * Inputs : aktuelle Checksumme + * + * Returns : korrigierte Pruefsumme + * + * Operation: + * + *----------------------------------------------------------------------*/ +unsigned short +eac(long sum) +{ + register unsigned short csum; + +#ifdef __WIN32__ + sum = csum = (sum >> 16) + (sum & 0xffff); +#else + while ((csum = sum >> 16) != 0) + sum = csum + (sum & 0xffffL); +#endif /* WIN32 */ + return ((unsigned short)(sum & 0xffffL)); /* nur 16 bits */ +} + +/* *********************************************************************** + * Function : Checksum an mhtyp, with optional pseudo-header + * + * Inputs : pseudo header, buffer to checksum and byte count + * + * Returns : unsigned integer checksum with eac corrected + * + * Operation: add up all bytes in a long, in perverse arpa way then eac + * ---------------------------------------------------------------------*/ +unsigned short +cksum(register PSEUDO_HEADER * ph, register MBHEAD *m, + register unsigned short len) +{ + long sum; + unsigned rxcnt; + char huge *rxchr; + + sum = 0L; + + /* Sum pseudo-header, if present */ + if (ph != NULLHEADER) + { +#ifndef L1TCPIP + sum = ((unsigned *)(&ph->source))[0]; + sum += ((unsigned *)(&ph->source))[1]; + sum += ((unsigned *)(&ph->dest))[0]; + sum += ((unsigned *)(&ph->dest))[1]; + sum += ((unsigned)ph->protocol & 0xff); + sum += ((unsigned)ph->length); +#else + sum += (ph->source & 0xffffUL); + sum += ((ph->source >> 16) & 0xffffUL); + sum += (ph->dest & 0xffffUL); + sum += ((ph->dest >> 16) & 0xffffUL); + sum += (ph->protocol & 0xff); + sum += (ph->length); +#endif /* L1TCPIP */ + } + + rxcnt = m->mbgc; + rxchr = m->mbbp; + while (len > 0) + { + if (len > 1) + { + sum += (unsigned)get16(m); + len -= 2; + } + else + { +#ifndef L1TCPIP + sum += ((unsigned)getchr(m) & 0xFF00); +#else + sum += ((getchr(m) << 8) & 0xFF00); +#endif /* L1TCPIP */ + len--; + } + } + m->mbgc = rxcnt; + m->mbbp = rxchr; + return ((unsigned short)(~eac(sum) & 0xffff)); +} + +/* ********************************************************************** + * Function : ARP service zur Beantwortung von ARP-Requests und + * die Auswertung der Antworten + * + * Inputs : Zeiger auf das ARP-Frame + * + * Returns : nix + * + * Outputs : UI Frame mit dem Ergebnis der Bearbeitung + * + * Operation: Wenn nach uns gefragt wurde, oder nach einem Eintrag, der + * als published gekennzeichnet ist, dann beantworten + * ---------------------------------------------------------------------*/ +void +arp_service(MBHEAD *mhbp) +{ + unsigned char arp_not_revarp; + /* char *ptr; */ + register MBHEAD *mbhd = mhbp; + register ARP_TAB *ap; + register unsigned i; + ARP_TAB *atp; + IP_ROUTE *ipr; + + /* ARP auf dem Port erlaubt ? */ + if (!(IPpar[mbhd->l2port].ipMode & ARP_OK)) + { + return; + } + + /* Hardware korrekt ? */ + if ((arp.hardware = get16(mbhd)) != ARP_AX25) + { +/* arp_stat.badtype++; */ + return; + } + + /* Protokoll ok ? */ + if ((arp.protocol = get16(mbhd)) != L2CIP) + { +/* arp_stat.badtype++; */ + return; + } + + arp.hwalen = getchr(mbhd); + arp.pralen = getchr(mbhd); + + /* Laenge(n) ok ? */ + if (arp.hwalen > MAXHWALEN || arp.pralen != sizeof(ipaddr)) + { +/* arp_stat.badlen++; */ + return; + } + + /* Opcode */ + arp.opcode = get16(mbhd); + + /* Quell- und Ziel-Adressen (jeweils Call und IP-Adress) */ + getfid((char *)arp.shwaddr, mbhd); + arp.sprotaddr = get32(mbhd); + getfid((char *)arp.thwaddr, mbhd); + arp.tprotaddr = get32(mbhd); + + /* Frame an "QST ? */ + if (cmpid((char *)arp.shwaddr, QST)) + { +/* arp_stat.badaddr++; */ + return; + } + + ap = res_arp(arp.sprotaddr, arp.hardware); + + /* IP-Adresse anhand des ARP-Requests lernen */ + if ( (((i = is_my_ip_addr(arp.tprotaddr)) != 0) && ap == NULLARP) + || (ap != NULLARP && ap->timer != 0)) + { + /* ARP-Eintrag machen (mit Timeout) */ + arp_add(arp.sprotaddr, mbhd->l2port, (char *)arp.shwaddr, "", 2, ARPtimer, 1, FALSE); + + /* Falls der Weg zum neu eingetragenen Host nicht oder von einer */ + /* Route erfasst wird, die die Frames auf einem anderen Port als dem */ + /* Port auf dem das ARP empfangen wurde aussenden wuerde, dann eine */ + /* explizite /32 Route zu diesem Host auf dem ARP-Empfangsport eintragen. */ + ipr = rt_find((ipaddr)arp.sprotaddr); + + if ( (ipr == NULLROUTE) + || ( (ipr != NULLROUTE) + && (ipr->port != mbhd->l2port) + ) + ) + rt_add(arp.sprotaddr, 32, 0L, mbhd->l2port, 0, 0, 0, TRUE); + } + + if ( arp.opcode == REVARP_REQUEST + || ( arp.opcode == ARP_REQUEST + && ( (i /* = is_my_ip_addr(&arp.tprotaddr) */ ) + || ( (ap = res_arp(arp.tprotaddr, arp.hardware)) != NULLARP + && ap->publish_flag)))) + { + arp_not_revarp = (arp.opcode == ARP_REQUEST); + if (!arp_not_revarp) + for (atp = (ARP_TAB *) Arp_tab.head; + atp != (ARP_TAB *) & Arp_tab; + atp = (ARP_TAB *) atp->nextar) + if ((i = cmpid(atp->callsign, (char *)arp.thwaddr)) != 0) + break; + if (arp_not_revarp || (i && ap->publish_flag)) + { + if (arp_not_revarp) + { + cpyid((char *)arp.thwaddr, (char *)arp.shwaddr); + /* if (arp.hardware == ARP_AX25) */ + arp.thwaddr[arp.hwalen - 1] |= 1; + } + + cpyid((char *)arp.shwaddr, i ? myid : ap->callsign); + arp.tprotaddr = arp_not_revarp ? arp.sprotaddr : ap->dest; + arp.sprotaddr = i ? my_ip_addr : ap->dest; + arp.opcode = arp_not_revarp ? ARP_REPLY : REVARP_REPLY; + arp_send(mhbp->l2port, (char *)arp.thwaddr); +/* Arp_stat.inreq++; */ + } + } +} + +/************************************************************************ + * Function : Einen ARP request/response Frame senden ( L2 AX25 ) + * + * Inputs : Internes ARP-Frame und Port + * + * Returns : nix + * + * Outputs : UI Frame mit ARP request/response + * + *----------------------------------------------------------------------*/ +void +arp_send(unsigned port, char *hwaddr) +{ + register MBHEAD *mbhd; + + mbhd = (MBHEAD *)allocb(ALLOC_MBHEAD); +#ifdef __WIN32__ + put16((unsigned short)arp.hardware, mbhd); + put16((unsigned short)arp.protocol, mbhd); +#else + put16(arp.hardware, mbhd); + put16(arp.protocol, mbhd); +#endif /* WIN32 */ + putchr(arp.hwalen, mbhd); + putchr(arp.pralen, mbhd); +#ifdef __WIN32__ + put16((unsigned short)arp.opcode, mbhd); +#else + put16(arp.opcode, mbhd); +#endif /* WIN32 */ + putfid((char *)arp.shwaddr, mbhd); + put32(arp.sprotaddr, mbhd); + putfid((char *)arp.thwaddr, mbhd); + put32(arp.tprotaddr, mbhd); + mbhd->l2fflg = L2CARP; + rwndmb(mbhd); +#ifdef __WIN32__ + sdui("", hwaddr, myid, (char)port, mbhd); +#else + sdui("", hwaddr, myid, port, mbhd); +#endif /* WIN32 */ + dealmb(mbhd); +} + +/************************************************************************ + * Function : Ein ARP request Frame senden (L2 AX25 UI) + * + * Inputs : Internes ARP-Frame und der port + * + * Returns : nix + * + * Outputs : UI Frame mit ARP request senden + * + *----------------------------------------------------------------------*/ +void +arp_request(ipaddr gateway, unsigned hwtype, unsigned port) +{ + register unsigned i; + + arp.hardware = hwtype; + arp.protocol = L2CIP; + arp.hwalen = L2IDLEN; + arp.pralen = sizeof(ipaddr); + arp.opcode = ARP_REQUEST; + cpyid((char *)arp.shwaddr, myid); + arp.sprotaddr = my_ip_addr; + arp.tprotaddr = gateway; + for (i = 0; i < L2IDLEN; i++) + arp.thwaddr[i] = 0; + arp_send(port, QST); +} + +/*----------------------------------------------------------------------*/ +/* Neue Status-Meldung verarbeiten */ +/* 0=nicht verwendet, 1=connectet, 2=disconnectet, 3=busy, 4=Failure */ +/*----------------------------------------------------------------------*/ +BOOLEAN +l2toip(WORD status) +{ + ARP_TAB *ap; + PTCENT *ptcp; + const char *viap; + + viap = ndigipt(lnkpoi->viaidl); + + if (!cmpid(lnkpoi->srcid, myid)) + return (FALSE); + for (ap = (ARP_TAB *) Arp_tab.head; + ap != (ARP_TAB *) & Arp_tab; + ap = (ARP_TAB *) ap->nextar) + if ( (ap->port == lnkpoi->liport) + && cmpidl(ap->digi, viap) + && cmpid(ap->callsign, lnkpoi->dstid)) + { + ptcp = ptctab + g_uid(lnkpoi, L2_USER); + switch (status) + { + case L2MCONNT: + case L2MLRESF: + case L2MLREST: + if (ptcp->state != D_IPLINK) + ptcp->state = U_IPLINK; + ptcp->ublk = NULL; + ptcp->p_uid = NO_UID; + break; + + case L2MDISCF: + case L2MBUSYF: + case L2MFAILW: + clrptc(g_uid(lnkpoi, L2_USER)); + } + return (TRUE); /* Meldung verarbeitet */ + } + return (FALSE); +} +#endif + +/* End of src/l3ip.c */ diff --git a/src/l3misc.c b/src/l3misc.c new file mode 100755 index 0000000..a3ccfc9 --- /dev/null +++ b/src/l3misc.c @@ -0,0 +1,1304 @@ +/************************************************************************/ +/* */ +/* ***** ***** */ +/* ***** ***** */ +/* ***** ***** */ +/* ***** ***** */ +/* *************** *************** */ +/* ***************** ***************** */ +/* *************** *************** */ +/* ***** ***** TheNetNode */ +/* ***** ***** Portable */ +/* ***** ***** Network */ +/* ***** ***** Software */ +/* */ +/* File src/l3misc.c (maintained by: ???) */ +/* */ +/* This file is part of "TheNetNode" - Software Package */ +/* */ +/* Copyright (C) 1998 - 2008 NORD>max_peers = max_peers; + netp->max_nodes = max_nodes; + netp->peertab = (PEER *) memp; memp += sizeof(PEER)*netp->max_peers; + netp->nodetab = (NODE *) memp /*, memp += sizeof(NODE)*netp->max_nodes */; + inithd(&netp->nodelis); + return(TRUE); + } + return(FALSE); +} + +/* einen Router deinitialisieren */ +void unregister_network(void) +{ + free(netp); +} + +/************************************************************************\ +* * +* Netzwerk-Heap initialisieren * +* * +\************************************************************************/ +static void +init_network(void) +{ + char *s; + + if ((s = getenv("TNNCFG")) != NULL) + sscanf(s, "%d,%d", &max_nodes, &max_peers); + + max_nodes = max(max_nodes, 1); + max_peers = max(max_peers, 1); + if (!register_network(max_peers, get_next_prim(max_nodes))) + memerr(); + xprintf("*** NETWORK startup, %d Nodes, %d Neighbours\n", + netp->max_nodes, netp->max_peers); +} + +/************************************************************************\ +* * +* Initialisierung des Level 3 * +* * +* FlexNet und Net/ROM Router intialisieren, Ziellisten loeschen. * +* * +\************************************************************************/ +void +l3init(void) /* Level 3 initialisieren */ +{ + inithd(&l3rxfl); /* Liste empfangene Frames loeschen */ + inithd(&l3txl); /* Liste zu sendende Frames loeschen */ + init_network(); +} + +/************************************************************************/ +/* */ +/* Informationstransfer von Level3 zum Level2 */ +/* Uebergeben werden reine Datenpackete ohne AX.25-Header. Diese werden */ +/* dann an den angegebenen Link gehaengt und mit der gewuenschten PID */ +/* gesendet. Grosse Frames (> 256 Bytes) werden fragmentiert und mit */ +/* PID 0x08 gesendet (die gewuenschte PID wird im 1. Fragment ueber- */ +/* mittelt). */ +/* */ +/************************************************************************/ +void +i3tolnk(UBYTE pid, LNKBLK *linkp, MBHEAD *imbp) +{ + int anz_frag, + info; + MBHEAD *tmpmbp; + BOOLEAN frame1 = TRUE; + + info = ((imbp->mbpc) - (imbp->mbgc)); /* Laenge bestimmen */ + ptctab[g_uid(linkp, L2_USER)].infotx += info; + +#ifndef THENETMOD + linkp->noatou = ininat; +#else /* L4TIMEOUT */ + linkp->noatou = SetL4Timeout(); /* L2/L4-Timeout setzen. */ +#endif /* THENETMOD */ + + if (info < 257) + { + imbp->l2fflg = pid; /* PID uebernehmen */ + imbp->repeated = 0; + relink((LEHEAD *)imbp, /* -> ab in den Link */ + (LEHEAD *)linkp->sendil.tail); + ++linkp->tosend; /* ein Sendepaket mehr */ + } + else + { +/* fuer grosse Pakete generieren wir AX25-Fragmente */ + anz_frag = info / 255; /* wieviele Folgefragmente? */ + if (anz_frag > 127) /* zu gross geht nicht */ + { + dealmb(imbp); + return; + } + do + { + tmpmbp = (MBHEAD *)allocb(ALLOC_MBHEAD); /* Buffer holen */ + tmpmbp->l2fflg = L2CFRAG; /* wir senden mit PID 08 */ + tmpmbp->repeated = 0; + if (frame1) + { +#ifdef __WIN32__ + putchr((char)(anz_frag | 0x80), tmpmbp);/* es folgen n Fragmente */ +#else + putchr(anz_frag | 0x80, tmpmbp);/* es folgen n Fragmente */ +#endif /* WIN32 */ + putchr(pid, tmpmbp); /* mit pid */ + frame1 = FALSE; + } + else +#ifdef __WIN32__ + putchr((char)anz_frag, tmpmbp); /* es folgen n Fragmente */ +#else + putchr(anz_frag, tmpmbp); /* es folgen n Fragmente */ +#endif /* WIN32 */ + while (tmpmbp->mbpc < 256) /* max. 256 Bytes im Fragment */ + { + if (!(imbp->mbpc - imbp->mbgc)) /* Frameende */ + break; + putchr(getchr(imbp), tmpmbp); /* Daten umkopieren */ + } + rwndmb(tmpmbp); /* zurueckspulen */ + relink((LEHEAD *)tmpmbp, /* in die Sendeliste damit */ + (LEHEAD *)linkp->sendil.tail); + ++linkp->tosend; /* ein Frame mehr zu senden */ + } while (anz_frag-- > 0); +/* wir sind fertig */ + dealmb(imbp); + } +} + +/*----------------------------------------------------------------------*/ +/* l3rx() Empfangene Frames der Nachbarn verarbeiten. */ +/*----------------------------------------------------------------------*/ +void +l3rx(void) +{ + PEER *pp; + int max_peers = netp->max_peers; + static int peer = 0; + + if (++peer >= max_peers) + peer = 0; + + if (peer < max_peers) + { + pp = &netp->peertab[peer]; + + if (pp->used) + { + switch (pp->typ) + { + case FLEXNET: + flexnet_rx(pp); + break; + case NETROM: + case TNN: + case THENET: + case INP: + netrom_rx(pp); + } + } + } +} + +/*..................................................................... */ +/*.. Empfangsliste abgearbeitet, nun zu sendende Frames verarbeiten .. */ +/*..................................................................... */ +void +l3tx(void) /* Level 3 Service */ +{ + UWORD rxgetc; /* Getcount des Frames */ + MBHEAD *mbp; /* Pointer auf aktuellen Framekopf */ + NODE *dstnod; + PEER *bestpp; + MHEARD *mhp; + + /* solange L3-Sende-Liste nicht leer */ + while ( (mbp = (MBHEAD *)l3txl.head) + != (MBHEAD *)&l3txl.head) + { + ulink((LEHEAD *)mbp); /* Frame aushaengen */ + dstnod = (NODE *)mbp->l2link; /* Pointer auf Nachbarn */ + if (dstnod == NULL) + dstnod = netp->nodetab + + find_node_this_ssid(mbp->destcall); + + if ( nmbfre > 14 /* Platz im Speicher? */ + && (valcal(dstnod->id) == YES) + && find_best_qual((int)(dstnod - netp->nodetab), + &bestpp, DG) > 0) + { + rwndmb(mbp); /* Pointer auf Ausgangsstellung */ + getchr(mbp); /* alles initialisieren */ + --mbp->mbbp; + rxgetc = mbp->mbpc; /* Framelaenge merken */ + mbp->mbpc = 1; /* auf Anfang */ + putfid(myid, mbp); /* Absender ins Frame */ + putfid(dstnod->id, mbp); /* Ziel ins Frame */ + *(mbp->mbbp - 1) |= 1; /* Ende der Adresse setzen */ +#ifdef __WIN32__ + putchr((char)timliv, mbp); /* Lebensdauer setzen */ +#else + putchr(timliv, mbp); /* Lebensdauer setzen */ +#endif /* WIN32 */ + mbp->mbpc = rxgetc; /* Putcount zurueck */ + rwndmb(mbp); /* Pointer wieder aufziehen */ + toneig(bestpp, mbp); /* Frame an besten Nachbarn */ + /* MH-Liste */ + if ((mhp = mh_lookup(&l3heard, dstnod->id)) != NULL) + mhp->tx_bytes += (mbp->mbpc); + } + else /* kein Ziel def. o. kein Platz */ + dealmb(mbp); /* Frame wegwerfen */ + } +} + +/*..................................................................... */ +/*.... sonstige Funktionen abarbeiten ............................... */ +/*..................................................................... */ +void +l3rest(void) +{ + if (brotim10) + brosrv2(); +} + +/*----------------------------------------------------------------------*/ +void +brosrv(void) +{ + static int tim10 = 1; + static int tim60 = 1; + + local_flex_srv(); /* Time-Server der anderen Module */ + + if (++tim60 >= 60) /* eine Minute vorbei */ + { + tim60 = 0; + brosrv60(); + } + + if (++tim10 >= 10) + { /* 10 Sekunden vorbei */ + drop_unreachable_nodes(); + tim10 = 0; + brotim10 = TRUE; + } +} + +static void +brosrv2(void) +{ + static int peer = 0; + int max_peers = netp->max_peers; + + if (++peer >= max_peers) + { + peer = 0; + brotim10 = FALSE; + } + + if (peer < max_peers) + brosrv10(peer); +} + +/************************************************************************/ +/* 10-sekuendlicher Zeitserver */ +/************************************************************************/ +static void +brosrv10(int i) +{ + PEER *pp = &netp->peertab[i]; + int broint; + + if (pp->used) /* nur benutzte Peers bearbeiten */ + { + if (pp->typ > NETROM) /* nur fuer NETROM und verwandte Protokolle */ + return; + + if (nmbfre < 300) /* nicht mehr genug Speicher */ + return; + +#ifdef THENETMOD + if (pp->typ == THENET) /* Segment ist ein THENET. */ + return; /* Funktion BroadCastBake() ist fuer den Rest verantwortlich. */ +#endif /* THENETMOD. */ + + if (pp->nbrl2l == NULL) /* noch kein Link? */ + return; /* den grossen UI-Broadcast sparen wir */ + /* uns, uns hoert ja eh keiner. */ + + /* wenn der Link sich noch im Aufbau befindet oder ziemlich verstopft */ + /* ist, wird die Nodes-Information zurueckgehalten. */ + if ( pp->nbrl2l->state < L2SIXFER + || pp->nbrl2l->tosend > 20) /* Link ist voll */ + return; + + /* Bei INP senden wir erst los, wenn beide Messungen da sind. */ + if (pp->typ == INP) + if (!pp->my_quality || !pp->his_quality) + return; + + /* Wollen wir einen INP-Link haben, haben einen Connect aber noch */ + /* nicht zu INP umgeschaltet und die RTT-Messung laeuft noch, dann */ + /* senden wir keinen Nodes-Broadcast irgendeiner Art */ + if ((pp->soll_typ == INP) && (pp->typ != INP) && (pp->rttstart != 0)) + return; + +#ifdef L4NOBAKE + if (pp->typ == NETROM) /* Steht noch ein Routing-Typ fest, senden */ + return; /* wir keine Bake irgendeiner Art. */ +#endif /* L4NOBAKE */ + + if (pp->typ != THENET) + inform_peer(pp, CHANGES); /* nur die Aenderungen durchsagen */ + + if (pp->typ != INP) + { + broint = (pp->typ == TNN) ? broint_i : broint_ui; + if (++pp->brotim >= broint) + { + /* Broadcast anfordern */ + pp->brotim = 0; + /* und weg damit */ + inform_peer(pp, ALL); + } + } + + /* Peer ist INP-Nachbar, den Broadcast-Timer geringfuegig anders */ + /* benutzen als bei den anderen Typen */ + if (pp->typ == INP) + { + if (++pp->brotim >= 360) /* jede Stunde einmal alles melden */ + { + pp->brotim = 0; /* merken dass wir gebroadcastet haben */ + brosrv360(netp->max_nodes, pp); + } + } + } +} + +/************************************************************************/ +/* minuetlicher Zeitserver */ +/************************************************************************/ +static void +brosrv60(void) +{ + INDEX index; + NODE *np; + ROUTE *rp; + PEER *pp; + int i; + int max_nodes = netp->max_nodes; + +#ifdef THENETMOD + BroadCastBake(); /* Eine Broadcast-Nodes Bake zum Nachbarn senden. */ +#endif /* THENETMOD */ + + /* alle Peers durchgehen */ + for (i = netp->max_peers, pp = netp->peertab; i--; pp++) + { + if (!pp->used) /* unbenutzte interessieren nicht */ + continue; + +#ifdef THENETMOD + if (OBSinitTimer(pp)) /* Restlebensdauer fuer Rundspruch minimieren. */ + continue; /* Segment wurde geloescht, zum naechsten. */ +#endif /* THENETMOD */ + + /* alle Nodes dieses Peers durchgehen */ + for (index = 0, np = netp->nodetab, rp = pp->routes; + index < max_nodes; + index++, np++, rp++) + { + if (np->id[0]) /* nur benutzte Eintraege */ + { + if (rp->lt > max_lt) /* bei zu hoher Lifetime abmelden */ + update_route(pp, index, 0); + + if (rp->timeout) /* Route mit Timeout ? */ + { + if (--rp->timeout == 0) /* Timeout abgelaufen ? */ + update_route(pp, index, 0); /* ja, dann abmelden */ + } + else + if (!pp->secured) /* ungesicherte Route ? */ +#ifndef THENETMOD + rp->timeout = ROUTE_TIMEOUT; /* dann Timeout neu setzen */ +#else + rp->timeout = obcini; /* dann Timeout neu setzen */ +#endif /* THENETMOD */ + } /* if (np->id[0]) */ + } /* for */ + } /* for */ +} + +/************************************************************************/ +/* stuendlicher Zeitserver */ +/************************************************************************/ +static void +brosrv360(int max_nodes, PEER *pp) +{ + NODE *np = netp->nodetab; + ROUTE *rp = pp->routes; + int x; + +#if MAX_TRACE_LEVEL > 2 + int node_count = 0; + char notify_call[10]; +#endif + + /* alle Eintraege durchgehen dabei keine Ruecksicht auf die */ + /* Horizonte nehmen, dies soll sicherstellen, dass hier auch */ + /* Nodes an den Nachbarn gemeldet werden die bisher immer */ + /* durch die Filter gefallen sind weil die Aenderungen zu */ + /* gering waren. */ + for (x = max_nodes; x--; np++, rp++) + { + if (!np->id[0]) /* freier Eintrag? */ + continue; + + /* Nodes die zur Abmeldung ausstehen nicht anfassen */ + if (rp->quality == 0 && rp->reported_quality != 0) + continue; + + rp->reported_quality = 0; /* Eintrag muss gemeldet werden */ +#if MAX_TRACE_LEVEL > 2 + node_count++; + } + call2str(notify_call, pp->l2link->call); + notify(3, "broadcasting INP nodes to %s (%u of %u nodes triggered for update)", notify_call, node_count, max_nodes); +#else + } +#endif +} + +/*----------------------------------------------------------------------*/ +/* 6 Zeichen aus Message-Puffer lesen und nach Buffer schreiben */ +/* Rueckgabe: TRUE = hat funktioniert */ +/*----------------------------------------------------------------------*/ +BOOLEAN +ge6chr(char *buffer, MBHEAD *mbp) +{ + int i, + ch; + + for (i = 6; + (mbp->mbpc > mbp->mbgc) && i; /* noch Zeichen da? */ + i--) + { + *buffer++ = ch = getchr(mbp); + if (ch < ' ') + return (FALSE); /* ungueltiges Zeichen */ + if (ch > 127) + return (FALSE); + } + return (i == 0); /* waren genug Zeichen da? */ +} + +/************************************************************************/ +/* 6 Zeichen aus Buffer in Message-Puffer schreiben */ +/************************************************************************/ +void +pu6chr(char *buffer, MBHEAD *mbp) +{ + WORD i; + + for (i = 0; i < 6; ++i) + putchr(*buffer++, mbp); +} + +/************************************************************************/ +/* Eine Status-Aenderung fuer NET/ROM behandeln */ +/************************************************************************/ +static void +netrom_status(PEER *pp, WORD status) +{ +#ifdef PORT_L2_CONNECT_TIME + UWORD port = 0; +#endif + if (pp->typ <= NETROM) + { /* nur NET/ROM interessiert */ + switch (status) + { + case L2MCONNT: + connect_peer(pp); + break; + + case L2MLREST: + case L2MLRESF: + reset_peer(pp); + 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 */ + + if ( (pp->typ != THENET) /* Alle Typen ausser THENET. */ + ||((pp->typ == THENET) /* oder THENET-Typ und */ + && (status == L2MFAILW))) /* Status FAILURE. */ + { /* Route als ausgefallen melden. */ + update_peer_quality(pp, 0L, DONT_CHANGE_QUAL); + memset(pp->routes, 0, netp->max_nodes * sizeof(ROUTE)); + pp->num_routes = 0; /* Routen loeschen */ + drop_unreachable_nodes(); /* Routes/Nodes loeschen */ + +#ifdef AUTOROUTING + if (pp->l2link->ppAuto == AUTO_ROUTE)/* Segment ist eine 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; + } +#endif /* AUTOROUTING */ + + } + + break; + + default: + disconnect_peer(pp); + update_peer_quality(pp, 0, DONT_CHANGE_QUAL); + check_all_destot(); + break; + } + pp->rttstart = 0; + pp->rtt_time = 0; + switch (pp->typ) + { + case TNN: + case INP: + set_peer_typ(pp, NETROM); + } + pp->brotim = 0; /* mit Broadcast beginnen */ + } +} + +/*----------------------------------------------------------------------*/ +/* eine Status-Aenderung an alle L3-Module senden */ +/* Die Module muessen selber darauf achten, das sie die Meldung nur */ +/* annehmen, wenn der Typ des pp stimmt! */ +/*----------------------------------------------------------------------*/ +static void +mstatus(PEER *pp, WORD status) +{ + netrom_status(pp, status); /* neuen Status melden */ + flex_status(pp, status); /* an NETROM & FlexNet */ + local_status(pp, status); /* und unsere Locals */ +} + +/*----------------------------------------------------------------------*/ +/* Neue Status-Meldung verarbeiten */ +/* 0=nicht verwendet, 1=connectet, 2=disconnectet, 3=busy, 4=Failure */ +/*----------------------------------------------------------------------*/ +BOOLEAN +l2tol3(WORD status) +{ + PEER *pp; +#if MAX_TRACE_LEVEL > 2 + char notify_call[10]; +#endif + + switch (status) + { + case L2MCONNT: /* CONNECTED to */ + case L2MLREST: /* LINK RESET to */ + if ((pp = ispeer()) == NULL) + return (l2toip(status)); /* der L7 ist dran */ + newnbr(pp); /* Nachbar eintragen */ + mstatus(pp, status); /* Status melden */ + return (TRUE); /* Status verarbeitet */ + + case L2MLRESF: /* LINK RESET from */ + if ((pp = ispeer()) == NULL) + return (l2toip(status)); /* der L7 ist dran */ + mstatus(pp, status); /* Status melden */ + disnbr(pp); /* Nachbar inaktiv */ + newnbr(pp); /* Nachbar eintragen */ + mstatus(pp, status); /* Status melden */ +#if MAX_TRACE_LEVEL > 2 + call2str(notify_call, rxfhdr + L2IDLEN); + notify(3, "Linkreset %6s", notify_call); +#endif + return (TRUE); /* Status verarbeitet */ + + case L2MDISCF: /* DISCONNECTED from */ + case L2MBUSYF: /* BUSY from */ + case L2MFAILW: /* LINK FAILURE with */ + if ((pp = ispeer()) == NULL) + return (l2toip(status)); /* der L7 ist dran */ +#ifdef AXIPR_UDP + newnbr(pp); /* Nachbar eintragen */ +#endif + mstatus(pp, status); /* melden */ + disnbr(pp); /* Nachbar inaktiv */ +#ifdef AUTOROUTING + /* Segment steht auf Auto-Route. */ + if (pp->l2link->ppAuto == AUTO_ROUTE) + return(FALSE); + else +#endif /* AUTOROUTING */ + return (TRUE); /* nicht in den L7 */ + + case L2MFRMRF: /* FRAME REJECT from */ + case L2MFRMRT: /* FRAME REJECT to */ + if ((pp = ispeer()) == NULL) + return (l2toip(status)); /* der L7 ist dran */ + return (TRUE); /* Status verarbeitet */ + + case L2MBUSYT: /* BUSY to */ + return (TRUE); /* hier abfangen */ + } + + return (FALSE); /* ungueltige Meldung */ +} + +/************************************************************************\ +* * +* "to level 3 switch" * +* * +* Aus I- oder UI-Frame (Framekopf fbp, Getzeiger/Zaehler auf 1. Byte * +* hinter Level-2-Adressfeld) PID holen, falls vorhanden. Falls es nicht * +* Level-2-PID ist, das Paket an die Level-3-Empfangsframeliste l3rxfl * +* haengen. Im Framekopf wird in jedem Fall l2fflg auf PID, wenn * +* vorhanden, oder 0 gesetzt, l2link auf den aktuellen Link (lnkpoi). * +* Fuer Level-3-Frames wird der Nachbar bestimmt. * +* * +* Return: TRUE - das I/UI-Frame hat ein Nicht-Level-2-PID und wurde an * +* die Level-3-Empfangsframeliste gehaengt * +* FALSE - Frame hat Standard-Level-2-PID * +* * +\************************************************************************/ +BOOLEAN +tol3sw(MBHEAD *fbp) +{ + PEER *pp; + UBYTE pid = fbp->l2fflg; + int state; + int filter_ip_frame; + + fbp->l2link = lnkpoi; /* Linkverbindung von diesem Frame */ + fbp->l2port = rxfprt; /* Auf diesem Port kam das Frame */ + + if (lnkpoi) + { + state = ptctab[g_uid(lnkpoi, L2_USER)].state; + filter_ip_frame = (state == D_IPLINK || state == U_IPLINK); + } + else + filter_ip_frame = TRUE; + +/* Protokolle, die nicht an einen Nachbarn gebunden sind, direkt */ +/* abfangen */ + switch (pid) + { +#ifdef IPROUTE + case L2CIP: + if (filter_ip_frame) + { + if (fbp->l2link) /* fuer Level 2 Links Info zaehlen */ + ptctab[g_uid(fbp->l2link, L2_USER)].inforx + += (fbp->mbpc - fbp->mbgc); + + relink((LEHEAD *)fbp, (LEHEAD *)iprxfl.tail); + return (TRUE); /* Frame verarbeitet */ + } + else + break; + + case L2CARP: + if (filter_ip_frame) + { + if (fbp->l2link) /* fuer Level 2 Links Info zaehlen */ + ptctab[g_uid(fbp->l2link, L2_USER)].inforx + += (fbp->mbpc - fbp->mbgc); + + relink((LEHEAD *)fbp, (LEHEAD *)arprxfl.tail); + return (TRUE); /* Frame verarbeitet */ + } + else + break; +#endif + +#ifdef L2PROFILER + case 0x12: /* Spielzeug fuer DB7KG (PID 12) */ + dealmb(fbp); + return (TRUE); +#endif + } + +#ifndef AUTOROUTING + if ((pp = ispeer()) == NULL) /* kein Frame fuer einen Nachbarn? */ + return (FALSE); /* zum Level 7 durchlassen */ +#else + /* Pruefen, ob sich jemand Automatisch anbinden will. */ + /* Wir untersuchen anhand der PID das Segment. */ + if ((pp = ReadLink(pid)) == NULL) + return (FALSE); /* zum Level 7 durchlassen */ +#endif + +/* Hier landen nur Frames, die zu einem bestimmten Nachbarn gehoeren. */ +/* Nun muss noch Protokoll-ID und Protokoll verglichen werden. */ + + if (fbp->l2link) /* fuer Level 2 Links Info zaehlen */ + ptctab[g_uid(fbp->l2link, L2_USER)].inforx + += (fbp->mbpc - fbp->mbgc); + + switch (fbp->l2fflg) + { +/* Protokoll/Nachbartyp feststellen */ +/* NET/ROM-Protokoll fuer TheNet, TheNetNode, TNX1J(TexNet) */ +/* KA9Q und Devirate, Wampes, Linux usw., BPQ, andere Switches */ + case L2CTEXNET: /* fuer TexNet/TheNetX1J */ + case L2CNETROM: + if (pp->typ > NETROM) + break; /* nicht richtiger Nachbar-Typ? */ + rxneig(pp, fbp); /* Frame zur Nachbar-Bearbeitung */ + return (TRUE); /* ... und fertig */ + + /* Flexnet Protokoll fuer */ + case L2CFLEXNET: /* Flexnet eben, BayCom, Digiware */ + if (pp->typ != FLEXNET) + break; + if (lnkpoi == NULL) + break; /* UI-Frames sind verboten */ + rxneig(pp, fbp); /* FlexNet-Internode-Frame */ + return (TRUE); /* toL7: Frame verarbeitet */ + +#ifdef IPROUTE /* IP/ARP auf Interlink ist erlaubt */ + case L2CIP: + relink((LEHEAD *)fbp, (LEHEAD *)iprxfl.tail); + return (TRUE); /* Frame verarbeitet */ + + case L2CARP: + relink((LEHEAD *)fbp, (LEHEAD *)arprxfl.tail); + return (TRUE); /* Frame verarbeitet */ +#endif + } + dealmb(fbp); /* unpassende/unbekannte PID, falscher */ + /* Nachbar, Fehler... */ + return (TRUE); +} + +/*----------------------------------------------------------------------*/ +/* Kopiert zwei Calls ins Ziel (via-Beschraenkung fuer Linkeintraege) */ +/*----------------------------------------------------------------------*/ +void +cpyidl2(char *dest, const char *source) +{ + int count = 2; + + while (*source != '\0' && count-- > 0) + { + memcpy(dest, source, L2IDLEN); + source += L2IDLEN; + dest += L2IDLEN; + } + *dest = '\0'; +} + +#define TO 0 /* dir */ +#define BACK 1 + +#define NOTKNOWN 1 /* tome und ret */ +#define ISLOCAL 2 +#define VIAFLEX 3 +#define DIRECT 4 +#define LOOPED 5 + +/* Diese Funktion analysiert die empfangenen NRR-Frames. */ +/* Etliche Fehler werden erkannt und entsprechend reagiert. */ +/* */ +/* tome gibt an, ob mich das Frame was angeht */ +/* ret besagt, ob das Frame zurueckgeschickt werden soll und wieso */ +/* dir gibt die NRR-Richtung an */ +/* looped ist wahr, wenn unsere ID im Hinweg vorkam und dir gleich TO */ +void +nrr_rx(MBHEAD *mbp, PEER *rxpp) +{ + NRRLIST list[30], + *l; + int nlist, + ret, + tome, + dir; + BOOLEAN looped; + PEER *topp; + + if (!time_to_live) /* zuspaet */ + return; + + + looped = tome = ret = FALSE; + dir = TO; + topp = NULL; + + if (cmpid(desnod, myid)) /* das geht uns an... */ + tome = DIRECT; + else if (iscall(desnod, NULL, /* sonst den besten Weg */ + &topp, DG | VC | VC_FAR)) + { /* bestimmen */ + if (topp->options & VC) /* ein local von uns */ + tome = ISLOCAL; + else if (topp->options & VC_FAR) /* wuerde via flex gehen */ + tome = VIAFLEX; + } + + nlist = 0; + l = list; + while (mbp->mbpc - mbp->mbgc >= L2IDLEN + 1) + { /* Eintrag da? */ + if (getfid(l->id, mbp) == TRUE) + { + l->lt = getchr(mbp); + if (l->lt & ECHO_FLAG) + { /* EchoFlag */ + dir = BACK; + looped = FALSE; + } + if (dir == TO && cmpid(l->id, myid)) /* Loop in Hin-Liste */ + looped = TRUE; + nlist++; + l++; + } + } + l->id[0] = '\0'; /* Liste beenden */ + + if ( !nlist /* leere Liste */ + || rxpp == topp) /* Loop in den Nodes */ + return; + + if (cmpid(list[0].id, myid)) + { /* das ist meine Anwort */ + nrr2usr(list, time_to_live); + return; + } + + if (dir == BACK && ( topp == NULL /* Ziel unbekannt */ + || tome == VIAFLEX)) /* bzw. Flex im Rueckweg */ + return; + + + if (topp == NULL && !tome) /* Ziel unbekannt */ + ret = NOTKNOWN; + else if (looped) /* Loop in der Liste */ + ret = LOOPED; + else if (tome) /* wir sind das Ziel */ + ret = tome; + + if (ret) + { /* Weg umdrehen */ + cpyid(desnod, orgnod); + cpyid(orgnod, myid); + } + + if (nlist < 29) + { /* wir passen noch dran */ + cpyid(l->id, myid); + l->lt = time_to_live + 1; + if (ret) + { + l->id[L2CALEN] &= 0x1f; + l->id[L2CALEN] |= (ret - 1) << 5; /* Fehler in SSID-Feld */ + l->lt |= ECHO_FLAG; + } + l++; + l->id[0] = '\0'; /* Liste beenden */ + } + + send_nrr_frame(list); +} + +/* Hier wird das NRR-Frame zusammengebastelt und verschickt */ +void +send_nrr_frame(NRRLIST *l) +{ + PEER *pp; + NODE *dstnod; + MBHEAD *mbp; + + if (iscall(desnod, &dstnod, &pp, DG)) + { + mbp = (MBHEAD *)allocb(ALLOC_MBHEAD); + + putfid(orgnod, mbp); + putfid(desnod, mbp); + putchr(time_to_live, mbp); + putchr(l4hdr0, mbp); + putchr(l4hdr1, mbp); + putchr(l4hdr2, mbp); + putchr(l4hdr3, mbp); + putchr(l4hdr4, mbp); + while (*l->id) + { + putfid(l->id, mbp); + putchr(l->lt, mbp); + l++; + } + rwndmb(mbp); + toneig(pp, mbp); + } +} + +/*----------------------------------------------------------------------*/ +/* Diese Routine bereitet das Senden des NRR-Requestframes vor */ +void +request_nrr(char *id, UID uid) +{ + NRRLIST list[2]; + + cpyid(desnod, id); /* L3-Teil */ + cpyid(orgnod, myid); +#ifdef __WIN32__ + time_to_live = (char)timliv; +#else + time_to_live = timliv; +#endif /* WIN32 */ + + l4hdr0 = 0; /* L4-Teil */ + l4hdr1 = 1; + + l4hdr2 = uid >> 8; + l4hdr3 = uid & 0xFF; + l4hdr4 = 0; + + cpyid(list[0].id, myid); /* Daten */ + list[0].lt = time_to_live + 1; + list[1].id[0] = NUL; + + send_nrr_frame(list); +} + +/*----------------------------------------------------------------------*/ +/* Diese Routine ermittelt, ob es auf einem Port Interlinks gibt */ +BOOLEAN islinkport(int port) +{ + PEER *pp; + int i; + + for (i = 0, pp = netp->peertab; i < max_peers; i++, pp++) + if ((pp->used) && (pp->l2link->port == port)) + return TRUE; + + return FALSE; +} + +/* TEST DG9OBU */ +/*----------------------------------------------------------------------*/ +/* Prueft, ob das Call id ein lokaler Eintrag bei uns ist. */ +/* NO = kein Local von uns */ +/* YES = ein Local von uns UND erreichbar (oder Local ohne Messung) */ +/* ERRORS = ein Local von uns, aber derzeit nicht erreichbar */ +/*----------------------------------------------------------------------*/ +TRILLIAN islocal(const char* id) +{ + PEER *pp; + register int i; + register int max_peers = netp->max_peers; + + for (i = 0, pp = netp->peertab; i < max_peers; ++i, pp++) + { + if ( (pp->used) + && (cmpid(id, pp->l2link->call)) /* Call + SSID stimmt */ + ) + { + if (pp->typ == LOCAL) + return YES; + else if (pp->typ == LOCAL_M) + return (pp->my_quality != 0) ? YES : ERRORS; + } + } + + /* kein Local von uns */ + return NO; +} + +#ifdef PROXYFUNC +BOOLEAN isproxy(const char* id) +{ + PEER *pp; + register int i; + register int max_peers = netp->max_peers; + + for (i = 0, pp = netp->peertab; i < max_peers; ++i, pp++) + { + if ( (pp->used) + && (cmpid(id, pp->l2link->call)) /* Call + SSID stimmt */ + ) + { + if (pp->proxy == TRUE) + return TRUE; + } + } + + /* kein Local von uns */ + return FALSE; +} +#endif + +/* TEST DG9OBU */ +/*----------------------------------------------------------------------*/ +/* Bestimmt die aktuelle SSID-Range des Knotens. Es werden alle lokalen */ +/* Nodes mit dem gleichen Call wie der Knoten, sowie das Knotencall */ +/* selber ausgewertet. Die uebergebenen Variablen werden nur geaendert, */ +/* wenn der aktuelle SSID-Bereich von den uebergebenen Werten abweicht. */ +/*----------------------------------------------------------------------*/ +void getSSIDrange(int *min, int *max) +{ + PEER *pp; + register int i; + + /* Knotencall auswerten */ + if (SSID(myid) < *min) + *min = SSID(myid); + + if (SSID(myid) > *max) + *max = SSID(myid); + + /* Alle lokalen Links auswerten */ + for (i = 0, pp = netp->peertab; i < max_peers; ++i, pp++) + if ( (pp->used) /* nur benutzte Eintraege auswerten */ + && (cmpcal(myid, pp->l2link->call)) /* Call stimmt, SSID egal */ + && (pp->l2link->alias[0] != '#') /* keine versteckten Locals */ + && ( (pp->typ == LOCAL) /* nur Locals, L+ muss erreichbar sein */ + || ((pp->typ == LOCAL_M) /* && (pp->my_quality != 0L) */ ) + ) + ) + { + if (SSID(pp->l2link->call) < *min) + *min = SSID(pp->l2link->call); + + if (SSID(pp->l2link->call) > *max) + *max = SSID(pp->l2link->call); + } +} + +/* TEST DG9OBU */ +/*----------------------------------------------------------------------*/ +/* Bestimmt die aktuelle maximale SSID des Knotens. */ +/* Naeheres siehe Funktion getSSIDrange(). */ +/*----------------------------------------------------------------------*/ +int maxSSID(void) +{ + int ssid_low = 15; + int ssid_high = 0; + + getSSIDrange(&ssid_low, &ssid_high); + + return ssid_high; +} + +/* TEST DG9OBU */ +/*----------------------------------------------------------------------*/ +/* Bestimmt, ob die uebergebene SSID im SSID-Bereich des Knotens liegt. */ +/*----------------------------------------------------------------------*/ +BOOLEAN SSIDinrange(int ssid) +{ + int ssid_low = 15; + int ssid_high = 0; + + getSSIDrange(&ssid_low, &ssid_high); + + if ((ssid >= ssid_low) && (ssid <= ssid_high)) + return TRUE; + + return FALSE; +} + +#ifdef AUTOROUTING +static int UpdateLink(char *call, int port, UWORD pid, PEER *pp) +{ + switch(pid) + { + case L2CTEXNET: /* THENET, NETROM oder INP-TYP */ + case L2CNETROM: +#ifdef AXIPR_HTML + SetHTML(port, /* Protokoll fuer HTML-Ausgabe setzen. */ + call, + pp, + TRUE); +#endif /* AXIPR_HTML */ + + switch (portpar[port].poAuto) /* Modus. */ + { + case L_THENET : /* THENET-TYP. */ + return(THENET); /* THENET-TYP setzen. */ + + case L_INP : /* INP-TYP. */ + return(INP); /* INP-TYP setzen. */ + + case L_INPFLEX : /* Voll-Modus. */ + return(NETROM); /* Standard NETROM-Typ setzen. */ + + default : + return(EOF); /* Kein Eintrag liefern. */ + } + + break; + + + case L2CFLEXNET: /* FLEXNET-TYP */ +#ifdef AXIPR_HTML + SetHTML(port, /* Protokoll fuer HTML-Ausgabe setzen. */ + call, + pp, + TRUE); +#endif /* AXIPR_HTML */ + + switch (portpar[port].poAuto) /* Modus. */ + { + case L_FLEXNET : + case L_INPFLEX : + return(FLEXNET); /* FLEXNET-TYP setzen. */ + + default: + return(EOF); /* Kein Eintrag liefern. */ + } + } /* Switch */ + + return(EOF); /* Kein Eintrag liefern. */ +} + +/********************************************************/ +/* */ +/* Neues Segment anlegen. */ +/* Je nach PID wird Link-Typ gesetzt. */ +/* */ +/********************************************************/ +static PEER *AddLink(UWORD pid) +{ + PEER *pp = NUL; + char digil[L2VLEN + 1] = ""; + WORD typs = EOF; + + if ((pp = ispeer()) == NULL) + { +#ifdef LINKSMODINFO + char Info[INFOSIZE + 1] = "AutoRoute"; +#endif /* LINKSMODINFO */ + + /* Segment Updaten und Typ setzen. */ + if ((typs = UpdateLink(rxfhdr + L2IDLEN, rxfprt, pid, pp)) == EOF) + return(NULL); + + cpyid(digil, dheardcall(rxfhdr)); + + if (cmpid(rxfhdr + L2IDLEN, digil)) + digil[0] = 0; + + /* Einen Neuen Link-Nachbar eintragen. */ + pp = register_neigb(rxfhdr + L2IDLEN, digil, rxfhdr + L2IDLEN, rxfprt, typs +#ifdef LINKSMODINFO + , Info +#endif /* LINKSMODINFO */ + , AUTO_ROUTE); + + /* Linkeintragung fehlgeschlagen. */ + if (pp == NULL) + /* Kein Eintrag liefern. */ + return(NULL); + + /* Den aktuellen Nachbarn als connected eintragen.*/ + newnbr(pp); + + /* Nachbar ist ein Flexnet. */ + if (pp->typ == FLEXNET) + /* Maxtime auf default stellen. */ + pp->maxtime = 30000U; + + /* Neues Segment liefern. */ + return(pp); + } + + /* Segment Updaten. */ + UpdateLink(rxfhdr + L2IDLEN, rxfprt, pid, pp); + + /* Segment liefern. */ + return(pp); +} + +/*****************************************************/ +/* */ +/* Pruefen, ob sich jemand Automtisch anbinden will. */ +/* Anhand der PID wird das Segment ermittelt. */ +/* */ +/*****************************************************/ +static PEER *ReadLink(UBYTE pid) +{ + PEER *pp; + + if ((pp = AddLink(pid)) == NULL) + /* Kein Segment gefunden. */ + return(NULL); + + /* Aktuelles Segment liefern. */ + return(pp); +} +#endif /* AUTOROUTING */ + +/* End of src/l3misc.c */ diff --git a/src/l3nbr.c b/src/l3nbr.c new file mode 100755 index 0000000..01fae0a --- /dev/null +++ b/src/l3nbr.c @@ -0,0 +1,482 @@ +/************************************************************************/ +/* */ +/* ***** ***** */ +/* ***** ***** */ +/* ***** ***** */ +/* ***** ***** */ +/* *************** *************** */ +/* ***************** ***************** */ +/* *************** *************** */ +/* ***** ***** TheNetNode */ +/* ***** ***** Portable */ +/* ***** ***** Network */ +/* ***** ***** Software */ +/* */ +/* File src/l3nbr.c (maintained by: ???) */ +/* */ +/* This file is part of "TheNetNode" - Software Package */ +/* */ +/* Copyright (C) 1998 - 2008 NORD>nbrl2l) != NULL) + dsclnk(); /* disconnect link, dealml ... */ + lnkpoi = save_lp; +} + +/* einen Nachbarn austragen */ +#ifndef LINKSMOD_MSG +void +unregister_neigb(const char *id, const char *via, int port) +#else +BOOLEAN unregister_neigb(const char *id, const char *via, int port) +#endif /* LINKSMOD_MSG */ +{ + char digi_list[2 * L2IDLEN + 1]; + PEER *pp; /* Buffer fuer Eintrag */ + + cpyidl2(digi_list, via); /* nur maximal 2 Digipeater! */ + pp = getnei(digi_list, id, port); + if (!pp) +#ifndef LINKSMOD_MSG + return; +#else + return(FALSE); +#endif /* LINKSMOD_MSG */ + + update_peer_quality(pp, 0L, 0L); /* als ausgefallen melden */ + + if (pp->nbrl2l) /* noch connected? */ + discnbp(pp); + + dealoc((MBHEAD *)pp->l2link); + unregister_peer(pp); +#ifdef LINKSMOD_MSG + return(TRUE); +#endif /* LINKSMOD_MSG */ +} + +/* einen neuen Nachbarn eintragen */ +PEER * +register_neigb(const char *id, const char *via, const char *alias, + int port, int typ +#ifdef LINKSMODINFO + ,const char *info +#endif /* LINKSMODINFO */ +#ifdef AUTOROUTING + , UWORD Status +#endif /* AUTOROUTING */ +) + +{ + L2LINK *p; + char digi_list[2 * L2IDLEN + 1]; + PEER *pp; + INDEX index; + +#ifdef PROXYFUNC + BOOLEAN ppproxy; + ppproxy = (typ & PROXYMASK) ? TRUE : FALSE; + typ &= PROXYMASK - 1; +#endif + + cpyidl2(digi_list, via); /* nur maximal 2 Digipeater! */ + pp = getnei(digi_list, id, port); + + if (pp != NULL) + { /* wir kennen den Nachbarn */ + index = find_node_this_ssid(id); + if (update_alias(index, alias)) /* Alias hat sich geaendert */ + { + p = pp->l2link; + cpyals(p->alias, alias); + propagate_node_update(index); + } + return (pp); /* Eintrag liefern */ + } + + if ((pp = register_peer()) == NULL) + return (NULL); + + p = pp->l2link = (L2LINK *)allocb(ALLOC_L2LINK); /* Platz f. L2-Link */ + +/* Diese beiden Eintraege werden sofort von aussen neu gesetzt. */ +/* Bei NET/ROMs wird der alias selbstaendig bestimmt, die Qualitaet */ +/* ist nur fuer ungemessene Links der Vorgabe-Wert. */ + + cpyid(p->call, id); /* Call eintragen */ + cpyidl2(p->digil, digi_list); /* maximal 2 Digis eintragen */ + cpyals(p->alias, alias); /* Alias eintragen */ + p->port = port; /* Port eintragen */ + p->ssid_high = SSID(id); /* noch keine Grenze bekannt */ + +#ifdef LINKSMODINFO + memset(p->info, 0, sizeof(p->info)); + strncpy(p->info, info, INFOSIZE); +#endif /* LINKSMODINFO */ + +#ifdef AUTOROUTING + p->ppAuto = Status; /* Fixed/Auto-Route eintragen. */ +#endif + +#ifdef PORT_L2_CONNECT_TIME + p->sabmtime = 0; +#endif + + pp->soll_typ = typ; /* soll ein Link dieses Typs werden */ + if (typ == TNN || typ == INP) + typ = NETROM; /* werden automatisch erkannt */ + +#ifdef PROXYFUNC + pp->proxy = ppproxy; +#endif + set_peer_typ(pp, typ); /* ist derzeit ein Link dieses Typs */ + + pp->nbrl2l = NULL; /* kein L2 Link vorhanden */ + pp->version = 0; /* unbekannte Version */ + pp->rttstart = 0; /* keine Messung unterwegs */ + pp->rtt_time = 0; /* schnell messen */ + pp->brotim = 0; /* Broadcast Timer */ + +#ifdef CONNECTTIME + pp->contime = 0; /* Connectzeit zuruecksetzen. */ +#endif /* CONNECTTIME */ + +#ifdef THENETMOD + if (typ == THENET) /* Nur wenn THENET-TYP ist, */ + { + pp->brotim = broint_ui; /* Broadcast-Timer setzen. */ + pp->obscnt = 0; /* Restlebensdauer fuer Rundspruch zuruecksetzen. */ + } +#endif /* THENETMOD */ + + pp->options = (typ <= NETROM) ? /* Datagramm oder VirtualConnect */ + DG : + (typ == FLEXNET) ? /* FlexNet oder Local? */ + VC_FAR : VC; + + inithd(&(pp->rxfl)); /* Empfangsliste */ + + if (typ == LOCAL) + { /* erste Messung simulieren */ +#ifndef LOCAL_ROUTEFIX + if ((index = add_route(pp, id, 400)) != NO_INDEX) +#else + if ((index = add_route(pp, id, 10)) != NO_INDEX) /* 10ms setzen. */ +#endif /* LOCAL_ROUTEFIX */ + { + update_alias(index, alias); + update_lt(pp, index, 1); + } + pp->quality = 1; /* Messung simulieren */ + } + +#ifdef LINKSMOD_LOCALMOD + if (typ == LOCAL_N) + { /* erste Messung simulieren */ + if ((index = add_route(pp, id, 10)) != NO_INDEX) + { + update_alias(index, alias); + update_lt(pp, index, 1); + } + pp->quality = 1; /* Messung simulieren */ + } + + if (typ == LOCAL_V) + { /* erste Messung simulieren */ + if ((index = add_route(pp, id, 10)) != NO_INDEX) + { + update_alias(index, alias); + update_lt(pp, index, 1); + } + pp->quality = 1; /* Messung simulieren */ + } +#endif /* LINKSMOD_LOCALMOD */ + + update_primary_peer(pp->l2link->call); + + return (pp); /* mit Pointer auf Eintrag zurueck */ +} + +/************************************************************************/ +/* */ +/* Eine neue Verbindung zum Nachbarn herstellen. */ +/* */ +/************************************************************************/ +BOOLEAN +connbr(PEER *pp) +{ + char id[L2IDLEN]; +#if MAX_TRACE_LEVEL > 2 + char notify_call[10]; +#endif + + cpyid(id, myid); + if (pp->typ == LOCAL_M) + id[L2IDLEN - 1] = (testid << 1) | 0x60; + +#ifdef __WIN32__ + lnkpoi = getlnk((unsigned char)pp->l2link->port, id, pp->l2link->call, pp->l2link->digil); +#else + lnkpoi = getlnk(pp->l2link->port, id, pp->l2link->call, pp->l2link->digil); +#endif /* WIN32 */ + + if (lnkpoi) + { /* gabs noch einen freien Eintrag? */ + if (lnkpoi->state == L2SDSCED) + { + newlnk(); /* Verbindung erstellen */ + pp->nbrl2l = lnkpoi; + return (TRUE); + } +#if MAX_TRACE_LEVEL > 2 + call2str(notify_call, pp->l2link->call); + notify(3, "%s: dsclnk in connbr", notify_call); +#endif + dsclnk(); + } + return (FALSE); +} + +/*----------------------------------------------------------------------*/ +/* Den aktuellen Nachbarn als disconnected eintragen. */ +/*----------------------------------------------------------------------*/ +void +disnbr(PEER *pp) +{ + if (pp->nbrl2l == NULL) + return; + ptctab[g_uid(pp->nbrl2l, L2_USER)].state = 0; + if (pp->nbrl2l) + { + pp->nbrl2l = NULL; + dealml((LEHEAD *)&pp->rxfl); /* nur rx loeschen, den */ + /* Rest macht die Abmeldung */ + } +} + +/*----------------------------------------------------------------------*/ +/* Nachbarn in Nachbarliste suchen */ +/*----------------------------------------------------------------------*/ +PEER * +getnei(const char *digil, const char *call, int port) +{ + 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 (isneig(digil, call, port, pp)) + return (pp); + return (NULL); +} + +/*----------------------------------------------------------------------*/ +/* Stimmen Digipeaterliste (digis), Rufzeichen (call) und Port mit dem */ +/* Eintrag in die Nachbarnliste (nachp) ueberein? */ +/* Rueckgabe: TRUE=ja, FALSE=nein */ +/*----------------------------------------------------------------------*/ +static BOOLEAN +isneig(const char *digis, const char *call, int port, PEER *pp) +{ + if (pp->l2link->port != port) + return (FALSE); + if (cmpid(pp->l2link->call, call) == FALSE) + return (FALSE); + if (cmpidl(digis, pp->l2link->digil) == FALSE) + return (FALSE); + + return (TRUE); +} + +/*----------------------------------------------------------------------*/ +/* Ein Frame an einen Nachbarn senden. */ +void +toneig(PEER *pp, MBHEAD *mbp) +{ +#ifdef THENETMOD + if (pp->nbrl2l == NULL) /* Link ist nicht aktiv. */ + connbr(pp); /* Eine neue Verbindung zum Nachbarn herstellen. */ +#endif /* THENETMOD */ + + if ((lnkpoi = pp->nbrl2l) != NULL) /* L2-Link vorhanden? */ + i3tolnk(L2CNETROM, pp->nbrl2l, mbp); + else + dealmb(mbp); /* sonst wegwerfen */ +} + +/*----------------------------------------------------------------------*/ +/* Den aktuellen Nachbarn als connected eintragen. */ +/*----------------------------------------------------------------------*/ +void +newnbr(PEER *pp) +{ + + pp->nbrl2l = lnkpoi; /* Link eintragen */ + +#ifdef THENETMOD + if (pp->nbrl2l != NULL) /* Nur wenn Segment aktiv ist. */ + ptctab[g_uid(pp->nbrl2l,L2_USER)].state = PEERLINK; +#else + ptctab[g_uid(lnkpoi, L2_USER)].state = PEERLINK; +#endif /* THENETMOD */ +} + +/*----------------------------------------------------------------------*/ +/* Ist der neue Link ein erlaubter Nachbar ? */ +/* Wenn ja: Pointer auf die Nachbarstruktur zurueck, sonst NULL. */ +/*----------------------------------------------------------------------*/ +PEER * +ispeer(void) +{ + L2LINK *p; + PEER *pp; + int i; + int max_peers = netp->max_peers; + char *srcid; + + for (i = 0, pp = netp->peertab; i < max_peers; i++, pp++) + if (pp->used) + { + p = pp->l2link; /* Pointer auf den eingetragenen Link */ + if (lnkpoi) + { + if (pp->nbrl2l == lnkpoi) + return (pp); + if ( !cmpid(p->call, lnkpoi->dstid) + || !cmpidl(p->digil, lnkpoi->viaidl) + || (p->port != lnkpoi->liport)) + continue; + } + else + { + if ( !cmpid(p->call, &rxfhdr[L2IDLEN]) + || !cmpidl(p->digil, &txfhdr[L2ILEN]) + || (rxfprt != p->port)) + continue; + + return ((pp->typ <= NETROM) ? pp : NULL); + } + + srcid = (lnkpoi == NULL) ? rxfhdr : lnkpoi->srcid; + +#ifndef LINKSMOD_LOCALMOD + if (pp->typ != LOCAL) +#else + if (pp->typ >= LOCAL) +#endif /* LINKSMOD_LOCALMOD */ + { + if (cmpcal(myid, srcid)) + { + if (pp->typ == LOCAL_M) + { + if (srcid[L2IDLEN - 1] == ((testid << 1) | 0x60)) + return (pp); + } + else + { + if ((srcid[L2IDLEN - 1] & 0x1E) == (myid[L2IDLEN - 1] & 0x1E)) + return (pp); + } + } + } + } + return (NULL); +} + +/************************************************************************\ +* * +* "rx frame to neigbour" * +* * +* Ein L3-Frame wurde empfangen und wird hier an den entsprechenden * +* Nachbarpointer zur weiteren verarbeitung angehaengt. * +* * +\************************************************************************/ +void +rxneig(PEER *pp, MBHEAD *fbp) +{ + relink((LEHEAD *)fbp, (LEHEAD *)pp->rxfl.tail); /* ok->weiter */ +} + +#ifdef LINKSMOD_LOCALMOD +BOOLEAN CheckLocalLink(const char *call) +{ + PEER *pp; + int i; + int max_peers = netp->max_peers; + + if (call[0] == FALSE) + return(FALSE); + + /* Durchsuche die Segment-Liste. */ + for (i = 0, pp = netp->peertab; i < max_peers; i++, pp++) + { + if (pp->used) /* Nur benutze Eintraege interessieren. */ + { + if (cmpid(pp->l2link->call, call)) /* Callvergleich. */ + { + if ( (pp->typ == LOCAL_N) + ||(pp->typ == LOCAL_V)) + return(TRUE); /* Ist eine LOCAL-Route "L-" oder "L#" */ + } + } /* unbenutzter Eintrag. */ + } /* for */ + + return(FALSE); /* Rufzeichen ist kein LOCAL. */ +} +#endif /* LINKSMOD_LOCALMOD */ + +/* End of src/l3nbr.c */ diff --git a/src/l3netrom.c b/src/l3netrom.c new file mode 100755 index 0000000..ff4000f --- /dev/null +++ b/src/l3netrom.c @@ -0,0 +1,871 @@ +/************************************************************************/ +/* */ +/* ***** ***** */ +/* ***** ***** */ +/* ***** ***** */ +/* ***** ***** */ +/* *************** *************** */ +/* ***************** ***************** */ +/* *************** *************** */ +/* ***** ***** TheNetNode */ +/* ***** ***** Portable */ +/* ***** ***** Network */ +/* ***** ***** Software */ +/* */ +/* File src/l3netrom.c (maintained by: ???) */ +/* */ +/* This file is part of "TheNetNode" - Software Package */ +/* */ +/* Copyright (C) 1998 - 2008 NORD> Laufzeit */ +/* */ +/************************************************************************/ +static int +rtt2qual(ULONG rtt) /* Laufzeit zu Qualitaet */ +{ + int qual; + + if (rtt) + { + qual = 255 - (unsigned)(rtt / autoqual); + if (qual > 254) + qual = 254; + if (qual < 3) + qual = 3; + return (qual); + } + return (0); /* ausgefallen */ +} + +static int +qual2rtt(unsigned qual) /* Qualitaet zu Laufzeit */ +{ + if (qual < 2) + return (0); /* unerreichbar */ + return ((256 - qual) * autoqual); +} + +/************************************************************************/ +/* */ +/* Die Absenderknoten muessen in der Nodesliste stehen, damit wir */ +/* Antworten zurueckschicken koennen. Ist ein Absender noch nicht */ +/* bekannt, wird dieser mit einer Laufzeit von 599,99s eingetragen. */ +/* */ +/************************************************************************/ +static void +fastlearn(PEER *pp, char *id) +{ + INDEX index = find_node_this_ssid(id); +#if MAX_TRACE_LEVEL > 6 + char notify_call1[10]; + char notify_call2[10]; +#endif + + if (index != NO_INDEX) /* Node bekannt und Qualitaet gut */ + if (pp->routes[index].quality) /* dann nicht lernen */ + return; + if ((index = add_route(pp, id, LEARN)) != NO_INDEX) + { + update_lt(pp, index, DEFAULT_LT); +#ifndef THENETMOD + pp->routes[index].timeout = ROUTE_TIMEOUT; +#else + /* Lebensdauer einer Node markieren. */ + pp->routes[index].timeout = obcini; +#endif /* THENETMOD */ +#if MAX_TRACE_LEVEL > 6 + call2str(notify_call1, orgnod); + call2str(notify_call2, pp->l2link->call); + notify(7, "fastlearn %s via %s", + notify_call1, notify_call2); +#endif + } +} + +/************************************************************************\ +* * +* Informationstransfer von Level2 zum NET/ROM-Router * +* * +* Die empfangenen Frames vom Nachbarn werden ausgewertet und ggf. an den * +* eigenen L4 (Verbindungsebene) oder an einen anderen Nachbarn * +* weitergeleitet. * +* * +\************************************************************************/ +void +netrom_rx(PEER *rxpp) +{ + MBHEAD *mbp; /* Buffer fuer ein Frame */ + char huge *savmbbp; /* mbbp-Sicherung */ + WORD savmbgc; /* mbgc-Sicherung */ + NODE *srcnod; + NODE *dstnod; + PEER *pp; + MHEARD *mhp; + int mask; +#if MAX_TRACE_LEVEL > 2 + char notify_call1[10]; + char notify_call2[10]; + char notify_call3[10]; +#endif + +/* Zunaechst empfangene Frames verarbeiten, bis Liste leer... */ + while ( (mbp = (MBHEAD *)(rxpp->rxfl.head)) + != (MBHEAD *)&(rxpp->rxfl)) + { + ulink((LEHEAD *)mbp); /* 1 Frame aus der Liste holen */ + if (mbp->l2link == NULL) + rx_ui_broadcast(rxpp, mbp); /* ist UI-Broadcast */ + else /* Info Frame */ + { + if (rx_inp_broadcast(rxpp, mbp)) /* INP Broadcast? */ + { + dealmb(mbp); + return; /* max 1 Frame pro Runde */ + } + savmbbp = mbp->mbbp; /* Position im Frame merken */ + savmbgc = mbp->mbgc; /* fuer Weiterleitung */ + if ( (getfid(orgnod, mbp)) /* Call des Quellknotens holen */ + && (getfid(desnod, mbp)) /* Call des Zielknotens holen */ + && (mbp->mbgc < mbp->mbpc)) /* und Info im Frame? */ + { + if ( valcal(orgnod) == ERRORS /* Absender und Zielrufzeichen */ + || valcal(desnod) == ERRORS /* pruefen */ + ) + { +#if MAX_TRACE_LEVEL > 2 + call2str(notify_call1, orgnod); + call2str(notify_call2, desnod); + call2str(notify_call3, rxpp->l2link->call); + notify(3, "invalid node %s>%s from %s (flushed)", + notify_call1, notify_call2, notify_call3); + /* wir sagens dem Sysop */ +#endif + dealmb(mbp); /* Frame wegwerfen */ + continue; /* ... und zum naechsten Frame */ + } + --(*(mbp->mbbp)); /* Restlebensdauer um 1 runter */ + time_to_live = getchr(mbp); /* Restlebensdauer lesen */ + + if ((mbp->mbpc - mbp->mbgc) >= 5) /* ist es lang genug ? */ + { +/* Frames, die von einem Knoten kommen, der noch nicht in unsere */ +/* Knoten-Liste eingetragen ist, fuehren zu einem Eintrag des Quell- */ +/* Knotens mit Qualitaet 59999 in unsere Nodes-Liste (Fast-Learn) */ + + if ( !cmpid(myid, orgnod) /* kein eigenes Frame */ + && !cmpid(myid, rxpp->l2link->call)) + fastlearn(rxpp, orgnod); + + l4hdr0 = getchr(mbp); /* Header holen */ + l4hdr1 = getchr(mbp); /* ist eigentlich Sache des L4, */ + l4hdr2 = getchr(mbp); /* aber der L3 verschickt auch */ + l4hdr3 = getchr(mbp); /* L4-Messframes, deswegen */ + l4hdr4 = getchr(mbp); /* wird das schon hier er- */ + l4opco = l4hdr4 & L4OPMASK; /* ledigt. */ + + if (l4opco == L3TCPUDP && l4hdr0 == 0 && l4hdr1 == 1) /* NRR */ + { + nrr_rx(mbp, rxpp); + dealmb(mbp); /* Frame wegwerfen */ + continue; /* ... und zum naechsten Frame */ + } + +/*----- Auswertung der eigenen und fremden L3RTT Frames ----------------*/ + if ( cmpid(desnod, "L3RTT \140") /* Ziel und Inhalt OK! */ + && ( cmpid(orgnod, rxpp->l2link->call) + || cmpid(orgnod, myid))) /* und von dem Nachbarn */ + { /* oder eigenes */ + rx_l3rtt_frame(rxpp, mbp, savmbbp, savmbgc); + continue; + } + +/* L3-MH-Liste fuehren */ + if ((mhp = mh_lookup(&l3heard, orgnod)) == NULL) + mhp = mh_add(&l3heard); + if (mhp) + { /* Eintrag vorhanden? */ + mh_update(&l3heard, mhp, orgnod, mbp->l2port); + mhp->rx_bytes += (mbp->mbpc - mbp->mbgc); + } + +/*----------------- Frame ist fuer mich --------------------------------*/ + if (cmpid(myid, desnod)) + { +#ifdef IPROUTE + if (l4opco == L3TCPUDP) + { /* L3 TCP/UDP-Frame */ + mbp->l2fflg = L2CIP; /* es ist ein IP-Frame */ + relink((LEHEAD *)mbp, (LEHEAD *)iprxfl.tail); + continue; /* Frame verarbeitet */ + } +#endif + mbp->l3_typ = L3NORMAL; /* kein LOCAL und kein L3RTT */ + if (iscall(orgnod, &srcnod, NULL, DG)) /* Absender-Node */ + { + l4rx(srcnod, NULL, mbp); /* Frame an Level 4 geben */ + continue; /* naechstes Frame */ + } +#if MAX_TRACE_LEVEL > 4 + call2str(notify_call1, orgnod); + notify(5, "unreachable source node %s", notify_call1); +#endif + dealmb(mbp); /* Frame entsorgen */ + continue; + } + +/* MH-Liste Senderichtung */ + if ((mhp = mh_lookup(&l3heard, desnod)) != NULL) + mhp->tx_bytes += (mbp->mbpc - mbp->mbgc); + +/*---- nur CONREQ kann auf L2 umgeroutet werden */ + if ((l4opco == L4CONREQ) || (l4istome(orgnod, desnod))) + mask = DG | VC | VC_FAR; + else + mask = DG; + +/*---- Level 3 Frame nicht fuer mich, sondern weiterleiten -----*/ + if (iscall(desnod, &dstnod, &pp, mask)) + { /* Ziel erreichbar? */ +/* wenn das Ziel nicht im DG-Mode erreicht werden kann, dann muessen */ +/* wir umsetzen. */ + if ((pp->options & DG) == 0) + { + mbp->l3_typ = L3LOCAL; + mbp->l2link = (LNKBLK *)dstnod; /* Ziel-Node */ + if (iscall(orgnod, &srcnod, NULL, DG)) /* Absender */ + { + l4rx(srcnod, dstnod, mbp); + continue; /* naechstes Frame */ + } +#if MAX_TRACE_LEVEL > 4 + call2str(notify_call1, orgnod); + notify(5, "unreachable source node %s", notify_call1); +#endif + dealmb(mbp); /* Frame entsorgen */ + continue; + } + + if (time_to_live) + { /* noch Restlebensdauer? */ + mbp->mbbp = savmbbp; + mbp->mbgc = savmbgc; + + if (cmpid(myid, orgnod)) /* eigenes Frame gehoert, weg */ + { /* damit */ +#if MAX_TRACE_LEVEL > 4 + call2str(notify_call1, desnod); + call2str(notify_call2, rxpp->l2link->call); + notify(5, "own frame to %s received fm %s (loop)", + notify_call1, notify_call2); +#endif + dealmb(mbp); + continue; + } + +/* Falls wir ein Frame ueber den Nachbarn zurueckschicken */ + + if (rxpp == pp) /* wuerden, dann vernichten wir es */ + { +#if MAX_TRACE_LEVEL > 4 + call2str(notify_call1, orgnod); + call2str(notify_call2, desnod); + call2str(notify_call3, rxpp->l2link->call); + notify(5, "frame fm %s to %s via %s flushed (neigb loop)", + notify_call1, notify_call2, notify_call3); +#endif + dealmb(mbp); + continue; + } + + toneig(pp, mbp); /* Info absetzen */ + continue; + } /* noch Restlebensdauer */ + } /* Ziel bekannt */ + } /* Laenge ok */ + } /* Info ist im Frame */ + } /* es ist ein I-Frame */ + dealmb(mbp); + } +} + +/************************************************************************/ +/* */ +/* L3 UI-Frame (Broadcast) */ +/* */ +/************************************************************************/ +static void +rx_ui_broadcast(PEER *rxpp, MBHEAD *mbp) +{ + char alias[L2CALEN]; /* Alias Rundspruch sendender Knoten */ + INDEX index; + + if (worqua != 0) /* darf Auswertung erfolgen? */ + { + if ( mbp->mbgc < mbp->mbpc /* Info im Frame? */ + && (getchr(mbp) & 0xFF) == 0xFF /* stimmt Signatur */ + && ge6chr(alias, mbp)) /* Alias des Absender-Knotens */ + { + if ( (alias[0] != '#') /* NOROUTE, Keine Route '#' im Alias, */ +#ifdef THENETMOD + ||(NoRoute) /* oder NOROUTE eingeschaltet, */ +#endif /* THENETMOD */ + ) /* Broadcast-Node zulassen, ansonsten ablehnen. */ + { + cpyals(rxpp->l2link->alias, alias); + if ((index = add_route(rxpp, rxpp->l2link->call, 1)) != NO_INDEX) + { + update_lt(rxpp, index, 1); + if (update_alias(index, alias)) + propagate_node_update(index); + rx_broadcast(rxpp, mbp); +#ifdef THENETMOD + if ( (rxpp->soll_typ == NETROM) /* Noch kein TYP gesetzt. */ + ||(rxpp->soll_typ == THENET)) /* Typ soll ein THENET-TYP sein. */ + rxpp->typ = THENET; /* TYP auf THENET-TYP setzen. */ + + if (!rxpp->obscnt) /* Restlebensdauer fuer Rundspruch */ + { /* noch nicht gesetzt. */ + MBHEAD *rxmbp = NULL; + + bcast(&rxmbp, /* Broadcast-Bake to CALL senden, */ + rxpp->l2link->call, /* damit der Link sofort nutzbar ist. */ + rxpp->l2link->port); + } + + rxpp->obscnt = obcbro; /* Restlebensdauer fuer Rundspruch setzen. */ + + if (rxpp->quality < 1) /* Nur wenn ungueltige Qualitaet, */ + rxpp->quality = worqua; /* minimale Qualitaet setzen. */ + +#endif /* THENETMOD */ + } + } + } + } /* Signatur ist gut */ +} /* Auswertung zulaessig */ + +/*----------------------------------------------------------------------*/ +void +rx_broadcast(PEER *rxpp, MBHEAD *mbp) +{ + char desnod[L2IDLEN]; + char beaide[L2CALEN]; + char nbr_call[L2IDLEN]; + int rx_qual; + INDEX index; + PEER *pp; +#if MAX_TRACE_LEVEL > 8 + char notify_call1[10]; + char notify_call2[10]; + char notify_call3[10]; +#endif + + if (rxpp->typ == INP) + return; + +#ifdef THENETMOD + if (rxpp->l2link->alias[0] == '#') /* Unser Partner ist GEHEIM, */ + return; /* damit wir nehmen keine NODES an. */ +#endif /* THENETMOD */ + + while ( (getfid(desnod, mbp)) + && (valcal(desnod)) + && (ge6chr(beaide, mbp)) + && (getfid(nbr_call, mbp)) + && (valcal(nbr_call)) + && (mbp->mbgc < mbp->mbpc)) + { + rx_qual = getchr(mbp) & 0xFF; + +#if MAX_TRACE_LEVEL > 8 + call2str(notify_call1, rxpp->l2link->call); + call2str(notify_call2, desnod); + call2str(notify_call3, nbr_call); + notify(9, "%-9.9s>%-6.6s:%-9.9s Q%u v %-9.9s", + notify_call1, beaide, notify_call2, rx_qual, notify_call2); +#endif + +#ifdef THENETMOD + if (beaide[0] == '#') + { +#if MAX_TRACE_LEVEL > 2 + call2str(notify_call1, rxpp->l2link->call); + call2str(notify_call2, desnod); + notify(3, "NETROM: %s sent secret node %s", notify_call1, notify_call2); +#endif + /* XNet hat (derzeit ?) einen Fehler, der Nodes mit Geheim-Aliassen */ + /* sendet. Da diese Nodes nicht wirklich geheim sind nehmen wir sie */ + /* trotzdem, loeschen aber ihre Aliasse. */ + if ( (strncasecmp(&beaide[1], "temp", 4) == 0) + || (strncasecmp(&beaide[1], "tmp", 3) == 0) + ) + { + /* fehlerhaften Alias loeschen */ + cpyals(beaide, DONT_CHANGE_ALIAS); /* Alias loeschen */ +#if MAX_TRACE_LEVEL > 2 + notify(3, "NETROM: not real secret node, corrected"); +#endif + } + } +#endif /* THENETMOD */ + + if ( (cmpid(myid, nbr_call) == TRUE) /* er wuerde an mich senden, */ + || (rx_qual == LEARNQUAL) /* oder er kennt keinen Weg, */ + || (beaide[0] == '#')) /* oder Ziel (jetzt) "hidden" */ + rx_qual = 0; /* also den Weg austragen */ + + if (cmpid(myid, desnod) == TRUE) /* nicht uns selber */ + continue; + + switch (rxpp->typ) + { + case NETROM: + case THENET: + if (rx_qual < worqua) + rx_qual = 0; /* ausgefallen */ + break; + case TNN: + if (rx_qual < 2) + rx_qual = 0; /* ausgefallen */ + break; + } + + if ((index = add_route(rxpp, desnod, qual2rtt(rx_qual))) != NO_INDEX) + { + update_lt(rxpp, index, DEFAULT_LT); + + if (!cmpcal(netp->nodetab[index].alias, nulide)) + if (find_best_qual(index, &pp, DG) > 0) /* beste Qualitaet */ + if (pp != rxpp) + continue; + + if (update_alias(index, beaide)) /* Alias hat sich geaendert */ + propagate_node_update(index); + } + } +} + +void +sdl3ui(PEER *pp, MBHEAD *mbp) /* UI-Broadcast senden */ +{ + unsigned int i; + STAT *statp; + + if (pp->l2link->digil[0] == 0) /* direkter Nachbar */ + sdui("", /* Level 2 senden */ + "NODES \140", /* an das Ziel "NODES" */ + myid, +#ifdef __WIN32__ + (char)pp->l2link->port, +#else + pp->l2link->port, +#endif /* WIN32 */ + mbp); + else + sdui(pp->l2link->digil, /* Level 2 senden */ + pp->l2link->call, + myid, +#ifdef __WIN32__ + (char)pp->l2link->port, +#else + pp->l2link->port, +#endif /* WIN32 */ + mbp); + + /* Da gesendete UI-Frames nicht in der Statistik an der dafuer vorgesehenen */ + /* Stelle erfasst werden koennen, dort ist das eigentliche Ziel (der Link- */ + /* partner) nicht mehr bekannt, die Statistik hier fuehren. */ + + for (statp = mh, i = 0; i < MAXSTAT; statp++, i++) + { + if (!(*statp->call)) /* nur benutzte Eintraege interessieren */ + continue; + + if (cmpid(pp->l2link->call, statp->call)) /* richtiger Stat-Eintrag */ + { + if (pp->l2link->digil[0] == NUL) /* ohne via Angabe */ + { + statp->UIno[1]++; + break; + } + else + { /* mit via */ + if (cmpid(pp->l2link->digil, statp->viacall)) + { + statp->UIno[1]++; + break; + } + } + } + } + dealmb(mbp); /* Buffer wieder freigeben */ +} + +/************************************************************************/ +/* */ +/* "send broadcast" */ +/* */ +/* Ein Broadcast-Frame auf die Reise schicken. Es wird je nach Nachbar- */ +/* typ als UI oder als I-Frame gesendet. "nodemb" wird auf NULL ge- */ +/* setzt, um einen fehlenden Node-Buffer zu signalisieren. Der naechste */ +/* Aufruf von addbro() erzeugt dann ein neues Broadcast-Frame. */ +/* */ +/*----------------------------------------------------------------------*/ +void +brosnd(MBHEAD **mbpp, PEER *pp) +{ + if (*mbpp == NULL) + { + if (pp->typ == THENET /* || pp->typ == NETROM*/) + { + (*mbpp = (MBHEAD *)allocb(ALLOC_MBHEAD))->l3_typ = L2CUI; +#ifdef __WIN32__ + putchr((char)0xFF, *mbpp); +#else + putchr(0xFF, *mbpp); +#endif /* WIN32 */ + pu6chr(alias, *mbpp); +#if MAX_TRACE_LEVEL > 6 + notify(7, "brosnd"); +#endif + } + else + return; + } + + rwndmb(*mbpp); /* vor dem Senden Buffer zurueckspulen */ + + if ((*mbpp)->l3_typ == L2CI) /* Als I-Frame ueber den Link senden */ + toneig(pp, *mbpp); + else + { + (*mbpp)->l2fflg = L2CNETROM;/* Als UI-Bake rausschicken an "NODES" */ + sdl3ui(pp, *mbpp); /* PID = Level 3 */ + } + *mbpp = NULL; /* und Buffer loeschen */ +} + +/************************************************************************/ +/* */ +/* "add broadcast" */ +/* */ +/* Einen Weg zu dem Broadcast-Frame fuer einen Nachbarn hinzufuegen. */ +/* Das Frame wird gesendet, sobald es voll ist oder in brosrv() wenn */ +/* der Timeout abgelaufen ist. */ +/* */ +/*----------------------------------------------------------------------*/ +static void +add_netrom_info(MBHEAD **mbpp, NODE *node, PEER *topp, + PEER *viapp, unsigned qualit) +{ + int qual = rtt2qual(qualit); + + /* schlechte Wege werden unterdrueckt, abmelden kennt NETROM nicht */ + if (qual <= worqua) + return; + + if (*mbpp) + if (((*mbpp)->mbpc + 21) > 256) /* bis Frame voll */ + brosnd(mbpp, topp); + + if (*mbpp == NULL) + { /* neues Frame holen */ + (*mbpp = (MBHEAD *)allocb(ALLOC_MBHEAD))->l3_typ = L2CUI; +#ifdef __WIN32__ + putchr((char)0xFF, *mbpp); +#else + putchr(0xFF, *mbpp); +#endif /* WIN32 */ + pu6chr(alias, *mbpp); + } + + putfid(node->id, *mbpp); /* Call des Zieles */ + pu6chr(node->alias, *mbpp); /* Ident des Zieles */ + if (qualit && viapp) + putfid(viapp->l2link->call, *mbpp); /* Nachbar des Zieles */ + else + putfid(myid, *mbpp); /* Nachbar geloescht */ +#ifdef __WIN32__ + putchr((char)rtt2qual(qualit), *mbpp); +#else + putchr(rtt2qual(qualit), *mbpp); +#endif /* WIN32 */ +} + +/************************************************************************/ +/* */ +/* Einen Weg zu dem Infocast-Frame fuer einen Nachbarn hinzufuegen. */ +/* Das Frame wird gesendet, sobald es voll ist oder in brosrv() wenn */ +/* der Timeout abgelaufen ist. */ +/* */ +/*----------------------------------------------------------------------*/ +static void +add_thenet_info(MBHEAD **mbpp, NODE *node, PEER *topp, + PEER *viapp, unsigned qualit) +{ + if (*mbpp) + if (((*mbpp)->mbpc + 21) > 256) /* bis Frame voll */ + brosnd(mbpp, topp); + + if (*mbpp == NULL) + { /* neues Frame holen */ + (*mbpp = (MBHEAD *)allocb(ALLOC_MBHEAD))->l3_typ = L2CI; + putfid(myid, *mbpp); /* von eigenes Call */ + putfid("L3RTT \140", *mbpp); /* an Pseudo-Destination */ + *((*mbpp)->mbbp - 1) |= 1; /* EOA setzen */ + putchr(0x02, *mbpp); /* Lifetime = 2 */ + putchr(0x00, *mbpp); /* Circuit-Index */ + putchr(0x00, *mbpp); /* Circuit-ID */ + putchr(0x00, *mbpp); /* TX-Sequence-Number */ + putchr(0x00, *mbpp); /* RX-Sequence-Number */ + putchr(0x05, *mbpp); /* OpCode & Flags */ + putstr("BROAD", *mbpp); /* Framekennung */ + } + + putfid(node->id, *mbpp); /* Call des Zieles */ + pu6chr(node->alias, *mbpp); /* Ident des Zieles */ + if (qualit && viapp) + putfid(viapp->l2link->call, *mbpp); /* Nachbar des Zieles */ + else + putfid(myid, *mbpp); /* Nachbar geloescht */ +#ifdef __WIN32__ + putchr((char)rtt2qual(qualit), *mbpp); +#else + putchr(rtt2qual(qualit), *mbpp); +#endif /* WIN32 */ +} + +static void +addbro(MBHEAD **mbpp, NODE *node, PEER *topp, PEER *viapp, + unsigned qualit, unsigned lastqual, int lt) +{ + switch (topp->typ) + { + case THENET: + case NETROM: + add_netrom_info(mbpp, node, topp, viapp, qualit); + break; + case TNN: + add_thenet_info(mbpp, node, topp, viapp, qualit); + break; + case INP: + add_inp_info(mbpp, node, topp, qualit, lastqual, lt); + break; + } +} + +/*----------------------------------------------------------------------*/ +/* Broadcast fuer einen Nachbarn */ +void +inform_peer(PEER *pp, int kind_of) +{ + INDEX index; + int max_nodes = netp->max_nodes; + NODE *np = netp->nodetab; + ROUTE *rp = pp->routes; + PEER *bestpp; + UWORD quality; + unsigned int reported_quality; + unsigned int diff; + UWORD maxtime; + + int timeout; + MBHEAD *mbp = NULL; /* noch kein Buffer offen */ + + BOOLEAN old_netrom = (pp->typ == NETROM || pp->typ == THENET); + + for (index = 0; index < max_nodes; index++, np++, rp++) + { + if (np->id[0] == 0) /* kein Eintrag */ + continue; + + if (cmpid(np->id, pp->l2link->call)) /* der Nachbar */ + continue; + +#ifdef LINKSMOD_LOCALMOD + if (CheckLocalLink(np->id) == TRUE) /* Ist ein Local-Link. */ + continue; /* Zum nechsten Eintrag. */ +#endif /* LINKSMOD_LOCALMOD */ + +/************************************************************************/ +/**** HACK: wird nur benoetigt, solange wir nur die Flexnet Nachbarn ****/ +/**** und nicht deren Ziele melden wollen ****/ +#ifndef FLEX_ROUTINGFIX + if ( ((quality = find_best_qual(index, &bestpp, VC | VC_FAR | DG)) + != 0) + && (bestpp->options == VC_FAR) +#else +/* Hiermit werden keine FLEXNET-Routen durchgelassen, FLEXGATE deaktiviert. */ +/* Es duerfen nur LOCAL und LOCAL_M (VC) ins Netrom-Netz geroutet werden. */ +/* LOCAL_N und LOCAL_V werden weiter oben behandelt und duerfen nicht */ +/* weiter geroutet werden !!! */ + if ( ((quality = find_best_qual(index, &bestpp, HOST_MASK)) != 0) + && (bestpp->options == VC) +#endif /* FLEX_ROUTINGFIX */ + && (cmpid(bestpp->l2link->call, np->id))) + { + } + else +/************************************************************************/ + +/** An Nachbarn, die das gleiche Call haben, wie der beste Weg (also */ +/* auch der beste Weg selbst) melden wir 0. */ + quality = find_best_qual(index, &bestpp, HOST_MASK); + if (cmpid(bestpp->l2link->call, pp->l2link->call)) + quality = 0; + +/*** Alternativ: ***/ +/*** quality = find_best_notvia(index, pp, &bestpp, HOST_MASK); ***/ + + reported_quality = rp->reported_quality; + if (np->alias[0] == '#') /* versteckter Node */ + { + if (!reported_quality) /* hatten wir gemeldet? */ + continue; /* nein, also auch jetzt nicht */ + quality = 0; /* ja, also abmelden */ + } + if (kind_of == ALL) + { + /* gesicherten Nachbarn brauchen wir nur Ziele zu uebertragen, */ + /* die wir schon mal gemeldet hatten */ + if (!old_netrom && !reported_quality) + continue; + /* wir senden alle Routen ohne Timeout und diejenigen, die noch */ + /* mindestens 30% des Timeouts uebrig haben */ + timeout = rp->timeout; + if ( (timeout == 0) +#ifndef THENETMOD + || (timeout >= (ROUTE_TIMEOUT / 3))) +#else + || (timeout >= (obcini / 3))) +#endif /* THENETMOD */ + { + addbro(&mbp, netp->nodetab + index, pp, bestpp, quality, + reported_quality, bestpp->routes[index].lt); + rp->reported_quality = quality;/* merken was wir gemeldet haben */ + } + } + else + { +/* Die maximal zulaessige Laufzeit fuer Meldungen ist entweder 600s */ +/* oder ein vom Nachbarn vorgegebener kleinerer Wert. Hat der Nachbar */ +/* eine max. Laufzeit gemeldet, so wird diese beruecksichtigt. */ + maxtime = pp->maxtime; + if (!maxtime || maxtime > HORIZONT) + maxtime = HORIZONT; +/* Zusaetzliches Filter: Bei der ersten Meldung eines Zieles darf die */ +/* Laufzeit hoechstens die Haelfte des Maximalwertes betragen, damit */ +/* wir nicht schon bei der ersten Verschlechterung das Ziel wieder */ +/* abmelden muessen. */ + if (!reported_quality) /* noch nix gemeldet? */ + if (quality > (maxtime / 2)) /* zu schlecht? */ + continue; + + if (reported_quality != DIRTY) + { + if (quality == reported_quality) + continue; /* keine Aenderung */ + +/* Wenn ein Ziel ausfaellt oder neu gemeldet wird, dann brauchen wir */ +/* nicht zu kontrollieren, ob die Meldung unterdrueckt werden kann. */ +/* Diese Meldungen sind zwingend. */ + if (quality && reported_quality) + { +/* Verbesserungen werden nur gemeldet, wenn Sie mindestens um 50% von */ +/* der letzten Meldung abweichen. Ebenfalls nicht gemeldet werden sehr */ +/* geringe Verbesserungen (<= 100ms) bei sehr schnellen Links */ +/* (Aenderung z.B. von 50ms auf 90ms wird nicht gemeldet, obwohl es 60% */ +/* sind). Die Verbesserung muss mindestens ueber der halben Laufzeit */ +/* zum empfangenden Segment liegen. Die Verbesserung wird nur gemeldet */ +/* wenn der Link nicht verstopft ist! */ + if (quality < reported_quality) + { + diff = reported_quality - quality; + if (diff < reported_quality / 2) /* Filter 1: */ + continue; /* 50% Verbesserung */ + if (diff < 10) /* Filter 2: */ + continue; /* mindestens 100ms */ + if (diff < pp->quality / 2) /* Filter 3: */ + continue; /* adaptiv nach Zielr. */ + if (pp->nbrl2l->tosend > 7) /* Filter 4: */ + continue; /* Link verstopft? */ + } + else + { +/* Verschlechterungen muessen immer sofort uebertragen werden! Wir */ +/* senken die Qualitaet bei der Meldung vorbeugend um 12.5% ab und */ +/* zusaetzlich um die 1/2 Laufzeit zu diesem Nachbarn. Bei weiterem */ +/* Abfall sollen weitere hektische Meldungen dadurch vermieden werden. */ +#ifdef __WIN32__ + quality += quality / 8 + (unsigned short)pp->quality / 2; +#else + quality += quality / 8 + pp->quality / 2; +#endif /* WIN32 */ +/* Ist die neue Laufzeit groesser als der Nachbar wuenscht, wird das */ +/* Ziel abgemeldet. */ + if (quality > maxtime) + quality = 0; + } + } + } + + addbro(&mbp, netp->nodetab + index, pp, bestpp, quality, + reported_quality, bestpp->routes[index].lt); + + rp->reported_quality = quality; /* merken was wir gemeldet haben */ + + /* bei abgemeldeten Nodes die Lifetime loeschen */ + if ((rp->reported_quality == 0) && (rp->quality == 0)) + rp->lt = 0; + } + } + brosnd(&mbp, pp); +} + +/* End of src/l3netrom.c */ diff --git a/src/l3rtt.c b/src/l3rtt.c new file mode 100755 index 0000000..bffe49b --- /dev/null +++ b/src/l3rtt.c @@ -0,0 +1,539 @@ +/************************************************************************/ +/* */ +/* ***** ***** */ +/* ***** ***** */ +/* ***** ***** */ +/* ***** ***** */ +/* *************** *************** */ +/* ***************** ***************** */ +/* *************** *************** */ +/* ***** ***** TheNetNode */ +/* ***** ***** Portable */ +/* ***** ***** Network */ +/* ***** ***** Software */ +/* */ +/* File src/l3rtt.c (maintained by: ???) */ +/* */ +/* This file is part of "TheNetNode" - Software Package */ +/* */ +/* Copyright (C) 1998 - 2008 NORD>max_peers; + MBHEAD *mbp; + INDEX index; +#if MAX_TRACE_LEVEL > 2 + char notify_call[10]; +#endif + + for (i = 0, pp = netp->peertab; i < max_peers; i++, pp++) + { + if (!pp->used) + continue; + if (pp->typ > NETROM) + continue; + +#ifdef THENETMOD + if ( (pp->typ == THENET) /* THENET-Typ und */ + &&(pp->constatus == TRUE)) /* kein Dauerconnect gewuenscht. */ + continue; /* Zum naechsten Segment. */ +#endif /* THENETMOD */ + +#ifdef L4NOBAKE + if (pp->soll_typ == NETROM)/* Wenn noch kein Routing-TYP fest steht,*/ + continue; /* zum naechsten Segment. */ +#endif /* L4NOBAKE */ + + if (pp->nbrl2l == NULL) + { +/* Der Nachbar, auf den pp zeigt, bekommt eine L3-Mini-Broadcast-Bake */ +/* von uns. Diese ist notwendig, da einige aeltere Versionen von TheNet */ +/* und andere NET/ROM-Implementierungen den Nachbarn nur annehmen, wenn */ +/* vorher bereits eine L3-Bake empfangen wurde. Anschliessend wird eine */ +/* Verbindung zum Nachbarn hergestellt. */ +/* Wollen wir einen INP-Link, so senden wir keine NODES-Bake vorher da */ +/* wir mit NETROM ja nix machen wollen und wir wegen INP annehmen, dass */ +/* die Gegenseite keine Uralt-Soft hat, die diese Minibake braucht. */ +#ifndef THENETMOD + if (pp->soll_typ != INP) +#else + if (pp->typ == TNN) /* L3-Mini Bake nur fuer TNN-Typ zulassen. */ +#endif /* THENETMOD */ + { + mbp = (MBHEAD *)allocb(ALLOC_MBHEAD); /* Buffer besorgen */ +#ifdef __WIN32__ + putchr((char)0xFF, mbp); +#else + putchr(0xFF, mbp); +#endif /* WIN32 */ + pu6chr(alias, mbp); /* Ident in Buffer */ + mbp->l2fflg = L2CNETROM; /* PID = Level 3 */ + rwndmb(mbp); /* Pointer aufziehen */ + sdl3ui(pp, mbp); /* UI-Broadcast senden */ + } + +#ifdef PORT_L2_CONNECT_TIME + if (pp->l2link->sabmtime == 0) + { +#endif +#ifdef PORT_L2_CONNECT_RETRY + if (connbr(pp)) + pp->nbrl2l->tries = (UBYTE)portpar[pp->nbrl2l->liport].retry - (UBYTE)portpar[pp->nbrl2l->liport].l2_connect_retry; + + continue; +#else + if (connbr(pp)) + pp->nbrl2l->tries = portpar[pp->nbrl2l->liport].retry - 1; + + continue; +#endif +#ifdef PORT_L2_CONNECT_TIME + } + else + { + pp->l2link->sabmtime--; + continue; + } +#endif + } + if (pp->nbrl2l->state < L2SIXFER) + continue; + if (pp->rttstart) + { + if (tic10 - pp->rttstart >= 18000L) /* maximal 180 Sekunden */ + { +#if MAX_TRACE_LEVEL > 2 + call2str(notify_call, pp->l2link->call); + notify(3, "%s: l3rtt too high: %ld", notify_call, + tic10 - pp->rttstart); +#endif + discnbp(pp); + } + continue; + } + if (pp->rtt_time == 0) + { /* Messung ist faellig */ + if (pp->typ == THENET) + { /* der kann nicht messen */ + update_peer_quality(pp, pp->nbrl2l->SRTT * 4L, DONT_CHANGE_QUAL); + /* Falls das Timeout auf einer Route mal abfaellt, */ + /* melden wir hier wieder die Routen-Qualitaet hoch. */ + if ((index = add_route(pp, pp->l2link->call, 1)) != NO_INDEX) + update_lt(pp, index, 1); + rtt_metric(pp, pp->nbrl2l->SRTT * 4L); + pp->rtt_time = L3_RTT_TIME; + +#ifdef THENETMOD + if (pp->constatus == FALSE)/* Link soll staendig Aktiv bleiben. */ + pp->nbrl2l->noatou = ininat; /* L2-Timeout setzen. */ +#endif /* THENETMOD */ + } + else +#ifndef L4NOBAKE + send_l3srtt_frame(pp); /* Neue Messung starten */ +#else + { + if (pp->soll_typ != NETROM) /* Nur wenn Routing-TYP fest steht,*/ + send_l3srtt_frame(pp); /* Neue Messung starten */ + } +#endif /* L4NOBAKE */ + } + else + pp->rtt_time--; /* Messintervall runterzaehlen */ + } +} + +/*----------------------------------------------------------------------*/ +void +send_l3srtt_frame(PEER *pp) +{ + MBHEAD *mbp; + int mtu; + + if (pp->typ > NETROM) /* nur bei NET/ROM erlaubt */ + return; + + if (pp->nbrl2l) + { /* nur aktiver mit L2-Link.. */ + mbp = (MBHEAD *)allocb(ALLOC_MBHEAD); /* Buffer besorgen */ + putfid(myid, mbp); /* von eigenes Call */ + putfid("L3RTT \140", mbp); /* an Pseudo-Destination */ + *(mbp->mbbp - 1) |= 1; /* EOA setzen */ + putchr(0x02, mbp); /* Lifetime = 2 */ + putchr(0x00, mbp); /* Circuit-Index */ + putchr(0x00, mbp); /* Circuit-ID */ + putchr(0x00, mbp); /* TX-Sequence-Number */ + putchr(0x00, mbp); /* RX-Sequence-Number */ + putchr(0x05, mbp); /* OpCode & Flags */ + putstr("L3RTT:", mbp); /* Framekennung */ + pp->rttstart = tic10; /* Startzeit merken */ + putlong(tic10, TRUE, mbp); /* 10ms Ticks seit Softstart */ + putlong((ULONG)pp->quality, TRUE, mbp); /* aktueller L3-SRTT Wert */ + putlong((ULONG)pp->my_quality, TRUE, mbp); /* letzter L3-RTT Wert */ + putlong((ULONG)pp, TRUE, mbp); /* Pointer als ID */ + putchr(' ', mbp); + pu6chr(alias, mbp); + putstr(" LEVEL3_V2.1 ", mbp); /* L3-Version */ + putstr(infostr, mbp); /* TNN-Version */ + + /* nur wenn wir einen INP-Link wollen auch dem Nachbarn sagen dass */ + /* wir INP koennen und ggf. maxtime melden, ansonsten nix sagen */ + if (pp->soll_typ == INP) + { + if (mymaxtime != 0) + putprintf(mbp, " $M%u", mymaxtime); + + putstr(" $N\r", mbp); + } + + mtu = portpar[pp->l2link->port].mtu; + while (mbp->mbpc < mtu) /* Buffer voll machen */ + putchr(' ', mbp); + rwndmb(mbp); /* Frame aufziehen */ + toneig(pp, mbp); /* Frame an den Nachbarn */ + } +} + +/************************************************************************\ +* * +* Das Frame mit der gewuenschten Kennung vergleichen. Wenn ja, * +* wird sie ueberlesen, sonst wird mbbp/mbgc restauriert. * +* * +\************************************************************************/ +BOOLEAN +match(MBHEAD *fbp, const char *text) +{ + char huge *mbbp; /* Sicherung von mbbp */ + UWORD mbgc; /* Sicherung von mbgc */ + + mbbp = fbp->mbbp; /* Position im Frame (mbbp,mbgc) */ + mbgc = fbp->mbgc; /* merken, falls kein Erfolg */ + while (*text) + { /* die Kennung durchgehen */ + if (getchr(fbp) != *text++) + { /* Abweichung! */ + fbp->mbbp = mbbp; /* auf die alte Position im Frame */ + fbp->mbgc = mbgc; /* zurueckgehen */ + return (FALSE); /* Kennung stimmt nicht */ + } + } + return (TRUE); /* Kennung stimmt */ +} + +/************************************************************************/ +/* */ +/* Eine Bake senden mit Informationen zur erfolgten Laufzeitmessung */ +/* */ +/************************************************************************/ +void +rtt_metric(PEER *pp, long rtt) +{ + BEACON *beapoi; /* Zeiger auf einen Baken-Eintrag */ + int i; + MBHEAD *mbp; + struct tm *p; + LNKBLK *lp; + PTCENT *ptcp; + int telemetrie; + + p = localtime(&sys_time); + + /* fuer alle Ports, bei denen die Bake freigegeben ist.. */ + for (i = 0, beapoi = beacon; i < L2PNUM; ++beapoi, ++i) + { +#ifdef BEACON_STATUS + if ((telemetrie = beapoi->telemetrie) == 2) +#else + if ((telemetrie = beapoi->telemetrie) >= 2) +#endif + { + (mbp = (MBHEAD *)allocb(ALLOC_MBHEAD))->l2fflg = L2CPID; + lp = pp->nbrl2l; + ptcp = ptctab + g_uid(lp, L2_USER); + if (telemetrie != 2) /* Format fuer automatische Auswertung */ + { + mbp->l4time = mbp->mbpc; + putid(pp->l2link->call, mbp); /* Node Call */ + putspa(10, mbp); + putprintf(mbp, "%2d %02d.%02d.%02d %02d:%02d:%02d", + lp->liport, + p->tm_mday, p->tm_mon + 1, p->tm_year % 100, + p->tm_hour, p->tm_min, p->tm_sec); + putprintf(mbp, " %7lu", rtt * 10L); + + if (pp->quality > 9999) + { + putprintf(mbp, " %2lumin", pp->quality / 6000); + } + else + putprintf(mbp, " %5lu", pp->quality * 10L); + + if (pp->my_quality > 9999) + { + putprintf(mbp, " %2lumin", pp->my_quality / 6000); + } + else + putprintf(mbp, " %5lu", pp->my_quality * 10L); + + if (pp->his_quality > 9999) + { + putprintf(mbp, " %2lumin", pp->his_quality / 6000); + } + else + putprintf(mbp, " %5lu", pp->his_quality * 10L); + + putprintf(mbp, " %7lu %lu\r", + lp->SRTT * 10L, + ptcp->inforx + ptcp->infotx); + } + else + { + putprintf(mbp, "%02d.%02d.%02d %02d:%02d:%02d ", + p->tm_mday, p->tm_mon + 1, p->tm_year % 100, + p->tm_hour, p->tm_min, p->tm_sec); + putid(pp->l2link->call, mbp); /* Node Call */ + putprintf(mbp, "(%02d)\rL3RTT=%lums L3SRTT=%lums (%lums/%lums) " + "L2SRTT=%lums SUM=%lu\r", + lp->liport, + rtt * 10L, + pp->quality * 10L, + pp->my_quality * 10L, + pp->his_quality * 10L, + lp->SRTT * 10L, + ptcp->inforx + ptcp->infotx); + } + rwndmb(mbp); +#ifdef __WIN32__ + sdui(beapoi->beadil, "METRIC\140", myid, (char)i, mbp); +#else + sdui(beapoi->beadil, "METRIC\140", myid, i, mbp); +#endif /* WIN32 */ + dealmb(mbp); /* Telemetrie-Frame kann jetzt weg */ + } /* Telemetrie */ + } /* alle Ports */ +} + +/************************************************************************/ +/* */ +/* L3RTT-Frames auswerten: Entweder sind es Messframes fuer Laufzeit- */ +/* messungen oder aber NODES-Meldungen bei ON5ZS-Routing */ +/* */ +/************************************************************************/ +void +rx_l3rtt_frame(PEER *rxpp, MBHEAD *mbp, char huge *savmbbp, WORD savmbgc) +{ + char rx_alias[L2IDLEN]; /* Ident des Nachbarn (wenn bekannt) */ + char ver[12]; /* Version des Nachbarn */ + WORD i, + j; /* Zaehler */ + char buffer[150]; /* Speicher fuer RTT String-Operationen */ + char *bp; + char version[4]; /* TNN-Version */ + ULONG prev_tic10; /* Zeitpunkt der RTT Messung in 10ms */ + ULONG prev_l3srtt; /* letzter SRTT (smoothed RTT) */ + ULONG prev_l3rtt; /* letzter gemessener RTT-Wert */ + PEER *rtt_pp; /* Pointer auf Nachbarliste */ + char buf2[8]; + ULONG rtt; + INDEX index; + ULONG maxtime; + + if (l4opco == L4INFTRA) /* Info-Transfer */ + { + if (match(mbp, "BROAD")) /* BROAD Kennung ? */ + { + if (cmpid(rxpp->l2link->call, orgnod) == TRUE) + if (rxpp->typ == TNN) /* kann der andere Info? */ + rx_broadcast(rxpp, mbp); /* dann auswerten */ + dealmb(mbp); /* Buffer entsorgen */ + return; + } + + if (match(mbp, "L3RTT:")) /* L3RTT Kennung ? */ + { + for (i = 0; ((i < 110) && (mbp->mbgc < mbp->mbpc)); i++) + buffer[i] = getchr(mbp); + + /* zur Sicherheit */ + memset(rx_alias, 0, L2IDLEN); + strcpy(&buffer[i], " 1 2 3 4 5 6 \n\0"); + + sscanf(&buffer[0], "%lu %lu %lu %lu %6s %11s %6s", + &prev_tic10, + &prev_l3srtt, + &prev_l3rtt, + (unsigned long *)&rtt_pp, + rx_alias, + ver, + buf2); + *version = NUL; + if (!strncmp(buf2, "TNN", 3)) + strcpy(version, &buf2[3]); + + for (i = j = 0; i < L2CALEN; i++) + if (rx_alias[i] == 0x00 || j == 1) + { + rx_alias[i] = ' '; /* mit Leerzeichen fuellen */ + j = 1; + } + +/************************************************************************/ +/* Eigenes Frame auswerten */ +/************************************************************************/ + if (cmpid(orgnod, myid)) /* selbst Absender */ + { + if ((rtt_pp == rxpp)) /* passender Nachbar */ + if ( tic10 > prev_tic10 /* Uhr nicht uebergelaufen */ + && rxpp->rttstart == prev_tic10 /* richtige Messung */ + && ((tic10 - prev_tic10) < 10000))/* nicht zu lang! */ + { /* gemessene L3-RTT */ + rtt = (tic10 - prev_tic10) + 2; + update_peer_quality(rxpp, rtt / 2, DONT_CHANGE_QUAL); + +/* Falls das Timeout auf einer Route mal abfaellt, melden wir hier */ +/* wieder die Routen-Qualitaet hoch. */ + if ((index = add_route(rxpp, rxpp->l2link->call, 1)) + != NO_INDEX) + update_lt(rxpp, index, 1); + rtt_metric(rxpp, (long)rtt); + rxpp->rttstart = 0L; + rxpp->rtt_time = L3_RTT_TIME; + +/* erste Bake ueberhaupt, dem Nachbarn wurde noch nicht die */ +/* Laufzeit uebertragen, das machen wir jetzt gleich mit einer */ +/* zweiten Bake. Dies fuehrt dazu, dass der Link sofort benutzbar */ +/* wird. Den Nachbarn merken wir selber provisorisch mit schlechtester */ +/* Laufzeit, bei der ersten regulaeren Bake wird das durch die echte */ +/* Laufzeitmeldung korrigiert. Der provisorische Wert wird nicht */ +/* an andere Nodes weiterverbreitet. */ + + if ((prev_l3srtt == 0) && (prev_l3rtt == 0)) + send_l3srtt_frame(rxpp); + + } + dealmb(mbp); + return; + } /* eigenes L3RTT-Frame */ + +/* Fremdes L3RTT-Frame auswerten, und an Nachbarn zurueck */ + if (cmpid(rxpp->l2link->call, orgnod) == TRUE) + { + if (time_to_live >= 1) + { /* noch Restlebenszeit.. */ + mbp->mbbp = savmbbp; + mbp->mbgc = savmbgc; + /* Frame sofort zurueck an Absender */ + toneig(rxpp, mbp); + + /* Frame auswerten */ + if (strnicmp("LEVEL3_V2.1", ver, 11) == 0) + { + if (rxpp->typ == NETROM) + set_peer_typ(rxpp, TNN); + rxpp->version = atoi(version); + cpyals(rxpp->l2link->alias, rx_alias); + } + else + cpyals(rx_alias, rxpp->l2link->alias); + + /* meldet der Nachbar INP-Faehigkeit ? */ + if (strstr(buffer, "$N")) + { +#ifndef L4NOBAKE + /* Partner ist noch nicht I und wir wollen auch einen I-Link */ + if ((rxpp->typ != INP) && (rxpp->soll_typ == INP)) +#else + /* Partner ist noch nicht I und wir wollen auch einen I-Link */ + if ( ((rxpp->typ != INP) && (rxpp->soll_typ == INP)) + ||(rxpp->soll_typ == NETROM)) /* Routing-Typ steht noch nicht*/ + /* fest, Nachbar will I, dann */ + /* stellen wir auf INP um. */ +#endif /* L4NOBAKE */ + { + set_peer_typ(rxpp, INP); /* Typ aendern */ +#ifdef L4NOBAKE + rxpp->soll_typ = INP; /* Typ auf INP setzen. */ +#endif /* L4NOBAKE */ + send_inp_nodebeacon(rxpp); /* uns selber melden */ + } + } + + /* MaxTime fuer INP-Nachbarn */ + if (rxpp->typ == INP) + { + /* Nachbar sagt uns eine MaxTime ? */ + if ((bp = strstr(buffer, "$M")) != NULL) + { + /* Ja, dann uebernehmen */ + sscanf(bp + 2, "%lu", &maxtime); + rxpp->maxtime = (UWORD)maxtime; + } + else + rxpp->maxtime = 0; /* Nein, dann keine MaxTime */ + } + + if (prev_l3srtt >= 5L) + update_peer_quality(rxpp, DONT_CHANGE_QUAL, prev_l3srtt); + + if ((index = add_route(rxpp, rxpp->l2link->call, 1)) != NO_INDEX) + { + update_lt(rxpp, index, 1); + if (update_alias(index, rx_alias)) + propagate_node_update(index); + } + return; + } + } + } /* L3RTT: */ + } /* L4-Info-Frame */ + dealmb(mbp); +} + +/* End of src/l3rtt.c */ diff --git a/src/l3sock.c b/src/l3sock.c new file mode 100755 index 0000000..9828181 --- /dev/null +++ b/src/l3sock.c @@ -0,0 +1,446 @@ +#include "tnn.h" + +#ifdef TCP_STACK + +TSOCKET sockets[NUM_SOCKETS]; + +static int SocketAlloc(void); /* Ein socket anlegen. */ +static BOOLEAN SearchPort(ULONG); /* Pruefen, ob LocalPort belegt ist. */ + + +/* Ein socket anlegen. */ +int Socket(int domain, int type, int protocol) +{ + register int i; + + if ((i = SocketAlloc()) == EOF) /* Neuen Socket erstellen.*/ + return(EOF); /* Kein Socket mehr frei. */ + + sockets[i].Socket = i; /* Socket setzen. */ + sockets[i].Domain = domain; /* Domain setzen. */ + sockets[i].Type = type; /* Protokoll-Typ setzen. */ + sockets[i].State = TCP_SOCKET; /* Socket-Status setzen. */ + sockets[i].tos = 0; /* Typ of Service. */ + sockets[i].TState = TCP_CLOSED; /* TCP-Statusaenderungen. */ + sockets[i].IpDest = 0; /* IP-Adresse vom Nachbarn. */ + sockets[i].RecvNext = 0; /* Next-Frame. */ + sockets[i].SendNext = 0; /* Sequence Number */ + sockets[i].SendUnacked = 0; /* Sequence Number */ + sockets[i].LocalPort = 0; /* Local-Port setzen. */ + sockets[i].PacNum = 0; /* Frame-Zahler. */ + sockets[i].MaxListen = 0; /* Groesse der Warteschlange. */ + sockets[i].Listen = 0; /* Momentan in der Warteschlange. */ + sockets[i].RecvEvent = FALSE; /* Select Signalisieren - Empfang. */ + sockets[i].SendEvent = FALSE; /* Select Signalisieren - Senden. */ + sockets[i].DestPort = 0; /* Nachbar-Port. */ + sockets[i].UrgPointer = 0; /* Urgent Pointer. */ + + return(i); /* Neuer Socket. */ +} + +/* Verbindungsbau annehmen/ablehnen. */ +int Accept(int s, struct Sockaddr *addr, Socklen_t *addrlen) +{ + TSOCKET *sock = &sockets[s]; + int NewSock; + struct Sockaddr_in sin; + + if (!sock) /* Angegebener Socket wurde nicht in der Socket-Liste gefunden. */ + return(EOF); /* Abbrechen. */ + + memset(&sin, 0, sizeof(sin)); /* Frischer Buffer holen. */ + sin.sin_family = AF_INET; /* Type setzen. */ + sin.sin_port = Htons((unsigned short)sock->LocalPort); /* Local-Port*/ + /* setzen. */ + sin.sin_addr._S_addr = sock->IpDest; /* IP-Adresse setzen. */ + + memcpy(addr, &sin, *addrlen); + + sock->RecvEvent = FALSE; /* Select - Empfang ausschalten. */ + sock->SendEvent = FALSE; /* Select - Sender ausschalten. */ + + if ((NewSock = Socket(sock->Domain, sock->Type, 0)) == EOF) /* Neuen Socket*/ + /* anlegen. */ + return(EOF); /* Neuer Socket kann nicht erstellt werden. */ + + sockets[NewSock].Socket = NewSock; + sockets[NewSock].State = TCP_CONNECTED; /* Socket-Status auf */ + /* CONNECTED setzen. */ + sockets[NewSock].TState = TCP_SYNCON;/* Verbindungsaufbau bestaetigen. */ + sockets[NewSock].IpDest = sock->IpDest; /* IP-Adresse setzen. */ + sockets[NewSock].RecvNext = sock->RecvNext; + sockets[NewSock].SendNext = sock->SendNext; + sockets[NewSock].SendUnacked = sock->SendUnacked; + sockets[NewSock].tos = sock->tos; /* Type of Service setzen. */ + sockets[NewSock].LocalPort = sock->LocalPort; /* Local-Port setzen. */ + sockets[NewSock].DestPort = sock->DestPort; /* Nachbar-Port setzen. */ + sockets[NewSock].UrgPointer = sock->UrgPointer; /* Urgent Pointer setzen. */ + + sock->Listen--; + + return(NewSock); /* Neuer Socket. */ +} + +/* Socket schliessen. */ +void Close(int Sock) +{ + register int i; + + for (i = 1; i < NUM_SOCKETS; ++i) /* Durchsuche die Socket-Liste. */ + { + if (sockets[i].Socket != Sock) /* Socketvergleich. */ + continue; /* Zum naechsten Eintrag. */ + + if (sockets[i].State == TCP_CONNECTED) /* Socket mit Status CONNECTED. */ + { + switch (sockets[i].TState) /* TCP-Status. */ + { + case TCP_ACKWAIT : /* Status Stabil: Warte auf ACK-Bestaetigung. */ + if (sockets[i].PacNum) /* Es liegen noch Frames an. */ + sockets[i].TState = TCP_PSHWAITFIN; /* Neuer Status: Sende alle */ + else /* offenstehende Packete. */ + sockets[i].TState = TCP_ACKWAITFIN;/* Neuer Status: Warte auf ACK,*/ + return; /* danach FIN senden. */ + + case TCP_ESTABLISHED : /* Verbindung ist stabil. */ + if (sockets[i].PacNum) /* Es liegen noch Frames an. */ + sockets[i].TState = TCP_PSHSENTFIN; /* Neuer Status:Naechstes */ + else /* Packet senden. */ + sockets[i].TState = TCP_FINSENT; /* Neuer Status: Socket sofort */ + return; /* schliessen. */ + + default : + return; + } + } + + DelSock(sockets[i].Socket); /* Socket entsorgen. */ + return; + } +} + +/* Socket binden. */ +int Bind(int s, struct Sockaddr *name, Socklen_t namelen) +{ + TSOCKET *sock = &sockets[s]; + + if (!sock) /* Angegebener Socket wurde nicht in der Socket-Liste gefunden. */ + return(EOF); /* Abbrechen. */ + + if (sock->State != TCP_SOCKET) /* Socket-Status muss auf TCP_SOCKET stehen. */ + return(EOF); /* Status stimmt nicht ueberein. */ + + if (SearchPort(((struct Sockaddr_in *)name)->sin_port)) /* Pruefe, ob der */ + /* Port belegt ist. */ + return(EOF); /* Abbrechen.. */ + + sock->LocalPort = Ntohs(((struct Sockaddr_in *)name)->sin_port);/* Port und */ + sock->State = TCP_BIND; /* Socket-Status BIND setzen. */ + return(FALSE); +} + +/* Lausche auf Socket. */ +int Listen(int s, int Number) +{ + TSOCKET *sock = &sockets[s]; + + if (!sock) /* Angegebener Socket wurde nicht in der Socket-Liste gefunden. */ + return(EOF); /* Abbrechen. */ + + if (sock->State != TCP_BIND) /* Kein Status BIND */ + return(EOF); /* Abbrechen. */ + + sock->MaxListen = Number; /* Groesse der Warteschlange setzen. */ + sock->State = TCP_LISTEN; /* Socket-Status auf LISTEN setzen. */ + return(FALSE); +} + +/* Daten Empfangen. */ +int Recv(int Sock, char *Buffer, int Len, int flag) +{ + TSOCKET *sock = &sockets[Sock]; +#ifdef L1TCPIP + DATENRX *Drx; +#endif /* L1TCPIP */ + int DataLen = 0; + int i = 0; + + if (!sock) /* Angegebener Socket wurde nicht in der Socket-Liste gefunden. */ + return(EOF); /* Abbrechen. */ + + if (sock->TState >= TCP_CLOSE) /* Socket soll geschlossen werden. */ + { + sock->TState = TCP_CLOSED; + return(EOF); /* Dann machen wir das.. */ + } + +#ifdef L1TCPIP + if ((Drx = GetBuffer(sock)) == NULL) /* Buffer aus der EmpfangsListe holen. */ + return(FALSE); /* Kein eintrag gefunden. */ + + DataLen = Drx->Data->mbpc - Drx->Data->mbgc; /* Gesamtlaenge ermitteln. */ + + while (DataLen--) /* Zeichen in Buffer schreiben. */ + { + if (Len == i) /* Buffergroesse beachten. */ + break; /* Wenn zu gross, abbrechen. */ + + Buffer[i++] = getchr(Drx->Data); /* Schreibe in Buffer. */ + } + + if (Drx->Data->mbpc == Drx->Data->mbgc) /* Alle zeichen verarbeitet. */ + { + sock->RecvEvent = FALSE; /* Select Empfang ausschalten. */ + dealmb((MBHEAD *)Drx->Data); /* Buffer entsorgen. */ + dealoc((MBHEAD *)ulink((LEHEAD *)Drx)); /* TX Segment entsorgen. */ + } + else + { + relink((LEHEAD *) Drx, ((LEHEAD *)rxDaten.tail)); /* Umhaengen in die RX*/ + /* Buffer-Liste. */ + sock->RecvEvent = TRUE; /* Select siginalisieren Empfang ein. */ + } +#endif /* TCP_L1TCPIP */ + + return(i); /* Anzahl zeichen im Buffer. */ +} + +/* Daten Senden. */ +int Send(int Sock, char *Buffer, int DataLen, int Flag) +{ + TSOCKET *sock = &sockets[Sock]; + MBHEAD *Data = NULL; + int i = 0; + + if (!sock) /* Angegebener Socket wurde nicht in der Socket-Liste gefunden. */ + return(EOF); /* Abbrechen. */ + + if (sock->TState >= TCP_CLOSE) /* Socket soll geschlossen werden. */ + { + sock->TState = TCP_CLOSED; + return(EOF); /* Keine weiteren Daten senden. */ + } + + if (DataLen) /* Es gibt was zusenden. */ + { + if ((Data = (MBHEAD *)allocb(ALLOC_TCPSTACK)) == NULL)/* Buffer besorgen. */ + return(FALSE); /* Buffer ist voll. */ + + while (DataLen--) /* Alle zeichen in Buffer schreiben. */ + { + if (i == 214) /* Maximum Segment Size erreicht. */ + { + rwndmb(Data); /* Buffer zurueck spulen. */ + PutTXStack(sock->Socket, /* In die Sende-Liste haengen. */ + Data, + Data->mbpc - Data->mbgc, + (TACK + TPSH), + TCP_PSHSENT); + + sock->SendEvent = FALSE; /* Select signalisieren Sender aus. */ + sock->SendNext += i; /* Sequence Number aktualisieren. */ + return(i); /* Anzahl zeichen im Buffer. */ + } + + putchr(Buffer[i++], Data); /* Schreibe zeichen in Buffer. */ + } + + rwndmb(Data); /* Buffer zurueckspulen. */ + PutTXStack(sock->Socket, /* In die Sende-Liste haengen. */ + Data, + Data->mbpc - Data->mbgc, + (TACK + TPSH), + TCP_PSHSENT); + + sock->SendEvent = FALSE; /* Select signalisieren Sender aus. */ + sock->SendNext += i; /* Sequence Number aktualisieren. */ + } + + return(i); /* Anzahl zeichen im Buffer. */ +} + +/* Den Socket auf Aktivitaet pruefen. */ +int SelScan(int max_fd, Fd_set *readset, Fd_set *writeset, Fd_set *exceptset) +{ + int nready = 0; + register int i; + Fd_set lreadset, + lwriteset, + lexceptset; + + FD_ZERO_T(&lreadset); /* Filedescriptoren entleeren. */ + FD_ZERO_T(&lwriteset); + FD_ZERO_T(&lexceptset); + + for (i = 1; i < NUM_SOCKETS; ++i) /* Durchsuche die Socket-Liste. */ + { + if (FD_ISSET_T(sockets[i].Socket, readset)) /* Socketvergleich - Read. */ + { + if (sockets[i].RecvEvent) /* Es liegen daten in der Empfangsliste. */ + { + FD_SET_T((unsigned)sockets[i].Socket, &lreadset); /* Socket setzen. */ + nready++; /* Markiere, es wird was empfangen. */ + } + } + + if (FD_ISSET_T(sockets[i].Socket, writeset)) /* Socketvergleich - Write. */ + { + if (sockets[i].SendEvent) /* Es liegen daten in der Sendeliste. */ + { + FD_SET_T((unsigned)sockets[i].Socket, &lwriteset); /* Socket setzen. */ + nready++; /* Markiere, es wird was gesendet. */ + } + } + } + + *readset = lreadset; /* Aktion weiterleiten. */ + *writeset = lwriteset; + FD_ZERO_T(exceptset); /* Filedescriptoren entleeren. */ + + return nready; +} + +/* Den Socket auf Aktivitaet pruefen. */ +int Select(int max_fd, + Fd_set *readset, + Fd_set *writeset, + Fd_set *exceptset, + struct Timeval *timeout) +{ + int nready; + Fd_set lreadset, + lwriteset, + lexceptset; + + if (readset) /* Es soll auf Lesen geprueft werden. */ + lreadset = *readset; /* Socket-liste uebergeben.*/ + else + FD_ZERO_T(&lreadset); /* Filedescriptoren entleeren. */ + + if (writeset) /* Es soll auf Schreiben geprueft werden. */ + lwriteset = *writeset; /* Socket-liste uebergeben.*/ + else + FD_ZERO_T(&lwriteset); /* Filedescriptoren entleeren. */ + + FD_ZERO_T(&lexceptset); /* Filedescriptoren entleeren. */ + + nready = SelScan(max_fd, /* Den Socket auf Aktivitaet pruefen. */ + &lreadset, + &lwriteset, + &lexceptset); + + if (readset) /* Es soll auf lesen geprueft werden. */ + *readset = lreadset; /* Neue Socket-liste uebergeben. */ + + if (writeset) /* Es soll auf schreiben geprueft werden. */ + *writeset = lwriteset; /* Neue Socket-liste uebergeben. */ + + return nready; +} + +/* Einen neuen Socket anlegen. */ +static int SocketAlloc(void) +{ + register int i; + + for(i = 1; i < NUM_SOCKETS; i++) /* Durchsuche die Socketliste. */ + { + if (sockets[i].State == TCP_CLOSED) /* Eintrag ist frei. */ + return(i); /* Neuer Socket. */ + } + + return(EOF); /* Kein freier Eintrag vorhanden. */ +} + +/* Pruefe, ob der Socket in der Filedescriptoren-Liste steht. */ +BOOLEAN GetSocket(Socklen_t Sock, Fd_set *rmask) +{ + unsigned int i; + + for (i = 0; i < rmask->fd_count; i++) /* Durchsuche alle FD-Eintraege. */ + { /* Neuen Eintrag ermitteln und */ + if ((Socklen_t)rmask->fd_array[i] == Sock) /* vergleichen. */ + return(TRUE); /* Socket gefunden. */ + } + + return(FALSE); /* Kein Socket gefunden. */ +} + +/* Pruefe, ob der Local-Port belegt ist. */ +static BOOLEAN SearchPort(ULONG LocalPort) +{ + register int i; + + for (i = 1; i < NUM_SOCKETS; ++i) /* Durchsuche die Socketliste. */ + { + if (sockets[i].LocalPort == LocalPort) /* Portvergleich. */ + return(TRUE); /* Port ist schon belegt. */ + } + + return(FALSE); /* Kein Port gefunden. */ +} + +/* Den Socket aus der Socketliste suchen. */ +int SearchSock(int Sock) +{ + register int i; + + for (i = 1; i < NUM_SOCKETS; ++i) /* Durchsuche die Socketliste. */ + { + if (sockets[i].Socket == Sock) /* Socketvergleich. */ + return(sockets[i].Socket); /* Socket gefunden. */ + } + + return(EOF); /* Kein Socket gefunden oder mittlerweile entsorgt. */ + +} + +/* Socket als unbenutzt markieren. */ +void DelSocket(int Sock) +{ + register int i; + + for (i = 1; i < NUM_SOCKETS; ++i) /* Durchsuche die Socketliste. */ + { + if (sockets[i].Socket != Sock) /* Socketvergleich. */ + continue; /* Zum naechsten socket. */ + + sockets[i].State = TCP_CLOSED; /* Markiere socket als unbenutzt. */ + return; + } +} + +/* konvertiert die Kurzganzzahl hostshort Rechner- nach Netzwerk-Byteordnung.*/ +unsigned short +Htons(unsigned short n) +{ + return ((n & 0xff) << 8) | ((n & 0xff00) >> 8); +} + +/* konvertiert die Kurzganzzahl netshort von Netzwerk- nach Rechner-Byteordnung. */ +unsigned short +Ntohs(unsigned short n) +{ + return Htons(n); +} + +/* konvertiert die Langganzzahl hostlong von Rechner- nach Netzwerk-Byteordnung. */ +unsigned long +Htonl(unsigned long n) +{ + return ((n & 0xff) << 24) | + ((n & 0xff00) << 8) | + ((n & 0xff0000) >> 8) | + ((n & 0xff000000) >> 24); +} + +/* konvertiert die Langganzzahl netlong von Netzwerk- nach Rechner-Byteordnung. */ +unsigned long +Ntohl(unsigned long n) +{ + return Htonl(n); +} + +#endif /* TCPSTACK */ + +/* End of src/l3sock.c */ diff --git a/src/l3tab.c b/src/l3tab.c new file mode 100755 index 0000000..fa9b9d0 --- /dev/null +++ b/src/l3tab.c @@ -0,0 +1,949 @@ +/************************************************************************/ +/* */ +/* ***** ***** */ +/* ***** ***** */ +/* ***** ***** */ +/* ***** ***** */ +/* *************** *************** */ +/* ***************** ***************** */ +/* *************** *************** */ +/* ***** ***** TheNetNode */ +/* ***** ***** Portable */ +/* ***** ***** Network */ +/* ***** ***** Software */ +/* */ +/* File src/l3tab.c (maintained by: ???) */ +/* */ +/* This file is part of "TheNetNode" - Software Package */ +/* */ +/* Copyright (C) 1998 - 2008 NORD>peertab; /* Segment-Tabelle */ + PEER *pp; + + for (pp = peertab; pp < &peertab[netp->max_peers]; pp++) + if (!pp->used) break; + + if (pp != &peertab[netp->max_peers]) { /* nur wenn Platz */ + if ((pp->routes = calloc((size_t)netp->max_nodes, sizeof(ROUTE))) == NULL) + return(NULL); /* kein Speicher */ + pp->quality = /* Segment nicht erreichbar */ + pp->my_quality = + pp->his_quality = 0L; + pp->locked = FALSE; + pp->used = TRUE; + pp->num_routes = 0; + pp->primary = pp; + pp->maxtime = 0; + +#ifdef THENETMOD + /* Kein Dauerconnect zum Nachbarn (nur THENET-TYP). Ist keine */ + pp->constatus = 1; /* Aktivitaet, wird die Verbindung getrennt. */ +#endif /* THENETMOD */ + + netp->num_peers++; + return(pp); + } + return(NULL); +} + +void unregister_peer( /* Segment austragen */ + PEER *pp) /* Zeiger auf das Segment */ +{ + clear_peer(pp); /* Routen ueber das Segment verwerfen */ + free(pp->routes); /* Routentabelle freigeben */ + netp->num_peers--; + pp->used = FALSE; +} + +/************************************************************************/ +/* */ +/* Node id mit SSID-Bereich suchen */ +/* */ +/************************************************************************/ +INDEX +find_node_ssid_range(const char *id) +{ + NODE *np; + NODE *nodetab = netp->nodetab; + int max_nodes = netp->max_nodes; + int hash_tries; /* Anzahl Schritte bis Treffer */ + int ssid = SSID(id); + INDEX index; + + if (id[0] == FALSE) + return (NO_INDEX); + + index = hashid(id, max_nodes); + if ((np = nodetab + index) == NULL) + return (NO_INDEX); + + for (hash_tries = 0; /* Ab Hash-Position suchen */ + hash_tries < max_nodes; /* ueber die ganze Hash-Tabelle */ + hash_tries++) /* keine Nodes mehr uebrig? */ + { + if (np->id[0] == TRUE) + { + if ( (ssid >= SSID(np->id)) /* passt der SSID-Bereich? */ + && (ssid <= np->ssid_high)) + { + if (cmpcal(np->id, id)) + return (index); /* Index liefern */ + } + } + + if (++index >= max_nodes) /* np weiterruecken, Umbruch */ + { /* beachten */ + np = nodetab; + index = 0; + } + else + np++; + } + + return (NO_INDEX); +} + +/************************************************************************/ +/* */ +/* Node id mit festem SSID suchen */ +/* */ +/************************************************************************/ +INDEX +find_node_this_ssid(const char *id) +{ + NODE *np; + NODE *nodetab = netp->nodetab; + int max_nodes = netp->max_nodes; + int hash_tries; /* Anzahl Schritte bis Treffer */ + INDEX index; + + index = hashid(id, max_nodes); + np = nodetab + index; + + for (hash_tries = 0; /* Ab Hash-Position suchen */ + hash_tries < max_nodes; /* ueber die ganze Hash-Tabelle */ + hash_tries++) /* keine Nodes mehr uebrig? */ + { + if (np->id[0]) + if (cmpid(np->id, id)) /* gefunden? */ + return (index); /* Index liefern */ + if (++index >= max_nodes) /* np weiterruecken, Umbruch */ + { /* beachten */ + np = nodetab; + index = 0; + } + else + np++; + } + return (NO_INDEX); +} + +/************************************************************************/ +/* */ +/* einen Node einsortieren */ +/* */ +/************************************************************************/ +static void +sort_node(NODE *new_np) +{ + NODE *np; + char *id = new_np->id; /* Rufzeichen des neuen Nodes */ + int ssid = SSID(id); /* SSID des neuen Nodes */ + int i; + + for (np = (NODE *)netp->nodelis.head; + np != (NODE *)&netp->nodelis; + np = np->next) /* richtige Stelle finden */ + if ((i = strncmp(np->id, id, L2CALEN)) >= 0) + if ((i > 0) || (SSID(np->id) > ssid)) + break; + relink((LEHEAD *)new_np, (LEHEAD *)np->prev); +} + +/************************************************************************/ +/* */ +/* Node id zur Nodestabelle hinzufuegen + LINKTYP */ +/* */ +/************************************************************************/ +INDEX +add_node(const char *id) +{ + int i; + NODE *np; + NODE *nodetab = netp->nodetab; + int max_nodes = netp->max_nodes; + INDEX index; + + index = hashid(id, max_nodes); /* Position vorraussagen */ + np = nodetab + index; + + for (i = 0; i < max_nodes; i++) + { + if (!np->id[0]) /* Platz gefunden */ + { + cpyid(np->id, id); /* Call umkopieren */ + cpyals(np->alias, nulide); /* Alias loeschen */ + np->ipa = 0L; /* IP-Adresse loeschen */ + np->bits = 0; /* Subnet-Maskenbits loeschen */ + np->options = NULL; /* keine weiteren INP-Options */ + np->ssid_high = SSID(id); /* ohne SSID-Bereich */ + netp->num_nodes++; /* ein Node mehr */ + if (netp->num_nodes > num_nodes_max) + num_nodes_max = netp->num_nodes; + sort_node(np); /* Node einsortieren */ + return (index); /* Index liefern */ + } + if (++index >= max_nodes) /* np weiterruecken, Umbruch */ + { /* beachten */ + np = nodetab; + index = 0; + } + else + np++; + } + return (NO_INDEX); +} + +/************************************************************************/ +/* */ +/* einen Node aus der Liste nehmen */ +/* */ +/************************************************************************/ +void +del_node(INDEX index) +{ + NODE *np = netp->nodetab + index; + + destot(index); + np->id[0] = NUL; /* Eintrag unbenutzt */ + + /* INP: Node hatte eine IP, deshalb ARP- und IPR-Eintrag loeschen */ + /* aber nur wenn erlaubt */ + if (np->ipa != 0L && autoipr != 0) + { + arp_drop(np->ipa, NETROM_PORT, TRUE); + rt_drop(np->ipa, np->bits, TRUE); + } + + if (np->options != NULL) /* eventuell vorhandene Optionen loeschen */ + { + dealmb(np->options); /* Optionen loeschen */ + np->options = NULL; /* hat keine Optionen mehr */ + } + + netp->num_nodes--; /* ein bekannter Node weniger */ + + ulink((LEHEAD*)np); /* aussortieren */ +} + +/************************************************************************/ +/* */ +/* unerreichbare Nodes loeschen */ +/* */ +/************************************************************************/ +void drop_unreachable_nodes(void) /* Routes/Nodes loeschen */ +{ + ROUTE *rp; /* Zeiger auf eine Route */ + PEER *pp; /* Zeiger auf ein Segment */ + NODE *np; /* Zeiger auf einen Node */ + NODE *nodetab = netp->nodetab; /* Zeiger auf die Node-Tabelle */ + PEER *peertab = netp->peertab; /* Zeiger auf die Segment-Tabelle */ + int max_nodes = netp->max_nodes; /* Groesse der Nodes-Tabelle */ + int max_peers = netp->max_peers; /* Groesse der Segment-Tabelle */ + INDEX index; + +#ifdef L3TABDEBUG +#if MAX_TRACE_LEVEL > 2 + char notify_call1[10]; +#endif +#endif + + /* die ganze Nodetabelle durchgehen */ + for (index = 0, np = nodetab; index < max_nodes; index++, np++) + { + if (!np->id[0]) /* Eintrag ist unbenutzt */ + continue; /* braucht nicht bearbeitet zu werden */ + + /* alle Peers durchgehen */ + for (pp = peertab; pp < &peertab[max_peers]; pp++) + { + if (!pp->used) /* Eintrag ist unbenutzt */ + continue; /* braucht nicht bearbeitet zu werden */ + + rp = &pp->routes[index]; /* Zeiger auf den Routeneintrag */ + + if ( (rp->reported_quality != 0) /* wir haben Qualitaet gemeldet */ + || (rp->quality != 0)) /* und er auch */ + break; /* noch Routen vorhanden, nicht loeschen */ +#ifdef L3TABDEBUG +#if MAX_TRACE_LEVEL > 2 + call2str(notify_call1, np->id); + notify(3, "drop_unreachable_nodes(): node %s has no routing info", + notify_call1); +#endif +#endif + } + + /* steht nach dem Durchlauf der oberen Schleife der pp-Pointer */ + /* auf dem letzten Eintrag, dann kann geloescht werden */ + if (pp == &peertab[max_peers]) /* keine aktiven Routen mehr */ + { +#ifdef L3TABDEBUG +#if MAX_TRACE_LEVEL > 2 + call2str(notify_call1, np->id); + notify(3, "drop_unreachable_nodes(): no peer found for %s", notify_call1); +#endif +#endif + del_node(index); /* Node austragen */ + } + } +} + +/************************************************************************/ +/* */ +/* eine Route hinzufuegen */ +/* */ +/************************************************************************/ +INDEX +add_route(PEER *pp, const char *id, unsigned quality) +{ + INDEX index = find_node_this_ssid(id); + + if ((index == NO_INDEX) && quality) /* nur bei guter Qualitaet neu */ + index = add_node(id); + + if (index != NO_INDEX) /* nur wenn noch Platz war */ + update_route(pp, index, quality); + return (index); +} + +/************************************************************************/ +/* */ +/* eine Route aktualisieren */ +/* */ +/************************************************************************/ +void +update_route(PEER *pp, INDEX index, unsigned quality) +{ + ROUTE *rp = pp->routes + index; /* Zeiger auf die Route */ + +/* Empfangene Laufzeit aktualisieren */ + + if (quality >= HORIZONT) + quality = 0; /* Route ausgefallen */ + + if (rp->quality && !quality) /* faellt eine Route aus? */ + pp->num_routes--; + + if (!rp->quality && quality) /* neue Route? */ + pp->num_routes++; + + rp->quality = quality; /* Qualitaet neu setzen */ + + rp->timeout = (pp->secured) + ? (0) /* ohne Timeout */ +#ifndef THENETMOD + : ROUTE_TIMEOUT; +#else + : obcini; /* Lebensdauer einer Node aktualisieren. */ +#endif /* THENETMOD */ +} + +/************************************************************************/ +/* */ +/* Eintragen der L3-Lifetime fuer ein Ziel */ +/* */ +/************************************************************************/ +void +update_lt(PEER *pp, INDEX index, int lt) +{ + (pp->routes + index)->lt = lt; +} + +/************************************************************************/ +/* */ +/* Feststellen, ob sich der Alias aendert, und bei neuem Alias diesen */ +/* eintragen. */ +/* */ +/************************************************************************/ +BOOLEAN +update_alias(INDEX index, const char *alias) +{ + NODE *np = netp->nodetab + index; + + if (cmpcal(alias, nulide)) /* kein Alias gemeldet */ + return (FALSE); + if (cmpcal(np->alias, alias)) /* keine Aenderung */ + return (FALSE); + cpyals(np->alias, alias); /* neuen Alias setzen */ + return (TRUE); +} + +BOOLEAN +update_ssid(INDEX index, int ssid_high) +{ + NODE *np = netp->nodetab+index; + + if (np->ssid_high == ssid_high) + return (FALSE); /* keine Aenderung */ + np->ssid_high = ssid_high; /* obere SSID-Grenze nachtragen */ + return (TRUE); /* geaendert */ +} + +/* Grenzen pruefen */ +static void range(ULONG *oldval, ULONG newval) +{ + if (newval < RTT_MIN) + newval = RTT_MIN; + if (newval <= RTT_MAX) /* noch nicht am Horizont? */ + *oldval = newval; + else + *oldval = 0; +} + +/* Glaettung durchfuehren und Grenzen pruefen */ +static void +smooth(ULONG *oldval, ULONG newval) +{ + if (newval < RTT_MIN) + newval = RTT_MIN; + if (newval <= RTT_MAX) { /* noch nicht am Horizont? */ + if (*oldval) /* nicht die erste Messung */ + *oldval = ((*oldval + 1) * RTT_ALPHA1 - 1 + newval) / RTT_ALPHA2; + else + *oldval = (newval * RTT_BETA); + if (*oldval < 1) + *oldval = 1; + } else + *oldval = 0; /* Link ist tot, komplette Neumessung */ + /* ist notwendig */ +} + +/* Die Qualitaet eines Segmentes aktualisieren, wir unterscheiden dabei + seine und unsere Messung. Unbekannte/unveraenderte Werte werden + durch IGNORE_RTT (==0) uebergeben. + pp->his_quality und pp->my_quality koennen folgende Werte annehmen: + + 0 noch keine Messung in diese Richtung erfolgreich + RTT_MIN...RTT_MAX gueltiger Messwert + groesser RTT_MAX Peer nicht erreichbar + + pp->quality wird auf RTT_MAX+1 gesetzt + - wenn pp->my_quality nicht gueltig *oder* unbekannt + - wenn pp->his_quality nicht gueltig ist +*/ + +void update_peer_quality( +PEER *pp, /* fuer welches Segment? */ +ULONG my_quality, /* meine Messung */ +ULONG his_quality) /* Nachbarqualitaet */ +{ + if (his_quality != DONT_CHANGE_QUAL) { + if (his_quality > 0) /* hat er eine Messung? */ + range(&pp->his_quality, his_quality); + else + if (his_quality == 0) + pp->his_quality = 0; + } + + if (my_quality != DONT_CHANGE_QUAL) { + if (my_quality > 0) /* unsere Messung gueltig? */ + smooth(&pp->my_quality, my_quality); + else + if (my_quality == 0) + pp->my_quality = 0; + } + + if (pp->my_quality == 0) +#ifndef THENETMOD + pp->quality = 0; +#else + { + if (pp->typ != THENET) /* Alle Segmente ausser THENET Qualitaet updaten. */ + pp->quality = 0; + } +#endif /* THENETMOD */ + else { + if (pp->typ == FLEXNET) + range(&pp->quality, + (pp->my_quality + (pp->his_quality ? pp->his_quality : 6000))/2); + else +#ifdef THENETMOD + if (pp->typ != THENET) /* Alle Segmente ausser THENET Quali. updaten. */ +#endif /* THENETMOD */ + pp->quality = pp->my_quality; + } + + update_primary_peer(pp->l2link->call); +} + +/************************************************************************/ +/* */ +/* Routen ueber das Segment verwerfen */ +/* */ +/************************************************************************/ +static void +clear_peer(PEER *pp) +{ +#ifdef THENETMOD + if (pp->typ == THENET) /* Segment ist ein THENET-Typ */ + return; /* keine Aenderungen vornehmen. */ +#endif /* THENETMOD */ + + memset(pp->routes, 0, netp->max_nodes * sizeof(ROUTE)); + pp->num_routes = 0; /* Routen loeschen */ + drop_unreachable_nodes(); /* Routes/Nodes loeschen */ +} + +/************************************************************************/ +/* */ +/* Linkreset eines Nachbarn */ +/* */ +/************************************************************************/ +void +reset_peer(PEER *pp) +{ + int i; + NODE *np; + ROUTE *rp; + int max_nodes = netp->max_nodes; + + if (pp->typ <= TNN) + set_peer_typ(pp, NETROM); + for (i = 0, np = netp->nodetab, rp = pp->routes; + i < max_nodes; + i++, np++, rp++) + { + if (!np->id[0]) /* freier Eintrag? */ + continue; + rp->reported_quality = 0; /* Eintrag muss gemeldet werden */ + if (rp->quality != 0) /* Nachbar hatte gemeldet */ + if ( rp->timeout == 0 /* bisher sichere Route oder */ + || rp->timeout > 4) /* Timeout zu gross? */ + rp->timeout = 4; /* neues Timeout 3-4 Minuten */ + } + update_peer_quality(pp, 0, DONT_CHANGE_QUAL); + drop_unreachable_nodes(); +} + +/************************************************************************/ +/* */ +/* Verbindung zum Segment hergestellt */ +/* */ +/************************************************************************/ +void +connect_peer(PEER *pp) +{ + clear_peer(pp); /* Alle Ziele loeschen (erstmal) */ +} + +/************************************************************************/ +/* */ +/* Verbindung zum Segment beendet */ +/* */ +/************************************************************************/ +void +disconnect_peer(PEER *pp) +{ + clear_peer(pp); /* alle Routen loeschen */ +} + +void +set_peer_typ(PEER *pp, int typ) +{ + int i; + NODE *np; + ROUTE *rp; + int max_nodes; + + pp->typ = typ; + +#ifndef LINKSMOD_LOCALMOD + pp->secured = (typ == LOCAL_M) + || (typ == LOCAL) + || (typ == FLEXNET) + || (typ == INP); +#else + pp->secured = (typ == LOCAL_V) + || (typ == LOCAL_N) + || (typ == LOCAL_M) + || (typ == LOCAL) + || (typ == FLEXNET) + || (typ == INP); +#endif /* LINKSMOD_LOCALMOD */ + + /* bei INP werden nach Linkaufbau alles Nodes an den Nachbarn gemeldet */ + if (typ == INP) + { + max_nodes = netp->max_nodes; + for (i = 0, np = netp->nodetab, rp = pp->routes; + i < max_nodes; + i++, np++, rp++) + { + if (!np->id[0]) /* freier Eintrag? */ + continue; + rp->reported_quality = 0; /* Eintrag muss gemeldet werden */ + } + } +} + +/* Qualitaet des besten Weges (immer >= 1) */ +/* oder 0 wenn es keinen Weg zum Ziel gibt */ +unsigned +do_find_best_qual(INDEX index, PEER *notthis, PEER **retpp, int options) +{ + int i; + PEER *pp = netp->peertab, + *bestpp = NULL; + ROUTE *rp; + unsigned bestqual = 0; + unsigned quality = 0; + + for (i = netp->max_peers; i--; pp++) + { + if (!pp->used) + continue; + if (pp == notthis) + continue; + if ((pp->options & options) == 0) + continue; + rp = pp->routes + index; + quality = getquality(rp->quality, pp); + if ((quality && quality < bestqual) || !bestqual) + { + bestpp = pp; /* Route und Peer merken */ + bestqual = quality; + } + } + if (retpp) + *retpp = bestpp; /* besten Nachbarn liefern */ + return (bestqual); /* und Qualitaet als Rueckgabewert */ +} + +unsigned +getquality(unsigned route_qual, PEER *pp) +{ + ULONG qual; + + if (route_qual == 0 || pp->quality == 0) + return (0); + if (pp->typ <= NETROM) + { + qual = ((ULONG)route_qual) + pp->quality; + if (qual > HORIZONT) + qual = HORIZONT; + return ((unsigned)qual); + } + else + return (route_qual); +} + +/* find_route() wird vom L7 benutzt, um einen Connect zu einem Node + * aufzubauen. Dies kann ein dummer L2 sein (Local), ein + * L2 (Flexnet) oder ein L4 QSO (NetRom). + * Wegen Flexnet sieht das Addressfeld bei einem Connect recht witzig + * aus: + * fm DB0SRC to DB0DST via DB0MY DB0DUM DB0NBR + * DB0MY ist das eigene Rufzeichen (myid), DB0DUM ein schlichter L2- + * Wassertraeger und DB0NBR der Nachbar. DB0DUM entfaellt in der Regel. + * Besondere Vorkehrung wird fuer die ausgefallenen Nachbarn getroffen, + * sie stehen eventuell nicht in der Nodes-Liste, aber wir kennen sie + * ja noch als Nachbarn. + * In dest.call steht das Ziel-Call, call ist eventuell nur ein Nachbar + * auf dem Weg dorthin. + */ +int l3_find_route(char *call, DEST *dest) +{ + int max_peers = netp->max_peers; + INDEX index; + PEER *bestpp; + PEER *pp; + int i; + int ssid; + char *id; + int maske = DG | VC | VC_FAR; /* erstmal alles erlaubt */ + + + if ((index = find_node_this_ssid(call)) == NO_INDEX) + { + /* Kein Node, ist es vielleicht ein Alias ? */ + if ((index = find_alias(call)) == NO_INDEX) + { + /* Da das genaue Ziel nicht gefunden wurde, koennen wir noch nach dem */ + /* SSID-Bereich ueber Flexnet-Nachbarn suchen */ + if ((index = find_node_ssid_range(call)) != NO_INDEX) + { + /* Wir haben einen Flexnet-Weg gefunden - dann duerfen wir nachher auch */ + /* nur ueber einen Flexnet-Weg connecten */ + maske = FLEX_MASK; + } + } + } + + if (index != NO_INDEX) + { + if (find_best_qual(index, &bestpp, maske) > 0) + { + dest->via[0] = NUL; + cpyid(dest->nbrcal, bestpp->l2link->call); + + if (bestpp->typ > NETROM) + cpyidl(dest->via, bestpp->l2link->digil); + /* + * Wenn des Ziel nicht in den SSID-Bereich des Nachbarn passt, + * muessen wir das Nachbarrufzeichen in des via-Feld aufnehmen. + */ + id = netp->nodetab[index].id; + + ssid = SSID(id); + if ( (!cmpcal(id, bestpp->l2link->call)) + || (ssid < SSID(bestpp->l2link->call)) + || (ssid > bestpp->l2link->ssid_high)) + addid(dest->via, bestpp->l2link->call); + + dest->port = bestpp->l2link->port; + dest->typ = bestpp->typ; + dest->np = netp->nodetab+index; +#ifdef THENETMOD + if ( (bestpp->typ == THENET) /* Segment ist ein THENET-Typ */ + &&(dest->typ != 'U') /* wenn kein "direkt ('U')" markiert ist. */ + &&(bestpp->nbrl2l == NULL)) /* und kein aktiver Link. */ + connbr(bestpp); /* Link neu aufbauen. */ +#endif /* THENETMOD */ + + return(NODE_AVAILABLE); /* Ziel ist erreichbar */ + } + return(NODE_DOWN); + } + + /* wenn direkter Nachbar nicht erreichbar, dies mitteilen */ + for (pp = netp->peertab, i = 0; i < max_peers; pp++, i++) + if (pp->used) + if (cmpid(pp->l2link->call, call)) +#ifndef CONNECTMOD_NODE_AVAI + if (!pp->quality) { + dest->typ = pp->typ; + cpyid(dest->nbrcal, myid); + return(NODE_DOWN); /* Nachbar unerreichbar */ + } +#else + { + /* Auch wenn der Nachbar "unerreichbar" sein */ + /* sollte versuchen wir es ueber einen L2_link.*/ + dest->port = pp->l2link->port; /* L2-Port setzen. */ + dest->typ = 'U'; /* wir rufen direkt. */ + return(NODE_AVAILABLE); /* Ziel ist erreichbar */ + } +#endif /* CONNECTMOD_NODE_AVAI */ + + return(NODE_UNKNOWN); /* Ziel nicht gefunden */ +} + +/*----------------------------------------------------------------------*/ +/* Feststellen, ob zu einem Node noch ein Weg existiert. Wenn es keinen */ +/* aktiven Weg mehr gibt, wird dies dem L4 gemeldet. Dieser traegt dann */ +/* alle aktiven L4-Verbindungen aus. */ +/* Da wir die Wege nach der Qualitaet sortieren, reicht es zu pruefen, */ +/* ob der beste Weg ausgefallen ist. In diesem Fall erfolgt die Meldung */ +/* an den L4. */ +/* Diese Routine wird nach jeder Veraenderung der Qualitaet eines Weges */ +/* aufgerufen. */ +/*----------------------------------------------------------------------*/ +BOOLEAN +check_destot(INDEX index) /* ueberprueft, ob es noch verwendbare */ +{ /* Wege zu einem Ziel gibt */ + if (find_best_qual(index, NULL, DG) == 0) + { + destot(index); + return (TRUE); + } + return (FALSE); +} + +/*----------------------------------------------------------------------*/ +void +check_all_destot(void) +{ + INDEX index; + int max_nodes = netp->max_nodes; + + for (index = 0; index < max_nodes; index++) + check_destot(index); +} + +/*----------------------------------------------------------------------*/ +void +destot(INDEX index) /* Ziel ist nicht mehr erreichbar */ +{ + MBHEAD *mbp, + *nextmbp; + NODE *totnod = netp->nodetab + index; + + l3tol4(totnod); /* an L4 melden: Knoten wird entfernt */ + + for (mbp = (MBHEAD *)l3txl.head; /* L4 Sendeliste */ + mbp != (MBHEAD *)&l3txl.head; /* durchgehen */ + mbp = nextmbp) + { + nextmbp = (MBHEAD *)mbp->nextmh; + if ((NODE *)mbp->l2link == totnod) + { /* dieser Node? */ + ulink((LEHEAD *)mbp); + dealmb(mbp); + } + } +} + +/* den besten Weg zu einem Segment feststellen (wenn es mehrere gibt) */ +void +update_primary_peer(char *id) +{ + PEER *peertab = netp->peertab; /* Segment-Tabelle */ + PEER *pp; + PEER *bestpp = NULL; + ULONG quality; + ULONG bestqual = 0; + + /* den primaeren Weg suchen und merken */ + for (pp = peertab; pp < &peertab[netp->max_peers]; pp++) + if (pp->used) + { + if (cmpid(pp->l2link->call, id)) + { + if (bestpp) + { + quality = pp->quality; + if ((quality && quality < bestqual) || !bestqual) + { + bestpp = pp; + bestqual = quality; + } + } + else + { + bestpp = pp; + bestqual = pp->quality; + } + } + } + + /* und dann in allen Wegen (zu dem Nachbarn) eintragen */ + for (pp = peertab; pp < &peertab[netp->max_peers]; pp++) + if (pp->used) + if (cmpid(pp->l2link->call, id)) + pp->primary = bestpp; +} + +/* Kennen wir das Ziel als Ident? */ +INDEX +find_alias(char *ident) +{ + NODE *np = netp->nodetab; /* NET/ROM-Tabelle durchsuchen */ + INDEX i; + int max_nodes = netp->max_nodes; + + for (i = 0; i < max_nodes; i++, np++) + if (np->id[0]) /* Eintrag existiert? */ + if (cmpals(ident, np->alias)) + return (i); + return (NO_INDEX); /* nix gefunden */ +} + +/* Rufzeichen suchen */ +BOOLEAN +iscall(const char *id, NODE **retnp, PEER **bestpp, int options) +{ + INDEX index; + +/* Call ueber genaues Ziel oder/und ueber SSId suchen */ + if ((index = find_node_this_ssid(id)) == NO_INDEX) + index = find_node_ssid_range(id); + if (index != NO_INDEX) + { + if (retnp) + *retnp = netp->nodetab + index; + return (find_best_qual(index, bestpp, options) != 0); /* beste Qual */ + } + return (FALSE); /* nix gefunden */ +} + +/* End of src/l3tab.c */ diff --git a/src/l3tcp.c b/src/l3tcp.c new file mode 100755 index 0000000..5b2e02f --- /dev/null +++ b/src/l3tcp.c @@ -0,0 +1,856 @@ +#include "tnn.h" +#ifdef TCP_STACK + +LHEAD rxSegment; /* RX TCP-Segment. */ +LHEAD txSegment; /* TX TCP-Segment. */ +LHEAD rxDaten; /* RX-Buffer. */ + + +static void StackRX(void); /* Eingehende RX Segmente. */ +static void StackState(void); /* Statusanderungen. */ +static void StackTX(void); /* Ausgehende TX Segmente. */ + + +/* Initialisiere, */ +void StackInitTCP(void) +{ + inithd(&rxSegment); /* Frame fuer Empfangs-Liste. */ + inithd(&txSegment); /* Frame fuer Sende-Liste. */ + inithd(&rxDaten); /* RX-Bufferung. */ +} + +/* TCP-Service */ +void StackSRV(void) +{ + StackRX(); /* Eingehende RX-Segmente. */ + StackState(); /* Statusaenderungen. */ + StackTX(); /* Ausgehende TX-Segmente. */ +} + + +/* Neues TX-Segment in die Sende-Liste anlegen/anhaengen. */ +void PutTXStack(register int i , /* SOCKET */ + MBHEAD *Data, /* Daten ohne TCP-Header. */ + int DataLen, /* Datenlaenge. */ + unsigned short Flags, /* TCP-Flag. */ + unsigned char TState) /* Sendestatus. */ +{ + STACKTX *TSeq; + + if ((TSeq = (STACKTX *)allocb(ALLOC_TCPSTACK)) == NULL) /* Buffer besorgen. */ + { + sockets[i].TState = TCP_RSTSENT; /* Kein Speicher,Verbindung zuruecksetzen*/ + return; + } + + TSeq->Sock = i; /* Socket setzen. */ + TSeq->Data = Data; /* Daten setzen. */ + TSeq->Flags = Flags; /* TCP-Flag setzen. */ + TSeq->TState = TState; /* Sende-Status setzen. */ + TSeq->TimeLast = time(NULL); + TSeq->Timer = 0; /* Timer zuruecksetzen. */ + TSeq->Retry = 0; /* Retry zuruecksetzen. */ + + ++sockets[i].PacNum; /* Ein Frame mehr in der Sende-Liste. */ + + relink((LEHEAD *)TSeq, (LEHEAD *)txSegment.tail); /* In die Sende-Liste */ +} /* haengen. */ + +/* Entsorge alle RX-Daten. */ +static void DelDatenRX(int Sock) +{ + DATENRX *Drx; + DATENRX *DrxPrev; + + for (Drx = (DATENRX *)rxDaten.head; /* Durchsuche RX-Datenliste. */ + Drx != (DATENRX *)&rxDaten; + Drx = DrxPrev) + { + DrxPrev = Drx->next; + + if (Drx->Sock != Sock) /* Socketvergleich. */ + continue; /* Zum naechsten Eintrag. */ + + if (Drx->Data != NULL) /* Wenn es Daten gibt, */ + dealmb(Drx->Data); /* entsorgen. */ + + dealoc((MBHEAD *)ulink((LEHEAD *)Drx)); /* RX-Segment entsorgen. */ + } +} + +/* Entsorge alle TX-Segment. */ +static void DelTXSegment(int Sock) +{ + STACKTX *TSeq; + + for (TSeq = (STACKTX *)txSegment.head; /* Durchsuche die TX-Segmentliste. */ + TSeq != (STACKTX *)&txSegment; + TSeq = TSeq->next) + { + if (TSeq->Sock != Sock) /* Socketvegleich. */ + continue; /* Zum naechsten Eintrag. */ + + if (TSeq->Data != NULL) /* Wenn es daten gibt, */ + dealmb(TSeq->Data); /* entsorgen. */ + + dealoc((MBHEAD *)ulink((LEHEAD *)TSeq)); /* TX-Segment entsorgen. */ + return; + } +} + +/* Entsorge alle Buffer vom Socket. */ +void DelSock(int Sock) +{ + DelDatenRX(Sock); /* RX-Daten entsorgen. */ + DelTXSegment(Sock); /* TX-Segmente entsorgen. */ + DelSocket(Sock); /* Socket entsorgen. */ +} + +/* Einen Eintrag aus der RX-Liste holen. */ +DATENRX *GetBuffer(TSOCKET *Sock) +{ + DATENRX *Drx; + + for (Drx = (DATENRX *)rxDaten.head; /* Durchsuche die RX-Liste. */ + Drx != (DATENRX *)&rxDaten; + Drx = Drx->next) + { + if (Sock->Socket != Drx->Sock) /* Socketvergleich. */ + continue; /* Zum naechsten Socket. */ + + return(Drx); /* Aktueller Eintrag. */ + } + + return(NULL); /* Kein Eintrag gefunden. */ +} + +/* Eingehende TCP-Daten weiterleiten in die RX-Segmentliste. */ +void TCPIPProcess(register IP *ip, + register MBHEAD *bp) +{ + MBHEAD *Data; + STACKRX *RSeq; + + if ((Data = (MBHEAD *)allocb(ALLOC_MBHEAD)) == NULL) /* Buffer besorgen. */ + return; /* Kein Speicher, Empfangsbuffer entsorgt der IP-Router. */ + + while (bp->mbgc != bp->mbpc) /* Alle Zeichen in den Buffer schreiben. */ + putchr(getchr(bp), Data); + + rwndmb(Data); /* Buffer zurueckspulen. */ + + if ((RSeq = (STACKRX *)allocb(ALLOC_TCPSTACK)) == NULL)/* RX-Segment besorgen.*/ + { + dealmb(Data); /* Kein Speicher, Buffer entsorgen. */ + return; + } + + RSeq->Data = Data; /* Empfang-Daten setzen. */ + RSeq->IpHdr = ip; /* IP-Header setzen. */ + + relink((LEHEAD *)RSeq, (LEHEAD *)rxSegment.tail); /* Umhaengen in die */ + return; /* Empfangs-Liste. */ +} + +/* TCP-Header lesen. */ +void ReadTcpHeader(TCP *tcp, + IP *ip, + MBHEAD *bp) +{ + int temp_flag; + + tcp->srcPort = get16(bp); /* Port-Nummer der Quelle. */ + tcp->dstPort = get16(bp); /* Port-Nummer des Ziel. */ + tcp->seqnum = get32(bp); /* Sequenznummer des 1. Datenbytes */ + /* in diesem Segment. */ + tcp->acknum = get32(bp); /* Bestaetigungsnummer. */ + temp_flag = get16(bp); /* Flags einlesen. */ + tcp->data_offset = (temp_flag >> 12) & 0x0f; /* Datenworte im header. */ + tcp->res = (temp_flag >> 6) & 0x3f; /* nicht benutzt -> 0.*/ + tcp->flags = temp_flag & 0x3f; /* URG,ACK,PSH,RST,SYN & FIN. */ + tcp->window = get16(bp); /* Groesse des Buffers fuer diese Verb. */ + tcp->checksum = get16(bp); /* CRC-Checksum. */ + tcp->urgentPointer = get16(bp); /* Fuer wichtige Daten. */ + + if (tcp->flags == TSYN) /* Verbindungsaufbau. */ + { + int DataLen = 0, + options = 0, + i = 0; + /* Gesamtlaenge ermitteln */ + DataLen = ((tcp->data_offset * 4) + (ip->ihl * 4));/* (TCP-Header + Daten).*/ + options = (DataLen - TCP_HEADER); /* Optionslaenge ermitteln */ + /* (Data - TCP-Header abziehen). */ + + options = options / 2; + + for (i = 0; i < options; i++) + tcp->options[i] = (char)get16(bp); /* Optionen setzen. */ + } +} + +/* Entsorge alte TX-Segmente. */ +void DelSegment(register int i, + TCP *tcp) +{ + STACKTX *TSeq; + + for (TSeq = (STACKTX *)txSegment.head; /* Durchsuche alle TX-Segmente. */ + TSeq != (STACKTX *)&txSegment; + TSeq = TSeq->next) + { + if (TSeq->Sock != sockets[i].Socket) /* Socketvergleich. */ + continue; /* Zum naechsten Segment. */ + + if (sockets[i].SendNext == tcp->acknum) /* Frame uebertragen. */ + { + --sockets[i].PacNum; /* Ein Frame weniger. */ + + sockets[i].SendEvent = TRUE; /* Select signalisieren - weiter senden. */ + + if (TSeq->Data != NULL) /* Nur wenn es Daten gibt. */ + dealmb(TSeq->Data); /* Buffer leeren/entsorgen. */ + + dealoc((MBHEAD *)ulink((LEHEAD *)TSeq)); /* TX Segment entsorgen. */ + return; + } + else /* Frame konnte nicht uebertragen werden. */ + { + if (sockets[i].TState != TCP_RSTSENT) + sockets[i].SendEvent = FALSE; /* Select signalisieren - keine */ + } /* weiteren Frame senden. */ + } +} + +/* Daten auslesen und fuer Funktion Recv bereitstellen. */ +BOOLEAN ReadBuffer(register IP *ip, + register TCP *tcp, + register int i, + MBHEAD *bp) +{ + DATENRX *Drx; + unsigned int DataLen = 0; + + /* Gesamtlaenge ermitteln (TCP-Header + Daten). */ + DataLen = (ip->length) - ((tcp->data_offset * 4) + (ip->ihl * 4)); + + if (DataLen >= TCP_HEADER) + DataLen -= TCP_HEADER; /* TCP-Header abziehen. */ + else + DataLen = 0; + + if (DataLen) /* Es gibt Daten. */ + { + if ((Drx = (DATENRX *)allocb(ALLOC_TCPSTACK)) == NULL) /* Besorge Buffer. */ + return(TRUE); /* Speicher ist voll. */ + /* Besorge Buffer. */ + if ((Drx->Data = (MBHEAD *)allocb(ALLOC_TCPSTACK)) == NULL) + { + dealoc((MBHEAD *)ulink((LEHEAD *)Drx)); /* Buffer entsorgen. */ + return(TRUE); /* Speicher ist voll. */ + } + + Drx->Sock = sockets[i].Socket; /* Socket setzen. */ + sockets[i].RecvEvent = TRUE; /* Select Siginalisieren, */ + /* wir haben was empfangen. */ + + sockets[i].RecvNext += DataLen; /* Daten an den Seq-Wert anhaengen. */ + + while (DataLen--) /* Daten in Buffer schreiben. */ + putchr(getchr(bp), Drx->Data); + + rwndmb(Drx->Data); /* Buffer zurueckspulen. */ + relink((LEHEAD *) Drx, (LEHEAD *)rxDaten.tail); /* RX-Liste umhaengen. */ + } + + return(FALSE); /* Frame angenommen. */ +} + +/* Eingehende RX-Segment analysieren. */ +int ReadRXStack(TCP *tcp, IP *ip, MBHEAD *bp) +{ + register int i; + + for (i = 1; i < NUM_SOCKETS; ++i) /* Durchsuche die Socketliste. */ + { + switch(sockets[i].State) /* Socket status. */ + { + case TCP_LISTEN: /* LISTEN-Modus. */ + if (tcp->flags != TSYN) /* Nur annehmen, wenn neue Verbindung. */ + continue; /* Ansonsten zum naechsten Eintrag. */ + + if (sockets[i].LocalPort != tcp->dstPort) /* Portvergleich. */ + continue; /* Zum naechsten Eintrag. */ + + if (tcp->flags == TSYN) + { + if (sockets[i].Listen++ >= sockets[i].MaxListen)/* in die Warteschlange. */ + continue; /* Warteschlange ist voll, zum naechsten eintrag. */ + } + + /* Verbindungsaufbau starten. */ + sockets[i].IpDest = ip->source;/* Empfaenger, IP-Adresse setzen. */ + sockets[i].tos = ip->tos; /* Type of Service setzen. */ + sockets[i].RecvEvent = TRUE; /* Select signalisieren - */ + /* wir haben was empfangen. */ + sockets[i].DestPort = tcp->srcPort; /* Port-Nummer vom Ziel. */ + sockets[i].UrgPointer = tcp->urgentPointer; /* Flags einlesen. */ + + sockets[i].RecvNext = tcp->seqnum + 1; + sockets[i].SendUnacked = 1; + + sockets[i].SendNext = sockets[i].SendUnacked + 1; + + return(i); /* Socket uebergeben. */ + + case TCP_CONNECTED: /* CONNECTED-Modus. */ + if (sockets[i].DestPort != tcp->srcPort) /* Destportvergleich! */ + continue; + + return(i); /* Unser gesuchter Socket. */ + } + } + + return(EOF); /* Nix gefunden. */ +} + +/* Verbindung nicht annehmen/zuruecksetzen. */ +void SendRST(IP *ip, TCP *tcp) +{ + register int NewSock; + + /* Neuen Socket anlegen. */ + if ((NewSock = Socket(AF_INET, SOCK_STREAM, 0)) == EOF) + return; /* Neuer Socket kann nicht erstellt werden. */ + + sockets[NewSock].IpDest = ip->source; + sockets[NewSock].LocalPort = tcp->dstPort; + sockets[NewSock].DestPort = tcp->srcPort; + sockets[NewSock].SendUnacked= tcp->acknum; + sockets[NewSock].RecvNext = tcp->seqnum + 1; + + SendTcpFlag(NewSock, /* Frame an den Nachbarn senden. */ + NULL, + 0, + (TACK + TRST), + 0, + 0); + + DelSock(NewSock); /* Socket entsorgen. */ +} + +/* ACK-Statusaendernungen. */ +void StateACK(register int i, TCP *tcp) +{ + if ( (sockets[i].SendUnacked != tcp->acknum) /* Noch nicht aktualisiert, */ + &&(tcp->window != 0)) /* wenn noch was ins Fenster passt!. */ + sockets[i].SendUnacked = tcp->acknum; /* ACK-Aktualisieren. */ + + switch(sockets[i].TState) /* Aktueller Status. */ + { + /* Status schliessen: */ + case TCP_PSHWAITFIN : /* Sende alle offenstehende Packete. */ + if (tcp->window == 0) /* Nachbar kann keine Daten mehr annehmen. */ + sockets[i].SendEvent = FALSE; /* Select signalisieren, keine weiteren Frame senden */ + else /* Nachbar kann daten annehmen. */ + { + if (sockets[i].PacNum) /* Es gibt noch Frame. */ + { /* Neuer Status: */ + sockets[i].TState = TCP_PSHSENTFIN; /* Naechstes Packet senden. */ + sockets[i].SendEvent = TRUE;/* Select signalisieren, weiter senden.*/ + } + else /* Neuer Status: */ + sockets[i].TState = TCP_FINSENT; /* Socket sofort schliessen. */ + } + break; + + case TCP_ACKWAIT : /* Status Stabil: Warte auf ACK-Bestaetigung. */ + if (tcp->window == 0) /* Nachbar kann keine Daten mehr annehmen . */ + sockets[i].SendEvent = FALSE;/* Select signalisieren, keine weiteren Frame senden. */ + else /* Nachbar kann daten annehmen. */ + { /* Neuer Status: */ + sockets[i].TState = TCP_ESTABLISHED; /* Verbindung stabil. */ + sockets[i].SendEvent = TRUE; /* Select Signalisieren, */ + } /* weitere Frames senden. */ + break; + + /* Status schliessen: */ + case TCP_ACKWAITFIN : /* Warte auf ACK, danach FIN senden. */ + sockets[i].TState = TCP_FINSENT; /* Neuer Status: */ + /* Socket sofort schliessen. */ + sockets[i].SendEvent = TRUE;/* Select Signalisieren, weitere Frames senden. */ + break; + + case TCP_FINACKWAIT : /* Status schliessen: Warte auf ACK-Bestaetigung. */ + sockets[i].TState = TCP_FINWAIT; /* Neuer Status: */ + /* Warte auf FIN & ACK-Bestaetigung. */ + sockets[i].SendEvent = TRUE;/* Select Signalisieren, weitere Frames senden. */ + break; + + /* Status schliessen: */ + case TCP_ACKWAITCLOSED : /* Warte auf ACK-Bestaetigung, Socket entfernen. */ + sockets[i].TState = TCP_CLOSED; /* Entsorge Socket. */ + break; + + } +} + +/* RX-Segmente analysieren. */ +static void StackRX(void) +{ + STACKRX *RSeq; + register int i; + static TCP tcp; + + while ((RSeq = (STACKRX *)rxSegment.head) != (STACKRX *)&rxSegment) + { + ReadTcpHeader(&tcp, RSeq->IpHdr, RSeq->Data); /* TCP-Header lesen. */ + + /* Eingehende RX-Segment analysieren. */ + if ((i = ReadRXStack(&tcp, RSeq->IpHdr, RSeq->Data)) != EOF) + { + ReadBuffer(RSeq->IpHdr, &tcp, i, RSeq->Data); + switch (tcp.flags) + { + case (TACK + TFIN) : /* Nachbar will sofort getrennt werden. */ + sockets[i].RecvEvent = TRUE; /* Select signalisieren, wir haben was empfangen. */ + sockets[i].SendEvent = TRUE; /* Select signalisieren, weitere Frames senden. */ + + if ( (sockets[i].TState == TCP_ESTABLISHED) /* Verbindung stabil. */ + ||(sockets[i].TState == TCP_ACKWAIT) + ||(sockets[i].TState == TCP_PSHSENTFIN)) + { + sockets[i].RecvNext += 1; /* Bei Bestaetigung um ein erhoehen. */ + SendTcpFlag(i, /* ACK & FIN mit ACK-bestaetigen. */ + NULL, + 0, + TACK, + WINSIZE, + 0); + + /* Neuer Status: ACK & FIN */ + sockets[i].TState = TCP_FINSENTCLOSED;/* an den Nachbarn schicken.*/ + } + + if (sockets[i].TState == TCP_FINWAIT) /* FIN & ACK-Bestaetigung erhalten. */ + { + sockets[i].RecvNext += 1; /* Seq-Wert um eins erhoehen. */ + SendTcpFlag(i, /* ACK-Bestaetigung senden. */ + NULL, + 0, + TACK, + WINSIZE, + 0); + + sockets[i].TState = TCP_CLOSED;/* Socket kann geschlossen werden. */ + } + break; + + case (TACK + TPSH + TFIN) : /* Nachbar will sofort getrennt werden. */ + sockets[i].RecvEvent = TRUE;/* Select signalisieren, wir haben was empfangen. */ + sockets[i].SendEvent = TRUE;/* Select signalisieren, weitere Frames senden. */ + + SendTcpFlag(i, /* Verbindung zuruecksetzen. */ + NULL, + 0, + TRST, + WINSIZE, + 0); + + sockets[i].TState = TCP_CLOSED; /* Neuer Status: Socket entsorgen. */ + break; + + case (TACK) : /* ACK-Bestaetigung. */ + StateACK(i, &tcp); + break; + + + case (TACK + TPSH) : /* Es sind Daten im Header. */ + if (sockets[i].SendUnacked != tcp.acknum) + sockets[i].SendUnacked = tcp.acknum; + + sockets[i].SendEvent = TRUE; + SendTcpFlag(i, /* ACK-Bestaetigung senden. */ + NULL, + 0, + TACK, + WINSIZE, + 0); + /* Neuer Status: */ + sockets[i].TState = TCP_ESTABLISHED; /* Verbindung stabil. */ + break; + + + case (TRST) : /* Verbindung zuruecksetzen. */ + sockets[i].TState = TCP_RSTSENT; /* Socket entsorgen. */ + sockets[i].SendEvent = TRUE; + DelSock(i); + break; + } + + DelSegment(i, &tcp); + } + else + SendRST(RSeq->IpHdr, &tcp); /* Verbindung nicht annehmen/zuruecksetzen. */ + + dealmb(RSeq->Data); /* Buffer entsorgen. */ + dealoc((MBHEAD *)ulink((LEHEAD *)RSeq)); /* RX-Segment entsorgen. */ + } +} + +/* Je nach Status reagieren. */ +static void StackState(void) +{ + register int i; + + for (i = 1; i < NUM_SOCKETS; ++i) /* durchsuche alle Socket. */ + { /* Socket mit Status */ + if ( (sockets[i].State == TCP_CLOSED) /* Socket unbenutzt */ + ||(sockets[i].State == TCP_LISTEN) /* Listen */ + ||(sockets[i].TState == TCP_ESTABLISHED) /* Stabile Verbindung und */ + ||(sockets[i].TState == TCP_PSHSENT)) /* Frame senden nicht beachten. */ + continue; /* Zum naechsten Socket. */ + + switch(sockets[i].TState) /* Socket-Status. */ + { + case TCP_SYNCON: /* Verbindungsaufbau bestaetigen. */ + PutTXStack(i, /* SYN & ACK senden.*/ + NULL, + 0, + (TSYN + TACK), + TCP_SYNCON); + sockets[i].TState = TCP_PSHSENT; + continue; /* Zum naechsten Socket. */ + + + case TCP_FINSENT: /* Status schliessen: Socket sofort schliessen. */ + PutTXStack(i, /* FIN & ACK senden. */ + NULL, + 0, + (TACK + TFIN), + TCP_FINSENT); + sockets[i].TState = TCP_PSHSENT; /* Neuer Status: Frames senden. */ + continue; /* Zum naechsten Socket. */ + + /* Status schliessen: */ + case TCP_FINSENTCLOSED : /* Nach ACK-Bestaetigung, FIN & ACK-Senden.*/ + PutTXStack(i, /* FIN & ACK senden. */ + NULL, + 0, + (TACK + TFIN), + TCP_FINSENTCLOSED); + sockets[i].TState = TCP_PSHSENT; /* Neuer Status: Frames senden. */ + continue; /* Zum naechsten Socket. */ + + /* Status schliessen: */ + case TCP_PSHSENTFIN : /* Naechstes Frame senden. */ + if (!sockets[i].PacNum) /* Alle Frame gesendet. */ + sockets[i].TState = TCP_FINSENT; /* Neuer Status: FIN & ACK senden. */ + continue; /* Zum naechsten Socket. */ + + + case TCP_RSTSENT : /* Status schliessen: Verbindung zuruecksetzen. */ + PutTXStack(i, /* Frame mit Flag RST senden. */ + NULL, + 0, + TRST, + TCP_RSTSENT); + sockets[i].TState = TCP_PSHSENT; /* Neuer Status: Frames senden. */ + continue; /* Zum naechsten Socket. */ + + + case TCP_CLOSED : /* Socket leeren/entsorgen. */ + DelSock(i); + return; + } + } +} + +/* Frame senden. */ +static void StackTX(void) +{ + STACKTX *TSeq; + register int i; + time_t now; + + for (TSeq = (STACKTX *)txSegment.head; /* Durchsuche alle Socket. */ + TSeq != (STACKTX *)&txSegment; + TSeq = TSeq->next) + { + if ((i = SearchSock(TSeq->Sock)) == EOF) /* Socket ermitteln. */ + { /* Socket wurde mittlerweile geschlossen. */ + if (TSeq->Data != NULL) /* Gibt es Daten. */ + dealmb((MBHEAD *)TSeq->Data); /* Buffer leeren/entsorgen. */ + + dealoc((MBHEAD *)ulink((LEHEAD *)TSeq)); /* TX Segment entsorgen. */ + return; + } + + if (TSeq->Timer) /* Timer laeuft. */ + { + now = time(NULL); + + if (TSeq->TimeLast < now) + { + TSeq->TimeLast = time(NULL); + + if (TSeq->Timer < 20) + { + ++TSeq->Timer; + continue; + } + + /* Max. versuche ueberschritten. */ + if (TSeq->Retry >= TCP_MAX_RETRY) + { + /* Socket soll geschlossen werden. */ + if (sockets[i].TState == TCP_CLOSE) + { + /* Socket schliessen. */ + sockets[i].TState = TCP_CLOSED; + /* zum naechsten Frame. */ + continue; + } + + /* Socket soll geschlossen werden. */ + sockets[i].TState = TCP_CLOSE; + /* Select signalisieren. */ + sockets[i].RecvEvent = TRUE; + sockets[i].SendEvent = TRUE; + continue; + } + + ++TSeq->Retry; + TSeq->Timer = 0; + + if (TSeq->Data != NULL) + rwndmb(TSeq->Data); + + sockets[i].TState = TCP_PSHSENT; + } + } + + if ( (sockets[i].TState == TCP_PSHSENT) /* Frame an den Nachbarn senden */ + ||(sockets[i].TState == TCP_ESTABLISHED) /* wenn Verbindung stabil. */ + ||(sockets[i].TState == TCP_PSHSENTFIN)) /* Socket soll geschloessen */ + { /* werden, vorher alle Frames senden. */ + SendTcpFlag(i, /* Frame senden. */ + TSeq->Data, + (TSeq->Data == NULL ? 0 : TSeq->Data->mbpc - TSeq->Data->mbgc), + TSeq->Flags, + WINSIZE, + (unsigned short)(TSeq->Flags == (TSYN + TACK) ? TCP_OPTION : FALSE)); + + if ((unsigned short)(TSeq->Flags == (TSYN + TACK))) + { + sockets[i].TState = TCP_ACKWAIT; /* Warte auf ACK-Bestaetigung. */ + ++TSeq->Timer; /* Timer starten. */ + continue; /* Zum naechsten Frame. */ + } + + switch(TSeq->TState) /* Statusaendung. */ + { + case TCP_ESTABLISHED : /* Status: Stabile Verbindung. */ + case TCP_PSHSENT : /* Status: Frame senden. */ + if (sockets[i].TState == TCP_PSHSENTFIN) + { + sockets[i].TState = TCP_PSHWAITFIN;/* offenstehende Frames senden */ + ++TSeq->Timer; /* Timer starten. */ + continue; /* Zum naechsten Frame. */ + } + + /* Neuer Status: */ + sockets[i].TState = TCP_ACKWAIT; /* Warte auf ACK-Bestaetigung. */ + ++TSeq->Timer; /* Timer starten. */ + continue; /* Zum naechsten Frame. */ + + + case TCP_PSHSENTFIN : /* Status schliessen: Naechstes Packet senden. */ + sockets[i].TState = TCP_PSHWAITFIN;/* Status: Warte auf ACK-Meldung.*/ + ++TSeq->Timer; /* Timer starten. */ + continue; /* Zum naechsten Frame. */ + + + case TCP_FINSENT :/* Status schliessen: Socket soll geschlossen werden*/ + sockets[i].TState = TCP_FINACKWAIT; /* Neuer Status: Warte auf ACK. */ + ++TSeq->Timer; /* Timer starten. */ + continue; /* Zum naechsten Frame. */ + + /* Status schliessen: */ + case TCP_FINSENTCLOSED : /* Nach ACK-Bestaetigung, FIN & ACK-Senden.*/ + sockets[i].TState = TCP_ACKWAITCLOSED;/* Neuer Status: Warte auf ACK*/ + ++TSeq->Timer; /* Timer starten. */ + continue; /* Zum naechsten Frame. */ + + + case TCP_RSTSENT : /* Verbindung zuruecksetzen. */ + sockets[i].TState = TCP_CLOSED; /* Neuer Status: .Socket schliessen.*/ + ++TSeq->Timer; /* Timer starten. */ + continue; /* Zum naechsten Frame. */ + + + default: /* Fuer alle restlichen Status. */ + continue; /* Zum naechsten Frame. */ + } + } + } +} + + +/* TCP-Header zusammenbasteln. */ +MBHEAD * +htontcp(register int i, /* Aktueller Socket. */ + MBHEAD *Data, /* evl. Daten. */ + unsigned short flags, /* TCP-Flags. */ + unsigned short tcp_len, /* Headerlaenge. */ + unsigned short WinSize, /* Fenstergroesse. */ + BOOLEAN options) /* evl. Optionen. */ +{ + register MBHEAD *bp; + PSEUDO_HEADER pseudo_hdr; + unsigned short checksum; + WORD DataMbpc; /* Sicherung mbpc */ + WORD DataMbgc; /* Sicherung mbgc. */ + int SaveLen; + + bp = (MBHEAD *)allocb(ALLOC_MBHEAD); /* Buffer besorgen. */ + + put16((unsigned short)sockets[i].LocalPort, bp); /* Dest-Port´setzen. */ + put16((unsigned short)sockets[i].DestPort, bp); /* Source-Port setzen. */ + + put32((unsigned long)sockets[i].SendUnacked, bp); /* Ack-Nummer setzen. */ + put32((unsigned long)sockets[i].RecvNext, bp); /* Seq-Nummer setzen. */ + + put16((unsigned short)flags, bp); /* TCP-Flags setzen. (ACK, FIN, SYN...). */ + put16((unsigned short)WinSize, bp); /* Fenstergroesse setzen. */ + put16((unsigned short)0, bp); /* Checksum ERSTMAL auf 0 setzen. */ + put16((unsigned short)sockets[i].UrgPointer, bp); /* Urgent-Flag setzen. */ + + if (options) /* Nur wenn Optionen gewuenscht wird setzen. */ + { + put16((unsigned short)OPTEND, bp); /* End of Option List. */ + put16((unsigned short)OPTMSS, bp); /* Maximum Segment Size. */ + put16((unsigned short)OPTNOO, bp); /* No-Operation. */ + put16((unsigned short)OPTPA3, bp); + } + else /* Keine Optionen setzen. */ + { + if (tcp_len > TCP_HEADER) /* Es gibt daten. */ + { + int i = 0; + + SaveLen = i = Data->mbpc - Data->mbgc; /* Laenge ermitteln. */ + + DataMbpc = Data->mbpc; /* Werte sichern. */ + DataMbgc = Data->mbgc; + + while (i--) /* Alle zeichen einlesen und */ + putchr(getchr(Data), bp); /* in Buffer schreiben. */ + + rwndmb(Data); /* Buffer zurueckspulen. */ + } + } + + rwndmb(bp); /* Frame zurueckspulen. */ + + /************************ Pseudo-Header ermitteln. *************************/ + pseudo_hdr.source = my_ip_addr; /* Unsere IP-Adresse. */ + pseudo_hdr.dest = sockets[i].IpDest; /* IP-Adresse vom Nachbarn. */ + pseudo_hdr.protocol = TCP_PTCL; /* Protokoll-Typ. */ + pseudo_hdr.length = tcp_len; /* TCP-Header + Daten. */ + checksum = cksum(&pseudo_hdr, bp, (unsigned short)tcp_len);/* Checksume ermitteln. */ + + dealmb(bp); /* Alten buffer loeschen. */ + + bp = (MBHEAD *)allocb(ALLOC_MBHEAD); /* Neuen buffer besorgen. */ + + put16((unsigned short)sockets[i].LocalPort, bp); /* Dest-Port´setzen. */ + put16((unsigned short)sockets[i].DestPort, bp); /* Source-Port setzen. */ + + put32((unsigned long)sockets[i].SendUnacked, bp); /* Ack-Nummer setzen. */ + put32((unsigned long)sockets[i].RecvNext, bp); /* Seq-Nummer setzen. */ + put16((unsigned short)flags, bp); /* TCP-Flags setzen. (ACK, FIN, SYN...) */ + put16((unsigned short)WinSize, bp); /* Fenstergroesse setzen. */ + put16((unsigned short)checksum, bp); /* Checksum setzen. */ + put16((unsigned short)sockets[i].UrgPointer, bp); /* Urgent-Flag setzen. */ + + if (options) /* Nur wenn Optionen gewuenscht wird setzen. */ + { + put16((unsigned short)OPTEND, bp); /* End of Option List. */ + put16((unsigned short)OPTMSS, bp); /* Maximum Segment Size. */ + put16((unsigned short)OPTNOO, bp); /* No-Operation. */ + put16((unsigned short)OPTPA3, bp); + } + else /* Keine Optionen setzen. */ + { + if (tcp_len > TCP_HEADER) /* Es gibt daten. */ + { + int i = 0; + + i = Data->mbpc - SaveLen; /* Laenge ermitteln. */ + + if (i != Data->mbpc) + { + while (i--) + getchr(Data); + } + + while (SaveLen--) /* Alle zeichen einlesen und */ + putchr(getchr(Data), bp); /* in buffer schreiben. */ + } + } + + rwndmb(bp); /* Daten zurueckspulen. */ + return (bp); +} + +/* Frame fuer IP-Router vorbereiten. */ +void +SendTcpFlag(register int i, /* Aktueller Socket. */ + MBHEAD *Data, /* Reine Daten. */ + unsigned int DataLen, /* Bufferlaenge. */ + unsigned short Flag, /* TCP-Flags. */ + unsigned short WinSize, /* Fenstergroesse setzen.*/ + unsigned short Options) /* Optionen setzen. */ +{ + MBHEAD *bp; + unsigned short TcpLen; + unsigned short TcpFlags; + + /* TCP-Headerlaenge + evl. Optionen + */ + TcpLen = TCP_HEADER + Options + DataLen; /* Reine Daten ermitteln. */ + + if (Options) /* Nur wenn Optionen gewuenscht wird setzen. */ + { + TcpFlags = (TCP_HEADER + Options) << 10; /* TCP-Header + Optionen setzen.*/ + Options = TRUE; /* Optionen setzen. */ + } + else /* Keine Optionen. */ + { + TcpFlags = TCP_HEADER << 10; + Options = FALSE; /* Keine Optionen. */ + } + + TcpFlags |= Flag; + + bp = htontcp(i, /* TCP-Header + Daten zusammenfuegen. */ + Data, + TcpFlags, + TcpLen, + WinSize, + Options); + + ip_send(my_ip_addr, /* IP-Header basteln und ab in den IP-Router. */ + sockets[i].IpDest, + TCP_PTCL, + sockets[i].tos, + 0, + bp, + 0, + 0, + 0); +} + +#endif /* TCPSTACK */ + +/* End of src/l3tcp.c. */ diff --git a/src/l3thenet.c b/src/l3thenet.c new file mode 100755 index 0000000..be3b3e7 --- /dev/null +++ b/src/l3thenet.c @@ -0,0 +1,733 @@ +#include "tnn.h" + +#ifdef THENETMOD +#include "l3local.h" + +UWORD obcini /* Anfangswert Knotenlebensdauer */ + = 60; + +UWORD obcbro /* min Wert Restlebensdauer fuer Rundspruch */ + = 60; + +/* L4TIMEOUT */ +UWORD L4Timeout /* L4-Timeout, nur fuer THENET-Typ. */ + = 900; /* Wenn keine Aktivitaet wird */ + /* der Link getrennt. */ +/* NOROUTE */ +UWORD NoRoute /* Standardwert fuer # im Alias nicht zulassen. */ + = 0; + + +PARAM L4partab[] = { /* L4 Parameter Tabelle */ + {&worqua, 0, 255,"Min-Quality"}, /* min Qualiatet Autoupdate */ + {&obcini, 1, 255,"OBS_Init"}, /* Anfangswert Knotenlebensdauer. */ + {&obcbro, 1, 255,"OBS_Min"}, /* min Wert Restlebensdauer */ + /* fuer Rundspruch */ + {&broint_ui, 1, 240,"Broadcast"}, /* Rundspruchintervall in 1min. */ + {&l4_beta3, 1, 1000,"L4-Busytim"}, /* BUSY/REQ-TIMEOUT */ + /* (T3) = SRTT * BETA3 */ + /* L4TIMEOUT */ + {&L4Timeout, 60, 54000,"L4-Timeout"}, /* L4-Link no activity Timer. */ + + /* NOROUTE */ + {&NoRoute, 0, 1,"#Alias"}, /* 0 = Link-Nachbar mit # im . */ + /* Alias NICHT zulassen */ + /* 1 = Link-Nachbar mit # im */ + /* Alias zulassen. */ + /* Parameter 0 ist standard. */ +}; + +int L4partablen = (int)(sizeof(L4partab)/sizeof(PARAM)); + +static void add_nodes_info(MBHEAD **, NODE *, char *, PEER *, unsigned, UWORD); + +/************************************************************************/ +/* */ +/* Parameter anzeigen/aendern */ +/* */ +/************************************************************************/ +void ccpL4par(void) +{ + ccp_par("L4Parms:\r", L4partab, L4partablen); +} + + +/************************************************************************/ +/* */ +/* L4-Parameter auf Festplatte sichern. */ +/* */ +/************************************************************************/ +void dump_l4parms(MBHEAD *mbp) +{ + UWORD num; + PARAM *p; + + putstr(";\r; L4-Parameters\r;\r", mbp); + + for (p = L4partab, num = 1; num <= L4partablen; p++, num++) + { + if ( (p->paradr) + &&(strncmp(p->parstr, "unu", 3))) + putprintf(mbp, "L4PAR %s %u\r", p->parstr, *(p->paradr)); + } +} + +/************************************************************************/ +/* */ +/* L4-Parameter unter ROUTES aendern. */ +/* */ +/* z.Z. ist folgendes moeglich, */ +/* Qualitaet einer Route (nur THENET-TYP) aendern: */ +/* R CB0GLA QUAL=10..255 */ +/* */ +/* Connect-Status, 0 = wenn keine Aktivitaet, Verbindung trennen (X1J4).*/ +/* 1 = Verbindung wird gehalten (Dauerconnect z.b.XNET).*/ +/* R CB0GLA CONSTATUS=0..1 */ +/* */ +/************************************************************************/ +BOOLEAN RoutesL4Para(MBHEAD *mbp, PEER *pp) +{ +#define L4_NONE 0 +#define L4_QUAL 1 +#define L4_CONSTATUS 2 +#define BUFLEN 64 + + char pBuf[BUFLEN + 1]; + char call[10]; + unsigned int pCmd = L4_NONE; + unsigned int quality = 0; + int constatus = 0; + register int i; + + if ( (issyso()) /* Nur Sysop darf. */ + &&(clicnt > 0)) /* Parameter aendern. */ + { + do + { + memset(pBuf, 0, sizeof(pBuf)); /* Frischer Buffer */ + skipsp(&clicnt, &clipoi); /* ggf. Leerzeichen entfernen. */ + + for (i = 0; i < BUFLEN; ++i) + { + if (!clicnt) + break; + + if ( (*clipoi == ' ') /* Leerzeichen im Lese-Buffer. */ + ||(*clipoi == '=')) /* Zeichen '=' im Lese-Buffer. */ + { + clicnt--; /* Zeichen loeschen. */ + clipoi++; + break; /* Zeichen einlesen abbrechen. */ + } + + clicnt--; /* Zeichen im Lese-Buffer weniger. */ + pBuf[i] = toupper(*clipoi++); /* Zeichen in Buffer schreiben. */ + } + + if ( (strcmp(pBuf, "QUAL") == 0) /* Qualitaet aendern */ + ||(pBuf[0] == 'Q') + ) + pCmd = L4_QUAL; /* Modus setzen. */ + + if ( (strcmp(pBuf, "CONSTATUS") == 0) /* Connect-Status aendern. */ + ||(pBuf[0] == 'C') + ) + pCmd = L4_CONSTATUS; /* Modus setzen. */ + + + switch (pCmd) /* L4-Parameter auswerten. */ + { + case L4_QUAL : /* Qualitaet aendern. */ + + quality = nxtlong(&clicnt, &clipoi); /* Ermittle neue Qualitaet. */ + + if ( (quality > 9) /* Grenzbereich pruefen. */ + &&(quality < 256)) + pp->quality = quality; /* Neue Qualitaet setzen. */ + else /* Liegt ausserhalb im Grenzbereich. */ + { + if (pp->quality < 1) /* Nur wenn ungueltige Qualitaet, */ + pp->quality = worqua; /* minimale Qualitaet setzen. */ + } + + break; + + + case L4_CONSTATUS : /* Connect-Status aendert. */ + + constatus = nxtlong(&clicnt, &clipoi); /* Ermittle Connect-Status. */ + + if ( (constatus >= 0) /* Grenzbereich pruefen. */ + &&(constatus <= 1)) + pp->constatus = constatus; /* Neuer Connect-Status setzen. */ + + break; + + default : /* Unbekannter L4-Parameter. */ + break; + } + } while (clicnt > 0); /* evl. naechsten Paramter einlesen. */ + } + else + return(FALSE); + + call2str(call, pp->l2link->call); /* Rufzeichen. */ + mbp = putals("L4-Parameter:\r"); /* Buffer besorgen. */ + + putstr("--Call----Quality---ConStatus--\r", mbp); + + putprintf(mbp,"%-9s %-3d %-1d\r", + call, + pp->quality, + pp->constatus); + + prompt(mbp); /* L4-Parameter wurde geaendert, zurueck zum Prompt. */ + seteom(mbp); + return(TRUE); /* Kein Sysop oder keine Aenderungen. */ +} + +/************************************************************************/ +/* */ +/* Hat man mehrerer THENET-Links auf den gleichen Port, */ +/* wird in der Regel fuer jeden THENET-Partner eine */ +/* Broadcast-Bake geschickt,was aber unsinn ist - ausge- */ +/* nommen auf AX25IP-Ports. Fuer die Restlichen THENET- */ +/* Partner den Broadcast-Timer zuruecksetzen. */ +/* */ +/************************************************************************/ +void BroadcastBakeClear(PEER *pp) +{ + PEER *p; + int i; + int max_peers = netp->max_peers; + + /* durchsuche alle Segmente. */ + for (i = 0, p = netp->peertab; i < max_peers; i++, p++) + { + if (p->used) /* Nur benutze Eintraege. */ + { + if (pp->l2link->port == p->l2link->port) /* Link auf den gleichen Port. */ + p->brotim = 0; /* Broadcast-Timer zuruecksetzen. */ + } + } +} + +/************************************************************************/ +/* */ +/* Alterungs-Zaehler minimieren. */ +/* ggf Segment entfernen wenn Auto-Route. */ +/* */ +/************************************************************************/ +BOOLEAN OBSinitTimer(PEER *pp) +{ + if (pp->typ != THENET) /* Segment ist kein THENET. */ + return(FALSE); /* hat hier nix zu suchen. */ + + if (pp->obscnt == 0) /* Restlebensdauer fuer Rundspruch abgelaufen. */ + { + update_peer_quality(pp, 0L, DONT_CHANGE_QUAL); + memset(pp->routes, 0, netp->max_nodes * sizeof(ROUTE)); + pp->num_routes = 0; /* Routen loeschen */ + drop_unreachable_nodes(); /* Routes/Nodes loeschen */ + +#ifdef AUTOROUTING + if (pp->l2link->ppAuto == AUTO_ROUTE) /* Segment ist eine Auto-Route. */ + { +#ifdef AXIPR_HTML + /* Protokoll fuer HTML-Ausgabe aktualisieren. */ + SetHTML(pp->l2link->port, pp->l2link->call, NULL, FALSE); +#endif /* AXIPR_HTML */ + + unregister_neigb(pp->l2link->call, /* Segment austragen. */ + pp->l2link->digil, + pp->l2link->port); + return(TRUE); /* Segment wurde geloescht, weiter sagen. */ + } /* keine auto-route. */ +#endif /* AUTOROUTING */ + + } + else /* Restlebensdauer fuer Rundspruch noch nicht abgelaufen */ + --pp->obscnt; /* Restlebensdauer fuer Rundspruch um eins minimieren. */ + + return(FALSE); /* Segment weiterpruefen. */ +} + +/************************************************************************/ +/* */ +/* Suche ein Segment mit Typ THENET auf den angegebenen Port. */ +/* */ +/************************************************************************/ +static PEER *SearchSegmentTHENET(UWORD port) +{ + PEER *pp; + int i; + + /* Durchsuche alle Segmente. */ + for (i = 0, pp = netp->peertab; i < max_peers; i++, pp++) + { + if ( (pp->used) /* Nur benutzte eintraege. */ + && (pp->typ == THENET) /* Routing-Typ THENET. */ + && (pp->l2link->port == port)) /* auf den gesuchten port. */ + return(pp); /* Segment ist ein THENET. */ + } + + return(NULL); /* Kein Segment oder nicht auf den angebenen Port. */ +} + +/************************************************************************/ +/* */ +/* Broadcast-Nodes Bake erstellen und auf den angegebenen Port senden. */ +/* */ +/************************************************************************/ +static void sendui(UWORD port, char *NODES, MBHEAD *mbp) +{ + sdui("", /* an Level 2 senden */ + NODES, + myid, /* Absender ist unser Knotencall. */ + (char)port, /* an den angegebenen Port senden. */ + mbp); /* Alle Noden */ + + dealmb(mbp); /* Buffer wieder freigeben */ +} + +/************************************************************************/ +/* */ +/* Broadcast-Nodes Bake erstellen und auf den angegebenen Port senden. */ +/* */ +/************************************************************************/ +void bcast(MBHEAD **mbpp, char *call, UWORD port) +{ + if (*mbpp == NULL) /* Noch keine Daten in der Bake. */ + { /* Buffer besorgen. */ + (*mbpp = (MBHEAD *)allocb(ALLOC_MBHEAD))->l3_typ = L2CUI; + + if (mbpp == NULL) /* Kein Buffer frei. */ + return; /* Abbrechen. */ + + putchr((char)0xFF, *mbpp); + pu6chr(alias, *mbpp); + } + + rwndmb(*mbpp); /* vor dem Senden Buffer zurueckspulen */ + (*mbpp)->l2fflg = L2CNETROM; /* Als UI-Bake rausschicken an "NODES" */ + + sendui(port, call, *mbpp); /* Bake auf den gewuenschten Port senden. */ + + *mbpp = NULL; +} + +/************************************************************************/ +/* */ +/* Umrechnung NETROM-Qualitaet <-> Laufzeit */ +/* */ +/************************************************************************/ +static int +rtt2qual(ULONG rtt) /* Laufzeit zu Qualitaet */ +{ + int qual; + + if (rtt) + { + qual = 255 - (unsigned)(rtt / autoqual); + if (qual > 254) + qual = 254; + if (qual < 3) + qual = 3; + return (qual); + } + return (0); /* ausgefallen */ +} + +/************************************************************************/ +/* */ +/* Einen Weg zu dem Infocast-Frame fuer einen Nachbarn hinzufuegen. */ +/* Das Frame wird gesendet, sobald es voll ist oder in BroadCastBake() */ +/* wenn der Timeout abgelaufen ist. */ +/* */ +/************************************************************************/ +static void add_nodes_info(MBHEAD **mbpp, + NODE *node, + char *call, + PEER *viapp, + unsigned qualit, + UWORD port) +{ + int qual = rtt2qual(qualit); + + /* schlechte Wege werden unterdrueckt, abmelden kennt NETROM nicht */ + if (qual <= worqua) + return; + + if (*mbpp) + { + if (((*mbpp)->mbpc + 21) > 256) /* bis Frame voll */ + bcast(mbpp, /* Broadcast-Bake senden. */ + call, + port); + } + + if (*mbpp == NULL) + { /* neues Frame holen */ + (*mbpp = (MBHEAD *)allocb(ALLOC_MBHEAD))->l3_typ = L2CUI; + putchr((char)0xFF, *mbpp); + pu6chr(alias, *mbpp); + } + + putfid(node->id, *mbpp); /* Call des Zieles */ + pu6chr(node->alias, *mbpp); /* Ident des Zieles */ + if (qualit && viapp) + putfid(viapp->l2link->call, *mbpp); /* Nachbar des Zieles */ + else + putfid(myid, *mbpp); /* Nachbar geloescht */ + putchr((char)rtt2qual(qualit), *mbpp); +} + +/************************************************************************/ +/* */ +/* LOCAL-Route hinzufuegen fuer Broadcast-Nodes Bake. */ +/* */ +/************************************************************************/ +static void AddLocal(PEER *pp, MBHEAD **mbp, UWORD port, char *call) +{ + PEER *Segm; + PEER *BestSegm; + NODE *np; + INDEX index; + register int i; + unsigned int qual = 0; + + /* Durchsuche alle Segmente. */ + for (i = 0, Segm = netp->peertab; i < max_peers; i++, Segm++) + { + if (!Segm->used) /* Wenn kein Eintrag, */ + continue; /* zum naechsten Segment. */ + + if ( (Segm->typ != LOCAL) /* Local-Route. */ + &&(Segm->typ != LOCAL_M)) /* Local-Route mit Messung. */ + continue; + + /* Ermittle den index. */ + if ((index = find_node_this_ssid(Segm->l2link->call)) != NO_INDEX) + { + np = &netp->nodetab[index]; /* Nodes-Eintrag ermitteln. */ + qual = find_best_qual(index, /* Qualitaet ermitteln. */ + &BestSegm, + OPTIONS_MASK); + + if ((BestSegm == NULL) || (qual == 0)) /* geloeschte Nodes abfangen */ + continue; + + if (np->alias[0] == '#') /* versteckter Node. */ + continue; + + add_nodes_info(mbp, /* Local-Route hinzufuegen. */ + np, + call, + BestSegm, + qual, + port); + continue; /* zum naechsten Eintrag. */ + } + } /* for */ +} + +/************************************************************************/ +/* */ +/* Nodes hinzufuegen fuer Broadcast-Nodes Bake. */ +/* */ +/************************************************************************/ +static void AddNodes(char *ppcall, UWORD port, MBHEAD **mbp) +{ + PEER *pp, + *bestpp; + NODE *np; + INDEX index; + BOOLEAN addlocal = FALSE; + register int i; + unsigned int qual = 0; + + /* Durchsuche alle Segmente. */ + for (i = 0, pp = netp->peertab; i < max_peers; i++, pp++) + { + if (!pp->used) /* Wenn kein Eintrag, */ + continue; /* zum naechsten Segment. */ + + if (addlocal == FALSE) /* LOCAL-Routen sind noch nicht behandelt. */ + { + AddLocal(pp, mbp, port, ppcall); /* LOCAL-Routen hinzufuegen. */ + addlocal = TRUE; /* LOCAL-Routen sind abgearbeitet. */ + } + + if (pp->typ != THENET) /* Kein Routing-Typ THENET. */ + continue; /* Zum naechsten Segment. */ + + for (np = (NODE *)netp->nodelis.head; + np != (NODE *)&netp->nodelis; /* sortierte Nodes-Liste durchgehen */ + np = np->next) + { + if (np->id[0]) /* nur benutzte Eintraege interessieren */ + { + index = (INDEX)(np - netp->nodetab); /* Index berechnen */ + qual = find_best_qual(index, /* Qualitaet ermitteln. */ + &bestpp, + OPTIONS_MASK); + + if ((bestpp == NULL) || (qual == 0)) /* geloeschte Nodes abfangen */ + continue; /* Zum naechsten Eintrag. */ + + if (cmpid(bestpp->l2link->call, pp->l2link->call)) /* Callvergleich */ + { + int Timeout; + ROUTE *rp = bestpp->routes + index; /* Zeiger auf die Route. */ + + if (np->alias[0] == '#') /* versteckter Node. */ + continue; + + Timeout = rp->timeout; /* Timeout ermitteln. */ + + if (Timeout >= (obcini / 3)) /* mindestens 30% des Timeouts. */ + add_nodes_info(mbp, /* Node hinzufuegen. */ + np, + ppcall, + bestpp, + qual, + port); + continue; /* Zum naechsten Eintrag. */ + } /* Call war nicht gleich. */ + } /* nicht benutzer Eintrag. */ + } /* for NODE */ + } /* for PEER */ +} + +#ifdef AX25IP +/************************************************************************/ +/* */ +/* Sende Broadcast-Nodes Bake zu jedem Segment mit Routing-TYP THENET. */ +/* Gilt nur fuer AX25IP-Port. */ +/* */ +/************************************************************************/ +void bcastAXIP(void) +{ + PEER *pp; + int i; + /* Durchsuche alle Segmente. */ + for (i = 0, pp = netp->peertab; i < max_peers; i++, pp++) + { + if ( (pp->used) /* Nur benutzte eintraege. */ + && (pp->typ == THENET) /* Routing-Typ THENET. */ + && (kissmode(pp->l2link->port) == KISS_AXIP)) /* Portvergleich. */ + { + MBHEAD *mbp = NUL; + + if (pp->obscnt) /* Wenn ein Link zum Nachbarn steht, */ + AddNodes(pp->l2link->call, /* ggf. Nodes hinzufuegen. */ + pp->l2link->port, + &mbp); + + bcast(&mbp, /* Broadcast-Bake senden. */ + pp->l2link->call, + pp->l2link->port); + + continue; /* Zum naechsten Segment. */ + } + } +} + +/************************************************************************/ +/* */ +/* Wenn der Timer abgelaufen, ggf. Broadcast-Bake senden. */ +/* Gilt nur fuer AX25IP-Port. */ +/* */ +/************************************************************************/ +void BroadCastBakeAXIP(void) +{ + PORTINFO *p; + UWORD port; + + /* Alle Port's durchgehen. */ + for (port = 0, p = portpar; port < L2PNUM; p++, port++) + { + if (!portenabled(port)) /* Port ist nicht aktiv. */ + continue; /* Zum naechsten Port. */ + +#ifdef AX25IP + if (kissmode(port) != KISS_AXIP) /* Port ist kein AX25IP-Port, */ + continue; /* zum naechsten Port. */ +#endif /* AX25IP */ + + if (++p->broadcast >= broint_ui) /* Timer abgelaufen. */ + { + bcastAXIP(); /* ggf. Broadcast-Bake senden. */ + + p->broadcast = 0; /* Timer zurueck setzen. */ + } /* Timer noch nicht abgelaufen. */ + } +} +#endif /* AX25IP */ + +/************************************************************************/ +/* */ +/* Broadcast-Nodes Bake senden. */ +/* */ +/************************************************************************/ +void BroadCastBake(void) +{ + PORTINFO *p; + PEER *pp; + UWORD port; + +#ifdef AX25IP + BroadCastBakeAXIP(); +#endif /* AX25IP */ + /* Durchsuche alle aktiven Port's. */ + for (port = 0, p = portpar; port < L2PNUM; p++, port++) + { + if (!portenabled(port)) /* Port ist nicht aktiv. */ + continue; /* Zum naechsten Port. */ + +#ifdef AX25IP + if (kissmode(port) == KISS_AXIP) /* AX25IP-Port hat hier nix zu suchen */ + continue; /* Zum naechsten Port. */ +#endif /* AX25IP */ + +#ifdef L1TCPIP + /* Pruefe, ob Port ein TCPIP-Interface ist. */ + if (CheckPortTCP(port)) + /* Zum naechsten Eintrag. */ + continue; +#endif + + if (++p->broadcast >= broint_ui) /* Timer ist abgelaufen. */ + { + MBHEAD *mbp = NUL; + + /* Suche auf den Port Segmente. */ + if ((pp = SearchSegmentTHENET(port)) != NULL) + { +#ifdef AUTOROUTING + if ( (p->poAuto != L_THENET) /* kein THENET-TYP gesetzt bzw. */ + &&(p->poAuto != L_INPFLEX)) /* kein Vollmodus gestezt. */ + { + AddNodes(pp->l2link->call, /* ggf. Nodes hin zufuegen. */ + port, + &mbp); + bcast(&mbp, /* Bake an to CALL senden. */ + pp->l2link->call, + port); + + p->broadcast = 0; /* Timer zuruecksetzen. */ + continue; /* Zum naechsten Port. */ + } + else /* THENET-TYP bzw. Vollmodus gesetzt. */ +#endif /* AUTOROUTING */ + { + AddNodes("NODES \140", /* ggf. Nodes hin zufuegen. */ + port, + &mbp); + bcast(&mbp, /* Bake an to NODES senden. */ + "NODES \140", + port); + + p->broadcast = 0; /* Timer zuruecksetzen. */ + continue; /* Zum naechsten Port. */ + } + } + else /* kein Segment gefunden. */ + { +#ifdef AUTOROUTING + if ( (p->poAuto == L_THENET) /* Nur wenn THENET-TYP gesetzt bzw. */ + ||(p->poAuto == L_INPFLEX)) /* Vollmodus gestezt. */ + { +#endif /* AUTOROUTING */ + AddNodes("NODES \140", /* ggf. Nodes hin zufuegen. */ + port, + &mbp); + bcast(&mbp, /* BAKE an to NODES senden. */ + "NODES \140", + port); + + p->broadcast = 0; /* Timer zurueck setzen. */ + continue; /* Zum naechsten Port. */ +#ifdef AUTOROUTING + } +#endif /* AUTOROUTING */ + } /* kein Segment gefunden. */ + } /* Timer noch nicht abgelaufen. */ + } /* for */ +} + + +/************************************************************************/ +/* */ +/* Suche Segment mit THENET-Typ. */ +/* */ +/* L4TIMEOUT */ +/************************************************************************/ +PEER *SearchTHENET(void) +{ + PEER *pp; + + if ((pp = ispeer()) != NULL) /* Aktueller Linkblock ist ein Segment. */ + { + if (pp->typ == THENET) /* Segment ist ein THENET-Typ. */ + return(pp); /* THENET gefunden. */ + } + /* Aktueller Linkblock ist KEIN */ + return(NULL); /* Segment oder THENET-Typ. */ +} + +/************************************************************************/ +/* */ +/* Wenn THENET-Typ, L4-Timeout setzen, ansonsten L2-Timeout. */ +/* */ +/* L4TIMEOUT */ +/************************************************************************/ +unsigned short SetL4Timeout(void) +{ + PEER *pp; + + if ((pp = SearchTHENET()) != NULL) /* Suche nach THENET-Typ. Wenn gefunden, */ + { + if (pp->constatus == FALSE) /* Der Link soll nicht getrennt werden. */ + return(ininat); /* L2-Timeout setzen. */ + else /* Link soll bei keiner Aktivitaet getrennt werden. */ + return(L4Timeout); /* L4-Timeout setzen. */ + } + + return(ininat); /* anonsten L2-Timeout setzen. */ +} + +/************************************************************************/ +/* */ +/* Qualitaet einer Route (nur THENET) speichern. . */ +/* */ +/* L4QUALI */ +/************************************************************************/ +void dump_routes(MBHEAD *mbp) +{ + PEER *pp; + int i; + int max_peers = netp->max_peers; + + putstr(";\r; Routes\r;\r", mbp); + + /* durchsuche alle Segmente. */ + for (i = 0, pp = netp->peertab; i < max_peers; i++, pp++) + { + if (pp->used) /* Nur benutzte Eintraege. */ + { + if (pp->typ == THENET) /* Nur vom Typ THENET. */ + { + putprintf(mbp,"R "); + putid(pp->l2link->call, mbp); /* Rufzeichen. */ + putprintf(mbp," QUAL=%d CONSTATUS=%d\r", + pp->quality, /* Qualitaet. */ + pp->constatus); /* Connect-Status. */ + } /* kein THENET. */ + } /* unbenutzer Eintrag. */ + } /* for */ +} + +#endif /* THENETMOD */ + + /* End of src/l3thenet.c */ diff --git a/src/l3var.c b/src/l3var.c new file mode 100755 index 0000000..7881bf3 --- /dev/null +++ b/src/l3var.c @@ -0,0 +1,65 @@ +/************************************************************************/ +/* */ +/* ***** ***** */ +/* ***** ***** */ +/* ***** ***** */ +/* ***** ***** */ +/* *************** *************** */ +/* ***************** ***************** */ +/* *************** *************** */ +/* ***** ***** TheNetNode */ +/* ***** ***** Portable */ +/* ***** ***** Network */ +/* ***** ***** Software */ +/* */ +/* File src/l3var.c (maintained by: ???) */ +/* */ +/* This file is part of "TheNetNode" - Software Package */ +/* */ +/* Copyright (C) 1998 - 2008 NORD>> 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 = " "; + 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 */ diff --git a/src/l4.c b/src/l4.c new file mode 100755 index 0000000..3dd8eb1 --- /dev/null +++ b/src/l4.c @@ -0,0 +1,1368 @@ +/************************************************************************/ +/* */ +/* ***** ***** */ +/* ***** ***** */ +/* ***** ***** */ +/* ***** ***** */ +/* *************** *************** */ +/* ***************** ***************** */ +/* *************** *************** */ +/* ***** ***** TheNetNode */ +/* ***** ***** Portable */ +/* ***** ***** Network */ +/* ***** ***** Software */ +/* */ +/* File src/l4.c (maintained by: ???) */ +/* */ +/* This file is part of "TheNetNode" - Software Package */ +/* */ +/* Copyright (C) 1998 - 2008 NORD>state = L4SDSCED; /* Eintrag ist leer */ + cirpoi->numrx = 0; /* keine Frames empfangen */ + cirpoi->numtx = 0; /* keine Frames zu senden */ + cirpoi->ll4txNR = 0; /* last l4 ack sent */ + cirpoi->fragme = NULL; /* kein Frame Fragment da */ + inithd(&cirpoi->mbhdrx); /* Empfangskette ist leer */ + inithd(&cirpoi->mbhdtx); /* Sendekette ist leer */ + inithd(&cirpoi->mbhdos); /* Kette "ausser Reihenfolge" */ + clrcir(); /* Rest initialisieren */ + relink((LEHEAD *)cirpoi, /* in die Liste fuer unbenutzte */ + (LEHEAD *)l4frel.tail); /* Controllbloecke */ + } + nmbcir = nmbcir_max = 0; /* Circuit-Zaehler */ +} + +/*----------------------------------------------------------------------*/ +#define START 0 +#define STOP 1 +#define CLEAR 2 +static void l4rtt(CIRBLK *cirp, int what) +{ + UWORD RTT, SRTT; + + switch (what) { + case START : cirp->RTT = 1; + cirp->RTTvs = cirp->l4vs; + break; + + case STOP : RTT = cirp->RTT; + SRTT = cirp->SRTT; + + if (RTT > SRTT) + SRTT = (L4_ALPHA1 * SRTT + RTT * 100) / (L4_ALPHA1 + 1); + else + SRTT = (L4_ALPHA2 * SRTT + RTT * 100) / (L4_ALPHA2 + 1); + if (SRTT < L4_IRTT / 10) + SRTT = L4_IRTT / 10; + if (SRTT > L4_IRTT * 10) + SRTT = L4_IRTT * 10; + + cirp->SRTT = SRTT; + + case CLEAR : cirp->RTT = + cirp->RTTvs = 0; + break; + } +} + +/************************************************************************/ +/* */ +/* RETRY TIMER (T1) */ +/* */ +/* Der T1 wird fuer jedes Frame in der Sendewarteschlange verwaltet und */ +/* bei jeder Aussendung dieses Frames gestartet. Wenn er ablaeuft, wird */ +/* das Frame erneut ausgesendet. L4_BETA1 muss so gewaehlt werden, dass */ +/* der T1 nicht zu frueh ablaeuft und damit das Frame doppelt geschickt */ +/* wird. */ +/* */ +/************************************************************************/ +static void l4setT1(CIRBLK *cirp, MBHEAD *fbp) { + if (fbp->l4trie > 1) + fbp->l4time = (cirp->SRTT/100 + 1) * 2 * L4_BETA1; + else + fbp->l4time = (cirp->SRTT/100 + 1) * L4_BETA1; + if (fbp->l4time < 30) /* nicht unter 30s */ + fbp->l4time = 30; +} + +/************************************************************************/ +/* */ +/* ACKNOWLEDGE TIMER (T2) */ +/* */ +/* Der T2 bestimmt die maximale Verzoegerung, bis ein empfangenes Frame */ +/* bestaetigt wird. L4_BETA sollte so gewaehlt werden, dass Frames */ +/* moeglichst schnell bestaetigt werden, aber nicht zuviele ACK-Frames */ +/* generiert werden. */ +/* */ +/************************************************************************/ +static void l4setT2(CIRBLK *cirp) { + UWORD frack; + + frack = (cirp->SRTT/100 + 1) * L4_BETA2; + + if (frack < 10) + frack = 10; + + if ( cirp->acktim > frack + && cirp->numrx < (cirp->window / 2)) + cirp->acktim = frack; +} + +/************************************************************************/ +/* */ +/* CONREQ/BUSY TIMEOUT (T3) */ +/* */ +/* Der T3 bestimmt die Wartezeit zwischen der Wiederholung von CONACK/ */ +/* DISREQ und der Linkkontrolle bei Busy. */ +/* Der T3 sollte nicht zu gering gewaehlt werden. */ +/* */ +/************************************************************************/ +static void l4setT3(CIRBLK *cirp, int what) { +#define L4TCREQ 0 +#define L4TDREQ 1 +#define L4TBUSY 2 + switch (what) { + case L4TCREQ : + case L4TDREQ : cirp->traout = (cirp->SRTT/100 + 1) * L4_BETA3; + if (cirp->traout < 30) + cirp->traout = 30; + break; + case L4TBUSY : cirp->traout = L4_BSYDEL; + break; + } +} + +/*----------------------------------------------------------------------*/ +static void l4clrT3(CIRBLK *cirp) { + cirp->traout = 0; +} + +/*----------------------------------------------------------------------*/ +static void l4newstate(UWORD state) +{ + if (state) { /* Verbindung steht */ + if (cirpoi->state == L4SDSCED) { /* ein neuer Connect */ + ulink((LEHEAD *)cirpoi); /* Circuit aus der Freiliste */ + relink((LEHEAD *)cirpoi, /* in die Liste fuer benutzte */ + (LEHEAD *)l4actl.tail); /* Controllbloecke */ + if (++nmbcir > nmbcir_max) /* Maximalanzahl der Circuits */ + nmbcir_max = nmbcir; + } + } else { /* Verbindungsabbruch */ + if (cirpoi->state != L4SDSCED) { /* Circuit wird inaktiv */ + ulink((LEHEAD *)cirpoi); /* Circuit aus der Aktivliste */ + relink((LEHEAD *)cirpoi, /* in die Liste fuer unbenutzte */ + (LEHEAD *)l4frel.tail); /* Controllbloecke */ + nmbcir--; /* einen aktiven Circuit weniger */ + } + } +#ifdef __WIN32__ + cirpoi->state = (char)state; /* neuen Status setzen */ +#else + cirpoi->state = state; /* neuen Status setzen */ +#endif /* WIN32 */ +} + +/*----------------------------------------------------------------------*/ +void l4tx(void) /* Frames senden */ +{ + UWORD unack; /* unbestaetigte Frames */ + UWORD isweg; /* schon gesendete Frames */ + MBHEAD *fbp; /* naechstes Frame */ + CIRBLK *nxtcir; /* Zeiger auf naechsten CIRBLK */ + + for (cirpoi = (CIRBLK *) l4actl.head; /* alle aktiven Circuits */ + cirpoi != (CIRBLK *) &l4actl.head; /* durchgehen */ + cirpoi = nxtcir) /* und zum naechsten Circuit */ + { + nxtcir = (CIRBLK *) cirpoi->head; /* wegen l4newstate()... */ + + if ((cirpoi->state == L4SIXFER) && /* Eintrag hat L4-Verbindung */ + (!(cirpoi->l4flag & L4FPBUSY))) { /* und Partner nicht choked */ + + unack = (cirpoi->l4vs - cirpoi->l4rxvs) & 0x7F; + if ((unack < cirpoi->numtx) /* nur wenn Fenstergroesse */ + && (unack < cirpoi->window)) { /* noch nicht erreicht */ + + fbp = (MBHEAD *) cirpoi->mbhdtx.head; /* Anfang der Sendeliste */ + for (isweg = 0; isweg < unack; ++isweg)/* schon gesendete offene*/ + fbp = (MBHEAD *) fbp->nextmh; /* Frames, die auf Be- */ + /* staetigung warten, */ + /* uebergehen */ + do { + fbp->l4trie = 0; /* noch kein Versuch */ + sndfrm(cirpoi->l4vs++, fbp); /* naechstes Frame senden */ + + fbp = (MBHEAD *) fbp->nextmh; /* naechstes Frame */ + } while ((++unack < cirpoi->numtx) /* bis keine Frames mehr */ + &&(unack < cirpoi->window)); /* o.Fenstergroesse ueber-*/ + /* schritten */ + if (!cirpoi->RTT) /* keine Messung unterwegs*/ + l4rtt(cirpoi, START); /* dann neue starten */ + } + } + } +} + +/*----------------------------------------------------------------------*/ +/* Diese Routine prueft, ob das aktuelle Frame ein Circuit von uns sein */ +/* koennte. Das ist ziemlich unsauber, eigentlich sollte nur im L4 */ +/* landen, was auch direkt an uns addressiert ist. Das Lokal-Konzept */ +/* von alten NET/ROMs zwingt uns aber, auch "fremde" Frames zu durch- */ +/* suchen. */ +BOOLEAN l4istome(char *srcid, char *dstid) +{ + if (l4opco != L4CONREQ) /* es ist kein Connect Request */ + { + if ( (l4hdr0 < NUMCIR) /* Index im richtigen Bereich? */ + /* die Verbindung haben wir */ + && (cirtab[l4hdr0].state != L4SDSCED) + /* und die ID stimmt */ + && (cirtab[l4hdr0].ideige == l4hdr1)) + { + cirpoi = &cirtab[l4hdr0]; /* CIRCUIT-Eintrag ist gueltig! */ + if (l4opco != L4CONACK) /* CONACK kann vom Host kommen */ + if (!cmpid(srcid, cirpoi->l3node)) + return(FALSE); /* Absender muss stimmen */ + if (!cmpid(dstid, myid)) /* nicht direkt an uns ? */ + if (!cmpid(dstid, cirpoi->destca)) + return(FALSE); /* Ziel muss stimmen */ + return(TRUE); + } + } + return(FALSE); +} + +/*----------------------------------------------------------------------*/ +void l4rx(NODE *srcnod, NODE *dstnod, MBHEAD *fbp) /* Frame empfangen */ +{ + char usrcall[L2IDLEN]; /* Call des Users */ + char orgnod[L2IDLEN]; /* Call des Absender Knotens */ + UWORD fenste; /* Fenstergroesse */ + int i; /* Scratch Zaehler */ + MBHEAD *antwor; /* Antwort auf das empfange Frame */ + CIRBLK *cirent; /* Eintrag des Users in der CIRTAB */ + CIRBLK nocir; /* Platzhalter wenn kein CIRCUIT */ + char *viapoi; /* Zeiger fuer VIA-Liste */ + char upno[L2IDLEN]; /* Uplink Knoten */ + char upnov[L2VLEN+1]; /* L2-via zu dem Uplink Knoten */ + +/* Hier gab es frueher oefters Abstuerze, da itol3() immer einen */ +/* gueltigen cirpoi erwartet, aber wir haben eventuell keinen, weil wir */ +/* die Verbindung nicht kennen. Dies betrifft spaete Versionen von TN */ +/* und einige fruehe Versionen von TNN. */ + + cirpoi = &nocir; + cpyid(cirpoi->l3node, srcnod->id); + + if (l4opco != L4CONREQ) /* es ist kein Connect Request */ + { + if ( (l4hdr0 < NUMCIR) /* Index im richtigen Bereich? */ + && (cirtab[l4hdr0].state != L4SDSCED) /* Verbindung haben wir */ + && (cirtab[l4hdr0].ideige == l4hdr1)) /* und die ID stimmt */ + { + cirpoi = &cirtab[l4hdr0]; /* CIRCUIT-Eintrag ist gueltig! */ + l4pidx = cirpoi->idxpar; /* Partner-Index uebernehmen */ + l4pcid = cirpoi->idpart; /* Partner-ID uebernehmen */ + } + else + { + if ( (l4opco != L4CONACK) /* alles ausser CONACK = Muell */ + && !(l4hdr4 & L4CCHOKE) + && !(l4opco & L4DISREQ)) + { + l4pidx = l4hdr2; /* Partner Circuit-Index */ + l4pcid = l4hdr3; /* und -ID fuer Antwort */ + l4ahd2 = + l4ahd3 = 0; + l4aopc = L4DISREQ; /* Disconnect Request als Antwort */ + itol3(gennhd()); /* Antwort &nocir->l3node=despoi */ + } + dealmb(fbp); /* schlechter Header, entsorgen */ + return; + } + } + + switch (l4opco) /* Ueber Opcode verzweigen */ + { + case L4CONREQ: /* Connect-Request oder ein */ + if (((fbp->mbpc - fbp->mbgc) >= 15) && /* Frame lang genug ? */ + ((fenste = getchr(fbp) & 0x7F) != 0) && /* und Fenster da */ + (getfid(usrcall, fbp) == TRUE) && /* gueltiges Usercall */ + (getfid(orgnod, fbp) == TRUE)) /* gueltiger Absender */ + { +/*****************************************************************************\ +* * +* Protokollerweiterung: Beim Connect-Request-Frame wird im Anschluss an die * +* Fenstergroesse der Uplinkknoten und die Via-Liste beim Uplink uebertragen * +* (nullterminiert), also maximal 64 Bytes zusaetzlich. Diese Erweiterung ist * +* kompatibel zur bisherigen Software, da laengere Frames nicht weiter unter- * +* sucht werden. Um auch hier spaetere Erweiterungen zu ermoeglichen, wird * +* der Rest des Frames nicht untersucht. Ist kein Uplinkknoten im Frame * +* enthalten, also bei aelterer Software, wird das Call des Absenderknotens * +* als Uplinkknoten eingesetzt. * +* * +\*****************************************************************************/ + if ( !(fbp->mbpc - fbp->mbgc >= L2IDLEN) /* neue Software? */ + || (!getfid(upno,fbp))) /* kein Uplinkknoten? */ + { + cpyid(upno,orgnod); /* Absenderknoten als Uplinkknoten annehmen */ + *upnov = '\0'; /* und dort keine Digikette */ + } + else /* neue Software */ + { + for (viapoi = upnov; /* Vialiste holen */ + viapoi < upnov + L2VLEN; /* max. 8 Calls */ + viapoi = viapoi + L2IDLEN) /* viapoi -> naechstes Call */ + { + if (!getfid(viapoi, fbp)) break; /* Ende Vialiste? */ + } + *viapoi = '\0'; /* Ende markieren */ + } + + l4pidx = l4hdr0; /* Index */ + l4pcid = l4hdr1; /* und ID des Parnters merken */ + cirent = NULL; + for (i = 0, cirpoi = cirtab; /* Circuit Tabelle absuchen */ + i < NUMCIR;++i, ++cirpoi) + { + if (cirpoi->state != L4SDSCED) { /* Verbingung besteht */ + if ( (cirpoi->idxpar == l4hdr0) /* PartnerIndex stimmt*/ + && (cirpoi->idpart == l4hdr1) /* Parner-ID stimmt */ + && cmpid(usrcall, cirpoi->upcall)/* UserCall stimmt */ + && cmpid(orgnod, cirpoi->downca))/* Absender stimmt */ + break; /* wir haben ihn gefunden ! */ + } + else /* sonst merken wir uns den freien */ + if (cirent == NULL) /* Platz in der Circuit Table */ + cirent = cirpoi; + } + if (i == NUMCIR) { /* Eintrag war nicht in der Liste */ + if ((cirent != NULL) && /* wenn wir noch ein Plaetzchen */ + (fvalca(usrcall) == YES)) /* haben und Call ok */ + { + cirpoi = cirent; /* dann Eintrag nehmen */ + cpyid(cirpoi->upcall, usrcall); /* Usercall setzen */ + cpyid(cirpoi->downca, orgnod); /* Absenderknoten */ + cpyid(cirpoi->upnod, upno); /* Uplink Knoten */ + cpyidl(cirpoi->upnodv, upnov); /* Uplink via's */ + + cirpoi->idxpar = l4hdr0; /* Partner-Index merken */ + cirpoi->idpart = l4hdr1; /* Parner-ID merken */ + + cirpoi->ideige = rand() % 256; /* eigene Zufalls-ID */ + cpyid(cirpoi->l3node, srcnod->id); + if (fbp->l3_typ == L3LOCAL) /* ein Lokal? */ + cpyid(cirpoi->destca, dstnod->id); + else + cpyid(cirpoi->destca, myid); + + cirpoi->tranoa = ininat; /* Timeout setzen */ + } + else + { /* kein Platz oder ungueltiges Call */ + l4ahd2 = /* Antwort aufbauen */ + l4ahd3 = 0; + l4aopc = L4CONACK | L4CCHOKE; /* Antwortframe aufbauen */ + antwor = gennhd(); + antwor->l2link = NULL; + cpyid(antwor->destcall, srcnod->id); + relink((LEHEAD *)antwor,(LEHEAD *) l3txl.tail); + break; /* und in die Sendekette haengen. */ + } + } /* den Eintrag gibt es schon */ + +#ifdef CONL3LOCAL + /* Unser Nachbar ist in der Liste und */ + /* schickt ein weiteres statusflag CONREQ.*/ + if (i != NUMCIR) + /* damit brechen wir hier ab. */ + break; +#endif + /* Vom Partner vorgeschlagene Fenstergroesse uebernehmen */ + /* wenn sie nicht groesser als unsere maximal-Groesse ist. */ + cirpoi->window = (fenste > trawir) ? trawir : fenste; + clrcir(); /* Eintrag initialisieren */ +#ifdef CONL3LOCAL + /* Statusflag CONACK NUR fuer das eigene Node Mycall */ + /* vorbereiten/verschicken. */ + if (fbp->l3_typ != L3LOCAL) + { +#endif + l4ahd2 = (UBYTE) (cirpoi - cirtab); /* Unseren Index setzen */ + l4ahd3 = cirpoi->ideige; /* Unsere (Zufalls-) ID */ + l4aopc = L4CONACK; /* Connect Acknowledge */ + putchr(cirpoi->window, (antwor = gennhd())); /* endgueltige */ + /* Fenstergroesse zurueck an den Partner */ + itol3(antwor); /* senden */ +#ifdef CONL3LOCAL + } +#endif + switch (cirpoi->state) { + case L2SDSCED : + case L2SLKSUP : +#ifdef CONL3LOCAL + if (fbp->l3_typ != L3LOCAL) + l4newstate(L4SIXFER); /* STATUS = connected */ + else + /* Es gibt noch keine Verbindung! */ + l4newstate(L4SLKSUP); /* STATUS = link setup */ +#else + l4newstate(L4SIXFER); /* STATUS = connected */ +#endif + l2tol7(L4MCONNT, cirpoi, L4_USER); + } + } + break; + + case L4CONACK: + if (cirpoi->state == L4SLKSUP) { /* nur wenn Connect von uns */ + if (!(l4hdr4 & L4CCHOKE)) { /* verlangt war und Partner */ + if (fbp->mbgc < fbp->mbpc) { /* nicht choked. */ + cirpoi->window = getchr(fbp); /* Entgueltige Fenstergr. */ + cirpoi->idpart = l4hdr3; /* Partner ID */ + cirpoi->idxpar = l4hdr2; /* Partner Index */ + clrcir(); /* Eintrag initialisieren */ + cirpoi->tranoa = ininat; /* Timeout setzen */ + l4newstate(L4SIXFER); /* Status = connected */ + /**********************************************************/ + /* Protokollerweiterung nach DB7KG, 23.11.1996 */ + /* Bei jedem eingehenden Connect-ACK setzen wir den Ziel- */ + /* Node auf den Absender, von dem das Frame kam. Damit */ + /* soll bei einem Connect an einen Local der tatsaechliche*/ + /* L3 Partner als Ziel gewaehlt werden, damit es keine */ + /* Probleme beim umrouten dieser Verbindungen gibt. */ + /* (Ein umrouten ist dann nur bis zum Partner moeglich, */ + /* da kuenftig Frames mit dieser Addresse gesendet werden)*/ + /* HINWEIS: Impelementierung hier so nur moeglich, weil */ + /* l4rx() direkt aus dem L3 aufgerufen wird! (fuer DF2AU) */ + /**********************************************************/ + cpyid(cirpoi->l3node, srcnod->id); + l2tol7(L4MCONNT, cirpoi, L4_USER); /* L7 melden */ + } + } + else /* Partner ist choked (busy) */ + l4nsta(L4MBUSYF); /* an L7 melden */ + } + break; + + case L4DISREQ: /* Disconnect Request */ + l4ahd2 = + l4ahd3 = 0; /* Antwort aufbauen */ + l4aopc = L4DISACK; /* Opcode: Disconnect Ackn. */ + itol3(gennhd()); /* Frame senden */ + clr4rx(1); /* restliche Infos senden */ + l4nsta(L4MDISCF); /* an L7 melden */ + break; + + case L4DISACK: /* Disconnect Acknowledge */ + if (cirpoi->state == L4SDSCRQ) /* Hatten wir Disc gesendet ?*/ + l4nsta(L4MDISCF); /* wenn ja dann dem L7 melden*/ + break; + + case L4INFTRA: /* Infoframe */ + if (cirpoi->state != L4SIXFER) /* nur wenn connected */ + break; + chksts(); /* Status Info auswerten */ + /* TEST DG9OBU */ + if (((fbp->l4seq = /* passt Frame ins Fenster */ + (l4hdr2 - cirpoi->l4vr) & 0x7f) < cirpoi->window) + && !(cirpoi->l4flag & L4FBUSY)) + { /* und Partner nicht busy */ + fbp->morflg = (l4hdr4 & L4CMORE) != 0; /* Fragmentiert ? */ + if (fbp->l4seq == 0) { /* passt Sequenz? */ + takfrm(fbp); /* Frame uebernehmen */ + /* Frames, die ausser der Reihe kamen ueberpruefen */ + for (i = 1, antwor = (MBHEAD *) cirpoi->mbhdos.head; + (MBHEAD *) &(cirpoi->mbhdos) != antwor; + antwor = (MBHEAD *) antwor->nextmh) + { + if ((antwor->l4seq -= i) == 0) { /* passt das Frame ? */ + fbp = (MBHEAD *) antwor->prevmh; /* ja, nehmen und */ + takfrm((MBHEAD *) ulink((LEHEAD *)antwor));/*naechstes*/ + antwor = fbp; /* Frame ueberpruefen */ + ++i; /* Offset eins weiter */ + } + } + cirpoi->l4rs = 0; /* Antwort: ACK (Bestaetigung) */ + + /* Dynamisches ACKDEL */ + + i = cirpoi->numrx - (cirpoi->window /2); + if (i < 1) i = 1; + cirpoi->acktim = i * L4_ACKDEL ; + } + else + { /* Sequenz passt nicht */ + for (antwor = (MBHEAD *) cirpoi->mbhdos.head;;) { + /* Wenn die Kette dort zuende ist, dann dort einhaengen */ + if ((MBHEAD *) &(cirpoi->mbhdos) == antwor) { + relink((LEHEAD *)fbp, (LEHEAD *)cirpoi->mbhdos.tail); + break; + } + /* Wenn das Frame schoneinmal gekommen ist -> weg damit */ + if (antwor->l4seq == fbp->l4seq) { + dealmb(fbp); + break; + } + /* sonst an der passenden Stelle einhaengen */ + if (antwor->l4seq > fbp->l4seq) { + relink((LEHEAD *)fbp, (LEHEAD *)antwor->prevmh); + break; + } + antwor = (MBHEAD *) antwor->nextmh; /* ein Frame weiter */ + } + + if (cirpoi->l4rs == 0) { /* Wenn ACK gesendet werden soll */ + cirpoi->l4rs = 1; /* dann nun einen N(ot)AK senden */ + cirpoi->acktim = L4_ACKDEL; /* ACK-Wartezeit setzen */ + } + } + return; /* Frame verarbeitet */ + } + else /* ungueltiges Frame oder wir haben */ + cirpoi->acktim = L4_ACKDEL; /* zuwenig Buffers (choked), dann */ + break; /* Antwort verzoegern. */ + + case L4INFACK: /* Info Acknowledge */ + if (cirpoi->state == L4SIXFER)/* nur wenn connected */ + chksts(); /* Statusinformation auswerten */ + +#ifdef NEW_L4 + break; + + case L4PIDCHG: /* PID-Change */ + cirpoi->pid = l4hdr3; /* neue PID uebernehmen */ +#endif + } + dealmb(fbp); /* hier landen wir bei ungueltigen */ + /* Opcodes oder wenn die Bearbeitung*/ + + /* fertig ist, auf jeden Fall Frame */ +} /* wegwerfen. */ + +/*------------------------------------------------------------------------*/ +void l4rest(void) /* sonstige L4-Funktionen */ +{ + UWORD rx_unack; + UBYTE w2; + CIRBLK *nxtcir; + + for (cirpoi = (CIRBLK *) l4actl.head; /* alle aktiven Circuits */ + cirpoi != (CIRBLK *) &l4actl.head; /* durchgehen */ + cirpoi = nxtcir) { + nxtcir = (CIRBLK *) cirpoi->head; /* vorher schon merken */ + if ((cirpoi->l4flag & L4FDIMM)) /* sofortiger Abwurf */ + { + l4nsta(L4MDISCF); /* Disconnect melden */ + } + else + if (cirpoi->state == L4SIXFER) {/* nur fuer connectete Eintraege */ + if ( (cirpoi->l4flag & L4FDSLE) /* Abwurf gefordert */ + && (cirpoi->numtx == 0)) /* und alle Infos gesendet */ + endcir(); /* Eintrag loeschen */ + else + { + clr4rx(0); /* sonst Info senden */ + + /* Fruehes Ack */ + rx_unack = ((cirpoi->l4vr | 0x100) - cirpoi->ll4txNR) & 0x7F; + w2 = cirpoi->window/2; + + if (!(cirpoi->l4flag & L4FBUSY)) { /* wir sind nicht busy */ + if (nmbfre < 30) { /* Aber zu wenig Platz */ + cirpoi->l4flag |= L4FBUSY; /* Dann sind wir nun Busy ! */ + cirpoi->l4rs = 0; /* Antwort sofort senden */ + sndack(); /* ACK senden */ + } + else { /* ich bin nicht busy */ + if ( cirpoi->acktim > 1 + && rx_unack >= w2 + && cirpoi->numrx < w2) /* und es ist noch Platz */ + sndack(); + } + } + else { /* im Moment sind wir Busy */ + if ( nmbfre > 62 /* wieder genug Platz ? */ + && cirpoi->numrx < w2) { /* Und nicht zuviel ? */ + cirpoi->l4flag &= ~L4FBUSY; /* Busy aufheben */ + sndack(); /* und ACK senden */ + } + } + } + } + } +} + +#ifdef L4TIMEOUTAUSGABE +/************************************************************************/ +/* */ +/* Vor dem Disconect eine Info-Meldung an den User senden. */ +/* */ +/************************************************************************/ +static void l4DiscInfo(void) +{ + MBHEAD *mbp; + + if ((mbp = (MBHEAD *) allocb(ALLOC_MBHEAD)) != NULL) /* Buffer besorgen. */ + { + putchr('\r', mbp); + putalt(alias, mbp); + putid(myid, mbp); + + putstr("> Timeout (", mbp); + putnum(ininat, mbp); /* Timeout in s ausgeben */ + putstr("s) run off.\r", mbp); + rwndmb(mbp); + + sndfrm(cirpoi->l4vs++, mbp); /* Info senden */ + dealmb(mbp); /* Buffer entsorgen. */ + } +} +#endif /* L4TIMEOUTAUSGABE */ + +/*----------------------------------------------------------------------*/ +void trasrv(void) /* Timerservice fuer den L4 */ +{ + UWORD actsts; /* Status des aktuellen Eintrages */ + UWORD fropen; /* Zahl der unbestaetigten Frames */ + UWORD tosend; /* Zahl der zu sendenden Frames */ + MBHEAD *fbp; /* aktuelles Frame */ + UWORD rx_unack; + CIRBLK *nxtcir; + char txvs; + + for (cirpoi = (CIRBLK *) l4actl.head; /* alle aktiven Circuits */ + cirpoi != (CIRBLK *) &l4actl.head; /* durchgehen */ + cirpoi = nxtcir) { + nxtcir = (CIRBLK *) cirpoi->head; /* vorher schon merken */ + if ((actsts = cirpoi->state) != L4SDSCED) { /* nur fuer aktive Verb.*/ + if (cirpoi->RTT) /* RTT-Messung */ + cirpoi->RTT++; + if (cirpoi->traout != 0) { /* Timeout noch nicht abgelaufen? */ + if (--cirpoi->traout == 0) {/* Timeout nun abgelaufen ? */ + if (actsts == L4SIXFER) { /* nur fuer connectete Eintraege */ + cirpoi->l4flag &= ~L4FPBUSY; /* nichts mehr senden */ + } else { + if (++cirpoi->l4try < L4_RETRY) /* nochmal Versuchen ? */ + { + if (actsts == L4SLKSUP) /* CON REQ kam nicht an, nochmal */ + sconrq(); + else + sdisrq(); /* DISC REQ kam nicht an, nochmal */ + } else + l4nsta(L4MFAILW); /* Fehler an L7 melden */ + } + } + } + else { /* Timeout ist abgelaufen */ + if ((actsts == L4SIXFER) /* connected und Frames unbestaetigt ? */ + && ((fropen = (cirpoi->l4vs - cirpoi->l4rxvs) & 0x7F) != 0)) { + /* Frames wiederholen */ + for (tosend = 0, fbp = (MBHEAD *) cirpoi->mbhdtx.head; + tosend < fropen; + ++tosend, fbp = (MBHEAD *) fbp->nextmh) { + if (--fbp->l4time == 0) { /* wenn Timeout um */ + if (++fbp->l4trie < L4_RETRY) {/* und noch Versuch frei */ + txvs = fbp->l4seq; /* Framenummer holen */ + if (cirpoi->RTTvs == txvs) /* bei Wiederholung RTT- */ + l4rtt(cirpoi, CLEAR); /* Messung verwerfen */ + sndfrm(txvs, fbp); /* Frames senden */ + } else { + l4nsta(L4MFAILW); /* sonst L7 failure melden */ + break; + } + } + } + } + } + + if (actsts == L4SIXFER) { /* connected ? */ + if ( (cirpoi->acktim != 0) /* ACK noch nicht gesendet */ + && (--cirpoi->acktim == 0)) /* aber Timer laeuft gerade aus */ + { + /* schnelle Flow-control */ + rx_unack = ((cirpoi->l4vr | 0x100) - cirpoi->ll4txNR) & 0x7F; + + if ( cirpoi->numrx > (cirpoi->window / 2) + && rx_unack >= cirpoi->window) + { + cirpoi->l4flag |= L4FBUSY; + cirpoi->l4rs = 0; + } + sndack(); /* dann ein ACK senden */ + } + + if ( (cirpoi->tranoa != 0) /* No-activity Timeout laeuft aus */ + && (--cirpoi->tranoa == 0)) +#ifndef L4TIMEOUTAUSGABE + endcir(); /* Verbindung trennen */ +#else + { + l4DiscInfo();/* Vor Trennung, Timeout-Meldung zum User senden.*/ + endcir(); /* Verbindung trennen */ + } +#endif /* L4TIMEOUTAUSGABE */ + } + } + } +} + +/*----------------------------------------------------------------------*/ +void newcir(void) /* neuen Circuit-Eintrag aufbauen */ +{ + clrcir(); /* Eintrag erstmal loeschen */ + cirpoi->ideige = rand() % 256; /* eigene ID zufaellig erzeugen */ + cirpoi->l4try = 0; /* noch keine Sende-Versuche gemacht*/ + sconrq(); /* Connect Request senden */ + l4newstate(L4SLKSUP); /* neuer Status: Verbindungsaufbau */ +} + +/*----------------------------------------------------------------------*/ +void discir(void) /* Circuit aufloesen */ +{ + if ((cirpoi->state == L4SLKSUP) ||/* Status Connect Request oder */ + (cirpoi->state == L4SDSCRQ)) /* Disconnect Request ? */ + { + /* Bis jetzt wurde ein L4 Disconnect nicht nach oben gemeldet, */ + /* wenn der State noch LINK SETUP oder DISCONNECT REQUEST war. */ + /* Ich nehme an, das war wegen der reentranz-Problematik so */ + /* geloest worden. Jetzt wird ein Flag gesetzt, das eigenliche */ + /* Melden passiert in L4rest. */ + cirpoi->l4flag |= L4FDIMM; /* spaeter in l4rest */ +#ifdef CONL3LOCAL + /* Statusflag CONACK + CHOKE Flag senden */ + /* wenn Verbindungsstatus Setup/Disc ist. */ + bsycir(); +#endif + } + else { + kilfra(); /* Fragmentliste loeschen */ + dealml((LEHEAD *)&cirpoi->mbhdrx); /* Empfangsliste loeschen */ + cirpoi->numrx = 0; /* Empfangszaehler zuruecksetzen */ + cirpoi->l4flag |= L4FDSLE; /* fuer Abwurf markieren */ + } +} + +/************************************************************************/ +/* */ +/* Info vom L7 an Circuit senden */ +/* */ +/************************************************************************/ +BOOLEAN +itocir(BOOLEAN cflg, MBHEAD *mbp) +{ + CIRBLK *cblk; + + cblk = (CIRBLK *)mbp->l2link; + if (cblk->l4flag & L4FDIMM) /* Circuit ist abgefuellt? */ + { + dealmb(mbp); /* Info abnehmen (gibt Platz) */ + return (TRUE); /* Info ist weg */ + } + if ( (cblk->numtx < conctl) /* noch Platz ? */ + || (cflg == TRUE)) /* oder immer senden */ + { +/* Infoframe in die TX-Liste des Circuit haengen */ + relink(ulink((LEHEAD *)mbp), (LEHEAD *)cblk->mbhdtx.tail); + ++cblk->numtx; /* Framezaehler erhoehen */ +/* Um ein Abfuellen des Knotens durch einzelne User auch im L4 zu */ +/* verhindern, wird wie im L2 die max. Zahl an Frames auf 150 begrenzt */ + if (cblk->numtx >= 150) + cblk->l4flag |= L4FDIMM; +/* Das morflg des Frames wird jetzt im L7 geloescht vor dem Aufruf von */ +/* itocir, falls das Frame nicht von einem L4-Partner kommt. */ + cblk->tranoa = ininat; /* Timeout neu aufziehen */ + return(TRUE); /* ok zurueckmelden */ + } + return(FALSE); /* kein Platz zurueckmelden */ +} + +/* Informationstransfer von Layer 4 nach Layer X */ +/* Solange noch empfangene Pakete vorhanden sind, werden diese an */ +/* andere Layer durch Aufruf von fmlink() uebertragen. Bei geseztem */ +/* Ueberfuellungskontroll-Flag (conctl == TRUE) wird die Uebertragung */ +/* abgebrochen, wenn der andere Layer keine weiteren Daten mehr auf- */ +/* aufnehmen kann. */ +/* Nach erfolgter Uebertragung wird die Anzahl der uebertragenen Zeichen*/ +/* fuer die Statistik gezaehlt und der No-Activity-Timer neu gesetzt. */ +static void clr4rx(BOOLEAN conctrl) +{ + MBHEAD *mbp; + + while (cirpoi->numrx != 0) {/* solange noch Frames vorhanden */ + mbp = (MBHEAD *) cirpoi->mbhdrx.head; /* ein Frame holen */ + mbp->l2link = (LNKBLK *) cirpoi; /*zugehoerigen Circuit merken*/ + mbp->type = 4; /* User ist Circuit */ +#ifdef NEW_L4 + mbp->l2fflg = cirpoi->pid; /* PID einstellen */ +#else + mbp->l2fflg = L2CPID; /* L4 immer PID F0 */ +#endif + if (!fmlink(conctrl, mbp)) break;/* Ende bei Fehler */ + --cirpoi->numrx; /* ein Frame weniger */ + cirpoi->tranoa = ininat; /* Timeout neu setzen */ + l4setT2(cirpoi); /* ACK_TIMER neu setzen */ + } +} + +/*----------------------------------------------------------------------*/ +static void chksts(void) /* Status des Frames auswerten */ +{ + UWORD frofs; /* bestaetigter Offset */ + UWORD fropen; /* unbesteatigter Offset */ + + if ((fropen = (cirpoi->l4vs - cirpoi->l4rxvs) & 0x7F) != 0) { + /* Frames offen ? */ + if ((frofs = (l4hdr3 - cirpoi->l4rxvs) & 0x7F) != 0) { + /* neu bestaetigte Frames ? */ + if (frofs <= fropen) { /* Frames wurden bestaetigt */ + while (frofs-- != 0) { /* solange bestaetigte Frames ueber */ + dealmb((MBHEAD *)ulink((LEHEAD *)cirpoi->mbhdtx.head)); /* weg*/ + cirpoi->numtx--; /* einen weniger zu senden */ + if (cirpoi->l4rxvs++ == /* einen mehr bestaetigt */ + cirpoi->RTTvs) /* Messframe bestaetigt? */ + l4rtt(cirpoi, STOP); /* Messung auswerten */ + } + } + } + } + + if (!(l4hdr4 & L4CCHOKE)) { /* Partner choked ? */ + cirpoi->l4flag &= ~L4FPBUSY; /* nein, merken */ + l4clrT3(cirpoi); /* Timeout kann nicht kommen */ + if ((l4hdr4 & L4CNAK) && /* NAK-Flag ? */ + (cirpoi->l4vs != cirpoi->l4rxvs)) { /* und noch was offen ? */ + /* dann wiederholen */ + if (cirpoi->RTTvs == cirpoi->l4rxvs) + l4rtt(cirpoi, CLEAR); /* bei Wiederholung RTT verwerfen */ + sndfrm(cirpoi->l4rxvs, (MBHEAD *)cirpoi->mbhdtx.head); + } + } + else { /* Partner ist choked (busy) */ + cirpoi->l4flag |= L4FPBUSY; /* merken */ + cirpoi->l4vs = cirpoi->l4rxvs; /* keine Frames offen */ + l4setT3(cirpoi, L4TBUSY); /* warten */ + } +} + +/*----------------------------------------------------------------------*/ +static void takfrm(MBHEAD *mbp) /* empfangenes Frame uebernehmen */ +{ + BOOLEAN more; /* morflg des zu verarbeitenden Frames */ + BOOLEAN copy = FALSE; /* umkopieren noetig wegen Fragmentierung */ + MBHEAD *fragmn; /* dieses Fragment wird bearbeitet */ + int max; /* maximale Info-Laenge fuer Weiterleitung */ + int sum = 0; /* Summe vorhandenes Fragment + neues Frame */ + + if (!(cirpoi->l4flag & L4FDSLE)) /* Circuit ist nicht zu beenden */ + { + more = mbp->morflg; + +/* Framegroesse fuer vorhandenes Fragment und neues Frame bestimmen. */ +/* Da fuer das Fragment in einen neuen Buffer geschrieben wurde, ist */ +/* (fragmn->mbgc == 0) und muss nicht von fragmn->mbpc subtrahiert */ +/* werden. */ + + if ((fragmn = cirpoi->fragme) != NULL) + { + sum += fragmn->mbpc; + } + sum += mbp->mbpc - mbp->mbgc; + +/* Im L7 nachfragen, welche maximale Paketlaenge verarbeitet werden */ +/* kann (CCP / Hostmode / L2 -> 256 Bytes; L4 -> 236 Bytes) */ + + max = ptc_p_max(cirpoi, L4_USER); + +/* muss umkopiert werden? */ + if ((sum > max) || (fragmn != NULL) || (more)) + copy = TRUE; + + while (copy) + { +/* ggf. neuen Buffer fuer Arbeits-Fragment holen */ + if (fragmn == NULL) + { + fragmn = (MBHEAD *) allocb(ALLOC_MBHEAD); + cirpoi->fragme = fragmn; + } +/* erstmal vermuten, dass nach diesem Fragment noch mehr folgt */ + fragmn->morflg = 1; +/* aus neuem Frame ans Fragment anhaengen, bis max erreicht ist, oder */ +/* neues Frame leer */ + while ((fragmn->mbpc < max) && (mbp->mbpc > mbp->mbgc)) + { + putchr(getchr(mbp), fragmn); + } +/* Fragment fertig - Rest berechnen */ + sum -= fragmn->mbpc; + if (!sum) + { +/* neues Frame ist leer und kann weg */ + dealmb(mbp); + mbp = NULL; + copy = FALSE; +/* wenn nichts mehr folgt, dies im Fragment vermerken */ + if (!more) + fragmn->morflg = 0; + } +/* Fragment weiterreichen, wenn max erreicht oder wenn nix mehr kommt */ + if ((fragmn->mbpc == max) || (fragmn->morflg == 0)) + { + rwndmb(fragmn); + relink((LEHEAD *)fragmn, (LEHEAD *) cirpoi->mbhdrx.tail); + fragmn = NULL; + cirpoi->fragme = NULL; + ++cirpoi->numrx; + } + } + + if (mbp != NULL) /* Frame noch da? */ + { + relink((LEHEAD *)mbp,(LEHEAD *) cirpoi->mbhdrx.tail); /* in L4-RX */ + ++cirpoi->numrx; /* ein Frame mehr empfangen */ + } + } + else /* Verbindung soll abgeworfen werden*/ + dealmb(mbp); /* Frame einfach vernichten */ + ++cirpoi->l4vr; /* RX-Sequenz erhoehen */ +} + +/*----------------------------------------------------------------------*/ +static void sndfrm(int txsequ, MBHEAD *mbp) /* Frame senden */ +{ + char huge *next; /* Pointer auf Ende des Headers */ + MBHEAD *netmhd; /* Netzwerk Header */ +#ifdef __WIN32__ + WORD mtu; /* MTU auf dem Sende-Port */ +#else + int mtu; /* MTU auf dem Sende-Port */ +#endif +#ifdef NEW_L4 + if ( (mbp->type == 2) /* nur L2-User */ + && (mbp->l2fflg != cirpoi->pid) /* andere PID als bisher ? */ + && (cmpcal(cirpoi->upnod, myid))) /* nur lokale Uplinks beachten */ + { + spidchg(mbp->l2fflg); /* neue PID mitteilen */ + cirpoi->pid = mbp->l2fflg; /* und selber merken */ + } +#endif + + l4ahd2 = /* Sendesequenzzaehler in den Header*/ + mbp->l4seq = txsequ; /* und im Buffer merken */ + l4aopc = L4INFTRA; /* Opcode: Info */ + if (mbp->morflg) + l4aopc |= L4CMORE; + ackhdr(); /* Rest des Headers erzeugen */ + next = (netmhd = gennhd()) ->mbbp;/* Buffer holen und Position Opcode */ + /* merken */ + mtu = 256; /* NETROM immer 256 Bytes Frames */ + +#ifdef __WIN32__ + if (splcpy(((short)(mtu - netmhd->mbpc)), netmhd, mbp)) /* Info umkopieren */ +#else + if (splcpy((mtu - netmhd->mbpc), netmhd, mbp)) /* Info umkopieren */ +#endif /* WIN32 */ + { /* hat nicht alles reingepasst */ + ++cirpoi->numtx; /* ein Frame mehr gesendet */ + mbp->morflg = TRUE; /* markieren, es kommt noch mehr */ + } + + if (mbp->morflg) + *(next -1) |= L4CMORE; /* more Flag im Opcode setzen */ + + itol3(netmhd); /* Frame an L3 geben */ + l4setT1(cirpoi, mbp); /* Timeout neu aufziehen */ +} + +/*----------------------------------------------------------------------*/ +static void l4nsta(WORD frtyp) /* Statusaenderung im L4 */ +{ + l4newstate(L4SDSCED); /* Status: Disconnected */ + clrcir(); /* Eintrag zuruecksetzen */ + dealml((LEHEAD *) &cirpoi->mbhdrx); /* Empfangsliste loeschen */ + dealml((LEHEAD *) &cirpoi->mbhdtx); /* Sendeliste loeschen */ + cirpoi->numrx = /* Zaehler zuruecksetzen */ + cirpoi->numtx = 0; + l2tol7(frtyp, cirpoi, L4_USER); +} + +/*----------------------------------------------------------------------*/ +static void endcir(void) /* Circuit aufloesen */ +{ + clrcir(); /* Eintrag in CIRTAB loeschen */ + cirpoi->l4try = 0; /* Versuche zuruecksetzen */ + sdisrq(); /* Abwurf einleiten */ + l4newstate(L4SDSCRQ); /* neuer Status: DISC-REQ gegeben */ +} + +/*----------------------------------------------------------------------*/ +static void clrcir(void) /* Eintrag in CIRTAB loeschen */ +{ + kilfra(); /* Fragmente loeschen */ + dealml((LEHEAD *)&cirpoi->mbhdos); /* Messageliste dafuer auch */ +#ifdef __WIN32__ + cirpoi->l4rxvs = 0; /* alle Sequenzen auf 0 */ + cirpoi->l4vs = 0; + cirpoi->l4vr = 0; + cirpoi->l4rs = 0; /* ACK-NAK Flag */ + cirpoi->l4try = 0; +#else + cirpoi->l4rxvs = /* alle Sequenzen auf 0 */ + cirpoi->l4vs = + cirpoi->l4vr = + cirpoi->l4rs = /* ACK-NAK Flag */ + cirpoi->l4try = +#endif /* WIN32 */ + cirpoi->ll4txNR = 0; + cirpoi->l4flag = 0; /* niemand choked, kein DISC-REQ */ + cirpoi->acktim = 0; + cirpoi->SRTT = L4_IRTT; /* SRTT initialisieren */ +#ifdef NEW_L4 + cirpoi->pid = L2CPID; /* standardmaessig PID F0 */ +#endif + l4clrT3(cirpoi); /* Timer loeschen */ + l4rtt(cirpoi, CLEAR); /* RTT-Messung stoppen und verwerfen */ + resptc(g_uid(cirpoi, L4_USER)); +} + +/*----------------------------------------------------------------------*/ +static void sconrq(void) /* CON-REQ senden */ +{ + MBHEAD *mbp; /* Buffer fuer Frame */ + char *viapoi; /* Zeiger in Vialiste */ + + l4pidx = cirpoi - &cirtab[0]; /* Index setzen */ + l4pcid = cirpoi->ideige; /* Partner und eigener Index */ + l4ahd2 = /* zwei Bytes leer */ + l4ahd3 = 0; + l4aopc = L4CONREQ; /* Opcode */ +#ifdef __WIN32__ + putchr ((char)trawir, (mbp = gennhd())); /* Rest des Headers */ +#else + putchr (trawir, (mbp = gennhd())); /* Rest des Headers */ +#endif /* WIN32 */ + putfid(cirpoi->upcall, mbp); /* beide Calls in das Frame */ + putfid(myid, mbp); + putfid(cirpoi->upnod, mbp); /* Uplinkknoten dazu */ + viapoi = cirpoi->upnodv; /* Uplink-Vialiste auch */ + while (*viapoi != '\0') /* Ende Vialiste erreicht? */ + { + putfid(viapoi, mbp); /* Call in Puffer */ + viapoi = viapoi + L2IDLEN; /* zum naechsten Call */ + } + putchr('\0', mbp); /* 0 markiert Ende Vialiste */ + itol3(mbp); /* an Layer 3 liefern */ + l4setT3(cirpoi, L4TCREQ); /* Timeout setzen */ +} + +/*----------------------------------------------------------------------*/ +static void sdisrq(void) /* DISQ-REQ senden */ +{ + l4pidx = cirpoi->idxpar; /* Index setzen */ + l4pcid = cirpoi->idpart; /* und ID */ + l4ahd2 = /* 2 Bytes leer */ + l4ahd3 = 0; + l4aopc = L4DISREQ; /* Opcode */ + itol3(gennhd()); /* Rest des Headers und dann an Layer 3 */ + l4setT3(cirpoi, L4TDREQ); /* Timeout setzen */ +} + +#ifdef NEW_L4 +/*----------------------------------------------------------------------*/ +static void spidchg(UBYTE pid) /* PID-CHG senden (ohne Timeout) */ +{ + l4pidx = cirpoi->idxpar; /* Index setzen */ + l4pcid = cirpoi->idpart; /* und ID */ + l4ahd2 = 0; /* erste Byte leer */ + l4ahd3 = pid; /* zweite Byte enthaelt die PID */ + l4aopc = L4PIDCHG; /* Opcode */ + itol3(gennhd()); /* Rest des Headers und dann an Layer 3 */ +} +#endif + +/*----------------------------------------------------------------------*/ +/* Fast L4 von DB7KG */ +/*----------------------------------------------------------------------*/ +static void sndack(void) /* ACK senden */ +{ + l4ahd2 = 0x00; + l4aopc = L4INFACK; /* Opcode */ + ackhdr(); /* Rest des Headers */ + itol3(gennhd()); /* schnelle Weiterleitung */ +} + +/*----------------------------------------------------------------------*/ +static void ackhdr(void) /* ACK Header erzeugen */ +{ + l4pidx = cirpoi->idxpar; /* Partner Index */ + l4pcid = cirpoi->idpart; /* Partner ID */ + l4ahd3 = cirpoi->l4vr; /* RX-Sequenz */ + + cirpoi->ll4txNR = cirpoi->l4vr & 0xFF; /* Letzten ACK senden */ + + if (cirpoi->l4flag & L4FBUSY) /* selbst choked */ + l4aopc |= L4CCHOKE; /* dann Flag setzen */ + else { + if (cirpoi->l4rs == 1) { /* wird es ein NAK Header? */ + l4aopc |= L4CNAK; /* dann Flag setzen */ + cirpoi->l4rs = 2; /* NAK als gesendet markieren */ + } + } + cirpoi->acktim = 0; /* ACK Timer ruecksetzen */ +} + +/*----------------------------------------------------------------------*/ +static void itol3(MBHEAD *mbp) /* Info an Layer 3 */ +{ + mbp->l2link = NULL; /* erstmal ggf. CRASHEN */ + cpyid(mbp->destcall, cirpoi->l3node); + relink((LEHEAD *)mbp, (LEHEAD *) l3txl.tail); /* nur umhaengen */ +} + +/*----------------------------------------------------------------------*/ +MBHEAD *gennhd(void) /* Netzwerk Header erzeugen */ +{ + int i; + MBHEAD *mbp; /* Buffer fuer Info */ + + mbp = (MBHEAD *) allocb(ALLOC_MBHEAD); /* Buffer besorgen */ + for (i = 0; i < 15; ++i) /* die ersten 15 Bytes fuer Header leer */ + putchr(0, mbp); + putchr(l4pidx, mbp); /* Transport Header schreiben */ + putchr(l4pcid, mbp); + putchr(l4ahd2, mbp); + putchr(l4ahd3, mbp); + putchr(l4aopc, mbp); + + return(mbp); /* Buffer wird zurueckgegeben */ +} + +/*----------------------------------------------------------------------*/ +static void kilfra(void) /* Fragmente loeschen */ +{ + if (cirpoi->fragme != NULL) { /* schon leer? */ + dealmb(cirpoi->fragme); /* Fragment loeschen */ + cirpoi->fragme = NULL; /* Eintrag loeschen */ + } +} + +/*-------------------------------------------------------------------------*/ +void l3tol4(NODE *totnod) /* Meldung L3 -> L4: Knoten, auf den despoi */ +{ /* zeigt, wird aus der Nodesliste gestrichen */ + CIRBLK *nxtcir; + + for (cirpoi = (CIRBLK *) l4actl.head;/* alle aktiven Circuits */ + cirpoi != (CIRBLK *)&l4actl.head;/* durchgehen, Eintraege suchen, */ + cirpoi = nxtcir) { /* die zum Zielknoten despoi gehen */ + nxtcir = (CIRBLK *) cirpoi->head; /* vorher schon merken */ + if (cmpid(cirpoi->l3node, totnod->id)) /* Zielknoten wurde geloescht */ + { + clr4rx(TRUE); /* empfangene Frames abliefern */ + l4nsta(L4MFAILW); /* Meldung an L7: Failure (Zielknoten ist weg) */ + } + } +} + +#ifdef CONL3LOCAL +/* wartenden L4 circuit bestaetigen, CONACK */ +void ackcir(CIRBLK *cp) +{ + MBHEAD *antwor; + + /* Partner Index */ + l4pidx = cp->idxpar; + /* Partner ID */ + l4pcid = cp->idpart; + /* Unseren Index setzen */ + l4ahd2 = (UBYTE) (cp - cirtab); + /* Unsere (Zufalls-) ID */ + l4ahd3 = cp->ideige; + /* Connect Acknowledge */ + l4aopc = L4CONACK; + /* endgueltige Fenstergroesse zurueck an den Partner senden */ + putchr(cp->window, (antwor = gennhd())); + antwor->l2link = NULL; + /* Call hinzufuegen. */ + cpyid(antwor->destcall, cp->l3node); + /* Nur umhaengen. */ + relink((LEHEAD *)antwor,(LEHEAD *) l3txl.tail); + /* Verbindungstatus auf information transfer setzen. */ + cp->state = L4SIXFER; +} + +/* fehlgeschlagener L4 circuit bestaetigen, CONACK + CHOKE */ +void bsycir(void) +{ + + MBHEAD *antwor; + + /* Partner Index */ + l4pidx = cirpoi->idxpar; + /* Partner ID */ + l4pcid = cirpoi->idpart; + /* Unseren Index setzen */ + l4ahd2 = (UBYTE) (cirpoi - cirtab); + /* Unsere (Zufalls-) ID */ + l4ahd3 = cirpoi->ideige; + /* Connect Acknowledge */ + l4aopc = L4CONACK | L4CCHOKE; + /* endgueltige Fenstergroesse zurueck an den Partner senden */ + putchr(cirpoi->window, (antwor = gennhd())); + antwor->l2link = NULL; + /* Call hinzufuegen. */ + cpyid(antwor->destcall, cirpoi->l3node); + /* Nur umhaengen. */ + relink((LEHEAD *)antwor,(LEHEAD *) l3txl.tail); +} +#endif + +#ifdef L4KILL +/******************************************************************************/ +/* */ +/* L4-User killen (ccpkill kann nur L2). */ +/* */ +/******************************************************************************/ +UWORD KillL4(char *call, char *msg) +{ + UWORD kill_zaehler = 0, + i; + BOOLEAN kill = 0; + + /* Circuit Tabelle absuchen */ + for (i = 0, cirpoi = cirtab; i < NUMCIR;++i, ++cirpoi) + { + if (cirpoi->state != L4SDSCED) /* Verbingung besteht */ + { + kill = (cmpid(call, cirpoi->upcall) || /* Rufzeichenvergleich. */ + cmpid(call, cirpoi->downca)); + + if (kill) /* Rufzeichen gefunden. */ + { + if (*msg) /* Mitteilung vom Sysop. */ + { + MBHEAD *mbp; + /* Buffer besorgen. */ + if ((mbp = (MBHEAD *) allocb(ALLOC_MBHEAD)) != NULL) + { + putchr('\r', mbp); + +#ifdef SPEECH + putprintf(mbp, speech_message(207), msg); +#else + putprintf(mbp, "\r*** Msg from Sysop: %s ***\r", msg); +#endif + rwndmb(mbp); /* Msg zurueckspulen. */ + + sndfrm(cirpoi->l4vs++, mbp); /* Msg senden */ + dealmb(mbp); /* Buffer entsorgen. */ + } + } + + kill_zaehler++; /* zaehlen */ + endcir(); /* Circuit aufloesen. */ + } + } + } + + return(kill_zaehler); +} +#endif /* L4KILL */ + +/* End of src/l4.c */ diff --git a/src/l7.c b/src/l7.c new file mode 100755 index 0000000..30f47c1 --- /dev/null +++ b/src/l7.c @@ -0,0 +1,835 @@ +/************************************************************************/ +/* */ +/* ***** ***** */ +/* ***** ***** */ +/* ***** ***** */ +/* ***** ***** */ +/* *************** *************** */ +/* ***************** ***************** */ +/* *************** *************** */ +/* ***** ***** TheNetNode */ +/* ***** ***** Portable */ +/* ***** ***** Network */ +/* ***** ***** Software */ +/* */ +/* File src/l7.c (maintained by: ???) */ +/* */ +/* This file is part of "TheNetNode" - Software Package */ +/* */ +/* Copyright (C) 1998 - 2008 NORD>l2fflg) */ +/* */ +/*----------------------------------------------------------------------*/ +BOOLEAN +itousr(UID to_uid, UID fm_uid, BOOLEAN conflg, MBHEAD *mbp) +{ + BOOLEAN ok = FALSE; + int bytes = mbp->mbpc - mbp->mbgc; + + if (g_utyp(fm_uid) != L4_USER) + mbp->morflg = 0; + mbp->l2link = g_ulink(to_uid); + switch (g_utyp(to_uid)) /* je nach Typ */ + { + case L4_USER: + ok = itocir(conflg, mbp); + break; + case L2_USER: + ok = itolnk(mbp->l2fflg, conflg, mbp); + break; + case HOST_USER: + ok = itohst(conflg, mbp); + break; +#ifdef L1TCPIP + case TCP_USER: + ok = itoTCP(conflg, mbp); + break; +#endif /* L1TCPIP */ + } + if (ok) + { + ptctab[to_uid].infotx += bytes; + if (fm_uid != NO_UID) + ptctab[fm_uid].inforx += bytes; + } + return(ok); +} + +/************************************************************************/ +/* */ +/* IP-Frames herrausfiltern, nur PID F0 (L2CPID) durchlassen. */ +/* */ +/************************************************************************/ +static BOOLEAN itoccp(MBHEAD *mbp) { + int uid; + PTCENT *ptcp; + + mbp->type = uid = g_uid(mbp->l2link, (unsigned char)mbp->type); + ptcp = ptctab + uid; + ptcp->inforx += (mbp->mbpc-mbp->mbgc); /* reine Info ohne Header */ + + switch (mbp->l2fflg) { +#ifdef IPROUTE + case L2CIP : + relink(ulink((LEHEAD *)mbp), (LEHEAD *)iprxfl.tail); + break; + + case L2CARP : + relink(ulink((LEHEAD *)mbp), (LEHEAD *)arprxfl.tail); + break; +#endif + + case L2CPID : + relink(ulink((LEHEAD *)mbp), (LEHEAD *)userhd.tail); + break; + + default : + dealmb((MBHEAD *)ulink((LEHEAD *)mbp)); + break; + } + + return(TRUE); +} + +/************************************************************************/ +/* */ +/* Informationstransfer in den L7. */ +/* */ +/* Wenn der Link einen Partner hat, die Daten direkt transferieren, */ +/* ansonsten die Daten in den CCP. */ +/* */ +/*----------------------------------------------------------------------*/ +BOOLEAN fmlink(BOOLEAN conflg, MBHEAD *mbp) +{ + PTCENT *ptcp; + UID p_uid; + UID uid; + + uid = g_uid(mbp->l2link, (unsigned char)mbp->type); + ptcp = ptctab + uid; + + p_uid = ptcp->p_uid; /* gibts einen Partner-Link? */ + if (ptcp->local == PTC_LOCAL) { /* Locals senden nie in CCP */ + if (p_uid != NO_UID) /* gibts einen Partner-Link? */ + return(itousr(p_uid, uid, conflg, mbp)); + /* Wenn der Link noch keinen Partner hat, haben wir l7tx() noch */ + /* nicht erreicht, um den Connect einzuleiten. Wir lehnen die Info */ + /* aus dem L2 solange ab, bis der Weiterconnect steht. */ + return(FALSE); /* Info abgelehnt */ + } else { + if (ptcp->ublk) /* noch im CCP? */ + return(itoccp(mbp)); /* Info in den CCP */ + if (p_uid != NO_UID) /* gibts einen Partner-Link? */ + return(itousr(p_uid, uid, conflg, mbp)); + return(itoccp(mbp)); /* den Rest auch in den CCP */ + } +} + +/************************************************************************/ +/* */ +/*----------------------------------------------------------------------*/ +static void kill_partner(UID this_uid) { + UID uid; + PTCENT *ptcp; + + for (uid = 0, ptcp = ptctab; uid < NUMPAT; uid++, ptcp++) + if (ptcp->p_uid == this_uid) { + disusr(uid); + ptcp->p_uid = NO_UID; + } +} + +/************************************************************************/ +/* */ +/* Statusmeldungen an L7. Es wird auf Connect, Disconnect, Busy, */ +/* Failure reagiert. */ +/* */ +/*----------------------------------------------------------------------*/ +void +l2tol7(WORD opcod, void *userlink, WORD typ) +{ + UID uid = g_uid(userlink, (unsigned char)typ); + UID p_uid; + PTCENT *ptcp; + PTCENT *p_ptcp; + MBHEAD *mbp; + LNKBLK *oldlp = lnkpoi; + CIRBLK *oldcp = cirpoi; + HOSTUS *oldhp = hstusr; + USRBLK *oldup = userpo; +#ifdef L1TCPIP + TCPIP *oldtc = tcppoi; +#endif /* L1TCPIP */ + +/* Wenn das Sysop-Port Flag gesetzt ist, duerfen wir keinen via-Connect */ +/* zulassen, weil eine Password-Pruefung nicht moeglich ist. */ + + if (typ == L2_USER && opcod == L2MCONNT) + { + if (lnkpoi->state == L2SHTH) + if (portpar[lnkpoi->liport].l2mode & MODE_s) + { + rejlnk(lnkpoi); + return; + } + } + + ptcp = ptctab + uid; /* Zeiger auf den Patchcord */ + p_uid = ptcp->p_uid; /* Partner-UID, wenn vorhanden */ + switch (opcod) /* je nach Opcode */ + { + case L2MCONNT: + case L7MCONNT: + if (p_uid != NO_UID) /* hat der Link einen Partner? */ + { + p_ptcp = ptctab + p_uid; /* Zeiger auf Partner-Patchcord */ + userpo = p_ptcp->ublk; /* Userblock des Partners im CCP */ + if (userpo) + { + if (p_ptcp->local == PTC_NORMAL) + msgfrm(opcod == L2MCONNT + ? DOWNLINK + : CQ_LINK, uid, conmsg); +#ifdef CONL3LOCAL + if (g_utyp(p_uid) == L4_USER) /* Partner kommt via L4? */ + ackcir(g_ulink(p_uid)); /* ja? mit CACK bestaetigen */ +#endif + if (g_utyp(p_uid) == L2_USER) /* Partner kommt via L2? */ + acklnk(g_ulink(p_uid)); /* falls HTH, bestaetigen */ + clrccp(); /* User aus dem CCP werfen */ + ptcp->state = DOWNLINK; /* ist ein Downlink */ + p_ptcp->ublk = NULL; + } + else + { + kill_partner(uid); /* eventuelle Partner loeschen */ + disusr(uid); + lnkpoi = oldlp; + cirpoi = oldcp; + hstusr = oldhp; + userpo = oldup; +#ifdef L1TCPIP + tcppoi = oldtc; +#endif /* L1TCPIP */ + return; + } + } + else + { + kill_partner(uid); /* eventuelle Partner loeschen */ + if ((userpo = ptcp->ublk) != NULL) /* Connect vom CCP */ + { + if (userpo->status == US_CHST) + { + userpo->status = US_CCP; + send_proto("L7", "Entering convers"); + mbp = getmbp(); + putstr("convers\r", mbp); /* Partner in den Convers */ + seteom(mbp); + mbp = getmbp(); + putprintf(mbp, "/\377\200HOST %s %s %s\r", myhostname, myrev, myfeatures); + seteom(mbp); + } + /* war nur ein Linkreset */ + } + else + { /* neuer User */ + if (!new_user(FALSE, uid)) /* User abgelehnt? */ + { + disusr(uid); + lnkpoi = oldlp; + cirpoi = oldcp; + hstusr = oldhp; + userpo = oldup; +#ifdef L1TCPIP + tcppoi = oldtc; +#endif /* L1TCPIP */ + return; + } + ptcp->state = UPLINK; /* ein User ist Uplink */ + ptcp->ublk = userpo; /* Partnerblock eintragen */ +#ifdef USER_PASSWORD + if (typ != L2_USER) + userpo->pwdtyp = PW_USER; + else + if (!(portpar[lnkpoi->liport].l2mode & MODE_s)) + userpo->pwdtyp = PW_USER; +#endif +#ifdef USERPROFIL + if (SearchPasswdProfil()) +#endif /* USERPROFIL */ + send_ctext(); /* CTEXT senden */ + } + } + break; + case L2MDISCF : + case L2MBUSYF : + case L2MFAILW : + if (p_uid != NO_UID) /* User hatte einen Partner */ + { + p_ptcp = ptctab + p_uid; + if ((userpo = p_ptcp->ublk) == NULL) /* Partner nicht im CCP? */ + { + if (p_ptcp->recflg) /* moechte aber zurueck */ + { + if (new_user(TRUE, p_uid)) /* dann erneut in CCP */ + { + msgfrm(DOWNLINK, NO_UID, recmsg);/* Reconnected to ... */ + p_ptcp->ublk = userpo; + } + else + disusr(p_uid); + } + else + disusr(p_uid); /* sonst Partner abwerfen */ + } + else + { /* Partner ist noch im CCP */ + if (p_ptcp->local == PTC_LOCAL) /* Local? */ + { + if (g_utyp(p_uid) == L2_USER && opcod == L2MBUSYF) + rejlnk(g_ulink(p_uid)); /* Busy durchreichen */ + disusr(p_uid); + } + else + { + if (opcod != L2MDISCF) + msgfrm(DOWNLINK, uid, (opcod == L2MBUSYF) ? dmmsg : failmsg); + p_ptcp->local = PTC_NORMAL; + userpo->status = US_CCP; + } + } + p_ptcp->p_uid = NO_UID; + } + if ((userpo = ptcp->ublk) != NULL) + clrccp(); + clrptc(uid); + kill_partner(uid); /* eventuelle Partner loeschen */ + } + lnkpoi = oldlp; + cirpoi = oldcp; + hstusr = oldhp; + userpo = oldup; +#ifdef L1TCPIP + tcppoi = oldtc; +#endif /* L1TCPIP */ +} + +/************************************************************************/ +/* */ +/* Usereintrag aus der CCP-Userliste loeschen. */ +/* Vorher die von diesem User verwendeten Resourcen freigeben. */ +/* */ +/*----------------------------------------------------------------------*/ +static void +clrccp(void) +{ + MBHEAD *mbp; + char file[128]; + CQBUF *cqp; + + if (userpo->sysflg > 1) + save_stat(); + + if (userpo->monitor) + { + moncmd(NULL, userpo->monitor, "N", 1); /* Monitor abschalten */ + dealoc((MBHEAD *)userpo->monitor); + userpo->monitor = NULL; + } + + for (cqp = (CQBUF *)cq_user.head; /* CQ-Liste durchsuchen */ + cqp != (CQBUF *)&cq_user; + cqp = cqp->next) + { + if (userpo->uid == cqp->uid) /* Eintrag gefunden */ + dealoc((MBHEAD *)ulink((LEHEAD *)cqp)); /* CQ-Eintrag loeschen */ + break; + } + + if ( userpo->status == US_WBIN /* Upload beenden */ + || userpo->status == US_RBIN + || userpo->status == US_RTXT + ) + { + fclose(loadfp); +#ifndef MC68302 + xremove(loadtmp); +#else + xremove(loadname); +#endif + loadname[0] = loadtmp[0] = NUL; + } + + if (userpo->fp != NULL) /* Read beenden */ + { + fclose(userpo->fp); + userpo->fp = NULL; + if (userpo->fname != NULL) + { + xremove(userpo->fname); + free(userpo->fname); + userpo->fname = NULL; + } + } + + if (userpo->convers != NULLCONNECTION) /* Convers beenden */ + { + userpo->convers->up = NULL; + send_proto("L7", "link failure with %s", userpo->convers->name); + if (userpo->convers->type == CT_HOST) + { +#ifdef SPEECH + sprintf(file, speech_message(139), myhostname, userpo->convers->name); +#else + sprintf(file, "%s<>%s broken", myhostname, userpo->convers->name); +#endif + bye_command2(userpo->convers, file); + } + else + bye_command2(userpo->convers, "link failure"); + } + userpo->convers = NULLCONNECTION; + userpo->convflag = 0; + + userpo->status = US_NULL; + + if ((mbp = userpo->mbhd) != NULL) + dealmb(mbp); + +#ifdef PACSAT + if (userpo->pacsat != NULL) + { + if (userpo->pacsat->tempfp != NULL) + { + fclose(userpo->pacsat->tempfp); + xremove(userpo->pacsat->tempfile); + free(userpo->pacsat->tempfile); + } + dealoc((MBHEAD *)userpo->pacsat); + userpo->pacsat = NULL; + } +#endif + + dealoc((MBHEAD *)ulink((LEHEAD *)userpo)); + userpo = NULL; +} + +/************************************************************************/ +/*---- ----*/ +/*----------------------------------------------------------------------*/ +void disusr(UID uid) +{ + LNKBLK *cblk2; + CIRBLK *cblk4; + HOSTUS *cblk0; +#ifdef L1TCPIP + TCPIP *cblk8; +#endif /* L1TCPIP */ + + switch (g_utyp(uid)) { + case L4_USER: + cblk4 = cirpoi; + cirpoi = (CIRBLK *) g_ulink(uid); + discir(); + cirpoi = cblk4; + break; + case L2_USER: + cblk2 = lnkpoi; + lnkpoi = (LNKBLK *) g_ulink(uid); + dsclnk(); + lnkpoi = cblk2; + break; + case HOST_USER: + cblk0 = hstusr; + hstusr = (HOSTUS *) g_ulink(uid); + hstout(); + hstusr = cblk0; + break; +#ifdef L1TCPIP + case TCP_USER: + cblk8 = tcppoi; + tcppoi = (TCPIP *) g_ulink(uid); + SetDiscTCP(); + tcppoi = cblk8; + break; +#endif /* L1TCPIP */ + } +} + +/************************************************************************/ +/*---- ----*/ +/* Neuen Message-Buffer besorgen und Inhalte umkopieren. Dabei je */ +/* nach Paclen-Parameter entsprechend viele Packete der vorgegebenen */ +/* Laenge erzeugen und mit send_msg() an L2, L4 oder Host weitergeben. */ +/*----------------------------------------------------------------------*/ +void seteom(MBHEAD *mbp1) +{ + MBHEAD *mbp2; +#ifdef PORT_MANUELL + LNKBLK *link; + UWORD PacLen; + UID uid; +#endif /* PORT_MANUELL */ + + rwndmb(mbp1); + + if (mbp1->mbpc == mbp1->mbgc) { /* Info im Frame? */ + dealmb(mbp1); /* Nein, dann weg damit */ + return; + } + + mbp2 = (MBHEAD *) allocb(ALLOC_MBHEAD); + mbp2->l2link = mbp1->l2link; + mbp2->type = mbp1->type; + +#ifdef PORT_MANUELL + uid = g_uid(mbp1->l2link, (unsigned char)mbp1->type); + + switch (g_utyp(uid)) + { + case L2_USER: + link = g_ulink(uid); + PacLen = portpar[link->liport].paclen; + break; + +#ifdef L1TCPIP + case TCP_USER: + link = g_ulink(uid); + PacLen = TXLEN; + break; +#endif /* L1TCPIP */ + + default: + PacLen = 236; + break; + } +#endif /* PORT_MANUELL */ + while (mbp1->mbpc > mbp1->mbgc) { + putchr(getchr(mbp1), mbp2); + +#ifdef PORT_MANUELL + if (mbp2->mbpc == PacLen) { +#else + if (mbp2->mbpc == paclen) { +#endif /* PORT_MANUELL */ + send_msg(TRUE, mbp2); + mbp2 = (MBHEAD *) allocb(ALLOC_MBHEAD); + mbp2->l2link = mbp1->l2link; + mbp2->type = mbp1->type; + } + } + + if (mbp2->mbpc > mbp2->mbgc) + send_msg(TRUE, mbp2); + else + dealmb(mbp2); + dealmb(mbp1); +} + +/*------------------------------------------------------------------------*/ + +BOOLEAN send_msg(BOOLEAN conflg, MBHEAD *mbp) +{ + static LHEAD mbhd; + + rwndmb(mbp); + inithd(&mbhd); + relink((LEHEAD *)mbp, (LEHEAD *)mbhd.tail); + mbp->l2fflg = L2CPID; + + return(itousr(g_uid(mbp->l2link, (unsigned char)mbp->type), NO_UID, conflg, mbp)); +} + +/************************************************************************/ +/*--- neuen User in Liste aufnehmen ---*/ +/* */ +/* Parameter im Aufruf: */ +/* check = TRUE: nicht aufnehmen, wenn Nachbar oder L2-Link */ +/* uid: User-ID des Users */ +/* */ +/* Rueckgabe: FALSE, wenn User abgelehnt. */ +/*----------------------------------------------------------------------*/ +BOOLEAN new_user(BOOLEAN check, UID uid) +{ + PERMLINK *p; + WORD i; + char call[L2IDLEN]; + MBHEAD *mbp; + FILE *fp; + char name[MAXPATH]; + + userpo = NULL; + if (check) { + cpyid(call,calofs(UPLINK, uid)); + for (i = 0; i < MAXCVSHOST; i++) { + p = permarray[i]; + if (p && cmpid(call,p->call)) + return(FALSE); + } + } + +/*--- fuer alle uebrigen User: */ + userpo = (USRBLK *) allocb(ALLOC_USRBLK2); /* Kontrollblock holen */ + userpo->mbhd = NULL; /* keine Info wartend */ +#ifdef PACSAT + userpo->pacsat = NULL; /* User noch nicht in der Box */ +#endif + userpo->monitor = NULL; /* User will keinen Monitor */ + userpo->auditlevel = 0; + userpo->sysflg = 0; /* erstmal nicht Sysop */ +#ifdef USER_PASSWORD + userpo->pwdtyp = PW_NOPW; /* noch kein Password */ +#endif + if (g_utyp(uid) == HOST_USER) + { + if ( !ishmod /* Terminalmodus -> Sysop */ + || (HOSTUS *)g_ulink(uid) == hstubl) /* Hostkanal 0 auch (TNBs) */ + userpo->sysflg = 1; + } + userpo->uid = uid; + userpo->errcnt = 0; + + userpo->status = US_CCP; /* am CCP, Befehl kommt */ + userpo->convers = NULLCONNECTION; + userpo->convflag = 0; /* noch nicht in CONVERS */ + userpo->talkcall[0] = '\0'; + userpo->fp = NULL; + userpo->fname = NULL; /* kein Dateiname gespeichert */ +#ifdef MAKRO_FILE + userpo->read_ok = FALSE; +#endif +#ifdef L1IRC + userpo->IrcMode = FALSE; +#endif /* L1IRC */ + +#ifdef PORT_SUSPEND + if (check == FALSE) + { + if (port_suspend_enabled(rxfprt)) { /* Wurde Flag l gesetzt ?(Port gesperrt) */ + if (is_port_suspended(userpo)) { /* Ja, dann checken wir ob dieser L2 */ + strcpy(name, textpath); /* auch ein eingetragener LINK ist!!! */ + strcat(name, "LOCK.TXT"); /* Hat der Sysop eine LOCK.TXT erstelt. */ + mbp = getmbp(); + if ((fp = xfopen(name, "rt")) != NULL) { /* Wenn ja, oeffnen wir diese und geben den*/ + while ((i = getc(fp)) != EOF) /* Inhalt dem L2. Anschliessend disconnect. */ + putchr((BYTE)(i == '\n' ? '\r' : i), mbp); + + fclose(fp); + putchr('\r', mbp); + } else + putstr("INTERLINK.\r", mbp); /* Bevor der L2 Disconnectet wird, bekommt */ + seteom(mbp); /* er noch eine Meldung, WARUM. */ + dealoc((MBHEAD *)userpo); + return(FALSE); /* ablehnen */ + } + } + } +#endif + if (is_suspended(userpo)) { + strcpy(name, textpath); + strcat(name, "SUSPEND.TXT"); + mbp = getmbp(); + if ((fp = xfopen(name, "rt")) != NULL) { + while ((i = getc(fp)) != EOF) + putchr((char)(i == '\n' ? '\r' : i), mbp); + + fclose(fp); + putchr('\r', mbp); + } else +#ifdef SPEECH + putstr(speech_message(140), mbp); +#else + putstr("You are suspended.\r", mbp); +#endif + seteom(mbp); + dealoc((MBHEAD *)userpo); + return(FALSE); /* ablehnen */ + } + /* neuen User in Kette haengen */ + relink((LEHEAD *)userpo, (LEHEAD *) usccpl.tail); + + return(TRUE); +} + +/************************************************************************\ +* * +* "get user id" * +* * +* Die User-ID-Nummer fuer einen Link-Pointer und einen Link-Typ (Level 2,* +* Level 4, Host) feststellen. Die UID setzt sich wie folgt zusammen: * +* * +* 0 .. LINKNMBR-1 Level 2 Links * +* LINKNMBR .. LINKNMBR+NUMCIR-1 Level 4 Circuits * +* LINKNMBR+NUMCIR .. LINKNMBR+NUMCIR+MAXHST-1 Host User * +* * +\************************************************************************/ +UID g_uid(void *userlink, UBYTE typ) { + + switch (typ) { + case L2_USER: /* Level 2 User */ + return((UWORD)(((LNKBLK *)userlink) - lnktbl)); + case L4_USER: /* Level 4 User */ + return(((UWORD)(((CIRBLK *)userlink) - cirtab)) + LINKNMBR); +#ifndef L1TCPIP + case HOST_USER: /* Host User */ + return(((UWORD)(((HOSTUS *)userlink) - hstubl)) + LINKNMBR + NUMCIR); +#else + case HOST_USER: /* Host User */ + return(((UWORD)(((HOSTUS *)userlink) - hstubl)) + LINKNMBR + NUMCIR + MAXTCPIP); + case TCP_USER: /* TCPIP User/Link */ + return(((UWORD)(((TCPIP *)userlink) - tcptbl)) + LINKNMBR + NUMCIR); +#endif /* L1TCPIP */ + } + return(NO_UID); +} + +/************************************************************************\ +* * +* "get user typ" * +* * +* Den User-Typ eines User anhand seiner UID feststellen. * +* * +* 0 .. LINKNMBR-1 Level 2 Links * +* LINKNMBR .. LINKNMBR+NUMCIR-1 Level 4 Circuits * +* LINKNMBR+NUMCIR .. LINKNMBR+NUMCIR+MAXHST-1 Host User * +* * +\************************************************************************/ +UBYTE g_utyp(UID uid) { +#ifndef L1TCPIP + if (uid >= LINKNMBR+NUMCIR) + return(HOST_USER); +#else + if (uid >= LINKNMBR+NUMCIR+MAXTCPIP) + return(HOST_USER); + + if (uid >= LINKNMBR+NUMCIR) + return(TCP_USER); +#endif /* L1TCPIP */ + if (uid >= LINKNMBR) + return(L4_USER); + return(L2_USER); +} + +/************************************************************************\ +* * +* "get user link" * +* * +* Den User-Link eines User anhand seiner UID feststellen. * +* * +* 0 .. LINKNMBR-1 Level 2 Links * +* LINKNMBR .. LINKNMBR+NUMCIR-1 Level 4 Circuits * +* LINKNMBR+NUMCIR .. LINKNMBR+NUMCIR+MAXHST-1 Host User * +* * +\************************************************************************/ +void *g_ulink(UID uid) { + switch (g_utyp(uid)) { + case L2_USER : return(lnktbl + uid); + case L4_USER : return(cirtab + uid - LINKNMBR); +#ifndef L1TCPIP + } + return(hstubl + uid - (LINKNMBR + NUMCIR)); +#else + case TCP_USER : return(tcptbl + uid - (LINKNMBR + NUMCIR)); + } + return(hstubl + uid - (LINKNMBR + NUMCIR + MAXTCPIP)); +#endif /* L1TCPIP */ +} + +/************************************************************************\ +* * +* "reset patchcord entry" * +* * +\************************************************************************/ +void resptc(UID uid) { + PTCENT *ptcp = ptctab + uid; + + ptcp->inforx = ptcp->lastrx = + ptcp->infotx = ptcp->lasttx = + ptcp->rxbps = ptcp->txbps = 0L; + ptcp->contime = 1L; /* Ueberlauf verhindern */ +} + +/************************************************************************\ +* * +* "clear patchcord entry" * +* * +\************************************************************************/ +void clrptc(UID uid) { + PTCENT *ptcp = ptctab+uid; + + resptc(uid); + ptcp->p_uid = NO_UID; + ptcp->ublk = NULL; + ptcp->state = EMPTY; + ptcp->local = PTC_NORMAL; /* 18.10.97 (1) hier zuruecksetzen */ + ptcp->recflg = FALSE; +} + +/* End of src/l7.c */ diff --git a/src/l7ccp.c b/src/l7ccp.c new file mode 100644 index 0000000..cd4df99 --- /dev/null +++ b/src/l7ccp.c @@ -0,0 +1,3300 @@ +/************************************************************************/ +/* */ +/* ***** ***** */ +/* ***** ***** */ +/* ***** ***** */ +/* ***** ***** */ +/* *************** *************** */ +/* ***************** ***************** */ +/* *************** *************** */ +/* ***** ***** TheNetNode */ +/* ***** ***** Portable */ +/* ***** ***** Network */ +/* ***** ***** Software */ +/* */ +/* File src/l7ccp.c (maintained by: ???) */ +/* */ +/* This file is part of "TheNetNode" - Software Package */ +/* */ +/* Copyright (C) 1998 - 2008 NORD>mbpc - mbp->mbgc) >= 4) + return(get32(mbp) != 0x234f4b23L); /* BC ist zu bloede fuer '#OK#' */ + return(FALSE); +} + +static void ccpcmd(void) +{ + TRILLIAN result; +#ifdef ALIASCMD + CMDALIAS *ap; + char cmdtmp[256], *clipoi2; + int i; +#endif + + cpyid(usrcal, calofs(UPLINK, userpo->uid)); +#ifdef CONNECTMOD_SET_NODE + switch(g_utyp(userpo->uid)) /* Den User-Typ eines User anhand */ + { /* seiner UID feststellen. */ + LNKBLK *l2_link; /* Zeiger auf L2-Ebene. */ + CIRBLK *l4_link; /* Zeiger auf L4-Ebene. */ + + case L2_USER : + /* Den User-Link eines User anhand */ + l2_link = g_ulink(userpo->uid); /* seiner UID feststellen. */ + SetMyNode(l2_link->viaidl); /* Den Einstiegsknoten liefern, */ + break; + + case L4_USER: + /* Den User-Link eines User anhand */ + l4_link = g_ulink(userpo->uid); /* seiner UID feststellen. */ + cpyid(updigi,l4_link->upnod); /* Den Einstiegsknoten liefern, */ + /* dafuer nehmen wir den Uplink Knoten. */ + break; + + /* damit der Compiler auch bei Optimierungen zufrieden ist ... */ + default: + updigi[0] = '\0'; + break; + } +#endif /* CONNECTMOD_SET_NODE */ + + if (ismemr()) { /* keine Arbeit ohne Speicher */ + if ( userpo->sysflg /* Sysop oder kein Sysop-Port? */ + || g_utyp(userpo->uid) != L2_USER + || !sysoponly(((LNKBLK*)g_ulink(userpo->uid))->liport) +#ifdef USER_PASSWORD + || userpo->pwdtyp != PW_NOPW +#endif + ) + { +#ifdef ALIASCMD + clipoi2 = clipoi; + i = 0; + + /* Kommando extrahieren und in Grossbuchstaben konvertieren */ + while (*clipoi2 && *clipoi2 != ' ' && i < 255) + cmdtmp[i++] = toupper(*clipoi2++); + cmdtmp[i] = '\0'; + + if (i > 0) + { + for (ap = aliaslist; ap != NULL; ap = ap->next) + if (!strcmp(cmdtmp, ap->alias)) + break; + + if (ap != NULL) + { + strcpy(cmdtmp, ap->cmd); /* neues Kommando einsetzen */ + clicnt = strlen(cmdtmp); + if (*clipoi2 == ' ') /* wenn Pars da waren */ + { + while (*clipoi2 && clicnt < 255) /* diese anfuegen */ + cmdtmp[clicnt++] = *clipoi2++; + cmdtmp[clicnt] = NUL; + } + strcpy(clilin, cmdtmp); + clipoi = clilin; + } + } +#endif + result = intern_command(cmdtab); /* interner Befehl */ + if (result == ERRORS) /* Sonderzeichen im Befehl? */ + { + inv_cmd(); + return; + } + if (result == YES /* kein Interner Befehl */ + && read_txt() /* kein lesbarer Text */ + && extern_command() /* kein externer Befehl */ + ) + inv_cmd(); /* unbekannter Befehl */ + else /* Befehl war OK */ + userpo->errcnt = 0; + } else { /* SYSOP-Port */ + if (intern_command(syscmdtab)) + inv_cmd(); /* einfach nur Invalid Command */ + } + } +} + +void l7rx(void) { + FILE *prot; + char huge *usnxtc; + WORD usget; + WORD zeichen; + MBHEAD *mhdp; + MBHEAD *usrmhd; + MBHEAD *mbp; + UID uid; + UID p_uid; + PTCENT *ptcp; + CQBUF *cqp; + + /*=== eingelaufene Info Frames fuer den CCP verarbeiten ===*/ + while ((mhdp = (MBHEAD *) userhd.head) != (MBHEAD *) &userhd.head) + { + ulink((LEHEAD *)mhdp); + uid = mhdp->type; /* User ID lesen */ + ptcp = ptctab+uid; + userpo = ptcp->ublk; /* Userblock-Zeiger lesen */ + if (userpo == NULL) { /* nicht im CCP? */ + dealmb(mhdp); + continue; + } + + /*==================================================================*/ + /*=== eingelaufene Info Frames fuer User verarbeiten ===*/ + /*------------------------------------------------------------------*/ + + if ((usrmhd = userpo->mbhd) == NULL) + userpo->mbhd = mhdp; + else { + usnxtc = usrmhd->mbbp; + usget = usrmhd->mbgc; + while (usrmhd->mbgc < usrmhd->mbpc) + getchr(usrmhd); + while (mhdp->mbgc < mhdp->mbpc) + putchr(getchr(mhdp), usrmhd); + usrmhd->mbbp = usnxtc; + usrmhd->mbgc = usget; + dealmb(mhdp); + } + + while (userpo && (mhdp = userpo->mbhd) != NULL && getlin(mhdp)) + { + if (l7tosh(mhdp)) /* Shell hat verarbeitet */ + continue; + + if (userpo->fp != NULL) /* Laeuft Datei-Uebertragung? */ + { + if ( userpo->status == US_SBIN /* binaersenden? */ + && abort_sbin(mhdp) == FALSE) /* kam #OK#?, ignorieren */ + { + dealmb(mhdp); + userpo->mbhd = NULL; + continue; + } + + fclose(userpo->fp); /* Ja, dann abbrechen */ + userpo->fp = NULL; + + if (userpo->fname != NULL) + { + xremove(userpo->fname); + free(userpo->fname); + userpo->fname = NULL; + } + + mbp = getmbp(); +#ifdef SPEECH + putstr(speech_message(141), mbp); +#else + putstr("\r- Aborted -\r\r", mbp); +#endif + prompt(mbp); + seteom(mbp); + dealmb(mhdp); /* Abbruchzeile ignorieren */ + userpo->mbhd = NULL; + userpo->status = US_CCP; + continue; + } + + if (userpo->status == US_RBIN) /* BIN-Load */ + { + program_load(mhdp); + if (mhdp->mbgc == mhdp->mbpc) + { + dealmb(mhdp); + userpo->mbhd = NULL; + } + continue; + } + + if (userpo->convers != NULLCONNECTION) + if (convers_input(mhdp)) + { + if (mhdp->mbgc == mhdp->mbpc) + { + dealmb(mhdp); + userpo->mbhd = NULL; + } + continue; + } + + clipoi = clilin; + clicnt = 0; + +#ifdef AUTOBINAERFIX + if (userpo->status == US_WBIN) + { + if ((zeichen = getchr(mhdp)) == CR) + clicnt = 0; + else + { + *clipoi++ = (char)zeichen; + clicnt++; + } + } +#endif /* AUTOBINAERFIX */ + + while ((mhdp->mbgc < mhdp->mbpc) + && ((zeichen = getchr(mhdp)) != CR)) + { + if ((zeichen == BS) || (zeichen == DEL)) + { + if (clicnt != 0) + { + --clipoi; + --clicnt; + } + } + else + { + if ((zeichen != LF) && (clicnt < (WORD)(sizeof(clilin) - 5))) + { +#ifdef __WIN32__ + *clipoi++ = (char)zeichen; +#else + *clipoi++ = zeichen; +#endif /* WIN32 */ + ++clicnt; + } + } + } + *clipoi = NUL; /* und mit NUL terminieren! */ + + if (mhdp->mbgc == mhdp->mbpc) + { + dealmb(mhdp); + userpo->mbhd = NULL; + } + + /*=== Zeile vom User auswerten ===*/ + + switch (userpo->status) { + case US_WBIN : + start_autobin(); + continue; + case US_RTXT : + load_text(); + continue; + } + +#ifdef PACSAT + if (userpo->pacsat != NULL) { + l7_to_pacsat(); + continue; + } +#endif + clipoi = clilin; + + switch (userpo->status) { + case US_WPWD : + case US_WUPW : + get_password(); + mbp = getmbp(); + prompt(mbp); + seteom(mbp); + continue; + +#ifdef USERPROFIL + case US_UPWD : + if (CheckPasswd()) + { + mbp = getmbp(); + + putstr("Invalid Password\r", mbp); + seteom(mbp); + + SendPasswdStringProfil(); + continue; + } + + userpo->status = US_CCP; + send_ctext(); + continue; +#endif /* USERPROFIL */ + + case US_TALK : + if (*clipoi == '/' && tolower(*(clipoi+1)) == 'q') + { + mbp = getmbp(); + prompt(mbp); + seteom(mbp); + userpo->talkcall[0] = NUL; + userpo->status = US_CCP; + } + else + talk_to(userpo->talkcall, 0); + continue; + case US_CREQ : + p_uid = ptcp->p_uid; + disusr(p_uid); + ptcp->p_uid = NO_UID; + ptctab[p_uid].p_uid = NO_UID; + userpo->status = US_CCP; + break; + case US_CQ : + for (cqp = (CQBUF *)cq_user.head; + cqp != (CQBUF *)&cq_user; + cqp = cqp->next) + { + if (cqp->uid == userpo->uid) + { + dealoc((MBHEAD *)ulink((LEHEAD *)cqp)); + break; + } + } + userpo->status = US_CCP; + ptcp = ptctab + uid; + ptcp->p_uid = NO_UID; + break; + } + + clipoi = clilin; + + /* hier werden alle Eingaben in einer Datei protokolliert */ + /* wenn dies gewuenscht wird ! */ + + if ( (proto == 2) || + ((proto == 1) && (issyso () ))) + { + if ((prot = xfopen("COMMAND.LOG", "at")) != NULL) + { + fprintf(prot, "(%u) %.6s %s > %s\n\n", + uid, + calofs(UPLINK, uid), + ctime(&sys_time), + clipoi); + fclose(prot); + } + } + + if (skipsp(&clicnt, &clipoi)) + ccpcmd(); /* Zeile mit Inhalt */ + else + { /* leere Zeile */ + mbp = getmbp(); + prompt(mbp); + seteom(mbp); + } /* else */ + } /* while */ + } /* while */ +} + +/************************************************************************/ +/* */ +/* Wenn noch Reste aus einer Datei zu senden sind, diese an den User */ +/* senden */ +/* */ +/************************************************************************/ +void +l7tx(void) +{ + MBHEAD *mbp; + LONG pos; + WORD c; + WORD i; +#ifdef PORT_MANUELL + LNKBLK *link; + UWORD PacLen = FALSE; +#endif /* PORT_MANUELL */ + + for (userpo = (USRBLK *) usccpl.head; + userpo != (USRBLK *) &usccpl; + userpo = (USRBLK *) userpo->unext) + { + if (userpo->status == US_DIG) + { + gateway(); + if (userpo->status == US_DIG) + userpo->status = US_CCP; + continue; + } + + if (userpo->fp != NULL) + { +#ifdef PORT_MANUELL + switch (g_utyp(userpo->uid)) + { + case L2_USER: + link = g_ulink(userpo->uid); + PacLen = portpar[link->liport].paclen; + break; + + default: + PacLen = 236; + break; + } +#endif /* PORT_MANUELL */ + do + { + pos = ftell(userpo->fp); + mbp = getmbp(); + if (userpo->status == US_SBIN) + { +#ifdef PORT_MANUELL + for (i = 0; i < PacLen; ++i) +#else + for (i = 0; i < paclen; ++i) +#endif /* PORT_MANUELL */ + { + if ((c = fgetc(userpo->fp)) == EOF) + break; /* for ... */ +#ifdef __WIN32__ + putchr((char)c, mbp); +#else + putchr(c, mbp); +#endif /* WIN32 */ + } + } + else + { +#ifdef MAKRO_FILE + /* USERPO->FILE nach Makros untersuchen */ + /* und neue USER->FILE erstellen. */ + /* Gibt es einen Fehler in der funktion */ + /* update_userpo_file(userpo); wird die */ + /* alte userpo->fp genommen! */ + update_userpo_file(userpo); +#endif +#ifdef PORT_MANUELL + for (i = 0; i < PacLen; ++i) +#else + for (i = 0; i < paclen; ++i) +#endif /* PORT_MANUELL */ + { + if ((c = fgetc(userpo->fp)) == EOF) + break; /* for ... */ + + if (c != CR) +#ifdef __WIN32__ + putchr((char)(c == '\n' ? CR : c), mbp); +#else + putchr(c == '\n' ? CR : c, mbp); +#endif /* WIN32 */ + } + } + } + while (i && send_msg(FALSE, mbp)); /* sind wir losgeworden */ + + if (i) /* spaeter versuchen */ + { + dealmb((MBHEAD *)ulink((LEHEAD *) mbp)); + fseek(userpo->fp, pos, SEEK_SET); + } + else /* Ende erreicht */ + { +#ifdef MAKRO_FILE + /* Alle Daten verarbeitet, */ + /* dies markieren. */ + userpo->read_ok = FALSE; +#endif + putchr('\r', mbp); + prompt(mbp); + send_msg(TRUE, mbp); + fclose(userpo->fp); + userpo->fp = NULL; + if (userpo->fname != NULL) + { + xremove(userpo->fname); + free(userpo->fname); + userpo->fname = NULL; + } + userpo->status = US_CCP; + } + } + } + convers_output(); +} + +/**************************************************************************/ +/* BEACON */ +/*------------------------------------------------------------------------*/ +void ccpbea(void) +{ + MBHEAD *mbp; + BEACON *beapoi; + char call[L2IDLEN]; + char digil[L2VLEN+1]; + WORD port; + WORD interval; + WORD telemetrie; + WORD chaptr; + + if (issyso()) + { + skipsp(&clicnt, &clipoi); + if (clicnt) + if ((port = (WORD) (nxtnum(&clicnt, &clipoi) & 0x7F)) < L2PNUM) { + beapoi = &beacon[port]; + skipsp(&clicnt, &clipoi); + if (*clipoi == '=') { + ++clipoi; + --clicnt; + skipsp(&clicnt, &clipoi); + chaptr = 0; + while ((clicnt-- >0) && chaptr < 79) + beapoi->text[chaptr++] = *clipoi++; + beapoi->text[chaptr] = NUL; + if (beapoi->text[0] == '.') + beapoi->text[0] = NUL; + } else { + interval = nxtnum(&clicnt, &clipoi); + telemetrie = nxtnum (&clicnt, &clipoi); + if (getcal(&clicnt, &clipoi, FALSE, call) == YES) { + cpyid(beapoi->beades, call); + getdig(&clicnt, &clipoi, TRUE, digil); + cpyidl(beapoi->beadil, digil); + beapoi->interval = interval; + beapoi->telemetrie = telemetrie; + if (beapoi->interval != 0) + { + beapoi->beatim = interval; /* vorzeitige Aussendung erwirken */ + beacsv(); + } + } + } + userpo->sysflg = 2; + } + } + + mbp = putals("Beacons:\r"); + for (port = 0, beapoi = beacon; port < L2PNUM; ++port, ++beapoi) { + if (beapoi->interval != 0) { + if (userpo->sysflg == 2) + beapoi->beatim = 0; + putnum(port, mbp); + putchr(' ', mbp); + putnum(beapoi->interval, mbp); + putchr(' ', mbp); + putnum(beapoi->telemetrie, mbp); + putchr(' ', mbp); + putid(beapoi->beades, mbp); + putdil(beapoi->beadil, mbp); + putchr('\r', mbp); + putstr(beapoi->text, mbp); + putchr('\r', mbp); + } + } + prompt(mbp); + seteom(mbp); +} + +/**************************************************************************/ +/* READ - Datei lesen */ +/*------------------------------------------------------------------------*/ +void ccpread(char *text) /* READ - Befehl (Dateien lesen) */ +{ + char file[MAXPATH+1]; + + MBHEAD *mbp; +#ifdef __WIN32__ + int a; +#endif + +/* wenn text == NULL, dann war es ein Readbefehl + ansonsten enthaelt text entweder den Namen einer Infodatei + oder einer Tempdatei + ob die Datei geloescht werden muss, erfaehrt man, + wenn userpo->fname != NULL ist +*/ + if (text != NULL) + { + normfname(text); + if (strpbrk(text, ":\\/") == NULL) { + strcpy(file, textpath); + strcat(file, text); + } + else + strcpy(file, text); + userpo->fp = xfopen(file, "rt"); + } + else + { + if (issyso()) + { + strncpy(file, (char*)clipoi, MAXPATH); + file[MAXPATH] = NUL; +#ifdef WIN32 + a = strlen((char*)clipoi); + if (a == 0) { + mbp = getmbp(); +#ifdef SPEECH + putstr(speech_message(142), mbp); +#else + putstr("Sri, no text available!\r", mbp); +#endif + prompt(mbp); + seteom(mbp); + return; + } +#endif + + } + userpo->fp = xfopen(file, "rt"); + } + + if (userpo->fp == NULL) { + mbp = getmbp(); + if (text != NULL) + if (strcmp(text, "CMD.TMP") == 0) { +#ifdef SPEECH + putstr(speech_message(143), mbp); +#else + putstr("CLI failed!\r", mbp); +#endif + prompt(mbp); + seteom(mbp); + return; + } + if (userpo->fname != NULL) + { + free(userpo->fname); + userpo->fname = NULL; + } +#ifdef SPEECH + putstr(speech_message(142), mbp); +#else + putstr("Sri, no text available!\r", mbp); +#endif + prompt(mbp); + seteom(mbp); + } +} + +/** + * Parameter-Auswertung fuer LOAD/EDIT. + * Es kann immer nur ein EDIT/LOAD zur Zeit laufen, dafuer aber mit + * vollen Pfaden. Dies ist wohl keine echte Einschraenkung, es sollten + * sowieso nicht zwei Sysops auf einmal schrauben, das bringt nur Chaos. + */ +static BOOLEAN loadprm(void) { + char name[MAXPATH], *c; + + if (issyso()) { + if (!*loadname) + { + clipoi[clicnt] = NUL; + if (sscanf((char *) clipoi, "%s", name) == 1) + { + /* TMP-File auf dem Pfad des Zielfiles wegen Rename */ + + if (strpbrk(name, ":/\\") == NULL) + { + strcpy(loadname, textpath); + strcpy(loadtmp, textpath); + } + else + { + strcpy(loadtmp, name); + if ((c = strrchr(loadtmp, '/')) == NULL) + if ((c = strrchr(loadtmp, '\\')) == NULL) + c = strchr(loadtmp, ':'); + c++; + *c = NUL; + } + strcat(loadname, name); + strcat(loadtmp, "LOAD.TMP"); + return(TRUE); + } else +#ifdef SPEECH + putmsg(speech_message(188)); +#else + putmsg("Invalid filename!\r"); +#endif + } else +#ifdef SPEECH + putmsg(speech_message(189)); +#else + putmsg("EDIT/LOAD in use by other Sysop\r"); +#endif + } + else + invmsg(); + + return(FALSE); +} + +/**************************************************************************/ +/* EDIT */ +/*------------------------------------------------------------------------*/ +void ccpedi(void) +{ + MBHEAD *mbp; +#ifdef EDITOR + + if (loadprm()) + { +#ifndef MC68302 + if ((loadfp = xfopen(loadtmp, "wt")) != NULL) +#else + xremove(loadname); + if ((loadfp = xfopen(loadname, "wt")) != NULL) +#endif + { + userpo->status = US_RTXT; + mbp = getmbp(); +#ifdef SPEECH + putprintf(mbp, speech_message(175), loadname); +#else + putprintf(mbp, "editing>%s\r" + "Enter text. End with '.' in a new line.\r", loadname); +#endif + seteom(mbp); + } + else { +#ifdef SPEECH + putmsg(speech_message(190)); +#else + putmsg("Open error!\r"); +#endif + loadname[0] = loadtmp[0] = NUL; + } + } +#else + if (loadprm()) { +#ifndef MC68302 + if ((loadfp = xfopen(loadtmp, "wt")) != NULL) +#else + xremove(loadname); + if ((loadfp = xfopen(loadname, "wt")) != NULL) +#endif + { + userpo->status = US_RTXT; + mbp = getmbp(); +#ifdef SPEECH + putprintf(mbp, speech_message(175), loadname); +#else + putprintf(mbp, "editing>%s\r" + "Enter text. End with '.' in a new line.\r", loadname); +#endif + seteom(mbp); + } + else { +#ifdef SPEECH + putmsg(speech_message(190)); +#else + putmsg("Open error!\r"); +#endif + loadname[0] = loadtmp[0] = NUL; + } + } +#endif /* EDITOR */ +} + +/**************************************************************************/ +/* LOAD */ +/*------------------------------------------------------------------------*/ +void ccpload(void) +{ + MBHEAD *mbp; + + if (loadprm()) { +#ifndef MC68302 + if ((loadfp = xfopen(loadtmp, "wb")) != NULL) +#else + xremove(loadname); + if ((loadfp = xfopen(loadname, "wb")) != NULL) +#endif + { + userpo->status = US_WBIN; + mbp = getmbp(); +#ifdef SPEECH + putstr(speech_message(144), mbp); +#else + putstr("Waiting for AUTOBIN-Transfer...\r", mbp); +#endif + seteom(mbp); + checksum = 0L; + crc = 0; + } + else { +#ifdef SPEECH + putmsg(speech_message(191)); +#else + putmsg("File error!\r"); +#endif + loadname[0] = loadtmp[0] = NUL; + } + } +} + +/**************************************************************************/ +/* SysOp */ +/*------------------------------------------------------------------------*/ +void ccpsys(void) /* SYSOP - Befehl (Als Sysop anmelden) */ +{ +#ifndef USER_PASSWORD + WORD num; + WORD i, j; + MBHEAD *mbp; + + if (paswle != 0) + { + mbp = putals(""); + srand((UWORD)tic10); + for (i = 0; i < 5; ++i) { + do { + do; + while (((num = (rand()%256)) >= paswle) || (paswrd[num] == ' ')); + for (j = 0; j < i; ++j) { + if ((userpo->paswrd[j] & 0xFF) == num) + break; + } + } while (i != j); +#ifdef __WIN32__ + userpo->paswrd[i] = (unsigned char)num; +#else + userpo->paswrd[i] = num; +#endif /* WIN32 */ + putchr(' ', mbp); + putnum((num + 1), mbp); + } + putchr('\r', mbp); + seteom(mbp); + for (i = 0; i < 5; ++i) /* Antwort aufbauen */ + userpo->paswrd[i] = paswrd[userpo->paswrd[i]]; + userpo->status = US_WPWD; + } +#else + WORD num; + WORD i, j; + MBHEAD *mbp; + FILE *fp; + BOOLEAN found = FALSE; + char *pwd = paswrd; + int pwl = paswle; + char userpwd[100]; + char call1[L2IDLEN]; + char call2[L2IDLEN]; + char line[256]; + char fn[MAXPATH]; + char *c; + + if (userpo->pwdtyp == PW_NOPW) + { + cpyid(call1, calofs(UPLINK, userpo->uid)); + if ((fp = xfopen("PERMS.TNN", "rt")) != NULL) + { + while (fgets(line, 256, fp) != NULL) + { + if (line[0] == '#') /* Kommentarzeile ignorieren */ + continue; + str2call(call2, line); /* Call steht am Zeilenanfang */ + if (cmpcal(call1, call2)) /* User gefunden? */ + { + sscanf(line, "%*s %s", fn); /* Filename steht an 2. Stelle */ + found = TRUE; /* Password-File gefunden */ + break; + } + } + fclose(fp); + } + if (found) /* wenn Password-File angegeben */ + { + if ((fp = xfopen(fn, "rt")) != NULL) /* existiert PWD-File? */ + { + fgets(userpwd, 81, fp); /* Password lesen */ + if ((c = strchr(userpwd, '\n')) != NULL) + *c = NUL; + if ((i = strlen(userpwd)) >= 5) /* min. 5 Zeichen! */ + { + pwd = userpwd; + pwl = i; + } + else + found = FALSE; /* war nix - also globales PWD */ + fclose(fp); + } + } + } + + if (pwl >= 5) + { + mbp = putals(""); + srand((UWORD)tic10); + for (i = 0; i < 5; ++i) + { + do + { + do; while (((num = (rand()%256)) >= pwl) || (pwd[num] == ' ')); + for (j = 0; j < i; ++j) + { + if ((userpo->paswrd[j] & 0xFF) == num) + break; + } + } while (i != j); +#ifdef __WIN32__ + userpo->paswrd[i] = (UBYTE)num; +#else + userpo->paswrd[i] = num; +#endif + putchr(' ', mbp); + putnum((num + 1), mbp); + } + putchr('\r', mbp); + seteom(mbp); + for (i = 0; i < 5; ++i) /* Antwort aufbauen */ + userpo->paswrd[i] = pwd[userpo->paswrd[i]]; + userpo->status = US_WPWD; + if (found) /* war User-Password */ + userpo->status = US_WUPW; + } +#endif +} + +/************************************************************************/ +/* USER */ +/*----------------------------------------------------------------------*/ +void ccpuse(void) +{ + WORD port; + MBHEAD *mbp; + #define USE_ALL 255 + #define USE_MASK 254 + #define USE_CALL 253 + #define USE_CONV 252 + #define USE_HOST 251 + char call[L2IDLEN+1]; + char mask[MAXMASK]; + int i; + +/* Titelzeile in neuen Buffer */ + mbp = putals(" "); + putprintf(mbp, "%s%d)", signon, nmbfre); + i = mbp->mbpc; + +/* Ueberpruefen, ob Befehl mit Parametern eingegeben wurde... */ + if (skipsp(&clicnt, &clipoi)) + { + if (getport(&clicnt, &clipoi, &port)) { + /* Bei U Port alle L2-Uses dieses Ports zeigen */ + l2user(mbp, port, ""); + if (i == mbp->mbpc) putchr('\r', mbp); + prompt(mbp); + seteom(mbp); + return; + } + + if (strchr(clipoi, '+')) + { + l2user(mbp, USE_ALL, ""); /* Level 2 User in Tabellenform anzeigen */ + l4user(mbp, USE_ALL, ""); /* Level 4 User in Tabellenform anzeigen */ +#ifdef L1TCPIP + TcpipUser(mbp, USE_ALL, "");/* Tcpip-User in Tabellenform anzeigen. */ +#endif /* L1TCPIP */ + hostuser(mbp, USE_ALL, ""); /* Host-User in Tabellenform anzeigen */ + } else + if (toupper(*clipoi) == 'C' && clicnt == 1) + { + l4user(mbp, USE_ALL, ""); /* Bei U C nur die L4 User ausgeben */ + } else + if (toupper(*clipoi) == 'L' && clicnt == 1) + { + l2user(mbp, USE_ALL, ""); /* Bei U L alle L2 user anzeigen */ + } else + if (toupper(*clipoi) == 'H' && clicnt == 1) + { + ptcuser(mbp, USE_CONV, ""); + ptcuser(mbp, USE_HOST, ""); +#ifdef L1TCPIP + TcpipUser(mbp, USE_ALL, ""); /* Telnet-User in Tabellenform anzeigen*/ +#endif /* L1TCPIP */ + hostuser(mbp, USE_ALL, ""); + } else + if (getcal(&clicnt, &clipoi, TRUE, call) == YES) { + ptcuser(mbp, USE_CALL, call); + l2user(mbp, USE_CALL, call); + l4user(mbp, USE_CALL, call); +#ifdef L1TCPIP + TcpipUser(mbp, USE_CALL, call);/* Telnet-User in Tabellenform anzeigen */ +#endif /* L1TCPIP */ + hostuser(mbp, USE_CALL, call); + } else + if (mhprm(clipoi, clicnt, mask) == TRUE) { + ptcuser(mbp, USE_MASK, mask); + l2user(mbp, USE_MASK, mask); + l4user(mbp, USE_MASK, mask); +#ifdef L1TCPIP + TcpipUser(mbp, USE_MASK, mask); /* Telnet-User in Tabellenform anzeigen*/ +#endif /* L1TCPIP */ + hostuser(mbp, USE_MASK, mask); + } + if (i == mbp->mbpc) putchr('\r', mbp); + } + else + ptcuser(mbp, USE_ALL, ""); + prompt(mbp); + seteom(mbp); +} + +/* + * Formatierte Ausgabe einer Zahl 7stellig plus Suffix (k, M, G) + */ +static void put_kMG(MBHEAD *mbp, ULONG num) { + const char *kMG = " kMG"; + int suffix = 0; + + while ((num > 999999L) && (suffix < 3)) { + num /= 1024L; + suffix++; + } + putprintf(mbp, " %6lu%c", num, kMG[suffix]); +} + +/************************************************************************/ +/* */ +/* Formatierte Ausgabe evtl. sehr grosser Zahlen mit Punkten. */ +/* Die tatsaechliche Zahl besteht aus den Teilen "num" und "millions", */ +/* die zusammengerechnet werden muessen zu "num + millions * 1000000". */ +/* */ +/************************************************************************/ +static void +put_pktnum(MBHEAD *mbp, ULONG millions, ULONG num) +{ + char str[20]; + char *p; + int len; + int i; + + sprintf(str, "%lu%06lu", millions, num); + p = str; + while (*p == '0') + p++; + for (i = len = (int) strlen(p); i > 0; i--) + { + if ((i % 3) == 0) + if (i != len) + putchr(',', mbp); + putchr(*p++, mbp); + } +} + +/* + * Baudrate, Counter und Connect-Zeit aus der Patchcord-Tabelle ausgeben. + */ +static void putptcinfo(PTCENT *ptcp, MBHEAD *mbp) { + ULONG Baud = (ptcp->rxbps + ptcp->txbps) * 8; +#ifndef CONNECTTIME + ULONG d, h, m, s; + /* Die Ausgabe aller Werte erfolgt 7stellig plus Suffix (k, M, G) */ +#endif /* CONNECTTIME */ + + put_kMG(mbp, ptcp->inforx); /* empfangene Bytes */ + put_kMG(mbp, ptcp->infotx); /* gesendete Bytes */ + put_kMG(mbp, Baud); /* errechnete Baudrate */ + +#ifndef CONNECTTIME + d = ptcp->contime; + s = d % 60L; d /= 60L; + m = d % 60L; d /= 60L; + h = d % 24L; d /= 24L; + if (d < 1L) + putprintf(mbp, " %2lu:%02lu:%02lu", h, m, s); /* hh:mm:ss */ + else + if (d < 99L) + putprintf(mbp, " %2lu/%02lu:%02lu", d, h, m); /* dd/hh:mm */ + else + putprintf(mbp, "%5lu/%02lu", d, h); /* ddddd/hh */ +#else /* CONNECTTIME */ + putprintf(mbp, " %s", ConnectTime(ptcp->contime)); +#endif /* CONNECTTIME */ +} + +/*------------------------------------------------------------------------*/ +/* + * Level 2 User in Tabellenform anzeigen: + * + * Po SrcCall DstCall LS Rx Tx Tr SRTT RxkB TxkB Baud ConTime Pri + * ------------------------------------------------------------------------- + * 0 DD1FR DB0KH IXF 2 10 3 1234 3456 72345 122 0:45:16 0 + * 1 DB0KH DF7ZE REJ 0 0 0 254 652 52345 345 1:23:01 10 + * / / / / / / / / / / / / / + * 0) 1) 2) 3) 4) 5) 6) 7) 8) 9) 10) 11) 12) + * 0) Port + * 1) Quellrufzeichen des L2-QSOs + * 2) Zielrufzeichen des L2-QSOs + * 3) L2-Link-Status: + * SET = Link-Setup + * FMR = Frame Reject + * DRQ = Disconnect Request + * IXF = Info Transfer + * REJ = REJ Sent + * WAK = Waiting Ackknowledge + * DBS = Device Busy + * RBS = Remote Busy + * BBS = Both Busy + * WDB = Waiting Ack And Device Busy + * WRB = Waiting Ack And Remote Busy + * WBB = Waiting Ack And Both Busy + * RDB = REJ Sent and Device Busy + * RRB = REJ Sent and Remote Busy + * RBB = REJ Sent and Both Busy + * HTH = HTH waiting + * 4) Anzahl der empfangenen Frames in der Warteschlange fuer diesen + * Link + * 5) Anzahl der noch zu sendenden Frames in der Warteschlange fuer + * diesen Link + * 6) Anzahl Retries + * 7) Stand des 'Smoothed Round Trip Timers' + * 8) Anzahl empfangender Bytes seit Bestehen des Links + * 9) Anzahl gesendetet Bytes seit Bestehen des Links + * 10) Aus 8) + 9) errechnete effektive Baudrate fuer diesen Link + * 11) Connectzeit + * 12) Bei DAMA-Netzeinstiegen: aktuelle Prioritaet des Users + * (0 = hoechste Prioritaet) + * */ + +static void l2user(MBHEAD *mbp, WORD what, const char *pstr) +{ + LNKBLK *lp; + char lsts[] = {"DISSETFMRDRQIXFREJWAKDBSRBSBBSWDBWRBWBBRDBRRBRBBHTH"}; + char tmp1[10], + tmp2[10]; + LHEAD *actlp; + PTCENT *ptcp; + int port; + BOOLEAN first = TRUE; + + for (port = 0, actlp = &l2actl[0]; port < L2PNUM; port++, actlp++) { + for (lp = (LNKBLK *) actlp->head; + lp != (LNKBLK *) actlp; + lp = lp->next) { + switch (what) { + case USE_ALL : break; + case USE_MASK : if ( !c6mtch(lp->dstid, pstr) + && !c6mtch(lp->srcid, pstr)) continue; + break; + case USE_CALL : if ( !cmpid(lp->dstid, pstr) + && !cmpid(lp->srcid, pstr)) continue; + break; + default : if (what < L2PNUM && port != what) continue; + } + ptcp = ptctab + g_uid(lp, L2_USER); + mbp->l4time = mbp->mbpc; + call2str(tmp1, lp->srcid); + call2str(tmp2, lp->dstid); + if (first) { + putstr("\rL2 - User:\r", mbp); + putstr("Po SrcCall DstCall LS Rx Tx Tr SRTT RxB TxB Baud ConTime Pr Da\r", mbp); + putstr("-------------------------------------------------------------------------------\r", mbp); + first = FALSE; + } + putprintf(mbp, "%2d %-9.9s %-9.9s %3.3s%3u%3u%3u%5u", + lp->liport, /* Port nr user */ + tmp1, /* Quell-Rufzeichen */ + tmp2, /* Ziel-Rufzeichen */ + &lsts[lp->state * 3], /* Link-Status */ + lp->rcvd, /* Frames in RX-Queue */ + lp->tosend, /* Frames in TX-Queue */ + lp->tries, /* Link-Retries */ + lp->SRTT); /* Round Trip Timer */ + + putptcinfo(ptcp, mbp); + + if (dama(lp->liport)) + putprintf(mbp, " %2d %2d\r", /* DAMA-Prioritaet */ + lp->damapm, + portpar[lp->liport].dch + 1); + else + putstr(" -\r", mbp); + } + } +} + +/*------------------------------------------------------------------------*/ + +/* + * Level 4 User in Tabellenform anzeigen: + * + * Call Node S Rx Tx Tr Win RxB TxB Baud ConTime + * ------------------------------------------------------------------------------ + * DL9HCJ HHOST :DB0HHO IXF 0 1 0 10 4321 45621 153 01:33:12 + * DG9FU KS :DB0EAM IXF 0 0 0 10 87554 12874 743 01:59:03 + * / / / / / / / / / / / + * 1) 2) 3) 4) 5) 6) 7) 8) 9) 10) 11) + * + * 1) Rufzeichen des Users + * 2) Ident und Call des Knotens an dem der User eingeloggt ist + * 3) L4-Circuit-Status: + * SET = Circuit-Setup + * IXF = Info-Transfer + * DRQ = Disconnect-Request + * 4) Anzahl der empfangenen Frames in der Warteschlange fuer diesen + * Circuit + * 5) Anzahl der noch zu sendenden Frames in der Warteschlange fuer + * diesen Circuit + * 6) Anzahl Transport-Retries + * 7) Transport Fenstergroesse + * 8) Anzahl empfangender Bytes seit Bestehen des Circuits + * 9) Anzahl gesendetet Bytes seit Bestehen des Circuits + * 10) Aus 8) + 9) errechnete effektive Baudrate fuer diesen Circuit + * 11) Connectzeit + * + */ + +static void l4user(MBHEAD *mbp, WORD what, const char *pstr) +{ + CIRBLK *p; + WORD i; + char lsts[] = {"-SID"}; /* {"---SETIXFDRQ"}; */ + char tmp1[10], + tmp3[10]; + PTCENT *ptcp; + BOOLEAN first = TRUE; + + /* + * Circuit-Tabelle durchgehen und fuer alle nicht disconnecteten + * Circuits Info anzeigen + */ + + for (p = cirtab, i = 0; i < NUMCIR; ++p, ++i) { + if (p->state != 0) { /* nur aktive Circuits */ + switch (what) { + case USE_ALL : break; + case USE_MASK : if (!c6mtch(p->upcall, pstr)) continue; + break; + case USE_CALL : if (!cmpid(p->upcall, pstr)) continue; + break; + } + ptcp = ptctab + g_uid(p, L4_USER); + mbp->l4time = mbp->mbpc; + call2str(tmp1, p->upcall); + + call2str(tmp3, p->l3node); + /*find_best_qual((int)(np-netp->nodetab), &bestpp, DG); + call2str(tmp2, bestpp->l2link->call);*/ + + if (first) { +#ifdef SPEECH + putstr(speech_message(146), mbp); +#else + putstr("\rL4 - User:\r", mbp); + putstr("Call Node S Rx Tx Tr Win SRTT RxB TxB Baud ConTime\r", mbp); +#endif + putstr("-----------------------------------------------------------------------------\r", mbp); + first = FALSE; + } + + putprintf(mbp, "%-9.9s %-9.9s %c%c%c%3u %3u %2u %2u %5u ", + tmp1, /* User-Call */ + tmp3, /* Node */ + ((p->l4flag & L4FBUSY) ? '.':' '), + lsts[(int)p->state], /* Circuit Status */ + ((p->l4flag & L4FPBUSY) ? '.':' '), + p->numrx, /* Frames in RX-Queue */ + p->numtx, /* Frames in TX-Queue */ + p->l4try, /* Transport-Retries */ + p->window, /* Transport-Window */ + p->SRTT); + + putptcinfo(ptcp, mbp); + + putchr('\r', mbp); + } + } +} + + +/*----------------------------------------------------------------------*/ +/* */ +/*----------------------------------------------------------------------*/ +void viaput(LINKTYP seite, UID uid, MBHEAD *mbp) +{ + UBYTE typ = g_utyp(uid); + LNKBLK *lp; + CIRBLK *cp; + const char *p; +#ifdef USER_AUSGABE + int index; + NODE *np; +#endif /* USER_AUSGABE */ + + if (typ == L2_USER) { + lp = g_ulink(uid); + p = ndigipt(lp->viaidl); + if ((*p != NUL) || (!updmheard(lp->liport))) + { +#ifndef USER_AUSGABE + putstr(seite == UPLINK ? "\r Uplink" : "\r Downlink", mbp); + if (*p == NUL) /* ohne Digis */ + putprintf(mbp, " %s", portpar[lp->liport].name); + else + putdil(p, mbp); +#else + if (*p != NUL) /* Ausgabe nur mit Digis */ + { + putstr(seite == UPLINK ? "\r Uplink" : "\r Downlink", mbp); + putdil(p, mbp); + } +#endif /* USER_AUSGABE */ + } + } else { +#ifdef USER_AUSGABE + if (typ == L4_USER) +#else + if (typ == L4_USER && seite == UPLINK) /* User ist Circuit */ +#endif /* USER_AUSGABE */ + { +/************************************************************************\ +* * +* Die Uplinkinformation wird nur angezeigt, wenn entweder der letzte * +* Absenderknoten nicht der Uplinkknoten ist oder aber wenn beim Uplink * +* Digis verwendet wurden. Dann steht in einer eigenen Zeile: * +* ' Uplink @ uplinkknoten via digikette' * +* * +\************************************************************************/ +#ifdef USER_AUSGABE + cp = g_ulink(uid); + if ( (!cmpid(cp->downca, cp->upnod)) + ||(*(cp->upnodv) != NUL)) + { + putstr(seite == UPLINK ? "\r Uplink @ " : "\r Downlink @ ", mbp); + + index = find_node_this_ssid(cp->downca); + + if (index != -1) + { + np = netp->nodetab+index; + putalt(np->alias, mbp); + } + + putid(cp->downca, mbp); +#else + cp = g_ulink(uid); + if ( (!cmpid(cp->upnod, cp->downca)) + ||(*(cp->upnodv) != NUL)) + { + putstr("\r Uplink @ ", mbp); + putid(cp->upnod, mbp); + putdil(cp->upnodv, mbp); +#endif /* USER_AUSGABE */ + } + } + } +} + +#ifdef USER_MONITOR +void puttraceu(USRBLK *u, MBHEAD *mbp) +{ + UID uid = u->uid; + + putuse(UPLINK, uid, mbp); + putspa(38, mbp); + putstr("<--> (", mbp); + putid(calofs(UPLINK, uid), mbp); + putspa(53,mbp); + putstr("<> Tracen)", mbp); + putspa(65,mbp); + putstr(" PO ", mbp); + putprintf(mbp,"%d",u->monitor->Mport); +} +#endif /* USER_MONITOR */ + +/* Ausgeben der Patchcordliste, eventuell auch nur fuer ein Call oder eine */ +/* Menge von Calls. */ +static void ptcuser(MBHEAD *mbp, WORD what, const char *pstr) +{ + LINKTYP updown; + PTCENT *ptcp; + UID uid; + WORD cvsflg = 0; + + if (what == USE_CONV) { + cvsflg = 1; + what = USE_ALL; + } + + /* + * Ausgegeben werden alle Uplinks aus der Patchcord mit ihren Downlinks + * und die CCP-User (Convers, echte User usw) + */ + if (what != USE_HOST) + putchr('\r', mbp); + for (uid = 0, ptcp = ptctab; uid < NUMPAT; ++uid, ptcp++) + { + if (ptcp->state == 0) continue; + switch (what) { + case USE_ALL : break; + case USE_MASK : if ( (!c6mtch(calofs(UPLINK, uid), pstr)) + && (!c6mtch(calofs(DOWNLINK, uid), pstr))) + continue; + break; + case USE_CALL : if ( (!cmpid(calofs(UPLINK, uid), pstr)) + && (!cmpid(calofs(DOWNLINK, uid), pstr))) + continue; + break; + case USE_HOST : if ( (g_utyp(uid) != HOST_USER) + && (g_utyp(ptcp->p_uid) != HOST_USER)) + continue; + break; + } + mbp->l4time = mbp->mbpc; + switch (ptcp->state) { + case UPLINK : /* kommt vom CCP (Convers) */ + if (ptcp->ublk) { /* ist der im CCP? */ + if ( (!cvsflg && ptcp->ublk->convflag == TRUE) + || (cvsflg && !ptcp->ublk->convflag == TRUE)) + continue; + if (ptcp->ublk->convers != NULLCONNECTION) { + putcvsu(ptcp->ublk, mbp); /* Convers-Verb. */ + putchr('\r', mbp); + continue; + } +#ifdef USER_MONITOR + if (ptcp->ublk->status == US_TRAC) + { + puttraceu(ptcp->ublk, mbp); /* Trace-Verb. */ + putchr('\r', mbp); + continue; + } +#endif /* USER_MONITOR */ + } + break; +#ifndef USER_AUSGABE + case D_IPLINK : +#endif /* USER_AUSGABE */ + case U_IPLINK : + updown = ptcp->state == D_IPLINK ? DOWNLINK : UPLINK; + putuse(updown, uid, mbp); + putspa(38, mbp); +#ifdef USER_AUSGABE + putstr("<--> (", mbp); + putid(calofs(UPLINK, uid), mbp); + putspa(53,mbp); + putstr("<> IP-Router)", mbp); +#else /* USER_AUSGABE */ + putstr("<--> IP-Router", mbp); +#endif /* USER_AUSGABE */ + viaput(updown, uid, mbp); + putchr('\r', mbp); + continue; + +#ifdef L1IPCONV + case C_IPLINK : + updown = ptcp->state == D_IPLINK ? DOWNLINK : UPLINK; + + if (ptcp->ublk->convers == NULL) /* Login fehlgeschlagen. */ + continue; /* zum naechsten Eintrag. */ + + putuse(updown, uid, mbp); + putspa(38, mbp); +#ifdef USER_AUSGABE + putstr("<--> (", mbp); + putid(calofs(UPLINK, uid), mbp); + putspa(53,mbp); + putstr("<> Convers)", mbp); + putspa(65,mbp); + putstr("Ch ", mbp); + +#ifndef L1IRC + if (ptcp->ublk != NULL) + putlong(ptcp->ublk->convers->channel, 0, mbp); +#else + if (ptcp->ublk != NULL) + { + if (ptcp->ublk->convers->channel == EOF) + putstr(" no Channel", mbp); + else + putlong(ptcp->ublk->convers->channel, 0, mbp); + } +#endif /* L1IRC */ +#else /* USER_AUSGABE */ + putstr("<--> Convers", mbp); +#endif /* USER_AUSGABE */ + putchr('\r', mbp); + continue; +#endif /* L1IPCONV / L1IRC */ + + default: + continue; + } + if (cvsflg) + continue; + putuse(UPLINK, uid, mbp); + if (ptcp->p_uid != NO_UID) { /* gibts einen Partner-Link? */ + putspa(38, mbp); + putstr(ptcp->ublk ? "<..> " : "<--> ", mbp); + if (ptcp->ublk) + if (ptcp->ublk->status == US_CQ) + { + putuse(CQ_LINK, uid, mbp); + continue; + } + putuse(DOWNLINK, ptcp->p_uid, mbp); + } + viaput(UPLINK, uid, mbp); + if (ptcp->p_uid != NO_UID) + viaput(DOWNLINK, ptcp->p_uid, mbp); + putchr('\r', mbp); + } +} + + +#ifdef L1TCPIP +static void TcpipUser(MBHEAD *mbp, WORD what, const char *pstr) +{ + TCPIP *tpoi; + int i; + char tmp1[10]; + char tmp2[10]; + PTCENT *ptcp; + BOOLEAN first = TRUE; + static char *Interface[] = {"Telnet","Httpd ","IPConv"}; + + for (i = 0, tpoi = tcptbl; i < MAXTCPIP; ++i, ++tpoi) + { + if ( tpoi->activ == TRUE + && tpoi->login == TRUE) + { + switch (what) + { + case USE_ALL : break; + case USE_MASK : if (!c6mtch(tpoi->Upcall, pstr)) continue; + break; + case USE_CALL : if (!cmpid(tpoi->Upcall, pstr)) continue; + break; + } + call2str(tmp1, tpoi->Upcall); + call2str(tmp2, tpoi->Downcall); + + ptcp = ptctab + g_uid(tpoi, TCP_USER); + if (first) + { + putstr("\rTCPIP-User:\r" + "Interf SrcCall DstCall T3 RxB TxB Baud ConTime\r" + "-------------------------------------------------------------------\r", mbp); + first = FALSE; + } + putprintf(mbp, "%6s: %-9.9s %-9.9s %5u ", + Interface[tpoi->Interface - KISS_TCPIP] + ,tmp1 + ,tmp2 + ,tpoi->noacti); + + putptcinfo(ptcp, mbp); + putchr('\r', mbp); + } + } +} +#endif /* L1TCPIP */ + +/* + * + * Host-User in Tabellenform anzeigen: + * + * CH Call F NT RX TX ST RxB TxB Baud ConTime + * ------------------------------------------------------------------------- + * 03 DB0IL-3 CD 7199 1 0 0 65 1494 120 0:02:05 + * 05 DB0IL-5 C 7086 0 0 0 51 595 56 0:02:05 + * 06 OZ5BBS-1 C 7068 0 0 0 7620 1598 96 0:09:37 + * / / / / / / / / / / / + * 1) 2) 3) 4) 5) 6) 7) 8) 9) 10) 11) + * + * 1) Hostmode-Kanal + * 2) Rufzeichen des Users (Connect vom User) oder eigenes Call (Connect + * vom Host zum Knoten) + * 3) Hostmode-Flags + * C = Connected + * D = Disconnecten wenn Info uebertragen + * 4) Noactivity-Timer + * 5) empfangene Frames in Warteschlange + * 6) zu sendende Frames in Warteschlange + * 7) Statusmeldungen in Warteschlange + * 8) Anzahl empfangender Bytes seit Bestehen des Links + * 9) Anzahl gesendetet Bytes seit Bestehen des Links + * 10) Aus 8) + 9) + 11) errechnete effektive Baudrate fuer diesen Link + * 11) Connectzeit + * + */ + +static void +hostuser(MBHEAD *mbp, WORD what, const char *pstr) +{ + HOSTUS *hp; + int i; + char str[10]; + PTCENT *ptcp; + BOOLEAN first = TRUE; + + for (hp = hstubl + 1, i = 1; i < MAXHST; ++hp, ++i) + { + if ( (!hp->conflg) + && (!hp->disflg) + && (cmpid(hp->call, hostid)) + ) + continue; + switch (what) + { + case USE_ALL : break; + case USE_MASK : if (!c6mtch(hp->call, pstr)) continue; + break; + case USE_CALL : if (!cmpid(hp->call, pstr)) continue; + break; + } + call2str(str, hp->call); + if (first) + { +#ifdef SPEECH + putstr(speech_message(149), mbp); +#else + putstr("\rHost-User:\r" + "CH Call F NT RX TX ST RxB TxB Baud ConTime\r" + "-------------------------------------------------------------------------\r", mbp); +#endif + first = FALSE; + } + putprintf(mbp, "%02ld %-9.9s %c%c %5u %5u %5u %5u ", + hp - hstubl, str, (hp->conflg ? 'C':' '), + (hp->disflg ? 'D':' '), hp->noacti, hp->inlin, + hp->outlin, hp->outsta); + ptcp = ptctab + g_uid(hp, HOST_USER); + putptcinfo(ptcp, mbp); + putchr('\r', mbp); + } +} + +/************************************************************************/ +/* Time */ +/*----------------------------------------------------------------------*/ +void ccptim(void) +{ +#ifdef MC68K + UWORD t1, t2, t3; + char t4; + struct tm *tim; +#endif + MBHEAD *mbp; + +#ifdef MC68K + if (issyso()) { + t1 = nxtnum(&clicnt, &clipoi); + t4 = *clipoi++; + clicnt--; + t2 = nxtnum(&clicnt, &clipoi); + clipoi++; + clicnt--; + t3 = nxtnum(&clicnt, &clipoi); + if (t4 == '.') { + if (t1 <= 31 && t2 <= 12 && t3 <= 99) { + if (t3 < 92) + t3 += 100; + tim = localtime(&sys_time); + tim->tm_mday = t1; + tim->tm_mon = t2 - 1; + tim->tm_year = t3; + sys_time = mktime(tim); + stime(&sys_time); + } + } + if (t4 == ':') { + if (t1 <= 23 && t2 <= 59 && t3 <= 59) + { + tim = localtime(&sys_time); + tim->tm_hour = t1; + tim->tm_min = t2; + tim->tm_sec = t3; + sys_time = mktime(tim); + stime(&sys_time); + } + } + } +#endif + mbp = putals("Time: "); + puttim(&sys_time, mbp); + putstr(" (", mbp); + putlong(tic10, FALSE, mbp); + putstr(")\r", mbp); + prompt(mbp); + seteom(mbp); +} + +/************************************************************************/ +/* CLEAR : Loeschen der Statistiken */ +/*----------------------------------------------------------------------*/ +void +ccpclr(void) +{ + register int i; + STAT *statp; + char call[L2IDLEN]; + char viacall[L2IDLEN]; + + if (issyso()) + { + memset(portstat, 0, sizeof(portstat)); + + for (i = 0, statp = mh; i < MAXSTAT; ++i, statp++) + { +/* Rufzeichen und via-Rufzeichen beibehalten, Start-Zeit setzen */ + cpyid(call, statp->call); + cpyid(viacall, statp->viacall); + memset(statp, 0, sizeof(STAT)); + cpyid(statp->call, call); + cpyid(statp->viacall, viacall); + statp->hfirst = sys_time; + } + for (i = 3; i <= 19; ++i) + if (i != 13) /* Timeout nicht ruecksetzen */ + Ip_mib[i].value.integer = 0; + + l1sclr("*"); + + time(&clear_time); +#ifdef SPEECH + putmsg(speech_message(192)); +#else + putmsg("Statistic-table cleared!\r"); +#endif + userpo->sysflg = 2; + } + else + invmsg(); +} + +/************************************************************************/ +/* percent */ +/* int comma: gibt an wieviele Nachkommastellen berechnet werden sollen */ +/*----------------------------------------------------------------------*/ +static void +percent (ULONG zaehler, ULONG nenner, int comma, int space, MBHEAD *mbp) +{ + int i, zaehlernull; + char resultstr[32]; + + resultstr[0] = NUL; + zaehlernull = 0; + if (nenner == 0) + { + zaehler = 0L; + nenner = 1L; + } + + if (zaehler / nenner != 0) + sprintf(resultstr, "%s%lu", resultstr, zaehler / nenner); + else + zaehlernull = 1; + zaehler = (zaehler % nenner) * 10; + + if (zaehlernull != 1 || zaehler / nenner != 0) + sprintf(resultstr, "%s%lu", resultstr, zaehler / nenner); + zaehler = (zaehler % nenner) * 10; + + sprintf(resultstr, "%s%lu", resultstr, zaehler / nenner); + zaehler = (zaehler % nenner) * 10; + if (comma > 0) + strcat(resultstr, "."); + + for (i = 0 ; i < comma; i++) + { + sprintf(resultstr, "%s%lu", resultstr, zaehler / nenner); + zaehler = (zaehler % nenner) * 10; + } +/* String mit space Angabe formatieren */ + putprintf(mbp, "%*s%%", space, resultstr); + return; +} + +/************************************************************************/ +/* Statistik-Befehl */ +/* Syntax: S + nimmt ein neues Call in die Statistik */ +/* auf */ +/* S - loescht ein Call aus der Statistik */ +/* S p zeigt nur die Port-Statistik */ +/* S e zeigt nur die Fehler-Statistik */ +/* S l zeigt nur die Link-Statistik */ +/* S h zeigt nur die Hardware-Statistik */ +/* S i zeigt nur die IP-statistik */ +/* S zeigt nur die System-Statistik */ +/* S * zeigt alles */ +/*----------------------------------------------------------------------*/ +void +ccpsta(void) +{ + MBHEAD *mbp; + STAT *statp; + WORD i, j; + char call[L2IDLEN], viacall[L2IDLEN]; + ULONG summe, /* Gesamter Datendurchsatz in KBytes */ + offset; +#ifndef CONNECTTIME + LONG upt, upd, uph; +#endif /* CONNECTTIME */ + PORTSTAT *pstatp; + PORTINFO *portp; + ULONG rxoverhead = 0L, txoverhead = 0L; + ULONG trxframes[2]; + int ch; +#define PORTSTATFLAG 1 /* Die Reihenfolge muss mit chars */ +#define ERRORSTATFLAG 2 /* uebereinstimmen */ +#define LINKSTATFLAG 4 +#define HARDWAREFLAG 8 +#define IPSTATFLAG 16 +#define KERNELFLAG 32 +#define STATFLAG 64 /* kein oder falscher parameter */ + int flag = 0; +#ifndef KERNELIF + const char *chars = "PELHI", *cp; +#else + const char *chars = "PELHIK", *cp; +#endif + + mbp = getmbp(); + + skipsp(&clicnt, &clipoi); + ch = toupper(*clipoi); + + for (cp = chars, i = 1; *cp; cp++, i <<= 1) + if (ch == *cp) flag |= i; + + if (ch == '*') + flag = (~0); /* Monats-Statistik (alles) */ + + if (flag == 0) + flag |= STATFLAG; + + if (issyso()) + { +/******* Delete Call from Statistics ************************************/ + if (ch == '-') + { + clipoi++; + clicnt--; + + if (getcal(&clicnt, &clipoi, FALSE, call) == YES) + { + if (getcal(&clicnt, &clipoi, TRUE, viacall) == YES) + { + for (statp = mh, j = 0; j < MAXSTAT; statp++, j++) + if ( cmpid(statp->call, call) + && cmpid(statp->viacall, viacall)) + { + statp->call[0] = NUL; + statp->viacall[0] = NUL; + } + } + else /* Kein oder falsches via Rufzeichen */ + { + for (statp = mh, j = 0; j < MAXSTAT; statp++, j++) + if ( cmpid(statp->call, call) + && !*statp->viacall) + { + statp->call[0] = NUL; + statp->viacall[0] = NUL; + } + } + } + flag |= LINKSTATFLAG; + } + +/******** Add Call to Statistics ****************************************/ + if (*clipoi == '+') + { + clipoi++; + clicnt--; + +/************************************************************************/ +/* Wenn das Call schon in der Statistik steht, dann tragen wir es nicht */ +/* nochmal ein. Rufzeichen und Via Rufzeichen duerfen nicht gleich */ +/* sein. Das Zeichen "*" ist nur erlaubt, wenn ein korrektes Via- */ +/* Rufzeichen mitangegeben wird. */ +/************************************************************************/ + + if (getcal(&clicnt, &clipoi, FALSE, call) == YES) +/* Es ist ein "*" oder ein gueltiges Rufzeichen */ + if (cmpid(call, anycall) || fvalca(call) == YES) + { + if ( getcal(&clicnt, &clipoi, TRUE, viacall) == YES + && !cmpid(call, viacall)) + { + for (statp = mh, j = 0; j < MAXSTAT; statp++, j++) + if ( cmpid(statp->call, call) + && cmpid(statp->viacall, viacall)) + break; + } + else /* Kein oder falsches Via-Rufzeichen */ + { + viacall[0] = NUL; + for (statp = mh, j = 0; j < MAXSTAT; statp++, j++) + { +/* "*" ohne Via-Rufzeichen nicht zulassen */ + if (cmpid(call, anycall)) + break; +/* Rufzeichen (ohne via) schon gefunden, kein Eintrag noetig */ + if (cmpid(statp->call, call) && !*statp->viacall) + break; + } + } + + if (j >= MAXSTAT) + { + for (statp = mh, j = 0; j < MAXSTAT; statp++, j++) + if (!*statp->call) + { + memset(statp, 0, sizeof(STAT)); + cpyid(statp->call, call); + cpyid(statp->viacall, viacall); + statp->hfirst = sys_time; + statp->hlast = sys_time; + userpo->sysflg = 2; + break; + } + } + } + flag |= LINKSTATFLAG; + } + } + summe = 0L; + +/********** Show System Statistics **************************************/ +#ifdef SPEECH + putstr(speech_message(151), mbp); /* aktuelle Uhrzeit */ +#else + putstr("\r System Statistics: ", mbp); /* aktuelle Uhrzeit */ +#endif + puttim(&clear_time, mbp); + putstr(" - ", mbp); + puttim(&sys_time, mbp); +#ifdef SPEECH + putstr(speech_message(152), mbp); /* Startzeit */ +#else + putstr("\r Startup: ", mbp); /* Startzeit */ +#endif + puttim(&start_time, mbp); + +#ifndef CONNECTTIME + upt = sys_time - start_time; /* Uptime in seconds */ + upd = upt / SECONDS_PER_DAY; /* Uptime days */ + upt %= SECONDS_PER_DAY; + uph = upt / SECONDS_PER_HOUR; /* Uptime hours */ + upt %= SECONDS_PER_HOUR; + + putprintf(mbp, "\r Uptime:%9ld/%02ld:%02ld\r", + upd, uph, upt / SECONDS_PER_MIN); +#else /* CONNECTTIME */ + putprintf(mbp, "\r Runtime: %s", ConnectTime(tic10 / 100)); +#endif /* CONNECTTIME */ + + if (flag & STATFLAG) + { +#ifdef SPEECH + putprintf(mbp, speech_message(177), + rounds_min_sec, rounds_pro_sec, rounds_max_sec); +#else + putprintf(mbp, "\r (min) (now) (max)\r" + " Rounds/sec: %8lu %8lu %8lu\r", + rounds_min_sec, rounds_pro_sec, rounds_max_sec); +#endif +#ifdef SPEECH + putprintf(mbp, speech_message(178), + nmbfre_min, nmbfre, nmbfre_max, + thbps * 8L, thbps_max * 8L, + nmblks, nmblks_max, + nmbcir, nmbcir_max, + netp->num_nodes, + num_nodes_max); +#else + putprintf(mbp, " Free Buffers: %8u %8u %8u\r" + "Overall Throughput:%18lu %8lu Baud\r" + " Active L2-Links:%18u %8u\r" + " Active Circuits:%18u %8u\r" + " Active Nodes:%18u %8u\r", + nmbfre_min, nmbfre, nmbfre_max, + thbps * 8L, thbps_max * 8L, + nmblks, nmblks_max, + nmbcir, nmbcir_max, + netp->num_nodes, + num_nodes_max); +#endif +#ifdef L1TCPIP + putprintf(mbp, "\r Active Socket:%18u %8u\r" + ,nmbtcp, nmbtcp_max); +#endif /* L1TCPIP */ + +#ifdef __LINUX__ + print_load (mbp); + if (nmbfre_max) +#ifdef SPEECH + putprintf(mbp, speech_message(180), + 100 - (((ULONG)nmbfre) * 100L) / ((ULONG)nmbfre_max)); +#else + putprintf(mbp, "\r Buffer usage: %lu%%", + 100 - (((ULONG)nmbfre) * 100L) / ((ULONG)nmbfre_max)); +#endif +#ifdef SPEECH + putprintf(mbp, speech_message(181), + sizeof(NETWORK) + (ULONG)netp->num_peers * (sizeof(PEER) + + (ULONG)netp->max_nodes * sizeof(ROUTE))); +#else + putprintf(mbp, "\r Network Heap: %lu Bytes", + sizeof(NETWORK) + (ULONG)netp->num_peers * (sizeof(PEER) + + (ULONG)netp->max_nodes * sizeof(ROUTE))); +#endif + putprintf(mbp, "\r Console: "); + switch (console_type) + { + case CONS_NO_CONSOLE: putprintf(mbp, "no console\r"); break; + + case CONS_TERM_DO_SETUP: + case CONS_TERM_RUNNING: putprintf(mbp, "terminal\r"); break; + + case CONS_SOCKET_DO_SETUP: putprintf(mbp, "unix socket (setting up)\r"); break; + case CONS_SOCKET_WAITING: putprintf(mbp, "unix socket (waiting)\r"); break; + case CONS_SOCKET_CONNECTED: putprintf(mbp, "unix socket (connected)\r"); break; + + default: putprintf(mbp, "unknown\r"); break; + } +#else + if (rounds_max_sec) +#ifdef SPEECH + putprintf(mbp, speech_message(182), + 100 - (((ULONG)rounds_pro_sec) * 100L) / ((ULONG)rounds_max_sec)); +#else + putprintf(mbp, "\r CPU load: %lu%%", + 100 - (((ULONG)rounds_pro_sec) * 100L) / ((ULONG)rounds_max_sec)); +#endif + if (nmbfre_max) +#ifdef SPEECH + putprintf(mbp, speech_message(180), + 100 - (((ULONG)nmbfre) * 100L) / ((ULONG)nmbfre_max)); +#else + putprintf(mbp, "\r Buffer usage: %lu%%", + 100 - (((ULONG)nmbfre) * 100L) / ((ULONG)nmbfre_max)); +#endif +#ifdef SPEECH + putprintf(mbp, speech_message(181), + sizeof(NETWORK) + (ULONG)netp->num_peers * (sizeof(PEER) + + (ULONG)netp->max_nodes * sizeof(ROUTE))); +#else + putprintf(mbp, "\r Network Heap: %lu Bytes\r", + sizeof(NETWORK) + (ULONG)netp->num_peers * (sizeof(PEER) + + (ULONG)netp->max_nodes * sizeof(ROUTE))); +#endif +#endif + } + +/********** Show Port Statistics ****************************************/ + if (flag & PORTSTATFLAG) + { + +/******************** number of byte rx/tx per port *********************/ + summe = + offset = 0L; + +#ifdef SPEECH + putstr(speech_message(153), mbp); +#else + putstr("\r\r Port-Statistics:\r\r" + " Links RxB TxB RxBaud" + " TxBaud RxOver TxOver\r", mbp); +#endif + + for (i = 0, pstatp = portstat, portp = portpar; + i < L2PNUM; + i++, pstatp++, portp++) + { + if (portenabled(i)) + { + putprintf(mbp, "%2u:%-10s%3u/%-3u ", i, portp->name, + portp->nmblks, + portp->nmbstn); + put_kMG(mbp, pstatp->rx_bytes); + putchr(' ', mbp); + put_kMG(mbp, pstatp->tx_bytes); + putchr(' ', mbp); + put_kMG(mbp, pstatp->rx_baud*8L); + putchr(' ', mbp); + put_kMG(mbp, pstatp->tx_baud*8L); + if (pstatp->rx_bytes / 100L) + { + rxoverhead = pstatp->rx_overhead / (pstatp->rx_bytes / 100L); + if (rxoverhead > 99) + rxoverhead = 100; + putprintf(mbp, " %3lu%%", rxoverhead); + } + else + if (pstatp->tx_bytes / 100L) + putstr(" ", mbp); + if (pstatp->tx_bytes / 100L) + { + txoverhead = pstatp->tx_overhead / (pstatp->tx_bytes / 100L); + if (txoverhead > 99) + txoverhead = 100; + putprintf(mbp, " %3lu%%", txoverhead); + } + putchr(CR, mbp); + summe += (pstatp->rx_bytes + pstatp->tx_bytes); + while (summe > 999999L) + { + offset++; + summe -= 1000000L; + } + } + } +#ifdef SPEECH + putstr(speech_message(154), mbp); +#else + putstr("\rTotal = ", mbp); +#endif +/* wird noch erweitert, gilt noch nicht fuer die einzelnen Ports, die */ +/* koennen weiterhin nur bis 4.2GB zaehlen */ + put_pktnum(mbp, offset, summe); +#ifdef SPEECH + putstr(speech_message(155), mbp); +#else + putstr(" Bytes\r", mbp); +#endif +} + +/************* Fehler-Statistik *****************************************/ + if (flag & ERRORSTATFLAG) + { +#ifdef SPEECH + putstr(speech_message(156), mbp); +#else + putstr("\r Error-Statistics:\r\r" + " RxID RxLen RxCtl Resets\r", mbp); +#endif + + for (i = 0, pstatp = portstat, portp = portpar; + i < L2PNUM; + i++, pstatp++, portp++) + { + if (portenabled(i)) + { + putprintf(mbp, "%2u:%-10s ", i, portp->name); + for (j = 0; j < 3; j++) + putprintf(mbp, "%6u ", pstatp->invalid[j]); + putprintf(mbp, "%6u\r", pstatp->reset_count); + } + } + } + + if (flag & HARDWAREFLAG) + l1stat("*", mbp); + +#ifdef KERNELIF +/************* Show Kernel Link Statistics ********************************/ + if (flag & KERNELFLAG) + ifip_dispstat(mbp); +#endif + +/************* Show Link Statistics *************************************/ + if (flag & LINKSTATFLAG) + { +#ifdef SPEECH + putstr(speech_message(157), mbp); +#else + putstr("\rLink-Statistics:\r", mbp); +#endif + for (i = MAXSTAT, statp = mh; i--; statp++) + { + if (*statp->call) + { + mbp->l4time = mbp->mbpc; +#ifdef SPEECH + putstr(speech_message(158), mbp); +#else + putstr("\rLink to ", mbp); +#endif + putid(statp->call, mbp); + if (*statp->viacall) + { +#ifdef SPEECH + putstr(speech_message(159), mbp); +#else + putstr(" via ", mbp); +#endif + putid(statp->viacall, mbp); + } + putspa(35, mbp); + puttim(&statp->hfirst, mbp); + if (statp->hlast > 0) + { + putstr(" - ", mbp); + puttim(&statp->hlast, mbp); + } +#ifdef SPEECH + putstr(speech_message(160), mbp); +#else + putstr("\rFrames: I UI RR REJ " + "RNR SABM/UA DISC/DM FRMR\r", mbp); +#endif + for (j = 0; j < 2; j++) + putprintf(mbp, "%s:%11lu%11lu%11lu%10lu%9lu%9lu%9lu%5lu\r", + (j == 0) ? "RX" : "TX", + statp->Ino[j], + statp->UIno[j], + statp->RRno[j], + statp->REJno[j], + statp->RNRno[j], + statp->SABMno[j] + statp->UAno[j], + statp->DISCno[j] + statp->DMno[j], + statp->FRMRno[j]); +#ifdef SPEECH + putstr(speech_message(161), mbp); +#else + putstr("Bytes: Total Info Header Overhead %I " + "%RR %REJ %RNR\r", mbp); +#endif + for (j = 0; j < 2; j++) + { + trxframes[j] = statp->Ino[j] + statp->UIno[j] + statp->RRno[j] + + statp->REJno[j] + statp->RNRno[j] + statp->SABMno[j] + + statp->UAno[j] + statp->DISCno[j] + statp->DMno[j] + + statp->FRMRno[j]; + putprintf(mbp, "%s:%11lu%11lu%11lu", + (j == 0) ? "RX" : "TX", + statp->Bytetotal[j], + statp->Bytetotal[j] - statp->Byteheader[j], + statp->Byteheader[j]); + percent(statp->Byteheader[j], statp->Bytetotal[j], 1, 9, mbp); + percent(statp->Ino[j], trxframes[j], 1, 7, mbp); + percent(statp->RRno[j], trxframes[j], 1, 7, mbp); + percent(statp->REJno[j], trxframes[j], 1, 7, mbp); + percent(statp->RNRno[j], trxframes[j], 1, 7, mbp); + putchr(CR, mbp); + } + txoverhead = (statp->Bytetotal[1] - statp->Byteheader[1]) + - statp->txByterepeated; +#ifdef SPEECH + putprintf(mbp, speech_message(183), + txoverhead, + statp->txByterepeated); +#else + putprintf(mbp, "TX: Once:%11lu Repeated:%10lu IQual:", + txoverhead, + statp->txByterepeated); +#endif + percent(txoverhead, statp->Bytetotal[1] - statp->Byteheader[1], + 1, 7, mbp); +#ifdef SPEECH + putstr(speech_message(162),mbp); +#else + putstr(" TQual:",mbp); +#endif + percent(txoverhead,statp->Bytetotal[1], 1, 7, mbp); + putchr(CR, mbp); + } + } + } + +#ifdef IPROUTE +/************* Show IP-Gateway Statistics *******************************/ + if (flag & IPSTATFLAG) + { +#ifdef SPEECH + putstr(speech_message(163), mbp); +#else + putstr("\rIP-Gateway-Statistics:\r\r", mbp); +#endif + for (i = 1; i <= NUMIPMIB; ) + { + mbp->l4time = mbp->mbpc; + for (j = 0; j < 3 && i <= NUMIPMIB; j++, i++) + { +#ifdef __WIN32__ + putspa((char)(26 * j), mbp); +#else + putspa(26 * j, mbp); +#endif /* WIN32 */ + putstr(Ip_mib[i].name, mbp); + putchr(':', mbp); +#ifdef __WIN32__ + putspa((char)(26 * j + 19), mbp); +#else + putspa(26 * j + 19, mbp); +#endif /* WIN32 */ + putnum(Ip_mib[i].value.integer, mbp); + } + putchr(CR, mbp); + } + putchr(CR, mbp); + } +#endif + + putchr(CR, mbp); + prompt(mbp); + seteom(mbp); +} + +/************************************************************************/ +/* Test-Command */ +/*----------------------------------------------------------------------*/ +void ccptst(void) +{ + MBHEAD *mbp; + WORD port; + + if (issyso()) /* Bin ich Sysop? */ + { + if ((port = (char) nxtnum(&clicnt, &clipoi)) >= L2PNUM) + { +#ifdef SPEECH + putmsg(speech_message(193)); +#else + putmsg("\rInvalid Port\r"); +#endif + return; + } + + if (!portenabled(port)) /* Port nicht eingeschaltet */ + { +#ifdef SPEECH + putmsg(speech_message(345)); +#else + putmsg("\rCan't send, Port is disabled\r"); +#endif + return; + } + + l1ctl(L1CTST, port); + mbp = putals("Sending test on Port "); + putnum(port, mbp); + putchr('\r', mbp); + prompt(mbp); + seteom(mbp); + } + else + invmsg(); +} + +/************************************************************************/ +/* Version-Command */ +/*----------------------------------------------------------------------*/ +void ccpver(void) +{ + MBHEAD *mbp; /* message-buffer-pointer */ + + mbp = putals(version); /* Versionskennung zeigen */ +#ifdef SPEECH + putprintf(mbp,speech_message(184), L2PNUM, LINKNMBR, NUMCIR,author); +#else + putprintf(mbp," Copyright by NORD>max_peers; + const char *cp; +#ifdef LINKSMODINFO + char info[INFOSIZE + 1]; +#endif /* LINKSMODINFO */ + + mbp = getmbp(); + + /* nur Neueintraege als Sysop und wenn noch was in der Kommandozeile da ist */ + if (issyso() && clicnt > 0) + { + mode = *clipoi; /* Modus bestimmen (+ oder -) */ + clipoi++; + clicnt--; + skipsp(&clicnt, &clipoi); + typ[0] = toupper(*clipoi); /* Linktyp holen (N I F usw.) */ + clipoi++; + clicnt--; + if (*clipoi != ' ') /* Linkzusatz holen (+ oder -) wenn vorhanden */ + { + typ[1] = *clipoi++; + clicnt--; + } + +#ifdef PROXYFUNC + skipsp(&clicnt, &clipoi); + if ( (typproxy = ((*clipoi == 'P' || *clipoi == 'p') && *(clipoi+1) == ' ' ) ? TRUE : FALSE) == TRUE) { + clipoi++; + clicnt--; + } +#endif + if ((port = (UWORD) nxtnum(&clicnt, &clipoi)) < L2PNUM) + { + skipsp(&clicnt, &clipoi); + + if (strchr((char *)clipoi, ':')) + *strchr((char *)clipoi, ':') = ' '; + + if (getide(&clicnt, &clipoi, ident) == YES) + { + skipsp(&clicnt, &clipoi); + if ((getcal(&clicnt, &clipoi, TRUE, call)) == YES) + { + getdig(&clicnt, &clipoi, TRUE, digil); + digil[2*L2IDLEN] = NUL; + +#ifdef LINKSMODINFO + /* Frischer Buffer. */ + memset(info, 0, sizeof(info)); + + /* Pruefe, ob es weiter Zeichen gibt. */ + if (skipsp(&clicnt, &clipoi)) + { + char *infotext; + + if ((infotext = strchr(clipoi, '=')) != NULL) + { + /* Zeichen "=" loeschen. */ + infotext++; + + /* Stations-Beschreibung speichern. */ + strncpy(info, infotext, INFOSIZE); + } /* kein "=" enthalen. */ + } /* keine weiteren Zeichen im Buffer. */ +#endif /* LINKSMODINFO */ + + for (cp = typtbl; *cp; cp += 2) + if ((cp[0] == typ[0]) && (cp[1] == typ[1])) /* Typ stimmt */ + typs = ((int)(cp-typtbl))/2; + +#ifdef LINKSMODROUTINGTYP + if ( (typs == NETROM) /* NETROM-TYP */ + &&(typs == (mode == '+'))) /* und soll eingetragen werden, */ + { /* nicht zulassen!!! */ + putstr("None Routing-Typ indicated.\r", mbp); + prompt(mbp); /* Zum Prompt zurueck. */ + seteom(mbp); + return; + } +#endif /* LINKSMODROUTINGTYP */ + if (mode == '+') + { +#ifdef PROXYFUNC + typs = typproxy ? typs+PROXYMASK : typs; +#endif + pp = register_neigb(call, digil, ident, port, typs +#ifdef LINKSMODINFO + ,info +#endif /* LINKSMODINFO */ +#ifdef AUTOROUTING + ,FIXED_ROUTE /* Link ist immer Fest. */ +#endif /* AUTOROUTING */ +); + if (!portenabled(port)) +#ifdef SPEECH + putstr(speech_message(166), mbp); +#else + putstr("Warning - Port not active.\r", mbp); +#endif +#ifdef LINKSMOD_MSG + if (pp != NULL) /* Linkpartner erfolgreich eingetragen. */ + { + putstr("Link is registered.\r", mbp); + prompt(mbp); /* Zum Prompt zurueck. */ + seteom(mbp); + return; + } +#endif /* LINKSMOD_MSG. */ + } + + if (mode == '-') +#ifdef LINKSMOD_MSG + { + if (unregister_neigb(call, digil, port)) /* Link austragen. */ + { +#ifdef AXIPR_HTML + /* Protokoll fuer HTML-Ausgabe setzen. */ + SetHTML(port, call, NULL, FALSE); +#endif /* AXIPR_HTML */ + + putstr("Link is deleted.\r", mbp); + prompt(mbp); /* Und zum Prompt zurueck. */ + seteom(mbp); + return; + } + } +#else + unregister_neigb(call, digil, port); +#endif /* LINKSMOD_MSG. */ + + } /* if (getcal(&clicnt ... */ + else /* Call war nicht ok */ + { +#ifdef SPEECH + putstr(speech_message(167), mbp); +#else + putstr("Invalid callsign.\r", mbp); +#endif + prompt(mbp); + seteom(mbp); + return; + } + } /* if (ident_ok... */ + else /* Ident ist nicht ok (enthaelt ungueltige Zeichen etc.) */ + { +#ifdef SPEECH + putstr(speech_message(168), mbp); +#else + putstr("Invalid ident.\r", mbp); +#endif + prompt(mbp); + seteom(mbp); + return; + } + } /* if (port = nxtnum(&clicnt, &clipoi) < L2PNUM) */ + /* putstr("Syntax: L +/- TYP PORT ALIAS:CALL[-*] [Digi1 [Digi2]]\r", mbp);*/ + } /* if (sysop... */ + +#ifdef LINKSMODSYNTAXFIX + /* Nur Sysop's duerfen die Syntax sehen. */ + if (issyso()) + putstr("Syntax: L +/- TYP PORT ALIAS:CALL[-*] [Digi1 [Digi2]] [INFO=]\r", mbp); +#endif /* LINKSMODSYNTAXFIX */ + + putstr("Links of ", mbp); /* Konfiguration zeigen */ + putalt(alias, mbp); + putid(myid, mbp); + putprintf(mbp, " (%d/%d)\r", netp->num_peers, netp->max_peers); + +#ifndef LINKSMODINFO + putstr("Type-Port--Alias:Call------Route--------------\r", mbp); +#else + putstr("Type-Port--Alias:Call------Route--------------Info------------------------\r", mbp); +#endif /* LINKSMODINFO */ + + for (i = 0, pp = netp->peertab; i < max_peers; i++, pp++) + if (pp->used) { + mbp->l4time = mbp->mbpc; /* Zaehler merken fuer putspa() */ + +#ifdef LINKSMOD_LOCALMOD + if ( (pp->typ == LOCAL_V) /* Local-Link versteckt. */ + &&(!issyso())) /* und kein Sysop. */ + continue; /* Zum naechsten Eintrag. */ +#endif /* LINKSMOD_LOCALMOD */ + +#ifdef PROXYFUNC + putprintf (mbp, "%2.2s %c", typtbl + pp->typ*2 , pp->proxy ? 'P' : ' '); +#else + putspa(2, mbp); + putprintf (mbp, "%2.2s", typtbl + pp->typ*2); +#endif + putspa(6, mbp); + if (pp->l2link->port < 10) putchr(' ', mbp); + putnum(pp->l2link->port, mbp); + putstr(" ", mbp); + putide(pp->l2link->alias, mbp); + putchr(':', mbp); + putid(pp->l2link->call, mbp); + via = pp->l2link->digil; /* nicht putdil() wegen "via" */ + if (via[0]) + { + putspa(27, mbp); + putid(via, mbp); + if (via[L2IDLEN]) + { + putchr(' ', mbp); + putid(via+L2IDLEN, mbp); + } + } +#ifdef LINKSMODINFO + /* Ab spalte 46. */ + putspa(46, mbp); + /* Stations-Beschreibung ausgeben. */ + putprintf(mbp, "%s",pp->l2link->info, mbp); +#endif /* LINKSMODINFO */ + putchr('\r', mbp); + } + + prompt(mbp); + seteom(mbp); +} + +/************************************************************************/ +/* Quit-Command */ +/*----------------------------------------------------------------------*/ +void ccpquit(void) +{ + MBHEAD *mbp; + char name[MAXPATH]; + + mbp = getmbp(); + + /* Gibt es eine QUIT.TXT ? */ + if (xaccess("QUIT.TXT", 0) == 0) + { + /* Markiere Path/Datei. */ + sprintf(name, "%sQUIT.TXT", textpath); + /* Gibt es Makros, diese ausfuehren. */ + out_ctext(name, mbp); + } + else + { + putstr("\r73 de ", mbp); + putid(myid, mbp); + } + + putchr('\r', mbp); + seteom(mbp); + disusr(userpo->uid); +} + + +/************************************************************************/ +/* */ +/* ECHO Befehl */ +/* */ +/* Funktion : Rest der Eingabezeile des Users zurueck schicken. */ +/* Anwendung z.B. fuer RTT Messung. */ +/* */ +/* Syntax : //E */ +/* */ +/*----------------------------------------------------------------------*/ +void ccpecho(void) { + MBHEAD *mbp; + + mbp = getmbp(); + if (clicnt > 0 && !strnicmp(clilin, "//E", 3)) { + putchr('\r', mbp); + while (clicnt > 0) { + putchr(*clipoi++, mbp); + clicnt--; + } + putchr('\r', mbp); + } + prompt(mbp); + seteom(mbp); +} + +/************************************************************************/ +/* */ +/* TALK Befehl */ +/* */ +/* Funktion : Nachricht an einen anderen User schicken, der im CCP und */ +/* nicht anderweitig connected ist! */ +/* Syntax : TALK */ +/* Ausgabe : Msg from : */ +/*----------------------------------------------------------------------*/ +void ccptalk(void) +{ + char tmp[8]; + WORD suc; + MBHEAD *mbp; + char call[L2IDLEN]; + + if (skipsp(&clicnt, &clipoi)) { /* steht da was? */ + if (!strnicmp((char *)clipoi, "ALL", 3)) { /* an alle? */ + nextspace(&clicnt, &clipoi); + if (skipsp(&clicnt, &clipoi) == FALSE) { /* kein Text? */ +#ifdef SPEECH + putmsg(speech_message(195)); +#else + putmsg("No Text\r"); +#endif + return; + } + call[0] = '*'; + suc = talk_to(call, 0); /* weiterpetzen */ + } else + if (getcal(&clicnt, &clipoi, TRUE, call) == YES) { /* ein call ? */ + if (skipsp(&clicnt, &clipoi)) { /* kommtn Text? */ + suc = talk_to(call, 0); /* weiterpetzen */ + } else { + suc = talk_to(call, 1); /* gibs den? */ + mbp = getmbp(); + if (suc) { + cpyid(userpo->talkcall, call); /* call merken */ + userpo->status = US_TALK; + callss2str(tmp, call); +#ifdef SPEECH + putprintf(mbp, speech_message(185), tmp); +#else + putprintf(mbp, "You are now talking with %s. Leave this mode with /q\r", tmp); +#endif + } else { +#ifdef SPEECH + putstr(speech_message(172), mbp); +#else + putstr("No such User!\r", mbp); +#endif + prompt(mbp); /* Prompt dran */ + } + seteom(mbp); /* fertig */ + return; + } + } else { +#ifdef SPEECH + putmsg(speech_message(196)); +#else + putmsg("Invalid Call\r"); +#endif + return; + } +#ifdef SPEECH + putmsg(suc ? speech_message(197) : speech_message(198)); +#else + putmsg(suc ? "Msg sent\r" : "No User\r"); +#endif + } else +#ifdef SPEECH + putmsg(speech_message(199)); +#else + putmsg("No Arguments\r"); +#endif +} + +static BOOLEAN talk_to(char *call, WORD test) +{ + char tmp[8]; + WORD cnt = 0; + USRBLK *save_userpo = userpo; + MBHEAD *mbp; + + callss2str(tmp, calofs(UPLINK, userpo->uid)); + strlwr(tmp); + + for (userpo = (USRBLK *) usccpl.head; + userpo != (USRBLK *) &usccpl; + userpo = (USRBLK *) userpo->unext) + { + if ( userpo->convers == NULLCONNECTION + && ( userpo->status == US_CCP + || userpo->status == US_TALK) + && userpo != save_userpo + && ( cmpcal(calofs(UPLINK, userpo->uid), call) + || call[0] == '*')) { + if (test) { + userpo = save_userpo; + return(TRUE); + } + mbp = getmbp(); + + /* String zu lang? */ + if (clicnt > 214) + { + /* Aktuellen user setzen. */ + userpo = save_userpo; + /* Der String ist zu lang, abbruch. */ + return(TRUE); + } + +#ifdef SPEECH + putprintf(mbp, speech_message(186), tmp, clipoi); +#else + putprintf(mbp, "Msg from %s (use TALK to reply): %s\r", tmp, clipoi); +#endif + seteom(mbp); + if (call[0] != '*') { + userpo = save_userpo; + return(TRUE); + } + cnt++; + } + } + userpo = save_userpo; + return(cnt ? TRUE : FALSE); +} + +/************************************************************************/ +/* Mailbox-Befehl */ +/************************************************************************/ +void ccpmail(void) +{ + if (issyso() && skipsp(&clicnt, &clipoi)) { + ccp_call(boxid); /* Rufzeichen setzen */ + } else { /* Connect zur Mailbox */ + if (boxid[0]) { + call2str((char *)(clipoi = clilin), boxid); + clicnt = strlen((char *)clipoi); + ccpcon(NULL); + } else +#ifdef SPEECH + putmsg(speech_message(200)); +#else + putmsg("No mailbox!\r"); +#endif + } +} + +/************************************************************************/ +/* DXCluster-Command */ +/*----------------------------------------------------------------------*/ +void ccpdxc(void) +{ + if (issyso() && skipsp(&clicnt, &clipoi)) { + ccp_call(dxcid); /* Rufzeichen setzen */ + } else { /* Connect zur Mailbox */ + if (dxcid[0]) { + call2str((char *)(clipoi = clilin), dxcid); + clicnt = strlen((char *)clipoi); + ccpcon(NULL); + } else +#ifdef SPEECH + putmsg(speech_message(201)); +#else + putmsg("No DX-Cluster!\r"); +#endif + } +} + +#ifdef HOSTMYCALL +/************************************************************************/ +/* */ +/* Consolen-Mycall setzen. */ +/* */ +/************************************************************************/ +void ccpmyhost(void) +{ + MBHEAD *mbp; + + if (issyso()) /* Nur Sysop darf aendern. */ + { + if (skipsp(&clicnt, &clipoi)) + { + ccp_call(hostuserid); /* Neues rufzeichen setzen */ + return; + } + + mbp = putals("HostMyCall:\r\r"); + + putstr("Consolen MyCall:", mbp); + putid(hostuserid, mbp); + putstr("\r", mbp); + + prompt(mbp); + seteom(mbp); + } + else + invmsg(); +} +#endif /* HOSTMYCALL */ + +#ifdef SYSOPPASSWD +/*************************************************************************/ +/* */ +/* Sysop-Passwort im laufenden Betrieb aendern. */ +/* Das neue Passwort wird in der TNN179.TNB gespeichert und beim */ +/* naechsten neustart eingelesen. */ +/* */ +/* SYNTAX: PASS dasistmeinpasswort */ +/* (Passwortstring muss genau 80Zeichen haben) */ +/* */ +/*************************************************************************/ +void ccppasswd(void) +{ + MBHEAD *mbp; + + if (issyso()) /* Nur Sysop darf aendern. */ + { + if (skipsp(&clicnt, &clipoi)) + { + if (clicnt == 80) /* Passwort hat 80 Zeichen. */ + { + strncpy(paswrd, clipoi, 80); /* Neues Passwort sichern. */ + mbp = putals("Sysop Passwort:\r\r"); +#ifdef SPEECH + putstr(speech_message(173),mbp); +#else + putstr("Das Sysop Passwort wurde geaendert!\r",mbp); +#endif + prompt(mbp); + seteom(mbp); + return; + } + else /* Passwort hat keine 80 Zeichen. */ + { + mbp = putals("Sysop Passwort:\r\r"); +#ifdef SPEECH + putstr(speech_message(174),mbp); +#else + putstr("Fehler: Das Passwort muss 80 Zeichen enthalten!\r",mbp); +#endif + prompt(mbp); + seteom(mbp); + return; + } + } + + mbp = putals("Sysop Passwort:\r\r"); + putprintf(mbp,"%s\r",paswrd); + prompt(mbp); + seteom(mbp); + } + else + invmsg(); +} +#endif /* SYSPASSWD */ + +/************************************************************************/ +/* Paddle-Command */ +/*----------------------------------------------------------------------*/ +#ifdef PADDLE /* spezielle Hardware fuer AtariST */ +char *padread(WORD i); +extern WORD paddles[8]; +void ccppaddle(void) +{ + int i; + MBHEAD *mbp; + + mbp = putals("Analog inputs:\r"); + + for (i = 0; i < 6; i++) + putstr(padread(i), mbp); + + putchr(CR, mbp); + prompt(mbp); + seteom(mbp); +} +#endif + + +/************************************************************************/ +/* */ +/*----------------------------------------------------------------------*/ + +void send_ctext(void) +{ + BOOLEAN ok = FALSE; + UWORD port = 0; + MBHEAD *mbp; + char file[14]; + char name[MAXPATH]; + UBYTE typ = g_utyp(userpo->uid); + CIRBLK *cp; + LNKBLK *lp; + int i; + PERMLINK *p; + + /* + * Wenn eine Verbindung als Digipeating reinkommt, setzen wir den + * Status entsprechend und senden kein CTEXT. + */ + + if (typ == L2_USER) { + lp = g_ulink(userpo->uid); + if (lp->state == L2SHTH) { + userpo->status = US_DIG; + return; + } + } else + if (typ == L4_USER) { + + cp = g_ulink(userpo->uid); + if (cmpid(cp->destca, myid) == FALSE) { + userpo->status = US_DIG; + return; + } + } + +#ifdef L1TCPIP + { + TCPIP *tc; + + if (typ == TCP_USER) + { + tc = g_ulink(userpo->uid); + + switch(tc->Interface) + { +#ifdef L1HTTPD + case KISS_HTTPD : + return; +#endif /* L1HTTPD */ + +#ifdef L1IPCONV + case KISS_IPCONV : + return; +#endif /* L1IPCONV */ + +#ifdef L1IRC + case KISS_IRC : + return; +#endif /* L1IRC */ + + default : + break; + } + } + } +#endif /* L1TCPIP */ + + /* + * Der CTEXT wird abhaengig vom Port gesendet. + */ + port = userport(userpo); + +#ifndef NOCTEXT + /* Jedes Rufzeichen, das wir in der Nodes-Liste finden, begruessen + * wir ueberhaupt nicht. */ + if (find_node_ssid_range(calofs(UPLINK, userpo->uid)) != -1) + return; +#else + { + 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 (cmpid(pp->l2link->call, calofs(UPLINK, userpo->uid))) + { + if (pp->typ <= FLEXNET) /* Routing-Protokolle kein CTEXT. */ + return; + } + } + } + } +#endif /* NOCTEXT */ + +/* Keinen Ctext fuer eingetragene Convers-Hosts */ + for (i = 0; i < MAXCVSHOST; i++) + { + if ((p = permarray[i]) != NULLPERMLINK) + if (cmpcal(calofs(UPLINK, userpo->uid), p->cname)) + return; + } + + if (port == L2PNUM) /* HOST */ + ok = TRUE; + else + if (ctextenabled(port)) + ok = TRUE; + + mbp = getmbp(); + + if (ok) { +#ifndef MAKRO_NOLOGINSTR + putstr(loginstr, mbp); +#endif + sprintf(name, "%sCTEXT.TXT", textpath); + out_ctext(name, mbp); + + /* sende nun CTEXT.Port */ + sprintf(name, "%sCTEXT.%u", textpath, port); + out_ctext(name, mbp); + + /* Digimail Text(e), falls File "CALL.MSG" vorhanden */ + callss2str(file, calofs(UPLINK, userpo->uid)); + sprintf(name, "%s%s.MSG", msgpath, file); + if (xaccess(name, 0) == 0) { + putstr("\r", mbp); + seteom(mbp); + ccpread(name); + return; /* nicht nochmal Prompt */ + } + } /* kein CTEXT gewuenscht .. dann nur Prompt */ + + putchr('\r', mbp); + prompt(mbp); + seteom(mbp); +} + +#ifdef MAKRO_FILE +/* USERPO->FILE nach Makros untersuchen */ +/* und neue USER->FILE erstellen. */ +static int update_userpo_file(USRBLK *user) +{ + MBHEAD *usermbp; + FILE *fp; + char *tmpfile; + char zeichen; + char inbuf[255], + *inread = inbuf; + + if (user->read_ok == FALSE) + { + /* Buffer besorgen. */ + usermbp = getmbp(); + + /* Wir lesen userpo->fp komplett ein. */ + while(fgets(inread,255,user->fp) != NULL) + /* Jede Zeile nach Makros pruefen */ + /* und gegebenfalls auswerten. */ + prompt2str(usermbp,inread); + + /* Buffer zurueck spulen. */ + rwndmb(usermbp); + + /* Markiere, das wir die funktion */ + /* durchlaufen haben. */ + user->read_ok = TRUE; + + /* Ermitteln eines Namens fuer eine temporaere Datei. */ + if ((tmpfile = tempnam(textpath, "tmp")) == NULL) + /* da ging was schief. */ + return(TRUE); + + /* Temp-File oeffenen. */ + if ((fp = xfopen(tmpfile, "wt")) == NULL) + { + putmsg("Sri, can't open tempfile...\r"); + free(tmpfile); + return(TRUE); + } + + /* Keine Fehler, jetzt koennen wir */ + /* die alte Temp-File Schliessen!. */ + fclose(user->fp); + user->fp = NULL; + + if (user->fname != NULL) + { + xremove(user->fname); + free(user->fname); + user->fname = NULL; + } + + while(usermbp->mbpc != usermbp->mbgc) + /* Alle Zeichen in das Temp-File schreiben.*/ + fprintf(fp,"%c",(zeichen = getchr(usermbp))); + + /* Buffer leeren/entsorgen. */ + dealmb(usermbp); + /* Temporaeres File schliessen */ + fclose(fp); + /* Temporaeres File setzen. */ + user->fname = tmpfile; + /* NEUE (mit eventuelle Makros) */ + /* Temporaeres File einlesen. */ + ccpread(tmpfile); + return(FALSE); + } + return(FALSE); +} +#endif +/* End of src/l7ccp.c */ diff --git a/src/l7cmds.c b/src/l7cmds.c new file mode 100755 index 0000000..9fc0492 --- /dev/null +++ b/src/l7cmds.c @@ -0,0 +1,1911 @@ +/************************************************************************/ +/* */ +/* ***** ***** */ +/* ***** ***** */ +/* ***** ***** */ +/* ***** ***** */ +/* *************** *************** */ +/* ***************** ***************** */ +/* *************** *************** */ +/* ***** ***** TheNetNode */ +/* ***** ***** Portable */ +/* ***** ***** Network */ +/* ***** ***** Software */ +/* */ +/* File src/l7cmds.c (maintained by: ???) */ +/* */ +/* This file is part of "TheNetNode" - Software Package */ +/* */ +/* Copyright (C) 1998 - 2008 NORD>next) + putprintf(mbp, "%s -> %s\r", ap->alias, ap->cmd); + } + else +#ifdef SPEECH + putstr(speech_message(218), mbp); +#else + putstr("No aliasses defined\r", mbp); +#endif + } + else /* handling if called with parameters */ + { + /* read alias first */ + i = 0; + while (clicnt > 0 && *clipoi != ' ' && i < MAXALIASLEN) + { + aliastmp[i++] = toupper(*clipoi++); + clicnt--; + } + aliastmp[i] = '\0'; + + /* check its length */ + if (clicnt > 0 && *clipoi != ' ') + { +#ifdef SPEECH + putprintf(mbp, speech_message(202), MAXALIASLEN); +#else + putprintf(mbp, "Alias too long, max. %u characters.\r", MAXALIASLEN); +#endif + prompt(mbp); + seteom(mbp); + return; + } + + for (ap2 = NULL ; ap != NULL; ap = ap->next) + { + if (!strcmp(aliastmp, ap->alias)) /* aendern */ + break; + + ap2 = ap; + } + + /* are there any more characters ? */ + if (skipsp(&clicnt, &clipoi)) + { + if (clicnt > MAXALIASCMDLEN) + { +#ifdef SPEECH + putprintf(mbp, speech_message(203), MAXALIASCMDLEN); +#else + putprintf(mbp, "Command too long, max. %u characters.\r", MAXALIASCMDLEN); +#endif + prompt(mbp); + seteom(mbp); + return; + } + + /*strupr(clipoi); wenns denn unbedingt noetig ist */ + + if (ap != NULL) /* aendern */ + { + strcpy(ap->cmd, clipoi); +#ifdef SPEECH + putstr(speech_message(219), mbp); +#else + putstr("Alias stored.\r", mbp); +#endif + prompt(mbp); + seteom(mbp); + return; + } + + /* nicht gefunden, also neu */ + ap = (CMDALIAS *)calloc(1, sizeof(CMDALIAS)); + if (ap == NULL) + { +#ifdef SPEECH + putstr(speech_message(220), mbp); +#else + putstr("Can't store, no memory.\r", mbp); +#endif + prompt(mbp); + seteom(mbp); + return; + } + + strcpy(ap->alias, aliastmp); + strcpy(ap->cmd, clipoi); + if (aliaslist == NULL) /* erster Eintrag */ + aliaslist = ap; + else /* in Liste */ + ap2->next = ap; + +#ifdef SPEECH + putstr(speech_message(219), mbp); +#else + putstr("Alias stored.\r", mbp); +#endif + } + else /* no more parameters than alias-name */ + { + if (ap != NULL) /* loeschen */ + { + if (ap == aliaslist) + aliaslist = ap->next; + else + ap2->next = ap->next; + + free(ap); + +#ifdef SPEECH + putstr(speech_message(221), mbp); +#else + putstr("Alias deleted.\r", mbp); +#endif + prompt(mbp); + seteom(mbp); + return; + } + + /* no match */ +#ifdef SPEECH + putstr(speech_message(222), mbp); +#else + putstr("No such alias defined, can't delete.\r", mbp); +#endif + } + } + prompt(mbp); + seteom(mbp); + } + else + invmsg(); +} + +/* Loeschen der gesamten Alias-Liste */ +void clean_aliaslist(void) +{ + CMDALIAS *ap = aliaslist, *ap2; + + /* Aliaslist gefuellt ? */ + if (ap == NULL) + return; + + /* alle Elemente der Liste durchgehen und loeschen */ + do + { + ap2 = ap->next; /* Zeiger auf naechstes Alias retten */ + free(ap); /* aktuelles Alias loeschen */ + ap = ap2; /* geretteten Zeiger wiederherstellen */ + } while (ap != NULL); /* so lange die Liste nicht terminiert ist */ +} + +#endif + +/************************************************************************/ +/* Programm starten */ +/*----------------------------------------------------------------------*/ +void ccpstart(void) +{ + if (issyso()) { + tnnexec((char *)clipoi); +#ifndef MC68302 /* da gibs mehrere Fehlermeldungen */ +#ifdef SPEECH + putmsg(speech_message(237)); +#else + putmsg("Invalid program!\r"); +#endif +#endif + } +} + +/************************************************************************/ +/* Parameter anzeigen/aendern */ +/*----------------------------------------------------------------------*/ +void ccppar(void) +{ + ccp_par("Parms:\r", partab, partablen); +} + +/**************************************************************************/ +/* RESET */ +/*------------------------------------------------------------------------*/ +void ccpres(void) +{ + MBHEAD *mbp; + WORD port; + + if (issyso()) { + if (strnicmp((char *)clipoi,"SYSTEM",6) == 0) + HALT("sysop"); + if (getport(&clicnt, &clipoi, &port)) { + mbp = putals("RESET Port "); + putnum(port, mbp); + putchr('\r', mbp); + prompt(mbp); + seteom(mbp); + l1ctl(L1CRES, port); + } else +#ifdef SPEECH + putmsg(speech_message(193)); +#else + putmsg("Invalid Port!\r"); +#endif + } else + invmsg(); +} + +/************************************************************************/ +/* PROMPT */ +/*----------------------------------------------------------------------*/ +void ccpprompt(void) +{ + MBHEAD *mbp; + WORD i; + + if (issyso() && *clipoi == '=') { + if (clicnt > 0) + { + clicnt--; + clipoi++; + } + for (i = 0; i < 79 && clicnt--; promptstr[i++] = *clipoi++); + promptstr[i] = 0; + } + mbp = putals("Prompt: "); + putstr(promptstr, mbp); + putchr('\r', mbp); + prompt(mbp); + seteom(mbp); +} + +#if defined(MC68302) || defined(__WIN32__) +/************************************************************************/ +/* DELETE - Befehl (Dateien loeschen) */ +/*----------------------------------------------------------------------*/ +void ccpdelete(void) +{ + MBHEAD *mbp; + char file[128]; + + if (issyso()) { + strcpy(file, clipoi); + mbp = putals(file); + if (remove(file)) +#ifdef SPEECH + putstr(speech_message(223), mbp); +#else + putstr(" not deleted!\r", mbp); +#endif + else + { +#ifndef __WIN32__ + compact(); +#endif /* WIN32 */ +#ifdef SPEECH + putstr(speech_message(224), mbp); +#else + putstr(" deleted.\r", mbp); +#endif + } + prompt(mbp); + seteom(mbp); + } + else + invmsg(); +} + +/************************************************************************/ +/* copy */ +/************************************************************************/ +void ccpcopy(void) +{ + FILE *f1; + FILE *f2; + size_t n; + char buf[512]; + char buf2[40]; + char file1[80]; + char file2[80]; + MBHEAD *mbp; + + if (issyso()) + { + if (clicnt > 0) + { + skipsp(&clicnt, &clipoi); + *file1 = *file2 = '\0'; + sscanf(clipoi, "%s %s", file1, file2); + + if (*file1 && *file2) + { + mbp = getmbp(); + strcpy(buf2, "OK\r"); + if ((f1 = fopen(file1, "rb")) != NULL) + { + if ((f2 = fopen(file2, "wb")) != NULL) + { + while ((n = fread(buf, 1, 512, f1)) > 0) + { + if (fwrite(buf, 1, n, f2) != n) + { + strcpy(buf2, "write error !\r"); + remove(file2); + break; + } + } + fclose(f1); + fclose(f2); +#ifndef __WIN32__ + compact(); +#endif /* WIN32 */ + } + else + { +#ifdef SPEECH + sprintf(buf2, speech_message(204), file2); +#else + sprintf(buf2, "can't create %s !\r", file2); +#endif + } + } + else + { +#ifdef SPEECH + sprintf(buf2, speech_message(205), file1); +#else + sprintf(buf2, "can't open %s !\r", file1); +#endif + } + putstr(buf2, mbp); + prompt(mbp); + seteom(mbp); + } + } + } + else + invmsg(); +} + +/************************************************************************/ +/* ccpdir */ +/************************************************************************/ +void ccpdir(void) +{ + char file[128]; + MBHEAD *mbp; + struct ffblk fblock; + int lastentry; + struct tm *ftime; + int einfach, cnt; + + einfach = FALSE; + if (userpo->sysflg != 0) { /* Benutzer ist Sysop */ + strcpy(file, textpath); /* Verzeichnis der Texte */ + if (clicnt > 0) { /* Parameter folgen */ + skipsp(&clicnt, &clipoi); /* Nachfolgende Leerzeichen */ + if (strncmp(strlwr(clipoi), "/w", 2) == 0) { /* Einfache Ausgabe */ + nextspace(&clicnt, &clipoi); + skipsp(&clicnt, &clipoi); /* Nachfolgende Leerzeichen */ + if (clicnt > 0) /* vorhandene Dateimaske */ + strcat(file, clipoi); /* an Pfad dranhaengen */ + else /* sonst: */ + strcat(file, "*.*"); /* alles auswaehlen */ + einfach = TRUE; + } + else { + strcat(file, clipoi); + } + } + else { + strcat(file,"*.*"); + } + mbp = getmbp(); + cnt = 0; + lastentry = xfindfirst(file, &fblock, 0); + while (!lastentry) { + if (einfach) { + putprintf(mbp,"%15s", fblock.ff_name); + if (++cnt == 5) { + putchr('\r', mbp); + cnt = 0; + } + } else { + ftime = localtime((const long *)&fblock.ff_ftime); + putprintf(mbp,"%12s %8ld Bytes %2.2d.%02d.%02d %2.2d:%02d:%02d\r", + fblock.ff_name, fblock.ff_fsize, + ftime->tm_mday, (ftime->tm_mon)+1, ftime->tm_year%100, + ftime->tm_hour, ftime->tm_min, ftime->tm_sec); + } + lastentry = xfindnext(&fblock); + } + if (einfach) putstr("\r", mbp); +#ifndef __WIN32__ + compact(); +#endif /* WIN32 */ +#ifdef SPEECH + putprintf(mbp,speech_message(206), coreleft()); +#else + putprintf(mbp,"%lu Bytes free\r", coreleft()); +#endif + prompt(mbp); + seteom(mbp); + } + else + invmsg(); +} +#endif /* WIN32 */ + +#ifndef MC68302 +/************************************************************************/ +/* SHELL/DOS/TOS */ +/*----------------------------------------------------------------------*/ +void ccpshell(void) +{ + char sysline[MAXPATH+1]; + + if (issyso()) /* darf nur ein Sysop */ + { + strncpy(sysline, (char *)clipoi, MAXPATH); + sysline[MAXPATH] = 0; + if (tnnshell(sysline) == TRUE) return; /* und ausfuehren */ + /* tnnshell() liefert in sysline den Namen der temporaeren Datei, */ + /* die die Ausgabe der Shell enthaelt. */ + if (*sysline) { + userpo->fname = strdup(sysline); + ccpread(sysline); /* Ergebnis dem User sagen */ + } + else + invmsg(); + } + else + invmsg(); +} +#endif + +/* Commandotabelle fuer die Porteinstellung, alles was hier nicht erscheint, + wird als Geraetename interpretiert und an l1attach() uebergeben. */ +#define PO_DETACH 1 +#define PO_NAME 2 +#define PO_TXD 3 +#define PO_MODE 4 +#define PO_MAXF 5 +#define PO_CTEXT 6 +#define PO_SYSOP 7 +#define PO_MH 8 +#define PO_DAMA 9 +#define PO_MAXC 10 +#define PO_TAIL 11 +#define PO_EAXMF 12 +#define PO_EAXBH 13 +#ifdef EXPERTPARAMETER +#define PO_PERS 14 +#define PO_SLOT 15 +#define PO_IRTT 16 +#define PO_T2 17 +#define PO_RETRY 18 +#endif + +#ifdef PORT_MANUELL +#define PO_PACL 19 +#define PO_T3 20 +#endif /* PORT_MANUELL */ + +#ifdef IPOLL_FRAME +#define PO_IPAC 21 +#define PO_IRET 22 +#endif /* IPOLL_FRAME */ +#ifdef PORT_L2_CONNECT_TIME +#define PO_L2_CONNECT_TIME 23 +#endif +#ifdef PORT_L2_CONNECT_RETRY +#define PO_L2_CONNECT_RETRY 24 +#endif +#ifdef AUTOROUTING +#define PO_RAUTO 25 +#endif /* AUTOROUTING */ + +PORTCMD portcmd[] = { /* nicht aktivierte Pars werden ueberlesen */ + {"OFF", PO_DETACH }, + {"NAME", PO_NAME }, + {"TXDELAY", PO_TXD }, + {"MODE", PO_MODE }, + {"MAXFRAME", PO_MAXF }, + {"CTEXT", PO_CTEXT }, + {"SYSOP", PO_SYSOP }, + {"MH", PO_MH }, + {"DAMA", PO_DAMA }, + {"MAXCON", PO_MAXC }, + {"TAILTIME", PO_TAIL }, + {"EAXMAXFR", PO_EAXMF }, + {"EAXMODE", PO_EAXBH }, +#ifdef EXPERTPARAMETER + {"PERSISTANCE", PO_PERS }, + {"SLOTTIME", PO_SLOT }, + {"IRTT", PO_IRTT }, + {"T2", PO_T2 }, + {"RETRY", PO_RETRY }, +#endif + +#ifdef PORT_MANUELL + {"PACLEN", PO_PACL }, + {"T3", PO_T3 }, +#endif /* PORT_MANUELL */ + +#ifdef IPOLL_FRAME + {"IPACLEN", PO_IPAC }, + {"IRETRY", PO_IRET }, +#endif /* IPOLL_FRAME */ +#ifdef PORT_L2_CONNECT_TIME + {"L2TIME", PO_L2_CONNECT_TIME }, +#endif +#ifdef PORT_L2_CONNECT_RETRY + {"L2RETRY", PO_L2_CONNECT_RETRY }, +#endif +#ifdef AUTOROUTING + {"L4AUTO", PO_RAUTO }, +#endif + {NULL, 0 } +}; + +/************************************************************************/ +/* */ +/*----------------------------------------------------------------------*/ +#ifdef MC68302 +void hsbus_stat(MBHEAD *); +#endif + +void +ccpport(void) +{ + MBHEAD *mbp; /* message-buffer-pointer */ + WORD port; /* Port-Nummer (0..L2PNUM-1) */ + char buf[80]; + PORTCMD *pc; + char *bps; + WORD bcs, found; + ULONG lbaud; + L1MODETAB *mtp; + PORTINFO *p; + WORD begport = 0; + WORD endport = L2PNUM - 1; + + skipsp(&clicnt, &clipoi); + + if (*clipoi == '*' || *clipoi == '+') /* Ausgabe der Autoparameter */ + { + mbp = putals("Port Parameters:\r"); +#ifdef PORT_MANUELL + putstr(" ",mbp); +#else + putstr(" TX- Max- L2- ", mbp); +#endif /* PORT_MANUELL */ +#ifdef SETTAILTIME + putstr(" Tail", mbp); +#endif +#ifdef USERMAXCON + putstr(" Max", mbp); +#endif +#ifdef EAX25 + putstr(" EAX- EAX-", mbp); +#endif +#ifdef IPOLL_FRAME + putstr(" IPOLL IPOLL ", mbp); +#endif /* IPOLL_FRAME */ +#ifdef PORT_L2_CONNECT_TIME + putstr("INTERLINK-", mbp); +#endif +#ifdef AUTOROUTING + putstr(" L4-", mbp); +#endif /* AUTOROUTING */ +#ifdef PORT_MANUELL + putstr("\r" + "-#-Port-------",mbp); +#else + putstr("\r" + "-#-Port-------Delay-Pers--Slot--IRTT--Frame-Retry--Timer2-", mbp); +#endif /* PORT_MANUELL */ +#ifdef SETTAILTIME + putstr("--Time", mbp); +#endif +#ifdef USERMAXCON + putstr("-Con", mbp); +#endif +#ifdef EAX25 + putstr("-MaxF-Mode", mbp); +#endif +#ifdef IPOLL_FRAME + putstr("-Paclen-Retry", mbp); +#endif /* IPOLL_FRAME */ +#ifdef PORT_L2_CONNECT_TIME + putstr("-Time", mbp); +#endif +#ifdef PORT_L2_CONNECT_RETRY + putstr("-Retry", mbp); +#endif +#ifdef AUTOROUTING + putstr("-Auto", mbp); +#endif /* AUTOROUTING */ +#ifdef PORT_MANUELL + putstr("-Hardware", mbp); +#endif /* PORT_MANUELL */ + putchr(CR, mbp); + + for (port = 0, p = portpar; port < L2PNUM; p++, port++) + { + if (!portenabled(port)) + continue; +#ifdef PORT_MANUELL + putprintf(mbp, "%2u:%-10s",port,p->name); +#else + putprintf(mbp, "%2u:%-10s %3u %3u%c %3u%c %4u%c " + "%1u%c %3u%c %4u%c ", + port, + p->name, + p->txdelay, + p->persistance, + (p->l2autoparam & MODE_apers) ? 'a' : ' ', + p->slottime, + (p->l2autoparam & MODE_aslot) ? 'a' : ' ', + p->IRTT, + (p->l2autoparam & MODE_aIRTT) ? 'a' : ' ', + p->maxframe, + automaxframe(port) ? 'a' : ' ', + p->retry, + (p->l2autoparam & MODE_aretry) ? 'a' : ' ', + p->T2, + (p->l2autoparam & MODE_aT2) ? 'a' : ' '); +#endif /* PORT_MANUELL */ +#ifdef SETTAILTIME + putprintf(mbp, " %5u", p->tailtime); +#endif +#ifdef USERMAXCON + putprintf(mbp, " %2u", p->maxcon); +#endif +#ifdef EAX25 + putprintf(mbp, " %2u %2u", p->maxframe_eax, p->eax_behaviour); +#endif +#ifdef IPOLL_FRAME + putprintf(mbp, " %6u %2u", p->ipoll_paclen, p->ipoll_retry); +#endif /* IPOLL_FRAME */ +#ifdef PORT_L2_CONNECT_TIME + putprintf(mbp, " %5u", p->l2_connect_time); +#endif +#ifdef PORT_L2_CONNECT_RETRY + putprintf(mbp, " %2u", p->l2_connect_retry); +#endif +#ifdef AUTOROUTING + putprintf(mbp, " %2u", p->poAuto); +#endif /* AUTOROUTING */ +#ifdef PORT_MANUELL + putstr(" ",mbp); + l1hwstr(port, mbp); +#endif /* PORT_MANUELL */ + putchr(CR, mbp); + } + +#if defined(EXPERTPARAMETER) && !defined(PORT_MANUELL) + putstr("(the little \"a\" means, this value is calculated automatically)\r", mbp); +#endif + prompt(mbp); + seteom(mbp); + return; + } +#ifdef MC68302 + if (*clipoi == '?') /* Ausgabe der Inquiry (vorerst nur hskiss) */ + { + mbp = putals("Port-Inquiry:\r" + "Po. Software-Version TxD " + "Per Slt Tail Dup DAMA Baud Duo\r"); + hsbus_stat(mbp); + prompt(mbp); + seteom(mbp); + return; + } +#endif + + if (issyso() && clicnt) + { + port = nxtnum(&clicnt, &clipoi); + if (port >= 0 && port < L2PNUM && skipsp(&clicnt, &clipoi)) + { + p = &portpar[port]; + l1ctl(L1CCMD, port); /* HB9PAE/DB7KG */ + do + { + *buf = NUL; + bps = buf; + if (skipsp(&clicnt, &clipoi)) + { + while (*clipoi && isalnum(*clipoi)) + { + *bps++ = toupper(*clipoi++); + --clicnt; + } + *bps = NUL; + } + if (!*buf) + { + clicnt = 0; + break; + } + bcs = (WORD)strlen(buf); + + for (pc = portcmd, found = 0; + !found && pc->cmdstr != NULL; + ++pc) + { + if (!strncmp(pc->cmdstr, buf, (size_t)bcs)) + found = pc->cmdpar; + } + + if (found) + { + switch (found) + { + case PO_DETACH: + l1detach(port); + break; + + case PO_NAME: + if (clicnt > 1) + { + clipoi++; + clicnt--; + if (sscanf((char *) clipoi,"%10s", buf) == 1) + { + strcpy(p->name, buf); + bcs = (WORD)strlen(buf); + clipoi += bcs; + clicnt -= bcs; + } + } + break; + + case PO_TXD: + p->txdelay = getparam(&clicnt, &clipoi, 0, 255, 25); + l1ctl(L1CCMD, port); + autopar(port); + break; + + case PO_MODE: + if (clicnt > 1) + { + clipoi++; + clicnt--; + *buf = 0; + + if (isdigit(*clipoi)) + { + lbaud = nxtlong(&clicnt, &clipoi); + if (lbaud > 4915200L) + p->speed = 49152U; + else if (lbaud < 300L) + p->speed = 3; + else + p->speed = (UWORD) (lbaud/100L); + } + + *buf = 0; + if (*clipoi && *clipoi != ' ') + { + sscanf((char *) clipoi,"%8s", buf); + strlwr(buf); + nextspace(&clicnt, &clipoi); + } + CLR_L1MODE(port); + for (mtp = l1modetab; mtp->ch; mtp++) + if (strchr(buf, mtp->ch)) + SET_L1MODE(port, mtp->mode); + + l1ctl(L1CCMD, port); + } + break; + + case PO_MAXF: + if (clicnt > 1) + { + p->maxframe = getparam(&clicnt, &clipoi, 1, 7, 2); + if (clicnt != 0 && toupper(*clipoi) == 'A') + p->l2mode |= MODE_am; + else + p->l2mode &= ~MODE_am; + nextspace(&clicnt, &clipoi); + } + break; + + case PO_CTEXT: + if (getparam(&clicnt, &clipoi, 0, 1, 0)) + p->l2mode |= MODE_x; + else + p->l2mode &= ~MODE_x; + break; + + case PO_SYSOP: + if (getparam(&clicnt, &clipoi, 0, 1, 0)) + p->l2mode |= MODE_s; + else + p->l2mode &= ~MODE_s; + break; + + case PO_MH: + if (getparam(&clicnt, &clipoi, 0, 1, 0)) + p->l2mode |= MODE_h; + else + p->l2mode &= ~MODE_h; + break; + + case PO_DAMA: +/* Es darf nur auf DAMA-Master oder DAMA-Slave geschaltet werden. */ +/* DAMA-Slave wird mit "DAMA S" (oder "DAMA=S") gewaehlt. */ + if (clicnt > 1 && toupper(clipoi[1]) == 'S') + { + clipoi++; + clicnt--; +#ifdef DAMASLAVE + p->l2mode |= MODE_ds; /* DAMA-Slave ON */ + p->dch = DAMA_CH; /* DAMA-Master OFF */ + p->l2mode &= ~MODE_a; +#endif + nextspace(&clicnt, &clipoi); + break; + } +#ifdef DAMASLAVE + p->l2mode &= ~MODE_ds; /* DAMA-Slave OFF */ +#endif + p->dch = getparam(&clicnt, &clipoi, 0, DAMA_CH, DAMA_CH); + if (p->dch > 0) + { + p->dch -= 1; + p->l2mode |= MODE_a; + } + else + { + p->dch = DAMA_CH; + p->l2mode &= ~MODE_a; + } + break; + + case PO_MAXC: +#ifdef USERMAXCON + p->maxcon = getparam(&clicnt, &clipoi, 0, 15, 0); +#else + nextspace(&clicnt, &clipoi); +#endif + break; + + case PO_TAIL: +#ifdef SETTAILTIME + p->tailtime = getparam(&clicnt, &clipoi, 0, 32700, TAILTIME); + l1ctl(L1CCMD, port); +#else + nextspace(&clicnt, &clipoi); +#endif + break; + + case PO_EAXMF: +#ifdef EAX25 + p->maxframe_eax = getparam(&clicnt, &clipoi, 1, 32, 16); +#else + nextspace(&clicnt, &clipoi); +#endif + break; + + case PO_EAXBH: +#ifdef EAX25 + p->eax_behaviour = getparam(&clicnt, &clipoi, 0, 3, 1); +#else + nextspace(&clicnt, &clipoi); +#endif + break; + +#ifdef EXPERTPARAMETER + case PO_PERS: + if (clicnt > 1) + { + p->persistance = getparam(&clicnt, &clipoi, 32, 255, 128); + if (clicnt != 0 && toupper(*clipoi) == 'A') + p->l2autoparam |= MODE_apers; + else + p->l2autoparam &= ~MODE_apers; + nextspace(&clicnt, &clipoi); + } + l1ctl(L1CCMD, port); + autopar(port); + break; + + case PO_SLOT: + if (clicnt > 1) + { + p->slottime = getparam(&clicnt, &clipoi, 0, 255, 10); + if (clicnt != 0 && toupper(*clipoi) == 'A') + p->l2autoparam |= MODE_aslot; + else + p->l2autoparam &= ~MODE_aslot; + nextspace(&clicnt, &clipoi); + l1ctl(L1CCMD, port); + } + autopar(port); + break; + + case PO_IRTT: + if (clicnt > 1) + { + p->IRTT = getparam(&clicnt, &clipoi, 1, 400, 200); + if (clicnt != 0 && toupper(*clipoi) == 'A') + p->l2autoparam |= MODE_aIRTT; + else + p->l2autoparam &= ~MODE_aIRTT; + nextspace(&clicnt, &clipoi); + l1ctl(L1CCMD, port); + } + autopar(port); + break; + + case PO_T2: + if (clicnt > 1) + { + p->T2 = getparam(&clicnt, &clipoi, 1, 300, 200); + if (clicnt != 0 && toupper(*clipoi) == 'A') + p->l2autoparam |= MODE_aT2; + else + p->l2autoparam &= ~MODE_aT2; + nextspace(&clicnt, &clipoi); + l1ctl(L1CCMD, port); + } + autopar(port); + break; + + case PO_RETRY: + if (clicnt > 1) + { + p->retry = getparam(&clicnt, &clipoi, 1, 127, 30); + if (clicnt != 0 && toupper(*clipoi) == 'A') + p->l2autoparam |= MODE_aretry; + else + p->l2autoparam &= ~MODE_aretry; + nextspace(&clicnt, &clipoi); + l1ctl(L1CCMD, port); + } + autopar(port); + break; +#endif + +#ifdef PORT_MANUELL + /* Packetlaenge setzen. */ + case PO_PACL: + p->paclen = getparam(&clicnt, &clipoi, 32, 256, 128); + l1ctl(L1CCMD, port); + break; + + /* T3-Timer setzen. */ + case PO_T3: + p->T3 = getparam(&clicnt, &clipoi, 1, 32700, 18000); + l1ctl(L1CCMD, port); + break; +#endif /* PORT_MANUELL */ + +#ifdef IPOLL_FRAME + case PO_IPAC: + p->ipoll_paclen = getparam(&clicnt, &clipoi, 32, 256, 128); + l1ctl(L1CCMD, port); + break; + case PO_IRET: + p->ipoll_retry = getparam(&clicnt, &clipoi, 1, 6, 3); + l1ctl(L1CCMD, port); + break; +#endif /* IPOLL_FRAME */ +#ifdef PORT_L2_CONNECT_TIME + case PO_L2_CONNECT_TIME: + p->l2_connect_time = getparam(&clicnt, &clipoi, 1, 500, 120); + l1ctl(L1CCMD, port); + break; +#endif +#ifdef PORT_L2_CONNECT_RETRY + case PO_L2_CONNECT_RETRY: + p->l2_connect_retry = getparam(&clicnt, &clipoi, 1, 127, 3); + l1ctl(L1CCMD, port); + break; +#endif +#ifdef AUTOROUTING + case PO_RAUTO: + p->poAuto = getparam(&clicnt, &clipoi, 0, 4, 0); + l1ctl(L1CCMD, port); + break; +#endif /* AUTOROUTING */ + } /* switch */ + } /* if */ + else + l1attach(port, buf); + } while (clicnt > 0); + /* Portnummer merken. */ + begport = endport = port; + autopar(begport = endport = port); /* Auto-Parameter setzen */ + } + } + + mbp = putals("Link-Interface Ports:\r"); /* Konfiguration zeigen */ +#ifdef PORT_MANUELL + putstr("-#-Name----------Speed/Mode-Max-TXD-", mbp); + putstr("PAC-",mbp); + putstr("PERS-",mbp); + putstr("SLOT-",mbp); + putstr("IRTT-",mbp); + putstr("--T2-",mbp); + putstr("---T3-",mbp); + putstr("-RET-",mbp); + putstr("DA-C-S-M", mbp); + putchr('\r', mbp); +#else + putstr("-#-Name----------Speed/Mode-Max-TXD-DA" + "----------------Hardware--\r", mbp); +#endif /* PORT_MANUELL */ + for (port = begport; port <= endport; port++) + put_pcnf(port, mbp); + + prompt(mbp); + seteom(mbp); +} + +/*----------------------------------------------------------------------*/ +static void +put_pcnf(WORD port, MBHEAD *mbp) +{ + char mode[16], *cp; + ULONG baud; + L1MODETAB *mtp; + PORTINFO *p = &portpar[port]; + + if (!portenabled(port)) + return; + + putprintf(mbp, "%2d %-10s", port, p->name); + + cp = mode; + for (mtp = l1modetab; mtp->ch; mtp++) + if (p->l1mode & mtp->mode) + *cp++ = mtp->ch; + *cp = 0; + + baud = ((ULONG)p->speed) * 100L; + putprintf(mbp, " %8lu%-5s %1u%c %3u ", baud, mode, p->maxframe, + automaxframe(port) ? 'a' : ' ', p->txdelay); + +#ifdef PORT_MANUELL + putprintf(mbp, "%3u " ,p->paclen); + putprintf(mbp, "%3u%c ",p->persistance, (p->l2autoparam & MODE_apers) ? 'a' : ' '); + putprintf(mbp, "%3u%c ",p->slottime, (p->l2autoparam & MODE_aslot) ? 'a' : ' '); + putprintf(mbp, "%3u%c ",p->IRTT, (p->l2autoparam & MODE_aIRTT) ? 'a' : ' '); + putprintf(mbp, "%3u%c ",p->T2, (p->l2autoparam & MODE_aT2) ? 'a' : ' '); + putprintf(mbp, "%5u ",p->T3); + putprintf(mbp, "%3u%c ",p->retry, (p->l2autoparam & MODE_aretry) ? 'a' : ' '); +#endif /* PORT_MANUELL */ + +#ifdef DAMASLAVE + if ((p->l2mode & MODE_ds) || (p->l2mode & MODE_a)) + { + if (p->l2mode & MODE_ds) + putstr(" s ", mbp); + else + if (p->l2mode & MODE_a) + putprintf(mbp, "%2u ", p->dch + 1); + } +#else + if (p->l2mode & MODE_a) + putprintf(mbp, "%2u ", p->dch + 1); +#endif + else + putstr(" ", mbp); +#ifdef PORT_MANUELL + putstr(p->l2mode & MODE_x ? "C " : " ", mbp); + putstr(p->l2mode & MODE_s ? "S " : " ", mbp); + putstr(p->l2mode & MODE_h ? "M" : " ", mbp); +#else + putstr(p->l2mode & MODE_x ? "CTEXT " : " ", mbp); + putstr(p->l2mode & MODE_s ? "SYSOP " : " ", mbp); + putstr(p->l2mode & MODE_h ? "MH " : " ", mbp); + + l1hwstr(port, mbp); +#endif /* PORT_MANUELL */ + + putchr(CR, mbp); +} + +/************************************************************************/ +/* HELP */ +/*----------------------------------------------------------------------*/ +void ccphelp(void) /* HELP - Befehl */ +{ + struct ffblk fb; + char tmp[9]; + MBHEAD *mbp; + char file[80]; + char *cp; + WORD i,j; + WORD next = 0; + WORD cnt; + char *poi; +#ifndef MC68K + BOOLEAN found = FALSE; +#endif + + poi = clipoi; + cnt = clicnt; + + clipoi = clilin; + clicnt = strlen(clilin); + +#ifdef __WIN32__ + strupr(poi); +#endif + +#ifndef MC68K + if (issyso()) /* HELP.EXE fuer Sysops (OHS) suchen */ + found = !do_file(sysopexepath); + if (!found) /* HELP.EXE fuer User (OHU) suchen */ + found = !do_file(userexepath); + + if (found) /* wenn es HELP.EXE gibt, sind wir fertig */ + return; +#endif + + clipoi = poi; /* die alte Hilfe */ + clicnt = cnt; + + if (clicnt == 0) /* Kein Argument angegegen, kurzer HELP.TXT */ + { + strcpy(file,textpath); + strcat(file,"HELP.TXT"); + ccpread(file); + } + else + { + if (strnicmp((char *)clipoi, "INDEX", 5) == 0) /* Hilfe-Index ausgeben */ + { + mbp = putals("HELP - Index:\r"); + strcpy (file,textpath); + strcat (file,"*.HLP"); + if (xfindfirst(file, &fb, 0) == 0) + { + while (next == 0) + { + for (i = 0; i < 7; i++) + { + for (cp = fb.ff_name, j = 0; j < 8 && *cp != '.'; cp++, j++) + { + tmp[j] = *cp; + } + tmp[j] = '\0'; + putstr(tmp, mbp); + for ( ; j < 10; j++) + putchr(' ', mbp); + if ((next = xfindnext(&fb)) != 0) + break; + } + putchr('\r', mbp); + } + } + + prompt(mbp); + seteom(mbp); + } + else + { /* HILFE-Info fuer angegebenen Befehl suchen und ausgeben */ + + for (cp = tmp, i = 0; clicnt-- && i < 8 && isalnum(*clipoi); ++i) + *cp++ = (char) toupper(*clipoi++); + if (i < 8) + *cp++ = '*'; + *cp = '\0'; + + if (userpo->sysflg != 0) + { + sprintf(file, "%s%s.SLP", textpath, tmp); + if (i && !xfindfirst(file, &fb, 0)) { + strcpy(file, textpath); + strcat(file, fb.ff_name); + ccpread(file); + return; + } + } + + sprintf(file, "%s%s.HLP", textpath, tmp); + if (i && !xfindfirst(file, &fb, 0)) { + strcpy(file, textpath); + strcat(file, fb.ff_name); + ccpread(file); + return; + } + + mbp = putals("No HELP available for \'"); + putstr(strtok(file,"*."), mbp); + putstr("\'.\r",mbp); + prompt(mbp); + seteom(mbp); + } + } +} + +/************************************************************************/ +/* SUSPEND - Befehl */ +/*----------------------------------------------------------------------*/ +void ccpsusp(void) + { + SUSPEND *suspoi; + MBHEAD *mbp; + char call[L2IDLEN]; + WORD i; + WORD port; + int mode; + + if (!issyso()) { /* nur der Sysop darf SUSPEND */ + invmsg(); + return; + } + + if (skipsp(&clicnt, &clipoi)) { + mode = *clipoi++; + clicnt--; + port = nxtnum(&clicnt, &clipoi); + if (getcal(&clicnt, &clipoi, FALSE, call) == YES) + for (suspoi = sustab, i = 0; i < MAXSUSPEND; suspoi++, i++) { + if ( suspoi->port == port + && cmpcal(suspoi->call, call)) /* erstmal austragen */ + suspoi->call[0] = '\0'; + if ( mode == '+' + && suspoi->call[0] == '\0') { + memcpy(suspoi->call, call, L2CALEN); + suspoi->port = port; +#ifdef __WIN32__ + suspoi->okcount = (unsigned char)nxtnum(&clicnt,&clipoi); +#else + suspoi->okcount = nxtnum(&clicnt,&clipoi); +#endif /* WIN32 */ + break; + } + } + } + + mbp = putals("Suspended are\r"); + for (suspoi = sustab, i = 0; i < MAXSUSPEND; suspoi++, i++) + { + if (*suspoi->call != '\0') { + putcal(suspoi->call, mbp); +#ifdef SPEECH + putstr(speech_message(225), mbp); +#else + putstr(" is restricted ", mbp); +#endif + switch (suspoi->port) { + case 253: +#ifdef SPEECH + putstr(speech_message(226), mbp); +#else + putstr("to Access denied\r", mbp); +#endif + break; + case 254: +#ifdef SPEECH + putstr(speech_message(227), mbp); +#else + putstr("to level-2 access\r", mbp); +#endif + break; + case 255: +#ifdef SPEECH + putstr(speech_message(228), mbp); +#else + putstr("to max ", mbp); +#endif + putnum(suspoi->okcount,mbp); +#ifdef SPEECH + putstr(speech_message(229), mbp); +#else + putstr(" simultanous connections\r", mbp); +#endif + break; + default: +#ifdef SPEECH + putstr(speech_message(230), mbp); +#else + putstr("from using Port ", mbp); +#endif + putnum(suspoi->port, mbp); + putchr('\r', mbp); + } + } + } + prompt(mbp); + seteom(mbp); +} + +/**************************************************************************/ +/* READB - Datei lesen (binaer) DL1XAO */ +/*------------------------------------------------------------------------*/ +#ifdef MC68K +LONG swaplong(LONG)0x4840; /* SWAP.L D0 */ +#endif + +void +ccpreadb(void) +{ + char buf[1024]; + char fn[14]; + char *cp; + WORD i; + UWORD crc; + LONG pos; + LONG len; + MBHEAD *mbp; + + if (issyso() && userpo->convers == NULLCONNECTION) /* darf er ? */ + { + mbp = getmbp(); + i = 0; + for (cp = buf; clicnt-- && i < 128; i++) + *cp++ = (char) toupper(*clipoi++); + *cp = NUL; + userpo->fp = (i == 0) ? NULL : xfopen(buf, "rb"); + + if (userpo->fp != NULL) + { +#ifndef MC68302 + getftime(fileno(userpo->fp), (struct ftime *)&pos); +#else + getftime(buf, (struct ftime *)&pos); +#endif +#ifdef MC68K + pos = swaplong(pos); +#endif + if ((cp = strrchr(buf, FILE_SEP)) != NULL)/* Dateinamen isolieren */ + cp++; + else + cp = buf; + strncpy(fn, cp, 12); + fn[12] = NUL; + len = 0L; + crc = 0; /* CRC errechnen und Laenge bestimmen */ + while ((i = (WORD)fread(buf, 1, 1024, userpo->fp)) > 0) + { + len += i; + for (cp = buf; i--; cp++) + crc = crctab[crc >> 8] ^ ((crc << 8) | (UWORD)*cp); + } + + if (len != 0) + { + putprintf(mbp, "\r#BIN#%ld#|%u#$%08lX#%s\r", len, crc, pos, fn); + send_msg(TRUE, mbp); + fseek(userpo->fp, 0L, SEEK_SET); + userpo->status = US_SBIN; + return; + } + +#ifdef SPEECH + putstr(speech_message(231), mbp); +#else + putstr("File has no length!\r", mbp); +#endif + } + else +#ifdef SPEECH + putstr(speech_message(232), mbp); +#else + putstr("File not found!\r", mbp); +#endif + prompt(mbp); + seteom(mbp); + } + else + invmsg(); +} + +/************************************************************************/ +/* */ +/* ESC Befehl (nach einer Idee von DL9HCJ) */ +/* (Implementation: DL2LAY) */ +/* */ +/* Funktion : Ermoeglicht den Sysops den Remote-Zugriff auf Konsolen- */ +/* ESC-Befehle */ +/* Syntax : ESC */ +/*----------------------------------------------------------------------*/ +void ccpesc(void) +{ + MBHEAD *mbp; + char esctab[] = "@CITVY"; + + if (issyso()) + { + if (clicnt != 0) + { + if (strchr(esctab, toupper(*clipoi))) + { + blipoi = (char *)clipoi; + blicnt = clicnt; + hstcmd(mbp = (MBHEAD *) allocb(ALLOC_MBHEAD)); + mbp->l2link = g_ulink(userpo->uid); + mbp->type = g_utyp(userpo->uid); + prompt(mbp); + seteom(mbp); + } + else +#ifdef SPEECH + putmsg(speech_message(238)); +#else + putmsg("Invalid Hostcommand\r"); +#endif + } + } + else + invmsg(); +} + +/************************************************/ +/* L2-QSO killen */ +/************************************************/ +void ccpkill(void) { + #define ALLPORTS 255 + + MBHEAD *mbp, *msg; + WORD what = 0, i; + char call[L2IDLEN]; + char syscall[L2IDLEN]; +#ifdef __WIN32__ + char mask[MAXMASK]; + WORD port = 128; +#else + char mask[MAXMASK]; + UBYTE port = 128; +#endif + LNKBLK *savlp = lnkpoi; + BOOLEAN kill = 0; + UWORD kill_zaehler = 0; + + if (issyso()) + { + mbp = getmbp(); + cpyid (syscall,calofs(UPLINK, userpo->uid)); + + /* schaun ob ein Port angegeben wurde, wenn ja, dann diesen merken */ + + if ((*clipoi >= '0') && (*clipoi <= '9' )) + { +#ifdef __WIN32__ + if ((port = (unsigned char)nxtnum(&clicnt, &clipoi)) <= L2PNUM) what = 3; /* Port angegeben ? */ +#else + if ((port = nxtnum(&clicnt, &clipoi)) <= L2PNUM) what = 3; /* Port angegeben ? */ +#endif /* WIN32 */ + else port = 128; + } + + if (*clipoi == '*') + { + if (*clipoi != 0) clipoi++; + if (*clipoi != 0) clipoi++; + port = ALLPORTS; /* alle Ports killen ? */ + what = 3; + } + + if ((port == 128) && (strlen ((char *)clipoi) > 3)) /* Call killen ? */ + { + getcal(&clicnt, &clipoi, FALSE, call); + what = 1; + port = ALLPORTS; /* Call auf allen Ports abwerfen */ + } + + if (what) + { + skipsp(&clicnt, &clipoi); + + /* nun die L2-Liste durchsehen und User ggfs abwerfen */ + + for (lnkpoi = lnktbl, i = 0;i < LINKNMBR; ++lnkpoi, ++i) + { + if (lnkpoi->state && + ((lnkpoi->liport == port) || (port == ALLPORTS))) + { + switch (what) + { + case 1 : kill = (!strncmp (call, lnkpoi->srcid,7) || + !strncmp (call, lnkpoi->dstid,7)); + break; + case 2 : kill = (c6mtch(lnkpoi->srcid, mask) || + c6mtch(lnkpoi->dstid, mask) ); + break; + case 3 : if (!cmpid (lnkpoi->dstid,syscall)) + /* nicht den Sysop killen ! */ + kill = TRUE; /* jeden auf dem Port */ + else + kill = FALSE; + } + if (kill) + { + /*dealml((LEHEAD *)&lnkpoi->sendil);*/ /* clear send liste */ + /*lnkpoi->tosend = 0; */ /* alles weg */ + /*siehe Hinweis in L2DAMA */ + if ( *clipoi + && lnkpoi->state >= L2SIXFER) /* Msg ? */ + { + msg = (MBHEAD *) allocb(ALLOC_MBHEAD); /* Buffer besorgen */ + msg->l2link = lnkpoi; + msg->type = 2; +#ifdef SPEECH + putprintf(msg, speech_message(207), clipoi); +#else + putprintf(msg, "\r*** Msg from Sysop: %s ***\r", clipoi); +#endif + seteom(msg); + } + kill_zaehler++; /* zaehlen */ +#ifdef DEBUG + newlnk(); +#else + dsclnk(); /* und DISC */ +#endif + } + } + } + +#ifdef L4KILL + kill_zaehler += KillL4(call, clipoi); /* ggf. L4-User killen. */ +#endif /* L4KILL */ +#ifdef L1TCPIP + kill_zaehler += KillTCP(port, call, what); /* ggf. TCP-User killen. */ +#endif /* L1TCPIP */ + + if (!kill_zaehler) +#ifdef SPEECH + putstr(speech_message(233), mbp); +#else + putstr("No L2-link found.\r", mbp); +#endif + else +#ifdef SPEECH + putprintf(mbp, speech_message(208),kill_zaehler); +#else + putprintf(mbp, "%3u link(s) disconnected.\r",kill_zaehler); +#endif + } + else + { + putstr("Syntax: KILL [Port] [Msg]\r", mbp); + putstr(" KILL [Call] [Msg]\r", mbp); + putstr(" KILL * [Msg]\r", mbp); + } + + lnkpoi = savlp; /* Pointer restaurieren */ + prompt(mbp); /* Prompt */ + seteom(mbp); /* senden.... */ + } + else invmsg(); +} + +/*----------------------------------------------------------------------*/ +/* Save Befehl */ +/* */ +/* Funktion : speichert die Parameter-Datei, generiert eine Text-Datei, */ +/* die als TNNxxx.TNB benutzt werden kann (PARMS.TNB) */ +/* Syntax : SPARAM */ +/*----------------------------------------------------------------------*/ +void ccpsave(void) +{ + MBHEAD *mbp; + + if (!issyso()) + { + invmsg(); + return; + } + save_stat(); /* Stat speichern */ + save_parms(); /* Parameter */ + save_mh(); /* und MH-Liste */ +#ifdef USERPROFIL + SaveProfil(); /* und Profil sichern. */ +#endif /* USERPROFIL. */ +#ifdef GRAPH + save_graph(); +#endif + + mbp = getmbp(); +#ifdef SAVEPARAMFIX +#ifdef SPEECH + putprintf(mbp,speech_message(209), cfgfile); +#else + putprintf(mbp,"%s.TNB saved...\r", cfgfile); +#endif /* SPEECH */ +#else /* SAVEPARAMFIX */ + putstr("PARMS.TNB saved...\r", mbp); +#endif /* SAVEPARAMFIX */ + prompt(mbp); + seteom(mbp); +} + +/**************************************************************************/ +/* */ +/* TRACE-Befehl */ +/* */ +/* Funktion : Einloggen zur Systemueberwachung. */ +/* */ +/*------------------------------------------------------------------------*/ +void ccptrace(void) +{ + MBHEAD *mbp; +#ifdef USER_MONITOR + PTCENT *ptcp; +#endif /* USER_MONIOR */ + + /* Bestehendes Monitoring wird ausgeschaltet */ + if (userpo->monitor) { + moncmd(NULL, userpo->monitor, "N", 1); /* Monitor abschalten */ + dealoc((MBHEAD *)userpo->monitor); + userpo->monitor = NULL; + } + userpo->auditlevel = 0; + +#ifndef USER_MONITOR + if (issyso()) { + /* Audit-Level und Monitor setzen */ + userpo->auditlevel = nxtnum(&clicnt, &clipoi); +#else + /* Sysop, */ + if (issyso()) + /* darf Tracen, */ + userpo->auditlevel = nxtnum(&clicnt, &clipoi); + else + /* aber User nicht ! */ + userpo->auditlevel = 0; + + /* Nur wenn Monitor ausgeschalten ist. */ + if (!userpo->monitor) + { +#endif /* USER_MONITOR */ + if (skipsp(&clicnt, &clipoi)) { + userpo->monitor = (MONBUF *)allocb(ALLOC_MONBUF); + moncmd(NULL, userpo->monitor, clipoi, clicnt); + if (!userpo->monitor->Mpar) { /* er ist nicht angegangen */ + dealoc((MBHEAD *)userpo->monitor); + userpo->monitor = NULL; + } + } + + /* ... zur Kontrolle anzeigen */ + mbp = putals("Trace"); + if (userpo->auditlevel) + putlong(userpo->auditlevel, FALSE, mbp); + else + putstr(" is off", mbp); + + if (userpo->monitor) /* Monitor-Status zeigen */ +#ifdef USER_MONITOR + { + /* Sysop/User als Trace markieren. */ + userpo->status = US_TRAC; + /* Die User Pid ins Patchcord Liste uebergeben */ + ptcp = ptctab + userpo->uid; + /* User eigene PID ins Partner P_PID uebergeben */ + ptcp->p_uid = userpo->uid; + /* wird TRACE beendet, wechseln wir auf CCP um */ + ptcp->recflg = TRUE; + moncmd(mbp, userpo->monitor, "", 0); + } + else + { + /* Vom TRACE-Modus in den CCP wechseln */ + userpo->status = US_CCP; + /* User PID an die Patchcord Liste uebergeben */ + ptcp = ptctab + userpo->uid; + /* Partner PID -> NO_UID uebergeben */ + ptcp->p_uid = NO_UID; + /* Portangabe auf NUL setzen */ + putchr('\r', mbp); + } +#else + moncmd(mbp, userpo->monitor, "", 0); + else + putchr('\r', mbp); +#endif /* USER_MONITOR */ +#if MAX_TRACE_LEVEL < 9 + if (userpo->auditlevel > MAX_TRACE_LEVEL) + putprintf(mbp, "Warning: max. trace level of this TNN version is %d\r", + MAX_TRACE_LEVEL); +#endif + prompt(mbp); + seteom(mbp); /* senden.... */ + } else + invmsg(); +} + +/************************************************************************/ +/* */ +/* RUNBATCH */ +/* */ +/* Funktion : Batch ausfuehren (nur als Sysop) */ +/* */ +/*----------------------------------------------------------------------*/ +void ccprun(void) +{ + if (issyso()) { /* nur der Sysop darf */ + if (skipsp(&clicnt, &clipoi)) +#ifdef SPEECH + putmsg(runbatch((char*)clipoi) ? "OK\r" : speech_message(232)); +#else + putmsg(runbatch((char*)clipoi) ? "OK\r" : "File not found!\r"); +#endif + else + putmsg("Syntax: RUNBATCH FILENAME.TNB\r"); + } else + invmsg(); +} + +/**************************************************************************/ +/* */ +/* DCD */ +/* */ +/* Funktion : Status der DCD pro Port anzeigen (fuer alle) */ +/* */ +/*----------------------------------------------------------------------*/ +void ccpdcd(void) +{ + MBHEAD *mbp; + int port; + PORTINFO *p; + int dcd; + + mbp = putals("Data carrier detect:\r"); + for (port = 0; port < L2PNUM; port++) { + putprintf(mbp, "P%02u", port); + if (port <= 15) putchr(' ', mbp); + } + putchr('\r', mbp); + for (port = 0, p = portpar; port < L2PNUM; p++, port++) { + mbp->l4time = mbp->mbpc; + if (portenabled(port)) { + if ((dcd = iscd(port)) & DCDFLAG) + putstr(dcd & RXBFLAG ? "R" : "r", mbp); + if (dcd & PTTFLAG) + putstr(dcd & TXBFLAG ? "T" : "t", mbp); + } else + putstr("OFF", mbp); + if (port <= 15) putspa(4, mbp); + } + putchr('\r', mbp); + prompt(mbp); + seteom(mbp); +} +#ifdef BUFFER_DEBUG +void ccpbuf(void) +{ + MBHEAD *mbp; + MAX_BUFFER huge *actbp; + ULONG i, n; + ULONG used[ALLOC_MAXELEMENTE + 1]; + + mbp = putals("Buffer Usage:\r"); + for (i = 0; i < ALLOC_MAXELEMENTE + 1; i++) + used[i] = 0; + actbp = (MAX_BUFFER *)RAMBOT; + n = (ULONG)((RAMTOP - RAMBOT) / sizeof(MAX_BUFFER)); +#ifdef SPEECH + putprintf(mbp, speech_message(213), n, nmbfre_max, + sizeof(MAX_BUFFER)); +#else + putprintf(mbp, "\rAllBuffer : %lu (%lu) a %lu Bytes\r", n, nmbfre_max, + sizeof(MAX_BUFFER)); +#endif + + while (n--) + { + if ((UBYTE) ((USRBLK *)actbp)->owner >= ALLOC_MAXELEMENTE) + { + used[ALLOC_MAXELEMENTE]++; +#ifdef SPEECH + putprintf(mbp,speech_message(214), n, + (UBYTE) ((USRBLK *)actbp)->owner); +#else + putprintf(mbp,"Wrong Owner: Buffer:%lu Wert:%d\r", n, + (UBYTE) ((USRBLK *)actbp)->owner); +#endif + } + else + used[(UBYTE) ((USRBLK *)actbp)->owner]++; + actbp++; + } +#ifdef SPEECH + putprintf(mbp, speech_message(215), used[ALLOC_NO_OWNER], nmbfre); +#else + putprintf(mbp, "FreeBuffer: %lu (%lu)\r", used[ALLOC_NO_OWNER], nmbfre); +#endif + + putprintf(mbp, "LEHEAD : %lu\r", used[ALLOC_LEHEAD]); + putprintf(mbp, "MBHEAD : %lu\r", used[ALLOC_MBHEAD]); + putprintf(mbp, "USRBLK1: %lu\r", used[ALLOC_USRBLK1]); + putprintf(mbp, "USRBLK2: %lu\r", used[ALLOC_USRBLK2]); + putprintf(mbp, "L2LINK : %lu\r", used[ALLOC_L2LINK]); + putprintf(mbp, "MB : %lu\r", used[ALLOC_MB]); + putprintf(mbp, "MONBUF : %lu\r", used[ALLOC_MONBUF]); + putprintf(mbp, "CQBUF : %lu\r", used[ALLOC_CQBUF]); + putprintf(mbp, "IPROUTE: %lu\r", used[ALLOC_IP_ROUTE]); + putprintf(mbp, "ARPTAB : %lu\r", used[ALLOC_ARP_TAB]); + putprintf(mbp, "MHEARD : %lu\r", used[ALLOC_MHEARD]); + putprintf(mbp, "PACSAT : %lu\r", used[ALLOC_PACSATBLK]); +#ifdef USERPROFIL + putprintf(mbp, "USEPROF: %lu\r", used[ALLOC_USEPROF]); +#endif /* USERPROFIL. */ +#ifdef TCP_STACK + putprintf(mbp, "TCPSTA : %lu\r", used[ALLOC_TCPSTACK]); +#endif /* TCP_STACK */ +#ifdef L1TCPIP + putprintf(mbp, "TCPIP : %lu\r", used[ALLOC_L1TCPIP]); +#endif /* L1TCPIP */ +#ifdef L1HTTPD + putprintf(mbp, "HTTPDRX: %lu\r", used[ALLOC_L1HTTPD_RX]); + putprintf(mbp, "HTTPDTX: %lu\r", used[ALLOC_L1HTTPD_TX]); +#endif /* L1HTTPD */ + putprintf(mbp, "INPOPT : %lu\r", used[ALLOC_INPOPT]); + if (used[0] != 0L) + putprintf(mbp, "??? : %lu\r", used[0]); +#ifdef SPEECH + putprintf(mbp, speech_message(216), used[ALLOC_MAXELEMENTE]); +#else + putprintf(mbp, "Errors : %lu\r", used[ALLOC_MAXELEMENTE]); +#endif + prompt(mbp); + seteom(mbp); +} +#endif + +/* End of src/l7cmds.c */ diff --git a/src/l7conn.c b/src/l7conn.c new file mode 100755 index 0000000..95f53b7 --- /dev/null +++ b/src/l7conn.c @@ -0,0 +1,1239 @@ +/************************************************************************/ +/* */ +/* ***** ***** */ +/* ***** ***** */ +/* ***** ***** */ +/* ***** ***** */ +/* *************** *************** */ +/* ***************** ***************** */ +/* *************** *************** */ +/* ***** ***** TheNetNode */ +/* ***** ***** Portable */ +/* ***** ***** Network */ +/* ***** ***** Software */ +/* */ +/* File src/l7conn.c (maintained by: DF6LN) */ +/* */ +/* This file is part of "TheNetNode" - Software Package */ +/* */ +/* Copyright (C) 1998 - 2008 NORD>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 */ diff --git a/src/l7host.c b/src/l7host.c new file mode 100755 index 0000000..2fd73ac --- /dev/null +++ b/src/l7host.c @@ -0,0 +1,1398 @@ +/************************************************************************/ +/* */ +/* ***** ***** */ +/* ***** ***** */ +/* ***** ***** */ +/* ***** ***** */ +/* *************** *************** */ +/* ***************** ***************** */ +/* *************** *************** */ +/* ***** ***** TheNetNode */ +/* ***** ***** Portable */ +/* ***** ***** Network */ +/* ***** ***** Software */ +/* */ +/* File src/l7host.c (maintained by: DF6LN) */ +/* */ +/* This file is part of "TheNetNode" - Software Package */ +/* */ +/* Copyright (C) 1998 - 2008 NORD>conflg = 0; + hstusr->disflg = 0; + hstusr->inlin = 0; + hstusr->outlin = 0; + hstusr->outsta = 0; +#else + hstusr->conflg = + hstusr->disflg = + hstusr->inlin = + hstusr->outlin = + hstusr->outsta = +#endif /* WIN32 */ + hstusr->direction = 0; + inithd(&hstusr->inbuf); + inithd(&hstusr->outbuf); + cpyid(hstusr->call, hostid); + } + hlixfl = FALSE; + incnt = 0; + monlin = stalin = 0; + tnnb_aktiv = FALSE; + last_hour = 30; + last_min = 70; + + xremove(tmp_tnb); /* temporaer-File loeschen */ + strcpy(startup, cfgfile); + strcat(startup, ".TNB"); + if ((startup_running = runbatch(startup)) == TRUE) + { +#ifndef MC68302 + pro_file = xfopen("STARTUP.LOG", "wt+"); +#else + pro_file = NULL; /* Platz sparen und Zeit */ +#endif +#ifdef ST + setvbuf(pro_file, NULL, _IOFBF, 4096L); /* speedup */ +#endif + } + else + xprintf("*** WARNING: %s not found!\r", startup); +} + +/************************************************************************/ +/* */ +/* */ +/* */ +/************************************************************************/ +void +exit_host(void) +{ + exit_console(); +} + +/************************************************************************/ +/* */ +/* "host to level 7" */ +/* */ +/* Hier begegnet uns mal wieder das Problem mit dem globalen userpo */ +/* usw., wir duerfen hier nicht l2tol7 aufrufen, weil wir selber aus */ +/* l7tx() aufgerufen wurden und eventuell die Userliste oder userpo */ +/* geaendert werden. Das Prinzip Bottom-Up (Meldungen nur von unten */ +/* nach oben) muss gewahrt bleiben, also melden wir spaeter. */ +/* */ +/************************************************************************/ +static void +hstol7(WORD status, void *link) +{ + MBHEAD *mbhd; + + (mbhd = (MBHEAD *)allocb(ALLOC_MBHEAD))->type = status; + mbhd->l2link = link; + relink((LEHEAD *)mbhd, (LEHEAD *)hstatl.tail); +} + +/************************************************************************/ +/* */ +/* "terminal mode response message buffer bell" */ +/* */ +/************************************************************************/ +static void +trpmbb(MBHEAD *mbp) +{ + hputs("\r* "); + rwndmb(mbp); + hputmb(mbp); + if (stamp) + { + hputs(" - "); + hputbt(&mbp->btime); + } + hputs(" *\007\r"); +} + +/************************************************************************/ +/* */ +/* "terminal mode line editor" */ +/* */ +/************************************************************************/ +static BOOLEAN +termle(unsigned ch) +{ + if (incnt == 0) + inbufp = hinbuf; /* leere Zeile: Pointer = Start */ + + switch (ch) /* ueber Eingabe verzweigen */ + { + case CR: + hputc(CR); /* abspeichern */ + if (hinbuf[0] != ESC) /* Textzeilen mit CR */ + { + *inbufp++ = CR; + incnt++; + } + *inbufp = NUL; /* Ende markieren */ + blipoi = hinbuf; /* blipoi auf Eingabezeile */ + blicnt = incnt; /* Laenge merken */ + inbufp = hinbuf; /* wieder auf Start */ + incnt = 0; /* neue Zeile beginnt */ + + if (console_login_status) /* ist Console eingeloggt ? */ + return (TRUE); /* eine Zeile ist fertig */ + else + { + if (strnicmp((char *)blipoi, "\x1BJHOST", 6) == 0) + { + blipoi += 2; /* ESC uebergehen */ + blicnt -= 2; + Jcmd(); /* Umschaltung ermoeglichen */ + break; + } + if (strstr((char *)blipoi, pass) == (char *)blipoi) + { + console_login_status = 1; /* die Console einloggen */ +#ifdef SPEECH + hprintf(speech_message(242), signon); +#else + hprintf("Welcome to %s", signon); +#endif + hputid(myid); + hputs(")\r"); + } + else + hputs("password: "); + } + break; + + case BS: /* BS und DEL werden gleich */ + case DEL: /* behandelt und loeschen */ + if (incnt) /* destruktiv. Sie werden aber */ + bliloe(); /* ignoriert. */ + break; + + case 0x15: /* ctl-U und */ + case 0x18: /* ctl-X loeschen Eingabezeile */ + while (incnt) + bliloe(); + break; + + case XON: /* XON loescht Flag */ + hlixfl = FALSE; + break; + + case XOFF: /* XOFF setzt Flag */ + hlixfl = TRUE; + break; + + default: + if ((incnt < 255) + && ((ch >= ' ') || (ch == ESC) || (ch == 26))) + { + blieco(ch); + *inbufp++ = ch; + ++incnt; + } + else + hputc(BELL); /* Zeile voll: meckern */ + } + return (FALSE); +} + +/************************************************************************/ +/* */ +/* "to host" */ +/* */ +/************************************************************************/ +static void +tohost(void) +{ + MBHEAD *mbp; + + if (nmbfre < 14) /* kein Speicher */ + { + if (!ishmod) + hprintf("* %s *\007\n", hm_err[HMELIG]); + else + { +#ifdef __WIN32__ + hputc((char)actch); +#else + hputc(actch); +#endif /* WIN32 */ + hputs(hm_err[HMELIG]); + } + return; + } + if (!hstusr->conflg) /* nicht connected? */ + { + if (!ishmod) + { +#ifdef SPEECH + hprintf(speech_message(243)); +#else + hprintf("* CHANNEL NOT CONNECTED *\007\n"); +#endif + return; + } + } + else + { + if (!(hstusr->disflg & 0x80)) /* schon DISCed */ + { + mbp = (MBHEAD *)allocb(ALLOC_MBHEAD); + while (blicnt--) + putchr(*blipoi++, mbp); + rwndmb(mbp); + relink((LEHEAD *)mbp, (LEHEAD *)hstusr->inbuf.tail); + ++hstusr->inlin; + hstsen(FALSE); /* Info an Rest des Programms */ + } + } + if (ishmod && !tnb_ch) + { +#ifdef __WIN32__ + hputc((char)actch); +#else + hputc(actch); +#endif /* WIN32 */ + hputc(0); + } +} + +/************************************************************************/ +/* */ +/* "service batch channel" */ +/* */ +/************************************************************************/ +static void +srvbch(void) +{ + MBHEAD *mbp; + char bline[256]; /* nicht die Host-Buffer! */ + USRBLK *user; + + hstusr = hstubl; /* auf den System-Kanal */ + +/* eingelaufene Infos ausgeben, Statusmeldungen ignorieren */ + + while ((LHEAD *)hstusr->outbuf.head != &hstusr->outbuf) + { + mbp = (MBHEAD *)ulink((LEHEAD *)hstusr->outbuf.head); + if (mbp->type == L2MNIX) /* Info-Frame */ + { + --hstusr->outlin; /* ein Frame weniger */ + cputmb(mbp); /* Frame ausgeben */ + } + else /* Meldung */ + --hstusr->outsta; /* eine Meldung weniger */ + dealmb(mbp); /* Buffer dann auf den Muell */ + } + +/* abarbeiten von Batch-Files */ + + if (tnnb_aktiv) + { + +/* ggf. erstmal zum Knoten connecten */ + + if (!hstusr->conflg) + { + hstcon(1); + return; + } + +/* der Befehl muss erst komplett ausgefuehrt sein, bevor der naechste */ +/* gestartet wird, d.h. saemtliche Ausgaben muessen beendet sein. */ + + user = (ptctab + g_uid(hstusr, HOST_USER))->ublk; + if (hstusr->outlin + || hstusr->outsta + || (user->status > US_CCP) + || (user->fp != NULL)) + return; + +/* Naechsten Befehl holen und in Protokollfile schreiben (wenn */ +/* verwendet). Befehle werden mit CR terminiert. */ + + if (fgets(bline, 255, tnnb_file)) + { + bline[255] = NUL; /* auf jeden Fall terminieren */ + if ((blipoi = strchr(bline, '\n')) != NULL) + { + if (pro_file != NULL) /* ggf. Befehl in ein Protokollfile */ + fputs(bline, pro_file); + *blipoi = CR; /* '\n' durch CR ersetzen */ + } + blipoi = bline; + blicnt = strlen((char *)blipoi); /* Laenge ermitteln */ + tohost(); /* Info an den L7 */ + } + else + { + if (hstusr->inlin || hstusr->outlin)/* noch Reste zu verarbeiten? */ + return; + fclose(tnnb_file); /* File wieder schliessen */ + xremove(tmp_tnb); /* temporaer-File loeschen */ + tnnb_aktiv = FALSE; + if ((hstusr->conflg) + && (user->auditlevel == 0) + && (user->monitor == NULL)) + hstdis(); /* Kanal rauswerfen */ + } + } + else + { + if (startup_running) + { + if (pro_file != NULL) + { + fclose(pro_file); + pro_file = NULL; + } + startup_running = FALSE; + } + } +} + +/************************************************************************/ +/* */ +/* "service host channel" */ +/* */ +/************************************************************************/ +static void +srvhch(void) +{ + MBHEAD *mbp; + unsigned ch; + static int hmstat = 0; /* Hostmode Status */ + static int hmch; /* Hostmode Kanal */ + static int hmcmd; /* Hostmode Befehl */ + static int hmlen; /* Hostmode Datenbytes */ + +/* Kanaele disconnecten, wenn disco gefordert und alle Info abgeholt */ + + for (hstusr = &hstubl[1]; hstusr < &hstubl[MAXHST]; hstusr++) + if (((hstusr->disflg & 0x80) != 0) + && (hstusr->outlin == 0) + && (hstusr->outsta == 0)) + hstdis(); + + hstusr = &hstubl[actch]; /* auf aktuellen Kanal */ + if (!ishmod) /* kein Hostmode? */ + { + if (!ishput()) /* keine Reste auszugeben */ + if (!incnt && !hlixfl) /* wenn am Zeilenanfang und */ + { /* kein XOFF Status */ + while (stalin) /* solange noch Meldungen */ + { + mbp = (MBHEAD *)ulink((LEHEAD *)statml.head); + trpmbb(mbp); + dealmb(mbp); + stalin--; + } + while (monlin) /* solange Frames fuer Monitor */ + { + mbp = (MBHEAD *)ulink((LEHEAD *)smonfl.head); + rwndmb(mbp); + hputmb(mbp); + hputc('\r'); + dealmb(mbp); + monlin--; + } + +/* eingelaufene Infos ausgeben */ + + while ((LHEAD *)hstusr->outbuf.head != &hstusr->outbuf) + { + mbp = (MBHEAD *)ulink((LEHEAD *)hstusr->outbuf.head); + if (mbp->type == L2MNIX) /* Info-Frame */ + { + --hstusr->outlin; /* ein Frame weniger */ + hputmb(mbp); /* Frame ausgeben */ + if (mbp->l4type != HMRINFO) + hputs(" *\r"); + } + else /* Meldung */ + { + --hstusr->outsta; /* eine Meldung weniger */ + trpmbb(mbp); /* Meldung ausgeben */ + } + dealmb(mbp); /* Buffer dann auf den Muell */ + } + } + + if (monlin > 50) /* damit der Knoten nicht voll- */ + { /* laeuft */ + dealml((LEHEAD *)&smonfl); + monlin = 0; /* Monitor leeren */ + } + + if (ishget()) /* nun Eingaben bearbeiten: */ + { + ch = hgetc(); /* Zeichen holen, wenn vorhanden */ + if (termle(ch)) /* Zeile fertig? */ + { + if (*blipoi == ESC) /* Befehl eingegeben? */ + { + *blipoi++ = 0x00; + --blicnt; + skipsp(&blicnt, &blipoi); + hstcmd((MBHEAD *)NULL); /* Befehl ausfuehren */ + } + else /* Info fuer Kanal */ + tohost(); + } + } + } + else /* Hostmode */ + { + while (ishget()) + { + ch = hgetc(); /* ein Zeichen lesen */ + switch (hmstat) + { + case 0: /* CHANNEL */ + hmch = ch; + ++hmstat; + break; + + case 1: /* COMMAND */ + hmcmd = ch; + ++hmstat; + break; + + case 2: /* LENGTH */ + hmlen = ch; + ++hmstat; + inbufp = hinbuf; + incnt = 0; + break; + + case 3: + *inbufp++ = ch; + ++incnt; + if (hmlen != 0) + --hmlen; + else /* Hostmode-Packet komplett da */ + { + hmstat = 0; + actch = hmch; + if ((actch < MAXHST) + || ((actch == 0xFF) + && (hmcmd == TRUE) + && (toupper(*hinbuf) == 'G'))) + { + if ((actch != 0) + && (actch != 0xFF)) + hstusr = &hstubl[actch]; + blipoi = hinbuf; + blicnt = incnt; + if (hmcmd) /* Befehl? */ + { + skipsp(&blicnt, &blipoi); + hstcmd((MBHEAD *)NULL); /* Konsolen-Befehl ausfuehren */ + } + else /* Info */ + if (actch) + tohost(); /* an den L7 senden */ + else + { + if (hmdest[0] != ' ') + { + (mbp = (MBHEAD *)allocb(ALLOC_MBHEAD))->l2fflg = L2CPID; + inbufp = hinbuf; + while (incnt--) + putchr(*inbufp++, mbp); + rwndmb(mbp); +#ifdef __WIN32__ + sdui(hmdigil, hmdest, hostid, (char)hmport, mbp); +#else + sdui(hmdigil, hmdest, hostid, hmport, mbp); +#endif /* WIN32 */ + dealmb(mbp); + } +#ifdef __WIN32__ + hputc((char)actch); /* Info an Monitor-Kanal */ +#else + hputc(actch); /* Info an Monitor-Kanal */ +#endif /* WIN32 */ + hputc(0); /* ignorieren */ + } + } + else /* Fehler */ + { + hmputr(HMRFMSG); + hputs("INVALID CHANNEL NUMBER"); + hputc(0); + } + actch = 1; /* Schutzmassnahme XAO 050100 */ + } + break; + } + } + } + hstsen(FALSE); /* Info an Rest des Programms */ +} + +/************************************************************************/ +/* */ +/* Host_Service */ +/* */ +/* Statusmeldungen an L7 weiterleiten, Batches ausfuehren, Konsole */ +/* bedienen. */ +/* */ +/************************************************************************/ +void +hostsv(void) +{ + MBHEAD *mbhd; + + while ((LHEAD *)hstatl.head != &hstatl) + { + mbhd = (MBHEAD *)ulink((LEHEAD *)hstatl.head); + l2tol7(mbhd->type, mbhd->l2link, HOST_USER); + dealoc(mbhd); + } + + tnb_ch = TRUE; + srvbch(); /* Batch-Kanal behandeln */ + tnb_ch = FALSE; + srvhch(); /* Host-Kanaele auch */ +} + +/************************************************************************/ +/* */ +/* Batches ausfuehren. */ +/* */ +/************************************************************************/ +BOOLEAN +runbatch(char *batchname) +{ + FILE *batch_file; + char line[256]; + char *lp; + LONG oldpos = 0L; + + strcpy(line, batchname); + if (strchr(line, '.') == NULL) + strcat(line, ".TNB"); + batch_file = xfopen(line, "rt"); + if (!batch_file) + return (FALSE); /* nicht gefunden! */ + if (tnnb_aktiv) /* laeuft schon ein Batch? */ + { + oldpos = ftell(tnnb_file); /* Position merken */ + fclose(tnnb_file); /* ... das ist zum lesen! */ + } + tnnb_file = xfopen(tmp_tnb, "at"); + if (!tnnb_file) /* Temp-File geht nicht auf? */ + { + fclose(batch_file); + tnnb_aktiv = FALSE; + return (FALSE); /* Fehler! */ + } +#ifdef ST + setvbuf(tnnb_file, NULL, _IOFBF, 4096L); /* speedup */ +#endif + +/* Eine Zeile aus Batchfile einlesen, Zeile beim ersten ";" oder "\n" */ +/* beenden. Tabs entfernen, sonst kommt der CPP durcheinander. Leer- */ +/* zeichen am Zeilenende werden ebenfalls entfernt. */ + + while (fgets(line, 255, batch_file) != NULL) + { + line[strcspn(line, ";\n\r")] = NUL; + while ((lp = strchr(line, 9)) != NULL) + *lp = 32; + lp = strchr(line, 0) - 1; /* Zeilenende */ + while ((lp > line) && (*lp == 32)) + *lp-- = NUL; + +/* Zeilen mit "#" am Zeilenanfang als ESC-Befehl in Temporaer-File, */ +/* andere Zeilen unveraendert ins Temporaer-File. Leerzeilen ignorieren */ + + if (line[0]) + { + if (line[0] == '#') + fprintf(tnnb_file, "ESC %s\n", &line[1]); + else + fprintf(tnnb_file, "%s\n", line); + } + } + + fclose(tnnb_file); /* File wieder schliessen */ + fclose(batch_file); /* auch Batch File */ + tnnb_file = xfopen(tmp_tnb, "rt"); /* ... und zum Lesen oeffnen */ + if (tnnb_file) + { + fseek(tnnb_file, oldpos, SEEK_SET); + tnnb_aktiv = TRUE; /* Markieren -> Batch laeuft */ + } + return (tnnb_aktiv); +} + +/************************************************************************/ +/* */ +/* Host-Timer */ +/* */ +/* Noactivity-Timer fuer Konsolen-Kanaele reduzieren und ggf. Kanal */ +/* disconnecten. Zur vollen Stunde Batches starten. */ +/* */ +/************************************************************************/ +void +hostim(void) +{ + WORD i; + char tnnb_d_name[15]; + char tnnb_w_name[15]; + WORD fertig; + struct ffblk tnnb_f; + + if (!tnnb_aktiv) + for (i = 1, hstusr = hstubl + 1; i < MAXHST; i++, hstusr++) + { + if (hstusr->conflg) + { + if ((hstusr->noacti != 0) && (--hstusr->noacti == 0)) + hstdis(); + } + } + hstusr = &hstubl[actch]; /* auf aktuellen Kanal */ + + if (sys_localtime->tm_min != last_min) + { + last_min = sys_localtime->tm_min; /* aktuelle Minute merken */ + if (xaccess("NOW.TNB", 0) == 0) + { + runbatch("NOW.TNB"); + xremove("NOW.TNB"); + } + } + + if (sys_localtime->tm_hour != last_hour) + { + +/* Stuendlich kontrollieren, ob ein passendes TNB-File existiert. Dazu */ +/* die gesuchten Filenamen fuer taeglichen und woechentlichen Job */ +/* aus aktuellem Datum und aktueller Zeit generieren. */ + + last_hour = sys_localtime->tm_hour; /* aktuelle Stunde merken */ + sprintf(tnnb_d_name, "%02d%02d%02d%02d.TNB", + sys_localtime->tm_year % 100, sys_localtime->tm_mon + 1, + sys_localtime->tm_mday, sys_localtime->tm_hour); + sprintf(tnnb_w_name, "%02d%02dW%1.1d%02d.TNB", + sys_localtime->tm_year % 100, sys_localtime->tm_mon + 1, + sys_localtime->tm_wday, sys_localtime->tm_hour); + +/* Nun nach allen passenden Files suchen, Wildcards beachten. */ + + fertig = xfindfirst("*.TNB", &tnnb_f, 0); + while (!fertig) + { + for (i = 0; i < 8; i += 2) /* Beide Buffer testen */ + { + if (tnnb_f.ff_name[i] == '#') + continue; + if (strnicmp(&tnnb_f.ff_name[i], &tnnb_d_name[i], 2) + && strnicmp(&tnnb_f.ff_name[i], &tnnb_w_name[i], 2)) + break; /* Abbruch beim ersten nicht passenden Zeichen */ + } + if (i == 8) /* Name stimmt? */ + runbatch(tnnb_f.ff_name); /* Batch ausfuehren */ + fertig = xfindnext(&tnnb_f); /* nichts gefunden, weitersuchen */ + } + } +} + +/************************************************************************/ +/* */ +/* Connect-Wunsch zum Host bearbeiten */ +/* */ +/************************************************************************/ +BOOLEAN +hstreq(void) +{ + MBHEAD *mbp; + + if (numhsts < Ypar) + { + hstcon(0); + } + else + { +#ifdef SPEECH + putstr(speech_message(246), mbp = (MBHEAD *)allocb(ALLOC_MBHEAD)); +#else + putstr("CONNECT REQUEST fm ", mbp = (MBHEAD *)allocb(ALLOC_MBHEAD)); +#endif + putid(hstusr->call, mbp); + mbp->btime = sys_time; + mbp->type = L2MBUSYT; + relink((LEHEAD *)mbp, (LEHEAD *)statml.tail); + stalin++; + hstol7(L2MBUSYF, hstusr); + cpyid(hstusr->call, hostid); + return (FALSE); + } + return (TRUE); +} + +/************************************************************************/ +/* */ +/* Host-User wurde vom CCP disconnected. */ +/* */ +/************************************************************************/ +void +hstout(void) +{ + dealml((LEHEAD *)&hstusr->inbuf); + hstusr->inlin = 0; + hstusr->disflg |= 0x80; +} + +/************************************************************************/ +/* */ +/* Info vom L7 an Host */ +/* */ +/************************************************************************/ +BOOLEAN +itohst(BOOLEAN conflg, MBHEAD *ublk) +{ + HOSTUS *hostp; + + hostp = (HOSTUS *)ublk->l2link; + + if (hostp == hstubl) /* im Batch-Modus keine */ + conflg = TRUE; /* Erstickungskontrolle. */ + + if ((conflg == TRUE) + || (hostp->outlin < conctl)) + { + if ((ublk->mbpc - ublk->mbgc) == 0) /* Frames ohne Info ignorieren */ + { + dealmb((MBHEAD *)ulink((LEHEAD *)ublk)); + return (TRUE); + } + relink(ulink((LEHEAD *)ublk), (LEHEAD *)hostp->outbuf.tail); + ublk->type = L2MNIX; /* Info-Frame (keine Meldung) */ + ublk->l4type = HMRINFO; + ++hostp->outlin; + hostp->noacti = ininat; + return (TRUE); + } + return (FALSE); +} + +/************************************************************************/ +/* */ +/* Echo fuer Konsole */ +/* */ +/************************************************************************/ +void +blieco(int zeichen) +{ + if (console_login_status) + { + if (incnt == 0 && zeichen == ESC) + hputs("* "); + else +#ifdef __WIN32__ + hputcc((char)zeichen); +#else + hputcc(zeichen); +#endif /* WIN32 */ + } + else /* Password als ***** anzeigen */ + hputc('*'); +} + +/************************************************************************/ +/* */ +/* 1 eingegebenes Zeichen im Buffer und in der Anzeige loeschen */ +/* */ +/************************************************************************/ +void +bliloe(void) +{ + char ch; + + if ((ch = *(--inbufp)) != BELL) + { + bputbs(); + if (ch < ' ') + bputbs(); + } + else + hputc(ch); + --incnt; +} + +/************************************************************************/ +/* */ +/* 1 Zeichen in der Anzeige loeschen */ +/* */ +/************************************************************************/ +void +bputbs(void) +{ + hputs("\010 \010"); +} + +/************************************************************************/ +/* */ +/* Konsolenbefehle bearbeiten, auch ESC-Befehl im CCP */ +/* */ +/************************************************************************/ +void +hstcmd(MBHEAD *mbpoi) +{ + HOSTCMD *cmdpoi; + + if (skipsp(&blicnt, &blipoi)) + { + +/* Befehl in Befehlsliste suchen */ + + for (cmdpoi = hostcmdtab; cmdpoi->cmdfun != NULL; ++cmdpoi) + { + if (toupper(*blipoi) == *cmdpoi->cmdstr) + { + ++blipoi; + --blicnt; + break; + } + } + if (cmdpoi->cmdfun != NULL) /* Befehl gefunden */ + { + hstmbp = mbpoi; + if (hstmbp == NULL) /* Aufruf von Terminal / Hostmode */ + hstmbp = (MBHEAD *)allocb(ALLOC_MBHEAD); + else + tnb_ch = TRUE; /* Aufruf vom CCP */ + hstmbp->type = L2MNIX; + hstmbp->l4type = HMRINFO; + + (*cmdpoi->cmdfun) (); /* Befehl ausfuehren */ + + if (mbpoi == NULL) /* Aufruf von Terminal / Hostmode */ + { + hstusr->noacti = ininat; /* Timeout zuruecksetzen */ + rwndmb(hstmbp); + if (!ishmod) /* Terminalmode */ + { + if (hstmbp->mbpc != 0) /* Antwort vorhanden */ + { + hputmb(hstmbp); + if (hstmbp->l4type != HMRINFO) + hputs(" *\n"); + if (hstmbp->l4type == HMRFMSG) + hputc('\007'); + } + } + else /* Hostmode */ + { + while (hstmbp->mbpc > hstmbp->mbgc) + hputc(getchr(hstmbp)); + if (hstmbp->l4type < HMRMONI) /* Meldung mit '\0' beenden */ + hputc(0); + } + dealmb(hstmbp); + } + else /* Aufruf vom CCP */ + if (hstmbp->mbpc > hstmbp->mbgc) /* wenn Antwort im Buffer */ + putchr('\r', hstmbp); /* hinterher */ + return; + } + if (mbpoi != NULL) +#ifdef SPEECH + putstr(speech_message(247), hstmbp); +#else + putstr("INVALID COMMAND\r", hstmbp); +#endif + else + { + hmputr(HMRFMSG); + if (!ishmod) + hputs("* "); + hputs("INVALID COMMAND: "); + hputcc(*blipoi); + if (!ishmod) + hputs(" *\007\r"); + else + hputc(0); + } + return; + } + if (ishmod) + hmputr(0); +} + +/************************************************************************/ +/* */ +/* "status to channel" */ +/* */ +/************************************************************************/ +static void +sttoch(unsigned msg) +{ + MBHEAD *mbp; + CIRBLK *cp; + UID uid; + const char *vp; + + if (tnb_ch) /* keine Meldung fuer TNBs */ + return; + + putprintf(mbp = (MBHEAD *)allocb(ALLOC_MBHEAD), + "(%u) ", (unsigned)(hstusr - hstubl)); +#ifdef SPEECH + putstr(msg == L2MCONNT ? speech_message(244) : speech_message(245), mbp); +#else + putstr(msg == L2MCONNT ? "CONNECTED to " : "DISCONNECTED fm ", mbp); +#endif + + if (hstusr->direction) + putid(myid, mbp); + else + { + putid(hstusr->call, mbp); + if (msg == L2MCONNT) + { + uid = userpo->uid; + switch (g_utyp(uid)) + { + case L2_USER: + putdil(((LNKBLK *)g_ulink(uid))->viaidl, mbp); + break; + + case L4_USER: + cp = g_ulink(uid); + if ((!cmpid(cp->upnod, cp->downca)) + || (*(cp->upnodv) != NUL)) + { + putstr(" via ", mbp); + putid(cp->upnod, mbp); + vp = cp->upnodv; + while (*vp != NUL) + { + putchr(' ', mbp); + putid(vp, mbp); + vp += L2IDLEN; + } + } + break; + } + } + } + + mbp->btime = sys_time; + mbp->type = msg; + if (!ishmod) + { + relink((LEHEAD *)mbp, (LEHEAD *)statml.tail); + stalin++; + } + else + { + relink((LEHEAD *)mbp, (LEHEAD *)hstusr->outbuf.tail); + hstusr->outsta++; + } +} + +/************************************************************************/ +/* */ +/* Hostmode-Kanal Connecten */ +/* */ +/************************************************************************/ +void +hstcon(char direction) +{ + hstusr->direction = direction; + sttoch(L2MCONNT); + hstol7(L2MCONNT, hstusr); + hstusr->conflg = 1; + hstusr->noacti = ininat; + +#ifdef HOSTMYCALL + cpyid(hstusr->call, hostuserid); +#endif /* HOSTMYCAL */ + + resptc(g_uid(hstusr, HOST_USER)); + numhsts++; +} + +/************************************************************************/ +/* */ +/* Host-Kanal disconnecten */ +/* */ +/************************************************************************/ +void +hstdis(void) +{ + dealml((LEHEAD *)&hstusr->inbuf); + dealml((LEHEAD *)&hstusr->outbuf); + hstusr->inlin = + hstusr->outlin = + hstusr->outsta = 0; + sttoch(L2MDISCF); + hstol7(L2MDISCF, hstusr); + resptc(g_uid(hstusr, HOST_USER)); + + hstusr->conflg = + hstusr->disflg = 0; + cpyid(hstusr->call, hostid); + + numhsts--; +} + +/************************************************************************/ +/* */ +/* Informationstransfer von Host nach Layer X */ +/* ------------------------------------------ */ +/* */ +/* Solange noch empfangene Pakete vorhanden sind, werden diese */ +/* an andere Layer durch Aufruf von fmlink() uebertragen. Bei ge- */ +/* setztem Ueberfuellungskontroll-Flag (conctl == TRUE) wird die */ +/* Uebertragung abgebrochen, wenn der andere Layer keine weiteren */ +/* Daten mehr aufnehmen kann. */ +/* */ +/* Nach erfolgter Uebertragung wird der No-Activity-Timer neu */ +/* gesetzt. */ +/* */ +/************************************************************************/ +void +hstsen(BOOLEAN conctl) +{ + MBHEAD *mbp; + + if ((hstusr - hstubl) >= MAXHST) + return; + while (hstusr->inlin != 0) + { + mbp = (MBHEAD *)hstusr->inbuf.head; + mbp->l2link = (LNKBLK *)hstusr; + mbp->type = HOST_USER; + mbp->l2fflg = L2CPID; + if (!fmlink(conctl, mbp)) + break; + hstusr->noacti = ininat; + --hstusr->inlin; + } +} + +/************************************************************************/ +/* */ +/* Rufzeichen mit SSID an der Konsole anzeigen. */ +/* */ +/************************************************************************/ +void +hputid(char *id) +{ + WORD ssid; + WORD i; + char ch; + + for (i = 0; i < L2CALEN; ++i) + if ((ch = *id++ & 0xFF) != ' ') + hputcc(ch); + if ((ssid = (*id >> 1) & 0x0F) != 0) + hprintf("-%d", ssid); +} + +/************************************************************************/ +/* */ +/* Zeichen an der Konsole anzeigen, Steuerzeichen mit "^" vorweg. */ +/* */ +/************************************************************************/ +void +hputcc(char c) +{ + if (c >= ' ') + hputc(c); + else + { + hputc('^'); +#ifdef __WIN32__ + hputc((char)(c + '@')); +#else + hputc(c + '@'); +#endif /* WIN32 */ + } +} + +/************************************************************************/ +/* */ +/* Uhrzeit aus Buffer an der Konsole anzeigen. */ +/* */ +/************************************************************************/ +void +hputbt(time_t * t) +{ + struct tm *p; + + p = localtime(t); + hprintf("%02u.%02u.%02u %02u:%02u:%02u", + p->tm_mday, p->tm_mon + 1, p->tm_year % 100, + p->tm_hour, p->tm_min, p->tm_sec); +} + +/************************************************************************/ +/* */ +/* String an der Konsole formatiert anzeigen. */ +/* */ +/************************************************************************/ +void +hprintf(const char *format,...) +{ + va_list arg_ptr; + char str[256]; + + va_start(arg_ptr, format); + vsprintf(str, format, arg_ptr); + va_end(arg_ptr); + hputs(str); +} + +/************************************************************************/ +/* */ +/* Text auf die Console ausgeben, nicht unbedingt an das Host-Interface.*/ +/* xprintf() wird fuer Status-Ausgaben genutzt, die den Hostmode durch- */ +/* einander bringen koennten. */ +/* Der TNC3 muss xprintf() im Hostmode unterdruecken! */ +/* */ +/************************************************************************/ +void +xprintf(const char *format,...) +{ + va_list arg_ptr; + + if (consfile == NULL) + return; + va_start(arg_ptr, format); + vfprintf(consfile, format, arg_ptr); + va_end(arg_ptr); +} + +/************************************************************************/ +/* */ +/* String an der Konsole anzeigen. */ +/* */ +/************************************************************************/ +void +hputs(const char *str) +{ + while (*str) + hputc(*str++); +} + +/************************************************************************/ +/* */ +/* Inhalt eines Buffers an der Konsole anzeigen, Steuerzeichen mit "^" */ +/* vorweg. */ +/* */ +/************************************************************************/ +void +hputmb(MBHEAD *mbp) +{ + UBYTE c; + + if (tnb_ch) + { + cputmb(mbp); + return; + } + while (mbp->mbgc < mbp->mbpc) + { + c = getchr(mbp); + if (c >= ' ' || c == BELL || c == TAB || c == LF || c == CR) + hputc(c); + else + hputcc(c); + } +} + +/************************************************************************/ +/* */ +/* Inhalt eines Buffers in das Protokollfile fuer Batches schreiben, */ +/* Steuerzeichen mit "^" vorweg. */ +/* */ +/************************************************************************/ +void +cputmb(MBHEAD *mbp) +{ + UBYTE c; + + if (pro_file == NULL) + return; + while (mbp->mbgc < mbp->mbpc) + { + c = getchr(mbp); + if (c >= ' ') + fputc(c, pro_file); + else + { + if (c == CR) + fputs("\n", pro_file); + else if (c != LF) + { + fputc('^', pro_file); + fputc(c + '@', pro_file); + } + } + } +} + +/* End of src/l7host.c */ diff --git a/src/l7hstcmd.c b/src/l7hstcmd.c new file mode 100755 index 0000000..1baf691 --- /dev/null +++ b/src/l7hstcmd.c @@ -0,0 +1,1182 @@ +/************************************************************************/ +/* */ +/* ***** ***** */ +/* ***** ***** */ +/* ***** ***** */ +/* ***** ***** */ +/* *************** *************** */ +/* ***************** ***************** */ +/* *************** *************** */ +/* ***** ***** TheNetNode */ +/* ***** ***** Portable */ +/* ***** ***** Network */ +/* ***** ***** Software */ +/* */ +/* File src/l7hstcmd.c (maintained by: DF6LN) */ +/* */ +/* This file is part of "TheNetNode" - Software Package */ +/* */ +/* Copyright (C) 1998 - 2008 NORD> */ + { /* aktuelles Call auf dem Host-Kanal */ + rspini(HMRSMSG); + if (hstusr->conflg) + putid(hstusr->direction ? myid : hstusr->call, hstmbp); + else +#ifdef SPEECH + putstr(speech_message(253), hstmbp); +#else + putstr("CHANNEL NOT CONNECTED", hstmbp); +#endif + } + else + { /* mit Parameter */ + if (hstusr->conflg == 0) /* schon connected? */ + { + hstcon(1); + rspsuc(); + } + else + rsperr(HMEALC); /* bereits connected */ + } + } +} + +/************************************************************************/ +/* */ +/* Konsole disconnecten */ +/* */ +/************************************************************************/ +void +Dcmd(void) +{ + if (hstusr->conflg != 0) + { + hstsen(TRUE); + hstdis(); + rspsuc(); + } + else + rspcs(); +} + +/************************************************************************/ +/* */ +/* Echo-Befehl nur fuer Kompatibilitaet */ +/* */ +/************************************************************************/ +void +Ecmd(void) +{ + rspsuc(); +} + +/************************************************************************/ +/* */ +/* @E-Befehl - Protokoll-File fuer TNBs ein- und ausschalten */ +/* */ +/************************************************************************/ +static void +xEcmd(void) +{ + char out_file_name[MAXPATH+1]; + struct tm *sys_t; + UWORD arg; + + if (!blicnt) + rsppar(pro_file == NULL ? 0 : 1); + else + switch ((arg = nxtnum(&blicnt, &blipoi))) + { + case 0: + if (pro_file != NULL) + { + fclose(pro_file); + pro_file = NULL; + rspsuc(); + } + else + rsperr(HMEFNO); + break; + case 1: + if (pro_file == NULL) + { + skipsp(&blicnt, &blipoi); + if (blicnt) + { + strncpy(out_file_name, (char*)blipoi, MAXPATH); + out_file_name[MAXPATH] = NUL; + } + else + { + +/* Aus Datum und Uhrzeit den Filenamen generieren */ + + sys_t = sys_localtime; + sprintf(out_file_name, "%02d%02d%02d%02d.PRO", + sys_t->tm_year % 100, sys_t->tm_mon + 1, + sys_t->tm_mday, sys_t->tm_hour); + } + pro_file = xfopen(out_file_name, "at+"); + rspsuc(); + } + else + rsperr(HMEFAO); + break; + default: + rspiv(arg); + } +} + +/************************************************************************/ +/* */ +/* action : G-Kommando (nur fuer Hostmode). */ +/* */ +/* Infoframedaten, Linkstatus-Meldungen, Monitorheader */ +/* und Monitorframeinfodaten im Hostmode abholen. */ +/* */ +/* Kanal 0 : G - Linkstatus/Monitorheader/Monitorinfo */ +/* G0 - Monitorheader/Monitorinfos */ +/* G1 - Linkstatus */ +/* */ +/* Kanal > 0 : G - Linkstati/Infoframedaten */ +/* G0 - Infoframedaten */ +/* G1 - Linkstati */ +/* */ +/* Im Kanal 0 ist die einzig moegliche Linkstatusmeldung */ +/* ein nicht angenommener Connect-Request, in den anderen */ +/* Kanaelen werden keine Connect-Request-Meldungen */ +/* ausgegeben. */ +/* */ +/* Es wird eine der Anforderung entsprechende Hostmode- */ +/* antwort ausgegeben. */ +/* */ +/************************************************************************/ +/* */ +/* parameter : - */ +/* */ +/* r/o globals: ishmod - TRUE = wir sind im Hostmode, Terminalmode */ +/* sonst */ +/* incnt - Anzahl Zeichen hinter 'G' im Eingabebuffer */ +/* inbufp - Zeiger hinter 'G' in Eingabebuffer */ +/* actch - Kanal des Hostmodekommandos */ +/* */ +/* r/w globals: mifmbp - Zeiger auf Framekopf eines I/UI-Frames, von */ +/* dem der Rumpf (die Daten) noch gemonitort */ +/* werden muessen */ +/* statml - Liste der auszugebenden Statusmeldungen fuer */ +/* Kanal 0 (Hostmode nur Connect-Requests) */ +/* smonfl - Liste der zu monitorenden Frames (Vorauswahl) */ +/* */ +/* locals : s.u. */ +/* */ +/* returns : - */ +/* */ +/************************************************************************/ + +void +Gcmd(void) +{ + static MBHEAD *mbp; /* Zeiger auf Kopf des aktuellen Frames */ + static unsigned n; + unsigned par; + FILE *fd; + char tmpcall[10]; + + if (ishmod) /* im Hostmode ? */ + { + if (actch == 0xFF) /* extended G */ + { + xGcmd(); + return; + } + if (blicnt) /* ja, Parameter da ? */ + { + if ((par = *blipoi++) > 1) /* ja, holen */ + { + rspiv(par); /* ... falsch angegeben */ + return; + } + blicnt++; + } + else /* kein Parameter, alle */ + par = MBALL; /* Typen sind gemeint */ + +/* G : par = MBALL G0 : par = MBINFO G1 : par = MBSTATUS */ + + if (!actch) /* Monitorkanal ? */ + { + if (mifmbp != NULL /* ja, noch alter Rest */ + && par != MBSTATUS) /* kein Status ? */ + { + rspini(HMRMONI); + + n = mifmbp->mbpc - mifmbp->mbgc; /* Datenlaenge ermitteln */ + if (n == 0) + { + putchr(15, hstmbp); +#ifdef SPEECH + putstr(speech_message(254), hstmbp); +#else + putstr("[FRAME EMPTY?!?]", hstmbp); +#endif + } + else + { + if (n <= 257) /* Max. 256 Datenbytes zulaessig */ + { +#ifdef __WIN32__ + putchr((char)(n - 1), hstmbp); /* Zahl der folgenden Datenbytes */ +#else + putchr(n - 1, hstmbp); /* Zahl der folgenden Datenbytes */ +#endif /* WIN32 */ + while (mifmbp->mbgc < mifmbp->mbpc) + putchr(getchr(mifmbp), hstmbp); + } + else /* stattdessen Fehlermeldung */ + { + putchr(15, hstmbp); +#ifdef SPEECH + putstr(speech_message(255), hstmbp); +#else + putstr("[FRAME TOO LONG]", hstmbp); +#endif + } + } + dealmb(mifmbp); + mifmbp = NULL; /* (kein Rest mehr) */ + } + else /* ... oder */ + { + if ((par != MBINFO) /* Status/Alles angefordert und */ + && (stalin)) /* Status da? */ + { + mbp = (MBHEAD *)ulink((LEHEAD *)statml.head); /* ja, holen */ + stalin--; /* eine weniger */ + rwndmb(mbp); /* und ausgeben */ + rspini(HMRSTAT); /* (Antworttyp) */ + while (mbp->mbpc > mbp->mbgc) + putchr(getchr(mbp), hstmbp); + if (stamp) + { + putstr(" - ", mbp); + puttim(&mbp->btime, mbp); + } + dealmb(mbp); /* (freigeben) */ + } + else + { + if ((par != MBSTATUS) /* ... oder Info/Alles */ + && (monlin)) /* angefordert und Frames da? */ + { + mbp = (MBHEAD *)ulink((LEHEAD *)smonfl.head); + monlin--; /* eine weniger */ + rspini(mbp->type); /* Typ ausgeben */ + while (mbp->mbpc > mbp->mbgc) + putchr(getchr(mbp), hstmbp); + if ((mbp->type == HMRMONIH) /* mit Infofeld? */ + && monlin) /* und Frames da? */ + { + if (((MBHEAD *)smonfl.head)->type == HMRMONI) + { + mifmbp = (MBHEAD *)ulink((LEHEAD *)smonfl.head); + monlin--; /* noch 1 weniger */ + } + } + dealmb(mbp); /* Buffer weg */ + } + else + rspsuc(); /* nix da */ + } + } + } + else /* if (!actch) */ + { + if (hstusr->outsta /* Status da und */ + && (par != MBINFO)) /* gewuenscht */ + { + for (mbp = (MBHEAD *)hstusr->outbuf.head; + mbp != (MBHEAD *)&hstusr->outbuf; + mbp = (MBHEAD *)mbp->nextmh) + { + if (mbp->type > L2MNIX) /* Status-Frame! */ + { + hstusr->outsta--; /* einen weniger */ + rwndmb((MBHEAD *)ulink((LEHEAD *)mbp)); /* zurueckspulen */ + rspini(HMRSTAT); /* Antwort starten */ + while (mbp->mbpc > mbp->mbgc) + putchr(getchr(mbp), hstmbp); + if (stamp) /* Zeit dazu */ + { + putstr(" - ", hstmbp); + puttim(&mbp->btime, hstmbp); + } + dealmb(mbp); /* Buffer weg */ + return; /* fertig */ + } + } + } + else + { + if (hstusr->outlin /* Meldungen und */ + && (par != MBSTATUS)) /* gewuenscht */ + { + for (mbp = (MBHEAD *)hstusr->outbuf.head; + mbp != (MBHEAD *)&hstusr->outbuf; + mbp = (MBHEAD *)mbp->nextmh) + if (mbp->type == L2MNIX) /* Info-Frame! */ + { + rspini(HMRCONI); + n = mbp->mbpc - mbp->mbgc; + if (n > 256) + { + call2str(tmpcall, hstusr->call); + fd = xfopen("hostmode.err", "a"); +#ifdef SPEECH + fprintf(fd, speech_message(248), n, tmpcall); +#else + fprintf(fd, "Laenge = %d; Call = %s\n", n, tmpcall); +#endif + fclose(fd); + n = 256; + } + putchr((BYTE)(n - 1), hstmbp); /* Laenge ausgeben */ + while (n-- > 0) /* Info ausgeben */ + putchr(getchr(mbp), hstmbp); + if (mbp->mbpc - mbp->mbgc > 0) + return; + mbp = (MBHEAD *)ulink((LEHEAD *)mbp); + hstusr->outlin--; /* einen weniger */ + dealmb(mbp); /* Buffer weg */ + return; + } + } + else + rspsuc(); + } + } + } + else + rspic('G'); /* Terminal-Mode: G ungueltig */ +} + +/************************************************************************/ +/* */ +/* EXTENDED HOSTMODE COMMAND nach DG3DBI, ueberarbeitet von DB2OS */ +/* */ +/* Der Rechner sendet ein 'G'-Kommando an den Kanal 255. */ +/* Handelt es sich um einen Slave ohne Erweiterung, so antwortet dieser */ +/* mit der Fehlermeldung "INVALID CHANNEL NUMBER". */ +/* Bei dem erweiterten Hostmode wird stattdessen ein Null-terminierter */ +/* String zurueckgeliefert, der eine Liste von Kanaelen enthaelt, bei */ +/* denen noch Infos in den Buffern abholbereit sind. Dies gilt auch */ +/* fuer den Monitor-Kanal und Statusdaten. Die Kanalnummern im String */ +/* sind wegen der Null-Terminierung um 1 erhoeht. */ +/* */ +/* Beispiele fuer Antwort des TNC: */ +/* 0xFF 0x01 0x00 - Keine Daten verfuegbar. */ +/* 0xFF 0x01 0x01 0x00 - Es sind Daten im Monitor-Buffer. */ +/* 0xFF 0x01 0x01 0x03 0x04 0x00 - Es sind Daten im Monitor und */ +/* in den Kanaelen 2 und 3. */ +/* */ +/************************************************************************/ +static void +xGcmd(void) +{ + static unsigned n; /* Index auf Kanaele */ + + rspini(HMRSMSG); /* Success with Response */ + + if ((mifmbp != NULL) /* Ist was im Monitor-Buffer? */ + || ((LHEAD *)statml.head != &statml) + || ((LHEAD *)smonfl.head != &smonfl)) + putchr(1, hstmbp); /* Ja, melden... */ + + for (n = 1; n < MAXHST; ++n) /* Haben wir etwas auf den Links? */ + if (hstubl[n].outlin || hstubl[n].outsta) +#ifdef __WIN32__ + putchr((char)(n + 1), hstmbp); /* Ja, diesen Kanal melden.. */ +#else + putchr(n + 1, hstmbp); /* Ja, diesen Kanal melden.. */ +#endif /* WIN32 */ +} + +/************************************************************************/ +/* */ +/* Host-Call anzeigen bzw. setzen. Ohne Parameter wird das globale */ +/* Hostcall ausgegeben (TNT/DP haette das gerne so). Mit Parameter wird */ +/* das Hostcall gesetzt: Auf Kanal 0 wird das globale Hostcall (hostid) */ +/* gesetzt, das beim Connect-Befehl verwendet wird, um eine Verbindung */ +/* zum Host herzustellen. Ausserdem werden die temporaeren Hostcalls */ +/* fuer alle nicht connecteten Kanaele gesetzt (hstusr->call). Dies */ +/* gilt auch fuer die anderen Hostkanaele, falls das Host-Call das */ +/* gleiche Rufzeichen ist, wie das Knoten-Call (myid). Sonst wird auf */ +/* allen anderen Kanaelen nur das temporaere Hostcall des entsprechen- */ +/* den Hostkanals (hstusr->call) gesetzt, wenn der Kanal nicht */ +/* connected ist. */ +/* */ +/************************************************************************/ +void +Icmd(void) +{ + char tempcall[L2IDLEN]; + char tempalias[L2CALEN]; + HOSTUS *tmpusr; + + if (!blicnt) + { + rspini(HMRSMSG); + putid(hstusr->direction ? hstusr->call : hostid, hstmbp); + } + else + { +/* Es soll ein Call auf dem aktiven Kanal gesetzt werden */ + if (getcal(&blicnt, &blipoi, TRUE, tempcall) == YES) + { + if ((actch == 0) || tnb_ch) + { +/* Auf dem Monitorkanal bzw. ueber den CCP-Befehl "ESC I" wird ausser */ +/* dem Host-Call auch der Alias fuer den Hostmode gesetzt. Wenn kein */ +/* Alias angegeben wird, ist es eine Fehlbedienung, die ignoriert wird. */ + skipsp(&blicnt, &blipoi); + if (getide(&blicnt, &blipoi, tempalias) == YES) + { +/* bevor neu eingetragen wird, muss der alte Eintrag geloescht werden */ + if (!cmpid(hostid, myid)) + unregister_neigb(hostid, "", L2PNUM); +/* Das neue Host-Call wird festgelegt und fuer alle nicht connecteten */ +/* Hostkanaele verwendet. */ + cpyid(hostid, tempcall); + for (tmpusr = &hstubl[1]; tmpusr < &hstubl[MAXHST]; tmpusr++) + { + if (!tmpusr->conflg) + cpyid(tmpusr->call, hostid); + } +/* Wenn Host-Call und Knoten-Call unterschiedlich sind, wird ein Local- */ +/* Link-Eintrag vorgenommen, um das Call im Netz bekanntzugeben. */ + if (!cmpid(hostid, myid)) +#ifdef PROXYFUNC + skipsp(&blicnt, &blipoi); +#endif + register_neigb(hostid, "", tempalias, L2PNUM, LOCAL +#ifdef PROXYFUNC + | (((blicnt > 0) && (*blipoi == 'p' || *blipoi == 'P')) ? PROXYMASK : 0) +#endif +#ifdef LINKSMODINFO + ,"Local-Route" +#endif /* LINKSMODINFO */ +#ifdef AUTOROUTING + , FIXED_ROUTE /* Route ist immer Fest. */ +#endif /* AUTOROUTING */ + ); + } + } + else /* Call fuer einzelnen Host-Kanal setzen */ + { + if (hstusr->conflg) + { + rsperr(HMENWC); + return; + } + else + cpyid(hstusr->call, tempcall); + } + rspsuc(); + } + else + rsperr(HMEICS); + } +} + +/************************************************************************/ +/* */ +/* Umschalten vom / zum Hostmode */ +/* */ +/************************************************************************/ +void +Jcmd(void) +{ + UWORD par; + + if (blicnt >= 4) + { + if (strnicmp((char *)blipoi, "HOST", 4) == 0) + { + blicnt -= 4; + blipoi += 4; + if (!skipsp(&blicnt, &blipoi)) + rsppar(ishmod); + else if ((par = nxtnum(&blicnt, &blipoi)) <= 1) + { + rspsuc(); + ishmod = par; + } + else + rspiv(par); + return; + } + } + rspic('J'); +} + +/************************************************************************/ +/* */ +/* K-Befehl (Uhrzeit bei Monitor / Status-Meldungen) */ +/* */ +/************************************************************************/ +void +Kcmd(void) +{ + UWORD par; + + if (!blicnt) + { + rspini(HMRSMSG); + putprintf(hstmbp, "%d ", stamp); + puttim(&sys_time, hstmbp); + } + else + { + if ((par = nxtnum(&blicnt, &blipoi)) <= 2) + if (!blicnt) + stamp = par; + rspsuc(); /* Zeit kann hier nicht gesetzt werden */ + } +} + +/************************************************************************/ +/* */ +/* "list channel" - fuer den Kanal chnl anzeigen, wer connected ist und */ +/* wieviele Frames noch zu bearbeiten sind (rx / tx) */ +/* */ +/************************************************************************/ +static void +listch(WORD chnl) +{ + unsigned mbnmbr; + HOSTUS *hostp; + int cstate; + + putprintf(hstmbp, "%c(%u) ", chnl == actch ? '+' : ' ', chnl); + + if (chnl != 0) + { + hostp = &hstubl[chnl]; + cstate = hostp->conflg; + + if (cstate) /* CONNECTED */ + putid(myid, hstmbp); + + if ((mbnmbr = hostp->outlin + hostp->outsta) != 0 + || cstate) +#ifdef SPEECH + putprintf(hstmbp, speech_message(249), mbnmbr); +#else + putprintf(hstmbp, "\r receive %u", mbnmbr); +#endif + if (cstate) +#ifdef SPEECH + putprintf(hstmbp, speech_message(250), hostp->inlin); +#else + putprintf(hstmbp, " send %u unacked 0", hostp->inlin); +#endif + } + putchr('\r', hstmbp); +} + +/************************************************************************/ +/* */ +/* L-Befehl - Logout an der Konsole (nur Terminalmode) und anzeigen */ +/* wieviele Frames noch zu bearbeiten sind, fuer einen oder alle Host- */ +/* kanaele */ +/* */ +/************************************************************************/ +void +Lcmd(void) +{ + WORD n; + UWORD par; + + if (!ishmod) + { + if (strnicmp((char *)blipoi, "OGOUT", 5) == 0) + console_login_status = 0; + else + { + if (!blicnt) + for (n = 1; n <= Ypar2; n++) + listch(n); + else + { + if ((par = nxtnum(&blicnt, &blipoi)) <= Ypar2) + listch(par); + else + rspiv(par); + } + } + } + else + { + rspini(HMRSMSG); + if (!actch) + putprintf(hstmbp, "%u %u", stalin, monlin); + else + putprintf(hstmbp, "%u %u %u %u 0 %u", + hstusr->outsta, hstusr->outlin, + hstusr->inlin, hstusr->inlin, + hstusr->conflg ? L2SIXFER : L2SDSCED); + } +} + +/************************************************************************/ +/* */ +/* M-Befehl - einstellen / abfragen der Monitor-Parameter */ +/* */ +/************************************************************************/ +void +Mcmd(void) +{ + moncmd(NULL, &consmon, blipoi, blicnt); +} + +/************************************************************************/ +/* */ +/* QUIT-Befehl - Programm beenden */ +/* */ +/************************************************************************/ +void +Qcmd(void) +{ + if ((strnicmp((char *)blipoi, "UIT", 3) == 0) && !ishmod) + quit_program(0); + else + rspic('Q'); +} + +/************************************************************************/ +/* */ +/* R-Befehl - Anzeige von Token-Recoveries ein- und ausschalten */ +/* */ +/************************************************************************/ +void +Rcmd(void) +{ + UWORD arg; + + if (blicnt == 0) + rsppar(show_recovery); + else + { + if ((arg = nxtnum(&blicnt, &blipoi)) <= 1) + { + show_recovery = arg; + rspsuc(); + } + else + rspiv(arg); + } +} + +/************************************************************************/ +/* */ +/* S-Befehl - Kanal-Umschaltung (nur Terminal-Modus) */ +/* */ +/************************************************************************/ +void +Scmd(void) +{ + WORD arg; + + if (!ishmod) + { + if (!blicnt) + rsppar(actch); + else + { + if ((arg = nxtnum(&blicnt, &blipoi)) <= Ypar2 && arg > 0) + { + hstusr = &hstubl[actch = arg]; + rspcs(); + } + else + rspiv(arg); + } + } + else + rspic('S'); +} + +/************************************************************************/ +/* */ +/* Tokenring-Baudrate anzeigen / setzen */ +/* */ +/************************************************************************/ +void +Tcmd(void) +{ +#if !defined(__LINUX__) && !defined(__WIN32__) + ULONG arg; + + if (!ishmod) /* im Hostmode sperren */ + { + if (!blicnt) + rsppar(tkbaud * 100L); + else + { + arg = nxtlong(&blicnt, &blipoi); + if (tkcom > -1) + tkbaud = setbaud(tkcom, (WORD)(arg / 100L)); + rspsuc(); + } + } + else +#endif + rspic('T'); +} + +/************************************************************************/ +/* */ +/* Version anzeigen */ +/* */ +/************************************************************************/ +void +Vcmd(void) +{ + rspini(HMRSMSG); + putprintf(hstmbp, "%sXHOST)", signon); +} + +/************************************************************************/ +/* */ +/* Y-Befehl - zulaessige Zahl von connects anzeigen / setzen */ +/* */ +/************************************************************************/ +void +Ycmd(void) +{ + UWORD arg; + + if (blicnt == 0) + { + rspini(HMRSMSG); + putprintf(hstmbp, "%d (%d)", Ypar, numhsts); + } + else + { + if ((arg = nxtnum(&blicnt, &blipoi)) <= Ypar2) + { + Ypar = arg; + rspsuc(); + } + else + rspiv(arg); + } +} + +/************************************************************************/ +/* */ +/* @Y-Befehl - Anzahl der zu verwendenden Hostkanaele anzeigen / setzen */ +/* */ +/************************************************************************/ +static void +xYcmd(void) +{ + UWORD arg; + HOSTUS *tmpusr; + + if (blicnt == 0) + { + rspini(HMRSMSG); + putprintf(hstmbp, "%d (%d)", Ypar2, MAXHST - 1); + } + else + { + arg = nxtnum(&blicnt, &blipoi); + if ((arg < MAXHST) && (arg > 0) && (arg >= actch)) + { +/* alle Kanaele disconnecten, die kuenftig ungueltig sind */ + if (arg < Ypar2) + { + tmpusr = hstusr; + for (hstusr = &hstubl[arg + 1]; hstusr < &hstubl[MAXHST]; hstusr++) + { + if (hstusr->conflg) + hstdis(); + } + hstusr = tmpusr; + } +/* Zahl der erlaubten Connect-Ports auf erlaubte Ports begrenzen */ + if (arg < Ypar) + Ypar = arg; + Ypar2 = arg; + rspsuc(); + } + else + rspiv(arg); + } +} + +/************************************************************************/ +/* */ +/* "extended commands" */ +/* */ +/* Erweiterte Befehle abarbeiten. */ +/* */ +/************************************************************************/ +void +extcmd(void) +{ + char ch; + + if (blicnt) + { + ch = *blipoi++; + blicnt--; + skipsp(&blicnt, &blipoi); + switch (toupper(ch)) + { + case 'B': + rsppar(min(nmbfre, 1999)); /* max 1999 - wer weiss, ob sonst */ + break; /* das Terminalprg. verwirrt wird */ + case 'S': + if ((actch) && (!tnb_ch)) + rsppar(hstusr->conflg ? L2SIXFER : L2SDSCED); + else + rspiec('S'); + break; + case 'E': + xEcmd(); + break; + case 'Y': + if (!actch || tnb_ch) + xYcmd(); + else + rspiec('Y'); + break; + default: + rspiec(ch); + } + } + else + rspsuc(); +} + +/************************************************************************/ +/* */ +/* "host mode put response" */ +/* */ +/************************************************************************/ +void +hmputr(unsigned r) +{ +#ifdef __WIN32__ + hputc((char)actch); + hputc((char)r); +#else + hputc(actch); + hputc(r); +#endif /* WIN32 */ +} + +/************************************************************************/ +/* */ +/* "response init" */ +/* */ +/************************************************************************/ +void +rspini(unsigned r) +{ + if (tnb_ch) + return; + if (!ishmod) + putstr("* ", hstmbp); + else + { +#ifdef __WIN32__ + putchr((char)actch, hstmbp); + putchr((char)r, hstmbp); +#else + putchr(actch, hstmbp); + putchr(r, hstmbp); +#endif /* WIN32 */ + + } + hstmbp->l4type = r; +} + +/************************************************************************/ +/* */ +/* "response success" */ +/* */ +/************************************************************************/ +void +rspsuc(void) +{ + if (tnb_ch) + return; + if (ishmod) +#ifdef __WIN32__ + putchr((char)actch, hstmbp); +#else + putchr(actch, hstmbp); +#endif /* WIN32 */ +} + +/************************************************************************/ +/* */ +/* "response invalid command" */ +/* */ +/************************************************************************/ +static void +rspic(unsigned c) +{ + rspini(HMRFMSG); +#ifdef SPEECH + putstr(speech_message(256), hstmbp); +#else + putstr("INVALID COMMAND: ", hstmbp); +#endif +#ifdef __WIN32__ + putcc((char)c, hstmbp); +#else + putcc(c, hstmbp); +#endif /* WIN32 */ +} + +/************************************************************************/ +/* */ +/* "response invalid extended command" */ +/* */ +/************************************************************************/ +void +rspiec(unsigned c) +{ + rspini(HMRFMSG); +#ifdef SPEECH + putstr(speech_message(257), hstmbp); +#else + putstr("INVALID EXTENDED COMMAND: ", hstmbp); +#endif +#ifdef __WIN32__ + putcc((char)c, hstmbp); +#else + putcc(c, hstmbp); +#endif /* WIN32 */ +} + +/************************************************************************/ +/* */ +/* "response invalid value" */ +/* */ +/************************************************************************/ +static void +rspiv(unsigned value) +{ + if (tnb_ch) + return; + rspini(HMRFMSG); +#ifdef SPEECH + putprintf(hstmbp, speech_message(251), value); +#else + putprintf(hstmbp, "INVALID VALUE: %u", value); +#endif +} + +/************************************************************************/ +/* */ +/* Fehlermeldungen */ +/* */ +/************************************************************************/ +const char *hm_err[] = +{ + "CHANNEL ALREADY CONNECTED", + "INVALID PARAMETER", + "INVALID CALLSIGN", + "TNC BUSY - LINE IGNORED", + "ALREADY OPEN", + "FILE NOT OPEN", + "NOT WHILE CONNECTED", + "INVALID PORT" +}; + +/************************************************************************/ +/* */ +/* "response error" */ +/* */ +/************************************************************************/ +void +rsperr(int i) +{ + rspini(HMRFMSG); + putstr(hm_err[i], hstmbp); +} + +/************************************************************************/ +/* */ +/* "response channel status" */ +/* */ +/************************************************************************/ +static void +rspcs(void) +{ + rspini(HMRSMSG); + if (!actch) + putid(myid, hstmbp); + else + if (hstusr->conflg != 0) + putid(hstusr->direction ? myid : hstusr->call, hstmbp); + else +#ifdef SPEECH + putstr(speech_message(253), hstmbp); +#else + putstr("CHANNEL NOT CONNECTED", hstmbp); +#endif +} + +/************************************************************************/ +/* */ +/* "response parameter" */ +/* */ +/************************************************************************/ +static void +rsppar(ULONG par) +{ + rspini(HMRSMSG); + putprintf(hstmbp, "%lu", par); +} + +/************************************************************************/ +/* */ +/* Zeichen in Buffer schreiben, Steuerzeichen mit '^' vorweg */ +/* */ +/************************************************************************/ +static void +putcc(char c, MBHEAD *mbp) +{ + if (c < ' ') + { + putchr('^', mbp); +#ifdef __WIN32__ + putchr((char)(c + '@'), mbp); +#else + putchr(c + '@', mbp); +#endif /* WIN32 */ + } + else + putchr(c, mbp); +} + +/* End of src/l7hstcmd.c */ diff --git a/src/l7ip.c b/src/l7ip.c new file mode 100755 index 0000000..f0a5a08 --- /dev/null +++ b/src/l7ip.c @@ -0,0 +1,1005 @@ +/************************************************************************/ +/* */ +/* ***** ***** */ +/* ***** ***** */ +/* ***** ***** */ +/* ***** ***** */ +/* *************** *************** */ +/* ***************** ***************** */ +/* *************** *************** */ +/* ***** ***** TheNetNode */ +/* ***** ***** Portable */ +/* ***** ***** Network */ +/* ***** ***** Software */ +/* */ +/* File src/l7ip.c (maintained by: DG1KWA) */ +/* */ +/* This file is part of "TheNetNode" - Software Package */ +/* */ +/* Copyright (C) 1998 - 2008 NORD> 0) + { + /* eine gueltige IP-Addresse muss der erste Parameter sein, + * danach folgt die Anzahl der Host-bits + */ + if (get_ip_addr(&host, &clicnt, &clipoi)) + { + i = 0; + if (skipsp(&clicnt, &clipoi)) + { + if (*clipoi == '/') + { + clipoi++; + clicnt--; + if ((bits = nxtnum(&clicnt, &clipoi)) > 32) + bits = 32; + } + + /* the sysop only commands are '+' and '-' + */ + if (issyso()) + { + skipsp(&clicnt, &clipoi); + switch (*clipoi) + { + case '-': + rt_drop(host, bits, FALSE); + break; + + case '+': + clipoi++; + clicnt--; + if (skipsp(&clicnt, &clipoi)) + { + if (clicnt >= 2 && clipoi[1] == ' ') + if (toupper(*clipoi) == 'D') { + clipoi += 2; + clicnt -= 2; + flags |= RTDYNAMIC; + } + if (getport(&clicnt, &clipoi, &port) == FALSE) + { +#ifdef KERNELIF + if (toupper(*clipoi) == 'K') + { + nextspace(&clicnt, &clipoi); + port = KERNEL_PORT; + } + else + { + nextspace(&clicnt, &clipoi); + port = NETROM_PORT; + } +#else + nextspace(&clicnt, &clipoi); + port = NETROM_PORT; +#endif + } + get_ip_addr(&gateway, &clicnt, &clipoi); + metric = nxtnum(&clicnt, &clipoi); + host >>= (32 - bits); + host <<= (32 - bits); + rt_add(host, bits, gateway, port, metric, 0, flags, FALSE); + } + } + } + } + } + } else + if (issyso()) + putstr("IPROUTE DestIP/HostBts [+/-] [Port/NETROM] GateIP Metric\r", mbp); + + host &= ~0L << (32 - bits); +#ifdef SPEECH + putstr(speech_message(264), mbp); +#else + putstr("IP-Routes of ", mbp); +#endif + putalt(alias, mbp); + putid(myid, mbp); +#ifdef SPEECH + putstr(speech_message(265), mbp); +#else + putstr("\rDestination------Len--Flags-Interface--Gateway----------Metric----\r", mbp); +#endif + + while (mbp->mbpc < 17) putchr(' ', mbp); + + for (ipr = (IP_ROUTE *)IP_Routes.head; + ipr != (IP_ROUTE *)&IP_Routes; + ipr = (IP_ROUTE *)ipr->nextip) + if ((host == ipr->dest && + bits == ipr->bits) || i) { + showroute(ipr, mbp); + } + prompt(mbp); + seteom(mbp); +} + +/************************************************************************ + * Function : Einen IPRoute-Eintrag anzeigen + * + * Inputs : Zeiger auf den Eintrag + * + * Outputs : nix + * + * Operation : + *----------------------------------------------------------------------*/ +void showroute(IP_ROUTE *rp, MBHEAD *bufpoi) +{ + bufpoi->l4time = bufpoi->mbpc; /* Position merken */ + + show_ip_addr(rp->dest, bufpoi); /* Adresse anzeigen */ + putspa(17, bufpoi); + putnum(rp->bits, bufpoi); /* Bitmaske zeigen */ + putspa(22, bufpoi); +#ifdef __WIN32__ + putchr((char)(rp->flags & RTDYNAMIC ? 'D' : ' '), bufpoi); +#else + putchr(rp->flags & RTDYNAMIC ? 'D' : ' ', bufpoi); +#endif /* >WIN32 */ + putspa(28, bufpoi); +#ifndef KERNELIF + putstr(rp->port == NETROM_PORT ? + "NET/ROM" : + portpar[rp->port].name, bufpoi); +#else + switch(rp->port) + { + case NETROM_PORT: putstr("NET/ROM", bufpoi); + break; + case KERNEL_PORT: putstr("KERNEL", bufpoi); + break; + default : putstr(portpar[rp->port].name, bufpoi); + } +#endif + putspa(39, bufpoi); + if (rp->gateway != 0) + show_ip_addr(rp->gateway, bufpoi); /* Gateway */ + putspa(58, bufpoi); + if (rp->metric != 0) /* if metric set, */ + putnum(rp->metric, bufpoi); /* show metric */ + putchr('\r', bufpoi); + return; +} + +/************************************************************************ + * Function : eine IP-Addresse anzeigen + * + * Inputs : Die IP-Addresse und ein IP-Buffer + * + * Outputs : nix + * + * Operation : + *----------------------------------------------------------------------*/ +void show_ip_addr(ipaddr address, MBHEAD *bufpoi) +{ +#ifdef __WIN32__ + ULONG adr[4]; +#else + UWORD adr[4]; +#endif /* WIN32 */ + int i; + + for (i = 0; i < 4; i++) adr[i] = ((address >> 8 * i) & 0xff); + + putprintf(bufpoi, "%d.%d.%d.%d", adr[3], adr[2], adr[1], adr[0]); +} + +/* ********************************************************************** + * Function : Eine IP-Addresse aus der Kommandozeile lesen + * + * Inputs : clipoi/clicnt + * + * Outputs : FALSE bei Fehler, TRUE wenn ok + * + * Operation : + * ---------------------------------------------------------------------*/ +BOOLEAN get_ip_addr(ipaddr *target, WORD *count, char **ptr) +{ + UWORD num; + ULONG adr; + int i; + + for (adr = 0, i = 0; i < 4; i++) { + if ((num = nxtnum(count, ptr)) > 255) + return(FALSE); + adr = (adr << 8) | num; + if (i < 3) { + if ((*count < 1) || (**ptr != '.')) + return(FALSE); + else + { + (*ptr)++; + (*count)--; + } + } + } + *target = adr; + return(TRUE); +} + +/************************************************************************ + * Function : ARP - Der ARP-Befehl + * + * Inputs : clicnt, clipoi & arp table + * + * Outputs : Updates table. + * + * Operation : Eintrag Hinzufuegen (Sysop) oder Tabelle anzeigen + * ---------------------------------------------------------------------*/ +void ccparp(void) +{ + ipaddr host; + WORD hwport = 0, dgmode = 0; + unsigned i; + MBHEAD *mbp; + ARP_TAB *arp; + char call[L2IDLEN]; + char digi[65]; +/* wieso 65??? */ + unsigned publish; + unsigned ttl; + + mbp = getmbp(); + + digi[0] = 0; + publish = FALSE; + host = 0; + ttl = 0; + + if (issyso()) + { + if (skipsp(&clicnt, &clipoi)) + { +#ifndef IPROUTEMOD + if (!get_ip_addr(&host, &clicnt, &clipoi)) + host = 0L; +#else + if (get_ip_addr(&host, &clicnt, &clipoi) == FALSE) + { +#ifdef SPEECH + putmsg(speech_message(267)); +#else + putmsg("\rERROR : Invalid IP-Adresse !\r"); +#endif /* SPEECH */ + return; + } + else + { + /* Wir puerfen den Host ob dieser Gueltig ist.*/ + if (host == FALSE) + { + /* Host ist 0, keine Gueltig IP-Adresse. */ +#ifdef SPEECH + putmsg(speech_message(267)); +#else + putmsg("\rERROR : Invalid IP-Adresse !\r"); +#endif /* SPEECH */ + return; + } + } +#endif /* IPROUTEMOD */ + + skipsp(&clicnt, &clipoi); + + switch (*clipoi) + { + case '-': + clipoi++; + clicnt--; + + if (!host) break; + + if (skipsp(&clicnt, &clipoi)) + if (getport(&clicnt, &clipoi, &hwport) == FALSE) + hwport = NETROM_PORT; + + arp_drop(host, hwport, FALSE); + break; + + case '+': + clipoi++; + clicnt--; + + if (skipsp(&clicnt, &clipoi)) { + if (clipoi[1] == ' ') { + publish = toupper(*clipoi++) == 'P'; + clicnt--; + nextspace(&clicnt, &clipoi); + } + } + + if (skipsp(&clicnt, &clipoi)) { + if (getport(&clicnt, &clipoi, &hwport) == FALSE) { + hwport = NETROM_PORT; + nextspace(&clicnt, &clipoi); + } else + if (skipsp(&clicnt, &clipoi)) { + if (clicnt > 2 && clipoi[2] == ' ') { + if (toupper(*clipoi) == 'D') dgmode = 1; + else if (toupper(*clipoi) == 'V') dgmode = 2; + nextspace(&clicnt, &clipoi); + } + } + } + + if (getcal(&clicnt, &clipoi, TRUE, call) == YES) { + getdig(&clicnt, &clipoi, TRUE, digi); + digi[14] = 0; /* auf 2 Hops begrenzen */ + arp_add(host, hwport, call, digi, dgmode, ttl, publish, FALSE); + } + else /* Fehler */ +#ifdef SPEECH + putstr(speech_message(258),mbp); +#else + putstr("\rERROR : Port or Call invalid !\r",mbp); +#endif + } + + } else + if (issyso()) + putstr("ARP DestIP + [Publ.] PORT [DG/VC] CALL [DIGI1[DIGI2]]\r" + "ARP DestIP - PORT\r", mbp); + } + /* ARP-Tabelle ausgeben */ +#ifdef SPEECH + putstr(speech_message(259), mbp); +#else + putstr("ARP-Table of ", mbp); +#endif + putalt(alias, mbp); + putid(myid, mbp); +#ifdef SPEECH + putstr(speech_message(260), mbp); +#else + putstr("\rDestination P Interface Callsign Digi Mode Timer\r", mbp); +#endif + i = (host == 0L); + for (arp = (ARP_TAB *)Arp_tab.head; + arp != (ARP_TAB *)&Arp_tab; + arp = (ARP_TAB *)arp->nextar) + if ((i != 0) || + (host == arp->dest)) + showarp(arp, mbp); + prompt(mbp); + seteom(mbp); +} + +/************************************************************************ + * Function : showarp() + * + * Inputs : Zeiger auf einen arp-Eintrag und einen Buffer + * + * Outputs : Text... + * + * Operation : + *----------------------------------------------------------------------*/ +void showarp(ARP_TAB *arp, MBHEAD *bufpoi) +{ + const char *dgmode_tab[] = {"", "DG", "VC"}; + bufpoi->l4time = bufpoi->mbpc; + show_ip_addr(arp->dest, bufpoi); + putspa(17, bufpoi); + putstr((arp->publish_flag ? "P " : " "), bufpoi); + putstr((arp->port == NETROM_PORT ? + "NET/ROM" : portpar[arp->port].name) , bufpoi); + putspa(30, bufpoi); + putid(arp->callsign, bufpoi); + putspa(39, bufpoi); + putdil(arp->digi, bufpoi); + putspa(64, bufpoi); + putstr(dgmode_tab[(int)arp->dgmode], bufpoi); + if (arp->timer != 0) + { + putspa(70, bufpoi); + putnum(arp->timer, bufpoi); + } + putchr('\r', bufpoi); +} + +/************************************************************************/ +/* */ +/* Function : Die IP-Adresse und Bits fuer Subnetz-Maske des Knotens */ +/* anzeigen bzw. aendern */ +/* */ +/* Inputs : clipoi/clicnt */ +/* */ +/* Outputs : nix, my_ip_address und my_ip_bits wird geaendert bzw. */ +/* angezeigt */ +/* */ +/* Operation: nur wenn Sysop Aenderung erlaubt */ +/* */ +/************************************************************************/ +void +ccpipa(void) +{ + MBHEAD *bufpoi; + PEER *pp; + + int i; + int iCalls = 0; + int max_peers = netp->max_peers; + + BOOLEAN bChanges = FALSE; + + ipaddr t_ip_addr = 0L; /* temporaere IP */ + int t_ip_bits = 32; /* temporaere Subnetzbits */ + + if (issyso()) /* nur als Sysop duerfen wir aendern */ + { + if (get_ip_addr(&t_ip_addr, &clicnt, &clipoi) == TRUE) /* IP lesen */ + { +/* Unmoegliche IP-Adressen abfangen (nur niederwertigstes Byte) */ +/* eigentlich muesste man die anderen auch noch pruefen... */ + if (((t_ip_addr & 0xFF) == 0L) || ((t_ip_addr & 0xFF) == 0xFF)) + { +#ifdef SPEECH + putmsg(speech_message(266)); +#else + putmsg("Invalid IP address!\r"); +#endif + return; + } + + if (skipsp(&clicnt, &clipoi)) /* sind noch weitere Zeichen da? */ + { + if (*clipoi++ == '/') /* Subnetz-Trenner vorhanden? */ + { + clicnt--; +/* Subnetz-Bits lesen und Idiotencheck machen */ + t_ip_bits = nxtnum(&clicnt, &clipoi); + if (t_ip_bits > 32 || t_ip_bits < 1) + t_ip_bits = 32; + } + } + my_ip_addr = t_ip_addr; + if (t_ip_addr == 0L) + my_ip_bits = 0; + else + my_ip_bits = t_ip_bits; /* Subnetz-Bits uebernehmen */ + + bChanges = TRUE; /* es gibt Aenderungen */ + } + } + + bufpoi = getmbp(); +#ifdef SPEECH + putstr(speech_message(261), bufpoi); +#else + putstr("My IP address: ", bufpoi); +#endif + show_ip_addr(my_ip_addr, bufpoi); + + if ((issyso()) && (bChanges == TRUE)) + { + /* INP-Nachbarn die Aenderung mitteilen */ + for (i = 0, pp = netp->peertab; i < max_peers; ++i, ++pp) + { + if (!pp->used) + continue; + if (pp->typ != INP) + continue; + + if (iCalls == 0) + putprintf(bufpoi, "Notifying INP-neighbours about changes. ("); + + if (++iCalls > 1) + putprintf(bufpoi, " "); + + putid(pp->l2link->call, bufpoi); /* Node Call ausgeben */ + + send_inp_nodebeacon(pp); + } + + if (iCalls != 0) + putprintf(bufpoi, ")\r"); + } + + putprintf(bufpoi, "/%d\r", my_ip_bits); + prompt(bufpoi); + seteom(bufpoi); +} + +void ccp_ip_help(ipaddr *ip_addr, const char *name) +{ + MBHEAD *bufpoi; + + if (issyso()) + get_ip_addr(ip_addr, &clicnt, &clipoi); + bufpoi = putals(name); +#ifdef SPEECH + putstr(speech_message(262), bufpoi); +#else + putstr(" IP address : ", bufpoi); +#endif + show_ip_addr(*ip_addr, bufpoi); + putchr('\r', bufpoi); + prompt(bufpoi); + seteom(bufpoi); +} + +/************************************************************************ + * Function : Die Knoten Broadcast-Addresse aendern + * + * Inputs : clipoi/clicnt + * + * Outputs : bcast_ip_address wird geaendert und angezeigt + * + * Operation : nur wenn Sysop Aenderung erlaubt + * ---------------------------------------------------------------------*/ +/* erstmal gesperrt - weil man's laut doku sowieso nicht verwenden darf */ +#if 0 +void ccpipb() +{ + ccp_ip_help(&bcast_ip_addr, "Broadcast"); +} +#endif + +/*partyp iptab[] = { + &Ip_mib[0].value.integer, 0, MAXPORTMASK, + &Ip_mib[1].value.integer, 0, 1, + &Ip_mib[2].value.integer, 2, MAXTTL, + &Ip_mib[3].value.integer, 0, 0, + &Ip_mib[4].value.integer, 0, 0, + &Ip_mib[5].value.integer, 0, 0, + &Ip_mib[6].value.integer, 0, 0, + &Ip_mib[7].value.integer, 0, 0, + &Ip_mib[8].value.integer, 0, 0, + &Ip_mib[9].value.integer, 0, 0, + &Ip_mib[10].value.integer, 0, 0, + &Ip_mib[11].value.integer, 0, 0, + &Ip_mib[12].value.integer, 0, 0, + &Ip_mib[13].value.integer, 1, 65535, + &Ip_mib[14].value.integer, 0, 0, + &Ip_mib[15].value.integer, 0, 0, + &Ip_mib[16].value.integer, 0, 0, + &Ip_mib[17].value.integer, 0, 0, + &Ip_mib[18].value.integer, 0, 0, + &Ip_mib[19].value.integer, 0, 0 +}; + +partyp arptab[] = +{ + &ARPrunning, 0, 1, + &ARPtimer, 15, 24*60 +}; +*/ + +/* *********************************************************************** + * as per iptab, this is the ICMP MIB. It is not currently used + */ +#ifdef ICMPSTATS + +partyp icmptab[] = { + &Icmp_mib[1].value.integer, 0, 0, + &Icmp_mib[2].value.integer, 0, 0, + &Icmp_mib[3].value.integer, 0, 0, + &Icmp_mib[4].value.integer, 0, 0, + &Icmp_mib[5].value.integer, 0, 0, + &Icmp_mib[6].value.integer, 0, 0, + &Icmp_mib[7].value.integer, 0, 0, + &Icmp_mib[8].value.integer, 0, 0, + &Icmp_mib[9].value.integer, 0, 0, + &Icmp_mib[10].value.integer, 0, 0, + &Icmp_mib[11].value.integer, 0, 0, + &Icmp_mib[12].value.integer, 0, 0, + &Icmp_mib[13].value.integer, 0, 0, + &Icmp_mib[14].value.integer, 0, 0, + &Icmp_mib[15].value.integer, 0, 0, + &Icmp_mib[16].value.integer, 0, 0, + &Icmp_mib[17].value.integer, 0, 0, + &Icmp_mib[18].value.integer, 0, 0, + &Icmp_mib[19].value.integer, 0, 0, + &Icmp_mib[20].value.integer, 0, 0, + &Icmp_mib[21].value.integer, 0, 0, + &Icmp_mib[22].value.integer, 0, 0, + &Icmp_mib[23].value.integer, 0, 0, + &Icmp_mib[24].value.integer, 0, 0, + &Icmp_mib[25].value.integer, 0, 0, + &Icmp_mib[26].value.integer, 0, 0 +}; + +/* *************************************************************************** + * Function : ccpics() - the icmp stats parameters command + * + * Inputs : none - reads ICMP MIB passes it on to ccp_par() + * + * Outputs : as per ccp_par + * + * Operation : updates and / or displays ICMP MIB data + * -------------------------------------------------------------------------*/ +void ccpics(void) +{ + ccp_par(icmptab, (sizeof(icmptab) / sizeof(struct param))); +} + +#endif + +/************************************************************************ + * Function : Einen Ping absenden + * + * Inputs : clipoi/clicnt + * + * Outputs : nix, bis auf ein Ping-Frame + * + * Operation : Die Antwort erfolgt dann durch das Echo-Frame + * ---------------------------------------------------------------------*/ +void ccpping(void) +{ + ipaddr ip_addr; + MBHEAD *mbp; + + mbp = putals(""); + if (get_ip_addr(&ip_addr, &clicnt, &clipoi)) + { + if (pingem(ip_addr, 0, 0, 0, NULL)) { + putstr("ping ", mbp); + show_ip_addr(ip_addr, mbp); + putstr(" ...\r", mbp); + } else { +#ifdef SPEECH + putstr(speech_message(263), mbp); +#else + putstr("No route to ", mbp); +#endif + show_ip_addr(ip_addr, mbp); + putstr("\r", mbp); + } + } else putstr("Syntax: PING \r", mbp); + prompt(mbp); + seteom(mbp); +} + +/************************************************************************ + * Function : rt_add + * + * Inputs : Host-Addressen + * Hostbits in der Addresse + * Gateway-Addresse ( 0 wenn kein Gateway ) + * Port-Nummer ( NETROM_PORT oder L2-Port ) + * Metric + * Time to Live fuer diesen Eintrag + * Flag fuer private Routen (kein Publish) + * + * Returns : TRUE / FALSE ob die Tabelle gaendert wurde + * + * Operation : Eintrag hinzufuegen oder aendern + *----------------------------------------------------------------------*/ +BOOLEAN rt_add(ipaddr target, unsigned bits, ipaddr gateway, int port, +unsigned metric, unsigned ttl, int flags, BOOLEAN automatic) +{ + IP_ROUTE *iprp; + IP_ROUTE *iprp2; + ipaddr temp; + BOOLEAN new_entry = FALSE; + + /* Tabelle durchsuchen, wenn ein Eintrag existiert dann diesen updaten, */ + /* sonst neuen Eintrag erzeugen */ + if (!route_find(&iprp, &temp, target, bits)) + { + iprp2 = (IP_ROUTE *)allocb(ALLOC_IP_ROUTE); + relink((LEHEAD *)iprp2, (LEHEAD *)iprp->previp); + iprp = iprp2; + new_entry = TRUE; + } + iprp2 = iprp; + iprp2->dest = target; + iprp2->gateway = gateway; + iprp2->bits = bits; + iprp2->port = port; + iprp2->metric = metric; + iprp2->timer = ttl; + iprp2->flags = flags; + + /* neuer Eintrag, nur dann dieses Flag anfassen */ + if (new_entry == TRUE) + iprp2->automatic_flag = automatic; + + return(TRUE); +} + +/************************************************************************ + * Function : route_find() - Sucht nach einer Route fuer eine IP-Addresse + * + * Inputs : Zeiger auf den IP-Route-Buffer, Zeiger auf das Ergebnis + * Zeiger auf die gewuenschte Ziel-Addresse und die Hostbits + * + * Returns : BOOLEAN, die maskierte Addresse, und der Eintrag, + * falls gefunden + * + * Operation : Sucht nach einem exakt passenden Eintrag nach Hostbits + * und Addresse + *----------------------------------------------------------------------*/ +BOOLEAN route_find(IP_ROUTE **iprptr, ipaddr *temp, ipaddr target, +unsigned bits) +{ + IP_ROUTE *iprp; + + (*temp) = target; + + if (bits > 32) + bits = 32; + + (*temp) &= (~0L) << (32 - bits); + + for (iprp = (IP_ROUTE *)IP_Routes.head; + iprp != (IP_ROUTE *)&IP_Routes && bits <= iprp->bits; + iprp = (IP_ROUTE *)iprp->nextip) + if (iprp->dest == (*temp) && iprp->bits == bits) + { + *iprptr = iprp; + return(TRUE); + } + + *iprptr = iprp; + return(FALSE); +} + +/************************************************************************ + * Function : Einen Eintrag aus der Route-Tabelle loeschen + * + * Inputs : Die IP-Addresse und die Bitmaske + * + * Returns : Ergebnis BOOLEAN, veraendert die Routing-Tabelle + * + * Operation : Eintrag suchen und loeschen + * ---------------------------------------------------------------------*/ +BOOLEAN rt_drop(ipaddr target, unsigned bits, BOOLEAN automatic) +{ + IP_ROUTE *iprp; + ipaddr temp; + + if (route_find(&iprp, &temp, target, bits)) + { + /* nicht automatisch gemachte Eintrage nicht anfassen wenn */ + /* wir von einer Automatik aufgerufen worden sind */ + if ((automatic == TRUE) && (iprp->automatic_flag != TRUE)) + return(FALSE); + + dealoc((MBHEAD *) ulink((LEHEAD *) iprp)); + return(TRUE); + } + return(FALSE); +} + +/************************************************************************ + * Function : Einen Eintrag in der ARP-Tabelle machen + * + * Inputs : Die IP-Addresse, der Hardware-Port, die Hardware- + * Addresse (Rufzeichen), Datagram-Flag, Time_to_Live + * und Publish-Flag + * WICHTIG: digi darf nicht zu lang sein, sonst krachts! + * (Dies erledigt die aufrufende Routine!) + * + * Returns : Ergebnis BOOLEAN, aber in Wirklichkeit immer TRUE + * + * Operation : Den passenden Eintrag finden und aendern, sonst einen + * neuen anlegen. + * WICHTIG - Die Tabelle ist in absteigender Reihenfolge + * der Hostbits gespeichert. + *----------------------------------------------------------------------*/ +BOOLEAN arp_add(ipaddr target, WORD port, char *callsign, const char *digi, +unsigned dgmode, unsigned ttl, BOOLEAN publish, BOOLEAN automatic) +{ + ARP_TAB *arprp; + ARP_TAB *arprp2; + BOOLEAN new_entry = FALSE; + + /* Tabelle durchsuchen, wenn ein Eintrag existiert dann diesen updaten, */ + /* sonst neuen Eintrag erzeugen */ + if (!find_arp(&arprp, target, port)) + { + arprp = (ARP_TAB *)allocb(ALLOC_ARP_TAB); + relink((LEHEAD *)arprp, (LEHEAD *)Arp_tab.tail); + new_entry = TRUE; + } + arprp2 = arprp; + arprp2->dest = target; +#ifdef __WIN32__ + arprp2->port = (unsigned char)port; +#else + arprp2->port = port; +#endif /* WIN32 */ + arprp2->hwtype = port == NETROM_PORT ? ARP_NETROM : ARP_AX25; + arprp2->timer = ttl; + arprp2->publish_flag = publish; + arprp2->dgmode = dgmode; + + /* neuer Eintrag, nur dann dieses Flag anfassen */ + if (new_entry == TRUE) + arprp2->automatic_flag = automatic; + + cpyid(arprp2->callsign, callsign); + cpyidl(arprp2->digi, digi); + return(TRUE); +} + +#ifdef NOTUSE +/**************************************************************************** + * Function : Ist eine IP-Addresse als ARP bekannt? + * + * Inputs : die IP-Addresse + * + * Returns : Ergebnis BOOLEAN + *-------------------------------------------------------------------------*/ +static BOOLEAN is_ipaddr_inuse(ipaddr target) +{ + ARP_TAB *arprp; + + for (arprp = (ARP_TAB *)Arp_tab.head; + arprp != (ARP_TAB *)&Arp_tab; + arprp = (ARP_TAB *)arprp->nextar) + if (arprp->dest == target) + return(TRUE); + return(FALSE); +} + +/**************************************************************************** + * Function : Ist auf einem Port ein User als ARP bekannt? + * + * Inputs : die AX25-Addresse, Port + * + * Returns : Ergebnis BOOLEAN + *-------------------------------------------------------------------------*/ +static ipaddr is_hwaddr_inuse(char *hwaddr, WORD hwport) +{ + ARP_TAB *arprp; + + for (arprp = (ARP_TAB *)Arp_tab.head; + arprp != (ARP_TAB *)&Arp_tab; + arprp = (ARP_TAB *)arprp->nextar) + if (cmpid(arprp->callsign, hwaddr) && arprp->port == hwport) + return(arprp->dest); + return(0L); +} +#endif +/**************************************************************************** + * Function : Eine IP-Addresse aufloesen + * + * Inputs : Zeiger auf das Ergebnis, die IP-Addresse + * + * Returns : Ergebnis BOOLEAN, arpptr wird gesetzt + * + * Operation : Die ARP-Tabelle nach einem passenden Eintrag absuchen + *-------------------------------------------------------------------------*/ +BOOLEAN find_arp(ARP_TAB **arpptr, ipaddr target, WORD hwport) +{ + ARP_TAB *arprp; + + for (arprp = (ARP_TAB *)Arp_tab.head; + arprp != (ARP_TAB *)&Arp_tab; + arprp = (ARP_TAB *)arprp->nextar) + if ((arprp->dest == target) && + (hwport == arprp->port)) + { + *arpptr = arprp; + return(TRUE); + } + return(FALSE); +} + +/************************************************************************ + * Function : Einen ARP-Eintrag loeschen + * + * Inputs : Die IP-Nummer und die Hostbits + * + * Returns : Ergebnis BOOLEAN, ARP-Tabelle wird geandert + * + * Operation : Den passenden Eintrag suchen und ab in den Muell + *----------------------------------------------------------------------*/ +BOOLEAN arp_drop(ipaddr target, WORD hwport, BOOLEAN automatic) +{ + ARP_TAB *arprp; + + if (find_arp(&arprp, target, hwport)) + { + /* nicht automatisch gemachte Eintrage nicht anfassen wenn */ + /* wir von einer Automatik aufgerufen worden sind */ + if ((automatic == TRUE) && (arprp->automatic_flag != TRUE)) + return(FALSE); + + dealoc((MBHEAD *)ulink((LEHEAD *)arprp)); + return(TRUE); + } + return(FALSE); +} + +/*- End of IP router switch commands ---------------------------------------*/ + +/*- Start of IP router timer service routine--------------------------------*/ + +void arpsrv(void) +{ + ARP_TAB *arprp; + ARP_TAB *arp; + + if (--ARPcounter == 0) + { + ARPcounter = 60; + for (arprp = (ARP_TAB *)Arp_tab.head; + arprp != (ARP_TAB *)&Arp_tab; ) + { + if (IPpar[arprp->port].ipMode & ARP_OK) { + arp = arprp; + arprp = (ARP_TAB *)arprp->nextar; + /* ARP-Eintrag entfernen */ + if (arp->timer != 0 && --arp->timer == 0) + { + /* eventuell zusaetzlich angelegte Route entfernen */ + rt_drop(arp->dest, 32, TRUE); + + arp_drop(arp->dest, arp->port, FALSE); + } + } + } + } +} + +/*- End of IP router timer service routine------------------------------*/ + +#endif + +/* End of src/l7ip.c */ diff --git a/src/l7moni.c b/src/l7moni.c new file mode 100755 index 0000000..8447200 --- /dev/null +++ b/src/l7moni.c @@ -0,0 +1,1514 @@ +/************************************************************************/ +/* */ +/* ***** ***** */ +/* ***** ***** */ +/* ***** ***** */ +/* ***** ***** */ +/* *************** *************** */ +/* ***************** ***************** */ +/* *************** *************** */ +/* ***** ***** TheNetNode */ +/* ***** ***** Portable */ +/* ***** ***** Network */ +/* ***** ***** Software */ +/* */ +/* File src/l7moni.c (maintained by: ???) */ +/* */ +/* This file is part of "TheNetNode" - Software Package */ +/* */ +/* Copyright (C) 1998 - 2008 NORD>mbgc < mbp2->mbpc) { + c = getchr(mbp2); + if (c != TAB && c != LF) { + if (c != CR && c < ' ') { + putchr('^', mbp); + c += '@'; + } + putchr(c, mbp); + } + } +} + +/* Info-Daten umkopieren */ +static void frimon(MBHEAD *mbp, MBHEAD *fbp) +{ + BOOLEAN cr = (fbp->mbgc < fbp->mbpc); + UBYTE ch; + + while (fbp->mbgc < fbp->mbpc) { /* verfuegbare Info holen */ + ch = getchr(fbp); /* ein Byte holen */ + if (cr) { /* wenn ein CR aussteht */ + if (ch == CR) cr = FALSE; /* es ist schon gekommen */ + } else { /* kein CR ausstehen */ + if (ch != CR && ch != LF) /* CR,LF sind ok, sonst CR */ + cr = TRUE; /* anfordern */ + } + if (ch != LF) /* Line-Feed filtern */ + putchr(ch, mbp); /* Info umkopieren */ + } + if (cr) putchr(CR, mbp); /* neue Zeile am Schluss */ +} + +/*----------------------------------------------------------------------*/ +/* Frames fuer Monitor bearbeiten */ +/*----------------------------------------------------------------------*/ +void monitor(MBHEAD *fbp) +{ + MBHEAD *l2mbp; + MBHEAD *netmbp; + MBHEAD *imbp; + MBHEAD *tmpmbp; + char huge *mbbp; + UWORD mbgc; + char inflen[128]; + + mbbp = fbp->mbbp; + mbgc = fbp->mbgc; + + /* Bei I- und UI-Frames ist fbp->mbgc um eins zu klein, wegen PID */ +#ifndef MHRXTXBYTESFIX + statsv(fbp->mbpc, +#else + statsv(fbp->mbpc - fbp->mbgc, +#endif /* MHRXTXBYTESFIX */ + (fbp->mbgc < fbp->mbpc) ? fbp->mbgc + 1 : fbp->mbgc, + fbp->tx, + fbp->repeated); + + if (consmon.Mpar || tracnt) /* nur wenn Monitor oder Trace */ + { + l2mbp = (MBHEAD *)allocb(ALLOC_MBHEAD); /* Buffer fuer L2-Header */ + netmbp = (MBHEAD *)allocb(ALLOC_MBHEAD); /* Buffer fuer L3/4-Header */ + imbp = (MBHEAD *)allocb(ALLOC_MBHEAD); /* und einen fuer die Info */ + frhmon(l2mbp, fbp); /* L2-Header auswerten */ + netmbp->type = l2mbp->type; /* PID kopieren */ + nethmon(netmbp, fbp); /* L3/4-Header auch */ + if (!(rxfctl & L2CNOIM)) + { + if (fbp->tx && fbp->repeated > 0) + sprintf(inflen, "[Info %u Bytes repeated: %u]", + fbp->mbpc - fbp->mbgc, + fbp->repeated); + else + sprintf(inflen, "[Info %u Bytes]", + fbp->mbpc - fbp->mbgc); + } + else + { + inflen[0] = NUL; + } + frimon(imbp, fbp); /* Infofeld auswerten */ + if (tracnt) /* min. ein User will lauschen */ + { + for (userpo = (USRBLK *) usccpl.head; + userpo != (USRBLK *) &usccpl; + userpo = (USRBLK *) userpo->unext) + { +#ifdef USER_MONITOR + if (userpo->status == US_TRAC && userpo->monitor) +#else + if (userpo->status == US_CCP && userpo->monitor) +#endif /* USER_MONITOR */ + { + if (ismonf(fbp, userpo->monitor)) + { + tmpmbp = getmbp(); /* ein Buffer fuer den User */ + putmb(tmpmbp, l2mbp); /* L2-Header ausgeben */ + if (userpo->monitor->Mpar & MONT) + { + putstr(" - ", tmpmbp); + puttim(&sys_time, tmpmbp); + putlong(tic10, FALSE, tmpmbp); + } + putmb(tmpmbp, netmbp); /* L3/4_Header hinterher */ + if ( (userpo->monitor->Mpar & MONL) + && !(rxfctl & L2CNOIM)) + putprintf(tmpmbp, "%s\r", inflen);/* Infolaenge anzeigen */ + if (userpo->monitor->Mpar & MONF) /* wenn gewuenscht, auch */ + putmb(tmpmbp, imbp); /* die Infos ausgeben */ + +/* Damit der User nicht mehr Info bekommt, als er abnimmt, wird die */ +/* Ausgabe verworfen, wenn sein Link abgefuellt ist. */ + + if (!send_msg(FALSE,tmpmbp)) + dealmb(tmpmbp); + } + } + } + } + if ( monlin < 100 /* falls nix abgeholt wird */ + && ismonf(fbp, &consmon)) /* Ausgabe gewuenscht */ + { + if (consmon.Mpar & MONT) + { + putstr(" - ", l2mbp); + puttim(&sys_time, l2mbp); + } + l2mbp->type = HMRMONH; + if (!ishmod) + { + putmb(netmbp, l2mbp); + if ( (consmon.Mpar & MONL) + && !(rxfctl & L2CNOIM)) + putprintf(l2mbp, "\r%s", inflen); + } + dealmb(netmbp); + rwndmb(l2mbp); + relink((LEHEAD *)l2mbp, (LEHEAD *)smonfl.tail); + monlin++; + if ((imbp->mbpc != 0) && (consmon.Mpar & MONF)) + { + l2mbp->type = HMRMONIH; + if (ishmod) /* im Hostmode direkt das Infofeld */ + { /* ausgeben, nicht die ^A gewandelte */ + dealmb(imbp); + imbp = (MBHEAD *)allocb(ALLOC_MBHEAD); + fbp->mbbp = mbbp; + fbp->mbgc = mbgc; + getchr(fbp); /* ueberlesen */ + while ((fbp->mbgc < fbp->mbpc) && (imbp->mbpc < 256)) + putchr(getchr(fbp), imbp); + } + rwndmb(imbp); /* zurueckspulen */ + imbp->type = HMRMONI; + relink((LEHEAD *)imbp, (LEHEAD *)smonfl.tail); + monlin++; + } + else + dealmb(imbp); /* Info-Buffer freigeben */ + } + else /* Host ohne Monitor */ + { + dealmb(l2mbp); /* noch belegte Buffer freigeben */ + dealmb(netmbp); + dealmb(imbp); + } + fbp->mbbp = mbbp; + fbp->mbgc = mbgc; + } +} + +static BOOLEAN +owndigipt(const char *digis) +{ + if (*digis) + { /* via eigenes Call, zaehlt nicht als via in der Statistik */ + if (istome(digis) && !*(digis + L2IDLEN)) + return (TRUE); + } + return (FALSE); +} + +/*----------------------------------------------------------------------*/ +/* Statistik Arbeiten */ +/*----------------------------------------------------------------------*/ +static void +statsv(int count, int over_count, BOOLEAN tx, int repeated) +{ + WORD i; /* zum Zaehlen diverser Sachen */ + STAT *statp; /* Zeiger auf Statistiktabelle */ + char *viap; + const char *p; + char *callp; + MHEARD *mhp; + PORTSTAT *pstatp = portstat + (int)rxfprt; + WORD trx = tx ? 1 : 0; +#ifdef MH_LISTE + char via[8 * L2IDLEN + 1]; + char SaveHeader[L2AFLEN + 1]; +#endif + + throughput += count; /* fuer den Gesammtdurchsatz */ + +/*------------------------------------- Portstatistikliste updaten -----*/ +/* gesendete und empfangene Bytes zaehlen */ + if (!tx) + { + pstatp->rx_bytes += (ULONG) count; + pstatp->rx_overhead += (ULONG) over_count; + } + else + { + pstatp->tx_bytes += (ULONG) count; + pstatp->tx_overhead += (ULONG) over_count; + } +/*------------------------------------------- Portgraph updaten --------*/ +#ifdef PORTGRAPH + if (!(rxfctl & L2CNOIM)) + { + graph_actual_trxpeak(&graph.info[(int)rxfprt], tx); + } + else + if (!(rxfctl & L2CNOSM)) + { + if ((rxfctl & ~L2CPF) == L2CREJ) + graph_actual_trxpeak(&graph.reject[(int)rxfprt], tx); + } + else + { + switch (rxfctl & ~L2CPF) + { + case L2CSABM: +#ifdef EAX25 + case L2CSABME: +#endif + graph_actual_trxpeak(&graph.sabm[(int)rxfprt], tx); + break; + case L2CDISC: + graph_actual_trxpeak(&graph.disc[(int)rxfprt], tx); + break; + case L2CDM: + graph_actual_trxpeak(&graph.dm[(int)rxfprt], tx); + break; + case L2CFRMR: + graph_actual_trxpeak(&graph.frmr[(int)rxfprt], tx); + break; + } /* switch */ + } /* else */ +#endif + +/************************************************************************/ +/* MH-Liste bearbeiten */ +/************************************************************************/ +#ifdef MH_LISTE + /* Original Haeder sichern. */ + strncpy(SaveHeader, rxfhdr, 2 * L2IDLEN + L2VLEN + 1); + /* Hole das aktuelle via-call. */ + strncpy(via, dheardcall(rxfhdr), 8 * L2IDLEN); + + /* Unser Eigenes Knotencall oder call was zuletzt gedigipeated hat. */ + if (via[0] != FALSE) + { + /* Eigenes Knotencall. */ + if (cmpid(via, myid)) + { + /* Zum naechsten Rufzeichen. */ + if (via[L2IDLEN + 1] != FALSE) + /* Das ist unser Rufzeichen. */ + cpyid(rxfhdr, via + L2IDLEN); + /* Keine Digipeaterkette. */ + else + /* 2. Rufzeichen im rxfhdr. */ + cpyid(rxfhdr + L2IDLEN, rxfhdr); + } + /* Nicht unser Knotencall. */ + else + { + /* TX-Frame. */ + if (tx) + /* Das ist unser Rufzeichen. */ + cpyid(rxfhdr, via); + /* RX-Frame */ + else + /* Keine Digipeaterkette. */ + if (via[L2IDLEN + 1] == FALSE) + /* Das ist unser Rufzeichen. */ + cpyid(rxfhdr + L2IDLEN, via); + /* Digipeaterkette. */ + else + /* 2. Rufzeichen im rxfhdr. */ + cpyid(rxfhdr + L2IDLEN, via); + } + } +#endif + + if (updmheard((int)rxfprt)) + { + if (!tx) /* RX-Frame */ + { +#ifdef MH_LISTE +#ifdef __WIN32__ + if ((mhp = mh_lookup_port(&l2heard, rxfhdr + L2IDLEN, (unsigned short)rxfprt,tx)) == NULL) +#else + if ((mhp = mh_lookup_port(&l2heard, rxfhdr + L2IDLEN, rxfprt,tx)) == NULL) +#endif /* WIN32 */ +#else /* MH_LISTE */ +#ifdef __WIN32__ + if ((mhp = mh_lookup_port(&l2heard, rxfhdr + L2IDLEN, (unsigned short)rxfprt)) == NULL) +#else + if ((mhp = mh_lookup_port(&l2heard, rxfhdr + L2IDLEN, rxfprt)) == NULL) +#endif /* WIN32 */ +#endif /* MH_LISTE */ + mhp = mh_add(&l2heard); + if (mhp) + { +#ifdef __WIN32__ + mh_update(&l2heard, mhp, rxfhdr + L2IDLEN, (unsigned short)rxfprt); +#else + mh_update(&l2heard, mhp, rxfhdr + L2IDLEN, rxfprt); +#endif /* WIN32 */ +#ifdef EAX25 + switch (rxfctl) + { + case L2CSABM : mhp->eax_link = FALSE; break; + case L2CSABME: mhp->eax_link = TRUE; break; +#ifdef MHEAX_LINKFIX + case L2CUA : mhp->eax_link = FALSE; break; +#endif /* MHEAX_LINKFIX */ + + default: break; + } +#endif + mhp->rx_bytes += count; + if ((rxfctl & 0xf) == L2CREJ) + mhp->rx_rej++; + } + } + else + { +#ifdef MH_LISTE +#ifdef __WIN32__ + if ((mhp = mh_lookup_port(&l2heard, rxfhdr, (unsigned short)rxfprt,tx)) != NULL) +#else + if ((mhp = mh_lookup_port(&l2heard, rxfhdr, rxfprt,tx)) != NULL) +#endif /* WIN32 */ +#else /* MH_LISTE */ +#ifdef __WIN32__ + if ((mhp = mh_lookup_port(&l2heard, rxfhdr, (unsigned short)rxfprt)) != NULL) +#else + if ((mhp = mh_lookup_port(&l2heard, rxfhdr, rxfprt)) != NULL) +#endif /* WIN32 */ +#endif /* MH_LISTE */ + { + mhp->tx_bytes += count; + if ((rxfctl & 0xf) == L2CREJ) + mhp->tx_rej++; + } + } + } + +#ifdef MH_LISTE + strncpy(rxfhdr, SaveHeader, 2 * L2IDLEN + L2VLEN); +#endif /* MHLISTDIRECTLY */ + + + /*------------------------------------------ LinkStatistik updaten -----*/ + + for (statp = mh, i = 0; i < MAXSTAT; statp++, i++) + { + if (!(*statp->call)) + continue; + +/************************************************************************/ +/* Die rxfhdr Liste ist in Ziel/Quell/via Rufzeichen aufgeteilt. Bei */ +/* einem TX-Frame (tx == 1) ist somit das Zielid (rxfhdr) interessant */ +/* und bei einem RX-Frame (tx == 0) ist das Quellid (rxfhdr+L2IDLEN) */ +/* von Interesse. */ +/************************************************************************/ + + if (!tx) + callp = rxfhdr + L2IDLEN; /* Quellcall bei Rx-Frame */ + else + callp = rxfhdr; /* Zielcall bei Tx-Frame */ + +/************************************************************************/ +/* Bei einem Linkstateintrag ohne viacall-Angabe darf trotzdem das */ +/* eigene Call im Viafeld stehen. */ +/************************************************************************/ + + if (statp->viacall[0] == NUL) /* ohne via Angabe */ + { + if ( cmpid(callp, statp->call) /* Stimmt Rufzeichen */ + && ( *(rxfhdr + L2ILEN) == NUL /* und kein Viafeld */ + || owndigipt(rxfhdr + L2ILEN))) /* oder eigenes Call */ + break; + } + else /* mit via Angabe */ + { + if ( cmpid(statp->call, callp) /* Stimmt Rufzeichen */ + || cmpid(statp->call, anycall)) + { + if (!tx) + { + +/************************************************************************/ +/* Viacall-Liste nach entsprechenden via-Rufzeichen durchsuchen. */ +/* Korrekter waere es, das letzte "digipeated" Rufzeichen zu suchen und */ +/* zu vergleichen! */ +/************************************************************************/ + + if (*(viap = rxfhdr + L2ILEN) != NUL) /* Zeiger auf Via-Liste */ + if (invial(viap, statp->viacall)) /* Wenn Call in Liste */ + if (*(viap + L2IDLEN - 1) & L2CH) /* und ge-digipeatet */ + break; + } + else /* "first not digipeated" Rufzeichen ermitteln */ + { + if (*(p = ndigipt(rxfhdr + L2ILEN)) != NUL) + if (cmpid(statp->viacall, p)) + break; + } + } + } + } /* for */ + +/************************************************************************/ +/* ACHTUNG !!! Bei einer doppelten Eintragung des Via-Rufzeichens und */ +/* der Verwendung des "*" Symbols ist darauf zu achten, dass das */ +/* normale Rufzeichen vor der Eintragung mit dem "*" Symbol steht, */ +/* ansonsten wird fuer die normale Eintragung keine Zaehlung */ +/* vorgenommen. */ +/************************************************************************/ + + if (i < MAXSTAT) + { + if (statp->hfirst == 0L) /* zum ersten Mal gehoert */ + statp->hfirst = sys_time; + + if (!tx) + statp->hlast = sys_time; /* last heard updaten */ + + statp->Bytetotal[trx] += (ULONG) count; + statp->Byteheader[trx] += (ULONG) over_count; + + if (!(rxfctl & L2CNOIM)) + { + statp->Ino[trx]++; +/* wiederholt gesendetes I-Frame ? */ + if (tx && repeated && count > over_count) + statp->txByterepeated += (ULONG)(count - over_count); + } + else + if (!(rxfctl & L2CNOSM)) + { + switch ((rxfctl >> 2) & 0x3) + { + case 0 : statp->RRno[trx]++; + break; + case 1 : statp->RNRno[trx]++; + break; + case 2 : statp->REJno[trx]++; + break; + } + } + else + { + switch ((rxfctl >> 2) & 0x3b) + { + case 0 : statp->UIno[trx]++; + break; + case 3 : statp->DMno[trx]++; + break; + case 11 : statp->SABMno[trx]++; + break; + case 16 : statp->DISCno[trx]++; + break; + case 24 : statp->UAno[trx]++; + break; + case 33 : statp->FRMRno[trx]++; + break; + } /* switch */ + } /* else */ + } +} + +static void dump_nodes(MBHEAD *mbp, MBHEAD *fbp) +{ + char id[L2IDLEN]; + int i; + + putstr("\rNODES-Broadcast:", mbp); + while (fbp->mbpc - fbp->mbgc >= 21) { + if (getfid(id,fbp) == TRUE) { + putchr('\r', mbp); + for (i = 0; i < L2CALEN; ++i) + putchr(getchr(fbp), mbp); + putchr(':', mbp); + putid(id, mbp); + if (getfid(id,fbp) == TRUE) { + putstr(" v ", mbp); + putid(id, mbp); + putchr(' ', mbp); + putnum(getchr(fbp), mbp); + continue; + } + } + return; + } +} + +static void +dump_inp_nodes(MBHEAD *mbp, MBHEAD *fbp) +{ + char desnod[L2IDLEN]; + char beaide[L2IDLEN], *bp; + int qual; + int ttl; + int tag; + int len; + int ch, i; + UBYTE ipa[5]; + + getchr(fbp); /* Kennung uebergehen */ + putstr("\rRouting Information:", mbp); + while (fbp->mbpc - fbp->mbgc > 10) + { + if (!getfid(desnod, fbp)) + break; + putchr('\r', mbp); + putid(desnod, mbp); + ttl = getchr(fbp); + qual = get16(fbp); + putprintf(mbp, " %u / %u", qual, ttl); + while (fbp->mbgc < fbp->mbpc) /* 1 RIP Eintrag lesen */ + { + if ((len = getchr(fbp)) > 0) /* Eintragsende? (EOP Byte) */ + len--; /* Laengenbyte selbst abziehen */ + + if (fbp->mbpc - fbp->mbgc < len) /* noch genug vorhanden? */ + { +#ifdef SPEECH + putprintf(mbp, speech_message(268), len, (int) (fbp->mbpc - fbp->mbgc)); +#else + putprintf(mbp, "\rINP: frame error, len = %u, left = %u\r", + len, (int) (fbp->mbpc - fbp->mbgc)); +#endif + break; + } + if (len-- < 1) /* TAG abziehen */ + break; + + switch (tag = getchr(fbp)) + { + case INP_ALIAS: + if (len > L2CALEN) + { +#ifdef SPEECH + putstr(speech_message(271), mbp); +#else + putstr(" (INVALID ALIAS!)\r", mbp); +#endif + return; + } + for (i = 0, bp = beaide; i < len; i++) + { + ch = getchr(fbp); + if ((ch < ' ') || (ch > 127)) + ch = '?'; + *bp++ = ch; + } + for (; i < L2CALEN; i++) + *bp++ = ' '; + putprintf(mbp, " (ALIAS=%6.6s)", beaide); + break; + case INP_IPA: + if (len != 5) + { +#ifdef SPEECH + putstr(speech_message(272), mbp); +#else + putstr(" (INVALID IP ADDRESS!)\r", mbp); +#endif + return; + } + for (i = 0; i < 5; i++) /* IP-Nr + Subnet lesen */ + ipa[i] = (UBYTE)getchr(fbp); + putprintf(mbp, " (IP = %u.%u.%u.%u/%u)", + ipa[0], ipa[1], ipa[2], ipa[3], ipa[4]); + break; + default : + putprintf(mbp, " (LEN=%u TAG=%u", len, tag); + while (len-- > 0) + putprintf(mbp, " %02X", getchr(fbp)); + putchr(')', mbp); + break; + } + } + } + putchr('\r', mbp); +} + +const char * +l4opctab = "ESCAPE" + "CONREQ" + "CONACK" + "DISREQ" + "DISACK" + "INFTRA" + "INFACK" +#ifdef NEW_L4 + "PIDCHG"; +#else + "STATRA"; +#endif + +static void dump_netrom(MBHEAD *mbp, MBHEAD *fbp) +{ + char id[L2IDLEN]; + UBYTE l4opco = 0; + UBYTE l4idx[4]; + WORD i; + + if (rxfctl != L2CUI) { /* I-Frames */ + if (*fbp->mbbp == 0xFF) + dump_inp_nodes(mbp, fbp); + else + if (getfid(id,fbp) == TRUE) { /* L3-Teil beginnt mit Call */ + putstr("\r(L3 ", mbp); /* L3-Teil in neue Zeile */ + putid(id, mbp); /* L3-Absendercall */ + if (getfid(id,fbp) == TRUE) { /* L3-Empfaenger vorhanden? */ + putchr('>', mbp); + putid(id, mbp); /* L3-Empfaenger anzeigen */ + if (fbp->mbgc < fbp->mbpc) { /* L3-Lifetime vorhanden? */ + putstr(" TTL=", mbp); + putnum(getchr(fbp), mbp); /* dann anzeigen */ + } + if (fbp->mbpc - fbp->mbgc >= 5) { /* gueltiger L4-Teil? */ + putstr(")\r(L4 ", mbp); /* L4-Teil in neue Zeile */ + for (i = 0; i < 4; ++i) /* 4 L4-Header Bytes */ + l4idx[i] = getchr(fbp); + l4opco = getchr(fbp); + if (l4opco & 0x18) + putnum(l4opco, mbp); + else + putprintf(mbp, "%6.6s", l4opctab + (l4opco & L4OPMASK) * 6); + if (l4opco & L4CMORE) + putstr("+MORE", mbp); + if (l4opco & L4CNAK) + putstr("+NAK", mbp); + if (l4opco & L4CCHOKE) + putstr("+CHOKE", mbp); + for (i = 0; i < 4; ++i) { /* Opcodes anzeigen */ + putchr(' ', mbp); + putnum(l4idx[i], mbp); + } + if (l4opco == 5 && + cmpid(id, "L3RTT \140") && + match(fbp, "BROAD") /* BROAD Kennung ? */ + ) { + putchr(')', mbp); + dump_nodes(mbp, fbp); /* Nodes zeigen */ + return; + } + if (l4opco == 1 || l4opco == 2) /* ConnReq o. ConnAck */ + if (fbp->mbgc < fbp->mbpc) { /* es sollte noch mehr */ + putchr(' ', mbp); /* kommen */ + putnum(getchr(fbp), mbp); /* L4 Window Size */ + if (l4opco == 1) /* Connect Request */ + if (getfid(id,fbp) == TRUE) { + putchr(' ', mbp); + putid(id, mbp); /* User Call */ + if (getfid(id,fbp) == TRUE) + { + putchr(' ', mbp); + putid(id, mbp); /* Absenderknoten */ + if (fbp->mbpc - fbp->mbgc >= 7) /* neue Soft- */ + { /* ware? */ + if (getfid(id,fbp) == TRUE) /* Uplinkknoten */ + { + putstr(" v ",mbp); /*wie normale Digiliste*/ + putid(id, mbp); /* aber max. 9 Calls */ + while (*fbp->mbbp != NUL) /* Ende erreicht?*/ + { + if (fbp->mbpc - fbp->mbgc < 7) break; + if (!getfid(id,fbp)) break; + putchr(' ', mbp); + putid(id, mbp); + } + if (fbp->mbgc < fbp->mbpc) getchr(fbp); + /* Nullterminierung Digiliste abholen */ + } + } + } + } + } + } + } + putchr(')', mbp); /* Ende L3/4-Teil */ + if (l4opco == L3TCPUDP) { + if (l4idx[0] == 0 && l4idx[1] == 1) { + dump_nrr(mbp, fbp); + } +#ifdef IPROUTE + else + dump_ip(mbp, fbp); +#endif + } + } + } + else /* L3-UI Frame */ + if (fbp->mbpc - fbp->mbgc >= 7) + { + putprintf(mbp, "\r%02X ", getchr(fbp)); + for (i = 0; i < L2CALEN; ++i) + putchr(getchr(fbp), mbp); + dump_nodes(mbp, fbp); /* Node-Informationen zeigen */ + } +} + +/* ---------------------------------------- */ +/* ---- Netrom-Record-Route ausgeben ------ */ +/* ---------------------------------------- */ +static void dump_nrr(MBHEAD *mbp, MBHEAD *fbp) +{ + char id[L2IDLEN]; + int lt; + + putstr(" NET/ROM Route Record\r", mbp); + while (fbp->mbpc - fbp->mbgc >= L2IDLEN+1) { /* Eintrag da? */ + if (getfid(id, fbp) == TRUE) { + lt = getchr(fbp); + if (lt & ECHO_FLAG) putchr('*', mbp); + putid(id, mbp); + putprintf(mbp, "(%u) ", lt & LT_MASK); + } + } + + while (fbp->mbgc < fbp->mbpc) getchr(fbp); /* kein Schrott auf den Schirm */ +} + +#ifdef IPROUTE +/* ------------------------------------ */ +/* Adress-Resolution-Protokoll ausgeben */ +/* ------------------------------------ */ +static void dump_arp(MBHEAD *mbp, MBHEAD *fbp) +{ + ARP arp; + + arp.hardware = get16(fbp); + arp.protocol = get16(fbp); + arp.hwalen = getchr(fbp); + arp.pralen = getchr(fbp); + arp.opcode = get16(fbp); + getfid((char *)arp.shwaddr, fbp); + arp.sprotaddr = get32(fbp); + getfid((char *)arp.thwaddr, fbp); + arp.tprotaddr = get32(fbp); + + putstr("\r(", mbp); + switch (arp.opcode) { + case ARP_REQUEST : putstr("ARP-REQ ", mbp); break; + case ARP_REPLY : putstr("ARP-REPLY ", mbp); break; + case REVARP_REQUEST : putstr("REVARP-REQ ", mbp); break; + case REVARP_REPLY : putstr("REVRARP-REPLY ", mbp); break; + default : putprintf(mbp, "ARP%04X ", arp.opcode); break; + } + switch (arp.hardware) { + case ARP_NETROM : putstr("NET/ROM ", mbp); break; + case ARP_AX25 : putstr("AX25 ", mbp); break; + default : putprintf(mbp, "hardware=%04X ", arp.hardware); + } + switch (arp.protocol) { + case L2CIP : putstr("IP-Proto", mbp); break; + default : putprintf(mbp, "Proto=%04X", arp.protocol); break; + } + if (arp.hwalen != 7 || arp.pralen != 4) + putprintf(mbp, " hwalen=%u pralen=%u", arp.hwalen, arp.pralen); + putstr(")\rSource=", mbp); + putid((char *)arp.shwaddr, mbp); + putchr(':', mbp); + show_ip_addr(arp.sprotaddr, mbp); + putstr(" Dest=", mbp); + if (arp.opcode == ARP_REQUEST) + putstr("unknown", mbp); + else + putid((char *)arp.thwaddr, mbp); + putchr(':', mbp); + if (arp.opcode == REVARP_REQUEST) + putstr("unknown", mbp); + else + show_ip_addr(arp.tprotaddr, mbp); +} + +/* -------------------------------------------------------- */ +/* ------------ IP-Header ausgeben ------------------------ */ +/* -------------------------------------------------------- */ +static void dump_ip(MBHEAD *mbp, MBHEAD *fbp) +{ + IP ip; + int ip_len; + + ip_len = getchr(fbp); /* Laenge und Version lesen */ + ip.ihl = ip_len & 0x0f; + ip.version = (ip_len >> 4) & 0x0f; /* Versionsnummer */ + ip.tos = getchr(fbp); /* Type off Service */ + ip.length = get16(fbp); /* Laenge Header und Data */ + ip.id = get16(fbp); /* Fragment ID */ + ip.offset = get16(fbp); /* Fragnent Offset */ + ip.flags.mf = (ip.offset & 0x2000) ? 1 : 0; /* more follow */ + ip.flags.df = (ip.offset & 0x4000) ? 1 : 0; /* dont fragment */ + ip.offset = (ip.offset & 0x1fff); /* << 3 Fragment Offset*/ + ip.ttl = getchr(fbp); /* Time-to-Live */ + ip.protocol = getchr(fbp); /* Kennzahl des aufsetzenden Protokolls */ + ip.checksum = get16(fbp); + ip.source = get32(fbp); + ip.dest = get32(fbp); + + putprintf(mbp, "\r(IPV%u ", ip.version); + if (ip.version == 4) { + putstr("fm ", mbp); + show_ip_addr(ip.source, mbp); + putstr(" to ", mbp); + show_ip_addr(ip.dest, mbp); + putprintf(mbp, " IHL=%d TOS:%x Length=%d ID=%d \rFlags:MF=%x DF=%x FraOff=%u TTL=%u ", + ip.ihl, ip.tos, ip.length, ip.id ,ip.flags.mf , ip.flags.df ,ip.offset ,ip.ttl); + switch (ip.protocol) { + case ICMP_PTCL : putstr("ICMP)\r", mbp); + if (ip.offset == 0) + dump_icmp(mbp, fbp, &ip); + break; + case TCP_PTCL : putstr("TCP)\r", mbp); + if (ip.offset == 0) /* das Folgefragment hat keinen TCP-Header */ + tcp_DumpHeader(mbp, fbp, &ip); + break; + case UDP_PTCL : putstr("UDP)\r", mbp); + if (ip.offset == 0) + dump_udp(mbp, fbp, &ip); + break; + default : putprintf(mbp, "Proto=%02X)", ip.protocol); + } + } else + putstr("unknown)", mbp); +} + +/* ------------------------------------------------------------------ */ +/* ----- Dump tcp protocol header of a packet ----------------------- */ +/* ------------------------------------------------------------------ */ +static void tcp_DumpHeader(MBHEAD *mbp, MBHEAD *fbp, IP *in_header) +{ + static const char *flags[] = { "FIN", "SYN", "RST", "PUSH", "ACK", "URG" }; + int len,f,temp_flag; + TCP tcp; + + tcp.srcPort = get16(fbp); /* Port-Nummer der Quelle */ + tcp.dstPort = get16(fbp); /* Port-Nummer des Ziels */ + tcp.seqnum = get32(fbp); /* Sequenznummer des 1. Datenbytes in diesem Segment */ + tcp.acknum = get32(fbp); /* Bestaetigungsnummer */ + temp_flag = get16(fbp); + tcp.data_offset = (temp_flag >> 12) & 0x0f; /* Datenworte im header */ + tcp.res = (temp_flag >> 6) & 0x3f; /* nicht benutzt -> 0 */ + tcp.flags = temp_flag & 0x3f; /* URG,ACK,PSH,RST,SYN & FIN */ + tcp.window = get16(fbp); /* Groesse des Puffers fuer diese Verb. */ + tcp.checksum = get16(fbp); /* CRC */ + tcp.urgentPointer = get16(fbp); + + len = (in_header->length) - ((tcp.data_offset * 4) + (in_header->ihl * 4)); + + putprintf(mbp, "TCP Packet: SrcP:%d DstP:%d SeqN=%lx AckN=%lx Wind=%d\r", + tcp.srcPort, + tcp.dstPort, + tcp.seqnum, + tcp.acknum, + tcp.window); + + putprintf(mbp, "DataLen=%d DataOffset=%d, CRC=%x Urgent=%d\r", + len, + tcp.data_offset, + tcp.checksum, + tcp.urgentPointer); + + /* output flags */ + f = (tcp.flags); + for (len = 0; len < 6; len++) + if (f & (1 << len)) + putprintf(mbp,"Flag: %s\r", flags[len]); +} + +/* DUMP UDP */ +static void dump_udp(MBHEAD *mbp, MBHEAD *fbp, IP *in_header) +{ + + UDP udp; + + udp.srcPort = get16(fbp); + udp.dstPort = get16(fbp); + udp.length = get16(fbp); + udp.checksum = get16(fbp); + + putprintf(mbp, "UDP Packet: SrcP:%d DstP:%d Len=%d CRC=%x\r", + udp.srcPort, + udp.dstPort, + udp.length, + udp.checksum); + +} + +/* DUMP ICMP */ +static void dump_icmp(MBHEAD *mbp, MBHEAD *fbp, IP *in_header) +{ + + ICMP icmp; + + icmp.type = getchr(fbp); + icmp.code = getchr(fbp); + icmp.checksum = get16(fbp); + + putprintf(mbp, "ICMP Packet: Type:%d Code:%d CRC=%x\r", + icmp.type, + icmp.code, + icmp.checksum); +} +#endif + +/*----------------------------------------------------------------------*/ +/* Fragmentierte AX25 Frames bearbeiten */ +/*----------------------------------------------------------------------*/ +static void +dump_frag(MBHEAD *mbp, MBHEAD *fbp) +{ + BYTE anz_frames; + BYTE pid; + + anz_frames = getchr(fbp); /* erstes Byte lesen */ + + if (anz_frames & 0x80) /* erstes Frame ? */ + { + pid = getchr(fbp); +#ifdef SPEECH + putprintf(mbp,speech_message(269), (anz_frames & 0x7F), (pid & 0xFF)); +#else + putprintf(mbp,"\r[AX25 Fragment; %u Frame(s) to follow - " + "original PID %X]\r", (anz_frames & 0x7F), (pid & 0xFF)); +#endif +#ifdef IPROUTE + /* Je nach PID noch eine extra Ausgabe */ + switch (pid & 0xFF) + { + case L2CIP: + dump_ip(mbp, fbp); + break; + + case L2CNETROM: + dump_netrom (mbp, fbp); + break; + } +#endif + } + else /* Folgeframe */ +#ifdef SPEECH + putprintf(mbp,speech_message(270),(anz_frames & 0x7F)); +#else + putprintf(mbp,"\r[AX25 Fragment; %u Frame(s) to follow]\r", + (anz_frames & 0x7F)); +#endif +} + +/*----------------------------------------------------------------------*/ +/* Frame Header im Monitor zeigen */ +/*----------------------------------------------------------------------*/ +static void +frhmon(MBHEAD *mbp, MBHEAD *fbp) +{ +#if MAX_TRACE_LEVEL > 0 + UBYTE uFRMR_Bytes[4]; +#endif + +#ifdef NOPORTINMON + putstr("fm ", mbp); +#else + putprintf(mbp,"%c%d: fm ", fbp->tx ? 'T' : 'R', fbp->l2port); +#endif + + putid(rxfhdr + L2IDLEN, mbp); /* Absender-Rufzeichen */ + putstr(" to ", mbp); + putid(rxfhdr, mbp); /* Zielrufzeichen */ + putdil(rxfhdr + L2ILEN, mbp); + putchr(' ', mbp); + if (!(rxfctl & L2CNOIM)) + putchr('I', mbp); + else + if (!(rxfctl & L2CNOSM)) + switch (rxfctl & 0x0c) + { + case L2CRR & 0x0c: + putstr("RR", mbp); + break; + case L2CRNR & 0x0c: + putstr("RNR", mbp); + break; + case L2CREJ & 0x0c: + putstr("REJ", mbp); + break; + default: + putprintf(mbp, "?%02XH", (char)(rxfctl | rxfPF)); + break; + } + else + /* U-Frame */ + switch (rxfctl & 0xFF) + { + case L2CUI: + putstr("UI", mbp); + break; + case L2CDM: + putstr("DM", mbp); + break; + case L2CSABM: + putstr("SABM", mbp); + break; +#ifdef EAX25 + case L2CSABME: + putstr("SABME", mbp); + break; +#endif + case L2CDISC: + putstr("DISC", mbp); + break; + case L2CUA: + putstr("UA", mbp); + break; + case L2CFRMR: + putstr("FRMR", mbp); + +#if MAX_TRACE_LEVEL > 0 + switch (fbp->mbpc - fbp->mbgc) + { + /* AX.25 hat drei FRMR-Bytes */ + case 3: + /* EAX.25 hat fuenf FRMR-Bytes */ + case 5: + if ((fbp->mbpc - fbp->mbgc) == 3) + { /* AX.25 */ + uFRMR_Bytes[0] = getchr(fbp); + uFRMR_Bytes[1] = getchr(fbp); + + notify(1, "FRMR: Ctl: 0x%0.2X, N(r): %u, N(s): %u, C/R: %u", + uFRMR_Bytes[0], + (uFRMR_Bytes[1] >> 5 & 0x07), + (uFRMR_Bytes[1] >> 4 & 0x01), + (uFRMR_Bytes[1] & 0x01)); + } + else + { /* EAX.25 */ + uFRMR_Bytes[0] = getchr(fbp); + uFRMR_Bytes[1] = getchr(fbp); + uFRMR_Bytes[2] = getchr(fbp); + uFRMR_Bytes[3] = getchr(fbp); + + notify(1, "FRMR: Ctl1: 0x%0.2X, Ctl2: 0x%0.2X, N(s): %u, N(r): %u, C/R: %u", + uFRMR_Bytes[0], + uFRMR_Bytes[1], + (uFRMR_Bytes[2] >> 1 & 0x7F), + (uFRMR_Bytes[3] >> 1 & 0x7F), + (uFRMR_Bytes[3] & 0x01)); + } + + /* AX.25 und EAX.25 */ + /* ZYXW-Byte */ + uFRMR_Bytes[0] = getchr(fbp); + /* W */ + if (uFRMR_Bytes[0] & 0x01) + notify(1, "Invalid control field"); + /* X */ + if (uFRMR_Bytes[0] & 0x02) + notify(1, "Illegal I-field"); + /* Y */ + if (uFRMR_Bytes[0] & 0x04) + notify(1, "I-field too long"); + /* Z */ + if (uFRMR_Bytes[0] & 0x08) + notify(1, "Invalid sequence number"); + + break; + + /* keine spezielle Auswertung / unbekannte Anzahl FRMR-Bytes */ + default: + while (fbp->mbgc < fbp->mbpc) + putprintf(mbp, "%02X", getchr(fbp)); + } +#else + while (fbp->mbgc < fbp->mbpc) + putprintf(mbp, "%02X", getchr(fbp)); +#endif + break; + + default: + putprintf(mbp, "?%02XH", (char)(rxfctl | rxfPF)); + break; + } + + if ((rxfctl & 0x3) != 3) /* keine U-Frames, nur I- und S-Frames */ + { +#ifdef EAX25 + if (rxfEAX) /* EAX.25-Frames */ + { + /* S-Frames */ + putprintf(mbp, "%02X", (rxfctlE >> 1) & 0x7F); /* N(r) */ + + if ((rxfctl & 0x01) == 0) /* zusaetzliches fuer I-Frames */ + putprintf(mbp, "%02X", (rxfctl >> 1) & 0x7F); /* N(s) */ + } + else + { +#endif + /* normale AX.25-Frames */ + putnum((rxfctl >> 5) & 0x7, mbp); + + if (!(rxfctl & L2CNOIM)) + putnum((rxfctl >> 1) & 0x7, mbp); +#ifdef EAX25 + } +#endif + } + + /* Pollflag und Command/Response */ + if (rxfPF != 0) +#ifdef __WIN32__ + putchr((char)(rxfCR != 0 ? '+' : '-'), mbp); +#else + putchr(rxfCR != 0 ? '+' : '-', mbp); +#endif /* WIN32 */ + else +#ifdef __WIN32__ + putchr((char)(rxfCR != 0 ? '^' : 'v'), mbp); +#else + putchr(rxfCR != 0 ? '^' : 'v', mbp); +#endif /* WIN32 */ + if (!(rxfctl & L2CNOIM) || rxfctl == L2CUI) + putprintf(mbp, " pid %02X", + mbp->type = (fbp->mbgc < fbp->mbpc) ? getchr(fbp) : 0); + /* DAMA-Frame */ + if (rxfDA) + putstr(" [DAMA]", mbp); + +#ifdef EAX25 + /* EAX.25-Frame */ + if (rxfEAX) + putstr(" [EAX]", mbp); +#endif + +#ifdef MAXFRAMEDEBUG + if (fbp->tx == 1 && !(rxfctl & L2CNOIM)) + putprintf(mbp, " f=%04x, lmf=%u, pmf=%u, t=%u", + fbp->lnkflag, fbp->lmf, fbp->pmf, fbp->tosend); +#endif +} + +/*----------------------------------------------------------------------*/ +/* Network Header im Monitor zeigen */ +/*----------------------------------------------------------------------*/ +static void +nethmon(MBHEAD *netmbp, MBHEAD *fbp) +{ + if (!(rxfctl & L2CNOIM) || rxfctl == L2CUI) + { + switch (netmbp->type) /* PID */ + { + case L2CTEXNET: + case L2CNETROM: dump_netrom(netmbp, fbp); + break; + case L2CFRAG : dump_frag(netmbp, fbp); + break; +#ifdef IPROUTE + case L2CARP : dump_arp(netmbp, fbp); + break; + case L2CIP : putstr(" TCP/IP", netmbp); + dump_ip(netmbp, fbp); + break; +#endif + } + } + putchr('\r', netmbp); +} + +/*----------------------------------------------------------------------*/ +/* is monitor frame? */ +/*----------------------------------------------------------------------*/ +static BOOLEAN ismonf(MBHEAD *fbp, MONBUF *m) +{ + if ((m->Mpar & MONC) != FALSE) { + if ((fbp->l2port == m->Mport) || (m->Mport > L2PNUM)) { + if ( ((!(rxfctl & L2CNOIM)) && (((m->Mpar & MONI) != 0))) + || (((rxfctl & 3) == 1) && ((m->Mpar & MONS) != 0)) + || ( ((rxfctl & 3) == 3) + && (rxfctl != L2CUI) + && ((m->Mpar & MONS) != 0)) + || ((rxfctl == L2CUI) && ((m->Mpar & MONU) != 0))) + { + if (m->mftsel != 0) { + if ( invial(m->mftidl,rxfhdr + L2IDLEN) == TRUE + || invial(m->mftidl,rxfhdr) == TRUE) + { + if (m->mftsel == 2) + return(FALSE); + } + else + if (m->mftsel == 1) + return(FALSE); + } + return(TRUE); + } + } + } + return(FALSE); +} + +/*----------------------------------------------------------------------*/ +/* in via list? */ +/*----------------------------------------------------------------------*/ +static BOOLEAN invial(char *vial, char *id) +{ + while (*vial != NUL) + if (cmpid(vial,id) == TRUE) + return(TRUE); + else + vial += L2IDLEN; + return(FALSE); +} + +void moncmd(MBHEAD *mbp, MONBUF *m, char *blipoi, WORD blicnt) +{ + WORD arg; + BOOLEAN host = (m == &consmon); + char *c; + char str[128]; + char call[15]; + char *s; + + if (blicnt == 0) + { + if (host) + rspini(HMRSMSG); + else + putstr(", Monitor=", mbp); + + if (m->Mpar == 0) + strcpy(str, "N"); + else { + s = str; + if ((m->Mpar & MONI) || (m->Mpar & MONU)) + { + if (m->Mpar & MONF) + *s++ = 'F'; + if (m->Mpar & MONL) + *s++ = 'L'; + } + if (m->Mpar & MONU) + *s++ = 'U'; + if (m->Mpar & MONS) + *s++ = 'S'; + if (m->Mpar & MONT) + *s++ = 'T'; + if (m->Mpar & MONI) + *s++ = 'I'; + if (m->Mpar & MONC) + *s++ = 'C'; + if ((m->Mpar & MONI) || (m->Mpar & MONU)) + if (!(m->Mpar & MONF)) + *s++ = 'H'; + + if (m->Mport < L2PNUM) /* Welcher Port selektiert? */ + s += sprintf(s, " Port%d", m->Mport); + + *s = NUL; + + if (m->mftsel) { + if (m->mftsel == 1) + strcat(s, " +"); + if (m->mftsel == 2) + strcat(s, " -"); + if (*(c = m->mftidl )) { + while (*c) { + strcat(s, " "); + call2str(call, c); + strcat(s, call); + c += L2IDLEN; + } + } + } + } + + if (host) { + putstr(str, hstmbp); + } else { + putstr(str, mbp); + putstr("\r", mbp); + } + } else { + m->Mport = 255; + m->Mpar = 0; + m->mftsel = 0; + arg = 0; + while (blicnt) + { + skipsp(&blicnt, &blipoi); + if (toupper(*blipoi) == 'N') + { + blicnt--; + blipoi++; + m->Mport = 255; /* Alle Ports freigeben */ + if (skipsp(&blicnt,&blipoi) == FALSE) + arg = 0; + else + { + if (*blipoi == '+' || *blipoi == '-') + arg = 0; + else + { + if (host) { + rsperr(HMEIPA); + return; + } + blicnt = 1; + arg = m->Mpar; + } + } + } + else + { + switch (toupper(*blipoi)) + { + case 'M': if (host) /* An der Konsole ist M falsch */ + { + rsperr(HMEIPA); + return; + } + break; /* Bei TRACE ist M erlaubt */ + case 'T': arg |= MONT; + break; + case 'L': arg |= MONL; + break; + case 'A': arg |= (MONI | MONU | MONS | MONC | MONF | MONT | MONL); + break; + case 'U': arg |= MONU; + break; + case 'S': arg |= MONS; + break; + case 'I': arg |= MONI; + break; + case 'C': arg |= MONC; + break; + case 'F': arg |= MONF; /* Full-Monitor: Infos anzeigen */ + break; + case 'H': arg &= ~MONF; /* Header-Monitor: nur Header */ + break; + case '+': --blicnt; + ++blipoi; + if (getdig(&blicnt, &blipoi, FALSE, m->mftidl) != YES) { + if (host) { + rsperr(HMEIPA); + return; + } + } else { + if (m->mftidl[0] == NUL) + m->mftsel = 0; + else + m->mftsel = 1; + } + blicnt = 1; + break; + case '-': --blicnt; + ++blipoi; + if (getdig(&blicnt, &blipoi, FALSE, m->mftidl) != YES) { + if (host) { + rsperr(HMEIPA); + return; + } + } else { + if (m->mftidl[0] == NUL) + m->mftsel = 0; + else + m->mftsel = 2; + } + blicnt = 1; + break; + default: if (isdigit(*blipoi)) + { + m->Mport = nxtnum(&blicnt, &blipoi); + while (isdigit(*blipoi)) { + blicnt--; + blipoi++; + } + continue; + } + else + { + if (host) { + rsperr(HMEIPA); + return; + } + blicnt = 1; + arg = 0; + } + } + blicnt--; + blipoi++; + } + } + if ( (arg & MONL) /* Laenge nur sinnvoll wenn I- */ + && !(arg & (MONI | MONU))) /* oder UI-Frames ausgewaehlt */ + arg &= ~MONL; + if (!host) { /* nicht fuer die Console... */ + if (m->Mpar && !arg) tracnt--; /* der Monitor wurde abgeschaltet */ + if (!m->Mpar && arg) tracnt++; /* ... oder angeschaltet */ + if (arg) + arg |= MONC; /* Parameter C nur von Bedeutung an der Konsole */ + } else + rspsuc(); +#ifdef __WIN32__ + m->Mpar = (unsigned char)arg; +#else + m->Mpar = arg; +#endif /* WIN32 */ + } +} + +/* End of src/l7moni.c */ diff --git a/src/l7showl3.c b/src/l7showl3.c new file mode 100755 index 0000000..b8c5f2d --- /dev/null +++ b/src/l7showl3.c @@ -0,0 +1,1100 @@ +/************************************************************************/ +/* */ +/* ***** ***** */ +/* ***** ***** */ +/* ***** ***** */ +/* ***** ***** */ +/* *************** *************** */ +/* ***************** ***************** */ +/* *************** *************** */ +/* ***** ***** TheNetNode */ +/* ***** ***** Portable */ +/* ***** ***** Network */ +/* ***** ***** Software */ +/* */ +/* File src/l7showl3.c (maintained by: ???) */ +/* */ +/* This file is part of "TheNetNode" - Software Package */ +/* */ +/* Copyright (C) 1998 - 2008 NORD>options == NULL) + return; + op = np->options; + rwndmb(op); + putstr("\rINP-Options:", mbp); + while (op->mbpc > op->mbgc) + { + len = getchr(op); + tag = getchr(op); + for (i = 0; i < len - 2; i++) + buf[i] = getchr(op); + buf[i] = NUL; + putprintf(mbp, "\rlen = %d, tag = 0x%02x\r", len, tag); + for (i = 0; i < len - 2; i++) + putprintf(mbp, "%02x%c", buf[i], ((i % 16) == 0) ? CR : ' '); + } + putchr(CR, mbp); +} + +/* Rufzeichen eines Node ausgeben, wahlweise Alias und SSID-Bereich */ +static void +putnod(NODE *np, int options, MBHEAD *mbp) +{ + char id[L2IDLEN]; + int i; + + cpyid(id, np->id); + if (np->options != NULL) + { + for(i = 0; i < L2CALEN; i++) + id[i] = tolower(id[i]); + } + if (!(options & OPT_SSID_RANGE)) /* Anzeige als Node */ + { + if (*np->alias != ' ') /* Alias ist vorhanden, dann */ + options |= OPT_ALIAS; /* auch anzeigen */ + } + if (options & OPT_ALIAS) + { + putide(np->alias, mbp); + putchr(':', mbp); /* ":" als Trennung zum Rufzeichen */ + } + if (options & OPT_SSID_RANGE) + { + putprintf(mbp, "%6.6s %2d-%-2d", id, SSID(np->id), np->ssid_high); + } + else + putid(id, mbp); +} + +/*----------------------------------------------------------------------*/ +/* NODES */ +/* ----------- */ +/* clipoi zeigt auf das naechste Zeichen der Komandozeile. */ +/* Wenn clicnt == 0 ist diese zu ende. */ +/* nodprm() operiert nur auf einer KOPIE von clicnt/clipoi ! */ +/*----------------------------------------------------------------------*/ +static void +show_nodes(const char *name, /* Name (Nodes,Destinations,Locals) */ + int options) /* Optionen fuer die Ausgabe */ +{ + char newcal[L2IDLEN]; /* neues Call */ + char niden[L2CALEN]; /* neuer Alias */ + char *cpoisa; /* temp fuer clipoi */ + BOOLEAN alles; /* versteckte Nodes auch zeigen */ + BOOLEAN plus_quality; /* mit Qualitaet etc. zeigen */ + TRILLIAN callok; /* Ergebnis Test auf gueltiges Call */ + TRILLIAN isnode; /* Ergebnis Test auf gueltigen Alias */ + WORD ccntsa; /* temp fuer clicnt */ + MBHEAD *mbp; /* Buffer fuer Meldung an User */ + WORD is_mask_or_qual; /* Qualitaet / Wildcards angegeben */ + char mask[MAXMASK]; + UWORD qual; + char nbrcal[L2IDLEN]; + int j; + INDEX index; + int max_peers = netp->max_peers; + unsigned route_quality; + unsigned quality = 0; + PEER *pp; + PEER *bestpp; + NODE *np; + ROUTE *rp; + int width; + int len; + BOOLEAN all_routes; + char buf[40]; + char call1[15]; + char call2[15]; + int maske = OPTIONS_MASK; + + if (!ismemr()) /* Nicht genuegend Buffer !!! */ + return; + + alles = /* default: keine versteckten Nodes */ + plus_quality = FALSE; /* default: ohne Qualitaet etc. */ + +/* Wenn Befehlszeile leer, Qualitaet nicht beruecksichtigen; bei Aufruf */ +/* mit Parametern, pruefen, ob Qualitaet / Wildcards angegeben */ + + is_mask_or_qual = clicnt ? nodprm(clipoi, clicnt, mask, &qual, nbrcal) : 0; + + if ((!is_mask_or_qual) && clicnt) /* nur 1 Node gefragt */ + { + cpoisa = clipoi; /* Befehlszeile merken */ + ccntsa = clicnt; + if (options & OPT_ALIAS) + { + isnode = getide(&clicnt, &clipoi, niden); /* Test auf gueltigen */ + /* Alias */ + clipoi = cpoisa; /* Befehlszeile zurueck */ + clicnt = ccntsa; + } + else + isnode = NO; + callok = getcal(&clicnt, &clipoi, TRUE, newcal); /* Rufzeichen? */ + + if (callok == YES || isnode != ERRORS) /* einzelner Eintrag gefragt */ + { + if ( !(options & OPT_ALIAS) + || !(isnode) + || ((index = find_alias(niden)) == NO_INDEX)) + { + +/* Bei Nodes gibt es nur eine SSID. Nur Flex kann mehrere haben. Darum */ +/* erstmal auf genaues Ziel testen. */ +/* Wenn das genaue Ziel nicht gefunden wurde, koennen wir noch nach dem */ +/* SSID-Bereich ueber Flexnet-Nachbarn suchen */ + + if (callok == YES) + { + if ((index = find_node_this_ssid(newcal)) == NO_INDEX) + { +/* Da das genaue Ziel nicht gefunden wurde, koennen wir noch nach dem */ +/* SSID-Bereich ueber Flexnet-Nachbarn suchen */ + if ((index = find_node_ssid_range(newcal)) != NO_INDEX) + { +/* Wir haben einen Flexnet-Weg gefunden - dann duerfen wir nachher auch */ +/* nur einen Flexnet-Weg anzeigen */ + maske = VC | VC_FAR; + } + } + } + else + index = NO_INDEX; + } + + if (index != NO_INDEX) + { + np = netp->nodetab + index; + find_best_qual(index, &bestpp, options & maske); + +#ifdef NONODESFIX + if (bestpp == NULL) + { + mbp = putals("No entry for: "); + + putid(newcal, mbp); + putstr("\r", mbp); + prompt(mbp); + seteom(mbp); + return; + } +#endif /* NONODESFIX */ + + mbp = getmbp(); /* Buffer holen fuer Antwort */ + putstr("Routes to ", mbp); + + if (!(maske & DG)) /* Flex-Ziel ueber SSID-Bereich */ + putid(newcal, mbp); + else + { + putnod(np, (options & ~OPT_ALIAS), mbp); +/* bei "n alias" wird kein Call uebergeben */ + cpyid(newcal,np->id); + if (np->ipa != 0L) + putprintf(mbp, " (%u.%u.%u.%u/%u)", + (unsigned)(np->ipa >> 24), + (unsigned)((np->ipa >> 16) & 0xff), + (unsigned)((np->ipa >> 8) & 0xff), + (unsigned)(np->ipa & 0xff), + (unsigned)np->bits); + } + putstr("\r---T[ms]----RxT----TxT--LT-Mode-Obc-----" + "RTT-Po-Route------------------------", mbp); + + all_routes = (strchr((char *)clipoi, '*') != NULL); + + for (pp = netp->peertab, j = 0; /* alle Wege anzeigen */ + j < max_peers; j++, pp++) + { + if (!pp->used) + continue; + if (!(pp->options & (options & OPTIONS_MASK))) + continue; + if (!(maske & DG)) + if (pp->typ != FLEXNET) + continue; + + mbp->l4time = mbp->mbpc; + + rp = pp->routes + index; + route_quality = rp->quality; + quality = getquality(route_quality, pp); + + if (!quality && !all_routes) + continue; + + if (pp->typ == FLEXNET) + putstr(rp->reported_quality ? "\r- " : "\r> ", mbp); + else + putstr(quality ? pp == bestpp ? "\r> " : "\r " : "\r- ", mbp); + + putspa(2, mbp); + putprintf(mbp, "%6lu %6lu ", + ((ULONG)quality) * 10L, + ((ULONG)route_quality) * 10L); + if (rp->reported_quality != DIRTY) + putprintf(mbp, "%6lu ", + ((ULONG)rp->reported_quality) * 10L); + else + putstr("UPDATE ", mbp); + putprintf(mbp, "%3u %4s %3u %7lu %2u", + (int)rp->lt, + pp->typ <= NETROM ? "DG" : "VC", + rp->timeout, + ((ULONG)pp->quality * 10), + pp->l2link->port); + + putspa(48, mbp); + putid(pp->l2link->call, mbp); /* Nachbarcall fuer Weg */ + putdil(pp->l2link->digil, mbp); /* Digiweg zum Nachbarn */ + } + putchr('\r', mbp); /* Antwort abschliessen */ + dump_options(np, mbp); + call2str(call1, myid); + if (quality && bestpp->typ >= LOCAL) + { + putchr('\r', mbp); + putalt(alias, mbp); + putid(myid, mbp); + putprintf(mbp, "> %s \r\r", call1); + } + prompt(mbp); + seteom(mbp); /* Antwort abschicken */ + +/* Routentest abhaengig vom Typ des besten Weges (LOCAL / LOCAL_M wurde */ +/* schon vorher behandelt) */ + if (bestpp->typ <= NETROM) + request_nrr(np->id, userpo->uid); + else + if (bestpp->typ == FLEXNET) + { + call2str(call2, newcal); /* das gesuchte Call */ + sprintf(buf, "6!%5u%s %s", userpo->uid, call1, call2); + if (clipoi[clicnt-1] == '>')/* Routentest um Laufzeitangabe */ + buf[2] = buf[2] | 0x60; /* der Einzellinks erweitert */ + flex_route_query(buf); + } + return; /* fertig */ + } + else + { + mbp = putals("No entry for: "); + strupr((char *)cpoisa); + putstr((char *)cpoisa, mbp); + putchr('\r', mbp); + prompt(mbp); + seteom(mbp); + return; + } + } + } + +/* ========================== Nodestabelle anzeigen =================== */ + + mbp = putals(name); /* Kopfzeile */ + putnum(netp->num_nodes, mbp); /* Zahl Nodeseintraege anzeigen */ + putchr('/', mbp); /* Maximalanzahl ausgeben */ + putnum(num_nodes_max, mbp); + putstr("):\r", mbp); /* Zeile abschliessen */ + + width = 0; + + if (is_mask_or_qual) /* wenn Wildcards, alle untersuchen */ + alles = plus_quality = TRUE; + + for (np = (NODE *)netp->nodelis.head; + np != (NODE *)&netp->nodelis;/* sortierte Nodes-Liste durchgehen */ + np = np->next) + { + index = (INDEX)(np - netp->nodetab); /* Index berechnen */ + if ((np->alias[0] != '#') || (alles == TRUE)) + { /* Eintrag kein #-Node oder alles anzeigen */ + quality = find_best_qual(index, &bestpp, options & OPTIONS_MASK); + if (bestpp == NULL) + continue; + rp = bestpp->routes + index; + if (is_mask_or_qual) /* nur eine Auswahl bitte ... */ + { + +/* wird nach Routes eines bestimmten Nachbarn gesucht? */ + + if ( (is_mask_or_qual & ISNBRCALL) + && (!cmpid(bestpp->l2link->call, nbrcal))) + continue; + + if (is_mask_or_qual & ISCALLMASK) /* Call mit Wildcards? */ + { + +/* wenn Call mit Wildcards nicht passt und nicht Alias mit Wildcards */ +/* gefragt wurde oder auch nicht passt, naechsten Eintrag testen */ + + if ( !c6mtch(np->id, mask) + && ( !(is_mask_or_qual & ISIDENTMASK) + || !c6mtch(np->alias, mask))) + continue; + } + +/* wenn Alias mit Wildcards gefragt, aber nicht passt, naechsten */ +/* Eintrag */ + + else if ( (is_mask_or_qual & ISIDENTMASK) + && !c6mtch(np->alias, mask)) + continue; + + if (quality > 0) + { /* aktiver Weg zum Node? */ + +/* wenn untere Qualitaetsgrenze angegeben, aber die Qualitaet fuer den */ +/* aktiven Weg zu gering ist, naechsten Eintrag testen */ + + if ( (is_mask_or_qual & ISMINQUAL) + && (quality < qual)) + continue; + +/* wenn obere Qualitaetsgrenze angegeben, aber die Qualitaet fuer den */ +/* aktiven Weg zu hoch ist, naechsten Eintrag testen */ + + if ( (is_mask_or_qual & ISMAXQUAL) + && (quality > qual)) + continue; + } + } + else if (quality == 0) + continue; + } + +#ifdef LINKSMOD_LOCALMOD + if (CheckLocalLink(np->id) == TRUE) /* Ist ein LOCAL-Link. */ + continue; /* Zum naechsten Eintrag. */ +#endif /* LINKSMOD_LOCALMOD */ + + mbp->l4time = mbp->mbpc; /* Zaehler merken fuer putspa() */ + putnod(np, options, mbp); + if (options & OPT_SSID_RANGE) + putspa(12, mbp); + else + { + if (options & OPT_ALIAS) + putspa(16, mbp); + else + putspa(9, mbp); + } + + if (plus_quality == TRUE) /* Qualitaet etc. auch anzeigen? */ + { + if (quality > 0) + { /* wenn aktiver, diesen anzeigen */ + if (quality > 6000) /* mehr als eine Minute? */ + putprintf(mbp, " %2umin", quality / 6000); + else + putprintf(mbp, " %5lu", ((ULONG)quality) * 10L); + if (bestpp) + { + putchr('/', mbp); + putprintf(mbp, "%2d ", bestpp->l2link->port); + } + else + putstr(" ", mbp); + } + else /* kein aktiver Weg */ + putstr(" -/ - ", mbp); + } + + len = (mbp->mbpc - mbp->l4time); /* Laenge eines Eintrages */ + width += len; + if (width + len < 79) + { /* einer passt noch in die Zeile */ + len = (79 % len) / (79 / len); + while (len--) + putchr(' ', mbp); + } + else + { + putchr('\r', mbp); + width = 0; + } + } + putchr('\r', mbp); /* Antwort abschliessen */ + prompt(mbp); + seteom(mbp); /* und abschicken */ +} + +/*----------------------------------------------------------------------*/ +/* nodprm() - Parameter des erweiterten NODE Befehls auswerten */ +/* testet ob p ein Wort mit Wildcard enthaelt, kopiert dieses nach mp */ +/* Case-Conversion! Nod*E wird NOD*E */ +/* n MUSS > 0 sein */ +/*----------------------------------------------------------------------*/ +static WORD +nodprm(char *p, /* parameter des node befehls */ + WORD n, /* restlaenge der parameterzeile */ + char *mp, /* nimmt die maske auf */ + UWORD *qp, /* nimmt die quality auf */ + char *nc) /* nimmt das nachbarcall auf */ +{ + WORD i; + WORD ret = ISMINQUAL; + WORD matchok; + WORD c; + + if (*p == '-') + { + n--; + p++; + ret = ISMAXQUAL; + } + if ((*qp = (UWORD)(nxtlong(&n, &p) / 10L)) == 0) + { + ret = 0; + } + + if (*p == '<') + { + n--; + p++; + if (getcal(&n, &p, TRUE, nc) == YES) + ret |= ISNBRCALL; + } + + if (skipsp(&n, &p)) + { + matchok = FALSE; + for (i = 0; i < (MAXMASK - 1);) + { + if (!n || ((c = *p++) == ' ')) + break; + n--; + if (c == ':') + { + if (i == 0) + { + ret |= ISCALLMASK; + continue; + } + else + { + ret &= ~ISCALLMASK; + ret |= ISIDENTMASK; + break; + } + } + if ((c == MATCHMANY) || (c == MATCHONE)) + { + matchok = TRUE; + } + mp[i++] = isascii(c) ? toupper(c) : MATCHONE; + } + mp[i] = MATCHEND; + if (matchok) + { + if (!(ret & (ISCALLMASK | ISIDENTMASK))) + { + ret |= (ISCALLMASK | ISIDENTMASK); + } + } + else + { + ret &= ~(ISCALLMASK | ISIDENTMASK); + } + } + return (ret); +} + +/*----------------------------------------------------------------------*/ +void +ccpnod(void) /* Nodes ausgeben */ +{ +#ifndef SHOW_DESTNODES + show_nodes("Nodes (", OPT_ALIAS | OPT_DGTEST | VC | VC_FAR | DG); +#else + show_nodes("Nodes (", OPT_ALIAS | OPT_DGTEST | VC | DG); +#endif /* SHOW_DESTNODES */ +} + +/*----------------------------------------------------------------------*/ +void +ccpdest(void) /* Destinations ausgeben */ +{ +#ifndef SHOW_DESTNODES + show_nodes("Destinations (", OPT_SSID_RANGE | OPT_VCTEST | VC | VC_FAR | DG); +#else + show_nodes("Destinations (", OPT_SSID_RANGE | OPT_VCTEST | VC | VC_FAR); +#endif /* SHOW_DESTNODES */ +} + +/* Die Antwort wird hier etwas leserlicher gemacht und an den User */ +/* geschickt */ +static const char *reason[] = +{"no route", "local", "flexgate", "", "loop"}; + +void +nrr2usr(NRRLIST *l, char time_to_live) +{ + char buffer[512], + *bp, + call[10]; + int llt, + lt, + err; + UID uid; + USRBLK *up; + + bp = buffer; + llt = l->lt & LT_MASK; + + while (*l->id) + { /* Liste abarbeiten */ + *bp++ = ' '; + lt = l->lt & LT_MASK; + while (llt > lt) + { /* fehlende Digis markieren */ + *bp++ = '?'; + *bp++ = ' '; + llt--; + } + call2str(call, l->id); + bp += sprintf(bp, "%s", call); + if (l->lt & ECHO_FLAG) + { /* Echoflag anzeigen */ + *bp++ = '*'; + err = l->id[L2CALEN] >> 5; /* Fehlercode extrahieren */ + if (err < 5 && err != 3) /* und anzeigen */ + bp += sprintf(bp, "<%s>", reason[err]); + } + llt--; + l++; + } + *bp++ = ' '; + time_to_live++; + while (llt > time_to_live) + { + *bp++ = '?'; + *bp++ = ' '; + llt--; + } + call2str(call, myid); + bp += sprintf(bp, "%s", call); + + uid = (l4hdr2 << 8) | l4hdr3; /* User suchen */ + if (uid > 0 && uid < NUMPAT) + if ((up = ptctab[uid].ublk) != NULL) +#ifndef SEND_ASYNC_RESFIX + send_async_response(up, "Route (DG):", buffer); +#else + { + /* Sicher ist sicher. */ + buffer[256] = 0; + send_async_response(up, "Route (DG):", buffer); + } +#endif /* SEND_ASYNC_RESFIX. */ + +} + +/* + * Qualitaet links oder rechtsbuendig ausgeben + */ +static void putquality(MBHEAD *mbp, ULONG qual, int align) +{ +#define QA_LEFT 0 +#define QA_RIGHT 1 + if (align == QA_LEFT) { +#ifndef ROUTESMOD_L3RTTSHOW + if (qual) putprintf(mbp, "%-6ld ", qual*10L); +#else + if (qual) putprintf(mbp, "%-6ld ", qual/10L); +#endif /* ROUTESMOD_L3RTTSHOW */ + else putstr("---- ", mbp); + } else { +#ifndef ROUTESMOD_L3RTTSHOW + if (qual) putprintf(mbp, " %6ld", qual*10L); +#else + if (qual) putprintf(mbp, " %6ld", qual/10L); +#endif /* ROUTESMOD_L3RTTSHOW */ + else putstr(" ----", mbp); + } +} + +/**************************************************************************/ +/* Anzeigen des Routing und der Links */ +/*------------------------------------------------------------------------*/ +static void putrou(PEER *pp, MBHEAD *mbp, BOOLEAN printver) +{ + const char *c_state[] = {" ", "setup ", "conn. ", "active"}; + int state; +#define S_UNUSED 0 +#define S_SETUP 1 +#define S_CONN 2 +#define S_ACTIVE 3 + int typ = pp->typ; + char *c; + const char *cp; + NODE *np; + PEER *bestpp; + INDEX index; + unsigned int numroutes = 0; + unsigned int qual; + +#ifdef LINKSMOD_LOCALMOD + if ( (pp->typ == LOCAL_V) /* Segment ist eine versteckte LOCAL-Route. */ + &&(!issyso())) /* Kein Sysop. */ + return; /* Eintrag geheim halten. */ +#endif /* LINKSMOD_LOCALMOD */ + + mbp->l4time = mbp->mbpc; + putid(pp->l2link->call, mbp); /* Node Call ausgeben */ + if (pp->primary != pp) + putchr('*', mbp); + putspa(10, mbp); /* Qua-Po-Dst Werte ausgeben */ + + for (np = (NODE *)netp->nodelis.head; + np != (NODE *)&netp->nodelis;/* sortierte Nodes-Liste durchgehen */ + np = np->next) + { + if (np->id[0]) /* nur benutzte Eintraege interessieren */ + { + index = (INDEX)(np - netp->nodetab); /* Index berechnen */ + qual = find_best_qual(index, &bestpp, OPTIONS_MASK); /* suche besten Weg */ + + if ((bestpp == NULL) || (qual == 0)) /* geloeschte Nodes abfangen */ + continue; + + if (cmpid(bestpp->l2link->call, pp->l2link->call)) /* Callvergleich */ + ++numroutes; + } + } + + /* TEST DG9OBU */ + /* SSID bzw. SSID-Bereich ausgeben */ + if (pp->typ == FLEXNET) + { + putprintf(mbp, "%2d-%-2d", SSID(pp->l2link->call), pp->l2link->ssid_high); + } + else + { + putspa(11, mbp); + putprintf(mbp, "%2d", SSID(pp->l2link->call)); + } + + putspa(17, mbp); + + putprintf(mbp, "%2.2s %2d %4d/%-4d", typtbl + pp->typ*2, + pp->l2link->port, + pp->num_routes, + numroutes); + + if (pp->nbrl2l != NULL) { + if (pp->nbrl2l->state < L2SIXFER) + state = S_SETUP; /* setup */ + else + state = S_CONN; /* connected */ + } else { + if (pp->typ == LOCAL_M) { + if (pp->quality > 0) + state = S_ACTIVE; /* active */ + else + state = S_UNUSED; /* unused */ + } else + state = S_UNUSED; /* nicht connected */ + } + +#ifndef LINKSMOD_LOCALMOD + if (typ != LOCAL) +#else + if (typ < LOCAL) +#endif /* LINKSMOD_LOCALMOD */ + { + if (typ == THENET && pp->quality != 0) + putprintf(mbp," Qual:%d",pp->quality); + else { + putquality(mbp, pp->my_quality, QA_RIGHT); + putchr('/', mbp); + if (pp->my_quality) + putquality(mbp, pp->his_quality, QA_LEFT); + else + putquality(mbp, 0, QA_LEFT); + } + } + putspa(40, mbp); + + if (typ == INP || typ == FLEXNET) + putprintf(mbp, "%8lu ", (ULONG)pp->maxtime * 10L); + else + putstr(" ", mbp); + + putspa(52,mbp); + putstr(c_state[state], mbp); + + putchr(' ', mbp); + + if (typ == LOCAL) + putstr(" ", mbp); + + if (!printver) { + if (*(c = pp->l2link->digil)) + { + while (*c) + { + putid(c, mbp); + putchr(' ', mbp); + c += L2IDLEN; + } + } + } + else + { + switch (pp->typ) + { + case NETROM : + cp = "NET/ROM (UI)"; + break; + case THENET : + cp = "THENET (UI)"; + break; + case TNN : + putprintf(mbp, "TNN V%d.%d (I) ", (pp->version/100), + (pp->version%100)); + cp = ""; + break; + case INP : + cp = "INP Node"; + break; + case FLEXNET : + switch (pp->version & 0x07) + { + case 0 : cp = "FlexNet"; break; + case 1 : cp = "BayCom"; break; + case 2 : cp = "Digiware"; break; + case 3 : cp = "TheNetNode"; break; + case 4 : cp = "SNet"; break; + case 5 : cp = "(X)Net"; break; + default: cp = "unknown"; return; + } + putspa(58,mbp); + putstr(cp, mbp); + if (pp->version) + putprintf (mbp, " V%d.%d", ((pp->version>>8) / 10), + ((pp->version>>8) % 10)); + default : + cp = ""; + break; + } + putspa(65,mbp); + putstr(cp, mbp); + } + +#ifdef CONNECTTIME + if (!printver) /* Nur wenn keine erweiterte Ausgabe */ + { /* Connectzeit ausgeben. */ + putspa(72, mbp); + putprintf(mbp, "%s", ConnectTime(pp->contime)); + } +#endif /* CONNECTTIME */ + + putchr('\r', mbp); +} + +#ifdef ROUTESMODVIANODES +/**************************************************************************/ +/* */ +/* Segment suchen und bereitstellen. */ +/* */ +/**************************************************************************/ +static PEER *isSegment(const char *call) +{ + PEER *pp; + int max_peers = netp->max_peers; + int i; + + if (call[0] == FALSE) + return(NULL); + + /* durchsuche alle Segmente. */ + for (i = 0, pp = netp->peertab; i < max_peers; i++, pp++) + { + /* Nur benutzte Eintraege. */ + if ( (pp->used) + /* Callvergleich (SSID beachten). */ + &&(cmpid(call, pp->l2link->call))) + /* Segment gefunden. */ + return(pp); + } + + /* Kein Eintrag gefunden. */ + return(NULL); +} + +/**************************************************************************/ +/* */ +/* Ausgabe vorbereiten. */ +/* */ +/**************************************************************************/ +static MBHEAD *RoutesMBP(void) +{ + MBHEAD *mbp; + + mbp = getmbp(); /* frischen Puffer besorgen */ + putstr("Routes of ", mbp); /* Konfiguration zeigen */ + putalt(alias, mbp); + putid(myid, mbp); + + putprintf(mbp, " (%d/%d)\r", netp->num_peers, netp->max_peers); +#ifndef CONNECTTIME + putstr("Node------SSID--Typ-Po--Dst/Rou---L3SRTT[ms]---MaxT[ms]-State--Route-\r", mbp); +#else + putstr("Node------SSID--Typ-Po--Dst/Rou---L3SRTT[ms]---MaxT[ms]-State--Route----Contime\r", mbp); +#endif /* CONNECTTIME */ + return(mbp); +} + +/**************************************************************************/ +/* */ +/* ROUTES COMMAND mit Erweiterung. */ +/* Ein Routes-Eintrag ausgeben und dazu alle Noden */ +/* die ueber diesen Routes-Eintrag geroutet werden. */ +/* */ +/* THENETMOD */ +/* Qualitaet einer Route (nur THENET-Typ) setzen/aendern. */ +/**************************************************************************/ +void putnodes(PEER *pp, MBHEAD *mbp) +{ + PEER *bestpp; + NODE *np; + INDEX index; + char call[10]; + int len; + int width = 0; + unsigned int numroutes = 0; + unsigned int qual; + + call2str(call, pp->l2link->call); +#ifdef SPEECH + putprintf(mbp,speech_message(273), call); +#else + putprintf(mbp, "\rAll Nodes over %s to be geroutet to show:\r", call); +#endif + + for (np = (NODE *)netp->nodelis.head; + np != (NODE *)&netp->nodelis;/* sortierte Nodes-Liste durchgehen */ + np = np->next) + { + if (np->id[0]) /* nur benutzte Eintraege interessieren */ + { + index = (INDEX)(np - netp->nodetab); /* Index berechnen */ + qual = find_best_qual(index, &bestpp, OPTIONS_MASK); /* suche besten Weg */ + + if ((bestpp == NULL) || (qual == 0)) /* geloeschte Nodes abfangen */ + continue; + + if (cmpid(bestpp->l2link->call, pp->l2link->call)) /* Callvergleich */ + { + ++numroutes; + + /* Rufzeichen ausgeben. */ + putid(np->id,mbp); + /* Konvertiere Rufzeichen. */ + call2str(call, np->id); + /* Laenge eines Eintrages. */ + len = strlen(call) + 16; + width += len; + + if (width + len < 169) + { + /* einer passt noch in die Zeile */ + len = (79 % len) / (79 / len); + + while (len--) + putchr(' ', mbp); + } + else + { + putchr('\r', mbp); + width = 0; + } + } + } + } + + putchr('\r', mbp); +} + +/**************************************************************************/ +/* */ +/* ROUTES COMMAND mit Erweiterung. */ +/* Ein Routes-Eintrag ausgeben und dazu alle Noden */ +/* die ueber diesen Routes-Eintrag geroutet werden. */ +/* */ +/* THENETMOD */ +/* Qualitaet einer Route (nur THENET-Typ) setzen/aendern. */ +/**************************************************************************/ +static void RoutesViaNodes(void) +{ + MBHEAD *mbp = NULL; + char call[L2IDLEN]; + + skipsp(&clicnt,&clipoi); /* evl. Leerzeichen entfernen. */ + + /* Pruefe Rufzeichen. */ + if ((getcal(&clicnt, &clipoi, TRUE, call)) == YES) + { + PEER *pp; + + /* Aktueller Linkblock ist ein Segment. */ + if ((pp = isSegment(call)) != NULL) + { +#ifdef THENETMOD + if (pp->typ == THENET) /* L4QUALI, Aenderungen nur am Typ THENET. */ + { + if (RoutesL4Para(mbp, pp)) + return; + } +#endif /* THENETMOD */ + + mbp = RoutesMBP(); + + putrou(pp, mbp, FALSE); + putnodes(pp, mbp); + prompt(mbp); + seteom(mbp); + } + else + /* Es gibt kein Segment mit den angegeben Rufzeichen. */ + { + mbp = RoutesMBP(); +#ifdef SPEECH + putstr(speech_message(276),mbp); +#else + putstr("Call does not stand in the links List!\r",mbp); +#endif + prompt(mbp); + seteom(mbp); + return; + } + } + else + /* Ungueltiges Rufzeichen . */ + { + mbp = RoutesMBP(); +#ifdef SPEECH + putstr(speech_message(196),mbp); +#else + putstr("Invalid Call!\r",mbp); +#endif + prompt(mbp); + seteom(mbp); + return; + } +} +#endif /* ROUTESMODVIANODES */ + +/*------------------------------------------------------------------------*/ +/* ROUTES COMMAND Ausgabe einer formatierten Routes-Liste an User. */ +/* Eingabe von Routes durch SYSOP. */ +/*------------------------------------------------------------------------*/ +void ccprou(void) +{ + MBHEAD *mbp; + BOOLEAN printver = FALSE; + PEER *i_pp, *j_pp; + int i, j; + int flag[MAX_PEERS]; + const int max_peers = netp->max_peers; + + memset(flag, 0, sizeof(flag)); + + if (clicnt != 0) + { + if ( *clipoi == '*' + || *clipoi == '+') + printver = TRUE; /* Version mit ausgeben */ +#ifdef ROUTESMODVIANODES + else + { + RoutesViaNodes(); + return; + } +#endif /* ROUTESMODVIANODES */ + } + + mbp = getmbp(); /* frischen Puffer besorgen */ + putstr("Routes of ", mbp); /* Konfiguration zeigen */ + putalt(alias, mbp); + putid(myid, mbp); + + putprintf(mbp, " (%d/%d)\r", netp->num_peers, netp->max_peers); + putstr("Node------SSID--Typ-Po--Dst/Rou---L3SRTT[ms]---MaxT[ms]-State--", mbp); +#ifdef CONNECTTIME + putstr(printver ? "Software/Version\r" + : "Route----Contime\r", mbp); +#else + putstr(printver ? "Software/Version\r" + : "Route-----------\r", mbp); +#endif /* CONNECTTIME */ + + for (i = 0, i_pp = netp->peertab; i < max_peers; ++i, ++i_pp) + if (i_pp->used) + if (i_pp->primary == i_pp) + { + putrou(i_pp, mbp, printver); + + for (j = 0, j_pp = netp->peertab; j < max_peers; ++j, ++j_pp) + if (j_pp->used) + if (j_pp->primary == i_pp && j_pp != i_pp) + putrou(j_pp, mbp, printver); + } + + prompt(mbp); + seteom(mbp); +} + +/* End of src/l7showl3.c */ diff --git a/src/l7time.c b/src/l7time.c new file mode 100755 index 0000000..7e661a9 --- /dev/null +++ b/src/l7time.c @@ -0,0 +1,575 @@ +/************************************************************************/ +/* */ +/* ***** ***** */ +/* ***** ***** */ +/* ***** ***** */ +/* ***** ***** */ +/* *************** *************** */ +/* ***************** ***************** */ +/* *************** *************** */ +/* ***** ***** TheNetNode */ +/* ***** ***** Portable */ +/* ***** ***** Network */ +/* ***** ***** Software */ +/* */ +/* File src/l7time.c (maintained by: ???) */ +/* */ +/* This file is part of "TheNetNode" - Software Package */ +/* */ +/* Copyright (C) 1998 - 2008 NORD>max_peers; +#endif /* CONNECTTIME */ + + /************************************************************************/ +/* */ +/* Die Verbindungen bei Antwort auf CQ-Ruf herstellen. */ +/* In der Liste cq_statl sind die herzustellenden Verbindungen festge- */ +/* legt. In jedem Buffer dieser Liste steht die UID des CQ-Rufers in */ +/* uid sowie die UID dessen, der antwortet in p_uid. */ +/* */ +/************************************************************************/ + + while ((LHEAD *)cq_statl.head != &cq_statl) + { + cqp = (CQBUF *)ulink((LEHEAD *)cq_statl.head); + uid = cqp->uid; + p_uid = cqp->p_uid; + l2tol7(L7MCONNT, g_ulink(uid), g_utyp(uid)); + l2tol7(L7MCONNT, g_ulink(p_uid), g_utyp(p_uid)); + (ptctab + p_uid)->state = UPLINK; + (ptctab + uid)->state = DOWNLINK; + dealoc((MBHEAD *)cqp); + } + + zeit = (UWORD) (tic10-lastic); + + if (zeit != 0) + { + lastic = tic10; +#ifndef MC68K + l1timr(zeit); +#endif + + hostsv(); + +#ifdef __LINUX__ + if ((tic10 % 10) == 0) /* Alle 100ms arbeiten */ + shellsrv(); +#endif + + if ((UWORD)(tic1s += zeit) >= 100) /* Alle Sekunde arbeiten */ + { + tic1s -= 100; + time(&sys_time); + sys_localtime = localtime(&sys_time); + + for (i = 0, ptcp = ptctab; i < NUMPAT; i++, ptcp++) + if (ptcp->state) + ptcp->contime++; + +#ifdef CONNECTTIME + /* Alle Segmente durchgehen. */ + for (i = 0, pp = netp->peertab; i < max_peers; i++, pp++) + { + if (!pp->used) /* Unbenutzer Eintrag, */ + continue; /* zum naechsten Segment. */ + + if (pp->nbrl2l == NULL) /* Link ist deaktiv. */ + { + pp->contime = 0; /* Connectzeit zuruecksetzen. */ + continue; + } + + if (pp->nbrl2l->state < L2SIXFER)/* Link ist aktiv,aber im Auf/Abbau*/ + { + pp->contime = 0; /* Connectzeit zuruecksetzen. */ + continue; + } + + if (pp->nbrl2l->state >= L2SIXFER) /* Link ist aktiv. */ + { + if (pp->quality) /* Nur wenn gueltige Qualitaet, */ + pp->contime++; /* connectzeit um eins erhoehen. */ + else + pp->contime = 0; /* Connectzeit zuruecksetzen. */ + } + } +#endif /* CONNECTTIME */ + + if (++sec_cnt % 10 == 0) /* alle 10 Sekunden */ + { +#ifdef __LINUX__ + calculate_load (); +#endif + for (i = 0, statp = portstat; i < L2PNUM; i++, statp++) { + + if (statp->rx_baud) + statp->rx_baud = ((statp->rx_baud+1)*7L-1+ + (statp->rx_bytes-statp->last_rx)/10L ) / 8L; + else + statp->rx_baud = (statp->rx_bytes-statp->last_rx)/10L / 4L; + + if (statp->tx_baud) + statp->tx_baud = ((statp->tx_baud+1)*7L-1+ + (statp->tx_bytes-statp->last_tx)/10L ) / 8L; + else + statp->tx_baud = (statp->tx_bytes-statp->last_tx)/10L / 4L; + + statp->last_rx = statp->rx_bytes; + statp->last_tx = statp->tx_bytes; + } + + if (thbps) /* Durchsatz/Baudrate berechnen */ + thbps = ((thbps+1)*7L-1+throughput/10L)/8L; + else + thbps = throughput/10L / 4L; + if (thbps > thbps_max) /* Maximalwert merken */ + thbps_max = thbps; + throughput = 0L; /* Durschsatzzaehler leeren */ + + for (i = 0, ptcp = ptctab; i < NUMPAT; i++, ptcp++) + if (ptcp->state) { + if (ptcp->rxbps) /* Durchsatz/Baudrate berechnen */ + ptcp->rxbps = ((ptcp->rxbps+1)*7L-1+ + (ptcp->inforx-ptcp->lastrx)/10L ) / 8L; + else + ptcp->rxbps = (ptcp->inforx-ptcp->lastrx)/10L / 4L; + + if (ptcp->txbps) + ptcp->txbps = ((ptcp->txbps+1)*7L-1+ + (ptcp->infotx-ptcp->lasttx)/10L ) / 8L; + else + ptcp->txbps = (ptcp->infotx-ptcp->lasttx)/10L / 4L; + + ptcp->lastrx = ptcp->inforx; + ptcp->lasttx = ptcp->infotx; + } + } + + if (sec_cnt == 60) /* Alle Minute */ + { + sec_cnt = 0; + + rounds_pro_sec = (rounds_count / 60L); + if (rounds_max_sec && rounds_min_sec) { + rounds_max_sec = rounds_pro_sec > rounds_max_sec + ? rounds_pro_sec : rounds_max_sec; + rounds_min_sec = rounds_pro_sec > rounds_min_sec + ? rounds_min_sec : rounds_pro_sec; + } else + rounds_min_sec = rounds_max_sec = rounds_pro_sec; + rounds_count = 0; +#ifdef GRAPH + /* Eine Minute warten nach Programmstart*/ + if (graph.enabled == FALSE) + graph.enabled = TRUE; +#endif +#ifdef MC68K + l1timr(zeit); +#endif + beacsv(); /* Baken bearbeiten */ +#ifdef __GO32__ + toggle_lpt(); +#endif + } +#ifdef GRAPH + graph_timer(); +#endif + if (Time10 <= 0L) /* 10 min abgelaufen */ + { + Time10 = 600L; /* neu setzen */ + /* 600 Sekunden = 10 min */ + if (save_timer != 0) + { + if (s_time <= 0) + { + save_stat(); /* Einstellungen sichern*/ +#ifdef GRAPH + save_graph(); +#endif + if (!startup_running) + save_mh(); + personalmanager(SAVE, NULL, NULL); /* Convers pers. Daten */ + s_time = save_timer & 0x7FFF; + } + s_time--; + } +#ifdef MC68302 + compact(); /* RAM aufraeumen */ +#endif + } + Time10--; /* 10 min Zaehler decrementieren*/ +#ifdef BEACON_STATUS + /* Ist statusbake abgelaufen */ + if (Time500 <= 0L) + { + /* Timer statusbake neusetzen. */ + Time500 = statustim; + /* Bake aussenden. */ + bake(); + } + Time500--; +#endif + + hostim(); + + chknoa(); + l3rtt_service(); + brosrv(); + trasrv(); + conversd(); +#ifdef IPROUTE + arpsrv(); +#endif +#ifndef __LINUX__ + shellsrv(); +#endif + /* Timeout fuer gelernte AX25IP-Routen durchfuehren */ +#if defined(__LINUX__) || defined(__WIN32__) + route_age(); +#endif +#ifdef L1TCPIP + /* TCPIP Timer, */ + /* Noactivity-Timer fuer alle TCPIP Connect */ + /* reduzieren und ggf. Link disconnecten. */ + TimerTCP(); +#endif /* L1TCPIP */ + } + } +} /* timsrv() */ + + +/*------------------------------------------------------------------------*/ +/* beacsv() Baken-Server zur Identifikation des Knotens und */ +/* per BEACON-Befehl zuschaltbarer Telemetrie. */ +/*------------------------------------------------------------------------*/ +void beacsv(void) +{ + MBHEAD *mbp; + BEACON *beapoi; + time_t upt; + LONG upd, uph; + WORD i, k; + ULONG summe; + struct tm *p; + + p = localtime(&sys_time); + + for (i = 0, beapoi = beacon; i < L2PNUM; ++beapoi, ++i) + { + beapoi->beatim++; + if (nmbfre > 300 && beapoi->interval != 0) + { + if (beapoi->beatim >= beapoi->interval) + { + beapoi->beatim = 0; +#ifndef BAKEFIX + (mbp = (MBHEAD *) allocb(ALLOC_MBHEAD))->l2fflg = L2CPID; + putstr(signon, mbp); + if (alias[0] != ' ') + putalt(alias,mbp); + putcal(myid, mbp); + putstr(")\r", mbp); + if (beapoi->text[0] != '\0') + { + putstr(beapoi->text, mbp); + putchr('\r', mbp); + } + rwndmb(mbp); +#ifdef __WIN32__ + sdui(beapoi->beadil, beapoi->beades, myid, (char)i, mbp); +#else + sdui(beapoi->beadil, beapoi->beades, myid, i, mbp); +#endif /* WIN32 */ + dealmb(mbp); +#else + if (beapoi->text[0] != '\0')/* Bake nur senden wenn Text gesetzt ist. */ + { /* Buffer besorgen. */ + (mbp = (MBHEAD *) allocb(ALLOC_MBHEAD))->l2fflg = L2CPID; + putstr(beapoi->text, mbp); + putchr('\r', mbp); + rwndmb(mbp); + sdui(beapoi->beadil, beapoi->beades, myid, (char)i, mbp); + dealmb(mbp); + } +#endif /* BAKEFIX */ +#ifdef BEACON_STATUS + if (beapoi->telemetrie == 2) +#else + if (beapoi->telemetrie) +#endif + { + (mbp = (MBHEAD *) allocb(ALLOC_MBHEAD))->l2fflg = L2CPID; + upt = sys_time - start_time; /* Uptime in seconds */ + /* Summe */ + summe = 0L; /* Gesamtdurchsatz */ + for (k = 0; k < L2PNUM; k++) /* Alle Ports des Knotens*/ + if (portenabled(k)) + summe += (portstat[k].rx_bytes+portstat[k].tx_bytes); + if (beapoi->telemetrie == 3) { + putprintf(mbp,"%02d.%02d.%02d %02d:%02d:%02d %7lu %8lu %4u %5lu", + p->tm_mday, p->tm_mon+1, p->tm_year % 100, + p->tm_hour, p->tm_min, p->tm_sec, + upt, + (ULONG) coreleft(), + nmbfre, + rounds_pro_sec); + putprintf(mbp, " %3d %3d %10lu %7lu\r", + nmblks, /* Number of L2-Links */ + nmbcir, /* Numer of aktive Cir */ + summe, + thbps*8L); +#ifdef BEACON_STATUS + } + if (beapoi->telemetrie == 1) + { +#else + } else { +#endif + putprintf(mbp,"%02d%02d%02d %02d%02d%02d", + p->tm_year % 100, p->tm_mon+1, p->tm_mday, + p->tm_hour, p->tm_min, p->tm_sec); + upd = upt/SECONDS_PER_DAY; /* Uptime days */ + upt %= SECONDS_PER_DAY; + uph = upt/SECONDS_PER_HOUR; /* Uptime hours */ + upt %= SECONDS_PER_HOUR; + upt /= SECONDS_PER_MIN; /* Uptime minutes */ + putprintf(mbp," Up=%3ld%02ld%02lu Mem=%6lu Buf=%4d Rps=%5lu", + upd, uph, upt, /* Uptime */ + (ULONG) coreleft(), /* Free Mem */ + nmbfre, /* Free Buffer */ + rounds_pro_sec); /* Runden */ + putprintf(mbp, "\rLnk=%3d Cir=%3d Sum=%10lu Thr=%6lu\r", + nmblks, /* Number of L2-Links */ + nmbcir, /* Numer of aktive Cir */ + summe, + thbps*8L); + } + rwndmb(mbp); +#ifdef __WIN32__ + sdui(beapoi->beadil, "STAT \140", myid, (char)i, mbp); +#else + sdui(beapoi->beadil, "STAT \140", myid, i, mbp); +#endif /* WIN32 */ + dealmb(mbp); + } + } + } + } +} + +#ifdef BEACON_STATUS +static void statusqual(MBHEAD *mbp, ULONG qual) +{ + if (qual) + putprintf(mbp,":%-4ld ", qual/10); + else + putstr(":-- ",mbp); +} + +static void noden(MBHEAD *mbp) +{ + PEER *pp; + int i; + int max_peers = netp->max_peers; + int len,width = 0; + + for (i = 0, pp = netp->peertab; i < max_peers; i++, pp++) + { + if (pp->used) + { + mbp->l4time = mbp->mbpc; + + if (pp->typ >= LOCAL) + continue; + + putide(pp->l2link->call,mbp); + statusqual(mbp,pp->quality); + + len = (mbp->mbpc - mbp->l4time); /* Laenge eines Eintrages */ + width += len; + if (width + len < 79) + { /* einer passt noch in die Zeile */ + len = (79 % len) / (79 / len); + while (len--) + putchr(' ', mbp); + } + else + { + putchr('\r', mbp); + width = 0; + } + } + } +} + + +void bake(void) +{ + MBHEAD *mbp; + MBHEAD *tmpmbp; + BEACON *beapoi; + BOOLEAN frame1 = TRUE; + char cuser[4]; + int i; + int anz_frag,info,pacl = 0; + + for (i = 0, beapoi = beacon; i < L2PNUM; ++beapoi, ++i) + { + if (beapoi->telemetrie == 3) + { + char runtime[8 + 1]; +#ifndef CONNECTTIME_ + unsigned long zeit, + sec, + min, + std; + + zeit = sys_time - start_time; /* Uptime in seconds */ + sec = zeit % 60L; zeit /= 60L; + min = zeit % 60L; zeit /= 60L; + std = zeit % 24L; zeit /= 24L; + + if (zeit > 0) + sprintf(runtime, "%2lud,%2luh",zeit, std); /* Tage, Stunden. */ + else + if (std > 0) + sprintf(runtime, "%2luh,%2lum",std, min); /* Stunden, Minuten. */ + else + if (min > 0) + sprintf(runtime, "%2lum,%2lus", min, sec); /* Minuten, Sekunden. */ + else + { + if (sec > 0) + sprintf(runtime, " %2lus", sec); /* Ausgabe in Sekunden. */ + else + sprintf(runtime, " "); + } +#else + sprintf(runtime, "%s", ConnectTime(tic10 / 100)); +#endif /* CONNECTTIME */ + + (mbp = (MBHEAD *)allocb(ALLOC_MBHEAD))->l2fflg = L2CPID; + convers_user(cuser); + + putprintf(mbp, "Links: %2d, Convers: %2s, Dest/Nodes: %3d, Buffers: %5lu, Runtime: %7s\r" + , nmblks + , cuser + , netp->num_nodes + , nmbfre + , runtime); + + noden(mbp); + rwndmb(mbp); + + info = ((mbp->mbpc) - (mbp->mbgc)); + if (info < 257) + { +#ifdef __WIN32__ + sdui("", "STATUS\140", myid, (char)i, mbp); +#else + sdui("", "STATUS\140", myid, i, mbp); +#endif /* WIN32 */ + dealmb(mbp); + } + else + { + anz_frag = info / 217; + if (anz_frag > 127) + { + dealmb(mbp); + return; + } + do + { + (tmpmbp = (MBHEAD *)allocb(ALLOC_MBHEAD))->l2fflg = L2CPID; + if (frame1 == TRUE) + { + pacl = 229; + frame1 = FALSE; + } + else + pacl = 234; + + while (tmpmbp->mbpc < pacl) + { + if (!(mbp->mbpc - mbp->mbgc)) + break; + + putchr(getchr(mbp), tmpmbp); + } + + rwndmb(tmpmbp); +#ifdef __WIN32__ + sdui("", "STATUS\140", myid, (char)i, tmpmbp); +#else + sdui("", "STATUS\140", myid, i, tmpmbp); +#endif /* WIN32 */ + dealmb(tmpmbp); + } + + while (anz_frag-- > 0); + dealmb(mbp); + } + } + } +} +#endif +/* End of src/l7time.c */ diff --git a/src/l7utils.c b/src/l7utils.c new file mode 100755 index 0000000..f574295 --- /dev/null +++ b/src/l7utils.c @@ -0,0 +1,2814 @@ +/************************************************************************/ +/* */ +/* ***** ***** */ +/* ***** ***** */ +/* ***** ***** */ +/* ***** ***** */ +/* *************** *************** */ +/* ***************** ***************** */ +/* *************** *************** */ +/* ***** ***** TheNetNode */ +/* ***** ***** Portable */ +/* ***** ***** Network */ +/* ***** ***** Software */ +/* */ +/* File src/l7utils.c (maintained by: ???) */ +/* */ +/* This file is part of "TheNetNode" - Software Package */ +/* */ +/* Copyright (C) 1998 - 2008 NORD>downca); + if (index != -1) + { + np = netp->nodetab+index; + putalt(np->alias, mbp); + } + } + putid(calofs(uplink, uid), mbp); + } else { + putalt(alias, mbp); + putid(myid, mbp); + } + putchr('\r', mbp); + if (msg != conmsg) + prompt(mbp); + seteom(mbp); +} + +/**************************************************************************/ +/* */ +/*------------------------------------------------------------------------*/ +void puttfu(const char *name) +{ + MBHEAD *mbp; + +#ifdef SPEECH + putstr(speech_message(279), (mbp = putals(name))); +#else + putstr(" table full\r", (mbp = putals(name))); +#endif + prompt(mbp); + seteom(mbp); +} + +/**************************************************************************/ +/* */ +/*------------------------------------------------------------------------*/ +void putmsg(const char *string) +{ + MBHEAD *mbp; + + mbp = putals(string); + if (userpo->convflag == 0) + prompt(mbp); + seteom(mbp); +} + +/**************************************************************************/ +/* */ +/*------------------------------------------------------------------------*/ +MBHEAD *putals(const char *string) +{ + MBHEAD *mbp; + + mbp = getmbp(); + putalt(alias, mbp); + putid(myid, mbp); + putstr("> ", mbp); + putstr(string, mbp); + return(mbp); +} + +/**************************************************************************/ +/* */ +/*------------------------------------------------------------------------*/ +MBHEAD *getmbp(void) +{ + MBHEAD *mbp; + + mbp = (MBHEAD *) allocb(ALLOC_MBHEAD); + mbp->l2link = g_ulink(userpo->uid); + mbp->type = g_utyp(userpo->uid); + + return(mbp); +} + +/**************************************************************************/ +/* */ +/*------------------------------------------------------------------------*/ +void putuse(LINKTYP seite, UID uid, MBHEAD *mbp) +{ + CIRBLK *cp; + LNKBLK *lp; + HOSTUS *hp; +#ifdef L1TCPIP + TCPIP *tc; +#endif /* L1TCPIP */ +#ifndef USER_AUSGABE + int index; + NODE *np; +#endif /* USER_AUSGABE */ + + if (seite == CQ_LINK) + { + putstr("CQ(", mbp); + switch (g_utyp(uid)) + { + case L4_USER: + putid(((CIRBLK *)g_ulink(uid))->upcall, mbp); + break; + + case L2_USER: + putid(((LNKBLK *)g_ulink(uid))->dstid, mbp); + break; + +#ifdef L1TCPIP + case TCP_USER: + putid(((TCPIP *)g_ulink(uid))->Upcall, mbp); + break; +#endif /* L1TCPIP */ + + default: + putid(((HOSTUS *)g_ulink(uid))->call, mbp); + break; + } + putstr(")\r", mbp); + return; + } + + switch (g_utyp(uid)) { + case L4_USER: + cp = g_ulink(uid); +#ifdef USER_AUSGABE + if (seite == UPLINK) + { + putstr("Uplink(", mbp); + putid(cp->upcall, mbp); + putchr(')', mbp); + putspa(18,mbp); + putstr("N: ",mbp); + putid(cp->downca, mbp); + } + else + { + putstr("(", mbp); + putid(cp->upcall, mbp); + putspa(52,mbp); + putstr(" <> ", mbp); + putid(cp->downca, mbp); + putchr(')', mbp); + putspa(65,mbp); + } +#else /* USER_AUSGABE */ + putstr("Circuit(", mbp); + index = find_node_this_ssid(cp->downca); + + if (index != -1) + { + np = netp->nodetab+index; + putalt(np->alias, mbp); + } + + putid(cp->downca, mbp); + putchr(' ', mbp); + putid(cp->upcall, mbp); + putchr(')', mbp); +#endif /* USER_AUSGABE */ + break; + + case L2_USER: + lp = g_ulink(uid); +#ifdef USER_AUSGABE + if (seite == UPLINK) + { + putstr("Uplink(", mbp); + putid(lp->dstid, mbp); + putchr(')', mbp); + putspa(18,mbp); + putprintf(mbp,"P%-2u ",lp->liport); + putprintf(mbp,"%-10s ",portpar[lp->liport].name); + } + else + { + putspa(40,mbp); + putstr("(", mbp); + putid(lp->srcid, mbp); + putspa(52,mbp); + putstr(" <> ", mbp); + putid(lp->dstid, mbp); + putchr(')', mbp); + putspa(65,mbp); + putprintf(mbp,"P%-2u ",lp->liport); + putprintf(mbp,"%-10s",portpar[lp->liport].name); +#else /* USER_AUSGABE */ + + if (seite == UPLINK) { + putstr("Uplink(", mbp); + putid(lp->dstid, mbp); + putchr(')', mbp); + } + else { + putstr("Downlink(", mbp); + putid(lp->srcid, mbp); + putchr(' ', mbp); + putid(lp->dstid, mbp); + putchr(')', mbp); +#endif /* USER_AUSGABE */ + } + break; + +#ifdef L1TCPIP + case TCP_USER: + tc = g_ulink(uid); + if (seite == UPLINK) { + putstr("Uplink(", mbp); + putid(tc->Upcall, mbp); + putchr(')', mbp); + putspa(18,mbp); + putprintf(mbp,"P%-2u ",tc->port); + putprintf(mbp,"%-15s ",tc->ip); + } + else + { + putspa(40,mbp); + putstr("(", mbp); + putprintf(mbp,"%s",tc->ip); + putchr(')', mbp); + putspa(65,mbp); + putprintf(mbp,"P%-2u ",tc->port); + putprintf(mbp,"%-10s",portpar[tc->port].name); + } + break; +#endif /* L1TCPIP */ + + + default: + hp = g_ulink(uid); + putstr("Host(", mbp); + if (cmpid(hostid, myid)) + { + putalt(alias, mbp); + putid(myid, mbp); + } + else + { + if (seite == UPLINK) putid(hp->call, mbp); + else + { + putid(hp->call, mbp); + putchr(' ', mbp); + putid(hostid, mbp); + } + } + putchr(')', mbp); + break; + } +} + +static BOOLEAN issecret(WORD channel) +{ + CHANNEL *ch; + + for (ch = channels; ch; ch = ch->next) + if (ch->chan == channel) + break; + if (ch->flags & (M_CHAN_S|M_CHAN_I)) + return(TRUE); + return(FALSE); +} + +/************************************************************************/ +/* putcvsu */ +/* Da die Verbindungen des Conversmodus so verdreht aufgebaut werden, */ +/* hier nun eine entsprechend verdrehte Ausgaberoutine DL1XAO */ +/*----------------------------------------------------------------------*/ +void putcvsu(USRBLK *u, MBHEAD *mbp) +{ + UID uid = u->uid; + CONNECTION *cp = u->convers; + + if (u->convflag == 2) { /* ausgehender Convershost */ +#ifdef USER_AUSGABE + putstr("Uplink", mbp); + putstr("(", mbp); + putid(myid, mbp); + putchr(')', mbp); + putspa(18,mbp); + putstr("Convers", mbp); +#else + putstr("Convers(", mbp); + putid(myid, mbp); /* SSID egal? ja! */ + putchr(')', mbp); +#endif /* USER_AUSGABE */ + + if (cp->type == CT_HOST) + putstr(" Host", mbp); + putspa(38, mbp); + putstr(u->status == US_CHST ? "<..> " /* im Aufbau? */ + : "<--> ", mbp); + + putuse(DOWNLINK, uid, mbp); + viaput(DOWNLINK, uid, mbp); + } + else { /* User und eingehende CVSHOST */ + putuse(UPLINK, uid, mbp); + putspa(38, mbp); +#ifdef USER_AUSGABE + putstr("<--> (", mbp); + putid(calofs(UPLINK, uid), mbp); + putspa(53,mbp); + putstr("<> Convers)", mbp); +#else + + putstr("<--> Convers(", mbp); + putid(calofs(UPLINK, uid), mbp); + putchr(')', mbp); +#endif /* USER_AUSGABE */ + if ( cp->type == CT_USER + && (issecret(cp->channel) == FALSE || userpo->sysflg)) { +#ifdef USER_AUSGABE + putspa(65,mbp); +#endif /*USER_AUSGABE */ +#ifndef L1IRC + putstr("Ch", mbp); + putlong((LONG)cp->channel, 0, mbp); +#else + if (cp->channel == EOF) + putstr("IRC", mbp); + else + { + putstr("Ch", mbp); + putlong((LONG)cp->channel, 0, mbp); + } +#endif /* L1IRC */ + } + if (cp->type == CT_HOST) + putstr(" Host", mbp); + viaput(UPLINK, uid, mbp); + } +} + +/**************************************************************************/ +/* */ +/*------------------------------------------------------------------------*/ +void putdil(const char *liste, MBHEAD *mbp) +{ + BOOLEAN mark = TRUE; + + if (*liste) { + putstr(" via", mbp); + while (*liste) { + putchr(' ', mbp); + putid(liste, mbp); + if (mark) + if ((liste[L2IDLEN - 1] & L2CH) != 0) + if (!liste[L2IDLEN] || !(liste[L2ILEN - 1] & L2CH)) { + putchr('*', mbp); + mark = FALSE; + } + liste += L2IDLEN; + } + } +} + +/**************************************************************************/ +/* */ +/*------------------------------------------------------------------------*/ +void putid(const char *call, MBHEAD *mbp) + { + char ssid; + char c; + WORD i; + + for (i = 0; i < L2IDLEN-1; ++i) + { + c = *call++; + + if (c > ' ') putchr(c, mbp); + else + { + if (c < ' ') + { + putchr('^', mbp); +#ifdef __WIN32__ + putchr((char)(c + '@'), mbp); +#else + putchr((c + '@'), mbp); +#endif /* WIN32 */ + } + } + } + ssid = (*call >> 1) & 0x0f; + if (ssid != 0) { + putchr('-', mbp); + putnum(ssid, mbp); + } +} + +/**************************************************************************/ +/* */ +/*------------------------------------------------------------------------*/ +void putalt(char *ident, MBHEAD *mbp) +{ + if (*ident != ' ') { + putcal(ident, mbp); + putchr(':', mbp); + } +} + +/**************************************************************************/ +/* */ +/*------------------------------------------------------------------------*/ +void putcal(char *call, MBHEAD *mbp) +{ + char *cp; + WORD i; + + for (i = 0, cp = call; i < L2CALEN; ++cp, ++i) { + if (*cp == ' ') + break; + putchr(*cp, mbp); + } +} + +/**************************************************************************/ +/* */ +/*------------------------------------------------------------------------*/ +void puttim(time_t *time, MBHEAD *mbp) +{ + struct tm *p; + + p = localtime(time); + putprintf(mbp,"%02d.%02d.%02d %02d:%02d:%02d", + p->tm_mday, p->tm_mon+1, p->tm_year % 100, + p->tm_hour, p->tm_min, p->tm_sec); +} + +/**************************************************************************/ +/* */ +/*------------------------------------------------------------------------*/ +void putnum(int zahl, MBHEAD *mbp) +{ + char buf[10]; + + sprintf(buf, "%d", zahl); + putstr(buf, mbp); +} + +/**************************************************************************/ +/* */ +/*------------------------------------------------------------------------*/ +void putlong(ULONG zahl, BOOLEAN justify, MBHEAD *mbp) +{ + char buf[20]; + + sprintf(buf,justify ? " %10lu" : " %lu",zahl); + putstr(buf, mbp); +} + +/**************************************************************************/ +/* */ +/*------------------------------------------------------------------------*/ +void putstr(const char *string, MBHEAD *mbp) +{ + while (*string) + putchr(*string++, mbp); +} + +/**************************************************************************/ +/* printf fuer mbp-Fuellen DL1XAO */ +/*------------------------------------------------------------------------*/ +#define VSPRINTFBUFFER 256 +void putprintf(MBHEAD *mbp, const char *format, ...) +{ + va_list arg_ptr; + char str[VSPRINTFBUFFER]; + int n = 0; + + va_start(arg_ptr, format); + n = vsnprintf(str, VSPRINTFBUFFER, format, arg_ptr); + va_end(arg_ptr); + + if (n > -1 && n < VSPRINTFBUFFER) + putstr(str, mbp); +} + +/**************************************************************************/ +/* */ +/*------------------------------------------------------------------------*/ +void putspa(WORD stop, MBHEAD *mbp) +{ + WORD i; + + i = mbp->l4time + stop - mbp->mbpc; + while (i-- > 0) + putchr(' ', mbp); +} + +/**************************************************************************/ +/* VIA-Pfad extrahieren und pruefen */ +/* */ +/* YES = Check ohne Fehler */ +/* NO = Check mit Fehler, Pfad zu kurz */ +/* ERRORS = Check mit Fehler, Calls konnten nicht extrahiert werden */ +/*------------------------------------------------------------------------*/ +TRILLIAN +getdig(WORD *laenge, char **inbuf, BOOLEAN pflag, char *outbuf) +{ + char *lispoi; + WORD i; + char *p; + WORD n; + + *outbuf = NUL; + + skipsp(laenge, inbuf); + + /* Laengenpruefung */ + if ((n = *laenge) < 4) + return (NO); /* zu kurz */ + + p = *inbuf; + + /* optionales "VIA" im Pfad ueberspringen */ + if (!strnicmp((char*)p, "VIA", 3)) + { + p += 3; + n -= 3; + } + + skipsp(&n, &p); + + /* solange wir gueltige Calls finden */ + for (i = 0, lispoi = outbuf; n > 0 && i < L2VNUM; ++i, lispoi += L2IDLEN) + if (getcal(&n, &p, pflag, lispoi) != YES) + break; + + *lispoi = NUL; + + /* mindestens ein gueltiges Call gefunden */ + if (i > 0) + { + *laenge = n; + *inbuf = p; + return(YES); + } + + return(ERRORS); +} + +/**************************************************************************/ +/* */ +/*------------------------------------------------------------------------*/ +TRILLIAN +getcal(WORD *laenge, char **inbuf, BOOLEAN pflag, char *outbuf) +{ + char call[L2IDLEN]; + char binsid = 0; + char *bufpoi; + char zeichen; + WORD i; + char *p = *inbuf; + WORD n = *laenge; + + cpyid(call,nullid); + + skipsp(&n, &p); + + bufpoi = call; + i = 0; + while (n > 0) { + if (((zeichen = (char) toupper(*p)) == ' ' ) || (zeichen == ',')) + break; + if (zeichen < ' ') + return(ERRORS); + if (zeichen == '-') { + if (n <= 0) + return(ERRORS); + ++p; + --n; + if (n <= 0) + return(ERRORS); + zeichen = *p; + if ((zeichen < '0') || (zeichen > '9')) + return(ERRORS); + ++p; + --n; + binsid = (zeichen - '0'); + if (n > 0) { + zeichen = *p; + if ((zeichen >= '0') && (zeichen <= '9')) { + binsid *= 10; + binsid += (zeichen - '0'); + if (binsid > 15) + return(ERRORS); + ++p; + --n; + } + } + call[L2IDLEN-1] = (binsid << 1) | 0x60; + break; + } + else { + if (i++ == L2IDLEN-1) + return(ERRORS); + *bufpoi++ = zeichen; + ++p; + --n; + } + } + + while (n > 0) { + zeichen = *p; + if ((zeichen != ' ') && (zeichen != ',')) + break; + ++p; + --n; + if (zeichen == ',') break; + } + + /* haben wir nur eine SID bekommen, dann ergaenzen wir mit unserem Call */ + if ((call[0] == ' ') && (binsid <= 15) && (binsid > 0)) + { + cpyid(call, myid); + call[L2IDLEN-1] = (binsid << 1) | 0x60; + i = 1; + } + + if (i == 0) + return(NO); + + if (pflag && (fvalca(call) == ERRORS)) + return(ERRORS); + + cpyid(outbuf, call); + *laenge = n; + *inbuf = p; + + return(YES); +} + +/**************************************************************************/ +/* */ +/*------------------------------------------------------------------------*/ +BOOLEAN getport(WORD *laenge, char **inbuf, WORD *port) +{ + WORD i; + WORD tmp_port; + char *save_inbuf = *inbuf; + WORD save_laenge = *laenge; + char pn[12]; + char *inbp; + char ch; + + skipsp(laenge, (char **) inbuf); + + if (*laenge <= 0) return(FALSE); + + inbp = *inbuf; + for (i = 0; i < min(*laenge, 11); i++) + { + ch = *inbp++; + if (ch == ' ') + break; + pn[i] = ch; + } + pn[i] = NUL; + + for (i = 0; i < L2PNUM; i++) { /* erst Portnamen vergleichen */ + if (stricmp(portpar[i].name, pn) == 0) { + nextspace(laenge, inbuf); + return(portenabled(*port = i)); + } + } + + if (isdigit(**inbuf)) { /* sonst Portnummer pruefen */ + tmp_port = nxtnum(laenge, inbuf); + if ( (tmp_port >= 0) + && (tmp_port < L2PNUM)) { /* Port gueltig? */ + return(portenabled(*port = tmp_port)); + } + } + + *inbuf = save_inbuf; /* Position restaurieren */ + *laenge = save_laenge; + + return(FALSE); +} + +/**************************************************************************/ +/* */ +/*------------------------------------------------------------------------*/ +TRILLIAN +getide(WORD *laenge, char *(*inbuf), char *outbuf) +{ + char ident[L2CALEN]; + char c; + WORD i; + WORD n = *laenge; + char *p = *inbuf; + + memcpy(ident, nulide, L2CALEN); + + for (i = 0; (i < L2CALEN) && (n > 0); ++i) { + --n; + c = *p++; + if (c != ' ') { + if (c != '*') { + ident[i] = c; + continue; + } + if (i != 0 || c != '*') + return(ERRORS); + } + break; + } + + if ((i == L2CALEN) && (n > 0) && (*p != ' ')) + return(ERRORS); + + if (valcal(ident) == YES) + return(ERRORS); + + memcpy(outbuf, ident, L2CALEN); + + if (ident[0] != ' ') /* Ident korrekt gelesen */ + { + *laenge = n; + *inbuf = p; + return(YES); + } + + return(NO); +} + +/**************************************************************************/ +/* */ +/*------------------------------------------------------------------------*/ +UWORD nxtnum(WORD *laenge, char **buffer) +{ + UWORD temp; + + skipsp(laenge, buffer); + temp = 0; + while (*laenge > 0 && **buffer >= '0' && **buffer <= '9') { + --*laenge; + temp *= 10; + temp += (*(*buffer)++ - '0'); + } + return(temp); +} + +/**************************************************************************/ +/* */ +/*------------------------------------------------------------------------*/ +LONG nxtlong(WORD *laenge, char **buffer) +{ + LONG temp; + + skipsp(laenge, buffer); + temp = 0; + while (*laenge > 0 && **buffer >= '0' && **buffer <= '9') { + --*laenge; + temp *= 10; + temp += (*(*buffer)++ - '0'); + } + return(temp); +} + +/**************************************************************************/ +/* */ +/*------------------------------------------------------------------------*/ +TRILLIAN +fvalca(char *call) +{ + if (*call == ' ' ) + return(NO); + return(valcal(call)); +} + +/**************************************************************************/ +/* */ +/*------------------------------------------------------------------------*/ +TRILLIAN +valcal(char *call) +{ + char *numpos = 0; + char *actual; + char zeichen; + WORD zahl = 0; + WORD i = 0; + + for (actual = call; i < L2IDLEN-1; ++i, ++actual) + { + if ((zeichen = *actual) == ' ') + break; + if (!((zeichen >= 'A') && (zeichen <= 'Z'))) + { + if ((zeichen >= '0') && (zeichen <= '9')) + { + zahl += 1; + numpos = actual; + } + else + return(ERRORS); + } + } + +#ifndef CALLCHECK + if ( ((actual - call) < 4) || zahl == 0 || zahl > 2 || (numpos == call) + || (numpos == (actual - 1)) || ((numpos - call) >= 3)) + return(ERRORS); +#else + /* Hat Rufzeichen weniger als 4 Zeichen, */ + if (i < 4) + /* ist es ungueltig. */ + return(ERRORS); +#endif /* CALLCHECK */ + + return(YES); +} + +/**************************************************************************/ +/* */ +/*------------------------------------------------------------------------*/ +BOOLEAN ismemr(void) +{ + if (nmbfre < 300 && !userpo->sysflg) + return(FALSE); + + return(TRUE); +} + +/**************************************************************************/ +/* */ +/*------------------------------------------------------------------------*/ +char *calofs(LINKTYP uplink, UID uid) +{ + void *link; + + if (uid == NO_UID) return(myid); + + link = g_ulink(uid); + switch (g_utyp(uid)) { + case L2_USER : + return(((LNKBLK *)link)->dstid); + case L4_USER : + return( ((uplink == UPLINK) || (uplink == CQ_LINK)) + ? ((CIRBLK *)link)->upcall + : ((CIRBLK *)link)->downca); +#ifdef L1TCPIP + case TCP_USER : + return(((TCPIP *)link)->Upcall); +#endif /* L1TCPIP */ + } + + if (tnnb_aktiv) return(myid); + if (uplink == DOWNLINK) return(hostid); + return(hstusr->call); +} + +/**************************************************************************/ +/* */ +/*------------------------------------------------------------------------*/ +BOOLEAN getlin(MBHEAD *mbp) +{ + char huge *nextch; + WORD getcou; + WORD found; + WORD laenge; + WORD mlaenge = 81; + + if (userpo->status == US_WBIN || userpo->status == US_RBIN) + return(TRUE); + + if (userpo->convers) { + if (userpo->convers->type == CT_UNKNOWN) + return(TRUE); + mlaenge = 2047; + } + nextch = mbp->mbbp; + getcou = mbp->mbgc; + found = FALSE; + laenge = 0; + while (mbp->mbgc < mbp->mbpc) { + if ( ((getchr(mbp)) == CR) || (++laenge == mlaenge)) { + found = TRUE; + break; + } + } + mbp->mbbp = nextch; + mbp->mbgc = getcou; + return(found); +} + +/**************************************************************************/ +/* */ +/*------------------------------------------------------------------------*/ +BOOLEAN issyso(void) +{ + return(userpo->sysflg != 0); +} + +/**************************************************************************/ +/* */ +/*------------------------------------------------------------------------*/ +BOOLEAN skipsp(WORD *cnt, char **cpp) +{ + while ((*cnt > 0) && **cpp == ' ') { + ++*cpp; + --*cnt; + } + return((*cnt > 0) ? TRUE : FALSE); +} + +/**************************************************************************/ +/* */ +/*------------------------------------------------------------------------*/ +WORD getparam(WORD *cnt, char **cpp, WORD min, WORD max, WORD def) +{ + int par; + if ((*cnt) > 1) { + (*cpp)++; + (*cnt)--; + if (toupper(*(*cpp)) == 'O') { /* BOOLEAN */ + if (toupper((*cpp)[1]) == 'N') par = 1; + else par = 0; + nextspace(cnt, cpp); + return(par); + } + par = (nxtnum(cnt, cpp)); + if (par > max) par = max; + if (par < min) par = min; + return(par); + } + return(def); +} + +/**************************************************************************/ +/* */ +/*------------------------------------------------------------------------*/ +BOOLEAN nextspace(WORD *cnt, char **cpp) +{ + while ((*cnt > 0) && **cpp != ' ') { + ++*cpp; + --*cnt; + } + return((*cnt > 0) ? TRUE : FALSE); +} + +/* Ermittelt das Filedatum von AKTUELL.TXT und stellt es zur Verfuegung + */ +static char *aktuell(void) +{ + char file[128]; + struct ffblk fb; + static char akt[10] = "?"; +#ifdef MC68302 + struct tm *ftime; +#endif + + strcpy(file, textcmdpath); +#ifdef MC68302 + strcat(file, "aktuell.txc"); +#else + strcat(file, "aktuell.txt"); +#endif + if (xfindfirst(file, &fb, 0) == 0) { +#ifdef MC68302 + ftime = localtime(&fb.ff_ftime); + sprintf(akt, "%02d.%02d.%02d", ftime->tm_mday, + (ftime->tm_mon)+1, + (ftime->tm_year)%100); +#else + sprintf(akt,"%02d.%02d.%02d", fb.ff_fdate & 0x1f, + (fb.ff_fdate >> 5) & 0xf, + ((fb.ff_fdate >> 9) + 80) % 100); +#endif + } + return(akt); +} + +/*------------------------------------------------------------------------*/ +/* Prompt generieren und an Message-Buffer anhaengen */ +/*------------------------------------------------------------------------*/ +/* Prompt aufbauen, im Convers-Modus gibt es keinen Prompt, sondern */ +/* stattdessen einen String '***\r', der das Ende der Ausgabe des */ +/* Digis anzeigt. */ +void prompt(MBHEAD *mbp) +{ + if (userpo->convers == NULLCONNECTION) + prompt2str(mbp, promptstr); + else + putstr("***\r", mbp); +} + + /* String nach '%' durchsucht und gegebenenfalls ergaenzt. */ + /* '%a' wird durch den Digipeater-Ident ersetzt, */ + /* '%A' wird durch das Datum des aktuell.txt ersetzt, */ + /* '%c' durch das Call des Users, */ + /* '%C' durch das User-Call mit SSID, */ + /* '%d' durch das Call des Digipeaters, */ + /* '%D' durch das Call des Digipeaters mit SSID, */ + /* '%f' durch den Inhalt der angegebenen Datei */ + /* '%l' durch die Anzahl aktiver L2-Links */ + /* '%p' durch die Portnummer */ + /* '%P' durch den Pseudo-Name des Ports */ + /* '%r' durch Carriage-Return */ + /* '%s' durch Datum */ + /* '%t' durch die aktuelle Uhrzeit (HH:MM). */ + /* '%u' durch die Anzahl der User auf dem aktuellen Port */ + /* '%%' durch % */ + /* '%0' unterdrueckt die Aussendung eines Prompts. */ +void prompt2str(MBHEAD *mbp, char *str) +{ + char *cp; + char buf[128]; + struct tm *lt; + LNKBLK *link; /* L2-Link des Users */ + FILE *fp; + char *c; + char filename[128]; +#ifdef MAKRO_USER + UWORD user_anzahl = 0; /* die echte Useranzahl im Knoten */ + UWORD interlinks = 0; /* alle Interlinks im knoten */ + UWORD _nmblks = 0; /* Sicherungskopie fuer das echte nmblks */ +#endif +#ifdef L1TCPIP + TCPIP *tpoi; +#endif /* L1TCPIP */ + + while (*str) { + for (cp = str; *cp && *cp != '%'; ++cp) + ; + if (*cp == '%') { + *cp = NUL; + putstr(str, mbp); + *cp++ = '%'; + switch (*cp) { + case 'a': putalt(alias, mbp); + break; + + case 'A': putstr(aktuell(), mbp); + break; + + case 'c': putcal(calofs(UPLINK, userpo->uid), mbp); + break; + + case 'C': putid(calofs(UPLINK, userpo->uid), mbp); + break; + + case 'd': putcal(myid, mbp); + break; + + case 'D': putid(myid, mbp); + break; + + case 'f': cp++; + strcpy(filename, cp); /* Dateiname extrahieren */ + + if ((c = strchr(filename, ' ')) != NULL) + *c = '\0'; + + if ((fp = xfopen(filename, "rt")) != NULL) { + + while (fgets(buf, 126, fp) != NULL) { + + if ((c = strchr(buf, '\n')) != NULL) + *c = CR; + putprintf(mbp, buf); + } + + fclose(fp); + + cp += strlen(filename) - 1; /* Ein Zeichen vor dem Ende */ + + if (*(cp + 1) == ' ') + cp++; /* Sonst Probs bei Text am Strinende */ + } + break; + + case 'l': putprintf(mbp, "%01u", nmblks); /* Anzahl L2-Links */ + break; + + case 'p': /* Portnummer */ + switch(g_utyp(userpo->uid)) + { + case L2_USER : + link = g_ulink(userpo->uid); /* Userlink ermitteln */ + putprintf(mbp, "%u", link->liport); /* -> Portnummer */ + break; + +#ifdef L1TCPIP + case TCP_USER : + tpoi = g_ulink(userpo->uid); /* Userlink ermitteln */ + putprintf(mbp, "%u", tpoi->port); /* -> Portnummer */ + break; +#endif /* L1TCPIP */ + + default : + /* Host-Console */ + putstr("C", mbp); /* -> "C" */ + break; + } + break; + + case 'P': /* Portname */ + switch(g_utyp(userpo->uid)) + { + case L2_USER : + link = g_ulink(userpo->uid); /* Userlink ermitteln */ + /* Portname ausgeben, wenn User nicht von Console kommt */ + putprintf(mbp, "%s", portpar[link->liport].name); + break; + +#ifdef L1TCPIP + case TCP_USER : + tpoi = g_ulink(userpo->uid); /* Userlink ermitteln */ + /* Portname ausgeben, wenn User nicht von Console kommt */ + putprintf(mbp, "%s", portpar[tpoi->port].name); + break; +#endif /* L1TCPIP */ + + default : + /* Host-Console */ + putstr("Console", mbp); /* -> "Console" */ + break; + } + break; + + case 'r': putchr(CR, mbp); + break; + + case 's': lt = localtime(&sys_time); + putprintf(mbp, "%02u.%02u.%02u", + lt->tm_mday, lt->tm_mon+1, lt->tm_year%100); + break; + + case 't': sprintf(buf,"%16.16s",ctime(&sys_time)); + putstr(&buf[11], mbp); + break; + +#ifdef MAKRO_USER + case 'u': interlinks = Interlinks_zaehlen(); + /* wir zaehlen erstmal alle Interlinks im Knoten */ + _nmblks = nmblks; + /* Sicherungskopie vom Original nmblks */ + putprintf(mbp, "%u", user_anzahl = (_nmblks - interlinks) + nmbcir +#ifdef L1TCPIP + + nmbtcp +#endif /* L1TCPIP */ + ); + /* L2-Links - Interlinks + L4-User = echte Useranzahl */ + break; +#else + case 'u': /* Useranzahl auf aktuellem L2-Port */ + if (mbp->type == L2_USER) + { + lnk = g_ulink(userpo->uid); /* Userlink ermitteln */ + /* Anzahl ausgeben, wenn User nicht von Console kommt */ + putprintf(mbp, "%u", portpar[lnk->liport].nmbstn); + } + else /* fuer Host-Console und L4 nicht */ + putstr("N/A", mbp); /* verfuegbar */ + break; +#endif +#ifdef MAKRO_NOLOGINSTR + case 'v': putprintf(mbp,"%s",loginstr); +#endif + case '0': break; + + case '%': putchr('%', mbp); + break; + } + str = ++cp; + } + else + { + putstr(str, mbp); + str = cp; + } + } +} + +/************************************************************************/ +/* */ +/*----------------------------------------------------------------------*/ +void putide(char *ID, MBHEAD *mbp) +{ + int i; + + for (i = 5; (i >= 0) && (ID[i] == ' '); i--) putchr(' ', mbp); + for (i = 0; (i < L2CALEN) && (ID[i] != ' '); i++) putchr(ID[i],mbp); +} + +/************************************************************************/ +/* */ +/*----------------------------------------------------------------------*/ +void invmsg(void) +{ +#ifdef SPEECH + putmsg(speech_message(277)); +#else + putmsg("Invalid command. Try HELP.\r"); +#endif +} + +/************************************************************************/ +/* Beacons */ +/*----------------------------------------------------------------------*/ +void dump_beacn(MBHEAD *mbp) +{ + BEACON *beapoi; + int port; + + putstr(";\r; Stat/Text-Broadcast\r;\r", mbp); + for (port = 0, beapoi = beacon; port < L2PNUM; ++port, ++beapoi) { + if (*beapoi->text) + putprintf(mbp, "BEACON %d = %s\r", port, beapoi->text); + putprintf(mbp, "BEACON %d %d %d ", port, beapoi->interval, beapoi->telemetrie); + putid(beapoi->beades, mbp); + putdil(beapoi->beadil, mbp); + putchr('\r', mbp); + } +} + +/************************************************************************/ +/* Convers-Links */ +/*----------------------------------------------------------------------*/ +void dump_convc(MBHEAD *mbp) +{ + int pl; + char *c; + PERMLINK *p; + + putstr(";\r; Convers Interlinks\r;\r", mbp); +#ifdef CONVERS_HOSTNAME + putprintf(mbp,"CONV HOSTNAME %s\r",myhostname); +#endif + for (pl = 0; pl < MAXCVSHOST; pl++) { + p = permarray[pl]; + if (p ) { + putstr("CONV C ", mbp); +#ifdef L1IPCONV + putprintf(mbp,"%s ", p->cname); + if (p->TcpLink) + putprintf(mbp,"%s ", p->HostName); + else +#endif /* L1IPCONV */ + putid(p->call, mbp); + if (p->port != 255) { + putchr(' ', mbp); + putnum(p->port, mbp); + if (*(c = p->via)) { + while (*c) { + putchr(' ', mbp); + putid(c, mbp); + c += L2IDLEN; + } + } + } + putchr('\r', mbp); + } + } +} + + +/************************************************************************/ +/* Links */ +/*----------------------------------------------------------------------*/ +void dump_links(MBHEAD *mbp) +{ + char *c; + L2LINK *p; + PEER *pp; + int i; + int max_peers = netp->max_peers; +#ifdef ALIASSAVEMOD + char alias[L2IDLEN]; +#endif /* ALIASSAVEMOD */ + + putstr(";\r; Links\r;\r", mbp); + + for (i = 0, pp = netp->peertab; i < max_peers; i++, pp++) + if (pp->used) + { + p = pp->l2link; + if (p->port != L2PNUM) /* Sonderbehandlung Hostmode-Link */ + { +#ifdef AUTOROUTING + /* Link ist eine Auto-Route, */ + if (p->ppAuto == AUTO_ROUTE) + /* zum naechsten Eintrag. */ + continue; +#endif /* AUTOROUTING */ + putstr("LINK + ", mbp); + putprintf(mbp, "%2.2s ",typtbl + pp->soll_typ * 2); + +#ifdef PROXYFUNC + if (pp->proxy == TRUE) + putstr("P ", mbp); +#endif /* PROXYFUNC */ + putnum(p->port, mbp); + putchr(' ', mbp); +#ifdef ALIASSAVEMOD + /* Ist der Alias komplett in Grossbuchstaben, wird der Linkeintrag */ + /* beim naechsten mal NICHT eingelesen!!! Darum muessen wir den */ + /* in kleinbuchstaben umwandeln. */ + cpyid(alias, p->alias); + /* Ein Alias kann max. 6 Zeichen haben. */ + alias[L2CALEN] = 0; + + /* Alias in kleinbuchstaben umwandeln und in den Buffer schreiben. */ + putcal(strlwr(alias), mbp); +#else + putcal(p->alias, mbp); +#endif /* ALIASSAVEMOD */ + putchr(' ', mbp); + putid (p->call, mbp); + putchr(' ', mbp); + + if (*(c = p->digil )) + { + while (*c) + { + putchr(' ', mbp); + putid(c, mbp); + c += L2IDLEN; + } + } + +#ifdef LINKSMODINFO + putchr(' ', mbp); + putstr("INFO=",mbp); + putprintf(mbp,"%s",p->info, mbp); +#endif /* LINKSMODINFO */ + } + else + { + putstr("ESC I ", mbp); + putid(p->call, mbp); + putchr(' ', mbp); + putcal(p->alias, mbp); + +#ifdef PROXYFUNC + if (pp->proxy == TRUE) + putstr(" P", mbp); +#endif + } + + putchr('\r',mbp); + } +} + +/************************************************************************/ +/* Parameter */ +/*----------------------------------------------------------------------*/ +void dump_parms(MBHEAD *mbp) +{ + UWORD num; + PARAM *p; + + putstr(";\r; Parameters\r;\r", mbp); + for (p = partab, num = 1; num <= partablen; p++, num++) + if (p->paradr && strncmp(p->parstr, "unu", 3)) + putprintf(mbp, "PAR %s %u\r", p->parstr, *(p->paradr)); +} + +/************************************************************************/ +/* Ports */ +/*----------------------------------------------------------------------*/ +void +dump_ports(MBHEAD *mbp) +{ + int port; + PORTINFO *pp; + L1MODETAB *mtp; + char mode[16], *cp; + + putstr(";\r; Port Configuration (Level 1)\r;\r", mbp); + for (port = 0, pp = portpar; port < L2PNUM; port++, pp++) + { + putprintf(mbp, "PORT %d NAME=%s ", port, pp->name); + l1hwcfg(port, mbp); + cp = mode; + for (mtp = l1modetab; mtp->ch; mtp++) + if (pp->l1mode & mtp->mode) + *cp++ = mtp->ch; + *cp = NUL; + + putprintf(mbp, " MODE=%u00%s TXD=%u MAX=%u%s ", + pp->speed, + mode, + pp->txdelay, + pp->maxframe, + automaxframe(port) ? "a" : ""); +#ifdef SETTAILTIME + putprintf(mbp, "TAIL=%u ", pp->tailtime); +#endif + +#ifdef DAMASLAVE + if (pp->l2mode & MODE_ds) + strcpy(mode, "s"); + else +#endif + sprintf(mode, "%2u", pp->l2mode & MODE_a ? pp->dch + 1 : 0); + + putprintf(mbp, "DAMA=%s CTEXT=%u SYSOP=%u MH=%u", + mode, + pp->l2mode & MODE_x ? 1 : 0, + pp->l2mode & MODE_s ? 1 : 0, + pp->l2mode & MODE_h ? 1 : 0); +#ifdef USERMAXCON + putprintf(mbp, " MAXCON=%u", pp->maxcon); +#endif +#ifdef EAX25 + putprintf(mbp, " EAXMAXF=%u EAXMODE=%u", pp->maxframe_eax, pp->eax_behaviour); +#endif + +#ifdef EXPERTPARAMETER + putprintf(mbp, " PERS=%u%c SLOT=%u%c IRTT=%u%c T2=%u%c RETRY=%u%c", + pp->persistance, + (pp->l2autoparam & MODE_apers) ? 'a' : ' ', + pp->slottime, + (pp->l2autoparam & MODE_aslot) ? 'a' : ' ', + pp->IRTT, + (pp->l2autoparam & MODE_aIRTT) ? 'a' : ' ', + pp->T2, + (pp->l2autoparam & MODE_aT2) ? 'a' : ' ', + pp->retry, + (pp->l2autoparam & MODE_aretry) ? 'a' : ' '); +#endif + +#ifdef PORT_MANUELL + putprintf(mbp, "\rPORT %d", port); + + putprintf(mbp, " PACLEN=%u", pp->paclen); + putprintf(mbp, " T3=%u", pp->T3); +#endif /* PORT_MANUELL */ + +#ifdef IPOLL_FRAME + putprintf(mbp, " IPACLEN=%u IRETRY=%u", pp->ipoll_paclen,pp->ipoll_retry); +#endif /* IPOLL_FRAME */ +#ifdef PORT_L2_CONNECT_TIME + putprintf(mbp, " L2TIME=%u", pp->l2_connect_time); +#endif +#ifdef PORT_L2_CONNECT_RETRY + putprintf(mbp, " L2RETRY=%u", pp->l2_connect_retry); +#endif +#ifdef AUTOROUTING + /* Fixed/Auto-Route eintragen. */ + putprintf(mbp, " L4AUTO=%u", pp->poAuto); +#endif /* AUTOROUTING */ + putchr('\r', mbp); + } +} + +/************************************************************************/ +/* SUSPEND */ +/*----------------------------------------------------------------------*/ +void dump_suspd(MBHEAD *mbp) +{ + SUSPEND *suspoi; + int i; + + putstr(";\r; Suspended Users\r;\r", mbp); + for (suspoi = sustab, i = 0; i < MAXSUSPEND; suspoi++, i++) + if (suspoi->call[0]) { + putprintf(mbp, "SUSPEND + %d ", suspoi->port); + putcal(suspoi->call, mbp); + if (suspoi->port == 255) { + putchr(' ', mbp); + putnum(suspoi->okcount, mbp); + } + putchr('\r', mbp); + } +} + +/************************************************************************/ +/* ip */ +/*----------------------------------------------------------------------*/ +#ifdef IPROUTE +void dump_ipr(MBHEAD *mbp) +{ + IP_ROUTE *ipr; + ARP_TAB *arp; + const char *dgmode_tab[] = {"", "DG", "VC"}; + + putstr(";\r;IP-Config\r;\rIPA ", mbp); + show_ip_addr(my_ip_addr, mbp); /* My IP-Adress */ + putprintf(mbp, "/%d\r", my_ip_bits); + + for (ipr = (IP_ROUTE *)IP_Routes.head; /* IP-Routen */ + ipr != (IP_ROUTE *)&IP_Routes; + ipr = (IP_ROUTE *)ipr->nextip) { + putstr("IPR ", mbp); + show_ip_addr(ipr->dest, mbp); /* Adresse anzeigen */ + putprintf(mbp, "/%d + %s", + ipr->bits, /* Bitmaske zeigen */ + ipr->flags & RTDYNAMIC ? "D " : " "); + switch (ipr->port) + { + case NETROM_PORT: putstr("NET/ROM ", mbp); break; +#ifdef KERNELIF + case KERNEL_PORT: putstr("KERNEL ", mbp); break; +#endif + default : putprintf(mbp, "%s ", portpar[ipr->port].name); + } + if (ipr->gateway != 0) + show_ip_addr(ipr->gateway, mbp); /* Gateway */ + putchr(' ', mbp); + if (ipr->metric != 0) /* if metric set, */ + putnum(ipr->metric, mbp); /* show metric */ + putchr('\r', mbp); + } + + for (arp = (ARP_TAB *)Arp_tab.head; /* ARP */ + arp != (ARP_TAB *)&Arp_tab; + arp = (ARP_TAB *)arp->nextar) { + if (arp->timer == 0) { /* nur feste Eintraege */ + putstr("ARP ", mbp); + show_ip_addr(arp->dest, mbp); + putprintf(mbp, " + %c ", arp->publish_flag ? 'P' : ' '); + switch (arp->port) + { + case NETROM_PORT: putstr("NET/ROM ", mbp); break; +#ifdef KERNELIF + case KERNEL_PORT: putstr("KERNEL ", mbp); break; +#endif + default : putprintf(mbp, "%s ", portpar[arp->port].name); + } + putprintf(mbp, "%s ", dgmode_tab[(int)arp->dgmode]); + putid(arp->callsign, mbp); + putchr(' ', mbp ); + putdil(arp->digi, mbp); + putchr('\r', mbp ); + } + } +} +#endif + +#ifdef ALIASCMD +/************************************************************************/ +/* print aliasses */ +/*----------------------------------------------------------------------*/ +void dump_alias(MBHEAD *mbp) +{ + CMDALIAS *ap; + + putstr(";\r; Commando-Aliasses\r;\r", mbp); + + for (ap = aliaslist; ap != NULL; ap = ap->next) + putprintf(mbp, "ALIAS %s %s\r", ap->alias, ap->cmd); + +} +#endif + +/************************************************************************/ +/* Versch. noch eintragen */ +/*----------------------------------------------------------------------*/ +void dump_divrs(MBHEAD *mbp) +{ +#ifdef PACSAT + WORD x; + + /* PACSAT-BROADCAST */ + + putstr(";\r; Pacsat Broadcast\r;\r", mbp); + for (x = 0; x < L2PNUM; x++) + { + if (pacsat_enabled[x]) + { + putprintf(mbp, "PACSAT + %u\r", x); + } + } + putstr("PACSAT C ", mbp); + if (!cmpid(pacsatid, nullid)) + putid(pacsatid,mbp); + else + putchr('-', mbp); + + putprintf(mbp, "\rPACSAT P 1 %u\r",pacsat_timer); + putprintf(mbp, "PACSAT P 2 %u\r",pacsat_frames); + putprintf(mbp, "PACSAT P 3 %u\r",pacsat_free); +#endif + /* versch. */ + + putstr(";\r; Mailbox and Cluster\r;", mbp); + if (boxid[0]) + { + putstr("\rMAILBOX ", mbp); + putid(boxid, mbp); + } + if (dxcid[0]) + { + putstr("\rDXCLUSTER ", mbp); + putid(dxcid, mbp); + } + +#ifdef HOSTMYCALL + if (hostuserid[0]) + { + putstr("\rMYHOST ", mbp); + putid(hostuserid, mbp); + } +#endif /* HOSTMYCALL */ + +#ifdef SYSOPPASSWD + if (paswrd[0]) + { + putstr("\rSYSPASS ", mbp); + putprintf(mbp,"%s",paswrd); + } +#endif /* SYSOPPASSWD */ + + putstr("\r;\r; MHeard, Prompt\r;\r", mbp); + putprintf(mbp, "MH = %d\r", l2heard.max); + putprintf(mbp, "L3MH = %d\r", l3heard.max); + putprintf(mbp, "PROMPT =%s\r", promptstr); +#ifndef __LINUX__ /* steht bei Linux in tnn.ini */ + if (tkcom > -1) { + /* Tokenring-Speed */ + putstr(";\r; Tokenspeed\r;\r", mbp); + putprintf(mbp, "#T %u00",tkbaud); + } +#endif +} + +void save_parms(void) +{ + MBHEAD *mbp; + FILE *fp; + UBYTE ch; + char call[20]; + +#ifdef SAVEPARAMFIX + char konfigfile[128]; + + strcpy(konfigfile,cfgfile); + strcat(konfigfile,".TNB"); + + if ((fp = xfopen(konfigfile, "wt+")) == NULL) return; +#else /* SAVEPARAMFIX */ + if ((fp = xfopen("PARMS.TNB", "wt+")) == NULL) return; +#endif /* SAVEPARAMFIX */ +#ifdef ST + setvbuf(fp, NULL, _IOFBF, 4096L); /* speedup */ +#endif + + mbp = (MBHEAD *) allocb(ALLOC_MBHEAD); + + /* Versionskennung und Datum speichern */ + + putprintf(mbp, "; ----------------------------------------------\r" + ";\r" + "; THIS FILE MAY BE OVERWRITTEN - DO NOT CHANGE!!\r" + "; (use %s.TNB)\r;\r", cfgfile); + putprintf(mbp, "; ----------------------------------------------\r" + "; TheNetNode AutoConfiguration Batch File\r" + ";\r" + "; Created: "); + puttim(&sys_time, mbp); + call2str(call,myid); + putprintf(mbp, "\r; Version: %s;\r" + "; Node Ident : %s\r" + "; Node MyCall: %s\r;\r", version, alias, call); + +#ifdef ATTACH + dump_attach(mbp); +#endif + /* die ganzen Parameter ausgeben, nach DL1XAO */ + dump_ports(mbp); + dump_beacn(mbp); + dump_convc(mbp); + dump_links(mbp); + dump_parms(mbp); +#ifdef THENETMOD + dump_l4parms(mbp); /* L4-Parameter speichern. */ + /* L4QUALI */ + dump_routes(mbp); /* Qualitaet einer Route (nur THENET) speichern. */ +#endif /* THENETMOD */ + dump_suspd(mbp); +#ifdef ALIASCMD + dump_alias(mbp); +#endif +#ifdef IPROUTE + dump_ipr(mbp); +#endif +#ifdef KERNELIF + dump_kernel(mbp); +#endif +#ifdef AX25IP + dump_ax25ip(mbp); +#endif +#ifdef SPEECH + dump_speech(mbp); +#endif +#ifdef L1TCPIP + DumpTCP(mbp); +#endif /* L1TCPIP */ + dump_divrs(mbp); + rwndmb(mbp); + + while (mbp->mbgc < mbp->mbpc) + { + ch = getchr(mbp); + if (ch == CR) fprintf(fp, "\n"); + else fputc(ch, fp); + } + + dealmb(mbp); + fclose(fp); +} + +/************************************************************************/ +/* Ein Ereignis protokollieren, jeder Sysop, der einen Trace mit dem */ +/* notwendigen Level eingestellt hat, bekommt die Meldung zugeschickt. */ +/*----------------------------------------------------------------------*/ +void notify(int level, const char *format, ...) +{ +#if MAX_TRACE_LEVEL > 0 +#define NOTIFYVSNPFBUFF 1024 + va_list arg_ptr; + char str[NOTIFYVSNPFBUFF]; + USRBLK *sav_userpo; + MBHEAD *mbp; + struct tm *p; + int n; + + p = localtime(&sys_time); + + va_start(arg_ptr, format); + n = vsnprintf(str, NOTIFYVSNPFBUFF, format, arg_ptr); + va_end(arg_ptr); + + if (n == -1 || n > NOTIFYVSNPFBUFF) + return; + + sav_userpo = userpo; + + for (userpo = (USRBLK *) usccpl.head; + userpo != (USRBLK *) &usccpl; + userpo = (USRBLK *) userpo->unext) + { + if (userpo->status == US_CCP && userpo->auditlevel >= level) { + mbp = getmbp(); + putprintf(mbp, "(%u) %02d.%02d.%02d %02d:%02d:%02d ", + level, + p->tm_mday, p->tm_mon+1, p->tm_year % 100, + p->tm_hour, p->tm_min, p->tm_sec); + putstr(str, mbp); + putchr('\r', mbp); + if (!send_msg(FALSE,mbp)) + dealmb((MBHEAD *)ulink((LEHEAD *)mbp)); /* der Link ist voll */ + break; + } + } + + userpo = sav_userpo; +#endif +} + +/************************************************************************/ +/* Feststellen, ob ein User einen Downlink auf einem Port machen darf. */ +/*----------------------------------------------------------------------*/ +BOOLEAN is_down_suspended(char *user_call, int user_port) +{ + LNKBLK *link; + SUSPEND *suspended; + WORD user_links; + WORD i, j; + + /* Suspended-Liste nach dem User-Rufzeichen durchsuchen */ + for (suspended = sustab, i = 0; i < MAXSUSPEND; suspended++, i++) + if (strnicmp(user_call, suspended->call, L2CALEN) == 0) + break; + + if (i == MAXSUSPEND) /* User nicht in der Liste */ + return(FALSE); /* er darf.. */ + + if (user_port == suspended->port) /* User gesperrt auf diesem Port */ + return(TRUE); /* also abwerfen.. */ + + if (suspended->port == 254) /* darf ueberhauptnicht */ + return(TRUE); + + if (suspended->port != 255) /* Falls 255 dann zaehlen... */ + return(FALSE); + + /* Anzahl der Links dieses Users zum Knoten ermitteln */ + for (link = lnktbl, j = 0, user_links = 0; j < LINKNMBR; j++, link++) + if (cmpcal(link->dstid, user_call) && link->state != L2SDSCED ) + user_links++; + + return(user_links > suspended->okcount); +} + +/************************************************************************/ +/*--- Test, ob User gesperrt ist ---*/ +/* */ +/* Parameter im Aufruf: */ +/* *u_block: Pointer auf User Kontrollblock */ +/* */ +/* Rueckgabe: */ +/* TRUE: User ist gesperrt */ +/* FALSE: User hat noch mindestens einen Kanal frei */ +/* */ +/* Es wird auf PORT und OKCOUNT geprueft. OKCOUNT ist die Maximalzahl */ +/* der zulaessigen Links, unabhaengig vom Port. PORT ist immer gesperrt.*/ +/* Um einen User nur fuer einen Port zu sperren ist also OKCOUNT auf */ +/* 255 zu setzen und PORT auf den Sperrport. Um einen USER auf eine */ +/* Maximalzahl von Links zu begrenzen, ist PORT auf 255 zu setzen und */ +/* OKCOUNT auf die gewuenschte Zahl an Links. */ +/* Der Port 254 entspricht einem L4-User */ +/*----------------------------------------------------------------------*/ +BOOLEAN is_suspended(USRBLK *u_block) +{ + LNKBLK *link; + SUSPEND *suspended; + char *user_call; + UBYTE user_port; + WORD user_links; + WORD i, j; +#ifdef L1TCPIP + TCPIP *tc; +#endif /* L1TCPIP */ + + + switch (g_utyp(u_block->uid)) + { + case HOST_USER: + return(FALSE); /* User am Host-Terminal */ + + /* User im Level-2 Uplink */ + case L2_USER: + link = g_ulink(u_block->uid); + user_call = link->dstid; +#ifdef __WIN32__ + user_port = (unsigned char)link->liport; +#else + user_port = link->liport; +#endif /* WIN32 */ + break; + + /* User kommt per Circuit */ + case L4_USER: + user_call = ((CIRBLK *)g_ulink(u_block->uid))->upcall; + user_port = 254; + break; + +#ifdef L1TCPIP + case TCP_USER: + tc = g_ulink(u_block->uid); + user_call = tc->Upcall; + user_port = (unsigned char)tc->port; + break; +#endif /* L1TCPIP */ + + /* damit der Compiler auch bei Optimierungen zufrieden ist ... */ + default: + user_call = 0; + user_port = 254; + break; + } + + /* Suspended-Liste nach dem User-Rufzeichen durchsuchen */ + for (suspended = sustab, i = 0; i < MAXSUSPEND; ++suspended, ++i) + if (cmpcal(user_call, suspended->call)) + break; + + if (i == MAXSUSPEND) /* User nicht in der Liste */ + return(FALSE); /* er darf.. */ + + if (user_port == suspended->port) /* User gesperrt auf diesem Port */ + return(TRUE); /* also abwerfen.. */ + + /* Anzahl der Links dieses Users zum Knoten ermitteln */ + for (link = lnktbl, j = 0, user_links = 0; j < LINKNMBR; ++j, ++link) + if (cmpcal(link->dstid, user_call) && link->state != L2SDSCED ) + ++user_links; + + if (user_links > suspended->okcount) /* Anzahl der Links ueberschritten */ + return(TRUE); /* also abwerfen.. */ + + return(FALSE); /* User darf.. */ +} + +#ifdef PORT_SUSPEND +BOOLEAN is_port_suspended(USRBLK *u_block) +{ + LNKBLK *link; + char *user_call = NUL; + char *p; + UWORD user_port = FALSE; + PEER *pp; + int max_peers = netp->max_peers; + int i; + + switch (g_utyp(u_block->uid)) + { + case HOST_USER: + return(FALSE); /* Host ist nie gesperrt !!! */ + + case L2_USER: + link = g_ulink(u_block->uid); + /* In den Linkblock wird ein Zeiger auf das Rufzeichen abgelegt, das in */ + /* Wirklichkeit der Ansprechpartner dieses Linkes ist. Es ist das Erste */ + /* Rufzeichen im via-Feld ohne H-Bit oder das Ziel-Rufzeichen selbst. */ + for (p = link->viaidl; *p; p += L2IDLEN) + if ((p[L2IDLEN - 1] & L2CH) == 0) + break; + link->realid = *p ? p : link->dstid; + user_call = link->realid; + user_port = link->liport; + break; + case L4_USER: + return(FALSE); + + /* damit der Compiler auch bei Optimierungen zufrieden ist ... */ + default: + break; + } + +for (i = 0, pp = netp->peertab; i < max_peers; i++, pp++) + if (pp->used) + { + if ((cmpcal(user_call,pp->l2link->call) || (cmpcal(user_call,pp->l2link->digil) == TRUE))) + if ((user_port == pp->l2link->port) == TRUE) + return (FALSE); + } + return(TRUE); +} +#endif +/************************************************************************/ +/*--- CRC-Tabelle berechnen ---*/ +/* */ +/*----------------------------------------------------------------------*/ +void init_crctab(void) +{ + UWORD n; + UWORD m; + UWORD r; + UWORD mask; + + static UWORD bitrmdrs[] = { 0x9188, 0x48C4, 0x2462, 0x1231, + 0x8108, 0x4084, 0x2042, 0x1021}; + + for (n = 0; n < 256; ++n) + { + for (mask = 0x0080, r = 0, m = 0; m < 8; ++m, mask >>= 1) + if (n & mask) + r = bitrmdrs[m] ^ r; + crctab[n] = r; + } +} + +/*----------------------------------------------------------------------*/ +static char *search_file(char *dir_name, char *text_name) { +/* */ +/* Das erste Wort in *clipoi als Filenamen annehmen. Dabei sind */ +/* Abkuerzungen erlaubt. Nach einem passenden File im Directory dir_name*/ +/* suchen und den Namen bei Bedarf ergaenzen. */ +/* */ +/* Rueckgabe: char * auf den Filenamen ohne Extention, wenn gefunden */ +/* NULL : kein passendes File gefunden */ +/* */ +/* 18/02/95 DL9HCJ Extention nicht zurueckgeben, damit mehr Platz in der*/ +/* Eingabezeile ist. */ +/* */ +/*----------------------------------------------------------------------*/ + + char *cli_save; + WORD cli_cnt; + struct ffblk file_block; + WORD i; + + cli_save = clipoi; + cli_cnt = clicnt; + strcpy(text_name, dir_name); + + i = 0; + while (isalnum(*clipoi) && (i < 8) && (clicnt > 0)) { + strncat(text_name, (char *) clipoi++, 1); + clicnt--; + i++; + } + + if (i == 0) return(NULL); + + if (i < 8) + strcat(text_name, "*"); + +/*****************************************************************************/ +/*** Da es beim MC68302-Betriebssystem keine Verzeichnisse gibt, unter- ***/ +/*** scheiden wir anhand der Dateiendung um was es sich hier handelt... ***/ +#ifdef MC68302 + if (dir_name == userexepath) + strcat(text_name, ".APU"); + else if (dir_name == sysopexepath) + strcat(text_name, ".APS"); + else + strcat(text_name, ".TXC"); +#endif +#if defined(__GO32__) || defined(__WIN32__) + if (dir_name == textcmdpath) + strcat(text_name, ".TXT"); + else + strcat(text_name, ".EXE"); +#endif +#ifdef ST + if (dir_name == textcmdpath) + strcat(text_name, ".TXT"); + else + strcat(text_name, ".TTP"); +#endif + if (xfindfirst(text_name, &file_block, 0) == 0) + { + strcpy(text_name, dir_name); + strcat(text_name, file_block.ff_name); + + return(text_name); + } + clipoi = cli_save; + clicnt = cli_cnt; + return(NULL); +} +/*----------------------------------------------------------------------*/ + + +/*----------------------------------------------------------------------*/ +BOOLEAN read_txt(void) { +/* */ +/* Das erste Wort *clipoi als Filenamen annehmen. Dabei sind */ +/* Abkuerzungen erlaubt. Nach einem passenden File im Directory "TEXT" */ +/* suchen und den Namen bei Bedarf ergaenzen. Das File lesen und an den */ +/* User userpo schicken. */ +/* */ +/* Rueckgabe: */ +/* TRUE: Fehler, File nicht gefunden. */ +/* FALSE: kein Fehler. */ +/* */ +/*----------------------------------------------------------------------*/ + + char file_path[128]; + + if (search_file(textcmdpath, file_path) != NULL) + { + ccpread(file_path); + return(FALSE); + } + return(TRUE); +} + + +/*----------------------------------------------------------------------*/ +BOOLEAN do_file(char *directory) { +/* */ +/* Sucht in Directory directory nach einem zu *clipoi passenden File */ +/* und fuehrt es bei Erfolg aus. Der Rest von clilin wird als Argument */ +/* uebergeben. */ +/* Wenn die auszufuehrende Kommandozeile nicht zu lang ist, dann wird */ +/* die Ausgabe auf ein File umgeleitet und an den User ueber ccpread */ +/* geschickt. */ +/* Als zusaetzliches Argument wird das User Call+SSID uebergeben */ +/* */ +/* Rueckgabe: TRUE : Fehler, kein File gefunden */ +/* FALSE: kein Fehler aufgetreten */ +/* */ +/*----------------------------------------------------------------------*/ + + /* Puffergroesse je nach OS */ +#if !defined(__LINUX__) && !defined(__WIN32__) +#define MAXCMDLINE 512 /* so wie bisher */ +#else +#define MAXCMDLINE MAXPATH /* Linux (mehr hat keinen Sinn, siehe unten) */ +#endif + char command_line[MAXCMDLINE]; + char call[10]; + char *tmpfile; +#ifdef __GO32__ + int i; +#endif + + if (search_file(directory, command_line) != NULL) + { + if (clicnt > 0) + { + /* Vorerst case abfangen -> nur Sonderzeichen */ + /* zusaetzlich noch das, was spaeter noch maximal angehaengt */ + /* werden kann (Call, Umleitung und temp. Datei) */ + if ( 2*(clicnt-1) + strlen(command_line) + 21 <= MAXCMDLINE) + strncat(command_line, (char *) clipoi, clicnt); + else + { + putmsg("Commandline too long..\r"); + return(FALSE); + } + } + +#ifdef __LINUX__ + security_check(command_line); +#else + command_line[strcspn(command_line,"<>|")] = NUL; +#endif + strcat(command_line, " "); + + tmpfile = tempnam(textpath, "do"); + if (tmpfile == NULL) return(FALSE); + call2str(call, usrcal); + strcat(command_line, call); /* Call anhaengen */ +#ifndef MC68302 + strcat(command_line, " > "); /* Ausgabe umleiten */ +#else + strcat(command_line, " "); +#endif + strcat(command_line, tmpfile); /* Zieldatei */ +#ifdef __LINUX__ + if (strlen(command_line) > 127) /* max. Laenge der Kommando- */ +#else + if (strlen(command_line) > MAXPATH) /* max. Laenge der Kommando- */ +#endif + { /* Zeile ist 127 bei DOSE */ +#ifdef SPEECH + putmsg(speech_message(278)); +#else + putmsg("Commandline too long..\r"); +#endif + free(tmpfile); + } + else + { + xchdir(textpath); + system(command_line); /* Ausgaben ins Temporaerfile */ +#ifdef __GO32__ + for (i = 0; i < MAXCOMS; i++) + clear_rs232(i); /* DOS schaltet IRQs ab??? */ +#endif + xchdir(NULL); +#ifdef MAKRO_FILE + /* Markiere, userpo->fp NICHT updaten. */ + userpo->read_ok = TRUE; +#endif + userpo->fname = tmpfile; + ccpread(tmpfile); + } + return(FALSE); /* Kommandoauswertung beenden */ + } + return(TRUE); +} + + +/*----------------------------------------------------------------------*/ +BOOLEAN extern_command(void) { +/* */ +/* Sucht in Directory "USEREXE" nach einem *clipoi passenden File */ +/* und fuehrt es bei Erfolg aus. Der Rest von clilin wird als Argument */ +/* uebergeben. Die Ausgabe wird auf EXTCMD.TMP umgeleitet und den User */ +/* ueber ccpread geschickt. */ +/* Als zusaetzliches Argument wird das User Call uebergeben */ +/* Falls der User Sysop Status hat, auch in "SYSEXE" nachsehen */ +/* */ +/* Rueckgabe: TRUE : Fehler, kein File gefunden */ +/* FALSE: kein Fehler aufgetreten */ +/* */ +/*----------------------------------------------------------------------*/ + + if (!do_file(userexepath)) + return(FALSE); + + if (issyso()) + return(do_file(sysopexepath)); + return(TRUE); + + } + +/*----------------------------------------------------------------------*/ +TRILLIAN intern_command(COMAND *tabelle) { +/* */ +/* Das erste Wort in clilin als Befehl annehmen und nach einem */ +/* passenden Befehl suchen und ihn bei Erfolg ausfuehren. */ +/* */ +/* Rueckgabe: ERRORS: Befehl mit Sonderzeichen */ +/* YES : Fehler, nichts gefunden */ +/* NO : kein Fehler, Befehl wurde ausgefuehrt. */ +/* */ +/*----------------------------------------------------------------------*/ + COMAND *cmdpoi; + const char *cmdnam; + char *command_line_save; + WORD command_length_save; + + command_line_save = clipoi; + command_length_save = clicnt; + for (cmdpoi = tabelle; + cmdpoi->cmdstr != 0; + ++cmdpoi) { + clipoi = command_line_save; + clicnt = command_length_save; + cmdnam = cmdpoi->cmdstr; + while ((clicnt != 0) && (*clipoi != ' ')) { + if ((char) toupper(*clipoi) != *cmdnam) + break; + ++clipoi; + --clicnt; + ++cmdnam; + } + if (clicnt == 0 || *clipoi == ' ') + break; + } + if (cmdpoi->cmdfun != NULL) { + skipsp(&clicnt, &clipoi); + (*cmdpoi->cmdfun)(cmdpoi->cmdpar); + return(NO); + } + clipoi = command_line_save; + clicnt = command_length_save; + while ((clicnt != 0) && (*clipoi != ' ')) + { + if (!isalnum(*clipoi)) + return(ERRORS); + ++clipoi; + --clicnt; + } + clipoi = command_line_save; + clicnt = command_length_save; + return(YES); +} + +/************************************************************************/ +/* Unbekanntes Kommando, Anzahl Fehler zaehlen */ +/*----------------------------------------------------------------------*/ +void inv_cmd(void) +{ + invmsg(); + if (g_ulink(userpo->uid) != hstubl) + if (++userpo->errcnt >= 5) + disusr(userpo->uid); +} + +/************************************************************************/ +/* Binaerfile einladen, Pruefsumme berechnen. */ +/*----------------------------------------------------------------------*/ +void program_load(MBHEAD *mhdp) +{ + MBHEAD *mbp; +#ifndef AUTOBINAERFIX + char c; +#else + UBYTE c; +#endif /* AUTOBINAERFIX */ + + while (mhdp->mbgc < mhdp->mbpc) { + c = getchr(mhdp) & 0xFF; + fputc(c, loadfp); + checksum += c; + crc = crctab[crc >> 8] ^ ((crc << 8) | (UWORD)c); + bytecnt--; + if (bytecnt == 0L) { + userpo->status = US_CCP; + fclose(loadfp); + mbp = getmbp(); +#ifndef MC68302 + if (xrename(loadtmp, loadname) == 0) +#endif + strcpy(loadtmp, loadname); +#ifndef AUTOBINAERFIX + putprintf(mbp,"%s ok. Checksum: %ld CRC: %u\r", loadtmp, checksum, crc); +#else + putprintf(mbp,"%s ok.\rChecksum: %ld CRC: %u\r", loadtmp, checksum, crc); +#endif /* AUTOBINAERFIX */ + prompt(mbp); + seteom(mbp); + checksum = 0L; + crc = 0; + loadname[0] = loadtmp[0] = NUL; + } + } +} + +/*----------------------------------------------------------------------*/ +/* Binaerfileuebertragung nach dem THP-AUTOBIN-Format starten. */ +/*----------------------------------------------------------------------*/ +void start_autobin(void) +{ + MBHEAD *mbp; + + if (strnicmp(clilin, "#BIN#", 5) == 0) + { + clipoi = clilin + 5; + clicnt -= 5; + + if ((bytecnt = nxtlong(&clicnt,&clipoi)) != 0L) + { + userpo->status = US_RBIN; + xremove(loadname); + mbp = getmbp(); + putstr("#OK#\r", mbp); + seteom(mbp); + return; + } + } + + fclose(loadfp); + loadname[0] = loadtmp[0] = NUL; + userpo->status = US_CCP; +} + +/*----------------------------------------------------------------------*/ +/* Text-Eingabe starten. Der Text wird zunaechst in die Datei TMP.TXT */ +/* geschrieben. Wird ein '.' als erstes Zeichen einer Zeile empfangen, */ +/* wird TMP.TXT umbenannt in den vom Sysop angegebenen Dateinamen. */ +/* Da nur ein temporaeres File TMP.TXT zur gleichen Zeit vorhanden */ +/* sein kann, darf bei mehreren eingelogten Sysops immer nur einer */ +/* Dateien editieren. */ +/*----------------------------------------------------------------------*/ +void load_text(void) +{ + MBHEAD *mbp; + + *clipoi = NUL; + clipoi = clilin; + if (*clipoi == '.' || *clipoi == 0x1A) { + userpo->status = US_CCP; + fclose(loadfp); + mbp = getmbp(); +#ifndef MC68302 +#ifdef __WIN32__ + remove(loadname); +#endif + if (xrename(loadtmp, loadname) == 0) +#endif + strcpy(loadtmp, loadname); + putprintf(mbp, "%s ok!\r", loadtmp); + prompt(mbp); + seteom(mbp); + loadname[0] = loadtmp[0] = NUL; + } + else { + fputs(clilin, loadfp); + fputc('\n', loadfp); + } +} + +/************************************************************************/ +/* Vom User eingegebene Zeichen mit aktuellem Passwort vergleichen und */ +/* bei korrekter Eingabe SYSOP-Flag setzen. In jedem Fall den Versuch */ +/* in die Datei SYSOP-PRO aufnehmen. */ +/*----------------------------------------------------------------------*/ +void get_password(void) +{ + WORD i; + char file[128]; + FILE *fp; + char pwd[6]; /* ala BayBox DL1XAO */ + + memcpy(pwd, userpo->paswrd, 5); + pwd[5] = NUL; + i = FALSE; + if (strlen((char *)clipoi) > 80) /* maximal 80 Zeichen */ + *(clipoi + 80) = NUL; + if (clicnt >= 5 && strstr((char *)clipoi, pwd) != NULL) { + userpo->errcnt = 0; + i = TRUE; +#ifndef USER_PASSWORD + userpo->sysflg = 1; +#else + if (userpo->status == US_WPWD) + userpo->sysflg = 1; + userpo->pwdtyp = PW_USER; +#endif + } + else + if (++userpo->errcnt >= 5) + { + disusr(userpo->uid); + return; + } + + /* Wenn SYSOP-Protokoll gefuehrt werden soll, Rufzeichen, Datum, */ + /* Zeit und ob SYSOP-Befehl erfolgreich in eine Datei mit Namen */ + /* SYSOP.PRO schreiben. Diese Datei kann spaeter vom SYSOP */ + /* ausgelesen und ausgewertet werden. */ + +#ifndef USER_PASSWORD + if (syspro_flag == TRUE) +#else + if (syspro_flag == TRUE && userpo->status == US_WPWD) +#endif + { + strcpy(file, confpath); + strcat(file, "SYSOP.PRO"); + if ((fp = xfopen(file,"at")) != NULL) { + fprintf(fp, "%24.24s %6.6s: %s\n", + ctime(&sys_time), + calofs(UPLINK, userpo->uid), + i ? "accepted" : "rejected"); + fclose(fp); + } + } + userpo->status = US_CCP; +} + +/* + * CTEXT mit mehr Moeglichkeiten (wie prompt) + */ +void out_ctext(char *name, MBHEAD *mbp) +{ + FILE *fp; + char line[128]; + char *c; + + if ((fp = xfopen(name, "rt")) != NULL) + { + while (fgets(line, 126, fp) != NULL) + { + if ((c = strchr(line, '\n')) != NULL) + *c = CR; + prompt2str(mbp, line); + } + fclose(fp); + } +} + +/* + * Einstiegsport des User feststellen fuer LOOP-Warning + */ +int userport(USRBLK *u) +{ + CIRBLK *cirp; + LNKBLK *lnkp; +#ifdef L1TCPIP + TCPIP *tpoi; +#endif /* L1TCPIP */ + PEER *pp; + + /* Einstiegsport des Users feststellen (fuer LOOP-Warning) */ + switch (g_utyp(u->uid)) { + case L4_USER: /* User ist Circuit */ + cirp = (CIRBLK *) g_ulink(u->uid); + if (find_best_qual(find_node_this_ssid(cirp->l3node), &pp, DG) > 0) + return(pp->l2link->port); + break; + + case L2_USER: /* User ist L2-Link */ + lnkp = (LNKBLK *) g_ulink(u->uid); + return(lnkp->liport); + +#ifdef L1TCPIP + case TCP_USER: /* User ist TCPIP */ + tpoi = (TCPIP *) g_ulink(u->uid); + return(tpoi->port); +#endif /* L1TCPIP */ + } + return(L2PNUM); /* Defaultport */ +} + +/* + * Manche Befehle erhalten die Anwort erst ein bischen spaeter (PING, + * DEST, NRR usw), deshalb mit besonderer Vorsicht ausgeben. + */ +void send_async_response(USRBLK *ublk, const char *title, const char *text) { + MBHEAD *mbp; + USRBLK *up; + LHEAD mbhd; + + /* Antwort generieren und an den User senden */ + for (up = (USRBLK *) usccpl.head; + (USRBLK *) &usccpl != up; + up = (USRBLK *) up->unext) + { + if (up == ublk) + /* das ist der gesuchte User, darf er die Antwort bekommen? */ + if ((up->status == US_CCP || up->status == US_TALK)) + { + (mbp = (MBHEAD *)allocb(ALLOC_MBHEAD))->l2fflg = L2CPID; /* tnx DB2OS */ + putchr('\r', mbp); + putalt(alias, mbp); + putid(myid, mbp); + putprintf(mbp, "> %s%s\r", title, text); + rwndmb(mbp); + inithd(&mbhd); + relink((LEHEAD *)mbp, (LEHEAD *)mbhd.tail); + if (!itousr(up->uid, NO_UID, FALSE, mbp)) + dealmb(mbp); + } + } +} + +/************************************************************************/ +/* Parameternummer aus Namen ermitteln */ +/*----------------------------------------------------------------------*/ +static UWORD getparnum(PARAM *partab, int len) +{ + size_t l; + UWORD num; + PARAM *p; + + for (p = partab, num = 1; num <= len; p++, num++) + if (p->paradr) { + l = strlen(p->parstr); + if (!strnicmp(p->parstr, clipoi, l)) { + clipoi += l; + clicnt -= (WORD)l; + return(num); + } + } + return(0); +} + +/* Interpreter fuer einfache Parametertabellen. + */ +void ccp_par(const char *name, PARAM *partab, int len) +{ + int i; + UWORD parnum; + MBHEAD *mbp; + PARAM *parpoi; + UWORD nummer; + UWORD wert; + + nummer = 0; + if (issyso()) + { + if (!isdigit(*clipoi)) + nummer = getparnum(partab, len); + else + nummer = nxtnum(&clicnt, &clipoi); + } + + if (nummer != 0 && nummer <= len) + { + parpoi = partab + nummer-1; + if ( clicnt != 0 + && ((wert = nxtnum(&clicnt, &clipoi)) >= parpoi->minimal) + && (wert <= parpoi->maximal) + ) + *(parpoi->paradr) = wert; + mbp = putals(name); + putprintf(mbp, "%u: %s = %u (%u...%u)\r", nummer, parpoi->parstr, + *(parpoi->paradr), parpoi->minimal, parpoi->maximal); + } else { + mbp = putals(name); + + mbp->l4time = mbp->mbpc; + for (i = 0, parnum = 1, parpoi = partab; + parnum <= len; ++i, ++parnum, ++parpoi) + { + if (i >= 3) { + putchr('\r', mbp); + mbp->l4time = mbp->mbpc; + i = 0; + } else +#ifdef __WIN32__ + putspa((char)(25 * i), mbp); +#else + putspa(25 * i, mbp); +#endif /* WIN32 */ + putprintf(mbp, "%02u:%-12s %5u", parnum, parpoi->parstr, *(parpoi->paradr)); + } + putchr('\r', mbp); + } + prompt(mbp); + seteom(mbp); +} + +/* Rufzeichen eintragen/Austragen. + */ +void ccp_call(char *id) +{ + if (!issyso()) + invmsg(); + + if (*clipoi == '-') /* Call austragen? */ + { + id[0] = NUL; + putmsg("ok\r"); + } + else + if (getcal(&clicnt, &clipoi, TRUE, id) != YES) { /* ein Call ? */ +#ifdef SPEECH + putmsg(speech_message(167)); +#else + putmsg("Invalid call\r"); +#endif + } else { + MBHEAD *mbp = getmbp(); + prompt(mbp); + seteom(mbp); + } +} + +/* Fuer den L4 feststellen, wie gross fragmentierte Frames sein duerfen */ + +int +ptc_p_max(void *link, UBYTE typ) +{ + UID p_uid; + + p_uid = (ptctab + g_uid(link, typ))->p_uid; + if (p_uid == NO_UID) return(256); + if (g_utyp(p_uid) == L4_USER) + return(236); + return(256); +} + +#ifdef MAKRO_USER +/* Wir zaehlen alle Interlinks und */ +/* Convers-Host's die aktiv sind. */ +static UWORD Interlinks_zaehlen(void) +{ + PEER *pp; + PERMLINK *p; + int i; + int max_peers = netp->max_peers; + UWORD interlinks = 0; + + /* Interlinks zaehlen ausser */ + /* LOCAL ,LOCAL_N, LOCAL_V. */ + for (i = 0, pp = netp->peertab; i < max_peers; i++, pp++) + { + /* Nur benutzte eintraege. */ + if (pp->used) + { + /* Rufzeichen? */ + if (pp->l2link->call) + { + /* Pruefe ob das Rufzeichen ein LOCAL ist. */ + if (pp->typ >= LOCAL) + continue; + + /* Ist der PEER aktiv? */ + if (pp->nbrl2l == NULL) + /* Nein! */ + continue; + + /* Kein LOCAL/N/V und aktiv.*/ + interlinks++; + } /* kein Rufzeichen gefunden. */ + } /* freier eintrag. */ + } + + /* Zaehlen der Convers-Host's. */ + for (i = 0; i < MAXCVSHOST; i++) + { + p = permarray[i]; + /* Nur eingetragene Host's zaehlen. */ + if (p != NULL) + { + /* Ist der Host aktiv? */ + if (p->connection) + /* Dann wird gezaehlt. */ + interlinks++; + + /* Host ist nicht aktiv. */ + continue; + } + + /* Kein Host gefunden. */ + /* Weiter suchen. */ + break; + } + + /* Gesamtanzahl der Interlinks und Convers-Host's. */ + return(interlinks); +} +#endif + +#ifdef CONNECTTIME +/*************************************************************************/ +/* */ +/* Connect-Zeit in Flexnet-Stil ausgeben. */ +/* 1 CB0RIE CB1GLA IXF 0 0 0 13 136 138 96 13h,21m - */ +/* ======= */ +/*************************************************************************/ +char *ConnectTime(unsigned long contime) +{ + static char runtime[8 + 1]; + char *time = runtime; + register int zeit; + unsigned long sec, + min, + std; + + zeit = contime; + sec = zeit % 60L; zeit /= 60L; + min = zeit % 60L; zeit /= 60L; + std = zeit % 24L; zeit /= 24L; + + if (zeit > 0) + sprintf(time, "%2dd,%2luh",zeit, std); /* Tage, Stunden. */ + else + if (std > 0) + sprintf(time, "%2luh,%2lum",std, min); /* Stunden, Minuten. */ + else + if (min > 0) + sprintf(time, "%2lum,%2lus", min, sec); /* Minuten, Sekunden. */ + else + { + if (sec > 0) + sprintf(time, " %2lus", sec); /* Ausgabe in Sekunden. */ + else + sprintf(time, " "); + } + + return(time); +} +#endif /* CONNECTTIME */ + +/* Ende src/l7utils.c */ diff --git a/src/main.c b/src/main.c new file mode 100755 index 0000000..67a8a8d --- /dev/null +++ b/src/main.c @@ -0,0 +1,600 @@ +/************************************************************************/ +/* */ +/* ***** ***** */ +/* ***** ***** */ +/* ***** ***** */ +/* ***** ***** */ +/* *************** *************** */ +/* ***************** ***************** */ +/* *************** *************** */ +/* ***** ***** TheNetNode */ +/* ***** ***** Portable */ +/* ***** ***** Network */ +/* ***** ***** Software */ +/* */ +/* File src/main.c (maintained by: ???) */ +/* */ +/* This file is part of "TheNetNode" - Software Package */ +/* */ +/* Copyright (C) 1998 - 2008 NORD> + +#ifdef __GO32__ +#define ptrdiff_t int +#endif + +extern int console_login_status; + +static void initvar(void); +static void main_loop(void); +static void mainf(void); +#ifdef SETPATH +static void SetPath(void); +#endif /* SETPATH */ + +static void initvar(void) +{ + int port, i; + PORTINFO *p; + BEACON *b; + + memset(mh, 0, sizeof(STAT)*MAXSTAT); + + memset(portstat, 0, sizeof(PORTSTAT)*L2PNUM); + + for (port = 0, p = &portpar[0], b = &beacon[0]; + port < L2PNUM; + port++, p++, b++) + { + sprintf(p->name, "Port%u", port); /* Portnamen eintragen */ + + p->mtu = 256; + + p->l1mode = + p->l2mode = 0; + p->l1_tx_timer = 0; + p->txdelay = 25; + p->persistance = 128; + p->slottime = 10; +#ifdef PORT_MANUELL + p->paclen = 128; + p->IRTT = 200; + p->T2 = 10; + p->T3 = 18000; +#else + p->IRTT = 500; + p->T2 = 150; +#endif /* PORT_MANUELL */ + +#ifdef IPOLL_FRAME + p->ipoll_paclen = 128; + p->ipoll_retry = 3; +#endif /* IPOLL_FRAME */ + +#ifdef PORT_L2_CONNECT_TIME + p->l2_connect_time = 120; +#endif +#ifdef PORT_L2_CONNECT_RETRY + p->l2_connect_retry = 3; +#endif + +#ifdef AUTOROUTING + p->poAuto = L_NOROUTE; +#endif /* AUTOROUTING */ + +#ifdef THENETMOD + p->broadcast = broint_ui; /* Timer fuer Broadcast-Nodes Bake. */ +#endif /* THENETMOD */ + + p->maxframe = 2; +#ifdef EAX25 + p->maxframe_eax = 16; /* Standard: Maxframe 16 */ + p->eax_behaviour = 1; /* Mode nach MHEARD */ +#endif + p->retry = 15; + +#ifdef SETTAILTIME +#ifdef MC68302 + p->tailtime = TAILTIME*10; +#else + p->tailtime = TAILTIME; +#endif +#endif + +#ifdef EXPERTPARAMETER + p->l2autoparam = ~0L; +#endif + + p->nmblks = + p->nmbstn = 0; + +#ifdef DAMASLAVE + p->damaok = 0; + p->sendok = 0; +#endif + +#ifdef USERMAXCON + p->maxcon = 0; +#endif + +#ifdef PACSAT + pacsat_enabled[port] = FALSE; +#endif + cpyid(b->beades, "QST \140"); + b->beadil[0] = b->text[0] = NUL; + b->interval = b->beatim = b->telemetrie = 0; + } + + for (i = 0; i < MAXSUSPEND; i++) + *sustab[i].call = NUL; + +#ifdef GRAPH + graphclear(); +#endif +} + + +void memerr(void) { + hputs("*** ERROR: Not enough Memory!\n"); + exit(10); +} + +int main(int argc, char *argv[]) +{ +#if defined(__GO32__) + static char *line; + char drive[MAXDRIVE]; + char path[MAXDIR]; + char name[MAXFILE]; + char ext[MAXEXT]; +#endif + +#ifdef __WIN32__ + SetConsoleCtrlHandler( (PHANDLER_ROUTINE) CtrlHandler, TRUE ); +#endif + /* Hardwarespezifische Sachen (Uhr nachstellen, UTC ins Enviroment, */ + /* Kommandozeile auswerten steht jetzt in init_hardware(). */ + + if (init_hardware(argc, argv)) /* Hardwarespezifische Sachen */ + exit(1); + + time(&start_time); /* Startzeit merken */ + clear_time = start_time; + + /**********************************************************************/ + /* Speicher besorgen */ + /**********************************************************************/ + + VMSG("--- Allocating mem for LinkTable ...\n"); + lnktbl = (LNKBLK *) malloc (sizeof(LNKBLK) * (LINKNMBR )); + VMSG("--- Allocating mem for CircuitTable ...\n"); + cirtab = (CIRBLK *) malloc (sizeof(CIRBLK) * (NUMCIR )); + VMSG("--- Allocating mem for PatchcordTable ...\n"); + ptctab = (PTCENT *) malloc (sizeof(PTCENT) * (NUMPAT )); + VMSG("--- Allocating mem for HostTable ...\n"); + hstubl = (HOSTUS *) malloc (sizeof(HOSTUS) * (MAXHST )); +#ifdef L1TCPIP + VMSG("--- Allocating mem for TcpipTable ...\n"); + tcptbl = (TCPIP *) malloc (sizeof(TCPIP) * (MAXTCPIP )); +#endif /* L1TCPIP */ + + if (lnktbl == NULL || + cirtab == NULL || + ptctab == NULL || +#ifdef L1TCPIP + tcptbl == NULL || +#endif /* L1TCPIP */ + hstubl == NULL + ) memerr(); + + VMSG("--- Initializing variables ...\n"); + initvar(); /* Variablen Initialisieren */ + + /**********************************************************************/ + /* Configuration laden */ + /**********************************************************************/ + *confpath = NUL; +#if defined(__GO32__) + fnsplit(argv[0],drive,path,name,ext); /* Pfad zu TNN.EXE ermitteln, */ + strcpy(confpath,drive); /* dort auch die .cfg Dateien! */ + strcat(confpath,path); + strcpy(exename, argv[0]); /* Name der EXE merken */ + normfname(exename); /* normieren */ +#endif + + /* wird aus dem aktuellen Verzeichniss gestartet, dann ist das der */ + /* ConfPath (Dose gibt "" zurueck !) */ +#ifndef MC68302 /* DL1HAZ 01.02.95 */ + if (*confpath == NUL) /* sonst wie Atari */ + getcwd(confpath,MAXPATH); /* Aktuelles Verzeichnis, Suchpfad */ + addslash(confpath); +#endif + + if (load_configuration() == FALSE) /* Configuration laden */ + hprintf("*** WARNING: Error reading %s.PAS ***\n",cfgfile); + if (load_stat() == FALSE) /* Statistik laden */ + hprintf("*** WARNING: Error reading %s.STA ***\n",cfgfile); +#ifdef GRAPH + if (load_graph() == FALSE) /* Graphen laden */ + hprintf("*** WARNING: Error reading GRAPH.STA ***\n"); + graph.enabled = FALSE; /* wird erst nach einer Minute */ + /* auf TRUE gesetzt */ +#endif + +#ifdef SETPATH + SetPath(); +#endif /* WIN32 */ + +#ifdef MC68302 + strcpy(confpath, textpath); + strcpy(msgpath, textpath); +#else + + xchdir(textpath); /* Aktuelles Laufwerk und Pfad */ +#if defined(__GO32__) + line = malloc(MAXPATH); /* Pfad zu den Konfigurations- */ + strcpy(line,"CONFPATH="); /* dateien */ + strcat(line,confpath); + if (putenv(line) == -1) + printf("*** WARNING: Enviroment full ***\n"); + line = malloc(MAXPATH); /* Temporaerpfad umleiten */ + strcpy(line,"TMP="); + strcat(line,textpath); + if (putenv(line) == -1) + printf("*** WARNING: Enviroment full ***\n"); +#ifdef __GO32__ + line = malloc(MAXPATH); /* Temporaerpfad umleiten */ + strcpy(line,"TMPDIR="); + strcat(line,textpath); + if (putenv(line) == -1) + printf("*** WARNING: Enviroment full ***\n"); +#endif +#endif + if (getenv("MSGPATH") == NULL) { +#if defined(__GO32__) + line = malloc(MAXPATH); + strcpy(line,"MSGPATH="); /* MSGPATH auf TEXTPATH setzten */ + strcat(line,textpath); + if (putenv(line) == -1) + printf("*** WARNING: Enviroment full ***\n"); +#endif +#if defined(__WIN32__) + strcpy(msgpath, textpath); /* MSGPATH auf TEXTPATH setzten */ + strcat(msgpath, "msg"); + addslash(msgpath); +#endif /* WIN32 */ + } + else + { + strcpy(msgpath, getenv("MSGPATH")); + addslash(msgpath); + } + +#endif + +#ifndef MC68302 + init_rs232(); /* Schnittstellen */ + init_host(); /* Host-Schnittstelle */ + init_timer(); /* Timer initialisieren */ +#else + init_host(); /* Host-Schnittstelle */ + init_timer(); /* Timer initialisieren */ + mem_init(); +#endif + + /**********************************************************************/ + /* Software initialisieren */ + /**********************************************************************/ + + VMSG("--- Initializing Level 1 ...\n"); + l1init(); /* Level 1 initialisieren */ + VMSG("--- Initializing Level 2 ...\n"); + l2init(); /* L2 */ + VMSG("--- Initializing Level 3 ...\n"); + l3init(); /* L3 */ + VMSG("--- Initializing Level 4 ...\n"); + initl4(); /* L4 */ + VMSG("--- Initializing Level 7 ...\n"); + initl7(); /* L7 */ +#ifdef PACSAT + VMSG("--- Initializing PACSAT ...\n"); + pacsat_init(); /* PACSAT-Broadcast */ +#endif +#ifdef IPROUTE + VMSG("--- Initializing IP-router ...\n"); + ipinit(); /* IP-Router initialisieren */ +#endif +#ifdef L1TCPIP + VMSG("--- Initializing L1TCPIP ...\n"); + InitTCP(); /* TCPIP Initialisieren. */ +#endif /* L1TCPIP */ + VMSG("--- Initializing MHeard ...\n"); + init_mh(); /* MHEARD Liste laden */ +#ifdef SPEECH + speech_init(); /* Sprache initialisieren */ +#endif + + VMSG("*** Entering main loop ...\n"); + mainf(); /* ab in die Hauptschleife */ + + return(0); /* hierhin kommen wir niemals! */ +} + +#ifdef ST +char *wowarich; +#endif + +/************************************************************************/ +/* die Hauptschleife ---*/ +/*----------------------------------------------------------------------*/ +static void main_loop(void) +{ + prof_start(PROF_SUM); + + PROFILE(PROF_L2,"l2",l2); + PROFILE(PROF_L3RX,"l3rx",l3rx); + PROFILE(PROF_L7RX,"l7rx",l7rx); + PROFILE(PROF_TIM,"timsrv",timsrv); +#ifdef PACSAT + PROFILE(PROF_PAC,"pacsrv",pacsrv); +#endif +#ifdef IPROUTE + PROFILE(PROF_IP,"ipserv",ipserv); +#endif +#ifdef TCP_STACK + PROFILE(PROF_STACK,"StackSRV",StackSRV); +#endif /* TCP_STACK */ +#ifdef L1TCPIP + PROFILE(PROF_TCPIP,"TcpipSRV",TcpipSRV); +#endif /* L1TCPIP */ + PROFILE(PROF_L4,"l4rest",l4rest); + PROFILE(PROF_L3,"l3rest",l3rest); + PROFILE(PROF_L7TX,"l7tx",l7tx); + PROFILE(PROF_L4TX,"l4tx",l4tx); + PROFILE(PROF_L3TX,"l3tx",l3tx); + PROFILE(PROF_L1,"l1rxtx",l1rxtx); + prof_stop(PROF_SUM); + +#ifndef MC68K + PROFILE(PROF_UPD,"timer",update_timer); +#endif +} + +/************************************************************************/ +/* das Programm persoenlich... ---*/ +/*----------------------------------------------------------------------*/ +static void mainf(void) +{ +#ifdef ST + ULONG t; +#endif + + hputs(signon); + hputid(myid); + hprintf(")\r" + "Copyright by NORD> tic10) /* zusaetzliche 5s Ruhe fuer den Tokenring */ + { + l1rxtx(); + hostsv(); + hostim(); + l7rx(); + l7tx(); + dealml((LEHEAD*)&rxfl); + } +#endif + +#ifdef AXIPR_UDP + /* Sperre zuruecksetzen. */ + LookAX25IP = FALSE; +#endif /* AXIPR_UDP */ + VMSG("*** All done. Here we go ...\n\n"); + + hputs("password: "); + +/* Die Start-TNB wurde geladen, jetzt koennen wir anfangen */ + LOOP + main_loop(); +} + +/************************************************************************/ +/* Programm Ende, aufraeumen */ +/************************************************************************/ +void quit_program(int exit_code) +{ +#ifdef SPEECH + printf(speech_message(280)); +#else + printf("Programm wird beendet!\n"); +#endif + if ( console_login_status + || exit_code == -1 +#ifdef ST + || exit_code == 2 +#endif + ) { + exit_mh(); /* MH-Liste sichern */ + save_stat(); +#ifdef GRAPH + save_graph(); +#endif +#ifndef MC68302 /*hier nur noch auf Anforderung */ +#ifndef DEBUG + if (nmbfre >= 600) /* nur wenn genug Buffer da ! */ + save_parms(); /* Braucht 500 Buffer! */ +#endif + personalmanager(SAVE,NULL,NULL); /* Pers. Daten fuer Convers */ +#ifdef USERPROFIL + SaveProfil(); +#endif /* USERPROFIL */ + exit_timer(); /* Timer in Ursprungszustand */ + l1exit(); /* L1 zuruecksetzen! */ + exit_hardware(); /* Andere Hardware in Ursprungs.*/ + exit_host(); /* Console schliessen */ +#else + personalmanager(SAVE,NULL,NULL); /* Pers. Daten fuer Convers */ + exit_hardware(); /* Andere Hardware in Ursprungs.*/ +#endif + +#ifdef ALIASCMD + /* Aliasliste loeschen */ + clean_aliaslist(); +#endif + + /* Netzwerk deregistieren */ + unregister_network(); + + /* Speicher freigeben */ + free (lnktbl); + free (cirtab); + free (ptctab); + free (hstubl); +#ifdef L1TCPIP + free (tcptbl); +#endif /* L1TCPIP */ + + /* und tschuess.... */ + exit(exit_code); + } +} + +#ifdef SETPATH +/* System Pfade setzen. */ +static void SetPath(void) + { +#ifdef __LINUX__ + mode_t mode = 0775; +#endif /* LINUX */ +#ifdef __GO32__ + mode_t mode = S_IWUSR; +#endif /* GO32 */ + + strcpy(textpath, confpath); /* TEXTPATH setzen */ + strcpy(textcmdpath, confpath); /* TEXTCMDPATH setzen */ + strcat(textcmdpath, "textcmd"); + addslash(textcmdpath); +#if defined(__LINUX__) || defined(__GO32__) + mkdir(textcmdpath, mode); /* Verzeichnis textcmd erstellen */ +#else + mkdir(textcmdpath); /* Verzeichnis textcmd erstellen */ +#endif /* LINUX / GO32 */ + + strcpy(userexepath, textpath); /* USEREXEPATH setzen */ + strcat(userexepath, "userexe"); + addslash(userexepath); +#if defined(__LINUX__) || defined(__GO32__) + mkdir(userexepath, mode); /* Verzeichnis USEREXE erstllen */ +#else + mkdir(userexepath); /* Verzeichnis USEREXE erstllen */ +#endif /* LINUX / GO32 */ + + strcpy(sysopexepath, textpath);/* SYSOEXEPATH setzen */ + strcat(sysopexepath, "sysexe"); + addslash(sysopexepath); +#if defined(__LINUX__) || defined(__GO32__) + mkdir(sysopexepath, mode); /* Verzeichnis SYSEXE erstllen */ +#else + mkdir(sysopexepath); /* Verzeichnis SYSEXE erstllen */ +#endif /* LINUX / GO32 */ + + strcpy(msgpath, textpath); /* MSGPATH setzen */ + strcat(msgpath, "msg"); + addslash(msgpath); +#if defined(__LINUX__) || defined(__GO32__) + mkdir(msgpath, mode); /* Verzeichnis MSG erstllen */ +#else + mkdir(msgpath); /* Verzeichnis MSG erstllen */ +#endif /* LINUX / GO32 */ + +#ifdef PACSAT + strcpy(pacsatpath, textpath); /* PACSATPATH setzen */ + strcat(pacsatpath, "pacsat"); + addslash(pacsatpath); +#if defined(__LINUX__) || defined(__GO32__) + mkdir(pacsatpath, mode); /* Verzeichnis PACSAT erstllen */ +#else + mkdir(pacsatpath); /* Verzeichnis PACSAT erstllen */ +#endif /* LINUX / GO32 */ +#endif /* PACSAT */ + +#ifdef SPEECH + strcpy(speechpath, textpath); /* SPEECHPATH setzen */ + strcat(speechpath, "speech"); + addslash(speechpath); +#if defined(__LINUX__) || defined(__GO32__) + mkdir(speechpath, mode); /* Verzeichnis SPEECH erstllen */ +#else + mkdir(speechpath); /* Verzeichnis SPEECH erstllen */ +#endif /* LINUX / GO32 */ +#endif /* SPEECH */ +} +#endif /* SETPATH */ + +/* End of src/main.c */ diff --git a/src/mh.c b/src/mh.c new file mode 100755 index 0000000..f83593e --- /dev/null +++ b/src/mh.c @@ -0,0 +1,846 @@ +/************************************************************************/ +/* */ +/* ***** ***** */ +/* ***** ***** */ +/* ***** ***** */ +/* ***** ***** */ +/* *************** *************** */ +/* ***************** ***************** */ +/* *************** *************** */ +/* ***** ***** TheNetNode */ +/* ***** ***** Portable */ +/* ***** ***** Network */ +/* ***** ***** Software */ +/* */ +/* File src/mh.c (maintained by: ???) */ +/* */ +/* This file is part of "TheNetNode" - Software Package */ +/* */ +/* Copyright (C) 1998 - 2008 NORD>name); + if ((fp = xfopen(file, "rt")) != NULL) + { + while (fgets(file, 120, fp) != NULL) + { + if (*file == ':') + { + sscanf(file + 1, "%ld", (long *) &mh->mhstart); + continue; + } + mhp = (MHEARD *)allocb(ALLOC_MHEARD); + ptr = file; + cnt = strlen(ptr) - 1; /* \n uebersehen */ + mhp->heard = nxtlong(&cnt, &ptr); + mhp->rx_bytes = nxtlong(&cnt, &ptr); + mhp->tx_bytes = nxtlong(&cnt, &ptr); + mhp->port = nxtnum(&cnt, &ptr); + mhp->damawarn = nxtnum(&cnt, &ptr); + mhp->rx_rej = nxtlong(&cnt, &ptr); + mhp->tx_rej = nxtlong(&cnt, &ptr); +#ifdef EAX25 + /* Standardmaessig kein EAX.25 */ + mhp->eax_link = FALSE; +#endif +#ifdef MH_LISTE + mhp->flag = nxtnum(&cnt, &ptr); +#endif + if (getcal(&cnt, &ptr, TRUE, mhp->id) == YES) + { + mh->act++; + relink((LEHEAD *)mhp, (LEHEAD *)(mh->heardl.tail)); + continue; + } + else + dealoc((MBHEAD *)mhp); + } + fclose(fp); + return(TRUE); + } + return(FALSE); +} + +/*----------------------------------------------------------------------*/ + +/* + * MHEARD-Liste abspeichern + */ + +static void +save_table(char *path, MHTAB *mh) +{ + FILE *fp; + MHEARD huge *mhp; + char file[128]; /* Puffer fuer Filenamen */ + char call[12]; + + strcpy(file, path); + strcat(file, mh->name); + if ((fp = xfopen(file, "wt")) != NULL) + { + for (mhp = (MHEARD *)mh->heardl.head; + mhp != ((MHEARD huge *)&(mh->heardl)); + mhp = mhp->next) + { + call2str(call, mhp->id); + fprintf(fp, "%lu %lu %lu %u %u %lu %lu" +#ifdef MH_LISTE + " %u" +#endif + " %s\n" + ,(long)mhp->heard, mhp->rx_bytes, mhp->tx_bytes + ,mhp->port, mhp->damawarn, mhp->rx_rej, mhp->tx_rej +#ifdef MH_LISTE + ,mhp->flag +#endif + ,call); + } + + fprintf(fp, ":%ld\n", (long) mh->mhstart); + fclose(fp); + } +} + +/*----------------------------------------------------------------------*/ +void save_mh(void) +{ +#ifdef ST + char *mcp; +#endif + + save_table(confpath, &l2heard); +#ifdef ST + if ((mcp = getenv("MHTOPPATH")) != NULL) + save_table(mcp, &l2heard); +#endif + + save_table(confpath, &l3heard); +} + +/*----------------------------------------------------------------------*/ +MHEARD *mh_lookup(MHTAB *mh, char *id) +{ + MHEARD *mhp; + LHEAD *heardl = &mh->heardl; + + for (mhp = (MHEARD *)heardl->tail; + mhp != (MHEARD *)heardl; + mhp = mhp->prev) + if (cmpid(id, mhp->id)) + return(mhp); + return(NULL); +} + +/*----------------------------------------------------------------------*/ +/* Call auf dem richtigen Port suchen */ +#ifdef MH_LISTE +MHEARD *mh_lookup_port(MHTAB *mh, char *id, UWORD port, int txrx) +#else +MHEARD *mh_lookup_port(MHTAB *mh, char *id, UWORD port) +#endif +{ + MHEARD *mhp; + LHEAD *heardl = &mh->heardl; + + for (mhp = (MHEARD *)heardl->tail; + mhp != (MHEARD *)heardl; + mhp = mhp->prev) +#ifdef MH_LISTE + { + /* TX-FRAME */ + if (txrx == TRUE) + { +#endif + if (cmpid(id, mhp->id) && port == mhp->port) + return(mhp); +#ifdef MH_LISTE + } + /* RX-FRAME */ + else + { + /* Rufzeichen gefunden? */ + if (cmpid(id, mhp->id)) + { + /* auf dem gleichen Port? */ + if (port == mhp->port) + /* Rufzeichen und Port */ + /* stimmen ueber ein. */ + return(mhp); + else + /* Markiere Rufzeichen, */ + /* keine Anzeige unter MH. */ + mhp->flag = FALSE; + } + } + } + #endif + return(NULL); +} + +/*----------------------------------------------------------------------*/ +void mh_update(MHTAB *mh, MHEARD *mhp, char *id, UWORD port) +{ + mhp->heard = sys_time; + cpyid(mhp->id, id); + mhp->via[0] = NUL; + mhp->port = port; +#ifdef MH_LISTE + mhp->flag = TRUE; +#endif + ulink((LEHEAD *)mhp); + relink((LEHEAD *)mhp, (LEHEAD *)(mh->heardl.tail)); +} + +/*----------------------------------------------------------------------*/ +void mh_clear(MHEARD *mhp) +{ + mhp->tx_bytes = + mhp->rx_bytes = + mhp->tx_rej = + mhp->rx_rej = 0L; + mhp->damawarn = 0; +#ifdef MHEAX_LINKFIX + mhp->eax_link = FALSE; +#endif /* MHEAX_LINKFIX */ +} + +/*----------------------------------------------------------------------*/ +MHEARD *mh_add(MHTAB *mh) +{ + MHEARD *mhp; + + if (mh->max == 0) return(NULL); + while (mh->act >= mh->max) { + dealoc((MBHEAD *)ulink((LEHEAD *)mh->heardl.head)); + mh->act--; + } + relink((LEHEAD *)(mhp = ((MHEARD *)allocb(ALLOC_MHEARD))), + (LEHEAD *)(mh->heardl.head)); + mh->act++; + mh_clear(mhp); + return(mhp); +} + +static void +ccp_mh(MHTAB *mh) +{ +#ifndef MH_LISTE + MHEARD *prevmhp; +#endif + MHEARD *mhp; + char call[L2IDLEN]; + char *cpoisa = NUL; + WORD ccntsa = FALSE; + WORD num = 10; + WORD i; + WORD n; + WORD what = 0; + char mask[MAXMASK]; + WORD comp(const void *, const void *); + char tmp1[10]; + char tmp2[10]; + char buffer[100], *bp; + FILE *fp; + char *tmpfile; + struct tm *ts; + BOOLEAN show_counter = FALSE; +#ifdef MH_LISTE + char _rx_bytes[7]; + char _tx_bytes[7]; +#define _TNN 0 +#define _FLEXNET 1 + WORD show_mode; + ULONG d, h, m, s; /* Tag, Stunde, Minute, Sekunde */ + WORD j = 0; /* Zaehler fuer Flexnet */ + WORD uport = FALSE; /* einzelne Portausgabe */ +#endif + /* parameter auswerten */ + +#ifdef MH_LISTE + if (MHdefault) /* Welche MH-Liste ist zur auswahl ? */ + show_mode = _FLEXNET; /* ist das etwa FLEXNET ? */ + else /* oder doch */ + show_mode = _TNN; /* unser altes TNN (HI) */ +#endif + + /* Parameter auswerten */ + if (clicnt) + { + cpoisa = clipoi; + ccntsa = clicnt; + do + { + if (*cpoisa == '+') + { + show_counter = TRUE; + *cpoisa = 32; + } + cpoisa++; + } while (--ccntsa > 0); + + if (issyso() == TRUE && *clipoi == '=') + { + clipoi++; + clicnt--; + num = nxtnum(&clicnt, &clipoi); + num = min(5000, num); + num = max(0, num); + mh->max = num; + while (mh->act > mh->max) + { + dealoc((MBHEAD *)ulink((LEHEAD *)mh->heardl.head)); + mh->act--; + } + + /* Meldung */ + memset(buffer, 0 , sizeof(buffer)); + sprintf(buffer, "Capacity set to %u entries.\r", mh->max); + putmsg(buffer); + return; + } + + if (issyso() == TRUE && *clipoi == '-') +#ifdef MH_LISTE + mh_delete(mh,clipoi,0); +#else + { + clipoi++; + if (--clicnt == 0) + { + for (mhp = (MHEARD *)mh->heardl.tail; + mhp != (MHEARD *)&(mh->heardl); + mhp = prevmhp) + { + prevmhp = mhp->prev; + + if (mhp->tx_bytes + mhp->rx_bytes == 0) + { + dealoc((MBHEAD *)ulink((LEHEAD *)mhp)); + mh->act--; + } + else + mh_clear(mhp); + } + mh->mhstart = sys_time; + } + else + { + if (getcal(&clicnt, &clipoi, FALSE, call) != YES) + { + putmsg("Invalid Call"); + return; + } + for (mhp = (MHEARD *)mh->heardl.tail; + mhp != (MHEARD *)&(mh->heardl); + mhp = prevmhp) + { + prevmhp = mhp->prev; + + if (!cmpcal(call,mhp->id)) + continue; + dealoc((MBHEAD *)ulink((LEHEAD *)mhp)); + mh->act--; + } + } + } +#endif + else + { + cpoisa = clipoi; + ccntsa = clicnt; + + if ((num = nxtnum(&clicnt, &clipoi)) == 0) + { + clipoi = cpoisa; + clicnt = ccntsa; + num = 10; + } +#ifdef MH_LISTE + /* Pruefen ob im Buffer eine Zahl ist. Wenn */ + /* nicht, kann das nur eine Rufzeichen sein.*/ + if ((isalpha(*cpoisa) == FALSE) && !(*cpoisa == '*')) + { + /* Liegt die Portangabe zwischen 0..15? */ + /* Wenn ja, markieren wir den Port, ansonsten */ + /* wird die Anzahl der Rufzeichen ausgegeben. */ + if (atoi(cpoisa) < 16) + { + /* Portangabe holen. */ + uport = atoi(cpoisa); + /* Pruefen ob der Port eingeschaltet ist. */ + if (portenabled(uport)) + { + num = MHlen; + /* Markiere Portangabe. */ + what = 3; + } + else + { +#ifdef SPEECH + putmsg(speech_message(194)); +#else + putmsg("Port is disabled!\r"); +#endif + return; + } + } + } + else +#endif + if ((mhprm(clipoi, clicnt, mask) == TRUE) && !(*cpoisa == '*')) + { + what = 2; + num = mh->max; + } + else + if ((getcal(&clicnt, &clipoi, FALSE, call) == YES) && !(*cpoisa == '*')) + { + what = 1; + num = mh->max; + } + } + } + else +#ifdef MH_LISTE + num = MHlen; +#else + num = 10; +#endif +#ifdef MH_LISTE + if (ccntsa) + { + if (*cpoisa == '*') + num = mh->max; + } +#endif + + if ((tmpfile = tempnam(textpath, "mh")) == NULL) + return; + + if ((fp = xfopen(tmpfile, "wt")) == NULL) + { + putmsg("Sri, can't open tempfile...\r"); + free(tmpfile); + return; + } + + call2str(tmp1, myid); + for (i = 0; alias[i] != ' ' && i < L2CALEN; ++i) + fprintf(fp, "%c", alias[i]); + + fprintf(fp, ":%s> MHEARD (%d/%d)\n", tmp1, mh->act, mh->max); + +#ifdef MH_LISTE + /* Pruefen ob TNN-Liste eingeschaltet ist. */ + /* Wenn ja, Senden wir paar extra Infos fuer */ + /* den User, ansonsten kann nur die Flexnet-Liste */ + /* eingeschaltet sein. */ + if (show_mode == _TNN) + { +#ifdef SPEECH + fprintf(fp, speech_message(281)); +#else + fprintf(fp, "Date Time Port"); +#endif + + if (!show_counter) +#ifdef SPEECH + fprintf(fp,speech_message(282)); +#else + fprintf(fp," Rx Tx Call\n"); +#endif + else +#ifdef SPEECH + fprintf(fp,speech_message(283)); +#else + fprintf(fp," RX TX Call RX-Rej TX-Rej DAMA\n"); +#endif + } +#endif + + /* kommando ausfuehren */ + for (n = 0, mhp = (MHEARD *)mh->heardl.tail; + mhp != (MHEARD *)&(mh->heardl) && n < num; + mhp = mhp->prev, n++) + { + if (mhp->heard == 0L) + continue; + + switch (what) + { + case 0: break; + + case 1: if (! cmpcal(call,mhp->id)) + continue; + break; + + case 2: if (! c6mtch(mhp->id, mask)) + continue; + break; +#ifdef MH_LISTE + case 3: if ( mhp->port != uport ) + { + n--; + continue; + } + break; +#endif + + default: continue; + } + +#ifdef MH_LISTE + if (what == 0 && mhp->flag == FALSE) + { + n--; + continue; + } +#endif + + call2str(tmp2, mhp->id); + ts = localtime(&mhp->heard); + +#ifdef MH_LISTE + if (show_mode == _TNN) + { +#endif + bp = buffer; + bp += sprintf(bp, "%02d.%02d.%02d %02d:%02d ", ts->tm_mday, + ts->tm_mon+1, + ts->tm_year%100, + ts->tm_hour, + ts->tm_min); + + if (mh == &l2heard) + { + if (show_counter) + { +#ifdef MH_LISTE + bp += sprintf(bp, "P%2u [%10s,%10s] %-9s %6lur %6lut %6ud" + ,mhp->port + ,lese_rx_bytes(_rx_bytes,mhp->rx_bytes) + ,lese_tx_bytes(_tx_bytes,mhp->tx_bytes) + ,tmp2 + ,mhp->rx_rej + ,mhp->tx_rej + ,mhp->damawarn); +#else + bp += sprintf(bp, "P%2u [%10lu,%10lu] %-9s %6lur %6lut %6ud" + ,mhp->port + ,mhp->rx_bytes + ,mhp->tx_bytes + ,tmp2 + ,mhp->rx_rej + ,mhp->tx_rej + ,mhp->damawarn); +#endif + } + else + { +#ifdef MH_LISTE + bp += sprintf(bp, "(%s)%.*s [%10s,%10s] %s" + ,portpar[mhp->port].name + ,10 - (WORD)strlen(portpar[mhp->port].name) + ," " + ,lese_rx_bytes(_rx_bytes,mhp->rx_bytes) + ,lese_tx_bytes(_tx_bytes,mhp->tx_bytes) + ,tmp2); +#else + bp += sprintf(bp, "(%s)%.*s [%10lu,%10lu] %s" + ,portpar[mhp->port].name + ,10 - (WORD)strlen(portpar[mhp->port].name) + ," " + ,mhp->rx_bytes + ,mhp->tx_bytes + ,tmp2); +#endif +#ifdef EAX25 + /* EAX.25-Verbindungen markieren */ + if (mhp->eax_link == TRUE) + bp += sprintf(bp, "%.*s (EAX.25)" + ,9 - (WORD)strlen(tmp2) + ," "); +#endif + } + } + else + if (mh == &l3heard) +#ifdef MH_LISTE + bp += sprintf(bp, "(%s)%.*s [%10s,%10s] %s" + ,portpar[mhp->port].name + ,10 - (WORD)strlen(portpar[mhp->port].name) + ," " + ,lese_rx_bytes(_rx_bytes,mhp->rx_bytes) + ,lese_tx_bytes(_tx_bytes,mhp->tx_bytes) + ,tmp2); +#else + bp += sprintf(bp, "P%2u [%10lu,%10lu] %-9s" + ,mhp->port + ,mhp->rx_bytes + ,mhp->tx_bytes + ,tmp2); +#endif + fprintf(fp, "%s\n", buffer); + } +#ifdef MH_LISTE + if (show_mode == _FLEXNET) + { + if (j == 3) + { + fprintf(fp, "\n"); + j = 0; + } + + j ++; + d = (sys_time-mhp->heard); + s = d % 60L; d /= 60L; + m = d % 60L; d /= 60L; + h = d % 24L; d /= 24L; + + if (d > 0) + fprintf(fp, " %2ldd,%2ldh ", d, h); /* dd,hh */ + else + if (h > 0) + fprintf(fp, " %2ldh,%2ldm ", h, m); /* hh,mm */ + else + if (m > 0) + fprintf(fp, " %2ldm,%2lds ", m, s); /* mm,ss */ + else + fprintf(fp, " %2lds ", s); /* ss */ + + if (mh == &l2heard) + fprintf(fp, "P%-2u %-9s" + ,mhp->port + ,tmp2); + + if (mh == &l3heard) + fprintf(fp, "P%-2u %-9s" + ,mhp->port + ,tmp2); + } + } +#endif + + fclose(fp); /* Temporaeres File schliessen */ + userpo->fname = tmpfile; + ccpread(tmpfile); +} + +/**************************************************************************/ +/* ccpmh() Erweiterter MHEARD-Befehl mit Wildcards wie bei NODES */ +/* Beispiel: "MHEARD D?5*" 04.06.91 DG5OJ/DB2OS */ +/* Special Counter Erweiterung, DB7KG */ +/*------------------------------------------------------------------------*/ +void ccpl2mh(void) +{ + ccp_mh(&l2heard); +} + +void ccpl3mh(void) +{ + ccp_mh(&l3heard); +} + +/*........................................................................*/ +/* mhprm() Parameter des erweiterten MHEARD-Befehls auswerten, */ +/* testet ob 'p' ein Wort mit Wildcards enthaelt und kopiert */ +/* dieses nach 'mp'. Case-Conversion: db*E wird zu DB*E */ +/* Parameter 'n' muss > 0 sein! 04.06.91 DB5OJ/DB2OS */ +/*........................................................................*/ +BOOLEAN mhprm(char *p, WORD n, char *mp) +{ + WORD i, c, ret; + + ret = FALSE; + + if (skipsp(&n, &p)) + { + for (i = 0; i < (MAXMASK - 1); ) + { + if (!n || ((c = *p++) == ' ')) + break; + + n--; + + if ((c == MATCHMANY) || (c == MATCHONE)) + ret = TRUE; + + mp[i++] = isascii(c) ? toupper(c) : MATCHONE; + } + mp[i] = MATCHEND; + } + return(ret); +} + +/*----------------------------------------------------------------------*/ +void init_mh(void) +{ + l2heard.mhstart = + l3heard.mhstart = sys_time; + l2heard.act = + l3heard.act = 0; + l2heard.max = + l3heard.max = 10; + l2heard.name = "MHEARD.TAB"; + l3heard.name = "L3HEARD.TAB"; + inithd(&l2heard.heardl); + inithd(&l3heard.heardl); + load_table(&l2heard); + load_table(&l3heard); +} + +/*----------------------------------------------------------------------*/ +void exit_mh(void) +{ + save_mh(); +} + +#ifdef MH_LISTE +static char *lese_rx_bytes(char *rx_bytes,int rxbytes) +{ + if(rxbytes >= 999999) + { + sprintf(rx_bytes,"%iMB",rxbytes/(1024*1024)); + return(rx_bytes); + } + else + if(rxbytes >= 9999) + { + sprintf(rx_bytes,"%iKB",rxbytes/1024); + return(rx_bytes); + } + else + sprintf(rx_bytes,"%iB ",rxbytes); + return(rx_bytes); +} + +static char *lese_tx_bytes(char *tx_bytes,int txbytes) +{ + if(txbytes >= 999999) + { + sprintf(tx_bytes,"%iMB",txbytes/(1024*1024)); + return(tx_bytes); + } + else + if(txbytes >= 9999) + { + sprintf(tx_bytes,"%iKB",txbytes/1024); + return(tx_bytes); + } + else + sprintf(tx_bytes,"%iB ",txbytes); + return(tx_bytes); +} + +static void mh_delete(MHTAB *mh, char *bufcal, int option) +{ + MHEARD *prevmhp; + MHEARD *mhp; + WORD laenge = strlen(bufcal); + char call[10]; + + bufcal++; + if (--laenge == 0) + { + for (mhp = (MHEARD *)mh->heardl.tail; + mhp != (MHEARD *)&(mh->heardl); + mhp = prevmhp) + { + prevmhp = mhp->prev; + + if (mhp->tx_bytes + mhp->rx_bytes == 0) + { + dealoc((MBHEAD *)ulink((LEHEAD *)mhp)); + mh->act--; + } + else + mh_clear(mhp); + } + + mh->mhstart = sys_time; + } + else + { + if (getcal(&laenge, &bufcal, FALSE, call) != YES) + { +#ifdef SPEECH + putmsg(speech_message(196)); +#else + putmsg("Invalid Call\n"); +#endif + return; + } + + for (mhp = (MHEARD *)mh->heardl.tail; + mhp != (MHEARD *)&(mh->heardl); + mhp = prevmhp) + { + prevmhp = mhp->prev; + + if (!cmpcal(call,mhp->id)) + continue; + + dealoc((MBHEAD *)ulink((LEHEAD *)mhp)); + mh->act--; + } + } +} +#endif /* MH_LISTE */ + +/* End of src/mh.c */ diff --git a/src/pacsat.c b/src/pacsat.c new file mode 100755 index 0000000..fa8e4fe --- /dev/null +++ b/src/pacsat.c @@ -0,0 +1,438 @@ +/************************************************************************/ +/* */ +/* ***** ***** */ +/* ***** ***** */ +/* ***** ***** */ +/* ***** ***** */ +/* *************** *************** */ +/* ***************** ***************** */ +/* *************** *************** */ +/* ***** ***** TheNetNode */ +/* ***** ***** Portable */ +/* ***** ***** Network */ +/* ***** ***** Software */ +/* */ +/* File src/pacsat.c (maintained by: ???) */ +/* */ +/* This file is part of "TheNetNode" - Software Package */ +/* */ +/* Copyright (C) 1998 - 2008 NORD>pacsat +#define pacver "Version 1.15" + +#if !defined(__LINUX__) && !defined(__WIN32__) +/************************************************************************/ +/* */ +/* Platz auf dem angegebenen Laufwerk ermitteln */ +/* */ +/************************************************************************/ +LONG getdiskfree(char *drive) +{ + struct dfree free; + + getdfree(toupper(*drive) - 'A' + 1, &free); + if (free.df_sclus == (unsigned)-1) + return(0L); + + return((LONG) free.df_avail + * (LONG) free.df_bsec + * (LONG) free.df_sclus); +} +#endif + +/************************************************************************/ +/* */ +/* Temporaerdatei fuer den aktuellen User oeffnen */ +/* */ +/************************************************************************/ +static void open_tempfile(void) +{ + pacuser->tempfp = NULL; + + /* einen Temporaerdateinamen im TEXTPATH erstellen */ + pacuser->tempfile = tempnam(textpath, "ps"); + if (pacuser->tempfile == NULL) return; + + if (getdiskfree(textpath) > 2000000L) + /* Datei oeffnen */ + pacuser->tempfp = xfopen(pacuser->tempfile, "wb"); + /* Versagt das oeffnen ist tempfp = NULL, das wird bei den */ + /* Schreib-Routinen abgefangen. */ +} + +/************************************************************************/ +/* */ +/* eine Zeile an den Pacsat-User schicken */ +/* */ +/************************************************************************/ +static void send_user(const char *s) +{ + MBHEAD *mbp; + + mbp = getmbp(); + putstr(s, mbp); + seteom(mbp); +} + +/************************************************************************/ +/* */ +/* Die empfangene Zeile in die Temporaerdatei speichern */ +/* */ +/************************************************************************/ +static void store_line(void) +{ + if (pacuser->tempfp) + { + fputs(clilin, pacuser->tempfp); + fputc('\r', pacuser->tempfp); + fputc('\12', pacuser->tempfp); + } +} + +/************************************************************************/ +/* */ +/* eine Box moechte eine Nachricht speichern. */ +/* */ +/************************************************************************/ +static void pacsat_send(void) +{ + open_tempfile(); /* in eine Temporaer-Datei speichern */ + if (pacuser->tempfp != NULL) /* wenn Datei geoeffnet werden konnte*/ + { + send_user("OK\r"); /* Bestaetigung fuer den User/die Box*/ + store_line(); /* Zeile speichern (S DB7KG @ ...) */ + } + else + send_user("Disk full\r"); /* Abbrechen, kein File */ +} + +/************************************************************************/ +/* */ +/* Filespeicherung beenden, File in das Filesystem uebertragen */ +/* */ +/************************************************************************/ +static void stop_send(void) +{ + if (pacuser->tempfp) + { + fclose(pacuser->tempfp); /* Temporaerdatei schliessen */ + pacuser->tempfp = NULL; + new_file(pacuser->tempfile); + xremove(pacuser->tempfile); /* Temporaerdatei loeschen */ + free(pacuser->tempfile); + pacuser->tempfile = NULL; + } + send_user(">\r"); /* S&F Prompt */ +} + +/************************************************************************/ +/* */ +/* Box moechte PACSAT verlassen */ +/* */ +/************************************************************************/ +static void pacsat_exit(void) +{ + MBHEAD *mbp; + + dealoc((MBHEAD *) pacuser); + pacuser = NULL; + mbp = putals("Reconnected to "); + putid(myid, mbp); + putchr('\r', mbp); + prompt(mbp); + seteom(mbp); +} + +/************************************************************************/ +/* */ +/* Routine zur Nachrichtenspeicherung */ +/* */ +/************************************************************************/ +static void store(void) +{ + store_line(); /* Zeile speichern */ + if (strchr(clilin, 0x1A)) stop_send(); /* ein CTRL-Z gefunden ? */ +} + +#if 0 +/************************************************************************/ +/* */ +/* Anzeigen/einlesen des PACSAT-BOX Rufzeichens */ +/* */ +/************************************************************************/ +void boxcall(void) +{ + char call[L2IDLEN]; + MBHEAD *mbp; + + clipoi++; + clicnt--; + + if (clicnt > 2 && getcal(&clicnt, &clipoi, FALSE, call) == TRUE) + cpyid(pacsatid, call); + + mbp = getmbp(); +#ifdef SPEECH + putstr(speech_message(291), mbp); +#else + putstr("PACSAT BOX-Call is now ", mbp); +#endif + putid(pacsatid, mbp); + putstr("\r", mbp); + seteom(mbp); +} +#endif + +/************************************************************************/ +/* */ +/* Analyse eines eingegeben Befehls */ +/* */ +/************************************************************************/ +static void pacsat_command_switch(void) +{ + FILE *fp; + static char file[MAXPATH], s[20] ,*cp; + time_t t; + + /* muss er Passwort senden und hat nicht ? */ + if (*clipoi == '[') + { + if (pacuser->check_pwd) + { + cp = strchr((char *)clipoi, ']') + 2; + + callss2str(s, calofs(UPLINK, userpo->uid)); + sprintf(file, "%s%s.PWD", pacsatpath, s); + if ((fp = xfopen(file, "rt")) != NULL) + { + pacuser->row++; + while (pacuser->row--) if (!fgets(file, MAXPATH-1, fp)) break; + fclose(fp); + file[pacuser->col+4] = NUL; + pacuser->check_pwd = strcmp(file+pacuser->col, cp); + } + } + if (!pacuser->check_pwd) send_user(">\r"); + return; + } + + if (pacuser->check_pwd && (*clipoi != '[')) + { + if (syspro_flag == TRUE) + { + strcpy(file, confpath); + strcat(file, "SYSOP.PRO"); + if ((fp = xfopen(file,"at")) != NULL) + { +#ifdef SPEECH + fprintf(fp, speech_message(285), ctime(&t), calofs(UPLINK, userpo->uid)); +#else + fprintf(fp, "%24.24s %6.6s: rejected (mailbox)\n", ctime(&t), calofs(UPLINK, userpo->uid)); +#endif + fclose(fp); + } + } + pacsat_exit(); /* und das wars ... */ + return; + } + + switch (toupper(*clipoi)) /* sonst Befehl auswerten */ + { + case 'S' : pacsat_send(); + break; + case 'F' : pacsat_exit(); /* F> beendet */ + break; + } +} + +/************************************************************************/ +/* */ +/* Dataswitch L7 (CCP) -> PACSAT */ +/* */ +/************************************************************************/ +void l7_to_pacsat(void) +{ + *clipoi = NUL; + clipoi = clilin; + if (pacuser->tempfp != NULL) + store(); /* bei Datenspeicherung */ + else + pacsat_command_switch(); +} + +/************************************************************************/ +/* */ +/* In die PACSAT S&F Box einloggen */ +/* */ +/************************************************************************/ +void ccpbox(void) +{ + MBHEAD *mbp; + char pwdfile[MAXPATH], s[20]; + struct tm *tim; + WORD mon; + + if (cmpid(pacsatid, nullid)) + { + invmsg(); + return; + } + pacuser = (PACSATBLK *)allocb(ALLOC_PACSATBLK); + pacuser->tempfp = NULL; + pacuser->tempfile = NULL; + /* wenn ein Passwort-File vorhanden ist, dann muss der User sich + auch privilegieren */ + pacuser->login = sys_time; + callss2str(s, calofs(UPLINK, userpo->uid)); + sprintf(pwdfile, "%s%s.PWD", pacsatpath, s); + pacuser->check_pwd = !xaccess(pwdfile, 0); + + send_user("Internal link setup ...\r"); + mbp = putals(conmsg); + putid(pacsatid, mbp); + putstr("\r", mbp); + seteom(mbp); + + /* Begruessung oder S&F-SID senden */ + strcpy(pwdfile, "[THEBOX-1.8-$]"); + if (pacuser->check_pwd) + { + tim = localtime(&pacuser->login); + mon = tim->tm_mon + 1; + sprintf(s," %02d%02d%02d%02d%02d",tim->tm_year,mon,tim->tm_mday, + tim->tm_hour,tim->tm_min); + strcat(pwdfile, s); + pacuser->row = (tim->tm_min + tim->tm_year) % 60; + pacuser->col = tim->tm_hour; + } + strcat(pwdfile, "\r"); + send_user(pwdfile); + send_user(">\r"); + + return; +} + +PARAM pacsatpartab[] = { /* Parameter Tabelle */ + {&pacsat_timer,0,10000, "Timer"}, + {&pacsat_frames,0,20, "Frames"}, + {&pacsat_free,0,10000, "Diskfree"} +}; + +/************************************************************************/ +/* */ +/* Pacsat-Server konfigurieren (nur durch Sysop) */ +/* */ +/************************************************************************/ +void ccppacsat(void) +{ + MBHEAD *mbp = NULL; + int ch; + WORD port; + + if (issyso() && skipsp(&clicnt, &clipoi)) { + ch = *clipoi; + nextspace(&clicnt, &clipoi); + skipsp(&clicnt, &clipoi); + switch (toupper(ch)) { + case 'R' : filesystem_init(); /* Reload */ +#ifdef SPEECH + putmsg(speech_message(292)); +#else + putmsg("Filesystem reloaded\r"); +#endif + return; + case 'C' : ccp_call(pacsatid); + if (!pacsatid[0]) + cpyid(pacsatid, nullid); + return; + case 'P' : ccp_par("BROADCAST-Parms:\r", pacsatpartab, sizeof(pacsatpartab)/sizeof(PARAM)); + return; + case '-' : + case '+' : if (getport(&clicnt, &clipoi, &port)) + pacsat_enabled[port] = (ch == '+'); + } + } + + mbp = getmbp(); +#ifdef SPEECH + putstr(speech_message(288), mbp); +#else + putstr("Server call: ", mbp); +#endif + putid(pacsatid, mbp); +#ifdef SPEECH + putstr(speech_message(289), mbp); +#else + putstr("\rMessage pool: ", mbp); +#endif + if (last_fid < first_fid) +#ifdef SPEECH + putstr(speech_message(290), mbp); +#else + putstr("Empty\r", mbp); +#endif + else +#ifdef SPEECH + putprintf(mbp,speech_message(286), first_fid, last_fid, last_fid - first_fid + 1); +#else + putprintf(mbp,"%lX-%lX (%lu Messages)\r", first_fid, last_fid, last_fid - first_fid + 1); +#endif + + for (port = 0; port < L2PNUM; port++) + if (pacsat_enabled[port]) +#ifdef SPEECH + putprintf(mbp, speech_message(287), port, portpar[port].name); +#else + putprintf(mbp, "BROADCAST enabled on port %u (%s).\r", port, portpar[port].name); +#endif + + prompt(mbp); + seteom(mbp); +} + +#endif /* PACSAT */ +/* End of src/pacsat.c */ diff --git a/src/pacserv.c b/src/pacserv.c new file mode 100755 index 0000000..9af61e0 --- /dev/null +++ b/src/pacserv.c @@ -0,0 +1,607 @@ +/************************************************************************/ +/* */ +/* ***** ***** */ +/* ***** ***** */ +/* ***** ***** */ +/* ***** ***** */ +/* *************** *************** */ +/* ***************** ***************** */ +/* *************** *************** */ +/* ***** ***** TheNetNode */ +/* ***** ***** Portable */ +/* ***** ***** Network */ +/* ***** ***** Software */ +/* */ +/* File src/pacserv.c (maintained by: ???) */ +/* */ +/* This file is part of "TheNetNode" - Software Package */ +/* */ +/* Copyright (C) 1998 - 2008 NORD> last_fid) + last_fid = fid; + if (fid < first_fid) + first_fid = fid; + if ((next = xfindnext(&fb)) != 0) + break; + } + } + + if (first_fid == LONG_MAX) + { + first_fid = sys_time; + last_fid = first_fid - 1L; + } + } +/* die Ports initialisieren */ + for (x = 0; x < L2PNUM; x++) + { + pacstate[x].busy = FALSE; + pacstate[x].last = FALSE; + pacstate[x].actfid = first_fid - 1; + pacstate[x].fid200 = last_fid; + pacsat_delay[x] = 0; + } +} + +/************************************************************************/ +/* */ +/* Garbage-Collection der Mailbox */ +/* */ +/************************************************************************/ +static void garbage(void) +{ + char name[MAXPATH]; + + while (first_fid + (LONG) pacsat_free <= last_fid) + { + make_name(first_fid++, name); + xremove(name); + } + + if (first_fid >= last_fid) filesystem_init(); +} + +/************************************************************************/ +/* */ +/* PACSAT-Server initialisiern */ +/* */ +/************************************************************************/ +void pacsat_init(void) +{ + filesystem_init(); + /*garbage();*/ +} + +static UWORD calc_crc(char c, UWORD crc) +{ + UWORD hi1, hi2; + + hi1 = ((crc >> 8) & 0xff); + hi2 = ((crc & 0xff) << 8); + return((crctab[hi1 ^ c] ^ hi2)); +} + +/************************************************************************/ +/* */ +/* Dateigroesse ermitteln */ +/* */ +/************************************************************************/ +static LONG fsize(char *name) +{ + struct stat s; + + stat(name,&s); + return(s.st_size); +} + +/************************************************************************/ +/* */ +/* Das Temporaerfile "tempname" ins PACSAT-Fileformat uebernehmen. Alle */ +/* PACSAT-Nachrichten werden im pacsatpath Verzeichnis gespeichert. Der */ +/* Dateiname ist die 8-Stellige FileId (Hex, long) und die Endung .DAT */ +/* */ +/************************************************************************/ +void new_file(char *tempname) +{ + char e_name[MAXPATH]; + char file1[MAXPATH], file2[MAXPATH]; + char s[20], s2[20]; + +/* Neueingaenge aus dem Hintergrund, z.B. Netzwerk */ + do + { + last_fid++; + make_name(last_fid, file1); + } while (!xaccess(file1, 0)); + +/* jetzt den Header hinzufuegen */ + strcpy(file2, tempname); + strcpy(e_name, pacsatpath); + strcat(e_name, "PFHADD"); +#ifndef __LINUX__ + strcat(e_name, ".EXE"); +#endif + normfname(e_name); + sprintf(s, "%lx", last_fid); + callss2str(s2, calofs(UPLINK, userpo->uid)); + + if (spawnl(P_WAIT, e_name, e_name, file2, file1, s, s2, NULL) != 0) + last_fid--; + else garbage(); +} + +/************************************************************************/ +/* PacSat-Broadcast vorbereiten, Broadcast-Struktur fuellen */ +/************************************************************************/ +static WORD init_bcast(LONG fid, char port, PACTXDESC *tp) +{ + char name[MAXPATH]; + struct stat st; + + make_name(fid, name); + tp->fid = fid; + tp->port = port; + tp->filesize = fsize(name); + if ((tp->filehandle = fopen(name, "rb")) == NULL) + return(FALSE); + tp->pos = -1L; + fstat(fileno(tp->filehandle), &st); + tp->filetime = st.st_atime; + tp->destcall = "QST \142"; + tp->via = ""; + return(TRUE); +} + +/************************************************************************/ +/* Ab der Adresse (!) Data Count Bytes in den Message-Buffer kopieren */ +/************************************************************************/ +static void add_frm(MBHEAD *mbp, char *x, WORD count) +{ + while (count-- > 0) + { + mbp->l4time = calc_crc(*x, mbp->l4time); /* CRC updaten */ + putchr(*(x++), mbp); + } +} + +#ifdef PAC_DEBUG +UWORD gen_crc(UWORD crc, char data) +{ + UWORD y; + crc ^= ((UWORD)data) << 8; + for (y = 0; y < 8; y++) + if (crc & 0x8000) + crc = (crc << 1) ^ 0x1021; + else + crc <<= 1; + return(crc); +} + +/* Debug-Funktion, CRC auf Richtigkeit ueberpruefen */ +void ckcrc(MBHEAD *mbp) +{ + UWORD crc = 0; + + rwndmb(mbp); + /* Ueberprueft auf "traditioneller" Weise die CRC (ohne Tabelle) */ + /* damit kann man auf Nummer sicher gehen beim senden ... */ + /* nur fuer Tests! */ + while (mbp->mbpc - mbp->mbgc > 2) crc = gen_crc(crc, getchr(mbp)); + crc = gen_crc(crc, getchr(mbp)); /* 1. CRC Byte */ + if (gen_crc(crc, getchr(mbp))) +#ifdef SPEECH + printf(speech_message(293)); +#else + printf("CRC Error\n"); +#endif +} +#endif + +/***************************************************************************/ +/* CRC fuer das Frame anhaengen (haben wir in l4time berechnet, s. add_frm */ +/***************************************************************************/ +static void add_crc(MBHEAD *mbp) +{ +#ifdef __WIN32__ + putchr((char)((mbp->l4time >> 8) & 0xff), mbp); + putchr((char)(mbp->l4time & 0xff), mbp); +#else + putchr((mbp->l4time >> 8) & 0xff, mbp); + putchr(mbp->l4time & 0xff, mbp); +#endif /* WIN32 */ + +#ifdef PAC_DEBUG + ckcrc(mbp); /* CRC ueberpruefen */ +#endif +} + +/************************************************************************/ +/* Ein Frame broadcasten */ +/************************************************************************/ +static BOOLEAN send_frame(PACTXDESC *tp) +{ + char flags = 0x00; /* Flag: Offset im Header enthalten */ + char type = 0x00; + char data_buf[blocksize+1], *cp; + WORD data_size; + WORD ret = TRUE; + ULONG offset = 0L; + + MBHEAD *mbp; + + mbp = (MBHEAD *) allocb(ALLOC_MBHEAD); + mbp->l4time = 0; /* Benutzen wir fuer die CRC */ + + if (tp->pos == -1L) { /* den PACSAT-Directory-Entry broadcasten */ + +/* ACHTUNG ! PFH groesser dir_blocksize muessten in 2 Durchgaengen ge- */ + flags |= PF_E; /* broadcastet werden, das ist hier nicht vorgesehen */ + + tp->pos = 0L; /* beim naechsten mal das File selber broadcasten */ + if (tp->fid == last_fid) flags |= PF_N; /* neuster Eintrag ? */ + /* den Body-Offset bestimmen */ + if (tp->filehandle != NULL) + { + fseek(tp->filehandle, 0L, SEEK_SET); + fread(data_buf, blocksize, 1, tp->filehandle); + for (cp = data_buf + 2; + (cp < data_buf+blocksize) && + (cp[2]); + cp += cp[2] + 3); + data_size = cp - data_buf; + } + else return(FALSE); + + /* jetzt den Directory Header aufbauen */ + add_frm(mbp, &flags, 1); + add_frm(mbp, (char *) &tp->fid, 4); + add_frm(mbp, (char *) &offset, 4); + add_frm(mbp, (char *) &tp->filetime, 4); /* t_old */ + add_frm(mbp, (char *) &tp->filetime, 4); /* t_new */ + if (data_size > 254 - mbp->mbpc) data_size = 254 - mbp->mbpc; + add_frm(mbp, data_buf, data_size); + add_crc(mbp); /* CRC an die Daten anhaengen */ + + rwndmb(mbp); /* Frame als UI-Frame senden */ + mbp->l2fflg = 0xBD; /* PID 0xBD */ +#ifdef __WIN32__ + sdui(tp->via, tp->destcall, myid, (char)tp->port, mbp); +#else + sdui(tp->via, tp->destcall, myid, tp->port, mbp); +#endif /* WIN32 */ + dealmb(mbp); /* Wegwerfen, sdui kopiert selbstaendig um */ + + return(TRUE); + } + else flags = PF_O; + + /* PACSAT-Header aufbauen */ + add_frm(mbp, &flags, 1); + add_frm(mbp, (char *) &tp->fid, 4); + add_frm(mbp, (char *) &type, 1); + add_frm(mbp, (char *) &tp->pos, 3); + + if ((LONG) blocksize >= /* wenn maximaler Dateninhalt */ + (tp->filesize - tp->pos) ) /* nicht gebraucht wird */ + { + data_size = (WORD) (tp->filesize - tp->pos); /* nur noch den Rest senden */ + ret = FALSE; + } + else data_size = blocksize; + +#ifdef PAC_DEBUG + printf("QST: msg=%lx offset=%lu, len=%d\n",tp->fid, tp->pos, data_size); +#endif + + if (tp->filehandle != NULL) + { + fseek(tp->filehandle, tp->pos, 0); + fread(data_buf, data_size, 1, tp->filehandle); /* Info lesen */ + add_frm(mbp, data_buf, data_size); /* Daten kopieren */ + tp->pos += (LONG) data_size; /* Offset erhoehen */ + if (tp->pos >= tp->filesize) + { + fclose(tp->filehandle);/* fertig -> Datei zu */ + } + } + else return(FALSE); /* es gibt nix mehr zu lesen ... */ + + add_crc(mbp); /* CRC an die Daten anhaengen */ + + rwndmb(mbp); /* Frame als UI-Frame senden */ + mbp->l2fflg = 0xBB; /* PID 0xBB */ +#ifdef __WIN32__ + sdui(tp->via, tp->destcall, myid, (char)tp->port, mbp); +#else + sdui(tp->via, tp->destcall, myid, tp->port, mbp); +#endif /* WIN32 */ + dealmb(mbp); /* Wegwerfen, sdui kopiert selbstaendig um */ + + return(ret); +} + +/************************************************************************/ +/* eine Broadcastrunde auf einem bestimmen Port durchfuehren. */ +/************************************************************************/ +static BOOLEAN send_bcast2(WORD port) +{ + WORD x; + + /* Falls die Datei nicht existiert */ + if (pacstate[port].now.filehandle == NULL) return(FALSE); + + /* senden bis nix mehr da ist oder maximale Frame-Anzahl erreicht */ + for (x = 0; x < pacsat_frames; x++) + if (!send_frame(&pacstate[port].now)) return(FALSE); + + return(TRUE); +} + +/************************************************************************/ +/* Broadcast-Steuerung */ +/* */ +/* Die Routine sendet alle Files zwischen first_fd und last_fid. */ +/* Das aktuell gesendete File wird in actfid gespeichert. */ +/* Sind mehr als 200 Files vorhanden, wird last auf TRUE gesetzt */ +/* Wenn LAST=TRUE ist, dann wird bei jedem zweiten Durchgang ein File */ +/* aus den letzten 200 empfangenen Files gesendet. */ +/* */ +/* Bsp: */ +/* Files 1-350 sind vorhanden. es wird gesendet: */ +/* 001-350-002-349-003-348-004-347- ... */ +/* 199-150-200-350-201-349- ... */ +/* im Bsp. wird nicht beruecksichtigt, dass evtl neue Files einlaufen. */ +/* */ +/************************************************************************/ +static void send_bcast(WORD port) +{ + PACSTATEDESC *ps = &pacstate[port]; + + /* wenn noch im Transfer dann senden */ + if (ps->busy) ps->busy = send_bcast2(port); + + /* wenn nichts mehr zu senden dann neuen Transfer beginnen */ + if (!ps->busy) + { + if (ps->last) /* Wenn eine zwischenschieben */ + { + ps->fid200--; + + /* wieder mit der letzten anfangen */ + if (ps->fid200 < (last_fid - 200)) + ps->fid200 = last_fid; + + /* sicherheitshalber */ + if (ps->fid200 < first_fid) + ps->fid200 = last_fid; + +#ifdef __WIN32__ + init_bcast(ps->fid200, (char)port, &ps->now); +#else + init_bcast(ps->fid200, port, &ps->now); +#endif /* WIN32 */ + ps->last = FALSE; + } + else + { + ps->actfid++; + if (ps->actfid > last_fid) + ps->actfid = first_fid; +#ifdef __WIN32__ + init_bcast(ps->actfid, (char)port, &ps->now); +#else + init_bcast(ps->actfid, port, &ps->now); +#endif /* WIN32 */ + if (last_fid - first_fid > 200) + ps->last = TRUE; + } + ps->busy = TRUE; + } +} + + +/****************************************************************************/ +/* Broadcast Service, wird staendig in MAIN aufgerufen. Gesendet wird wenn */ +/* der Sender nicht mehr beschaeftigt ist und mindestens der Verzoegerungs- */ +/* Timer abgelaufen ist (fuer Einstiege die nebenher Broadcasten). */ +/****************************************************************************/ +void pacsrv(void) +{ +#ifdef __WIN32__ + ULONG zeit; +#else + UWORD zeit; +#endif /* WIN32 */ + static ULONG lasttic = 0; + WORD x; + + if (last_fid < first_fid) return; + + zeit = tic10 - lasttic; + lasttic = tic10; + + for (x = 0; x < L2PNUM; x++) + if (pacsat_enabled[x]) + if (!iscd(x)) + { + if (pacsat_delay[x] <= zeit) + { + send_bcast(x); + pacsat_delay[x] = pacsat_timer; /* Timer wieder aufziehen */ + } + else +#ifdef __WIN32__ + pacsat_delay[x] -= (UWORD)zeit; +#else + pacsat_delay[x] -= zeit; +#endif /* WIN32 */ + } +} + + +#endif /* PACSAT */ +/* End of src/pacserv.c */ diff --git a/src/prof_nick.c b/src/prof_nick.c new file mode 100755 index 0000000..a97a6eb --- /dev/null +++ b/src/prof_nick.c @@ -0,0 +1,57 @@ +#ifdef CONVNICK + +/* ggf. Nickname setzen. */ +BOOLEAN GetNickname(CONNECTION *cp) +{ + PRFHEARD *prf; + + /* TBL durchsuchen. */ + if ((prf = LookupProfil(&proftab, cp->name)) == FALSE) + /* Kein Eintrag gefunden. */ + return(FALSE); + + /* Frischer Buffer. */ + memset(cp->nickname, 0, sizeof(cp->nickname)); + + /* Nur wenn es ein Nick gibt, */ + if (prf->nick[0] != FALSE) + /* Nickname setzen. */ + strncpy(cp->nickname, prf->nick, NAMESIZE); + + return(TRUE); +} + +/* Aktualisiere Profil-Daten. */ +void ProfilService(CONNECTION *cp) +{ + PRFHEARD *nicp; + + /* Eintrag suchen/bereitstellen. */ + if ((nicp = LookupProfil(&proftab, cp->name)) == FALSE) + /* Neuen Eintrag erstellen. */ + nicp = AddProfil(&proftab, cp->name); + + /* Nur wenn gueltiger Eintrag, */ + if (nicp) + /* Nickname im User-Profil sichern. */ + UpdateNickProfil(&proftab, nicp, cp->name, cp->nickname); +} + +/* Nickname im User-Profil sichern. */ +void UpdateNickProfil(PROFTAB *nic, PRFHEARD *nicp, const char *name, const char *nick) +{ + /* Nur wenn es einen Nick gibt, */ + if (nick[0] != FALSE) + /* Nickname sichern. */ + strncpy(nicp->nick, nick, NAMESIZE); + + nicp->name[L2IDLEN] = 0; + + /* Eintrag Aktualisieren. */ + ulink((LEHEAD *)nicp); + relink((LEHEAD *)nicp, (LEHEAD *)(nic->heardl.tail)); +} + +#endif /* CONVNICK */ + +/* End of src/prof_nick.c */ diff --git a/src/prof_pwd.c b/src/prof_pwd.c new file mode 100755 index 0000000..9ee2298 --- /dev/null +++ b/src/prof_pwd.c @@ -0,0 +1,122 @@ + +TRILLIAN +GetPasswd(WORD *laenge, char **inbuf, int Len, char *outbuf) +{ + char Buffer[80 + 1]; + char *bufpoi; + char zeichen; + WORD i; + char *p = *inbuf; + WORD n = *laenge; + + skipsp(&n, &p); + + bufpoi = Buffer; + i = 0; + while (n > 0) + { + if (((zeichen = (char)(*p)) == ' ' )) + break; + + if (i++ == Len - 1) + return(ERRORS); + + *bufpoi++ = zeichen; + ++p; + --n; + } + + if (i == 0) + return(NO); + + Buffer[i] = 0; + + memset(outbuf, 0, sizeof(outbuf)); + + strncpy(outbuf, Buffer, NAMESIZE); + *laenge = n; + *inbuf = p; + + return(YES); +} + + +/* Eine SIMPLE Kodierung eines Strings. */ +/* Koennte man spaeter noch weiter ausbauen! */ +void PasswdKodierung(const char *in, char *out) +{ + char passwd[80 + 1] = DEFAULT_PASS; + int i, + a = 0; + int j = 0; + + /* String leer? */ + if (in[0] == FALSE) + { + out[0] = 0; + return; + } + + j = strlen(in); + + if ( (j < 5) + ||(j > 81)) + { + out[0] = 0; + return; + } + + /* Frischer Buffer. */ + memset(out, 0, sizeof(out)); + + for (i = 0; i < j; i++) + { + a = passwd[i] + in[i]; + out[i] = a; + } + + /* Und zum Schluss das 0 Zeichen. */ + out[i] = 0; + return; +} + +/* Eine SIMPLE Dekodierung eines Strings. */ +/* Koennte man spaeter noch weiter ausbauen! */ +void PasswdDekodierung(const char *in, char *out) +{ + char passwd[80 + 1] = DEFAULT_PASS; + int i, + a = 0; + int j; + + /* String leer? */ + if (in[0] == FALSE) + { + out[0] = 0; + return; + } + + j = strlen(in); + + if ( (j < 5) + ||(j > 81)) + { + out[0] = 0; + return; + } + + /* Frischer Buffer. */ + memset(out, 0, sizeof(out)); + + for (i = 0; i < j; i++) + { + a = in[i] - passwd[i]; + out[i] = a; + } + + /* Und zum Schluss das 0 Zeichen. */ + out[i] = 0; + return; +} + +/* End of src/cvs_passwd.c */ diff --git a/src/profil.c b/src/profil.c new file mode 100755 index 0000000..b5ad344 --- /dev/null +++ b/src/profil.c @@ -0,0 +1,1330 @@ +#include "tnn.h" +#ifdef USERPROFIL + +#include "prof_pwd.c" +#include "prof_nick.c" + +PROFTAB proftab; + +static TRILLIAN GetName(WORD *, char **, int, char *); + +/* Initialisiere User-Profil. */ +void InitProfilTAB(void) +{ + proftab.act = 0; /* Aktuelle Eintraege. */ + proftab.max = 100; /* Max. Eintraege. */ + proftab.name = "PROFIL.TAB"; /* Dateiname setzen. */ + inithd(&proftab.heardl); /* Initialisiere Profil-Liste. */ + LoadTableProfil(&proftab); /* Lade Profil-TBL ein. */ +} + +#define PO_NAME 1 +#define PO_NICK 2 +#define PO_SETPW 3 +#define PO_PASSWD 4 + +PROFCMD profcmd[] = +{ + {"NAME", PO_NAME }, + {"NICK", PO_NICK }, + {"SETPW", PO_SETPW }, + {"PASSWD", PO_PASSWD }, + {NULL, 0 } +}; + +void call3str(char *id1, const char *id2) +{ + int i, + j = 0; + + /* Frischen Buffer besorgen. */ + memset(id1, 0, sizeof(id1)); + + /* Rufzeichen ohne SSID einlesen. */ + for (i = 0; i < L2IDLEN - 1; i++, j++) + { + /* Kein Zeichen. */ + if (id2[i] == FALSE) + { + /* Rest fuellen wir mit Leerzeichen aus. */ + while (i++ < L2IDLEN - 1) + id1[j++] = ' '; + + break; + } + + /* Zeichen setzen. */ + id1[j] = toupper(id2[i]); + } + + /* Nullzeichen setzen. */ + id1[L2IDLEN] = 0; +} + +/* Lade Profil-TBL "profil.tab" ein. */ +void LoadTableProfil(PROFTAB *nic) +{ + FILE *fp; + PRFHEARD *nicp; + PROFCMD *tbl; + char file[128], + buf[80]; + char *ptr, + *bps; + WORD cnt; + WORD bcs, + found; + int Len = PWSETLEN, + i = 0; + char passwort[80 + 1]; + int Error; + + /* Path setzen. */ + strcpy(file, confpath); + /* Dateiname setzen. */ + strcat(file, nic->name); + + /* Oeffne Datei. */ + if ((fp = xfopen(file, "rt")) != NULL) + { + /* Zeile einlesen (Max. 120 Zeichen). */ + while (fgets(file, 120, fp) != NULL) + { + /* Buffer beseorgen. */ + nicp = (PRFHEARD *)allocb(ALLOC_USEPROF); + /* Buffer uebergeben. */ + ptr = file; + /* Zeilenlaenge uebergeben. */ + cnt = strlen(ptr) - 1; + + /* Frischer Buffer. */ + memset(nicp->name, 0, sizeof(nicp->name)); + + do + { + *buf = NUL; + bps = buf; + if (skipsp(&cnt, &ptr)) + { + while (*ptr && isalnum(*ptr)) + { + *bps++ = toupper(*ptr++); + --cnt; + } + *bps = NUL; + } + if (!*buf) + { + cnt = 0; + break; + } + bcs = (WORD)strlen(buf); + + for (tbl = profcmd, found = 0; !found && tbl->str != NULL; ++tbl) + { + if (!strncmp(tbl->str, buf, (size_t)bcs)) + found = tbl->par; + } + + /* Befehl gefunden. */ + if (found) + { + switch (found) + { + /* Rufzeichen einlesen. */ + case PO_NAME : + ptr++; + cnt--; + + /* Pruefe, ob Rufzeichen korrekt ist. */ + if (getcal(&cnt, &ptr, TRUE, nicp->name) == ERRORS) + /* Ungueltiges Rufzeichen. */ + nicp->name[0] = 0; + + break; + + + /* Nickname einlesen. */ + case PO_NICK : + ptr++; + cnt--; + + /* Pruefe, ob Nickname korrekt ist. */ + if (GetName(&cnt, &ptr, NAMESIZE, nicp->nick) == ERRORS) + /* Ungueltiger Nickname. */ + nicp->name[0] = 0; + + nicp->name[L2IDLEN] = 0; + break; + + + /* Passwort-Einstellungen einlesen. */ + case PO_SETPW : + ptr++; + cnt--; + + while (Len--) + { + /* Bei leerstelle, */ + if ( (*ptr == ' ') + /* keine 0 */ + ||((*ptr != '0') + /* oder kein 1 */ + &&(*ptr != '1'))) + { + /* Eintrag ungueltig. */ + nicp->name[0] = 0; + break; + } + + /* Einstellung setzen. */ + nicp->setpw[i++] = *ptr; + + /* Zur naechsten Einstellung. */ + ptr++; + cnt--; + } + + if (nicp->name[0] == FALSE) + break; + + /* Nullzeichen setzen. */ + nicp->setpw[i] = 0; + /* Laenge neu setzen, fuer naechsten Eintrag. */ + Len = PWSETLEN; + /* Zuruecksetzen. */ + i = 0; + break; + + + /* Passwort einlesen. */ + case PO_PASSWD : + ptr++; + cnt--; + + /* Pruefe Passwort . */ + if ((Error = GetPasswd(&cnt, &ptr, 80 + 1, passwort)) == YES) + { + /* Passwort Dekodieren. */ + PasswdDekodierung(passwort, nicp->passwd); + break; + } + /* Kein Passwort gesetzt. */ + else + nicp->passwd[0] = 0; + + break; + + + default : + break; + } + } + } while (cnt > 0); + + /* Nur wenn Rufzeichen gesetzt. */ + if (nicp->name[0] != FALSE) + { + /* Eintrag in die List haengen. */ + relink((LEHEAD *)nicp, (LEHEAD *)(nic->heardl.tail)); + /* Ein Eintrag mehr. */ + nic->act++; + } + /* Kein Rufzeichen gesetzt. */ + else + /* Eintrag entsorgen. */ + dealoc((MBHEAD *)nicp); + + } + + /* Datei schliessen. */ + fclose(fp); + return; + } +} + +/* Profil-TBL auf Platte sichern. */ +void SaveTableProfil(char *path, PROFTAB *nictab) +{ + FILE *fp; + PRFHEARD huge *nicp; + char file[128]; + char passwd[80 + 1]; + + /* Path setzen. */ + strcpy(file, path); + /* Dateiname setzen. */ + strcat(file, nictab->name); + + /* Datei oeffnen. */ + if ((fp = xfopen(file, "wt")) != NULL) + { + /* Alle Eintraege sichern. */ + for (nicp = (PRFHEARD *)nictab->heardl.head; + nicp != (PRFHEARD *)&nictab->heardl; + nicp = nicp->next) + { + /* Kein Rufzeichen gesetzt (sicher ist sicher). */ + if (nicp->name[0] == FALSE) + /* Zum naechsten Eintrag. */ + continue; + + /* Frischen Buffer. */ + memset(passwd, 0, sizeof(passwd)); + /* Passwortvariable zuruecksetzen. */ + passwd[0] = 0; + /* Evl. Passwort kodieren. */ + PasswdKodierung(nicp->passwd, passwd); + + nicp->name[L2CALEN] = 0; + + /* Eintrag in Datei schreiben. */ + fprintf(fp, "NAME=%s NICK=%s SETPW=%s PASSWD=%s\n" + , nicp->name + , nicp->nick + , nicp->setpw + , passwd); + } + + /* Datei schliessen. */ + fclose(fp); + } +} + +/* Profil-Liste sichern. */ +void SaveProfil(void) +{ +#ifdef ST + char *mcp; +#endif + + /* Profil-TBL auf Platte sichern. */ + SaveTableProfil(confpath, &proftab); +#ifdef ST + if ((mcp = getenv("MHTOPPATH")) != NULL) + SaveTableProfil(mcp, &proftab); +#endif +} + +/* Eintrag suchen/bereitstellen. */ +PRFHEARD *LookupProfil(PROFTAB *nic, const char *id) +{ + PRFHEARD *nicp; + LHEAD *heardl = &nic->heardl; + char call[L2IDLEN]; + + call3str(call, id); + + /* Durchsuche alle Eintraege. */ + for (nicp = (PRFHEARD *)heardl->tail; + nicp != (PRFHEARD *)heardl; + nicp = nicp->prev) + { + /* Callvergleich. */ + if (cmpcal(nicp->name, call)) + /* Aktueller Eintrag. */ + return(nicp); + } + + /* Kein Eintrag gefunden. */ + return(NULL); +} + +/* Neues Profil anlegen. */ +PRFHEARD *AddProfil(PROFTAB *nic, const char *id) +{ + PRFHEARD *nicp; + char call[L2IDLEN]; + int i; + + call3str(call, id); + + /* Keine Eintraege anlegen. */ + if (nic->max == 0) + /* Abbrechen. */ + return(NULL); + + /* Max. Profil-Eintraege erreicht. */ + while (nic->act >= nic->max) + { + /* Den letzten Profil-Eintrag loeschen. */ + dealoc((MBHEAD *)ulink((LEHEAD *)nic->heardl.head)); + /* Einen Eintrag weniger. */ + nic->act--; + } + /* Neues Profil anlegen. */ + relink((LEHEAD *)(nicp = ((PRFHEARD *)allocb(ALLOC_USEPROF))), + (LEHEAD *)(nic->heardl.head)); + /* Einen Eintrag mehr. */ + nic->act++; + + nicp->nick[0] = 0; + nicp->passwd[0] = 0; + + strncpy(nicp->name, call, L2CALEN); + + /* Passwort-Einstellungen auf deaktiv stellen. */ + for (i = 0; i < PWSETLEN; i++) + nicp->setpw[i] = '0'; + + /* Nullzeichen. */ + nicp->setpw[i] = 0; + + ulink((LEHEAD *)nicp); + relink((LEHEAD *)nicp, (LEHEAD *)(nic->heardl.tail)); + + return(nicp); +} + +/* Profil-Eintrag loeschen. */ +void DeleteProfil(char *name) +{ + PRFHEARD *prf; + PROFTAB *ptab = &proftab; + + /* Durchsuche alle Eintraege. */ + for (prf = (PRFHEARD *)ptab->heardl.head; + prf != (PRFHEARD *)&ptab->heardl; + prf = prf->next) + { + /* Callvergleich. */ + if (!cmpcal(prf->name, name)) + /* Zum naechsten Eintrag. */ + continue; + + /* Loesche Profil-Eintrag. */ + dealoc((MBHEAD *)ulink((LEHEAD *)prf)); + /* Einen Eintrag weniger. */ + ptab->act--; + return; + } +} + +/* Nickname einlesen. */ +static TRILLIAN +GetName(WORD *laenge, char **inbuf, int Len, char *outbuf) +{ + char Buffer[NAMESIZE + 1]; + char *bufpoi = Buffer; + char zeichen; + WORD i; + int a = 0, + b = 0; + char *p = *inbuf; + WORD n = *laenge; + + /* Frischer Buffer. */ + memset(Buffer, 0, sizeof(Buffer)); + memset(outbuf, 0, sizeof(outbuf)); + + i = 0; + while (n > 0) + { + if (((zeichen = (char)(*p)) == ' ' )) + break; + + if (zeichen < ' ') + { + /* Umlaute zulassen. */ + if ( (zeichen != (char)0xe4) /* ae */ + &&(zeichen != (char)0xf6) /* oe */ + &&(zeichen != (char)0xfc) /* ue */ + &&(zeichen != (char)0xc4) /* Ae */ + &&(zeichen != (char)0xd6) /* Oe */ + &&(zeichen != (char)0xdc) /* Ue */ + &&(zeichen != (char)0xdf)) /* ss */ + return(ERRORS); + } + + if (i++ == Len - 1) + return(ERRORS); + + *bufpoi++ = zeichen; + ++p; + --n; + } + + if (i == 0) + return(NO); + + Buffer[i] = 0; + + while (i--) + outbuf[a++] = Buffer[b++]; + + outbuf[a] = 0; + + *laenge = n; + *inbuf = p; + + return(YES); +} + +/* Pruefe Passwortstring vom User. */ +BOOLEAN CheckPasswd(void) +{ + char pwd[5 + 1]; + + memcpy(pwd, userpo->paswrd, 5); + pwd[5] = 0; + + if (strlen((char *)clipoi) > 80) /* maximal 80 Zeichen */ + *(clipoi + 80) = NUL; + if (clicnt >= 5 && strstr((char *)clipoi, pwd) != NULL) + return(FALSE); /* Passwort war korrekt. */ + else + return(TRUE); /* Passwort war falsch. */ +} + +/* Passwortstring senden. */ +void SendPasswdStringProfil(void) +{ + PRFHEARD *prf = NULL; + MBHEAD *mbp; + WORD num; + WORD a, + b; + int i; + char buffer[255]; + char *pwd; + int pwl; + + /* Profil-Eintrag suchen. */ + if ((prf = SearchProfil(calofs(UPLINK, userpo->uid))) == NULL) + return; + + pwd = prf->passwd; + pwl = strlen(prf->passwd); + + mbp = getmbp(); + + putstr("*** ", mbp); + + /* Zufallsgenerator starten. */ + srand((UWORD)tic10); + + memset(buffer, 0, sizeof(buffer)); + + for (a = 0; a < 5; ++a) + { + do + { + do; while (((num = (rand()%256)) >= pwl) || (pwd[num] == ' ')); + + for (b = 0; b < a; ++b) + { + if ((userpo->paswrd[b] & 0xFF) == num) + break; + } + } while (a != b); + + /* Passwortstring merken. */ + userpo->paswrd[a] = (UBYTE)num; + sprintf(buffer," %d",num+1); + putprintf(mbp, "%s", buffer); + } + + putstr(">\r", mbp); + seteom(mbp); + + for (i = 0; i < 5; ++i) + userpo->paswrd[i] = pwd[userpo->paswrd[i]]; +} + +/* Ein Profil-Eintrag suchen. */ +PRFHEARD *SearchProfil(const char *call) +{ + PRFHEARD *prf = NULL; + PROFTAB *ptab = &proftab; + + /* Durchsuche alle Eintraege. */ + for (prf = (PRFHEARD *)ptab->heardl.head; + prf != (PRFHEARD *)&ptab->heardl; + prf = prf->next) + { + if (call[0] == FALSE) + /* Kein Eintrag gefunden. */ + return(NULL); + + /* Callvergleich. */ + if (cmpcal(call, prf->name)) + { + ulink((LEHEAD *)prf); + relink((LEHEAD *)prf, (LEHEAD *)(ptab->heardl.tail)); + /* Eintrag gefunden. */ + return(prf); + } + } + + /* Kein Eintrag gefunden. */ + return(NULL); +} + +/* Profil-Eintrag mit Passwortabfrage suchen. */ +BOOLEAN SearchPasswdProfil() +{ + PRFHEARD *prf = NULL; + LNKBLK *link; +#ifdef L1TCPIP + TCPIP *tpoi; +#endif /* L1TCPIP */ + + /* Profil-Eintrag suchen. */ + if ((prf = SearchProfil(calofs(UPLINK, userpo->uid))) != NULL) + { + /* Kein Passwortabfrage bei Host-User. */ + if (g_utyp(userpo->uid) == HOST_USER) + return(TRUE); + + /* User-Typ anhand der UID feststellen. */ + switch(g_utyp(userpo->uid)) + { + /* L2-Link */ + case L2_USER : + link = g_ulink(userpo->uid); + + /* Keine Passwortabfrage. */ + if (prf->setpw[link->liport] == '0') + return(TRUE); + + break; + +#ifdef L1TCPIP + /* TCPIP */ + case TCP_USER : + tpoi = g_ulink(userpo->uid); + + /* Keine Passwortabfrage. */ + if (prf->setpw[(int)tpoi->port] == '0') + return(TRUE); + + break; +#endif /* L1TCPIP */ + + } + + /* Passwort ist gesetzt. */ + if (prf->passwd[0] != FALSE) + { + /* Passwort-Modus setzen. */ + userpo->status = US_UPWD; + /* Passwortstring senden. */ + SendPasswdStringProfil(); + return(FALSE); + } + } + + /* Kein Eintrag oder kein Passwort gesetzt. */ + return(TRUE); +} + +/* Passwort-Einstellungen ausgeben. */ +static void GetPortPW(MBHEAD *mbp, PRFHEARD *prf) +{ + PORTINFO *p; + int port, + None = 0; + + + putstr("Activ Password of Port:\r", mbp); + + for (port = 0, p = portpar; port < L2PNUM; p++, port++) + { + if (prf->setpw[port] == '1') + { + putprintf(mbp, "P%02u (%s)\r", port, p->name); + ++None; + } + } + + if (None == FALSE) + putstr("None\r", mbp); +} + +/* Einen Eintrag ausgeben. */ +static void ShowProfil(MBHEAD *mbp, const char *id) +{ + PRFHEARD *prf = NULL; + char passwd[80 + 1], + call[10]; + int i = 0; + + /* Profil-Eintrag suchen. */ + if ((prf = SearchProfil(id)) != NULL) + { + /* Passwort ist gesetzt. */ + if (prf->passwd[0] != FALSE) + { + /* Frischer Buffer. */ + memset(passwd, 0, sizeof(passwd)); + + /* Passwort bleibt Geheim!. */ + for (i = 0; i < (signed)strlen(prf->passwd); ++i) + passwd[i] = '*'; + } + + /* Nullzeichen setzen. */ + passwd[i] = 0; + + memset(call, 0, sizeof(call)); + call2str(call, prf->name); + /* Profil-Eintrag ausgeben. */ + putprintf(mbp, "Call %s is registered\r" + "Nick : %s\r" + "Passwd: %s\r\r" + , call + , (prf->nick[0] == FALSE ? "No set Nickname" : prf->nick) + , (passwd[0] == FALSE ? "No set Passwd" : passwd)); + + /* Passwort-Einstellungen ausgeben. */ + GetPortPW(mbp, prf); + return; + } + + /* Kein Eintrag gefunden! */ + putstr("Call is not registerd!\r", mbp); +} + +/* Neues Profil anlegen. */ +static void NewProfil(MBHEAD *mbp, const char *call) +{ + PRFHEARD *prf = NULL; + + /* Wenn es keinen Eintrag gibt. */ + if ((prf = SearchProfil(call)) == NULL) + { + /* Neues Profil anlegen. */ + if ((prf = AddProfil(&proftab, call)) != NULL) + { + putprintf(mbp, "Call successfully registerd\r"); + return; + } + + putprintf(mbp, "Invalid Call!\r", call); + return; + } + + /* Eintrag gibt es schon. */ + putprintf(mbp, "Call existed already\r"); +} + +/* Profil loeschen. */ +static void DelProfil(MBHEAD *mbp, char *call) +{ + PRFHEARD *prf; + + /* Eintrag suchen der geloescht werden soll. */ + if ((prf = SearchProfil(call)) != NULL) + { + /* Profil loeschen. */ + DeleteProfil(call); + putprintf(mbp, "Call was exitinguished.\r"); + return; + } + + /* Kein Eintrag gefunden. */ + putstr("Call is not registerd!\r", mbp); +} + +/* Alle Profil-Eintraege auflisten. */ +static void ListProfil(MBHEAD *mbp) +{ + PRFHEARD *prf; + PROFTAB *ptab = &proftab; + char call[10]; + + /* Wenn kein Sysop, */ + if (!issyso()) + { + /* ist hier schluss. */ + putstr("No Sysop!\r", mbp); + return; + } + + /* Wenn keine Eintraege, */ + if (ptab->act == FALSE) + { + /* ist hier ebenfalls schluss. */ + putstr("No entries found!\r", mbp); + return; + } + + putstr("--Call----Nick-Passwd-\r", mbp); + + /* Alle Eintraege. */ + for (prf = (PRFHEARD *)ptab->heardl.head; + prf != (PRFHEARD *)&ptab->heardl; + prf = prf->next) + { + /* Frischer Buffer. */ + memset(call, 0, sizeof(call)); + /* Konvertiere Rutzeichen. */ + call2str(call, prf->name); + /* Eintrag auslisten. */ + putprintf(mbp, "%-9s %-3s %-3s\r" + , call + , (prf->nick[0] == FALSE ? "NO" : "YES") + , (prf->passwd[0] == FALSE ? "NO" : "YES")); + } +} + +/* Passwort setzen/loeschen. */ +static void SetPasswd(MBHEAD *mbp, const char *call) +{ + PRFHEARD *prf; + char passwd[80 + 1]; + int i; + + /* Pruefe ob der User direkt kommt. */ + if ( (strlen(call) > L2IDLEN + 1) + &&(!cmpcal(call + L2IDLEN, myid))) + { + putstr("They may not change the password!\r", mbp); + return; + } + + /* Suche Eintrag. */ + if ((prf = SearchProfil(call)) != NULL) + { + /* Eventuelle leerzeile loeschen. */ + skipsp(&clicnt, &clipoi); + + /* Passwortstring. */ + if (clicnt) + { + /* Pruefe Passwortstring. */ + if ( (clicnt < 5) + ||(clicnt > 81)) + { + putstr("Invalid password!\r", mbp); + return; + } + + /* Frischer Buffer. */ + memset(passwd, 0, sizeof(passwd)); + + /* Max. 80 zeichen einlesen. */ + for (i = 0; i < 80; i++) + { + /* Keine Zeichen mehr. */ + if (clicnt == 0) + /* Abbrechen. */ + break; + + /* Leerzeichen. */ + if (*clipoi == ' ') + /* Abbrechen. */ + break; + + /* Zeichen setzen. */ + passwd[i] = *clipoi; + + /* Naechstes Zeichen. */ + ++clipoi; + --clicnt; + } + + /* Max. 80 Zeichen. */ + for (i = 0; i < 80; i++) + { + /* Passwort string zu ende. */ + if (passwd[i] == FALSE) + /* Abbrechen. */ + break; + + /* Zeichen setzen. */ + prf->passwd[i] = passwd[i]; + } + + /* Nullzeichen setzen. */ + prf->passwd[i] = 0; + + putstr("Password is set.\r", mbp); + return; + } + /* Kein Passwort angegeben. */ + else + { + putstr("Syntax: PROF P S Passwordstring\rNo password indicated!\r", mbp); + return; + } + } + + /* Kein Eintrag gefunden. */ + putstr("Call is not registerd!\r", mbp); +} + +/* Passwort loeschen. */ +static void DelPasswd(MBHEAD *mbp, const char *call) +{ + PRFHEARD *prf; + + /* Pruefe ob der User direkt kommt. */ + if ( (strlen(call) > L2IDLEN + 1) + &&(!cmpcal(call + L2IDLEN, myid))) + { + putstr("They may not change the password!\r", mbp); + return; + } + + /* Suche Eintrag. */ + if ((prf = SearchProfil(call)) != NULL) + { + /* Kein Passwort gesetzt. */ + if (prf->passwd[0] == FALSE) + { + /* Dann brauchen wir auch nix loeschen. */ + putstr("No password indicated!\r", mbp); + return; + } + + /* Passwort ist gesetzt. */ + else + { + int i; + + /* Loeschen Passwort. */ + prf->passwd[0] = 0; + putstr("Password is delete!\r", mbp); + + /* Passwort-Modus zuruecksetzen. */ + for (i = 0; i < PWSETLEN; i++) + prf->setpw[i] = '0'; + + /* Nullzeichen setzen. */ + prf->setpw[i] = 0; + return; + } + } +} + +/* Passwort-Modus ein/ausschalten. */ +static void SetPortPW(MBHEAD *mbp, const char *call) +{ + PRFHEARD *prf; + int Port, + Opt; + + /* Suche Eintrag. */ + if ((prf = SearchProfil(call)) != NULL) + { + /* Passwortstring. */ + if (clicnt) + { + skipsp(&clicnt, &clipoi); + + /* Modus ermitteln (0 = aus, 1 = ein). */ + Opt = atoi(clipoi); + /* Wenn Keine Ziffer, */ + if ( (isalpha(*clipoi)) + ||(Opt < 0) + ||(Opt > 1)) + { + /* Abbrechen. */ + putstr("Invalid Option!\r", mbp); + return; + } + + clipoi++; + clicnt--; + + /* Eventuelle leerzeile loeschen. */ + skipsp(&clicnt, &clipoi); + /* Port ermitteln. */ + Port = atoi(clipoi); + + /* Wenn Keine Ziffer, */ + if ( (isalpha(*clipoi)) + ||(Port < 0) + ||(Port >= PWSETLEN)) + { + /* Abbrechen. */ + putstr("Invalid Port!\r", mbp); + return; + } + + /* Wenn kein Passwort gesetzt, */ + if (prf->passwd[0] == FALSE) + { + /* abbrechen. */ + putstr("No set password!\r", mbp); + return; + } + + /* Passwort-Modus einschalten. */ + if (Opt == 1) + { + /* Modus setzen. */ + prf->setpw[Port] = '1'; + putprintf(mbp, "Password is of Port %d enabled.\r", Port); + } + /* Passwort-Modus ausschalten. */ + else + { + /* Modus setzen. */ + prf->setpw[Port] = '0'; + putprintf(mbp, "Port %d disabled.\r", Port); + } + + return; + } + else + { + putstr("Syntax: PROF P P 0..1 0..15\rNo Port!\r\r", mbp); + /* Passwort-Einstellungen ausgeben. */ + GetPortPW(mbp, prf); + return; + } + } + + /* Kein Eintrag gefunden. */ + putstr("Call is not registerd!\r", mbp); +} + +/* Nickname setzen. */ +static void SetNick(MBHEAD *mbp, const char *call) +{ + PRFHEARD *prf; + char nickname[NAMESIZE + 1]; + int i; + + /* Pruefe ob der User direkt kommt. */ + if ( (strlen(call) > L2IDLEN + 1) + &&(!cmpcal(call + L2IDLEN, myid))) + { + putstr("They may not change the nickname!\r", mbp); + return; + } + + /* Suche Eintrag. */ + if ((prf = SearchProfil(call)) != NULL) + { + /* Eventuelle leerzeile loeschen. */ + skipsp(&clicnt, &clipoi); + + /* Passwortstring. */ + if (clicnt) + { + /* Pruefe Passwortstring. */ + if (clicnt > NAMESIZE) + { + putstr("Invalid nickname!\r", mbp); + return; + } + + /* Frischer Buffer. */ + memset(nickname, 0, sizeof(nickname)); + + /* Max. 16 zeichen einlesen. */ + for (i = 0; i < NAMESIZE; i++) + { + /* Keine Zeichen mehr. */ + if (clicnt == 0) + /* Abbrechen. */ + break; + + /* Leerzeichen. */ + if (*clipoi == ' ') + /* Abbrechen. */ + break; + + /* Zeichen setzen. */ + nickname[i] = *clipoi; + + /* Naechstes Zeichen. */ + ++clipoi; + --clicnt; + } + + /* Max. 16 Zeichen. */ + for (i = 0; i < NAMESIZE; i++) + { + /* Passwort string zu ende. */ + if (nickname[i] == FALSE) + /* Abbrechen. */ + break; + + /* Zeichen setzen. */ + prf->nick[i] = nickname[i]; + } + + /* Nullzeichen setzen. */ + prf->nick[i] = 0; + + putstr("Nickname is set.\r", mbp); + return; + } + /* Kein Nickname angegeben. */ + else + { + putstr("Syntax: PROF I S nickname\rNo nickname indicated!\r", mbp); + return; + } + } + + /* Kein Eintrag gefunden. */ + putstr("Call is not registerd!\r", mbp); +} + +/* Nickname loeschen. */ +static void DelNick(MBHEAD *mbp, const char *call) +{ + PRFHEARD *prf; + + /* Pruefe ob der User direkt kommt. */ + if ( (strlen(call) > L2IDLEN + 1) + &&(!cmpcal(call + L2IDLEN, myid))) + { + putstr("They may not change the nickname!\r", mbp); + return; + } + + /* Suche Eintrag. */ + if ((prf = SearchProfil(call)) != NULL) + { + /* Kein Passwort gesetzt. */ + if (prf->nick[0] == FALSE) + { + /* Dann brauchen wir auch nix loeschen. */ + putstr("No nickname indicated!\r", mbp); + return; + } + + /* Nickname ist gesetzt. */ + else + { + /* Loeschen Nickname. */ + prf->nick[0] = 0; + putstr("Nickname is delete!\r", mbp); + return; + } + } +} + +/* Nick setzen/loeschen. */ +static void NickProfil(MBHEAD *mbp, const char *call) +{ + skipsp(&clicnt, &clipoi); + + switch (*clipoi) + { + /* Passwort setzen. */ + case 'S' : + case 's' : + clipoi++; + clicnt--; + + SetNick(mbp, call); + return; + + /* Passwort loeschen. */ + case 'D' : + case 'd' : + clipoi++; + clicnt--; + + DelNick(mbp, call); + return; + + default : + break; + } + + putstr("(S)et Nickname (D)el Nickname\r", mbp); +} + +/* Passwort setzen/loeschen. */ +static void PasswdProfil(MBHEAD *mbp, const char *call) +{ + skipsp(&clicnt, &clipoi); + + switch (*clipoi) + { + /* Passwort setzen. */ + case 'S' : + case 's' : + clipoi++; + clicnt--; + + SetPasswd(mbp, call); + return; + + /* Passwort loeschen. */ + case 'D' : + case 'd' : + clipoi++; + clicnt--; + + DelPasswd(mbp, call); + return; + + /* Passwort-Modus ein/ausschalten. */ + case 'P' : + case 'p' : + clipoi++; + clicnt--; + + SetPortPW(mbp, call); + return; + + default : + break; + } + + putstr("(S)et Password (D)el Password (P)ort activ/deactiv\r", mbp); +} + +#define OP_NONE 0 +#define OP_SHOW 1 +#define OP_NEW 2 +#define OP_NICK 3 +#define OP_DEL 4 +#define OP_LIST 5 +#define OP_PASS 6 +#define BUFLEN 32 + +void ccpprofil(void) +{ + MBHEAD *mbp; + PROFTAB *ptab = &proftab; + char cBuf[BUFLEN + 1]; + int i; + unsigned int uCmd = OP_NONE; + + if (clicnt) + { + /* Frischer Buffer */ + memset(cBuf, 0, sizeof(cBuf)); + + /* Buffer einlesen. */ + for (i = 0; i < BUFLEN; ++i) + { + if ((!clicnt) || (*clipoi == ' ')) + break; + clicnt--; + cBuf[i] = toupper(*clipoi++); + } + + /* Befehl: Eigenes Profil zeigen. */ + if ( (strcmp(cBuf, "SHOW") == 0) + || (cBuf[0] == 'S') + ) + uCmd = OP_SHOW; + + /* Befehl: Neues Profil anlegen. */ + if ( (strcmp(cBuf, "NEW") == 0) + || (cBuf[0] == 'N') + ) + uCmd = OP_NEW; + + /* Befehl: Nickname setzen/loeschen. */ + if ( (strcmp(cBuf, "NICK") == 0) + || (cBuf[0] == 'I') + ) + uCmd = OP_NICK; + + /* Befehl: Profil loeschen. */ + if ( (strcmp(cBuf, "DEL") == 0) + || (cBuf[0] == 'D') + ) + uCmd = OP_DEL; + + /* Befehl: Alle Profil-Eintraege auflisten. */ + if ( (strcmp(cBuf, "LIST") == 0) + || (cBuf[0] == 'L') + ) + uCmd = OP_LIST; + + /* Befehl Passwort setzen. */ + if ( (strcmp(cBuf, "PASSWD") == 0) + || (cBuf[0] == 'P') + ) + uCmd = OP_PASS; + + /* Befehl. */ + switch (uCmd) + { + /* Profil zeigen. */ + case OP_SHOW : + mbp = putals(""); + putprintf(mbp, "Profil->Show (%d:%d):\r\r", ptab->act, ptab->max); + + ShowProfil(mbp, calofs(UPLINK, userpo->uid)); + prompt(mbp); + seteom(mbp); + return; + + /* Neues Profil anlegen. */ + case OP_NEW : + mbp = putals(""); + putprintf(mbp, "Profil->New (%d:%d):\r\r", ptab->act, ptab->max); + + NewProfil(mbp, calofs(UPLINK, userpo->uid)); + prompt(mbp); + seteom(mbp); + return; + + /* Neues Profil anlegen. */ + case OP_NICK : + mbp = putals(""); + putprintf(mbp, "Profil->Nick (%d:%d):\r\r", ptab->act, ptab->max); + + NickProfil(mbp, calofs(UPLINK, userpo->uid)); + prompt(mbp); + seteom(mbp); + return; + + /* Profil loeschen. */ + case OP_DEL : + mbp = putals(""); + putprintf(mbp, "Profil->Delete (%d:%d):\r\r", ptab->act, ptab->max); + + DelProfil(mbp, calofs(UPLINK, userpo->uid)); + prompt(mbp); + seteom(mbp); + return; + + /* Alle Profil-Eintraege auflisten. */ + case OP_LIST : + mbp = putals(""); + + putprintf(mbp, "Profil->List (%d:%d):\r\r", ptab->act, ptab->max); + ListProfil(mbp); + prompt(mbp); + seteom(mbp); + return; + + /* Passwort setzen/loeschen. */ + case OP_PASS : + mbp = putals(""); + putprintf(mbp, "Profil->Passwd (%d:%d):\r\r", ptab->act, ptab->max); + + PasswdProfil(mbp, calofs(UPLINK, userpo->uid)); + prompt(mbp); + seteom(mbp); + return; + + default: + mbp = putals(""); + putprintf(mbp, "User-Profil (%d:%d):\r\r", ptab->act, ptab->max); + + putstr("Invalid command\r", mbp); + prompt(mbp); + seteom(mbp); + return; + } + } + + mbp = putals(""); + putprintf(mbp, "User-Profil (%d:%d):\r\r", ptab->act, ptab->max); + + if (uCmd == OP_NONE) + putprintf(mbp, "(S)how (N)ew (D)el N(I)ckname (P)asswd %s\r", (issyso() == TRUE ? "(L)ist" : "")); + + prompt(mbp); + seteom(mbp); +} + +#endif /* USERPROF. */ + +/* End of src/profil.c. */ diff --git a/src/profiler.c b/src/profiler.c new file mode 100755 index 0000000..49fa25b --- /dev/null +++ b/src/profiler.c @@ -0,0 +1,225 @@ +/************************************************************************/ +/* */ +/* ***** ***** */ +/* ***** ***** */ +/* ***** ***** */ +/* ***** ***** */ +/* *************** *************** */ +/* ***************** ***************** */ +/* *************** *************** */ +/* ***** ***** TheNetNode */ +/* ***** ***** Portable */ +/* ***** ***** Network */ +/* ***** ***** Software */ +/* */ +/* File src/profiler.c (maintained by: DL1XAO) */ +/* */ +/* This file is part of "TheNetNode" - Software Package */ +/* */ +/* Copyright (C) 1998 - 2008 NORD>t_start; + if (t > HIST) + t = HIST; + p->histo[(int) t]++; + } +} +#endif + +#ifdef __LINUX__ +void prof_start(int num) +{ + struct timeval tv; + struct timezone tz; + + if (prof_onoff) + { + gettimeofday(&tv, &tz); + profiles[num].t_start = tv; + } +} + +void prof_stop(int num) +{ + ULONG t; + PROFILE_T *p; + struct timeval tv; + struct timezone tz; + + if (prof_onoff) + { + gettimeofday(&tv, &tz); + p = &profiles[num]; + t = (tv.tv_sec - p->t_start.tv_sec) * 1000000 + + (tv.tv_usec - p->t_start.tv_usec); + if (t > HIST) + t = HIST; + p->histo[(int) t]++; + } +} +#endif + +#ifdef __GO32__ +void prof_start(int num) +{ + if (prof_onoff) + profiles[num].t_start = uclock(); +} + +void prof_stop(int num) +{ + ULONG t; + PROFILE_T *p; + + if (prof_onoff) + { + p = &profiles[num]; + t = uclock() - p->t_start; + if (t > HIST) + t = HIST; + p->histo[(int) t]++; + } +} +#endif + +static void prof_reset(int num) +{ + memset(&profiles[num], 0, sizeof(PROFILE_T)); +} + +static void prof_dump(void) +{ + FILE *fp; + int i, j; + + if ((fp = xfopen("profile.dat", "wt")) != NULL) + { + for (i = 0; i <= HIST; i++) + { + for (j = 0; j < (N_PROFILES - 1); j++) + fprintf(fp, "%lu\t", profiles[j].histo[i]); + fprintf(fp, "%lu\n", profiles[j].histo[i]); + } + fclose(fp); + putmsg("profiler data saved\r"); + } + else + putmsg("file error!\r"); +} + +void ccp_profile(void) +{ + int i; + + if (issyso() == TRUE) + { + skipsp(&clicnt, &clipoi); + *(clipoi + clicnt) = NUL; + + if (!stricmp(clipoi, "on")) + { + prof_onoff = 1; + putmsg("profiler on\r"); + } + else if (!stricmp(clipoi, "off")) + { + prof_onoff = 0; + putmsg("profiler off\r"); + } + else if (!stricmp(clipoi, "reset")) + { + for (i = 0; i < N_PROFILES; i++) + prof_reset(i); + putmsg("profiler data cleared\r"); + } + else if (!stricmp(clipoi, "save")) + { + prof_dump(); + } + else if (prof_onoff) + putmsg("profile is on\r"); + else + putmsg("profile is off\r"); + } + else + invmsg(); +} + +#endif diff --git a/src/speech.c b/src/speech.c new file mode 100755 index 0000000..48c8deb --- /dev/null +++ b/src/speech.c @@ -0,0 +1,706 @@ +#include "tnn.h" + +#ifdef SPEECH +#include "speech.h" + +struct speech_msg +{ + char speech[20]; + char num1[255]; + char mode_num[8]; + char default_num[8]; + char default_mode_num[9]; + unsigned mode; + unsigned default_mode; +}; + +struct speech_msg speech_tbl[MAXZEILEN+1]; + +static int sprachen = EOF; +static int meldungen = TRUE; + +char speech[15] = "Englisch"; +char speechpath[MAXPATH] = SPEECHPATH; /* Pfad fuer Sprachen */ + +static unsigned set_substitute_symbols(const char *speechbuf, char *mode); + + +/* Default Sprache laden. */ +static void speech_default(void) +{ + struct + { + int nummer; + int mode; + char mode_num[9]; + char meldung[255]; + } + speech_tab[] = { + + { 0, 0x0000000,"00000000","Convers session terminated.\rEnter command. Type HELP for help.\r" }, + { 1, 0x0000000,"00000000","*** You are already in convers-mode.\r" }, + { 2, 0x0000000,"00000000","The Convers-Hostname is to long (max.9 indications)!\r" }, + { 3, 0x0050000,"00010000","Convers-Hostname successful changed in %s.\r" }, + { 4, 0x0000000,"00000000","Locked!\r" }, + { 5, 0x0050000,"00040000","%s%s@%s has gone away:\r %s\r" }, + { 6, 0x0050000,"00030000","%s%s@%s is back again.\r" }, + { 7, 0x0050020,"00020010","%s%s made you a channel operator for channel %d\r" }, + { 8, 0x0050020,"00030010","%s%s@%s is now a channel operator for channel %d\r" }, + { 9, 0x0000020,"00000010","channel %d" }, + { 10, 0x0050000,"00050000","%s%s@%s on %s set personal text:\r %s\r" }, + { 11, 0x0050000,"00040000","%s%s@%s on %s removed personal text.\r" }, + { 12, 0x0050000,"00050000","%s%s@%s on %s set channel topic:\r %s\r" }, + { 13, 0x0050000,"00040000","%s%s@%s on %s removed channel topic.\r" }, + { 14, 0x0000000,"00000000","secret channel" }, + { 15, 0x0000000,"00000000","this invisible channel" }, + { 16, 0x0050000,"00060000","%s%s:%s@%s on %s set personal text:\r %s\r" }, + { 17, 0x0050000,"00050000","%s%s:%s@%s left %s.\r" }, + { 18, 0x0050000,"00040000","%s%s@%s left %s.\r" }, + { 19, 0x0050000,"00050000","%s%s@%s left %s (%s).\r" }, + { 20, 0x0050000,"00050000","%s%s:%s@%s joined %s\r" }, + { 21, 0x0050000,"00040000","%s%s@%s joined %s\r" }, + { 22, 0x0050000,"00030000","%s%s is away: %s" }, + { 23, 0x0050000,"00020000","%sYour messages are ignored by %s" }, + { 24, 0x0050020,"00030010","\r\007\007%sMessage from %s...\rPlease join %s channel %d.\r\007\007\r" }, + { 25, 0x0050000,"00040000","%s%s Invitation sent to %s @ %s." }, + { 26, 0x0050000,"00020000","%sUser %s is already on this channel." }, + { 27, 0x0000000,"00000000","*** Unknown command '/" }, + { 28, 0x0000000,"00000000","'. Type /HELP for Help.\r" }, + { 29, 0x0000000,"00000000","*** You are away, aren't you ? :-)\r" }, + { 30, 0x0000000,"00000000","*** This is a moderated channel. Only channel operators may write.\r" }, + { 31 ,0x0000000,"00000000","*** Queried user left channel.\r" }, + { 32, 0x0050000,"00010000","%sYou are marked as being away.\r" }, + { 33, 0x0050000,"00010000","%sYou are no longer marked as being away.\r" }, + { 34, 0x0050000,"00010000","%sActually you were marked as being here :-)\r" }, + { 35, 0x0050000,"00010000","*** Beep mode %sabled\r" }, + { 36, 0x0050020,"00010020","%sYou are talking to channel %d. There are %d users.\r" }, + { 37, 0x0050000,"00020000","*** current Topic by: %s (%s):\r " }, + { 38, 0x0000000,"00000000","*** Also attached:" }, + { 39, 0x0000020,"00000010","channel %d (alone)" }, + { 40, 0x0000020,"00000020","channel %d (%d users)" }, + { 41, 0x0050020,"00010010","%sChannel number must be in the range 0..%d.\r" }, + { 42, 0x0050020,"00010010","%sChannel %d is already default.\r" }, + { 43, 0x0050020,"00010010","%sYou need an invitation to join the privat channel %d.\r" }, + { 44, 0x0050000,"00030000","%s%s@%s try to join your privat channel." }, + { 45, 0x0050020,"00010010","%scannot join channel %d, no more space.\r" }, + { 46, 0x0050020,"00010010","%sYou are now talking to channel %d" }, + { 47, 0x0000000,"00000000","You're alone.\r" }, + { 48, 0x0000020,"00000010","There are %d users.\r" }, + { 49, 0x0050000,"00020000","*** Charset in/out is %s/%s.\r" }, + { 50, 0x0050000,"00020000","Unknown charset: '%s'. You may use one of them:\r%s***\r" }, + { 51, 0x0050000,"00020000","*** Charset in/out set to %s/%s.\r" }, + { 52, 0x0000000,"00000000","Help on this command not yet implemented ...\rWrite it - or try another one :-)\r" }, + { 53, 0x0000000,"00000000","No such command...\r" }, + { 54, 0x0050000,"00010000","*** no route to %s\r" }, + { 55, 0x0050020,"00010010","%sDefault channel is now %d.\r" }, + { 56, 0x0050020,"00010010","%sLeft channel %d.\r" }, + { 57 ,0x0050020,"00010010","%sYou were not on channel %d.\r" }, + { 58, 0x0050000,"00010000","*** Reguest sent to %s.\r" }, + { 59, 0x0000000,"00000000","You must be an operator to set a new links\r" }, + { 60, 0x0000000,"00000000","Link table full !\r" }, + { 61, 0x0000000,"00000000","Argument error !\r" }, + { 62, 0x0050020,"00010010","%sYou have not joined channel %d.\r" }, + { 63, 0x0050000,"00020000","%sNo such user: %s.\r" }, + { 64 ,0x0050000,"00030000","%s%s is away: %s\r" }, + { 65, 0x0000000,"00000000","*** non existing channel !\r" }, + { 66, 0x0000000,"00000000","*** no modes on channel 0 !\r" }, + { 67, 0x0000000,"00000000","*** You are not on operator !\r" }, + { 68, 0x0050000,"00020000","%s @ %s PingPong-Release %5.5s (TNN) - Type /HELP for help.\r" }, + { 69, 0x0050020,"00010010","%sYou need an invitation to join channel %d.\r" }, + { 70, 0x0050000,"00030000","%s%s@%s try to join your privat channel." }, + { 71, 0x0000020,"00000010","*** You created a new channel %d.\r" }, + { 72, 0x0050000,"00010000","*** Personal text and date set.\rHello, %s\r" }, + { 73, 0x0000000,"00000000","*** Please set your personal text. ( /H PERS )" }, + { 74, 0x0050000,"00010000","%sYou are notified if one of the following users sign on/off:\r" }, + { 75, 0x0050000,"00010000","%sYou filter the messages of the following users:\r" }, + { 76, 0x0050000,"00010000","*** %s is online.\r" }, + { 77, 0x0000000,"00000000","and data saved.\r" }, + { 78, 0x0000000,"00000000","*** No personal text save.\r" }, + { 79, 0x0000000,"00000000","deleted.\r" }, + { 80, 0x0000000,"00000000","and data set.\r" }, + { 81, 0x0050000,"00010000","*** Prompting mode %sabled\r" }, + { 82, 0x0000000,"00000000","en" }, + { 83, 0x0000000,"00000000","dis" }, + { 84, 0x0000000,"00000000","You must be an operator to restart!\r" }, + { 85 ,0x0050000,"00010000","Link to %s delocked.\r" }, + { 86, 0x0050000,"00010000","%sNo such user: %.20s.\r" }, + { 87, 0x0050000,"00020000","%sStarting privat conversation with %s.\r" }, + { 88 ,0x0050000,"00020000","%sEnding privat conversation with %s.\r" }, + { 89, 0x0050020,"00030010","%sChannel topic on channel %d removed from %s (%s).\r" }, + { 90, 0x0050020,"00030010","%sChannel topic set on channel %d from %s (%s).\r" }, + { 91, 0x0050020,"00030010","%sCurrent channel topic on channel %d from %s (%s) is\r " }, + { 92, 0x0050020,"00010010","%sNo current channel topic on channel %d.\r" }, + { 93, 0x0050020,"00010010","%sChannel channel %d non existent.\r" }, + { 94, 0x0050000,"00030000","*** %s@%s is up for %s\r" }, + { 95, 0x0050000,"00010000","*** Verbose mode %sabled\r" }, + { 96 ,0x0000000,"00000000"," This conversd implementation was originally written by Dieter Deyke\r . It was modified and maintained up to version\r 3.11 by Fred Baumgarten, dc6iq." }, + { 97, 0x0000000,"00000000"," This implementation is partly rewritten,\r enhanced and maintained by Odo Roscher \r for TheNetNode and Xnet.\r" }, + { 98, 0x0000000,"00000000"," Idle Personal\r" }, + { 99 ,0x0000000,"00000000","Login State\r" }, + { 100,0x0000000,"00000000","Login Personal\r" }, + { 101,0x0000000,"00000000","(here)" }, + { 102,0x0000000,"00000000","\r Away: " }, + { 103,0x0000000,"00000000"," (since " }, + { 104,0x0000000,"00000000"," (AWAY)" }, + { 105,0x0000000,"00000000","\r Last Activity: " }, + { 106,0x0000020,"00000010","*** Current screen width is %d\r" }, + { 107,0x0000000,"00000000","*** Range 32 to 255\r" }, + { 108,0x0000020,"00000010","*** Screen width set to %d\r" }, + { 109,0x0050000,"00010000","*** Urgent message from operator (%s):\r " }, + { 110,0x0050000,"00010000","*** Links at %s" }, + { 111,0x0000000,"00000000","free" }, + { 112,0x0050000,"00010000","*** Nickname set to: %s.\r" }, + { 113,0x0050000,"00020000","none login possible!\ncall signal %s is logged in at the host %s!\n" }, + { 114,0x0000000,"00000000","*** your password was deleted!\r" }, + { 115,0x0000000,"00000000","*** no password set!\r" }, + { 116,0x0050000,"00010000","*** reads. your password:\r%s\r" }, + { 117,0x0000000,"00000000","*** it is not defined a password!\r" }, + { 118,0x0000000,"00000000","*** password was set!\r" }, + { 119,0x0000000,"00000000","*** password must contain at least 5 and/or maximally 80 indications!\r" }, + { 120,0x0000000,"00000000","*** is missing. to password!\r" }, + { 121,0x0000000,"00000000","*** Syntax: pass [new password]\r" }, + { 122,0x0000000,"00000000","*** password is correct!\r" }, + { 123,0x0000000,"00000000","*** password is wrong!\r" }, + { 124,0x0050000,"00030000","*** current Topic by: %s (%s):\r %s\r" }, + { 125,0x0050020,"00010010","\r*** %d user on channel%s ***\r" }, + { 126,0x7000000,"01000000"," Average: %lu" }, + { 127,0x0000000,"00000000","\r%7s00 02 04 06 08 10 12 14 16 18 20 22\r%9s01 03 05 07 09 11 13 15 17 19 21 23 Hour\r\r" }, + { 128,0x0000000,"00000000","\r%7s0 0 1 1 0 0 1 1 0 0 1 1 0 0 1 1 0 0 1 1 0 0 1 1 0 0 1 1\r%7s0 6 2 8 0 6 2 8 0 6 2 8 0 6 2 8 0 6 2 8 0 6 2 8 0 6 2 8 h\r%7sMonday Tuesday Wednes. Thursd. Friday Saturd. Sunday\r\r" }, + { 129,0x0000000,"00000000"," Elap. time\r%6s-3600 -3240 -2880 -2520 -2160 -1800 -1440 -1080 -720 -360 0 Seconds\r\r" }, + { 130,0x0600000,"00100000","> DISCONNECT: Too many non-DAMA Polls (%u) !!\r" }, + { 131,0x0600000,"00200000","WARNING: non-DAMA Poll #%u, Disconnect after %u !!\r" }, + { 132,0x0000000,"00000000","Graph cleared!\r" }, + { 133,0x0000000,"00000000","SYSTEMGRAPH:\r" }, + { 134,0x0000000,"00000000","(G)raph (H)our (B)aud\r (D)ay (C)ircuits\r (W)eek (F)ree buffers\r (L)2-Links\r (N)odes\r (R)ounds\r (*) All\r" }, + { 135,0x0000000,"00000000","PORTGRAPH:\r(G)raph (H)our (I)nfo frames\r (D)ay (R)eject frames\r (W)eek (F)rmr frames\r (S)abm frames\r dis(C) frames\r" }, + { 136,0x0000000,"00000000"," d(M) frames\r (*) All\r" }, + { 137,0x0000000,"00000000","\r*** from DAMA-Master " }, + { 138,0x0050000,"00020000","%s<>%s broken" }, + { 139,0x0000000,"00000000","You are suspended.\r" }, + { 140,0x0000000,"00000000","\r- Aborted -\r\r" }, + { 141,0x0000000,"00000000","Sri, no text available!\r" }, + { 142,0x0000000,"00000000","CLI failed!\r" }, + { 143,0x0000000,"00000000","Waiting for AUTOBIN-Transfer...\r" }, + { 144,0x0000000,"00000000","\rL2 - User:\rPo SrcCall DstCall LS Rx Tx Tr SRTT RxB TxB Baud ConTime Pr Da\r" }, + { 145,0x0000000,"00000000","\rL4 - User:\rCall Node S Rx Tx Tr Win SRTT RxB TxB Baud ConTime\r" }, + { 146,0x0000000,"00000000","free" }, + { 147,0x0000000,"00000000","free" }, + { 148,0x0000000,"00000000","\rHost-User:\rCH Call F NT RX TX ST RxB TxB Baud ConTime\r-------------------------------------------------------------------------\r" }, + { 149,0x0000000,"00000000","free" }, + { 150,0x0000000,"00000000","\r System Statistics: " }, + { 151,0x0000000,"00000000","\r Startup: " }, + { 152,0x0000000,"00000000","\r\r Port-Statistics:\r\r Links RxB TxB RxBaud TxBaud RxOver TxOver\r" }, + { 153,0x0000000,"00000000","\rTotal = " }, + { 154,0x0000000,"00000000"," Bytes\r" }, + { 155,0x0000000,"00000000", "\r Error-Statistics:\r\r RxID RxLen RxCtl Resets\r" }, + { 156,0x0000000,"00000000","\rLink-Statistics:\r" }, + { 157,0x0000000,"00000000","\rLink to " }, + { 158,0x0000000,"00000000"," via " }, + { 159,0x0000000,"00000000","\rFrames: I UI RR REJ RNR SABM/UA DISC/DM FRMR\r" }, + { 160,0x0000000,"00000000","Bytes: Total Info Header Overhead %I %RR %REJ %RNR\r" }, + { 161,0x0000000,"00000000"," TQual:" }, + { 162,0x0000000,"00000000","\rIP-Gateway-Statistics:\r\r" }, + { 163,0x0000000,"00000000","free" }, + { 164,0x0000000,"00000000","free" }, + { 165,0x0000000,"00000000","Warning - Port not active.\r" }, + { 166,0x0000000,"00000000","Invalid callsign.\r" }, + { 167,0x0000000,"00000000","Invalid ident.\r" }, + { 168,0x0000000,"00000000","free" }, + { 169,0x0000000,"00000000","free" }, + { 170,0x0000000,"00000000","Type-Port--Alias:Call------Route--------------Infotext------------\r" }, + { 171,0x0000000,"00000000","No such User!\r" }, + { 172,0x0000000,"00000000","Das Sysop Passwort wurde geaendert!\r" }, + { 173,0x0000000,"00000000","Fehler: Das Passwort muss 80 Zeichen enthalten!\r" }, + { 174,0x0050000,"00010000","editing>%s\rEnter text. End with '.' in a new line.\r" }, + { 175,0x0000000,"00000000","free" }, + { 176,0x0000000,"00000000","\r (min) (now) (max)\r Rounds/sec: %8lu %8lu %8lu\r" }, + { 177,0x0000000,"00000000"," Free Buffers: %8u %8u %8u\rOverall Throughput:%18lu %8lu Baud\r Active L2-Links:%18u %8u\r Active Circuits:%18u %8u\r Active Nodes:%18u %8u\r" }, + { 178,0x0000000,"00000000","\r Active Telnets:%18u %8u\r" }, + { 179,0x7000000,"01000000","\r Buffer usage: %lu%%" }, + { 180,0x7000000,"01000000","\r Network Heap: %lu Bytes" }, + { 181,0x7000000,"01000000","\r CPU load: %lu%%" }, + { 182,0x0000000,"00000000","TX: Once:%11lu Repeated:%10lu IQual:" }, + { 183,0x0050020,"00010030"," Copyright by NORD> 0 && *clipoi == NUL) + putstr("Folgende Sprachen wurden gefunden:\r",mbp); + else + { + if (sprachen == 0) + putstr("Es wurden keine Sprachdateien gefunden\r",mbp); + } + + if (*clipoi == NUL) + { + for (i = 0; i < sprachen; i++) + { + putprintf(mbp,"%s\r",speech_tbl[i].speech); + } + } + + putprintf(mbp,"Sprache ist auf %s eingestellt.\r",speech); + prompt(mbp); + seteom(mbp); +} +void dump_speech(MBHEAD *mbp) +{ + putstr(";\r; Sprache\r;\r", mbp); + putprintf(mbp,"SPEECH %s\r;\r",speech); +} + +static char *lese_meldung(char *buffer,FILE *fp) +{ + char buf[320]; + int i = 1; + int j = 0; + + strcpy(buf,buffer); + + if(buffer[0]=='"') + while(buf) + { + while( (buf[i] == 0x1b || buf[i] >= 0x20) && + (buf[i]!='"' || (i && buf[i-1]=='\\')) && + buf[i]!='\n' && i < 255) + { + if(buf[i]=='\\') + { i++; + + switch(buf[i]) + { + case 'n': buffer[j]='\n'; break; + case 'r': buffer[j]='\r'; break; + case '"': buffer[j]='"' ; break; + case 'a': buffer[j]='\a'; break; + case '\\': buffer[j]='\\'; break; + } + } + else + buffer[j] = buf[i]; + j++; + i++; + } + buffer[j] = 0; + return(buffer); + } +return(FALSE); +} + +int speech_load(char *bufspeech) +{ + FILE *fp; + char speechcfg[255]; + char buffer[255]; + char mode_num[8] = "0000000"; + + strcpy(speechcfg,speechpath); + strcat(speechcfg,bufspeech); + strcat(speechcfg,".txt"); + meldungen = 1; + if ((fp = xfopen(speechcfg,"rt")) == NULL) + return(TRUE); + + { + while(!feof(fp)) + { + if (meldungen > MAXZEILEN) + { + printf("Fehler in Sprachdatei %s, maximale Zeilenlaenge von %d ueberschritten !!!\r",speech,MAXZEILEN); + fclose(fp); + speech_default(); + return(FALSE); + } + + fgets(buffer,255,fp); + lese_meldung(buffer,fp); + if (strlen(buffer) >= 254) + { + printf("Fehler in Sprachdatei %s Zeile %d ist zu lang !!!\r",speech,meldungen); + fclose(fp); + return(FALSE); + } + strcpy(speech_tbl[meldungen].num1, buffer); + strcpy(mode_num,"00000000"); + speech_tbl[meldungen].mode = set_substitute_symbols(speech_tbl[meldungen].num1,mode_num); + strcpy(speech_tbl[meldungen].mode_num ,mode_num); + + if ((strncmp(speech_tbl[meldungen].default_mode_num,speech_tbl[meldungen].mode_num,7) == FALSE) + && (speech_tbl[meldungen].mode == speech_tbl[meldungen].default_mode)) + { + meldungen++; + } + else + { + printf("Fehler in Sprachdatei %s Zeile %d !!!",speech,meldungen); + fclose(fp); + return(FALSE); + } + } + fclose(fp); + } + if (meldungen-1 != MAXZEILEN) + { + printf("Fehler in Sprachdatei %s.txt, maximale Zeilenlaenge von %d unterschritten (letzte Melung %d)!!!\n",speech,MAXZEILEN,meldungen); + return(FALSE); + } + return(TRUE); +} + +void speech_init(void) +{ + struct ffblk dir; + char speechname[255]; + long erg,hfile; + char path[255]; + char *loc; + int i; + + if (sprachen == EOF) + speech_default(); + + sprachen = FALSE; + strcpy(path,speechpath); + addslash(path); + strcat(path,"*.txt"); + sprachen = 0; + + hfile = xfindfirst(path,&dir,0); + erg = (hfile == -1); + while (erg == 0) + { + strcpy(speechname,dir.ff_name); + loc = strstr(speechname,"."); + i = loc-speechname; + speechname[i] = '\0'; + strcpy(speech_tbl[sprachen].speech,speechname); + sprachen++; + erg = xfindnext(&dir); + } +} + +char *speech_message(int msgnum) +{ + if (*speech_tbl[msgnum].num1 == NUL) + printf("Fehler in Sprachdatei %s Zeile %d !!!",speech,msgnum); + +return speech_tbl[msgnum].num1; +} + +static unsigned set_substitute_symbols(const char *speechbuf, char *mode) +{ + unsigned char a[11] = "1234567890"; + unsigned num = 0x0; + int num_lX = 0; + int num_d = 0; + int num_ld = 0; + int num_f = 0; + unsigned num_s = 0; + int num_u = 0; + int num_lu = 0; + + while(*speechbuf) + { + if (strncmp(speechbuf,"%",1) == 0) + { + speechbuf++; + switch (*speechbuf) + { + case 'd': + num |= speech_mode_d; + mode[speech_mode_d_num] = a[num_d]; + num_d++; + break; + + case 'l': + { + speechbuf++; + if (strncmp(speechbuf,"d",1) == FALSE) + { + num |= speech_mode_ld; + mode[speech_mode_ld_num] = a[num_ld]; + num_ld++; + + break; + } + if (strncmp(speechbuf,"u",1) == FALSE) + { + num |= speech_mode_lu; + mode[speech_mode_lu_num] = a[num_lu]; + num_lu++; + break; + } + if (strncmp(speechbuf,"X",1) == FALSE) + { + num |= speech_mode_lX; + mode[speech_mode_lX_num] = a[num_lX]; + num_lX++; + break; + } + } + + case 'f': + num |= speech_mode_f; + mode[speech_mode_f_num] = a[num_f]; + num_f++; + break; + + case 's': + num |= speech_mode_s; + mode[speech_mode_s_num] = a[num_s]; + num_s++; + break; + + case 'u': + num |= speech_mode_u; + mode[speech_mode_u_num] = a[num_u]; + num_u++; + break; + } + } + speechbuf++; + } + +return(num); +} + +#endif diff --git a/src/update.c b/src/update.c new file mode 100755 index 0000000..8cc4a9c --- /dev/null +++ b/src/update.c @@ -0,0 +1,297 @@ +/************************************************************************/ +/* */ +/* ***** ***** */ +/* ***** ***** */ +/* ***** ***** */ +/* ***** ***** */ +/* *************** *************** */ +/* ***************** ***************** */ +/* *************** *************** */ +/* ***** ***** TheNetNode */ +/* ***** ***** Portable */ +/* ***** ***** Network */ +/* ***** ***** Software */ +/* */ +/* File src/update.c (maintained by: DF6LN) */ +/* */ +/* This file is part of "TheNetNode" - Software Package */ +/* */ +/* Copyright (C) 1998 - 2003 NORD>= 'A') && (*s <= 'Z')) + *s += 'a'-'A'; + s++; + } + return(p); +} +#endif + +/*----------------------------------------------------------------------*/ +/* */ +/* Einen Dateinamen normieren, d.h. er wird den Gegenheiten des */ +/* verwendeten Dateisystems angepasst. Die Informationen hierfuer */ +/* werden in ALL.H festgelegt. */ +/* */ +/*----------------------------------------------------------------------*/ +char * +normfname(char *filename) +{ + char *s; /* Zeiger innerhalb des Namens */ + + for (s = filename; *s; s++) /* alle Zeichen im String durchgehen */ + if (strchr(SEPARATORS, *s)) /* ein Dateitrennungszeichen ? */ + *s = FILE_SEP; /* dann durch das richtige ersetzen */ +#if (FILE_FLAGS & FF_LWR) + strlwr(filename); /* eventuell in Kleinschreibung... */ +#endif + return(filename); +} + +/*----------------------------------------------------------------------*/ +/* */ +/* Eine Datei oeffnen, es wird darauf geachtet, dass einige Betriebs- */ +/* systeme zwischen Textdateien und Binaerdateien unterscheiden. */ +/* normfname() wird zur Normierung des Dateinamens benutzt. */ +/* */ +/*----------------------------------------------------------------------*/ +FILE * +xfopen(const char *filename, const char *mode) +{ + char fmode[4], *fm; /* der angepasste Datei-Mode */ + char fname[MAXPATH+1]; + + strcpy(fname, filename); /* umkopieren, den Originalnamen */ + normfname(fname); /* nicht anfassen */ + + fm = fmode; + if (strchr(mode, 'w')) /* zum Schreiben */ + *fm++ = 'w'; + else if (strchr(mode, 'a')) /* zum Anhaengen */ + *fm++ = 'a'; + else + *fm++ = 'r'; /* sonst zum Lesen oeffnen */ +#if (FILE_FLAGS & FF_TXT) /* b/t-Flag uebernehmen? */ + if (strchr(mode, 'b')) /* eine Binaer-Datei? */ + *fm++ = 'b'; /* ... Flag uebernehmen */ +#ifndef MC68K + if (strchr(mode, 't')) /* eine Text-Datei? */ + *fm++ = 't'; /* ... Flag uebernehmen */ +#endif +#endif + if (strchr(mode, '+')) /* Ueberschreiben? */ + *fm++ = '+'; + + *fm = NUL; /* String terminieren */ + return(fopen(fname, fmode)); /* Datei oeffnen */ +} + +/************************************************************************/ +/* */ +/* Parameter-Befehl bearbeiten bei Vorgaengerversion 1.76: */ +/* */ +/* Par 2 war frueher Timeout und ist nun L3-Maxtime. Wenn als Zahl */ +/* oder mit Namen Timeout angegeben, wird die Zeile auskommentiert. */ +/* Par 10 war frueher Downport und ist entfallen. Zeile wird aus- */ +/* kommentiert. */ +/* Par 11 und 12 haben jetzt eine neue Nummer, weil Par 10 entfallen */ +/* ist. Mit Namen ausgeben. */ +/* */ +/************************************************************************/ +void +do_parms(const char *str) +{ + char *s1; + char *s2; + char *s3; + int i; + + s1 = strchr(str, ' '); /* Leerzeichen nach Befehl */ + if (!s1) /* keine Parameter angegeben */ + { + fputs(str, ofd); + return; + } + s1++; /* 1. Parameter */ + if (sscanf(s1, "%d", &i) != 1) /* Parameter als Nummer? */ + { + i = -1; + if (strnicmp(s1, "timeout", min(strlen(s1), 7)) == 0) + i = 2; + if (strnicmp(s1, "downport", min(strlen(s1), 8)) == 0) + i = 10; + } + switch (i) + { + case 11: + s2 = "TestSSID"; + s3 = strchr(s1, ' '); + fprintf(ofd, "PAR %s%s", s2, s3); + return; + case 12: + s2 = "ConvSSID"; + s3 = strchr(s1, ' '); + fprintf(ofd, "PAR %s%s", s2, s3); + return; + case 2: + case 10: + fputc(';', ofd); + break; + } + fputs(str, ofd); +} + +void +open_files(const char *ext) +{ +#ifdef __LINUX__ + struct stat istat; +#endif + + sprintf(outfile, "tnn178.%s", ext); + if (oldver != 176) + { + sprintf(infile, "tnn177.%s", ext); + ifd = xfopen(infile, "rt"); + if (oldver == 177 && ifd == NULL) + { + printf("Input file %s not found!\n", infile); + exit(1); + } + oldver = 177; + } + if (oldver != 177) + { + sprintf(infile, "tnn176.%s", ext); + ifd = xfopen(infile, "rt"); + if (ifd == NULL) + { + printf("Input file %s not found!\n", infile); + exit(1); + } + oldver = 176; + } + ofd = xfopen(outfile, "rt"); + if (ofd != NULL) + { + printf("Output file %s exists!\n", outfile); + fclose(ifd); + fclose(ofd); + exit(1); + } + ofd = xfopen(outfile, "wt"); + if (ofd == NULL) + { + printf("Open error %s\n", outfile); + fclose(ifd); + exit(1); + } +#ifdef __LINUX__ + if (fstat(fileno(ifd), &istat) == 0) + fchmod(fileno(ofd), istat.st_mode); +#endif +} + +void +copy(char *ext) +{ + int c; + + open_files(ext); + LOOP + { + c = fgetc(ifd); + if (c == EOF) + break; + fputc(c, ofd); + } + fclose(ifd); + fclose(ofd); +} + +int +main(int argc, char *argv[]) +{ + char str[256]; + char str2[256]; + + copy("pas"); + copy("sta"); + open_files("tnb"); + while (!feof(ifd)) + { + if (!fgets(str, 255, ifd)) + break; + sscanf(str, "%s", str2); + if (oldver == 176) + { + if (strnicmp(str2, "PARMS", min(strlen(str2), 5)) == 0) + { + do_parms(str); + continue; + } + } + fputs(str, ofd); + } + fclose(ifd); + fclose(ofd); + return(0); +} diff --git a/src/version.c b/src/version.c new file mode 100755 index 0000000..213ad8c --- /dev/null +++ b/src/version.c @@ -0,0 +1,121 @@ +/************************************************************************/ +/* */ +/* ***** ***** */ +/* ***** ***** */ +/* ***** ***** */ +/* ***** ***** */ +/* *************** *************** */ +/* ***************** ***************** */ +/* *************** *************** */ +/* ***** ***** TheNetNode */ +/* ***** ***** Portable */ +/* ***** ***** Network */ +/* ***** ***** Software */ +/* */ +/* File src/version.c (maintained by: ???) */ +/* */ +/* This file is part of "TheNetNode" - Software Package */ +/* */ +/* Copyright (C) 1998 - 2008 NORD> MAKEFILE Uebersetzer +CFLAGS+=-fexceptions -W +#wozu? CFLAGS+=-DWIN32 -D_CONSOLE -D_MBCS +# "patches" (sonst vanessa - schlechte definition in der linux.h) +CFLAGS+=-Ui386 +# debugging ein/aus +ifneq ($(DEBUGGING),on) +CFLAGS+=-O0 +#wozu? CFLAGS+=-DNDEBUG +else +CFLAGS+=-O0 -g +#wozu? CFLAGS+=-D_DEBUG +endif + +# Libraries +LIBS+=-lws2_32 -lwsock32 +LIBS+=-lkernel32 -luser32 -lgdi32 -lwinspool -lcomdlg32 -ladvapi32 +LIBS+=-lshell32 -lole32 -loleaut32 -luuid -lodbc32 -lodbccp32 + +BIN=os/win32/tnn32 +TARGET=$(BIN)/tnn32.exe + + +.PHONY: all contrib tnn clean cleantnn cleancontrib +all: tnn contrib +clean: cleantnn cleancontrib +tnn: $(TARGET) +contrib: $(BIN)/help.exe $(BIN)/msg.exe $(BIN)/msy.exe $(BIN)/pfhadd.exe $(BIN)/top.exe + + +%.o: %.c + $(CC) $(CFLAGS) -o $@ -c $< + +%.res: %.rc + $(RC) $(CPPFLAGS) $(RCFLAGS) --include-dir os/win32/tnn32 -o $@ -i $< + +RESSOURCENDATEIEN= \ + os/win32/tnn32/icon1.ico \ + os/win32/tnn32/tnn32.rc + +WIN32= \ + os/win32/sys/dirent32.c \ + os/win32/sys/dirent32.h \ + os/win32/sys/fnmatch.c \ + os/win32/sys/fnmatch.h \ + os/win32/sys/strings.c \ + os/win32/sys/strings.h \ + os/win32/6pack.c \ + os/win32/6pack.h \ + os/win32/ax25ip.c \ + os/win32/ax25ip.h \ + os/win32/init.c \ + os/win32/l1attach.c \ + os/win32/l1win32.c \ + os/win32/ostcpip.c \ + os/win32/osipconv.c \ + os/win32/win32.c \ + os/win32/win32.h \ + os/linux/linclude.h + +INCLUDE= \ + include/all.h \ + include/allmodif.h \ + include/conversd.h \ + include/cvs_cmds.h \ + include/function.h \ + include/global.h \ + include/host.h \ + include/icmp.h \ + include/ip.h \ + include/ipv.h \ + include/l1attach.h \ + include/l2.h \ + include/l2s.h \ + include/l3global.h \ + include/l3local.h \ + include/l3thenet.h \ + include/l4.h \ + include/l7.h \ + include/profiler.h \ + include/stat.h \ + include/system.h \ + include/tnn.h \ + include/typedef.h + +SRC= \ + src/buffer.c \ + src/callstr.c \ + src/cvs_cmds.c \ + src/cvs_cvrt.c \ + src/cvs_cvsd.c \ + src/cvs_serv.c \ + src/file.c \ + src/global.c \ + src/graph.c \ + src/l1tcpip.c \ + src/l1httpd.c \ + src/l1ipconv.c \ + src/l1telnet.c \ + src/l2dama.c \ + src/l2misc.c \ + src/l2rx.c \ + src/l2stma.c \ + src/l2timer.c \ + src/l2tx.c \ + src/l3inp.c \ + src/l3ip.c \ + src/l3misc.c \ + src/l3nbr.c \ + src/l3netrom.c \ + src/l3thenet.c \ + src/l3rtt.c \ + src/l3tab.c \ + src/l3var.c \ + src/l3vc.c \ + src/l3sock.c \ + src/l3tcp.c \ + src/l4.c \ + src/l7.c \ + src/l7ccp.c \ + src/l7cmds.c \ + src/l7conn.c \ + src/l7host.c \ + src/l7hstcmd.c \ + src/l7ip.c \ + src/l7moni.c \ + src/l7showl3.c \ + src/l7time.c \ + src/l7utils.c \ + src/main.c \ + src/mh.c \ + src/pacsat.c \ + src/pacserv.c \ + src/profil.c \ + src/profiler.c \ + src/speech.c \ + src/version.c + +SRCS=$(RESSOURCENDATEIEN) $(OS) $(LINUX) $(WIN32) $(INCLUDE) $(SRC) + +OBJS=$(patsubst %.rc,%.res,$(patsubst %.c,%.o,$(filter %.c %.cc %.cpp %.cxx %.rc,$(SRCS)))) + +HELPSRCS= \ + contrib/onlhelp/oh.c + +MSGSRCS= \ + os/win32/sys/dirent32.c \ + os/win32/sys/dirent32.h \ + os/win32/sys/fnmatch.c \ + os/win32/sys/fnmatch.h \ + contrib/msgmsy/msg_lin.c + +MSYSRCS= \ + os/win32/sys/dirent32.c \ + os/win32/sys/dirent32.h \ + os/win32/sys/fnmatch.c \ + os/win32/sys/fnmatch.h \ + contrib/msgmsy/msy_lin.c + +PACSRCS= \ + contrib/pfhadd/pfhadd.c + +TOPSRCS= \ + contrib/top/top_gnu.c + +HELPOBJS=$(patsubst %.rc,%.res,$(patsubst %.cxx,%.o,$(patsubst %.cpp,%.o,$(patsubst %.cc,%.o,$(patsubst %.c,%.o,$(filter %.c %.cc %.cpp %.cxx %.rc,$(HELPSRCS))))))) +MSGOBJS=$(patsubst %.rc,%.res,$(patsubst %.cxx,%.o,$(patsubst %.cpp,%.o,$(patsubst %.cc,%.o,$(patsubst %.c,%.o,$(filter %.c %.cc %.cpp %.cxx %.rc,$(MSGSRCS))))))) +MSYOBJS=$(patsubst %.rc,%.res,$(patsubst %.cxx,%.o,$(patsubst %.cpp,%.o,$(patsubst %.cc,%.o,$(patsubst %.c,%.o,$(filter %.c %.cc %.cpp %.cxx %.rc,$(MSYSRCS))))))) +PACOBJS=$(patsubst %.rc,%.res,$(patsubst %.cxx,%.o,$(patsubst %.cpp,%.o,$(patsubst %.cc,%.o,$(patsubst %.c,%.o,$(filter %.c %.cc %.cpp %.cxx %.rc,$(PACSRCS))))))) +TOPOBJS=$(patsubst %.rc,%.res,$(patsubst %.cxx,%.o,$(patsubst %.cpp,%.o,$(patsubst %.cc,%.o,$(patsubst %.c,%.o,$(filter %.c %.cc %.cpp %.cxx %.rc,$(TOPSRCS))))))) + + +$(BIN): +ifneq ($(wildcard $(BIN)), $(BIN)) + echo Creating directory $(BIN) + - mkdir $(BIN) +endif + + +$(TARGET): $(OBJS) $(BIN) + $(LD) $(LDFLAGS) -o $@ $(OBJS) $(LIBS) + +$(BIN)/help.exe: $(HELPOBJS) $(BIN) + $(LD) $(LDFLAGS) -o $@ $(HELPOBJS) $(LIBS) + +$(BIN)/msg.exe: $(MSGOBJS) $(BIN) + $(LD) $(LDFLAGS) -o $@ $(MSGOBJS) $(LIBS) + +$(BIN)/msy.exe: $(MSYOBJS) $(BIN) + $(LD) $(LDFLAGS) -o $@ $(MSYOBJS) $(LIBS) + +$(BIN)/pfhadd.exe: $(PACOBJS) $(BIN) + $(LD) $(LDFLAGS) -o $@ $(PACOBJS) $(LIBS) + +$(BIN)/top.exe: $(TOPOBJS) $(BIN) + $(LD) $(LDFLAGS) -o $@ $(TOPOBJS) $(LIBS) + + +cleantnn: + -rm -f $(OBJS) $(TARGET) + +cleancontrib: + -rm -f $(HELPOBJS) $(BIN)/help.exe + -rm -f $(MSGOBJS) $(BIN)/msg.exe + -rm -f $(MSYOBJS) $(BIN)/msy.exe + -rm -f $(PACOBJS) $(BIN)/pfhadd.exe + -rm -f $(TOPOBJS) $(BIN)/top.exe + +hardpatch: + -echo "!! WARNING !! EXPERIMENTAL !! DO NOT USE THIS OPTION !! (too late now)" + -find . \( -name '.svn' \) -exec rm -Rf {} \; + -find . \( -name '*.c' -o -name '*.h' \) -exec sed -ri 's/(^|[() *,;:])BOOLEAN([() *,;:]|$$)/\1BOOLEANN\2/g' {} \; + -find . \( -name '*.c' -o -name '*.h' \) -exec sed -ri 's/(^|[() *,;:])BYTE([() *,;:]|$$)/\1BYTEE\2/g' {} \; + -find . \( -name '*.c' -o -name '*.h' \) -exec sed -ri 's/(^|[() *,;:])WORD([() *,;:]|$$)/\1WORDD\2/g' {} \; + -find . \( -name '*.c' -o -name '*.h' \) -exec sed -ri 's/(^|[() *,;:])WORD([() *,;:]|$$)/\1WORDD\2/g' {} \; +