diff options
Diffstat (limited to 'drivers/isdn/capi/capi.c')
-rw-r--r-- | drivers/isdn/capi/capi.c | 181 |
1 files changed, 88 insertions, 93 deletions
diff --git a/drivers/isdn/capi/capi.c b/drivers/isdn/capi/capi.c index 9d7c3692c7d7..403bf8fcb285 100644 --- a/drivers/isdn/capi/capi.c +++ b/drivers/isdn/capi/capi.c | |||
@@ -141,7 +141,7 @@ struct capidev { | |||
141 | 141 | ||
142 | struct capincci *nccis; | 142 | struct capincci *nccis; |
143 | 143 | ||
144 | struct mutex ncci_list_mtx; | 144 | struct mutex lock; |
145 | }; | 145 | }; |
146 | 146 | ||
147 | /* -------- global variables ---------------------------------------- */ | 147 | /* -------- global variables ---------------------------------------- */ |
@@ -574,38 +574,31 @@ static void capi_recv_message(struct capi20_appl *ap, struct sk_buff *skb) | |||
574 | u16 datahandle; | 574 | u16 datahandle; |
575 | #endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */ | 575 | #endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */ |
576 | struct capincci *np; | 576 | struct capincci *np; |
577 | u32 ncci; | ||
578 | unsigned long flags; | 577 | unsigned long flags; |
579 | 578 | ||
579 | mutex_lock(&cdev->lock); | ||
580 | |||
580 | if (CAPIMSG_CMD(skb->data) == CAPI_CONNECT_B3_CONF) { | 581 | if (CAPIMSG_CMD(skb->data) == CAPI_CONNECT_B3_CONF) { |
581 | u16 info = CAPIMSG_U16(skb->data, 12); // Info field | 582 | u16 info = CAPIMSG_U16(skb->data, 12); // Info field |
582 | if ((info & 0xff00) == 0) { | 583 | if ((info & 0xff00) == 0) |
583 | mutex_lock(&cdev->ncci_list_mtx); | ||
584 | capincci_alloc(cdev, CAPIMSG_NCCI(skb->data)); | 584 | capincci_alloc(cdev, CAPIMSG_NCCI(skb->data)); |
585 | mutex_unlock(&cdev->ncci_list_mtx); | ||
586 | } | ||
587 | } | 585 | } |
588 | if (CAPIMSG_CMD(skb->data) == CAPI_CONNECT_B3_IND) { | 586 | if (CAPIMSG_CMD(skb->data) == CAPI_CONNECT_B3_IND) |
589 | mutex_lock(&cdev->ncci_list_mtx); | ||
590 | capincci_alloc(cdev, CAPIMSG_NCCI(skb->data)); | 587 | capincci_alloc(cdev, CAPIMSG_NCCI(skb->data)); |
591 | mutex_unlock(&cdev->ncci_list_mtx); | 588 | |
592 | } | ||
593 | spin_lock_irqsave(&workaround_lock, flags); | 589 | spin_lock_irqsave(&workaround_lock, flags); |
594 | if (CAPIMSG_COMMAND(skb->data) != CAPI_DATA_B3) { | 590 | if (CAPIMSG_COMMAND(skb->data) != CAPI_DATA_B3) { |
595 | skb_queue_tail(&cdev->recvqueue, skb); | 591 | skb_queue_tail(&cdev->recvqueue, skb); |
596 | wake_up_interruptible(&cdev->recvwait); | 592 | wake_up_interruptible(&cdev->recvwait); |
597 | spin_unlock_irqrestore(&workaround_lock, flags); | 593 | goto unlock_out; |
598 | return; | ||
599 | } | 594 | } |
600 | ncci = CAPIMSG_CONTROL(skb->data); | 595 | |
601 | for (np = cdev->nccis; np && np->ncci != ncci; np = np->next) | 596 | np = capincci_find(cdev, CAPIMSG_CONTROL(skb->data)); |
602 | ; | ||
603 | if (!np) { | 597 | if (!np) { |
604 | printk(KERN_ERR "BUG: capi_signal: ncci not found\n"); | 598 | printk(KERN_ERR "BUG: capi_signal: ncci not found\n"); |
605 | skb_queue_tail(&cdev->recvqueue, skb); | 599 | skb_queue_tail(&cdev->recvqueue, skb); |
606 | wake_up_interruptible(&cdev->recvwait); | 600 | wake_up_interruptible(&cdev->recvwait); |
607 | spin_unlock_irqrestore(&workaround_lock, flags); | 601 | goto unlock_out; |
608 | return; | ||
609 | } | 602 | } |
610 | 603 | ||
611 | #ifndef CONFIG_ISDN_CAPI_MIDDLEWARE | 604 | #ifndef CONFIG_ISDN_CAPI_MIDDLEWARE |
@@ -618,8 +611,7 @@ static void capi_recv_message(struct capi20_appl *ap, struct sk_buff *skb) | |||
618 | if (!mp) { | 611 | if (!mp) { |
619 | skb_queue_tail(&cdev->recvqueue, skb); | 612 | skb_queue_tail(&cdev->recvqueue, skb); |
620 | wake_up_interruptible(&cdev->recvwait); | 613 | wake_up_interruptible(&cdev->recvwait); |
621 | spin_unlock_irqrestore(&workaround_lock, flags); | 614 | goto unlock_out; |
622 | return; | ||
623 | } | 615 | } |
624 | if (CAPIMSG_SUBCOMMAND(skb->data) == CAPI_IND) { | 616 | if (CAPIMSG_SUBCOMMAND(skb->data) == CAPI_IND) { |
625 | datahandle = CAPIMSG_U16(skb->data, CAPIMSG_BASELEN+4+4+2); | 617 | datahandle = CAPIMSG_U16(skb->data, CAPIMSG_BASELEN+4+4+2); |
@@ -652,7 +644,9 @@ static void capi_recv_message(struct capi20_appl *ap, struct sk_buff *skb) | |||
652 | } | 644 | } |
653 | #endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */ | 645 | #endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */ |
654 | 646 | ||
647 | unlock_out: | ||
655 | spin_unlock_irqrestore(&workaround_lock, flags); | 648 | spin_unlock_irqrestore(&workaround_lock, flags); |
649 | mutex_unlock(&cdev->lock); | ||
656 | } | 650 | } |
657 | 651 | ||
658 | /* -------- file_operations for capidev ----------------------------- */ | 652 | /* -------- file_operations for capidev ----------------------------- */ |
@@ -730,9 +724,9 @@ capi_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos | |||
730 | CAPIMSG_SETAPPID(skb->data, cdev->ap.applid); | 724 | CAPIMSG_SETAPPID(skb->data, cdev->ap.applid); |
731 | 725 | ||
732 | if (CAPIMSG_CMD(skb->data) == CAPI_DISCONNECT_B3_RESP) { | 726 | if (CAPIMSG_CMD(skb->data) == CAPI_DISCONNECT_B3_RESP) { |
733 | mutex_lock(&cdev->ncci_list_mtx); | 727 | mutex_lock(&cdev->lock); |
734 | capincci_free(cdev, CAPIMSG_NCCI(skb->data)); | 728 | capincci_free(cdev, CAPIMSG_NCCI(skb->data)); |
735 | mutex_unlock(&cdev->ncci_list_mtx); | 729 | mutex_unlock(&cdev->lock); |
736 | } | 730 | } |
737 | 731 | ||
738 | cdev->errcode = capi20_put_message(&cdev->ap, skb); | 732 | cdev->errcode = capi20_put_message(&cdev->ap, skb); |
@@ -765,30 +759,35 @@ capi_ioctl(struct inode *inode, struct file *file, | |||
765 | unsigned int cmd, unsigned long arg) | 759 | unsigned int cmd, unsigned long arg) |
766 | { | 760 | { |
767 | struct capidev *cdev = file->private_data; | 761 | struct capidev *cdev = file->private_data; |
768 | struct capi20_appl *ap = &cdev->ap; | ||
769 | capi_ioctl_struct data; | 762 | capi_ioctl_struct data; |
770 | int retval = -EINVAL; | 763 | int retval = -EINVAL; |
771 | void __user *argp = (void __user *)arg; | 764 | void __user *argp = (void __user *)arg; |
772 | 765 | ||
773 | switch (cmd) { | 766 | switch (cmd) { |
774 | case CAPI_REGISTER: | 767 | case CAPI_REGISTER: |
775 | { | 768 | mutex_lock(&cdev->lock); |
776 | if (ap->applid) | ||
777 | return -EEXIST; | ||
778 | 769 | ||
779 | if (copy_from_user(&cdev->ap.rparam, argp, | 770 | if (cdev->ap.applid) { |
780 | sizeof(struct capi_register_params))) | 771 | retval = -EEXIST; |
781 | return -EFAULT; | 772 | goto register_out; |
782 | 773 | } | |
783 | cdev->ap.private = cdev; | 774 | if (copy_from_user(&cdev->ap.rparam, argp, |
784 | cdev->ap.recv_message = capi_recv_message; | 775 | sizeof(struct capi_register_params))) { |
785 | cdev->errcode = capi20_register(ap); | 776 | retval = -EFAULT; |
786 | if (cdev->errcode) { | 777 | goto register_out; |
787 | ap->applid = 0; | 778 | } |
788 | return -EIO; | 779 | cdev->ap.private = cdev; |
789 | } | 780 | cdev->ap.recv_message = capi_recv_message; |
781 | cdev->errcode = capi20_register(&cdev->ap); | ||
782 | retval = (int)cdev->ap.applid; | ||
783 | if (cdev->errcode) { | ||
784 | cdev->ap.applid = 0; | ||
785 | retval = -EIO; | ||
790 | } | 786 | } |
791 | return (int)ap->applid; | 787 | |
788 | register_out: | ||
789 | mutex_unlock(&cdev->lock); | ||
790 | return retval; | ||
792 | 791 | ||
793 | case CAPI_GET_VERSION: | 792 | case CAPI_GET_VERSION: |
794 | { | 793 | { |
@@ -887,68 +886,67 @@ capi_ioctl(struct inode *inode, struct file *file, | |||
887 | return 0; | 886 | return 0; |
888 | 887 | ||
889 | case CAPI_SET_FLAGS: | 888 | case CAPI_SET_FLAGS: |
890 | case CAPI_CLR_FLAGS: | 889 | case CAPI_CLR_FLAGS: { |
891 | { | 890 | unsigned userflags; |
892 | unsigned userflags; | 891 | |
893 | if (copy_from_user(&userflags, argp, | 892 | if (copy_from_user(&userflags, argp, sizeof(userflags))) |
894 | sizeof(userflags))) | 893 | return -EFAULT; |
895 | return -EFAULT; | ||
896 | if (cmd == CAPI_SET_FLAGS) | ||
897 | cdev->userflags |= userflags; | ||
898 | else | ||
899 | cdev->userflags &= ~userflags; | ||
900 | } | ||
901 | return 0; | ||
902 | 894 | ||
895 | mutex_lock(&cdev->lock); | ||
896 | if (cmd == CAPI_SET_FLAGS) | ||
897 | cdev->userflags |= userflags; | ||
898 | else | ||
899 | cdev->userflags &= ~userflags; | ||
900 | mutex_unlock(&cdev->lock); | ||
901 | return 0; | ||
902 | } | ||
903 | case CAPI_GET_FLAGS: | 903 | case CAPI_GET_FLAGS: |
904 | if (copy_to_user(argp, &cdev->userflags, | 904 | if (copy_to_user(argp, &cdev->userflags, |
905 | sizeof(cdev->userflags))) | 905 | sizeof(cdev->userflags))) |
906 | return -EFAULT; | 906 | return -EFAULT; |
907 | return 0; | 907 | return 0; |
908 | 908 | ||
909 | case CAPI_NCCI_OPENCOUNT: | 909 | case CAPI_NCCI_OPENCOUNT: { |
910 | { | 910 | struct capincci *nccip; |
911 | struct capincci *nccip; | 911 | unsigned ncci; |
912 | unsigned ncci; | 912 | int count = 0; |
913 | int count = 0; | ||
914 | if (copy_from_user(&ncci, argp, sizeof(ncci))) | ||
915 | return -EFAULT; | ||
916 | 913 | ||
917 | mutex_lock(&cdev->ncci_list_mtx); | 914 | if (copy_from_user(&ncci, argp, sizeof(ncci))) |
918 | if ((nccip = capincci_find(cdev, (u32) ncci)) == NULL) { | 915 | return -EFAULT; |
919 | mutex_unlock(&cdev->ncci_list_mtx); | 916 | |
920 | return 0; | 917 | mutex_lock(&cdev->lock); |
921 | } | 918 | nccip = capincci_find(cdev, (u32)ncci); |
922 | count += capincci_minor_opencount(nccip); | 919 | if (nccip) |
923 | mutex_unlock(&cdev->ncci_list_mtx); | 920 | count = capincci_minor_opencount(nccip); |
924 | return count; | 921 | mutex_unlock(&cdev->lock); |
925 | } | 922 | return count; |
926 | return 0; | 923 | } |
927 | 924 | ||
928 | #ifdef CONFIG_ISDN_CAPI_MIDDLEWARE | 925 | #ifdef CONFIG_ISDN_CAPI_MIDDLEWARE |
929 | case CAPI_NCCI_GETUNIT: | 926 | case CAPI_NCCI_GETUNIT: { |
930 | { | 927 | struct capincci *nccip; |
931 | struct capincci *nccip; | 928 | struct capiminor *mp; |
932 | struct capiminor *mp; | 929 | unsigned ncci; |
933 | unsigned ncci; | 930 | int unit = -ESRCH; |
934 | int unit = 0; | 931 | |
935 | if (copy_from_user(&ncci, argp, | 932 | if (copy_from_user(&ncci, argp, sizeof(ncci))) |
936 | sizeof(ncci))) | 933 | return -EFAULT; |
937 | return -EFAULT; | 934 | |
938 | mutex_lock(&cdev->ncci_list_mtx); | 935 | mutex_lock(&cdev->lock); |
939 | nccip = capincci_find(cdev, (u32) ncci); | 936 | nccip = capincci_find(cdev, (u32)ncci); |
940 | if (!nccip || (mp = nccip->minorp) == NULL) { | 937 | if (nccip) { |
941 | mutex_unlock(&cdev->ncci_list_mtx); | 938 | mp = nccip->minorp; |
942 | return -ESRCH; | 939 | if (mp) |
943 | } | 940 | unit = mp->minor; |
944 | unit = mp->minor; | ||
945 | mutex_unlock(&cdev->ncci_list_mtx); | ||
946 | return unit; | ||
947 | } | 941 | } |
948 | return 0; | 942 | mutex_unlock(&cdev->lock); |
943 | return unit; | ||
944 | } | ||
949 | #endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */ | 945 | #endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */ |
946 | |||
947 | default: | ||
948 | return -EINVAL; | ||
950 | } | 949 | } |
951 | return -EINVAL; | ||
952 | } | 950 | } |
953 | 951 | ||
954 | static int capi_open(struct inode *inode, struct file *file) | 952 | static int capi_open(struct inode *inode, struct file *file) |
@@ -959,7 +957,7 @@ static int capi_open(struct inode *inode, struct file *file) | |||
959 | if (!cdev) | 957 | if (!cdev) |
960 | return -ENOMEM; | 958 | return -ENOMEM; |
961 | 959 | ||
962 | mutex_init(&cdev->ncci_list_mtx); | 960 | mutex_init(&cdev->lock); |
963 | skb_queue_head_init(&cdev->recvqueue); | 961 | skb_queue_head_init(&cdev->recvqueue); |
964 | init_waitqueue_head(&cdev->recvwait); | 962 | init_waitqueue_head(&cdev->recvwait); |
965 | file->private_data = cdev; | 963 | file->private_data = cdev; |
@@ -979,15 +977,10 @@ static int capi_release(struct inode *inode, struct file *file) | |||
979 | list_del(&cdev->list); | 977 | list_del(&cdev->list); |
980 | mutex_unlock(&capidev_list_lock); | 978 | mutex_unlock(&capidev_list_lock); |
981 | 979 | ||
982 | if (cdev->ap.applid) { | 980 | if (cdev->ap.applid) |
983 | capi20_release(&cdev->ap); | 981 | capi20_release(&cdev->ap); |
984 | cdev->ap.applid = 0; | ||
985 | } | ||
986 | skb_queue_purge(&cdev->recvqueue); | 982 | skb_queue_purge(&cdev->recvqueue); |
987 | |||
988 | mutex_lock(&cdev->ncci_list_mtx); | ||
989 | capincci_free(cdev, 0xffffffff); | 983 | capincci_free(cdev, 0xffffffff); |
990 | mutex_unlock(&cdev->ncci_list_mtx); | ||
991 | 984 | ||
992 | kfree(cdev); | 985 | kfree(cdev); |
993 | return 0; | 986 | return 0; |
@@ -1446,11 +1439,13 @@ static int capi20ncci_proc_show(struct seq_file *m, void *v) | |||
1446 | mutex_lock(&capidev_list_lock); | 1439 | mutex_lock(&capidev_list_lock); |
1447 | list_for_each(l, &capidev_list) { | 1440 | list_for_each(l, &capidev_list) { |
1448 | cdev = list_entry(l, struct capidev, list); | 1441 | cdev = list_entry(l, struct capidev, list); |
1442 | mutex_lock(&cdev->lock); | ||
1449 | for (np=cdev->nccis; np; np = np->next) { | 1443 | for (np=cdev->nccis; np; np = np->next) { |
1450 | seq_printf(m, "%d 0x%x\n", | 1444 | seq_printf(m, "%d 0x%x\n", |
1451 | cdev->ap.applid, | 1445 | cdev->ap.applid, |
1452 | np->ncci); | 1446 | np->ncci); |
1453 | } | 1447 | } |
1448 | mutex_unlock(&cdev->lock); | ||
1454 | } | 1449 | } |
1455 | mutex_unlock(&capidev_list_lock); | 1450 | mutex_unlock(&capidev_list_lock); |
1456 | return 0; | 1451 | return 0; |