Stacking Protocols

I find myself writing a program in C that is supposed to handle multiple protocols. At its entry point, the protocol is Platform Communication Channel (extended memory, type 3 and type 4). Embedded in that is an Management Component Transport Protocol (MCTP) message, and embedded in that is one of many different protocols.

I might want to swap out the PCC layer in the future for….something else. MCTP can come over many different protocols, so there is a good be that the tool will be more useful if it can assume that the protocol outside of the MCTP layer is something other than MCTP.

One problem I have is that the MCTP header does not have a length field. We do not not know how long the payload is; all it has is version, source, destination, and flags. Thus, if we want to pass a buffer of type MCTP header along, and we want the length, we need to pass it in a separate field. This goes both for incoming (how many bytes to read) and outgoing (how many bytes to write).

My initial thought on writing this layer is to have a request/response pair for each layer of the protocol. For PCC, I could just do this. For all the other internal ones, I would need to pass length in and length out for each handler. Length in will not change, but length out might, so this needs to be passed as pointer. This leads to functions that look like this:

void handle_mctp_control_message(struct mctp_hdr * mctp_req,  int req_len,  struct mctp_hdr * mctp_resp,  int *resp_len)
{

}

I will also need to be converting from outer protocols to inner protocols. So I will need code like this:

struct mctp_hdr * mctp_req  = (struct mctp_hdr *)pcc_req->buffer_start;
int mctp_req_len = pcc_req->length - sizeof(MCTP_SIGNATURE);
struct mctp_hdr * mctp_rsp  = (struct mctp_hdr *)pcc_rsp->buffer_start;

The outgoing length would be initialized to 0, and grow as each later of the protocol stack adds its own data. However, I am planning on pre-allocating the buffer, and just passing a pointer to the location where the protocol is supposed to write its data. IN order to confirm we don’t want to write past the end of the function, we will have to pass the overall buffer length in, maybe shortened by the amount we need to reserve for the outer headers.

If each protocol header had a smart pointer, I could pass those around instead. Something like:

struct pcc_header_p {
    struct pcc_header * header;
    int buffer_length;
}

struct mctp_header_p {
    struct mctp_header * header;
    int length;
    int buffer_length;
}

Then it would be fairly easy to write a function that, given an *pcc_header_p populates a struct mctp_header_p that points to it.

void pcc_2_mctp(struct pcc_header_p *pcc, struct mctp_header_p *mctp)
{
   mctp->header = (struct mctp_header *)pcc->header[sizeof struct pcc_header];
   mctp->len =  pcc->header.length - sizeof(MCTP_SIGNATURE);
   mctp->buffer_length = pcc->buffer->length - sizof(struct pcc_header);
     
}

This seems like it would benefit from a set of preprocesser Macros. I know that Qemu does something like this. But for a first pass, I think I can just code it up like this.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.