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