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