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