/************************************************************************/ /* */ /* ***** ***** */ /* ***** ***** */ /* ***** ***** */ /* ***** ***** */ /* *************** *************** */ /* ***************** ***************** */ /* *************** *************** */ /* ***** ***** 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 */