@@ -101,7 +101,8 @@ String commandToString(LE_COMMAND command){
101101HCIClass::HCIClass () :
102102 _debug(NULL ),
103103 _recvIndex(0 ),
104- _pendingPkt(0 )
104+ _pendingPkt(0 ),
105+ _l2CapPduBufferSize(0 )
105106{
106107}
107108
@@ -728,87 +729,135 @@ int HCIClass::sendCommand(uint16_t opcode, uint8_t plen, void* parameters)
728729void HCIClass::handleAclDataPkt (uint8_t /* plen*/ , uint8_t pdata[])
729730{
730731 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;
736735
736+ uint8_t bcFlag = (aclHeader->connectionHandleWithFlags & 0xc000 ) >> 14 ;
737+ uint8_t pbFlag = (aclHeader->connectionHandleWithFlags & 0x3000 ) >> 12 ;
738+ uint16_t connectionHandle = aclHeader->connectionHandleWithFlags & 0x0fff ;
737739
738- uint16_t aclFlags = (aclHdr-> handle & 0xf000 ) >> 12 ;
740+ uint8_t *aclSdu = &pdata[ sizeof (HCIACLHdr)] ;
739741
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
748752
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;
750756
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 ;
755772
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
757777#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" );
767779#endif
768- // don't have the full packet yet
769780 return ;
770781 }
771782
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+
781789#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);
783796#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 ) {
787800#ifdef _BLE_TRACE_
788- Serial.println (" Security data " );
801+ Serial.println (" L2CAP SDU incomplete " );
789802#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;
794817 }
795818
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 {
797844 struct __attribute__ ((packed)) {
798845 uint8_t op;
799846 uint8_t id;
800847 uint16_t length;
801848 uint16_t reason;
802849 uint16_t localCid;
803850 uint16_t remoteCid;
804- } l2capRejectCid= { 0x01 , 0x00 , 0x006 , 0x0002 , aclHdr ->cid , 0x0000 };
851+ } l2capRejectCid= { 0x01 , 0x00 , 0x006 , 0x0002 , l2CapHeader ->cid , 0x0000 };
805852#ifdef _BLE_TRACE_
806- Serial.print (" rejecting packet cid: 0x" );
807- Serial.println (aclHdr->cid ,HEX);
853+ Serial.println (" Rejecting packet cid" );
808854#endif
809855
810- sendAclPkt (aclHdr-> handle & 0x0fff , 0x0005 , sizeof (l2capRejectCid), &l2capRejectCid);
856+ sendAclPkt (connectionHandle , 0x0005 , sizeof (l2capRejectCid), &l2capRejectCid);
811857 }
858+
859+ // We have processed everything in the buffer. Discard the contents.
860+ _l2CapPduBufferSize = 0 ;
812861}
813862
814863void HCIClass::handleNumCompPkts (uint16_t /* handle*/ , uint16_t numPkts)
0 commit comments