xref: /openbmc/libpldm/src/transport/af-mctp.c (revision 2a6a342d4b4bc4e59753ec155e659d7fef08dd22)
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_TESTING
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_TESTING
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 LIBPLDM_ABI_TESTING
64 int pldm_transport_af_mctp_map_tid(struct pldm_transport_af_mctp *ctx,
65 				   pldm_tid_t tid, mctp_eid_t eid)
66 {
67 	ctx->tid_eid_map[eid] = tid;
68 
69 	return 0;
70 }
71 
72 LIBPLDM_ABI_TESTING
73 int pldm_transport_af_mctp_unmap_tid(struct pldm_transport_af_mctp *ctx,
74 				     __attribute__((unused)) pldm_tid_t tid,
75 				     mctp_eid_t eid)
76 {
77 	ctx->tid_eid_map[eid] = 0;
78 
79 	return 0;
80 }
81 
82 static pldm_requester_rc_t pldm_transport_af_mctp_recv(struct pldm_transport *t,
83 						       pldm_tid_t tid,
84 						       void **pldm_msg,
85 						       size_t *msg_len)
86 {
87 	struct pldm_transport_af_mctp *af_mctp = transport_to_af_mctp(t);
88 	mctp_eid_t eid = 0;
89 	ssize_t length;
90 	int rc;
91 
92 	rc = pldm_transport_af_mctp_get_eid(af_mctp, tid, &eid);
93 	if (rc) {
94 		return PLDM_REQUESTER_RECV_FAIL;
95 	}
96 
97 	length = recv(af_mctp->socket, NULL, 0, MSG_PEEK | MSG_TRUNC);
98 	if (length <= 0) {
99 		return PLDM_REQUESTER_RECV_FAIL;
100 	}
101 
102 	*pldm_msg = malloc(length);
103 	length = recv(af_mctp->socket, *pldm_msg, length, MSG_TRUNC);
104 	if (length < (ssize_t)sizeof(struct pldm_msg_hdr)) {
105 		free(*pldm_msg);
106 		return PLDM_REQUESTER_INVALID_RECV_LEN;
107 	}
108 
109 	*msg_len = length;
110 
111 	return PLDM_REQUESTER_SUCCESS;
112 }
113 
114 static pldm_requester_rc_t pldm_transport_af_mctp_send(struct pldm_transport *t,
115 						       pldm_tid_t tid,
116 						       const void *pldm_msg,
117 						       size_t msg_len)
118 {
119 	struct pldm_transport_af_mctp *af_mctp = transport_to_af_mctp(t);
120 	mctp_eid_t eid = 0;
121 	if (pldm_transport_af_mctp_get_eid(af_mctp, tid, &eid)) {
122 		return PLDM_REQUESTER_SEND_FAIL;
123 	}
124 
125 	struct sockaddr_mctp addr = { 0 };
126 	addr.smctp_family = AF_MCTP;
127 	addr.smctp_addr.s_addr = eid;
128 	addr.smctp_type = MCTP_MSG_TYPE_PLDM;
129 	addr.smctp_tag = MCTP_TAG_OWNER;
130 
131 	if (msg_len > INT_MAX ||
132 	    pldm_socket_sndbuf_accomodate(&(af_mctp->socket_send_buf),
133 					  (int)msg_len)) {
134 		return PLDM_REQUESTER_SEND_FAIL;
135 	}
136 
137 	ssize_t rc = sendto(af_mctp->socket, pldm_msg, msg_len, 0,
138 			    (struct sockaddr *)&addr, sizeof(addr));
139 	if (rc == -1) {
140 		return PLDM_REQUESTER_SEND_FAIL;
141 	}
142 	return PLDM_REQUESTER_SUCCESS;
143 }
144 
145 LIBPLDM_ABI_TESTING
146 int pldm_transport_af_mctp_init(struct pldm_transport_af_mctp **ctx)
147 {
148 	if (!ctx || *ctx) {
149 		return -EINVAL;
150 	}
151 
152 	struct pldm_transport_af_mctp *af_mctp =
153 		calloc(1, sizeof(struct pldm_transport_af_mctp));
154 	if (!af_mctp) {
155 		return -ENOMEM;
156 	}
157 
158 	af_mctp->transport.name = AF_MCTP_NAME;
159 	af_mctp->transport.version = 1;
160 	af_mctp->transport.recv = pldm_transport_af_mctp_recv;
161 	af_mctp->transport.send = pldm_transport_af_mctp_send;
162 	af_mctp->transport.init_pollfd = pldm_transport_af_mctp_init_pollfd;
163 	af_mctp->socket = socket(AF_MCTP, SOCK_DGRAM, 0);
164 	if (af_mctp->socket == -1) {
165 		free(af_mctp);
166 		return -1;
167 	}
168 
169 	if (pldm_socket_sndbuf_init(&af_mctp->socket_send_buf,
170 				    af_mctp->socket)) {
171 		close(af_mctp->socket);
172 		free(af_mctp);
173 		return -1;
174 	}
175 
176 	*ctx = af_mctp;
177 	return 0;
178 }
179 
180 LIBPLDM_ABI_TESTING
181 void pldm_transport_af_mctp_destroy(struct pldm_transport_af_mctp *ctx)
182 {
183 	if (!ctx) {
184 		return;
185 	}
186 	close(ctx->socket);
187 	free(ctx);
188 }
189