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