xref: /openbmc/libpldm/src/requester/pldm.c (revision 39f88325)
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 		fd = pldm_transport_mctp_demux_get_socket_fd(open_transport);
35 		return fd;
36 	}
37 
38 	struct pldm_transport_mctp_demux *demux = NULL;
39 	rc = pldm_transport_mctp_demux_init(&demux);
40 	if (rc) {
41 		return rc;
42 	}
43 
44 	fd = pldm_transport_mctp_demux_get_socket_fd(demux);
45 
46 	open_transport = demux;
47 
48 	return fd;
49 }
50 
51 /* This macro does the setup and teardown required for the old API to use the
52  * new API. Since the setup/teardown logic is the same for all four send/recv
53  * functions, it makes sense to only define it once. */
54 #define PLDM_REQ_FN(eid, fd, fn, ...)                                            \
55 	do {                                                                     \
56 		struct pldm_transport_mctp_demux *demux;                         \
57 		bool using_open_transport = false;                               \
58 		pldm_requester_rc_t rc;                                          \
59 		pldm_tid_t tid = 1;                                              \
60 		struct pldm_transport *ctx;                                      \
61 		/* The fd can be for a socket we opened or one the consumer    \
62 		 * opened. */ \
63 		if (open_transport &&                                            \
64 		    mctp_fd == pldm_transport_mctp_demux_get_socket_fd(          \
65 				       open_transport)) {                        \
66 			using_open_transport = true;                             \
67 			demux = open_transport;                                  \
68 		} else {                                                         \
69 			demux = pldm_transport_mctp_demux_init_with_fd(fd);      \
70 			if (!demux) {                                            \
71 				rc = PLDM_REQUESTER_OPEN_FAIL;                   \
72 				goto transport_out;                              \
73 			}                                                        \
74 		}                                                                \
75 		ctx = pldm_transport_mctp_demux_core(demux);                     \
76 		rc = pldm_transport_mctp_demux_map_tid(demux, tid, eid);         \
77 		if (rc) {                                                        \
78 			rc = PLDM_REQUESTER_OPEN_FAIL;                           \
79 			goto transport_out;                                      \
80 		}                                                                \
81 		rc = fn(ctx, tid, __VA_ARGS__);                                  \
82 	transport_out:                                                           \
83 		if (!using_open_transport) {                                     \
84 			pldm_transport_mctp_demux_destroy(demux);                \
85 		}                                                                \
86 		return rc;                                                       \
87 	} while (0)
88 
89 pldm_requester_rc_t pldm_recv_any(mctp_eid_t eid, int mctp_fd,
90 				  uint8_t **pldm_resp_msg, size_t *resp_msg_len)
91 {
92 	PLDM_REQ_FN(eid, mctp_fd, pldm_transport_recv_msg,
93 		    (void **)pldm_resp_msg, resp_msg_len);
94 }
95 
96 pldm_requester_rc_t pldm_recv(mctp_eid_t eid, int mctp_fd,
97 			      __attribute__((unused)) uint8_t instance_id,
98 			      uint8_t **pldm_resp_msg, size_t *resp_msg_len)
99 {
100 	pldm_requester_rc_t rc =
101 		pldm_recv_any(eid, mctp_fd, pldm_resp_msg, resp_msg_len);
102 	struct pldm_msg_hdr *hdr = (struct pldm_msg_hdr *)(*pldm_resp_msg);
103 	if (hdr->instance_id != instance_id) {
104 		free(*pldm_resp_msg);
105 		*pldm_resp_msg = NULL;
106 		return PLDM_REQUESTER_INSTANCE_ID_MISMATCH;
107 	}
108 	return rc;
109 }
110 
111 pldm_requester_rc_t pldm_send_recv(mctp_eid_t eid, int mctp_fd,
112 				   const uint8_t *pldm_req_msg,
113 				   size_t req_msg_len, uint8_t **pldm_resp_msg,
114 				   size_t *resp_msg_len)
115 {
116 	PLDM_REQ_FN(eid, mctp_fd, pldm_transport_send_recv_msg, pldm_req_msg,
117 		    req_msg_len, (void **)pldm_resp_msg, resp_msg_len);
118 }
119 
120 pldm_requester_rc_t pldm_send(mctp_eid_t eid, int mctp_fd,
121 			      const uint8_t *pldm_req_msg, size_t req_msg_len)
122 {
123 	PLDM_REQ_FN(eid, mctp_fd, pldm_transport_send_msg, (void *)pldm_req_msg,
124 		    req_msg_len);
125 }
126 
127 /* Adding this here for completeness in the case we can't smoothly
128  * transition apps over to the new api */
129 void pldm_close(void)
130 {
131 	if (open_transport) {
132 		pldm_transport_mctp_demux_destroy(open_transport);
133 	}
134 	open_transport = NULL;
135 }
136