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