@@ -101,7 +101,8 @@ String commandToString(LE_COMMAND command){
101
101
HCIClass::HCIClass () :
102
102
_debug(NULL ),
103
103
_recvIndex(0 ),
104
- _pendingPkt(0 )
104
+ _pendingPkt(0 ),
105
+ _l2CapPduBufferSize(0 )
105
106
{
106
107
}
107
108
@@ -728,87 +729,135 @@ int HCIClass::sendCommand(uint16_t opcode, uint8_t plen, void* parameters)
728
729
void HCIClass::handleAclDataPkt (uint8_t /* plen*/ , uint8_t pdata[])
729
730
{
730
731
struct __attribute__ ((packed)) HCIACLHdr {
731
- uint16_t handle;
732
- uint16_t dlen;
733
- uint16_t len;
734
- uint16_t cid;
735
- } *aclHdr = (HCIACLHdr*)pdata;
732
+ uint16_t connectionHandleWithFlags;
733
+ uint16_t dlen; // dlen + 4 = plen (dlen is the size of the ACL SDU)
734
+ } *aclHeader = (HCIACLHdr*)pdata;
736
735
736
+ uint8_t bcFlag = (aclHeader->connectionHandleWithFlags & 0xc000 ) >> 14 ;
737
+ uint8_t pbFlag = (aclHeader->connectionHandleWithFlags & 0x3000 ) >> 12 ;
738
+ uint16_t connectionHandle = aclHeader->connectionHandleWithFlags & 0x0fff ;
737
739
738
- uint16_t aclFlags = (aclHdr-> handle & 0xf000 ) >> 12 ;
740
+ uint8_t *aclSdu = &pdata[ sizeof (HCIACLHdr)] ;
739
741
740
- if ((aclHdr->dlen - 4 ) != aclHdr->len ) {
741
- // packet is fragmented
742
- if (aclFlags != 0x01 ) {
743
- // copy into ACL buffer
744
- memcpy (_aclPktBuffer, &_recvBuffer[1 ], sizeof (HCIACLHdr) + aclHdr->dlen - 4 );
745
- } else {
746
- // copy next chunk into the buffer
747
- HCIACLHdr* aclBufferHeader = (HCIACLHdr*)_aclPktBuffer;
742
+ #ifdef _BLE_TRACE_
743
+ Serial.print (" Acl packet bcFlag = " );
744
+ Serial.print (bcFlag, BIN);
745
+ Serial.print (" pbFlag = " );
746
+ Serial.print (pbFlag, BIN);
747
+ Serial.print (" connectionHandle = " );
748
+ Serial.print (connectionHandle, HEX);
749
+ Serial.print (" dlen = " );
750
+ Serial.println (aclHeader->dlen , DEC);
751
+ #endif
748
752
749
- memcpy (&_aclPktBuffer[sizeof (HCIACLHdr) + aclBufferHeader->dlen - 4 ], &_recvBuffer[1 + sizeof (aclHdr->handle ) + sizeof (aclHdr->dlen )], aclHdr->dlen );
753
+ // Pointer to the L2CAP PDU (might be reconstructed from multiple fragments)
754
+ uint8_t *l2CapPdu;
755
+ uint8_t l2CapPduSize;
750
756
751
- aclBufferHeader->dlen += aclHdr->dlen ;
752
- aclHdr = aclBufferHeader;
753
- }
754
- }
757
+ if (pbFlag == 0b10 ) {
758
+ // "First automatically flushable packet" = Start of our L2CAP PDU
759
+
760
+ l2CapPdu = aclSdu;
761
+ l2CapPduSize = aclHeader->dlen ;
762
+ } else if (pbFlag == 0b01 ) {
763
+ // "Continuing Fragment" = Continued L2CAP PDU
764
+ #ifdef _BLE_TRACE_
765
+ Serial.print (" Continued packet. Appending to L2CAP PDU buffer (previously " );
766
+ Serial.print (_l2CapPduBufferSize, DEC);
767
+ Serial.println (" bytes in buffer)" );
768
+ #endif
769
+ // If we receive a fragment, we always need to append it to the L2CAP PDU buffer
770
+ memcpy (&_l2CapPduBuffer[_l2CapPduBufferSize], aclSdu, aclHeader->dlen );
771
+ _l2CapPduBufferSize += aclHeader->dlen ;
755
772
756
- if ((aclHdr->dlen - 4 ) != aclHdr->len ) {
773
+ l2CapPdu = _l2CapPduBuffer;
774
+ l2CapPduSize = _l2CapPduBufferSize;
775
+ } else {
776
+ // I don't think other values are allowed for BLE
757
777
#ifdef _BLE_TRACE_
758
- Serial.println (" Don't have full packet yet" );
759
- Serial.print (" Handle: " );
760
- btct.printBytes ((uint8_t *)&aclHdr->handle ,2 );
761
- Serial.print (" dlen: " );
762
- btct.printBytes ((uint8_t *)&aclHdr->dlen ,2 );
763
- Serial.print (" len: " );
764
- btct.printBytes ((uint8_t *)&aclHdr->len ,2 );
765
- Serial.print (" cid: " );
766
- btct.printBytes ((uint8_t *)&aclHdr->cid ,2 );
778
+ Serial.println (" Invalid pbFlag, discarding packet" );
767
779
#endif
768
- // don't have the full packet yet
769
780
return ;
770
781
}
771
782
772
- if (aclHdr->cid == ATT_CID) {
773
- if (aclFlags == 0x01 ) {
774
- // use buffered packet
775
- ATT.handleData (aclHdr->handle & 0x0fff , aclHdr->len , &_aclPktBuffer[sizeof (HCIACLHdr)]);
776
- } else {
777
- // use the recv buffer
778
- ATT.handleData (aclHdr->handle & 0x0fff , aclHdr->len , &_recvBuffer[1 + sizeof (HCIACLHdr)]);
779
- }
780
- } else if (aclHdr->cid == SIGNALING_CID) {
783
+ // We now have a valid L2CAP header in l2CapPdu and can parse the headers
784
+ struct __attribute__ ((packed)) HCIL2CapHdr {
785
+ uint16_t len; // size of the L2CAP SDU
786
+ uint16_t cid;
787
+ } *l2CapHeader = (HCIL2CapHdr*)l2CapPdu;
788
+
781
789
#ifdef _BLE_TRACE_
782
- Serial.println (" Signaling" );
790
+ Serial.print (" Received " );
791
+ Serial.print (l2CapPduSize - 4 , DEC);
792
+ Serial.print (" B/" );
793
+ Serial.print (l2CapHeader->len , DEC);
794
+ Serial.print (" B of the L2CAP SDU. CID = " );
795
+ Serial.println (l2CapHeader->cid , HEX);
783
796
#endif
784
- L2CAPSignaling. handleData (aclHdr-> handle & 0x0fff , aclHdr-> len , &_recvBuffer[ 1 + sizeof (HCIACLHdr)]);
785
- } else if (aclHdr-> cid == SECURITY_CID){
786
- // Security manager
797
+
798
+ // -4 because the buffer is the L2CAP PDU (with L2CAP header). The len field is only the L2CAP SDU (without L2CAP header).
799
+ if (l2CapPduSize - 4 != l2CapHeader-> len ) {
787
800
#ifdef _BLE_TRACE_
788
- Serial.println (" Security data " );
801
+ Serial.println (" L2CAP SDU incomplete " );
789
802
#endif
790
- if (aclFlags == 0x1 ){
791
- L2CAPSignaling.handleSecurityData (aclHdr->handle & 0x0fff , aclHdr->len , &_aclPktBuffer[sizeof (HCIACLHdr)]);
792
- }else {
793
- L2CAPSignaling.handleSecurityData (aclHdr->handle & 0x0fff , aclHdr->len , &_recvBuffer[1 + sizeof (HCIACLHdr)]);
803
+
804
+ // If this is a first packet, we have not copied it into the buffer yet
805
+ if (pbFlag == 0b10 ) {
806
+ #ifdef _BLE_TRACE_
807
+ Serial.println (" Storing first packet to L2CAP PDU buffer" );
808
+ if (_l2CapPduBufferSize != 0 ) {
809
+ Serial.print (" Warning: Discarding " );
810
+ Serial.print (_l2CapPduBufferSize, DEC);
811
+ Serial.println (" bytes from buffer" );
812
+ }
813
+ #endif
814
+
815
+ memcpy (_l2CapPduBuffer, l2CapPdu, l2CapPduSize);
816
+ _l2CapPduBufferSize = l2CapPduSize;
794
817
}
795
818
796
- }else {
819
+ // We need to wait for the missing parts of the L2CAP SDU
820
+ return ;
821
+ }
822
+
823
+ #ifdef _BLE_TRACE_
824
+ Serial.println (" L2CAP SDU complete" );
825
+ #endif
826
+
827
+ if (l2CapHeader->cid == ATT_CID) {
828
+ #ifdef _BLE_TRACE_
829
+ Serial.println (" CID: ATT" );
830
+ #endif
831
+ ATT.handleData (connectionHandle, l2CapHeader->len , &l2CapPdu[sizeof (HCIL2CapHdr)]);
832
+ } else if (l2CapHeader->cid == SIGNALING_CID) {
833
+ #ifdef _BLE_TRACE_
834
+ Serial.println (" CID: SIGNALING" );
835
+ #endif
836
+ L2CAPSignaling.handleData (connectionHandle, l2CapHeader->len , &l2CapPdu[sizeof (HCIL2CapHdr)]);
837
+ } else if (l2CapHeader->cid == SECURITY_CID) {
838
+ // Security manager
839
+ #ifdef _BLE_TRACE_
840
+ Serial.println (" CID: SECURITY" );
841
+ #endif
842
+ L2CAPSignaling.handleSecurityData (connectionHandle, l2CapHeader->len , &l2CapPdu[sizeof (HCIL2CapHdr)]);
843
+ } else {
797
844
struct __attribute__ ((packed)) {
798
845
uint8_t op;
799
846
uint8_t id;
800
847
uint16_t length;
801
848
uint16_t reason;
802
849
uint16_t localCid;
803
850
uint16_t remoteCid;
804
- } l2capRejectCid= { 0x01 , 0x00 , 0x006 , 0x0002 , aclHdr ->cid , 0x0000 };
851
+ } l2capRejectCid= { 0x01 , 0x00 , 0x006 , 0x0002 , l2CapHeader ->cid , 0x0000 };
805
852
#ifdef _BLE_TRACE_
806
- Serial.print (" rejecting packet cid: 0x" );
807
- Serial.println (aclHdr->cid ,HEX);
853
+ Serial.println (" Rejecting packet cid" );
808
854
#endif
809
855
810
- sendAclPkt (aclHdr-> handle & 0x0fff , 0x0005 , sizeof (l2capRejectCid), &l2capRejectCid);
856
+ sendAclPkt (connectionHandle , 0x0005 , sizeof (l2capRejectCid), &l2capRejectCid);
811
857
}
858
+
859
+ // We have processed everything in the buffer. Discard the contents.
860
+ _l2CapPduBufferSize = 0 ;
812
861
}
813
862
814
863
void HCIClass::handleNumCompPkts (uint16_t /* handle*/ , uint16_t numPkts)
0 commit comments