13d36ee2eSJeremy Kerr /* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later */
23d36ee2eSJeremy Kerr
38e31cfd1SJeremy Kerr #define _GNU_SOURCE
48e31cfd1SJeremy Kerr
5*3ef47785SMatt Johnston #ifdef HAVE_CONFIG_H
6d4103f8fSAndrew Jeffery #include "config.h"
7*3ef47785SMatt Johnston #endif
85ab78259SAndrew Jeffery
95ab78259SAndrew Jeffery #define SD_LISTEN_FDS_START 3
105ab78259SAndrew Jeffery
115ab78259SAndrew Jeffery #include "compiler.h"
125ab78259SAndrew Jeffery #include "libmctp.h"
135ab78259SAndrew Jeffery #include "libmctp-serial.h"
145ab78259SAndrew Jeffery #include "libmctp-astlpc.h"
15cad47301SAndrew Jeffery #include "utils/mctp-capture.h"
16d4103f8fSAndrew Jeffery
178e31cfd1SJeremy Kerr #include <assert.h>
188e31cfd1SJeremy Kerr #include <err.h>
196896d41eSAndrew Jeffery #include <errno.h>
208e31cfd1SJeremy Kerr #include <getopt.h>
21b93b6112SAndrew Jeffery #include <limits.h>
228e31cfd1SJeremy Kerr #include <poll.h>
23490e3873SAndrew Jeffery #include <signal.h>
2404b81fc7SAndrew Jeffery #include <stdbool.h>
258e31cfd1SJeremy Kerr #include <stdio.h>
268e31cfd1SJeremy Kerr #include <stdlib.h>
278e31cfd1SJeremy Kerr #include <string.h>
288e31cfd1SJeremy Kerr #include <unistd.h>
298e31cfd1SJeremy Kerr
30490e3873SAndrew Jeffery #include <sys/signalfd.h>
318e31cfd1SJeremy Kerr #include <sys/socket.h>
328e31cfd1SJeremy Kerr #include <sys/un.h>
338e31cfd1SJeremy Kerr
348e31cfd1SJeremy Kerr #define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
358e31cfd1SJeremy Kerr
36d4103f8fSAndrew Jeffery #if HAVE_SYSTEMD_SD_DAEMON_H
37d4103f8fSAndrew Jeffery #include <systemd/sd-daemon.h>
38d4103f8fSAndrew Jeffery #else
sd_listen_fds(int i __unused)39d4103f8fSAndrew Jeffery static inline int sd_listen_fds(int i __unused)
40d4103f8fSAndrew Jeffery {
41d4103f8fSAndrew Jeffery return -1;
42d4103f8fSAndrew Jeffery }
43d4103f8fSAndrew Jeffery #endif
44d4103f8fSAndrew Jeffery
458e31cfd1SJeremy Kerr static const mctp_eid_t local_eid_default = 8;
468e31cfd1SJeremy Kerr static char sockname[] = "\0mctp-mux";
478e31cfd1SJeremy Kerr
488e31cfd1SJeremy Kerr struct binding {
498e31cfd1SJeremy Kerr const char *name;
508f53d631SAndrew Jeffery int (*init)(struct mctp *mctp, struct binding *binding, mctp_eid_t eid,
518f53d631SAndrew Jeffery int n_params, char *const *params);
52edebe169SAndrew Jeffery void (*destroy)(struct mctp *mctp, struct binding *binding);
538f53d631SAndrew Jeffery int (*init_pollfd)(struct binding *binding, struct pollfd *pollfd);
548e31cfd1SJeremy Kerr int (*process)(struct binding *binding);
558e31cfd1SJeremy Kerr void *data;
568e31cfd1SJeremy Kerr };
578e31cfd1SJeremy Kerr
588e31cfd1SJeremy Kerr struct client {
598e31cfd1SJeremy Kerr bool active;
608e31cfd1SJeremy Kerr int sock;
618e31cfd1SJeremy Kerr uint8_t type;
628e31cfd1SJeremy Kerr };
638e31cfd1SJeremy Kerr
648e31cfd1SJeremy Kerr struct ctx {
658e31cfd1SJeremy Kerr struct mctp *mctp;
668e31cfd1SJeremy Kerr struct binding *binding;
678e31cfd1SJeremy Kerr bool verbose;
688e31cfd1SJeremy Kerr int local_eid;
69*3ef47785SMatt Johnston uint8_t *buf;
70f49b2ac8SJeremy Kerr size_t buf_size;
718e31cfd1SJeremy Kerr
728e31cfd1SJeremy Kerr int sock;
738e31cfd1SJeremy Kerr struct pollfd *pollfds;
748e31cfd1SJeremy Kerr
758e31cfd1SJeremy Kerr struct client *clients;
768e31cfd1SJeremy Kerr int n_clients;
77cad47301SAndrew Jeffery
78cad47301SAndrew Jeffery struct {
79cad47301SAndrew Jeffery struct capture binding;
80cad47301SAndrew Jeffery struct capture socket;
81cad47301SAndrew Jeffery } pcap;
828e31cfd1SJeremy Kerr };
838e31cfd1SJeremy Kerr
tx_message(struct ctx * ctx,mctp_eid_t eid,void * msg,size_t len)848e31cfd1SJeremy Kerr static void tx_message(struct ctx *ctx, mctp_eid_t eid, void *msg, size_t len)
858e31cfd1SJeremy Kerr {
8606735055SAndrew Jeffery int rc;
8706735055SAndrew Jeffery
88f39c3857SSumanth Bhat rc = mctp_message_tx(ctx->mctp, eid, MCTP_MESSAGE_TO_SRC, 0, msg, len);
8906735055SAndrew Jeffery if (rc)
9006735055SAndrew Jeffery warnx("Failed to send message: %d", rc);
918e31cfd1SJeremy Kerr }
928e31cfd1SJeremy Kerr
client_remove_inactive(struct ctx * ctx)938e31cfd1SJeremy Kerr static void client_remove_inactive(struct ctx *ctx)
948e31cfd1SJeremy Kerr {
958e31cfd1SJeremy Kerr int i;
968e31cfd1SJeremy Kerr
978e31cfd1SJeremy Kerr for (i = 0; i < ctx->n_clients; i++) {
988e31cfd1SJeremy Kerr struct client *client = &ctx->clients[i];
998e31cfd1SJeremy Kerr if (client->active)
1008e31cfd1SJeremy Kerr continue;
1018e31cfd1SJeremy Kerr close(client->sock);
1028e31cfd1SJeremy Kerr
1038e31cfd1SJeremy Kerr ctx->n_clients--;
1048e31cfd1SJeremy Kerr memmove(&ctx->clients[i], &ctx->clients[i + 1],
1058e31cfd1SJeremy Kerr (ctx->n_clients - i) * sizeof(*ctx->clients));
1068e31cfd1SJeremy Kerr ctx->clients = realloc(ctx->clients,
1078e31cfd1SJeremy Kerr ctx->n_clients * sizeof(*ctx->clients));
1088e31cfd1SJeremy Kerr }
1098e31cfd1SJeremy Kerr }
1108e31cfd1SJeremy Kerr
rx_message(uint8_t eid,bool tag_owner __unused,uint8_t msg_tag __unused,void * data,void * msg,size_t len)111a721c2d8SPatrick Williams static void rx_message(uint8_t eid, bool tag_owner __unused,
112a721c2d8SPatrick Williams uint8_t msg_tag __unused, void *data, void *msg,
113a721c2d8SPatrick Williams size_t len)
1148e31cfd1SJeremy Kerr {
1158e31cfd1SJeremy Kerr struct ctx *ctx = data;
1168e31cfd1SJeremy Kerr struct iovec iov[2];
1178e31cfd1SJeremy Kerr struct msghdr msghdr;
1188e31cfd1SJeremy Kerr bool removed;
1198e31cfd1SJeremy Kerr uint8_t type;
1208e31cfd1SJeremy Kerr int i, rc;
1218e31cfd1SJeremy Kerr
1228e31cfd1SJeremy Kerr if (len < 2)
1238e31cfd1SJeremy Kerr return;
1248e31cfd1SJeremy Kerr
1258e31cfd1SJeremy Kerr type = *(uint8_t *)msg;
1268e31cfd1SJeremy Kerr
1278e31cfd1SJeremy Kerr if (ctx->verbose)
1288e31cfd1SJeremy Kerr fprintf(stderr, "MCTP message received: len %zd, type %d\n",
1298e31cfd1SJeremy Kerr len, type);
1308e31cfd1SJeremy Kerr
1318e31cfd1SJeremy Kerr memset(&msghdr, 0, sizeof(msghdr));
1328e31cfd1SJeremy Kerr msghdr.msg_iov = iov;
1338e31cfd1SJeremy Kerr msghdr.msg_iovlen = 2;
1348e31cfd1SJeremy Kerr iov[0].iov_base = &eid;
1358e31cfd1SJeremy Kerr iov[0].iov_len = 1;
1368e31cfd1SJeremy Kerr iov[1].iov_base = msg;
1378e31cfd1SJeremy Kerr iov[1].iov_len = len;
1388e31cfd1SJeremy Kerr
1398e31cfd1SJeremy Kerr for (i = 0; i < ctx->n_clients; i++) {
1408e31cfd1SJeremy Kerr struct client *client = &ctx->clients[i];
1418e31cfd1SJeremy Kerr
1428e31cfd1SJeremy Kerr if (client->type != type)
1438e31cfd1SJeremy Kerr continue;
1448e31cfd1SJeremy Kerr
1458e31cfd1SJeremy Kerr if (ctx->verbose)
1468e31cfd1SJeremy Kerr fprintf(stderr, " forwarding to client %d\n", i);
1478e31cfd1SJeremy Kerr
1488e31cfd1SJeremy Kerr rc = sendmsg(client->sock, &msghdr, 0);
1498e31cfd1SJeremy Kerr if (rc != (ssize_t)(len + 1)) {
1508e31cfd1SJeremy Kerr client->active = false;
1518e31cfd1SJeremy Kerr removed = true;
1528e31cfd1SJeremy Kerr }
1538e31cfd1SJeremy Kerr }
1548e31cfd1SJeremy Kerr
1558e31cfd1SJeremy Kerr if (removed)
1568e31cfd1SJeremy Kerr client_remove_inactive(ctx);
1578e31cfd1SJeremy Kerr }
1588e31cfd1SJeremy Kerr
binding_null_init(struct mctp * mctp __unused,struct binding * binding __unused,mctp_eid_t eid __unused,int n_params,char * const * params __unused)15934b9b3d8SJeremy Kerr static int binding_null_init(struct mctp *mctp __unused,
16034b9b3d8SJeremy Kerr struct binding *binding __unused,
161a721c2d8SPatrick Williams mctp_eid_t eid __unused, int n_params,
162a721c2d8SPatrick Williams char *const *params __unused)
16334b9b3d8SJeremy Kerr {
16434b9b3d8SJeremy Kerr if (n_params != 0) {
16534b9b3d8SJeremy Kerr warnx("null binding doesn't accept parameters");
16634b9b3d8SJeremy Kerr return -1;
16734b9b3d8SJeremy Kerr }
16834b9b3d8SJeremy Kerr return 0;
16934b9b3d8SJeremy Kerr }
17034b9b3d8SJeremy Kerr
binding_serial_init(struct mctp * mctp,struct binding * binding,mctp_eid_t eid,int n_params,char * const * params)1718e31cfd1SJeremy Kerr static int binding_serial_init(struct mctp *mctp, struct binding *binding,
172a721c2d8SPatrick Williams mctp_eid_t eid, int n_params,
173a721c2d8SPatrick Williams char *const *params)
1748e31cfd1SJeremy Kerr {
1758e31cfd1SJeremy Kerr struct mctp_binding_serial *serial;
1768e31cfd1SJeremy Kerr const char *path;
1778e31cfd1SJeremy Kerr int rc;
1788e31cfd1SJeremy Kerr
1798e31cfd1SJeremy Kerr if (n_params != 1) {
1808e31cfd1SJeremy Kerr warnx("serial binding requires device param");
1818e31cfd1SJeremy Kerr return -1;
1828e31cfd1SJeremy Kerr }
1838e31cfd1SJeremy Kerr
1848e31cfd1SJeremy Kerr path = params[0];
1858e31cfd1SJeremy Kerr
1868e31cfd1SJeremy Kerr serial = mctp_serial_init();
1878e31cfd1SJeremy Kerr assert(serial);
1888e31cfd1SJeremy Kerr
1898e31cfd1SJeremy Kerr rc = mctp_serial_open_path(serial, path);
1908e31cfd1SJeremy Kerr if (rc)
1918e31cfd1SJeremy Kerr return -1;
1928e31cfd1SJeremy Kerr
1933b36d17cSJeremy Kerr mctp_register_bus(mctp, mctp_binding_serial_core(serial), eid);
1948e31cfd1SJeremy Kerr
1958e31cfd1SJeremy Kerr binding->data = serial;
1968e31cfd1SJeremy Kerr
1978e31cfd1SJeremy Kerr return 0;
1988e31cfd1SJeremy Kerr }
1998e31cfd1SJeremy Kerr
binding_serial_init_pollfd(struct binding * binding,struct pollfd * pollfd)2008f53d631SAndrew Jeffery static int binding_serial_init_pollfd(struct binding *binding,
2018f53d631SAndrew Jeffery struct pollfd *pollfd)
2028e31cfd1SJeremy Kerr {
2038f53d631SAndrew Jeffery return mctp_serial_init_pollfd(binding->data, pollfd);
2048e31cfd1SJeremy Kerr }
2058e31cfd1SJeremy Kerr
binding_serial_process(struct binding * binding)2068e31cfd1SJeremy Kerr static int binding_serial_process(struct binding *binding)
2078e31cfd1SJeremy Kerr {
2088e31cfd1SJeremy Kerr return mctp_serial_read(binding->data);
2098e31cfd1SJeremy Kerr }
2108e31cfd1SJeremy Kerr
binding_astlpc_init(struct mctp * mctp,struct binding * binding,mctp_eid_t eid,int n_params,char * const * params)2118e31cfd1SJeremy Kerr static int binding_astlpc_init(struct mctp *mctp, struct binding *binding,
2128e31cfd1SJeremy Kerr mctp_eid_t eid, int n_params,
2138e31cfd1SJeremy Kerr char *const *params __attribute__((unused)))
2148e31cfd1SJeremy Kerr {
2158e31cfd1SJeremy Kerr struct mctp_binding_astlpc *astlpc;
216400766f9SKonstantin Aladyshev const char *path;
2178e31cfd1SJeremy Kerr
218400766f9SKonstantin Aladyshev if (n_params != 1) {
219400766f9SKonstantin Aladyshev warnx("astlpc binding requires kcs device param");
2208e31cfd1SJeremy Kerr return -1;
2218e31cfd1SJeremy Kerr }
2228e31cfd1SJeremy Kerr
223400766f9SKonstantin Aladyshev path = params[0];
224400766f9SKonstantin Aladyshev
225400766f9SKonstantin Aladyshev astlpc = mctp_astlpc_init_fileio(path);
2268e31cfd1SJeremy Kerr if (!astlpc) {
2278e31cfd1SJeremy Kerr warnx("could not initialise astlpc binding");
2288e31cfd1SJeremy Kerr return -1;
2298e31cfd1SJeremy Kerr }
2308e31cfd1SJeremy Kerr
2313b36d17cSJeremy Kerr mctp_register_bus(mctp, mctp_binding_astlpc_core(astlpc), eid);
2323b36d17cSJeremy Kerr
2338e31cfd1SJeremy Kerr binding->data = astlpc;
2348e31cfd1SJeremy Kerr return 0;
2358e31cfd1SJeremy Kerr }
2368e31cfd1SJeremy Kerr
binding_astlpc_destroy(struct mctp * mctp,struct binding * binding)237edebe169SAndrew Jeffery static void binding_astlpc_destroy(struct mctp *mctp, struct binding *binding)
238edebe169SAndrew Jeffery {
239edebe169SAndrew Jeffery struct mctp_binding_astlpc *astlpc = binding->data;
240edebe169SAndrew Jeffery
241edebe169SAndrew Jeffery mctp_unregister_bus(mctp, mctp_binding_astlpc_core(astlpc));
242edebe169SAndrew Jeffery
243edebe169SAndrew Jeffery mctp_astlpc_destroy(astlpc);
244edebe169SAndrew Jeffery }
245edebe169SAndrew Jeffery
binding_astlpc_init_pollfd(struct binding * binding,struct pollfd * pollfd)2468f53d631SAndrew Jeffery static int binding_astlpc_init_pollfd(struct binding *binding,
2478f53d631SAndrew Jeffery struct pollfd *pollfd)
2488e31cfd1SJeremy Kerr {
2498f53d631SAndrew Jeffery return mctp_astlpc_init_pollfd(binding->data, pollfd);
2508e31cfd1SJeremy Kerr }
2518e31cfd1SJeremy Kerr
binding_astlpc_process(struct binding * binding)2528e31cfd1SJeremy Kerr static int binding_astlpc_process(struct binding *binding)
2538e31cfd1SJeremy Kerr {
2548e31cfd1SJeremy Kerr return mctp_astlpc_poll(binding->data);
2558e31cfd1SJeremy Kerr }
2568e31cfd1SJeremy Kerr
257a721c2d8SPatrick Williams struct binding bindings[] = { {
25834b9b3d8SJeremy Kerr .name = "null",
25934b9b3d8SJeremy Kerr .init = binding_null_init,
26034b9b3d8SJeremy Kerr },
26134b9b3d8SJeremy Kerr {
2628e31cfd1SJeremy Kerr .name = "serial",
2638e31cfd1SJeremy Kerr .init = binding_serial_init,
264edebe169SAndrew Jeffery .destroy = NULL,
2658f53d631SAndrew Jeffery .init_pollfd = binding_serial_init_pollfd,
2668e31cfd1SJeremy Kerr .process = binding_serial_process,
2678e31cfd1SJeremy Kerr },
2688e31cfd1SJeremy Kerr {
2698e31cfd1SJeremy Kerr .name = "astlpc",
2708e31cfd1SJeremy Kerr .init = binding_astlpc_init,
271edebe169SAndrew Jeffery .destroy = binding_astlpc_destroy,
2728f53d631SAndrew Jeffery .init_pollfd = binding_astlpc_init_pollfd,
2738e31cfd1SJeremy Kerr .process = binding_astlpc_process,
274a721c2d8SPatrick Williams } };
2758e31cfd1SJeremy Kerr
binding_lookup(const char * name)2768e31cfd1SJeremy Kerr struct binding *binding_lookup(const char *name)
2778e31cfd1SJeremy Kerr {
2788e31cfd1SJeremy Kerr struct binding *binding;
2798e31cfd1SJeremy Kerr unsigned int i;
2808e31cfd1SJeremy Kerr
2818e31cfd1SJeremy Kerr for (i = 0; i < ARRAY_SIZE(bindings); i++) {
2828e31cfd1SJeremy Kerr binding = &bindings[i];
2838e31cfd1SJeremy Kerr
2848e31cfd1SJeremy Kerr if (!strcmp(binding->name, name))
2858e31cfd1SJeremy Kerr return binding;
2868e31cfd1SJeremy Kerr }
2878e31cfd1SJeremy Kerr
2888e31cfd1SJeremy Kerr return NULL;
2898e31cfd1SJeremy Kerr }
2908e31cfd1SJeremy Kerr
socket_init(struct ctx * ctx)2918e31cfd1SJeremy Kerr static int socket_init(struct ctx *ctx)
2928e31cfd1SJeremy Kerr {
2938e31cfd1SJeremy Kerr struct sockaddr_un addr;
2948e31cfd1SJeremy Kerr int namelen, rc;
2958e31cfd1SJeremy Kerr
2968e31cfd1SJeremy Kerr namelen = sizeof(sockname) - 1;
2978e31cfd1SJeremy Kerr addr.sun_family = AF_UNIX;
2988e31cfd1SJeremy Kerr memcpy(addr.sun_path, sockname, namelen);
2998e31cfd1SJeremy Kerr
3008e31cfd1SJeremy Kerr ctx->sock = socket(AF_UNIX, SOCK_SEQPACKET, 0);
3018e31cfd1SJeremy Kerr if (ctx->sock < 0) {
3028e31cfd1SJeremy Kerr warn("can't create socket");
3038e31cfd1SJeremy Kerr return -1;
3048e31cfd1SJeremy Kerr }
3058e31cfd1SJeremy Kerr
3068e31cfd1SJeremy Kerr rc = bind(ctx->sock, (struct sockaddr *)&addr,
3078e31cfd1SJeremy Kerr sizeof(addr.sun_family) + namelen);
3088e31cfd1SJeremy Kerr if (rc) {
3098e31cfd1SJeremy Kerr warn("can't bind socket");
3108e31cfd1SJeremy Kerr goto err_close;
3118e31cfd1SJeremy Kerr }
3128e31cfd1SJeremy Kerr
3138e31cfd1SJeremy Kerr rc = listen(ctx->sock, 1);
3148e31cfd1SJeremy Kerr if (rc) {
3158e31cfd1SJeremy Kerr warn("can't listen on socket");
3168e31cfd1SJeremy Kerr goto err_close;
3178e31cfd1SJeremy Kerr }
3188e31cfd1SJeremy Kerr
3198e31cfd1SJeremy Kerr return 0;
3208e31cfd1SJeremy Kerr
3218e31cfd1SJeremy Kerr err_close:
3228e31cfd1SJeremy Kerr close(ctx->sock);
3238e31cfd1SJeremy Kerr return -1;
3248e31cfd1SJeremy Kerr }
3258e31cfd1SJeremy Kerr
socket_process(struct ctx * ctx)3268e31cfd1SJeremy Kerr static int socket_process(struct ctx *ctx)
3278e31cfd1SJeremy Kerr {
3288e31cfd1SJeremy Kerr struct client *client;
3298e31cfd1SJeremy Kerr int fd;
3308e31cfd1SJeremy Kerr
3318e31cfd1SJeremy Kerr fd = accept4(ctx->sock, NULL, 0, SOCK_NONBLOCK);
3328e31cfd1SJeremy Kerr if (fd < 0)
3338e31cfd1SJeremy Kerr return -1;
3348e31cfd1SJeremy Kerr
3358e31cfd1SJeremy Kerr ctx->n_clients++;
336a721c2d8SPatrick Williams ctx->clients =
337a721c2d8SPatrick Williams realloc(ctx->clients, ctx->n_clients * sizeof(struct client));
3388e31cfd1SJeremy Kerr
3398e31cfd1SJeremy Kerr client = &ctx->clients[ctx->n_clients - 1];
3408676c934SAndrew Jeffery memset(client, 0, sizeof(*client));
3418e31cfd1SJeremy Kerr client->active = true;
3428e31cfd1SJeremy Kerr client->sock = fd;
3438e31cfd1SJeremy Kerr
3448e31cfd1SJeremy Kerr return 0;
3458e31cfd1SJeremy Kerr }
3468e31cfd1SJeremy Kerr
client_process_recv(struct ctx * ctx,int idx)3478e31cfd1SJeremy Kerr static int client_process_recv(struct ctx *ctx, int idx)
3488e31cfd1SJeremy Kerr {
3498e31cfd1SJeremy Kerr struct client *client = &ctx->clients[idx];
350f49b2ac8SJeremy Kerr uint8_t eid;
351f49b2ac8SJeremy Kerr ssize_t len;
3528e31cfd1SJeremy Kerr int rc;
3538e31cfd1SJeremy Kerr
3548e31cfd1SJeremy Kerr /* are we waiting for a type message? */
3558e31cfd1SJeremy Kerr if (!client->type) {
3568e31cfd1SJeremy Kerr uint8_t type;
3578e31cfd1SJeremy Kerr rc = read(client->sock, &type, 1);
3588e31cfd1SJeremy Kerr if (rc <= 0)
3598e31cfd1SJeremy Kerr goto out_close;
3608e31cfd1SJeremy Kerr
3618e31cfd1SJeremy Kerr if (type == 0) {
3628e31cfd1SJeremy Kerr rc = -1;
3638e31cfd1SJeremy Kerr goto out_close;
3648e31cfd1SJeremy Kerr }
3658e31cfd1SJeremy Kerr if (ctx->verbose)
3668e31cfd1SJeremy Kerr fprintf(stderr, "client[%d] registered for type %u\n",
3678e31cfd1SJeremy Kerr idx, type);
3688e31cfd1SJeremy Kerr client->type = type;
3698e31cfd1SJeremy Kerr return 0;
3708e31cfd1SJeremy Kerr }
3718e31cfd1SJeremy Kerr
372f49b2ac8SJeremy Kerr len = recv(client->sock, NULL, 0, MSG_PEEK | MSG_TRUNC);
373f49b2ac8SJeremy Kerr if (len < 0) {
3746896d41eSAndrew Jeffery if (errno != ECONNRESET)
375f49b2ac8SJeremy Kerr warn("can't receive (peek) from client");
3766896d41eSAndrew Jeffery
37713a4041fSAndrew Jeffery rc = -1;
378f49b2ac8SJeremy Kerr goto out_close;
379f49b2ac8SJeremy Kerr }
380f49b2ac8SJeremy Kerr
381b93b6112SAndrew Jeffery if ((size_t)len > ctx->buf_size) {
382f49b2ac8SJeremy Kerr void *tmp;
383f49b2ac8SJeremy Kerr
384f49b2ac8SJeremy Kerr tmp = realloc(ctx->buf, len);
385f49b2ac8SJeremy Kerr if (!tmp) {
386f49b2ac8SJeremy Kerr warn("can't allocate for incoming message");
38713a4041fSAndrew Jeffery rc = -1;
388f49b2ac8SJeremy Kerr goto out_close;
389f49b2ac8SJeremy Kerr }
390f49b2ac8SJeremy Kerr ctx->buf = tmp;
391f49b2ac8SJeremy Kerr ctx->buf_size = len;
392f49b2ac8SJeremy Kerr }
393f49b2ac8SJeremy Kerr
394f49b2ac8SJeremy Kerr rc = recv(client->sock, ctx->buf, ctx->buf_size, 0);
3958e31cfd1SJeremy Kerr if (rc < 0) {
3966896d41eSAndrew Jeffery if (errno != ECONNRESET)
3978e31cfd1SJeremy Kerr warn("can't receive from client");
39813a4041fSAndrew Jeffery rc = -1;
3998e31cfd1SJeremy Kerr goto out_close;
4008e31cfd1SJeremy Kerr }
4018e31cfd1SJeremy Kerr
402195a7c5eSJeremy Kerr if (rc <= 0) {
4038e31cfd1SJeremy Kerr rc = -1;
4048e31cfd1SJeremy Kerr goto out_close;
4058e31cfd1SJeremy Kerr }
4068e31cfd1SJeremy Kerr
407f49b2ac8SJeremy Kerr eid = *(uint8_t *)ctx->buf;
408d690d8eaSJeremy Kerr
409f2988977SRashmica Gupta if (ctx->pcap.socket.path)
410f2988977SRashmica Gupta capture_socket(ctx->pcap.socket.dumper, ctx->buf, rc,
411f2988977SRashmica Gupta MCTP_MESSAGE_CAPTURE_OUTGOING, eid);
412f2988977SRashmica Gupta
4138e31cfd1SJeremy Kerr if (ctx->verbose)
414a721c2d8SPatrick Williams fprintf(stderr, "client[%d] sent message: dest 0x%02x len %d\n",
4158e31cfd1SJeremy Kerr idx, eid, rc - 1);
4168e31cfd1SJeremy Kerr
417195a7c5eSJeremy Kerr if (eid == ctx->local_eid)
418f39c3857SSumanth Bhat rx_message(eid, MCTP_MESSAGE_TO_DST, 0, ctx, ctx->buf + 1,
419f39c3857SSumanth Bhat rc - 1);
420195a7c5eSJeremy Kerr else
421f49b2ac8SJeremy Kerr tx_message(ctx, eid, ctx->buf + 1, rc - 1);
4228e31cfd1SJeremy Kerr
4238e31cfd1SJeremy Kerr return 0;
4248e31cfd1SJeremy Kerr
4258e31cfd1SJeremy Kerr out_close:
4268e31cfd1SJeremy Kerr client->active = false;
4278e31cfd1SJeremy Kerr return rc;
4288e31cfd1SJeremy Kerr }
4298e31cfd1SJeremy Kerr
binding_init(struct ctx * ctx,const char * name,int argc,char * const * argv)430a721c2d8SPatrick Williams static int binding_init(struct ctx *ctx, const char *name, int argc,
431a721c2d8SPatrick Williams char *const *argv)
4328e31cfd1SJeremy Kerr {
4338e31cfd1SJeremy Kerr int rc;
4348e31cfd1SJeremy Kerr
4358e31cfd1SJeremy Kerr ctx->binding = binding_lookup(name);
4368e31cfd1SJeremy Kerr if (!ctx->binding) {
4378e31cfd1SJeremy Kerr warnx("no such binding '%s'", name);
4388e31cfd1SJeremy Kerr return -1;
4398e31cfd1SJeremy Kerr }
4408e31cfd1SJeremy Kerr
441a721c2d8SPatrick Williams rc = ctx->binding->init(ctx->mctp, ctx->binding, ctx->local_eid, argc,
442a721c2d8SPatrick Williams argv);
4438e31cfd1SJeremy Kerr return rc;
4448e31cfd1SJeremy Kerr }
4458e31cfd1SJeremy Kerr
binding_destroy(struct ctx * ctx)446edebe169SAndrew Jeffery static void binding_destroy(struct ctx *ctx)
447edebe169SAndrew Jeffery {
448edebe169SAndrew Jeffery if (ctx->binding->destroy)
449edebe169SAndrew Jeffery ctx->binding->destroy(ctx->mctp, ctx->binding);
450edebe169SAndrew Jeffery }
451edebe169SAndrew Jeffery
4528e31cfd1SJeremy Kerr enum {
4538e31cfd1SJeremy Kerr FD_BINDING = 0,
4548e31cfd1SJeremy Kerr FD_SOCKET,
455490e3873SAndrew Jeffery FD_SIGNAL,
4568e31cfd1SJeremy Kerr FD_NR,
4578e31cfd1SJeremy Kerr };
4588e31cfd1SJeremy Kerr
run_daemon(struct ctx * ctx)4598e31cfd1SJeremy Kerr static int run_daemon(struct ctx *ctx)
4608e31cfd1SJeremy Kerr {
4618e31cfd1SJeremy Kerr bool clients_changed = false;
462490e3873SAndrew Jeffery sigset_t mask;
4638e31cfd1SJeremy Kerr int rc, i;
4648e31cfd1SJeremy Kerr
4658e31cfd1SJeremy Kerr ctx->pollfds = malloc(FD_NR * sizeof(struct pollfd));
4668e31cfd1SJeremy Kerr
4678f53d631SAndrew Jeffery if (!ctx->binding->init_pollfd) {
46834b9b3d8SJeremy Kerr ctx->pollfds[FD_BINDING].fd = -1;
46934b9b3d8SJeremy Kerr ctx->pollfds[FD_BINDING].events = 0;
47034b9b3d8SJeremy Kerr }
4718e31cfd1SJeremy Kerr
472490e3873SAndrew Jeffery sigemptyset(&mask);
473490e3873SAndrew Jeffery sigaddset(&mask, SIGINT);
474490e3873SAndrew Jeffery sigaddset(&mask, SIGTERM);
475490e3873SAndrew Jeffery sigaddset(&mask, SIGQUIT);
476490e3873SAndrew Jeffery
477490e3873SAndrew Jeffery if ((rc = sigprocmask(SIG_BLOCK, &mask, NULL)) == -1) {
478490e3873SAndrew Jeffery warn("sigprocmask");
479490e3873SAndrew Jeffery return rc;
480490e3873SAndrew Jeffery }
481490e3873SAndrew Jeffery
482490e3873SAndrew Jeffery ctx->pollfds[FD_SIGNAL].fd = signalfd(-1, &mask, 0);
483490e3873SAndrew Jeffery ctx->pollfds[FD_SIGNAL].events = POLLIN;
484490e3873SAndrew Jeffery
4858e31cfd1SJeremy Kerr ctx->pollfds[FD_SOCKET].fd = ctx->sock;
4868e31cfd1SJeremy Kerr ctx->pollfds[FD_SOCKET].events = POLLIN;
4878e31cfd1SJeremy Kerr
4888e31cfd1SJeremy Kerr mctp_set_rx_all(ctx->mctp, rx_message, ctx);
4898e31cfd1SJeremy Kerr
4908e31cfd1SJeremy Kerr for (;;) {
4918e31cfd1SJeremy Kerr if (clients_changed) {
4928e31cfd1SJeremy Kerr int i;
4938e31cfd1SJeremy Kerr
4948e31cfd1SJeremy Kerr ctx->pollfds = realloc(ctx->pollfds,
4958e31cfd1SJeremy Kerr (ctx->n_clients + FD_NR) *
4968e31cfd1SJeremy Kerr sizeof(struct pollfd));
4978e31cfd1SJeremy Kerr
4988e31cfd1SJeremy Kerr for (i = 0; i < ctx->n_clients; i++) {
4998e31cfd1SJeremy Kerr ctx->pollfds[FD_NR + i].fd =
5008e31cfd1SJeremy Kerr ctx->clients[i].sock;
5018e31cfd1SJeremy Kerr ctx->pollfds[FD_NR + i].events = POLLIN;
5028e31cfd1SJeremy Kerr }
5038e31cfd1SJeremy Kerr clients_changed = false;
5048e31cfd1SJeremy Kerr }
5058e31cfd1SJeremy Kerr
5068f53d631SAndrew Jeffery if (ctx->binding->init_pollfd)
5078f53d631SAndrew Jeffery ctx->binding->init_pollfd(ctx->binding,
5088f53d631SAndrew Jeffery &ctx->pollfds[FD_BINDING]);
5098e31cfd1SJeremy Kerr rc = poll(ctx->pollfds, ctx->n_clients + FD_NR, -1);
5108e31cfd1SJeremy Kerr if (rc < 0) {
5118e31cfd1SJeremy Kerr warn("poll failed");
5128e31cfd1SJeremy Kerr break;
5138e31cfd1SJeremy Kerr }
5148e31cfd1SJeremy Kerr
5158e31cfd1SJeremy Kerr if (!rc)
5168e31cfd1SJeremy Kerr continue;
5178e31cfd1SJeremy Kerr
518490e3873SAndrew Jeffery if (ctx->pollfds[FD_SIGNAL].revents) {
519490e3873SAndrew Jeffery struct signalfd_siginfo si;
520490e3873SAndrew Jeffery ssize_t got;
521490e3873SAndrew Jeffery
522490e3873SAndrew Jeffery got = read(ctx->pollfds[FD_SIGNAL].fd, &si, sizeof(si));
523490e3873SAndrew Jeffery if (got == sizeof(si)) {
524490e3873SAndrew Jeffery warnx("Received %s, quitting",
525490e3873SAndrew Jeffery strsignal(si.ssi_signo));
526490e3873SAndrew Jeffery rc = 0;
527490e3873SAndrew Jeffery break;
528490e3873SAndrew Jeffery } else {
529490e3873SAndrew Jeffery warnx("Unexpected read result for signalfd: %d",
530490e3873SAndrew Jeffery rc);
531490e3873SAndrew Jeffery warnx("Quitting on the basis that signalfd became ready");
532490e3873SAndrew Jeffery rc = -1;
533490e3873SAndrew Jeffery break;
534490e3873SAndrew Jeffery }
535490e3873SAndrew Jeffery }
536490e3873SAndrew Jeffery
5378e31cfd1SJeremy Kerr if (ctx->pollfds[FD_BINDING].revents) {
53834b9b3d8SJeremy Kerr rc = 0;
53934b9b3d8SJeremy Kerr if (ctx->binding->process)
5408e31cfd1SJeremy Kerr rc = ctx->binding->process(ctx->binding);
5418e31cfd1SJeremy Kerr if (rc)
5428e31cfd1SJeremy Kerr break;
5438e31cfd1SJeremy Kerr }
5448e31cfd1SJeremy Kerr
5458e31cfd1SJeremy Kerr for (i = 0; i < ctx->n_clients; i++) {
5468e31cfd1SJeremy Kerr if (!ctx->pollfds[FD_NR + i].revents)
5478e31cfd1SJeremy Kerr continue;
5488e31cfd1SJeremy Kerr
5498e31cfd1SJeremy Kerr rc = client_process_recv(ctx, i);
5508e31cfd1SJeremy Kerr if (rc)
5518e31cfd1SJeremy Kerr clients_changed = true;
5528e31cfd1SJeremy Kerr }
5538e31cfd1SJeremy Kerr
5548e31cfd1SJeremy Kerr if (ctx->pollfds[FD_SOCKET].revents) {
5558e31cfd1SJeremy Kerr rc = socket_process(ctx);
5568e31cfd1SJeremy Kerr if (rc)
5578e31cfd1SJeremy Kerr break;
5588e31cfd1SJeremy Kerr clients_changed = true;
5598e31cfd1SJeremy Kerr }
5608e31cfd1SJeremy Kerr
5618e31cfd1SJeremy Kerr if (clients_changed)
5628e31cfd1SJeremy Kerr client_remove_inactive(ctx);
5638e31cfd1SJeremy Kerr }
5648e31cfd1SJeremy Kerr
5658e31cfd1SJeremy Kerr free(ctx->pollfds);
5668e31cfd1SJeremy Kerr
5678e31cfd1SJeremy Kerr return rc;
5688e31cfd1SJeremy Kerr }
5698e31cfd1SJeremy Kerr
5708e31cfd1SJeremy Kerr static const struct option options[] = {
571cad47301SAndrew Jeffery { "capture-binding", required_argument, 0, 'b' },
572cad47301SAndrew Jeffery { "capture-socket", required_argument, 0, 's' },
573cad47301SAndrew Jeffery { "binding-linktype", required_argument, 0, 'B' },
574cad47301SAndrew Jeffery { "socket-linktype", required_argument, 0, 'S' },
5758e31cfd1SJeremy Kerr { "verbose", no_argument, 0, 'v' },
5768e31cfd1SJeremy Kerr { "eid", required_argument, 0, 'e' },
5778e31cfd1SJeremy Kerr { 0 },
5788e31cfd1SJeremy Kerr };
5798e31cfd1SJeremy Kerr
usage(const char * progname)5808e31cfd1SJeremy Kerr static void usage(const char *progname)
5818e31cfd1SJeremy Kerr {
5828e31cfd1SJeremy Kerr unsigned int i;
5838e31cfd1SJeremy Kerr
5848e31cfd1SJeremy Kerr fprintf(stderr, "usage: %s <binding> [params]\n", progname);
5858e31cfd1SJeremy Kerr fprintf(stderr, "Available bindings:\n");
5868e31cfd1SJeremy Kerr for (i = 0; i < ARRAY_SIZE(bindings); i++)
5878e31cfd1SJeremy Kerr fprintf(stderr, " %s\n", bindings[i].name);
5888e31cfd1SJeremy Kerr }
5898e31cfd1SJeremy Kerr
main(int argc,char * const * argv)5908e31cfd1SJeremy Kerr int main(int argc, char *const *argv)
5918e31cfd1SJeremy Kerr {
5928e31cfd1SJeremy Kerr struct ctx *ctx, _ctx;
5938e31cfd1SJeremy Kerr int rc;
5948e31cfd1SJeremy Kerr
5958e31cfd1SJeremy Kerr ctx = &_ctx;
5968e31cfd1SJeremy Kerr ctx->clients = NULL;
5978e31cfd1SJeremy Kerr ctx->n_clients = 0;
5988e31cfd1SJeremy Kerr ctx->local_eid = local_eid_default;
59904b81fc7SAndrew Jeffery ctx->verbose = false;
600cad47301SAndrew Jeffery ctx->pcap.binding.path = NULL;
601cad47301SAndrew Jeffery ctx->pcap.socket.path = NULL;
6028e31cfd1SJeremy Kerr
6038e31cfd1SJeremy Kerr for (;;) {
604cad47301SAndrew Jeffery rc = getopt_long(argc, argv, "b:es::v", options, NULL);
6058e31cfd1SJeremy Kerr if (rc == -1)
6068e31cfd1SJeremy Kerr break;
6078e31cfd1SJeremy Kerr switch (rc) {
608cad47301SAndrew Jeffery case 'b':
609cad47301SAndrew Jeffery ctx->pcap.binding.path = optarg;
610cad47301SAndrew Jeffery break;
611cad47301SAndrew Jeffery case 's':
612cad47301SAndrew Jeffery ctx->pcap.socket.path = optarg;
613cad47301SAndrew Jeffery break;
614cad47301SAndrew Jeffery case 'B':
615f2988977SRashmica Gupta fprintf(stderr,
616f2988977SRashmica Gupta "binding-linktype argument is deprecated\n");
617cad47301SAndrew Jeffery break;
618cad47301SAndrew Jeffery case 'S':
619f2988977SRashmica Gupta fprintf(stderr,
620f2988977SRashmica Gupta "socket-linktype argument is deprecated\n");
621cad47301SAndrew Jeffery break;
6228e31cfd1SJeremy Kerr case 'v':
6238e31cfd1SJeremy Kerr ctx->verbose = true;
6248e31cfd1SJeremy Kerr break;
6258e31cfd1SJeremy Kerr case 'e':
6268e31cfd1SJeremy Kerr ctx->local_eid = atoi(optarg);
6278e31cfd1SJeremy Kerr break;
6288e31cfd1SJeremy Kerr default:
6298e31cfd1SJeremy Kerr fprintf(stderr, "Invalid argument\n");
6308e31cfd1SJeremy Kerr return EXIT_FAILURE;
6318e31cfd1SJeremy Kerr }
6328e31cfd1SJeremy Kerr }
6338e31cfd1SJeremy Kerr
6348e31cfd1SJeremy Kerr if (optind >= argc) {
6358e31cfd1SJeremy Kerr fprintf(stderr, "missing binding argument\n");
6368e31cfd1SJeremy Kerr usage(argv[0]);
6378e31cfd1SJeremy Kerr return EXIT_FAILURE;
6388e31cfd1SJeremy Kerr }
6398e31cfd1SJeremy Kerr
640f49b2ac8SJeremy Kerr /* setup initial buffer */
641f49b2ac8SJeremy Kerr ctx->buf_size = 4096;
642f49b2ac8SJeremy Kerr ctx->buf = malloc(ctx->buf_size);
643f49b2ac8SJeremy Kerr
644dca82599SAndrew Jeffery mctp_set_log_stdio(ctx->verbose ? MCTP_LOG_DEBUG : MCTP_LOG_NOTICE);
6450b278a63SJeremy Kerr
6468e31cfd1SJeremy Kerr ctx->mctp = mctp_init();
6478e31cfd1SJeremy Kerr assert(ctx->mctp);
6488e31cfd1SJeremy Kerr
649cad47301SAndrew Jeffery if (ctx->pcap.binding.path || ctx->pcap.socket.path) {
650cad47301SAndrew Jeffery if (capture_init()) {
651cad47301SAndrew Jeffery rc = EXIT_FAILURE;
652cad47301SAndrew Jeffery goto cleanup_mctp;
653cad47301SAndrew Jeffery }
654cad47301SAndrew Jeffery }
655cad47301SAndrew Jeffery
656cad47301SAndrew Jeffery if (ctx->pcap.binding.path) {
657cad47301SAndrew Jeffery rc = capture_prepare(&ctx->pcap.binding);
658cad47301SAndrew Jeffery if (rc == -1) {
659a721c2d8SPatrick Williams fprintf(stderr, "Failed to initialise capture: %d\n",
660a721c2d8SPatrick Williams rc);
661cad47301SAndrew Jeffery rc = EXIT_FAILURE;
662cad47301SAndrew Jeffery goto cleanup_mctp;
663cad47301SAndrew Jeffery }
664cad47301SAndrew Jeffery
665cad47301SAndrew Jeffery mctp_set_capture_handler(ctx->mctp, capture_binding,
666cad47301SAndrew Jeffery ctx->pcap.binding.dumper);
667cad47301SAndrew Jeffery }
668cad47301SAndrew Jeffery
669cad47301SAndrew Jeffery if (ctx->pcap.socket.path) {
670cad47301SAndrew Jeffery rc = capture_prepare(&ctx->pcap.socket);
671cad47301SAndrew Jeffery if (rc == -1) {
672a721c2d8SPatrick Williams fprintf(stderr, "Failed to initialise capture: %d\n",
673a721c2d8SPatrick Williams rc);
674cad47301SAndrew Jeffery rc = EXIT_FAILURE;
675cad47301SAndrew Jeffery goto cleanup_pcap_binding;
676cad47301SAndrew Jeffery }
677cad47301SAndrew Jeffery }
678cad47301SAndrew Jeffery
679a721c2d8SPatrick Williams rc = binding_init(ctx, argv[optind], argc - optind - 1,
680a721c2d8SPatrick Williams argv + optind + 1);
681cad47301SAndrew Jeffery if (rc) {
682cad47301SAndrew Jeffery fprintf(stderr, "Failed to initialise binding: %d\n", rc);
683cad47301SAndrew Jeffery rc = EXIT_FAILURE;
684cad47301SAndrew Jeffery goto cleanup_pcap_socket;
685cad47301SAndrew Jeffery }
6868e31cfd1SJeremy Kerr
687d4103f8fSAndrew Jeffery rc = sd_listen_fds(true);
688d4103f8fSAndrew Jeffery if (rc <= 0) {
6898e31cfd1SJeremy Kerr rc = socket_init(ctx);
690cad47301SAndrew Jeffery if (rc) {
691cad47301SAndrew Jeffery fprintf(stderr, "Failed to initialse socket: %d\n", rc);
692edebe169SAndrew Jeffery goto cleanup_binding;
693cad47301SAndrew Jeffery }
694d4103f8fSAndrew Jeffery } else {
695d4103f8fSAndrew Jeffery ctx->sock = SD_LISTEN_FDS_START;
696d4103f8fSAndrew Jeffery }
6978e31cfd1SJeremy Kerr
6988e31cfd1SJeremy Kerr rc = run_daemon(ctx);
6998e31cfd1SJeremy Kerr
700edebe169SAndrew Jeffery cleanup_binding:
701edebe169SAndrew Jeffery binding_destroy(ctx);
702edebe169SAndrew Jeffery
703cad47301SAndrew Jeffery cleanup_pcap_socket:
704cad47301SAndrew Jeffery if (ctx->pcap.socket.path)
705cad47301SAndrew Jeffery capture_close(&ctx->pcap.socket);
706cad47301SAndrew Jeffery
707cad47301SAndrew Jeffery cleanup_pcap_binding:
708cad47301SAndrew Jeffery if (ctx->pcap.binding.path)
709cad47301SAndrew Jeffery capture_close(&ctx->pcap.binding);
710cad47301SAndrew Jeffery
711cad47301SAndrew Jeffery rc = rc ? EXIT_FAILURE : EXIT_SUCCESS;
712cad47301SAndrew Jeffery cleanup_mctp:
713cad47301SAndrew Jeffery
714cad47301SAndrew Jeffery return rc;
7158e31cfd1SJeremy Kerr }
716