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