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