/* Copyright 2001-2022 John Wiseman G8BPQ This file is part of LinBPQ/BPQ32. LinBPQ/BPQ32 is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. LinBPQ/BPQ32 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with LinBPQ/BPQ32. If not, see http://www.gnu.org/licenses */ /* Using code from 6pack Linux Kernel driver with the following licence and credits * 6pack driver version 0.4.2, 1999/08/22 * * This module: * This module is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. * * This module implements the AX.25 protocol for kernel-based * devices like TTYs. It interfaces between a raw TTY, and the * kernel's AX.25 protocol layers, just like slip.c. * AX.25 needs to be separated from slip.c while slip.c is no * longer a static kernel device since it is a module. * * Author: Andreas Könsgen * * Lots of stuff has been taken from mkiss.c, written by * Hans Alblas * * with the fixes from * * Jonathan (G4KLX) Fixed to match Linux networking changes - 2.1.15. * Matthias (DG2FEF) Fixed bug in ax25_close(): dev_lock_wait() was * called twice, causing a deadlock. */ // 6pack needs fast response to received characters, and I want to be able to operate over TCP links as well as serial. // So I think the character level stuff may need to run in a separate thread, probably using select. // // I also need to support multiple 6pack ports. // ?? Do we add this as a backend to KISS driver or a separate Driver. KISS Driver is already quite messy. Not decided yet. // ?? If using serial/real TNC we need to be able to interleave control and data bytes, but I think with TCP/QtSM it won't be necessary // ?? Also a don't see any point in running multiple copies of QtSM on one port, but maybe should treat the QtSM channels as // multidropped ports for scheduling (?? only if on same radio ??) // ?? I think it needs to look like a KISS (L2) driver but will need a transmit scheduler level to do DCD/CSMA/PTT processing, // ideally with an interlock to other drivers on same port. This needs some thought with QtSM KISS with multiple modems on one channel #define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers #define _CRT_SECURE_NO_DEPRECATE #include "compatbits.h" #include #include "CHeaders.h" #include "bpq32.h" #include "tncinfo.h" #ifndef WIN32 #define APIENTRY #define DllExport #define VOID void #else #include #endif /**************************************************************************** * Defines for the 6pack driver. ****************************************************************************/ /* provisoric define */ #define SIXP_MAJOR MKISS_MAJOR /* end of provisoric defines */ #define TRUE 1 #define FALSE 0 #define AX25_MAXDEV 16 /* MAX number of AX25 channels; This can be overridden with insmod -oax25_maxdev=nnn */ #define AX_MTU 236 /* 6pack protocol bytes/masks. */ #define SIXP_INIT_CMD 0xE8 #define SIXP_TNC_FOUND 0xE9 #define SIXP_CMD_MASK 0xC0 #define SIXP_PRIO_CMD_MASK 0x80 #define SIXP_PRIO_DATA_MASK 0x38 #define SIXP_STD_CMD_MASK 0x40 #define SIXP_DCD_MASK 0x08 #define SIXP_RX_DCD_MASK 0x18 #define SIXP_CHN_MASK 0x07 #define SIXP_TX_MASK 0x20 #define SIXP_CON_LED_ON 0x68 #define SIXP_STA_LED_ON 0x70 #define SIXP_LED_OFF 0x60 /* checksum for a valid 6pack encapsulated packet */ #define SIXP_CHKSUM 0xFF /* priority commands */ #define SIXP_SEOF 0x40 /* TX underrun */ #define SIXP_TX_URUN 0x48 /* TX underrun */ #define SIXP_RX_ORUN 0x50 /* RX overrun */ #define SIXP_RX_BUF_OVL 0x58 /* RX overrun */ struct sixPackTNCInfo { // info for each TNC in chain int magic; char * name; /* These are pointers to the malloc()ed frame buffers. */ unsigned char *rbuff; /* receiver buffer */ int rcount; /* received chars counter */ unsigned char *xbuff; /* transmitter buffer */ unsigned char *xhead; /* pointer to next byte to XMIT */ int xleft; /* bytes left in XMIT queue */ /* SLIP interface statistics. */ unsigned long rx_packets; /* inbound frames counter */ unsigned long tx_packets; /* outbound frames counter */ unsigned long rx_errors; /* Parity, etc. errors */ unsigned long tx_errors; /* Planned stuff */ unsigned long rx_dropped; /* No memory for skb */ unsigned long tx_dropped; /* When MTU change */ unsigned long rx_over_errors; /* Frame bigger then SLIP buf. */ /* Detailed SLIP statistics. */ int mtu; /* Our mtu (to spot changes!) */ int buffsize; /* Max buffers sizes */ unsigned char flags; /* Flag values/ mode etc */ #define AXF_INUSE 0 /* Channel in use */ #define AXF_ESCAPE 1 /* ESC received */ #define AXF_ERROR 2 /* Parity, etc. error */ #define AXF_KEEPTEST 3 /* Keepalive test flag */ #define AXF_OUTWAIT 4 /* is outpacket was flag */ int mode; /* variables for the state machine */ unsigned char tnc_ok; unsigned char status; unsigned char status1; unsigned char status2; unsigned char duplex; unsigned char led_state; unsigned char tx_enable; unsigned char raw_buf[4]; /* receive buffer */ unsigned char cooked_buf[400]; /* receive buffer after 6pack decoding */ unsigned int rx_count; /* counter for receive buffer */ unsigned int rx_count_cooked; /* counter for receive buffer after 6pack decoding */ unsigned char tx_delay; unsigned char persistance; unsigned char slottime; }; struct sixPackPortInfo { // Per port (chain of TNC's) unsigned int linkOK; // Set if response is received unsigned int reinitTimer; struct sixPackTNCInfo * TNCS[8]; // Max TNCs in chain Not sure if real 6pack uses o or 1 for first }; #define AX25_MAGIC 0x5316 #define SIXP_DRIVER_MAGIC 0x5304 #define SIXP_INIT_RESYNC_TIMEOUT 150 /* in 10 ms */ #define SIXP_RESYNC_TIMEOUT 500 /* in 10 ms */ /* default radio channel access parameters */ #define SIXP_TXDELAY 25 /* in 10 ms */ #define SIXP_PERSIST 50 #define SIXP_SLOTTIME 10 /* in 10 ms */ static int sixpack_encaps(unsigned char *tx_buf, unsigned char *tx_buf_raw, int length, unsigned char tx_delay); static void sixpack_decaps(struct sixPackPortInfo *, unsigned char); static void decode_prio_command(unsigned char, struct sixPackTNCInfo *); static void decode_std_command(unsigned char, struct sixPackTNCInfo *); static void decode_data(unsigned char, struct sixPackTNCInfo *); static void resync_tnc(unsigned long); static void xmit_on_air(struct sixPackTNCInfo *ax); static void start_tx_timer(struct sixPackTNCInfo *ax); int Connectto6Pack(int port); VOID __cdecl Debugprintf(const char * format, ...); /* Set the "sending" flag. This must be atomic, hence the ASM. */ static void ax_lock(struct sixPackTNCInfo *ax) { // if (test_and_set_bit(0, (void *)&ax->dev->tbusy)) // printk(KERN_ERR "6pack: %s: trying to lock already locked device!\n", ax->dev->name); } /* Clear the "sending" flag. This must be atomic, hence the ASM. */ static void ax_unlock(struct sixPackTNCInfo *ax) { // if (!test_and_clear_bit(0, (void *)&ax->dev->tbusy)) // printk(KERN_ERR "6pack: %s: trying to unlock already unlocked device!\n", ax->dev->name); } /* Send one completely decapsulated AX.25 packet to the AX.25 layer. */ static void ax_bump(struct sixPackTNCInfo *ax) { } VOID SixPackProcessReceivedPacket(struct TNCINFO * TNC) { int InputLen, MsgLen; unsigned char * ptr; char Buffer[4096]; if (TNC->InputLen > 8000) // Shouldnt have packets longer than this TNC->InputLen=0; InputLen = recv(TNC->TCPSock, &TNC->ARDOPBuffer[TNC->InputLen], 8192 - TNC->InputLen, 0); if (InputLen == 0 || InputLen == SOCKET_ERROR) { // Does this mean closed? int err = GetLastError(); closesocket(TNC->TCPSock); TNC->TCPSock = 0; TNC->CONNECTED = FALSE; TNC->Streams[0].ReportDISC = TRUE; sprintf(TNC->WEB_COMMSSTATE, "Connection to TNC lost"); MySetWindowText(TNC->xIDC_COMMSSTATE, TNC->WEB_COMMSSTATE); return; } TNC->InputLen += InputLen; // Process Bytes } static int sixpack_encaps(unsigned char *tx_buf, unsigned char *tx_buf_raw, int length, unsigned char tx_delay) { int count = 0; unsigned char checksum = 0, buf[400]; int raw_count = 0; tx_buf_raw[raw_count++] = SIXP_PRIO_CMD_MASK | SIXP_TX_MASK; tx_buf_raw[raw_count++] = SIXP_SEOF; buf[0] = tx_delay; for(count = 1; count < length; count++) buf[count] = tx_buf[count]; for(count = 0; count < length; count++) checksum += buf[count]; buf[length] = (unsigned char)0xff - checksum; for(count = 0; count <= length; count++) { if((count % 3) == 0) { tx_buf_raw[raw_count++] = (buf[count] & 0x3f); tx_buf_raw[raw_count] = ((buf[count] >> 2) & 0x30); } else if((count % 3) == 1) { tx_buf_raw[raw_count++] |= (buf[count] & 0x0f); tx_buf_raw[raw_count] = ((buf[count] >> 2) & 0x3c); } else { tx_buf_raw[raw_count++] |= (buf[count] & 0x03); tx_buf_raw[raw_count++] = (buf[count] >> 2); } /* else */ } /* for */ if ((length % 3) != 2) raw_count++; tx_buf_raw[raw_count++] = SIXP_SEOF; return(raw_count); } static void sixpack_decaps(struct sixPackPortInfo *ax, unsigned char inbyte) { // if (inbyte == SIXP_TNC_FOUND) { // This is wrong. It will only work with one TNC in the chain. Should look for E8 in top bits. Bottome 3 bits are number in chain if ((inbyte & SIXP_INIT_CMD) == 0) { int Count = inbyte & SIXP_CHN_MASK; struct sixPackTNCInfo * sixTNC; int i; Debugprintf("6pack: %d TNCs found. ", Count); // clear existing TNC strucs and allocate new ones if needed for (i = 0; i < Count; i++) { sixTNC = ax->TNCS[i]; if (sixTNC) memset(sixTNC, 0, sizeof(struct sixPackTNCInfo)); else sixTNC = ax->TNCS[i] = zalloc(sizeof(struct sixPackTNCInfo)); sixTNC->tnc_ok = 1; } ax->linkOK = TRUE; } /* if((inbyte & SIXP_PRIO_CMD_MASK) != 0) decode_prio_command(inbyte, ax); else if((inbyte & SIXP_STD_CMD_MASK) != 0) decode_std_command(inbyte, ax); else { if ((ax->status & SIXP_RX_DCD_MASK) == SIXP_RX_DCD_MASK) decode_data(inbyte, ax); } */ } /* identify and execute a 6pack priority command byte */ void decode_prio_command(unsigned char cmd, struct sixPackTNCInfo *ax) { unsigned char channel; channel = cmd & SIXP_CHN_MASK; if ((cmd & SIXP_PRIO_DATA_MASK) != 0) { /* idle ? */ /* RX and DCD flags can only be set in the same prio command, if the DCD flag has been set without the RX flag in the previous prio command. If DCD has not been set before, something in the transmission has gone wrong. In this case, RX and DCD are cleared in order to prevent the decode_data routine from reading further data that might be corrupt. */ if (((ax->status & SIXP_DCD_MASK) == 0) && ((cmd & SIXP_RX_DCD_MASK) == SIXP_RX_DCD_MASK)) { if (ax->status != 1) Debugprintf("6pack: protocol violation\n"); else ax->status = 0; cmd &= !SIXP_RX_DCD_MASK; } ax->status = cmd & SIXP_PRIO_DATA_MASK; } /* if */ /* if the state byte has been received, the TNC is present, so the resync timer can be reset. */ if (ax->tnc_ok == 1) { // del_timer(&(ax->resync_t)); // ax->resync_t.data = (unsigned long) ax; // ax->resync_t.function = resync_tnc; // ax->resync_t.expires = jiffies + SIXP_INIT_RESYNC_TIMEOUT; // add_timer(&(ax->resync_t)); } ax->status1 = cmd & SIXP_PRIO_DATA_MASK; } /* try to resync the TNC. Called by the resync timer defined in decode_prio_command */ static void resync_tnc(unsigned long channel) { static char resync_cmd = SIXP_INIT_CMD; struct sixPackTNCInfo *ax = (struct sixPackTNCInfo *) channel; Debugprintf("6pack: resyncing TNC\n"); /* clear any data that might have been received */ ax->rx_count = 0; ax->rx_count_cooked = 0; /* reset state machine */ ax->status = 1; ax->status1 = 1; ax->status2 = 0; ax->tnc_ok = 0; /* resync the TNC */ ax->led_state = SIXP_LED_OFF; // ax->tty->driver.write(ax->tty, 0, &(ax->led_state), 1); // ax->tty->driver.write(ax->tty, 0, &resync_cmd, 1); /* Start resync timer again -- the TNC might be still absent */ // del_timer(&(ax->resync_t)); // ax->resync_t.data = (unsigned long) ax; // ax->resync_t.function = resync_tnc; // ax->resync_t.expires = jiffies + SIXP_RESYNC_TIMEOUT; // add_timer(&(ax->resync_t)); } /* identify and execute a standard 6pack command byte */ void decode_std_command(unsigned char cmd, struct sixPackTNCInfo *ax) { unsigned char checksum = 0, channel; unsigned int i; channel = cmd & SIXP_CHN_MASK; switch(cmd & SIXP_CMD_MASK) { /* normal command */ case SIXP_SEOF: if ((ax->rx_count == 0) && (ax->rx_count_cooked == 0)) { if ((ax->status & SIXP_RX_DCD_MASK) == SIXP_RX_DCD_MASK) { ax->led_state = SIXP_CON_LED_ON; // ax->tty->driver.write(ax->tty, 0, &(ax->led_state), 1); } /* if */ } else { ax->led_state = SIXP_LED_OFF; // ax->tty->driver.write(ax->tty, 0, &(ax->led_state), 1); /* fill trailing bytes with zeroes */ if (ax->rx_count == 2) { decode_data(0, ax); decode_data(0, ax); ax->rx_count_cooked -= 2; } else if (ax->rx_count == 3) { decode_data(0, ax); ax->rx_count_cooked -= 1; } for (i=0; i< ax->rx_count_cooked; i++) checksum += ax->cooked_buf[i]; if (checksum != SIXP_CHKSUM) { Debugprintf("6pack: bad checksum %2.2x\n", checksum); } else { ax->rcount = ax->rx_count_cooked-1; ax_bump(ax); } /* else */ ax->rx_count_cooked = 0; } /* else */ break; case SIXP_TX_URUN: Debugprintf("6pack: TX underrun\n"); break; case SIXP_RX_ORUN: Debugprintf("6pack: RX overrun\n"); break; case SIXP_RX_BUF_OVL: Debugprintf("6pack: RX buffer overflow\n"); } /* switch */ } /* function */ /* decode 4 sixpack-encoded bytes into 3 data bytes */ void decode_data(unsigned char inbyte, struct sixPackTNCInfo *ax) { unsigned char *buf; if (ax->rx_count != 3) ax->raw_buf[ax->rx_count++] = inbyte; else { buf = ax->raw_buf; ax->cooked_buf[ax->rx_count_cooked++] = buf[0] | ((buf[1] << 2) & 0xc0); ax->cooked_buf[ax->rx_count_cooked++] = (buf[1] & 0x0f) | ((buf[2] << 2) & 0xf0); ax->cooked_buf[ax->rx_count_cooked++] = (buf[2] & 0x03) | (inbyte << 2); ax->rx_count = 0; } } // This takes a packet from the KISS driver and converts to 6pack format static void ax_encaps(struct sixPackTNCInfo *ax, unsigned char *icp, int len) { unsigned char *p; int count; struct sixPackTNCInfo *tmp_ax; if (len > ax->mtu) { /* Sigh, shouldn't occur BUT ... */ len = ax->mtu; Debugprintf("6pack: %s: truncating oversized transmit packet!\n", ax->name); ax->tx_dropped++; ax_unlock(ax); return; } p = icp; if (p[0] > 5) { Debugprintf("%s: invalid KISS command -- dropped\n", ax->name); ax_unlock(ax); return; } if ((p[0] != 0) && (len > 2)) { Debugprintf("%s: KISS command packet too long -- dropped\n", ax->name); ax_unlock(ax); return; } if ((p[0] == 0) && (len < 15)) { Debugprintf("%s: bad AX.25 packet to transmit -- dropped\n", ax->name); ax->tx_dropped++; ax_unlock(ax); return; } switch(p[0]) { case 1: tmp_ax->tx_delay = p[1]; break; case 2: tmp_ax->persistance = p[1]; break; case 3: tmp_ax->slottime = p[1]; break; case 4: Debugprintf("6pack: got KISS command 4 -- ignored\n"); break; case 5: tmp_ax->duplex = p[1]; break; } // How do we handle ACKMODE ?? if (p[0] != 0) { ax_unlock(ax); return; } count = sixpack_encaps(p, (unsigned char *) tmp_ax->xbuff, len, tmp_ax->tx_delay); tmp_ax->xleft = count; tmp_ax->status2 = count; tmp_ax->xhead = tmp_ax->xbuff; /* in case of DAMA or fullduplex operation, we don't take care about the state of the DCD or of any timers, as the determination of the correct time to send is the job of the AX.25 layer. We send immediately after data has arrived. */ if (tmp_ax->duplex == 1) { /* DAMA / fullduplex */ xmit_on_air(tmp_ax); } else { /* CSMA */ start_tx_timer(tmp_ax); } /* if ax->duplex */ } /* ax_encaps */ // This starts sending a packet to a TNC. TNC will immediately send (after TXD) /* the next two functions perform the persistence/slottime algorithm for CSMA access. If the persistence check was successful, write the data to the serial driver. Note that in case of DAMA operation, the data is not sent here. */ /* set timer to time out slottime */ static void start_tx_timer(struct sixPackTNCInfo *ax) { // del_timer(&(ax->tx_t)); // ax->tx_t.data = (unsigned long) ax; // ax->tx_t.function = tx_schedule; // ax->tx_t.expires = jiffies + (((ax->slottime)+1)*HZ)/100; // add_timer(&(ax->tx_t)); } /* compute random number and check if it is ok to send */ static void tx_schedule(unsigned long channel) { struct sixPackTNCInfo *ax = (struct sixPackTNCInfo *) channel; static unsigned char random; random = random * 17 + 41; if (((ax->status1 & SIXP_DCD_MASK) == 0) && (random < ax->persistance)) xmit_on_air(ax); else start_tx_timer(ax); } static void xmit_on_air(struct sixPackTNCInfo *ax) { int actual; // ax->tty->flags |= (1 << TTY_DO_WRITE_WAKEUP); ax->led_state = SIXP_STA_LED_ON; // ax->tty->driver.write(ax->tty, 0, &(ax->led_state), 1); ax->tx_enable = 1; // actual = ax->tty->driver.write(ax->tty, 0, ax->xbuff, ax->status2); ax->tx_packets++; // ax->dev->trans_start = jiffies; ax->xleft -= actual; ax->xhead = ax->xbuff + actual; ax->led_state = SIXP_LED_OFF; // ax->tty->driver.write(ax->tty, 0, &(ax->led_state), 1); } /* xmit_on_air */ // BPQ Driver Module Interface extern int (WINAPI FAR *GetModuleFileNameExPtr)(); extern int (WINAPI FAR *EnumProcessesPtr)(); static int Socket_Data(int sock, int error, int eventcode); VOID MoveWindows(struct TNCINFO * TNC); static VOID SendToTNC(struct TNCINFO * TNC, int Stream, UCHAR * Encoded, int EncLen); int ReadCOMBlockEx(HANDLE fd, char * Block, int MaxLength, BOOL * Error); BOOL SerialWriteCommBlock(struct TNCINFO * TNC); void SerialCheckRX(struct TNCINFO * TNC); int SerialSendData(struct TNCINFO * TNC, UCHAR * data, int txlen); int SerialSendCommand(struct TNCINFO * TNC, UCHAR * data); int DoScanLine(struct TNCINFO * TNC, char * Buff, int Len); VOID SendInitScript(struct TNCINFO * TNC); int SIXPACKGetLine(char * buf); int ProcessEscape(UCHAR * TXMsg); VOID SIXPACKProcessReceivedPacket(struct TNCINFO * TNC); static int KissEncode(UCHAR * inbuff, UCHAR * outbuff, int len); int ConnecttoKISS(int port); TRANSPORTENTRY * SetupNewSession(TRANSPORTENTRY * Session, char * Bufferptr); BOOL DecodeCallString(char * Calls, BOOL * Stay, BOOL * Spy, UCHAR * AXCalls); BOOL FindLink(UCHAR * LinkCall, UCHAR * OurCall, int Port, struct _LINKTABLE ** REQLINK); VOID RESET2(struct _LINKTABLE * LINK); VOID L2SENDXID(struct _LINKTABLE * LINK); VOID SENDSABM(struct _LINKTABLE * LINK); static char ClassName[]="KISSSTATUS"; static char WindowTitle[] = "SIXPACK"; static int RigControlRow = 165; #ifndef LINBPQ #include #endif extern int SemHeldByAPI; static RECT Rect; static int ProcessLine(char * buf, int Port); VOID WritetoTrace(struct TNCINFO * TNC, char * Msg, int Len); #define FEND 0xC0 // KISS CONTROL CODES #define FESC 0xDB #define TFEND 0xDC #define TFESC 0xDD static int ProcessLine(char * buf, int Port) { UCHAR * ptr,* p_cmd; char * p_ipad = 0; char * p_port = 0; unsigned short WINMORport = 0; int BPQport; int len=510; struct TNCINFO * TNC; char errbuf[256]; strcpy(errbuf, buf); ptr = strtok(buf, " \t\n\r"); if(ptr == NULL) return (TRUE); if(*ptr =='#') return (TRUE); // comment if(*ptr ==';') return (TRUE); // comment if (_stricmp(buf, "ADDR")) return FALSE; // Must start with ADDR ptr = strtok(NULL, " \t\n\r"); BPQport = Port; p_ipad = ptr; TNC = TNCInfo[BPQport] = malloc(sizeof(struct TNCINFO)); memset(TNC, 0, sizeof(struct TNCINFO)); TNC->DefaultMode = TNC->WL2KMode = 0; // Packet 1200 TNC->InitScript = malloc(1000); TNC->InitScript[0] = 0; if (p_ipad == NULL) p_ipad = strtok(NULL, " \t\n\r"); if (p_ipad == NULL) return (FALSE); p_port = strtok(NULL, " \t\n\r"); if (p_port == NULL) return (FALSE); WINMORport = atoi(p_port); TNC->destaddr.sin_family = AF_INET; TNC->destaddr.sin_port = htons(WINMORport); TNC->HostName = malloc(strlen(p_ipad)+1); if (TNC->HostName == NULL) return TRUE; strcpy(TNC->HostName,p_ipad); ptr = strtok(NULL, " \t\n\r"); if (ptr) { if (_stricmp(ptr, "PTT") == 0) { ptr = strtok(NULL, " \t\n\r"); if (ptr) { DecodePTTString(TNC, ptr); ptr = strtok(NULL, " \t\n\r"); } } } if (ptr) { if (_memicmp(ptr, "PATH", 4) == 0) { p_cmd = strtok(NULL, "\n\r"); if (p_cmd) TNC->ProgramPath = _strdup(p_cmd); } } // Read Initialisation lines while (TRUE) { if (GetLine(buf) == 0) return TRUE; strcpy(errbuf, buf); if (memcmp(buf, "****", 4) == 0) return TRUE; ptr = strchr(buf, ';'); if (ptr) { *ptr++ = 13; *ptr = 0; } if (_memicmp(buf, "UPDATEMAP", 9) == 0) TNC->PktUpdateMap = TRUE; else if (standardParams(TNC, buf) == FALSE) strcat(TNC->InitScript, buf); } return (TRUE); } char * Config; static char * ptr1, * ptr2; int SIXPACKGetLine(char * buf) { loop: if (ptr2 == NULL) return 0; memcpy(buf, ptr1, ptr2 - ptr1 + 2); buf[ptr2 - ptr1 + 2] = 0; ptr1 = ptr2 + 2; ptr2 = strchr(ptr1, 13); if (buf[0] < 0x20) goto loop; if (buf[0] == '#') goto loop; if (buf[0] == ';') goto loop; if (buf[strlen(buf)-1] < 0x20) buf[strlen(buf)-1] = 0; if (buf[strlen(buf)-1] < 0x20) buf[strlen(buf)-1] = 0; buf[strlen(buf)] = 13; return 1; } VOID SuspendOtherPorts(struct TNCINFO * ThisTNC); VOID ReleaseOtherPorts(struct TNCINFO * ThisTNC); VOID WritetoTrace(struct TNCINFO * TNC, char * Msg, int Len); static time_t ltime; static VOID SendToTNC(struct TNCINFO * TNC, int Stream, UCHAR * Encoded, int EncLen) { if (TNC->hDevice) { // Serial mode. Queue to Hostmode driver PMSGWITHLEN buffptr = (PMSGWITHLEN)GetBuff(); if (buffptr == 0) return; // No buffers, so ignore buffptr->Len = EncLen; memcpy(&buffptr->Data[0], Encoded, EncLen); C_Q_ADD(&TNC->Streams[Stream].BPQtoPACTOR_Q, buffptr); TNC->Streams[Stream].FramesQueued++; return; } } static SOCKADDR_IN sinx; static SOCKADDR_IN rxaddr; static int addrlen=sizeof(sinx); static size_t ExtProc(int fn, int port, PDATAMESSAGE buff) { int datalen; PMSGWITHLEN buffptr; char txbuff[500]; unsigned int bytes,txlen = 0; UCHAR * TXMsg; size_t Param; int Stream = 0; HKEY hKey=0; struct TNCINFO * TNC = TNCInfo[port]; struct STREAMINFO * STREAM = &TNC->Streams[0]; struct ScanEntry * Scan; if (TNC == NULL) return 0; // Port not defined if (TNC->CONNECTED == 0 && TNC->CONNECTING == 0) { // Try to reopen every 30 secs if (fn > 3 && fn < 7) goto ok; TNC->ReopenTimer++; if (TNC->ReopenTimer < 150) return 0; TNC->ReopenTimer = 0; Connectto6Pack(TNC->Port); return 0; SendInitScript(TNC); } ok: switch (fn) { case 7: // 100 mS Timer. May now be needed, as Poll can be called more frequently in some circumstances SerialCheckRX(TNC); return 0; case 1: // poll STREAM = &TNC->Streams[0]; if (STREAM->NeedDisc) { STREAM->NeedDisc--; if (STREAM->NeedDisc == 0) { // Send the DISCONNECT SerialSendCommand(TNC, "DISCONNECT\r"); } } if (TNC->PortRecord->ATTACHEDSESSIONS[Stream] && STREAM->Attached == 0) { // New Attach int calllen; char Msg[80]; STREAM->Attached = TRUE; calllen = ConvFromAX25(TNC->PortRecord->ATTACHEDSESSIONS[Stream]->L4USER, TNC->Streams[Stream].MyCall); TNC->Streams[Stream].MyCall[calllen] = 0; // Stop other ports in same group SuspendOtherPorts(TNC); sprintf(TNC->WEB_TNCSTATE, "In Use by %s", TNC->Streams[0].MyCall); MySetWindowText(TNC->xIDC_TNCSTATE, TNC->WEB_TNCSTATE); // Stop Scanning sprintf(Msg, "%d SCANSTOP", TNC->Port); Rig_Command( (TRANSPORTENTRY *) -1, Msg); } if (STREAM->Attached) CheckForDetach(TNC, Stream, STREAM, TidyClose, ForcedClose, CloseComplete); // See if any frames for this port STREAM = &TNC->Streams[0]; if (STREAM->BPQtoPACTOR_Q) { PMSGWITHLEN buffptr = (PMSGWITHLEN)Q_REM(&STREAM->BPQtoPACTOR_Q); UCHAR * data = &buffptr->Data[0]; STREAM->FramesQueued--; txlen = (int)buffptr->Len; STREAM->bytesTXed += txlen; bytes=SerialSendData(TNC, data, txlen); WritetoTrace(TNC, data, txlen); } if (STREAM->PACTORtoBPQ_Q != 0) { buffptr = (PMSGWITHLEN)Q_REM(&STREAM->PACTORtoBPQ_Q); datalen = (int)buffptr->Len; buff->PORT = Stream; // Compatibility with Kam Driver buff->PID = 0xf0; memcpy(&buff->L2DATA, &buffptr->Data[0], datalen); // Data goes to + 7, but we have an extra byte datalen += sizeof(void *) + 4; PutLengthinBuffer(buff, datalen); ReleaseBuffer(buffptr); return (1); } if (STREAM->ReportDISC) // May need a delay so treat as a counter { STREAM->ReportDISC--; if (STREAM->ReportDISC == 0) { buff->PORT = Stream; return -1; } } return (0); case 2: // send Stream = 0; if (!TNC->CONNECTED) return 0; // Don't try if not connected STREAM = &TNC->Streams[0]; if (TNC->SwallowSignon) { TNC->SwallowSignon = FALSE; // Discard *** connected return 0; } // We may get KISS packets (UI or session related) or text commands such as RADIO, CONNECT txlen = GetLengthfromBuffer(buff) - (MSGHDDRLEN); TXMsg = &buff->L2DATA[0]; if (buff->PID != 240) // ax.25 address { txlen = KissEncode(&buff->PID, txbuff, txlen); txlen = send(TNC->TCPSock, txbuff, txlen, 0); return 1; } TXMsg[txlen - 1] = 0; strcpy(txbuff, TXMsg); if (STREAM->Attached == 0) return 0; if (STREAM->Connected) { PMSGWITHLEN buffptr = (PMSGWITHLEN)GetBuff(); if (buffptr == 0) return 1; // No buffers, so ignore buffptr->Len = txlen; memcpy((UCHAR *)&buffptr->Data[0], &buff->L2DATA[0], txlen); C_Q_ADD(&TNC->Streams[Stream].PACTORtoBPQ_Q, buffptr); // connected data return 1; } // Process as Text Command if (_memicmp(txbuff, "D\r", 2) == 0 || _memicmp(txbuff, "BYE\r", 4) == 0) { STREAM->ReportDISC = TRUE; // Tell Node return 0; } if (_memicmp(txbuff, "RADIO ", 6) == 0) { sprintf(&buff->L2DATA[0], "%d %s", TNC->Port, &txbuff[6]); if (Rig_Command(TNC->PortRecord->ATTACHEDSESSIONS[0]->L4CROSSLINK, &buff->L2DATA[0])) { } else { PMSGWITHLEN buffptr = (PMSGWITHLEN)GetBuff(); if (buffptr == 0) return 1; // No buffers, so ignore buffptr->Len = sprintf((UCHAR *)&buffptr->Data[0], "%s", &buff->L2DATA[0]); C_Q_ADD(&TNC->Streams[Stream].PACTORtoBPQ_Q, buffptr); } return 1; } if (_memicmp(txbuff, "OVERRIDEBUSY", 12) == 0) { PMSGWITHLEN buffptr = (PMSGWITHLEN)GetBuff(); TNC->OverrideBusy = TRUE; if (buffptr) { buffptr->Len = sprintf((UCHAR *)&buffptr->Data[0], "SIXPACK} OK\r"); C_Q_ADD(&TNC->Streams[Stream].PACTORtoBPQ_Q, buffptr); } return 0; } if (_memicmp(&buff->L2DATA[0], "SessionTimeLimit", 16) == 0) { if (buff->L2DATA[16] != 13) { PMSGWITHLEN buffptr = (PMSGWITHLEN)GetBuff(); TNC->SessionTimeLimit = atoi(&buff->L2DATA[16]) * 60; if (buffptr) { buffptr->Len = sprintf((UCHAR *)&buffptr->Data[0], "SIXPACK} OK\r"); C_Q_ADD(&TNC->Streams[Stream].PACTORtoBPQ_Q, buffptr); } return 0; } } if (toupper(buff->L2DATA[0]) == 'C' && buff->L2DATA[1] == ' ' && txlen > 2) // Connect { // Connect Command. Pass to L2 code to start session char * ptr = strchr(&buff->L2DATA[2], 13); TRANSPORTENTRY * NewSess = L4TABLE; struct _LINKTABLE * LINK; TRANSPORTENTRY * Session = TNC->PortRecord->ATTACHEDSESSIONS[0]->L4CROSSLINK; struct PORTCONTROL * PORT = &TNC->PortRecord->PORTCONTROL; UCHAR axcalls[64]; UCHAR ourcall[7]; // Call we are using (may have SSID bits inverted int Stay = 0, Spy = 0, CQFLAG = 0, n; if (ptr) *ptr = 0; _strupr(&buff->L2DATA[2]); if (DecodeCallString(&buff->L2DATA[2], &Stay, &Spy, &axcalls[0]) == 0) { PMSGWITHLEN buffptr = (PMSGWITHLEN)GetBuff(); if (buffptr) { buffptr->Len = sprintf((UCHAR *)&buffptr->Data[0], "SIXPACK} Invalid Call\r"); C_Q_ADD(&TNC->Streams[Stream].PACTORtoBPQ_Q, buffptr); } return 0; } // Code copied from cmdc00 // Get Session Entry for Downlink NewSess = SetupNewSession(Session, NULL); if (NewSess == NULL) return 0; NewSess->L4CIRCUITTYPE = L2LINK + DOWNLINK; // FORMAT LINK TABLE ENTRY FOR THIS CONNECTION memcpy(Session->L4USER, NewSess->L4USER, 7); memcpy(ourcall, NewSess->L4USER, 7); // SSID SWAP TEST - LEAVE ALONE FOR HOST or Pactor like (unless UZ7HO) if ((Session->L4CIRCUITTYPE & BPQHOST))// host goto noFlip3; if ((Session->L4CIRCUITTYPE & PACTOR)) { // incoming is Pactorlike - see if UZ7HO if (memcmp(Session->L4TARGET.EXTPORT->PORT_DLL_NAME, "UZ7HO", 5) != 0) goto noFlip3; if (Session->L4TARGET.EXTPORT->MAXHOSTMODESESSIONS < 2) // Not multisession goto noFlip3; ourcall[6] ^= 0x1e; // UZ7HO Uplink - flip } else // Must be L2 uplink - flip ourcall[6] ^= 0x1e; // Flip SSID noFlip3: // SET UP NEW SESSION (OR RESET EXISTING ONE) FindLink(axcalls, ourcall, TNC->Port, &LINK); if (LINK == NULL) { PMSGWITHLEN buffptr = (PMSGWITHLEN)GetBuff(); if (buffptr) { buffptr->Len = sprintf((UCHAR *)&buffptr->Data[0], "SIXPACK} Sorry - System Tables Full\r"); C_Q_ADD(&TNC->Streams[Stream].PACTORtoBPQ_Q, buffptr); } return 0; } memcpy(LINK->LINKCALL, axcalls, 7); memcpy(LINK->OURCALL, ourcall, 7); LINK->LINKPORT = PORT; LINK->L2TIME = PORT->PORTT1; // Copy Digis n = 7; ptr = &LINK->DIGIS[0]; while (axcalls[n]) { memcpy(ptr, &axcalls[n], 7); n += 7; ptr += 7; LINK->L2TIME += 2 * PORT->PORTT1; // ADJUST TIMER VALUE FOR 1 DIGI } LINK->LINKTYPE = 2; // DOWNLINK LINK->LINKWINDOW = PORT->PORTWINDOW; RESET2(LINK); // RESET ALL FLAGS // if (CMD->String[0] == 'N' && SUPPORT2point2) // LINK->L2STATE = 1; // New (2.2) send XID // else LINK->L2STATE = 2; // Send SABM LINK->CIRCUITPOINTER = NewSess; NewSess->L4TARGET.LINK = LINK; if (PORT->PORTPACLEN) NewSess->SESSPACLEN = Session->SESSPACLEN = PORT->PORTPACLEN; STREAM->Connecting = TRUE; if (CQFLAG == 0) // if a CQ CALL DONT SEND SABM { if (LINK->L2STATE == 1) L2SENDXID(LINK); else SENDSABM(LINK); } return 0; } return 0; case 3: // CHECK IF OK TO SEND (And check TNC Status) return ((TNC->CONNECTED) << 8 | TNC->Streams[0].Disconnecting << 15); // OK case 4: // reinit7 return 0; case 5: // Close return 0; case 6: // Scan Stop Interface Param = (size_t)buff; if (Param == 2) // Check Permission (Shouldn't happen) { Debugprintf("Scan Check Permission called on SIXPACK"); return 1; // OK to change } if (Param == 1) // Request Permission { if (!TNC->CONNECTED) return 0; // No connection so no interlock if (TNC->ConnectPending == 0 && TNC->PTTState == 0) { SerialSendCommand(TNC, "CONOK OFF"); TNC->GavePermission = TRUE; return 0; // OK to Change } if (TNC->ConnectPending) TNC->ConnectPending--; // Time out if set too long return TRUE; } if (Param == 3) // Release Permission { if (TNC->GavePermission) { TNC->GavePermission = FALSE; if (TNC->ARDOPCurrentMode[0] != 'S') // Skip SerialSendCommand(TNC, "CONOK ON"); } return 0; } // Param is Address of a struct ScanEntry Scan = (struct ScanEntry *)buff; return 0; } return 0; } VOID SIXPACKReleaseTNC(struct TNCINFO * TNC) { // Set mycall back to Node or Port Call, and Start Scanner UCHAR TXMsg[64]; // Start Scanner sprintf(TXMsg, "%d SCANSTART 15", TNC->Port); Rig_Command( (TRANSPORTENTRY *) -1, TXMsg); strcpy(TNC->WEB_TNCSTATE, "Free"); MySetWindowText(TNC->xIDC_TNCSTATE, TNC->WEB_TNCSTATE); ReleaseOtherPorts(TNC); } VOID SIXPACKSuspendPort(struct TNCINFO * TNC, struct TNCINFO * ThisTNC) { } VOID SIXPACKReleasePort(struct TNCINFO * TNC) { } static int WebProc(struct TNCINFO * TNC, char * Buff, BOOL LOCAL) { int Len = sprintf(Buff, "" "" "VARA Status" "

SIXPACK Status" "

", TNC->Port); Len += sprintf(&Buff[Len], ""); Len += sprintf(&Buff[Len], "", TNC->WEB_COMMSSTATE); Len += sprintf(&Buff[Len], "", TNC->WEB_TNCSTATE); Len += sprintf(&Buff[Len], "", TNC->WEB_MODE); Len += sprintf(&Buff[Len], "", TNC->WEB_CHANSTATE); Len += sprintf(&Buff[Len], "", TNC->WEB_PROTOSTATE); Len += sprintf(&Buff[Len], "", TNC->WEB_TRAFFIC); // Len += sprintf(&Buff[Len], "", TNC->WEB_RESTARTS); Len += sprintf(&Buff[Len], "
Comms State%s
TNC State%s
Mode%s
Channel State%s
Proto State%s
Traffic%s
TNC Restarts
"); Len += sprintf(&Buff[Len], "", TNC->WebBuffer); Len = DoScanLine(TNC, Buff, Len); return Len; } VOID * SIXPACKExtInit(EXTPORTDATA * PortEntry) { int port; char Msg[255]; char * ptr; struct TNCINFO * TNC; char * TempScript; struct PORTCONTROL * PORT = &PortEntry->PORTCONTROL; port = PORT->PORTNUMBER; if (TNCInfo[port]) // If restarting, free old config free(TNCInfo[port]); TNC = TNCInfo[port] = malloc(sizeof(struct TNCINFO)); memset(TNC, 0, sizeof(struct TNCINFO)); TNC->InitScript = malloc(1000); TNC->InitScript[0] = 0; if (PortConfig[port]) // May not have config ReadConfigFile(port, ProcessLine); TNC = TNCInfo[port]; if (TNC == NULL) { // Not defined in Config file sprintf(Msg," ** Error - no info in BPQ32.cfg for this port\n"); WritetoConsole(Msg); return ExtProc; } TNC->sixPack = zalloc(sizeof(struct sixPackTNCInfo)); TNC->Port = port; TNC->Hardware = H_SIXPACK; TNC->ARDOPBuffer = malloc(8192); TNC->PortRecord = PortEntry; if (PortEntry->PORTCONTROL.PORTCALL[0] == 0) memcpy(TNC->NodeCall, MYNODECALL, 10); else ConvFromAX25(&PortEntry->PORTCONTROL.PORTCALL[0], TNC->NodeCall); if (PortEntry->PORTCONTROL.PORTINTERLOCK && TNC->RXRadio == 0 && TNC->TXRadio == 0) TNC->RXRadio = TNC->TXRadio = PortEntry->PORTCONTROL.PORTINTERLOCK; PortEntry->PORTCONTROL.PROTOCOL = 10; PortEntry->PORTCONTROL.PORTQUALITY = 0; PortEntry->PORTCONTROL.USERS = 1; // Max 1 Session TNC->PacketChannels = 0; PortEntry->MAXHOSTMODESESSIONS = 1; PortEntry->SCANCAPABILITIES = SIMPLE; // Scan Control - pending connect only PortEntry->PERMITGATEWAY = TRUE; // Can change ax.25 call on each stream PortEntry->PORTCONTROL.UICAPABLE = TRUE; if (PortEntry->PORTCONTROL.PORTPACLEN == 0) PortEntry->PORTCONTROL.PORTPACLEN = 236; TNC->SuspendPortProc = SIXPACKSuspendPort; TNC->ReleasePortProc = SIXPACKReleasePort; // PortEntry->PORTCONTROL.PORTSTARTCODE = KISSStartPort; // PortEntry->PORTCONTROL.PORTSTOPCODE = KISSStopPort; ptr=strchr(TNC->NodeCall, ' '); if (ptr) *(ptr) = 0; // Null Terminate // Set Essential Params and MYCALL // Put overridable ones on front, essential ones on end TempScript = zalloc(1000); // cant think of any yet if (TNC->InitScript) { strcat(TempScript, TNC->InitScript); free(TNC->InitScript); } TNC->InitScript = TempScript; if (TNC->WL2K == NULL) if (PortEntry->PORTCONTROL.WL2KInfo.RMSCall[0]) // Alrerady decoded TNC->WL2K = &PortEntry->PORTCONTROL.WL2KInfo; PortEntry->PORTCONTROL.TNC = TNC; TNC->WebWindowProc = WebProc; TNC->WebWinX = 520; TNC->WebWinY = 500; TNC->WebBuffer = zalloc(5000); TNC->WEB_COMMSSTATE = zalloc(100); TNC->WEB_TNCSTATE = zalloc(100); TNC->WEB_CHANSTATE = zalloc(100); TNC->WEB_BUFFERS = zalloc(100); TNC->WEB_PROTOSTATE = zalloc(100); TNC->WEB_RESTARTTIME = zalloc(100); TNC->WEB_RESTARTS = zalloc(100); TNC->WEB_MODE = zalloc(20); TNC->WEB_TRAFFIC = zalloc(100); #ifndef LINBPQ CreatePactorWindow(TNC, ClassName, WindowTitle, RigControlRow, PacWndProc, 700, 450, ForcedClose); CreateWindowEx(0, "STATIC", "Comms State", WS_CHILD | WS_VISIBLE, 10,6,120,20, TNC->hDlg, NULL, hInstance, NULL); TNC->xIDC_COMMSSTATE = CreateWindowEx(0, "STATIC", "", WS_CHILD | WS_VISIBLE, 116,6,386,20, TNC->hDlg, NULL, hInstance, NULL); CreateWindowEx(0, "STATIC", "TNC State", WS_CHILD | WS_VISIBLE, 10,28,106,20, TNC->hDlg, NULL, hInstance, NULL); TNC->xIDC_TNCSTATE = CreateWindowEx(0, "STATIC", "", WS_CHILD | WS_VISIBLE, 116,28,520,20, TNC->hDlg, NULL, hInstance, NULL); CreateWindowEx(0, "STATIC", "Mode", WS_CHILD | WS_VISIBLE, 10,50,80,20, TNC->hDlg, NULL, hInstance, NULL); TNC->xIDC_MODE = CreateWindowEx(0, "STATIC", "", WS_CHILD | WS_VISIBLE, 116,50,200,20, TNC->hDlg, NULL, hInstance, NULL); CreateWindowEx(0, "STATIC", "Channel State", WS_CHILD | WS_VISIBLE, 10,72,110,20, TNC->hDlg, NULL, hInstance, NULL); TNC->xIDC_CHANSTATE = CreateWindowEx(0, "STATIC", "", WS_CHILD | WS_VISIBLE, 116,72,144,20, TNC->hDlg, NULL, hInstance, NULL); CreateWindowEx(0, "STATIC", "Proto State", WS_CHILD | WS_VISIBLE,10,94,80,20, TNC->hDlg, NULL, hInstance, NULL); TNC->xIDC_PROTOSTATE = CreateWindowEx(0, "STATIC", "", WS_CHILD | WS_VISIBLE,116,94,374,20 , TNC->hDlg, NULL, hInstance, NULL); CreateWindowEx(0, "STATIC", "Traffic", WS_CHILD | WS_VISIBLE,10,116,80,20, TNC->hDlg, NULL, hInstance, NULL); TNC->xIDC_TRAFFIC = CreateWindowEx(0, "STATIC", "0 0 0 0", WS_CHILD | WS_VISIBLE,116,116,374,20 , TNC->hDlg, NULL, hInstance, NULL); CreateWindowEx(0, "STATIC", "TNC Restarts", WS_CHILD | WS_VISIBLE,10,138,100,20, TNC->hDlg, NULL, hInstance, NULL); TNC->xIDC_RESTARTS = CreateWindowEx(0, "STATIC", "0", WS_CHILD | WS_VISIBLE,116,138,40,20 , TNC->hDlg, NULL, hInstance, NULL); CreateWindowEx(0, "STATIC", "Last Restart", WS_CHILD | WS_VISIBLE,140,138,100,20, TNC->hDlg, NULL, hInstance, NULL); TNC->xIDC_RESTARTTIME = CreateWindowEx(0, "STATIC", "Never", WS_CHILD | WS_VISIBLE,250,138,200,20, TNC->hDlg, NULL, hInstance, NULL); TNC->hMonitor= CreateWindowEx(0, "LISTBOX", "", WS_CHILD | WS_VISIBLE | LBS_NOINTEGRALHEIGHT | LBS_DISABLENOSCROLL | WS_HSCROLL | WS_VSCROLL, 0,170,250,300, TNC->hDlg, NULL, hInstance, NULL); TNC->ClientHeight = 450; TNC->ClientWidth = 500; TNC->hMenu = CreatePopupMenu(); AppendMenu(TNC->hMenu, MF_STRING, WINMOR_KILL, "Kill TNC"); AppendMenu(TNC->hMenu, MF_STRING, WINMOR_RESTART, "Kill and Restart TNC"); AppendMenu(TNC->hMenu, MF_STRING, WINMOR_RESTARTAFTERFAILURE, "Restart TNC after failed Connection"); CheckMenuItem(TNC->hMenu, WINMOR_RESTARTAFTERFAILURE, (TNC->RestartAfterFailure) ? MF_CHECKED : MF_UNCHECKED); AppendMenu(TNC->hMenu, MF_STRING, ARDOP_ABORT, "Abort Current Session"); MoveWindows(TNC); #endif Consoleprintf("SIXPACK Host %s %d", TNC->HostName, htons(TNC->destaddr.sin_port)); Connectto6Pack(port); time(&TNC->lasttime); // Get initial time value return ExtProc; } VOID TidyClose(struct TNCINFO * TNC, int Stream) { // If all acked, send disc if (TNC->Streams[Stream].BytesOutstanding == 0) SerialSendCommand(TNC, "DISCONNECT\r"); } VOID ForcedClose(struct TNCINFO * TNC, int Stream) { SerialSendCommand(TNC, "DISCONNECT\r"); } VOID CloseComplete(struct TNCINFO * TNC, int Stream) { if (Stream == 0) { SIXPACKReleaseTNC(TNC); } } static int KissDecode(UCHAR * inbuff, UCHAR * outbuff, int len) { int i,txptr=0; UCHAR c; for (i=0;iInputLen > 8000) // Shouldnt have packets longer than this TNC->InputLen=0; InputLen = recv(TNC->TCPSock, &TNC->ARDOPBuffer[TNC->InputLen], 8192 - TNC->InputLen, 0); if (InputLen == 0 || InputLen == SOCKET_ERROR) { // Does this mean closed? int err = GetLastError(); closesocket(TNC->TCPSock); TNC->TCPSock = 0; TNC->CONNECTED = FALSE; TNC->Streams[0].ReportDISC = TRUE; sprintf(TNC->WEB_COMMSSTATE, "Connection to TNC lost"); MySetWindowText(TNC->xIDC_COMMSSTATE, TNC->WEB_COMMSSTATE); return; } TNC->InputLen += InputLen; // Extract and decode KISS frames ptr = memchr(TNC->ARDOPBuffer + 1, FEND, TNC->InputLen - 1); // Ignore leading FEND while (ptr) // FEND in buffer { ptr++; MsgLen = ptr - TNC->ARDOPBuffer; if (MsgLen > 360) { TNC->InputLen = 0; return; } TNC->InputLen -= MsgLen; if (MsgLen > 1) { PMESSAGE Buff = GetBuff(); MsgLen = KissDecode(TNC->ARDOPBuffer, Buffer, MsgLen); // we dont need the FENDS or control byte MsgLen -= 3; if (Buff) { memcpy(&Buff->DEST, &Buffer[2], MsgLen); MsgLen += (3 + sizeof(void *)); PutLengthinBuffer((PDATAMESSAGE)Buff, MsgLen); // Needed for arm5 portability C_Q_ADD(&TNC->PortRecord->PORTCONTROL.PORTRX_Q, (UINT *)Buff); } } if (TNC->InputLen == 0) return; memmove(TNC->ARDOPBuffer, ptr, TNC->InputLen); ptr = memchr(TNC->ARDOPBuffer + 1, FEND, TNC->InputLen - 1); // Ignore leading FEND } } /* // we dont need the control byte len --; if (Buffer) { memcpy(&Buffer->DEST, &Port->RXMSG[1], len); len += (3 + sizeof(void *)); PutLengthinBuffer((PDATAMESSAGE)Buffer, len); // Needed for arm5 portability C_Q_ADD(TNC->PortRecord->PORTCONTROL.PORTRX_Q, (UINT *)Buffer); } */ // TNC->InputLen -= MsgLen; // goto loop; void AttachSIXPACK(struct PORTCONTROL * PORT, MESSAGE * Buffer) { // SABM on HFKISS port. L2 code will accepr call and connect to appl if necessary, but // need to attach the port char Call[16] = ""; char OrigCall[16] = ""; struct TNCINFO * TNC = PORT->TNC; struct WL2KInfo * WL2K = TNC->WL2K; if (TNC->PortRecord->ATTACHEDSESSIONS[0] == 0) { TRANSPORTENTRY * SESS; struct TNCINFO * TNC = PORT->TNC; // Incoming Connect Call[ConvFromAX25(Buffer->DEST, Call)] = 0; OrigCall[ConvFromAX25(Buffer->ORIGIN, OrigCall)] = 0; // Stop other ports in same group SuspendOtherPorts(TNC); TNC->SessionTimeLimit = TNC->DefaultSessionTimeLimit; // Reset Limit ProcessIncommingConnectEx(TNC, Call, 0, FALSE, FALSE); SESS = TNC->PortRecord->ATTACHEDSESSIONS[0]; SESS->Mode = TNC->WL2KMode; TNC->ConnectPending = FALSE; if (TNC->RIG && TNC->RIG != &TNC->DummyRig && strcmp(TNC->RIG->RigName, "PTT")) { sprintf(TNC->WEB_TNCSTATE, "%s Connected to %s Inbound Freq %s", OrigCall, Call, TNC->RIG->Valchar); SESS->Frequency = (int)(atof(TNC->RIG->Valchar) * 1000000.0) + 1500; // Convert to Centre Freq if (SESS->Frequency == 1500) { // try to get from WL2K record if (WL2K) { SESS->Frequency = WL2K->Freq; } } SESS->Mode = TNC->WL2KMode; } else { sprintf(TNC->WEB_TNCSTATE, "%s Connected to %s Inbound", OrigCall, Call); if (WL2K) { SESS->Frequency = WL2K->Freq; SESS->Mode = WL2K->mode; } } if (WL2K) strcpy(SESS->RMSCall, WL2K->RMSCall); MySetWindowText(TNC->xIDC_TNCSTATE, TNC->WEB_TNCSTATE); } } void DetachSIXPACK(struct PORTCONTROL * PORT) { // L2 Link Closed. Detach. struct TNCINFO * TNC = PORT->TNC; struct STREAMINFO * STREAM = &TNC->Streams[0]; if (STREAM->Attached) STREAM->ReportDISC = TRUE; // Tell Node STREAM->Connecting = FALSE; STREAM->Connected = FALSE; } void SIXPACKConnected(struct PORTCONTROL * PORT, struct _LINKTABLE * LINK) { // UA received when connecting struct TNCINFO * TNC = PORT->TNC; struct STREAMINFO * STREAM = &TNC->Streams[0]; struct WL2KInfo * WL2K = TNC->WL2K; TRANSPORTENTRY * SESS; char Call[16] = ""; char OrigCall[16] = ""; if (STREAM->Connecting) { STREAM->Connecting = FALSE; STREAM->Connected = TRUE; Call[ConvFromAX25(LINK->LINKCALL, Call)] = 0; OrigCall[ConvFromAX25(LINK->OURCALL, OrigCall)] = 0; TNC->SessionTimeLimit = TNC->DefaultSessionTimeLimit; // Reset Limit SESS = TNC->PortRecord->ATTACHEDSESSIONS[0]; SESS->Mode = TNC->WL2KMode; if (TNC->RIG && TNC->RIG != &TNC->DummyRig && strcmp(TNC->RIG->RigName, "PTT")) { sprintf(TNC->WEB_TNCSTATE, "%s Connected to %s Outbound Freq %s", OrigCall, Call, TNC->RIG->Valchar); SESS->Frequency = (int)(atof(TNC->RIG->Valchar) * 1000000.0) + 1500; // Convert to Centre Freq if (SESS->Frequency == 1500) { // try to get from WL2K record if (WL2K) { SESS->Frequency = WL2K->Freq; } } SESS->Mode = TNC->WL2KMode; } else { sprintf(TNC->WEB_TNCSTATE, "%s Connected to %s Outbound", OrigCall, Call); if (WL2K) { SESS->Frequency = WL2K->Freq; SESS->Mode = WL2K->mode; } } if (WL2K) strcpy(SESS->RMSCall, WL2K->RMSCall); MySetWindowText(TNC->xIDC_TNCSTATE, TNC->WEB_TNCSTATE); } } VOID x6PackThead(void * portptr); int Connectto6Pack(int port) { _beginthread(x6PackThead, 0, (void *)(size_t)port); return 0; } VOID x6PackThead(void * portptr) { // 6pack over TNC thread // Opens socket and looks for data int port = (int)(size_t)portptr; char Msg[255]; int err, i, ret; u_long param=1; BOOL bcopt=TRUE; struct hostent * HostEnt; struct TNCINFO * TNC = TNCInfo[port]; fd_set readfs; fd_set errorfs; struct timeval timeout; char * ptr1; char * ptr2; UINT * buffptr; int reinitTimer = 0; int linkactive = 0; struct sixPackPortInfo * sixPack = TNC->sixPack; if (sixPack == NULL || TNC->HostName == NULL) return; TNC->BusyFlags = 0; TNC->CONNECTING = TRUE; Sleep(3000); // Allow init to complete #ifdef WIN32 if (strcmp(TNC->HostName, "127.0.0.1") == 0) { // can only check if running on local host TNC->PID = GetListeningPortsPID(TNC->destaddr.sin_port); if (TNC->PID == 0) { TNC->CONNECTING = FALSE; return; // Not listening so no point trying to connect } // Get the File Name in case we want to restart it. if (TNC->ProgramPath == NULL) { if (GetModuleFileNameExPtr) { HANDLE hProc; char ExeName[256] = ""; hProc = OpenProcess(PROCESS_QUERY_INFORMATION |PROCESS_VM_READ, FALSE, TNC->PID); if (hProc) { GetModuleFileNameExPtr(hProc, 0, ExeName, 255); CloseHandle(hProc); TNC->ProgramPath = _strdup(ExeName); } } } } #endif // // If we started the TNC make sure it is still running. // if (!IsProcess(TNC->PID)) // { // RestartTNC(TNC); // Sleep(3000); // } TNC->destaddr.sin_addr.s_addr = inet_addr(TNC->HostName); if (TNC->destaddr.sin_addr.s_addr == INADDR_NONE) { // Resolve name to address HostEnt = gethostbyname (TNC->HostName); if (!HostEnt) { TNC->CONNECTING = FALSE; return; // Resolve failed } memcpy(&TNC->destaddr.sin_addr.s_addr,HostEnt->h_addr,4); memcpy(&TNC->Datadestaddr.sin_addr.s_addr,HostEnt->h_addr,4); } // closesocket(TNC->TCPSock); TNC->TCPSock=socket(AF_INET,SOCK_STREAM,0); if (TNC->TCPSock == INVALID_SOCKET) { i=sprintf(Msg, "Socket Failed for 6Pack socket - error code = %d\r\n", WSAGetLastError()); WritetoConsole(Msg); TNC->CONNECTING = FALSE; return; } setsockopt(TNC->TCPSock, SOL_SOCKET, SO_REUSEADDR, (const char FAR *)&bcopt, 4); sinx.sin_family = AF_INET; sinx.sin_addr.s_addr = INADDR_ANY; sinx.sin_port = 0; if (connect(TNC->TCPSock,(LPSOCKADDR) &TNC->destaddr,sizeof(TNC->destaddr)) == 0) { // // Connected successful // } else { if (TNC->Alerted == FALSE) { err=WSAGetLastError(); i=sprintf(Msg, "Connect Failed for 6Pack socket - error code = %d\r\n", err); WritetoConsole(Msg); sprintf(TNC->WEB_COMMSSTATE, "Connection to TNC failed"); MySetWindowText(TNC->xIDC_COMMSSTATE, TNC->WEB_COMMSSTATE); TNC->Alerted = TRUE; } closesocket(TNC->TCPSock); TNC->TCPSock = 0; TNC->CONNECTING = FALSE; return; } Sleep(1000); TNC->LastFreq = 0; // so V4 display will be updated TNC->CONNECTING = FALSE; TNC->CONNECTED = TRUE; TNC->BusyFlags = 0; TNC->InputLen = 0; TNC->Alerted = TRUE; sprintf(TNC->WEB_COMMSSTATE, "Connected to TNC"); MySetWindowText(TNC->xIDC_COMMSSTATE, TNC->WEB_COMMSSTATE); FreeSemaphore(&Semaphore); sprintf(Msg, "Connected to TNC Port %d\r\n", TNC->Port); WritetoConsole(Msg); while (TNC->CONNECTED) { FD_ZERO(&readfs); FD_ZERO(&errorfs); FD_SET(TNC->TCPSock,&readfs); FD_SET(TNC->TCPSock,&errorfs); timeout.tv_sec = 1; timeout.tv_usec = 0; // We use this to run timeouts ret = select((int)TNC->TCPSock + 1, &readfs, NULL, &errorfs, &timeout); if (ret == SOCKET_ERROR) { Debugprintf("6Pack Select failed %d ", WSAGetLastError()); goto Lost; } if (ret > 0) { // See what happened if (FD_ISSET(TNC->TCPSock, &readfs)) { GetSemaphore(&Semaphore, 52); SixPackProcessReceivedPacket(TNC); FreeSemaphore(&Semaphore); } if (FD_ISSET(TNC->TCPSock, &errorfs)) { Lost: sprintf(Msg, "6Pack Connection lost for Port %d\r\n", TNC->Port); WritetoConsole(Msg); sprintf(TNC->WEB_COMMSSTATE, "Connection to TNC lost"); MySetWindowText(TNC->xIDC_COMMSSTATE, TNC->WEB_COMMSSTATE); TNC->CONNECTED = FALSE; TNC->Alerted = FALSE; if (TNC->PTTMode) Rig_PTT(TNC, FALSE); // Make sure PTT is down if (TNC->Streams[0].Attached) TNC->Streams[0].ReportDISC = TRUE; TNC->TCPSock = 0; return; } } else { // Timeout. See if we need to reinit tnc chain if (sixPack->linkOK == 0) { sixPack->reinitTimer++; if (sixPack->reinitTimer > 30) { // send SIXP_INIT_CMD which should rescan the tnc chain unsigned char Msg = SIXP_INIT_CMD; int txlen = send(TNC->TCPSock, &Msg, 1, 0); sixPack->reinitTimer = 0; } } } } sprintf(Msg, "6Pack Thread Terminated Port %d\r\n", TNC->Port); WritetoConsole(Msg); }