13d36ee2eSJeremy Kerr /* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later */ 23d36ee2eSJeremy Kerr 38e31cfd1SJeremy Kerr #define _GNU_SOURCE 48e31cfd1SJeremy Kerr 5d4103f8fSAndrew Jeffery #include "config.h" 6cad47301SAndrew Jeffery #include "utils/mctp-capture.h" 7d4103f8fSAndrew Jeffery 88e31cfd1SJeremy Kerr #include <assert.h> 98e31cfd1SJeremy Kerr #include <err.h> 106896d41eSAndrew Jeffery #include <errno.h> 118e31cfd1SJeremy Kerr #include <getopt.h> 12b93b6112SAndrew Jeffery #include <limits.h> 138e31cfd1SJeremy Kerr #include <poll.h> 14490e3873SAndrew Jeffery #include <signal.h> 1504b81fc7SAndrew Jeffery #include <stdbool.h> 168e31cfd1SJeremy Kerr #include <stdio.h> 178e31cfd1SJeremy Kerr #include <stdlib.h> 188e31cfd1SJeremy Kerr #include <string.h> 198e31cfd1SJeremy Kerr #include <unistd.h> 208e31cfd1SJeremy Kerr 21490e3873SAndrew Jeffery #include <sys/signalfd.h> 228e31cfd1SJeremy Kerr #include <sys/socket.h> 238e31cfd1SJeremy Kerr #include <sys/un.h> 248e31cfd1SJeremy Kerr 25d4103f8fSAndrew Jeffery #define SD_LISTEN_FDS_START 3 26d4103f8fSAndrew Jeffery 278e31cfd1SJeremy Kerr #include "libmctp.h" 288e31cfd1SJeremy Kerr #include "libmctp-serial.h" 298e31cfd1SJeremy Kerr #include "libmctp-astlpc.h" 308e31cfd1SJeremy Kerr 318e31cfd1SJeremy Kerr #define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0])) 3234b9b3d8SJeremy Kerr #define __unused __attribute__((unused)) 338e31cfd1SJeremy Kerr 34d4103f8fSAndrew Jeffery #if HAVE_SYSTEMD_SD_DAEMON_H 35d4103f8fSAndrew Jeffery #include <systemd/sd-daemon.h> 36d4103f8fSAndrew Jeffery #else 37d4103f8fSAndrew Jeffery static inline int sd_listen_fds(int i __unused) 38d4103f8fSAndrew Jeffery { 39d4103f8fSAndrew Jeffery return -1; 40d4103f8fSAndrew Jeffery } 41d4103f8fSAndrew Jeffery #endif 42d4103f8fSAndrew Jeffery 438e31cfd1SJeremy Kerr static const mctp_eid_t local_eid_default = 8; 448e31cfd1SJeremy Kerr static char sockname[] = "\0mctp-mux"; 458e31cfd1SJeremy Kerr 468e31cfd1SJeremy Kerr struct binding { 478e31cfd1SJeremy Kerr const char *name; 488e31cfd1SJeremy Kerr int (*init)(struct mctp *mctp, struct binding *binding, 498e31cfd1SJeremy Kerr mctp_eid_t eid, int n_params, 508e31cfd1SJeremy Kerr char * const * params); 51*edebe169SAndrew Jeffery void (*destroy)(struct mctp *mctp, struct binding *binding); 528e31cfd1SJeremy Kerr int (*get_fd)(struct binding *binding); 538e31cfd1SJeremy Kerr int (*process)(struct binding *binding); 548e31cfd1SJeremy Kerr void *data; 558e31cfd1SJeremy Kerr }; 568e31cfd1SJeremy Kerr 578e31cfd1SJeremy Kerr struct client { 588e31cfd1SJeremy Kerr bool active; 598e31cfd1SJeremy Kerr int sock; 608e31cfd1SJeremy Kerr uint8_t type; 618e31cfd1SJeremy Kerr }; 628e31cfd1SJeremy Kerr 638e31cfd1SJeremy Kerr struct ctx { 648e31cfd1SJeremy Kerr struct mctp *mctp; 658e31cfd1SJeremy Kerr struct binding *binding; 668e31cfd1SJeremy Kerr bool verbose; 678e31cfd1SJeremy Kerr int local_eid; 68f49b2ac8SJeremy Kerr void *buf; 69f49b2ac8SJeremy Kerr size_t buf_size; 708e31cfd1SJeremy Kerr 718e31cfd1SJeremy Kerr int sock; 728e31cfd1SJeremy Kerr struct pollfd *pollfds; 738e31cfd1SJeremy Kerr 748e31cfd1SJeremy Kerr struct client *clients; 758e31cfd1SJeremy Kerr int n_clients; 76cad47301SAndrew Jeffery 77cad47301SAndrew Jeffery struct { 78cad47301SAndrew Jeffery struct capture binding; 79cad47301SAndrew Jeffery struct capture socket; 80cad47301SAndrew Jeffery } pcap; 818e31cfd1SJeremy Kerr }; 828e31cfd1SJeremy Kerr 838e31cfd1SJeremy Kerr static void tx_message(struct ctx *ctx, mctp_eid_t eid, void *msg, size_t len) 848e31cfd1SJeremy Kerr { 8506735055SAndrew Jeffery int rc; 8606735055SAndrew Jeffery 8706735055SAndrew Jeffery rc = mctp_message_tx(ctx->mctp, eid, msg, len); 8806735055SAndrew Jeffery if (rc) 8906735055SAndrew Jeffery warnx("Failed to send message: %d", rc); 908e31cfd1SJeremy Kerr } 918e31cfd1SJeremy Kerr 928e31cfd1SJeremy Kerr static void client_remove_inactive(struct ctx *ctx) 938e31cfd1SJeremy Kerr { 948e31cfd1SJeremy Kerr int i; 958e31cfd1SJeremy Kerr 968e31cfd1SJeremy Kerr for (i = 0; i < ctx->n_clients; i++) { 978e31cfd1SJeremy Kerr struct client *client = &ctx->clients[i]; 988e31cfd1SJeremy Kerr if (client->active) 998e31cfd1SJeremy Kerr continue; 1008e31cfd1SJeremy Kerr close(client->sock); 1018e31cfd1SJeremy Kerr 1028e31cfd1SJeremy Kerr ctx->n_clients--; 1038e31cfd1SJeremy Kerr memmove(&ctx->clients[i], &ctx->clients[i+1], 1048e31cfd1SJeremy Kerr (ctx->n_clients - i) * sizeof(*ctx->clients)); 1058e31cfd1SJeremy Kerr ctx->clients = realloc(ctx->clients, 1068e31cfd1SJeremy Kerr ctx->n_clients * sizeof(*ctx->clients)); 1078e31cfd1SJeremy Kerr } 1088e31cfd1SJeremy Kerr } 1098e31cfd1SJeremy Kerr 1108e31cfd1SJeremy Kerr static void rx_message(uint8_t eid, void *data, void *msg, size_t len) 1118e31cfd1SJeremy Kerr { 1128e31cfd1SJeremy Kerr struct ctx *ctx = data; 1138e31cfd1SJeremy Kerr struct iovec iov[2]; 1148e31cfd1SJeremy Kerr struct msghdr msghdr; 1158e31cfd1SJeremy Kerr bool removed; 1168e31cfd1SJeremy Kerr uint8_t type; 1178e31cfd1SJeremy Kerr int i, rc; 1188e31cfd1SJeremy Kerr 1198e31cfd1SJeremy Kerr if (len < 2) 1208e31cfd1SJeremy Kerr return; 1218e31cfd1SJeremy Kerr 1228e31cfd1SJeremy Kerr type = *(uint8_t *)msg; 1238e31cfd1SJeremy Kerr 1248e31cfd1SJeremy Kerr if (ctx->verbose) 1258e31cfd1SJeremy Kerr fprintf(stderr, "MCTP message received: len %zd, type %d\n", 1268e31cfd1SJeremy Kerr len, type); 1278e31cfd1SJeremy Kerr 1288e31cfd1SJeremy Kerr memset(&msghdr, 0, sizeof(msghdr)); 1298e31cfd1SJeremy Kerr msghdr.msg_iov = iov; 1308e31cfd1SJeremy Kerr msghdr.msg_iovlen = 2; 1318e31cfd1SJeremy Kerr iov[0].iov_base = &eid; 1328e31cfd1SJeremy Kerr iov[0].iov_len = 1; 1338e31cfd1SJeremy Kerr iov[1].iov_base = msg; 1348e31cfd1SJeremy Kerr iov[1].iov_len = len; 1358e31cfd1SJeremy Kerr 1368e31cfd1SJeremy Kerr for (i = 0; i < ctx->n_clients; i++) { 1378e31cfd1SJeremy Kerr struct client *client = &ctx->clients[i]; 1388e31cfd1SJeremy Kerr 1398e31cfd1SJeremy Kerr if (client->type != type) 1408e31cfd1SJeremy Kerr continue; 1418e31cfd1SJeremy Kerr 1428e31cfd1SJeremy Kerr if (ctx->verbose) 1438e31cfd1SJeremy Kerr fprintf(stderr, " forwarding to client %d\n", i); 1448e31cfd1SJeremy Kerr 1458e31cfd1SJeremy Kerr rc = sendmsg(client->sock, &msghdr, 0); 1468e31cfd1SJeremy Kerr if (rc != (ssize_t)(len + 1)) { 1478e31cfd1SJeremy Kerr client->active = false; 1488e31cfd1SJeremy Kerr removed = true; 1498e31cfd1SJeremy Kerr } 1508e31cfd1SJeremy Kerr } 1518e31cfd1SJeremy Kerr 1528e31cfd1SJeremy Kerr if (removed) 1538e31cfd1SJeremy Kerr client_remove_inactive(ctx); 1548e31cfd1SJeremy Kerr 1558e31cfd1SJeremy Kerr } 1568e31cfd1SJeremy Kerr 15734b9b3d8SJeremy Kerr static int binding_null_init(struct mctp *mctp __unused, 15834b9b3d8SJeremy Kerr struct binding *binding __unused, 15934b9b3d8SJeremy Kerr mctp_eid_t eid __unused, 16034b9b3d8SJeremy Kerr int n_params, char * const *params __unused) 16134b9b3d8SJeremy Kerr { 16234b9b3d8SJeremy Kerr if (n_params != 0) { 16334b9b3d8SJeremy Kerr warnx("null binding doesn't accept parameters"); 16434b9b3d8SJeremy Kerr return -1; 16534b9b3d8SJeremy Kerr } 16634b9b3d8SJeremy Kerr return 0; 16734b9b3d8SJeremy Kerr } 16834b9b3d8SJeremy Kerr 1698e31cfd1SJeremy Kerr static int binding_serial_init(struct mctp *mctp, struct binding *binding, 1708e31cfd1SJeremy Kerr mctp_eid_t eid, int n_params, char * const *params) 1718e31cfd1SJeremy Kerr { 1728e31cfd1SJeremy Kerr struct mctp_binding_serial *serial; 1738e31cfd1SJeremy Kerr const char *path; 1748e31cfd1SJeremy Kerr int rc; 1758e31cfd1SJeremy Kerr 1768e31cfd1SJeremy Kerr if (n_params != 1) { 1778e31cfd1SJeremy Kerr warnx("serial binding requires device param"); 1788e31cfd1SJeremy Kerr return -1; 1798e31cfd1SJeremy Kerr } 1808e31cfd1SJeremy Kerr 1818e31cfd1SJeremy Kerr path = params[0]; 1828e31cfd1SJeremy Kerr 1838e31cfd1SJeremy Kerr serial = mctp_serial_init(); 1848e31cfd1SJeremy Kerr assert(serial); 1858e31cfd1SJeremy Kerr 1868e31cfd1SJeremy Kerr rc = mctp_serial_open_path(serial, path); 1878e31cfd1SJeremy Kerr if (rc) 1888e31cfd1SJeremy Kerr return -1; 1898e31cfd1SJeremy Kerr 1903b36d17cSJeremy Kerr mctp_register_bus(mctp, mctp_binding_serial_core(serial), eid); 1918e31cfd1SJeremy Kerr 1928e31cfd1SJeremy Kerr binding->data = serial; 1938e31cfd1SJeremy Kerr 1948e31cfd1SJeremy Kerr return 0; 1958e31cfd1SJeremy Kerr } 1968e31cfd1SJeremy Kerr 1978e31cfd1SJeremy Kerr static int binding_serial_get_fd(struct binding *binding) 1988e31cfd1SJeremy Kerr { 1998e31cfd1SJeremy Kerr return mctp_serial_get_fd(binding->data); 2008e31cfd1SJeremy Kerr } 2018e31cfd1SJeremy Kerr 2028e31cfd1SJeremy Kerr static int binding_serial_process(struct binding *binding) 2038e31cfd1SJeremy Kerr { 2048e31cfd1SJeremy Kerr return mctp_serial_read(binding->data); 2058e31cfd1SJeremy Kerr } 2068e31cfd1SJeremy Kerr 2078e31cfd1SJeremy Kerr static int binding_astlpc_init(struct mctp *mctp, struct binding *binding, 2088e31cfd1SJeremy Kerr mctp_eid_t eid, int n_params, 2098e31cfd1SJeremy Kerr char * const *params __attribute__((unused))) 2108e31cfd1SJeremy Kerr { 2118e31cfd1SJeremy Kerr struct mctp_binding_astlpc *astlpc; 2128e31cfd1SJeremy Kerr 2138e31cfd1SJeremy Kerr if (n_params) { 2148e31cfd1SJeremy Kerr warnx("astlpc binding does not accept parameters"); 2158e31cfd1SJeremy Kerr return -1; 2168e31cfd1SJeremy Kerr } 2178e31cfd1SJeremy Kerr 218bc53d35aSJeremy Kerr astlpc = mctp_astlpc_init_fileio(); 2198e31cfd1SJeremy Kerr if (!astlpc) { 2208e31cfd1SJeremy Kerr warnx("could not initialise astlpc binding"); 2218e31cfd1SJeremy Kerr return -1; 2228e31cfd1SJeremy Kerr } 2238e31cfd1SJeremy Kerr 2243b36d17cSJeremy Kerr mctp_register_bus(mctp, mctp_binding_astlpc_core(astlpc), eid); 2253b36d17cSJeremy Kerr 2268e31cfd1SJeremy Kerr binding->data = astlpc; 2278e31cfd1SJeremy Kerr return 0; 2288e31cfd1SJeremy Kerr } 2298e31cfd1SJeremy Kerr 230*edebe169SAndrew Jeffery static void binding_astlpc_destroy(struct mctp *mctp, struct binding *binding) 231*edebe169SAndrew Jeffery { 232*edebe169SAndrew Jeffery struct mctp_binding_astlpc *astlpc = binding->data; 233*edebe169SAndrew Jeffery 234*edebe169SAndrew Jeffery mctp_unregister_bus(mctp, mctp_binding_astlpc_core(astlpc)); 235*edebe169SAndrew Jeffery 236*edebe169SAndrew Jeffery mctp_astlpc_destroy(astlpc); 237*edebe169SAndrew Jeffery } 238*edebe169SAndrew Jeffery 2398e31cfd1SJeremy Kerr static int binding_astlpc_get_fd(struct binding *binding) 2408e31cfd1SJeremy Kerr { 2418e31cfd1SJeremy Kerr return mctp_astlpc_get_fd(binding->data); 2428e31cfd1SJeremy Kerr } 2438e31cfd1SJeremy Kerr 2448e31cfd1SJeremy Kerr static int binding_astlpc_process(struct binding *binding) 2458e31cfd1SJeremy Kerr { 2468e31cfd1SJeremy Kerr return mctp_astlpc_poll(binding->data); 2478e31cfd1SJeremy Kerr } 2488e31cfd1SJeremy Kerr 2498e31cfd1SJeremy Kerr struct binding bindings[] = { 2508e31cfd1SJeremy Kerr { 25134b9b3d8SJeremy Kerr .name = "null", 25234b9b3d8SJeremy Kerr .init = binding_null_init, 25334b9b3d8SJeremy Kerr }, 25434b9b3d8SJeremy Kerr { 2558e31cfd1SJeremy Kerr .name = "serial", 2568e31cfd1SJeremy Kerr .init = binding_serial_init, 257*edebe169SAndrew Jeffery .destroy = NULL, 2588e31cfd1SJeremy Kerr .get_fd = binding_serial_get_fd, 2598e31cfd1SJeremy Kerr .process = binding_serial_process, 2608e31cfd1SJeremy Kerr }, 2618e31cfd1SJeremy Kerr { 2628e31cfd1SJeremy Kerr .name = "astlpc", 2638e31cfd1SJeremy Kerr .init = binding_astlpc_init, 264*edebe169SAndrew Jeffery .destroy = binding_astlpc_destroy, 2658e31cfd1SJeremy Kerr .get_fd = binding_astlpc_get_fd, 2668e31cfd1SJeremy Kerr .process = binding_astlpc_process, 2678e31cfd1SJeremy Kerr } 2688e31cfd1SJeremy Kerr }; 2698e31cfd1SJeremy Kerr 2708e31cfd1SJeremy Kerr struct binding *binding_lookup(const char *name) 2718e31cfd1SJeremy Kerr { 2728e31cfd1SJeremy Kerr struct binding *binding; 2738e31cfd1SJeremy Kerr unsigned int i; 2748e31cfd1SJeremy Kerr 2758e31cfd1SJeremy Kerr for (i = 0; i < ARRAY_SIZE(bindings); i++) { 2768e31cfd1SJeremy Kerr binding = &bindings[i]; 2778e31cfd1SJeremy Kerr 2788e31cfd1SJeremy Kerr if (!strcmp(binding->name, name)) 2798e31cfd1SJeremy Kerr return binding; 2808e31cfd1SJeremy Kerr } 2818e31cfd1SJeremy Kerr 2828e31cfd1SJeremy Kerr return NULL; 2838e31cfd1SJeremy Kerr } 2848e31cfd1SJeremy Kerr 2858e31cfd1SJeremy Kerr static int socket_init(struct ctx *ctx) 2868e31cfd1SJeremy Kerr { 2878e31cfd1SJeremy Kerr struct sockaddr_un addr; 2888e31cfd1SJeremy Kerr int namelen, rc; 2898e31cfd1SJeremy Kerr 2908e31cfd1SJeremy Kerr namelen = sizeof(sockname) - 1; 2918e31cfd1SJeremy Kerr addr.sun_family = AF_UNIX; 2928e31cfd1SJeremy Kerr memcpy(addr.sun_path, sockname, namelen); 2938e31cfd1SJeremy Kerr 2948e31cfd1SJeremy Kerr ctx->sock = socket(AF_UNIX, SOCK_SEQPACKET, 0); 2958e31cfd1SJeremy Kerr if (ctx->sock < 0) { 2968e31cfd1SJeremy Kerr warn("can't create socket"); 2978e31cfd1SJeremy Kerr return -1; 2988e31cfd1SJeremy Kerr } 2998e31cfd1SJeremy Kerr 3008e31cfd1SJeremy Kerr rc = bind(ctx->sock, (struct sockaddr *)&addr, 3018e31cfd1SJeremy Kerr sizeof(addr.sun_family) + namelen); 3028e31cfd1SJeremy Kerr if (rc) { 3038e31cfd1SJeremy Kerr warn("can't bind socket"); 3048e31cfd1SJeremy Kerr goto err_close; 3058e31cfd1SJeremy Kerr } 3068e31cfd1SJeremy Kerr 3078e31cfd1SJeremy Kerr rc = listen(ctx->sock, 1); 3088e31cfd1SJeremy Kerr if (rc) { 3098e31cfd1SJeremy Kerr warn("can't listen on socket"); 3108e31cfd1SJeremy Kerr goto err_close; 3118e31cfd1SJeremy Kerr } 3128e31cfd1SJeremy Kerr 3138e31cfd1SJeremy Kerr return 0; 3148e31cfd1SJeremy Kerr 3158e31cfd1SJeremy Kerr err_close: 3168e31cfd1SJeremy Kerr close(ctx->sock); 3178e31cfd1SJeremy Kerr return -1; 3188e31cfd1SJeremy Kerr } 3198e31cfd1SJeremy Kerr 3208e31cfd1SJeremy Kerr static int socket_process(struct ctx *ctx) 3218e31cfd1SJeremy Kerr { 3228e31cfd1SJeremy Kerr struct client *client; 3238e31cfd1SJeremy Kerr int fd; 3248e31cfd1SJeremy Kerr 3258e31cfd1SJeremy Kerr fd = accept4(ctx->sock, NULL, 0, SOCK_NONBLOCK); 3268e31cfd1SJeremy Kerr if (fd < 0) 3278e31cfd1SJeremy Kerr return -1; 3288e31cfd1SJeremy Kerr 3298e31cfd1SJeremy Kerr ctx->n_clients++; 3308e31cfd1SJeremy Kerr ctx->clients = realloc(ctx->clients, 3318e31cfd1SJeremy Kerr ctx->n_clients * sizeof(struct client)); 3328e31cfd1SJeremy Kerr 3338e31cfd1SJeremy Kerr client = &ctx->clients[ctx->n_clients-1]; 3348676c934SAndrew Jeffery memset(client, 0, sizeof(*client)); 3358e31cfd1SJeremy Kerr client->active = true; 3368e31cfd1SJeremy Kerr client->sock = fd; 3378e31cfd1SJeremy Kerr 3388e31cfd1SJeremy Kerr return 0; 3398e31cfd1SJeremy Kerr } 3408e31cfd1SJeremy Kerr 3418e31cfd1SJeremy Kerr static int client_process_recv(struct ctx *ctx, int idx) 3428e31cfd1SJeremy Kerr { 3438e31cfd1SJeremy Kerr struct client *client = &ctx->clients[idx]; 344f49b2ac8SJeremy Kerr uint8_t eid; 345f49b2ac8SJeremy Kerr ssize_t len; 3468e31cfd1SJeremy Kerr int rc; 3478e31cfd1SJeremy Kerr 3488e31cfd1SJeremy Kerr /* are we waiting for a type message? */ 3498e31cfd1SJeremy Kerr if (!client->type) { 3508e31cfd1SJeremy Kerr uint8_t type; 3518e31cfd1SJeremy Kerr rc = read(client->sock, &type, 1); 3528e31cfd1SJeremy Kerr if (rc <= 0) 3538e31cfd1SJeremy Kerr goto out_close; 3548e31cfd1SJeremy Kerr 3558e31cfd1SJeremy Kerr if (type == 0) { 3568e31cfd1SJeremy Kerr rc = -1; 3578e31cfd1SJeremy Kerr goto out_close; 3588e31cfd1SJeremy Kerr } 3598e31cfd1SJeremy Kerr if (ctx->verbose) 3608e31cfd1SJeremy Kerr fprintf(stderr, "client[%d] registered for type %u\n", 3618e31cfd1SJeremy Kerr idx, type); 3628e31cfd1SJeremy Kerr client->type = type; 3638e31cfd1SJeremy Kerr return 0; 3648e31cfd1SJeremy Kerr } 3658e31cfd1SJeremy Kerr 366f49b2ac8SJeremy Kerr len = recv(client->sock, NULL, 0, MSG_PEEK | MSG_TRUNC); 367f49b2ac8SJeremy Kerr if (len < 0) { 3686896d41eSAndrew Jeffery if (errno != ECONNRESET) 369f49b2ac8SJeremy Kerr warn("can't receive (peek) from client"); 3706896d41eSAndrew Jeffery 37113a4041fSAndrew Jeffery rc = -1; 372f49b2ac8SJeremy Kerr goto out_close; 373f49b2ac8SJeremy Kerr } 374f49b2ac8SJeremy Kerr 375b93b6112SAndrew Jeffery if ((size_t)len > ctx->buf_size) { 376f49b2ac8SJeremy Kerr void *tmp; 377f49b2ac8SJeremy Kerr 378f49b2ac8SJeremy Kerr tmp = realloc(ctx->buf, len); 379f49b2ac8SJeremy Kerr if (!tmp) { 380f49b2ac8SJeremy Kerr warn("can't allocate for incoming message"); 38113a4041fSAndrew Jeffery rc = -1; 382f49b2ac8SJeremy Kerr goto out_close; 383f49b2ac8SJeremy Kerr } 384f49b2ac8SJeremy Kerr ctx->buf = tmp; 385f49b2ac8SJeremy Kerr ctx->buf_size = len; 386f49b2ac8SJeremy Kerr } 387f49b2ac8SJeremy Kerr 388f49b2ac8SJeremy Kerr rc = recv(client->sock, ctx->buf, ctx->buf_size, 0); 3898e31cfd1SJeremy Kerr if (rc < 0) { 3906896d41eSAndrew Jeffery if (errno != ECONNRESET) 3918e31cfd1SJeremy Kerr warn("can't receive from client"); 39213a4041fSAndrew Jeffery rc = -1; 3938e31cfd1SJeremy Kerr goto out_close; 3948e31cfd1SJeremy Kerr } 3958e31cfd1SJeremy Kerr 396195a7c5eSJeremy Kerr if (rc <= 0) { 3978e31cfd1SJeremy Kerr rc = -1; 3988e31cfd1SJeremy Kerr goto out_close; 3998e31cfd1SJeremy Kerr } 4008e31cfd1SJeremy Kerr 401cad47301SAndrew Jeffery if (ctx->pcap.socket.path) 402cad47301SAndrew Jeffery capture_socket(ctx->pcap.socket.dumper, ctx->buf, rc); 403cad47301SAndrew Jeffery 404f49b2ac8SJeremy Kerr eid = *(uint8_t *)ctx->buf; 405d690d8eaSJeremy Kerr 4068e31cfd1SJeremy Kerr if (ctx->verbose) 4078e31cfd1SJeremy Kerr fprintf(stderr, 4088e31cfd1SJeremy Kerr "client[%d] sent message: dest 0x%02x len %d\n", 4098e31cfd1SJeremy Kerr idx, eid, rc - 1); 4108e31cfd1SJeremy Kerr 411195a7c5eSJeremy Kerr 412195a7c5eSJeremy Kerr if (eid == ctx->local_eid) 413f49b2ac8SJeremy Kerr rx_message(eid, ctx, ctx->buf + 1, rc - 1); 414195a7c5eSJeremy Kerr else 415f49b2ac8SJeremy Kerr tx_message(ctx, eid, ctx->buf + 1, rc - 1); 4168e31cfd1SJeremy Kerr 4178e31cfd1SJeremy Kerr return 0; 4188e31cfd1SJeremy Kerr 4198e31cfd1SJeremy Kerr out_close: 4208e31cfd1SJeremy Kerr client->active = false; 4218e31cfd1SJeremy Kerr return rc; 4228e31cfd1SJeremy Kerr } 4238e31cfd1SJeremy Kerr 4248e31cfd1SJeremy Kerr static int binding_init(struct ctx *ctx, const char *name, 4258e31cfd1SJeremy Kerr int argc, char * const *argv) 4268e31cfd1SJeremy Kerr { 4278e31cfd1SJeremy Kerr int rc; 4288e31cfd1SJeremy Kerr 4298e31cfd1SJeremy Kerr ctx->binding = binding_lookup(name); 4308e31cfd1SJeremy Kerr if (!ctx->binding) { 4318e31cfd1SJeremy Kerr warnx("no such binding '%s'", name); 4328e31cfd1SJeremy Kerr return -1; 4338e31cfd1SJeremy Kerr } 4348e31cfd1SJeremy Kerr 4358e31cfd1SJeremy Kerr rc = ctx->binding->init(ctx->mctp, ctx->binding, ctx->local_eid, 4368e31cfd1SJeremy Kerr argc, argv); 4378e31cfd1SJeremy Kerr return rc; 4388e31cfd1SJeremy Kerr } 4398e31cfd1SJeremy Kerr 440*edebe169SAndrew Jeffery static void binding_destroy(struct ctx *ctx) 441*edebe169SAndrew Jeffery { 442*edebe169SAndrew Jeffery if (ctx->binding->destroy) 443*edebe169SAndrew Jeffery ctx->binding->destroy(ctx->mctp, ctx->binding); 444*edebe169SAndrew Jeffery } 445*edebe169SAndrew Jeffery 4468e31cfd1SJeremy Kerr enum { 4478e31cfd1SJeremy Kerr FD_BINDING = 0, 4488e31cfd1SJeremy Kerr FD_SOCKET, 449490e3873SAndrew Jeffery FD_SIGNAL, 4508e31cfd1SJeremy Kerr FD_NR, 4518e31cfd1SJeremy Kerr }; 4528e31cfd1SJeremy Kerr 4538e31cfd1SJeremy Kerr static int run_daemon(struct ctx *ctx) 4548e31cfd1SJeremy Kerr { 4558e31cfd1SJeremy Kerr bool clients_changed = false; 456490e3873SAndrew Jeffery sigset_t mask; 4578e31cfd1SJeremy Kerr int rc, i; 4588e31cfd1SJeremy Kerr 4598e31cfd1SJeremy Kerr ctx->pollfds = malloc(FD_NR * sizeof(struct pollfd)); 4608e31cfd1SJeremy Kerr 46134b9b3d8SJeremy Kerr if (ctx->binding->get_fd) { 4628e31cfd1SJeremy Kerr ctx->pollfds[FD_BINDING].fd = 4638e31cfd1SJeremy Kerr ctx->binding->get_fd(ctx->binding); 4648e31cfd1SJeremy Kerr ctx->pollfds[FD_BINDING].events = POLLIN; 46534b9b3d8SJeremy Kerr } else { 46634b9b3d8SJeremy Kerr ctx->pollfds[FD_BINDING].fd = -1; 46734b9b3d8SJeremy Kerr ctx->pollfds[FD_BINDING].events = 0; 46834b9b3d8SJeremy Kerr } 4698e31cfd1SJeremy Kerr 470490e3873SAndrew Jeffery sigemptyset(&mask); 471490e3873SAndrew Jeffery sigaddset(&mask, SIGINT); 472490e3873SAndrew Jeffery sigaddset(&mask, SIGTERM); 473490e3873SAndrew Jeffery sigaddset(&mask, SIGQUIT); 474490e3873SAndrew Jeffery 475490e3873SAndrew Jeffery if ((rc = sigprocmask(SIG_BLOCK, &mask, NULL)) == -1) { 476490e3873SAndrew Jeffery warn("sigprocmask"); 477490e3873SAndrew Jeffery return rc; 478490e3873SAndrew Jeffery } 479490e3873SAndrew Jeffery 480490e3873SAndrew Jeffery ctx->pollfds[FD_SIGNAL].fd = signalfd(-1, &mask, 0); 481490e3873SAndrew Jeffery ctx->pollfds[FD_SIGNAL].events = POLLIN; 482490e3873SAndrew Jeffery 4838e31cfd1SJeremy Kerr ctx->pollfds[FD_SOCKET].fd = ctx->sock; 4848e31cfd1SJeremy Kerr ctx->pollfds[FD_SOCKET].events = POLLIN; 4858e31cfd1SJeremy Kerr 4868e31cfd1SJeremy Kerr mctp_set_rx_all(ctx->mctp, rx_message, ctx); 4878e31cfd1SJeremy Kerr 4888e31cfd1SJeremy Kerr for (;;) { 4898e31cfd1SJeremy Kerr if (clients_changed) { 4908e31cfd1SJeremy Kerr int i; 4918e31cfd1SJeremy Kerr 4928e31cfd1SJeremy Kerr ctx->pollfds = realloc(ctx->pollfds, 4938e31cfd1SJeremy Kerr (ctx->n_clients + FD_NR) * 4948e31cfd1SJeremy Kerr sizeof(struct pollfd)); 4958e31cfd1SJeremy Kerr 4968e31cfd1SJeremy Kerr for (i = 0; i < ctx->n_clients; i++) { 4978e31cfd1SJeremy Kerr ctx->pollfds[FD_NR+i].fd = 4988e31cfd1SJeremy Kerr ctx->clients[i].sock; 4998e31cfd1SJeremy Kerr ctx->pollfds[FD_NR+i].events = POLLIN; 5008e31cfd1SJeremy Kerr } 5018e31cfd1SJeremy Kerr clients_changed = false; 5028e31cfd1SJeremy Kerr } 5038e31cfd1SJeremy Kerr 5048e31cfd1SJeremy Kerr rc = poll(ctx->pollfds, ctx->n_clients + FD_NR, -1); 5058e31cfd1SJeremy Kerr if (rc < 0) { 5068e31cfd1SJeremy Kerr warn("poll failed"); 5078e31cfd1SJeremy Kerr break; 5088e31cfd1SJeremy Kerr } 5098e31cfd1SJeremy Kerr 5108e31cfd1SJeremy Kerr if (!rc) 5118e31cfd1SJeremy Kerr continue; 5128e31cfd1SJeremy Kerr 513490e3873SAndrew Jeffery if (ctx->pollfds[FD_SIGNAL].revents) { 514490e3873SAndrew Jeffery struct signalfd_siginfo si; 515490e3873SAndrew Jeffery ssize_t got; 516490e3873SAndrew Jeffery 517490e3873SAndrew Jeffery got = read(ctx->pollfds[FD_SIGNAL].fd, &si, sizeof(si)); 518490e3873SAndrew Jeffery if (got == sizeof(si)) { 519490e3873SAndrew Jeffery warnx("Received %s, quitting", 520490e3873SAndrew Jeffery strsignal(si.ssi_signo)); 521490e3873SAndrew Jeffery rc = 0; 522490e3873SAndrew Jeffery break; 523490e3873SAndrew Jeffery } else { 524490e3873SAndrew Jeffery warnx("Unexpected read result for signalfd: %d", 525490e3873SAndrew Jeffery rc); 526490e3873SAndrew Jeffery warnx("Quitting on the basis that signalfd became ready"); 527490e3873SAndrew Jeffery rc = -1; 528490e3873SAndrew Jeffery break; 529490e3873SAndrew Jeffery } 530490e3873SAndrew Jeffery } 531490e3873SAndrew Jeffery 5328e31cfd1SJeremy Kerr if (ctx->pollfds[FD_BINDING].revents) { 53334b9b3d8SJeremy Kerr rc = 0; 53434b9b3d8SJeremy Kerr if (ctx->binding->process) 5358e31cfd1SJeremy Kerr rc = ctx->binding->process(ctx->binding); 5368e31cfd1SJeremy Kerr if (rc) 5378e31cfd1SJeremy Kerr break; 5388e31cfd1SJeremy Kerr } 5398e31cfd1SJeremy Kerr 5408e31cfd1SJeremy Kerr for (i = 0; i < ctx->n_clients; i++) { 5418e31cfd1SJeremy Kerr if (!ctx->pollfds[FD_NR+i].revents) 5428e31cfd1SJeremy Kerr continue; 5438e31cfd1SJeremy Kerr 5448e31cfd1SJeremy Kerr rc = client_process_recv(ctx, i); 5458e31cfd1SJeremy Kerr if (rc) 5468e31cfd1SJeremy Kerr clients_changed = true; 5478e31cfd1SJeremy Kerr } 5488e31cfd1SJeremy Kerr 5498e31cfd1SJeremy Kerr if (ctx->pollfds[FD_SOCKET].revents) { 5508e31cfd1SJeremy Kerr rc = socket_process(ctx); 5518e31cfd1SJeremy Kerr if (rc) 5528e31cfd1SJeremy Kerr break; 5538e31cfd1SJeremy Kerr clients_changed = true; 5548e31cfd1SJeremy Kerr } 5558e31cfd1SJeremy Kerr 5568e31cfd1SJeremy Kerr if (clients_changed) 5578e31cfd1SJeremy Kerr client_remove_inactive(ctx); 5588e31cfd1SJeremy Kerr } 5598e31cfd1SJeremy Kerr 5608e31cfd1SJeremy Kerr 5618e31cfd1SJeremy Kerr free(ctx->pollfds); 5628e31cfd1SJeremy Kerr 5638e31cfd1SJeremy Kerr return rc; 5648e31cfd1SJeremy Kerr } 5658e31cfd1SJeremy Kerr 5668e31cfd1SJeremy Kerr static const struct option options[] = { 567cad47301SAndrew Jeffery { "capture-binding", required_argument, 0, 'b' }, 568cad47301SAndrew Jeffery { "capture-socket", required_argument, 0, 's' }, 569cad47301SAndrew Jeffery { "binding-linktype", required_argument, 0, 'B' }, 570cad47301SAndrew Jeffery { "socket-linktype", required_argument, 0, 'S' }, 5718e31cfd1SJeremy Kerr { "verbose", no_argument, 0, 'v' }, 5728e31cfd1SJeremy Kerr { "eid", required_argument, 0, 'e' }, 5738e31cfd1SJeremy Kerr { 0 }, 5748e31cfd1SJeremy Kerr }; 5758e31cfd1SJeremy Kerr 5768e31cfd1SJeremy Kerr static void usage(const char *progname) 5778e31cfd1SJeremy Kerr { 5788e31cfd1SJeremy Kerr unsigned int i; 5798e31cfd1SJeremy Kerr 5808e31cfd1SJeremy Kerr fprintf(stderr, "usage: %s <binding> [params]\n", progname); 5818e31cfd1SJeremy Kerr fprintf(stderr, "Available bindings:\n"); 5828e31cfd1SJeremy Kerr for (i = 0; i < ARRAY_SIZE(bindings); i++) 5838e31cfd1SJeremy Kerr fprintf(stderr, " %s\n", bindings[i].name); 5848e31cfd1SJeremy Kerr } 5858e31cfd1SJeremy Kerr 5868e31cfd1SJeremy Kerr int main(int argc, char * const *argv) 5878e31cfd1SJeremy Kerr { 5888e31cfd1SJeremy Kerr struct ctx *ctx, _ctx; 5898e31cfd1SJeremy Kerr int rc; 5908e31cfd1SJeremy Kerr 5918e31cfd1SJeremy Kerr ctx = &_ctx; 5928e31cfd1SJeremy Kerr ctx->clients = NULL; 5938e31cfd1SJeremy Kerr ctx->n_clients = 0; 5948e31cfd1SJeremy Kerr ctx->local_eid = local_eid_default; 59504b81fc7SAndrew Jeffery ctx->verbose = false; 596cad47301SAndrew Jeffery ctx->pcap.binding.path = NULL; 597cad47301SAndrew Jeffery ctx->pcap.socket.path = NULL; 5988e31cfd1SJeremy Kerr 5998e31cfd1SJeremy Kerr for (;;) { 600cad47301SAndrew Jeffery rc = getopt_long(argc, argv, "b:es::v", options, NULL); 6018e31cfd1SJeremy Kerr if (rc == -1) 6028e31cfd1SJeremy Kerr break; 6038e31cfd1SJeremy Kerr switch (rc) { 604cad47301SAndrew Jeffery case 'b': 605cad47301SAndrew Jeffery ctx->pcap.binding.path = optarg; 606cad47301SAndrew Jeffery break; 607cad47301SAndrew Jeffery case 's': 608cad47301SAndrew Jeffery ctx->pcap.socket.path = optarg; 609cad47301SAndrew Jeffery break; 610cad47301SAndrew Jeffery case 'B': 611cad47301SAndrew Jeffery ctx->pcap.binding.linktype = atoi(optarg); 612cad47301SAndrew Jeffery break; 613cad47301SAndrew Jeffery case 'S': 614cad47301SAndrew Jeffery ctx->pcap.socket.linktype = atoi(optarg); 615cad47301SAndrew Jeffery break; 6168e31cfd1SJeremy Kerr case 'v': 6178e31cfd1SJeremy Kerr ctx->verbose = true; 6188e31cfd1SJeremy Kerr break; 6198e31cfd1SJeremy Kerr case 'e': 6208e31cfd1SJeremy Kerr ctx->local_eid = atoi(optarg); 6218e31cfd1SJeremy Kerr break; 6228e31cfd1SJeremy Kerr default: 6238e31cfd1SJeremy Kerr fprintf(stderr, "Invalid argument\n"); 6248e31cfd1SJeremy Kerr return EXIT_FAILURE; 6258e31cfd1SJeremy Kerr } 6268e31cfd1SJeremy Kerr } 6278e31cfd1SJeremy Kerr 6288e31cfd1SJeremy Kerr if (optind >= argc) { 6298e31cfd1SJeremy Kerr fprintf(stderr, "missing binding argument\n"); 6308e31cfd1SJeremy Kerr usage(argv[0]); 6318e31cfd1SJeremy Kerr return EXIT_FAILURE; 6328e31cfd1SJeremy Kerr } 6338e31cfd1SJeremy Kerr 634f49b2ac8SJeremy Kerr /* setup initial buffer */ 635f49b2ac8SJeremy Kerr ctx->buf_size = 4096; 636f49b2ac8SJeremy Kerr ctx->buf = malloc(ctx->buf_size); 637f49b2ac8SJeremy Kerr 6380b278a63SJeremy Kerr mctp_set_log_stdio(ctx->verbose ? MCTP_LOG_DEBUG : MCTP_LOG_WARNING); 6390b278a63SJeremy Kerr 6408e31cfd1SJeremy Kerr ctx->mctp = mctp_init(); 6418e31cfd1SJeremy Kerr assert(ctx->mctp); 6428e31cfd1SJeremy Kerr 643cad47301SAndrew Jeffery if (ctx->pcap.binding.path || ctx->pcap.socket.path) { 644cad47301SAndrew Jeffery if (capture_init()) { 645cad47301SAndrew Jeffery rc = EXIT_FAILURE; 646cad47301SAndrew Jeffery goto cleanup_mctp; 647cad47301SAndrew Jeffery } 648cad47301SAndrew Jeffery } 649cad47301SAndrew Jeffery 650cad47301SAndrew Jeffery if (ctx->pcap.binding.path) { 651cad47301SAndrew Jeffery rc = capture_prepare(&ctx->pcap.binding); 652cad47301SAndrew Jeffery if (rc == -1) { 653cad47301SAndrew Jeffery fprintf(stderr, "Failed to initialise capture: %d\n", rc); 654cad47301SAndrew Jeffery rc = EXIT_FAILURE; 655cad47301SAndrew Jeffery goto cleanup_mctp; 656cad47301SAndrew Jeffery } 657cad47301SAndrew Jeffery 658cad47301SAndrew Jeffery mctp_set_capture_handler(ctx->mctp, capture_binding, 659cad47301SAndrew Jeffery ctx->pcap.binding.dumper); 660cad47301SAndrew Jeffery } 661cad47301SAndrew Jeffery 662cad47301SAndrew Jeffery if (ctx->pcap.socket.path) { 663cad47301SAndrew Jeffery rc = capture_prepare(&ctx->pcap.socket); 664cad47301SAndrew Jeffery if (rc == -1) { 665cad47301SAndrew Jeffery fprintf(stderr, "Failed to initialise capture: %d\n", rc); 666cad47301SAndrew Jeffery rc = EXIT_FAILURE; 667cad47301SAndrew Jeffery goto cleanup_pcap_binding; 668cad47301SAndrew Jeffery } 669cad47301SAndrew Jeffery } 670cad47301SAndrew Jeffery 6718e31cfd1SJeremy Kerr rc = binding_init(ctx, argv[optind], argc - optind - 1, argv + optind + 1); 672cad47301SAndrew Jeffery if (rc) { 673cad47301SAndrew Jeffery fprintf(stderr, "Failed to initialise binding: %d\n", rc); 674cad47301SAndrew Jeffery rc = EXIT_FAILURE; 675cad47301SAndrew Jeffery goto cleanup_pcap_socket; 676cad47301SAndrew Jeffery } 6778e31cfd1SJeremy Kerr 678d4103f8fSAndrew Jeffery rc = sd_listen_fds(true); 679d4103f8fSAndrew Jeffery if (rc <= 0) { 6808e31cfd1SJeremy Kerr rc = socket_init(ctx); 681cad47301SAndrew Jeffery if (rc) { 682cad47301SAndrew Jeffery fprintf(stderr, "Failed to initialse socket: %d\n", rc); 683*edebe169SAndrew Jeffery goto cleanup_binding; 684cad47301SAndrew Jeffery } 685d4103f8fSAndrew Jeffery } else { 686d4103f8fSAndrew Jeffery ctx->sock = SD_LISTEN_FDS_START; 687d4103f8fSAndrew Jeffery } 6888e31cfd1SJeremy Kerr 6898e31cfd1SJeremy Kerr rc = run_daemon(ctx); 6908e31cfd1SJeremy Kerr 691*edebe169SAndrew Jeffery cleanup_binding: 692*edebe169SAndrew Jeffery binding_destroy(ctx); 693*edebe169SAndrew Jeffery 694cad47301SAndrew Jeffery cleanup_pcap_socket: 695cad47301SAndrew Jeffery if (ctx->pcap.socket.path) 696cad47301SAndrew Jeffery capture_close(&ctx->pcap.socket); 697cad47301SAndrew Jeffery 698cad47301SAndrew Jeffery cleanup_pcap_binding: 699cad47301SAndrew Jeffery if (ctx->pcap.binding.path) 700cad47301SAndrew Jeffery capture_close(&ctx->pcap.binding); 701cad47301SAndrew Jeffery 702cad47301SAndrew Jeffery rc = rc ? EXIT_FAILURE : EXIT_SUCCESS; 703cad47301SAndrew Jeffery cleanup_mctp: 704cad47301SAndrew Jeffery 705cad47301SAndrew Jeffery return rc; 7068e31cfd1SJeremy Kerr 7078e31cfd1SJeremy Kerr } 708