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