Commit 687f9ad4 authored by daniel.starke@siemens.com's avatar daniel.starke@siemens.com Committed by Greg Kroah-Hartman
Browse files

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: 7263287a ("tty: n_gsm: Fixed logic to decode break signal from modem status")
Cc: stable@vger.kernel.org
Signed-off-by: default avatarDaniel Starke <daniel.starke@siemens.com>
Link: https://lore.kernel.org/r/20220218073123.2121-6-daniel.starke@siemens.com


Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent c19d9354
Loading
Loading
Loading
Loading
+14 −9
Original line number Diff line number Diff line
@@ -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;