Received: by 2002:a05:6a10:6d10:0:0:0:0 with SMTP id gq16csp883052pxb; Fri, 22 Apr 2022 13:22:13 -0700 (PDT) X-Google-Smtp-Source: ABdhPJxa+6g4KcvUw711Bb1ym10IWaTShPr7vX42PCVlCodPjP+8glmHDUbz72/50J+kcHczwm41 X-Received: by 2002:a17:90b:3e84:b0:1d2:c015:2182 with SMTP id rj4-20020a17090b3e8400b001d2c0152182mr7315270pjb.232.1650658932929; Fri, 22 Apr 2022 13:22:12 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1650658932; cv=none; d=google.com; s=arc-20160816; b=wfkSEm111cgyey7ZkoO7z+4htb1v+YKStUzU4OBFSMAj6zAt+vJc6F9pc3eNANfWsB egL0toCA+LkAeujpppClbj3EGHKZacwK8xCZkzwz2t5lOMNqzkfXjt48aYj0AVyC0jNd 0s/iT3n0pfmvsx9/8ZI2QljmSSwPQ8Q6s6JvGMWkBtNOr7u71jXgy6SL2Mu5YxbxMewB djrXj2CmJCtI+mg2pQ0vFsj7dpk+4tJRg577cpmuJs9u7G55iVosMY3u0/74B3CG1cM3 stuTzfRESsJJBrWZ3iGx7SL4wmoFT19RXanhvAMKZBVhBo+mQle2K5z3o31xlyOBmyac r/5Q== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:feedback-id:content-transfer-encoding :mime-version:references:in-reply-to:message-id:date:subject:cc:to :from:dkim-signature; bh=6TYWz5NM2Ayh/wAaSx/ZruxeD4HMnQKe81wQRU87fBM=; b=KH0FZhHzwb0MqBI2m9VtWzGT/QxCjEAEw4Y8QMVG3Y7qNzsVoZw6meiNIpeJ3daObp PCfTpsDYRcA8DnBanq5k3yos2eqhO2DBDO/8h+BbeGEsoMTsDxZXwkIoKXfyrYpljp8b OiuXO2nGjS1AlHvVNdOuUws3ae7TTljx6Vgg+mUIkbHgok6fIacHvZPgf/iHYNb06oiI GJOHJBDDM6f7rrjjGKqajqYyCXghwZqdrxtEsv3+zK64BrG/CuNEc8MYB7zumEL93bK8 bbFxZwK26i8DX4IOxXCBOssfYBLOJgGfP6bLZYb/+5E59FFJ1V/nbCZmUoqwskFZmuTg +vtA== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@siemens.com header.s=fm1 header.b=VybX2RKu; spf=softfail (google.com: domain of transitioning linux-kernel-owner@vger.kernel.org does not designate 23.128.96.19 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=siemens.com Return-Path: Received: from lindbergh.monkeyblade.net (lindbergh.monkeyblade.net. [23.128.96.19]) by mx.google.com with ESMTPS id pi17-20020a17090b1e5100b001d2bde77c3asi13477456pjb.128.2022.04.22.13.22.12 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 22 Apr 2022 13:22:12 -0700 (PDT) Received-SPF: softfail (google.com: domain of transitioning linux-kernel-owner@vger.kernel.org does not designate 23.128.96.19 as permitted sender) client-ip=23.128.96.19; Authentication-Results: mx.google.com; dkim=pass header.i=@siemens.com header.s=fm1 header.b=VybX2RKu; spf=softfail (google.com: domain of transitioning linux-kernel-owner@vger.kernel.org does not designate 23.128.96.19 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=siemens.com Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by lindbergh.monkeyblade.net (Postfix) with ESMTP id E79971A0B33; Fri, 22 Apr 2022 12:08:28 -0700 (PDT) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1377117AbiDVHOi (ORCPT + 99 others); Fri, 22 Apr 2022 03:14:38 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:37214 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1345890AbiDVHOf (ORCPT ); Fri, 22 Apr 2022 03:14:35 -0400 X-Greylist: delayed 63 seconds by postgrey-1.37 at lindbergh.monkeyblade.net; Fri, 22 Apr 2022 00:11:43 PDT Received: from mta-65-225.siemens.flowmailer.net (mta-65-225.siemens.flowmailer.net [185.136.65.225]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 136465131E for ; Fri, 22 Apr 2022 00:11:41 -0700 (PDT) Received: by mta-65-225.siemens.flowmailer.net with ESMTPSA id 202204220710374730a04c63206925d3 for ; Fri, 22 Apr 2022 09:10:37 +0200 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; s=fm1; d=siemens.com; i=daniel.starke@siemens.com; h=Date:From:Subject:To:Message-ID:MIME-Version:Content-Type:Content-Transfer-Encoding:Cc:References:In-Reply-To; bh=6TYWz5NM2Ayh/wAaSx/ZruxeD4HMnQKe81wQRU87fBM=; b=VybX2RKuTM9/fnm3XwYiVizce4MpI0CMeQ2pXYxRFKB+n4Ek6w7wRF8Ti0Fq6Vt5lJHBgS 45ynA2nYKsJCldVpP0QZCOjSzQiD1N2krxZ1TIOKfNs2vu/TL+Vgh5o0B56mW4vfHdESsQD9 GeQWvB1BqRVh8Nvau8ETIIWep2Vsc=; From: "D. Starke" To: linux-serial@vger.kernel.org, gregkh@linuxfoundation.org, jirislaby@kernel.org Cc: linux-kernel@vger.kernel.org, Daniel Starke Subject: [PATCH 2/3] tty: n_gsm: fix invalid use of MSC in advanced option Date: Fri, 22 Apr 2022 00:10:24 -0700 Message-Id: <20220422071025.5490-2-daniel.starke@siemens.com> In-Reply-To: <20220422071025.5490-1-daniel.starke@siemens.com> References: <20220422071025.5490-1-daniel.starke@siemens.com> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Flowmailer-Platform: Siemens Feedback-ID: 519:519-314044:519-21489:flowmailer X-Spam-Status: No, score=-2.0 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,HEADER_FROM_DIFFERENT_DOMAINS, MAILING_LIST_MULTI,RDNS_NONE,SPF_HELO_NONE autolearn=no autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org From: Daniel Starke 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 --- drivers/tty/n_gsm.c | 125 +++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 117 insertions(+), 8 deletions(-) diff --git a/drivers/tty/n_gsm.c b/drivers/tty/n_gsm.c index 99fe54247a87..570f0b8b7576 100644 --- 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 @@ -914,6 +914,63 @@ static int gsm_dlci_data_output_framed(struct gsm_mux *gsm, return size; } +/** + * 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_dlci *dlci) 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_packet = { #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 gsm_dlci *dlci, u8 brk) 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 *port, int onoff) 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_struct *tty, 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_struct *tty) 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_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_struct *tty, int state) 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) -- 2.25.1