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