]> git.proxmox.com Git - mirror_ubuntu-jammy-kernel.git/commitdiff
tty: n_gsm: fix wrong command frame length field encoding
authorDaniel Starke <daniel.starke@siemens.com>
Thu, 14 Apr 2022 09:42:17 +0000 (02:42 -0700)
committerStefan Bader <stefan.bader@canonical.com>
Wed, 22 Jun 2022 12:23:05 +0000 (14:23 +0200)
BugLink: https://bugs.launchpad.net/bugs/1978234
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>
Signed-off-by: Kamal Mostafa <kamal@canonical.com>
Signed-off-by: Stefan Bader <stefan.bader@canonical.com>
drivers/tty/n_gsm.c

index c8f043ad057d86e850d4c03d30c2882b5ce47d2b..cd67cfe08b1a6e42180611f1129b71644884748f 100644 (file)
@@ -1302,11 +1302,12 @@ static void gsm_control_response(struct gsm_mux *gsm, unsigned int command,
 
 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);
 }
 
@@ -2889,19 +2890,17 @@ static struct tty_ldisc_ops tty_ldisc_packet = {
 
 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);