blob: 932f55e15f212a1cda8a707d1bc20493a3262633 [file] [log] [blame]
Andrew Jeffery9c766792022-08-10 23:12:49 +09301#include "pldm.h"
2#include "base.h"
3
4#include <errno.h>
5#include <stdlib.h>
6#include <sys/socket.h>
7#include <sys/types.h>
8#include <sys/un.h>
9#include <unistd.h>
10
11const uint8_t MCTP_MSG_TYPE_PLDM = 1;
12
13pldm_requester_rc_t pldm_open()
14{
15 int fd = -1;
16 int rc = -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 */
55static 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
98pldm_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
122pldm_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
140pldm_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
168pldm_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}