Skip to content

Commit

Permalink
tty: n_gsm: fix non flow control frames during mux flow off
Browse files Browse the repository at this point in the history
[ Upstream commit bec0224 ]

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.6 states that FCoff stops the
transmission on all channels except the control channel. This is already
implemented in gsm_data_kick(). However, chapter 5.4.8.1 explains that this
shall result in the same behavior as software flow control on the ldisc in
advanced option mode. That means only flow control frames shall be sent
during flow off. The current implementation does not consider this case.

Change gsm_data_kick() to send only flow control frames if constipated to
abide the standard. gsm_read_ea_val() and gsm_is_flow_ctrl_msg() are
introduced as helper functions for this.
It is planned to use gsm_read_ea_val() in later code cleanups for other
functions, too.

Fixes: c01af4f ("n_gsm : Flow control handling in Mux driver")
Signed-off-by: Daniel Starke <daniel.starke@siemens.com>
Link: https://lore.kernel.org/r/20220701061652.39604-5-daniel.starke@siemens.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
  • Loading branch information
dstarke-siemens authored and gregkh committed Aug 17, 2022
1 parent dd37f65 commit ace28af
Showing 1 changed file with 53 additions and 1 deletion.
54 changes: 53 additions & 1 deletion drivers/tty/n_gsm.c
Original file line number Diff line number Diff line change
Expand Up @@ -425,6 +425,27 @@ static int gsm_read_ea(unsigned int *val, u8 c)
return c & EA;
}

/**
* gsm_read_ea_val - read a value until EA
* @val: variable holding value
* @data: buffer of data
* @dlen: length of data
*
* Processes an EA value. Updates the passed variable and
* returns the processed data length.
*/
static unsigned int gsm_read_ea_val(unsigned int *val, const u8 *data, int dlen)
{
unsigned int len = 0;

for (; dlen > 0; dlen--) {
len++;
if (gsm_read_ea(val, *data++))
break;
}
return len;
}

/**
* gsm_encode_modem - encode modem data bits
* @dlci: DLCI to encode from
Expand Down Expand Up @@ -746,6 +767,37 @@ static struct gsm_msg *gsm_data_alloc(struct gsm_mux *gsm, u8 addr, int len,
return m;
}

/**
* gsm_is_flow_ctrl_msg - checks if flow control message
* @msg: message to check
*
* Returns true if the given message is a flow control command of the
* control channel. False is returned in any other case.
*/
static bool gsm_is_flow_ctrl_msg(struct gsm_msg *msg)
{
unsigned int cmd;

if (msg->addr > 0)
return false;

switch (msg->ctrl & ~PF) {
case UI:
case UIH:
cmd = 0;
if (gsm_read_ea_val(&cmd, msg->data + 2, msg->len - 2) < 1)
break;
switch (cmd & ~PF) {
case CMD_FCOFF:
case CMD_FCON:
return true;
}
break;
}

return false;
}

/**
* gsm_data_kick - poke the queue
* @gsm: GSM Mux
Expand All @@ -765,7 +817,7 @@ static void gsm_data_kick(struct gsm_mux *gsm, struct gsm_dlci *dlci)
int len;

list_for_each_entry_safe(msg, nmsg, &gsm->tx_list, list) {
if (gsm->constipated && msg->addr)
if (gsm->constipated && !gsm_is_flow_ctrl_msg(msg))
continue;
if (gsm->encoding != 0) {
gsm->txframe[0] = GSM1_SOF;
Expand Down

0 comments on commit ace28af

Please sign in to comment.