xref: /openbmc/libpldm/src/requester/pldm.c (revision c1b66f420912dd659a4159ebd176af18347958f4)
1 #include "libpldm/requester/pldm.h"
2 #include "base.h"
3 #include "libpldm/transport.h"
4 
5 #include <bits/types/struct_iovec.h>
6 #include <stdbool.h>
7 #include <stdlib.h>
8 #include <string.h>
9 #include <sys/socket.h>
10 #include <sys/un.h>
11 #include <unistd.h>
12 
13 /* Temporary for old api */
14 #include "libpldm/transport/mctp-demux.h"
15 extern int
16 pldm_transport_mctp_demux_get_socket_fd(struct pldm_transport_mctp_demux *ctx);
17 extern struct pldm_transport_mctp_demux *
18 pldm_transport_mctp_demux_init_with_fd(int mctp_fd);
19 
20 /* ---  old APIS written in terms of the new API -- */
21 /*
22  * pldm_open returns the file descriptor to the MCTP socket, which needs to
23  * persist over api calls (so a consumer can poll it for incoming messages).
24  * So we need a global variable to store the transport struct
25  */
26 static struct pldm_transport_mctp_demux *open_transport;
27 
28 pldm_requester_rc_t pldm_open(void)
29 {
30 	int fd;
31 	int rc;
32 
33 	if (open_transport) {
34 		return -1;
35 	}
36 
37 	struct pldm_transport_mctp_demux *demux = NULL;
38 	rc = pldm_transport_mctp_demux_init(&demux);
39 	if (rc) {
40 		return rc;
41 	}
42 
43 	fd = pldm_transport_mctp_demux_get_socket_fd(demux);
44 
45 	open_transport = demux;
46 
47 	return fd;
48 }
49 
50 /* This macro does the setup and teardown required for the old API to use the
51  * new API. Since the setup/teardown logic is the same for all four send/recv
52  * functions, it makes sense to only define it once. */
53 #define PLDM_REQ_FN(eid, fd, fn, ...)                                          \
54 	do {                                                                   \
55 		struct pldm_transport_mctp_demux *demux;                       \
56 		bool using_open_transport = false;                             \
57 		pldm_requester_rc_t rc;                                        \
58 		pldm_tid_t tid = 1;                                            \
59 		struct pldm_transport *ctx;                                    \
60 		/* The fd can be for a socket we opened or one the consumer    \
61 		 * opened. */                                                  \
62 		if (open_transport &&                                          \
63 		    mctp_fd == pldm_transport_mctp_demux_get_socket_fd(        \
64 				   open_transport)) {                          \
65 			using_open_transport = true;                           \
66 			demux = open_transport;                                \
67 		} else {                                                       \
68 			demux = pldm_transport_mctp_demux_init_with_fd(fd);    \
69 			if (!demux) {                                          \
70 				rc = PLDM_REQUESTER_OPEN_FAIL;                 \
71 				goto transport_out;                            \
72 			}                                                      \
73 		}                                                              \
74 		ctx = pldm_transport_mctp_demux_core(demux);                   \
75 		rc = pldm_transport_mctp_demux_map_tid(demux, tid, eid);       \
76 		if (rc) {                                                      \
77 			rc = PLDM_REQUESTER_OPEN_FAIL;                         \
78 			goto transport_out;                                    \
79 		}                                                              \
80 		rc = fn(ctx, tid, __VA_ARGS__);                                \
81 	transport_out:                                                         \
82 		if (!using_open_transport) {                                   \
83 			pldm_transport_mctp_demux_destroy(demux);              \
84 		}                                                              \
85 		return rc;                                                     \
86 	} while (0)
87 
88 pldm_requester_rc_t pldm_recv_any(mctp_eid_t eid, int mctp_fd,
89 				  uint8_t **pldm_resp_msg, size_t *resp_msg_len)
90 {
91 	PLDM_REQ_FN(eid, mctp_fd, pldm_transport_recv_msg,
92 		    (void **)pldm_resp_msg, resp_msg_len);
93 }
94 
95 pldm_requester_rc_t pldm_recv(mctp_eid_t eid, int mctp_fd,
96 			      __attribute__((unused)) uint8_t instance_id,
97 			      uint8_t **pldm_resp_msg, size_t *resp_msg_len)
98 {
99 	pldm_requester_rc_t rc =
100 	    pldm_recv_any(eid, mctp_fd, pldm_resp_msg, resp_msg_len);
101 	struct pldm_msg_hdr *hdr = (struct pldm_msg_hdr *)(*pldm_resp_msg);
102 	if (hdr->instance_id != instance_id) {
103 		free(*pldm_resp_msg);
104 		*pldm_resp_msg = NULL;
105 		return PLDM_REQUESTER_INSTANCE_ID_MISMATCH;
106 	}
107 	return rc;
108 }
109 
110 pldm_requester_rc_t pldm_send_recv(mctp_eid_t eid, int mctp_fd,
111 				   const uint8_t *pldm_req_msg,
112 				   size_t req_msg_len, uint8_t **pldm_resp_msg,
113 				   size_t *resp_msg_len)
114 {
115 	PLDM_REQ_FN(eid, mctp_fd, pldm_transport_send_recv_msg, pldm_req_msg,
116 		    req_msg_len, (void **)pldm_resp_msg, resp_msg_len);
117 }
118 
119 pldm_requester_rc_t pldm_send(mctp_eid_t eid, int mctp_fd,
120 			      const uint8_t *pldm_req_msg, size_t req_msg_len)
121 {
122 	PLDM_REQ_FN(eid, mctp_fd, pldm_transport_send_msg, (void *)pldm_req_msg,
123 		    req_msg_len);
124 }
125 
126 /* Adding this here for completeness in the case we can't smoothly
127  * transition apps over to the new api */
128 void pldm_close()
129 {
130 	if (open_transport) {
131 		pldm_transport_mctp_demux_destroy(open_transport);
132 	}
133 	open_transport = NULL;
134 }
135