Skip to content

drivers/slipmux: Add to RIOT #21418

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 6 commits into
base: master
Choose a base branch
from

Conversation

Teufelchen1
Copy link
Contributor

@Teufelchen1 Teufelchen1 commented Apr 17, 2025

Contribution description

Hey 🪼,

this adds an (incomplete) implementation of Slipmux to RIOT. It extends the current slip driver and is backwards compatible.

The second commit adds an usage example, where the shell commands are exposed to coap and through it to slipmux. That commit will be dropped prio merging.

It is incomplete as frame abort is missing.

Testing procedure

Grab your favorite slipmux tool and connect RIOTs stdio to it. Make sure to build RIOT with USEMODULE += slipdev_stdio and optionally set CFLAGS += "-DCONFIG_NANOCOAP_BLOCK_SIZE_EXP_MAX=10" to be able to handle coap packets that are longer than 64 bytes. See the changes I made to the default example.

Feedback wanted: coap server

My current approach spawns a new thread with a nanocoap server to handle the incoming and outgoing configuration frames. This might cause issues when another coap server is in use (one that is connected to the network instead of just the uart). For example, the NANOCOAP_RESOURCE(..)s will be shared between them.

I also experimented with sending the coap messages with a fake ip6+udp header into gnrc. One can then only run one single coap server (and it is no longer bound to nanocoap) who listens for such packets. The outgoing way is a bit more annoying, here a new dummy interface must be created, to which gnrc can direct those fake ip6+udp headers. Very similar to how it is already done with the current slip implementation.

What alternative approaches do you see? Any idea is appreciated.

@Teufelchen1 Teufelchen1 requested a review from miri64 as a code owner April 17, 2025 09:45
@github-actions github-actions bot added Area: drivers Area: Device drivers Area: sys Area: System Area: examples Area: Example Applications labels Apr 17, 2025
@miri64 miri64 requested a review from benpicco April 17, 2025 10:23
@benpicco
Copy link
Contributor

I don't quite understand the purpose if this.
When you already have a SLIP connection, you might as well do CoAP over UDP.

Sure, with this approach you can omit the IP and UDP header, but is that really worth the hassle?

@Teufelchen1
Copy link
Contributor Author

From the byte-wise overhead, it is not that much of a difference yes. I don't think it is that much of a hassle tho. Beside, as soon as you use IP+UDP you have endpoints in a network and those need to be configured (I need to know the IP I want to talk to). Doing slipmux configuration frames you have a guaranteed point to point channel with no configuration nor hassle ;)

@chrysn
Copy link
Member

chrysn commented Apr 17, 2025

I can't comment on the code right now, but maybe for the open aspects:

  • "Why?" Teufelchen already mentioned the configuration aspect; without precise knowledge of the concrete application (and a point of using SLIP is that this knowledge is not required) the host may not even know that it reaches the board this way. In particular,

    • this connection may be more trusted than a network connection: While I generally advocate no-TOFU / all-links-are-untrusted / cryptographically-secure-or-bust policy, TOFU policies do have their places, and TOFU over a link that is known not to be networked is preferable over a link where one would need to apply heuristics to know whether a peer is local. (Like, sure, might do link-local-only, but maybe there's NDP-proxying involved?).
    • This might be a good fit also for devices that don't do network at all, or not on that interface. On those, actual SLIP packets would be blackhole'd, but CoAP provides an interface that is easier to automate than shell interactions, and moreover easily ported to devices where no serial line but network is available.
    • Where we do have Ethernet-over-USB, I think that a dedicated CoAP-over-USB protocol would be preferred. However, I'm not aware of any such attempt, and even then, there are relatively new devices around still that still run through the moral equivalent of an FTDI chip.
  • "Which CoAP server to run?" I think we should run the same single CoAP server on all transports as a matter of simplicity; where a UART connection is more trusted than a network peer, which transport it is should be discoverable by inspecting the socket-ish thing it comes in over. I don't have an opinion yet on which implementation strategy I'd advocate for.

@Teufelchen1 Teufelchen1 changed the title DRAFT: Add slipmux to RIOT Add slipmux to RIOT May 16, 2025
@crasbe crasbe added Type: new feature The issue requests / The PR implemements a new feature for RIOT Discussion: RFC The issue/PR is used as a discussion starting point about the item of the issue/PR Community: help wanted The contributors require help from other members of the community labels May 16, 2025
@miri64 miri64 changed the title Add slipmux to RIOT slipmux: Add to RIOT May 16, 2025
Copy link
Member

@miri64 miri64 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

First round of review.

#if IS_USED(MODULE_SLIPDEV_STDIO)
chunk_ringbuf_t rb_config; /**< Ringbuffer to store received CONFIG frames.*/
uint8_t rxmem_config[CONFIG_SLIPDEV_BUFSIZE]; /**< memory used by RX buffer */
kernel_pid_t coap_server_pid;
Copy link
Member

@miri64 miri64 May 16, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
kernel_pid_t coap_server_pid;
kernel_pid_t coap_server_pid; /**< The PID of the CoAP server */

Wrt to future extensions, maybe that can be more generalized so that, e.g., also a gcoap or unicoap queue could be put here, if they exist to not have to provide an extra server then.

Again, mainly a comment for future improvements, this does not have to be addressed in this PR.

(edit: but would also address @chrysn's comment)

# Modules to include:
USEMODULE += slipdev_stdio
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would prefer this to be its own example.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The second commit adds an usage example, where the shell commands are exposed to coap and through it to slipmux. That commit will be dropped prio merging.

Thanks for the review!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I resolved your other comments without fixing them as they would be dropped too.

@crasbe crasbe added the CI: ready for build If set, CI server will compile all applications for all available boards for the labeled PR label May 16, 2025
@riot-ci
Copy link

riot-ci commented May 16, 2025

Murdock results

FAILED

d8dd55e fixup: Minor guard/parsing adjustment

Success Failures Total Runtime
2027 0 9598 03m:32s

Artifacts

@crasbe crasbe changed the title slipmux: Add to RIOT drivers/slipmux: Add to RIOT May 16, 2025
void slipdev_setup(slipdev_t *dev, const slipdev_params_t *params, uint8_t index)
{
#if IS_USED(MODULE_SLIPDEV_STDIO)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please use a separate pseudo-module for this, normal slipdev stdio multiplex should not require a CoAP server.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You are repeating yourself ;)

I am not sure yet if "just a separate pseudo-module" is the correct call. What do you think about making the driver "slipmux" with no functionality (not even slip). One can then add the pseudomodules slipmux_ip, slipmux_configuration and slipmux_stdio which add their respective functions. This way, one could use configuration frames (-> coap) without needing IP/gnrc as a dependency.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you desire to do so go ahead.
I just want to avoid bloating the slipdev driver for simple device to device links that might have a multiplexed debug interface for convenience.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That will be much more work than I thought. I'll move that task to a followup PR. For this one, I adopted your wish and guarded it with its own pseudomodule.
In addition, I changed the way the parsing is guarded with the #if IS_USED(..). Before: The whole case of stdio was removed if the module was not selected. Now: Only the data processing is removed, the cases for parsing remain. (Same for configuration frames). Reason is simple: If you remove the parsing + states, any byte received will be treated as a IP packet and then dropped by gnrc as "undefined packet type". This no-longer the case, instead, receiving a diagnostic/configuration frame without their pseudomodules enabled, they will be silently ignored.

@github-actions github-actions bot added the Area: build system Area: Build system label Jun 11, 2025
@github-actions github-actions bot added the Area: tests Area: tests and testing framework label Jun 17, 2025
@Teufelchen1
Copy link
Contributor Author

@benpicco I think this is ready for another review. If that is positive, I will drop the shell/example related commit and squash the others.

@Teufelchen1
Copy link
Contributor Author

@benpicco ping :)

review(miri) fix up

review(ben): Guard slipmux config handling with own pseudo module

adjustment for review, to be dropped

fixup whitespace issues
@@ -120,13 +129,19 @@ typedef struct {
typedef struct {
netdev_t netdev; /**< parent class */
slipdev_params_t config; /**< configuration parameters */
chunk_ringbuf_t rb; /**< Ringbuffer to store received frames. */
chunk_ringbuf_t rb; /**< Ringbuffer to store received NET frames. */
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is “NET frames” wording from the draft?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no it is not, it would be "Packet Transfer". I thought I would assume a bit that the reader is more likely to know RIOT than the Draft, so I picked a name that represents "Packet Transfer" for RIOT networking humans. Do you think that was a poor choice? I have no hard feelings on this. ("Packet frames" is rather confusing as one could say "coap packet")

/* Written to from interrupts (with irq_disable */
/* to prevent any simultaneous writes), */
/* consumed exclusively in the network stack's */
/* loop at _isr. */

uint8_t rxmem[CONFIG_SLIPDEV_BUFSIZE]; /**< memory used by RX buffer */

#if IS_USED(MODULE_SLIPDEV_CONFIG)
chunk_ringbuf_t rb_config; /**< Ringbuffer to store received CONFIG frames.*/
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here for “CONFIG frames”.

@mguetschow
Copy link
Contributor

Some high-level comments from my side:

  • incomplete implementation

this adds an (incomplete) implementation of Slipmux to RIOT. It extends the current slip driver and is backwards compatible. (...) It is incomplete as frame abort is missing.

Isn't it also missing diagnostic transfer? Just had a quick glance at the code, but could only find references to configuration frames.

  • documentation: before merging this should definitely get documentation, probably on the defined pseudomodule slipdev_config. Not sure if this may even warrant its own doc.md somewhere? It should definitely mention slipmux and clearly list what is currently supported. Also some notes on the implementation (currently spawning an additional thread, sharing NANOCOAP_RESOURCE with any other nanocoap server) should be in the documentation.

  • coap server with different backends: I would hope unicoap could help with that. I'm pretty sure it supports defining resources only for a subset of driver backends (e.g. just slipmux and not udp), which means that a single unicoap server could be used for several backends. Maybe @carl-tud has some more comments on this?

  • nanocoap/nanocoap_sock: could you maybe explain in a bit more detail how this actually works right now? I see the "server thread" just receives chunks from the ringbuffer, tries to parse and answer them (using nanocoap). Every chunk is supposed to be a CoAP packet as received within slipdev, right? Where do the NANOCOAP_RESOURCEs (which are part of nanocoap_sock afaict) actually come into play?

crb_consume_chunk(&dev->rb_config, buf, len);

/* Is crc correct via Residue test */
if (crc16_ccitt_fcs_update(SPECIAL_INIT_FCS, buf, len) != 0xF0B8) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

where does this constant come from? mind using a define or at least add a comment?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's a residue test, the magic value is defined here, in the crc header. Please don't make me add all crcs residue values as defines 😨

@Teufelchen1
Copy link
Contributor Author

Teufelchen1 commented Jun 30, 2025

Isn't it also missing diagnostic transfer? Just had a quick glance at the code, but could only find references to configuration frames.

That's because those were already implemented in RIOT and are just called stdio via slip. Blame @miri64 for that :p If you enable this, every printf() will be send slipmux encoded.

[..needs doc...] Not sure if this may even warrant its own doc.md somewhere?

Eventually, yes. There is still work to be done on the coap-handling/server side. If I can get away with minimal documentation this time, I would appreciate. I fear it will be duplicated work if I re-implement it later (for example with unicoap). Plus, as mentioned in a comment with benpicco, the handling of the pseudomodule is not ideal in the moment. For example, it is not possible to enable configuration transfer without packet transfer. And even if you could, nanocoap depends on udp, which means you would still pull in a lot of wasted code & bytes. Both issues are scheduled for follow-up work.

I see the "server thread" just receives chunks from the ringbuffer, tries to parse and answer them (using nanocoap). Every chunk is supposed to be a CoAP packet as received within slipdev, right?

That is correct.

Where do the NANOCOAP_RESOURCEs (which are part of nanocoap_sock afaict) actually come into play?

That's nanocoap specific, I do not interact with them myself (beside the shell stuff but thats just an example of what one could do and will be dropped before merging). Afaik it is just a XFA defining names and callbacks. The nanocoap server just magically knows that XFA and looks up the endpoints on the fly.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Area: build system Area: Build system Area: drivers Area: Device drivers Area: examples Area: Example Applications Area: sys Area: System Area: tests Area: tests and testing framework CI: ready for build If set, CI server will compile all applications for all available boards for the labeled PR Community: help wanted The contributors require help from other members of the community Discussion: RFC The issue/PR is used as a discussion starting point about the item of the issue/PR Type: new feature The issue requests / The PR implemements a new feature for RIOT
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants