diff options
author | Duncan Sands <baldrick@free.fr> | 2006-01-13 04:05:15 -0500 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2006-01-31 20:23:39 -0500 |
commit | 0e42a627ec3d8defa0c43cff94b8f2080a070716 (patch) | |
tree | 5b22c24b224de444ddc6fd9b874a86624d41c227 /drivers/usb/atm/usbatm.c | |
parent | 233c08e0ff303e659a9003d49b15608f59f08a64 (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.c | 66 |
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) | |||
845 | static int usbatm_atm_ioctl(struct atm_dev *atm_dev, unsigned int cmd, | 859 | static 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]); |