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