//--------------------------------------------------------------------
// Copyright (C)1998 Microsoft Corporation, All Rights Reserved.
//
// scep.h
//
// Constants and Types for the Simple Command Execution Protocol
// (SCEP). This is the transport protocol for IrTran-P V1.0.
//
// NOTE: That IrTran-P is a big-endian protocol when on the net.
//
// NOTE: That the protocol data structures below assume that the
//       compiler generates structures with natural alignment by
//       field type.
//
// Author:
//
//   Edward Reus (edwardr)     02-05-98   Initial coding.
//
//--------------------------------------------------------------------


#ifndef _SCEP_H_
#define _SCEP_H_

#ifndef _BFTP_H_
#include "bftp.h"
#endif

//--------------------------------------------------------------------
//  Constants:
//--------------------------------------------------------------------

#define  LITTLE_ENDIAN

#define  PROTOCOL_VERSION             0x01
#define  NEGOTIATION_VERSION          0x11   // SCEP_NEGOTIATION revision.
#define  INF_VERSION                  0x10   // Information Struct version.

#define  USE_LENGTH2                  0xff

// These PDU sizes are the default and negotiated sizes:
#define  PDU_SIZE_1                    512
#define  PDU_SIZE_2                   1024
#define  PDU_SIZE_3                   2048
#define  PDU_SIZE_4                   4096
#define  MAX_PDU_SIZE           PDU_SIZE_4

#define  DEFAULT_PDU_SIZE     MAX_PDU_SIZE

// These sizes are used to check if we have a complete PDU:
#define  MIN_PDU_SIZE_CONNECT           28
#define  MAX_PDU_SIZE_CONNECT          256
#define  MIN_PDU_SIZE_CONNECT_RESP      24
#define  MAX_PDU_SIZE_CONNECT_RESP     255

#define  MIN_PDU_SIZE_DATA               8

#define  MIN_PDU_SIZE_DISCONNECT         6

// These are the sizes of the SCEP headers:
#define  SCEP_HEADER_SIZE                2
#define  SCEP_REQ_HEADER_SHORT_SIZE     34
#define  COMMAND_HEADER_SIZE            28

#define  FILE_NAME_SIZE                 12  // 8.3

// These are the attribute strings that go in the negotiation part
// of connect request and response PDUs:
#define  CONNECT_PDU_ATTRIBUTES  "fr:3\r\nid:Microsoft IrTran-P v1.0\r\n"
#define  RESPONSE_PDU_ATTRIBUTES "fr:4\r\nid:Microsoft IrTran-P v1.0\r\n"

// Message Types (field: MsgType):
#define  MSG_TYPE_CONNECT_REQ         0x10  // Connection request.
#define  MSG_TYPE_CONNECT_RESP        0x11  // Connection confirmation.
#define  MSG_TYPE_DATA                0x20  // Data PDU.
#define  MSG_TYPE_DISCONNECT          0x30  // Disconnection.

// Information Types (field: InfType):
#define  INF_TYPE_VERSION             0x00  // Connection establishment.
#define  INF_TYPE_NEGOTIATION         0x01  // Connection establish or accept.
#define  INF_TYPE_USER_DATA           0x03  // Only if MsgType is MSG_TYPE_DATA.
#define  INF_TYPE_EXTEND              0x10  // Connection establishment.
#define  INF_TYPE_REASON              0x20  // Only for disconnect.

// Command Header: Pdu Types (top two bits in PduType):
#define  PDU_TYPE_REQUEST             0x00  // b:00000000
#define  PDU_TYPE_REPLY_ACK           0x40  // b:01000000
#define  PDU_TYPE_REPLY_NACK          0x80  // b:10000000
#define  PDU_TYPE_ABORT               0xc0  // b:11000000

#define  PDU_TYPE_MASK                0xc0  // b:11000000
#define  PDU_TYPE_RESERVED            0x3f  // b:00111111

// The machine ID is in the Connect PDU (SCEP_NEGOTIATION), it
// is in EUI-64 format:
#define  MACHINE_ID_SIZE                 8

// Machine PIDs: In the command header, the default source and destination
// program Ids are unsigned shorts with value 8. Some machines will have
// a PID other than this (see the first command header sent to us):
#define  DEFAULT_PID                     8

// CFlag meanings:
//
// There are two cases, one where a device/machine can only issue commands,
// the other when a device can both issue and execute commands.
//
#define  CFLAG_ISSUE_ONLY             0x00
#define  CFLAG_ISSUE_OR_EXECUTE       0x04

// DFlag Meanings:
//
// DFlag give information about the data and fragmentation (why did they
// put the reject in here?).
//
#define  DFLAG_SINGLE_PDU             0xc1
#define  DFLAG_FIRST_FRAGMENT         0x41
#define  DFLAG_FRAGMENT               0x01
#define  DFLAG_LAST_FRAGMENT          0x81
#define  DFLAG_INTERRUPT              0xc2
#define  DFLAG_CONNECT_REJECT         0xc3

// Reason Codes:
//
// Currently for V1.0 all reason codes are 2-byte numbers:
#define  REASON_CODE_UNSPECIFIED          0x0000
#define  REASON_CODE_USER_DISCONNECT      0x0001
#define  REASON_CODE_PROVIDER_DISCONNECT  0x0002

// Connection States:
#define  STATE_CLOSED                       0
#define  STATE_CONNECTING                   1
#define  STATE_CONNECTED                    2

// Put Response Protocol Error Codes (sent back to the camera):
#define  ERROR_PUT_UNDEFINED_ERROR     0x0000
#define  ERROR_PUT_ILLEGAL_DATA        0x0001
#define  ERROR_PUT_UNSUPPORTED_PID     0x0002
#define  ERROR_PUT_ILLEGAL_ATTRIBUTE   0x0010
#define  ERROR_PUT_UNSUPPORTED_CMD     0x0011
#define  ERROR_PUT_FILE_SYSTEM_FULL    0x0020
#define  ERROR_PUT_NO_FILE_OR_DIR      0x0021
#define  ERROR_PUT_LOW_BATTERY         0x0030
#define  ERROR_PUT_ABORT_EXECUTION     0x0031
#define  ERROR_PUT_NO_ERROR            0xffff

//--------------------------------------------------------------------
//  SCEP Protocol Headers:
//--------------------------------------------------------------------

// Turn off warning for zero-sized array...
#pragma warning(disable:4200)
#pragma pack(1)

typedef struct _SCEP_HEADER
   {
   UCHAR  Null;          // Always zero.
   UCHAR  MsgType;       // See MSG_TYPE_* above.
   UCHAR  Rest[];        // Dependent on the MsgType...
   } SCEP_HEADER;

typedef struct _SCEP_VERSION
   {
   UCHAR  InfType;       // Always INF_TYPE_VERSION (0x00).
   UCHAR  Version;       // Currently 0x01 (Version = 1).
   } SCEP_VERSION;

typedef struct _SCEP_NEGOTIATION
   {
   UCHAR  InfType;       // Always INF_TYPE_NEGOTATION (0x01).
   UCHAR  Length;        // Length (bytes) from InfVersion to
                         //   the end of the Negotiation information.
                         //   This will be from 0 to 228.
   UCHAR  InfVersion;    // Version of InfType = INF_VERSION.
   UCHAR  CFlag;         //
   UCHAR  SecondaryMachineId[8]; //
   UCHAR  PrimaryMachineId[8];   //
   UCHAR  Negotiation[]; //
   } SCEP_NEGOTIATION;

typedef struct _SCEP_DISCONNECT
   {
   UCHAR  InfType;       // Always INF_TYPE_REASON (0x20).
   UCHAR  Length1;       // For V1.0 this should be 2.
   USHORT ReasonCode;    // See the REASON_CODE_xxx
   } SCEP_DISCONNECT;

typedef struct _SCEP_EXTEND
   {
   UCHAR  InfType;       // Always INF_TYPE_EXTEND (0x10).
   UCHAR  Length;        // Always 2 (bytes).
   UCHAR  Parameter1;
   UCHAR  Parameter2;
   } SCEP_EXTEND;

typedef struct _COMMAND_HEADER
   {
   UCHAR  Marker58h;      // Always 0x58 (See: 3.2.2.1.3 of Protocol).
   UCHAR  PduType;        // One of: PDU_TYPE_xxxx.
   ULONG  Length4;
   UCHAR  DestMachineId[MACHINE_ID_SIZE];
   UCHAR  SrcMachineId[MACHINE_ID_SIZE];
   USHORT DestPid;
   USHORT SrcPid;
   USHORT CommandId;
   } COMMAND_HEADER;

typedef struct _SCEP_REQ_HEADER_SHORT
   {
   UCHAR  InfType;       // Always INF_TYPE_USER_DATA (0x03).
   UCHAR  Length1;
   UCHAR  InfVersion;    // Version of InfType = INF_VERSION.
   UCHAR  DFlag;
   USHORT Length3;
   UCHAR  CommandHeader[sizeof(COMMAND_HEADER)];
   UCHAR  UserData[];
   } SCEP_REQ_HEADER_SHORT;

typedef struct _SCEP_REQ_HEADER_LONG
   {
   UCHAR  InfType;       // Always INF_TYPE_USER_DATA (0x03).
   UCHAR  Length1;
   USHORT Length2;       // Only present if Length1 == 0xff.
   UCHAR  InfVersion;    // Version of InfType = INF_VERSION.
   UCHAR  DFlag;
   USHORT Length3;
   UCHAR  CommandHeader[sizeof(COMMAND_HEADER)];
   UCHAR  UserData[];
   } SCEP_REQ_HEADER_LONG;

typedef struct _SCEP_REQ_HEADER_SHORT_FRAG
   {
   UCHAR  Inftype;       // Always INF_TYPE_USER_DATA (0x03).
   UCHAR  Length1;
   UCHAR  InfVersion;    // Version of InfType = INF_VERSION.
   UCHAR  DFlag;
   USHORT Length3;
   DWORD  SequenceNo;    // Fragment number.
   DWORD  RestNo;        // Number of fragments left for this PDU.
   UCHAR  CommandHeader[sizeof(COMMAND_HEADER)];
   UCHAR  UserData[];
   } SCEP_REQ_HEADER_SHORT_FRAG;

typedef struct _SCEP_REQ_HEADER_LONG_FRAG
   {
   UCHAR  InfType;       // Always INF_TYPE_USER_DATA (0x03).
   UCHAR  Length1;
   USHORT Length2;       // Only present if Length1 == 0xff.
   UCHAR  InfVersion;    // Version of InfType = INF_VERSION.
   UCHAR  DFlag;
   USHORT Length3;
   DWORD  SequenceNo;    // Fragment number.
   DWORD  RestNo;        // Number of fragments left for this PDU.
   UCHAR  CommandHeader[sizeof(COMMAND_HEADER)];
   UCHAR  UserData[];
   } SCEP_REQ_HEADER_LONG_FRAG;

#pragma pack()
#pragma warning(default:4200)

//--------------------------------------------------------------------
//  SCEP API Structures:
//--------------------------------------------------------------------

class CSCEP_CONNECTION
{
public:
    CSCEP_CONNECTION();
    ~CSCEP_CONNECTION();

    void  *operator new( IN size_t Size );

    void   operator delete( IN void  *pObj,
                            IN size_t Size );

    // Assemble the next PDU as data comes in:
    DWORD  AssemblePdu( IN  void         *pInputData,
                        IN  DWORD         dwInputDataSize,
                        OUT SCEP_HEADER **ppPdu,
                        OUT DWORD        *pdwPduSize );

    // Parse the PDU returned from AssemblePdu():
    DWORD  ParsePdu( IN  SCEP_HEADER *pPdu,
                     IN  DWORD        dwPduSize,
                     OUT COMMAND_HEADER **ppCommand,
                     OUT UCHAR          **ppUserData,
                     OUT DWORD           *pdwUserDataSize );

    DWORD  SetScepLength( IN SCEP_HEADER *pPdu,
                          IN DWORD        dwTotalPduSize );

    // Construct SCEP connection/control PDUs:
    DWORD  BuildConnectPdu( OUT SCEP_HEADER **ppPdu,
                            OUT DWORD        *pdwPduSize );

    DWORD  BuildConnectRespPdu( OUT SCEP_HEADER **ppPdu,
                                OUT DWORD        *pdwPduSize );

    DWORD  BuildConnectNackPdu( OUT SCEP_HEADER **ppPdu,
                                OUT DWORD        *pdwPduSize );

    DWORD  BuildAbortPdu( OUT SCEP_HEADER **ppPdu,
                          OUT DWORD        *pdwPduSize );

    DWORD  BuildStopPdu( OUT SCEP_HEADER **ppPdu,
                         OUT DWORD        *pdwPduSize );

    DWORD  BuildDisconnectPdu( IN  USHORT        ReasonCode,
                               OUT SCEP_HEADER **ppPdu,
                               OUT DWORD        *pdwPduSize );

    // Build bFTP request (client-side) PDUs:
    DWORD  BuildBftpWht0RinfPdu( OUT SCEP_HEADER          **ppPdu,
                                 OUT DWORD                 *pdwPduSize,
                                 OUT SCEP_REQ_HEADER_LONG **ppCommand,
                                 OUT COMMAND_HEADER       **ppCommandHeader );

    DWORD  BuildBftpPutPdu( IN  DWORD                       dwUpfFileSize,
                            IN  CHAR                       *pszUpfFile,
                            IN OUT DWORD                   *pdwFragNo,
                            OUT SCEP_HEADER               **ppPdu,
                            OUT DWORD                      *pdwPduSize,
                            OUT SCEP_REQ_HEADER_LONG_FRAG **ppCommand );

    // Build bFTP response PDUs:
    DWORD  BuildBftpRespPdu( IN  DWORD            dwPduSize,
                             OUT SCEP_HEADER    **ppPdu,
                             OUT SCEP_REQ_HEADER_SHORT **ppCommand,
                             OUT COMMAND_HEADER **ppCommandHeader );

    DWORD  BuildWht0RespPdu( IN  DWORD         dwWht0Type,
                             OUT SCEP_HEADER **ppPdu,
                             OUT DWORD        *pdwPduSize );

    DWORD  BuildPutRespPdu( IN  DWORD         dwPduAckOrNack,
                            IN  USHORT        usErrorCode,
                            OUT SCEP_HEADER **ppPdu,
                            OUT DWORD        *pdwPduSize );

    // Parse the bFTP in a SCEP command request PDU:
    DWORD  ParseBftp( IN  UCHAR  *pvBftpData,
                      IN  DWORD   dwDataSize,
                      IN  BOOL    fSaveAsUPF,
                      OUT DWORD  *pdwBftpOp,
                      OUT UCHAR **ppPutData,
                      OUT DWORD  *pdwPutDataSize );

    // Parse and save the create date/time that was specified as a 
    // bFTP option:
    DWORD  SaveBftpCreateDate( IN UCHAR *pDate,
                               IN DWORD  dwLength );

    // Parse the UPF file header to find the image JPEG file:
    DWORD  ParseUpfHeaders( IN UCHAR  *pPutData,
                            IN DWORD   dwPutDataSize,
                            OUT DWORD *pdwJpegOffset,
                            OUT DWORD *pdwJpegSize );

    // Used when a SCEP command PDU is received:
    BOOL   IsFragmented();
    DWORD  GetSequenceNo();
    DWORD  GetRestNo();
    DWORD  GetCommandId();
    WCHAR *GetFileName();
    UCHAR  GetDFlag();
    FILETIME *GetCreateTime();

protected:

    DWORD  CheckPdu( OUT SCEP_HEADER **ppPdu,
                     OUT DWORD        *pdwPduSize );

    DWORD  CheckConnectPdu( OUT SCEP_HEADER **ppPdu,
                            OUT DWORD        *pdwPduSize );

    DWORD  CheckAckPdu( OUT SCEP_HEADER **ppPdu,
                        OUT DWORD        *pdwPduSize );

    DWORD  CheckNackPdu( OUT SCEP_HEADER **ppPdu,
                         OUT DWORD        *pdwPduSize );

    DWORD  CheckConnectRespPdu( OUT SCEP_HEADER **ppPdu,
                                OUT DWORD        *pdwPduSize );

    DWORD  CheckDataPdu( OUT SCEP_HEADER **ppPdu,
                         OUT DWORD        *pdwPduSize );

    DWORD  CheckDisconnectPdu( OUT SCEP_HEADER **ppPdu,
                               OUT DWORD        *pdwPduSize );

    DWORD  ParseConnectPdu( IN SCEP_HEADER *pPdu,
                            IN DWORD        dwPduSize );

    DWORD  ParseConnectRespPdu( IN SCEP_HEADER *pPdu,
                                IN DWORD        dwPduSize );

    DWORD  ParseDataPdu( IN  SCEP_HEADER *pPdu,
                         IN  DWORD        dwPduSize,
                         OUT COMMAND_HEADER **ppCommand,
                         OUT UCHAR          **ppUserData,
                         OUT DWORD           *pdwUserDataSize );

    DWORD  ParseDisconnectPdu( IN SCEP_HEADER *pPdu,
                               IN DWORD        dwPduSize );

    DWORD  ParseNegotiation( IN UCHAR *pNegotiation,
                             IN DWORD  dwNegotiationSize );

    UCHAR *ParseAttribute( IN     UCHAR *pAttributes,
                           IN OUT DWORD *pdwAttributeSize,
                           OUT    DWORD *pdwStatus );

    DWORD  ParseSingleLongPdu( IN SCEP_HEADER *pPdu,
                               IN DWORD        dwPduSize );

    BFTP_ATTRIBUTE *ParseBftpAttributeName(
                               IN BFTP_ATTRIBUTE *pAttr,
                               IN OUT DWORD      *pdwSize,
                               OUT    DWORD      *pdwWhichAttr );

    DWORD   m_dwConnectionState;
    DWORD   m_dwPduSendSize;
    DWORD   m_dwPduReceiveSize;
    UCHAR   m_CFlag;
    UCHAR  *m_pPrimaryMachineId;
    UCHAR  *m_pSecondaryMachineId;
    USHORT  m_DestPid;        // My PID (Camera point of view).
    USHORT  m_SrcPid;         // Camera's PID (Camera point of view).
    UCHAR  *m_pszProductId;
    UCHAR  *m_pszUserName;
    UCHAR  *m_pszPassword;

    // Used during PDU assembley process.
    UCHAR  *m_pAssembleBuffer;
    DWORD   m_dwAssembleBufferSize;
    DWORD   m_dwMaxAssembleBufferSize;
    BOOL    m_fDidByteSwap;

    // Used to manage the current SCEP command PDU.
    UCHAR   m_Fragmented;
    UCHAR   m_DFlag;
    DWORD   m_dwSequenceNo;
    DWORD   m_dwRestNo;
    DWORD   m_dwCommandId;
    COMMAND_HEADER *m_pCommandHeader;

    // UPF Hear and bFTP information
    // NOTE: The CHAR version of the file name is the one that camera
    //       sent us, the WCHAR version is the one we will actually 
    //       create. Note that the WCHAR version usually has a different
    //       suffix.
    CHAR    *m_pszFileName;
    CHAR    *m_pszLongFileName;
    WCHAR   *m_pwszFileName;
    FILETIME m_CreateTime;
};

//--------------------------------------------------------------------
// Inline Functions:
//--------------------------------------------------------------------

inline BOOL CSCEP_CONNECTION::IsFragmented()
    {
    return m_Fragmented;
    }

inline DWORD CSCEP_CONNECTION::GetSequenceNo()
    {
    return m_dwSequenceNo;
    }

inline DWORD CSCEP_CONNECTION::GetRestNo()
    {
    return m_dwRestNo;
    }

inline DWORD CSCEP_CONNECTION::GetCommandId()
    {
    return m_dwCommandId;
    }

inline WCHAR *CSCEP_CONNECTION::GetFileName()
    {
    return m_pwszFileName;
    }

inline UCHAR CSCEP_CONNECTION::GetDFlag()
    {
    return m_DFlag;
    }

inline FILETIME *CSCEP_CONNECTION::GetCreateTime()
    {
    if ( (m_CreateTime.dwLowDateTime)
       || (m_CreateTime.dwHighDateTime) )
        {
        return &m_CreateTime;
        }
    else
        {
        return 0;
        }
    }

//--------------------------------------------------------------------
// Utility Functions/Macros:
//--------------------------------------------------------------------

#define ByteSwapShort(Value)              \
            (  (((Value) & 0x00FF) << 8)  \
             | (((Value) & 0xFF00) >> 8))

#define ByteSwapLong(Value) \
            (  (((Value) & 0xFF000000) >> 24) \
             | (((Value) & 0x00FF0000) >> 8)  \
             | (((Value) & 0x0000FF00) << 8)  \
             | (((Value) & 0x000000FF) << 24))

extern void ByteSwapReqHeaderShort( SCEP_REQ_HEADER_SHORT *pSingleShort );

extern void ByteSwapReqHeaderLong( SCEP_REQ_HEADER_LONG *pSingleLong );

extern void ByteSwapCommandHeader( COMMAND_HEADER *pCommandHeader );


//--------------------------------------------------------------------
// Memory management functions:
//--------------------------------------------------------------------

DWORD        InitializeMemory();

DWORD        UninitializeMemory();

void        *AllocateMemory( DWORD dwBytes );
 
DWORD        FreeMemory( void *pvMemory );

SCEP_HEADER *NewPdu( DWORD dwPduSize = MAX_PDU_SIZE );

void         DeletePdu( SCEP_HEADER *pPdu );

#if FALSE
//--------------------------------------------------------------------

    SCEP Connect PDU
    ----------------

    Connection request PDU. This is a SCEP_HEADER with Rest[] filled
    with three Inf Records, a SCEP_VERSION followed by a SCEP_NEGOTIATION
    followed by a SCEP_EXTEND. The Connect PDU must be less than or equal
    to 256 bytes in length.

      SCEP_HEADER                        2 bytes.
      Rest[]: SCEP_VERSION               2 bytes.
              SCEP_NEGOTIATION    20 - 228 bytes.
              SCEP_EXTEND                4 bytes.
                                  --------
                                  28 - 256 bytes.

    - If either the SecondaryMachineId[] or PrimariyMachineId is unused,
      then they are set to 00,00,00,00,00,00,00,00.
    - If a machine gets a Connect PDU but can't  execute commands
      (CFlag = CFLAG_ISSUE_ONLY), then it needs to respond with a
      NACK PDU.
    - The negotiation information is a simple text based command
      language.


    SCEP Connection ACK PDU
    -----------------------

    Connection acceptance PDU. This is a SCEP_HEADER with Rest[] filled
    with two Inf Records, a SCEP_VERSION followed by a SCEP_NEGOTIATION.

      SCEP_HEADER                        2 bytes.
      SCEP_VERSION                       2 bytes.
      Rest[]: SCEP_NEGOTIATION      20-251 bytes.
                                    ------
                                    24-255 bytes.

    - Note that the size of the ACK PDU is limited by the fact that
      the Length field is a single byte and that the ACK PDU can not
      be fragmented. Normally these PDUs will never be this long.


    SCEP Connection NACK PDU
    ------------------------

    Connection rejected PDU. This one can have either of two different
    formats.

      SCEP_HEADER
      Rest[]: SCEP_REQ_HEADER_SHORT

      or

      SCEP_HEADER
      Rest[]: SCEP_REQ_HEADER_LONG

    - In the first case, Length1 = 4, DFlag = DFLAG_CONNECT_REJECT,
      and Length 3 = 0.
    - In the second case, Length1 = 0xff, DFlag = DFLAG_CONNECT_REJECT,
      and Length 3 = 0.


    SCEP Disconnect PDU
    -------------------

    A disconnect can be generated by either side of the connection,
    or by one of the transports at any time.

      SCEP_HEADER
      Rest[]: SCEP_DISCONNECT

    - For V1.0, Length1 = 2, and ReasonCode is a USHORT.


    SCEP Command Request and Response PDUs (Non-fragmented)
    -------------------------------------------------------

      SCEP_HEADER                              2 bytes
      Rest[]: SCEP_REQ_HEADER_SHORT    4 + 0-254 bytes
                                       ---------
                                         6 - 260 bytes
      or

      SCEP_HEADER                              2 bytes
      Rest[]: SCEP_REQ_HEADER_LONG    4 + 0-4090 bytes (1)
                                      ----------
                                        6 - 4096 bytes

    - In either case, DFlag = DFLAG_SINGLE_PDU.
    - PduType = PDU_TYPE_REQUEST.
    - If Length1 = 0xff then the long version is used.
    - The Length1(2) field specifies the byte size from InfVersion to the
      end of the user data. If the total size will exceed the maximum PDU
      size then the request must be fragmented.
    - So the total PDU size is: 6 + Length1(2) bytes.

    (1) Assuming the maximum PDU size is 4096 (fr:4).


    SCEP Command Request and Response PDUs (Fragmented)
    ---------------------------------------------------

    For requests these PDUs are generated when the PDU size is greater
    than that of the responder that you are connected to. For responses,
    the PDUs are fragmented when the returned data is greater than the
    maximum that the requester specified during the connection establishment.

      SCEP_HEADER                              2 bytes
      Rest[]: SCEP_REQ_HEADER_SHORT_FRAG    6 + 0-254 bytes
                                       ---------
                                         8 - 260 bytes
      or

      SCEP_HEADER                              2 bytes
      Rest[]: SCEP_REQ_HEADER_LONG_FRAG    8 + 0-4088 bytes (1)
                                       ---------
                                       10 - 4096 bytes

    - For the first PDU fragment, DFlag = DFLAG_FIRST_FRAGMENT, for
      intermediate fragments, DFlag = DFLAG_FRAGMENT, and for the
      last fragment, DFlag = DFLAG_LAST_FRAGMENT.
    - PduType = PDU_TYPE_REQUEST for the request.
    - PduType = PDU_TYPE_REPLY_ACK or PDU_TYPE_REPLY_NACK in the
      response.
    - If Length1 = 0xff then the long version is used.
    - Length1(2) can not exceed the maximum PDU size - 6 bytes.
    - SequenceNo is 0 for the first PDU (NOTE: 4 bytes).
    - RestNo is the remaining number of PDUs to get. It is 1 for
      the last PDU (really, it says so in the spec!). So, a client
      should start this as the total number of PDUs in the first
      fragment (not really the number remaining). NOTE: 4 bytes.

    (1) Assuming the maximum PDU size is 4096 (fr:4).


    SCEP Abort PDU
    --------------

    Use the abort to stop execution of a command (specified by the
    DestPid and CommandId) after ALL of the request PDUs have been
    sent. An abort PDU also has two possible formats.

      SCEP_HEADER                              2 bytes
      Rest[]: SCEP_REQ_HEADER_SHORT           34 bytes
                                              --
                                              36 bytes
      or

      SCEP_HEADER                              2 bytes
      Rest[]: SCEP_REQ_HEADER_LONG            36 bytes
                                              --
                                              38 bytes

    - In either case, DFlag = DFLAG_SINGLE_PDU.
    - In either case, PduType = PDU_TYPE_ABORT.
    - For the short PDU, Length1 = 0x20 (32), and Length3 = 0x1c
      (28).
    - For the long PDU, Length1 = 0xff, Length2 = 0x20 (32),
      and Length3 = 0x1c (28).


    SCEP Stop (Interrupt) PDU
    -------------------------

    If an Abort PDU has been sent out to stop a command, and as the
    command is halted some response data has already been sent, the
    the responder will send this PDU. It appears that a Stop PDU should
    not be sent if no response has yet been sent back.

      SCEP_HEADER                              2 bytes
      Rest[]: SCEP_REQ_HEADER_SHORT            6 bytes
                                              --
                                               8 bytes
      or

      SCEP_HEADER                              2 bytes
      Rest[]: SCEP_REQ_HEADER_LONG             8 bytes
                                              --
                                              10 bytes

    - In either case, DFlag = DFLAG_INTERRUPT.
    - For the short PDU, Length1 = 4, and Length3 = 0.
    - For the long PDU, Length1 = 0xff, Length2 = 4, and
      Length3 = 0.

    Negotiation Information
    -----------------------

    The negotiation information is used to convey the frame size,
    authentication data, and product information, etc.

    Its structure is a version code (currently 0x11) followed by
    text in the following syntax:

      NegInf    -> Attribute ':' Spaces Value CrLf

      Attribute -> AttribChar AttribChar

      AttribChar-> 'a-zA-Z'

      Value     -> ValueChar Value
                ->

      ValueChar -> 'ASCII string, bytes must be between 0x20 and 0x8e
                    inclusive'

      Spaces    -> ' ' Spaces
                ->

      CrLf      -> 0x0d 0x0a

      Attribute    Meaning
      ---------    -------
      fr           Frame (PDU) size. The sender requests the maximum
                   receivable PDU size, the receiver decides the
                   transmission PDU size in accordance with the senders
                   requested PDU size. The maximum PDU size of the sender
                   may be different than that of the receiver. The value
                   is one of:

                   1 -  512 bytes PDU size (default).
                   2 - 1024 bytes PDU size.
                   3 - 2048 bytes PDU size.
                   4 - 4096 bytes PDU size.

      id           Product Identification string.

      nm           User name. any byte string that doesn't include CR or
                   LF (note the conflict in by values with the syntax
                   specification above). The user name may be up to 32
                   characters long.

      pw           Password. This is a MD5 encoded password expressed
                   in a 16 byte "hex" string, no spaces are allowd.
                   It appears that this will always be 32 characters
                   long. For example: 0aff3728e4a62791337984282871a6bc

//--------------------------------------------------------------------
#endif

#endif //_SCEP_H_