- add tag to CBD

- DHCP state separated
- link change handler added
- timer mutex added
This commit is contained in:
Wiesner András 2023-10-15 12:17:37 +02:00
parent ab8d45932f
commit e4d27454cd
9 changed files with 224 additions and 57 deletions

View File

@ -50,6 +50,26 @@ bool cbdt_get_connection_block(CbdTable *cbdt, cbd d, ConnBlock *connBlock) {
return true;
}
bool cbdt_set_tag(CbdTable *cbdt, cbd d, PcktSieveLayerTag tag) {
ConnBlock connBlock;
if (cbdt_get_connection_block(cbdt, d, &connBlock)) {
connBlock.sieveLayer->tag = tag;
return true;
} else {
return false;
}
}
bool cbdt_get_tag(CbdTable * cbdt, cbd d, PcktSieveLayerTag * tag) {
ConnBlock connBlock;
if (cbdt_get_connection_block(cbdt, d, &connBlock)) {
*tag = connBlock.sieveLayer->tag;
return true;
} else {
return false;
}
}
void cbdt_report(const CbdTable *cbdt) {
INFO("CBDT listing (%d/%d):\n---------------\n\n", cbdt->level, cbdt->maxEntries);

View File

@ -52,6 +52,24 @@ void cbdt_release(CbdTable * cbdt, cbd d);
*/
bool cbdt_get_connection_block(CbdTable * cbdt, cbd d, ConnBlock * connBlock);
/**
* Set connection block sieve tag.
* @param cbdt pointer to CBDT
* @param d CBD value
* @param tag tag getting stored
* @return operation successful (d was valid)
*/
bool cbdt_set_tag(CbdTable * cbdt, cbd d, PcktSieveLayerTag tag);
/**
* Retrieve connection block sieve tag.
* @param cbdt pointer to CBDT
* @param d CBD value
* @param tag pointer to area where tag is written
* @return operation successful (d was valid)
*/
bool cbdt_get_tag(CbdTable * cbdt, cbd d, PcktSieveLayerTag * tag);
/**
* Print report on connection block descriptors.
* @param cbdt pointer to CBD table

View File

@ -18,10 +18,17 @@ static int ethintf_llrxnotify(EthIODef * io) {
return 0;
}
static int ethinf_lllinkchg(EthIODef * io, int ls) {
ethinf_set_link_state((EthInterface *) io->tag, ls);
MSG("Link state: %d\n", ls);
return 0;
}
static void ethintf_register(EthInterface * intf) {
intf->ioDef->tag = intf;
intf->ioDef->llRxStore = ethintf_llrecv;
intf->ioDef->llRxNotify = ethintf_llrxnotify;
intf->ioDef->llLinkChg = ethinf_lllinkchg;
}
// interface processing thread
@ -49,6 +56,12 @@ EthInterface *ethintf_new(EthIODef * io) {
ethIntf->capabilities = 0;
ethIntf->dhcp = NULL;
memset(&ethIntf->evtCbTable, 0, sizeof(EthIntfEventCbTable));
ethIntf->linkState = false;
return ethIntf;
}
@ -87,3 +100,25 @@ void ethinf_notify(EthInterface *intf) {
void ethinf_set_capabilities(EthInterface *intf, uint32_t cap) {
intf->capabilities = cap;
}
void ethinf_set_event_callback(EthInterface *intf, EthIntfEvIndex idx, EthIntfEvtCb cb) {
((EthIntfEvtCb *)((&(intf->evtCbTable))))[idx] = cb;
}
void ethinf_trigger_event(EthInterface *intf, EthIntfEvIndex idx) {
EthIntfEvtCb cb = ((EthIntfEvtCb *)((&(intf->evtCbTable))))[idx];
if (cb != NULL) {
cb(intf);
}
}
void ethinf_set_link_state(EthInterface *intf, bool ls) {
if (intf->linkState != ls) { // trigger event only if state has actually changed
intf->linkState = ls;
ethinf_trigger_event(intf, ETH_EVT_LINK_CHANGE);
}
}
bool ethinf_get_link_state(EthInterface *intf) {
return intf->linkState;
}

View File

@ -1,6 +1,8 @@
#ifndef ETHERLIB_ETH_INTERFACE_H
#define ETHERLIB_ETH_INTERFACE_H
#include <stdbool.h>
#include "packet_sieve.h"
#include "prefab/packet_parsers/packet_parsers.h"
#include "prefab/packet_parsers/ipv4_types.h"
@ -9,6 +11,7 @@
#include "msg_queue.h"
#include "prefab/conn_blocks/ipv4/ip_assembler.h"
#include "etherlib_options.h"
#include "etherlib/prefab/packet_parsers/dhcp.h"
/**
* Ethernet interface low level definition.
@ -38,6 +41,23 @@ typedef enum {
ETHINF_CAP_ALL_RX_TX_CHECKSUM_OFFLOADS = 0b11111,
} EthIntfCap;
struct EthInterface_;
typedef void (*EthIntfEvtCb)(struct EthInterface_ * intf);
typedef enum {
ETH_EVT_LINK_CHANGE = 0,
ETH_EVT_IP_CHANGE = 1
} EthIntfEvIndex;
/**
* Ethernet interface event callback table
*/
typedef struct {
EthIntfEvtCb linkChange; ///< Link change event
EthIntfEvtCb ipChange; ///< IP-address changed
} EthIntfEventCbTable;
/**
* Ethernet interface representation.
*/
@ -46,6 +66,7 @@ typedef struct EthInterface_ {
EthIODef * ioDef; ///< Low-level IO definitions
EthernetAddress mac; ///< Ethernet address
uint32_t capabilities; ///< Ethernet interface capabilities
DhcpState * dhcp; ///< DHCP control block (allocated only, if DHCP operation is initiated)
ip4_addr ip; ///< IP address
ip4_addr router; ///< Router IP address
ip4_addr netmask; ///< Subnet mask
@ -56,6 +77,8 @@ typedef struct EthInterface_ {
MsgQueue * rxQ; ///< Receive queue
ETHLIB_OS_SEM_TYPE rxSem; ///< Receive queue semaphore
IPv4Assembler * ipra; ///< IPv4 reassembler
EthIntfEventCbTable evtCbTable; ///< Event callback table
bool linkState; ///< Interface link state
} EthInterface;
/**
@ -90,4 +113,32 @@ void ethinf_transmit(EthInterface *intf, const RawPckt *rawPckt);
*/
void ethinf_set_capabilities(EthInterface *intf, uint32_t cap);
/**
* Set Ethernet event callback.
* @param intf pointer to Ethernet interface
* @param idx index of Ethernet event
* @param cb callback function pointer
*/
void ethinf_set_event_callback(EthInterface * intf, EthIntfEvIndex idx, EthIntfEvtCb cb);
/**
* Trigger Ethernet event.
* @param intf pointer to Ethernet interface
* @param idx index of Ethernet interface event
*/
void ethinf_trigger_event(EthInterface * intf, EthIntfEvIndex idx);
/**
* Set link state.
* @param intf pointer to Ethernet interface
* @param ls link state
*/
void ethinf_set_link_state(EthInterface * intf, bool ls);
/**
* Get link state.
* @param intf pointer to Ethernet interface
*/
bool ethinf_get_link_state(EthInterface * intf);
#endif //ETHERLIB_ETH_INTERFACE_H

View File

@ -10,15 +10,6 @@
#include "../conn_blocks/udp_connblock.h"
#include "../../global_state.h"
static struct {
DhcpState state;
void *buf;
cbd desc;
uint32_t tranId;
EthInterface *intf;
ETHLIB_OS_MTX_TYPE procMtx;
} s;
static const uint8_t DHCP_MAGIC_COOKIE[] = {99, 130, 83, 99};
#define SNAME_LEN (64)
@ -124,9 +115,9 @@ static const DhcpOption *dhcp_get_option(const DhcpOption *opts, DhcpOptionId id
return NULL;
}
static void dhcp_send(const DhcpProps *props, const DhcpOption *opts) {
static void dhcp_send(DhcpState * s, const DhcpProps *props, const DhcpOption *opts) {
// construct body
uint8_t *buf = (uint8_t *) s.buf;
uint8_t *buf = (uint8_t *) s->buf;
memset(buf, 0, DHCP_MIN_PACKET_SIZE);
FILL_BYTE_ADVANCE(buf, &(props->op));
FILL_BYTE_ADVANCE(buf, &(props->htype));
@ -155,7 +146,7 @@ static void dhcp_send(const DhcpProps *props, const DhcpOption *opts) {
// dhcp_option_insert_end(&buf);
// send packet
udp_sendto(s.desc, s.buf, DHCP_MIN_PACKET_SIZE, IPv4_ANY_ADDR, DHCP_SERVER_PORT);
udp_sendto(s->desc, s->buf, DHCP_MIN_PACKET_SIZE, IPv4_ANY_ADDR, DHCP_SERVER_PORT);
}
static void dhcp_parse(const uint8_t *buf, DhcpProps *props, DhcpOption **opts) {
@ -196,15 +187,15 @@ static void dhcp_parse(const uint8_t *buf, DhcpProps *props, DhcpOption **opts)
#define IPv4_ADDR_TO_BE_BYTES(addr) ((addr) & 0xFF), (((addr) >> 8) & 0xFF), (((addr) >> 16) & 0xFF), (((addr) >> 24) & 0xFF),
#define HWADDR_TO_BE_BYTES(hwa) (hwa)[0], (hwa)[1], (hwa)[2], (hwa)[3], (hwa)[4], (hwa)[5],
static void dhcp_discover() {
s.tranId = rand();
static void dhcp_discover(DhcpState * s) {
s->tranId = rand();
DhcpProps props = {0};
props.op = DHCP_BOOTREQUEST;
props.htype = DHCP_HW_TYPE_ETHERNET;
props.hlen = 6;
props.hops = 0;
props.xid = s.tranId;
props.xid = s->tranId;
props.secs = 0;
props.flags = 0;
props.ciaddr = 0;
@ -212,24 +203,24 @@ static void dhcp_discover() {
props.siaddr = 0;
props.giaddr = 0;
memcpy(props.chaddr, s.intf->mac, ETH_HW_ADDR_LEN);
memcpy(props.chaddr, s->intf->mac, ETH_HW_ADDR_LEN);
DhcpOption optEnd = {DHCP_OPT_End, 0, NULL};
uint16_t maxSize = 1500; // TODO...
DhcpOption maxMsgSize = {DHCP_OPT_MaxMsgSize, 2, &optEnd, {UINT16_TO_BE_BYTES(maxSize)}};
DhcpOption msgType = {DHCP_OPT_MsgType, 1, &maxMsgSize, {DHCPDISCOVER}};
dhcp_send(&props, &msgType);
dhcp_send(s, &props, &msgType);
}
void dhcp_request(ip4_addr reqAddr, ip4_addr dhcpServerAddr) {
void dhcp_request(DhcpState * s, ip4_addr reqAddr, ip4_addr dhcpServerAddr) {
DhcpProps props = {0};
props.op = DHCP_BOOTREQUEST;
props.htype = DHCP_HW_TYPE_ETHERNET;
props.hlen = 6;
props.hops = 0;
props.xid = s.tranId;
props.xid = s->tranId;
props.secs = 0;
props.flags = 0;
props.ciaddr = 0;
@ -237,7 +228,7 @@ void dhcp_request(ip4_addr reqAddr, ip4_addr dhcpServerAddr) {
props.siaddr = 0;
props.giaddr = 0;
memcpy(props.chaddr, s.intf->mac, ETH_HW_ADDR_LEN);
memcpy(props.chaddr, s->intf->mac, ETH_HW_ADDR_LEN);
uint16_t maxSize = 1500; // TODO...
@ -245,20 +236,20 @@ void dhcp_request(ip4_addr reqAddr, ip4_addr dhcpServerAddr) {
DhcpOption paramReq = {DHCP_OPT_ParamReqList, 4, &optEnd, {1, 3, 6, 51}}; // TODO...
DhcpOption reqIp = {DHCP_OPT_RequestedIpAddress, 4, &paramReq, {IPv4_ADDR_TO_BE_BYTES(reqAddr)}};
DhcpOption serverIp = {DHCP_OPT_ServerId, 4, &reqIp, {IPv4_ADDR_TO_BE_BYTES(dhcpServerAddr)}};
DhcpOption clId = {DHCP_OPT_ClientIdentifier, 7, &serverIp, {DHCP_HW_TYPE_ETHERNET, HWADDR_TO_BE_BYTES(s.intf->mac)}};
DhcpOption clId = {DHCP_OPT_ClientIdentifier, 7, &serverIp, {DHCP_HW_TYPE_ETHERNET, HWADDR_TO_BE_BYTES(s->intf->mac)}};
DhcpOption maxMsgSize = {DHCP_OPT_MaxMsgSize, 2, &clId, {UINT16_TO_BE_BYTES(maxSize)}};
DhcpOption msgType = {DHCP_OPT_MsgType, 1, &maxMsgSize, {DHCPREQUEST}};
dhcp_send(&props, &msgType);
dhcp_send(s, &props, &msgType);
}
static void dhcp_process(DhcpProps *props, DhcpOption *opts) {
ETHLIB_OS_MTX_LOCK(&s.procMtx); // LOCK!
static void dhcp_process(DhcpState * s, DhcpProps *props, DhcpOption *opts) {
ETHLIB_OS_MTX_LOCK(&s->procMtx); // LOCK!
switch (s.state) {
switch (s->state) {
case DHCP_INIT:
dhcp_discover(); // send discover message
s.state = DHCP_SELECTING;
dhcp_discover(s); // send discover message
s->state = DHCP_SELECTING;
break;
case DHCP_SELECTING: {
const DhcpOption *msgType = dhcp_get_option(opts, DHCP_OPT_MsgType);
@ -268,10 +259,10 @@ static void dhcp_process(DhcpProps *props, DhcpOption *opts) {
ip4_addr serverAddr;
FETCH_DWORD(&serverAddr, serverIdentifier->value);
ip4_addr addrOffer = props->yiaddr;
dhcp_request(addrOffer, serverAddr);
dhcp_request(s, addrOffer, serverAddr);
}
s.state = DHCP_REQUESTING;
s->state = DHCP_REQUESTING;
}
}
break;
@ -282,16 +273,16 @@ static void dhcp_process(DhcpProps *props, DhcpOption *opts) {
//dhcp_discover();
//s.state = DHCP_SELECTING;
} else if (msgType == DHCPACK) {
s.intf->ip = props->yiaddr; // fetch ip address
s->intf->ip = props->yiaddr; // fetch ip address
opt = dhcp_get_option(opts, DHCP_OPT_Router); // get gateway/router address
FETCH_DWORD(&(s.intf->router), opt->value);
FETCH_DWORD(&(s->intf->router), opt->value);
opt = dhcp_get_option(opts, DHCP_OPT_SubnetMask); // get subnet mask
FETCH_DWORD(&(s.intf->netmask), opt->value);
FETCH_DWORD(&(s->intf->netmask), opt->value);
opt = dhcp_get_option(opts, DHCP_OPT_DomainNameServer); // get DNS
FETCH_DWORD(&(s.intf->dns), opt->value);
FETCH_DWORD(&(s->intf->dns), opt->value);
opt = dhcp_get_option(opts, DHCP_OPT_IPAddrLeaseTime); // fetch Lease Time
uint32_t dhcpLeaseTime_s;
@ -302,17 +293,20 @@ static void dhcp_process(DhcpProps *props, DhcpOption *opts) {
MSG("DHCP done!\n");
MSG("IP: ");
PRINT_IPv4(s.intf->ip);
PRINT_IPv4(s->intf->ip);
MSG("\nRouter: ");
PRINT_IPv4(s.intf->router);
PRINT_IPv4(s->intf->router);
MSG("\nNetmask: ");
PRINT_IPv4(s.intf->netmask);
PRINT_IPv4(s->intf->netmask);
MSG("\nDNS: ");
PRINT_IPv4(s.intf->dns);
PRINT_IPv4(s->intf->dns);
MSG("\nLease time: %u s\n", dhcpLeaseTime_s);
MSG("\n");
s.state = DHCP_BOUND;
s->state = DHCP_BOUND;
// call event callback
ethinf_trigger_event(s->intf, ETH_EVT_IP_CHANGE);
}
}
break;
@ -320,7 +314,7 @@ static void dhcp_process(DhcpProps *props, DhcpOption *opts) {
break;
}
ETHLIB_OS_MTX_UNLOCK(&s.procMtx); // RELEASE!
ETHLIB_OS_MTX_UNLOCK(&s->procMtx); // RELEASE!
}
static int dhcp_resp_cb(const Pckt *pckt, PcktSieveLayerTag tag) {
@ -328,22 +322,30 @@ static int dhcp_resp_cb(const Pckt *pckt, PcktSieveLayerTag tag) {
DhcpOption *opts = NULL;
dhcp_parse(pckt->payload, &props, &opts);
dhcp_process(&props, opts);
DhcpState * s = (DhcpState *) tag.p;
dhcp_process(s, &props, opts);
dhcp_free_opt_chain(opts);
return 0;
}
void dhcp_start() {
s.state = DHCP_INIT;
dhcp_process(NULL, NULL);
void dhcp_start(DhcpState * s) {
s->state = DHCP_INIT;
dhcp_process(s, NULL, NULL);
}
void dhcp_initiate(EthInterface *intf) {
ETHLIB_OS_MTX_CREATE(&s.procMtx);
s.state = DHCP_INIT;
s.buf = dynmem_alloc(DHCP_MIN_PACKET_SIZE);
s.desc = udp_new_connblock(intf, IPv4_ANY_ADDR, DHCP_CLIENT_PORT, dhcp_resp_cb);
s.intf = intf;
DhcpState * s = (DhcpState *) dynmem_alloc(sizeof(DhcpState));
ETHLIB_OS_MTX_CREATE(&s->procMtx);
s->state = DHCP_INIT;
s->buf = dynmem_alloc(DHCP_MIN_PACKET_SIZE);
s->desc = udp_new_connblock(intf, IPv4_ANY_ADDR, DHCP_CLIENT_PORT, dhcp_resp_cb);
PcktSieveLayerTag tag; // store pointer to DHCP state into UDP connection block tag
tag.p = (void *)s;
cbdt_set_tag(E.cbdt, s->desc, tag);
s->intf = intf;
intf->dhcp = s;
}

View File

@ -2,7 +2,9 @@
#define ETHERLIB_DHCP_H
#include <stdint.h>
#include "../../eth_interface.h"
//#include "../../eth_interface.h"
#include "etherlib/cbd_table.h"
#include "etherlib_options.h"
typedef struct {
uint8_t op; ///< Operations
@ -33,7 +35,7 @@ typedef enum {
DHCP_REBINDING,
DHCP_BOUND,
DHCP_RENEWING
} DhcpState;
} DhcpFSMState;
/**
* DHCP id codes.
@ -47,15 +49,27 @@ typedef enum {
#define DHCP_CLIENT_PORT (68)
#define DHCP_SERVER_PORT (67)
struct EthInterface_;
typedef struct {
DhcpFSMState state; ///< DHCP state machine state
void *buf; ///< Pointer to packet an allocated packet buffer
cbd desc; ///< UDP connection block descriptor
uint32_t tranId; ///< Transaction ID
struct EthInterface_ *intf; ///< Pointer to corresponding Ethernet interface
ETHLIB_OS_MTX_TYPE procMtx; ///< Mutex protecting the state machine
} DhcpState;
/**
* Initiate DHCP on interface
* @param intf interface
*/
void dhcp_initiate(EthInterface * intf);
void dhcp_initiate(struct EthInterface_ * intf);
/**
*
* Start DHCP operation.
* @param s pointer to DhcpState structure
*/
void dhcp_start();
void dhcp_start(DhcpState * s);
#endif //ETHERLIB_DHCP_H

30
timer.c
View File

@ -26,6 +26,7 @@ Timer *timer_new(uint32_t maxSched) {
Timer * tmr = (Timer *) dynmem_alloc(sizeof(Timer) + maxSched * sizeof(AlarmAssignment));
ASSERT_NULL(tmr);
ETHLIB_OS_MTX_CREATE(&tmr->tabMtx);
tmr->maxSched = maxSched;
tmr->nSched = 0;
tmr->nextAlarm = NULL;
@ -87,6 +88,8 @@ uint32_t timer_sched(Timer * tmr, const TimePoint * t, TimerAlarmCb cb, AlarmUse
return TIMER_SCHED_FAILED;
}
ETHLIB_OS_MTX_LOCK(&(tmr->tabMtx));
// if we can schedule get the first unused block
AlarmAssignment * slot = timer_get_alarm_by_id(tmr, 0);
@ -106,6 +109,10 @@ uint32_t timer_sched(Timer * tmr, const TimePoint * t, TimerAlarmCb cb, AlarmUse
tmr->nextAlarm = slot;
}
timer_report(tmr);
ETHLIB_OS_MTX_UNLOCK(&(tmr->tabMtx));
return slot->id;
}
@ -116,11 +123,15 @@ uint32_t timer_sched_rel(Timer * tmr, int64_t us, TimerAlarmCb cb, AlarmUserData
}
void timer_unsched(Timer * tmr, uint32_t id) {
ETHLIB_OS_MTX_LOCK(&(tmr->tabMtx));
AlarmAssignment * alarm = timer_get_alarm_by_id(tmr, id);
if (alarm != NULL) {
memset(alarm, 0, sizeof(AlarmAssignment));
tmr->nSched--;
}
ETHLIB_OS_MTX_UNLOCK(&(tmr->tabMtx));
}
void timer_set_time(Timer *tmr, const TimePoint *t) {
@ -146,11 +157,15 @@ void timer_tick(Timer * tmr, int64_t us) {
if ((tmr->nSched > 0) && (tmr->nextAlarm != NULL)) {
int64_t t_alarm = time_to_us(&(tmr->nextAlarm->time));
while (((t_alarm - t_us) <= 0) && (tmr->nSched > 0)) {
// invoke callback
if (tmr->nextAlarm->cb != NULL) {
tmr->nextAlarm->cb(tmr, tmr->nextAlarm->params);
if (ETHLIB_OS_MTX_LOCK(&(tmr->tabMtx)) != 0) {
return; // break from the loop, since we cannot lock the mutex
}
timer_report(tmr);
// fetch alarm (obtain a COPY)
AlarmAssignment alarm = *(tmr->nextAlarm);
// clear alarm descriptor
memset(tmr->nextAlarm, 0, sizeof(AlarmAssignment));
@ -159,11 +174,20 @@ void timer_tick(Timer * tmr, int64_t us) {
// update nearest alarm
timer_update_nearest_alarm(tmr);
ETHLIB_OS_MTX_UNLOCK(&(tmr->tabMtx));
// invoke callback
if (alarm.cb != NULL) {
alarm.cb(tmr, alarm.params);
}
if (tmr->nextAlarm != NULL) {
t_alarm = time_to_us(&(tmr->nextAlarm->time));
}
}
}
}
void timer_report(const Timer * tmr) {

View File

@ -4,6 +4,8 @@
#include <stdint.h>
#include <stdbool.h>
#include <etherlib_options.h>
/**
* A single point in time
*/
@ -61,6 +63,7 @@ typedef struct {
* Timer class
*/
typedef struct Timer_ {
ETHLIB_OS_MTX_TYPE tabMtx; ///< Mutex protecting the scheduling table
TimePoint time; ///< Absolute time
AlarmAssignment * nextAlarm; ///< Nearest alarm
uint32_t maxSched; ///< Maximum number of scheduled alarms

View File

@ -39,7 +39,7 @@
#define IPv4(a,b,c,d) ((a) | (b << 8) | (c << 16) | (d << 24))
#define PRINT_IPv4(ip) MSG("%u.%u.%u.%u", (ip & 0xFF), ((ip >> 8) & 0xFF), ((ip >> 16) & 0xFF), ((ip >> 24) & 0xFF))
#define PRINT_HWADDR(hwaddr) MSG("%02x:%02x:%02x:%02x:%02x:%02x", (hwaddr)[0], (hwaddr)[1], (hwaddr)[2], (hwaddr)[3], (hwaddr)[4], (hwaddr)[5]);
#define PRINT_HWADDR(hwaddr) MSG("%02x:%02x:%02x:%02x:%02x:%02x", (hwaddr)[0], (hwaddr)[1], (hwaddr)[2], (hwaddr)[3], (hwaddr)[4], (hwaddr)[5])
#define ASSERT_BAD_ALIGN(p) if ((size_t)(p) & 0b11) ERROR("Bad memory alignment in function '%s' in file '%s' on line %d!\n", __func__, __FILE__, __LINE__)
#define ASSERT_NULL(p) if ((p) == NULL) ERROR("NULL in function '%s' in file '%s' on line %d!\n", __func__, __FILE__, __LINE__)