From: Greg Kroah-Hartman Date: Tue, 3 May 2022 13:43:23 +0000 (+0200) Subject: 5.17-stable patches X-Git-Tag: v5.4.192~11 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=71c5ce75aa6fe5b7ce045114a2172d6af36564ab;p=thirdparty%2Fkernel%2Fstable-queue.git 5.17-stable patches 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 --- diff --git a/queue-5.17/series b/queue-5.17/series index b9fa15710f0..cc1aa299a79 100644 --- a/queue-5.17/series +++ b/queue-5.17/series @@ -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 index 00000000000..2929e156eb1 --- /dev/null +++ b/queue-5.17/tty-n_gsm-fix-broken-virtual-tty-handling.patch @@ -0,0 +1,219 @@ +From a8c5b8255f8a9acd58a4b15ff1c14cd6effd114b Mon Sep 17 00:00:00 2001 +From: Daniel Starke +Date: Fri, 22 Apr 2022 00:10:23 -0700 +Subject: tty: n_gsm: fix broken virtual tty handling + +From: Daniel Starke + +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 +Link: https://lore.kernel.org/r/20220422071025.5490-1-daniel.starke@siemens.com +Signed-off-by: Greg Kroah-Hartman +--- + 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 index 00000000000..3e341d2c687 --- /dev/null +++ b/queue-5.17/tty-n_gsm-fix-incorrect-ua-handling.patch @@ -0,0 +1,38 @@ +From ff9166c623704337bd6fe66fce2838d9768a6634 Mon Sep 17 00:00:00 2001 +From: Daniel Starke +Date: Thu, 14 Apr 2022 02:42:25 -0700 +Subject: tty: n_gsm: fix incorrect UA handling + +From: Daniel Starke + +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 +Link: https://lore.kernel.org/r/20220414094225.4527-20-daniel.starke@siemens.com +Signed-off-by: Greg Kroah-Hartman +--- + 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 index 00000000000..767055ec001 --- /dev/null +++ b/queue-5.17/tty-n_gsm-fix-insufficient-txframe-size.patch @@ -0,0 +1,52 @@ +From 535bf600de75a859698892ee873521a48d289ec1 Mon Sep 17 00:00:00 2001 +From: Daniel Starke +Date: Thu, 14 Apr 2022 02:42:13 -0700 +Subject: tty: n_gsm: fix insufficient txframe size + +From: Daniel Starke + +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 +Link: https://lore.kernel.org/r/20220414094225.4527-8-daniel.starke@siemens.com +Signed-off-by: Greg Kroah-Hartman +--- + 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 index 00000000000..c7d11eadf25 --- /dev/null +++ b/queue-5.17/tty-n_gsm-fix-invalid-use-of-msc-in-advanced-option.patch @@ -0,0 +1,238 @@ +From c19ffe00fed6bb423d81406d2a7e5793074c7d83 Mon Sep 17 00:00:00 2001 +From: Daniel Starke +Date: Fri, 22 Apr 2022 00:10:24 -0700 +Subject: tty: n_gsm: fix invalid use of MSC in advanced option + +From: Daniel Starke + +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 +Link: https://lore.kernel.org/r/20220422071025.5490-2-daniel.starke@siemens.com +Signed-off-by: Greg Kroah-Hartman +--- + 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 index 00000000000..52825a09b0c --- /dev/null +++ b/queue-5.17/tty-n_gsm-fix-missing-explicit-ldisc-flush.patch @@ -0,0 +1,35 @@ +From 17eac652028501df7ea296b1d9b9c134db262b7d Mon Sep 17 00:00:00 2001 +From: Daniel Starke +Date: Thu, 14 Apr 2022 02:42:15 -0700 +Subject: tty: n_gsm: fix missing explicit ldisc flush + +From: Daniel Starke + +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 +Link: https://lore.kernel.org/r/20220414094225.4527-10-daniel.starke@siemens.com +Signed-off-by: Greg Kroah-Hartman +--- + 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 index 00000000000..27f264cd688 --- /dev/null +++ b/queue-5.17/tty-n_gsm-fix-missing-tty-wakeup-in-convergence-layer-type-2.patch @@ -0,0 +1,35 @@ +From 1adf6fee58ca25fb6720b8d34c919dcf5425cc9c Mon Sep 17 00:00:00 2001 +From: Daniel Starke +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 + +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 +Link: https://lore.kernel.org/r/20220414094225.4527-14-daniel.starke@siemens.com +Signed-off-by: Greg Kroah-Hartman +--- + 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 index 00000000000..dac9681078a --- /dev/null +++ b/queue-5.17/tty-n_gsm-fix-missing-update-of-modem-controls-after-dlci-open.patch @@ -0,0 +1,42 @@ +From 48473802506d2d6151f59e0e764932b33b53cb3b Mon Sep 17 00:00:00 2001 +From: Daniel Starke +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 + +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 +Link: https://lore.kernel.org/r/20220420101346.3315-1-daniel.starke@siemens.com +Signed-off-by: Greg Kroah-Hartman +--- + 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 index 00000000000..c27e7768852 --- /dev/null +++ b/queue-5.17/tty-n_gsm-fix-reset-fifo-race-condition.patch @@ -0,0 +1,61 @@ +From 73029a4d7161f8b6c0934553145ef574d2d0c645 Mon Sep 17 00:00:00 2001 +From: Daniel Starke +Date: Thu, 14 Apr 2022 02:42:22 -0700 +Subject: tty: n_gsm: fix reset fifo race condition + +From: Daniel Starke + +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 +Link: https://lore.kernel.org/r/20220414094225.4527-17-daniel.starke@siemens.com +Signed-off-by: Greg Kroah-Hartman +--- + 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 index 00000000000..a4dbd4e41fa --- /dev/null +++ b/queue-5.17/tty-n_gsm-fix-software-flow-control-handling.patch @@ -0,0 +1,86 @@ +From f4f7d63287217ba25e5c80f5faae5e4f7118790e Mon Sep 17 00:00:00 2001 +From: Daniel Starke +Date: Fri, 22 Apr 2022 00:10:25 -0700 +Subject: tty: n_gsm: fix software flow control handling + +From: Daniel Starke + +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 +Link: https://lore.kernel.org/r/20220422071025.5490-3-daniel.starke@siemens.com +Signed-off-by: Greg Kroah-Hartman +--- + 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 index 00000000000..61cdc6830b4 --- /dev/null +++ b/queue-5.17/tty-n_gsm-fix-wrong-command-frame-length-field-encoding.patch @@ -0,0 +1,76 @@ +From 398867f59f956985f4c324f173eff7b946e14bd8 Mon Sep 17 00:00:00 2001 +From: Daniel Starke +Date: Thu, 14 Apr 2022 02:42:17 -0700 +Subject: tty: n_gsm: fix wrong command frame length field encoding + +From: Daniel Starke + +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 +Link: https://lore.kernel.org/r/20220414094225.4527-12-daniel.starke@siemens.com +Signed-off-by: Greg Kroah-Hartman +--- + 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 index 00000000000..a151e107d22 --- /dev/null +++ b/queue-5.17/tty-n_gsm-fix-wrong-command-retry-handling.patch @@ -0,0 +1,66 @@ +From d0bcdffcad5a22f202e3bf37190c0dd8c080ea92 Mon Sep 17 00:00:00 2001 +From: Daniel Starke +Date: Thu, 14 Apr 2022 02:42:16 -0700 +Subject: tty: n_gsm: fix wrong command retry handling + +From: Daniel Starke + +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 +Link: https://lore.kernel.org/r/20220414094225.4527-11-daniel.starke@siemens.com +Signed-off-by: Greg Kroah-Hartman +--- + 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 index 00000000000..d350bdee346 --- /dev/null +++ b/queue-5.17/tty-n_gsm-fix-wrong-dlci-release-order.patch @@ -0,0 +1,35 @@ +From deefc58bafb4841df7f0a0d85d89a1c819db9743 Mon Sep 17 00:00:00 2001 +From: Daniel Starke +Date: Thu, 14 Apr 2022 02:42:14 -0700 +Subject: tty: n_gsm: fix wrong DLCI release order + +From: Daniel Starke + +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 +Link: https://lore.kernel.org/r/20220414094225.4527-9-daniel.starke@siemens.com +Signed-off-by: Greg Kroah-Hartman +--- + 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 index 00000000000..7e3a9107b76 --- /dev/null +++ b/queue-5.17/tty-n_gsm-fix-wrong-signal-octets-encoding-in-msc.patch @@ -0,0 +1,82 @@ +From 317f86af7f5d19f286ed2d181cbaef4a188c7f19 Mon Sep 17 00:00:00 2001 +From: Daniel Starke +Date: Thu, 14 Apr 2022 02:42:18 -0700 +Subject: tty: n_gsm: fix wrong signal octets encoding in MSC + +From: Daniel Starke + +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 +Link: https://lore.kernel.org/r/20220414094225.4527-13-daniel.starke@siemens.com +Signed-off-by: Greg Kroah-Hartman +--- + 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++; + }