Skip to content

Commit 70d7f14

Browse files
dstarke-siemensgregkh
authored andcommitted
tty: n_gsm: fix missing receive state reset after mode switch
The current implementation uses either gsm0_receive() or gsm1_receive() depending on whether the user configured the mux in basic or advanced option mode. Both functions share some state values over the same logical elements of the frame. However, both frame types differ in their nature. gsm0_receive() uses non-transparency framing, whereas gsm1_receive() uses transparency mechanism. Switching between both modes leaves the receive function in an undefined state when done during frame reception. Fix this by splitting both states. Add gsm0_receive_state_check_and_fix() and gsm1_receive_state_check_and_fix() to ensure that gsm->state is reset after a change of gsm->receive. Note that gsm->state is only accessed in: - gsm0_receive() - gsm1_receive() - gsm_error() Fixes: e1eaea4 ("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/20240424054842.7741-2-daniel.starke@siemens.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
1 parent 47388e8 commit 70d7f14

1 file changed

Lines changed: 92 additions & 41 deletions

File tree

drivers/tty/n_gsm.c

Lines changed: 92 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -245,16 +245,18 @@ enum gsm_encoding {
245245

246246
enum gsm_mux_state {
247247
GSM_SEARCH,
248-
GSM_START,
249-
GSM_ADDRESS,
250-
GSM_CONTROL,
251-
GSM_LEN,
252-
GSM_DATA,
253-
GSM_FCS,
254-
GSM_OVERRUN,
255-
GSM_LEN0,
256-
GSM_LEN1,
257-
GSM_SSOF,
248+
GSM0_ADDRESS,
249+
GSM0_CONTROL,
250+
GSM0_LEN0,
251+
GSM0_LEN1,
252+
GSM0_DATA,
253+
GSM0_FCS,
254+
GSM0_SSOF,
255+
GSM1_START,
256+
GSM1_ADDRESS,
257+
GSM1_CONTROL,
258+
GSM1_DATA,
259+
GSM1_OVERRUN,
258260
};
259261

260262
/*
@@ -2847,6 +2849,30 @@ static void gsm_queue(struct gsm_mux *gsm)
28472849
return;
28482850
}
28492851

2852+
/**
2853+
* gsm0_receive_state_check_and_fix - check and correct receive state
2854+
* @gsm: gsm data for this ldisc instance
2855+
*
2856+
* Ensures that the current receive state is valid for basic option mode.
2857+
*/
2858+
2859+
static void gsm0_receive_state_check_and_fix(struct gsm_mux *gsm)
2860+
{
2861+
switch (gsm->state) {
2862+
case GSM_SEARCH:
2863+
case GSM0_ADDRESS:
2864+
case GSM0_CONTROL:
2865+
case GSM0_LEN0:
2866+
case GSM0_LEN1:
2867+
case GSM0_DATA:
2868+
case GSM0_FCS:
2869+
case GSM0_SSOF:
2870+
break;
2871+
default:
2872+
gsm->state = GSM_SEARCH;
2873+
break;
2874+
}
2875+
}
28502876

28512877
/**
28522878
* gsm0_receive - perform processing for non-transparency
@@ -2860,26 +2886,27 @@ static void gsm0_receive(struct gsm_mux *gsm, u8 c)
28602886
{
28612887
unsigned int len;
28622888

2889+
gsm0_receive_state_check_and_fix(gsm);
28632890
switch (gsm->state) {
28642891
case GSM_SEARCH: /* SOF marker */
28652892
if (c == GSM0_SOF) {
2866-
gsm->state = GSM_ADDRESS;
2893+
gsm->state = GSM0_ADDRESS;
28672894
gsm->address = 0;
28682895
gsm->len = 0;
28692896
gsm->fcs = INIT_FCS;
28702897
}
28712898
break;
2872-
case GSM_ADDRESS: /* Address EA */
2899+
case GSM0_ADDRESS: /* Address EA */
28732900
gsm->fcs = gsm_fcs_add(gsm->fcs, c);
28742901
if (gsm_read_ea(&gsm->address, c))
2875-
gsm->state = GSM_CONTROL;
2902+
gsm->state = GSM0_CONTROL;
28762903
break;
2877-
case GSM_CONTROL: /* Control Byte */
2904+
case GSM0_CONTROL: /* Control Byte */
28782905
gsm->fcs = gsm_fcs_add(gsm->fcs, c);
28792906
gsm->control = c;
2880-
gsm->state = GSM_LEN0;
2907+
gsm->state = GSM0_LEN0;
28812908
break;
2882-
case GSM_LEN0: /* Length EA */
2909+
case GSM0_LEN0: /* Length EA */
28832910
gsm->fcs = gsm_fcs_add(gsm->fcs, c);
28842911
if (gsm_read_ea(&gsm->len, c)) {
28852912
if (gsm->len > gsm->mru) {
@@ -2889,14 +2916,14 @@ static void gsm0_receive(struct gsm_mux *gsm, u8 c)
28892916
}
28902917
gsm->count = 0;
28912918
if (!gsm->len)
2892-
gsm->state = GSM_FCS;
2919+
gsm->state = GSM0_FCS;
28932920
else
2894-
gsm->state = GSM_DATA;
2921+
gsm->state = GSM0_DATA;
28952922
break;
28962923
}
2897-
gsm->state = GSM_LEN1;
2924+
gsm->state = GSM0_LEN1;
28982925
break;
2899-
case GSM_LEN1:
2926+
case GSM0_LEN1:
29002927
gsm->fcs = gsm_fcs_add(gsm->fcs, c);
29012928
len = c;
29022929
gsm->len |= len << 7;
@@ -2907,11 +2934,11 @@ static void gsm0_receive(struct gsm_mux *gsm, u8 c)
29072934
}
29082935
gsm->count = 0;
29092936
if (!gsm->len)
2910-
gsm->state = GSM_FCS;
2937+
gsm->state = GSM0_FCS;
29112938
else
2912-
gsm->state = GSM_DATA;
2939+
gsm->state = GSM0_DATA;
29132940
break;
2914-
case GSM_DATA: /* Data */
2941+
case GSM0_DATA: /* Data */
29152942
gsm->buf[gsm->count++] = c;
29162943
if (gsm->count >= MAX_MRU) {
29172944
gsm->bad_size++;
@@ -2922,14 +2949,14 @@ static void gsm0_receive(struct gsm_mux *gsm, u8 c)
29222949
gsm->fcs = gsm_fcs_add_block(gsm->fcs, gsm->buf,
29232950
gsm->count);
29242951
}
2925-
gsm->state = GSM_FCS;
2952+
gsm->state = GSM0_FCS;
29262953
}
29272954
break;
2928-
case GSM_FCS: /* FCS follows the packet */
2955+
case GSM0_FCS: /* FCS follows the packet */
29292956
gsm->fcs = gsm_fcs_add(gsm->fcs, c);
2930-
gsm->state = GSM_SSOF;
2957+
gsm->state = GSM0_SSOF;
29312958
break;
2932-
case GSM_SSOF:
2959+
case GSM0_SSOF:
29332960
gsm->state = GSM_SEARCH;
29342961
if (c == GSM0_SOF)
29352962
gsm_queue(gsm);
@@ -2942,6 +2969,29 @@ static void gsm0_receive(struct gsm_mux *gsm, u8 c)
29422969
}
29432970
}
29442971

2972+
/**
2973+
* gsm1_receive_state_check_and_fix - check and correct receive state
2974+
* @gsm: gsm data for this ldisc instance
2975+
*
2976+
* Ensures that the current receive state is valid for advanced option mode.
2977+
*/
2978+
2979+
static void gsm1_receive_state_check_and_fix(struct gsm_mux *gsm)
2980+
{
2981+
switch (gsm->state) {
2982+
case GSM_SEARCH:
2983+
case GSM1_START:
2984+
case GSM1_ADDRESS:
2985+
case GSM1_CONTROL:
2986+
case GSM1_DATA:
2987+
case GSM1_OVERRUN:
2988+
break;
2989+
default:
2990+
gsm->state = GSM_SEARCH;
2991+
break;
2992+
}
2993+
}
2994+
29452995
/**
29462996
* gsm1_receive - perform processing for non-transparency
29472997
* @gsm: gsm data for this ldisc instance
@@ -2952,6 +3002,7 @@ static void gsm0_receive(struct gsm_mux *gsm, u8 c)
29523002

29533003
static void gsm1_receive(struct gsm_mux *gsm, u8 c)
29543004
{
3005+
gsm1_receive_state_check_and_fix(gsm);
29553006
/* handle XON/XOFF */
29563007
if ((c & ISO_IEC_646_MASK) == XON) {
29573008
gsm->constipated = true;
@@ -2964,11 +3015,11 @@ static void gsm1_receive(struct gsm_mux *gsm, u8 c)
29643015
}
29653016
if (c == GSM1_SOF) {
29663017
/* EOF is only valid in frame if we have got to the data state */
2967-
if (gsm->state == GSM_DATA) {
3018+
if (gsm->state == GSM1_DATA) {
29683019
if (gsm->count < 1) {
29693020
/* Missing FSC */
29703021
gsm->malformed++;
2971-
gsm->state = GSM_START;
3022+
gsm->state = GSM1_START;
29723023
return;
29733024
}
29743025
/* Remove the FCS from data */
@@ -2984,14 +3035,14 @@ static void gsm1_receive(struct gsm_mux *gsm, u8 c)
29843035
gsm->fcs = gsm_fcs_add(gsm->fcs, gsm->buf[gsm->count]);
29853036
gsm->len = gsm->count;
29863037
gsm_queue(gsm);
2987-
gsm->state = GSM_START;
3038+
gsm->state = GSM1_START;
29883039
return;
29893040
}
29903041
/* Any partial frame was a runt so go back to start */
2991-
if (gsm->state != GSM_START) {
3042+
if (gsm->state != GSM1_START) {
29923043
if (gsm->state != GSM_SEARCH)
29933044
gsm->malformed++;
2994-
gsm->state = GSM_START;
3045+
gsm->state = GSM1_START;
29953046
}
29963047
/* A SOF in GSM_START means we are still reading idling or
29973048
framing bytes */
@@ -3012,30 +3063,30 @@ static void gsm1_receive(struct gsm_mux *gsm, u8 c)
30123063
gsm->escape = false;
30133064
}
30143065
switch (gsm->state) {
3015-
case GSM_START: /* First byte after SOF */
3066+
case GSM1_START: /* First byte after SOF */
30163067
gsm->address = 0;
3017-
gsm->state = GSM_ADDRESS;
3068+
gsm->state = GSM1_ADDRESS;
30183069
gsm->fcs = INIT_FCS;
30193070
fallthrough;
3020-
case GSM_ADDRESS: /* Address continuation */
3071+
case GSM1_ADDRESS: /* Address continuation */
30213072
gsm->fcs = gsm_fcs_add(gsm->fcs, c);
30223073
if (gsm_read_ea(&gsm->address, c))
3023-
gsm->state = GSM_CONTROL;
3074+
gsm->state = GSM1_CONTROL;
30243075
break;
3025-
case GSM_CONTROL: /* Control Byte */
3076+
case GSM1_CONTROL: /* Control Byte */
30263077
gsm->fcs = gsm_fcs_add(gsm->fcs, c);
30273078
gsm->control = c;
30283079
gsm->count = 0;
3029-
gsm->state = GSM_DATA;
3080+
gsm->state = GSM1_DATA;
30303081
break;
3031-
case GSM_DATA: /* Data */
3082+
case GSM1_DATA: /* Data */
30323083
if (gsm->count > gsm->mru || gsm->count > MAX_MRU) { /* Allow one for the FCS */
3033-
gsm->state = GSM_OVERRUN;
3084+
gsm->state = GSM1_OVERRUN;
30343085
gsm->bad_size++;
30353086
} else
30363087
gsm->buf[gsm->count++] = c;
30373088
break;
3038-
case GSM_OVERRUN: /* Over-long - eg a dropped SOF */
3089+
case GSM1_OVERRUN: /* Over-long - eg a dropped SOF */
30393090
break;
30403091
default:
30413092
pr_debug("%s: unhandled state: %d\n", __func__, gsm->state);

0 commit comments

Comments
 (0)