- FTP, TCP
This commit is contained in:
parent
499b5f030c
commit
96bc37f271
@ -1,6 +1,7 @@
|
|||||||
#include "ftp_server.h"
|
#include "ftp_server.h"
|
||||||
|
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
#include <etherlib/prefab/conn_blocks/tcp_connblock.h>
|
#include <etherlib/prefab/conn_blocks/tcp_connblock.h>
|
||||||
|
|
||||||
@ -8,10 +9,21 @@
|
|||||||
|
|
||||||
/* FTP response messages */
|
/* FTP response messages */
|
||||||
|
|
||||||
static char ftpGreeting[] = "220 Service ready for new user.\r\n";
|
static const char ftpOpeningDataConn[] = "150 Opening data connection.\r\n";
|
||||||
static char ftpNotImplemented[] = "502 Command not implemented.\r\n";
|
static const char ftpCmdOk[] = "200 Command OK.\r\n";
|
||||||
static char ftpLoginOK[] = "230 User logged in, proceed.\r\n";
|
static const char ftpGreeting[] = "220 Service ready for new user.\r\n";
|
||||||
static char ftpRootDirName[] = "257 \"/\" is the current directory\r\n";
|
static const char ftpClosingDataConn[] = "226 Closing data connection.\r\n";
|
||||||
|
static const char ftpEnteringPassivePrefix[] = "227 Entering passive mode ";
|
||||||
|
static const char ftpLoginOK[] = "230 User logged in, proceed.\r\n";
|
||||||
|
static const char ftpFileActionCplt[] = "250 Requested file action complete.\r\n";
|
||||||
|
static const char ftpRootDirName[] = "257 \"/\" is the current directory\r\n";
|
||||||
|
static const char ftpSyntaxError[] = "501 Syntax error in command or parameters\r\n";
|
||||||
|
static const char ftpNotImplemented[] = "502 Command not implemented.\r\n";
|
||||||
|
static const char ftpCmdNotImplForParam[] = "504 Command not implemented for that parameter\r\n";
|
||||||
|
|
||||||
|
#define FTPS_DYNAMIC_RESPONSE_MAXLEN (63)
|
||||||
|
|
||||||
|
static char ftpsDynResp[FTPS_DYNAMIC_RESPONSE_MAXLEN + 1] = {0};
|
||||||
|
|
||||||
/* Implemented commands */
|
/* Implemented commands */
|
||||||
|
|
||||||
@ -29,6 +41,9 @@ static char *ftpImplementedCmdsStr[] = {
|
|||||||
|
|
||||||
// ------ additional commands
|
// ------ additional commands
|
||||||
"PWD",
|
"PWD",
|
||||||
|
"CWD",
|
||||||
|
"PASV",
|
||||||
|
"LIST",
|
||||||
"\0" // SENTRY!
|
"\0" // SENTRY!
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -45,7 +60,10 @@ typedef enum { // ordering must be the same as in the string version above
|
|||||||
NOOP,
|
NOOP,
|
||||||
|
|
||||||
// ------ additional commands
|
// ------ additional commands
|
||||||
PWD
|
PWD,
|
||||||
|
CWD,
|
||||||
|
PASV,
|
||||||
|
LIST
|
||||||
} Ftp_ImplementedCmds;
|
} Ftp_ImplementedCmds;
|
||||||
|
|
||||||
// -----------
|
// -----------
|
||||||
@ -61,7 +79,7 @@ int ftps_ctrl_recv(cbd d) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int ftps_accept_cb(cbd d) {
|
int ftps_ctrl_accept_cb(cbd d) {
|
||||||
s.connCtrl = d;
|
s.connCtrl = d;
|
||||||
uint32_t event = FTPEVT_NEW_CONNECTION;
|
uint32_t event = FTPEVT_NEW_CONNECTION;
|
||||||
ETHLIB_OS_QUEUE_PUSH(s.eventQ, &event);
|
ETHLIB_OS_QUEUE_PUSH(s.eventQ, &event);
|
||||||
@ -73,12 +91,36 @@ void ftps_thread(void *param);
|
|||||||
void ftps_init() {
|
void ftps_init() {
|
||||||
osThreadAttr_t attr;
|
osThreadAttr_t attr;
|
||||||
memset(&attr, 0, sizeof(osThreadAttr_t));
|
memset(&attr, 0, sizeof(osThreadAttr_t));
|
||||||
attr.stack_size = 2048;
|
attr.stack_size = 3072;
|
||||||
attr.priority = osPriorityNormal;
|
attr.priority = osPriorityNormal;
|
||||||
attr.name = "ftp";
|
attr.name = "ftp";
|
||||||
osThreadNew(ftps_thread, NULL, &attr);
|
osThreadNew(ftps_thread, NULL, &attr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
char *ftps_get_word(char *word, char *str, uint32_t maxLen) {
|
||||||
|
char *iter = str;
|
||||||
|
uint32_t len = 0;
|
||||||
|
|
||||||
|
// skip leading whitespaces
|
||||||
|
while ((*iter <= ' ') && (*iter != '\0')) {
|
||||||
|
iter++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// look for end of word, and copy until copy size is reached
|
||||||
|
while (*iter > ' ') {
|
||||||
|
if (len < maxLen) {
|
||||||
|
word[len] = *iter;
|
||||||
|
}
|
||||||
|
|
||||||
|
len++;
|
||||||
|
iter++;
|
||||||
|
}
|
||||||
|
word[len] = '\0'; // insert null termination
|
||||||
|
|
||||||
|
// return the position of the next whitespace
|
||||||
|
return iter;
|
||||||
|
}
|
||||||
|
|
||||||
bool ftps_is_command_implemented(char *cmd, uint32_t len, uint32_t *cmdCode) {
|
bool ftps_is_command_implemented(char *cmd, uint32_t len, uint32_t *cmdCode) {
|
||||||
char *iter = ftpImplementedCmdsStr[0];
|
char *iter = ftpImplementedCmdsStr[0];
|
||||||
bool ret = false;
|
bool ret = false;
|
||||||
@ -109,14 +151,29 @@ bool ftps_is_command_implemented(char *cmd, uint32_t len, uint32_t *cmdCode) {
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ftps_rtrim(char * str) {
|
void ftps_rtrim(char *str) {
|
||||||
char * iter = str + strlen(str) - 1;
|
char *iter = str + strlen(str) - 1;
|
||||||
while ((*iter <= ' ') && (iter >= str)) {
|
while ((*iter <= ' ') && (iter >= str)) {
|
||||||
*iter = '\0';
|
*iter = '\0';
|
||||||
iter--;
|
iter--;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// data reception on data port
|
||||||
|
int ftps_data_recv(cbd d) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// accept new data connection
|
||||||
|
int ftps_data_accept_cb(cbd d) {
|
||||||
|
s.connData = d; // set data connection ID
|
||||||
|
ETHLIB_OS_SEM_POST(s.dataConnHasOpened); // release data connection semaphore
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define FTPS_TYPE_ASCII 'A'
|
||||||
|
#define FTPS_TYPE_IMAGE 'I'
|
||||||
|
|
||||||
void ftps_process_event(uint32_t event) {
|
void ftps_process_event(uint32_t event) {
|
||||||
const char *resp = NULL; // response towards the FTP client
|
const char *resp = NULL; // response towards the FTP client
|
||||||
char *cmdArg = NULL; // command argument
|
char *cmdArg = NULL; // command argument
|
||||||
@ -169,12 +226,71 @@ void ftps_process_event(uint32_t event) {
|
|||||||
s.connState = FTPS_ESTABLISHED;
|
s.connState = FTPS_ESTABLISHED;
|
||||||
}
|
}
|
||||||
} else if (s.connState == FTPS_ESTABLISHED) {
|
} else if (s.connState == FTPS_ESTABLISHED) {
|
||||||
switch (cmdCode)
|
switch (cmdCode) {
|
||||||
{
|
|
||||||
case PWD: // print working directory name
|
case PWD: // print working directory name
|
||||||
resp = ftpRootDirName;
|
resp = ftpRootDirName;
|
||||||
break;
|
break;
|
||||||
case TYPE: //
|
case CWD:
|
||||||
|
resp = ftpFileActionCplt;
|
||||||
|
break;
|
||||||
|
case TYPE: { // set transfer format
|
||||||
|
char typeChar[2]; // get type character
|
||||||
|
ftps_get_word(typeChar, cmdArg, 1); // (first parameter)
|
||||||
|
|
||||||
|
// if no parameter was defined
|
||||||
|
if (typeChar[0] == '\0') {
|
||||||
|
goto syntax_error;
|
||||||
|
}
|
||||||
|
|
||||||
|
// if parameter is defined, then act accordingly
|
||||||
|
switch (typeChar[0]) {
|
||||||
|
case FTPS_TYPE_ASCII: // ASCII
|
||||||
|
case FTPS_TYPE_IMAGE: // Image (binary)
|
||||||
|
// I don't know if there's any difference between ASCII and Image transfers, since bytes are 8-bit long
|
||||||
|
goto cmd_ok;
|
||||||
|
break;
|
||||||
|
default: // other formats are not implemented
|
||||||
|
goto cmd_param_not_implemented;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
} break;
|
||||||
|
case PASV: { // enter passive mode
|
||||||
|
if (!s.passiveMode) {
|
||||||
|
// start data connection listener socket
|
||||||
|
uint16_t port;
|
||||||
|
do { // randomize a port number not in use currently
|
||||||
|
port = (rand() % (0xFFFF - 1024)) + 1024; // it's a nice practice if we pick a port number greater than 1024
|
||||||
|
s.connDataS = tcp_new_connblock(s.intf, IPv4_IF_ADDR, port, ftps_data_recv);
|
||||||
|
} while (s.connDataS == 0); // retry if connection block could not be opened
|
||||||
|
|
||||||
|
// convert to server socket
|
||||||
|
tcp_set_accept_callback(s.connDataS, ftps_data_accept_cb);
|
||||||
|
tcp_listen(s.connDataS);
|
||||||
|
|
||||||
|
MSG("port: %u\n", port);
|
||||||
|
|
||||||
|
// turn passive mode on and save passive mode port
|
||||||
|
s.passiveMode = true;
|
||||||
|
s.passiveModePort = port;
|
||||||
|
}
|
||||||
|
|
||||||
|
// compile response message
|
||||||
|
SNPRINTF(ftpsDynResp, FTPS_DYNAMIC_RESPONSE_MAXLEN, "%s (%u,%u,%u,%u,%u,%u)\r\n", // no space in the whole address-port compound
|
||||||
|
ftpEnteringPassivePrefix, EXPLODE_IPv4(s.intf->ip), (s.passiveModePort >> 8) & 0xFF, s.passiveModePort & 0xFF);
|
||||||
|
|
||||||
|
// set response
|
||||||
|
resp = ftpsDynResp;
|
||||||
|
} break;
|
||||||
|
case LIST: { // list files
|
||||||
|
ETHLIB_OS_SEM_WAIT(s.dataConnHasOpened); // wait for data connection to establish
|
||||||
|
tcp_send(s.connCtrl, (const uint8_t *)ftpOpeningDataConn, strlen(ftpOpeningDataConn)); // opening data connection
|
||||||
|
tcp_send(s.connData, (const uint8_t *)"\r\n", 2); // sending listing data
|
||||||
|
tcp_send(s.connCtrl, (const uint8_t *)ftpClosingDataConn, strlen(ftpClosingDataConn)); // closing data connection
|
||||||
|
close_connection(s.connData); // actually close connection
|
||||||
|
s.connData = 0; // clear data connection CBD
|
||||||
|
break;
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -187,19 +303,41 @@ resp_and_return:
|
|||||||
if (resp != NULL) {
|
if (resp != NULL) {
|
||||||
tcp_send(s.connCtrl, (const uint8_t *)resp, strlen(resp));
|
tcp_send(s.connCtrl, (const uint8_t *)resp, strlen(resp));
|
||||||
}
|
}
|
||||||
|
return;
|
||||||
|
|
||||||
|
// -----
|
||||||
|
syntax_error:
|
||||||
|
resp = ftpSyntaxError;
|
||||||
|
goto resp_and_return;
|
||||||
|
|
||||||
|
cmd_param_not_implemented:
|
||||||
|
resp = ftpCmdNotImplForParam;
|
||||||
|
goto resp_and_return;
|
||||||
|
|
||||||
|
cmd_ok:
|
||||||
|
resp = ftpCmdOk;
|
||||||
|
goto resp_and_return;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ftps_thread(void *param) {
|
void ftps_thread(void *param) {
|
||||||
|
// set interface
|
||||||
|
s.intf = get_default_interface();
|
||||||
|
|
||||||
// initialize event queue
|
// initialize event queue
|
||||||
s.eventQ = ETHLIB_OS_QUEUE_CREATE(FTPS_EVENT_QUEUE_LENGTH, uint32_t);
|
s.eventQ = ETHLIB_OS_QUEUE_CREATE(FTPS_EVENT_QUEUE_LENGTH, uint32_t);
|
||||||
|
|
||||||
// initialize control connection
|
// initialize control connection
|
||||||
s.connCtrlS = tcp_new_connblock(get_default_interface(), IPv4_IF_ADDR, FTPS_CTRL_PORT, ftps_ctrl_recv);
|
s.connCtrlS = tcp_new_connblock(s.intf, IPv4_IF_ADDR, FTPS_CTRL_PORT, ftps_ctrl_recv);
|
||||||
|
tcp_set_accept_callback(s.connCtrlS, ftps_ctrl_accept_cb); // set callback for accepting an incoming connection
|
||||||
tcp_listen(s.connCtrlS); // make it listen for incoming connections
|
tcp_listen(s.connCtrlS); // make it listen for incoming connections
|
||||||
tcp_set_accept_callback(s.connCtrlS, ftps_accept_cb); // set callback for accepting an incoming connection
|
|
||||||
|
|
||||||
// initialize connection state
|
// initialize connection state
|
||||||
s.connState = FTPS_IDLE;
|
s.connState = FTPS_IDLE;
|
||||||
|
s.passiveMode = false; // at the beginning we disable passive mode
|
||||||
|
s.passiveModePort = 0;
|
||||||
|
|
||||||
|
// initialize semaphore which synchronizes data connection state
|
||||||
|
s.dataConnHasOpened = ETHLIB_OS_SEM_CREATE(1);
|
||||||
|
|
||||||
// process loop
|
// process loop
|
||||||
for (;;) {
|
for (;;) {
|
||||||
|
@ -10,8 +10,6 @@
|
|||||||
|
|
||||||
#define FTPS_LINEBUF_LEN (63)
|
#define FTPS_LINEBUF_LEN (63)
|
||||||
|
|
||||||
#define FTPS_ROOT_DIR_NAME "ftp_root"
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* FTP connection state machine states.
|
* FTP connection state machine states.
|
||||||
*/
|
*/
|
||||||
@ -30,13 +28,20 @@ typedef enum {
|
|||||||
FTPEVT_CTRL_RECVD, // a control message has been received
|
FTPEVT_CTRL_RECVD, // a control message has been received
|
||||||
} Ftps_ConnEvents;
|
} Ftps_ConnEvents;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* FTP server state.
|
||||||
|
*/
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
EthInterface * intf; // pointer to associated Ethernet interface
|
||||||
|
bool passiveMode; // indicates whether the server is operating in passive mode
|
||||||
|
uint16_t passiveModePort; // passive mode port once the passive mode is activated
|
||||||
cbd connCtrlS; // control connection server
|
cbd connCtrlS; // control connection server
|
||||||
cbd connCtrl; // established control connection
|
cbd connCtrl; // established control connection
|
||||||
cbd connDataS; // data connection server
|
cbd connDataS; // data connection server
|
||||||
cbd connData; // established data connection
|
cbd connData; // established data connection
|
||||||
Ftps_ConnState connState; // connection state
|
Ftps_ConnState connState; // connection state
|
||||||
ETHLIB_OS_QUEUE_TYPE eventQ; // event queue
|
ETHLIB_OS_QUEUE_TYPE eventQ; // event queue
|
||||||
|
ETHLIB_OS_SEM_TYPE dataConnHasOpened; // semaphore synchronizing data connection opening
|
||||||
char lineBuffer[FTPS_LINEBUF_LEN + 1]; // line buffer
|
char lineBuffer[FTPS_LINEBUF_LEN + 1]; // line buffer
|
||||||
} Ftps_State;
|
} Ftps_State;
|
||||||
|
|
||||||
|
@ -11,12 +11,12 @@ typedef int (*ConnBlockTransmitFn)(struct EthInterface_ * intf, const uint8_t *
|
|||||||
* Connection block.
|
* Connection block.
|
||||||
*/
|
*/
|
||||||
typedef struct ConnBlock_ {
|
typedef struct ConnBlock_ {
|
||||||
PcktSieve * sieve; ///< Ethernet interface
|
PcktSieve * sieve; ///< Pointer to the packet sieve
|
||||||
PcktSieveLayer * sieveLayer; ///< Sieve layer
|
PcktSieveLayer * sieveLayer; ///< Sieve layer
|
||||||
} ConnBlock;
|
} ConnBlock;
|
||||||
|
|
||||||
typedef struct ConstConnBlock_ {
|
typedef struct ConstConnBlock_ {
|
||||||
const PcktSieve * sieve; ///< Ethernet interface
|
const PcktSieve * sieve; ///< Pointer to the packet sieve
|
||||||
const PcktSieveLayer * sieveLayer; ///< Sieve layer
|
const PcktSieveLayer * sieveLayer; ///< Sieve layer
|
||||||
} ConstConnBlock;
|
} ConstConnBlock;
|
||||||
|
|
||||||
|
@ -91,6 +91,13 @@ void close_connection(cbd d) {
|
|||||||
|
|
||||||
cbdt_release(E.cbdt, d); // release from CBD table
|
cbdt_release(E.cbdt, d); // release from CBD table
|
||||||
|
|
||||||
|
// connb_remove() calls pcktsieve_remove_layer() which does not guarantee
|
||||||
|
// that the layer is instantaneously removed, since some protocols (like TCP)
|
||||||
|
// must gracefully shutdown the connection and the protocol implementation
|
||||||
|
// will then remove the layer. As long as the protocol implementation does
|
||||||
|
// not attempt to use the CBD released above, the cleanup actions will
|
||||||
|
// execute silently in the background without raising errors.
|
||||||
|
|
||||||
connb_remove(&connBlock); // remove connection block
|
connb_remove(&connBlock); // remove connection block
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -257,6 +257,7 @@ PcktSieveLayer* packsieve_new_layer(PcktSieveLayer *parent, const PcktSieveFilte
|
|||||||
layer->tag = tag;
|
layer->tag = tag;
|
||||||
layer->connBReportFn = NULL;
|
layer->connBReportFn = NULL;
|
||||||
layer->txTsCb = NULL;
|
layer->txTsCb = NULL;
|
||||||
|
layer->mgmtCb = NULL;
|
||||||
return layer;
|
return layer;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -267,6 +268,13 @@ bool packsieve_remove_layer(const PcktSieveLayer *layer) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// dispath management message if callback is defined
|
||||||
|
if (layer->mgmtCb != NULL) {
|
||||||
|
if (layer->mgmtCb(layer, PSLEVT_REMOVE) == PSMGMT_RET_ABORT) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// remove parent elements if their only subnode is the one we're deleting
|
// remove parent elements if their only subnode is the one we're deleting
|
||||||
PcktSieveLayer *parent;
|
PcktSieveLayer *parent;
|
||||||
while (layer != NULL && layer->nodes == NULL) {
|
while (layer != NULL && layer->nodes == NULL) {
|
||||||
|
@ -78,8 +78,28 @@ typedef int (*SieveCallBackFn)(const Pckt *pckt, PcktSieveLayerTag tag);
|
|||||||
struct ConnBlock_;
|
struct ConnBlock_;
|
||||||
typedef void (*ConnBlockReportFn)(const struct ConnBlock_ *connBlock);
|
typedef void (*ConnBlockReportFn)(const struct ConnBlock_ *connBlock);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Timestamp callback function.
|
||||||
|
*/
|
||||||
typedef void(*TxTimeStampCBFn)(uint32_t ts_s, uint32_t ts_ns, uint32_t tag);
|
typedef void(*TxTimeStampCBFn)(uint32_t ts_s, uint32_t ts_ns, uint32_t tag);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Management event types.
|
||||||
|
*/
|
||||||
|
typedef enum {
|
||||||
|
PSLEVT_NONE, ///< No event.
|
||||||
|
PSLEVT_REMOVE ///< The sievele layer is about to get deleted.
|
||||||
|
} PcktSieveLayerMgmtEvent;
|
||||||
|
|
||||||
|
// Management callback return values
|
||||||
|
#define PSMGMT_RET_PROCEED (0) // proceed with processing
|
||||||
|
#define PSMGMT_RET_ABORT (1) // abort processing
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Packet sieve layer management function.
|
||||||
|
*/
|
||||||
|
typedef int(*MgmtCBFn)(const struct PcktSieveLayer_ * layer, PcktSieveLayerMgmtEvent event);
|
||||||
|
|
||||||
#define PCKT_SIEVE_INFOTAG_LEN (24)
|
#define PCKT_SIEVE_INFOTAG_LEN (24)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -97,6 +117,7 @@ typedef struct PcktSieveLayer_ {
|
|||||||
struct PcktSieveLayer_ *next, *prev; ///< Next and previous sieve layer on the same level
|
struct PcktSieveLayer_ *next, *prev; ///< Next and previous sieve layer on the same level
|
||||||
struct PcktSieveLayer_ *nodes; ///< Subnodes in the sieve tree
|
struct PcktSieveLayer_ *nodes; ///< Subnodes in the sieve tree
|
||||||
ConnBlockReportFn connBReportFn; ///< Connection block report function pointer
|
ConnBlockReportFn connBReportFn; ///< Connection block report function pointer
|
||||||
|
MgmtCBFn mgmtCb; ///< Management callback function
|
||||||
} PcktSieveLayer;
|
} PcktSieveLayer;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -27,7 +27,7 @@ void tcpw_set_seqnum_offset(TcpWindow * tcpw, uint32_t offset) {
|
|||||||
tcpw->firstUnACK = offset;
|
tcpw->firstUnACK = offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline uint32_t tcpw_get_occupied_size(TcpWindow * tcpw) {
|
uint32_t tcpw_get_occupied_size(TcpWindow * tcpw) {
|
||||||
return tcpw->nextWritten - tcpw->firstUnACK;
|
return tcpw->nextWritten - tcpw->firstUnACK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -44,6 +44,15 @@ void tcpw_set_seqnum_offset(TcpWindow * tcpw, uint32_t offset);
|
|||||||
*/
|
*/
|
||||||
uint32_t tcpw_get_max_window_size(TcpWindow * tcpw);
|
uint32_t tcpw_get_max_window_size(TcpWindow * tcpw);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TODO: rename function
|
||||||
|
* Get used area size of this window.
|
||||||
|
* @param tcpw pointer to TCP Window object
|
||||||
|
* @return used area size in bytes
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
uint32_t tcpw_get_occupied_size(TcpWindow * tcpw);
|
||||||
|
|
||||||
/** TODO: rename function
|
/** TODO: rename function
|
||||||
* Store TCP segment
|
* Store TCP segment
|
||||||
* @param tcpw pointer to TCP Window object
|
* @param tcpw pointer to TCP Window object
|
||||||
|
@ -45,7 +45,7 @@ static bool filtTcp(const PcktSieveFilterCondition *filtCond, const PcktProps *c
|
|||||||
(remote_addr == ipProps->SourceIPAddr)) || // the packet has come from the known origin
|
(remote_addr == ipProps->SourceIPAddr)) || // the packet has come from the known origin
|
||||||
(remote_addr == 0)); // the latter conditions only matter if the control block is connected to a remote station
|
(remote_addr == 0)); // the latter conditions only matter if the control block is connected to a remote station
|
||||||
|
|
||||||
return ipProps->Protocol == ETH_TCP_PACKET_CLASS && references_us;
|
return (ipProps->Protocol == ETH_TCP_PACKET_CLASS) && references_us;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define MAX_TCP_WINDOW_SIZE (1200)
|
#define MAX_TCP_WINDOW_SIZE (1200)
|
||||||
@ -57,15 +57,16 @@ static inline TcpState *tcps_create() {
|
|||||||
tcps->txBufNotFull = ETHLIB_OS_SEM_CREATE(1); // create transmit buffer not full semaphore
|
tcps->txBufNotFull = ETHLIB_OS_SEM_CREATE(1); // create transmit buffer not full semaphore
|
||||||
ETHLIB_OS_SEM_POST(tcps->txBufNotFull); // post the tx buffer semaphore
|
ETHLIB_OS_SEM_POST(tcps->txBufNotFull); // post the tx buffer semaphore
|
||||||
tcps->txInProgress = ETHLIB_OS_SEM_CREATE(1); // create transmission in progress semaphore
|
tcps->txInProgress = ETHLIB_OS_SEM_CREATE(1); // create transmission in progress semaphore
|
||||||
ETHLIB_OS_SEM_POST(tcps->txInProgress);
|
ETHLIB_OS_SEM_POST(tcps->txInProgress); // post the TX in progress, since no transmission is in progress
|
||||||
|
tcps->eventFlags = osEventFlagsNew(NULL); // create event flags for internal event synchronization
|
||||||
|
osEventFlagsSet(tcps->eventFlags, EVTFLAG_ALL_ACKED); // everything is ACKed in the beginning
|
||||||
|
tcps->processMtx = ETHLIB_OS_RECMTX_CREATE(); // create mutex protecting the internal state
|
||||||
return tcps;
|
return tcps;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void tcps_release_client_related_objects(TcpState *tcps) {
|
static inline void tcps_release_client_related_objects(TcpState *tcps) {
|
||||||
tcpw_destroy(tcps->txWin);
|
tcpw_destroy(tcps->txWin);
|
||||||
ETHLIB_OS_SEM_DESTROY(tcps->txBufNotFull);
|
ETHLIB_OS_SEM_DESTROY(tcps->txBufNotFull);
|
||||||
ETHLIB_OS_SEM_DESTROY(tcps->txInProgress);
|
|
||||||
eth_bfifo_destroy(tcps->rxFifo);
|
eth_bfifo_destroy(tcps->rxFifo);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -78,6 +79,10 @@ static inline void tcps_remove_and_cleanup(TcpState *tcps) {
|
|||||||
tcps_release_client_related_objects(tcps);
|
tcps_release_client_related_objects(tcps);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ETHLIB_OS_SEM_DESTROY(tcps->txInProgress); // TODO: ezt a szerver bezárásakor nem kell vizsgálni
|
||||||
|
osEventFlagsDelete(tcps->eventFlags);
|
||||||
|
ETHLIB_OS_MTX_DESTROY(tcps->processMtx);
|
||||||
|
|
||||||
dynmem_free(tcps);
|
dynmem_free(tcps);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -147,10 +152,76 @@ static inline cbd tcps_create_based_on_listening(const TcpState *source, uint16_
|
|||||||
return d;
|
return d;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ----------------------------
|
||||||
|
|
||||||
|
static bool tcp_close(TcpState *tcps) {
|
||||||
|
TcpConnectionState cs = tcps->connState;
|
||||||
|
|
||||||
|
// a closed connection cannot be more closed...
|
||||||
|
if (cs == TCP_STATE_CLOSED) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// act according to the current state
|
||||||
|
switch (cs) {
|
||||||
|
case TCP_STATE_ESTAB: // close connecion from established state
|
||||||
|
// take send semaphore
|
||||||
|
ETHLIB_OS_SEM_WAIT(tcps->txInProgress);
|
||||||
|
|
||||||
|
MSG("TX SEM\n");
|
||||||
|
|
||||||
|
// wait for the TX FIFO contents to get transmitted
|
||||||
|
osEventFlagsWait(tcps->eventFlags, EVTFLAG_ALL_ACKED, osFlagsWaitAll | osFlagsNoClear, osWaitForever); // FIXME: ez így nem lesz jó, mert, ha valamiért nem kapjuk meg az ACK-t, akkor itt ragadunk
|
||||||
|
|
||||||
|
MSG("FLAG\n");
|
||||||
|
|
||||||
|
// lock the mutex -----
|
||||||
|
ETHLIB_OS_MTX_LOCK(tcps->processMtx);
|
||||||
|
// --------------------
|
||||||
|
|
||||||
|
// send a FIN-ACK segment
|
||||||
|
tcp_send_segment(&(tcps->connBlock), TCP_FLAG_FIN | TCP_FLAG_ACK, NULL, NULL, 0);
|
||||||
|
tcps->txSeqNum++; // increase own sequence number
|
||||||
|
|
||||||
|
// step into FIN WAIT-1 state
|
||||||
|
tcps->connState = TCP_STATE_FIN_WAIT_1;
|
||||||
|
|
||||||
|
// unlock the mutex -----
|
||||||
|
ETHLIB_OS_MTX_UNLOCK(tcps->processMtx);
|
||||||
|
// --------------------
|
||||||
|
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
int tcp_mgmt_cb(const PcktSieveLayer *layer, PcktSieveLayerMgmtEvent event) {
|
||||||
|
TcpState *tcps = TCP_FETCH_STATE_FROM_SIEVE_LAYER(layer);
|
||||||
|
|
||||||
|
switch (event) {
|
||||||
|
case PSLEVT_REMOVE: { // connection removal is in progress
|
||||||
|
return tcp_close(tcps) ? PSMGMT_RET_PROCEED : PSMGMT_RET_ABORT; // abort further removal processing if further steps are required to close the connection
|
||||||
|
} break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return PSMGMT_RET_PROCEED;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------
|
||||||
|
|
||||||
int tcp_receive_segment_cb(const Pckt *pckt, PcktSieveLayerTag tag) {
|
int tcp_receive_segment_cb(const Pckt *pckt, PcktSieveLayerTag tag) {
|
||||||
TcpState *tcps = (TcpState *)tag.p; // pointer to state is stored in sieve layer tag
|
TcpState *tcps = (TcpState *)tag.p; // pointer to state is stored in sieve layer tag
|
||||||
TcpProps *tcpProps = HEADER_FETCH_PROPS(TcpProps, pckt->header); // fetch header
|
TcpProps *tcpProps = HEADER_FETCH_PROPS(TcpProps, pckt->header); // fetch header
|
||||||
|
|
||||||
|
// lock the mutex -----
|
||||||
|
ETHLIB_OS_MTX_LOCK(tcps->processMtx);
|
||||||
|
// --------------------
|
||||||
|
|
||||||
TcpConnectionState beginState = tcps->connState;
|
TcpConnectionState beginState = tcps->connState;
|
||||||
|
|
||||||
IPv4Props *ipProps = HEADER_FETCH_PROPS(IPv4Props, pckt->header->prev);
|
IPv4Props *ipProps = HEADER_FETCH_PROPS(IPv4Props, pckt->header->prev);
|
||||||
@ -175,6 +246,8 @@ int tcp_receive_segment_cb(const Pckt *pckt, PcktSieveLayerTag tag) {
|
|||||||
// store rxAckNum
|
// store rxAckNum
|
||||||
tcps->rxAckNum = tcpProps->SequenceNumber + 1;
|
tcps->rxAckNum = tcpProps->SequenceNumber + 1;
|
||||||
|
|
||||||
|
// MSG("SYN ACK\n");
|
||||||
|
|
||||||
// get MSS
|
// get MSS
|
||||||
TcpOption *mss = tcp_get_option_by_kind(tcpProps->options, TCP_OPT_KIND_MSS);
|
TcpOption *mss = tcp_get_option_by_kind(tcpProps->options, TCP_OPT_KIND_MSS);
|
||||||
if (mss != NULL) { // if MSS is included in the segment
|
if (mss != NULL) { // if MSS is included in the segment
|
||||||
@ -205,6 +278,9 @@ int tcp_receive_segment_cb(const Pckt *pckt, PcktSieveLayerTag tag) {
|
|||||||
|
|
||||||
// step into next state
|
// step into next state
|
||||||
tcps->connState = TCP_STATE_ESTAB;
|
tcps->connState = TCP_STATE_ESTAB;
|
||||||
|
|
||||||
|
// set event flags
|
||||||
|
osEventFlagsSet(tcps->eventFlags, EVTFLAG_ESTAB);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -247,8 +323,7 @@ int tcp_receive_segment_cb(const Pckt *pckt, PcktSieveLayerTag tag) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
} break;
|
||||||
}
|
|
||||||
|
|
||||||
case TCP_STATE_ESTAB: /* Connection established */
|
case TCP_STATE_ESTAB: /* Connection established */
|
||||||
// if the other end tries to close down the connection
|
// if the other end tries to close down the connection
|
||||||
@ -282,6 +357,13 @@ int tcp_receive_segment_cb(const Pckt *pckt, PcktSieveLayerTag tag) {
|
|||||||
// release segment from retransmit window
|
// release segment from retransmit window
|
||||||
tcpw_acknowledge(tcps->txWin, tcpProps->AcknowledgementNumber);
|
tcpw_acknowledge(tcps->txWin, tcpProps->AcknowledgementNumber);
|
||||||
|
|
||||||
|
// set or clear all ACKed flag according to TX window state
|
||||||
|
if (tcpw_get_occupied_size(tcps->txWin) == 0) {
|
||||||
|
osEventFlagsSet(tcps->eventFlags, EVTFLAG_ALL_ACKED);
|
||||||
|
} else {
|
||||||
|
osEventFlagsClear(tcps->eventFlags, EVTFLAG_ALL_ACKED);
|
||||||
|
}
|
||||||
|
|
||||||
// release the transmit semaphore
|
// release the transmit semaphore
|
||||||
ETHLIB_OS_SEM_POST(tcps->txBufNotFull);
|
ETHLIB_OS_SEM_POST(tcps->txBufNotFull);
|
||||||
|
|
||||||
@ -296,12 +378,51 @@ int tcp_receive_segment_cb(const Pckt *pckt, PcktSieveLayerTag tag) {
|
|||||||
case TCP_STATE_LAST_ACK: /* last ACK received */
|
case TCP_STATE_LAST_ACK: /* last ACK received */
|
||||||
if (tcpProps->Flags & TCP_FLAG_ACK) {
|
if (tcpProps->Flags & TCP_FLAG_ACK) {
|
||||||
tcps->connState = TCP_STATE_CLOSED;
|
tcps->connState = TCP_STATE_CLOSED;
|
||||||
//ETHLIB_OS_SEM_POST(tcps->txBufNotFull); FIXME!
|
// ETHLIB_OS_SEM_POST(tcps->txBufNotFull); FIXME!
|
||||||
//ETHLIB_OS_SEM_WAIT(tcps->txInProgress);
|
// ETHLIB_OS_SEM_WAIT(tcps->txInProgress);
|
||||||
ret = SIEVE_LAYER_REMOVE_THIS; // if peer closed the connection, remove sieve layer
|
ret = SIEVE_LAYER_REMOVE_THIS; // if peer closed the connection, remove sieve layer
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case TCP_STATE_FIN_WAIT_1: { /* our FIN has been sent, waiting for the peer's one */
|
||||||
|
uint16_t flags = tcpProps->Flags;
|
||||||
|
bool rxACKok = tcpProps->AcknowledgementNumber == tcps->txSeqNum; // check if received ACK was correct
|
||||||
|
bool sendACK = false; // set if we want to emit an ACK
|
||||||
|
|
||||||
|
if ((flags & TCP_FLAG_ACK) && (!(flags & TCP_FLAG_FIN))) { // only ACK received
|
||||||
|
tcps->connState = TCP_STATE_FIN_WAIT_2; // this case don't send ACK
|
||||||
|
} else if ((!(flags & TCP_FLAG_ACK)) && (flags & TCP_FLAG_FIN)) { // only FIN received
|
||||||
|
tcps->connState = TCP_STATE_CLOSING;
|
||||||
|
sendACK = true;
|
||||||
|
} else if ((flags & TCP_FLAG_ACK) && (flags & TCP_FLAG_FIN)) { // received ACK and FIN
|
||||||
|
tcps->connState = TCP_STATE_CLOSED;
|
||||||
|
ret = SIEVE_LAYER_REMOVE_THIS;
|
||||||
|
sendACK = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// send ACK if required and received ACK was correct
|
||||||
|
if (sendACK && rxACKok) {
|
||||||
|
tcps->rxAckNum++; // acknowledge the FIN-ACK packet
|
||||||
|
tcp_send_segment(&(tcps->connBlock), TCP_FLAG_ACK, NULL, NULL, 0);
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case TCP_STATE_FIN_WAIT_2: { /* waiting on peer's FIN */
|
||||||
|
if (tcpProps->Flags & TCP_FLAG_FIN) {
|
||||||
|
tcps->rxAckNum++; // acknowledge the FIN packet
|
||||||
|
tcp_send_segment(&(tcps->connBlock), TCP_FLAG_ACK, NULL, NULL, 0);
|
||||||
|
tcps->connState = TCP_STATE_CLOSED;
|
||||||
|
ret = SIEVE_LAYER_REMOVE_THIS;
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case TCP_STATE_CLOSING: /* waiting on arrival of ACK sent by the peer against our FIN */ /* connection is closing waiting on peers ACK */
|
||||||
|
if ((tcpProps->Flags & TCP_FLAG_ACK) && (tcpProps->AcknowledgementNumber == tcps->txSeqNum)) { // ACK received
|
||||||
|
tcps->connState = TCP_STATE_CLOSED;
|
||||||
|
ret = SIEVE_LAYER_REMOVE_THIS;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
case TCP_STATE_CLOSED: /* connection is CLOSED */
|
case TCP_STATE_CLOSED: /* connection is CLOSED */
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
@ -323,8 +444,13 @@ int tcp_receive_segment_cb(const Pckt *pckt, PcktSieveLayerTag tag) {
|
|||||||
tcpopt_chain_free(tcpProps->options);
|
tcpopt_chain_free(tcpProps->options);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// unlock the mutex -----
|
||||||
|
ETHLIB_OS_MTX_UNLOCK(tcps->processMtx);
|
||||||
|
// --------------------
|
||||||
|
|
||||||
// release descriptor if not meaningful anymore
|
// release descriptor if not meaningful anymore
|
||||||
if (ret == SIEVE_LAYER_REMOVE_THIS) {
|
if (ret == SIEVE_LAYER_REMOVE_THIS) {
|
||||||
|
tcps->connBlock.sieveLayer->mgmtCb = NULL;
|
||||||
cbdt_release(E.cbdt, tcps->d); // release descriptor
|
cbdt_release(E.cbdt, tcps->d); // release descriptor
|
||||||
tcps_remove_and_cleanup(tcps); // release TCP state
|
tcps_remove_and_cleanup(tcps); // release TCP state
|
||||||
}
|
}
|
||||||
@ -332,6 +458,7 @@ int tcp_receive_segment_cb(const Pckt *pckt, PcktSieveLayerTag tag) {
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: mindent egy függvénybe kellene tenni, mert így nagyon sok versenyhelyet alakulhat ki
|
||||||
void tcp_bind(cbd d, ip4_addr remoteAddr, uint16_t remotePort) {
|
void tcp_bind(cbd d, ip4_addr remoteAddr, uint16_t remotePort) {
|
||||||
ConnBlock connBlock;
|
ConnBlock connBlock;
|
||||||
if (!cbdt_get_connection_block(E.cbdt, d, &connBlock)) {
|
if (!cbdt_get_connection_block(E.cbdt, d, &connBlock)) {
|
||||||
@ -339,8 +466,14 @@ void tcp_bind(cbd d, ip4_addr remoteAddr, uint16_t remotePort) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// store remote station data
|
// fetch TCP state
|
||||||
TcpState *tcps = TCP_FETCH_STATE_FROM_CONNBLOCK(&connBlock);
|
TcpState *tcps = TCP_FETCH_STATE_FROM_CONNBLOCK(&connBlock);
|
||||||
|
|
||||||
|
// lock the mutex -----
|
||||||
|
ETHLIB_OS_MTX_LOCK(tcps->processMtx);
|
||||||
|
// --------------------
|
||||||
|
|
||||||
|
// set peer address and port
|
||||||
tcps->remoteAddr = remoteAddr;
|
tcps->remoteAddr = remoteAddr;
|
||||||
tcps->remotePort = remotePort;
|
tcps->remotePort = remotePort;
|
||||||
|
|
||||||
@ -359,6 +492,13 @@ void tcp_bind(cbd d, ip4_addr remoteAddr, uint16_t remotePort) {
|
|||||||
|
|
||||||
// step into SYN SENT state
|
// step into SYN SENT state
|
||||||
tcps->connState = TCP_STATE_SYN_SENT;
|
tcps->connState = TCP_STATE_SYN_SENT;
|
||||||
|
|
||||||
|
// unlock the mutex -----
|
||||||
|
ETHLIB_OS_MTX_UNLOCK(tcps->processMtx);
|
||||||
|
// --------------------
|
||||||
|
|
||||||
|
// wait for getting into Established state
|
||||||
|
osEventFlagsWait(tcps->eventFlags, EVTFLAG_ESTAB, osFlagsWaitAll | osFlagsNoClear, osWaitForever);
|
||||||
}
|
}
|
||||||
|
|
||||||
void tcp_listen(cbd d) {
|
void tcp_listen(cbd d) {
|
||||||
@ -368,12 +508,22 @@ void tcp_listen(cbd d) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// fetch state
|
||||||
TcpState *tcps = TCP_FETCH_STATE_FROM_CONNBLOCK(&connBlock);
|
TcpState *tcps = TCP_FETCH_STATE_FROM_CONNBLOCK(&connBlock);
|
||||||
|
|
||||||
|
// lock the mutex -----
|
||||||
|
ETHLIB_OS_MTX_LOCK(tcps->processMtx);
|
||||||
|
// --------------------
|
||||||
|
|
||||||
if ((tcps->streamCb != NULL) && (tcps->connState == TCP_STATE_CLOSED)) { // step into listen state
|
if ((tcps->streamCb != NULL) && (tcps->connState == TCP_STATE_CLOSED)) { // step into listen state
|
||||||
tcps->connState = TCP_STATE_LISTEN;
|
tcps->connState = TCP_STATE_LISTEN;
|
||||||
tcps->isServer = true;
|
tcps->isServer = true;
|
||||||
tcps_release_client_related_objects(tcps);
|
tcps_release_client_related_objects(tcps); // release client-only resources
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// unlock the mutex -----
|
||||||
|
ETHLIB_OS_MTX_UNLOCK(tcps->processMtx);
|
||||||
|
// --------------------
|
||||||
}
|
}
|
||||||
|
|
||||||
void tcp_set_accept_callback(cbd d, TcpAcceptCbFn acb) {
|
void tcp_set_accept_callback(cbd d, TcpAcceptCbFn acb) {
|
||||||
@ -415,6 +565,7 @@ static inline cbd tcp_new_connblock_filtcond(EthInterface *intf, ip4_addr ipAddr
|
|||||||
tcpConnB.sieveLayer = packsieve_new_layer(ipConnB.sieveLayer, filtCond, false, filtTcp, tcp_receive_segment_cb, tag, ETH_TCP_PACKET_CLASS);
|
tcpConnB.sieveLayer = packsieve_new_layer(ipConnB.sieveLayer, filtCond, false, filtTcp, tcp_receive_segment_cb, tag, ETH_TCP_PACKET_CLASS);
|
||||||
ASSERT_NULL(tcpConnB.sieveLayer);
|
ASSERT_NULL(tcpConnB.sieveLayer);
|
||||||
tcpConnB.sieveLayer->connBReportFn = tcp_print_report;
|
tcpConnB.sieveLayer->connBReportFn = tcp_print_report;
|
||||||
|
tcpConnB.sieveLayer->mgmtCb = tcp_mgmt_cb;
|
||||||
|
|
||||||
tcpConnB.sieve = &intf->sieve;
|
tcpConnB.sieve = &intf->sieve;
|
||||||
tcpState->connBlock = tcpConnB; // also store connection block parameters
|
tcpState->connBlock = tcpConnB; // also store connection block parameters
|
||||||
@ -565,6 +716,9 @@ uint32_t tcp_send(cbd d, const uint8_t *data, uint32_t size) {
|
|||||||
// store segment for possible retransmission
|
// store segment for possible retransmission
|
||||||
uint32_t txSize = tcpw_store(tcps->txWin, data, sizeLeft, tcps->txSeqNum);
|
uint32_t txSize = tcpw_store(tcps->txWin, data, sizeLeft, tcps->txSeqNum);
|
||||||
|
|
||||||
|
// clear all ACK-ed flag
|
||||||
|
osEventFlagsClear(tcps->eventFlags, EVTFLAG_ALL_ACKED);
|
||||||
|
|
||||||
// send segment with data (no options)
|
// send segment with data (no options)
|
||||||
tcp_send_segment(&connBlock, TCP_FLAG_ACK, NULL, data, txSize);
|
tcp_send_segment(&connBlock, TCP_FLAG_ACK, NULL, data, txSize);
|
||||||
|
|
||||||
|
@ -52,6 +52,9 @@ typedef enum {
|
|||||||
typedef int (*StreamCallBackFn)(cbd d);
|
typedef int (*StreamCallBackFn)(cbd d);
|
||||||
typedef int (*TcpAcceptCbFn)(cbd d);
|
typedef int (*TcpAcceptCbFn)(cbd d);
|
||||||
|
|
||||||
|
#define EVTFLAG_ESTAB (0x00000001)
|
||||||
|
#define EVTFLAG_ALL_ACKED (0x00000002)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TCP state.
|
* TCP state.
|
||||||
*/
|
*/
|
||||||
@ -103,11 +106,20 @@ typedef struct {
|
|||||||
|
|
||||||
// ---------------
|
// ---------------
|
||||||
|
|
||||||
|
ETHLIB_OS_MTX_TYPE processMtx; ///< a mutex protecting TCP state changes (this is how we can manipulate the internal state without raising race conditions)
|
||||||
|
|
||||||
|
// ---------------
|
||||||
|
|
||||||
|
osEventFlagsId_t eventFlags; ///< Semaphore for synchronizing on getting into established state
|
||||||
|
|
||||||
|
// ---------------
|
||||||
|
|
||||||
EthBlockingFifo * rxFifo; ///< Receive FIFO
|
EthBlockingFifo * rxFifo; ///< Receive FIFO
|
||||||
|
|
||||||
} TcpState;
|
} TcpState;
|
||||||
|
|
||||||
#define TCP_FETCH_STATE_FROM_CONNBLOCK(connBlock) ((TcpState *) (connBlock)->sieveLayer->tag.p)
|
#define TCP_FETCH_STATE_FROM_CONNBLOCK(connBlock) ((TcpState *) (connBlock)->sieveLayer->tag.p)
|
||||||
|
#define TCP_FETCH_STATE_FROM_SIEVE_LAYER(layer) ((TcpState *) (layer)->tag.p)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create new TCP connection block
|
* Create new TCP connection block
|
||||||
|
Loading…
x
Reference in New Issue
Block a user