From 4013f8899a3283335a2f58c683bba606d0bb2233 Mon Sep 17 00:00:00 2001 From: Vincent Pillet Date: Thu, 7 Jun 2012 15:21:22 +0200 Subject: [PATCH] n_gsm.c : Prevent adaption change while receiving datas BZ: 40341 If ioctl GSMIOC_DISABLE_NET is issued on gsmtty associated to network interface while IP traffic is icomming, in rare case gsm_mux_rx_netchar can use variable (mux_net) that can no more be valid. We add a mutex to prevent that. More generally we prevent that adaption can change while incomming data are managed. Change-Id: I121d62ed479991c59aa95ce4b184e2c422ae21cc Signed-off-by: Vincent Pillet --- drivers/tty/n_gsm.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/tty/n_gsm.c b/drivers/tty/n_gsm.c index f605dbe..c072162 100644 --- a/drivers/tty/n_gsm.c +++ b/drivers/tty/n_gsm.c @@ -133,6 +133,7 @@ struct gsm_dlci { struct kfifo *fifo; /* Queue fifo for the DLCI */ struct kfifo _fifo; /* For new fifo API porting only */ int adaption; /* Adaption layer in use */ + struct mutex rx_mutex; /* Mutex when adaption change */ u32 modem_rx; /* Our incoming virtual modem lines */ u32 modem_tx; /* Our outgoing modem lines */ int dead; /* Refuse re-open */ @@ -1639,6 +1640,7 @@ static struct gsm_dlci *gsm_dlci_alloc(struct gsm_mux *gsm, int addr) struct gsm_dlci *dlci = kzalloc(sizeof(struct gsm_dlci), GFP_ATOMIC); if (dlci == NULL) return NULL; + mutex_init(&dlci->rx_mutex); spin_lock_init(&dlci->lock); kref_init(&dlci->ref); dlci->fifo = &dlci->_fifo; @@ -1819,7 +1821,10 @@ static void gsm_queue(struct gsm_mux *gsm) gsm_command(gsm, address, DM|PF); return; } + /* We must prevent from changing adaption while receiving */ + mutex_lock(&dlci->rx_mutex); dlci->data(dlci, gsm->buf, gsm->len); + mutex_unlock(&dlci->rx_mutex); break; default: goto invalid; @@ -2838,9 +2843,11 @@ static void gsm_destroy_network(struct gsm_dlci *dlci) pr_debug("destroy network interface"); if (dlci->net) { + mutex_lock(&dlci->rx_mutex); netif_tx_disable(dlci->net); mux_net = (struct gsm_mux_net *)netdev_priv(dlci->net); kref_put(&mux_net->ref, net_free); + mutex_unlock(&dlci->rx_mutex); } } @@ -2889,6 +2896,8 @@ static int gsm_create_network(struct gsm_dlci *dlci, struct gsm_netconfig *nc) free_netdev(net); goto error_ret; } + + mutex_lock(&dlci->rx_mutex); dlci->net = net; dlci->adaption = nc->adaption; dlci->data = gsm_mux_rx_netchar; @@ -2896,6 +2905,7 @@ static int gsm_create_network(struct gsm_dlci *dlci, struct gsm_netconfig *nc) mux_net = (struct gsm_mux_net *)netdev_priv(net); mux_net->dlci = dlci; kref_init(&mux_net->ref); + mutex_unlock(&dlci->rx_mutex); strncpy(nc->if_name, net->name, IFNAMSIZ); /* return net name */ return net->ifindex; /* return network index */ -- 2.7.4