/** * @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 #define DEBUG_CATEGORY_ETCP_API DEBUG_CATEGORY_ETCP void etcp_conn_set_ready_cbk(struct ETCP_CONN* e, etcp_cbk_fn fn, void* arg) { if (!e) return; struct etcp_cbk_entry* entry = e->ready_cbks; while (entry) { struct etcp_cbk_entry* next = entry->next; u_free(entry); entry = next; } e->ready_cbks = NULL; if (fn) etcp_conn_add_ready_cbk(e, fn, arg); } void etcp_conn_set_up_cbk(struct ETCP_CONN* e, etcp_cbk_fn fn, void* arg) { if (!e) return; struct etcp_cbk_entry* entry = e->up_cbks; while (entry) { struct etcp_cbk_entry* next = entry->next; u_free(entry); entry = next; } e->up_cbks = NULL; if (fn) etcp_conn_add_up_cbk(e, fn, arg); } void etcp_conn_set_down_cbk(struct ETCP_CONN* e, etcp_cbk_fn fn, void* arg) { if (!e) return; struct etcp_cbk_entry* entry = e->down_cbks; while (entry) { struct etcp_cbk_entry* next = entry->next; u_free(entry); entry = next; } e->down_cbks = NULL; if (fn) etcp_conn_add_down_cbk(e, fn, arg); } void etcp_set_new_conn_cbk(struct UTUN_INSTANCE* inst, etcp_cbk_fn fn, void* arg) { if (!inst) return; struct etcp_cbk_entry* entry = inst->new_conn_cbks; while (entry) { struct etcp_cbk_entry* next = entry->next; u_free(entry); entry = next; } inst->new_conn_cbks = NULL; if (fn) etcp_add_new_conn_cbk(inst, fn, arg); } 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_ready_cbk(struct ETCP_CONN* conn, etcp_cbk_fn fn, void* arg) { if (conn) etcp_cbk_add_to_chain(&conn->ready_cbks, fn, arg); } void etcp_conn_remove_ready_cbk(struct ETCP_CONN* conn, etcp_cbk_fn fn, void* arg) { if (conn) etcp_cbk_remove_from_chain(&conn->ready_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); } 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]) inst->api_bindings.callbacks[id](conn, e); else if (inst->api_bindings.callbacks[0]) inst->api_bindings.callbacks[0](conn, e); else { queue_dgram_free(e); queue_entry_free(e); } queue_resume_callback(queue); }