From 9532b6b274c6050954d8ad8e741c016633dbc50f Mon Sep 17 00:00:00 2001 From: Epagris Date: Sun, 6 Oct 2024 23:29:15 +0200 Subject: [PATCH] - EthIntf: packet interception in both directions; DHCP automanage; config loading and storing; info printing - utils: atoip(), lefttrim() - ARP: bunch of bugfixes - TCP, FTP: WIP - DHCP: mutex; query the FSM state --- apps/ftp_server.c | 21 +++-- arp_cache.c | 1 + eth_interface.c | 76 +++++++++++++--- eth_interface.h | 57 ++++++++++-- prefab/conn_blocks/arp_connblock.c | 40 +++++---- prefab/conn_blocks/tcp_connblock.c | 54 +++++++++-- prefab/packet_parsers/dhcp.c | 41 ++++++++- prefab/packet_parsers/dhcp.h | 8 ++ timer.c | 3 + utils.c | 138 +++++++++++++++++++---------- utils.h | 16 ++++ 11 files changed, 359 insertions(+), 96 deletions(-) diff --git a/apps/ftp_server.c b/apps/ftp_server.c index b630b6d..16ff0f0 100644 --- a/apps/ftp_server.c +++ b/apps/ftp_server.c @@ -167,6 +167,7 @@ int ftps_data_recv(cbd d) { // accept new data connection int ftps_data_accept_cb(cbd d) { s.connData = d; // set data connection ID + tcp_debug(d, true); ETHLIB_OS_SEM_POST(s.dataConnHasOpened); // release data connection semaphore return 0; } @@ -185,10 +186,19 @@ void ftps_process_event(uint32_t event) { uint32_t recvLen = tcp_recv(s.connCtrl, (uint8_t *)s.lineBuffer, FTPS_LINEBUF_LEN); s.lineBuffer[recvLen] = '\0'; + // if recv len is zero in dicating that the connection was closed, by the peer, + // then reset the server state + if (recvLen == 0) { + s.connCtrl = 0; + s.connState = FTPS_IDLE; + // TODO: close data connection as well + return; + } + // right trim the line ftps_rtrim(s.lineBuffer); - MSG("%s\n", s.lineBuffer); + // MSG("%s\n", s.lineBuffer); // get first word: get pointer to first space and calculate compare length char *spacePos = strchr(s.lineBuffer, ' '); @@ -285,12 +295,13 @@ void ftps_process_event(uint32_t event) { 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.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; - } + s.connData = 0; + resp = NULL; // clear data connection CBD + } break; + default: break; } diff --git a/arp_cache.c b/arp_cache.c index 17ed51a..753655e 100644 --- a/arp_cache.c +++ b/arp_cache.c @@ -21,6 +21,7 @@ static int arpc_recv_cb(const Pckt * pckt, PcktSieveLayerTag tag) { if (weAreCalled) { arpc_respond(arpc, arpProps->SHA, arpProps->SPA); + //MSG("Megy a válasz!\n"); } return 0; diff --git a/eth_interface.c b/eth_interface.c index c3b84b3..51812d9 100644 --- a/eth_interface.c +++ b/eth_interface.c @@ -67,10 +67,12 @@ EthInterface *ethintf_new(EthIODef *io) { ethIntf->capabilities = 0; ethIntf->dhcp = NULL; + ethIntf->manageDhcp = true; // by default, enable automatic DHCP management memset(ðIntf->evtCbTable, 0, sizeof(EthIntfEventCbTable)); - ethIntf->interceptCb = NULL; + ethIntf->interceptTxCb = NULL; + ethIntf->interceptRxCb = NULL; ethIntf->linkState = false; @@ -97,8 +99,8 @@ static ThreadReturnType task_ethintf(ThreadParamType param) { mq_pop(intf->rxQ); // packet interception, if defined - if (intf->interceptCb != NULL) { - intf->interceptCb(intf, &rawPckt); + if (intf->interceptRxCb != NULL) { + intf->interceptRxCb(intf, &rawPckt); } // packet processing @@ -112,10 +114,10 @@ static ThreadReturnType task_ethintf(ThreadParamType param) { uint16_t speed = (event_data >> 2); bool prev_ls = ethinf_get_link_state(intf); // get previous link state - ethinf_set_link_state(intf, ls); // set new link state + ethinf_set_link_state(intf, ls); // set new link state - if ((intf->dhcp != NULL) && (ls != prev_ls)) { // no double start! - if (ls) { // if link is on + if ((intf->manageDhcp) && (intf->dhcp != NULL) && (ls != prev_ls)) { // no double start! + if (ls) { // if link is on dhcp_start(intf->dhcp); } else { // if link is off dhcp_stop(intf->dhcp); @@ -155,8 +157,13 @@ void ethinf_transmit(EthInterface *intf, const RawPckt *rawPckt) { return; } + // packet interception, if defined + if (intf->interceptTxCb != NULL) { + intf->interceptTxCb(intf, rawPckt); + } + // push packet onto the message queue - if (mq_push(intf->txQ, rawPckt)) { + if (mq_push(intf->txQ, rawPckt)) { ethinf_push_notification(intf, ETH_IIE_TRANSMIT_NOTIFY, 0); // notify processing thread of the peding transmit } else { ERROR("Interface TRANSMIT queue full, packet dropped!\n"); @@ -222,6 +229,55 @@ void ethinf_down(EthInterface *intf) { intf->up = false; } -void ethinf_set_intercept_callback(EthInterface * intf, EthIntfInterceptCb cb) { - intf->interceptCb = cb; -} \ No newline at end of file +void ethinf_set_intercept_callback(EthInterface *intf, EthIntfInterceptCb cb, EthIntfInterceptDir dir) { + if (dir & ETH_INTERCEPT_TX) { + intf->interceptTxCb = cb; + } + + if (dir & ETH_INTERCEPT_RX) { + intf->interceptRxCb = cb; + } +} + +void ethinf_set_automatic_dhcp_management(EthInterface *intf, bool automg) { + intf->manageDhcp = automg; +} + +void ethinf_set_config(EthInterface *intf, const EthInterfaceNetworkConfig *config) { + intf->ip = config->ip; + intf->router = config->router; + intf->netmask = config->netmask; + intf->dns = config->dns; + + intf->manageDhcp = config->manageDhcp; +} + +void ethinf_get_config(EthInterface *intf, EthInterfaceNetworkConfig *config) { + config->ip = intf->ip; + config->router = intf->router; + config->netmask = intf->netmask; + config->dns = intf->dns; + + config->manageDhcp = intf->manageDhcp; +} + +void ethinf_print_info(const EthInterface * intf) { + MSG("IP: " ANSI_COLOR_BYELLOW); + PRINT_IPv4(intf->ip); + MSG(ANSI_COLOR_RESET "\nRouter: "); + PRINT_IPv4(intf->router); + MSG("\nNetmask: "); + PRINT_IPv4(intf->netmask); + MSG("\nDNS: "); + PRINT_IPv4(intf->dns); + MSG("\n\n"); + + if (intf->dhcp != NULL) { + bool on = dhcp_get_fsm_state(intf->dhcp) != DHCP_STOPPED; + MSG("DHCP is %s" ANSI_COLOR_RESET "%s.", on ? (ANSI_COLOR_BGREEN "ON") : (ANSI_COLOR_BRED "OFF"), intf->manageDhcp ? "[automanaged]" : ""); + } else { + MSG ("DHCP is " ANSI_COLOR_RED "absent" ANSI_COLOR_RESET "."); + } + + MSG("\n"); +} diff --git a/eth_interface.h b/eth_interface.h index cf07233..78eafd7 100644 --- a/eth_interface.h +++ b/eth_interface.h @@ -48,6 +48,14 @@ struct EthInterface_; typedef void (*EthIntfEvtCb)(struct EthInterface_ *intf); +/** + * Frame interception direction. + */ +typedef enum { + ETH_INTERCEPT_TX = 1, + ETH_INTERCEPT_RX = 2 +} EthIntfInterceptDir; + /** * Function prototype for intercepting packets on an interface. * @param intf pointer to corresponding Ethernet interface @@ -77,6 +85,7 @@ typedef struct EthInterface_ { EthernetAddress mac; ///< Ethernet address uint32_t capabilities; ///< Ethernet interface capabilities DhcpState *dhcp; ///< DHCP control block (allocated only, if DHCP operation is initiated) + bool manageDhcp; ///< Let the interface automatically manage the DHCP client (start/stop) ip4_addr ip; ///< IP address ip4_addr router; ///< Router IP address ip4_addr netmask; ///< Subnet mask @@ -87,14 +96,23 @@ typedef struct EthInterface_ { MsgQueue *rxQ; ///< Receive queue ETHLIB_OS_QUEUE_TYPE eventQ; ///< Event queue // ETHLIB_OS_SEM_TYPE eventSem; ///< Event queue semaphore - IPv4Assembler *ipra; ///< IPv4 reassembler - EthIntfEventCbTable evtCbTable; ///< Event callback table - bool linkState; ///< Interface link state - bool up; ///< Is the interface up? - EthIntfInterceptCb interceptCb; ///< Intercept callback + IPv4Assembler *ipra; ///< IPv4 reassembler + EthIntfEventCbTable evtCbTable; ///< Event callback table + bool linkState; ///< Interface link state + bool up; ///< Is the interface up? + EthIntfInterceptCb interceptTxCb; ///< Intercept TX callback + EthIntfInterceptCb interceptRxCb; ///< Intercept RX callback } EthInterface; +/* + * Ethernet interface configuration. + */ +typedef struct { + ip4_addr ip, router, netmask, dns; + bool manageDhcp; +} EthInterfaceNetworkConfig; + /** * Allocate a new Ethernet interface * @param io Low-level IO definitions @@ -183,6 +201,33 @@ void ethinf_down(EthInterface *intf); * @param intf pointer to Ethernet interface * @param cb intercept callback pointer */ -void ethinf_set_intercept_callback(EthInterface *intf, EthIntfInterceptCb cb); +void ethinf_set_intercept_callback(EthInterface *intf, EthIntfInterceptCb cb, EthIntfInterceptDir dir); + +/** + * Turn ON/OFF automatic DHCP client management. + * @param intf pointer to Ethernet interface + * @param automg automanagement enabled/disabled + */ +void ethinf_set_automatic_dhcp_management(EthInterface *intf, bool automg); + +/** + * Set interface configuration. + * @param intf pointer to Ethernet interface + * @param config pointer to a filled config object +*/ +void ethinf_set_config(EthInterface * intf, const EthInterfaceNetworkConfig * config); + +/** + * Get interface configuration. + * @param intf pointer to Ethernet interface + * @param config pointer to an empty config object +*/ +void ethinf_get_config(EthInterface *intf, EthInterfaceNetworkConfig *config); + +/** + * Printf information on Ethernet interface. + * @param intf pointer to Ethernet interface +*/ +void ethinf_print_info(const EthInterface * intf); #endif // ETHERLIB_ETH_INTERFACE_H diff --git a/prefab/conn_blocks/arp_connblock.c b/prefab/conn_blocks/arp_connblock.c index 7052417..48bf9c1 100644 --- a/prefab/conn_blocks/arp_connblock.c +++ b/prefab/conn_blocks/arp_connblock.c @@ -2,17 +2,18 @@ #include -#include "../../utils.h" #include "../../dynmem.h" +#include "../../utils.h" +#include "../../pckt_assembler.h" -static bool filtArp(const PcktSieveFilterCondition * filtCond, const PcktProps * contProps, const PcktProps * ownProps, EthInterface * intf) { - EthernetProps * ethProps = (EthernetProps *) contProps; - ArpProps * arpProps = (ArpProps *) ownProps; +static bool filtArp(const PcktSieveFilterCondition *filtCond, const PcktProps *contProps, const PcktProps *ownProps, EthInterface *intf) { + EthernetProps *ethProps = (EthernetProps *)contProps; + ArpProps *arpProps = (ArpProps *)ownProps; return ethProps->length_type == ETH_ARP_PACKET_CLASS; } -ConnBlock arp_new_connblock(EthInterface * intf, SieveCallBackFn cb) { +ConnBlock arp_new_connblock(EthInterface *intf, SieveCallBackFn cb) { ConnBlock arpConnB; // create ARP connblock connb_init_defaults(&arpConnB); @@ -29,35 +30,35 @@ ConnBlock arp_new_connblock(EthInterface * intf, SieveCallBackFn cb) { return arpConnB; } -void arp_send(const ConnBlock * connBlock, const ArpProps * props) { +void arp_send(const ConnBlock *connBlock, const ArpProps *props) { // allocate header chain - PcktHeaderElement * arpHeader = ALLOC_HEADER_ELEMENT(ArpProps); - PcktHeaderElement * ethHeader = ALLOC_HEADER_ELEMENT(EthernetProps); + PcktHeaderElement *arpHeader = ALLOC_HEADER_ELEMENT(ArpProps); + PcktHeaderElement *ethHeader = ALLOC_HEADER_ELEMENT(EthernetProps); arpHeader->next = NULL; arpHeader->prev = ethHeader; ethHeader->next = arpHeader; ethHeader->prev = NULL; // fetch props - ArpProps * arpProps = HEADER_FETCH_PROPS(ArpProps, arpHeader); - EthernetProps * ethProps = HEADER_FETCH_PROPS(EthernetProps, ethHeader); + ArpProps *arpProps = HEADER_FETCH_PROPS(ArpProps, arpHeader); + EthernetProps *ethProps = HEADER_FETCH_PROPS(EthernetProps, ethHeader); // ARP *arpProps = *props; // Ethernet ethProps->length_type = ETH_ARP_PACKET_CLASS; - if (arpProps->OPER == ARPOP_REP) { // respond in unicast + if (arpProps->OPER == ARPOP_REP) { // respond in unicast memcpy(ethProps->destAddr, arpProps->THA, ETH_HW_ADDR_LEN); // unicast destination - } else if(arpProps->OPER == ARPOP_REQ) { // request in broadcast - memset(ethProps->destAddr, 0xFF, ETH_HW_ADDR_LEN); // broadcast destination + } else if (arpProps->OPER == ARPOP_REQ) { // request in broadcast + memset(ethProps->destAddr, 0xFF, ETH_HW_ADDR_LEN); // broadcast destination } memcpy(ethProps->sourceAddr, connBlock->sieve->intf->mac, ETH_HW_ADDR_LEN); // source // allocate transmit buffer uint32_t txHeaderSize = ETH_ETHERNET_HEADER_SIZE + ETH_ARP_HEADER_SIZE; - uint32_t txBufSize = MAX(txHeaderSize + 4, 60); - uint8_t * txBuf = dynmem_alloc(txBufSize); + uint32_t txBufSize = MAX(txHeaderSize + 4, ETH_FRAME_MIN_SIZE); + uint8_t *txBuf = dynmem_alloc(txBufSize); memset(txBuf, 0, txBufSize); // insert Ethernet header @@ -71,8 +72,11 @@ void arp_send(const ConnBlock * connBlock, const ArpProps * props) { dynmem_free(ethHeader); // append CRC at the end - uint32_t crc = crc32(txBuf, txBufSize - 4); - memcpy(txBuf + txBufSize - 4, &crc, 4); + //bool computeCRC = !(connBlock->sieve->intf->capabilities & ETHINF_CAP_TX_CRC_OFFLOAD); + //if (computeCRC) { + uint32_t crc = crc32(txBuf, txBufSize - 4); + memcpy(txBuf + txBufSize - 4, &crc, 4); + //} // send packet RawPckt rpckt; @@ -82,7 +86,7 @@ void arp_send(const ConnBlock * connBlock, const ArpProps * props) { ethinf_transmit(connBlock->sieve->intf, &rpckt); // release transmit buffer - //dynmem_free(txBuf); + // dynmem_free(txBuf); } void arp_print_report(const ConnBlock *connBlock) { diff --git a/prefab/conn_blocks/tcp_connblock.c b/prefab/conn_blocks/tcp_connblock.c index 29f7ea3..1c7c5f4 100644 --- a/prefab/conn_blocks/tcp_connblock.c +++ b/prefab/conn_blocks/tcp_connblock.c @@ -146,7 +146,7 @@ static inline cbd tcps_create_based_on_listening(const TcpState *source, uint16_ target->rxAckNum = source->rxAckNum; target->remoteAddr = remoteAddr; target->remotePort = remotePort; - target->connState = TCP_STATE_ESTAB; + target->connState = TCP_STATE_SYN_RCVD; tcpw_set_seqnum_offset(target->txWin, target->txSeqNum); return d; @@ -168,12 +168,12 @@ static bool tcp_close(TcpState *tcps) { // take send semaphore ETHLIB_OS_SEM_WAIT(tcps->txInProgress); - MSG("TX SEM\n"); + //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 + // osEventFlagsWait(tcps->eventFlags, EVTFLAG_ALL_ACKED, osFlagsNoClear, 1000); // FIXME: ez így nem lesz jó, mert, ha valamiért nem kapjuk meg az ACK-t, akkor itt ragadunk - MSG("FLAG\n"); + //MSG("FLAG\n"); // lock the mutex ----- ETHLIB_OS_MTX_LOCK(tcps->processMtx); @@ -311,21 +311,40 @@ int tcp_receive_segment_cb(const Pckt *pckt, PcktSieveLayerTag tag) { // create connection based on the listening connection ConnBlock connB; cbd client_d = tcps_create_based_on_listening(tcps, tcpProps->SourcePort, ipProps->SourceIPAddr, &connB); + TcpState *target = TCP_FETCH_STATE_FROM_CONNBLOCK(&connB); + + ETHLIB_OS_MTX_LOCK(target->processMtx); + tcp_send_segment(&connB, flags, NULL, NULL, 0); - TcpState *target = TCP_FETCH_STATE_FROM_CONNBLOCK(&connB); target->txSeqNum++; tcpw_set_seqnum_offset(target->txWin, target->txSeqNum); if ((client_d > 0) && (tcps->acceptCb != NULL)) { tcps->acceptCb(client_d); } + + ETHLIB_OS_MTX_UNLOCK(target->processMtx); } } } break; + case TCP_STATE_SYN_RCVD: /* SYN was received */ + { + bool SYNAcked = (dataSize == 0) && (tcps->txSeqNum == tcpProps->AcknowledgementNumber) && + (tcpProps->Flags & TCP_FLAG_ACK); + if (SYNAcked) { + tcps->connState = TCP_STATE_ESTAB; + osEventFlagsSet(tcps->eventFlags, EVTFLAG_ESTAB); + } + } break; + case TCP_STATE_ESTAB: /* Connection established */ + if (tcps->debug) { + MSG("data size: %d\n", dataSize); + } + // if the other end tries to close down the connection if (tcpProps->Flags & TCP_FLAG_FIN) { // send FIN, ACK @@ -333,6 +352,11 @@ int tcp_receive_segment_cb(const Pckt *pckt, PcktSieveLayerTag tag) { tcps->rxAckNum++; // advance acknowledgement number // TODO... tcp_send_segment(&tcps->connBlock, flags, NULL, NULL, 0); + // invoke stream callback to inform application, that the connection is closing + if (tcps->streamCb != NULL) { + tcps->streamCb(tcps->d); + } + // step into next state tcps->connState = TCP_STATE_LAST_ACK; } else if ((dataSize > 0) && (tcps->rxAckNum == tcpProps->SequenceNumber)) { // incoming data segment with integrity in ack/seq @@ -357,9 +381,16 @@ int tcp_receive_segment_cb(const Pckt *pckt, PcktSieveLayerTag tag) { // release segment from retransmit window tcpw_acknowledge(tcps->txWin, tcpProps->AcknowledgementNumber); + if (tcps->debug) { + MSG("occupied: %d\n", tcpw_get_occupied_size(tcps->txWin)); + } + // 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); + if (tcps->debug) { + MSG("All ACKed %d\n", tcps->d); + } } else { osEventFlagsClear(tcps->eventFlags, EVTFLAG_ALL_ACKED); } @@ -690,10 +721,15 @@ uint32_t tcp_send(cbd d, const uint8_t *data, uint32_t size) { TcpState *tcps = TCP_FETCH_STATE_FROM_CONNBLOCK(&connBlock); // can send only data if connection is ESTABLISHED - if (tcps->connState != TCP_STATE_ESTAB) { + if ((tcps->connState != TCP_STATE_ESTAB) && (tcps->connState != TCP_STATE_SYN_RCVD)) { return 0; } + // is the SYN_RCVD state wait for getting into the established state + if (tcps->connState == TCP_STATE_SYN_RCVD) { + osEventFlagsWait(tcps->eventFlags, EVTFLAG_ESTAB, osFlagsNoClear, osWaitForever); + } + // connection state is established... uint32_t sizeLeft = size; @@ -751,7 +787,11 @@ uint32_t tcp_recv(unsigned char d, uint8_t *data, uint32_t size) { // acquire TCP state TcpState *tcps = TCP_FETCH_STATE_FROM_CONNBLOCK(&connBlock); - return eth_bfifo_pop(tcps->rxFifo, data, size); + if (tcps->connState == TCP_STATE_ESTAB) { + return eth_bfifo_pop(tcps->rxFifo, data, size); + } else { + return 0; + } } void tcp_print_report(const ConnBlock *connBlock) { diff --git a/prefab/packet_parsers/dhcp.c b/prefab/packet_parsers/dhcp.c index 16b8fbf..dc9b594 100644 --- a/prefab/packet_parsers/dhcp.c +++ b/prefab/packet_parsers/dhcp.c @@ -244,15 +244,31 @@ void dhcp_request(DhcpState *s, ip4_addr reqAddr, ip4_addr dhcpServerAddr) { static void dhcp_retry_discover(struct Timer_ *timer, AlarmUserData user) { DhcpState *s = (DhcpState *)user.ptr; - if (s->state != DHCP_BOUND) { // only retransmit DISCOVER if not BOUND + if ((s->enabled) && (s->state != DHCP_BOUND)) { // only retransmit DISCOVER if not BOUND dhcp_start(s); } s->retryAlarmId = 0; // clear schedule ID } +static char * dhcp_state_names[] = { + "DHCP INIT REBOOT", + "DHCP REBOOTING", + "DHCP INIT", + "DHCP REQUESTING", + "DHCP SELECTING", + "DHCP REBINDING", + "DHCP BOUND", + "DHCP RENEWING", + "DHCP STOPPED" +}; + static void dhcp_process(DhcpState *s, DhcpProps *props, DhcpOption *opts) { ETHLIB_OS_MTX_LOCK(s->procMtx); // LOCK! +#ifdef DHCP_STATE_DEBUG + uint8_t oldState = s->state; +#endif + switch (s->state) { case DHCP_INIT: { dhcp_discover(s); // send discover message @@ -280,6 +296,7 @@ static void dhcp_process(DhcpState *s, DhcpProps *props, DhcpOption *opts) { case DHCP_REQUESTING: { const DhcpOption *opt = dhcp_get_option(opts, DHCP_OPT_MsgType); uint8_t msgType = opt->value[0]; + if (msgType == DHCPNAK) { // dhcp_discover(); // s.state = DHCP_SELECTING; @@ -325,6 +342,14 @@ static void dhcp_process(DhcpState *s, DhcpProps *props, DhcpOption *opts) { break; } +#ifdef DHCP_STATE_DEBUG + uint8_t newState = s->state; + + if (newState != oldState) { + MSG("# %s -> %s\n", dhcp_state_names[oldState], dhcp_state_names[newState]); + } +#endif + ETHLIB_OS_MTX_UNLOCK(s->procMtx); // RELEASE! } @@ -342,11 +367,19 @@ static int dhcp_resp_cb(const Pckt *pckt, PcktSieveLayerTag tag) { } void dhcp_start(DhcpState *s) { + //MSG("DHCP start!\n"); + s->enabled = true; s->state = DHCP_INIT; dhcp_process(s, NULL, NULL); } void dhcp_stop(DhcpState *s) { + //MSG("DHCP stop!\n"); + + ETHLIB_OS_MTX_LOCK(s->procMtx); // LOCK! + + s->enabled = false; + s->state = DHCP_STOPPED; if (s->renewAlarmId != 0) { // unschedule renew alarm timer_unsched(E.tmr, s->renewAlarmId); @@ -382,6 +415,12 @@ void dhcp_initiate(EthInterface *intf) { cbdt_set_tag(E.cbdt, s->desc, tag); s->intf = intf; s->renewAlarmId = 0; + s->retryAlarmId = 0; + s->enabled = false; intf->dhcp = s; } + +DhcpFSMState dhcp_get_fsm_state(const DhcpState *s) { + return s->state; +} \ No newline at end of file diff --git a/prefab/packet_parsers/dhcp.h b/prefab/packet_parsers/dhcp.h index 5f1128a..5bd461d 100644 --- a/prefab/packet_parsers/dhcp.h +++ b/prefab/packet_parsers/dhcp.h @@ -61,6 +61,7 @@ typedef struct { ETHLIB_OS_MTX_TYPE procMtx; ///< Mutex protecting the state machine uint32_t renewAlarmId; ///< IP renew alarm ID (valid if nonzero) uint32_t retryAlarmId; ///< DISCOVER retry alarm ID (valid if nonzero) + bool enabled; ///< DHCP client is enabled } DhcpState; #define DHCP_RETRY_TIMEOUT_S (3) @@ -83,4 +84,11 @@ void dhcp_start(DhcpState * s); */ void dhcp_stop(DhcpState * s); +/** + * Get DHCP FSM state. + * @param s pointer to DhcpState structure + * @return DHCP FSM state +*/ +DhcpFSMState dhcp_get_fsm_state(const DhcpState * s); + #endif //ETHERLIB_DHCP_H diff --git a/timer.c b/timer.c index a821689..84520e0 100644 --- a/timer.c +++ b/timer.c @@ -140,6 +140,9 @@ void timer_unsched(Timer *tmr, uint32_t id) { memset(alarm, 0, sizeof(AlarmAssignment)); tmr->nSched--; timer_update_nearest_alarm(tmr); + //MSG("Successful unsched of alarm #%x!\n", id); + } else { + //MSG("Could not unsched alarm #%x!\n", id); } } diff --git a/utils.c b/utils.c index 3a551e5..48d3c03 100644 --- a/utils.c +++ b/utils.c @@ -4,53 +4,54 @@ #include "utils.h" -static uint32_t crc32table[] = { /* CRC polynomial */ - 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, - 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, - 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2, - 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, - 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, - 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, - 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c, - 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, - 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, - 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, - 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106, - 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, - 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, - 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, - 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, - 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, - 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, - 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, - 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, - 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, - 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, - 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, - 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84, - 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, - 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, - 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, - 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e, - 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, - 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, - 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, - 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28, - 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, - 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, - 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, - 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, - 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, - 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, - 0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, - 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, - 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, - 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, - 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, - 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d -}; +#include -uint32_t crc32(const uint8_t * data, uint32_t size) { +static uint32_t crc32table[] = {/* CRC polynomial */ + 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, + 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, + 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2, + 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, + 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, + 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, + 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c, + 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, + 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, + 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, + 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106, + 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, + 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, + 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, + 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, + 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, + 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, + 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, + 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, + 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, + 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, + 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, + 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84, + 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, + 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, + 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, + 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e, + 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, + 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, + 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, + 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28, + 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, + 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, + 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, + 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, + 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, + 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, + 0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, + 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, + 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, + 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, + 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, + 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d}; + +uint32_t crc32(const uint8_t *data, uint32_t size) { uint32_t checksum = ~0; uint32_t i; for (i = 0; i < size; i++) { @@ -63,14 +64,14 @@ uint32_t crc32(const uint8_t * data, uint32_t size) { uint16_t chksum(const uint8_t *data, uint32_t size, int swap) { // sum fields uint32_t sum = 0; - const uint16_t *pField = (const uint16_t *) data; + const uint16_t *pField = (const uint16_t *)data; for (uint16_t i = 0; i < (size / sizeof(uint16_t)); i++) { uint16_t field = swap ? htons(pField[i]) : pField[i]; sum += field; } if (size % 2) { - sum += ((uint16_t) (data[size - 1] << 8)); + sum += ((uint16_t)(data[size - 1] << 8)); } while (sum >> 16) { @@ -80,4 +81,43 @@ uint16_t chksum(const uint8_t *data, uint32_t size, int swap) { // invert result uint16_t sum16 = sum ^ 0xFFFF; return sum16; -} \ No newline at end of file +} + +const char *trimleft(const char *str) { + while ((*str) <= ' ' && (*str != '\0')) { + str++; + } + return str; +} + +#define ATOIP_BUFLEN (20) + +ip4_addr atoip(const char *str) { + // copy to internal buffer after trimming + char buffer[ATOIP_BUFLEN]; + strncpy(buffer, trimleft(str), ATOIP_BUFLEN); + + // separate the four fields + const char *parts[4]; + parts[0] = buffer; + uint8_t partsFound = 1; + for (uint8_t i = 0; i < ATOIP_BUFLEN; i++) { + if (buffer[i] == '.') { + buffer[i] = '\0'; + parts[partsFound++] = buffer + i + 1; + } + } + + // check that all parts have been found + if (partsFound < 4) { + return 0; + } + + // convert to binary representation + uint32_t nums[4]; + for (uint8_t i = 0; i < 4; i++) { + nums[i] = atoi(parts[i]); + } + + return IPv4(nums[0], nums[1], nums[2], nums[3]); +} diff --git a/utils.h b/utils.h index 551cd14..db7ff24 100644 --- a/utils.h +++ b/utils.h @@ -11,6 +11,8 @@ #include #include +#include "prefab/packet_parsers/ipv4_types.h" + #ifndef htonl #define htonl(a) \ ((((a) >> 24) & 0x000000ff) | \ @@ -92,4 +94,18 @@ uint32_t crc32(const uint8_t * data, uint32_t size); */ uint16_t chksum(const uint8_t *data, uint32_t size, int swap); +/** + * Rip off whitespaces from the beginning of a string. + * @param str string to be trimmed + * @param pointer to the trimmed string +*/ +const char *trimleft(const char *str); + +/** + * Parse string representation of an IPv4 address and convert to binary form. + * @param str string representation of an IPv4 address + * @return IPv4 address +*/ +ip4_addr atoip(const char * str); + #endif //ETHERLIB_UTILS_H