RFC 5444 handler library Copyright (c) 2010 Henning Rogge The rfc 5444 library is a combined parser and generator for the 'Generalized Mobile Ad Hoc Network (MANET) Packet/Message Format'. The library is split into a separate reader and writer part, both of them use a generic avl-tree and double-linked list implementation. The reader and writer allow multiple independent code blocks to read overlapping parts of a RFC 5444 data stream and assemble packets and messages together. This allow API users to separate different sub- protocol in their codebase (e.g. NHDP and OLSRv2). ======================= RFC 5444 writer ======================= 1) general information 1.1) using the writer 1.2) packet sending 1.3) interfaces 1.4) maximum transmission unit 2) packets 2.1) packet creator 2.2) packet content provider 2.3) callback order for packets 3) messages 3.1) message creator 3.2) message content provider 3.3) message fragmentation 3.4) callback order for messages 1) general information ********************** The rfc5444 writer can be used on two different levels of rfc5444, packets and messages. Other than the reader, it has no third independant category for addresses in messages. For each type of message there has to be ONE (and only one) registered user responsible for the fixed message header. Only this user of the writer can manipulate the message header fields (hopcount, hoplimit, originator and sequence number) and set the address length for the message. Because there are no 'types' of packets, there is only ONE user responsible for the packet header. The only thing he can do is set a sequence number for the packet header. There can be multiple content providers for each packet header and for each message type. Each content provider has a priority and the parser will call them in the right order. Packet content providers can add TLVs to the packet header. Message content providers can add TLVs to their message header, can add addresses to it and add TLVs to this addresses. Each TLV type that should be added to an address has to be registered with the rfc5444 writer in advance. 1.1) using the writer ********************* Before using the writer you have to allocate a writer context by calling rfc5444_writer_init(). All functions of the writer need a pointer to this context as a parameter. If you don't need the writer anymore, call rfc5444_writer_cleanup() to free all allocated memory of the writer including the writer context itself. After allocating the context you can register and unregister all necessary callbacks to the writer, as long as you do this outside of the writer callbacks itself! To start a message call the rfc5444_writer_create_message() function. The writer will begin to call all callbacks associated with the message type. The message will then be stored in the packet buffer. The function rfc5444_writer_forward_msg() can be used to forward a received binary rfc5444 message by appending it to the current package. rfc5444_writer_flush() will clear the current packet buffer and send the packet. A parameter controls if this will generate an 'empty' packet if no messages are currently inside the packet buffer. 1.2) packet sending ******************* The rfc5444 writer cannot know how your protocol sends the finished packets. Because of this you have to set the sendPacket() callback in the writer context before generating messages and packet. The writer will call the callback once for each outgoing packet. 1.3) interfaces *************** The rfc5444 writer has support for multiple outgoing interfaces. Each interface have to be created with the rfc5444_writer_register_interface() function. When creating or forwarding a message the caller has to support a callback to a function that decides, if a certain interface is used for this message. This way a message going out on multiple interfaces does not need to be created/compressed multiple times. 1.4) maximum transmission unit ****************************** The writer has to deal with the problem of MTU size of interfaces to fragment the messages correctly. Each outgoing interface might have its own MTU, but even making sure that all generated messages will fit into the smallest interface MTU used for the message might not enough. If there are interfaces somewhere in the MANET with a smaller maximum message size (either because of a small MTU of the link or a large amount of packet TLVs for this link), all messages in the whole MANET must be small enough to fit through this bottleneck. Because of this you have to specify a maximum message size (in bytes) when initializing the writer AND specify a MTU for each registered interface. 2) packets ********** There are no distinct types of packets and packets cannot contain addresses, so the options for registering callbacks are more primitive than the callbacks for messages. All packet specific callbacks are interface specific. 2.1) packet creator ******************* There is no register/unregister function for a packet creator, there are just two callback pointers in the rfc5444_writer object. The first callback addPacketHeader() allows the packet creator to define if the packet should contain the sequence number. Both this and the second callback finishPacketHeader() can set the sequence number of the packet, if it was activated by the first callback. The addPacketHeader() callback will be the first called when a new packet is started. finishPacketHeader() is the last one called before the new packet is send. 2.2) packet content provider **************************** There can be multiple packet content providers registered to a rfc5444 writer. Each of them has a pair of callbacks to add TLVs to the message. The addPacketTLVs() callback allows a content provider to either add a TLV directly to the packet header or allocate memory for adding one later. The finishPacketTLVs() callback can use the allocated memory from the first callback to add TLVs after all messages have been created. The addPacketTLVs() callbacks will be called in the right order defined by their priority right after the addPacketHeader() callback. The finishPacketTLVs() callbacks will be called in reverse order after all messages have been created right before the finishPacketHeader() one. 2.3) callback order for packets ******************************* The order of callbacks for packets can be described as: New packet is started * addPacketHeader() * addPacketTLVs() (provider 1) ... * addPacketTLVs() (provider n) Message creation starts Message creation (fragment 1) finishes * finishPacketTLVs() (provider n) ... * finishPacketTLVs() (provider 1) * finishPacketHeader() ... Message creation (fragment n) finishes * finishPacketTLVs() (provider n) ... * finishPacketTLVs() (provider 1) * finishPacketHeader() 3) messages *********** Each message type registered to the rfc5444 writer has a single message creator and may have multiple content providers. Without a registered message creator even multiple content provider will be useless, because the writer will not create a message of this type. Message fragmentation is a special case when the all of the output of the message content providers does not fit into a single packet. Chapter 3.3 will explain the stategy of the writer fragmenting the message and how this will interact with the callbacks. Some messages are unique for each interface. If the if_specific parameter of rfc5444_writer_register_message() is true, the writer will call the message creation process once for each interface instead of generating a common message for interfaces in one step. 3.1) message creator ******************** The message creators are a pair of callbacks for a registered message similar to the packet creator. The first callback addMessageHeader() allows the message creator to define which header elements (hopcount, hoplimit, originator, sequence number) the message header will have. It can also set an address length for the message. Both this and the second callback finishMessageHeader() can set all four message header fields, if they were activated by the first callback. The addMessageHeader() callback will be the first called when the message is generated. finishMessageHeader() is the last one called before the binary message content is appended to the packet buffer. 3.2) message content provider ***************************** There can be multiple message content providers registered for each message type. Each of them has a pair of callbacks to add TLVs and one callback to add addresses and address-tlvs to the message. The addMessageTLVs() callback allows a content provider to either add a TLV directly to the message header or allocate memory for adding one later. The addAddresses() callback allows adding new addresses and TLVs for them to the message. Each tlvtype has to be registered with the rfc5444 writer. If multiple content providers add the same address, their tlvs will be merged together. The finishMessageTLVs() callback can use the allocated memory from the first callback to add TLVs after all addresses and addresstlvs have been added. The addMessageTLVs() callbacks will be called in the defined order after the addMessageHeader() callback. After this the addAddresses() callback of each provider is called in the same order, followed by the finishMessageTLVs() callback in reverse order. 3.3) message fragmentation ************************** RFC 5444 message fragmentation is a problem for a generic writer with multiple input sources. Because it's impossible for any of the content providers to calculate the necessary borders to split a message, the writer has to assist them. The strategy of this rfc5444 writer is simple, but will hopefully be sufficient for most usecases. The writer will begin to allocate space for both the message header, the message TLVs and the TLVs allocated by the addMessageTLVs() callback. It then starts to add one address at a time including it's tlvs. If the message gets too large the parser stops, calls all involved finishMessageTLVs() callbacks and the finishMessageHeader() callback. At this point, the first fragment will added to the packet and the packet will be sent in order to clear the packet buffer. Then the writer clears it's message buffer from all optional TLVs allocated by addMessageTLVs() and all addresses including their TLVs and begins to add the next address including its tlvs. This will continue until the last fragment has been finalized by calling the finishMessageTLVs() and finishMessageHeader() callback. If there is a single address with TLVs which do not fit into a message an error will be thrown and the message generation will stop. It's the job of the user to make sure that even with reserved packet TLVs and message TLVs there is enough MTU left to put at least any single address including its tlvs inside. 3.4) callback order for messages ******************************** The order of callbacks for messages can be described as: Message generation starts * addMessageHeader() * addMessageTLVs() (provider 1) ... * addMessageTLVs() (provider n) * addAddresses() (provider 1) ... * addAddresses() (provider n) Message fragment 1 * finishMessageTLVs() (provider n) ... * finishMessageTLVs() (provider 1) * finishMessageHeader() ... Message fragment n * finishMessageTLVs() (provider n) ... * finishMessageTLVs() (provider 1) * finishMessageHeader()