home *** CD-ROM | disk | FTP | other *** search
/ Hacker Chronicles 2 / HACKER2.BIN / 544.TNL4.C < prev    next >
Text File  |  1988-05-14  |  28KB  |  659 lines

  1. /*****************************************************************************/
  2. /*                                              */
  3. /*                                         */
  4. /*    *****              *****                      */
  5. /*     *****            *****                         */
  6. /*       *****          *****                         */
  7. /*         *****        *****                         */
  8. /*  ***************      ***************                     */
  9. /*  *****************    *****************                     */
  10. /*  ***************      ***************                     */
  11. /*         *****        *****       TheNet                    */
  12. /*       *****          *****       Portable. Compatible.         */
  13. /*     *****            *****       Public Domain             */
  14. /*    *****              *****    NORD><LINK                  */
  15. /*                                         */
  16. /* This software is public domain ONLY for non commercial use                */
  17. /*                                                                           */
  18. /*                                         */
  19. /*****************************************************************************/
  20.  
  21. /* Level 4, Transport
  22. /* Version 1.01                                     */
  23. /* Hans Georg Giese, DF2AU, Hinter dem Berge 5, 3300 Braunschweig         */
  24. /* 01-MAY-88                                     */
  25.  
  26. # include "tndef.h"        /* Definition von Konstanten             */
  27. # include "tntyp.h"        /* Definition der Typen                 */
  28. # include "tnl4v.c"        /* Defintion der globalen Variablen         */
  29. # include "tnl4e.h"        /* Externe Definitionen                 */
  30.  
  31. /*---------------------------------------------------------------------------*/
  32. VOID    initl4()            /* Level 4 initialisieren         */
  33.  {
  34.   unsigned cnt;                /* Sratch Zaehler             */
  35.  
  36.   inithd(&l4rxfl);            /* Liste fuer empfangene Frames         */
  37.  
  38.   for (cnt = 0, cirpoi = cirtab;    /* gesamte Circuit Tabelle         */
  39.        cnt < NUMCIR;                    /* bearbeiten                 */
  40.        ++cnt, ++cirpoi)
  41.    {
  42.     cirpoi->state3 =            /* Eintrag ist leer             */
  43.     cirpoi->numrx  =            /* keine Frames empfangen         */
  44.     cirpoi->numtx  = 0;            /* keine Frames zu senden         */
  45.     cirpoi->fragme = NULL;        /* kein Frame Fragment da         */
  46.     inithd(&cirpoi->mbhdrx);        /* Empfangskette ist leer         */
  47.     inithd(&cirpoi->mbhdtx);        /* Sendekette ist leer             */
  48.     inithd(&cirpoi->mbhdos);        /* Kette "ausser Reihenfolge" leer   */
  49.    }
  50.  
  51.   if (! iswarm())            /* im Kaltstart Standardwerte         */
  52.    {
  53.     tratou = DEFTTO;            /* Timeout                 */
  54.     tratri = DEFTTR;            /* Versuche                 */
  55.     traack = DEFTAC;            /* ACK Wartezeit             */
  56.     trabsy = DEFTBS;            /* Busy Wartezeit             */
  57.     trawir = DEFTWI;            /* Fenstergroesse             */
  58.    }
  59.  }
  60.  
  61. /*---------------------------------------------------------------------------*/
  62. VOID    l4serv()        /* Level 4 Service                 */
  63.   {
  64.   l4tx();            /* Frames senden                 */
  65.   l4rx();            /* Frames empfangen                 */
  66.   l4rest();            /* sonstige Funktionen                 */
  67.   }
  68.  
  69. /*---------------------------------------------------------------------------*/
  70. VOID    l4tx()            /* Frames senden                 */
  71.   {
  72.   unsigned unack;        /* unbestaetigte Frames                 */
  73.   unsigned cnt;            /* Sratch Zaehler                 */
  74.   unsigned isweg;        /* schon gesendete Frames             */
  75.   mhtyp       *nxtfra;        /* naechstes Frame                 */
  76.  
  77.   for (cnt = 0, cirpoi = cirtab;/* gesamte Circuittabelle             */
  78.        cnt < NUMCIR;
  79.        ++cnt, ++cirpoi) {
  80.     if ((cirpoi->state3 == 2)    /* Eintrag ist connected             */
  81.       && (!(cirpoi->l4flag & 0x20)) /* und Partner nicht choked             */
  82.       && ((unack = (cirpoi->l4vs - cirpoi->l4rxvs) & 0xff) < cirpoi->numtx)
  83.       && (unack < cirpoi->window)) { /* Fenstergroesse nicht erreicht         */
  84.       for (isweg = 0, nxtfra = (mhtyp *) cirpoi->mbhdtx.lnext; /* neue Frames*/
  85.            isweg < unack;    /* schon gesendete offene Frames uebergehen  */
  86.            ++isweg, nxtfra = (mhtyp *) nxtfra->link.lnext);
  87.       do {
  88.         nxtfra->l4trie = 0;    /* Versuche := 0                 */
  89.         sndfrm(cirpoi->l4vs++, nxtfra); /* naechstes Frame senden         */
  90.         nxtfra = (mhtyp *) nxtfra->link.lnext; /* vorruecken              */
  91.         }
  92.       while ((++unack < cirpoi->numtx) /* bis Ende der Kette             */
  93.         && (cirpoi->window > unack)); /* oder Fenstergroesse ueberschritten  */
  94.       }
  95.     }
  96.   }
  97.  
  98. /*---------------------------------------------------------------------------*/
  99. VOID    l4rx()            /* Frames empfangen                 */
  100.   {
  101.   char       usrcal[7];        /* Call des Users                 */
  102.   char       orgnod[7];        /* Call des absendenden Knotens             */
  103.   unsigned fenste;        /* Fenstergroesse                 */
  104.   unsigned cnt;            /* Scratch Zaehler                 */
  105.   mhtyp       *nxtfra;        /* naechstes Frame                 */
  106.   mhtyp       *antwor;        /* Antwort auf Frame                 */
  107.   cirtyp   *cirent;        /* CIRTAB Eintrag des Users             */
  108.  
  109.   while ((nxtfra = (mhtyp *) l4rxfl.lnext) != (mhtyp *) &l4rxfl.lnext) {
  110.     unlink(nxtfra);        /* Frame aus Kette loesen             */
  111.     if ((nxtfra->putcnt - nxtfra->getcnt) >= 5) { /* lang genug?         */
  112.       l4hdr0 = getchr(nxtfra);    /* Header holen                     */
  113.       l4hdr1 = getchr(nxtfra);
  114.       l4hdr2 = getchr(nxtfra);
  115.       l4hdr3 = getchr(nxtfra);
  116.       if (((l4opco = getchr(nxtfra)) & 0x07) != 0x01) { /* CONREQ immer gut  */
  117.         if ((l4hdr0 < NUMCIR)    /* Index im Bereich?                 */
  118.           && ((cirpoi = &cirtab[l4hdr0])->state3 != 0)
  119.           && (cirpoi->ideige == l4hdr1)) {
  120.           l4pidx = cirpoi->idxpar;
  121.           l4pcid = cirpoi->idpart;
  122.           }
  123.         else {            /* schlechter Header                 */
  124.           dealmb(nxtfra);    /* Frame vernichten                 */
  125.           continue;
  126.           }
  127.         }
  128.       switch (l4opco & 0x07) {    /* ueber Opcode verzweigen             */
  129. /*=============================*/
  130. case 1:                /* Connect Request                 */
  131.   if (((nxtfra->putcnt - nxtfra->getcnt) >= 15) /* Frame lang genug?         */
  132.     && ((fenste = getchr(nxtfra) & 0xff) != 0) /* Fenster muss angegeben sein*/
  133.     && (getfid(usrcal, nxtfra) == 1) /* gueltiges Usercall             */
  134.     && (getfid(orgnod, nxtfra) == 1) /* gueltiger Absender             */
  135.     && (seades(orgnod) == 1)) {    /* Absender bekannt                 */
  136.     l4pidx = l4hdr0;        /* Index und                     */
  137.     l4pcid = l4hdr1;        /* ID des Partners merken             */
  138.     for (cirent = 0, cnt = 0, cirpoi = cirtab; /* Circuit Tabelle absuchen   */
  139.          cnt < NUMCIR;
  140.          ++cnt, ++cirpoi) {
  141.       if (cirpoi->state3 != 0) {
  142.         if ((cmpid(usrcal, cirpoi->upcall) == 1)
  143.           && (cmpid(orgnod, cirpoi->downca) == 1)) {
  144.           if ((cirpoi->idxpar == l4hdr0)
  145.             && (cirpoi->idpart == l4hdr1)) break;
  146.             }
  147.           }
  148.       else {
  149.         if (cirent == 0) cirent = cirpoi;
  150.         }
  151.       }
  152.     if (cnt == NUMCIR) {    /* Ende der Tabelle erreicht?             */
  153.       if ((cirent != 0)        /* freien Platz gefunden?             */
  154.         && (fvalca(VCpar, usrcal) == 1)) { /* User Call gueltig?         */
  155.         cirpoi = cirent;    /* dann Eintrag nehmen                 */
  156.         cpyid(cirpoi->upcall, usrcal); /* Call eintragen             */
  157.         cpyid(cirpoi->downca, orgnod);
  158.         cirpoi->idxpar = l4hdr0; /* Parameter des Partnerknotens         */
  159.         cirpoi->idpart = l4hdr1;
  160.         cirpoi->ideige = random(); /* eigener ID                 */
  161.         cirpoi->l3node = despoi; /* Nachbar fuer den Eintrag             */
  162.         l2tol7(1, cirpoi, 4);    /* UA von Circuit nach zurueck             */
  163.         cirpoi->tranoa = ininat; /* Timeout setzen                 */
  164.         }
  165.       else {            /* kein Platz - ungueltiges Call         */
  166.         l4ahd2 =        /* Antwort aufbauen                 */
  167.         l4ahd3 = 0;
  168.         l4aopc = 0x82;        /* Opcode = choked, Acknowledge             */
  169.         (antwor = gennhd())->l2lnk = (l2ltyp *) despoi; /* Antwort aufbauen  */
  170.         relink(antwor, l3txl.lprev); /* in Sendekette haengen             */
  171.         break;
  172.         }
  173.       }                               /* Eintrag gibt es schon         */
  174.     cirpoi->window = (fenste > trawir)? trawir : fenste;
  175.     clrcir();                           /* Eintrag initialisieren     */
  176.     l4ahd2 = (cirpoi - &cirtab[0]);
  177.     l4ahd3 = cirpoi->ideige;                   /* eigene Parameter setzen    */
  178.     l4aopc = 0x02;                       /* Antwort wird ACK         */
  179.     putchr(cirpoi->window, (antwor = gennhd()));
  180.     itol3(antwor);                       /* senden             */
  181.     cirpoi->state3 = 2;                           /* Status = connected         */
  182.     }
  183.   break;
  184.  
  185. /*=============================*/
  186. case 2:                /* Connect Acknowledge                 */
  187.   if (cirpoi->state3 == 1) {    /* macht nur Sinn, wenn Connect verlangt     */
  188.     if ((l4opco & 0x80) == 0) {    /* Partner darf nicht choked sein         */
  189.       if (nxtfra->getcnt < nxtfra->putcnt) { /* noch Info da?             */
  190.         cirpoi->window = getchr(nxtfra); /* holen                 */
  191.         cirpoi->idpart = l4hdr3; /* Partner Parameter setzen             */
  192.         cirpoi->idxpar = l4hdr2;
  193.         clrcir();        /* Eintrag initialisieren             */
  194.         l2tol7(1, cirpoi, 4);    /* Antwort ist UA vom Circuit             */
  195.         cirpoi->tranoa = ininat; /* Timeout setzen                 */
  196.         cirpoi->state3 +=1;    /* Status = connected                 */
  197.         }
  198.       }
  199.     else {            /* Partner ist choked                 */
  200.       l4nsta(3);        /* melden                     */
  201.       }
  202.     }
  203.   break;
  204.  
  205. /*=============================*/
  206. case 3:                /* Disconnect Request                 */
  207.   clr4rx(1);            /* restliche Info senden             */
  208.   l4nsta(2);            /* nach oben melden                 */
  209.   l4ahd2 =
  210.   l4ahd3 = 0;            /* Antwort aufbauen                 */
  211.   l4aopc = 0x04;        /* Opcode = Disconnect ACK             */
  212.   itol3(gennhd());        /* Frame senden                     */
  213.   break;
  214.  
  215. /*=============================*/
  216. case 4:                /* Disconnect Acknowledge             */
  217.   if (cirpoi->state3 == 3) {    /* wurde DISC gegeben?                 */
  218.     l4nsta(2);            /* melden                     */
  219.     }
  220.   break;
  221.  
  222. /*=============================*/
  223. case 5:                /* Info Transfer                 */
  224.   if (cirpoi->state3 != 2)    /* nur wenn connected                 */
  225.     break;
  226.   chksts();            /* Status Info auswerten             */
  227.   if (((nxtfra->pid = (l4hdr2 - cirpoi->l4vr) & 0xff) < cirpoi->window)
  228.     && ((cirpoi->l4flag & 0x40) == 0)) { /* passt das Frame ins Fenster?     */
  229.     nxtfra->morflg = (l4opco & 0x20) != 0; /* fragmentiert?             */
  230.     if (nxtfra->pid == 0) {    /* passt Sequenz?                 */
  231.       takfrm(nxtfra);        /* Frame uebernehmen                 */
  232.       for (cnt = 1, antwor = (mhtyp *) cirpoi->mbhdos.lnext; /* Frames,      */
  233.         (mhtyp *) &(cirpoi->mbhdos) != antwor; /* die zu frueh kamen, absu-  */
  234.            antwor = (mhtyp *) antwor->link.lnext) { /* chen, ob nun passt    */
  235.         if ((antwor->pid -=cnt) == 0) { /* neuer Offset              */
  236.           nxtfra = (mhtyp *) antwor->link.lprev; /* Frame passt bei Offset 0 */
  237.           takfrm(unlink(antwor)); /* Frame aus Kette nehmen und verwerten    */
  238.           antwor = nxtfra;
  239.           ++cnt;        /* zulaessiger Offset eins weiter         */
  240.           }
  241.         }
  242.       cirpoi->l4rs = 0;    /* Antwort wird ACK                     */
  243.       cirpoi->acktim = traack;    /* ACK Timer laden                 */
  244.       }
  245.     else {            /* Sequenz passt nicht                 */
  246.       for (antwor = (mhtyp *) cirpoi->mbhdos.lnext;;)
  247.        {                                /* in extra Kette haengen         */
  248.         if ((mhtyp *) &(cirpoi->mbhdos) == antwor) { /* Ende der Kette?         */
  249.           relink(nxtfra, cirpoi->mbhdos.lprev); /* dann einhaengen         */
  250.           break;
  251.           }
  252.         if (antwor->pid == nxtfra->pid) { /* Frame schon mal angekommen?     */
  253.           dealmb(nxtfra);    /* dann wegwerfen                 */
  254.           break;
  255.           }
  256.         if (antwor->pid > nxtfra->pid) { /* an passender Stelle einhaengen   */
  257.           relink(nxtfra, antwor->link.lprev);
  258.           break;
  259.           }
  260.         antwor = (mhtyp *) antwor->link.lnext; /* ein Frame weiter         */
  261.         }
  262.       if (cirpoi->l4rs == 0) {    /* Frame haengt in extra Kette             */
  263.         cirpoi->l4rs = 1;        /* wenn ACK gefordert war, nun NAK   */
  264.         cirpoi->acktim = traack;    /* ACK Wartezeit setzen             */
  265.         }
  266.       }
  267.     continue;            /* naechstes Frame                 */
  268.     }
  269.   else                /* ungueltiges Frame oder selbst choked         */
  270.     cirpoi->acktim = traack;    /* Antwort hat Zeit                 */
  271.   break;
  272.  
  273. /*=============================*/
  274. case 6:                /* Info Acknowledge                 */
  275.   if (cirpoi->state3 == 2)    /* nur sinnvoll, wenn connected             */
  276.     chksts();            /* enthaltene Statusinfo auswerten         */
  277.   break;
  278.  
  279. /*=============================*/
  280. default:            /* ungueltiger Opcode                 */
  281.   break;            /* uebergehen                     */
  282.  
  283. /*=============================*/
  284.       } }            /* Ende des Switch ueber Opcode             */
  285.     dealmb(nxtfra);        /* fertig bearbeitet, wegwerfen             */
  286.   } }
  287.  
  288. /*---------------------------------------------------------------------------*/
  289. VOID    l4rest()        /* diverse Level4 Funktionen             */
  290.   {
  291.   unsigned cnt;            /* Scratch Zaehler                 */
  292.  
  293.   for (cnt = 0, cirpoi = cirtab; /* gesamte Tabelle bearbeiten             */
  294.        cnt < NUMCIR;
  295.        ++cnt, ++cirpoi) {
  296.     if (cirpoi->state3 == 2) {    /* nur fuer connectete Eintrage             */
  297.       if (((cirpoi->l4flag & 0x80) != 0) /* Abwurf gefordert             */
  298.         && (cirpoi->numtx == 0)) { /* und alles gesendet?             */
  299.         endcir();        /* Eintrag loeschen                 */
  300.         }
  301.       else {
  302.         clr4rx(0);        /* kein Abwurf gefordert: Info senden         */
  303.         if ((cirpoi->l4flag & 0x40) == 0) { /* selbst choked?             */
  304.           if ((nmbfre < 80)    /* nein: kein Platz im Buffer?             */
  305.             || (cirpoi->numrx >= conctl)) { /* oder zu viel empfangen?         */
  306.             cirpoi->l4flag |= 0x40; /* dann selbst choked setzen         */
  307.             cirpoi->l4rs = 0;    /* ACK als naechste Antwort             */
  308.             sndack();
  309.             }
  310.           }
  311.         else {
  312.           if ((nmbfre > 112)    /* selbst choked: wieder Platz im Buffer?    */
  313.             && (cirpoi->numrx < (conctl / 2))) { /* und Datenstau abgebaut?  */
  314.             cirpoi->l4flag &= 0xffbf; /* dann choked ruecksetzen         */
  315.             sndack();        /* melden                     */
  316.           } }
  317.       } }
  318.   } }
  319.  
  320. /*---------------------------------------------------------------------------*/
  321. VOID    trasrv()        /* Timerservice fuer Level 4             */
  322.   {
  323.   unsigned actsts;        /* Status des aktuellen Eintrages         */
  324.   unsigned fropen;        /* Zahl der unbestaetigten Frames         */
  325.   unsigned cnt;            /* Scratch Zaehler                 */
  326.   unsigned tosend;        /* Zahl der zu sendenden Frames             */
  327.   mhtyp       *nxtfra;        /* aktuelles Frame                 */
  328.  
  329.   for (cnt = 0, cirpoi = cirtab; /* gesamte Tabelle bearbeiten             */
  330.        cnt < NUMCIR;
  331.        ++cnt, ++cirpoi) {
  332.     if ((actsts = cirpoi->state3) != 0) { /* nur aktive Eintraege         */
  333.       if (cirpoi->traout != 0) { /* Timeout noch nicht abgelaufen         */
  334.         if (--cirpoi->traout == 0) { /* Timeout nun abgelaufen?             */
  335.           if (actsts == 2)    /* Status = connected?                 */
  336.             cirpoi->l4flag &= 0xffdf; /* nichts neues senden             */
  337.           else {        /* anderer Status:                 */
  338.             if (++cirpoi->l4try < tratri) /* noch mal versuchen?         */
  339.               (actsts == 1)? sconrq() : sdisrq(); /* ja                 */
  340.             else l4nsta(4);    /* Fehler melden                 */
  341.             }
  342.         } }
  343.       else {            /* Timeout ist schon 0                 */
  344.         if ((actsts == 2)    /* connectet und Frames unbestaetigt?         */
  345.           && ((fropen = (cirpoi->l4vs - cirpoi->l4rxvs) & 0xff) != 0)) {
  346.           for (tosend = 0, nxtfra = (mhtyp *) cirpoi->mbhdtx.lnext;
  347.              tosend < fropen;    /* Frames wiederholen                 */
  348.              ++tosend, nxtfra = (mhtyp *) nxtfra->link.lnext) {
  349.             if (--nxtfra->l4time == 0) { /* wenn Timeout abgelaufen         */
  350.               if (++nxtfra->l4trie < tratri) /* und noch Versuche frei         */
  351.                 sndfrm(nxtfra->pid, nxtfra);
  352.               else {
  353.                 l4nsta(4);    /* sonst melden                     */
  354.                 break;
  355.                 }
  356.               }
  357.             }
  358.           }
  359.         }
  360.       if (actsts == 2) {    /* connectet?                     */
  361.         if ((cirpoi->acktim != 0)
  362.           && (--cirpoi->acktim == 0)) /* ACK-Timer gerade abgelaufen?         */
  363.           sndack();        /* dann ACK senden                 */
  364.         if ((cirpoi->tranoa != 0)
  365.           && (--cirpoi->tranoa == 0)) /* No-activity-Timeout abgelaufen?     */
  366.           endcir();        /* dann abwerfen                 */
  367.         }
  368.   } } }
  369.  
  370. /*---------------------------------------------------------------------------*/
  371. VOID    newcir()        /* neuen Circuit aufbauen             */
  372.   {
  373.   clrcir();            /* Eintrag in CIRTAB loeschen             */
  374.   cirpoi->ideige = random();    /* eigenen ID erzeugen                 */
  375.   cirpoi->l4try = 0;        /* Versuche = 0                     */
  376.   sconrq();            /* Connect Request senden             */
  377.   cirpoi->state3 = 1;        /* neuer Status                     */
  378.   }
  379.  
  380. /*---------------------------------------------------------------------------*/
  381. VOID    discir()        /* Circuit aufloesen                 */
  382.   {
  383.   if ((cirpoi->state3 == 1)    /* Status CON-REQ?                 */
  384.     || (cirpoi->state3 == 3))    /* oder DIS-REQ?                 */
  385.     l4nsta(0);            /* nicht nach oben, nur intern melden         */
  386.  
  387.   else {            /* connectet:                     */
  388.     kilfra();            /* alle Fragmente loeschen             */
  389.     dealml(&cirpoi->mbhdrx);    /* empfangene Frames loesschen             */
  390.     cirpoi->numrx = 0;
  391.     cirpoi->l4flag |= 0x80;    /* Abwurf einleiten                 */
  392.     }
  393.   }
  394.  
  395. /*---------------------------------------------------------------------------*/
  396. BOOLEAN    itocir(cflg, mbhd)    /* Info an Circuit senden             */
  397.   mhtyp       *mbhd;        /* Message Header                 */
  398.   unsigned cflg;        /* Congestion Flag                 */
  399.   {
  400.   cirtyp *cblk;            /* Kontrollblock                 */
  401.  
  402.   if (((cblk = (cirtyp *) mbhd->l2lnk)->numtx < conctl)        /* Platz?    */
  403.     || (cflg == 1))                    /* immer senden?     */
  404.     {
  405.       relink(unlink(mbhd), cblk->mbhdtx.lprev);     /* Info umhaengen    */
  406.       ++cblk->numtx;                    /* Frames zaehlen    */
  407.       mbhd->morflg = 0;                    /* Frame komplett    */
  408.       cblk->tranoa = ininat;                /* Timeout neu         */
  409.       return(TRUE);                    /* hat funktioniert  */
  410.     }
  411.   else return(FALSE);                    /* Fehler, ging nicht*/
  412.   }
  413.  
  414. /*---------------------------------------------------------------------------*/
  415. VOID    clr4rx(cflg)        /* restliche Info senden             */
  416.   unsigned cflg;        /* Congestion Flag                 */
  417.   {
  418.   mhtyp     *mbhd;            /* Message Header                 */
  419.  
  420.   while (cirpoi->numrx != 0) {    /* ein Frame nach dem anderen             */
  421.     (mbhd = (mhtyp * )cirpoi->mbhdrx.lnext)->l2lnk = (l2ltyp *)cirpoi;
  422.     mbhd->usrtyp = 4;        /* User ist Circuit                 */
  423.     if (fmlink(cflg, mbhd) == 0) break; /* Ende bei Fehler             */
  424.     cirpoi->tranoa = ininat;    /* Timeout setzen                 */
  425.     --cirpoi->numrx;        /* ein Frame ist weg                 */
  426.     }
  427.   }
  428.  
  429. /*---------------------------------------------------------------------------*/
  430. VOID    chksts()        /* Status des eingelaufenen Frames auswerten */
  431.   {
  432.   unsigned frofs;        /* bestaetigter Offset                 */
  433.   unsigned fropen;        /* unbestaetigte Frames                 */
  434.  
  435.   if ((
  436.     fropen = (cirpoi->l4vs - cirpoi->l4rxvs) & 0xff
  437.     ) != 0) {            /* Frames offen?                 */
  438.     if ((
  439.       frofs = (l4hdr3 - cirpoi->l4rxvs) & 0xff /* neu bestaetigte Frames     */
  440.       ) != 0) {
  441.       if (frofs <= fropen) {
  442.         while (frofs-- != 0) {
  443.           dealmb(unlink(cirpoi->mbhdtx.lnext));   /* koennen weg         */
  444.           --cirpoi->numtx;    /* eins weniger zu senden             */
  445.           ++cirpoi->l4rxvs;    /* eins mehr bestaetigt                 */
  446.     } } } }
  447.   if ((l4opco & 0x80) == 0) {    /* Partner choked?                 */
  448.     cirpoi->l4flag &= 0xffdf;    /* nein: merken                     */
  449.     cirpoi->traout = 0;        /* Timeout kann nicht kommen             */
  450.     if (((l4opco & 0x40) != 0)    /* NAK Flag?                     */
  451.       && (cirpoi->l4vs != cirpoi->l4rxvs)) /* und noch was offen?         */
  452.       sndfrm(cirpoi->l4rxvs, cirpoi->mbhdtx.lnext);      /* dann wiederholen */
  453.     }
  454.   else {            /* Partner ist choked                 */
  455.     cirpoi->l4flag |= 0x20;    /* merken                     */
  456.     cirpoi->traout = trabsy;    /* warten                     */
  457.     cirpoi->l4vs = cirpoi->l4rxvs; /* keine Frames offen             */
  458.     }
  459.   }
  460.  
  461. /*---------------------------------------------------------------------------*/
  462. VOID    takfrm(mbhd)        /* empfangenes Frame uebernehmen         */
  463. mhtyp     *mbhd;
  464.   {
  465.   char     *nxt1;        /* naechstes Zeichen des ersten Teils         */
  466.   unsigned get1;        /* Getcount des ersten Teils             */
  467.   unsigned more;        /* Frame ist auch nur Fragment             */
  468.   mhtyp    *fragmn;        /* Fragment des Frames                 */
  469.  
  470.   if ((cirpoi->l4flag & 0x80) == 0) { /* liegt DISC-REQ vor?             */
  471.     if ((fragmn = cirpoi->fragme) == NULL) { /* noch kein Fragment vorhanden */
  472.       if (mbhd->morflg == 1) {    /* ist dies ein Fragment?             */
  473.         cirpoi->fragme = mbhd;    /* dann nur merken                 */
  474.         mbhd = NULL;        /* Frame ist weg                 */
  475.       } }
  476.     else {            /* Fragment schon vorhanden             */
  477.       nxt1 = fragmn->nxtchr;    /* altes Ende merken                 */
  478.       get1 = fragmn->getcnt;
  479.       while (fragmn->getcnt < fragmn->putcnt)
  480.         getchr(fragmn);        /* auf Ende des ertsen Teils gehen         */
  481.       while (mbhd->getcnt < mbhd->putcnt)
  482.         putchr(getchr(mbhd), fragmn); /* neues Frame anhaengen             */
  483.       fragmn->nxtchr = nxt1;    /* Pointer wieder auf alten Stand         */
  484.       fragmn->getcnt = get1;
  485.       more = mbhd->morflg;    /* kommt noch mehr?                 */
  486.       dealmb(mbhd);        /* neuer Teil kann weg                 */
  487.       if (more == 0) {        /* nichts mehr im Rohr?                 */
  488.         mbhd = fragmn;        /* dann ist das Ergebniss die neue Summe     */
  489.         cirpoi->fragme = 0;    /* kein Fragment mehr da             */
  490.         }
  491.       else mbhd = 0;        /* es kommt noch was: Fragment bleibt         */
  492.       }
  493.     if (mbhd != 0) {        /* Frame noch da?                 */
  494.       relink(mbhd, cirpoi->mbhdrx.lprev);      /* dann in RX Liste haengen   */
  495.       ++cirpoi->numrx;        /* ein Frame mehr da                 */
  496.       }
  497.     }
  498.   else {            /* Kanal soll abgeworfen werden             */
  499.     dealmb(mbhd);        /* Frame vernichten                 */
  500.     }
  501.   ++cirpoi->l4vr;        /* RX-Sequenz erhoehen                 */
  502.   }
  503.  
  504. /*---------------------------------------------------------------------------*/
  505. VOID    sndfrm(txsequ, mbhd)    /* Frame senden                     */
  506. mhtyp     *mbhd;            /* Info                         */
  507. unsigned txsequ;        /* Sendesequenz fuer L4                 */
  508.   {
  509.   char     *next;            /* Pointer auf letztes Zeichen des Headers   */
  510.   mhtyp     *netmhd;        /* Netzwerk MBHD                      */
  511.  
  512.   l4ahd2 =            /* VS in Netzwerkheader                 */
  513.   mbhd->pid = txsequ;        /* VS als PID                     */
  514.   l4aopc = 5;            /* Opcode = Info                 */
  515.   ackhdr();            /* Rest des Headers erzeugen             */
  516.   next =
  517.   (netmhd = gennhd())        /* Buffer fuer Netzwerkframe holen         */
  518.           ->nxtchr;        /* Position Opcode merken (eins davor)         */
  519.   if ((
  520.     splcpy((256 - netmhd->putcnt), netmhd, mbhd) /* Info umkopieren         */
  521.     ) == 1) {            /* hat alles reingepasst?             */
  522.     ++cirpoi->numtx;        /* neun: ein Frame mehr                 */
  523.     mbhd->morflg = TRUE;    /* Fragmentierung markieren             */
  524.     }
  525.   if (mbhd->morflg == TRUE)
  526.     *(next -1) |= 0x20;        /* MORE Flag im Opcode setzen             */
  527.   itol3(netmhd);        /* Frame an Level3 liefern             */
  528.   mbhd->l4time = tratou;    /* Timeout im Infoframe setzen             */
  529.   }
  530.  
  531. /*---------------------------------------------------------------------------*/
  532. VOID    l4nsta(frtyp)        /* Statusaenderung in Level4             */
  533. char    frtyp;            /* als Reaktion auf : 0=intern, 1=UA, 2=DISC */
  534.   {                /* 3=DM, 4=L4-Versuche abgelaufen         */
  535.   clrcir();            /* alle Pointer im Eintrag loeschen         */
  536.   if (frtyp != 0) {        /* nach oben melden?                 */
  537.     l2tol7(frtyp, cirpoi, 4);    /* meldender User ist der Circuit         */
  538.     }
  539.   dealml(&cirpoi->mbhdrx);    /* keine Frames empfangen             */
  540.   dealml(&cirpoi->mbhdtx);    /* keine Frames zu senden             */
  541.   cirpoi->numrx =        /* Emfangsliste ist leer             */
  542.   cirpoi->numtx =        /* Sendeliste ist leer                 */
  543.   cirpoi->state3 = 0;        /* Status = Eintrag ist leer             */
  544.   }
  545.  
  546. /*---------------------------------------------------------------------------*/
  547. VOID    endcir()        /* Circuit aufloesen                 */
  548.   {
  549.     clrcir();            /* Eintrag in CIRTAB loeschen             */
  550.     cirpoi->l4try = 0;        /* Versuche ruecksetzen                 */
  551.     sdisrq();            /* Abwurf einleiten                 */
  552.     cirpoi->state3 = 3;        /* neuer Status: DISC-REQ gegeben         */
  553.   }
  554.  
  555. /*---------------------------------------------------------------------------*/
  556. VOID    clrcir()        /* Eintrag in CIRTAB loeschen             */
  557.   {
  558.   kilfra();            /* Fragmente loeschen                 */
  559.   dealml(&cirpoi->mbhdos);    /* Messageliste dafuer auch             */
  560.   cirpoi->l4rxvs =        /* alle Sequenzen auf 0                 */
  561.   cirpoi->l4vs =
  562.   cirpoi->l4vr =
  563.   cirpoi->l4rs =        /* ACK-NAK Flag                     */
  564.   cirpoi->traout =        /* Timeout                     */
  565.   cirpoi->l4flag = 0;        /* niemand choked, kein DISC-REQ         */
  566.   }
  567.  
  568. /*---------------------------------------------------------------------------*/
  569. VOID    sconrq()        /* CON-REQ senden                 */
  570.   {
  571.   mhtyp    *mbhd;            /* Buffer fuer Frame                 */
  572.  
  573.   l4pidx = cirpoi - &cirtab[0];    /* Index setzen                     */
  574.   l4pcid = cirpoi->ideige;    /* Partner und eigener Index             */
  575.   l4ahd2 =            /* zwei Bytes leer                 */
  576.   l4ahd3 = 0;
  577.   l4aopc = 1;            /* Opcode                     */
  578.   putchr (trawir, (mbhd = gennhd())); /* Rest des Headers             */
  579.   putfid(cirpoi->upcall, mbhd);    /* beide Calls in das Frame             */
  580.   putfid(myid, mbhd);
  581.   itol3(mbhd);            /* an Level3 liefern                 */
  582.   cirpoi->traout = tratou;    /* Timeout setzen                 */
  583.   }
  584.  
  585. /*---------------------------------------------------------------------------*/
  586. VOID    sdisrq()        /* DISC-REQ senden                 */
  587.   {
  588.   l4pidx = cirpoi->idxpar;    /* Index setzen                     */
  589.   l4pcid = cirpoi->idpart;    /* und ID                     */
  590.   l4ahd2 =            /* zwei Bytes leer                 */
  591.   l4ahd3 = 0;
  592.   l4aopc = 3;            /* Opcode                     */
  593.   itol3(gennhd());        /* Rest des Headers und dann an Level3         */
  594.   cirpoi->traout = tratou;    /* Timeout setzen                 */
  595.   }
  596.  
  597. /*---------------------------------------------------------------------------*/
  598. VOID    sndack()        /* ACK senden                     */
  599.   {
  600.   l4ahd2 = 0;
  601.   l4aopc = 6;            /* Opcode                     */
  602.   ackhdr();            /* Rest des Headers                 */
  603.   itol3(gennhd());        /* Rest des Headers und dann an Level3         */
  604.   }
  605.  
  606. /*---------------------------------------------------------------------------*/
  607. VOID    ackhdr()        /* ACK Header erzeugen                 */
  608.   {
  609.   l4pidx = cirpoi->idxpar;    /* Partner Index                 */
  610.   l4pcid = cirpoi->idpart;    /* Partner ID                     */
  611.   l4ahd3 = cirpoi->l4vr;    /* RX-Sequenz                     */
  612.   if ((cirpoi->l4flag & 0x40) != 0) /* selbst choked?                 */
  613.     l4aopc |= 0x80;        /* dann Flag setzen                 */
  614.   else {
  615.     if (cirpoi->l4rs == 1) {    /* wird es ein NAK Header?             */
  616.       l4aopc |= 0x40;        /* dann Flag setzen                 */
  617.       cirpoi->l4rs = 2;        /* NAK als gesendet markieren             */
  618.       }
  619.     }
  620.   cirpoi->acktim = 0;        /* ACK Timer ruecksetzen             */
  621.   }
  622.  
  623. /*---------------------------------------------------------------------------*/
  624. VOID    itol3(mbhd)        /* Info an Level3                 */
  625. mhtyp    *mbhd;
  626.   {
  627.   mbhd->l2lnk = (l2ltyp *) cirpoi->l3node;    /* Controllblock         */
  628.   relink(mbhd, l3txl.lprev);    /* nur umhaengen                 */
  629.   }
  630.  
  631. /*---------------------------------------------------------------------------*/
  632. mhtyp    *gennhd()        /* Netzwerk Header erzeugen             */
  633.   {
  634.   unsigned cnt;            /* Scratch Zaehler                 */
  635.   mhtyp       *mbhd;        /* Buffer fuer Info                 */
  636.  
  637.   mbhd = (mhtyp *) allocb();        /* Buffer besorgen             */
  638.   for (cnt = 0; cnt < 15; ++cnt) /* die ersten 15 Bytes fuer den Header leer */
  639.     putchr(0, mbhd);
  640.   putchr(l4pidx, mbhd);        /* Transport Header schreiben             */
  641.   putchr(l4pcid, mbhd);
  642.   putchr(l4ahd2, mbhd);
  643.   putchr(l4ahd3, mbhd);
  644.   putchr(l4aopc, mbhd);
  645.  
  646.   return(mbhd);            /* Buffer wird zurueck gegeben             */
  647.   }
  648.  
  649. /*---------------------------------------------------------------------------*/
  650. VOID    kilfra()        /* Fragmente loeschen                 */
  651.   {
  652.   if (cirpoi->fragme != NULL) {      /* schon leer?                 */
  653.     dealmb(cirpoi->fragme);             /* Fragment loeschen             */
  654.     cirpoi->fragme = NULL;        /* Eintrag loeschen             */
  655.     }
  656.   }
  657.  
  658. /*- Ende Level 4 ------------------------------------------------------------*/
  659.