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> 76896d41eSAndrew Jeffery #include <errno.h> 88e31cfd1SJeremy Kerr #include <getopt.h> 9b93b6112SAndrew Jeffery #include <limits.h> 108e31cfd1SJeremy Kerr #include <poll.h> 1104b81fc7SAndrew Jeffery #include <stdbool.h> 128e31cfd1SJeremy Kerr #include <stdio.h> 138e31cfd1SJeremy Kerr #include <stdlib.h> 148e31cfd1SJeremy Kerr #include <string.h> 158e31cfd1SJeremy Kerr #include <unistd.h> 168e31cfd1SJeremy Kerr 178e31cfd1SJeremy Kerr #include <sys/socket.h> 188e31cfd1SJeremy Kerr #include <sys/un.h> 198e31cfd1SJeremy Kerr 208e31cfd1SJeremy Kerr #include "libmctp.h" 218e31cfd1SJeremy Kerr #include "libmctp-serial.h" 228e31cfd1SJeremy Kerr #include "libmctp-astlpc.h" 238e31cfd1SJeremy Kerr 248e31cfd1SJeremy Kerr #define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0])) 2534b9b3d8SJeremy Kerr #define __unused __attribute__((unused)) 268e31cfd1SJeremy Kerr 278e31cfd1SJeremy Kerr static const mctp_eid_t local_eid_default = 8; 288e31cfd1SJeremy Kerr static char sockname[] = "\0mctp-mux"; 298e31cfd1SJeremy Kerr 308e31cfd1SJeremy Kerr struct binding { 318e31cfd1SJeremy Kerr const char *name; 328e31cfd1SJeremy Kerr int (*init)(struct mctp *mctp, struct binding *binding, 338e31cfd1SJeremy Kerr mctp_eid_t eid, int n_params, 348e31cfd1SJeremy Kerr char * const * params); 358e31cfd1SJeremy Kerr int (*get_fd)(struct binding *binding); 368e31cfd1SJeremy Kerr int (*process)(struct binding *binding); 378e31cfd1SJeremy Kerr void *data; 388e31cfd1SJeremy Kerr }; 398e31cfd1SJeremy Kerr 408e31cfd1SJeremy Kerr struct client { 418e31cfd1SJeremy Kerr bool active; 428e31cfd1SJeremy Kerr int sock; 438e31cfd1SJeremy Kerr uint8_t type; 448e31cfd1SJeremy Kerr }; 458e31cfd1SJeremy Kerr 468e31cfd1SJeremy Kerr struct ctx { 478e31cfd1SJeremy Kerr struct mctp *mctp; 488e31cfd1SJeremy Kerr struct binding *binding; 498e31cfd1SJeremy Kerr bool verbose; 508e31cfd1SJeremy Kerr int local_eid; 51f49b2ac8SJeremy Kerr void *buf; 52f49b2ac8SJeremy Kerr size_t buf_size; 538e31cfd1SJeremy Kerr 548e31cfd1SJeremy Kerr int sock; 558e31cfd1SJeremy Kerr struct pollfd *pollfds; 568e31cfd1SJeremy Kerr 578e31cfd1SJeremy Kerr struct client *clients; 588e31cfd1SJeremy Kerr int n_clients; 598e31cfd1SJeremy Kerr }; 608e31cfd1SJeremy Kerr 618e31cfd1SJeremy Kerr static void tx_message(struct ctx *ctx, mctp_eid_t eid, void *msg, size_t len) 628e31cfd1SJeremy Kerr { 63*06735055SAndrew Jeffery int rc; 64*06735055SAndrew Jeffery 65*06735055SAndrew Jeffery rc = mctp_message_tx(ctx->mctp, eid, msg, len); 66*06735055SAndrew Jeffery if (rc) 67*06735055SAndrew Jeffery warnx("Failed to send message: %d", rc); 688e31cfd1SJeremy Kerr } 698e31cfd1SJeremy Kerr 708e31cfd1SJeremy Kerr static void client_remove_inactive(struct ctx *ctx) 718e31cfd1SJeremy Kerr { 728e31cfd1SJeremy Kerr int i; 738e31cfd1SJeremy Kerr 748e31cfd1SJeremy Kerr for (i = 0; i < ctx->n_clients; i++) { 758e31cfd1SJeremy Kerr struct client *client = &ctx->clients[i]; 768e31cfd1SJeremy Kerr if (client->active) 778e31cfd1SJeremy Kerr continue; 788e31cfd1SJeremy Kerr close(client->sock); 798e31cfd1SJeremy Kerr 808e31cfd1SJeremy Kerr ctx->n_clients--; 818e31cfd1SJeremy Kerr memmove(&ctx->clients[i], &ctx->clients[i+1], 828e31cfd1SJeremy Kerr (ctx->n_clients - i) * sizeof(*ctx->clients)); 838e31cfd1SJeremy Kerr ctx->clients = realloc(ctx->clients, 848e31cfd1SJeremy Kerr ctx->n_clients * sizeof(*ctx->clients)); 858e31cfd1SJeremy Kerr } 868e31cfd1SJeremy Kerr } 878e31cfd1SJeremy Kerr 888e31cfd1SJeremy Kerr static void rx_message(uint8_t eid, void *data, void *msg, size_t len) 898e31cfd1SJeremy Kerr { 908e31cfd1SJeremy Kerr struct ctx *ctx = data; 918e31cfd1SJeremy Kerr struct iovec iov[2]; 928e31cfd1SJeremy Kerr struct msghdr msghdr; 938e31cfd1SJeremy Kerr bool removed; 948e31cfd1SJeremy Kerr uint8_t type; 958e31cfd1SJeremy Kerr int i, rc; 968e31cfd1SJeremy Kerr 978e31cfd1SJeremy Kerr if (len < 2) 988e31cfd1SJeremy Kerr return; 998e31cfd1SJeremy Kerr 1008e31cfd1SJeremy Kerr type = *(uint8_t *)msg; 1018e31cfd1SJeremy Kerr 1028e31cfd1SJeremy Kerr if (ctx->verbose) 1038e31cfd1SJeremy Kerr fprintf(stderr, "MCTP message received: len %zd, type %d\n", 1048e31cfd1SJeremy Kerr len, type); 1058e31cfd1SJeremy Kerr 1068e31cfd1SJeremy Kerr memset(&msghdr, 0, sizeof(msghdr)); 1078e31cfd1SJeremy Kerr msghdr.msg_iov = iov; 1088e31cfd1SJeremy Kerr msghdr.msg_iovlen = 2; 1098e31cfd1SJeremy Kerr iov[0].iov_base = &eid; 1108e31cfd1SJeremy Kerr iov[0].iov_len = 1; 1118e31cfd1SJeremy Kerr iov[1].iov_base = msg; 1128e31cfd1SJeremy Kerr iov[1].iov_len = len; 1138e31cfd1SJeremy Kerr 1148e31cfd1SJeremy Kerr for (i = 0; i < ctx->n_clients; i++) { 1158e31cfd1SJeremy Kerr struct client *client = &ctx->clients[i]; 1168e31cfd1SJeremy Kerr 1178e31cfd1SJeremy Kerr if (client->type != type) 1188e31cfd1SJeremy Kerr continue; 1198e31cfd1SJeremy Kerr 1208e31cfd1SJeremy Kerr if (ctx->verbose) 1218e31cfd1SJeremy Kerr fprintf(stderr, " forwarding to client %d\n", i); 1228e31cfd1SJeremy Kerr 1238e31cfd1SJeremy Kerr rc = sendmsg(client->sock, &msghdr, 0); 1248e31cfd1SJeremy Kerr if (rc != (ssize_t)(len + 1)) { 1258e31cfd1SJeremy Kerr client->active = false; 1268e31cfd1SJeremy Kerr removed = true; 1278e31cfd1SJeremy Kerr } 1288e31cfd1SJeremy Kerr } 1298e31cfd1SJeremy Kerr 1308e31cfd1SJeremy Kerr if (removed) 1318e31cfd1SJeremy Kerr client_remove_inactive(ctx); 1328e31cfd1SJeremy Kerr 1338e31cfd1SJeremy Kerr } 1348e31cfd1SJeremy Kerr 13534b9b3d8SJeremy Kerr static int binding_null_init(struct mctp *mctp __unused, 13634b9b3d8SJeremy Kerr struct binding *binding __unused, 13734b9b3d8SJeremy Kerr mctp_eid_t eid __unused, 13834b9b3d8SJeremy Kerr int n_params, char * const *params __unused) 13934b9b3d8SJeremy Kerr { 14034b9b3d8SJeremy Kerr if (n_params != 0) { 14134b9b3d8SJeremy Kerr warnx("null binding doesn't accept parameters"); 14234b9b3d8SJeremy Kerr return -1; 14334b9b3d8SJeremy Kerr } 14434b9b3d8SJeremy Kerr return 0; 14534b9b3d8SJeremy Kerr } 14634b9b3d8SJeremy Kerr 1478e31cfd1SJeremy Kerr static int binding_serial_init(struct mctp *mctp, struct binding *binding, 1488e31cfd1SJeremy Kerr mctp_eid_t eid, int n_params, char * const *params) 1498e31cfd1SJeremy Kerr { 1508e31cfd1SJeremy Kerr struct mctp_binding_serial *serial; 1518e31cfd1SJeremy Kerr const char *path; 1528e31cfd1SJeremy Kerr int rc; 1538e31cfd1SJeremy Kerr 1548e31cfd1SJeremy Kerr if (n_params != 1) { 1558e31cfd1SJeremy Kerr warnx("serial binding requires device param"); 1568e31cfd1SJeremy Kerr return -1; 1578e31cfd1SJeremy Kerr } 1588e31cfd1SJeremy Kerr 1598e31cfd1SJeremy Kerr path = params[0]; 1608e31cfd1SJeremy Kerr 1618e31cfd1SJeremy Kerr serial = mctp_serial_init(); 1628e31cfd1SJeremy Kerr assert(serial); 1638e31cfd1SJeremy Kerr 1648e31cfd1SJeremy Kerr rc = mctp_serial_open_path(serial, path); 1658e31cfd1SJeremy Kerr if (rc) 1668e31cfd1SJeremy Kerr return -1; 1678e31cfd1SJeremy Kerr 1683b36d17cSJeremy Kerr mctp_register_bus(mctp, mctp_binding_serial_core(serial), eid); 1698e31cfd1SJeremy Kerr 1708e31cfd1SJeremy Kerr binding->data = serial; 1718e31cfd1SJeremy Kerr 1728e31cfd1SJeremy Kerr return 0; 1738e31cfd1SJeremy Kerr } 1748e31cfd1SJeremy Kerr 1758e31cfd1SJeremy Kerr static int binding_serial_get_fd(struct binding *binding) 1768e31cfd1SJeremy Kerr { 1778e31cfd1SJeremy Kerr return mctp_serial_get_fd(binding->data); 1788e31cfd1SJeremy Kerr } 1798e31cfd1SJeremy Kerr 1808e31cfd1SJeremy Kerr static int binding_serial_process(struct binding *binding) 1818e31cfd1SJeremy Kerr { 1828e31cfd1SJeremy Kerr return mctp_serial_read(binding->data); 1838e31cfd1SJeremy Kerr } 1848e31cfd1SJeremy Kerr 1858e31cfd1SJeremy Kerr static int binding_astlpc_init(struct mctp *mctp, struct binding *binding, 1868e31cfd1SJeremy Kerr mctp_eid_t eid, int n_params, 1878e31cfd1SJeremy Kerr char * const *params __attribute__((unused))) 1888e31cfd1SJeremy Kerr { 1898e31cfd1SJeremy Kerr struct mctp_binding_astlpc *astlpc; 1908e31cfd1SJeremy Kerr 1918e31cfd1SJeremy Kerr if (n_params) { 1928e31cfd1SJeremy Kerr warnx("astlpc binding does not accept parameters"); 1938e31cfd1SJeremy Kerr return -1; 1948e31cfd1SJeremy Kerr } 1958e31cfd1SJeremy Kerr 196bc53d35aSJeremy Kerr astlpc = mctp_astlpc_init_fileio(); 1978e31cfd1SJeremy Kerr if (!astlpc) { 1988e31cfd1SJeremy Kerr warnx("could not initialise astlpc binding"); 1998e31cfd1SJeremy Kerr return -1; 2008e31cfd1SJeremy Kerr } 2018e31cfd1SJeremy Kerr 2023b36d17cSJeremy Kerr mctp_register_bus(mctp, mctp_binding_astlpc_core(astlpc), eid); 2033b36d17cSJeremy Kerr 2048e31cfd1SJeremy Kerr binding->data = astlpc; 2058e31cfd1SJeremy Kerr return 0; 2068e31cfd1SJeremy Kerr } 2078e31cfd1SJeremy Kerr 2088e31cfd1SJeremy Kerr static int binding_astlpc_get_fd(struct binding *binding) 2098e31cfd1SJeremy Kerr { 2108e31cfd1SJeremy Kerr return mctp_astlpc_get_fd(binding->data); 2118e31cfd1SJeremy Kerr } 2128e31cfd1SJeremy Kerr 2138e31cfd1SJeremy Kerr static int binding_astlpc_process(struct binding *binding) 2148e31cfd1SJeremy Kerr { 2158e31cfd1SJeremy Kerr return mctp_astlpc_poll(binding->data); 2168e31cfd1SJeremy Kerr } 2178e31cfd1SJeremy Kerr 2188e31cfd1SJeremy Kerr struct binding bindings[] = { 2198e31cfd1SJeremy Kerr { 22034b9b3d8SJeremy Kerr .name = "null", 22134b9b3d8SJeremy Kerr .init = binding_null_init, 22234b9b3d8SJeremy Kerr }, 22334b9b3d8SJeremy Kerr { 2248e31cfd1SJeremy Kerr .name = "serial", 2258e31cfd1SJeremy Kerr .init = binding_serial_init, 2268e31cfd1SJeremy Kerr .get_fd = binding_serial_get_fd, 2278e31cfd1SJeremy Kerr .process = binding_serial_process, 2288e31cfd1SJeremy Kerr }, 2298e31cfd1SJeremy Kerr { 2308e31cfd1SJeremy Kerr .name = "astlpc", 2318e31cfd1SJeremy Kerr .init = binding_astlpc_init, 2328e31cfd1SJeremy Kerr .get_fd = binding_astlpc_get_fd, 2338e31cfd1SJeremy Kerr .process = binding_astlpc_process, 2348e31cfd1SJeremy Kerr } 2358e31cfd1SJeremy Kerr }; 2368e31cfd1SJeremy Kerr 2378e31cfd1SJeremy Kerr struct binding *binding_lookup(const char *name) 2388e31cfd1SJeremy Kerr { 2398e31cfd1SJeremy Kerr struct binding *binding; 2408e31cfd1SJeremy Kerr unsigned int i; 2418e31cfd1SJeremy Kerr 2428e31cfd1SJeremy Kerr for (i = 0; i < ARRAY_SIZE(bindings); i++) { 2438e31cfd1SJeremy Kerr binding = &bindings[i]; 2448e31cfd1SJeremy Kerr 2458e31cfd1SJeremy Kerr if (!strcmp(binding->name, name)) 2468e31cfd1SJeremy Kerr return binding; 2478e31cfd1SJeremy Kerr } 2488e31cfd1SJeremy Kerr 2498e31cfd1SJeremy Kerr return NULL; 2508e31cfd1SJeremy Kerr } 2518e31cfd1SJeremy Kerr 2528e31cfd1SJeremy Kerr static int socket_init(struct ctx *ctx) 2538e31cfd1SJeremy Kerr { 2548e31cfd1SJeremy Kerr struct sockaddr_un addr; 2558e31cfd1SJeremy Kerr int namelen, rc; 2568e31cfd1SJeremy Kerr 2578e31cfd1SJeremy Kerr namelen = sizeof(sockname) - 1; 2588e31cfd1SJeremy Kerr addr.sun_family = AF_UNIX; 2598e31cfd1SJeremy Kerr memcpy(addr.sun_path, sockname, namelen); 2608e31cfd1SJeremy Kerr 2618e31cfd1SJeremy Kerr ctx->sock = socket(AF_UNIX, SOCK_SEQPACKET, 0); 2628e31cfd1SJeremy Kerr if (ctx->sock < 0) { 2638e31cfd1SJeremy Kerr warn("can't create socket"); 2648e31cfd1SJeremy Kerr return -1; 2658e31cfd1SJeremy Kerr } 2668e31cfd1SJeremy Kerr 2678e31cfd1SJeremy Kerr rc = bind(ctx->sock, (struct sockaddr *)&addr, 2688e31cfd1SJeremy Kerr sizeof(addr.sun_family) + namelen); 2698e31cfd1SJeremy Kerr if (rc) { 2708e31cfd1SJeremy Kerr warn("can't bind socket"); 2718e31cfd1SJeremy Kerr goto err_close; 2728e31cfd1SJeremy Kerr } 2738e31cfd1SJeremy Kerr 2748e31cfd1SJeremy Kerr rc = listen(ctx->sock, 1); 2758e31cfd1SJeremy Kerr if (rc) { 2768e31cfd1SJeremy Kerr warn("can't listen on socket"); 2778e31cfd1SJeremy Kerr goto err_close; 2788e31cfd1SJeremy Kerr } 2798e31cfd1SJeremy Kerr 2808e31cfd1SJeremy Kerr return 0; 2818e31cfd1SJeremy Kerr 2828e31cfd1SJeremy Kerr err_close: 2838e31cfd1SJeremy Kerr close(ctx->sock); 2848e31cfd1SJeremy Kerr return -1; 2858e31cfd1SJeremy Kerr } 2868e31cfd1SJeremy Kerr 2878e31cfd1SJeremy Kerr static int socket_process(struct ctx *ctx) 2888e31cfd1SJeremy Kerr { 2898e31cfd1SJeremy Kerr struct client *client; 2908e31cfd1SJeremy Kerr int fd; 2918e31cfd1SJeremy Kerr 2928e31cfd1SJeremy Kerr fd = accept4(ctx->sock, NULL, 0, SOCK_NONBLOCK); 2938e31cfd1SJeremy Kerr if (fd < 0) 2948e31cfd1SJeremy Kerr return -1; 2958e31cfd1SJeremy Kerr 2968e31cfd1SJeremy Kerr ctx->n_clients++; 2978e31cfd1SJeremy Kerr ctx->clients = realloc(ctx->clients, 2988e31cfd1SJeremy Kerr ctx->n_clients * sizeof(struct client)); 2998e31cfd1SJeremy Kerr 3008e31cfd1SJeremy Kerr client = &ctx->clients[ctx->n_clients-1]; 3018676c934SAndrew Jeffery memset(client, 0, sizeof(*client)); 3028e31cfd1SJeremy Kerr client->active = true; 3038e31cfd1SJeremy Kerr client->sock = fd; 3048e31cfd1SJeremy Kerr 3058e31cfd1SJeremy Kerr return 0; 3068e31cfd1SJeremy Kerr } 3078e31cfd1SJeremy Kerr 3088e31cfd1SJeremy Kerr static int client_process_recv(struct ctx *ctx, int idx) 3098e31cfd1SJeremy Kerr { 3108e31cfd1SJeremy Kerr struct client *client = &ctx->clients[idx]; 311f49b2ac8SJeremy Kerr uint8_t eid; 312f49b2ac8SJeremy Kerr ssize_t len; 3138e31cfd1SJeremy Kerr int rc; 3148e31cfd1SJeremy Kerr 3158e31cfd1SJeremy Kerr /* are we waiting for a type message? */ 3168e31cfd1SJeremy Kerr if (!client->type) { 3178e31cfd1SJeremy Kerr uint8_t type; 3188e31cfd1SJeremy Kerr rc = read(client->sock, &type, 1); 3198e31cfd1SJeremy Kerr if (rc <= 0) 3208e31cfd1SJeremy Kerr goto out_close; 3218e31cfd1SJeremy Kerr 3228e31cfd1SJeremy Kerr if (type == 0) { 3238e31cfd1SJeremy Kerr rc = -1; 3248e31cfd1SJeremy Kerr goto out_close; 3258e31cfd1SJeremy Kerr } 3268e31cfd1SJeremy Kerr if (ctx->verbose) 3278e31cfd1SJeremy Kerr fprintf(stderr, "client[%d] registered for type %u\n", 3288e31cfd1SJeremy Kerr idx, type); 3298e31cfd1SJeremy Kerr client->type = type; 3308e31cfd1SJeremy Kerr return 0; 3318e31cfd1SJeremy Kerr } 3328e31cfd1SJeremy Kerr 333f49b2ac8SJeremy Kerr len = recv(client->sock, NULL, 0, MSG_PEEK | MSG_TRUNC); 334f49b2ac8SJeremy Kerr if (len < 0) { 3356896d41eSAndrew Jeffery if (errno != ECONNRESET) 336f49b2ac8SJeremy Kerr warn("can't receive (peek) from client"); 3376896d41eSAndrew Jeffery 33813a4041fSAndrew Jeffery rc = -1; 339f49b2ac8SJeremy Kerr goto out_close; 340f49b2ac8SJeremy Kerr } 341f49b2ac8SJeremy Kerr 342b93b6112SAndrew Jeffery if ((size_t)len > ctx->buf_size) { 343f49b2ac8SJeremy Kerr void *tmp; 344f49b2ac8SJeremy Kerr 345f49b2ac8SJeremy Kerr tmp = realloc(ctx->buf, len); 346f49b2ac8SJeremy Kerr if (!tmp) { 347f49b2ac8SJeremy Kerr warn("can't allocate for incoming message"); 34813a4041fSAndrew Jeffery rc = -1; 349f49b2ac8SJeremy Kerr goto out_close; 350f49b2ac8SJeremy Kerr } 351f49b2ac8SJeremy Kerr ctx->buf = tmp; 352f49b2ac8SJeremy Kerr ctx->buf_size = len; 353f49b2ac8SJeremy Kerr } 354f49b2ac8SJeremy Kerr 355f49b2ac8SJeremy Kerr rc = recv(client->sock, ctx->buf, ctx->buf_size, 0); 3568e31cfd1SJeremy Kerr if (rc < 0) { 3576896d41eSAndrew Jeffery if (errno != ECONNRESET) 3588e31cfd1SJeremy Kerr warn("can't receive from client"); 35913a4041fSAndrew Jeffery rc = -1; 3608e31cfd1SJeremy Kerr goto out_close; 3618e31cfd1SJeremy Kerr } 3628e31cfd1SJeremy Kerr 363195a7c5eSJeremy Kerr if (rc <= 0) { 3648e31cfd1SJeremy Kerr rc = -1; 3658e31cfd1SJeremy Kerr goto out_close; 3668e31cfd1SJeremy Kerr } 3678e31cfd1SJeremy Kerr 368f49b2ac8SJeremy Kerr eid = *(uint8_t *)ctx->buf; 369d690d8eaSJeremy Kerr 3708e31cfd1SJeremy Kerr if (ctx->verbose) 3718e31cfd1SJeremy Kerr fprintf(stderr, 3728e31cfd1SJeremy Kerr "client[%d] sent message: dest 0x%02x len %d\n", 3738e31cfd1SJeremy Kerr idx, eid, rc - 1); 3748e31cfd1SJeremy Kerr 375195a7c5eSJeremy Kerr 376195a7c5eSJeremy Kerr if (eid == ctx->local_eid) 377f49b2ac8SJeremy Kerr rx_message(eid, ctx, ctx->buf + 1, rc - 1); 378195a7c5eSJeremy Kerr else 379f49b2ac8SJeremy Kerr tx_message(ctx, eid, ctx->buf + 1, rc - 1); 3808e31cfd1SJeremy Kerr 3818e31cfd1SJeremy Kerr return 0; 3828e31cfd1SJeremy Kerr 3838e31cfd1SJeremy Kerr out_close: 3848e31cfd1SJeremy Kerr client->active = false; 3858e31cfd1SJeremy Kerr return rc; 3868e31cfd1SJeremy Kerr } 3878e31cfd1SJeremy Kerr 3888e31cfd1SJeremy Kerr static int binding_init(struct ctx *ctx, const char *name, 3898e31cfd1SJeremy Kerr int argc, char * const *argv) 3908e31cfd1SJeremy Kerr { 3918e31cfd1SJeremy Kerr int rc; 3928e31cfd1SJeremy Kerr 3938e31cfd1SJeremy Kerr ctx->binding = binding_lookup(name); 3948e31cfd1SJeremy Kerr if (!ctx->binding) { 3958e31cfd1SJeremy Kerr warnx("no such binding '%s'", name); 3968e31cfd1SJeremy Kerr return -1; 3978e31cfd1SJeremy Kerr } 3988e31cfd1SJeremy Kerr 3998e31cfd1SJeremy Kerr rc = ctx->binding->init(ctx->mctp, ctx->binding, ctx->local_eid, 4008e31cfd1SJeremy Kerr argc, argv); 4018e31cfd1SJeremy Kerr return rc; 4028e31cfd1SJeremy Kerr } 4038e31cfd1SJeremy Kerr 4048e31cfd1SJeremy Kerr enum { 4058e31cfd1SJeremy Kerr FD_BINDING = 0, 4068e31cfd1SJeremy Kerr FD_SOCKET, 4078e31cfd1SJeremy Kerr FD_NR, 4088e31cfd1SJeremy Kerr }; 4098e31cfd1SJeremy Kerr 4108e31cfd1SJeremy Kerr static int run_daemon(struct ctx *ctx) 4118e31cfd1SJeremy Kerr { 4128e31cfd1SJeremy Kerr bool clients_changed = false; 4138e31cfd1SJeremy Kerr int rc, i; 4148e31cfd1SJeremy Kerr 4158e31cfd1SJeremy Kerr ctx->pollfds = malloc(FD_NR * sizeof(struct pollfd)); 4168e31cfd1SJeremy Kerr 41734b9b3d8SJeremy Kerr if (ctx->binding->get_fd) { 4188e31cfd1SJeremy Kerr ctx->pollfds[FD_BINDING].fd = 4198e31cfd1SJeremy Kerr ctx->binding->get_fd(ctx->binding); 4208e31cfd1SJeremy Kerr ctx->pollfds[FD_BINDING].events = POLLIN; 42134b9b3d8SJeremy Kerr } else { 42234b9b3d8SJeremy Kerr ctx->pollfds[FD_BINDING].fd = -1; 42334b9b3d8SJeremy Kerr ctx->pollfds[FD_BINDING].events = 0; 42434b9b3d8SJeremy Kerr } 4258e31cfd1SJeremy Kerr 4268e31cfd1SJeremy Kerr ctx->pollfds[FD_SOCKET].fd = ctx->sock; 4278e31cfd1SJeremy Kerr ctx->pollfds[FD_SOCKET].events = POLLIN; 4288e31cfd1SJeremy Kerr 4298e31cfd1SJeremy Kerr mctp_set_rx_all(ctx->mctp, rx_message, ctx); 4308e31cfd1SJeremy Kerr 4318e31cfd1SJeremy Kerr for (;;) { 4328e31cfd1SJeremy Kerr if (clients_changed) { 4338e31cfd1SJeremy Kerr int i; 4348e31cfd1SJeremy Kerr 4358e31cfd1SJeremy Kerr ctx->pollfds = realloc(ctx->pollfds, 4368e31cfd1SJeremy Kerr (ctx->n_clients + FD_NR) * 4378e31cfd1SJeremy Kerr sizeof(struct pollfd)); 4388e31cfd1SJeremy Kerr 4398e31cfd1SJeremy Kerr for (i = 0; i < ctx->n_clients; i++) { 4408e31cfd1SJeremy Kerr ctx->pollfds[FD_NR+i].fd = 4418e31cfd1SJeremy Kerr ctx->clients[i].sock; 4428e31cfd1SJeremy Kerr ctx->pollfds[FD_NR+i].events = POLLIN; 4438e31cfd1SJeremy Kerr } 4448e31cfd1SJeremy Kerr clients_changed = false; 4458e31cfd1SJeremy Kerr } 4468e31cfd1SJeremy Kerr 4478e31cfd1SJeremy Kerr rc = poll(ctx->pollfds, ctx->n_clients + FD_NR, -1); 4488e31cfd1SJeremy Kerr if (rc < 0) { 4498e31cfd1SJeremy Kerr warn("poll failed"); 4508e31cfd1SJeremy Kerr break; 4518e31cfd1SJeremy Kerr } 4528e31cfd1SJeremy Kerr 4538e31cfd1SJeremy Kerr if (!rc) 4548e31cfd1SJeremy Kerr continue; 4558e31cfd1SJeremy Kerr 4568e31cfd1SJeremy Kerr if (ctx->pollfds[FD_BINDING].revents) { 45734b9b3d8SJeremy Kerr rc = 0; 45834b9b3d8SJeremy Kerr if (ctx->binding->process) 4598e31cfd1SJeremy Kerr rc = ctx->binding->process(ctx->binding); 4608e31cfd1SJeremy Kerr if (rc) 4618e31cfd1SJeremy Kerr break; 4628e31cfd1SJeremy Kerr } 4638e31cfd1SJeremy Kerr 4648e31cfd1SJeremy Kerr for (i = 0; i < ctx->n_clients; i++) { 4658e31cfd1SJeremy Kerr if (!ctx->pollfds[FD_NR+i].revents) 4668e31cfd1SJeremy Kerr continue; 4678e31cfd1SJeremy Kerr 4688e31cfd1SJeremy Kerr rc = client_process_recv(ctx, i); 4698e31cfd1SJeremy Kerr if (rc) 4708e31cfd1SJeremy Kerr clients_changed = true; 4718e31cfd1SJeremy Kerr } 4728e31cfd1SJeremy Kerr 4738e31cfd1SJeremy Kerr if (ctx->pollfds[FD_SOCKET].revents) { 4748e31cfd1SJeremy Kerr rc = socket_process(ctx); 4758e31cfd1SJeremy Kerr if (rc) 4768e31cfd1SJeremy Kerr break; 4778e31cfd1SJeremy Kerr clients_changed = true; 4788e31cfd1SJeremy Kerr } 4798e31cfd1SJeremy Kerr 4808e31cfd1SJeremy Kerr if (clients_changed) 4818e31cfd1SJeremy Kerr client_remove_inactive(ctx); 4828e31cfd1SJeremy Kerr 4838e31cfd1SJeremy Kerr } 4848e31cfd1SJeremy Kerr 4858e31cfd1SJeremy Kerr 4868e31cfd1SJeremy Kerr free(ctx->pollfds); 4878e31cfd1SJeremy Kerr 4888e31cfd1SJeremy Kerr return rc; 4898e31cfd1SJeremy Kerr } 4908e31cfd1SJeremy Kerr 4918e31cfd1SJeremy Kerr static const struct option options[] = { 4928e31cfd1SJeremy Kerr { "verbose", no_argument, 0, 'v' }, 4938e31cfd1SJeremy Kerr { "eid", required_argument, 0, 'e' }, 4948e31cfd1SJeremy Kerr { 0 }, 4958e31cfd1SJeremy Kerr }; 4968e31cfd1SJeremy Kerr 4978e31cfd1SJeremy Kerr static void usage(const char *progname) 4988e31cfd1SJeremy Kerr { 4998e31cfd1SJeremy Kerr unsigned int i; 5008e31cfd1SJeremy Kerr 5018e31cfd1SJeremy Kerr fprintf(stderr, "usage: %s <binding> [params]\n", progname); 5028e31cfd1SJeremy Kerr fprintf(stderr, "Available bindings:\n"); 5038e31cfd1SJeremy Kerr for (i = 0; i < ARRAY_SIZE(bindings); i++) 5048e31cfd1SJeremy Kerr fprintf(stderr, " %s\n", bindings[i].name); 5058e31cfd1SJeremy Kerr } 5068e31cfd1SJeremy Kerr 5078e31cfd1SJeremy Kerr int main(int argc, char * const *argv) 5088e31cfd1SJeremy Kerr { 5098e31cfd1SJeremy Kerr struct ctx *ctx, _ctx; 5108e31cfd1SJeremy Kerr int rc; 5118e31cfd1SJeremy Kerr 5128e31cfd1SJeremy Kerr ctx = &_ctx; 5138e31cfd1SJeremy Kerr ctx->clients = NULL; 5148e31cfd1SJeremy Kerr ctx->n_clients = 0; 5158e31cfd1SJeremy Kerr ctx->local_eid = local_eid_default; 51604b81fc7SAndrew Jeffery ctx->verbose = false; 5178e31cfd1SJeremy Kerr 5188e31cfd1SJeremy Kerr for (;;) { 5198e31cfd1SJeremy Kerr rc = getopt_long(argc, argv, "e:v", options, NULL); 5208e31cfd1SJeremy Kerr if (rc == -1) 5218e31cfd1SJeremy Kerr break; 5228e31cfd1SJeremy Kerr switch (rc) { 5238e31cfd1SJeremy Kerr case 'v': 5248e31cfd1SJeremy Kerr ctx->verbose = true; 5258e31cfd1SJeremy Kerr break; 5268e31cfd1SJeremy Kerr case 'e': 5278e31cfd1SJeremy Kerr ctx->local_eid = atoi(optarg); 5288e31cfd1SJeremy Kerr break; 5298e31cfd1SJeremy Kerr default: 5308e31cfd1SJeremy Kerr fprintf(stderr, "Invalid argument\n"); 5318e31cfd1SJeremy Kerr return EXIT_FAILURE; 5328e31cfd1SJeremy Kerr } 5338e31cfd1SJeremy Kerr } 5348e31cfd1SJeremy Kerr 5358e31cfd1SJeremy Kerr if (optind >= argc) { 5368e31cfd1SJeremy Kerr fprintf(stderr, "missing binding argument\n"); 5378e31cfd1SJeremy Kerr usage(argv[0]); 5388e31cfd1SJeremy Kerr return EXIT_FAILURE; 5398e31cfd1SJeremy Kerr } 5408e31cfd1SJeremy Kerr 541f49b2ac8SJeremy Kerr /* setup initial buffer */ 542f49b2ac8SJeremy Kerr ctx->buf_size = 4096; 543f49b2ac8SJeremy Kerr ctx->buf = malloc(ctx->buf_size); 544f49b2ac8SJeremy Kerr 5450b278a63SJeremy Kerr mctp_set_log_stdio(ctx->verbose ? MCTP_LOG_DEBUG : MCTP_LOG_WARNING); 5460b278a63SJeremy Kerr 5478e31cfd1SJeremy Kerr ctx->mctp = mctp_init(); 5488e31cfd1SJeremy Kerr assert(ctx->mctp); 5498e31cfd1SJeremy Kerr 5508e31cfd1SJeremy Kerr rc = binding_init(ctx, argv[optind], argc - optind - 1, argv + optind + 1); 5518e31cfd1SJeremy Kerr if (rc) 5528e31cfd1SJeremy Kerr return EXIT_FAILURE; 5538e31cfd1SJeremy Kerr 5548e31cfd1SJeremy Kerr rc = socket_init(ctx); 5558e31cfd1SJeremy Kerr if (rc) 5568e31cfd1SJeremy Kerr return EXIT_FAILURE; 5578e31cfd1SJeremy Kerr 5588e31cfd1SJeremy Kerr rc = run_daemon(ctx); 5598e31cfd1SJeremy Kerr 5608e31cfd1SJeremy Kerr return rc ? EXIT_FAILURE : EXIT_SUCCESS; 5618e31cfd1SJeremy Kerr 5628e31cfd1SJeremy Kerr } 563