Skip to content

Commit aa371e9

Browse files
dstarke-siemensgregkh
authored andcommitted
tty: n_gsm: fix restart handling via CLD command
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.8.2 states that both sides will revert to the non-multiplexed mode via a close-down message (CLD). The usual program flow is as following: - start multiplex mode by sending AT+CMUX to the mobile - establish the control channel (DLCI 0) - establish user channels (DLCI >0) - terminate user channels - send close-down message (CLD) - revert to AT protocol (i.e. leave multiplexed mode) The AT protocol is out of scope of the n_gsm driver. However, gsm_disconnect() sends CLD if gsm_config() detects that the requested parameters require the mux protocol to restart. The next immediate action is to start the mux protocol by opening DLCI 0 again. Any responder side which handles CLD commands correctly forces us to fail at this point because AT+CMUX needs to be sent to the mobile to start the mux again. Therefore, remove the CLD command in this phase and keep both sides in multiplexed mode. Remove the gsm_disconnect() function as it become unnecessary and merge the remaining parts into gsm_cleanup_mux() to handle the termination order and locking correctly. Fixes: 71e0779 ("tty: n_gsm: do not send/receive in ldisc close path") Cc: [email protected] Signed-off-by: Daniel Starke <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent 1145169 commit aa371e9

File tree

1 file changed

+20
-48
lines changed

1 file changed

+20
-48
lines changed

drivers/tty/n_gsm.c

Lines changed: 20 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -2106,49 +2106,35 @@ static void gsm_error(struct gsm_mux *gsm)
21062106
gsm->io_error++;
21072107
}
21082108

2109-
static int gsm_disconnect(struct gsm_mux *gsm)
2110-
{
2111-
struct gsm_dlci *dlci = gsm->dlci[0];
2112-
struct gsm_control *gc;
2113-
2114-
if (!dlci)
2115-
return 0;
2116-
2117-
/* In theory disconnecting DLCI 0 is sufficient but for some
2118-
modems this is apparently not the case. */
2119-
gc = gsm_control_send(gsm, CMD_CLD, NULL, 0);
2120-
if (gc)
2121-
gsm_control_wait(gsm, gc);
2122-
2123-
del_timer_sync(&gsm->t2_timer);
2124-
/* Now we are sure T2 has stopped */
2125-
2126-
gsm_dlci_begin_close(dlci);
2127-
wait_event_interruptible(gsm->event,
2128-
dlci->state == DLCI_CLOSED);
2129-
2130-
if (signal_pending(current))
2131-
return -EINTR;
2132-
2133-
return 0;
2134-
}
2135-
21362109
/**
21372110
* gsm_cleanup_mux - generic GSM protocol cleanup
21382111
* @gsm: our mux
2112+
* @disc: disconnect link?
21392113
*
21402114
* Clean up the bits of the mux which are the same for all framing
21412115
* protocols. Remove the mux from the mux table, stop all the timers
21422116
* and then shut down each device hanging up the channels as we go.
21432117
*/
21442118

2145-
static void gsm_cleanup_mux(struct gsm_mux *gsm)
2119+
static void gsm_cleanup_mux(struct gsm_mux *gsm, bool disc)
21462120
{
21472121
int i;
21482122
struct gsm_dlci *dlci = gsm->dlci[0];
21492123
struct gsm_msg *txq, *ntxq;
21502124

21512125
gsm->dead = true;
2126+
mutex_lock(&gsm->mutex);
2127+
2128+
if (dlci) {
2129+
if (disc && dlci->state != DLCI_CLOSED) {
2130+
gsm_dlci_begin_close(dlci);
2131+
wait_event(gsm->event, dlci->state == DLCI_CLOSED);
2132+
}
2133+
dlci->dead = true;
2134+
}
2135+
2136+
/* Finish outstanding timers, making sure they are done */
2137+
del_timer_sync(&gsm->t2_timer);
21522138

21532139
spin_lock(&gsm_mux_lock);
21542140
for (i = 0; i < MAX_MUX; i++) {
@@ -2162,13 +2148,7 @@ static void gsm_cleanup_mux(struct gsm_mux *gsm)
21622148
if (i == MAX_MUX)
21632149
return;
21642150

2165-
del_timer_sync(&gsm->t2_timer);
2166-
/* Now we are sure T2 has stopped */
2167-
if (dlci)
2168-
dlci->dead = true;
2169-
21702151
/* Free up any link layer users */
2171-
mutex_lock(&gsm->mutex);
21722152
for (i = 0; i < NUM_DLCI; i++)
21732153
if (gsm->dlci[i])
21742154
gsm_dlci_release(gsm->dlci[i]);
@@ -2370,19 +2350,11 @@ static int gsm_config(struct gsm_mux *gsm, struct gsm_config *c)
23702350

23712351
/*
23722352
* Close down what is needed, restart and initiate the new
2373-
* configuration
2353+
* configuration. On the first time there is no DLCI[0]
2354+
* and closing or cleaning up is not necessary.
23742355
*/
2375-
2376-
if (need_close || need_restart) {
2377-
int ret;
2378-
2379-
ret = gsm_disconnect(gsm);
2380-
2381-
if (ret)
2382-
return ret;
2383-
}
2384-
if (need_restart)
2385-
gsm_cleanup_mux(gsm);
2356+
if (need_close || need_restart)
2357+
gsm_cleanup_mux(gsm, true);
23862358

23872359
gsm->initiator = c->initiator;
23882360
gsm->mru = c->mru;
@@ -2494,7 +2466,7 @@ static void gsmld_detach_gsm(struct tty_struct *tty, struct gsm_mux *gsm)
24942466
for (i = 1; i < NUM_DLCI; i++)
24952467
tty_unregister_device(gsm_tty_driver, base + i);
24962468
}
2497-
gsm_cleanup_mux(gsm);
2469+
gsm_cleanup_mux(gsm, false);
24982470
tty_kref_put(gsm->tty);
24992471
gsm->tty = NULL;
25002472
}
@@ -2597,7 +2569,7 @@ static int gsmld_open(struct tty_struct *tty)
25972569

25982570
ret = gsmld_attach_gsm(tty, gsm);
25992571
if (ret != 0) {
2600-
gsm_cleanup_mux(gsm);
2572+
gsm_cleanup_mux(gsm, false);
26012573
mux_put(gsm);
26022574
}
26032575
return ret;

0 commit comments

Comments
 (0)