1*4058b2cbSMatt Johnston #include <string.h>
2*4058b2cbSMatt Johnston #include <stdbool.h>
3*4058b2cbSMatt Johnston #include <stdint.h>
4*4058b2cbSMatt Johnston #include <errno.h>
5*4058b2cbSMatt Johnston
6*4058b2cbSMatt Johnston #include "libmctp-cmds.h"
7*4058b2cbSMatt Johnston #include "libmctp-alloc.h"
8*4058b2cbSMatt Johnston #include "libmctp-log.h"
9*4058b2cbSMatt Johnston #include "core-internal.h"
10*4058b2cbSMatt Johnston
11*4058b2cbSMatt Johnston #include "control.h"
12*4058b2cbSMatt Johnston
fill_resp(const void * req,struct mctp_ctrl_msg_hdr * hdr)13*4058b2cbSMatt Johnston static void fill_resp(const void *req, struct mctp_ctrl_msg_hdr *hdr)
14*4058b2cbSMatt Johnston {
15*4058b2cbSMatt Johnston const struct mctp_ctrl_msg_hdr *req_hdr = req;
16*4058b2cbSMatt Johnston hdr->ic_msg_type = MCTP_CTRL_HDR_MSG_TYPE;
17*4058b2cbSMatt Johnston hdr->rq_dgram_inst = req_hdr->rq_dgram_inst &
18*4058b2cbSMatt Johnston MCTP_CTRL_HDR_INSTANCE_ID_MASK;
19*4058b2cbSMatt Johnston hdr->command_code = req_hdr->command_code;
20*4058b2cbSMatt Johnston }
21*4058b2cbSMatt Johnston
mctp_ctrl_set_endpoint_id(struct mctp_bus * bus,uint8_t src_eid,uint8_t msg_tag,const void * data,size_t len)22*4058b2cbSMatt Johnston static uint8_t mctp_ctrl_set_endpoint_id(struct mctp_bus *bus, uint8_t src_eid,
23*4058b2cbSMatt Johnston uint8_t msg_tag, const void *data,
24*4058b2cbSMatt Johnston size_t len)
25*4058b2cbSMatt Johnston {
26*4058b2cbSMatt Johnston if (len != sizeof(struct mctp_ctrl_cmd_set_endpoint_id_req)) {
27*4058b2cbSMatt Johnston return MCTP_CTRL_CC_ERROR_INVALID_LENGTH;
28*4058b2cbSMatt Johnston }
29*4058b2cbSMatt Johnston const struct mctp_ctrl_cmd_set_endpoint_id_req *req = data;
30*4058b2cbSMatt Johnston
31*4058b2cbSMatt Johnston uint8_t op = req->operation & MCTP_CTRL_SET_EID_OP_MASK;
32*4058b2cbSMatt Johnston if (!(op == MCTP_CTRL_SET_EID_OP_SET ||
33*4058b2cbSMatt Johnston op == MCTP_CTRL_SET_EID_OP_FORCE)) {
34*4058b2cbSMatt Johnston return MCTP_CTRL_CC_ERROR_INVALID_DATA;
35*4058b2cbSMatt Johnston }
36*4058b2cbSMatt Johnston
37*4058b2cbSMatt Johnston if (mctp_bus_set_eid(bus->binding, req->eid)) {
38*4058b2cbSMatt Johnston return MCTP_CTRL_CC_ERROR_INVALID_DATA;
39*4058b2cbSMatt Johnston }
40*4058b2cbSMatt Johnston
41*4058b2cbSMatt Johnston struct mctp_ctrl_cmd_set_endpoint_id_resp *resp =
42*4058b2cbSMatt Johnston __mctp_msg_alloc(sizeof(*resp), bus->mctp);
43*4058b2cbSMatt Johnston if (!resp) {
44*4058b2cbSMatt Johnston mctp_prdebug("no response buffer");
45*4058b2cbSMatt Johnston return MCTP_CTRL_CC_ERROR;
46*4058b2cbSMatt Johnston }
47*4058b2cbSMatt Johnston memset(resp, 0x00, sizeof(*resp));
48*4058b2cbSMatt Johnston fill_resp(data, &resp->hdr);
49*4058b2cbSMatt Johnston resp->completion_code = MCTP_CTRL_CC_SUCCESS;
50*4058b2cbSMatt Johnston resp->status = MCTP_CTRL_SET_EID_STATUS_ACCEPTED;
51*4058b2cbSMatt Johnston resp->eid = req->eid;
52*4058b2cbSMatt Johnston resp->pool_size = 0;
53*4058b2cbSMatt Johnston
54*4058b2cbSMatt Johnston int rc = mctp_message_tx_alloced(bus->mctp, src_eid, false, msg_tag,
55*4058b2cbSMatt Johnston resp, sizeof(*resp));
56*4058b2cbSMatt Johnston if (!rc) {
57*4058b2cbSMatt Johnston mctp_prdebug("set_endpoint_id response send failed: %d", rc);
58*4058b2cbSMatt Johnston }
59*4058b2cbSMatt Johnston return MCTP_CTRL_CC_SUCCESS;
60*4058b2cbSMatt Johnston }
61*4058b2cbSMatt Johnston
mctp_ctrl_get_endpoint_id(struct mctp_bus * bus,uint8_t src_eid,uint8_t msg_tag,const void * data,size_t len)62*4058b2cbSMatt Johnston static uint8_t mctp_ctrl_get_endpoint_id(struct mctp_bus *bus, uint8_t src_eid,
63*4058b2cbSMatt Johnston uint8_t msg_tag, const void *data,
64*4058b2cbSMatt Johnston size_t len)
65*4058b2cbSMatt Johnston {
66*4058b2cbSMatt Johnston if (len != sizeof(struct mctp_ctrl_msg_hdr)) {
67*4058b2cbSMatt Johnston /* Expect empty request */
68*4058b2cbSMatt Johnston return MCTP_CTRL_CC_ERROR_INVALID_LENGTH;
69*4058b2cbSMatt Johnston }
70*4058b2cbSMatt Johnston (void)data;
71*4058b2cbSMatt Johnston
72*4058b2cbSMatt Johnston struct mctp_ctrl_cmd_get_endpoint_id_resp *resp =
73*4058b2cbSMatt Johnston __mctp_msg_alloc(sizeof(*resp), bus->mctp);
74*4058b2cbSMatt Johnston if (!resp) {
75*4058b2cbSMatt Johnston mctp_prdebug("no response buffer");
76*4058b2cbSMatt Johnston return MCTP_CTRL_CC_ERROR;
77*4058b2cbSMatt Johnston }
78*4058b2cbSMatt Johnston memset(resp, 0x00, sizeof(*resp));
79*4058b2cbSMatt Johnston fill_resp(data, &resp->hdr);
80*4058b2cbSMatt Johnston resp->completion_code = MCTP_CTRL_CC_SUCCESS;
81*4058b2cbSMatt Johnston resp->endpoint_id = bus->eid;
82*4058b2cbSMatt Johnston resp->endpoint_type = MCTP_CTRL_ENDPOINT_TYPE_SIMPLE |
83*4058b2cbSMatt Johnston MCTP_CTRL_ENDPOINT_ID_TYPE_STATIC;
84*4058b2cbSMatt Johnston resp->medium_specific = 0x00;
85*4058b2cbSMatt Johnston
86*4058b2cbSMatt Johnston int rc = mctp_message_tx_alloced(bus->mctp, src_eid, false, msg_tag,
87*4058b2cbSMatt Johnston resp, sizeof(*resp));
88*4058b2cbSMatt Johnston if (!rc) {
89*4058b2cbSMatt Johnston mctp_prdebug("get_endpoint_id response send failed: %d", rc);
90*4058b2cbSMatt Johnston }
91*4058b2cbSMatt Johnston return MCTP_CTRL_CC_SUCCESS;
92*4058b2cbSMatt Johnston }
93*4058b2cbSMatt Johnston
94*4058b2cbSMatt Johnston #define MCTP_PROTOCOL_COUNT 4
95*4058b2cbSMatt Johnston /* Big endian */
96*4058b2cbSMatt Johnston const uint8_t MCTP_PROTOCOL_VERSIONS[MCTP_PROTOCOL_COUNT * 4] = {
97*4058b2cbSMatt Johnston // 1.0
98*4058b2cbSMatt Johnston 0xf1,
99*4058b2cbSMatt Johnston 0xf0,
100*4058b2cbSMatt Johnston 0xff,
101*4058b2cbSMatt Johnston 0x00,
102*4058b2cbSMatt Johnston // 1.1
103*4058b2cbSMatt Johnston 0xf1,
104*4058b2cbSMatt Johnston 0xf1,
105*4058b2cbSMatt Johnston 0xff,
106*4058b2cbSMatt Johnston 0x00,
107*4058b2cbSMatt Johnston // 1.2
108*4058b2cbSMatt Johnston 0xf1,
109*4058b2cbSMatt Johnston 0xf2,
110*4058b2cbSMatt Johnston 0xff,
111*4058b2cbSMatt Johnston 0x00,
112*4058b2cbSMatt Johnston // 1.3.3
113*4058b2cbSMatt Johnston 0xf1,
114*4058b2cbSMatt Johnston 0xf3,
115*4058b2cbSMatt Johnston 0xf3,
116*4058b2cbSMatt Johnston 0x00,
117*4058b2cbSMatt Johnston };
118*4058b2cbSMatt Johnston
mctp_ctrl_get_version(struct mctp_bus * bus,uint8_t src_eid,uint8_t msg_tag,const void * data,size_t len)119*4058b2cbSMatt Johnston static uint8_t mctp_ctrl_get_version(struct mctp_bus *bus, uint8_t src_eid,
120*4058b2cbSMatt Johnston uint8_t msg_tag, const void *data,
121*4058b2cbSMatt Johnston size_t len)
122*4058b2cbSMatt Johnston {
123*4058b2cbSMatt Johnston if (len != sizeof(struct mctp_ctrl_cmd_get_version_req)) {
124*4058b2cbSMatt Johnston return MCTP_CTRL_CC_ERROR_INVALID_LENGTH;
125*4058b2cbSMatt Johnston }
126*4058b2cbSMatt Johnston const struct mctp_ctrl_cmd_get_version_req *req = data;
127*4058b2cbSMatt Johnston
128*4058b2cbSMatt Johnston switch (req->msg_type) {
129*4058b2cbSMatt Johnston case 0x00:
130*4058b2cbSMatt Johnston case 0xff:
131*4058b2cbSMatt Johnston /* Only have versions for MCTP base or control */
132*4058b2cbSMatt Johnston break;
133*4058b2cbSMatt Johnston default:
134*4058b2cbSMatt Johnston return MCTP_CTRL_VERSIONS_NOT_SUPPORTED;
135*4058b2cbSMatt Johnston }
136*4058b2cbSMatt Johnston
137*4058b2cbSMatt Johnston /* Return only the versions for MCTP */
138*4058b2cbSMatt Johnston size_t total_sz = sizeof(struct mctp_ctrl_cmd_get_version_resp) +
139*4058b2cbSMatt Johnston sizeof(MCTP_PROTOCOL_VERSIONS);
140*4058b2cbSMatt Johnston
141*4058b2cbSMatt Johnston struct mctp_ctrl_cmd_get_version_resp *resp =
142*4058b2cbSMatt Johnston __mctp_msg_alloc(total_sz, bus->mctp);
143*4058b2cbSMatt Johnston if (!resp) {
144*4058b2cbSMatt Johnston mctp_prdebug("no response buffer");
145*4058b2cbSMatt Johnston return MCTP_CTRL_CC_ERROR;
146*4058b2cbSMatt Johnston }
147*4058b2cbSMatt Johnston memset(resp, 0x00, total_sz);
148*4058b2cbSMatt Johnston fill_resp(data, &resp->hdr);
149*4058b2cbSMatt Johnston resp->completion_code = MCTP_CTRL_CC_SUCCESS;
150*4058b2cbSMatt Johnston resp->version_count = MCTP_PROTOCOL_COUNT;
151*4058b2cbSMatt Johnston memcpy(resp->versions, MCTP_PROTOCOL_VERSIONS,
152*4058b2cbSMatt Johnston sizeof(MCTP_PROTOCOL_VERSIONS));
153*4058b2cbSMatt Johnston
154*4058b2cbSMatt Johnston int rc = mctp_message_tx_alloced(bus->mctp, src_eid, false, msg_tag,
155*4058b2cbSMatt Johnston resp, total_sz);
156*4058b2cbSMatt Johnston if (!rc) {
157*4058b2cbSMatt Johnston mctp_prdebug("mctp get_version response send failed: %d", rc);
158*4058b2cbSMatt Johnston }
159*4058b2cbSMatt Johnston return MCTP_CTRL_CC_SUCCESS;
160*4058b2cbSMatt Johnston }
161*4058b2cbSMatt Johnston
mctp_ctrl_get_types(struct mctp_bus * bus,uint8_t src_eid,uint8_t msg_tag,const void * data,size_t len)162*4058b2cbSMatt Johnston static uint8_t mctp_ctrl_get_types(struct mctp_bus *bus, uint8_t src_eid,
163*4058b2cbSMatt Johnston uint8_t msg_tag, const void *data,
164*4058b2cbSMatt Johnston size_t len)
165*4058b2cbSMatt Johnston {
166*4058b2cbSMatt Johnston if (len != sizeof(struct mctp_ctrl_msg_hdr)) {
167*4058b2cbSMatt Johnston return MCTP_CTRL_CC_ERROR_INVALID_LENGTH;
168*4058b2cbSMatt Johnston }
169*4058b2cbSMatt Johnston (void)data;
170*4058b2cbSMatt Johnston
171*4058b2cbSMatt Johnston size_t total_sz = sizeof(struct mctp_ctrl_cmd_get_types_resp) +
172*4058b2cbSMatt Johnston bus->mctp->control.num_msg_types;
173*4058b2cbSMatt Johnston
174*4058b2cbSMatt Johnston struct mctp_ctrl_cmd_get_types_resp *resp =
175*4058b2cbSMatt Johnston __mctp_msg_alloc(total_sz, bus->mctp);
176*4058b2cbSMatt Johnston if (!resp) {
177*4058b2cbSMatt Johnston mctp_prdebug("no response buffer");
178*4058b2cbSMatt Johnston return MCTP_CTRL_CC_ERROR;
179*4058b2cbSMatt Johnston }
180*4058b2cbSMatt Johnston memset(resp, 0x00, total_sz);
181*4058b2cbSMatt Johnston fill_resp(data, &resp->hdr);
182*4058b2cbSMatt Johnston resp->completion_code = MCTP_CTRL_CC_SUCCESS;
183*4058b2cbSMatt Johnston resp->type_count = bus->mctp->control.num_msg_types;
184*4058b2cbSMatt Johnston memcpy(resp->types, bus->mctp->control.msg_types,
185*4058b2cbSMatt Johnston bus->mctp->control.num_msg_types);
186*4058b2cbSMatt Johnston
187*4058b2cbSMatt Johnston int rc = mctp_message_tx_alloced(bus->mctp, src_eid, false, msg_tag,
188*4058b2cbSMatt Johnston resp, total_sz);
189*4058b2cbSMatt Johnston if (!rc) {
190*4058b2cbSMatt Johnston mctp_prdebug("mctp get_types response send failed: %d", rc);
191*4058b2cbSMatt Johnston }
192*4058b2cbSMatt Johnston return MCTP_CTRL_CC_SUCCESS;
193*4058b2cbSMatt Johnston }
194*4058b2cbSMatt Johnston
reply_error(struct mctp * mctp,uint8_t src_eid,uint8_t msg_tag,const struct mctp_ctrl_msg_hdr * ctrl_hdr,uint8_t ccode)195*4058b2cbSMatt Johnston static void reply_error(struct mctp *mctp, uint8_t src_eid, uint8_t msg_tag,
196*4058b2cbSMatt Johnston const struct mctp_ctrl_msg_hdr *ctrl_hdr, uint8_t ccode)
197*4058b2cbSMatt Johnston {
198*4058b2cbSMatt Johnston struct mctp_ctrl_cmd_empty_resp *resp =
199*4058b2cbSMatt Johnston __mctp_msg_alloc(sizeof(*resp), mctp);
200*4058b2cbSMatt Johnston if (!resp) {
201*4058b2cbSMatt Johnston mctp_prdebug("no response buffer");
202*4058b2cbSMatt Johnston return;
203*4058b2cbSMatt Johnston }
204*4058b2cbSMatt Johnston memset(resp, 0x00, sizeof(*resp));
205*4058b2cbSMatt Johnston fill_resp(ctrl_hdr, &resp->hdr);
206*4058b2cbSMatt Johnston resp->completion_code = ccode;
207*4058b2cbSMatt Johnston
208*4058b2cbSMatt Johnston int rc = mctp_message_tx_alloced(mctp, src_eid, false, msg_tag, resp,
209*4058b2cbSMatt Johnston sizeof(*resp));
210*4058b2cbSMatt Johnston if (!rc) {
211*4058b2cbSMatt Johnston mctp_prdebug("error response send failed: %d", rc);
212*4058b2cbSMatt Johnston }
213*4058b2cbSMatt Johnston }
214*4058b2cbSMatt Johnston
215*4058b2cbSMatt Johnston /* Control message request handler. This will respond to the mandatory MCTP control
216*4058b2cbSMatt Johnston * commands */
mctp_control_handler(struct mctp_bus * bus,mctp_eid_t src_eid,bool tag_owner,uint8_t msg_tag,const void * data,size_t len)217*4058b2cbSMatt Johnston bool mctp_control_handler(struct mctp_bus *bus, mctp_eid_t src_eid,
218*4058b2cbSMatt Johnston bool tag_owner, uint8_t msg_tag, const void *data,
219*4058b2cbSMatt Johnston size_t len)
220*4058b2cbSMatt Johnston {
221*4058b2cbSMatt Johnston if (!tag_owner) {
222*4058b2cbSMatt Johnston // Not a request
223*4058b2cbSMatt Johnston return false;
224*4058b2cbSMatt Johnston }
225*4058b2cbSMatt Johnston
226*4058b2cbSMatt Johnston if (len < 1) {
227*4058b2cbSMatt Johnston // No type byte
228*4058b2cbSMatt Johnston return false;
229*4058b2cbSMatt Johnston }
230*4058b2cbSMatt Johnston
231*4058b2cbSMatt Johnston const struct mctp_ctrl_msg_hdr *ctrl_hdr = data;
232*4058b2cbSMatt Johnston if (ctrl_hdr->ic_msg_type != MCTP_CTRL_HDR_MSG_TYPE) {
233*4058b2cbSMatt Johnston // Not Control type
234*4058b2cbSMatt Johnston return false;
235*4058b2cbSMatt Johnston }
236*4058b2cbSMatt Johnston
237*4058b2cbSMatt Johnston if (len < sizeof(struct mctp_ctrl_msg_hdr)) {
238*4058b2cbSMatt Johnston // Drop short messages, but treat as handled
239*4058b2cbSMatt Johnston return true;
240*4058b2cbSMatt Johnston }
241*4058b2cbSMatt Johnston
242*4058b2cbSMatt Johnston if ((ctrl_hdr->rq_dgram_inst &
243*4058b2cbSMatt Johnston (MCTP_CTRL_HDR_FLAG_REQUEST | MCTP_CTRL_HDR_FLAG_DGRAM)) !=
244*4058b2cbSMatt Johnston MCTP_CTRL_HDR_FLAG_REQUEST) {
245*4058b2cbSMatt Johnston // Drop message, isn't a request.
246*4058b2cbSMatt Johnston // Treat as handled since TO bit was set.
247*4058b2cbSMatt Johnston return true;
248*4058b2cbSMatt Johnston }
249*4058b2cbSMatt Johnston
250*4058b2cbSMatt Johnston // A valid MCTP Control request has been received, process it
251*4058b2cbSMatt Johnston
252*4058b2cbSMatt Johnston uint8_t cc = MCTP_CTRL_CC_ERROR_UNSUPPORTED_CMD;
253*4058b2cbSMatt Johnston switch (ctrl_hdr->command_code) {
254*4058b2cbSMatt Johnston case MCTP_CTRL_CMD_SET_ENDPOINT_ID:
255*4058b2cbSMatt Johnston cc = mctp_ctrl_set_endpoint_id(bus, src_eid, msg_tag, data,
256*4058b2cbSMatt Johnston len);
257*4058b2cbSMatt Johnston break;
258*4058b2cbSMatt Johnston case MCTP_CTRL_CMD_GET_ENDPOINT_ID:
259*4058b2cbSMatt Johnston cc = mctp_ctrl_get_endpoint_id(bus, src_eid, msg_tag, data,
260*4058b2cbSMatt Johnston len);
261*4058b2cbSMatt Johnston break;
262*4058b2cbSMatt Johnston case MCTP_CTRL_CMD_GET_VERSION_SUPPORT:
263*4058b2cbSMatt Johnston cc = mctp_ctrl_get_version(bus, src_eid, msg_tag, data, len);
264*4058b2cbSMatt Johnston break;
265*4058b2cbSMatt Johnston case MCTP_CTRL_CMD_GET_MESSAGE_TYPE_SUPPORT:
266*4058b2cbSMatt Johnston cc = mctp_ctrl_get_types(bus, src_eid, msg_tag, data, len);
267*4058b2cbSMatt Johnston break;
268*4058b2cbSMatt Johnston default:
269*4058b2cbSMatt Johnston cc = MCTP_CTRL_CC_ERROR_UNSUPPORTED_CMD;
270*4058b2cbSMatt Johnston break;
271*4058b2cbSMatt Johnston }
272*4058b2cbSMatt Johnston
273*4058b2cbSMatt Johnston if (cc) {
274*4058b2cbSMatt Johnston reply_error(bus->mctp, src_eid, msg_tag, ctrl_hdr, cc);
275*4058b2cbSMatt Johnston }
276*4058b2cbSMatt Johnston
277*4058b2cbSMatt Johnston // No further handling required.
278*4058b2cbSMatt Johnston return true;
279*4058b2cbSMatt Johnston }
280*4058b2cbSMatt Johnston
mctp_control_add_type(struct mctp * mctp,uint8_t msg_type)281*4058b2cbSMatt Johnston int mctp_control_add_type(struct mctp *mctp, uint8_t msg_type)
282*4058b2cbSMatt Johnston {
283*4058b2cbSMatt Johnston /* Check for existing */
284*4058b2cbSMatt Johnston for (size_t i = 0; i < mctp->control.num_msg_types; i++) {
285*4058b2cbSMatt Johnston if (mctp->control.msg_types[i] == msg_type) {
286*4058b2cbSMatt Johnston return 0;
287*4058b2cbSMatt Johnston }
288*4058b2cbSMatt Johnston }
289*4058b2cbSMatt Johnston
290*4058b2cbSMatt Johnston if (mctp->control.num_msg_types == MCTP_CONTROL_MAX_TYPES) {
291*4058b2cbSMatt Johnston return -ENOSPC;
292*4058b2cbSMatt Johnston }
293*4058b2cbSMatt Johnston
294*4058b2cbSMatt Johnston mctp->control.msg_types[mctp->control.num_msg_types] = msg_type;
295*4058b2cbSMatt Johnston mctp->control.num_msg_types++;
296*4058b2cbSMatt Johnston return 0;
297*4058b2cbSMatt Johnston }
298*4058b2cbSMatt Johnston
mctp_control_remove_type(struct mctp * mctp,uint8_t msg_type)299*4058b2cbSMatt Johnston void mctp_control_remove_type(struct mctp *mctp, uint8_t msg_type)
300*4058b2cbSMatt Johnston {
301*4058b2cbSMatt Johnston for (size_t i = 0; i < mctp->control.num_msg_types; i++) {
302*4058b2cbSMatt Johnston if (mctp->control.msg_types[i] == msg_type) {
303*4058b2cbSMatt Johnston memmove(&mctp->control.msg_types[i],
304*4058b2cbSMatt Johnston &mctp->control.msg_types[i + 1],
305*4058b2cbSMatt Johnston mctp->control.num_msg_types - (i + 1));
306*4058b2cbSMatt Johnston mctp->control.num_msg_types--;
307*4058b2cbSMatt Johnston }
308*4058b2cbSMatt Johnston }
309*4058b2cbSMatt Johnston }
310