diff --git a/doc/doxygen/riot.doxyfile b/doc/doxygen/riot.doxyfile index a7765df70b..4d10e9740d 100644 --- a/doc/doxygen/riot.doxyfile +++ b/doc/doxygen/riot.doxyfile @@ -1324,7 +1324,10 @@ HTML_EXTRA_FILES = src/css/bootstrap.min.css \ src/js/jquery.smartmenus.bootstrap.min.js \ src/js/jquery-ui.min.js \ src/js/menu.js \ - src/js/riot-doxy.js + src/js/riot-doxy.js \ + ../../sys/net/application_layer/unicoap/docs/unicoap-layers.svg \ + ../../sys/net/application_layer/unicoap/docs/unicoap-layers-comms.svg \ + ../../sys/net/application_layer/unicoap/docs/unicoap-layers-comms-apis.svg # The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen # will adjust the colors in the style sheet and background images according to diff --git a/sys/net/application_layer/unicoap/docs/doc.md b/sys/net/application_layer/unicoap/docs/doc.md new file mode 100644 index 0000000000..2777950e93 --- /dev/null +++ b/sys/net/application_layer/unicoap/docs/doc.md @@ -0,0 +1,51 @@ +@defgroup net_unicoap unicoap: Unified CoAP Suite +@ingroup net +@brief Send requests and create server resources using the Constrained Application Protocol across different transports +@{ + +Module. Specify `USEMODULE += unicoap` in your application's Makefile. + +@warning `unicoap` is work in progress. Not all functionality is implemented in RIOT yet, however +the documentation already exists. Do not expect everything to work yet. + +`unicoap` is RIOT's unified and modular framework for communication via the Constrained Application +Protocol. `unicoap` supports different transports and several CoAP features, enabled by +a **layered** and **modular** design. Support for each CoAP transport, such as UDP, is available through +[drivers](@ref net_unicoap_drivers). + +`unicoap` aims to eventually replace @ref net_gcoap, @ref net_nanocoap, and @ref net_nanosock, +in favor of a more beginner-friendly and easily extensible design. + +## CoAP + +The [Constrained Application Protocol (CoAP)](https://datatracker.ietf.org/doc/html/rfc7252) +is a lightweight alternative to HTTP. HTTP as a general-purpose application protocol carries a +significant overhead and is thus problematic for IoT networks with limited bandwidth and +nodes with little memory. CoAP covers a range of features needed in the IoT, such as resource +discovery, message fragmentation, and end-to-end message protection. + +## Quick start + +In your application Makefile, add +```Makefile +USEMODULE += unicoap +USEMODULE += unicoap_driver_udp +``` + +`unicoap` enables support for CoAP over various transport protocols. Currently, `unicoap` supports +a @ref net_unicoap_drivers_udp and @ref net_unicoap_drivers_dtls. +You must specify at least one driver to use networking functionality. If you just want to +[use message APIs](@ref net_unicoap_message_example), you can use the framing implementation of +each driver, such as the @ref net_unicoap_drivers_rfc7252_pdu submodule for the RFC 7252 PDU format. +`unicoap` implements both a client and a server. + +To configure `unicoap`, go to the @ref net_unicoap_config. +For extending `unicoap`, refer to @ref net_unicoap_internal. + + + +@} diff --git a/sys/net/application_layer/unicoap/docs/internals.doc.md b/sys/net/application_layer/unicoap/docs/internals.doc.md new file mode 100644 index 0000000000..918dd72ad9 --- /dev/null +++ b/sys/net/application_layer/unicoap/docs/internals.doc.md @@ -0,0 +1,158 @@ +@defgroup net_unicoap_internal Behind The Scenes of unicoap +@ingroup net_unicoap +@{ + +## CoAP 101 +CoAP was originally specified in [RFC 7252](https://datatracker.ietf.org/doc/html/rfc7252) +and could only be used in combination with UDP and DTLS as transport protocols. +[RFC 8223](https://datatracker.ietf.org/doc/html/rfc8323) modified the CoAP format +for sending CoAP messages over TCP, TLS, and WebSockets (including WebSockets over TLS). +There is also an Internet Draft for [CoAP over GATT (BLE)](https://datatracker.ietf.org/doc/draft-amsuess-core-coap-over-gatt). + +Each of these standards leverage different messaging models, i.e., what timeouts to apply, how +reliable transmission is implemented, and what messages are allowed to be sent +in response to a certain message type. A custom CoAP PDU header (i.e., another PDU +format) has been specified for CoAP over reliable transports. +For instance, CoAP over UDP and over DTLS share the same PDU format; so do CoAP over TCP and TLS. +The set of protocol characteristics that vary depending on the _transport_ forms a specific version +of CoAP, which is called a _CoAP combination_ in `unicoap`. +For instance, CoAP over UDP is CoAP combination, so is CoAP over DTLS. + +## Layered Design + +The design of `unicoap` involves three distinct layers that reflect the layered approach of CoAP, +as shown in the figure below. Conceptually, newly received message traverse these layers up to +the application, and data sent by the application travels in the opposite direction. +Located beneath the application, the _exchange_ layer embodies the REST model of CoAP. +It is responsible for handling advanced CoAP features operating above the request-response exchanges, +such as [resource observation](/FIXME-upcoming-pr-net_unicoap_client_resource_observation) +and [block-wise transfer](/FIXME-upcoming-pr-net_unicoap_blockwise). +This layer is shared between CoAP combinations, i.e., the REST semantics remain the same, +regardless of the messaging model and transport beneath. +Since messaging differs between CoAP combinations, a modular design to ease the addition +of new CoAP combinations was necessary: The layer dedicated to _messaging_ covers framing and can +accommodate a custom reliability mechanism, such as the one specified in RFC 7252 +(using the four tempers `CON`, `NON`, `ACK`, `RST`). Serializing messages and parsing PDUs received +from the network are also handled by the messaging layer. +The transport layer at the bottom manages different transport protocols. +Here, `unicoap` coordinates with the operating system networking interface. + +Figure 1: Layered Design of unicoap + +### Overview of CoAP Combinations +To better illustrate what parts of the CoAP stack differ, have a look +at the following graph, where each node represents a version of a certain layer. Each leaf node stands for +a different CoAP combination ("CoAP over ...") specification. +``` + Requests/Responses + RFC 7252, RFC 7641, RFC 7959, ... + (incl. Resource Observation, Block-Wise Transfers) + / \ + / \ + / \ +Specification: RFC 7252 RFC 8323 + | | ++-+- Messaging shared between largely shared between +| | Model: UDP & DTLS TCP, TLS & WebSockets +| | | / \ +| | | / \ +| +- PDU Format: shared between shared between WebSockets +| UDP & DTLS TCP & TLS / \ +| / \ / \ / \ +| / \ / \ / \ ++-- Transport UDP DTLS TCP TLS WebSockets WebSockets + Protocol: over TLS + +Figure 2: Differences between CoAP combinations +``` + +#### CoAP over UDP and CoAP over DTLS (RFC 7252) +CoAP over UDP and DTLS works with messages of different types. A message can be confirmable (a `CON` +message), non-confirmable (`NON`), an acknowledgment message (`ACK`), or a reset message (`RST`). +Confirmable messages elicit an acknowledgement message to be sent by the peer. Hence, RFC 7252 +provides optional reliability (i.e., retransmission using an exponential back-of mechanism) +using confirmable and acknowledgement messages. + +@see [RFC 7252](https://datatracker.ietf.org/doc/html/rfc7252) + +#### CoAP over TCP, CoAP over TLS, and CoAP over WebScokets (RFC 8323) +RFC 8323 eliminates the need for reliability to be implemented on the application layer, as the underlying +transport protocol already provides reliability. While message processing looks the same for both +CoAP over TCP/TLS ([RFC 8323, Section 3](https://datatracker.ietf.org/doc/html/rfc8323#section-3)) and +CoAP over WebSockets ([RFC 8323, Section 4](https://datatracker.ietf.org/doc/html/rfc8323#section-4)), +the PDU format employed *does* vary a little between them. + +@see [RFC 8323](https://datatracker.ietf.org/doc/html/rfc8323) + +#### CoAP over GATT over Bluetooth Low Energy (BLE) (IETF Draft) +The [CoAP over GATT (BLE)](https://datatracker.ietf.org/doc/draft-amsuess-core-coap-over-gatt) +messaging layer works entirely different from previously specified Constrained Application Protocol variants. +Hence, the PDU format is also custom and optimized to take as little space as possible to reduce airtime. + +@see [`draft-amsuess-core-coap-over-gatt`](https://datatracker.ietf.org/doc/draft-amsuess-core-coap-over-gatt) + +### Drivers + +To integrate new CoAP combinations, functionality for messaging and transport layer must be added. +The `unicoap` design refers to these integrations collectively as a _driver_ that represents +a CoAP combination, such as CoAP over DTLS. Each driver is a RIOT module you can import. For instance, +to use the CoAP over UDP driver, you import the `unicoap_driver_udp` by adding it to the `USEMODULE` +Makefile variable: `USEMODULE += unicoap_driver_udp`. + +Drivers themselves can in turn consist of a shared module for messaging and a specific transport +support module. For example, the CoAP over DTLS driver encompasses a transport module for DTLS networking; +and depends on the common RFC 7252 messaging module also employed by the CoAP over UDP driver. +You can see this relationship in `Makefile.dep` in the `unicoap` source directory: The common +messaging module is a shared dependency of both the @ref net_unicoap_drivers_udp and @ref net_unicoap_drivers_dtls. +driver module. We encourage you to follow the same approach for CoAP combinations that share a common +messaging model, such as CoAP over TCP, TLS, and WebSockets when implementing these. + +On a high level, each driver interacts with the upper layers on these three occasions: + +- **Initialization and deinitialization**: + Drivers must provide an [initialization](/FIXME-upcoming-pr-unicoap_init) and [teardown](/FIXME-upcoming-pr-unicoap_deinit) + These may be used for setup work in the transport and messaging layer such as for creating + sockets or establishing connections to peripherals, alongside allocating objects required for messaging. + +- **Sending side / Outbound**: + A driver must expose a standardized API for [sending from the messaging layer](/FIXME-upcoming-pr-unicoap_messaging_send). + The exchange layer will call into this functionality, prompting the driver to perform any due + work in the messaging layer like attempting to retransmit the message. Apart from the message, + as well as the remote and local endpoint, this function accepts flags that customize transmission + behavior. The RFC 7252 message type is abstracted into a _reliability_ flag the messaging layer in + the CoAP over UDP and DTLS drivers interpret as an instruction to send a confirmable message. When + finished, the messaging layer serializes the message and forwards it to the transport + implementation. + +- **Receiving side / Inbound**: + Upon receipt of a new message, each driver will need to invoke an [exchange-layer processing function](/FIXME-upcoming-pr-unicoap_exchange_process). + +- **Ping**: Due to the variability in ping mechanisms (empty `CON` in CoAP over UDP and `7.03` message in CoAP over reliable transports), each driver can implement a ping function. unicoap bundles these APIs and provides a [single, generic ping function that multiplexes](/FIXME-upcoming-pr-unicoap_ping) between the driver implementations. + +### Communication Between Layers + +The following figure illustrates communication between layers in a block-wise transfer, +where a client request from the application may result in multiple +[`unicoap_messaging_send`](/FIXME-upcoming-pr-unicoap_messaging_send) and +[`unicoap_exchange_process`](/FIXME-upcoming-pr-unicoap_exchange_process) calls between the +exchange and messaging layer: + +Figure 3: Communication between layers + +The next schematic depicts how these APIs are implemented, based on the CoAP over UDP and +CoAP over DTLS drivers that share the RFC 7252 messaging implementation: + +Figure 4: APIs for communication between layers + +Both the CoAP over UDP and CoAP over DTLS driver support sending vectored data, hence the `sendv` +suffixes in the function names depicted in the figure above. + +## Adding a New Driver + +In the `unicoap` codebase you will encounter several marks (`MARK: ...`) +that help with extending the suite. + +- **MARK: unicoap_driver_extension_point**: Every region of code that would need to be extended to support a new transport protocol or driver is + annotated with this mark. + +@} diff --git a/sys/net/application_layer/unicoap/docs/message-example.doc.md b/sys/net/application_layer/unicoap/docs/message-example.doc.md new file mode 100644 index 0000000000..54673868b9 --- /dev/null +++ b/sys/net/application_layer/unicoap/docs/message-example.doc.md @@ -0,0 +1,292 @@ +@defgroup net_unicoap_message_example Using Message APIs +@ingroup net_unicoap_message +@brief A demo of `unicoap` message APIs +@{ + +Sample code. +This example demonstrates how you can use `unicoap` message and options APIs and how to parse PDUs. +You can find a demo application in the `examples/networking/coap/unicoap_message` folder. + +## Bytes to Message (Deserializing) + +### Parsing a PDU + +To start, let us assume `pdu` is a buffer containing the CoAP PDU. +```c +const uint8_t pdu[] = { /* ... */ }; +``` + +Next, allocate a result structure. + +```c +unicoap_parser_result_t parsed = { 0 }; +``` + +Then, call one of the message parsers. CoAP supports different transports which is why the CoAP PDU +header varies. In this case, let us assume we received the message over UDP or DTLS. In these cases, +we use the RFC 7252 PDU format. Using the result structure frees you of needing to allocate options +and a message struct and to wire up options with message struct. + +```c +if ((res = unicoap_pdu_parse_rfc7252_result(pdu, sizeof(pdu), &parsed)) < 0) { + puts("Error: parsing failed"); + return; +} + +unicoap_message_t* message = &parsed.message; +``` + +Because the header varies, transport-dependent details like the RFC 7252 message type and ID +are accessible via the +@ref unicoap_message_properties_t::rfc7252 member. + +```c +printf("CoAP message has token=<%i bytes>\n", + parsed.properties.token_length); + +printf("CoAP over UDP/DTLS has id=%i type=%s\n", + parsed.properties.rfc7252.id, + unicoap_string_from_rfc7252_type(parsed.properties.rfc7252.type)); +``` + +### Inspecting a Message + +You use the +@ref unicoap_message_is_request, +@ref unicoap_message_is_response, and +@ref unicoap_message_is_signal +methods to check whether a given message is a request, response, or signaling message. + +The corresponding typed view of the code is accessible through +@ref unicoap_message_t.method, +@ref unicoap_message_t.status, and +@ref unicoap_message_t.signal. + +You can also obtain a human-readable constant null-terminated C string. There are also versions +available for status codes and signal numbers. To get a string description of the CoAP code +without checking the message class first, use @ref unicoap_string_from_code. + +```c +const char* method_name = unicoap_string_from_method(message->method); +``` + +The payload and payload size in bytes can be retrieved the +@ref unicoap_message_t.payload and +@ref unicoap_message_t.payload_size members. + +### Reading Options + +First, let us dump all options to the standard output. + +```c +unicoap_options_dump_all(message->options); +``` + +To read options like `Content-Format` which can occur no more than once, you use +@ref unicoap_options_t::unicoap_options_get_content_format. +Read accessors for non-repeatable options are prefixed with `unicoap_options_get`. + +```c +unicoap_content_format_t format = 0; + +if (unicoap_options_get_content_format(message->options, &format) < 0) { + puts("Error: could not read Content-Format!"); +} + +assert(format == UNICOAP_FORMAT_JSON); +``` + +Options like `Uri-Query` can occur more than once. For these types of options, `unicoap` defines +several convenience accessors. Let us retrieve the first `Uri-Query` option. + +```c +const char* query = NULL; + +ssize_t res = unicoap_options_get_first_uri_query(message->options, &query); +if (res < 0) { + if (res == -ENOENT) { + puts("Message has no Uri-Query option"); + } + printf("Error: could read first Uri-Query option"); +} +``` + +The `first` getter provides a view into the PDU buffer. The returned string +is thus not null-terminated. + +```c +printf("First URI query: '%.*s'\n", (int)res, query); +``` + +In the case of URI queries, you can also retrieve queries by name (if they obey the `name=value` +format). + +```c +res = unicoap_options_get_first_uri_query_by_name(message->options, "color", &query); +if (res < 0) { + /* The getter also fails in cases where no option was found */ + if (res == -ENOENT) { + puts("Message has no 'color' query"); + } + printf("Error: could read first 'color' query"); +} +``` + +For a number of repeatable options, such as `Uri-Path`, `Location-Path`, `Uri-Query`, +and `Location-Query`, `unicoap` offers accessors that generate the original, contiguous representation. +This means that multiple `Uri-Path` options are stitched back together, forming the `/original/path`. +These accessores do copy. Now, let us create a query string (`?a=1&b=2&c=3`). + +```c +char query_string[50] = { 0 }; + +res = unicoap_options_copy_uri_queries(message->options, query_string, sizeof(query_string)); +if (res < 0) { + puts("Error: could not generate URI query string"); +} +``` + +Alternatively, you can iterate over all query options, avoiding the copy operation and allocation. +To do this, you will need to allocate an +@ref unicoap_options_iterator_t and initialize it using +@ref unicoap_options_iterator_t::unicoap_options_iterator_init. +This is the main tool to iterate over options. +`unicoap` exposes multiple methods for getting the next instance of a repeatable option. + +```c +unicoap_options_iterator_t iterator; +unicoap_options_iterator_init(&iterator, message->options); + +while ((res = unicoap_options_get_next_uri_query(&iterator, &query)) >= 0) { + printf("- URI query: '%.*s'\n", (int)res, query); +} +``` + +The option iterator can also be used to iterate over all options, regardless of their type. + +```c +unicoap_options_iterator_init(&iterator, message->options); +unicoap_option_number_t number; +const uint8_t* value = NULL; + +while ((res = unicoap_options_get_next(&iterator, &number, &value)) >= 0) { + const char* name = unicoap_string_from_option_number(number); + printf("- option %s nr=%i contains %" PRIuSIZE " bytes\n", name, number, res); +} +``` + +## Message to Bytes (Serializing) + +### Creating a Message Container + +Since we want to add options to the CoAP message, we need to allocate an options buffer first. +To avoid the boilerplate necessary for allocating a helper structure and buffer and the initialization +work, you just need to call +@ref UNICOAP_OPTIONS_ALLOC and provide the desired buffer capacity. + +```c +UNICOAP_OPTIONS_ALLOC(options, 100); +``` + +Now, let us initialize a message. You can either use the designated initializer or initializer +function. + +```c +unicoap_request_init_string_with_options(&message, UNICOAP_METHOD_POST, "Hello, World!", &options); +``` + +### Customizing Options + +To set non-repeatable options like `Content-Format`, use `unicoap_options_set` accessors. + +```c +int res = unicoap_options_set_content_format(&options, UNICOAP_FORMAT_TEXT); +if (res < 0) { + puts("Error: could not set Content-Format"); +} +``` + +For repeatable options, `unicoap` provides two versions. You can either add multiple instances +of an option like `Uri-Path` by providing the original, contiguous representation (e.g., the path). + +```c +int res = unicoap_options_add_uri_path_string(&options, "/thermostat/temperature"); +if (res < 0) { + if (res == -ENOBUFS) { + puts("Error: options buffer too small"); + } + puts("Error: could not add URI path"); +} +``` + +Or, you can add _components_ individually as follows. + +```c +res = unicoap_options_add_uri_path_component_string(&options, "thermostat"); +if (res < 0) { + puts("Error: could not add path component"); +} +res = unicoap_options_add_uri_path_component_string(&options, "temperature"); +if (res < 0) { + puts("Error: could not add path component"); +} +``` + +The same applies to `Uri-Query`. + +```c +res = unicoap_options_add_uri_queries_string(&options, "unit=C&friendly=yes"); +if (res < 0) { + puts("Error: could not add URI query"); +} +``` + +`unicoap` offers versions for both null-terminated C strings and strings without a null-terminator +that require a length indication instead. Example: +@ref unicoap_options_t::unicoap_options_add_uri_queries and +@ref unicoap_options_t::unicoap_options_add_uri_queries_string, or +@ref unicoap_options_t::unicoap_options_add_uri_query and +@ref unicoap_options_t::unicoap_options_add_uri_query_string. + +### Serializing a Message + +First, allocate a buffer with a capacity of your choice. + +```c +uint8_t pdu[200]; +``` + +The header format varies depending on the transport. Let's use CoAP over UDP or CoAP over DTLS, +i.e., the RFC 7252 format. + +@remark In this very simple scenario, we don't use a token. Very constrained nodes +are allowed to handle one request at a time and thus don't need a token to differentiate +responses to outstanding requests. + +```c +unicoap_message_properties_t properties = { + .token = NULL, + .token_length = 0, + .rfc7252 = { + .id = 0xABCD, + .type = UNICOAP_TYPE_NON + } +}; +``` + +Finally, call the serializer appropriate for the transport. + +```c +ssize_t res = unicoap_pdu_build_rfc7252(pdu, sizeof(pdu), message, &properties); +if (res < 0) { + if (res == -ENOBUFS) { + puts("Error: PDU buffer too small"); + } + puts("Error: could not serialize message"); + return; +} + +printf("The final PDU has a size of %" PRIuSIZE " bytes.\n", res); +``` + +@} diff --git a/sys/net/application_layer/unicoap/docs/message.doc.md b/sys/net/application_layer/unicoap/docs/message.doc.md new file mode 100644 index 0000000000..75483859d1 --- /dev/null +++ b/sys/net/application_layer/unicoap/docs/message.doc.md @@ -0,0 +1,24 @@ +@defgroup net_unicoap_message Message APIs +@ingroup net_unicoap +@brief Create and serialize CoAP messages +@{ + +@ref unicoap_message_t is the central container type for CoAP messages. To see how to access +CoAP options, see @ref net_unicoap_options. You may also look at the [guide to using CoAP +messages](https://guides.riot-os.org/FIXME) + +## Example + +```c +unicoap_message_t message; + +const char payload[] = "Hello, World!"; +unicoap_request_init_string(&message, UNICOAP_METHOD_POST, payload, &options); +``` + +You can access the CoAP code through different views, including as ast +@ref unicoap_message_t.method, +@ref unicoap_message_t.status, or +@ref unicoap_message_t.signal number. + +@} diff --git a/sys/net/application_layer/unicoap/docs/pdu.doc.md b/sys/net/application_layer/unicoap/docs/pdu.doc.md new file mode 100644 index 0000000000..73c0332ae8 --- /dev/null +++ b/sys/net/application_layer/unicoap/docs/pdu.doc.md @@ -0,0 +1,50 @@ +@defgroup net_unicoap_pdu Parsing and Serialization +@ingroup net_unicoap_message +@brief Tools for parsing PDUs and serializing messages and options + +## Parsing +To parse a message on your own, use one of the parsers in @ref net_unicoap_message and +@ref unicoap_parser_result_t. The parsed message structure helps you allocate everything needed in +one go. + +```c +// Parse an RFC 7252 PDU +uint8_t pdu[] = { + 0x40, 0x02, 0xfe, 0xb1, 0xb9, 0x61, 0x63, 0x74, 0x75, 0x61, 0x74, 0x6f, 0x72, 0x73, 0x04, 0x6c, 0x65, 0x64, 0x73, 0x11, 0x32, 0x37, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x3d, 0x67, 0x21, 0x32, 0xff, 0x6d, 0x6f, 0x64, 0x65, 0x3d, 0x6f, 0x6e +}; + +unicoap_parser_result_t parsed = { 0 }; // Zero-initialize everything + +// Parse message +ssize_t res = unicoap_pdu_parse_rfc7252_result(pdu, sizeof(pdu), &parsed); + +// Handle errors +if (res < 0) { + // eat error +} + +// parsed.message contains the parsed message +``` + +## Serializing +To serialize a message on your own, decide whether you need vectored data or contiguous data. +To get vectored data, you use `unicoap_pdu_buildv_*` functions, depending on the CoAP transport you intend to use. +Vectored data is represented using an @ref iolist_t. +If you want to build a contiguous storage body, refer to the `unicoap_pdu_build_*` methods, also depending +on the transport. + +```c +// Build an RFC 7252 PDU +uint8_t pdu[MY_CAPACITY] = { 0 }; +ssize_t size = unicoap_pdu_build_rfc7252(pdu, sizeof(pdu), message, properties); + +// Handle errors +if (res < 0) { + // eat error +} +``` + +## Implementation +Parsing and serialization are each done in two steps: +1. Message header up until options is parsed/serialized by driver +2. Options are parsed/serialized by common `unicoap` implementation diff --git a/sys/net/application_layer/unicoap/docs/unicoap-layers-comms-apis.svg b/sys/net/application_layer/unicoap/docs/unicoap-layers-comms-apis.svg new file mode 100644 index 0000000000..202ab84046 --- /dev/null +++ b/sys/net/application_layer/unicoap/docs/unicoap-layers-comms-apis.svg @@ -0,0 +1,2023 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sys/net/application_layer/unicoap/docs/unicoap-layers-comms.svg b/sys/net/application_layer/unicoap/docs/unicoap-layers-comms.svg new file mode 100644 index 0000000000..580d132192 --- /dev/null +++ b/sys/net/application_layer/unicoap/docs/unicoap-layers-comms.svg @@ -0,0 +1,903 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sys/net/application_layer/unicoap/docs/unicoap-layers.svg b/sys/net/application_layer/unicoap/docs/unicoap-layers.svg new file mode 100644 index 0000000000..b08e33cc70 --- /dev/null +++ b/sys/net/application_layer/unicoap/docs/unicoap-layers.svg @@ -0,0 +1,2395 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sys/net/application_layer/unicoap/drivers/doc.md b/sys/net/application_layer/unicoap/drivers/doc.md new file mode 100644 index 0000000000..6c193b3e19 --- /dev/null +++ b/sys/net/application_layer/unicoap/drivers/doc.md @@ -0,0 +1,11 @@ +@defgroup net_unicoap_drivers Drivers +@ingroup net_unicoap +@brief Collection of transport drivers +@{ + +Drivers enable you to use different transports while still relying on the same high-level CoAP +API. Each driver implements framing and a messaging model optimized for the given transport. +Which transport you choose depends on the deployment. For most constrained deployments, +we recommend the @ref net_unicoap_drivers_udp or @ref net_unicoap_drivers_dtls. + +@} diff --git a/sys/net/application_layer/unicoap/drivers/rfc7252/common/pdu/doc.md b/sys/net/application_layer/unicoap/drivers/rfc7252/common/pdu/doc.md new file mode 100644 index 0000000000..c41c7459a1 --- /dev/null +++ b/sys/net/application_layer/unicoap/drivers/rfc7252/common/pdu/doc.md @@ -0,0 +1,30 @@ +@defgroup net_unicoap_drivers_rfc7252_pdu RFC 7252 Framing +@ingroup net_unicoap_drivers +@brief Parse and serialize RFC 7252 PDUs +@{ + +Module. Specify `USEMODULE += unicoap_driver_rfc7252_pdu` in your application's Makefile. + +This module allows you to use the RFC 7252 parser without having to import the +@ref net_unicoap_drivers_udp or @ref net_unicoap_drivers_dtls, i.e., without a network backend. +This is particularly handy if you want to experiment with `unicoap` or write tests that don't +need the ability to do network I/O. + +## PDU Format + +``` +0 1 2 3 +0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +|Ver| T | TKL | Code | Message ID | ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +| Token (if any, TKL bytes) ... ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +| Options (if any) ... ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +|1 1 1 1 1 1 1 1| Payload (if any) ... ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +``` + +@see [RFC 7252, Message Format](https://datatracker.ietf.org/doc/html/rfc7252#section-3) +@} diff --git a/sys/net/application_layer/unicoap/drivers/rfc7252/dtls/doc.md b/sys/net/application_layer/unicoap/drivers/rfc7252/dtls/doc.md new file mode 100644 index 0000000000..891f540a54 --- /dev/null +++ b/sys/net/application_layer/unicoap/drivers/rfc7252/dtls/doc.md @@ -0,0 +1,48 @@ +@defgroup net_unicoap_drivers_dtls CoAP over DTLS Driver +@ingroup net_unicoap_drivers +@brief Use CoAP over DTLS, with optional reliability +@{ + +Module. Specify `USEMODULE += unicoap_driver_dtls` in your application's Makefile. + +Include these headers required for managing DTLS credentials. +```c +#include "net/sock/dtls/creds.h" +#include "net/credman.h" +#include "net/dsm.h" +``` + +Then, in your application, call @ref sock_dtls_add_credential to add a DTLS credential. + + + +@see @ref unicoap_rfc7252_message_type_t + +This is the dependency graph of this driver: + +``` +unicoap_driver_dtls +├── unicoap_driver_rfc7252_common +│ ├── unicoap_driver_rfc7252_common_messaging +│ └── unicoap_driver_rfc7252_common_pdu +├── unicoap_sock_support +│ ├── sock_async +│ ├── sock_async_event +│ ├── sock_aux_local +│ └── sock_util +├── ... (operating system networking modules) +. +``` + +@} diff --git a/sys/net/application_layer/unicoap/drivers/rfc7252/udp/doc.md b/sys/net/application_layer/unicoap/drivers/rfc7252/udp/doc.md new file mode 100644 index 0000000000..f7b92430ac --- /dev/null +++ b/sys/net/application_layer/unicoap/drivers/rfc7252/udp/doc.md @@ -0,0 +1,32 @@ +@defgroup net_unicoap_drivers_udp CoAP over UDP Driver +@ingroup net_unicoap_drivers +@brief Use CoAP over the UDP transport protocol, with optional reliability +@{ + +Module. Specify `USEMODULE += unicoap_driver_udp` in your application's Makefile. + + +@see @ref unicoap_rfc7252_message_type_t + +This is the dependency graph of this driver: + +``` +unicoap_driver_udp +├── unicoap_driver_rfc7252_common +│ ├── unicoap_driver_rfc7252_common_messaging +│ └── unicoap_driver_rfc7252_common_pdu +├── unicoap_sock_support +│ ├── sock_async +│ ├── sock_async_event +│ ├── sock_aux_local +│ └── sock_util +└── ... (operating system networking module) +``` + +@}