qtsoundmodem/ax25_l2.c

1669 lines
36 KiB
C
Raw Normal View History

2023-09-04 19:06:44 +01:00
/*
Copyright (C) 2019-2020 Andrei Kopanchuk UZ7HO
This file is part of QtSoundModem
QtSoundModem 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.
QtSoundModem 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 QtSoundModem. If not, see http://www.gnu.org/licenses
*/
// UZ7HO Soundmodem Port by John Wiseman G8BPQ
#include "UZ7HOStuff.h"
extern int RSID_SABM[4];
extern int RSID_UI[4];
extern int RSID_SetModem[4];
extern int needRSID[4];
extern int needRSID[4];
2024-10-29 22:45:21 +00:00
BOOL useKISSControls = 0;
#define FEND 0xc0
#define FESC 0xDB
#define TFEND 0xDC
#define TFESC 0xDD
#define KISS_ACKMODE 0x0C
#define KISS_DATA 0
#define QTSMKISSCMD 7
2023-09-04 19:06:44 +01:00
/*
unit ax25_l2;
interface
uses sysutils,classes;
procedure frame_optimize(snd_ch,port: byte; var buf: TStringList);
procedure analiz_frame(snd_ch: byte; frame,code: string);
procedure send_data_buf(snd_ch,port: byte; path: string; nr: byte);
procedure add_pkt_buf(snd_ch,port: byte; data: string);
procedure set_link(snd_ch,port: byte; path: string);
procedure set_unlink(socket: integer; snd_ch,port: byte; path: string);
procedure set_chk_link(snd_ch,port: byte; path: string);
procedure UpdateActiveConnects(snd_ch: byte);
procedure timer_event;
procedure rst_values(snd_ch,port: byte);
procedure rst_timer(snd_ch,port: byte);
function get_free_port(snd_ch: byte; var port: byte): boolean;
function get_user_port_by_calls(snd_ch: byte; var port: byte; CallFrom,CallTo: string): boolean;
implementation
uses ax25,ax25_agw,sm_main,kiss_mode;
*/
string * make_frame(string * data, Byte * path, Byte pid, Byte nr, Byte ns, Byte f_type, Byte f_id, boolean rpt, boolean pf, boolean cr);
void rst_t3(TAX25Port * AX25Sess);
TAX25Port * get_user_port(int snd_ch, Byte * path);
2024-10-29 22:45:21 +00:00
void analiz_frame(int snd_ch, string * frame, char * code, boolean fecflag);
boolean is_last_digi(Byte *path);
int is_excluded_call(int snd_ch, unsigned char * path);
boolean is_correct_path(Byte * path, Byte pid);
void KISS_on_data_out(int port, string * frame, int TX);
void ax25_info_init(TAX25Port * AX25Sess);
void clr_frm_win(TAX25Port * AX25Sess);
void decode_frame(Byte * frame, int len, Byte * path, string * data,
Byte * pid, Byte * nr, Byte * ns, Byte * f_type, Byte * f_id,
Byte * rpt, Byte * pf, Byte * cr);
void ax25_info_init(TAX25Port * AX25Sess);
void AGW_AX25_disc(TAX25Port * AX25Sess, Byte mode);
void AGW_AX25_conn(TAX25Port * AX25Sess, int snd_ch, Byte mode);
int number_digi(char * path);
void AGW_AX25_data_in(void * socket, int snd_ch, int PID, Byte * path, string * data);
2023-09-04 19:06:44 +01:00
void inc_frack(TAX25Port * AX25Sess)
{
AX25Sess->clk_frack++;
}
void rst_frack(TAX25Port * AX25Sess)
{
AX25Sess->clk_frack = 0;
}
void inc_t1(TAX25Port * AX25Sess)
{
AX25Sess->t1++;
}
void rst_t1(TAX25Port * AX25Sess)
{
AX25Sess->t1 = 0;
}
void inc_t3(TAX25Port * AX25Sess)
{
AX25Sess->t3++;
}
void rst_t3(TAX25Port * AX25Sess)
{
AX25Sess->t3 = 0;
}
void rst_values(TAX25Port * AX25Sess)
{
AX25Sess->IPOLL_cnt = 0;
AX25Sess->hi_vs = 0;
AX25Sess->vs = 0;
AX25Sess->vr = 0;
Clear(&AX25Sess->I_frame_buf);
Clear(&AX25Sess->in_data_buf);
Clear(&AX25Sess->frm_collector);
ax25_info_init(AX25Sess);
clr_frm_win(AX25Sess);
}
void rst_timer(TAX25Port * AX25Sess)
{
rst_frack(AX25Sess);
rst_t1(AX25Sess);
rst_t3(AX25Sess);
}
void upd_i_lo(TAX25Port * AX25Sess, int n) //Update the counter of the first frame in the I-frame buffer
{
AX25Sess->i_lo = n;
}
void upd_i_hi(TAX25Port * AX25Sess, int n) //Update last frame counter in I-frame buffer
{
AX25Sess->i_hi = n;
}
void upd_vs(TAX25Port * AX25Sess, int n) //Update the counter of the next frame to transmit
{
AX25Sess->vs = ++n & 7;
}
void upd_vr(TAX25Port * AX25Sess, int n) //Refresh the counter of the next frame at the reception
{
AX25Sess->vr = ++n & 7;
}
void Frame_Optimize(TAX25Port * AX25Sess, TStringList * buf)
{
// I think this removes redundant frames from the TX Queue (eg repeated RR frames)
string * frame;
Byte path[80];
string * data = newString();
Byte pid, nr, ns, f_type, f_id, rpt, cr, pf;
boolean curr_req, optimize;
int i, k;
char need_frm[8] = "";
int index = 0;
boolean PollRR;
boolean PollREJ;
PollRR = FALSE;
PollREJ = FALSE;
curr_req = FALSE;
// Check Poll RR and REJ frame
i = 0;
while (i < buf->Count && !PollREJ)
{
frame = Strings(buf, i);
// TX frame has kiss control on front
decode_frame(frame->Data + 1, frame->Length - 1, path, data, &pid, &nr, &ns, &f_type, &f_id, &rpt, &pf, &cr);
if (cr == SET_R && pf == SET_P)
{
if (f_id == S_REJ)
PollREJ = TRUE;
else if (f_id == S_RR && nr == AX25Sess->vr)
PollRR = TRUE;
}
i++;
}
// Performance of the REJ Cards: Optional Rej Cards
i = 0;
while (i < buf->Count)
{
optimize = TRUE;
frame = Strings(buf, i);
decode_frame(frame->Data + 1, frame->Length - 1, path, data, &pid, &nr, &ns, &f_type, &f_id, &rpt, &pf, &cr);
if (f_id == S_REJ && cr == SET_R)
{
if ((pf == SET_F && PollREJ) || nr != AX25Sess->vr)
{
Debugprintf("Optimizer dropping REJ nr %d vr %d pf %d PollREJ %d", nr, AX25Sess->vr, pf, PollREJ);
Delete(buf, i);
optimize = FALSE;
}
if (nr == AX25Sess->vr)
curr_req = TRUE;
}
if (optimize)
i++;
}
// Performance Options
i = 0;
while (i <buf->Count)
{
need_frm[0] = 0;
index = 0;
k = AX25Sess->i_lo;
while (k != AX25Sess->vs)
{
need_frm[index++] = k + 'A';
k = (++k) & 7;
}
optimize = TRUE;
frame = Strings(buf, i);
decode_frame(frame->Data +1 , frame->Length - 1, path, data, &pid, &nr, &ns, &f_type, &f_id, &rpt, &pf, &cr);
if (f_id == S_RR)
{
// RR Cards Methods: Optional RR, F Cards
if (cr == SET_R)
{
if (nr != AX25Sess->vr || ((pf == SET_F) && PollRR) || curr_req)
{
Debugprintf("Optimizer dropping RR nr %d vr %d pf %d PollRR %d", nr, AX25Sess->vr, pf, PollRR);
Delete(buf, i);
optimize = FALSE;
}
}
// RR Cards Methods : Optional RR, P Cards
if (cr == SET_C)
{
if (AX25Sess->status == STAT_LINK || AX25Sess->status == STAT_WAIT_ANS)
{
Debugprintf("Optimizer dropping RR nr %d vr %d pf %d PollRR %d", nr, AX25Sess->vr, pf, PollRR);
Delete(buf, i);
optimize = FALSE;
}
}
}
// I - Cards Methods : Options for I - Cards
else if (f_id == I_I)
{
if (strchr(need_frm, ns + 'A') == 0)
{
Delete(buf, i);
optimize = FALSE;
}
else
{
if (nr != AX25Sess->vr)
buf->Items[i] = make_frame(data, path, pid, AX25Sess->vr, ns, f_type, f_id, rpt, pf, cr);
}
}
// SABM Applications
if (f_id == U_SABM)
{
if (AX25Sess->status != STAT_TRY_LINK)
{
Delete(buf, i);
optimize = FALSE;
}
}
if (optimize)
i++;
}
}
void add_pkt_buf(TAX25Port * AX25Sess, string * data)
{
boolean found = 0;
string * frm;
int i = 0;
while (i < AX25Sess->frame_buf.Count && !found)
{
found = compareStrings(Strings(&AX25Sess->frame_buf, i++), data);
}
if (found)
freeString(data);
else
Add(&AX25Sess->frame_buf, data);
}
void add_I_FRM(TAX25Port * AX25Sess, Byte * path)
{
string * data;
int i;
upd_i_lo(AX25Sess, AX25Sess->vs);
while (AX25Sess->in_data_buf.Count > 0 && AX25Sess->I_frame_buf.Count != maxframe[AX25Sess->snd_ch])
{
data = duplicateString(Strings(&AX25Sess->in_data_buf, 0));
Delete(&AX25Sess->in_data_buf, 0);
Add(&AX25Sess->I_frame_buf, data);
}
if (AX25Sess->I_frame_buf.Count > 0)
{
for (i = 0; i < AX25Sess->I_frame_buf.Count; i++)
{
upd_i_hi(AX25Sess, AX25Sess->vs);
upd_vs(AX25Sess, AX25Sess->vs);
AX25Sess->hi_vs = AX25Sess->vs; // Last transmitted frame
}
}
}
void delete_I_FRM(TAX25Port * AX25Sess, int nr)
{
int i;
i = AX25Sess->i_lo;
while (i != nr)
{
if (AX25Sess->I_frame_buf.Count > 0)
{
AX25Sess->info.stat_s_pkt++;
AX25Sess->info.stat_s_byte += Strings(&AX25Sess->I_frame_buf, 0)->Length;
Delete(&AX25Sess->I_frame_buf, 0);
}
i++;
i &= 7;
}
upd_i_lo(AX25Sess, nr);
}
void delete_I_FRM_port(TAX25Port * AX25Sess)
{
string * frame;
string path = { 0 };
string data= { 0 };
Byte pid, nr, ns, f_type, f_id, rpt, cr, pf;
boolean optimize;
int i = 0;
while (i < AX25Sess->frame_buf.Count)
{
optimize = TRUE;
frame = Strings(&AX25Sess->frame_buf, i);
decode_frame(frame->Data, frame->Length, &path, &data, &pid, &nr, &ns, &f_type, &f_id, &rpt, &pf, &cr);
if (f_id == I_I)
{
Delete(&AX25Sess->frame_buf, i);
optimize = FALSE;
}
if (optimize)
i++;
}
}
void send_data_buf(TAX25Port * AX25Sess, int nr)
{
int i;
boolean new_frames;
boolean PF_bit;
if (AX25Sess->status != STAT_LINK)
return;
AX25Sess->IPOLL_cnt = 0;
AX25Sess->vs = nr;
delete_I_FRM(AX25Sess, nr); // ?? free acked frames
// delete_I_FRM_port(AX25Sess);
if (TXFrmMode[AX25Sess->snd_ch] == 1)
{
new_frames = FALSE;
if (AX25Sess->I_frame_buf.Count < 2)
{
add_I_FRM(AX25Sess, AX25Sess->Path);
AX25Sess->status = STAT_LINK;
new_frames = TRUE;
}
if (AX25Sess->I_frame_buf.Count > 0)
{
if (new_frames)
{
for (i = 0; i < AX25Sess->I_frame_buf.Count; i++)
{
if (i == AX25Sess->I_frame_buf.Count - 1)
PF_bit = SET_P;
else
PF_bit = SET_F;
add_pkt_buf(AX25Sess, make_frame(Strings(&AX25Sess->I_frame_buf, i), AX25Sess->Path, AX25Sess->PID, AX25Sess->vr, ((AX25Sess->i_lo + i) & 7), I_FRM, I_I, FALSE, PF_bit, SET_C));
}
}
if (!new_frames)
{
add_pkt_buf(AX25Sess, make_frame(Strings(&AX25Sess->I_frame_buf, 0), AX25Sess->Path, AX25Sess->PID, AX25Sess->vr, AX25Sess->i_lo, I_FRM, I_I, FALSE, SET_P, SET_C)); //SET_P
upd_vs(AX25Sess, AX25Sess->vs);
}
AX25Sess->status = STAT_WAIT_ANS;
rst_timer(AX25Sess);
}
}
if (TXFrmMode[AX25Sess->snd_ch] == 0)
{
add_I_FRM(AX25Sess, AX25Sess->Path);
AX25Sess->status = STAT_LINK;
if (AX25Sess->I_frame_buf.Count > 0)
{
for (i = 0; i < AX25Sess->I_frame_buf.Count; i++)
{
if (i == AX25Sess->I_frame_buf.Count - 1)
PF_bit = SET_P;
else
PF_bit = SET_F;
add_pkt_buf(AX25Sess, make_frame(Strings(&AX25Sess->I_frame_buf, i), AX25Sess->Path, AX25Sess->PID, AX25Sess->vr, ((AX25Sess->i_lo + i) & 7), I_FRM, I_I, FALSE, PF_bit, SET_C));
}
AX25Sess->status = STAT_WAIT_ANS;
rst_timer(AX25Sess);
}
}
}
void send_data_buf_srej(TAX25Port * AX25Sess, int nr)
{
// Similar to send_data_buf but only sends the requested I frame with P set
int i = 0;
boolean new_frames;
boolean PF_bit;
if (AX25Sess->status != STAT_LINK)
return;
AX25Sess->IPOLL_cnt = 0;
AX25Sess->vs = nr;
delete_I_FRM(AX25Sess, nr); // ?? free acked frames
new_frames = FALSE;
add_I_FRM(AX25Sess, AX25Sess->Path);
AX25Sess->status = STAT_LINK;
new_frames = TRUE;
if (AX25Sess->I_frame_buf.Count > 0)
{
if (new_frames)
{
PF_bit = SET_P;
add_pkt_buf(AX25Sess, make_frame(Strings(&AX25Sess->I_frame_buf, i), AX25Sess->Path, AX25Sess->PID, AX25Sess->vr, ((AX25Sess->i_lo + i) & 7), I_FRM, I_I, FALSE, PF_bit, SET_C));
}
else
{
add_pkt_buf(AX25Sess, make_frame(Strings(&AX25Sess->I_frame_buf, 0), AX25Sess->Path, AX25Sess->PID, AX25Sess->vr, AX25Sess->i_lo, I_FRM, I_I, FALSE, SET_P, SET_C)); //SET_P
upd_vs(AX25Sess, AX25Sess->vs);
}
}
AX25Sess->status = STAT_WAIT_ANS;
rst_timer(AX25Sess);
}
void write_frame_collector(TAX25Port * AX25Sess, int ns, string * data)
{
Byte i;
char frm_ns;
string * frm;
boolean found ;
boolean need_frm;
if (max_frame_collector[AX25Sess->snd_ch] < 1)
return;
need_frm = FALSE;
i = 1;
do
{
if (ns == (AX25Sess->vr + i) & 7)
need_frm = TRUE;
i++;
} while (i <= max_frame_collector[AX25Sess->snd_ch] && !need_frm);
if (need_frm)
{
frm_ns = ns;
found = FALSE;
i = 0;
if (AX25Sess->frm_collector.Count > 0)
{
do
{
frm = Strings(&AX25Sess->frm_collector, i);
if (frm_ns == frm->Data[0])
found = TRUE;
i++;
}
while (!found && i != AX25Sess->frm_collector.Count);
}
if (!found)
{
string * frm = newString();
stringAdd(frm, (char *)&frm_ns, 1);
stringAdd(frm, data->Data, data->Length);
Add(&AX25Sess->frm_collector, frm);
}
}
}
string * read_frame_collector(TAX25Port * AX25Sess, boolean fecflag)
{
// Look for required frame no in saved frames
string * frm;
string * data = newString();
int i = 0;
boolean found = FALSE;
Byte frm_ns;
while (i < AX25Sess->frm_collector.Count)
{
frm = duplicateString(Strings(&AX25Sess->frm_collector, i));
frm_ns = frm->Data[0];
if (frm_ns == AX25Sess->vr)
{
Delete(&AX25Sess->frm_collector, i);
upd_vr(AX25Sess, AX25Sess->vr);
mydelete(frm, 0, 1); // Remove vr from front
stringAdd(data, frm->Data, frm->Length);
found = TRUE;
AX25Sess->info.stat_r_pkt++;
AX25Sess->info.stat_r_fc++;
if (fecflag)
AX25Sess->info.stat_fec_count++;
AX25Sess->info.stat_r_byte += frm->Length;
AX25Sess->frm_win[frm_ns].Length = frm->Length; //Save the frame to the window buffer
AX25Sess->frm_win[frm_ns].Data = frm->Data; //Save the frame to the window buffer
}
i++;
}
return data;
}
/////////////////////////// SET-FRAMES //////////////////////////////////
void set_chk_link(TAX25Port * AX25Sess, Byte * path)
{
boolean b_IPOLL;
int len;
AX25Sess->status = STAT_CHK_LINK;
// if AX25Sess->digi<>'' then path:=path+','+reverse_digi(AX25Sess->digi);
b_IPOLL = FALSE;
if (AX25Sess->I_frame_buf.Count > 0 && AX25Sess->IPOLL_cnt < 2)
{
len = Strings(&AX25Sess->I_frame_buf, 0)->Length;
if (len > 0 && len <= IPOLL[AX25Sess->snd_ch])
{
b_IPOLL = TRUE;
AX25Sess->IPOLL_cnt++;
}
}
if (b_IPOLL)
add_pkt_buf(AX25Sess, make_frame(Strings(&AX25Sess->I_frame_buf, 0), path, AX25Sess->PID, AX25Sess->vr, AX25Sess->i_lo, I_FRM, I_I, FALSE, SET_P, SET_C));
else
add_pkt_buf(AX25Sess, make_frame(NULL, path, 0xF0, AX25Sess->vr, 0, S_FRM, S_RR, FALSE, SET_P, SET_C));
inc_frack(AX25Sess);
}
// This seems to start a connection
void set_link(TAX25Port * AX25Sess, UCHAR * axpath)
{
if (AX25Sess->status != STAT_LINK)
{
string nullstring;
nullstring.Length = 0;
rst_values(AX25Sess);
AX25Sess->status = STAT_TRY_LINK;
// if (AX25Sess->digi[0] != 0)
// path: = path + ',' + reverse_digi(AX25Sess->digi);
add_pkt_buf(AX25Sess, make_frame(&nullstring, axpath, 0, 0, 0, U_FRM, U_SABM, SET_NO_RPT, SET_P, SET_C));
inc_frack(AX25Sess);
}
}
#define MODE_OUR 0
void set_try_unlink(TAX25Port * AX25Sess, Byte * path)
{
string nullstring;
nullstring.Length = 0;
AX25Sess->status = STAT_TRY_UNLINK;
add_pkt_buf(AX25Sess, make_frame(&nullstring, path, 0, 0, 0, U_FRM, U_DISC, SET_NO_RPT, SET_P, SET_C));
inc_frack(AX25Sess);
}
void set_unlink(TAX25Port * AX25Sess, Byte * path)
{
if (AX25Sess->status == STAT_TRY_UNLINK
|| AX25Sess->status == STAT_TRY_LINK
|| AX25Sess->status == STAT_NO_LINK)
{
string nullstring;
nullstring.Length = 0;
// if (AX25Sess->digi[0] != 0)
// path: = path + ',' + reverse_digi(AX25Sess->digi);
AGW_AX25_disc(AX25Sess, MODE_OUR);
if (AX25Sess->status != STAT_TRY_UNLINK)
add_pkt_buf(AX25Sess, make_frame(&nullstring, path, 0, 0, 0, U_FRM, U_DISC, SET_NO_RPT, SET_P, SET_C));
AX25Sess->info.stat_end_ses = time(NULL);
write_ax25_info(AX25Sess);
rst_values(AX25Sess);
memset(AX25Sess->corrcall, 0, 10);
memset(AX25Sess->mycall, 0, 10);
AX25Sess->digi[0] = 0;
AX25Sess->status = STAT_NO_LINK;
}
else
set_try_unlink(AX25Sess, AX25Sess->Path);
}
void set_FRMR(int snd_ch, Byte * path, unsigned char frameType)
{
//We may not have a session when sending FRMR so reverse path and send
Byte revpath[80];
string * Data = newString();
Data->Data[0] = frameType;
Data->Data[1] = 0;
Data->Data[2] = 1; // Invalid CTL Byte
Data->Length = 3;
reverse_addr(path, revpath, strlen(path));
add_pkt_buf(&AX25Port[snd_ch][0], make_frame(Data, revpath, 0, 0, 0, U_FRM, U_FRMR, FALSE, SET_P, SET_R));
freeString(Data);
}
void set_DM(int snd_ch, Byte * path)
{
//We may not have a session when sending DM so reverse path and send
Byte revpath[80];
reverse_addr(path, revpath, strlen(path));
add_pkt_buf(&AX25Port[snd_ch][0], make_frame(NULL, revpath, 0, 0, 0, U_FRM,U_DM,FALSE,SET_P,SET_R));
}
/////////////////////////// S-FRAMES ////////////////////////////////////
void on_RR(TAX25Port * AX25Sess, Byte * path, int nr, int pf, int cr)
{
char need_frame[16] = "";
int index = 0;
int i;
if (AX25Sess->status == STAT_TRY_LINK)
return;
if (AX25Sess->status == STAT_NO_LINK || AX25Sess->status == STAT_TRY_UNLINK)
{
if (cr == SET_C)
set_DM(AX25Sess->snd_ch, path);
return;
}
if (cr == SET_R)
{
// Determine which frames could get into the user<65>s frame buffer.
i = AX25Sess->vs;
need_frame[index++] = i + '0';
// Debugprintf("RR Rxed vs = %d hi_vs = %d", AX25Sess->vs, AX25Sess->hi_vs);
while (i != AX25Sess->hi_vs)
{
i = (i++) & 7;
need_frame[index++] = i + '0';
if (index > 10)
{
Debugprintf("Index corrupt %d need_frame = %s", index, need_frame);
break;
}
}
//Clear the received frames from the transmission buffer.
if (AX25Sess->status == STAT_WAIT_ANS)
delete_I_FRM(AX25Sess, nr);
// We restore the link if the number is valid
if (AX25Sess->status == STAT_CHK_LINK || strchr(need_frame, nr + '0') > 0)
{
rst_timer(AX25Sess);
AX25Sess->status = STAT_LINK;
send_data_buf(AX25Sess, nr);
}
}
if (cr == SET_C)
add_pkt_buf(AX25Sess, make_frame(NULL, path, 0, AX25Sess->vr, 0, S_FRM, S_RR, FALSE, pf, SET_R));
rst_t3(AX25Sess);
}
void on_RNR(TAX25Port * AX25Sess, Byte * path, int nr, int pf, int cr)
{
if (AX25Sess->status == STAT_TRY_LINK)
return;
if (AX25Sess->status == STAT_NO_LINK || AX25Sess->status == STAT_TRY_UNLINK)
{
if (cr == SET_C)
set_DM(AX25Sess->snd_ch, path);
return;
}
if (cr == SET_R)
{
rst_timer(AX25Sess);
if (AX25Sess->status == STAT_WAIT_ANS)
delete_I_FRM(AX25Sess, nr);
AX25Sess->status = STAT_CHK_LINK;
}
if (cr == SET_C)
add_pkt_buf(AX25Sess, make_frame(NULL, path, 0, AX25Sess->vr, 0, S_FRM, S_RR, FALSE, SET_P, SET_R));
rst_t3(AX25Sess);
}
void on_REJ(TAX25Port * AX25Sess, Byte * path, int nr, int pf, int cr)
{
if (AX25Sess->status == STAT_TRY_LINK)
return;
if (AX25Sess->status == STAT_NO_LINK || AX25Sess->status == STAT_TRY_UNLINK)
{
if (cr == SET_C)
set_DM(AX25Sess->snd_ch, path);
return;
}
if (cr == SET_R)
{
rst_timer(AX25Sess);
AX25Sess->status = STAT_LINK;
send_data_buf(AX25Sess, nr);
}
if (cr == SET_C)
add_pkt_buf(AX25Sess, make_frame(NULL, path, 0, AX25Sess->vr, 0, S_FRM, S_RR, FALSE, SET_P, SET_R));
}
void on_SREJ(TAX25Port * AX25Sess, Byte * path, int nr, int pf, int cr)
{
if (AX25Sess->status == STAT_TRY_LINK)
return;
if (AX25Sess->status == STAT_NO_LINK || AX25Sess->status == STAT_TRY_UNLINK)
{
if (cr == SET_C)
set_DM(AX25Sess->snd_ch, path);
return;
}
if (cr == SET_R)
{
rst_timer(AX25Sess);
AX25Sess->status = STAT_LINK;
send_data_buf_srej(AX25Sess, nr);
}
if (cr == SET_C)
add_pkt_buf(AX25Sess, make_frame(NULL, path, 0, AX25Sess->vr, 0, S_FRM, S_RR, FALSE, SET_P, SET_R));
}
/////////////////////////// I-FRAMES ////////////////////////////////////
void on_I(void * socket, TAX25Port * AX25Sess, int PID, Byte * path, string * data, int nr, int ns, int pf, int cr, boolean fecflag)
{
string * collector_data;
int i;
Byte need_frame[16] = "";
int index = 0;
{
if (AX25Sess->status == STAT_TRY_LINK)
return;
if (AX25Sess->status == STAT_NO_LINK || AX25Sess->status == STAT_TRY_UNLINK)
{
set_DM(0, path);
return;
}
if (busy)
{
add_pkt_buf(AX25Sess, make_frame(NULL, path, PID, AX25Sess->vr, 0, S_FRM, S_RNR, FALSE, pf, SET_R));
return;
}
// Determine which frames could get into the user<65>s frame buffer.
i = AX25Sess->vs;
need_frame[index++] = i + '0';
// Debugprintf("I Rxed vs = %d hi_vs = %d", AX25Sess->vs, AX25Sess->hi_vs);
while (i != AX25Sess->hi_vs)
{
i = (i++) & 7;
need_frame[index++] = i + '0';
if (index > 10)
{
Debugprintf("Index corrupt %d need_frame = %s", index, need_frame);
break;
}
}
//Clear received frames from the transmission buffer.
if (AX25Sess->status == STAT_WAIT_ANS)
delete_I_FRM(AX25Sess, nr);
//We restore the link if the number is valid
if (AX25Sess->status == STAT_CHK_LINK || strchr(need_frame, nr + '0') > 0)
{
//We restore the link if the number is valid
rst_timer(AX25Sess);
AX25Sess->status = STAT_LINK;
send_data_buf(AX25Sess, nr);
}
if (ns == AX25Sess->vr)
{
//If the expected frame, send RR, F
AX25Sess->info.stat_r_pkt++;
AX25Sess->info.stat_r_byte += data->Length;
if (fecflag)
AX25Sess->info.stat_fec_count++;
upd_vr(AX25Sess, AX25Sess->vr);
AX25Sess->frm_win[ns].Length = data->Length; //Save the frame to the window buffer
AX25Sess->frm_win[ns].Data = data->Data; //Save the frame to the window buffer
collector_data = read_frame_collector(AX25Sess, fecflag);
AGW_AX25_data_in(socket, AX25Sess->snd_ch, PID, path, stringAdd(data, collector_data->Data, collector_data->Length));
add_pkt_buf(AX25Sess, make_frame(NULL, path, 0, AX25Sess->vr, 0, S_FRM, S_RR, FALSE, pf, SET_R));
}
else
{
// If the frame is not expected, send REJ, F
if ((AX25Sess->frm_win[ns].Length != data->Length) &&
memcmp(&AX25Sess->frm_win[ns].Data, data->Data, data->Length) != 0)
write_frame_collector(AX25Sess, ns, data);
add_pkt_buf(AX25Sess, make_frame(NULL, path, 0, AX25Sess->vr, 0, S_FRM, S_REJ, FALSE, pf, SET_R));
}
rst_t3(AX25Sess);
}
}
/////////////////////////// U-FRAMES ////////////////////////////////////
void on_SABM(void * socket, TAX25Port * AX25Sess)
{
if (AX25Sess->status == STAT_TRY_UNLINK)
{
AX25Sess->info.stat_end_ses = time(NULL);
write_ax25_info(AX25Sess);
rst_values(AX25Sess);
memset(AX25Sess->corrcall, 0, 10);
memset(AX25Sess->mycall, 0, 10);
AX25Sess->digi[0] = 0;
AGW_AX25_disc(AX25Sess, MODE_OTHER);
Clear(&AX25Sess->frame_buf);
AX25Sess->status = STAT_NO_LINK;
}
if (AX25Sess->status == STAT_TRY_LINK)
{
AGW_AX25_disc(AX25Sess, MODE_OTHER);
rst_timer(AX25Sess);
rst_values(AX25Sess);
Clear(&AX25Sess->frame_buf);
AX25Sess->status = STAT_NO_LINK;
}
if (AX25Sess->status != STAT_NO_LINK)
{
if ((strcmp(AX25Sess->kind, "Outgoing") == 0) ||
AX25Sess->status == STAT_TRY_UNLINK || AX25Sess->info.stat_s_byte > 0 ||
AX25Sess->info.stat_r_byte > 0 || AX25Sess->frm_collector.Count > 0)
{
AX25Sess->info.stat_end_ses = time(NULL);
AGW_AX25_disc(AX25Sess, MODE_OTHER);
write_ax25_info(AX25Sess);
rst_timer(AX25Sess);
rst_values(AX25Sess);
Clear(&AX25Sess->frame_buf);
AX25Sess->status = STAT_NO_LINK;
}
}
if (AX25Sess->status == STAT_NO_LINK)
{
AGW_AX25_conn(AX25Sess, AX25Sess->snd_ch, MODE_OTHER);
AX25Sess->vr = 0;
AX25Sess->vs = 0;
AX25Sess->hi_vs = 0;
Clear(&AX25Sess->frm_collector);
clr_frm_win(AX25Sess);
AX25Sess->status = STAT_LINK;
AX25Sess->info.stat_begin_ses = time(NULL);
strcpy(AX25Sess->kind, "Incoming");
AX25Sess->socket = socket;
if (RSID_SABM[AX25Sess->snd_ch]) // Send RSID before SABM/UA
needRSID[AX25Sess->snd_ch] = 1;
}
add_pkt_buf(AX25Sess, make_frame(NULL, AX25Sess->Path, 0, 0, 0, U_FRM, U_UA, FALSE, SET_P, SET_R));
}
void on_DISC(void * socket, TAX25Port * AX25Sess)
{
if (AX25Sess->status != STAT_NO_LINK)
{
AX25Sess->info.stat_end_ses = time(NULL);
AGW_AX25_disc(AX25Sess, MODE_OTHER);
write_ax25_info(AX25Sess);
}
if (AX25Sess->status == STAT_NO_LINK || AX25Sess->status == STAT_TRY_LINK)
set_DM(AX25Sess->snd_ch, AX25Sess->Path);
else
{
add_pkt_buf(AX25Sess, make_frame(NULL, AX25Sess->Path, 0, 0, 0, U_FRM, U_UA, FALSE, SET_P, SET_R));
if (RSID_SABM[AX25Sess->snd_ch]) // Send RSID before SABM/UA
needRSID[AX25Sess->snd_ch] = 1;
}
rst_values(AX25Sess);
memset(AX25Sess->corrcall, 0, 10);
memset(AX25Sess->mycall, 0, 10);
AX25Sess->digi[0] = 0;
AX25Sess->status = STAT_NO_LINK;
}
void on_DM(void * socket, TAX25Port * AX25Sess)
{
if (AX25Sess->status != STAT_NO_LINK)
{
AX25Sess->info.stat_end_ses = time(NULL);
AGW_AX25_disc(AX25Sess, MODE_OTHER);
write_ax25_info(AX25Sess);
}
rst_timer(AX25Sess);
rst_values(AX25Sess);
memset(AX25Sess->corrcall, 0, 10);
memset(AX25Sess->mycall, 0, 10);
AX25Sess->digi[0] = 0;
AX25Sess->status = STAT_NO_LINK;
}
void on_UA(void *socket, TAX25Port * AX25Sess)
{
switch (AX25Sess->status)
{
case STAT_TRY_LINK:
AX25Sess->info.stat_begin_ses = time(NULL);
AX25Sess->status = STAT_LINK;
AGW_AX25_conn(AX25Sess, AX25Sess->snd_ch, MODE_OUR);
break;
case STAT_TRY_UNLINK:
AX25Sess->info.stat_end_ses = time(NULL);
AGW_AX25_disc(AX25Sess, MODE_OUR);
write_ax25_info(AX25Sess);
rst_values(AX25Sess);
AX25Sess->status = STAT_NO_LINK;
memset(AX25Sess->corrcall, 0, 10);
memset(AX25Sess->mycall, 0, 10);
AX25Sess->digi[0] = 0;
break;
}
rst_timer(AX25Sess);
}
void on_UI(TAX25Port * AX25Sess, int pf, int cr)
{
}
void on_FRMR(void * socket, TAX25Port * AX25Sess, Byte * path)
{
if (AX25Sess->status != STAT_NO_LINK)
{
AX25Sess->info.stat_end_ses = time(NULL);
2024-10-29 22:45:21 +00:00
AGW_AX25_disc(AX25Sess, MODE_OTHER);
2023-09-04 19:06:44 +01:00
write_ax25_info(AX25Sess);
}
set_DM(AX25Sess->snd_ch, path);
rst_values(AX25Sess);
memset(AX25Sess->corrcall, 0, 10);
memset(AX25Sess->mycall, 0, 10);
AX25Sess->digi[0] = 0;
AX25Sess->status = STAT_NO_LINK;
}
void UpdateActiveConnects(int snd_ch)
{
int port;
users[snd_ch] = 0;
for (port = 0; port < port_num; port++)
if (AX25Port[snd_ch][port].status != STAT_NO_LINK)
users[snd_ch]++;
}
void timer_event()
{
int snd_ch, port;
void * socket;
single frack;
Byte active;
TAX25Port * AX25Sess;
TimerEvent = TIMER_EVENT_OFF;
for (snd_ch = 0; snd_ch < 4; snd_ch++)
{
//reset the slottime timer
if (dyn_frack[snd_ch])
{
UpdateActiveConnects(snd_ch);
if (users[snd_ch] > 0)
active = users[snd_ch] - 1;
else
active = 0;
frack = frack_time[snd_ch] + frack_time[snd_ch] * active * 0.5;
}
else
frack = frack_time[snd_ch];
//
for (port = 0; port < port_num; port++)
{
AX25Sess = &AX25Port[snd_ch][port];
if (AX25Sess->status == STAT_NO_LINK)
continue;
if (snd_status[snd_ch] != SND_TX) //when at the reception
if (AX25Sess->frame_buf.Count == 0) //when the transfer buffer is empty
inc_t1(AX25Sess); // we consider time of the timer of repeated requests
// Wouldn't it make more sense to keep path in ax.25 struct?
if (AX25Sess->t1 >= frack * 10 + (number_digi(AX25Sess->digi) * frack * 20))
{
if (AX25Sess->clk_frack >= fracks[snd_ch])
{
// This disconnects after retries expires
rst_frack(AX25Sess);
//socket:=get_incoming_socket_by_call(AX25Sess->mycall);
set_unlink(AX25Sess, AX25Sess->Path);
}
switch (AX25Sess->status)
{
case STAT_TRY_LINK:
set_link(AX25Sess, AX25Sess->Path);
break;
case STAT_TRY_UNLINK:
set_try_unlink(AX25Sess, AX25Sess->Path);
break;
case STAT_WAIT_ANS:
set_chk_link(AX25Sess, AX25Sess->Path);
break;
case STAT_CHK_LINK:
set_chk_link(AX25Sess, AX25Sess->Path);
break;
}
rst_t1(AX25Sess);
}
if (AX25Sess->t3 >= idletime[snd_ch] * 10)
{
set_chk_link(AX25Sess, AX25Sess->Path);
rst_t1(AX25Sess);
rst_t3(AX25Sess);
}
if (AX25Sess->status == STAT_LINK)
inc_t3(AX25Sess);
}
}
// KISS ACKMODE
//if (snd_status[snd_ch]<>SND_TX) and KISSServ then KISS_send_ack1(snd_ch);
}
TAX25Port * get_free_port(int snd_ch)
{
int i;
int need_free_port;
i = 0;
need_free_port = FALSE;
while (i < port_num)
{
if (AX25Port[snd_ch][i].status == STAT_NO_LINK)
return &AX25Port[snd_ch][i];
i++;
}
return FALSE;
}
TAX25Port * get_user_port(int snd_ch, Byte * path)
{
TAX25Port * AX25Sess = NULL;
int i = 0;
int port = 0;
while (i < port_num)
{
AX25Sess = &AX25Port[snd_ch][i];
if (AX25Sess->status != STAT_NO_LINK && memcmp(AX25Sess->ReversePath, path, AX25Sess->pathLen) == 0)
return AX25Sess;
i++;
}
return FALSE;
}
boolean get_user_dupe(int snd_ch, Byte * path)
{
int i = 0;
TAX25Port * AX25Sess;
while (i < port_num)
{
AX25Sess = &AX25Port[snd_ch][i];
if (AX25Sess->status != STAT_NO_LINK && memcmp(AX25Sess->ReversePath, path, AX25Sess->pathLen) == 0)
return TRUE;
i++;
}
return FALSE;
}
TAX25Port * get_user_port_by_calls(int snd_ch, char * CallFrom, char * CallTo)
{
int i = 0;
TAX25Port * AX25Sess = NULL;
while (i < port_num)
{
AX25Sess = &AX25Port[snd_ch][i];
if (AX25Sess->status != STAT_NO_LINK &&
strcmp(CallFrom, AX25Sess->mycall) == 0 && strcmp(CallTo, AX25Sess->corrcall) == 0)
return AX25Sess;
i++;
}
return NULL;
}
void * get_sock_by_port(TAX25Port * AX25Sess)
{
void * socket = (void *)-1;
if (AX25Sess)
socket = AX25Sess->socket;
return socket;
}
void Digipeater(int snd_ch, string * frame)
{
boolean addr_end, flag_replaced, digi_stop;
word crc;
char call[16];
Byte * addr = &frame->Data[7]; // Origon
int len = frame->Length - 2; // not FCS
string * frameCopy;
int n = 8; // Max digis
if (list_digi_callsigns[snd_ch].Count == 0)
return;
// Look for first unused digi
while ((addr[6] & 1) == 0 && n--) // until end of address
{
addr += 7;
if ((addr[6] & 128) == 0)
{
// unused digi - is it addressed to us?
UCHAR CRCString[2];
memcpy(call, addr, 7);
call[6] &= 0x7E; // Mask end of call
// See if in digi list
int i;
for (i = 0; i < list_digi_callsigns->Count; i++)
{
if (memcmp(list_digi_callsigns->Items[i]->Data, call, 7) == 0)
{
// for us
addr[6] |= 128; // set digi'ed
// TX Frames need a KISS control on front
frameCopy = newString();
frameCopy->Data[0] = 0;
frameCopy->Length = 1;
stringAdd(frameCopy, frame->Data, frame->Length - 2); // Exclude CRC
addr[6] &= 0x7f; // clear digi'ed from original;
// Need to redo crc
crc = get_fcs(frameCopy->Data, len);
CRCString[0] = crc & 0xff;
CRCString[1] = crc >> 8;
stringAdd(frameCopy, CRCString, 2);
Add(&all_frame_buf[snd_ch], frameCopy);
return;
}
}
}
}
}
void analiz_frame(int snd_ch, string * frame, char * code, boolean fecflag)
{
int port, free_port;
Byte path[80];
string *data = newString();
Byte pid, nr, ns, f_type, f_id, rpt, cr, pf;
boolean need_free_port;
void * socket = NULL;
boolean incoming_conn = 0;
Byte revpath[80];
int pathlen;
Byte * ptr;
int excluded = 0;
int len;
TAX25Port * AX25Sess;
// mod_icon_status = mod_rx;
len = frame->Length;
if (len < PKT_ERR)
return;
2024-10-29 22:45:21 +00:00
bytes[snd_ch] += frame->Length; // For AGW stats
if (AGWServ)
AGW_AX25_frame_analiz(snd_ch, TRUE, frame);
2023-09-04 19:06:44 +01:00
decode_frame(frame->Data, frame->Length, path, data, &pid, &nr, &ns, &f_type, &f_id, &rpt, &pf, &cr);
if (is_excluded_call(snd_ch, path))
2024-10-29 22:45:21 +00:00
excluded = TRUE;
2023-09-04 19:06:44 +01:00
// if is_excluded_frm(snd_ch,f_id,data) then excluded:=TRUE;
if (excluded)
return;
if (NonAX25[snd_ch])
{
if (AGWServ)
AGW_Raw_monitor(snd_ch, frame);
if (KISSServ)
KISS_on_data_out(snd_ch, frame, 0);
}
// CRC Collision Check
if (!is_correct_path(path, pid))
{
// Duff path - if Non-AX25 filter active log and discard
if (NonAX25[snd_ch])
{
put_frame(snd_ch, frame, "NON-AX25", FALSE, excluded);
return;
}
}
put_frame(snd_ch, frame, code, 0, excluded); // Monitor
if (!NonAX25[snd_ch])
{
if (AGWServ)
AGW_Raw_monitor(snd_ch, frame);
if (KISSServ)
2024-10-29 22:45:21 +00:00
{
if (useKISSControls)
{
// Send a KISS Control frame with frame stats before data frame
int len = strlen(code);
UCHAR * Control = (UCHAR *)malloc(64);
len = sprintf(Control, "%c%cPKTINFO [%s]%c", FEND, (snd_ch) << 4 | QTSMKISSCMD, code, FEND);
KISSSendtoServer(NULL, Control, len);
}
2023-09-04 19:06:44 +01:00
KISS_on_data_out(snd_ch, frame, 0);
2024-10-29 22:45:21 +00:00
}
2023-09-04 19:06:44 +01:00
}
// Digipeat frame
Digipeater(snd_ch, frame);
if (!is_last_digi(path))
return; // Don't process if still unused digis
// Clear reapeated bits from digi path
ptr = &path[13];
while ((*ptr & 1) == 0) // end of address
{
ptr += 7;
*(ptr) &= 0x7f; // Clear digi'd bit
}
// search for port of correspondent
AX25Sess = get_user_port(snd_ch, path);
// if not an active session, AX25Sess will be NULL
if (AX25Sess == NULL)
socket = in_list_incoming_mycall(path);
else
socket = get_sock_by_port(AX25Sess);
// link analysis
if (AX25Sess == NULL)
{
// No Session. If socket is set (so call is in incoming calls list) and SABM set up session
if (socket == NULL)
return; // not for us
if (f_id != U_SABM) // Not SABM
{
// // send DM if P set
if (cr == SET_C)
{
switch (f_id)
{
case U_DISC:
case S_RR:
case S_REJ:
case S_RNR:
case I_I:
set_DM(snd_ch, path);
break;
case U_UI:
break;
default:
set_FRMR(snd_ch, path, f_id);
}
}
return;
}
// Must be SABM. See if it would duplicate an existing session (but could it - wouldn't that be found earlier ??
if (get_user_dupe(snd_ch, path)) // Not SABM or a duplicate call pair
return;
AX25Sess = get_free_port(snd_ch);
if (AX25Sess == NULL)
{
// if there are no free ports for connection - beat off
Byte Rev[80];
reverse_addr(path, Rev, strlen(path));
set_DM(snd_ch, Rev);
return;
}
// initialise new session
AX25Sess->snd_ch = snd_ch;
AX25Sess->corrcall[ConvFromAX25(&path[7], AX25Sess->corrcall)] = 0;
AX25Sess->mycall[ConvFromAX25(path, AX25Sess->mycall)] = 0;
AX25Sess->digi[0] = 0;
// rst_timer(snd_ch, free_port);
strcpy(AX25Sess->kind, "Incoming");
AX25Sess->socket = socket;
Debugprintf("incoming call socket = %x", socket);
// I think we need to reverse the path
AX25Sess->pathLen = strlen(path);
strcpy(AX25Sess->ReversePath, path);
reverse_addr(path, AX25Sess->Path, strlen(path));
}
// we process a packet on the necessary port
memcpy(path, AX25Sess->Path, AX25Sess->pathLen);
switch (f_id)
{
case I_I:
on_I(socket, AX25Sess, pid, path, data, nr, ns, pf, cr, fecflag);
break;
case S_RR:
on_RR(AX25Sess, path, nr, pf, cr);
break;
case S_RNR:
on_RNR(AX25Sess, path, nr, pf, cr);
break;
case S_REJ:
on_REJ(AX25Sess, path, nr, pf, cr);
break;
case S_SREJ:
on_SREJ(AX25Sess, path, nr, pf, cr);
break;
case U_SABM:
on_SABM(socket, AX25Sess);
break;
case U_DISC:
on_DISC(socket, AX25Sess);
break;
case U_UA:
on_UA(socket, AX25Sess);
break;
case U_DM:
on_DM(socket, AX25Sess);
break;
case U_UI:
on_UI(AX25Sess, pf, cr);
break;
case U_FRMR:
on_FRMR(socket, AX25Sess, path);
break;
}
}