125 lines
3.5 KiB
C
125 lines
3.5 KiB
C
//
|
|
// Created by epagris on 2022.10.20..
|
|
//
|
|
|
|
#include "eth_interface.h"
|
|
#include "dynmem.h"
|
|
#include "utils.h"
|
|
#include "etherlib_options.h"
|
|
#include "etherlib/prefab/conn_blocks/ethernet_connblock.h"
|
|
|
|
static int ethintf_llrecv(EthIODef * io, const RawPckt * pckt) {
|
|
ethinf_receive((EthInterface *) io->tag, pckt);
|
|
return 0;
|
|
}
|
|
|
|
static int ethintf_llrxnotify(EthIODef * io) {
|
|
ethinf_notify((EthInterface *) io->tag);
|
|
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
|
|
static void * ethinf_proc_thread(void * param);
|
|
|
|
EthInterface *ethintf_new(EthIODef * io) {
|
|
EthInterface * ethIntf = (EthInterface *)dynmem_alloc(sizeof(EthInterface));
|
|
ASSERT_NULL(ethIntf);
|
|
memset(ðIntf->sieve.layer0, 0, sizeof(PcktSieveLayer));
|
|
ethIntf->sieve.intf = ethIntf;
|
|
ethIntf->sieve.layer0.connBReportFn = ethernet_print_report;
|
|
ethIntf->ioDef = io;
|
|
ethIntf->ip = 0;
|
|
ethIntf->arpc = arpc_new(ethIntf, ETHLIB_ARPCACHE_SIZE);
|
|
ASSERT_NULL(ethIntf->arpc);
|
|
ethintf_register(ethIntf);
|
|
|
|
ethIntf->txQ = mq_create(ETHLIB_DEF_MQ_SIZE);
|
|
ethIntf->rxQ = mq_create(ETHLIB_DEF_MQ_SIZE);
|
|
ETHLIB_OS_SEM_CREATE(ðIntf->rxSem, ETHLIB_DEF_MQ_SIZE);
|
|
ETHLIB_OS_THREAD_DEFINE(ethinf_proc_thread, ethrx, osPriorityHigh, 4096, ethIntf);
|
|
ETHLIB_OS_THREAD_CREATE(ethrx, ethIntf);
|
|
|
|
ethIntf->ipra = ipra_new();
|
|
|
|
ethIntf->capabilities = 0;
|
|
|
|
ethIntf->dhcp = NULL;
|
|
|
|
memset(ðIntf->evtCbTable, 0, sizeof(EthIntfEventCbTable));
|
|
|
|
ethIntf->linkState = false;
|
|
|
|
return ethIntf;
|
|
}
|
|
|
|
static void * ethinf_proc_thread(void * param) {
|
|
EthInterface * intf = (EthInterface *) param;
|
|
while (true) {
|
|
ETHLIB_OS_SEM_WAIT(&intf->rxSem);
|
|
intf->ioDef->llRxRead(intf->ioDef, intf->rxQ); // read packets
|
|
while (mq_avail(intf->rxQ) > 0) {
|
|
RawPckt rawPckt = mq_top(intf->rxQ);
|
|
mq_pop(intf->rxQ);
|
|
packsieve_input(&intf->sieve, &rawPckt);
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
void ethinf_receive(EthInterface *intf, const RawPckt *rawPckt) {
|
|
bool pushOK = mq_push(intf->rxQ, rawPckt);
|
|
if (!pushOK) {
|
|
dynmem_free(rawPckt->payload);
|
|
ERROR("Input queue full, packet dropped!\n");
|
|
}
|
|
}
|
|
|
|
void ethinf_transmit(EthInterface *intf, const RawPckt *rawPckt) {
|
|
mq_push(intf->txQ, rawPckt); // push packet onto the message queue
|
|
|
|
intf->ioDef->llTxTrigger(intf->ioDef, intf->txQ);
|
|
}
|
|
|
|
void ethinf_notify(EthInterface *intf) {
|
|
ETHLIB_OS_SEM_POST(&intf->rxSem);
|
|
}
|
|
|
|
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;
|
|
}
|