diff options
-rw-r--r-- | drivers/atm/solos-pci.c | 83 | ||||
-rw-r--r-- | include/linux/atmdev.h | 2 | ||||
-rw-r--r-- | net/atm/br2684.c | 55 | ||||
-rw-r--r-- | net/atm/common.c | 12 | ||||
-rw-r--r-- | net/atm/pppoatm.c | 68 |
5 files changed, 158 insertions, 62 deletions
diff --git a/drivers/atm/solos-pci.c b/drivers/atm/solos-pci.c index 98510931c815..6619a8a9607c 100644 --- a/drivers/atm/solos-pci.c +++ b/drivers/atm/solos-pci.c | |||
@@ -164,7 +164,6 @@ static void fpga_queue(struct solos_card *card, int port, struct sk_buff *skb, | |||
164 | static uint32_t fpga_tx(struct solos_card *); | 164 | static uint32_t fpga_tx(struct solos_card *); |
165 | static irqreturn_t solos_irq(int irq, void *dev_id); | 165 | static irqreturn_t solos_irq(int irq, void *dev_id); |
166 | static struct atm_vcc* find_vcc(struct atm_dev *dev, short vpi, int vci); | 166 | static struct atm_vcc* find_vcc(struct atm_dev *dev, short vpi, int vci); |
167 | static int list_vccs(int vci); | ||
168 | static int atm_init(struct solos_card *, struct device *); | 167 | static int atm_init(struct solos_card *, struct device *); |
169 | static void atm_remove(struct solos_card *); | 168 | static void atm_remove(struct solos_card *); |
170 | static int send_command(struct solos_card *card, int dev, const char *buf, size_t size); | 169 | static int send_command(struct solos_card *card, int dev, const char *buf, size_t size); |
@@ -710,7 +709,8 @@ void solos_bh(unsigned long card_arg) | |||
710 | dev_warn(&card->dev->dev, "Received packet for unknown VPI.VCI %d.%d on port %d\n", | 709 | dev_warn(&card->dev->dev, "Received packet for unknown VPI.VCI %d.%d on port %d\n", |
711 | le16_to_cpu(header->vpi), le16_to_cpu(header->vci), | 710 | le16_to_cpu(header->vpi), le16_to_cpu(header->vci), |
712 | port); | 711 | port); |
713 | continue; | 712 | dev_kfree_skb_any(skb); |
713 | break; | ||
714 | } | 714 | } |
715 | atm_charge(vcc, skb->truesize); | 715 | atm_charge(vcc, skb->truesize); |
716 | vcc->push(vcc, skb); | 716 | vcc->push(vcc, skb); |
@@ -790,44 +790,6 @@ static struct atm_vcc *find_vcc(struct atm_dev *dev, short vpi, int vci) | |||
790 | return vcc; | 790 | return vcc; |
791 | } | 791 | } |
792 | 792 | ||
793 | static int list_vccs(int vci) | ||
794 | { | ||
795 | struct hlist_head *head; | ||
796 | struct atm_vcc *vcc; | ||
797 | struct hlist_node *node; | ||
798 | struct sock *s; | ||
799 | int num_found = 0; | ||
800 | int i; | ||
801 | |||
802 | read_lock(&vcc_sklist_lock); | ||
803 | if (vci != 0){ | ||
804 | head = &vcc_hash[vci & (VCC_HTABLE_SIZE -1)]; | ||
805 | sk_for_each(s, node, head) { | ||
806 | num_found ++; | ||
807 | vcc = atm_sk(s); | ||
808 | printk(KERN_DEBUG "Device: %d Vpi: %d Vci: %d\n", | ||
809 | vcc->dev->number, | ||
810 | vcc->vpi, | ||
811 | vcc->vci); | ||
812 | } | ||
813 | } else { | ||
814 | for(i = 0; i < VCC_HTABLE_SIZE; i++){ | ||
815 | head = &vcc_hash[i]; | ||
816 | sk_for_each(s, node, head) { | ||
817 | num_found ++; | ||
818 | vcc = atm_sk(s); | ||
819 | printk(KERN_DEBUG "Device: %d Vpi: %d Vci: %d\n", | ||
820 | vcc->dev->number, | ||
821 | vcc->vpi, | ||
822 | vcc->vci); | ||
823 | } | ||
824 | } | ||
825 | } | ||
826 | read_unlock(&vcc_sklist_lock); | ||
827 | return num_found; | ||
828 | } | ||
829 | |||
830 | |||
831 | static int popen(struct atm_vcc *vcc) | 793 | static int popen(struct atm_vcc *vcc) |
832 | { | 794 | { |
833 | struct solos_card *card = vcc->dev->dev_data; | 795 | struct solos_card *card = vcc->dev->dev_data; |
@@ -840,7 +802,7 @@ static int popen(struct atm_vcc *vcc) | |||
840 | return -EINVAL; | 802 | return -EINVAL; |
841 | } | 803 | } |
842 | 804 | ||
843 | skb = alloc_skb(sizeof(*header), GFP_ATOMIC); | 805 | skb = alloc_skb(sizeof(*header), GFP_KERNEL); |
844 | if (!skb) { | 806 | if (!skb) { |
845 | if (net_ratelimit()) | 807 | if (net_ratelimit()) |
846 | dev_warn(&card->dev->dev, "Failed to allocate sk_buff in popen()\n"); | 808 | dev_warn(&card->dev->dev, "Failed to allocate sk_buff in popen()\n"); |
@@ -857,8 +819,6 @@ static int popen(struct atm_vcc *vcc) | |||
857 | 819 | ||
858 | set_bit(ATM_VF_ADDR, &vcc->flags); | 820 | set_bit(ATM_VF_ADDR, &vcc->flags); |
859 | set_bit(ATM_VF_READY, &vcc->flags); | 821 | set_bit(ATM_VF_READY, &vcc->flags); |
860 | list_vccs(0); | ||
861 | |||
862 | 822 | ||
863 | return 0; | 823 | return 0; |
864 | } | 824 | } |
@@ -866,10 +826,21 @@ static int popen(struct atm_vcc *vcc) | |||
866 | static void pclose(struct atm_vcc *vcc) | 826 | static void pclose(struct atm_vcc *vcc) |
867 | { | 827 | { |
868 | struct solos_card *card = vcc->dev->dev_data; | 828 | struct solos_card *card = vcc->dev->dev_data; |
869 | struct sk_buff *skb; | 829 | unsigned char port = SOLOS_CHAN(vcc->dev); |
830 | struct sk_buff *skb, *tmpskb; | ||
870 | struct pkt_hdr *header; | 831 | struct pkt_hdr *header; |
871 | 832 | ||
872 | skb = alloc_skb(sizeof(*header), GFP_ATOMIC); | 833 | /* Remove any yet-to-be-transmitted packets from the pending queue */ |
834 | spin_lock(&card->tx_queue_lock); | ||
835 | skb_queue_walk_safe(&card->tx_queue[port], skb, tmpskb) { | ||
836 | if (SKB_CB(skb)->vcc == vcc) { | ||
837 | skb_unlink(skb, &card->tx_queue[port]); | ||
838 | solos_pop(vcc, skb); | ||
839 | } | ||
840 | } | ||
841 | spin_unlock(&card->tx_queue_lock); | ||
842 | |||
843 | skb = alloc_skb(sizeof(*header), GFP_KERNEL); | ||
873 | if (!skb) { | 844 | if (!skb) { |
874 | dev_warn(&card->dev->dev, "Failed to allocate sk_buff in pclose()\n"); | 845 | dev_warn(&card->dev->dev, "Failed to allocate sk_buff in pclose()\n"); |
875 | return; | 846 | return; |
@@ -881,15 +852,22 @@ static void pclose(struct atm_vcc *vcc) | |||
881 | header->vci = cpu_to_le16(vcc->vci); | 852 | header->vci = cpu_to_le16(vcc->vci); |
882 | header->type = cpu_to_le16(PKT_PCLOSE); | 853 | header->type = cpu_to_le16(PKT_PCLOSE); |
883 | 854 | ||
884 | fpga_queue(card, SOLOS_CHAN(vcc->dev), skb, NULL); | 855 | skb_get(skb); |
856 | fpga_queue(card, port, skb, NULL); | ||
885 | 857 | ||
886 | clear_bit(ATM_VF_ADDR, &vcc->flags); | 858 | if (!wait_event_timeout(card->param_wq, !skb_shared(skb), 5 * HZ)) |
887 | clear_bit(ATM_VF_READY, &vcc->flags); | 859 | dev_warn(&card->dev->dev, |
860 | "Timeout waiting for VCC close on port %d\n", port); | ||
861 | |||
862 | dev_kfree_skb(skb); | ||
888 | 863 | ||
889 | /* Hold up vcc_destroy_socket() (our caller) until solos_bh() in the | 864 | /* Hold up vcc_destroy_socket() (our caller) until solos_bh() in the |
890 | tasklet has finished processing any incoming packets (and, more to | 865 | tasklet has finished processing any incoming packets (and, more to |
891 | the point, using the vcc pointer). */ | 866 | the point, using the vcc pointer). */ |
892 | tasklet_unlock_wait(&card->tlet); | 867 | tasklet_unlock_wait(&card->tlet); |
868 | |||
869 | clear_bit(ATM_VF_ADDR, &vcc->flags); | ||
870 | |||
893 | return; | 871 | return; |
894 | } | 872 | } |
895 | 873 | ||
@@ -1011,9 +989,10 @@ static uint32_t fpga_tx(struct solos_card *card) | |||
1011 | if (vcc) { | 989 | if (vcc) { |
1012 | atomic_inc(&vcc->stats->tx); | 990 | atomic_inc(&vcc->stats->tx); |
1013 | solos_pop(vcc, oldskb); | 991 | solos_pop(vcc, oldskb); |
1014 | } else | 992 | } else { |
1015 | dev_kfree_skb_irq(oldskb); | 993 | dev_kfree_skb_irq(oldskb); |
1016 | 994 | wake_up(&card->param_wq); | |
995 | } | ||
1017 | } | 996 | } |
1018 | } | 997 | } |
1019 | /* For non-DMA TX, write the 'TX start' bit for all four ports simultaneously */ | 998 | /* For non-DMA TX, write the 'TX start' bit for all four ports simultaneously */ |
@@ -1248,7 +1227,7 @@ static int atm_init(struct solos_card *card, struct device *parent) | |||
1248 | card->atmdev[i]->phy_data = (void *)(unsigned long)i; | 1227 | card->atmdev[i]->phy_data = (void *)(unsigned long)i; |
1249 | atm_dev_signal_change(card->atmdev[i], ATM_PHY_SIG_FOUND); | 1228 | atm_dev_signal_change(card->atmdev[i], ATM_PHY_SIG_FOUND); |
1250 | 1229 | ||
1251 | skb = alloc_skb(sizeof(*header), GFP_ATOMIC); | 1230 | skb = alloc_skb(sizeof(*header), GFP_KERNEL); |
1252 | if (!skb) { | 1231 | if (!skb) { |
1253 | dev_warn(&card->dev->dev, "Failed to allocate sk_buff in atm_init()\n"); | 1232 | dev_warn(&card->dev->dev, "Failed to allocate sk_buff in atm_init()\n"); |
1254 | continue; | 1233 | continue; |
@@ -1345,6 +1324,8 @@ static struct pci_driver fpga_driver = { | |||
1345 | 1324 | ||
1346 | static int __init solos_pci_init(void) | 1325 | static int __init solos_pci_init(void) |
1347 | { | 1326 | { |
1327 | BUILD_BUG_ON(sizeof(struct solos_skb_cb) > sizeof(((struct sk_buff *)0)->cb)); | ||
1328 | |||
1348 | printk(KERN_INFO "Solos PCI Driver Version %s\n", VERSION); | 1329 | printk(KERN_INFO "Solos PCI Driver Version %s\n", VERSION); |
1349 | return pci_register_driver(&fpga_driver); | 1330 | return pci_register_driver(&fpga_driver); |
1350 | } | 1331 | } |
diff --git a/include/linux/atmdev.h b/include/linux/atmdev.h index 22ef21c33d0c..c1da539f5e28 100644 --- a/include/linux/atmdev.h +++ b/include/linux/atmdev.h | |||
@@ -99,6 +99,7 @@ struct atm_vcc { | |||
99 | struct atm_dev *dev; /* device back pointer */ | 99 | struct atm_dev *dev; /* device back pointer */ |
100 | struct atm_qos qos; /* QOS */ | 100 | struct atm_qos qos; /* QOS */ |
101 | struct atm_sap sap; /* SAP */ | 101 | struct atm_sap sap; /* SAP */ |
102 | void (*release_cb)(struct atm_vcc *vcc); /* release_sock callback */ | ||
102 | void (*push)(struct atm_vcc *vcc,struct sk_buff *skb); | 103 | void (*push)(struct atm_vcc *vcc,struct sk_buff *skb); |
103 | void (*pop)(struct atm_vcc *vcc,struct sk_buff *skb); /* optional */ | 104 | void (*pop)(struct atm_vcc *vcc,struct sk_buff *skb); /* optional */ |
104 | int (*push_oam)(struct atm_vcc *vcc,void *cell); | 105 | int (*push_oam)(struct atm_vcc *vcc,void *cell); |
@@ -106,6 +107,7 @@ struct atm_vcc { | |||
106 | void *dev_data; /* per-device data */ | 107 | void *dev_data; /* per-device data */ |
107 | void *proto_data; /* per-protocol data */ | 108 | void *proto_data; /* per-protocol data */ |
108 | struct k_atm_aal_stats *stats; /* pointer to AAL stats group */ | 109 | struct k_atm_aal_stats *stats; /* pointer to AAL stats group */ |
110 | struct module *owner; /* owner of ->push function */ | ||
109 | /* SVC part --- may move later ------------------------------------- */ | 111 | /* SVC part --- may move later ------------------------------------- */ |
110 | short itf; /* interface number */ | 112 | short itf; /* interface number */ |
111 | struct sockaddr_atmsvc local; | 113 | struct sockaddr_atmsvc local; |
diff --git a/net/atm/br2684.c b/net/atm/br2684.c index 8eb6fbe8d8dd..403e71fa88fe 100644 --- a/net/atm/br2684.c +++ b/net/atm/br2684.c | |||
@@ -68,6 +68,8 @@ struct br2684_vcc { | |||
68 | /* keep old push, pop functions for chaining */ | 68 | /* keep old push, pop functions for chaining */ |
69 | void (*old_push)(struct atm_vcc *vcc, struct sk_buff *skb); | 69 | void (*old_push)(struct atm_vcc *vcc, struct sk_buff *skb); |
70 | void (*old_pop)(struct atm_vcc *vcc, struct sk_buff *skb); | 70 | void (*old_pop)(struct atm_vcc *vcc, struct sk_buff *skb); |
71 | void (*old_release_cb)(struct atm_vcc *vcc); | ||
72 | struct module *old_owner; | ||
71 | enum br2684_encaps encaps; | 73 | enum br2684_encaps encaps; |
72 | struct list_head brvccs; | 74 | struct list_head brvccs; |
73 | #ifdef CONFIG_ATM_BR2684_IPFILTER | 75 | #ifdef CONFIG_ATM_BR2684_IPFILTER |
@@ -269,6 +271,17 @@ static int br2684_xmit_vcc(struct sk_buff *skb, struct net_device *dev, | |||
269 | return !atmvcc->send(atmvcc, skb); | 271 | return !atmvcc->send(atmvcc, skb); |
270 | } | 272 | } |
271 | 273 | ||
274 | static void br2684_release_cb(struct atm_vcc *atmvcc) | ||
275 | { | ||
276 | struct br2684_vcc *brvcc = BR2684_VCC(atmvcc); | ||
277 | |||
278 | if (atomic_read(&brvcc->qspace) > 0) | ||
279 | netif_wake_queue(brvcc->device); | ||
280 | |||
281 | if (brvcc->old_release_cb) | ||
282 | brvcc->old_release_cb(atmvcc); | ||
283 | } | ||
284 | |||
272 | static inline struct br2684_vcc *pick_outgoing_vcc(const struct sk_buff *skb, | 285 | static inline struct br2684_vcc *pick_outgoing_vcc(const struct sk_buff *skb, |
273 | const struct br2684_dev *brdev) | 286 | const struct br2684_dev *brdev) |
274 | { | 287 | { |
@@ -280,6 +293,8 @@ static netdev_tx_t br2684_start_xmit(struct sk_buff *skb, | |||
280 | { | 293 | { |
281 | struct br2684_dev *brdev = BRPRIV(dev); | 294 | struct br2684_dev *brdev = BRPRIV(dev); |
282 | struct br2684_vcc *brvcc; | 295 | struct br2684_vcc *brvcc; |
296 | struct atm_vcc *atmvcc; | ||
297 | netdev_tx_t ret = NETDEV_TX_OK; | ||
283 | 298 | ||
284 | pr_debug("skb_dst(skb)=%p\n", skb_dst(skb)); | 299 | pr_debug("skb_dst(skb)=%p\n", skb_dst(skb)); |
285 | read_lock(&devs_lock); | 300 | read_lock(&devs_lock); |
@@ -290,9 +305,26 @@ static netdev_tx_t br2684_start_xmit(struct sk_buff *skb, | |||
290 | dev->stats.tx_carrier_errors++; | 305 | dev->stats.tx_carrier_errors++; |
291 | /* netif_stop_queue(dev); */ | 306 | /* netif_stop_queue(dev); */ |
292 | dev_kfree_skb(skb); | 307 | dev_kfree_skb(skb); |
293 | read_unlock(&devs_lock); | 308 | goto out_devs; |
294 | return NETDEV_TX_OK; | ||
295 | } | 309 | } |
310 | atmvcc = brvcc->atmvcc; | ||
311 | |||
312 | bh_lock_sock(sk_atm(atmvcc)); | ||
313 | |||
314 | if (test_bit(ATM_VF_RELEASED, &atmvcc->flags) || | ||
315 | test_bit(ATM_VF_CLOSE, &atmvcc->flags) || | ||
316 | !test_bit(ATM_VF_READY, &atmvcc->flags)) { | ||
317 | dev->stats.tx_dropped++; | ||
318 | dev_kfree_skb(skb); | ||
319 | goto out; | ||
320 | } | ||
321 | |||
322 | if (sock_owned_by_user(sk_atm(atmvcc))) { | ||
323 | netif_stop_queue(brvcc->device); | ||
324 | ret = NETDEV_TX_BUSY; | ||
325 | goto out; | ||
326 | } | ||
327 | |||
296 | if (!br2684_xmit_vcc(skb, dev, brvcc)) { | 328 | if (!br2684_xmit_vcc(skb, dev, brvcc)) { |
297 | /* | 329 | /* |
298 | * We should probably use netif_*_queue() here, but that | 330 | * We should probably use netif_*_queue() here, but that |
@@ -304,8 +336,11 @@ static netdev_tx_t br2684_start_xmit(struct sk_buff *skb, | |||
304 | dev->stats.tx_errors++; | 336 | dev->stats.tx_errors++; |
305 | dev->stats.tx_fifo_errors++; | 337 | dev->stats.tx_fifo_errors++; |
306 | } | 338 | } |
339 | out: | ||
340 | bh_unlock_sock(sk_atm(atmvcc)); | ||
341 | out_devs: | ||
307 | read_unlock(&devs_lock); | 342 | read_unlock(&devs_lock); |
308 | return NETDEV_TX_OK; | 343 | return ret; |
309 | } | 344 | } |
310 | 345 | ||
311 | /* | 346 | /* |
@@ -378,9 +413,10 @@ static void br2684_close_vcc(struct br2684_vcc *brvcc) | |||
378 | list_del(&brvcc->brvccs); | 413 | list_del(&brvcc->brvccs); |
379 | write_unlock_irq(&devs_lock); | 414 | write_unlock_irq(&devs_lock); |
380 | brvcc->atmvcc->user_back = NULL; /* what about vcc->recvq ??? */ | 415 | brvcc->atmvcc->user_back = NULL; /* what about vcc->recvq ??? */ |
416 | brvcc->atmvcc->release_cb = brvcc->old_release_cb; | ||
381 | brvcc->old_push(brvcc->atmvcc, NULL); /* pass on the bad news */ | 417 | brvcc->old_push(brvcc->atmvcc, NULL); /* pass on the bad news */ |
418 | module_put(brvcc->old_owner); | ||
382 | kfree(brvcc); | 419 | kfree(brvcc); |
383 | module_put(THIS_MODULE); | ||
384 | } | 420 | } |
385 | 421 | ||
386 | /* when AAL5 PDU comes in: */ | 422 | /* when AAL5 PDU comes in: */ |
@@ -554,9 +590,13 @@ static int br2684_regvcc(struct atm_vcc *atmvcc, void __user * arg) | |||
554 | brvcc->encaps = (enum br2684_encaps)be.encaps; | 590 | brvcc->encaps = (enum br2684_encaps)be.encaps; |
555 | brvcc->old_push = atmvcc->push; | 591 | brvcc->old_push = atmvcc->push; |
556 | brvcc->old_pop = atmvcc->pop; | 592 | brvcc->old_pop = atmvcc->pop; |
593 | brvcc->old_release_cb = atmvcc->release_cb; | ||
594 | brvcc->old_owner = atmvcc->owner; | ||
557 | barrier(); | 595 | barrier(); |
558 | atmvcc->push = br2684_push; | 596 | atmvcc->push = br2684_push; |
559 | atmvcc->pop = br2684_pop; | 597 | atmvcc->pop = br2684_pop; |
598 | atmvcc->release_cb = br2684_release_cb; | ||
599 | atmvcc->owner = THIS_MODULE; | ||
560 | 600 | ||
561 | /* initialize netdev carrier state */ | 601 | /* initialize netdev carrier state */ |
562 | if (atmvcc->dev->signal == ATM_PHY_SIG_LOST) | 602 | if (atmvcc->dev->signal == ATM_PHY_SIG_LOST) |
@@ -695,10 +735,13 @@ static int br2684_ioctl(struct socket *sock, unsigned int cmd, | |||
695 | return -ENOIOCTLCMD; | 735 | return -ENOIOCTLCMD; |
696 | if (!capable(CAP_NET_ADMIN)) | 736 | if (!capable(CAP_NET_ADMIN)) |
697 | return -EPERM; | 737 | return -EPERM; |
698 | if (cmd == ATM_SETBACKEND) | 738 | if (cmd == ATM_SETBACKEND) { |
739 | if (sock->state != SS_CONNECTED) | ||
740 | return -EINVAL; | ||
699 | return br2684_regvcc(atmvcc, argp); | 741 | return br2684_regvcc(atmvcc, argp); |
700 | else | 742 | } else { |
701 | return br2684_create(argp); | 743 | return br2684_create(argp); |
744 | } | ||
702 | #ifdef CONFIG_ATM_BR2684_IPFILTER | 745 | #ifdef CONFIG_ATM_BR2684_IPFILTER |
703 | case BR2684_SETFILT: | 746 | case BR2684_SETFILT: |
704 | if (atmvcc->push != br2684_push) | 747 | if (atmvcc->push != br2684_push) |
diff --git a/net/atm/common.c b/net/atm/common.c index 0c0ad930a632..806fc0a40051 100644 --- a/net/atm/common.c +++ b/net/atm/common.c | |||
@@ -126,10 +126,19 @@ static void vcc_write_space(struct sock *sk) | |||
126 | rcu_read_unlock(); | 126 | rcu_read_unlock(); |
127 | } | 127 | } |
128 | 128 | ||
129 | static void vcc_release_cb(struct sock *sk) | ||
130 | { | ||
131 | struct atm_vcc *vcc = atm_sk(sk); | ||
132 | |||
133 | if (vcc->release_cb) | ||
134 | vcc->release_cb(vcc); | ||
135 | } | ||
136 | |||
129 | static struct proto vcc_proto = { | 137 | static struct proto vcc_proto = { |
130 | .name = "VCC", | 138 | .name = "VCC", |
131 | .owner = THIS_MODULE, | 139 | .owner = THIS_MODULE, |
132 | .obj_size = sizeof(struct atm_vcc), | 140 | .obj_size = sizeof(struct atm_vcc), |
141 | .release_cb = vcc_release_cb, | ||
133 | }; | 142 | }; |
134 | 143 | ||
135 | int vcc_create(struct net *net, struct socket *sock, int protocol, int family) | 144 | int vcc_create(struct net *net, struct socket *sock, int protocol, int family) |
@@ -156,7 +165,9 @@ int vcc_create(struct net *net, struct socket *sock, int protocol, int family) | |||
156 | atomic_set(&sk->sk_rmem_alloc, 0); | 165 | atomic_set(&sk->sk_rmem_alloc, 0); |
157 | vcc->push = NULL; | 166 | vcc->push = NULL; |
158 | vcc->pop = NULL; | 167 | vcc->pop = NULL; |
168 | vcc->owner = NULL; | ||
159 | vcc->push_oam = NULL; | 169 | vcc->push_oam = NULL; |
170 | vcc->release_cb = NULL; | ||
160 | vcc->vpi = vcc->vci = 0; /* no VCI/VPI yet */ | 171 | vcc->vpi = vcc->vci = 0; /* no VCI/VPI yet */ |
161 | vcc->atm_options = vcc->aal_options = 0; | 172 | vcc->atm_options = vcc->aal_options = 0; |
162 | sk->sk_destruct = vcc_sock_destruct; | 173 | sk->sk_destruct = vcc_sock_destruct; |
@@ -175,6 +186,7 @@ static void vcc_destroy_socket(struct sock *sk) | |||
175 | vcc->dev->ops->close(vcc); | 186 | vcc->dev->ops->close(vcc); |
176 | if (vcc->push) | 187 | if (vcc->push) |
177 | vcc->push(vcc, NULL); /* atmarpd has no push */ | 188 | vcc->push(vcc, NULL); /* atmarpd has no push */ |
189 | module_put(vcc->owner); | ||
178 | 190 | ||
179 | while ((skb = skb_dequeue(&sk->sk_receive_queue)) != NULL) { | 191 | while ((skb = skb_dequeue(&sk->sk_receive_queue)) != NULL) { |
180 | atm_return(vcc, skb->truesize); | 192 | atm_return(vcc, skb->truesize); |
diff --git a/net/atm/pppoatm.c b/net/atm/pppoatm.c index 226dca989448..8c93267ce969 100644 --- a/net/atm/pppoatm.c +++ b/net/atm/pppoatm.c | |||
@@ -60,6 +60,8 @@ struct pppoatm_vcc { | |||
60 | struct atm_vcc *atmvcc; /* VCC descriptor */ | 60 | struct atm_vcc *atmvcc; /* VCC descriptor */ |
61 | void (*old_push)(struct atm_vcc *, struct sk_buff *); | 61 | void (*old_push)(struct atm_vcc *, struct sk_buff *); |
62 | void (*old_pop)(struct atm_vcc *, struct sk_buff *); | 62 | void (*old_pop)(struct atm_vcc *, struct sk_buff *); |
63 | void (*old_release_cb)(struct atm_vcc *); | ||
64 | struct module *old_owner; | ||
63 | /* keep old push/pop for detaching */ | 65 | /* keep old push/pop for detaching */ |
64 | enum pppoatm_encaps encaps; | 66 | enum pppoatm_encaps encaps; |
65 | atomic_t inflight; | 67 | atomic_t inflight; |
@@ -107,6 +109,24 @@ static void pppoatm_wakeup_sender(unsigned long arg) | |||
107 | ppp_output_wakeup((struct ppp_channel *) arg); | 109 | ppp_output_wakeup((struct ppp_channel *) arg); |
108 | } | 110 | } |
109 | 111 | ||
112 | static void pppoatm_release_cb(struct atm_vcc *atmvcc) | ||
113 | { | ||
114 | struct pppoatm_vcc *pvcc = atmvcc_to_pvcc(atmvcc); | ||
115 | |||
116 | /* | ||
117 | * As in pppoatm_pop(), it's safe to clear the BLOCKED bit here because | ||
118 | * the wakeup *can't* race with pppoatm_send(). They both hold the PPP | ||
119 | * channel's ->downl lock. And the potential race with *setting* it, | ||
120 | * which leads to the double-check dance in pppoatm_may_send(), doesn't | ||
121 | * exist here. In the sock_owned_by_user() case in pppoatm_send(), we | ||
122 | * set the BLOCKED bit while the socket is still locked. We know that | ||
123 | * ->release_cb() can't be called until that's done. | ||
124 | */ | ||
125 | if (test_and_clear_bit(BLOCKED, &pvcc->blocked)) | ||
126 | tasklet_schedule(&pvcc->wakeup_tasklet); | ||
127 | if (pvcc->old_release_cb) | ||
128 | pvcc->old_release_cb(atmvcc); | ||
129 | } | ||
110 | /* | 130 | /* |
111 | * This gets called every time the ATM card has finished sending our | 131 | * This gets called every time the ATM card has finished sending our |
112 | * skb. The ->old_pop will take care up normal atm flow control, | 132 | * skb. The ->old_pop will take care up normal atm flow control, |
@@ -151,12 +171,11 @@ static void pppoatm_unassign_vcc(struct atm_vcc *atmvcc) | |||
151 | pvcc = atmvcc_to_pvcc(atmvcc); | 171 | pvcc = atmvcc_to_pvcc(atmvcc); |
152 | atmvcc->push = pvcc->old_push; | 172 | atmvcc->push = pvcc->old_push; |
153 | atmvcc->pop = pvcc->old_pop; | 173 | atmvcc->pop = pvcc->old_pop; |
174 | atmvcc->release_cb = pvcc->old_release_cb; | ||
154 | tasklet_kill(&pvcc->wakeup_tasklet); | 175 | tasklet_kill(&pvcc->wakeup_tasklet); |
155 | ppp_unregister_channel(&pvcc->chan); | 176 | ppp_unregister_channel(&pvcc->chan); |
156 | atmvcc->user_back = NULL; | 177 | atmvcc->user_back = NULL; |
157 | kfree(pvcc); | 178 | kfree(pvcc); |
158 | /* Gee, I hope we have the big kernel lock here... */ | ||
159 | module_put(THIS_MODULE); | ||
160 | } | 179 | } |
161 | 180 | ||
162 | /* Called when an AAL5 PDU comes in */ | 181 | /* Called when an AAL5 PDU comes in */ |
@@ -165,9 +184,13 @@ static void pppoatm_push(struct atm_vcc *atmvcc, struct sk_buff *skb) | |||
165 | struct pppoatm_vcc *pvcc = atmvcc_to_pvcc(atmvcc); | 184 | struct pppoatm_vcc *pvcc = atmvcc_to_pvcc(atmvcc); |
166 | pr_debug("\n"); | 185 | pr_debug("\n"); |
167 | if (skb == NULL) { /* VCC was closed */ | 186 | if (skb == NULL) { /* VCC was closed */ |
187 | struct module *module; | ||
188 | |||
168 | pr_debug("removing ATMPPP VCC %p\n", pvcc); | 189 | pr_debug("removing ATMPPP VCC %p\n", pvcc); |
190 | module = pvcc->old_owner; | ||
169 | pppoatm_unassign_vcc(atmvcc); | 191 | pppoatm_unassign_vcc(atmvcc); |
170 | atmvcc->push(atmvcc, NULL); /* Pass along bad news */ | 192 | atmvcc->push(atmvcc, NULL); /* Pass along bad news */ |
193 | module_put(module); | ||
171 | return; | 194 | return; |
172 | } | 195 | } |
173 | atm_return(atmvcc, skb->truesize); | 196 | atm_return(atmvcc, skb->truesize); |
@@ -211,7 +234,7 @@ error: | |||
211 | ppp_input_error(&pvcc->chan, 0); | 234 | ppp_input_error(&pvcc->chan, 0); |
212 | } | 235 | } |
213 | 236 | ||
214 | static inline int pppoatm_may_send(struct pppoatm_vcc *pvcc, int size) | 237 | static int pppoatm_may_send(struct pppoatm_vcc *pvcc, int size) |
215 | { | 238 | { |
216 | /* | 239 | /* |
217 | * It's not clear that we need to bother with using atm_may_send() | 240 | * It's not clear that we need to bother with using atm_may_send() |
@@ -269,10 +292,33 @@ static inline int pppoatm_may_send(struct pppoatm_vcc *pvcc, int size) | |||
269 | static int pppoatm_send(struct ppp_channel *chan, struct sk_buff *skb) | 292 | static int pppoatm_send(struct ppp_channel *chan, struct sk_buff *skb) |
270 | { | 293 | { |
271 | struct pppoatm_vcc *pvcc = chan_to_pvcc(chan); | 294 | struct pppoatm_vcc *pvcc = chan_to_pvcc(chan); |
295 | struct atm_vcc *vcc; | ||
296 | int ret; | ||
297 | |||
272 | ATM_SKB(skb)->vcc = pvcc->atmvcc; | 298 | ATM_SKB(skb)->vcc = pvcc->atmvcc; |
273 | pr_debug("(skb=0x%p, vcc=0x%p)\n", skb, pvcc->atmvcc); | 299 | pr_debug("(skb=0x%p, vcc=0x%p)\n", skb, pvcc->atmvcc); |
274 | if (skb->data[0] == '\0' && (pvcc->flags & SC_COMP_PROT)) | 300 | if (skb->data[0] == '\0' && (pvcc->flags & SC_COMP_PROT)) |
275 | (void) skb_pull(skb, 1); | 301 | (void) skb_pull(skb, 1); |
302 | |||
303 | vcc = ATM_SKB(skb)->vcc; | ||
304 | bh_lock_sock(sk_atm(vcc)); | ||
305 | if (sock_owned_by_user(sk_atm(vcc))) { | ||
306 | /* | ||
307 | * Needs to happen (and be flushed, hence test_and_) before we unlock | ||
308 | * the socket. It needs to be seen by the time our ->release_cb gets | ||
309 | * called. | ||
310 | */ | ||
311 | test_and_set_bit(BLOCKED, &pvcc->blocked); | ||
312 | goto nospace; | ||
313 | } | ||
314 | if (test_bit(ATM_VF_RELEASED, &vcc->flags) || | ||
315 | test_bit(ATM_VF_CLOSE, &vcc->flags) || | ||
316 | !test_bit(ATM_VF_READY, &vcc->flags)) { | ||
317 | bh_unlock_sock(sk_atm(vcc)); | ||
318 | kfree_skb(skb); | ||
319 | return DROP_PACKET; | ||
320 | } | ||
321 | |||
276 | switch (pvcc->encaps) { /* LLC encapsulation needed */ | 322 | switch (pvcc->encaps) { /* LLC encapsulation needed */ |
277 | case e_llc: | 323 | case e_llc: |
278 | if (skb_headroom(skb) < LLC_LEN) { | 324 | if (skb_headroom(skb) < LLC_LEN) { |
@@ -285,8 +331,10 @@ static int pppoatm_send(struct ppp_channel *chan, struct sk_buff *skb) | |||
285 | } | 331 | } |
286 | consume_skb(skb); | 332 | consume_skb(skb); |
287 | skb = n; | 333 | skb = n; |
288 | if (skb == NULL) | 334 | if (skb == NULL) { |
335 | bh_unlock_sock(sk_atm(vcc)); | ||
289 | return DROP_PACKET; | 336 | return DROP_PACKET; |
337 | } | ||
290 | } else if (!pppoatm_may_send(pvcc, skb->truesize)) | 338 | } else if (!pppoatm_may_send(pvcc, skb->truesize)) |
291 | goto nospace; | 339 | goto nospace; |
292 | memcpy(skb_push(skb, LLC_LEN), pppllc, LLC_LEN); | 340 | memcpy(skb_push(skb, LLC_LEN), pppllc, LLC_LEN); |
@@ -296,6 +344,7 @@ static int pppoatm_send(struct ppp_channel *chan, struct sk_buff *skb) | |||
296 | goto nospace; | 344 | goto nospace; |
297 | break; | 345 | break; |
298 | case e_autodetect: | 346 | case e_autodetect: |
347 | bh_unlock_sock(sk_atm(vcc)); | ||
299 | pr_debug("Trying to send without setting encaps!\n"); | 348 | pr_debug("Trying to send without setting encaps!\n"); |
300 | kfree_skb(skb); | 349 | kfree_skb(skb); |
301 | return 1; | 350 | return 1; |
@@ -305,9 +354,12 @@ static int pppoatm_send(struct ppp_channel *chan, struct sk_buff *skb) | |||
305 | ATM_SKB(skb)->atm_options = ATM_SKB(skb)->vcc->atm_options; | 354 | ATM_SKB(skb)->atm_options = ATM_SKB(skb)->vcc->atm_options; |
306 | pr_debug("atm_skb(%p)->vcc(%p)->dev(%p)\n", | 355 | pr_debug("atm_skb(%p)->vcc(%p)->dev(%p)\n", |
307 | skb, ATM_SKB(skb)->vcc, ATM_SKB(skb)->vcc->dev); | 356 | skb, ATM_SKB(skb)->vcc, ATM_SKB(skb)->vcc->dev); |
308 | return ATM_SKB(skb)->vcc->send(ATM_SKB(skb)->vcc, skb) | 357 | ret = ATM_SKB(skb)->vcc->send(ATM_SKB(skb)->vcc, skb) |
309 | ? DROP_PACKET : 1; | 358 | ? DROP_PACKET : 1; |
359 | bh_unlock_sock(sk_atm(vcc)); | ||
360 | return ret; | ||
310 | nospace: | 361 | nospace: |
362 | bh_unlock_sock(sk_atm(vcc)); | ||
311 | /* | 363 | /* |
312 | * We don't have space to send this SKB now, but we might have | 364 | * We don't have space to send this SKB now, but we might have |
313 | * already applied SC_COMP_PROT compression, so may need to undo | 365 | * already applied SC_COMP_PROT compression, so may need to undo |
@@ -362,6 +414,8 @@ static int pppoatm_assign_vcc(struct atm_vcc *atmvcc, void __user *arg) | |||
362 | atomic_set(&pvcc->inflight, NONE_INFLIGHT); | 414 | atomic_set(&pvcc->inflight, NONE_INFLIGHT); |
363 | pvcc->old_push = atmvcc->push; | 415 | pvcc->old_push = atmvcc->push; |
364 | pvcc->old_pop = atmvcc->pop; | 416 | pvcc->old_pop = atmvcc->pop; |
417 | pvcc->old_owner = atmvcc->owner; | ||
418 | pvcc->old_release_cb = atmvcc->release_cb; | ||
365 | pvcc->encaps = (enum pppoatm_encaps) be.encaps; | 419 | pvcc->encaps = (enum pppoatm_encaps) be.encaps; |
366 | pvcc->chan.private = pvcc; | 420 | pvcc->chan.private = pvcc; |
367 | pvcc->chan.ops = &pppoatm_ops; | 421 | pvcc->chan.ops = &pppoatm_ops; |
@@ -377,7 +431,9 @@ static int pppoatm_assign_vcc(struct atm_vcc *atmvcc, void __user *arg) | |||
377 | atmvcc->user_back = pvcc; | 431 | atmvcc->user_back = pvcc; |
378 | atmvcc->push = pppoatm_push; | 432 | atmvcc->push = pppoatm_push; |
379 | atmvcc->pop = pppoatm_pop; | 433 | atmvcc->pop = pppoatm_pop; |
434 | atmvcc->release_cb = pppoatm_release_cb; | ||
380 | __module_get(THIS_MODULE); | 435 | __module_get(THIS_MODULE); |
436 | atmvcc->owner = THIS_MODULE; | ||
381 | 437 | ||
382 | /* re-process everything received between connection setup and | 438 | /* re-process everything received between connection setup and |
383 | backend setup */ | 439 | backend setup */ |
@@ -406,6 +462,8 @@ static int pppoatm_ioctl(struct socket *sock, unsigned int cmd, | |||
406 | return -ENOIOCTLCMD; | 462 | return -ENOIOCTLCMD; |
407 | if (!capable(CAP_NET_ADMIN)) | 463 | if (!capable(CAP_NET_ADMIN)) |
408 | return -EPERM; | 464 | return -EPERM; |
465 | if (sock->state != SS_CONNECTED) | ||
466 | return -EINVAL; | ||
409 | return pppoatm_assign_vcc(atmvcc, argp); | 467 | return pppoatm_assign_vcc(atmvcc, argp); |
410 | } | 468 | } |
411 | case PPPIOCGCHAN: | 469 | case PPPIOCGCHAN: |