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