bluetooth/btstack/l2cap/L2CapPDU.h
changeset 0 29b1cd4cb562
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/bluetooth/btstack/l2cap/L2CapPDU.h	Fri Jan 15 08:13:17 2010 +0200
@@ -0,0 +1,682 @@
+// Copyright (c) 2004-2009 Nokia Corporation and/or its subsidiary(-ies).
+// All rights reserved.
+// This component and the accompanying materials are made available
+// under the terms of "Eclipse Public License v1.0"
+// which accompanies this distribution, and is available
+// at the URL "http://www.eclipse.org/legal/epl-v10.html".
+//
+// Initial Contributors:
+// Nokia Corporation - initial contribution.
+//
+// Contributors:
+//
+// Description:
+//
+
+#ifndef L2CAPPDU_H_
+#define L2CAPPDU_H_
+
+#include <e32std.h>
+#include <es_sock.h>
+#include <es_prot.h>
+
+#include <es_mbuf.h>
+#include <bttypes.h>
+
+#include "L2types.h"
+#include "l2util.h"
+
+class HL2CapCommand;
+class CServProviderBase;
+class CL2CAPMux;
+class CL2CapDataFlowController;
+
+class HIFramePDU;
+class HBFramePDU;
+class HGFramePDU;
+class HCFramePDU;
+class HSFramePDU;
+class HL2CapPDU;
+
+class MOutgoingPDUHandler
+	{
+public:
+	virtual TInt HandleOutgoingIFrame(HIFramePDU* aIFrame) = 0;
+	virtual TInt HandleOutgoingBFrame(HBFramePDU* aBFrame) = 0;
+	virtual TInt HandleOutgoingGFrame(HGFramePDU* aGFrame) = 0;
+	virtual TInt HandleOutgoingCFrame(HCFramePDU* aCFrame) = 0;
+	virtual TInt HandleOutgoingSFrame(HSFramePDU* aSFrame) = 0;
+	};
+
+// A PDU owner gets notified though this interface when a PDU send operation is complete.
+// It's then up to the owner to delete the PDU or resend it, and to move it between
+// various PDU lists - a PDU should not call iLink.Deque() nor destruct itself unless
+// it has been orphaned.
+// In practice CL2CAPMux owns C-, S- and B-Frames, while (E)RTM Data Controllers own
+// I-Frames.
+class MPduOwner
+	{
+public:
+	virtual void HandlePduSendComplete(HL2CapPDU& aPdu) = 0;
+	virtual void HandlePduSendError(HL2CapPDU& aPdu) = 0;
+	};
+
+enum TL2CapSAR
+	{
+	EUnsegmentedL2CapSDU	= 0,
+	EStartOfL2CapSDU		= 1,
+	EEndOfL2CapSDU			= 2,
+	EContinuationOfL2CapSDU	= 3,
+	};
+	
+enum TSupervisoryFunction
+	{
+	EReceiverReady		= 0,
+	EReject				= 1,
+	EReceiverNotReady	= 2,
+	ESelectiveReject	= 3,
+	};
+
+class MDataPlaneElement
+	{
+public:
+	virtual void DataElementSent(TUint16 aElementID = 0) = 0;
+	virtual void DataElementFlushed(TUint16 aElementID = 0) = 0;
+
+	virtual TBool IsPDUFlushed() const = 0;
+	};
+	
+NONSHARABLE_CLASS(TDataPlaneElementHandle) : public TSockAddr
+	{
+public:
+	struct SDataPlaneElementHandle
+		{
+		MDataPlaneElement* iDataElement;
+		TUint16 iElementID;
+		};
+			
+	TDataPlaneElementHandle(MDataPlaneElement* aDataElement, TUint16 aElementID = 0);
+
+	MDataPlaneElement& DataPlaneElement() const;
+	TUint16 ElementID() const;
+	};
+
+
+//
+// Base class for all PDU types.
+//
+NONSHARABLE_CLASS(HL2CapPDU) : public MDataPlaneElement
+	{
+public:
+	// Base or shared length definitions.	
+	const static TUint8 KPDUHeaderLength 			= 4;
+	const static TUint8 KControlFieldLength			= 2;		
+	const static TUint8 KSDULengthFieldLength		= 2;
+	const static TUint8 KMaxPDUHeaderLength			= KPDUHeaderLength + KControlFieldLength + KSDULengthFieldLength;		
+	const static TUint8 KFCSFieldLength				= 2;
+	const static TUint8 KSFrameLength				= 8;
+
+	const static TUint8 KNumberOfFragmentsUnknown 	= 0;
+		
+	virtual ~HL2CapPDU();
+	
+	// Deliver Interface.
+	virtual void DeliverOutgoingPDU(MOutgoingPDUHandler& aPDUHandler);
+
+	// Method for reconstructing SDU data.
+	virtual void AppendPayloadToBuffer(RMBufChain& aSDUData);
+	 
+	// Message Accessors.
+	// Static
+	static TUint16 PDUPayloadLength(const RMBufChain& aPDU);
+	static TUint16 PDUCID(const RMBufChain& aPDU);
+    static TInt CheckDecode(const RMBufChain& aPDU);
+
+	// This method appends a fragment to the aPDU parameter and then
+	// checks if the PDU is complete.
+	static TBool AddFragment(RMBufChain& aPDU, RMBufChain& aPDUFragment);
+
+	// Member
+	inline TUint16 PDUPayloadLength() const;
+
+	inline TUint16 PDUCID() const;
+	void SetPDUCID(TUint16 aCID);
+
+	// Calculate the PDU length, and place it in the PDU header.
+	void WritePDUPayloadLength();  
+
+	// For basic mode return the fragment overhead otherwise return the
+	// L2CAP PDU overhead in bytes.
+	static TInt GetPDUOrFragmentOverhead(TBool aBasicMode);
+	
+	// Return the optimal PDU size based on the MTU and controller buffer size.
+	static TInt GetPDUOrFragmentSize(TInt aMTU, TInt aMaxMps, TInt aBufSize, TBool aBasicMode);
+	
+	inline TInt OptimalFragmentSize() const;
+	
+	// Inline accessor methods.
+	inline RMBufChain& PDUBuffer();
+	inline void SetPDUFlushed();
+	inline TBool IsPDUFlushed() const;
+	inline TDataPlaneElementHandle& ElementHandle();
+
+	void PDUSendPending(TUint16 aTotalNumberOfFragments);
+	void PDUSendComplete();
+	
+	inline void SetPduOwner(MPduOwner* aPduOwner);
+	inline TBool HasOwner() const;
+	inline TBool IsOwner(const MPduOwner* aPduOwner) const;
+	inline void DeregisterPduOwner();
+
+	inline TBool IsAwaitingHciCompletion() const;
+
+	inline TBool IsQueuedForSend() const;
+	inline void SetQueuedForSend(TBool aQueuedForSend);
+
+	// MDataPlaneElement Interface
+	void DataElementSent(TUint16 aElementID);
+	void DataElementFlushed(TUint16 aElementID);
+		
+protected:
+	// An optimal fragment size of 0 indicates that we do not expect fragmentation to take place
+	HL2CapPDU(RMBufChain& aPDUData, TInt aOptimalFragmentSize);
+	HL2CapPDU(TInt aOptimalFragmentSize = 0);
+
+	void SetPDUPayloadLength(TUint16 aLength);
+
+	virtual void DeliverOutgoingPDUDoubleDispatch(MOutgoingPDUHandler& aPDUHandler) = 0;
+	virtual void SendComplete(); // for frame type-specific actions on send complete
+
+	inline TUint16 CalcCRC();	
+	static TUint16 CalcCRC(const RMBufChain& aPDU);	
+
+public:
+	// General link though which the PDU is "owned" by different entities during its lifetime.
+	// An I-Frame PDU starts as a member of the PDU list in its SDU, then is pulled by a data
+	// controller and depending on the data controller, proceeds through its unacknowledged I-Frame
+	// lists (RTM and ERTM). B-Frames start linked to their SDUs but then are put on link muxer's
+	// PDU list, because Basic mode doesn't do retransmissions, so the data controller doesn't care.
+	// S-Frames are created inside data controllers and are put on the link muxer's list as well -
+	// they are fire'n'forget too.
+	// Note that the owning relationship is formalized with the MPduOwner interface.
+	TDblQueLink iLink;
+	// This is an additional link that can be used by a data controller to manage internal PDU
+	// queues. (currently used in ERTM for Outgoing Q)
+	TSglQueLink iDataControllerInternalQLink;
+protected:
+	// Base or shared field positions. 
+	const static TUint8 KLengthByteOffset 			= 0;
+	const static TUint8 KCIDByteOffset 				= 2;
+	const static TUint8 KControlFieldByteOffset 	= 4;
+	const static TUint8 KSDULengthFieldByteOffset 	= 6;
+
+	// Control field bit masks.	
+	const static TUint16 KCtrlFrameTypeMask 	= 0x0001;
+	const static TUint16 KCtrlTxSeqMask			= 0x007e;
+	const static TUint16 KCtrlReTxDisableMask	= 0x0080;
+	const static TUint16 KCtrlFinalBitMask		= 0x0080;
+	const static TUint16 KCtrlPollBitMask		= 0x0010;
+	const static TUint16 KCtrlReqSeqMask		= 0x3f00;
+	const static TUint16 KCtrlSARMask			= 0xc000;
+	const static TUint16 KCtrlSupervisoryMask	= 0x000c;
+
+	// Control field bit shifters.
+	const static TUint16 KCtrlTxSeqShift		= 1;
+	const static TUint16 KCtrlReTxDisableShift	= 7;
+	const static TUint16 KCtrlReqSeqShift		= 8;
+	const static TUint16 KCtrlSARShift			= 14;
+				
+	// All message information is held in this buffer.	
+	RMBufChain iPDUData;
+
+	TBool iIsFlushed;
+	TBool iSendingError;
+
+	// True when it's on the OutgoingQ in ERTM waiting for GetPdu to pull it.
+	// Used for protecting the consistency of the OutgoingQ list - we mustn't try to
+	// queue the same frame twice. Also useful for detecting misbehaving remotes, if
+	// they try to request a retransmission of the same I-Frame more than once (per
+	// one loss).
+	TBool iQueuedForSend;
+
+	// This indicates whether an initiated transmission has been completed by HCI or not,
+	// so that a retransmission of the PDU can proceed or be stalled until this becomes false.
+	// A PDU is supposed to start its life with this condition = False so that the initial
+	// transmission can proceed, and then it should become True once the PDU is scheduled
+	// for transmission. This is important for PDUs that can are acknowledgable or can be
+	// rejected by the peer (read I-Frames). In case the acknowledgement/reject comes through
+	// before the HCI completion event (which happens with the USB HCTL on Windows) we want
+	// to wait until an I-Frame is transmitted until we can delete it/start re-transmitting it.
+	// Note: an I-Frame may be queued for a retransmission before being completed by HCI
+	// (because it may happen that we receive the (S)REJ before the HCI packet completion
+	// event). That's why there are separate boolean flags instead of a single PDU state
+	// enum.
+	TBool iAwaitingHciCompletion;
+
+	TDataPlaneElementHandle iElementHandle;
+	MPduOwner* iPduOwner;	// Non-owned pointer.
+	
+	// Optimal Fragment size.
+	// Only set for basic mode as we expect segmentation only in all other cases.
+	TInt iOptimalFragmentSize;
+	
+public:	
+	TUint16 iTotalNumberOfFragments;
+	TUint16 iFragmentAcksReceived;
+	};
+
+//
+// Class used to fragment and send any type of PDU.
+// An instance of this class is currently owned by the Mux
+//
+NONSHARABLE_CLASS(HFragmentedPDUSender)
+	{
+public:
+	enum TFragmentSenderStatus
+		{
+		EFragmentOK				= 0,
+		EFragmentationComplete 	= 1,
+		EFlowControlledOff 		= 2,
+		};
+		
+	HFragmentedPDUSender(CL2CAPMux& aMuxer);
+	~HFragmentedPDUSender();
+		
+	TInt FragmentPDU(HL2CapPDU& aPDU);
+	TFragmentSenderStatus WriteNextFragment(CServProviderBase& aSender, TInt aACLMTU);
+	inline TBool IsPDUBeingSent() const; 
+
+	void Reset();
+	void CheckForFlushed();
+	void PDUSenderFailed();
+
+private:
+	HL2CapPDU* iPDU;			// Non-owned
+	HBufC8* iPDUBuffer;			// Buffer for the outgoing PDU.
+	CL2CAPMux& iMuxer;			// Reference to the sending object.
+	TInt iCurrentWriteIndex;	// Current position in the PDU buffer.
+	TUint16 iCurrentFragmentID;	// Current [next] fragment ID to be sent (first fragment has ID = 0)
+	TInt iPDULength;			// Length of the PDU being sent.
+	TInt iPDUFragmentSize;		// Optimal fragment size.
+	};
+
+//
+// Basic frame PDU class.
+//
+NONSHARABLE_CLASS(HBFramePDU) : public HL2CapPDU
+	{
+public:
+	~HBFramePDU();
+
+	static HBFramePDU* New(RMBufChain& aPayloadData, TInt aOptimalFragmentSize);
+
+	// Deliver Interface.
+	void DeliverOutgoingPDUDoubleDispatch(MOutgoingPDUHandler& aPDUHandler);
+
+	static void RemoveHeaderBytes(RMBufChain& aPDU);
+	void AppendPayloadToBuffer(RMBufChain& aSDUData);
+
+	void PDUFragmentSent(TUint16 aFragmentIx);
+	
+	static TInt CheckPayloadDecode(const RMBufChain& aPDU);
+		
+private:
+	HBFramePDU(RMBufChain& aPDUData, TInt aOptimalFragmentSize);
+
+	virtual void SendComplete();
+	};
+
+	
+//
+// Information frame PDU class.
+//
+NONSHARABLE_CLASS(HIFramePDU) : public HL2CapPDU
+	{
+public:
+	~HIFramePDU();
+	
+	static HIFramePDU* New(RMBufChain& aPayloadData, TL2CapSAR aPduSAR);
+
+	// Deliver Interface.
+	void DeliverOutgoingPDUDoubleDispatch(MOutgoingPDUHandler& aPDUHandler);
+
+	// Message Accessors.
+	// Static
+	static TBool IFrameIdentifier(const RMBufChain& aPDU);
+	static TBool CheckFCS(const RMBufChain& aPDU);
+	static TInt CheckPayloadDecode(const RMBufChain& aPDU);
+	static TInt CheckLengthWithinLimits(const RMBufChain& aPDU, TUint16 aMps);
+	static TInt CheckStartSduLength(const RMBufChain& aPDU, TUint16 aMtu);
+	static TL2CapSAR SAR(const RMBufChain& aPDU);
+	static void RemoveHeaderAndFCSBytes(RMBufChain& aPDU);
+	static TBool IsStartOfSDU(const RMBufChain& aPDU);
+	static TUint16 SDUSize(const RMBufChain& aPDU);
+	static TUint8 ReqSeqNumber(const RMBufChain& aPDU);
+	static TUint8 TxSeqNumber(const RMBufChain& aPDU);
+	static TBool FinalBit(const RMBufChain& aPDU);
+	static TBool RetransmitDisable(const RMBufChain& aPDU);
+	
+	// Member
+	void SetFinalBit(TBool aFinalBit);
+	inline TBool FinalBit() const;
+	
+	inline TUint8 TxSeqNumber() const;
+	void SetTxSeqNumber(TUint8 aTxSeqNum);
+	
+	void SetRetransmitDisable(TBool aReTxDisable);
+
+	inline TUint8 ReqSeqNumber() const;
+	void SetReqSeqNumber(TUint8 aReqSeqNum);
+	
+	inline TL2CapSAR SAR() const;
+	void SetSAR(TL2CapSAR aSARValue);
+	
+	inline TUint16 SDUSize() const;
+	void SetSDUSize(TUint16 aSDUSize);
+	
+	void CalculateAndSetFCS();
+	TBool CheckFCS();
+	
+	void AppendPayloadToBuffer(RMBufChain& aSDUData);	
+
+	inline TBool IsStartOfSDU() const;
+	
+	// Re-transmission Methods
+	inline TBool CanTransmit(TUint8 aMaxNumberOfTransmissions) const;
+	inline TUint8 TransmissionCount() const;
+	
+	inline TBool Acked() const { return iAcked; }
+	inline void SetAcked(TBool aAcked) { iAcked = aAcked; }
+
+private:
+	const static TUint16 KIFrameControlDefault	= 0x0000;			
+
+	HIFramePDU(RMBufChain& aPDUData);
+
+	void SetIFrameControlDefault();
+	virtual void SendComplete();
+
+	TUint8 iTransmissionCount;
+	TBool iAcked;					// has been acknowledged by the remote
+	};
+
+//
+// Group frame PDU class.
+//
+NONSHARABLE_CLASS(HGFramePDU) : public HL2CapPDU
+	{
+public:
+	HGFramePDU(RMBufChain& aPDUData);
+	~HGFramePDU();
+	
+	static HGFramePDU* New(RMBufChain& aPayloadData);
+
+	// Deliver Interface.
+	void DeliverOutgoingPDUDoubleDispatch(MOutgoingPDUHandler& aPDUHandler);
+
+	TUint16 PSM() const;
+	void SetPSM(TUint16 aPSM);
+	
+	void AppendPayloadToBuffer(RMBufChain& aSDUData);
+	
+private:
+	const static TUint8 KGFramePSMLength 			= 2;
+	};
+
+
+//
+// Control frame PDU class.
+//
+NONSHARABLE_CLASS(HCFramePDU) : public HL2CapPDU
+	{
+public:
+	const static TUint8 KCFrameHeaderLength			= 4;
+	const static TUint8 KCFrameCodeSize				= 1;
+	const static TUint8 KCFrameIdentifierSize		= 1;
+	const static TUint8 KCFrameLengthSize     		= 2;
+		
+	static HCFramePDU* New(TInt aOptimalFragmentSize);
+
+	HCFramePDU(RMBufChain& aPDUData, TInt aOptimalFragmentSize);
+	
+	~HCFramePDU();
+
+	// Deliver Interface.
+	void DeliverOutgoingPDUDoubleDispatch(MOutgoingPDUHandler& aPDUHandler);
+
+	HL2CapCommand* FirstCommand();
+	HL2CapCommand* NextCommand();
+
+	inline TBool HasCommands() const;
+	
+	TInt AddCommand(HL2CapCommand& aCommand, CL2CAPMux& aMuxer);
+	TInt CheckDecode();
+	
+private:
+	TInt CheckPayloadDecode();
+	TInt CreateCommands();
+	
+	//Dbl link list of commands included within this pdu
+	TDblQue<HL2CapCommand> iCommands;
+	TDblQueIter<HL2CapCommand> iCommandIter;
+	};
+
+
+//
+// Supervisory frame PDU class.
+//
+NONSHARABLE_CLASS(HSFramePDU) : public HL2CapPDU
+	{
+public:
+	HSFramePDU(RMBufChain& aPDUData);
+	~HSFramePDU();
+	
+	static HSFramePDU* New(TSupervisoryFunction aFunction);
+	static HSFramePDU* NewL(TSupervisoryFunction aFunction);
+
+	// Deliver Interface.
+	void DeliverOutgoingPDUDoubleDispatch(MOutgoingPDUHandler& aPDUHandler);
+
+	// Message Accessors.
+	// Static
+	static TInt CheckLengthField(const RMBufChain& aPDU);
+	static TBool CheckFCS(RMBufChain& aPDU);
+	static TInt CheckPayloadDecode(RMBufChain& aPDU);
+	static TSupervisoryFunction SupervisoryFunction(const RMBufChain& aPDU);
+	static TUint8 ReqSeqNumber(const RMBufChain& aPDU);
+	static TBool RetransmitDisable(const RMBufChain& aPDU);
+	static TBool FinalBit(const RMBufChain& aPDU);
+	static TBool PollBit(const RMBufChain& aPDU);
+	
+	// Members
+	void SetFinalBit(TBool aFinalBit);
+	inline TBool FinalBit() const;
+
+	void SetPollBit(TBool aPollBit);
+	inline TBool PollBit() const;
+
+	void SetSupervisoryFunction(TSupervisoryFunction aSupervisoryFunction);
+	inline TSupervisoryFunction SupervisoryFunction() const;
+
+	void SetRetransmitDisable(TBool aReTxDisable);
+	void SetReqSeqNumber(TUint8 aReqSeqNum);
+	inline TUint8 ReqSeqNumber() const;
+	
+	void CalculateAndSetFCS();
+	TInt CheckFCS();
+
+	void SetSFrameControlDefault();
+	
+	void PDUFragmentSent(TUint16 aFragmentIx);
+	
+private:
+	const static TUint16 KSFrameControlDefault	= 0x0001;			
+	};
+
+
+//
+// PDU Fragment sender inline methods.
+//
+inline TBool HFragmentedPDUSender::IsPDUBeingSent() const
+	{
+	return (iPDU != NULL);
+	}
+
+
+//
+// Base class inline methods.
+//
+inline RMBufChain& HL2CapPDU::PDUBuffer()
+	{
+	return iPDUData;
+	}
+
+inline void HL2CapPDU::SetPDUFlushed()
+	{
+	iIsFlushed = ETrue;
+	}
+	
+inline TBool HL2CapPDU::IsPDUFlushed() const
+	{
+	return iIsFlushed;
+	}
+
+inline TDataPlaneElementHandle& HL2CapPDU::ElementHandle()
+	{
+	return iElementHandle;
+	}
+
+inline TUint16 HL2CapPDU::PDUCID() const
+	{
+	return PDUCID(iPDUData);
+	}
+
+inline TUint16 HL2CapPDU::PDUPayloadLength() const
+	{
+	return PDUPayloadLength(iPDUData);
+	}
+
+inline TUint16 HL2CapPDU::CalcCRC()	
+	{
+	return CalcCRC(iPDUData);
+	}
+	
+inline TInt HL2CapPDU::OptimalFragmentSize() const
+	{
+	return iOptimalFragmentSize;
+	}
+
+inline void HL2CapPDU::SetPduOwner(MPduOwner* aPduOwner)
+	{
+	__ASSERT_ALWAYS(aPduOwner != NULL, Panic(EL2CAPNullOwnerSupplied));
+	__ASSERT_ALWAYS(iPduOwner == NULL || iPduOwner == aPduOwner, Panic(EL2CAPTryingToStealOwnedPdu));
+	iPduOwner = aPduOwner;
+	}
+
+inline TBool HL2CapPDU::HasOwner() const
+	{
+	return iPduOwner != NULL;
+	}
+
+inline TBool HL2CapPDU::IsOwner(const MPduOwner* aPduOwner) const
+	{
+	__ASSERT_ALWAYS(aPduOwner != NULL, Panic(EL2CAPNullOwnerSupplied));
+	return iPduOwner == aPduOwner;
+	}
+
+inline void HL2CapPDU::DeregisterPduOwner()
+	{
+	iPduOwner = NULL;
+	}
+
+inline TBool HL2CapPDU::IsAwaitingHciCompletion() const
+	{
+	return iAwaitingHciCompletion;
+	}
+
+inline TBool HL2CapPDU::IsQueuedForSend() const
+	{
+	return iQueuedForSend;
+	}
+
+inline void HL2CapPDU::SetQueuedForSend(TBool aQueuedForSend)
+	{
+	iQueuedForSend = aQueuedForSend;
+	}
+
+//
+// Information frame inline methods.
+//
+inline TBool HIFramePDU::CanTransmit(TUint8 aMaxNumberOfTransmissions) const
+	{
+	return (iTransmissionCount < aMaxNumberOfTransmissions);
+	}
+
+inline TUint8 HIFramePDU::TransmissionCount() const
+	{
+	return iTransmissionCount;
+	}
+
+
+inline TL2CapSAR HIFramePDU::SAR() const
+	{
+	return SAR(iPDUData);
+	}
+	
+inline TBool HIFramePDU::IsStartOfSDU() const
+	{
+	return IsStartOfSDU(iPDUData);
+	}
+
+inline TUint16 HIFramePDU::SDUSize() const
+	{
+	return SDUSize(iPDUData);
+	}
+
+inline TUint8 HIFramePDU::ReqSeqNumber() const
+	{
+	return ReqSeqNumber(iPDUData);
+	}
+
+inline TUint8 HIFramePDU::TxSeqNumber() const
+	{
+	return TxSeqNumber(iPDUData);
+	}
+
+inline TBool HIFramePDU::FinalBit() const
+	{
+	return FinalBit(iPDUData);
+	}
+
+//
+// Control frame inline methods.
+//
+inline TBool HCFramePDU::HasCommands() const
+	{
+	return !iCommands.IsEmpty();
+	}
+
+//
+// Supervisory frame inline methods.
+//
+inline TBool HSFramePDU::FinalBit() const
+	{
+	return FinalBit(iPDUData); 
+	}
+
+inline TBool HSFramePDU::PollBit() const
+	{
+	return PollBit(iPDUData);
+	}
+
+inline TSupervisoryFunction HSFramePDU::SupervisoryFunction() const
+	{
+	return SupervisoryFunction(iPDUData);
+	}
+
+inline TUint8 HSFramePDU::ReqSeqNumber() const
+	{
+	return ReqSeqNumber(iPDUData);
+	}
+
+#endif