mirror of https://github.com/wb2osz/direwolf.git
AGW network protocol now works properly for big-endian
processors such as PowerPC or MIPS.
This commit is contained in:
parent
0c496541e5
commit
4406c1a5e3
10
CHANGES.md
10
CHANGES.md
|
@ -1,6 +1,16 @@
|
||||||
|
|
||||||
# Revision History #
|
# Revision History #
|
||||||
|
|
||||||
|
----------
|
||||||
|
|
||||||
|
## Version 1.3 -- Development snapshot J -- January 2016 ##
|
||||||
|
|
||||||
|
### Bugs Fixed: ###
|
||||||
|
|
||||||
|
- AGW network protocol now works properly for big-endian processors
|
||||||
|
such as PowerPC or MIPS.
|
||||||
|
|
||||||
|
|
||||||
----------
|
----------
|
||||||
|
|
||||||
## Version 1.3 -- Development snapshot I -- December 2015 ##
|
## Version 1.3 -- Development snapshot I -- December 2015 ##
|
||||||
|
|
|
@ -231,7 +231,7 @@ int main (int argc, char *argv[])
|
||||||
text_color_init(t_opt);
|
text_color_init(t_opt);
|
||||||
text_color_set(DW_COLOR_INFO);
|
text_color_set(DW_COLOR_INFO);
|
||||||
//dw_printf ("Dire Wolf version %d.%d (%s) Beta Test\n", MAJOR_VERSION, MINOR_VERSION, __DATE__);
|
//dw_printf ("Dire Wolf version %d.%d (%s) Beta Test\n", MAJOR_VERSION, MINOR_VERSION, __DATE__);
|
||||||
dw_printf ("Dire Wolf DEVELOPMENT version %d.%d %s (%s)\n", MAJOR_VERSION, MINOR_VERSION, "I", __DATE__);
|
dw_printf ("Dire Wolf DEVELOPMENT version %d.%d %s (%s)\n", MAJOR_VERSION, MINOR_VERSION, "J", __DATE__);
|
||||||
//dw_printf ("Dire Wolf version %d.%d\n", MAJOR_VERSION, MINOR_VERSION);
|
//dw_printf ("Dire Wolf version %d.%d\n", MAJOR_VERSION, MINOR_VERSION);
|
||||||
|
|
||||||
#if defined(ENABLE_GPSD) || defined(USE_HAMLIB)
|
#if defined(ENABLE_GPSD) || defined(USE_HAMLIB)
|
||||||
|
|
464
server.c
464
server.c
|
@ -162,6 +162,21 @@ static int enable_send_monitor_to_client[MAX_NET_CLIENTS];
|
||||||
/* the client app must send a command to enable this. */
|
/* the client app must send a command to enable this. */
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Registered callsigns from 'X' command.
|
||||||
|
* For simplicity just use a fixed size array until there
|
||||||
|
* is evidence that a larger number would be needed.
|
||||||
|
*
|
||||||
|
* Also keep track of which client did the registration.
|
||||||
|
* For example client 0 might register the callsign ABC
|
||||||
|
* and client 1 register DEF. If something comes addressed
|
||||||
|
* to DEF, we would want it going only to client 1.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define MAX_REG_CALLSIGNS 20
|
||||||
|
|
||||||
|
static char registered_callsigns[MAX_REG_CALLSIGNS][AX25_MAX_ADDR_LEN];
|
||||||
|
static int registered_by_client[MAX_REG_CALLSIGNS];
|
||||||
|
|
||||||
|
|
||||||
// TODO: define in one place, use everywhere.
|
// TODO: define in one place, use everywhere.
|
||||||
|
@ -178,28 +193,77 @@ static THREAD_F cmd_listen_thread (void *arg);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Message header for AGW protocol.
|
* Message header for AGW protocol.
|
||||||
* Assuming little endian such as x86 or ARM.
|
* Multibyte numeric values require rearranging for big endian cpu.
|
||||||
* Byte swapping would be required for big endian cpu.
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#if __GNUC__
|
/*
|
||||||
#if __BYTE_ORDER__ != __ORDER_LITTLE_ENDIAN__
|
* With MinGW version 4.6, obviously x86.
|
||||||
#error This needs to be more portable to work on big endian.
|
* or Linux gcc version 4.9, Linux ARM.
|
||||||
#endif
|
*
|
||||||
|
* $ gcc -E -dM - < /dev/null | grep END
|
||||||
|
* #define __ORDER_LITTLE_ENDIAN__ 1234
|
||||||
|
* #define __FLOAT_WORD_ORDER__ __ORDER_LITTLE_ENDIAN__
|
||||||
|
* #define __ORDER_PDP_ENDIAN__ 3412
|
||||||
|
* #define __ORDER_BIG_ENDIAN__ 4321
|
||||||
|
* #define __BYTE_ORDER__ __ORDER_LITTLE_ENDIAN__
|
||||||
|
*
|
||||||
|
* This is for standard OpenWRT on MIPS.
|
||||||
|
*
|
||||||
|
* #define __ORDER_LITTLE_ENDIAN__ 1234
|
||||||
|
* #define __FLOAT_WORD_ORDER__ __ORDER_BIG_ENDIAN__
|
||||||
|
* #define __ORDER_PDP_ENDIAN__ 3412
|
||||||
|
* #define __ORDER_BIG_ENDIAN__ 4321
|
||||||
|
* #define __BYTE_ORDER__ __ORDER_BIG_ENDIAN__
|
||||||
|
*
|
||||||
|
* This was reported for an old Mac with PowerPC processor.
|
||||||
|
* (Newer versions have x86.)
|
||||||
|
*
|
||||||
|
* $ gcc -E -dM - < /dev/null | grep END
|
||||||
|
* #define __BIG_ENDIAN__ 1
|
||||||
|
* #define _BIG_ENDIAN 1
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#if defined(__BIG_ENDIAN__) || (defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)
|
||||||
|
|
||||||
|
// gcc >= 4.2 has __builtin_swap32() but be compatible with older versions.
|
||||||
|
|
||||||
|
#define host2netle(x) ( (((x)>>24)&0x000000ff) | (((x)>>8)&0x0000ff00) | (((x)<<8)&0x00ff0000) | (((x)<<24)&0xff000000) )
|
||||||
|
#define netle2host(x) ( (((x)>>24)&0x000000ff) | (((x)>>8)&0x0000ff00) | (((x)<<8)&0x00ff0000) | (((x)<<24)&0xff000000) )
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
#define host2netle(x) (x)
|
||||||
|
#define netle2host(x) (x)
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
struct agwpe_s {
|
struct agwpe_s {
|
||||||
short portx; /* 0 for first, 1 for second, etc. */
|
unsigned char portx; /* 0 for first, 1 for second, etc. */
|
||||||
short port_hi_reserved;
|
unsigned char reserved1;
|
||||||
short kind_lo; /* message type */
|
unsigned char reserved2;
|
||||||
short kind_hi;
|
unsigned char reserved3;
|
||||||
|
|
||||||
|
unsigned char datakind; /* message type, usually written as a letter. */
|
||||||
|
unsigned char reserved4;
|
||||||
|
unsigned char pid;
|
||||||
|
unsigned char reserved5;
|
||||||
|
|
||||||
char call_from[10];
|
char call_from[10];
|
||||||
|
|
||||||
char call_to[10];
|
char call_to[10];
|
||||||
int data_len; /* Number of data bytes following. */
|
|
||||||
int user_reserved;
|
int data_len_NETLE; /* Number of data bytes following. */
|
||||||
|
/* _NETLE suffix is reminder to convert for network byte order. */
|
||||||
|
|
||||||
|
int user_reserved_NETLE;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
static void send_to_client (int client, void *reply_p);
|
||||||
|
|
||||||
|
|
||||||
/*-------------------------------------------------------------------
|
/*-------------------------------------------------------------------
|
||||||
*
|
*
|
||||||
* Name: debug_print
|
* Name: debug_print
|
||||||
|
@ -258,7 +322,7 @@ static void debug_print (fromto_t fromto, int client, struct agwpe_s *pmsg, int
|
||||||
case FROM_CLIENT:
|
case FROM_CLIENT:
|
||||||
strlcpy (direction, "from", sizeof(direction)); /* from the client application */
|
strlcpy (direction, "from", sizeof(direction)); /* from the client application */
|
||||||
|
|
||||||
switch (pmsg->kind_lo) {
|
switch (pmsg->datakind) {
|
||||||
case 'P': strlcpy (datakind, "Application Login", sizeof(datakind)); break;
|
case 'P': strlcpy (datakind, "Application Login", sizeof(datakind)); break;
|
||||||
case 'X': strlcpy (datakind, "Register CallSign", sizeof(datakind)); break;
|
case 'X': strlcpy (datakind, "Register CallSign", sizeof(datakind)); break;
|
||||||
case 'x': strlcpy (datakind, "Unregister CallSign", sizeof(datakind)); break;
|
case 'x': strlcpy (datakind, "Unregister CallSign", sizeof(datakind)); break;
|
||||||
|
@ -286,7 +350,7 @@ static void debug_print (fromto_t fromto, int client, struct agwpe_s *pmsg, int
|
||||||
default:
|
default:
|
||||||
strlcpy (direction, "to", sizeof(direction)); /* sent to the client application. */
|
strlcpy (direction, "to", sizeof(direction)); /* sent to the client application. */
|
||||||
|
|
||||||
switch (pmsg->kind_lo) {
|
switch (pmsg->datakind) {
|
||||||
case 'R': strlcpy (datakind, "Version Number", sizeof(datakind)); break;
|
case 'R': strlcpy (datakind, "Version Number", sizeof(datakind)); break;
|
||||||
case 'X': strlcpy (datakind, "Callsign Registration", sizeof(datakind)); break;
|
case 'X': strlcpy (datakind, "Callsign Registration", sizeof(datakind)); break;
|
||||||
case 'G': strlcpy (datakind, "Port Information", sizeof(datakind)); break;
|
case 'G': strlcpy (datakind, "Port Information", sizeof(datakind)); break;
|
||||||
|
@ -296,6 +360,7 @@ static void debug_print (fromto_t fromto, int client, struct agwpe_s *pmsg, int
|
||||||
case 'H': strlcpy (datakind, "Heard Stations on a Port", sizeof(datakind)); break;
|
case 'H': strlcpy (datakind, "Heard Stations on a Port", sizeof(datakind)); break;
|
||||||
case 'C': strlcpy (datakind, "AX.25 Connection Received", sizeof(datakind)); break;
|
case 'C': strlcpy (datakind, "AX.25 Connection Received", sizeof(datakind)); break;
|
||||||
case 'D': strlcpy (datakind, "Connected AX.25 Data", sizeof(datakind)); break;
|
case 'D': strlcpy (datakind, "Connected AX.25 Data", sizeof(datakind)); break;
|
||||||
|
case 'd': strlcpy (datakind, "Disconnected", sizeof(datakind)); break;
|
||||||
case 'M': strlcpy (datakind, "Monitored Connected Information", sizeof(datakind)); break;
|
case 'M': strlcpy (datakind, "Monitored Connected Information", sizeof(datakind)); break;
|
||||||
case 'S': strlcpy (datakind, "Monitored Supervisory Information", sizeof(datakind)); break;
|
case 'S': strlcpy (datakind, "Monitored Supervisory Information", sizeof(datakind)); break;
|
||||||
case 'U': strlcpy (datakind, "Monitored Unproto Information", sizeof(datakind)); break;
|
case 'U': strlcpy (datakind, "Monitored Unproto Information", sizeof(datakind)); break;
|
||||||
|
@ -311,20 +376,19 @@ static void debug_print (fromto_t fromto, int client, struct agwpe_s *pmsg, int
|
||||||
dw_printf ("%s %s %s AGWPE client application %d, total length = %d\n",
|
dw_printf ("%s %s %s AGWPE client application %d, total length = %d\n",
|
||||||
prefix[(int)fromto], datakind, direction, client, msg_len);
|
prefix[(int)fromto], datakind, direction, client, msg_len);
|
||||||
|
|
||||||
dw_printf ("\tportx = %d, port_hi_reserved = %d\n", pmsg->portx, pmsg->port_hi_reserved);
|
dw_printf ("\tportx = %d, datakind = '%c', pid = 0x%02x\n", pmsg->portx, pmsg->datakind, pmsg->pid);
|
||||||
dw_printf ("\tkind_lo = %d = '%c', kind_hi = %d\n", pmsg->kind_lo, pmsg->kind_lo, pmsg->kind_hi);
|
|
||||||
dw_printf ("\tcall_from = \"%s\", call_to = \"%s\"\n", pmsg->call_from, pmsg->call_to);
|
dw_printf ("\tcall_from = \"%s\", call_to = \"%s\"\n", pmsg->call_from, pmsg->call_to);
|
||||||
dw_printf ("\tdata_len = %d, user_reserved = %d, data =\n", pmsg->data_len, pmsg->user_reserved);
|
dw_printf ("\tdata_len = %d, user_reserved = %d, data =\n", netle2host(pmsg->data_len_NETLE), netle2host(pmsg->user_reserved_NETLE));
|
||||||
|
|
||||||
hex_dump ((unsigned char*)pmsg + sizeof(struct agwpe_s), pmsg->data_len);
|
hex_dump ((unsigned char*)pmsg + sizeof(struct agwpe_s), netle2host(pmsg->data_len_NETLE));
|
||||||
|
|
||||||
if (msg_len < 36) {
|
if (msg_len < 36) {
|
||||||
text_color_set (DW_COLOR_ERROR);
|
text_color_set (DW_COLOR_ERROR);
|
||||||
dw_printf ("AGWPE message length, %d, is shorter than minumum 36.\n", msg_len);
|
dw_printf ("AGWPE message length, %d, is shorter than minumum 36.\n", msg_len);
|
||||||
}
|
}
|
||||||
if (msg_len != pmsg->data_len + 36) {
|
if (msg_len != netle2host(pmsg->data_len_NETLE) + 36) {
|
||||||
text_color_set (DW_COLOR_ERROR);
|
text_color_set (DW_COLOR_ERROR);
|
||||||
dw_printf ("AGWPE message length, %d, inconsistent with data length %d.\n", msg_len, pmsg->data_len);
|
dw_printf ("AGWPE message length, %d, inconsistent with data length %d.\n", msg_len, netle2host(pmsg->data_len_NETLE));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -383,6 +447,8 @@ void server_init (struct audio_s *audio_config_p, struct misc_config_s *mc)
|
||||||
enable_send_monitor_to_client[client] = 0;
|
enable_send_monitor_to_client[client] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
memset (registered_callsigns, 0, sizeof(registered_callsigns));
|
||||||
|
|
||||||
if (server_port == 0) {
|
if (server_port == 0) {
|
||||||
text_color_set(DW_COLOR_INFO);
|
text_color_set(DW_COLOR_INFO);
|
||||||
dw_printf ("Disabled AGW network client port.\n");
|
dw_printf ("Disabled AGW network client port.\n");
|
||||||
|
@ -727,13 +793,13 @@ void server_send_rec_packet (int chan, packet_t pp, unsigned char *fbuf, int fl
|
||||||
|
|
||||||
agwpe_msg.hdr.portx = chan;
|
agwpe_msg.hdr.portx = chan;
|
||||||
|
|
||||||
agwpe_msg.hdr.kind_lo = 'K';
|
agwpe_msg.hdr.datakind = 'K';
|
||||||
|
|
||||||
ax25_get_addr_with_ssid (pp, AX25_SOURCE, agwpe_msg.hdr.call_from);
|
ax25_get_addr_with_ssid (pp, AX25_SOURCE, agwpe_msg.hdr.call_from);
|
||||||
|
|
||||||
ax25_get_addr_with_ssid (pp, AX25_DESTINATION, agwpe_msg.hdr.call_to);
|
ax25_get_addr_with_ssid (pp, AX25_DESTINATION, agwpe_msg.hdr.call_to);
|
||||||
|
|
||||||
agwpe_msg.hdr.data_len = flen + 1;
|
agwpe_msg.hdr.data_len_NETLE = host2netle(flen + 1);
|
||||||
|
|
||||||
/* Stick in extra byte for the "TNC" to use. */
|
/* Stick in extra byte for the "TNC" to use. */
|
||||||
|
|
||||||
|
@ -741,11 +807,11 @@ void server_send_rec_packet (int chan, packet_t pp, unsigned char *fbuf, int fl
|
||||||
memcpy (agwpe_msg.data + 1, fbuf, (size_t)flen);
|
memcpy (agwpe_msg.data + 1, fbuf, (size_t)flen);
|
||||||
|
|
||||||
if (debug_client) {
|
if (debug_client) {
|
||||||
debug_print (TO_CLIENT, client, &agwpe_msg.hdr, sizeof(agwpe_msg.hdr) + agwpe_msg.hdr.data_len);
|
debug_print (TO_CLIENT, client, &agwpe_msg.hdr, sizeof(agwpe_msg.hdr) + netle2host(agwpe_msg.hdr.data_len_NETLE));
|
||||||
}
|
}
|
||||||
|
|
||||||
#if __WIN32__
|
#if __WIN32__
|
||||||
err = send (client_sock[client], (char*)(&agwpe_msg), sizeof(agwpe_msg.hdr) + agwpe_msg.hdr.data_len, 0);
|
err = send (client_sock[client], (char*)(&agwpe_msg), sizeof(agwpe_msg.hdr) + netle2host(agwpe_msg.hdr.data_len_NETLE), 0);
|
||||||
if (err == SOCKET_ERROR)
|
if (err == SOCKET_ERROR)
|
||||||
{
|
{
|
||||||
text_color_set(DW_COLOR_ERROR);
|
text_color_set(DW_COLOR_ERROR);
|
||||||
|
@ -755,7 +821,7 @@ void server_send_rec_packet (int chan, packet_t pp, unsigned char *fbuf, int fl
|
||||||
WSACleanup();
|
WSACleanup();
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
err = write (client_sock[client], &agwpe_msg, sizeof(agwpe_msg.hdr) + agwpe_msg.hdr.data_len);
|
err = write (client_sock[client], &agwpe_msg, sizeof(agwpe_msg.hdr) + netle2host(agwpe_msg.hdr.data_len_NETLE));
|
||||||
if (err <= 0)
|
if (err <= 0)
|
||||||
{
|
{
|
||||||
text_color_set(DW_COLOR_ERROR);
|
text_color_set(DW_COLOR_ERROR);
|
||||||
|
@ -785,7 +851,7 @@ void server_send_rec_packet (int chan, packet_t pp, unsigned char *fbuf, int fl
|
||||||
|
|
||||||
agwpe_msg.hdr.portx = chan;
|
agwpe_msg.hdr.portx = chan;
|
||||||
|
|
||||||
agwpe_msg.hdr.kind_lo = 'U';
|
agwpe_msg.hdr.datakind = 'U';
|
||||||
|
|
||||||
ax25_get_addr_with_ssid (pp, AX25_SOURCE, agwpe_msg.hdr.call_from);
|
ax25_get_addr_with_ssid (pp, AX25_SOURCE, agwpe_msg.hdr.call_from);
|
||||||
|
|
||||||
|
@ -807,14 +873,14 @@ void server_send_rec_packet (int chan, packet_t pp, unsigned char *fbuf, int fl
|
||||||
tm->tm_hour, tm->tm_min, tm->tm_sec,
|
tm->tm_hour, tm->tm_min, tm->tm_sec,
|
||||||
pinfo);
|
pinfo);
|
||||||
|
|
||||||
agwpe_msg.hdr.data_len = strlen(agwpe_msg.data) + 1 /* include null */ ;
|
agwpe_msg.hdr.data_len_NETLE = host2netle(strlen(agwpe_msg.data) + 1) /* include null */ ;
|
||||||
|
|
||||||
if (debug_client) {
|
if (debug_client) {
|
||||||
debug_print (TO_CLIENT, client, &agwpe_msg.hdr, sizeof(agwpe_msg.hdr) + agwpe_msg.hdr.data_len);
|
debug_print (TO_CLIENT, client, &agwpe_msg.hdr, sizeof(agwpe_msg.hdr) + netle2host(agwpe_msg.hdr.data_len_NETLE));
|
||||||
}
|
}
|
||||||
|
|
||||||
#if __WIN32__
|
#if __WIN32__
|
||||||
err = send (client_sock[client], (char*)(&agwpe_msg), sizeof(agwpe_msg.hdr) + agwpe_msg.hdr.data_len, 0);
|
err = send (client_sock[client], (char*)(&agwpe_msg), sizeof(agwpe_msg.hdr) + netle2host(agwpe_msg.hdr.data_len_NETLE), 0);
|
||||||
if (err == SOCKET_ERROR)
|
if (err == SOCKET_ERROR)
|
||||||
{
|
{
|
||||||
text_color_set(DW_COLOR_ERROR);
|
text_color_set(DW_COLOR_ERROR);
|
||||||
|
@ -824,7 +890,7 @@ void server_send_rec_packet (int chan, packet_t pp, unsigned char *fbuf, int fl
|
||||||
WSACleanup();
|
WSACleanup();
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
err = write (client_sock[client], &agwpe_msg, sizeof(agwpe_msg.hdr) + agwpe_msg.hdr.data_len);
|
err = write (client_sock[client], &agwpe_msg, sizeof(agwpe_msg.hdr) + netle2host(agwpe_msg.hdr.data_len_NETLE));
|
||||||
if (err <= 0)
|
if (err <= 0)
|
||||||
{
|
{
|
||||||
text_color_set(DW_COLOR_ERROR);
|
text_color_set(DW_COLOR_ERROR);
|
||||||
|
@ -840,6 +906,110 @@ void server_send_rec_packet (int chan, packet_t pp, unsigned char *fbuf, int fl
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*-------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* Name: server_link_established
|
||||||
|
*
|
||||||
|
* Purpose: Send notification to client app when a link has
|
||||||
|
* been established with another station.
|
||||||
|
*
|
||||||
|
* Inputs: chan - Which radio channel.
|
||||||
|
*
|
||||||
|
* client - Which one of potentially several clients.
|
||||||
|
*
|
||||||
|
* remote_call - Callsign[-ssid] of remote station.
|
||||||
|
*
|
||||||
|
* own_call - Callsign[-ssid] of my end.
|
||||||
|
*
|
||||||
|
* incoming - true if connection was initiated from other end.
|
||||||
|
* false if this end started it.
|
||||||
|
*
|
||||||
|
*--------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
void server_link_established (int chan, int client, char *remote_call, char *own_call, int incoming)
|
||||||
|
{
|
||||||
|
|
||||||
|
struct {
|
||||||
|
struct agwpe_s hdr;
|
||||||
|
char info[100];
|
||||||
|
} reply;
|
||||||
|
|
||||||
|
|
||||||
|
memset (&reply, 0, sizeof(reply));
|
||||||
|
reply.hdr.portx = chan;
|
||||||
|
reply.hdr.datakind = 'C';
|
||||||
|
|
||||||
|
strlcpy (reply.hdr.call_from, remote_call, sizeof(reply.hdr.call_from));
|
||||||
|
strlcpy (reply.hdr.call_to, own_call, sizeof(reply.hdr.call_to));
|
||||||
|
|
||||||
|
if (incoming) {
|
||||||
|
// Other end initiated the connection.
|
||||||
|
snprintf (reply.info, sizeof(reply.info), "*** CONNECTED To Station %s\r", remote_call);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// We started the connection.
|
||||||
|
snprintf (reply.info, sizeof(reply.info), "*** CONNECTED With Station %s\r", remote_call);
|
||||||
|
}
|
||||||
|
reply.hdr.data_len_NETLE = host2netle(strlen(reply.info) + 1);
|
||||||
|
|
||||||
|
send_to_client (client, &reply);
|
||||||
|
|
||||||
|
} /* end server_link_established */
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*-------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* Name: server_link_terminated
|
||||||
|
*
|
||||||
|
* Purpose: Send notification to client app when a link with
|
||||||
|
* another station has been terminated or a connection
|
||||||
|
* attempt failed.
|
||||||
|
*
|
||||||
|
* Inputs: chan - Which radio channel.
|
||||||
|
*
|
||||||
|
* client - Which one of potentially several clients.
|
||||||
|
*
|
||||||
|
* remote_call - Callsign[-ssid] of remote station.
|
||||||
|
*
|
||||||
|
* own_call - Callsign[-ssid] of my end.
|
||||||
|
*
|
||||||
|
* timeout - true when no answer from other station.
|
||||||
|
* How do we distinguish who asked for the
|
||||||
|
* termination of an existing linkn?
|
||||||
|
*
|
||||||
|
*--------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
void server_link_terminated (int chan, int client, char *remote_call, char *own_call, int timeout)
|
||||||
|
{
|
||||||
|
|
||||||
|
struct {
|
||||||
|
struct agwpe_s hdr;
|
||||||
|
char info[100];
|
||||||
|
} reply;
|
||||||
|
|
||||||
|
|
||||||
|
memset (&reply, 0, sizeof(reply));
|
||||||
|
reply.hdr.portx = chan;
|
||||||
|
reply.hdr.datakind = 'd';
|
||||||
|
strlcpy (reply.hdr.call_from, remote_call, sizeof(reply.hdr.call_from)); /* right order */
|
||||||
|
strlcpy (reply.hdr.call_to, own_call, sizeof(reply.hdr.call_to));
|
||||||
|
|
||||||
|
if (timeout) {
|
||||||
|
snprintf (reply.info, sizeof(reply.info), "*** DISCONNECTED RETRYOUT With %s\r", remote_call);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
snprintf (reply.info, sizeof(reply.info), "*** DISCONNECTED From Station %s\r", remote_call);
|
||||||
|
}
|
||||||
|
reply.hdr.data_len_NETLE = host2netle(strlen(reply.info) + 1);
|
||||||
|
|
||||||
|
send_to_client (client, &reply);
|
||||||
|
|
||||||
|
|
||||||
|
} /* end server_link_terminated */
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*-------------------------------------------------------------------
|
/*-------------------------------------------------------------------
|
||||||
*
|
*
|
||||||
* Name: read_from_socket
|
* Name: read_from_socket
|
||||||
|
@ -923,13 +1093,13 @@ static void send_to_client (int client, void *reply_p)
|
||||||
|
|
||||||
ph = (struct agwpe_s *) reply_p; // Replies are often hdr + other stuff.
|
ph = (struct agwpe_s *) reply_p; // Replies are often hdr + other stuff.
|
||||||
|
|
||||||
len = sizeof(struct agwpe_s) + ph->data_len;
|
len = sizeof(struct agwpe_s) + netle2host(ph->data_len_NETLE);
|
||||||
|
|
||||||
/* Not sure what max data length might be. */
|
/* Not sure what max data length might be. */
|
||||||
|
|
||||||
if (ph->data_len < 0 || ph->data_len > 4096) {
|
if (netle2host(ph->data_len_NETLE) < 0 || netle2host(ph->data_len_NETLE) > 4096) {
|
||||||
text_color_set(DW_COLOR_ERROR);
|
text_color_set(DW_COLOR_ERROR);
|
||||||
dw_printf ("Invalid data length %d for AGW protocol message to client %d.\n", ph->data_len, client);
|
dw_printf ("Invalid data length %d for AGW protocol message to client %d.\n", netle2host(ph->data_len_NETLE), client);
|
||||||
debug_print (TO_CLIENT, client, ph, len);
|
debug_print (TO_CLIENT, client, ph, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1000,11 +1170,13 @@ static THREAD_F cmd_listen_thread (void *arg)
|
||||||
* Leave room for an extra nul byte terminator at end later.
|
* Leave room for an extra nul byte terminator at end later.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (cmd.hdr.data_len < 0 || cmd.hdr.data_len > sizeof(cmd.data) - 1) {
|
int data_len = netle2host(cmd.hdr.data_len_NETLE);
|
||||||
|
|
||||||
|
if (data_len < 0 || data_len > sizeof(cmd.data) - 1) {
|
||||||
|
|
||||||
text_color_set(DW_COLOR_ERROR);
|
text_color_set(DW_COLOR_ERROR);
|
||||||
dw_printf ("\nInvalid message from AGW client application %d.\n", client);
|
dw_printf ("\nInvalid message from AGW client application %d.\n", client);
|
||||||
dw_printf ("Data Length of %d is out of range.\n", cmd.hdr.data_len);
|
dw_printf ("Data Length of %d is out of range.\n", data_len);
|
||||||
|
|
||||||
/* This is a bad situation. */
|
/* This is a bad situation. */
|
||||||
/* If we tried to read again, the header probably won't be there. */
|
/* If we tried to read again, the header probably won't be there. */
|
||||||
|
@ -1022,12 +1194,12 @@ static THREAD_F cmd_listen_thread (void *arg)
|
||||||
|
|
||||||
cmd.data[0] = '\0';
|
cmd.data[0] = '\0';
|
||||||
|
|
||||||
if (cmd.hdr.data_len > 0) {
|
if (data_len > 0) {
|
||||||
n = read_from_socket (client_sock[client], cmd.data, cmd.hdr.data_len);
|
n = read_from_socket (client_sock[client], cmd.data, data_len);
|
||||||
if (n != cmd.hdr.data_len) {
|
if (n != data_len) {
|
||||||
text_color_set(DW_COLOR_ERROR);
|
text_color_set(DW_COLOR_ERROR);
|
||||||
dw_printf ("\nError getting message data from AGW client application %d.\n", client);
|
dw_printf ("\nError getting message data from AGW client application %d.\n", client);
|
||||||
dw_printf ("Tried to read %d bytes but got only %d.\n", cmd.hdr.data_len, n);
|
dw_printf ("Tried to read %d bytes but got only %d.\n", data_len, n);
|
||||||
dw_printf ("Closing connection.\n\n");
|
dw_printf ("Closing connection.\n\n");
|
||||||
#if __WIN32__
|
#if __WIN32__
|
||||||
closesocket (client_sock[client]);
|
closesocket (client_sock[client]);
|
||||||
|
@ -1037,8 +1209,8 @@ static THREAD_F cmd_listen_thread (void *arg)
|
||||||
client_sock[client] = -1;
|
client_sock[client] = -1;
|
||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
if (n > 0) {
|
if (n >= 0) {
|
||||||
cmd.data[cmd.hdr.data_len] = '\0';
|
cmd.data[n] = '\0'; // Tidy if we print for debug.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1047,31 +1219,31 @@ static THREAD_F cmd_listen_thread (void *arg)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (debug_client) {
|
if (debug_client) {
|
||||||
debug_print (FROM_CLIENT, client, &cmd.hdr, sizeof(cmd.hdr) + cmd.hdr.data_len);
|
debug_print (FROM_CLIENT, client, &cmd.hdr, sizeof(cmd.hdr) + data_len);
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (cmd.hdr.kind_lo) {
|
switch (cmd.hdr.datakind) {
|
||||||
|
|
||||||
case 'R': /* Request for version number */
|
case 'R': /* Request for version number */
|
||||||
{
|
{
|
||||||
struct {
|
struct {
|
||||||
struct agwpe_s hdr;
|
struct agwpe_s hdr;
|
||||||
int major_version;
|
int major_version_NETLE;
|
||||||
int minor_version;
|
int minor_version_NETLE;
|
||||||
} reply;
|
} reply;
|
||||||
|
|
||||||
|
|
||||||
memset (&reply, 0, sizeof(reply));
|
memset (&reply, 0, sizeof(reply));
|
||||||
reply.hdr.kind_lo = 'R';
|
reply.hdr.datakind = 'R';
|
||||||
reply.hdr.data_len = sizeof(reply.major_version) + sizeof(reply.minor_version);
|
reply.hdr.data_len_NETLE = host2netle(sizeof(reply.major_version_NETLE) + sizeof(reply.minor_version_NETLE));
|
||||||
assert (reply.hdr.data_len == 8);
|
assert (netle2host(reply.hdr.data_len_NETLE) == 8);
|
||||||
|
|
||||||
// Xastir only prints this and doesn't care otherwise.
|
// Xastir only prints this and doesn't care otherwise.
|
||||||
// APRSIS32 doesn't seem to care.
|
// APRSIS32 doesn't seem to care.
|
||||||
// UI-View32 wants on 2000.15 or later.
|
// UI-View32 wants on 2000.15 or later.
|
||||||
|
|
||||||
reply.major_version = 2005;
|
reply.major_version_NETLE = host2netle(2005);
|
||||||
reply.minor_version = 127;
|
reply.minor_version_NETLE = host2netle(127);
|
||||||
|
|
||||||
assert (sizeof(reply) == 44);
|
assert (sizeof(reply) == 44);
|
||||||
|
|
||||||
|
@ -1093,7 +1265,7 @@ static THREAD_F cmd_listen_thread (void *arg)
|
||||||
|
|
||||||
|
|
||||||
memset (&reply, 0, sizeof(reply));
|
memset (&reply, 0, sizeof(reply));
|
||||||
reply.hdr.kind_lo = 'G';
|
reply.hdr.datakind = 'G';
|
||||||
|
|
||||||
|
|
||||||
// Xastir only prints this and doesn't care otherwise.
|
// Xastir only prints this and doesn't care otherwise.
|
||||||
|
@ -1141,7 +1313,7 @@ static THREAD_F cmd_listen_thread (void *arg)
|
||||||
snprintf (reply.info, sizeof(reply.info), "2;Port1 Left channel;Port2 Right Channel;");
|
snprintf (reply.info, sizeof(reply.info), "2;Port1 Left channel;Port2 Right Channel;");
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
reply.hdr.data_len = strlen(reply.info) + 1;
|
reply.hdr.data_len_NETLE = host2netle(strlen(reply.info) + 1);
|
||||||
|
|
||||||
send_to_client (client, &reply);
|
send_to_client (client, &reply);
|
||||||
|
|
||||||
|
@ -1162,15 +1334,15 @@ static THREAD_F cmd_listen_thread (void *arg)
|
||||||
unsigned char slottime;
|
unsigned char slottime;
|
||||||
unsigned char maxframe;
|
unsigned char maxframe;
|
||||||
unsigned char active_connections;
|
unsigned char active_connections;
|
||||||
int how_many_bytes;
|
int how_many_bytes_NETLE;
|
||||||
} reply;
|
} reply;
|
||||||
|
|
||||||
|
|
||||||
memset (&reply, 0, sizeof(reply));
|
memset (&reply, 0, sizeof(reply));
|
||||||
|
|
||||||
reply.hdr.portx = cmd.hdr.portx; /* Reply with same port number ! */
|
reply.hdr.portx = cmd.hdr.portx; /* Reply with same port number ! */
|
||||||
reply.hdr.kind_lo = 'g';
|
reply.hdr.datakind = 'g';
|
||||||
reply.hdr.data_len = 12;
|
reply.hdr.data_len_NETLE = host2netle(12);
|
||||||
|
|
||||||
// YAAC asks for this.
|
// YAAC asks for this.
|
||||||
// Fake it to keep application happy.
|
// Fake it to keep application happy.
|
||||||
|
@ -1183,7 +1355,7 @@ static THREAD_F cmd_listen_thread (void *arg)
|
||||||
reply.slottime = 4;
|
reply.slottime = 4;
|
||||||
reply.maxframe = 7;
|
reply.maxframe = 7;
|
||||||
reply.active_connections = 0;
|
reply.active_connections = 0;
|
||||||
reply.how_many_bytes = 1;
|
reply.how_many_bytes_NETLE = host2netle(1);
|
||||||
|
|
||||||
assert (sizeof(reply) == 48);
|
assert (sizeof(reply) == 48);
|
||||||
|
|
||||||
|
@ -1204,7 +1376,7 @@ static THREAD_F cmd_listen_thread (void *arg)
|
||||||
|
|
||||||
|
|
||||||
memset (&reply.hdr, 0, sizeof(reply.hdr));
|
memset (&reply.hdr, 0, sizeof(reply.hdr));
|
||||||
reply.hdr.kind_lo = 'H';
|
reply.hdr.datakind = 'H';
|
||||||
|
|
||||||
// TODO: Implement properly.
|
// TODO: Implement properly.
|
||||||
|
|
||||||
|
@ -1214,7 +1386,7 @@ static THREAD_F cmd_listen_thread (void *arg)
|
||||||
|
|
||||||
strlcpy (agwpe_msg.data, ..., sizeof(agwpe_msg.data));
|
strlcpy (agwpe_msg.data, ..., sizeof(agwpe_msg.data));
|
||||||
|
|
||||||
reply.hdr.data_len = strlen(reply.info);
|
reply.hdr.data_len_NETLE = host2netle(strlen(reply.info));
|
||||||
|
|
||||||
send_to_client (client, &reply);
|
send_to_client (client, &reply);
|
||||||
#endif
|
#endif
|
||||||
|
@ -1253,13 +1425,11 @@ static THREAD_F cmd_listen_thread (void *arg)
|
||||||
|
|
||||||
packet_t pp;
|
packet_t pp;
|
||||||
|
|
||||||
// We have already verified these do not exceed 9 characters. (?)
|
|
||||||
|
|
||||||
strlcpy (stemp, cmd.hdr.call_from, sizeof(stemp));
|
strlcpy (stemp, cmd.hdr.call_from, sizeof(stemp));
|
||||||
strlcat (stemp, ">", sizeof(stemp));
|
strlcat (stemp, ">", sizeof(stemp));
|
||||||
strlcat (stemp, cmd.hdr.call_to, sizeof(stemp));
|
strlcat (stemp, cmd.hdr.call_to, sizeof(stemp));
|
||||||
|
|
||||||
cmd.data[cmd.hdr.data_len] = '\0';
|
cmd.data[data_len] = '\0';
|
||||||
ndigi = cmd.data[0];
|
ndigi = cmd.data[0];
|
||||||
p = cmd.data + 1;
|
p = cmd.data + 1;
|
||||||
|
|
||||||
|
@ -1324,7 +1494,7 @@ static THREAD_F cmd_listen_thread (void *arg)
|
||||||
// cmd.hdr.data_len so we ended up sending an extra byte.
|
// cmd.hdr.data_len so we ended up sending an extra byte.
|
||||||
|
|
||||||
memset (&alevel, 0xff, sizeof(alevel));
|
memset (&alevel, 0xff, sizeof(alevel));
|
||||||
pp = ax25_from_frame ((unsigned char *)cmd.data+1, cmd.hdr.data_len - 1, alevel);
|
pp = ax25_from_frame ((unsigned char *)cmd.data+1, data_len - 1, alevel);
|
||||||
|
|
||||||
if (pp == NULL) {
|
if (pp == NULL) {
|
||||||
text_color_set(DW_COLOR_ERROR);
|
text_color_set(DW_COLOR_ERROR);
|
||||||
|
@ -1352,46 +1522,127 @@ static THREAD_F cmd_listen_thread (void *arg)
|
||||||
|
|
||||||
case 'X': /* Register CallSign */
|
case 'X': /* Register CallSign */
|
||||||
|
|
||||||
/* Send success status. */
|
|
||||||
|
|
||||||
{
|
{
|
||||||
struct {
|
struct {
|
||||||
struct agwpe_s hdr;
|
struct agwpe_s hdr;
|
||||||
char data;
|
char data;
|
||||||
} reply;
|
} reply;
|
||||||
|
|
||||||
|
int j, ok;
|
||||||
|
|
||||||
memset (&reply, 0, sizeof(reply));
|
memset (&reply, 0, sizeof(reply));
|
||||||
reply.hdr.kind_lo = 'X';
|
reply.hdr.datakind = 'X';
|
||||||
memcpy (reply.hdr.call_from, cmd.hdr.call_from, sizeof(reply.hdr.call_from));
|
memcpy (reply.hdr.call_from, cmd.hdr.call_from, sizeof(reply.hdr.call_from));
|
||||||
reply.hdr.data_len = 1;
|
reply.hdr.data_len_NETLE = host2netle(1);
|
||||||
reply.data = 1; /* success */
|
|
||||||
|
|
||||||
// Version 1.0.
|
// Version 1.0.
|
||||||
// Previously used sizeof(reply) but compiler rounded it up to next byte boundary.
|
// Previously used sizeof(reply) but compiler rounded it up to next byte boundary.
|
||||||
// That's why more cumbersome size expression is used.
|
// That's why more cumbersome size expression is used.
|
||||||
|
|
||||||
send_to_client (client, &reply);
|
// The protocol spec says it is an error to register the same one more than once.
|
||||||
|
// First make sure is it not already in there. Add if space available.
|
||||||
|
|
||||||
|
if (server_callsign_registered_by_client(cmd.hdr.call_from) >= 0) {
|
||||||
|
ok = 0;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
ok = 0;
|
||||||
|
for (j = 0; j < MAX_REG_CALLSIGNS && ok == 0; j++) {
|
||||||
|
if (registered_callsigns[j][0] == '\0') {
|
||||||
|
strlcpy (registered_callsigns[j], cmd.hdr.call_from, sizeof(registered_callsigns[j]));
|
||||||
|
registered_by_client[j] = client;
|
||||||
|
ok = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
reply.data = ok; /* 1 = success, 0 = failure */
|
||||||
|
send_to_client (client, &reply);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'x': /* Unregister CallSign */
|
case 'x': /* Unregister CallSign */
|
||||||
|
|
||||||
|
{
|
||||||
|
int j;
|
||||||
|
|
||||||
|
for (j = 0; j < MAX_REG_CALLSIGNS; j++) {
|
||||||
|
if (strcmp(registered_callsigns[j], cmd.hdr.call_from) == 0) {
|
||||||
|
registered_callsigns[j][0] = '\0';
|
||||||
|
registered_by_client[j] = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
/* No reponse is expected. */
|
/* No reponse is expected. */
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'C': /* Connect, Start an AX.25 Connection */
|
case 'C': /* Connect, Start an AX.25 Connection */
|
||||||
case 'v': /* Connect VIA, Start an AX.25 circuit thru digipeaters */
|
case 'v': /* Connect VIA, Start an AX.25 circuit thru digipeaters */
|
||||||
case 'D': /* Send Connected Data */
|
case 'c': /* Connection with non-standard PID */
|
||||||
case 'd': /* Disconnect, Terminate an AX.25 Connection */
|
|
||||||
|
|
||||||
// Version 1.0. Better message instead of generic unexpected command.
|
{
|
||||||
|
struct via_info {
|
||||||
|
unsigned char num_digi; /* Expect to be in range 1 to 7. Why not up to 8? */
|
||||||
|
char dcall[7][10];
|
||||||
|
} *v = (struct via_info *)cmd.data;
|
||||||
|
|
||||||
|
char callsigns[AX25_MAX_ADDRS][AX25_MAX_ADDR_LEN];
|
||||||
|
int num_calls = 2; /* 2 plus any digipeaters. */
|
||||||
|
int pid = 0xf0; /* normal for AX.25 I frames. */
|
||||||
|
int j;
|
||||||
|
char stemp[256];
|
||||||
|
|
||||||
|
strlcpy (callsigns[AX25_SOURCE], cmd.hdr.call_from, sizeof(callsigns[AX25_SOURCE]));
|
||||||
|
strlcpy (callsigns[AX25_DESTINATION], cmd.hdr.call_to, sizeof(callsigns[AX25_SOURCE]));
|
||||||
|
|
||||||
|
if (cmd.hdr.datakind == 'c') {
|
||||||
|
pid = cmd.hdr.pid; /* non standard for NETROM, TCP/IP, etc. */
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cmd.hdr.datakind == 'v') {
|
||||||
|
if (v->num_digi >= 1 && v->num_digi <= 7) {
|
||||||
|
|
||||||
|
if (data_len != v->num_digi * 10 + 1 && data_len != v->num_digi * 10 + 2) {
|
||||||
|
// I'm getting 1 more than expected from AGWterminal.
|
||||||
|
text_color_set(DW_COLOR_ERROR);
|
||||||
|
dw_printf ("AGW client, connect via, has data len, %d when %d expected.\n", data_len, v->num_digi * 10 + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (j = 0; j < v->num_digi; j++) {
|
||||||
|
strlcpy (callsigns[AX25_REPEATER_1 + j], v->dcall[j], sizeof(callsigns[AX25_REPEATER_1 + j]));
|
||||||
|
num_calls++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
text_color_set(DW_COLOR_ERROR);
|
||||||
|
dw_printf ("\n");
|
||||||
|
dw_printf ("AGW client, connect via, has invalid number of digipeaters = %d\n", v->num_digi);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
text_color_set(DW_COLOR_ERROR);
|
||||||
|
dw_printf ("\n");
|
||||||
|
dw_printf ("Can't process command '%c' from AGW client app %d.\n", cmd.hdr.datakind, client);
|
||||||
|
dw_printf ("Connected packet mode is not implemented.\n");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'D': /* Send Connected Data */
|
||||||
|
|
||||||
text_color_set(DW_COLOR_ERROR);
|
text_color_set(DW_COLOR_ERROR);
|
||||||
dw_printf ("\n");
|
dw_printf ("\n");
|
||||||
dw_printf ("Can't process command '%c' from AGW client app %d.\n", cmd.hdr.kind_lo, client);
|
dw_printf ("Can't process command '%c' from AGW client app %d.\n", cmd.hdr.datakind, client);
|
||||||
dw_printf ("Connected packet mode is not implemented.\n");
|
dw_printf ("Connected packet mode is not implemented.\n");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'd': /* Disconnect, Terminate an AX.25 Connection */
|
||||||
|
|
||||||
|
{
|
||||||
|
text_color_set(DW_COLOR_ERROR);
|
||||||
|
dw_printf ("\n");
|
||||||
|
dw_printf ("Can't process command '%c' from AGW client app %d.\n", cmd.hdr.datakind, client);
|
||||||
|
dw_printf ("Connected packet mode is not implemented.\n");
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
||||||
|
@ -1400,36 +1651,35 @@ static THREAD_F cmd_listen_thread (void *arg)
|
||||||
/*
|
/*
|
||||||
Added in version 1.3.
|
Added in version 1.3.
|
||||||
This is the same as 'V' except there is no provision for digipeaters.
|
This is the same as 'V' except there is no provision for digipeaters.
|
||||||
|
TODO: combine 'V' and 'M' into one case.
|
||||||
AGWterminal sends this for beacon or ask QRA.
|
AGWterminal sends this for beacon or ask QRA.
|
||||||
|
|
||||||
<<< Send UNPROTO Information from AGWPE client application 0, total length = 253
|
<<< Send UNPROTO Information from AGWPE client application 0, total length = 253
|
||||||
portx = 0, port_hi_reserved = 0
|
portx = 0, datakind = 'M', pid = 0x00
|
||||||
kind_lo = 77 = 'M', kind_hi = 0
|
call_from = "WB2OSZ-15", call_to = "BEACON"
|
||||||
call_from = "SV2AGW-1", call_to = "BEACON"
|
data_len = 217, user_reserved = 556, data =
|
||||||
data_len = 217, user_reserved = 588, data =
|
|
||||||
000: 54 68 69 73 20 76 65 72 73 69 6f 6e 20 75 73 65 This version use
|
000: 54 68 69 73 20 76 65 72 73 69 6f 6e 20 75 73 65 This version use
|
||||||
010: 73 20 74 68 65 20 6e 65 77 20 41 47 57 20 50 61 s the new AGW Pa
|
...
|
||||||
020: 63 6b 65 74 20 45 6e 67 69 6e 65 20 77 69 6e 73 cket Engine wins
|
|
||||||
|
|
||||||
<<< Send UNPROTO Information from AGWPE client application 0, total length = 37
|
<<< Send UNPROTO Information from AGWPE client application 0, total length = 37
|
||||||
portx = 0, port_hi_reserved = 0
|
portx = 0, datakind = 'M', pid = 0x00
|
||||||
kind_lo = 77 = 'M', kind_hi = 0
|
call_from = "WB2OSZ-15", call_to = "QRA"
|
||||||
call_from = "SV2AGW-1", call_to = "QRA"
|
data_len = 1, user_reserved = 31759424, data =
|
||||||
data_len = 1, user_reserved = 32218432, data =
|
|
||||||
000: 0d .
|
000: 0d .
|
||||||
|
.
|
||||||
|
|
||||||
There is also a report of it coming from UISS.
|
There is also a report of it coming from UISS.
|
||||||
|
|
||||||
<<< Send UNPROTO Information from AGWPE client application 0, total length = 50
|
<<< Send UNPROTO Information from AGWPE client application 0, total length = 50
|
||||||
portx = 0, port_hi_reserved = 0
|
portx = 0, port_hi_reserved = 0
|
||||||
kind_lo = 77 = 'M', kind_hi = 0
|
datakind = 77 = 'M', kind_hi = 0
|
||||||
call_from = "JH4XSY", call_to = "APRS"
|
call_from = "JH4XSY", call_to = "APRS"
|
||||||
data_len = 14, user_reserved = 0, data =
|
data_len = 14, user_reserved = 0, data =
|
||||||
000: 21 22 3c 43 2e 74 71 6c 48 72 71 21 21 5f !"<C.tqlHrq!!_
|
000: 21 22 3c 43 2e 74 71 6c 48 72 71 21 21 5f !"<C.tqlHrq!!_
|
||||||
*/
|
*/
|
||||||
{
|
{
|
||||||
|
|
||||||
int pid = cmd.hdr.kind_hi & 0xff;
|
int pid = cmd.hdr.pid;
|
||||||
(void)(pid);
|
(void)(pid);
|
||||||
/* The AGW protocol spec says, */
|
/* The AGW protocol spec says, */
|
||||||
/* "AX.25 PID 0x00 or 0xF0 for AX.25 0xCF NETROM and others" */
|
/* "AX.25 PID 0x00 or 0xF0 for AX.25 0xCF NETROM and others" */
|
||||||
|
@ -1448,7 +1698,7 @@ static THREAD_F cmd_listen_thread (void *arg)
|
||||||
strlcat (stemp, ">", sizeof(stemp));
|
strlcat (stemp, ">", sizeof(stemp));
|
||||||
strlcat (stemp, cmd.hdr.call_to, sizeof(stemp));
|
strlcat (stemp, cmd.hdr.call_to, sizeof(stemp));
|
||||||
|
|
||||||
cmd.data[cmd.hdr.data_len] = '\0';
|
cmd.data[data_len] = '\0';
|
||||||
|
|
||||||
strlcat (stemp, ":", sizeof(stemp));
|
strlcat (stemp, ":", sizeof(stemp));
|
||||||
strlcat (stemp, cmd.data, sizeof(stemp));
|
strlcat (stemp, cmd.data, sizeof(stemp));
|
||||||
|
@ -1474,19 +1724,20 @@ static THREAD_F cmd_listen_thread (void *arg)
|
||||||
{
|
{
|
||||||
struct {
|
struct {
|
||||||
struct agwpe_s hdr;
|
struct agwpe_s hdr;
|
||||||
int data; // Assuming little-endian architecture.
|
int data_NETLE; // Little endian order.
|
||||||
} reply;
|
} reply;
|
||||||
|
|
||||||
|
|
||||||
memset (&reply, 0, sizeof(reply));
|
memset (&reply, 0, sizeof(reply));
|
||||||
reply.hdr.portx = cmd.hdr.portx; /* Reply with same port number */
|
reply.hdr.portx = cmd.hdr.portx; /* Reply with same port number */
|
||||||
reply.hdr.kind_lo = 'y';
|
reply.hdr.datakind = 'y';
|
||||||
reply.hdr.data_len = 4;
|
reply.hdr.data_len_NETLE = host2netle(4);
|
||||||
reply.data = 0;
|
|
||||||
|
|
||||||
|
int n = 0;
|
||||||
if (cmd.hdr.portx >= 0 && cmd.hdr.portx < MAX_CHANS) {
|
if (cmd.hdr.portx >= 0 && cmd.hdr.portx < MAX_CHANS) {
|
||||||
reply.data = tq_count (cmd.hdr.portx, TQ_PRIO_0_HI) + tq_count (cmd.hdr.portx, TQ_PRIO_1_LO);
|
n = tq_count (cmd.hdr.portx, TQ_PRIO_0_HI) + tq_count (cmd.hdr.portx, TQ_PRIO_1_LO);
|
||||||
}
|
}
|
||||||
|
reply.data_NETLE = host2netle(n);
|
||||||
|
|
||||||
send_to_client (client, &reply);
|
send_to_client (client, &reply);
|
||||||
}
|
}
|
||||||
|
@ -1496,14 +1747,39 @@ static THREAD_F cmd_listen_thread (void *arg)
|
||||||
|
|
||||||
text_color_set(DW_COLOR_ERROR);
|
text_color_set(DW_COLOR_ERROR);
|
||||||
dw_printf ("--- Unexpected Command from application %d using AGW protocol:\n", client);
|
dw_printf ("--- Unexpected Command from application %d using AGW protocol:\n", client);
|
||||||
debug_print (FROM_CLIENT, client, &cmd.hdr, sizeof(cmd.hdr) + cmd.hdr.data_len);
|
debug_print (FROM_CLIENT, client, &cmd.hdr, sizeof(cmd.hdr) + data_len);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
} /* end send_to_client */
|
||||||
|
|
||||||
|
|
||||||
|
/*-------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* Name: server_callsign_registered_by_client
|
||||||
|
*
|
||||||
|
* Purpose: See if given callsign was registered.
|
||||||
|
*
|
||||||
|
* Inputs: callsign
|
||||||
|
*
|
||||||
|
* Returns: >= 0 for the client number.
|
||||||
|
* -1 for not found.
|
||||||
|
*
|
||||||
|
*--------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
int server_callsign_registered_by_client (char *callsign)
|
||||||
|
{
|
||||||
|
int j;
|
||||||
|
|
||||||
|
for (j = 0; j < MAX_REG_CALLSIGNS; j++) {
|
||||||
|
if (strcmp(registered_callsigns[j], callsign) == 0) {
|
||||||
|
return (registered_by_client[j]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return (-1);
|
||||||
|
|
||||||
|
} /* end server_callsign_registered_by_client */
|
||||||
|
|
||||||
/* end server.c */
|
/* end server.c */
|
||||||
|
|
3
server.h
3
server.h
|
@ -15,5 +15,8 @@ void server_init (struct audio_s *audio_config_p, struct misc_config_s *misc_con
|
||||||
|
|
||||||
void server_send_rec_packet (int chan, packet_t pp, unsigned char *fbuf, int flen);
|
void server_send_rec_packet (int chan, packet_t pp, unsigned char *fbuf, int flen);
|
||||||
|
|
||||||
|
int server_callsign_registered_by_client (char *callsign);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* end server.h */
|
/* end server.h */
|
||||||
|
|
Loading…
Reference in New Issue