Skip to content

Commit c19ffe0

Browse files
dstarke-siemensgregkh
authored andcommitted
tty: n_gsm: fix invalid use of MSC in advanced option
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: 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/20220422071025.5490-2-daniel.starke@siemens.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
1 parent a8c5b82 commit c19ffe0

File tree

1 file changed

+117
-8
lines changed

1 file changed

+117
-8
lines changed

drivers/tty/n_gsm.c

Lines changed: 117 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -366,7 +366,7 @@ static const u8 gsm_fcs8[256] = {
366366
#define GOOD_FCS 0xCF
367367

368368
static int gsmld_output(struct gsm_mux *gsm, u8 *data, int len);
369-
static int gsmtty_modem_update(struct gsm_dlci *dlci, u8 brk);
369+
static int gsm_modem_update(struct gsm_dlci *dlci, u8 brk);
370370

371371
/**
372372
* gsm_fcs_add - update FCS
@@ -914,6 +914,63 @@ static int gsm_dlci_data_output_framed(struct gsm_mux *gsm,
914914
return size;
915915
}
916916

917+
/**
918+
* gsm_dlci_modem_output - try and push modem status out of a DLCI
919+
* @gsm: mux
920+
* @dlci: the DLCI to pull modem status from
921+
* @brk: break signal
922+
*
923+
* Push an empty frame in to the transmit queue to update the modem status
924+
* bits and to transmit an optional break.
925+
*
926+
* Caller must hold the tx_lock of the mux.
927+
*/
928+
929+
static int gsm_dlci_modem_output(struct gsm_mux *gsm, struct gsm_dlci *dlci,
930+
u8 brk)
931+
{
932+
u8 *dp = NULL;
933+
struct gsm_msg *msg;
934+
int size;
935+
936+
/* for modem bits without break data */
937+
if (dlci->adaption == 1) {
938+
size = 0;
939+
} else if (dlci->adaption == 2) {
940+
size = 1;
941+
if (brk > 0)
942+
size++;
943+
} else {
944+
pr_err("%s: unsupported adaption %d\n", __func__,
945+
dlci->adaption);
946+
}
947+
948+
msg = gsm_data_alloc(gsm, dlci->addr, size, gsm->ftype);
949+
if (!msg) {
950+
pr_err("%s: gsm_data_alloc error", __func__);
951+
return -ENOMEM;
952+
}
953+
dp = msg->data;
954+
switch (dlci->adaption) {
955+
case 1: /* Unstructured */
956+
break;
957+
case 2: /* Unstructured with modem bits. */
958+
if (brk == 0) {
959+
*dp++ = (gsm_encode_modem(dlci) << 1) | EA;
960+
} else {
961+
*dp++ = gsm_encode_modem(dlci) << 1;
962+
*dp++ = (brk << 4) | 2 | EA; /* Length, Break, EA */
963+
}
964+
break;
965+
default:
966+
/* Handled above */
967+
break;
968+
}
969+
970+
__gsm_data_queue(dlci, msg);
971+
return size;
972+
}
973+
917974
/**
918975
* gsm_dlci_data_sweep - look for data to send
919976
* @gsm: the GSM mux
@@ -1464,7 +1521,7 @@ static void gsm_dlci_open(struct gsm_dlci *dlci)
14641521
pr_debug("DLCI %d goes open.\n", dlci->addr);
14651522
/* Send current modem state */
14661523
if (dlci->addr)
1467-
gsmtty_modem_update(dlci, 0);
1524+
gsm_modem_update(dlci, 0);
14681525
wake_up(&dlci->gsm->event);
14691526
}
14701527

@@ -2897,12 +2954,43 @@ static struct tty_ldisc_ops tty_ldisc_packet = {
28972954

28982955
#define TX_SIZE 512
28992956

2900-
static int gsmtty_modem_update(struct gsm_dlci *dlci, u8 brk)
2957+
/**
2958+
* gsm_modem_upd_via_data - send modem bits via convergence layer
2959+
* @dlci: channel
2960+
* @brk: break signal
2961+
*
2962+
* Send an empty frame to signal mobile state changes and to transmit the
2963+
* break signal for adaption 2.
2964+
*/
2965+
2966+
static void gsm_modem_upd_via_data(struct gsm_dlci *dlci, u8 brk)
2967+
{
2968+
struct gsm_mux *gsm = dlci->gsm;
2969+
unsigned long flags;
2970+
2971+
if (dlci->state != DLCI_OPEN || dlci->adaption != 2)
2972+
return;
2973+
2974+
spin_lock_irqsave(&gsm->tx_lock, flags);
2975+
gsm_dlci_modem_output(gsm, dlci, brk);
2976+
spin_unlock_irqrestore(&gsm->tx_lock, flags);
2977+
}
2978+
2979+
/**
2980+
* gsm_modem_upd_via_msc - send modem bits via control frame
2981+
* @dlci: channel
2982+
* @brk: break signal
2983+
*/
2984+
2985+
static int gsm_modem_upd_via_msc(struct gsm_dlci *dlci, u8 brk)
29012986
{
29022987
u8 modembits[3];
29032988
struct gsm_control *ctrl;
29042989
int len = 2;
29052990

2991+
if (dlci->gsm->encoding != 0)
2992+
return 0;
2993+
29062994
modembits[0] = (dlci->addr << 2) | 2 | EA; /* DLCI, Valid, EA */
29072995
if (!brk) {
29082996
modembits[1] = (gsm_encode_modem(dlci) << 1) | EA;
@@ -2917,6 +3005,27 @@ static int gsmtty_modem_update(struct gsm_dlci *dlci, u8 brk)
29173005
return gsm_control_wait(dlci->gsm, ctrl);
29183006
}
29193007

3008+
/**
3009+
* gsm_modem_update - send modem status line state
3010+
* @dlci: channel
3011+
* @brk: break signal
3012+
*/
3013+
3014+
static int gsm_modem_update(struct gsm_dlci *dlci, u8 brk)
3015+
{
3016+
if (dlci->adaption == 2) {
3017+
/* Send convergence layer type 2 empty data frame. */
3018+
gsm_modem_upd_via_data(dlci, brk);
3019+
return 0;
3020+
} else if (dlci->gsm->encoding == 0) {
3021+
/* Send as MSC control message. */
3022+
return gsm_modem_upd_via_msc(dlci, brk);
3023+
}
3024+
3025+
/* Modem status lines are not supported. */
3026+
return -EPROTONOSUPPORT;
3027+
}
3028+
29203029
static int gsm_carrier_raised(struct tty_port *port)
29213030
{
29223031
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)
29493058
modem_tx &= ~(TIOCM_DTR | TIOCM_RTS);
29503059
if (modem_tx != dlci->modem_tx) {
29513060
dlci->modem_tx = modem_tx;
2952-
gsmtty_modem_update(dlci, 0);
3061+
gsm_modem_update(dlci, 0);
29533062
}
29543063
}
29553064

@@ -3140,7 +3249,7 @@ static int gsmtty_tiocmset(struct tty_struct *tty,
31403249

31413250
if (modem_tx != dlci->modem_tx) {
31423251
dlci->modem_tx = modem_tx;
3143-
return gsmtty_modem_update(dlci, 0);
3252+
return gsm_modem_update(dlci, 0);
31443253
}
31453254
return 0;
31463255
}
@@ -3201,7 +3310,7 @@ static void gsmtty_throttle(struct tty_struct *tty)
32013310
dlci->modem_tx &= ~TIOCM_RTS;
32023311
dlci->throttled = true;
32033312
/* Send an MSC with RTS cleared */
3204-
gsmtty_modem_update(dlci, 0);
3313+
gsm_modem_update(dlci, 0);
32053314
}
32063315

32073316
static void gsmtty_unthrottle(struct tty_struct *tty)
@@ -3213,7 +3322,7 @@ static void gsmtty_unthrottle(struct tty_struct *tty)
32133322
dlci->modem_tx |= TIOCM_RTS;
32143323
dlci->throttled = false;
32153324
/* Send an MSC with RTS set */
3216-
gsmtty_modem_update(dlci, 0);
3325+
gsm_modem_update(dlci, 0);
32173326
}
32183327

32193328
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)
32313340
if (encode > 0x0F)
32323341
encode = 0x0F; /* Best effort */
32333342
}
3234-
return gsmtty_modem_update(dlci, encode);
3343+
return gsm_modem_update(dlci, encode);
32353344
}
32363345

32373346
static void gsmtty_cleanup(struct tty_struct *tty)

0 commit comments

Comments
 (0)