|
@@ -1689,6 +1689,8 @@ static inline void dlci_put(struct gsm_dlci *dlci)
|
|
|
tty_port_put(&dlci->port);
|
|
|
}
|
|
|
|
|
|
+static void gsm_destroy_network(struct gsm_dlci *dlci);
|
|
|
+
|
|
|
/**
|
|
|
* gsm_dlci_release - release DLCI
|
|
|
* @dlci: DLCI to destroy
|
|
@@ -1702,9 +1704,19 @@ static void gsm_dlci_release(struct gsm_dlci *dlci)
|
|
|
{
|
|
|
struct tty_struct *tty = tty_port_tty_get(&dlci->port);
|
|
|
if (tty) {
|
|
|
+ mutex_lock(&dlci->mutex);
|
|
|
+ gsm_destroy_network(dlci);
|
|
|
+ mutex_unlock(&dlci->mutex);
|
|
|
+
|
|
|
+ /* tty_vhangup needs the tty_lock, so unlock and
|
|
|
+ relock after doing the hangup. */
|
|
|
+ tty_unlock(tty);
|
|
|
tty_vhangup(tty);
|
|
|
+ tty_lock(tty);
|
|
|
+ tty_port_tty_set(&dlci->port, NULL);
|
|
|
tty_kref_put(tty);
|
|
|
}
|
|
|
+ dlci->state = DLCI_CLOSED;
|
|
|
dlci_put(dlci);
|
|
|
}
|
|
|
|
|
@@ -2947,6 +2959,8 @@ static void gsmtty_close(struct tty_struct *tty, struct file *filp)
|
|
|
|
|
|
if (dlci == NULL)
|
|
|
return;
|
|
|
+ if (dlci->state == DLCI_CLOSED)
|
|
|
+ return;
|
|
|
mutex_lock(&dlci->mutex);
|
|
|
gsm_destroy_network(dlci);
|
|
|
mutex_unlock(&dlci->mutex);
|
|
@@ -2965,6 +2979,8 @@ out:
|
|
|
static void gsmtty_hangup(struct tty_struct *tty)
|
|
|
{
|
|
|
struct gsm_dlci *dlci = tty->driver_data;
|
|
|
+ if (dlci->state == DLCI_CLOSED)
|
|
|
+ return;
|
|
|
tty_port_hangup(&dlci->port);
|
|
|
gsm_dlci_begin_close(dlci);
|
|
|
}
|
|
@@ -2972,9 +2988,12 @@ static void gsmtty_hangup(struct tty_struct *tty)
|
|
|
static int gsmtty_write(struct tty_struct *tty, const unsigned char *buf,
|
|
|
int len)
|
|
|
{
|
|
|
+ int sent;
|
|
|
struct gsm_dlci *dlci = tty->driver_data;
|
|
|
+ if (dlci->state == DLCI_CLOSED)
|
|
|
+ return -EINVAL;
|
|
|
/* Stuff the bytes into the fifo queue */
|
|
|
- int sent = kfifo_in_locked(dlci->fifo, buf, len, &dlci->lock);
|
|
|
+ sent = kfifo_in_locked(dlci->fifo, buf, len, &dlci->lock);
|
|
|
/* Need to kick the channel */
|
|
|
gsm_dlci_data_kick(dlci);
|
|
|
return sent;
|
|
@@ -2983,18 +3002,24 @@ static int gsmtty_write(struct tty_struct *tty, const unsigned char *buf,
|
|
|
static int gsmtty_write_room(struct tty_struct *tty)
|
|
|
{
|
|
|
struct gsm_dlci *dlci = tty->driver_data;
|
|
|
+ if (dlci->state == DLCI_CLOSED)
|
|
|
+ return -EINVAL;
|
|
|
return TX_SIZE - kfifo_len(dlci->fifo);
|
|
|
}
|
|
|
|
|
|
static int gsmtty_chars_in_buffer(struct tty_struct *tty)
|
|
|
{
|
|
|
struct gsm_dlci *dlci = tty->driver_data;
|
|
|
+ if (dlci->state == DLCI_CLOSED)
|
|
|
+ return -EINVAL;
|
|
|
return kfifo_len(dlci->fifo);
|
|
|
}
|
|
|
|
|
|
static void gsmtty_flush_buffer(struct tty_struct *tty)
|
|
|
{
|
|
|
struct gsm_dlci *dlci = tty->driver_data;
|
|
|
+ if (dlci->state == DLCI_CLOSED)
|
|
|
+ return;
|
|
|
/* Caution needed: If we implement reliable transport classes
|
|
|
then the data being transmitted can't simply be junked once
|
|
|
it has first hit the stack. Until then we can just blow it
|
|
@@ -3013,6 +3038,8 @@ static void gsmtty_wait_until_sent(struct tty_struct *tty, int timeout)
|
|
|
static int gsmtty_tiocmget(struct tty_struct *tty)
|
|
|
{
|
|
|
struct gsm_dlci *dlci = tty->driver_data;
|
|
|
+ if (dlci->state == DLCI_CLOSED)
|
|
|
+ return -EINVAL;
|
|
|
return dlci->modem_rx;
|
|
|
}
|
|
|
|
|
@@ -3022,6 +3049,8 @@ static int gsmtty_tiocmset(struct tty_struct *tty,
|
|
|
struct gsm_dlci *dlci = tty->driver_data;
|
|
|
unsigned int modem_tx = dlci->modem_tx;
|
|
|
|
|
|
+ if (dlci->state == DLCI_CLOSED)
|
|
|
+ return -EINVAL;
|
|
|
modem_tx &= ~clear;
|
|
|
modem_tx |= set;
|
|
|
|
|
@@ -3040,6 +3069,8 @@ static int gsmtty_ioctl(struct tty_struct *tty,
|
|
|
struct gsm_netconfig nc;
|
|
|
int index;
|
|
|
|
|
|
+ if (dlci->state == DLCI_CLOSED)
|
|
|
+ return -EINVAL;
|
|
|
switch (cmd) {
|
|
|
case GSMIOC_ENABLE_NET:
|
|
|
if (copy_from_user(&nc, (void __user *)arg, sizeof(nc)))
|
|
@@ -3066,6 +3097,9 @@ static int gsmtty_ioctl(struct tty_struct *tty,
|
|
|
|
|
|
static void gsmtty_set_termios(struct tty_struct *tty, struct ktermios *old)
|
|
|
{
|
|
|
+ struct gsm_dlci *dlci = tty->driver_data;
|
|
|
+ if (dlci->state == DLCI_CLOSED)
|
|
|
+ return;
|
|
|
/* For the moment its fixed. In actual fact the speed information
|
|
|
for the virtual channel can be propogated in both directions by
|
|
|
the RPN control message. This however rapidly gets nasty as we
|
|
@@ -3077,6 +3111,8 @@ static void gsmtty_set_termios(struct tty_struct *tty, struct ktermios *old)
|
|
|
static void gsmtty_throttle(struct tty_struct *tty)
|
|
|
{
|
|
|
struct gsm_dlci *dlci = tty->driver_data;
|
|
|
+ if (dlci->state == DLCI_CLOSED)
|
|
|
+ return;
|
|
|
if (tty->termios.c_cflag & CRTSCTS)
|
|
|
dlci->modem_tx &= ~TIOCM_DTR;
|
|
|
dlci->throttled = 1;
|
|
@@ -3087,6 +3123,8 @@ static void gsmtty_throttle(struct tty_struct *tty)
|
|
|
static void gsmtty_unthrottle(struct tty_struct *tty)
|
|
|
{
|
|
|
struct gsm_dlci *dlci = tty->driver_data;
|
|
|
+ if (dlci->state == DLCI_CLOSED)
|
|
|
+ return;
|
|
|
if (tty->termios.c_cflag & CRTSCTS)
|
|
|
dlci->modem_tx |= TIOCM_DTR;
|
|
|
dlci->throttled = 0;
|
|
@@ -3098,6 +3136,8 @@ static int gsmtty_break_ctl(struct tty_struct *tty, int state)
|
|
|
{
|
|
|
struct gsm_dlci *dlci = tty->driver_data;
|
|
|
int encode = 0; /* Off */
|
|
|
+ if (dlci->state == DLCI_CLOSED)
|
|
|
+ return -EINVAL;
|
|
|
|
|
|
if (state == -1) /* "On indefinitely" - we can't encode this
|
|
|
properly */
|