aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/isdn/capi/capi.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/isdn/capi/capi.c')
-rw-r--r--drivers/isdn/capi/capi.c181
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
647unlock_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
788register_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
954static int capi_open(struct inode *inode, struct file *file) 952static 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;