1 #include "pldm.h" 2 #include "base.h" 3 4 #include <bits/types/struct_iovec.h> 5 #include <stdlib.h> 6 #include <string.h> 7 #include <sys/socket.h> 8 #include <sys/un.h> 9 #include <unistd.h> 10 11 const uint8_t MCTP_MSG_TYPE_PLDM = 1; 12 13 pldm_requester_rc_t pldm_open(void) 14 { 15 ssize_t rc = -1; 16 int fd = -1; 17 18 fd = socket(AF_UNIX, SOCK_SEQPACKET, 0); 19 if (-1 == fd) { 20 return fd; 21 } 22 23 const char path[] = "\0mctp-mux"; 24 struct sockaddr_un addr; 25 addr.sun_family = AF_UNIX; 26 memcpy(addr.sun_path, path, sizeof(path) - 1); 27 rc = connect(fd, (struct sockaddr *)&addr, 28 sizeof(path) + sizeof(addr.sun_family) - 1); 29 if (-1 == rc) { 30 return PLDM_REQUESTER_OPEN_FAIL; 31 } 32 rc = write(fd, &MCTP_MSG_TYPE_PLDM, sizeof(MCTP_MSG_TYPE_PLDM)); 33 if (-1 == rc) { 34 return PLDM_REQUESTER_OPEN_FAIL; 35 } 36 37 return fd; 38 } 39 40 /** 41 * @brief Read MCTP socket. If there's data available, return success only if 42 * data is a PLDM message. 43 * 44 * @param[in] eid - destination MCTP eid 45 * @param[in] mctp_fd - MCTP socket fd 46 * @param[out] pldm_resp_msg - *pldm_resp_msg will point to PLDM msg, 47 * this function allocates memory, caller to free(*pldm_resp_msg) on 48 * success. 49 * @param[out] resp_msg_len - caller owned pointer that will be made point to 50 * the size of the PLDM msg. 51 * 52 * @return pldm_requester_rc_t (errno may be set). failure is returned even 53 * when data was read, but wasn't a PLDM response message 54 */ 55 static pldm_requester_rc_t mctp_recv(mctp_eid_t eid, int mctp_fd, 56 uint8_t **pldm_resp_msg, 57 size_t *resp_msg_len) 58 { 59 ssize_t min_len = sizeof(eid) + sizeof(MCTP_MSG_TYPE_PLDM) + 60 sizeof(struct pldm_msg_hdr); 61 ssize_t length = recv(mctp_fd, NULL, 0, MSG_PEEK | MSG_TRUNC); 62 if (length <= 0) { 63 return PLDM_REQUESTER_RECV_FAIL; 64 } else if (length < min_len) { 65 /* read and discard */ 66 uint8_t buf[length]; 67 recv(mctp_fd, buf, length, 0); 68 return PLDM_REQUESTER_INVALID_RECV_LEN; 69 } else { 70 struct iovec iov[2]; 71 size_t mctp_prefix_len = 72 sizeof(eid) + sizeof(MCTP_MSG_TYPE_PLDM); 73 uint8_t mctp_prefix[mctp_prefix_len]; 74 size_t pldm_len = length - mctp_prefix_len; 75 iov[0].iov_len = mctp_prefix_len; 76 iov[0].iov_base = mctp_prefix; 77 *pldm_resp_msg = malloc(pldm_len); 78 iov[1].iov_len = pldm_len; 79 iov[1].iov_base = *pldm_resp_msg; 80 struct msghdr msg = {0}; 81 msg.msg_iov = iov; 82 msg.msg_iovlen = sizeof(iov) / sizeof(iov[0]); 83 ssize_t bytes = recvmsg(mctp_fd, &msg, 0); 84 if (length != bytes) { 85 free(*pldm_resp_msg); 86 return PLDM_REQUESTER_INVALID_RECV_LEN; 87 } 88 if ((mctp_prefix[0] != eid) || 89 (mctp_prefix[1] != MCTP_MSG_TYPE_PLDM)) { 90 free(*pldm_resp_msg); 91 return PLDM_REQUESTER_NOT_PLDM_MSG; 92 } 93 *resp_msg_len = pldm_len; 94 return PLDM_REQUESTER_SUCCESS; 95 } 96 } 97 98 pldm_requester_rc_t pldm_recv_any(mctp_eid_t eid, int mctp_fd, 99 uint8_t **pldm_resp_msg, size_t *resp_msg_len) 100 { 101 pldm_requester_rc_t rc = 102 mctp_recv(eid, mctp_fd, pldm_resp_msg, resp_msg_len); 103 if (rc != PLDM_REQUESTER_SUCCESS) { 104 return rc; 105 } 106 107 struct pldm_msg_hdr *hdr = (struct pldm_msg_hdr *)(*pldm_resp_msg); 108 if (hdr->request != PLDM_RESPONSE) { 109 free(*pldm_resp_msg); 110 return PLDM_REQUESTER_NOT_RESP_MSG; 111 } 112 113 uint8_t pldm_rc = 0; 114 if (*resp_msg_len < (sizeof(struct pldm_msg_hdr) + sizeof(pldm_rc))) { 115 free(*pldm_resp_msg); 116 return PLDM_REQUESTER_RESP_MSG_TOO_SMALL; 117 } 118 119 return PLDM_REQUESTER_SUCCESS; 120 } 121 122 pldm_requester_rc_t pldm_recv(mctp_eid_t eid, int mctp_fd, uint8_t instance_id, 123 uint8_t **pldm_resp_msg, size_t *resp_msg_len) 124 { 125 pldm_requester_rc_t rc = 126 pldm_recv_any(eid, mctp_fd, pldm_resp_msg, resp_msg_len); 127 if (rc != PLDM_REQUESTER_SUCCESS) { 128 return rc; 129 } 130 131 struct pldm_msg_hdr *hdr = (struct pldm_msg_hdr *)(*pldm_resp_msg); 132 if (hdr->instance_id != instance_id) { 133 free(*pldm_resp_msg); 134 return PLDM_REQUESTER_INSTANCE_ID_MISMATCH; 135 } 136 137 return PLDM_REQUESTER_SUCCESS; 138 } 139 140 pldm_requester_rc_t pldm_send_recv(mctp_eid_t eid, int mctp_fd, 141 const uint8_t *pldm_req_msg, 142 size_t req_msg_len, uint8_t **pldm_resp_msg, 143 size_t *resp_msg_len) 144 { 145 struct pldm_msg_hdr *hdr = (struct pldm_msg_hdr *)pldm_req_msg; 146 if ((hdr->request != PLDM_REQUEST) && 147 (hdr->request != PLDM_ASYNC_REQUEST_NOTIFY)) { 148 return PLDM_REQUESTER_NOT_REQ_MSG; 149 } 150 151 pldm_requester_rc_t rc = 152 pldm_send(eid, mctp_fd, pldm_req_msg, req_msg_len); 153 if (rc != PLDM_REQUESTER_SUCCESS) { 154 return rc; 155 } 156 157 while (1) { 158 rc = pldm_recv(eid, mctp_fd, hdr->instance_id, pldm_resp_msg, 159 resp_msg_len); 160 if (rc == PLDM_REQUESTER_SUCCESS) { 161 break; 162 } 163 } 164 165 return rc; 166 } 167 168 pldm_requester_rc_t pldm_send(mctp_eid_t eid, int mctp_fd, 169 const uint8_t *pldm_req_msg, size_t req_msg_len) 170 { 171 uint8_t hdr[2] = {eid, MCTP_MSG_TYPE_PLDM}; 172 173 struct iovec iov[2]; 174 iov[0].iov_base = hdr; 175 iov[0].iov_len = sizeof(hdr); 176 iov[1].iov_base = (uint8_t *)pldm_req_msg; 177 iov[1].iov_len = req_msg_len; 178 179 struct msghdr msg = {0}; 180 msg.msg_iov = iov; 181 msg.msg_iovlen = sizeof(iov) / sizeof(iov[0]); 182 183 ssize_t rc = sendmsg(mctp_fd, &msg, 0); 184 if (rc == -1) { 185 return PLDM_REQUESTER_SEND_FAIL; 186 } 187 return PLDM_REQUESTER_SUCCESS; 188 } 189