summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authordaniel.starke@siemens.com <daniel.starke@siemens.com>2022-02-17 23:31:22 -0800
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2022-02-21 19:51:04 +0100
commit687f9ad43c52501f46164758e908a5dd181a87fc (patch)
treebda22305006ff19bd9a8bcc6ddc859529a809013
parentc19d93542a6081577e6da9bf5e887979c72e80c1 (diff)
downloadlinux-687f9ad43c52501f46164758e908a5dd181a87fc.tar.gz
linux-687f9ad43c52501f46164758e908a5dd181a87fc.tar.bz2
linux-687f9ad43c52501f46164758e908a5dd181a87fc.zip
tty: n_gsm: fix wrong modem processing in convergence layer type 2
The function gsm_process_modem() exists to handle modem status bits of incoming frames. This includes incoming MSC (modem status command) frames and convergence layer type 2 data frames. The function, however, was only designed to handle MSC frames as it expects the command length. Within gsm_dlci_data() it is wrongly assumed that this is the same as the data frame length. This is only true if the data frame contains only 1 byte of payload. This patch names the length parameter of gsm_process_modem() in a generic manner to reflect its association. It also corrects all calls to the function to handle the variable number of modem status octets correctly in both cases. Fixes: 7263287af93d ("tty: n_gsm: Fixed logic to decode break signal from modem status") Cc: stable@vger.kernel.org Signed-off-by: Daniel Starke <daniel.starke@siemens.com> Link: https://lore.kernel.org/r/20220218073123.2121-6-daniel.starke@siemens.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r--drivers/tty/n_gsm.c23
1 files changed, 14 insertions, 9 deletions
diff --git a/drivers/tty/n_gsm.c b/drivers/tty/n_gsm.c
index b4ddac0124b9..8ff5c0c61233 100644
--- a/drivers/tty/n_gsm.c
+++ b/drivers/tty/n_gsm.c
@@ -1021,25 +1021,25 @@ static void gsm_control_reply(struct gsm_mux *gsm, int cmd, const u8 *data,
* @tty: virtual tty bound to the DLCI
* @dlci: DLCI to affect
* @modem: modem bits (full EA)
- * @clen: command length
+ * @slen: number of signal octets
*
* Used when a modem control message or line state inline in adaption
* layer 2 is processed. Sort out the local modem state and throttles
*/
static void gsm_process_modem(struct tty_struct *tty, struct gsm_dlci *dlci,
- u32 modem, int clen)
+ u32 modem, int slen)
{
int mlines = 0;
u8 brk = 0;
int fc;
- /* The modem status command can either contain one octet (v.24 signals)
- or two octets (v.24 signals + break signals). The length field will
- either be 2 or 3 respectively. This is specified in section
- 5.4.6.3.7 of the 27.010 mux spec. */
+ /* The modem status command can either contain one octet (V.24 signals)
+ * or two octets (V.24 signals + break signals). This is specified in
+ * section 5.4.6.3.7 of the 07.10 mux spec.
+ */
- if (clen == 2)
+ if (slen == 1)
modem = modem & 0x7f;
else {
brk = modem & 0x7f;
@@ -1096,6 +1096,7 @@ static void gsm_control_modem(struct gsm_mux *gsm, const u8 *data, int clen)
unsigned int brk = 0;
struct gsm_dlci *dlci;
int len = clen;
+ int slen;
const u8 *dp = data;
struct tty_struct *tty;
@@ -1115,6 +1116,7 @@ static void gsm_control_modem(struct gsm_mux *gsm, const u8 *data, int clen)
return;
dlci = gsm->dlci[addr];
+ slen = len;
while (gsm_read_ea(&modem, *dp++) == 0) {
len--;
if (len == 0)
@@ -1131,7 +1133,7 @@ static void gsm_control_modem(struct gsm_mux *gsm, const u8 *data, int clen)
modem |= (brk & 0x7f);
}
tty = tty_port_tty_get(&dlci->port);
- gsm_process_modem(tty, dlci, modem, clen);
+ gsm_process_modem(tty, dlci, modem, slen);
if (tty) {
tty_wakeup(tty);
tty_kref_put(tty);
@@ -1597,6 +1599,7 @@ static void gsm_dlci_data(struct gsm_dlci *dlci, const u8 *data, int clen)
struct tty_struct *tty;
unsigned int modem = 0;
int len = clen;
+ int slen = 0;
if (debug & 16)
pr_debug("%d bytes for tty\n", len);
@@ -1609,12 +1612,14 @@ static void gsm_dlci_data(struct gsm_dlci *dlci, const u8 *data, int clen)
case 2: /* Asynchronous serial with line state in each frame */
while (gsm_read_ea(&modem, *data++) == 0) {
len--;
+ slen++;
if (len == 0)
return;
}
+ slen++;
tty = tty_port_tty_get(port);
if (tty) {
- gsm_process_modem(tty, dlci, modem, clen);
+ gsm_process_modem(tty, dlci, modem, slen);
tty_kref_put(tty);
}
fallthrough;