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 "socket.h" 8 #include "transport.h" 9 10 #include <errno.h> 11 #include <limits.h> 12 #include <linux/mctp.h> 13 #include <poll.h> 14 #include <stdlib.h> 15 #include <string.h> 16 #include <sys/socket.h> 17 #include <sys/types.h> 18 #include <sys/un.h> 19 #include <unistd.h> 20 21 #define AF_MCTP_NAME "AF_MCTP" 22 struct pldm_transport_af_mctp { 23 struct pldm_transport transport; 24 int socket; 25 pldm_tid_t tid_eid_map[MCTP_MAX_NUM_EID]; 26 struct pldm_socket_sndbuf socket_send_buf; 27 }; 28 29 #define transport_to_af_mctp(ptr) \ 30 container_of(ptr, struct pldm_transport_af_mctp, transport) 31 32 LIBPLDM_ABI_STABLE 33 struct pldm_transport * 34 pldm_transport_af_mctp_core(struct pldm_transport_af_mctp *ctx) 35 { 36 return &ctx->transport; 37 } 38 39 LIBPLDM_ABI_STABLE 40 int pldm_transport_af_mctp_init_pollfd(struct pldm_transport *t, 41 struct pollfd *pollfd) 42 { 43 struct pldm_transport_af_mctp *ctx = transport_to_af_mctp(t); 44 pollfd->fd = ctx->socket; 45 pollfd->events = POLLIN; 46 return 0; 47 } 48 49 static int pldm_transport_af_mctp_get_eid(struct pldm_transport_af_mctp *ctx, 50 pldm_tid_t tid, mctp_eid_t *eid) 51 { 52 int i; 53 for (i = 0; i < MCTP_MAX_NUM_EID; i++) { 54 if (ctx->tid_eid_map[i] == tid) { 55 *eid = i; 56 return 0; 57 } 58 } 59 *eid = -1; 60 return -1; 61 } 62 63 static int pldm_transport_af_mctp_get_tid(struct pldm_transport_af_mctp *ctx, 64 mctp_eid_t eid, pldm_tid_t *tid) 65 { 66 if (ctx->tid_eid_map[eid] != 0) { 67 *tid = ctx->tid_eid_map[eid]; 68 return 0; 69 } 70 return -1; 71 } 72 73 LIBPLDM_ABI_STABLE 74 int pldm_transport_af_mctp_map_tid(struct pldm_transport_af_mctp *ctx, 75 pldm_tid_t tid, mctp_eid_t eid) 76 { 77 ctx->tid_eid_map[eid] = tid; 78 79 return 0; 80 } 81 82 LIBPLDM_ABI_STABLE 83 int pldm_transport_af_mctp_unmap_tid(struct pldm_transport_af_mctp *ctx, 84 __attribute__((unused)) pldm_tid_t tid, 85 mctp_eid_t eid) 86 { 87 ctx->tid_eid_map[eid] = 0; 88 89 return 0; 90 } 91 92 static pldm_requester_rc_t pldm_transport_af_mctp_recv(struct pldm_transport *t, 93 pldm_tid_t *tid, 94 void **pldm_msg, 95 size_t *msg_len) 96 { 97 struct pldm_transport_af_mctp *af_mctp = transport_to_af_mctp(t); 98 struct sockaddr_mctp addr = { 0 }; 99 socklen_t addrlen = sizeof(addr); 100 pldm_requester_rc_t res; 101 mctp_eid_t eid = 0; 102 ssize_t length; 103 void *msg; 104 int rc; 105 106 length = recv(af_mctp->socket, NULL, 0, MSG_PEEK | MSG_TRUNC); 107 if (length <= 0) { 108 return PLDM_REQUESTER_RECV_FAIL; 109 } 110 111 msg = malloc(length); 112 if (!msg) { 113 return PLDM_REQUESTER_RECV_FAIL; 114 } 115 116 length = recvfrom(af_mctp->socket, msg, length, MSG_TRUNC, 117 (struct sockaddr *)&addr, &addrlen); 118 if (length < (ssize_t)sizeof(struct pldm_msg_hdr)) { 119 res = PLDM_REQUESTER_INVALID_RECV_LEN; 120 goto cleanup_msg; 121 } 122 123 eid = addr.smctp_addr.s_addr; 124 rc = pldm_transport_af_mctp_get_tid(af_mctp, eid, tid); 125 if (rc) { 126 res = PLDM_REQUESTER_RECV_FAIL; 127 goto cleanup_msg; 128 } 129 130 *pldm_msg = msg; 131 *msg_len = length; 132 133 return PLDM_REQUESTER_SUCCESS; 134 135 cleanup_msg: 136 free(msg); 137 138 return res; 139 } 140 141 static pldm_requester_rc_t pldm_transport_af_mctp_send(struct pldm_transport *t, 142 pldm_tid_t tid, 143 const void *pldm_msg, 144 size_t msg_len) 145 { 146 struct pldm_transport_af_mctp *af_mctp = transport_to_af_mctp(t); 147 mctp_eid_t eid = 0; 148 if (pldm_transport_af_mctp_get_eid(af_mctp, tid, &eid)) { 149 return PLDM_REQUESTER_SEND_FAIL; 150 } 151 152 struct sockaddr_mctp addr = { 0 }; 153 addr.smctp_family = AF_MCTP; 154 addr.smctp_addr.s_addr = eid; 155 addr.smctp_type = MCTP_MSG_TYPE_PLDM; 156 addr.smctp_tag = MCTP_TAG_OWNER; 157 158 if (msg_len > INT_MAX || 159 pldm_socket_sndbuf_accomodate(&(af_mctp->socket_send_buf), 160 (int)msg_len)) { 161 return PLDM_REQUESTER_SEND_FAIL; 162 } 163 164 ssize_t rc = sendto(af_mctp->socket, pldm_msg, msg_len, 0, 165 (struct sockaddr *)&addr, sizeof(addr)); 166 if (rc == -1) { 167 return PLDM_REQUESTER_SEND_FAIL; 168 } 169 return PLDM_REQUESTER_SUCCESS; 170 } 171 172 LIBPLDM_ABI_STABLE 173 int pldm_transport_af_mctp_init(struct pldm_transport_af_mctp **ctx) 174 { 175 if (!ctx || *ctx) { 176 return -EINVAL; 177 } 178 179 struct pldm_transport_af_mctp *af_mctp = 180 calloc(1, sizeof(struct pldm_transport_af_mctp)); 181 if (!af_mctp) { 182 return -ENOMEM; 183 } 184 185 af_mctp->transport.name = AF_MCTP_NAME; 186 af_mctp->transport.version = 1; 187 af_mctp->transport.recv = pldm_transport_af_mctp_recv; 188 af_mctp->transport.send = pldm_transport_af_mctp_send; 189 af_mctp->transport.init_pollfd = pldm_transport_af_mctp_init_pollfd; 190 af_mctp->socket = socket(AF_MCTP, SOCK_DGRAM, 0); 191 if (af_mctp->socket == -1) { 192 free(af_mctp); 193 return -1; 194 } 195 196 if (pldm_socket_sndbuf_init(&af_mctp->socket_send_buf, 197 af_mctp->socket)) { 198 close(af_mctp->socket); 199 free(af_mctp); 200 return -1; 201 } 202 203 *ctx = af_mctp; 204 return 0; 205 } 206 207 LIBPLDM_ABI_STABLE 208 void pldm_transport_af_mctp_destroy(struct pldm_transport_af_mctp *ctx) 209 { 210 if (!ctx) { 211 return; 212 } 213 close(ctx->socket); 214 free(ctx); 215 } 216