xref: /openbmc/libpldm/src/requester/pldm.c (revision 39f883259956e7b2d80581bedf471ae2ccd531d5)
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