mirror of
https://github.com/followmsi/android_kernel_google_msm.git
synced 2024-11-06 23:17:41 +00:00
tty: n_smux: Fix packet close synchronization issue
If a channel is logical channel open or close ack is pending in the transmit queue when a logical channel is closed, then they are currently purged and the remote and local channel states are mismatched and the port cannot be re-opened. Note that this issue only occurs during rapid open/close/open sequences that are typically only seen in remote loopback stress testing. Add code to not purge ACK commands from a logical channel unless the logical channel purge is due to a subsystem restart (at which point the remote state is known to be power-on default). Change-Id: I52763323642bb7c505630bb994ecc1e021270d17 Signed-off-by: Eric Holmberg <eholmber@codeaurora.org> (cherry picked from commit 0e91408cb6343d5ac18206ff3d6639ccec5464fd) (cherry picked from commit ef0445e15b20369c7189a61d63fb284c5a51c3fb)
This commit is contained in:
parent
840782ad43
commit
807fc66ba9
1 changed files with 27 additions and 13 deletions
|
@ -351,7 +351,7 @@ static void list_channel(struct smux_lch_t *ch);
|
|||
static int smux_send_status_cmd(struct smux_lch_t *ch);
|
||||
static int smux_dispatch_rx_pkt(struct smux_pkt_t *pkt);
|
||||
static void smux_flush_tty(void);
|
||||
static void smux_purge_ch_tx_queue(struct smux_lch_t *ch);
|
||||
static void smux_purge_ch_tx_queue(struct smux_lch_t *ch, int is_ssr);
|
||||
static int schedule_notify(uint8_t lcid, int event,
|
||||
const union notifier_metadata *metadata);
|
||||
static int ssr_notifier_cb(struct notifier_block *this,
|
||||
|
@ -503,7 +503,7 @@ static void smux_lch_purge(void)
|
|||
|
||||
/* Purge TX queue */
|
||||
spin_lock(&ch->tx_lock_lhb2);
|
||||
smux_purge_ch_tx_queue(ch);
|
||||
smux_purge_ch_tx_queue(ch, 1);
|
||||
spin_unlock(&ch->tx_lock_lhb2);
|
||||
|
||||
/* Notify user of disconnect and reset channel state */
|
||||
|
@ -2158,25 +2158,35 @@ static void smux_flush_tty(void)
|
|||
* Purge TX queue for logical channel.
|
||||
*
|
||||
* @ch Logical channel pointer
|
||||
* @is_ssr 1 = this is a subsystem restart purge
|
||||
*
|
||||
* Must be called with the following spinlocks locked:
|
||||
* state_lock_lhb1
|
||||
* tx_lock_lhb2
|
||||
*/
|
||||
static void smux_purge_ch_tx_queue(struct smux_lch_t *ch)
|
||||
static void smux_purge_ch_tx_queue(struct smux_lch_t *ch, int is_ssr)
|
||||
{
|
||||
struct smux_pkt_t *pkt;
|
||||
int send_disconnect = 0;
|
||||
struct smux_pkt_t *pkt_tmp;
|
||||
int is_state_pkt;
|
||||
|
||||
while (!list_empty(&ch->tx_queue)) {
|
||||
pkt = list_first_entry(&ch->tx_queue, struct smux_pkt_t,
|
||||
list);
|
||||
list_del(&pkt->list);
|
||||
|
||||
list_for_each_entry_safe(pkt, pkt_tmp, &ch->tx_queue, list) {
|
||||
is_state_pkt = 0;
|
||||
if (pkt->hdr.cmd == SMUX_CMD_OPEN_LCH) {
|
||||
/* Open was never sent, just force to closed state */
|
||||
ch->local_state = SMUX_LCH_LOCAL_CLOSED;
|
||||
send_disconnect = 1;
|
||||
if (pkt->hdr.flags & SMUX_CMD_OPEN_ACK) {
|
||||
/* Open ACK must still be sent */
|
||||
is_state_pkt = 1;
|
||||
} else {
|
||||
/* Open never sent -- force to closed state */
|
||||
ch->local_state = SMUX_LCH_LOCAL_CLOSED;
|
||||
send_disconnect = 1;
|
||||
}
|
||||
} else if (pkt->hdr.cmd == SMUX_CMD_CLOSE_LCH) {
|
||||
if (pkt->hdr.flags & SMUX_CMD_CLOSE_ACK)
|
||||
is_state_pkt = 1;
|
||||
if (!send_disconnect)
|
||||
is_state_pkt = 1;
|
||||
} else if (pkt->hdr.cmd == SMUX_CMD_DATA) {
|
||||
/* Notify client of failed write */
|
||||
union notifier_metadata meta_write;
|
||||
|
@ -2186,7 +2196,11 @@ static void smux_purge_ch_tx_queue(struct smux_lch_t *ch)
|
|||
meta_write.write.len = pkt->hdr.payload_len;
|
||||
schedule_notify(ch->lcid, SMUX_WRITE_FAIL, &meta_write);
|
||||
}
|
||||
smux_free_pkt(pkt);
|
||||
|
||||
if (!is_state_pkt || is_ssr) {
|
||||
list_del(&pkt->list);
|
||||
smux_free_pkt(pkt);
|
||||
}
|
||||
}
|
||||
|
||||
if (send_disconnect) {
|
||||
|
@ -3020,7 +3034,7 @@ int msm_smux_close(uint8_t lcid)
|
|||
|
||||
/* Purge TX queue */
|
||||
spin_lock(&ch->tx_lock_lhb2);
|
||||
smux_purge_ch_tx_queue(ch);
|
||||
smux_purge_ch_tx_queue(ch, 0);
|
||||
spin_unlock(&ch->tx_lock_lhb2);
|
||||
|
||||
/* Send Close Command */
|
||||
|
|
Loading…
Reference in a new issue