tty-n_gsm-fix-missing-mux-reset-on-config-change-at-responder.patch
tty-n_gsm-fix-restart-handling-via-cld-command.patch
tty-n_gsm-fix-decoupled-mux-resource.patch
+tty-n_gsm-fix-mux-cleanup-after-unregister-tty-device.patch
+tty-n_gsm-fix-wrong-signal-octet-encoding-in-convergence-layer-type-2.patch
+tty-n_gsm-fix-frame-reception-handling.patch
+tty-n_gsm-fix-malformed-counter-for-out-of-frame-data.patch
--- /dev/null
+From 7a0e4b1733b635026a87c023f6d703faf0095e39 Mon Sep 17 00:00:00 2001
+From: Daniel Starke <daniel.starke@siemens.com>
+Date: Thu, 14 Apr 2022 02:42:11 -0700
+Subject: tty: n_gsm: fix frame reception handling
+
+From: Daniel Starke <daniel.starke@siemens.com>
+
+commit 7a0e4b1733b635026a87c023f6d703faf0095e39 upstream.
+
+The frame checksum (FCS) is currently handled in gsm_queue() after
+reception of a frame. However, this breaks layering. A workaround with
+'received_fcs' was implemented so far.
+Furthermore, frames are handled as such even if no end flag was received.
+Move FCS calculation from gsm_queue() to gsm0_receive() and gsm1_receive().
+Also delay gsm_queue() call there until a full frame was received to fix
+both points.
+
+Fixes: e1eaea46bb40 ("tty: n_gsm line discipline")
+Cc: stable@vger.kernel.org
+Signed-off-by: Daniel Starke <daniel.starke@siemens.com>
+Link: https://lore.kernel.org/r/20220414094225.4527-6-daniel.starke@siemens.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/tty/n_gsm.c | 53 +++++++++++++++++++++++++++++-----------------------
+ 1 file changed, 30 insertions(+), 23 deletions(-)
+
+--- a/drivers/tty/n_gsm.c
++++ b/drivers/tty/n_gsm.c
+@@ -219,7 +219,6 @@ struct gsm_mux {
+ int encoding;
+ u8 control;
+ u8 fcs;
+- u8 received_fcs;
+ u8 *txframe; /* TX framing buffer */
+
+ /* Method for the receiver side */
+@@ -1794,18 +1793,7 @@ static void gsm_queue(struct gsm_mux *gs
+ u8 cr;
+ int address;
+ int i, j, k, address_tmp;
+- /* We have to sneak a look at the packet body to do the FCS.
+- A somewhat layering violation in the spec */
+
+- if ((gsm->control & ~PF) == UI)
+- gsm->fcs = gsm_fcs_add_block(gsm->fcs, gsm->buf, gsm->len);
+- if (gsm->encoding == 0) {
+- /* WARNING: gsm->received_fcs is used for
+- gsm->encoding = 0 only.
+- In this case it contain the last piece of data
+- required to generate final CRC */
+- gsm->fcs = gsm_fcs_add(gsm->fcs, gsm->received_fcs);
+- }
+ if (gsm->fcs != GOOD_FCS) {
+ gsm->bad_fcs++;
+ if (debug & 4)
+@@ -1993,19 +1981,25 @@ static void gsm0_receive(struct gsm_mux
+ break;
+ case GSM_DATA: /* Data */
+ gsm->buf[gsm->count++] = c;
+- if (gsm->count == gsm->len)
++ if (gsm->count == gsm->len) {
++ /* Calculate final FCS for UI frames over all data */
++ if ((gsm->control & ~PF) != UIH) {
++ gsm->fcs = gsm_fcs_add_block(gsm->fcs, gsm->buf,
++ gsm->count);
++ }
+ gsm->state = GSM_FCS;
++ }
+ break;
+ case GSM_FCS: /* FCS follows the packet */
+- gsm->received_fcs = c;
+- gsm_queue(gsm);
++ gsm->fcs = gsm_fcs_add(gsm->fcs, c);
+ gsm->state = GSM_SSOF;
+ break;
+ case GSM_SSOF:
+- if (c == GSM0_SOF) {
+- gsm->state = GSM_SEARCH;
+- break;
+- }
++ gsm->state = GSM_SEARCH;
++ if (c == GSM0_SOF)
++ gsm_queue(gsm);
++ else
++ gsm->bad_size++;
+ break;
+ default:
+ pr_debug("%s: unhandled state: %d\n", __func__, gsm->state);
+@@ -2024,11 +2018,24 @@ static void gsm0_receive(struct gsm_mux
+ static void gsm1_receive(struct gsm_mux *gsm, unsigned char c)
+ {
+ if (c == GSM1_SOF) {
+- /* EOF is only valid in frame if we have got to the data state
+- and received at least one byte (the FCS) */
+- if (gsm->state == GSM_DATA && gsm->count) {
+- /* Extract the FCS */
++ /* EOF is only valid in frame if we have got to the data state */
++ if (gsm->state == GSM_DATA) {
++ if (gsm->count < 1) {
++ /* Missing FSC */
++ gsm->malformed++;
++ gsm->state = GSM_START;
++ return;
++ }
++ /* Remove the FCS from data */
+ gsm->count--;
++ if ((gsm->control & ~PF) != UIH) {
++ /* Calculate final FCS for UI frames over all
++ * data but FCS
++ */
++ gsm->fcs = gsm_fcs_add_block(gsm->fcs, gsm->buf,
++ gsm->count);
++ }
++ /* Add the FCS itself to test against GOOD_FCS */
+ gsm->fcs = gsm_fcs_add(gsm->fcs, gsm->buf[gsm->count]);
+ gsm->len = gsm->count;
+ gsm_queue(gsm);
--- /dev/null
+From a24b4b2f660b7ddf3f484b37600bba382cb28a9d Mon Sep 17 00:00:00 2001
+From: Daniel Starke <daniel.starke@siemens.com>
+Date: Thu, 14 Apr 2022 02:42:12 -0700
+Subject: tty: n_gsm: fix malformed counter for out of frame data
+
+From: Daniel Starke <daniel.starke@siemens.com>
+
+commit a24b4b2f660b7ddf3f484b37600bba382cb28a9d upstream.
+
+The gsm_mux field 'malformed' represents the number of malformed frames
+received. However, gsm1_receive() also increases this counter for any out
+of frame byte.
+Fix this by ignoring out of frame data for the malformed counter.
+
+Fixes: e1eaea46bb40 ("tty: n_gsm line discipline")
+Cc: stable@vger.kernel.org
+Signed-off-by: Daniel Starke <daniel.starke@siemens.com>
+Link: https://lore.kernel.org/r/20220414094225.4527-7-daniel.starke@siemens.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/tty/n_gsm.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+--- a/drivers/tty/n_gsm.c
++++ b/drivers/tty/n_gsm.c
+@@ -2044,7 +2044,8 @@ static void gsm1_receive(struct gsm_mux
+ }
+ /* Any partial frame was a runt so go back to start */
+ if (gsm->state != GSM_START) {
+- gsm->malformed++;
++ if (gsm->state != GSM_SEARCH)
++ gsm->malformed++;
+ gsm->state = GSM_START;
+ }
+ /* A SOF in GSM_START means we are still reading idling or
--- /dev/null
+From 284260f278b706364fb4c88a7b56ba5298d5973c Mon Sep 17 00:00:00 2001
+From: Daniel Starke <daniel.starke@siemens.com>
+Date: Thu, 14 Apr 2022 02:42:09 -0700
+Subject: tty: n_gsm: fix mux cleanup after unregister tty device
+
+From: Daniel Starke <daniel.starke@siemens.com>
+
+commit 284260f278b706364fb4c88a7b56ba5298d5973c upstream.
+
+Internally, we manage the alive state of the mux channels and mux itself
+with the field member 'dead'. This makes it possible to notify the user
+if the accessed underlying link is already gone. On the other hand,
+however, removing the virtual ttys before terminating the channels may
+result in peer messages being received without any internal target. Move
+the mux cleanup procedure from gsmld_detach_gsm() to gsmld_close() to fix
+this by keeping the virtual ttys open until the mux has been cleaned up.
+
+Fixes: e1eaea46bb40 ("tty: n_gsm line discipline")
+Cc: stable@vger.kernel.org
+Signed-off-by: Daniel Starke <daniel.starke@siemens.com>
+Link: https://lore.kernel.org/r/20220414094225.4527-4-daniel.starke@siemens.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/tty/n_gsm.c | 7 ++++++-
+ 1 file changed, 6 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/tty/n_gsm.c b/drivers/tty/n_gsm.c
+index f546dfe03d29..de97a3810731 100644
+--- a/drivers/tty/n_gsm.c
++++ b/drivers/tty/n_gsm.c
+@@ -2479,7 +2479,6 @@ static void gsmld_detach_gsm(struct tty_struct *tty, struct gsm_mux *gsm)
+ for (i = 1; i < NUM_DLCI; i++)
+ tty_unregister_device(gsm_tty_driver, base + i);
+ }
+- gsm_cleanup_mux(gsm, false);
+ tty_kref_put(gsm->tty);
+ gsm->tty = NULL;
+ }
+@@ -2544,6 +2543,12 @@ static void gsmld_close(struct tty_struct *tty)
+ {
+ struct gsm_mux *gsm = tty->disc_data;
+
++ /* The ldisc locks and closes the port before calling our close. This
++ * means we have no way to do a proper disconnect. We will not bother
++ * to do one.
++ */
++ gsm_cleanup_mux(gsm, false);
++
+ gsmld_detach_gsm(tty, gsm);
+
+ gsmld_flush_buffer(tty);
+--
+2.36.0
+
--- /dev/null
+From 06d5afd4d640eea67f5623e76cd5fc03359b7f3c Mon Sep 17 00:00:00 2001
+From: Daniel Starke <daniel.starke@siemens.com>
+Date: Thu, 14 Apr 2022 02:42:10 -0700
+Subject: tty: n_gsm: fix wrong signal octet encoding in convergence layer type 2
+
+From: Daniel Starke <daniel.starke@siemens.com>
+
+commit 06d5afd4d640eea67f5623e76cd5fc03359b7f3c upstream.
+
+n_gsm is based on the 3GPP 07.010 and its newer version is the 3GPP 27.010.
+See https://portal.3gpp.org/desktopmodules/Specifications/SpecificationDetails.aspx?specificationId=1516
+The changes from 07.010 to 27.010 are non-functional. Therefore, I refer to
+the newer 27.010 here. Chapter 5.5.2 describes that the signal octet in
+convergence layer type 2 can be either one or two bytes. The length is
+encoded in the EA bit. This is set 1 for the last byte in the sequence.
+gsmtty_modem_update() handles this correctly but gsm_dlci_data_output()
+fails to set EA to 1. There is no case in which we encode two signal octets
+as there is no case in which we send out a break signal.
+Therefore, always set the EA bit to 1 for the signal octet to fix this.
+
+Fixes: e1eaea46bb40 ("tty: n_gsm line discipline")
+Cc: stable@vger.kernel.org
+Signed-off-by: Daniel Starke <daniel.starke@siemens.com>
+Link: https://lore.kernel.org/r/20220414094225.4527-5-daniel.starke@siemens.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/tty/n_gsm.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/tty/n_gsm.c
++++ b/drivers/tty/n_gsm.c
+@@ -832,7 +832,7 @@ static int gsm_dlci_data_output(struct g
+ break;
+ case 2: /* Unstructed with modem bits.
+ Always one byte as we never send inline break data */
+- *dp++ = gsm_encode_modem(dlci);
++ *dp++ = (gsm_encode_modem(dlci) << 1) | EA;
+ break;
+ }
+ WARN_ON(kfifo_out_locked(&dlci->fifo, dp , len, &dlci->lock) != len);