--- zzzz-none-000/linux-3.10.107/drivers/tty/n_gsm.c 2017-06-27 09:49:32.000000000 +0000 +++ scorpion-7490-727/linux-3.10.107/drivers/tty/n_gsm.c 2021-02-04 17:41:59.000000000 +0000 @@ -161,7 +161,7 @@ struct net_device *net; /* network interface, if created */ }; -/* DLCI 0, 62/63 are special or reseved see gsmtty_open */ +/* DLCI 0, 62/63 are special or reserved see gsmtty_open */ #define NUM_DLCI 64 @@ -194,6 +194,7 @@ struct gsm_mux { struct tty_struct *tty; /* The tty our ldisc is bound to */ spinlock_t lock; + struct mutex mutex; unsigned int num; struct kref ref; @@ -807,7 +808,7 @@ int h = dlci->adaption - 1; total_size = 0; - while(1) { + while (1) { len = kfifo_len(dlci->fifo); if (len == 0) return total_size; @@ -827,8 +828,8 @@ switch (dlci->adaption) { case 1: /* Unstructured */ break; - case 2: /* Unstructed with modem bits. Always one byte as we never - send inline break data */ + case 2: /* Unstructed with modem bits. + Always one byte as we never send inline break data */ *dp++ = gsm_encode_modem(dlci); break; } @@ -968,7 +969,7 @@ unsigned long flags; int sweep; - if (dlci->constipated) + if (dlci->constipated) return; spin_lock_irqsave(&dlci->gsm->tx_lock, flags); @@ -981,7 +982,7 @@ gsm_dlci_data_output(dlci->gsm, dlci); } if (sweep) - gsm_dlci_data_sweep(dlci->gsm); + gsm_dlci_data_sweep(dlci->gsm); spin_unlock_irqrestore(&dlci->gsm->tx_lock, flags); } @@ -1149,7 +1150,7 @@ static void gsm_control_rls(struct gsm_mux *gsm, u8 *data, int clen) { struct tty_port *port; - unsigned int addr = 0 ; + unsigned int addr = 0; u8 bits; int len = clen; u8 *dp = data; @@ -1715,11 +1716,8 @@ 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); } @@ -1751,10 +1749,11 @@ if ((gsm->control & ~PF) == UI) gsm->fcs = gsm_fcs_add_block(gsm->fcs, gsm->buf, gsm->len); - if (gsm->encoding == 0){ - /* WARNING: gsm->received_fcs is used for gsm->encoding = 0 only. - In this case it contain the last piece of data - required to generate final CRC */ + if (gsm->encoding == 0) { + /* WARNING: gsm->received_fcs is used for + gsm->encoding = 0 only. + In this case it contain the last piece of data + required to generate final CRC */ gsm->fcs = gsm_fcs_add(gsm->fcs, gsm->received_fcs); } if (gsm->fcs != GOOD_FCS) { @@ -2029,7 +2028,7 @@ * and then shut down each device hanging up the channels as we go. */ -void gsm_cleanup_mux(struct gsm_mux *gsm) +static void gsm_cleanup_mux(struct gsm_mux *gsm) { int i; struct gsm_dlci *dlci = gsm->dlci[0]; @@ -2046,7 +2045,9 @@ } } spin_unlock(&gsm_mux_lock); - WARN_ON(i == MAX_MUX); + /* open failed before registering => nothing to do */ + if (i == MAX_MUX) + return; /* In theory disconnecting DLCI 0 is sufficient but for some modems this is apparently not the case. */ @@ -2064,15 +2065,16 @@ dlci->state == DLCI_CLOSED); } /* Free up any link layer users */ + mutex_lock(&gsm->mutex); for (i = 0; i < NUM_DLCI; i++) if (gsm->dlci[i]) gsm_dlci_release(gsm->dlci[i]); + mutex_unlock(&gsm->mutex); /* Now wipe the queues */ list_for_each_entry_safe(txq, ntxq, &gsm->tx_list, list) kfree(txq); INIT_LIST_HEAD(&gsm->tx_list); } -EXPORT_SYMBOL_GPL(gsm_cleanup_mux); /** * gsm_activate_mux - generic GSM setup @@ -2083,14 +2085,12 @@ * finally kick off connecting to DLCI 0 on the modem. */ -int gsm_activate_mux(struct gsm_mux *gsm) +static int gsm_activate_mux(struct gsm_mux *gsm) { struct gsm_dlci *dlci; int i = 0; - init_timer(&gsm->t2_timer); - gsm->t2_timer.function = gsm_control_retransmit; - gsm->t2_timer.data = (unsigned long)gsm; + setup_timer(&gsm->t2_timer, gsm_control_retransmit, (unsigned long)gsm); init_waitqueue_head(&gsm->event); spin_lock_init(&gsm->control_lock); spin_lock_init(&gsm->tx_lock); @@ -2119,7 +2119,6 @@ gsm->dead = 0; /* Tty opens are now permissible */ return 0; } -EXPORT_SYMBOL_GPL(gsm_activate_mux); /** * gsm_free_mux - free up a mux @@ -2127,13 +2126,12 @@ * * Dispose of allocated resources for a dead mux */ -void gsm_free_mux(struct gsm_mux *gsm) +static void gsm_free_mux(struct gsm_mux *gsm) { kfree(gsm->txframe); kfree(gsm->buf); kfree(gsm); } -EXPORT_SYMBOL_GPL(gsm_free_mux); /** * gsm_free_muxr - free up a mux @@ -2163,7 +2161,7 @@ * Creates a new mux ready for activation. */ -struct gsm_mux *gsm_alloc_mux(void) +static struct gsm_mux *gsm_alloc_mux(void) { struct gsm_mux *gsm = kzalloc(sizeof(struct gsm_mux), GFP_KERNEL); if (gsm == NULL) @@ -2180,6 +2178,7 @@ return NULL; } spin_lock_init(&gsm->lock); + mutex_init(&gsm->mutex); kref_init(&gsm->ref); INIT_LIST_HEAD(&gsm->tx_list); @@ -2195,7 +2194,6 @@ return gsm; } -EXPORT_SYMBOL_GPL(gsm_alloc_mux); /** * gsmld_output - write to link @@ -2232,8 +2230,7 @@ static int gsmld_attach_gsm(struct tty_struct *tty, struct gsm_mux *gsm) { - int ret, i; - int base = gsm->num << 6; /* Base for this MUX */ + int ret, i, base; gsm->tty = tty_kref_get(tty); gsm->output = gsmld_output; @@ -2243,6 +2240,7 @@ else { /* Don't register device 0 - this is the control channel and not a usable tty interface */ + base = gsm->num << 6; /* Base for this MUX */ for (i = 1; i < NUM_DLCI; i++) tty_register_device(gsm_tty_driver, base + i, NULL); } @@ -2278,15 +2276,15 @@ const unsigned char *dp; char *f; int i; - char buf[64]; - char flags; + char flags = TTY_NORMAL; if (debug & 4) print_hex_dump_bytes("gsmld_receive: ", DUMP_PREFIX_OFFSET, cp, count); for (i = count, dp = cp, f = fp; i; i--, dp++) { - flags = *f++; + if (f) + flags = *f++; switch (flags) { case TTY_NORMAL: gsm->receive(gsm, *dp); @@ -2299,7 +2297,7 @@ break; default: WARN_ONCE(1, "%s: unknown flag %d\n", - tty_name(tty, buf), flags); + tty_name(tty), flags); break; } } @@ -2369,6 +2367,7 @@ static int gsmld_open(struct tty_struct *tty) { struct gsm_mux *gsm; + int ret; if (tty->ops->write == NULL) return -EINVAL; @@ -2383,7 +2382,13 @@ /* Attach the initial passive connection */ gsm->encoding = 1; - return gsmld_attach_gsm(tty, gsm); + + ret = gsmld_attach_gsm(tty, gsm); + if (ret != 0) { + gsm_cleanup_mux(gsm); + mux_put(gsm); + } + return ret; } /** @@ -2665,7 +2670,7 @@ static int gsm_mux_net_start_xmit(struct sk_buff *skb, struct net_device *net) { - struct gsm_mux_net *mux_net = (struct gsm_mux_net *)netdev_priv(net); + struct gsm_mux_net *mux_net = netdev_priv(net); struct gsm_dlci *dlci = mux_net->dlci; muxnet_get(mux_net); @@ -2694,7 +2699,7 @@ { struct net_device *net = dlci->net; struct sk_buff *skb; - struct gsm_mux_net *mux_net = (struct gsm_mux_net *)netdev_priv(net); + struct gsm_mux_net *mux_net = netdev_priv(net); muxnet_get(mux_net); /* Allocate an sk_buff */ @@ -2709,7 +2714,7 @@ memcpy(skb_put(skb, size), in_buf, size); skb->dev = net; - skb->protocol = __constant_htons(ETH_P_IP); + skb->protocol = htons(ETH_P_IP); /* Ship it off to the kernel */ netif_rx(skb); @@ -2721,9 +2726,9 @@ return; } -int gsm_change_mtu(struct net_device *net, int new_mtu) +static int gsm_change_mtu(struct net_device *net, int new_mtu) { - struct gsm_mux_net *mux_net = (struct gsm_mux_net *)netdev_priv(net); + struct gsm_mux_net *mux_net = netdev_priv(net); if ((new_mtu < 8) || (new_mtu > mux_net->dlci->gsm->mtu)) return -EINVAL; net->mtu = new_mtu; @@ -2759,7 +2764,7 @@ pr_debug("destroy network interface"); if (!dlci->net) return; - mux_net = (struct gsm_mux_net *)netdev_priv(dlci->net); + mux_net = netdev_priv(dlci->net); muxnet_put(mux_net); } @@ -2790,15 +2795,14 @@ netname = "gsm%d"; if (nc->if_name[0] != '\0') netname = nc->if_name; - net = alloc_netdev(sizeof(struct gsm_mux_net), - netname, - gsm_mux_net_init); + net = alloc_netdev(sizeof(struct gsm_mux_net), netname, + NET_NAME_UNKNOWN, gsm_mux_net_init); if (!net) { pr_err("alloc_netdev failed"); return -ENOMEM; } net->mtu = dlci->gsm->mtu; - mux_net = (struct gsm_mux_net *)netdev_priv(net); + mux_net = netdev_priv(net); mux_net->dlci = dlci; kref_init(&mux_net->ref); strncpy(nc->if_name, net->name, IFNAMSIZ); /* return net name */ @@ -2821,7 +2825,7 @@ } /* Line discipline for real tty */ -struct tty_ldisc_ops tty_ldisc_packet = { +static struct tty_ldisc_ops tty_ldisc_packet = { .owner = THIS_MODULE, .magic = TTY_LDISC_MAGIC, .name = "n_gsm", @@ -2915,25 +2919,37 @@ gsm = gsm_mux[mux]; if (gsm->dead) return -EL2HLT; - /* If DLCI 0 is not yet fully open return an error. This is ok from a locking - perspective as we don't have to worry about this if DLCI0 is lost */ - if (gsm->dlci[0] && gsm->dlci[0]->state != DLCI_OPEN) + /* If DLCI 0 is not yet fully open return an error. + This is ok from a locking + perspective as we don't have to worry about this + if DLCI0 is lost */ + mutex_lock(&gsm->mutex); + if (gsm->dlci[0] && gsm->dlci[0]->state != DLCI_OPEN) { + mutex_unlock(&gsm->mutex); return -EL2NSYNC; + } dlci = gsm->dlci[line]; if (dlci == NULL) { alloc = true; dlci = gsm_dlci_alloc(gsm, line); } - if (dlci == NULL) + if (dlci == NULL) { + mutex_unlock(&gsm->mutex); return -ENOMEM; + } ret = tty_port_install(&dlci->port, driver, tty); if (ret) { if (alloc) dlci_put(dlci); + mutex_unlock(&gsm->mutex); return ret; } + dlci_get(dlci); + dlci_get(gsm->dlci[0]); + mux_get(gsm); tty->driver_data = dlci; + mutex_unlock(&gsm->mutex); return 0; } @@ -2944,9 +2960,6 @@ struct tty_port *port = &dlci->port; port->count++; - dlci_get(dlci); - dlci_get(dlci->gsm->dlci[0]); - mux_get(dlci->gsm); tty_port_tty_set(port, tty); dlci->modem_rx = 0; @@ -2973,7 +2986,7 @@ mutex_unlock(&dlci->mutex); gsm = dlci->gsm; if (tty_port_close_start(&dlci->port, tty, filp) == 0) - goto out; + return; gsm_dlci_begin_close(dlci); if (test_bit(ASYNCB_INITIALIZED, &dlci->port.flags)) { if (C_HUPCL(tty)) @@ -2981,10 +2994,7 @@ } tty_port_close_end(&dlci->port, tty); tty_port_tty_set(&dlci->port, NULL); -out: - dlci_put(dlci); - dlci_put(gsm->dlci[0]); - mux_put(gsm); + return; } static void gsmtty_hangup(struct tty_struct *tty) @@ -3161,6 +3171,15 @@ return gsmtty_modem_update(dlci, encode); } +static void gsmtty_cleanup(struct tty_struct *tty) +{ + struct gsm_dlci *dlci = tty->driver_data; + struct gsm_mux *gsm = dlci->gsm; + + dlci_put(dlci); + dlci_put(gsm->dlci[0]); + mux_put(gsm); +} /* Virtual ttys for the demux */ static const struct tty_operations gsmtty_ops = { @@ -3180,6 +3199,7 @@ .tiocmget = gsmtty_tiocmget, .tiocmset = gsmtty_tiocmset, .break_ctl = gsmtty_break_ctl, + .cleanup = gsmtty_cleanup, };