aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/atm/usbatm.c
diff options
context:
space:
mode:
authorDuncan Sands <baldrick@free.fr>2006-01-13 04:05:15 -0500
committerGreg Kroah-Hartman <gregkh@suse.de>2006-01-31 20:23:39 -0500
commit0e42a627ec3d8defa0c43cff94b8f2080a070716 (patch)
tree5b22c24b224de444ddc6fd9b874a86624d41c227 /drivers/usb/atm/usbatm.c
parent233c08e0ff303e659a9003d49b15608f59f08a64 (diff)
[PATCH] USBATM: shutdown open connections when disconnected
This patch causes vcc_release_async to be applied to any open vcc's when the modem is disconnected. This signals a socket shutdown, letting the socket user know that the game is up. I wrote this patch because of reports that pppd would keep connections open forever when the modem is disconnected. This patch does not fix that problem, but it's a step in the right direction. It doesn't help because the pppoatm module doesn't yet monitor state changes on the ATM socket, so simply never realises that the ATM connection has gone down (meaning it doesn't tell the ppp layer). But at least there is a socket state change now. Unfortunately this patch may create problems for those rare users like me who use routed IP or some other non-ppp connection method that goes via the ATM ARP daemon: the daemon is buggy, and with this patch will crash when the modem is disconnected. Users with a buggy atmarpd can simply restart it after disconnecting the modem. Signed-off-by: Duncan Sands <baldrick@free.fr> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/usb/atm/usbatm.c')
-rw-r--r--drivers/usb/atm/usbatm.c66
1 files changed, 47 insertions, 19 deletions
diff --git a/drivers/usb/atm/usbatm.c b/drivers/usb/atm/usbatm.c
index 3ed5f02c36d3..e660a1ebf12b 100644
--- a/drivers/usb/atm/usbatm.c
+++ b/drivers/usb/atm/usbatm.c
@@ -602,8 +602,12 @@ static int usbatm_atm_send(struct atm_vcc *vcc, struct sk_buff *skb)
602 602
603 vdbg("%s called (skb 0x%p, len %u)", __func__, skb, skb->len); 603 vdbg("%s called (skb 0x%p, len %u)", __func__, skb, skb->len);
604 604
605 if (!instance) { 605 /* racy disconnection check - fine */
606 dbg("%s: NULL data!", __func__); 606 if (!instance || instance->disconnected) {
607#ifdef DEBUG
608 if (printk_ratelimit())
609 printk(KERN_DEBUG "%s: %s!\n", __func__, instance ? "disconnected" : "NULL instance");
610#endif
607 err = -ENODEV; 611 err = -ENODEV;
608 goto fail; 612 goto fail;
609 } 613 }
@@ -715,15 +719,19 @@ static int usbatm_atm_proc_read(struct atm_dev *atm_dev, loff_t * pos, char *pag
715 atomic_read(&atm_dev->stats.aal5.rx_err), 719 atomic_read(&atm_dev->stats.aal5.rx_err),
716 atomic_read(&atm_dev->stats.aal5.rx_drop)); 720 atomic_read(&atm_dev->stats.aal5.rx_drop));
717 721
718 if (!left--) 722 if (!left--) {
719 switch (atm_dev->signal) { 723 if (instance->disconnected)
720 case ATM_PHY_SIG_FOUND: 724 return sprintf(page, "Disconnected\n");
721 return sprintf(page, "Line up\n"); 725 else
722 case ATM_PHY_SIG_LOST: 726 switch (atm_dev->signal) {
723 return sprintf(page, "Line down\n"); 727 case ATM_PHY_SIG_FOUND:
724 default: 728 return sprintf(page, "Line up\n");
725 return sprintf(page, "Line state unknown\n"); 729 case ATM_PHY_SIG_LOST:
726 } 730 return sprintf(page, "Line down\n");
731 default:
732 return sprintf(page, "Line state unknown\n");
733 }
734 }
727 735
728 return 0; 736 return 0;
729} 737}
@@ -757,6 +765,12 @@ static int usbatm_atm_open(struct atm_vcc *vcc)
757 765
758 down(&instance->serialize); /* vs self, usbatm_atm_close, usbatm_usb_disconnect */ 766 down(&instance->serialize); /* vs self, usbatm_atm_close, usbatm_usb_disconnect */
759 767
768 if (instance->disconnected) {
769 atm_dbg(instance, "%s: disconnected!\n", __func__);
770 ret = -ENODEV;
771 goto fail;
772 }
773
760 if (usbatm_find_vcc(instance, vpi, vci)) { 774 if (usbatm_find_vcc(instance, vpi, vci)) {
761 atm_dbg(instance, "%s: %hd/%d already in use!\n", __func__, vpi, vci); 775 atm_dbg(instance, "%s: %hd/%d already in use!\n", __func__, vpi, vci);
762 ret = -EADDRINUSE; 776 ret = -EADDRINUSE;
@@ -845,6 +859,13 @@ static void usbatm_atm_close(struct atm_vcc *vcc)
845static int usbatm_atm_ioctl(struct atm_dev *atm_dev, unsigned int cmd, 859static int usbatm_atm_ioctl(struct atm_dev *atm_dev, unsigned int cmd,
846 void __user * arg) 860 void __user * arg)
847{ 861{
862 struct usbatm_data *instance = atm_dev->dev_data;
863
864 if (!instance || instance->disconnected) {
865 dbg("%s: %s!", __func__, instance ? "disconnected" : "NULL instance");
866 return -ENODEV;
867 }
868
848 switch (cmd) { 869 switch (cmd) {
849 case ATM_QUERYLOOP: 870 case ATM_QUERYLOOP:
850 return put_user(ATM_LM_NONE, (int __user *)arg) ? -EFAULT : 0; 871 return put_user(ATM_LM_NONE, (int __user *)arg) ? -EFAULT : 0;
@@ -1129,6 +1150,7 @@ void usbatm_usb_disconnect(struct usb_interface *intf)
1129{ 1150{
1130 struct device *dev = &intf->dev; 1151 struct device *dev = &intf->dev;
1131 struct usbatm_data *instance = usb_get_intfdata(intf); 1152 struct usbatm_data *instance = usb_get_intfdata(intf);
1153 struct usbatm_vcc_data *vcc_data;
1132 int i; 1154 int i;
1133 1155
1134 dev_dbg(dev, "%s entered\n", __func__); 1156 dev_dbg(dev, "%s entered\n", __func__);
@@ -1141,12 +1163,18 @@ void usbatm_usb_disconnect(struct usb_interface *intf)
1141 usb_set_intfdata(intf, NULL); 1163 usb_set_intfdata(intf, NULL);
1142 1164
1143 down(&instance->serialize); 1165 down(&instance->serialize);
1166 instance->disconnected = 1;
1144 if (instance->thread_pid >= 0) 1167 if (instance->thread_pid >= 0)
1145 kill_proc(instance->thread_pid, SIGTERM, 1); 1168 kill_proc(instance->thread_pid, SIGTERM, 1);
1146 up(&instance->serialize); 1169 up(&instance->serialize);
1147 1170
1148 wait_for_completion(&instance->thread_exited); 1171 wait_for_completion(&instance->thread_exited);
1149 1172
1173 down(&instance->serialize);
1174 list_for_each_entry(vcc_data, &instance->vcc_list, list)
1175 vcc_release_async(vcc_data->vcc, -EPIPE);
1176 up(&instance->serialize);
1177
1150 tasklet_disable(&instance->rx_channel.tasklet); 1178 tasklet_disable(&instance->rx_channel.tasklet);
1151 tasklet_disable(&instance->tx_channel.tasklet); 1179 tasklet_disable(&instance->tx_channel.tasklet);
1152 1180
@@ -1156,6 +1184,14 @@ void usbatm_usb_disconnect(struct usb_interface *intf)
1156 del_timer_sync(&instance->rx_channel.delay); 1184 del_timer_sync(&instance->rx_channel.delay);
1157 del_timer_sync(&instance->tx_channel.delay); 1185 del_timer_sync(&instance->tx_channel.delay);
1158 1186
1187 /* turn usbatm_[rt]x_process into something close to a no-op */
1188 /* no need to take the spinlock */
1189 INIT_LIST_HEAD(&instance->rx_channel.list);
1190 INIT_LIST_HEAD(&instance->tx_channel.list);
1191
1192 tasklet_enable(&instance->rx_channel.tasklet);
1193 tasklet_enable(&instance->tx_channel.tasklet);
1194
1159 if (instance->atm_dev && instance->driver->atm_stop) 1195 if (instance->atm_dev && instance->driver->atm_stop)
1160 instance->driver->atm_stop(instance, instance->atm_dev); 1196 instance->driver->atm_stop(instance, instance->atm_dev);
1161 1197
@@ -1164,14 +1200,6 @@ void usbatm_usb_disconnect(struct usb_interface *intf)
1164 1200
1165 instance->driver_data = NULL; 1201 instance->driver_data = NULL;
1166 1202
1167 /* turn usbatm_[rt]x_process into noop */
1168 /* no need to take the spinlock */
1169 INIT_LIST_HEAD(&instance->rx_channel.list);
1170 INIT_LIST_HEAD(&instance->tx_channel.list);
1171
1172 tasklet_enable(&instance->rx_channel.tasklet);
1173 tasklet_enable(&instance->tx_channel.tasklet);
1174
1175 for (i = 0; i < num_rcv_urbs + num_snd_urbs; i++) { 1203 for (i = 0; i < num_rcv_urbs + num_snd_urbs; i++) {
1176 kfree(instance->urbs[i]->transfer_buffer); 1204 kfree(instance->urbs[i]->transfer_buffer);
1177 usb_free_urb(instance->urbs[i]); 1205 usb_free_urb(instance->urbs[i]);