1 #include "config.h" 2 #include "mctp-defines.h" 3 #include "base.h" 4 #include "container-of.h" 5 #include "libpldm/pldm.h" 6 #include "libpldm/transport.h" 7 #include "transport.h" 8 9 #include <errno.h> 10 #include <poll.h> 11 #include <stdlib.h> 12 #include <string.h> 13 #include <sys/socket.h> 14 #include <sys/types.h> 15 #include <sys/un.h> 16 #include <unistd.h> 17 18 #define MCTP_DEMUX_NAME "libmctp-demux-daemon" 19 const uint8_t mctp_msg_type = MCTP_MSG_TYPE_PLDM; 20 21 struct pldm_transport_mctp_demux { 22 struct pldm_transport transport; 23 int socket; 24 /* In the future this probably needs to move to a tid-eid-uuid/network 25 * id mapping for multi mctp networks */ 26 pldm_tid_t tid_eid_map[MCTP_MAX_NUM_EID]; 27 }; 28 29 #define transport_to_demux(ptr) \ 30 container_of(ptr, struct pldm_transport_mctp_demux, transport) 31 32 LIBPLDM_ABI_TESTING 33 struct pldm_transport * 34 pldm_transport_mctp_demux_core(struct pldm_transport_mctp_demux *ctx) 35 { 36 return &ctx->transport; 37 } 38 39 static pldm_requester_rc_t pldm_transport_mctp_demux_open(void) 40 { 41 int fd = -1; 42 ssize_t rc = -1; 43 44 fd = socket(AF_UNIX, SOCK_SEQPACKET, 0); 45 if (fd == -1) { 46 return fd; 47 } 48 49 const char path[] = "\0mctp-mux"; 50 struct sockaddr_un addr; 51 addr.sun_family = AF_UNIX; 52 memcpy(addr.sun_path, path, sizeof(path) - 1); 53 rc = connect(fd, (struct sockaddr *)&addr, 54 sizeof(path) + sizeof(addr.sun_family) - 1); 55 if (rc == -1) { 56 return PLDM_REQUESTER_OPEN_FAIL; 57 } 58 rc = write(fd, &mctp_msg_type, sizeof(mctp_msg_type)); 59 if (rc == -1) { 60 return PLDM_REQUESTER_OPEN_FAIL; 61 } 62 63 return fd; 64 } 65 66 LIBPLDM_ABI_TESTING 67 int pldm_transport_mctp_demux_init_pollfd(struct pldm_transport *t, 68 struct pollfd *pollfd) 69 { 70 struct pldm_transport_mctp_demux *ctx = transport_to_demux(t); 71 pollfd->fd = ctx->socket; 72 pollfd->events = POLLIN; 73 return 0; 74 } 75 76 static int 77 pldm_transport_mctp_demux_get_eid(struct pldm_transport_mctp_demux *ctx, 78 pldm_tid_t tid, mctp_eid_t *eid) 79 { 80 int i; 81 for (i = 0; i < MCTP_MAX_NUM_EID; i++) { 82 if (ctx->tid_eid_map[i] == tid) { 83 *eid = i; 84 return 0; 85 } 86 } 87 *eid = -1; 88 return -1; 89 } 90 91 LIBPLDM_ABI_TESTING 92 int pldm_transport_mctp_demux_map_tid(struct pldm_transport_mctp_demux *ctx, 93 pldm_tid_t tid, mctp_eid_t eid) 94 { 95 ctx->tid_eid_map[eid] = tid; 96 97 return 0; 98 } 99 100 LIBPLDM_ABI_TESTING 101 int pldm_transport_mctp_demux_unmap_tid(struct pldm_transport_mctp_demux *ctx, 102 __attribute__((unused)) pldm_tid_t tid, 103 mctp_eid_t eid) 104 { 105 ctx->tid_eid_map[eid] = 0; 106 107 return 0; 108 } 109 110 static pldm_requester_rc_t 111 pldm_transport_mctp_demux_recv(struct pldm_transport *t, pldm_tid_t tid, 112 void **pldm_resp_msg, size_t *resp_msg_len) 113 { 114 struct pldm_transport_mctp_demux *demux = transport_to_demux(t); 115 mctp_eid_t eid = 0; 116 int rc = pldm_transport_mctp_demux_get_eid(demux, tid, &eid); 117 if (rc) { 118 return PLDM_REQUESTER_RECV_FAIL; 119 } 120 121 ssize_t min_len = sizeof(eid) + sizeof(mctp_msg_type) + 122 sizeof(struct pldm_msg_hdr); 123 ssize_t length = recv(demux->socket, NULL, 0, MSG_PEEK | MSG_TRUNC); 124 if (length <= 0) { 125 return PLDM_REQUESTER_RECV_FAIL; 126 } 127 uint8_t *buf = malloc(length); 128 if (buf == NULL) { 129 return PLDM_REQUESTER_RECV_FAIL; 130 } 131 if (length < min_len) { 132 /* read and discard */ 133 recv(demux->socket, buf, length, 0); 134 free(buf); 135 return PLDM_REQUESTER_INVALID_RECV_LEN; 136 } 137 struct iovec iov[2]; 138 uint8_t mctp_prefix[2]; 139 size_t mctp_prefix_len = 2; 140 size_t pldm_len = length - mctp_prefix_len; 141 iov[0].iov_len = mctp_prefix_len; 142 iov[0].iov_base = mctp_prefix; 143 iov[1].iov_len = pldm_len; 144 iov[1].iov_base = buf; 145 struct msghdr msg = { 0 }; 146 msg.msg_iov = iov; 147 msg.msg_iovlen = sizeof(iov) / sizeof(iov[0]); 148 ssize_t bytes = recvmsg(demux->socket, &msg, 0); 149 if (length != bytes) { 150 free(buf); 151 return PLDM_REQUESTER_INVALID_RECV_LEN; 152 } 153 if ((mctp_prefix[0] != eid) || (mctp_prefix[1] != mctp_msg_type)) { 154 free(buf); 155 return PLDM_REQUESTER_NOT_PLDM_MSG; 156 } 157 *pldm_resp_msg = buf; 158 *resp_msg_len = pldm_len; 159 return PLDM_REQUESTER_SUCCESS; 160 } 161 162 static pldm_requester_rc_t 163 pldm_transport_mctp_demux_send(struct pldm_transport *t, pldm_tid_t tid, 164 const void *pldm_req_msg, size_t req_msg_len) 165 { 166 struct pldm_transport_mctp_demux *demux = transport_to_demux(t); 167 mctp_eid_t eid = 0; 168 if (pldm_transport_mctp_demux_get_eid(demux, tid, &eid)) { 169 return PLDM_REQUESTER_SEND_FAIL; 170 } 171 172 uint8_t hdr[2] = { eid, mctp_msg_type }; 173 174 struct iovec iov[2]; 175 iov[0].iov_base = hdr; 176 iov[0].iov_len = sizeof(hdr); 177 iov[1].iov_base = (uint8_t *)pldm_req_msg; 178 iov[1].iov_len = req_msg_len; 179 180 struct msghdr msg = { 0 }; 181 msg.msg_iov = iov; 182 msg.msg_iovlen = sizeof(iov) / sizeof(iov[0]); 183 184 ssize_t rc = sendmsg(demux->socket, &msg, 0); 185 if (rc == -1) { 186 return PLDM_REQUESTER_SEND_FAIL; 187 } 188 return PLDM_REQUESTER_SUCCESS; 189 } 190 191 LIBPLDM_ABI_TESTING 192 int pldm_transport_mctp_demux_init(struct pldm_transport_mctp_demux **ctx) 193 { 194 if (!ctx || *ctx) { 195 return -EINVAL; 196 } 197 198 struct pldm_transport_mctp_demux *demux = 199 calloc(1, sizeof(struct pldm_transport_mctp_demux)); 200 if (!demux) { 201 return -ENOMEM; 202 } 203 204 demux->transport.name = MCTP_DEMUX_NAME; 205 demux->transport.version = 1; 206 demux->transport.recv = pldm_transport_mctp_demux_recv; 207 demux->transport.send = pldm_transport_mctp_demux_send; 208 demux->transport.init_pollfd = pldm_transport_mctp_demux_init_pollfd; 209 demux->socket = pldm_transport_mctp_demux_open(); 210 if (demux->socket == -1) { 211 free(demux); 212 return -1; 213 } 214 *ctx = demux; 215 return 0; 216 } 217 218 LIBPLDM_ABI_TESTING 219 void pldm_transport_mctp_demux_destroy(struct pldm_transport_mctp_demux *ctx) 220 { 221 if (!ctx) { 222 return; 223 } 224 close(ctx->socket); 225 free(ctx); 226 } 227 228 /* Temporary for old API */ 229 LIBPLDM_ABI_TESTING 230 struct pldm_transport_mctp_demux * 231 pldm_transport_mctp_demux_init_with_fd(int mctp_fd) 232 { 233 struct pldm_transport_mctp_demux *demux = 234 calloc(1, sizeof(struct pldm_transport_mctp_demux)); 235 if (!demux) { 236 return NULL; 237 } 238 239 demux->transport.name = MCTP_DEMUX_NAME; 240 demux->transport.version = 1; 241 demux->transport.recv = pldm_transport_mctp_demux_recv; 242 demux->transport.send = pldm_transport_mctp_demux_send; 243 demux->transport.init_pollfd = pldm_transport_mctp_demux_init_pollfd; 244 /* dup is so we can call pldm_transport_mctp_demux_destroy which closes 245 * the socket, without closing the fd that is being used by the consumer 246 */ 247 demux->socket = dup(mctp_fd); 248 if (demux->socket == -1) { 249 free(demux); 250 return NULL; 251 } 252 return demux; 253 } 254 255 LIBPLDM_ABI_TESTING 256 int pldm_transport_mctp_demux_get_socket_fd( 257 struct pldm_transport_mctp_demux *ctx) 258 { 259 if (ctx && ctx->socket) { 260 return ctx->socket; 261 } 262 return -1; 263 } 264