From: Greg Kroah-Hartman Date: Mon, 2 May 2022 23:14:17 +0000 (+0200) Subject: 5.17-stable patches X-Git-Tag: v5.4.192~30 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=38ac529c343896032a20b6293ae23faf01ecaaf7;p=thirdparty%2Fkernel%2Fstable-queue.git 5.17-stable patches added patches: tty-n_gsm-fix-decoupled-mux-resource.patch tty-n_gsm-fix-missing-mux-reset-on-config-change-at-responder.patch tty-n_gsm-fix-restart-handling-via-cld-command.patch --- diff --git a/queue-5.17/series b/queue-5.17/series index 19d7dee2567..eae275a4cf7 100644 --- a/queue-5.17/series +++ b/queue-5.17/series @@ -198,3 +198,6 @@ arm-dts-imx8mm-venice-gw-71xx-72xx-73xx-fix-otg-controller-oc-mode.patch perf-symbol-pass-is_kallsyms-to-symbols__fixup_end.patch perf-symbol-update-symbols__fixup_end.patch perf-symbol-remove-arch__symbols__fixup_end.patch +tty-n_gsm-fix-missing-mux-reset-on-config-change-at-responder.patch +tty-n_gsm-fix-restart-handling-via-cld-command.patch +tty-n_gsm-fix-decoupled-mux-resource.patch diff --git a/queue-5.17/tty-n_gsm-fix-decoupled-mux-resource.patch b/queue-5.17/tty-n_gsm-fix-decoupled-mux-resource.patch new file mode 100644 index 00000000000..a9d0f9681d8 --- /dev/null +++ b/queue-5.17/tty-n_gsm-fix-decoupled-mux-resource.patch @@ -0,0 +1,148 @@ +From 1ec92e9742774bf42614fceea3bf6b50c9409225 Mon Sep 17 00:00:00 2001 +From: Daniel Starke +Date: Thu, 14 Apr 2022 02:42:08 -0700 +Subject: tty: n_gsm: fix decoupled mux resource + +From: Daniel Starke + +commit 1ec92e9742774bf42614fceea3bf6b50c9409225 upstream. + +The active mux instances are managed in the gsm_mux array and via mux_get() +and mux_put() functions separately. This gives a very loose coupling +between the actual instance and the gsm_mux array which manages it. It also +results in unnecessary lockings which makes it prone to failures. And it +creates a race condition if more than the maximum number of mux instances +are requested while the user changes the parameters of an active instance. +The user may loose ownership of the current mux instance in this case. +Fix this by moving the gsm_mux array handling to the mux allocation and +deallocation functions. + +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-3-daniel.starke@siemens.com +Signed-off-by: Greg Kroah-Hartman +--- + drivers/tty/n_gsm.c | 63 +++++++++++++++++++++++++++++++--------------------- + 1 file changed, 38 insertions(+), 25 deletions(-) + +--- a/drivers/tty/n_gsm.c ++++ b/drivers/tty/n_gsm.c +@@ -2136,18 +2136,6 @@ static void gsm_cleanup_mux(struct gsm_m + /* Finish outstanding timers, making sure they are done */ + del_timer_sync(&gsm->t2_timer); + +- spin_lock(&gsm_mux_lock); +- for (i = 0; i < MAX_MUX; i++) { +- if (gsm_mux[i] == gsm) { +- gsm_mux[i] = NULL; +- break; +- } +- } +- spin_unlock(&gsm_mux_lock); +- /* open failed before registering => nothing to do */ +- if (i == MAX_MUX) +- return; +- + /* Free up any link layer users */ + for (i = 0; i < NUM_DLCI; i++) + if (gsm->dlci[i]) +@@ -2171,7 +2159,6 @@ static void gsm_cleanup_mux(struct gsm_m + static int gsm_activate_mux(struct gsm_mux *gsm) + { + struct gsm_dlci *dlci; +- int i = 0; + + timer_setup(&gsm->t2_timer, gsm_control_retransmit, 0); + init_waitqueue_head(&gsm->event); +@@ -2183,18 +2170,6 @@ static int gsm_activate_mux(struct gsm_m + else + gsm->receive = gsm1_receive; + +- spin_lock(&gsm_mux_lock); +- for (i = 0; i < MAX_MUX; i++) { +- if (gsm_mux[i] == NULL) { +- gsm->num = i; +- gsm_mux[i] = gsm; +- break; +- } +- } +- spin_unlock(&gsm_mux_lock); +- if (i == MAX_MUX) +- return -EBUSY; +- + dlci = gsm_dlci_alloc(gsm, 0); + if (dlci == NULL) + return -ENOMEM; +@@ -2210,6 +2185,15 @@ static int gsm_activate_mux(struct gsm_m + */ + static void gsm_free_mux(struct gsm_mux *gsm) + { ++ int i; ++ ++ for (i = 0; i < MAX_MUX; i++) { ++ if (gsm == gsm_mux[i]) { ++ gsm_mux[i] = NULL; ++ break; ++ } ++ } ++ mutex_destroy(&gsm->mutex); + kfree(gsm->txframe); + kfree(gsm->buf); + kfree(gsm); +@@ -2229,12 +2213,20 @@ static void gsm_free_muxr(struct kref *r + + static inline void mux_get(struct gsm_mux *gsm) + { ++ unsigned long flags; ++ ++ spin_lock_irqsave(&gsm_mux_lock, flags); + kref_get(&gsm->ref); ++ spin_unlock_irqrestore(&gsm_mux_lock, flags); + } + + static inline void mux_put(struct gsm_mux *gsm) + { ++ unsigned long flags; ++ ++ spin_lock_irqsave(&gsm_mux_lock, flags); + kref_put(&gsm->ref, gsm_free_muxr); ++ spin_unlock_irqrestore(&gsm_mux_lock, flags); + } + + static inline unsigned int mux_num_to_base(struct gsm_mux *gsm) +@@ -2255,6 +2247,7 @@ static inline unsigned int mux_line_to_n + + static struct gsm_mux *gsm_alloc_mux(void) + { ++ int i; + struct gsm_mux *gsm = kzalloc(sizeof(struct gsm_mux), GFP_KERNEL); + if (gsm == NULL) + return NULL; +@@ -2284,6 +2277,26 @@ static struct gsm_mux *gsm_alloc_mux(voi + gsm->mtu = 64; + gsm->dead = true; /* Avoid early tty opens */ + ++ /* Store the instance to the mux array or abort if no space is ++ * available. ++ */ ++ spin_lock(&gsm_mux_lock); ++ for (i = 0; i < MAX_MUX; i++) { ++ if (!gsm_mux[i]) { ++ gsm_mux[i] = gsm; ++ gsm->num = i; ++ break; ++ } ++ } ++ spin_unlock(&gsm_mux_lock); ++ if (i == MAX_MUX) { ++ mutex_destroy(&gsm->mutex); ++ kfree(gsm->txframe); ++ kfree(gsm->buf); ++ kfree(gsm); ++ return NULL; ++ } ++ + return gsm; + } + diff --git a/queue-5.17/tty-n_gsm-fix-missing-mux-reset-on-config-change-at-responder.patch b/queue-5.17/tty-n_gsm-fix-missing-mux-reset-on-config-change-at-responder.patch new file mode 100644 index 00000000000..f5ee67a3826 --- /dev/null +++ b/queue-5.17/tty-n_gsm-fix-missing-mux-reset-on-config-change-at-responder.patch @@ -0,0 +1,38 @@ +From 11451693e4081d32ef65147c6ca08cd0094ae252 Mon Sep 17 00:00:00 2001 +From: Daniel Starke +Date: Thu, 14 Apr 2022 02:42:06 -0700 +Subject: tty: n_gsm: fix missing mux reset on config change at responder + +From: Daniel Starke + +commit 11451693e4081d32ef65147c6ca08cd0094ae252 upstream. + +Currently, only the initiator resets the mux protocol if the user requests +new parameters that are incompatible to those of the current connection. +The responder also needs to reset the multiplexer if the new parameter set +requires this. Otherwise, we end up with an inconsistent parameter set +between initiator and responder. +Revert the old behavior to inform the peer upon an incompatible parameter +set change from the user on the responder side by re-establishing the mux +protocol in such case. + +Fixes: 509067bbd264 ("tty: n_gsm: Delete gsm_disconnect when config requester") +Cc: stable@vger.kernel.org +Signed-off-by: Daniel Starke +Link: https://lore.kernel.org/r/20220414094225.4527-1-daniel.starke@siemens.com +Signed-off-by: Greg Kroah-Hartman +--- + drivers/tty/n_gsm.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/tty/n_gsm.c ++++ b/drivers/tty/n_gsm.c +@@ -2373,7 +2373,7 @@ static int gsm_config(struct gsm_mux *gs + * configuration + */ + +- if (gsm->initiator && (need_close || need_restart)) { ++ if (need_close || need_restart) { + int ret; + + ret = gsm_disconnect(gsm); diff --git a/queue-5.17/tty-n_gsm-fix-restart-handling-via-cld-command.patch b/queue-5.17/tty-n_gsm-fix-restart-handling-via-cld-command.patch new file mode 100644 index 00000000000..f2b0c8cb3a1 --- /dev/null +++ b/queue-5.17/tty-n_gsm-fix-restart-handling-via-cld-command.patch @@ -0,0 +1,165 @@ +From aa371e96f05dcb36a88298f5cb70aa7234d5e8b8 Mon Sep 17 00:00:00 2001 +From: Daniel Starke +Date: Thu, 14 Apr 2022 02:42:07 -0700 +Subject: tty: n_gsm: fix restart handling via CLD command + +From: Daniel Starke + +commit aa371e96f05dcb36a88298f5cb70aa7234d5e8b8 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.8.2 states that both sides will revert to +the non-multiplexed mode via a close-down message (CLD). The usual program +flow is as following: +- start multiplex mode by sending AT+CMUX to the mobile +- establish the control channel (DLCI 0) +- establish user channels (DLCI >0) +- terminate user channels +- send close-down message (CLD) +- revert to AT protocol (i.e. leave multiplexed mode) + +The AT protocol is out of scope of the n_gsm driver. However, +gsm_disconnect() sends CLD if gsm_config() detects that the requested +parameters require the mux protocol to restart. The next immediate action +is to start the mux protocol by opening DLCI 0 again. Any responder side +which handles CLD commands correctly forces us to fail at this point +because AT+CMUX needs to be sent to the mobile to start the mux again. +Therefore, remove the CLD command in this phase and keep both sides in +multiplexed mode. +Remove the gsm_disconnect() function as it become unnecessary and merge the +remaining parts into gsm_cleanup_mux() to handle the termination order and +locking correctly. + +Fixes: 71e077915396 ("tty: n_gsm: do not send/receive in ldisc close path") +Cc: stable@vger.kernel.org +Signed-off-by: Daniel Starke +Link: https://lore.kernel.org/r/20220414094225.4527-2-daniel.starke@siemens.com +Signed-off-by: Greg Kroah-Hartman +--- + drivers/tty/n_gsm.c | 68 +++++++++++++++------------------------------------- + 1 file changed, 20 insertions(+), 48 deletions(-) + +--- a/drivers/tty/n_gsm.c ++++ b/drivers/tty/n_gsm.c +@@ -2106,49 +2106,35 @@ static void gsm_error(struct gsm_mux *gs + gsm->io_error++; + } + +-static int gsm_disconnect(struct gsm_mux *gsm) +-{ +- struct gsm_dlci *dlci = gsm->dlci[0]; +- struct gsm_control *gc; +- +- if (!dlci) +- return 0; +- +- /* In theory disconnecting DLCI 0 is sufficient but for some +- modems this is apparently not the case. */ +- gc = gsm_control_send(gsm, CMD_CLD, NULL, 0); +- if (gc) +- gsm_control_wait(gsm, gc); +- +- del_timer_sync(&gsm->t2_timer); +- /* Now we are sure T2 has stopped */ +- +- gsm_dlci_begin_close(dlci); +- wait_event_interruptible(gsm->event, +- dlci->state == DLCI_CLOSED); +- +- if (signal_pending(current)) +- return -EINTR; +- +- return 0; +-} +- + /** + * gsm_cleanup_mux - generic GSM protocol cleanup + * @gsm: our mux ++ * @disc: disconnect link? + * + * Clean up the bits of the mux which are the same for all framing + * protocols. Remove the mux from the mux table, stop all the timers + * and then shut down each device hanging up the channels as we go. + */ + +-static void gsm_cleanup_mux(struct gsm_mux *gsm) ++static void gsm_cleanup_mux(struct gsm_mux *gsm, bool disc) + { + int i; + struct gsm_dlci *dlci = gsm->dlci[0]; + struct gsm_msg *txq, *ntxq; + + gsm->dead = true; ++ mutex_lock(&gsm->mutex); ++ ++ if (dlci) { ++ if (disc && dlci->state != DLCI_CLOSED) { ++ gsm_dlci_begin_close(dlci); ++ wait_event(gsm->event, dlci->state == DLCI_CLOSED); ++ } ++ dlci->dead = true; ++ } ++ ++ /* Finish outstanding timers, making sure they are done */ ++ del_timer_sync(&gsm->t2_timer); + + spin_lock(&gsm_mux_lock); + for (i = 0; i < MAX_MUX; i++) { +@@ -2162,13 +2148,7 @@ static void gsm_cleanup_mux(struct gsm_m + if (i == MAX_MUX) + return; + +- del_timer_sync(&gsm->t2_timer); +- /* Now we are sure T2 has stopped */ +- if (dlci) +- dlci->dead = true; +- + /* Free up any link layer users */ +- mutex_lock(&gsm->mutex); + for (i = 0; i < NUM_DLCI; i++) + if (gsm->dlci[i]) + gsm_dlci_release(gsm->dlci[i]); +@@ -2370,19 +2350,11 @@ static int gsm_config(struct gsm_mux *gs + + /* + * Close down what is needed, restart and initiate the new +- * configuration ++ * configuration. On the first time there is no DLCI[0] ++ * and closing or cleaning up is not necessary. + */ +- +- if (need_close || need_restart) { +- int ret; +- +- ret = gsm_disconnect(gsm); +- +- if (ret) +- return ret; +- } +- if (need_restart) +- gsm_cleanup_mux(gsm); ++ if (need_close || need_restart) ++ gsm_cleanup_mux(gsm, true); + + gsm->initiator = c->initiator; + gsm->mru = c->mru; +@@ -2494,7 +2466,7 @@ static void gsmld_detach_gsm(struct tty_ + for (i = 1; i < NUM_DLCI; i++) + tty_unregister_device(gsm_tty_driver, base + i); + } +- gsm_cleanup_mux(gsm); ++ gsm_cleanup_mux(gsm, false); + tty_kref_put(gsm->tty); + gsm->tty = NULL; + } +@@ -2597,7 +2569,7 @@ static int gsmld_open(struct tty_struct + + ret = gsmld_attach_gsm(tty, gsm); + if (ret != 0) { +- gsm_cleanup_mux(gsm); ++ gsm_cleanup_mux(gsm, false); + mux_put(gsm); + } + return ret;