13d36ee2eSJeremy Kerr /* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later */ 23d36ee2eSJeremy Kerr 38e31cfd1SJeremy Kerr #define _GNU_SOURCE 48e31cfd1SJeremy Kerr 58e31cfd1SJeremy Kerr #include <assert.h> 68e31cfd1SJeremy Kerr #include <err.h> 78e31cfd1SJeremy Kerr #include <getopt.h> 88e31cfd1SJeremy Kerr #include <poll.h> 904b81fc7SAndrew Jeffery #include <stdbool.h> 108e31cfd1SJeremy Kerr #include <stdio.h> 118e31cfd1SJeremy Kerr #include <stdlib.h> 128e31cfd1SJeremy Kerr #include <string.h> 138e31cfd1SJeremy Kerr #include <unistd.h> 148e31cfd1SJeremy Kerr 158e31cfd1SJeremy Kerr #include <sys/socket.h> 168e31cfd1SJeremy Kerr #include <sys/un.h> 178e31cfd1SJeremy Kerr 188e31cfd1SJeremy Kerr #include "libmctp.h" 198e31cfd1SJeremy Kerr #include "libmctp-serial.h" 208e31cfd1SJeremy Kerr #include "libmctp-astlpc.h" 218e31cfd1SJeremy Kerr 228e31cfd1SJeremy Kerr #define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0])) 2334b9b3d8SJeremy Kerr #define __unused __attribute__((unused)) 248e31cfd1SJeremy Kerr 258e31cfd1SJeremy Kerr static const mctp_eid_t local_eid_default = 8; 268e31cfd1SJeremy Kerr static char sockname[] = "\0mctp-mux"; 278e31cfd1SJeremy Kerr 288e31cfd1SJeremy Kerr struct binding { 298e31cfd1SJeremy Kerr const char *name; 308e31cfd1SJeremy Kerr int (*init)(struct mctp *mctp, struct binding *binding, 318e31cfd1SJeremy Kerr mctp_eid_t eid, int n_params, 328e31cfd1SJeremy Kerr char * const * params); 338e31cfd1SJeremy Kerr int (*get_fd)(struct binding *binding); 348e31cfd1SJeremy Kerr int (*process)(struct binding *binding); 358e31cfd1SJeremy Kerr void *data; 368e31cfd1SJeremy Kerr }; 378e31cfd1SJeremy Kerr 388e31cfd1SJeremy Kerr struct client { 398e31cfd1SJeremy Kerr bool active; 408e31cfd1SJeremy Kerr int sock; 418e31cfd1SJeremy Kerr uint8_t type; 428e31cfd1SJeremy Kerr }; 438e31cfd1SJeremy Kerr 448e31cfd1SJeremy Kerr struct ctx { 458e31cfd1SJeremy Kerr struct mctp *mctp; 468e31cfd1SJeremy Kerr struct binding *binding; 478e31cfd1SJeremy Kerr bool verbose; 488e31cfd1SJeremy Kerr int local_eid; 49f49b2ac8SJeremy Kerr void *buf; 50f49b2ac8SJeremy Kerr size_t buf_size; 518e31cfd1SJeremy Kerr 528e31cfd1SJeremy Kerr int sock; 538e31cfd1SJeremy Kerr struct pollfd *pollfds; 548e31cfd1SJeremy Kerr 558e31cfd1SJeremy Kerr struct client *clients; 568e31cfd1SJeremy Kerr int n_clients; 578e31cfd1SJeremy Kerr }; 588e31cfd1SJeremy Kerr 598e31cfd1SJeremy Kerr static void tx_message(struct ctx *ctx, mctp_eid_t eid, void *msg, size_t len) 608e31cfd1SJeremy Kerr { 618e31cfd1SJeremy Kerr mctp_message_tx(ctx->mctp, eid, msg, len); 628e31cfd1SJeremy Kerr } 638e31cfd1SJeremy Kerr 648e31cfd1SJeremy Kerr static void client_remove_inactive(struct ctx *ctx) 658e31cfd1SJeremy Kerr { 668e31cfd1SJeremy Kerr int i; 678e31cfd1SJeremy Kerr 688e31cfd1SJeremy Kerr for (i = 0; i < ctx->n_clients; i++) { 698e31cfd1SJeremy Kerr struct client *client = &ctx->clients[i]; 708e31cfd1SJeremy Kerr if (client->active) 718e31cfd1SJeremy Kerr continue; 728e31cfd1SJeremy Kerr close(client->sock); 738e31cfd1SJeremy Kerr 748e31cfd1SJeremy Kerr ctx->n_clients--; 758e31cfd1SJeremy Kerr memmove(&ctx->clients[i], &ctx->clients[i+1], 768e31cfd1SJeremy Kerr (ctx->n_clients - i) * sizeof(*ctx->clients)); 778e31cfd1SJeremy Kerr ctx->clients = realloc(ctx->clients, 788e31cfd1SJeremy Kerr ctx->n_clients * sizeof(*ctx->clients)); 798e31cfd1SJeremy Kerr } 808e31cfd1SJeremy Kerr } 818e31cfd1SJeremy Kerr 828e31cfd1SJeremy Kerr static void rx_message(uint8_t eid, void *data, void *msg, size_t len) 838e31cfd1SJeremy Kerr { 848e31cfd1SJeremy Kerr struct ctx *ctx = data; 858e31cfd1SJeremy Kerr struct iovec iov[2]; 868e31cfd1SJeremy Kerr struct msghdr msghdr; 878e31cfd1SJeremy Kerr bool removed; 888e31cfd1SJeremy Kerr uint8_t type; 898e31cfd1SJeremy Kerr int i, rc; 908e31cfd1SJeremy Kerr 918e31cfd1SJeremy Kerr if (len < 2) 928e31cfd1SJeremy Kerr return; 938e31cfd1SJeremy Kerr 948e31cfd1SJeremy Kerr type = *(uint8_t *)msg; 958e31cfd1SJeremy Kerr 968e31cfd1SJeremy Kerr if (ctx->verbose) 978e31cfd1SJeremy Kerr fprintf(stderr, "MCTP message received: len %zd, type %d\n", 988e31cfd1SJeremy Kerr len, type); 998e31cfd1SJeremy Kerr 1008e31cfd1SJeremy Kerr memset(&msghdr, 0, sizeof(msghdr)); 1018e31cfd1SJeremy Kerr msghdr.msg_iov = iov; 1028e31cfd1SJeremy Kerr msghdr.msg_iovlen = 2; 1038e31cfd1SJeremy Kerr iov[0].iov_base = &eid; 1048e31cfd1SJeremy Kerr iov[0].iov_len = 1; 1058e31cfd1SJeremy Kerr iov[1].iov_base = msg; 1068e31cfd1SJeremy Kerr iov[1].iov_len = len; 1078e31cfd1SJeremy Kerr 1088e31cfd1SJeremy Kerr for (i = 0; i < ctx->n_clients; i++) { 1098e31cfd1SJeremy Kerr struct client *client = &ctx->clients[i]; 1108e31cfd1SJeremy Kerr 1118e31cfd1SJeremy Kerr if (client->type != type) 1128e31cfd1SJeremy Kerr continue; 1138e31cfd1SJeremy Kerr 1148e31cfd1SJeremy Kerr if (ctx->verbose) 1158e31cfd1SJeremy Kerr fprintf(stderr, " forwarding to client %d\n", i); 1168e31cfd1SJeremy Kerr 1178e31cfd1SJeremy Kerr rc = sendmsg(client->sock, &msghdr, 0); 1188e31cfd1SJeremy Kerr if (rc != (ssize_t)(len + 1)) { 1198e31cfd1SJeremy Kerr client->active = false; 1208e31cfd1SJeremy Kerr removed = true; 1218e31cfd1SJeremy Kerr } 1228e31cfd1SJeremy Kerr } 1238e31cfd1SJeremy Kerr 1248e31cfd1SJeremy Kerr if (removed) 1258e31cfd1SJeremy Kerr client_remove_inactive(ctx); 1268e31cfd1SJeremy Kerr 1278e31cfd1SJeremy Kerr } 1288e31cfd1SJeremy Kerr 12934b9b3d8SJeremy Kerr static int binding_null_init(struct mctp *mctp __unused, 13034b9b3d8SJeremy Kerr struct binding *binding __unused, 13134b9b3d8SJeremy Kerr mctp_eid_t eid __unused, 13234b9b3d8SJeremy Kerr int n_params, char * const *params __unused) 13334b9b3d8SJeremy Kerr { 13434b9b3d8SJeremy Kerr if (n_params != 0) { 13534b9b3d8SJeremy Kerr warnx("null binding doesn't accept parameters"); 13634b9b3d8SJeremy Kerr return -1; 13734b9b3d8SJeremy Kerr } 13834b9b3d8SJeremy Kerr return 0; 13934b9b3d8SJeremy Kerr } 14034b9b3d8SJeremy Kerr 1418e31cfd1SJeremy Kerr static int binding_serial_init(struct mctp *mctp, struct binding *binding, 1428e31cfd1SJeremy Kerr mctp_eid_t eid, int n_params, char * const *params) 1438e31cfd1SJeremy Kerr { 1448e31cfd1SJeremy Kerr struct mctp_binding_serial *serial; 1458e31cfd1SJeremy Kerr const char *path; 1468e31cfd1SJeremy Kerr int rc; 1478e31cfd1SJeremy Kerr 1488e31cfd1SJeremy Kerr if (n_params != 1) { 1498e31cfd1SJeremy Kerr warnx("serial binding requires device param"); 1508e31cfd1SJeremy Kerr return -1; 1518e31cfd1SJeremy Kerr } 1528e31cfd1SJeremy Kerr 1538e31cfd1SJeremy Kerr path = params[0]; 1548e31cfd1SJeremy Kerr 1558e31cfd1SJeremy Kerr serial = mctp_serial_init(); 1568e31cfd1SJeremy Kerr assert(serial); 1578e31cfd1SJeremy Kerr 1588e31cfd1SJeremy Kerr rc = mctp_serial_open_path(serial, path); 1598e31cfd1SJeremy Kerr if (rc) 1608e31cfd1SJeremy Kerr return -1; 1618e31cfd1SJeremy Kerr 1623b36d17cSJeremy Kerr mctp_register_bus(mctp, mctp_binding_serial_core(serial), eid); 1638e31cfd1SJeremy Kerr 1648e31cfd1SJeremy Kerr binding->data = serial; 1658e31cfd1SJeremy Kerr 1668e31cfd1SJeremy Kerr return 0; 1678e31cfd1SJeremy Kerr } 1688e31cfd1SJeremy Kerr 1698e31cfd1SJeremy Kerr static int binding_serial_get_fd(struct binding *binding) 1708e31cfd1SJeremy Kerr { 1718e31cfd1SJeremy Kerr return mctp_serial_get_fd(binding->data); 1728e31cfd1SJeremy Kerr } 1738e31cfd1SJeremy Kerr 1748e31cfd1SJeremy Kerr static int binding_serial_process(struct binding *binding) 1758e31cfd1SJeremy Kerr { 1768e31cfd1SJeremy Kerr return mctp_serial_read(binding->data); 1778e31cfd1SJeremy Kerr } 1788e31cfd1SJeremy Kerr 1798e31cfd1SJeremy Kerr static int binding_astlpc_init(struct mctp *mctp, struct binding *binding, 1808e31cfd1SJeremy Kerr mctp_eid_t eid, int n_params, 1818e31cfd1SJeremy Kerr char * const *params __attribute__((unused))) 1828e31cfd1SJeremy Kerr { 1838e31cfd1SJeremy Kerr struct mctp_binding_astlpc *astlpc; 1848e31cfd1SJeremy Kerr 1858e31cfd1SJeremy Kerr if (n_params) { 1868e31cfd1SJeremy Kerr warnx("astlpc binding does not accept parameters"); 1878e31cfd1SJeremy Kerr return -1; 1888e31cfd1SJeremy Kerr } 1898e31cfd1SJeremy Kerr 190bc53d35aSJeremy Kerr astlpc = mctp_astlpc_init_fileio(); 1918e31cfd1SJeremy Kerr if (!astlpc) { 1928e31cfd1SJeremy Kerr warnx("could not initialise astlpc binding"); 1938e31cfd1SJeremy Kerr return -1; 1948e31cfd1SJeremy Kerr } 1958e31cfd1SJeremy Kerr 1963b36d17cSJeremy Kerr mctp_register_bus(mctp, mctp_binding_astlpc_core(astlpc), eid); 1973b36d17cSJeremy Kerr 1988e31cfd1SJeremy Kerr binding->data = astlpc; 1998e31cfd1SJeremy Kerr return 0; 2008e31cfd1SJeremy Kerr } 2018e31cfd1SJeremy Kerr 2028e31cfd1SJeremy Kerr static int binding_astlpc_get_fd(struct binding *binding) 2038e31cfd1SJeremy Kerr { 2048e31cfd1SJeremy Kerr return mctp_astlpc_get_fd(binding->data); 2058e31cfd1SJeremy Kerr } 2068e31cfd1SJeremy Kerr 2078e31cfd1SJeremy Kerr static int binding_astlpc_process(struct binding *binding) 2088e31cfd1SJeremy Kerr { 2098e31cfd1SJeremy Kerr return mctp_astlpc_poll(binding->data); 2108e31cfd1SJeremy Kerr } 2118e31cfd1SJeremy Kerr 2128e31cfd1SJeremy Kerr struct binding bindings[] = { 2138e31cfd1SJeremy Kerr { 21434b9b3d8SJeremy Kerr .name = "null", 21534b9b3d8SJeremy Kerr .init = binding_null_init, 21634b9b3d8SJeremy Kerr }, 21734b9b3d8SJeremy Kerr { 2188e31cfd1SJeremy Kerr .name = "serial", 2198e31cfd1SJeremy Kerr .init = binding_serial_init, 2208e31cfd1SJeremy Kerr .get_fd = binding_serial_get_fd, 2218e31cfd1SJeremy Kerr .process = binding_serial_process, 2228e31cfd1SJeremy Kerr }, 2238e31cfd1SJeremy Kerr { 2248e31cfd1SJeremy Kerr .name = "astlpc", 2258e31cfd1SJeremy Kerr .init = binding_astlpc_init, 2268e31cfd1SJeremy Kerr .get_fd = binding_astlpc_get_fd, 2278e31cfd1SJeremy Kerr .process = binding_astlpc_process, 2288e31cfd1SJeremy Kerr } 2298e31cfd1SJeremy Kerr }; 2308e31cfd1SJeremy Kerr 2318e31cfd1SJeremy Kerr struct binding *binding_lookup(const char *name) 2328e31cfd1SJeremy Kerr { 2338e31cfd1SJeremy Kerr struct binding *binding; 2348e31cfd1SJeremy Kerr unsigned int i; 2358e31cfd1SJeremy Kerr 2368e31cfd1SJeremy Kerr for (i = 0; i < ARRAY_SIZE(bindings); i++) { 2378e31cfd1SJeremy Kerr binding = &bindings[i]; 2388e31cfd1SJeremy Kerr 2398e31cfd1SJeremy Kerr if (!strcmp(binding->name, name)) 2408e31cfd1SJeremy Kerr return binding; 2418e31cfd1SJeremy Kerr } 2428e31cfd1SJeremy Kerr 2438e31cfd1SJeremy Kerr return NULL; 2448e31cfd1SJeremy Kerr } 2458e31cfd1SJeremy Kerr 2468e31cfd1SJeremy Kerr static int socket_init(struct ctx *ctx) 2478e31cfd1SJeremy Kerr { 2488e31cfd1SJeremy Kerr struct sockaddr_un addr; 2498e31cfd1SJeremy Kerr int namelen, rc; 2508e31cfd1SJeremy Kerr 2518e31cfd1SJeremy Kerr namelen = sizeof(sockname) - 1; 2528e31cfd1SJeremy Kerr addr.sun_family = AF_UNIX; 2538e31cfd1SJeremy Kerr memcpy(addr.sun_path, sockname, namelen); 2548e31cfd1SJeremy Kerr 2558e31cfd1SJeremy Kerr ctx->sock = socket(AF_UNIX, SOCK_SEQPACKET, 0); 2568e31cfd1SJeremy Kerr if (ctx->sock < 0) { 2578e31cfd1SJeremy Kerr warn("can't create socket"); 2588e31cfd1SJeremy Kerr return -1; 2598e31cfd1SJeremy Kerr } 2608e31cfd1SJeremy Kerr 2618e31cfd1SJeremy Kerr rc = bind(ctx->sock, (struct sockaddr *)&addr, 2628e31cfd1SJeremy Kerr sizeof(addr.sun_family) + namelen); 2638e31cfd1SJeremy Kerr if (rc) { 2648e31cfd1SJeremy Kerr warn("can't bind socket"); 2658e31cfd1SJeremy Kerr goto err_close; 2668e31cfd1SJeremy Kerr } 2678e31cfd1SJeremy Kerr 2688e31cfd1SJeremy Kerr rc = listen(ctx->sock, 1); 2698e31cfd1SJeremy Kerr if (rc) { 2708e31cfd1SJeremy Kerr warn("can't listen on socket"); 2718e31cfd1SJeremy Kerr goto err_close; 2728e31cfd1SJeremy Kerr } 2738e31cfd1SJeremy Kerr 2748e31cfd1SJeremy Kerr return 0; 2758e31cfd1SJeremy Kerr 2768e31cfd1SJeremy Kerr err_close: 2778e31cfd1SJeremy Kerr close(ctx->sock); 2788e31cfd1SJeremy Kerr return -1; 2798e31cfd1SJeremy Kerr } 2808e31cfd1SJeremy Kerr 2818e31cfd1SJeremy Kerr static int socket_process(struct ctx *ctx) 2828e31cfd1SJeremy Kerr { 2838e31cfd1SJeremy Kerr struct client *client; 2848e31cfd1SJeremy Kerr int fd; 2858e31cfd1SJeremy Kerr 2868e31cfd1SJeremy Kerr fd = accept4(ctx->sock, NULL, 0, SOCK_NONBLOCK); 2878e31cfd1SJeremy Kerr if (fd < 0) 2888e31cfd1SJeremy Kerr return -1; 2898e31cfd1SJeremy Kerr 2908e31cfd1SJeremy Kerr ctx->n_clients++; 2918e31cfd1SJeremy Kerr ctx->clients = realloc(ctx->clients, 2928e31cfd1SJeremy Kerr ctx->n_clients * sizeof(struct client)); 2938e31cfd1SJeremy Kerr 2948e31cfd1SJeremy Kerr client = &ctx->clients[ctx->n_clients-1]; 2958676c934SAndrew Jeffery memset(client, 0, sizeof(*client)); 2968e31cfd1SJeremy Kerr client->active = true; 2978e31cfd1SJeremy Kerr client->sock = fd; 2988e31cfd1SJeremy Kerr 2998e31cfd1SJeremy Kerr return 0; 3008e31cfd1SJeremy Kerr } 3018e31cfd1SJeremy Kerr 3028e31cfd1SJeremy Kerr static int client_process_recv(struct ctx *ctx, int idx) 3038e31cfd1SJeremy Kerr { 3048e31cfd1SJeremy Kerr struct client *client = &ctx->clients[idx]; 305f49b2ac8SJeremy Kerr uint8_t eid; 306f49b2ac8SJeremy Kerr ssize_t len; 3078e31cfd1SJeremy Kerr int rc; 3088e31cfd1SJeremy Kerr 3098e31cfd1SJeremy Kerr /* are we waiting for a type message? */ 3108e31cfd1SJeremy Kerr if (!client->type) { 3118e31cfd1SJeremy Kerr uint8_t type; 3128e31cfd1SJeremy Kerr rc = read(client->sock, &type, 1); 3138e31cfd1SJeremy Kerr if (rc <= 0) 3148e31cfd1SJeremy Kerr goto out_close; 3158e31cfd1SJeremy Kerr 3168e31cfd1SJeremy Kerr if (type == 0) { 3178e31cfd1SJeremy Kerr rc = -1; 3188e31cfd1SJeremy Kerr goto out_close; 3198e31cfd1SJeremy Kerr } 3208e31cfd1SJeremy Kerr if (ctx->verbose) 3218e31cfd1SJeremy Kerr fprintf(stderr, "client[%d] registered for type %u\n", 3228e31cfd1SJeremy Kerr idx, type); 3238e31cfd1SJeremy Kerr client->type = type; 3248e31cfd1SJeremy Kerr return 0; 3258e31cfd1SJeremy Kerr } 3268e31cfd1SJeremy Kerr 327f49b2ac8SJeremy Kerr len = recv(client->sock, NULL, 0, MSG_PEEK | MSG_TRUNC); 328f49b2ac8SJeremy Kerr if (len < 0) { 329f49b2ac8SJeremy Kerr warn("can't receive(peek) from client"); 330*13a4041fSAndrew Jeffery rc = -1; 331f49b2ac8SJeremy Kerr goto out_close; 332f49b2ac8SJeremy Kerr } 333f49b2ac8SJeremy Kerr 334f49b2ac8SJeremy Kerr if (len > ctx->buf_size) { 335f49b2ac8SJeremy Kerr void *tmp; 336f49b2ac8SJeremy Kerr 337f49b2ac8SJeremy Kerr tmp = realloc(ctx->buf, len); 338f49b2ac8SJeremy Kerr if (!tmp) { 339f49b2ac8SJeremy Kerr warn("can't allocate for incoming message"); 340*13a4041fSAndrew Jeffery rc = -1; 341f49b2ac8SJeremy Kerr goto out_close; 342f49b2ac8SJeremy Kerr } 343f49b2ac8SJeremy Kerr ctx->buf = tmp; 344f49b2ac8SJeremy Kerr ctx->buf_size = len; 345f49b2ac8SJeremy Kerr } 346f49b2ac8SJeremy Kerr 347f49b2ac8SJeremy Kerr rc = recv(client->sock, ctx->buf, ctx->buf_size, 0); 3488e31cfd1SJeremy Kerr if (rc < 0) { 3498e31cfd1SJeremy Kerr warn("can't receive from client"); 350*13a4041fSAndrew Jeffery rc = -1; 3518e31cfd1SJeremy Kerr goto out_close; 3528e31cfd1SJeremy Kerr } 3538e31cfd1SJeremy Kerr 354195a7c5eSJeremy Kerr if (rc <= 0) { 3558e31cfd1SJeremy Kerr rc = -1; 3568e31cfd1SJeremy Kerr goto out_close; 3578e31cfd1SJeremy Kerr } 3588e31cfd1SJeremy Kerr 359f49b2ac8SJeremy Kerr eid = *(uint8_t *)ctx->buf; 360d690d8eaSJeremy Kerr 3618e31cfd1SJeremy Kerr if (ctx->verbose) 3628e31cfd1SJeremy Kerr fprintf(stderr, 3638e31cfd1SJeremy Kerr "client[%d] sent message: dest 0x%02x len %d\n", 3648e31cfd1SJeremy Kerr idx, eid, rc - 1); 3658e31cfd1SJeremy Kerr 366195a7c5eSJeremy Kerr 367195a7c5eSJeremy Kerr if (eid == ctx->local_eid) 368f49b2ac8SJeremy Kerr rx_message(eid, ctx, ctx->buf + 1, rc - 1); 369195a7c5eSJeremy Kerr else 370f49b2ac8SJeremy Kerr tx_message(ctx, eid, ctx->buf + 1, rc - 1); 3718e31cfd1SJeremy Kerr 3728e31cfd1SJeremy Kerr return 0; 3738e31cfd1SJeremy Kerr 3748e31cfd1SJeremy Kerr out_close: 3758e31cfd1SJeremy Kerr client->active = false; 3768e31cfd1SJeremy Kerr return rc; 3778e31cfd1SJeremy Kerr } 3788e31cfd1SJeremy Kerr 3798e31cfd1SJeremy Kerr static int binding_init(struct ctx *ctx, const char *name, 3808e31cfd1SJeremy Kerr int argc, char * const *argv) 3818e31cfd1SJeremy Kerr { 3828e31cfd1SJeremy Kerr int rc; 3838e31cfd1SJeremy Kerr 3848e31cfd1SJeremy Kerr ctx->binding = binding_lookup(name); 3858e31cfd1SJeremy Kerr if (!ctx->binding) { 3868e31cfd1SJeremy Kerr warnx("no such binding '%s'", name); 3878e31cfd1SJeremy Kerr return -1; 3888e31cfd1SJeremy Kerr } 3898e31cfd1SJeremy Kerr 3908e31cfd1SJeremy Kerr rc = ctx->binding->init(ctx->mctp, ctx->binding, ctx->local_eid, 3918e31cfd1SJeremy Kerr argc, argv); 3928e31cfd1SJeremy Kerr return rc; 3938e31cfd1SJeremy Kerr } 3948e31cfd1SJeremy Kerr 3958e31cfd1SJeremy Kerr enum { 3968e31cfd1SJeremy Kerr FD_BINDING = 0, 3978e31cfd1SJeremy Kerr FD_SOCKET, 3988e31cfd1SJeremy Kerr FD_NR, 3998e31cfd1SJeremy Kerr }; 4008e31cfd1SJeremy Kerr 4018e31cfd1SJeremy Kerr static int run_daemon(struct ctx *ctx) 4028e31cfd1SJeremy Kerr { 4038e31cfd1SJeremy Kerr bool clients_changed = false; 4048e31cfd1SJeremy Kerr int rc, i; 4058e31cfd1SJeremy Kerr 4068e31cfd1SJeremy Kerr ctx->pollfds = malloc(FD_NR * sizeof(struct pollfd)); 4078e31cfd1SJeremy Kerr 40834b9b3d8SJeremy Kerr if (ctx->binding->get_fd) { 4098e31cfd1SJeremy Kerr ctx->pollfds[FD_BINDING].fd = 4108e31cfd1SJeremy Kerr ctx->binding->get_fd(ctx->binding); 4118e31cfd1SJeremy Kerr ctx->pollfds[FD_BINDING].events = POLLIN; 41234b9b3d8SJeremy Kerr } else { 41334b9b3d8SJeremy Kerr ctx->pollfds[FD_BINDING].fd = -1; 41434b9b3d8SJeremy Kerr ctx->pollfds[FD_BINDING].events = 0; 41534b9b3d8SJeremy Kerr } 4168e31cfd1SJeremy Kerr 4178e31cfd1SJeremy Kerr ctx->pollfds[FD_SOCKET].fd = ctx->sock; 4188e31cfd1SJeremy Kerr ctx->pollfds[FD_SOCKET].events = POLLIN; 4198e31cfd1SJeremy Kerr 4208e31cfd1SJeremy Kerr mctp_set_rx_all(ctx->mctp, rx_message, ctx); 4218e31cfd1SJeremy Kerr 4228e31cfd1SJeremy Kerr for (;;) { 4238e31cfd1SJeremy Kerr if (clients_changed) { 4248e31cfd1SJeremy Kerr int i; 4258e31cfd1SJeremy Kerr 4268e31cfd1SJeremy Kerr ctx->pollfds = realloc(ctx->pollfds, 4278e31cfd1SJeremy Kerr (ctx->n_clients + FD_NR) * 4288e31cfd1SJeremy Kerr sizeof(struct pollfd)); 4298e31cfd1SJeremy Kerr 4308e31cfd1SJeremy Kerr for (i = 0; i < ctx->n_clients; i++) { 4318e31cfd1SJeremy Kerr ctx->pollfds[FD_NR+i].fd = 4328e31cfd1SJeremy Kerr ctx->clients[i].sock; 4338e31cfd1SJeremy Kerr ctx->pollfds[FD_NR+i].events = POLLIN; 4348e31cfd1SJeremy Kerr } 4358e31cfd1SJeremy Kerr clients_changed = false; 4368e31cfd1SJeremy Kerr } 4378e31cfd1SJeremy Kerr 4388e31cfd1SJeremy Kerr rc = poll(ctx->pollfds, ctx->n_clients + FD_NR, -1); 4398e31cfd1SJeremy Kerr if (rc < 0) { 4408e31cfd1SJeremy Kerr warn("poll failed"); 4418e31cfd1SJeremy Kerr break; 4428e31cfd1SJeremy Kerr } 4438e31cfd1SJeremy Kerr 4448e31cfd1SJeremy Kerr if (!rc) 4458e31cfd1SJeremy Kerr continue; 4468e31cfd1SJeremy Kerr 4478e31cfd1SJeremy Kerr if (ctx->pollfds[FD_BINDING].revents) { 44834b9b3d8SJeremy Kerr rc = 0; 44934b9b3d8SJeremy Kerr if (ctx->binding->process) 4508e31cfd1SJeremy Kerr rc = ctx->binding->process(ctx->binding); 4518e31cfd1SJeremy Kerr if (rc) 4528e31cfd1SJeremy Kerr break; 4538e31cfd1SJeremy Kerr } 4548e31cfd1SJeremy Kerr 4558e31cfd1SJeremy Kerr for (i = 0; i < ctx->n_clients; i++) { 4568e31cfd1SJeremy Kerr if (!ctx->pollfds[FD_NR+i].revents) 4578e31cfd1SJeremy Kerr continue; 4588e31cfd1SJeremy Kerr 4598e31cfd1SJeremy Kerr rc = client_process_recv(ctx, i); 4608e31cfd1SJeremy Kerr if (rc) 4618e31cfd1SJeremy Kerr clients_changed = true; 4628e31cfd1SJeremy Kerr } 4638e31cfd1SJeremy Kerr 4648e31cfd1SJeremy Kerr if (ctx->pollfds[FD_SOCKET].revents) { 4658e31cfd1SJeremy Kerr rc = socket_process(ctx); 4668e31cfd1SJeremy Kerr if (rc) 4678e31cfd1SJeremy Kerr break; 4688e31cfd1SJeremy Kerr clients_changed = true; 4698e31cfd1SJeremy Kerr } 4708e31cfd1SJeremy Kerr 4718e31cfd1SJeremy Kerr if (clients_changed) 4728e31cfd1SJeremy Kerr client_remove_inactive(ctx); 4738e31cfd1SJeremy Kerr 4748e31cfd1SJeremy Kerr } 4758e31cfd1SJeremy Kerr 4768e31cfd1SJeremy Kerr 4778e31cfd1SJeremy Kerr free(ctx->pollfds); 4788e31cfd1SJeremy Kerr 4798e31cfd1SJeremy Kerr return rc; 4808e31cfd1SJeremy Kerr } 4818e31cfd1SJeremy Kerr 4828e31cfd1SJeremy Kerr static const struct option options[] = { 4838e31cfd1SJeremy Kerr { "verbose", no_argument, 0, 'v' }, 4848e31cfd1SJeremy Kerr { "eid", required_argument, 0, 'e' }, 4858e31cfd1SJeremy Kerr { 0 }, 4868e31cfd1SJeremy Kerr }; 4878e31cfd1SJeremy Kerr 4888e31cfd1SJeremy Kerr static void usage(const char *progname) 4898e31cfd1SJeremy Kerr { 4908e31cfd1SJeremy Kerr unsigned int i; 4918e31cfd1SJeremy Kerr 4928e31cfd1SJeremy Kerr fprintf(stderr, "usage: %s <binding> [params]\n", progname); 4938e31cfd1SJeremy Kerr fprintf(stderr, "Available bindings:\n"); 4948e31cfd1SJeremy Kerr for (i = 0; i < ARRAY_SIZE(bindings); i++) 4958e31cfd1SJeremy Kerr fprintf(stderr, " %s\n", bindings[i].name); 4968e31cfd1SJeremy Kerr } 4978e31cfd1SJeremy Kerr 4988e31cfd1SJeremy Kerr int main(int argc, char * const *argv) 4998e31cfd1SJeremy Kerr { 5008e31cfd1SJeremy Kerr struct ctx *ctx, _ctx; 5018e31cfd1SJeremy Kerr int rc; 5028e31cfd1SJeremy Kerr 5038e31cfd1SJeremy Kerr ctx = &_ctx; 5048e31cfd1SJeremy Kerr ctx->clients = NULL; 5058e31cfd1SJeremy Kerr ctx->n_clients = 0; 5068e31cfd1SJeremy Kerr ctx->local_eid = local_eid_default; 50704b81fc7SAndrew Jeffery ctx->verbose = false; 5088e31cfd1SJeremy Kerr 5098e31cfd1SJeremy Kerr for (;;) { 5108e31cfd1SJeremy Kerr rc = getopt_long(argc, argv, "e:v", options, NULL); 5118e31cfd1SJeremy Kerr if (rc == -1) 5128e31cfd1SJeremy Kerr break; 5138e31cfd1SJeremy Kerr switch (rc) { 5148e31cfd1SJeremy Kerr case 'v': 5158e31cfd1SJeremy Kerr ctx->verbose = true; 5168e31cfd1SJeremy Kerr break; 5178e31cfd1SJeremy Kerr case 'e': 5188e31cfd1SJeremy Kerr ctx->local_eid = atoi(optarg); 5198e31cfd1SJeremy Kerr break; 5208e31cfd1SJeremy Kerr default: 5218e31cfd1SJeremy Kerr fprintf(stderr, "Invalid argument\n"); 5228e31cfd1SJeremy Kerr return EXIT_FAILURE; 5238e31cfd1SJeremy Kerr } 5248e31cfd1SJeremy Kerr } 5258e31cfd1SJeremy Kerr 5268e31cfd1SJeremy Kerr if (optind >= argc) { 5278e31cfd1SJeremy Kerr fprintf(stderr, "missing binding argument\n"); 5288e31cfd1SJeremy Kerr usage(argv[0]); 5298e31cfd1SJeremy Kerr return EXIT_FAILURE; 5308e31cfd1SJeremy Kerr } 5318e31cfd1SJeremy Kerr 532f49b2ac8SJeremy Kerr /* setup initial buffer */ 533f49b2ac8SJeremy Kerr ctx->buf_size = 4096; 534f49b2ac8SJeremy Kerr ctx->buf = malloc(ctx->buf_size); 535f49b2ac8SJeremy Kerr 5360b278a63SJeremy Kerr mctp_set_log_stdio(ctx->verbose ? MCTP_LOG_DEBUG : MCTP_LOG_WARNING); 5370b278a63SJeremy Kerr 5388e31cfd1SJeremy Kerr ctx->mctp = mctp_init(); 5398e31cfd1SJeremy Kerr assert(ctx->mctp); 5408e31cfd1SJeremy Kerr 5418e31cfd1SJeremy Kerr rc = binding_init(ctx, argv[optind], argc - optind - 1, argv + optind + 1); 5428e31cfd1SJeremy Kerr if (rc) 5438e31cfd1SJeremy Kerr return EXIT_FAILURE; 5448e31cfd1SJeremy Kerr 5458e31cfd1SJeremy Kerr rc = socket_init(ctx); 5468e31cfd1SJeremy Kerr if (rc) 5478e31cfd1SJeremy Kerr return EXIT_FAILURE; 5488e31cfd1SJeremy Kerr 5498e31cfd1SJeremy Kerr rc = run_daemon(ctx); 5508e31cfd1SJeremy Kerr 5518e31cfd1SJeremy Kerr return rc ? EXIT_FAILURE : EXIT_SUCCESS; 5528e31cfd1SJeremy Kerr 5538e31cfd1SJeremy Kerr } 554