1 /* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later */ 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 "libpldm/transport/af-mctp.h" 8 #include "responder.h" 9 #include "socket.h" 10 #include "transport.h" 11 12 #include <errno.h> 13 #include <limits.h> 14 #include <linux/mctp.h> 15 #include <poll.h> 16 #include <stdbool.h> 17 #include <stdlib.h> 18 #include <string.h> 19 #include <sys/socket.h> 20 #include <sys/types.h> 21 #include <sys/un.h> 22 #include <unistd.h> 23 24 struct pldm_responder_cookie_af_mctp { 25 struct pldm_responder_cookie req; 26 struct sockaddr_mctp smctp; 27 }; 28 29 #define cookie_to_af_mctp(c) \ 30 container_of((c), struct pldm_responder_cookie_af_mctp, req) 31 32 #define AF_MCTP_NAME "AF_MCTP" 33 struct pldm_transport_af_mctp { 34 struct pldm_transport transport; 35 int socket; 36 pldm_tid_t tid_eid_map[MCTP_MAX_NUM_EID]; 37 struct pldm_socket_sndbuf socket_send_buf; 38 bool bound; 39 struct pldm_responder_cookie cookie_jar; 40 }; 41 42 #define transport_to_af_mctp(ptr) \ 43 container_of(ptr, struct pldm_transport_af_mctp, transport) 44 45 LIBPLDM_ABI_STABLE 46 struct pldm_transport * 47 pldm_transport_af_mctp_core(struct pldm_transport_af_mctp *ctx) 48 { 49 return &ctx->transport; 50 } 51 52 LIBPLDM_ABI_STABLE 53 int pldm_transport_af_mctp_init_pollfd(struct pldm_transport *t, 54 struct pollfd *pollfd) 55 { 56 struct pldm_transport_af_mctp *ctx = transport_to_af_mctp(t); 57 pollfd->fd = ctx->socket; 58 pollfd->events = POLLIN; 59 return 0; 60 } 61 62 static int pldm_transport_af_mctp_get_eid(struct pldm_transport_af_mctp *ctx, 63 pldm_tid_t tid, mctp_eid_t *eid) 64 { 65 int i; 66 for (i = 0; i < MCTP_MAX_NUM_EID; i++) { 67 if (ctx->tid_eid_map[i] == tid) { 68 *eid = i; 69 return 0; 70 } 71 } 72 *eid = -1; 73 return -1; 74 } 75 76 static int pldm_transport_af_mctp_get_tid(struct pldm_transport_af_mctp *ctx, 77 mctp_eid_t eid, pldm_tid_t *tid) 78 { 79 if (ctx->tid_eid_map[eid] != 0) { 80 *tid = ctx->tid_eid_map[eid]; 81 return 0; 82 } 83 return -1; 84 } 85 86 LIBPLDM_ABI_STABLE 87 int pldm_transport_af_mctp_map_tid(struct pldm_transport_af_mctp *ctx, 88 pldm_tid_t tid, mctp_eid_t eid) 89 { 90 ctx->tid_eid_map[eid] = tid; 91 92 return 0; 93 } 94 95 LIBPLDM_ABI_STABLE 96 int pldm_transport_af_mctp_unmap_tid(struct pldm_transport_af_mctp *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 pldm_transport_af_mctp_recv(struct pldm_transport *t, 106 pldm_tid_t *tid, 107 void **pldm_msg, 108 size_t *msg_len) 109 { 110 struct pldm_transport_af_mctp *af_mctp = transport_to_af_mctp(t); 111 struct sockaddr_mctp addr = { 0 }; 112 socklen_t addrlen = sizeof(addr); 113 struct pldm_msg_hdr *hdr; 114 pldm_requester_rc_t res; 115 mctp_eid_t eid = 0; 116 ssize_t length; 117 void *msg; 118 int rc; 119 120 length = recv(af_mctp->socket, NULL, 0, MSG_PEEK | MSG_TRUNC); 121 if (length <= 0) { 122 return PLDM_REQUESTER_RECV_FAIL; 123 } 124 125 msg = malloc(length); 126 if (!msg) { 127 return PLDM_REQUESTER_RECV_FAIL; 128 } 129 130 length = recvfrom(af_mctp->socket, msg, length, MSG_TRUNC, 131 (struct sockaddr *)&addr, &addrlen); 132 if (length < (ssize_t)sizeof(struct pldm_msg_hdr)) { 133 res = PLDM_REQUESTER_INVALID_RECV_LEN; 134 goto cleanup_msg; 135 } 136 137 eid = addr.smctp_addr.s_addr; 138 rc = pldm_transport_af_mctp_get_tid(af_mctp, eid, tid); 139 if (rc) { 140 res = PLDM_REQUESTER_RECV_FAIL; 141 goto cleanup_msg; 142 } 143 144 hdr = msg; 145 146 if (af_mctp->bound && hdr->request) { 147 struct pldm_responder_cookie_af_mctp *cookie; 148 149 cookie = malloc(sizeof(*cookie)); 150 if (!cookie) { 151 res = PLDM_REQUESTER_RECV_FAIL; 152 goto cleanup_msg; 153 } 154 155 cookie->req.tid = *tid, 156 cookie->req.instance_id = hdr->instance_id, 157 cookie->req.type = hdr->type, 158 cookie->req.command = hdr->command; 159 cookie->smctp = addr; 160 161 rc = pldm_responder_cookie_track(&af_mctp->cookie_jar, 162 &cookie->req); 163 if (rc) { 164 res = PLDM_REQUESTER_RECV_FAIL; 165 goto cleanup_msg; 166 } 167 } 168 169 *pldm_msg = msg; 170 *msg_len = length; 171 172 return PLDM_REQUESTER_SUCCESS; 173 174 cleanup_msg: 175 free(msg); 176 177 return res; 178 } 179 180 static pldm_requester_rc_t pldm_transport_af_mctp_send(struct pldm_transport *t, 181 pldm_tid_t tid, 182 const void *pldm_msg, 183 size_t msg_len) 184 { 185 struct pldm_transport_af_mctp *af_mctp = transport_to_af_mctp(t); 186 const struct pldm_msg_hdr *hdr; 187 struct sockaddr_mctp addr = { 0 }; 188 189 if (msg_len < (ssize_t)sizeof(struct pldm_msg_hdr)) { 190 return PLDM_REQUESTER_SEND_FAIL; 191 } 192 193 hdr = pldm_msg; 194 if (af_mctp->bound && !hdr->request) { 195 struct pldm_responder_cookie_af_mctp *cookie; 196 struct pldm_responder_cookie *req; 197 198 req = pldm_responder_cookie_untrack(&af_mctp->cookie_jar, tid, 199 hdr->instance_id, hdr->type, 200 hdr->command); 201 if (!req) { 202 return PLDM_REQUESTER_SEND_FAIL; 203 } 204 205 cookie = cookie_to_af_mctp(req); 206 addr = cookie->smctp; 207 /* Clear the TO to indicate a response */ 208 addr.smctp_tag &= ~MCTP_TAG_OWNER; 209 free(cookie); 210 } else { 211 mctp_eid_t eid = 0; 212 if (pldm_transport_af_mctp_get_eid(af_mctp, tid, &eid)) { 213 return PLDM_REQUESTER_SEND_FAIL; 214 } 215 216 addr.smctp_family = AF_MCTP; 217 addr.smctp_addr.s_addr = eid; 218 addr.smctp_type = MCTP_MSG_TYPE_PLDM; 219 addr.smctp_tag = MCTP_TAG_OWNER; 220 } 221 222 if (msg_len > INT_MAX || 223 pldm_socket_sndbuf_accomodate(&(af_mctp->socket_send_buf), 224 (int)msg_len)) { 225 return PLDM_REQUESTER_SEND_FAIL; 226 } 227 228 ssize_t rc = sendto(af_mctp->socket, pldm_msg, msg_len, 0, 229 (struct sockaddr *)&addr, sizeof(addr)); 230 if (rc == -1) { 231 return PLDM_REQUESTER_SEND_FAIL; 232 } 233 234 return PLDM_REQUESTER_SUCCESS; 235 } 236 237 LIBPLDM_ABI_STABLE 238 int pldm_transport_af_mctp_init(struct pldm_transport_af_mctp **ctx) 239 { 240 if (!ctx || *ctx) { 241 return -EINVAL; 242 } 243 244 struct pldm_transport_af_mctp *af_mctp = 245 calloc(1, sizeof(struct pldm_transport_af_mctp)); 246 if (!af_mctp) { 247 return -ENOMEM; 248 } 249 250 af_mctp->transport.name = AF_MCTP_NAME; 251 af_mctp->transport.version = 1; 252 af_mctp->transport.recv = pldm_transport_af_mctp_recv; 253 af_mctp->transport.send = pldm_transport_af_mctp_send; 254 af_mctp->transport.init_pollfd = pldm_transport_af_mctp_init_pollfd; 255 af_mctp->bound = false; 256 af_mctp->cookie_jar.next = NULL; 257 af_mctp->socket = socket(AF_MCTP, SOCK_DGRAM, 0); 258 if (af_mctp->socket == -1) { 259 free(af_mctp); 260 return -1; 261 } 262 263 if (pldm_socket_sndbuf_init(&af_mctp->socket_send_buf, 264 af_mctp->socket)) { 265 close(af_mctp->socket); 266 free(af_mctp); 267 return -1; 268 } 269 270 *ctx = af_mctp; 271 return 0; 272 } 273 274 LIBPLDM_ABI_STABLE 275 void pldm_transport_af_mctp_destroy(struct pldm_transport_af_mctp *ctx) 276 { 277 if (!ctx) { 278 return; 279 } 280 close(ctx->socket); 281 free(ctx); 282 } 283 284 LIBPLDM_ABI_STABLE 285 int pldm_transport_af_mctp_bind(struct pldm_transport_af_mctp *transport, 286 const struct sockaddr_mctp *smctp, size_t len) 287 { 288 struct sockaddr_mctp lsmctp = { 0 }; 289 int rc; 290 291 if (!transport) { 292 return PLDM_REQUESTER_INVALID_SETUP; 293 } 294 295 if (!smctp && len) { 296 return PLDM_REQUESTER_INVALID_SETUP; 297 } 298 299 if (!smctp) { 300 lsmctp.smctp_family = AF_MCTP; 301 lsmctp.smctp_network = MCTP_NET_ANY; 302 lsmctp.smctp_addr.s_addr = MCTP_ADDR_ANY; 303 lsmctp.smctp_type = MCTP_MSG_TYPE_PLDM; 304 lsmctp.smctp_tag = MCTP_TAG_OWNER; 305 smctp = &lsmctp; 306 len = sizeof(lsmctp); 307 } 308 309 if (smctp->smctp_family != AF_MCTP || 310 smctp->smctp_type != MCTP_MSG_TYPE_PLDM || 311 smctp->smctp_tag != MCTP_TAG_OWNER) { 312 return PLDM_REQUESTER_INVALID_SETUP; 313 } 314 315 if (len != sizeof(*smctp)) { 316 return PLDM_REQUESTER_INVALID_SETUP; 317 } 318 319 rc = bind(transport->socket, (const struct sockaddr *)smctp, 320 sizeof(*smctp)); 321 if (rc) { 322 return PLDM_REQUESTER_SETUP_FAIL; 323 } 324 325 transport->bound = true; 326 327 return PLDM_REQUESTER_SUCCESS; 328 } 329