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"
65ab78259SAndrew Jeffery
75ab78259SAndrew Jeffery #define SD_LISTEN_FDS_START 3
85ab78259SAndrew Jeffery
95ab78259SAndrew Jeffery #include "compiler.h"
105ab78259SAndrew Jeffery #include "libmctp.h"
115ab78259SAndrew Jeffery #include "libmctp-serial.h"
125ab78259SAndrew Jeffery #include "libmctp-astlpc.h"
13cad47301SAndrew Jeffery #include "utils/mctp-capture.h"
14d4103f8fSAndrew Jeffery
158e31cfd1SJeremy Kerr #include <assert.h>
168e31cfd1SJeremy Kerr #include <err.h>
176896d41eSAndrew Jeffery #include <errno.h>
188e31cfd1SJeremy Kerr #include <getopt.h>
19b93b6112SAndrew Jeffery #include <limits.h>
208e31cfd1SJeremy Kerr #include <poll.h>
21490e3873SAndrew Jeffery #include <signal.h>
2204b81fc7SAndrew Jeffery #include <stdbool.h>
238e31cfd1SJeremy Kerr #include <stdio.h>
248e31cfd1SJeremy Kerr #include <stdlib.h>
258e31cfd1SJeremy Kerr #include <string.h>
268e31cfd1SJeremy Kerr #include <unistd.h>
278e31cfd1SJeremy Kerr
28490e3873SAndrew Jeffery #include <sys/signalfd.h>
298e31cfd1SJeremy Kerr #include <sys/socket.h>
308e31cfd1SJeremy Kerr #include <sys/un.h>
318e31cfd1SJeremy Kerr
328e31cfd1SJeremy Kerr #define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
338e31cfd1SJeremy Kerr
34d4103f8fSAndrew Jeffery #if HAVE_SYSTEMD_SD_DAEMON_H
35d4103f8fSAndrew Jeffery #include <systemd/sd-daemon.h>
36d4103f8fSAndrew Jeffery #else
sd_listen_fds(int i __unused)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;
488f53d631SAndrew Jeffery int (*init)(struct mctp *mctp, struct binding *binding, mctp_eid_t eid,
498f53d631SAndrew Jeffery int n_params, char *const *params);
50edebe169SAndrew Jeffery void (*destroy)(struct mctp *mctp, struct binding *binding);
518f53d631SAndrew Jeffery int (*init_pollfd)(struct binding *binding, struct pollfd *pollfd);
528e31cfd1SJeremy Kerr int (*process)(struct binding *binding);
538e31cfd1SJeremy Kerr void *data;
548e31cfd1SJeremy Kerr };
558e31cfd1SJeremy Kerr
568e31cfd1SJeremy Kerr struct client {
578e31cfd1SJeremy Kerr bool active;
588e31cfd1SJeremy Kerr int sock;
598e31cfd1SJeremy Kerr uint8_t type;
608e31cfd1SJeremy Kerr };
618e31cfd1SJeremy Kerr
628e31cfd1SJeremy Kerr struct ctx {
638e31cfd1SJeremy Kerr struct mctp *mctp;
648e31cfd1SJeremy Kerr struct binding *binding;
658e31cfd1SJeremy Kerr bool verbose;
668e31cfd1SJeremy Kerr int local_eid;
67f49b2ac8SJeremy Kerr void *buf;
68f49b2ac8SJeremy Kerr size_t buf_size;
698e31cfd1SJeremy Kerr
708e31cfd1SJeremy Kerr int sock;
718e31cfd1SJeremy Kerr struct pollfd *pollfds;
728e31cfd1SJeremy Kerr
738e31cfd1SJeremy Kerr struct client *clients;
748e31cfd1SJeremy Kerr int n_clients;
75cad47301SAndrew Jeffery
76cad47301SAndrew Jeffery struct {
77cad47301SAndrew Jeffery struct capture binding;
78cad47301SAndrew Jeffery struct capture socket;
79cad47301SAndrew Jeffery } pcap;
808e31cfd1SJeremy Kerr };
818e31cfd1SJeremy Kerr
tx_message(struct ctx * ctx,mctp_eid_t eid,void * msg,size_t len)828e31cfd1SJeremy Kerr static void tx_message(struct ctx *ctx, mctp_eid_t eid, void *msg, size_t len)
838e31cfd1SJeremy Kerr {
8406735055SAndrew Jeffery int rc;
8506735055SAndrew Jeffery
86f39c3857SSumanth Bhat rc = mctp_message_tx(ctx->mctp, eid, MCTP_MESSAGE_TO_SRC, 0, msg, len);
8706735055SAndrew Jeffery if (rc)
8806735055SAndrew Jeffery warnx("Failed to send message: %d", rc);
898e31cfd1SJeremy Kerr }
908e31cfd1SJeremy Kerr
client_remove_inactive(struct ctx * ctx)918e31cfd1SJeremy Kerr static void client_remove_inactive(struct ctx *ctx)
928e31cfd1SJeremy Kerr {
938e31cfd1SJeremy Kerr int i;
948e31cfd1SJeremy Kerr
958e31cfd1SJeremy Kerr for (i = 0; i < ctx->n_clients; i++) {
968e31cfd1SJeremy Kerr struct client *client = &ctx->clients[i];
978e31cfd1SJeremy Kerr if (client->active)
988e31cfd1SJeremy Kerr continue;
998e31cfd1SJeremy Kerr close(client->sock);
1008e31cfd1SJeremy Kerr
1018e31cfd1SJeremy Kerr ctx->n_clients--;
1028e31cfd1SJeremy Kerr memmove(&ctx->clients[i], &ctx->clients[i + 1],
1038e31cfd1SJeremy Kerr (ctx->n_clients - i) * sizeof(*ctx->clients));
1048e31cfd1SJeremy Kerr ctx->clients = realloc(ctx->clients,
1058e31cfd1SJeremy Kerr ctx->n_clients * sizeof(*ctx->clients));
1068e31cfd1SJeremy Kerr }
1078e31cfd1SJeremy Kerr }
1088e31cfd1SJeremy Kerr
rx_message(uint8_t eid,bool tag_owner __unused,uint8_t msg_tag __unused,void * data,void * msg,size_t len)109a721c2d8SPatrick Williams static void rx_message(uint8_t eid, bool tag_owner __unused,
110a721c2d8SPatrick Williams uint8_t msg_tag __unused, void *data, void *msg,
111a721c2d8SPatrick Williams size_t len)
1128e31cfd1SJeremy Kerr {
1138e31cfd1SJeremy Kerr struct ctx *ctx = data;
1148e31cfd1SJeremy Kerr struct iovec iov[2];
1158e31cfd1SJeremy Kerr struct msghdr msghdr;
1168e31cfd1SJeremy Kerr bool removed;
1178e31cfd1SJeremy Kerr uint8_t type;
1188e31cfd1SJeremy Kerr int i, rc;
1198e31cfd1SJeremy Kerr
1208e31cfd1SJeremy Kerr if (len < 2)
1218e31cfd1SJeremy Kerr return;
1228e31cfd1SJeremy Kerr
1238e31cfd1SJeremy Kerr type = *(uint8_t *)msg;
1248e31cfd1SJeremy Kerr
1258e31cfd1SJeremy Kerr if (ctx->verbose)
1268e31cfd1SJeremy Kerr fprintf(stderr, "MCTP message received: len %zd, type %d\n",
1278e31cfd1SJeremy Kerr len, type);
1288e31cfd1SJeremy Kerr
1298e31cfd1SJeremy Kerr memset(&msghdr, 0, sizeof(msghdr));
1308e31cfd1SJeremy Kerr msghdr.msg_iov = iov;
1318e31cfd1SJeremy Kerr msghdr.msg_iovlen = 2;
1328e31cfd1SJeremy Kerr iov[0].iov_base = &eid;
1338e31cfd1SJeremy Kerr iov[0].iov_len = 1;
1348e31cfd1SJeremy Kerr iov[1].iov_base = msg;
1358e31cfd1SJeremy Kerr iov[1].iov_len = len;
1368e31cfd1SJeremy Kerr
1378e31cfd1SJeremy Kerr for (i = 0; i < ctx->n_clients; i++) {
1388e31cfd1SJeremy Kerr struct client *client = &ctx->clients[i];
1398e31cfd1SJeremy Kerr
1408e31cfd1SJeremy Kerr if (client->type != type)
1418e31cfd1SJeremy Kerr continue;
1428e31cfd1SJeremy Kerr
1438e31cfd1SJeremy Kerr if (ctx->verbose)
1448e31cfd1SJeremy Kerr fprintf(stderr, " forwarding to client %d\n", i);
1458e31cfd1SJeremy Kerr
1468e31cfd1SJeremy Kerr rc = sendmsg(client->sock, &msghdr, 0);
1478e31cfd1SJeremy Kerr if (rc != (ssize_t)(len + 1)) {
1488e31cfd1SJeremy Kerr client->active = false;
1498e31cfd1SJeremy Kerr removed = true;
1508e31cfd1SJeremy Kerr }
1518e31cfd1SJeremy Kerr }
1528e31cfd1SJeremy Kerr
1538e31cfd1SJeremy Kerr if (removed)
1548e31cfd1SJeremy Kerr client_remove_inactive(ctx);
1558e31cfd1SJeremy Kerr }
1568e31cfd1SJeremy Kerr
binding_null_init(struct mctp * mctp __unused,struct binding * binding __unused,mctp_eid_t eid __unused,int n_params,char * const * params __unused)15734b9b3d8SJeremy Kerr static int binding_null_init(struct mctp *mctp __unused,
15834b9b3d8SJeremy Kerr struct binding *binding __unused,
159a721c2d8SPatrick Williams mctp_eid_t eid __unused, int n_params,
160a721c2d8SPatrick Williams 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
binding_serial_init(struct mctp * mctp,struct binding * binding,mctp_eid_t eid,int n_params,char * const * params)1698e31cfd1SJeremy Kerr static int binding_serial_init(struct mctp *mctp, struct binding *binding,
170a721c2d8SPatrick Williams mctp_eid_t eid, int n_params,
171a721c2d8SPatrick Williams char *const *params)
1728e31cfd1SJeremy Kerr {
1738e31cfd1SJeremy Kerr struct mctp_binding_serial *serial;
1748e31cfd1SJeremy Kerr const char *path;
1758e31cfd1SJeremy Kerr int rc;
1768e31cfd1SJeremy Kerr
1778e31cfd1SJeremy Kerr if (n_params != 1) {
1788e31cfd1SJeremy Kerr warnx("serial binding requires device param");
1798e31cfd1SJeremy Kerr return -1;
1808e31cfd1SJeremy Kerr }
1818e31cfd1SJeremy Kerr
1828e31cfd1SJeremy Kerr path = params[0];
1838e31cfd1SJeremy Kerr
1848e31cfd1SJeremy Kerr serial = mctp_serial_init();
1858e31cfd1SJeremy Kerr assert(serial);
1868e31cfd1SJeremy Kerr
1878e31cfd1SJeremy Kerr rc = mctp_serial_open_path(serial, path);
1888e31cfd1SJeremy Kerr if (rc)
1898e31cfd1SJeremy Kerr return -1;
1908e31cfd1SJeremy Kerr
1913b36d17cSJeremy Kerr mctp_register_bus(mctp, mctp_binding_serial_core(serial), eid);
1928e31cfd1SJeremy Kerr
1938e31cfd1SJeremy Kerr binding->data = serial;
1948e31cfd1SJeremy Kerr
1958e31cfd1SJeremy Kerr return 0;
1968e31cfd1SJeremy Kerr }
1978e31cfd1SJeremy Kerr
binding_serial_init_pollfd(struct binding * binding,struct pollfd * pollfd)1988f53d631SAndrew Jeffery static int binding_serial_init_pollfd(struct binding *binding,
1998f53d631SAndrew Jeffery struct pollfd *pollfd)
2008e31cfd1SJeremy Kerr {
2018f53d631SAndrew Jeffery return mctp_serial_init_pollfd(binding->data, pollfd);
2028e31cfd1SJeremy Kerr }
2038e31cfd1SJeremy Kerr
binding_serial_process(struct binding * binding)2048e31cfd1SJeremy Kerr static int binding_serial_process(struct binding *binding)
2058e31cfd1SJeremy Kerr {
2068e31cfd1SJeremy Kerr return mctp_serial_read(binding->data);
2078e31cfd1SJeremy Kerr }
2088e31cfd1SJeremy Kerr
binding_astlpc_init(struct mctp * mctp,struct binding * binding,mctp_eid_t eid,int n_params,char * const * params)2098e31cfd1SJeremy Kerr static int binding_astlpc_init(struct mctp *mctp, struct binding *binding,
2108e31cfd1SJeremy Kerr mctp_eid_t eid, int n_params,
2118e31cfd1SJeremy Kerr char *const *params __attribute__((unused)))
2128e31cfd1SJeremy Kerr {
2138e31cfd1SJeremy Kerr struct mctp_binding_astlpc *astlpc;
214*400766f9SKonstantin Aladyshev const char *path;
2158e31cfd1SJeremy Kerr
216*400766f9SKonstantin Aladyshev if (n_params != 1) {
217*400766f9SKonstantin Aladyshev warnx("astlpc binding requires kcs device param");
2188e31cfd1SJeremy Kerr return -1;
2198e31cfd1SJeremy Kerr }
2208e31cfd1SJeremy Kerr
221*400766f9SKonstantin Aladyshev path = params[0];
222*400766f9SKonstantin Aladyshev
223*400766f9SKonstantin Aladyshev astlpc = mctp_astlpc_init_fileio(path);
2248e31cfd1SJeremy Kerr if (!astlpc) {
2258e31cfd1SJeremy Kerr warnx("could not initialise astlpc binding");
2268e31cfd1SJeremy Kerr return -1;
2278e31cfd1SJeremy Kerr }
2288e31cfd1SJeremy Kerr
2293b36d17cSJeremy Kerr mctp_register_bus(mctp, mctp_binding_astlpc_core(astlpc), eid);
2303b36d17cSJeremy Kerr
2318e31cfd1SJeremy Kerr binding->data = astlpc;
2328e31cfd1SJeremy Kerr return 0;
2338e31cfd1SJeremy Kerr }
2348e31cfd1SJeremy Kerr
binding_astlpc_destroy(struct mctp * mctp,struct binding * binding)235edebe169SAndrew Jeffery static void binding_astlpc_destroy(struct mctp *mctp, struct binding *binding)
236edebe169SAndrew Jeffery {
237edebe169SAndrew Jeffery struct mctp_binding_astlpc *astlpc = binding->data;
238edebe169SAndrew Jeffery
239edebe169SAndrew Jeffery mctp_unregister_bus(mctp, mctp_binding_astlpc_core(astlpc));
240edebe169SAndrew Jeffery
241edebe169SAndrew Jeffery mctp_astlpc_destroy(astlpc);
242edebe169SAndrew Jeffery }
243edebe169SAndrew Jeffery
binding_astlpc_init_pollfd(struct binding * binding,struct pollfd * pollfd)2448f53d631SAndrew Jeffery static int binding_astlpc_init_pollfd(struct binding *binding,
2458f53d631SAndrew Jeffery struct pollfd *pollfd)
2468e31cfd1SJeremy Kerr {
2478f53d631SAndrew Jeffery return mctp_astlpc_init_pollfd(binding->data, pollfd);
2488e31cfd1SJeremy Kerr }
2498e31cfd1SJeremy Kerr
binding_astlpc_process(struct binding * binding)2508e31cfd1SJeremy Kerr static int binding_astlpc_process(struct binding *binding)
2518e31cfd1SJeremy Kerr {
2528e31cfd1SJeremy Kerr return mctp_astlpc_poll(binding->data);
2538e31cfd1SJeremy Kerr }
2548e31cfd1SJeremy Kerr
255a721c2d8SPatrick Williams struct binding bindings[] = { {
25634b9b3d8SJeremy Kerr .name = "null",
25734b9b3d8SJeremy Kerr .init = binding_null_init,
25834b9b3d8SJeremy Kerr },
25934b9b3d8SJeremy Kerr {
2608e31cfd1SJeremy Kerr .name = "serial",
2618e31cfd1SJeremy Kerr .init = binding_serial_init,
262edebe169SAndrew Jeffery .destroy = NULL,
2638f53d631SAndrew Jeffery .init_pollfd = binding_serial_init_pollfd,
2648e31cfd1SJeremy Kerr .process = binding_serial_process,
2658e31cfd1SJeremy Kerr },
2668e31cfd1SJeremy Kerr {
2678e31cfd1SJeremy Kerr .name = "astlpc",
2688e31cfd1SJeremy Kerr .init = binding_astlpc_init,
269edebe169SAndrew Jeffery .destroy = binding_astlpc_destroy,
2708f53d631SAndrew Jeffery .init_pollfd = binding_astlpc_init_pollfd,
2718e31cfd1SJeremy Kerr .process = binding_astlpc_process,
272a721c2d8SPatrick Williams } };
2738e31cfd1SJeremy Kerr
binding_lookup(const char * name)2748e31cfd1SJeremy Kerr struct binding *binding_lookup(const char *name)
2758e31cfd1SJeremy Kerr {
2768e31cfd1SJeremy Kerr struct binding *binding;
2778e31cfd1SJeremy Kerr unsigned int i;
2788e31cfd1SJeremy Kerr
2798e31cfd1SJeremy Kerr for (i = 0; i < ARRAY_SIZE(bindings); i++) {
2808e31cfd1SJeremy Kerr binding = &bindings[i];
2818e31cfd1SJeremy Kerr
2828e31cfd1SJeremy Kerr if (!strcmp(binding->name, name))
2838e31cfd1SJeremy Kerr return binding;
2848e31cfd1SJeremy Kerr }
2858e31cfd1SJeremy Kerr
2868e31cfd1SJeremy Kerr return NULL;
2878e31cfd1SJeremy Kerr }
2888e31cfd1SJeremy Kerr
socket_init(struct ctx * ctx)2898e31cfd1SJeremy Kerr static int socket_init(struct ctx *ctx)
2908e31cfd1SJeremy Kerr {
2918e31cfd1SJeremy Kerr struct sockaddr_un addr;
2928e31cfd1SJeremy Kerr int namelen, rc;
2938e31cfd1SJeremy Kerr
2948e31cfd1SJeremy Kerr namelen = sizeof(sockname) - 1;
2958e31cfd1SJeremy Kerr addr.sun_family = AF_UNIX;
2968e31cfd1SJeremy Kerr memcpy(addr.sun_path, sockname, namelen);
2978e31cfd1SJeremy Kerr
2988e31cfd1SJeremy Kerr ctx->sock = socket(AF_UNIX, SOCK_SEQPACKET, 0);
2998e31cfd1SJeremy Kerr if (ctx->sock < 0) {
3008e31cfd1SJeremy Kerr warn("can't create socket");
3018e31cfd1SJeremy Kerr return -1;
3028e31cfd1SJeremy Kerr }
3038e31cfd1SJeremy Kerr
3048e31cfd1SJeremy Kerr rc = bind(ctx->sock, (struct sockaddr *)&addr,
3058e31cfd1SJeremy Kerr sizeof(addr.sun_family) + namelen);
3068e31cfd1SJeremy Kerr if (rc) {
3078e31cfd1SJeremy Kerr warn("can't bind socket");
3088e31cfd1SJeremy Kerr goto err_close;
3098e31cfd1SJeremy Kerr }
3108e31cfd1SJeremy Kerr
3118e31cfd1SJeremy Kerr rc = listen(ctx->sock, 1);
3128e31cfd1SJeremy Kerr if (rc) {
3138e31cfd1SJeremy Kerr warn("can't listen on socket");
3148e31cfd1SJeremy Kerr goto err_close;
3158e31cfd1SJeremy Kerr }
3168e31cfd1SJeremy Kerr
3178e31cfd1SJeremy Kerr return 0;
3188e31cfd1SJeremy Kerr
3198e31cfd1SJeremy Kerr err_close:
3208e31cfd1SJeremy Kerr close(ctx->sock);
3218e31cfd1SJeremy Kerr return -1;
3228e31cfd1SJeremy Kerr }
3238e31cfd1SJeremy Kerr
socket_process(struct ctx * ctx)3248e31cfd1SJeremy Kerr static int socket_process(struct ctx *ctx)
3258e31cfd1SJeremy Kerr {
3268e31cfd1SJeremy Kerr struct client *client;
3278e31cfd1SJeremy Kerr int fd;
3288e31cfd1SJeremy Kerr
3298e31cfd1SJeremy Kerr fd = accept4(ctx->sock, NULL, 0, SOCK_NONBLOCK);
3308e31cfd1SJeremy Kerr if (fd < 0)
3318e31cfd1SJeremy Kerr return -1;
3328e31cfd1SJeremy Kerr
3338e31cfd1SJeremy Kerr ctx->n_clients++;
334a721c2d8SPatrick Williams ctx->clients =
335a721c2d8SPatrick Williams realloc(ctx->clients, ctx->n_clients * sizeof(struct client));
3368e31cfd1SJeremy Kerr
3378e31cfd1SJeremy Kerr client = &ctx->clients[ctx->n_clients - 1];
3388676c934SAndrew Jeffery memset(client, 0, sizeof(*client));
3398e31cfd1SJeremy Kerr client->active = true;
3408e31cfd1SJeremy Kerr client->sock = fd;
3418e31cfd1SJeremy Kerr
3428e31cfd1SJeremy Kerr return 0;
3438e31cfd1SJeremy Kerr }
3448e31cfd1SJeremy Kerr
client_process_recv(struct ctx * ctx,int idx)3458e31cfd1SJeremy Kerr static int client_process_recv(struct ctx *ctx, int idx)
3468e31cfd1SJeremy Kerr {
3478e31cfd1SJeremy Kerr struct client *client = &ctx->clients[idx];
348f49b2ac8SJeremy Kerr uint8_t eid;
349f49b2ac8SJeremy Kerr ssize_t len;
3508e31cfd1SJeremy Kerr int rc;
3518e31cfd1SJeremy Kerr
3528e31cfd1SJeremy Kerr /* are we waiting for a type message? */
3538e31cfd1SJeremy Kerr if (!client->type) {
3548e31cfd1SJeremy Kerr uint8_t type;
3558e31cfd1SJeremy Kerr rc = read(client->sock, &type, 1);
3568e31cfd1SJeremy Kerr if (rc <= 0)
3578e31cfd1SJeremy Kerr goto out_close;
3588e31cfd1SJeremy Kerr
3598e31cfd1SJeremy Kerr if (type == 0) {
3608e31cfd1SJeremy Kerr rc = -1;
3618e31cfd1SJeremy Kerr goto out_close;
3628e31cfd1SJeremy Kerr }
3638e31cfd1SJeremy Kerr if (ctx->verbose)
3648e31cfd1SJeremy Kerr fprintf(stderr, "client[%d] registered for type %u\n",
3658e31cfd1SJeremy Kerr idx, type);
3668e31cfd1SJeremy Kerr client->type = type;
3678e31cfd1SJeremy Kerr return 0;
3688e31cfd1SJeremy Kerr }
3698e31cfd1SJeremy Kerr
370f49b2ac8SJeremy Kerr len = recv(client->sock, NULL, 0, MSG_PEEK | MSG_TRUNC);
371f49b2ac8SJeremy Kerr if (len < 0) {
3726896d41eSAndrew Jeffery if (errno != ECONNRESET)
373f49b2ac8SJeremy Kerr warn("can't receive (peek) from client");
3746896d41eSAndrew Jeffery
37513a4041fSAndrew Jeffery rc = -1;
376f49b2ac8SJeremy Kerr goto out_close;
377f49b2ac8SJeremy Kerr }
378f49b2ac8SJeremy Kerr
379b93b6112SAndrew Jeffery if ((size_t)len > ctx->buf_size) {
380f49b2ac8SJeremy Kerr void *tmp;
381f49b2ac8SJeremy Kerr
382f49b2ac8SJeremy Kerr tmp = realloc(ctx->buf, len);
383f49b2ac8SJeremy Kerr if (!tmp) {
384f49b2ac8SJeremy Kerr warn("can't allocate for incoming message");
38513a4041fSAndrew Jeffery rc = -1;
386f49b2ac8SJeremy Kerr goto out_close;
387f49b2ac8SJeremy Kerr }
388f49b2ac8SJeremy Kerr ctx->buf = tmp;
389f49b2ac8SJeremy Kerr ctx->buf_size = len;
390f49b2ac8SJeremy Kerr }
391f49b2ac8SJeremy Kerr
392f49b2ac8SJeremy Kerr rc = recv(client->sock, ctx->buf, ctx->buf_size, 0);
3938e31cfd1SJeremy Kerr if (rc < 0) {
3946896d41eSAndrew Jeffery if (errno != ECONNRESET)
3958e31cfd1SJeremy Kerr warn("can't receive from client");
39613a4041fSAndrew Jeffery rc = -1;
3978e31cfd1SJeremy Kerr goto out_close;
3988e31cfd1SJeremy Kerr }
3998e31cfd1SJeremy Kerr
400195a7c5eSJeremy Kerr if (rc <= 0) {
4018e31cfd1SJeremy Kerr rc = -1;
4028e31cfd1SJeremy Kerr goto out_close;
4038e31cfd1SJeremy Kerr }
4048e31cfd1SJeremy Kerr
405f49b2ac8SJeremy Kerr eid = *(uint8_t *)ctx->buf;
406d690d8eaSJeremy Kerr
407f2988977SRashmica Gupta if (ctx->pcap.socket.path)
408f2988977SRashmica Gupta capture_socket(ctx->pcap.socket.dumper, ctx->buf, rc,
409f2988977SRashmica Gupta MCTP_MESSAGE_CAPTURE_OUTGOING, eid);
410f2988977SRashmica Gupta
4118e31cfd1SJeremy Kerr if (ctx->verbose)
412a721c2d8SPatrick Williams fprintf(stderr, "client[%d] sent message: dest 0x%02x len %d\n",
4138e31cfd1SJeremy Kerr idx, eid, rc - 1);
4148e31cfd1SJeremy Kerr
415195a7c5eSJeremy Kerr if (eid == ctx->local_eid)
416f39c3857SSumanth Bhat rx_message(eid, MCTP_MESSAGE_TO_DST, 0, ctx, ctx->buf + 1,
417f39c3857SSumanth Bhat rc - 1);
418195a7c5eSJeremy Kerr else
419f49b2ac8SJeremy Kerr tx_message(ctx, eid, ctx->buf + 1, rc - 1);
4208e31cfd1SJeremy Kerr
4218e31cfd1SJeremy Kerr return 0;
4228e31cfd1SJeremy Kerr
4238e31cfd1SJeremy Kerr out_close:
4248e31cfd1SJeremy Kerr client->active = false;
4258e31cfd1SJeremy Kerr return rc;
4268e31cfd1SJeremy Kerr }
4278e31cfd1SJeremy Kerr
binding_init(struct ctx * ctx,const char * name,int argc,char * const * argv)428a721c2d8SPatrick Williams static int binding_init(struct ctx *ctx, const char *name, int argc,
429a721c2d8SPatrick Williams char *const *argv)
4308e31cfd1SJeremy Kerr {
4318e31cfd1SJeremy Kerr int rc;
4328e31cfd1SJeremy Kerr
4338e31cfd1SJeremy Kerr ctx->binding = binding_lookup(name);
4348e31cfd1SJeremy Kerr if (!ctx->binding) {
4358e31cfd1SJeremy Kerr warnx("no such binding '%s'", name);
4368e31cfd1SJeremy Kerr return -1;
4378e31cfd1SJeremy Kerr }
4388e31cfd1SJeremy Kerr
439a721c2d8SPatrick Williams rc = ctx->binding->init(ctx->mctp, ctx->binding, ctx->local_eid, argc,
440a721c2d8SPatrick Williams argv);
4418e31cfd1SJeremy Kerr return rc;
4428e31cfd1SJeremy Kerr }
4438e31cfd1SJeremy Kerr
binding_destroy(struct ctx * ctx)444edebe169SAndrew Jeffery static void binding_destroy(struct ctx *ctx)
445edebe169SAndrew Jeffery {
446edebe169SAndrew Jeffery if (ctx->binding->destroy)
447edebe169SAndrew Jeffery ctx->binding->destroy(ctx->mctp, ctx->binding);
448edebe169SAndrew Jeffery }
449edebe169SAndrew Jeffery
4508e31cfd1SJeremy Kerr enum {
4518e31cfd1SJeremy Kerr FD_BINDING = 0,
4528e31cfd1SJeremy Kerr FD_SOCKET,
453490e3873SAndrew Jeffery FD_SIGNAL,
4548e31cfd1SJeremy Kerr FD_NR,
4558e31cfd1SJeremy Kerr };
4568e31cfd1SJeremy Kerr
run_daemon(struct ctx * ctx)4578e31cfd1SJeremy Kerr static int run_daemon(struct ctx *ctx)
4588e31cfd1SJeremy Kerr {
4598e31cfd1SJeremy Kerr bool clients_changed = false;
460490e3873SAndrew Jeffery sigset_t mask;
4618e31cfd1SJeremy Kerr int rc, i;
4628e31cfd1SJeremy Kerr
4638e31cfd1SJeremy Kerr ctx->pollfds = malloc(FD_NR * sizeof(struct pollfd));
4648e31cfd1SJeremy Kerr
4658f53d631SAndrew Jeffery if (!ctx->binding->init_pollfd) {
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
5048f53d631SAndrew Jeffery if (ctx->binding->init_pollfd)
5058f53d631SAndrew Jeffery ctx->binding->init_pollfd(ctx->binding,
5068f53d631SAndrew Jeffery &ctx->pollfds[FD_BINDING]);
5078e31cfd1SJeremy Kerr rc = poll(ctx->pollfds, ctx->n_clients + FD_NR, -1);
5088e31cfd1SJeremy Kerr if (rc < 0) {
5098e31cfd1SJeremy Kerr warn("poll failed");
5108e31cfd1SJeremy Kerr break;
5118e31cfd1SJeremy Kerr }
5128e31cfd1SJeremy Kerr
5138e31cfd1SJeremy Kerr if (!rc)
5148e31cfd1SJeremy Kerr continue;
5158e31cfd1SJeremy Kerr
516490e3873SAndrew Jeffery if (ctx->pollfds[FD_SIGNAL].revents) {
517490e3873SAndrew Jeffery struct signalfd_siginfo si;
518490e3873SAndrew Jeffery ssize_t got;
519490e3873SAndrew Jeffery
520490e3873SAndrew Jeffery got = read(ctx->pollfds[FD_SIGNAL].fd, &si, sizeof(si));
521490e3873SAndrew Jeffery if (got == sizeof(si)) {
522490e3873SAndrew Jeffery warnx("Received %s, quitting",
523490e3873SAndrew Jeffery strsignal(si.ssi_signo));
524490e3873SAndrew Jeffery rc = 0;
525490e3873SAndrew Jeffery break;
526490e3873SAndrew Jeffery } else {
527490e3873SAndrew Jeffery warnx("Unexpected read result for signalfd: %d",
528490e3873SAndrew Jeffery rc);
529490e3873SAndrew Jeffery warnx("Quitting on the basis that signalfd became ready");
530490e3873SAndrew Jeffery rc = -1;
531490e3873SAndrew Jeffery break;
532490e3873SAndrew Jeffery }
533490e3873SAndrew Jeffery }
534490e3873SAndrew Jeffery
5358e31cfd1SJeremy Kerr if (ctx->pollfds[FD_BINDING].revents) {
53634b9b3d8SJeremy Kerr rc = 0;
53734b9b3d8SJeremy Kerr if (ctx->binding->process)
5388e31cfd1SJeremy Kerr rc = ctx->binding->process(ctx->binding);
5398e31cfd1SJeremy Kerr if (rc)
5408e31cfd1SJeremy Kerr break;
5418e31cfd1SJeremy Kerr }
5428e31cfd1SJeremy Kerr
5438e31cfd1SJeremy Kerr for (i = 0; i < ctx->n_clients; i++) {
5448e31cfd1SJeremy Kerr if (!ctx->pollfds[FD_NR + i].revents)
5458e31cfd1SJeremy Kerr continue;
5468e31cfd1SJeremy Kerr
5478e31cfd1SJeremy Kerr rc = client_process_recv(ctx, i);
5488e31cfd1SJeremy Kerr if (rc)
5498e31cfd1SJeremy Kerr clients_changed = true;
5508e31cfd1SJeremy Kerr }
5518e31cfd1SJeremy Kerr
5528e31cfd1SJeremy Kerr if (ctx->pollfds[FD_SOCKET].revents) {
5538e31cfd1SJeremy Kerr rc = socket_process(ctx);
5548e31cfd1SJeremy Kerr if (rc)
5558e31cfd1SJeremy Kerr break;
5568e31cfd1SJeremy Kerr clients_changed = true;
5578e31cfd1SJeremy Kerr }
5588e31cfd1SJeremy Kerr
5598e31cfd1SJeremy Kerr if (clients_changed)
5608e31cfd1SJeremy Kerr client_remove_inactive(ctx);
5618e31cfd1SJeremy Kerr }
5628e31cfd1SJeremy Kerr
5638e31cfd1SJeremy Kerr free(ctx->pollfds);
5648e31cfd1SJeremy Kerr
5658e31cfd1SJeremy Kerr return rc;
5668e31cfd1SJeremy Kerr }
5678e31cfd1SJeremy Kerr
5688e31cfd1SJeremy Kerr static const struct option options[] = {
569cad47301SAndrew Jeffery { "capture-binding", required_argument, 0, 'b' },
570cad47301SAndrew Jeffery { "capture-socket", required_argument, 0, 's' },
571cad47301SAndrew Jeffery { "binding-linktype", required_argument, 0, 'B' },
572cad47301SAndrew Jeffery { "socket-linktype", required_argument, 0, 'S' },
5738e31cfd1SJeremy Kerr { "verbose", no_argument, 0, 'v' },
5748e31cfd1SJeremy Kerr { "eid", required_argument, 0, 'e' },
5758e31cfd1SJeremy Kerr { 0 },
5768e31cfd1SJeremy Kerr };
5778e31cfd1SJeremy Kerr
usage(const char * progname)5788e31cfd1SJeremy Kerr static void usage(const char *progname)
5798e31cfd1SJeremy Kerr {
5808e31cfd1SJeremy Kerr unsigned int i;
5818e31cfd1SJeremy Kerr
5828e31cfd1SJeremy Kerr fprintf(stderr, "usage: %s <binding> [params]\n", progname);
5838e31cfd1SJeremy Kerr fprintf(stderr, "Available bindings:\n");
5848e31cfd1SJeremy Kerr for (i = 0; i < ARRAY_SIZE(bindings); i++)
5858e31cfd1SJeremy Kerr fprintf(stderr, " %s\n", bindings[i].name);
5868e31cfd1SJeremy Kerr }
5878e31cfd1SJeremy Kerr
main(int argc,char * const * argv)5888e31cfd1SJeremy Kerr int main(int argc, char *const *argv)
5898e31cfd1SJeremy Kerr {
5908e31cfd1SJeremy Kerr struct ctx *ctx, _ctx;
5918e31cfd1SJeremy Kerr int rc;
5928e31cfd1SJeremy Kerr
5938e31cfd1SJeremy Kerr ctx = &_ctx;
5948e31cfd1SJeremy Kerr ctx->clients = NULL;
5958e31cfd1SJeremy Kerr ctx->n_clients = 0;
5968e31cfd1SJeremy Kerr ctx->local_eid = local_eid_default;
59704b81fc7SAndrew Jeffery ctx->verbose = false;
598cad47301SAndrew Jeffery ctx->pcap.binding.path = NULL;
599cad47301SAndrew Jeffery ctx->pcap.socket.path = NULL;
6008e31cfd1SJeremy Kerr
6018e31cfd1SJeremy Kerr for (;;) {
602cad47301SAndrew Jeffery rc = getopt_long(argc, argv, "b:es::v", options, NULL);
6038e31cfd1SJeremy Kerr if (rc == -1)
6048e31cfd1SJeremy Kerr break;
6058e31cfd1SJeremy Kerr switch (rc) {
606cad47301SAndrew Jeffery case 'b':
607cad47301SAndrew Jeffery ctx->pcap.binding.path = optarg;
608cad47301SAndrew Jeffery break;
609cad47301SAndrew Jeffery case 's':
610cad47301SAndrew Jeffery ctx->pcap.socket.path = optarg;
611cad47301SAndrew Jeffery break;
612cad47301SAndrew Jeffery case 'B':
613f2988977SRashmica Gupta fprintf(stderr,
614f2988977SRashmica Gupta "binding-linktype argument is deprecated\n");
615cad47301SAndrew Jeffery break;
616cad47301SAndrew Jeffery case 'S':
617f2988977SRashmica Gupta fprintf(stderr,
618f2988977SRashmica Gupta "socket-linktype argument is deprecated\n");
619cad47301SAndrew Jeffery break;
6208e31cfd1SJeremy Kerr case 'v':
6218e31cfd1SJeremy Kerr ctx->verbose = true;
6228e31cfd1SJeremy Kerr break;
6238e31cfd1SJeremy Kerr case 'e':
6248e31cfd1SJeremy Kerr ctx->local_eid = atoi(optarg);
6258e31cfd1SJeremy Kerr break;
6268e31cfd1SJeremy Kerr default:
6278e31cfd1SJeremy Kerr fprintf(stderr, "Invalid argument\n");
6288e31cfd1SJeremy Kerr return EXIT_FAILURE;
6298e31cfd1SJeremy Kerr }
6308e31cfd1SJeremy Kerr }
6318e31cfd1SJeremy Kerr
6328e31cfd1SJeremy Kerr if (optind >= argc) {
6338e31cfd1SJeremy Kerr fprintf(stderr, "missing binding argument\n");
6348e31cfd1SJeremy Kerr usage(argv[0]);
6358e31cfd1SJeremy Kerr return EXIT_FAILURE;
6368e31cfd1SJeremy Kerr }
6378e31cfd1SJeremy Kerr
638f49b2ac8SJeremy Kerr /* setup initial buffer */
639f49b2ac8SJeremy Kerr ctx->buf_size = 4096;
640f49b2ac8SJeremy Kerr ctx->buf = malloc(ctx->buf_size);
641f49b2ac8SJeremy Kerr
642dca82599SAndrew Jeffery mctp_set_log_stdio(ctx->verbose ? MCTP_LOG_DEBUG : MCTP_LOG_NOTICE);
6430b278a63SJeremy Kerr
6448e31cfd1SJeremy Kerr ctx->mctp = mctp_init();
6458e31cfd1SJeremy Kerr assert(ctx->mctp);
6468e31cfd1SJeremy Kerr
647cad47301SAndrew Jeffery if (ctx->pcap.binding.path || ctx->pcap.socket.path) {
648cad47301SAndrew Jeffery if (capture_init()) {
649cad47301SAndrew Jeffery rc = EXIT_FAILURE;
650cad47301SAndrew Jeffery goto cleanup_mctp;
651cad47301SAndrew Jeffery }
652cad47301SAndrew Jeffery }
653cad47301SAndrew Jeffery
654cad47301SAndrew Jeffery if (ctx->pcap.binding.path) {
655cad47301SAndrew Jeffery rc = capture_prepare(&ctx->pcap.binding);
656cad47301SAndrew Jeffery if (rc == -1) {
657a721c2d8SPatrick Williams fprintf(stderr, "Failed to initialise capture: %d\n",
658a721c2d8SPatrick Williams rc);
659cad47301SAndrew Jeffery rc = EXIT_FAILURE;
660cad47301SAndrew Jeffery goto cleanup_mctp;
661cad47301SAndrew Jeffery }
662cad47301SAndrew Jeffery
663cad47301SAndrew Jeffery mctp_set_capture_handler(ctx->mctp, capture_binding,
664cad47301SAndrew Jeffery ctx->pcap.binding.dumper);
665cad47301SAndrew Jeffery }
666cad47301SAndrew Jeffery
667cad47301SAndrew Jeffery if (ctx->pcap.socket.path) {
668cad47301SAndrew Jeffery rc = capture_prepare(&ctx->pcap.socket);
669cad47301SAndrew Jeffery if (rc == -1) {
670a721c2d8SPatrick Williams fprintf(stderr, "Failed to initialise capture: %d\n",
671a721c2d8SPatrick Williams rc);
672cad47301SAndrew Jeffery rc = EXIT_FAILURE;
673cad47301SAndrew Jeffery goto cleanup_pcap_binding;
674cad47301SAndrew Jeffery }
675cad47301SAndrew Jeffery }
676cad47301SAndrew Jeffery
677a721c2d8SPatrick Williams rc = binding_init(ctx, argv[optind], argc - optind - 1,
678a721c2d8SPatrick Williams argv + optind + 1);
679cad47301SAndrew Jeffery if (rc) {
680cad47301SAndrew Jeffery fprintf(stderr, "Failed to initialise binding: %d\n", rc);
681cad47301SAndrew Jeffery rc = EXIT_FAILURE;
682cad47301SAndrew Jeffery goto cleanup_pcap_socket;
683cad47301SAndrew Jeffery }
6848e31cfd1SJeremy Kerr
685d4103f8fSAndrew Jeffery rc = sd_listen_fds(true);
686d4103f8fSAndrew Jeffery if (rc <= 0) {
6878e31cfd1SJeremy Kerr rc = socket_init(ctx);
688cad47301SAndrew Jeffery if (rc) {
689cad47301SAndrew Jeffery fprintf(stderr, "Failed to initialse socket: %d\n", rc);
690edebe169SAndrew Jeffery goto cleanup_binding;
691cad47301SAndrew Jeffery }
692d4103f8fSAndrew Jeffery } else {
693d4103f8fSAndrew Jeffery ctx->sock = SD_LISTEN_FDS_START;
694d4103f8fSAndrew Jeffery }
6958e31cfd1SJeremy Kerr
6968e31cfd1SJeremy Kerr rc = run_daemon(ctx);
6978e31cfd1SJeremy Kerr
698edebe169SAndrew Jeffery cleanup_binding:
699edebe169SAndrew Jeffery binding_destroy(ctx);
700edebe169SAndrew Jeffery
701cad47301SAndrew Jeffery cleanup_pcap_socket:
702cad47301SAndrew Jeffery if (ctx->pcap.socket.path)
703cad47301SAndrew Jeffery capture_close(&ctx->pcap.socket);
704cad47301SAndrew Jeffery
705cad47301SAndrew Jeffery cleanup_pcap_binding:
706cad47301SAndrew Jeffery if (ctx->pcap.binding.path)
707cad47301SAndrew Jeffery capture_close(&ctx->pcap.binding);
708cad47301SAndrew Jeffery
709cad47301SAndrew Jeffery rc = rc ? EXIT_FAILURE : EXIT_SUCCESS;
710cad47301SAndrew Jeffery cleanup_mctp:
711cad47301SAndrew Jeffery
712cad47301SAndrew Jeffery return rc;
7138e31cfd1SJeremy Kerr }
714