This is an automated email from the ASF dual-hosted git repository.
xiaoxiang pushed a commit to branch releases/12.13
in repository https://gitbox.apache.org/repos/asf/nuttx.git
The following commit(s) were added to refs/heads/releases/12.13 by this push:
new ab0ad3cee51 drivers/net/telnet: Ignore unsupported subnegotiation data.
ab0ad3cee51 is described below
commit ab0ad3cee517bbc8c92159cd56b96dbe3c13f5a6
Author: Shunchao Hu <[email protected]>
AuthorDate: Tue Mar 24 15:52:11 2026 +0800
drivers/net/telnet: Ignore unsupported subnegotiation data.
Ignore unsupported telnet subnegotiation payload until `IAC SE` so
option bytes do not leak into the first NSH command.
Keep existing NAWS handling intact and also treat `IAC IAC` inside
subnegotiation payload as an escaped `0xFF` data byte rather than a
subnegotiation terminator.
This makes subnegotiation parsing RFC-compliant for both unsupported
options and NAWS payload processing.
Signed-off-by: Shunchao Hu <[email protected]>
---
drivers/net/telnet.c | 53 +++++++++++++++++++++++++++++++++++++++++++---------
1 file changed, 44 insertions(+), 9 deletions(-)
diff --git a/drivers/net/telnet.c b/drivers/net/telnet.c
index 08c23e0dbbf..6cd92ebf8b2 100644
--- a/drivers/net/telnet.c
+++ b/drivers/net/telnet.c
@@ -107,8 +107,8 @@ enum telnet_state_e
STATE_DO,
STATE_DONT,
STATE_SB,
- STATE_SB_NAWS,
- STATE_SE
+ STATE_SB_DATA,
+ STATE_SB_NAWS
};
/* This structure describes the internal state of the driver */
@@ -118,6 +118,7 @@ struct telnet_dev_s
uint8_t td_state; /* (See telnet_state_e) */
uint8_t td_crefs; /* The number of open references to the
session */
uint8_t td_minor; /* Minor device number */
+ bool td_sb_iac; /* Saw IAC within sub-negotiation payload */
uint16_t td_offset; /* Offset to the valid, pending bytes in the
rxbuffer */
uint16_t td_pending; /* Number of valid, pending bytes in the
rxbuffer */
#ifdef CONFIG_TELNET_SUPPORT_NAWS
@@ -372,16 +373,17 @@ static ssize_t telnet_receive(FAR struct telnet_dev_s
*priv,
priv->td_state = STATE_DONT;
break;
-#ifdef CONFIG_TELNET_SUPPORT_NAWS
case TELNET_SB:
priv->td_state = STATE_SB;
+ priv->td_sb_iac = false;
+#ifdef CONFIG_TELNET_SUPPORT_NAWS
priv->td_sb_count = 0;
+#endif
break;
case TELNET_SE:
priv->td_state = STATE_NORMAL;
break;
-#endif
default:
priv->td_state = STATE_NORMAL;
@@ -458,25 +460,58 @@ static ssize_t telnet_receive(FAR struct telnet_dev_s
*priv,
}
break;
-#ifdef CONFIG_TELNET_SUPPORT_NAWS
- /* Handle Telnet Sub negotiation request */
+ /* Handle Telnet sub-negotiation requests. */
case STATE_SB:
switch (ch)
{
+#ifdef CONFIG_TELNET_SUPPORT_NAWS
case TELNET_NAWS:
priv->td_state = STATE_SB_NAWS;
break;
+#endif
default:
- priv->td_state = STATE_NORMAL;
+ priv->td_state = STATE_SB_DATA;
break;
}
break;
+ /* Ignore unsupported sub-negotiation payload until IAC SE. */
+
+ case STATE_SB_DATA:
+ if (priv->td_sb_iac)
+ {
+ priv->td_sb_iac = false;
+ if (ch == TELNET_SE)
+ {
+ priv->td_state = STATE_NORMAL;
+ }
+ }
+ else if (ch == TELNET_IAC)
+ {
+ priv->td_sb_iac = true;
+ }
+ break;
+
+#ifdef CONFIG_TELNET_SUPPORT_NAWS
/* Handle NAWS sub-option negotiation */
case STATE_SB_NAWS:
+ if (priv->td_sb_iac)
+ {
+ priv->td_sb_iac = false;
+ if (ch == TELNET_SE)
+ {
+ priv->td_state = STATE_NORMAL;
+ break;
+ }
+ }
+ else if (ch == TELNET_IAC)
+ {
+ priv->td_sb_iac = true;
+ break;
+ }
/* Update cols / rows based on received byte count */
@@ -500,11 +535,11 @@ static ssize_t telnet_receive(FAR struct telnet_dev_s
*priv,
break;
}
- /* Increment SB count and switch to NORMAL when complete */
+ /* Increment SB count and keep discarding until IAC SE. */
if (++priv->td_sb_count == 4)
{
- priv->td_state = STATE_NORMAL;
+ priv->td_state = STATE_SB_DATA;
}
break;