]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
5.17-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 3 May 2022 13:43:23 +0000 (15:43 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 3 May 2022 13:43:23 +0000 (15:43 +0200)
added patches:
tty-n_gsm-fix-broken-virtual-tty-handling.patch
tty-n_gsm-fix-incorrect-ua-handling.patch
tty-n_gsm-fix-insufficient-txframe-size.patch
tty-n_gsm-fix-invalid-use-of-msc-in-advanced-option.patch
tty-n_gsm-fix-missing-explicit-ldisc-flush.patch
tty-n_gsm-fix-missing-tty-wakeup-in-convergence-layer-type-2.patch
tty-n_gsm-fix-missing-update-of-modem-controls-after-dlci-open.patch
tty-n_gsm-fix-reset-fifo-race-condition.patch
tty-n_gsm-fix-software-flow-control-handling.patch
tty-n_gsm-fix-wrong-command-frame-length-field-encoding.patch
tty-n_gsm-fix-wrong-command-retry-handling.patch
tty-n_gsm-fix-wrong-dlci-release-order.patch
tty-n_gsm-fix-wrong-signal-octets-encoding-in-msc.patch

14 files changed:
queue-5.17/series
queue-5.17/tty-n_gsm-fix-broken-virtual-tty-handling.patch [new file with mode: 0644]
queue-5.17/tty-n_gsm-fix-incorrect-ua-handling.patch [new file with mode: 0644]
queue-5.17/tty-n_gsm-fix-insufficient-txframe-size.patch [new file with mode: 0644]
queue-5.17/tty-n_gsm-fix-invalid-use-of-msc-in-advanced-option.patch [new file with mode: 0644]
queue-5.17/tty-n_gsm-fix-missing-explicit-ldisc-flush.patch [new file with mode: 0644]
queue-5.17/tty-n_gsm-fix-missing-tty-wakeup-in-convergence-layer-type-2.patch [new file with mode: 0644]
queue-5.17/tty-n_gsm-fix-missing-update-of-modem-controls-after-dlci-open.patch [new file with mode: 0644]
queue-5.17/tty-n_gsm-fix-reset-fifo-race-condition.patch [new file with mode: 0644]
queue-5.17/tty-n_gsm-fix-software-flow-control-handling.patch [new file with mode: 0644]
queue-5.17/tty-n_gsm-fix-wrong-command-frame-length-field-encoding.patch [new file with mode: 0644]
queue-5.17/tty-n_gsm-fix-wrong-command-retry-handling.patch [new file with mode: 0644]
queue-5.17/tty-n_gsm-fix-wrong-dlci-release-order.patch [new file with mode: 0644]
queue-5.17/tty-n_gsm-fix-wrong-signal-octets-encoding-in-msc.patch [new file with mode: 0644]

index b9fa15710f06e39c68b1f4710d561825020d2eae..cc1aa299a796a7c3204589aa94f642bc9eaa74b5 100644 (file)
@@ -206,3 +206,16 @@ 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
 netfilter-nft_socket-only-do-sk-lookups-when-indev-is-available.patch
+tty-n_gsm-fix-insufficient-txframe-size.patch
+tty-n_gsm-fix-wrong-dlci-release-order.patch
+tty-n_gsm-fix-missing-explicit-ldisc-flush.patch
+tty-n_gsm-fix-wrong-command-retry-handling.patch
+tty-n_gsm-fix-wrong-command-frame-length-field-encoding.patch
+tty-n_gsm-fix-wrong-signal-octets-encoding-in-msc.patch
+tty-n_gsm-fix-missing-tty-wakeup-in-convergence-layer-type-2.patch
+tty-n_gsm-fix-reset-fifo-race-condition.patch
+tty-n_gsm-fix-incorrect-ua-handling.patch
+tty-n_gsm-fix-missing-update-of-modem-controls-after-dlci-open.patch
+tty-n_gsm-fix-broken-virtual-tty-handling.patch
+tty-n_gsm-fix-invalid-use-of-msc-in-advanced-option.patch
+tty-n_gsm-fix-software-flow-control-handling.patch
diff --git a/queue-5.17/tty-n_gsm-fix-broken-virtual-tty-handling.patch b/queue-5.17/tty-n_gsm-fix-broken-virtual-tty-handling.patch
new file mode 100644 (file)
index 0000000..2929e15
--- /dev/null
@@ -0,0 +1,219 @@
+From a8c5b8255f8a9acd58a4b15ff1c14cd6effd114b Mon Sep 17 00:00:00 2001
+From: Daniel Starke <daniel.starke@siemens.com>
+Date: Fri, 22 Apr 2022 00:10:23 -0700
+Subject: tty: n_gsm: fix broken virtual tty handling
+
+From: Daniel Starke <daniel.starke@siemens.com>
+
+commit a8c5b8255f8a9acd58a4b15ff1c14cd6effd114b upstream.
+
+Dynamic virtual tty registration was introduced to allow the user to handle
+these cases with uevent rules. The following commits relate to this:
+Commit 5b87686e3203 ("tty: n_gsm: Modify gsmtty driver register method when config requester")
+Commit 0b91b5332368 ("tty: n_gsm: Save dlci address open status when config requester")
+Commit 46292622ad73 ("tty: n_gsm: clean up indenting in gsm_queue()")
+
+However, the following behavior can be seen with this implementation:
+- n_gsm ldisc is activated via ioctl
+- all configuration parameters are set to their default value (initiator=0)
+- the mux gets activated and attached and gsmtty0 is being registered in
+  in gsm_dlci_open() after DLCI 0 was established (DLCI 0 is the control
+  channel)
+- the user configures n_gsm via ioctl GSMIOC_SETCONF as initiator
+- this re-attaches the n_gsm mux
+- no new gsmtty devices are registered in gsmld_attach_gsm() because the
+  mux is already active
+- the initiator side registered only the control channel as gsmtty0
+  (which should never happen) and no user channel tty
+
+The commits above make it impossible to operate the initiator side as no
+user channel tty is or will be available.
+On the other hand, this behavior will make it also impossible to allow DLCI
+parameter negotiation on responder side in the future. The responder side
+first needs to provide a device for the application before the application
+can set its parameters of the associated DLCI via ioctl.
+Note that the user application is still able to detect a link establishment
+without relaying to uevent by waiting for DTR open on responder side. This
+is the same behavior as on a physical serial interface. And on initiator
+side a tty hangup can be detected if a link establishment request failed.
+
+Revert the commits above completely to always register all user channels
+and no control channel after mux attachment. No other changes are made.
+
+Fixes: 5b87686e3203 ("tty: n_gsm: Modify gsmtty driver register method when config requester")
+Cc: stable@vger.kernel.org
+Signed-off-by: Daniel Starke <daniel.starke@siemens.com>
+Link: https://lore.kernel.org/r/20220422071025.5490-1-daniel.starke@siemens.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/tty/n_gsm.c |   87 ++++++++--------------------------------------------
+ 1 file changed, 15 insertions(+), 72 deletions(-)
+
+--- a/drivers/tty/n_gsm.c
++++ b/drivers/tty/n_gsm.c
+@@ -272,10 +272,6 @@ static DEFINE_SPINLOCK(gsm_mux_lock);
+ static struct tty_driver *gsm_tty_driver;
+-/* Save dlci open address */
+-static int addr_open[256] = { 0 };
+-/* Save dlci open count */
+-static int addr_cnt;
+ /*
+  *    This section of the driver logic implements the GSM encodings
+  *    both the basic and the 'advanced'. Reliable transport is not
+@@ -1185,7 +1181,6 @@ static void gsm_control_rls(struct gsm_m
+ }
+ static void gsm_dlci_begin_close(struct gsm_dlci *dlci);
+-static void gsm_dlci_close(struct gsm_dlci *dlci);
+ /**
+  *    gsm_control_message     -       DLCI 0 control processing
+@@ -1204,28 +1199,15 @@ static void gsm_control_message(struct g
+ {
+       u8 buf[1];
+       unsigned long flags;
+-      struct gsm_dlci *dlci;
+-      int i;
+-      int address;
+       switch (command) {
+       case CMD_CLD: {
+-              if (addr_cnt > 0) {
+-                      for (i = 0; i < addr_cnt; i++) {
+-                              address = addr_open[i];
+-                              dlci = gsm->dlci[address];
+-                              gsm_dlci_close(dlci);
+-                              addr_open[i] = 0;
+-                      }
+-              }
++              struct gsm_dlci *dlci = gsm->dlci[0];
+               /* Modem wishes to close down */
+-              dlci = gsm->dlci[0];
+               if (dlci) {
+                       dlci->dead = true;
+                       gsm->dead = true;
+-                      gsm_dlci_close(dlci);
+-                      addr_cnt = 0;
+-                      gsm_response(gsm, 0, UA|PF);
++                      gsm_dlci_begin_close(dlci);
+               }
+               }
+               break;
+@@ -1459,8 +1441,6 @@ static void gsm_dlci_close(struct gsm_dl
+               wake_up_interruptible(&dlci->port.open_wait);
+       } else
+               dlci->gsm->dead = true;
+-      /* Unregister gsmtty driver,report gsmtty dev remove uevent for user */
+-      tty_unregister_device(gsm_tty_driver, dlci->addr);
+       wake_up(&dlci->gsm->event);
+       /* A DLCI 0 close is a MUX termination so we need to kick that
+          back to userspace somehow */
+@@ -1482,8 +1462,6 @@ static void gsm_dlci_open(struct gsm_dlc
+       dlci->state = DLCI_OPEN;
+       if (debug & 8)
+               pr_debug("DLCI %d goes open.\n", dlci->addr);
+-      /* Register gsmtty driver,report gsmtty dev add uevent for user */
+-      tty_register_device(gsm_tty_driver, dlci->addr, NULL);
+       /* Send current modem state */
+       if (dlci->addr)
+               gsmtty_modem_update(dlci, 0);
+@@ -1794,7 +1772,6 @@ static void gsm_queue(struct gsm_mux *gs
+       struct gsm_dlci *dlci;
+       u8 cr;
+       int address;
+-      int i, j, k, address_tmp;
+       if (gsm->fcs != GOOD_FCS) {
+               gsm->bad_fcs++;
+@@ -1826,11 +1803,6 @@ static void gsm_queue(struct gsm_mux *gs
+               else {
+                       gsm_response(gsm, address, UA|PF);
+                       gsm_dlci_open(dlci);
+-                      /* Save dlci open address */
+-                      if (address) {
+-                              addr_open[addr_cnt] = address;
+-                              addr_cnt++;
+-                      }
+               }
+               break;
+       case DISC|PF:
+@@ -1841,33 +1813,8 @@ static void gsm_queue(struct gsm_mux *gs
+                       return;
+               }
+               /* Real close complete */
+-              if (!address) {
+-                      if (addr_cnt > 0) {
+-                              for (i = 0; i < addr_cnt; i++) {
+-                                      address = addr_open[i];
+-                                      dlci = gsm->dlci[address];
+-                                      gsm_dlci_close(dlci);
+-                                      addr_open[i] = 0;
+-                              }
+-                      }
+-                      dlci = gsm->dlci[0];
+-                      gsm_dlci_close(dlci);
+-                      addr_cnt = 0;
+-                      gsm_response(gsm, 0, UA|PF);
+-              } else {
+-                      gsm_response(gsm, address, UA|PF);
+-                      gsm_dlci_close(dlci);
+-                      /* clear dlci address */
+-                      for (j = 0; j < addr_cnt; j++) {
+-                              address_tmp = addr_open[j];
+-                              if (address_tmp == address) {
+-                                      for (k = j; k < addr_cnt; k++)
+-                                              addr_open[k] = addr_open[k+1];
+-                                      addr_cnt--;
+-                                      break;
+-                              }
+-                      }
+-              }
++              gsm_response(gsm, address, UA|PF);
++              gsm_dlci_close(dlci);
+               break;
+       case UA|PF:
+               if (cr == 0 || dlci == NULL)
+@@ -2451,19 +2398,17 @@ static int gsmld_attach_gsm(struct tty_s
+       else {
+               /* Don't register device 0 - this is the control channel and not
+                  a usable tty interface */
+-              if (gsm->initiator) {
+-                      base = mux_num_to_base(gsm); /* Base for this MUX */
+-                      for (i = 1; i < NUM_DLCI; i++) {
+-                              struct device *dev;
++              base = mux_num_to_base(gsm); /* Base for this MUX */
++              for (i = 1; i < NUM_DLCI; i++) {
++                      struct device *dev;
+-                              dev = tty_register_device(gsm_tty_driver,
++                      dev = tty_register_device(gsm_tty_driver,
+                                                       base + i, NULL);
+-                              if (IS_ERR(dev)) {
+-                                      for (i--; i >= 1; i--)
+-                                              tty_unregister_device(gsm_tty_driver,
+-                                                                      base + i);
+-                                      return PTR_ERR(dev);
+-                              }
++                      if (IS_ERR(dev)) {
++                              for (i--; i >= 1; i--)
++                                      tty_unregister_device(gsm_tty_driver,
++                                                              base + i);
++                              return PTR_ERR(dev);
+                       }
+               }
+       }
+@@ -2485,10 +2430,8 @@ static void gsmld_detach_gsm(struct tty_
+       int i;
+       WARN_ON(tty != gsm->tty);
+-      if (gsm->initiator) {
+-              for (i = 1; i < NUM_DLCI; i++)
+-                      tty_unregister_device(gsm_tty_driver, base + i);
+-      }
++      for (i = 1; i < NUM_DLCI; i++)
++              tty_unregister_device(gsm_tty_driver, base + i);
+       tty_kref_put(gsm->tty);
+       gsm->tty = NULL;
+ }
diff --git a/queue-5.17/tty-n_gsm-fix-incorrect-ua-handling.patch b/queue-5.17/tty-n_gsm-fix-incorrect-ua-handling.patch
new file mode 100644 (file)
index 0000000..3e341d2
--- /dev/null
@@ -0,0 +1,38 @@
+From ff9166c623704337bd6fe66fce2838d9768a6634 Mon Sep 17 00:00:00 2001
+From: Daniel Starke <daniel.starke@siemens.com>
+Date: Thu, 14 Apr 2022 02:42:25 -0700
+Subject: tty: n_gsm: fix incorrect UA handling
+
+From: Daniel Starke <daniel.starke@siemens.com>
+
+commit ff9166c623704337bd6fe66fce2838d9768a6634 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.4.4.2 states that any received unnumbered
+acknowledgment (UA) with its poll/final (PF) bit set to 0 shall be
+discarded. Currently, all UA frame are handled in the same way regardless
+of the PF bit. This does not comply with the standard.
+Remove the UA case in gsm_queue() to process only UA frames with PF bit set
+to 1 to abide the standard.
+
+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-20-daniel.starke@siemens.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/tty/n_gsm.c |    1 -
+ 1 file changed, 1 deletion(-)
+
+--- a/drivers/tty/n_gsm.c
++++ b/drivers/tty/n_gsm.c
+@@ -1865,7 +1865,6 @@ static void gsm_queue(struct gsm_mux *gs
+                       }
+               }
+               break;
+-      case UA:
+       case UA|PF:
+               if (cr == 0 || dlci == NULL)
+                       break;
diff --git a/queue-5.17/tty-n_gsm-fix-insufficient-txframe-size.patch b/queue-5.17/tty-n_gsm-fix-insufficient-txframe-size.patch
new file mode 100644 (file)
index 0000000..767055e
--- /dev/null
@@ -0,0 +1,52 @@
+From 535bf600de75a859698892ee873521a48d289ec1 Mon Sep 17 00:00:00 2001
+From: Daniel Starke <daniel.starke@siemens.com>
+Date: Thu, 14 Apr 2022 02:42:13 -0700
+Subject: tty: n_gsm: fix insufficient txframe size
+
+From: Daniel Starke <daniel.starke@siemens.com>
+
+commit 535bf600de75a859698892ee873521a48d289ec1 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.7.2 states that the maximum frame size
+(N1) refers to the length of the information field (i.e. user payload).
+However, 'txframe' stores the whole frame including frame header, checksum
+and start/end flags. We also need to consider the byte stuffing overhead.
+Define constant for the protocol overhead and adjust the 'txframe' size
+calculation accordingly to reserve enough space for a complete mux frame
+including byte stuffing for advanced option mode. Note that no byte
+stuffing is applied to the start and end flag.
+Also use MAX_MTU instead of MAX_MRU as this buffer is used for data
+transmission.
+
+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-8-daniel.starke@siemens.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/tty/n_gsm.c |    4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+--- a/drivers/tty/n_gsm.c
++++ b/drivers/tty/n_gsm.c
+@@ -73,6 +73,8 @@ module_param(debug, int, 0600);
+  */
+ #define MAX_MRU 1500
+ #define MAX_MTU 1500
++/* SOF, ADDR, CTRL, LEN1, LEN2, ..., FCS, EOF */
++#define PROT_OVERHEAD 7
+ #define       GSM_NET_TX_TIMEOUT (HZ*10)
+ /*
+@@ -2264,7 +2266,7 @@ static struct gsm_mux *gsm_alloc_mux(voi
+               kfree(gsm);
+               return NULL;
+       }
+-      gsm->txframe = kmalloc(2 * MAX_MRU + 2, GFP_KERNEL);
++      gsm->txframe = kmalloc(2 * (MAX_MTU + PROT_OVERHEAD - 1), GFP_KERNEL);
+       if (gsm->txframe == NULL) {
+               kfree(gsm->buf);
+               kfree(gsm);
diff --git a/queue-5.17/tty-n_gsm-fix-invalid-use-of-msc-in-advanced-option.patch b/queue-5.17/tty-n_gsm-fix-invalid-use-of-msc-in-advanced-option.patch
new file mode 100644 (file)
index 0000000..c7d11ea
--- /dev/null
@@ -0,0 +1,238 @@
+From c19ffe00fed6bb423d81406d2a7e5793074c7d83 Mon Sep 17 00:00:00 2001
+From: Daniel Starke <daniel.starke@siemens.com>
+Date: Fri, 22 Apr 2022 00:10:24 -0700
+Subject: tty: n_gsm: fix invalid use of MSC in advanced option
+
+From: Daniel Starke <daniel.starke@siemens.com>
+
+commit c19ffe00fed6bb423d81406d2a7e5793074c7d83 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.4.6.3.7 states that the Modem Status
+Command (MSC) shall only be used if the basic option was chosen.
+The current implementation uses MSC frames even if advanced option was
+chosen to inform the peer about modem line state updates. A standard
+conform peer may choose to discard these frames in advanced option mode.
+Furthermore, gsmtty_modem_update() is not part of the 'tty_operations'
+functions despite its name.
+Rename gsmtty_modem_update() to gsm_modem_update() to clarify this. Split
+its function into gsm_modem_upd_via_data() and gsm_modem_upd_via_msc()
+depending on the encoding and adaption. Introduce gsm_dlci_modem_output()
+as adaption of gsm_dlci_data_output() to encode and queue empty frames in
+advanced option mode. Use it in gsm_modem_upd_via_data().
+gsm_modem_upd_via_msc() is based on the initial gsmtty_modem_update()
+function which used only MSC frames to update modem states.
+
+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/20220422071025.5490-2-daniel.starke@siemens.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/tty/n_gsm.c |  125 ++++++++++++++++++++++++++++++++++++++++++++++++----
+ 1 file changed, 117 insertions(+), 8 deletions(-)
+
+--- a/drivers/tty/n_gsm.c
++++ b/drivers/tty/n_gsm.c
+@@ -366,7 +366,7 @@ static const u8 gsm_fcs8[256] = {
+ #define GOOD_FCS      0xCF
+ static int gsmld_output(struct gsm_mux *gsm, u8 *data, int len);
+-static int gsmtty_modem_update(struct gsm_dlci *dlci, u8 brk);
++static int gsm_modem_update(struct gsm_dlci *dlci, u8 brk);
+ /**
+  *    gsm_fcs_add     -       update FCS
+@@ -915,6 +915,63 @@ static int gsm_dlci_data_output_framed(s
+ }
+ /**
++ *    gsm_dlci_modem_output   -       try and push modem status out of a DLCI
++ *    @gsm: mux
++ *    @dlci: the DLCI to pull modem status from
++ *    @brk: break signal
++ *
++ *    Push an empty frame in to the transmit queue to update the modem status
++ *    bits and to transmit an optional break.
++ *
++ *    Caller must hold the tx_lock of the mux.
++ */
++
++static int gsm_dlci_modem_output(struct gsm_mux *gsm, struct gsm_dlci *dlci,
++                               u8 brk)
++{
++      u8 *dp = NULL;
++      struct gsm_msg *msg;
++      int size;
++
++      /* for modem bits without break data */
++      if (dlci->adaption == 1) {
++              size = 0;
++      } else if (dlci->adaption == 2) {
++              size = 1;
++              if (brk > 0)
++                      size++;
++      } else {
++              pr_err("%s: unsupported adaption %d\n", __func__,
++                     dlci->adaption);
++      }
++
++      msg = gsm_data_alloc(gsm, dlci->addr, size, gsm->ftype);
++      if (!msg) {
++              pr_err("%s: gsm_data_alloc error", __func__);
++              return -ENOMEM;
++      }
++      dp = msg->data;
++      switch (dlci->adaption) {
++      case 1: /* Unstructured */
++              break;
++      case 2: /* Unstructured with modem bits. */
++              if (brk == 0) {
++                      *dp++ = (gsm_encode_modem(dlci) << 1) | EA;
++              } else {
++                      *dp++ = gsm_encode_modem(dlci) << 1;
++                      *dp++ = (brk << 4) | 2 | EA; /* Length, Break, EA */
++              }
++              break;
++      default:
++              /* Handled above */
++              break;
++      }
++
++      __gsm_data_queue(dlci, msg);
++      return size;
++}
++
++/**
+  *    gsm_dlci_data_sweep             -       look for data to send
+  *    @gsm: the GSM mux
+  *
+@@ -1464,7 +1521,7 @@ static void gsm_dlci_open(struct gsm_dlc
+               pr_debug("DLCI %d goes open.\n", dlci->addr);
+       /* Send current modem state */
+       if (dlci->addr)
+-              gsmtty_modem_update(dlci, 0);
++              gsm_modem_update(dlci, 0);
+       wake_up(&dlci->gsm->event);
+ }
+@@ -2897,12 +2954,43 @@ static struct tty_ldisc_ops tty_ldisc_pa
+ #define TX_SIZE               512
+-static int gsmtty_modem_update(struct gsm_dlci *dlci, u8 brk)
++/**
++ *    gsm_modem_upd_via_data  -       send modem bits via convergence layer
++ *    @dlci: channel
++ *    @brk: break signal
++ *
++ *    Send an empty frame to signal mobile state changes and to transmit the
++ *    break signal for adaption 2.
++ */
++
++static void gsm_modem_upd_via_data(struct gsm_dlci *dlci, u8 brk)
++{
++      struct gsm_mux *gsm = dlci->gsm;
++      unsigned long flags;
++
++      if (dlci->state != DLCI_OPEN || dlci->adaption != 2)
++              return;
++
++      spin_lock_irqsave(&gsm->tx_lock, flags);
++      gsm_dlci_modem_output(gsm, dlci, brk);
++      spin_unlock_irqrestore(&gsm->tx_lock, flags);
++}
++
++/**
++ *    gsm_modem_upd_via_msc   -       send modem bits via control frame
++ *    @dlci: channel
++ *    @brk: break signal
++ */
++
++static int gsm_modem_upd_via_msc(struct gsm_dlci *dlci, u8 brk)
+ {
+       u8 modembits[3];
+       struct gsm_control *ctrl;
+       int len = 2;
++      if (dlci->gsm->encoding != 0)
++              return 0;
++
+       modembits[0] = (dlci->addr << 2) | 2 | EA;  /* DLCI, Valid, EA */
+       if (!brk) {
+               modembits[1] = (gsm_encode_modem(dlci) << 1) | EA;
+@@ -2917,6 +3005,27 @@ static int gsmtty_modem_update(struct gs
+       return gsm_control_wait(dlci->gsm, ctrl);
+ }
++/**
++ *    gsm_modem_update        -       send modem status line state
++ *    @dlci: channel
++ *    @brk: break signal
++ */
++
++static int gsm_modem_update(struct gsm_dlci *dlci, u8 brk)
++{
++      if (dlci->adaption == 2) {
++              /* Send convergence layer type 2 empty data frame. */
++              gsm_modem_upd_via_data(dlci, brk);
++              return 0;
++      } else if (dlci->gsm->encoding == 0) {
++              /* Send as MSC control message. */
++              return gsm_modem_upd_via_msc(dlci, brk);
++      }
++
++      /* Modem status lines are not supported. */
++      return -EPROTONOSUPPORT;
++}
++
+ static int gsm_carrier_raised(struct tty_port *port)
+ {
+       struct gsm_dlci *dlci = container_of(port, struct gsm_dlci, port);
+@@ -2949,7 +3058,7 @@ static void gsm_dtr_rts(struct tty_port
+               modem_tx &= ~(TIOCM_DTR | TIOCM_RTS);
+       if (modem_tx != dlci->modem_tx) {
+               dlci->modem_tx = modem_tx;
+-              gsmtty_modem_update(dlci, 0);
++              gsm_modem_update(dlci, 0);
+       }
+ }
+@@ -3140,7 +3249,7 @@ static int gsmtty_tiocmset(struct tty_st
+       if (modem_tx != dlci->modem_tx) {
+               dlci->modem_tx = modem_tx;
+-              return gsmtty_modem_update(dlci, 0);
++              return gsm_modem_update(dlci, 0);
+       }
+       return 0;
+ }
+@@ -3201,7 +3310,7 @@ static void gsmtty_throttle(struct tty_s
+               dlci->modem_tx &= ~TIOCM_RTS;
+       dlci->throttled = true;
+       /* Send an MSC with RTS cleared */
+-      gsmtty_modem_update(dlci, 0);
++      gsm_modem_update(dlci, 0);
+ }
+ static void gsmtty_unthrottle(struct tty_struct *tty)
+@@ -3213,7 +3322,7 @@ static void gsmtty_unthrottle(struct tty
+               dlci->modem_tx |= TIOCM_RTS;
+       dlci->throttled = false;
+       /* Send an MSC with RTS set */
+-      gsmtty_modem_update(dlci, 0);
++      gsm_modem_update(dlci, 0);
+ }
+ static int gsmtty_break_ctl(struct tty_struct *tty, int state)
+@@ -3231,7 +3340,7 @@ static int gsmtty_break_ctl(struct tty_s
+               if (encode > 0x0F)
+                       encode = 0x0F;  /* Best effort */
+       }
+-      return gsmtty_modem_update(dlci, encode);
++      return gsm_modem_update(dlci, encode);
+ }
+ static void gsmtty_cleanup(struct tty_struct *tty)
diff --git a/queue-5.17/tty-n_gsm-fix-missing-explicit-ldisc-flush.patch b/queue-5.17/tty-n_gsm-fix-missing-explicit-ldisc-flush.patch
new file mode 100644 (file)
index 0000000..52825a0
--- /dev/null
@@ -0,0 +1,35 @@
+From 17eac652028501df7ea296b1d9b9c134db262b7d Mon Sep 17 00:00:00 2001
+From: Daniel Starke <daniel.starke@siemens.com>
+Date: Thu, 14 Apr 2022 02:42:15 -0700
+Subject: tty: n_gsm: fix missing explicit ldisc flush
+
+From: Daniel Starke <daniel.starke@siemens.com>
+
+commit 17eac652028501df7ea296b1d9b9c134db262b7d upstream.
+
+In gsm_cleanup_mux() the muxer is closed down and all queues are removed.
+However, removing the queues is done without explicit control of the
+underlying buffers. Flush those before freeing up our queues to ensure
+that all outgoing queues are cleared consistently. Otherwise, a new mux
+connection establishment attempt may time out while the underlying tty is
+still busy sending out the remaining data from the previous connection.
+
+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-10-daniel.starke@siemens.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/tty/n_gsm.c |    1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/drivers/tty/n_gsm.c
++++ b/drivers/tty/n_gsm.c
+@@ -2152,6 +2152,7 @@ static void gsm_cleanup_mux(struct gsm_m
+                       gsm_dlci_release(gsm->dlci[i]);
+       mutex_unlock(&gsm->mutex);
+       /* Now wipe the queues */
++      tty_ldisc_flush(gsm->tty);
+       list_for_each_entry_safe(txq, ntxq, &gsm->tx_list, list)
+               kfree(txq);
+       INIT_LIST_HEAD(&gsm->tx_list);
diff --git a/queue-5.17/tty-n_gsm-fix-missing-tty-wakeup-in-convergence-layer-type-2.patch b/queue-5.17/tty-n_gsm-fix-missing-tty-wakeup-in-convergence-layer-type-2.patch
new file mode 100644 (file)
index 0000000..27f264c
--- /dev/null
@@ -0,0 +1,35 @@
+From 1adf6fee58ca25fb6720b8d34c919dcf5425cc9c Mon Sep 17 00:00:00 2001
+From: Daniel Starke <daniel.starke@siemens.com>
+Date: Thu, 14 Apr 2022 02:42:19 -0700
+Subject: tty: n_gsm: fix missing tty wakeup in convergence layer type 2
+
+From: Daniel Starke <daniel.starke@siemens.com>
+
+commit 1adf6fee58ca25fb6720b8d34c919dcf5425cc9c upstream.
+
+gsm_control_modem() informs the virtual tty that more data can be written
+after receiving a control signal octet via modem status command (MSC).
+However, gsm_dlci_data() fails to do the same after receiving a control
+signal octet from the convergence layer type 2 header.
+Add tty_wakeup() in gsm_dlci_data() for convergence layer type 2 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-14-daniel.starke@siemens.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/tty/n_gsm.c |    1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/drivers/tty/n_gsm.c
++++ b/drivers/tty/n_gsm.c
+@@ -1615,6 +1615,7 @@ static void gsm_dlci_data(struct gsm_dlc
+               tty = tty_port_tty_get(port);
+               if (tty) {
+                       gsm_process_modem(tty, dlci, modem, slen);
++                      tty_wakeup(tty);
+                       tty_kref_put(tty);
+               }
+               fallthrough;
diff --git a/queue-5.17/tty-n_gsm-fix-missing-update-of-modem-controls-after-dlci-open.patch b/queue-5.17/tty-n_gsm-fix-missing-update-of-modem-controls-after-dlci-open.patch
new file mode 100644 (file)
index 0000000..dac9681
--- /dev/null
@@ -0,0 +1,42 @@
+From 48473802506d2d6151f59e0e764932b33b53cb3b Mon Sep 17 00:00:00 2001
+From: Daniel Starke <daniel.starke@siemens.com>
+Date: Wed, 20 Apr 2022 03:13:44 -0700
+Subject: tty: n_gsm: fix missing update of modem controls after DLCI open
+
+From: Daniel Starke <daniel.starke@siemens.com>
+
+commit 48473802506d2d6151f59e0e764932b33b53cb3b upstream.
+
+Currently the peer is not informed about the initial state of the modem
+control lines after a new DLCI has been opened.
+Fix this by sending the initial modem control line states after DLCI open.
+
+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/20220420101346.3315-1-daniel.starke@siemens.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/tty/n_gsm.c |    4 ++++
+ 1 file changed, 4 insertions(+)
+
+--- a/drivers/tty/n_gsm.c
++++ b/drivers/tty/n_gsm.c
+@@ -370,6 +370,7 @@ static const u8 gsm_fcs8[256] = {
+ #define GOOD_FCS      0xCF
+ static int gsmld_output(struct gsm_mux *gsm, u8 *data, int len);
++static int gsmtty_modem_update(struct gsm_dlci *dlci, u8 brk);
+ /**
+  *    gsm_fcs_add     -       update FCS
+@@ -1483,6 +1484,9 @@ static void gsm_dlci_open(struct gsm_dlc
+               pr_debug("DLCI %d goes open.\n", dlci->addr);
+       /* Register gsmtty driver,report gsmtty dev add uevent for user */
+       tty_register_device(gsm_tty_driver, dlci->addr, NULL);
++      /* Send current modem state */
++      if (dlci->addr)
++              gsmtty_modem_update(dlci, 0);
+       wake_up(&dlci->gsm->event);
+ }
diff --git a/queue-5.17/tty-n_gsm-fix-reset-fifo-race-condition.patch b/queue-5.17/tty-n_gsm-fix-reset-fifo-race-condition.patch
new file mode 100644 (file)
index 0000000..c27e776
--- /dev/null
@@ -0,0 +1,61 @@
+From 73029a4d7161f8b6c0934553145ef574d2d0c645 Mon Sep 17 00:00:00 2001
+From: Daniel Starke <daniel.starke@siemens.com>
+Date: Thu, 14 Apr 2022 02:42:22 -0700
+Subject: tty: n_gsm: fix reset fifo race condition
+
+From: Daniel Starke <daniel.starke@siemens.com>
+
+commit 73029a4d7161f8b6c0934553145ef574d2d0c645 upstream.
+
+gsmtty_write() and gsm_dlci_data_output() properly guard the fifo access.
+However, gsm_dlci_close() and gsmtty_flush_buffer() modifies the fifo but
+do not guard this.
+Add a guard here to prevent race conditions on parallel writes to the fifo.
+
+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-17-daniel.starke@siemens.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/tty/n_gsm.c |    8 ++++++++
+ 1 file changed, 8 insertions(+)
+
+--- a/drivers/tty/n_gsm.c
++++ b/drivers/tty/n_gsm.c
+@@ -1442,13 +1442,17 @@ static int gsm_control_wait(struct gsm_m
+ static void gsm_dlci_close(struct gsm_dlci *dlci)
+ {
++      unsigned long flags;
++
+       del_timer(&dlci->t1);
+       if (debug & 8)
+               pr_debug("DLCI %d goes closed.\n", dlci->addr);
+       dlci->state = DLCI_CLOSED;
+       if (dlci->addr != 0) {
+               tty_port_tty_hangup(&dlci->port, false);
++              spin_lock_irqsave(&dlci->lock, flags);
+               kfifo_reset(&dlci->fifo);
++              spin_unlock_irqrestore(&dlci->lock, flags);
+               /* Ensure that gsmtty_open() can return. */
+               tty_port_set_initialized(&dlci->port, 0);
+               wake_up_interruptible(&dlci->port.open_wait);
+@@ -3148,13 +3152,17 @@ static unsigned int gsmtty_chars_in_buff
+ static void gsmtty_flush_buffer(struct tty_struct *tty)
+ {
+       struct gsm_dlci *dlci = tty->driver_data;
++      unsigned long flags;
++
+       if (dlci->state == DLCI_CLOSED)
+               return;
+       /* Caution needed: If we implement reliable transport classes
+          then the data being transmitted can't simply be junked once
+          it has first hit the stack. Until then we can just blow it
+          away */
++      spin_lock_irqsave(&dlci->lock, flags);
+       kfifo_reset(&dlci->fifo);
++      spin_unlock_irqrestore(&dlci->lock, flags);
+       /* Need to unhook this DLCI from the transmit queue logic */
+ }
diff --git a/queue-5.17/tty-n_gsm-fix-software-flow-control-handling.patch b/queue-5.17/tty-n_gsm-fix-software-flow-control-handling.patch
new file mode 100644 (file)
index 0000000..a4dbd4e
--- /dev/null
@@ -0,0 +1,86 @@
+From f4f7d63287217ba25e5c80f5faae5e4f7118790e Mon Sep 17 00:00:00 2001
+From: Daniel Starke <daniel.starke@siemens.com>
+Date: Fri, 22 Apr 2022 00:10:25 -0700
+Subject: tty: n_gsm: fix software flow control handling
+
+From: Daniel Starke <daniel.starke@siemens.com>
+
+commit f4f7d63287217ba25e5c80f5faae5e4f7118790e 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.4.8.1 states that XON/XOFF characters
+shall be used instead of Fcon/Fcoff command in advanced option mode to
+handle flow control. Chapter 5.4.8.2 describes how XON/XOFF characters
+shall be handled. Basic option mode only used Fcon/Fcoff commands and no
+XON/XOFF characters. These are treated as data bytes here.
+The current implementation uses the gsm_mux field 'constipated' to handle
+flow control from the remote peer and the gsm_dlci field 'constipated' to
+handle flow control from each DLCI. The later is unrelated to this patch.
+The gsm_mux field is correctly set for Fcon/Fcoff commands in
+gsm_control_message(). However, the same is not true for XON/XOFF
+characters in gsm1_receive().
+Disable software flow control handling in the tty to allow explicit
+handling by n_gsm.
+Add the missing handling in advanced option mode for gsm_mux in
+gsm1_receive() to comply with the standard.
+
+This patch depends on the following commit:
+Commit 8838b2af23ca ("tty: n_gsm: fix SW flow control encoding/handling")
+
+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/20220422071025.5490-3-daniel.starke@siemens.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/tty/n_gsm.c |   16 ++++++++++++++++
+ 1 file changed, 16 insertions(+)
+
+--- a/drivers/tty/n_gsm.c
++++ b/drivers/tty/n_gsm.c
+@@ -232,6 +232,7 @@ struct gsm_mux {
+       int initiator;                  /* Did we initiate connection */
+       bool dead;                      /* Has the mux been shut down */
+       struct gsm_dlci *dlci[NUM_DLCI];
++      int old_c_iflag;                /* termios c_iflag value before attach */
+       bool constipated;               /* Asked by remote to shut up */
+       spinlock_t tx_lock;
+@@ -2022,6 +2023,16 @@ static void gsm0_receive(struct gsm_mux
+ static void gsm1_receive(struct gsm_mux *gsm, unsigned char c)
+ {
++      /* handle XON/XOFF */
++      if ((c & ISO_IEC_646_MASK) == XON) {
++              gsm->constipated = true;
++              return;
++      } else if ((c & ISO_IEC_646_MASK) == XOFF) {
++              gsm->constipated = false;
++              /* Kick the link in case it is idling */
++              gsm_data_kick(gsm, NULL);
++              return;
++      }
+       if (c == GSM1_SOF) {
+               /* EOF is only valid in frame if we have got to the data state */
+               if (gsm->state == GSM_DATA) {
+@@ -2449,6 +2460,9 @@ static int gsmld_attach_gsm(struct tty_s
+       int ret, i;
+       gsm->tty = tty_kref_get(tty);
++      /* Turn off tty XON/XOFF handling to handle it explicitly. */
++      gsm->old_c_iflag = tty->termios.c_iflag;
++      tty->termios.c_iflag &= (IXON | IXOFF);
+       ret =  gsm_activate_mux(gsm);
+       if (ret != 0)
+               tty_kref_put(gsm->tty);
+@@ -2489,6 +2503,8 @@ static void gsmld_detach_gsm(struct tty_
+       WARN_ON(tty != gsm->tty);
+       for (i = 1; i < NUM_DLCI; i++)
+               tty_unregister_device(gsm_tty_driver, base + i);
++      /* Restore tty XON/XOFF handling. */
++      gsm->tty->termios.c_iflag = gsm->old_c_iflag;
+       tty_kref_put(gsm->tty);
+       gsm->tty = NULL;
+ }
diff --git a/queue-5.17/tty-n_gsm-fix-wrong-command-frame-length-field-encoding.patch b/queue-5.17/tty-n_gsm-fix-wrong-command-frame-length-field-encoding.patch
new file mode 100644 (file)
index 0000000..61cdc68
--- /dev/null
@@ -0,0 +1,76 @@
+From 398867f59f956985f4c324f173eff7b946e14bd8 Mon Sep 17 00:00:00 2001
+From: Daniel Starke <daniel.starke@siemens.com>
+Date: Thu, 14 Apr 2022 02:42:17 -0700
+Subject: tty: n_gsm: fix wrong command frame length field encoding
+
+From: Daniel Starke <daniel.starke@siemens.com>
+
+commit 398867f59f956985f4c324f173eff7b946e14bd8 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.4.6.1 states that each command frame shall
+be made up from type, length and value. Looking for example in chapter
+5.4.6.3.5 at the description for the encoding of a flow control on command
+it becomes obvious, that the type and length field is always present
+whereas the value may be zero bytes long. The current implementation omits
+the length field if the value is not present. This is wrong.
+Correct this by always sending the length in gsm_control_transmit().
+So far only the modem status command (MSC) has included a value and encoded
+its length directly. Therefore, also change gsmtty_modem_update().
+
+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-12-daniel.starke@siemens.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/tty/n_gsm.c |   23 +++++++++++------------
+ 1 file changed, 11 insertions(+), 12 deletions(-)
+
+--- a/drivers/tty/n_gsm.c
++++ b/drivers/tty/n_gsm.c
+@@ -1327,11 +1327,12 @@ static void gsm_control_response(struct
+ static void gsm_control_transmit(struct gsm_mux *gsm, struct gsm_control *ctrl)
+ {
+-      struct gsm_msg *msg = gsm_data_alloc(gsm, 0, ctrl->len + 1, gsm->ftype);
++      struct gsm_msg *msg = gsm_data_alloc(gsm, 0, ctrl->len + 2, gsm->ftype);
+       if (msg == NULL)
+               return;
+-      msg->data[0] = (ctrl->cmd << 1) | 2 | EA;       /* command */
+-      memcpy(msg->data + 1, ctrl->data, ctrl->len);
++      msg->data[0] = (ctrl->cmd << 1) | CR | EA;      /* command */
++      msg->data[1] = (ctrl->len << 1) | EA;
++      memcpy(msg->data + 2, ctrl->data, ctrl->len);
+       gsm_data_queue(gsm->dlci[0], msg);
+ }
+@@ -2957,19 +2958,17 @@ static struct tty_ldisc_ops tty_ldisc_pa
+ static int gsmtty_modem_update(struct gsm_dlci *dlci, u8 brk)
+ {
+-      u8 modembits[5];
++      u8 modembits[3];
+       struct gsm_control *ctrl;
+       int len = 2;
+-      if (brk)
++      modembits[0] = (dlci->addr << 2) | 2 | EA;  /* DLCI, Valid, EA */
++      modembits[1] = (gsm_encode_modem(dlci) << 1) | EA;
++      if (brk) {
++              modembits[2] = (brk << 4) | 2 | EA; /* Length, Break, EA */
+               len++;
+-
+-      modembits[0] = len << 1 | EA;           /* Data bytes */
+-      modembits[1] = dlci->addr << 2 | 3;     /* DLCI, EA, 1 */
+-      modembits[2] = gsm_encode_modem(dlci) << 1 | EA;
+-      if (brk)
+-              modembits[3] = brk << 4 | 2 | EA;       /* Valid, EA */
+-      ctrl = gsm_control_send(dlci->gsm, CMD_MSC, modembits, len + 1);
++      }
++      ctrl = gsm_control_send(dlci->gsm, CMD_MSC, modembits, len);
+       if (ctrl == NULL)
+               return -ENOMEM;
+       return gsm_control_wait(dlci->gsm, ctrl);
diff --git a/queue-5.17/tty-n_gsm-fix-wrong-command-retry-handling.patch b/queue-5.17/tty-n_gsm-fix-wrong-command-retry-handling.patch
new file mode 100644 (file)
index 0000000..a151e10
--- /dev/null
@@ -0,0 +1,66 @@
+From d0bcdffcad5a22f202e3bf37190c0dd8c080ea92 Mon Sep 17 00:00:00 2001
+From: Daniel Starke <daniel.starke@siemens.com>
+Date: Thu, 14 Apr 2022 02:42:16 -0700
+Subject: tty: n_gsm: fix wrong command retry handling
+
+From: Daniel Starke <daniel.starke@siemens.com>
+
+commit d0bcdffcad5a22f202e3bf37190c0dd8c080ea92 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.7.3 states that the valid range for the
+maximum number of retransmissions (N2) is from 0 to 255 (both including).
+gsm_config() fails to limit this range correctly. Furthermore,
+gsm_control_retransmit() handles this number incorrectly by performing
+N2 - 1 retransmission attempts. Setting N2 to zero results in more than 255
+retransmission attempts.
+Fix the range check in gsm_config() and the value handling in
+gsm_control_send() and gsm_control_retransmit() to comply with 3GPP 27.010.
+
+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-11-daniel.starke@siemens.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/tty/n_gsm.c |    6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+--- a/drivers/tty/n_gsm.c
++++ b/drivers/tty/n_gsm.c
+@@ -1354,7 +1354,6 @@ static void gsm_control_retransmit(struc
+       spin_lock_irqsave(&gsm->control_lock, flags);
+       ctrl = gsm->pending_cmd;
+       if (ctrl) {
+-              gsm->cretries--;
+               if (gsm->cretries == 0) {
+                       gsm->pending_cmd = NULL;
+                       ctrl->error = -ETIMEDOUT;
+@@ -1363,6 +1362,7 @@ static void gsm_control_retransmit(struc
+                       wake_up(&gsm->event);
+                       return;
+               }
++              gsm->cretries--;
+               gsm_control_transmit(gsm, ctrl);
+               mod_timer(&gsm->t2_timer, jiffies + gsm->t2 * HZ / 100);
+       }
+@@ -1403,7 +1403,7 @@ retry:
+       /* If DLCI0 is in ADM mode skip retries, it won't respond */
+       if (gsm->dlci[0]->mode == DLCI_MODE_ADM)
+-              gsm->cretries = 1;
++              gsm->cretries = 0;
+       else
+               gsm->cretries = gsm->n2;
+@@ -2343,7 +2343,7 @@ static int gsm_config(struct gsm_mux *gs
+       /* Check the MRU/MTU range looks sane */
+       if (c->mru > MAX_MRU || c->mtu > MAX_MTU || c->mru < 8 || c->mtu < 8)
+               return -EINVAL;
+-      if (c->n2 < 3)
++      if (c->n2 > 255)
+               return -EINVAL;
+       if (c->encapsulation > 1)       /* Basic, advanced, no I */
+               return -EINVAL;
diff --git a/queue-5.17/tty-n_gsm-fix-wrong-dlci-release-order.patch b/queue-5.17/tty-n_gsm-fix-wrong-dlci-release-order.patch
new file mode 100644 (file)
index 0000000..d350bde
--- /dev/null
@@ -0,0 +1,35 @@
+From deefc58bafb4841df7f0a0d85d89a1c819db9743 Mon Sep 17 00:00:00 2001
+From: Daniel Starke <daniel.starke@siemens.com>
+Date: Thu, 14 Apr 2022 02:42:14 -0700
+Subject: tty: n_gsm: fix wrong DLCI release order
+
+From: Daniel Starke <daniel.starke@siemens.com>
+
+commit deefc58bafb4841df7f0a0d85d89a1c819db9743 upstream.
+
+The current DLCI release order starts with the control channel followed by
+the user channels. Reverse this order to keep the control channel open
+until all user channels have been released.
+
+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-9-daniel.starke@siemens.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/tty/n_gsm.c |    4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+--- a/drivers/tty/n_gsm.c
++++ b/drivers/tty/n_gsm.c
+@@ -2146,8 +2146,8 @@ static void gsm_cleanup_mux(struct gsm_m
+       /* Finish outstanding timers, making sure they are done */
+       del_timer_sync(&gsm->t2_timer);
+-      /* Free up any link layer users */
+-      for (i = 0; i < NUM_DLCI; i++)
++      /* Free up any link layer users and finally the control channel */
++      for (i = NUM_DLCI - 1; i >= 0; i--)
+               if (gsm->dlci[i])
+                       gsm_dlci_release(gsm->dlci[i]);
+       mutex_unlock(&gsm->mutex);
diff --git a/queue-5.17/tty-n_gsm-fix-wrong-signal-octets-encoding-in-msc.patch b/queue-5.17/tty-n_gsm-fix-wrong-signal-octets-encoding-in-msc.patch
new file mode 100644 (file)
index 0000000..7e3a910
--- /dev/null
@@ -0,0 +1,82 @@
+From 317f86af7f5d19f286ed2d181cbaef4a188c7f19 Mon Sep 17 00:00:00 2001
+From: Daniel Starke <daniel.starke@siemens.com>
+Date: Thu, 14 Apr 2022 02:42:18 -0700
+Subject: tty: n_gsm: fix wrong signal octets encoding in MSC
+
+From: Daniel Starke <daniel.starke@siemens.com>
+
+commit 317f86af7f5d19f286ed2d181cbaef4a188c7f19 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. The value of the modem status command (MSC) frame
+contains an address field, control signal and optional break signal octet.
+The address field is encoded as described in chapter 5.2.1.2 with only one
+octet (may be extended to more in future versions of the standard). Whereas
+the control signal and break signal octet are always one byte each. This is
+strange at first glance as it makes the EA bit redundant. However, the same
+two octets are also encoded as header in convergence layer type 2 as
+described in chapter 5.5.2. No header length field is given and the only
+way to test if there is an optional break signal octet is via the EA flag
+which extends the control signal octet with a break signal octet. Now it
+becomes obvious how the EA bit for those two octets shall be encoded in the
+MSC frame. The current implementation treats the signal octet different for
+MSC frame and convergence layer type 2 header even though the standard
+describes it for both in the same way.
+Use the EA bit to encode the signal octets not only in the convergence
+layer type 2 header but also in the MSC frame in the same way with either
+1 or 2 bytes in case of an optional break signal. Adjust the receiving path
+accordingly in gsm_control_modem().
+
+Fixes: 3ac06b905655 ("tty: n_gsm: Fix for modems with brk in modem status control")
+Cc: stable@vger.kernel.org
+Signed-off-by: Daniel Starke <daniel.starke@siemens.com>
+Link: https://lore.kernel.org/r/20220414094225.4527-13-daniel.starke@siemens.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/tty/n_gsm.c |   18 +++++-------------
+ 1 file changed, 5 insertions(+), 13 deletions(-)
+
+--- a/drivers/tty/n_gsm.c
++++ b/drivers/tty/n_gsm.c
+@@ -1094,7 +1094,6 @@ static void gsm_control_modem(struct gsm
+ {
+       unsigned int addr = 0;
+       unsigned int modem = 0;
+-      unsigned int brk = 0;
+       struct gsm_dlci *dlci;
+       int len = clen;
+       int slen;
+@@ -1124,17 +1123,8 @@ static void gsm_control_modem(struct gsm
+                       return;
+       }
+       len--;
+-      if (len > 0) {
+-              while (gsm_read_ea(&brk, *dp++) == 0) {
+-                      len--;
+-                      if (len == 0)
+-                              return;
+-              }
+-              modem <<= 7;
+-              modem |= (brk & 0x7f);
+-      }
+       tty = tty_port_tty_get(&dlci->port);
+-      gsm_process_modem(tty, dlci, modem, slen);
++      gsm_process_modem(tty, dlci, modem, slen - len);
+       if (tty) {
+               tty_wakeup(tty);
+               tty_kref_put(tty);
+@@ -2963,8 +2953,10 @@ static int gsmtty_modem_update(struct gs
+       int len = 2;
+       modembits[0] = (dlci->addr << 2) | 2 | EA;  /* DLCI, Valid, EA */
+-      modembits[1] = (gsm_encode_modem(dlci) << 1) | EA;
+-      if (brk) {
++      if (!brk) {
++              modembits[1] = (gsm_encode_modem(dlci) << 1) | EA;
++      } else {
++              modembits[1] = gsm_encode_modem(dlci) << 1;
+               modembits[2] = (brk << 4) | 2 | EA; /* Length, Break, EA */
+               len++;
+       }