aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/isdn/gigaset
diff options
context:
space:
mode:
authorTilman Schmidt <tilman@imap.cc>2010-06-21 09:55:20 -0400
committerDavid S. Miller <davem@davemloft.net>2010-06-26 00:17:01 -0400
commit1b4843c5e8cbab86830da8a53b8288882060c059 (patch)
treee85f56181da19d0cd314cc369749f756b58e0063 /drivers/isdn/gigaset
parent1ce368ff288ed872a8fee93b8a2b7706111feb9a (diff)
isdn/gigaset: correct CAPI connection state storage
CAPI applications can handle several connections in parallel, so one connection state per application isn't sufficient. Store the connection state in the channel structure instead. Impact: bugfix Signed-off-by: Tilman Schmidt <tilman@imap.cc> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/isdn/gigaset')
-rw-r--r--drivers/isdn/gigaset/capi.c225
-rw-r--r--drivers/isdn/gigaset/common.c4
-rw-r--r--drivers/isdn/gigaset/gigaset.h4
3 files changed, 180 insertions, 53 deletions
diff --git a/drivers/isdn/gigaset/capi.c b/drivers/isdn/gigaset/capi.c
index 665673f4d667..6fbe8999c419 100644
--- a/drivers/isdn/gigaset/capi.c
+++ b/drivers/isdn/gigaset/capi.c
@@ -70,7 +70,7 @@
70#define MAX_NUMBER_DIGITS 20 70#define MAX_NUMBER_DIGITS 20
71#define MAX_FMT_IE_LEN 20 71#define MAX_FMT_IE_LEN 20
72 72
73/* values for gigaset_capi_appl.connected */ 73/* values for bcs->apconnstate */
74#define APCONN_NONE 0 /* inactive/listening */ 74#define APCONN_NONE 0 /* inactive/listening */
75#define APCONN_SETUP 1 /* connecting */ 75#define APCONN_SETUP 1 /* connecting */
76#define APCONN_ACTIVE 2 /* B channel up */ 76#define APCONN_ACTIVE 2 /* B channel up */
@@ -84,7 +84,6 @@ struct gigaset_capi_appl {
84 u16 nextMessageNumber; 84 u16 nextMessageNumber;
85 u32 listenInfoMask; 85 u32 listenInfoMask;
86 u32 listenCIPmask; 86 u32 listenCIPmask;
87 int connected;
88}; 87};
89 88
90/* CAPI specific controller data structure */ 89/* CAPI specific controller data structure */
@@ -384,7 +383,7 @@ void gigaset_skb_sent(struct bc_state *bcs, struct sk_buff *dskb)
384 } 383 }
385 384
386 /* don't send further B3 messages if disconnected */ 385 /* don't send further B3 messages if disconnected */
387 if (ap->connected < APCONN_ACTIVE) { 386 if (bcs->apconnstate < APCONN_ACTIVE) {
388 gig_dbg(DEBUG_LLDATA, "disconnected, discarding ack"); 387 gig_dbg(DEBUG_LLDATA, "disconnected, discarding ack");
389 return; 388 return;
390 } 389 }
@@ -428,7 +427,7 @@ void gigaset_skb_rcvd(struct bc_state *bcs, struct sk_buff *skb)
428 } 427 }
429 428
430 /* don't send further B3 messages if disconnected */ 429 /* don't send further B3 messages if disconnected */
431 if (ap->connected < APCONN_ACTIVE) { 430 if (bcs->apconnstate < APCONN_ACTIVE) {
432 gig_dbg(DEBUG_LLDATA, "disconnected, discarding data"); 431 gig_dbg(DEBUG_LLDATA, "disconnected, discarding data");
433 dev_kfree_skb_any(skb); 432 dev_kfree_skb_any(skb);
434 return; 433 return;
@@ -500,6 +499,7 @@ int gigaset_isdn_icall(struct at_state_t *at_state)
500 u32 actCIPmask; 499 u32 actCIPmask;
501 struct sk_buff *skb; 500 struct sk_buff *skb;
502 unsigned int msgsize; 501 unsigned int msgsize;
502 unsigned long flags;
503 int i; 503 int i;
504 504
505 /* 505 /*
@@ -624,7 +624,14 @@ int gigaset_isdn_icall(struct at_state_t *at_state)
624 format_ie(iif->hcmsg.CalledPartyNumber)); 624 format_ie(iif->hcmsg.CalledPartyNumber));
625 625
626 /* scan application list for matching listeners */ 626 /* scan application list for matching listeners */
627 bcs->ap = NULL; 627 spin_lock_irqsave(&bcs->aplock, flags);
628 if (bcs->ap != NULL || bcs->apconnstate != APCONN_NONE) {
629 dev_warn(cs->dev, "%s: channel not properly cleared (%p/%d)\n",
630 __func__, bcs->ap, bcs->apconnstate);
631 bcs->ap = NULL;
632 bcs->apconnstate = APCONN_NONE;
633 }
634 spin_unlock_irqrestore(&bcs->aplock, flags);
628 actCIPmask = 1 | (1 << iif->hcmsg.CIPValue); 635 actCIPmask = 1 | (1 << iif->hcmsg.CIPValue);
629 list_for_each_entry(ap, &iif->appls, ctrlist) 636 list_for_each_entry(ap, &iif->appls, ctrlist)
630 if (actCIPmask & ap->listenCIPmask) { 637 if (actCIPmask & ap->listenCIPmask) {
@@ -642,10 +649,12 @@ int gigaset_isdn_icall(struct at_state_t *at_state)
642 dump_cmsg(DEBUG_CMD, __func__, &iif->hcmsg); 649 dump_cmsg(DEBUG_CMD, __func__, &iif->hcmsg);
643 650
644 /* add to listeners on this B channel, update state */ 651 /* add to listeners on this B channel, update state */
652 spin_lock_irqsave(&bcs->aplock, flags);
645 ap->bcnext = bcs->ap; 653 ap->bcnext = bcs->ap;
646 bcs->ap = ap; 654 bcs->ap = ap;
647 bcs->chstate |= CHS_NOTIFY_LL; 655 bcs->chstate |= CHS_NOTIFY_LL;
648 ap->connected = APCONN_SETUP; 656 bcs->apconnstate = APCONN_SETUP;
657 spin_unlock_irqrestore(&bcs->aplock, flags);
649 658
650 /* emit message */ 659 /* emit message */
651 capi_ctr_handle_message(&iif->ctr, ap->id, skb); 660 capi_ctr_handle_message(&iif->ctr, ap->id, skb);
@@ -670,7 +679,7 @@ static void send_disconnect_ind(struct bc_state *bcs,
670 struct gigaset_capi_ctr *iif = cs->iif; 679 struct gigaset_capi_ctr *iif = cs->iif;
671 struct sk_buff *skb; 680 struct sk_buff *skb;
672 681
673 if (ap->connected == APCONN_NONE) 682 if (bcs->apconnstate == APCONN_NONE)
674 return; 683 return;
675 684
676 capi_cmsg_header(&iif->hcmsg, ap->id, CAPI_DISCONNECT, CAPI_IND, 685 capi_cmsg_header(&iif->hcmsg, ap->id, CAPI_DISCONNECT, CAPI_IND,
@@ -684,7 +693,6 @@ static void send_disconnect_ind(struct bc_state *bcs,
684 } 693 }
685 capi_cmsg2message(&iif->hcmsg, __skb_put(skb, CAPI_DISCONNECT_IND_LEN)); 694 capi_cmsg2message(&iif->hcmsg, __skb_put(skb, CAPI_DISCONNECT_IND_LEN));
686 dump_cmsg(DEBUG_CMD, __func__, &iif->hcmsg); 695 dump_cmsg(DEBUG_CMD, __func__, &iif->hcmsg);
687 ap->connected = APCONN_NONE;
688 capi_ctr_handle_message(&iif->ctr, ap->id, skb); 696 capi_ctr_handle_message(&iif->ctr, ap->id, skb);
689} 697}
690 698
@@ -701,9 +709,9 @@ static void send_disconnect_b3_ind(struct bc_state *bcs,
701 struct sk_buff *skb; 709 struct sk_buff *skb;
702 710
703 /* nothing to do if no logical connection active */ 711 /* nothing to do if no logical connection active */
704 if (ap->connected < APCONN_ACTIVE) 712 if (bcs->apconnstate < APCONN_ACTIVE)
705 return; 713 return;
706 ap->connected = APCONN_SETUP; 714 bcs->apconnstate = APCONN_SETUP;
707 715
708 capi_cmsg_header(&iif->hcmsg, ap->id, CAPI_DISCONNECT_B3, CAPI_IND, 716 capi_cmsg_header(&iif->hcmsg, ap->id, CAPI_DISCONNECT_B3, CAPI_IND,
709 ap->nextMessageNumber++, 717 ap->nextMessageNumber++,
@@ -730,14 +738,25 @@ void gigaset_isdn_connD(struct bc_state *bcs)
730{ 738{
731 struct cardstate *cs = bcs->cs; 739 struct cardstate *cs = bcs->cs;
732 struct gigaset_capi_ctr *iif = cs->iif; 740 struct gigaset_capi_ctr *iif = cs->iif;
733 struct gigaset_capi_appl *ap = bcs->ap; 741 struct gigaset_capi_appl *ap;
734 struct sk_buff *skb; 742 struct sk_buff *skb;
735 unsigned int msgsize; 743 unsigned int msgsize;
744 unsigned long flags;
736 745
746 spin_lock_irqsave(&bcs->aplock, flags);
747 ap = bcs->ap;
737 if (!ap) { 748 if (!ap) {
749 spin_unlock_irqrestore(&bcs->aplock, flags);
738 dev_err(cs->dev, "%s: no application\n", __func__); 750 dev_err(cs->dev, "%s: no application\n", __func__);
739 return; 751 return;
740 } 752 }
753 if (bcs->apconnstate == APCONN_NONE) {
754 spin_unlock_irqrestore(&bcs->aplock, flags);
755 dev_warn(cs->dev, "%s: application %u not connected\n",
756 __func__, ap->id);
757 return;
758 }
759 spin_unlock_irqrestore(&bcs->aplock, flags);
741 while (ap->bcnext) { 760 while (ap->bcnext) {
742 /* this should never happen */ 761 /* this should never happen */
743 dev_warn(cs->dev, "%s: dropping extra application %u\n", 762 dev_warn(cs->dev, "%s: dropping extra application %u\n",
@@ -746,11 +765,6 @@ void gigaset_isdn_connD(struct bc_state *bcs)
746 CapiCallGivenToOtherApplication); 765 CapiCallGivenToOtherApplication);
747 ap->bcnext = ap->bcnext->bcnext; 766 ap->bcnext = ap->bcnext->bcnext;
748 } 767 }
749 if (ap->connected == APCONN_NONE) {
750 dev_warn(cs->dev, "%s: application %u not connected\n",
751 __func__, ap->id);
752 return;
753 }
754 768
755 /* prepare CONNECT_ACTIVE_IND message 769 /* prepare CONNECT_ACTIVE_IND message
756 * Note: LLC not supported by device 770 * Note: LLC not supported by device
@@ -788,17 +802,24 @@ void gigaset_isdn_connD(struct bc_state *bcs)
788void gigaset_isdn_hupD(struct bc_state *bcs) 802void gigaset_isdn_hupD(struct bc_state *bcs)
789{ 803{
790 struct gigaset_capi_appl *ap; 804 struct gigaset_capi_appl *ap;
805 unsigned long flags;
791 806
792 /* 807 /*
793 * ToDo: pass on reason code reported by device 808 * ToDo: pass on reason code reported by device
794 * (requires ev-layer state machine extension to collect 809 * (requires ev-layer state machine extension to collect
795 * ZCAU device reply) 810 * ZCAU device reply)
796 */ 811 */
797 for (ap = bcs->ap; ap != NULL; ap = ap->bcnext) { 812 spin_lock_irqsave(&bcs->aplock, flags);
813 while (bcs->ap != NULL) {
814 ap = bcs->ap;
815 bcs->ap = ap->bcnext;
816 spin_unlock_irqrestore(&bcs->aplock, flags);
798 send_disconnect_b3_ind(bcs, ap); 817 send_disconnect_b3_ind(bcs, ap);
799 send_disconnect_ind(bcs, ap, 0); 818 send_disconnect_ind(bcs, ap, 0);
819 spin_lock_irqsave(&bcs->aplock, flags);
800 } 820 }
801 bcs->ap = NULL; 821 bcs->apconnstate = APCONN_NONE;
822 spin_unlock_irqrestore(&bcs->aplock, flags);
802} 823}
803 824
804/** 825/**
@@ -812,24 +833,21 @@ void gigaset_isdn_connB(struct bc_state *bcs)
812{ 833{
813 struct cardstate *cs = bcs->cs; 834 struct cardstate *cs = bcs->cs;
814 struct gigaset_capi_ctr *iif = cs->iif; 835 struct gigaset_capi_ctr *iif = cs->iif;
815 struct gigaset_capi_appl *ap = bcs->ap; 836 struct gigaset_capi_appl *ap;
816 struct sk_buff *skb; 837 struct sk_buff *skb;
838 unsigned long flags;
817 unsigned int msgsize; 839 unsigned int msgsize;
818 u8 command; 840 u8 command;
819 841
842 spin_lock_irqsave(&bcs->aplock, flags);
843 ap = bcs->ap;
820 if (!ap) { 844 if (!ap) {
845 spin_unlock_irqrestore(&bcs->aplock, flags);
821 dev_err(cs->dev, "%s: no application\n", __func__); 846 dev_err(cs->dev, "%s: no application\n", __func__);
822 return; 847 return;
823 } 848 }
824 while (ap->bcnext) { 849 if (!bcs->apconnstate) {
825 /* this should never happen */ 850 spin_unlock_irqrestore(&bcs->aplock, flags);
826 dev_warn(cs->dev, "%s: dropping extra application %u\n",
827 __func__, ap->bcnext->id);
828 send_disconnect_ind(bcs, ap->bcnext,
829 CapiCallGivenToOtherApplication);
830 ap->bcnext = ap->bcnext->bcnext;
831 }
832 if (!ap->connected) {
833 dev_warn(cs->dev, "%s: application %u not connected\n", 851 dev_warn(cs->dev, "%s: application %u not connected\n",
834 __func__, ap->id); 852 __func__, ap->id);
835 return; 853 return;
@@ -841,13 +859,26 @@ void gigaset_isdn_connB(struct bc_state *bcs)
841 * CONNECT_B3_ACTIVE_IND in reply to CONNECT_B3_RESP 859 * CONNECT_B3_ACTIVE_IND in reply to CONNECT_B3_RESP
842 * Parameters in both cases always: NCCI = 1, NCPI empty 860 * Parameters in both cases always: NCCI = 1, NCPI empty
843 */ 861 */
844 if (ap->connected >= APCONN_ACTIVE) { 862 if (bcs->apconnstate >= APCONN_ACTIVE) {
845 command = CAPI_CONNECT_B3_ACTIVE; 863 command = CAPI_CONNECT_B3_ACTIVE;
846 msgsize = CAPI_CONNECT_B3_ACTIVE_IND_BASELEN; 864 msgsize = CAPI_CONNECT_B3_ACTIVE_IND_BASELEN;
847 } else { 865 } else {
848 command = CAPI_CONNECT_B3; 866 command = CAPI_CONNECT_B3;
849 msgsize = CAPI_CONNECT_B3_IND_BASELEN; 867 msgsize = CAPI_CONNECT_B3_IND_BASELEN;
850 } 868 }
869 bcs->apconnstate = APCONN_ACTIVE;
870
871 spin_unlock_irqrestore(&bcs->aplock, flags);
872
873 while (ap->bcnext) {
874 /* this should never happen */
875 dev_warn(cs->dev, "%s: dropping extra application %u\n",
876 __func__, ap->bcnext->id);
877 send_disconnect_ind(bcs, ap->bcnext,
878 CapiCallGivenToOtherApplication);
879 ap->bcnext = ap->bcnext->bcnext;
880 }
881
851 capi_cmsg_header(&iif->hcmsg, ap->id, command, CAPI_IND, 882 capi_cmsg_header(&iif->hcmsg, ap->id, command, CAPI_IND,
852 ap->nextMessageNumber++, 883 ap->nextMessageNumber++,
853 iif->ctr.cnr | ((bcs->channel + 1) << 8) | (1 << 16)); 884 iif->ctr.cnr | ((bcs->channel + 1) << 8) | (1 << 16));
@@ -858,7 +889,6 @@ void gigaset_isdn_connB(struct bc_state *bcs)
858 } 889 }
859 capi_cmsg2message(&iif->hcmsg, __skb_put(skb, msgsize)); 890 capi_cmsg2message(&iif->hcmsg, __skb_put(skb, msgsize));
860 dump_cmsg(DEBUG_CMD, __func__, &iif->hcmsg); 891 dump_cmsg(DEBUG_CMD, __func__, &iif->hcmsg);
861 ap->connected = APCONN_ACTIVE;
862 capi_ctr_handle_message(&iif->ctr, ap->id, skb); 892 capi_ctr_handle_message(&iif->ctr, ap->id, skb);
863} 893}
864 894
@@ -964,6 +994,61 @@ static void gigaset_register_appl(struct capi_ctr *ctr, u16 appl,
964 ap->rp = *rp; 994 ap->rp = *rp;
965 995
966 list_add(&ap->ctrlist, &iif->appls); 996 list_add(&ap->ctrlist, &iif->appls);
997 dev_info(cs->dev, "application %u registered\n", ap->id);
998}
999
1000/*
1001 * remove CAPI application from channel
1002 * helper function to keep indentation levels down and stay in 80 columns
1003 */
1004
1005static inline void remove_appl_from_channel(struct bc_state *bcs,
1006 struct gigaset_capi_appl *ap)
1007{
1008 struct cardstate *cs = bcs->cs;
1009 struct gigaset_capi_appl *bcap;
1010 unsigned long flags;
1011 int prevconnstate;
1012
1013 spin_lock_irqsave(&bcs->aplock, flags);
1014 bcap = bcs->ap;
1015 if (bcap == NULL) {
1016 spin_unlock_irqrestore(&bcs->aplock, flags);
1017 return;
1018 }
1019
1020 /* check first application on channel */
1021 if (bcap == ap) {
1022 bcs->ap = ap->bcnext;
1023 if (bcs->ap != NULL) {
1024 spin_unlock_irqrestore(&bcs->aplock, flags);
1025 return;
1026 }
1027
1028 /* none left, clear channel state */
1029 prevconnstate = bcs->apconnstate;
1030 bcs->apconnstate = APCONN_NONE;
1031 spin_unlock_irqrestore(&bcs->aplock, flags);
1032
1033 if (prevconnstate == APCONN_ACTIVE) {
1034 dev_notice(cs->dev, "%s: hanging up channel %u\n",
1035 __func__, bcs->channel);
1036 gigaset_add_event(cs, &bcs->at_state,
1037 EV_HUP, NULL, 0, NULL);
1038 gigaset_schedule_event(cs);
1039 }
1040 return;
1041 }
1042
1043 /* check remaining list */
1044 do {
1045 if (bcap->bcnext == ap) {
1046 bcap->bcnext = bcap->bcnext->bcnext;
1047 return;
1048 }
1049 bcap = bcap->bcnext;
1050 } while (bcap != NULL);
1051 spin_unlock_irqrestore(&bcs->aplock, flags);
967} 1052}
968 1053
969/* 1054/*
@@ -975,19 +1060,19 @@ static void gigaset_release_appl(struct capi_ctr *ctr, u16 appl)
975 = container_of(ctr, struct gigaset_capi_ctr, ctr); 1060 = container_of(ctr, struct gigaset_capi_ctr, ctr);
976 struct cardstate *cs = iif->ctr.driverdata; 1061 struct cardstate *cs = iif->ctr.driverdata;
977 struct gigaset_capi_appl *ap, *tmp; 1062 struct gigaset_capi_appl *ap, *tmp;
1063 unsigned ch;
978 1064
979 list_for_each_entry_safe(ap, tmp, &iif->appls, ctrlist) 1065 list_for_each_entry_safe(ap, tmp, &iif->appls, ctrlist)
980 if (ap->id == appl) { 1066 if (ap->id == appl) {
981 if (ap->connected != APCONN_NONE) { 1067 /* remove from any channels */
982 dev_err(cs->dev, 1068 for (ch = 0; ch < cs->channels; ch++)
983 "%s: application %u still connected\n", 1069 remove_appl_from_channel(&cs->bcs[ch], ap);
984 __func__, ap->id); 1070
985 /* ToDo: clear active connection */ 1071 /* remove from registration list */
986 }
987 list_del(&ap->ctrlist); 1072 list_del(&ap->ctrlist);
988 kfree(ap); 1073 kfree(ap);
1074 dev_info(cs->dev, "application %u released\n", appl);
989 } 1075 }
990
991} 1076}
992 1077
993/* 1078/*
@@ -1166,6 +1251,7 @@ static void do_connect_req(struct gigaset_capi_ctr *iif,
1166 char **commands; 1251 char **commands;
1167 char *s; 1252 char *s;
1168 u8 *pp; 1253 u8 *pp;
1254 unsigned long flags;
1169 int i, l, lbc, lhlc; 1255 int i, l, lbc, lhlc;
1170 u16 info; 1256 u16 info;
1171 1257
@@ -1181,8 +1267,15 @@ static void do_connect_req(struct gigaset_capi_ctr *iif,
1181 send_conf(iif, ap, skb, CapiNoPlciAvailable); 1267 send_conf(iif, ap, skb, CapiNoPlciAvailable);
1182 return; 1268 return;
1183 } 1269 }
1270 spin_lock_irqsave(&bcs->aplock, flags);
1271 if (bcs->ap != NULL || bcs->apconnstate != APCONN_NONE)
1272 dev_warn(cs->dev, "%s: channel not properly cleared (%p/%d)\n",
1273 __func__, bcs->ap, bcs->apconnstate);
1184 ap->bcnext = NULL; 1274 ap->bcnext = NULL;
1185 bcs->ap = ap; 1275 bcs->ap = ap;
1276 bcs->apconnstate = APCONN_SETUP;
1277 spin_unlock_irqrestore(&bcs->aplock, flags);
1278
1186 bcs->rx_bufsize = ap->rp.datablklen; 1279 bcs->rx_bufsize = ap->rp.datablklen;
1187 dev_kfree_skb(bcs->rx_skb); 1280 dev_kfree_skb(bcs->rx_skb);
1188 gigaset_new_rx_skb(bcs); 1281 gigaset_new_rx_skb(bcs);
@@ -1419,7 +1512,6 @@ static void do_connect_req(struct gigaset_capi_ctr *iif,
1419 goto error; 1512 goto error;
1420 } 1513 }
1421 gigaset_schedule_event(cs); 1514 gigaset_schedule_event(cs);
1422 ap->connected = APCONN_SETUP;
1423 send_conf(iif, ap, skb, CapiSuccess); 1515 send_conf(iif, ap, skb, CapiSuccess);
1424 return; 1516 return;
1425 1517
@@ -1447,6 +1539,7 @@ static void do_connect_resp(struct gigaset_capi_ctr *iif,
1447 _cmsg *cmsg = &iif->acmsg; 1539 _cmsg *cmsg = &iif->acmsg;
1448 struct bc_state *bcs; 1540 struct bc_state *bcs;
1449 struct gigaset_capi_appl *oap; 1541 struct gigaset_capi_appl *oap;
1542 unsigned long flags;
1450 int channel; 1543 int channel;
1451 1544
1452 /* decode message */ 1545 /* decode message */
@@ -1466,12 +1559,21 @@ static void do_connect_resp(struct gigaset_capi_ctr *iif,
1466 switch (cmsg->Reject) { 1559 switch (cmsg->Reject) {
1467 case 0: /* Accept */ 1560 case 0: /* Accept */
1468 /* drop all competing applications, keep only this one */ 1561 /* drop all competing applications, keep only this one */
1469 for (oap = bcs->ap; oap != NULL; oap = oap->bcnext) 1562 spin_lock_irqsave(&bcs->aplock, flags);
1470 if (oap != ap) 1563 while (bcs->ap != NULL) {
1564 oap = bcs->ap;
1565 bcs->ap = oap->bcnext;
1566 if (oap != ap) {
1567 spin_unlock_irqrestore(&bcs->aplock, flags);
1471 send_disconnect_ind(bcs, oap, 1568 send_disconnect_ind(bcs, oap,
1472 CapiCallGivenToOtherApplication); 1569 CapiCallGivenToOtherApplication);
1570 spin_lock_irqsave(&bcs->aplock, flags);
1571 }
1572 }
1473 ap->bcnext = NULL; 1573 ap->bcnext = NULL;
1474 bcs->ap = ap; 1574 bcs->ap = ap;
1575 spin_unlock_irqrestore(&bcs->aplock, flags);
1576
1475 bcs->rx_bufsize = ap->rp.datablklen; 1577 bcs->rx_bufsize = ap->rp.datablklen;
1476 dev_kfree_skb(bcs->rx_skb); 1578 dev_kfree_skb(bcs->rx_skb);
1477 gigaset_new_rx_skb(bcs); 1579 gigaset_new_rx_skb(bcs);
@@ -1542,31 +1644,45 @@ static void do_connect_resp(struct gigaset_capi_ctr *iif,
1542 send_disconnect_ind(bcs, ap, 0); 1644 send_disconnect_ind(bcs, ap, 0);
1543 1645
1544 /* remove it from the list of listening apps */ 1646 /* remove it from the list of listening apps */
1647 spin_lock_irqsave(&bcs->aplock, flags);
1545 if (bcs->ap == ap) { 1648 if (bcs->ap == ap) {
1546 bcs->ap = ap->bcnext; 1649 bcs->ap = ap->bcnext;
1547 if (bcs->ap == NULL) 1650 if (bcs->ap == NULL) {
1548 /* last one: stop ev-layer hupD notifications */ 1651 /* last one: stop ev-layer hupD notifications */
1652 bcs->apconnstate = APCONN_NONE;
1549 bcs->chstate &= ~CHS_NOTIFY_LL; 1653 bcs->chstate &= ~CHS_NOTIFY_LL;
1654 }
1655 spin_unlock_irqrestore(&bcs->aplock, flags);
1550 return; 1656 return;
1551 } 1657 }
1552 for (oap = bcs->ap; oap != NULL; oap = oap->bcnext) { 1658 for (oap = bcs->ap; oap != NULL; oap = oap->bcnext) {
1553 if (oap->bcnext == ap) { 1659 if (oap->bcnext == ap) {
1554 oap->bcnext = oap->bcnext->bcnext; 1660 oap->bcnext = oap->bcnext->bcnext;
1661 spin_unlock_irqrestore(&bcs->aplock, flags);
1555 return; 1662 return;
1556 } 1663 }
1557 } 1664 }
1665 spin_unlock_irqrestore(&bcs->aplock, flags);
1558 dev_err(cs->dev, "%s: application %u not found\n", 1666 dev_err(cs->dev, "%s: application %u not found\n",
1559 __func__, ap->id); 1667 __func__, ap->id);
1560 return; 1668 return;
1561 1669
1562 default: /* Reject */ 1670 default: /* Reject */
1563 /* drop all competing applications, keep only this one */ 1671 /* drop all competing applications, keep only this one */
1564 for (oap = bcs->ap; oap != NULL; oap = oap->bcnext) 1672 spin_lock_irqsave(&bcs->aplock, flags);
1565 if (oap != ap) 1673 while (bcs->ap != NULL) {
1674 oap = bcs->ap;
1675 bcs->ap = oap->bcnext;
1676 if (oap != ap) {
1677 spin_unlock_irqrestore(&bcs->aplock, flags);
1566 send_disconnect_ind(bcs, oap, 1678 send_disconnect_ind(bcs, oap,
1567 CapiCallGivenToOtherApplication); 1679 CapiCallGivenToOtherApplication);
1680 spin_lock_irqsave(&bcs->aplock, flags);
1681 }
1682 }
1568 ap->bcnext = NULL; 1683 ap->bcnext = NULL;
1569 bcs->ap = ap; 1684 bcs->ap = ap;
1685 spin_unlock_irqrestore(&bcs->aplock, flags);
1570 1686
1571 /* reject call - will trigger DISCONNECT_IND for this app */ 1687 /* reject call - will trigger DISCONNECT_IND for this app */
1572 dev_info(cs->dev, "%s: Reject=%x\n", 1688 dev_info(cs->dev, "%s: Reject=%x\n",
@@ -1589,6 +1705,7 @@ static void do_connect_b3_req(struct gigaset_capi_ctr *iif,
1589{ 1705{
1590 struct cardstate *cs = iif->ctr.driverdata; 1706 struct cardstate *cs = iif->ctr.driverdata;
1591 _cmsg *cmsg = &iif->acmsg; 1707 _cmsg *cmsg = &iif->acmsg;
1708 struct bc_state *bcs;
1592 int channel; 1709 int channel;
1593 1710
1594 /* decode message */ 1711 /* decode message */
@@ -1603,9 +1720,10 @@ static void do_connect_b3_req(struct gigaset_capi_ctr *iif,
1603 send_conf(iif, ap, skb, CapiIllContrPlciNcci); 1720 send_conf(iif, ap, skb, CapiIllContrPlciNcci);
1604 return; 1721 return;
1605 } 1722 }
1723 bcs = &cs->bcs[channel-1];
1606 1724
1607 /* mark logical connection active */ 1725 /* mark logical connection active */
1608 ap->connected = APCONN_ACTIVE; 1726 bcs->apconnstate = APCONN_ACTIVE;
1609 1727
1610 /* build NCCI: always 1 (one B3 connection only) */ 1728 /* build NCCI: always 1 (one B3 connection only) */
1611 cmsg->adr.adrNCCI |= 1 << 16; 1729 cmsg->adr.adrNCCI |= 1 << 16;
@@ -1651,7 +1769,7 @@ static void do_connect_b3_resp(struct gigaset_capi_ctr *iif,
1651 1769
1652 if (cmsg->Reject) { 1770 if (cmsg->Reject) {
1653 /* Reject: clear B3 connect received flag */ 1771 /* Reject: clear B3 connect received flag */
1654 ap->connected = APCONN_SETUP; 1772 bcs->apconnstate = APCONN_SETUP;
1655 1773
1656 /* trigger hangup, causing eventual DISCONNECT_IND */ 1774 /* trigger hangup, causing eventual DISCONNECT_IND */
1657 if (!gigaset_add_event(cs, &bcs->at_state, 1775 if (!gigaset_add_event(cs, &bcs->at_state,
@@ -1723,11 +1841,11 @@ static void do_disconnect_req(struct gigaset_capi_ctr *iif,
1723 } 1841 }
1724 1842
1725 /* skip if DISCONNECT_IND already sent */ 1843 /* skip if DISCONNECT_IND already sent */
1726 if (!ap->connected) 1844 if (!bcs->apconnstate)
1727 return; 1845 return;
1728 1846
1729 /* check for active logical connection */ 1847 /* check for active logical connection */
1730 if (ap->connected >= APCONN_ACTIVE) { 1848 if (bcs->apconnstate >= APCONN_ACTIVE) {
1731 /* 1849 /*
1732 * emit DISCONNECT_B3_IND with cause 0x3301 1850 * emit DISCONNECT_B3_IND with cause 0x3301
1733 * use separate cmsg structure, as the content of iif->acmsg 1851 * use separate cmsg structure, as the content of iif->acmsg
@@ -1776,6 +1894,7 @@ static void do_disconnect_b3_req(struct gigaset_capi_ctr *iif,
1776{ 1894{
1777 struct cardstate *cs = iif->ctr.driverdata; 1895 struct cardstate *cs = iif->ctr.driverdata;
1778 _cmsg *cmsg = &iif->acmsg; 1896 _cmsg *cmsg = &iif->acmsg;
1897 struct bc_state *bcs;
1779 int channel; 1898 int channel;
1780 1899
1781 /* decode message */ 1900 /* decode message */
@@ -1791,17 +1910,17 @@ static void do_disconnect_b3_req(struct gigaset_capi_ctr *iif,
1791 send_conf(iif, ap, skb, CapiIllContrPlciNcci); 1910 send_conf(iif, ap, skb, CapiIllContrPlciNcci);
1792 return; 1911 return;
1793 } 1912 }
1913 bcs = &cs->bcs[channel-1];
1794 1914
1795 /* reject if logical connection not active */ 1915 /* reject if logical connection not active */
1796 if (ap->connected < APCONN_ACTIVE) { 1916 if (bcs->apconnstate < APCONN_ACTIVE) {
1797 send_conf(iif, ap, skb, 1917 send_conf(iif, ap, skb,
1798 CapiMessageNotSupportedInCurrentState); 1918 CapiMessageNotSupportedInCurrentState);
1799 return; 1919 return;
1800 } 1920 }
1801 1921
1802 /* trigger hangup, causing eventual DISCONNECT_B3_IND */ 1922 /* trigger hangup, causing eventual DISCONNECT_B3_IND */
1803 if (!gigaset_add_event(cs, &cs->bcs[channel-1].at_state, 1923 if (!gigaset_add_event(cs, &bcs->at_state, EV_HUP, NULL, 0, NULL)) {
1804 EV_HUP, NULL, 0, NULL)) {
1805 send_conf(iif, ap, skb, CAPI_MSGOSRESOURCEERR); 1924 send_conf(iif, ap, skb, CAPI_MSGOSRESOURCEERR);
1806 return; 1925 return;
1807 } 1926 }
@@ -1822,6 +1941,7 @@ static void do_data_b3_req(struct gigaset_capi_ctr *iif,
1822 struct sk_buff *skb) 1941 struct sk_buff *skb)
1823{ 1942{
1824 struct cardstate *cs = iif->ctr.driverdata; 1943 struct cardstate *cs = iif->ctr.driverdata;
1944 struct bc_state *bcs;
1825 int channel = CAPIMSG_PLCI_PART(skb->data); 1945 int channel = CAPIMSG_PLCI_PART(skb->data);
1826 u16 ncci = CAPIMSG_NCCI_PART(skb->data); 1946 u16 ncci = CAPIMSG_NCCI_PART(skb->data);
1827 u16 msglen = CAPIMSG_LEN(skb->data); 1947 u16 msglen = CAPIMSG_LEN(skb->data);
@@ -1844,6 +1964,7 @@ static void do_data_b3_req(struct gigaset_capi_ctr *iif,
1844 send_conf(iif, ap, skb, CapiIllContrPlciNcci); 1964 send_conf(iif, ap, skb, CapiIllContrPlciNcci);
1845 return; 1965 return;
1846 } 1966 }
1967 bcs = &cs->bcs[channel-1];
1847 if (msglen != CAPI_DATA_B3_REQ_LEN && msglen != CAPI_DATA_B3_REQ_LEN64) 1968 if (msglen != CAPI_DATA_B3_REQ_LEN && msglen != CAPI_DATA_B3_REQ_LEN64)
1848 dev_notice(cs->dev, "%s: unexpected length %d\n", 1969 dev_notice(cs->dev, "%s: unexpected length %d\n",
1849 "DATA_B3_REQ", msglen); 1970 "DATA_B3_REQ", msglen);
@@ -1863,7 +1984,7 @@ static void do_data_b3_req(struct gigaset_capi_ctr *iif,
1863 } 1984 }
1864 1985
1865 /* reject if logical connection not active */ 1986 /* reject if logical connection not active */
1866 if (ap->connected < APCONN_ACTIVE) { 1987 if (bcs->apconnstate < APCONN_ACTIVE) {
1867 send_conf(iif, ap, skb, CapiMessageNotSupportedInCurrentState); 1988 send_conf(iif, ap, skb, CapiMessageNotSupportedInCurrentState);
1868 return; 1989 return;
1869 } 1990 }
@@ -1874,7 +1995,7 @@ static void do_data_b3_req(struct gigaset_capi_ctr *iif,
1874 skb_pull(skb, msglen); 1995 skb_pull(skb, msglen);
1875 1996
1876 /* pass to device-specific module */ 1997 /* pass to device-specific module */
1877 if (cs->ops->send_skb(&cs->bcs[channel-1], skb) < 0) { 1998 if (cs->ops->send_skb(bcs, skb) < 0) {
1878 send_conf(iif, ap, skb, CAPI_MSGOSRESOURCEERR); 1999 send_conf(iif, ap, skb, CAPI_MSGOSRESOURCEERR);
1879 return; 2000 return;
1880 } 2001 }
diff --git a/drivers/isdn/gigaset/common.c b/drivers/isdn/gigaset/common.c
index 9778fabbc488..5d4befb81057 100644
--- a/drivers/isdn/gigaset/common.c
+++ b/drivers/isdn/gigaset/common.c
@@ -649,6 +649,10 @@ static struct bc_state *gigaset_initbcs(struct bc_state *bcs,
649 for (i = 0; i < AT_NUM; ++i) 649 for (i = 0; i < AT_NUM; ++i)
650 bcs->commands[i] = NULL; 650 bcs->commands[i] = NULL;
651 651
652 spin_lock_init(&bcs->aplock);
653 bcs->ap = NULL;
654 bcs->apconnstate = 0;
655
652 gig_dbg(DEBUG_INIT, " setting up bcs[%d]->hw", channel); 656 gig_dbg(DEBUG_INIT, " setting up bcs[%d]->hw", channel);
653 if (cs->ops->initbcshw(bcs)) 657 if (cs->ops->initbcshw(bcs))
654 return bcs; 658 return bcs;
diff --git a/drivers/isdn/gigaset/gigaset.h b/drivers/isdn/gigaset/gigaset.h
index c4e6c26897ea..8738b0821fc9 100644
--- a/drivers/isdn/gigaset/gigaset.h
+++ b/drivers/isdn/gigaset/gigaset.h
@@ -403,7 +403,9 @@ struct bc_state {
403 struct bas_bc_state *bas; /* usb hardware driver (base) */ 403 struct bas_bc_state *bas; /* usb hardware driver (base) */
404 } hw; 404 } hw;
405 405
406 void *ap; /* LL application structure */ 406 void *ap; /* associated LL application */
407 int apconnstate; /* LL application connection state */
408 spinlock_t aplock;
407}; 409};
408 410
409struct cardstate { 411struct cardstate {