Reviewed-on: #5 Co-authored-by: Finn <fwaggoner@nmfpgt.de> Co-committed-by: Finn <fwaggoner@nmfpgt.de>
208 lines
6.4 KiB
C
208 lines
6.4 KiB
C
/*
|
||
* openuf - main.c
|
||
*
|
||
* Main daemon. Loop with three tasks:
|
||
* 1. Announce – UDP broadcast+multicast each 10s (discovery L2)
|
||
* 2. Inform – HTTP POST cifrado each 10s (adoption + telemetrics)
|
||
* 3. LLDP – Raw frame L2 each 30s (visual topology in UniFi)
|
||
*/
|
||
|
||
#include <stdio.h>
|
||
#include <stdlib.h>
|
||
#include <string.h>
|
||
#include <unistd.h>
|
||
#include <time.h>
|
||
#include <net/if.h>
|
||
#include <sys/ioctl.h>
|
||
#include <sys/socket.h>
|
||
#include <arpa/inet.h>
|
||
#include <netinet/in.h>
|
||
|
||
#include "config.h"
|
||
#include "state.h"
|
||
#include "ufmodel.h"
|
||
#include "announce.h"
|
||
#include "inform.h"
|
||
#include "lldp.h"
|
||
|
||
#if ENABLE_LOGGING
|
||
FILE *log_fp = NULL;
|
||
#endif
|
||
|
||
#define LLDP_INTERVAL 30 /* seconds between LLDP frames */
|
||
#define LLDP_TTL 120 /* LLDP record lifetime in seconds */
|
||
|
||
static int get_mac(const char *iface, char *out, size_t sz)
|
||
{
|
||
char path[128];
|
||
snprintf(path, sizeof(path), "/sys/class/net/%s/address", iface);
|
||
FILE *f = fopen(path, "r");
|
||
if (!f) return -1;
|
||
char buf[32] = {0};
|
||
fgets(buf, sizeof(buf), f);
|
||
fclose(f);
|
||
buf[strcspn(buf, "\r\n")] = '\0';
|
||
if (strlen(buf) < 11) return -1;
|
||
strncpy(out, buf, sz-1);
|
||
return 0;
|
||
}
|
||
|
||
static int get_ip(const char *iface, char *out, size_t sz)
|
||
{
|
||
int fd = socket(AF_INET, SOCK_DGRAM, 0);
|
||
if (fd < 0) return -1;
|
||
struct ifreq ifr;
|
||
memset(&ifr, 0, sizeof(ifr));
|
||
strncpy(ifr.ifr_name, iface, IFNAMSIZ-1);
|
||
int ret = -1;
|
||
if (ioctl(fd, SIOCGIFADDR, &ifr) == 0) {
|
||
struct sockaddr_in *sa = (struct sockaddr_in *)&ifr.ifr_addr;
|
||
strncpy(out, inet_ntoa(sa->sin_addr), sz-1);
|
||
ret = 0;
|
||
}
|
||
close(fd);
|
||
return ret;
|
||
}
|
||
|
||
int main(int argc, char *argv[])
|
||
{
|
||
for (int i = 1; i < argc-1; i++)
|
||
if (!strcmp(argv[i], "-c"))
|
||
setenv("OPENUF_CONF", argv[i+1], 1);
|
||
|
||
openuf_config_t cfg;
|
||
config_load(&cfg);
|
||
|
||
#if ENABLE_LOGGING
|
||
if (cfg.enable_logging) {
|
||
log_fp = fopen("/var/log/openuf.log", "a");
|
||
if (log_fp) {
|
||
LOG("Logging enabled");
|
||
}
|
||
}
|
||
#endif
|
||
|
||
const uf_model_t *model = ufmodel_find(cfg.ufmodel);
|
||
|
||
char mac_str[32] = "00:00:00:00:00:00";
|
||
char ip_str[64] = "192.168.1.1";
|
||
|
||
if (get_mac(cfg.lan_if, mac_str, sizeof(mac_str)) != 0)
|
||
get_mac("eth0", mac_str, sizeof(mac_str));
|
||
if (get_ip(cfg.lan_if, ip_str, sizeof(ip_str)) != 0)
|
||
get_ip("eth0", ip_str, sizeof(ip_str));
|
||
|
||
openuf_state_t state;
|
||
state_load(&state);
|
||
strncpy(state.mac, mac_str, sizeof(state.mac)-1);
|
||
strncpy(state.ip, ip_str, sizeof(state.ip)-1);
|
||
if (!state.hostname[0])
|
||
strncpy(state.hostname, model->display_name, sizeof(state.hostname)-1);
|
||
|
||
/* Log initial state */
|
||
LOG("Initial device state: adopted=%d, authkey=%.8s...", state.adopted,
|
||
state.authkey[0] ? state.authkey : "DEFAULT");
|
||
|
||
if (!state.adopted || !state.inform_url[0])
|
||
snprintf(state.inform_url, sizeof(state.inform_url),
|
||
"http://%s:%d%s", cfg.controller_ip, INFORM_PORT, INFORM_PATH);
|
||
state_save(&state);
|
||
|
||
printf("[openuf] Starting model=%-8s MAC=%s IP=%s\n",
|
||
model->model, mac_str, ip_str);
|
||
printf("[openuf] Controller: %s\n", state.inform_url);
|
||
printf("[openuf] Adopted: %s\n", state.adopted ? "yes" : "no");
|
||
printf("[openuf] LLDP available: %s\n",
|
||
lldp_available() ? "yes (lldpd)" : "no (transmit only)");
|
||
fflush(stdout);
|
||
|
||
LOG("Daemon started");
|
||
|
||
/* ── Announce socket ────────────────────────────────────────── */
|
||
announce_ctx_t ann;
|
||
if (cfg.enable_announce) {
|
||
if (announce_init(&ann, model, mac_str, ip_str) != 0) {
|
||
LOG("Failed to initialize announce service");
|
||
cfg.enable_announce = 0;
|
||
}
|
||
}
|
||
|
||
/* ── LLDP device description ───────────────────────── */
|
||
char lldp_desc[128];
|
||
snprintf(lldp_desc, sizeof(lldp_desc),
|
||
"%s %s%s (openuf)",
|
||
model->model_display, model->fw_pre, model->fw_ver);
|
||
|
||
/* ── Main loop ─────────────────────────────────────────── */
|
||
time_t start_time = time(NULL);
|
||
time_t last_announce = 0;
|
||
time_t last_inform = 0;
|
||
time_t last_lldp = 0;
|
||
|
||
printf("[openuf] Main loop started\n");
|
||
fflush(stdout);
|
||
|
||
while (1) {
|
||
time_t now = time(NULL);
|
||
|
||
/* Announce L2/UDP */
|
||
if (cfg.enable_announce &&
|
||
(now - last_announce) >= ANNOUNCE_INTERVAL) {
|
||
LOG("Sending announce");
|
||
int announce_rc = announce_send(&ann);
|
||
LOG("Announce completed with result=%d", announce_rc);
|
||
last_announce = now;
|
||
}
|
||
|
||
/* LLDP frames for each Ethernet interface */
|
||
if ((now - last_lldp) >= LLDP_INTERVAL) {
|
||
LOG("Sending LLDP frames");
|
||
for (int i = 0; i < model->port_table_len; i++) {
|
||
const char *iface = model->port_table[i].ifname;
|
||
/* Read the actual MAC of the interface if available */
|
||
char iface_mac[32];
|
||
if (get_mac(iface, iface_mac, sizeof(iface_mac)) != 0)
|
||
strncpy(iface_mac, mac_str, sizeof(iface_mac)-1);
|
||
int lldp_rc = lldp_send_frame(iface, iface_mac,
|
||
state.hostname, lldp_desc,
|
||
LLDP_TTL);
|
||
LOG("LLDP frame interface=%s mac=%s result=%d",
|
||
iface, iface_mac, lldp_rc);
|
||
}
|
||
last_lldp = now;
|
||
}
|
||
|
||
/* Inform HTTP POST */
|
||
if (cfg.enable_inform &&
|
||
(now - last_inform) >= cfg.inform_interval) {
|
||
last_inform = now;
|
||
LOG("Sending inform");
|
||
|
||
/* Update IP each cycle */
|
||
char new_ip[64] = {0};
|
||
if (get_ip(cfg.lan_if, new_ip, sizeof(new_ip)) == 0 ||
|
||
get_ip("eth0", new_ip, sizeof(new_ip)) == 0)
|
||
strncpy(state.ip, new_ip, sizeof(state.ip)-1);
|
||
|
||
long uptime = (long)(now - start_time);
|
||
char err[128] = {0};
|
||
if (inform_send(&state, model, uptime, err) != 0) {
|
||
LOG("inform error: %s", err);
|
||
}
|
||
}
|
||
|
||
sleep(1);
|
||
}
|
||
|
||
announce_close(&ann);
|
||
|
||
#if ENABLE_LOGGING
|
||
if (log_fp) {
|
||
LOG("Shutting down");
|
||
fclose(log_fp);
|
||
}
|
||
#endif
|
||
|
||
return 0;
|
||
}
|