xref: /openbmc/libpldm/src/transport/af-mctp.c (revision f89befe3ef7bfc8efc139711e5bc27bdc08502e0)
1 #include "mctp-defines.h"
2 #include "base.h"
3 #include "container-of.h"
4 #include "libpldm/pldm.h"
5 #include "libpldm/transport.h"
6 #include "socket.h"
7 #include "transport.h"
8 
9 #include <errno.h>
10 #include <limits.h>
11 #include <linux/mctp.h>
12 #include <poll.h>
13 #include <stdlib.h>
14 #include <string.h>
15 #include <sys/socket.h>
16 #include <sys/types.h>
17 #include <sys/un.h>
18 #include <unistd.h>
19 
20 #define AF_MCTP_NAME "AF_MCTP"
21 struct pldm_transport_af_mctp {
22 	struct pldm_transport transport;
23 	int socket;
24 	pldm_tid_t tid_eid_map[MCTP_MAX_NUM_EID];
25 	struct pldm_socket_sndbuf socket_send_buf;
26 };
27 
28 #define transport_to_af_mctp(ptr)                                              \
29 	container_of(ptr, struct pldm_transport_af_mctp, transport)
30 
31 LIBPLDM_ABI_TESTING
32 struct pldm_transport *
33 pldm_transport_af_mctp_core(struct pldm_transport_af_mctp *ctx)
34 {
35 	return &ctx->transport;
36 }
37 
38 LIBPLDM_ABI_TESTING
39 int pldm_transport_af_mctp_init_pollfd(struct pldm_transport *t,
40 				       struct pollfd *pollfd)
41 {
42 	struct pldm_transport_af_mctp *ctx = transport_to_af_mctp(t);
43 	pollfd->fd = ctx->socket;
44 	pollfd->events = POLLIN;
45 	return 0;
46 }
47 
48 static int pldm_transport_af_mctp_get_eid(struct pldm_transport_af_mctp *ctx,
49 					  pldm_tid_t tid, mctp_eid_t *eid)
50 {
51 	int i;
52 	for (i = 0; i < MCTP_MAX_NUM_EID; i++) {
53 		if (ctx->tid_eid_map[i] == tid) {
54 			*eid = i;
55 			return 0;
56 		}
57 	}
58 	*eid = -1;
59 	return -1;
60 }
61 
62 LIBPLDM_ABI_TESTING
63 int pldm_transport_af_mctp_map_tid(struct pldm_transport_af_mctp *ctx,
64 				   pldm_tid_t tid, mctp_eid_t eid)
65 {
66 	ctx->tid_eid_map[eid] = tid;
67 
68 	return 0;
69 }
70 
71 LIBPLDM_ABI_TESTING
72 int pldm_transport_af_mctp_unmap_tid(struct pldm_transport_af_mctp *ctx,
73 				     __attribute__((unused)) pldm_tid_t tid,
74 				     mctp_eid_t eid)
75 {
76 	ctx->tid_eid_map[eid] = 0;
77 
78 	return 0;
79 }
80 
81 static pldm_requester_rc_t pldm_transport_af_mctp_recv(struct pldm_transport *t,
82 						       pldm_tid_t tid,
83 						       void **pldm_resp_msg,
84 						       size_t *resp_msg_len)
85 {
86 	struct pldm_transport_af_mctp *af_mctp = transport_to_af_mctp(t);
87 	mctp_eid_t eid = 0;
88 	int rc = pldm_transport_af_mctp_get_eid(af_mctp, tid, &eid);
89 	if (rc) {
90 		return PLDM_REQUESTER_RECV_FAIL;
91 	}
92 
93 	ssize_t length = recv(af_mctp->socket, NULL, 0, MSG_PEEK | MSG_TRUNC);
94 	if (length <= 0) {
95 		return PLDM_REQUESTER_RECV_FAIL;
96 	}
97 	*pldm_resp_msg = malloc(length);
98 	length = recv(af_mctp->socket, *pldm_resp_msg, length, MSG_TRUNC);
99 	if (length < (ssize_t)sizeof(struct pldm_msg_hdr)) {
100 		free(*pldm_resp_msg);
101 		return PLDM_REQUESTER_INVALID_RECV_LEN;
102 	}
103 	*resp_msg_len = length;
104 	return PLDM_REQUESTER_SUCCESS;
105 }
106 
107 static pldm_requester_rc_t pldm_transport_af_mctp_send(struct pldm_transport *t,
108 						       pldm_tid_t tid,
109 						       const void *pldm_req_msg,
110 						       size_t req_msg_len)
111 {
112 	struct pldm_transport_af_mctp *af_mctp = transport_to_af_mctp(t);
113 	mctp_eid_t eid = 0;
114 	if (pldm_transport_af_mctp_get_eid(af_mctp, tid, &eid)) {
115 		return PLDM_REQUESTER_SEND_FAIL;
116 	}
117 
118 	struct sockaddr_mctp addr = { 0 };
119 	addr.smctp_family = AF_MCTP;
120 	addr.smctp_addr.s_addr = eid;
121 	addr.smctp_type = MCTP_MSG_TYPE_PLDM;
122 	addr.smctp_tag = MCTP_TAG_OWNER;
123 
124 	if (req_msg_len > INT_MAX ||
125 	    pldm_socket_sndbuf_accomodate(&(af_mctp->socket_send_buf),
126 					  (int)req_msg_len)) {
127 		return PLDM_REQUESTER_SEND_FAIL;
128 	}
129 
130 	ssize_t rc = sendto(af_mctp->socket, pldm_req_msg, req_msg_len, 0,
131 			    (struct sockaddr *)&addr, sizeof(addr));
132 	if (rc == -1) {
133 		return PLDM_REQUESTER_SEND_FAIL;
134 	}
135 	return PLDM_REQUESTER_SUCCESS;
136 }
137 
138 LIBPLDM_ABI_TESTING
139 int pldm_transport_af_mctp_init(struct pldm_transport_af_mctp **ctx)
140 {
141 	if (!ctx || *ctx) {
142 		return -EINVAL;
143 	}
144 
145 	struct pldm_transport_af_mctp *af_mctp =
146 		calloc(1, sizeof(struct pldm_transport_af_mctp));
147 	if (!af_mctp) {
148 		return -ENOMEM;
149 	}
150 
151 	af_mctp->transport.name = AF_MCTP_NAME;
152 	af_mctp->transport.version = 1;
153 	af_mctp->transport.recv = pldm_transport_af_mctp_recv;
154 	af_mctp->transport.send = pldm_transport_af_mctp_send;
155 	af_mctp->socket = socket(AF_MCTP, SOCK_DGRAM, 0);
156 	if (af_mctp->socket == -1) {
157 		free(af_mctp);
158 		return -1;
159 	}
160 
161 	if (pldm_socket_sndbuf_init(&af_mctp->socket_send_buf,
162 				    af_mctp->socket)) {
163 		close(af_mctp->socket);
164 		free(af_mctp);
165 		return -1;
166 	}
167 
168 	*ctx = af_mctp;
169 	return 0;
170 }
171 
172 LIBPLDM_ABI_TESTING
173 void pldm_transport_af_mctp_destroy(struct pldm_transport_af_mctp *ctx)
174 {
175 	if (!ctx) {
176 		return;
177 	}
178 	close(ctx->socket);
179 	free(ctx);
180 }
181