You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
104 lines
5.1 KiB
104 lines
5.1 KiB
/** |
|
* @file etcp_api.c |
|
* @brief ETCP API — send/bind/recv dispatch |
|
*/ |
|
#include "etcp_api.h" |
|
#include "etcp.h" |
|
#include "pkt_normalizer.h" |
|
#include "utun_instance.h" |
|
#include "../lib/debug_config.h" |
|
#include "../lib/mem.h" |
|
#include <string.h> |
|
|
|
#define DEBUG_CATEGORY_ETCP_API DEBUG_CATEGORY_ETCP |
|
|
|
static void etcp_cbk_add_to_chain(struct etcp_cbk_entry** head, etcp_cbk_fn fn, void* arg) { |
|
if (!head || !fn) return; |
|
struct etcp_cbk_entry* e = u_malloc(sizeof(struct etcp_cbk_entry)); |
|
if (!e) return; |
|
e->fn = fn; e->arg = arg; e->next = *head; |
|
*head = e; |
|
} |
|
static void etcp_cbk_remove_from_chain(struct etcp_cbk_entry** head, etcp_cbk_fn fn, void* arg) { |
|
if (!head || !fn) return; |
|
struct etcp_cbk_entry** p = head; |
|
while (*p) { |
|
if ((*p)->fn == fn && (*p)->arg == arg) { |
|
struct etcp_cbk_entry* rm = *p; |
|
*p = rm->next; u_free(rm); return; |
|
} |
|
p = &(*p)->next; |
|
} |
|
} |
|
|
|
void etcp_conn_add_init_cbk(struct ETCP_CONN* conn, etcp_cbk_fn fn, void* arg) { if (conn) etcp_cbk_add_to_chain(&conn->init_cbks, fn, arg); } |
|
void etcp_conn_remove_init_cbk(struct ETCP_CONN* conn, etcp_cbk_fn fn, void* arg) { if (conn) etcp_cbk_remove_from_chain(&conn->init_cbks, fn, arg); } |
|
void etcp_conn_add_up_cbk(struct ETCP_CONN* conn, etcp_cbk_fn fn, void* arg) { if (conn) etcp_cbk_add_to_chain(&conn->up_cbks, fn, arg); } |
|
void etcp_conn_remove_up_cbk(struct ETCP_CONN* conn, etcp_cbk_fn fn, void* arg) { if (conn) etcp_cbk_remove_from_chain(&conn->up_cbks, fn, arg); } |
|
void etcp_conn_add_down_cbk(struct ETCP_CONN* conn, etcp_cbk_fn fn, void* arg) { if (conn) etcp_cbk_add_to_chain(&conn->down_cbks, fn, arg); } |
|
void etcp_conn_remove_down_cbk(struct ETCP_CONN* conn, etcp_cbk_fn fn, void* arg) { if (conn) etcp_cbk_remove_from_chain(&conn->down_cbks, fn, arg); } |
|
void etcp_add_new_conn_cbk(struct UTUN_INSTANCE* inst, etcp_cbk_fn fn, void* arg) { if (inst) etcp_cbk_add_to_chain(&inst->new_conn_cbks, fn, arg); } |
|
void etcp_remove_new_conn_cbk(struct UTUN_INSTANCE* inst, etcp_cbk_fn fn, void* arg) { if (inst) etcp_cbk_remove_from_chain(&inst->new_conn_cbks, fn, arg); } |
|
|
|
static void etcp_status_cbk_add_chain(struct etcp_status_cbk_entry** head, etcp_conn_status_fn fn, void* arg) { |
|
if (!head || !fn) return; |
|
struct etcp_status_cbk_entry* e = u_malloc(sizeof(struct etcp_status_cbk_entry)); |
|
if (!e) return; |
|
e->fn = fn; e->arg = arg; e->next = *head; |
|
*head = e; |
|
} |
|
static void etcp_status_cbk_remove_chain(struct etcp_status_cbk_entry** head, etcp_conn_status_fn fn, void* arg) { |
|
if (!head || !fn) return; |
|
struct etcp_status_cbk_entry** p = head; |
|
while (*p) { |
|
if ((*p)->fn == fn && (*p)->arg == arg) { |
|
struct etcp_status_cbk_entry* rm = *p; |
|
*p = rm->next; u_free(rm); return; |
|
} |
|
p = &(*p)->next; |
|
} |
|
} |
|
void etcp_add_conn_status_cbk(struct UTUN_INSTANCE* inst, etcp_conn_status_fn fn, void* arg) { if (inst) etcp_status_cbk_add_chain(&inst->conn_status_cbks, fn, arg); } |
|
void etcp_remove_conn_status_cbk(struct UTUN_INSTANCE* inst, etcp_conn_status_fn fn, void* arg) { if (inst) etcp_status_cbk_remove_chain(&inst->conn_status_cbks, fn, arg); } |
|
void etcp_set_routing_exchange_state(struct ETCP_CONN* conn, uint8_t new_state) { |
|
if (!conn) return; |
|
conn->routing_exchange_active = new_state; |
|
if (new_state >= 3 && conn->bgp_ready_cbk) |
|
conn->bgp_ready_cbk(conn); |
|
} |
|
|
|
int etcp_bind(struct UTUN_INSTANCE* inst, uint8_t id, etcp_recv_fn callback) { |
|
if (!inst || !callback || (unsigned)id >= ETCP_MAX_BINDINGS) return -1; |
|
inst->api_bindings.callbacks[id] = callback; |
|
return 0; |
|
} |
|
|
|
int etcp_unbind(struct UTUN_INSTANCE* inst, uint8_t id) { |
|
if (!inst || (unsigned)id >= ETCP_MAX_BINDINGS) return -1; |
|
inst->api_bindings.callbacks[id] = NULL; |
|
return 0; |
|
} |
|
|
|
int etcp_send(struct ETCP_CONN* conn, struct ll_entry* entry) { |
|
if (!conn || !entry || !conn->send_input_q) return -1; |
|
return queue_data_put(conn->send_input_q, entry); |
|
} |
|
|
|
void etcp_int_recv(struct ll_queue* queue, void* arg) { |
|
struct ETCP_CONN* conn = (struct ETCP_CONN*)arg; |
|
if (!queue || !conn) return; |
|
struct ll_entry* e = queue_data_get(queue); |
|
if (!e) { queue_resume_callback(queue); return; } |
|
if (!e->dgram || e->len == 0) { queue_dgram_free(e); queue_entry_free(e); queue_resume_callback(queue); return; } |
|
uint8_t id = e->dgram[0]; |
|
struct UTUN_INSTANCE* inst = conn->instance; |
|
if (!inst) { queue_dgram_free(e); queue_entry_free(e); queue_resume_callback(queue); return; } |
|
if (inst->api_bindings.callbacks[id]) { |
|
DEBUG_TRACE(DEBUG_CATEGORY_DEBUG, "dispatch id=0x%02x conn=%s len=%zu", id, conn->log_name, e->len); |
|
inst->api_bindings.callbacks[id](conn, e); |
|
} else if (inst->api_bindings.callbacks[0]) { |
|
DEBUG_TRACE(DEBUG_CATEGORY_DEBUG, "dispatch id=0x%02x (fallback) conn=%s len=%zu", id, conn->log_name, e->len); |
|
inst->api_bindings.callbacks[0](conn, e); |
|
} else { DEBUG_DEBUG(DEBUG_CATEGORY_DEBUG, "dispatch id=0x%02x NO CB conn=%s len=%zu — DROPPED", id, conn->log_name, e->len); queue_dgram_free(e); queue_entry_free(e); } |
|
queue_resume_callback(queue); |
|
}
|
|
|