Skip to content

Protocols

Daniele Lacamera edited this page Jun 10, 2018 · 9 revisions

A TCP/IP stack is made of layers, each one represented by a protocol. The main structure representing a protocol in picoTCP is the structure pico_protocol defined in pico_protocols.h.

    struct pico_protocol {
        char name[MAX_PROTOCOL_NAME];
        uint32_t hash;
        enum pico_layer layer;
        uint16_t proto_number;
        struct pico_queue *q_in;
        struct pico_queue *q_out;
        struct pico_frame *(*alloc)(struct pico_protocol *self, uint16_t size); /* Frame allocation. */
        int (*push)(struct pico_protocol *self, struct pico_frame *p);    /* Push function, for active outgoing pkts from above */
        int (*process_out)(struct pico_protocol *self, struct pico_frame *p);  /* Send loop. */
        int (*process_in)(struct pico_protocol *self, struct pico_frame *p);  /* Recv loop. */
        uint16_t (*get_mtu)(struct pico_protocol *self);
    }

Here is a brief description of the fields:

  • name contains a unique name used to identify the protocol implementation. Values for this fields look like “ipv4” or “tcp”

  • hash is a signature obtained by hashing the name with the pico_hash function. It is used for fast matches in ordered structures and it is generated automatically when the protocol gets registered to the stack.

  • layer is an identifier of the OSI layer where the protocol belongs to. For convention, all the protocols that connect directly to the networking core protocols (IPv4/IPv6), such as ICMP, must be grouped in the PICO_PROTO_TRANSPORT layer.

  • q_in and q_out refer to the queues of frames traversing the protocol in either direction. For a better understanding of the queuing mechanism, refer to the Queues section in this chapter.

  • alloc is a pointer to the function, provided by the protocol, that offers the capability of allocating outgoing frames at this level, which would take into account all the protocols overhead in the stack. This function is only mandatory if the top layers utilize a generic function for the frame allocation in the bottom layers. For example, in order to allocate an outgoing IP frame, the IPv4 protocol implementation associates this pointer to a function called pico_ipv4_alloc, which takes into account the overhead of the IPv4 header and the possible underlying datalink headers.

    static struct pico_frame *pico_ipv4_alloc(struct pico_protocol *self, uint16_t size)
    {
        struct pico_frame *f =  pico_frame_alloc(size + PICO_SIZE_IP4HDR + PICO_SIZE_ETHHDR);
        IGNORE_PARAMETER(self);
        if (!f)
            return NULL;
        f->datalink_hdr = f->buffer;
        f->net_hdr = f->buffer + PICO_SIZE_ETHHDR;
        f->net_len = PICO_SIZE_IP4HDR;
        f->transport_hdr = f->net_hdr + PICO_SIZE_IP4HDR;
        f->transport_len = size;
        f->len =  size + PICO_SIZE_IP4HDR;
        return f;
    }
  • The push function pointer is the entry point for the upper layers to communicate that a new frame needs to be enqueued for transmission. The protocol can perform all the needed checks in this function, prepend information in the header, and decide whether or not it is the case to enqueue the packet for later transmission - or have the frame processed inline to its next destination.

  • process_in and process_out are the two entry point from the stack internal scheduler. These functions will be called at regular intervals when the protocol is registered to the stack. The goal of these functions is to get rid of the frames in the queues q_in and q_out respectively, and forward them to their next destinations.

  • The get_mtu hook is not mandatory, and can be used to enforce a maximum packet size for the outgoing packets that cross the layer. If your protocol works with a certain packet or frame size, this field might be useful to propagate this information along the stack.

In order to add a new protocol to the stack, a new instance of the structure pico_protocol needs to be filled in, and then the API function pico_protocol_init can be called. From that moment on, the protocol is part of the stack and can start to interact with the other components.

Protocol output: diagram

Protocol input: diagram

Clone this wiki locally